1304 lines
30 KiB
C++
1304 lines
30 KiB
C++
// OXShellFolderTree.cpp : implementation file
|
|
//
|
|
// Version: 9.3
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "OXShellFolderTree.h"
|
|
#include "OXMainRes.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
// image index for the desktop item
|
|
const int IDI_DESKTOPIMAGE_INDEX=34;
|
|
// delimiter for filter
|
|
const TCHAR OXSHELLTREE_EXT_DELIMITER=_T('|');
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXShellFolderTree
|
|
|
|
COXShellFolderTree::COXShellFolderTree(BOOL bEnableContextMenu/*=TRUE*/,
|
|
BOOL bOnlyFileSystemFolders/*=TRUE*/,
|
|
BOOL bNotifyError/*=TRUE*/,
|
|
BOOL bShowDesktopItem/*=TRUE*/,
|
|
BOOL bShowFiles/*=FALSE*/,
|
|
LPCTSTR lpszFilter/*=_T("")*/) :
|
|
m_hShellImageList(NULL),
|
|
m_bEditingItem(FALSE),
|
|
m_nRedraw(0),
|
|
m_hContextMenuItem(NULL),
|
|
m_bNoRestoreContextMenuItem(FALSE)
|
|
{
|
|
SetEnableContextMenu(bEnableContextMenu);
|
|
SetOnlyFileSystemFolders(bOnlyFileSystemFolders);
|
|
SetNotifyError(bNotifyError);
|
|
|
|
SetShowFiles(bShowFiles);
|
|
SetShowDesktopItem(bShowDesktopItem);
|
|
|
|
SetFilter(lpszFilter);
|
|
}
|
|
|
|
COXShellFolderTree::~COXShellFolderTree()
|
|
{
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(COXShellFolderTree, CTreeCtrl)
|
|
//{{AFX_MSG_MAP(COXShellFolderTree)
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_RBUTTONDOWN()
|
|
ON_WM_RBUTTONUP()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_CANCELMODE()
|
|
ON_WM_CAPTURECHANGED()
|
|
// ON_NOTIFY_REFLECT_EX(NM_RCLICK, OnRClick)
|
|
ON_NOTIFY_REFLECT_EX(NM_DBLCLK, OnDblClick)
|
|
ON_NOTIFY_REFLECT_EX(TVN_ITEMEXPANDING, OnItemExpanding)
|
|
ON_NOTIFY_REFLECT_EX(TVN_BEGINLABELEDIT, OnBeginLabelEdit)
|
|
ON_NOTIFY_REFLECT_EX(TVN_ENDLABELEDIT, OnEndLabelEdit)
|
|
#ifdef OXSHELLTREE_WATCHFORDIR
|
|
ON_MESSAGE(WM_OX_FILE_NOTIFY, OnDirChangeNotify)
|
|
#endif // OXSHELLTREE_WATCHFORDIR
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXShellFolderTree message handlers
|
|
|
|
BOOL COXShellFolderTree::PreCreateWindow(CREATESTRUCT& cs)
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
|
|
return CTreeCtrl::PreCreateWindow(cs);
|
|
}
|
|
|
|
void COXShellFolderTree::PreSubclassWindow()
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
|
|
CTreeCtrl::PreSubclassWindow();
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::InitializeTree(CString sFolderStartFrom/*=_T("")*/)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
if(!::IsWindow(GetSafeHwnd()))
|
|
return FALSE;
|
|
|
|
SetNotifyError(m_bNotifyError);
|
|
|
|
// use system image list as tree control's image list
|
|
//
|
|
int nDesktopItemImageIndex=0;
|
|
if((HIMAGELIST)m_imageList!=NULL)
|
|
m_imageList.DeleteImageList();
|
|
m_mapImageIndex.RemoveAll();
|
|
// retrieve Shell image list
|
|
if(m_hShellImageList==NULL)
|
|
{
|
|
m_hShellImageList=m_navigator.GetShellImageList();
|
|
if(m_hShellImageList==NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
IMAGEINFO imageInfo;
|
|
VERIFY(ImageList_GetImageInfo(m_hShellImageList,0,&imageInfo));
|
|
|
|
CRect rect(imageInfo.rcImage);
|
|
VERIFY(m_imageList.Create(rect.Width(),rect.Height(),ILC_COLOR32|ILC_MASK,0,0));
|
|
HICON hIcon=::ExtractIcon(
|
|
AfxGetInstanceHandle(),_T("shell32.dll"),IDI_DESKTOPIMAGE_INDEX);
|
|
ASSERT(hIcon!=NULL);
|
|
nDesktopItemImageIndex=m_imageList.Add(hIcon);
|
|
ASSERT(nDesktopItemImageIndex!=-1);
|
|
VERIFY(::DestroyIcon(hIcon));
|
|
|
|
|
|
SetImageList(&m_imageList,TVSIL_NORMAL);
|
|
|
|
|
|
// now let's fill TreeCtrl with shell namespace objects that is located
|
|
// in sFolderStartFrom folder. If sFolderStartFrom is NULL then we use
|
|
// Desktop as start folder
|
|
|
|
// shell folder returned by that function have to be released afterwards
|
|
LPSHELLFOLDER lpFolder=m_navigator.GetShellFolder(sFolderStartFrom);
|
|
if(lpFolder==NULL)
|
|
return FALSE;
|
|
|
|
LPITEMIDLIST lpidlFull;
|
|
if(!m_navigator.GetShellFolderFullIDL(sFolderStartFrom,&lpidlFull))
|
|
{
|
|
// Release the folder
|
|
lpFolder->Release();
|
|
return FALSE;
|
|
}
|
|
|
|
// unselect item
|
|
SelectItem(NULL);
|
|
|
|
// Clean up TreeCtrl
|
|
DeleteAllItems();
|
|
|
|
HTREEITEM htiRoot=TVI_ROOT;
|
|
if(m_bShowDesktopItem)
|
|
{
|
|
// structures for inserting new items in our TreeCtrl
|
|
TV_INSERTSTRUCT tvins;
|
|
|
|
tvins.item.mask=TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|
|
|
TVIF_PARAM|TVIF_CHILDREN;
|
|
// NAMESPACEOBJECT object is not defined for Desktop item
|
|
tvins.item.lParam=(LPARAM)NULL;
|
|
// Desktop item always has subfolders
|
|
tvins.item.cChildren=1;
|
|
// display name
|
|
CString sItem;
|
|
VERIFY(sItem.LoadString(IDS_OX_SHELLFOLDERTREEDESKTOP));//"Desktop"
|
|
tvins.item.pszText=(LPTSTR) (LPCTSTR) sItem;
|
|
|
|
// Request icon index for normal state
|
|
tvins.item.iImage=nDesktopItemImageIndex;
|
|
tvins.item.iSelectedImage=nDesktopItemImageIndex;
|
|
// expanded from the beginning
|
|
tvins.item.state=TVIS_EXPANDED|TVIS_EXPANDEDONCE;
|
|
tvins.item.stateMask=tvins.item.state;
|
|
|
|
// We collected all information we needed. It's time to insert
|
|
// new item in our TreeCtrl.
|
|
tvins.hInsertAfter=TVI_LAST;
|
|
tvins.hParent=TVI_ROOT;
|
|
htiRoot=InsertItem(&tvins);
|
|
ASSERT(htiRoot!=NULL);
|
|
}
|
|
|
|
// Fill TreeCtrl with objects in lpFolder folder.
|
|
FillTreeWithSubfolders(htiRoot,lpFolder,lpidlFull);
|
|
|
|
lpFolder->Release();
|
|
|
|
// We cannot sort item using just their display names. We have to
|
|
// request shell to sort items.
|
|
SortChildren(TVI_ROOT);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::OpenFolder(CString sFolderToOpen,
|
|
BOOL bExpand/*=FALSE*/)
|
|
{
|
|
if(sFolderToOpen.IsEmpty())
|
|
return TRUE;
|
|
|
|
LPITEMIDLIST lpidlFull;
|
|
if(!m_navigator.GetShellFolderFullIDL(sFolderToOpen,&lpidlFull))
|
|
return FALSE;
|
|
return OpenFolder(lpidlFull,bExpand);
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::OpenFolder(const LPITEMIDLIST lpFullIDL,
|
|
BOOL bExpand/*=FALSE*/)
|
|
{
|
|
if(lpFullIDL==NULL)
|
|
return FALSE;
|
|
|
|
HTREEITEM hItem=GetRootItem();
|
|
ASSERT(hItem!=NULL);
|
|
if(m_bShowDesktopItem)
|
|
{
|
|
hItem=GetNextItem(hItem,TVGN_CHILD);
|
|
ASSERT(hItem!=NULL);
|
|
}
|
|
|
|
LPITEMIDLIST pidlCopy=lpFullIDL;
|
|
LPITEMIDLIST pidlNext=NULL;
|
|
BOOL bFound=FALSE;
|
|
while(pidlCopy!=NULL)
|
|
{
|
|
pidlNext=m_navigator.GetNextIDLItem(pidlCopy);
|
|
|
|
bFound=FALSE;
|
|
while(hItem!=NULL)
|
|
{
|
|
// Get folder info associated with item
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=
|
|
(LPNAMESPACEOBJECT)GetItemData(hItem);
|
|
ASSERT(lpNameSpaceObject!=NULL);
|
|
if(pidlCopy->mkid.cb==lpNameSpaceObject->
|
|
lpRelativeIDL->mkid.cb &&
|
|
memcmp((void*)pidlCopy,(void*)lpNameSpaceObject->
|
|
lpRelativeIDL,pidlCopy->mkid.cb)==0)
|
|
{
|
|
bFound=TRUE;
|
|
if(pidlNext!=NULL)
|
|
{
|
|
Expand(hItem,TVE_EXPAND);
|
|
hItem=GetNextItem(hItem,TVGN_CHILD);
|
|
}
|
|
else
|
|
{
|
|
SelectItem(hItem);
|
|
if(bExpand)
|
|
Expand(hItem,TVE_EXPAND);
|
|
EnsureVisible(hItem);
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
hItem=GetNextItem(hItem,TVGN_NEXT);
|
|
}
|
|
|
|
if(!bFound)
|
|
break;
|
|
|
|
pidlCopy=pidlNext;
|
|
}
|
|
|
|
return bFound;
|
|
}
|
|
|
|
|
|
HTREEITEM COXShellFolderTree::FindFolder(CString sFolderToFind)
|
|
{
|
|
if(sFolderToFind.IsEmpty())
|
|
return NULL;
|
|
|
|
LPITEMIDLIST lpidlFull;
|
|
if(!m_navigator.GetShellFolderFullIDL(sFolderToFind,&lpidlFull))
|
|
return NULL;
|
|
return FindFolder(lpidlFull);
|
|
}
|
|
|
|
|
|
HTREEITEM COXShellFolderTree::FindFolder(const LPITEMIDLIST lpFullIDL)
|
|
{
|
|
if(lpFullIDL==NULL)
|
|
return NULL;
|
|
|
|
HTREEITEM hItem=GetRootItem();
|
|
ASSERT(hItem!=NULL);
|
|
if(m_bShowDesktopItem)
|
|
{
|
|
hItem=GetNextItem(hItem,TVGN_CHILD);
|
|
ASSERT(hItem!=NULL);
|
|
}
|
|
|
|
LPITEMIDLIST pidlCopy=lpFullIDL;
|
|
LPITEMIDLIST pidlNext=NULL;
|
|
HTREEITEM hFoundItem=NULL;
|
|
while(pidlCopy!=NULL)
|
|
{
|
|
pidlNext=m_navigator.GetNextIDLItem(pidlCopy);
|
|
|
|
hFoundItem=NULL;
|
|
while(hItem!=NULL )
|
|
{
|
|
// Get folder info associated with item
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=
|
|
(LPNAMESPACEOBJECT)GetItemData(hItem);
|
|
ASSERT(lpNameSpaceObject!=NULL);
|
|
if(pidlCopy->mkid.cb==lpNameSpaceObject->
|
|
lpRelativeIDL->mkid.cb &&
|
|
memcmp((void*)pidlCopy,(void*)lpNameSpaceObject->
|
|
lpRelativeIDL,pidlCopy->mkid.cb)==0)
|
|
{
|
|
hFoundItem=hItem;
|
|
if(pidlNext!=NULL)
|
|
{
|
|
if(GetItemState(hItem,TVIS_EXPANDED)&TVIS_EXPANDED)
|
|
hItem=GetNextItem(hItem,TVGN_CHILD);
|
|
else
|
|
hFoundItem=NULL;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
hItem=GetNextItem(hItem,TVGN_NEXT);
|
|
}
|
|
|
|
if(hFoundItem==NULL)
|
|
break;
|
|
|
|
pidlCopy=pidlNext;
|
|
}
|
|
|
|
return hFoundItem;
|
|
}
|
|
|
|
|
|
CString COXShellFolderTree::GetFullPath(HTREEITEM hItem) const
|
|
{
|
|
ASSERT(hItem!=NULL);
|
|
|
|
// retrieve associated structure
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=(LPNAMESPACEOBJECT)GetItemData(hItem);
|
|
if(lpNameSpaceObject==NULL)
|
|
return _T("");
|
|
|
|
return m_navigator.GetFullPath(lpNameSpaceObject->lpFullIDL);
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::FillTreeWithSubfolders(HTREEITEM htiParent,
|
|
const LPSHELLFOLDER lpFolder,
|
|
const LPITEMIDLIST lpFullIDL)
|
|
{
|
|
ASSERT(lpFolder);
|
|
|
|
CWaitCursor wait;
|
|
|
|
// Initialize enumeration of objects within given folder
|
|
if(!m_navigator.InitObjectsEnumerator(lpFolder,lpFullIDL))
|
|
return FALSE;
|
|
|
|
// After we get pointer to IEnumIDList interface we can use its methods to
|
|
// retrieve information about all objects of given lpFolder
|
|
//
|
|
|
|
// structures for inserting new items in our TreeCtrl
|
|
TV_ITEM tvi;
|
|
TV_INSERTSTRUCT tvins;
|
|
|
|
BOOL bLast;
|
|
// Loop through folders and objects that have subfolders
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=
|
|
m_navigator.EnumerateObjectNext(bLast);
|
|
while(!bLast)
|
|
{
|
|
BOOL bQualified=TRUE;
|
|
if(GetOnlyFileSystemFolders())
|
|
{
|
|
if(GetShowFiles())
|
|
bQualified=lpNameSpaceObject!=NULL &&
|
|
(lpNameSpaceObject->dwFlags&SFGAO_FILESYSANCESTOR ||
|
|
lpNameSpaceObject->dwFlags&SFGAO_FILESYSTEM);
|
|
else
|
|
bQualified=lpNameSpaceObject!=NULL &&
|
|
((lpNameSpaceObject->dwFlags&SFGAO_FILESYSANCESTOR &&
|
|
lpNameSpaceObject->dwFlags&SFGAO_HASSUBFOLDER) ||
|
|
(lpNameSpaceObject->dwFlags&SFGAO_FILESYSTEM &&
|
|
lpNameSpaceObject->dwFlags&SFGAO_FOLDER));
|
|
}
|
|
else
|
|
{
|
|
if(GetShowFiles())
|
|
bQualified=lpNameSpaceObject!=NULL;
|
|
else
|
|
bQualified=lpNameSpaceObject!=NULL &&
|
|
(lpNameSpaceObject->dwFlags&SFGAO_HASSUBFOLDER ||
|
|
lpNameSpaceObject->dwFlags&SFGAO_FOLDER);
|
|
}
|
|
if(bQualified && (lpNameSpaceObject->dwFlags&SFGAO_FILESYSTEM) &&
|
|
!(lpNameSpaceObject->dwFlags&SFGAO_FOLDER))
|
|
{
|
|
bQualified=IsMatchingFilter(lpNameSpaceObject->szDisplayName);
|
|
}
|
|
if(bQualified && IsQualified(lpNameSpaceObject))
|
|
{
|
|
// We define text, image (including selected) and lParam value
|
|
// which is going to be a pointer to NAMESPACEOBJECT structure
|
|
tvi.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
|
|
// NAMESPACEOBJECT structure is already filled
|
|
tvi.lParam=(LPARAM)lpNameSpaceObject;
|
|
|
|
// if object has subfolders then we define the corresponding
|
|
// tree item as one that has children
|
|
if(lpNameSpaceObject->dwFlags&SFGAO_FILESYSANCESTOR ||
|
|
lpNameSpaceObject->dwFlags&SFGAO_HASSUBFOLDER ||
|
|
(GetShowFiles() && lpNameSpaceObject->dwFlags&SFGAO_FOLDER))
|
|
{
|
|
tvi.cChildren=1;
|
|
tvi.mask|=TVIF_CHILDREN;
|
|
}
|
|
|
|
// display name
|
|
tvi.pszText=lpNameSpaceObject->szDisplayName;
|
|
|
|
// images
|
|
int nTreeImageIndex=-1;
|
|
if(!m_mapImageIndex.Lookup(lpNameSpaceObject->nImageSmall,nTreeImageIndex))
|
|
{
|
|
nTreeImageIndex=PtrToInt(m_mapImageIndex.GetCount())+1;
|
|
m_mapImageIndex.SetAt(lpNameSpaceObject->nImageSmall,nTreeImageIndex);
|
|
HICON hIcon=ImageList_ExtractIcon(
|
|
0,m_hShellImageList,lpNameSpaceObject->nImageSmall);
|
|
ASSERT(hIcon!=NULL);
|
|
tvi.iImage=m_imageList.Add(hIcon);
|
|
ASSERT(tvi.iImage!=-1 && tvi.iImage==nTreeImageIndex);
|
|
VERIFY(::DestroyIcon(hIcon));
|
|
}
|
|
else
|
|
{
|
|
tvi.iImage=nTreeImageIndex;
|
|
}
|
|
|
|
nTreeImageIndex=-1;
|
|
if(!m_mapImageIndex.Lookup(lpNameSpaceObject->nImageSelectedSmall,
|
|
nTreeImageIndex))
|
|
{
|
|
nTreeImageIndex=PtrToInt(m_mapImageIndex.GetCount())+1;
|
|
m_mapImageIndex.SetAt(lpNameSpaceObject->nImageSelectedSmall,
|
|
nTreeImageIndex);
|
|
HICON hIcon=ImageList_ExtractIcon(
|
|
0,m_hShellImageList,lpNameSpaceObject->nImageSelectedSmall);
|
|
ASSERT(hIcon!=NULL);
|
|
tvi.iSelectedImage=m_imageList.Add(hIcon);
|
|
ASSERT(tvi.iSelectedImage!=-1 && tvi.iSelectedImage==nTreeImageIndex);
|
|
VERIFY(::DestroyIcon(hIcon));
|
|
}
|
|
else
|
|
{
|
|
tvi.iSelectedImage=nTreeImageIndex;
|
|
}
|
|
///////////////////////////
|
|
|
|
// We collected all information we needed. It's time to insert
|
|
// new item in our TreeCtrl.
|
|
tvins.item=tvi;
|
|
tvins.hInsertAfter=TVI_LAST;
|
|
tvins.hParent=htiParent;
|
|
VERIFY(InsertItem(&tvins)!=NULL);
|
|
}
|
|
lpNameSpaceObject=m_navigator.EnumerateObjectNext(bLast);
|
|
}
|
|
|
|
// Release enumerator
|
|
m_navigator.ReleaseObjectsEnumerator();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
|
|
// TODO: Add your control notification handler code here
|
|
|
|
*pResult = 0;
|
|
|
|
ASSERT(pNMTreeView->itemNew.hItem!=NULL);
|
|
|
|
// If folder at least once was expanded then it was already populated
|
|
if((pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE))
|
|
return TRUE;
|
|
|
|
// retrieve associated structure
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=
|
|
(LPNAMESPACEOBJECT)pNMTreeView->itemNew.lParam;
|
|
ASSERT(lpNameSpaceObject!=NULL || GetShowDesktopItem());
|
|
|
|
|
|
CWaitCursor waitCusor;
|
|
|
|
// get shell folder object from saved PIDLs
|
|
LPSHELLFOLDER lpsfExpanded=m_navigator.
|
|
GetShellFolder(lpNameSpaceObject->lpsfParent,
|
|
lpNameSpaceObject->lpRelativeIDL);
|
|
if(lpsfExpanded!=NULL)
|
|
{
|
|
// add new items
|
|
FillTreeWithSubfolders(pNMTreeView->itemNew.hItem,lpsfExpanded,
|
|
lpNameSpaceObject->lpFullIDL);
|
|
SortChildren(pNMTreeView->itemNew.hItem);
|
|
}
|
|
|
|
|
|
#ifdef OXSHELLTREE_WATCHFORDIR
|
|
if(lpNameSpaceObject!=NULL &&
|
|
((lpNameSpaceObject->dwFlags&SFGAO_FILESYSANCESTOR)==SFGAO_FILESYSANCESTOR)
|
|
||(lpNameSpaceObject->dwFlags&SFGAO_FILESYSTEM)==SFGAO_FILESYSTEM)
|
|
{
|
|
CString sCurrentFolder=GetFullPath(pNMTreeView->itemNew.hItem);
|
|
if(!sCurrentFolder.IsEmpty())
|
|
{
|
|
if(m_fileWatcher.AddWatch(sCurrentFolder,/*FALSE*/TRUE,
|
|
COXFileWatcher::OXFileWatchChangeDirName|(GetShowFiles() ?
|
|
COXFileWatcher::OXFileWatchChangeFileName : NULL)))
|
|
{
|
|
m_fileWatcher.EnableWindowNotification(sCurrentFolder,this,TRUE);
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnItemExpanding: failed to set a file watcher for the expanding folder\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HTREEITEM hChildItem=this->GetNextItem(
|
|
pNMTreeView->itemNew.hItem,TVGN_CHILD);
|
|
while (hChildItem)
|
|
{
|
|
|
|
CString sFolder=GetFullPath(hChildItem);
|
|
if (!sFolder.IsEmpty())
|
|
{
|
|
if(m_fileWatcher.AddWatch(sFolder,/*FALSE*/TRUE,
|
|
COXFileWatcher::OXFileWatchChangeDirName|(GetShowFiles() ?
|
|
COXFileWatcher::OXFileWatchChangeFileName : NULL)))
|
|
{
|
|
m_fileWatcher.EnableWindowNotification(sFolder,this,TRUE);
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnItemExpanding: failed to set a file watcher for the expanding folder\n"));
|
|
}
|
|
|
|
}
|
|
hChildItem=this->GetNextItem(
|
|
hChildItem,TVGN_NEXT);
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif // OXSHELLTREE_WATCHFORDIR
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::OnRClick(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
UNREFERENCED_PARAMETER(pNMHDR);
|
|
|
|
// TODO: Add your control notification handler code here
|
|
*pResult = 0;
|
|
|
|
if(GetEnableContextMenu())
|
|
{
|
|
// On right click we display context menu for any item
|
|
//
|
|
|
|
// Get the item that was right clicked in screen coordinates
|
|
CPoint ptMouseCursor;
|
|
if(!::GetCursorPos(&ptMouseCursor))
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnRClick: GetCursorPos() failed\n"));
|
|
return FALSE;
|
|
}
|
|
ScreenToClient(&ptMouseCursor);
|
|
|
|
// Use HitTest function to define the tree item by coordinate
|
|
TV_HITTESTINFO tvhti;
|
|
tvhti.pt=ptMouseCursor;
|
|
HitTest(&tvhti);
|
|
|
|
if(tvhti.hItem)
|
|
{
|
|
// Get folder info associated with item
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=
|
|
(LPNAMESPACEOBJECT)GetItemData(tvhti.hItem);
|
|
if(m_bShowDesktopItem && lpNameSpaceObject==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
ASSERT(lpNameSpaceObject!=NULL);
|
|
|
|
DWORD dwMenuFlags=CMF_EXPLORE |
|
|
((((GetStyle()&TVS_EDITLABELS)==TVS_EDITLABELS) &&
|
|
((lpNameSpaceObject->dwFlags&SFGAO_CANRENAME)==SFGAO_CANRENAME)) ?
|
|
CMF_CANRENAME : NULL);
|
|
HMENU hMenu=
|
|
m_navigator.GetObjectContextMenu(lpNameSpaceObject->lpsfParent,
|
|
lpNameSpaceObject->lpRelativeIDL,dwMenuFlags);
|
|
if(hMenu==NULL)
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnRClick: GetObjectContextMenu() failed\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Display popup menu using Windows API TrackPopupMenu function because
|
|
// it provides easy way of getting selected menu item. We need to set
|
|
// screen coordinates of the point where popup menu should be displayed.
|
|
ClientToScreen(&ptMouseCursor);
|
|
BOOL nCmdID=::TrackPopupMenu(hMenu,
|
|
TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON,
|
|
ptMouseCursor.x,ptMouseCursor.y,0,GetSafeHwnd(),NULL);
|
|
|
|
if(nCmdID!=0)
|
|
{
|
|
switch(nCmdID)
|
|
{
|
|
case IDCMD_RENAME:
|
|
{
|
|
EditLabel(tvhti.hItem);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
if(!m_navigator.InvokeCommand(lpNameSpaceObject->lpsfParent,
|
|
lpNameSpaceObject->lpRelativeIDL,nCmdID,dwMenuFlags))
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnRClick: InvokeCommand() failed\n"));
|
|
}
|
|
else
|
|
{
|
|
switch(nCmdID)
|
|
{
|
|
case IDCMD_DELETE:
|
|
{
|
|
DeleteItem(tvhti.hItem);
|
|
break;
|
|
}
|
|
case IDCMD_PASTE:
|
|
{
|
|
Refresh(tvhti.hItem);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
::DestroyMenu(hMenu);
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void COXShellFolderTree::OnRButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
if(GetEnableContextMenu())
|
|
{
|
|
ASSERT(m_hContextMenuItem==NULL);
|
|
|
|
TV_HITTESTINFO tvhti;
|
|
tvhti.pt=point;
|
|
HitTest(&tvhti);
|
|
|
|
if(tvhti.hItem!=NULL)
|
|
{
|
|
m_hContextMenuItem=tvhti.hItem;
|
|
|
|
// remove highlight from the currently selected item
|
|
HTREEITEM hSelectedItem=GetSelectedItem();
|
|
if(hSelectedItem!=m_hContextMenuItem)
|
|
{
|
|
if(hSelectedItem!=NULL)
|
|
{
|
|
SetItemState(hSelectedItem,0,TVIS_SELECTED);
|
|
}
|
|
|
|
// highlight the item under mouse cursor
|
|
SetItemState(m_hContextMenuItem,TVIS_DROPHILITED,TVIS_DROPHILITED);
|
|
}
|
|
}
|
|
|
|
::SetCapture(GetSafeHwnd());
|
|
}
|
|
else
|
|
{
|
|
CTreeCtrl::OnRButtonDown(nFlags,point);
|
|
}
|
|
}
|
|
|
|
|
|
void COXShellFolderTree::OnRButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
if(GetEnableContextMenu())
|
|
{
|
|
// On right click we display context menu for any item
|
|
//
|
|
|
|
// set handle to context menu item to NULL in order to avoid triggering
|
|
// preliminary restore routine in OnCancelMode() and OnCaptureChanged()
|
|
m_bNoRestoreContextMenuItem=TRUE;
|
|
|
|
if(m_hContextMenuItem!=NULL)
|
|
{
|
|
ASSERT(::GetCapture()==GetSafeHwnd());
|
|
|
|
// Get the item that was right clicked in screen coordinates
|
|
CPoint ptMouseCursor=point;
|
|
|
|
#ifdef _DEBUG
|
|
// double check for context menu item
|
|
TV_HITTESTINFO tvhti;
|
|
tvhti.pt=ptMouseCursor;
|
|
HitTest(&tvhti);
|
|
VERIFY(tvhti.hItem==m_hContextMenuItem);
|
|
#endif
|
|
|
|
// Get folder info associated with item
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=
|
|
(LPNAMESPACEOBJECT)GetItemData(m_hContextMenuItem);
|
|
if(!m_bShowDesktopItem || lpNameSpaceObject!=NULL)
|
|
{
|
|
ASSERT(lpNameSpaceObject!=NULL);
|
|
|
|
DWORD dwMenuFlags=CMF_EXPLORE |
|
|
((((GetStyle()&TVS_EDITLABELS)==TVS_EDITLABELS) &&
|
|
((lpNameSpaceObject->dwFlags&SFGAO_CANRENAME)==SFGAO_CANRENAME)) ?
|
|
CMF_CANRENAME : 0);
|
|
HMENU hMenu=m_navigator.GetObjectContextMenu(
|
|
lpNameSpaceObject->lpsfParent,
|
|
lpNameSpaceObject->lpRelativeIDL,dwMenuFlags);
|
|
if(hMenu!=NULL)
|
|
{
|
|
// Display popup menu using Windows API TrackPopupMenu function
|
|
// because it provides an e+asy way of getting selected menu item.
|
|
// We need to set screen coordinates of the point where popup menu
|
|
// should be displayed.
|
|
ClientToScreen(&ptMouseCursor);
|
|
BOOL nCmdID=::TrackPopupMenu(
|
|
hMenu,TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON,
|
|
ptMouseCursor.x,ptMouseCursor.y,0,GetSafeHwnd(),NULL);
|
|
|
|
if(nCmdID!=0)
|
|
{
|
|
switch(nCmdID)
|
|
{
|
|
case IDCMD_RENAME:
|
|
{
|
|
EditLabel(m_hContextMenuItem);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
if(!m_navigator.InvokeCommand(
|
|
lpNameSpaceObject->lpsfParent,
|
|
lpNameSpaceObject->lpRelativeIDL,
|
|
nCmdID,dwMenuFlags))
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnContextMenu: InvokeCommand() failed\n"));
|
|
}
|
|
else
|
|
{
|
|
switch(nCmdID)
|
|
{
|
|
case IDCMD_DELETE:
|
|
{
|
|
DeleteItem(m_hContextMenuItem);
|
|
break;
|
|
}
|
|
case IDCMD_PASTE:
|
|
{
|
|
Refresh(m_hContextMenuItem);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
::DestroyMenu(hMenu);
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnContextMenu: GetObjectContextMenu() failed\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
m_bNoRestoreContextMenuItem=FALSE;
|
|
if(::GetCapture()==GetSafeHwnd())
|
|
{
|
|
::ReleaseCapture();
|
|
}
|
|
else
|
|
{
|
|
RestoreStateAfterContextMenu();
|
|
}
|
|
ASSERT(m_hContextMenuItem==NULL);
|
|
}
|
|
else
|
|
{
|
|
CTreeCtrl::OnRButtonUp(nFlags,point);
|
|
}
|
|
}
|
|
|
|
|
|
void COXShellFolderTree::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if(GetEnableContextMenu() && (nFlags & MK_RBUTTON)!=0)
|
|
{
|
|
TV_HITTESTINFO tvhti;
|
|
tvhti.pt=point;
|
|
HitTest(&tvhti);
|
|
|
|
if(tvhti.hItem!=m_hContextMenuItem)
|
|
{
|
|
HTREEITEM hSelectedItem=GetSelectedItem();
|
|
|
|
if(m_hContextMenuItem!=NULL)
|
|
{
|
|
if(m_hContextMenuItem!=hSelectedItem)
|
|
{
|
|
SetItemState(m_hContextMenuItem,0,TVIS_DROPHILITED);
|
|
}
|
|
else
|
|
{
|
|
SetItemState(m_hContextMenuItem,0,TVIS_SELECTED);
|
|
}
|
|
}
|
|
|
|
m_hContextMenuItem=tvhti.hItem;
|
|
|
|
if(m_hContextMenuItem!=NULL)
|
|
{
|
|
if(m_hContextMenuItem!=hSelectedItem)
|
|
{
|
|
SetItemState(m_hContextMenuItem,TVIS_DROPHILITED,TVIS_DROPHILITED);
|
|
}
|
|
else
|
|
{
|
|
SetItemState(m_hContextMenuItem,TVIS_SELECTED,TVIS_SELECTED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CTreeCtrl::OnMouseMove(nFlags,point);
|
|
}
|
|
|
|
|
|
void COXShellFolderTree::OnCancelMode()
|
|
{
|
|
CTreeCtrl::OnCancelMode();
|
|
|
|
RestoreStateAfterContextMenu();
|
|
}
|
|
|
|
|
|
void COXShellFolderTree::OnCaptureChanged(CWnd* pWnd)
|
|
{
|
|
CTreeCtrl::OnCaptureChanged(pWnd);
|
|
|
|
RestoreStateAfterContextMenu();
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::OnDblClick(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
UNREFERENCED_PARAMETER(pNMHDR);
|
|
|
|
// TODO: Add your control notification handler code here
|
|
*pResult = 0;
|
|
|
|
// if double click over a folder we expand it or otherwise invoke
|
|
// the default command for a file
|
|
//
|
|
|
|
// Get the item that was double clicked in screen coordinates
|
|
CPoint ptMouseCursor;
|
|
if(!::GetCursorPos(&ptMouseCursor))
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnDblClick: GetCursorPos() failed\n"));
|
|
return FALSE;
|
|
}
|
|
ScreenToClient(&ptMouseCursor);
|
|
|
|
// Use HitTest function to define the tree item by coordinate
|
|
TV_HITTESTINFO tvhti;
|
|
tvhti.pt=ptMouseCursor;
|
|
HitTest(&tvhti);
|
|
|
|
if(tvhti.hItem)
|
|
{
|
|
// Get folder info associated with item
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=
|
|
(LPNAMESPACEOBJECT)GetItemData(tvhti.hItem);
|
|
if(m_bShowDesktopItem && lpNameSpaceObject==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
ASSERT(lpNameSpaceObject!=NULL);
|
|
|
|
if((lpNameSpaceObject->dwFlags&SFGAO_FOLDER)!=SFGAO_FOLDER)
|
|
{
|
|
if(!m_navigator.InvokeDefaultCommand(lpNameSpaceObject->lpsfParent,
|
|
lpNameSpaceObject->lpRelativeIDL))
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnDblClick: InvokeDefaultCommand() failed"));
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void COXShellFolderTree::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
if(!m_bEditingItem)
|
|
{
|
|
CTreeCtrl::OnLButtonDown(nFlags,point);
|
|
}
|
|
else
|
|
{
|
|
SetFocus();
|
|
}
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::SortChildren(const HTREEITEM htiParent)
|
|
{
|
|
TV_SORTCB tvscb;
|
|
tvscb.hParent=htiParent;
|
|
tvscb.lParam=0;
|
|
tvscb.lpfnCompare=COXShellNamespaceNavigator::CompareObjectsProc;
|
|
|
|
return CTreeCtrl::SortChildrenCB(&tvscb);
|
|
}
|
|
|
|
|
|
void COXShellFolderTree::SetRedraw(BOOL bRedraw/*=TRUE*/)
|
|
{
|
|
ASSERT(m_nRedraw>=0);
|
|
|
|
if(!bRedraw)
|
|
{
|
|
if(m_nRedraw==0)
|
|
{
|
|
CWnd::SetRedraw(FALSE);
|
|
}
|
|
m_nRedraw++;
|
|
}
|
|
else
|
|
{
|
|
if(m_nRedraw>=1)
|
|
m_nRedraw--;
|
|
if(m_nRedraw==0)
|
|
{
|
|
CWnd::SetRedraw(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
LPNMTVDISPINFO ptvdi=(LPNMTVDISPINFO)pNMHDR;
|
|
ASSERT(ptvdi!=NULL);
|
|
// TODO: Add your control notification handler code here
|
|
|
|
(*pResult)=FALSE;
|
|
|
|
// retrieve associated structure
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=(LPNAMESPACEOBJECT)ptvdi->item.lParam;
|
|
if(lpNameSpaceObject==NULL)
|
|
{
|
|
(*pResult)=TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
// check if item is allowed to be edited
|
|
if((lpNameSpaceObject->dwFlags&SFGAO_CANRENAME)!=SFGAO_CANRENAME)
|
|
{
|
|
(*pResult)=TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
m_bEditingItem=TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
LPNMTVDISPINFO ptvdi=(LPNMTVDISPINFO)pNMHDR;
|
|
ASSERT(ptvdi!=NULL);
|
|
// TODO: Add your control notification handler code here
|
|
|
|
*pResult=TRUE;;
|
|
|
|
CString sNewText=ptvdi->item.pszText;
|
|
|
|
CWaitCursor waitCusor;
|
|
|
|
// retrieve associated structure
|
|
LPNAMESPACEOBJECT lpNameSpaceObject=(LPNAMESPACEOBJECT)ptvdi->item.lParam;
|
|
ASSERT(lpNameSpaceObject!=NULL);
|
|
|
|
// rename the item
|
|
LPITEMIDLIST lpNewRelativeIDL=NULL;
|
|
if(sNewText.IsEmpty() ||
|
|
!m_navigator.RenameShellObject(lpNameSpaceObject->lpsfParent,
|
|
lpNameSpaceObject->lpRelativeIDL,&lpNewRelativeIDL,sNewText))
|
|
{
|
|
*pResult=FALSE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(lpNewRelativeIDL!=NULL);
|
|
lpNameSpaceObject->lpRelativeIDL=lpNewRelativeIDL;
|
|
m_navigator.FreeShellObject((void*)lpNameSpaceObject->lpFullIDL);
|
|
|
|
HTREEITEM hItem=GetParentItem(ptvdi->item.hItem);
|
|
if(hItem==NULL || GetItemData(hItem)==NULL)
|
|
{
|
|
lpNameSpaceObject->lpFullIDL=m_navigator.
|
|
CopyPIDL(lpNameSpaceObject->lpRelativeIDL);
|
|
}
|
|
else
|
|
{
|
|
LPNAMESPACEOBJECT lpNameSpaceObjectParent=
|
|
(LPNAMESPACEOBJECT)GetItemData(hItem);
|
|
ASSERT(lpNameSpaceObjectParent!=NULL);
|
|
lpNameSpaceObject->lpFullIDL=m_navigator.
|
|
ConcatenatePIDLs(lpNameSpaceObjectParent->lpFullIDL,
|
|
lpNameSpaceObject->lpRelativeIDL);
|
|
ASSERT(lpNameSpaceObject->lpFullIDL!=NULL);
|
|
}
|
|
|
|
*pResult=TRUE;
|
|
}
|
|
|
|
m_bEditingItem=FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::Refresh(LPCTSTR lpszFolder)
|
|
{
|
|
HTREEITEM hItem=FindFolder(lpszFolder);
|
|
if(hItem==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return Refresh(hItem);
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::Refresh(HTREEITEM htiParent/*=TVI_ROOT*/)
|
|
{
|
|
if(htiParent==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// save currently selected folder
|
|
CString sCurrentFolder(_T(""));
|
|
HTREEITEM hItem=GetSelectedItem();
|
|
if(hItem!=NULL)
|
|
{
|
|
sCurrentFolder=GetFullPath(hItem);
|
|
SelectItem(NULL);
|
|
}
|
|
//////////////////
|
|
|
|
if(htiParent!=TVI_ROOT &&
|
|
(GetItemState(htiParent,TVIS_EXPANDED)&TVIS_EXPANDED)!=TVIS_EXPANDED)
|
|
{
|
|
return (SetItemState(htiParent,NULL,TVIS_EXPANDEDONCE)!=0);
|
|
}
|
|
|
|
if(htiParent==TVI_ROOT)
|
|
{
|
|
hItem=GetRootItem();
|
|
ASSERT(hItem!=NULL);
|
|
if(m_bShowDesktopItem && GetItemData(hItem)==NULL)
|
|
{
|
|
hItem=GetNextItem(hItem,TVGN_CHILD);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hItem=GetNextItem(htiParent,TVGN_CHILD);
|
|
}
|
|
if(hItem==NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// save info about curently expanded folders
|
|
CArray<CString,CString> m_arrExpandedFolders;
|
|
while(hItem!=NULL)
|
|
{
|
|
// Get full path for the item
|
|
if(GetItemState(hItem,TVIS_EXPANDED)&TVIS_EXPANDED)
|
|
{
|
|
CString sPath=GetFullPath(hItem);
|
|
if(!sPath.IsEmpty())
|
|
m_arrExpandedFolders.Add(sPath);
|
|
}
|
|
|
|
hItem=GetNextItem(hItem,TVGN_NEXTVISIBLE);
|
|
}
|
|
///////////////////////
|
|
|
|
|
|
SetRedraw(FALSE);
|
|
|
|
if(htiParent==TVI_ROOT)
|
|
{
|
|
InitializeTree();
|
|
}
|
|
else
|
|
{
|
|
BOOL bWasExpanded=(GetItemState(htiParent,TVIS_EXPANDED)!=0);
|
|
// repopulate the branch
|
|
for(;;)
|
|
{
|
|
HTREEITEM htiChild=GetNextItem(htiParent,TVGN_CHILD);
|
|
if(htiChild==NULL)
|
|
break;
|
|
DeleteItem(htiChild);
|
|
}
|
|
SetItemState(htiParent,NULL,TVIS_EXPANDEDONCE);
|
|
if(bWasExpanded)
|
|
{
|
|
Expand(htiParent,TVE_COLLAPSE);
|
|
Expand(htiParent,TVE_EXPAND);
|
|
}
|
|
}
|
|
|
|
// expand the previously expanded folders
|
|
for(int nIndex=0; nIndex<m_arrExpandedFolders.GetSize(); nIndex++)
|
|
{
|
|
CString sPath=m_arrExpandedFolders[nIndex];
|
|
ASSERT(!sPath.IsEmpty());
|
|
OpenFolder(sPath,TRUE);
|
|
}
|
|
|
|
// select current folder
|
|
if(!sCurrentFolder.IsEmpty())
|
|
OpenFolder(sCurrentFolder);
|
|
|
|
SetRedraw(TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#ifdef OXSHELLTREE_WATCHFORDIR
|
|
|
|
LRESULT COXShellFolderTree::OnDirChangeNotify(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
CString str;
|
|
|
|
COXFileWatchNotifier fwNotifier;
|
|
fwNotifier=m_fileWatcher.GetFileWatchNotifier(wParam);
|
|
|
|
// If the wParam is an invalid ID then the notifier is empty
|
|
if(!fwNotifier.IsEmpty())
|
|
{
|
|
CString sDirPath=fwNotifier.GetPath();
|
|
ASSERT(!sDirPath.IsEmpty());
|
|
if(!Refresh(sDirPath))
|
|
{
|
|
TRACE(_T("COXShellFolderTree::OnDirChangeNotify: failed to refresh folder '%s'"),sDirPath);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif // OXSHELLTREE_WATCHFORDIR
|
|
|
|
|
|
void COXShellFolderTree::SetFilter(LPCTSTR lpszExtentions)
|
|
{
|
|
m_arrFilter.RemoveAll();
|
|
|
|
CString sExtentions=lpszExtentions;
|
|
if(sExtentions.IsEmpty())
|
|
return;
|
|
|
|
for(;;)
|
|
{
|
|
int nDelimiterPos=sExtentions.Find(OXSHELLTREE_EXT_DELIMITER);
|
|
if(nDelimiterPos==-1)
|
|
{
|
|
m_arrFilter.Add(sExtentions);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if(nDelimiterPos>0)
|
|
m_arrFilter.Add(sExtentions.Left(nDelimiterPos));
|
|
sExtentions=sExtentions.Mid(nDelimiterPos+1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CString COXShellFolderTree::GetFilter() const
|
|
{
|
|
TCHAR sDelimiter[2];
|
|
sDelimiter[0]=OXSHELLTREE_EXT_DELIMITER;
|
|
sDelimiter[1]=_T('\0');
|
|
// special case
|
|
if(m_arrFilter.GetSize()==1 && m_arrFilter[0].IsEmpty())
|
|
return sDelimiter;
|
|
|
|
CString sExtentions(_T(""));
|
|
for(int nIndex=0; nIndex<m_arrFilter.GetSize(); nIndex++)
|
|
{
|
|
sExtentions=(nIndex==0 ? _T("") : sDelimiter)+m_arrFilter[nIndex];
|
|
}
|
|
return sExtentions;
|
|
}
|
|
|
|
|
|
BOOL COXShellFolderTree::IsMatchingFilter(LPCTSTR lpszFileName)
|
|
{
|
|
ASSERT(lpszFileName!=NULL);
|
|
|
|
if(m_arrFilter.GetSize()==0)
|
|
return TRUE;
|
|
|
|
CString sFileName=lpszFileName;
|
|
CString sExtention(_T(""));
|
|
int nDelimeterPos=sFileName.Find(_T('.'));
|
|
if(nDelimeterPos!=0)
|
|
sExtention=sFileName.Mid(nDelimeterPos+1);
|
|
|
|
BOOL bFoundMatch=FALSE;
|
|
for(int nIndex=0; nIndex<m_arrFilter.GetSize(); nIndex++)
|
|
{
|
|
if(sExtention.CompareNoCase(m_arrFilter[nIndex])==0)
|
|
{
|
|
bFoundMatch=TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return bFoundMatch;
|
|
}
|
|
|
|
|
|
void COXShellFolderTree::RestoreStateAfterContextMenu()
|
|
{
|
|
if(!m_bNoRestoreContextMenuItem)
|
|
{
|
|
HTREEITEM hSelectedItem=GetSelectedItem();
|
|
|
|
// restore selection to the focused item
|
|
if(hSelectedItem!=m_hContextMenuItem)
|
|
{
|
|
if(hSelectedItem!=NULL)
|
|
{
|
|
SetItemState(hSelectedItem,TVIS_SELECTED,TVIS_SELECTED);
|
|
}
|
|
|
|
if(m_hContextMenuItem!=NULL)
|
|
{
|
|
// remove highlight from the item under mouse cursor
|
|
SetItemState(m_hContextMenuItem,0,TVIS_DROPHILITED);
|
|
}
|
|
}
|
|
|
|
m_hContextMenuItem=NULL;
|
|
}
|
|
}
|