Merge branch 'dont-redraw-the-whole-gui-every-time-we-change-the-tiniest-thing' into 'master'
Some checks failed
Build and test / Ubuntu (push) Has been cancelled
Build and test / MacOS (push) Has been cancelled
Build and test / Read .env file and expose it as output (push) Has been cancelled
Build and test / Windows (2019) (push) Has been cancelled
Build and test / Windows (2022) (push) Has been cancelled

Be more careful when we tell Qt that data has changed

Closes #8405

See merge request OpenMW/openmw!4621
This commit is contained in:
psi29a 2025-04-09 11:19:32 +00:00
commit ea8369eff0
6 changed files with 37 additions and 50 deletions

View file

@ -8,6 +8,7 @@
#include <QList>
#include <QMessageBox>
#include <QPair>
#include <QProgressDialog>
#include <QPushButton>
#include <algorithm>
@ -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<QString> 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)");
}

View file

@ -1,6 +1,7 @@
#include "gamesettings.hpp"
#include <QDir>
#include <QProgressDialog>
#include <QRegularExpression>
#include <components/files/configurationmanager.hpp>
@ -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();

View file

@ -10,6 +10,7 @@
#include <QDataStream>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFont>
#include <QIODevice>
@ -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::LoadOrderError> ContentSelectorModel::ContentModel::checkForLoadOrderErrors(
@ -791,11 +767,12 @@ QList<ContentSelectorModel::LoadOrderError> 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("<b>");
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 });
}

View file

@ -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<const EsmFile*> mCheckedFiles;
QHash<QString, bool> mNewFiles;
QSet<QString> mPluginsWithLoadOrderError;
QString mEncoding;
QIcon mWarningIcon;
QIcon mErrorIcon;

View file

@ -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())

View file

@ -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);