From 482f13a50b921e61d34d09f72a7fb4216efe742b Mon Sep 17 00:00:00 2001 From: Tannin Date: Mon, 8 Sep 2014 20:37:23 +0200 Subject: - re-enabled building of loot_cli and started developing against the new api - extended set of default categories - more tolerand bbcode parser - added a few colors for the bbcode parser - more fixes to qt5 compatibility - started work on ability to unloading (and thus re-loading) of plugins - names of plugins are no longer localizable (because those names are also used to store settings) - added settings to disable individual diagnosis settings - path of dependencies is now configured in a .pri file instead of environment variablees - bugfix: if the modid-input is canceled, the id was saved as -1 and wasn't re-requested from the user - bugfix: moving files with the SHFileOperation-Api didn't update the vfs correctly (still not perfect but better) - bugfix: attempt to remove the deleter-file seems to have caused error messages for some users - bugfix: fixed a couple of cases that might have caused the tutorial to hang --- src/modinfo.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/modinfo.cpp') diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 9558e03b..4ab6d142 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -569,9 +569,7 @@ void ModInfoRegular::saveMeta() metaFile.setValue("newestVersion", m_NewestVersion.canonicalString()); metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString()); metaFile.setValue("version", m_Version.canonicalString()); - if (m_NexusID != -1) { - metaFile.setValue("modid", m_NexusID); - } + metaFile.setValue("modid", m_NexusID); metaFile.setValue("notes", m_Notes); metaFile.setValue("nexusDescription", m_NexusDescription); metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate)); -- cgit v1.3.1 From d3d7e302860fb18d7c59c213c9f3cb99c8ff4efb Mon Sep 17 00:00:00 2001 From: Tannin Date: Wed, 10 Sep 2014 20:44:39 +0200 Subject: non-mo mods now have a constructed name that cannot conflict with a regular mod --- src/editexecutablesdialog.cpp | 578 ++++++------ src/modinfo.cpp | 2098 ++++++++++++++++++++--------------------- 2 files changed, 1338 insertions(+), 1338 deletions(-) (limited to 'src/modinfo.cpp') diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 0e3aa55b..fe548a9a 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -1,289 +1,289 @@ -/* -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 "editexecutablesdialog.h" -#include "ui_editexecutablesdialog.h" -#include "filedialogmemory.h" -#include -#include -#include - - -using namespace MOBase; -using namespace MOShared; - -EditExecutablesDialog::EditExecutablesDialog(const ExecutablesList &executablesList, QWidget *parent) - : TutorableDialog("EditExecutables", parent), - ui(new Ui::EditExecutablesDialog), m_CurrentItem(NULL), m_ExecutablesList(executablesList) -{ - ui->setupUi(this); - - refreshExecutablesWidget(); -} - -EditExecutablesDialog::~EditExecutablesDialog() -{ - delete ui; -} - -ExecutablesList EditExecutablesDialog::getExecutablesList() const -{ - ExecutablesList newList; - for (int i = 0; i < ui->executablesListBox->count(); ++i) { - newList.addExecutable(ui->executablesListBox->item(i)->data(Qt::UserRole).value()); - } - return newList; -} - -void EditExecutablesDialog::refreshExecutablesWidget() -{ - QListWidget *executablesWidget = findChild("executablesListBox"); - - executablesWidget->clear(); - std::vector::const_iterator current, end; - m_ExecutablesList.getExecutables(current, end); - - for(; current != end; ++current) { - QListWidgetItem *newItem = new QListWidgetItem(current->m_Title); - QVariant temp; - temp.setValue(*current); - newItem->setData(Qt::UserRole, temp); - newItem->setTextColor(current->m_Custom ? QColor(Qt::black) : QColor(Qt::darkGray)); - executablesWidget->addItem(newItem); - } - - ui->addButton->setEnabled(false); - ui->removeButton->setEnabled(false); -} - - -void EditExecutablesDialog::on_binaryEdit_textChanged(const QString &arg1) -{ - QFileInfo fileInfo(arg1); - ui->addButton->setEnabled(fileInfo.exists() && fileInfo.isFile()); -} - -void EditExecutablesDialog::resetInput() -{ - ui->binaryEdit->setText(""); - ui->titleEdit->setText(""); - ui->workingDirEdit->clear(); - ui->argumentsEdit->setText(""); - ui->appIDOverwriteEdit->clear(); - ui->overwriteAppIDBox->setChecked(false); - ui->closeCheckBox->setChecked(false); - m_CurrentItem = NULL; -} - - -void EditExecutablesDialog::saveExecutable() -{ - m_ExecutablesList.addExecutable(ui->titleEdit->text(), QDir::fromNativeSeparators(ui->binaryEdit->text()), - ui->argumentsEdit->text(), QDir::fromNativeSeparators(ui->workingDirEdit->text()), - (ui->closeCheckBox->checkState() == Qt::Checked) ? DEFAULT_CLOSE : DEFAULT_STAY, - ui->overwriteAppIDBox->isChecked() ? ui->appIDOverwriteEdit->text() : "", - true, false); -} - - -void EditExecutablesDialog::delayedRefresh() -{ - int index = ui->executablesListBox->currentIndex().row(); - resetInput(); - refreshExecutablesWidget(); - ui->executablesListBox->setCurrentRow(index); -} - - -void EditExecutablesDialog::on_addButton_clicked() -{ - saveExecutable(); - - resetInput(); - refreshExecutablesWidget(); -} - -void EditExecutablesDialog::on_browseButton_clicked() -{ - QString binaryName = FileDialogMemory::getOpenFileName("editExecutableBinary", this, - tr("Select a binary"), QString(), tr("Executable (%1)").arg("*.exe *.bat *.jar")); - - if (binaryName.endsWith(".jar", Qt::CaseInsensitive)) { - QString binaryPath; - { // try to find java automatically - std::wstring binaryNameW = ToWString(binaryName); - WCHAR buffer[MAX_PATH]; - if (::FindExecutableW(binaryNameW.c_str(), NULL, buffer) > (HINSTANCE)32) { - DWORD binaryType = 0UL; - if (!::GetBinaryTypeW(binaryNameW.c_str(), &binaryType)) { - qDebug("failed to determine binary type of \"%ls\": %lu", binaryNameW.c_str(), ::GetLastError()); - } else if (binaryType == SCS_32BIT_BINARY) { - binaryPath = ToQString(buffer); - } - } - } - if (binaryPath.isEmpty()) { - QSettings javaReg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat); - if (javaReg.contains("CurrentVersion")) { - QString currentVersion = javaReg.value("CurrentVersion").toString(); - binaryPath = javaReg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe"); - } - } - if (binaryPath.isEmpty()) { - QMessageBox::information(this, tr("Java (32-bit) required"), - tr("MO requires 32-bit java to run this application. If you already have it installed, select javaw.exe " - "from that installation as the binary.")); - } else { - ui->binaryEdit->setText(binaryPath); - } - - ui->workingDirEdit->setText(QDir::toNativeSeparators(QFileInfo(binaryName).absolutePath())); - ui->argumentsEdit->setText("-jar \"" + QDir::toNativeSeparators(binaryName) + "\""); - } else { - ui->binaryEdit->setText(QDir::toNativeSeparators(binaryName)); - } -} - -void EditExecutablesDialog::on_browseDirButton_clicked() -{ - QString dirName = FileDialogMemory::getExistingDirectory("editExecutableDirectory", this, - tr("Select a directory")); - - ui->workingDirEdit->setText(dirName); -} - -void EditExecutablesDialog::on_removeButton_clicked() -{ -// QLineEdit *binaryEdit = findChild("binaryEdit"); - - if (QMessageBox::question(this, tr("Confirm"), tr("Really remove \"%1\" from executables?").arg(ui->titleEdit->text()), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - m_ExecutablesList.remove(ui->titleEdit->text()); - } - - resetInput(); - refreshExecutablesWidget(); -} - -void EditExecutablesDialog::on_titleEdit_textChanged(const QString &arg1) -{ - QPushButton *addButton = findChild("addButton"); - QPushButton *removeButton = findChild("removeButton"); - - QListWidget *executablesWidget = findChild("executablesListBox"); - - QList existingItems = executablesWidget->findItems(arg1, Qt::MatchFixedString); - - addButton->setEnabled(arg1.length() != 0); - - if (existingItems.count() == 0) { - addButton->setText(tr("Add")); - removeButton->setEnabled(false); - } else { - // existing item. is it a custom one? - addButton->setText(tr("Modify")); - removeButton->setEnabled(true); - } -} - - -bool EditExecutablesDialog::executableChanged() -{ - if (m_CurrentItem != NULL) { - const Executable &selectedExecutable = m_CurrentItem->data(Qt::UserRole).value(); - - return selectedExecutable.m_Arguments != ui->argumentsEdit->text() - || selectedExecutable.m_SteamAppID != ui->appIDOverwriteEdit->text() - || selectedExecutable.m_WorkingDirectory != QDir::fromNativeSeparators(ui->workingDirEdit->text()) - || selectedExecutable.m_BinaryInfo.absoluteFilePath() != QDir::fromNativeSeparators(ui->binaryEdit->text()) - || (selectedExecutable.m_CloseMO == DEFAULT_CLOSE) != ui->closeCheckBox->isChecked(); - } else { - return false; - } -} - - -void EditExecutablesDialog::on_executablesListBox_currentItemChanged(QListWidgetItem *current, QListWidgetItem*) -{ - if (current == NULL) { - resetInput(); - return; - } - - if (executableChanged()) { - QMessageBox::StandardButton res = QMessageBox::question(this, tr("Save Changes?"), - tr("You made changes to the current executable, do you want to save them?"), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); - if (res == QMessageBox::Cancel) { - return; - } else if (res == QMessageBox::Yes) { - // this invalidates the item passed as a a parameter - saveExecutable(); - - QTimer::singleShot(50, this, SLOT(delayedRefresh())); - return; - } - } - - m_CurrentItem = current; - - const Executable &selectedExecutable = current->data(Qt::UserRole).value(); - - ui->titleEdit->setText(selectedExecutable.m_Title); - ui->binaryEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath())); - ui->argumentsEdit->setText(selectedExecutable.m_Arguments); - ui->workingDirEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_WorkingDirectory)); - ui->closeCheckBox->setChecked(selectedExecutable.m_CloseMO == DEFAULT_CLOSE); - if (selectedExecutable.m_CloseMO == NEVER_CLOSE) { - ui->closeCheckBox->setEnabled(false); - ui->closeCheckBox->setToolTip(tr("MO must be kept running or this application will not work correctly.")); - } else { - ui->closeCheckBox->setEnabled(true); - ui->closeCheckBox->setToolTip(tr("If checked, MO will be closed once the specified executable is run.")); - } - ui->removeButton->setEnabled(selectedExecutable.m_Custom); - ui->overwriteAppIDBox->setChecked(selectedExecutable.m_SteamAppID != 0); - if (selectedExecutable.m_SteamAppID != 0) { - ui->appIDOverwriteEdit->setText(selectedExecutable.m_SteamAppID); - } else { - ui->appIDOverwriteEdit->clear(); - } -} - - -void EditExecutablesDialog::on_overwriteAppIDBox_toggled(bool checked) -{ - ui->appIDOverwriteEdit->setEnabled(checked); -} - -void EditExecutablesDialog::on_closeButton_clicked() -{ - if (executableChanged()) { - QMessageBox::StandardButton res = QMessageBox::question(this, tr("Save Changes?"), - tr("You made changes to the current executable, do you want to save them?"), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); - if (res == QMessageBox::Cancel) { - return; - } else if (res == QMessageBox::Yes) { - saveExecutable(); - } - } - this->accept(); -} - +/* +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 "editexecutablesdialog.h" +#include "ui_editexecutablesdialog.h" +#include "filedialogmemory.h" +#include +#include +#include + + +using namespace MOBase; +using namespace MOShared; + +EditExecutablesDialog::EditExecutablesDialog(const ExecutablesList &executablesList, QWidget *parent) + : TutorableDialog("EditExecutables", parent), + ui(new Ui::EditExecutablesDialog), m_CurrentItem(NULL), m_ExecutablesList(executablesList) +{ + ui->setupUi(this); + + refreshExecutablesWidget(); +} + +EditExecutablesDialog::~EditExecutablesDialog() +{ + delete ui; +} + +ExecutablesList EditExecutablesDialog::getExecutablesList() const +{ + ExecutablesList newList; + for (int i = 0; i < ui->executablesListBox->count(); ++i) { + newList.addExecutable(ui->executablesListBox->item(i)->data(Qt::UserRole).value()); + } + return newList; +} + +void EditExecutablesDialog::refreshExecutablesWidget() +{ + QListWidget *executablesWidget = findChild("executablesListBox"); + + executablesWidget->clear(); + std::vector::const_iterator current, end; + m_ExecutablesList.getExecutables(current, end); + + for(; current != end; ++current) { + QListWidgetItem *newItem = new QListWidgetItem(current->m_Title); + QVariant temp; + temp.setValue(*current); + newItem->setData(Qt::UserRole, temp); + newItem->setTextColor(current->m_Custom ? QColor(Qt::black) : QColor(Qt::darkGray)); + executablesWidget->addItem(newItem); + } + + ui->addButton->setEnabled(false); + ui->removeButton->setEnabled(false); +} + + +void EditExecutablesDialog::on_binaryEdit_textChanged(const QString &arg1) +{ + QFileInfo fileInfo(arg1); + ui->addButton->setEnabled(fileInfo.exists() && fileInfo.isFile()); +} + +void EditExecutablesDialog::resetInput() +{ + ui->binaryEdit->setText(""); + ui->titleEdit->setText(""); + ui->workingDirEdit->clear(); + ui->argumentsEdit->setText(""); + ui->appIDOverwriteEdit->clear(); + ui->overwriteAppIDBox->setChecked(false); + ui->closeCheckBox->setChecked(false); + m_CurrentItem = NULL; +} + + +void EditExecutablesDialog::saveExecutable() +{ + m_ExecutablesList.addExecutable(ui->titleEdit->text(), QDir::fromNativeSeparators(ui->binaryEdit->text()), + ui->argumentsEdit->text(), QDir::fromNativeSeparators(ui->workingDirEdit->text()), + (ui->closeCheckBox->checkState() == Qt::Checked) ? DEFAULT_CLOSE : DEFAULT_STAY, + ui->overwriteAppIDBox->isChecked() ? ui->appIDOverwriteEdit->text() : "", + true, false); +} + + +void EditExecutablesDialog::delayedRefresh() +{ + int index = ui->executablesListBox->currentIndex().row(); + resetInput(); + refreshExecutablesWidget(); + ui->executablesListBox->setCurrentRow(index); +} + + +void EditExecutablesDialog::on_addButton_clicked() +{ + saveExecutable(); + + resetInput(); + refreshExecutablesWidget(); +} + +void EditExecutablesDialog::on_browseButton_clicked() +{ + QString binaryName = FileDialogMemory::getOpenFileName("editExecutableBinary", this, + tr("Select a binary"), QString(), tr("Executable (%1)").arg("*.exe *.bat *.jar")); + + if (binaryName.endsWith(".jar", Qt::CaseInsensitive)) { + QString binaryPath; + { // try to find java automatically + std::wstring binaryNameW = ToWString(binaryName); + WCHAR buffer[MAX_PATH]; + if (::FindExecutableW(binaryNameW.c_str(), NULL, buffer) > (HINSTANCE)32) { + DWORD binaryType = 0UL; + if (!::GetBinaryTypeW(binaryNameW.c_str(), &binaryType)) { + qDebug("failed to determine binary type of \"%ls\": %lu", binaryNameW.c_str(), ::GetLastError()); + } else if (binaryType == SCS_32BIT_BINARY) { + binaryPath = ToQString(buffer); + } + } + } + if (binaryPath.isEmpty()) { + QSettings javaReg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat); + if (javaReg.contains("CurrentVersion")) { + QString currentVersion = javaReg.value("CurrentVersion").toString(); + binaryPath = javaReg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe"); + } + } + if (binaryPath.isEmpty()) { + QMessageBox::information(this, tr("Java (32-bit) required"), + tr("MO requires 32-bit java to run this application. If you already have it installed, select javaw.exe " + "from that installation as the binary.")); + } else { + ui->binaryEdit->setText(binaryPath); + } + + ui->workingDirEdit->setText(QDir::toNativeSeparators(QFileInfo(binaryName).absolutePath())); + ui->argumentsEdit->setText("-jar \"" + QDir::toNativeSeparators(binaryName) + "\""); + } else { + ui->binaryEdit->setText(QDir::toNativeSeparators(binaryName)); + } +} + +void EditExecutablesDialog::on_browseDirButton_clicked() +{ + QString dirName = FileDialogMemory::getExistingDirectory("editExecutableDirectory", this, + tr("Select a directory")); + + ui->workingDirEdit->setText(dirName); +} + +void EditExecutablesDialog::on_removeButton_clicked() +{ +// QLineEdit *binaryEdit = findChild("binaryEdit"); + + if (QMessageBox::question(this, tr("Confirm"), tr("Really remove \"%1\" from executables?").arg(ui->titleEdit->text()), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + m_ExecutablesList.remove(ui->titleEdit->text()); + } + + resetInput(); + refreshExecutablesWidget(); +} + +void EditExecutablesDialog::on_titleEdit_textChanged(const QString &arg1) +{ + QPushButton *addButton = findChild("addButton"); + QPushButton *removeButton = findChild("removeButton"); + + QListWidget *executablesWidget = findChild("executablesListBox"); + + QList existingItems = executablesWidget->findItems(arg1, Qt::MatchFixedString); + + addButton->setEnabled(arg1.length() != 0); + + if (existingItems.count() == 0) { + addButton->setText(tr("Add")); + removeButton->setEnabled(false); + } else { + // existing item. is it a custom one? + addButton->setText(tr("Modify")); + removeButton->setEnabled(true); + } +} + + +bool EditExecutablesDialog::executableChanged() +{ + if (m_CurrentItem != NULL) { + const Executable &selectedExecutable = m_CurrentItem->data(Qt::UserRole).value(); + + return selectedExecutable.m_Arguments != ui->argumentsEdit->text() + || selectedExecutable.m_SteamAppID != ui->appIDOverwriteEdit->text() + || selectedExecutable.m_WorkingDirectory != QDir::fromNativeSeparators(ui->workingDirEdit->text()) + || selectedExecutable.m_BinaryInfo.absoluteFilePath() != QDir::fromNativeSeparators(ui->binaryEdit->text()) + || (selectedExecutable.m_CloseMO == DEFAULT_CLOSE) != ui->closeCheckBox->isChecked(); + } else { + return false; + } +} + + +void EditExecutablesDialog::on_executablesListBox_currentItemChanged(QListWidgetItem *current, QListWidgetItem*) +{ + if (current == NULL) { + resetInput(); + return; + } + + if (executableChanged()) { + QMessageBox::StandardButton res = QMessageBox::question(this, tr("Save Changes?"), + tr("You made changes to the current executable, do you want to save them?"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + if (res == QMessageBox::Cancel) { + return; + } else if (res == QMessageBox::Yes) { + // this invalidates the item passed as a a parameter + saveExecutable(); + + QTimer::singleShot(50, this, SLOT(delayedRefresh())); + return; + } + } + + m_CurrentItem = current; + + const Executable &selectedExecutable = current->data(Qt::UserRole).value(); + + ui->titleEdit->setText(selectedExecutable.m_Title); + ui->binaryEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath())); + ui->argumentsEdit->setText(selectedExecutable.m_Arguments); + ui->workingDirEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_WorkingDirectory)); + ui->closeCheckBox->setChecked(selectedExecutable.m_CloseMO == DEFAULT_CLOSE); + if (selectedExecutable.m_CloseMO == NEVER_CLOSE) { + ui->closeCheckBox->setEnabled(false); + ui->closeCheckBox->setToolTip(tr("MO must be kept running or this application will not work correctly.")); + } else { + ui->closeCheckBox->setEnabled(true); + ui->closeCheckBox->setToolTip(tr("If checked, MO will be closed once the specified executable is run.")); + } + ui->removeButton->setEnabled(selectedExecutable.m_Custom); + ui->overwriteAppIDBox->setChecked(selectedExecutable.m_SteamAppID != 0); + if (selectedExecutable.m_SteamAppID != 0) { + ui->appIDOverwriteEdit->setText(selectedExecutable.m_SteamAppID); + } else { + ui->appIDOverwriteEdit->clear(); + } +} + + +void EditExecutablesDialog::on_overwriteAppIDBox_toggled(bool checked) +{ + ui->appIDOverwriteEdit->setEnabled(checked); +} + +void EditExecutablesDialog::on_closeButton_clicked() +{ + if (executableChanged()) { + QMessageBox::StandardButton res = QMessageBox::question(this, tr("Save Changes?"), + tr("You made changes to the current executable, do you want to save them?"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + if (res == QMessageBox::Cancel) { + return; + } else if (res == QMessageBox::Yes) { + saveExecutable(); + } + } + this->accept(); +} + diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 4ab6d142..796dab71 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -1,1049 +1,1049 @@ -/* -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 "modinfo.h" -#include "utility.h" -#include "installationtester.h" -#include "categories.h" -#include "report.h" -#include "modinfodialog.h" -#include "overwriteinfodialog.h" -#include "json.h" -#include "messagedialog.h" - -#include -#include - -#include - -#include -#include -#include -#include - - -using namespace MOBase; -using namespace MOShared; - - -std::vector ModInfo::s_Collection; -std::map ModInfo::s_ModsByName; -std::map > ModInfo::s_ModsByModID; -int ModInfo::s_NextID; -QMutex ModInfo::s_Mutex(QMutex::Recursive); - -QString ModInfo::s_HiddenExt(".mohidden"); - - -static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) -{ - return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; -} - - -ModInfo::Ptr ModInfo::createFrom(const QDir &dir, DirectoryEntry **directoryStructure) -{ - QMutexLocker locker(&s_Mutex); -// int id = s_NextID++; - static QRegExp backupExp(".*backup[0-9]*"); - ModInfo::Ptr result; - if (backupExp.exactMatch(dir.dirName())) { - result = ModInfo::Ptr(new ModInfoBackup(dir, directoryStructure)); - } else { - result = ModInfo::Ptr(new ModInfoRegular(dir, directoryStructure)); - } - s_Collection.push_back(result); - return result; -} - -ModInfo::Ptr ModInfo::createFromPlugin(const QString &espName, const QStringList &bsaNames - , DirectoryEntry ** directoryStructure) -{ - QMutexLocker locker(&s_Mutex); - ModInfo::Ptr result = ModInfo::Ptr(new ModInfoForeign(espName, bsaNames, directoryStructure)); - s_Collection.push_back(result); - return result; -} - -QString ModInfo::getContentTypeName(int contentType) -{ - switch (contentType) { - case CONTENT_PLUGIN: return tr("Plugins"); - case CONTENT_TEXTURE: return tr("Textures"); - case CONTENT_MESH: return tr("Meshes"); - case CONTENT_INTERFACE: return tr("UI Changes"); - case CONTENT_MUSIC: return tr("Music"); - case CONTENT_SOUND: return tr("Sound Effects"); - case CONTENT_SCRIPT: return tr("Scripts"); - case CONTENT_SKSE: return tr("SKSE Plugins"); - case CONTENT_SKYPROC: return tr("SkyProc Tools"); - case CONTENT_STRING: return tr("Strings"); - default: throw MyException(tr("invalid content type %1").arg(contentType)); - } -} - -void ModInfo::createFromOverwrite() -{ - QMutexLocker locker(&s_Mutex); - - s_Collection.push_back(ModInfo::Ptr(new ModInfoOverwrite)); -} - -unsigned int ModInfo::getNumMods() -{ - QMutexLocker locker(&s_Mutex); - return s_Collection.size(); -} - - -ModInfo::Ptr ModInfo::getByIndex(unsigned int index) -{ - QMutexLocker locker(&s_Mutex); - - if (index >= s_Collection.size()) { - throw MyException(tr("invalid index %1").arg(index)); - } - return s_Collection[index]; -} - - -std::vector ModInfo::getByModID(int modID) -{ - QMutexLocker locker(&s_Mutex); - - auto iter = s_ModsByModID.find(modID); - if (iter == s_ModsByModID.end()) { - return std::vector(); - } - - std::vector result; - for (auto idxIter = iter->second.begin(); idxIter != iter->second.end(); ++idxIter) { - result.push_back(getByIndex(*idxIter)); - } - - return result; -} - - -bool ModInfo::removeMod(unsigned int index) -{ - QMutexLocker locker(&s_Mutex); - - if (index >= s_Collection.size()) { - throw MyException(tr("invalid index %1").arg(index)); - } - - // update the indices first - ModInfo::Ptr modInfo = s_Collection[index]; - s_ModsByName.erase(s_ModsByName.find(modInfo->name())); - - auto iter = s_ModsByModID.find(modInfo->getNexusID()); - if (iter != s_ModsByModID.end()) { - std::vector indices = iter->second; - std::remove(indices.begin(), indices.end(), index); - s_ModsByModID[modInfo->getNexusID()] = indices; - } - - // physically remove the mod directory - //TODO the return value is ignored because the indices were already removed here, so stopping - // would cause data inconsistencies. Instead we go through with the removal but the mod will show up - // again if the user refreshes - modInfo->remove(); - - // finally, remove the mod from the collection - s_Collection.erase(s_Collection.begin() + index); - - // and update the indices - updateIndices(); - return true; -} - - -unsigned int ModInfo::getIndex(const QString &name) -{ - QMutexLocker locker(&s_Mutex); - - std::map::iterator iter = s_ModsByName.find(name); - if (iter == s_ModsByName.end()) { - return UINT_MAX; - } - - return iter->second; -} - -unsigned int ModInfo::findMod(const boost::function &filter) -{ - for (unsigned int i = 0U; i < s_Collection.size(); ++i) { - if (filter(s_Collection[i])) { - return i; - } - } - return UINT_MAX; -} - - -void ModInfo::updateFromDisc(const QString &modDirectory, DirectoryEntry **directoryStructure, bool displayForeign) -{ - QMutexLocker lock(&s_Mutex); - s_Collection.clear(); - s_NextID = 0; - - { // list all directories in the mod directory and make a mod out of each - QDir mods(QDir::fromNativeSeparators(modDirectory)); - mods.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); - QDirIterator modIter(mods); - while (modIter.hasNext()) { - createFrom(QDir(modIter.next()), directoryStructure); - } - } - - { // list plugins in the data directory and make a foreign-managed mod out of each - std::vector dlcPlugins = GameInfo::instance().getDLCPlugins(); - QDir dataDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data"); - foreach (const QFileInfo &file, dataDir.entryInfoList(QStringList() << "*.esp" << "*.esm")) { - if ((file.baseName() != "Update") // hide update - && (file.baseName() != ToQString(GameInfo::instance().getGameName())) // hide the game esp - && (displayForeign // show non-dlc bundles only if the user wants them - || std::find(dlcPlugins.begin(), dlcPlugins.end(), ToWString(file.fileName())) != dlcPlugins.end())) { - QStringList archives; - foreach (const QString archiveName, dataDir.entryList(QStringList() << file.baseName() + "*.bsa")) { - archives.append(dataDir.absoluteFilePath(archiveName)); - } - - createFromPlugin(file.fileName(), archives, directoryStructure); - } - } - } - - createFromOverwrite(); - - std::sort(s_Collection.begin(), s_Collection.end(), ByName); - - updateIndices(); -} - - -void ModInfo::updateIndices() -{ - s_ModsByName.clear(); - s_ModsByModID.clear(); - QRegExp backupRegEx(".*backup[0-9]*$"); - - for (unsigned int i = 0; i < s_Collection.size(); ++i) { - QString modName = s_Collection[i]->internalName(); - int modID = s_Collection[i]->getNexusID(); - s_ModsByName[modName] = i; - s_ModsByModID[modID].push_back(i); - } -} - - -ModInfo::ModInfo() - : m_Valid(false), m_PrimaryCategory(-1) -{ -} - - -void ModInfo::checkChunkForUpdate(const std::vector &modIDs, QObject *receiver) -{ - if (modIDs.size() != 0) { - NexusInterface::instance()->requestUpdates(modIDs, receiver, QVariant(), QString()); - } -} - - -int ModInfo::checkAllForUpdate(QObject *receiver) -{ - int result = 0; - std::vector modIDs; - - modIDs.push_back(GameInfo::instance().getNexusModID()); - - for (std::vector::iterator iter = s_Collection.begin(); - iter != s_Collection.end(); ++iter) { - if ((*iter)->canBeUpdated()) { - modIDs.push_back((*iter)->getNexusID()); - if (modIDs.size() >= 255) { - checkChunkForUpdate(modIDs, receiver); - modIDs.clear(); - } - } - } - - checkChunkForUpdate(modIDs, receiver); - - return result; -} - -void ModInfo::setVersion(const VersionInfo &version) -{ - m_Version = version; -} - -bool ModInfo::hasFlag(ModInfo::EFlag flag) const -{ - std::vector flags = getFlags(); - return std::find(flags.begin(), flags.end(), flag) != flags.end(); -} - -bool ModInfo::hasContent(ModInfo::EContent content) const -{ - std::vector contents = getContents(); - return std::find(contents.begin(), contents.end(), content) != contents.end(); -} - -bool ModInfo::categorySet(int categoryID) const -{ - for (std::set::const_iterator iter = m_Categories.begin(); iter != m_Categories.end(); ++iter) { - if ((*iter == categoryID) || - (CategoryFactory::instance().isDecendantOf(*iter, categoryID))) { - return true; - } - } - - return false; -} - - -void ModInfo::testValid() -{ - m_Valid = false; - QDirIterator dirIter(absolutePath()); - while (dirIter.hasNext()) { - dirIter.next(); - if (dirIter.fileInfo().isDir()) { - if (InstallationTester::isTopLevelDirectory(dirIter.fileName())) { - m_Valid = true; - break; - } - } else { - if (InstallationTester::isTopLevelSuffix(dirIter.fileName())) { - m_Valid = true; - break; - } - } - } - - // NOTE: in Qt 4.7 it seems that QDirIterator leaves a file handle open if it is not iterated to the - // end - while (dirIter.hasNext()) { - dirIter.next(); - } -} - - -ModInfoWithConflictInfo::ModInfoWithConflictInfo(DirectoryEntry **directoryStructure) - : m_DirectoryStructure(directoryStructure) {} - -void ModInfoWithConflictInfo::clearCaches() -{ - m_LastConflictCheck = QTime(); -} - -std::vector ModInfoWithConflictInfo::getFlags() const -{ - std::vector result; - switch (isConflicted()) { - case CONFLICT_MIXED: { - result.push_back(ModInfo::FLAG_CONFLICT_MIXED); - } break; - case CONFLICT_OVERWRITE: { - result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE); - } break; - case CONFLICT_OVERWRITTEN: { - result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN); - } break; - case CONFLICT_REDUNDANT: { - result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT); - } break; - default: { /* NOP */ } - } - return result; -} - - -void ModInfoWithConflictInfo::doConflictCheck() const -{ - m_OverwriteList.clear(); - m_OverwrittenList.clear(); - bool regular = false; - - int dataID = 0; - if ((*m_DirectoryStructure)->originExists(L"data")) { - dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID(); - } - - std::wstring name = ToWString(this->name()); - if ((*m_DirectoryStructure)->originExists(name)) { - FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); - std::vector files = origin.getFiles(); - // for all files in this origin - for (auto iter = files.begin(); iter != files.end(); ++iter) { - const std::vector &alternatives = (*iter)->getAlternatives(); - if ((alternatives.size() == 0) - || (alternatives[0] == dataID)) { - // no alternatives -> no conflict - regular = true; - } else { - if ((*iter)->getOrigin() != origin.getID()) { - FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID((*iter)->getOrigin()); - unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); - m_OverwrittenList.insert(altIndex); - } - // for all non-providing alternative origins - for (auto altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) { - if ((*altIter != dataID) && (*altIter != origin.getID())) { - FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(*altIter); - unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); - if (origin.getPriority() > altOrigin.getPriority()) { - m_OverwriteList.insert(altIndex); - } else { - m_OverwrittenList.insert(altIndex); - } - } - } - } - } - } - - m_LastConflictCheck = QTime::currentTime(); - - if (!m_OverwriteList.empty() && !m_OverwrittenList.empty()) - m_CurrentConflictState = CONFLICT_MIXED; - else if (!m_OverwriteList.empty()) - m_CurrentConflictState = CONFLICT_OVERWRITE; - else if (!m_OverwrittenList.empty()) { - if (!regular) { - m_CurrentConflictState = CONFLICT_REDUNDANT; - } else { - m_CurrentConflictState = CONFLICT_OVERWRITTEN; - } - } - else m_CurrentConflictState = CONFLICT_NONE; -} - -ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isConflicted() const -{ - // this is costy so cache the result - QTime now = QTime::currentTime(); - if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) { - doConflictCheck(); - } - - return m_CurrentConflictState; -} - - -bool ModInfoWithConflictInfo::isRedundant() const -{ - std::wstring name = ToWString(this->name()); - if ((*m_DirectoryStructure)->originExists(name)) { - FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); - std::vector files = origin.getFiles(); - bool ignore = false; - for (auto iter = files.begin(); iter != files.end(); ++iter) { - if ((*iter)->getOrigin(ignore) == origin.getID()) { - return false; - } - } - return true; - } else { - return false; - } -} - - - -ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStructure) - : ModInfoWithConflictInfo(directoryStructure) - , m_Name(path.dirName()) - , m_Path(path.absolutePath()) - , m_MetaInfoChanged(false) - , m_EndorsedState(ENDORSED_UNKNOWN) -{ - testValid(); - m_CreationTime = QFileInfo(path.absolutePath()).created(); - // read out the meta-file for information - readMeta(); - - connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant)) - , this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant)) - , this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(requestFailed(int,int,QVariant,QString)) - , this, SLOT(nxmRequestFailed(int,int,QVariant,QString))); -} - - -ModInfoRegular::~ModInfoRegular() -{ - try { - saveMeta(); - } catch (const std::exception &e) { - qCritical("failed to save meta information for \"%s\": %s", - m_Name.toUtf8().constData(), e.what()); - } -} - -bool ModInfoRegular::isEmpty() const -{ - QDirIterator iter(m_Path, QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); - if (!iter.hasNext()) return true; - iter.next(); - if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; - return false; -} - - -void ModInfoRegular::readMeta() -{ - QSettings metaFile(m_Path + "/meta.ini", QSettings::IniFormat); - - m_Notes = metaFile.value("notes", "").toString(); - m_NexusID = metaFile.value("modid", -1).toInt(); - m_Version.parse(metaFile.value("version", "").toString()); - m_NewestVersion = metaFile.value("newestVersion", "").toString(); - m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString(); - m_InstallationFile = metaFile.value("installationFile", "").toString(); - m_NexusDescription = metaFile.value("nexusDescription", "").toString(); - m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate); - if (metaFile.contains("endorsed")) { - if (metaFile.value("endorsed").canConvert()) { - switch (metaFile.value("endorsed").toInt()) { - case ENDORSED_FALSE: m_EndorsedState = ENDORSED_FALSE; break; - case ENDORSED_TRUE: m_EndorsedState = ENDORSED_TRUE; break; - case ENDORSED_NEVER: m_EndorsedState = ENDORSED_NEVER; break; - default: m_EndorsedState = ENDORSED_UNKNOWN; break; - } - } else { - m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; - } - } - - QString categoriesString = metaFile.value("category", "").toString(); - - QStringList categories = categoriesString.split(',', QString::SkipEmptyParts); - for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) { - bool ok = false; - int categoryID = iter->toInt(&ok); - if (categoryID < 0) { - // ignore invalid id - continue; - } - if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) { - m_Categories.insert(categoryID); - if (iter == categories.begin()) { - m_PrimaryCategory = categoryID; - } - } - } - - m_MetaInfoChanged = false; -} - -void ModInfoRegular::saveMeta() -{ - // only write meta data if the mod directory exists - if (m_MetaInfoChanged && QFile::exists(absolutePath())) { - QSettings metaFile(absolutePath().append("/meta.ini"), QSettings::IniFormat); - if (metaFile.status() == QSettings::NoError) { - std::set temp = m_Categories; - temp.erase(m_PrimaryCategory); - metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ",")); - metaFile.setValue("newestVersion", m_NewestVersion.canonicalString()); - metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString()); - metaFile.setValue("version", m_Version.canonicalString()); - metaFile.setValue("modid", m_NexusID); - metaFile.setValue("notes", m_Notes); - metaFile.setValue("nexusDescription", m_NexusDescription); - metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate)); - if (m_EndorsedState != ENDORSED_UNKNOWN) { - metaFile.setValue("endorsed", m_EndorsedState); - } - metaFile.sync(); // sync needs to be called to ensure the file is created - - if (metaFile.status() == QSettings::NoError) { - m_MetaInfoChanged = false; - } else { - reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status())); - } - } else { - reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status())); - } - } -} - - -bool ModInfoRegular::updateAvailable() const -{ - if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { - return false; - } - return m_NewestVersion.isValid() && (m_Version < m_NewestVersion); -} - - -bool ModInfoRegular::downgradeAvailable() const -{ - if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { - return false; - } - return m_NewestVersion.isValid() && (m_NewestVersion < m_Version); -} - - -void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData) -{ - QVariantMap result = resultData.toMap(); - m_NewestVersion.parse(result["version"].toString()); - m_NexusDescription = result["description"].toString(); - if ((m_EndorsedState != ENDORSED_NEVER) && (result.contains("voted_by_user"))) { - m_EndorsedState = result["voted_by_user"].toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; - } - m_LastNexusQuery = QDateTime::currentDateTime(); - m_MetaInfoChanged = true; - saveMeta(); - emit modDetailsUpdated(true); -} - - -void ModInfoRegular::nxmEndorsementToggled(int, QVariant, QVariant resultData) -{ - m_EndorsedState = resultData.toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; - m_MetaInfoChanged = true; - saveMeta(); - emit modDetailsUpdated(true); -} - - -void ModInfoRegular::nxmRequestFailed(int, int, QVariant userData, const QString &errorMessage) -{ - QString fullMessage = errorMessage; - if (userData.canConvert() && (userData.toInt() == 1)) { - fullMessage += "\nNexus will reject endorsements within 15 Minutes of a failed attempt, the error message may be misleading."; - } - if (QApplication::activeWindow() != NULL) { - MessageDialog::showMessage(fullMessage, QApplication::activeWindow()); - } - emit modDetailsUpdated(false); -} - - -bool ModInfoRegular::updateNXMInfo() -{ - if (m_NexusID > 0) { - m_NexusBridge.requestDescription(m_NexusID, QVariant()); - return true; - } - return false; -} - - -void ModInfoRegular::setCategory(int categoryID, bool active) -{ - m_MetaInfoChanged = true; - - if (active) { - m_Categories.insert(categoryID); - if (m_PrimaryCategory == -1) { - m_PrimaryCategory = categoryID; - } - } else { - std::set::iterator iter = m_Categories.find(categoryID); - if (iter != m_Categories.end()) { - m_Categories.erase(iter); - } - if (categoryID == m_PrimaryCategory) { - if (m_Categories.size() == 0) { - m_PrimaryCategory = -1; - } else { - m_PrimaryCategory = *(m_Categories.begin()); - } - } - } -} - - -bool ModInfoRegular::setName(const QString &name) -{ - if (name.contains('/') || name.contains('\\')) { - return false; - } - - QString newPath = m_Path.mid(0).replace(m_Path.length() - m_Name.length(), m_Name.length(), name); - QDir modDir(m_Path.mid(0, m_Path.length() - m_Name.length())); - - if (m_Name.compare(name, Qt::CaseInsensitive) == 0) { - QString tempName = name; - tempName.append("_temp"); - while (modDir.exists(tempName)) { - tempName.append("_"); - } - if (!modDir.rename(m_Name, tempName)) { - return false; - } - if (!modDir.rename(tempName, name)) { - qCritical("rename to final name failed after successful rename to intermediate name"); - modDir.rename(tempName, m_Name); - return false; - } - } else { - if (!shellRename(modDir.absoluteFilePath(m_Name), modDir.absoluteFilePath(name))) { - qCritical("failed to rename mod %s (errorcode %d)", - qPrintable(name), ::GetLastError()); - return false; - } - } - - std::map::iterator nameIter = s_ModsByName.find(m_Name); - if (nameIter != s_ModsByName.end()) { - unsigned int index = nameIter->second; - s_ModsByName.erase(nameIter); - - m_Name = name; - m_Path = newPath; - - s_ModsByName[m_Name] = index; - - std::sort(s_Collection.begin(), s_Collection.end(), ByName); - updateIndices(); - } else { // otherwise mod isn't registered yet? - m_Name = name; - m_Path = newPath; - } - - return true; -} - -void ModInfoRegular::setNotes(const QString ¬es) -{ - m_Notes = notes; - m_MetaInfoChanged = true; -} - -void ModInfoRegular::setNexusID(int modID) -{ - m_NexusID = modID; - m_MetaInfoChanged = true; -} - -void ModInfoRegular::setVersion(const VersionInfo &version) -{ - m_Version = version; - m_MetaInfoChanged = true; -} - -void ModInfoRegular::setNewestVersion(const VersionInfo &version) { - m_NewestVersion = version; -} - -void ModInfoRegular::setNexusDescription(const QString &description) -{ - m_NexusDescription = description; - m_MetaInfoChanged = true; -} - -void ModInfoRegular::addNexusCategory(int categoryID) -{ - m_Categories.insert(CategoryFactory::instance().resolveNexusID(categoryID)); -} - -void ModInfoRegular::setIsEndorsed(bool endorsed) -{ - if (m_EndorsedState != ENDORSED_NEVER) { - m_EndorsedState = endorsed ? ENDORSED_TRUE : ENDORSED_FALSE; - m_MetaInfoChanged = true; - } -} - - -void ModInfoRegular::setNeverEndorse() -{ - m_EndorsedState = ENDORSED_NEVER; - m_MetaInfoChanged = true; -} - - -bool ModInfoRegular::remove() -{ - m_MetaInfoChanged = false; - return shellDelete(QStringList(absolutePath()), true); -} - -void ModInfoRegular::endorse(bool doEndorse) -{ - if (doEndorse != (m_EndorsedState == ENDORSED_TRUE)) { - m_NexusBridge.requestToggleEndorsement(getNexusID(), doEndorse, QVariant(1)); - } -} - - -QString ModInfoRegular::absolutePath() const -{ - return m_Path; -} - -void ModInfoRegular::ignoreUpdate(bool ignore) -{ - if (ignore) { - m_IgnoredVersion = m_NewestVersion; - } else { - m_IgnoredVersion.clear(); - } - m_MetaInfoChanged = true; -} - - -std::vector ModInfoRegular::getFlags() const -{ - std::vector result = ModInfoWithConflictInfo::getFlags(); - if ((m_NexusID != -1) && (endorsedState() == ENDORSED_FALSE)) { - result.push_back(ModInfo::FLAG_NOTENDORSED); - } - if (!isValid()) { - result.push_back(ModInfo::FLAG_INVALID); - } - if (m_Notes.length() != 0) { - result.push_back(ModInfo::FLAG_NOTES); - } - return result; -} - - -std::vector ModInfoRegular::getContents() const -{ - std::vector result; - QDir dir(absolutePath()); - if (dir.entryList(QStringList() << "*.esp" << "*.esm").size() > 0) { - result.push_back(CONTENT_PLUGIN); - } - QString sePluginPath = ToQString(GameInfo::instance().getSEName()) + "/plugins"; - if (dir.exists("textures")) result.push_back(CONTENT_TEXTURE); - if (dir.exists("meshes")) result.push_back(CONTENT_MESH); - if (dir.exists("interface") - || dir.exists("menus")) result.push_back(CONTENT_INTERFACE); - 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; -} - - -int ModInfoRegular::getHighlight() const -{ - return isValid() ? HIGHLIGHT_NONE: HIGHLIGHT_INVALID; -} - - -QString ModInfoRegular::getDescription() const -{ - if (!isValid()) { - return tr("%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory").arg(name()); - } else { - const std::set &categories = getCategories(); - std::wostringstream categoryString; - categoryString << ToWString(tr("Categories:
")); - CategoryFactory &categoryFactory = CategoryFactory::instance(); - for (std::set::const_iterator catIter = categories.begin(); - catIter != categories.end(); ++catIter) { - if (catIter != categories.begin()) { - categoryString << " , "; - } - categoryString << "" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << ""; - } - - return ToQString(categoryString.str()); - } -} - -QString ModInfoRegular::notes() const -{ - return m_Notes; -} - -QDateTime ModInfoRegular::creationTime() const -{ - return m_CreationTime; -} - -QString ModInfoRegular::getNexusDescription() const -{ - return m_NexusDescription; -} - -ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const -{ - return m_EndorsedState; -} - -QDateTime ModInfoRegular::getLastNexusQuery() const -{ - return m_LastNexusQuery; -} - - -QStringList ModInfoRegular::archives() const -{ - QStringList result; - QDir dir(this->absolutePath()); - foreach (const QString &archive, dir.entryList(QStringList("*.bsa"))) { - result.append(this->absolutePath() + "/" + archive); - } - return result; -} - -std::vector ModInfoRegular::getIniTweaks() const -{ - QString metaFileName = absolutePath().append("/meta.ini"); - QSettings metaFile(metaFileName, QSettings::IniFormat); - - std::vector result; - - int numTweaks = metaFile.beginReadArray("INI Tweaks"); - - if (numTweaks != 0) { - qDebug("%d active ini tweaks in %s", - numTweaks, QDir::toNativeSeparators(metaFileName).toUtf8().constData()); - } - - for (int i = 0; i < numTweaks; ++i) { - metaFile.setArrayIndex(i); - QString filename = absolutePath().append("/INI Tweaks/").append(metaFile.value("name").toString()); - result.push_back(filename); - } - metaFile.endArray(); - return result; -} - -std::vector ModInfoBackup::getFlags() const -{ - std::vector result = ModInfoRegular::getFlags(); - result.insert(result.begin(), ModInfo::FLAG_BACKUP); - return result; -} - - -QString ModInfoBackup::getDescription() const -{ - return tr("This is the backup of a mod"); -} - - -ModInfoBackup::ModInfoBackup(const QDir &path, DirectoryEntry **directoryStructure) - : ModInfoRegular(path, directoryStructure) -{ -} - - -ModInfoOverwrite::ModInfoOverwrite() - : m_StartupTime(QDateTime::currentDateTime()) -{ - testValid(); -} - - -bool ModInfoOverwrite::isEmpty() const -{ - QDirIterator iter(absolutePath(), QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); - if (!iter.hasNext()) return true; - iter.next(); - if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; - return false; -} - -QString ModInfoOverwrite::absolutePath() const -{ - return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOverwriteDir())); -} - -std::vector ModInfoOverwrite::getFlags() const -{ - std::vector result; - result.push_back(FLAG_OVERWRITE); - return result; -} - -int ModInfoOverwrite::getHighlight() const -{ - return (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; -} - -QString ModInfoOverwrite::getDescription() const -{ - return tr("This pseudo mod contains files from the virtual data tree that got " - "modified (i.e. by the construction kit)"); -} - -QStringList ModInfoOverwrite::archives() const -{ - QStringList result; - QDir dir(this->absolutePath()); - foreach (const QString &archive, dir.entryList(QStringList("*.bsa"))) { - result.append(this->absolutePath() + "/" + archive); - } - return result; -} - -const char ModInfoForeign::INT_IDENTIFIER[] = "__int__foreign"; - -QString ModInfoForeign::name() const -{ - return m_Name; -} - -QDateTime ModInfoForeign::creationTime() const -{ - return m_CreationTime; -} - -QString ModInfoForeign::absolutePath() const -{ - return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data"; -} - -std::vector ModInfoForeign::getFlags() const -{ - std::vector result = ModInfoWithConflictInfo::getFlags(); - result.push_back(FLAG_FOREIGN); - - return result; -} - -int ModInfoForeign::getHighlight() const -{ - return 0; -} - -QString ModInfoForeign::getDescription() const -{ - return tr("This pseudo mod represents content managed outside MO. It isn't modified by MO."); -} - -ModInfoForeign::ModInfoForeign(const QString &referenceFile, const QStringList &archives, - DirectoryEntry **directoryStructure) - : ModInfoWithConflictInfo(directoryStructure) - , m_ReferenceFile(referenceFile) - , m_Archives(archives) -{ - m_CreationTime = QFileInfo(referenceFile).created(); - m_Name = QFileInfo(m_ReferenceFile).baseName(); -} +/* +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 "modinfo.h" +#include "utility.h" +#include "installationtester.h" +#include "categories.h" +#include "report.h" +#include "modinfodialog.h" +#include "overwriteinfodialog.h" +#include "json.h" +#include "messagedialog.h" + +#include +#include + +#include + +#include +#include +#include +#include + + +using namespace MOBase; +using namespace MOShared; + + +std::vector ModInfo::s_Collection; +std::map ModInfo::s_ModsByName; +std::map > ModInfo::s_ModsByModID; +int ModInfo::s_NextID; +QMutex ModInfo::s_Mutex(QMutex::Recursive); + +QString ModInfo::s_HiddenExt(".mohidden"); + + +static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) +{ + return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; +} + + +ModInfo::Ptr ModInfo::createFrom(const QDir &dir, DirectoryEntry **directoryStructure) +{ + QMutexLocker locker(&s_Mutex); +// int id = s_NextID++; + static QRegExp backupExp(".*backup[0-9]*"); + ModInfo::Ptr result; + if (backupExp.exactMatch(dir.dirName())) { + result = ModInfo::Ptr(new ModInfoBackup(dir, directoryStructure)); + } else { + result = ModInfo::Ptr(new ModInfoRegular(dir, directoryStructure)); + } + s_Collection.push_back(result); + return result; +} + +ModInfo::Ptr ModInfo::createFromPlugin(const QString &espName, const QStringList &bsaNames + , DirectoryEntry ** directoryStructure) +{ + QMutexLocker locker(&s_Mutex); + ModInfo::Ptr result = ModInfo::Ptr(new ModInfoForeign(espName, bsaNames, directoryStructure)); + s_Collection.push_back(result); + return result; +} + +QString ModInfo::getContentTypeName(int contentType) +{ + switch (contentType) { + case CONTENT_PLUGIN: return tr("Plugins"); + case CONTENT_TEXTURE: return tr("Textures"); + case CONTENT_MESH: return tr("Meshes"); + case CONTENT_INTERFACE: return tr("UI Changes"); + case CONTENT_MUSIC: return tr("Music"); + case CONTENT_SOUND: return tr("Sound Effects"); + case CONTENT_SCRIPT: return tr("Scripts"); + case CONTENT_SKSE: return tr("SKSE Plugins"); + case CONTENT_SKYPROC: return tr("SkyProc Tools"); + case CONTENT_STRING: return tr("Strings"); + default: throw MyException(tr("invalid content type %1").arg(contentType)); + } +} + +void ModInfo::createFromOverwrite() +{ + QMutexLocker locker(&s_Mutex); + + s_Collection.push_back(ModInfo::Ptr(new ModInfoOverwrite)); +} + +unsigned int ModInfo::getNumMods() +{ + QMutexLocker locker(&s_Mutex); + return s_Collection.size(); +} + + +ModInfo::Ptr ModInfo::getByIndex(unsigned int index) +{ + QMutexLocker locker(&s_Mutex); + + if (index >= s_Collection.size()) { + throw MyException(tr("invalid index %1").arg(index)); + } + return s_Collection[index]; +} + + +std::vector ModInfo::getByModID(int modID) +{ + QMutexLocker locker(&s_Mutex); + + auto iter = s_ModsByModID.find(modID); + if (iter == s_ModsByModID.end()) { + return std::vector(); + } + + std::vector result; + for (auto idxIter = iter->second.begin(); idxIter != iter->second.end(); ++idxIter) { + result.push_back(getByIndex(*idxIter)); + } + + return result; +} + + +bool ModInfo::removeMod(unsigned int index) +{ + QMutexLocker locker(&s_Mutex); + + if (index >= s_Collection.size()) { + throw MyException(tr("invalid index %1").arg(index)); + } + + // update the indices first + ModInfo::Ptr modInfo = s_Collection[index]; + s_ModsByName.erase(s_ModsByName.find(modInfo->name())); + + auto iter = s_ModsByModID.find(modInfo->getNexusID()); + if (iter != s_ModsByModID.end()) { + std::vector indices = iter->second; + std::remove(indices.begin(), indices.end(), index); + s_ModsByModID[modInfo->getNexusID()] = indices; + } + + // physically remove the mod directory + //TODO the return value is ignored because the indices were already removed here, so stopping + // would cause data inconsistencies. Instead we go through with the removal but the mod will show up + // again if the user refreshes + modInfo->remove(); + + // finally, remove the mod from the collection + s_Collection.erase(s_Collection.begin() + index); + + // and update the indices + updateIndices(); + return true; +} + + +unsigned int ModInfo::getIndex(const QString &name) +{ + QMutexLocker locker(&s_Mutex); + + std::map::iterator iter = s_ModsByName.find(name); + if (iter == s_ModsByName.end()) { + return UINT_MAX; + } + + return iter->second; +} + +unsigned int ModInfo::findMod(const boost::function &filter) +{ + for (unsigned int i = 0U; i < s_Collection.size(); ++i) { + if (filter(s_Collection[i])) { + return i; + } + } + return UINT_MAX; +} + + +void ModInfo::updateFromDisc(const QString &modDirectory, DirectoryEntry **directoryStructure, bool displayForeign) +{ + QMutexLocker lock(&s_Mutex); + s_Collection.clear(); + s_NextID = 0; + + { // list all directories in the mod directory and make a mod out of each + QDir mods(QDir::fromNativeSeparators(modDirectory)); + mods.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + QDirIterator modIter(mods); + while (modIter.hasNext()) { + createFrom(QDir(modIter.next()), directoryStructure); + } + } + + { // list plugins in the data directory and make a foreign-managed mod out of each + std::vector dlcPlugins = GameInfo::instance().getDLCPlugins(); + QDir dataDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data"); + foreach (const QFileInfo &file, dataDir.entryInfoList(QStringList() << "*.esp" << "*.esm")) { + if ((file.baseName() != "Update") // hide update + && (file.baseName() != ToQString(GameInfo::instance().getGameName())) // hide the game esp + && (displayForeign // show non-dlc bundles only if the user wants them + || std::find(dlcPlugins.begin(), dlcPlugins.end(), ToWString(file.fileName())) != dlcPlugins.end())) { + QStringList archives; + foreach (const QString archiveName, dataDir.entryList(QStringList() << file.baseName() + "*.bsa")) { + archives.append(dataDir.absoluteFilePath(archiveName)); + } + + createFromPlugin(file.fileName(), archives, directoryStructure); + } + } + } + + createFromOverwrite(); + + std::sort(s_Collection.begin(), s_Collection.end(), ByName); + + updateIndices(); +} + + +void ModInfo::updateIndices() +{ + s_ModsByName.clear(); + s_ModsByModID.clear(); + QRegExp backupRegEx(".*backup[0-9]*$"); + + for (unsigned int i = 0; i < s_Collection.size(); ++i) { + QString modName = s_Collection[i]->internalName(); + int modID = s_Collection[i]->getNexusID(); + s_ModsByName[modName] = i; + s_ModsByModID[modID].push_back(i); + } +} + + +ModInfo::ModInfo() + : m_Valid(false), m_PrimaryCategory(-1) +{ +} + + +void ModInfo::checkChunkForUpdate(const std::vector &modIDs, QObject *receiver) +{ + if (modIDs.size() != 0) { + NexusInterface::instance()->requestUpdates(modIDs, receiver, QVariant(), QString()); + } +} + + +int ModInfo::checkAllForUpdate(QObject *receiver) +{ + int result = 0; + std::vector modIDs; + + modIDs.push_back(GameInfo::instance().getNexusModID()); + + for (std::vector::iterator iter = s_Collection.begin(); + iter != s_Collection.end(); ++iter) { + if ((*iter)->canBeUpdated()) { + modIDs.push_back((*iter)->getNexusID()); + if (modIDs.size() >= 255) { + checkChunkForUpdate(modIDs, receiver); + modIDs.clear(); + } + } + } + + checkChunkForUpdate(modIDs, receiver); + + return result; +} + +void ModInfo::setVersion(const VersionInfo &version) +{ + m_Version = version; +} + +bool ModInfo::hasFlag(ModInfo::EFlag flag) const +{ + std::vector flags = getFlags(); + return std::find(flags.begin(), flags.end(), flag) != flags.end(); +} + +bool ModInfo::hasContent(ModInfo::EContent content) const +{ + std::vector contents = getContents(); + return std::find(contents.begin(), contents.end(), content) != contents.end(); +} + +bool ModInfo::categorySet(int categoryID) const +{ + for (std::set::const_iterator iter = m_Categories.begin(); iter != m_Categories.end(); ++iter) { + if ((*iter == categoryID) || + (CategoryFactory::instance().isDecendantOf(*iter, categoryID))) { + return true; + } + } + + return false; +} + + +void ModInfo::testValid() +{ + m_Valid = false; + QDirIterator dirIter(absolutePath()); + while (dirIter.hasNext()) { + dirIter.next(); + if (dirIter.fileInfo().isDir()) { + if (InstallationTester::isTopLevelDirectory(dirIter.fileName())) { + m_Valid = true; + break; + } + } else { + if (InstallationTester::isTopLevelSuffix(dirIter.fileName())) { + m_Valid = true; + break; + } + } + } + + // NOTE: in Qt 4.7 it seems that QDirIterator leaves a file handle open if it is not iterated to the + // end + while (dirIter.hasNext()) { + dirIter.next(); + } +} + + +ModInfoWithConflictInfo::ModInfoWithConflictInfo(DirectoryEntry **directoryStructure) + : m_DirectoryStructure(directoryStructure) {} + +void ModInfoWithConflictInfo::clearCaches() +{ + m_LastConflictCheck = QTime(); +} + +std::vector ModInfoWithConflictInfo::getFlags() const +{ + std::vector result; + switch (isConflicted()) { + case CONFLICT_MIXED: { + result.push_back(ModInfo::FLAG_CONFLICT_MIXED); + } break; + case CONFLICT_OVERWRITE: { + result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE); + } break; + case CONFLICT_OVERWRITTEN: { + result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN); + } break; + case CONFLICT_REDUNDANT: { + result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT); + } break; + default: { /* NOP */ } + } + return result; +} + + +void ModInfoWithConflictInfo::doConflictCheck() const +{ + m_OverwriteList.clear(); + m_OverwrittenList.clear(); + bool regular = false; + + int dataID = 0; + if ((*m_DirectoryStructure)->originExists(L"data")) { + dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID(); + } + + std::wstring name = ToWString(this->name()); + if ((*m_DirectoryStructure)->originExists(name)) { + FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); + std::vector files = origin.getFiles(); + // for all files in this origin + for (auto iter = files.begin(); iter != files.end(); ++iter) { + const std::vector &alternatives = (*iter)->getAlternatives(); + if ((alternatives.size() == 0) + || (alternatives[0] == dataID)) { + // no alternatives -> no conflict + regular = true; + } else { + if ((*iter)->getOrigin() != origin.getID()) { + FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID((*iter)->getOrigin()); + unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); + m_OverwrittenList.insert(altIndex); + } + // for all non-providing alternative origins + for (auto altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) { + if ((*altIter != dataID) && (*altIter != origin.getID())) { + FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(*altIter); + unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); + if (origin.getPriority() > altOrigin.getPriority()) { + m_OverwriteList.insert(altIndex); + } else { + m_OverwrittenList.insert(altIndex); + } + } + } + } + } + } + + m_LastConflictCheck = QTime::currentTime(); + + if (!m_OverwriteList.empty() && !m_OverwrittenList.empty()) + m_CurrentConflictState = CONFLICT_MIXED; + else if (!m_OverwriteList.empty()) + m_CurrentConflictState = CONFLICT_OVERWRITE; + else if (!m_OverwrittenList.empty()) { + if (!regular) { + m_CurrentConflictState = CONFLICT_REDUNDANT; + } else { + m_CurrentConflictState = CONFLICT_OVERWRITTEN; + } + } + else m_CurrentConflictState = CONFLICT_NONE; +} + +ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isConflicted() const +{ + // this is costy so cache the result + QTime now = QTime::currentTime(); + if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) { + doConflictCheck(); + } + + return m_CurrentConflictState; +} + + +bool ModInfoWithConflictInfo::isRedundant() const +{ + std::wstring name = ToWString(this->name()); + if ((*m_DirectoryStructure)->originExists(name)) { + FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); + std::vector files = origin.getFiles(); + bool ignore = false; + for (auto iter = files.begin(); iter != files.end(); ++iter) { + if ((*iter)->getOrigin(ignore) == origin.getID()) { + return false; + } + } + return true; + } else { + return false; + } +} + + + +ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStructure) + : ModInfoWithConflictInfo(directoryStructure) + , m_Name(path.dirName()) + , m_Path(path.absolutePath()) + , m_MetaInfoChanged(false) + , m_EndorsedState(ENDORSED_UNKNOWN) +{ + testValid(); + m_CreationTime = QFileInfo(path.absolutePath()).created(); + // read out the meta-file for information + readMeta(); + + connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant)) + , this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant))); + connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant)) + , this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant))); + connect(&m_NexusBridge, SIGNAL(requestFailed(int,int,QVariant,QString)) + , this, SLOT(nxmRequestFailed(int,int,QVariant,QString))); +} + + +ModInfoRegular::~ModInfoRegular() +{ + try { + saveMeta(); + } catch (const std::exception &e) { + qCritical("failed to save meta information for \"%s\": %s", + m_Name.toUtf8().constData(), e.what()); + } +} + +bool ModInfoRegular::isEmpty() const +{ + QDirIterator iter(m_Path, QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + if (!iter.hasNext()) return true; + iter.next(); + if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; + return false; +} + + +void ModInfoRegular::readMeta() +{ + QSettings metaFile(m_Path + "/meta.ini", QSettings::IniFormat); + + m_Notes = metaFile.value("notes", "").toString(); + m_NexusID = metaFile.value("modid", -1).toInt(); + m_Version.parse(metaFile.value("version", "").toString()); + m_NewestVersion = metaFile.value("newestVersion", "").toString(); + m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString(); + m_InstallationFile = metaFile.value("installationFile", "").toString(); + m_NexusDescription = metaFile.value("nexusDescription", "").toString(); + m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate); + if (metaFile.contains("endorsed")) { + if (metaFile.value("endorsed").canConvert()) { + switch (metaFile.value("endorsed").toInt()) { + case ENDORSED_FALSE: m_EndorsedState = ENDORSED_FALSE; break; + case ENDORSED_TRUE: m_EndorsedState = ENDORSED_TRUE; break; + case ENDORSED_NEVER: m_EndorsedState = ENDORSED_NEVER; break; + default: m_EndorsedState = ENDORSED_UNKNOWN; break; + } + } else { + m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; + } + } + + QString categoriesString = metaFile.value("category", "").toString(); + + QStringList categories = categoriesString.split(',', QString::SkipEmptyParts); + for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) { + bool ok = false; + int categoryID = iter->toInt(&ok); + if (categoryID < 0) { + // ignore invalid id + continue; + } + if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) { + m_Categories.insert(categoryID); + if (iter == categories.begin()) { + m_PrimaryCategory = categoryID; + } + } + } + + m_MetaInfoChanged = false; +} + +void ModInfoRegular::saveMeta() +{ + // only write meta data if the mod directory exists + if (m_MetaInfoChanged && QFile::exists(absolutePath())) { + QSettings metaFile(absolutePath().append("/meta.ini"), QSettings::IniFormat); + if (metaFile.status() == QSettings::NoError) { + std::set temp = m_Categories; + temp.erase(m_PrimaryCategory); + metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ",")); + metaFile.setValue("newestVersion", m_NewestVersion.canonicalString()); + metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString()); + metaFile.setValue("version", m_Version.canonicalString()); + metaFile.setValue("modid", m_NexusID); + metaFile.setValue("notes", m_Notes); + metaFile.setValue("nexusDescription", m_NexusDescription); + metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate)); + if (m_EndorsedState != ENDORSED_UNKNOWN) { + metaFile.setValue("endorsed", m_EndorsedState); + } + metaFile.sync(); // sync needs to be called to ensure the file is created + + if (metaFile.status() == QSettings::NoError) { + m_MetaInfoChanged = false; + } else { + reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status())); + } + } else { + reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status())); + } + } +} + + +bool ModInfoRegular::updateAvailable() const +{ + if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { + return false; + } + return m_NewestVersion.isValid() && (m_Version < m_NewestVersion); +} + + +bool ModInfoRegular::downgradeAvailable() const +{ + if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { + return false; + } + return m_NewestVersion.isValid() && (m_NewestVersion < m_Version); +} + + +void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData) +{ + QVariantMap result = resultData.toMap(); + m_NewestVersion.parse(result["version"].toString()); + m_NexusDescription = result["description"].toString(); + if ((m_EndorsedState != ENDORSED_NEVER) && (result.contains("voted_by_user"))) { + m_EndorsedState = result["voted_by_user"].toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; + } + m_LastNexusQuery = QDateTime::currentDateTime(); + m_MetaInfoChanged = true; + saveMeta(); + emit modDetailsUpdated(true); +} + + +void ModInfoRegular::nxmEndorsementToggled(int, QVariant, QVariant resultData) +{ + m_EndorsedState = resultData.toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; + m_MetaInfoChanged = true; + saveMeta(); + emit modDetailsUpdated(true); +} + + +void ModInfoRegular::nxmRequestFailed(int, int, QVariant userData, const QString &errorMessage) +{ + QString fullMessage = errorMessage; + if (userData.canConvert() && (userData.toInt() == 1)) { + fullMessage += "\nNexus will reject endorsements within 15 Minutes of a failed attempt, the error message may be misleading."; + } + if (QApplication::activeWindow() != NULL) { + MessageDialog::showMessage(fullMessage, QApplication::activeWindow()); + } + emit modDetailsUpdated(false); +} + + +bool ModInfoRegular::updateNXMInfo() +{ + if (m_NexusID > 0) { + m_NexusBridge.requestDescription(m_NexusID, QVariant()); + return true; + } + return false; +} + + +void ModInfoRegular::setCategory(int categoryID, bool active) +{ + m_MetaInfoChanged = true; + + if (active) { + m_Categories.insert(categoryID); + if (m_PrimaryCategory == -1) { + m_PrimaryCategory = categoryID; + } + } else { + std::set::iterator iter = m_Categories.find(categoryID); + if (iter != m_Categories.end()) { + m_Categories.erase(iter); + } + if (categoryID == m_PrimaryCategory) { + if (m_Categories.size() == 0) { + m_PrimaryCategory = -1; + } else { + m_PrimaryCategory = *(m_Categories.begin()); + } + } + } +} + + +bool ModInfoRegular::setName(const QString &name) +{ + if (name.contains('/') || name.contains('\\')) { + return false; + } + + QString newPath = m_Path.mid(0).replace(m_Path.length() - m_Name.length(), m_Name.length(), name); + QDir modDir(m_Path.mid(0, m_Path.length() - m_Name.length())); + + if (m_Name.compare(name, Qt::CaseInsensitive) == 0) { + QString tempName = name; + tempName.append("_temp"); + while (modDir.exists(tempName)) { + tempName.append("_"); + } + if (!modDir.rename(m_Name, tempName)) { + return false; + } + if (!modDir.rename(tempName, name)) { + qCritical("rename to final name failed after successful rename to intermediate name"); + modDir.rename(tempName, m_Name); + return false; + } + } else { + if (!shellRename(modDir.absoluteFilePath(m_Name), modDir.absoluteFilePath(name))) { + qCritical("failed to rename mod %s (errorcode %d)", + qPrintable(name), ::GetLastError()); + return false; + } + } + + std::map::iterator nameIter = s_ModsByName.find(m_Name); + if (nameIter != s_ModsByName.end()) { + unsigned int index = nameIter->second; + s_ModsByName.erase(nameIter); + + m_Name = name; + m_Path = newPath; + + s_ModsByName[m_Name] = index; + + std::sort(s_Collection.begin(), s_Collection.end(), ByName); + updateIndices(); + } else { // otherwise mod isn't registered yet? + m_Name = name; + m_Path = newPath; + } + + return true; +} + +void ModInfoRegular::setNotes(const QString ¬es) +{ + m_Notes = notes; + m_MetaInfoChanged = true; +} + +void ModInfoRegular::setNexusID(int modID) +{ + m_NexusID = modID; + m_MetaInfoChanged = true; +} + +void ModInfoRegular::setVersion(const VersionInfo &version) +{ + m_Version = version; + m_MetaInfoChanged = true; +} + +void ModInfoRegular::setNewestVersion(const VersionInfo &version) { + m_NewestVersion = version; +} + +void ModInfoRegular::setNexusDescription(const QString &description) +{ + m_NexusDescription = description; + m_MetaInfoChanged = true; +} + +void ModInfoRegular::addNexusCategory(int categoryID) +{ + m_Categories.insert(CategoryFactory::instance().resolveNexusID(categoryID)); +} + +void ModInfoRegular::setIsEndorsed(bool endorsed) +{ + if (m_EndorsedState != ENDORSED_NEVER) { + m_EndorsedState = endorsed ? ENDORSED_TRUE : ENDORSED_FALSE; + m_MetaInfoChanged = true; + } +} + + +void ModInfoRegular::setNeverEndorse() +{ + m_EndorsedState = ENDORSED_NEVER; + m_MetaInfoChanged = true; +} + + +bool ModInfoRegular::remove() +{ + m_MetaInfoChanged = false; + return shellDelete(QStringList(absolutePath()), true); +} + +void ModInfoRegular::endorse(bool doEndorse) +{ + if (doEndorse != (m_EndorsedState == ENDORSED_TRUE)) { + m_NexusBridge.requestToggleEndorsement(getNexusID(), doEndorse, QVariant(1)); + } +} + + +QString ModInfoRegular::absolutePath() const +{ + return m_Path; +} + +void ModInfoRegular::ignoreUpdate(bool ignore) +{ + if (ignore) { + m_IgnoredVersion = m_NewestVersion; + } else { + m_IgnoredVersion.clear(); + } + m_MetaInfoChanged = true; +} + + +std::vector ModInfoRegular::getFlags() const +{ + std::vector result = ModInfoWithConflictInfo::getFlags(); + if ((m_NexusID != -1) && (endorsedState() == ENDORSED_FALSE)) { + result.push_back(ModInfo::FLAG_NOTENDORSED); + } + if (!isValid()) { + result.push_back(ModInfo::FLAG_INVALID); + } + if (m_Notes.length() != 0) { + result.push_back(ModInfo::FLAG_NOTES); + } + return result; +} + + +std::vector ModInfoRegular::getContents() const +{ + std::vector result; + QDir dir(absolutePath()); + if (dir.entryList(QStringList() << "*.esp" << "*.esm").size() > 0) { + result.push_back(CONTENT_PLUGIN); + } + QString sePluginPath = ToQString(GameInfo::instance().getSEName()) + "/plugins"; + if (dir.exists("textures")) result.push_back(CONTENT_TEXTURE); + if (dir.exists("meshes")) result.push_back(CONTENT_MESH); + if (dir.exists("interface") + || dir.exists("menus")) result.push_back(CONTENT_INTERFACE); + 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; +} + + +int ModInfoRegular::getHighlight() const +{ + return isValid() ? HIGHLIGHT_NONE: HIGHLIGHT_INVALID; +} + + +QString ModInfoRegular::getDescription() const +{ + if (!isValid()) { + return tr("%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory").arg(name()); + } else { + const std::set &categories = getCategories(); + std::wostringstream categoryString; + categoryString << ToWString(tr("Categories:
")); + CategoryFactory &categoryFactory = CategoryFactory::instance(); + for (std::set::const_iterator catIter = categories.begin(); + catIter != categories.end(); ++catIter) { + if (catIter != categories.begin()) { + categoryString << " , "; + } + categoryString << "" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << ""; + } + + return ToQString(categoryString.str()); + } +} + +QString ModInfoRegular::notes() const +{ + return m_Notes; +} + +QDateTime ModInfoRegular::creationTime() const +{ + return m_CreationTime; +} + +QString ModInfoRegular::getNexusDescription() const +{ + return m_NexusDescription; +} + +ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const +{ + return m_EndorsedState; +} + +QDateTime ModInfoRegular::getLastNexusQuery() const +{ + return m_LastNexusQuery; +} + + +QStringList ModInfoRegular::archives() const +{ + QStringList result; + QDir dir(this->absolutePath()); + foreach (const QString &archive, dir.entryList(QStringList("*.bsa"))) { + result.append(this->absolutePath() + "/" + archive); + } + return result; +} + +std::vector ModInfoRegular::getIniTweaks() const +{ + QString metaFileName = absolutePath().append("/meta.ini"); + QSettings metaFile(metaFileName, QSettings::IniFormat); + + std::vector result; + + int numTweaks = metaFile.beginReadArray("INI Tweaks"); + + if (numTweaks != 0) { + qDebug("%d active ini tweaks in %s", + numTweaks, QDir::toNativeSeparators(metaFileName).toUtf8().constData()); + } + + for (int i = 0; i < numTweaks; ++i) { + metaFile.setArrayIndex(i); + QString filename = absolutePath().append("/INI Tweaks/").append(metaFile.value("name").toString()); + result.push_back(filename); + } + metaFile.endArray(); + return result; +} + +std::vector ModInfoBackup::getFlags() const +{ + std::vector result = ModInfoRegular::getFlags(); + result.insert(result.begin(), ModInfo::FLAG_BACKUP); + return result; +} + + +QString ModInfoBackup::getDescription() const +{ + return tr("This is the backup of a mod"); +} + + +ModInfoBackup::ModInfoBackup(const QDir &path, DirectoryEntry **directoryStructure) + : ModInfoRegular(path, directoryStructure) +{ +} + + +ModInfoOverwrite::ModInfoOverwrite() + : m_StartupTime(QDateTime::currentDateTime()) +{ + testValid(); +} + + +bool ModInfoOverwrite::isEmpty() const +{ + QDirIterator iter(absolutePath(), QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + if (!iter.hasNext()) return true; + iter.next(); + if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; + return false; +} + +QString ModInfoOverwrite::absolutePath() const +{ + return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOverwriteDir())); +} + +std::vector ModInfoOverwrite::getFlags() const +{ + std::vector result; + result.push_back(FLAG_OVERWRITE); + return result; +} + +int ModInfoOverwrite::getHighlight() const +{ + return (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; +} + +QString ModInfoOverwrite::getDescription() const +{ + return tr("This pseudo mod contains files from the virtual data tree that got " + "modified (i.e. by the construction kit)"); +} + +QStringList ModInfoOverwrite::archives() const +{ + QStringList result; + QDir dir(this->absolutePath()); + foreach (const QString &archive, dir.entryList(QStringList("*.bsa"))) { + result.append(this->absolutePath() + "/" + archive); + } + return result; +} + +const char ModInfoForeign::INT_IDENTIFIER[] = "__int__foreign"; + +QString ModInfoForeign::name() const +{ + return m_Name; +} + +QDateTime ModInfoForeign::creationTime() const +{ + return m_CreationTime; +} + +QString ModInfoForeign::absolutePath() const +{ + return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data"; +} + +std::vector ModInfoForeign::getFlags() const +{ + std::vector result = ModInfoWithConflictInfo::getFlags(); + result.push_back(FLAG_FOREIGN); + + return result; +} + +int ModInfoForeign::getHighlight() const +{ + return 0; +} + +QString ModInfoForeign::getDescription() const +{ + return tr("This pseudo mod represents content managed outside MO. It isn't modified by MO."); +} + +ModInfoForeign::ModInfoForeign(const QString &referenceFile, const QStringList &archives, + DirectoryEntry **directoryStructure) + : ModInfoWithConflictInfo(directoryStructure) + , m_ReferenceFile(referenceFile) + , m_Archives(archives) +{ + m_CreationTime = QFileInfo(referenceFile).created(); + m_Name = tr("Unmanaged") + ": " + QFileInfo(m_ReferenceFile).baseName(); +} -- cgit v1.3.1 From 93bd29c13d3355b2544c2fd40dff1f4f985f9b57 Mon Sep 17 00:00:00 2001 From: Tannin Date: Wed, 24 Sep 2014 19:51:51 +0200 Subject: - several style fixes suggested by static analysis - will now support up to 4 levels of version numbers (major.minor.subminor.subsubminor --- src/browserdialog.cpp | 2 +- src/categories.cpp | 8 +++--- src/installationmanager.h | 2 +- src/main.cpp | 11 +++----- src/mainwindow.cpp | 55 +++++++++++++++++++--------------------- src/modinfo.cpp | 2 +- src/modlist.cpp | 8 ++++-- src/modlist.h | 2 +- src/modlistsortproxy.cpp | 2 +- src/nexusinterface.cpp | 5 +++- src/pluginlist.cpp | 50 ++++++++++++++++++------------------- src/profile.cpp | 4 ++- src/selfupdater.h | 3 ++- src/settings.cpp | 2 +- src/shared/directoryentry.cpp | 6 ++--- src/shared/directoryentry.h | 2 +- src/shared/fallout3info.cpp | 21 ++++++++-------- src/shared/fallout3info.h | 6 ++--- src/shared/falloutnvinfo.cpp | 58 +++++++++++++++++++------------------------ src/shared/falloutnvinfo.h | 6 ++--- src/shared/gameinfo.cpp | 40 ++++++++--------------------- src/shared/leaktrace.cpp | 2 +- src/shared/oblivioninfo.cpp | 21 ++++++++-------- src/shared/oblivioninfo.h | 6 ++--- src/shared/skyriminfo.cpp | 53 ++++++++++++++++++--------------------- src/shared/skyriminfo.h | 8 +++--- 26 files changed, 176 insertions(+), 209 deletions(-) (limited to 'src/modinfo.cpp') diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp index 521459d0..f93ffcae 100644 --- a/src/browserdialog.cpp +++ b/src/browserdialog.cpp @@ -22,10 +22,10 @@ along with Mod Organizer. If not, see . #include "messagedialog.h" #include "report.h" -#include "json.h" #include "persistentcookiejar.h" #include +#include "json.h" #include #include diff --git a/src/categories.cpp b/src/categories.cpp index 28b1f4a2..57e18a28 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -232,7 +232,7 @@ void CategoryFactory::loadDefaultCategories() int CategoryFactory::getParentID(unsigned int index) const { - if ((index < 0) || (index >= m_Categories.size())) { + if (index >= m_Categories.size()) { throw MyException(QObject::tr("invalid index %1").arg(index)); } @@ -267,7 +267,7 @@ bool CategoryFactory::isDecendantOf(int id, int parentID) const bool CategoryFactory::hasChildren(unsigned int index) const { - if ((index < 0) || (index >= m_Categories.size())) { + if (index >= m_Categories.size()) { throw MyException(QObject::tr("invalid index %1").arg(index)); } @@ -277,7 +277,7 @@ bool CategoryFactory::hasChildren(unsigned int index) const QString CategoryFactory::getCategoryName(unsigned int index) const { - if ((index < 0) || (index >= m_Categories.size())) { + if (index >= m_Categories.size()) { throw MyException(QObject::tr("invalid index %1").arg(index)); } @@ -287,7 +287,7 @@ QString CategoryFactory::getCategoryName(unsigned int index) const int CategoryFactory::getCategoryID(unsigned int index) const { - if ((index < 0) || (index >= m_Categories.size())) { + if (index >= m_Categories.size()) { throw MyException(QObject::tr("invalid index %1").arg(index)); } diff --git a/src/installationmanager.h b/src/installationmanager.h index d430c065..336c1ce3 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -55,7 +55,7 @@ public: **/ explicit InstallationManager(QWidget *parent); - ~InstallationManager(); + virtual ~InstallationManager(); /** * @brief update the directory where mods are to be installed diff --git a/src/main.cpp b/src/main.cpp index 3198208a..642bfa1a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -455,14 +455,9 @@ int main(int argc, char *argv[]) settings.setValue("gamePath", gamePath.toUtf8().constData()); } - int edition = 0; - if (settings.contains("game_edition")) { - edition = settings.value("game_edition").toInt(); - } else { + if (!settings.contains("game_edition")) { std::vector editions = GameInfo::instance().getSteamVariants(); - if (editions.size() < 2) { - edition = 0; - } else { + if (editions.size() > 1) { SelectionDialog selection(QObject::tr("Please select the game edition you have (MO can't start the game correctly if this is set incorrectly!)"), NULL); int index = 0; for (auto iter = editions.begin(); iter != editions.end(); ++iter) { @@ -475,7 +470,7 @@ int main(int argc, char *argv[]) } } } - +#pragma message("edition isn't used?") qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(gamePath))); ExecutablesList executablesList; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ae5c1e48..19be758e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1137,7 +1137,6 @@ void MainWindow::registerPluginTool(IPluginTool *tool) void MainWindow::registerModPage(IPluginModPage *modPage) { - QToolButton *browserBtn = NULL; // turn the browser action into a drop-down menu if necessary if (ui->actionNexus->menu() == NULL) { QAction *nexusAction = ui->actionNexus; @@ -1147,10 +1146,8 @@ void MainWindow::registerModPage(IPluginModPage *modPage) ui->toolBar->removeAction(nexusAction); actionToToolButton(ui->actionNexus); - browserBtn = qobject_cast(ui->toolBar->widgetForAction(ui->actionNexus)); + QToolButton *browserBtn = qobject_cast(ui->toolBar->widgetForAction(ui->actionNexus)); browserBtn->menu()->addAction(nexusAction); - } else { - browserBtn = qobject_cast(ui->toolBar->widgetForAction(ui->actionNexus)); } QAction *action = new QAction(modPage->icon(), modPage->displayName(), ui->toolBar); @@ -1434,30 +1431,32 @@ void MainWindow::spawnBinary(const QFileInfo &binary, const QString &arguments, DWORD retLen; JOBOBJECT_BASIC_PROCESS_ID_LIST info; - bool isJobHandle = true; + { + bool isJobHandle = true; - DWORD res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); - while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0) && !dialog->unlockClicked()) { - if (isJobHandle) { - if (::QueryInformationJobObject(processHandle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { - if (info.NumberOfProcessIdsInList == 0) { - break; - } - } 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; + DWORD res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); + while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0) && !dialog->unlockClicked()) { + if (isJobHandle) { + if (::QueryInformationJobObject(processHandle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { + if (info.NumberOfProcessIdsInList == 0) { + break; + } + } 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(); + // keep processing events so the app doesn't appear dead + QCoreApplication::processEvents(); - res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); + res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); + } } ::CloseHandle(processHandle); @@ -2191,11 +2190,7 @@ void MainWindow::storeSettings() QSettings::Status result = QSettings::NoError; { QSettings settings(iniFile + ".new", QSettings::IniFormat); - if (m_CurrentProfile != NULL) { - settings.setValue("selected_profile", m_CurrentProfile->getName().toUtf8().constData()); - } else { - settings.remove("selected_profile"); - } + settings.setValue("selected_profile", m_CurrentProfile->getName().toUtf8().constData()); settings.setValue("mod_list_state", ui->modList->header()->saveState()); settings.setValue("plugin_list_state", ui->espList->header()->saveState()); @@ -5560,11 +5555,11 @@ void MainWindow::on_bossButton_clicked() DWORD retLen; JOBOBJECT_BASIC_PROCESS_ID_LIST info; - bool isJobHandle = true; - ULONG lastProcessID; HANDLE processHandle = loot; if (loot != INVALID_HANDLE_VALUE) { + bool isJobHandle = true; + ULONG lastProcessID; DWORD res = ::MsgWaitForMultipleObjects(1, &loot, false, 1000, QS_KEY | QS_MOUSE); while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) { if (isJobHandle) { diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 796dab71..189e67b2 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -156,7 +156,7 @@ bool ModInfo::removeMod(unsigned int index) auto iter = s_ModsByModID.find(modInfo->getNexusID()); if (iter != s_ModsByModID.end()) { std::vector indices = iter->second; - std::remove(indices.begin(), indices.end(), index); + indices.erase(std::remove(indices.begin(), indices.end(), index), indices.end()); s_ModsByModID[modInfo->getNexusID()] = indices; } diff --git a/src/modlist.cpp b/src/modlist.cpp index eedf1ec6..fb8df15e 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -49,8 +49,12 @@ using namespace MOBase; ModList::ModList(QObject *parent) - : QAbstractItemModel(parent), m_Profile(NULL), m_Modified(false), - m_FontMetrics(QFont()), m_DropOnItems(false) + : QAbstractItemModel(parent) + , m_Profile(NULL) + , m_NexusInterface(NULL) + , m_Modified(false) + , m_FontMetrics(QFont()) + , m_DropOnItems(false) { m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(QIcon(":/MO/gui/content/plugin"), ":/MO/gui/content/plugin", tr("Game plugins (esp/esm)")); m_ContentIcons[ModInfo::CONTENT_INTERFACE] = std::make_tuple(QIcon(":/MO/gui/content/interface"), ":/MO/gui/content/interface", tr("Interface")); diff --git a/src/modlist.h b/src/modlist.h index 632689c6..cf52b2ec 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -267,7 +267,7 @@ private: struct TModInfo { TModInfo(unsigned int index, ModInfo::Ptr modInfo) - : modInfo(modInfo), nameOrder(index) {} + : modInfo(modInfo), nameOrder(index), priorityOrder(0), modIDOrder(0), categoryOrder(0) {} ModInfo::Ptr modInfo; unsigned int nameOrder; unsigned int priorityOrder; diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index da5d99d5..8907e712 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -298,7 +298,7 @@ bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const } break; case CategoryFactory::CATEGORY_SPECIAL_NOTENDORSED: { ModInfo::EEndorsedState state = info->endorsedState(); - if ((state == ModInfo::ENDORSED_FALSE) && (state != ModInfo::ENDORSED_NEVER)) return true; + if ((state == ModInfo::ENDORSED_FALSE) || (state == ModInfo::ENDORSED_NEVER)) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_MANAGED: { if (!info->hasFlag(ModInfo::FLAG_FOREIGN)) return true; diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 30221f4b..b4006097 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -20,7 +20,7 @@ along with Mod Organizer. If not, see . #include "nexusinterface.h" #include "nxmaccessmanager.h" #include "utility.h" -#include +#include "json.h" #include "selectiondialog.h" #include #include @@ -580,6 +580,7 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID , m_URL(url) , m_SubModule(subModule) , m_NexusGameID(nexusGameId) + , m_Endorse(false) {} NexusInterface::NXMRequestInfo::NXMRequestInfo(std::vector modIDList @@ -600,6 +601,7 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(std::vector modIDList , m_URL(url) , m_SubModule(subModule) , m_NexusGameID(nexusGameId) + , m_Endorse(false) {} NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID @@ -620,4 +622,5 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID , m_URL(url) , m_SubModule(subModule) , m_NexusGameID(nexusGameId) + , m_Endorse(false) {} diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index ff370fa4..973e3cfc 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -685,7 +685,7 @@ QString PluginList::origin(const QString &name) const { auto iter = m_ESPsByName.find(name.toLower()); if (iter == m_ESPsByName.end()) { - return false; + return QString(); } else { return m_ESPs[iter->second].m_OriginName; } @@ -836,7 +836,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const std::set_difference(m_ESPs[index].m_Masters.begin(), m_ESPs[index].m_Masters.end(), m_ESPs[index].m_MasterUnset.begin(), m_ESPs[index].m_MasterUnset.end(), std::inserter(enabledMasters, enabledMasters.end())); - if (enabledMasters.size() > 0) { + if (!enabledMasters.empty()) { text += "
" + tr("Enabled Masters") + ": " + SetJoin(enabledMasters, ", "); } if (m_ESPs[index].m_HasIni) { @@ -1102,34 +1102,34 @@ bool PluginList::eventFilter(QObject *obj, QEvent *event) ((keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down))) { QItemSelectionModel *selectionModel = itemView->selectionModel(); const QSortFilterProxyModel *proxyModel = qobject_cast(selectionModel->model()); - int diff = -1; - if (((keyEvent->key() == Qt::Key_Up) && (proxyModel->sortOrder() == Qt::DescendingOrder)) || - ((keyEvent->key() == Qt::Key_Down) && (proxyModel->sortOrder() == Qt::AscendingOrder))) { - diff = 1; - } - QModelIndexList rows = selectionModel->selectedRows(); - // remove elements that aren't supposed to be movable - QMutableListIterator iter(rows); - while (iter.hasNext()) { - if ((iter.next().flags() & Qt::ItemIsDragEnabled) == 0) { - iter.remove(); + if (proxyModel != NULL) { + int diff = -1; + if (((keyEvent->key() == Qt::Key_Up) && (proxyModel->sortOrder() == Qt::DescendingOrder)) || + ((keyEvent->key() == Qt::Key_Down) && (proxyModel->sortOrder() == Qt::AscendingOrder))) { + diff = 1; } - } - if (keyEvent->key() == Qt::Key_Down) { - for (int i = 0; i < rows.size() / 2; ++i) { - rows.swap(i, rows.size() - i - 1); + QModelIndexList rows = selectionModel->selectedRows(); + // remove elements that aren't supposed to be movable + QMutableListIterator iter(rows); + while (iter.hasNext()) { + if ((iter.next().flags() & Qt::ItemIsDragEnabled) == 0) { + iter.remove(); + } } - } - foreach (QModelIndex idx, rows) { - if (proxyModel != NULL) { - idx = proxyModel->mapToSource(idx); + if (keyEvent->key() == Qt::Key_Down) { + for (int i = 0; i < rows.size() / 2; ++i) { + rows.swap(i, rows.size() - i - 1); + } } - int newPriority = m_ESPs[idx.row()].m_Priority + diff; - if ((newPriority >= 0) && (newPriority < rowCount())) { - setPluginPriority(idx.row(), newPriority); + foreach (QModelIndex idx, rows) { + idx = proxyModel->mapToSource(idx); + int newPriority = m_ESPs[idx.row()].m_Priority + diff; + if ((newPriority >= 0) && (newPriority < rowCount())) { + setPluginPriority(idx.row(), newPriority); + } } + refreshLoadOrder(); } - refreshLoadOrder(); return true; } else if (keyEvent->key() == Qt::Key_Space) { QItemSelectionModel *selectionModel = itemView->selectionModel(); diff --git a/src/profile.cpp b/src/profile.cpp index 77e4f813..958084d7 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -585,7 +585,9 @@ void Profile::mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const bool Profile::invalidationActive(bool *supported) const { if (GameInfo::instance().requiresBSAInvalidation()) { - *supported = true; + if (supported != NULL) { + *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 diff --git a/src/selfupdater.h b/src/selfupdater.h index 9648f15a..75b0ff45 100644 --- a/src/selfupdater.h +++ b/src/selfupdater.h @@ -65,7 +65,8 @@ public: * @todo passing the nexus interface is unneccessary **/ SelfUpdater(NexusInterface *nexusInterface, QWidget *parent); - ~SelfUpdater(); + + virtual ~SelfUpdater(); /** * @brief start the update process diff --git a/src/settings.cpp b/src/settings.cpp index 04a5f279..0ca811a3 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -25,7 +25,7 @@ along with Mod Organizer. If not, see . #include #include #include -#include +#include "json.h" #include #include diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 5d785822..24868a93 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -325,13 +325,13 @@ static bool ByOriginPriority(DirectoryEntry *entry, int LHS, int RHS) FileEntry::FileEntry() - : m_Index(UINT_MAX), m_Name(), m_Parent(NULL), m_LastAccessed(time(NULL)) + : m_Index(UINT_MAX), m_Name(), m_Origin(-1), m_Parent(NULL), m_LastAccessed(time(NULL)) { LEAK_TRACE; } FileEntry::FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent) - : m_Index(index), m_Name(name), m_Parent(parent), m_Origin(-1), m_Archive(L""), m_LastAccessed(time(NULL)) + : m_Index(index), m_Name(name), m_Origin(-1), m_Parent(parent), m_Archive(L""), m_LastAccessed(time(NULL)) { LEAK_TRACE; } @@ -636,7 +636,7 @@ void DirectoryEntry::insertFile(const std::wstring &filePath, FilesOrigin &origi void DirectoryEntry::removeFile(FileEntry::Index index) { - if (m_Files.size() != 0) { + if (!m_Files.empty()) { auto iter = std::find_if(m_Files.begin(), m_Files.end(), [&index](const std::pair &iter) -> bool { return iter.second == index; } ); diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index 096f373e..d588ab02 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -219,7 +219,7 @@ public: void clear(); bool isPopulated() const { return m_Populated; } - bool isEmpty() const { return (m_Files.size() == 0) && (m_SubDirectories.size() == 0); } + bool isEmpty() const { return m_Files.empty() && m_SubDirectories.empty(); } const DirectoryEntry *getParent() const { return m_Parent; } diff --git a/src/shared/fallout3info.cpp b/src/shared/fallout3info.cpp index 9487d2de..22db91ac 100644 --- a/src/shared/fallout3info.cpp +++ b/src/shared/fallout3info.cpp @@ -54,15 +54,17 @@ std::wstring Fallout3Info::getRegPathStatic() 0, KEY_QUERY_VALUE, &key); if (errorcode != ERROR_SUCCESS) { - return L""; + return std::wstring(); } WCHAR temp[MAX_PATH]; DWORD bufferSize = MAX_PATH; - errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize); - - return std::wstring(temp); + if (::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize) == ERROR_SUCCESS) { + return std::wstring(temp); + } else { + return std::wstring(); + } } std::wstring Fallout3Info::getInvalidationBSA() @@ -233,15 +235,12 @@ void Fallout3Info::createProfile(const std::wstring &directory, bool useDefaults } } { // copy falloutprefs.ini-file - std::wstring target = directory.substr().append(L"\\falloutprefs.ini"); + std::wstring target = directory + L"\\falloutprefs.ini"; if (!FileExists(target)) { - std::wostringstream source; - source << getMyGamesDirectory() << L"\\Fallout3\\falloutprefs.ini"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + std::wstring source = getMyGamesDirectory() + L"\\Fallout3\\falloutprefs.ini"; + if (!::CopyFileW(source.c_str(), target.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()); + throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false)); } } } diff --git a/src/shared/fallout3info.h b/src/shared/fallout3info.h index 8e4c260d..d1356de1 100644 --- a/src/shared/fallout3info.h +++ b/src/shared/fallout3info.h @@ -38,7 +38,7 @@ public: virtual unsigned long getBSAVersion(); static std::wstring getRegPathStatic(); - virtual std::wstring getRegPath() { return Fallout3Info::getRegPathStatic(); } + virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"Fallout3.exe"; } virtual GameInfo::Type getType() { return TYPE_FALLOUT3; } @@ -75,9 +75,9 @@ public: virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); - virtual std::wstring getNexusInfoUrl() { return Fallout3Info::getNexusInfoUrlStatic(); } + virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } static int getNexusModIDStatic(); - virtual int getNexusModID() { return Fallout3Info::getNexusModIDStatic(); } + virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 120; } virtual void createProfile(const std::wstring &directory, bool useDefaults); diff --git a/src/shared/falloutnvinfo.cpp b/src/shared/falloutnvinfo.cpp index 9bba7fe4..0dde4db1 100644 --- a/src/shared/falloutnvinfo.cpp +++ b/src/shared/falloutnvinfo.cpp @@ -55,15 +55,17 @@ std::wstring FalloutNVInfo::getRegPathStatic() 0, KEY_QUERY_VALUE, &key); if (errorcode != ERROR_SUCCESS) { - return L""; + return std::wstring(); } WCHAR temp[MAX_PATH]; DWORD bufferSize = MAX_PATH; - errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize); - - return std::wstring(temp); + if (::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize) == ERROR_SUCCESS) { + return std::wstring(temp); + } else { + return std::wstring(); + } } std::wstring FalloutNVInfo::getInvalidationBSA() @@ -162,56 +164,46 @@ std::wstring FalloutNVInfo::getSteamAPPId(int) const void FalloutNVInfo::createProfile(const std::wstring &directory, bool useDefaults) { - std::wostringstream target; + std::wstring target = directory + L"\\plugins.txt"; // copy plugins.txt - target << directory << "\\plugins.txt"; - - if (!FileExists(target.str())) { - std::wostringstream source; - source << getLocalAppFolder() << "\\FalloutNV\\plugins.txt"; - if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) { - HANDLE file = ::CreateFileW(target.str().c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + 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, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); ::CloseHandle(file); } } // copy ini-file - target.str(L""); target.clear(); - target << directory << L"\\fallout.ini"; + target = directory + L"\\fallout.ini"; - if (!FileExists(target.str())) { - std::wostringstream source; + if (!FileExists(target)) { + std::wstring source; if (useDefaults) { - source << getGameDirectory() << L"\\fallout_default.ini"; + source = getGameDirectory() + L"\\fallout_default.ini"; } else { - source << getMyGamesDirectory() << L"\\FalloutNV"; - if (FileExists(source.str(), L"fallout.ini")) { - source << L"\\fallout.ini"; + source = getMyGamesDirectory() + L"\\FalloutNV"; + if (FileExists(source, L"fallout.ini")) { + source += L"\\fallout.ini"; } else { - source.str(L""); - source << getGameDirectory() << L"\\fallout_default.ini"; + source = getGameDirectory() + L"\\fallout_default.ini"; } } - if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) { + if (!::CopyFileW(source.c_str(), target.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()); + throw windows_error("failed to copy ini file: " + ToString(source, false)); } } } { // copy falloutprefs.ini-file - std::wstring target = directory.substr().append(L"\\falloutprefs.ini"); + std::wstring target = directory + L"\\falloutprefs.ini"; if (!FileExists(target)) { - std::wostringstream source; - source << getMyGamesDirectory() << L"\\FalloutNV\\falloutprefs.ini"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + std::wstring source = getMyGamesDirectory() + L"\\FalloutNV\\falloutprefs.ini"; + if (!::CopyFileW(source.c_str(), target.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()); + throw windows_error("failed to copy ini file: " + ToString(source, false)); } } } diff --git a/src/shared/falloutnvinfo.h b/src/shared/falloutnvinfo.h index cfd373c7..50a0d00d 100644 --- a/src/shared/falloutnvinfo.h +++ b/src/shared/falloutnvinfo.h @@ -38,7 +38,7 @@ public: virtual unsigned long getBSAVersion(); static std::wstring getRegPathStatic(); - virtual std::wstring getRegPath() { return FalloutNVInfo::getRegPathStatic(); } + virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"FalloutNV.exe"; } virtual GameInfo::Type getType() { return TYPE_FALLOUTNV; } @@ -76,9 +76,9 @@ public: virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); - virtual std::wstring getNexusInfoUrl() { return FalloutNVInfo::getNexusInfoUrlStatic(); } + virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } static int getNexusModIDStatic(); - virtual int getNexusModID() { return FalloutNVInfo::getNexusModIDStatic(); } + virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 130; } virtual void createProfile(const std::wstring &directory, bool useDefaults); diff --git a/src/shared/gameinfo.cpp b/src/shared/gameinfo.cpp index 21e9a586..5439efff 100644 --- a/src/shared/gameinfo.cpp +++ b/src/shared/gameinfo.cpp @@ -57,7 +57,7 @@ void GameInfo::identifyMyGamesDirectory(const std::wstring &file) { // this function attempts 3 (three!) ways to determine the correct "My Games" folder. wchar_t myDocuments[MAX_PATH]; - memset(myDocuments, '\0', MAX_PATH); + memset(myDocuments, '\0', MAX_PATH * sizeof(wchar_t)); m_MyGamesDirectory.clear(); @@ -137,71 +137,53 @@ std::wstring GameInfo::getGameDirectory() const std::wstring GameInfo::getModsDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\mods"; - return temp.str(); + return m_OrganizerDirectory + L"\\mods"; } std::wstring GameInfo::getProfilesDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\profiles"; - return temp.str(); + return m_OrganizerDirectory + L"\\profiles"; } std::wstring GameInfo::getIniFilename() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\ModOrganizer.ini"; - return temp.str(); + return m_OrganizerDirectory + L"\\ModOrganizer.ini"; } std::wstring GameInfo::getDownloadDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\downloads"; - return temp.str(); + return m_OrganizerDirectory + L"\\downloads"; } std::wstring GameInfo::getCacheDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\webcache"; - return temp.str(); + return m_OrganizerDirectory + L"\\webcache"; } std::wstring GameInfo::getOverwriteDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << "\\overwrite"; - return temp.str(); + return m_OrganizerDirectory + L"\\overwrite"; } std::wstring GameInfo::getLogDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << "\\logs"; - return temp.str(); + return m_OrganizerDirectory + L"\\logs"; } std::wstring GameInfo::getLootDir() const { - std::wostringstream temp; - temp << m_OrganizerDirectory << "\\loot"; - return temp.str(); + return m_OrganizerDirectory + L"\\loot"; } std::wstring GameInfo::getTutorialDir() const { - std::wostringstream temp; - temp << m_OrganizerDirectory << "\\tutorials"; - return temp.str(); + return m_OrganizerDirectory + L"\\tutorials"; } @@ -219,7 +201,7 @@ std::vector GameInfo::getSteamVariants() const std::wstring GameInfo::getLocalAppFolder() const { wchar_t localAppFolder[MAX_PATH]; - memset(localAppFolder, '\0', MAX_PATH); + memset(localAppFolder, '\0', MAX_PATH * sizeof(wchar_t)); if (::SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, localAppFolder) == S_OK) { return localAppFolder; diff --git a/src/shared/leaktrace.cpp b/src/shared/leaktrace.cpp index 68e57609..729eb42e 100644 --- a/src/shared/leaktrace.cpp +++ b/src/shared/leaktrace.cpp @@ -36,7 +36,7 @@ class StackData { public: StackData() - : m_FunctionName("Dummy"), m_CodeLine(0) + : m_Count(0), m_Hash(0UL), m_FunctionName("Dummy"), m_CodeLine(0) {} StackData(const char *functionName, int line) { m_Count = ::CaptureStackBackTrace(FRAMES_TO_SKIP, FRAMES_TO_CAPTURE, m_Stack, &m_Hash); diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp index f317812f..790fcdb0 100644 --- a/src/shared/oblivioninfo.cpp +++ b/src/shared/oblivioninfo.cpp @@ -55,15 +55,17 @@ std::wstring OblivionInfo::getRegPathStatic() 0, KEY_QUERY_VALUE, &key); if (errorcode != ERROR_SUCCESS) { - return L""; + return std::wstring(); } WCHAR temp[MAX_PATH]; DWORD bufferSize = MAX_PATH; - errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize); - - return std::wstring(temp); + if (::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize) == ERROR_SUCCESS) { + return std::wstring(temp); + } else { + return std::wstring(); + } } std::wstring OblivionInfo::getInvalidationBSA() @@ -188,16 +190,13 @@ void OblivionInfo::createProfile(const std::wstring &directory, bool useDefaults } { // copy oblivionprefs.ini-file - std::wstring target = directory.substr().append(L"\\oblivionprefs.ini"); + std::wstring target = directory + L"\\oblivionprefs.ini"; if (!FileExists(target)) { - std::wostringstream source; - source << getMyGamesDirectory() << L"\\Oblivion\\oblivionprefs.ini"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + 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, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL) == INVALID_HANDLE_VALUE) && (::GetLastError() != ERROR_FILE_EXISTS)) { - std::ostringstream stream; - stream << "failed to create ini file: " << ToString(target.c_str(), false); - throw windows_error(stream.str()); + throw windows_error(std::string("failed to create ini file: ") + ToString(target, false)); } } } diff --git a/src/shared/oblivioninfo.h b/src/shared/oblivioninfo.h index 02fd90b4..e64ae37b 100644 --- a/src/shared/oblivioninfo.h +++ b/src/shared/oblivioninfo.h @@ -36,7 +36,7 @@ public: virtual unsigned long getBSAVersion(); static std::wstring getRegPathStatic(); - virtual std::wstring getRegPath() { return OblivionInfo::getRegPathStatic(); } + virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"Oblivion.exe"; } virtual GameInfo::Type getType() { return TYPE_OBLIVION; } @@ -72,9 +72,9 @@ public: virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); - virtual std::wstring getNexusInfoUrl() { return OblivionInfo::getNexusInfoUrlStatic(); } + virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } static int getNexusModIDStatic(); - virtual int getNexusModID() { return OblivionInfo::getNexusModIDStatic(); } + virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 101; } virtual void createProfile(const std::wstring &directory, bool useDefaults); diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp index c985fe9f..319e58d5 100644 --- a/src/shared/skyriminfo.cpp +++ b/src/shared/skyriminfo.cpp @@ -63,15 +63,17 @@ std::wstring SkyrimInfo::getRegPathStatic() 0, KEY_QUERY_VALUE, &key); if (errorcode != ERROR_SUCCESS) { - return L""; + return std::wstring(); } WCHAR temp[MAX_PATH]; DWORD bufferSize = MAX_PATH; - errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize); - - return std::wstring(temp); + if (::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize) == ERROR_SUCCESS) { + return std::wstring(temp); + } else { + return std::wstring(); + } } @@ -222,7 +224,7 @@ int SkyrimInfo::getNexusModIDStatic() void SkyrimInfo::createProfile(const std::wstring &directory, bool useDefaults) { { // copy plugins.txt - std::wstring target = directory.substr().append(L"\\plugins.txt"); + std::wstring target = directory + L"\\plugins.txt"; if (!FileExists(target)) { std::wostringstream source; source << getLocalAppFolder() << "\\Skyrim\\plugins.txt"; @@ -231,11 +233,10 @@ void SkyrimInfo::createProfile(const std::wstring &directory, bool useDefaults) ::CloseHandle(file); } } - target = directory.substr().append(L"\\loadorder.txt"); + target = directory + L"\\loadorder.txt"; if (!FileExists(target)) { - std::wostringstream source; - source << getLocalAppFolder() << "\\Skyrim\\loadorder.txt"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + 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, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); ::CloseHandle(file); } @@ -243,42 +244,36 @@ void SkyrimInfo::createProfile(const std::wstring &directory, bool useDefaults) } { // copy skyrim.ini-file - std::wstring target = directory.substr().append(L"\\skyrim.ini"); + std::wstring target = directory + L"\\skyrim.ini"; if (!FileExists(target)) { - std::wostringstream source; + std::wstring source; if (useDefaults) { - source << getGameDirectory() << L"\\skyrim_default.ini"; + source = getGameDirectory() + L"\\skyrim_default.ini"; } else { - source << getMyGamesDirectory() << L"\\Skyrim"; - if (FileExists(source.str(), L"skyrim.ini")) { - source << L"\\skyrim.ini"; + source = getMyGamesDirectory() + L"\\Skyrim"; + if (FileExists(source, L"skyrim.ini")) { + source += L"\\skyrim.ini"; } else { - source.str(L""); - source << getGameDirectory() << L"\\skyrim_default.ini"; + source = getGameDirectory() + L"\\skyrim_default.ini"; } } - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + if (!::CopyFileW(source.c_str(), target.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()); + throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false)); } } } } { // copy skyrimprefs.ini-file - std::wstring target = directory.substr().append(L"\\skyrimprefs.ini"); + std::wstring target = directory + L"\\skyrimprefs.ini"; if (!FileExists(target)) { - std::wostringstream source; - source << getMyGamesDirectory() << L"\\Skyrim\\skyrimprefs.ini"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { - log("failed to copy ini file %ls", source.str().c_str()); + 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, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) == INVALID_HANDLE_VALUE) { - std::ostringstream stream; - stream << "failed to copy ini file: " << ToString(source.str(), false); - throw windows_error(stream.str()); + throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false)); } } } diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h index 132f2aee..a7aff8dc 100644 --- a/src/shared/skyriminfo.h +++ b/src/shared/skyriminfo.h @@ -38,7 +38,7 @@ public: virtual unsigned long getBSAVersion(); static std::wstring getRegPathStatic(); - virtual std::wstring getRegPath() { return SkyrimInfo::getRegPathStatic(); } + virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"TESV.exe"; } virtual GameInfo::Type getType() { return TYPE_SKYRIM; } @@ -81,11 +81,11 @@ public: virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); - virtual std::wstring getNexusInfoUrl() { return SkyrimInfo::getNexusInfoUrlStatic(); } + virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } static int getNexusModIDStatic(); - virtual int getNexusModID() { return SkyrimInfo::getNexusModIDStatic(); } + virtual int getNexusModID() { return getNexusModIDStatic(); } static int getNexusGameIDStatic() { return 110; } - virtual int getNexusGameID() { return SkyrimInfo::getNexusGameIDStatic(); } + virtual int getNexusGameID() { return getNexusGameIDStatic(); } virtual void createProfile(const std::wstring &directory, bool useDefaults); virtual void repairProfile(const std::wstring &directory); -- cgit v1.3.1