diff options
| author | Tannin <sherb@gmx.net> | 2016-01-10 20:19:56 +0100 |
|---|---|---|
| committer | Tannin <sherb@gmx.net> | 2016-01-10 20:19:56 +0100 |
| commit | 2aae65d6f6c1ab3309e54437a339d1644088c5c8 (patch) | |
| tree | b693c455a4433370724cfbaa23a66998a16027a9 /src | |
| parent | ddf841400ef4da235f11e9b67177a78bb3d519d4 (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.txt | 22 | ||||
| -rw-r--r-- | src/installationmanager.cpp | 2 | ||||
| -rw-r--r-- | src/instancemanager.cpp | 206 | ||||
| -rw-r--r-- | src/instancemanager.h | 62 | ||||
| -rw-r--r-- | src/logbuffer.cpp | 120 | ||||
| -rw-r--r-- | src/main.cpp | 321 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 26 | ||||
| -rw-r--r-- | src/mainwindow.h | 7 | ||||
| -rw-r--r-- | src/organizercore.cpp | 22 | ||||
| -rw-r--r-- | src/organizercore.h | 2 | ||||
| -rw-r--r-- | src/profile.cpp | 7 | ||||
| -rw-r--r-- | src/profilesdialog.cpp | 6 | ||||
| -rw-r--r-- | src/selectiondialog.cpp | 5 | ||||
| -rw-r--r-- | src/selectiondialog.h | 2 | ||||
| -rw-r--r-- | src/selfupdater.cpp | 2 | ||||
| -rw-r--r-- | src/settings.cpp | 274 | ||||
| -rw-r--r-- | src/settings.h | 20 | ||||
| -rw-r--r-- | src/settingsdialog.cpp | 24 | ||||
| -rw-r--r-- | src/settingsdialog.h | 3 | ||||
| -rw-r--r-- | src/settingsdialog.ui | 242 |
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 "Remember selection"-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 "Remember selection"-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>
|
