diff --git a/src/filetreemodel.cpp b/src/filetreemodel.cpp index 5a6f6a2c..de6194ff 100644 --- a/src/filetreemodel.cpp +++ b/src/filetreemodel.cpp @@ -9,6 +9,7 @@ using namespace MOBase; using namespace MOShared; +namespace fs = std::filesystem; // in mainwindow.cpp QString UnmanagedModName(); @@ -969,8 +970,11 @@ void FileTreeModel::updateFileItem(FileTreeItem& item, const MOShared::FileEntry bool FileTreeModel::shouldShowFile(const FileEntry& file) const { - if (showConflictsOnly() && (file.getAlternatives().size() == 0)) { - // only conflicts should be shown, but this file is not conflicted + if (showConflictsOnly() && + ((file.getAlternatives().size() == 0) || + QString::fromStdWString(file.getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive))) { + // only conflicts should be shown, but this file is hidden or not conflicted return false; } @@ -979,8 +983,8 @@ bool FileTreeModel::shouldShowFile(const FileEntry& file) const return false; } - if (!showHiddenFiles() && - file.getName().ends_with(ModInfo::s_HiddenExt.toStdWString())) { + if (!showHiddenFiles() && QString::fromStdWString(file.getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) { // hidden files shouldn't be shown, but this file is hidden return false; } @@ -991,8 +995,9 @@ bool FileTreeModel::shouldShowFile(const FileEntry& file) const bool FileTreeModel::shouldShowFolder(const DirectoryEntry& dir, const FileTreeItem* item) const { - if (!showHiddenFiles() && - dir.getName().ends_with(ModInfo::s_HiddenExt.toStdWString())) { + if ((!showHiddenFiles() || showConflictsOnly()) && + QString::fromStdWString(dir.getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) { return false; } diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index 715214b3..f405f0e1 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -11,6 +11,7 @@ using namespace MOShared; using namespace MOBase; +namespace fs = std::filesystem; // if there are more than 50 selected items in the conflict tree, don't bother // checking whether menu items apply to them, just show all of them @@ -110,7 +111,7 @@ bool ConflictsTab::canHandleUnmanaged() const return true; } -void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) +void ConflictsTab::hideItems(QTreeView* tree) { bool changed = false; bool stop = false; @@ -119,19 +120,16 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) // logging { - const QString action = (visible ? "unhiding" : "hiding"); - QString files; if (n > max_small_selection) files = "a lot of"; else files = QString("%1").arg(n); - log::debug("{} {} conflict files", action, files); + log::debug("hiding {} conflict files", files); } - QFlags flags = - (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); + QFlags flags = FileRenamer::HIDE; if (n > 1) { flags |= FileRenamer::MULTIPLE; @@ -158,25 +156,13 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) return false; } - auto result = FileRenamer::RESULT_CANCEL; - - if (visible) { - if (!item->canUnhide()) { - log::debug("cannot unhide {}, skipping", item->relativeName()); - return true; - } - - result = unhideFile(renamer, item->fileName()); - - } else { - if (!item->canHide()) { - log::debug("cannot hide {}, skipping", item->relativeName()); - return true; - } - - result = hideFile(renamer, item->fileName()); + if (!item->canHide()) { + log::debug("cannot hide {}, skipping", item->relativeName()); + return true; } + auto result = hideFile(renamer, item->fileName()); + switch (result) { case FileRenamer::RESULT_OK: { // will trigger a refresh at the end @@ -199,7 +185,7 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) return true; }); - log::debug("{} conflict files done", (visible ? "unhiding" : "hiding")); + log::debug("hiding conflict files done"); if (changed) { log::debug("triggering refresh"); @@ -351,21 +337,12 @@ void ConflictsTab::showContextMenu(const QPoint& pos, QTreeView* tree) // hide if (actions.hide) { connect(actions.hide, &QAction::triggered, [&] { - changeItemsVisibility(tree, false); + hideItems(tree); }); menu.addAction(actions.hide); } - // unhide - if (actions.unhide) { - connect(actions.unhide, &QAction::triggered, [&] { - changeItemsVisibility(tree, true); - }); - - menu.addAction(actions.unhide); - } - if (!menu.isEmpty()) { if (actions.open || actions.preview || actions.runHooked) { // bold the first option @@ -386,7 +363,6 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) } bool enableHide = true; - bool enableUnhide = true; bool enableRun = true; bool enableOpen = true; bool enablePreview = true; @@ -421,7 +397,6 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) } enableHide = item->canHide(); - enableUnhide = item->canUnhide(); enableRun = item->canRun(); enableOpen = item->canOpen(); enablePreview = item->canPreview(plugin()); @@ -443,19 +418,14 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) if (n <= max_small_selection) { // if the number of selected items is low, checking them to accurately // show the menu items is worth it - enableHide = false; - enableUnhide = false; + enableHide = false; forEachInSelection(tree, [&](const ConflictItem* item) { if (item->canHide()) { enableHide = true; } - if (item->canUnhide()) { - enableUnhide = true; - } - - if (enableHide && enableUnhide && enableGoto) { + if (enableHide && enableGoto) { // found all, no need to check more return false; } @@ -487,11 +457,6 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) actions.hide = new QAction(tr("&Hide"), parentWidget()); actions.hide->setEnabled(enableHide); - // note that it is possible for hidden files to appear if they override other - // hidden files from another mod - actions.unhide = new QAction(tr("&Unhide"), parentWidget()); - actions.unhide->setEnabled(enableUnhide); - if (enableGoto && n == 1) { const auto* item = model->getItem(static_cast(modelSel.indexes()[0].row())); @@ -633,8 +598,39 @@ bool GeneralConflictsTab::update() if (m_tab->origin() != nullptr) { const auto rootPath = m_tab->mod().absolutePath(); + std::set checkedDirs; for (const auto& file : m_tab->origin()->getFiles()) { + if (QString::fromStdWString(file->getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) { + // skip hidden file conflicts + continue; + } else { + const DirectoryEntry* parent = file->getParent(); + auto hidden = false; + // iterate on all parent directory entries to check for .mohiddden + while (parent != nullptr) { + auto insertResult = checkedDirs.insert(parent); + + if (insertResult.second == false) { + // if already present break as we can assume to have checked the parents as + // well + break; + } else { + if (QString::fromStdWString(parent->getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) { + hidden = true; + break; + } + parent = parent->getParent(); + } + } + if (hidden) { + // skip hidden file conflicts + continue; + } + } + // careful: these two strings are moved into createXItem() below QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); @@ -954,8 +950,38 @@ void AdvancedConflictsTab::update() const auto& files = m_tab->origin()->getFiles(); m_model->reserve(files.size()); + std::set checkedDirs; for (const auto& file : files) { + if (QString::fromStdWString(file->getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) { + // skip hidden file conflicts + continue; + } else { + const DirectoryEntry* parent = file->getParent(); + auto hidden = false; + // iterate on all parent directory entries to check for .mohiddden + while (parent != nullptr) { + auto insertResult = checkedDirs.insert(parent); + + if (insertResult.second == false) { + // if already present break as we can assume to have checked the parents as + // well + break; + } else { + if (QString::fromStdWString(parent->getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) { + hidden = true; + break; + } + parent = parent->getParent(); + } + } + if (hidden) { + // skip hidden file conflicts + continue; + } + } // careful: these two strings are moved into createItem() below QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); diff --git a/src/modinfodialogconflicts.h b/src/modinfodialogconflicts.h index f1edd33a..4bbd469f 100644 --- a/src/modinfodialogconflicts.h +++ b/src/modinfodialogconflicts.h @@ -135,7 +135,7 @@ class ConflictsTab : public ModInfoDialogTab void openItem(const ConflictItem* item, bool hooked); void previewItem(const ConflictItem* item); - void changeItemsVisibility(QTreeView* tree, bool visible); + void hideItems(QTreeView* tree); void showContextMenu(const QPoint& pos, QTreeView* tree); @@ -143,7 +143,6 @@ class ConflictsTab : public ModInfoDialogTab struct Actions { QAction* hide = nullptr; - QAction* unhide = nullptr; QAction* open = nullptr; QAction* runHooked = nullptr; QAction* preview = nullptr; diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index df2dc7ce..af43433d 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -98,6 +98,7 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co bool providesAnything = false; bool hasHiddenFiles = false; + bool hasVisibleFiles = false; std::vector dataIDs; if (m_Core.directoryStructure()->originExists(L"data")) { @@ -110,8 +111,7 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co } } - std::wstring name = ToWString(this->name()); - const std::wstring hideExt = ToWString(ModInfo::s_HiddenExt); + std::wstring name = ToWString(this->name()); if (m_Core.directoryStructure()->originExists(name)) { FilesOrigin& origin = m_Core.directoryStructure()->getOriginByName(name); @@ -120,36 +120,39 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co // for all files in this origin for (FileEntryPtr file : files) { + if (QString::fromStdWString(file->getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) { + hasHiddenFiles = true; + // skip hidden file conflicts + continue; + } else { + const DirectoryEntry* parent = file->getParent(); + auto hidden = false; - // skip hiidden file check if already found one - if (!hasHiddenFiles) { - const fs::path nameAsPath(file->getName()); - - if (nameAsPath.extension().wstring().compare(hideExt) == 0) { - hasHiddenFiles = true; - } else { - const DirectoryEntry* parent = file->getParent(); - - // iterate on all parent direEntries to check for .mohiddden - while (parent != nullptr) { - auto insertResult = checkedDirs.insert(parent); + // iterate on all parent directory entries to check for .mohiddden + while (parent != nullptr) { + auto insertResult = checkedDirs.insert(parent); - if (insertResult.second == false) { - // if already present break as we can assume to have checked the parents - // as well + if (insertResult.second == false) { + // if already present break as we can assume to have checked the parents as + // well + break; + } else { + if (QString::fromStdWString(parent->getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)) { + hasHiddenFiles = hidden = true; break; - } else { - const fs::path dirPath(parent->getName()); - if (dirPath.extension().wstring().compare(hideExt) == 0) { - hasHiddenFiles = true; - break; - } - parent = parent->getParent(); } + parent = parent->getParent(); } } + if (hidden) { + // skip hidden file conflicts + continue; + } } + hasVisibleFiles = true; auto alternatives = file->getAlternatives(); if ((alternatives.size() == 0) || std::find(dataIDs.begin(), dataIDs.end(), alternatives.back().originID()) != @@ -223,7 +226,7 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co } if (files.size() != 0) { - if (!providesAnything) + if (hasVisibleFiles && !providesAnything) conflicts.m_CurrentConflictState = CONFLICT_REDUNDANT; else if (!conflicts.m_OverwriteList.empty() && !conflicts.m_OverwrittenList.empty())