/*
Copyright (C) 2016 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer 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, either version 3 of the License, or
(at your option) any later version.
Mod Organizer 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 Mod Organizer. If not, see .
*/
#include "instancemanager.h"
#include "selectiondialog.h"
#include
#include
#include
#include
#include
#include
#include
static const char COMPANY_NAME[] = "Tannin";
static const char APPLICATION_NAME[] = "Mod Organizer";
static const char INSTANCE_KEY[] = "CurrentInstance";
InstanceManager::InstanceManager()
: m_AppSettings(COMPANY_NAME, APPLICATION_NAME)
{
}
QString InstanceManager::currentInstance() const
{
return m_AppSettings.value(INSTANCE_KEY, "").toString();
}
void InstanceManager::clearCurrentInstance()
{
setCurrentInstance("");
}
void InstanceManager::setCurrentInstance(const QString &name)
{
m_AppSettings.setValue(INSTANCE_KEY, name);
}
QString InstanceManager::queryInstanceName() const
{
QString instanceId;
while (instanceId.isEmpty()) {
QInputDialog dialog;
// would be neat if we could take the names from the game plugins but
// the required initialization order requires the ini file to be
// available *before* we load plugins
dialog.setComboBoxItems({ "Oblivion", "Skyrim", "Fallout 3",
"Fallout NV", "Fallout 4" });
dialog.setComboBoxEditable(true);
dialog.setWindowTitle(QObject::tr("Enter Instance Name"));
dialog.setLabelText(QObject::tr("Name"));
if (dialog.exec() == QDialog::Rejected) {
throw MOBase::MyException(QObject::tr("Canceled"));
}
instanceId = dialog.textValue().replace(QRegExp("[^0-9a-zA-Z ]"), "");
}
return instanceId;
}
QString InstanceManager::chooseInstance(const QStringList &instanceList) const
{
SelectionDialog selection(QObject::tr("Choose Instance"), nullptr);
selection.disableCancel();
for (const QString &instance : instanceList) {
selection.addChoice(instance, "", instance);
}
selection.addChoice(QObject::tr("New"),
QObject::tr("Create a new instance."),
"");
if (selection.exec() == QDialog::Rejected) {
qDebug("rejected");
throw MOBase::MyException(QObject::tr("Canceled"));
}
QString choice = selection.getChoiceData().toString();
if (choice.isEmpty()) {
return queryInstanceName();
} else {
return choice;
}
}
QString InstanceManager::instancePath() const
{
return QDir::fromNativeSeparators(
QStandardPaths::writableLocation(QStandardPaths::DataLocation));
}
QStringList InstanceManager::instances() const
{
return QDir(instancePath()).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
}
bool InstanceManager::portableInstall() const
{
return QFile::exists(qApp->applicationDirPath() + "/" +
QString::fromStdWString(AppConfig::iniFileName()));
}
InstanceManager::InstallationMode InstanceManager::queryInstallMode() const
{
SelectionDialog selection(QObject::tr("Installation Mode"), nullptr);
selection.disableCancel();
selection.addChoice(QObject::tr("Portable"),
QObject::tr("Everything in one directory, only one game per installation."),
0);
selection.addChoice(QObject::tr("Regular"),
QObject::tr("Data in separate directory, multiple games supported."),
1);
if (selection.exec() == QDialog::Rejected) {
throw MOBase::MyException(QObject::tr("Canceled"));
}
switch (selection.getChoiceData().toInt()) {
case 0: return InstallationMode::PORTABLE;
default: return InstallationMode::REGULAR;
}
}
void InstanceManager::createDataPath(const QString &dataPath) const
{
if (!QDir(dataPath).exists()) {
if (!QDir().mkpath(dataPath)) {
throw MOBase::MyException(
QObject::tr("failed to create %1").arg(dataPath));
} else {
QMessageBox::information(
nullptr, QObject::tr("Data directory created"),
QObject::tr("New data directory created at %1. If you don't want to "
"store a lot of data there, reconfigure the storage "
"directories via settings.").arg(dataPath));
}
}
}
QString InstanceManager::determineDataPath()
{
QString instanceId = currentInstance();
QString dataPath = QDir::fromNativeSeparators(
QStandardPaths::writableLocation(QStandardPaths::DataLocation)
+ "/" + instanceId);
if ((instanceId.isEmpty() || !QFileInfo::exists(dataPath)) && !portableInstall()) {
// no portable install and no selected instance
QStringList instanceList = instances();
if (instanceList.size() == 0) {
if (QFileInfo(qApp->applicationDirPath()).isWritable()) {
switch (queryInstallMode()) {
case InstallationMode::PORTABLE: {
instanceId = QString();
} break;
case InstallationMode::REGULAR: {
instanceId = queryInstanceName();
} break;
}
} else {
instanceId = queryInstanceName();
}
} else {
// don't offer portable instance if we can't set one up.
instanceId = chooseInstance(instanceList);
}
}
if (instanceId.isEmpty() || !QFileInfo::exists(dataPath)) {
return qApp->applicationDirPath();
} else {
setCurrentInstance(instanceId);
createDataPath(dataPath);
return dataPath;
}
}