diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e03892..d6ec833f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - compatibility templates can now be viewed from the settings window [#1891](https://github.com/sandboxie-plus/Sandboxie/issues/1891) - the refresh command is now bound to F5 [#1885](https://github.com/sandboxie-plus/Sandboxie/issues/1885) +- added option to permanently disable immidate recovery for any given box when it opens [#1478](https://github.com/sandboxie-plus/Sandboxie/issues/1478) +- double click on the path column now opens the box root in explorer [#1924](https://github.com/sandboxie-plus/Sandboxie/issues/1924) ### Changed - improved implementation of the PreferExternalManifest option -- win32k hooks are now by default only used for edge and chromium as thay cause issues with other software [#1902](https://github.com/sandboxie-plus/Sandboxie/issues/1902) +- win32k hooks are now by default only used for edge and chromium as thay cause issues with other software [#1902](https://github.com/sandboxie-plus/Sandboxie/issues/1902) [#1912](https://github.com/sandboxie-plus/Sandboxie/issues/1912) [#1897](https://github.com/sandboxie-plus/Sandboxie/issues/1897) ### Fixed - fixed Edge issue with Windows 11 after KB5014019 @@ -27,7 +29,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - fixed crash issue with WatchBoxSize=true [#1885](https://github.com/sandboxie-plus/Sandboxie/issues/1885) - fixed issue with recovery folder paths [#1840](https://github.com/sandboxie-plus/Sandboxie/issues/1840) - fixed issues with sbie desktop and wndStation affecting acrobat reader [#1863](https://github.com/sandboxie-plus/Sandboxie/issues/1863) - +- fixed issues with box grouping [#1921](https://github.com/sandboxie-plus/Sandboxie/issues/1921) [#1920](https://github.com/sandboxie-plus/Sandboxie/issues/1920) +- fixed issues when changing language [#1914](https://github.com/sandboxie-plus/Sandboxie/issues/1914) diff --git a/SandboxiePlus/SandMan/Models/SbieModel.cpp b/SandboxiePlus/SandMan/Models/SbieModel.cpp index 76a33317..59c1aa43 100644 --- a/SandboxiePlus/SandMan/Models/SbieModel.cpp +++ b/SandboxiePlus/SandMan/Models/SbieModel.cpp @@ -530,9 +530,9 @@ bool CSbieModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int foreach(const QString & Name, Boxes) { if(CSbieModel__HasGroupMark(Name)) - MoveGroup(CSbieModel__RemoveGroupMark(Name), To); + MoveGroup(CSbieModel__RemoveGroupMark(Name), To, row); else - MoveBox(Name, To); + MoveBox(Name, To, row); } return true; diff --git a/SandboxiePlus/SandMan/Models/SbieModel.h b/SandboxiePlus/SandMan/Models/SbieModel.h index d6884379..86ee5706 100644 --- a/SandboxiePlus/SandMan/Models/SbieModel.h +++ b/SandboxiePlus/SandMan/Models/SbieModel.h @@ -54,8 +54,8 @@ public: }; signals: - void MoveBox(const QString& Name, const QString& To); - void MoveGroup(const QString& Name, const QString& To); + void MoveBox(const QString& Name, const QString& To, int row); + void MoveGroup(const QString& Name, const QString& To, int row); protected: bool Sync(const CSandBoxPtr& pBox, const QList& Path, const QMap& ProcessList, QMap, QList >& New, QHash& Old, QList& Added); diff --git a/SandboxiePlus/SandMan/Views/SbieView.cpp b/SandboxiePlus/SandMan/Views/SbieView.cpp index 517f6ca6..07bf3789 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.cpp +++ b/SandboxiePlus/SandMan/Views/SbieView.cpp @@ -64,8 +64,8 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent) //connect(theGUI, SIGNAL(ReloadPanels()), m_pSbieModel, SLOT(Clear())); - connect(m_pSbieModel, SIGNAL(MoveBox(const QString&, const QString&)), this, SLOT(OnMoveItem(const QString&, const QString&))); - connect(m_pSbieModel, SIGNAL(MoveGroup(const QString&, const QString&)), this, SLOT(OnMoveItem(const QString&, const QString&))); + connect(m_pSbieModel, SIGNAL(MoveBox(const QString&, const QString&, int)), this, SLOT(OnMoveItem(const QString&, const QString&, int))); + connect(m_pSbieModel, SIGNAL(MoveGroup(const QString&, const QString&, int)), this, SLOT(OnMoveItem(const QString&, const QString&, int))); //m_pSbieTree->setStyleSheet("QTreeView::item:focus {selection-background-color: yellow;}"); //m_pSbieTree->setFocusPolicy(Qt::NoFocus); @@ -209,11 +209,8 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent) } else m_pSbieTree->restoreState(Columns); - if (theConf->GetBool("MainWindow/BoxTree_UseOrder", false)) { - m_pSortProxy->sort(0, Qt::AscendingOrder); - m_pSortProxy->setSortRole(Qt::InitialSortOrderRole); - m_pSbieTree->header()->setSortIndicatorShown(false); - } + if (theConf->GetBool("MainWindow/BoxTree_UseOrder", false)) + SetCustomOrder(); //m_pMenu = new QMenu(); AddPanelItemsToMenu(); @@ -233,6 +230,54 @@ void CSbieView::Clear() m_pSbieModel->Clear(); } + + +int CSbieView__ParseGroup(const QString& Grouping, QMap& m_Groups, const QString& Parent = "", int Index = 0) +{ + QRegExp RegExp("[,()]", Qt::CaseInsensitive, QRegExp::RegExp); + for (; ; ) + { + int pos = Grouping.indexOf(RegExp, Index); + QString Name; + if (pos == -1) { + Name = Grouping.mid(Index); + Index = Grouping.length(); + } + else { + Name = Grouping.mid(Index, pos - Index); + Index = pos + 1; + } + if (!Name.isEmpty()) + m_Groups[Parent].append(Name); + if (pos == -1) + break; + if (Grouping.at(pos) == "(") + { + m_Groups[Name] = QStringList(); + Index = CSbieView__ParseGroup(Grouping, m_Groups, Name, Index); + } + else if (Grouping.at(pos) == ")") + break; + } + return Index; +} + +QString CSbieView__SerializeGroup(QMap& m_Groups, const QString& Parent = "", QSet Test = QSet()) +{ + QStringList Grouping; + foreach(const QString& Name, m_Groups[Parent]) + { + if (Test.contains(Name)) + continue; // recursion, skil + Test.insert(Name); + if (m_Groups.contains(Name)) + Grouping.append(Name + "(" + CSbieView__SerializeGroup(m_Groups, Name, Test) + ")"); + else + Grouping.append(Name); + } + return Grouping.join(","); +} + void CSbieView::Refresh() { QList Added = m_pSbieModel->Sync(theAPI->GetAllBoxes(), m_Groups, theGUI->IsShowHidden()); @@ -260,6 +305,21 @@ void CSbieView::Refresh() } }); } + + // add new boxes to the default group + + foreach(const QStringList &list, m_Groups) { + foreach(const QString &str, list) + Added.removeAll(str); + } + + if (!Added.isEmpty()) { + foreach(const QVariant &ID, Added) + m_Groups[""].append(ID.toString()); + + QString Grouping = CSbieView__SerializeGroup(m_Groups); + theAPI->GetUserSettings()->SetText("BoxDisplayOrder", Grouping); + } } void CSbieView::OnToolTipCallback(const QVariant& ID, QString& ToolTip) @@ -300,10 +360,8 @@ void CSbieView::OnCustomSortByColumn(int column) theConf->SetValue("MainWindow/BoxTree_UseOrder", false); m_pSbieTree->header()->setSortIndicatorShown(true); } else if (order == Qt::DescendingOrder) { - m_pSortProxy->sort(0, Qt::AscendingOrder); - m_pSortProxy->setSortRole(Qt::InitialSortOrderRole); + SetCustomOrder(); theConf->SetValue("MainWindow/BoxTree_UseOrder", true); - m_pSbieTree->header()->setSortIndicatorShown(false); } } else { @@ -464,36 +522,6 @@ void CSbieView::OnMenu(const QPoint& Point) CPanelView::OnMenu(Point); } -int CSbieView__ParseGroup(const QString& Grouping, QMap& m_Groups, const QString& Parent = "", int Index = 0) -{ - QRegExp RegExp("[,()]", Qt::CaseInsensitive, QRegExp::RegExp); - for (; ; ) - { - int pos = Grouping.indexOf(RegExp, Index); - QString Name; - if (pos == -1) { - Name = Grouping.mid(Index); - Index = Grouping.length(); - } - else { - Name = Grouping.mid(Index, pos - Index); - Index = pos + 1; - } - if (!Name.isEmpty()) - m_Groups[Parent].append(Name); - if (pos == -1) - break; - if (Grouping.at(pos) == "(") - { - m_Groups[Name] = QStringList(); - Index = CSbieView__ParseGroup(Grouping, m_Groups, Name, Index); - } - else if (Grouping.at(pos) == ")") - break; - } - return Index; -} - void CSbieView::UpdateGroupMenu() { // update move to menu @@ -533,22 +561,6 @@ bool CSbieView::RenameItem(const QString OldName, const QString NewName) return true; } -QString CSbieView__SerializeGroup(QMap& m_Groups, const QString& Parent = "", QSet Test = QSet()) -{ - QStringList Grouping; - foreach(const QString& Name, m_Groups[Parent]) - { - if (Test.contains(Name)) - continue; // recursion, skil - Test.insert(Name); - if (m_Groups.contains(Name)) - Grouping.append(Name + "(" + CSbieView__SerializeGroup(m_Groups, Name, Test) + ")"); - else - Grouping.append(Name); - } - return Grouping.join(","); -} - QString CSbieView::FindParent(const QString& Name) { for (auto I = m_Groups.begin(); I != m_Groups.end(); ++I) @@ -653,10 +665,8 @@ void CSbieView::OnGroupAction(QAction* Action) else if (Action == m_pMenuMoveUp /*|| Action == m_pMenuMoveBy*/ || Action == m_pMenuMoveDown) { if (!theConf->GetBool("MainWindow/BoxTree_UseOrder", false)) { - m_pSortProxy->sort(0, Qt::AscendingOrder); - m_pSortProxy->setSortRole(Qt::InitialSortOrderRole); + SetCustomOrder(); theConf->SetValue("MainWindow/BoxTree_UseOrder", true); - m_pSbieTree->header()->setSortIndicatorShown(false); } int Offset = 0; @@ -716,14 +726,21 @@ void CSbieView::OnGroupAction(QAction* Action) SaveUserConfig(); } -void CSbieView::MoveItem(const QString& Name, const QString& To) +void CSbieView::SetCustomOrder() +{ + m_pSortProxy->sort(0, Qt::AscendingOrder); + m_pSortProxy->setSortRole(Qt::InitialSortOrderRole); + m_pSbieTree->header()->setSortIndicatorShown(false); +} + +void CSbieView::MoveItem(const QString& Name, const QString& To, int pos) { // remove from old for (auto I = m_Groups.begin(); I != m_Groups.end(); ++I) I.value().removeAll(Name); // add to new - m_Groups[To].append(Name); + m_Groups[To].insert(pos, Name); } QString CSbieView::AddNewBox() @@ -1264,6 +1281,12 @@ void CSbieView::OnDoubleClicked(const QModelIndex& index) if (pBox.isNull()) return; + if (index.column() == CSbieModel::ePath) + OnSandBoxAction(m_pMenuExplore); + + if (index.column() != CSbieModel::eName) + return; + if (!pBox->IsEnabled()) { if (QMessageBox("Sandboxie-Plus", tr("This sandbox is disabled, do you want to enable it?"), QMessageBox::Question, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) @@ -1467,9 +1490,17 @@ void CSbieView::SaveUserConfig() theAPI->GetUserSettings()->SetText("BoxCollapsedView", m_Collapsed.toList().join(",")); } -void CSbieView::OnMoveItem(const QString& Name, const QString& To) +void CSbieView::OnMoveItem(const QString& Name, const QString& To, int row) { - MoveItem(Name, To); + QModelIndex index; + if (!To.isEmpty()) { // only groups can be parents so add the group marker "!" + QModelIndex index0 = m_pSbieModel->FindIndex("!" + To); + index = index0.child(row, 0); + } else + index = m_pSbieModel->index(row, 0); + QModelIndex index2 = m_pSortProxy->mapFromSource(index); + int row2 = index2.row(); + MoveItem(Name, To, row2); m_pSbieModel->Clear(); //todo improve that diff --git a/SandboxiePlus/SandMan/Views/SbieView.h b/SandboxiePlus/SandMan/Views/SbieView.h index 08a6eeb6..475c6f81 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.h +++ b/SandboxiePlus/SandMan/Views/SbieView.h @@ -54,7 +54,7 @@ private slots: void OnExpanded(const QModelIndex& index) { ChangeExpand(index, true); } void OnCollapsed(const QModelIndex& index) { ChangeExpand(index, false); } - void OnMoveItem(const QString& Name, const QString& To); + void OnMoveItem(const QString& Name, const QString& To, int row); void OnRemoveItem(); diff --git a/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp b/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp index cd93a4ba..0542f4f6 100644 --- a/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp @@ -245,6 +245,7 @@ void CRecoveryWindow::AddFile(const QString& FilePath, const QString& BoxPath) QMenu* pCloseMenu = new QMenu(ui.btnClose); pCloseMenu->addAction(tr("Close until all programs stop in this box"), this, SLOT(OnCloseUntil())); + pCloseMenu->addAction(tr("Close and Disable Immediate Recovery for this box"), this, SLOT(OnAutoDisable())); ui.btnClose->setPopupMode(QToolButton::MenuButtonPopup); ui.btnClose->setMenu(pCloseMenu); } @@ -501,6 +502,12 @@ void CRecoveryWindow::OnCloseUntil() close(); } +void CRecoveryWindow::OnAutoDisable() +{ + m_pBox->SetBool("AutoRecover", false); + close(); +} + void CRecoveryCounter::run() { quint32 fileCount = 0; diff --git a/SandboxiePlus/SandMan/Windows/RecoveryWindow.h b/SandboxiePlus/SandMan/Windows/RecoveryWindow.h index 0cb79a77..355da118 100644 --- a/SandboxiePlus/SandMan/Windows/RecoveryWindow.h +++ b/SandboxiePlus/SandMan/Windows/RecoveryWindow.h @@ -60,6 +60,7 @@ private slots: void OnDeleteAll(); void OnDeleteEverything(); void OnCloseUntil(); + void OnAutoDisable(); void OnCount(quint32 fileCount, quint32 folderCount, quint64 totalSize); protected: diff --git a/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp b/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp index 4e2e67b5..2e3ecc6b 100644 --- a/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp +++ b/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp @@ -111,12 +111,17 @@ CIntroPage::CIntroPage(QWidget *parent) connect(m_pBusinessRadio, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged())); registerField("useBusiness", m_pBusinessRadio); + QLabel* pNote = new QLabel(tr("Note: this option is immutable")); + layout->addWidget(pNote); + + if (BusinessUse != 2) { m_pLabel->setEnabled(false); m_pPersonalRadio->setChecked(BusinessUse == 0); m_pPersonalRadio->setEnabled(false); m_pBusinessRadio->setChecked(BusinessUse == 1); m_pBusinessRadio->setEnabled(false); + pNote->setEnabled(false); } setLayout(layout); @@ -167,6 +172,10 @@ CCertificatePage::CCertificatePage(QWidget *parent) registerField("useCertificate", m_pCertificate, "plainText"); m_pEvaluate = new QCheckBox(tr("Start evaluation without a certificate for a limited period of time.")); + if (g_CertInfo.evaluation) { + m_pEvaluate->setEnabled(false); + m_pEvaluate->setChecked(true); + } layout->addWidget(m_pEvaluate); connect(m_pEvaluate, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged())); registerField("isEvaluate", m_pEvaluate); @@ -215,8 +224,8 @@ bool CCertificatePage::isComplete() const { if (field("useBusiness").toBool()) { - m_pCertificate->setEnabled(!m_pEvaluate->isChecked()); - if (m_pCertificate->toPlainText().isEmpty() && !m_pEvaluate->isChecked()) + m_pCertificate->setEnabled(!(m_pEvaluate->isChecked() && m_pEvaluate->isEnabled())); + if (m_pCertificate->toPlainText().isEmpty() && !(m_pEvaluate->isChecked() && m_pEvaluate->isEnabled())) return false; } return QWizardPage::isComplete(); @@ -225,7 +234,11 @@ bool CCertificatePage::isComplete() const bool CCertificatePage::validatePage() { QByteArray Certificate = m_pCertificate->toPlainText().toLatin1(); - if (!m_pEvaluate->isChecked() && !Certificate.isEmpty() && g_Certificate != Certificate) { + if (m_pEvaluate->isChecked()) { + theAPI->StartEvaluation(); + theGUI->UpdateCertState(); + } + else if (!m_pEvaluate->isChecked() && !Certificate.isEmpty() && g_Certificate != Certificate) { return CSettingsWindow::ApplyCertificate(Certificate, this); } return true;