mirror of
https://github.com/reactos/reactos.git
synced 2025-04-03 20:21:17 +00:00
[SHELL32] brfolder.cpp: Refresh items (#6965)
Refresh the items in the tree-view control of SHBrowseForFolderA/W functions against change notifications. JIRA issue: CORE-17340 - Add BrFolder_IsTreeItemInEnum and BrFolder_TreeItemHasThisChild helper functions. - Add BrFolder_Refresh, BrFolder_RefreshRecurse, and BrFolder_UpdateItem functions to refresh items. - Call BrFolder_Refresh in BrFolder_OnChangeEx function and on keyboard F5 and Ctrl+R actions.
This commit is contained in:
parent
c3ec1b9ac6
commit
b50ab0dc68
1 changed files with 137 additions and 31 deletions
|
@ -254,6 +254,73 @@ BrFolder_GetName(
|
|||
return bSuccess;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
BrFolder_IsTreeItemInEnum(
|
||||
_Inout_ BrFolder *info,
|
||||
_In_ HTREEITEM hItem,
|
||||
_Inout_ IEnumIDList *pEnum)
|
||||
{
|
||||
BrItemData *pItemData = BrFolder_GetItemData(info, hItem);
|
||||
if (!pItemData)
|
||||
return FALSE;
|
||||
|
||||
pEnum->Reset();
|
||||
|
||||
CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
|
||||
while (pEnum->Next(1, &pidlTemp, NULL) == S_OK)
|
||||
{
|
||||
if (ILIsEqual(pidlTemp, pItemData->pidlChild))
|
||||
return TRUE;
|
||||
|
||||
pidlTemp.Free();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
BrFolder_TreeItemHasThisChild(
|
||||
_In_ BrFolder *info,
|
||||
_In_ HTREEITEM hItem,
|
||||
_Outptr_opt_ PITEMID_CHILD pidlChild)
|
||||
{
|
||||
for (hItem = TreeView_GetChild(info->hwndTreeView, hItem); hItem;
|
||||
hItem = TreeView_GetNextSibling(info->hwndTreeView, hItem))
|
||||
{
|
||||
BrItemData *pItemData = BrFolder_GetItemData(info, hItem);
|
||||
if (ILIsEqual(pItemData->pidlChild, pidlChild))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
BrFolder_UpdateItem(
|
||||
_In_ BrFolder *info,
|
||||
_In_ HTREEITEM hItem)
|
||||
{
|
||||
BrItemData *pItemData = BrFolder_GetItemData(info, hItem);
|
||||
if (!pItemData)
|
||||
return;
|
||||
|
||||
TVITEMW item = { TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN };
|
||||
item.hItem = hItem;
|
||||
|
||||
BrFolder_GetIconPair(pItemData->pidlFull, &item);
|
||||
|
||||
item.cChildren = 0;
|
||||
CComPtr<IEnumIDList> pEnum;
|
||||
if (BrFolder_GetChildrenEnum(info, pItemData, &pEnum) == S_OK)
|
||||
{
|
||||
CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
|
||||
if (pEnum->Next(1, &pidlTemp, NULL) == S_OK)
|
||||
++item.cChildren;
|
||||
}
|
||||
|
||||
TreeView_SetItem(info->hwndTreeView, &item);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* BrFolder_InsertItem [Internal]
|
||||
*
|
||||
|
@ -335,7 +402,7 @@ BrFolder_Expand(
|
|||
SetCapture(info->hWnd);
|
||||
SetCursor(LoadCursorW(NULL, (LPWSTR)IDC_WAIT));
|
||||
|
||||
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlTemp;
|
||||
CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
|
||||
ULONG ulFetched;
|
||||
while (S_OK == pEnum->Next(1, &pidlTemp, &ulFetched))
|
||||
{
|
||||
|
@ -474,7 +541,7 @@ BrFolder_Treeview_Rename(BrFolder *info, NMTVDISPINFOW *pnmtv)
|
|||
return FALSE;
|
||||
|
||||
LPITEMIDLIST newFull;
|
||||
if (SUCCEEDED(hr = SHILClone((LPITEMIDLIST)data->pidlFull, &newFull)))
|
||||
if (SUCCEEDED(hr = SHILClone(data->pidlFull, &newFull)))
|
||||
{
|
||||
ILRemoveLastID(newFull);
|
||||
if (SUCCEEDED(hr = SHILAppend(newChild, &newFull)))
|
||||
|
@ -525,6 +592,9 @@ BrFolder_Delete(BrFolder *info, HTREEITEM hItem)
|
|||
SHFileOperationW(&fileop);
|
||||
}
|
||||
|
||||
static void
|
||||
BrFolder_Refresh(_Inout_ BrFolder *info);
|
||||
|
||||
static LRESULT
|
||||
BrFolder_Treeview_Keydown(BrFolder *info, LPNMTVKEYDOWN keydown)
|
||||
{
|
||||
|
@ -542,6 +612,17 @@ BrFolder_Treeview_Keydown(BrFolder *info, LPNMTVKEYDOWN keydown)
|
|||
case VK_DELETE:
|
||||
BrFolder_Delete(info, hItem);
|
||||
break;
|
||||
case 'R':
|
||||
{
|
||||
if (GetKeyState(VK_CONTROL) < 0) // Ctrl+R
|
||||
BrFolder_Refresh(info);
|
||||
break;
|
||||
}
|
||||
case VK_F5:
|
||||
{
|
||||
BrFolder_Refresh(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1024,24 +1105,63 @@ BrFolder_OnDestroy(BrFolder *info)
|
|||
SHChangeNotifyDeregister(info->hChangeNotify);
|
||||
}
|
||||
|
||||
// Find a treeview node by recursively walking the treeview
|
||||
static HTREEITEM
|
||||
BrFolder_FindItemByPidl(BrFolder *info, PCIDLIST_ABSOLUTE pidlFull, HTREEITEM hItem)
|
||||
static void
|
||||
BrFolder_RefreshRecurse(
|
||||
_Inout_ BrFolder *info,
|
||||
_In_ HTREEITEM hTarget)
|
||||
{
|
||||
BrItemData *item_data = BrFolder_GetItemData(info, hItem);
|
||||
// Get enum
|
||||
CComPtr<IEnumIDList> pEnum;
|
||||
BrItemData *pItemData = BrFolder_GetItemData(info, hTarget);
|
||||
HRESULT hrEnum = BrFolder_GetChildrenEnum(info, pItemData, &pEnum);
|
||||
|
||||
if (ILIsEqual(item_data->pidlFull, pidlFull))
|
||||
return hItem;
|
||||
|
||||
for (hItem = TreeView_GetChild(info->hwndTreeView, hItem); hItem;
|
||||
hItem = TreeView_GetNextSibling(info->hwndTreeView, hItem))
|
||||
// Insert new items
|
||||
if (SUCCEEDED(hrEnum))
|
||||
{
|
||||
HTREEITEM newItem = BrFolder_FindItemByPidl(info, pidlFull, hItem);
|
||||
if (newItem)
|
||||
return newItem;
|
||||
CComHeapPtr<ITEMIDLIST_RELATIVE> pidlTemp;
|
||||
while (S_OK == pEnum->Next(1, &pidlTemp, NULL))
|
||||
{
|
||||
if (!BrFolder_TreeItemHasThisChild(info, hTarget, pidlTemp))
|
||||
{
|
||||
BrFolder_InsertItem(info, pItemData->lpsfParent, pidlTemp, pItemData->pidlFull,
|
||||
hTarget);
|
||||
}
|
||||
pidlTemp.Free();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
// Delete zombie items and update items
|
||||
HTREEITEM hItem, hNextItem;
|
||||
for (hItem = TreeView_GetChild(info->hwndTreeView, hTarget); hItem; hItem = hNextItem)
|
||||
{
|
||||
hNextItem = TreeView_GetNextSibling(info->hwndTreeView, hItem);
|
||||
|
||||
if (FAILED(hrEnum) || !BrFolder_IsTreeItemInEnum(info, hItem, pEnum))
|
||||
{
|
||||
TreeView_DeleteItem(info->hwndTreeView, hItem);
|
||||
hNextItem = TreeView_GetChild(info->hwndTreeView, hTarget);
|
||||
continue;
|
||||
}
|
||||
|
||||
BrFolder_UpdateItem(info, hItem);
|
||||
BrFolder_RefreshRecurse(info, hItem);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hrEnum))
|
||||
TreeView_SortChildren(info->hwndTreeView, hTarget, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
BrFolder_Refresh(_Inout_ BrFolder *info)
|
||||
{
|
||||
HTREEITEM hRoot = TreeView_GetRoot(info->hwndTreeView);
|
||||
|
||||
SendMessageW(info->hwndTreeView, WM_SETREDRAW, FALSE, 0);
|
||||
|
||||
BrFolder_RefreshRecurse(info, hRoot);
|
||||
|
||||
SendMessageW(info->hwndTreeView, WM_SETREDRAW, TRUE, 0);
|
||||
InvalidateRect(info->hwndTreeView, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1058,30 +1178,16 @@ BrFolder_OnChangeEx(
|
|||
case SHCNE_DRIVEADD:
|
||||
case SHCNE_MKDIR:
|
||||
case SHCNE_CREATE:
|
||||
{
|
||||
// FIXME
|
||||
break;
|
||||
}
|
||||
case SHCNE_DRIVEREMOVED:
|
||||
case SHCNE_RMDIR:
|
||||
case SHCNE_DELETE:
|
||||
{
|
||||
HTREEITEM hRoot = TreeView_GetRoot(info->hwndTreeView);
|
||||
for (;;)
|
||||
{
|
||||
HTREEITEM hItem = BrFolder_FindItemByPidl(info, pidl0, hRoot);
|
||||
if (!hItem)
|
||||
break;
|
||||
TreeView_DeleteItem(info->hwndTreeView, hItem);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHCNE_RENAMEFOLDER:
|
||||
case SHCNE_RENAMEITEM:
|
||||
case SHCNE_UPDATEDIR:
|
||||
case SHCNE_UPDATEITEM:
|
||||
{
|
||||
// FIXME
|
||||
// FIXME: Avoid full refresh and optimize for speed. Use pidl0 and pidl1
|
||||
BrFolder_Refresh(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue