feat: track instance copies that use links

confirm deleations when other instances link to it

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers 2023-02-15 22:01:27 -07:00
parent 3ec92acfe7
commit 1ca2c59f2e
11 changed files with 213 additions and 2 deletions

View File

@ -40,6 +40,8 @@
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
#include <QRegularExpression> #include <QRegularExpression>
#include <QJsonDocument>
#include <QJsonObject>
#include "settings/INISettingsObject.h" #include "settings/INISettingsObject.h"
#include "settings/Setting.h" #include "settings/Setting.h"
@ -64,6 +66,8 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
m_settings->registerSetting("totalTimePlayed", 0); m_settings->registerSetting("totalTimePlayed", 0);
m_settings->registerSetting("lastTimePlayed", 0); m_settings->registerSetting("lastTimePlayed", 0);
m_settings->registerSetting("linkedInstancesList", "[]");
// Game time override // Game time override
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false); auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride); m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride);
@ -182,6 +186,38 @@ bool BaseInstance::shouldStopOnConsoleOverflow() const
return m_settings->get("ConsoleOverflowStop").toBool(); return m_settings->get("ConsoleOverflowStop").toBool();
} }
QStringList BaseInstance::getLinkedInstances() const
{
return m_settings->getList<QString>("linkedInstancesList");
}
void BaseInstance::setLinkedInstances(const QStringList& list)
{
auto linkedInstancesList = m_settings->getList<QString>("linkedInstancesList");
m_settings->setList("linkedInstancesList", list);
}
void BaseInstance::addLinkedInstanceId(const QString& id)
{
auto linkedInstancesList = m_settings->getList<QString>("linkedInstancesList");
linkedInstancesList.append(id);
setLinkedInstances(linkedInstancesList);
}
bool BaseInstance::removeLinkedInstanceId(const QString& id)
{
auto linkedInstancesList = m_settings->getList<QString>("linkedInstancesList");
int numRemoved = linkedInstancesList.removeAll(id);
setLinkedInstances(linkedInstancesList);
return numRemoved > 0;
}
bool BaseInstance::isLinkedToInstanceId(const QString& id) const
{
auto linkedInstancesList = m_settings->getList<QString>("linkedInstancesList");
return linkedInstancesList.contains(id);
}
void BaseInstance::iconUpdated(QString key) void BaseInstance::iconUpdated(QString key)
{ {
if(iconKey() == key) if(iconKey() == key)

View File

@ -282,6 +282,12 @@ public:
int getConsoleMaxLines() const; int getConsoleMaxLines() const;
bool shouldStopOnConsoleOverflow() const; bool shouldStopOnConsoleOverflow() const;
QStringList getLinkedInstances() const;
void setLinkedInstances(const QStringList& list);
void addLinkedInstanceId(const QString& id);
bool removeLinkedInstanceId(const QString& id);
bool isLinkedToInstanceId(const QString& id) const;
protected: protected:
void changeStatus(Status newStatus); void changeStatus(Status newStatus);

View File

@ -137,6 +137,8 @@ void InstanceCopyTask::copyFinished()
if(!m_keepPlaytime) { if(!m_keepPlaytime) {
inst->resetTimePlayed(); inst->resetTimePlayed();
} }
if (m_useLinks)
inst->addLinkedInstanceId(m_origInstance->id());
emitSucceeded(); emitSucceeded();
} }

View File

@ -129,6 +129,16 @@ QMimeData* InstanceList::mimeData(const QModelIndexList& indexes) const
return mimeData; return mimeData;
} }
QStringList InstanceList::getLinkedInstancesById(const QString &id) const
{
QStringList linkedInstances;
for (auto inst : m_instances) {
if (inst->isLinkedToInstanceId(id))
linkedInstances.append(inst->id());
}
return linkedInstances;
}
int InstanceList::rowCount(const QModelIndex& parent) const int InstanceList::rowCount(const QModelIndex& parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);

View File

@ -154,6 +154,8 @@ public:
QStringList mimeTypes() const override; QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override; QMimeData *mimeData(const QModelIndexList &indexes) const override;
QStringList getLinkedInstancesById(const QString &id) const;
signals: signals:
void dataIsInvalid(); void dataIsInvalid();
void instancesChanged(); void instancesChanged();

View File

@ -183,3 +183,21 @@ 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

@ -19,6 +19,9 @@
#include <QVariant> #include <QVariant>
#include <QIODevice> #include <QIODevice>
#include <QJsonDocument>
#include <QJsonArray>
// Sectionless INI parser (for instance config files) // Sectionless INI parser (for instance config files)
class INIFile : public QMap<QString, QVariant> class INIFile : public QMap<QString, QVariant>
{ {
@ -33,4 +36,36 @@ public:
void set(QString key, QVariant val); void set(QString key, QVariant val);
static QString unescape(QString orig); static QString unescape(QString orig);
static QString escape(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,6 +121,19 @@ 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

@ -19,6 +19,8 @@
#include <QMap> #include <QMap>
#include <QStringList> #include <QStringList>
#include <QVariant> #include <QVariant>
#include <QJsonDocument>
#include <QJsonArray>
#include <memory> #include <memory>
class Setting; class Setting;
@ -142,6 +144,45 @@ 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

@ -1337,6 +1337,20 @@ void MainWindow::on_actionDeleteInstance_triggered()
if (response != QMessageBox::Yes) if (response != QMessageBox::Yes)
return; return;
auto linkedInstances = APPLICATION->instances()->getLinkedInstancesById(id);
if (!linkedInstances.empty()) {
response = CustomMessageBox::selectable(
this, tr("There are linked instances"),
tr("The folowing Instance(s) might reference files in this instance:\n\n"
"%1\n\n"
"Deleting it could break the other instance(s), \n\n"
"Are you sure?").arg(linkedInstances.join("\n")),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No
)->exec();
if (response != QMessageBox::Yes)
return;
}
if (APPLICATION->instances()->trashInstance(id)) { if (APPLICATION->instances()->trashInstance(id)) {
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething()); ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
return; return;

View File

@ -1,7 +1,10 @@
#include <QTest> #include <QTest>
#include <QList>
#include <QVariant>
#include <settings/INIFile.h> #include <settings/INIFile.h>
class IniFileTest : public QObject class IniFileTest : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -52,8 +55,39 @@ slots:
// load // load
INIFile f2; INIFile f2;
f2.loadFile(filename); f2.loadFile(filename);
QCOMPARE(a, f2.get("a","NOT SET").toString()); QCOMPARE(f2.get("a","NOT SET").toString(), a);
QCOMPARE(b, f2.get("b","NOT SET").toString()); QCOMPARE(f2.get("b","NOT SET").toString(), b);
}
void test_SaveLoadLists()
{
QString slist_strings = "[\"a\",\"b\",\"c\"]";
QStringList list_strings = {"a", "b", "c"};
QString slist_numbers = "[1,2,3,10]";
QList<int> list_numbers = {1, 2, 3, 10};
QString filename = "test_SaveLoadLists.ini";
INIFile f;
f.setList("list_strings", list_strings);
f.setList("list_numbers", list_numbers);
f.saveFile(filename);
// load
INIFile f2;
f2.loadFile(filename);
QStringList out_list_strings = f2.getList<QString>("list_strings", QStringList());
qDebug() << "OutStringList" << out_list_strings;
QList<int> out_list_numbers = f2.getList<int>("list_numbers", QList<int>());
qDebug() << "OutNumbersList" << out_list_numbers;
QCOMPARE(f2.get("list_strings","NOT SET").toString(), slist_strings);
QCOMPARE(out_list_strings, list_strings);
QCOMPARE(f2.get("list_numbers","NOT SET").toString(), slist_numbers);
QCOMPARE(out_list_numbers, list_numbers);
} }
}; };