This commit is contained in:
Whindmar Saksit 2025-03-30 17:18:05 +02:00 committed by GitHub
commit fb069396e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -15,7 +15,10 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, UINT Flags);
#define SHV_CHANGE_NOTIFY (WM_USER + 0x1111)
enum { SHGDN_TREE = SHGDN_NORMAL | SHGDN_INFOLDER };
static LPITEMIDLIST
ILCloneToDepth(LPCITEMIDLIST pidlSrc, UINT depth)
@ -33,14 +36,6 @@ ILCloneToDepth(LPCITEMIDLIST pidlSrc, UINT depth)
return pidlOut;
}
static INT
GetIconIndex(PCIDLIST_ABSOLUTE pidl, UINT uFlags)
{
SHFILEINFOW sfi;
SHGetFileInfoW((LPCWSTR)pidl, 0, &sfi, sizeof(sfi), uFlags);
return sfi.iIcon;
}
struct BrFolder
{
LPBROWSEINFOW lpBrowseInfo;
@ -111,11 +106,12 @@ BrFolder_GetItemData(BrFolder *info, HTREEITEM hItem)
}
static SFGAOF
BrFolder_GetItemAttributes(BrFolder *info, HTREEITEM hItem, SFGAOF Att)
BrFolder_GetItemAttributes(BrFolder *info, HTREEITEM hItem, SFGAOF Query)
{
BrItemData *item = BrFolder_GetItemData(info, hItem);
SFGAOF Att = Query;
HRESULT hr = item ? item->lpsfParent->GetAttributesOf(1, &item->pidlChild, &Att) : E_FAIL;
return SUCCEEDED(hr) ? Att : 0;
return SUCCEEDED(hr) ? (Query & Att) : 0;
}
static HRESULT
@ -203,15 +199,19 @@ BrFolder_InitTreeView(BrFolder *info)
TreeView_Expand(info->hwndTreeView, hItem, TVE_EXPAND);
}
static void
BrFolder_GetIconPair(PCIDLIST_ABSOLUTE pidl, LPTVITEMW pItem)
static HRESULT
BrFolder_GetIconPair(BrItemData &item, TVITEMW &tvi)
{
static const ITEMIDLIST idlDesktop = { };
if (!pidl)
pidl = &idlDesktop;
DWORD flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
pItem->iImage = GetIconIndex(pidl, flags);
pItem->iSelectedImage = GetIconIndex(pidl, flags | SHGFI_OPENICON);
INT open = -1;
INT normal = SHMapPIDLToSystemImageListIndex(item.lpsfParent, item.pidlChild, &open);
if (normal >= 0)
{
tvi.iImage = normal;
tvi.iSelectedImage = (open >= 0) ? open : normal;
return S_OK;
}
tvi.iImage = tvi.iSelectedImage = Shell_GetCachedImageIndexW(swShell32Name, IDI_SHELL_FOLDER - 1, 0);
return S_FALSE;
}
/******************************************************************************
@ -247,6 +247,18 @@ BrFolder_GetName(
return bSuccess;
}
static BOOL
BrFolder_GetName(
BrFolder *info,
HTREEITEM hItem,
UINT Flags,
PWSTR Buffer)
{
if (BrItemData *item = BrFolder_GetItemData(info, hItem))
return BrFolder_GetName(item->lpsfParent, item->pidlChild, Flags, Buffer);
return FALSE;
}
static BOOL
BrFolder_IsTreeItemInEnum(
_Inout_ BrFolder *info,
@ -288,30 +300,82 @@ BrFolder_TreeItemHasThisChild(
return FALSE;
}
static void
BrFolder_UpdateItem(
_In_ BrFolder *info,
_In_ HTREEITEM hItem)
static HTREEITEM
BrFolder_FindTreeItemOfAbsoluteItem(
BrFolder &info,
PCIDLIST_ABSOLUTE pidl,
HTREEITEM hItem = NULL)
{
BrItemData *pItemData = BrFolder_GetItemData(info, hItem);
if (!pItemData)
return;
if (!hItem)
hItem = TreeView_GetRoot(info.hwndTreeView);
TVITEMW item = { TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN };
item.hItem = hItem;
for (; pidl && hItem; hItem = TreeView_GetNextSibling(info.hwndTreeView, hItem))
{
BrItemData *pItemData = BrFolder_GetItemData(&info, hItem);
if (ILIsEqual(pItemData->pidlFull, pidl))
return hItem;
HTREEITEM hChild = TreeView_GetChild(info.hwndTreeView, hItem);
if (hChild && (hChild = BrFolder_FindTreeItemOfAbsoluteItem(info, pidl, hChild)) != NULL)
return hChild;
}
return NULL;
}
BrFolder_GetIconPair(pItemData->pidlFull, &item);
static BOOL
BrFolder_UpdateItemEx(
_In_ BrFolder &info,
_In_ HTREEITEM hItem,
_In_opt_ PCIDLIST_ABSOLUTE pidlFull,
_In_ UINT Flags = TVIF_TEXT | TVIF_IMAGE | TVIF_CHILDREN)
{
ASSERT(hItem);
TVITEMW item = { (TVIF_HANDLE | Flags), hItem };
BrItemData *data = BrFolder_GetItemData(&info, hItem);
if (!data)
return FALSE;
if (pidlFull)
{
if ((pidlFull = ILClone(pidlFull)) == NULL)
return FALSE;
data->pidlFull.Free();
data->pidlFull.Attach(const_cast<PIDLIST_ABSOLUTE>(pidlFull));
data->pidlChild = ILFindLastID(data->pidlFull);
// Note: We assume lpsfParent does not change
}
WCHAR Name[MAX_PATH];
if (Flags & TVIF_TEXT)
{
item.pszText = Name;
if (!BrFolder_GetName(data->lpsfParent, data->pidlChild, SHGDN_TREE, Name))
return FALSE;
}
if (Flags & TVIF_IMAGE)
{
item.mask |= TVIF_SELECTEDIMAGE;
BrFolder_GetIconPair(*data, item);
}
item.cChildren = 0;
CComPtr<IEnumIDList> pEnum;
if (BrFolder_GetChildrenEnum(info, pItemData, &pEnum) == S_OK)
if ((Flags & TVIF_CHILDREN) && BrFolder_GetChildrenEnum(&info, data, &pEnum) == S_OK)
{
CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
if (pEnum->Next(1, &pidlTemp, NULL) == S_OK)
++item.cChildren;
}
TreeView_SetItem(info->hwndTreeView, &item);
return TreeView_SetItem(info.hwndTreeView, &item);
}
static void
BrFolder_UpdateItem(
_In_ BrFolder *info,
_In_ HTREEITEM hItem)
{
BrFolder_UpdateItemEx(*info, hItem, NULL, TVIF_IMAGE | TVIF_CHILDREN);
}
/******************************************************************************
@ -346,7 +410,7 @@ BrFolder_InsertItem(
}
WCHAR szName[MAX_PATH];
if (!BrFolder_GetName(lpsf, pidlChild, SHGDN_NORMAL, szName))
if (!BrFolder_GetName(lpsf, pidlChild, SHGDN_TREE, szName))
return NULL;
BrItemData *pItemData = new BrItemData();
@ -358,11 +422,11 @@ BrFolder_InsertItem(
PIDLIST_ABSOLUTE pidlFull =
(pidlParent ? ILCombine(pidlParent, pidlChild) : ILClone(pidlChild));
BrFolder_GetIconPair(pidlFull, &item);
pItemData->lpsfParent = lpsf;
pItemData->pidlFull.Attach(pidlFull);
pItemData->pidlChild = ILFindLastID(pItemData->pidlFull);
BrFolder_GetIconPair(*pItemData, item);
if (BrFolder_GetChildrenEnum(info, pItemData, NULL) == S_OK)
item.cChildren = 1;
@ -517,7 +581,7 @@ BrFolder_Treeview_Changed(BrFolder *info, NMTREEVIEWW *pnmtv)
info->pidlRet = ILClone(pItemData->pidlFull);
WCHAR szName[MAX_PATH];
if (BrFolder_GetName(pItemData->lpsfParent, pItemData->pidlChild, SHGDN_NORMAL, szName))
if (BrFolder_GetName(pItemData->lpsfParent, pItemData->pidlChild, SHGDN_NORMAL | SHGDN_INFOLDER, szName))
SetDlgItemTextW(info->hWnd, IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT, szName);
BrFolder_Callback(info->lpBrowseInfo, info->hWnd, BFFM_SELCHANGED, (LPARAM)info->pidlRet);
@ -537,8 +601,8 @@ BrFolder_Treeview_Rename(BrFolder *info, NMTVDISPINFOW *pnmtv)
ASSERT(BrFolder_GetItemAttributes(info, hItem, SFGAO_CANRENAME) & SFGAO_CANRENAME);
PITEMID_CHILD newChild;
HRESULT hr = data->lpsfParent->SetNameOf(info->hWnd, data->pidlChild,
pnmtv->item.pszText, SHGDN_NORMAL, &newChild);
HRESULT hr = data->lpsfParent->SetNameOf(info->hWnd, data->pidlChild, pnmtv->item.pszText,
SHGDN_NORMAL | SHGDN_INFOLDER, &newChild);
if (FAILED(hr))
return FALSE;
@ -556,10 +620,14 @@ BrFolder_Treeview_Rename(BrFolder *info, NMTVDISPINFOW *pnmtv)
}
ILFree(newChild);
BOOL AllowTreeTextChange = !BrFolder_UpdateItemEx(*info, hItem, NULL, TVIF_TEXT);
NMTREEVIEWW nmtv;
nmtv.itemNew.hItem = hItem;
nmtv.itemNew.mask = TVIF_PARAM;
nmtv.itemNew.lParam = (LPARAM)data;
BrFolder_Treeview_Changed(info, &nmtv);
return TRUE;
return AllowTreeTextChange;
}
static HRESULT
@ -573,25 +641,18 @@ BrFolder_Rename(BrFolder *info, HTREEITEM hItem)
static void
BrFolder_Delete(BrFolder *info, HTREEITEM hItem)
{
SHFILEOPSTRUCTW fileop = { info->hwndTreeView };
WCHAR szzFrom[MAX_PATH + 1];
// Get item_data
BrItemData *item_data = BrFolder_GetItemData(info, hItem);
// Get the path
if (!SHGetPathFromIDListW(item_data->pidlFull, szzFrom))
{
ERR("SHGetPathFromIDListW failed\n");
BrItemData *data = BrFolder_GetItemData(info, hItem);
if (!data || !BrFolder_GetItemAttributes(info, hItem, SFGAO_CANDELETE))
return;
}
szzFrom[lstrlenW(szzFrom) + 1] = UNICODE_NULL; // Double NULL-terminated
fileop.pFrom = szzFrom;
// Delete folder
fileop.fFlags = FOF_ALLOWUNDO;
fileop.wFunc = FO_DELETE;
SHFileOperationW(&fileop);
CComPtr<IContextMenu> pCM;
if (FAILED(data->lpsfParent->GetUIObjectOf(info->hWnd, 1, &data->pidlChild, IID_NULL_PPV_ARG(IContextMenu, &pCM))))
return;
UINT fCMIC = 0;
if (GetKeyState(VK_SHIFT) < 0)
fCMIC |= CMIC_MASK_SHIFT_DOWN;
if (GetKeyState(VK_CONTROL) < 0)
fCMIC |= CMIC_MASK_CONTROL_DOWN;
SHInvokeCommandOnContextMenu(info->hWnd, NULL, pCM, fCMIC, "delete");
}
static void
@ -656,9 +717,18 @@ BrFolder_OnNotify(BrFolder *info, UINT CtlID, LPNMHDR lpnmh)
case TVN_BEGINLABELEDITA:
case TVN_BEGINLABELEDITW:
{
HWND hWndEdit = TreeView_GetEditControl(lpnmh->hwndFrom);
NMTVDISPINFO &tvdi = *(NMTVDISPINFO*)lpnmh;
UINT att = BrFolder_GetItemAttributes(info, tvdi.item.hItem, SFGAO_CANRENAME);
return !(att & SFGAO_CANRENAME);
if (!(att & SFGAO_CANRENAME))
{
MessageBeep(0xffffffff);
return S_FALSE;
}
WCHAR Name[MAX_PATH];
if (BrFolder_GetName(info, tvdi.item.hItem, SHGDN_INFOLDER | SHGDN_FOREDITING, Name))
SetWindowTextW(hWndEdit, Name);
return S_OK;
}
case TVN_ENDLABELEDITW:
@ -1186,11 +1256,32 @@ BrFolder_Refresh(_Inout_ BrFolder *info)
static void
BrFolder_OnChangeEx(
_Inout_ BrFolder *info,
_In_ PCIDLIST_ABSOLUTE pidl0,
_In_ PCIDLIST_ABSOLUTE pidl1,
_In_ PCIDLIST_ABSOLUTE pidl2,
_In_ LONG event)
{
TRACE("(%p)->(%p, %p, 0x%lX)\n", info, pidl0, pidl1, event);
TRACE("(%p)->(%p, %p, 0x%lX)\n", info, pidl1, pidl2, event);
HTREEITEM hTI;
switch (event)
{
case SHCNE_RENAMEFOLDER:
case SHCNE_RENAMEITEM:
case SHCNE_UPDATEITEM:
{
UINT UpdateFlags = (event == SHCNE_UPDATEITEM) ? (TVIF_IMAGE | TVIF_CHILDREN) : (TVIF_TEXT);
if ((hTI = BrFolder_FindTreeItemOfAbsoluteItem(*info, pidl1)) != NULL)
{
if (BrFolder_UpdateItemEx(*info, hTI, pidl2, UpdateFlags))
{
if ((hTI = TreeView_GetParent(info->hwndTreeView, hTI)) != NULL)
TreeView_SortChildren(info->hwndTreeView, hTI, FALSE);
return;
}
}
break;
}
}
switch (event)
{