diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 093c64c99b..c1bcc8f944 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -351,9 +352,17 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) if (!resourcesVfs.isEmpty()) directories.insert(0, { resourcesVfs }); + QIcon containsDataIcon(":/images/openmw-plugin.png"); + + QProgressDialog progressBar("Adding data directories", {}, 0, directories.count(), this); + progressBar.setWindowModality(Qt::WindowModal); + progressBar.setValue(0); + std::unordered_set visitedDirectories; for (const Config::SettingValue& currentDir : directories) { + progressBar.setValue(progressBar.value() + 1); + if (!visitedDirectories.insert(currentDir.value).second) continue; @@ -402,7 +411,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) // Add a "data file" icon if the directory contains a content file if (mSelector->containsDataFiles(currentDir.value)) { - item->setIcon(QIcon(":/images/openmw-plugin.png")); + item->setIcon(containsDataIcon); tooltip << tr("Contains content file(s)"); } diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index f318cec4a4..36373f8f35 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -1,6 +1,7 @@ #include "gamesettings.hpp" #include +#include #include #include @@ -37,8 +38,13 @@ void Config::GameSettings::validatePaths() mDataDirs.clear(); + QProgressDialog progressBar("Validating paths", {}, 0, paths.count() + 1); + progressBar.setWindowModality(Qt::WindowModal); + progressBar.setValue(0); + for (const auto& dataDir : paths) { + progressBar.setValue(progressBar.value() + 1); if (QDir(dataDir.value).exists()) { SettingValue copy = dataDir; @@ -50,6 +56,8 @@ void Config::GameSettings::validatePaths() // Do the same for data-local const QString& local = mSettings.value(QString("data-local")).value; + progressBar.setValue(progressBar.value() + 1); + if (!local.isEmpty() && QDir(local).exists()) { mDataLocal = QDir(local).canonicalPath(); diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index fe26d37b97..5f0d41d38c 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -78,14 +79,10 @@ ContentSelectorModel::EsmFile* ContentSelectorModel::ContentModel::item(int row) } const ContentSelectorModel::EsmFile* ContentSelectorModel::ContentModel::item(const QString& name) const { - EsmFile::FileProperty fp = EsmFile::FileProperty_FileName; - - if (name.contains('/')) - fp = EsmFile::FileProperty_FilePath; - + bool path = name.contains('/'); for (const EsmFile* file : mFiles) { - if (name.compare(file->fileProperty(fp).toString(), Qt::CaseInsensitive) == 0) + if (name.compare(path ? file->filePath() : file->fileName(), Qt::CaseInsensitive) == 0) return file; } return nullptr; @@ -310,7 +307,6 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const { setCheckState(file->filePath(), success); emit dataChanged(index, index); - checkForLoadOrderErrors(); } else return success; @@ -425,7 +421,6 @@ bool ContentSelectorModel::ContentModel::dropMimeData( dataChanged(index(minRow, 0), index(maxRow, 0)); // at this point we know that drag and drop has finished. - checkForLoadOrderErrors(); return true; } @@ -552,15 +547,13 @@ void ContentSelectorModel::ContentModel::addFiles(const QString& path, bool newf bool ContentSelectorModel::ContentModel::containsDataFiles(const QString& path) { - QDir dir(path); QStringList filters; filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; - dir.setNameFilters(filters); - - return dir.entryList().count() != 0; + QDirIterator it(path, filters, QDir::Files | QDir::NoDotAndDotDot); + return it.hasNext(); } void ContentSelectorModel::ContentModel::clearFiles() @@ -707,12 +700,13 @@ void ContentSelectorModel::ContentModel::setNonUserContent(const QStringList& fi bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile* file) const { - return mPluginsWithLoadOrderError.contains(file->filePath()); + int index = indexFromItem(file).row(); + auto errors = checkForLoadOrderErrors(file, index); + return !errors.empty(); } void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileList) { - mPluginsWithLoadOrderError.clear(); int previousPosition = -1; for (const QString& filepath : fileList) { @@ -725,7 +719,6 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL if (filePosition < previousPosition) { mFiles.move(filePosition, previousPosition); - emit dataChanged(index(filePosition, 0, QModelIndex()), index(previousPosition, 0, QModelIndex())); } else { @@ -733,24 +726,7 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL } } } - checkForLoadOrderErrors(); -} - -void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() -{ - for (int row = 0; row < mFiles.count(); ++row) - { - EsmFile* file = mFiles.at(row); - bool isRowInError = checkForLoadOrderErrors(file, row).count() != 0; - if (isRowInError) - { - mPluginsWithLoadOrderError.insert(file->filePath()); - } - else - { - mPluginsWithLoadOrderError.remove(file->filePath()); - } - } + emit dataChanged(index(0, 0), index(rowCount(), columnCount())); } QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors( @@ -791,11 +767,12 @@ QList ContentSelectorModel::ContentModel:: QString ContentSelectorModel::ContentModel::toolTip(const EsmFile* file) const { - if (isLoadOrderError(file)) + int index = indexFromItem(file).row(); + auto errors = checkForLoadOrderErrors(file, index); + if (!errors.empty()) { QString text(""); - int index = indexFromItem(item(file->filePath())).row(); - for (const LoadOrderError& error : checkForLoadOrderErrors(file, index)) + for (const LoadOrderError& error : errors) { assert(error.errorCode() != LoadOrderError::ErrorCode::ErrorCode_None); @@ -900,7 +877,6 @@ ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checke void ContentSelectorModel::ContentModel::uncheckAll() { - emit layoutAboutToBeChanged(); mCheckedFiles.clear(); - emit layoutChanged(); + emit dataChanged(index(0, 0), index(rowCount(), columnCount()), { Qt::CheckStateRole, Qt::UserRole + 1 }); } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 467a9c032a..3eba939125 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -69,9 +69,6 @@ namespace ContentSelectorModel void refreshModel(); - /// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues - void checkForLoadOrderErrors(); - private: void addFile(EsmFile* file); @@ -89,7 +86,6 @@ namespace ContentSelectorModel QStringList mNonUserContent; std::set mCheckedFiles; QHash mNewFiles; - QSet mPluginsWithLoadOrderError; QString mEncoding; QIcon mWarningIcon; QIcon mErrorIcon; diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index 28b4bd2822..d040dbd04d 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -48,18 +48,18 @@ namespace ContentSelectorModel void addGameFile(const QString& name) { mGameFiles.append(name); } QVariant fileProperty(const FileProperty prop) const; - QString fileName() const { return mFileName; } - QString author() const { return mAuthor; } + const QString& fileName() const { return mFileName; } + const QString& author() const { return mAuthor; } QDateTime modified() const { return mModified; } - QString formatVersion() const { return mVersion; } - QString filePath() const { return mPath; } + const QString& formatVersion() const { return mVersion; } + const QString& filePath() const { return mPath; } bool builtIn() const { return mBuiltIn; } bool fromAnotherConfigFile() const { return mFromAnotherConfigFile; } bool isMissing() const { return mPath.isEmpty(); } /// @note Contains file names, not paths. const QStringList& gameFiles() const { return mGameFiles; } - QString description() const { return mDescription; } + const QString& description() const { return mDescription; } QString toolTip() const { if (isMissing()) diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index bce136b335..0be6e7c023 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -211,7 +211,6 @@ void ContentSelectorView::ContentSelector::addFiles(const QString& path, bool ne ui->gameFileView->setCurrentIndex(0); mContentModel->uncheckAll(); - mContentModel->checkForLoadOrderErrors(); } void ContentSelectorView::ContentSelector::sortFiles() @@ -254,7 +253,6 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i oldIndex = index; setGameFileSelected(index, true); - mContentModel->checkForLoadOrderErrors(); } emit signalCurrentGamefileIndexChanged(index);