diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/ilockedwaitingforprocess.h | 2 | ||||
| -rw-r--r-- | src/lockeddialog.cpp | 37 | ||||
| -rw-r--r-- | src/lockeddialog.h | 33 | ||||
| -rw-r--r-- | src/lockeddialogbase.cpp | 73 | ||||
| -rw-r--r-- | src/lockeddialogbase.h | 62 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 20 | ||||
| -rw-r--r-- | src/mainwindow.h | 6 | ||||
| -rw-r--r-- | src/organizercore.cpp | 45 | ||||
| -rw-r--r-- | src/organizercore.h | 1 | ||||
| -rw-r--r-- | src/waitingonclosedialog.cpp | 71 | ||||
| -rw-r--r-- | src/waitingonclosedialog.h | 56 | ||||
| -rw-r--r-- | src/waitingonclosedialog.ui | 119 |
13 files changed, 443 insertions, 87 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 39aabb91..914bdd12 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,7 +42,9 @@ SET(organizer_SRCS main.cpp loghighlighter.cpp logbuffer.cpp + lockeddialogbase.cpp lockeddialog.cpp + waitingonclosedialog.cpp loadmechanism.cpp installationmanager.cpp helper.cpp @@ -128,7 +130,9 @@ SET(organizer_HDRS mainwindow.h loghighlighter.h logbuffer.h + lockeddialogbase.h lockeddialog.h + waitingonclosedialog.h loadmechanism.h installationmanager.h helper.h @@ -200,6 +204,7 @@ SET(organizer_UIS messagedialog.ui mainwindow.ui lockeddialog.ui + waitingonclosedialog.ui installdialog.ui finddialog.ui editexecutablesdialog.ui diff --git a/src/ilockedwaitingforprocess.h b/src/ilockedwaitingforprocess.h index 5bf1f1ca..9475ddb9 100644 --- a/src/ilockedwaitingforprocess.h +++ b/src/ilockedwaitingforprocess.h @@ -6,7 +6,7 @@ class QString; class ILockedWaitingForProcess { public: - virtual bool unlockForced() = 0; + virtual bool unlockForced() const = 0; virtual void setProcessName(QString const &) = 0; }; diff --git a/src/lockeddialog.cpp b/src/lockeddialog.cpp index 09538a0f..143d5838 100644 --- a/src/lockeddialog.cpp +++ b/src/lockeddialog.cpp @@ -26,10 +26,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <Qt> // for Qt::FramelessWindowHint, etc
LockedDialog::LockedDialog(QWidget *parent, bool unlockByButton)
- : QDialog(parent)
+ : LockedDialogBase(parent, !unlockByButton)
, ui(new Ui::LockedDialog)
- , m_Unlocked(false)
- , m_allowClose(!unlockByButton)
{
ui->setupUi(this);
@@ -38,7 +36,7 @@ LockedDialog::LockedDialog(QWidget *parent, bool unlockByButton) // seem to work. We will ignore pressing the close button if unlockByButton == true
Qt::WindowFlags flags =
this->windowFlags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint;
- if (!unlockByButton)
+ if (m_allowClose)
flags |= Qt::WindowCloseButtonHint;
this->setWindowFlags(flags);
@@ -48,13 +46,6 @@ LockedDialog::LockedDialog(QWidget *parent, bool unlockByButton) ui->verticalLayout->addItem(
new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
}
-
- if (parent != nullptr) {
- QPoint position = parent->mapToGlobal(QPoint(parent->width() / 2, parent->height() / 2));
- position.rx() -= this->width() / 2;
- position.ry() -= this->height() / 2;
- move(position);
- }
}
LockedDialog::~LockedDialog()
@@ -68,35 +59,13 @@ void LockedDialog::setProcessName(const QString &name) ui->processLabel->setText(name);
}
-
-void LockedDialog::resizeEvent(QResizeEvent *event)
-{
- QWidget *par = parentWidget();
- if (par != nullptr) {
- QPoint position = par->mapToGlobal(QPoint(par->width() / 2, par->height() / 2));
- position.rx() -= event->size().width() / 2;
- position.ry() -= event->size().height() / 2;
- move(position);
- }
-}
-
void LockedDialog::on_unlockButton_clicked()
{
unlock();
}
-void LockedDialog::reject()
-{
- if (m_allowClose)
- unlock();
-}
-
-bool LockedDialog::unlockForced() {
- return m_Unlocked;
-}
-
void LockedDialog::unlock() {
- m_Unlocked = true;
+ LockedDialogBase::unlock();
ui->label->setText("unlocking may take a few seconds");
ui->unlockButton->setEnabled(false);
}
diff --git a/src/lockeddialog.h b/src/lockeddialog.h index 82a15a93..36c16429 100644 --- a/src/lockeddialog.h +++ b/src/lockeddialog.h @@ -17,16 +17,9 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef LOCKEDDIALOG_H
-#define LOCKEDDIALOG_H
+#pragma once
-#include "ilockedwaitingforprocess.h"
-#include <QDialog> // for QDialog
-#include <QObject> // for Q_OBJECT, slots
-#include <QString> // for QString
-
-class QResizeEvent;
-class QWidget;
+#include "lockeddialogbase.h"
namespace Ui {
class LockedDialog;
@@ -40,7 +33,7 @@ namespace Ui { * data on which Mod Organizer works. After the UI is unlocked (manually or after the
* external application closed) MO will refresh all of its data sources
**/
-class LockedDialog : public QDialog, public ILockedWaitingForProcess
+class LockedDialog : public LockedDialogBase
{
Q_OBJECT
@@ -48,35 +41,17 @@ public: explicit LockedDialog(QWidget *parent = 0, bool unlockByButton = false);
~LockedDialog();
- /**
- * @brief see if the user clicked the unlock-button
- *
- * @return true if the user clicked the unlock button
- **/
- bool unlockForced() override;
-
- /**
- * @brief set the name of the process being run
- * @param name of process
- */
void setProcessName(const QString &name) override;
protected:
- virtual void resizeEvent(QResizeEvent *event);
-
- virtual void reject();
+ void unlock() override;
private slots:
void on_unlockButton_clicked();
private:
- void unlock();
Ui::LockedDialog *ui;
- bool m_Unlocked;
- bool m_allowClose;
};
-
-#endif // LOCKEDDIALOG_H
diff --git a/src/lockeddialogbase.cpp b/src/lockeddialogbase.cpp new file mode 100644 index 00000000..b18f7429 --- /dev/null +++ b/src/lockeddialogbase.cpp @@ -0,0 +1,73 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "lockeddialogbase.h" + +#include <QPoint> +#include <QResizeEvent> +#include <QWidget> +#include <Qt> // for Qt::FramelessWindowHint, etc + +LockedDialogBase::LockedDialogBase(QWidget *parent, bool allowClose) + : QDialog(parent) + , m_Unlocked(false) + , m_Canceled(false) + , m_allowClose(allowClose) +{ + if (parent != nullptr) { + QPoint position = parent->mapToGlobal(QPoint(parent->width() / 2, parent->height() / 2)); + position.rx() -= this->width() / 2; + position.ry() -= this->height() / 2; + move(position); + } +} + +void LockedDialogBase::resizeEvent(QResizeEvent *event) +{ + QWidget *par = parentWidget(); + if (par != nullptr) { + QPoint position = par->mapToGlobal(QPoint(par->width() / 2, par->height() / 2)); + position.rx() -= event->size().width() / 2; + position.ry() -= event->size().height() / 2; + move(position); + } +} + +void LockedDialogBase::reject() +{ + if (m_allowClose) + unlock(); +} + +bool LockedDialogBase::unlockForced() const { + return m_Unlocked; +} + +bool LockedDialogBase::canceled() const { + return m_Canceled; +} + +void LockedDialogBase::unlock() { + m_Unlocked = true; +} + +void LockedDialogBase::cancel() { + m_Canceled = true; +} + diff --git a/src/lockeddialogbase.h b/src/lockeddialogbase.h new file mode 100644 index 00000000..3c974a38 --- /dev/null +++ b/src/lockeddialogbase.h @@ -0,0 +1,62 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "ilockedwaitingforprocess.h" +#include <QDialog> // for QDialog +#include <QObject> // for Q_OBJECT, slots +#include <QString> // for QString + +class QResizeEvent; +class QWidget; + +/** + * a small borderless dialog displayed while the Mod Organizer UI is locked + * The dialog contains only a label and a button to force the UI to be unlocked + * + * The UI gets locked while running external applications since they may modify the + * data on which Mod Organizer works. After the UI is unlocked (manually or after the + * external application closed) MO will refresh all of its data sources + **/ +class LockedDialogBase : public QDialog, public ILockedWaitingForProcess +{ + Q_OBJECT + +public: + explicit LockedDialogBase(QWidget *parent, bool allowClose); + + bool unlockForced() const override; + + virtual bool canceled() const; + +protected: + + virtual void resizeEvent(QResizeEvent *event); + + virtual void reject(); + + virtual void unlock(); + + virtual void cancel(); + + bool m_Unlocked; + bool m_Canceled; + bool m_allowClose; +}; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1e1a4558..85808e8d 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -59,6 +59,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "messagedialog.h"
#include "installationmanager.h"
#include "lockeddialog.h"
+#include "waitingonclosedialog.h"
#include "logbuffer.h"
#include "downloadlistsortproxy.h"
#include "motddialog.h"
@@ -855,6 +856,8 @@ void MainWindow::showEvent(QShowEvent *event) void MainWindow::closeEvent(QCloseEvent* event)
{
+ m_closing = true;
+
if (m_OrganizerCore.downloadManager()->downloadsInProgress()) {
if (QMessageBox::question(this, tr("Downloads in progress"),
tr("There are still downloads in progress, do you really want to quit?"),
@@ -866,6 +869,16 @@ void MainWindow::closeEvent(QCloseEvent* event) }
}
+ HANDLE injected_process_still_running = m_OrganizerCore.findAndOpenAUSVFSProcess();
+ if (injected_process_still_running != INVALID_HANDLE_VALUE)
+ {
+ m_OrganizerCore.waitForApplication(injected_process_still_running);
+ if (!m_closing) { // if operation cancelled
+ event->ignore();
+ return;
+ }
+ }
+
setCursor(Qt::WaitCursor);
}
@@ -1471,7 +1484,10 @@ ILockedWaitingForProcess* MainWindow::lock() ++m_LockCount;
return m_LockDialog;
}
- m_LockDialog = new LockedDialog(this, true);
+ if (m_closing)
+ m_LockDialog = new WaitingOnCloseDialog(this);
+ else
+ m_LockDialog = new LockedDialog(this, true);
m_LockDialog->setModal(true);
m_LockDialog->show();
setEnabled(false);
@@ -1489,6 +1505,8 @@ void MainWindow::unlock() }
--m_LockCount;
if (m_LockCount == 0) {
+ if (m_closing && m_LockDialog->canceled())
+ m_closing = false;
m_LockDialog->hide();
m_LockDialog->deleteLater();
m_LockDialog = nullptr;
diff --git a/src/mainwindow.h b/src/mainwindow.h index f6f11157..575bf020 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -35,7 +35,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. //when I get round to cleaning up main.cpp
struct Executable;
class CategoryFactory;
-class LockedDialog;
+class LockedDialogBase;
class OrganizerCore;
#include "plugincontainer.h" //class PluginContainer;
class PluginListSortProxy;
@@ -348,9 +348,11 @@ private: bool m_DidUpdateMasterList;
- LockedDialog *m_LockDialog { nullptr };
+ LockedDialogBase *m_LockDialog { nullptr };
uint64_t m_LockCount { 0 };
+ bool m_closing{ false };
+
std::vector<std::pair<QString, QHeaderView*>> m_PersistedGeometry;
enum class ShortcutType {
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 1f42bf95..c4bcaf3d 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1367,26 +1367,8 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode, IL QThread::msleep(500);
// search if there is another usvfs process active and if so wait for it
- // in theory a querySize of 1 is probably enough since the MO process doesn't seem to be returned by GetVFSProcessList
- constexpr size_t querySize = 2; // just to be on the safe side
- DWORD pids[querySize];
- size_t found = querySize;
- if (!::GetVFSProcessList(&found, pids)) {
- qWarning() << "Failed waiting for process completion : GetVFSProcessList failed?!";
- break;
- }
-
- for (size_t i = 0; i < found; ++i) {
- if (pids[i] == GetCurrentProcessId())
- continue; // obviously don't wait for MO process
- handle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION|SYNCHRONIZE, FALSE, pids[i]);
- if (handle == INVALID_HANDLE_VALUE) {
- qWarning() << "Failed waiting for process completion : OpenProcess failed" << GetLastError();
- continue;
- }
- newHandle = true;
- break;
- }
+ handle = findAndOpenAUSVFSProcess();
+ newHandle = handle != INVALID_HANDLE_VALUE;
}
}
@@ -1403,6 +1385,29 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode, IL return res == WAIT_OBJECT_0;
}
+HANDLE OrganizerCore::findAndOpenAUSVFSProcess() {
+ // in theory a querySize of 1 is probably enough since the MO process doesn't seem to be returned by GetVFSProcessList
+ constexpr size_t querySize = 2; // just to be on the safe side
+ DWORD pids[querySize];
+ size_t found = querySize;
+ if (!::GetVFSProcessList(&found, pids)) {
+ qWarning() << "Failed seeking USVFS processes : GetVFSProcessList failed?!";
+ return INVALID_HANDLE_VALUE;
+ }
+
+ for (size_t i = 0; i < found; ++i) {
+ if (pids[i] == GetCurrentProcessId())
+ continue; // obviously don't wait for MO process
+ HANDLE handle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, pids[i]);
+ if (handle != INVALID_HANDLE_VALUE)
+ return handle;
+ else
+ qWarning() << "Failed openning USVFS process " << pids[i] << " : OpenProcess failed" << GetLastError();
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
bool OrganizerCore::onAboutToRun(
const std::function<bool(const QString &)> &func)
{
diff --git a/src/organizercore.h b/src/organizercore.h index f8806289..cf030e0a 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -206,6 +206,7 @@ public: HANDLE runShortcut(const QString &title);
HANDLE startApplication(const QString &executable, const QStringList &args, const QString &cwd, const QString &profile);
bool waitForApplication(HANDLE processHandle, LPDWORD exitCode = nullptr);
+ HANDLE findAndOpenAUSVFSProcess();
bool onModInstalled(const std::function<void (const QString &)> &func);
bool onAboutToRun(const std::function<bool (const QString &)> &func);
bool onFinishedRun(const std::function<void (const QString &, unsigned int)> &func);
diff --git a/src/waitingonclosedialog.cpp b/src/waitingonclosedialog.cpp new file mode 100644 index 00000000..565d0a36 --- /dev/null +++ b/src/waitingonclosedialog.cpp @@ -0,0 +1,71 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "waitingonclosedialog.h" +#include "ui_waitingonclosedialog.h" + +#include <QPoint> +#include <QResizeEvent> +#include <QWidget> +#include <Qt> // for Qt::FramelessWindowHint, etc + +WaitingOnCloseDialog::WaitingOnCloseDialog(QWidget *parent) + : LockedDialogBase(parent,true) + , ui(new Ui::WaitingOnCloseDialog) +{ + ui->setupUi(this); + + // Supposedly the Qt::CustomizeWindowHint should use a customized window + // allowing us to select if there is a close button. In practice this doesn't + // seem to work. We will ignore pressing the close button if unlockByButton == true + Qt::WindowFlags flags = + this->windowFlags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint; + if (m_allowClose) + flags |= Qt::WindowCloseButtonHint; + this->setWindowFlags(flags); +} + +WaitingOnCloseDialog::~WaitingOnCloseDialog() +{ + delete ui; +} + + +void WaitingOnCloseDialog::setProcessName(const QString &name) +{ + ui->processLabel->setText(name); +} + +void WaitingOnCloseDialog::on_closeButton_clicked() +{ + unlock(); +} + +void WaitingOnCloseDialog::on_cancelButton_clicked() +{ + cancel(); + unlock(); +} + +void WaitingOnCloseDialog::unlock() { + LockedDialogBase::unlock(); + ui->label->setText("unlocking may take a few seconds"); + ui->closeButton->setEnabled(false); + ui->cancelButton->setEnabled(false); +} diff --git a/src/waitingonclosedialog.h b/src/waitingonclosedialog.h new file mode 100644 index 00000000..6650c390 --- /dev/null +++ b/src/waitingonclosedialog.h @@ -0,0 +1,56 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "lockeddialogbase.h" + +namespace Ui { + class WaitingOnCloseDialog; +} + +/** + * Similar to the LockedDialog but used for waiting on running process during + * a process close request which requries a slightly different dialog. + **/ +class WaitingOnCloseDialog : public LockedDialogBase +{ + Q_OBJECT + +public: + explicit WaitingOnCloseDialog(QWidget *parent = 0); + ~WaitingOnCloseDialog(); + + bool canceled() const { return m_Canceled; } + + void setProcessName(const QString &name) override; + +protected: + + void unlock() override; + +private slots: + + void on_closeButton_clicked(); + void on_cancelButton_clicked(); + +private: + + Ui::WaitingOnCloseDialog *ui; +}; diff --git a/src/waitingonclosedialog.ui b/src/waitingonclosedialog.ui new file mode 100644 index 00000000..9c7818e0 --- /dev/null +++ b/src/waitingonclosedialog.ui @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>WaitingOnCloseDialog</class> + <widget class="QDialog" name="WaitingOnCloseDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>317</width> + <height>151</height> + </rect> + </property> + <property name="windowTitle"> + <string>Waiting for virtualized processes</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,0"> + <item> + <widget class="QLabel" name="label"> + <property name="toolTip"> + <string>This dialog should disappear automatically if the application/game is done.</string> + </property> + <property name="text"> + <string>Virtualized processes are still running, it is prefered to keep MO running until they are finished.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer1"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <height>10</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="processLabel"> + <property name="font"> + <font> + <italic>true</italic> + </font> + </property> + <property name="styleSheet"> + <string notr="true">color: grey;</string> + </property> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <height>10</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0"> + <item> + <widget class="QPushButton" name="closeButton"> + <property name="text"> + <string>Close Now</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cancelButton"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <height>10</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> |
