Sandboxie/SandboxiePlus/SandMan/Windows/PopUpWindow.h

496 lines
14 KiB
C++

#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_PopUpWindow.h"
#include "../SbiePlusAPI.h"
#include "../SbieProcess.h"
#include "../SandMan.h"
class CPopUpEntry: public QWidget
{
Q_OBJECT
public:
CPopUpEntry(const QString& Message, QWidget* parent = 0) : QWidget(parent)
{
m_Message = Message;
m_pMainLayout = new QGridLayout(this);
m_pMainLayout->setContentsMargins(6, 0, 6, 0);
this->setLayout(m_pMainLayout);
}
virtual ~CPopUpEntry() {}
virtual QString GetMessageText() { return m_Message; }
protected:
QGridLayout* m_pMainLayout;
QString m_Message;
};
class CPopUpMessage : public CPopUpEntry
{
Q_OBJECT
public:
CPopUpMessage(const QString& Message, const QString& Link, quint32 MsgCode, const QStringList& MsgData, const QString& ProcessName, const QString& BoxName, QWidget* parent = 0) : CPopUpEntry(Message, parent)
{
m_Message = Message;
m_MsgCode = MsgCode;
m_MsgData = MsgData;
m_ProcessName = ProcessName;
m_BoxName = BoxName;
m_Count = 1;
m_pLabel = new QLabel(Message);
m_pLabel->setToolTip(Message);
m_pLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum);
connect(m_pLabel, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&)));
m_pMainLayout->addWidget(m_pLabel, 0, 0);
if (MsgCode != 0)
{
QToolButton* pHelp = new QToolButton();
pHelp->setText(tr("?"));
pHelp->setToolTip(tr("Visit %1 for a detailed explanation.").arg(Link));
pHelp->setMaximumWidth(16);
pHelp->setProperty("url", Link);
QObject::connect(pHelp, SIGNAL(clicked(bool)), this, SLOT(OnHelp()));
m_pMainLayout->addWidget(pHelp, 0, 1);
QToolButton* pFix = new QToolButton();
QFont fnt = pFix->font();
fnt.setBold(true);
//fnt.setWeight(QFont::DemiBold);
pFix->setFont(fnt);
pFix->setText(tr("Troubleshooting"));
pFix->setToolTip(tr("Start troubleshooting wizard"));
QObject::connect(pFix, SIGNAL(clicked(bool)), this, SLOT(OnTryFix()));
m_pMainLayout->addWidget(pFix, 0, 2);
QToolButton* pDismiss = new QToolButton();
pDismiss->setText(tr("Dismiss"));
pDismiss->setToolTip(tr("Remove this message from the list"));
pDismiss->setPopupMode(QToolButton::MenuButtonPopup);
QMenu* pMenu = new QMenu();
pMenu->addAction(tr("Hide all such messages"), this, SIGNAL(Hide()));
pDismiss->setMenu(pMenu);
//QObject::connect(pDismiss, SIGNAL(triggered(QAction*)), , SLOT());
QObject::connect(pDismiss, SIGNAL(clicked(bool)), this, SIGNAL(Dismiss()));
m_pMainLayout->addWidget(pDismiss, 0, 3);
}
}
quint32 GetMsgCode() { return m_MsgCode; }
quint32 GetMsgId() { return m_MsgCode & 0xFFFF; }
QStringList GetMsgData() { return m_MsgData; }
QString GetMsgData(int Index) { return m_MsgData.size() <= Index ? QString() : m_MsgData[Index]; }
QString GetMsgString() { return m_Message; }
void Repeat() { m_Count++; m_pLabel->setText(m_Message + tr(" (%1)").arg(m_Count)); }
signals:
void Dismiss();
void Hide();
private slots:
void OnHelp() { QDesktopServices::openUrl(QUrl(sender()->property("url").toString())); }
void OnTryFix()
{
theGUI->TryFix(m_MsgCode, m_MsgData, m_ProcessName, m_BoxName);
}
protected:
QString m_Message;
quint32 m_MsgCode;
QStringList m_MsgData;
QString m_ProcessName;
QString m_BoxName;
QLabel* m_pLabel;
int m_Count;
};
class CPopUpPrompt : public CPopUpEntry
{
Q_OBJECT
public:
CPopUpPrompt(const QString& Message, quint32 RequestId, QVariantMap Result, const CBoxedProcessPtr& pProcess, QWidget* parent = 0) : CPopUpEntry(Message, parent)
{
m_RequestId = RequestId;
m_Result = Result;
m_pProcess = pProcess;
m_bAddToList = false;
m_pLabel = new QLabel(Message);
m_pLabel->setToolTip(Message);
m_pLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum);
m_pMainLayout->addWidget(m_pLabel, 0, 0, 1, 5);
m_pRemember = new QCheckBox(tr("Remember for this process"));
m_pRemember->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
m_pMainLayout->addWidget(m_pRemember, 1, 0);
m_pTimeOut = new QLabel();
//m_pTimeOut->setStyleSheet("background-color:red;");
m_pMainLayout->addWidget(m_pTimeOut, 1, 1);
m_pYes = new QToolButton();
m_pYes->setText(tr("Yes"));
connect(m_pYes, SIGNAL(clicked(bool)), this, SLOT(OnAccepted()));
m_pMainLayout->addWidget(m_pYes, 1, 2);
m_pNo = new QToolButton();
m_pNo->setText(tr("No"));
connect(m_pNo, SIGNAL(clicked(bool)), this, SLOT(OnRejected()));
m_pMainLayout->addWidget(m_pNo, 1, 3);
m_pTerminate = new QToolButton();
m_pTerminate->setText(tr("Terminate"));
connect(m_pTerminate, SIGNAL(clicked(bool)), this, SLOT(OnTerminate()));
m_pMainLayout->addWidget(m_pTerminate, 1, 4);
m_iTimeOutSec = 60; // todo: communicate the actual value from dll or have a setting for that
if (RequestId == 0)
m_uTimerID = -1;
else
m_uTimerID = startTimer(1000);
}
~CPopUpPrompt() {
if(m_uTimerID != -1)
killTimer(m_uTimerID);
}
void AddAddToList()
{
m_pYes->setPopupMode(QToolButton::MenuButtonPopup);
QMenu* pMenu = new QMenu();
pMenu->addAction(tr("Yes and add to allowed programs"), this, SLOT(OnAcceptedAlways()));
m_pYes->setMenu(pMenu);
}
signals:
void PromptResult(int retval);
private slots:
void OnAcceptedAlways() { m_bAddToList = true; emit PromptResult(1); }
void OnAccepted() { emit PromptResult(1); }
void OnRejected() { emit PromptResult(0); }
void OnTerminate() { emit PromptResult(-1); }
protected:
friend class CPopUpWindow;
void timerEvent(QTimerEvent* pEvent)
{
if (pEvent->timerId() != m_uTimerID)
return;
if (m_iTimeOutSec > 0)
{
m_iTimeOutSec--;
extern bool CPopUpWindow__DarkMode;
if (CPopUpWindow__DarkMode) {
QPalette palette = m_pLabel->palette();
palette.setColor(QPalette::Text, Qt::red);
m_pLabel->setPalette(palette);
}
else
repaint();
}
if (m_pProcess->IsTerminated()) {
m_pTimeOut->setText(tr("Requesting process terminated"));
m_pYes->setEnabled(false);
m_pTerminate->setEnabled(false);
}
else if (m_iTimeOutSec > 0)
m_pTimeOut->setText(tr("Request will time out in %1 sec").arg(m_iTimeOutSec));
else {
m_pTimeOut->setText(tr("Request timed out").arg(m_iTimeOutSec));
m_pYes->setEnabled(false);
}
}
int m_uTimerID;
virtual void paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
extern bool CPopUpWindow__DarkMode;
if (!CPopUpWindow__DarkMode && (m_iTimeOutSec % 2) != 0)
{
QPainter p(this);
p.fillRect(2, 1, width() - 4, height() - 2, QColor(0xFF, 0xCC, 0xCC));
}
}
quint32 m_RequestId;
QVariantMap m_Result;
CBoxedProcessPtr m_pProcess;
bool m_bAddToList;
QLabel* m_pLabel;
QCheckBox* m_pRemember;
qint32 m_iTimeOutSec;
QLabel* m_pTimeOut;
QToolButton* m_pYes;
QToolButton* m_pNo;
QToolButton* m_pTerminate;
};
class CPopUpRecovery : public CPopUpEntry
{
Q_OBJECT
public:
CPopUpRecovery(const QString& Message, const QString& FilePath, const QString& BoxPath, const QString& BoxName, QWidget* parent = 0) : CPopUpEntry(Message, parent)
{
m_BoxName = BoxName;
m_FilePath = FilePath;
m_BoxPath = BoxPath;
QLabel* pLabel = new QLabel(Message);
pLabel->setToolTip(Message);
pLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum);
//pLabel->setWordWrap(true);
extern bool CPopUpWindow__DarkMode;
if(CPopUpWindow__DarkMode) {
QPalette palette = pLabel->palette();
palette.setColor(QPalette::Text, Qt::green);
pLabel->setPalette(palette);
}
m_pMainLayout->addWidget(pLabel, 0, 0, 2, 4);
m_pMainLayout->addWidget(new QLabel(tr("Recover to:")), 2, 0);
m_pTarget = new QComboBox();
m_LastTargetIndex = 0;
m_pTarget->addItem(m_FilePath.left(m_FilePath.lastIndexOf("\\")));
m_pTarget->addItem(tr("Browse"), 1);
m_pTarget->addItem(tr("Clear folder list"), -1);
m_ListCleared = false;
connect(m_pTarget, SIGNAL(currentIndexChanged(int)), this, SLOT(OnTargetChanged()));
m_pTarget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_pMainLayout->addWidget(m_pTarget, 2, 1);
QToolButton* pRecover = new QToolButton();
pRecover->setText(tr("Recover"));
pRecover->setToolTip(tr("Recover the file to original location"));
pRecover->setPopupMode(QToolButton::MenuButtonPopup);
QMenu* pRecMenu = new QMenu();
pRecMenu->addAction(tr("Recover && Explore"), this, SLOT(OnRecoverExp()));
pRecMenu->addAction(tr("Recover && Open/Run"), this, SLOT(OnRecoverRun()));
pRecMenu->addSeparator();
pRecMenu->addAction(tr("Open file recovery for this box"), this, SIGNAL(OpenRecovery()));
pRecover->setMenu(pRecMenu);
//QObject::connect(pRecover, SIGNAL(triggered(QAction*)), , SLOT());
QObject::connect(pRecover, SIGNAL(clicked(bool)), this, SLOT(OnRecover()));
m_pMainLayout->addWidget(pRecover, 2, 2);
QToolButton* pDismiss = new QToolButton();
pDismiss->setText(tr("Dismiss"));
pDismiss->setToolTip(tr("Don't recover this file right now"));
pDismiss->setPopupMode(QToolButton::MenuButtonPopup);
QMenu* pMenu = new QMenu();
pMenu->addAction(tr("Dismiss all from this box"), this, SLOT(OnDismissAll()));
pMenu->addAction(tr("Disable quick recovery until the box restarts"), this, SLOT(OnDisable()));
pDismiss->setMenu(pMenu);
//QObject::connect(pDismiss, SIGNAL(triggered(QAction*)), , SLOT());
QObject::connect(pDismiss, SIGNAL(clicked(bool)), this, SIGNAL(Dismiss()));
m_pMainLayout->addWidget(pDismiss, 2, 3);
}
signals:
void Dismiss(int iFlag = 0);
void RecoverFile(int Action = 0);
void OpenRecovery();
private slots:
void OnDisable() { emit Dismiss(0x03); }
void OnDismissAll() { emit Dismiss(0x01); }
void OnRecover() { emit RecoverFile(); }
void OnRecoverRun() { emit RecoverFile(1); }
void OnRecoverExp() { emit RecoverFile(2); }
void OnTargetChanged()
{
int op = m_pTarget->currentData().toInt();
if (op == 1)
{
QString Folder = QFileDialog::getExistingDirectory(this, tr("Select Directory")).replace("/", "\\");
if (Folder.isEmpty()) {
m_pTarget->setCurrentIndex(m_LastTargetIndex);
return;
}
m_LastTargetIndex = m_pTarget->count() - 1;
m_pTarget->insertItem(m_LastTargetIndex, Folder);
m_pTarget->setCurrentIndex(m_LastTargetIndex);
}
else if (op == -1)
{
while (m_pTarget->count() > 3)
m_pTarget->removeItem(2);
m_pTarget->setCurrentIndex(0);
m_ListCleared = true;
}
}
protected:
friend class CPopUpWindow;
virtual void paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
extern bool CPopUpWindow__DarkMode;
if (!CPopUpWindow__DarkMode) {
QPainter p(this);
p.fillRect(2, 1, width() - 4, height() - 2, QColor(0xCC, 0xFF, 0xCC));
}
}
QString m_FilePath;
QString m_BoxPath;
QString m_BoxName;
QComboBox* m_pTarget;
int m_LastTargetIndex;
bool m_ListCleared;
};
class CPopUpProgress : public CPopUpEntry
{
Q_OBJECT
public:
CPopUpProgress(const QString& Message, const QString& ID, quint64 Total, QWidget* parent = 0) : CPopUpEntry(Message, parent)
{
m_ID = ID;
m_Total = Total;
m_pLabel = new QLabel(Message);
m_pLabel->setToolTip(Message);
m_pLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum);
m_pMainLayout->addWidget(m_pLabel, 0, 0, 1, 3);
m_pProgressBar = new QProgressBar();
m_pProgressBar->setTextVisible(false);
m_pProgressBar->setMaximum(m_Total != 0? 100 : 0);
m_pProgressBar->setMinimum(0);
m_pProgressBar->setFixedHeight(16);
m_pMainLayout->addWidget(m_pProgressBar, 1, 0, 1, 2);
QToolButton* pDismiss = new QToolButton();
pDismiss->setText(tr("Dismiss"));
pDismiss->setToolTip(tr("Remove this progress indicator from the list"));
//pDismiss->setPopupMode(QToolButton::MenuButtonPopup);
//QMenu* pMenu = new QMenu();
//pMenu->addAction(tr("Hide this progress for this process"), this, SIGNAL(Hide()));
//pDismiss->setMenu(pMenu);
//QObject::connect(pDismiss, SIGNAL(triggered(QAction*)), , SLOT());
QObject::connect(pDismiss, SIGNAL(clicked(bool)), this, SIGNAL(Dismiss()));
m_pMainLayout->addWidget(pDismiss, 1, 2);
m_iTimeOutSec = 5;
m_uTimerID = startTimer(1000);
}
~CPopUpProgress() {
if (m_uTimerID != -1)
killTimer(m_uTimerID);
}
void UpdateProgress(const QString& Message, quint64 Value)
{
if(m_Total != 0)
m_pProgressBar->setValue(100 - (100 * Value / m_Total));
m_pLabel->setText(Message);
m_iTimeOutSec = 5;
}
signals:
void Dismiss(bool bHide = true);
//void Hide();
protected:
friend class CPopUpWindow;
void timerEvent(QTimerEvent* pEvent)
{
if (pEvent->timerId() != m_uTimerID)
return;
if (m_iTimeOutSec > 0)
{
if (--m_iTimeOutSec == 0)
emit Dismiss(false);
}
}
int m_uTimerID;
QString m_ID;
quint64 m_Total;
QLabel* m_pLabel;
QProgressBar* m_pProgressBar;
qint32 m_iTimeOutSec;
};
class CPopUpWindow : public QMainWindow
{
Q_OBJECT
public:
CPopUpWindow(QWidget* parent = 0);
~CPopUpWindow();
virtual void AddLogMessage(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId);
virtual void AddUserPrompt(quint32 RequestId, const QVariantMap& Data, quint32 ProcessId);
virtual void AddFileToRecover(const QString& FilePath, QString BoxPath, const CSandBoxPtr& pBox, quint32 ProcessId);
virtual void ShowProgress(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId);
static void SetDarkMode(bool bDark) { extern bool CPopUpWindow__DarkMode; CPopUpWindow__DarkMode = bDark; }
public slots:
virtual void Show();
virtual void Poke();
virtual void ReloadHiddenMessages();
private slots:
virtual void OnDismissMessage();
virtual void OnHideMessage();
virtual void OnPromptResult(int retval);
virtual void OnDismiss(int iFlag);
virtual void OnRecoverFile(int Action);
virtual void OnOpenRecovery();
virtual void OnDismissProgress(bool bHide);
virtual void OnCopy();
protected:
virtual void closeEvent(QCloseEvent *e);
void timerEvent(QTimerEvent* pEvent);
virtual void AddEntry(CPopUpEntry* pEntry);
virtual void RemoveEntry(CPopUpEntry* pEntry);
virtual bool IsMessageHidden(quint32 MsgCode, const QStringList& MsgData);
virtual void SendPromptResult(CPopUpPrompt* pEntry, int retval);
QMultiMap<quint32, QString> m_HiddenMessages;
bool m_HideAllMessages;
private:
bool m_ResetPosition;
QAction* m_pActionCopy;
int m_uTimerID;
int m_iTopMost;
Ui::PopUpWindow ui;
};