summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTannin <sherb@gmx.net>2016-01-10 20:19:56 +0100
committerTannin <sherb@gmx.net>2016-01-10 20:19:56 +0100
commit2aae65d6f6c1ab3309e54437a339d1644088c5c8 (patch)
treeb693c455a4433370724cfbaa23a66998a16027a9 /src
parentddf841400ef4da235f11e9b67177a78bb3d519d4 (diff)
made instance-switching usable
this includes tons and tons of changes to how paths are determined. the profiles-dir can now also be configured
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt22
-rw-r--r--src/installationmanager.cpp2
-rw-r--r--src/instancemanager.cpp206
-rw-r--r--src/instancemanager.h62
-rw-r--r--src/logbuffer.cpp120
-rw-r--r--src/main.cpp321
-rw-r--r--src/mainwindow.cpp26
-rw-r--r--src/mainwindow.h7
-rw-r--r--src/organizercore.cpp22
-rw-r--r--src/organizercore.h2
-rw-r--r--src/profile.cpp7
-rw-r--r--src/profilesdialog.cpp6
-rw-r--r--src/selectiondialog.cpp5
-rw-r--r--src/selectiondialog.h2
-rw-r--r--src/selfupdater.cpp2
-rw-r--r--src/settings.cpp274
-rw-r--r--src/settings.h20
-rw-r--r--src/settingsdialog.cpp24
-rw-r--r--src/settingsdialog.h3
-rw-r--r--src/settingsdialog.ui242
20 files changed, 896 insertions, 479 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7cd66739..fda85b76 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,11 +35,11 @@ SET(organizer_SRCS
modlist.cpp
modinfodialog.cpp
modinfo.cpp
- modinfobackup.cpp
- modinfoforeign.cpp
- modinfooverwrite.cpp
- modinforegular.cpp
- modinfowithconflictinfo.cpp
+ modinfobackup.cpp
+ modinfoforeign.cpp
+ modinfooverwrite.cpp
+ modinforegular.cpp
+ modinfowithconflictinfo.cpp
messagedialog.cpp
mainwindow.cpp
main.cpp
@@ -87,6 +87,7 @@ SET(organizer_SRCS
viewmarkingscrollbar.cpp
plugincontainer.cpp
organizercore.cpp
+ instancemanager.cpp
usvfsconnector.cpp
shared/inject.cpp
@@ -131,11 +132,11 @@ SET(organizer_HDRS
modlist.h
modinfodialog.h
modinfo.h
- modinfobackup.h
- modinfoforeign.h
- modinfooverwrite.h
- modinforegular.h
- modinfowithconflictinfo.h
+ modinfobackup.h
+ modinfoforeign.h
+ modinfooverwrite.h
+ modinforegular.h
+ modinfowithconflictinfo.h
messagedialog.h
mainwindow.h
loghighlighter.h
@@ -183,6 +184,7 @@ SET(organizer_HDRS
plugincontainer.h
organizercore.h
iuserinterface.h
+ instancemanager.h
usvfsconnector.h
shared/inject.h
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp
index 739948cd..58565489 100644
--- a/src/installationmanager.cpp
+++ b/src/installationmanager.cpp
@@ -78,7 +78,7 @@ InstallationManager::InstallationManager()
: m_ParentWidget(nullptr)
, m_SupportedExtensions({ "zip", "rar", "7z", "fomod", "001" })
{
- QLibrary archiveLib("dlls\\archive.dll");
+ QLibrary archiveLib(QCoreApplication::applicationDirPath() + "\\dlls\\archive.dll");
if (!archiveLib.load()) {
throw MyException(tr("archive.dll not loaded: \"%1\"").arg(archiveLib.errorString()));
}
diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp
new file mode 100644
index 00000000..48c12d42
--- /dev/null
+++ b/src/instancemanager.cpp
@@ -0,0 +1,206 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "instancemanager.h"
+#include "selectiondialog.h"
+#include <utility.h>
+#include <appconfig.h>
+#include <QCoreApplication>
+#include <QDir>
+#include <QStandardPaths>
+#include <QInputDialog>
+#include <QMessageBox>
+
+
+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();
+
+ if (instanceId.isEmpty() && !portableInstall()) {
+ // no portable install and no selected instance
+
+ QStringList instanceList = instances();
+
+ qDebug("%d - %s", instanceList.size(), qPrintable(instanceList.join(";")));
+
+ if (instanceList.size() == 0) {
+ switch (queryInstallMode()) {
+ case InstallationMode::PORTABLE: {
+ instanceId = QString();
+ } break;
+ case InstallationMode::REGULAR: {
+ instanceId = queryInstanceName();
+ } break;
+ }
+ } else {
+ instanceId = chooseInstance(instanceList);
+ }
+ }
+
+ if (instanceId.isEmpty()) {
+ qDebug("portable mode");
+ return qApp->applicationDirPath();
+ } else {
+ setCurrentInstance(instanceId);
+
+ QString dataPath = QDir::fromNativeSeparators(
+ QStandardPaths::writableLocation(QStandardPaths::DataLocation)
+ + "/" + instanceId);
+
+ createDataPath(dataPath);
+
+ return dataPath;
+ }
+}
+
diff --git a/src/instancemanager.h b/src/instancemanager.h
new file mode 100644
index 00000000..2e17d1c0
--- /dev/null
+++ b/src/instancemanager.h
@@ -0,0 +1,62 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+
+#pragma once
+
+
+#include <QString>
+#include <QSettings>
+
+
+class InstanceManager {
+
+ enum class InstallationMode {
+ PORTABLE,
+ REGULAR
+ };
+
+public:
+
+ InstanceManager();
+
+ QString determineDataPath();
+ QStringList instances() const;
+ void clearCurrentInstance();
+
+private:
+
+ QString currentInstance() const;
+ QString instancePath() const;
+
+ bool portableInstall() const;
+
+ void setCurrentInstance(const QString &name);
+
+ QString queryInstanceName() const;
+ QString chooseInstance(const QStringList &instanceList) const;
+
+ void createDataPath(const QString &dataPath) const;
+ InstallationMode queryInstallMode() const;
+
+private:
+
+ QSettings m_AppSettings;
+
+};
diff --git a/src/logbuffer.cpp b/src/logbuffer.cpp
index 2c3fc101..01ff2b87 100644
--- a/src/logbuffer.cpp
+++ b/src/logbuffer.cpp
@@ -26,37 +26,33 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QDateTime>
#include <Windows.h>
-
using MOBase::reportError;
QScopedPointer<LogBuffer> LogBuffer::s_Instance;
QMutex LogBuffer::s_Mutex;
-
-LogBuffer::LogBuffer(int messageCount, QtMsgType minMsgType, const QString &outputFileName)
- : QAbstractItemModel(nullptr), m_OutFileName(outputFileName), m_ShutDown(false),
- m_MinMsgType(minMsgType), m_NumMessages(0)
+LogBuffer::LogBuffer(int messageCount, QtMsgType minMsgType,
+ const QString &outputFileName)
+ : QAbstractItemModel(nullptr)
+ , m_OutFileName(outputFileName)
+ , m_ShutDown(false)
+ , m_MinMsgType(minMsgType)
+ , m_NumMessages(0)
{
m_Messages.resize(messageCount);
}
LogBuffer::~LogBuffer()
{
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
+ qDebug("closing log buffer");
qInstallMessageHandler(0);
-#else
- qInstallMsgHandler(0);
-#endif
-// if (!m_ShutDown) {
- write();
-// }
+ write();
}
-
void LogBuffer::logMessage(QtMsgType type, const QString &message)
{
if (type >= m_MinMsgType) {
- Message msg = { type, QTime::currentTime(), message };
+ Message msg = {type, QTime::currentTime(), message};
if (m_NumMessages < m_Messages.size()) {
beginInsertRows(QModelIndex(), m_NumMessages, m_NumMessages + 1);
}
@@ -73,7 +69,6 @@ void LogBuffer::logMessage(QtMsgType type, const QString &message)
}
}
-
void LogBuffer::write() const
{
if (m_NumMessages == 0) {
@@ -84,12 +79,15 @@ void LogBuffer::write() const
QFile file(m_OutFileName);
if (!file.open(QIODevice::WriteOnly)) {
- reportError(tr("failed to write log to %1: %2").arg(m_OutFileName).arg(file.errorString()));
+ reportError(tr("failed to write log to %1: %2")
+ .arg(m_OutFileName)
+ .arg(file.errorString()));
return;
}
- unsigned int i = (m_NumMessages > m_Messages.size()) ? m_NumMessages - m_Messages.size()
- : 0U;
+ unsigned int i = (m_NumMessages > m_Messages.size())
+ ? m_NumMessages - m_Messages.size()
+ : 0U;
for (; i < m_NumMessages; ++i) {
file.write(m_Messages.at(i % m_Messages.size()).toString().toUtf8());
file.write("\r\n");
@@ -97,68 +95,68 @@ void LogBuffer::write() const
::SetLastError(lastError);
}
-
-void LogBuffer::init(int messageCount, QtMsgType minMsgType, const QString &outputFileName)
+void LogBuffer::init(int messageCount, QtMsgType minMsgType,
+ const QString &outputFileName)
{
QMutexLocker guard(&s_Mutex);
- if (!s_Instance.isNull()) {
- s_Instance.reset();
- }
s_Instance.reset(new LogBuffer(messageCount, minMsgType, outputFileName));
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
qInstallMessageHandler(LogBuffer::log);
-#else
- qInstallMsgHandler(LogBuffer::log);
-#endif
}
char LogBuffer::msgTypeID(QtMsgType type)
{
switch (type) {
- case QtDebugMsg: return 'D';
- case QtWarningMsg: return 'W';
- case QtCriticalMsg: return 'C';
- case QtFatalMsg: return 'F';
- default: return '?';
+ case QtDebugMsg:
+ return 'D';
+ case QtWarningMsg:
+ return 'W';
+ case QtCriticalMsg:
+ return 'C';
+ case QtFatalMsg:
+ return 'F';
+ default:
+ return '?';
}
}
-void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QString &message)
+void LogBuffer::log(QtMsgType type, const QMessageLogContext &context,
+ const QString &message)
{
// QMutexLocker doesn't support timeout...
if (!s_Mutex.tryLock(100)) {
fprintf(stderr, "failed to log: %s", qPrintable(message));
return;
}
- ON_BLOCK_EXIT([] () {
- s_Mutex.unlock();
- });
+ ON_BLOCK_EXIT([]() { s_Mutex.unlock(); });
if (!s_Instance.isNull()) {
s_Instance->logMessage(type, message);
}
-// fprintf(stdout, "(%s:%u) %s\n", context.file, context.line, qPrintable(message));
if (type == QtDebugMsg) {
- fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), qPrintable(message));
+ fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()),
+ msgTypeID(type), qPrintable(message));
} else {
if (context.line != 0) {
- fprintf(stdout, "%s [%c] (%s:%u) %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type),
+ fprintf(stdout, "%s [%c] (%s:%u) %s\n",
+ qPrintable(QTime::currentTime().toString()), msgTypeID(type),
context.file, context.line, qPrintable(message));
} else {
- fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), qPrintable(message));
+ fprintf(stdout, "%s [%c] %s\n",
+ qPrintable(QTime::currentTime().toString()), msgTypeID(type),
+ qPrintable(message));
}
}
fflush(stdout);
}
-QModelIndex LogBuffer::index(int row, int column, const QModelIndex&) const
+QModelIndex LogBuffer::index(int row, int column, const QModelIndex &) const
{
return createIndex(row, column, row);
}
-QModelIndex LogBuffer::parent(const QModelIndex&) const
+QModelIndex LogBuffer::parent(const QModelIndex &) const
{
return QModelIndex();
}
@@ -171,16 +169,16 @@ int LogBuffer::rowCount(const QModelIndex &parent) const
return std::min(m_NumMessages, m_Messages.size());
}
-int LogBuffer::columnCount(const QModelIndex&) const
+int LogBuffer::columnCount(const QModelIndex &) const
{
return 2;
}
-
QVariant LogBuffer::data(const QModelIndex &index, int role) const
{
- unsigned offset = m_NumMessages < m_Messages.size() ? 0
- : m_NumMessages - m_Messages.size();
+ unsigned offset = m_NumMessages < m_Messages.size()
+ ? 0
+ : m_NumMessages - m_Messages.size();
unsigned int msgIndex = (offset + index.row() + 1) % m_Messages.size();
switch (role) {
case Qt::DisplayRole: {
@@ -198,20 +196,28 @@ QVariant LogBuffer::data(const QModelIndex &index, int role) const
case Qt::DecorationRole: {
if (index.column() == 1) {
switch (m_Messages[msgIndex].type) {
- case QtDebugMsg: return QIcon(":/MO/gui/information");
- case QtWarningMsg: return QIcon(":/MO/gui/warning");
- case QtCriticalMsg: return QIcon(":/MO/gui/important");
- case QtFatalMsg: return QIcon(":/MO/gui/problem");
+ case QtDebugMsg:
+ return QIcon(":/MO/gui/information");
+ case QtWarningMsg:
+ return QIcon(":/MO/gui/warning");
+ case QtCriticalMsg:
+ return QIcon(":/MO/gui/important");
+ case QtFatalMsg:
+ return QIcon(":/MO/gui/problem");
}
}
} break;
case Qt::UserRole: {
if (index.column() == 1) {
switch (m_Messages[msgIndex].type) {
- case QtDebugMsg: return "D";
- case QtWarningMsg: return "W";
- case QtCriticalMsg: return "C";
- case QtFatalMsg: return "F";
+ case QtDebugMsg:
+ return "D";
+ case QtWarningMsg:
+ return "W";
+ case QtCriticalMsg:
+ return "C";
+ case QtFatalMsg:
+ return "F";
}
}
} break;
@@ -227,7 +233,6 @@ void LogBuffer::writeNow()
}
}
-
void LogBuffer::cleanQuit()
{
QMutexLocker guard(&s_Mutex);
@@ -255,5 +260,8 @@ void log(const char *format, ...)
QString LogBuffer::Message::toString() const
{
- return QString("%1 [%2] %3").arg(time.toString()).arg(msgTypeID(type)).arg(message);
+ return QString("%1 [%2] %3")
+ .arg(time.toString())
+ .arg(msgTypeID(type))
+ .arg(message);
}
diff --git a/src/main.cpp b/src/main.cpp
index 30938485..a262d031 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -45,6 +45,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "moapplication.h"
#include "tutorialmanager.h"
#include "nxmaccessmanager.h"
+#include "instancemanager.h"
+
#include <eh.h>
#include <windows_error.h>
@@ -84,6 +86,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
using namespace MOBase;
using namespace MOShared;
+
bool createAndMakeWritable(const std::wstring &subPath)
{
QString const dataPath = qApp->property("dataPath").toString();
@@ -135,43 +138,6 @@ bool bootstrap()
return true;
}
-void cleanupDir()
-{
- // files from previous versions of MO that are no longer
- // required (in that location)
- QStringList fileNames {
- "imageformats/",
- "loot/resources/",
- "plugins/previewDDS.dll",
- "dlls/boost_python-vc100-mt-1_55.dll",
- "dlls/QtCore4.dll",
- "dlls/QtDeclarative4.dll",
- "dlls/QtGui4.dll",
- "dlls/QtNetwork4.dll",
- "dlls/QtOpenGL4.dll",
- "dlls/QtScript4.dll",
- "dlls/QtSql4.dll",
- "dlls/QtSvg4.dll",
- "dlls/QtWebKit4.dll",
- "dlls/QtXml4.dll",
- "dlls/QtXmlPatterns4.dll",
- "msvcp100.dll",
- "msvcr100.dll",
- "proxy.dll"
- };
-
- for (const QString &fileName : fileNames) {
- QString fullPath = qApp->applicationDirPath() + "/" + fileName;
- if (QFile::exists(fullPath)) {
- if (shellDelete(QStringList(fullPath), true)) {
- qDebug("removed obsolete file %s", qPrintable(fullPath));
- } else {
- qDebug("failed to remove obsolete %s", qPrintable(fullPath));
- }
- }
- }
-}
-
bool isNxmLink(const QString &link)
{
@@ -195,6 +161,10 @@ static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *except
if (dbgDLL) {
FuncMiniDumpWriteDump funcDump = (FuncMiniDumpWriteDump)::GetProcAddress(dbgDLL, "MiniDumpWriteDump");
if (funcDump) {
+ wchar_t exeNameBuffer[MAX_PATH];
+ ::GetModuleFileNameW(nullptr, exeNameBuffer, MAX_PATH);
+ QString dumpName = QString::fromWCharArray(exeNameBuffer) + ".dmp";
+
if (QMessageBox::question(nullptr, QObject::tr("Woops"),
QObject::tr("ModOrganizer has crashed! "
"Should a diagnostic file be created? "
@@ -202,12 +172,10 @@ static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *except
"the bug is a lot more likely to be fixed. "
"Please include a short description of what you were "
"doing when the crash happened"
- ).arg(qApp->applicationFilePath().append(".dmp")),
+ ).arg(dumpName),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
- std::wstring dumpName = ToWString(qApp->applicationFilePath().append(".dmp"));
-
- HANDLE dumpFile = ::CreateFile(dumpName.c_str(),
+ HANDLE dumpFile = ::CreateFile(dumpName.toStdWString().c_str(),
GENERIC_WRITE, FILE_SHARE_WRITE, nullptr,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (dumpFile != INVALID_HANDLE_VALUE) {
@@ -225,10 +193,10 @@ static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *except
return EXCEPTION_EXECUTE_HANDLER;
}
_snprintf(errorBuffer, errorLen, "failed to save minidump to %ls (error %lu)",
- dumpName.c_str(), ::GetLastError());
+ dumpName.toStdWString().c_str(), ::GetLastError());
} else {
_snprintf(errorBuffer, errorLen, "failed to create %ls (error %lu)",
- dumpName.c_str(), ::GetLastError());
+ dumpName.toStdWString().c_str(), ::GetLastError());
}
} else {
return result;
@@ -435,139 +403,95 @@ MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &sett
return nullptr;
}
-int main(int argc, char *argv[])
-{
- MOApplication application(argc, argv);
-
- qDebug("application name: %s", qPrintable(application.applicationName()));
- QString instanceID;
- QFile instanceFile(application.applicationDirPath() + "/INSTANCE");
- if (instanceFile.open(QIODevice::ReadOnly)) {
- instanceID = instanceFile.readAll().trimmed();
- }
+// extend path to include dll directory so plugins don't need a manifest
+// (using AddDllDirectory would be an alternative to this but it seems fairly
+// complicated esp.
+// since it isn't easily accessible on Windows < 8
+// SetDllDirectory replaces other search directories and this seems to
+// propagate to child processes)
+void setupPath()
+{
+ static const int BUFSIZE = 4096;
- QString const dataPath =
- instanceID.isEmpty() ? application.applicationDirPath()
- : QDir::fromNativeSeparators(
- QStandardPaths::writableLocation(QStandardPaths::DataLocation)
- + "/" + instanceID
- );
- application.setProperty("dataPath", dataPath);
+ qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators(
+ QCoreApplication::applicationDirPath())));
- if (!QDir(dataPath).exists()) {
- if (!QDir().mkpath(dataPath)) {
- qCritical("failed to create %s", qPrintable(dataPath));
- return 1;
- }
+ boost::scoped_array<TCHAR> oldPath(new TCHAR[BUFSIZE]);
+ DWORD offset = ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), BUFSIZE);
+ if (offset > BUFSIZE) {
+ oldPath.reset(new TCHAR[offset]);
+ ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), offset);
}
- SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
+ std::wstring newPath(oldPath.get());
+ newPath += L";";
+ newPath += ToWString(QDir::toNativeSeparators(
+ QCoreApplication::applicationDirPath()))
+ .c_str();
+ newPath += L"\\dlls";
+
+ ::SetEnvironmentVariableW(L"PATH", newPath.c_str());
+}
- if (!HaveWriteAccess(ToWString(application.applicationDirPath()))) {
- QStringList arguments = application.arguments();
- arguments.pop_front();
- ::ShellExecuteW( nullptr
- , L"runas"
- , ToWString(QString("\"%1\"").arg(QCoreApplication::applicationFilePath())).c_str()
- , ToWString(arguments.join(" ")).c_str()
- , ToWString(QDir::currentPath()).c_str(), SW_SHOWNORMAL);
- return 1;
- }
+int runApplication(MOApplication &application, SingleInstance &instance)
+{
+ qDebug("start main application");
QPixmap pixmap(":/MO/gui/splash");
QSplashScreen splash(pixmap);
- try {
- if (!bootstrap()) {
- return -1;
- }
+ QString dataPath = application.property("dataPath").toString();
+ qDebug("data path: %s", qPrintable(dataPath));
- LogBuffer::init(100, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log");
+ if (!bootstrap()) {
+ reportError("failed to set up data path");
+ return 1;
+ }
-#if QT_VERSION >= 0x050000 && !defined(QT_NO_SSL)
- qDebug("ssl support: %d", QSslSocket::supportsSsl());
-#endif
+ QStringList arguments = application.arguments();
+ try {
qDebug("Working directory: %s", qPrintable(QDir::toNativeSeparators(QDir::currentPath())));
- qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators(application.applicationDirPath())));
splash.show();
-
- cleanupDir();
} catch (const std::exception &e) {
reportError(e.what());
return 1;
}
- { // extend path to include dll directory so plugins don't need a manifest
- // (using AddDllDirectory would be an alternative to this but it seems fairly complicated esp.
- // since it isn't easily accessible on Windows < 8
- // SetDllDirectory replaces other search directories and this seems to propagate to child processes)
- static const int BUFSIZE = 4096;
-
- boost::scoped_array<TCHAR> oldPath(new TCHAR[BUFSIZE]);
- DWORD offset = ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), BUFSIZE);
- if (offset > BUFSIZE) {
- oldPath.reset(new TCHAR[offset]);
- ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), offset);
- }
-
- std::wstring newPath(oldPath.get());
- newPath += L";";
- newPath += ToWString(QDir::toNativeSeparators(QCoreApplication::applicationDirPath())).c_str();
- newPath += L"\\dlls";
-
- ::SetEnvironmentVariableW(L"PATH", newPath.c_str());
- }
-
- QStringList arguments = application.arguments();
-
- bool forcePrimary = false;
- if (arguments.contains("update")) {
- arguments.removeAll("update");
- forcePrimary = true;
- }
-
try {
- SingleInstance instance(forcePrimary);
- if (!instance.primaryInstance()) {
- if ((arguments.size() == 2) && isNxmLink(arguments.at(1))) {
- qDebug("not primary instance, sending download message");
- instance.sendMessage(arguments.at(1));
- return 0;
- } else if (arguments.size() == 1) {
- QMessageBox::information(nullptr, QObject::tr("Mod Organizer"), QObject::tr("An instance of Mod Organizer is already running"));
- return 0;
- }
- } // we continue for the primary instance OR if MO has been called with parameters
-
- QSettings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()), QSettings::IniFormat);
+ QSettings settings(dataPath + "/"
+ + QString::fromStdWString(AppConfig::iniFileName()),
+ QSettings::IniFormat);
qDebug("initializing core");
OrganizerCore organizer(settings);
qDebug("initialize plugins");
PluginContainer pluginContainer(&organizer);
pluginContainer.loadPlugins();
- MOBase::IPluginGame *game = determineCurrentGame(application.applicationDirPath(), settings, pluginContainer);
+ MOBase::IPluginGame *game = determineCurrentGame(
+ application.applicationDirPath(), settings, pluginContainer);
if (game == nullptr) {
return 1;
}
organizer.setManagedGame(game);
-
organizer.createDefaultProfile();
- //See the pragma - we apparently don't use this so not sure why we check it
if (!settings.contains("game_edition")) {
QStringList editions = game->gameVariants();
if (editions.size() > 1) {
- SelectionDialog selection(QObject::tr("Please select the game edition you have (MO can't start the game correctly if this is set incorrectly!)"), nullptr);
+ SelectionDialog selection(
+ QObject::tr("Please select the game edition you have (MO can't "
+ "start the game correctly if this is set "
+ "incorrectly!)"),
+ nullptr);
int index = 0;
for (const QString &edition : editions) {
selection.addChoice(edition, "", index++);
}
if (selection.exec() == QDialog::Rejected) {
- return -1;
+ return 1;
} else {
settings.setValue("game_edition", selection.getChoiceString());
}
@@ -575,8 +499,8 @@ int main(int argc, char *argv[])
}
game->setGameVariant(settings.value("game_edition").toString());
-#pragma message("edition isn't used?")
- qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(game->gameDirectory().absolutePath())));
+ qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(
+ game->gameDirectory().absolutePath())));
organizer.updateExecutablesList(settings);
@@ -585,27 +509,35 @@ int main(int argc, char *argv[])
// if we have a command line parameter, it is either a nxm link or
// a binary to start
- if ((arguments.size() > 1)
- && !isNxmLink(arguments.at(1))) {
- QString exeName = arguments.at(1);
- qDebug("starting %s from command line", qPrintable(exeName));
- arguments.removeFirst(); // remove application name (ModOrganizer.exe)
- arguments.removeFirst(); // remove binary name
- // pass the remaining parameters to the binary
- try {
- organizer.startApplication(exeName, arguments, QString(), QString());
- return 0;
- } catch (const std::exception &e) {
- reportError(QObject::tr("failed to start application: %1").arg(e.what()));
- return 1;
+ if (arguments.size() > 1) {
+ if (isNxmLink(arguments.at(1))) {
+ qDebug("starting download from command line: %s",
+ qPrintable(arguments.at(1)));
+ organizer.externalMessage(arguments.at(1));
+ } else {
+ QString exeName = arguments.at(1);
+ qDebug("starting %s from command line", qPrintable(exeName));
+ arguments.removeFirst(); // remove application name (ModOrganizer.exe)
+ arguments.removeFirst(); // remove binary name
+ // pass the remaining parameters to the binary
+ try {
+ organizer.startApplication(exeName, arguments, QString(), QString());
+ } catch (const std::exception &e) {
+ reportError(
+ QObject::tr("failed to start application: %1").arg(e.what()));
+ return 1;
+ }
}
+ return 0;
}
NexusInterface::instance()->getAccessManager()->startLoginCheck();
qDebug("initializing tutorials");
- TutorialManager::init(qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::tutorialsPath()) + "/",
- &organizer);
+ TutorialManager::init(
+ qApp->applicationDirPath() + "/"
+ + QString::fromStdWString(AppConfig::tutorialsPath()) + "/",
+ &organizer);
if (!application.setStyleFile(settings.value("Settings/style", "").toString())) {
// disable invalid stylesheet
@@ -615,27 +547,94 @@ int main(int argc, char *argv[])
int res = 1;
{ // scope to control lifetime of mainwindow
// set up main window and its data structures
- MainWindow mainWindow(argv[0], settings, organizer, pluginContainer);
+ MainWindow mainWindow(settings, organizer, pluginContainer);
- QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application, SLOT(setStyleFile(QString)));
- QObject::connect(&instance, SIGNAL(messageSent(QString)), &organizer, SLOT(externalMessage(QString)));
+ QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application,
+ SLOT(setStyleFile(QString)));
+ QObject::connect(&instance, SIGNAL(messageSent(QString)), &organizer,
+ SLOT(externalMessage(QString)));
mainWindow.readSettings();
qDebug("displaying main window");
mainWindow.show();
- if ((arguments.size() > 1)
- && isNxmLink(arguments.at(1))) {
- qDebug("starting download from command line: %s", qPrintable(arguments.at(1)));
- organizer.externalMessage(arguments.at(1));
- }
splash.finish(&mainWindow);
- res = application.exec();
+ return application.exec();
}
- return res;
} catch (const std::exception &e) {
reportError(e.what());
return 1;
}
}
+
+
+int main(int argc, char *argv[])
+{
+ SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
+
+ MOApplication application(argc, argv);
+ QStringList arguments = application.arguments();
+
+ if ((arguments.length() >= 4) && (arguments.at(1) == "launch")) {
+ // all we're supposed to do is launch another process
+ QProcess process;
+ process.setWorkingDirectory(QDir::fromNativeSeparators(arguments.at(2)));
+ process.setProgram(QDir::fromNativeSeparators(arguments.at(3)));
+ process.setArguments(arguments.mid(4));
+ process.start();
+ process.waitForFinished(-1);
+ return process.exitCode();
+ }
+
+ setupPath();
+
+ #if !defined(QT_NO_SSL)
+ qDebug("ssl support: %d", QSslSocket::supportsSsl());
+ #else
+ qDebug("non-ssl build");
+ #endif
+
+ bool forcePrimary = false;
+ if (arguments.contains("update")) {
+ arguments.removeAll("update");
+ forcePrimary = true;
+ }
+
+ SingleInstance instance(forcePrimary);
+ if (!instance.primaryInstance()) {
+ if ((arguments.size() == 2) && isNxmLink(arguments.at(1))) {
+ qDebug("not primary instance, sending download message");
+ instance.sendMessage(arguments.at(1));
+ return 0;
+ } else if (arguments.size() == 1) {
+ QMessageBox::information(
+ nullptr, QObject::tr("Mod Organizer"),
+ QObject::tr("An instance of Mod Organizer is already running"));
+ return 0;
+ }
+ } // we continue for the primary instance OR if MO was called with parameters
+
+ do {
+ QString dataPath;
+
+ try {
+ dataPath = InstanceManager().determineDataPath();
+ } catch (const std::exception &e) {
+ QMessageBox::critical(nullptr, QObject::tr("Failed to set up instance"),
+ e.what());
+ return 1;
+ }
+
+ application.setProperty("dataPath", dataPath);
+
+ LogBuffer::init(100, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log");
+
+ int result = runApplication(application, instance);
+
+ if (result != INT_MAX) {
+ return result;
+ }
+ argc = 1;
+ } while (true);
+}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 0c54fc8d..80e3490c 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -74,6 +74,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <taskprogressmanager.h>
#include <util.h>
#include <scopeguard.h>
+#include <usvfs.h>
#include <QTime>
#include <QInputDialog>
@@ -146,8 +147,7 @@ using namespace MOBase;
using namespace MOShared;
-MainWindow::MainWindow(const QString &exeName
- , QSettings &initSettings
+MainWindow::MainWindow(QSettings &initSettings
, OrganizerCore &organizerCore
, PluginContainer &pluginContainer
, QWidget *parent)
@@ -155,7 +155,6 @@ MainWindow::MainWindow(const QString &exeName
, ui(new Ui::MainWindow)
, m_WasVisible(false)
, m_Tutorial(this, "MainWindow")
- , m_ExeName(exeName)
, m_OldProfileIndex(-1)
, m_ModListGroupingProxy(nullptr)
, m_ModListSortProxy(nullptr)
@@ -301,6 +300,7 @@ MainWindow::MainWindow(const QString &exeName
connect(ui->toolBar, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(toolBar_customContextMenuRequested(QPoint)));
connect(&m_OrganizerCore, &OrganizerCore::modInstalled, this, &MainWindow::modInstalled);
+ connect(&m_OrganizerCore, &OrganizerCore::close, this, &QMainWindow::close);
connect(&m_IntegratedBrowser, SIGNAL(requestDownload(QUrl,QNetworkReply*)), &m_OrganizerCore, SLOT(requestDownload(QUrl,QNetworkReply*)));
@@ -347,6 +347,8 @@ MainWindow::MainWindow(const QString &exeName
MainWindow::~MainWindow()
{
+ cleanup();
+
m_PluginContainer.setUserInterface(nullptr, nullptr);
m_OrganizerCore.setUserInterface(nullptr, nullptr);
m_IntegratedBrowser.close();
@@ -810,6 +812,14 @@ void MainWindow::closeEvent(QCloseEvent* event)
}
setCursor(Qt::WaitCursor);
+}
+
+void MainWindow::cleanup()
+{
+ if (ui->logList->model() != nullptr) {
+ disconnect(ui->logList->model(), nullptr, nullptr, nullptr);
+ ui->logList->setModel(nullptr);
+ }
m_IntegratedBrowser.close();
}
@@ -1175,7 +1185,7 @@ bool MainWindow::refreshProfiles(bool selectProfile)
profileBox->clear();
profileBox->addItem(QObject::tr("<Manage...>"));
- QDir profilesDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()));
+ QDir profilesDir(Settings::instance().getProfileDirectory());
profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
QDirIterator profileIter(profilesDir);
@@ -3166,7 +3176,7 @@ QString getStartMenuLinkfile(const Executable &exec)
void MainWindow::addWindowsLink(const ShortcutType mapping)
{
- Executable const &selectedExecutable(getSelectedExecutable());
+ const Executable &selectedExecutable(getSelectedExecutable());
QString const linkName = getLinkfile(mapping == ShortcutType::Desktop ? getDesktopDirectory() : getStartMenuDirectory(),
selectedExecutable);
@@ -4217,6 +4227,7 @@ void MainWindow::on_bossButton_clicked()
HANDLE stdOutRead = INVALID_HANDLE_VALUE;
createStdoutPipe(&stdOutRead, &stdOutWrite);
m_OrganizerCore.prepareVFS();
+
HANDLE loot = startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"),
parameters.join(" "),
qApp->applicationDirPath() + "/loot",
@@ -4313,6 +4324,7 @@ void MainWindow::on_bossButton_clicked()
} catch (const std::exception &e) {
reportError(tr("failed to run loot: %1").arg(e.what()));
}
+
if (errorMessages.length() > 0) {
QMessageBox *warn = new QMessageBox(QMessageBox::Warning, tr("Errors occured"), errorMessages.c_str(), QMessageBox::Ok, this);
warn->setModal(false);
@@ -4326,11 +4338,7 @@ void MainWindow::on_bossButton_clicked()
QStringList temp = report.split("?");
QUrl url = QUrl::fromLocalFile(temp.at(0));
if (temp.size() > 1) {
-#if QT_VERSION >= 0x050000
url.setQuery(temp.at(1).toUtf8());
-#else
- url.setEncodedQuery(temp.at(1).toUtf8());
-#endif
}
m_IntegratedBrowser.openUrl(url);
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 49476bf3..530097cf 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -26,7 +26,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QTreeWidget>
#include <QListWidgetItem>
#include <QProcess>
-#include <QThread>
#include <QProgressBar>
#include <QTranslator>
#include <QPluginLoader>
@@ -75,7 +74,7 @@ class MainWindow : public QMainWindow, public IUserInterface
public:
- explicit MainWindow(const QString &exeName, QSettings &initSettings,
+ explicit MainWindow(QSettings &initSettings,
OrganizerCore &organizerCore, PluginContainer &pluginContainer,
QWidget *parent = 0);
~MainWindow();
@@ -155,6 +154,8 @@ protected:
private:
+ void cleanup();
+
void actionToToolButton(QAction *&sourceAction);
void updateToolBar();
@@ -263,8 +264,6 @@ private:
MOBase::TutorialControl m_Tutorial;
- QString m_ExeName;
-
int m_OldProfileIndex;
std::vector<QString> m_ModNameList; // the mod-list to go with the directory structure
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index c84b603d..a73e6845 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -535,7 +535,7 @@ InstallationManager *OrganizerCore::installationManager()
void OrganizerCore::createDefaultProfile()
{
- QString profilesPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath());
+ QString profilesPath = settings().getProfileDirectory();
if (QDir(profilesPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot).size() == 0) {
Profile newProf("Default", managedGame(), false);
}
@@ -552,7 +552,7 @@ void OrganizerCore::setCurrentProfile(const QString &profileName)
(profileName == m_CurrentProfile->name())) {
return;
}
- QString profileDir = qApp->property("dataPath").toString() + "/" + ToQString(AppConfig::profilesPath()) + "/" + profileName;
+ QString profileDir = settings().getProfileDirectory() + "/" + profileName;
Profile *newProfile = new Profile(QDir(profileDir), managedGame());
delete m_CurrentProfile;
@@ -994,10 +994,9 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &
m_CurrentProfile->modlistWriter().writeImmediately(true);
}
- // TODO: should also pass arguments
if (m_AboutToRun(binary.absoluteFilePath())) {
m_USVFS.updateMapping(fileMapping());
- QString modsPath(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::modsPath()));
+ QString modsPath = settings().getModDirectory();
QString binPath = binary.absoluteFilePath();
@@ -1008,15 +1007,14 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &
QString cwdPath = currentDirectory.absolutePath();
int binOffset = binPath.indexOf('/', modsPath.length() + 1);
- int cwdOffset = cwdPath.indexOf('/', cwdPath.length() + 1);
- QString binPath = m_GamePlugin->dataDirectory().absolutePath() + "/" + binPath.mid(binOffset);
- QString cwd = m_GamePlugin->dataDirectory().absolutePath() + "/" + cwdPath.mid(cwdOffset);
+ int cwdOffset = cwdPath.indexOf('/', modsPath.length() + 1);
+ QString dataBinPath = m_GamePlugin->dataDirectory().absolutePath() + binPath.mid(binOffset, -1);
+ QString dataCwd = m_GamePlugin->dataDirectory().absolutePath() + cwdPath.mid(cwdOffset, -1);
QString cmdline = QString("launch \"%1\" \"%2\" %3")
- .arg(QDir::toNativeSeparators(cwd),
- QDir::toNativeSeparators(binPath),
+ .arg(QDir::toNativeSeparators(dataCwd),
+ QDir::toNativeSeparators(dataBinPath),
arguments);
-
- return startBinary(QFileInfo(QCoreApplication::applicationDirPath() + "/helper.exe"),
+ return startBinary(QFileInfo(QCoreApplication::applicationFilePath()),
cmdline,
QCoreApplication::applicationDirPath(), true);
} else {
@@ -1600,7 +1598,7 @@ std::vector<Mapping> OrganizerCore::fileMapping()
int overwriteId = m_DirectoryStructure->getOriginByName(L"Overwrite").getID();
- const IPluginGame *game = qApp->property("managed_game").value<const IPluginGame *>();
+ IPluginGame *game = qApp->property("managed_game").value<IPluginGame *>();
MappingType result = fileMapping(
QDir::toNativeSeparators(game->dataDirectory().absolutePath()),
"\\",
diff --git a/src/organizercore.h b/src/organizercore.h
index d86033eb..bf6c5a8b 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -201,6 +201,8 @@ signals:
void managedGameChanged(MOBase::IPluginGame const *gamePlugin);
+ void close();
+
private:
void storeSettings();
diff --git a/src/profile.cpp b/src/profile.cpp
index 4b916a2f..99a6bd90 100644
--- a/src/profile.cpp
+++ b/src/profile.cpp
@@ -22,6 +22,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "windows_error.h"
#include "modinfo.h"
#include "safewritefile.h"
+#include "settings.h"
#include <utility.h>
#include <util.h>
#include <error_report.h>
@@ -58,7 +59,7 @@ Profile::Profile(const QString &name, IPluginGame const *gamePlugin, bool useDef
: m_ModListWriter(std::bind(&Profile::writeModlistNow, this))
, m_GamePlugin(gamePlugin)
{
- QString profilesDir = qApp->property("dataPath").toString() + "/" + ToQString(AppConfig::profilesPath());
+ QString profilesDir = Settings::instance().getProfileDirectory();
QDir profileBase(profilesDir);
QString fixedName = name;
@@ -487,7 +488,7 @@ void Profile::setModPriority(unsigned int index, int &newPriority)
Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin)
{
- QString profileDirectory = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()) + "/" + name;
+ QString profileDirectory = Settings::instance().getProfileDirectory() + "/" + name;
reference.copyFilesTo(profileDirectory);
return new Profile(QDir(profileDirectory), gamePlugin);
}
@@ -691,7 +692,7 @@ QString Profile::absolutePath() const
void Profile::rename(const QString &newName)
{
- QDir profileDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()));
+ QDir profileDir(Settings::instance().getProfileDirectory());
profileDir.rename(name(), newName);
m_Directory = profileDir.absoluteFilePath(newName);
}
diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp
index b21aee53..49fbda4e 100644
--- a/src/profilesdialog.cpp
+++ b/src/profilesdialog.cpp
@@ -25,6 +25,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "profileinputdialog.h"
#include "mainwindow.h"
#include "aboutdialog.h"
+#include "settings.h"
#include <iplugingame.h>
#include <bsainvalidation.h>
#include <appconfig.h>
@@ -50,7 +51,7 @@ ProfilesDialog::ProfilesDialog(const QString &profileName, MOBase::IPluginGame c
{
ui->setupUi(this);
- QDir profilesDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()));
+ QDir profilesDir(Settings::instance().getProfileDirectory());
profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
m_ProfilesList = findChild<QListWidget*>("profilesList");
@@ -187,8 +188,7 @@ void ProfilesDialog::on_removeProfileButton_clicked()
Profile::Ptr currentProfile = profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>();
QString profilePath;
if (currentProfile.get() == nullptr) {
- profilePath = qApp->property("dataPath").toString()
- + "/" + QString::fromStdWString(AppConfig::profilesPath())
+ profilePath = Settings::instance().getProfileDirectory()
+ "/" + profilesList->currentItem()->text();
if (QMessageBox::question(this, tr("Profile broken"),
tr("This profile you're about to delete seems to be broken or the path is invalid. "
diff --git a/src/selectiondialog.cpp b/src/selectiondialog.cpp
index aae95f56..55728751 100644
--- a/src/selectiondialog.cpp
+++ b/src/selectiondialog.cpp
@@ -79,6 +79,11 @@ QString SelectionDialog::getChoiceString()
}
}
+void SelectionDialog::disableCancel()
+{
+ ui->cancelButton->setEnabled(false);
+ ui->cancelButton->setHidden(true);
+}
void SelectionDialog::on_buttonBox_clicked(QAbstractButton *button)
{
diff --git a/src/selectiondialog.h b/src/selectiondialog.h
index 43ba9767..3c4b25df 100644
--- a/src/selectiondialog.h
+++ b/src/selectiondialog.h
@@ -53,6 +53,8 @@ public:
QVariant getChoiceData();
QString getChoiceString();
+ void disableCancel();
+
private slots:
void on_buttonBox_clicked(QAbstractButton *button);
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp
index 0cfd7f08..ae75b9cb 100644
--- a/src/selfupdater.cpp
+++ b/src/selfupdater.cpp
@@ -65,7 +65,7 @@ SelfUpdater::SelfUpdater(NexusInterface *nexusInterface)
, m_Attempts(3)
, m_NexusDownload(nullptr)
{
- QLibrary archiveLib("dlls\\archive.dll");
+ QLibrary archiveLib(QCoreApplication::applicationDirPath() + "\\dlls\\archive.dll");
if (!archiveLib.load()) {
throw MyException(tr("archive.dll not loaded: \"%1\"").arg(archiveLib.errorString()));
}
diff --git a/src/settings.cpp b/src/settings.cpp
index 7b812759..c99b434d 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -125,7 +125,7 @@ void Settings::registerPlugin(IPlugin *plugin)
m_Plugins.push_back(plugin);
m_PluginSettings.insert(plugin->name(), QMap<QString, QVariant>());
m_PluginDescriptions.insert(plugin->name(), QMap<QString, QVariant>());
- foreach (const PluginSetting &setting, plugin->settings()) {
+ for (const PluginSetting &setting : plugin->settings()) {
QVariant temp = m_Settings.value("Plugins/" + plugin->name() + "/" + setting.key, setting.defaultValue);
if (!temp.convert(setting.defaultValue.type())) {
qWarning("failed to interpret \"%s\" as correct type for \"%s\" in plugin \"%s\", using default",
@@ -183,7 +183,7 @@ void Settings::setDownloadSpeed(const QString &serverName, int bytesPerSecond)
{
m_Settings.beginGroup("Servers");
- foreach (const QString &serverKey, m_Settings.childKeys()) {
+ for (const QString &serverKey : m_Settings.childKeys()) {
QVariantMap data = m_Settings.value(serverKey).toMap();
if (serverKey == serverName) {
data["downloadCount"] = data["downloadCount"].toInt() + 1;
@@ -201,7 +201,7 @@ std::map<QString, int> Settings::getPreferredServers()
std::map<QString, int> result;
m_Settings.beginGroup("Servers");
- foreach (const QString &serverKey, m_Settings.childKeys()) {
+ for (const QString &serverKey : m_Settings.childKeys()) {
QVariantMap data = m_Settings.value(serverKey).toMap();
int preference = data["preferred"].toInt();
if (preference > 0) {
@@ -233,6 +233,11 @@ QString Settings::getModDirectory() const
return getConfigurablePath("mod_directory", ToQString(AppConfig::modsPath()));
}
+QString Settings::getProfileDirectory() const
+{
+ return getConfigurablePath("profiles_directory", ToQString(AppConfig::profilesPath()));
+}
+
QString Settings::getNMMVersion() const
{
static const QString MIN_NMM_VERSION = "0.52.3";
@@ -411,7 +416,7 @@ void Settings::updateServers(const QList<ServerInfo> &servers)
m_Settings.beginGroup("Servers");
QStringList oldServerKeys = m_Settings.childKeys();
- foreach (const ServerInfo &server, servers) {
+ for (const ServerInfo &server : servers) {
if (!oldServerKeys.contains(server.name)) {
// not yet known server
QVariantMap newVal;
@@ -433,7 +438,7 @@ void Settings::updateServers(const QList<ServerInfo> &servers)
// clean up unavailable servers
QDate now = QDate::currentDate();
- foreach (const QString &key, m_Settings.childKeys()) {
+ for (const QString &key : m_Settings.childKeys()) {
QVariantMap val = m_Settings.value(key).toMap();
QDate lastSeen = val["lastSeen"].toDate();
if (lastSeen.daysTo(now) > 30) {
@@ -457,7 +462,7 @@ void Settings::writePluginBlacklist()
{
m_Settings.beginWriteArray("pluginBlacklist");
int idx = 0;
- foreach (const QString &plugin, m_PluginBlacklist) {
+ for (const QString &plugin : m_PluginBlacklist) {
m_Settings.setArrayIndex(idx++);
m_Settings.setValue("name", plugin);
}
@@ -522,7 +527,7 @@ void Settings::resetDialogs()
{
m_Settings.beginGroup("DialogChoices");
QStringList keys = m_Settings.childKeys();
- foreach (QString key, keys) {
+ for (QString key : keys) {
m_Settings.remove(key);
}
@@ -539,6 +544,7 @@ void Settings::query(QWidget *parent)
std::vector<std::unique_ptr<SettingsTab>> tabs;
tabs.push_back(std::unique_ptr<SettingsTab>(new GeneralTab(this, dialog)));
+ tabs.push_back(std::unique_ptr<SettingsTab>(new PathsTab(this, dialog)));
tabs.push_back(std::unique_ptr<SettingsTab>(new NexusTab(this, dialog)));
tabs.push_back(std::unique_ptr<SettingsTab>(new SteamTab(this, dialog)));
tabs.push_back(std::unique_ptr<SettingsTab>(new PluginsTab(this, dialog)));
@@ -552,56 +558,54 @@ void Settings::query(QWidget *parent)
}
}
-Settings::SettingsTab::SettingsTab(Settings *m_parent, SettingsDialog &m_dialog) :
- m_parent(m_parent),
- m_Settings(m_parent->m_Settings),
- m_dialog(m_dialog)
-{}
+Settings::SettingsTab::SettingsTab(Settings *m_parent, SettingsDialog &m_dialog)
+ : m_parent(m_parent)
+ , m_Settings(m_parent->m_Settings)
+ , m_dialog(m_dialog)
+{
+}
Settings::SettingsTab::~SettingsTab()
{}
-Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) :
- Settings::SettingsTab(m_parent, m_dialog),
- m_languageBox(m_dialog.findChild<QComboBox*>("languageBox")),
- m_styleBox(m_dialog.findChild<QComboBox*>("styleBox")),
- m_logLevelBox(m_dialog.findChild<QComboBox*>("logLevelBox")),
- m_downloadDirEdit(m_dialog.findChild<QLineEdit*>("downloadDirEdit")),
- m_modDirEdit(m_dialog.findChild<QLineEdit*>("modDirEdit")),
- m_cacheDirEdit(m_dialog.findChild<QLineEdit*>("cacheDirEdit")),
- m_compactBox(m_dialog.findChild<QCheckBox*>("compactBox")),
- m_showMetaBox(m_dialog.findChild<QCheckBox*>("showMetaBox"))
+Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog)
+ : Settings::SettingsTab(m_parent, m_dialog)
+ , m_languageBox(m_dialog.findChild<QComboBox *>("languageBox"))
+ , m_styleBox(m_dialog.findChild<QComboBox *>("styleBox"))
+ , m_logLevelBox(m_dialog.findChild<QComboBox *>("logLevelBox"))
+ , m_compactBox(m_dialog.findChild<QCheckBox *>("compactBox"))
+ , m_showMetaBox(m_dialog.findChild<QCheckBox *>("showMetaBox"))
+{
+ // FIXME I think 'addLanguages' lives in here not in parent
+ m_parent->addLanguages(m_languageBox);
{
- //FIXME I think 'addLanguages' lives in here not in parent
- m_parent->addLanguages(m_languageBox);
- {
- QString languageCode = m_parent->language();
- int currentID = m_languageBox->findData(languageCode);
- // I made a mess. :( Most languages are stored with only the iso country code (2 characters like "de") but chinese
- // with the exact language variant (zh_TW) so I have to search for both variants
- if (currentID == -1) {
- currentID = m_languageBox->findData(languageCode.mid(0, 2));
- }
- if (currentID != -1) {
- m_languageBox->setCurrentIndex(currentID);
- }
+ QString languageCode = m_parent->language();
+ int currentID = m_languageBox->findData(languageCode);
+ // I made a mess. :( Most languages are stored with only the iso country
+ // code (2 characters like "de") but chinese
+ // with the exact language variant (zh_TW) so I have to search for both
+ // variants
+ if (currentID == -1) {
+ currentID = m_languageBox->findData(languageCode.mid(0, 2));
+ }
+ if (currentID != -1) {
+ m_languageBox->setCurrentIndex(currentID);
}
+ }
- //FIXME I think addStyles lives in here not in parent
- m_parent->addStyles(m_styleBox);
- {
- int currentID = m_styleBox->findData(m_Settings.value("Settings/style", "").toString());
- if (currentID != -1) {
- m_styleBox->setCurrentIndex(currentID);
- }
+ // FIXME I think addStyles lives in here not in parent
+ m_parent->addStyles(m_styleBox);
+ {
+ int currentID = m_styleBox->findData(
+ m_Settings.value("Settings/style", "").toString());
+ if (currentID != -1) {
+ m_styleBox->setCurrentIndex(currentID);
}
+ }
- m_logLevelBox->setCurrentIndex(m_parent->logLevel());
- m_downloadDirEdit->setText(m_parent->getDownloadDirectory());
- m_modDirEdit->setText(m_parent->getModDirectory());
- m_cacheDirEdit->setText(m_parent->getCacheDirectory());
- m_compactBox->setChecked(m_parent->compactDownloads());
- m_showMetaBox->setChecked(m_parent->metaDownloads());
+ m_logLevelBox->setCurrentIndex(m_parent->logLevel());
+ m_compactBox->setChecked(m_parent->compactDownloads());
+ m_showMetaBox->setChecked(m_parent->metaDownloads());
}
void Settings::GeneralTab::update()
@@ -622,68 +626,108 @@ void Settings::GeneralTab::update()
m_Settings.setValue("Settings/log_level", m_logLevelBox->currentIndex());
- { // advanced settings
- if ((QDir::fromNativeSeparators(m_modDirEdit->text()) != QDir::fromNativeSeparators(m_parent->getModDirectory())) &&
- (QMessageBox::question(nullptr, tr("Confirm"), tr("Changing the mod directory affects all your profiles! "
- "Mods not present (or named differently) in the new location will be disabled in all profiles. "
- "There is no way to undo this unless you backed up your profiles manually. Proceed?"),
- QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)) {
- m_modDirEdit->setText(m_parent->getModDirectory());
- }
- if (!QDir(m_downloadDirEdit->text()).exists()) {
- QDir().mkpath(m_downloadDirEdit->text());
- }
- if (QFileInfo(m_downloadDirEdit->text()) !=
- QFileInfo(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::downloadPath()))) {
- m_Settings.setValue("Settings/download_directory", QDir::toNativeSeparators(m_downloadDirEdit->text()));
- } else {
- m_Settings.remove("Settings/download_directory");
- }
+ m_Settings.setValue("Settings/compact_downloads", m_compactBox->isChecked());
+ m_Settings.setValue("Settings/meta_downloads", m_showMetaBox->isChecked());
+}
- if (!QDir(m_modDirEdit->text()).exists()) {
- QDir().mkpath(m_modDirEdit->text());
- }
- if (QFileInfo(m_modDirEdit->text()) !=
- QFileInfo(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::modsPath()))) {
- m_Settings.setValue("Settings/mod_directory", QDir::toNativeSeparators(m_modDirEdit->text()));
- } else {
- m_Settings.remove("Settings/mod_directory");
- }
+Settings::PathsTab::PathsTab(Settings *parent, SettingsDialog &dialog)
+ : SettingsTab(parent, dialog)
+ , m_downloadDirEdit(m_dialog.findChild<QLineEdit *>("downloadDirEdit"))
+ , m_modDirEdit(m_dialog.findChild<QLineEdit *>("modDirEdit"))
+ , m_cacheDirEdit(m_dialog.findChild<QLineEdit *>("cacheDirEdit"))
+ , m_profilesDirEdit(m_dialog.findChild<QLineEdit *>("profilesDirEdit"))
+{
+ m_downloadDirEdit->setText(m_parent->getDownloadDirectory());
+ m_modDirEdit->setText(m_parent->getModDirectory());
+ m_cacheDirEdit->setText(m_parent->getCacheDirectory());
+ m_profilesDirEdit->setText(m_parent->getProfileDirectory());
+}
- if (!QDir(m_cacheDirEdit->text()).exists()) {
- QDir().mkpath(m_cacheDirEdit->text());
- }
- if (QFileInfo(m_cacheDirEdit->text()) !=
- QFileInfo(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::cachePath()))) {
- m_Settings.setValue("Settings/cache_directory", QDir::toNativeSeparators(m_cacheDirEdit->text()));
- } else {
- m_Settings.remove("Settings/cache_directory");
- }
+void Settings::PathsTab::update()
+{
+ if ((QDir::fromNativeSeparators(m_modDirEdit->text())
+ != QDir::fromNativeSeparators(m_parent->getModDirectory()))
+ && (QMessageBox::question(
+ nullptr, tr("Confirm"),
+ tr("Changing the mod directory affects all your profiles! "
+ "Mods not present (or named differently) in the new location "
+ "will be disabled in all profiles. "
+ "There is no way to undo this unless you backed up your "
+ "profiles manually. Proceed?"),
+ QMessageBox::Yes | QMessageBox::No)
+ == QMessageBox::No)) {
+ m_modDirEdit->setText(m_parent->getModDirectory());
}
- m_Settings.setValue("Settings/compact_downloads", m_compactBox->isChecked());
- m_Settings.setValue("Settings/meta_downloads", m_showMetaBox->isChecked());
+ if (!QDir(m_downloadDirEdit->text()).exists()) {
+ QDir().mkpath(m_downloadDirEdit->text());
+ }
+ if (QFileInfo(m_downloadDirEdit->text())
+ != QFileInfo(qApp->property("dataPath").toString() + "/"
+ + QString::fromStdWString(AppConfig::downloadPath()))) {
+ m_Settings.setValue("Settings/download_directory",
+ QDir::toNativeSeparators(m_downloadDirEdit->text()));
+ } else {
+ m_Settings.remove("Settings/download_directory");
+ }
+
+ if (!QDir(m_modDirEdit->text()).exists()) {
+ QDir().mkpath(m_modDirEdit->text());
+ }
+ if (QFileInfo(m_modDirEdit->text())
+ != QFileInfo(qApp->property("dataPath").toString() + "/"
+ + QString::fromStdWString(AppConfig::modsPath()))) {
+ m_Settings.setValue("Settings/mod_directory",
+ QDir::toNativeSeparators(m_modDirEdit->text()));
+ } else {
+ m_Settings.remove("Settings/mod_directory");
+ }
+
+ if (!QDir(m_cacheDirEdit->text()).exists()) {
+ QDir().mkpath(m_cacheDirEdit->text());
+ }
+ if (QFileInfo(m_cacheDirEdit->text())
+ != QFileInfo(qApp->property("dataPath").toString() + "/"
+ + QString::fromStdWString(AppConfig::cachePath()))) {
+ m_Settings.setValue("Settings/cache_directory",
+ QDir::toNativeSeparators(m_cacheDirEdit->text()));
+ } else {
+ m_Settings.remove("Settings/cache_directory");
+ }
+
+ if (!QDir(m_profilesDirEdit->text()).exists()) {
+ QDir().mkpath(m_profilesDirEdit->text());
+ }
+ if (QFileInfo(m_profilesDirEdit->text())
+ != QFileInfo(qApp->property("dataPath").toString() + "/"
+ + QString::fromStdWString(AppConfig::profilesPath()))) {
+ m_Settings.setValue("Settings/profiles_directory",
+ QDir::toNativeSeparators(m_profilesDirEdit->text()));
+ } else {
+ m_Settings.remove("Settings/profiles_directory");
+ }
}
-Settings::NexusTab::NexusTab(Settings *m_parent, SettingsDialog &m_dialog) :
- Settings::SettingsTab(m_parent, m_dialog),
- m_loginCheckBox(m_dialog.findChild<QCheckBox*>("loginCheckBox")),
- m_usernameEdit(m_dialog.findChild<QLineEdit*>("usernameEdit")),
- m_passwordEdit(m_dialog.findChild<QLineEdit*>("passwordEdit")),
- m_offlineBox(m_dialog.findChild<QCheckBox*>("offlineBox")),
- m_proxyBox(m_dialog.findChild<QCheckBox*>("proxyBox")),
- m_knownServersList(m_dialog.findChild<QListWidget*>("knownServersList")),
- m_preferredServersList(m_dialog.findChild<QListWidget*>("preferredServersList"))
+Settings::NexusTab::NexusTab(Settings *parent, SettingsDialog &dialog)
+ : Settings::SettingsTab(parent, dialog)
+ , m_loginCheckBox(dialog.findChild<QCheckBox *>("loginCheckBox"))
+ , m_usernameEdit(dialog.findChild<QLineEdit *>("usernameEdit"))
+ , m_passwordEdit(dialog.findChild<QLineEdit *>("passwordEdit"))
+ , m_offlineBox(dialog.findChild<QCheckBox *>("offlineBox"))
+ , m_proxyBox(dialog.findChild<QCheckBox *>("proxyBox"))
+ , m_knownServersList(dialog.findChild<QListWidget *>("knownServersList"))
+ , m_preferredServersList(
+ dialog.findChild<QListWidget *>("preferredServersList"))
{
- if (m_parent->automaticLoginEnabled()) {
+ if (parent->automaticLoginEnabled()) {
m_loginCheckBox->setChecked(true);
m_usernameEdit->setText(m_Settings.value("Settings/nexus_username", "").toString());
m_passwordEdit->setText(deObfuscate(m_Settings.value("Settings/nexus_password", "").toString()));
}
- m_offlineBox->setChecked(m_parent->offlineMode());
- m_proxyBox->setChecked(m_parent->useProxy());
+ m_offlineBox->setChecked(parent->offlineMode());
+ m_proxyBox->setChecked(parent->useProxy());
// display server preferences
m_Settings.beginGroup("Servers");
@@ -743,11 +787,10 @@ void Settings::NexusTab::update()
m_Settings.endGroup();
}
-
-Settings::SteamTab::SteamTab(Settings *m_parent, SettingsDialog &m_dialog) :
- Settings::SettingsTab(m_parent, m_dialog),
- m_steamUserEdit(m_dialog.findChild<QLineEdit*>("steamUserEdit")),
- m_steamPassEdit(m_dialog.findChild<QLineEdit*>("steamPassEdit"))
+Settings::SteamTab::SteamTab(Settings *m_parent, SettingsDialog &m_dialog)
+ : Settings::SettingsTab(m_parent, m_dialog)
+ , m_steamUserEdit(m_dialog.findChild<QLineEdit *>("steamUserEdit"))
+ , m_steamPassEdit(m_dialog.findChild<QLineEdit *>("steamPassEdit"))
{
if (m_Settings.contains("Settings/steam_username")) {
m_steamUserEdit->setText(m_Settings.value("Settings/steam_username", "").toString());
@@ -763,10 +806,10 @@ void Settings::SteamTab::update()
m_parent->setSteamLogin(m_steamUserEdit->text(), m_steamPassEdit->text());
}
-Settings::PluginsTab::PluginsTab(Settings *m_parent, SettingsDialog &m_dialog) :
- Settings::SettingsTab(m_parent, m_dialog),
- m_pluginsList(m_dialog.findChild<QListWidget*>("pluginsList")),
- m_pluginBlacklistList(m_dialog.findChild<QListWidget*>("pluginBlacklist"))
+Settings::PluginsTab::PluginsTab(Settings *m_parent, SettingsDialog &m_dialog)
+ : Settings::SettingsTab(m_parent, m_dialog)
+ , m_pluginsList(m_dialog.findChild<QListWidget *>("pluginsList"))
+ , m_pluginBlacklistList(m_dialog.findChild<QListWidget *>("pluginBlacklist"))
{
// display plugin settings
for (IPlugin *plugin : m_parent->m_Plugins) {
@@ -799,20 +842,21 @@ void Settings::PluginsTab::update()
// store plugin blacklist
m_parent->m_PluginBlacklist.clear();
- foreach (QListWidgetItem *item, m_pluginBlacklistList->findItems("*", Qt::MatchWildcard)) {
+ for (QListWidgetItem *item : m_pluginBlacklistList->findItems("*", Qt::MatchWildcard)) {
m_parent->m_PluginBlacklist.insert(item->text());
}
m_parent->writePluginBlacklist();
}
-Settings::WorkaroundsTab::WorkaroundsTab(Settings *m_parent, SettingsDialog &m_dialog) :
- Settings::SettingsTab(m_parent, m_dialog),
- m_appIDEdit(m_dialog.findChild<QLineEdit*>("appIDEdit")),
- m_mechanismBox(m_dialog.findChild<QComboBox*>("mechanismBox")),
- m_nmmVersionEdit(m_dialog.findChild<QLineEdit*>("nmmVersionEdit")),
- m_hideUncheckedBox(m_dialog.findChild<QCheckBox*>("hideUncheckedBox")),
- m_forceEnableBox(m_dialog.findChild<QCheckBox*>("forceEnableBox")),
- m_displayForeignBox(m_dialog.findChild<QCheckBox*>("displayForeignBox"))
+Settings::WorkaroundsTab::WorkaroundsTab(Settings *m_parent,
+ SettingsDialog &m_dialog)
+ : Settings::SettingsTab(m_parent, m_dialog)
+ , m_appIDEdit(m_dialog.findChild<QLineEdit *>("appIDEdit"))
+ , m_mechanismBox(m_dialog.findChild<QComboBox *>("mechanismBox"))
+ , m_nmmVersionEdit(m_dialog.findChild<QLineEdit *>("nmmVersionEdit"))
+ , m_hideUncheckedBox(m_dialog.findChild<QCheckBox *>("hideUncheckedBox"))
+ , m_forceEnableBox(m_dialog.findChild<QCheckBox *>("forceEnableBox"))
+ , m_displayForeignBox(m_dialog.findChild<QCheckBox *>("displayForeignBox"))
{
m_appIDEdit->setText(m_parent->getSteamAppID());
diff --git a/src/settings.h b/src/settings.h
index 1ee16e76..85a3dac0 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -131,6 +131,11 @@ public:
QString getCacheDirectory() const;
/**
+ * retrieve the directory where profiles stored (with native separators)
+ **/
+ QString getProfileDirectory() const;
+
+ /**
* @return true if the user has set up automatic login to nexus
**/
bool automaticLoginEnabled() const;
@@ -339,11 +344,22 @@ private:
QComboBox *m_languageBox;
QComboBox *m_styleBox;
QComboBox *m_logLevelBox;
+ QCheckBox *m_compactBox;
+ QCheckBox *m_showMetaBox;
+ };
+
+ class PathsTab : public SettingsTab
+ {
+ public:
+ PathsTab(Settings *parent, SettingsDialog &dialog);
+
+ void update();
+
+ private:
QLineEdit *m_downloadDirEdit;
QLineEdit *m_modDirEdit;
QLineEdit *m_cacheDirEdit;
- QCheckBox *m_compactBox;
- QCheckBox *m_showMetaBox;
+ QLineEdit *m_profilesDirEdit;
};
/** Display/store the configuration in the 'nexus' tab of the settings dialogue */
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
index 4e2f89a1..341fa19d 100644
--- a/src/settingsdialog.cpp
+++ b/src/settingsdialog.cpp
@@ -25,6 +25,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "noeditdelegate.h"
#include "iplugingame.h"
#include "settings.h"
+#include "instancemanager.h"
#include <QDirIterator>
#include <QFileDialog>
@@ -39,11 +40,13 @@ using namespace MOBase;
SettingsDialog::SettingsDialog(QWidget *parent)
- : TutorableDialog("SettingsDialog", parent), ui(new Ui::SettingsDialog)
+ : TutorableDialog("SettingsDialog", parent)
+ , ui(new Ui::SettingsDialog)
{
ui->setupUi(this);
- QShortcut *delShortcut = new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist);
+ QShortcut *delShortcut
+ = new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist);
connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem()));
}
@@ -54,7 +57,7 @@ SettingsDialog::~SettingsDialog()
void SettingsDialog::addPlugins(const std::vector<IPlugin*> &plugins)
{
- foreach (IPlugin *plugin, plugins) {
+ for (IPlugin *plugin : plugins) {
ui->pluginsList->addItem(plugin->name());
}
}
@@ -89,7 +92,8 @@ void SettingsDialog::on_categoriesBtn_clicked()
void SettingsDialog::on_bsaDateBtn_clicked()
{
- IPluginGame const *game = qApp->property("managed_game").value<IPluginGame *>();
+ IPluginGame const *game
+ = qApp->property("managed_game").value<IPluginGame *>();
QDir dir = game->dataDirectory();
Helper::backdateBSAs(qApp->property("dataPath").toString().toStdWString(),
@@ -186,3 +190,15 @@ void SettingsDialog::on_associateButton_clicked()
{
Settings::instance().registerAsNXMHandler(true);
}
+
+void SettingsDialog::on_changeInstanceButton_clicked()
+{
+ if (QMessageBox::question(this, tr("Are you sure?"),
+ tr("This will restart MO, continue?"),
+ QMessageBox::Yes | QMessageBox::Cancel)
+ == QMessageBox::Yes) {
+ InstanceManager().clearCurrentInstance();
+ this->reject();
+ qApp->exit(INT_MAX);
+ }
+}
diff --git a/src/settingsdialog.h b/src/settingsdialog.h
index e99fb3e3..8bd080ab 100644
--- a/src/settingsdialog.h
+++ b/src/settingsdialog.h
@@ -52,6 +52,9 @@ signals:
void resetDialogs();
+private slots:
+ void on_changeInstanceButton_clicked();
+
private:
void storeSettings(QListWidgetItem *pluginItem);
diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui
index b88885dc..805a5060 100644
--- a/src/settingsdialog.ui
+++ b/src/settingsdialog.ui
@@ -108,114 +108,60 @@ p, li { white-space: pre-wrap; }
</layout>
</item>
<item>
- <widget class="QGroupBox" name="groupBox_2">
+ <widget class="QGroupBox" name="groupBox">
<property name="title">
- <string>Advanced</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="checked">
- <bool>false</bool>
+ <string>User interface</string>
</property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="1">
- <widget class="QLineEdit" name="downloadDirEdit">
+ <layout class="QVBoxLayout" name="verticalLayout_11">
+ <item>
+ <widget class="QCheckBox" name="compactBox">
<property name="toolTip">
- <string>Directory where downloads are stored.</string>
+ <string>If checked, the download interface will be more compact.</string>
</property>
- <property name="whatsThis">
- <string>Directory where downloads are stored.</string>
+ <property name="text">
+ <string>Compact Download Interface</string>
</property>
</widget>
</item>
- <item row="0" column="2">
- <widget class="QPushButton" name="browseDownloadDirBtn">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <item>
+ <widget class="QCheckBox" name="showMetaBox">
+ <property name="toolTip">
+ <string>If checked, the download list will display meta information instead of file names.</string>
</property>
<property name="text">
- <string notr="true">...</string>
+ <string>Download Meta Information</string>
</property>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_8">
- <property name="text">
- <string>Mod Directory</string>
+ <item>
+ <widget class="QPushButton" name="resetDialogsButton">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
</property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLineEdit" name="modDirEdit">
<property name="toolTip">
- <string>Directory where mods are stored.</string>
+ <string>Reset stored information from dialogs.</string>
</property>
<property name="whatsThis">
- <string>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</string>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QPushButton" name="browseModDirBtn">
- <property name="text">
- <string notr="true">...</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Download Directory</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_9">
- <property name="text">
- <string>Cache Directory</string>
+ <string>This will make all dialogs show up again where you checked the &quot;Remember selection&quot;-box.</string>
</property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLineEdit" name="cacheDirEdit"/>
- </item>
- <item row="3" column="2">
- <widget class="QPushButton" name="browseCacheDirBtn">
<property name="text">
- <string notr="true">...</string>
+ <string>Reset Dialogs</string>
</property>
</widget>
</item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>User interface</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_11">
<item>
- <widget class="QCheckBox" name="compactBox">
+ <widget class="QPushButton" name="categoriesBtn">
<property name="toolTip">
- <string>If checked, the download interface will be more compact.</string>
+ <string>Modify the categories available to arrange your mods.</string>
</property>
- <property name="text">
- <string>Compact Download Interface</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="showMetaBox">
- <property name="toolTip">
- <string>If checked, the download list will display meta information instead of file names.</string>
+ <property name="whatsThis">
+ <string>Modify the categories available to arrange your mods.</string>
</property>
<property name="text">
- <string>Download Meta Information</string>
+ <string>Configure Mod Categories</string>
</property>
</widget>
</item>
@@ -223,26 +169,132 @@ p, li { white-space: pre-wrap; }
</widget>
</item>
<item>
- <widget class="QPushButton" name="resetDialogsButton">
- <property name="maximumSize">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
<size>
- <width>16777215</width>
- <height>16777215</height>
+ <width>20</width>
+ <height>40</height>
</size>
</property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="changeInstanceButton">
<property name="toolTip">
- <string>Reset stored information from dialogs.</string>
+ <string>Restart MO and choose a different set of data paths.</string>
</property>
<property name="whatsThis">
- <string>This will make all dialogs show up again where you checked the &quot;Remember selection&quot;-box.</string>
+ <string>This will restart MO and give you opportunity to switch to a different set of data paths.</string>
</property>
<property name="text">
- <string>Reset Dialogs</string>
+ <string>Change Instance</string>
</property>
</widget>
</item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="pathsTab">
+ <attribute name="title">
+ <string>Paths</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_10">
<item>
- <spacer name="verticalSpacer">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Downloads</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Caches</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="browseModDirBtn">
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="cacheDirEdit"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="downloadDirEdit">
+ <property name="toolTip">
+ <string>Directory where downloads are stored.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Directory where downloads are stored.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>Mods</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="browseCacheDirBtn">
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="modDirEdit">
+ <property name="toolTip">
+ <string>Directory where mods are stored.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="browseDownloadDirBtn">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_22">
+ <property name="text">
+ <string>Profiles</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="profilesDirEdit"/>
+ </item>
+ <item row="3" column="2">
+ <widget class="QPushButton" name="browseProfilesDirBtn">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -255,15 +307,9 @@ p, li { white-space: pre-wrap; }
</spacer>
</item>
<item>
- <widget class="QPushButton" name="categoriesBtn">
- <property name="toolTip">
- <string>Modify the categories available to arrange your mods.</string>
- </property>
- <property name="whatsThis">
- <string>Modify the categories available to arrange your mods.</string>
- </property>
+ <widget class="QLabel" name="label_23">
<property name="text">
- <string>Configure Mod Categories</string>
+ <string>Important: All directories have to be writeable!</string>
</property>
</widget>
</item>