From f6ef5477e718b14af99bd22436f66dee0b9d22cd Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 17 Jul 2014 22:02:15 +0200 Subject: normalized eol style (all files should now have windows line endings) --- src/profilesdialog.h | 192 +++++++++++++++++++++++++-------------------------- 1 file changed, 96 insertions(+), 96 deletions(-) (limited to 'src/profilesdialog.h') diff --git a/src/profilesdialog.h b/src/profilesdialog.h index f864a7e0..905d49b1 100644 --- a/src/profilesdialog.h +++ b/src/profilesdialog.h @@ -1,96 +1,96 @@ -/* -Copyright (C) 2012 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 . -*/ - -#ifndef PROFILESDIALOG_H -#define PROFILESDIALOG_H - -#include "tutorabledialog.h" -#include -#include "profile.h" - - -namespace Ui { - class ProfilesDialog; -} - - -/** - * @brief Dialog that can be used to create/delete/modify profiles - **/ -class ProfilesDialog : public MOBase::TutorableDialog -{ - Q_OBJECT - -public: - - /** - * @brief constructor - * - * @param gamePath the path to the game directory - * @param parent parent widget - * @todo the game path could be retrieved from GameInfo just as easily - **/ - explicit ProfilesDialog(const QString &gamePath, QWidget *parent = 0); - ~ProfilesDialog(); - - /** - * @return true if creation of a new profile failed - * @todo the notion of a fail state makes little sense in the current dialog - **/ - bool failed() const { return m_FailState; } - -protected: - - virtual void showEvent(QShowEvent *event); - -private: - - void addItem(const QString &name); - void createProfile(const QString &name, bool useDefaultSettings); - void createProfile(const QString &name, const Profile &reference); - -private slots: - - void on_closeButton_clicked(); - - void on_addProfileButton_clicked(); - - void on_invalidationBox_stateChanged(int arg1); - - void on_copyProfileButton_clicked(); - - void on_profilesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); - - void on_removeProfileButton_clicked(); - - void on_localSavesBox_stateChanged(int arg1); - - void on_transferButton_clicked(); - - void on_renameButton_clicked(); - -private: - Ui::ProfilesDialog *ui; - QString m_GamePath; - QListWidget *m_ProfilesList; - bool m_FailState; - -}; - -#endif // PROFILESDIALOG_H +/* +Copyright (C) 2012 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 . +*/ + +#ifndef PROFILESDIALOG_H +#define PROFILESDIALOG_H + +#include "tutorabledialog.h" +#include +#include "profile.h" + + +namespace Ui { + class ProfilesDialog; +} + + +/** + * @brief Dialog that can be used to create/delete/modify profiles + **/ +class ProfilesDialog : public MOBase::TutorableDialog +{ + Q_OBJECT + +public: + + /** + * @brief constructor + * + * @param gamePath the path to the game directory + * @param parent parent widget + * @todo the game path could be retrieved from GameInfo just as easily + **/ + explicit ProfilesDialog(const QString &gamePath, QWidget *parent = 0); + ~ProfilesDialog(); + + /** + * @return true if creation of a new profile failed + * @todo the notion of a fail state makes little sense in the current dialog + **/ + bool failed() const { return m_FailState; } + +protected: + + virtual void showEvent(QShowEvent *event); + +private: + + void addItem(const QString &name); + void createProfile(const QString &name, bool useDefaultSettings); + void createProfile(const QString &name, const Profile &reference); + +private slots: + + void on_closeButton_clicked(); + + void on_addProfileButton_clicked(); + + void on_invalidationBox_stateChanged(int arg1); + + void on_copyProfileButton_clicked(); + + void on_profilesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + + void on_removeProfileButton_clicked(); + + void on_localSavesBox_stateChanged(int arg1); + + void on_transferButton_clicked(); + + void on_renameButton_clicked(); + +private: + Ui::ProfilesDialog *ui; + QString m_GamePath; + QListWidget *m_ProfilesList; + bool m_FailState; + +}; + +#endif // PROFILESDIALOG_H -- cgit v1.3.1 From 9edc39633b82b5e02d33c4b0a395fe110af28eb4 Mon Sep 17 00:00:00 2001 From: Tannin Date: Tue, 6 Jan 2015 19:31:53 +0100 Subject: - bugfixes - moved more functionality to game-plugins - further decoupled management functionality from the UI - created another "tutorial" which is only a single page with relevant parts of the ui highlighted with info as tooltips --- src/dlls.manifest.debug.qt5 | 16 ++- src/dlls.manifest.qt5 | 7 +- src/executableslist.cpp | 2 - src/iuserinterface.h | 3 + src/logbuffer.cpp | 8 +- src/main.cpp | 63 ++++++++--- src/mainwindow.cpp | 132 ++++++----------------- src/mainwindow.h | 5 - src/modinfo.cpp | 3 +- src/modlist.cpp | 4 +- src/motddialog.cpp | 2 - src/organizer.pro | 11 +- src/organizercore.cpp | 198 +++++++++++++++------------------- src/organizercore.h | 18 +++- src/organizerproxy.cpp | 2 +- src/pluginlist.h | 1 - src/profile.cpp | 47 ++++---- src/profile.h | 16 ++- src/profilesdialog.cpp | 26 +++-- src/profilesdialog.h | 7 +- src/settings.cpp | 12 ++- src/settings.h | 12 +++ src/shared/appconfig.inc | 5 +- src/shared/fallout3info.cpp | 105 ------------------ src/shared/fallout3info.h | 10 -- src/shared/falloutnvinfo.cpp | 81 -------------- src/shared/falloutnvinfo.h | 11 -- src/shared/gameinfo.cpp | 43 +------- src/shared/gameinfo.h | 15 +-- src/shared/oblivioninfo.cpp | 105 ------------------ src/shared/oblivioninfo.h | 11 -- src/shared/skyriminfo.cpp | 109 +------------------ src/shared/skyriminfo.h | 16 --- src/transfersavesdialog.cpp | 23 ++-- src/transfersavesdialog.h | 5 +- src/tutorials/Highlight.qml | 1 - src/tutorials/Tooltip.qml | 31 ++++++ src/tutorials/TooltipArea.qml | 55 ++++++++++ src/tutorials/TutorialDescription.qml | 5 +- src/tutorials/TutorialOverlay.qml | 93 +++++++++------- src/tutorials/tutorial_primer_main.js | 111 +++++++++++++++++++ src/tutorials/tutorials.js | 28 +++-- 42 files changed, 590 insertions(+), 868 deletions(-) create mode 100644 src/tutorials/Tooltip.qml create mode 100644 src/tutorials/TooltipArea.qml create mode 100644 src/tutorials/tutorial_primer_main.js (limited to 'src/profilesdialog.h') diff --git a/src/dlls.manifest.debug.qt5 b/src/dlls.manifest.debug.qt5 index 1bbdf691..e49b33b8 100644 --- a/src/dlls.manifest.debug.qt5 +++ b/src/dlls.manifest.debug.qt5 @@ -1,19 +1,27 @@ - - - + + + - + + + + + + + + + diff --git a/src/dlls.manifest.qt5 b/src/dlls.manifest.qt5 index 59918f2b..b8f2d467 100644 --- a/src/dlls.manifest.qt5 +++ b/src/dlls.manifest.qt5 @@ -1,9 +1,9 @@ - - - + + + @@ -19,6 +19,7 @@ + diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 25b6bb0f..65a2ea80 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -92,7 +92,6 @@ void ExecutablesList::getExecutables(std::vector::iterator &begin, s end = m_Executables.end(); } - void ExecutablesList::getExecutables(std::vector::const_iterator &begin, std::vector::const_iterator &end) const { @@ -100,7 +99,6 @@ void ExecutablesList::getExecutables(std::vector::const_iterator &be end = m_Executables.end(); } - const Executable &ExecutablesList::find(const QString &title) const { for (std::vector::const_iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) { diff --git a/src/iuserinterface.h b/src/iuserinterface.h index 4799b934..ff683bce 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -20,6 +20,9 @@ public: virtual void disconnectPlugins() = 0; + virtual bool closeWindow() = 0; + virtual void setWindowEnabled(bool enabled) = 0; + virtual void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) = 0; virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0; diff --git a/src/logbuffer.cpp b/src/logbuffer.cpp index 635ce13e..fdfce6c5 100644 --- a/src/logbuffer.cpp +++ b/src/logbuffer.cpp @@ -132,8 +132,12 @@ void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QSt if (type == QtDebugMsg) { fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), qPrintable(message)); } else { - fprintf(stdout, "%s [%c] (%s:%u) %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), - context.file, context.line, qPrintable(message)); + if (context.line != 0) { + 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)); + } } fflush(stdout); } diff --git a/src/main.cpp b/src/main.cpp index a3ddac20..92ebf8bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -81,20 +81,52 @@ along with Mod Organizer. If not, see . using namespace MOBase; using namespace MOShared; +bool createAndMakeWritable(const std::wstring &subPath) +{ + QString fullPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(subPath); + + if (!QDir(fullPath).exists()) { + QDir().mkdir(fullPath); + } + + QFileInfo fileInfo(fullPath); + if (!fileInfo.exists() || !fileInfo.isWritable()) { + if (QMessageBox::question(nullptr, QObject::tr("Permissions required"), + QObject::tr("The current user account doesn't have the required access rights to run " + "Mod Organizer. The neccessary changes can be made automatically (the MO directory " + "will be made writable for the current user account). You will be asked to run " + "\"helper.exe\" with administrative rights."), + QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) { + if (!Helper::init(GameInfo::instance().getOrganizerDirectory())) { + return false; + } + } else { + return false; + } + // no matter which directory didn't exist/wasn't writable, the helper + // should have created them all so we don't have to worry this message box would appear repeatedly + } + return true; +} + bool bootstrap() { - GameInfo &gameInfo = GameInfo::instance(); - // remove the temporary backup directory in case we're restarting after an update - QString moDirectory = QDir::fromNativeSeparators(ToQString(gameInfo.getOrganizerDirectory())); - QString backupDirectory = moDirectory + "/update_backup"; + QString backupDirectory = qApp->applicationDirPath() + "/update_backup"; if (QDir(backupDirectory).exists()) { shellDelete(QStringList(backupDirectory)); } // cycle logfile - removeOldFiles(ToQString(GameInfo::instance().getLogDir()), "ModOrganizer*.log", 5, QDir::Name); + removeOldFiles(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()), + "ModOrganizer*.log", 5, QDir::Name); + + createAndMakeWritable(AppConfig::profilesPath()); + createAndMakeWritable(AppConfig::modsPath()); + createAndMakeWritable(AppConfig::downloadPath()); + createAndMakeWritable(AppConfig::overwritePath()); + createAndMakeWritable(AppConfig::logPath()); // verify the hook-dll exists QString dllName = qApp->applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName()); @@ -248,6 +280,7 @@ QString determineProfile(QStringList arguments, const QSettings &settings) } if (selectedProfileName.isEmpty()) { qDebug("no configured profile"); + selectedProfileName = "Default"; } else { qDebug("configured profile: %s", qPrintable(selectedProfileName)); } @@ -304,6 +337,11 @@ int main(int argc, char *argv[]) , ToWString(QDir::currentPath()).c_str(), SW_SHOWNORMAL); return 1; } + + if (!bootstrap()) { // requires gameinfo to be initialised! + return -1; + } + LogBuffer::init(100, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log"); qDebug("Working directory: %s", qPrintable(QDir::toNativeSeparators(QDir::currentPath()))); @@ -353,8 +391,7 @@ int main(int argc, char *argv[]) } } // we continue for the primary instance OR if MO has been called with parameters - - QSettings settings(dataPath + "/ModOrganizer.ini", QSettings::IniFormat); + QSettings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()), QSettings::IniFormat); OrganizerCore organizer(settings); @@ -362,7 +399,6 @@ int main(int argc, char *argv[]) pluginContainer.loadPlugins(); QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray()); - bool done = false; while (!done) { if (!GameInfo::init(ToWString(application.applicationDirPath()), ToWString(dataPath), ToWString(QDir::toNativeSeparators(gamePath)))) { @@ -418,6 +454,10 @@ int main(int argc, char *argv[]) settings.setValue("gamePath", gamePath.toUtf8().constData()); } + organizer.setManagedGame(ToQString(GameInfo::instance().getGameName())); + + organizer.createDefaultProfile(); + if (pluginContainer.managedGame(ToQString(GameInfo::instance().getGameName())) == nullptr) { reportError(QObject::tr("Plugin to handle %1 not installed").arg(ToQString(GameInfo::instance().getGameName()))); return 1; @@ -443,9 +483,6 @@ int main(int argc, char *argv[]) organizer.updateExecutablesList(settings); - if (!bootstrap()) { // requires gameinfo to be initialised! - return -1; - } QString selectedProfileName = determineProfile(arguments, settings); organizer.setCurrentProfile(selectedProfileName); @@ -468,7 +505,7 @@ int main(int argc, char *argv[]) } qDebug("initializing tutorials"); - TutorialManager::init(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getTutorialDir())).append("/")); + TutorialManager::init(qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::tutorialsPath()) + "/"); if (!application.setStyleFile(settings.value("Settings/style", "").toString())) { // disable invalid stylesheet @@ -485,8 +522,6 @@ int main(int argc, char *argv[]) mainWindow.readSettings(); - mainWindow.createFirstProfile(); - qDebug("displaying main window"); mainWindow.show(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index a15da6a4..594849f2 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -137,7 +137,11 @@ using namespace MOShared; -MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, OrganizerCore &organizerCore, PluginContainer &pluginContainer, QWidget *parent) +MainWindow::MainWindow(const QString &exeName + , QSettings &initSettings + , OrganizerCore &organizerCore + , PluginContainer &pluginContainer + , QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_Tutorial(this, "MainWindow") @@ -157,7 +161,6 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, Organize { ui->setupUi(this); this->setWindowTitle(ToQString(GameInfo::instance().getGameName()) + " Mod Organizer v" + m_OrganizerCore.getVersion().displayString()); - languageChange(m_OrganizerCore.settings().language()); ui->logList->setModel(LogBuffer::instance()); @@ -280,6 +283,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, Organize connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString))); connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString))); + connect(ui->tabWidget, SIGNAL(currentChanged(int)), &TutorialManager::instance(), SIGNAL(tabChanged(int))); connect(ui->modList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(modListSortIndicatorChanged(int,Qt::SortOrder))); connect(ui->toolBar, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(toolBar_customContextMenuRequested(QPoint))); @@ -313,7 +317,6 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, Organize ::SetDllDirectoryW(ToWString(QDir::toNativeSeparators(qApp->applicationDirPath() + "/dlls")).c_str()); m_OrganizerCore.setUserInterface(this, this); - for (const QString &fileName : m_PluginContainer.pluginFileNames()) { installTranslator(QFileInfo(fileName).baseName()); } @@ -326,6 +329,9 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, Organize registerModPage(modPagePlugin); } + // refresh profiles so the current profile can be activated + refreshProfiles(false); + ui->profileBox->setCurrentText(m_OrganizerCore.currentProfile()->getName()); refreshExecutablesList(); @@ -477,7 +483,6 @@ void MainWindow::actionToToolButton(QAction *&sourceAction) sourceAction = newAction; } - void MainWindow::updateToolBar() { foreach (QAction *action, ui->toolBar->actions()) { @@ -560,7 +565,7 @@ void MainWindow::updateProblemsButton() bool MainWindow::errorReported(QString &logFile) { - QDir dir(ToQString(GameInfo::instance().getLogDir())); + QDir dir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath())); QFileInfoList files = dir.entryInfoList(QStringList("ModOrganizer_??_??_??_??_??.log"), QDir::Files, QDir::Name | QDir::Reversed); @@ -655,7 +660,7 @@ void MainWindow::createHelpWidget() } std::sort(tutorials.begin(), tutorials.end(), - [](const ActionList::value_type &LHS, const ActionList::value_type &RHS) { + [] (const ActionList::value_type &LHS, const ActionList::value_type &RHS) { return LHS.first < RHS.first; } ); for (auto iter = tutorials.begin(); iter != tutorials.end(); ++iter) { @@ -816,16 +821,6 @@ void MainWindow::closeEvent(QCloseEvent* event) } -void MainWindow::createFirstProfile() -{ - if (!refreshProfiles(false)) { - qDebug("creating default profile"); - Profile newProf("Default", false); - refreshProfiles(false); - } -} - - void MainWindow::setBrowserGeometry(const QByteArray &geometry) { m_IntegratedBrowser.restoreGeometry(geometry); @@ -1033,9 +1028,9 @@ void MainWindow::on_profileBox_currentIndexChanged(int index) } if (ui->profileBox->currentIndex() == 0) { - ProfilesDialog(m_GamePath).exec(); + ProfilesDialog(m_GamePath, m_OrganizerCore.managedGame(), this).exec(); while (!refreshProfiles()) { - ProfilesDialog(m_GamePath).exec(); + ProfilesDialog(m_GamePath, m_OrganizerCore.managedGame(), this).exec(); } ui->profileBox->setCurrentIndex(previousIndex); } else { @@ -1181,21 +1176,15 @@ bool MainWindow::refreshProfiles(bool selectProfile) profileBox->clear(); profileBox->addItem(QObject::tr("")); - QDir profilesDir(ToQString(GameInfo::instance().getProfilesDir())); + QDir profilesDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath())); profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); QDirIterator profileIter(profilesDir); - int newIndex = profileIter.hasNext() ? 1 : 0; - int currentIndex = 0; while (profileIter.hasNext()) { profileIter.next(); - ++currentIndex; try { profileBox->addItem(profileIter.fileName()); - if (currentProfileName == profileIter.fileName()) { - newIndex = currentIndex; - } } catch (const std::runtime_error& error) { reportError(QObject::tr("failed to parse profile %1: %2").arg(profileIter.fileName()).arg(error.what())); } @@ -1206,20 +1195,13 @@ bool MainWindow::refreshProfiles(bool selectProfile) if (selectProfile) { if (profileBox->count() > 1) { - if (currentProfileName.length() != 0) { - if ((newIndex != 0) && (profileBox->count() > newIndex)) { - profileBox->setCurrentIndex(newIndex); - } else { - profileBox->setCurrentIndex(1); - } + profileBox->setCurrentText(currentProfileName); + if (profileBox->currentIndex() == 0) { + profileBox->setCurrentIndex(1); } - return true; - } else { - return false; } - } else { - return profileBox->count() > 1; } + return profileBox->count() > 1; } @@ -1301,7 +1283,7 @@ void MainWindow::refreshSaveList() ::GetPrivateProfileStringW(L"General", L"SLocalSavePath", L"Saves", path, MAX_PATH, (ToWString(m_OrganizerCore.currentProfile()->getPath()) + L"\\" + GameInfo::instance().getIniFileNames().at(0)).c_str()); - savesDir.setPath(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getDocumentsDir() + L"\\" + path))); + savesDir.setPath(m_OrganizerCore.managedGame()->documentsDirectory().absoluteFilePath(QString::fromWCharArray(path))); } if (m_SavesWatcher.directories().length() > 0) { @@ -1310,11 +1292,10 @@ void MainWindow::refreshSaveList() m_SavesWatcher.addPath(savesDir.absolutePath()); QStringList filters; - filters << ToQString(GameInfo::instance().getSaveGameExtension()); + filters << QString("*.") + m_OrganizerCore.managedGame()->savegameExtension(); savesDir.setNameFilters(filters); QFileInfoList files = savesDir.entryInfoList(QDir::Files, QDir::Time); - foreach (const QFileInfo &file, files) { QListWidgetItem *item = new QListWidgetItem(file.fileName()); item->setData(Qt::UserRole, file.absoluteFilePath()); @@ -1414,14 +1395,16 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString subItem->setExpanded(true); } - checkBSAList(defaultArchives); + checkBSAList(); } -void MainWindow::checkBSAList(const QStringList &defaultArchives) +void MainWindow::checkBSAList() { ui->bsaList->blockSignals(true); + QStringList defaultArchives = m_OrganizerCore.defaultArchiveList(); + bool warning = false; for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { @@ -1512,7 +1495,7 @@ void MainWindow::activateProxy(bool activate) void MainWindow::readSettings() { - QSettings settings(ToQString(GameInfo::instance().getIniFilename()), QSettings::IniFormat); + QSettings settings(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::iniFileName()), QSettings::IniFormat); if (settings.contains("window_geometry")) { restoreGeometry(settings.value("window_geometry").toByteArray()); @@ -1791,7 +1774,7 @@ void MainWindow::on_actionAdd_Profile_triggered() { bool repeat = true; while (repeat) { - ProfilesDialog profilesDialog(m_GamePath); + ProfilesDialog profilesDialog(m_GamePath, m_OrganizerCore.managedGame(), this); profilesDialog.exec(); if (refreshProfiles() && !profilesDialog.failed()) { repeat = false; @@ -1975,7 +1958,7 @@ void MainWindow::modRenamed(const QString &oldName, const QString &newName) //TODO this functionality should be in the Profile class QString modlistName = QString("%1/%2/modlist.txt") - .arg(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir()))) + .arg(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath())) .arg(profileName); QFile modList(modlistName); @@ -3176,7 +3159,7 @@ void MainWindow::fixMods_clicked() // search in overwrite { - QDir overwriteDir(ToQString(GameInfo::instance().getOverwriteDir())); + QDir overwriteDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath())); QStringList esps = overwriteDir.entryList(espFilter); foreach (const QString &esp, esps) { std::map >::iterator iter = missingPlugins.find(esp); @@ -3398,6 +3381,8 @@ void MainWindow::languageChange(const QString &newLanguage) updateProblemsButton(); ui->listOptionsBtn->setMenu(modListContextMenu()); +} + void MainWindow::writeDataToFile(QFile &file, const QString &directory, const DirectoryEntry &directoryEntry) { { // list files @@ -3433,7 +3418,6 @@ void MainWindow::writeDataToFile(QFile &file, const QString &directory, const Di } } - void MainWindow::writeDataToFile() { QString fileName = QFileDialog::getSaveFileName(this); @@ -4286,62 +4270,6 @@ void MainWindow::processLOOTOut(const std::string &lootOut, std::string &errorMe } } } -bool MainWindow::waitForProcessOrJob(HANDLE handle, LPDWORD exitCode) -{ - LockedDialog *dialog = new LockedDialog(this); - dialog->show(); - setEnabled(false); - ON_BLOCK_EXIT([&] () { dialog->hide(); dialog->deleteLater(); setEnabled(true); }); - - DWORD retLen; - JOBOBJECT_BASIC_PROCESS_ID_LIST info; - - bool isJobHandle = true; - - ULONG lastProcessID = ULONG_MAX; - HANDLE processHandle = handle; - - DWORD res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE); - while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0) && !dialog->unlockClicked()) { - if (isJobHandle) { - if (::QueryInformationJobObject(handle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { - if (info.NumberOfProcessIdsInList == 0) { - // fake signaled state - res = WAIT_OBJECT_0; - break; - } else { - // this is indeed a job handle. Figure out one of the process handles as well. - if (lastProcessID != info.ProcessIdList[0]) { - lastProcessID = info.ProcessIdList[0]; - if (processHandle != handle) { - ::CloseHandle(processHandle); - } - processHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, lastProcessID); - } - } - } else { - // the info-object I passed only provides space for 1 process id. but since this code only cares about whether there - // is more than one that's good enough. ERROR_MORE_DATA simply signals there are at least two processes running. - // any other error probably means the handle is a regular process handle, probably caused by running MO in a job without - // the right to break out. - if (::GetLastError() != ERROR_MORE_DATA) { - isJobHandle = false; - } - } - } - - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - - res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE); - } - - if (exitCode != NULL) { - ::GetExitCodeProcess(processHandle, exitCode); - } - ::CloseHandle(processHandle); - - return res == WAIT_OBJECT_0; } void MainWindow::on_bossButton_clicked() diff --git a/src/mainwindow.h b/src/mainwindow.h index feaedef8..52c202a7 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -39,7 +39,6 @@ along with Mod Organizer. If not, see . #include #include "directoryrefresher.h" #include -#include #include "settings.h" #include "downloadmanager.h" #include "installationmanager.h" @@ -98,8 +97,6 @@ public: void setModListSorting(int index); void setESPListSorting(int index); - void createFirstProfile(); - bool saveArchiveList(); void registerPluginTool(MOBase::IPluginTool *tool); @@ -303,8 +300,6 @@ private: OrganizerCore &m_OrganizerCore; PluginContainer &m_PluginContainer; - MOBase::IPluginGame *m_ActiveGame; - QString m_CurrentLanguage; std::vector m_Translators; diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 4befd232..e956377c 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -29,6 +29,7 @@ along with Mod Organizer. If not, see . #include #include +#include #include @@ -1012,7 +1013,7 @@ bool ModInfoOverwrite::isEmpty() const QString ModInfoOverwrite::absolutePath() const { - return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOverwriteDir())); + return QDir::fromNativeSeparators(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath())); } std::vector ModInfoOverwrite::getFlags() const diff --git a/src/modlist.cpp b/src/modlist.cpp index 6d55764a..55344865 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -25,6 +25,7 @@ along with Mod Organizer. If not, see . #include "qtgroupingproxy.h" #include "viewmarkingscrollbar.h" #include +#include #include #include #include @@ -41,6 +42,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include @@ -750,7 +752,7 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa ModInfo::Ptr modInfo = ModInfo::getByIndex(row); QDir modDirectory(modInfo->absolutePath()); - QDir gameDirectory(QDir::fromNativeSeparators(ToQString(MOShared::GameInfo::instance().getOverwriteDir()))); + QDir gameDirectory(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath())); unsigned int overwriteIndex = ModInfo::findMod([](ModInfo::Ptr mod) -> bool { std::vector flags = mod->getFlags(); diff --git a/src/motddialog.cpp b/src/motddialog.cpp index 59ace4d1..96d88542 100644 --- a/src/motddialog.cpp +++ b/src/motddialog.cpp @@ -28,8 +28,6 @@ MotDDialog::MotDDialog(const QString &message, QWidget *parent) { ui->setupUi(this); ui->motdView->setHtml(BBCode::convertToHTML(message)); -// ui->motdView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); -// connect(ui->motdView->page(), SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl))); connect(ui->motdView, SIGNAL(anchorClicked(QUrl)), this, SLOT(linkClicked(QUrl))); } diff --git a/src/organizer.pro b/src/organizer.pro index 4524a09b..b67fb3e5 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -249,7 +249,7 @@ LIBS += -L"E:/Visual Leak Detector/lib/Win32" #DEFINES += LEAK_CHECK_WITH_VLD # custom leak detection -LIBS += -lDbgHelp +#LIBS += -lDbgHelp # model tests #SOURCES += modeltest.cpp @@ -257,7 +257,7 @@ LIBS += -lDbgHelp #DEFINES += TEST_MODELS -INCLUDEPATH += ../shared ../archive ../uibase ../bsatk ../esptk ../boss_modified/boss-api "$${BOOSTPATH}" +INCLUDEPATH += ../shared ../archive ../uibase ../bsatk ../esptk "$${LOOTPATH}" "$${BOOSTPATH}" LIBS += -L"$${BOOSTPATH}/stage/lib" @@ -317,7 +317,7 @@ LIBS += -L"$${ZLIBPATH}/build" -lzlibstatic DEFINES += UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS _SCL_SECURE_NO_WARNINGS NOMINMAX -DEFINES += BOOST_DISABLE_ASSERTS NDEBUG +DEFINES += BOOST_DISABLE_ASSERTS NDEBUG QT_MESSAGELOGCONTEXT #DEFINES += QMLJSDEBUGGER HGID = $$system(hg id -i) @@ -361,3 +361,8 @@ CONFIG(debug, debug|release) { QMAKE_POST_LINK += xcopy /y /s /I $$quote($$BASEDIR\\..\\dlls.*manifest) $$quote($$DSTDIR)\\dlls $$escape_expand(\\n) } } + +DISTFILES += \ + tutorials/tutorial_primer_main.js \ + tutorials/Tooltip.qml \ + tutorials/TooltipArea.qml diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 5b322a0a..936e5529 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -77,52 +77,6 @@ static std::wstring getProcessName(DWORD processId) } } -bool OrganizerCore::testForSteam() -{ - size_t currentSize = 1024; - std::unique_ptr processIDs; - DWORD bytesReturned; - bool success = false; - while (!success) { - processIDs.reset(new DWORD[currentSize]); - if (!::EnumProcesses(processIDs.get(), currentSize * sizeof(DWORD), &bytesReturned)) { - qWarning("failed to determine if steam is running"); - return true; - } - if (bytesReturned == (currentSize * sizeof(DWORD))) { - // maximum size used, list probably truncated - currentSize *= 2; - } else { - success = true; - } - } - TCHAR processName[MAX_PATH]; - for (unsigned int i = 0; i < bytesReturned / sizeof(DWORD); ++i) { - memset(processName, '\0', sizeof(TCHAR) * MAX_PATH); - if (processIDs[i] != 0) { - HANDLE process = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processIDs[i]); - - if (process != nullptr) { - HMODULE module; - DWORD ignore; - - // first module in a process is always the binary - if (EnumProcessModules(process, &module, sizeof(HMODULE) * 1, &ignore)) { - ::GetModuleBaseName(process, module, processName, MAX_PATH); - if ((_tcsicmp(processName, TEXT("steam.exe")) == 0) || - (_tcsicmp(processName, TEXT("steamservice.exe")) == 0)) { - return true; - } - } - } else { - qDebug("can't open process %lu: %lu", processIDs[i], ::GetLastError()); - } - } - } - - return false; -} - static void startSteam(QWidget *widget) { QSettings steamSettings("HKEY_CURRENT_USER\\Software\\Valve\\Steam", QSettings::NativeFormat); @@ -153,6 +107,7 @@ OrganizerCore::OrganizerCore(const QSettings &initSettings) : m_GameInfo(new GameInfoImpl()) , m_UserInterface(nullptr) , m_PluginContainer(nullptr) + , m_GameName() , m_CurrentProfile(nullptr) , m_Settings(initSettings) , m_Updater(NexusInterface::instance()) @@ -188,6 +143,8 @@ OrganizerCore::OrganizerCore(const QSettings &initSettings) connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginSuccessful(bool)), this, SLOT(loginSuccessful(bool))); connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString))); + connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame*)), &m_Settings, SLOT(managedGameChanged(MOBase::IPluginGame*))); + // make directory refresher run in a separate thread m_RefresherThread.start(); m_DirectoryRefresher.moveToThread(&m_RefresherThread); @@ -217,7 +174,7 @@ OrganizerCore::~OrganizerCore() void OrganizerCore::storeSettings() { - QString iniFile = ToQString(GameInfo::instance().getIniFilename()); + QString iniFile = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::iniFileName()); shellCopy(iniFile, iniFile + ".new", true, qApp->activeWindow()); QSettings::Status result = QSettings::NoError; @@ -275,8 +232,57 @@ void OrganizerCore::storeSettings() } } +bool OrganizerCore::testForSteam() +{ + size_t currentSize = 1024; + std::unique_ptr processIDs; + DWORD bytesReturned; + bool success = false; + while (!success) { + processIDs.reset(new DWORD[currentSize]); + if (!::EnumProcesses(processIDs.get(), currentSize * sizeof(DWORD), &bytesReturned)) { + qWarning("failed to determine if steam is running"); + return true; + } + if (bytesReturned == (currentSize * sizeof(DWORD))) { + // maximum size used, list probably truncated + currentSize *= 2; + } else { + success = true; + } + } + TCHAR processName[MAX_PATH]; + for (unsigned int i = 0; i < bytesReturned / sizeof(DWORD); ++i) { + memset(processName, '\0', sizeof(TCHAR) * MAX_PATH); + if (processIDs[i] != 0) { + HANDLE process = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processIDs[i]); + + if (process != nullptr) { + HMODULE module; + DWORD ignore; + + // first module in a process is always the binary + if (EnumProcessModules(process, &module, sizeof(HMODULE) * 1, &ignore)) { + ::GetModuleBaseName(process, module, processName, MAX_PATH); + if ((_tcsicmp(processName, TEXT("steam.exe")) == 0) || + (_tcsicmp(processName, TEXT("steamservice.exe")) == 0)) { + return true; + } + } + } + } + } + + return false; +} + void OrganizerCore::updateExecutablesList(QSettings &settings) { + if (m_PluginContainer == nullptr) { + qCritical("can't update executables list now"); + return; + } + m_ExecutablesList.init(m_PluginContainer->managedGame(ToQString(GameInfo::instance().getGameName()))); qDebug("setting up configured executables"); @@ -337,6 +343,11 @@ void OrganizerCore::connectPlugins(PluginContainer *container) { m_DownloadManager.setSupportedExtensions(m_InstallationManager.getSupportedExtensions()); m_PluginContainer = container; + + if (!m_GameName.isEmpty()) { + m_GamePlugin = m_PluginContainer->managedGame(m_GameName); + emit managedGameChanged(m_GamePlugin); + } } void OrganizerCore::disconnectPlugins() @@ -348,9 +359,19 @@ void OrganizerCore::disconnectPlugins() m_PluginList.disconnectSlots(); m_Settings.clearPlugins(); + m_GamePlugin = nullptr; m_PluginContainer = nullptr; } +void OrganizerCore::setManagedGame(const QString &gameName) +{ + m_GameName = gameName; + if (m_PluginContainer != nullptr) { + m_GamePlugin = m_PluginContainer->managedGame(m_GameName); + emit managedGameChanged(m_GamePlugin); + } +} + Settings &OrganizerCore::settings() { return m_Settings; @@ -449,11 +470,19 @@ InstallationManager *OrganizerCore::installationManager() return &m_InstallationManager; } +void OrganizerCore::createDefaultProfile() +{ + QString profilesPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()); + qDebug("%d", QDir(profilesPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot).size()); + if (QDir(profilesPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot).size() == 0) { + Profile newProf("Default", managedGame(), false); + } +} + void OrganizerCore::setCurrentProfile(const QString &profileName) { QString profileDir = qApp->property("dataPath").toString() + "/" + ToQString(AppConfig::profilesPath()) + "/" + profileName; - - Profile *newProfile = new Profile(QDir(profileDir)); + Profile *newProfile = new Profile(QDir(profileDir), managedGame()); delete m_CurrentProfile; m_CurrentProfile = newProfile; @@ -576,8 +605,7 @@ void OrganizerCore::setPersistent(const QString &pluginName, const QString &key, QString OrganizerCore::pluginDataPath() const { - QString pluginPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())) + "/" + ToQString(AppConfig::pluginPath()); - return pluginPath + "/data"; + return qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()) + "/data"; } MOBase::IModInterface *OrganizerCore::installMod(const QString &fileName, const QString &initModName) @@ -676,63 +704,6 @@ void OrganizerCore::installDownload(int index) } } -void OrganizerCore::installDownload(int downloadIndex) -{ - try { - QString fileName = m_DownloadManager.getFilePath(downloadIndex); - int modID = m_DownloadManager.getModID(downloadIndex); - GuessedValue modName; - - // see if there already are mods with the specified mod id - if (modID != 0) { - std::vector modInfo = ModInfo::getByModID(modID); - for (auto iter = modInfo.begin(); iter != modInfo.end(); ++iter) { - std::vector flags = (*iter)->getFlags(); - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == flags.end()) { - modName.update((*iter)->name(), GUESS_PRESET); - (*iter)->saveMeta(); - } - } - } - - m_CurrentProfile->writeModlistNow(); - - bool hasIniTweaks = false; - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); - if (m_InstallationManager.install(fileName, modName, hasIniTweaks)) { - MessageDialog::showMessage(tr("Installation successful"), qApp->activeWindow()); - refreshModList(); - - int modIndex = ModInfo::getIndex(modName); - if (modIndex != UINT_MAX) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - - if (hasIniTweaks - && (m_UserInterface != nullptr) - && (QMessageBox::question(qApp->activeWindow(), tr("Configure Mod"), - tr("This mod contains ini tweaks. Do you want to configure them now?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) { - m_UserInterface->displayModInformation(modInfo, modIndex, ModInfoDialog::TAB_INIFILES); - } - - m_ModInstalled(modName); - } else { - reportError(tr("mod \"%1\" not found").arg(modName)); - } - m_DownloadManager.markInstalled(downloadIndex); - - emit modInstalled(modName); - } else if (m_InstallationManager.wasCancelled()) { - QMessageBox::information(qApp->activeWindow(), - tr("Installation cancelled"), - tr("The mod was not installed completely."), - QMessageBox::Ok); - } - } catch (const std::exception &e) { - reportError(e.what()); - } -} - QString OrganizerCore::resolvePath(const QString &fileName) const { if (m_DirectoryStructure == nullptr) { @@ -1011,7 +982,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, const QStringL return spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID); } -bool OrganizerCore::waitForProcessOrJob(HANDLE handle, LPDWORD exitCode) +bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) { if (m_UserInterface != nullptr) { m_UserInterface->lock(); @@ -1131,7 +1102,7 @@ QStringList OrganizerCore::defaultArchiveList() result.append(ToQString(buffer).split(',')); } - for (int i = 0; i < m_DefaultArchives.count(); ++i) { + for (int i = 0; i < result.count(); ++i) { result[i] = result[i].trimmed(); } @@ -1284,6 +1255,11 @@ PluginListSortProxy *OrganizerCore::createPluginListProxyModel() return result; } +IPluginGame *OrganizerCore::managedGame() const +{ + return m_GamePlugin; +} + std::set OrganizerCore::enabledArchives() { std::set result; @@ -1308,8 +1284,6 @@ void OrganizerCore::refreshDirectoryStructure() m_DirectoryRefresher.setMods(activeModList, enabledArchives()); QTimer::singleShot(0, &m_DirectoryRefresher, SLOT(refresh())); - } else { - qDebug("directory update"); } } diff --git a/src/organizercore.h b/src/organizercore.h index cf8d10f5..4d9b0a7c 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,9 @@ class PluginContainer; +namespace MOBase { + class IPluginGame; +} class OrganizerCore : public QObject, public MOBase::IPluginDiagnose { @@ -68,6 +72,8 @@ public: void connectPlugins(PluginContainer *container); void disconnectPlugins(); + void setManagedGame(const QString &gameName); + void updateExecutablesList(QSettings &settings); void startMOUpdate(); @@ -92,7 +98,7 @@ public: ModListSortProxy *createModListProxyModel(); PluginListSortProxy *createPluginListProxyModel(); - HANDLE spawnBinaryDirect(const QFileInfo &binary, const QString &arguments, const QString &profileName, const QDir ¤tDirectory, const QString &steamAppID); + MOBase::IPluginGame *managedGame() const; bool isArchivesInit() const { return m_ArchivesInit; } @@ -116,6 +122,8 @@ public: void syncOverwrite(); + void createDefaultProfile(); + public: MOBase::IGameInfo &gameInfo() const; MOBase::IModRepositoryBridge *createNexusBridge() const; @@ -132,7 +140,7 @@ public: QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def) const; void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync); QString pluginDataPath() const; - virtual MOBase::IModInterface *installMod(const QString &fileName); + virtual MOBase::IModInterface *installMod(const QString &fileName, const QString &initModName); QString resolvePath(const QString &fileName) const; QStringList listDirectories(const QString &directoryName) const; QStringList findFiles(const QString &path, const std::function &filter) const; @@ -147,6 +155,7 @@ public: bool onAboutToRun(const std::function &func); bool onFinishedRun(const std::function &func); void refreshModList(bool saveChanges = true); + QStringList defaultArchiveList(); public: // IPluginDiagnose interface @@ -181,6 +190,8 @@ signals: */ void modInstalled(const QString &modName); + void managedGameChanged(MOBase::IPluginGame *gamePlugin); + private: void storeSettings(); @@ -190,7 +201,6 @@ private: void updateModActiveState(int index, bool active); bool testForSteam(); - QStringList defaultArchiveList(); private slots: @@ -211,6 +221,8 @@ private: IUserInterface *m_UserInterface; PluginContainer *m_PluginContainer; + QString m_GameName; + MOBase::IPluginGame *m_GamePlugin; Profile *m_CurrentProfile; diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp index ff030d40..2ce5b3ee 100644 --- a/src/organizerproxy.cpp +++ b/src/organizerproxy.cpp @@ -102,7 +102,7 @@ HANDLE OrganizerProxy::startApplication(const QString &executable, const QString bool OrganizerProxy::waitForApplication(HANDLE handle, LPDWORD exitCode) const { - return m_Proxied->waitForProcessOrJob(handle, exitCode); + return m_Proxied->waitForApplication(handle, exitCode); } bool OrganizerProxy::onAboutToRun(const std::function &func) diff --git a/src/pluginlist.h b/src/pluginlist.h index da644ad3..e0913840 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -33,7 +33,6 @@ along with Mod Organizer. If not, see . #include #include #include "pdll.h" -#include template diff --git a/src/profile.cpp b/src/profile.cpp index 21c9d1d8..775b309e 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -28,6 +28,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include @@ -55,12 +56,11 @@ void Profile::touchFile(QString fileName) } } -Profile::Profile(const QString &name, bool useDefaultSettings) +Profile::Profile(const QString &name, IPluginGame *gamePlugin, bool useDefaultSettings) : m_SaveTimer(nullptr) { initTimer(); - QString profilesDir = qApp->property("datapath").toString() + "/" + ToQString(AppConfig::profilesPath()); -qDebug("pd %s", qPrintable(profilesDir)); + QString profilesDir = qApp->property("dataPath").toString() + "/" + ToQString(AppConfig::profilesPath()); QDir profileBase(profilesDir); QString fixedName = name; @@ -79,8 +79,15 @@ qDebug("pd %s", qPrintable(profilesDir)); touchFile("modlist.txt"); touchFile("archives.txt"); -qDebug("fp %s", qPrintable(fullPath)); - GameInfo::instance().createProfile(ToWString(fullPath), useDefaultSettings); + IPluginGame::ProfileSettings settings = IPluginGame::CONFIGURATION + | IPluginGame::MODS + | IPluginGame::SAVEGAMES; + + if (useDefaultSettings) { + settings |= IPluginGame::PREFER_DEFAULTS; + } + + gamePlugin->initializeProfile(fullPath, settings); } catch (...) { // clean up in case of an error shellDelete(QStringList(profileBase.absoluteFilePath(fixedName))); @@ -90,15 +97,21 @@ qDebug("fp %s", qPrintable(fullPath)); } -Profile::Profile(const QDir &directory) +Profile::Profile(const QDir &directory, IPluginGame *gamePlugin) : m_Directory(directory), m_SaveTimer(nullptr) { + assert(gamePlugin != nullptr); initTimer(); + if (!QFile::exists(m_Directory.filePath("modlist.txt"))) { qWarning("missing modlist.txt in %s", qPrintable(directory.path())); + touchFile(m_Directory.filePath("modlist.txt")); } - GameInfo::instance().repairProfile(ToWString(m_Directory.absolutePath())); + IPluginGame::ProfileSettings settings = IPluginGame::CONFIGURATION + | IPluginGame::MODS + | IPluginGame::SAVEGAMES; + gamePlugin->initializeProfile(directory, settings); if (!QFile::exists(getIniFileName())) { reportError(QObject::tr("\"%1\" is missing or inaccessible").arg(getIniFileName())); @@ -492,29 +505,18 @@ void Profile::setModPriority(unsigned int index, int &newPriority) writeModlist(); } - -Profile Profile::createFrom(const QString &name, const Profile &reference) +Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame *gamePlugin) { - QString profileDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir())).append("/").append(name); + QString profileDirectory = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()) + "/" + name; reference.copyFilesTo(profileDirectory); - return Profile(QDir(profileDirectory)); + return new Profile(QDir(profileDirectory), gamePlugin); } - -Profile *Profile::createPtrFrom(const QString &name, const Profile &reference) -{ - QString profileDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir())).append("/").append(name); - reference.copyFilesTo(profileDirectory); - return new Profile(QDir(profileDirectory)); -} - - void Profile::copyFilesTo(QString &target) const { copyDir(m_Directory.absolutePath(), target, false); } - std::vector Profile::splitDZString(const wchar_t *buffer) const { std::vector result; @@ -528,7 +530,6 @@ std::vector Profile::splitDZString(const wchar_t *buffer) const return result; } - void Profile::mergeTweak(const QString &tweakName, const QString &tweakedIni) const { static const int bufferSize = 32768; @@ -787,7 +788,7 @@ QString Profile::getPath() const void Profile::rename(const QString &newName) { - QDir profileDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir()))); + QDir profileDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath())); profileDir.rename(getName(), newName); m_Directory = profileDir.absoluteFilePath(newName); } diff --git a/src/profile.h b/src/profile.h index aa27d6e8..34efd4b2 100644 --- a/src/profile.h +++ b/src/profile.h @@ -31,6 +31,10 @@ along with Mod Organizer. If not, see . #include +namespace MOBase { + class IPluginGame; +} + /** * @brief represents a profile **/ @@ -59,7 +63,7 @@ public: * @param name name of the new profile * @param filter save game filter. Defaults to <no filter>. **/ - Profile(const QString &name, bool useDefaultSettings); + Profile(const QString &name, MOBase::IPluginGame *gamePlugin, bool useDefaultSettings); /** * @brief constructor * @@ -68,7 +72,7 @@ public: * invoking this should always produce a working profile * @param directory directory to read the profile from **/ - Profile(const QDir &directory); + Profile(const QDir &directory, MOBase::IPluginGame *gamePlugin); Profile(const Profile &reference); @@ -83,13 +87,7 @@ public: * @param name of the new profile * @param reference profile to copy from **/ - static Profile createFrom(const QString &name, const Profile &reference); - - /** - * @param name of the new profile - * @param reference profile to copy from - **/ - static Profile *createPtrFrom(const QString &name, const Profile &reference); + static Profile *createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame *gamePlugin); /** * @brief write out the modlist.txt diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index 26891b3c..02566db3 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -26,6 +26,7 @@ along with Mod Organizer. If not, see . #include "profileinputdialog.h" #include "mainwindow.h" #include +#include #include #include #include @@ -40,12 +41,16 @@ using namespace MOShared; Q_DECLARE_METATYPE(Profile::Ptr) -ProfilesDialog::ProfilesDialog(const QString &gamePath, QWidget *parent) - : TutorableDialog("Profiles", parent), ui(new Ui::ProfilesDialog), m_GamePath(gamePath), m_FailState(false) +ProfilesDialog::ProfilesDialog(const QString &gamePath, MOBase::IPluginGame *gamePlugin, QWidget *parent) + : TutorableDialog("Profiles", parent) + , ui(new Ui::ProfilesDialog) + , m_GamePlugin(gamePlugin) + , m_GamePath(gamePath) + , m_FailState(false) { ui->setupUi(this); - QDir profilesDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir()))); + QDir profilesDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath())); profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); m_ProfilesList = findChild("profilesList"); @@ -93,20 +98,19 @@ void ProfilesDialog::addItem(const QString &name) QDir profileDir(name); QListWidgetItem *newItem = new QListWidgetItem(profileDir.dirName(), m_ProfilesList); try { - newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(profileDir)))); + newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(profileDir, m_GamePlugin)))); m_FailState = false; } catch (const std::exception& e) { reportError(tr("failed to create profile: %1").arg(e.what())); } } - void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings) { try { QListWidget *profilesList = findChild("profilesList"); QListWidgetItem *newItem = new QListWidgetItem(name, profilesList); - newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(name, useDefaultSettings)))); + newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(name, m_GamePlugin, useDefaultSettings)))); profilesList->addItem(newItem); m_FailState = false; } catch (const std::exception&) { @@ -115,13 +119,12 @@ void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings) } } - void ProfilesDialog::createProfile(const QString &name, const Profile &reference) { try { QListWidget *profilesList = findChild("profilesList"); QListWidgetItem *newItem = new QListWidgetItem(name, profilesList); - newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(Profile::createPtrFrom(name, reference)))); + newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(Profile::createPtrFrom(name, reference, m_GamePlugin)))); profilesList->addItem(newItem); m_FailState = false; } catch (const std::exception&) { @@ -130,7 +133,6 @@ void ProfilesDialog::createProfile(const QString &name, const Profile &reference } } - void ProfilesDialog::on_addProfileButton_clicked() { ProfileInputDialog dialog(this); @@ -178,7 +180,9 @@ void ProfilesDialog::on_removeProfileButton_clicked() Profile::Ptr currentProfile = profilesList->currentItem()->data(Qt::UserRole).value(); QString profilePath; if (currentProfile.get() == nullptr) { - profilePath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir())) + "/" + profilesList->currentItem()->text(); + profilePath = qApp->property("dataPath").toString() + + "/" + QString::fromStdWString(AppConfig::profilesPath()) + + "/" + 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. " "I'm about to delete the following folder: \"%1\". Proceed?").arg(profilePath), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { @@ -315,6 +319,6 @@ void ProfilesDialog::on_localSavesBox_stateChanged(int state) void ProfilesDialog::on_transferButton_clicked() { const Profile::Ptr currentProfile = m_ProfilesList->currentItem()->data(Qt::UserRole).value(); - TransferSavesDialog transferDialog(*currentProfile, this); + TransferSavesDialog transferDialog(*currentProfile, m_GamePlugin, this); transferDialog.exec(); } diff --git a/src/profilesdialog.h b/src/profilesdialog.h index 905d49b1..18b3932f 100644 --- a/src/profilesdialog.h +++ b/src/profilesdialog.h @@ -29,6 +29,10 @@ namespace Ui { class ProfilesDialog; } +namespace MOBase { + class IPluginGame; +} + /** * @brief Dialog that can be used to create/delete/modify profiles @@ -46,7 +50,7 @@ public: * @param parent parent widget * @todo the game path could be retrieved from GameInfo just as easily **/ - explicit ProfilesDialog(const QString &gamePath, QWidget *parent = 0); + explicit ProfilesDialog(const QString &gamePath, MOBase::IPluginGame *gamePlugin, QWidget *parent = 0); ~ProfilesDialog(); /** @@ -87,6 +91,7 @@ private slots: private: Ui::ProfilesDialog *ui; + MOBase::IPluginGame *m_GamePlugin; QString m_GamePath; QListWidget *m_ProfilesList; bool m_FailState; diff --git a/src/settings.cpp b/src/settings.cpp index f44edb24..a052620d 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -22,10 +22,11 @@ along with Mod Organizer. If not, see . #include "settingsdialog.h" #include "utility.h" #include "helper.h" +#include "json.h" #include #include #include -#include "json.h" +#include #include #include @@ -117,6 +118,11 @@ void Settings::registerAsNXMHandler(bool force) } } +void Settings::managedGameChanged(IPluginGame *gamePlugin) +{ + m_GamePlugin = gamePlugin; +} + void Settings::registerPlugin(IPlugin *plugin) { m_Plugins.push_back(plugin); @@ -176,7 +182,7 @@ bool Settings::automaticLoginEnabled() const QString Settings::getSteamAppID() const { - return m_Settings.value("Settings/app_id", ToQString(GameInfo::instance().getSteamAPPId(m_Settings.value("game_edition", 0).toInt()))).toString(); + return m_Settings.value("Settings/app_id", m_GamePlugin->steamAPPId()).toString(); } QString Settings::getDownloadDirectory() const @@ -691,7 +697,7 @@ void Settings::query(QWidget *parent) m_Settings.setValue("Settings/log_level", logLevelBox->currentIndex()); - if (appIDEdit->text() != ToQString(GameInfo::instance().getSteamAPPId())) { + if (appIDEdit->text() != m_GamePlugin->steamAPPId()) { m_Settings.setValue("Settings/app_id", appIDEdit->text()); } else { m_Settings.remove("Settings/app_id"); diff --git a/src/settings.h b/src/settings.h index cea4729a..51e109c4 100644 --- a/src/settings.h +++ b/src/settings.h @@ -29,6 +29,11 @@ along with Mod Organizer. If not, see . #include +namespace MOBase { + class IPluginGame; +} + + /** * manages the settings for Mod Organizer. The settings are not cached * inside the class but read/written directly from/to disc @@ -272,6 +277,11 @@ public: * even if the user said earlier not to */ void registerAsNXMHandler(bool force); + +public slots: + + void managedGameChanged(MOBase::IPluginGame *gamePlugin); + private: QString obfuscate(const QString &password) const; @@ -296,6 +306,8 @@ private: static Settings *s_Instance; + MOBase::IPluginGame *m_GamePlugin; + QSettings m_Settings; LoadMechanism m_LoadMechanism; diff --git a/src/shared/appconfig.inc b/src/shared/appconfig.inc index 4450763f..e2dbfe20 100644 --- a/src/shared/appconfig.inc +++ b/src/shared/appconfig.inc @@ -6,8 +6,11 @@ APPPARAM(std::wstring, downloadPath, L"downloads") APPPARAM(std::wstring, overwritePath, L"overwrite") APPPARAM(std::wstring, stylesheetsPath, L"stylesheets") APPPARAM(std::wstring, cachePath, L"webcache") +APPPARAM(std::wstring, tutorialsPath, L"tutorials") +APPPARAM(std::wstring, logPath, L"logs") APPPARAM(std::wstring, profileTweakIni, L"profile_tweaks.ini") -APPPARAM(std::wstring, logFile, L"ModOrganizer.log") +APPPARAM(std::wstring, logFileName, L"ModOrganizer.log") +APPPARAM(std::wstring, iniFileName, L"ModOrganizer.ini") APPPARAM(std::wstring, proxyDLLTarget, L"steam_api.dll") APPPARAM(std::wstring, proxyDLLOrig, L"steam_api_orig.dll") // needs to be identical to the value used in proxydll-project APPPARAM(std::wstring, proxyDLLSource, L"proxy.dll") diff --git a/src/shared/fallout3info.cpp b/src/shared/fallout3info.cpp index 6c420044..c8688cc4 100644 --- a/src/shared/fallout3info.cpp +++ b/src/shared/fallout3info.cpp @@ -84,21 +84,6 @@ bool Fallout3Info::isInvalidationBSA(const std::wstring &bsaName) return false; } -std::wstring Fallout3Info::getDocumentsDir() -{ - std::wostringstream temp; - temp << getMyGamesDirectory() << L"\\Fallout3"; - - return temp.str(); -} - -std::wstring Fallout3Info::getSaveGameDir() -{ - std::wostringstream temp; - temp << getDocumentsDir() << L"\\Saves"; - return temp.str(); -} - std::vector Fallout3Info::getPrimaryPlugins() { return boost::assign::list_of(L"fallout3.esm"); @@ -134,11 +119,6 @@ std::vector Fallout3Info::getIniFileNames() return boost::assign::list_of(L"fallout.ini")(L"falloutprefs.ini"); } -std::wstring Fallout3Info::getSaveGameExtension() -{ - return L"*.fos"; -} - std::wstring Fallout3Info::getReferenceDataFile() { return L"Fallout - Meshes.bsa"; @@ -155,21 +135,11 @@ std::vector Fallout3Info::getSteamVariants() const return boost::assign::list_of(L"Regular")(L"Game Of The Year"); } -std::wstring Fallout3Info::getSteamAPPId(int variant) const -{ - switch (variant) { - case 1: return L"22370"; - default: return L"22300"; - } -} - - std::wstring Fallout3Info::getSEName() { return L"fose"; } - std::wstring Fallout3Info::getNexusPage(bool nmmScheme) { if (nmmScheme) { @@ -192,68 +162,6 @@ int Fallout3Info::getNexusModIDStatic() } -void Fallout3Info::createProfile(const std::wstring &directory, bool useDefaults) -{ - std::wostringstream target; - - // copy plugins.txt - target << directory << "\\plugins.txt"; - - if (!FileExists(target.str())) { - std::wostringstream source; - source << getLocalAppFolder() << "\\Fallout3\\plugins.txt"; - if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) { - HANDLE file = ::CreateFileW(target.str().c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - ::CloseHandle(file); - } - } - - // copy ini-file - target.str(L""); target.clear(); - target << directory << L"\\fallout.ini"; - - if (!FileExists(target.str())) { - std::wostringstream source; - if (useDefaults) { - source << getGameDirectory() << L"\\fallout_default.ini"; - } else { - source << getMyGamesDirectory() << L"\\Fallout3"; - if (FileExists(source.str(), L"fallout.ini")) { - source << L"\\fallout.ini"; - } else { - source.str(L""); - source << getGameDirectory() << L"\\fallout_default.ini"; - } - } - - if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) { - if (::GetLastError() != ERROR_FILE_EXISTS) { - std::ostringstream stream; - stream << "failed to copy ini file: " << ToString(source.str(), false); - throw windows_error(stream.str()); - } - } - } - { // copy falloutprefs.ini-file - std::wstring target = directory + L"\\falloutprefs.ini"; - if (!FileExists(target)) { - std::wstring source = getMyGamesDirectory() + L"\\Fallout3\\falloutprefs.ini"; - if (!::CopyFileW(source.c_str(), target.c_str(), true)) { - if (::GetLastError() != ERROR_FILE_EXISTS) { - throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false)); - } - } - } - } -} - - -void Fallout3Info::repairProfile(const std::wstring &directory) -{ - createProfile(directory, false); -} - - bool Fallout3Info::rerouteToProfile(const wchar_t *fileName, const wchar_t*) { static LPCWSTR profileFiles[] = { L"fallout.ini", L"falloutprefs.ini", L"plugins.txt", nullptr }; @@ -266,17 +174,4 @@ bool Fallout3Info::rerouteToProfile(const wchar_t *fileName, const wchar_t*) return false; } - -/*std::vector Fallout3Info::getExecutables() -{ - std::vector result; - result.push_back(ExecutableInfo(L"FOSE", L"fose_loader.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Fallout 3", L"fallout3.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Fallout Mod Manager", L"fomm/fomm.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Construction Kit", L"geck.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Fallout Launcher", L"FalloutLauncher.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"BOSS", L"BOSS/BOSS.exe", L"", L"", NEVER_CLOSE)); - - return result; -}*/ } // namespace MOShared diff --git a/src/shared/fallout3info.h b/src/shared/fallout3info.h index 7e39cce4..6a211d4f 100644 --- a/src/shared/fallout3info.h +++ b/src/shared/fallout3info.h @@ -50,11 +50,6 @@ public: virtual bool isInvalidationBSA(const std::wstring &bsaName); - // full path to this games "My Games"-directory - virtual std::wstring getDocumentsDir(); - - virtual std::wstring getSaveGameDir(); - virtual std::vector getPrimaryPlugins(); virtual std::vector getVanillaBSAs(); @@ -64,12 +59,10 @@ public: // file name of this games ini (no path) virtual std::vector getIniFileNames(); - virtual std::wstring getSaveGameExtension(); virtual std::wstring getReferenceDataFile(); virtual std::wstring getOMODExt(); virtual std::vector getSteamVariants() const; - virtual std::wstring getSteamAPPId(int variant = 0) const; virtual std::wstring getSEName(); @@ -80,9 +73,6 @@ public: virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 120; } - virtual void createProfile(const std::wstring &directory, bool useDefaults); - virtual void repairProfile(const std::wstring &directory); - virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath); // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to diff --git a/src/shared/falloutnvinfo.cpp b/src/shared/falloutnvinfo.cpp index f589124a..8e701887 100644 --- a/src/shared/falloutnvinfo.cpp +++ b/src/shared/falloutnvinfo.cpp @@ -85,21 +85,6 @@ bool FalloutNVInfo::isInvalidationBSA(const std::wstring &bsaName) return false; } -std::wstring FalloutNVInfo::getDocumentsDir() -{ - std::wostringstream temp; - temp << getMyGamesDirectory() << L"\\FalloutNV"; - - return temp.str(); -} - -std::wstring FalloutNVInfo::getSaveGameDir() -{ - std::wostringstream temp; - temp << getDocumentsDir() << L"\\Saves"; - return temp.str(); -} - std::vector FalloutNVInfo::getPrimaryPlugins() { return boost::assign::list_of(L"falloutnv.esm"); @@ -139,11 +124,6 @@ std::vector FalloutNVInfo::getIniFileNames() return boost::assign::list_of(L"fallout.ini")(L"falloutprefs.ini"); } -std::wstring FalloutNVInfo::getSaveGameExtension() -{ - return L"*.fos"; -} - std::wstring FalloutNVInfo::getReferenceDataFile() { return L"Fallout - Meshes.bsa"; @@ -156,61 +136,6 @@ std::wstring FalloutNVInfo::getOMODExt() } -std::wstring FalloutNVInfo::getSteamAPPId(int) const -{ - return L"22380"; -} - - -void FalloutNVInfo::createProfile(const std::wstring &directory, bool useDefaults) -{ - std::wstring target = directory + L"\\plugins.txt"; - - // copy plugins.txt - if (!FileExists(target)) { - std::wstring source = getLocalAppFolder() + L"\\FalloutNV\\plugins.txt"; - if (!::CopyFileW(source.c_str(), target.c_str(), true)) { - HANDLE file = ::CreateFileW(target.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - ::CloseHandle(file); - } - } - - // copy ini-file - target = directory + L"\\fallout.ini"; - - if (!FileExists(target)) { - std::wstring source; - if (useDefaults) { - source = getGameDirectory() + L"\\fallout_default.ini"; - } else { - source = getMyGamesDirectory() + L"\\FalloutNV"; - if (FileExists(source, L"fallout.ini")) { - source += L"\\fallout.ini"; - } else { - source = getGameDirectory() + L"\\fallout_default.ini"; - } - } - - if (!::CopyFileW(source.c_str(), target.c_str(), true)) { - if (::GetLastError() != ERROR_FILE_EXISTS) { - throw windows_error("failed to copy ini file: " + ToString(source, false)); - } - } - } - { // copy falloutprefs.ini-file - std::wstring target = directory + L"\\falloutprefs.ini"; - if (!FileExists(target)) { - std::wstring source = getMyGamesDirectory() + L"\\FalloutNV\\falloutprefs.ini"; - if (!::CopyFileW(source.c_str(), target.c_str(), true)) { - if (::GetLastError() != ERROR_FILE_EXISTS) { - throw windows_error("failed to copy ini file: " + ToString(source, false)); - } - } - } - } -} - - std::wstring FalloutNVInfo::getSEName() { return L"nvse"; @@ -239,12 +164,6 @@ int FalloutNVInfo::getNexusModIDStatic() } -void FalloutNVInfo::repairProfile(const std::wstring &directory) -{ - createProfile(directory, false); -} - - bool FalloutNVInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) { static LPCWSTR profileFiles[] = { L"fallout.ini", L"falloutprefs.ini", L"plugins.txt", nullptr }; diff --git a/src/shared/falloutnvinfo.h b/src/shared/falloutnvinfo.h index 231311de..513b7218 100644 --- a/src/shared/falloutnvinfo.h +++ b/src/shared/falloutnvinfo.h @@ -52,11 +52,6 @@ public: virtual bool isInvalidationBSA(const std::wstring &bsaName); - // full path to this games "My Games"-directory - virtual std::wstring getDocumentsDir(); - - virtual std::wstring getSaveGameDir(); - virtual std::vector getPrimaryPlugins(); virtual std::vector getVanillaBSAs(); @@ -66,12 +61,9 @@ public: // file name of this games ini (no path) virtual std::vector getIniFileNames(); - virtual std::wstring getSaveGameExtension(); virtual std::wstring getReferenceDataFile(); virtual std::wstring getOMODExt(); - virtual std::wstring getSteamAPPId(int variant = 0) const; - virtual std::wstring getSEName(); virtual std::wstring getNexusPage(bool nmmScheme = true); @@ -81,9 +73,6 @@ public: virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 130; } - virtual void createProfile(const std::wstring &directory, bool useDefaults); - virtual void repairProfile(const std::wstring &directory); - virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath); // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to diff --git a/src/shared/gameinfo.cpp b/src/shared/gameinfo.cpp index 3727ea49..6d8957ad 100644 --- a/src/shared/gameinfo.cpp +++ b/src/shared/gameinfo.cpp @@ -135,49 +135,9 @@ std::wstring GameInfo::getGameDirectory() const return m_GameDirectory; } -std::wstring GameInfo::getModsDir() const -{ - return m_OrganizerDirectory + L"\\mods"; -} - -std::wstring GameInfo::getProfilesDir() const -{ - return m_OrganizerDirectory + L"\\profiles"; -} - -std::wstring GameInfo::getIniFilename() const -{ - return m_OrganizerDirectory + L"\\ModOrganizer.ini"; -} - - -std::wstring GameInfo::getOverwriteDir() const -{ - return m_OrganizerDirectory + L"\\overwrite"; -} - - -std::wstring GameInfo::getLogDir() const -{ - return m_OrganizerDirectory + L"\\logs"; -} - - -std::wstring GameInfo::getLootDir() const -{ - return m_OrganizerDirectory + L"\\loot"; -} - - -std::wstring GameInfo::getTutorialDir() const -{ - return m_OrganizerDirectory + L"\\tutorials"; -} - - bool GameInfo::requiresSteam() const { - return FileExists(getGameDirectory().append(L"\\steam_api.dll")); + return FileExists(getGameDirectory() + L"\\steam_api.dll"); } std::vector GameInfo::getSteamVariants() const @@ -185,7 +145,6 @@ std::vector GameInfo::getSteamVariants() const return boost::assign::list_of(L"Regular"); } - std::wstring GameInfo::getLocalAppFolder() const { wchar_t localAppFolder[MAX_PATH]; diff --git a/src/shared/gameinfo.h b/src/shared/gameinfo.h index a9da0b97..dbb935f6 100644 --- a/src/shared/gameinfo.h +++ b/src/shared/gameinfo.h @@ -93,18 +93,13 @@ public: virtual std::wstring getGameName() const = 0; virtual std::wstring getGameShortName() const = 0; - // full path to this games "My Games"-directory - virtual std::wstring getDocumentsDir() = 0; - - virtual std::wstring getSaveGameDir() = 0; - /// determine the load order mechanism used by this game. this may throw an /// exception if the mechanism can't be determined virtual LoadOrderMechanism getLoadOrderMechanism() const { return TYPE_FILETIME; } virtual std::wstring getGameDirectory() const; // get absolute path to the directory where omo stores its mods - virtual std::wstring getModsDir() const; +/* virtual std::wstring getModsDir() const; // get absolute path to the directory where omo stores its profiles virtual std::wstring getProfilesDir() const; @@ -112,7 +107,7 @@ public: virtual std::wstring getOverwriteDir() const; virtual std::wstring getLogDir() const; virtual std::wstring getLootDir() const; - virtual std::wstring getTutorialDir() const; + virtual std::wstring getTutorialDir() const;*/ virtual bool requiresBSAInvalidation() const { return true; } virtual bool requiresSteam() const; @@ -137,13 +132,11 @@ public: // file name of this games ini file(s) virtual std::vector getIniFileNames() = 0; - virtual std::wstring getSaveGameExtension() = 0; virtual std::wstring getReferenceDataFile() = 0; virtual std::wstring getOMODExt() = 0; virtual std::vector getSteamVariants() const; - virtual std::wstring getSteamAPPId(int variant = 0) const = 0; virtual std::wstring getSEName() = 0; @@ -152,10 +145,6 @@ public: virtual int getNexusModID() = 0; virtual int getNexusGameID() = 0; - // clone relevant files to the specified directory - virtual void createProfile(const std::wstring &directory, bool useDefaults) = 0; - virtual void repairProfile(const std::wstring &directory) = 0; - virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) = 0; public: diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp index 586bcaef..c945dcf4 100644 --- a/src/shared/oblivioninfo.cpp +++ b/src/shared/oblivioninfo.cpp @@ -86,22 +86,6 @@ bool OblivionInfo::isInvalidationBSA(const std::wstring &bsaName) return false; } -std::wstring OblivionInfo::getDocumentsDir() -{ - std::wostringstream temp; - temp << getMyGamesDirectory() << L"\\Oblivion"; - - return temp.str(); -} - -std::wstring OblivionInfo::getSaveGameDir() -{ - std::wostringstream temp; - temp << getDocumentsDir() << L"\\Saves"; - return temp.str(); -} - - std::vector OblivionInfo::getPrimaryPlugins() { return boost::assign::list_of(L"oblivion.esm"); @@ -147,63 +131,6 @@ std::vector OblivionInfo::getIniFileNames() } -void OblivionInfo::createProfile(const std::wstring &directory, bool useDefaults) -{ - std::wostringstream target; - - // copy plugins.txt - target << directory << "\\plugins.txt"; - - if (!FileExists(target.str())) { - std::wostringstream source; - source << getLocalAppFolder() << "\\Oblivion\\plugins.txt"; - if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) { - HANDLE file = ::CreateFileW(target.str().c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - ::CloseHandle(file); - } - } - - // copy ini-file - target.str(L""); target.clear(); - target << directory << L"\\oblivion.ini"; - - if (!FileExists(target.str())) { - std::wostringstream source; - if (useDefaults) { - source << getGameDirectory() << L"\\oblivion_default.ini"; - } else { - source << getMyGamesDirectory() << L"Oblivion"; - if (FileExists(source.str(), L"oblivion.ini")) { - source << L"\\oblivion.ini"; - } else { - source.str(L""); - source << getGameDirectory() << L"\\oblivion_default.ini"; - } - } - if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) { - if (::GetLastError() != ERROR_FILE_EXISTS) { - std::ostringstream stream; - stream << "failed to copy ini file: " << ToString(source.str(), false); - throw windows_error(stream.str()); - } - } - } - - { // copy oblivionprefs.ini-file - std::wstring target = directory + L"\\oblivionprefs.ini"; - if (!FileExists(target)) { - std::wstring source = getMyGamesDirectory() + L"\\Oblivion\\oblivionprefs.ini"; - if (!::CopyFileW(source.c_str(), target.c_str(), true)) { - if ((::CreateFileW(target.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr) == INVALID_HANDLE_VALUE) && - (::GetLastError() != ERROR_FILE_EXISTS)) { - throw windows_error(std::string("failed to create ini file: ") + ToString(target, false)); - } - } - } - } -} - - std::wstring OblivionInfo::getSEName() { return L"obse"; @@ -231,13 +158,6 @@ int OblivionInfo::getNexusModIDStatic() return 38277; } - -void OblivionInfo::repairProfile(const std::wstring &directory) -{ - createProfile(directory, false); -} - - bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) { static LPCWSTR profileFiles[] = { L"oblivion.ini", L"oblivionprefs.ini", L"plugins.txt", nullptr }; @@ -250,12 +170,6 @@ bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) return false; } - -std::wstring OblivionInfo::getSaveGameExtension() -{ - return L"*.ess"; -} - std::wstring OblivionInfo::getReferenceDataFile() { return L"Oblivion - Meshes.bsa"; @@ -268,23 +182,4 @@ std::wstring OblivionInfo::getOMODExt() } -std::wstring OblivionInfo::getSteamAPPId(int) const -{ - return L"22330"; -} - -/* -std::vector OblivionInfo::getExecutables() -{ - std::vector result; - result.push_back(ExecutableInfo(L"OBSE", L"obse_loader.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Oblivion", L"oblivion.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Oblivion Mod Manager", L"OblivionModManager.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Construction Set", L"TESConstructionSet.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Oblivion Launcher", L"OblivionLauncher.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"BOSS", L"BOSS/BOSS.exe", L"", L"", NEVER_CLOSE)); - result.push_back(ExecutableInfo(L"BOSS (old)", L"Data/BOSS.exe", L"", L"", NEVER_CLOSE)); - - return result; -}*/ } // namespace MOShared diff --git a/src/shared/oblivioninfo.h b/src/shared/oblivioninfo.h index cb506c01..a93f510e 100644 --- a/src/shared/oblivioninfo.h +++ b/src/shared/oblivioninfo.h @@ -48,11 +48,6 @@ public: virtual bool isInvalidationBSA(const std::wstring &bsaName); - // full path to this games "My Games"-directory - virtual std::wstring getDocumentsDir(); - - virtual std::wstring getSaveGameDir(); - virtual std::vector getPrimaryPlugins(); virtual std::vector getVanillaBSAs(); @@ -62,12 +57,9 @@ public: // file name of this games ini (no path) virtual std::vector getIniFileNames(); - virtual std::wstring getSaveGameExtension(); virtual std::wstring getReferenceDataFile(); virtual std::wstring getOMODExt(); - virtual std::wstring getSteamAPPId(int variant = 0) const; - virtual std::wstring getSEName(); virtual std::wstring getNexusPage(bool nmmScheme = true); @@ -77,9 +69,6 @@ public: virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 101; } - virtual void createProfile(const std::wstring &directory, bool useDefaults); - virtual void repairProfile(const std::wstring &directory); - virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath); // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp index 1d00c4f3..feaf88a3 100644 --- a/src/shared/skyriminfo.cpp +++ b/src/shared/skyriminfo.cpp @@ -97,7 +97,7 @@ bool SkyrimInfo::isInvalidationBSA(const std::wstring &bsaName) GameInfo::LoadOrderMechanism SkyrimInfo::getLoadOrderMechanism() const { - std::wstring fileName = getGameDirectory().append(L"\\TESV.exe"); + std::wstring fileName = getGameDirectory() + L"\\TESV.exe"; try { VS_FIXEDFILEINFO versionInfo = GetFileVersion(fileName); @@ -113,21 +113,6 @@ GameInfo::LoadOrderMechanism SkyrimInfo::getLoadOrderMechanism() const } } -std::wstring SkyrimInfo::getDocumentsDir() -{ - std::wostringstream temp; - temp << getMyGamesDirectory() << L"\\Skyrim"; - - return temp.str(); -} - -std::wstring SkyrimInfo::getSaveGameDir() -{ - std::wostringstream temp; - temp << getDocumentsDir() << L"\\Saves"; - return temp.str(); -} - std::vector SkyrimInfo::getPrimaryPlugins() { return boost::assign::list_of(L"skyrim.esm")(L"update.esm"); @@ -170,11 +155,6 @@ std::vector SkyrimInfo::getIniFileNames() return boost::assign::list_of(L"skyrim.ini")(L"skyrimprefs.ini"); } -std::wstring SkyrimInfo::getSaveGameExtension() -{ - return L"*.ess"; -} - std::wstring SkyrimInfo::getReferenceDataFile() { return L"Skyrim - Meshes.bsa"; @@ -186,13 +166,6 @@ std::wstring SkyrimInfo::getOMODExt() return L"fomod"; } - -std::wstring SkyrimInfo::getSteamAPPId(int) const -{ - return L"72850"; -} - - std::wstring SkyrimInfo::getSEName() { return L"skse"; @@ -220,73 +193,6 @@ int SkyrimInfo::getNexusModIDStatic() return 1334; } - -void SkyrimInfo::createProfile(const std::wstring &directory, bool useDefaults) -{ - { // copy plugins.txt - std::wstring target = directory + L"\\plugins.txt"; - if (!FileExists(target)) { - std::wostringstream source; - source << getLocalAppFolder() << "\\Skyrim\\plugins.txt"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { - HANDLE file = ::CreateFileW(target.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - ::CloseHandle(file); - } - } - target = directory + L"\\loadorder.txt"; - if (!FileExists(target)) { - std::wstring source = getLocalAppFolder() + L"\\Skyrim\\loadorder.txt"; - if (!::CopyFileW(source.c_str(), target.c_str(), true)) { - HANDLE file = ::CreateFileW(target.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - ::CloseHandle(file); - } - } - } - - { // copy skyrim.ini-file - std::wstring target = directory + L"\\skyrim.ini"; - if (!FileExists(target)) { - std::wstring source; - if (useDefaults) { - source = getGameDirectory() + L"\\skyrim_default.ini"; - } else { - source = getMyGamesDirectory() + L"\\Skyrim"; - if (FileExists(source, L"skyrim.ini")) { - source += L"\\skyrim.ini"; - } else { - source = getGameDirectory() + L"\\skyrim_default.ini"; - } - } - if (!::CopyFileW(source.c_str(), target.c_str(), true)) { - if (::GetLastError() != ERROR_FILE_EXISTS) { - throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false) + " to " + ToString(target, false)); - } - } - } - } - - { // copy skyrimprefs.ini-file - std::wstring target = directory + L"\\skyrimprefs.ini"; - if (!FileExists(target)) { - std::wstring source = getMyGamesDirectory() + L"\\Skyrim\\skyrimprefs.ini"; - if (!::CopyFileW(source.c_str(), target.c_str(), true)) { - log("failed to copy ini file %ls", source.c_str()); - // create empty - if (::CreateFileW(target.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) == INVALID_HANDLE_VALUE) { - throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false)); - } - } - } - } -} - - -void SkyrimInfo::repairProfile(const std::wstring &directory) -{ - createProfile(directory, false); -} - - bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) { static LPCWSTR profileFiles[] = { L"skyrim.ini", L"skyrimprefs.ini", L"loadorder.txt", nullptr }; @@ -306,17 +212,4 @@ bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPa } -/*std::vector SkyrimInfo::getExecutables() -{ - std::vector result; - result.push_back(ExecutableInfo(L"SKSE", L"skse_loader.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"SBW", L"SBW.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Skyrim", L"TESV.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Skyrim Launcher", L"SkyrimLauncher.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"BOSS", L"BOSS/BOSS.exe", L"", L"", DEFAULT_STAY)); - result.push_back(ExecutableInfo(L"Creation Kit", L"CreationKit.exe", L"", L"", DEFAULT_STAY, L"202480")); - - return result; -}*/ - } // namespace MOShared diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h index ad6ab95d..bf08fb25 100644 --- a/src/shared/skyriminfo.h +++ b/src/shared/skyriminfo.h @@ -49,17 +49,11 @@ public: virtual LoadOrderMechanism getLoadOrderMechanism() const; virtual bool requiresBSAInvalidation() const { return true; } -// virtual bool requiresSteam() const { return true; } virtual std::wstring getInvalidationBSA(); virtual bool isInvalidationBSA(const std::wstring &bsaName); - // full path to this games "My Games"-directory - virtual std::wstring getDocumentsDir(); - - virtual std::wstring getSaveGameDir(); - virtual std::vector getPrimaryPlugins(); virtual std::vector getVanillaBSAs(); @@ -70,12 +64,9 @@ public: // file name of this games ini (no path) virtual std::vector getIniFileNames(); - virtual std::wstring getSaveGameExtension(); virtual std::wstring getReferenceDataFile(); virtual std::wstring getOMODExt(); - virtual std::wstring getSteamAPPId(int variant = 0) const; - virtual std::wstring getSEName(); virtual std::wstring getNexusPage(bool nmmScheme = true); @@ -87,15 +78,8 @@ public: static int getNexusGameIDStatic() { return 110; } virtual int getNexusGameID() { return getNexusGameIDStatic(); } - virtual void createProfile(const std::wstring &directory, bool useDefaults); - virtual void repairProfile(const std::wstring &directory); - virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath); - // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to - // the game directory - //virtual std::vector getExecutables(); - virtual std::wstring archiveListKey() { return L"SResourceArchiveList"; } private: diff --git a/src/transfersavesdialog.cpp b/src/transfersavesdialog.cpp index b07b1673..5d20c253 100644 --- a/src/transfersavesdialog.cpp +++ b/src/transfersavesdialog.cpp @@ -31,8 +31,11 @@ using namespace MOBase; using namespace MOShared; -TransferSavesDialog::TransferSavesDialog(const Profile &profile, QWidget *parent) - : TutorableDialog("TransferSaves", parent), ui(new Ui::TransferSavesDialog), m_Profile(profile) +TransferSavesDialog::TransferSavesDialog(const Profile &profile, IPluginGame *gamePlugin, QWidget *parent) + : TutorableDialog("TransferSaves", parent) + , ui(new Ui::TransferSavesDialog) + , m_Profile(profile) + , m_GamePlugin(gamePlugin) { ui->setupUi(this); refreshGlobalSaves(); @@ -51,10 +54,10 @@ void TransferSavesDialog::refreshGlobalSaves() { m_GlobalSaves.clear(); - QDir savesDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getSaveGameDir()))); + QDir savesDir(m_GamePlugin->savesDirectory()); QStringList filters; - filters << ToQString(GameInfo::instance().getSaveGameExtension()); + filters << m_GamePlugin->savegameExtension(); savesDir.setNameFilters(filters); QStringList files = savesDir.entryList(QDir::Files, QDir::Time); @@ -71,10 +74,10 @@ void TransferSavesDialog::refreshLocalSaves() { m_LocalSaves.clear(); - QDir savesDir(m_Profile.getPath().append("/saves")); + QDir savesDir(m_Profile.getPath() + "/saves"); QStringList filters; - filters << ToQString(GameInfo::instance().getSaveGameExtension()); + filters << m_GamePlugin->savegameExtension(); savesDir.setNameFilters(filters); QStringList files = savesDir.entryList(QDir::Files, QDir::Time); @@ -232,7 +235,7 @@ void TransferSavesDialog::on_moveToGlobalBtn_clicked() "that this will mess up the running number of save games.").arg(selectedCharacter), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - QString destination = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getSaveGameDir())); + QDir destination = m_GamePlugin->savesDirectory(); OverwriteMode overwriteMode = OVERWRITE_ASK; for (std::vector::const_iterator iter = m_LocalSaves.begin(); iter != m_LocalSaves.end(); ++iter) { @@ -240,7 +243,7 @@ void TransferSavesDialog::on_moveToGlobalBtn_clicked() QStringList files = (*iter)->saveFiles(); foreach (const QString &file, files) { QFileInfo fileInfo(file); - QString destinationFile = destination.mid(0).append("/").append(fileInfo.fileName()); + QString destinationFile = destination.filePath(fileInfo.fileName()); if (QFile::exists(destinationFile)) { if (testOverwrite(overwriteMode, destinationFile)) { QFile::remove(destinationFile); @@ -271,7 +274,7 @@ void TransferSavesDialog::on_copyToGlobalBtn_clicked() "that this will mess up the running number of save games.").arg(selectedCharacter), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - QString destination = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getSaveGameDir())); + QDir destination = m_GamePlugin->savesDirectory(); OverwriteMode overwriteMode = OVERWRITE_ASK; for (std::vector::const_iterator iter = m_LocalSaves.begin(); iter != m_LocalSaves.end(); ++iter) { @@ -279,7 +282,7 @@ void TransferSavesDialog::on_copyToGlobalBtn_clicked() QStringList files = (*iter)->saveFiles(); foreach (const QString &file, files) { QFileInfo fileInfo(file); - QString destinationFile = destination.mid(0).append("/").append(fileInfo.fileName()); + QString destinationFile = destination.filePath(fileInfo.fileName()); if (QFile::exists(destinationFile)) { if (testOverwrite(overwriteMode, destinationFile)) { QFile::remove(destinationFile); diff --git a/src/transfersavesdialog.h b/src/transfersavesdialog.h index 37a85000..4d466bf2 100644 --- a/src/transfersavesdialog.h +++ b/src/transfersavesdialog.h @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include "tutorabledialog.h" #include "savegamegamebyro.h" #include "profile.h" +#include namespace Ui { class TransferSavesDialog; @@ -33,7 +34,7 @@ class TransferSavesDialog : public MOBase::TutorableDialog Q_OBJECT public: - explicit TransferSavesDialog(const Profile &profile, QWidget *parent = 0); + explicit TransferSavesDialog(const Profile &profile, MOBase::IPluginGame *gamePlugin, QWidget *parent = 0); ~TransferSavesDialog(); private slots: @@ -74,6 +75,8 @@ private: Profile m_Profile; + MOBase::IPluginGame *m_GamePlugin; + std::vector m_GlobalSaves; std::vector m_LocalSaves; diff --git a/src/tutorials/Highlight.qml b/src/tutorials/Highlight.qml index bb4db78f..55474c91 100644 --- a/src/tutorials/Highlight.qml +++ b/src/tutorials/Highlight.qml @@ -1,4 +1,3 @@ -// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5 import QtQuick 1.1 Rectangle { diff --git a/src/tutorials/Tooltip.qml b/src/tutorials/Tooltip.qml new file mode 100644 index 00000000..6424d9ab --- /dev/null +++ b/src/tutorials/Tooltip.qml @@ -0,0 +1,31 @@ +import QtQuick 1.1 + + +Rectangle { + color: "#EE888888" + width: childrenRect.width + 15 + height: childrenRect.height + 15 + z: 20000 + clip: false + border.color: "black" + border.width: 1 + property alias text: tooltipText.text + Text { + id: tooltipText + font.pointSize: 11 + wrapMode: Text.WordWrap + anchors.left: parent.left + anchors.top: parent.top + anchors.leftMargin: 7 + anchors.rightMargin: 7 + z: parent.z + color: "black" + onTextChanged: { + if (width > 200) + width = 200 + } + } + visible: false +} + + diff --git a/src/tutorials/TooltipArea.qml b/src/tutorials/TooltipArea.qml new file mode 100644 index 00000000..48a50f76 --- /dev/null +++ b/src/tutorials/TooltipArea.qml @@ -0,0 +1,55 @@ +import QtQuick 1.1 + +Rectangle { + radius: 2 + color: clickable ? "#AA6666AA" : "#AA882222" + height: 100 + border.color: "black" + border.width: 2 + z: 1 + smooth: true + property bool wasLocked: false + property bool clickable: false + property string tooltipText: "" + + MouseArea { + id: clickArea + anchors.fill: parent + hoverEnabled: true + + onMousePositionChanged: { + if (parent.parent.width - (parent.x + mouseX) < tooltip.width + 50) { + tooltip.x = parent.x + mouseX - 15 - tooltip.width + } else { + tooltip.x = parent.x + mouseX + 15 + } + + if (parent.parent.height - (parent.y + mouseY) < tooltip.height + 50) { + tooltip.y = parent.y + mouseY - 15 - tooltip.height + } else { + tooltip.y = parent.y + mouseY + 15 + } + } + + onEntered: { + tooltip.visible = true + tooltip.text = tooltipText + } + + onPressed: { + wasLocked = tutToplevel.backgroundEnabled() + if (wasLocked && clickable) { + tutorialControl.simulateClick(mouseX + parent.x, mouseY + parent.y) + } + mouse.accepted = false + } + + onCanceled: { + tooltip.visible = false + } + + onExited: { + tooltip.visible = false + } + } +} diff --git a/src/tutorials/TutorialDescription.qml b/src/tutorials/TutorialDescription.qml index b295e477..498573d2 100644 --- a/src/tutorials/TutorialDescription.qml +++ b/src/tutorials/TutorialDescription.qml @@ -15,8 +15,9 @@ Rectangle { border.color: "black" border.width: 3 smooth: true - opacity: 0.9 - color: "#707070" + //opacity: 0.9 + z: 10000 + color: "#FF707070" Image { id: continueIcon diff --git a/src/tutorials/TutorialOverlay.qml b/src/tutorials/TutorialOverlay.qml index f2aad027..15fe9603 100644 --- a/src/tutorials/TutorialOverlay.qml +++ b/src/tutorials/TutorialOverlay.qml @@ -2,52 +2,67 @@ import QtQuick 1.1 import "tutorials.js" as Logic Rectangle { - color: "transparent" - - property int step : 0 - property alias description: tutDescription - property alias highlight: tutHighlight - property alias text: tutDescription.text - property alias boxOpacity: tutDescription.opacity - property int offsetBottom: 50 - property int maxWidth: 400 - - function init() { - Logic.init() - Logic.nextStep() - } + color: "transparent" - function enableBackground(enabled) { - disabledBackground.visible = enabled - } -/* - signal nextStep + id: tutToplevel - onNextStep: {*/ - function nextStep() { - if (step == 0) { - Logic.init() - } + property int step : 0 + property alias description: tutDescription + property alias highlight: tutHighlight + property alias text: tutDescription.text + property alias boxOpacity: tutDescription.opacity + property int offsetBottom: 50 + property int maxWidth: 400 - Logic.nextStep() - } + signal tabChanged(int index) + + function init() { + Logic.init() + Logic.nextStep() + } + + function enableBackground(enabled) { + disabledBackground.visible = enabled + } - TutorialDescription { - id: tutDescription - innerWidth: maxWidth - anchors.bottomMargin: offsetBottom - onClicked: { - Logic.clickNext() - } + function backgroundEnabled() { + return disabledBackground.visible + } + + function nextStep() { + if (step == 0) { + Logic.init() } - Rectangle { - id: disabledBackground - anchors.fill: parent - opacity: 0.2 - color: "#808080" + Logic.nextStep() + } + + TutorialDescription { + id: tutDescription + innerWidth: maxWidth + anchors.bottomMargin: offsetBottom + onClicked: { + Logic.clickNext() } + } + + Rectangle { + id: disabledBackground + anchors.fill: parent + opacity: 0.2 + color: "#808080" + } + + Connections { + target: manager + onTabChanged: tabChanged(index) + } - Highlight { id: tutHighlight } + Tooltip { + id: tooltip + } + Highlight { + id: tutHighlight + } } diff --git a/src/tutorials/tutorial_primer_main.js b/src/tutorials/tutorial_primer_main.js new file mode 100644 index 00000000..12df2c86 --- /dev/null +++ b/src/tutorials/tutorial_primer_main.js @@ -0,0 +1,111 @@ +//TL Overview#5 + + +var tooltips = [] + +function tooltipWidget(widgetName, explanation, maxheight, clickable) { + var rect = tutorialControl.getRect(widgetName) + var component = Qt.createComponent("TooltipArea.qml") + if (component.status === Component.Error) { + console.log("b" + component.errorString()) + } + if (typeof clickable === 'undefined') { + clickable = false + } + if ((typeof maxheight === 'undefined') || maxheight === 0) { + maxheight = rect.height + } + + var obj = component.createObject(tutToplevel, + { "x" : rect.x, + "y" : rect.y, + "width" : rect.width, + "height" : maxheight + }) + obj.tooltipText = explanation + obj.clickable = clickable + obj.visible = true + + tooltips.push(obj) +} + +function tooltipAction(actionName, explanation, maxheight, clickable) { + var rect = tutorialControl.getActionRect(actionName) + var component = Qt.createComponent("TooltipArea.qml") + if (typeof clickable === 'undefined') { + clickable = false + } + if ((typeof maxheight === 'undefined') || maxheight === 0) { + maxheight = rect.height + } + var obj = component.createObject(tutToplevel, + { "x" : rect.x, + "y" : rect.y, + "width" : rect.width, + "height" : maxheight + }) + obj.tooltipText = explanation + obj.clickable = clickable + obj.visible = true + + tooltips.push(obj) +} + +function setupTooptips() { + for (var tip in tooltips) { + tooltips[tip].destroy() + } + tooltips = [] + + tooltipWidget("modList", qsTr("This window shows all the mods that are installed. The column headers can be used for sorting. Only checked mods are active in the current profile.")) + tooltipWidget("profileBox", qsTr("Each profile is a separate set of enabled mods and ini settings.")) + tooltipWidget("groupCombo", qsTr("The dropdown allows various ways of grouping the mods shown in the mod list.")) + tooltipWidget("displayCategoriesBtn", qsTr("Show/hide the category pane.")) + tooltipWidget("modFilterEdit", qsTr("Quickly filter the mod list as you type.")) + tooltipWidget("qt_tabwidget_tabbar", qsTr("Switch between information views."), 0, true) + tooltipWidget("categoriesList", qsTr("This shows mod categories and some meta categories (in angle-brackets). Select some to filter the mod list. For example select \"\" to show only active mods.")) + tooltipWidget("executablesListBox", qsTr("Customizable list for choosing the program to run.")) + tooltipWidget("startButton", qsTr("When this button is clicked, Mod Organizer creates a virtual directory structure then runs the program selected to the left.")) + tooltipWidget("linkButton", qsTr("Will create a shortcut for quick access. The shortcut can be placed in the toolbar at the top, in the Start Menu or on the Windows Desktop.")) + tooltipWidget("logList", qsTr("Log messages produced by MO. Please note that messages with a light bulb usually don't require your attention.")) + + tooltipAction("actionSettings", qsTr("Configure Mod Organizer.")) + tooltipAction("actionProblems", qsTr("Reports potential Problems about the current setup.")) + tooltipAction("actionUpdate", qsTr("Activates if there is an update for MO. Please note that if, for any reason, MO can't communicate with NMM, this will not work either.")) + + switch (manager.findControl("tabWidget").currentIndex) { + case 0: + tooltipWidget("espList", qsTr("Plugins (esp/esm files) of the mods in the current profile. They need to be checked to be loaded.")) + tooltipWidget("bossButton", qsTr("Automatically sort plugins using the bundled LOOT application.")) + tooltipWidget("espFilterEdit", qsTr("Quickly filter plugin list as you type.")) + break + case 1: + tooltipWidget("bsaList", qsTr("All the asset archives (.bsa files) for all active mods.")) + break + case 2: + tooltipWidget("dataTree", qsTr("The directory tree and all files that the program will see.")) + break + case 3: + tooltipWidget("savegameList", qsTr("Save game browser. Shows all the saves for the current profile and whether or not the current mod-load status is correct.")) + break + case 4: + tooltipWidget("downloadView", qsTr("Shows the mods that have been downloaded and if they’ve been installed.")) + break + } +} + +function getTutorialSteps() { + return [ + function() { + tutorial.text = qsTr("Click to quit") + + setupTooptips() + + onTabChanged(setupTooptips) + + waitForClick() + } + ] +} + + diff --git a/src/tutorials/tutorials.js b/src/tutorials/tutorials.js index f2b18856..eb23eab7 100644 --- a/src/tutorials/tutorials.js +++ b/src/tutorials/tutorials.js @@ -52,15 +52,25 @@ function clickNext() function nextStep() { - waitingForClick = false; - description.continueVisible = false - if (step < tutorialSteps.length) { - tutorialControl.lockUI(false) - step++ - tutorialSteps[step - 1]() - } else { - tutorialControl.finish() - } + waitingForClick = false; + description.continueVisible = false + if (step < tutorialSteps.length) { + tutorialControl.lockUI(false) + step++ + tutorialSteps[step - 1]() + } else { + tutorialControl.finish() + } +} + +function sameStep() +{ + tutorialSteps[step - 1]() +} + +function onTabChanged(func) +{ + tutToplevel.tabChanged.connect(func) } function init() -- cgit v1.3.1 From 8aa6dc4c7dcf4139cd0144207a327013bd3cb1dc Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 29 Jan 2015 19:26:42 +0100 Subject: extended the game-plugin interface --- src/dlls.manifest.debug.qt5 | 2 + src/dlls.manifest.qt5 | 2 + src/dummybsa.cpp | 244 ------------------------------------------- src/dummybsa.h | 64 ------------ src/loadmechanism.cpp | 91 ++++++++-------- src/main.cpp | 28 ++--- src/mainwindow.cpp | 119 ++++++++++----------- src/mainwindow.h | 2 - src/modinfo.cpp | 11 +- src/organizer.pro | 4 +- src/organizercore.cpp | 75 +++++-------- src/organizercore.h | 1 - src/pluginlist.cpp | 23 ++-- src/profile.cpp | 124 +++++----------------- src/profile.h | 15 +-- src/profilesdialog.cpp | 27 +++-- src/profilesdialog.h | 3 +- src/selectiondialog.cpp | 23 +++- src/selectiondialog.h | 5 +- src/shared/fallout3info.cpp | 46 +------- src/shared/fallout3info.h | 45 +++++--- src/shared/falloutnvinfo.cpp | 63 ----------- src/shared/falloutnvinfo.h | 43 +++++--- src/shared/gameinfo.h | 55 +--------- src/shared/oblivioninfo.cpp | 48 +-------- src/shared/oblivioninfo.h | 45 +++++--- src/shared/skyriminfo.cpp | 56 +--------- src/shared/skyriminfo.h | 16 --- 28 files changed, 338 insertions(+), 942 deletions(-) delete mode 100644 src/dummybsa.cpp delete mode 100644 src/dummybsa.h (limited to 'src/profilesdialog.h') diff --git a/src/dlls.manifest.debug.qt5 b/src/dlls.manifest.debug.qt5 index e49b33b8..59497baa 100644 --- a/src/dlls.manifest.debug.qt5 +++ b/src/dlls.manifest.debug.qt5 @@ -23,5 +23,7 @@ + + diff --git a/src/dlls.manifest.qt5 b/src/dlls.manifest.qt5 index b8f2d467..76206f21 100644 --- a/src/dlls.manifest.qt5 +++ b/src/dlls.manifest.qt5 @@ -23,5 +23,7 @@ + + \ No newline at end of file diff --git a/src/dummybsa.cpp b/src/dummybsa.cpp deleted file mode 100644 index 49c6ee53..00000000 --- a/src/dummybsa.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Mod Organizer. If not, see . -*/ - -#include "dummybsa.h" -#include -#include -#define WIN32_LEAN_AND_MEAN -#include - - -static void writeUlong(unsigned char* buffer, int offset, unsigned long value) -{ - union { - unsigned long ulValue; - unsigned char cValue[4]; - }; - ulValue = value; - memcpy(buffer + offset, cValue, 4); -} - -static void writeUlonglong(unsigned char* buffer, int offset, unsigned long long value) -{ - union { - unsigned long long ullValue; - unsigned char cValue[8]; - }; - ullValue = value; - memcpy(buffer + offset, cValue, 8); -} -/* -static unsigned long long genHashInt(const char* pos, const char* end) -{ - unsigned long long hash2 = 0; - for (; pos < end; ++pos) { - hash2 *= 0x1003f; - hash2 += *pos; - } - return hash2; -} - - -static unsigned long long genHash(const char* fileName) -{ - char fileNameLower[MAX_PATH + 1]; - int i = 0; - for (; i < MAX_PATH && fileName[i] != '\0'; ++i) { - fileNameLower[i] = tolower(fileName[i]); - } - fileNameLower[i] = '\0'; - - char* ext = strrchr(fileNameLower, '.'); - if (ext == nullptr) { - ext = fileNameLower + strlen(fileNameLower); - } - - int length = ext - fileNameLower; - - unsigned long long hash = 0ULL; - - if (length > 0) { - hash = *(ext - 1) | - ((length > 2 ? *(ext - 2) : 0) << 8) | - (length << 16) | - (fileNameLower[0] << 24); - } - - if (strcmp(ext + 1, "dds") == 0) { - hash |= 0x8080; - } // the rest is not supported currently - - hash |= genHashInt(fileNameLower + 1, ext - 2) << 0x32; - hash |= genHashInt(ext, ext + strlen(ext)) << 0x32; - - return hash; -}*/ - - -static unsigned long genHashInt(const unsigned char *pos, const unsigned char *end) -{ - unsigned long hash = 0; - for (; pos < end; ++pos) { - hash *= 0x1003f; - hash += *pos; - } - return hash; -} - - -static unsigned long long genHash(const char* fileName) -{ - char fileNameLower[MAX_PATH + 1]; - int i = 0; - for (; i < MAX_PATH && fileName[i] != '\0'; ++i) { - fileNameLower[i] = static_cast(tolower(fileName[i])); - if (fileNameLower[i] == '\\') { - fileNameLower[i] = '/'; - } - } - fileNameLower[i] = '\0'; - - unsigned char *fileNameLowerU = reinterpret_cast(fileNameLower); - - char* ext = strrchr(fileNameLower, '.'); - if (ext == nullptr) { - ext = fileNameLower + strlen(fileNameLower); - } - unsigned char *extU = reinterpret_cast(ext); - - int length = ext - fileNameLower; - - unsigned long long hash = 0ULL; - - if (length > 0) { - hash = *(extU - 1) | - ((length > 2 ? *(ext - 2) : 0) << 8) | - (length << 16) | - (fileNameLowerU[0] << 24); - } - - if (strlen(ext) > 0) { - if (strcmp(ext + 1, "kf") == 0) { - hash |= 0x80; - } else if (strcmp(ext + 1, "nif") == 0) { - hash |= 0x8000; - } else if (strcmp(ext + 1, "dds") == 0) { - hash |= 0x8080; - } else if (strcmp(ext + 1, "wav") == 0) { - hash |= 0x80000000; - } - - unsigned long long temp = static_cast(genHashInt( - fileNameLowerU + 1, extU - 2)); - temp += static_cast(genHashInt( - extU, extU + strlen(ext))); - - hash |= (temp & 0xFFFFFFFF) << 32; - } - return hash; -} - - -DummyBSA::DummyBSA() - : m_Version(MOShared::GameInfo::instance().getBSAVersion()), m_FolderName(""), m_FileName("dummy.dds"), - m_TotalFileNameLength(0) -{ -} - - -void DummyBSA::writeHeader(QFile& file) -{ - unsigned char header[] = { - 'B', 'S', 'A', '\0', // magic string - 0xDE, 0xAD, 0xBE, 0xEF, // version - insert later - 0x24, 0x00, 0x00, 0x00, // offset to folder recors. header size is static - 0xDE, 0xAD, 0xBE, 0xEF, // archive flags - insert later - 0x01, 0x00, 0x00, 0x00, // folder count - 0x01, 0x00, 0x00, 0x00, // file count - 0xDE, 0xAD, 0xBE, 0xEF, // total folder names length - insert later - 0xDE, 0xAD, 0xBE, 0xEF, // total file names length - insert later - 0xDE, 0xAD, 0xBE, 0xEF // file flags - insert later - }; - - writeUlong(header, 4, MOShared::GameInfo::instance().getBSAVersion()); - writeUlong(header, 12, 0x01 | 0x02); // has directories and has files. - writeUlong(header, 24, m_FolderName.length() + 1); // empty folder name - writeUlong(header, 28, m_TotalFileNameLength); // single character file name - - writeUlong(header, 32, 2); // has dds - - file.write(reinterpret_cast(header), sizeof(header)); -} - - -void DummyBSA::writeFolderRecord(QFile& file, const std::string& folderName) -{ - unsigned char folderRecord[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, // folder hash - 0x01, 0x00, 0x00, 0x00, // file count - 0xDE, 0xAD, 0xBE, 0xEF, // offset to folder name - }; - // we'd usually have to sort folders be the hash value generated here - writeUlonglong(folderRecord, 0, genHash(folderName.c_str())); - writeUlong( folderRecord, 12, 0x34 + m_TotalFileNameLength); // TODO: this should be calculated properly - - file.write(reinterpret_cast(folderRecord), sizeof(folderRecord)); -} - - -void DummyBSA::writeFileRecord(QFile& file, const std::string& fileName) -{ - unsigned char fileRecord[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, // file name hash - 0xDE, 0xAD, 0xBE, 0xEF, // size - 0xDE, 0xAD, 0xBE, 0xEF, // offset to file data - }; - - // we'd usually have to sort files by the value generated here - writeUlonglong(fileRecord, 0, genHash(fileName.c_str())); - writeUlong( fileRecord, 8, 0); - writeUlong( fileRecord, 12, 0x44 + (fileName.length() + 1) + 4); // after this record we expect the filename and 4 bytes of file size - - file.write(reinterpret_cast(fileRecord), sizeof(fileRecord)); -} - - -void DummyBSA::writeFileRecordBlocks(QFile& file, const std::string& folderName) -{ - file.write(folderName.c_str(), folderName.length() + 1); - - writeFileRecord(file, m_FileName); -} - - -void DummyBSA::write(const QString& fileName) -{ - QFile file(fileName); - file.open(QIODevice::WriteOnly); - - m_TotalFileNameLength = m_FileName.length() + 1; - - writeHeader(file); - writeFolderRecord(file, m_FolderName); - writeFileRecordBlocks(file, m_FolderName); - file.write(m_FileName.c_str() , m_FileName.length() + 1); - char fileSize[] = { 0x00, 0x00, 0x00, 0x00 }; - file.write(fileSize, sizeof(fileSize)); - file.close(); -} diff --git a/src/dummybsa.h b/src/dummybsa.h deleted file mode 100644 index 0d231393..00000000 --- a/src/dummybsa.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright (C) 2012 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 . -*/ - -#ifndef DUMMYBSA_H -#define DUMMYBSA_H - -#include -#include - -/** - * @brief Class for creating a dummy bsa used for archive invalidation - **/ -class DummyBSA -{ - -public: - - /** - * @brief constructor - * - **/ - DummyBSA(); - - /** - * @brief write to the specified file - * - * @param fileName name of the file to write to - **/ - void write(const QString& fileName); - -private: - - void writeHeader(QFile& file); - void writeFolderRecord(QFile& file, const std::string& folderName); - void writeFileRecord(QFile& file, const std::string& fileName); - void writeFileRecordBlocks(QFile& file, const std::string& folderName); - -private: - - unsigned long m_Version; - std::string m_FolderName; - std::string m_FileName; - unsigned long m_TotalFileNameLength; - -}; - - -#endif // DUMMYBSA_H diff --git a/src/loadmechanism.cpp b/src/loadmechanism.cpp index 711a7f1a..913d018c 100644 --- a/src/loadmechanism.cpp +++ b/src/loadmechanism.cpp @@ -20,7 +20,8 @@ along with Mod Organizer. If not, see . #include "loadmechanism.h" #include "utility.h" #include "util.h" -#include +#include +#include #include #include #include @@ -28,6 +29,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include using namespace MOBase; @@ -49,7 +51,7 @@ void LoadMechanism::writeHintFile(const QDir &targetDirectory) if (!hintFile.open(QIODevice::WriteOnly)) { throw MyException(QObject::tr("failed to open %1: %2").arg(hintFilePath).arg(hintFile.errorString())); } - hintFile.write(ToString(GameInfo::instance().getOrganizerDirectory(), true).c_str()); + hintFile.write(qApp->applicationDirPath().toUtf8().constData()); hintFile.close(); } @@ -62,38 +64,31 @@ void LoadMechanism::removeHintFile(QDir &targetDirectory) bool LoadMechanism::isDirectLoadingSupported() { - if (GameInfo::instance().getType() == GameInfo::TYPE_OBLIVION) { + IPluginGame *game = qApp->property("managed_game").value(); + if (game->gameName().compare("oblivion", Qt::CaseInsensitive)) { // oblivion can be loaded directly if it's not the steam variant - QString gamePath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())); - QDir gameDir(gamePath); - // test if this is the steam version of oblivion - if (QFile(gameDir.absoluteFilePath("steam_api.dll")).exists()) { - return false; - } + return !game->gameDirectory().exists("steam_api.dll"); + } else { + // all other games work afaik + return true; } - - // all other games work afaik - return true; } - bool LoadMechanism::isScriptExtenderSupported() { - QString targetPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())); - if ((QFile(targetPath.mid(0).append("/").append(ToQString(GameInfo::instance().getSEName())).append("_loader.exe")).exists()) || - (QFile(targetPath.mid(0).append("/").append(ToQString(GameInfo::instance().getSEName())).append("_steam_loader.dll")).exists())) { - return true; - } else { - return false; - } -} + IPluginGame *game = qApp->property("managed_game").value(); + ScriptExtender *extender = game->feature(); + // test if there even is an extender for the managed game and if so whether it's installed + return (extender != nullptr) + && (game->gameDirectory().exists(extender->name() + "_loader.exe") + || game->gameDirectory().exists(extender->name() + "_steam_loader.dll")); +} bool LoadMechanism::isProxyDLLSupported() { - QString targetPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())); - targetPath.append("/").append(ToQString(AppConfig::proxyDLLTarget())); - return QFile(targetPath).exists(); + IPluginGame *game = qApp->property("managed_game").value(); + return game->gameDirectory().exists(QString::fromStdWString(AppConfig::proxyDLLTarget())); } @@ -124,12 +119,13 @@ bool LoadMechanism::hashIdentical(const QString &fileNameLHS, const QString &fil void LoadMechanism::deactivateScriptExtender() { try { - QString gameDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())); - - QString pluginsDirPath = gameDirectory; - pluginsDirPath.append("/data/").append(ToQString(GameInfo::instance().getSEName())).append("/plugins"); + IPluginGame *game = qApp->property("managed_game").value(); + ScriptExtender *extender = game->feature(); + if (extender == nullptr) { + throw MyException(QObject::tr("game doesn't support a script extender")); + } - QDir pluginsDir(pluginsDirPath); + QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->name() + "/plugins"); QString hookDLLName = ToQString(AppConfig::hookDLLName()); if (QFile(pluginsDir.absoluteFilePath(hookDLLName)).exists()) { @@ -149,14 +145,13 @@ void LoadMechanism::deactivateScriptExtender() void LoadMechanism::deactivateProxyDLL() { try { - QString gameDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())); + IPluginGame *game = qApp->property("managed_game").value(); - QString targetPath = gameDirectory; - targetPath.append("/").append(ToQString(AppConfig::proxyDLLTarget())); + QString targetPath = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLTarget())); QFile targetDLL(targetPath); if (targetDLL.exists()) { - QString origFile = gameDirectory.mid(0).append(ToQString(AppConfig::proxyDLLOrig())); + QString origFile = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLOrig())); // determine if a proxy-dll is installed // this is a very crude way of making this decision but it should be good enough if ((targetDLL.size() < 24576) && (QFile(origFile).exists())) { @@ -169,8 +164,7 @@ void LoadMechanism::deactivateProxyDLL() } } - QDir dir(gameDirectory); - removeHintFile(dir); + removeHintFile(game->gameDirectory()); } catch (const std::exception &e) { QMessageBox::critical(nullptr, QObject::tr("Failed to deactivate proxy-dll loading"), e.what()); } @@ -180,19 +174,20 @@ void LoadMechanism::deactivateProxyDLL() void LoadMechanism::activateScriptExtender() { try { - QString gameDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())); - - QString pluginsDirPath = gameDirectory; - pluginsDirPath.append("/data/").append(ToQString(GameInfo::instance().getSEName())).append("/plugins"); + IPluginGame *game = qApp->property("managed_game").value(); + ScriptExtender *extender = game->feature(); + if (extender == nullptr) { + throw MyException(QObject::tr("game doesn't support a script extender")); + } - QDir pluginsDir(pluginsDirPath); + QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->name() + "/plugins"); if (!pluginsDir.exists()) { pluginsDir.mkpath("."); } QString targetPath = pluginsDir.absoluteFilePath(ToQString(AppConfig::hookDLLName())); - QString hookDLLPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())).append("/").append(ToQString(AppConfig::hookDLLName())); + QString hookDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::hookDLLName()); QFile dllFile(targetPath); @@ -219,17 +214,16 @@ void LoadMechanism::activateScriptExtender() void LoadMechanism::activateProxyDLL() { try { - QString gameDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())); + IPluginGame *game = qApp->property("managed_game").value(); + + QString targetPath = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLTarget())); - QString targetPath = gameDirectory; - targetPath.append("/").append(ToQString(AppConfig::proxyDLLTarget())); QFile targetDLL(targetPath); if (!targetDLL.exists()) { return; } - QString sourcePath = QDir::fromNativeSeparators( - ToQString(GameInfo::instance().getOrganizerDirectory())).append("/").append(ToQString(AppConfig::proxyDLLSource())); + QString sourcePath = qApp->applicationDirPath() + "/" + ToQString(AppConfig::proxyDLLSource()); // this is a very crude way of making this decision but it should be good enough if (targetDLL.size() < 24576) { @@ -246,8 +240,7 @@ void LoadMechanism::activateProxyDLL() } else { // no proxy dll installed yet. move the original and insert proxy-dll - QString origFile = gameDirectory; - origFile.append("/").append(ToQString(AppConfig::proxyDLLOrig())); + QString origFile = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLOrig())); if (QFile(origFile).exists()) { // orig-file exists. this may happen if the steam-api was updated or the user messed with the @@ -263,7 +256,7 @@ void LoadMechanism::activateProxyDLL() throw MyException(QObject::tr("Failed to copy %1 to %2").arg(sourcePath).arg(targetPath)); } } - writeHintFile(QDir(gameDirectory)); + writeHintFile(game->gameDirectory()); } catch (const std::exception &e) { QMessageBox::critical(nullptr, QObject::tr("Failed to set up proxy-dll loading"), e.what()); } diff --git a/src/main.cpp b/src/main.cpp index a048d50d..8507d725 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -406,29 +406,17 @@ int main(int argc, char *argv[]) reportError(QObject::tr("No game identified in \"%1\". The directory is required to contain " "the game binary and its launcher.").arg(gamePath)); } - SelectionDialog selection(QObject::tr("Please select the game to manage"), nullptr); - - { // add options - QString skyrimPath = ToQString(SkyrimInfo::getRegPathStatic()); - QString falloutNVPath = ToQString(FalloutNVInfo::getRegPathStatic()); - QString fallout3Path = ToQString(Fallout3Info::getRegPathStatic()); - QString oblivionPath = ToQString(OblivionInfo::getRegPathStatic()); - if (skyrimPath.length() != 0) { - selection.addChoice(QString("Skyrim"), skyrimPath, skyrimPath); - } - if (falloutNVPath.length() != 0) { - selection.addChoice(QString("Fallout NV"), falloutNVPath, falloutNVPath); - } - if (fallout3Path.length() != 0) { - selection.addChoice(QString("Fallout 3"), fallout3Path, fallout3Path); - } - if (oblivionPath.length() != 0) { - selection.addChoice(QString("Oblivion"), oblivionPath, oblivionPath); - } + SelectionDialog selection(QObject::tr("Please select the game to manage"), nullptr, QSize(32, 32)); - selection.addChoice(QString("Browse..."), QString(), QString()); + for (const IPluginGame * const game : pluginContainer.plugins()) { + if (game->isInstalled()) { + QString path = game->gameDirectory().absolutePath(); + selection.addChoice(game->gameIcon(), game->gameName(), path, path); + } } + selection.addChoice(QString("Browse..."), QString(), QString()); + if (selection.exec() == QDialog::Rejected) { gamePath = ""; done = true; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 50a07b75..1c54d250 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -60,13 +60,15 @@ along with Mod Organizer. If not, see . #include "aboutdialog.h" #include "safewritefile.h" #include "organizerproxy.h" -#include "nxmaccessmanager.h +#include "nxmaccessmanager.h" #include #include #include #include #include +#include #include +#include #include #include #include @@ -139,7 +141,7 @@ using namespace MOShared; MainWindow::MainWindow(const QString &exeName - : QMainWindow(parent), ui(new Ui::MainWindow), m_Tutorial(this, "MainWindow"), + , QSettings &initSettings , OrganizerCore &organizerCore , PluginContainer &pluginContainer , QWidget *parent) @@ -148,7 +150,7 @@ MainWindow::MainWindow(const QString &exeName , m_WasVisible(false) , m_Tutorial(this, "MainWindow") , m_ExeName(exeName) - , m_OldProfileIndex(-1), + , m_OldProfileIndex(-1) , m_ModListGroupingProxy(nullptr) , m_ModListSortProxy(nullptr) , m_OldExecutableIndex(-1) @@ -191,7 +193,7 @@ MainWindow::MainWindow(const QString &exeName updateToolBar(); - languageChange(m_Settings.language()); + TaskProgressManager::instance().tryCreateTaskbar(); // set up mod list m_ModListSortProxy = m_OrganizerCore.createModListProxyModel(); @@ -335,7 +337,7 @@ MainWindow::MainWindow(const QString &exeName // refresh profiles so the current profile can be activated refreshProfiles(false); - ui->profileBox->setCurrentText(m_OrganizerCore.currentProfile()->getName()); + ui->profileBox->setCurrentText(m_OrganizerCore.currentProfile()->name()); refreshExecutablesList(); updateToolBar(); @@ -1036,9 +1038,9 @@ void MainWindow::on_profileBox_currentIndexChanged(int index) } if (ui->profileBox->currentIndex() == 0) { - ProfilesDialog(m_GamePath, m_OrganizerCore.managedGame(), this).exec(); + ProfilesDialog(m_GamePath, this).exec(); while (!refreshProfiles()) { - ProfilesDialog(m_GamePath, m_OrganizerCore.managedGame(), this).exec(); + ProfilesDialog(m_GamePath, this).exec(); } ui->profileBox->setCurrentIndex(previousIndex); } else { @@ -1213,25 +1215,6 @@ bool MainWindow::refreshProfiles(bool selectProfile) } -#if QT_VERSION >= 0x050000 -extern QPixmap qt_pixmapFromWinHICON(HICON icon); -#else -#define qt_pixmapFromWinHICON(icon) QPixmap::fromWinHICON(icon) -#endif - -QIcon MainWindow::iconForExecutable(const QString &filePath) -{ - HICON winIcon; - UINT res = ::ExtractIconExW(ToWString(filePath).c_str(), 0, &winIcon, nullptr, 1); - if (res == 1) { - QIcon result = QIcon(qt_pixmapFromWinHICON(winIcon)); - ::DestroyIcon(winIcon); - return result; - } else { - return QIcon(":/MO/gui/executable"); - } -} - void MainWindow::refreshExecutablesList() { QComboBox* executablesList = findChild("executablesListBox"); @@ -1285,12 +1268,12 @@ void MainWindow::refreshSaveList() QDir savesDir; if (m_OrganizerCore.currentProfile()->localSavesEnabled()) { - savesDir.setPath(m_OrganizerCore.currentProfile()->getPath() + "/saves"); + savesDir.setPath(m_OrganizerCore.currentProfile()->absolutePath() + "/saves"); } else { wchar_t path[MAX_PATH]; ::GetPrivateProfileStringW(L"General", L"SLocalSavePath", L"Saves", path, MAX_PATH, - (ToWString(m_OrganizerCore.currentProfile()->getPath()) + L"\\" + GameInfo::instance().getIniFileNames().at(0)).c_str()); + (ToWString(m_OrganizerCore.currentProfile()->absolutePath()) + L"\\" + GameInfo::instance().getIniFileNames().at(0)).c_str()); savesDir.setPath(m_OrganizerCore.managedGame()->documentsDirectory().absoluteFilePath(QString::fromWCharArray(path))); } @@ -1417,42 +1400,46 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString void MainWindow::checkBSAList() { - ui->bsaList->blockSignals(true); + DataArchives *archives = m_OrganizerCore.managedGame()->feature(); - QStringList defaultArchives = m_OrganizerCore.defaultArchiveList(); + if (archives != nullptr) { + ui->bsaList->blockSignals(true); - bool warning = false; + QStringList defaultArchives = archives->archives(m_OrganizerCore.currentProfile()); - for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { - bool modWarning = false; - QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i); - for (int j = 0; j < tlItem->childCount(); ++j) { - QTreeWidgetItem *item = tlItem->child(j); - QString filename = item->text(0); - item->setIcon(0, QIcon()); - item->setToolTip(0, QString()); + bool warning = false; - if (item->checkState(0) == Qt::Unchecked) { - if (defaultArchives.contains(filename)) { - item->setIcon(0, QIcon(":/MO/gui/warning")); - item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!")); - modWarning = true; + for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { + bool modWarning = false; + QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i); + for (int j = 0; j < tlItem->childCount(); ++j) { + QTreeWidgetItem *item = tlItem->child(j); + QString filename = item->text(0); + item->setIcon(0, QIcon()); + item->setToolTip(0, QString()); + + if (item->checkState(0) == Qt::Unchecked) { + if (defaultArchives.contains(filename)) { + item->setIcon(0, QIcon(":/MO/gui/warning")); + item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!")); + modWarning = true; + } } } + if (modWarning) { + ui->bsaList->expandItem(ui->bsaList->topLevelItem(i)); + warning = true; + } } - if (modWarning) { - ui->bsaList->expandItem(ui->bsaList->topLevelItem(i)); - warning = true; + + if (warning) { + ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/warning")); + } else { + ui->tabWidget->setTabIcon(1, QIcon()); } - } - if (warning) { - ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/warning")); - } else { - ui->tabWidget->setTabIcon(1, QIcon()); + ui->bsaList->blockSignals(false); } - - ui->bsaList->blockSignals(false); } @@ -1790,7 +1777,7 @@ void MainWindow::on_actionAdd_Profile_triggered() { bool repeat = true; while (repeat) { - ProfilesDialog profilesDialog(m_GamePath, m_OrganizerCore.managedGame(), this); + ProfilesDialog profilesDialog(m_GamePath, this); profilesDialog.exec(); if (refreshProfiles() && !profilesDialog.failed()) { repeat = false; @@ -2333,10 +2320,10 @@ void MainWindow::overwriteClosed(int) void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) { - if (!m_OrganizerCore.modList()->modInfoAboutToChange(modInfo)) { - qDebug("A different mod information dialog is open. If this is incorrect, please restart MO"); - return; - } + if (!m_OrganizerCore.modList()->modInfoAboutToChange(modInfo)) { + qDebug("A different mod information dialog is open. If this is incorrect, please restart MO"); + return; + } std::vector flags = modInfo->getFlags(); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) { QDialog *dialog = this->findChild("__overwriteDialog"); @@ -3379,7 +3366,7 @@ void MainWindow::installTranslator(const QString &name) QString fileName = name + "_" + m_CurrentLanguage; if (!translator->load(fileName, qApp->applicationDirPath() + "/translations")) { if ((m_CurrentLanguage != "en-US") && (m_CurrentLanguage != "en_US")) { - qWarning("localization file %s not found", qPrintable(fileName)); + qDebug("localization file %s not found", qPrintable(fileName)); } // we don't actually expect localization files for english } @@ -3481,10 +3468,10 @@ int MainWindow::getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &bin { // try to find java automatically WCHAR buffer[MAX_PATH]; - if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { - DWORD binaryType = 0UL; - if (!::GetBinaryTypeW(buffer, &binaryType)) { - qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); + if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { + DWORD binaryType = 0UL; + if (!::GetBinaryTypeW(buffer, &binaryType)) { + qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); } else if (binaryType == SCS_32BIT_BINARY) { binaryPath = ToQString(buffer); } @@ -3659,7 +3646,7 @@ void MainWindow::openDataFile() QString arguments; switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) { case 1: { - m_OrganizerCore.spawnBinaryDirect(binaryInfo, arguments, m_OrganizerCore.currentProfile()->getName(), targetInfo.absolutePath(), ""); + m_OrganizerCore.spawnBinaryDirect(binaryInfo, arguments, m_OrganizerCore.currentProfile()->name(), targetInfo.absolutePath(), ""); } break; case 2: { ::ShellExecuteW(nullptr, L"open", ToWString(targetInfo.absoluteFilePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); @@ -4339,7 +4326,7 @@ void MainWindow::on_bossButton_clicked() createStdoutPipe(&stdOutRead, &stdOutWrite); HANDLE loot = startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"), parameters.join(" "), - m_OrganizerCore.currentProfile()->getName(), + m_OrganizerCore.currentProfile()->name(), m_OrganizerCore.settings().logLevel(), qApp->applicationDirPath() + "/loot", true, diff --git a/src/mainwindow.h b/src/mainwindow.h index b9f93cd5..d0e3aaf5 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -229,8 +229,6 @@ private: bool errorReported(QString &logFile); - QIcon iconForExecutable(const QString &filePath); - void updateESPLock(bool locked); static void setupNetworkProxy(bool activate); diff --git a/src/modinfo.cpp b/src/modinfo.cpp index b1d9bed4..3b8d6b92 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -28,8 +28,10 @@ along with Mod Organizer. If not, see . #include "messagedialog.h" #include +#include #include #include +#include #include @@ -862,7 +864,13 @@ std::vector ModInfoRegular::getContents() const if (dir.entryList(QStringList() << "*.esp" << "*.esm").size() > 0) { result.push_back(CONTENT_PLUGIN); } - QString sePluginPath = ToQString(GameInfo::instance().getSEName()) + "/plugins"; + + ScriptExtender *extender = qApp->property("managed_game").value()->feature(); + + if (extender != nullptr) { + QString sePluginPath = extender->name() + "/plugins"; + if (dir.exists(sePluginPath)) result.push_back(CONTENT_SKSE); + } if (dir.exists("textures")) result.push_back(CONTENT_TEXTURE); if (dir.exists("meshes")) result.push_back(CONTENT_MESH); if (dir.exists("interface") @@ -870,7 +878,6 @@ std::vector ModInfoRegular::getContents() const if (dir.exists("music")) result.push_back(CONTENT_MUSIC); if (dir.exists("sound")) result.push_back(CONTENT_SOUND); if (dir.exists("scripts")) result.push_back(CONTENT_SCRIPT); - if (dir.exists(sePluginPath)) result.push_back(CONTENT_SKSE); if (dir.exists("strings")) result.push_back(CONTENT_STRING); if (dir.exists("SkyProc Patchers")) result.push_back(CONTENT_SKYPROC); return result; diff --git a/src/organizer.pro b/src/organizer.pro index b67fb3e5..9300f348 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -57,7 +57,6 @@ SOURCES += \ filedialogmemory.cpp \ executableslist.cpp \ editexecutablesdialog.cpp \ - dummybsa.cpp \ downloadmanager.cpp \ downloadlistwidgetcompact.cpp \ downloadlistwidget.cpp \ @@ -137,7 +136,6 @@ HEADERS += \ filedialogmemory.h \ executableslist.h \ editexecutablesdialog.h \ - dummybsa.h \ downloadmanager.h \ downloadlistwidgetcompact.h \ downloadlistwidget.h \ @@ -257,7 +255,7 @@ LIBS += -L"E:/Visual Leak Detector/lib/Win32" #DEFINES += TEST_MODELS -INCLUDEPATH += ../shared ../archive ../uibase ../bsatk ../esptk "$${LOOTPATH}" "$${BOOSTPATH}" +INCLUDEPATH += ../shared ../archive ../uibase ../bsatk ../esptk ../plugins/gamefeatures "$${LOOTPATH}" "$${BOOSTPATH}" LIBS += -L"$${BOOSTPATH}/stage/lib" diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 936e5529..0ea3ccb1 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -11,7 +11,9 @@ #include "spawn.h" #include "safewritefile.h" #include "syncoverwritedialog.h" +#include "nxmaccessmanager.h" #include +#include #include #include #include @@ -184,7 +186,7 @@ void OrganizerCore::storeSettings() m_UserInterface->storeSettings(settings); } if (m_CurrentProfile != nullptr) { - settings.setValue("selected_profile", m_CurrentProfile->getName().toUtf8().constData()); + settings.setValue("selected_profile", m_CurrentProfile->name().toUtf8().constData()); } settings.setValue("ask_for_nexuspw", m_AskForNexusPW); @@ -368,6 +370,7 @@ void OrganizerCore::setManagedGame(const QString &gameName) m_GameName = gameName; if (m_PluginContainer != nullptr) { m_GamePlugin = m_PluginContainer->managedGame(m_GameName); + qApp->setProperty("managed_game", QVariant::fromValue(m_GamePlugin)); emit managedGameChanged(m_GamePlugin); } } @@ -473,7 +476,6 @@ InstallationManager *OrganizerCore::installationManager() void OrganizerCore::createDefaultProfile() { QString profilesPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()); - qDebug("%d", QDir(profilesPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot).size()); if (QDir(profilesPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot).size() == 0) { Profile newProf("Default", managedGame(), false); } @@ -506,7 +508,7 @@ MOBase::IModRepositoryBridge *OrganizerCore::createNexusBridge() const QString OrganizerCore::profileName() const { if (m_CurrentProfile != nullptr) { - return m_CurrentProfile->getName(); + return m_CurrentProfile->name(); } else { return ""; } @@ -515,7 +517,7 @@ QString OrganizerCore::profileName() const QString OrganizerCore::profilePath() const { if (m_CurrentProfile != nullptr) { - return m_CurrentProfile->getPath(); + return m_CurrentProfile->absolutePath(); } else { return ""; } @@ -809,7 +811,7 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &argument dialog->show(); ON_BLOCK_EXIT([&] () { dialog->hide(); dialog->deleteLater(); }); - HANDLE processHandle = spawnBinaryDirect(binary, arguments, m_CurrentProfile->getName(), currentDirectory, steamAppID); + HANDLE processHandle = spawnBinaryDirect(binary, arguments, m_CurrentProfile->name(), currentDirectory, steamAppID); if (processHandle != INVALID_HANDLE_VALUE) { if (closeAfterStart && (m_UserInterface != nullptr)) { m_UserInterface->closeWindow(); @@ -938,7 +940,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, const QStringL QString profileName = profile; if (profile.length() == 0) { if (m_CurrentProfile != nullptr) { - profileName = m_CurrentProfile->getName(); + profileName = m_CurrentProfile->name(); } else { throw MyException(tr("No profile set")); } @@ -1081,7 +1083,7 @@ void OrganizerCore::refreshESPList() // clear list try { - m_PluginList.refresh(m_CurrentProfile->getName(), + m_PluginList.refresh(m_CurrentProfile->name(), *m_DirectoryStructure, m_CurrentProfile->getPluginsFileName(), m_CurrentProfile->getLoadOrderFileName(), @@ -1091,55 +1093,34 @@ void OrganizerCore::refreshESPList() } } -QStringList OrganizerCore::defaultArchiveList() -{ - QStringList result; - wchar_t buffer[256]; - std::wstring iniFileName = ToWString(QDir::toNativeSeparators(m_CurrentProfile->getIniFileName())); - - if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().append(L"2").c_str(), - L"", buffer, 256, iniFileName.c_str()) != 0) { - result.append(ToQString(buffer).split(',')); - } - - for (int i = 0; i < result.count(); ++i) { - result[i] = result[i].trimmed(); - } - - return result; -} - void OrganizerCore::refreshBSAList() { - m_ArchivesInit = false; + DataArchives *archives = m_GamePlugin->feature(); - m_DefaultArchives = defaultArchiveList(); + if (archives != nullptr) { + m_ArchivesInit = false; - wchar_t buffer[256]; - std::wstring iniFileName = ToWString(QDir::toNativeSeparators(m_CurrentProfile->getIniFileName())); - if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(), - L"", buffer, 256, iniFileName.c_str()) != 0) { - m_DefaultArchives = ToQString(buffer).split(','); - } else { - std::vector vanillaBSAs = GameInfo::instance().getVanillaBSAs(); - for (auto iter = vanillaBSAs.begin(); iter != vanillaBSAs.end(); ++iter) { - m_DefaultArchives.append(ToQString(*iter)); + // default archives are the ones enabled outside MO. if the list can't be found (which might + // happen if ini files are missing) use hard-coded defaults (preferrably the same the game would use) + m_DefaultArchives = archives->archives(m_CurrentProfile); + if (m_DefaultArchives.length() == 0) { + m_DefaultArchives = archives->vanillaArchives(); } - } - m_ActiveArchives.clear(); + m_ActiveArchives.clear(); - auto iter = enabledArchives(); - m_ActiveArchives = toStringList(iter.begin(), iter.end()); - if (m_ActiveArchives.isEmpty()) { - m_ActiveArchives = m_DefaultArchives; - } + auto iter = enabledArchives(); + m_ActiveArchives = toStringList(iter.begin(), iter.end()); + if (m_ActiveArchives.isEmpty()) { + m_ActiveArchives = m_DefaultArchives; + } - if (m_UserInterface != nullptr) { - m_UserInterface->updateBSAList(m_DefaultArchives, m_ActiveArchives); - } + if (m_UserInterface != nullptr) { + m_UserInterface->updateBSAList(m_DefaultArchives, m_ActiveArchives); + } - m_ArchivesInit = true; + m_ArchivesInit = true; + } } void OrganizerCore::refreshLists() diff --git a/src/organizercore.h b/src/organizercore.h index 4d9b0a7c..3191e2a9 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -155,7 +155,6 @@ public: bool onAboutToRun(const std::function &func); bool onFinishedRun(const std::function &func); void refreshModList(bool saveChanges = true); - QStringList defaultArchiveList(); public: // IPluginDiagnose interface diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index ad177247..3c7af59f 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -26,6 +26,7 @@ along with Mod Organizer. If not, see . #include "modinfo.h" #include #include +#include #include #include @@ -126,16 +127,19 @@ QString PluginList::getColumnToolTip(int column) } -void PluginList::refresh(const QString &profileName, const DirectoryEntry &baseDirectory, - const QString &pluginsFile, const QString &loadOrderFile, - const QString &lockedOrderFile) +void PluginList::refresh(const QString &profileName + , const DirectoryEntry &baseDirectory + , const QString &pluginsFile + , const QString &loadOrderFile + , const QString &lockedOrderFile) { ChangeBracket layoutChange(this); m_ESPsByName.clear(); m_ESPsByPriority.clear(); m_ESPs.clear(); - std::vector primaryPlugins = GameInfo::instance().getPrimaryPlugins(); + + QStringList primaryPlugins = qApp->property("managed_game").value()->getPrimaryPlugins(); m_CurrentProfile = profileName; @@ -150,7 +154,7 @@ void PluginList::refresh(const QString &profileName, const DirectoryEntry &baseD if ((extension == "esp") || (extension == "esm")) { bool forceEnabled = Settings::instance().forceEnableCoreFiles() && - std::find(primaryPlugins.begin(), primaryPlugins.end(), ToWString(filename.toLower())) != primaryPlugins.end(); + std::find(primaryPlugins.begin(), primaryPlugins.end(), filename.toLower()) != primaryPlugins.end(); bool archive = false; try { @@ -321,11 +325,10 @@ bool PluginList::readLoadOrder(const QString &fileName) int priority = 0; - std::vector primaryPlugins = GameInfo::instance().getPrimaryPlugins(); - for (std::vector::iterator iter = primaryPlugins.begin(); - iter != primaryPlugins.end(); ++iter) { - if (availableESPs.find(ToQString(*iter)) != availableESPs.end()) { - m_ESPLoadOrder[ToQString(*iter)] = priority++; + QStringList primaryPlugins = qApp->property("managed_game").value()->getPrimaryPlugins(); + for (const QString &plugin : primaryPlugins) { + if (availableESPs.find(plugin) != availableESPs.end()) { + m_ESPLoadOrder[plugin] = priority++; } } diff --git a/src/profile.cpp b/src/profile.cpp index dd6814fd..5d31533a 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -21,7 +21,6 @@ along with Mod Organizer. If not, see . #include "report.h" #include "gameinfo.h" #include "windows_error.h" -#include "dummybsa.h" #include "modinfo.h" #include "safewritefile.h" #include @@ -29,6 +28,8 @@ along with Mod Organizer. If not, see . #include #include #include +#include +#include #include #include #include @@ -58,6 +59,7 @@ void Profile::touchFile(QString fileName) Profile::Profile(const QString &name, IPluginGame *gamePlugin, bool useDefaultSettings) : m_SaveTimer(nullptr) + , m_GamePlugin(gamePlugin) { initTimer(); QString profilesDir = qApp->property("dataPath").toString() + "/" + ToQString(AppConfig::profilesPath()); @@ -120,8 +122,9 @@ Profile::Profile(const QDir &directory, IPluginGame *gamePlugin) } -Profile::Profile(const Profile& reference) - : m_Directory(reference.m_Directory), m_SaveTimer(nullptr) +Profile::Profile(const Profile &reference) + : m_Directory(reference.m_Directory) + , m_SaveTimer(nullptr) { initTimer(); refreshModStatus(); @@ -590,35 +593,22 @@ void Profile::mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const bool Profile::invalidationActive(bool *supported) const { - if (GameInfo::instance().requiresBSAInvalidation()) { + IPluginGame *gamePlugin = qApp->property("managed_game").value(); + + BSAInvalidation *invalidation = gamePlugin->feature(); + DataArchives *dataArchives = gamePlugin->feature(); + + if ((invalidation != nullptr) && (dataArchives != nullptr)) { if (supported != nullptr) { *supported = true; } - wchar_t buffer[1024]; - std::wstring iniFileName = ToWString(QDir::toNativeSeparators(getIniFileName())); - // epic ms fail: GetPrivateProfileString uses errno (for whatever reason) to signal a fail since the return value - // has a different meaning (number of bytes copied). HOWEVER, it will not set errno to 0 if NO error occured - errno = 0; - if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(), - L"", buffer, 1024, iniFileName.c_str()) == 0) { - if (errno != 0x02) { - if (supported != nullptr) { - *supported = false; - } - return false; - } else { - QString errorMessage = tr("failed to parse ini file (%1)").arg(ToQString(iniFileName)); - throw windows_error(errorMessage.toUtf8().constData()); - } - } - QStringList archives = ToQString(buffer).split(','); - for (int i = 0; i < archives.count(); ++i) { - QString bsaName = archives.at(i).trimmed(); - if (GameInfo::instance().isInvalidationBSA(ToWString(bsaName))) { + for (const QString &archive : dataArchives->archives(this)) { + if (invalidation->isInvalidationBSA(archive)) { return true; } } + return false; } else { *supported = false; } @@ -626,85 +616,26 @@ bool Profile::invalidationActive(bool *supported) const } -void Profile::deactivateInvalidation() const +void Profile::deactivateInvalidation() { - if (GameInfo::instance().requiresBSAInvalidation()) { - wchar_t buffer[1024]; - std::wstring iniFileName = ToWString(QDir::toNativeSeparators(getIniFileName())); - errno = 0; - if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(), - L"", buffer, 1024, iniFileName.c_str()) == 0) { - if (errno == 0x02) { - QString errorMessage = tr("failed to parse ini file (%1): %2").arg(QDir::toNativeSeparators(getIniFileName())).arg(::GetLastError()); - throw windows_error(errorMessage.toUtf8().constData()); - } else { - return; - } - } - QStringList archives = ToQString(buffer).split(", "); - - for (int i = 0; i < archives.count();) { - QString bsaName = archives.at(i).trimmed(); - if (GameInfo::instance().isInvalidationBSA(ToWString(bsaName))) { - archives.removeAt(i); - } else { - ++i; - } - } + IPluginGame *gamePlugin = qApp->property("managed_game").value(); - // just to be safe... - ::SetFileAttributesW(iniFileName.c_str(), FILE_ATTRIBUTE_NORMAL); + BSAInvalidation *invalidation = gamePlugin->feature(); - if (!::WritePrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(), - ToWString(archives.join(", ").toUtf8()).c_str(), iniFileName.c_str()) || - !::WritePrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"0", iniFileName.c_str()) || - !::WritePrivateProfileStringW(L"Archive", L"SInvalidationFile", L"ArchiveInvalidation.txt", iniFileName.c_str())) { - QString errorMessage = tr("failed to modify \"%1\"").arg(ToQString(iniFileName)); - throw windows_error(errorMessage.toUtf8().constData()); - } + if (invalidation != nullptr) { + invalidation->deactivate(this); } } -void Profile::activateInvalidation(const QString& dataDirectory) const +void Profile::activateInvalidation() { - if (GameInfo::instance().requiresBSAInvalidation()) { - wchar_t buffer[1024]; - std::wstring iniFileName = ToWString(QDir::toNativeSeparators(getIniFileName())); - errno = 0; - if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(), - L"", buffer, 1024, iniFileName.c_str()) == 0) { - if (errno == 0x02) { - throw windows_error("failed to parse ini file"); - } else { - // ignore. shouldn't have gotten here anyway - return; - } - } - QStringList archives = ToQString(buffer).split(", "); - - QString invalidationBSA = ToQString(GameInfo::instance().getInvalidationBSA()); + IPluginGame *gamePlugin = qApp->property("managed_game").value(); - if (!archives.contains(invalidationBSA)) { - archives.insert(0, invalidationBSA); - } - - // just to be safe... - ::SetFileAttributesW(iniFileName.c_str(), FILE_ATTRIBUTE_NORMAL); - - if (!::WritePrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(), - ToWString(archives.join(", ").toUtf8()).c_str(), iniFileName.c_str()) || - !::WritePrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"1", iniFileName.c_str()) || - !::WritePrivateProfileStringW(L"Archive", L"SInvalidationFile", L"", iniFileName.c_str())) { - QString errorMessage = tr("failed to modify \"%1\"").arg(ToQString(iniFileName)); - throw windows_error(errorMessage.toUtf8().constData()); - } + BSAInvalidation *invalidation = gamePlugin->feature(); - QString bsaFile = dataDirectory + "/" + invalidationBSA; - if (!QFile::exists(bsaFile)) { - DummyBSA bsa; - bsa.write(bsaFile); - } + if (invalidation != nullptr) { + invalidation->activate(this); } } @@ -784,7 +715,7 @@ QString Profile::getProfileTweaks() const return QDir::cleanPath(m_Directory.absoluteFilePath(ToQString(AppConfig::profileTweakIni()))); } -QString Profile::getPath() const +QString Profile::absolutePath() const { return QDir::cleanPath(m_Directory.absolutePath()); } @@ -792,6 +723,7 @@ QString Profile::getPath() const void Profile::rename(const QString &newName) { QDir profileDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath())); - profileDir.rename(getName(), newName); + profileDir.rename(name(), newName); m_Directory = profileDir.absoluteFilePath(newName); } + diff --git a/src/profile.h b/src/profile.h index 34efd4b2..5eaa1ea1 100644 --- a/src/profile.h +++ b/src/profile.h @@ -22,7 +22,7 @@ along with Mod Organizer. If not, see . #include "modinfo.h" - +#include #include #include #include @@ -38,7 +38,7 @@ namespace MOBase { /** * @brief represents a profile **/ -class Profile : public QObject +class Profile : public QObject, public MOBase::IProfile { Q_OBJECT @@ -112,7 +112,7 @@ public: /** * @brief deactivate archive invalidation if it was active **/ - void deactivateInvalidation() const; + void deactivateInvalidation(); /** * @brief activate archive invalidation @@ -121,7 +121,7 @@ public: * @todo passing the data directory as a parameter is useless, the function should * be able to query it from GameInfo **/ - void activateInvalidation(const QString &dataDirectory) const; + void activateInvalidation(); /** * @return true if this profile uses local save games @@ -139,7 +139,7 @@ public: /** * @return name of the profile (this is identical to its directory name) **/ - QString getName() const { return m_Directory.dirName(); } + QString name() const { return m_Directory.dirName(); } /** * @return the path of the plugins file in this profile @@ -188,7 +188,7 @@ public: /** * @return path to this profile **/ - QString getPath() const; + QString absolutePath() const; void rename(const QString &newName); @@ -315,12 +315,15 @@ private: QDir m_Directory; + MOBase::IPluginGame *m_GamePlugin; + mutable QByteArray m_LastModlistHash; std::vector m_ModStatus; std::vector m_ModIndexByPriority; unsigned int m_NumRegularMods; QTimer *m_SaveTimer; + }; Q_DECLARE_METATYPE(Profile) diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index c6731041..44ee96e9 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -24,7 +24,9 @@ along with Mod Organizer. If not, see . #include "transfersavesdialog.h" #include "profileinputdialog.h" #include "mainwindow.h" -#include +#include "aboutdialog.h" +#include +#include #include #include #include @@ -40,10 +42,9 @@ using namespace MOShared; Q_DECLARE_METATYPE(Profile::Ptr) -ProfilesDialog::ProfilesDialog(const QString &gamePath, MOBase::IPluginGame *gamePlugin, QWidget *parent) +ProfilesDialog::ProfilesDialog(const QString &gamePath, QWidget *parent) : TutorableDialog("Profiles", parent) , ui(new Ui::ProfilesDialog) - , m_GamePlugin(gamePlugin) , m_GamePath(gamePath) , m_FailState(false) { @@ -61,7 +62,11 @@ ProfilesDialog::ProfilesDialog(const QString &gamePath, MOBase::IPluginGame *gam } QCheckBox *invalidationBox = findChild("invalidationBox"); - if (!GameInfo::instance().requiresBSAInvalidation()) { + + IPluginGame *game = qApp->property("managed_game").value(); + BSAInvalidation *invalidation = game->feature(); + + if (invalidation == nullptr) { invalidationBox->setToolTip(tr("Archive invalidation isn't required for this game.")); invalidationBox->setEnabled(false); } @@ -97,7 +102,7 @@ void ProfilesDialog::addItem(const QString &name) QDir profileDir(name); QListWidgetItem *newItem = new QListWidgetItem(profileDir.dirName(), m_ProfilesList); try { - newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(profileDir, m_GamePlugin)))); + newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(profileDir, qApp->property("managed_game").value())))); m_FailState = false; } catch (const std::exception& e) { reportError(tr("failed to create profile: %1").arg(e.what())); @@ -109,7 +114,7 @@ void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings) try { QListWidget *profilesList = findChild("profilesList"); QListWidgetItem *newItem = new QListWidgetItem(name, profilesList); - newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(name, m_GamePlugin, useDefaultSettings)))); + newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(name, qApp->property("managed_game").value(), useDefaultSettings)))); profilesList->addItem(newItem); m_FailState = false; } catch (const std::exception&) { @@ -123,7 +128,7 @@ void ProfilesDialog::createProfile(const QString &name, const Profile &reference try { QListWidget *profilesList = findChild("profilesList"); QListWidgetItem *newItem = new QListWidgetItem(name, profilesList); - newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(Profile::createPtrFrom(name, reference, m_GamePlugin)))); + newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(Profile::createPtrFrom(name, reference, qApp->property("managed_game").value())))); profilesList->addItem(newItem); m_FailState = false; } catch (const std::exception&) { @@ -190,7 +195,7 @@ void ProfilesDialog::on_removeProfileButton_clicked() } else { // on destruction, the profile object would write the profile.ini file again, so // we have to get rid of the it before deleting the directory - profilePath = currentProfile->getPath(); + profilePath = currentProfile->absolutePath(); } QListWidgetItem* item = profilesList->takeItem(profilesList->currentRow()); if (item != nullptr) { @@ -216,7 +221,7 @@ void ProfilesDialog::on_renameButton_clicked() while (!valid) { bool ok = false; name = QInputDialog::getText(this, tr("Rename Profile"), tr("New Name"), - QLineEdit::Normal, currentProfile->getName(), + QLineEdit::Normal, currentProfile->name(), &ok); valid = fixDirectoryName(name); if (!ok) { @@ -249,7 +254,7 @@ void ProfilesDialog::on_invalidationBox_stateChanged(int state) if (state == Qt::Unchecked) { currentProfile->deactivateInvalidation(); } else { - currentProfile->activateInvalidation(m_GamePath + "/data"); + currentProfile->activateInvalidation(); } } catch (const std::exception &e) { reportError(tr("failed to change archive invalidation state: %1").arg(e.what())); @@ -318,6 +323,6 @@ void ProfilesDialog::on_localSavesBox_stateChanged(int state) void ProfilesDialog::on_transferButton_clicked() { const Profile::Ptr currentProfile = m_ProfilesList->currentItem()->data(Qt::UserRole).value(); - TransferSavesDialog transferDialog(*currentProfile, m_GamePlugin, this); + TransferSavesDialog transferDialog(*currentProfile, qApp->property("managed_game").value(), this); transferDialog.exec(); } diff --git a/src/profilesdialog.h b/src/profilesdialog.h index 18b3932f..5cb5a449 100644 --- a/src/profilesdialog.h +++ b/src/profilesdialog.h @@ -50,7 +50,7 @@ public: * @param parent parent widget * @todo the game path could be retrieved from GameInfo just as easily **/ - explicit ProfilesDialog(const QString &gamePath, MOBase::IPluginGame *gamePlugin, QWidget *parent = 0); + explicit ProfilesDialog(const QString &gamePath, QWidget *parent = 0); ~ProfilesDialog(); /** @@ -91,7 +91,6 @@ private slots: private: Ui::ProfilesDialog *ui; - MOBase::IPluginGame *m_GamePlugin; QString m_GamePath; QListWidget *m_ProfilesList; bool m_FailState; diff --git a/src/selectiondialog.cpp b/src/selectiondialog.cpp index 1b284928..aae95f56 100644 --- a/src/selectiondialog.cpp +++ b/src/selectiondialog.cpp @@ -22,8 +22,8 @@ along with Mod Organizer. If not, see . #include -SelectionDialog::SelectionDialog(const QString &description, QWidget *parent) - : QDialog(parent), ui(new Ui::SelectionDialog), m_Choice(nullptr), m_ValidateByData(false) +SelectionDialog::SelectionDialog(const QString &description, QWidget *parent, const QSize &iconSize) + : QDialog(parent), ui(new Ui::SelectionDialog), m_Choice(nullptr), m_ValidateByData(false), m_IconSize(iconSize) { ui->setupUi(this); @@ -35,10 +35,24 @@ SelectionDialog::~SelectionDialog() delete ui; } - void SelectionDialog::addChoice(const QString &buttonText, const QString &description, const QVariant &data) { - QCommandLinkButton *button = new QCommandLinkButton(buttonText, description, ui->buttonBox); + QAbstractButton *button = new QCommandLinkButton(buttonText, description, ui->buttonBox); + if (m_IconSize.isValid()) { + button->setIconSize(m_IconSize); + } + button->setProperty("data", data); + ui->buttonBox->addButton(button, QDialogButtonBox::AcceptRole); + if (data.isValid()) m_ValidateByData = true; +} + +void SelectionDialog::addChoice(const QIcon &icon, const QString &buttonText, const QString &description, const QVariant &data) +{ + QAbstractButton *button = new QCommandLinkButton(buttonText, description, ui->buttonBox); + if (m_IconSize.isValid()) { + button->setIconSize(m_IconSize); + } + button->setIcon(icon); button->setProperty("data", data); ui->buttonBox->addButton(button, QDialogButtonBox::AcceptRole); if (data.isValid()) m_ValidateByData = true; @@ -49,7 +63,6 @@ int SelectionDialog::numChoices() const return ui->buttonBox->findChildren(QString()).count(); } - QVariant SelectionDialog::getChoiceData() { return m_Choice->property("data"); diff --git a/src/selectiondialog.h b/src/selectiondialog.h index fe148859..43ba9767 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -33,7 +33,7 @@ class SelectionDialog : public QDialog public: - explicit SelectionDialog(const QString &description, QWidget *parent = 0); + explicit SelectionDialog(const QString &description, QWidget *parent = 0, const QSize &iconSize = QSize()); ~SelectionDialog(); @@ -46,6 +46,8 @@ public: */ void addChoice(const QString &buttonText, const QString &description, const QVariant &data); + void addChoice(const QIcon &icon, const QString &buttonText, const QString &description, const QVariant &data); + int numChoices() const; QVariant getChoiceData(); @@ -62,6 +64,7 @@ private: Ui::SelectionDialog *ui; QAbstractButton *m_Choice; bool m_ValidateByData; + QSize m_IconSize; }; diff --git a/src/shared/fallout3info.cpp b/src/shared/fallout3info.cpp index c8688cc4..37238a2a 100644 --- a/src/shared/fallout3info.cpp +++ b/src/shared/fallout3info.cpp @@ -42,11 +42,6 @@ bool Fallout3Info::identifyGame(const std::wstring &searchPath) FileExists(searchPath, L"FalloutLauncher.exe"); } -unsigned long Fallout3Info::getBSAVersion() -{ - return 0x68; -} - std::wstring Fallout3Info::getRegPathStatic() { HKEY key; @@ -67,37 +62,6 @@ std::wstring Fallout3Info::getRegPathStatic() } } -std::wstring Fallout3Info::getInvalidationBSA() -{ - return L"Fallout - Invalidation.bsa"; -} - -bool Fallout3Info::isInvalidationBSA(const std::wstring &bsaName) -{ - static LPCWSTR invalidation[] = { L"Fallout - AI!.bsa", L"Fallout - Invalidation.bsa", nullptr }; - - for (int i = 0; invalidation[i] != nullptr; ++i) { - if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) { - return true; - } - } - return false; -} - -std::vector Fallout3Info::getPrimaryPlugins() -{ - return boost::assign::list_of(L"fallout3.esm"); -} - -std::vector Fallout3Info::getVanillaBSAs() -{ - return boost::assign::list_of (L"Fallout - Textures.bsa") - (L"Fallout - Meshes.bsa") - (L"Fallout - Voices.bsa") - (L"Fallout - Sound.bsa") - (L"Fallout - MenuVoices.bsa") - (L"Fallout - Misc.bsa"); -} std::vector Fallout3Info::getDLCPlugins() { @@ -125,20 +89,14 @@ std::wstring Fallout3Info::getReferenceDataFile() } -std::wstring Fallout3Info::getOMODExt() -{ - return L"fomod"; -} + std::vector Fallout3Info::getSteamVariants() const { return boost::assign::list_of(L"Regular")(L"Game Of The Year"); } -std::wstring Fallout3Info::getSEName() -{ - return L"fose"; -} + std::wstring Fallout3Info::getNexusPage(bool nmmScheme) { diff --git a/src/shared/fallout3info.h b/src/shared/fallout3info.h index 6a211d4f..1f3a381d 100644 --- a/src/shared/fallout3info.h +++ b/src/shared/fallout3info.h @@ -35,8 +35,6 @@ public: virtual ~Fallout3Info() {} - virtual unsigned long getBSAVersion(); - static std::wstring getRegPathStatic(); virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"Fallout3.exe"; } @@ -45,14 +43,38 @@ public: virtual std::wstring getGameName() const { return L"Fallout 3"; } virtual std::wstring getGameShortName() const { return L"Fallout3"; } - - virtual std::wstring getInvalidationBSA(); - - virtual bool isInvalidationBSA(const std::wstring &bsaName); - - virtual std::vector getPrimaryPlugins(); - - virtual std::vector getVanillaBSAs(); +/* + virtual std::wstring getInvalidationBSA() + { + return L"Fallout - Invalidation.bsa"; + } + + virtual bool isInvalidationBSA(const std::wstring &bsaName) + { + static LPCWSTR invalidation[] = { L"Fallout - AI!.bsa", L"Fallout - Invalidation.bsa", nullptr }; + + for (int i = 0; invalidation[i] != nullptr; ++i) { + if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) { + return true; + } + } + return false; + } + + virtual std::vector getVanillaBSAs() + { + return boost::assign::list_of (L"Fallout - Textures.bsa") + (L"Fallout - Meshes.bsa") + (L"Fallout - Voices.bsa") + (L"Fallout - Sound.bsa") + (L"Fallout - MenuVoices.bsa") + (L"Fallout - Misc.bsa"); + } + + virtual std::vector getPrimaryPlugins() + { + return boost::assign::list_of(L"fallout3.esm"); + }*/ virtual std::vector getDLCPlugins(); virtual std::vector getSavegameAttachmentExtensions(); @@ -60,12 +82,9 @@ public: virtual std::vector getIniFileNames(); virtual std::wstring getReferenceDataFile(); - virtual std::wstring getOMODExt(); virtual std::vector getSteamVariants() const; - virtual std::wstring getSEName(); - virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } diff --git a/src/shared/falloutnvinfo.cpp b/src/shared/falloutnvinfo.cpp index 8e701887..1203bd25 100644 --- a/src/shared/falloutnvinfo.cpp +++ b/src/shared/falloutnvinfo.cpp @@ -43,11 +43,6 @@ bool FalloutNVInfo::identifyGame(const std::wstring &searchPath) FileExists(searchPath, L"FalloutNVLauncher.exe"); } -unsigned long FalloutNVInfo::getBSAVersion() -{ - return 0x68; -} - std::wstring FalloutNVInfo::getRegPathStatic() { HKEY key; @@ -68,38 +63,6 @@ std::wstring FalloutNVInfo::getRegPathStatic() } } -std::wstring FalloutNVInfo::getInvalidationBSA() -{ - return L"Fallout - Invalidation.bsa"; -} - -bool FalloutNVInfo::isInvalidationBSA(const std::wstring &bsaName) -{ - static LPCWSTR invalidation[] = { L"Fallout - AI!.bsa", L"Fallout - Invalidation.bsa", nullptr }; - - for (int i = 0; invalidation[i] != nullptr; ++i) { - if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) { - return true; - } - } - return false; -} - -std::vector FalloutNVInfo::getPrimaryPlugins() -{ - return boost::assign::list_of(L"falloutnv.esm"); -} - -std::vector FalloutNVInfo::getVanillaBSAs() -{ - return boost::assign::list_of (L"Fallout - Textures.bsa") - (L"Fallout - Textures2.bsa") - (L"Fallout - Meshes.bsa") - (L"Fallout - Voices1.bsa") - (L"Fallout - Sound.bsa") - (L"Fallout - Misc.bsa"); -} - std::vector FalloutNVInfo::getDLCPlugins() { return boost::assign::list_of (L"DeadMoney.esm") @@ -129,19 +92,6 @@ std::wstring FalloutNVInfo::getReferenceDataFile() return L"Fallout - Meshes.bsa"; } - -std::wstring FalloutNVInfo::getOMODExt() -{ - return L"fomod"; -} - - -std::wstring FalloutNVInfo::getSEName() -{ - return L"nvse"; -} - - std::wstring FalloutNVInfo::getNexusPage(bool nmmScheme) { if (nmmScheme) { @@ -176,17 +126,4 @@ bool FalloutNVInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) return false; } -/* -std::vector FalloutNVInfo::getExecutables() -{ - std::vector result; - result.push_back(ExecutableInfo(L"NVSE", L"nvse_loader.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"New Vegas", L"falloutnv.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Fallout Mod Manager", L"fomm/fomm.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Construction Kit", L"geck.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"Fallout Launcher", L"FalloutNVLauncher.exe", L"", L"", DEFAULT_CLOSE)); - result.push_back(ExecutableInfo(L"BOSS", L"BOSS/BOSS.exe", L"", L"", NEVER_CLOSE)); - - return result; -}*/ } // namespace MOShared diff --git a/src/shared/falloutnvinfo.h b/src/shared/falloutnvinfo.h index 513b7218..e1a614d2 100644 --- a/src/shared/falloutnvinfo.h +++ b/src/shared/falloutnvinfo.h @@ -35,8 +35,6 @@ public: virtual ~FalloutNVInfo() {} - virtual unsigned long getBSAVersion(); - static std::wstring getRegPathStatic(); virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"FalloutNV.exe"; } @@ -48,13 +46,37 @@ public: // virtual bool requiresSteam() const { return true; } - virtual std::wstring getInvalidationBSA(); - - virtual bool isInvalidationBSA(const std::wstring &bsaName); - - virtual std::vector getPrimaryPlugins(); - - virtual std::vector getVanillaBSAs(); +/* virtual std::wstring getInvalidationBSA() + { + return L"Fallout - Invalidation.bsa"; + } + + virtual bool isInvalidationBSA(const std::wstring &bsaName) + { + static LPCWSTR invalidation[] = { L"Fallout - AI!.bsa", L"Fallout - Invalidation.bsa", nullptr }; + + for (int i = 0; invalidation[i] != nullptr; ++i) { + if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) { + return true; + } + } + return false; + } + + virtual std::vector getVanillaBSAs() + { + return boost::assign::list_of (L"Fallout - Textures.bsa") + (L"Fallout - Textures2.bsa") + (L"Fallout - Meshes.bsa") + (L"Fallout - Voices1.bsa") + (L"Fallout - Sound.bsa") + (L"Fallout - Misc.bsa"); + } + + virtual std::vector getPrimaryPlugins() + { + return boost::assign::list_of(L"falloutnv.esm"); + }*/ virtual std::vector getDLCPlugins(); virtual std::vector getSavegameAttachmentExtensions(); @@ -62,9 +84,6 @@ public: virtual std::vector getIniFileNames(); virtual std::wstring getReferenceDataFile(); - virtual std::wstring getOMODExt(); - - virtual std::wstring getSEName(); virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); diff --git a/src/shared/gameinfo.h b/src/shared/gameinfo.h index dbb935f6..77ed4d3c 100644 --- a/src/shared/gameinfo.h +++ b/src/shared/gameinfo.h @@ -28,32 +28,7 @@ along with Mod Organizer. If not, see . #include namespace MOShared { -/* -enum CloseMOStyle { - DEFAULT_CLOSE, - DEFAULT_STAY, - NEVER_CLOSE -}; -struct ExecutableInfo { - - ExecutableInfo(const std::wstring &aTitle, const std::wstring &aBinary, - const std::wstring &aArguments, const std::wstring &aWorkingDirectory, CloseMOStyle aCloseMO) - : title(aTitle), binary(aBinary), arguments(aArguments), workingDirectory(aWorkingDirectory), - closeMO(aCloseMO), steamAppID(L"") {} - ExecutableInfo(const std::wstring &aTitle, const std::wstring &aBinary, - const std::wstring &aArguments, const std::wstring &aWorkingDirectory, - CloseMOStyle aCloseMO, const std::wstring &aSteamAppID) - : title(aTitle), binary(aBinary), arguments(aArguments), workingDirectory(aWorkingDirectory), - closeMO(aCloseMO), steamAppID(aSteamAppID) {} - std::wstring title; - std::wstring binary; - std::wstring arguments; - std::wstring workingDirectory; - CloseMOStyle closeMO; - std::wstring steamAppID; -}; -*/ /** Class to manage information that depends on the used game type. The intention is to keep @@ -86,8 +61,6 @@ public: virtual std::wstring getRegPath() = 0; virtual std::wstring getBinaryName() = 0; - virtual unsigned long getBSAVersion() = 0; - virtual GameInfo::Type getType() = 0; virtual std::wstring getGameName() const = 0; @@ -98,30 +71,8 @@ public: virtual LoadOrderMechanism getLoadOrderMechanism() const { return TYPE_FILETIME; } virtual std::wstring getGameDirectory() const; - // get absolute path to the directory where omo stores its mods -/* virtual std::wstring getModsDir() const; - // get absolute path to the directory where omo stores its profiles - virtual std::wstring getProfilesDir() const; - - virtual std::wstring getIniFilename() const; - virtual std::wstring getOverwriteDir() const; - virtual std::wstring getLogDir() const; - virtual std::wstring getLootDir() const; - virtual std::wstring getTutorialDir() const;*/ - - virtual bool requiresBSAInvalidation() const { return true; } - virtual bool requiresSteam() const; - - virtual std::wstring getInvalidationBSA() = 0; - virtual bool isInvalidationBSA(const std::wstring &bsaName) = 0; - - // the key in the game's ini-file that defines the list of bsas to load - virtual std::wstring archiveListKey() = 0; - - virtual std::vector getPrimaryPlugins() = 0; - - virtual std::vector getVanillaBSAs() = 0; + virtual bool requiresSteam() const; // get a list of file extensions for additional files belonging to a save game virtual std::vector getSavegameAttachmentExtensions() = 0; @@ -134,12 +85,8 @@ public: virtual std::wstring getReferenceDataFile() = 0; - virtual std::wstring getOMODExt() = 0; - virtual std::vector getSteamVariants() const; - virtual std::wstring getSEName() = 0; - virtual std::wstring getNexusPage(bool nmmScheme = true) = 0; virtual std::wstring getNexusInfoUrl() = 0; virtual int getNexusModID() = 0; diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp index c945dcf4..16748f58 100644 --- a/src/shared/oblivioninfo.cpp +++ b/src/shared/oblivioninfo.cpp @@ -43,11 +43,6 @@ bool OblivionInfo::identifyGame(const std::wstring &searchPath) FileExists(searchPath, L"OblivionLauncher.exe"); } -unsigned long OblivionInfo::getBSAVersion() -{ - return 0x67; -} - std::wstring OblivionInfo::getRegPathStatic() { HKEY key; @@ -68,39 +63,14 @@ std::wstring OblivionInfo::getRegPathStatic() } } -std::wstring OblivionInfo::getInvalidationBSA() -{ - return L"Oblivion - Invalidation.bsa"; -} -bool OblivionInfo::isInvalidationBSA(const std::wstring &bsaName) -{ - static LPCWSTR invalidation[] = { L"Oblivion - Invalidation.bsa", L"ArchiveInvalidationInvalidated!.bsa", - L"BSARedirection.bsa", nullptr }; - for (int i = 0; invalidation[i] != nullptr; ++i) { - if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) { - return true; - } - } - return false; -} -std::vector OblivionInfo::getPrimaryPlugins() -{ - return boost::assign::list_of(L"oblivion.esm"); -} -std::vector OblivionInfo::getVanillaBSAs() -{ - return boost::assign::list_of(L"Oblivion - Meshes.bsa") - (L"Oblivion - Textures - Compressed.bsa") - (L"Oblivion - Sounds.bsa") - (L"Oblivion - Voices1.bsa") - (L"Oblivion - Voices2.bsa") - (L"Oblivion - Misc.bsa"); -} + + + std::vector OblivionInfo::getDLCPlugins() @@ -131,10 +101,7 @@ std::vector OblivionInfo::getIniFileNames() } -std::wstring OblivionInfo::getSEName() -{ - return L"obse"; -} + std::wstring OblivionInfo::getNexusPage(bool nmmScheme) @@ -175,11 +142,4 @@ std::wstring OblivionInfo::getReferenceDataFile() return L"Oblivion - Meshes.bsa"; } - -std::wstring OblivionInfo::getOMODExt() -{ - return L"omod"; -} - - } // namespace MOShared diff --git a/src/shared/oblivioninfo.h b/src/shared/oblivioninfo.h index a93f510e..87ba26ff 100644 --- a/src/shared/oblivioninfo.h +++ b/src/shared/oblivioninfo.h @@ -33,8 +33,6 @@ public: virtual ~OblivionInfo() {} - virtual unsigned long getBSAVersion(); - static std::wstring getRegPathStatic(); virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"Oblivion.exe"; } @@ -43,14 +41,40 @@ public: virtual std::wstring getGameName() const { return L"Oblivion"; } virtual std::wstring getGameShortName() const { return L"Oblivion"; } +/* + virtual std::wstring getInvalidationBSA() + { + return L"Oblivion - Invalidation.bsa"; + } + + virtual bool isInvalidationBSA(const std::wstring &bsaName) + { + static LPCWSTR invalidation[] = { L"Oblivion - Invalidation.bsa", L"ArchiveInvalidationInvalidated!.bsa", + L"BSARedirection.bsa", nullptr }; + + for (int i = 0; invalidation[i] != nullptr; ++i) { + if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) { + return true; + } + } + return false; + } + + virtual std::vector getVanillaBSAs() + { + return boost::assign::list_of(L"Oblivion - Meshes.bsa") + (L"Oblivion - Textures - Compressed.bsa") + (L"Oblivion - Sounds.bsa") + (L"Oblivion - Voices1.bsa") + (L"Oblivion - Voices2.bsa") + (L"Oblivion - Misc.bsa"); + } + + virtual std::vector getPrimaryPlugins() + { + return boost::assign::list_of(L"oblivion.esm"); + }*/ - virtual std::wstring getInvalidationBSA(); - - virtual bool isInvalidationBSA(const std::wstring &bsaName); - - virtual std::vector getPrimaryPlugins(); - - virtual std::vector getVanillaBSAs(); virtual std::vector getDLCPlugins(); virtual std::vector getSavegameAttachmentExtensions(); @@ -58,9 +82,6 @@ public: virtual std::vector getIniFileNames(); virtual std::wstring getReferenceDataFile(); - virtual std::wstring getOMODExt(); - - virtual std::wstring getSEName(); virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp index feaf88a3..f66fcef4 100644 --- a/src/shared/skyriminfo.cpp +++ b/src/shared/skyriminfo.cpp @@ -50,10 +50,7 @@ bool SkyrimInfo::identifyGame(const std::wstring &searchPath) FileExists(searchPath, L"SkyrimLauncher.exe"); } -unsigned long SkyrimInfo::getBSAVersion() -{ - return 0x68; -} + std::wstring SkyrimInfo::getRegPathStatic() @@ -76,25 +73,6 @@ std::wstring SkyrimInfo::getRegPathStatic() } } - -std::wstring SkyrimInfo::getInvalidationBSA() -{ - return L"Skyrim - Invalidation.bsa"; -} - -bool SkyrimInfo::isInvalidationBSA(const std::wstring &bsaName) -{ - static LPCWSTR invalidation[] = { L"Skyrim - Invalidation.bsa", nullptr }; - - for (int i = 0; invalidation[i] != nullptr; ++i) { - if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) { - return true; - } - } - return false; -} - - GameInfo::LoadOrderMechanism SkyrimInfo::getLoadOrderMechanism() const { std::wstring fileName = getGameDirectory() + L"\\TESV.exe"; @@ -113,27 +91,6 @@ GameInfo::LoadOrderMechanism SkyrimInfo::getLoadOrderMechanism() const } } -std::vector SkyrimInfo::getPrimaryPlugins() -{ - return boost::assign::list_of(L"skyrim.esm")(L"update.esm"); -} - -std::vector SkyrimInfo::getVanillaBSAs() -{ - return boost::assign::list_of(L"Skyrim - Misc.bsa") - (L"Skyrim - Shaders.bsa") - (L"Skyrim - Textures.bsa") - (L"HighResTexturePack01.bsa") - (L"HighResTexturePack02.bsa") - (L"HighResTexturePack03.bsa") - (L"Skyrim - Interface.bsa") - (L"Skyrim - Animations.bsa") - (L"Skyrim - Meshes.bsa") - (L"Skyrim - Sounds.bsa") - (L"Skyrim - Voices.bsa") - (L"Skyrim - VoicesExtra.bsa"); -} - std::vector SkyrimInfo::getDLCPlugins() { return boost::assign::list_of (L"Dawnguard.esm") @@ -161,17 +118,6 @@ std::wstring SkyrimInfo::getReferenceDataFile() } -std::wstring SkyrimInfo::getOMODExt() -{ - return L"fomod"; -} - -std::wstring SkyrimInfo::getSEName() -{ - return L"skse"; -} - - std::wstring SkyrimInfo::getNexusPage(bool nmmScheme) { if (nmmScheme) { diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h index bf08fb25..5951f910 100644 --- a/src/shared/skyriminfo.h +++ b/src/shared/skyriminfo.h @@ -35,8 +35,6 @@ public: virtual ~SkyrimInfo() {} - virtual unsigned long getBSAVersion(); - static std::wstring getRegPathStatic(); virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"TESV.exe"; } @@ -48,15 +46,6 @@ public: virtual LoadOrderMechanism getLoadOrderMechanism() const; - virtual bool requiresBSAInvalidation() const { return true; } - - virtual std::wstring getInvalidationBSA(); - - virtual bool isInvalidationBSA(const std::wstring &bsaName); - - virtual std::vector getPrimaryPlugins(); - - virtual std::vector getVanillaBSAs(); virtual std::vector getDLCPlugins(); virtual std::vector getSavegameAttachmentExtensions(); @@ -65,9 +54,6 @@ public: virtual std::vector getIniFileNames(); virtual std::wstring getReferenceDataFile(); - virtual std::wstring getOMODExt(); - - virtual std::wstring getSEName(); virtual std::wstring getNexusPage(bool nmmScheme = true); @@ -80,8 +66,6 @@ public: virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath); - virtual std::wstring archiveListKey() { return L"SResourceArchiveList"; } - private: SkyrimInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory); -- cgit v1.3.1