初步修复
This commit is contained in:
parent
8fc4357cc6
commit
e4714f3f0e
46705 changed files with 12004901 additions and 0 deletions
915
Third/XTToolkitPro/Source/Controls/XTShellListBase.cpp
Normal file
915
Third/XTToolkitPro/Source/Controls/XTShellListBase.cpp
Normal file
|
|
@ -0,0 +1,915 @@
|
|||
// XTShellListBase.cpp : implementation file
|
||||
//
|
||||
// This file is a part of the XTREME CONTROLS MFC class library.
|
||||
// (c)1998-2008 Codejock Software, All Rights Reserved.
|
||||
//
|
||||
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
||||
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
||||
// CONSENT OF CODEJOCK SOFTWARE.
|
||||
//
|
||||
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
||||
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
||||
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
||||
// SINGLE COMPUTER.
|
||||
//
|
||||
// CONTACT INFORMATION:
|
||||
// support@codejock.com
|
||||
// http://www.codejock.com
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Resource.h"
|
||||
|
||||
#include "Common/XTPVC80Helpers.h" // Visual Studio 2005 helper functions
|
||||
#include "Common/XTPResourceManager.h"
|
||||
|
||||
#include "XTDefines.h"
|
||||
#include "XTVC50Helpers.h"
|
||||
#include "XTFunctions.h"
|
||||
#include "XTHeaderCtrl.h"
|
||||
#include "XTListCtrlView.h"
|
||||
|
||||
#include "XTShellPidl.h"
|
||||
#include "XTShellSettings.h"
|
||||
#include "XTDirWatcher.h"
|
||||
#include "XTShellListBase.h"
|
||||
#include "XTSortClass.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define new DEBUG_NEW
|
||||
#undef THIS_FILE
|
||||
static char THIS_FILE[] = __FILE__;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CXTShellListBase
|
||||
|
||||
CXTShellListBase::CXTShellListBase()
|
||||
: m_pDirThread(0)
|
||||
{
|
||||
m_bContextMenu = TRUE;
|
||||
m_uFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
|
||||
|
||||
if (m_shSettings.ShowAllFiles() && !m_shSettings.ShowSysFiles())
|
||||
{
|
||||
m_uFlags |= SHCONTF_INCLUDEHIDDEN;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(::SHGetSpecialFolderLocation(NULL, CSIDL_INTERNET, &m_pidlINet)))
|
||||
{
|
||||
m_pidlINet = NULL;
|
||||
}
|
||||
|
||||
m_nNameColumnWidth = 150;
|
||||
|
||||
m_lpsfFolder = NULL;
|
||||
}
|
||||
|
||||
CXTShellListBase::~CXTShellListBase()
|
||||
{
|
||||
// End the directory monitoring thread.
|
||||
if (m_pDirThread)
|
||||
{
|
||||
m_pDirThread->StopNotifications();
|
||||
m_pDirThread = NULL;
|
||||
}
|
||||
|
||||
if (m_pidlINet)
|
||||
{
|
||||
CShellMalloc lpMalloc;
|
||||
lpMalloc.Free(m_pidlINet);
|
||||
}
|
||||
|
||||
SAFE_RELEASE(m_lpsfFolder);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CXTShellListBase message handlers
|
||||
|
||||
BOOL CXTShellListBase::PopulateListView(XT_TVITEMDATA* lptvid, LPSHELLFOLDER lpsf)
|
||||
{
|
||||
// Turn off redraw so the user does't see resorting
|
||||
m_pListCtrl->SetRedraw(false);
|
||||
|
||||
//clear the view for new items
|
||||
m_pListCtrl->DeleteAllItems();
|
||||
|
||||
SAFE_RELEASE(m_lpsfFolder);
|
||||
|
||||
if (InitListViewItems(lptvid, lpsf))
|
||||
{
|
||||
SortList((m_nSortedCol > -1) ? m_nSortedCol : 0,
|
||||
(m_nSortedCol > -1) ? m_bAscending : 1);
|
||||
|
||||
// create the directory monitoring thread.
|
||||
if (m_pDirThread == NULL)
|
||||
{
|
||||
m_pDirThread = (CXTDirWatcher*)AfxBeginThread(RUNTIME_CLASS(CXTDirWatcher),
|
||||
THREAD_PRIORITY_LOWEST, 0, CREATE_SUSPENDED, NULL);
|
||||
|
||||
m_pDirThread->SetFolderData(m_pListCtrl, lptvid);
|
||||
m_pDirThread->ResumeThread();
|
||||
}
|
||||
|
||||
// if the folder changed, update the folder data.
|
||||
else
|
||||
{
|
||||
TCHAR szFolderPath[_MAX_PATH];
|
||||
if (::SHGetPathFromIDList(lptvid->lpifq, szFolderPath))
|
||||
{
|
||||
CString strFolderPath = m_pDirThread->GetFolderPath();
|
||||
if (strFolderPath.CompareNoCase(szFolderPath) != 0)
|
||||
{
|
||||
m_pDirThread->SuspendThread();
|
||||
m_pDirThread->SetFolderData(m_pListCtrl, lptvid);
|
||||
m_pDirThread->ResumeThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_lpsfFolder = lpsf;
|
||||
m_lpsfFolder->AddRef();
|
||||
|
||||
m_pListCtrl->SetRedraw(true);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
m_pListCtrl->SetRedraw(true);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CXTShellListBase::BuildDefaultColumns()
|
||||
{
|
||||
CString strLabel;
|
||||
VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_NAME));
|
||||
m_pListCtrl->InsertColumn(0, strLabel, LVCFMT_LEFT, m_nNameColumnWidth, 0);
|
||||
|
||||
VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_SIZE));
|
||||
m_pListCtrl->InsertColumn(1, strLabel, LVCFMT_RIGHT, 100, 1);
|
||||
|
||||
VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_TYPE));
|
||||
m_pListCtrl->InsertColumn(2, strLabel, LVCFMT_LEFT, 120, 2);
|
||||
|
||||
VERIFY(XTPResourceManager()->LoadString(&strLabel, XT_IDS_MODIFIED));
|
||||
m_pListCtrl->InsertColumn(3, strLabel, LVCFMT_LEFT, 120, 3);
|
||||
}
|
||||
|
||||
BOOL CXTShellListBase::InitSystemImageLists()
|
||||
{
|
||||
HIMAGELIST himlSmall = GetSystemImageList(SHGFI_SMALLICON);
|
||||
|
||||
HIMAGELIST himlLarge = GetSystemImageList(SHGFI_LARGEICON);
|
||||
|
||||
if (himlSmall && himlLarge)
|
||||
{
|
||||
ListView_SetImageList(m_pListCtrl->GetSafeHwnd(), himlSmall, LVSIL_SMALL);
|
||||
ListView_SetImageList(m_pListCtrl->GetSafeHwnd(), himlLarge, LVSIL_NORMAL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CXTShellListBase::IsItemFiltered(LPCTSTR lpszItemName, ULONG ulItemAttrs)
|
||||
{
|
||||
if (ulItemAttrs & SFGAO_FOLDER)
|
||||
return FALSE;
|
||||
|
||||
if (!m_csIncludeEXT.IsEmpty())
|
||||
{
|
||||
TCHAR szDrive[_MAX_DRIVE];
|
||||
TCHAR szDir[_MAX_DIR];
|
||||
TCHAR szFileName[_MAX_FNAME];
|
||||
TCHAR szExt[_MAX_EXT];
|
||||
|
||||
SPLITPATH_S(lpszItemName, szDrive, szDir, szFileName, szExt);
|
||||
|
||||
if (_tcsclen(szExt) == 0)
|
||||
return m_csIncludeEXT.Find(_T("*.;")) == -1;
|
||||
|
||||
return m_csIncludeEXT.Find(szExt) == -1;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
BOOL CXTShellListBase::InitListViewItems(XT_TVITEMDATA* lptvid, LPSHELLFOLDER lpsf)
|
||||
{
|
||||
CShellMalloc lpMalloc;
|
||||
|
||||
if (!lpMalloc)
|
||||
return FALSE;
|
||||
|
||||
LPENUMIDLIST lpe = NULL;
|
||||
|
||||
if (FAILED(lpsf->EnumObjects(::GetParent(m_pListCtrl->m_hWnd), m_uFlags, &lpe)))
|
||||
return FALSE;
|
||||
|
||||
int iCtr = 0;
|
||||
ULONG ulFetched = 0;
|
||||
LPITEMIDLIST lpi = NULL;
|
||||
|
||||
while (lpe->Next(1, &lpi, &ulFetched) == S_OK)
|
||||
{
|
||||
// Now get the friendly name that we'll put in the treeview...
|
||||
CString szFileName, szFullFilePath;
|
||||
GetName(lpsf, lpi, SHGDN_NORMAL, szFileName);
|
||||
GetName(lpsf, lpi, SHGDN_FORPARSING, szFullFilePath);
|
||||
|
||||
// Note that since we are interested in the display attributes as well as
|
||||
// the other attributes, we need to set ulAttrs to SFGAO_DISPLAYATTRMASK
|
||||
// before calling GetAttributesOf();
|
||||
ULONG ulAttrs = SFGAO_DISPLAYATTRMASK | SFGAO_REMOVABLE;
|
||||
UINT uFlags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
|
||||
lpsf->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lpi, &ulAttrs);
|
||||
|
||||
BOOL bIncludeFile = !IsItemFiltered(szFullFilePath, ulAttrs);
|
||||
|
||||
if (bIncludeFile)
|
||||
{
|
||||
// allocate memory for ITEMDATA struct
|
||||
XT_LVITEMDATA* lplvid = new XT_LVITEMDATA;
|
||||
if (lplvid == NULL)
|
||||
{
|
||||
if (lpe)
|
||||
{
|
||||
lpe->Release();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lplvid->ulAttribs = ulAttrs;
|
||||
LPITEMIDLIST lpifqThisItem = ConcatPidls(lpMalloc, lptvid->lpifq, lpi);
|
||||
|
||||
LV_ITEM lvi;
|
||||
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
|
||||
lvi.iItem = iCtr++;
|
||||
lvi.iSubItem = 0;
|
||||
lvi.pszText = (LPTSTR)(LPCTSTR)szFileName;
|
||||
lvi.cchTextMax = 0;
|
||||
lvi.iImage = GetItemIcon(lpifqThisItem, uFlags);
|
||||
|
||||
lplvid->lpsfParent = lpsf;
|
||||
lpsf->AddRef();
|
||||
|
||||
// Make a copy of the ITEMIDLIST
|
||||
lplvid->lpi = DuplicateItem(lpMalloc, lpi);
|
||||
lvi.lParam = (LPARAM)lplvid;
|
||||
|
||||
// Add the item to the listview
|
||||
int iIndex = m_pListCtrl->InsertItem(&lvi);
|
||||
SetAttributes(iIndex, ulAttrs);
|
||||
if (iIndex >= 0)
|
||||
{
|
||||
TCHAR szItemPath[_MAX_PATH];
|
||||
::SHGetPathFromIDList(lpifqThisItem, szItemPath);
|
||||
|
||||
if (((ulAttrs & SFGAO_FILESYSTEM) == SFGAO_FILESYSTEM) &&
|
||||
((ulAttrs & SFGAO_FOLDER) == 0))
|
||||
{
|
||||
WIN32_FIND_DATA fdata;
|
||||
HANDLE handle = ::FindFirstFile(szItemPath, &fdata);
|
||||
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LONGLONG fsize = fdata.nFileSizeHigh*((LONGLONG)ULONG_MAX + 1) + fdata.nFileSizeLow;
|
||||
|
||||
TCHAR szBuffer[16];
|
||||
CString strSize;
|
||||
strSize.Format(_T("%s KB"), InsertCommas((fsize + 1024)/1024, szBuffer, 15));
|
||||
|
||||
m_pListCtrl->SetItemText(iIndex, 1, strSize);
|
||||
|
||||
FILETIME ltime;
|
||||
::FileTimeToLocalFileTime(&fdata.ftLastWriteTime, <ime);
|
||||
|
||||
SYSTEMTIME time;
|
||||
::FileTimeToSystemTime(<ime, &time);
|
||||
|
||||
if ((time.wYear >= 1970 && time.wYear <= 2038) &&
|
||||
(time.wMonth >= 1 && time.wMonth <= 12))
|
||||
{
|
||||
CTime cTime;
|
||||
cTime = CTime(
|
||||
time.wYear,
|
||||
time.wMonth,
|
||||
time.wDay,
|
||||
time.wHour,
|
||||
time.wMinute,
|
||||
time.wSecond);
|
||||
|
||||
m_pListCtrl->SetItemText(iIndex, 3, cTime.Format(_T("%m/%d/%y %I:%M %p")));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pListCtrl->SetItemText(iIndex, 3, _T("")); // Invalid date
|
||||
}
|
||||
|
||||
::FindClose(handle);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pListCtrl->SetItemText(iIndex, 2, _T("0 bytes"));
|
||||
}
|
||||
|
||||
SHFILEINFO sfi;
|
||||
::SHGetFileInfo((TCHAR*)lpifqThisItem, 0, &sfi,
|
||||
sizeof(SHFILEINFO), SHGFI_PIDL | SHGFI_TYPENAME);
|
||||
|
||||
m_pListCtrl->SetItemText(iIndex, 2, sfi.szTypeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lpifqThisItem)
|
||||
{
|
||||
lpMalloc.Free(lpifqThisItem);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (lpifqThisItem)
|
||||
{
|
||||
lpMalloc.Free(lpifqThisItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Free the pidl that the shell gave us.
|
||||
if (lpi)
|
||||
{
|
||||
lpMalloc.Free(lpi);
|
||||
lpi = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (lpe)
|
||||
{
|
||||
lpe->Release();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
TCHAR* CXTShellListBase::InsertCommas(LONGLONG value, TCHAR* szBufferOut, UINT nSize)
|
||||
{
|
||||
CString strValue; // 30 digits is a really big number
|
||||
TCHAR szBufferIn[30]; // 30 digits is a really big number
|
||||
TCHAR szDecimalSep[ 5 ];
|
||||
TCHAR szThousandSep[ 5 ];
|
||||
|
||||
NUMBERFMT fmt;
|
||||
fmt.NumDigits = 0; // No decimal places
|
||||
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILZERO, szBufferIn, 2);
|
||||
fmt.LeadingZero = _ttoi(szBufferIn);
|
||||
fmt.Grouping = 3;
|
||||
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSep, 4);
|
||||
fmt.lpDecimalSep = szDecimalSep;
|
||||
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szThousandSep, 4);
|
||||
fmt.lpThousandSep = szThousandSep;
|
||||
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER, szBufferIn, 2);
|
||||
fmt.NegativeOrder = _ttoi(szBufferIn);
|
||||
strValue.Format(_T("%I64d"), value);
|
||||
::GetNumberFormat(LOCALE_USER_DEFAULT, 0, strValue, &fmt, szBufferOut, nSize);
|
||||
|
||||
return szBufferOut;
|
||||
}
|
||||
|
||||
void CXTShellListBase::GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTV_ITEM lptvitem)
|
||||
{
|
||||
// Note that we don't check the return value here because if GetIcon()
|
||||
// fails, then we're in big trouble...
|
||||
lptvitem->iImage = GetItemIcon(lpifq,
|
||||
SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
|
||||
|
||||
lptvitem->iSelectedImage = GetItemIcon(lpifq,
|
||||
SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON);
|
||||
}
|
||||
|
||||
int CXTShellListBase::GetDoubleClickedItem()
|
||||
{
|
||||
CPoint point;
|
||||
::GetCursorPos(&point);
|
||||
m_pListCtrl->ScreenToClient(&point);
|
||||
|
||||
LV_HITTESTINFO lvhti;
|
||||
lvhti.pt = point;
|
||||
m_pListCtrl->HitTest(&lvhti);
|
||||
|
||||
if ((lvhti.flags & LVHT_ONITEM) == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return lvhti.iItem;
|
||||
}
|
||||
|
||||
void CXTShellListBase::ShowShellContextMenu(CPoint point)
|
||||
{
|
||||
if (m_bContextMenu == FALSE)
|
||||
return;
|
||||
|
||||
CPoint ptClient(point);
|
||||
m_pListCtrl->ScreenToClient(&ptClient);
|
||||
|
||||
int nIndex = point == CPoint(-1, -1) ? m_pListCtrl->GetNextItem(-1, LVNI_FOCUSED) : m_pListCtrl->HitTest(ptClient);
|
||||
|
||||
if (nIndex != -1)
|
||||
{
|
||||
if (point == CPoint(-1, -1))
|
||||
{
|
||||
CRect rcItem;
|
||||
m_pListCtrl->GetItemRect(nIndex, &rcItem, LVIR_ICON);
|
||||
point = rcItem.CenterPoint();
|
||||
m_pListCtrl->ClientToScreen(&point);
|
||||
}
|
||||
|
||||
XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(nIndex);
|
||||
ASSERT(lplvid != NULL);
|
||||
if (!lplvid)
|
||||
return;
|
||||
|
||||
CPtrArray arrItems;
|
||||
arrItems.Add(lplvid->lpi);
|
||||
|
||||
POSITION pos = m_pListCtrl->GetFirstSelectedItemPosition();
|
||||
|
||||
while (NULL != pos)
|
||||
{
|
||||
int nSelItem = m_pListCtrl->GetNextSelectedItem(pos);
|
||||
|
||||
XT_LVITEMDATA* lplvidSelected = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(nSelItem);
|
||||
ASSERT(lplvidSelected != NULL);
|
||||
|
||||
if (lplvidSelected != lplvid && lplvidSelected)
|
||||
arrItems.Add(lplvidSelected->lpi);
|
||||
}
|
||||
|
||||
CXTShellPidl::ShowContextMenu(m_pListCtrl->m_hWnd,
|
||||
lplvid->lpsfParent, (LPCITEMIDLIST*)arrItems.GetData(), (int)arrItems.GetSize(), &point);
|
||||
|
||||
}
|
||||
else if (m_lpsfFolder)
|
||||
{
|
||||
ShowContextMenu(m_pListCtrl->m_hWnd, m_lpsfFolder, 0, 0, &point);
|
||||
}
|
||||
}
|
||||
|
||||
bool CXTShellListBase::ShellOpenItem(int iItem)
|
||||
{
|
||||
// Long pointer to ListView item data
|
||||
XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(iItem);
|
||||
return ShellOpenItem(lplvid);
|
||||
}
|
||||
|
||||
bool CXTShellListBase::ShellOpenItem(XT_LVITEMDATA* lplvid)
|
||||
{
|
||||
// Long pointer to ListView item data
|
||||
if (!(lplvid->ulAttribs & (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_REMOVABLE)))
|
||||
{
|
||||
SHELLEXECUTEINFO sei;
|
||||
::ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
|
||||
|
||||
sei.cbSize = sizeof(SHELLEXECUTEINFO);
|
||||
sei.fMask = SEE_MASK_INVOKEIDLIST;
|
||||
sei.hwnd = ::GetParent(m_pListCtrl->m_hWnd);
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.hInstApp = AfxGetInstanceHandle();
|
||||
sei.lpIDList = GetFullyQualPidl(lplvid->lpsfParent, lplvid->lpi);
|
||||
|
||||
if (::ShellExecuteEx(&sei))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL CXTShellListBase::GetItemPath(int iItem, CString& strItemPath)
|
||||
{
|
||||
if (iItem >= 0)
|
||||
{
|
||||
// Long pointer to TreeView item data
|
||||
XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)m_pListCtrl->GetItemData(iItem);
|
||||
if (lplvid != 0)
|
||||
{
|
||||
LPITEMIDLIST lpid = GetFullyQualPidl(lplvid->lpsfParent, lplvid->lpi);
|
||||
|
||||
TCHAR szItemPath[_MAX_PATH];
|
||||
if (::SHGetPathFromIDList(lpid, szItemPath))
|
||||
{
|
||||
strItemPath = szItemPath;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CXTShellListBase::OnDeleteListItem(NMHDR* pNMHDR, LRESULT* pResult)
|
||||
{
|
||||
NM_LISTVIEW* pNMTreeView = (NM_LISTVIEW*)pNMHDR;
|
||||
|
||||
XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)pNMTreeView->lParam;
|
||||
if (lplvid != NULL)
|
||||
{
|
||||
CShellMalloc lpMalloc;
|
||||
|
||||
if (lplvid->lpi)
|
||||
{
|
||||
lpMalloc.Free(lplvid->lpi);
|
||||
lplvid->lpi = NULL;
|
||||
}
|
||||
if (lplvid->lpsfParent)
|
||||
{
|
||||
lplvid->lpsfParent->Release();
|
||||
lplvid->lpsfParent = NULL;
|
||||
}
|
||||
|
||||
delete lplvid;
|
||||
}
|
||||
|
||||
*pResult = 0;
|
||||
}
|
||||
|
||||
|
||||
void CXTShellListBase::UpdateList(int nMessage, XT_TVITEMDATA* pItemData)
|
||||
{
|
||||
switch (nMessage)
|
||||
{
|
||||
case SHN_XT_CONTENTSCHANGED:
|
||||
case SHN_XT_TREESELCHANGE:
|
||||
{
|
||||
CWnd* pOwner = m_pListCtrl->GetOwner();
|
||||
ASSERT_VALID(pOwner);
|
||||
if (!pOwner)
|
||||
return;
|
||||
|
||||
// The tree view selection has changed, so update the contents
|
||||
// of the list view
|
||||
XT_TVITEMDATA* lptvid = (XT_TVITEMDATA*)pItemData;
|
||||
ASSERT(lptvid != NULL);
|
||||
if (!lptvid)
|
||||
return;
|
||||
|
||||
if (lptvid->lpsfParent == NULL)
|
||||
{
|
||||
CShellMalloc lpMalloc;
|
||||
if (!lpMalloc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LPSHELLFOLDER lpShellFolder;
|
||||
if (FAILED(::SHGetDesktopFolder(&lpShellFolder)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LPITEMIDLIST pidlDesktop = NULL;
|
||||
if (FAILED(::SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidlDesktop)))
|
||||
{
|
||||
lpShellFolder->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
IShellFolder *pFolder = NULL;
|
||||
if (lpShellFolder->CompareIDs(0, lptvid->lpifq, pidlDesktop) == 0)
|
||||
{
|
||||
pFolder = lpShellFolder;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpShellFolder->BindToObject(lptvid->lpifq, 0, IID_IShellFolder, (LPVOID*)&pFolder);
|
||||
lpShellFolder->Release();
|
||||
}
|
||||
ASSERT (pFolder != 0);
|
||||
|
||||
PopulateListView(lptvid, pFolder);
|
||||
|
||||
if (m_pidlINet && (pFolder->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
|
||||
{
|
||||
pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
pOwner->SendMessage(XTWM_SHELL_NOTIFY);
|
||||
}
|
||||
|
||||
if (pidlDesktop)
|
||||
{
|
||||
lpMalloc.Free(pidlDesktop);
|
||||
}
|
||||
if (pFolder)
|
||||
{
|
||||
pFolder->Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LPSHELLFOLDER lpsf = NULL;
|
||||
if (SUCCEEDED(lptvid->lpsfParent->BindToObject(lptvid->lpi,
|
||||
0, IID_IShellFolder, (LPVOID*)&lpsf)))
|
||||
{
|
||||
PopulateListView(lptvid, lpsf);
|
||||
lpsf->Release();
|
||||
|
||||
if (SUCCEEDED(::SHGetDesktopFolder(&lpsf)))
|
||||
{
|
||||
if (m_pidlINet && (lpsf->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
|
||||
{
|
||||
pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
pOwner->SendMessage(XTWM_SHELL_NOTIFY);
|
||||
}
|
||||
|
||||
lpsf->Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(::SHGetDesktopFolder(&lpsf)))
|
||||
{
|
||||
if (m_pidlINet && (lpsf->CompareIDs(0, lptvid->lpifq, m_pidlINet) == 0))
|
||||
{
|
||||
pOwner->SendMessage(XTWM_SHELL_NOTIFY, SHN_XT_INETFOLDER);
|
||||
}
|
||||
|
||||
lpsf->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SHN_XT_REFRESHFOLDER:
|
||||
case SHN_XT_REFRESHTREE:
|
||||
{
|
||||
// Directory monitory thread has issued an update notification,
|
||||
// refresh the list control.
|
||||
XT_TVITEMDATA* lpTVID = (XT_TVITEMDATA*)pItemData;
|
||||
ASSERT(lpTVID);
|
||||
if (!lpTVID)
|
||||
return;
|
||||
|
||||
PopulateListView(lpTVID, lpTVID->lpsfParent);
|
||||
break;
|
||||
}
|
||||
|
||||
case SHN_XT_NOFOLDER:
|
||||
{
|
||||
// The item double clicked was not found in the treeview
|
||||
// so it sent us back a confirmation to execute it
|
||||
XT_LVITEMDATA* lplvid = (XT_LVITEMDATA*)pItemData;
|
||||
ASSERT(lplvid);
|
||||
if (!lplvid)
|
||||
return;
|
||||
|
||||
ShellOpenItem(lplvid);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CXTShellListBase::SortList(int nCol, bool bAscending)
|
||||
{
|
||||
if (m_nSortedCol >= 0)
|
||||
{
|
||||
CXTFlatHeaderCtrl* pHeaderCtrl = GetFlatHeaderCtrl();
|
||||
if (pHeaderCtrl && pHeaderCtrl->GetSortedCol() < 0)
|
||||
{
|
||||
pHeaderCtrl->SetSortImage(nCol, bAscending);
|
||||
}
|
||||
}
|
||||
|
||||
if (nCol == 0)
|
||||
{
|
||||
return m_pListCtrl->SortItems(
|
||||
ListViewCompareProc, (DWORD)bAscending) == TRUE;
|
||||
}
|
||||
|
||||
XTSortType arrColType[] =
|
||||
{
|
||||
xtSortString, xtSortInt, xtSortString, xtSortDateTime
|
||||
};
|
||||
|
||||
CXTSortClass sortClass(m_pListCtrl, nCol);
|
||||
sortClass.Sort(bAscending, arrColType[nCol]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CXTShellListBase::SetAttributes(int iItem, DWORD dwAttributes)
|
||||
{
|
||||
MapShellFlagsToItemAttributes(m_pListCtrl, iItem, dwAttributes);
|
||||
}
|
||||
|
||||
void CXTShellListBase::OnDragDrop(NM_LISTVIEW* /*pNMListView*/)
|
||||
{
|
||||
COleDataSource oleDataSource;
|
||||
HGLOBAL hgDrop;
|
||||
DROPFILES* pDrop;
|
||||
CStringList lsDraggedFiles;
|
||||
POSITION pos;
|
||||
int nSelItem;
|
||||
CString sFile;
|
||||
UINT uBuffSize = 0;
|
||||
TCHAR* pszBuff;
|
||||
|
||||
FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
|
||||
// For every selected item in the list, put the filename into lsDraggedFiles.
|
||||
pos = m_pListCtrl->GetFirstSelectedItemPosition();
|
||||
|
||||
while (NULL != pos)
|
||||
{
|
||||
nSelItem = m_pListCtrl->GetNextSelectedItem(pos);
|
||||
GetItemPath(nSelItem, sFile);
|
||||
lsDraggedFiles.AddTail (sFile);
|
||||
|
||||
// Calculate the # of chars required to hold this string.
|
||||
uBuffSize += lstrlen (sFile) + 1;
|
||||
}
|
||||
|
||||
// Add 1 extra for the final null char, and the size of the DROPFILES struct.
|
||||
uBuffSize = sizeof(DROPFILES) + sizeof(TCHAR) * (uBuffSize + 1);
|
||||
|
||||
// Allocate memory from the heap for the DROPFILES struct.
|
||||
hgDrop = ::GlobalAlloc (GHND | GMEM_SHARE, uBuffSize);
|
||||
|
||||
if (NULL == hgDrop)
|
||||
return;
|
||||
|
||||
pDrop = (DROPFILES*) ::GlobalLock (hgDrop);
|
||||
|
||||
if (NULL == pDrop)
|
||||
{
|
||||
::GlobalFree (hgDrop);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill in the DROPFILES struct.
|
||||
pDrop->pFiles = sizeof(DROPFILES);
|
||||
|
||||
#ifdef _UNICODE
|
||||
// If we're compiling for Unicode, set the Unicode flag in the struct to
|
||||
// indicate it contains Unicode strings.
|
||||
pDrop->fWide = TRUE;
|
||||
#endif
|
||||
|
||||
// Copy all the filenames into memory after the end of the DROPFILES struct.
|
||||
pos = lsDraggedFiles.GetHeadPosition();
|
||||
pszBuff = (TCHAR*) (LPBYTE(pDrop) + sizeof(DROPFILES));
|
||||
|
||||
while (NULL != pos)
|
||||
{
|
||||
lstrcpy (pszBuff, (LPCTSTR) lsDraggedFiles.GetNext (pos));
|
||||
pszBuff = 1 + _tcschr (pszBuff, '\0');
|
||||
}
|
||||
|
||||
::GlobalUnlock (hgDrop);
|
||||
|
||||
// Put the data in the data source.
|
||||
oleDataSource.CacheGlobalData (CF_HDROP, hgDrop, &etc);
|
||||
|
||||
// Add in our own custom data, so we know that the drag originated from our
|
||||
// window. OnDragEnter() checks for this custom format, and
|
||||
// doesn't allow the drop if it's present. This is how we prevent the user
|
||||
// from dragging and then dropping in our own window.
|
||||
// The data will just be a dummy bool.
|
||||
HGLOBAL hgBool;
|
||||
|
||||
hgBool = ::GlobalAlloc (GHND | GMEM_SHARE, sizeof(bool));
|
||||
|
||||
if (NULL == hgBool)
|
||||
{
|
||||
::GlobalFree (hgDrop);
|
||||
return;
|
||||
}
|
||||
|
||||
static CLIPFORMAT clpFormat = (CLIPFORMAT)
|
||||
::RegisterClipboardFormat(_T("{B0D76F7A-B5D9-436c-8F10-BA16AEE69D42}"));
|
||||
|
||||
// Put the data in the data source.
|
||||
etc.cfFormat = clpFormat;
|
||||
oleDataSource.CacheGlobalData(clpFormat, hgBool, &etc);
|
||||
|
||||
// Start the drag 'n' drop!
|
||||
DROPEFFECT dwEffect = oleDataSource.DoDragDrop (DROPEFFECT_COPY | DROPEFFECT_MOVE);
|
||||
|
||||
// If the DnD completed OK, we remove all of the dragged items from our
|
||||
//
|
||||
switch (dwEffect)
|
||||
{
|
||||
case DROPEFFECT_MOVE:
|
||||
{
|
||||
// The files were copied or moved.
|
||||
// Note: Don't call ::GlobalFree() because the data will be freed by the drop target.
|
||||
for (nSelItem = m_pListCtrl->GetNextItem (-1, LVNI_SELECTED);
|
||||
nSelItem != -1;
|
||||
nSelItem = m_pListCtrl->GetNextItem (nSelItem, LVNI_SELECTED))
|
||||
{
|
||||
m_pListCtrl->DeleteItem (nSelItem);
|
||||
nSelItem--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DROPEFFECT_COPY:
|
||||
break;
|
||||
|
||||
case DROPEFFECT_NONE:
|
||||
{
|
||||
// This needs special handling, because on NT, DROPEFFECT_NONE
|
||||
// is returned for move operations, instead of DROPEFFECT_MOVE.
|
||||
// See Q182219 for the details.
|
||||
// So if we're on NT, we check each selected item, and if the
|
||||
// file no longer exists, it was moved successfully and we can
|
||||
// remove it from the
|
||||
if ((GetVersion() & 0x80000000) == 0)
|
||||
{
|
||||
bool bDeletedAnything = false;
|
||||
|
||||
for (nSelItem = m_pListCtrl->GetNextItem (-1, LVNI_SELECTED);
|
||||
nSelItem != -1;
|
||||
nSelItem = m_pListCtrl->GetNextItem(nSelItem, LVNI_SELECTED))
|
||||
{
|
||||
GetItemPath(nSelItem, sFile);
|
||||
|
||||
if (GetFileAttributes(sFile) == DWORD(-1) &&
|
||||
GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
// We couldn't read the file's attributes, and GetLastError()
|
||||
// says the file doesn't exist, so remove the corresponding
|
||||
// item from the
|
||||
m_pListCtrl->DeleteItem(nSelItem);
|
||||
|
||||
nSelItem--;
|
||||
bDeletedAnything = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Resize the list columns if we deleted any items.
|
||||
if (bDeletedAnything)
|
||||
{
|
||||
m_pListCtrl->SetColumnWidth (0, LVSCW_AUTOSIZE_USEHEADER);
|
||||
m_pListCtrl->SetColumnWidth (1, LVSCW_AUTOSIZE_USEHEADER);
|
||||
m_pListCtrl->SetColumnWidth (2, LVSCW_AUTOSIZE_USEHEADER);
|
||||
|
||||
// Note: Don't call ::GlobalFree() because the data belongs to
|
||||
// the caller.
|
||||
}
|
||||
else
|
||||
{
|
||||
// The DnD operation wasn't accepted, or was canceled, so we
|
||||
// should call ::GlobalFree() to clean up.
|
||||
::GlobalFree (hgDrop);
|
||||
::GlobalFree (hgBool);
|
||||
}
|
||||
} // end if (NT)
|
||||
else
|
||||
{
|
||||
// We're on 9x, and a return of DROPEFFECT_NONE always means
|
||||
// that the DnD operation was aborted. We need to free the
|
||||
// allocated memory.
|
||||
::GlobalFree (hgDrop);
|
||||
::GlobalFree (hgBool);
|
||||
}
|
||||
}
|
||||
break; // end case DROPEFFECT_NONE
|
||||
} // end switch
|
||||
}
|
||||
|
||||
|
||||
bool CXTShellListBase::Init()
|
||||
{
|
||||
if (!CXTListBase::Init())
|
||||
return false;
|
||||
|
||||
if (!m_pListCtrl->GetImageList(LVSIL_SMALL))
|
||||
{
|
||||
// Initialize the columns and image list for the list control.
|
||||
BuildDefaultColumns();
|
||||
InitSystemImageLists();
|
||||
m_pListCtrl->ModifyStyle(NULL, LVS_REPORT | LVS_SHAREIMAGELISTS);
|
||||
|
||||
SubclassHeader(FALSE);
|
||||
GetFlatHeaderCtrl()->ShowSortArrow(TRUE);
|
||||
|
||||
m_pListCtrl->DragAcceptFiles(TRUE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue