From f5a815185ffc378bf0902eac4f03c54ab5be80f3 Mon Sep 17 00:00:00 2001 From: Thomas Tanner Date: Sun, 15 May 2016 11:03:43 +0100 Subject: Updates for QT5.5 --- src/dlls.manifest.debug.qt5 | 6 +++--- src/dlls.manifest.qt5 | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/dlls.manifest.debug.qt5 b/src/dlls.manifest.debug.qt5 index 59497baa..a2f75206 100644 --- a/src/dlls.manifest.debug.qt5 +++ b/src/dlls.manifest.debug.qt5 @@ -1,9 +1,9 @@ - - - + + + diff --git a/src/dlls.manifest.qt5 b/src/dlls.manifest.qt5 index 76206f21..5c64e4f9 100644 --- a/src/dlls.manifest.qt5 +++ b/src/dlls.manifest.qt5 @@ -1,9 +1,9 @@ - - - + + + @@ -26,4 +26,4 @@ - \ No newline at end of file + -- cgit v1.3.1 From c7101be7d8a077eba563a6fd6f15ec8169eeca51 Mon Sep 17 00:00:00 2001 From: Thomas Tanner Date: Sat, 25 Jun 2016 11:47:15 +0100 Subject: Some refactoring of the spawn code and to make waitForApplication get the right error code (usually) A note: It is possible for the executed program to completely exit before MO attempts to get hold of the pid from the job handle, in which case strangeness will happen (this has always been an issue) --- src/iuserinterface.h | 1 + src/lockeddialog.cpp | 5 +- src/lockeddialog.h | 11 +++- src/mainwindow.cpp | 24 +++++++- src/mainwindow.h | 2 + src/organizercore.cpp | 157 ++++++++++++++++++-------------------------------- src/organizercore.h | 15 +++-- 7 files changed, 103 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/iuserinterface.h b/src/iuserinterface.h index e03bcde2..540839c6 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -34,6 +34,7 @@ public: virtual void lock() = 0; virtual void unlock() = 0; virtual bool unlockClicked() = 0; + virtual void setProcessName(QString const &) = 0; }; diff --git a/src/lockeddialog.cpp b/src/lockeddialog.cpp index 907e3c0a..519abd5b 100644 --- a/src/lockeddialog.cpp +++ b/src/lockeddialog.cpp @@ -19,8 +19,11 @@ along with Mod Organizer. If not, see . #include "lockeddialog.h" #include "ui_lockeddialog.h" -#include +#include +#include +#include +#include // for Qt::FramelessWindowHint, etc LockedDialog::LockedDialog(QWidget *parent, const QString &text, bool unlockButton) : QDialog(parent) diff --git a/src/lockeddialog.h b/src/lockeddialog.h index 60af425d..29ac459b 100644 --- a/src/lockeddialog.h +++ b/src/lockeddialog.h @@ -20,7 +20,12 @@ along with Mod Organizer. If not, see . #ifndef LOCKEDDIALOG_H #define LOCKEDDIALOG_H -#include +#include // for QDialog +#include // for Q_OBJECT, slots +#include // for QString + +class QResizeEvent; +class QWidget; namespace Ui { class LockedDialog; @@ -49,6 +54,10 @@ public: **/ bool unlockClicked() const { return m_UnlockClicked; } + /** + * @brief set the name of the process being run + * @param name of process + */ void setProcessName(const QString &name); protected: diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 096ce94b..702e661d 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1608,18 +1608,31 @@ void MainWindow::storeSettings(QSettings &settings) void MainWindow::lock() { + if (m_LockDialog != nullptr) { + ++m_LockCount; + return; + } m_LockDialog = new LockedDialog(qApp->activeWindow()); m_LockDialog->show(); setEnabled(false); + m_LockDialog->setEnabled(true); //What's the point otherwise? + ++m_LockCount; } void MainWindow::unlock() { - if (m_LockDialog != nullptr) { + //If you come through here with a null lock pointer, it's a bug! + if (m_LockDialog == nullptr) { + qDebug("Unlocking main window when already unlocked"); + return; + } + --m_LockCount; + if (m_LockCount == 0) { m_LockDialog->hide(); m_LockDialog->deleteLater(); + m_LockDialog = nullptr; + setEnabled(true); } - setEnabled(true); } bool MainWindow::unlockClicked() @@ -1631,6 +1644,13 @@ bool MainWindow::unlockClicked() } } +void MainWindow::setProcessName(QString const &name) +{ + if (m_LockDialog != nullptr) { + m_LockDialog->setProcessName(name); + } +} + void MainWindow::on_btnRefreshData_clicked() { m_OrganizerCore.refreshDirectoryStructure(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 177048b4..8e63a14f 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -118,6 +118,7 @@ public: virtual void lock() override; virtual void unlock() override; virtual bool unlockClicked() override; + virtual void setProcessName(QString const &name) override; bool addProfile(); void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives); @@ -350,6 +351,7 @@ private: bool m_DidUpdateMasterList; LockedDialog *m_LockDialog { nullptr }; + uint64_t m_LockCount { 0 }; MOBase::DelayedFileWriter m_ArchiveListWriter; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index cee367b0..4267573b 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1,13 +1,19 @@ #include "organizercore.h" +#include "delayedfilewriter.h" +#include "guessedvalue.h" #include "imodinterface.h" +#include "imoinfo.h" #include "iplugingame.h" #include "iuserinterface.h" #include "loadmechanism.h" #include "messagedialog.h" #include "modlistsortproxy.h" +#include "modrepositoryfileinfo.h" +#include "nexusinterface.h" #include "plugincontainer.h" #include "pluginlistsortproxy.h" +#include "profile.h" #include "logbuffer.h" #include "credentialsdialog.h" #include "filedialogmemory.h" @@ -26,21 +32,32 @@ #include #include +#include +#include #include #include #include #include #include +#include #include #include +#include // for qPrintable, etc #include +#include // for _tcsicmp + +#include +#include +#include // for memset, wcsrchr #include #include #include #include +#include //for wstring +#include #include @@ -892,66 +909,22 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory, bool closeAfterStart, const QString &steamAppID) { - LockedDialog *dialog = new LockedDialog(qApp->activeWindow()); - dialog->show(); - ON_BLOCK_EXIT([&] () { dialog->hide(); dialog->deleteLater(); }); + if (m_UserInterface != nullptr) { + m_UserInterface->lock(); + } + ON_BLOCK_EXIT([&] () { + if (m_UserInterface != nullptr) { m_UserInterface->unlock(); } + }); HANDLE processHandle = spawnBinaryDirect(binary, arguments, m_CurrentProfile->name(), currentDirectory, steamAppID); if (processHandle != INVALID_HANDLE_VALUE) { - if (closeAfterStart && (m_UserInterface != nullptr)) { + if (closeAfterStart && m_UserInterface != nullptr) { m_UserInterface->closeWindow(); } else { - if (m_UserInterface != nullptr) { - m_UserInterface->setWindowEnabled(false); - } - // re-enable the locked dialog because what'd be the point otherwise? - dialog->setEnabled(true); - - QCoreApplication::processEvents(); DWORD processExitCode; - DWORD retLen; - JOBOBJECT_BASIC_PROCESS_ID_LIST info; - - { - DWORD currentProcess = 0UL; - bool isJobHandle = true; - - DWORD res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); - while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0) && !dialog->unlockClicked()) { - if (isJobHandle) { - if (::QueryInformationJobObject(processHandle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { - if (info.NumberOfProcessIdsInList == 0) { - break; - } else { - if (info.ProcessIdList[0] != currentProcess) { - currentProcess = info.ProcessIdList[0]; - dialog->setProcessName(ToQString(getProcessName(currentProcess))); - } - } - } else { - // the info-object I passed only provides space for 1 process id. but since this code only cares about whether there - // is more than one that's good enough. ERROR_MORE_DATA simply signals there are at least two processes running. - // any other error probably means the handle is a regular process handle, probably caused by running MO in a job without - // the right to break out. - if (::GetLastError() != ERROR_MORE_DATA) { - isJobHandle = false; - } - } - } - - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - - res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); - } - ::GetExitCodeProcess(processHandle, &processExitCode); - } - ::CloseHandle(processHandle); + (void)waitForProcessCompletion(processHandle, &processExitCode); - if (m_UserInterface != nullptr) { - m_UserInterface->setWindowEnabled(true); - } refreshDirectoryStructure(); // need to remove our stored load order because it may be outdated if a foreign tool changed the // file time. After removing that file, refreshESPList will use the file time as the order @@ -965,6 +938,7 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &argument savePluginList(); } + //These callbacks should not fiddle with directoy structure and ESPs. m_FinishedRun(binary.absoluteFilePath(), processExitCode); } } @@ -1081,22 +1055,30 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) { if (m_UserInterface != nullptr) { m_UserInterface->lock(); - ON_BLOCK_EXIT([&] () { m_UserInterface->unlock(); }); } - DWORD retLen; - JOBOBJECT_BASIC_PROCESS_ID_LIST info; + ON_BLOCK_EXIT([&] () { + if (m_UserInterface != nullptr) { + m_UserInterface->unlock(); + } }); + return waitForProcessCompletion(handle, exitCode); +} +bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) +{ bool isJobHandle = true; ULONG lastProcessID = ULONG_MAX; HANDLE processHandle = handle; - DWORD res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE); - while ((res != WAIT_FAILED) - && (res != WAIT_OBJECT_0) - && ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { + DWORD res; + //Wait for a an event on the handle, a key press, mouse click or timeout + while (res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE), + (res != WAIT_FAILED && res != WAIT_OBJECT_0 + && (m_UserInterface == nullptr || !m_UserInterface->unlockClicked()))) { if (isJobHandle) { + DWORD retLen; + JOBOBJECT_BASIC_PROCESS_ID_LIST info; if (::QueryInformationJobObject(handle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { if (info.NumberOfProcessIdsInList == 0) { // fake signaled state @@ -1106,6 +1088,9 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) // this is indeed a job handle. Figure out one of the process handles as well. if (lastProcessID != info.ProcessIdList[0]) { lastProcessID = info.ProcessIdList[0]; + if (m_UserInterface != nullptr) { + m_UserInterface->setProcessName(ToQString(getProcessName(lastProcessID))); + } if (processHandle != handle) { ::CloseHandle(processHandle); } @@ -1125,14 +1110,22 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) // keep processing events so the app doesn't appear dead QCoreApplication::processEvents(); - - res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE); } if (exitCode != nullptr) { - ::GetExitCodeProcess(processHandle, exitCode); + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (! ::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } } + ::CloseHandle(processHandle); + if (handle != processHandle) { + ::CloseHandle(handle); + } return res == WAIT_OBJECT_0; } @@ -1599,43 +1592,3 @@ void OrganizerCore::prepareStart() { storeSettings(); } -/* -std::vector> OrganizerCore::fileMapping() -{ - return fileMapping(managedGame()->dataDirectory().absolutePath(), - directoryStructure(), - directoryStructure()); -} - - -std::vector> OrganizerCore::fileMapping( - const QString &dataPath, - const DirectoryEntry *base, - const DirectoryEntry *directoryEntry) -{ - std::vector> result; - - for (FileEntry::Ptr current : directoryEntry->getFiles()) { - bool isArchive = false; - int origin = current->getOrigin(isArchive); - if (isArchive || (origin == 0)) { - continue; - } - - QString fileName = ToQString(current->getRelativePath()); - QString source = ToQString(base->getOriginByID(origin).getPath()) + fileName; - QString target = QDir::toNativeSeparators(dataPath) + fileName; - result.push_back(std::make_pair(source, target)); - } - - // recurse into subdirectories - std::vector::const_iterator current, end; - directoryEntry->getSubDirectories(current, end); - for (; current != end; ++current) { - std::vector> subRes = fileMapping(dataPath, base, *current); - result.insert(result.end(), subRes.begin(), subRes.end()); - } - return result; -} - -*/ diff --git a/src/organizercore.h b/src/organizercore.h index b50b3e9f..120e83fa 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -21,21 +21,28 @@ class ModListSortProxy; class PluginListSortProxy; class Profile; -namespace MOBase { template class GuessedValue; } +namespace MOBase { + template class GuessedValue; + class IModInterface; +} namespace MOShared { class DirectoryEntry; } #include +#include #include #include #include #include #include #include +#include class QNetworkReply; class QUrl; class QWidget; +#include //for HANDLE, LPDWORD + #include #include @@ -222,11 +229,7 @@ private: bool testForSteam(); - /* - * std::vector> fileMapping(const QString &dataPath, - const MOShared::DirectoryEntry *base, - const MOShared::DirectoryEntry *directoryEntry); -*/ + bool waitForProcessCompletion(HANDLE handle, LPDWORD exitCode); private slots: -- cgit v1.3.1 From 6b60d54853e15343a5f09889c4db5757e9f81823 Mon Sep 17 00:00:00 2001 From: Thomas Tanner Date: Sat, 25 Jun 2016 14:03:37 +0100 Subject: Extra question box functionality --- src/organizercore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 4267573b..f202d447 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -970,7 +970,7 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString & if ((window != nullptr) && (!window->isVisible())) { window = nullptr; } - if (QuestionBoxMemory::query(window, "steamQuery", + if (QuestionBoxMemory::query(window, "steamQuery", binary.fileName(), tr("Start Steam?"), tr("Steam is required to be running already to correctly start the game. " "Should MO try to start steam now?"), -- cgit v1.3.1 From 607b2a10aa4eab4c8b0534be20696ebe55151b9a Mon Sep 17 00:00:00 2001 From: Thomas Tanner Date: Sun, 26 Jun 2016 20:27:13 +0100 Subject: Restore commented out code --- src/organizercore.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- src/organizercore.h | 6 ++++++ 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index f202d447..196ef6bf 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -918,7 +918,7 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &argument HANDLE processHandle = spawnBinaryDirect(binary, arguments, m_CurrentProfile->name(), currentDirectory, steamAppID); if (processHandle != INVALID_HANDLE_VALUE) { - if (closeAfterStart && m_UserInterface != nullptr) { + if (closeAfterStart && (m_UserInterface != nullptr)) { m_UserInterface->closeWindow(); } else { @@ -1592,3 +1592,43 @@ void OrganizerCore::prepareStart() { storeSettings(); } +/* +std::vector> OrganizerCore::fileMapping() +{ + return fileMapping(managedGame()->dataDirectory().absolutePath(), + directoryStructure(), + directoryStructure()); +} + + +std::vector> OrganizerCore::fileMapping( + const QString &dataPath, + const DirectoryEntry *base, + const DirectoryEntry *directoryEntry) +{ + std::vector> result; + + for (FileEntry::Ptr current : directoryEntry->getFiles()) { + bool isArchive = false; + int origin = current->getOrigin(isArchive); + if (isArchive || (origin == 0)) { + continue; + } + + QString fileName = ToQString(current->getRelativePath()); + QString source = ToQString(base->getOriginByID(origin).getPath()) + fileName; + QString target = QDir::toNativeSeparators(dataPath) + fileName; + result.push_back(std::make_pair(source, target)); + } + + // recurse into subdirectories + std::vector::const_iterator current, end; + directoryEntry->getSubDirectories(current, end); + for (; current != end; ++current) { + std::vector> subRes = fileMapping(dataPath, base, *current); + result.insert(result.end(), subRes.begin(), subRes.end()); + } + return result; +} + +*/ diff --git a/src/organizercore.h b/src/organizercore.h index 120e83fa..28fc14ca 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -229,6 +229,12 @@ private: bool testForSteam(); + /* + * std::vector> fileMapping(const QString &dataPath, + const MOShared::DirectoryEntry *base, + const MOShared::DirectoryEntry *directoryEntry); +*/ + bool waitForProcessCompletion(HANDLE handle, LPDWORD exitCode); private slots: -- cgit v1.3.1 From c3a8a0b9eb89b1464a0d19d728471e0077cbd8dd Mon Sep 17 00:00:00 2001 From: Thomas Tanner Date: Sun, 26 Jun 2016 20:27:50 +0100 Subject: Moved QuestionBoxMemory clearance from settings into QuestionBoxMemory --- src/settings.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/settings.cpp b/src/settings.cpp index 7b812759..6e82b3ca 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -25,6 +25,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include @@ -520,13 +521,7 @@ void Settings::addStyles(QComboBox *styleBox) void Settings::resetDialogs() { - m_Settings.beginGroup("DialogChoices"); - QStringList keys = m_Settings.childKeys(); - foreach (QString key, keys) { - m_Settings.remove(key); - } - - m_Settings.endGroup(); + QuestionBoxMemory::resetDialogs(); } -- cgit v1.3.1 From 42407866e9f04cac3c1bad0e1002e23c6f0d5064 Mon Sep 17 00:00:00 2001 From: Thomas Tanner Date: Mon, 27 Jun 2016 21:21:54 +0100 Subject: Some include-what-you-use suggested changes --- src/mainwindow.cpp | 1 + src/pluginlist.cpp | 1 + src/settings.cpp | 27 +++++++++++++++++++++++---- src/settings.h | 24 +++++++++++++++++++----- 4 files changed, 44 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 702e661d..72ee8d6a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -34,6 +34,7 @@ along with Mod Organizer. If not, see . #include "organizercore.h" #include "pluginlistsortproxy.h" #include "previewgenerator.h" +#include "serverinfo.h" #include "savegameinfo.h" #include "spawn.h" #include "versioninfo.h" diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index bf5a09dc..96757ec6 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -33,6 +33,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include diff --git a/src/settings.cpp b/src/settings.cpp index 6e82b3ca..03e13826 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -19,23 +19,42 @@ along with Mod Organizer. If not, see . #include "settings.h" +#include "pluginsetting.h" +#include "serverinfo.h" #include "settingsdialog.h" -#include "utility.h" -#include "helper.h" -#include +#include "versioninfo.h" +#include "appconfig.h" #include +#include #include #include #include #include -#include +#include +#include +#include +#include #include +#include #include +#include +#include #include #include +#include +#include +#include // for Qt::UserRole, etc +#include // for qDebug, qWarning + +#include // For ShellExecuteW, HINSTANCE, etc + +#include // for sort #include +#include // for runtime_error +#include +#include // for pair, make_pair using namespace MOBase; diff --git a/src/settings.h b/src/settings.h index 1ee16e76..9f6adaa7 100644 --- a/src/settings.h +++ b/src/settings.h @@ -21,20 +21,34 @@ along with Mod Organizer. If not, see . #define WORKAROUNDS_H #include "loadmechanism.h" -#include "serverinfo.h" -#include +#include +#include +#include +#include #include -#include -#include +#include +#include +#include //for uint + +#include +#include + +class QCheckBox; +class QComboBox; +class QLineEdit; +class QListWidget; +class QWidget; + +struct ServerInfo; namespace MOBase { + class IPlugin; class IPluginGame; } class SettingsDialog; -class QCheckBox; /** * manages the settings for Mod Organizer. The settings are not cached -- cgit v1.3.1