diff options
| -rw-r--r-- | SConstruct | 4 | ||||
| -rw-r--r-- | massage_messages.py | 23 | ||||
| -rw-r--r-- | src/dlls.manifest.debug.qt5 | 6 | ||||
| -rw-r--r-- | src/dlls.manifest.qt5 | 8 | ||||
| -rw-r--r-- | src/iuserinterface.h | 1 | ||||
| -rw-r--r-- | src/lockeddialog.cpp | 5 | ||||
| -rw-r--r-- | src/lockeddialog.h | 11 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 25 | ||||
| -rw-r--r-- | src/mainwindow.h | 2 | ||||
| -rw-r--r-- | src/organizercore.cpp | 117 | ||||
| -rw-r--r-- | src/organizercore.h | 11 | ||||
| -rw-r--r-- | src/pluginlist.cpp | 1 | ||||
| -rw-r--r-- | src/settings.cpp | 36 | ||||
| -rw-r--r-- | src/settings.h | 24 |
14 files changed, 173 insertions, 101 deletions
@@ -669,7 +669,9 @@ if qt_env['QT_MAJOR_VERSION'] > 4: dlls_to_install += [ os.path.join(env['QTDIR'], 'bin', - 'icu%s%d%d.dll' % (lib, qt_env['QT_MAJOR_VERSION'], qt_env['QT_MINOR_VERSION'] - 1)) + 'icu%s%d%d.dll' % (lib, + qt_env['QT_MAJOR_VERSION'], + qt_env['QT_MINOR_VERSION'] - 1)) for lib in ('dt','in', 'uc') ] diff --git a/massage_messages.py b/massage_messages.py index 0a3ee9ad..34d18eaf 100644 --- a/massage_messages.py +++ b/massage_messages.py @@ -35,7 +35,7 @@ removing = None includes = dict() adding = None -added = dict() +added = defaultdict(list) lcadded = dict() foundline = None @@ -70,10 +70,10 @@ def process_next_line(line, outfile): elif adding: m = re.match(r'.*class (.*);', line) if m: - added[m.group(1)] = (adding, line) + added[m.group(1)].append((adding, line)) lcadded[m.group(1).lower() + '.h'] = m.group(1) else: - added[line] = (adding, line) + added[line].append((adding, line)) elif removing: # Really we should stash these so that if we get a 'class xxx' in # the add lines we can print it here. also we could do the case @@ -88,10 +88,12 @@ def process_next_line(line, outfile): if clname in lcadded: clname = lcadded[clname] if clname in added: - messages[removing].append( - '%s(%s) : warning I0004: Replace include of %s with ' - 'forward reference %s' % ( - removing, m.group(2), m.group(1), added[clname][1])) + for item in added[clname]: + if removing == item[0]: + messages[removing].append( + '%s(%s) : warning I0004: Replace include of %s' + ' with forward reference %s' % ( + removing, m.group(2), m.group(1), item[1])) del added[clname] else: messages[removing].append( @@ -140,9 +142,10 @@ if foundline is None: foundline = '1' for add in added: - messages[added[add][0]].append( - '%s(%s) : warning I0003: Need to include %s' % ( - added[add][0], foundline, added[add][1])) + for item in added[add]: + messages[item[0]].append( + '%s(%s) : warning I0003: Need to include %s' % ( + item[0], foundline, item[1])) for file in sorted(messages.keys(), reverse = True): for line in messages[file]: 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 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
- <file name="icuin53.dll"/>
- <file name="icuuc53.dll"/>
- <file name="icudt53.dll"/>
+ <file name="icuin54.dll"/>
+ <file name="icuuc54.dll"/>
+ <file name="icudt54.dll"/>
<file name="Qt5Cored.dll"/>
<file name="Qt5Declaratived.dll"/>
<file name="Qt5Guid.dll"/>
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 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
- <file name="icuin53.dll"/>
- <file name="icuuc53.dll"/>
- <file name="icudt53.dll"/>
+ <file name="icuin54.dll"/>
+ <file name="icuuc54.dll"/>
+ <file name="icudt54.dll"/>
<file name="Qt5Core.dll"/>
<file name="Qt5Declarative.dll"/>
<file name="Qt5Gui.dll"/>
@@ -26,4 +26,4 @@ <file name="Qt5WinExtras.dll"/>
<file name="Qt5Xml.dll"/>
<file name="Qt5XmlPatterns.dll"/>
-</assembly>
\ No newline at end of file +</assembly>
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 <http://www.gnu.org/licenses/>. #include "lockeddialog.h"
#include "ui_lockeddialog.h"
-#include <QResizeEvent>
+#include <QPoint>
+#include <QResizeEvent>
+#include <QWidget>
+#include <Qt> // 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 <http://www.gnu.org/licenses/>. #ifndef LOCKEDDIALOG_H
#define LOCKEDDIALOG_H
-#include <QDialog>
+#include <QDialog> // for QDialog
+#include <QObject> // for Q_OBJECT, slots
+#include <QString> // 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..72ee8d6a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -34,6 +34,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "organizercore.h"
#include "pluginlistsortproxy.h"
#include "previewgenerator.h"
+#include "serverinfo.h"
#include "savegameinfo.h"
#include "spawn.h"
#include "versioninfo.h"
@@ -1608,18 +1609,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 +1645,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..196ef6bf 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 <questionboxmemory.h>
#include <QApplication>
+#include <QCoreApplication>
+#include <QDialog>
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QNetworkInterface>
#include <QProcess>
#include <QTimer>
+#include <QUrl>
#include <QWidget>
#include <QtDebug>
+#include <QtGlobal> // for qPrintable, etc
#include <Psapi.h>
+#include <tchar.h> // for _tcsicmp
+
+#include <limits.h>
+#include <stddef.h>
+#include <string.h> // for memset, wcsrchr
#include <exception>
#include <functional>
#include <memory>
#include <set>
+#include <string> //for wstring
+#include <tuple>
#include <utility>
@@ -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)) {
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;
+ (void)waitForProcessCompletion(processHandle, &processExitCode);
- 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);
-
- 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);
}
}
@@ -996,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?"),
@@ -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;
}
diff --git a/src/organizercore.h b/src/organizercore.h index b50b3e9f..28fc14ca 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -21,21 +21,28 @@ class ModListSortProxy;
class PluginListSortProxy;
class Profile;
-namespace MOBase { template <typename T> class GuessedValue; }
+namespace MOBase {
+ template <typename T> class GuessedValue;
+ class IModInterface;
+}
namespace MOShared { class DirectoryEntry; }
#include <QDir>
+#include <QFileInfo>
#include <QList>
#include <QObject>
#include <QSettings>
#include <QString>
#include <QStringList>
#include <QThread>
+#include <QVariant>
class QNetworkReply;
class QUrl;
class QWidget;
+#include <Windows.h> //for HANDLE, LPDWORD
+
#include <functional>
#include <vector>
@@ -228,6 +235,8 @@ private: const MOShared::DirectoryEntry *directoryEntry);
*/
+ bool waitForProcessCompletion(HANDLE handle, LPDWORD exitCode);
+
private slots:
void directory_refreshed();
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 <http://www.gnu.org/licenses/>. #include <QMessageBox>
#include <QMimeData>
#include <QCoreApplication>
+#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QTextCodec>
diff --git a/src/settings.cpp b/src/settings.cpp index 7b812759..03e13826 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -19,22 +19,42 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "settings.h" +#include "pluginsetting.h" +#include "serverinfo.h" #include "settingsdialog.h" -#include "utility.h" -#include "helper.h" -#include <appconfig.h> +#include "versioninfo.h" +#include "appconfig.h" #include <utility.h> +#include <iplugin.h> #include <iplugingame.h> +#include <questionboxmemory.h> #include <QCheckBox> #include <QCoreApplication> -#include <QDesktopServices> +#include <QComboBox> +#include <QDate> +#include <QDialog> +#include <QDir> #include <QDirIterator> +#include <QFileInfo> #include <QLineEdit> +#include <QListWidgetItem> +#include <QLocale> #include <QMessageBox> #include <QRegExp> +#include <QStringList> +#include <QVariantMap> +#include <Qt> // for Qt::UserRole, etc +#include <QtDebug> // for qDebug, qWarning + +#include <Windows.h> // For ShellExecuteW, HINSTANCE, etc + +#include <algorithm> // for sort #include <memory> +#include <stdexcept> // for runtime_error +#include <string> +#include <utility> // for pair, make_pair using namespace MOBase; @@ -520,13 +540,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(); } 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 <http://www.gnu.org/licenses/>. #define WORKAROUNDS_H #include "loadmechanism.h" -#include "serverinfo.h" -#include <iplugin.h> +#include <QList> +#include <QMap> +#include <QObject> +#include <QSet> #include <QSettings> -#include <QListWidget> -#include <QComboBox> +#include <QString> +#include <QVariant> +#include <QtGlobal> //for uint + +#include <map> +#include <vector> + +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 |
