From 780a4904bde94043b83b33e231d1b04fda22728a Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 13 Jun 2025 14:41:00 +0300 Subject: [PATCH] Handle implicitly checked files more consistently (#8563) --- .../contentselector/model/contentmodel.cpp | 26 ++++++++++++------- .../contentselector/model/contentmodel.hpp | 1 + .../contentselector/view/contentselector.cpp | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 2604a02885..53d5476fb6 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -129,7 +129,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex& index { if (depFile->isGameFile() && file->gameFiles().contains(depFile->fileName(), Qt::CaseInsensitive)) { - if (!depFile->builtIn() && !depFile->fromAnotherConfigFile() && !mCheckedFiles.contains(depFile)) + if (!isChecked(depFile)) break; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; @@ -215,8 +215,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int if (file == mGameFile) return QVariant(); - return (file->builtIn() || file->fromAnotherConfigFile() || mCheckedFiles.contains(file)) ? Qt::Checked - : Qt::Unchecked; + return isChecked(file) ? Qt::Checked : Qt::Unchecked; } case Qt::UserRole: @@ -230,7 +229,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int } case Qt::UserRole + 1: - return mCheckedFiles.contains(file); + return isChecked(file); } return QVariant(); } @@ -264,9 +263,9 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const { int checkValue = value.toInt(); if (checkValue == Qt::Checked) - return mCheckedFiles.contains(file) || setCheckState(file, true); + return isChecked(file) || setCheckState(file, true); if (checkValue == Qt::Unchecked) - return !mCheckedFiles.contains(file) || setCheckState(file, false); + return !isChecked(file) || setCheckState(file, false); } } @@ -606,6 +605,14 @@ void ContentSelectorModel::ContentModel::sortFiles() emit layoutChanged(); } +bool ContentSelectorModel::ContentModel::isChecked(const EsmFile* file) const +{ + if (file == nullptr) + return false; + + return file->builtIn() || file->fromAnotherConfigFile() || mCheckedFiles.contains(file); +} + bool ContentSelectorModel::ContentModel::isEnabled(const QModelIndex& index) const { return (flags(index) & Qt::ItemIsEnabled); @@ -691,7 +698,7 @@ QList ContentSelectorModel::ContentModel:: } else { - if (!mCheckedFiles.contains(dependentFile)) + if (!isChecked(dependentFile)) { errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); } @@ -706,7 +713,7 @@ QList ContentSelectorModel::ContentModel:: { // Warn the user if Bloodmoon is loaded before Tribunal (Tribunal is not a hard dependency) const EsmFile* tribunalFile = item("Tribunal.esm"); - if (tribunalFile != nullptr && mCheckedFiles.contains(tribunalFile) && row < indexFromItem(tribunalFile).row()) + if (isChecked(tribunalFile) && row < indexFromItem(tribunalFile).row()) errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, "Tribunal.esm")); } @@ -770,8 +777,9 @@ bool ContentSelectorModel::ContentModel::setCheckState(const EsmFile* file, bool for (const QString& upstreamName : file->gameFiles()) { const EsmFile* upstreamFile = item(upstreamName); - if (upstreamFile == nullptr || !mCheckedFiles.insert(upstreamFile).second) + if (upstreamFile == nullptr || isChecked(upstreamFile)) continue; + mCheckedFiles.insert(upstreamFile); QModelIndex upstreamIndex = indexFromItem(upstreamFile); emit dataChanged(upstreamIndex, upstreamIndex); } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index cf182263f9..6260e5f1fe 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -58,6 +58,7 @@ namespace ContentSelectorModel QStringList gameFiles() const; void setCurrentGameFile(const EsmFile* file); + bool isChecked(const EsmFile* file) const; bool isEnabled(const QModelIndex& index) const; bool setCheckState(const EsmFile* file, bool isChecked); bool isNew(const QString& filepath) const; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index f8374b5db5..5fd54ee789 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -157,7 +157,7 @@ void ContentSelectorView::ContentSelector::setGameFile(const QString& filename) index = ui->gameFileView->findText(file->fileName()); // verify that the current index is also checked in the model - if (!mContentModel->setCheckState(file, true)) + if (!mContentModel->isChecked(file) && !mContentModel->setCheckState(file, true)) { // throw error in case file not found? return;