dirlistview.divers.cpp

来自「c++系统开发实例精粹内附的80例源代码 环境:windows2000,c++」· C++ 代码 · 共 398 行

CPP
398
字号
//////////////////////////////////////////////////////////////////////
// FileFury
// Copyright (c) 2000 Tenebril Incorporated
// All rights reserved.
//
// This source code is governed by the Tenebril open source
// license (http://www.tenebril.com/developers/opensource/license.html)
//
// For more information on this and other open source applications,
// visit the Tenebril OpenSource page:
//       http://www.tenebril.com/developers/opensource
//
//////////////////////////////////////////////////////////////////////

// DirListView.Divers.cpp : implementation file
//

#include "stdafx.h"
#include "Oscar.h"
#include <shlobj.h>

#include "DirListView.h"
#include "DirSplitter.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

bool CDirListView::IsItemBefore(int iBase, int iCheck)
{
	CString strBase, strCheck;
	bool bBaseDir, bCheckDir;
	int iBaseArray, iCheckArray;
	int iSortType, iThisSort;
	UINT uBaseVal, uCheckVal;

	iBaseArray = (int)m_List.GetItemData(iBase);
	bBaseDir = m_cFileArray.GetDirectory(iBaseArray);
	iCheckArray = (int)m_List.GetItemData(iCheck);
	bCheckDir = m_cFileArray.GetDirectory(iCheckArray);

	CString TestBase = m_cFileArray.GetFullName(iBaseArray);
	CString TestCheck = m_cFileArray.GetFullName(iCheckArray);

	// We want directories to be compared by name only
	if(!bBaseDir && !bCheckDir)
		iThisSort = m_iSortType;
	else
		iThisSort = 0;

	switch(iThisSort)
	{
	case 0: default:                                          // Sort by name
		strBase = m_List.GetItemText(iBase, 0);
		strCheck = m_List.GetItemText(iCheck, 0);
		iSortType = 0;                                        // Alphabetic
		break;

	case 1:                                                   // Sort by type
		strBase = m_cFileArray.GetType(iBaseArray);
		strCheck = m_cFileArray.GetType(iCheckArray);
		iSortType = 0;
		break;

	case 2:                                                   // Sort by size
		strBase = m_cFileArray.GetSize(iBaseArray);
		strCheck = m_cFileArray.GetSize(iCheckArray);

		//Trim the KB off the end
		if(strBase.Find(_T("KB")) > -1)
			strBase = strBase.Left(strBase.GetLength() - 2);
		if(strCheck.Find(_T("KB")) > -1)
			strCheck = strCheck.Left(strCheck.GetLength() - 2);

		//Remove commas
		int iPos;
		while((iPos = strBase.Find(_T(','))) > -1)
		{
			CString temp;
			temp = strBase.Left(iPos) + strBase.Right(strBase.GetLength() - iPos - 1);
			strBase = temp;
		}
		while((iPos = strCheck.Find(_T(','))) > -1)
		{
			CString temp;
			temp = strCheck.Left(iPos) + strCheck.Right(strCheck.GetLength() - iPos - 1);
			strCheck = temp;
		}

		iSortType = 1;                                        // Numeric
		break;

	case 3:                                                   // Sort by date
		uBaseVal = (UINT)m_cFileArray.GetModTime(iBaseArray);
		uCheckVal = (UINT)m_cFileArray.GetModTime(iCheckArray);
		iSortType = 2;                                        // Implicit
		break;
	}

	if((bBaseDir && bCheckDir) || (!bBaseDir && !bCheckDir))  // Compare two
		                                                      // directories or
															  // files fairly
	{
		if(iSortType == 0)
			return (strCheck.CompareNoCase(strBase) > 0);

		if(iSortType == 2)
			return (uCheckVal > uBaseVal);

		int iBaseVal, iCheckVal;
		iBaseVal = atoi(strBase);
		iCheckVal = atoi(strCheck);

		return (iCheckVal > iBaseVal);
	}

	if(bBaseDir && !bCheckDir)        // Directories always come before files
		return true;

	return false;
}

bool CDirListView::ShouldHighlight( int iIndex )
{
	if(iIndex < 0)
		return false;

	int iArray = (int)m_List.GetItemData(iIndex);

	if(m_nDragIndex == iIndex)        // Can't drop onto yourself
		return false;

	if(!m_cFileArray.GetDirectory(iArray))    // Can't drop onto a non-directory
		return false;

	return true;
}

BOOL CDirListView::SortTextItems( BOOL bAscending, 
								  int low, int high )
{
	if( high == -1 ) high = m_List.GetItemCount() - 1;

	int lo = low;
	int hi = high;
	int mid = (lo + hi) / 2;

	if( hi <= lo ) return FALSE;

	// loop through the list until indices cross
	while( lo <= hi )
	{
		// rowText will hold all column text for one row
		CStringArray rowText;

		// find the first element that is greater than or equal to 
		// the partition element starting from the left Index.
		if( bAscending )
			while( ( lo < high ) && ( IsItemBefore(lo, mid )))
				++lo;
		else
			while( ( lo < high ) && ( IsItemBefore(mid, lo)))
				++lo;

		// find an element that is smaller than or equal to 
		// the partition element starting from the right Index.
		if( bAscending )
			while( ( hi > low ) && ( IsItemBefore(mid, hi)))
				--hi;
		else
			while( ( hi > low ) && ( IsItemBefore(hi, mid)))
				--hi;

		// if the indexes have not crossed, swap
		// and if the items are not equal
		if( lo <= hi )
		{
			// swap only if the items are not equal
			if( m_List.GetItemText(lo, 0) != m_List.GetItemText(hi, 0))
			{
				// swap the rows
				LV_ITEM lvitemlo, lvitemhi;
				int nColCount = 
					((CHeaderCtrl*)m_List.GetDlgItem(0))->GetItemCount();

				if(nColCount < 1)      // When there are no columns
					nColCount = 1;

				rowText.SetSize( nColCount );
				int i;
				for( i=0; i<nColCount; i++)
					rowText[i] = m_List.GetItemText(lo, i);
				lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
				lvitemlo.iItem = lo;
				lvitemlo.iSubItem = 0;
				lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED | 
						LVIS_FOCUSED |  LVIS_SELECTED | 
						LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;

				lvitemhi = lvitemlo;
				lvitemhi.iItem = hi;

				m_List.GetItem( &lvitemlo );
				m_List.GetItem( &lvitemhi );

				for( i=0; i<nColCount; i++)
					m_List.SetItemText(lo, i, m_List.GetItemText(hi, i));

				lvitemhi.iItem = lo;
				m_List.SetItem( &lvitemhi );

				for( i=0; i<nColCount; i++)
					m_List.SetItemText(hi, i, rowText[i]);

				lvitemlo.iItem = hi;
				m_List.SetItem( &lvitemlo );

				// if swapping the mid, keep it updated
				if(mid == lo)
					mid = hi;
				else if(mid == hi)
					mid = lo;
			}

			++lo;
			--hi;
		}
	}

	// If the right index has not reached the left side of array
	// must now sort the left partition.
	if( low < hi )
		SortTextItems(bAscending , low, hi);

	// If the left index has not reached the right side of array
	// must now sort the right partition.
	if( lo < high )
		SortTextItems(bAscending , lo, high);

	return TRUE;
}

void CDirListView::FormatColumns(int iViewType)
{
	// build list columns
	CRect cr;
	GetClientRect(&cr);

	if(iViewType == 3)      // Details
	{
		// First check to see if we've already added the below columns.
		if(m_bHasFormattedColumns)
			return;

		m_bHasFormattedColumns = TRUE;

	//	int nWidth = cr.Width()/4;
		int nWidth = 100;

		// set up the grid column titles
		LV_COLUMN lvcol;
		lvcol.cx = nWidth;
		lvcol.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
		lvcol.fmt = LVCFMT_LEFT;
		lvcol.pszText = (LPSTR)"Name";
		lvcol.iSubItem = 0;
		m_List.InsertColumn( 0, &lvcol );

		// second col
		lvcol.fmt = LVCFMT_RIGHT;
		lvcol.pszText = (LPSTR)"Size";
		lvcol.iSubItem = 1;
		m_List.InsertColumn( 1, &lvcol );

		// third col
		lvcol.fmt = LVCFMT_LEFT;
		lvcol.pszText = (LPSTR)"Type";
		lvcol.iSubItem = 2;
		m_List.InsertColumn( 2, &lvcol );

		// fourth col
		lvcol.pszText = (LPSTR)"Modified";
		lvcol.iSubItem = 3;
		m_List.InsertColumn( 3, &lvcol );
	}

	return;
}

void CDirListView::SetViewType(int iType)
{
	LONG lCtrlStyle;

	if(iType < 0) iType = 0;
	if(iType > 3) iType = 0;

	m_iViewType = iType;

	lCtrlStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE);
	lCtrlStyle &= ~(LVS_ICON | LVS_SMALLICON | LVS_LIST | LVS_REPORT);
	lCtrlStyle &= ~(WS_HSCROLL | WS_VSCROLL);
	lCtrlStyle &= ~(LVS_ALIGNTOP | LVS_ALIGNLEFT);

	switch(m_iViewType)
	{
	case 0: default:   // Large icons
		lCtrlStyle |= (LVS_ICON | WS_VSCROLL | LVS_ALIGNTOP | LVS_AUTOARRANGE);
		m_iIconStyle = SHGFI_LARGEICON;

		break;

	case 1:            // Small icons
		lCtrlStyle |= (LVS_SMALLICON | WS_VSCROLL | LVS_ALIGNTOP | LVS_AUTOARRANGE);
		m_iIconStyle = SHGFI_SMALLICON;
		break;

	case 2:            // List
		lCtrlStyle |= (LVS_LIST | WS_HSCROLL | LVS_ALIGNLEFT | LVS_AUTOARRANGE);
		m_iIconStyle = SHGFI_SMALLICON;
		break;

	case 3:            // Details
		lCtrlStyle |= (LVS_REPORT | WS_HSCROLL | WS_VSCROLL | LVS_ALIGNTOP | LVS_AUTOARRANGE);
		m_iIconStyle = SHGFI_SMALLICON;
		break;
	}

	SetWindowLong(m_List.m_hWnd, GWL_STYLE, lCtrlStyle);

	FormatColumns(m_iViewType);

	// Refresh the view (switching icons).
	DisplayList(m_strPath, TRUE);

	// Send a resize message to fix the scrollbars.
	CRect crListRect;
	m_List.GetWindowRect(&crListRect);
	m_List.SetWindowPos(&wndTop, 0, 0, crListRect.Width() + 1, crListRect.Height(),
		SWP_NOZORDER | SWP_NOMOVE);  // Has to actually resize.
	m_List.SetWindowPos(&wndTop, 0, 0, crListRect.Width(), crListRect.Height(),
		SWP_NOZORDER | SWP_NOMOVE);

	return;
}

void CDirListView::SetArrangeType(int iType)
{
	if(iType < 0) iType = 0;
	if(iType > 3) iType = 0;

	m_iSortType = iType;

	m_List.SetRedraw( FALSE );
	SortTextItems(TRUE);
	m_List.SetRedraw( TRUE );

	return;
}

BOOL CDirListView::ExecuteFile(LPCTSTR strName)
{
	if(m_pFileSystem->IsDirectory(strName))     // Open a directory
	{
		CDirSplitter *pSplit = (CDirSplitter *)GetParent();

		if(!pSplit)
			return false;

		pSplit->SetDirectory(strName);
		return true;
	}
	else if(m_pFileSystem->IsLink(strName))     // Follow a link
	{
		TCHAR tcPathBuffer[MAX_PATH];
		CString cszLinkTarget;

		if(m_pFileSystem->ResolveLink(this->m_hWnd, strName, tcPathBuffer) ==
			(HRESULT)0)
			return false;

		cszLinkTarget = m_pFileSystem->GetFullPathName(tcPathBuffer);
		
		return ExecuteFile(cszLinkTarget);      // Recursively follow the link
	}

	// Check to see if it's a remote filesystem.
	if(m_pFileSystem->GetFSType() == 1)
	{
		// We want to just download the file, not execute it.
		return DownloadFile(strName);
	}

	// Execute a file
	return m_pFileSystem->ExecuteFile(this->m_hWnd, strName);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?