From f5330efd0d2692eb14738d8ccbe4e269ce165b46 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 25 May 2019 01:05:15 -0400 Subject: a copy of getBinaryExecuteInfo() and openDataFile() was in both mainwindow and modinfodialog, it's now moved to organizercore and renamed getFileExecutionContext() and executefile() getFileExecutionContext() is also changed to return an enum instead of a 0-1-2 int --- src/organizercore.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 8212d248..bdaf4ffc 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1220,6 +1220,102 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const return res; } + +bool OrganizerCore::getFileExecutionContext( + QWidget* parent, const QFileInfo &targetInfo, + QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type) +{ + QString extension = targetInfo.suffix(); + if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) || + (extension.compare("com", Qt::CaseInsensitive) == 0) || + (extension.compare("bat", Qt::CaseInsensitive) == 0)) { + binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe"); + arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + type = FileExecutionTypes::executable; + return true; + } else if (extension.compare("exe", Qt::CaseInsensitive) == 0) { + binaryInfo = targetInfo; + type = FileExecutionTypes::executable; + return true; + } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) { + // types that need to be injected into + std::wstring targetPathW = ToWString(targetInfo.absoluteFilePath()); + QString binaryPath; + + { // try to find java automatically + WCHAR buffer[MAX_PATH]; + if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { + DWORD binaryType = 0UL; + if (!::GetBinaryTypeW(buffer, &binaryType)) { + qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); + } else if (binaryType == SCS_32BIT_BINARY) { + binaryPath = ToQString(buffer); + } + } + } + if (binaryPath.isEmpty() && (extension == "jar")) { + // second attempt: look to the registry + 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()) { + binaryPath = QFileDialog::getOpenFileName( + parent, QObject::tr("Select binary"), QString(), QObject::tr("Binary") + " (*.exe)"); + } + if (binaryPath.isEmpty()) { + return false; + } + binaryInfo = QFileInfo(binaryPath); + if (extension == "jar") { + arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + } else { + arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + } + + type = FileExecutionTypes::executable; + return true; + } else { + type = FileExecutionTypes::other; + return true; + } +} + +bool OrganizerCore::executeFile(QWidget* parent, const QFileInfo& targetInfo) +{ + QFileInfo binaryInfo; + QString arguments; + FileExecutionTypes type; + + if (!getFileExecutionContext(parent, targetInfo, binaryInfo, arguments, type)) { + return false; + } + + switch (type) + { + case FileExecutionTypes::executable: { + spawnBinaryDirect( + binaryInfo, arguments, currentProfile()->name(), + targetInfo.absolutePath(), "", ""); + + return true; + } + + case FileExecutionTypes::other: { + ::ShellExecuteW(nullptr, L"open", + ToWString(targetInfo.absoluteFilePath()).c_str(), + nullptr, nullptr, SW_SHOWNORMAL); + + return true; + } + } + + // nop + return false; +} + void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory, -- cgit v1.3.1 From 9a014db4b3a64dc93450dff8afe980db3694c595 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 25 May 2019 02:12:11 -0400 Subject: moved GetFileExecutionContext() out of OrganizerCore, no reason for it to be there added ExploreFile(), changed all mentions of ShellExecute() in MainWindow to use it --- src/mainwindow.cpp | 43 ++++++--------- src/organizercore.cpp | 150 +++++++++++++++++++++++++++++--------------------- src/organizercore.h | 13 +++-- 3 files changed, 113 insertions(+), 93 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 88d7ba9d..ce6620c0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3241,12 +3241,12 @@ void MainWindow::openExplorer_clicked() if (selection->hasSelection() && selection->selectedRows().count() > 1) { for (QModelIndex idx : selection->selectedRows()) { ModInfo::Ptr info = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - ::ShellExecuteW(nullptr, L"explore", ToWString(info->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(info->absolutePath()); } } else { ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow); - ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(modInfo->absolutePath()); } } @@ -3261,18 +3261,14 @@ void MainWindow::openOriginExplorer_clicked() continue; } ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - std::vector flags = modInfo->getFlags(); - - ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(modInfo->absolutePath()); } } else { QModelIndex idx = selection->currentIndex(); QString fileName = idx.data().toString(); ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - std::vector flags = modInfo->getFlags(); - - ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(modInfo->absolutePath()); } } @@ -3287,7 +3283,7 @@ void MainWindow::openExplorer_activated() std::vector flags = modInfo->getFlags(); if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(modInfo->absolutePath()); } } @@ -3308,7 +3304,7 @@ void MainWindow::openExplorer_activated() std::vector flags = modInfo->getFlags(); if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(modInfo->absolutePath()); } } } @@ -4275,64 +4271,61 @@ void MainWindow::disableVisibleMods() void MainWindow::openInstanceFolder() { QString dataPath = qApp->property("dataPath").toString(); - ::ShellExecuteW(nullptr, L"explore", ToWString(dataPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL); - - //opens BaseDirectory instead - //::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getBaseDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(dataPath); } void MainWindow::openLogsFolder() { QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); - ::ShellExecuteW(nullptr, L"explore", ToWString(logsPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(logsPath); } void MainWindow::openInstallFolder() { - ::ShellExecuteW(nullptr, L"explore", ToWString(qApp->applicationDirPath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(qApp->applicationDirPath()); } void MainWindow::openPluginsFolder() { QString pluginsPath = QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); - ::ShellExecuteW(nullptr, L"explore", ToWString(pluginsPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(pluginsPath); } void MainWindow::openProfileFolder() { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.currentProfile()->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); } void MainWindow::openIniFolder() { if (m_OrganizerCore.currentProfile()->localSettingsEnabled()) { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.currentProfile()->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); } else { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->documentsDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); } } void MainWindow::openDownloadsFolder() { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getDownloadDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_OrganizerCore.settings().getDownloadDirectory()); } void MainWindow::openModsFolder() { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getModDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_OrganizerCore.settings().getModDirectory()); } void MainWindow::openGameFolder() { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->gameDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_OrganizerCore.managedGame()->gameDirectory()); } void MainWindow::openMyGamesFolder() { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->documentsDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); } @@ -5164,7 +5157,7 @@ void MainWindow::addAsExecutable() QString arguments; FileExecutionTypes type; - if (!m_OrganizerCore.getFileExecutionContext(this, targetInfo, binaryInfo, arguments, type)) { + if (!GetFileExecutionContext(this, targetInfo, binaryInfo, arguments, type)) { return; } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index bdaf4ffc..2542545f 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -267,6 +267,91 @@ bool checkService() return serviceRunning; } + +bool GetFileExecutionContext( + QWidget* parent, const QFileInfo &targetInfo, + QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type) +{ + QString extension = targetInfo.suffix(); + if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) || + (extension.compare("com", Qt::CaseInsensitive) == 0) || + (extension.compare("bat", Qt::CaseInsensitive) == 0)) { + binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe"); + arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + type = FileExecutionTypes::executable; + return true; + } else if (extension.compare("exe", Qt::CaseInsensitive) == 0) { + binaryInfo = targetInfo; + type = FileExecutionTypes::executable; + return true; + } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) { + // types that need to be injected into + std::wstring targetPathW = targetInfo.absoluteFilePath().toStdWString(); + QString binaryPath; + + { // try to find java automatically + WCHAR buffer[MAX_PATH]; + if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { + DWORD binaryType = 0UL; + if (!::GetBinaryTypeW(buffer, &binaryType)) { + qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); + } else if (binaryType == SCS_32BIT_BINARY) { + binaryPath = QString::fromWCharArray(buffer); + } + } + } + if (binaryPath.isEmpty() && (extension == "jar")) { + // second attempt: look to the registry + 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()) { + binaryPath = QFileDialog::getOpenFileName( + parent, QObject::tr("Select binary"), QString(), QObject::tr("Binary") + " (*.exe)"); + } + if (binaryPath.isEmpty()) { + return false; + } + binaryInfo = QFileInfo(binaryPath); + if (extension == "jar") { + arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + } else { + arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + } + + type = FileExecutionTypes::executable; + return true; + } else { + type = FileExecutionTypes::other; + return true; + } +} + +bool ExploreFile(const QString& path) +{ + const auto ws = path.toStdWString(); + + const auto h = ::ShellExecuteW( + nullptr, L"explore", ws.c_str(), nullptr, nullptr, SW_SHOWNORMAL); + + // anything <= 32 is not an actual HINSTANCE and signals failure + return (h > reinterpret_cast(32)); +} + +bool ExploreFile(const QFileInfo& info) +{ + return ExploreFile(info.absolutePath()); +} + +bool ExploreFile(const QDir& dir) +{ + return ExploreFile(dir.absolutePath()); +} + + OrganizerCore::OrganizerCore(const QSettings &initSettings) : m_UserInterface(nullptr) , m_PluginContainer(nullptr) @@ -1220,76 +1305,13 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const return res; } - -bool OrganizerCore::getFileExecutionContext( - QWidget* parent, const QFileInfo &targetInfo, - QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type) -{ - QString extension = targetInfo.suffix(); - if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) || - (extension.compare("com", Qt::CaseInsensitive) == 0) || - (extension.compare("bat", Qt::CaseInsensitive) == 0)) { - binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe"); - arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - type = FileExecutionTypes::executable; - return true; - } else if (extension.compare("exe", Qt::CaseInsensitive) == 0) { - binaryInfo = targetInfo; - type = FileExecutionTypes::executable; - return true; - } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) { - // types that need to be injected into - std::wstring targetPathW = ToWString(targetInfo.absoluteFilePath()); - QString binaryPath; - - { // try to find java automatically - WCHAR buffer[MAX_PATH]; - if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { - DWORD binaryType = 0UL; - if (!::GetBinaryTypeW(buffer, &binaryType)) { - qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); - } else if (binaryType == SCS_32BIT_BINARY) { - binaryPath = ToQString(buffer); - } - } - } - if (binaryPath.isEmpty() && (extension == "jar")) { - // second attempt: look to the registry - 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()) { - binaryPath = QFileDialog::getOpenFileName( - parent, QObject::tr("Select binary"), QString(), QObject::tr("Binary") + " (*.exe)"); - } - if (binaryPath.isEmpty()) { - return false; - } - binaryInfo = QFileInfo(binaryPath); - if (extension == "jar") { - arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - } else { - arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - } - - type = FileExecutionTypes::executable; - return true; - } else { - type = FileExecutionTypes::other; - return true; - } -} - bool OrganizerCore::executeFile(QWidget* parent, const QFileInfo& targetInfo) { QFileInfo binaryInfo; QString arguments; FileExecutionTypes type; - if (!getFileExecutionContext(parent, targetInfo, binaryInfo, arguments, type)) { + if (!GetFileExecutionContext(parent, targetInfo, binaryInfo, arguments, type)) { return false; } diff --git a/src/organizercore.h b/src/organizercore.h index 94cfa5ae..103443eb 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -56,12 +56,21 @@ namespace MOBase { class IPluginGame; } + enum class FileExecutionTypes { executable = 1, other = 2 }; +bool GetFileExecutionContext( + QWidget* parent, const QFileInfo &targetInfo, + QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); + +bool ExploreFile(const QString& path); +bool ExploreFile(const QFileInfo& info); +bool ExploreFile(const QDir& dir); + class OrganizerCore : public QObject, public MOBase::IPluginDiagnose { @@ -147,10 +156,6 @@ public: void doAfterLogin(const std::function &function) { m_PostLoginTasks.append(function); } - static bool getFileExecutionContext( - QWidget* parent, const QFileInfo &targetInfo, - QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); - bool executeFile(QWidget* parent, const QFileInfo& targetInfo); void spawnBinary(const QFileInfo &binary, const QString &arguments = "", -- cgit v1.3.1 From ebb855dc1421e89813a1f4a74a4963d76aba9747 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 25 May 2019 03:10:37 -0400 Subject: ExploreFile() will select the file in explorer when the path is a file replaced more ShellExecute() calls with ExploreFile() --- src/downloadmanager.cpp | 25 ++++++++++++------------- src/modinfodialog.cpp | 2 +- src/organizercore.cpp | 44 +++++++++++++++++++++++++++++++++++++++----- src/organizercore.h | 2 +- src/overwriteinfodialog.cpp | 3 ++- 5 files changed, 55 insertions(+), 21 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 78162f11..686092b5 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -1037,7 +1037,7 @@ void DownloadManager::openFile(int index) return; } - ::ShellExecuteW(nullptr, L"explore", ToWString(QDir::toNativeSeparators(m_OutputDirectory)).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_OutputDirectory); return; } @@ -1047,23 +1047,22 @@ void DownloadManager::openInDownloadsFolder(int index) reportError(tr("OpenFileInDownloadsFolder: invalid download index %1").arg(index)); return; } - QString params = "/select,\""; - QDir path = QDir(m_OutputDirectory); - if (path.exists(getFileName(index))) { - params = params + QDir::toNativeSeparators(getFilePath(index)) + "\""; - ::ShellExecuteW(nullptr, nullptr, L"explorer", ToWString(params).c_str(), nullptr, SW_SHOWNORMAL); - return; - } - else if (path.exists(getFileName(index) + ".unfinished")) { - params = params + QDir::toNativeSeparators(getFilePath(index)+".unfinished") + "\""; + const auto path = getFilePath(index); - ::ShellExecuteW(nullptr, nullptr, L"explorer", ToWString(params).c_str(), nullptr, SW_SHOWNORMAL); + if (QFile::exists(path)) { + ExploreFile(path); return; } + else { + const auto unfinished = path + ".unfinished"; + if (QFile::exists(unfinished)) { + ExploreFile(unfinished); + return; + } + } - ::ShellExecuteW(nullptr, L"explore", ToWString(QDir::toNativeSeparators(m_OutputDirectory)).c_str(), nullptr, nullptr, SW_SHOWNORMAL); - return; + ExploreFile(m_OutputDirectory); } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 83c0169a..5fb3e9cf 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1242,7 +1242,7 @@ bool ModInfoDialog::recursiveDelete(const QModelIndex &index) void ModInfoDialog::on_openInExplorerButton_clicked() { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_ModInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_ModInfo->absolutePath()); } void ModInfoDialog::deleteFile(const QModelIndex &index) diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 2542545f..d228dfe1 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -330,25 +330,59 @@ bool GetFileExecutionContext( } } -bool ExploreFile(const QString& path) + +bool ExploreDirectory(const QFileInfo& info) { - const auto ws = path.toStdWString(); + const auto path = QDir::toNativeSeparators(info.absoluteFilePath()); + const auto ws_path = path.toStdWString(); const auto h = ::ShellExecuteW( - nullptr, L"explore", ws.c_str(), nullptr, nullptr, SW_SHOWNORMAL); + nullptr, L"explore", ws_path.c_str(), nullptr, nullptr, SW_SHOWNORMAL); // anything <= 32 is not an actual HINSTANCE and signals failure return (h > reinterpret_cast(32)); } +bool ExploreFileInDirectory(const QFileInfo& info) +{ + const auto path = QDir::toNativeSeparators(info.absoluteFilePath()); + const auto params = "/select,\"" + path + "\""; + const auto ws_params = params.toStdWString(); + + const auto h = ::ShellExecuteW( + nullptr, nullptr, L"explorer", ws_params.c_str(), nullptr, SW_SHOWNORMAL); + + // anything <= 32 is not an actual HINSTANCE and signals failure + return (h > reinterpret_cast(32)); +} + + bool ExploreFile(const QFileInfo& info) { - return ExploreFile(info.absolutePath()); + if (info.isFile()) { + return ExploreFileInDirectory(info); + } else if (info.isDir()) { + return ExploreDirectory(info); + } else { + // try the parent directory + const auto parent = info.dir(); + + if (parent.exists()) { + return ExploreDirectory(parent.absolutePath()); + } + } + + return false; +} + +bool ExploreFile(const QString& path) +{ + return ExploreFile(QFileInfo(path)); } bool ExploreFile(const QDir& dir) { - return ExploreFile(dir.absolutePath()); + return ExploreFile(QFileInfo(dir.absolutePath())); } diff --git a/src/organizercore.h b/src/organizercore.h index 103443eb..3f773277 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -67,8 +67,8 @@ bool GetFileExecutionContext( QWidget* parent, const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); -bool ExploreFile(const QString& path); bool ExploreFile(const QFileInfo& info); +bool ExploreFile(const QString& path); bool ExploreFile(const QDir& dir); diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index 3d82cf17..e9d7ce06 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include "ui_overwriteinfodialog.h" #include "report.h" #include "utility.h" +#include "organizercore.h" #include #include #include @@ -263,7 +264,7 @@ void OverwriteInfoDialog::createDirectoryTriggered() void OverwriteInfoDialog::on_explorerButton_clicked() { - ::ShellExecuteW(nullptr, L"explore", ToWString(m_ModInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ExploreFile(m_ModInfo->absolutePath()); } void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint &pos) -- cgit v1.3.1 From 76708b9694070bcaa5775a097ae73ffc163ca31b Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 25 May 2019 08:34:52 -0400 Subject: put explore and open functions in namespace shell previewDataFile() was duplicated in both MainWindow and ModInfoDialog, moved to OrganizerCore added preview menu item to filetree better logging when shell operations fail --- src/downloadmanager.cpp | 8 +- src/mainwindow.cpp | 98 ++++--------------- src/modinfodialog.cpp | 133 ++++++++++---------------- src/modinfodialog.h | 12 ++- src/organizercore.cpp | 228 +++++++++++++++++++++++++++++++++++++++++--- src/organizercore.h | 15 ++- src/overwriteinfodialog.cpp | 2 +- 7 files changed, 311 insertions(+), 185 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 686092b5..1412df51 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -1037,7 +1037,7 @@ void DownloadManager::openFile(int index) return; } - ExploreFile(m_OutputDirectory); + shell::ExploreFile(m_OutputDirectory); return; } @@ -1051,18 +1051,18 @@ void DownloadManager::openInDownloadsFolder(int index) const auto path = getFilePath(index); if (QFile::exists(path)) { - ExploreFile(path); + shell::ExploreFile(path); return; } else { const auto unfinished = path + ".unfinished"; if (QFile::exists(unfinished)) { - ExploreFile(unfinished); + shell::ExploreFile(unfinished); return; } } - ExploreFile(m_OutputDirectory); + shell::ExploreFile(m_OutputDirectory); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ce6620c0..94cbe9b1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3241,12 +3241,12 @@ void MainWindow::openExplorer_clicked() if (selection->hasSelection() && selection->selectedRows().count() > 1) { for (QModelIndex idx : selection->selectedRows()) { ModInfo::Ptr info = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - ExploreFile(info->absolutePath()); + shell::ExploreFile(info->absolutePath()); } } else { ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow); - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } @@ -3261,14 +3261,14 @@ void MainWindow::openOriginExplorer_clicked() continue; } ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } else { QModelIndex idx = selection->currentIndex(); QString fileName = idx.data().toString(); ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } @@ -3283,7 +3283,7 @@ void MainWindow::openExplorer_activated() std::vector flags = modInfo->getFlags(); if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } @@ -3304,7 +3304,7 @@ void MainWindow::openExplorer_activated() std::vector flags = modInfo->getFlags(); if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } } @@ -4271,61 +4271,61 @@ void MainWindow::disableVisibleMods() void MainWindow::openInstanceFolder() { QString dataPath = qApp->property("dataPath").toString(); - ExploreFile(dataPath); + shell::ExploreFile(dataPath); } void MainWindow::openLogsFolder() { QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); - ExploreFile(logsPath); + shell::ExploreFile(logsPath); } void MainWindow::openInstallFolder() { - ExploreFile(qApp->applicationDirPath()); + shell::ExploreFile(qApp->applicationDirPath()); } void MainWindow::openPluginsFolder() { QString pluginsPath = QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); - ExploreFile(pluginsPath); + shell::ExploreFile(pluginsPath); } void MainWindow::openProfileFolder() { - ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); + shell::ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); } void MainWindow::openIniFolder() { if (m_OrganizerCore.currentProfile()->localSettingsEnabled()) { - ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); + shell::ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); } else { - ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); + shell::ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); } } void MainWindow::openDownloadsFolder() { - ExploreFile(m_OrganizerCore.settings().getDownloadDirectory()); + shell::ExploreFile(m_OrganizerCore.settings().getDownloadDirectory()); } void MainWindow::openModsFolder() { - ExploreFile(m_OrganizerCore.settings().getModDirectory()); + shell::ExploreFile(m_OrganizerCore.settings().getModDirectory()); } void MainWindow::openGameFolder() { - ExploreFile(m_OrganizerCore.managedGame()->gameDirectory()); + shell::ExploreFile(m_OrganizerCore.managedGame()->gameDirectory()); } void MainWindow::openMyGamesFolder() { - ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); + shell::ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); } @@ -5304,67 +5304,7 @@ void MainWindow::disableSelectedMods_clicked() void MainWindow::previewDataFile() { QString fileName = QDir::fromNativeSeparators(m_ContextItem->data(0, Qt::UserRole).toString()); - - // what we have is an absolute path to the file in its actual location (for the primary origin) - // what we want is the path relative to the virtual data directory - - // we need to look in the virtual directory for the file to make sure the info is up to date. - - // check if the file comes from the actual data folder instead of a mod - QDir gameDirectory = m_OrganizerCore.managedGame()->dataDirectory().absolutePath(); - QString relativePath = gameDirectory.relativeFilePath(fileName); - QDir dirRelativePath = gameDirectory.relativeFilePath(fileName); - // if the file is on a different drive the dirRelativePath will actually be an absolute path so we make sure that is not the case - if (!dirRelativePath.isAbsolute() && !relativePath.startsWith("..")) { - fileName = relativePath; - } - else { - // crude: we search for the next slash after the base mod directory to skip everything up to the data-relative directory - int offset = m_OrganizerCore.settings().getModDirectory().size() + 1; - offset = fileName.indexOf("/", offset); - fileName = fileName.mid(offset + 1); - } - - - - const FileEntry::Ptr file = m_OrganizerCore.directoryStructure()->searchFile(ToWString(fileName), nullptr); - - if (file.get() == nullptr) { - reportError(tr("file not found: %1").arg(qUtf8Printable(fileName))); - return; - } - - // set up preview dialog - PreviewDialog preview(fileName); - auto addFunc = [&] (int originId) { - FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId); - QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; - if (QFile::exists(filePath)) { - // it's very possible the file doesn't exist, because it's inside an archive. we don't support that - QWidget *wid = m_PluginContainer.previewGenerator().genPreview(filePath); - if (wid == nullptr) { - reportError(tr("failed to generate preview for %1").arg(filePath)); - } else { - preview.addVariant(ToQString(origin.getName()), wid); - } - } - }; - - addFunc(file->getOrigin()); - for (auto alt : file->getAlternatives()) { - addFunc(alt.first); - } - if (preview.numVariants() > 0) { - QSettings &settings = m_OrganizerCore.settings().directInterface(); - QString key = QString("geometry/%1").arg(preview.objectName()); - if (settings.contains(key)) { - preview.restoreGeometry(settings.value(key).toByteArray()); - } - preview.exec(); - settings.setValue(key, preview.saveGeometry()); - } else { - QMessageBox::information(this, tr("Sorry"), tr("Sorry, can't preview anything. This function currently does not support extracting from bsas.")); - } + m_OrganizerCore.previewFileWithAlternatives(this, fileName); } void MainWindow::openDataFile() @@ -5374,7 +5314,7 @@ void MainWindow::openDataFile() } QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString()); - m_OrganizerCore.executeFile(this, targetInfo); + m_OrganizerCore.executeFileVirtualized(this, targetInfo); } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 9bd36f7e..c3ef7c47 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -322,9 +322,9 @@ bool ExpanderWidget::opened() const ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directory, bool unmanaged, OrganizerCore *organizerCore, PluginContainer *pluginContainer, QWidget *parent) : TutorableDialog("ModInfoDialog", parent), ui(new Ui::ModInfoDialog), m_ModInfo(modInfo), m_ThumbnailMapper(this), m_RequestStarted(false), - m_NewFolderAction(nullptr), m_OpenAction(nullptr), m_RenameAction(nullptr), - m_DeleteAction(nullptr), m_HideAction(nullptr), m_UnhideAction(nullptr), - m_Directory(directory), m_Origin(nullptr), + m_NewFolderAction(nullptr), m_OpenAction(nullptr), m_PreviewAction(nullptr), + m_RenameAction(nullptr), m_DeleteAction(nullptr), m_HideAction(nullptr), + m_UnhideAction(nullptr), m_Directory(directory), m_Origin(nullptr), m_OrganizerCore(organizerCore), m_PluginContainer(pluginContainer) { ui->setupUi(this); @@ -483,16 +483,18 @@ void ModInfoDialog::initFiletree(ModInfo::Ptr modInfo) m_NewFolderAction = new QAction(tr("&New Folder"), ui->fileTree); m_OpenAction = new QAction(tr("&Open"), ui->fileTree); + m_PreviewAction = new QAction(tr("&Preview"), ui->fileTree); m_RenameAction = new QAction(tr("&Rename"), ui->fileTree); m_DeleteAction = new QAction(tr("&Delete"), ui->fileTree); m_HideAction = new QAction(tr("&Hide"), ui->fileTree); m_UnhideAction = new QAction(tr("&Unhide"), ui->fileTree); - QObject::connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered())); - QObject::connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered())); - QObject::connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered())); - QObject::connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered())); - QObject::connect(m_HideAction, SIGNAL(triggered()), this, SLOT(hideTriggered())); + connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered())); + connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered())); + connect(m_PreviewAction, SIGNAL(triggered()), this, SLOT(previewTriggered())); + connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered())); + connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered())); + connect(m_HideAction, SIGNAL(triggered()), this, SLOT(hideTriggered())); connect(m_UnhideAction, SIGNAL(triggered()), this, SLOT(unhideTriggered())); } @@ -1244,12 +1246,11 @@ bool ModInfoDialog::recursiveDelete(const QModelIndex &index) void ModInfoDialog::on_openInExplorerButton_clicked() { - ExploreFile(m_ModInfo->absolutePath()); + shell::ExploreFile(m_ModInfo->absolutePath()); } void ModInfoDialog::deleteFile(const QModelIndex &index) { - bool res = m_FileSystemModel->isDir(index) ? recursiveDelete(index) : m_FileSystemModel->remove(index); if (!res) { @@ -1406,21 +1407,29 @@ void ModInfoDialog::changeFiletreeVisibility(bool hide) } -void ModInfoDialog::openFile(const QModelIndex &index) +void ModInfoDialog::openTriggered() { - QString fileName = m_FileSystemModel->filePath(index); + if (m_FileSelection.size() == 1) { + const auto index = m_FileSelection.at(0); + if (!index.isValid()) { + return; + } - HINSTANCE res = ::ShellExecuteW(nullptr, L"open", ToWString(fileName).c_str(), nullptr, nullptr, SW_SHOW); - if ((unsigned long long)res <= 32) { - qCritical("failed to invoke %s: %d", qUtf8Printable(fileName), res); + QString fileName = m_FileSystemModel->filePath(index); + shell::OpenFile(fileName); } } - -void ModInfoDialog::openTriggered() +void ModInfoDialog::previewTriggered() { - foreach(QModelIndex idx, m_FileSelection) { - openFile(idx); + if (m_FileSelection.size() == 1) { + const auto index = m_FileSelection.at(0); + if (!index.isValid()) { + return; + } + + QString fileName = m_FileSystemModel->filePath(index); + m_OrganizerCore->previewFile(this, m_ModInfo->name(), fileName); } } @@ -1464,6 +1473,7 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) if (selectionModel->hasSelection()) { bool enableOpen = true; + bool enablePreview = true; bool enableRename = true; bool enableDelete = true; bool enableHide = true; @@ -1484,10 +1494,15 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) if (!hasFiles) { enableOpen = false; + enablePreview = false; } const QString fileName = m_FileSystemModel->fileName(m_FileSelection.at(0)); + if (!canPreviewFile(false, fileName)) { + enablePreview = false; + } + if (!canHideFile(false, fileName)) { enableHide = false; } @@ -1499,6 +1514,7 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) // this is a multiple selection, don't show open action so users don't open // a thousand files enableOpen = false; + enablePreview = false; enableRename = false; if (m_FileSelection.size() < max_scan_for_visibility) { @@ -1530,6 +1546,10 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) menu.addAction(m_OpenAction); } + if (enablePreview) { + menu.addAction(m_PreviewAction); + } + if (enableRename) { menu.addAction(m_RenameAction); } @@ -1755,7 +1775,7 @@ void ModInfoDialog::openDataFile(const QTreeWidgetItem* item) } QFileInfo targetInfo(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->executeFile(this, targetInfo); + m_OrganizerCore->executeFileVirtualized(this, targetInfo); } void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) @@ -1765,63 +1785,17 @@ void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) } QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString()); + m_OrganizerCore->previewFileWithAlternatives(this, fileName); +} - // what we have is an absolute path to the file in its actual location (for the primary origin) - // what we want is the path relative to the virtual data directory - - // we need to look in the virtual directory for the file to make sure the info is up to date. - - // check if the file comes from the actual data folder instead of a mod - QDir gameDirectory = m_OrganizerCore->managedGame()->dataDirectory().absolutePath(); - QString relativePath = gameDirectory.relativeFilePath(fileName); - QDir direRelativePath = gameDirectory.relativeFilePath(fileName); - // if the file is on a different drive the dirRelativePath will actually be an absolute path so we make sure that is not the case - if (!direRelativePath.isAbsolute() && !relativePath.startsWith("..")) { - fileName = relativePath; - } - else { - // crude: we search for the next slash after the base mod directory to skip everything up to the data-relative directory - int offset = m_OrganizerCore->settings().getModDirectory().size() + 1; - offset = fileName.indexOf("/", offset); - fileName = fileName.mid(offset + 1); - } - - - - const FileEntry::Ptr file = m_OrganizerCore->directoryStructure()->searchFile(ToWString(fileName), nullptr); - - if (file.get() == nullptr) { - reportError(tr("file not found: %1").arg(qUtf8Printable(fileName))); - return; - } - - // set up preview dialog - PreviewDialog preview(fileName); - auto addFunc = [&](int originId) { - FilesOrigin &origin = m_OrganizerCore->directoryStructure()->getOriginByID(originId); - QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; - if (QFile::exists(filePath)) { - // it's very possible the file doesn't exist, because it's inside an archive. we don't support that - QWidget *wid = m_PluginContainer->previewGenerator().genPreview(filePath); - if (wid == nullptr) { - reportError(tr("failed to generate preview for %1").arg(filePath)); - } - else { - preview.addVariant(ToQString(origin.getName()), wid); - } - } - }; +bool ModInfoDialog::canPreviewFile(bool isArchive, const QString& filename) const +{ + if (isArchive) { + return false; + } - addFunc(file->getOrigin()); - for (auto alt : file->getAlternatives()) { - addFunc(alt.first); - } - if (preview.numVariants() > 0) { - preview.exec(); - } - else { - QMessageBox::information(this, tr("Sorry"), tr("Sorry, can't preview anything. This function currently does not support extracting from bsas.")); - } + const auto ext = QFileInfo(filename).suffix(); + return m_PluginContainer->previewGenerator().previewSupported(ext); } bool ModInfoDialog::canHideFile(bool isArchive, const QString& filename) const @@ -1866,12 +1840,9 @@ bool ModInfoDialog::canUnhideConflictItem(const QTreeWidgetItem* item) const bool ModInfoDialog::canPreviewConflictItem(const QTreeWidgetItem* item) const { - const QString fileName = item->data(0, Qt::UserRole).toString(); - if (!m_PluginContainer->previewGenerator().previewSupported(QFileInfo(fileName).suffix())) { - return false; - } - - return true; + return canPreviewFile( + item->data(1, Qt::UserRole + 2).toBool(), + item->data(0, Qt::UserRole).toString()); } void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &pos) diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 6bf30a52..c0730afa 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -313,7 +313,6 @@ private: QString getFileCategory(int categoryID); bool recursiveDelete(const QModelIndex &index); void deleteFile(const QModelIndex &index); - void openFile(const QModelIndex &index); void saveIniTweaks(); void saveCategories(QTreeWidgetItem *currentNode); void saveCurrentTextFile(); @@ -348,10 +347,11 @@ private slots: void delete_activated(); - void deleteTriggered(); - void renameTriggered(); - void openTriggered(); void createDirectoryTriggered(); + void openTriggered(); + void previewTriggered(); + void renameTriggered(); + void deleteTriggered(); void hideTriggered(); void unhideTriggered(); @@ -416,6 +416,7 @@ private: QAction *m_NewFolderAction; QAction *m_OpenAction; + QAction *m_PreviewAction; QAction *m_RenameAction; QAction *m_DeleteAction; QAction *m_HideAction; @@ -439,11 +440,12 @@ private: bool canUnhideConflictItem(const QTreeWidgetItem* item) const; bool canPreviewConflictItem(const QTreeWidgetItem* item) const; - void previewDataFile(const QTreeWidgetItem* item); void openDataFile(const QTreeWidgetItem* item); + void previewDataFile(const QTreeWidgetItem* item); void changeConflictFilesVisibility(bool hide); void changeFiletreeVisibility(bool hide); + bool canPreviewFile(bool isArchive, const QString& filename) const; bool canHideFile(bool isArchive, const QString& filename) const; bool canUnhideFile(bool isArchive, const QString& filename) const; }; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d228dfe1..3a6b810e 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -35,6 +35,7 @@ #include "instancemanager.h" #include #include "helper.h" +#include "previewdialog.h" #include #include @@ -331,16 +332,103 @@ bool GetFileExecutionContext( } -bool ExploreDirectory(const QFileInfo& info) +const char* ShellExecuteError(int i) { - const auto path = QDir::toNativeSeparators(info.absoluteFilePath()); - const auto ws_path = path.toStdWString(); + switch (i) { + case 0: + return "The operating system is out of memory or resources"; + + case ERROR_FILE_NOT_FOUND: + return "The specified file was not found"; + + case ERROR_PATH_NOT_FOUND: + return "The specified path was not found"; + + case ERROR_BAD_FORMAT: + return "The .exe file is invalid (non-Win32 .exe or error in .exe image)"; + + case SE_ERR_ACCESSDENIED: + return "The operating system denied access to the specified file"; + + case SE_ERR_ASSOCINCOMPLETE: + return "The file name association is incomplete or invalid"; + + case SE_ERR_DDEBUSY: + return "The DDE transaction could not be completed because other DDE " + "transactions were being processed"; + + case SE_ERR_DDEFAIL: + return "The DDE transaction failed"; + + case SE_ERR_DDETIMEOUT: + return "The DDE transaction could not be completed because the request " + "timed out"; + + case SE_ERR_DLLNOTFOUND: + return "The specified DLL was not found"; + + case SE_ERR_NOASSOC: + return "There is no application associated with the given file name " + "extension"; + + case SE_ERR_OOM: + return "There was not enough memory to complete the operation"; + + case SE_ERR_SHARE: + return "A sharing violation occurred"; + + default: + return "Unknown error"; + } +} + +void LogShellFailure( + const wchar_t* operation, const wchar_t* file, const wchar_t* params, + HINSTANCE h) +{ + const auto code = static_cast(reinterpret_cast(h)); + + QString s = "failed to invoke"; + + if (operation) { + s += " " + QString::fromWCharArray(operation); + } + + if (file) { + s += " " + QString::fromWCharArray(file); + } + if (params) { + s += " " + QString::fromWCharArray(params); + } + + qCritical( + "failed to invoke %s: %s (error %d)", + s, ShellExecuteError(code), code); +} + +bool ShellExecuteWrapper( + const wchar_t* operation, const wchar_t* file, const wchar_t* params) +{ const auto h = ::ShellExecuteW( - nullptr, L"explore", ws_path.c_str(), nullptr, nullptr, SW_SHOWNORMAL); + 0, operation, file, params, nullptr, SW_SHOWNORMAL); // anything <= 32 is not an actual HINSTANCE and signals failure - return (h > reinterpret_cast(32)); + if (h <= reinterpret_cast(32)) + { + LogShellFailure(operation, file, params, h); + return false; + } + + return true; +} + +bool ExploreDirectory(const QFileInfo& info) +{ + const auto path = QDir::toNativeSeparators(info.absoluteFilePath()); + const auto ws_path = path.toStdWString(); + + return ShellExecuteWrapper(L"explore", ws_path.c_str(), nullptr); } bool ExploreFileInDirectory(const QFileInfo& info) @@ -349,14 +437,13 @@ bool ExploreFileInDirectory(const QFileInfo& info) const auto params = "/select,\"" + path + "\""; const auto ws_params = params.toStdWString(); - const auto h = ::ShellExecuteW( - nullptr, nullptr, L"explorer", ws_params.c_str(), nullptr, SW_SHOWNORMAL); - - // anything <= 32 is not an actual HINSTANCE and signals failure - return (h > reinterpret_cast(32)); + return ShellExecuteWrapper(nullptr, L"explorer", ws_params.c_str()); } +namespace shell +{ + bool ExploreFile(const QFileInfo& info) { if (info.isFile()) { @@ -385,6 +472,14 @@ bool ExploreFile(const QDir& dir) return ExploreFile(QFileInfo(dir.absolutePath())); } +bool OpenFile(const QString& path) +{ + const auto ws_path = path.toStdWString(); + return ShellExecuteWrapper(L"open", ws_path.c_str(), nullptr); +} + +} // namespace shell + OrganizerCore::OrganizerCore(const QSettings &initSettings) : m_UserInterface(nullptr) @@ -1339,7 +1434,8 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const return res; } -bool OrganizerCore::executeFile(QWidget* parent, const QFileInfo& targetInfo) +bool OrganizerCore::executeFileVirtualized( + QWidget* parent, const QFileInfo& targetInfo) { QFileInfo binaryInfo; QString arguments; @@ -1372,6 +1468,116 @@ bool OrganizerCore::executeFile(QWidget* parent, const QFileInfo& targetInfo) return false; } +bool OrganizerCore::previewFileWithAlternatives( + QWidget* parent, QString fileName) +{ + // what we have is an absolute path to the file in its actual location (for the primary origin) + // what we want is the path relative to the virtual data directory + + // we need to look in the virtual directory for the file to make sure the info is up to date. + + // check if the file comes from the actual data folder instead of a mod + QDir gameDirectory = managedGame()->dataDirectory().absolutePath(); + QString relativePath = gameDirectory.relativeFilePath(fileName); + QDir dirRelativePath = gameDirectory.relativeFilePath(fileName); + + // if the file is on a different drive the dirRelativePath will actually be an + // absolute path so we make sure that is not the case + if (!dirRelativePath.isAbsolute() && !relativePath.startsWith("..")) { + fileName = relativePath; + } + else { + // crude: we search for the next slash after the base mod directory to skip + // everything up to the data-relative directory + int offset = settings().getModDirectory().size() + 1; + offset = fileName.indexOf("/", offset); + fileName = fileName.mid(offset + 1); + } + + + + const FileEntry::Ptr file = directoryStructure()->searchFile(ToWString(fileName), nullptr); + + if (file.get() == nullptr) { + reportError(tr("file not found: %1").arg(qUtf8Printable(fileName))); + return false; + } + + // set up preview dialog + PreviewDialog preview(fileName); + auto addFunc = [&](int originId) { + FilesOrigin &origin = directoryStructure()->getOriginByID(originId); + QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; + if (QFile::exists(filePath)) { + // it's very possible the file doesn't exist, because it's inside an archive. we don't support that + QWidget *wid = m_PluginContainer->previewGenerator().genPreview(filePath); + if (wid == nullptr) { + reportError(tr("failed to generate preview for %1").arg(filePath)); + } + else { + preview.addVariant(ToQString(origin.getName()), wid); + } + } + }; + + addFunc(file->getOrigin()); + for (auto alt : file->getAlternatives()) { + addFunc(alt.first); + } + + if (preview.numVariants() > 0) { + QSettings &s = settings().directInterface(); + QString key = QString("geometry/%1").arg(preview.objectName()); + if (s.contains(key)) { + preview.restoreGeometry(s.value(key).toByteArray()); + } + + preview.exec(); + + s.setValue(key, preview.saveGeometry()); + + return true; + } + else { + QMessageBox::information( + parent, tr("Sorry"), + tr("Sorry, can't preview anything. This function currently does not support extracting from bsas.")); + + return false; + } +} + +bool OrganizerCore::previewFile( + QWidget* parent, const QString& originName, const QString& path) +{ + if (!QFile::exists(path)) { + reportError(tr("File '%1' not found.").arg(path)); + return false; + } + + PreviewDialog preview(path); + + QWidget *wid = m_PluginContainer->previewGenerator().genPreview(path); + if (wid == nullptr) { + reportError(tr("Failed to generate preview for %1").arg(path)); + return false; + } + + preview.addVariant(originName, wid); + + QSettings &s = settings().directInterface(); + QString key = QString("geometry/%1").arg(preview.objectName()); + if (s.contains(key)) { + preview.restoreGeometry(s.value(key).toByteArray()); + } + + preview.exec(); + + s.setValue(key, preview.saveGeometry()); + + return true; +} + void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory, diff --git a/src/organizercore.h b/src/organizercore.h index 3f773277..41f0fd46 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -67,9 +67,14 @@ bool GetFileExecutionContext( QWidget* parent, const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); -bool ExploreFile(const QFileInfo& info); -bool ExploreFile(const QString& path); -bool ExploreFile(const QDir& dir); +namespace shell +{ + bool ExploreFile(const QFileInfo& info); + bool ExploreFile(const QString& path); + bool ExploreFile(const QDir& dir); + + bool OpenFile(const QString& path); +} class OrganizerCore : public QObject, public MOBase::IPluginDiagnose @@ -156,7 +161,9 @@ public: void doAfterLogin(const std::function &function) { m_PostLoginTasks.append(function); } - bool executeFile(QWidget* parent, const QFileInfo& targetInfo); + bool executeFileVirtualized(QWidget* parent, const QFileInfo& targetInfo); + bool previewFileWithAlternatives(QWidget* parent, QString filename); + bool previewFile(QWidget* parent, const QString& originName, const QString& path); void spawnBinary(const QFileInfo &binary, const QString &arguments = "", const QDir ¤tDirectory = QDir(), diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index e9d7ce06..d6764852 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -264,7 +264,7 @@ void OverwriteInfoDialog::createDirectoryTriggered() void OverwriteInfoDialog::on_explorerButton_clicked() { - ExploreFile(m_ModInfo->absolutePath()); + shell::ExploreFile(m_ModInfo->absolutePath()); } void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint &pos) -- cgit v1.3.1 From c82c7af678c088a6b94fc8a4a0f31fc9498e8220 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 26 May 2019 04:00:54 -0400 Subject: changed rest of ShellExecuteW() calls to use shell::Execute(), shell::OpenLink() or shell::OpenFile() --- src/downloadmanager.cpp | 4 ++-- src/modinfodialog.cpp | 3 +-- src/motddialog.cpp | 3 ++- src/organizercore.cpp | 14 ++++++++++++++ src/organizercore.h | 3 +++ src/overwriteinfodialog.cpp | 7 +------ src/problemsdialog.cpp | 3 ++- src/selfupdater.cpp | 19 ++++++------------- src/settings.cpp | 23 ++++++++++++----------- 9 files changed, 43 insertions(+), 36 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 1412df51..ecc3cfd6 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -1030,10 +1030,10 @@ void DownloadManager::openFile(int index) reportError(tr("OpenFile: invalid download index %1").arg(index)); return; } + QDir path = QDir(m_OutputDirectory); if (path.exists(getFileName(index))) { - - ::ShellExecuteW(nullptr, L"open", ToWString(QDir::toNativeSeparators(getFilePath(index))).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + shell::OpenFile(getFilePath(index)); return; } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index c3ef7c47..19a03ea7 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1075,10 +1075,9 @@ void ModInfoDialog::linkClicked(const QUrl &url) //Ideally we'd ask the mod for the game and the web service then pass the game //and URL to the web service if (NexusInterface::instance(m_PluginContainer)->isURLGameRelated(url)) { - emit linkActivated(url.toString()); } else { - ::ShellExecuteW(nullptr, L"open", ToWString(url.toString()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + shell::OpenLink(url); } } diff --git a/src/motddialog.cpp b/src/motddialog.cpp index 96d88542..9be41d96 100644 --- a/src/motddialog.cpp +++ b/src/motddialog.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include "bbcode.h" #include "utility.h" #include "ui_motddialog.h" +#include "organizercore.h" #include MotDDialog::MotDDialog(const QString &message, QWidget *parent) @@ -43,5 +44,5 @@ void MotDDialog::on_okButton_clicked() void MotDDialog::linkClicked(const QUrl &url) { - ::ShellExecuteW(nullptr, L"open", MOBase::ToWString(url.toString()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + shell::OpenLink(url); } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 3a6b810e..a10c23d7 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -478,6 +478,20 @@ bool OpenFile(const QString& path) return ShellExecuteWrapper(L"open", ws_path.c_str(), nullptr); } +bool OpenLink(const QUrl& url) +{ + const auto ws_url = url.toString().toStdWString(); + return ShellExecuteWrapper(L"open", ws_url.c_str(), nullptr); +} + +bool Execute(const QString& program, const QString& params) +{ + const auto program_ws = program.toStdWString(); + const auto params_ws = params.toStdWString(); + + return ShellExecuteWrapper(L"open", program_ws.c_str(), params_ws.c_str()); +} + } // namespace shell diff --git a/src/organizercore.h b/src/organizercore.h index 41f0fd46..c9434e92 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -74,6 +74,9 @@ namespace shell bool ExploreFile(const QDir& dir); bool OpenFile(const QString& path); + bool OpenLink(const QUrl& url); + + bool Execute(const QString& program, const QString& params); } diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index d6764852..9b3e55df 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -218,12 +218,7 @@ void OverwriteInfoDialog::renameTriggered() void OverwriteInfoDialog::openFile(const QModelIndex &index) { - QString fileName = m_FileSystemModel->filePath(index); - - HINSTANCE res = ::ShellExecuteW(nullptr, L"open", ToWString(fileName).c_str(), nullptr, nullptr, SW_SHOW); - if ((INT_PTR)res <= 32) { - qCritical("failed to invoke %s: %d", qUtf8Printable(fileName), res); - } + shell::OpenFile(m_FileSystemModel->filePath(index)); } diff --git a/src/problemsdialog.cpp b/src/problemsdialog.cpp index 795baab0..56109d34 100644 --- a/src/problemsdialog.cpp +++ b/src/problemsdialog.cpp @@ -1,5 +1,6 @@ #include "problemsdialog.h" #include "ui_problemsdialog.h" +#include "organizercore.h" #include #include #include @@ -87,5 +88,5 @@ void ProblemsDialog::startFix() void ProblemsDialog::urlClicked(const QUrl &url) { - ::ShellExecuteW(nullptr, L"open", ToWString(url.toString()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); + shell::OpenLink(url); } diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 4c0f9a8d..271c621b 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see . #include "settings.h" #include "bbcode.h" #include "plugincontainer.h" +#include "organizercore.h" #include #include #include @@ -178,7 +179,7 @@ void SelfUpdater::startUpdate() tr("New update available (%1)") .arg(m_UpdateCandidate["tag_name"].toString()), tr("Do you want to install update? All your mods and setup will be left untouched.\nSelect Show Details option to see the full change-log."), QMessageBox::Yes | QMessageBox::Cancel, m_Parent); - + query.setDetailedText(m_UpdateCandidate["body"].toString()); query.button(QMessageBox::Yes)->setText(tr("Install")); @@ -329,22 +330,14 @@ void SelfUpdater::downloadCancel() void SelfUpdater::installUpdate() { - const QString mopath - = QDir::fromNativeSeparators(qApp->property("dataPath").toString()); - - std::wstring parameters = ToWString("/DIR=\"" + qApp->applicationDirPath() + "\" "); + const QString parameters = "/DIR=\"" + qApp->applicationDirPath() + "\" "; - HINSTANCE res = ::ShellExecuteW( - nullptr, L"open", m_UpdateFile.fileName().toStdWString().c_str(), parameters.c_str(), - nullptr, SW_SHOW); - - if (res > (HINSTANCE)32) { + if (shell::Execute(m_UpdateFile.fileName(), parameters)) { QCoreApplication::quit(); } else { - reportError(tr("Failed to start %1: %2") - .arg(m_UpdateFile.fileName()) - .arg((INT_PTR)res)); + reportError(tr("Failed to start %1").arg(m_UpdateFile.fileName())); } + m_UpdateFile.remove(); } diff --git a/src/settings.cpp b/src/settings.cpp index 231487bb..a844fdc9 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -130,18 +130,19 @@ bool Settings::pluginBlacklisted(const QString &fileName) const void Settings::registerAsNXMHandler(bool force) { - std::wstring nxmPath = ToWString(QCoreApplication::applicationDirPath() + "/nxmhandler.exe"); - std::wstring executable = ToWString(QCoreApplication::applicationFilePath()); - std::wstring mode = force ? L"forcereg" : L"reg"; - std::wstring parameters = mode + L" " + m_GamePlugin->gameShortName().toStdWString(); - for (QString altGame : m_GamePlugin->validShortNames()) { - parameters += L"," + altGame.toStdWString(); + const auto nxmPath = QCoreApplication::applicationDirPath() + "/nxmhandler.exe"; + const auto executable = QCoreApplication::applicationFilePath(); + + QString mode = force ? "forcereg" : "reg"; + QString parameters = mode + " " + m_GamePlugin->gameShortName(); + for (const QString& altGame : m_GamePlugin->validShortNames()) { + parameters += "," + altGame; } - parameters += L" \"" + executable + L"\""; - HINSTANCE res = ::ShellExecuteW(nullptr, L"open", nxmPath.c_str(), parameters.c_str(), nullptr, SW_SHOWNORMAL); - if ((INT_PTR)res <= 32) { - QMessageBox::critical(nullptr, tr("Failed"), - tr("Sorry, failed to start the helper application")); + parameters += " \"" + executable + "\""; + + if (!shell::Execute(nxmPath, parameters)) { + QMessageBox::critical( + nullptr, tr("Failed"), tr("Failed to start the helper application")); } } -- cgit v1.3.1 From 0439e18fe4cd2500c4ab6b3ff219c53153cf2175 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 26 May 2019 05:31:02 -0400 Subject: changed enum case to follow convention --- src/mainwindow.cpp | 4 ++-- src/organizercore.cpp | 12 ++++++------ src/organizercore.h | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 94cbe9b1..b1728617 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -5163,7 +5163,7 @@ void MainWindow::addAsExecutable() switch (type) { - case FileExecutionTypes::executable: { + case FileExecutionTypes::Executable: { QString name = QInputDialog::getText(this, tr("Enter Name"), tr("Please enter a name for the executable"), QLineEdit::Normal, targetInfo.baseName()); @@ -5182,7 +5182,7 @@ void MainWindow::addAsExecutable() break; } - case FileExecutionTypes::other: // fall-through + case FileExecutionTypes::Other: // fall-through default: { QMessageBox::information(this, tr("Not an executable"), tr("This is not a recognized executable.")); break; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index a10c23d7..04c94164 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -279,11 +279,11 @@ bool GetFileExecutionContext( (extension.compare("bat", Qt::CaseInsensitive) == 0)) { binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe"); arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - type = FileExecutionTypes::executable; + type = FileExecutionTypes::Executable; return true; } else if (extension.compare("exe", Qt::CaseInsensitive) == 0) { binaryInfo = targetInfo; - type = FileExecutionTypes::executable; + type = FileExecutionTypes::Executable; return true; } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) { // types that need to be injected into @@ -323,10 +323,10 @@ bool GetFileExecutionContext( arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); } - type = FileExecutionTypes::executable; + type = FileExecutionTypes::Executable; return true; } else { - type = FileExecutionTypes::other; + type = FileExecutionTypes::Other; return true; } } @@ -1461,7 +1461,7 @@ bool OrganizerCore::executeFileVirtualized( switch (type) { - case FileExecutionTypes::executable: { + case FileExecutionTypes::Executable: { spawnBinaryDirect( binaryInfo, arguments, currentProfile()->name(), targetInfo.absolutePath(), "", ""); @@ -1469,7 +1469,7 @@ bool OrganizerCore::executeFileVirtualized( return true; } - case FileExecutionTypes::other: { + case FileExecutionTypes::Other: { ::ShellExecuteW(nullptr, L"open", ToWString(targetInfo.absoluteFilePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); diff --git a/src/organizercore.h b/src/organizercore.h index c9434e92..6f9defc2 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -59,8 +59,8 @@ namespace MOBase { enum class FileExecutionTypes { - executable = 1, - other = 2 + Executable = 1, + Other = 2 }; bool GetFileExecutionContext( -- cgit v1.3.1 From 21185182c6551d053cccdcf087e0c219a3785cf8 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 26 May 2019 06:18:11 -0400 Subject: moved getFileExecutionContext() and its enum into OrganizerCore --- src/mainwindow.cpp | 4 +- src/organizercore.cpp | 127 +++++++++++++++++++++++++------------------------- src/organizercore.h | 20 ++++---- 3 files changed, 76 insertions(+), 75 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index b1728617..810caa01 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -5152,12 +5152,14 @@ void MainWindow::addAsExecutable() return; } + using FileExecutionTypes = OrganizerCore::FileExecutionTypes; + QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString()); QFileInfo binaryInfo; QString arguments; FileExecutionTypes type; - if (!GetFileExecutionContext(this, targetInfo, binaryInfo, arguments, type)) { + if (!OrganizerCore::getFileExecutionContext(this, targetInfo, binaryInfo, arguments, type)) { return; } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 04c94164..d3de3e01 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -269,69 +269,6 @@ bool checkService() } -bool GetFileExecutionContext( - QWidget* parent, const QFileInfo &targetInfo, - QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type) -{ - QString extension = targetInfo.suffix(); - if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) || - (extension.compare("com", Qt::CaseInsensitive) == 0) || - (extension.compare("bat", Qt::CaseInsensitive) == 0)) { - binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe"); - arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - type = FileExecutionTypes::Executable; - return true; - } else if (extension.compare("exe", Qt::CaseInsensitive) == 0) { - binaryInfo = targetInfo; - type = FileExecutionTypes::Executable; - return true; - } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) { - // types that need to be injected into - std::wstring targetPathW = targetInfo.absoluteFilePath().toStdWString(); - QString binaryPath; - - { // try to find java automatically - WCHAR buffer[MAX_PATH]; - if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { - DWORD binaryType = 0UL; - if (!::GetBinaryTypeW(buffer, &binaryType)) { - qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); - } else if (binaryType == SCS_32BIT_BINARY) { - binaryPath = QString::fromWCharArray(buffer); - } - } - } - if (binaryPath.isEmpty() && (extension == "jar")) { - // second attempt: look to the registry - 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()) { - binaryPath = QFileDialog::getOpenFileName( - parent, QObject::tr("Select binary"), QString(), QObject::tr("Binary") + " (*.exe)"); - } - if (binaryPath.isEmpty()) { - return false; - } - binaryInfo = QFileInfo(binaryPath); - if (extension == "jar") { - arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - } else { - arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - } - - type = FileExecutionTypes::Executable; - return true; - } else { - type = FileExecutionTypes::Other; - return true; - } -} - - const char* ShellExecuteError(int i) { switch (i) { @@ -1448,6 +1385,68 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const return res; } +bool OrganizerCore::getFileExecutionContext( + QWidget* parent, const QFileInfo &targetInfo, + QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type) +{ + QString extension = targetInfo.suffix(); + if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) || + (extension.compare("com", Qt::CaseInsensitive) == 0) || + (extension.compare("bat", Qt::CaseInsensitive) == 0)) { + binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe"); + arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + type = FileExecutionTypes::Executable; + return true; + } else if (extension.compare("exe", Qt::CaseInsensitive) == 0) { + binaryInfo = targetInfo; + type = FileExecutionTypes::Executable; + return true; + } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) { + // types that need to be injected into + std::wstring targetPathW = targetInfo.absoluteFilePath().toStdWString(); + QString binaryPath; + + { // try to find java automatically + WCHAR buffer[MAX_PATH]; + if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { + DWORD binaryType = 0UL; + if (!::GetBinaryTypeW(buffer, &binaryType)) { + qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); + } else if (binaryType == SCS_32BIT_BINARY) { + binaryPath = QString::fromWCharArray(buffer); + } + } + } + if (binaryPath.isEmpty() && (extension == "jar")) { + // second attempt: look to the registry + 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()) { + binaryPath = QFileDialog::getOpenFileName( + parent, QObject::tr("Select binary"), QString(), QObject::tr("Binary") + " (*.exe)"); + } + if (binaryPath.isEmpty()) { + return false; + } + binaryInfo = QFileInfo(binaryPath); + if (extension == "jar") { + arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + } else { + arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + } + + type = FileExecutionTypes::Executable; + return true; + } else { + type = FileExecutionTypes::Other; + return true; + } +} + bool OrganizerCore::executeFileVirtualized( QWidget* parent, const QFileInfo& targetInfo) { @@ -1455,7 +1454,7 @@ bool OrganizerCore::executeFileVirtualized( QString arguments; FileExecutionTypes type; - if (!GetFileExecutionContext(parent, targetInfo, binaryInfo, arguments, type)) { + if (!getFileExecutionContext(parent, targetInfo, binaryInfo, arguments, type)) { return false; } diff --git a/src/organizercore.h b/src/organizercore.h index 6f9defc2..9c4e3ae2 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -57,16 +57,6 @@ namespace MOBase { } -enum class FileExecutionTypes -{ - Executable = 1, - Other = 2 -}; - -bool GetFileExecutionContext( - QWidget* parent, const QFileInfo &targetInfo, - QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); - namespace shell { bool ExploreFile(const QFileInfo& info); @@ -111,6 +101,12 @@ private: typedef boost::signals2::signal SignalModInstalled; public: + enum class FileExecutionTypes + { + Executable = 1, + Other = 2 + }; + static bool isNxmLink(const QString &link) { return link.startsWith("nxm://", Qt::CaseInsensitive); } OrganizerCore(const QSettings &initSettings); @@ -164,6 +160,10 @@ public: void doAfterLogin(const std::function &function) { m_PostLoginTasks.append(function); } + static bool getFileExecutionContext( + QWidget* parent, const QFileInfo &targetInfo, + QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); + bool executeFileVirtualized(QWidget* parent, const QFileInfo& targetInfo); bool previewFileWithAlternatives(QWidget* parent, QString filename); bool previewFile(QWidget* parent, const QString& originName, const QString& path); -- cgit v1.3.1 From fce3c9f8c3058d9975ccc634be3572a431c1a50d Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 26 May 2019 06:52:45 -0400 Subject: moved shell functions to uibase --- src/motddialog.cpp | 3 + src/organizercore.cpp | 163 -------------------------------------------------- src/organizercore.h | 13 ---- 3 files changed, 3 insertions(+), 176 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/motddialog.cpp b/src/motddialog.cpp index 9be41d96..ca1e60ad 100644 --- a/src/motddialog.cpp +++ b/src/motddialog.cpp @@ -22,8 +22,11 @@ along with Mod Organizer. If not, see . #include "utility.h" #include "ui_motddialog.h" #include "organizercore.h" +#include #include +using namespace MOBase; + MotDDialog::MotDDialog(const QString &message, QWidget *parent) : QDialog(parent), ui(new Ui::MotDDialog) { diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d3de3e01..19b53b8d 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -269,169 +269,6 @@ bool checkService() } -const char* ShellExecuteError(int i) -{ - switch (i) { - case 0: - return "The operating system is out of memory or resources"; - - case ERROR_FILE_NOT_FOUND: - return "The specified file was not found"; - - case ERROR_PATH_NOT_FOUND: - return "The specified path was not found"; - - case ERROR_BAD_FORMAT: - return "The .exe file is invalid (non-Win32 .exe or error in .exe image)"; - - case SE_ERR_ACCESSDENIED: - return "The operating system denied access to the specified file"; - - case SE_ERR_ASSOCINCOMPLETE: - return "The file name association is incomplete or invalid"; - - case SE_ERR_DDEBUSY: - return "The DDE transaction could not be completed because other DDE " - "transactions were being processed"; - - case SE_ERR_DDEFAIL: - return "The DDE transaction failed"; - - case SE_ERR_DDETIMEOUT: - return "The DDE transaction could not be completed because the request " - "timed out"; - - case SE_ERR_DLLNOTFOUND: - return "The specified DLL was not found"; - - case SE_ERR_NOASSOC: - return "There is no application associated with the given file name " - "extension"; - - case SE_ERR_OOM: - return "There was not enough memory to complete the operation"; - - case SE_ERR_SHARE: - return "A sharing violation occurred"; - - default: - return "Unknown error"; - } -} - -void LogShellFailure( - const wchar_t* operation, const wchar_t* file, const wchar_t* params, - HINSTANCE h) -{ - const auto code = static_cast(reinterpret_cast(h)); - - QString s = "failed to invoke"; - - if (operation) { - s += " " + QString::fromWCharArray(operation); - } - - if (file) { - s += " " + QString::fromWCharArray(file); - } - - if (params) { - s += " " + QString::fromWCharArray(params); - } - - qCritical( - "failed to invoke %s: %s (error %d)", - s, ShellExecuteError(code), code); -} - -bool ShellExecuteWrapper( - const wchar_t* operation, const wchar_t* file, const wchar_t* params) -{ - const auto h = ::ShellExecuteW( - 0, operation, file, params, nullptr, SW_SHOWNORMAL); - - // anything <= 32 is not an actual HINSTANCE and signals failure - if (h <= reinterpret_cast(32)) - { - LogShellFailure(operation, file, params, h); - return false; - } - - return true; -} - -bool ExploreDirectory(const QFileInfo& info) -{ - const auto path = QDir::toNativeSeparators(info.absoluteFilePath()); - const auto ws_path = path.toStdWString(); - - return ShellExecuteWrapper(L"explore", ws_path.c_str(), nullptr); -} - -bool ExploreFileInDirectory(const QFileInfo& info) -{ - const auto path = QDir::toNativeSeparators(info.absoluteFilePath()); - const auto params = "/select,\"" + path + "\""; - const auto ws_params = params.toStdWString(); - - return ShellExecuteWrapper(nullptr, L"explorer", ws_params.c_str()); -} - - -namespace shell -{ - -bool ExploreFile(const QFileInfo& info) -{ - if (info.isFile()) { - return ExploreFileInDirectory(info); - } else if (info.isDir()) { - return ExploreDirectory(info); - } else { - // try the parent directory - const auto parent = info.dir(); - - if (parent.exists()) { - return ExploreDirectory(parent.absolutePath()); - } - } - - return false; -} - -bool ExploreFile(const QString& path) -{ - return ExploreFile(QFileInfo(path)); -} - -bool ExploreFile(const QDir& dir) -{ - return ExploreFile(QFileInfo(dir.absolutePath())); -} - -bool OpenFile(const QString& path) -{ - const auto ws_path = path.toStdWString(); - return ShellExecuteWrapper(L"open", ws_path.c_str(), nullptr); -} - -bool OpenLink(const QUrl& url) -{ - const auto ws_url = url.toString().toStdWString(); - return ShellExecuteWrapper(L"open", ws_url.c_str(), nullptr); -} - -bool Execute(const QString& program, const QString& params) -{ - const auto program_ws = program.toStdWString(); - const auto params_ws = params.toStdWString(); - - return ShellExecuteWrapper(L"open", program_ws.c_str(), params_ws.c_str()); -} - -} // namespace shell - - OrganizerCore::OrganizerCore(const QSettings &initSettings) : m_UserInterface(nullptr) , m_PluginContainer(nullptr) diff --git a/src/organizercore.h b/src/organizercore.h index 9c4e3ae2..e24227b7 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -57,19 +57,6 @@ namespace MOBase { } -namespace shell -{ - bool ExploreFile(const QFileInfo& info); - bool ExploreFile(const QString& path); - bool ExploreFile(const QDir& dir); - - bool OpenFile(const QString& path); - bool OpenLink(const QUrl& url); - - bool Execute(const QString& program, const QString& params); -} - - class OrganizerCore : public QObject, public MOBase::IPluginDiagnose { -- cgit v1.3.1 From 5716676e083bde4a6f2ddb57a683df85b96c2d04 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 26 May 2019 08:14:21 -0400 Subject: fixes for /permissive-: - no implicit conversions for enum classes - can't bind rvalue to non-const ref - string literals are const --- src/forcedloaddialogwidget.cpp | 8 ++++---- src/forcedloaddialogwidget.h | 4 ++-- src/instancemanager.cpp | 2 +- src/organizercore.cpp | 2 +- src/settingsdialog.cpp | 2 +- src/settingsdialog.h | 2 +- src/usvfsconnector.cpp | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/forcedloaddialogwidget.cpp b/src/forcedloaddialogwidget.cpp index 10069c35..b92838c3 100644 --- a/src/forcedloaddialogwidget.cpp +++ b/src/forcedloaddialogwidget.cpp @@ -54,12 +54,12 @@ void ForcedLoadDialogWidget::setForced(bool forced) ui->processEdit->setEnabled(!forced); } -void ForcedLoadDialogWidget::setLibraryPath(QString &path) +void ForcedLoadDialogWidget::setLibraryPath(const QString &path) { ui->libraryPathEdit->setText(path); } -void ForcedLoadDialogWidget::setProcess(QString &name) +void ForcedLoadDialogWidget::setProcess(const QString &name) { ui->processEdit->setText(name); } @@ -71,7 +71,7 @@ void ForcedLoadDialogWidget::on_enabledBox_toggled() void ForcedLoadDialogWidget::on_libraryPathBrowseButton_clicked() { - QDir gameDir(m_GamePlugin->gameDirectory()); + QDir gameDir(m_GamePlugin->gameDirectory()); QString startPath = gameDir.absolutePath(); QString result = QFileDialog::getOpenFileName(nullptr, "Select a library...", startPath, "Dynamic link library (*.dll)", nullptr, QFileDialog::ReadOnly); if (!result.isEmpty()) { @@ -100,7 +100,7 @@ void ForcedLoadDialogWidget::on_processBrowseButton_clicked() QString fileName = fileInfo.fileName(); if (fileInfo.exists()) { - ui->processEdit->setText(fileName); + ui->processEdit->setText(fileName); } else { qCritical("%ls does not exist", fileInfo.filePath().toStdWString().c_str()); } diff --git a/src/forcedloaddialogwidget.h b/src/forcedloaddialogwidget.h index eb7c3f4d..239653c8 100644 --- a/src/forcedloaddialogwidget.h +++ b/src/forcedloaddialogwidget.h @@ -23,8 +23,8 @@ public: void setEnabled(bool enabled); void setForced(bool forced); - void setLibraryPath(QString &path); - void setProcess(QString &name); + void setLibraryPath(const QString &path); + void setProcess(const QString &name); private slots: void on_enabledBox_toggled(); diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index 1c65f635..5b57827a 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -227,7 +227,7 @@ QString InstanceManager::chooseInstance(const QStringList &instanceList) const if (choice.type() == QVariant::String) { return choice.toString(); } else { - switch (choice.value()) { + switch (static_cast(choice.value())) { case Special::NewInstance: return queryInstanceName(instanceList); case Special::Portable: return QString(); case Special::Manage: { diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 8212d248..9488f83a 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -111,7 +111,7 @@ static bool renameFile(const QString &oldName, const QString &newName, static std::wstring getProcessName(HANDLE process) { wchar_t buffer[MAX_PATH]; - wchar_t *fileName = L"unknown"; + const wchar_t *fileName = L"unknown"; if (process == nullptr) return fileName; diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 74091469..7f53a9bb 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -88,7 +88,7 @@ QString SettingsDialog::getColoredButtonStyleSheet() const "}"); } -void SettingsDialog::setButtonColor(QPushButton *button, QColor &color) +void SettingsDialog::setButtonColor(QPushButton *button, const QColor &color) { button->setStyleSheet( QString("QPushButton {" diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 92a97c3f..afe988bd 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -53,7 +53,7 @@ public: */ QString getColoredButtonStyleSheet() const; - void setButtonColor(QPushButton *button, QColor &color); + void setButtonColor(QPushButton *button, const QColor &color); public slots: diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index 5ad19fb0..b752667d 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -92,7 +92,7 @@ void LogWorker::exit() LogLevel logLevel(int level) { - switch (level) { + switch (static_cast(level)) { case LogLevel::Info: return LogLevel::Info; case LogLevel::Warning: @@ -106,7 +106,7 @@ LogLevel logLevel(int level) CrashDumpsType crashDumpsType(int type) { - switch (type) { + switch (static_cast(type)) { case CrashDumpsType::Mini: return CrashDumpsType::Mini; case CrashDumpsType::Data: -- cgit v1.3.1 From adb5ace7997c4cf8ed5e0bee726478c8e1593524 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 10:14:15 -0400 Subject: added selectedOrigin to previewFileWithAlternatives() this is so that an origin other than the primary can be shown first and is used from previewDataFile() in ModInfoDialog since showing a preview for a conflicting file could initially show the file from the wrong mod removed unused, uninitialized and dangerous ModInfoDialog::m_OriginID --- src/modinfodialog.cpp | 4 +++- src/modinfodialog.h | 1 - src/organizercore.cpp | 41 +++++++++++++++++++++++++++++++++++++---- src/organizercore.h | 2 +- 4 files changed, 41 insertions(+), 7 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 024679f3..fd8093d1 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1740,8 +1740,10 @@ void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) return; } + const int originId = (m_Origin ? m_Origin->getID() : -1); + QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->previewFileWithAlternatives(this, fileName); + m_OrganizerCore->previewFileWithAlternatives(this, fileName, originId); } bool ModInfoDialog::canPreviewFile(bool isArchive, const QString& filename) const diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 983da8d4..5f7d831b 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -397,7 +397,6 @@ private: Ui::ModInfoDialog *ui; ModInfo::Ptr m_ModInfo; - int m_OriginID; QSignalMapper m_ThumbnailMapper; QString m_RootPath; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 19b53b8d..00292e32 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1319,7 +1319,7 @@ bool OrganizerCore::executeFileVirtualized( } bool OrganizerCore::previewFileWithAlternatives( - QWidget* parent, QString fileName) + QWidget* parent, QString fileName, int selectedOrigin) { // what we have is an absolute path to the file in its actual location (for the primary origin) // what we want is the path relative to the virtual data directory @@ -1370,9 +1370,42 @@ bool OrganizerCore::previewFileWithAlternatives( } }; - addFunc(file->getOrigin()); - for (auto alt : file->getAlternatives()) { - addFunc(alt.first); + if (selectedOrigin == -1) { + // don't bother with the vector of origins, just add them as they come + addFunc(file->getOrigin()); + for (auto alt : file->getAlternatives()) { + addFunc(alt.first); + } + } else { + std::vector origins; + + // start with the primary origin + origins.push_back(file->getOrigin()); + + // add other origins, push to front if it's the selected one + for (auto alt : file->getAlternatives()) { + if (alt.first == selectedOrigin) { + origins.insert(origins.begin(), alt.first); + } else { + origins.push_back(alt.first); + } + } + + // can't be empty; either the primary origin was the selected one, or it + // was one of the alternatives, which got inserted in front + + if (origins[0] != selectedOrigin) { + // sanity check, this shouldn't happen unless the caller passed an + // incorrect id + + qWarning().nospace() + << "selected preview origin " << selectedOrigin << " not found in " + << "list of alternatives"; + } + + for (int id : origins) { + addFunc(id); + } } if (preview.numVariants() > 0) { diff --git a/src/organizercore.h b/src/organizercore.h index e24227b7..8ed34e24 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -152,7 +152,7 @@ public: QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); bool executeFileVirtualized(QWidget* parent, const QFileInfo& targetInfo); - bool previewFileWithAlternatives(QWidget* parent, QString filename); + bool previewFileWithAlternatives(QWidget* parent, QString filename, int selectedOrigin=-1); bool previewFile(QWidget* parent, const QString& originName, const QString& path); void spawnBinary(const QFileInfo &binary, const QString &arguments = "", -- cgit v1.3.1 From 0f6f0c23943116ea668ab035055cb8b0e4a6574e Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 May 2019 12:49:25 -0400 Subject: replaced all the manual UserRole stuff with a few constants and helper functions setConflictItem() is now used by all conflict lists to setup the data (filename, archive, etc.) and visuals (italic for archives) merged openDataFile() and previewDataFile() into their caller as they weren't used anywhere else previewDataFile() used to do a fromNativeSeparators() before previewing, moved that to previewFileWithAlternatives() instead brought overwrittenTree double click in line with overwriteTree, there's no difference between apply() and close() because there's only a close button --- src/modinfodialog.cpp | 133 +++++++++++++++++++++++++++----------------------- src/modinfodialog.h | 10 +++- src/modinfodialog.ui | 9 ++++ src/organizercore.cpp | 2 + 4 files changed, 91 insertions(+), 63 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 1dd44112..e639dcc7 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -57,6 +57,10 @@ along with Mod Organizer. If not, see . using namespace MOBase; using namespace MOShared; +const auto FILENAME_USERROLE = Qt::UserRole + 1; +const auto ORIGIN_USERROLE = Qt::UserRole + 2; +const auto ARCHIVE_USERROLE = Qt::UserRole + 3; + class ModFileListWidget : public QListWidgetItem { friend bool operator<(const ModFileListWidget &LHS, const ModFileListWidget &RHS); @@ -744,18 +748,10 @@ QTreeWidgetItem* ModInfoDialog::createOverwriteItem( QStringList fields(relativeName); fields.append(altString); - QTreeWidgetItem *item = new QTreeWidgetItem(fields); - item->setData(0, Qt::UserRole, fileName); - item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives.back().first).getName())); - item->setData(1, Qt::UserRole + 1, alternatives.back().first); - item->setData(1, Qt::UserRole + 2, archive); + const auto origin = ToQString(m_Directory->getOriginByID(alternatives.back().first).getName()); - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - item->setFont(1, font); - } + QTreeWidgetItem *item = new QTreeWidgetItem(fields); + setConflictItem(item, fileName, origin, archive); return item; } @@ -764,13 +760,7 @@ QTreeWidgetItem* ModInfoDialog::createNoConflictItem( bool archive, const QString& fileName, const QString& relativeName) { QTreeWidgetItem *item = new QTreeWidgetItem(QStringList({relativeName})); - item->setData(0, Qt::UserRole, fileName); - - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - } + setConflictItem(item, fileName, "", archive); return item; } @@ -785,16 +775,7 @@ QTreeWidgetItem* ModInfoDialog::createOverwrittenItem( fields.append(ToQString(realOrigin.getName())); QTreeWidgetItem *item = new QTreeWidgetItem(fields); - item->setData(0, Qt::UserRole, fileName); - item->setData(1, Qt::UserRole, ToQString(realOrigin.getName())); - item->setData(1, Qt::UserRole + 2, archive); - - if (archive) { - QFont font = item->font(0); - font.setItalic(true); - item->setFont(0, font); - item->setFont(1, font); - } + setConflictItem(item, fileName, ToQString(realOrigin.getName()), archive); return item; } @@ -908,9 +889,44 @@ QTreeWidgetItem* ModInfoDialog::createAdvancedConflictItem( item->setText(1, relativeName); item->setText(2, after); + setConflictItem(item, fileName, "", archive); + return item; } +void ModInfoDialog::setConflictItem( + QTreeWidgetItem* item, + const QString& fileName, const QString& origin, bool archive) const +{ + item->setData(0, FILENAME_USERROLE, fileName); + item->setData(0, ORIGIN_USERROLE, origin); + item->setData(0, ARCHIVE_USERROLE, archive); + + if (archive) { + QFont font = item->font(0); + font.setItalic(true); + + for (int i=0; icolumnCount(); ++i) { + item->setFont(i, font); + } + } +} + +QString ModInfoDialog::conflictFileName(const QTreeWidgetItem* conflictItem) const +{ + return conflictItem->data(0, FILENAME_USERROLE).toString(); +} + +QString ModInfoDialog::conflictOrigin(const QTreeWidgetItem* conflictItem) const +{ + return conflictItem->data(0, ORIGIN_USERROLE).toString(); +} + +bool ModInfoDialog::conflictIsArchive(const QTreeWidgetItem* conflictItem) const +{ + return conflictItem->data(0, ARCHIVE_USERROLE).toBool(); +} + void ModInfoDialog::refreshFiles() { if (m_RootPath.length() > 0) { @@ -1860,8 +1876,12 @@ void ModInfoDialog::on_primaryCategoryBox_currentIndexChanged(int index) void ModInfoDialog::on_overwriteTree_itemDoubleClicked(QTreeWidgetItem *item, int) { - this->close(); - emit modOpen(item->data(1, Qt::UserRole).toString(), TAB_CONFLICTS); + const auto origin = conflictOrigin(item); + + if (!origin.isEmpty()) { + close(); + emit modOpen(origin, TAB_CONFLICTS); + } } FileRenamer::RenameResults ModInfoDialog::hideFile(FileRenamer& renamer, const QString &oldName) @@ -1907,14 +1927,14 @@ void ModInfoDialog::changeConflictItemsVisibility( qDebug().nospace() << "cannot unhide " << item->text(0) << ", skipping"; continue; } - result = unhideFile(renamer, item->data(0, Qt::UserRole).toString()); + result = unhideFile(renamer, conflictFileName(item)); } else { if (!canHideConflictItem(item)) { qDebug().nospace() << "cannot hide " << item->text(0) << ", skipping"; continue; } - result = hideFile(renamer, item->data(0, Qt::UserRole).toString()); + result = hideFile(renamer, conflictFileName(item)); } switch (result) { @@ -1953,7 +1973,9 @@ void ModInfoDialog::openConflictItems(const QList& items) // the menu item is only shown for a single selection, but handle all of them // in case this changes for (auto* item : items) { - openDataFile(item); + if (item) { + m_OrganizerCore->executeFileVirtualized(this, conflictFileName(item)); + } } } @@ -1962,28 +1984,10 @@ void ModInfoDialog::previewConflictItems(const QList& items) // the menu item is only shown for a single selection, but handle all of them // in case this changes for (auto* item : items) { - previewDataFile(item); - } -} - -void ModInfoDialog::openDataFile(const QTreeWidgetItem* item) -{ - if (!item) { - return; - } - - QFileInfo targetInfo(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->executeFileVirtualized(this, targetInfo); -} - -void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) -{ - if (!item) { - return; + if (item) { + m_OrganizerCore->previewFileWithAlternatives(this, conflictFileName(item)); + } } - - QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->previewFileWithAlternatives(this, fileName); } bool ModInfoDialog::canPreviewFile(bool isArchive, const QString& filename) const @@ -2028,19 +2032,17 @@ bool ModInfoDialog::canUnhideFile(bool isArchive, const QString& filename) const bool ModInfoDialog::canHideConflictItem(const QTreeWidgetItem* item) const { - return canHideFile(item->data(1, Qt::UserRole + 2).toBool(), item->text(0)); + return canHideFile(conflictIsArchive(item), conflictFileName(item)); } bool ModInfoDialog::canUnhideConflictItem(const QTreeWidgetItem* item) const { - return canUnhideFile(item->data(1, Qt::UserRole + 2).toBool(), item->text(0)); + return canUnhideFile(conflictIsArchive(item), conflictFileName(item)); } bool ModInfoDialog::canPreviewConflictItem(const QTreeWidgetItem* item) const { - return canPreviewFile( - item->data(1, Qt::UserRole + 2).toBool(), - item->data(0, Qt::UserRole).toString()); + return canPreviewFile(conflictIsArchive(item), conflictFileName(item)); } void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &pos) @@ -2058,6 +2060,11 @@ void ModInfoDialog::on_noConflictTree_customContextMenuRequested(const QPoint &p showConflictMenu(pos, ui->noConflictTree); } +void ModInfoDialog::on_conflictsAdvancedList_customContextMenuRequested(const QPoint &pos) +{ + showConflictMenu(pos, ui->conflictsAdvancedList); +} + void ModInfoDialog::showConflictMenu(const QPoint &pos, QTreeWidget* tree) { auto actions = createConflictMenuActions(tree->selectedItems()); @@ -2181,8 +2188,12 @@ ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( void ModInfoDialog::on_overwrittenTree_itemDoubleClicked(QTreeWidgetItem *item, int) { - emit modOpen(item->data(1, Qt::UserRole).toString(), TAB_CONFLICTS); - this->accept(); + const auto origin = conflictOrigin(item); + + if (!origin.isEmpty()) { + close(); + emit modOpen(origin, TAB_CONFLICTS); + } } void ModInfoDialog::on_refreshButton_clicked() diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 40e45eb4..59912127 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -368,6 +368,7 @@ private slots: void on_overwriteTree_customContextMenuRequested(const QPoint &pos); void on_overwrittenTree_customContextMenuRequested(const QPoint &pos); void on_noConflictTree_customContextMenuRequested(const QPoint &pos); + void on_conflictsAdvancedList_customContextMenuRequested(const QPoint &pos); void on_fileTree_customContextMenuRequested(const QPoint &pos); void on_refreshButton_clicked(); @@ -450,6 +451,13 @@ private: const QString& fileName, const QString& relativeName, const MOShared::FileEntry::AlternativesVector& alternatives); + void setConflictItem( + QTreeWidgetItem* item, + const QString& fileName, const QString& origin, bool archive) const; + + QString conflictFileName(const QTreeWidgetItem* conflictItem) const; + QString conflictOrigin(const QTreeWidgetItem* conflictItem) const; + bool conflictIsArchive(const QTreeWidgetItem* conflictItem) const; void restoreTabState(const QByteArray &state); void restoreConflictsState(const QByteArray &state); @@ -461,8 +469,6 @@ private: bool canUnhideConflictItem(const QTreeWidgetItem* item) const; bool canPreviewConflictItem(const QTreeWidgetItem* item) const; - void openDataFile(const QTreeWidgetItem* item); - void previewDataFile(const QTreeWidgetItem* item); void changeFiletreeVisibility(bool visible); void openConflictItems(const QList& items); diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 8744b216..93291c02 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -707,6 +707,15 @@ text-align: left; + + Qt::CustomContextMenu + + + QAbstractItemView::ExtendedSelection + + + true + 3 diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 3ad4e586..892162f6 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1321,6 +1321,8 @@ bool OrganizerCore::executeFileVirtualized( bool OrganizerCore::previewFileWithAlternatives( QWidget* parent, QString fileName, int selectedOrigin) { + fileName = QDir::fromNativeSeparators(fileName); + // what we have is an absolute path to the file in its actual location (for the primary origin) // what we want is the path relative to the virtual data directory -- cgit v1.3.1 From 5fb26b2dcbfae9d6a1aaac9d61f017bacf572f09 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 7 Jun 2019 17:15:44 -0400 Subject: made Executable members private, added member function to get and set them --- src/editexecutablesdialog.cpp | 32 ++++----- src/executableslist.cpp | 149 ++++++++++++++++++++++++++++++++---------- src/executableslist.h | 50 ++++++++++---- src/mainwindow.cpp | 50 +++++++------- src/mainwindow.h | 2 +- src/organizercore.cpp | 42 ++++++------ 6 files changed, 215 insertions(+), 110 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 177661ff..67fbff31 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -71,7 +71,7 @@ void EditExecutablesDialog::refreshExecutablesWidget() m_ExecutablesList.getExecutables(current, end); for(; current != end; ++current) { - QListWidgetItem *newItem = new QListWidgetItem(current->m_Title); + QListWidgetItem *newItem = new QListWidgetItem(current->title()); newItem->setTextColor(current->isCustom() ? QColor(Qt::black) : QColor(Qt::darkGray)); ui->executablesListBox->addItem(newItem); } @@ -284,10 +284,10 @@ bool EditExecutablesDialog::executableChanged() if (m_CurrentItem != nullptr) { Executable const &selectedExecutable(m_ExecutablesList.find(m_CurrentItem->text())); - QString storedCustomOverwrite = m_Profile->setting("custom_overwrites", selectedExecutable.m_Title).toString(); + QString storedCustomOverwrite = m_Profile->setting("custom_overwrites", selectedExecutable.title()).toString(); bool forcedLibrariesDirty = false; - auto forcedLibaries = m_Profile->determineForcedLibraries(selectedExecutable.m_Title); + auto forcedLibaries = m_Profile->determineForcedLibraries(selectedExecutable.title()); forcedLibrariesDirty |= !std::equal(forcedLibaries.begin(), forcedLibaries.end(), m_ForcedLibraries.begin(), m_ForcedLibraries.end(), [](const ExecutableForcedLoadSetting &lhs, const ExecutableForcedLoadSetting &rhs) @@ -300,13 +300,13 @@ bool EditExecutablesDialog::executableChanged() forcedLibrariesDirty |= m_Profile->setting("forced_libraries", ui->titleEdit->text() + "/enabled", false).toBool() != ui->forceLoadCheckBox->isChecked(); - return selectedExecutable.m_Title != ui->titleEdit->text() - || selectedExecutable.m_Arguments != ui->argumentsEdit->text() - || selectedExecutable.m_SteamAppID != ui->appIDOverwriteEdit->text() + return selectedExecutable.title() != ui->titleEdit->text() + || selectedExecutable.arguments() != ui->argumentsEdit->text() + || selectedExecutable.steamAppID() != ui->appIDOverwriteEdit->text() || !storedCustomOverwrite.isEmpty() != ui->newFilesModCheckBox->isChecked() || !storedCustomOverwrite.isEmpty() && (storedCustomOverwrite != ui->newFilesModBox->currentText()) - || selectedExecutable.m_WorkingDirectory != QDir::fromNativeSeparators(ui->workingDirEdit->text()) - || selectedExecutable.m_BinaryInfo.absoluteFilePath() != QDir::fromNativeSeparators(ui->binaryEdit->text()) + || selectedExecutable.workingDirectory() != QDir::fromNativeSeparators(ui->workingDirEdit->text()) + || selectedExecutable.binaryInfo().absoluteFilePath() != QDir::fromNativeSeparators(ui->binaryEdit->text()) || selectedExecutable.usesOwnIcon() != ui->useAppIconCheckBox->isChecked() || forcedLibrariesDirty ; @@ -376,14 +376,14 @@ void EditExecutablesDialog::on_executablesListBox_clicked(const QModelIndex &cur Executable const &selectedExecutable(m_ExecutablesList.find(m_CurrentItem->text())); - 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->titleEdit->setText(selectedExecutable.title()); + ui->binaryEdit->setText(QDir::toNativeSeparators(selectedExecutable.binaryInfo().absoluteFilePath())); + ui->argumentsEdit->setText(selectedExecutable.arguments()); + ui->workingDirEdit->setText(QDir::toNativeSeparators(selectedExecutable.workingDirectory())); ui->removeButton->setEnabled(selectedExecutable.isCustom()); - ui->overwriteAppIDBox->setChecked(!selectedExecutable.m_SteamAppID.isEmpty()); - if (!selectedExecutable.m_SteamAppID.isEmpty()) { - ui->appIDOverwriteEdit->setText(selectedExecutable.m_SteamAppID); + ui->overwriteAppIDBox->setChecked(!selectedExecutable.steamAppID().isEmpty()); + if (!selectedExecutable.steamAppID().isEmpty()) { + ui->appIDOverwriteEdit->setText(selectedExecutable.steamAppID()); } else { ui->appIDOverwriteEdit->clear(); } @@ -391,7 +391,7 @@ void EditExecutablesDialog::on_executablesListBox_clicked(const QModelIndex &cur int index = -1; - QString customOverwrite = m_Profile->setting("custom_overwrites", selectedExecutable.m_Title).toString(); + QString customOverwrite = m_Profile->setting("custom_overwrites", selectedExecutable.title()).toString(); if (!customOverwrite.isEmpty()) { index = ui->newFilesModBox->findText(customOverwrite); qDebug("find %s -> %d", qUtf8Printable(customOverwrite), index); diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 4b2e380b..79b17f5b 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -84,7 +84,7 @@ void ExecutablesList::getExecutables(std::vector::const_iterator &be const Executable &ExecutablesList::find(const QString &title) const { for (Executable const &exe : m_Executables) { - if (exe.m_Title == title) { + if (exe.title() == title) { return exe; } } @@ -95,7 +95,7 @@ const Executable &ExecutablesList::find(const QString &title) const Executable &ExecutablesList::find(const QString &title) { for (Executable &exe : m_Executables) { - if (exe.m_Title == title) { + if (exe.title() == title) { return exe; } } @@ -106,7 +106,7 @@ Executable &ExecutablesList::find(const QString &title) Executable &ExecutablesList::findByBinary(const QFileInfo &info) { for (Executable &exe : m_Executables) { - if (info == exe.m_BinaryInfo) { + if (exe.binaryInfo() == info) { return exe; } } @@ -117,7 +117,7 @@ Executable &ExecutablesList::findByBinary(const QFileInfo &info) std::vector::iterator ExecutablesList::findExe(const QString &title) { for (std::vector::iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) { - if (iter->m_Title == title) { + if (iter->title() == title) { return iter; } } @@ -127,14 +127,14 @@ std::vector::iterator ExecutablesList::findExe(const QString &title) bool ExecutablesList::titleExists(const QString &title) const { - auto test = [&] (const Executable &exe) { return exe.m_Title == title; }; + auto test = [&] (const Executable &exe) { return exe.title() == title; }; return std::find_if(m_Executables.begin(), m_Executables.end(), test) != m_Executables.end(); } void ExecutablesList::addExecutable(const Executable &executable) { - auto existingExe = findExe(executable.m_Title); + auto existingExe = findExe(executable.title()); if (existingExe != m_Executables.end()) { *existingExe = executable; } else { @@ -157,31 +157,32 @@ void ExecutablesList::updateExecutable(const QString &title, flags &= mask; if (existingExe != m_Executables.end()) { - existingExe->m_Title = title; - existingExe->m_Flags &= ~mask; - existingExe->m_Flags |= flags; + existingExe->setTitle(title); + + auto newFlags = existingExe->flags(); + newFlags &= ~mask; + newFlags |= flags; + + existingExe->setFlags(newFlags); + // for pre-configured executables don't overwrite settings we didn't store if (flags & Executable::CustomExecutable) { if (file.exists()) { // don't overwrite a valid binary with an invalid one - existingExe->m_BinaryInfo = file; + existingExe->setBinaryInfo(file); } + if (dir.exists()) { // don't overwrite a valid working directory with an invalid one - existingExe->m_WorkingDirectory = workingDirectory; + existingExe->setWorkingDirectory(workingDirectory); } - existingExe->m_Arguments = arguments; - existingExe->m_SteamAppID = steamAppID; + existingExe->setArguments(arguments); + existingExe->setSteamAppID(steamAppID); } } else { - Executable newExe; - newExe.m_Title = title; - newExe.m_BinaryInfo = file; - newExe.m_Arguments = arguments; - newExe.m_WorkingDirectory = workingDirectory; - newExe.m_SteamAppID = steamAppID; - newExe.m_Flags = Executable::CustomExecutable | flags; - m_Executables.push_back(newExe); + m_Executables.push_back({ + title, file, arguments, workingDirectory, steamAppID, + Executable::CustomExecutable | flags}); } } @@ -189,7 +190,7 @@ void ExecutablesList::updateExecutable(const QString &title, void ExecutablesList::remove(const QString &title) { for (std::vector::iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) { - if (iter->isCustom() && (iter->m_Title == title)) { + if (iter->isCustom() && (iter->title() == title)) { m_Executables.erase(iter); break; } @@ -203,23 +204,105 @@ void ExecutablesList::addExecutableInternal(const QString &title, const QString { QFileInfo file(executableName); if (file.exists()) { - Executable newExe; - newExe.m_BinaryInfo = file; - newExe.m_Title = title; - newExe.m_Arguments = arguments; - newExe.m_WorkingDirectory = workingDirectory; - newExe.m_SteamAppID = steamAppID; - newExe.m_Flags = Executable::UseApplicationIcon; - m_Executables.push_back(newExe); + m_Executables.push_back({ + title, file, arguments, steamAppID, + workingDirectory, Executable::UseApplicationIcon}); } } -void Executable::showOnToolbar(bool state) +Executable::Executable( + QString title, QFileInfo binaryInfo, QString arguments, + QString steamAppID, QString workingDirectory, Flags flags) : + m_title(std::move(title)), + m_binaryInfo(std::move(binaryInfo)), + m_arguments(std::move(arguments)), + m_steamAppID(std::move(steamAppID)), + m_workingDirectory(std::move(workingDirectory)), + m_flags(flags) +{ +} + +const QString& Executable::title() const +{ + return m_title; +} + +void Executable::setTitle(const QString& s) +{ + m_title = s; +} + +const QFileInfo& Executable::binaryInfo() const +{ + return m_binaryInfo; +} + +void Executable::setBinaryInfo(const QFileInfo& fi) +{ + m_binaryInfo = fi; +} + +const QString& Executable::arguments() const +{ + return m_arguments; +} + +void Executable::setArguments(const QString& s) +{ + m_arguments = s; +} + +const QString& Executable::steamAppID() const +{ + return m_steamAppID; +} + +void Executable::setSteamAppID(const QString& s) +{ + m_steamAppID = s; +} + +const QString& Executable::workingDirectory() const +{ + return m_workingDirectory; +} + +void Executable::setWorkingDirectory(const QString& s) +{ + m_workingDirectory = s; +} + +Executable::Flags Executable::flags() const +{ + return m_flags; +} + +void Executable::setFlags(Flags f) +{ + m_flags = f; +} + +bool Executable::isCustom() const +{ + return m_flags.testFlag(CustomExecutable); +} + +bool Executable::isShownOnToolbar() const +{ + return m_flags.testFlag(ShowInToolbar); +} + +void Executable::setShownOnToolbar(bool state) { if (state) { - m_Flags |= ShowInToolbar; + m_flags |= ShowInToolbar; } else { - m_Flags &= ~ShowInToolbar; + m_flags &= ~ShowInToolbar; } } + +bool Executable::usesOwnIcon() const +{ + return m_flags.testFlag(UseApplicationIcon); +} diff --git a/src/executableslist.h b/src/executableslist.h index 0534c09e..0e43b337 100644 --- a/src/executableslist.h +++ b/src/executableslist.h @@ -32,14 +32,11 @@ namespace MOBase { class IPluginGame; } /*! * @brief Information about an executable **/ -struct Executable { - QString m_Title; - QFileInfo m_BinaryInfo; - QString m_Arguments; - QString m_SteamAppID; - QString m_WorkingDirectory; - - enum Flag { +class Executable +{ +public: + enum Flag + { CustomExecutable = 0x01, ShowInToolbar = 0x02, UseApplicationIcon = 0x04, @@ -47,17 +44,42 @@ struct Executable { AllFlags = 0xff //I know, I know }; - Q_DECLARE_FLAGS(Flags, Flag) + Q_DECLARE_FLAGS(Flags, Flag); + + Executable( + QString title, QFileInfo binaryInfo, QString arguments, + QString steamAppID, QString workingDirectory, Flags flags); + + const QString& title() const; + void setTitle(const QString& s); - Flags m_Flags; + const QFileInfo& binaryInfo() const; + void setBinaryInfo(const QFileInfo& fi); - bool isCustom() const { return m_Flags.testFlag(CustomExecutable); } + const QString& arguments() const; + void setArguments(const QString& s); - bool isShownOnToolbar() const { return m_Flags.testFlag(ShowInToolbar); } + const QString& steamAppID() const; + void setSteamAppID(const QString& s); - void showOnToolbar(bool state); + const QString& workingDirectory() const; + void setWorkingDirectory(const QString& s); - bool usesOwnIcon() const { return m_Flags.testFlag(UseApplicationIcon); } + Flags flags() const; + void setFlags(Flags f); + + bool isCustom() const; + bool isShownOnToolbar() const; + void setShownOnToolbar(bool state); + bool usesOwnIcon() const; + +private: + QString m_title; + QFileInfo m_binaryInfo; + QString m_arguments; + QString m_steamAppID; + QString m_workingDirectory; + Flags m_flags; }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 205ab7cc..38b2ed3f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -741,7 +741,7 @@ void MainWindow::updatePinnedExecutables() hasLinks = true; QAction *exeAction = new QAction( - iconForExecutable(iter->m_BinaryInfo.filePath()), iter->m_Title); + iconForExecutable(iter->binaryInfo().filePath()), iter->title()); exeAction->setObjectName(QString("custom__") + iter->m_Title); exeAction->setStatusTip(iter->m_BinaryInfo.filePath()); @@ -1506,17 +1506,17 @@ void MainWindow::startExeAction() QAction *action = qobject_cast(sender()); if (action != nullptr) { const Executable &selectedExecutable(m_OrganizerCore.executablesList()->find(action->text())); - QString customOverwrite = m_OrganizerCore.currentProfile()->setting("custom_overwrites", selectedExecutable.m_Title).toString(); - auto forcedLibraries = m_OrganizerCore.currentProfile()->determineForcedLibraries(selectedExecutable.m_Title); - if (!m_OrganizerCore.currentProfile()->forcedLibrariesEnabled(selectedExecutable.m_Title)) { + QString customOverwrite = m_OrganizerCore.currentProfile()->setting("custom_overwrites", selectedExecutable.title()).toString(); + auto forcedLibraries = m_OrganizerCore.currentProfile()->determineForcedLibraries(selectedExecutable.title()); + if (!m_OrganizerCore.currentProfile()->forcedLibrariesEnabled(selectedExecutable.title())) { forcedLibraries.clear(); } m_OrganizerCore.spawnBinary( - selectedExecutable.m_BinaryInfo, selectedExecutable.m_Arguments, - selectedExecutable.m_WorkingDirectory.length() != 0 - ? selectedExecutable.m_WorkingDirectory - : selectedExecutable.m_BinaryInfo.absolutePath(), - selectedExecutable.m_SteamAppID, + selectedExecutable.binaryInfo(), selectedExecutable.arguments(), + selectedExecutable.workingDirectory().length() != 0 + ? selectedExecutable.workingDirectory() + : selectedExecutable.binaryInfo().absolutePath(), + selectedExecutable.steamAppID(), customOverwrite, forcedLibraries); } else { @@ -1792,8 +1792,8 @@ void MainWindow::refreshExecutablesList() std::vector::const_iterator current, end; m_OrganizerCore.executablesList()->getExecutables(current, end); for(int i = 0; current != end; ++current, ++i) { - QIcon icon = iconForExecutable(current->m_BinaryInfo.filePath()); - executablesList->addItem(icon, current->m_Title); + QIcon icon = iconForExecutable(current->binaryInfo().filePath()); + executablesList->addItem(icon, current->title()); model->setData(model->index(i, 0), QSize(0, executablesList->iconSize().height() + 4), Qt::SizeHintRole); } @@ -2359,17 +2359,17 @@ void MainWindow::on_startButton_clicked() { ui->startButton->setEnabled(false); try { const Executable &selectedExecutable(getSelectedExecutable()); - QString customOverwrite = m_OrganizerCore.currentProfile()->setting("custom_overwrites", selectedExecutable.m_Title).toString(); - auto forcedLibraries = m_OrganizerCore.currentProfile()->determineForcedLibraries(selectedExecutable.m_Title); - if (!m_OrganizerCore.currentProfile()->forcedLibrariesEnabled(selectedExecutable.m_Title)) { + QString customOverwrite = m_OrganizerCore.currentProfile()->setting("custom_overwrites", selectedExecutable.title()).toString(); + auto forcedLibraries = m_OrganizerCore.currentProfile()->determineForcedLibraries(selectedExecutable.title()); + if (!m_OrganizerCore.currentProfile()->forcedLibrariesEnabled(selectedExecutable.title())) { forcedLibraries.clear(); } m_OrganizerCore.spawnBinary( - selectedExecutable.m_BinaryInfo, selectedExecutable.m_Arguments, - selectedExecutable.m_WorkingDirectory.length() != 0 - ? selectedExecutable.m_WorkingDirectory - : selectedExecutable.m_BinaryInfo.absolutePath(), - selectedExecutable.m_SteamAppID, + selectedExecutable.binaryInfo(), selectedExecutable.arguments(), + selectedExecutable.workingDirectory().length() != 0 + ? selectedExecutable.workingDirectory() + : selectedExecutable.binaryInfo().absolutePath(), + selectedExecutable.steamAppID(), customOverwrite, forcedLibraries); } catch (...) { @@ -5204,7 +5204,7 @@ void MainWindow::on_savegameList_customContextMenuRequested(const QPoint &pos) void MainWindow::linkToolbar() { Executable &exe(getSelectedExecutable()); - exe.showOnToolbar(!exe.isShownOnToolbar()); + exe.setShownOnToolbar(!exe.isShownOnToolbar()); ui->linkButton->menu()->actions().at(static_cast(ShortcutType::Toolbar))->setIcon(exe.isShownOnToolbar() ? QIcon(":/MO/gui/remove") : QIcon(":/MO/gui/link")); updatePinnedExecutables(); } @@ -5212,7 +5212,7 @@ void MainWindow::linkToolbar() namespace { QString getLinkfile(const QString &dir, const Executable &exec) { - return QDir::fromNativeSeparators(dir) + "/" + exec.m_Title + ".lnk"; + return QDir::fromNativeSeparators(dir) + "/" + exec.title() + ".lnk"; } QString getDesktopLinkfile(const Executable &exec) @@ -5241,12 +5241,12 @@ void MainWindow::addWindowsLink(const ShortcutType mapping) } else { QFileInfo const exeInfo(qApp->applicationFilePath()); // create link - QString executable = QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath()); + QString executable = QDir::toNativeSeparators(selectedExecutable.binaryInfo().absoluteFilePath()); std::wstring targetFile = ToWString(exeInfo.absoluteFilePath()); std::wstring parameter = ToWString( - QString("\"moshortcut://%1:%2\"").arg(InstanceManager::instance().currentInstance(),selectedExecutable.m_Title)); - std::wstring description = ToWString(QString("Run %1 with ModOrganizer").arg(selectedExecutable.m_Title)); + QString("\"moshortcut://%1:%2\"").arg(InstanceManager::instance().currentInstance(),selectedExecutable.title())); + std::wstring description = ToWString(QString("Run %1 with ModOrganizer").arg(selectedExecutable.title())); std::wstring iconFile = ToWString(executable); std::wstring currentDirectory = ToWString(QDir::toNativeSeparators(qApp->applicationDirPath())); @@ -6391,7 +6391,7 @@ void MainWindow::removeFromToolbar() { try { Executable &exe = m_OrganizerCore.executablesList()->find(m_ContextAction->text()); - exe.showOnToolbar(false); + exe.setShownOnToolbar(false); } catch (const std::runtime_error&) { qDebug("executable doesn't exist any more"); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 88389738..b6283a26 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -33,7 +33,7 @@ along with Mod Organizer. If not, see . //Note the commented headers here can be replaced with forward references, //when I get round to cleaning up main.cpp -struct Executable; +class Executable; class CategoryFactory; class LockedDialogBase; class OrganizerCore; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 892162f6..cfbcad39 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -381,15 +381,15 @@ QSettings::Status OrganizerCore::storeSettings(const QString &fileName) for (; current != end; ++current) { const Executable &item = *current; settings.setArrayIndex(count++); - settings.setValue("title", item.m_Title); + settings.setValue("title", item.title()); settings.setValue("custom", item.isCustom()); settings.setValue("toolbar", item.isShownOnToolbar()); settings.setValue("ownicon", item.usesOwnIcon()); if (item.isCustom()) { - settings.setValue("binary", item.m_BinaryInfo.absoluteFilePath()); - settings.setValue("arguments", item.m_Arguments); - settings.setValue("workingDirectory", item.m_WorkingDirectory); - settings.setValue("steamAppID", item.m_SteamAppID); + settings.setValue("binary", item.binaryInfo().absoluteFilePath()); + settings.setValue("arguments", item.arguments()); + settings.setValue("workingDirectory", item.workingDirectory()); + settings.setValue("steamAppID", item.steamAppID()); } } settings.endArray(); @@ -1742,12 +1742,12 @@ HANDLE OrganizerCore::runShortcut(const MOShortcut& shortcut) } return spawnBinaryDirect( - exe.m_BinaryInfo, exe.m_Arguments, + exe.binaryInfo(), exe.arguments(), m_CurrentProfile->name(), - exe.m_WorkingDirectory.length() != 0 - ? exe.m_WorkingDirectory - : exe.m_BinaryInfo.absolutePath(), - exe.m_SteamAppID, + exe.workingDirectory().length() != 0 + ? exe.workingDirectory() + : exe.binaryInfo().absolutePath(), + exe.steamAppID(), "", forcedLibaries); } @@ -1787,12 +1787,12 @@ HANDLE OrganizerCore::startApplication(const QString &executable, } try { const Executable &exe = m_ExecutablesList.findByBinary(binary); - steamAppID = exe.m_SteamAppID; + steamAppID = exe.steamAppID(); customOverwrite - = m_CurrentProfile->setting("custom_overwrites", exe.m_Title) + = m_CurrentProfile->setting("custom_overwrites", exe.title()) .toString(); - if (m_CurrentProfile->forcedLibrariesEnabled(exe.m_Title)) { - forcedLibraries = m_CurrentProfile->determineForcedLibraries(exe.m_Title); + if (m_CurrentProfile->forcedLibrariesEnabled(exe.title())) { + forcedLibraries = m_CurrentProfile->determineForcedLibraries(exe.title()); } } catch (const std::runtime_error &) { // nop @@ -1801,19 +1801,19 @@ HANDLE OrganizerCore::startApplication(const QString &executable, // only a file name, search executables list try { const Executable &exe = m_ExecutablesList.find(executable); - steamAppID = exe.m_SteamAppID; + steamAppID = exe.steamAppID(); customOverwrite - = m_CurrentProfile->setting("custom_overwrites", exe.m_Title) + = m_CurrentProfile->setting("custom_overwrites", exe.title()) .toString(); - if (m_CurrentProfile->forcedLibrariesEnabled(exe.m_Title)) { - forcedLibraries = m_CurrentProfile->determineForcedLibraries(exe.m_Title); + if (m_CurrentProfile->forcedLibrariesEnabled(exe.title())) { + forcedLibraries = m_CurrentProfile->determineForcedLibraries(exe.title()); } if (arguments == "") { - arguments = exe.m_Arguments; + arguments = exe.arguments(); } - binary = exe.m_BinaryInfo; + binary = exe.binaryInfo(); if (cwd.length() == 0) { - currentDirectory = exe.m_WorkingDirectory; + currentDirectory = exe.workingDirectory(); } } catch (const std::runtime_error &) { qWarning("\"%s\" not set up as executable", -- cgit v1.3.1 From 4f01b94f01180989abbdf0407cdf95483970dba8 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 7 Jun 2019 17:53:42 -0400 Subject: replaced ExecutablesList::getExecutables() by a standard container interface renamed ExecutablesList::init() to addFromPlugin() renamed ExecutablesList::find() to get() and added a find() that returns an iterator changed some calls from get() to find() so they can handle failure because they didn't seem to handle std::runtime_error at all --- src/editexecutablesdialog.cpp | 43 ++++++++++++++++---- src/executableslist.cpp | 84 +++++++++++++++++++-------------------- src/executableslist.h | 63 +++++++++++------------------ src/mainwindow.cpp | 92 ++++++++++++++++++++++++++----------------- src/organizercore.cpp | 16 ++++---- 5 files changed, 164 insertions(+), 134 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 67fbff31..9dbc6bae 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -59,20 +59,29 @@ ExecutablesList EditExecutablesDialog::getExecutablesList() const { ExecutablesList newList; for (int i = 0; i < ui->executablesListBox->count(); ++i) { - newList.addExecutable(m_ExecutablesList.find(ui->executablesListBox->item(i)->text())); + const auto& title = ui->executablesListBox->item(i)->text(); + auto itor = m_ExecutablesList.find(title); + + if (itor == m_ExecutablesList.end()) { + qWarning().nospace() + << "getExecutablesList(): executable '" << title << "' not found"; + + continue; + } + + newList.addExecutable(*itor); } + return newList; } void EditExecutablesDialog::refreshExecutablesWidget() { ui->executablesListBox->clear(); - std::vector::const_iterator current, end; - m_ExecutablesList.getExecutables(current, end); - for(; current != end; ++current) { - QListWidgetItem *newItem = new QListWidgetItem(current->title()); - newItem->setTextColor(current->isCustom() ? QColor(Qt::black) : QColor(Qt::darkGray)); + for(const auto& exe : m_ExecutablesList) { + QListWidgetItem *newItem = new QListWidgetItem(exe.title()); + newItem->setTextColor(exe.isCustom() ? QColor(Qt::black) : QColor(Qt::darkGray)); ui->executablesListBox->addItem(newItem); } @@ -282,7 +291,17 @@ void EditExecutablesDialog::on_titleEdit_textChanged(const QString &arg1) bool EditExecutablesDialog::executableChanged() { if (m_CurrentItem != nullptr) { - Executable const &selectedExecutable(m_ExecutablesList.find(m_CurrentItem->text())); + const auto& title = m_CurrentItem->text(); + auto itor = m_ExecutablesList.find(title); + + if (itor == m_ExecutablesList.end()) { + qWarning().nospace() + << "executableChanged(): title '" << title << "' not found"; + + return false; + } + + const Executable& selectedExecutable = *itor; QString storedCustomOverwrite = m_Profile->setting("custom_overwrites", selectedExecutable.title()).toString(); @@ -374,7 +393,15 @@ void EditExecutablesDialog::on_executablesListBox_clicked(const QModelIndex &cur m_CurrentItem = ui->executablesListBox->item(current.row()); - Executable const &selectedExecutable(m_ExecutablesList.find(m_CurrentItem->text())); + const auto& title = m_CurrentItem->text(); + auto itor = m_ExecutablesList.find(title); + + if (itor == m_ExecutablesList.end()) { + qWarning().nospace() << "selection: executable '" << title << "' not found"; + return; + } + + const Executable& selectedExecutable = *itor; ui->titleEdit->setText(selectedExecutable.title()); ui->binaryEdit->setText(QDir::toNativeSeparators(selectedExecutable.binaryInfo().absoluteFilePath())); diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 79b17f5b..2ea9c3d9 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -33,19 +33,40 @@ along with Mod Organizer. If not, see . using namespace MOBase; +ExecutablesList::iterator ExecutablesList::begin() +{ + return m_Executables.begin(); +} + +ExecutablesList::const_iterator ExecutablesList::begin() const +{ + return m_Executables.begin(); +} + +ExecutablesList::iterator ExecutablesList::end() +{ + return m_Executables.end(); +} + +ExecutablesList::const_iterator ExecutablesList::end() const +{ + return m_Executables.end(); +} -ExecutablesList::ExecutablesList() +std::size_t ExecutablesList::size() const { + return m_Executables.size(); } -ExecutablesList::~ExecutablesList() +bool ExecutablesList::empty() const { + return m_Executables.empty(); } -void ExecutablesList::init(IPluginGame const *game) +void ExecutablesList::addFromPlugin(IPluginGame const *game) { Q_ASSERT(game != nullptr); - m_Executables.clear(); + for (const ExecutableInfo &info : game->executables()) { if (info.isValid()) { addExecutableInternal(info.title(), @@ -55,6 +76,7 @@ void ExecutablesList::init(IPluginGame const *game) info.steamAppID()); } } + ExecutableInfo explorerpp = ExecutableInfo("Explore Virtual Folder", QFileInfo(QCoreApplication::applicationDirPath() + "/explorer++/Explorer++.exe" )) .withArgument(QString("\"%1\"").arg(QDir::toNativeSeparators(game->dataDirectory().absolutePath()))); @@ -65,45 +87,25 @@ void ExecutablesList::init(IPluginGame const *game) explorerpp.workingDirectory().absolutePath(), explorerpp.steamAppID()); } - } -void ExecutablesList::getExecutables(std::vector::iterator &begin, std::vector::iterator &end) +const Executable &ExecutablesList::get(const QString &title) const { - begin = m_Executables.begin(); - end = m_Executables.end(); -} - -void ExecutablesList::getExecutables(std::vector::const_iterator &begin, - std::vector::const_iterator &end) const -{ - begin = m_Executables.begin(); - end = m_Executables.end(); -} - -const Executable &ExecutablesList::find(const QString &title) const -{ - for (Executable const &exe : m_Executables) { + for (const auto& exe : m_Executables) { if (exe.title() == title) { return exe; } } - throw std::runtime_error(QString("invalid executable name: %1").arg(title).toLocal8Bit().constData()); -} + throw std::runtime_error(QString("executable not found: %1").arg(title).toLocal8Bit().constData()); +} -Executable &ExecutablesList::find(const QString &title) +Executable &ExecutablesList::get(const QString &title) { - for (Executable &exe : m_Executables) { - if (exe.title() == title) { - return exe; - } - } - throw std::runtime_error(QString("invalid executable name: %1").arg(title).toLocal8Bit().constData()); + return const_cast(std::as_const(*this).get(title)); } - -Executable &ExecutablesList::findByBinary(const QFileInfo &info) +Executable &ExecutablesList::getByBinary(const QFileInfo &info) { for (Executable &exe : m_Executables) { if (exe.binaryInfo() == info) { @@ -113,17 +115,15 @@ Executable &ExecutablesList::findByBinary(const QFileInfo &info) throw std::runtime_error("invalid info"); } - -std::vector::iterator ExecutablesList::findExe(const QString &title) +ExecutablesList::iterator ExecutablesList::find(const QString &title) { - for (std::vector::iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) { - if (iter->title() == title) { - return iter; - } - } - return m_Executables.end(); + return std::find_if(begin(), end(), [&](auto&& e) { return e.title() == title; }); } +ExecutablesList::const_iterator ExecutablesList::find(const QString &title) const +{ + return std::find_if(begin(), end(), [&](auto&& e) { return e.title() == title; }); +} bool ExecutablesList::titleExists(const QString &title) const { @@ -131,10 +131,9 @@ bool ExecutablesList::titleExists(const QString &title) const return std::find_if(m_Executables.begin(), m_Executables.end(), test) != m_Executables.end(); } - void ExecutablesList::addExecutable(const Executable &executable) { - auto existingExe = findExe(executable.title()); + auto existingExe = find(executable.title()); if (existingExe != m_Executables.end()) { *existingExe = executable; } else { @@ -142,7 +141,6 @@ void ExecutablesList::addExecutable(const Executable &executable) } } - void ExecutablesList::updateExecutable(const QString &title, const QString &executableName, const QString &arguments, @@ -153,7 +151,7 @@ void ExecutablesList::updateExecutable(const QString &title, { QFileInfo file(executableName); QDir dir(workingDirectory); - auto existingExe = findExe(title); + auto existingExe = find(title); flags &= mask; if (existingExe != m_Executables.end()) { diff --git a/src/executableslist.h b/src/executableslist.h index 0e43b337..b8e4cf77 100644 --- a/src/executableslist.h +++ b/src/executableslist.h @@ -88,28 +88,33 @@ private: **/ class ExecutablesList { public: + using vector_type = std::vector; + using iterator = vector_type::iterator; + using const_iterator = vector_type::const_iterator; /** - * @brief constructor - * - **/ - ExecutablesList(); - - ~ExecutablesList(); + * standard container interface + */ + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + std::size_t size() const; + bool empty() const; /** - * @brief initialise the list with the executables preconfigured for this game + * @brief add the executables preconfigured for this game **/ - void init(MOBase::IPluginGame const *game); + void addFromPlugin(MOBase::IPluginGame const *game); /** - * @brief find an executable by its name + * @brief get an executable by name * * @param title the title of the executable to look up * @return the executable - * @exception runtime_error will throw an exception if the name is not correct + * @exception runtime_error will throw an exception if the executable is not found **/ - const Executable &find(const QString &title) const; + const Executable &get(const QString &title) const; /** * @brief find an executable by its name @@ -118,7 +123,7 @@ public: * @return the executable * @exception runtime_error will throw an exception if the name is not correct **/ - Executable &find(const QString &title); + Executable &get(const QString &title); /** * @brief find an executable by a fileinfo structure @@ -126,7 +131,13 @@ public: * @return the executable * @exception runtime_error will throw an exception if the name is not correct */ - Executable &findByBinary(const QFileInfo &info); + Executable &getByBinary(const QFileInfo &info); + + /** + * @brief returns an iterator for the given executable by title, or end() + */ + iterator find(const QString &title); + const_iterator find(const QString &title) const; /** * @brief determine if an executable exists @@ -183,33 +194,7 @@ public: **/ void remove(const QString &title); - /** - * @brief retrieve begin and end iterators of the configured executables - * - * @param begin iterator to the first executable - * @param end iterator one past the last executable - **/ - void getExecutables(std::vector::const_iterator &begin, std::vector::const_iterator &end) const; - - /** - * @brief retrieve begin and end iterators of the configured executables - * - * @param begin iterator to the first executable - * @param end iterator one past the last executable - **/ - void getExecutables(std::vector::iterator &begin, std::vector::iterator &end); - - /** - * @brief get the number of executables (custom or otherwise) - **/ - size_t size() const { - return m_Executables.size(); - } - private: - - std::vector::iterator findExe(const QString &title); - void addExecutableInternal(const QString &title, const QString &executableName, const QString &arguments, const QString &workingDirectory, const QString &steamAppID); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 38b2ed3f..2fbdbec7 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -733,15 +733,12 @@ void MainWindow::updatePinnedExecutables() bool hasLinks = false; - std::vector::iterator begin, end; - m_OrganizerCore.executablesList()->getExecutables(begin, end); - - for (auto iter = begin; iter != end; ++iter) { - if (iter->isShownOnToolbar()) { + for (const auto& exe : *m_OrganizerCore.executablesList()) { + if (exe.isShownOnToolbar()) { hasLinks = true; QAction *exeAction = new QAction( - iconForExecutable(iter->binaryInfo().filePath()), iter->title()); + iconForExecutable(exe.binaryInfo().filePath()), exe.title()); exeAction->setObjectName(QString("custom__") + iter->m_Title); exeAction->setStatusTip(iter->m_BinaryInfo.filePath()); @@ -1504,24 +1501,42 @@ void MainWindow::registerModPage(IPluginModPage *modPage) void MainWindow::startExeAction() { QAction *action = qobject_cast(sender()); - if (action != nullptr) { - const Executable &selectedExecutable(m_OrganizerCore.executablesList()->find(action->text())); - QString customOverwrite = m_OrganizerCore.currentProfile()->setting("custom_overwrites", selectedExecutable.title()).toString(); - auto forcedLibraries = m_OrganizerCore.currentProfile()->determineForcedLibraries(selectedExecutable.title()); - if (!m_OrganizerCore.currentProfile()->forcedLibrariesEnabled(selectedExecutable.title())) { - forcedLibraries.clear(); - } - m_OrganizerCore.spawnBinary( - selectedExecutable.binaryInfo(), selectedExecutable.arguments(), - selectedExecutable.workingDirectory().length() != 0 - ? selectedExecutable.workingDirectory() - : selectedExecutable.binaryInfo().absolutePath(), - selectedExecutable.steamAppID(), - customOverwrite, - forcedLibraries); - } else { + + if (action == nullptr) { qCritical("not an action?"); + return; } + + const auto& list = *m_OrganizerCore.executablesList(); + + const auto title = action->text(); + auto itor = list.find(title); + + if (itor == list.end()) { + qWarning().nospace() + << "startExeAction(): executable '" << title << "' not found"; + + return; + } + + const Executable& exe = *itor; + auto& profile = *m_OrganizerCore.currentProfile(); + + QString customOverwrite = profile.setting("custom_overwrites", exe.title()).toString(); + auto forcedLibraries = profile.determineForcedLibraries(exe.title()); + + if (!profile.forcedLibrariesEnabled(exe.title())) { + forcedLibraries.clear(); + } + + m_OrganizerCore.spawnBinary( + exe.binaryInfo(), exe.arguments(), + exe.workingDirectory().length() != 0 + ? exe.workingDirectory() + : exe.binaryInfo().absolutePath(), + exe.steamAppID(), + customOverwrite, + forcedLibraries); } @@ -1789,12 +1804,12 @@ void MainWindow::refreshExecutablesList() QAbstractItemModel *model = executablesList->model(); - std::vector::const_iterator current, end; - m_OrganizerCore.executablesList()->getExecutables(current, end); - for(int i = 0; current != end; ++current, ++i) { - QIcon icon = iconForExecutable(current->binaryInfo().filePath()); - executablesList->addItem(icon, current->title()); + int i = 0; + for (const auto& exe : *m_OrganizerCore.executablesList()) { + QIcon icon = iconForExecutable(exe.binaryInfo().filePath()); + executablesList->addItem(icon, exe.title()); model->setData(model->index(i, 0), QSize(0, executablesList->iconSize().height() + 4), Qt::SizeHintRole); + ++i; } setExecutableIndex(1); @@ -6389,13 +6404,18 @@ void MainWindow::unlockESPIndex() void MainWindow::removeFromToolbar() { - try { - Executable &exe = m_OrganizerCore.executablesList()->find(m_ContextAction->text()); - exe.setShownOnToolbar(false); - } catch (const std::runtime_error&) { - qDebug("executable doesn't exist any more"); + const auto& title = m_ContextAction->text(); + auto& list = *m_OrganizerCore.executablesList(); + + auto itor = list.find(title); + if (itor == list.end()) { + qWarning().nospace() + << "removeFromToolbar(): executable '" << title << "' not found"; + + return; } + itor->setShownOnToolbar(false); updatePinnedExecutables(); } @@ -6520,14 +6540,14 @@ void MainWindow::on_groupCombo_currentIndexChanged(int index) const Executable &MainWindow::getSelectedExecutable() const { - QString name = ui->executablesListBox->itemText(ui->executablesListBox->currentIndex()); - return m_OrganizerCore.executablesList()->find(name); + const QString name = ui->executablesListBox->itemText(ui->executablesListBox->currentIndex()); + return m_OrganizerCore.executablesList()->get(name); } Executable &MainWindow::getSelectedExecutable() { - QString name = ui->executablesListBox->itemText(ui->executablesListBox->currentIndex()); - return m_OrganizerCore.executablesList()->find(name); + const QString name = ui->executablesListBox->itemText(ui->executablesListBox->currentIndex()); + return m_OrganizerCore.executablesList()->get(name); } void MainWindow::on_linkButton_pressed() diff --git a/src/organizercore.cpp b/src/organizercore.cpp index cfbcad39..4d11a35f 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -375,11 +375,10 @@ QSettings::Status OrganizerCore::storeSettings(const QString &fileName) settings.remove("customExecutables"); settings.beginWriteArray("customExecutables"); - std::vector::const_iterator current, end; - m_ExecutablesList.getExecutables(current, end); + int count = 0; - for (; current != end; ++current) { - const Executable &item = *current; + + for (const auto& item : m_ExecutablesList) { settings.setArrayIndex(count++); settings.setValue("title", item.title()); settings.setValue("custom", item.isCustom()); @@ -508,7 +507,7 @@ void OrganizerCore::updateExecutablesList(QSettings &settings) return; } - m_ExecutablesList.init(managedGame()); + m_ExecutablesList.addFromPlugin(managedGame()); qDebug("setting up configured executables"); @@ -1735,7 +1734,8 @@ HANDLE OrganizerCore::runShortcut(const MOShortcut& shortcut) .arg(shortcut.instance(),shortcut.executable()) .toLocal8Bit().constData()); - Executable& exe = m_ExecutablesList.find(shortcut.executable()); + const Executable& exe = m_ExecutablesList.get(shortcut.executable()); + auto forcedLibaries = m_CurrentProfile->determineForcedLibraries(shortcut.executable()); if (!m_CurrentProfile->forcedLibrariesEnabled(shortcut.executable())) { forcedLibaries.clear(); @@ -1786,7 +1786,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, currentDirectory = binary.absolutePath(); } try { - const Executable &exe = m_ExecutablesList.findByBinary(binary); + const Executable &exe = m_ExecutablesList.getByBinary(binary); steamAppID = exe.steamAppID(); customOverwrite = m_CurrentProfile->setting("custom_overwrites", exe.title()) @@ -1800,7 +1800,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, } else { // only a file name, search executables list try { - const Executable &exe = m_ExecutablesList.find(executable); + const Executable &exe = m_ExecutablesList.get(executable); steamAppID = exe.steamAppID(); customOverwrite = m_CurrentProfile->setting("custom_overwrites", exe.title()) -- cgit v1.3.1 From 26786da96d37914ca91eff633de751acf1a3b9d8 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 7 Jun 2019 18:04:31 -0400 Subject: moved store/load to ExecutablesList --- src/executableslist.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ src/executableslist.h | 21 ++++++++++++------- src/organizercore.cpp | 47 ++++-------------------------------------- 3 files changed, 72 insertions(+), 50 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 2ea9c3d9..43a30f02 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -63,6 +63,60 @@ bool ExecutablesList::empty() const return m_Executables.empty(); } +void ExecutablesList::load(const MOBase::IPluginGame* game, QSettings& settings) +{ + addFromPlugin(game); + + qDebug("setting up configured executables"); + + int numCustomExecutables = settings.beginReadArray("customExecutables"); + for (int i = 0; i < numCustomExecutables; ++i) { + settings.setArrayIndex(i); + + Executable::Flags flags; + if (settings.value("custom", true).toBool()) + flags |= Executable::CustomExecutable; + if (settings.value("toolbar", false).toBool()) + flags |= Executable::ShowInToolbar; + if (settings.value("ownicon", false).toBool()) + flags |= Executable::UseApplicationIcon; + + addExecutable( + settings.value("title").toString(), settings.value("binary").toString(), + settings.value("arguments").toString(), + settings.value("workingDirectory", "").toString(), + settings.value("steamAppID", "").toString(), flags); + } + + settings.endArray(); +} + +void ExecutablesList::store(QSettings& settings) +{ + settings.remove("customExecutables"); + settings.beginWriteArray("customExecutables"); + + int count = 0; + + for (const auto& item : *this) { + settings.setArrayIndex(count++); + + settings.setValue("title", item.title()); + settings.setValue("custom", item.isCustom()); + settings.setValue("toolbar", item.isShownOnToolbar()); + settings.setValue("ownicon", item.usesOwnIcon()); + + if (item.isCustom()) { + settings.setValue("binary", item.binaryInfo().absoluteFilePath()); + settings.setValue("arguments", item.arguments()); + settings.setValue("workingDirectory", item.workingDirectory()); + settings.setValue("steamAppID", item.steamAppID()); + } + } + + settings.endArray(); +} + void ExecutablesList::addFromPlugin(IPluginGame const *game) { Q_ASSERT(game != nullptr); diff --git a/src/executableslist.h b/src/executableslist.h index b8e4cf77..136f70bf 100644 --- a/src/executableslist.h +++ b/src/executableslist.h @@ -103,9 +103,14 @@ public: bool empty() const; /** - * @brief add the executables preconfigured for this game - **/ - void addFromPlugin(MOBase::IPluginGame const *game); + * @brief initializes the list from the settings and the given plugin + */ + void load(const MOBase::IPluginGame* game, QSettings& settings); + + /** + * @brief writes the current list to the settings + */ + void store(QSettings& settings); /** * @brief get an executable by name @@ -195,14 +200,16 @@ public: void remove(const QString &title); private: + std::vector m_Executables; + void addExecutableInternal(const QString &title, const QString &executableName, const QString &arguments, const QString &workingDirectory, const QString &steamAppID); -private: - - std::vector m_Executables; - + /** + * @brief add the executables preconfigured for this game + **/ + void addFromPlugin(MOBase::IPluginGame const *game); }; Q_DECLARE_OPERATORS_FOR_FLAGS(Executable::Flags) diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 4d11a35f..2172538e 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -365,33 +365,17 @@ QString OrganizerCore::commitSettings(const QString &iniFile) QSettings::Status OrganizerCore::storeSettings(const QString &fileName) { QSettings settings(fileName, QSettings::IniFormat); + if (m_UserInterface != nullptr) { m_UserInterface->storeSettings(settings); } + if (m_CurrentProfile != nullptr) { settings.setValue("selected_profile", m_CurrentProfile->name().toUtf8().constData()); } - settings.remove("customExecutables"); - settings.beginWriteArray("customExecutables"); - - int count = 0; - - for (const auto& item : m_ExecutablesList) { - settings.setArrayIndex(count++); - settings.setValue("title", item.title()); - settings.setValue("custom", item.isCustom()); - settings.setValue("toolbar", item.isShownOnToolbar()); - settings.setValue("ownicon", item.usesOwnIcon()); - if (item.isCustom()) { - settings.setValue("binary", item.binaryInfo().absoluteFilePath()); - settings.setValue("arguments", item.arguments()); - settings.setValue("workingDirectory", item.workingDirectory()); - settings.setValue("steamAppID", item.steamAppID()); - } - } - settings.endArray(); + m_ExecutablesList.store(settings); FileDialogMemory::save(settings); @@ -507,30 +491,7 @@ void OrganizerCore::updateExecutablesList(QSettings &settings) return; } - m_ExecutablesList.addFromPlugin(managedGame()); - - qDebug("setting up configured executables"); - - int numCustomExecutables = settings.beginReadArray("customExecutables"); - for (int i = 0; i < numCustomExecutables; ++i) { - settings.setArrayIndex(i); - - Executable::Flags flags; - if (settings.value("custom", true).toBool()) - flags |= Executable::CustomExecutable; - if (settings.value("toolbar", false).toBool()) - flags |= Executable::ShowInToolbar; - if (settings.value("ownicon", false).toBool()) - flags |= Executable::UseApplicationIcon; - - m_ExecutablesList.addExecutable( - settings.value("title").toString(), settings.value("binary").toString(), - settings.value("arguments").toString(), - settings.value("workingDirectory", "").toString(), - settings.value("steamAppID", "").toString(), flags); - } - - settings.endArray(); + m_ExecutablesList.load(managedGame(), settings); // TODO this has nothing to do with executables list move to an appropriate // function! -- cgit v1.3.1 From 1897d60134e1cff31375f1c602196a99ece7fc86 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 7 Jun 2019 23:31:58 -0400 Subject: pulled java installation detection out of getFileExecutionContext() and into findJavaInstallation() because it was copy/pasted into EditExecutablesDialog fixed FileDialogMemory::getOpenFileName() to also use the given directory correctly handle browse binary button --- src/editexecutablesdialog.cpp | 104 +++++++++++++++++++++--------------------- src/editexecutablesdialog.h | 1 + src/filedialogmemory.cpp | 16 +++++-- src/organizercore.cpp | 72 +++++++++++++++-------------- src/organizercore.h | 2 + 5 files changed, 105 insertions(+), 90 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index efcec8e0..08e2c3d1 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -22,10 +22,12 @@ along with Mod Organizer. If not, see . #include "filedialogmemory.h" #include "stackdata.h" #include "modlist.h" +#include "forcedloaddialog.h" +#include "organizercore.h" + #include #include #include -#include "forcedloaddialog.h" #include using namespace MOBase; @@ -321,6 +323,30 @@ void EditExecutablesDialog::on_forceLoadLibraries_toggled(bool checked) save(); } +void EditExecutablesDialog::on_browseBinary_clicked() +{ + const QString binaryName = FileDialogMemory::getOpenFileName( + "editExecutableBinary", this, tr("Select a binary"), ui->binary->text(), + tr("Executable (%1)").arg("*.exe *.bat *.jar")); + + if (binaryName.isNull()) { + // canceled + return; + } + + if (binaryName.endsWith(".jar", Qt::CaseInsensitive)) { + setJarBinary(binaryName); + } else { + ui->binary->setText(QDir::toNativeSeparators(binaryName)); + } + + if (ui->title->text().isEmpty()) { + ui->title->setText(QFileInfo(binaryName).baseName()); + } + + save(); +} + void EditExecutablesDialog::on_browseWorkingDirectory_clicked() { QString dirName = FileDialogMemory::getExistingDirectory( @@ -356,6 +382,30 @@ void EditExecutablesDialog::on_configureLibraries_clicked() } } +void EditExecutablesDialog::setJarBinary(const QString& binaryName) +{ + auto java = OrganizerCore::findJavaInstallation(binaryName); + + if (java.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.")); + } + + // only save once + + m_settingUI = true; + ui->binary->setText(java); + ui->workingDirectory->setText(QDir::toNativeSeparators(QFileInfo(binaryName).absolutePath())); + ui->arguments->setText("-jar \"" + QDir::toNativeSeparators(binaryName) + "\""); + m_settingUI = false; + + save(); +} + + void EditExecutablesDialog::resetInput() @@ -465,58 +515,6 @@ void EditExecutablesDialog::on_add_clicked() //refreshExecutablesWidget(); } -void EditExecutablesDialog::on_browseBinary_clicked() -{ - QString binaryName = FileDialogMemory::getOpenFileName( - "editExecutableBinary", this, tr("Select a binary"), QString(), - tr("Executable (%1)").arg("*.exe *.bat *.jar")); - - if (binaryName.isNull()) { - // canceled - return; - } - - 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(), nullptr, buffer) - > reinterpret_cast(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->binary->setText(binaryPath); - } - - ui->workingDirectory->setText(QDir::toNativeSeparators(QFileInfo(binaryName).absolutePath())); - ui->arguments->setText("-jar \"" + QDir::toNativeSeparators(binaryName) + "\""); - } else { - ui->binary->setText(QDir::toNativeSeparators(binaryName)); - } - - if (ui->title->text().isEmpty()) { - ui->title->setText(QFileInfo(binaryName).baseName()); - } -} - void EditExecutablesDialog::on_remove_clicked() { if (QMessageBox::question(this, tr("Confirm"), tr("Really remove \"%1\" from executables?").arg(ui->title->text()), diff --git a/src/editexecutablesdialog.h b/src/editexecutablesdialog.h index 37b50127..1f3f0082 100644 --- a/src/editexecutablesdialog.h +++ b/src/editexecutablesdialog.h @@ -98,6 +98,7 @@ private: void clearEdits(); void setEdits(const Executable& e); void save(); + void setJarBinary(const QString& binaryName); void resetInput(); bool executableChanged(); diff --git a/src/filedialogmemory.cpp b/src/filedialogmemory.cpp index 9607beb9..554a6235 100644 --- a/src/filedialogmemory.cpp +++ b/src/filedialogmemory.cpp @@ -61,14 +61,22 @@ QString FileDialogMemory::getOpenFileName( const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { - std::pair::iterator, bool> currentDir = - instance().m_Cache.insert(std::make_pair(dirID, dir)); + QString currentDir = dir; + + if (currentDir.isEmpty()) { + auto itor = instance().m_Cache.find(dirID); + if (itor != instance().m_Cache.end()) { + currentDir = itor->first; + } + } + + QString result = QFileDialog::getOpenFileName( + parent, caption, currentDir, filter, selectedFilter, options); - QString result = QFileDialog::getOpenFileName(parent, caption, currentDir.first->second, - filter, selectedFilter, options); if (!result.isNull()) { instance().m_Cache[dirID] = QFileInfo(result).path(); } + return result; } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 2172538e..c724e57f 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1182,6 +1182,34 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const return res; } +QString OrganizerCore::findJavaInstallation(const QString& jarFile) +{ + if (!jarFile.isEmpty()) { + // try to find java automatically based on the given jar file + std::wstring jarFileW = jarFile.toStdWString(); + + WCHAR buffer[MAX_PATH]; + if (::FindExecutableW(jarFileW.c_str(), nullptr, buffer) > (HINSTANCE)32) { + DWORD binaryType = 0UL; + if (!::GetBinaryTypeW(buffer, &binaryType)) { + qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); + } else if (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY) { + return QString::fromWCharArray(buffer); + } + } + } + + // second attempt: look to the registry + QSettings reg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat); + if (reg.contains("CurrentVersion")) { + QString currentVersion = reg.value("CurrentVersion").toString(); + return reg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe"); + } + + // not found + return {}; +} + bool OrganizerCore::getFileExecutionContext( QWidget* parent, const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type) @@ -1199,44 +1227,22 @@ bool OrganizerCore::getFileExecutionContext( type = FileExecutionTypes::Executable; return true; } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) { - // types that need to be injected into - std::wstring targetPathW = targetInfo.absoluteFilePath().toStdWString(); - QString binaryPath; - - { // try to find java automatically - WCHAR buffer[MAX_PATH]; - if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { - DWORD binaryType = 0UL; - if (!::GetBinaryTypeW(buffer, &binaryType)) { - qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); - } else if (binaryType == SCS_32BIT_BINARY) { - binaryPath = QString::fromWCharArray(buffer); - } - } - } - if (binaryPath.isEmpty() && (extension == "jar")) { - // second attempt: look to the registry - 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()) { - binaryPath = QFileDialog::getOpenFileName( - parent, QObject::tr("Select binary"), QString(), QObject::tr("Binary") + " (*.exe)"); + auto java = findJavaInstallation(targetInfo.absoluteFilePath()); + + if (java.isEmpty()) { + java = QFileDialog::getOpenFileName( + parent, QObject::tr("Select binary"), + QString(), QObject::tr("Binary") + " (*.exe)"); } - if (binaryPath.isEmpty()) { + + if (java.isEmpty()) { return false; } - binaryInfo = QFileInfo(binaryPath); - if (extension == "jar") { - arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - } else { - arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); - } + binaryInfo = QFileInfo(java); + arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); type = FileExecutionTypes::Executable; + return true; } else { type = FileExecutionTypes::Other; diff --git a/src/organizercore.h b/src/organizercore.h index 8ed34e24..a4a57496 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -147,6 +147,8 @@ public: void doAfterLogin(const std::function &function) { m_PostLoginTasks.append(function); } + static QString findJavaInstallation(const QString& jarFile={}); + static bool getFileExecutionContext( QWidget* parent, const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); -- cgit v1.3.1 From 724fad7cb62a0ee4913ed41bde45c7564183c7af Mon Sep 17 00:00:00 2001 From: Matte A Date: Sun, 23 Jun 2019 04:38:36 +0200 Subject: Correcting minor spelling mistakes in the UI + add contributor --- src/aboutdialog.ui | 4 ++-- src/instancemanager.cpp | 2 +- src/mainwindow.cpp | 4 ++-- src/mainwindow.ui | 4 ++-- src/moapplication.cpp | 4 ++-- src/modinfodialog.cpp | 8 ++++---- src/modinfodialog.ui | 8 ++++---- src/organizercore.cpp | 6 +++--- src/overwriteinfodialog.cpp | 8 ++++---- src/settingsdialog.ui | 4 ++-- src/spawn.cpp | 2 +- src/tutorials/tutorial_conflictresolution_main.js | 2 +- src/tutorials/tutorial_firststeps_main.js | 2 +- src/tutorials/tutorial_firststeps_modinfo.js | 2 +- 14 files changed, 30 insertions(+), 30 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/aboutdialog.ui b/src/aboutdialog.ui index 86b95c83..1b3f0ad2 100644 --- a/src/aboutdialog.ui +++ b/src/aboutdialog.ui @@ -337,7 +337,7 @@ - Jax (Swedish) + Jax, Nubbie (Swedish) @@ -361,7 +361,7 @@ - Other Supporters && Contributors + Other Supporters & Contributors diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index 5b57827a..b5130e8b 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -102,7 +102,7 @@ QString InstanceManager::manageInstances(const QStringList &instanceList) const SelectionDialog selection( QString("

%1


%2") .arg(QObject::tr("Choose Instance to Delete")) - .arg(QObject::tr("Be Carefull! Deleting an Instance will remove all your files for that Instance (mods, downloads, profiles, configuration, ...). Custom paths outside of the instance folder for downloads, mods, etc. will be left untoched.")), + .arg(QObject::tr("Be Careful! Deleting an Instance will remove all your files for that Instance (mods, downloads, profiles, configuration, ...). Custom paths outside of the instance folder for downloads, mods, etc. will be left untoched.")), nullptr); for (const QString &instance : instanceList) { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e383006b..da7c721d 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -6796,7 +6796,7 @@ void MainWindow::on_bossButton_clicked() } if (errorMessages.length() > 0) { - QMessageBox *warn = new QMessageBox(QMessageBox::Warning, tr("Errors occured"), errorMessages.c_str(), QMessageBox::Ok, this); + QMessageBox *warn = new QMessageBox(QMessageBox::Warning, tr("Errors occurred"), errorMessages.c_str(), QMessageBox::Ok, this); warn->setModal(false); warn->show(); } @@ -6899,7 +6899,7 @@ void MainWindow::on_saveModsButton_clicked() m_OrganizerCore.currentProfile()->writeModlistNow(true); QDateTime now = QDateTime::currentDateTime(); if (createBackup(m_OrganizerCore.currentProfile()->getModlistFileName(), now)) { - MessageDialog::showMessage(tr("Backup of modlist created"), this); + MessageDialog::showMessage(tr("Backup of mod list created"), this); } } diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 0ee74239..6a816262 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -221,8 +221,8 @@ <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different playthroughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept separate for different profiles.</span></p></body></html>
diff --git a/src/moapplication.cpp b/src/moapplication.cpp index 3a791827..5652833a 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -116,12 +116,12 @@ bool MOApplication::notify(QObject *receiver, QEvent *event) } catch (const std::exception &e) { qCritical("uncaught exception in handler (object %s, eventtype %d): %s", receiver->objectName().toUtf8().constData(), event->type(), e.what()); - reportError(tr("an error occured: %1").arg(e.what())); + reportError(tr("an error occurred: %1").arg(e.what())); return false; } catch (...) { qCritical("uncaught non-std exception in handler (object %s, eventtype %d)", receiver->objectName().toUtf8().constData(), event->type()); - reportError(tr("an error occured")); + reportError(tr("an error occurred")); return false; } } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 2be8e481..188ea956 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1670,13 +1670,13 @@ void ModInfoDialog::delete_activated() } else if (selection->selectedRows().count() == 1) { QString fileName = m_FileSystemModel->fileName(selection->selectedRows().at(0)); - if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete \"%1\"?").arg(fileName), + if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete \"%1\"?").arg(fileName), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } else { - if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete the selected files?"), + if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected files?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } @@ -1695,12 +1695,12 @@ void ModInfoDialog::deleteTriggered() return; } else if (m_FileSelection.count() == 1) { QString fileName = m_FileSystemModel->fileName(m_FileSelection.at(0)); - if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete \"%1\"?").arg(fileName), + if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete \"%1\"?").arg(fileName), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } else { - if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete the selected files?"), + if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected files?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index e009a599..eed4e31f 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -136,7 +136,7 @@ This is a list of ini tweaks (ini modifications that can be toggled). - This is a list of ini tweaks. Ini Tweaks are (usually small) fragments of ini files that are applied over existing settings in skyrim.ini/skyrimprefs.ini. Each tweak can be toggled individually. You should check the description of the mod wether the tweaks are really optional. + This is a list of ini tweaks. Ini Tweaks are (usually small) fragments of ini files that are applied over existing settings in skyrim.ini/skyrimprefs.ini. Each tweak can be toggled individually. You should check the description of the mod whether the tweaks are really optional.
@@ -383,7 +383,7 @@ Most mods do not have optional esps, so chances are good you are looking at an e ESPs in the data directory and thus visible to the game. - These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window. + These are the mod files that are in the (virtual) data directory of your game and will thus be selectable in the esp list in the main window. @@ -897,7 +897,7 @@ text-align: left; <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: <a href=" https://www.nexusmods.com/skyrimspecialedition/mods/6194"><span style=" text-decoration: underline; color:#0000ff;">https://www.nexusmods.com/skyrimspecialedition/mods/6194</span></a>. In this example, 6194 is the id you're looking for. Besides: The above is the link to Mod Organizer2 on Nexus. Why not go there now and endorse us?</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: <a href=" https://www.nexusmods.com/skyrimspecialedition/mods/6194"><span style=" text-decoration: underline; color:#0000ff;">https://www.nexusmods.com/skyrimspecialedition/mods/6194</span></a>. In this example, 6194 is the id you're looking for. Besides: The above is the link to Mod Organizer 2 on Nexus. Why not go there now and endorse us?</p></body></html> @@ -1067,7 +1067,7 @@ p, li { white-space: pre-wrap; } - Web page URL (only used if invalid NexusID) : + Web page URL (only used if invalid Nexus ID) : diff --git a/src/organizercore.cpp b/src/organizercore.cpp index c724e57f..2cad9ce8 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -391,7 +391,7 @@ void OrganizerCore::storeSettings() if (!shellCopy(iniFile, iniFile + ".new", true, qApp->activeWindow())) { QMessageBox::critical( qApp->activeWindow(), tr("Failed to write settings"), - tr("An error occured trying to update MO settings to %1: %2") + tr("An error occurred trying to update MO settings to %1: %2") .arg(iniFile, windowsErrorString(::GetLastError()))); return; } @@ -418,7 +418,7 @@ void OrganizerCore::storeSettings() : tr("Unknown error %1").arg(result); QMessageBox::critical( qApp->activeWindow(), tr("Failed to write settings"), - tr("An error occured trying to write back MO settings to %1: %2") + tr("An error occurred trying to write back MO settings to %1: %2") .arg(writeTarget, reason)); } } @@ -1570,7 +1570,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, tr("MO was denied access to the Steam process. This normally indicates that " "Steam is being run as administrator while MO is not. This can cause issues " "launching the game. It is recommended to not run Steam as administrator unless " - "absolutely neccessary.\n\n" + "absolutely necessary.\n\n" "Restart MO as administrator?"), QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel); if (result == QDialogButtonBox::Yes) { diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index 9b3e55df..0a884ac9 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -162,13 +162,13 @@ void OverwriteInfoDialog::delete_activated() } else if (selection->selectedRows().count() == 1) { QString fileName = m_FileSystemModel->fileName(selection->selectedRows().at(0)); - if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete \"%1\"?").arg(fileName), + if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete \"%1\"?").arg(fileName), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } else { - if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete the selected files?"), + if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected files?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } @@ -187,12 +187,12 @@ void OverwriteInfoDialog::deleteTriggered() return; } else if (m_FileSelection.count() == 1) { QString fileName = m_FileSystemModel->fileName(m_FileSelection.at(0)); - if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete \"%1\"?").arg(fileName), + if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete \"%1\"?").arg(fileName), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } else { - if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete the selected files?"), + if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected files?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 08c8d9f2..faaf1653 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -441,7 +441,7 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - Important: All directories have to be writeable! + Important: All directories have to be writable! @@ -1297,7 +1297,7 @@ programs you are intentionally running. Decides the amount of data printed to "ModOrganizer.log". - "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty. + "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regular use. On the "Error" level the log file usually remains empty. diff --git a/src/spawn.cpp b/src/spawn.cpp index d7d5efc2..f77da35f 100644 --- a/src/spawn.cpp +++ b/src/spawn.cpp @@ -150,7 +150,7 @@ HANDLE startBinary(const QFileInfo &binary, if (e.getErrorCode() == ERROR_ELEVATION_REQUIRED) { if (QMessageBox::question(QApplication::activeModalWidget(), QObject::tr("Elevation required"), QObject::tr("This process requires elevation to run.\n" - "This is a potential security risk so I highly advice you to investigate if\n" + "This is a potential security risk so I highly advise you to investigate if\n" "\"%1\"\n" "can be installed to work without elevation.\n\n" "Restart Mod Organizer as an elevated process?\n" diff --git a/src/tutorials/tutorial_conflictresolution_main.js b/src/tutorials/tutorial_conflictresolution_main.js index 3c782af2..404afe5d 100644 --- a/src/tutorials/tutorial_conflictresolution_main.js +++ b/src/tutorials/tutorial_conflictresolution_main.js @@ -56,7 +56,7 @@ function getTutorialSteps() { waitForClick() }, function() { - tutorial.text = qsTr(" indicates that the mod is completely overwrtten by another. You could as well disable it."); + tutorial.text = qsTr(" indicates that the mod is completely overwritten by another. You could as well disable it."); waitForClick() }, function() { diff --git a/src/tutorials/tutorial_firststeps_main.js b/src/tutorials/tutorial_firststeps_main.js index ee97766b..35d1aa11 100644 --- a/src/tutorials/tutorial_firststeps_main.js +++ b/src/tutorials/tutorial_firststeps_main.js @@ -137,7 +137,7 @@ function getTutorialSteps() function() { tutorial.text = qsTr("A single mod may contain zero, one or multiple esps. Some or all may be optional. " - + "If in doubt, please consult the documentation of the indiviual mod. " + + "If in doubt, please consult the documentation of the individual mod. " + "To do so, right-click the mod and select \"Information\".") highlightItem("modList", true) manager.activateTutorial("ModInfoDialog", "tutorial_firststeps_modinfo.js") diff --git a/src/tutorials/tutorial_firststeps_modinfo.js b/src/tutorials/tutorial_firststeps_modinfo.js index 50c38345..1ed0dab7 100644 --- a/src/tutorials/tutorial_firststeps_modinfo.js +++ b/src/tutorials/tutorial_firststeps_modinfo.js @@ -16,7 +16,7 @@ function getTutorialSteps() }, function() { unhighlight() - tutorial.text = qsTr("We may re-visit this screen in later tutorials.") + tutorial.text = qsTr("We may revisit this screen in later tutorials.") waitForClick() } ] -- cgit v1.3.1 From 8d1c121f648f2f6a8e0a5e2ad76cd245e318290d Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 23 Jun 2019 02:24:34 -0400 Subject: split nexus tab added OrganizerCore::loggedInAction() to execute a function only when logged in, replaces a bunch of copy/pasted stuff in mainwindow moved common variables in ModInfoDialogTab moved DescriptionPage to modinfodialognexus.h, renamed to NexusTabWebpage, deleted now empty descriptionpage.h --- src/CMakeLists.txt | 5 +- src/descriptionpage.h | 28 ----- src/mainwindow.cpp | 167 ++++++------------------ src/modinfodialog.cpp | 233 +++------------------------------- src/modinfodialog.h | 29 ----- src/modinfodialog.ui | 222 +++++++++++++++----------------- src/modinfodialogcategories.cpp | 43 +++---- src/modinfodialogcategories.h | 8 +- src/modinfodialogconflicts.cpp | 91 ++++++-------- src/modinfodialogconflicts.h | 17 +-- src/modinfodialogesps.cpp | 8 +- src/modinfodialogesps.h | 7 +- src/modinfodialogimages.cpp | 6 +- src/modinfodialogimages.h | 5 +- src/modinfodialognexus.cpp | 273 ++++++++++++++++++++++++++++++++++++++++ src/modinfodialognexus.h | 67 ++++++++++ src/modinfodialogtab.cpp | 39 +++++- src/modinfodialogtab.h | 25 +++- src/modinfodialogtextfiles.cpp | 26 ++-- src/modinfodialogtextfiles.h | 12 +- src/modinforegular.cpp | 20 ++- src/modinforegular.h | 1 + src/organizercore.cpp | 15 +++ src/organizercore.h | 1 + 24 files changed, 690 insertions(+), 658 deletions(-) delete mode 100644 src/descriptionpage.h create mode 100644 src/modinfodialognexus.cpp create mode 100644 src/modinfodialognexus.h (limited to 'src/organizercore.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6ebfaddd..7dc39fd9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,6 +58,7 @@ SET(organizer_SRCS modinfodialogconflicts.cpp modinfodialogesps.cpp modinfodialogimages.cpp + modinfodialognexus.cpp modinfodialogtab.cpp modinfodialogtextfiles.cpp modinfo.cpp @@ -164,6 +165,7 @@ SET(organizer_HDRS modinfodialogconflicts.h modinfodialogesps.h modinfodialogimages.h + modinfodialognexus.h modinfodialogtab.h modinfodialogtextfiles.h modinfo.h @@ -223,7 +225,6 @@ SET(organizer_HDRS instancemanager.h usvfsconnector.h eventfilter.h - descriptionpage.h moshortcut.h listdialog.h lcdnumber.h @@ -368,6 +369,7 @@ set(modinfo modinfodialogconflicts modinfodialogesps modinfodialogimages + modinfodialognexus modinfodialogtab modinfodialogtextfiles modinfoforeign @@ -424,7 +426,6 @@ set(utilities ) set(widgets - descriptionpage expanderwidget genericicondelegate filerenamer diff --git a/src/descriptionpage.h b/src/descriptionpage.h deleted file mode 100644 index f6158ee0..00000000 --- a/src/descriptionpage.h +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#ifndef DESCRIPTIONPAGE_H -#define DESCRIPTIONPAGE_H - -class DescriptionPage : public QWebEnginePage -{ - Q_OBJECT - -public: - DescriptionPage(QObject* parent = 0) : QWebEnginePage(parent){} - - bool acceptNavigationRequest(const QUrl & url, QWebEnginePage::NavigationType type, bool isMainFrame) - { - if (type == QWebEnginePage::NavigationTypeLinkClicked) - { - emit linkClicked(url); - return false; - } - return true; - } - -signals: - void linkClicked(const QUrl&); - -}; - -#endif //DESCRIPTIONPAGE_H diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index da7c721d..8eb0838e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3073,66 +3073,34 @@ void MainWindow::backupMod_clicked() void MainWindow::resumeDownload(int downloadIndex) { - if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->validated()) { + m_OrganizerCore.loggedInAction(this, [this, downloadIndex] { m_OrganizerCore.downloadManager()->resumeDownload(downloadIndex); - } else { - QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { - m_OrganizerCore.doAfterLogin([this, downloadIndex] () { - this->resumeDownload(downloadIndex); - }); - NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); - } else { - MessageDialog::showMessage(tr("You need to be logged in with Nexus to resume a download"), this); - } - } + }); } void MainWindow::endorseMod(ModInfo::Ptr mod) { - if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->validated()) { + m_OrganizerCore.loggedInAction(this, [this, mod] { mod->endorse(true); - } else { - QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { - m_OrganizerCore.doAfterLogin([&]() { this->endorseMod(mod); }); - NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); - } else { - MessageDialog::showMessage(tr("You need to be logged in with Nexus to endorse"), this); - } - } + }); } void MainWindow::endorse_clicked() { QItemSelectionModel *selection = ui->modList->selectionModel(); - if (selection->hasSelection() && selection->selectedRows().count() > 1) { - if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->validated()) { + + m_OrganizerCore.loggedInAction(this, [this] { + QItemSelectionModel *selection = ui->modList->selectionModel(); + if (selection->hasSelection() && selection->selectedRows().count() > 1) { MessageDialog::showMessage(tr("Endorsing multiple mods will take a while. Please wait..."), this); - for (QModelIndex idx : selection->selectedRows()) { - ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->endorse(true); - } } - else { - QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { - MessageDialog::showMessage(tr("Endorsing multiple mods will take a while. Please wait..."), this); - for (QModelIndex idx : selection->selectedRows()) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - m_OrganizerCore.doAfterLogin([&]() { this->endorseMod(modInfo); }); - } - NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); - } else { - MessageDialog::showMessage(tr("You need to be logged in with Nexus to endorse"), this); - return; - } + + for (QModelIndex idx : selection->selectedRows()) { + ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->endorse(true); } - } - else { - endorseMod(ModInfo::getByIndex(m_ContextRow)); - } + }); } void MainWindow::dontendorse_clicked() @@ -3151,114 +3119,53 @@ void MainWindow::dontendorse_clicked() void MainWindow::unendorseMod(ModInfo::Ptr mod) { - if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->validated()) { - ModInfo::getByIndex(m_ContextRow)->endorse(false); - } else { - QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { - m_OrganizerCore.doAfterLogin([&]() { this->unendorseMod(mod); }); - NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); - } else { - MessageDialog::showMessage(tr("You need to be logged in with Nexus to endorse"), this); - } - } + m_OrganizerCore.loggedInAction(this, [mod] { + mod->endorse(false); + }); } void MainWindow::unendorse_clicked() { - QItemSelectionModel *selection = ui->modList->selectionModel(); - if (selection->hasSelection() && selection->selectedRows().count() > 1) { - if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->validated()) { + m_OrganizerCore.loggedInAction(this, [this] { + QItemSelectionModel *selection = ui->modList->selectionModel(); + if (selection->hasSelection() && selection->selectedRows().count() > 1) { MessageDialog::showMessage(tr("Unendorsing multiple mods will take a while. Please wait..."), this); - for (QModelIndex idx : selection->selectedRows()) { - ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->endorse(false); - } - } else { - QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { - MessageDialog::showMessage(tr("Unendorsing multiple mods will take a while. Please wait..."), this); - for (QModelIndex idx : selection->selectedRows()) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - m_OrganizerCore.doAfterLogin([&]() { this->unendorseMod(modInfo); }); - } - NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); - } else { - MessageDialog::showMessage(tr("You need to be logged in with Nexus to endorse"), this); - return; - } } - } - else { - unendorseMod(ModInfo::getByIndex(m_ContextRow)); - } + + for (QModelIndex idx : selection->selectedRows()) { + ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->endorse(false); + } + }); } void MainWindow::trackMod(ModInfo::Ptr mod, bool doTrack) { - if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->validated()) { - ModInfo::getByIndex(m_ContextRow)->track(doTrack); - } else { - QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { - m_OrganizerCore.doAfterLogin([&]() { this->trackMod(mod, doTrack); }); - NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); - } else { - MessageDialog::showMessage(tr("You need to be logged in with Nexus to track"), this); - } - } + m_OrganizerCore.loggedInAction(this, [mod, doTrack] { + mod->track(doTrack); + }); } void MainWindow::track_clicked() { - QItemSelectionModel *selection = ui->modList->selectionModel(); - if (selection->hasSelection() && selection->selectedRows().count() > 1) { - if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->validated()) { - for (auto idx : selection->selectedRows()) { - ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->track(true); - } - } else { - QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { - for (auto idx : selection->selectedRows()) { - auto modInfo = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - m_OrganizerCore.doAfterLogin([&]() { this->trackMod(modInfo, true); }); - } - NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); - } else { - MessageDialog::showMessage(tr("You need to be logged in with Nexus to track"), this); - } + m_OrganizerCore.loggedInAction(this, [this] { + QItemSelectionModel *selection = ui->modList->selectionModel(); + for (auto idx : selection->selectedRows()) { + ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->track(true); } - } else { - trackMod(ModInfo::getByIndex(m_ContextRow), true); - } + }); } void MainWindow::untrack_clicked() { - QItemSelectionModel *selection = ui->modList->selectionModel(); - if (selection->hasSelection() && selection->selectedRows().count() > 1) { - if (NexusInterface::instance(&m_PluginContainer)->getAccessManager()->validated()) { - for (auto idx : selection->selectedRows()) { - ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->track(false); - } - } else { - QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { - for (auto idx : selection->selectedRows()) { - auto modInfo = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - m_OrganizerCore.doAfterLogin([&]() { this->trackMod(modInfo, false); }); - } - NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); - } else { - MessageDialog::showMessage(tr("You need to be logged in with Nexus to track"), this); - } + m_OrganizerCore.loggedInAction(this, [this] { + QItemSelectionModel *selection = ui->modList->selectionModel(); + for (auto idx : selection->selectedRows()) { + ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->track(false); } - } else { - trackMod(ModInfo::getByIndex(m_ContextRow), false); - } + }); } void MainWindow::validationFailed(const QString &error) @@ -3316,13 +3223,11 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, } else { modInfo->saveMeta(); ModInfoDialog dialog(modInfo, m_OrganizerCore.directoryStructure(), modInfo->hasFlag(ModInfo::FLAG_FOREIGN), &m_OrganizerCore, &m_PluginContainer, this); - connect(&dialog, SIGNAL(linkActivated(QString)), this, SLOT(linkClicked(QString))); connect(&dialog, SIGNAL(downloadRequest(QString)), &m_OrganizerCore, SLOT(downloadRequestedNXM(QString))); connect(&dialog, SIGNAL(modOpen(QString, int)), this, SLOT(displayModInformation(QString, int)), Qt::QueuedConnection); connect(&dialog, SIGNAL(modOpenNext(int)), this, SLOT(modOpenNext(int)), Qt::QueuedConnection); connect(&dialog, SIGNAL(modOpenPrev(int)), this, SLOT(modOpenPrev(int)), Qt::QueuedConnection); connect(&dialog, SIGNAL(originModified(int)), this, SLOT(originModified(int))); - connect(&dialog, SIGNAL(endorseMod(ModInfo::Ptr)), this, SLOT(endorseMod(ModInfo::Ptr))); //Open the tab first if we want to use the standard indexes of the tabs. if (tab != -1) { diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 3263a511..30110d14 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -43,6 +43,7 @@ along with Mod Organizer. If not, see . #include "modinfodialogesps.h" #include "modinfodialogconflicts.h" #include "modinfodialogcategories.h" +#include "modinfodialognexus.h" #include #include @@ -145,7 +146,6 @@ FileRenamer::RenameResults unhideFile(FileRenamer& renamer, const QString &oldNa ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directory, bool unmanaged, OrganizerCore *organizerCore, PluginContainer *pluginContainer, QWidget *parent) : TutorableDialog("ModInfoDialog", parent), ui(new Ui::ModInfoDialog), m_ModInfo(modInfo), - m_RequestStarted(false), m_NewFolderAction(nullptr), m_OpenAction(nullptr), m_PreviewAction(nullptr), m_RenameAction(nullptr), m_DeleteAction(nullptr), m_HideAction(nullptr), m_UnhideAction(nullptr), m_Directory(directory), m_Origin(nullptr), @@ -173,38 +173,9 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo m_RootPath = modInfo->absolutePath(); - QString metaFileName = m_RootPath.mid(0).append("/meta.ini"); - m_Settings = new QSettings(metaFileName, QSettings::IniFormat); - - QLineEdit *modIDEdit = findChild("modIDEdit"); - ui->modIDEdit->setValidator(new QIntValidator(modIDEdit)); - ui->modIDEdit->setText(QString("%1").arg(modInfo->getNexusID())); - - connect(ui->modIDEdit, SIGNAL(linkClicked(QString)), this, SLOT(linkClicked(QString))); - - QString gameName = modInfo->getGameName(); - ui->sourceGameEdit->addItem(organizerCore->managedGame()->gameName(), organizerCore->managedGame()->gameShortName()); - if (organizerCore->managedGame()->validShortNames().size() == 0) { - ui->sourceGameEdit->setDisabled(true); - } else { - for (auto game : pluginContainer->plugins()) { - for (QString gameName : organizerCore->managedGame()->validShortNames()) { - if (game->gameShortName().compare(gameName, Qt::CaseInsensitive) == 0) { - ui->sourceGameEdit->addItem(game->gameName(), game->gameShortName()); - break; - } - } - } - } - ui->sourceGameEdit->setCurrentIndex(ui->sourceGameEdit->findData(gameName)); - ui->commentsEdit->setText(modInfo->comments()); ui->notesEdit->setText(modInfo->notes()); - ui->descriptionView->setPage(new DescriptionPage()); - - connect(m_ModInfo.data(), SIGNAL(modDetailsUpdated(bool)), this, SLOT(modDetailsUpdated(bool))); - connect(ui->descriptionView->page(), SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl))); //TODO: No easy way to delegate links //ui->descriptionView->page()->acceptNavigationRequest(QWebEnginePage::DelegateAllLinks); @@ -246,14 +217,12 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo ui->tabWidget->setTabEnabled(TAB_IMAGES, true); ui->tabWidget->setTabEnabled(TAB_ESPS, true); ui->tabWidget->setTabEnabled(TAB_CONFLICTS, true); + ui->tabWidget->setTabEnabled(TAB_CATEGORIES, true); + ui->tabWidget->setTabEnabled(TAB_NEXUS, true); initFiletree(modInfo); } - ui->endorseBtn->setVisible(Settings::instance().endorsementIntegration()); - ui->endorseBtn->setEnabled((m_ModInfo->endorsedState() == ModInfo::ENDORSED_FALSE) || - (m_ModInfo->endorsedState() == ModInfo::ENDORSED_NEVER)); - // activate first enabled tab for (int i = 0; i < ui->tabWidget->count(); ++i) { if (ui->tabWidget->isTabEnabled(i)) { @@ -262,10 +231,6 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo } } - if (ui->tabWidget->currentIndex() == TAB_NEXUS) { - activateNexusTab(); - } - for (auto& tab : m_tabs) { tab->setMod(m_ModInfo, m_Origin); } @@ -281,27 +246,28 @@ ModInfoDialog::~ModInfoDialog() else m_ModInfo->setNotes(ui->notesEdit->toHtml()); - delete ui->descriptionView->page(); - delete ui->descriptionView; delete ui; - delete m_Settings; } -std::vector> ModInfoDialog::createTabs() +template +std::vector> createTabsImpl( + OrganizerCore& oc, PluginContainer& plugin, + ModInfoDialog* self, Ui::ModInfoDialog* ui) { std::vector> v; - - v.push_back(std::make_unique(this, ui)); - v.push_back(std::make_unique(this, ui)); - v.push_back(std::make_unique(this, ui)); - v.push_back(std::make_unique(this, ui)); - v.push_back(std::make_unique( - this, ui, *m_OrganizerCore, *m_PluginContainer)); - v.push_back(std::make_unique(this, ui)); + (v.push_back(std::make_unique(oc, plugin, self, ui)), ...); return v; } +std::vector> ModInfoDialog::createTabs() +{ + return createTabsImpl< + TextFilesTab, IniFilesTab, ImagesTab, ESPsTab, + ConflictsTab, CategoriesTab, NexusTab>( + *m_OrganizerCore, *m_PluginContainer, this, ui); +} + int ModInfoDialog::exec() { refreshLists(); @@ -434,7 +400,6 @@ void ModInfoDialog::refreshFiles() } } - void ModInfoDialog::on_closeButton_clicked() { for (auto& tab : m_tabs) { @@ -446,19 +411,6 @@ void ModInfoDialog::on_closeButton_clicked() close(); } - - -QString ModInfoDialog::getModVersion() const -{ - return m_Settings->value("version", "").toString(); -} - - -const int ModInfoDialog::getModID() const -{ - return m_Settings->value("modid", 0).toInt(); -} - void ModInfoDialog::openTab(int tab) { QTabWidget *tabWidget = findChild("tabWidget"); @@ -467,40 +419,6 @@ void ModInfoDialog::openTab(int tab) } } -void ModInfoDialog::on_visitNexusLabel_linkActivated(const QString &link) -{ - emit linkActivated(link); -} - -void ModInfoDialog::linkClicked(const QUrl &url) -{ - //Ideally we'd ask the mod for the game and the web service then pass the game - //and URL to the web service - if (NexusInterface::instance(m_PluginContainer)->isURLGameRelated(url)) { - emit linkActivated(url.toString()); - } else { - shell::OpenLink(url); - } -} - -void ModInfoDialog::linkClicked(QString url) -{ - emit linkActivated(url); -} - - -void ModInfoDialog::refreshNexusData(int modID) -{ - if ((!m_RequestStarted) && (modID > 0)) { - m_RequestStarted = true; - - m_ModInfo->updateNXMInfo(); - - MessageDialog::showMessage(tr("Info requested, please wait"), this); - } -} - - QString ModInfoDialog::getFileCategory(int categoryID) { switch (categoryID) { @@ -514,111 +432,8 @@ QString ModInfoDialog::getFileCategory(int categoryID) } } - -void ModInfoDialog::updateVersionColor() -{ -// QPalette versionColor; - if (m_ModInfo->getVersion() != m_ModInfo->getNewestVersion()) { - ui->versionEdit->setStyleSheet("color: red"); -// versionColor.setColor(QPalette::Text, Qt::red); - ui->versionEdit->setToolTip(tr("Current Version: %1").arg(m_ModInfo->getNewestVersion().canonicalString())); - } else { - ui->versionEdit->setStyleSheet("color: green"); -// versionColor.setColor(QPalette::Text, Qt::green); - ui->versionEdit->setToolTip(tr("No update available")); - } -// ui->versionEdit->setPalette(versionColor); -} - - -void ModInfoDialog::modDetailsUpdated(bool success) -{ - QString nexusDescription = m_ModInfo->getNexusDescription(); - QString descriptionAsHTML = "" - "" - "%1" - ""; - - if (!nexusDescription.isEmpty()) { - descriptionAsHTML = descriptionAsHTML.arg(BBCode::convertToHTML(nexusDescription)); - } else { - descriptionAsHTML = descriptionAsHTML.arg(tr("

Uh oh!

Sorry, there is no description available for this mod. :(

")); - } - - ui->descriptionView->page()->setHtml(descriptionAsHTML); - - updateVersionColor(); -} - - -void ModInfoDialog::activateNexusTab() -{ - QLineEdit *modIDEdit = findChild("modIDEdit"); - int modID = modIDEdit->text().toInt(); - if (modID > 0) { - QString nexusLink = NexusInterface::instance(m_PluginContainer)->getModURL(modID, m_ModInfo->getGameName()); - QLabel *visitNexusLabel = findChild("visitNexusLabel"); - visitNexusLabel->setText(tr("Visit on Nexus").arg(nexusLink)); - visitNexusLabel->setToolTip(nexusLink); - m_ModInfo->setURL(nexusLink); - - if (m_ModInfo->getNexusDescription().isEmpty() || QDateTime::currentDateTimeUtc() >= m_ModInfo->getLastNexusQuery().addDays(1)) { - refreshNexusData(modID); - } else { - modDetailsUpdated(true); - } - } else - modDetailsUpdated(true); - QLineEdit *versionEdit = findChild("versionEdit"); - QString currentVersion = m_Settings->value("version", "???").toString(); - versionEdit->setText(currentVersion); - ui->customUrlLineEdit->setText(m_ModInfo->getURL()); -} - - void ModInfoDialog::on_tabWidget_currentChanged(int index) { - if (index == TAB_NEXUS || m_RealTabPos[index] == TAB_NEXUS) { - activateNexusTab(); - } -} - - -void ModInfoDialog::on_modIDEdit_editingFinished() -{ - int oldID = m_Settings->value("modid", 0).toInt(); - int modID = ui->modIDEdit->text().toInt(); - if (oldID != modID){ - m_ModInfo->setNexusID(modID); - - ui->descriptionView->page()->setHtml(""); - if (modID != 0) { - m_RequestStarted = false; - refreshNexusData(modID); - } - } -} - -void ModInfoDialog::on_sourceGameEdit_currentIndexChanged(int) -{ - for (auto game : m_PluginContainer->plugins()) { - if (game->gameName() == ui->sourceGameEdit->currentText()) { - m_ModInfo->setGameName(game->gameShortName()); - return; - } - } -} - -void ModInfoDialog::on_versionEdit_editingFinished() -{ - VersionInfo version(ui->versionEdit->text()); - m_ModInfo->setVersion(version); - updateVersionColor(); -} - -void ModInfoDialog::on_customUrlLineEdit_editingFinished() -{ - m_ModInfo->setURL(ui->customUrlLineEdit->text()); } bool ModInfoDialog::recursiveDelete(const QModelIndex &index) @@ -975,22 +790,6 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) menu.exec(ui->fileTree->viewport()->mapToGlobal(pos)); } - -void ModInfoDialog::on_refreshButton_clicked() -{ - if (m_ModInfo->getNexusID() > 0) { - QLineEdit *modIDEdit = findChild("modIDEdit"); - int modID = modIDEdit->text().toInt(); - refreshNexusData(modID); - } else - qInfo("Mod has no valid Nexus ID, info can't be updated."); -} - -void ModInfoDialog::on_endorseBtn_clicked() -{ - emit endorseMod(m_ModInfo); -} - void ModInfoDialog::on_nextButton_clicked() { int currentTab = ui->tabWidget->currentIndex(); diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 384aafce..7b96d21a 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -138,18 +138,11 @@ public: void restoreState(const Settings& s); signals: - - void linkActivated(const QString &link); void downloadRequest(const QString &link); void modOpen(const QString &modName, int tab); void modOpenNext(int tab=-1); void modOpenPrev(int tab=-1); void originModified(int originID); - void endorseMod(ModInfo::Ptr nexusID); - -public slots: - - void modDetailsUpdated(bool success); private: @@ -157,10 +150,6 @@ private: void refreshLists(); - void updateVersionColor(); - - void refreshNexusData(int modID); - void activateNexusTab(); QString getFileCategory(int categoryID); bool recursiveDelete(const QModelIndex &index); void deleteFile(const QModelIndex &index); @@ -168,9 +157,6 @@ private: int tabIndex(const QString &tabId); private slots: - void linkClicked(const QUrl &url); - void linkClicked(QString url); - void delete_activated(); void createDirectoryTriggered(); @@ -183,20 +169,10 @@ private slots: void on_openInExplorerButton_clicked(); void on_closeButton_clicked(); - void on_visitNexusLabel_linkActivated(const QString &link); - void on_modIDEdit_editingFinished(); - void on_sourceGameEdit_currentIndexChanged(int); - void on_versionEdit_editingFinished(); - void on_customUrlLineEdit_editingFinished(); void on_tabWidget_currentChanged(int index); void on_fileTree_customContextMenuRequested(const QPoint &pos); - void on_refreshButton_clicked(); - - void on_endorseBtn_clicked(); - void on_nextButton_clicked(); - void on_prevButton_clicked(); private: @@ -217,11 +193,6 @@ private: QTreeView *m_FileTree; QModelIndexList m_FileSelection; - QSettings *m_Settings; - - std::set m_RequestIDs; - bool m_RequestStarted; - QAction *m_NewFolderAction; QAction *m_OpenAction; QAction *m_PreviewAction; diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index c8ffd470..29a7400f 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -829,7 +829,7 @@ text-align: left; - + true @@ -853,13 +853,13 @@ text-align: left; - +
- + :/MO/gui/resources/internet-web-browser.png:/MO/gui/resources/internet-web-browser.png @@ -870,6 +870,60 @@ text-align: left; + + + + + 0 + 0 + + + + Refresh + + + Refresh all information from Nexus. + + + Refresh + + + + :/MO/gui/refresh:/MO/gui/refresh + + + Qt::ToolButtonTextBesideIcon + + + + + + + Open in Browser + + + + :/MO/gui/resources/internet-web-browser.png:/MO/gui/resources/internet-web-browser.png + + + Qt::ToolButtonTextBesideIcon + + + + + + + Endorse + + + + :/MO/gui/icon_favorite:/MO/gui/icon_favorite + + + Qt::ToolButtonTextBesideIcon + + + @@ -878,7 +932,7 @@ text-align: left; - + Mod ID for this mod on Nexus. @@ -891,22 +945,6 @@ p, li { white-space: pre-wrap; } - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 20 - - - - @@ -915,7 +953,7 @@ p, li { white-space: pre-wrap; } - + Source game for this mod. @@ -925,20 +963,7 @@ p, li { white-space: pre-wrap; } - - - Qt::Horizontal - - - - 40 - 20 - - - - - - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> @@ -952,7 +977,7 @@ p, li { white-space: pre-wrap; } - + 150 @@ -967,102 +992,61 @@ p, li { white-space: pre-wrap; } - - - - - - 0 - 0 - - - - Refresh - - - Refresh all information from Nexus. - - - - - - - :/MO/gui/refresh:/MO/gui/refresh - - - - - - - Description - - - - - - - - - - 0 - 0 - - - - - 0 - 200 - + + + QFrame::StyledPanel - - - about:blank - + + QFrame::Sunken + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 200 + + + + + about:blank + + + + + - - - - - - - 1 - 0 - - - - - - - false - - - - - - - Endorse - - - - :/MO/gui/icon_favorite:/MO/gui/icon_favorite - - - - - - Web page URL (only used if invalid Nexus ID) : + URL - + diff --git a/src/modinfodialogcategories.cpp b/src/modinfodialogcategories.cpp index 7df13aea..69c7c6b5 100644 --- a/src/modinfodialogcategories.cpp +++ b/src/modinfodialogcategories.cpp @@ -3,28 +3,25 @@ #include "categories.h" #include "modinfo.h" -CategoriesTab::CategoriesTab(QWidget*, Ui::ModInfoDialog* ui) - : ui(ui) +CategoriesTab::CategoriesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) + : ModInfoDialogTab(oc, plugin, parent, ui) { connect( - ui->categoriesTree, &QTreeWidget::itemChanged, + ui->categories, &QTreeWidget::itemChanged, [&](auto* item, int col){ onCategoryChanged(item, col); }); connect( - ui->primaryCategoryBox, + ui->primaryCategories, static_cast(&QComboBox::currentIndexChanged), [&](int index){ onPrimaryChanged(index); }); } -void CategoriesTab::setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) -{ - m_mod = mod; -} - void CategoriesTab::clear() { - ui->categoriesTree->clear(); - ui->primaryCategoryBox->clear(); + ui->categories->clear(); + ui->primaryCategories->clear(); } void CategoriesTab::update() @@ -32,8 +29,8 @@ void CategoriesTab::update() clear(); add( - CategoryFactory::instance(), m_mod->getCategories(), - ui->categoriesTree->invisibleRootItem(), 0); + CategoryFactory::instance(), mod()->getCategories(), + ui->categories->invisibleRootItem(), 0); updatePrimary(); } @@ -71,15 +68,15 @@ void CategoriesTab::add( void CategoriesTab::updatePrimary() { - ui->primaryCategoryBox->clear(); + ui->primaryCategories->clear(); - int primaryCategory = m_mod->getPrimaryCategory(); + int primaryCategory = mod()->getPrimaryCategory(); - addChecked(ui->categoriesTree->invisibleRootItem()); + addChecked(ui->categories->invisibleRootItem()); - for (int i = 0; i < ui->primaryCategoryBox->count(); ++i) { - if (ui->primaryCategoryBox->itemData(i).toInt() == primaryCategory) { - ui->primaryCategoryBox->setCurrentIndex(i); + for (int i = 0; i < ui->primaryCategories->count(); ++i) { + if (ui->primaryCategories->itemData(i).toInt() == primaryCategory) { + ui->primaryCategories->setCurrentIndex(i); break; } } @@ -90,7 +87,7 @@ void CategoriesTab::addChecked(QTreeWidgetItem* tree) for (int i = 0; i < tree->childCount(); ++i) { QTreeWidgetItem *child = tree->child(i); if (child->checkState(0) == Qt::Checked) { - ui->primaryCategoryBox->addItem(child->text(0), child->data(0, Qt::UserRole)); + ui->primaryCategories->addItem(child->text(0), child->data(0, Qt::UserRole)); addChecked(child); } } @@ -101,7 +98,7 @@ void CategoriesTab::save(QTreeWidgetItem* currentNode) for (int i = 0; i < currentNode->childCount(); ++i) { QTreeWidgetItem *childNode = currentNode->child(i); - m_mod->setCategory( + mod()->setCategory( childNode->data(0, Qt::UserRole).toInt(), childNode->checkState(0)); save(childNode); @@ -118,12 +115,12 @@ void CategoriesTab::onCategoryChanged(QTreeWidgetItem* item, int) } updatePrimary(); - save(ui->categoriesTree->invisibleRootItem()); + save(ui->categories->invisibleRootItem()); } void CategoriesTab::onPrimaryChanged(int index) { if (index != -1) { - m_mod->setPrimaryCategory(ui->primaryCategoryBox->itemData(index).toInt()); + mod()->setPrimaryCategory(ui->primaryCategories->itemData(index).toInt()); } } diff --git a/src/modinfodialogcategories.h b/src/modinfodialogcategories.h index c0644c7f..76426a5d 100644 --- a/src/modinfodialogcategories.h +++ b/src/modinfodialogcategories.h @@ -5,16 +5,14 @@ class CategoryFactory; class CategoriesTab : public ModInfoDialogTab { public: - CategoriesTab(QWidget* parent, Ui::ModInfoDialog* ui); + CategoriesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); void clear() override; - void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) override; void update() override; private: - Ui::ModInfoDialog* ui; - ModInfo::Ptr m_mod; - void add( const CategoryFactory& factory, const std::set& enabledCategories, QTreeWidgetItem* root, int rootLevel); diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index d2dca492..4176ac3e 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -116,10 +116,10 @@ public: ConflictsTab::ConflictsTab( - QWidget* parent, Ui::ModInfoDialog* ui, - OrganizerCore& oc, PluginContainer& plugin) : - m_parent(parent), ui(ui), m_core(oc), m_plugin(plugin), - m_origin(nullptr), m_general(this, ui, oc), m_advanced(this, ui, oc) + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) : + ModInfoDialogTab(oc, plugin, parent, ui), + m_general(this, ui, oc), m_advanced(this, ui, oc) { connect( &m_general, &GeneralConflictsTab::modOpen, @@ -130,15 +130,6 @@ ConflictsTab::ConflictsTab( [&](const QString& name){ emitModOpen(name); }); } -void ConflictsTab::setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) -{ - m_mod = mod; - m_origin = origin; - - m_general.setMod(mod, origin); - m_advanced.setMod(mod, origin); -} - void ConflictsTab::update() { m_general.update(); @@ -186,7 +177,7 @@ void ConflictsTab::changeItemsVisibility( flags |= FileRenamer::MULTIPLE; } - FileRenamer renamer(m_parent, flags); + FileRenamer renamer(parentWidget(), flags); for (const auto* item : items) { if (stop) { @@ -242,8 +233,8 @@ void ConflictsTab::changeItemsVisibility( if (changed) { qDebug().nospace() << "triggering refresh"; - if (m_origin) { - emit originModified(m_origin->getID()); + if (origin()) { + emit originModified(origin()->getID()); } update(); @@ -256,7 +247,7 @@ void ConflictsTab::openItems(const QList& items) // in case this changes for (auto* item : items) { if (auto* ci=dynamic_cast(item)) { - m_core.executeFileVirtualized(m_parent, ci->fileName()); + core().executeFileVirtualized(parentWidget(), ci->fileName()); } } } @@ -267,7 +258,7 @@ void ConflictsTab::previewItems(const QList& items) // in case this changes for (auto* item : items) { if (auto* ci=dynamic_cast(item)) { - m_core.previewFileWithAlternatives(m_parent, ci->fileName()); + core().previewFileWithAlternatives(parentWidget(), ci->fileName()); } } } @@ -355,7 +346,7 @@ ConflictsTab::Actions ConflictsTab::createMenuActions( enableHide = ci->canHide(); enableUnhide = ci->canUnhide(); enableOpen = ci->canOpen(); - enablePreview = ci->canPreview(m_plugin); + enablePreview = ci->canPreview(plugin()); enableGoto = ci->hasAlts(); } else { @@ -394,21 +385,21 @@ ConflictsTab::Actions ConflictsTab::createMenuActions( Actions actions; - actions.hide = new QAction(tr("Hide"), m_parent); + actions.hide = new QAction(tr("Hide"), parentWidget()); actions.hide->setEnabled(enableHide); // note that it is possible for hidden files to appear if they override other // hidden files from another mod - actions.unhide = new QAction(tr("Unhide"), m_parent); + actions.unhide = new QAction(tr("Unhide"), parentWidget()); actions.unhide->setEnabled(enableUnhide); - actions.open = new QAction(tr("Open/Execute"), m_parent); + actions.open = new QAction(tr("Open/Execute"), parentWidget()); actions.open->setEnabled(enableOpen); - actions.preview = new QAction(tr("Preview"), m_parent); + actions.preview = new QAction(tr("Preview"), parentWidget()); actions.preview->setEnabled(enablePreview); - actions.gotoMenu = new QMenu(tr("Go to..."), m_parent); + actions.gotoMenu = new QMenu(tr("Go to..."), parentWidget()); actions.gotoMenu->setEnabled(enableGoto); if (enableGoto) { @@ -421,7 +412,7 @@ ConflictsTab::Actions ConflictsTab::createMenuActions( std::vector ConflictsTab::createGotoActions( const QList& selection) { - if (!m_origin || selection.size() != 1) { + if (!origin() || selection.size() != 1) { return {}; } @@ -430,26 +421,26 @@ std::vector ConflictsTab::createGotoActions( return {}; } - auto file = m_origin->findFile(item->fileIndex()); + auto file = origin()->findFile(item->fileIndex()); if (!file) { return {}; } std::vector mods; - const auto& ds = *m_core.directoryStructure(); + const auto& ds = *core().directoryStructure(); // add all alternatives for (const auto& alt : file->getAlternatives()) { const auto& o = ds.getOriginByID(alt.first); - if (o.getID() != m_origin->getID()) { + if (o.getID() != origin()->getID()) { mods.push_back(ToQString(o.getName())); } } // add the real origin if different from this mod const FilesOrigin& realOrigin = ds.getOriginByID(file->getOrigin()); - if (realOrigin.getID() != m_origin->getID()) { + if (realOrigin.getID() != origin()->getID()) { mods.push_back(ToQString(realOrigin.getName())); } @@ -460,7 +451,7 @@ std::vector ConflictsTab::createGotoActions( std::vector actions; for (const auto& name : mods) { - actions.push_back(new QAction(name, m_parent)); + actions.push_back(new QAction(name, parentWidget())); } return actions; @@ -469,7 +460,7 @@ std::vector ConflictsTab::createGotoActions( GeneralConflictsTab::GeneralConflictsTab( ConflictsTab* tab, Ui::ModInfoDialog* ui, OrganizerCore& oc) - : m_tab(tab), ui(ui), m_core(oc), m_origin(nullptr) + : m_tab(tab), ui(ui), m_core(oc) { m_expanders.overwrite.set(ui->overwriteExpander, ui->overwriteTree, true); m_expanders.overwritten.set(ui->overwrittenExpander, ui->overwrittenTree, true); @@ -560,12 +551,6 @@ void GeneralConflictsTab::restoreState(const Settings& s) .value("mod_info_conflicts_general_overwritten").toByteArray()); } -void GeneralConflictsTab::setMod(ModInfo::Ptr mod, FilesOrigin* origin) -{ - m_mod = mod; - m_origin = origin; -} - void GeneralConflictsTab::update() { clear(); @@ -574,10 +559,10 @@ void GeneralConflictsTab::update() int numOverwrite = 0; int numOverwritten = 0; - if (m_origin != nullptr) { - const auto rootPath = m_mod->absolutePath(); + if (m_tab->origin() != nullptr) { + const auto rootPath = m_tab->mod()->absolutePath(); - for (const auto& file : m_origin->getFiles()) { + for (const auto& file : m_tab->origin()->getFiles()) { const QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); const QString fileName = relativeName.mid(0).prepend(rootPath); @@ -585,7 +570,7 @@ void GeneralConflictsTab::update() const int fileOrigin = file->getOrigin(archive); const auto& alternatives = file->getAlternatives(); - if (fileOrigin == m_origin->getID()) { + if (fileOrigin == m_tab->origin()->getID()) { if (!alternatives.empty()) { ui->overwriteTree->addTopLevelItem(createOverwriteItem( file->getIndex(), archive, fileName, relativeName, alternatives)); @@ -684,7 +669,7 @@ void GeneralConflictsTab::onOverwrittenActivated(QTreeWidgetItem *item, int) AdvancedConflictsTab::AdvancedConflictsTab( ConflictsTab* tab, Ui::ModInfoDialog* ui, OrganizerCore& oc) - : m_tab(tab), ui(ui), m_core(oc), m_origin(nullptr) + : m_tab(tab), ui(ui), m_core(oc) { // left-elide the overwrites column so that the nearest are visible ui->conflictsAdvancedList->setItemDelegateForColumn( @@ -760,20 +745,14 @@ void AdvancedConflictsTab::restoreState(const Settings& s) } } -void AdvancedConflictsTab::setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) -{ - m_mod = mod; - m_origin = origin; -} - void AdvancedConflictsTab::update() { clear(); - if (m_origin != nullptr) { - const auto rootPath = m_mod->absolutePath(); + if (m_tab->origin() != nullptr) { + const auto rootPath = m_tab->mod()->absolutePath(); - for (const auto& file : m_origin->getFiles()) { + for (const auto& file : m_tab->origin()->getFiles()) { const QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); const QString fileName = relativeName.mid(0).prepend(rootPath); @@ -813,14 +792,14 @@ QTreeWidgetItem* AdvancedConflictsTab::createItem( // fills 'before' and 'after' with all the alternatives that come // before and after this mod in terms of priority - if (altOrigin.getPriority() < m_origin->getPriority()) { + if (altOrigin.getPriority() < m_tab->origin()->getPriority()) { // add all the mods having a lower priority than this one if (!before.isEmpty()) { before += ", "; } before += ToQString(altOrigin.getName()); - } else if (altOrigin.getPriority() > m_origin->getPriority()) { + } else if (altOrigin.getPriority() > m_tab->origin()->getPriority()) { // add all the mods having a higher priority than this one if (!after.isEmpty()) { after += ", "; @@ -832,7 +811,7 @@ QTreeWidgetItem* AdvancedConflictsTab::createItem( // keep track of the nearest mods that come before and after this one // in terms of priority - if (altOrigin.getPriority() < m_origin->getPriority()) { + if (altOrigin.getPriority() < m_tab->origin()->getPriority()) { // the alternative has a lower priority than this mod if (altOrigin.getPriority() > beforePrio) { @@ -843,7 +822,7 @@ QTreeWidgetItem* AdvancedConflictsTab::createItem( } } - if (altOrigin.getPriority() > m_origin->getPriority()) { + if (altOrigin.getPriority() > m_tab->origin()->getPriority()) { // the alternative has a higher priority than this mod if (altOrigin.getPriority() < afterPrio) { @@ -869,7 +848,7 @@ QTreeWidgetItem* AdvancedConflictsTab::createItem( // if no mods overwrite this file, the primary origin is the same as this // mod, so ignore that - if (realOrigin.getID() != m_origin->getID()) { + if (realOrigin.getID() != m_tab->origin()->getID()) { if (!after.isEmpty()) { after += ", "; } diff --git a/src/modinfodialogconflicts.h b/src/modinfodialogconflicts.h index 212a196d..20362575 100644 --- a/src/modinfodialogconflicts.h +++ b/src/modinfodialogconflicts.h @@ -21,7 +21,6 @@ public: void saveState(Settings& s); void restoreState(const Settings& s); - void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin); void update(); signals: @@ -36,8 +35,6 @@ private: ConflictsTab* m_tab; Ui::ModInfoDialog* ui; OrganizerCore& m_core; - ModInfo::Ptr m_mod; - MOShared::FilesOrigin* m_origin; Expanders m_expanders; QTreeWidgetItem* createOverwriteItem( @@ -74,7 +71,6 @@ public: void saveState(Settings& s); void restoreState(const Settings& s); - void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin); void update(); signals: @@ -84,8 +80,6 @@ private: ConflictsTab* m_tab; Ui::ModInfoDialog* ui; OrganizerCore& m_core; - ModInfo::Ptr m_mod; - MOShared::FilesOrigin* m_origin; FilterWidget m_filter; QTreeWidgetItem* createItem( @@ -101,10 +95,9 @@ class ConflictsTab : public ModInfoDialogTab public: ConflictsTab( - QWidget* parent, Ui::ModInfoDialog* ui, - OrganizerCore& oc, PluginContainer& plugin); + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); - void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) override; void update() override; void clear() override; @@ -136,12 +129,6 @@ private: } }; - QWidget* m_parent; - Ui::ModInfoDialog* ui; - OrganizerCore& m_core; - PluginContainer& m_plugin; - ModInfo::Ptr m_mod; - MOShared::FilesOrigin* m_origin; GeneralConflictsTab m_general; AdvancedConflictsTab m_advanced; diff --git a/src/modinfodialogesps.cpp b/src/modinfodialogesps.cpp index cb3dcc84..ea7eb3b0 100644 --- a/src/modinfodialogesps.cpp +++ b/src/modinfodialogesps.cpp @@ -122,8 +122,10 @@ private: }; -ESPsTab::ESPsTab(QWidget* parent, Ui::ModInfoDialog* ui) - : m_parent(parent), ui(ui) +ESPsTab::ESPsTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) + : ModInfoDialogTab(oc, plugin, parent, ui) { QObject::connect( ui->activateESP, &QToolButton::clicked, [&]{ onActivate(); }); @@ -187,7 +189,7 @@ void ESPsTab::onActivate() bool okClicked = false; newName = QInputDialog::getText( - m_parent, + parentWidget(), QObject::tr("File Exists"), QObject::tr("A file with that name exists, please enter a new one"), QLineEdit::Normal, file.fileName(), &okClicked); diff --git a/src/modinfodialogesps.h b/src/modinfodialogesps.h index d71ad3ff..e1a7a4f7 100644 --- a/src/modinfodialogesps.h +++ b/src/modinfodialogesps.h @@ -10,15 +10,14 @@ class ESPsTab : public ModInfoDialogTab Q_OBJECT; public: - ESPsTab(QWidget* parent, Ui::ModInfoDialog* ui); + ESPsTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); void clear() override; bool feedFile(const QString& rootPath, const QString& fullPath) override; private: - QWidget* m_parent; - Ui::ModInfoDialog* ui; - void onActivate(); void onDeactivate(); diff --git a/src/modinfodialogimages.cpp b/src/modinfodialogimages.cpp index 752c8d0c..1c7dcc1f 100644 --- a/src/modinfodialogimages.cpp +++ b/src/modinfodialogimages.cpp @@ -80,8 +80,10 @@ void ScalableImage::mousePressEvent(QMouseEvent* e) } -ImagesTab::ImagesTab(QWidget*, Ui::ModInfoDialog* ui) - : ui(ui), m_image(new ScalableImage) +ImagesTab::ImagesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) + : ModInfoDialogTab(oc, plugin, parent, ui), m_image(new ScalableImage) { ui->imagesImage->layout()->addWidget(m_image); ui->imagesThumbnails->setLayout(new QVBoxLayout); diff --git a/src/modinfodialogimages.h b/src/modinfodialogimages.h index 708045c8..7853935a 100644 --- a/src/modinfodialogimages.h +++ b/src/modinfodialogimages.h @@ -34,13 +34,14 @@ class ImagesTab : public ModInfoDialogTab Q_OBJECT; public: - ImagesTab(QWidget* parent, Ui::ModInfoDialog* ui); + ImagesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); void clear() override; bool feedFile(const QString& rootPath, const QString& fullPath) override; private: - Ui::ModInfoDialog* ui; ScalableImage* m_image; void add(const QString& fullPath); diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp new file mode 100644 index 00000000..753d43de --- /dev/null +++ b/src/modinfodialognexus.cpp @@ -0,0 +1,273 @@ +#include "modinfodialognexus.h" +#include "ui_modinfodialog.h" +#include "settings.h" +#include "organizercore.h" +#include "iplugingame.h" +#include "bbcode.h" +#include +#include + +NexusTab::NexusTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) + : ModInfoDialogTab(oc, plugin, parent, ui), m_requestStarted(false) +{ + ui->modID->setValidator(new QIntValidator(ui->modID)); + ui->endorse->setVisible(core().settings().endorsementIntegration()); + + connect(ui->modID, &QLineEdit::editingFinished, [&]{ onModIDChanged(); }); + connect(ui->version, &QLineEdit::editingFinished, [&]{ onVersionChanged(); }); + connect(ui->openInBrowser, &QToolButton::clicked, [&]{ onOpenLink(); }); + connect(ui->url, &QLineEdit::editingFinished, [&]{ onUrlChanged(); }); + connect(ui->endorse, &QToolButton::clicked, [&]{ onEndorse(); }); + connect(ui->refresh, &QToolButton::clicked, [&]{ updateWebpage(); }); + + connect( + ui->sourceGame, + static_cast(&QComboBox::currentIndexChanged), + [&]{ onSourceGameChanged(); }); +} + +NexusTab::~NexusTab() +{ + cleanup(); +} + +void NexusTab::cleanup() +{ + if (m_modConnection) { + disconnect(m_modConnection); + m_modConnection = {}; + } +} + +void NexusTab::clear() +{ + ui->modID->clear(); + ui->sourceGame->clear(); + ui->version->clear(); + ui->browser->setPage(new NexusTabWebpage(ui->browser)); + ui->url->clear(); +} + +void NexusTab::update() +{ + clear(); + + ui->modID->setText(QString("%1").arg(mod()->getNexusID())); + + QString gameName = mod()->getGameName(); + ui->sourceGame->addItem( + core().managedGame()->gameName(), + core().managedGame()->gameShortName()); + + if (core().managedGame()->validShortNames().size() == 0) { + ui->sourceGame->setDisabled(true); + } else { + for (auto game : plugin().plugins()) { + for (QString gameName : core().managedGame()->validShortNames()) { + if (game->gameShortName().compare(gameName, Qt::CaseInsensitive) == 0) { + ui->sourceGame->addItem(game->gameName(), game->gameShortName()); + break; + } + } + } + } + + ui->sourceGame->setCurrentIndex(ui->sourceGame->findData(gameName)); + + auto* page = new NexusTabWebpage(ui->browser); + ui->browser->setPage(page); + + connect( + page, &NexusTabWebpage::linkClicked, + [&](const QUrl& url){ MOBase::shell::OpenLink(url); }); + + ui->endorse->setEnabled( + (mod()->endorsedState() == ModInfo::ENDORSED_FALSE) || + (mod()->endorsedState() == ModInfo::ENDORSED_NEVER)); + + updateWebpage(); +} + +void NexusTab::setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) +{ + cleanup(); + + ModInfoDialogTab::setMod(mod, origin); + + m_modConnection = connect( + mod.data(), &ModInfo::modDetailsUpdated, [&]{ onModChanged(); }); +} + +void NexusTab::updateVersionColor() +{ + if (mod()->getVersion() != mod()->getNewestVersion()) { + ui->version->setStyleSheet("color: red"); + ui->version->setToolTip(tr("Current Version: %1").arg( + mod()->getNewestVersion().canonicalString())); + } else { + ui->version->setStyleSheet("color: green"); + ui->version->setToolTip(tr("No update available")); + } +} + +void NexusTab::updateWebpage() +{ + const int modID = mod()->getNexusID(); + + if (modID > 0) { + const QString nexusLink = NexusInterface::instance(&plugin()) + ->getModURL(modID, mod()->getGameName()); + + ui->openInBrowser->setToolTip(nexusLink); + mod()->setURL(nexusLink); + refreshData(modID); + } else { + onModChanged(); + } + + ui->version->setText(mod()->getVersion().displayString()); + ui->url->setText(mod()->getURL()); +} + +void NexusTab::onModChanged() +{ + m_requestStarted = false; + + const QString nexusDescription = mod()->getNexusDescription(); + + QString descriptionAsHTML = R"( + + + + + %1 +)"; + + if (nexusDescription.isEmpty()) { + descriptionAsHTML = descriptionAsHTML.arg(tr( + "
" + "

Uh oh!

" + "

Sorry, there is no description available for this mod. :(

" + "
")); + + } else { + descriptionAsHTML = descriptionAsHTML.arg( + BBCode::convertToHTML(nexusDescription)); + } + + ui->browser->page()->setHtml(descriptionAsHTML); + updateVersionColor(); +} + +void NexusTab::onModIDChanged() +{ + const int oldID = mod()->getNexusID(); + const int newID = ui->modID->text().toInt(); + + if (oldID != newID){ + mod()->setNexusID(newID); + mod()->setLastNexusQuery(QDateTime::fromSecsSinceEpoch(0)); + + ui->browser->page()->setHtml(""); + + if (newID != 0) { + refreshData(newID); + } + } +} + +void NexusTab::onSourceGameChanged() +{ + for (auto game : plugin().plugins()) { + if (game->gameName() == ui->sourceGame->currentText()) { + mod()->setGameName(game->gameShortName()); + mod()->setLastNexusQuery(QDateTime::fromSecsSinceEpoch(0)); + refreshData(mod()->getNexusID()); + return; + } + } +} + +void NexusTab::onVersionChanged() +{ + MOBase::VersionInfo version(ui->version->text()); + mod()->setVersion(version); + updateVersionColor(); +} + +void NexusTab::onUrlChanged() +{ + mod()->setURL(ui->url->text()); + mod()->setLastNexusQuery(QDateTime::fromSecsSinceEpoch(0)); +} + +void NexusTab::onOpenLink() +{ + const int modID = mod()->getNexusID(); + + if (modID > 0) { + const QString nexusLink = NexusInterface::instance(&plugin()) + ->getModURL(modID, mod()->getGameName()); + + MOBase::shell::OpenLink(QUrl(nexusLink)); + } +} + +void NexusTab::onRefreshBrowser() +{ + const auto modID = mod()->getNexusID(); + + if (modID > 0) { + refreshData(modID); + } else + qInfo("Mod has no valid Nexus ID, info can't be updated."); +} + +void NexusTab::onEndorse() +{ + core().loggedInAction(parentWidget(), [m=mod()]{ m->endorse(true); }); +} + +void NexusTab::refreshData(int modID) +{ + if (tryRefreshData(modID)) { + m_requestStarted = true; + } else { + onModChanged(); + } + + //MessageDialog::showMessage(tr("Info requested, please wait"), this); +} + +bool NexusTab::tryRefreshData(int modID) +{ + if (modID <= 0) { + qDebug() << "NexusTab: can't refresh, no mod id"; + return false; + } + + if (m_requestStarted) { + qDebug() << "NexusTab: a refresh request is already running"; + return false; + } + + if (!mod()->updateNXMInfo()) { + qDebug() << "NexusTab: nexus description does not need an update"; + return false; + } + + return true; +} diff --git a/src/modinfodialognexus.h b/src/modinfodialognexus.h new file mode 100644 index 00000000..2e328c6d --- /dev/null +++ b/src/modinfodialognexus.h @@ -0,0 +1,67 @@ +#ifndef MODINFODIALOGNEXUS_H +#define MODINFODIALOGNEXUS_H + +#include "modinfodialogtab.h" + +class NexusTabWebpage : public QWebEnginePage +{ + Q_OBJECT + +public: + NexusTabWebpage(QObject* parent = 0) + : QWebEnginePage(parent) + { + } + + bool acceptNavigationRequest( + const QUrl & url, QWebEnginePage::NavigationType type, bool) override + { + if (type == QWebEnginePage::NavigationTypeLinkClicked) + { + emit linkClicked(url); + return false; + } + + return true; + } + +signals: + void linkClicked(const QUrl&); +}; + + +class NexusTab : public ModInfoDialogTab +{ +public: + NexusTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); + + ~NexusTab(); + + void clear() override; + void update() override; + void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) override; + +private: + QMetaObject::Connection m_modConnection; + bool m_requestStarted; + + void cleanup(); + void updateVersionColor(); + void updateWebpage(); + + void refreshData(int modID); + bool tryRefreshData(int modID); + + void onModChanged(); + void onOpenLink(); + void onModIDChanged(); + void onSourceGameChanged(); + void onVersionChanged(); + void onRefreshBrowser(); + void onEndorse(); + void onUrlChanged(); +}; + +#endif // MODINFODIALOGNEXUS_H diff --git a/src/modinfodialogtab.cpp b/src/modinfodialogtab.cpp index 6dcff0ac..ae0de5e8 100644 --- a/src/modinfodialogtab.cpp +++ b/src/modinfodialogtab.cpp @@ -1,5 +1,12 @@ #include "modinfodialogtab.h" +ModInfoDialogTab::ModInfoDialogTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) + : ui(ui), m_core(oc), m_plugin(plugin), m_parent(parent), m_origin(nullptr) +{ +} + bool ModInfoDialogTab::feedFile(const QString&, const QString&) { // no-op @@ -21,14 +28,40 @@ void ModInfoDialogTab::restoreState(const Settings& s) // no-op } -void ModInfoDialogTab::setMod(ModInfo::Ptr, MOShared::FilesOrigin*) +void ModInfoDialogTab::update() { // no-op } -void ModInfoDialogTab::update() +void ModInfoDialogTab::setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) { - // no-op + m_mod = mod; + m_origin = origin; +} + +ModInfo::Ptr ModInfoDialogTab::mod() const +{ + return m_mod; +} + +MOShared::FilesOrigin* ModInfoDialogTab::origin() const +{ + return m_origin; +} + +OrganizerCore& ModInfoDialogTab::core() +{ + return m_core; +} + +PluginContainer& ModInfoDialogTab::plugin() +{ + return m_plugin; +} + +QWidget* ModInfoDialogTab::parentWidget() +{ + return m_parent; } void ModInfoDialogTab::emitOriginModified(int originID) diff --git a/src/modinfodialogtab.h b/src/modinfodialogtab.h index ead29d10..dd851b31 100644 --- a/src/modinfodialogtab.h +++ b/src/modinfodialogtab.h @@ -8,13 +8,13 @@ namespace MOShared { class FilesOrigin; } namespace Ui { class ModInfoDialog; } class Settings; +class OrganizerCore; class ModInfoDialogTab : public QObject { Q_OBJECT; public: - ModInfoDialogTab() = default; ModInfoDialogTab(const ModInfoDialogTab&) = delete; ModInfoDialogTab& operator=(const ModInfoDialogTab&) = delete; ModInfoDialogTab(ModInfoDialogTab&&) = default; @@ -22,21 +22,42 @@ public: virtual ~ModInfoDialogTab() = default; virtual void clear() = 0; + virtual void update(); virtual bool feedFile(const QString& rootPath, const QString& filename); virtual bool canClose(); virtual void saveState(Settings& s); virtual void restoreState(const Settings& s); virtual void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin); - virtual void update(); + + ModInfo::Ptr mod() const; + MOShared::FilesOrigin* origin() const; signals: void originModified(int originID); void modOpen(QString name); protected: + Ui::ModInfoDialog* ui; + + ModInfoDialogTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); + + OrganizerCore& core(); + PluginContainer& plugin(); + + QWidget* parentWidget(); + void emitOriginModified(int originID); void emitModOpen(QString name); + +private: + OrganizerCore& m_core; + PluginContainer& m_plugin; + QWidget* m_parent; + ModInfo::Ptr m_mod; + MOShared::FilesOrigin* m_origin; }; #endif // MODINFODIALOGTAB_H diff --git a/src/modinfodialogtextfiles.cpp b/src/modinfodialogtextfiles.cpp index 0dd6f06e..f48557b0 100644 --- a/src/modinfodialogtextfiles.cpp +++ b/src/modinfodialogtextfiles.cpp @@ -22,8 +22,10 @@ private: GenericFilesTab::GenericFilesTab( - QWidget* parent, QListWidget* list, QSplitter* sp, TextEditor* e) - : m_parent(parent), m_list(list), m_editor(e) + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui, + QListWidget* list, QSplitter* sp, TextEditor* e) + : ModInfoDialogTab(oc, plugin, parent, ui), m_list(list), m_editor(e) { m_editor->setupToolbar(); @@ -49,7 +51,7 @@ bool GenericFilesTab::canClose() } const int res = QMessageBox::question( - m_parent, + parentWidget(), QObject::tr("Save changes?"), QObject::tr("Save changes to \"%1\"?").arg(m_editor->filename()), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); @@ -109,9 +111,12 @@ void GenericFilesTab::select(FileListItem* item) } -TextFilesTab::TextFilesTab(QWidget* parent, Ui::ModInfoDialog* ui) - : GenericFilesTab( - parent, ui->textFileList, ui->tabTextSplitter, ui->textFileEditor) +TextFilesTab::TextFilesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) + : GenericFilesTab( + oc, plugin, parent, ui, + ui->textFileList, ui->tabTextSplitter, ui->textFileEditor) { } @@ -130,9 +135,12 @@ bool TextFilesTab::wantsFile(const QString& rootPath, const QString& fullPath) c return false; } -IniFilesTab::IniFilesTab(QWidget* parent, Ui::ModInfoDialog* ui) - : GenericFilesTab( - parent, ui->iniFileList, ui->tabIniSplitter, ui->iniFileEditor) +IniFilesTab::IniFilesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) + : GenericFilesTab( + oc, plugin, parent, ui, + ui->iniFileList, ui->tabIniSplitter, ui->iniFileEditor) { } diff --git a/src/modinfodialogtextfiles.h b/src/modinfodialogtextfiles.h index 11691d64..0dc5ec89 100644 --- a/src/modinfodialogtextfiles.h +++ b/src/modinfodialogtextfiles.h @@ -18,12 +18,12 @@ public: bool feedFile(const QString& rootPath, const QString& fullPath) override; protected: - QWidget* m_parent; QListWidget* m_list; TextEditor* m_editor; GenericFilesTab( - QWidget* parent, + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui, QListWidget* list, QSplitter* splitter, TextEditor* editor); virtual bool wantsFile(const QString& rootPath, const QString& fullPath) const = 0; @@ -37,7 +37,9 @@ private: class TextFilesTab : public GenericFilesTab { public: - TextFilesTab(QWidget* parent, Ui::ModInfoDialog* ui); + TextFilesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); protected: bool wantsFile(const QString& rootPath, const QString& fullPath) const override; @@ -47,7 +49,9 @@ protected: class IniFilesTab : public GenericFilesTab { public: - IniFilesTab(QWidget* parent, Ui::ModInfoDialog* ui); + IniFilesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); protected: bool wantsFile(const QString& rootPath, const QString& fullPath) const override; diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index a271c4e8..babbd665 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -118,7 +118,7 @@ void ModInfoRegular::readMeta() m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; } } - + QString categoriesString = metaFile.value("category", "").toString(); QStringList categories = categoriesString.split(',', QString::SkipEmptyParts); @@ -291,15 +291,27 @@ void ModInfoRegular::nxmRequestFailed(QString, int, int, QVariant userData, QNet bool ModInfoRegular::updateNXMInfo() { - QDateTime time = QDateTime::currentDateTimeUtc(); - QDateTime target = m_LastNexusQuery.addDays(1); - if (m_NexusID > 0 && time >= target) { + if (needsDescriptionUpdate()) { m_NexusBridge.requestDescription(m_GameName, m_NexusID, QVariant()); return true; } + return false; } +bool ModInfoRegular::needsDescriptionUpdate() const +{ + if (m_NexusID > 0) { + QDateTime time = QDateTime::currentDateTimeUtc(); + QDateTime target = m_LastNexusQuery.addDays(1); + + if (time >= target) { + return true; + } + } + + return false; +} void ModInfoRegular::setCategory(int categoryID, bool active) { diff --git a/src/modinforegular.h b/src/modinforegular.h index f70487a2..cfe713ca 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -464,6 +464,7 @@ private: mutable std::vector m_CachedContent; mutable QTime m_LastContentCheck; + bool needsDescriptionUpdate() const; }; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 2cad9ce8..e073924b 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -2204,6 +2204,21 @@ void OrganizerCore::updateModsInDirectoryStructure(QMap f) +{ + if (NexusInterface::instance(m_PluginContainer)->getAccessManager()->validated()) { + f(); + } else { + QString apiKey; + if (settings().getNexusApiKey(apiKey)) { + doAfterLogin([f]{ f(); }); + NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(apiKey); + } else { + MessageDialog::showMessage(tr("You need to be logged in with Nexus"), parent); + } + } +} + void OrganizerCore::requestDownload(const QUrl &url, QNetworkReply *reply) { if (m_PluginContainer != nullptr) { diff --git a/src/organizercore.h b/src/organizercore.h index a4a57496..4dd11831 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -146,6 +146,7 @@ public: void updateModsInDirectoryStructure(QMap modInfos); void doAfterLogin(const std::function &function) { m_PostLoginTasks.append(function); } + void loggedInAction(QWidget* parent, std::function f); static QString findJavaInstallation(const QString& jarFile={}); -- cgit v1.3.1 From 4aa59cdc7dd779c7e864a1c4e96c6b52c61879ff Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 2 Jul 2019 12:35:33 -0400 Subject: added modinfodialogfwd.h, mostly for the enum that's used in various places renamed ETabs to ModInfoTabIDs and changed all ints to use the enum instead added ModInfoPtr to avoid having to include modinfo.h just to get ModInfo::Ptr --- src/CMakeLists.txt | 2 ++ src/iuserinterface.h | 5 ++-- src/mainwindow.cpp | 37 +++++++++++++++------------- src/mainwindow.h | 7 +++--- src/modinfodialog.cpp | 60 ++++++++++++++++++++-------------------------- src/modinfodialog.h | 50 ++++++-------------------------------- src/modinfodialogfwd.h | 50 ++++++++++++++++++++++++++++++++++++++ src/modinfodialognexus.cpp | 2 +- src/modinfodialognexus.h | 2 +- src/modinfodialogtab.cpp | 7 +++--- src/modinfodialogtab.h | 20 ++++++++-------- src/organizercore.cpp | 8 +++---- 12 files changed, 132 insertions(+), 118 deletions(-) create mode 100644 src/modinfodialogfwd.h (limited to 'src/organizercore.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d27f444..929ee296 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -166,6 +166,7 @@ SET(organizer_HDRS modinfodialogconflicts.h modinfodialogesps.h modinfodialogfiletree.h + modinfodialogfwd.h modinfodialogimages.h modinfodialognexus.h modinfodialogtab.h @@ -379,6 +380,7 @@ set(modinfo\\dialog modinfodialogconflicts modinfodialogesps modinfodialogfiletree + modinfodialogfwd modinfodialogimages modinfodialognexus modinfodialogtab diff --git a/src/iuserinterface.h b/src/iuserinterface.h index 034fa029..bba8de2b 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -2,7 +2,7 @@ #define IUSERINTERFACE_H -#include "modinfo.h" +#include "modinfodialogfwd.h" #include "ilockedwaitingforprocess.h" #include #include @@ -29,7 +29,8 @@ public: virtual bool closeWindow() = 0; virtual void setWindowEnabled(bool enabled) = 0; - virtual void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) = 0; + virtual void displayModInformation( + ModInfoPtr modInfo, unsigned int modIndex, ModInfoTabIDs tabID) = 0; virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7ab555fa..a596c542 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3192,7 +3192,8 @@ void MainWindow::overwriteClosed(int) } -void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) +void MainWindow::displayModInformation( + ModInfo::Ptr modInfo, unsigned int modIndex, ModInfoTabIDs tabID) { if (!m_OrganizerCore.modList()->modInfoAboutToChange(modInfo)) { qDebug("A different mod information dialog is open. If this is incorrect, please restart MO"); @@ -3227,8 +3228,8 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, connect(&dialog, SIGNAL(originModified(int)), this, SLOT(originModified(int))); //Open the tab first if we want to use the standard indexes of the tabs. - if (tab != -1) { - dialog.setTab(ModInfoDialog::ETabs(tab)); + if (tabID != ModInfoTabIDs::None) { + dialog.setTab(tabID); } dialog.restoreState(m_OrganizerCore.settings()); @@ -3247,7 +3248,7 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, m_OrganizerCore.modList()->modInfoChanged(modInfo); } - if (m_OrganizerCore.currentProfile()->modEnabled(index) + if (m_OrganizerCore.currentProfile()->modEnabled(modIndex) && !modInfo->hasFlag(ModInfo::FLAG_FOREIGN)) { FilesOrigin& origin = m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(modInfo->name())); origin.enable(false); @@ -3258,7 +3259,7 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, m_OrganizerCore.directoryRefresher()->addModToStructure(m_OrganizerCore.directoryStructure() , modInfo->name() - , m_OrganizerCore.currentProfile()->getModPriority(index) + , m_OrganizerCore.currentProfile()->getModPriority(modIndex) , modInfo->absolutePath() , modInfo->stealFiles() , modInfo->archives()); @@ -3347,7 +3348,7 @@ ModInfo::Ptr MainWindow::previousModInList() return {}; } -void MainWindow::displayModInformation(const QString &modName, int tab) +void MainWindow::displayModInformation(const QString &modName, ModInfoTabIDs tabID) { unsigned int index = ModInfo::getIndex(modName); if (index == UINT_MAX) { @@ -3356,14 +3357,14 @@ void MainWindow::displayModInformation(const QString &modName, int tab) } ModInfo::Ptr modInfo = ModInfo::getByIndex(index); - displayModInformation(modInfo, index, tab); + displayModInformation(modInfo, index, tabID); } -void MainWindow::displayModInformation(int row, int tab) +void MainWindow::displayModInformation(int row, ModInfoTabIDs tabID) { ModInfo::Ptr modInfo = ModInfo::getByIndex(row); - displayModInformation(modInfo, row, tab); + displayModInformation(modInfo, row, tabID); } @@ -4048,16 +4049,18 @@ void MainWindow::on_modList_doubleClicked(const QModelIndex &index) try { m_ContextRow = m_ModListSortProxy->mapToSource(index).row(); sourceIdx.column(); - int tab = -1; + + auto tab = ModInfoTabIDs::None; + switch (sourceIdx.column()) { - case ModList::COL_NOTES: tab = ModInfoDialog::TAB_NOTES; break; - case ModList::COL_VERSION: tab = ModInfoDialog::TAB_NEXUS; break; - case ModList::COL_MODID: tab = ModInfoDialog::TAB_NEXUS; break; - case ModList::COL_GAME: tab = ModInfoDialog::TAB_NEXUS; break; - case ModList::COL_CATEGORY: tab = ModInfoDialog::TAB_CATEGORIES; break; - case ModList::COL_FLAGS: tab = ModInfoDialog::TAB_CONFLICTS; break; - default: tab = -1; + case ModList::COL_NOTES: tab = ModInfoTabIDs::Notes; break; + case ModList::COL_VERSION: tab = ModInfoTabIDs::Nexus; break; + case ModList::COL_MODID: tab = ModInfoTabIDs::Nexus; break; + case ModList::COL_GAME: tab = ModInfoTabIDs::Nexus; break; + case ModList::COL_CATEGORY: tab = ModInfoTabIDs::Categories; break; + case ModList::COL_FLAGS: tab = ModInfoTabIDs::Conflicts; break; } + displayModInformation(sourceIdx.row(), tab); // workaround to cancel the editor that might have opened because of // selection-click diff --git a/src/mainwindow.h b/src/mainwindow.h index f204211e..00f15a2b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -151,7 +151,8 @@ public: virtual void disconnectPlugins(); - void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab); + void displayModInformation( + ModInfo::Ptr modInfo, unsigned int modIndex, ModInfoTabIDs tabID) override; bool confirmExit(); @@ -235,7 +236,7 @@ private: QList findFileInfos(const QString &path, const std::function &filter) const; bool modifyExecutablesDialog(); - void displayModInformation(int row, int tab = -1); + void displayModInformation(int row, ModInfoTabIDs tab=ModInfoTabIDs::None); void testExtractBSA(int modIndex); void writeDataToFile(QFile &file, const QString &directory, const MOShared::DirectoryEntry &directoryEntry); @@ -551,7 +552,7 @@ private slots: void editCategories(); void deselectFilters(); - void displayModInformation(const QString &modName, int tab); + void displayModInformation(const QString &modName, ModInfoTabIDs tabID); void modRenamed(const QString &oldName, const QString &newName); void modRemoved(const QString &fileName); diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 4ef010e4..c8ffa35b 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -131,7 +131,7 @@ ModInfoDialog::ModInfoDialog( ModInfo::Ptr mod) : TutorableDialog("ModInfoDialog", mw), ui(new Ui::ModInfoDialog), m_mainWindow(mw), - m_core(core), m_plugin(plugin), m_initialTab(ETabs(-1)), + m_core(core), m_plugin(plugin), m_initialTab(ModInfoTabIDs::None), m_arrangingTabs(false) { ui->setupUi(this); @@ -155,16 +155,11 @@ ModInfoDialog::ModInfoDialog( connect( tabInfo.tab.get(), &ModInfoDialogTab::originModified, - [this, i](int originID) { - onOriginModified(originID); - }); + [this](int originID){ onOriginModified(originID); }); connect( tabInfo.tab.get(), &ModInfoDialogTab::modOpen, - [&](const QString& name){ - setMod(name); - update(); - }); + [&](const QString& name){ setMod(name); update(); }); connect( tabInfo.tab.get(), &ModInfoDialogTab::hasDataChanged, @@ -172,12 +167,7 @@ ModInfoDialog::ModInfoDialog( connect( tabInfo.tab.get(), &ModInfoDialogTab::wantsFocus, - [&, i=static_cast(i)] - { - if (i < m_tabs.size()) { - switchToTab(ETabs(m_tabs[i].tab->tabID())); - } - }); + [&, id=tabInfo.tab->tabID()]{ switchToTab(id); }); } connect(ui->tabWidget, &QTabWidget::currentChanged, [&]{ onTabChanged(); }); @@ -187,32 +177,32 @@ ModInfoDialog::ModInfoDialog( ModInfoDialog::~ModInfoDialog() = default; template -std::unique_ptr createTab(ModInfoDialog& d, int index) +std::unique_ptr createTab(ModInfoDialog& d, ModInfoTabIDs id) { return std::make_unique(ModInfoDialogTabContext( - *d.m_core, *d.m_plugin, &d, d.ui.get(), index, d.m_mod, d.getOrigin())); + *d.m_core, *d.m_plugin, &d, d.ui.get(), id, d.m_mod, d.getOrigin())); } std::vector ModInfoDialog::createTabs() { std::vector v; - v.push_back(createTab(*this, TAB_TEXTFILES)); - v.push_back(createTab(*this, TAB_INIFILES)); - v.push_back(createTab(*this, TAB_IMAGES)); - v.push_back(createTab(*this, TAB_ESPS)); - v.push_back(createTab(*this, TAB_CONFLICTS)); - v.push_back(createTab(*this, TAB_CATEGORIES)); - v.push_back(createTab(*this, TAB_NEXUS)); - v.push_back(createTab(*this, TAB_NOTES)); - v.push_back(createTab(*this, TAB_FILETREE)); + v.push_back(createTab(*this, ModInfoTabIDs::TextFiles)); + v.push_back(createTab(*this, ModInfoTabIDs::IniFiles)); + v.push_back(createTab(*this, ModInfoTabIDs::Images)); + v.push_back(createTab(*this, ModInfoTabIDs::Esps)); + v.push_back(createTab(*this, ModInfoTabIDs::Conflicts)); + v.push_back(createTab(*this, ModInfoTabIDs::Categories)); + v.push_back(createTab(*this, ModInfoTabIDs::Nexus)); + v.push_back(createTab(*this, ModInfoTabIDs::Notes)); + v.push_back(createTab(*this, ModInfoTabIDs::Filetree)); return v; } int ModInfoDialog::exec() { - const auto selectFirst = (m_initialTab == -1); + const auto selectFirst = (m_initialTab == ModInfoTabIDs::None); update(true); @@ -252,7 +242,7 @@ void ModInfoDialog::setMod(const QString& name) setMod(mod); } -void ModInfoDialog::setTab(ETabs id) +void ModInfoDialog::setTab(ModInfoTabIDs id) { if (!isVisible()) { m_initialTab = id; @@ -288,9 +278,9 @@ void ModInfoDialog::update(bool firstTime) updateTabs(); - if (m_initialTab >= 0) { + if (m_initialTab != ModInfoTabIDs::None) { switchToTab(m_initialTab); - m_initialTab = ETabs(-1); + m_initialTab = ModInfoTabIDs::None; } if (ui->tabWidget->currentIndex() == oldTab) { @@ -335,11 +325,11 @@ void ModInfoDialog::setTabsVisibility(bool firstTime) // remember selection const int selIndex = ui->tabWidget->currentIndex(); - ETabs sel = ETabs(-1); + auto sel = ModInfoTabIDs::None; for (const auto& tabInfo : m_tabs) { if (tabInfo.realPos == selIndex) { - sel = ETabs(tabInfo.tab->tabID()); + sel = tabInfo.tab->tabID(); break; } } @@ -420,7 +410,7 @@ void ModInfoDialog::setTabsColors() } } -void ModInfoDialog::switchToTab(ETabs id) +void ModInfoDialog::switchToTab(ModInfoTabIDs id) { for (const auto& tabInfo : m_tabs) { if (tabInfo.tab->tabID() == id) { @@ -429,7 +419,8 @@ void ModInfoDialog::switchToTab(ETabs id) } } - qDebug() << "can't switch to tab " << id << ", not available"; + qDebug() + << "can't switch to tab ID " << static_cast(id) << ", not available"; } MOShared::FilesOrigin* ModInfoDialog::getOrigin() @@ -525,7 +516,8 @@ std::vector ModInfoDialog::getOrderedTabNames() const return v; } -void ModInfoDialog::reAddTabs(const std::vector& visibility, ETabs sel) +void ModInfoDialog::reAddTabs( + const std::vector& visibility, ModInfoTabIDs sel) { Q_ASSERT(visibility.size() == m_tabs.size()); diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 9eb00a3b..effb5d98 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -24,6 +24,7 @@ along with Mod Organizer. If not, see . #include "modinfo.h" #include "tutorabledialog.h" #include "filerenamer.h" +#include "modinfodialogfwd.h" namespace Ui { class ModInfoDialog; } namespace MOShared { class FilesOrigin; } @@ -34,32 +35,6 @@ class Settings; class ModInfoDialogTab; class MainWindow; -bool canPreviewFile(PluginContainer& pluginContainer, bool isArchive, const QString& filename); -bool canOpenFile(bool isArchive, const QString& filename); -bool canExploreFile(bool isArchive, const QString& filename); -bool canHideFile(bool isArchive, const QString& filename); -bool canUnhideFile(bool isArchive, const QString& filename); - -FileRenamer::RenameResults hideFile(FileRenamer& renamer, const QString &oldName); -FileRenamer::RenameResults unhideFile(FileRenamer& renamer, const QString &oldName); - -int naturalCompare(const QString& a, const QString& b); - - -class ElideLeftDelegate : public QStyledItemDelegate -{ -public: - using QStyledItemDelegate::QStyledItemDelegate; - -protected: - void initStyleOption(QStyleOptionViewItem* o, const QModelIndex& i) const - { - QStyledItemDelegate::initStyleOption(o, i); - o->textElideMode = Qt::ElideLeft; - } -}; - - /** * this is a larger dialog used to visualise information about the mod. * @todo this would probably a good place for a plugin-system @@ -70,21 +45,9 @@ class ModInfoDialog : public MOBase::TutorableDialog template friend std::unique_ptr createTab( - ModInfoDialog& d, int index); + ModInfoDialog& d, ModInfoTabIDs index); public: - enum ETabs { - TAB_TEXTFILES, - TAB_INIFILES, - TAB_IMAGES, - TAB_ESPS, - TAB_CONFLICTS, - TAB_CATEGORIES, - TAB_NEXUS, - TAB_NOTES, - TAB_FILETREE - }; - ModInfoDialog( MainWindow* mw, OrganizerCore* core, PluginContainer* plugin, ModInfo::Ptr mod); @@ -93,7 +56,8 @@ public: void setMod(ModInfo::Ptr mod); void setMod(const QString& name); - void setTab(ETabs id); + + void setTab(ModInfoTabIDs id); int exec() override; @@ -130,7 +94,7 @@ private: OrganizerCore* m_core; PluginContainer* m_plugin; std::vector m_tabs; - ETabs m_initialTab; + ModInfoTabIDs m_initialTab; bool m_arrangingTabs; std::vector createTabs(); @@ -144,8 +108,8 @@ private: void updateTabs(bool becauseOriginChanged=false); void feedFiles(bool becauseOriginChanged); void setTabsColors(); - void switchToTab(ETabs id); - void reAddTabs(const std::vector& visibility, ETabs sel); + void switchToTab(ModInfoTabIDs id); + void reAddTabs(const std::vector& visibility, ModInfoTabIDs sel); std::vector getOrderedTabNames() const; bool tryClose(); diff --git a/src/modinfodialogfwd.h b/src/modinfodialogfwd.h new file mode 100644 index 00000000..9ede766f --- /dev/null +++ b/src/modinfodialogfwd.h @@ -0,0 +1,50 @@ +#ifndef MODINFODIALOGFWD_H +#define MODINFODIALOGFWD_H + +#include "filerenamer.h" + +class ModInfo; +using ModInfoPtr = QSharedPointer; + +enum class ModInfoTabIDs +{ + None = -1, + TextFiles = 0, + IniFiles, + Images, + Esps, + Conflicts, + Categories, + Nexus, + Notes, + Filetree +}; + +class PluginContainer; + +bool canPreviewFile(PluginContainer& pluginContainer, bool isArchive, const QString& filename); +bool canOpenFile(bool isArchive, const QString& filename); +bool canExploreFile(bool isArchive, const QString& filename); +bool canHideFile(bool isArchive, const QString& filename); +bool canUnhideFile(bool isArchive, const QString& filename); + +FileRenamer::RenameResults hideFile(FileRenamer& renamer, const QString &oldName); +FileRenamer::RenameResults unhideFile(FileRenamer& renamer, const QString &oldName); + +int naturalCompare(const QString& a, const QString& b); + + +class ElideLeftDelegate : public QStyledItemDelegate +{ +public: + using QStyledItemDelegate::QStyledItemDelegate; + +protected: + void initStyleOption(QStyleOptionViewItem* o, const QModelIndex& i) const + { + QStyledItemDelegate::initStyleOption(o, i); + o->textElideMode = Qt::ElideLeft; + } +}; + +#endif // MODINFODIALOGFWD_H diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp index 81546f58..04683c89 100644 --- a/src/modinfodialognexus.cpp +++ b/src/modinfodialognexus.cpp @@ -108,7 +108,7 @@ void NexusTab::firstActivation() updateWebpage(); } -void NexusTab::setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) +void NexusTab::setMod(ModInfoPtr mod, MOShared::FilesOrigin* origin) { cleanup(); diff --git a/src/modinfodialognexus.h b/src/modinfodialognexus.h index 6478375b..7f894dbf 100644 --- a/src/modinfodialognexus.h +++ b/src/modinfodialognexus.h @@ -40,7 +40,7 @@ public: void clear() override; void update() override; void firstActivation() override; - void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) override; + void setMod(ModInfoPtr mod, MOShared::FilesOrigin* origin) override; bool usesOriginFiles() const override; private: diff --git a/src/modinfodialogtab.cpp b/src/modinfodialogtab.cpp index 554df6df..9748d059 100644 --- a/src/modinfodialogtab.cpp +++ b/src/modinfodialogtab.cpp @@ -2,6 +2,7 @@ #include "ui_modinfodialog.h" #include "texteditor.h" #include "directoryentry.h" +#include "modinfo.h" ModInfoDialogTab::ModInfoDialogTab(ModInfoDialogTabContext cx) : ui(cx.ui), m_core(cx.core), m_plugin(cx.plugin), m_parent(cx.parent), @@ -74,7 +75,7 @@ bool ModInfoDialogTab::usesOriginFiles() const return true; } -void ModInfoDialogTab::setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin) +void ModInfoDialogTab::setMod(ModInfoPtr mod, MOShared::FilesOrigin* origin) { m_mod = mod; m_origin = origin; @@ -86,7 +87,7 @@ ModInfo& ModInfoDialogTab::mod() const return *m_mod; } -ModInfo::Ptr ModInfoDialogTab::modPtr() const +ModInfoPtr ModInfoDialogTab::modPtr() const { Q_ASSERT(m_mod); return m_mod; @@ -97,7 +98,7 @@ MOShared::FilesOrigin* ModInfoDialogTab::origin() const return m_origin; } -int ModInfoDialogTab::tabID() const +ModInfoTabIDs ModInfoDialogTab::tabID() const { return m_tabID; } diff --git a/src/modinfodialogtab.h b/src/modinfodialogtab.h index eb574de0..283d9e73 100644 --- a/src/modinfodialogtab.h +++ b/src/modinfodialogtab.h @@ -1,7 +1,7 @@ #ifndef MODINFODIALOGTAB_H #define MODINFODIALOGTAB_H -#include "modinfo.h" +#include "modinfodialogfwd.h" #include namespace MOShared { class FilesOrigin; } @@ -18,8 +18,8 @@ struct ModInfoDialogTabContext PluginContainer& plugin; QWidget* parent; Ui::ModInfoDialog* ui; - int id; - ModInfo::Ptr mod; + ModInfoTabIDs id; + ModInfoPtr mod; MOShared::FilesOrigin* origin; ModInfoDialogTabContext( @@ -27,8 +27,8 @@ struct ModInfoDialogTabContext PluginContainer& plugin, QWidget* parent, Ui::ModInfoDialog* ui, - int id, - ModInfo::Ptr mod, + ModInfoTabIDs id, + ModInfoPtr mod, MOShared::FilesOrigin* origin) : core(core), plugin(plugin), parent(parent), ui(ui), id(id), mod(mod), origin(origin) @@ -96,7 +96,7 @@ public: // derived classes can override this to connect to events on the mod for // examples (see NexusTab), but must call the base class implementation // - virtual void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin); + virtual void setMod(ModInfoPtr mod, MOShared::FilesOrigin* origin); // this tab should clear its user interface; clear() will always be called // before feedFile() and update() @@ -195,7 +195,7 @@ public: // returns the currently selected mod, can never be empty // - ModInfo::Ptr modPtr() const; + ModInfoPtr modPtr() const; // returns the origin of the selected mod; this can be null for mods that // don't have an origin, like deactivated mods @@ -203,7 +203,7 @@ public: MOShared::FilesOrigin* origin() const; - int tabID() const; + ModInfoTabIDs tabID() const; bool hasData() const; signals: @@ -249,9 +249,9 @@ private: OrganizerCore& m_core; PluginContainer& m_plugin; QWidget* m_parent; - ModInfo::Ptr m_mod; + ModInfoPtr m_mod; MOShared::FilesOrigin* m_origin; - int m_tabID; + ModInfoTabIDs m_tabID; bool m_hasData; bool m_firstActivation; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index e073924b..99ddda1d 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -966,8 +966,8 @@ MOBase::IModInterface *OrganizerCore::installMod(const QString &fileName, "want to configure them now?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) { - m_UserInterface->displayModInformation(modInfo, modIndex, - ModInfoDialog::TAB_INIFILES); + m_UserInterface->displayModInformation( + modInfo, modIndex, ModInfoTabIDs::IniFiles); } m_ModInstalled(modName); m_DownloadManager.markInstalled(fileName); @@ -1033,8 +1033,8 @@ void OrganizerCore::installDownload(int index) "want to configure them now?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) { - m_UserInterface->displayModInformation(modInfo, modIndex, - ModInfoDialog::TAB_INIFILES); + m_UserInterface->displayModInformation( + modInfo, modIndex, ModInfoTabIDs::IniFiles); } m_ModInstalled(modName); -- cgit v1.3.1 From 37aa5e07f473e0377ef59d6e2f53f7373b11aecd Mon Sep 17 00:00:00 2001 From: Silarn Date: Mon, 8 Jul 2019 13:19:52 -0500 Subject: Add some basic checks for symlinks --- src/main.cpp | 18 +++++++++++++++++- src/organizercore.cpp | 17 ++++++++++++++++- src/organizercore.h | 1 + src/selectiondialog.cpp | 8 ++++++++ src/selectiondialog.h | 1 + 5 files changed, 43 insertions(+), 2 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/main.cpp b/src/main.cpp index 4a2f6035..f2571685 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -303,6 +303,11 @@ MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &sett gamePath = game->gameDirectory().absolutePath(); } QDir gameDir(gamePath); + QFileInfo directoryInfo(gameDir.path()); + if (directoryInfo.isSymLink()) { + reportError(QObject::tr("The configured path to the game directory (%1) appears to be a symbolic (or other) link. " + "This setup is incompatible with MO2's VFS and will not run correctly.").arg(gamePath)); + } if (game->looksValid(gameDir)) { return selectGame(settings, gameDir, game); } @@ -335,15 +340,26 @@ MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &sett while (selection.exec() != QDialog::Rejected) { IPluginGame * game = selection.getChoiceData().value(); + QString gamePath = selection.getChoiceDescription(); + QFileInfo directoryInfo(gamePath); + if (directoryInfo.isSymLink()) { + reportError(QObject::tr("The configured path to the game directory (%1) appears to be a symbolic (or other) link. " + "This setup is incompatible with MO2's VFS and will not run correctly.").arg(gamePath)); + } if (game != nullptr) { return selectGame(settings, game->gameDirectory(), game); } - QString gamePath = QFileDialog::getExistingDirectory(nullptr, gameConfigured ? QObject::tr("Please select the installation of %1 to manage").arg(gameName) + gamePath = QFileDialog::getExistingDirectory(nullptr, gameConfigured ? QObject::tr("Please select the installation of %1 to manage").arg(gameName) : QObject::tr("Please select the game to manage"), QString(), QFileDialog::ShowDirsOnly); if (!gamePath.isEmpty()) { QDir gameDir(gamePath); + QFileInfo directoryInfo(gamePath); + if (directoryInfo.isSymLink()) { + reportError(QObject::tr("The configured path to the game directory (%1) appears to be a symbolic (or other) link. " + "This setup is incompatible with MO2's VFS and will not run correctly.").arg(gamePath)); + } QList possibleGames; for (IPluginGame * const game : plugins.plugins()) { //If a game is already configured, skip any plugins that are not for that game diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 99ddda1d..81ec7f43 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -691,12 +691,27 @@ bool OrganizerCore::createDirectory(const QString &path) { } } +bool OrganizerCore::checkPathSymlinks() { + bool hasSymlink = (QFileInfo(m_Settings.getProfileDirectory()).isSymLink() || + QFileInfo(m_Settings.getModDirectory()).isSymLink() || + QFileInfo(m_Settings.getOverwriteDirectory()).isSymLink()); + if (hasSymlink) { + QMessageBox::critical(nullptr, QObject::tr("Error"), + QObject::tr("One of the configured MO2 directories (profiles, mods, or overwrite) " + "is on a path containing a symbolic (or other) link. This is incompatible " + "with MO2's VFS system.")); + return false; + } + return true; +} + bool OrganizerCore::bootstrap() { return createDirectory(m_Settings.getProfileDirectory()) && createDirectory(m_Settings.getModDirectory()) && createDirectory(m_Settings.getDownloadDirectory()) && createDirectory(m_Settings.getOverwriteDirectory()) && - createDirectory(QString::fromStdWString(crashDumpsPath())) && cycleDiagnostics(); + createDirectory(QString::fromStdWString(crashDumpsPath())) && + checkPathSymlinks() && cycleDiagnostics(); } void OrganizerCore::createDefaultProfile() diff --git a/src/organizercore.h b/src/organizercore.h index 4dd11831..99b1c5f2 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -183,6 +183,7 @@ public: void loginFailedUpdate(const QString &message); static bool createAndMakeWritable(const QString &path); + bool checkPathSymlinks(); bool bootstrap(); void createDefaultProfile(); diff --git a/src/selectiondialog.cpp b/src/selectiondialog.cpp index 55728751..089760f9 100644 --- a/src/selectiondialog.cpp +++ b/src/selectiondialog.cpp @@ -79,6 +79,14 @@ QString SelectionDialog::getChoiceString() } } +QString SelectionDialog::getChoiceDescription() +{ + if (m_Choice == nullptr) + return QString(); + else + return m_Choice->accessibleDescription(); +} + void SelectionDialog::disableCancel() { ui->cancelButton->setEnabled(false); diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 3c4b25df..5a70aa5e 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -52,6 +52,7 @@ public: QVariant getChoiceData(); QString getChoiceString(); + QString getChoiceDescription(); void disableCancel(); -- cgit v1.3.1