mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
[BROWSEUI]
-CExplorerBand: Commit the last part of the work submitted by Sylvain Deverre. Sorry for not committing all this time. Unfortunately some parts were changed and some parts don't work well and we need to debug it a bit. CORE-10838 svn path=/trunk/; revision=73706
This commit is contained in:
parent
2ee2be0a07
commit
1b634b38ec
2 changed files with 555 additions and 16 deletions
|
@ -28,13 +28,148 @@
|
|||
#define UNIMPLEMENTED DbgPrint("%s is UNIMPLEMENTED!\n", __FUNCTION__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Monitor correctly "external" shell interrupts (seems like we need to register/deregister them for each folder)
|
||||
* - find and fix what cause explorer crashes sometimes (seems to be explorer that does more releases than addref)
|
||||
* - TESTING
|
||||
*/
|
||||
|
||||
typedef struct _PIDLDATA
|
||||
{
|
||||
BYTE type;
|
||||
BYTE data[1];
|
||||
} PIDLDATA, *LPPIDLDATA;
|
||||
|
||||
#define PT_GUID 0x1F
|
||||
#define PT_SHELLEXT 0x2E
|
||||
#define PT_YAGUID 0x70
|
||||
|
||||
static BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl)
|
||||
{
|
||||
LPPIDLDATA lpPData = (LPPIDLDATA)&pidl->mkid.abID;
|
||||
|
||||
return (pidl &&
|
||||
((lpPData && (PT_GUID == lpPData->type || PT_SHELLEXT== lpPData->type ||
|
||||
PT_YAGUID == lpPData->type)) || (pidl && pidl->mkid.cb == 0x00)));
|
||||
}
|
||||
|
||||
static BOOL _ILIsDesktop (LPCITEMIDLIST pidl)
|
||||
{
|
||||
return (pidl && pidl->mkid.cb == 0x00);
|
||||
}
|
||||
|
||||
|
||||
HRESULT GetDisplayName(LPCITEMIDLIST pidlDirectory,TCHAR *szDisplayName,UINT cchMax,DWORD uFlags)
|
||||
{
|
||||
IShellFolder *pShellFolder = NULL;
|
||||
LPCITEMIDLIST pidlRelative = NULL;
|
||||
STRRET str;
|
||||
HRESULT hr;
|
||||
|
||||
if (pidlDirectory == NULL || szDisplayName == NULL)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
hr = SHBindToParent(pidlDirectory, IID_PPV_ARG(IShellFolder, &pShellFolder), &pidlRelative);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pShellFolder->GetDisplayNameOf(pidlRelative,uFlags,&str);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StrRetToBuf(&str,pidlDirectory,szDisplayName,cchMax);
|
||||
}
|
||||
pShellFolder->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
HRESULT WINAPI CExplorerBand_Constructor(REFIID riid, LPVOID *ppv)
|
||||
{
|
||||
#ifdef __REACTOS__
|
||||
return ShellObjectCreator<CExplorerBand>(riid, ppv);
|
||||
#else
|
||||
return S_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
This is a Windows hack, because shell event messages in Windows gives an
|
||||
ill-formed PIDL stripped from useful data that parses incorrectly with SHGetFileInfo.
|
||||
So we need to re-enumerate subfolders until we find one with the same name.
|
||||
*/
|
||||
HRESULT _ReparsePIDL(LPITEMIDLIST buggyPidl, LPITEMIDLIST *cleanPidl)
|
||||
{
|
||||
HRESULT hr;
|
||||
CComPtr<IShellFolder> folder;
|
||||
CComPtr<IPersistFolder2> persist;
|
||||
CComPtr<IEnumIDList> pEnumIDList;
|
||||
LPITEMIDLIST childPidl;
|
||||
LPITEMIDLIST correctChild;
|
||||
LPITEMIDLIST correctParent;
|
||||
ULONG fetched;
|
||||
DWORD EnumFlags;
|
||||
|
||||
|
||||
EnumFlags = SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
|
||||
hr = SHBindToParent(buggyPidl, IID_PPV_ARG(IShellFolder, &folder), (LPCITEMIDLIST*)&childPidl);
|
||||
*cleanPidl = NULL;
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
ERR("Can't bind to parent folder\n");
|
||||
return hr;
|
||||
}
|
||||
hr = folder->QueryInterface(IID_PPV_ARG(IPersistFolder2, &persist));
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
ERR("PIDL doesn't belong to the shell namespace, aborting\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = persist->GetCurFolder(&correctParent);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
ERR("Unable to get current folder\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = folder->EnumObjects(NULL,EnumFlags,&pEnumIDList);
|
||||
// avoid broken IShellFolder implementations that return null pointer with success
|
||||
if (!SUCCEEDED(hr) || !pEnumIDList)
|
||||
{
|
||||
ERR("Can't enum the folder !\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
while(SUCCEEDED(pEnumIDList->Next(1, &correctChild, &fetched)) && correctChild && fetched)
|
||||
{
|
||||
if (!folder->CompareIDs(0, childPidl, correctChild))
|
||||
{
|
||||
*cleanPidl = ILCombine(correctParent, correctChild);
|
||||
ILFree(correctChild);
|
||||
goto Cleanup;
|
||||
}
|
||||
ILFree(correctChild);
|
||||
}
|
||||
Cleanup:
|
||||
ILFree(correctParent);
|
||||
return hr;
|
||||
}
|
||||
|
||||
CExplorerBand::CExplorerBand() :
|
||||
pSite(NULL), fVisible(FALSE), bNavigating(FALSE), dwBandID(0)
|
||||
pSite(NULL), fVisible(FALSE), bNavigating(FALSE), dwBandID(0), pidlCurrent(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CExplorerBand::~CExplorerBand()
|
||||
{
|
||||
if(pidlCurrent)
|
||||
{
|
||||
ILFree(pidlCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
void CExplorerBand::InitializeExplorerBand()
|
||||
|
@ -176,6 +311,11 @@ HRESULT CExplorerBand::UpdateBrowser(LPITEMIDLIST pidlGoto)
|
|||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
if(pidlCurrent)
|
||||
{
|
||||
ILFree(pidlCurrent);
|
||||
pidlCurrent = ILClone(pidlGoto);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -214,6 +354,17 @@ BOOL CExplorerBand::OnTreeItemExpanding(LPNMTREEVIEW pnmtv)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CExplorerBand::OnTreeItemDeleted(LPNMTREEVIEW pnmtv)
|
||||
{
|
||||
/* Destroy memory associated to our node */
|
||||
NodeInfo* ptr = GetNodeInfo(pnmtv->itemNew.hItem);
|
||||
|
||||
ILFree(ptr->relativePidl);
|
||||
ILFree(ptr->absolutePidl);
|
||||
delete ptr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv)
|
||||
{
|
||||
NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
|
||||
|
@ -229,6 +380,29 @@ void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv)
|
|||
//TreeView_Expand(m_hWnd, pnmtv->itemNew.hItem, TVE_EXPAND);
|
||||
}
|
||||
|
||||
void CExplorerBand::OnTreeItemDragging(LPNMTREEVIEW pnmtv, BOOL isRightClick)
|
||||
{
|
||||
CComPtr<IShellFolder> pSrcFolder;
|
||||
CComPtr<IDataObject> pObj;
|
||||
LPCITEMIDLIST pLast;
|
||||
HRESULT hr;
|
||||
DWORD dwEffect;
|
||||
DWORD dwEffect2;
|
||||
|
||||
dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
|
||||
if (!pnmtv->itemNew.lParam)
|
||||
return;
|
||||
NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
|
||||
hr = SHBindToParent(pNodeInfo->absolutePidl, IID_PPV_ARG(IShellFolder, &pSrcFolder), &pLast);
|
||||
if (!SUCCEEDED(hr))
|
||||
return;
|
||||
hr = pSrcFolder->GetUIObjectOf(m_hWnd, 1, &pLast, IID_IDataObject, 0, reinterpret_cast<void**>(&pObj));
|
||||
if (!SUCCEEDED(hr))
|
||||
return;
|
||||
DoDragDrop(pObj, this, dwEffect, &dwEffect2);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// *** ATL event handlers ***
|
||||
LRESULT CExplorerBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
||||
|
@ -323,6 +497,64 @@ LRESULT CExplorerBand::ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam,
|
|||
}
|
||||
return FALSE; /* let the wndproc process the message */
|
||||
}
|
||||
|
||||
LRESULT CExplorerBand::OnShellEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
||||
{
|
||||
LPITEMIDLIST *dest;
|
||||
LPITEMIDLIST clean;
|
||||
HTREEITEM pItem;
|
||||
|
||||
dest = (LPITEMIDLIST*)wParam;
|
||||
/* TODO: handle shell notifications */
|
||||
switch(lParam & ~SHCNE_INTERRUPT)
|
||||
{
|
||||
case SHCNE_MKDIR:
|
||||
if (!SUCCEEDED(_ReparsePIDL(dest[0], &clean)))
|
||||
{
|
||||
ERR("Can't reparse PIDL to a valid one\n");
|
||||
return FALSE;
|
||||
}
|
||||
NavigateToPIDL(clean, &pItem, FALSE, TRUE, FALSE);
|
||||
ILFree(clean);
|
||||
break;
|
||||
case SHCNE_RMDIR:
|
||||
DeleteItem(dest[0]);
|
||||
break;
|
||||
case SHCNE_RENAMEFOLDER:
|
||||
if (!SUCCEEDED(_ReparsePIDL(dest[1], &clean)))
|
||||
{
|
||||
ERR("Can't reparse PIDL to a valid one\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (NavigateToPIDL(dest[0], &pItem, FALSE, FALSE, FALSE))
|
||||
RenameItem(pItem, clean);
|
||||
ILFree(clean);
|
||||
break;
|
||||
case SHCNE_UPDATEDIR:
|
||||
// We don't take care of this message
|
||||
TRACE("Directory updated\n");
|
||||
break;
|
||||
default:
|
||||
TRACE("Unhandled message\n");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LRESULT CExplorerBand::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
||||
{
|
||||
bFocused = TRUE;
|
||||
IUnknown_OnFocusChangeIS(pSite, reinterpret_cast<IUnknown*>(this), TRUE);
|
||||
bHandled = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LRESULT CExplorerBand::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
||||
{
|
||||
IUnknown_OnFocusChangeIS(pSite, reinterpret_cast<IUnknown*>(this), FALSE);
|
||||
bHandled = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// *** Helper functions ***
|
||||
HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, IShellFolder *psfParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort)
|
||||
{
|
||||
|
@ -377,6 +609,15 @@ HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, IShellFolder *psfParent,
|
|||
|
||||
htiCreated = TreeView_InsertItem(m_hWnd, &tvInsert);
|
||||
|
||||
if (bSort)
|
||||
{
|
||||
TVSORTCB sortCallback;
|
||||
sortCallback.hParent = hParent;
|
||||
sortCallback.lpfnCompare = CompareTreeItems;
|
||||
sortCallback.lParam = (LPARAM)this;
|
||||
SendMessage(TVM_SORTCHILDRENCB, 0, (LPARAM)&sortCallback);
|
||||
}
|
||||
|
||||
return htiCreated;
|
||||
}
|
||||
|
||||
|
@ -401,6 +642,7 @@ BOOL CExplorerBand::InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo)
|
|||
ULONG fetched;
|
||||
ULONG uItemCount;
|
||||
CComPtr<IShellFolder> pFolder;
|
||||
TVSORTCB sortCallback;
|
||||
|
||||
entry = pNodeInfo->absolutePidl;
|
||||
fetched = 1;
|
||||
|
@ -458,6 +700,11 @@ BOOL CExplorerBand::InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo)
|
|||
ILFree(pidlSub);
|
||||
}
|
||||
pNodeInfo->expanded = TRUE;
|
||||
/* Let's do sorting */
|
||||
sortCallback.hParent = hItem;
|
||||
sortCallback.lpfnCompare = CompareTreeItems;
|
||||
sortCallback.lParam = (LPARAM)this;
|
||||
SendMessage(TVM_SORTCHILDRENCB, 0, (LPARAM)&sortCallback);
|
||||
|
||||
/* Now we can redraw */
|
||||
SendMessage(WM_SETREDRAW, TRUE, 0);
|
||||
|
@ -596,6 +843,184 @@ BOOL CExplorerBand::NavigateToCurrentFolder()
|
|||
return result;
|
||||
}
|
||||
|
||||
BOOL CExplorerBand::DeleteItem(LPITEMIDLIST idl)
|
||||
{
|
||||
HTREEITEM toDelete;
|
||||
TVITEM tvItem;
|
||||
HTREEITEM parentNode;
|
||||
|
||||
if (!NavigateToPIDL(idl, &toDelete, FALSE, FALSE, FALSE))
|
||||
return FALSE;
|
||||
|
||||
// TODO: check that the treeview item is really deleted
|
||||
|
||||
parentNode = TreeView_GetParent(m_hWnd, toDelete);
|
||||
// Navigate to parent when deleting child item
|
||||
if (!pDesktop->CompareIDs(0, idl, pidlCurrent))
|
||||
{
|
||||
TreeView_SelectItem(m_hWnd, parentNode);
|
||||
}
|
||||
|
||||
// Remove the child item
|
||||
TreeView_DeleteItem(m_hWnd, toDelete);
|
||||
// Probe parent to see if it has children
|
||||
if (!TreeView_GetChild(m_hWnd, parentNode))
|
||||
{
|
||||
// Decrement parent's child count
|
||||
ZeroMemory(&tvItem, sizeof(tvItem));
|
||||
tvItem.mask = TVIF_CHILDREN;
|
||||
tvItem.hItem = parentNode;
|
||||
tvItem.cChildren = 0;
|
||||
TreeView_SetItem(m_hWnd, &tvItem);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CExplorerBand::RenameItem(HTREEITEM toRename, LPITEMIDLIST newPidl)
|
||||
{
|
||||
WCHAR wszDisplayName[MAX_PATH];
|
||||
TVITEM itemInfo;
|
||||
LPCITEMIDLIST relPidl;
|
||||
NodeInfo *treeInfo;
|
||||
TVSORTCB sortCallback;
|
||||
HTREEITEM child;
|
||||
|
||||
ZeroMemory(&itemInfo, sizeof(itemInfo));
|
||||
itemInfo.mask = TVIF_PARAM;
|
||||
itemInfo.hItem = toRename;
|
||||
|
||||
// Change PIDL associated to the item
|
||||
relPidl = ILFindLastID(newPidl);
|
||||
TreeView_GetItem(m_hWnd, &itemInfo);
|
||||
if (!itemInfo.lParam)
|
||||
{
|
||||
ERR("Unable to fetch lParam\n");
|
||||
return FALSE;
|
||||
}
|
||||
SendMessage(WM_SETREDRAW, FALSE, 0);
|
||||
treeInfo = (NodeInfo*)itemInfo.lParam;
|
||||
ILFree(treeInfo->absolutePidl);
|
||||
ILFree(treeInfo->relativePidl);
|
||||
treeInfo->absolutePidl = ILClone(newPidl);
|
||||
treeInfo->relativePidl = ILClone(relPidl);
|
||||
|
||||
// Change the display name
|
||||
GetDisplayName(newPidl, wszDisplayName, MAX_PATH, SHGDN_INFOLDER);
|
||||
ZeroMemory(&itemInfo, sizeof(itemInfo));
|
||||
itemInfo.hItem = toRename;
|
||||
itemInfo.mask = TVIF_TEXT;
|
||||
itemInfo.pszText = wszDisplayName;
|
||||
TreeView_SetItem(m_hWnd, &itemInfo);
|
||||
|
||||
if((child = TreeView_GetChild(m_hWnd, toRename)) != NULL)
|
||||
{
|
||||
RefreshTreePidl(child, newPidl);
|
||||
}
|
||||
|
||||
// Sorting
|
||||
sortCallback.hParent = TreeView_GetParent(m_hWnd, toRename);
|
||||
sortCallback.lpfnCompare = CompareTreeItems;
|
||||
sortCallback.lParam = (LPARAM)this;
|
||||
SendMessage(TVM_SORTCHILDRENCB, 0, (LPARAM)&sortCallback);
|
||||
SendMessage(WM_SETREDRAW, TRUE, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CExplorerBand::RefreshTreePidl(HTREEITEM tree, LPITEMIDLIST pidlParent)
|
||||
{
|
||||
HTREEITEM tmp;
|
||||
NodeInfo *pInfo;
|
||||
|
||||
// Update our node data
|
||||
pInfo = GetNodeInfo(tree);
|
||||
if (!pInfo)
|
||||
{
|
||||
WARN("No tree info !\n");
|
||||
return FALSE;
|
||||
}
|
||||
ILFree(pInfo->absolutePidl);
|
||||
pInfo->absolutePidl = ILCombine(pidlParent, pInfo->relativePidl);
|
||||
if (!pInfo->absolutePidl)
|
||||
{
|
||||
WARN("PIDL allocation failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
// Recursively update children
|
||||
if ((tmp = TreeView_GetChild(m_hWnd, tree)) != NULL)
|
||||
{
|
||||
RefreshTreePidl(tmp, pInfo->absolutePidl);
|
||||
}
|
||||
|
||||
tmp = TreeView_GetNextSibling(m_hWnd, tree);
|
||||
while(tmp != NULL)
|
||||
{
|
||||
pInfo = GetNodeInfo(tmp);
|
||||
if(!pInfo)
|
||||
{
|
||||
WARN("No tree info !\n");
|
||||
continue;
|
||||
}
|
||||
ILFree(pInfo->absolutePidl);
|
||||
pInfo->absolutePidl = ILCombine(pidlParent, pInfo->relativePidl);
|
||||
tmp = TreeView_GetNextSibling(m_hWnd, tmp);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// *** Tree item sorting callback ***
|
||||
int CALLBACK CExplorerBand::CompareTreeItems(LPARAM p1, LPARAM p2, LPARAM p3)
|
||||
{
|
||||
/*
|
||||
* We first sort drive letters (Path root), then PIDLs and then regular folder
|
||||
* display name.
|
||||
* This is not how Windows sorts item, but it gives decent results.
|
||||
*/
|
||||
NodeInfo *info1;
|
||||
NodeInfo *info2;
|
||||
CExplorerBand *pThis;
|
||||
WCHAR wszFolder1[MAX_PATH];
|
||||
WCHAR wszFolder2[MAX_PATH];
|
||||
|
||||
info1 = (NodeInfo*)p1;
|
||||
info2 = (NodeInfo*)p2;
|
||||
pThis = (CExplorerBand*)p3;
|
||||
|
||||
GetDisplayName(info1->absolutePidl, wszFolder1, MAX_PATH, SHGDN_FORPARSING);
|
||||
GetDisplayName(info2->absolutePidl, wszFolder2, MAX_PATH, SHGDN_FORPARSING);
|
||||
if (PathIsRoot(wszFolder1) && PathIsRoot(wszFolder2))
|
||||
{
|
||||
return lstrcmpiW(wszFolder1,wszFolder2);
|
||||
}
|
||||
if (PathIsRoot(wszFolder1) && !PathIsRoot(wszFolder2))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!PathIsRoot(wszFolder1) && PathIsRoot(wszFolder2))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
// Now, we compare non-root folders, grab display name
|
||||
GetDisplayName(info1->absolutePidl, wszFolder1, MAX_PATH, SHGDN_INFOLDER);
|
||||
GetDisplayName(info2->absolutePidl, wszFolder2, MAX_PATH, SHGDN_INFOLDER);
|
||||
|
||||
if (_ILIsSpecialFolder(info1->relativePidl) && !_ILIsSpecialFolder(info2->relativePidl))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!_ILIsSpecialFolder(info1->relativePidl) && _ILIsSpecialFolder(info2->relativePidl))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (_ILIsSpecialFolder(info1->relativePidl) && !_ILIsSpecialFolder(info2->relativePidl))
|
||||
{
|
||||
HRESULT hr;
|
||||
hr = pThis->pDesktop->CompareIDs(0, info1->absolutePidl, info2->absolutePidl);
|
||||
if (!hr) return 0;
|
||||
return (hr > 0) ? -1 : 1;
|
||||
}
|
||||
return StrCmpLogicalW(wszFolder1, wszFolder2);
|
||||
}
|
||||
|
||||
// *** IOleWindow methods ***
|
||||
HRESULT STDMETHODCALLTYPE CExplorerBand::GetWindow(HWND *lphwnd)
|
||||
{
|
||||
|
@ -835,6 +1260,7 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::Save(IStream *pStm, BOOL fClearDirty)
|
|||
|
||||
HRESULT STDMETHODCALLTYPE CExplorerBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
|
||||
{
|
||||
// TODO: calculate max size
|
||||
UNIMPLEMENTED;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
@ -855,10 +1281,16 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM
|
|||
case TVN_SELCHANGED:
|
||||
OnSelectionChanged((LPNMTREEVIEW)lParam);
|
||||
break;
|
||||
case TVN_DELETEITEM:
|
||||
OnTreeItemDeleted((LPNMTREEVIEW)lParam);
|
||||
break;
|
||||
case NM_RCLICK:
|
||||
OnContextMenu(WM_CONTEXTMENU, (WPARAM)m_hWnd, GetMessagePos(), bHandled);
|
||||
*theResult = 1;
|
||||
break;
|
||||
case TVN_BEGINDRAG:
|
||||
case TVN_BEGINRDRAG:
|
||||
OnTreeItemDragging((LPNMTREEVIEW)lParam, pNotifyHeader->code == TVN_BEGINRDRAG);
|
||||
case TVN_BEGINLABELEDITW:
|
||||
{
|
||||
// TODO: put this in a function ? (mostly copypasta from CDefView)
|
||||
|
@ -1009,37 +1441,120 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::Invoke(DISPID dispIdMember, REFIID riid
|
|||
// *** IDropTarget methods ***
|
||||
HRESULT STDMETHODCALLTYPE CExplorerBand::DragEnter(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return E_NOTIMPL;
|
||||
ERR("Entering drag\n");
|
||||
pCurObject = pObj;
|
||||
oldSelected = TreeView_GetSelection(m_hWnd);
|
||||
return DragOver(glfKeyState, pt, pdwEffect);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CExplorerBand::DragOver(DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return E_NOTIMPL;
|
||||
TVHITTESTINFO info;
|
||||
CComPtr<IShellFolder> pShellFldr;
|
||||
NodeInfo *nodeInfo;
|
||||
//LPCITEMIDLIST pChild;
|
||||
HRESULT hr;
|
||||
|
||||
info.pt.x = pt.x;
|
||||
info.pt.y = pt.y;
|
||||
info.flags = TVHT_ONITEM;
|
||||
info.hItem = NULL;
|
||||
ScreenToClient(&info.pt);
|
||||
|
||||
// Move to the item selected by the treeview (don't change right pane)
|
||||
TreeView_HitTest(m_hWnd, &info);
|
||||
|
||||
if (info.hItem)
|
||||
{
|
||||
bNavigating = TRUE;
|
||||
TreeView_SelectItem(m_hWnd, info.hItem);
|
||||
bNavigating = FALSE;
|
||||
// Delegate to shell folder
|
||||
if (pDropTarget && info.hItem != childTargetNode)
|
||||
{
|
||||
pDropTarget = NULL;
|
||||
}
|
||||
if (info.hItem != childTargetNode)
|
||||
{
|
||||
nodeInfo = GetNodeInfo(info.hItem);
|
||||
if (!nodeInfo)
|
||||
return E_FAIL;
|
||||
#if 0
|
||||
hr = SHBindToParent(nodeInfo->absolutePidl, IID_PPV_ARG(IShellFolder, &pShellFldr), &pChild);
|
||||
if (!SUCCEEDED(hr))
|
||||
return E_FAIL;
|
||||
hr = pShellFldr->GetUIObjectOf(m_hWnd, 1, &pChild, IID_IDropTarget, NULL, reinterpret_cast<void**>(&pDropTarget));
|
||||
if (!SUCCEEDED(hr))
|
||||
return E_FAIL;
|
||||
#endif
|
||||
if(_ILIsDesktop(nodeInfo->absolutePidl))
|
||||
pShellFldr = pDesktop;
|
||||
else
|
||||
{
|
||||
hr = pDesktop->BindToObject(nodeInfo->absolutePidl, 0, IID_PPV_ARG(IShellFolder, &pShellFldr));
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
/* Don't allow dnd since we couldn't get our folder object */
|
||||
ERR("Can't bind to folder object\n");
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
hr = pShellFldr->CreateViewObject(m_hWnd, IID_PPV_ARG(IDropTarget, &pDropTarget));
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
/* Don't allow dnd since we couldn't get our drop target */
|
||||
ERR("Can't get drop target for folder object\n");
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
return E_FAIL;
|
||||
}
|
||||
hr = pDropTarget->DragEnter(pCurObject, glfKeyState, pt, pdwEffect);
|
||||
childTargetNode = info.hItem;
|
||||
}
|
||||
hr = pDropTarget->DragOver(glfKeyState, pt, pdwEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
childTargetNode = NULL;
|
||||
pDropTarget = NULL;
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CExplorerBand::DragLeave()
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return E_NOTIMPL;
|
||||
bNavigating = TRUE;
|
||||
TreeView_SelectItem(m_hWnd, oldSelected);
|
||||
bNavigating = FALSE;
|
||||
childTargetNode = NULL;
|
||||
if (pCurObject)
|
||||
{
|
||||
pCurObject = NULL;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CExplorerBand::Drop(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return E_NOTIMPL;
|
||||
if (!pDropTarget)
|
||||
return E_FAIL;
|
||||
pDropTarget->Drop(pObj, glfKeyState, pt, pdwEffect);
|
||||
DragLeave();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// *** IDropSource methods ***
|
||||
HRESULT STDMETHODCALLTYPE CExplorerBand::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return E_NOTIMPL;
|
||||
if (fEscapePressed)
|
||||
return DRAGDROP_S_CANCEL;
|
||||
if ((grfKeyState & MK_LBUTTON) || (grfKeyState & MK_RBUTTON))
|
||||
return S_OK;
|
||||
return DRAGDROP_S_DROP;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CExplorerBand::GiveFeedback(DWORD dwEffect)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return E_NOTIMPL;
|
||||
return DRAGDROP_S_USEDEFAULTCURSORS;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ private:
|
|||
// *** BaseBarSite information ***
|
||||
CComPtr<IUnknown> pSite;
|
||||
CComPtr<IShellFolder> pDesktop;
|
||||
|
||||
|
||||
// *** tree explorer band stuff ***
|
||||
BOOL fVisible;
|
||||
BOOL bNavigating;
|
||||
|
@ -62,21 +62,33 @@ private:
|
|||
HIMAGELIST hImageList;
|
||||
HTREEITEM hRoot;
|
||||
HTREEITEM oldSelected;
|
||||
|
||||
LPITEMIDLIST pidlCurrent;
|
||||
|
||||
// *** notification cookies ***
|
||||
DWORD adviseCookie;
|
||||
ULONG shellRegID;
|
||||
|
||||
|
||||
// *** Drop target information ***
|
||||
CComPtr<IDropTarget> pDropTarget;
|
||||
HTREEITEM childTargetNode;
|
||||
CComPtr<IDataObject> pCurObject;
|
||||
|
||||
void InitializeExplorerBand();
|
||||
void DestroyExplorerBand();
|
||||
HRESULT ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd);
|
||||
|
||||
// *** notifications handling ***
|
||||
BOOL OnTreeItemExpanding(LPNMTREEVIEW pnmtv);
|
||||
void OnSelectionChanged(LPNMTREEVIEW pnmtv);
|
||||
BOOL OnTreeItemDeleted(LPNMTREEVIEW pnmtv);
|
||||
void OnTreeItemDragging(LPNMTREEVIEW pnmtv, BOOL isRightClick);
|
||||
|
||||
// *** ATL event handlers ***
|
||||
LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||
LRESULT ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||
LRESULT OnShellEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||
LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||
LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
|
||||
|
||||
// *** Helper functions ***
|
||||
NodeInfo* GetNodeInfo(HTREEITEM hItem);
|
||||
|
@ -85,8 +97,14 @@ private:
|
|||
HTREEITEM InsertItem(HTREEITEM hParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort);
|
||||
BOOL InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo);
|
||||
BOOL NavigateToPIDL(LPITEMIDLIST dest, HTREEITEM *item, BOOL bExpand, BOOL bInsert, BOOL bSelect);
|
||||
BOOL DeleteItem(LPITEMIDLIST toDelete);
|
||||
BOOL RenameItem(HTREEITEM toRename, LPITEMIDLIST newPidl);
|
||||
BOOL RefreshTreePidl(HTREEITEM tree, LPITEMIDLIST pidlParent);
|
||||
BOOL NavigateToCurrentFolder();
|
||||
|
||||
// *** Tree item sorting callback ***
|
||||
static int CALLBACK CompareTreeItems(LPARAM p1, LPARAM p2, LPARAM p3);
|
||||
|
||||
public:
|
||||
CExplorerBand();
|
||||
virtual ~CExplorerBand();
|
||||
|
@ -181,6 +199,12 @@ public:
|
|||
|
||||
BEGIN_MSG_MAP(CExplorerBand)
|
||||
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
|
||||
MESSAGE_HANDLER(WM_USER_SHELLEVENT, OnShellEvent)
|
||||
MESSAGE_HANDLER(WM_RBUTTONDOWN, ContextMenuHack)
|
||||
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
|
||||
// MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
|
||||
END_MSG_MAP()
|
||||
};
|
||||
|
||||
extern "C"
|
||||
HRESULT WINAPI CExplorerBand_Constructor(REFIID riid, LPVOID *ppv);
|
||||
|
|
Loading…
Reference in a new issue