X-Git-Url: http://git.jankratochvil.net/?p=reactos.git;a=blobdiff_plain;f=subsys%2Fsystem%2Fexplorer%2FSeashell%2FSeaShellExt%2FIEFolderTreeCtrl.cpp;fp=subsys%2Fsystem%2Fexplorer%2FSeashell%2FSeaShellExt%2FIEFolderTreeCtrl.cpp;h=d8a04bb22e5012985c7dbe7c38100b63447d36cd;hp=0000000000000000000000000000000000000000;hb=a3df8bf1429570e0bd6c6428f6ed80073578cf4b;hpb=7c0db166f81fbe8c8b913d7f26048e337d383605 diff --git a/subsys/system/explorer/Seashell/SeaShellExt/IEFolderTreeCtrl.cpp b/subsys/system/explorer/Seashell/SeaShellExt/IEFolderTreeCtrl.cpp new file mode 100644 index 0000000..d8a04bb --- /dev/null +++ b/subsys/system/explorer/Seashell/SeaShellExt/IEFolderTreeCtrl.cpp @@ -0,0 +1,548 @@ +//******************************************************************************* +// COPYRIGHT NOTES +// --------------- +// You may use this source code, compile or redistribute it as part of your application +// for free. You cannot redistribute it as a part of a software development +// library without the agreement of the author. If the sources are +// distributed along with the application, you should leave the original +// copyright notes in the source code without any changes. +// This code can be used WITHOUT ANY WARRANTIES at your own risk. +// +// For the latest updates to this code, check this site: +// http://www.masmex.com +// after Sept 2000 +// +// Copyright(C) 2000 Philip Oldaker +//******************************************************************************* + + +#include "stdafx.h" +#include "IEFolderTreeCtrl.h" +#include "UIMessages.h" +#include +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +typedef map mapPidlToHTREEITEM; +typedef vector vecPidl; + +int CALLBACK CIEFolderTreeCtrl::CompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + LPTVITEMDATA lptvid1 = (LPTVITEMDATA)((CUIListCtrlData*)lParam1)->GetExtData(); + LPTVITEMDATA lptvid2 = (LPTVITEMDATA)((CUIListCtrlData*)lParam2)->GetExtData(); + LPSHELLFOLDER psfParent = (LPSHELLFOLDER)lParamSort; + + HRESULT hr = psfParent->CompareIDs (0, lptvid1->lpi, lptvid2->lpi); + if (FAILED (hr)) + return 0; + return (short)hr; +} + +///////////////////////////////////////////////////////////////////////////// +// CIEFolderTreeCtrl + +CIEFolderTreeCtrl::CIEFolderTreeCtrl() +{ + SHGetMalloc(&m_pMalloc); + m_hImageList = NULL; +} + +CIEFolderTreeCtrl::~CIEFolderTreeCtrl() +{ + // Free our memory allocator + if (m_pMalloc) + m_pMalloc->Release(); +} + +void CIEFolderTreeCtrl::Refresh() +{ + HTREEITEM hItem = GetRootItem(); + if (hItem == NULL) + return; + CWaitCursor w; + SetRedraw(FALSE); + RefreshNode(hItem); + SetRedraw(TRUE); +} + +void CIEFolderTreeCtrl::OnDeleteItemData(DWORD dwData) +{ + LPTVITEMDATA pItemData=(LPTVITEMDATA)dwData; + if (pItemData == NULL) + return; + if (pItemData->lpsfParent) + pItemData->lpsfParent->Release(); + if (pItemData->lpi) + m_pMalloc->Free(pItemData->lpi); + if (pItemData->lpifq) + m_pMalloc->Free(pItemData->lpifq); + m_pMalloc->Free(pItemData); +} + +BOOL CIEFolderTreeCtrl::LoadURL(HTREEITEM hItem) +{ + if (GetRootItem() == hItem) + return FALSE; + if (ItemHasChildren(hItem)) + return FALSE; + CString strText(GetItemText(hItem)); + AfxMessageBox(strText); + return TRUE; +} + +bool CIEFolderTreeCtrl::LoadItems(LPCTSTR pszPath,DWORD dwFolderType) +{ + ASSERT(m_pMalloc); + if (m_hImageList == NULL) + Init(); + bool bRet = false; + + CWaitCursor w; + DeleteAllItems(); + //DeleteItemData(); + + LPITEMIDLIST pidl=NULL; + LPSHELLFOLDER psfDesktop=NULL; + LPSHELLFOLDER pSubFolder=NULL; + HRESULT hr = SHGetDesktopFolder(&psfDesktop); + + if (dwFolderType) + { + hr = SHGetSpecialFolderLocation(NULL, dwFolderType, &pidl); +#ifdef _DEBUG + CString sPath; + GetShellPidl().SHPidlToPathEx(pidl,sPath); + TRACE1("Populating special folder %s\n",sPath); +#endif + hr = psfDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pSubFolder); + } + else + { + if (pszPath && *pszPath != '\0') + { + hr = m_ShellPidl.SHPathToPidlEx(pszPath,&pidl,psfDesktop); + if (SUCCEEDED(hr)) + { + hr = psfDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pSubFolder); + if (SUCCEEDED(hr)) + m_sRootPath = pszPath; + } + } + else + { + hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl); + } + } + LPCTSTR pszTitle=NULL; + SHFILEINFO fileInfo; + ZeroMemory(&fileInfo,sizeof(fileInfo)); + int nImage=0, nSelImage=0; + if (pidl) + { + SHGetFileInfo((LPCTSTR)pidl, NULL, &fileInfo, sizeof(fileInfo), SHGFI_PIDL|SHGFI_ATTRIBUTES|SHGFI_DISPLAYNAME); + pszTitle = fileInfo.szDisplayName; + m_ShellPidl.GetNormalAndSelectedIcons(pidl, nImage, nSelImage); + if (nImage < 0) + nImage = 0; + if (nSelImage < 0) + nSelImage = 0; + } + if (SUCCEEDED(hr)) + { + LPTVITEMDATA lptvid = (LPTVITEMDATA)m_pMalloc->Alloc(sizeof(TVITEMDATA)); + if (lptvid == NULL) + return bRet; + ZeroMemory(lptvid,sizeof(TVITEMDATA)); + // Now make a copy of the ITEMIDLIST. + lptvid->lpi = m_ShellPidl.CopyLastItemID(pidl); + lptvid->lpifq = m_ShellPidl.CopyItemIDList(pidl); + lptvid->lpsfParent = NULL; + if (lptvid->lpsfParent) + lptvid->lpsfParent->AddRef(); + + HTREEITEM hRootItem = AddAnItem((HTREEITEM)NULL,pszTitle,(LPARAM)lptvid,(HTREEITEM)TVI_ROOT,nImage,nSelImage); + AddItems(hRootItem,pSubFolder ? pSubFolder : psfDesktop); + Expand(hRootItem,TVE_EXPAND); + PostMessage(WM_APP_POPULATE_TREE); + bRet = true; + } + if (pidl) + m_pMalloc->Free(pidl); + if (pSubFolder) + pSubFolder->Release(); + if (psfDesktop) + psfDesktop->Release(); + return bRet; +} + +bool CIEFolderTreeCtrl::AddItems(HTREEITEM hItem,IShellFolder* pFolder) +{ + IEnumIDList* pItems = NULL; + LPITEMIDLIST pidlNext = NULL; + DWORD dwFlags = SHCONTF_FOLDERS; + if (GetShellSettings().ShowAllObjects() && !GetShellSettings().ShowSysFiles()) + dwFlags |= SHCONTF_INCLUDEHIDDEN; + // Enumerate all object in the given folder + HRESULT hr = pFolder->EnumObjects(NULL, dwFlags, &pItems); + if (hr != NOERROR) + return false; + while (NOERROR == hr) + { + hr = pItems->Next(1, &pidlNext, NULL); + if (hr == S_FALSE || pidlNext == NULL) + break; + if (AddFolder(hItem,pidlNext,pFolder) == NULL) + m_pMalloc->Free(pidlNext); + pidlNext = NULL; + } + if (pidlNext) + m_pMalloc->Free(pidlNext); + if (pItems) + pItems->Release(); + Sort(hItem,pFolder); + return true; +} + +void CIEFolderTreeCtrl::Sort(HTREEITEM hParent,LPSHELLFOLDER pFolder) +{ + // Sort the the node based on pidls + TVSORTCB cbSort; + cbSort.hParent = hParent; + cbSort.lpfnCompare = CompareProc; + cbSort.lParam = (LPARAM)pFolder; + SortChildrenCB(&cbSort); +} + +HTREEITEM CIEFolderTreeCtrl::AddFolder(HTREEITEM hItem,LPCTSTR pszPath) +{ + LPITEMIDLIST pidlfq=NULL; + HRESULT hr = GetShellPidl().SHPathToPidlEx(pszPath,&pidlfq,NULL); + if (FAILED(hr)) + return NULL; + LPTVITEMDATA lptvid = (LPTVITEMDATA)GetItemData(hItem); + ASSERT(lptvid); + LPITEMIDLIST pidl = GetShellPidl().CopyLastItemID(pidlfq); + HTREEITEM hFolderItem = AddFolder(hItem,pidl,lptvid->lpsfParent); + if (pidlfq) + m_pMalloc->Free(pidlfq); + return hFolderItem; +} + +HTREEITEM CIEFolderTreeCtrl::AddFolder(HTREEITEM hItem,LPITEMIDLIST pidl,LPSHELLFOLDER pFolder) +{ + ASSERT(m_pMalloc); + LPTSTR pszFilePath = NULL; + STRRET StrRetFilePath; + SHFILEINFO FileInfo; + + ZeroMemory(&FileInfo,sizeof(FileInfo)); + FileInfo.dwAttributes=SFGAO_HASSUBFOLDER | SFGAO_FOLDER; + HRESULT hr = pFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&pidl,&FileInfo.dwAttributes); + if (FAILED(hr)) + return NULL; +// Create a submenu if this item is a folder + if (!(FileInfo.dwAttributes & (SFGAO_HASSUBFOLDER | SFGAO_FOLDER))) + return NULL; + pFolder->GetDisplayNameOf(pidl,SHGDN_INFOLDER,&StrRetFilePath); + GetShellPidl().StrRetToStr(StrRetFilePath, &pszFilePath, pidl); + if (pszFilePath) + { + lstrcpy(FileInfo.szDisplayName,pszFilePath); + m_pMalloc->Free(pszFilePath); + pszFilePath = NULL; + } + // allocate new itemdata + LPTVITEMDATA lptvid = (LPTVITEMDATA)m_pMalloc->Alloc(sizeof(TVITEMDATA)); + if (lptvid == NULL) + return NULL; + ZeroMemory(lptvid,sizeof(TVITEMDATA)); + // get itemdata for current node + LPTVITEMDATA lpptvid = (LPTVITEMDATA)GetItemData(hItem); + ASSERT(lpptvid); + // create new fully qualified pidl + lptvid->lpifq = m_ShellPidl.ConcatPidl(lpptvid->lpifq,pidl); + // save relative pidl (will be freed in the clean up) + lptvid->lpi = pidl; + int nImage=0; + int nSelImage=0; + // get icons for new fq pidl + m_ShellPidl.GetNormalAndSelectedIcons(lptvid->lpifq, nImage, nSelImage); + // save folder for later use(when node is expanded) + lptvid->lpsfParent = pFolder; // pointer to parent folder + // keep hold of it(will be released in clean up) + lptvid->lpsfParent->AddRef(); + // add the node to the tree unsorted (will be sorted later) + int nChildren = 0; + if (FileInfo.dwAttributes & SFGAO_HASSUBFOLDER) + { + nChildren=1; + } + HTREEITEM hNewItem = AddAnItem(hItem,FileInfo.szDisplayName,(DWORD)lptvid,(HTREEITEM)TVI_FIRST,nImage,nSelImage,nChildren); + // set overlay images + if (hNewItem) + { + SetAttributes(hNewItem,pFolder,pidl); + } + return hNewItem; +} + +void CIEFolderTreeCtrl::SetAttributes(HTREEITEM hItem,LPSHELLFOLDER pFolder,LPITEMIDLIST pidl) +{ + DWORD dwAttributes = SFGAO_DISPLAYATTRMASK | SFGAO_REMOVABLE; + HRESULT hr = pFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&pidl,&dwAttributes); + if (FAILED(hr)) + return; + if ((dwAttributes & SFGAO_COMPRESSED) && GetShellSettings().ShowCompColor()) + SetTextColor(hItem,RGB(0,0,255)); + else + SetDefaultTextColor(hItem); + if (dwAttributes & SFGAO_GHOSTED) + SetItemState(hItem,TVIS_CUT,TVIS_CUT); + else + SetItemState(hItem,TVIS_CUT,0); + if (dwAttributes & SFGAO_LINK) + SetItemState(hItem,INDEXTOOVERLAYMASK(2),TVIS_OVERLAYMASK); + else + SetItemState(hItem,0,TVIS_OVERLAYMASK); + if (dwAttributes & SFGAO_SHARE) + SetItemState(hItem,INDEXTOOVERLAYMASK(1),TVIS_OVERLAYMASK); + else + SetItemState(hItem,0,TVIS_OVERLAYMASK); +} + +BEGIN_MESSAGE_MAP(CIEFolderTreeCtrl, CUITreeCtrl) + //{{AFX_MSG_MAP(CIEFolderTreeCtrl) + ON_WM_CREATE() + ON_WM_DESTROY() + ON_MESSAGE(WM_SETTINGCHANGE,OnSettingChange) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CIEFolderTreeCtrl message handlers + +int CIEFolderTreeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CUITreeCtrl::OnCreate(lpCreateStruct) == -1) + return -1; + + // TODO: Add your specialized creation code here + + return 0; +} + +BOOL CIEFolderTreeCtrl::PreCreateWindow(CREATESTRUCT& cs) +{ + // TODO: Add your specialized code here and/or call the base class + // No label editing for Explorer items + cs.style |= (TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS); + return CTreeCtrl::PreCreateWindow(cs); +} + +void CIEFolderTreeCtrl::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType) +{ + // TODO: Add your specialized code here and/or call the base class + + CUITreeCtrl::CalcWindowRect(lpClientRect, nAdjustType); +} + +LPCITEMIDLIST CIEFolderTreeCtrl::GetPathPidl(HTREEITEM hItem) +{ + if (hItem == NULL) + return NULL; + LPLVITEMDATA plvit = (LPLVITEMDATA)GetItemData(hItem); + ASSERT(plvit); + if (plvit == NULL) + return NULL; + return plvit->lpifq; +} + +LPSHELLFOLDER CIEFolderTreeCtrl::GetItemFolder(HTREEITEM hItem) +{ + LPTVITEMDATA lpidCurr = (LPTVITEMDATA)GetItemData(hItem); + ASSERT(lpidCurr); + if (lpidCurr == NULL) + return NULL; + LPSHELLFOLDER psfCurr=NULL; + +#if 1 // bug fix by Gregoire + LPSHELLFOLDER psfDesktop=NULL; + SHGetDesktopFolder(&psfDesktop); + psfDesktop->BindToObject(lpidCurr->lpifq,0,IID_IShellFolder,(LPVOID*)&psfCurr); +#else + if (lpidCurr->lpsfParent) + lpidCurr->lpsfParent->BindToObject(lpidCurr->lpi,0,IID_IShellFolder,(LPVOID*)&psfCurr); +#endif + + if (psfCurr == NULL) + { + SHGetDesktopFolder(&psfCurr); + } + return psfCurr; +} + +CString CIEFolderTreeCtrl::GetPathName(HTREEITEM hItem) +{ + if (hItem == NULL) + hItem = GetSelectedItem(); + CString sPath; + if (hItem == NULL) + return sPath; + LPTVITEMDATA lptvid = (LPTVITEMDATA)GetItemData(hItem); + if (lptvid != NULL) + { + SHGetPathFromIDList(lptvid->lpifq,sPath.GetBuffer(MAX_PATH)); + sPath.ReleaseBuffer(); + } + return sPath; +} + + +void CIEFolderTreeCtrl::SetButtonState(HTREEITEM hItem) +{ + LPSHELLFOLDER psfCurr=GetItemFolder(hItem); + if (psfCurr == NULL) + return; + IEnumIDList* pItems=NULL; + HRESULT hr = psfCurr->EnumObjects(NULL, SHCONTF_FOLDERS, &pItems); + int nChildren=0; + if (SUCCEEDED(hr)) + { + pItems->Release(); + nChildren=1; + } + if (nChildren == 1 && !ItemHasChildren(hItem)) + { + TVITEM tv; + tv.mask = TVIF_CHILDREN; + ZeroMemory(&tv,sizeof(tv)); + SetItem(&tv); + } + psfCurr->Release(); +} + +void CIEFolderTreeCtrl::RefreshNode(HTREEITEM hItem) +{ + // If the item is not expanded, update its button state and return. + if (!(GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED)) + { + SetButtonState(hItem); + return; + } + LPSHELLFOLDER psfCurr=GetItemFolder(hItem); + if (psfCurr == NULL) + return; + mapPidlToHTREEITEM mPidlCurr; + vecPidl vPidlNew; + HTREEITEM hSelItem = GetSelectedItem(); + HTREEITEM hChild = GetChildItem(hItem); + while (hChild != NULL) + { + HTREEITEM hNextItem = GetNextSiblingItem(hChild); + LPTVITEMDATA lpid = (LPTVITEMDATA)GetItemData(hChild); + mPidlCurr[CShellPidlCompare(psfCurr,lpid->lpi)] = hChild; + hChild = hNextItem; + } + LPITEMIDLIST pidlNext=NULL; + LPITEMIDLIST pidlCopy=NULL; + IEnumIDList* pItems=NULL; + DWORD dwFlags = SHCONTF_FOLDERS; + if (GetShellSettings().ShowAllObjects() && !GetShellSettings().ShowSysFiles()) + dwFlags |= SHCONTF_INCLUDEHIDDEN; + HRESULT hr = psfCurr->EnumObjects(NULL, dwFlags, &pItems); + while (NOERROR == hr) + { + hr = pItems->Next(1, &pidlNext, NULL); + if (hr == S_FALSE || pidlNext == NULL)// || pidlNext == pidlCopy) + break; + pidlCopy = pidlNext; + mapPidlToHTREEITEM::iterator it = mPidlCurr.find(CShellPidlCompare(psfCurr,pidlNext)); + if (it != mPidlCurr.end()) + { + mPidlCurr.erase(it); + } + else + { + SetAttributes((*it).second,psfCurr,pidlNext); + vPidlNew.push_back(GetShellPidl().CopyItemIDList(pidlNext)); + } + GetShellPidl().FreePidl(pidlNext); + pidlNext=NULL; + } + if (pItems) + pItems->Release(); + for(mapPidlToHTREEITEM::iterator it1=mPidlCurr.begin();it1 != mPidlCurr.end();it1++) + { + HTREEITEM hDelItem = (*it1).second; +#ifdef _DEBUG + CString sPath; + GetShellPidl().SHPidlToPathEx((*it1).first.GetPidl(),sPath,psfCurr); + TRACE1("Deleting item %s in tree refresh\n",sPath); +#endif + DeleteItem(hDelItem); + } + HTREEITEM hSortItem=NULL; + for(vecPidl::iterator it2=vPidlNew.begin();it2 != vPidlNew.end();it2++) + { + AddFolder(hItem,*it2,psfCurr); + hSortItem = hItem; + } + if (hSortItem) + Sort(hSortItem,psfCurr); + // Remove all items from the map + mPidlCurr.erase(mPidlCurr.begin(),mPidlCurr.end()); + vPidlNew.erase(vPidlNew.begin(),vPidlNew.end()); + psfCurr->Release(); + // Now repeat this procedure for hItem's children. + hChild = GetChildItem(hItem); + + while (hChild != NULL) + { + RefreshNode(hChild); + hChild = GetNextSiblingItem (hChild); + } +} + +void CIEFolderTreeCtrl::Init() +{ + CUITreeCtrl::Init(); + + GetShellSettings().GetSettings(); + // TODO: Add your specialized code here and/or call the base class + // Get the handle to the system image list, for our icons + SHFILEINFO sfi; + + m_hImageList = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T("C:\\"), + 0, + &sfi, + sizeof(SHFILEINFO), + SHGFI_SYSICONINDEX | SHGFI_SMALLICON); + + // Attach ImageList to TreeCtrl + if (m_hImageList) + ::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM) TVSIL_NORMAL,(LPARAM)m_hImageList); +} + +void CIEFolderTreeCtrl::OnDestroy() +{ + SetImageList(NULL,TVSIL_NORMAL); + CUITreeCtrl::OnDestroy(); +} + +LRESULT CIEFolderTreeCtrl::OnSettingChange(WPARAM wParam,LPARAM lParam) +{ + LPCTSTR lpszSection=(LPCTSTR)lParam; + if (lpszSection == NULL) + return 0L; + if (lstrcmpi(lpszSection, _T("ShellState")) == 0) + { + GetShellSettings().GetSettings(); + Refresh(); + } + return 1L; +}