mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 14:59:54 +00:00
Some launcher fixes
I tried to fix https://gitlab.com/OpenMW/openmw/-/issues/8080 by making it so that instead of crashing, we showed an error. In doing so, I discovered some problems with plugin sorting and the refresh button, like: * it forgetting the non-user content files somewhere * nothing guaranteeing that built-in content files stay at the top of the list and them only being there because the first data directory that provides them is usually the first data directory * it forgetting the non-user content files somewhere else * it looking like it'd forget any kind of non-user setting under certain circumstances I fixed those problems too
This commit is contained in:
parent
11c21c28bf
commit
cd7941dc9f
10 changed files with 72 additions and 23 deletions
|
@ -40,9 +40,8 @@ namespace Config
|
|||
|
||||
inline void setValue(const QString& key, const SettingValue& value)
|
||||
{
|
||||
mSettings.remove(key);
|
||||
remove(key);
|
||||
mSettings.insert(key, value);
|
||||
mUserSettings.remove(key);
|
||||
if (isUserSetting(value))
|
||||
mUserSettings.insert(key, value);
|
||||
}
|
||||
|
@ -63,7 +62,14 @@ namespace Config
|
|||
|
||||
inline void remove(const QString& key)
|
||||
{
|
||||
mSettings.remove(key);
|
||||
// simplify to removeIf when Qt5 goes
|
||||
for (auto itr = mSettings.lowerBound(key); itr != mSettings.upperBound(key);)
|
||||
{
|
||||
if (isUserSetting(*itr))
|
||||
itr = mSettings.erase(itr);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
mUserSettings.remove(key);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
#include <components/files/openfile.hpp>
|
||||
#include <components/files/qtconversion.hpp>
|
||||
|
||||
ContentSelectorModel::ContentModel::ContentModel(QObject* parent, QIcon& warningIcon, bool showOMWScripts)
|
||||
ContentSelectorModel::ContentModel::ContentModel(QObject* parent, QIcon& warningIcon, QIcon& errorIcon, bool showOMWScripts)
|
||||
: QAbstractTableModel(parent)
|
||||
, mWarningIcon(warningIcon)
|
||||
, mErrorIcon(errorIcon)
|
||||
, mShowOMWScripts(showOMWScripts)
|
||||
, mMimeType("application/omwcontent")
|
||||
, mMimeTypes(QStringList() << mMimeType)
|
||||
|
@ -169,7 +170,12 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int
|
|||
{
|
||||
case Qt::DecorationRole:
|
||||
{
|
||||
return isLoadOrderError(file) ? mWarningIcon : QVariant();
|
||||
if (file->isMissing())
|
||||
return mErrorIcon;
|
||||
else if (isLoadOrderError(file))
|
||||
return mWarningIcon;
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
case Qt::FontRole:
|
||||
|
@ -595,10 +601,32 @@ void ContentSelectorModel::ContentModel::sortFiles()
|
|||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
|
||||
int firstModifiable = 0;
|
||||
while (firstModifiable < mFiles.size()
|
||||
&& (mFiles.at(firstModifiable)->builtIn() || mFiles.at(firstModifiable)->fromAnotherConfigFile()))
|
||||
++firstModifiable;
|
||||
// make both Qt5 (int) and Qt6 (qsizetype aka size_t) happy
|
||||
using index_t = ContentFileList::size_type;
|
||||
|
||||
// ensure built-in are first
|
||||
index_t firstModifiable = 0;
|
||||
for (index_t i = 0; i < mFiles.length(); ++i)
|
||||
{
|
||||
if (mFiles.at(i)->builtIn())
|
||||
mFiles.move(i, firstModifiable++);
|
||||
}
|
||||
|
||||
// then non-user content
|
||||
for (const auto& filename : mNonUserContent)
|
||||
{
|
||||
const EsmFile* file = item(filename);
|
||||
int filePosition = indexFromItem(file).row();
|
||||
if (filePosition >= 0)
|
||||
mFiles.move(filePosition, firstModifiable++);
|
||||
else
|
||||
{
|
||||
// the file is not in the VFS, and will be displayed with an error
|
||||
auto missingFile = std::make_unique<EsmFile>(filename);
|
||||
missingFile->setFromAnotherConfigFile(true);
|
||||
mFiles.insert(firstModifiable++, missingFile.release());
|
||||
}
|
||||
}
|
||||
|
||||
// For the purposes of dependency sort we'll hallucinate that Bloodmoon is dependent on Tribunal
|
||||
const EsmFile* tribunalFile = item("Tribunal.esm");
|
||||
|
@ -669,20 +697,10 @@ void ContentSelectorModel::ContentModel::setNonUserContent(const QStringList& fi
|
|||
{
|
||||
mNonUserContent.clear();
|
||||
for (const auto& file : fileList)
|
||||
mNonUserContent.insert(file.toLower());
|
||||
mNonUserContent.append(file.toLower());
|
||||
for (auto* file : mFiles)
|
||||
file->setFromAnotherConfigFile(mNonUserContent.contains(file->fileName().toLower()));
|
||||
|
||||
auto insertPosition
|
||||
= std::ranges::find_if(mFiles, [](const EsmFile* file) { return !file->builtIn(); }) - mFiles.begin();
|
||||
|
||||
for (const auto& filepath : fileList)
|
||||
{
|
||||
const EsmFile* file = item(filepath);
|
||||
int filePosition = indexFromItem(file).row();
|
||||
mFiles.move(filePosition, insertPosition++);
|
||||
}
|
||||
|
||||
sortFiles();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace ContentSelectorModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ContentModel(QObject* parent, QIcon& warningIcon, bool showOMWScripts);
|
||||
explicit ContentModel(QObject* parent, QIcon& warningIcon, QIcon& errorIcon, bool showOMWScripts);
|
||||
~ContentModel();
|
||||
|
||||
void setEncoding(const QString& encoding);
|
||||
|
@ -86,12 +86,13 @@ namespace ContentSelectorModel
|
|||
|
||||
const EsmFile* mGameFile;
|
||||
ContentFileList mFiles;
|
||||
QSet<QString> mNonUserContent;
|
||||
QStringList mNonUserContent;
|
||||
std::set<const EsmFile*> mCheckedFiles;
|
||||
QHash<QString, bool> mNewFiles;
|
||||
QSet<QString> mPluginsWithLoadOrderError;
|
||||
QString mEncoding;
|
||||
QIcon mWarningIcon;
|
||||
QIcon mErrorIcon;
|
||||
bool mShowOMWScripts;
|
||||
|
||||
QString mErrorToolTips[ContentSelectorModel::LoadOrderError::ErrorCode_LoadOrder]
|
||||
|
|
|
@ -55,12 +55,15 @@ namespace ContentSelectorModel
|
|||
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; }
|
||||
QString toolTip() const
|
||||
{
|
||||
if (isMissing())
|
||||
return tr("<b>This file is specified in a non-user config file, but does not exist in the VFS.</b>");
|
||||
QString tooltip = mTooltipTemlate.arg(mAuthor)
|
||||
.arg(mVersion)
|
||||
.arg(mModified.toString(Qt::ISODate))
|
||||
|
|
|
@ -32,7 +32,8 @@ ContentSelectorView::ContentSelector::~ContentSelector() = default;
|
|||
void ContentSelectorView::ContentSelector::buildContentModel(bool showOMWScripts)
|
||||
{
|
||||
QIcon warningIcon(ui->addonView->style()->standardIcon(QStyle::SP_MessageBoxWarning));
|
||||
mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon, showOMWScripts);
|
||||
QIcon errorIcon(ui->addonView->style()->standardIcon(QStyle::SP_MessageBoxCritical));
|
||||
mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon, errorIcon, showOMWScripts);
|
||||
}
|
||||
|
||||
void ContentSelectorView::ContentSelector::buildGameFileView()
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
<source><br/><b>This content file cannot be disabled because it is enabled in a config file other than the user one.</b><br/></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>This file is specified in a non-user config file, but does not exist in the VFS.</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ContentSelectorView::ContentSelector</name>
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
<source><b>Author:</b> %1<br/><b>Format version:</b> %2<br/><b>Modified:</b> %3<br/><b>Path:</b><br/>%4<br/><br/><b>Description:</b><br/>%5<br/><br/><b>Dependencies: </b>%6<br/></source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>This file is specified in a non-user config file, but does not exist in the VFS.</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ContentSelectorView::ContentSelector</name>
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
<source><br/><b>This content file cannot be disabled because it is enabled in a config file other than the user one.</b><br/></source>
|
||||
<translation><br/><b>Ce fichier de contenu ne peut être désactivé, car il est activé par un fichier de configuration non contrôlé par l'utilisateur.</b><br/></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>This file is specified in a non-user config file, but does not exist in the VFS.</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ContentSelectorView::ContentSelector</name>
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
<source><br/><b>This content file cannot be disabled because it is enabled in a config file other than the user one.</b><br/></source>
|
||||
<translation><br/><b>Этот файл данных не может быть отключен, потому что он включен в файле с настройками, не являющемся пользовательским.</b><br/></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>This file is specified in a non-user config file, but does not exist in the VFS.</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ContentSelectorView::ContentSelector</name>
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
<source><br/><b>This content file cannot be disabled because it is enabled in a config file other than the user one.</b><br/></source>
|
||||
<translation><br/><b>Denna innehållsfil kan inte inaktiveras då den är en aktiverad i en annan konfigurationsfil än användarens.</b><br/></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>This file is specified in a non-user config file, but does not exist in the VFS.</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ContentSelectorView::ContentSelector</name>
|
||||
|
|
Loading…
Reference in a new issue