1515
1616WINE_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
2023static LPITEMIDLIST
2124ILCloneToDepth (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-
4439struct BrFolder
4540{
4641 LPBROWSEINFOW lpBrowseInfo;
@@ -111,11 +106,12 @@ BrFolder_GetItemData(BrFolder *info, HTREEITEM hItem)
111106}
112107
113108static 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
121117static 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 */
232232static BOOL
233233BrFolder_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+
250262static BOOL
251263BrFolder_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
565633static HRESULT
@@ -573,25 +641,18 @@ BrFolder_Rename(BrFolder *info, HTREEITEM hItem)
573641static void
574642BrFolder_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
597658static 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)
11861256static void
11871257BrFolder_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