mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 15:14:59 -06:00
450 lines
13 KiB
C++
Executable File
450 lines
13 KiB
C++
Executable File
// PanelOperations.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "resource.h"
|
|
|
|
#include "Panel.h"
|
|
|
|
#include "Common/StringConvert.h"
|
|
#include "Common/DynamicBuffer.h"
|
|
#include "Windows/FileDir.h"
|
|
#include "Windows/ResourceString.h"
|
|
#include "Windows/Thread.h"
|
|
#include "Windows/COM.h"
|
|
|
|
#include "ComboDialog.h"
|
|
|
|
#include "FSFolder.h"
|
|
#include "LangUtils.h"
|
|
#include "FormatUtils.h"
|
|
|
|
#include "UpdateCallback100.h"
|
|
|
|
using namespace NWindows;
|
|
using namespace NFile;
|
|
|
|
#ifndef _UNICODE
|
|
extern bool g_IsNT;
|
|
#endif
|
|
|
|
struct CThreadDelete
|
|
{
|
|
CMyComPtr<IFolderOperations> FolderOperations;
|
|
CRecordVector<UInt32> Indices;
|
|
CMyComPtr<IProgress> UpdateCallback;
|
|
CUpdateCallback100Imp *UpdateCallbackSpec;
|
|
HRESULT Result;
|
|
|
|
DWORD Process()
|
|
{
|
|
NCOM::CComInitializer comInitializer;
|
|
UpdateCallbackSpec->ProgressDialog.WaitCreating();
|
|
Result = FolderOperations->Delete(&Indices.Front(), Indices.Size(), UpdateCallback);
|
|
UpdateCallbackSpec->ProgressDialog.MyClose();
|
|
return 0;
|
|
}
|
|
|
|
static THREAD_FUNC_DECL MyThreadFunction(void *param)
|
|
{
|
|
return ((CThreadDelete *)param)->Process();
|
|
}
|
|
};
|
|
|
|
struct CThreadCreateFolder
|
|
{
|
|
CMyComPtr<IFolderOperations> FolderOperations;
|
|
UString Name;
|
|
CMyComPtr<IProgress> UpdateCallback;
|
|
CUpdateCallback100Imp *UpdateCallbackSpec;
|
|
HRESULT Result;
|
|
|
|
DWORD Process()
|
|
{
|
|
NCOM::CComInitializer comInitializer;
|
|
UpdateCallbackSpec->ProgressDialog.WaitCreating();
|
|
Result = FolderOperations->CreateFolder(Name, UpdateCallback);
|
|
UpdateCallbackSpec->ProgressDialog.MyClose();
|
|
return 0;
|
|
}
|
|
|
|
static THREAD_FUNC_DECL MyThreadFunction(void *param)
|
|
{
|
|
return ((CThreadCreateFolder *)param)->Process();
|
|
}
|
|
};
|
|
|
|
#ifndef _UNICODE
|
|
typedef int (WINAPI * SHFileOperationWP)(LPSHFILEOPSTRUCTW lpFileOp);
|
|
#endif
|
|
|
|
void CPanel::DeleteItems(bool toRecycleBin)
|
|
{
|
|
CPanel::CDisableTimerProcessing disableTimerProcessing2(*this);
|
|
CRecordVector<UInt32> indices;
|
|
GetOperatedItemIndices(indices);
|
|
if (indices.IsEmpty())
|
|
return;
|
|
CSelectedState state;
|
|
SaveSelectedState(state);
|
|
bool useInternalDelete = false;
|
|
if (IsFSFolder() && toRecycleBin)
|
|
{
|
|
#ifndef _UNICODE
|
|
if (!g_IsNT)
|
|
{
|
|
CDynamicBuffer<CHAR> buffer;
|
|
size_t size = 0;
|
|
for (int i = 0; i < indices.Size(); i++)
|
|
{
|
|
const AString path = GetSystemString(GetFsPath() + GetItemRelPath(indices[i]));
|
|
buffer.EnsureCapacity(size + path.Length() + 1);
|
|
memmove(((CHAR *)buffer) + size, (const CHAR *)path, (path.Length() + 1) * sizeof(CHAR));
|
|
size += path.Length() + 1;
|
|
}
|
|
buffer.EnsureCapacity(size + 1);
|
|
((CHAR *)buffer)[size] = 0;
|
|
SHFILEOPSTRUCTA fo;
|
|
fo.hwnd = GetParent();
|
|
fo.wFunc = FO_DELETE;
|
|
fo.pFrom = (const CHAR *)buffer;
|
|
fo.pTo = 0;
|
|
fo.fFlags = 0;
|
|
if (toRecycleBin)
|
|
fo.fFlags |= FOF_ALLOWUNDO;
|
|
// fo.fFlags |= FOF_NOCONFIRMATION;
|
|
// fo.fFlags |= FOF_NOERRORUI;
|
|
// fo.fFlags |= FOF_SILENT;
|
|
// fo.fFlags |= FOF_WANTNUKEWARNING;
|
|
fo.fAnyOperationsAborted = FALSE;
|
|
fo.hNameMappings = 0;
|
|
fo.lpszProgressTitle = 0;
|
|
/* int res = */ ::SHFileOperationA(&fo);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
CDynamicBuffer<WCHAR> buffer;
|
|
size_t size = 0;
|
|
int maxLen = 0;
|
|
for (int i = 0; i < indices.Size(); i++)
|
|
{
|
|
// L"\\\\?\\") doesn't work here.
|
|
const UString path = GetFsPath() + GetItemRelPath(indices[i]);
|
|
if (path.Length() > maxLen)
|
|
maxLen = path.Length();
|
|
buffer.EnsureCapacity(size + path.Length() + 1);
|
|
memmove(((WCHAR *)buffer) + size, (const WCHAR *)path, (path.Length() + 1) * sizeof(WCHAR));
|
|
size += path.Length() + 1;
|
|
}
|
|
buffer.EnsureCapacity(size + 1);
|
|
((WCHAR *)buffer)[size] = 0;
|
|
if (maxLen >= MAX_PATH)
|
|
{
|
|
if (toRecycleBin)
|
|
{
|
|
MessageBoxMyError(L"You can't send file with long path to Recycle Bin");
|
|
return;
|
|
}
|
|
useInternalDelete = true;
|
|
}
|
|
else
|
|
{
|
|
SHFILEOPSTRUCTW fo;
|
|
fo.hwnd = GetParent();
|
|
fo.wFunc = FO_DELETE;
|
|
fo.pFrom = (const WCHAR *)buffer;
|
|
fo.pTo = 0;
|
|
fo.fFlags = 0;
|
|
if (toRecycleBin)
|
|
fo.fFlags |= FOF_ALLOWUNDO;
|
|
fo.fAnyOperationsAborted = FALSE;
|
|
fo.hNameMappings = 0;
|
|
fo.lpszProgressTitle = 0;
|
|
int res;
|
|
#ifdef _UNICODE
|
|
res = ::SHFileOperationW(&fo);
|
|
#else
|
|
SHFileOperationWP shFileOperationW = (SHFileOperationWP)
|
|
::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHFileOperationW");
|
|
if (shFileOperationW == 0)
|
|
return;
|
|
res = shFileOperationW(&fo);
|
|
#endif
|
|
}
|
|
}
|
|
/*
|
|
if (fo.fAnyOperationsAborted)
|
|
MessageBoxError(result, LangString(IDS_ERROR_DELETING, 0x03020217));
|
|
*/
|
|
}
|
|
else
|
|
useInternalDelete = true;
|
|
if (useInternalDelete)
|
|
DeleteItemsInternal(indices);
|
|
RefreshListCtrl(state);
|
|
}
|
|
|
|
void CPanel::DeleteItemsInternal(CRecordVector<UInt32> &indices)
|
|
{
|
|
CMyComPtr<IFolderOperations> folderOperations;
|
|
if (_folder.QueryInterface(IID_IFolderOperations, &folderOperations) != S_OK)
|
|
{
|
|
MessageBox(LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208));
|
|
return;
|
|
}
|
|
|
|
UString title;
|
|
UString message;
|
|
if (indices.Size() == 1)
|
|
{
|
|
int index = indices[0];
|
|
const UString itemName = GetItemRelPath(index);
|
|
if (IsItemFolder(index))
|
|
{
|
|
title = LangString(IDS_CONFIRM_FOLDER_DELETE, 0x03020211);
|
|
message = MyFormatNew(IDS_WANT_TO_DELETE_FOLDER, 0x03020214, itemName);
|
|
}
|
|
else
|
|
{
|
|
title = LangString(IDS_CONFIRM_FILE_DELETE, 0x03020210);
|
|
message = MyFormatNew(IDS_WANT_TO_DELETE_FILE, 0x03020213, itemName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
title = LangString(IDS_CONFIRM_ITEMS_DELETE, 0x03020212);
|
|
message = MyFormatNew(IDS_WANT_TO_DELETE_ITEMS, 0x03020215,
|
|
NumberToString(indices.Size()));
|
|
}
|
|
if (::MessageBoxW(GetParent(), message, title, MB_OKCANCEL | MB_ICONQUESTION) != IDOK)
|
|
return;
|
|
|
|
{
|
|
CThreadDelete deleter;
|
|
deleter.UpdateCallbackSpec = new CUpdateCallback100Imp;
|
|
deleter.UpdateCallback = deleter.UpdateCallbackSpec;
|
|
deleter.UpdateCallbackSpec->Init(GetParent(), false, L"");
|
|
|
|
UString progressTitle = LangString(IDS_DELETING, 0x03020216);
|
|
|
|
deleter.UpdateCallbackSpec->ProgressDialog.MainWindow = _mainWindow;
|
|
deleter.UpdateCallbackSpec->ProgressDialog.MainTitle = LangString(IDS_APP_TITLE, 0x03000000);
|
|
deleter.UpdateCallbackSpec->ProgressDialog.MainAddTitle = progressTitle + UString(L" ");
|
|
|
|
deleter.FolderOperations = folderOperations;
|
|
deleter.Indices = indices;
|
|
|
|
NWindows::CThread thread;
|
|
if (thread.Create(CThreadDelete::MyThreadFunction, &deleter) != S_OK)
|
|
throw 271824;
|
|
deleter.UpdateCallbackSpec->StartProgressDialog(progressTitle);
|
|
|
|
HRESULT result = deleter.Result;
|
|
if (result != S_OK)
|
|
MessageBoxError(result, LangString(IDS_ERROR_DELETING, 0x03020217));
|
|
}
|
|
RefreshTitleAlways();
|
|
}
|
|
|
|
BOOL CPanel::OnBeginLabelEdit(LV_DISPINFOW * lpnmh)
|
|
{
|
|
int realIndex = GetRealIndex(lpnmh->item);
|
|
if (realIndex == kParentIndex)
|
|
return TRUE;
|
|
CMyComPtr<IFolderOperations> folderOperations;
|
|
if (_folder.QueryInterface(IID_IFolderOperations, &folderOperations) != S_OK)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CPanel::OnEndLabelEdit(LV_DISPINFOW * lpnmh)
|
|
{
|
|
if (lpnmh->item.pszText == NULL)
|
|
return FALSE;
|
|
CMyComPtr<IFolderOperations> folderOperations;
|
|
if (_folder.QueryInterface(IID_IFolderOperations, &folderOperations) != S_OK)
|
|
{
|
|
MessageBoxMyError(L"Renaming is not supported");
|
|
return FALSE;
|
|
}
|
|
const UString newName = lpnmh->item.pszText;
|
|
CPanel::CDisableTimerProcessing disableTimerProcessing2(*this);
|
|
|
|
SaveSelectedState(_selectedState);
|
|
|
|
int realIndex = GetRealIndex(lpnmh->item);
|
|
if (realIndex == kParentIndex)
|
|
return FALSE;
|
|
const UString prefix = GetItemPrefix(realIndex);
|
|
HRESULT result = folderOperations->Rename(realIndex, newName, 0);
|
|
if (result != S_OK)
|
|
{
|
|
MessageBoxError(result, LangString(IDS_ERROR_RENAMING, 0x03020221));
|
|
return FALSE;
|
|
}
|
|
// Can't use RefreshListCtrl here.
|
|
// RefreshListCtrlSaveFocused();
|
|
_selectedState.FocusedName = prefix + newName;
|
|
_selectedState.SelectFocused = true;
|
|
|
|
// We need clear all items to disable GetText before Reload:
|
|
// number of items can change.
|
|
// _listView.DeleteAllItems();
|
|
// But seems it can still call GetText (maybe for current item)
|
|
// so we can't delete items.
|
|
|
|
_dontShowMode = true;
|
|
|
|
PostMessage(kReLoadMessage);
|
|
return TRUE;
|
|
}
|
|
|
|
void CPanel::CreateFolder()
|
|
{
|
|
CMyComPtr<IFolderOperations> folderOperations;
|
|
if (_folder.QueryInterface(IID_IFolderOperations, &folderOperations) != S_OK)
|
|
{
|
|
MessageBox(LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208));
|
|
return;
|
|
}
|
|
CPanel::CDisableTimerProcessing disableTimerProcessing2(*this);
|
|
CSelectedState state;
|
|
SaveSelectedState(state);
|
|
CComboDialog comboDialog;
|
|
comboDialog.Title = LangString(IDS_CREATE_FOLDER, 0x03020230);
|
|
comboDialog.Static = LangString(IDS_CREATE_FOLDER_NAME, 0x03020231);
|
|
comboDialog.Value = LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, /*0x03020232*/ (UInt32)-1);
|
|
if (comboDialog.Create(GetParent()) == IDCANCEL)
|
|
return;
|
|
|
|
UString newName = comboDialog.Value;
|
|
|
|
// HRESULT result = folderOperations->CreateFolder(newName, 0);
|
|
|
|
{
|
|
CThreadCreateFolder upd;
|
|
upd.UpdateCallbackSpec = new CUpdateCallback100Imp;
|
|
upd.UpdateCallback = upd.UpdateCallbackSpec;
|
|
upd.UpdateCallbackSpec->Init(GetParent(), false, L"");
|
|
|
|
UString progressTitle = LangString(IDS_CREATE_FOLDER, 0x03020230);
|
|
|
|
upd.UpdateCallbackSpec->ProgressDialog.MainWindow = _mainWindow;
|
|
upd.UpdateCallbackSpec->ProgressDialog.MainTitle = LangString(IDS_APP_TITLE, 0x03000000);
|
|
upd.UpdateCallbackSpec->ProgressDialog.MainAddTitle = progressTitle + UString(L" ");
|
|
|
|
upd.FolderOperations = folderOperations;
|
|
upd.Name = newName;
|
|
|
|
NWindows::CThread thread;
|
|
if (thread.Create(CThreadCreateFolder::MyThreadFunction, &upd) != S_OK)
|
|
throw 271824;
|
|
upd.UpdateCallbackSpec->StartProgressDialog(progressTitle);
|
|
|
|
HRESULT result = upd.Result;
|
|
|
|
if (result != S_OK)
|
|
{
|
|
MessageBoxError(result, LangString(IDS_CREATE_FOLDER_ERROR, 0x03020233));
|
|
return;
|
|
}
|
|
int pos = newName.Find(L'\\');
|
|
if (pos >= 0)
|
|
newName = newName.Left(pos);
|
|
if (!_mySelectMode)
|
|
state.SelectedNames.Clear();
|
|
state.FocusedName = newName;
|
|
state.SelectFocused = true;
|
|
}
|
|
RefreshTitleAlways();
|
|
RefreshListCtrl(state);
|
|
}
|
|
|
|
void CPanel::CreateFile()
|
|
{
|
|
CMyComPtr<IFolderOperations> folderOperations;
|
|
if (_folder.QueryInterface(IID_IFolderOperations, &folderOperations) != S_OK)
|
|
{
|
|
MessageBox(LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208));
|
|
return;
|
|
}
|
|
CPanel::CDisableTimerProcessing disableTimerProcessing2(*this);
|
|
CSelectedState state;
|
|
SaveSelectedState(state);
|
|
CComboDialog comboDialog;
|
|
comboDialog.Title = LangString(IDS_CREATE_FILE, 0x03020240);
|
|
comboDialog.Static = LangString(IDS_CREATE_FILE_NAME, 0x03020241);
|
|
comboDialog.Value = LangString(IDS_CREATE_FILE_DEFAULT_NAME, /*0x03020242*/ (UInt32)-1);
|
|
if (comboDialog.Create(GetParent()) == IDCANCEL)
|
|
return;
|
|
UString newName = comboDialog.Value;
|
|
HRESULT result = folderOperations->CreateFile(newName, 0);
|
|
if (result != S_OK)
|
|
{
|
|
MessageBoxError(result, LangString(IDS_CREATE_FILE_ERROR, 0x03020243));
|
|
return;
|
|
}
|
|
int pos = newName.Find(L'\\');
|
|
if (pos >= 0)
|
|
newName = newName.Left(pos);
|
|
if (!_mySelectMode)
|
|
state.SelectedNames.Clear();
|
|
state.FocusedName = newName;
|
|
state.SelectFocused = true;
|
|
RefreshListCtrl(state);
|
|
}
|
|
|
|
void CPanel::RenameFile()
|
|
{
|
|
int index = _listView.GetFocusedItem();
|
|
if (index >= 0)
|
|
_listView.EditLabel(index);
|
|
}
|
|
|
|
void CPanel::ChangeComment()
|
|
{
|
|
CPanel::CDisableTimerProcessing disableTimerProcessing2(*this);
|
|
int index = _listView.GetFocusedItem();
|
|
if (index < 0)
|
|
return;
|
|
int realIndex = GetRealItemIndex(index);
|
|
if (realIndex == kParentIndex)
|
|
return;
|
|
CSelectedState state;
|
|
SaveSelectedState(state);
|
|
CMyComPtr<IFolderOperations> folderOperations;
|
|
if (_folder.QueryInterface(IID_IFolderOperations, &folderOperations) != S_OK)
|
|
{
|
|
MessageBox(LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208));
|
|
return;
|
|
}
|
|
|
|
UString comment;
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
if (_folder->GetProperty(realIndex, kpidComment, &propVariant) != S_OK)
|
|
return;
|
|
if (propVariant.vt == VT_BSTR)
|
|
comment = propVariant.bstrVal;
|
|
else if (propVariant.vt != VT_EMPTY)
|
|
return;
|
|
}
|
|
UString name = GetItemRelPath(realIndex);
|
|
CComboDialog comboDialog;
|
|
comboDialog.Title = name + L" " + LangString(IDS_COMMENT, 0x03020290);
|
|
comboDialog.Value = comment;
|
|
comboDialog.Static = LangString(IDS_COMMENT2, 0x03020291);
|
|
if (comboDialog.Create(GetParent()) == IDCANCEL)
|
|
return;
|
|
NCOM::CPropVariant propVariant = comboDialog.Value;
|
|
|
|
HRESULT result = folderOperations->SetProperty(realIndex, kpidComment, &propVariant, NULL);
|
|
if (result != S_OK)
|
|
{
|
|
MessageBoxError(result, L"Set Comment Error");
|
|
}
|
|
RefreshListCtrl(state);
|
|
}
|
|
|