Sandboxie/SandboxiePlus/SandMan/Windows/FileBrowserWindow.cpp

265 lines
8.9 KiB
C++

#include "stdafx.h"
#include "FileBrowserWindow.h"
#include "SandMan.h"
#include "../MiscHelpers/Common/Settings.h"
#include "../MiscHelpers/Common/TreeItemModel.h"
#include "../MiscHelpers/Common/OtherFunctions.h"
#include "../QSbieAPI/SbieUtils.h"
CFileBrowserWindow::CFileBrowserWindow(const CSandBoxPtr& pBox, 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;
setWindowFlags(flags);
bool bAlwaysOnTop = theConf->GetBool("Options/AlwaysOnTop", false);
this->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
ui.setupUi(this);
this->setWindowTitle(tr("%1 - Files").arg(pBox->GetName()));
m_pBox = pBox;
m_pFileModel = new QFileSystemModel(this);
m_pFileModel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Files | QDir::Hidden | QDir::System);
m_pFileModel->setRootPath(pBox->GetFileRoot());
ui.treeFiles->setModel(m_pFileModel);
ui.treeFiles->setRootIndex(m_pFileModel->setRootPath(pBox->GetFileRoot()));
ui.treeFiles->setSelectionMode(QAbstractItemView::ExtendedSelection);
#ifdef WIN32
QStyle* pStyle = QStyleFactory::create("windows");
ui.treeFiles->setStyle(pStyle);
#endif
ui.treeFiles->setExpandsOnDoubleClick(false);
ui.treeFiles->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui.treeFiles, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(OnFileMenu(const QPoint &)));
connect(ui.treeFiles, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(OnFileDblClick(const QModelIndex &)));
//statusBar();
restoreGeometry(theConf->GetBlob("FileBrowserWindow/Window_Geometry"));
QByteArray Columns = theConf->GetBlob("FileBrowserWindow/FileTree_Columns");
if (!Columns.isEmpty())
ui.treeFiles->header()->restoreState(Columns);
}
CFileBrowserWindow::~CFileBrowserWindow()
{
theConf->SetBlob("FileBrowserWindow/Window_Geometry",saveGeometry());
theConf->SetBlob("FileBrowserWindow/FileTree_Columns", ui.treeFiles->header()->saveState());
}
void CFileBrowserWindow::closeEvent(QCloseEvent *e)
{
emit Closed();
this->deleteLater();
}
#include <windows.h>
#include <Shlobj.h>
#include <atlbase.h>
#define MENU_RECOVER 1
#define MENU_RECOVER_TO_ANY 2
#define MENU_CREATE_SHORTCUT 3
void addSeparatorToShellContextMenu(HMENU hMenu)
{
MENUITEMINFO menu_item_info;
memset(&menu_item_info, 0, sizeof(MENUITEMINFO));
menu_item_info.cbSize = sizeof(MENUITEMINFO);
menu_item_info.fType = MFT_SEPARATOR;
menu_item_info.wID = 0;
InsertMenuItem(hMenu, 0, TRUE, &menu_item_info);
}
void addItemToShellContextMenu(HMENU hMenu, const wchar_t *name, int ID)
{
MENUITEMINFO menu_item_info;
memset(&menu_item_info, 0, sizeof(MENUITEMINFO));
menu_item_info.cbSize = sizeof(MENUITEMINFO);
menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
menu_item_info.wID = 0xF000 + ID;
menu_item_info.dwTypeData = (wchar_t*)name;
InsertMenuItem(hMenu, 0, TRUE, &menu_item_info);
}
int openShellContextMenu(const QStringList& Files, void * parentWindow)
{
std::list<CComHeapPtr<ITEMIDLIST_ABSOLUTE>> items;
items.resize(Files.count());
auto IT = items.begin();
foreach(QString File, Files) {
CComPtr<IShellItem> item;
SHCreateItemFromParsingName(File.toStdWString().c_str(), NULL, IID_PPV_ARGS(&item));
CComQIPtr<IPersistIDList> idl(item);
idl->GetIDList(&*IT++);
}
std::vector<LPCITEMIDLIST> list;
list.resize(items.size());
LPCITEMIDLIST* listPtr = &list.front();
for (auto I = items.begin(); I != items.end(); I++)
*listPtr++ = *I;
CComPtr<IShellItemArray> array;
SHCreateShellItemArrayFromIDLists(list.size(), &list.front(), &array);
CComPtr<IContextMenu> menu;
array->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARGS(&menu));
if (!menu)
return 0;
HMENU hMenu = CreatePopupMenu();
if (!hMenu)
return 0;
if (SUCCEEDED(menu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_NORMAL)))
{
addSeparatorToShellContextMenu(hMenu);
std::wstring Str1 = CFileBrowserWindow::tr("Create Shortcut").toStdWString();
if (Files.count() == 1) {
addItemToShellContextMenu(hMenu, Str1.c_str(), MENU_CREATE_SHORTCUT);
addSeparatorToShellContextMenu(hMenu);
}
std::wstring Str2 = CFileBrowserWindow::tr("Recover to Any Folder").toStdWString();
addItemToShellContextMenu(hMenu, Str2.c_str(), MENU_RECOVER_TO_ANY);
std::wstring Str3 = CFileBrowserWindow::tr("Recover to Same Folder").toStdWString();
addItemToShellContextMenu(hMenu, Str3.c_str(), MENU_RECOVER);
POINT point;
GetCursorPos(&point);
int iCmd = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, point.x, point.y, (HWND)parentWindow, NULL);
if (iCmd > 0)
{
if ((iCmd & 0xF000) == 0xF000) {
DestroyMenu(hMenu);
return iCmd & 0x0FFF;
}
CMINVOKECOMMANDINFOEX info = { 0 };
info.cbSize = sizeof(info);
info.fMask = CMIC_MASK_UNICODE;
info.hwnd = (HWND)parentWindow;
info.lpVerb = MAKEINTRESOURCEA(iCmd - 1);
info.lpVerbW = MAKEINTRESOURCEW(iCmd - 1);
info.nShow = SW_SHOWNORMAL;
menu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
}
}
DestroyMenu(hMenu);
return 0;
}
void CFileBrowserWindow::OnFileMenu(const QPoint&)
{
QStringList Files;
foreach(const QModelIndex & Index, ui.treeFiles->selectionModel()->selectedIndexes()) {
QString BoxedPath = m_pFileModel->fileInfo(Index).absoluteFilePath().replace("/", "\\");
if (m_pFileModel->fileInfo(Index).isDir())
BoxedPath += "\\";
bool bFound = false;
foreach(const QString & File, Files) {
if (BoxedPath.contains(File))
bFound = true;
else if (File.contains(BoxedPath))
Files.removeOne(File);
}
if(!bFound)
Files.append(BoxedPath);
}
if (Files.isEmpty())
return;
int iCmd = openShellContextMenu(Files, (void*)this->winId());
if (iCmd == 0)
return;
QString RecoveryFolder;
switch (iCmd)
{
case MENU_RECOVER_TO_ANY:
RecoveryFolder = QFileDialog::getExistingDirectory(this, CFileBrowserWindow::tr("Select Directory")).replace("/", "\\");
if (RecoveryFolder.isEmpty())
break;
case MENU_RECOVER:
{
QStringList AllFiles;
foreach(const QString& File, Files)
{
if (File.right(1) == "\\") {
foreach(QString SubFile, ListDir(File))
AllFiles.append(File + SubFile.replace("/", "\\"));
}
else
AllFiles.append(File);
}
QList<QPair<QString, QString>> FileList;
foreach(QString BoxedPath, AllFiles)
{
if (!RecoveryFolder.isEmpty()) {
QString FileName = BoxedPath.mid(BoxedPath.lastIndexOf("\\") + 1);
FileList.append(qMakePair(BoxedPath, RecoveryFolder + "\\" + FileName));
}
else {
QString RealPath = theAPI->GetRealPath(m_pBox, BoxedPath);
FileList.append(qMakePair(BoxedPath, RealPath));
}
}
SB_PROGRESS Status = theGUI->RecoverFiles(FileList, 0);
if (Status.GetStatus() == OP_ASYNC)
theGUI->AddAsyncOp(Status.GetValue());
break;
}
case MENU_CREATE_SHORTCUT:
{
QString BoxName = m_pBox->GetName();
QString LinkPath = Files.first();
QString LinkName = LinkPath.mid(LinkPath.lastIndexOf("\\") + 1);
QString Path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).replace("/", "\\");
//Path = QFileDialog::getExistingDirectory(this, tr("Select Directory to create Shorcut in"), Path).replace("/", "\\");
//if (Path.isEmpty())
// return;
if (Path.right(1) != "\\")
Path.append("\\");
Path += "[" + BoxName + "] " + LinkName;
Path = QFileDialog::getSaveFileName(this, tr("Create Shortcut to sandbox %1").arg(BoxName), Path, QString("Shortcut files (*.lnk)")).replace("/", "\\");
if (Path.isEmpty())
return;
CSbieUtils::CreateShortcut(theAPI, Path, LinkName, BoxName, LinkPath, LinkPath);
break;
}
}
}
void CFileBrowserWindow::OnFileDblClick(const QModelIndex &)
{
QString BoxedPath = m_pFileModel->fileInfo(ui.treeFiles->currentIndex()).absoluteFilePath();
ShellExecute(NULL, NULL, BoxedPath.toStdWString().c_str(), NULL, m_pBox->GetFileRoot().toStdWString().c_str(), SW_SHOWNORMAL);
}