Compare commits

...
3 Commits
Author SHA1 Message Date
Tannin 1439347def updated version number 2016-02-08 20:33:53 +01:00
Tannin a9a51f5085 fixed a potential crash-cause when querying download info and slight improvement (?) to the regex that extracts the modid 2016-01-10 20:22:50 +01:00
Tannin 2aae65d6f6 made instance-switching usable
this includes tons and tons of changes to how paths are determined.
the profiles-dir can now also be configured
2016-01-10 20:19:56 +01:00
23 changed files with 924 additions and 512 deletions
+12 -10
View File
@@ -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
+9 -14
View File
@@ -693,19 +693,14 @@ void DownloadManager::queryInfo(int index)
QString ignore;
NexusInterface::interpretNexusFileName(fileName, ignore, info->m_FileInfo->modID, true);
if (info->m_FileInfo->modID < 0) {
QString modIDString;
while (modIDString.isEmpty()) {
modIDString = QInputDialog::getText(nullptr, tr("Please enter the nexus mod id"), tr("Mod ID:"), QLineEdit::Normal,
QString(), nullptr, 0, Qt::ImhFormattedNumbersOnly);
if (modIDString.isNull()) {
// canceled
return;
} else if (modIDString.contains(QRegExp("[^0-9]"))) {
qDebug("illegal character in mod-id");
modIDString.clear();
}
}
info->m_FileInfo->modID = modIDString.toInt(nullptr, 10);
bool ok = false;
int modId = QInputDialog::getInt(
nullptr, tr("Please enter the nexus mod id"), tr("Mod ID:"), 1, 1,
std::numeric_limits<int>::max(), 1, &ok);
// careful now: while the dialog was displayed, events were processed.
// the download list might have changed and our info-ptr invalidated.
m_ActiveDownloads[index]->m_FileInfo->modID = modId;
return;
}
}
info->m_ReQueried = true;
@@ -1247,7 +1242,7 @@ int DownloadManager::startDownloadURLs(const QStringList &urls)
int DownloadManager::startDownloadNexusFile(int modID, int fileID)
{
int newID = m_ActiveDownloads.size();
addNXMDownload(QString("nxm://%1/mods/%2/files/%3").arg(m_ManagedGame->getGameShortName()).arg(modID).arg(fileID));
addNXMDownload(QString("nxm://%1/mods/%2/files/%3").arg(m_ManagedGame->gameShortName()).arg(modID).arg(fileID));
return newID;
}
+1 -1
View File
@@ -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()));
}
+206
View File
@@ -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;
}
}
+62
View File
@@ -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;
};
+64 -56
View File
@@ -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);
}
+162 -163
View File
@@ -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[])
// 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()
{
MOApplication application(argc, argv);
static const int BUFSIZE = 4096;
qDebug("application name: %s", qPrintable(application.applicationName()));
qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators(
QCoreApplication::applicationDirPath())));
QString instanceID;
QFile instanceFile(application.applicationDirPath() + "/INSTANCE");
if (instanceFile.open(QIODevice::ReadOnly)) {
instanceID = instanceFile.readAll().trimmed();
}
QString const dataPath =
instanceID.isEmpty() ? application.applicationDirPath()
: QDir::fromNativeSeparators(
QStandardPaths::writableLocation(QStandardPaths::DataLocation)
+ "/" + instanceID
);
application.setProperty("dataPath", dataPath);
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";
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;
}
::SetEnvironmentVariableW(L"PATH", newPath.c_str());
}
int runApplication(MOApplication &application, SingleInstance &instance)
{
qDebug("start main application");
QPixmap pixmap(":/MO/gui/splash");
QSplashScreen splash(pixmap);
QString dataPath = application.property("dataPath").toString();
qDebug("data path: %s", qPrintable(dataPath));
if (!bootstrap()) {
reportError("failed to set up data path");
return 1;
}
QStringList arguments = application.arguments();
try {
if (!bootstrap()) {
return -1;
}
LogBuffer::init(100, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log");
#if QT_VERSION >= 0x050000 && !defined(QT_NO_SSL)
qDebug("ssl support: %d", QSslSocket::supportsSsl());
#endif
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);
}
+17 -9
View File
@@ -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);
}
+3 -4
View File
@@ -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
+1 -1
View File
@@ -193,7 +193,7 @@ void NexusInterface::loginCompleted()
void NexusInterface::interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query)
{
//Look for something along the lines of modulename-Vn-m + any old rubbish.
static std::regex exp("^([a-zA-Z0-9_'\"\\- ]*?)([-_ ][VvRr]?[0-9_]+)?-([1-9][0-9]+).*");
static std::regex exp("^([a-zA-Z0-9_'\"\\-.() ]*?)([-_ ][VvRr]?[0-9_]+)?-([1-9][0-9]+).*\.(zip|rar|7z)");
static std::regex simpleexp("^([a-zA-Z0-9_]+)");
QByteArray fileNameUTF8 = fileName.toUtf8();
+10 -12
View File
@@ -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()),
"\\",
+2
View File
@@ -201,6 +201,8 @@ signals:
void managedGameChanged(MOBase::IPluginGame const *gamePlugin);
void close();
private:
void storeSettings();
+4 -3
View File
@@ -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);
}
+3 -3
View File
@@ -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. "
+5
View File
@@ -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)
{
+2
View File
@@ -53,6 +53,8 @@ public:
QVariant getChoiceData();
QString getChoiceString();
void disableCancel();
private slots:
void on_buttonBox_clicked(QAbstractButton *button);
+1 -1
View File
@@ -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()));
}
+162 -118
View File
@@ -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));
}
//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);
}
if (currentID != -1) {
m_languageBox->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());
// 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_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");
}
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");
}
}
m_Settings.setValue("Settings/compact_downloads", m_compactBox->isChecked());
m_Settings.setValue("Settings/meta_downloads", m_showMetaBox->isChecked());
}
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::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"))
{
if (m_parent->automaticLoginEnabled()) {
m_downloadDirEdit->setText(m_parent->getDownloadDirectory());
m_modDirEdit->setText(m_parent->getModDirectory());
m_cacheDirEdit->setText(m_parent->getCacheDirectory());
m_profilesDirEdit->setText(m_parent->getProfileDirectory());
}
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());
}
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 *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 (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());
+18 -2
View File
@@ -130,6 +130,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
**/
@@ -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 */
+20 -4
View File
@@ -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);
}
}

Some files were not shown because too many files have changed in this diff Show More