void CSandMan::OnFileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId) { CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); if ((!pBox.isNull() && pBox.objectCast()->IsRecoverySuspended()) || IsDisableRecovery()) return; if (theConf->GetBool("Options/InstantRecovery", true)) { CRecoveryWindow* pWnd = ShowRecovery(pBox, false); //if (!theConf->GetBool("Options/AlwaysOnTop", false)) { // SetWindowPos((HWND)pWnd->winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); // QTimer::singleShot(100, this, [pWnd]() { // SetWindowPos((HWND)pWnd->winId(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); // }); //} if (pWnd) pWnd->AddFile(FilePath, BoxPath); } else m_pPopUpWindow->AddFileToRecover(FilePath, BoxPath, pBox, ProcessId); } bool CSandMan::OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteShapshots, bool bCloseEmpty) { auto pBoxEx = pBox.objectCast(); if (!pBoxEx) return false; if (pBoxEx->m_pRecoveryWnd != NULL) { if (pBoxEx->m_pRecoveryWnd->IsDeleteDialog()) return false; pBoxEx->m_pRecoveryWnd->close(); } CRecoveryWindow* pRecoveryWnd = pBoxEx->m_pRecoveryWnd = new CRecoveryWindow(pBox, false, this); if (pBoxEx->m_pRecoveryWnd->FindFiles() == 0 && bCloseEmpty) { delete pBoxEx->m_pRecoveryWnd; pBoxEx->m_pRecoveryWnd = NULL; return true; } else { connect(pBoxEx->m_pRecoveryWnd, &CRecoveryWindow::Closed, [pBoxEx]() { pBoxEx->m_pRecoveryWnd = NULL; }); if (pBoxEx->m_pRecoveryWnd->exec() != 1) return false; } DeleteShapshots = pRecoveryWnd->IsDeleteShapshots(); return true; } CRecoveryWindow* CSandMan::ShowRecovery(const CSandBoxPtr& pBox, bool bFind) { auto pBoxEx = pBox.objectCast(); if (!pBoxEx) return NULL; if (pBoxEx->m_pRecoveryWnd == NULL) { pBoxEx->m_pRecoveryWnd = new CRecoveryWindow(pBox, bFind == false); connect(pBoxEx->m_pRecoveryWnd, &CRecoveryWindow::Closed, [pBoxEx]() { pBoxEx->m_pRecoveryWnd = NULL; }); pBoxEx->m_pRecoveryWnd->show(); } else if(bFind) { // We don't want to force window in front on instant recovery pBoxEx->m_pRecoveryWnd->setWindowState((pBoxEx->m_pRecoveryWnd->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); SetForegroundWindow((HWND)pBoxEx->m_pRecoveryWnd->winId()); } if(bFind) pBoxEx->m_pRecoveryWnd->FindFiles(); return pBoxEx->m_pRecoveryWnd; } SB_PROGRESS CSandMan::RecoverFiles(const QString& BoxName, const QList>& FileList, int Action) { CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress()); QtConcurrent::run(CSandMan::RecoverFilesAsync, pProgress, BoxName, FileList, Action); return SB_PROGRESS(OP_ASYNC, pProgress); } void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QString& BoxName, const QList>& FileList, int Action) { SB_STATUS Status = SB_OK; int OverwriteOnExist = -1; QStringList Unrecovered; for (QList>::const_iterator I = FileList.begin(); I != FileList.end(); ++I) { QString BoxPath = I->first; QString RecoveryPath = I->second; QString FileName = BoxPath.mid(BoxPath.lastIndexOf("\\") + 1); QString RecoveryFolder = RecoveryPath.left(RecoveryPath.lastIndexOf("\\") + 1); pProgress->ShowMessage(tr("Recovering file %1 to %2").arg(FileName).arg(RecoveryFolder)); QDir().mkpath(RecoveryFolder); if (QFile::exists(RecoveryPath)) { int Overwrite = OverwriteOnExist; if (Overwrite == -1) { bool forAll = false; int retVal = 0; QMetaObject::invokeMethod(theGUI, "ShowQuestion", Qt::BlockingQueuedConnection, // show this question using the GUI thread Q_RETURN_ARG(int, retVal), Q_ARG(QString, tr("The file %1 already exists, do you want to overwrite it?").arg(RecoveryPath)), Q_ARG(QString, tr("Do this for all files!")), Q_ARG(bool*, &forAll), Q_ARG(int, QDialogButtonBox::Yes | QDialogButtonBox::No), Q_ARG(int, QDialogButtonBox::No), Q_ARG(int, QMessageBox::Question) ); Overwrite = retVal == QDialogButtonBox::Yes ? 1 : 0; if (forAll) OverwriteOnExist = Overwrite; } if (Overwrite == 1) QFile::remove(RecoveryPath); } if (!QFile::rename(BoxPath, RecoveryPath)) Unrecovered.append(BoxPath); else { QMetaObject::invokeMethod(theGUI, "OnFileRecovered", Qt::BlockingQueuedConnection, // show this question using the GUI thread Q_ARG(QString, BoxName), Q_ARG(QString, RecoveryPath), Q_ARG(QString, BoxPath) ); } } if (!Unrecovered.isEmpty()) Status = SB_ERR(SB_Message, QVariantList () << (tr("Failed to recover some files: \n") + Unrecovered.join("\n"))); else if(FileList.count() == 1 && Action != 0) { std::wstring path = FileList.first().second.toStdWString(); switch (Action) { case 1: // open ShellExecute(NULL, NULL, path.c_str(), NULL, NULL, SW_SHOWNORMAL); break; case 2: // explore ShellExecute(NULL, NULL, L"explorer.exe", (L"/select,\"" + path + L"\"").c_str(), NULL, SW_SHOWNORMAL); break; } } pProgress->Finish(Status); } void CSandMan::AddFileRecovered(const QString& BoxName, const QString& FilePath) { CPanelWidgetEx* pRecoveryLog = m_pRecoveryLog; if (pRecoveryLog == NULL) { pRecoveryLog = m_pRecoveryLogWnd->m_pRecoveryLog; if (!pRecoveryLog) return; } QTreeWidgetItem* pItem = new QTreeWidgetItem(); // Time|Box|FilePath pItem->setText(0, QDateTime::currentDateTime().toString("hh:mm:ss.zzz")); pItem->setText(1, BoxName); pItem->setText(2, FilePath); pRecoveryLog->GetTree()->addTopLevelItem(pItem); pRecoveryLog->GetView()->verticalScrollBar()->setValue(pRecoveryLog->GetView()->verticalScrollBar()->maximum()); } void CSandMan::OnFileRecovered(const QString& BoxName, const QString& FilePath, const QString& BoxPath) { AddFileRecovered(BoxName, FilePath); CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); if (pBox) pBox.objectCast()->UpdateSize(); } //////////////////////////////////////////////////////////////////////////////////////// // CRecoveryLogWnd CRecoveryLogWnd::CRecoveryLogWnd(QWidget *parent) : QDialog(parent) { Qt::WindowFlags flags = windowFlags(); flags |= Qt::CustomizeWindowHint; //flags &= ~Qt::WindowContextHelpButtonHint; //flags &= ~Qt::WindowSystemMenuHint; //flags &= ~Qt::WindowMinMaxButtonsHint; //flags |= Qt::WindowMinimizeButtonHint; //flags &= ~Qt::WindowCloseButtonHint; flags &= ~Qt::WindowContextHelpButtonHint; //flags &= ~Qt::WindowSystemMenuHint; setWindowFlags(flags); this->setWindowTitle(tr("Sandboxie-Plus - Recovery Log")); QGridLayout* pLayout = new QGridLayout(); //pLayout->setContentsMargins(3,3,3,3); m_pRecoveryLog = new CPanelWidgetEx(); m_pRecoveryLog->GetTree()->setItemDelegate(new CTreeItemDelegate()); m_pRecoveryLog->GetTree()->setAlternatingRowColors(theConf->GetBool("Options/AltRowColors", false)); //m_pRecoveryLog->GetView()->setItemDelegate(theGUI->GetItemDelegate()); ((QTreeWidgetEx*)m_pRecoveryLog->GetView())->setHeaderLabels(tr("Time|Box Name|File Path").split("|")); QAction* pAction = new QAction(tr("Cleanup Recovery Log")); connect(pAction, SIGNAL(triggered()), m_pRecoveryLog->GetTree(), SLOT(clear())); m_pRecoveryLog->GetMenu()->insertAction(m_pRecoveryLog->GetMenu()->actions()[0], pAction); m_pRecoveryLog->GetMenu()->insertSeparator(m_pRecoveryLog->GetMenu()->actions()[0]); m_pRecoveryLog->GetView()->setSelectionMode(QAbstractItemView::ExtendedSelection); m_pRecoveryLog->GetView()->setSortingEnabled(false); connect(m_pRecoveryLog->GetTree(), SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnDblClick(QTreeWidgetItem*))); pLayout->addWidget(new QLabel(tr("The following files were recently recovered and moved out of a sandbox.")), 0, 0); pLayout->addWidget(m_pRecoveryLog, 1, 0); this->setLayout(pLayout); restoreGeometry(theConf->GetBlob("RecoveryLogWindow/Window_Geometry")); } CRecoveryLogWnd::~CRecoveryLogWnd() { theConf->SetBlob("RecoveryLogWindow/Window_Geometry", saveGeometry()); } void CRecoveryLogWnd::closeEvent(QCloseEvent *e) { emit Closed(); //this->deleteLater(); } void CRecoveryLogWnd::OnDblClick(QTreeWidgetItem* pItem) { ShellExecute(NULL, NULL, L"explorer.exe", (L"/select,\"" + pItem->text(2).toStdWString() + L"\"").c_str(), NULL, SW_SHOWNORMAL); } void CSandMan::OnRecoveryLog() { if (!m_pRecoveryLogWnd->isVisible()) { bool bAlwaysOnTop = theConf->GetBool("Options/AlwaysOnTop", false); m_pRecoveryLogWnd->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop); SafeShow(m_pRecoveryLogWnd); } }