summaryrefslogtreecommitdiff
path: root/src/lockwidget.cpp
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-11-06 05:23:22 -0500
committerisanae <14251494+isanae@users.noreply.github.com>2019-11-06 07:45:02 -0500
commit642ddacab802df75d21a1ccf7508268d3efa141a (patch)
tree2b9cc615fd747da2bd049c9a5625d4b6cedfcb3c /src/lockwidget.cpp
parent3d0197fa5e6c4209d021398415f779994c21bd24 (diff)
moved LockWidget back to OrganizerCore to support having multiple locks active
moved the ui out of LockWidget into LockInterface added LockWidget::Session to manage multi locks
Diffstat (limited to 'src/lockwidget.cpp')
-rw-r--r--src/lockwidget.cpp490
1 files changed, 359 insertions, 131 deletions
diff --git a/src/lockwidget.cpp b/src/lockwidget.cpp
index 35d51dab..68eb9c2d 100644
--- a/src/lockwidget.cpp
+++ b/src/lockwidget.cpp
@@ -4,203 +4,431 @@
#include <QMenuBar>
#include <QStatusBar>
-QWidget* createTransparentWidget(QWidget* parent=nullptr)
+class LockInterface
{
- auto* w = new QWidget(parent);
+public:
+ LockInterface() :
+ m_hasMainUI(false), m_message(nullptr), m_info(nullptr), m_buttons(nullptr)
+ {
+ }
- w->setWindowOpacity(0);
- w->setAttribute(Qt::WA_NoSystemBackground);
- w->setAttribute(Qt::WA_TranslucentBackground);
+ ~LockInterface()
+ {
+ }
- return w;
-}
+ void set(QWidget* target)
+ {
+ QFrame* center = nullptr;
+ if (target) {
+ center = createOverlay(target);
+ } else {
+ center = createDialog();
+ }
-LockWidget::LockWidget(QWidget* parent, Reasons reason) :
- m_parent(parent), m_overlay(nullptr), m_info(nullptr), m_result(NoResult),
- m_filter(nullptr)
-{
- if (reason != NoReason) {
- lock(reason);
+ createMessageLabel();
+ createInfoLabel();
+ createButtonsPanel();
+
+ center->layout()->addWidget(m_message);
+ center->layout()->addWidget(m_info);
+ center->layout()->addWidget(m_buttons);
+
+ m_topLevel->setFocusPolicy(Qt::TabFocus);
+ m_topLevel->setFocus();
+ m_topLevel->show();
+ m_topLevel->setEnabled(true);
+
+ m_topLevel->raise();
+ m_topLevel->activateWindow();
}
-}
-LockWidget::~LockWidget()
-{
- unlock();
-}
+ void update(LockWidget::Reasons reason)
+ {
+ updateMessage(reason);
+ updateButtons(reason);
+ }
-void LockWidget::lock(Reasons reason)
-{
- m_result = StillLocked;
- createUi(reason);
-}
+ void setInfo(const QString& s)
+ {
+ m_info->setText(s);
+ }
+
+ QWidget* topLevel()
+ {
+ return m_topLevel.get();
+ }
+
+private:
+ class Filter : public QObject
+ {
+ public:
+ std::function<void ()> resized;
+ std::function<void ()> closed;
+
+ protected:
+ bool eventFilter(QObject* o, QEvent* e) override
+ {
+ if (e->type() == QEvent::Resize) {
+ if (resized) {
+ resized();
+ }
+ } else if (e->type() == QEvent::Close) {
+ if (closed) {
+ closed();
+ }
+ }
+
+ return QObject::eventFilter(o, e);
+ }
+ };
-void LockWidget::unlock()
-{
- m_overlay.reset();
- if (m_filter && m_parent) {
- m_parent->removeEventFilter(m_filter.get());
+ bool m_hasMainUI;
+ std::unique_ptr<QWidget> m_topLevel;
+ QLabel* m_message;
+ QLabel* m_info;
+ QWidget* m_buttons;
+ std::unique_ptr<Filter> m_filter;
+
+ QWidget* createTransparentWidget(QWidget* parent=nullptr)
+ {
+ auto* w = new QWidget(parent);
+
+ w->setWindowOpacity(0);
+ w->setAttribute(Qt::WA_NoSystemBackground);
+ w->setAttribute(Qt::WA_TranslucentBackground);
+
+ return w;
}
- enableAll();
-}
+ QFrame* createOverlay(QWidget* mainUI)
+ {
+ m_hasMainUI = true;
-void LockWidget::setInfo(DWORD pid, const QString& name)
-{
- m_info->setText(QString("%1 (%2)").arg(name).arg(pid));
-}
+ m_topLevel.reset(createTransparentWidget(mainUI));
+ m_topLevel->setWindowFlags(m_topLevel->windowFlags() & Qt::FramelessWindowHint);
+ m_topLevel->setGeometry(mainUI->rect());
-LockWidget::Results LockWidget::result() const
-{
- return m_result;
-}
+ m_filter.reset(new Filter);
+ m_filter->resized = [=]{ m_topLevel->setGeometry(mainUI->rect()); };
+ m_filter->closed = [=]{ LockWidget::instance().onForceUnlock(); };
-void LockWidget::createUi(Reasons reason)
-{
- QWidget* overlayTarget = m_parent;
- if (auto* w = qApp->activeWindow()) {
- overlayTarget = w;
+ mainUI->installEventFilter(m_filter.get());
+
+ return createFrame();
}
- if (overlayTarget) {
- m_overlay.reset(createTransparentWidget(overlayTarget));
- m_overlay->setWindowFlags(m_overlay->windowFlags() & Qt::FramelessWindowHint);
- m_overlay->setGeometry(overlayTarget->rect());
- } else {
- m_overlay.reset(new QDialog);
+ QFrame* createDialog()
+ {
+ m_hasMainUI = false;
+ m_topLevel.reset(new QDialog);
+
+ return createFrame();
}
- auto* center = new QFrame;
+ QFrame* createFrame()
+ {
+ auto* frame = new QFrame;
+ auto* ly = new QVBoxLayout(frame);
- if (overlayTarget) {
- center->setFrameStyle(QFrame::StyledPanel);
- center->setLineWidth(1);
- center->setAutoFillBackground(true);
+ if (m_hasMainUI) {
+ frame->setFrameStyle(QFrame::StyledPanel);
+ frame->setLineWidth(1);
+ frame->setAutoFillBackground(true);
- auto* shadow = new QGraphicsDropShadowEffect;
- shadow->setBlurRadius(50);
- shadow->setOffset(0);
- shadow->setColor(QColor(0, 0, 0, 100));
- center->setGraphicsEffect(shadow);
- }
+ auto* shadow = new QGraphicsDropShadowEffect;
+ shadow->setBlurRadius(50);
+ shadow->setOffset(0);
+ shadow->setColor(QColor(0, 0, 0, 100));
+ frame->setGraphicsEffect(shadow);
+ } else {
+ ly->setContentsMargins(0, 0, 0, 0);
+ }
+
+ auto* grid = new QGridLayout(m_topLevel.get());
+ grid->addWidget(createTransparentWidget(), 0, 1);
+ grid->addWidget(createTransparentWidget(), 2, 1);
+ grid->addWidget(createTransparentWidget(), 1, 0);
+ grid->addWidget(createTransparentWidget(), 1, 2);
+ grid->addWidget(frame, 1, 1);
+
+ if (!m_hasMainUI) {
+ grid->setContentsMargins(0, 0, 0, 0);
+ }
+
+ grid->setRowStretch(0, 1);
+ grid->setRowStretch(2, 1);
+ grid->setColumnStretch(0, 1);
+ grid->setColumnStretch(2, 1);
- m_info = new QLabel(" ");
- m_info->setAlignment(Qt::AlignCenter | Qt::AlignHCenter);
+ return frame;
+ }
- auto* ly = new QVBoxLayout(center);
+ void createMessageLabel()
+ {
+ m_message = new QLabel;
+ }
- if (!overlayTarget) {
- ly->setContentsMargins(0, 0, 0, 0);
+ void createInfoLabel()
+ {
+ m_info = new QLabel(" ");
+ m_info->setAlignment(Qt::AlignCenter | Qt::AlignHCenter);
}
- auto* message = new QLabel;
- ly->addWidget(message);
- ly->addWidget(m_info);
+ void createButtonsPanel()
+ {
+ m_buttons = new QWidget;
+ m_buttons->setLayout(new QHBoxLayout);
+ }
- auto* buttons = new QWidget;
- auto* buttonsLayout = new QHBoxLayout(buttons);
- ly->addWidget(buttons);
- switch (reason)
+ void updateMessage(LockWidget::Reasons reason)
{
- case LockUI:
+ switch (reason)
{
- QString s;
+ case LockWidget::LockUI:
+ {
+ QString s;
+
+ if (m_hasMainUI) {
+ s = QObject::tr(
+ "Mod Organizer is locked while the application is running.");
+ } else {
+ s = QObject::tr("Mod Organizer is currently running an application.");
+ }
- if (!m_parent) {
- s = QObject::tr("Mod Organizer is currently running an application.");
- } else {
- s = QObject::tr(
- "Mod Organizer is locked while the application is running.");
+ m_message->setText(s);
+
+ break;
}
- message->setText(s);
+ case LockWidget::OutputRequired:
+ {
+ m_message->setText(QObject::tr(
+ "The application must run to completion because its output is "
+ "required."));
- auto* unlockButton = new QPushButton(QObject::tr("Unlock"));
- QObject::connect(unlockButton, &QPushButton::clicked, [&]{ onForceUnlock(); });
- buttonsLayout->addWidget(unlockButton);
+ break;
+ }
- break;
+ case LockWidget::PreventExit:
+ {
+ m_message->setText(QObject::tr(
+ "Mod Organizer is waiting on application to close before exiting."));
+
+ break;
+ }
}
+ }
+
+ void updateButtons(LockWidget::Reasons reason)
+ {
+ MOBase::deleteChildWidgets(m_buttons);
+ auto* ly = m_buttons->layout();
- case OutputRequired:
+ switch (reason)
{
- message->setText(QObject::tr(
- "The application must run to completion because its output is "
- "required."));
+ case LockWidget::LockUI: // fall-through
+ case LockWidget::OutputRequired:
+ {
+ auto* unlock = new QPushButton(QObject::tr("Unlock"));
- auto* unlockButton = new QPushButton(QObject::tr("Unlock"));
- QObject::connect(unlockButton, &QPushButton::clicked, [&]{ onForceUnlock(); });
- buttonsLayout->addWidget(unlockButton);
+ QObject::connect(unlock, &QPushButton::clicked, [&]{
+ LockWidget::instance().onForceUnlock();
+ });
- break;
+ ly->addWidget(unlock);
+
+ break;
+ }
+
+ case LockWidget::PreventExit:
+ {
+ auto* exit = new QPushButton(QObject::tr("Exit Now"));
+ QObject::connect(exit, &QPushButton::clicked, [&]{
+ LockWidget::instance().onForceUnlock();
+ });
+
+ ly->addWidget(exit);
+
+ auto* cancel = new QPushButton(QObject::tr("Cancel"));
+ QObject::connect(cancel, &QPushButton::clicked, [&]{
+ LockWidget::instance().onCancel();
+ });
+
+ ly->addWidget(cancel);
+
+ break;
+ }
}
+ }
+};
- case PreventExit:
- {
- message->setText(QObject::tr(
- "Mod Organizer is waiting on application to close before exiting."));
+LockWidget::Session::~Session()
+{
+ LockWidget::instance().unlock(this);
+}
+
+void LockWidget::Session::setInfo(DWORD pid, const QString& name)
+{
+ m_pid = pid;
+ m_name = name;
+
+ LockWidget::instance().updateLabel();
+}
+
+DWORD LockWidget::Session::pid() const
+{
+ return m_pid;
+}
+
+const QString& LockWidget::Session::name() const
+{
+ return m_name;
+}
+
+LockWidget::Results LockWidget::Session::result() const
+{
+ return LockWidget::instance().result();
+}
+
+
+static LockWidget* g_instance = nullptr;
+
+
+LockWidget::LockWidget()
+ : m_parent(nullptr), m_result(NoResult)
+{
+ Q_ASSERT(!g_instance);
+ g_instance = this;
+}
+
+LockWidget::~LockWidget()
+{
+ const auto v = m_sessions;
+
+ for (auto& wp : v) {
+ if (auto s=wp.lock()) {
+ unlock(s.get());
+ }
+ }
+}
+
+LockWidget& LockWidget::instance()
+{
+ Q_ASSERT(g_instance);
+ return *g_instance;
+}
- auto* exit = new QPushButton(QObject::tr("Exit Now"));
- QObject::connect(exit, &QPushButton::clicked, [&]{ onForceUnlock(); });
- buttonsLayout->addWidget(exit);
+void LockWidget::setUserInterface(QWidget* parent)
+{
+ m_parent = parent;
+}
+
+std::shared_ptr<LockWidget::Session> LockWidget::lock(Reasons reason)
+{
+ m_result = StillLocked;
+ createUi(reason);
+
+ auto ls = std::make_shared<Session>();
+ m_sessions.push_back(ls);
- auto* cancel = new QPushButton(QObject::tr("Cancel"));
- QObject::connect(cancel, &QPushButton::clicked, [&]{ onCancel(); });
- buttonsLayout->addWidget(cancel);
+ updateLabel();
+ return ls;
+}
+
+void LockWidget::unlock(Session* s)
+{
+ auto itor = m_sessions.begin();
+ for (;;) {
+ if (itor == m_sessions.end()) {
break;
}
+
+ if (auto ss=itor->lock()) {
+ if (ss.get() == s) {
+ itor = m_sessions.erase(itor);
+ continue;
+ }
+ } else {
+ itor = m_sessions.erase(itor);
+ continue;
+ }
+
+ ++itor;
}
- auto* grid = new QGridLayout(m_overlay.get());
- grid->addWidget(createTransparentWidget(), 0, 1);
- grid->addWidget(createTransparentWidget(), 2, 1);
- grid->addWidget(createTransparentWidget(), 1, 0);
- grid->addWidget(createTransparentWidget(), 1, 2);
- grid->addWidget(center, 1, 1);
+ if (m_sessions.empty()) {
+ m_ui.reset();
+ enableAll();
+ } else {
+ updateLabel();
+ }
+}
- if (!overlayTarget) {
- grid->setContentsMargins(0, 0, 0, 0);
+void LockWidget::unlockCurrent()
+{
+ if (m_sessions.empty()) {
+ return;
}
- grid->setRowStretch(0, 1);
- grid->setRowStretch(2, 1);
- grid->setColumnStretch(0, 1);
- grid->setColumnStretch(2, 1);
+ auto s = m_sessions.back().lock();
+ if (!s) {
+ m_sessions.pop_back();
+ return;
+ }
- disableAll();
+ unlock(s.get());
+}
- if (overlayTarget) {
- m_filter.reset(new Filter);
- m_filter->resized = [=]{ m_overlay->setGeometry(overlayTarget->rect()); };
- m_filter->closed = [=]{ onForceUnlock(); };
- overlayTarget->installEventFilter(m_filter.get());
+void LockWidget::updateLabel()
+{
+ QString label;
+
+ for (auto itor=m_sessions.rbegin(); itor!=m_sessions.rend(); ++itor) {
+ if (auto ss=itor->lock()) {
+ label += QString("%1 (%2)").arg(ss->name()).arg(ss->pid());
+ break;
+ }
}
- m_overlay->setFocusPolicy(Qt::TabFocus);
- m_overlay->setFocus();
- m_overlay->show();
- m_overlay->setEnabled(true);
+ m_ui->setInfo(label);
+}
+
+LockWidget::Results LockWidget::result() const
+{
+ return m_result;
+}
+
+void LockWidget::createUi(Reasons reason)
+{
+ QWidget* target = m_parent;
+ if (auto* w = qApp->activeWindow()) {
+ target = w;
+ }
- if (!overlayTarget) {
- m_overlay->raise();
- m_overlay->activateWindow();
+ if (!m_ui) {
+ m_ui.reset(new LockInterface);
}
+
+ m_ui->set(target);
+ m_ui->update(reason);
+
+ disableAll();
}
void LockWidget::onForceUnlock()
{
m_result = ForceUnlocked;
- unlock();
+ unlockCurrent();
}
void LockWidget::onCancel()
{
m_result = Cancelled;
- unlock();
+ unlockCurrent();
}
template <class T>
@@ -231,10 +459,10 @@ void LockWidget::disableAll()
if (auto* d=dynamic_cast<QDialog*>(w)) {
// don't disable stuff if this dialog is the overlay, which happens when
// there's no ui
- if (d != m_overlay.get()) {
+ if (d != m_ui->topLevel()) {
// no central widget, just disable the children, except for the overlay
for (auto* child : findChildrenImmediate<QWidget*>(d)) {
- if (child != m_overlay.get()) {
+ if (child != m_ui->topLevel()) {
disable(child);
}
}