#include "stdafx.h" #include "OptionsWindow.h" #include "SandMan.h" #include "SettingsWindow.h" #include "../MiscHelpers/Common/Settings.h" #include "../MiscHelpers/Common/Common.h" #include "../MiscHelpers/Common/ComboInputDialog.h" #include "../MiscHelpers/Common/SettingsWidgets.h" #include "Helpers/WinAdmin.h" class NoEditDelegate : public QStyledItemDelegate { public: NoEditDelegate(QObject* parent = 0) : QStyledItemDelegate(parent) {} virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { return NULL; } }; class QTreeWidgetHacker : public QTreeWidget { public: friend class ProgramsDelegate; //QModelIndex indexFromItem(const QTreeWidgetItem *item, int column = 0) const; //QTreeWidgetItem *itemFromIndex(const QModelIndex &index) const; }; ////////////////////////////////////////////////////////////////////////// // ProgramsDelegate class ProgramsDelegate : public QStyledItemDelegate { public: ProgramsDelegate(COptionsWindow* pOptions, QTreeWidget* pTree, int Column, QObject* parent = 0) : QStyledItemDelegate(parent) { m_pOptions = pOptions; m_pTree = pTree; m_Column = Column; } virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { QTreeWidgetItem* pItem = ((QTreeWidgetHacker*)m_pTree)->itemFromIndex(index); if (!pItem->data(index.column(), Qt::UserRole).isValid()) return NULL; if (m_Column == -1 || pItem->data(m_Column, Qt::UserRole).toInt() == COptionsWindow::eProcess) { QComboBox* pBox = new QComboBox(parent); pBox->setEditable(true); foreach(const QString Group, m_pOptions->GetCurrentGroups()) { QString GroupName = Group.mid(1, Group.length() - 2); pBox->addItem(tr("Group: %1").arg(GroupName), Group); } foreach(const QString & Name, m_pOptions->GetPrograms()) pBox->addItem(Name, Name); connect(pBox->lineEdit(), &QLineEdit::textEdited, [pBox](const QString& text){ /*if (pBox->currentIndex() != -1) { int pos = pBox->lineEdit()->cursorPosition(); pBox->setCurrentIndex(-1); pBox->setCurrentText(text); pBox->lineEdit()->setCursorPosition(pos); }*/ pBox->setProperty("value", text); }); connect(pBox->lineEdit(), &QLineEdit::returnPressed, [pBox](){ /*if (pBox->currentIndex() != -1) { int pos = pBox->lineEdit()->cursorPosition(); pBox->setCurrentIndex(-1); pBox->setCurrentText(text); pBox->lineEdit()->setCursorPosition(pos); }*/ pBox->setProperty("value", pBox->lineEdit()->text()); }); connect(pBox, qOverload(&QComboBox::currentIndexChanged), [pBox](int index){ if (index != -1) pBox->setProperty("value", pBox->itemData(index)); }); return pBox; } else if (pItem->data(0, Qt::UserRole).toInt() == COptionsWindow::ePath) return QStyledItemDelegate::createEditor(parent, option, index); else return NULL; } virtual void setEditorData(QWidget* editor, const QModelIndex& index) const { QComboBox* pBox = qobject_cast(editor); if (pBox) { QTreeWidgetItem* pItem = ((QTreeWidgetHacker*)m_pTree)->itemFromIndex(index); QString Program = pItem->data(index.column(), Qt::UserRole).toString(); pBox->setProperty("value", Program); int Index = pBox->findData(Program); pBox->setCurrentIndex(Index); if (Index == -1) pBox->setCurrentText(Program); } else QStyledItemDelegate::setEditorData(editor, index); } virtual void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { QComboBox* pBox = qobject_cast(editor); if (pBox) { QTreeWidgetItem* pItem = ((QTreeWidgetHacker*)m_pTree)->itemFromIndex(index); QString Value = pBox->property("value").toString(); pItem->setText(index.column(), pBox->currentText()); //QString Text = pBox->currentText(); //QVariant Data = pBox->currentData(); pItem->setData(index.column(), Qt::UserRole, Value); } QLineEdit* pEdit = qobject_cast(editor); if (pEdit) { QTreeWidgetItem* pItem = ((QTreeWidgetHacker*)m_pTree)->itemFromIndex(index); pItem->setText(index.column(), pEdit->text()); pItem->setData(index.column(), Qt::UserRole, pEdit->text()); } } protected: COptionsWindow* m_pOptions; QTreeWidget* m_pTree; int m_Column; }; ////////////////////////////////////////////////////////////////////////// // COptionsWindow COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QString& Name, QWidget *parent) : CConfigDialog(parent) { m_pBox = pBox; m_Template = pBox->GetName().left(9).compare("Template_", Qt::CaseInsensitive) == 0; bool ReadOnly = /*pBox->GetAPI()->IsConfigLocked() ||*/ (m_Template && pBox->GetName().mid(9, 6).compare("Local_", Qt::CaseInsensitive) != 0); m_HoldChange = false; QSharedPointer pBoxPlus = m_pBox.objectCast(); if (!pBoxPlus.isNull()) m_Programs = pBoxPlus->GetRecentPrograms(); Qt::WindowFlags flags = windowFlags(); flags |= Qt::CustomizeWindowHint; //flags &= ~Qt::WindowContextHelpButtonHint; //flags &= ~Qt::WindowSystemMenuHint; //flags &= ~Qt::WindowMinMaxButtonsHint; flags |= Qt::WindowMinimizeButtonHint; //flags &= ~Qt::WindowCloseButtonHint; setWindowFlags(flags); bool bAlwaysOnTop = theConf->GetBool("Options/AlwaysOnTop", false); this->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop); ui.setupUi(this); this->setWindowTitle(tr("Sandboxie Plus - '%1' Options").arg(QString(Name).replace("_", " "))); ui.tabs->setTabPosition(QTabWidget::West); ui.tabs->tabBar()->setStyle(new CustomTabStyle(ui.tabs->tabBar()->style())); ui.tabs->tabBar()->setProperty("isSidebar", true); ui.tabs->setCurrentIndex(0); ui.tabs->setTabIcon(0, CSandMan::GetIcon("Config")); ui.tabs->setTabIcon(1, CSandMan::GetIcon("Security")); ui.tabs->setTabIcon(2, CSandMan::GetIcon("Group")); ui.tabs->setTabIcon(3, CSandMan::GetIcon("Control")); ui.tabs->setTabIcon(4, CSandMan::GetIcon("Stop")); ui.tabs->setTabIcon(5, CSandMan::GetIcon("Start")); ui.tabs->setTabIcon(6, CSandMan::GetIcon("Ampel")); ui.tabs->setTabIcon(7, CSandMan::GetIcon("Network")); ui.tabs->setTabIcon(8, CSandMan::GetIcon("Recover")); ui.tabs->setTabIcon(9, CSandMan::GetIcon("Settings")); ui.tabs->setTabIcon(10, CSandMan::GetIcon("Advanced")); ui.tabs->setTabIcon(11, CSandMan::GetIcon("Template")); ui.tabs->setTabIcon(12, CSandMan::GetIcon("Editor")); ui.tabsGeneral->setCurrentIndex(0); ui.tabsGeneral->setTabIcon(0, CSandMan::GetIcon("Box")); ui.tabsGeneral->setTabIcon(1, CSandMan::GetIcon("Folder")); ui.tabsGeneral->setTabIcon(2, CSandMan::GetIcon("Move")); ui.tabsGeneral->setTabIcon(3, CSandMan::GetIcon("NoAccess")); ui.tabsGeneral->setTabIcon(4, CSandMan::GetIcon("Run")); ui.tabsSecurity->setCurrentIndex(0); ui.tabsSecurity->setTabIcon(0, CSandMan::GetIcon("Shield7")); ui.tabsSecurity->setTabIcon(1, CSandMan::GetIcon("Fence")); ui.tabsSecurity->setTabIcon(2, CSandMan::GetIcon("Shield12")); ui.tabsForce->setCurrentIndex(0); ui.tabsForce->setTabIcon(0, CSandMan::GetIcon("Force")); ui.tabsForce->setTabIcon(1, CSandMan::GetIcon("Breakout")); ui.tabsStop->setCurrentIndex(0); ui.tabsStop->setTabIcon(0, CSandMan::GetIcon("Fail")); ui.tabsStop->setTabIcon(1, CSandMan::GetIcon("Pass")); ui.tabsInternet->setCurrentIndex(0); ui.tabsInternet->setTabIcon(0, CSandMan::GetIcon("Program")); ui.tabsInternet->setTabIcon(1, CSandMan::GetIcon("Wall")); ui.tabsInternet->setTabIcon(2, CSandMan::GetIcon("DNS")); ui.tabsInternet->setTabIcon(3, CSandMan::GetIcon("Proxy")); ui.tabsAccess->setCurrentIndex(0); ui.tabsAccess->setTabIcon(0, CSandMan::GetIcon("Folder")); ui.tabsAccess->setTabIcon(1, CSandMan::GetIcon("RegEdit")); ui.tabsAccess->setTabIcon(2, CSandMan::GetIcon("Port")); ui.tabsAccess->setTabIcon(3, CSandMan::GetIcon("Window")); ui.tabsAccess->setTabIcon(4, CSandMan::GetIcon("Objects")); //ui.tabsAccess->setTabIcon(0, CSandMan::GetIcon("Rules")); ui.tabsAccess->setTabIcon(5, CSandMan::GetIcon("Policy")); ui.tabsRecovery->setCurrentIndex(0); ui.tabsRecovery->setTabIcon(0, CSandMan::GetIcon("QuickRecovery")); ui.tabsRecovery->setTabIcon(1, CSandMan::GetIcon("ImmidiateRecovery")); ui.tabsAdvanced->setCurrentIndex(0); ui.tabsAdvanced->setTabIcon(0, CSandMan::GetIcon("Compatibility")); ui.tabsAdvanced->setTabIcon(1, CSandMan::GetIcon("Trigger")); ui.tabsAdvanced->setTabIcon(2, CSandMan::GetIcon("Anon")); ui.tabsAdvanced->setTabIcon(3, CSandMan::GetIcon("Users")); ui.tabsAdvanced->setTabIcon(4, CSandMan::GetIcon("Presets")); ui.tabsAdvanced->setTabIcon(5, CSandMan::GetIcon("SetLogging")); ui.tabsAdvanced->setTabIcon(6, CSandMan::GetIcon("Bug")); ui.tabsTemplates->setCurrentIndex(0); ui.tabsTemplates->setTabIcon(0, CSandMan::GetIcon("Compatibility")); ui.tabsTemplates->setTabIcon(1, CSandMan::GetIcon("Explore")); ui.tabsTemplates->setTabIcon(2, CSandMan::GetIcon("Accessibility")); int iViewMode = theConf->GetInt("Options/ViewMode", 1); int iOptionLayout = theConf->GetInt("Options/NewConfigLayout", 2); if (iOptionLayout == 2) iOptionLayout = iViewMode != 2 ? 1 : 0; if ((QGuiApplication::queryKeyboardModifiers() & Qt::AltModifier) != 0) iOptionLayout = !iOptionLayout; QWidget* pDummy = new QWidget(this); pDummy->setVisible(false); ui.tabs->removeTab(9); // remove unused variouse options tab // re structure the UI a bit if (iOptionLayout == 1) { // merge stop tabs QWidget* pWidget1 = new QWidget(); pWidget1->setLayout(ui.gridLayout_57); ui.gridLayout_17->addWidget(pWidget1, 1, 0); QWidget* pWidget2 = new QWidget(); pWidget2->setLayout(ui.gridLayout_61); ui.gridLayout_17->addWidget(pWidget2, 2, 0); delete ui.tabsStop; ui.gridLayout_17->setContentsMargins(0, 0, 0, 0); // move stop and restrictions to program tab ui.tabsForce->addTab(ui.tabs->widget(4), ui.tabs->tabText(4)); ui.tabsForce->setTabIcon(2, CSandMan::GetIcon("Stop")); ui.tabsForce->addTab(ui.tabs->widget(4), ui.tabs->tabText(4)); ui.tabsForce->setTabIcon(3, CSandMan::GetIcon("Start")); ui.gridLayout_19->setContentsMargins(3, 6, 3, 3); // merge recovery tabs QWidget* pWidget3 = new QWidget(); pWidget3->setLayout(ui.gridLayout_10); ui.gridLayout_24->addWidget(pWidget3, 1, 0); QWidget* pWidget4 = new QWidget(); pWidget4->setLayout(ui.gridLayout_56); ui.gridLayout_24->addWidget(pWidget4, 2, 0); delete ui.tabsRecovery; ui.gridLayout_24->setContentsMargins(0, 0, 0, 0); QWidget* pWidget = new QWidget(); QGridLayout* pLayout = new QGridLayout(pWidget); // move recovery to general //ui.tabsGeneral->insertTab(2, ui.tabs->widget(6), ui.tabs->tabText(6)); //ui.tabsGeneral->setTabIcon(2, CSandMan::GetIcon("Recover")); // collect file options on a new fils tab QTabWidget* pTabWidget = new QTabWidget(); pLayout->addWidget(pTabWidget, 0, 0); ui.tabs->insertTab(1, pWidget, tr("File Options")); ui.tabs->setTabIcon(1, CSandMan::GetIcon("Folder")); pTabWidget->addTab(ui.tabsGeneral->widget(1), ui.tabsGeneral->tabText(1)); pTabWidget->setTabIcon(0, CSandMan::GetIcon("Files")); pTabWidget->addTab(ui.tabsGeneral->widget(1), ui.tabsGeneral->tabText(1)); pTabWidget->setTabIcon(1, CSandMan::GetIcon("Move")); pTabWidget->addTab(ui.tabs->widget(7), ui.tabs->tabText(7)); pTabWidget->setTabIcon(2, CSandMan::GetIcon("Recover")); // move grouping to program tab ui.tabsForce->insertTab(0, ui.tabGroups, tr("Grouping")); ui.tabsForce->setTabIcon(0, CSandMan::GetIcon("Group")); ui.tabsForce->setCurrentIndex(0); ui.gridLayout_18->setContentsMargins(3, 6, 3, 3); } if (iViewMode != 1 && (QGuiApplication::queryKeyboardModifiers() & Qt::ControlModifier) == 0) { if (iOptionLayout == 1) { //ui.tabs->removeTab(7); // ini edit ui.tabAdvanced->setParent(pDummy); //ui.tabs->removeTab(5); // advanced //ui.tabsForce->removeTab(2); // breakout } else { //ui.tabs->removeTab(11); // ini edit ui.tabAdvanced->setParent(pDummy); //ui.tabs->removeTab(9); // advanced //ui.tabsForce->removeTab(1); // breakout } ui.tabPrivileges->setParent(pDummy); //ui.tabsSecurity->removeTab(3); // advanced security ui.tabIsolation->setParent(pDummy); //ui.tabsSecurity->removeTab(1); // security isolation //ui.tabsAccess->removeTab(5); // policy ui.treeOptions = NULL; } foreach(QTreeWidget* pTree, this->findChildren()) { if (pTree == ui.treeFolders) continue; pTree->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored); pTree->setMinimumHeight(50); } int size = 16.0; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) size *= (QApplication::desktop()->logicalDpiX() / 96.0); // todo Qt6 #endif AddIconToLabel(ui.lblAppearance, CSandMan::GetIcon("Design").pixmap(size,size)); AddIconToLabel(ui.lblBoxType, CSandMan::GetIcon("Maintenance").pixmap(size,size)); AddIconToLabel(ui.lblStructure, CSandMan::GetIcon("Structure").pixmap(size,size)); AddIconToLabel(ui.lblMigration, CSandMan::GetIcon("Move").pixmap(size,size)); AddIconToLabel(ui.lblDelete, CSandMan::GetIcon("Erase").pixmap(size,size)); AddIconToLabel(ui.lblRawDisk, CSandMan::GetIcon("Disk").pixmap(size,size)); AddIconToLabel(ui.lblSecurity, CSandMan::GetIcon("Shield5").pixmap(size,size)); AddIconToLabel(ui.lblElevation, CSandMan::GetIcon("Shield9").pixmap(size,size)); AddIconToLabel(ui.lblNetwork, CSandMan::GetIcon("Network").pixmap(size,size)); AddIconToLabel(ui.lblPrinting, CSandMan::GetIcon("Printer").pixmap(size,size)); AddIconToLabel(ui.lblOther, CSandMan::GetIcon("NoAccess").pixmap(size,size)); AddIconToLabel(ui.lblMode, CSandMan::GetIcon("Anon").pixmap(size,size)); AddIconToLabel(ui.lblPolicy, CSandMan::GetIcon("Policy").pixmap(size,size)); AddIconToLabel(ui.lblCompatibility, CSandMan::GetIcon("Compatibility").pixmap(size,size)); //AddIconToLabel(ui.lblComRpc, CSandMan::GetIcon("Objects").pixmap(size,size)); AddIconToLabel(ui.lblPrivilege, CSandMan::GetIcon("Privilege").pixmap(size,size)); AddIconToLabel(ui.lblFence, CSandMan::GetIcon("BFance").pixmap(size,size)); AddIconToLabel(ui.lblToken, CSandMan::GetIcon("Sandbox").pixmap(size,size)); AddIconToLabel(ui.lblIsolation, CSandMan::GetIcon("Fence").pixmap(size,size)); AddIconToLabel(ui.lblAccess, CSandMan::GetIcon("NoAccess").pixmap(size,size)); AddIconToLabel(ui.lblMonitor, CSandMan::GetIcon("Monitor").pixmap(size,size)); AddIconToLabel(ui.lblTracing, CSandMan::GetIcon("SetLogging").pixmap(size,size)); if (theConf->GetBool("Options/AltRowColors", false)) { foreach(QTreeWidget* pTree, this->findChildren()) pTree->setAlternatingRowColors(true); } CreateDebug(); if (m_Template) { //ui.tabGeneral->setEnabled(false); //ui.tabStart->setEnabled(false); //ui.tabInternet->setEnabled(false); //ui.tabAdvanced->setEnabled(false); //ui.tabOther->setEnabled(false); //ui.tabTemplates->setEnabled(false); // //for (int i = 0; i < ui.tabs->count(); i++) // ui.tabs->setTabEnabled(i, ui.tabs->widget(i)->isEnabled()); //ui.tabs->setCurrentIndex(ui.tabs->indexOf(ui.tabAccess)); ui.chkShowGroupTmpl->setEnabled(false); ui.chkShowForceTmpl->setEnabled(false); ui.chkShowBreakoutTmpl->setEnabled(false); ui.chkShowStopTmpl->setEnabled(false); ui.chkShowLeaderTmpl->setEnabled(false); ui.chkShowStartTmpl->setEnabled(false); ui.chkShowFilesTmpl->setEnabled(false); ui.chkShowKeysTmpl->setEnabled(false); ui.chkShowIPCTmpl->setEnabled(false); ui.chkShowWndTmpl->setEnabled(false); ui.chkShowCOMTmpl->setEnabled(false); ui.chkShowNetFwTmpl->setEnabled(false); ui.chkShowRecoveryTmpl->setEnabled(false); ui.chkShowRecIgnoreTmpl->setEnabled(false); ui.chkShowTriggersTmpl->setEnabled(false); ui.chkShowHiddenProcTmpl->setEnabled(false); ui.chkShowHostProcTmpl->setEnabled(false); ui.chkShowOptionsTmpl->setEnabled(false); //ui.chkWithTemplates->setEnabled(false); } ui.tabs->setCurrentIndex(m_Template ? ui.tabs->count()-1 : 0); if(m_Template) OnTab(); //connect(ui.chkWithTemplates, SIGNAL(clicked(bool)), this, SLOT(OnWithTemplates())); m_ConfigDirty = true; CreateGeneral(); // Groups connect(ui.btnAddGroup, SIGNAL(clicked(bool)), this, SLOT(OnAddGroup())); connect(ui.btnAddProg, SIGNAL(clicked(bool)), this, SLOT(OnAddProg())); connect(ui.btnDelProg, SIGNAL(clicked(bool)), this, SLOT(OnDelProg())); connect(ui.chkShowGroupTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowGroupTmpl())); ui.treeGroups->setItemDelegateForColumn(0, new ProgramsDelegate(this, ui.treeGroups, -1, this)); connect(ui.treeGroups, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnGroupsChanged(QTreeWidgetItem *, int))); // // Force connect(ui.btnForceProg, SIGNAL(clicked(bool)), this, SLOT(OnForceProg())); QMenu* pFileBtnMenu = new QMenu(ui.btnForceProg); pFileBtnMenu->addAction(tr("Browse for File"), this, SLOT(OnForceBrowse())); ui.btnForceProg->setPopupMode(QToolButton::MenuButtonPopup); ui.btnForceProg->setMenu(pFileBtnMenu); connect(ui.btnForceDir, SIGNAL(clicked(bool)), this, SLOT(OnForceDir())); connect(ui.btnDelForce, SIGNAL(clicked(bool)), this, SLOT(OnDelForce())); connect(ui.chkShowForceTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowForceTmpl())); //ui.treeForced->setEditTriggers(QAbstractItemView::DoubleClicked); ui.treeForced->setItemDelegateForColumn(0, new NoEditDelegate(this)); ui.treeForced->setItemDelegateForColumn(1, new ProgramsDelegate(this, ui.treeForced, -1, this)); connect(ui.treeForced, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnForcedChanged(QTreeWidgetItem *, int))); connect(ui.btnBreakoutProg, SIGNAL(clicked(bool)), this, SLOT(OnBreakoutProg())); QMenu* pFileBtnMenu2 = new QMenu(ui.btnBreakoutProg); pFileBtnMenu2->addAction(tr("Browse for File"), this, SLOT(OnBreakoutBrowse())); ui.btnBreakoutProg->setPopupMode(QToolButton::MenuButtonPopup); ui.btnBreakoutProg->setMenu(pFileBtnMenu2); connect(ui.btnBreakoutDir, SIGNAL(clicked(bool)), this, SLOT(OnBreakoutDir())); connect(ui.btnDelBreakout, SIGNAL(clicked(bool)), this, SLOT(OnDelBreakout())); connect(ui.chkShowBreakoutTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowBreakoutTmpl())); //ui.treeBreakout->setEditTriggers(QAbstractItemView::DoubleClicked); ui.treeBreakout->setItemDelegateForColumn(0, new NoEditDelegate(this)); ui.treeBreakout->setItemDelegateForColumn(1, new ProgramsDelegate(this, ui.treeBreakout, -1, this)); connect(ui.treeBreakout, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnForcedChanged(QTreeWidgetItem *, int))); // // Stop connect(ui.btnAddLingering, SIGNAL(clicked(bool)), this, SLOT(OnAddLingering())); connect(ui.btnDelStopProg, SIGNAL(clicked(bool)), this, SLOT(OnDelStopProg())); connect(ui.chkShowStopTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowStopTmpl())); ui.treeStop->setItemDelegateForColumn(0, new ProgramsDelegate(this, ui.treeStop, -1, this)); connect(ui.treeStop, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnStopChanged(QTreeWidgetItem *, int))); connect(ui.btnAddLeader, SIGNAL(clicked(bool)), this, SLOT(OnAddLeader())); connect(ui.btnDelLeader, SIGNAL(clicked(bool)), this, SLOT(OnDelLeader())); connect(ui.chkShowLeaderTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowLeaderTmpl())); ui.treeLeader->setItemDelegateForColumn(0, new ProgramsDelegate(this, ui.treeLeader, -1, this)); connect(ui.treeLeader, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnStopChanged(QTreeWidgetItem *, int))); // // Start connect(ui.radStartAll, SIGNAL(clicked(bool)), this, SLOT(OnRestrictStart())); connect(ui.radStartExcept, SIGNAL(clicked(bool)), this, SLOT(OnRestrictStart())); connect(ui.radStartSelected, SIGNAL(clicked(bool)), this, SLOT(OnRestrictStart())); connect(ui.btnAddStartProg, SIGNAL(clicked(bool)), this, SLOT(OnAddStartProg())); connect(ui.btnDelStartProg, SIGNAL(clicked(bool)), this, SLOT(OnDelStartProg())); //connect(ui.chkShowStartTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowStartTmpl())); ui.chkShowStartTmpl->setVisible(false); // todo connect(ui.chkStartBlockMsg, SIGNAL(clicked(bool)), this, SLOT(OnStartChanged())); ui.treeStart->setItemDelegateForColumn(0, new ProgramsDelegate(this, ui.treeStart, -1, this)); connect(ui.treeStart, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnStartChanged(QTreeWidgetItem *, int))); // CreateNetwork(); CreateAccess(); // Recovery connect(ui.chkAutoRecovery, SIGNAL(clicked(bool)), this, SLOT(OnRecoveryChanged())); connect(ui.btnAddRecovery, SIGNAL(clicked(bool)), this, SLOT(OnAddRecFolder())); connect(ui.btnDelRecovery, SIGNAL(clicked(bool)), this, SLOT(OnDelRecEntry())); connect(ui.btnAddRecIgnore, SIGNAL(clicked(bool)), this, SLOT(OnAddRecIgnore())); connect(ui.btnAddRecIgnoreExt, SIGNAL(clicked(bool)), this, SLOT(OnAddRecIgnoreExt())); connect(ui.btnDelRecIgnore, SIGNAL(clicked(bool)), this, SLOT(OnDelRecIgnoreEntry())); connect(ui.chkShowRecoveryTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowRecoveryTmpl())); connect(ui.chkShowRecIgnoreTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowRecIgnoreTmpl())); // CreateAdvanced(); // Templates connect(ui.cmbCategories, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFilterTemplates())); connect(ui.txtTemplates, SIGNAL(textChanged(const QString&)), this, SLOT(OnFilterTemplates())); //connect(ui.treeTemplates, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(OnTemplateClicked(QTreeWidgetItem*, int))); connect(ui.treeTemplates, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnTemplateClicked(QTreeWidgetItem*, int))); connect(ui.treeTemplates, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnTemplateDoubleClicked(QTreeWidgetItem*, int))); connect(ui.btnAddTemplate, SIGNAL(clicked(bool)), this, SLOT(OnAddTemplates())); connect(ui.btnDelTemplate, SIGNAL(clicked(bool)), this, SLOT(OnDelTemplates())); connect(ui.chkScreenReaders, SIGNAL(clicked(bool)), this, SLOT(OnScreenReaders())); // connect(ui.tabs, SIGNAL(currentChanged(int)), this, SLOT(OnTab())); // edit connect(ui.btnEditIni, SIGNAL(clicked(bool)), this, SLOT(OnEditIni())); connect(ui.btnSaveIni, SIGNAL(clicked(bool)), this, SLOT(OnSaveIni())); connect(ui.btnCancelEdit, SIGNAL(clicked(bool)), this, SLOT(OnCancelEdit())); connect(ui.txtIniSection, SIGNAL(textChanged()), this, SLOT(OnOptChanged())); // connect(ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked(bool)), this, SLOT(ok())); connect(ui.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked(bool)), this, SLOT(apply())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(close())); if (ReadOnly) { ui.btnEditIni->setEnabled(false); ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); } if (theAPI->IsRunningAsAdmin()) { ui.chkDropRights->setEnabled(false); ui.chkFakeElevation->setEnabled(false); } else ui.lblAdmin->setVisible(false); LoadConfig(); m_pCurrentTab = ui.tabGeneral; UpdateCurrentTab(); ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); ui.treeCopy->viewport()->installEventFilter(this); ui.treeINet->viewport()->installEventFilter(this); ui.treeNetFw->viewport()->installEventFilter(this); ui.treeFiles->viewport()->installEventFilter(this); ui.treeKeys->viewport()->installEventFilter(this); ui.treeIPC->viewport()->installEventFilter(this); ui.treeWnd->viewport()->installEventFilter(this); ui.treeCOM->viewport()->installEventFilter(this); //ui.treeAccess->viewport()->installEventFilter(this); if(ui.treeOptions) ui.treeOptions->viewport()->installEventFilter(this); this->installEventFilter(this); // prevent enter from closing the dialog restoreGeometry(theConf->GetBlob("OptionsWindow/Window_Geometry")); foreach(QTreeWidget * pTree, this->findChildren()) { QByteArray Columns = theConf->GetBlob("OptionsWindow/" + pTree->objectName() + "_Columns"); if (!Columns.isEmpty()) pTree->header()->restoreState(Columns); } if (theAPI->GetGlobalSettings()->GetBool("EditAdminOnly", false) && !IsAdminUser()) { for (int I = 0; I < ui.tabs->count(); I++) { QGridLayout* pGrid = qobject_cast(ui.tabs->widget(I)->layout()); QTabWidget* pSubTabs = pGrid ? qobject_cast(pGrid->itemAt(0)->widget()) : NULL; if (!pSubTabs) { ui.tabs->widget(I)->setEnabled(false); } else { for (int J = 0; J < pSubTabs->count(); J++) { pSubTabs->widget(J)->setEnabled(false); } } } } int iOptionTree = theConf->GetInt("Options/OptionTree", 2); if (iOptionTree == 2) iOptionTree = iViewMode == 2 ? 1 : 0; if (iOptionTree) OnSetTree(); else { //this->setMinimumHeight(490); this->setMinimumHeight(390); QWidget* pSearch = AddConfigSearch(ui.tabs); ui.horizontalLayout->insertWidget(0, pSearch); QTimer::singleShot(0, [this]() { m_pSearch->setMaximumWidth(m_pTabs->tabBar()->width()); }); QAction* pSetTree = new QAction(); connect(pSetTree, SIGNAL(triggered()), this, SLOT(OnSetTree())); pSetTree->setShortcut(QKeySequence("Ctrl+Alt+T")); pSetTree->setShortcutContext(Qt::WidgetWithChildrenShortcut); this->addAction(pSetTree); } m_pSearch->setPlaceholderText(tr("Search for options")); } void COptionsWindow::OnSetTree() { if (!ui.tabs) return; QWidget* pAltView = ConvertToTree(ui.tabs); ui.verticalLayout->replaceWidget(ui.tabs, pAltView); ui.tabs->deleteLater(); ui.tabs = NULL; } void COptionsWindow::OnOptChanged() { if (m_HoldChange) return; ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); } COptionsWindow::~COptionsWindow() { theConf->SetBlob("OptionsWindow/Window_Geometry",saveGeometry()); foreach(QTreeWidget * pTree, this->findChildren()) theConf->SetBlob("OptionsWindow/" + pTree->objectName() + "_Columns", pTree->header()->saveState()); } void COptionsWindow::closeEvent(QCloseEvent *e) { emit Closed(); this->deleteLater(); } bool COptionsWindow::eventFilter(QObject *source, QEvent *event) { if (event->type() == QEvent::KeyPress && ((QKeyEvent*)event)->key() == Qt::Key_Escape && ((QKeyEvent*)event)->modifiers() == Qt::NoModifier && (source == ui.treeCopy->viewport() || source == ui.treeINet->viewport() || source == ui.treeNetFw->viewport() // || source == ui.treeAccess->viewport() || source == ui.treeFiles->viewport() || source == ui.treeKeys->viewport() || source == ui.treeIPC->viewport() || source == ui.treeWnd->viewport() || source == ui.treeCOM->viewport() || (ui.treeOptions && source == ui.treeOptions->viewport()))) { CloseCopyEdit(false); CloseINetEdit(false); CloseNetFwEdit(false); CloseAccessEdit(false); CloseOptionEdit(false); return true; // cancel event } if (event->type() == QEvent::KeyPress && (((QKeyEvent*)event)->key() == Qt::Key_Enter || ((QKeyEvent*)event)->key() == Qt::Key_Return) && (((QKeyEvent*)event)->modifiers() == Qt::NoModifier || ((QKeyEvent*)event)->modifiers() == Qt::KeypadModifier)) { CloseCopyEdit(true); CloseINetEdit(true); CloseNetFwEdit(true); CloseAccessEdit(true); CloseOptionEdit(true); return true; // cancel event } if (source == ui.treeCopy->viewport() && event->type() == QEvent::MouseButtonPress) { CloseCopyEdit(); } if (source == ui.treeINet->viewport() && event->type() == QEvent::MouseButtonPress) { CloseINetEdit(); } if (source == ui.treeNetFw->viewport() && event->type() == QEvent::MouseButtonPress) { CloseNetFwEdit(); } if (//source == ui.treeAccess->viewport() (source == ui.treeFiles->viewport() || source == ui.treeKeys->viewport() || source == ui.treeIPC->viewport() || source == ui.treeWnd->viewport() || source == ui.treeCOM->viewport()) && event->type() == QEvent::MouseButtonPress) { CloseAccessEdit(); } if ((ui.treeOptions && source == ui.treeOptions->viewport()) && event->type() == QEvent::MouseButtonPress) { CloseOptionEdit(); } return QDialog::eventFilter(source, event); } //void COptionsWindow::OnWithTemplates() //{ // m_Template = ui.chkWithTemplates->isChecked(); // ui.buttonBox->setEnabled(!m_Template); // LoadConfig(); //} void COptionsWindow::ReadAdvancedCheck(const QString& Name, QCheckBox* pCheck, const QString& Value) { QString Data = m_pBox->GetText(Name); if (Data == Value) pCheck->setCheckState(Qt::Checked); else if (Data.isEmpty()) pCheck->setCheckState(Qt::Unchecked); else pCheck->setCheckState(Qt::PartiallyChecked); } int COptionsWindow__GetBoolConfig(const QString& Value) { QString temp = Value.left(1).toLower(); if (temp == "y") return 1; else if (temp == "n") return 0; return -1; } void COptionsWindow::ReadGlobalCheck(QCheckBox* pCheck, const QString& Setting, bool bDefault) { int iLocal = COptionsWindow__GetBoolConfig(m_pBox->GetText(Setting)); int iTemplate = COptionsWindow__GetBoolConfig(m_pBox->GetText(Setting, QString(), false, true, true)); int iGlobal = COptionsWindow__GetBoolConfig(m_pBox->GetText(Setting, QString(), true)); bool bTemplate = m_pBox->GetBool(Setting, bDefault, true, true); if (iLocal != -1) pCheck->setChecked(iLocal == 1); else pCheck->setChecked(iTemplate != -1 ? iTemplate == 1 : iGlobal != -1 ? iGlobal == 1 : bDefault); QStringList Info; Info.append(tr("Box: %1").arg(iLocal == 1 ? "y" : "n")); if (iTemplate != -1) Info.append(tr("Template: %1").arg(iTemplate == 1 ? "y" : "n")); if (iGlobal != -1) Info.append(tr("Global: %1").arg(iGlobal == 1 ? "y" : "n")); Info.append(tr("Default: %1").arg(bDefault ? "y" : "n")); pCheck->setToolTip(Info.join("\r\n")); } void COptionsWindow::WriteGlobalCheck(QCheckBox* pCheck, const QString& Setting, bool bDefault) { bool bLocal = pCheck->isChecked(); bool bPreset = m_pBox->GetBool(Setting, bDefault, true, true); SB_STATUS Status; if(bPreset == bLocal) Status = m_pBox->DelValue(Setting); else Status = m_pBox->SetText(Setting, bLocal ? "y" : "n"); if (!Status) throw Status; } void COptionsWindow::LoadConfig() { m_ConfigDirty = false; m_HoldChange = true; LoadGeneral(); LoadGroups(); LoadForced(); LoadStop(); LoadStart(); LoadINetAccess(); LoadNetFwRules(); LoadAccessList(); LoadRecoveryList(); LoadAdvanced(); LoadDebug(); LoadTemplates(); UpdateBoxType(); m_HoldChange = false; } void COptionsWindow::WriteAdvancedCheck(QCheckBox* pCheck, const QString& Name, const QString& Value) { SB_STATUS Status; if (pCheck->checkState() == Qt::Checked) Status = m_pBox->SetText(Name, Value); else if (pCheck->checkState() == Qt::Unchecked) Status = m_pBox->DelValue(Name); if (!Status) throw Status; } void COptionsWindow::WriteAdvancedCheck(QCheckBox* pCheck, const QString& Name, const QString& OnValue, const QString& OffValue) { //if (pCheck->checkState() == Qt::PartiallyChecked) // return; if (!pCheck->isEnabled()) return; QString StrValue; if (pCheck->checkState() == Qt::Checked) { if (!OnValue.isEmpty()) StrValue = OnValue; } else if (pCheck->checkState() == Qt::Unchecked) { if (!OffValue.isEmpty()) StrValue = OffValue; } QStringList Values = m_pBox->GetTextList(Name, false); foreach(const QString & CurValue, Values) { if (CurValue.contains(",")) continue; if (!StrValue.isEmpty() && CurValue == StrValue) StrValue.clear(); else m_pBox->DelValue(Name, CurValue); } if (!StrValue.isEmpty()) { SB_STATUS Status = m_pBox->InsertText(Name, StrValue); if (!Status) throw Status; } } void COptionsWindow::WriteText(const QString& Name, const QString& Value) { SB_STATUS Status = m_pBox->SetText(Name, Value); if (!Status) throw Status; } void COptionsWindow::WriteTextList(const QString& Setting, const QStringList& List) { SB_STATUS Status = m_pBox->UpdateTextList(Setting, List, m_Template); if (!Status) throw Status; } void COptionsWindow::SaveConfig() { bool UpdatePaths = false; m_pBox->SetRefreshOnChange(false); try { if (m_GeneralChanged) SaveGeneral(); if (m_GroupsChanged) SaveGroups(); if (m_ForcedChanged) SaveForced(); if (m_StopChanged) SaveStop(); if (m_StartChanged) SaveStart(); if (m_INetBlockChanged) SaveINetAccess(); if (m_NetFwRulesChanged) SaveNetFwRules(); if (m_AccessChanged) { SaveAccessList(); UpdatePaths = true; } if (m_RecoveryChanged) SaveRecoveryList(); if (m_AdvancedChanged) SaveAdvanced(); SaveDebug(); if (m_TemplatesChanged) SaveTemplates(); if (m_FoldersChanged) SaveFolders(); } catch (SB_STATUS Status) { theGUI->CheckResults(QList() << Status); } m_pBox->SetRefreshOnChange(true); m_pBox->GetAPI()->CommitIniChanges(); if (UpdatePaths) TriggerPathReload(); } void COptionsWindow::apply() { if (m_pBox->GetText("Enabled").isEmpty() && !(m_Template && m_pBox->GetName().mid(9, 6).compare("Local_", Qt::CaseInsensitive) == 0)) { QMessageBox::critical(this, "Sandboxie-Plus", tr("This sandbox has been deleted hence configuration can not be saved.")); return; } CloseINetEdit(); CloseNetFwEdit(); CloseAccessEdit(); CloseOptionEdit(); if (!ui.btnEditIni->isEnabled()) SaveIniSection(); else SaveConfig(); LoadConfig(); UpdateCurrentTab(); //emit OptionsChanged(); ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); } void COptionsWindow::ok() { apply(); this->close(); } void COptionsWindow::reject() { if (m_GeneralChanged || m_GroupsChanged || m_ForcedChanged || m_StopChanged || m_StartChanged // || m_RestrictionChanged || m_INetBlockChanged || m_NetFwRulesChanged || m_AccessChanged || m_TemplatesChanged || m_FoldersChanged || m_RecoveryChanged || m_AdvancedChanged) { if (QMessageBox("Sandboxie-Plus", tr("Some changes haven't been saved yet, do you really want to close this options window?") , QMessageBox::Warning, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) return; } this->close(); } void COptionsWindow::SetProgramItem(QString Program, QTreeWidgetItem* pItem, int Column, const QString& Sufix) { pItem->setData(Column, Qt::UserRole, Program); if (Program.left(1) == "<") Program = tr("Group: %1").arg(Program.mid(1, Program.length() - 2)); else if (Program.isEmpty() || Program == "*") Program = tr("All Programs"); else m_Programs.insert(Program); pItem->setText(Column, Program + Sufix); } QString COptionsWindow::SelectProgram(bool bOrGroup) { CComboInputDialog progDialog(this); progDialog.setText(tr("Enter program:")); progDialog.setEditable(true); if (bOrGroup) { foreach(const QString Group, GetCurrentGroups()){ QString GroupName = Group.mid(1, Group.length() - 2); progDialog.addItem(tr("Group: %1").arg(GroupName), Group); } } foreach(const QString & Name, m_Programs) progDialog.addItem(Name, Name); progDialog.setValue(""); if (!progDialog.exec()) return QString(); // Note: pressing enter adds the value to the combo list ! QString Program = progDialog.value(); int Index = progDialog.findValue(Program); if (Index != -1 && progDialog.data().isValid()) Program = progDialog.data().toString(); return Program; } void COptionsWindow::OnTab(QWidget* pTab) { m_pCurrentTab = pTab; if (pTab == ui.tabEdit) { LoadIniSection(); ui.txtIniSection->setReadOnly(true); } else { if (m_ConfigDirty) LoadConfig(); UpdateCurrentTab(); } } void COptionsWindow::UpdateCurrentTab() { if (m_pCurrentTab == ui.tabRestrictions || m_pCurrentTab == ui.tabOptions || m_pCurrentTab == ui.tabGeneral) { ui.chkVmRead->setChecked(GetAccessEntry(eIPC, "", eReadOnly, "$:*") != NULL); } else if (m_pCurrentTab ==ui.tabPrivileges || m_pCurrentTab == ui.tabSecurity) { if (GetAccessEntry(eWnd, "", eOpen, "*") != NULL) { ui.chkAddToJob->setEnabled(false); ui.chkAddToJob->setChecked(false); } else { ui.chkAddToJob->setEnabled(true); ui.chkAddToJob->setChecked(!m_pBox->GetBool("NoAddProcessToJob", false)); } } else if (m_pCurrentTab == ui.tabStart || m_pCurrentTab == ui.tabForce) { if (GetAccessEntry(eIPC, "!", eClosed, "*") != NULL) ui.radStartSelected->setChecked(true); else if (GetAccessEntry(eIPC, "", eClosed, "*") != NULL) ui.radStartExcept->setChecked(true); else ui.radStartAll->setChecked(true); ui.treeStart->clear(); CopyGroupToList("", ui.treeStart); CopyGroupToList("", ui.treeStart, true); OnRestrictStart(); } else if (m_pCurrentTab == ui.tabInternet || m_pCurrentTab == ui.tabINet) { CheckINetBlock(); LoadBlockINet(); } else if (m_pCurrentTab == ui.tabCOM) { CheckOpenCOM(); } else if (m_pCurrentTab == ui.tabWnd) { if (GetAccessEntry(eWnd, "", eOpen, "*") != NULL) { ui.chkNoWindowRename->setEnabled(false); ui.chkNoWindowRename->setChecked(true); } else { ui.chkNoWindowRename->setEnabled(true); ui.chkNoWindowRename->setChecked(GetAccessEntry(eWnd, "", eOpen, "#") != NULL); } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Raw section ini Editor // void COptionsWindow::SetIniEdit(bool bEnable) { if (m_pTree) { m_pTree->setEnabled(!bEnable); } else { for (int i = 0; i < ui.tabs->count() - 1; i++) { bool Enabled = ui.tabs->widget(i)->isEnabled(); ui.tabs->setTabEnabled(i, !bEnable && Enabled); ui.tabs->widget(i)->setEnabled(Enabled); } } ui.btnSaveIni->setEnabled(bEnable); ui.btnCancelEdit->setEnabled(bEnable); ui.txtIniSection->setReadOnly(!bEnable); ui.btnEditIni->setEnabled(!bEnable); } void COptionsWindow::OnEditIni() { SetIniEdit(true); } void COptionsWindow::OnSaveIni() { SaveIniSection(); SetIniEdit(false); } void COptionsWindow::OnCancelEdit() { SetIniEdit(false); } void COptionsWindow::LoadIniSection() { QString Section; // Note: the service only caches sandboxie.ini not templates.ini, hence for global templates we need to load the section through the driver if (m_Template && m_pBox->GetName().mid(9, 6).compare("Local_", Qt::CaseInsensitive) != 0) { m_Settings = m_pBox->GetIniSection(NULL, m_Template); for (QList>::const_iterator I = m_Settings.begin(); I != m_Settings.end(); ++I) Section += I->first + "=" + I->second + "\n"; } else Section = m_pBox->GetAPI()->SbieIniGetEx(m_pBox->GetName(), ""); m_HoldChange = true; ui.txtIniSection->setPlainText(Section); m_HoldChange = false; } void COptionsWindow::SaveIniSection() { m_ConfigDirty = true; /*m_pBox->SetRefreshOnChange(false); // Note: an incremental update would be more elegant but it would change the entry order in the ini, // hence it's better for the user to fully rebuild the section each time. // for (QList>::const_iterator I = m_Settings.begin(); I != m_Settings.end(); ++I) m_pBox->DelValue(I->first, I->second); //QList> NewSettings; //QList> OldSettings = m_Settings; QStringList Section = SplitStr(ui.txtIniSection->toPlainText(), "\n"); foreach(const QString& Line, Section) { if (Line.isEmpty()) return; StrPair Settings = Split2(Line, "="); //if (!OldSettings.removeOne(Settings)) // NewSettings.append(Settings); m_pBox->InsertText(Settings.first, Settings.second); } //for (QList>::const_iterator I = OldSettings.begin(); I != OldSettings.end(); ++I) // m_pBox->DelValue(I->first, I->second); // //for (QList>::const_iterator I = NewSettings.begin(); I != NewSettings.end(); ++I) // m_pBox->InsertText(I->first, I->second); m_pBox->SetRefreshOnChange(true); m_pBox->GetAPI()->CommitIniChanges();*/ m_pBox->GetAPI()->SbieIniSet(m_pBox->GetName(), "", ui.txtIniSection->toPlainText()); LoadIniSection(); } #include "OptionsAccess.cpp" #include "OptionsAdvanced.cpp" #include "OptionsForce.cpp" #include "OptionsGeneral.cpp" #include "OptionsGrouping.cpp" #include "OptionsNetwork.cpp" #include "OptionsRecovery.cpp" #include "OptionsStart.cpp" #include "OptionsStop.cpp" #include "OptionsTemplates.cpp" #include void COptionsWindow::TriggerPathReload() { // // this message makes all boxes reload their path presets // DWORD bsm_app = BSM_APPLICATIONS; BroadcastSystemMessage(BSF_POSTMESSAGE, &bsm_app, WM_DEVICECHANGE, 'sb', 0); }