Skip to content

Commit cc8ec38

Browse files
authored
[SHELL32] Use SHGDN_FOREDITING when renaming in BrowseForFolder (reactos#7840)
- Use SHGDN_FOREDITING when renaming. - Handle rename change notification without full refresh. - Don't use FS path when deleting. CORE-20064
1 parent c5325f5 commit cc8ec38

File tree

1 file changed

+151
-61
lines changed

1 file changed

+151
-61
lines changed

dll/win32/shell32/brfolder.cpp

Lines changed: 151 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515

1616
WINE_DEFAULT_DEBUG_CHANNEL(shell);
1717

18+
INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, UINT Flags);
19+
1820
#define SHV_CHANGE_NOTIFY (WM_USER + 0x1111)
21+
enum { SHGDN_TREE = SHGDN_NORMAL | SHGDN_INFOLDER };
1922

2023
static LPITEMIDLIST
2124
ILCloneToDepth(LPCITEMIDLIST pidlSrc, UINT depth)
@@ -33,14 +36,6 @@ ILCloneToDepth(LPCITEMIDLIST pidlSrc, UINT depth)
3336
return pidlOut;
3437
}
3538

36-
static INT
37-
GetIconIndex(PCIDLIST_ABSOLUTE pidl, UINT uFlags)
38-
{
39-
SHFILEINFOW sfi;
40-
SHGetFileInfoW((LPCWSTR)pidl, 0, &sfi, sizeof(sfi), uFlags);
41-
return sfi.iIcon;
42-
}
43-
4439
struct BrFolder
4540
{
4641
LPBROWSEINFOW lpBrowseInfo;
@@ -111,11 +106,12 @@ BrFolder_GetItemData(BrFolder *info, HTREEITEM hItem)
111106
}
112107

113108
static SFGAOF
114-
BrFolder_GetItemAttributes(BrFolder *info, HTREEITEM hItem, SFGAOF Att)
109+
BrFolder_GetItemAttributes(BrFolder *info, HTREEITEM hItem, SFGAOF Query)
115110
{
116111
BrItemData *item = BrFolder_GetItemData(info, hItem);
112+
SFGAOF Att = Query;
117113
HRESULT hr = item ? item->lpsfParent->GetAttributesOf(1, &item->pidlChild, &Att) : E_FAIL;
118-
return SUCCEEDED(hr) ? Att : 0;
114+
return SUCCEEDED(hr) ? (Query & Att) : 0;
119115
}
120116

121117
static HRESULT
@@ -203,15 +199,19 @@ BrFolder_InitTreeView(BrFolder *info)
203199
TreeView_Expand(info->hwndTreeView, hItem, TVE_EXPAND);
204200
}
205201

206-
static void
207-
BrFolder_GetIconPair(PCIDLIST_ABSOLUTE pidl, LPTVITEMW pItem)
202+
static HRESULT
203+
BrFolder_GetIconPair(BrItemData &item, TVITEMW &tvi)
208204
{
209-
static const ITEMIDLIST idlDesktop = { };
210-
if (!pidl)
211-
pidl = &idlDesktop;
212-
DWORD flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
213-
pItem->iImage = GetIconIndex(pidl, flags);
214-
pItem->iSelectedImage = GetIconIndex(pidl, flags | SHGFI_OPENICON);
205+
INT open = -1;
206+
INT normal = SHMapPIDLToSystemImageListIndex(item.lpsfParent, item.pidlChild, &open);
207+
if (normal >= 0)
208+
{
209+
tvi.iImage = normal;
210+
tvi.iSelectedImage = (open >= 0) ? open : normal;
211+
return S_OK;
212+
}
213+
tvi.iImage = tvi.iSelectedImage = Shell_GetCachedImageIndexW(swShell32Name, IDI_SHELL_FOLDER - 1, 0);
214+
return S_FALSE;
215215
}
216216

217217
/******************************************************************************
@@ -231,10 +231,10 @@ BrFolder_GetIconPair(PCIDLIST_ABSOLUTE pidl, LPTVITEMW pItem)
231231
*/
232232
static BOOL
233233
BrFolder_GetName(
234-
IShellFolder *lpsf,
235-
PCIDLIST_RELATIVE pidlChild,
236-
DWORD dwFlags,
237-
LPWSTR lpFriendlyName)
234+
_In_ IShellFolder *lpsf,
235+
_In_ PCIDLIST_RELATIVE pidlChild,
236+
_In_ DWORD dwFlags,
237+
_Out_ PWSTR lpFriendlyName)
238238
{
239239
BOOL bSuccess = FALSE;
240240
STRRET str;
@@ -247,6 +247,18 @@ BrFolder_GetName(
247247
return bSuccess;
248248
}
249249

250+
static BOOL
251+
BrFolder_GetName(
252+
_In_ BrFolder *info,
253+
_In_ HTREEITEM hItem,
254+
_In_ UINT Flags,
255+
_Out_ PWSTR Buffer)
256+
{
257+
if (BrItemData *item = BrFolder_GetItemData(info, hItem))
258+
return BrFolder_GetName(item->lpsfParent, item->pidlChild, Flags, Buffer);
259+
return FALSE;
260+
}
261+
250262
static BOOL
251263
BrFolder_IsTreeItemInEnum(
252264
_Inout_ BrFolder *info,
@@ -288,30 +300,82 @@ BrFolder_TreeItemHasThisChild(
288300
return FALSE;
289301
}
290302

291-
static void
292-
BrFolder_UpdateItem(
293-
_In_ BrFolder *info,
294-
_In_ HTREEITEM hItem)
303+
static HTREEITEM
304+
BrFolder_FindTreeItemOfAbsoluteItem(
305+
_In_ BrFolder &info,
306+
_In_ PCIDLIST_ABSOLUTE pidl,
307+
_In_opt_ HTREEITEM hItem = NULL)
295308
{
296-
BrItemData *pItemData = BrFolder_GetItemData(info, hItem);
297-
if (!pItemData)
298-
return;
309+
if (!hItem)
310+
hItem = TreeView_GetRoot(info.hwndTreeView);
299311

300-
TVITEMW item = { TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN };
301-
item.hItem = hItem;
312+
for (; pidl && hItem; hItem = TreeView_GetNextSibling(info.hwndTreeView, hItem))
313+
{
314+
BrItemData *pItemData = BrFolder_GetItemData(&info, hItem);
315+
if (ILIsEqual(pItemData->pidlFull, pidl))
316+
return hItem;
317+
HTREEITEM hChild = TreeView_GetChild(info.hwndTreeView, hItem);
318+
if (hChild && (hChild = BrFolder_FindTreeItemOfAbsoluteItem(info, pidl, hChild)) != NULL)
319+
return hChild;
320+
}
321+
return NULL;
322+
}
302323

303-
BrFolder_GetIconPair(pItemData->pidlFull, &item);
324+
static BOOL
325+
BrFolder_UpdateItemEx(
326+
_In_ BrFolder &info,
327+
_In_ HTREEITEM hItem,
328+
_In_opt_ PCIDLIST_ABSOLUTE pidlFull,
329+
_In_ UINT Flags = TVIF_TEXT | TVIF_IMAGE | TVIF_CHILDREN)
330+
{
331+
ASSERT(hItem);
332+
TVITEMW item = { (TVIF_HANDLE | Flags), hItem };
333+
BrItemData *data = BrFolder_GetItemData(&info, hItem);
334+
if (!data)
335+
return FALSE;
336+
337+
if (pidlFull)
338+
{
339+
if ((pidlFull = ILClone(pidlFull)) == NULL)
340+
return FALSE;
341+
data->pidlFull.Free();
342+
data->pidlFull.Attach(const_cast<PIDLIST_ABSOLUTE>(pidlFull));
343+
data->pidlChild = ILFindLastID(data->pidlFull);
344+
// Note: We assume lpsfParent does not change
345+
}
346+
347+
WCHAR Name[MAX_PATH];
348+
if (Flags & TVIF_TEXT)
349+
{
350+
item.pszText = Name;
351+
if (!BrFolder_GetName(data->lpsfParent, data->pidlChild, SHGDN_TREE, Name))
352+
return FALSE;
353+
}
354+
355+
if (Flags & TVIF_IMAGE)
356+
{
357+
item.mask |= TVIF_SELECTEDIMAGE;
358+
BrFolder_GetIconPair(*data, item);
359+
}
304360

305361
item.cChildren = 0;
306362
CComPtr<IEnumIDList> pEnum;
307-
if (BrFolder_GetChildrenEnum(info, pItemData, &pEnum) == S_OK)
363+
if ((Flags & TVIF_CHILDREN) && BrFolder_GetChildrenEnum(&info, data, &pEnum) == S_OK)
308364
{
309365
CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
310366
if (pEnum->Next(1, &pidlTemp, NULL) == S_OK)
311367
++item.cChildren;
312368
}
313369

314-
TreeView_SetItem(info->hwndTreeView, &item);
370+
return TreeView_SetItem(info.hwndTreeView, &item);
371+
}
372+
373+
static void
374+
BrFolder_UpdateItem(
375+
_In_ BrFolder *info,
376+
_In_ HTREEITEM hItem)
377+
{
378+
BrFolder_UpdateItemEx(*info, hItem, NULL, TVIF_IMAGE | TVIF_CHILDREN);
315379
}
316380

317381
/******************************************************************************
@@ -346,7 +410,7 @@ BrFolder_InsertItem(
346410
}
347411

348412
WCHAR szName[MAX_PATH];
349-
if (!BrFolder_GetName(lpsf, pidlChild, SHGDN_NORMAL, szName))
413+
if (!BrFolder_GetName(lpsf, pidlChild, SHGDN_TREE, szName))
350414
return NULL;
351415

352416
BrItemData *pItemData = new BrItemData();
@@ -358,11 +422,11 @@ BrFolder_InsertItem(
358422

359423
PIDLIST_ABSOLUTE pidlFull =
360424
(pidlParent ? ILCombine(pidlParent, pidlChild) : ILClone(pidlChild));
361-
BrFolder_GetIconPair(pidlFull, &item);
362425

363426
pItemData->lpsfParent = lpsf;
364427
pItemData->pidlFull.Attach(pidlFull);
365428
pItemData->pidlChild = ILFindLastID(pItemData->pidlFull);
429+
BrFolder_GetIconPair(*pItemData, item);
366430

367431
if (BrFolder_GetChildrenEnum(info, pItemData, NULL) == S_OK)
368432
item.cChildren = 1;
@@ -517,7 +581,7 @@ BrFolder_Treeview_Changed(BrFolder *info, NMTREEVIEWW *pnmtv)
517581
info->pidlRet = ILClone(pItemData->pidlFull);
518582

519583
WCHAR szName[MAX_PATH];
520-
if (BrFolder_GetName(pItemData->lpsfParent, pItemData->pidlChild, SHGDN_NORMAL, szName))
584+
if (BrFolder_GetName(pItemData->lpsfParent, pItemData->pidlChild, SHGDN_NORMAL | SHGDN_INFOLDER, szName))
521585
SetDlgItemTextW(info->hWnd, IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT, szName);
522586

523587
BrFolder_Callback(info->lpBrowseInfo, info->hWnd, BFFM_SELCHANGED, (LPARAM)info->pidlRet);
@@ -537,8 +601,8 @@ BrFolder_Treeview_Rename(BrFolder *info, NMTVDISPINFOW *pnmtv)
537601
ASSERT(BrFolder_GetItemAttributes(info, hItem, SFGAO_CANRENAME) & SFGAO_CANRENAME);
538602

539603
PITEMID_CHILD newChild;
540-
HRESULT hr = data->lpsfParent->SetNameOf(info->hWnd, data->pidlChild,
541-
pnmtv->item.pszText, SHGDN_NORMAL, &newChild);
604+
HRESULT hr = data->lpsfParent->SetNameOf(info->hWnd, data->pidlChild, pnmtv->item.pszText,
605+
SHGDN_NORMAL | SHGDN_INFOLDER, &newChild);
542606
if (FAILED(hr))
543607
return FALSE;
544608

@@ -556,10 +620,14 @@ BrFolder_Treeview_Rename(BrFolder *info, NMTVDISPINFOW *pnmtv)
556620
}
557621
ILFree(newChild);
558622

623+
BOOL AllowTreeTextChange = !BrFolder_UpdateItemEx(*info, hItem, NULL, TVIF_TEXT);
624+
559625
NMTREEVIEWW nmtv;
626+
nmtv.itemNew.hItem = hItem;
627+
nmtv.itemNew.mask = TVIF_PARAM;
560628
nmtv.itemNew.lParam = (LPARAM)data;
561629
BrFolder_Treeview_Changed(info, &nmtv);
562-
return TRUE;
630+
return AllowTreeTextChange;
563631
}
564632

565633
static HRESULT
@@ -573,25 +641,18 @@ BrFolder_Rename(BrFolder *info, HTREEITEM hItem)
573641
static void
574642
BrFolder_Delete(BrFolder *info, HTREEITEM hItem)
575643
{
576-
SHFILEOPSTRUCTW fileop = { info->hwndTreeView };
577-
WCHAR szzFrom[MAX_PATH + 1];
578-
579-
// Get item_data
580-
BrItemData *item_data = BrFolder_GetItemData(info, hItem);
581-
582-
// Get the path
583-
if (!SHGetPathFromIDListW(item_data->pidlFull, szzFrom))
584-
{
585-
ERR("SHGetPathFromIDListW failed\n");
644+
BrItemData *data = BrFolder_GetItemData(info, hItem);
645+
if (!data || !BrFolder_GetItemAttributes(info, hItem, SFGAO_CANDELETE))
586646
return;
587-
}
588-
szzFrom[lstrlenW(szzFrom) + 1] = UNICODE_NULL; // Double NULL-terminated
589-
fileop.pFrom = szzFrom;
590-
591-
// Delete folder
592-
fileop.fFlags = FOF_ALLOWUNDO;
593-
fileop.wFunc = FO_DELETE;
594-
SHFileOperationW(&fileop);
647+
CComPtr<IContextMenu> pCM;
648+
if (FAILED(data->lpsfParent->GetUIObjectOf(info->hWnd, 1, &data->pidlChild, IID_NULL_PPV_ARG(IContextMenu, &pCM))))
649+
return;
650+
UINT fCMIC = 0;
651+
if (GetKeyState(VK_SHIFT) < 0)
652+
fCMIC |= CMIC_MASK_SHIFT_DOWN;
653+
if (GetKeyState(VK_CONTROL) < 0)
654+
fCMIC |= CMIC_MASK_CONTROL_DOWN;
655+
SHInvokeCommandOnContextMenu(info->hWnd, NULL, pCM, fCMIC, "delete");
595656
}
596657

597658
static void
@@ -656,9 +717,18 @@ BrFolder_OnNotify(BrFolder *info, UINT CtlID, LPNMHDR lpnmh)
656717
case TVN_BEGINLABELEDITA:
657718
case TVN_BEGINLABELEDITW:
658719
{
720+
HWND hWndEdit = TreeView_GetEditControl(lpnmh->hwndFrom);
659721
NMTVDISPINFO &tvdi = *(NMTVDISPINFO*)lpnmh;
660722
UINT att = BrFolder_GetItemAttributes(info, tvdi.item.hItem, SFGAO_CANRENAME);
661-
return !(att & SFGAO_CANRENAME);
723+
if (!(att & SFGAO_CANRENAME))
724+
{
725+
MessageBeep(0xffffffff);
726+
return S_FALSE;
727+
}
728+
WCHAR Name[MAX_PATH];
729+
if (BrFolder_GetName(info, tvdi.item.hItem, SHGDN_INFOLDER | SHGDN_FOREDITING, Name))
730+
SetWindowTextW(hWndEdit, Name);
731+
return S_OK;
662732
}
663733

664734
case TVN_ENDLABELEDITW:
@@ -1186,11 +1256,31 @@ BrFolder_Refresh(_Inout_ BrFolder *info)
11861256
static void
11871257
BrFolder_OnChangeEx(
11881258
_Inout_ BrFolder *info,
1189-
_In_ PCIDLIST_ABSOLUTE pidl0,
11901259
_In_ PCIDLIST_ABSOLUTE pidl1,
1260+
_In_ PCIDLIST_ABSOLUTE pidl2,
11911261
_In_ LONG event)
11921262
{
1193-
TRACE("(%p)->(%p, %p, 0x%lX)\n", info, pidl0, pidl1, event);
1263+
TRACE("(%p)->(%p, %p, 0x%lX)\n", info, pidl1, pidl2, event);
1264+
1265+
switch (event)
1266+
{
1267+
case SHCNE_RENAMEFOLDER:
1268+
case SHCNE_RENAMEITEM:
1269+
case SHCNE_UPDATEITEM:
1270+
{
1271+
UINT UpdateFlags = (event == SHCNE_UPDATEITEM) ? (TVIF_IMAGE | TVIF_CHILDREN) : (TVIF_TEXT);
1272+
if (HTREEITEM hTI = BrFolder_FindTreeItemOfAbsoluteItem(*info, pidl1))
1273+
{
1274+
if (BrFolder_UpdateItemEx(*info, hTI, pidl2, UpdateFlags))
1275+
{
1276+
if ((hTI = TreeView_GetParent(info->hwndTreeView, hTI)) != NULL)
1277+
TreeView_SortChildren(info->hwndTreeView, hTI, FALSE);
1278+
return;
1279+
}
1280+
}
1281+
break;
1282+
}
1283+
}
11941284

11951285
switch (event)
11961286
{

0 commit comments

Comments
 (0)