SCRATCH things and stuff, related to grou saving

This commit is contained in:
Petr Mrázek 2018-07-23 00:49:26 +02:00
parent 12f2716f31
commit 7b439c85c0
9 changed files with 77 additions and 46 deletions

View File

@ -99,16 +99,11 @@ void BaseInstance::iconUpdated(QString key)
void BaseInstance::invalidate() void BaseInstance::invalidate()
{ {
changeStatus(Status::Gone); changeStatus(Status::Gone);
m_group = QString();
emit groupChanged();
qDebug() << "Instance" << id() << "has been invalidated."; qDebug() << "Instance" << id() << "has been invalidated.";
} }
void BaseInstance::nuke()
{
changeStatus(Status::Gone);
qDebug() << "Instance" << id() << "has been deleted by MultiMC.";
FS::deletePath(instanceRoot());
}
void BaseInstance::changeStatus(BaseInstance::Status newStatus) void BaseInstance::changeStatus(BaseInstance::Status newStatus)
{ {
Status status = currentStatus(); Status status = currentStatus();

View File

@ -72,10 +72,6 @@ public:
virtual void init() = 0; virtual void init() = 0;
virtual void saveNow() = 0; virtual void saveNow() = 0;
/// nuke thoroughly - deletes the instance contents, notifies the list/model which is
/// responsible of cleaning up the husk
void nuke();
/*** /***
* the instance has been invalidated - it is no longer tracked by MultiMC for some reason, * the instance has been invalidated - it is no longer tracked by MultiMC for some reason,
* but it has not necessarily been deleted. * but it has not necessarily been deleted.

View File

@ -8,6 +8,7 @@
#include "multimc_logic_export.h" #include "multimc_logic_export.h"
using InstanceId = QString; using InstanceId = QString;
using GroupId = QString;
using InstanceLocator = std::pair<InstancePtr, int>; using InstanceLocator = std::pair<InstancePtr, int>;
enum class InstCreateError enum class InstCreateError

View File

@ -48,6 +48,7 @@ FolderInstanceProvider::FolderInstanceProvider(SettingsObjectPtr settings, const
QList< InstanceId > FolderInstanceProvider::discoverInstances() QList< InstanceId > FolderInstanceProvider::discoverInstances()
{ {
qDebug() << "Discovering instances in" << m_instDir;
QList<InstanceId> out; QList<InstanceId> out;
QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks); QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks);
while (iter.hasNext()) while (iter.hasNext())
@ -71,6 +72,8 @@ QList< InstanceId > FolderInstanceProvider::discoverInstances()
out.append(id); out.append(id);
qDebug() << "Found instance ID" << id; qDebug() << "Found instance ID" << id;
} }
instanceSet = out.toSet();
m_instancesProbed = true;
return out; return out;
} }
@ -115,6 +118,12 @@ InstancePtr FolderInstanceProvider::loadInstance(const InstanceId& id)
void FolderInstanceProvider::saveGroupList() void FolderInstanceProvider::saveGroupList()
{ {
qDebug() << "Will save group list now.";
if(!m_instancesProbed)
{
qDebug() << "Group saving prevented because we don't know the full list of instances yet.";
return;
}
WatchLock foo(m_watcher, m_instDir); WatchLock foo(m_watcher, m_instDir);
QString groupFileName = m_instDir + "/instgroups.json"; QString groupFileName = m_instDir + "/instgroups.json";
QMap<QString, QSet<QString>> reverseGroupMap; QMap<QString, QSet<QString>> reverseGroupMap;
@ -124,6 +133,11 @@ void FolderInstanceProvider::saveGroupList()
QString group = iter.value(); QString group = iter.value();
if (group.isEmpty()) if (group.isEmpty())
continue; continue;
if(!instanceSet.contains(id))
{
qDebug() << "Skipping saving missing instance" << id << "to groups list.";
continue;
}
if (!reverseGroupMap.count(group)) if (!reverseGroupMap.count(group))
{ {
@ -159,6 +173,7 @@ void FolderInstanceProvider::saveGroupList()
try try
{ {
FS::write(groupFileName, doc.toJson()); FS::write(groupFileName, doc.toJson());
qDebug() << "Group list saved.";
} }
catch (const FS::FileSystemException &e) catch (const FS::FileSystemException &e)
{ {
@ -168,6 +183,7 @@ void FolderInstanceProvider::saveGroupList()
void FolderInstanceProvider::loadGroupList() void FolderInstanceProvider::loadGroupList()
{ {
qDebug() << "Will load group list now.";
QSet<QString> groupSet; QSet<QString> groupSet;
QString groupFileName = m_instDir + "/instgroups.json"; QString groupFileName = m_instDir + "/instgroups.json";
@ -262,6 +278,7 @@ void FolderInstanceProvider::loadGroupList()
} }
m_groupsLoaded = true; m_groupsLoaded = true;
emit groupsChanged(groupSet); emit groupsChanged(groupSet);
qDebug() << "Group list loaded.";
} }
void FolderInstanceProvider::groupChanged() void FolderInstanceProvider::groupChanged()
@ -309,6 +326,7 @@ static void clamp(T& current, T min, T max)
} }
} }
namespace {
// List of numbers from min to max. Next is exponent times bigger than previous. // List of numbers from min to max. Next is exponent times bigger than previous.
class ExponentialSeries class ExponentialSeries
{ {
@ -335,12 +353,8 @@ public:
unsigned m_max; unsigned m_max;
unsigned m_exponent; unsigned m_exponent;
}; };
}
/*
* WHY: the whole reason why this uses an exponential backoff retry scheme is antivirus on Windows.
* Basically, it starts messing things up while MultiMC is extracting/creating instances
* and causes that horrible failure that is NTFS to lock files in place because they are open.
*/
class FolderInstanceStaging : public Task class FolderInstanceStaging : public Task
{ {
Q_OBJECT Q_OBJECT
@ -405,6 +419,11 @@ private slots:
} }
private: private:
/*
* WHY: the whole reason why this uses an exponential backoff retry scheme is antivirus on Windows.
* Basically, it starts messing things up while MultiMC is extracting/creating instances
* and causes that horrible failure that is NTFS to lock files in place because they are open.
*/
ExponentialSeries backoff; ExponentialSeries backoff;
QString m_stagingPath; QString m_stagingPath;
FolderInstanceProvider * m_parent; FolderInstanceProvider * m_parent;
@ -449,6 +468,7 @@ bool FolderInstanceProvider::commitStagedInstance(const QString& path, const QSt
return false; return false;
} }
groupMap[instID] = groupName; groupMap[instID] = groupName;
instanceSet.insert(instID);
emit groupsChanged({groupName}); emit groupsChanged({groupName});
emit instancesChanged(); emit instancesChanged();
} }

View File

@ -19,24 +19,6 @@ public:
/// used by InstanceList to (re)load an instance with the given @id. /// used by InstanceList to (re)load an instance with the given @id.
InstancePtr loadInstance(const InstanceId& id) override; InstancePtr loadInstance(const InstanceId& id) override;
/*
// create instance in this provider
Task * creationTask(BaseVersionPtr version, const QString &instName, const QString &instGroup, const QString &instIcon);
// copy instance to this provider
Task * copyTask(const InstancePtr &oldInstance, const QString& instName, const QString& instGroup, const QString& instIcon, bool copySaves);
// import zipped instance into this provider
Task * zipImportTask(const QUrl sourceUrl, const QString &instName, const QString &instGroup, const QString &instIcon);
//create FtbInstance
Task * ftbCreationTask(FtbPackDownloader *downloader, const QString &instName, const QString &instGroup, const QString &instIcon);
// migrate an instance to the current format
Task * legacyUpgradeTask(const InstancePtr& oldInstance);
*/
// Wrap an instance creation task in some more task machinery and make it ready to be used // Wrap an instance creation task in some more task machinery and make it ready to be used
Task * wrapInstanceTask(InstanceTask * task); Task * wrapInstanceTask(InstanceTask * task);
@ -70,6 +52,8 @@ private: /* methods */
private: /* data */ private: /* data */
QString m_instDir; QString m_instDir;
QFileSystemWatcher * m_watcher; QFileSystemWatcher * m_watcher;
QMap<QString, QString> groupMap; QMap<InstanceId, GroupId> groupMap;
QSet<InstanceId> instanceSet;
bool m_groupsLoaded = false; bool m_groupsLoaded = false;
bool m_instancesProbed = false;
}; };

View File

@ -25,6 +25,7 @@
#include "BaseInstance.h" #include "BaseInstance.h"
#include "FolderInstanceProvider.h" #include "FolderInstanceProvider.h"
#include "FileSystem.h"
InstanceList::InstanceList(QObject *parent) InstanceList::InstanceList(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
@ -118,6 +119,25 @@ void InstanceList::deleteGroup(const QString& name)
} }
} }
void InstanceList::deleteInstance(const InstanceId& id)
{
auto inst = getInstanceById(id);
if(!inst)
{
qDebug() << "Cannot delete instance" << id << " No such instance is present.";
return;
}
qDebug() << "Will delete instance" << id;
if(!FS::deletePath(inst->instanceRoot()))
{
qWarning() << "Deletion of instance" << id << "has not been completely successful ...";
return;
}
qDebug() << "Instance" << id << "has been deleted by MultiMC.";
}
static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr> &list) static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr> &list)
{ {
QMap<InstanceId, InstanceLocator> out; QMap<InstanceId, InstanceLocator> out;

View File

@ -80,7 +80,8 @@ public:
QModelIndex getInstanceIndexById(const QString &id) const; QModelIndex getInstanceIndexById(const QString &id) const;
QStringList getGroups(); QStringList getGroups();
void deleteGroup(const QString & name); void deleteGroup(const GroupId & name);
void deleteInstance(const InstanceId & id);
signals: signals:
void dataIsInvalid(); void dataIsInvalid();

View File

@ -1617,7 +1617,7 @@ void MainWindow::on_actionDeleteInstance_triggered()
)->exec(); )->exec();
if (response == QMessageBox::Yes) if (response == QMessageBox::Yes)
{ {
m_selectedInstance->nuke(); MMC->instances()->deleteInstance(m_selectedInstance->id());
} }
} }

View File

@ -64,8 +64,6 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
ui->groupBox->setCurrentIndex(index); ui->groupBox->setCurrentIndex(index);
ui->groupBox->lineEdit()->setPlaceholderText(tr("No group")); ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
m_buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
m_buttons->button(QDialogButtonBox::Ok)->setDefault(true);
m_container = new PageContainer(this); m_container = new PageContainer(this);
@ -73,8 +71,25 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
m_container->layout()->setContentsMargins(0, 0, 0, 0); m_container->layout()->setContentsMargins(0, 0, 0, 0);
ui->verticalLayout->insertWidget(2, m_container); ui->verticalLayout->insertWidget(2, m_container);
m_buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
m_container->addButtons(m_buttons); m_container->addButtons(m_buttons);
m_buttons->setFocus();
// Bonk Qt over its stupid head and make sure it understands which button is the default one...
// See: https://stackoverflow.com/questions/24556831/qbuttonbox-set-default-button
auto OkButton = m_buttons->button(QDialogButtonBox::Ok);
OkButton->setDefault(true);
OkButton->setAutoDefault(true);
connect(OkButton, &QPushButton::clicked, this, &NewInstanceDialog::accept);
auto CancelButton = m_buttons->button(QDialogButtonBox::Cancel);
CancelButton->setDefault(false);
CancelButton->setAutoDefault(false);
connect(CancelButton, &QPushButton::clicked, this, &NewInstanceDialog::reject);
auto HelpButton = m_buttons->button(QDialogButtonBox::Help);
HelpButton->setDefault(false);
HelpButton->setAutoDefault(false);
connect(HelpButton, &QPushButton::clicked, m_container, &PageContainer::help);
if(!url.isEmpty()) if(!url.isEmpty())
{ {
@ -82,14 +97,9 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
importPage->setUrl(url); importPage->setUrl(url);
} }
connect(m_buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &NewInstanceDialog::accept);
connect(m_buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &NewInstanceDialog::reject);
connect(m_buttons->button(QDialogButtonBox::Help), &QPushButton::clicked, m_container, &PageContainer::help);
updateDialogState(); updateDialogState();
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("NewInstanceGeometry").toByteArray())); restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("NewInstanceGeometry").toByteArray()));
} }
void NewInstanceDialog::reject() void NewInstanceDialog::reject()
@ -160,7 +170,11 @@ InstanceTask * NewInstanceDialog::extractTask()
void NewInstanceDialog::updateDialogState() void NewInstanceDialog::updateDialogState()
{ {
auto allowOK = creationTask && !instName().isEmpty(); auto allowOK = creationTask && !instName().isEmpty();
m_buttons->button(QDialogButtonBox::Ok)->setEnabled(allowOK); auto OkButton = m_buttons->button(QDialogButtonBox::Ok);
if(OkButton->isEnabled() != allowOK)
{
OkButton->setEnabled(allowOK);
}
} }
QString NewInstanceDialog::instName() const QString NewInstanceDialog::instName() const