mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-28 21:07:59 +03:00
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
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:
commit
ea8369eff0
6 changed files with 37 additions and 50 deletions
|
@ -8,6 +8,7 @@
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
#include <QProgressDialog>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -351,9 +352,17 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||||
if (!resourcesVfs.isEmpty())
|
if (!resourcesVfs.isEmpty())
|
||||||
directories.insert(0, { resourcesVfs });
|
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;
|
std::unordered_set<QString> visitedDirectories;
|
||||||
for (const Config::SettingValue& currentDir : directories)
|
for (const Config::SettingValue& currentDir : directories)
|
||||||
{
|
{
|
||||||
|
progressBar.setValue(progressBar.value() + 1);
|
||||||
|
|
||||||
if (!visitedDirectories.insert(currentDir.value).second)
|
if (!visitedDirectories.insert(currentDir.value).second)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -402,7 +411,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||||
// Add a "data file" icon if the directory contains a content file
|
// Add a "data file" icon if the directory contains a content file
|
||||||
if (mSelector->containsDataFiles(currentDir.value))
|
if (mSelector->containsDataFiles(currentDir.value))
|
||||||
{
|
{
|
||||||
item->setIcon(QIcon(":/images/openmw-plugin.png"));
|
item->setIcon(containsDataIcon);
|
||||||
|
|
||||||
tooltip << tr("Contains content file(s)");
|
tooltip << tr("Contains content file(s)");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "gamesettings.hpp"
|
#include "gamesettings.hpp"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QProgressDialog>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
@ -37,8 +38,13 @@ void Config::GameSettings::validatePaths()
|
||||||
|
|
||||||
mDataDirs.clear();
|
mDataDirs.clear();
|
||||||
|
|
||||||
|
QProgressDialog progressBar("Validating paths", {}, 0, paths.count() + 1);
|
||||||
|
progressBar.setWindowModality(Qt::WindowModal);
|
||||||
|
progressBar.setValue(0);
|
||||||
|
|
||||||
for (const auto& dataDir : paths)
|
for (const auto& dataDir : paths)
|
||||||
{
|
{
|
||||||
|
progressBar.setValue(progressBar.value() + 1);
|
||||||
if (QDir(dataDir.value).exists())
|
if (QDir(dataDir.value).exists())
|
||||||
{
|
{
|
||||||
SettingValue copy = dataDir;
|
SettingValue copy = dataDir;
|
||||||
|
@ -50,6 +56,8 @@ void Config::GameSettings::validatePaths()
|
||||||
// Do the same for data-local
|
// Do the same for data-local
|
||||||
const QString& local = mSettings.value(QString("data-local")).value;
|
const QString& local = mSettings.value(QString("data-local")).value;
|
||||||
|
|
||||||
|
progressBar.setValue(progressBar.value() + 1);
|
||||||
|
|
||||||
if (!local.isEmpty() && QDir(local).exists())
|
if (!local.isEmpty() && QDir(local).exists())
|
||||||
{
|
{
|
||||||
mDataLocal = QDir(local).canonicalPath();
|
mDataLocal = QDir(local).canonicalPath();
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QDirIterator>
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
|
|
||||||
|
@ -78,14 +79,10 @@ ContentSelectorModel::EsmFile* ContentSelectorModel::ContentModel::item(int row)
|
||||||
}
|
}
|
||||||
const ContentSelectorModel::EsmFile* ContentSelectorModel::ContentModel::item(const QString& name) const
|
const ContentSelectorModel::EsmFile* ContentSelectorModel::ContentModel::item(const QString& name) const
|
||||||
{
|
{
|
||||||
EsmFile::FileProperty fp = EsmFile::FileProperty_FileName;
|
bool path = name.contains('/');
|
||||||
|
|
||||||
if (name.contains('/'))
|
|
||||||
fp = EsmFile::FileProperty_FilePath;
|
|
||||||
|
|
||||||
for (const EsmFile* file : mFiles)
|
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 file;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -310,7 +307,6 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
|
||||||
{
|
{
|
||||||
setCheckState(file->filePath(), success);
|
setCheckState(file->filePath(), success);
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
checkForLoadOrderErrors();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return success;
|
return success;
|
||||||
|
@ -425,7 +421,6 @@ bool ContentSelectorModel::ContentModel::dropMimeData(
|
||||||
|
|
||||||
dataChanged(index(minRow, 0), index(maxRow, 0));
|
dataChanged(index(minRow, 0), index(maxRow, 0));
|
||||||
// at this point we know that drag and drop has finished.
|
// at this point we know that drag and drop has finished.
|
||||||
checkForLoadOrderErrors();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -552,15 +547,13 @@ void ContentSelectorModel::ContentModel::addFiles(const QString& path, bool newf
|
||||||
|
|
||||||
bool ContentSelectorModel::ContentModel::containsDataFiles(const QString& path)
|
bool ContentSelectorModel::ContentModel::containsDataFiles(const QString& path)
|
||||||
{
|
{
|
||||||
QDir dir(path);
|
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
filters << "*.esp"
|
filters << "*.esp"
|
||||||
<< "*.esm"
|
<< "*.esm"
|
||||||
<< "*.omwgame"
|
<< "*.omwgame"
|
||||||
<< "*.omwaddon";
|
<< "*.omwaddon";
|
||||||
dir.setNameFilters(filters);
|
QDirIterator it(path, filters, QDir::Files | QDir::NoDotAndDotDot);
|
||||||
|
return it.hasNext();
|
||||||
return dir.entryList().count() != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorModel::ContentModel::clearFiles()
|
void ContentSelectorModel::ContentModel::clearFiles()
|
||||||
|
@ -707,12 +700,13 @@ void ContentSelectorModel::ContentModel::setNonUserContent(const QStringList& fi
|
||||||
|
|
||||||
bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile* file) const
|
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)
|
void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileList)
|
||||||
{
|
{
|
||||||
mPluginsWithLoadOrderError.clear();
|
|
||||||
int previousPosition = -1;
|
int previousPosition = -1;
|
||||||
for (const QString& filepath : fileList)
|
for (const QString& filepath : fileList)
|
||||||
{
|
{
|
||||||
|
@ -725,7 +719,6 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL
|
||||||
if (filePosition < previousPosition)
|
if (filePosition < previousPosition)
|
||||||
{
|
{
|
||||||
mFiles.move(filePosition, previousPosition);
|
mFiles.move(filePosition, previousPosition);
|
||||||
emit dataChanged(index(filePosition, 0, QModelIndex()), index(previousPosition, 0, QModelIndex()));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -733,24 +726,7 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkForLoadOrderErrors();
|
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::checkForLoadOrderErrors(
|
QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::checkForLoadOrderErrors(
|
||||||
|
@ -791,11 +767,12 @@ QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::
|
||||||
|
|
||||||
QString ContentSelectorModel::ContentModel::toolTip(const EsmFile* file) const
|
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>");
|
QString text("<b>");
|
||||||
int index = indexFromItem(item(file->filePath())).row();
|
for (const LoadOrderError& error : errors)
|
||||||
for (const LoadOrderError& error : checkForLoadOrderErrors(file, index))
|
|
||||||
{
|
{
|
||||||
assert(error.errorCode() != LoadOrderError::ErrorCode::ErrorCode_None);
|
assert(error.errorCode() != LoadOrderError::ErrorCode::ErrorCode_None);
|
||||||
|
|
||||||
|
@ -900,7 +877,6 @@ ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checke
|
||||||
|
|
||||||
void ContentSelectorModel::ContentModel::uncheckAll()
|
void ContentSelectorModel::ContentModel::uncheckAll()
|
||||||
{
|
{
|
||||||
emit layoutAboutToBeChanged();
|
|
||||||
mCheckedFiles.clear();
|
mCheckedFiles.clear();
|
||||||
emit layoutChanged();
|
emit dataChanged(index(0, 0), index(rowCount(), columnCount()), { Qt::CheckStateRole, Qt::UserRole + 1 });
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,9 +69,6 @@ namespace ContentSelectorModel
|
||||||
|
|
||||||
void refreshModel();
|
void refreshModel();
|
||||||
|
|
||||||
/// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues
|
|
||||||
void checkForLoadOrderErrors();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addFile(EsmFile* file);
|
void addFile(EsmFile* file);
|
||||||
|
|
||||||
|
@ -89,7 +86,6 @@ namespace ContentSelectorModel
|
||||||
QStringList mNonUserContent;
|
QStringList mNonUserContent;
|
||||||
std::set<const EsmFile*> mCheckedFiles;
|
std::set<const EsmFile*> mCheckedFiles;
|
||||||
QHash<QString, bool> mNewFiles;
|
QHash<QString, bool> mNewFiles;
|
||||||
QSet<QString> mPluginsWithLoadOrderError;
|
|
||||||
QString mEncoding;
|
QString mEncoding;
|
||||||
QIcon mWarningIcon;
|
QIcon mWarningIcon;
|
||||||
QIcon mErrorIcon;
|
QIcon mErrorIcon;
|
||||||
|
|
|
@ -48,18 +48,18 @@ namespace ContentSelectorModel
|
||||||
void addGameFile(const QString& name) { mGameFiles.append(name); }
|
void addGameFile(const QString& name) { mGameFiles.append(name); }
|
||||||
QVariant fileProperty(const FileProperty prop) const;
|
QVariant fileProperty(const FileProperty prop) const;
|
||||||
|
|
||||||
QString fileName() const { return mFileName; }
|
const QString& fileName() const { return mFileName; }
|
||||||
QString author() const { return mAuthor; }
|
const QString& author() const { return mAuthor; }
|
||||||
QDateTime modified() const { return mModified; }
|
QDateTime modified() const { return mModified; }
|
||||||
QString formatVersion() const { return mVersion; }
|
const QString& formatVersion() const { return mVersion; }
|
||||||
QString filePath() const { return mPath; }
|
const QString& filePath() const { return mPath; }
|
||||||
bool builtIn() const { return mBuiltIn; }
|
bool builtIn() const { return mBuiltIn; }
|
||||||
bool fromAnotherConfigFile() const { return mFromAnotherConfigFile; }
|
bool fromAnotherConfigFile() const { return mFromAnotherConfigFile; }
|
||||||
bool isMissing() const { return mPath.isEmpty(); }
|
bool isMissing() const { return mPath.isEmpty(); }
|
||||||
|
|
||||||
/// @note Contains file names, not paths.
|
/// @note Contains file names, not paths.
|
||||||
const QStringList& gameFiles() const { return mGameFiles; }
|
const QStringList& gameFiles() const { return mGameFiles; }
|
||||||
QString description() const { return mDescription; }
|
const QString& description() const { return mDescription; }
|
||||||
QString toolTip() const
|
QString toolTip() const
|
||||||
{
|
{
|
||||||
if (isMissing())
|
if (isMissing())
|
||||||
|
|
|
@ -211,7 +211,6 @@ void ContentSelectorView::ContentSelector::addFiles(const QString& path, bool ne
|
||||||
ui->gameFileView->setCurrentIndex(0);
|
ui->gameFileView->setCurrentIndex(0);
|
||||||
|
|
||||||
mContentModel->uncheckAll();
|
mContentModel->uncheckAll();
|
||||||
mContentModel->checkForLoadOrderErrors();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorView::ContentSelector::sortFiles()
|
void ContentSelectorView::ContentSelector::sortFiles()
|
||||||
|
@ -254,7 +253,6 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i
|
||||||
oldIndex = index;
|
oldIndex = index;
|
||||||
|
|
||||||
setGameFileSelected(index, true);
|
setGameFileSelected(index, true);
|
||||||
mContentModel->checkForLoadOrderErrors();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit signalCurrentGamefileIndexChanged(index);
|
emit signalCurrentGamefileIndexChanged(index);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue