refactor: Move ini to use QSettings && drop get/setList functions

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers 2023-04-29 18:05:48 -07:00
parent 0ce3049579
commit 788fa40c2a
12 changed files with 220 additions and 251 deletions

View File

@ -188,25 +188,25 @@ bool BaseInstance::shouldStopOnConsoleOverflow() const
QStringList BaseInstance::getLinkedInstances() const QStringList BaseInstance::getLinkedInstances() const
{ {
return m_settings->getList<QString>("linkedInstances"); return m_settings->get("linkedInstances").toStringList();
} }
void BaseInstance::setLinkedInstances(const QStringList& list) void BaseInstance::setLinkedInstances(const QStringList& list)
{ {
auto linkedInstances = m_settings->getList<QString>("linkedInstances"); auto linkedInstances = m_settings->get("linkedInstances").toStringList();
m_settings->setList("linkedInstances", list); m_settings->set("linkedInstances", list);
} }
void BaseInstance::addLinkedInstanceId(const QString& id) void BaseInstance::addLinkedInstanceId(const QString& id)
{ {
auto linkedInstances = m_settings->getList<QString>("linkedInstances"); auto linkedInstances = m_settings->get("linkedInstances").toStringList();
linkedInstances.append(id); linkedInstances.append(id);
setLinkedInstances(linkedInstances); setLinkedInstances(linkedInstances);
} }
bool BaseInstance::removeLinkedInstanceId(const QString& id) bool BaseInstance::removeLinkedInstanceId(const QString& id)
{ {
auto linkedInstances = m_settings->getList<QString>("linkedInstances"); auto linkedInstances = m_settings->get("linkedInstances").toStringList();
int numRemoved = linkedInstances.removeAll(id); int numRemoved = linkedInstances.removeAll(id);
setLinkedInstances(linkedInstances); setLinkedInstances(linkedInstances);
return numRemoved > 0; return numRemoved > 0;
@ -214,7 +214,7 @@ bool BaseInstance::removeLinkedInstanceId(const QString& id)
bool BaseInstance::isLinkedToInstanceId(const QString& id) const bool BaseInstance::isLinkedToInstanceId(const QString& id) const
{ {
auto linkedInstances = m_settings->getList<QString>("linkedInstances"); auto linkedInstances = m_settings->get("linkedInstances").toStringList();
return linkedInstances.contains(id); return linkedInstances.contains(id);
} }

View File

@ -26,6 +26,7 @@ set(CORE_SOURCES
MMCZip.cpp MMCZip.cpp
StringUtils.h StringUtils.h
StringUtils.cpp StringUtils.cpp
QVariantUtils.h
RuntimeContext.h RuntimeContext.h
# Basic instance manipulation tasks (derived from InstanceTask) # Basic instance manipulation tasks (derived from InstanceTask)

View File

@ -329,8 +329,7 @@ bool create_link::operator()(const QString& offset, bool dryRun)
/** /**
* @brief Make a list of all the links to make * @brief Make a list of all the links to make
* @param offset subdirectory form src to link to dest * @param offset subdirectory of src to link to dest
* @return if there was an error during the attempt to link
*/ */
void create_link::make_link_list(const QString& offset) void create_link::make_link_list(const QString& offset)
{ {

70
launcher/QVariantUtils.h Normal file
View File

@ -0,0 +1,70 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2023 flowln <flowlnlnln@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QVariant>
#include <QList>
namespace QVariantUtils {
template <typename T>
inline QList<T> toList(QVariant src) {
QVariantList variantList = src.toList();
QList<T> list_t;
list_t.reserve(variantList.size());
for (const QVariant& v : variantList)
{
list_t.append(v.value<T>());
}
return list_t;
}
template <typename T>
inline QVariant fromList(QList<T> val) {
QVariantList variantList;
variantList.reserve(val.size());
for (const T& v : val)
{
variantList.append(v);
}
return variantList;
}
}

View File

@ -1,3 +1,39 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2023 flowln <flowlnlnln@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "StringUtils.h" #include "StringUtils.h"
#include <QUuid> #include <QUuid>

View File

@ -1,3 +1,39 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2023 flowln <flowlnlnln@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once #pragma once
#include <QString> #include <QString>

View File

@ -242,7 +242,7 @@ ModDetails ReadQuiltModInfo(QByteArray contents)
return details; return details;
} }
ModDetails ReadForgeInfo(QByteArray contents) ModDetails ReadForgeInfo(QString fileName)
{ {
ModDetails details; ModDetails details;
// Read the data // Read the data
@ -250,7 +250,7 @@ ModDetails ReadForgeInfo(QByteArray contents)
details.mod_id = "Forge"; details.mod_id = "Forge";
details.homeurl = "http://www.minecraftforge.net/forum/"; details.homeurl = "http://www.minecraftforge.net/forum/";
INIFile ini; INIFile ini;
if (!ini.loadFile(contents)) if (!ini.loadFile(fileName))
return details; return details;
QString major = ini.get("forge.major.number", "0").toString(); QString major = ini.get("forge.major.number", "0").toString();
@ -422,7 +422,7 @@ bool processZIP(Mod& mod, ProcessingLevel level)
return false; return false;
} }
details = ReadForgeInfo(file.readAll()); details = ReadForgeInfo(file.getFileName());
file.close(); file.close();
zip.close(); zip.close();

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2023 flowln <flowlnlnln@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -42,131 +43,50 @@
#include <QSaveFile> #include <QSaveFile>
#include <QDebug> #include <QDebug>
#include <QSettings>
INIFile::INIFile() INIFile::INIFile()
{ {
} }
QString INIFile::unescape(QString orig)
{
QString out;
QChar prev = QChar::Null;
for(auto c: orig)
{
if(prev == '\\')
{
if(c == 'n')
out += '\n';
else if(c == 't')
out += '\t';
else if(c == '#')
out += '#';
else
out += c;
prev = QChar::Null;
}
else
{
if(c == '\\')
{
prev = c;
continue;
}
out += c;
prev = QChar::Null;
}
}
return out;
}
QString INIFile::escape(QString orig)
{
QString out;
for(auto c: orig)
{
if(c == '\n')
out += "\\n";
else if (c == '\t')
out += "\\t";
else if(c == '\\')
out += "\\\\";
else if(c == '#')
out += "\\#";
else
out += c;
}
return out;
}
bool INIFile::saveFile(QString fileName) bool INIFile::saveFile(QString fileName)
{ {
QByteArray outArray; QSettings _settings_obj{ fileName, QSettings::Format::IniFormat };
for (Iterator iter = begin(); iter != end(); iter++) _settings_obj.setFallbacksEnabled(false);
{
QString value = iter.value().toString(); for (Iterator iter = begin(); iter != end(); iter++)
value = escape(value); _settings_obj.setValue(iter.key(), iter.value());
outArray.append(iter.key().toUtf8());
outArray.append('='); _settings_obj.sync();
outArray.append(value.toUtf8());
outArray.append('\n'); if (auto status = _settings_obj.status(); status != QSettings::Status::NoError) {
} // Shouldn't be possible!
Q_ASSERT(status != QSettings::Status::FormatError);
if (status == QSettings::Status::AccessError)
qCritical() << "An access error occurred (e.g. trying to write to a read-only file).";
try
{
FS::write(fileName, outArray);
}
catch (const Exception &e)
{
qCritical() << e.what();
return false; return false;
} }
return true; return true;
} }
bool INIFile::loadFile(QString fileName) bool INIFile::loadFile(QString fileName)
{ {
QFile file(fileName); QSettings _settings_obj{ fileName, QSettings::Format::IniFormat };
if (!file.open(QIODevice::ReadOnly)) _settings_obj.setFallbacksEnabled(false);
if (auto status = _settings_obj.status(); status != QSettings::Status::NoError) {
if (status == QSettings::Status::AccessError)
qCritical() << "An access error occurred (e.g. trying to write to a read-only file).";
if (status == QSettings::Status::FormatError)
qCritical() << "A format error occurred (e.g. loading a malformed INI file).";
return false; return false;
bool success = loadFile(file.readAll());
file.close();
return success;
}
bool INIFile::loadFile(QByteArray file)
{
QTextStream in(file);
#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
in.setCodec("UTF-8");
#endif
QStringList lines = in.readAll().split('\n');
for (int i = 0; i < lines.count(); i++)
{
QString &lineRaw = lines[i];
// Ignore comments.
int commentIndex = 0;
QString line = lineRaw;
// Search for comments until no more escaped # are available
while((commentIndex = line.indexOf('#', commentIndex + 1)) != -1) {
if(commentIndex > 0 && line.at(commentIndex - 1) == '\\') {
continue;
}
line = line.left(lineRaw.indexOf('#')).trimmed();
} }
int eqPos = line.indexOf('='); for (auto&& key : _settings_obj.allKeys())
if (eqPos == -1) insert(key, _settings_obj.value(key));
continue;
QString key = line.left(eqPos).trimmed();
QString valueStr = line.right(line.length() - eqPos - 1).trimmed();
valueStr = unescape(valueStr);
QVariant value(valueStr);
this->operator[](key) = value;
}
return true; return true;
} }
@ -184,20 +104,3 @@ void INIFile::set(QString key, QVariant val)
this->operator[](key) = val; this->operator[](key) = val;
} }
void INIFile::setList(QString key, QVariantList val)
{
QString stringList = QJsonDocument(QVariant(val).toJsonArray()).toJson(QJsonDocument::Compact);
this->operator[](key) = stringList;
}
QVariantList INIFile::getList(QString key, QVariantList def) const
{
if (this->contains(key)) {
auto src = this->operator[](key);
return QJsonDocument::fromJson(src.toByteArray()).toVariant().toList();
}
return def;
}

View File

@ -1,4 +1,25 @@
/* Copyright 2013-2021 MultiMC Contributors // SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2023 flowln <flowlnlnln@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,44 +49,9 @@ class INIFile : public QMap<QString, QVariant>
public: public:
explicit INIFile(); explicit INIFile();
bool loadFile(QByteArray file);
bool loadFile(QString fileName); bool loadFile(QString fileName);
bool saveFile(QString fileName); bool saveFile(QString fileName);
QVariant get(QString key, QVariant def) const; QVariant get(QString key, QVariant def) const;
void set(QString key, QVariant val); void set(QString key, QVariant val);
static QString unescape(QString orig);
static QString escape(QString orig);
void setList(QString key, QVariantList val);
template <typename T> void setList(QString key, QList<T> val)
{
QVariantList variantList;
variantList.reserve(val.size());
for (const T& v : val)
{
variantList.append(v);
}
this->setList(key, variantList);
}
QVariantList getList(QString key, QVariantList def) const;
template <typename T> QList<T> getList(QString key, QList<T> def) const
{
if (this->contains(key)) {
QVariant src = this->operator[](key);
QVariantList variantList = QJsonDocument::fromJson(src.toByteArray()).toVariant().toList();
QList<T>TList;
TList.reserve(variantList.size());
for (const QVariant& v : variantList)
{
TList.append(v.value<T>());
}
return TList;
}
return def;
}
}; };

View File

@ -121,19 +121,6 @@ bool SettingsObject::contains(const QString &id)
return m_settings.contains(id); return m_settings.contains(id);
} }
bool SettingsObject::setList(const QString &id, QVariantList value)
{
QString stringList = QJsonDocument(QVariant(value).toJsonArray()).toJson(QJsonDocument::Compact);
return set(id, stringList);
}
QVariantList SettingsObject::getList(const QString &id)
{
QVariant value = this->get(id);
return QJsonDocument::fromJson(value.toByteArray()).toVariant().toList();
}
bool SettingsObject::reload() bool SettingsObject::reload()
{ {
for (auto setting : m_settings.values()) for (auto setting : m_settings.values())

View File

@ -144,45 +144,6 @@ public:
*/ */
bool contains(const QString &id); bool contains(const QString &id);
/*!
* \brief Sets the value of the setting with the given ID with a json list.
* If no setting with the given ID exists, returns false
* \param id The ID of the setting to change.
* \param value The new value of the setting.
*/
bool setList(const QString &id, QVariantList value);
template <typename T> bool setList(const QString &id, QList<T> val)
{
QVariantList variantList;
variantList.reserve(val.size());
for (const T& v : val)
{
variantList.append(v);
}
return setList(id, variantList);
}
/**
* \brief Gets the value of the setting with the given ID as if it were a json list.
* \param id The ID of the setting to change.
* \return The setting's value as a QVariantList.
* If no setting with the given ID exists, returns an empty QVariantList.
*/
QVariantList getList(const QString &id);
template <typename T> QList<T> getList(const QString &id)
{
QVariantList variantList = this->getList(id);
QList<T>TList;
TList.reserve(variantList.size());
for (const QVariant& v : variantList)
{
TList.append(v.value<T>());
}
return TList;
}
/*! /*!
* \brief Reloads the settings and emit signals for changed settings * \brief Reloads the settings and emit signals for changed settings
* \return True if reloading was successful * \return True if reloading was successful

View File

@ -4,6 +4,7 @@
#include <QVariant> #include <QVariant>
#include <settings/INIFile.h> #include <settings/INIFile.h>
#include <QVariantUtils.h>
class IniFileTest : public QObject class IniFileTest : public QObject
{ {
@ -30,15 +31,6 @@ slots:
QTest::newRow("Escape sequences 2") << "\"\n\n\""; QTest::newRow("Escape sequences 2") << "\"\n\n\"";
QTest::newRow("Hashtags") << "some data#something"; QTest::newRow("Hashtags") << "some data#something";
} }
void test_Escape()
{
QFETCH(QString, through);
QString there = INIFile::escape(through);
QString back = INIFile::unescape(there);
QCOMPARE(back, through);
}
void test_SaveLoad() void test_SaveLoad()
{ {
@ -61,32 +53,30 @@ slots:
void test_SaveLoadLists() void test_SaveLoadLists()
{ {
QString slist_strings = "[\"a\",\"b\",\"c\"]"; QString slist_strings = "(\"a\",\"b\",\"c\")";
QStringList list_strings = {"a", "b", "c"}; QStringList list_strings = {"a", "b", "c"};
QString slist_numbers = "[1,2,3,10]"; QString slist_numbers = "(1,2,3,10)";
QList<int> list_numbers = {1, 2, 3, 10}; QList<int> list_numbers = {1, 2, 3, 10};
QString filename = "test_SaveLoadLists.ini"; QString filename = "test_SaveLoadLists.ini";
INIFile f; INIFile f;
f.setList("list_strings", list_strings); f.set("list_strings", list_strings);
f.setList("list_numbers", list_numbers); f.set("list_numbers", QVariantUtils::fromList(list_numbers));
f.saveFile(filename); f.saveFile(filename);
// load // load
INIFile f2; INIFile f2;
f2.loadFile(filename); f2.loadFile(filename);
QStringList out_list_strings = f2.getList<QString>("list_strings", QStringList()); QStringList out_list_strings = f2.get("list_strings", QStringList()).toStringList();
qDebug() << "OutStringList" << out_list_strings; qDebug() << "OutStringList" << out_list_strings;
QList<int> out_list_numbers = f2.getList<int>("list_numbers", QList<int>()); QList<int> out_list_numbers = QVariantUtils::toList<int>(f2.get("list_numbers", QVariantUtils::fromList(QList<int>())));
qDebug() << "OutNumbersList" << out_list_numbers; qDebug() << "OutNumbersList" << out_list_numbers;
QCOMPARE(f2.get("list_strings","NOT SET").toString(), slist_strings);
QCOMPARE(out_list_strings, list_strings); QCOMPARE(out_list_strings, list_strings);
QCOMPARE(f2.get("list_numbers","NOT SET").toString(), slist_numbers);
QCOMPARE(out_list_numbers, list_numbers); QCOMPARE(out_list_numbers, list_numbers);
} }
}; };