⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ctrlbrowsetree.cpp

📁 p2p软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// CtrlBrowseTree.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "CoolInterface.h"
#include "CtrlBrowseTree.h"
#include "ShellIcons.h"
#include "G2Packet.h"
#include "Schema.h"
#include "SchemaCache.h"
#include "XML.h"

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

IMPLEMENT_DYNAMIC(CBrowseTreeCtrl, CWnd)

BEGIN_MESSAGE_MAP(CBrowseTreeCtrl, CWnd)
	ON_WM_SIZE()
	ON_WM_VSCROLL()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_MOUSEWHEEL()
	ON_WM_KEYDOWN()
	ON_WM_RBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

#define ITEM_HEIGHT	16


/////////////////////////////////////////////////////////////////////////////
// CBrowseTreeCtrl construction

CBrowseTreeCtrl::CBrowseTreeCtrl()
{
	m_pRoot = new CBrowseTreeItem();
	m_pRoot->m_bExpanded = TRUE;

	m_nTotal		= 0;
	m_nVisible		= 0;
	m_nScroll		= 0;
	m_nSelected		= 0;
	m_pSelFirst		= NULL;
	m_pSelLast		= NULL;
	m_pFocus		= NULL;
	m_nCleanCookie	= 0;
}

CBrowseTreeCtrl::~CBrowseTreeCtrl()
{
	delete m_pRoot;
}

/////////////////////////////////////////////////////////////////////////////
// CBrowseTreeCtrl operations

BOOL CBrowseTreeCtrl::Create(CWnd* pParentWnd) 
{
	CRect rect( 0, 0, 0, 0 );
	return CWnd::Create( NULL, _T("CBrowseTreeCtrl"),
		WS_CHILD|WS_TABSTOP|WS_VSCROLL, rect, pParentWnd, IDC_BROWSE_TREE, NULL );
}

void CBrowseTreeCtrl::Clear()
{
	if ( m_pRoot->m_nCount == 0 ) return;
	
	m_pRoot->Clear();
	
	m_nTotal		= 0;
	m_nSelected		= 0;
	m_pSelFirst		= NULL;
	m_pSelLast		= NULL;
	m_pFocus		= NULL;
	
	UpdateScroll();
	Invalidate();
}

/////////////////////////////////////////////////////////////////////////////
// CBrowseTreeCtrl expand

BOOL CBrowseTreeCtrl::Expand(CBrowseTreeItem* pItem, TRISTATE bExpand, BOOL bInvalidate)
{
	if ( pItem == NULL ) return FALSE;
	
	switch ( bExpand )
	{
	case TS_UNKNOWN:
		pItem->m_bExpanded = ! pItem->m_bExpanded;
		break;
	case TS_TRUE:
		if ( pItem->m_bExpanded ) return FALSE;
		pItem->m_bExpanded = TRUE;
		break;
	case TS_FALSE:
		if ( ! pItem->m_bExpanded ) return FALSE;
		pItem->m_bExpanded = FALSE;
		break;
	}

	if ( ! pItem->IsVisible() ) return FALSE;

	if ( pItem->m_bExpanded )
	{
		m_nTotal += pItem->GetChildCount();
	}
	else
	{
		m_nTotal -= pItem->GetChildCount();
		DeselectAll( NULL, pItem, FALSE );
	}
	
	pItem->m_bContract1 = pItem->m_bExpanded == TRUE && bExpand == TS_TRUE && bInvalidate == FALSE;
	
	if ( pItem->m_bContract1 == FALSE )
	{
		for ( CBrowseTreeItem* pParent = pItem ; pParent != NULL ; pParent = pParent->m_pParent )
			pParent->m_bContract1 = FALSE;
	}
	
	if ( bInvalidate )
	{
		UpdateScroll();
		Invalidate();
	}

	return TRUE;
}

BOOL CBrowseTreeCtrl::CollapseRecursive(CBrowseTreeItem* pItem)
{
	BOOL bChanged = FALSE;
	
	if ( pItem != m_pRoot && pItem->m_bExpanded && pItem->m_bContract1 )
	{
		bChanged |= Expand( pItem, TS_FALSE, FALSE );
	}
	
	CBrowseTreeItem** pChild = pItem->m_pList;
	
	for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
	{
		bChanged |= CollapseRecursive( *pChild );
	}
	
	return bChanged;
}

/////////////////////////////////////////////////////////////////////////////
// CBrowseTreeCtrl selection

BOOL CBrowseTreeCtrl::Select(CBrowseTreeItem* pItem, TRISTATE bSelect, BOOL bInvalidate)
{
	if ( pItem == NULL ) return FALSE;
	
	switch ( bSelect )
	{
	case TS_UNKNOWN:
		pItem->m_bSelected = ! pItem->m_bSelected;
		break;
	case TS_TRUE:
		if ( pItem->m_bSelected ) return FALSE;
		pItem->m_bSelected = TRUE;
		break;
	case TS_FALSE:
		if ( ! pItem->m_bSelected ) return FALSE;
		pItem->m_bSelected = FALSE;
		break;
	}
	
	if ( pItem->m_bSelected )
	{
		m_nSelected++;
		
		if ( m_pSelLast )
		{
			m_pSelLast->m_pSelNext = pItem;
			pItem->m_pSelPrev = m_pSelLast;
			pItem->m_pSelNext = NULL;
			m_pSelLast = pItem;
		}
		else
		{
			m_pSelFirst = m_pSelLast = pItem;
			pItem->m_pSelPrev = pItem->m_pSelNext = NULL;
		}
	}
	else
	{
		m_nSelected--;

		if ( pItem->m_pSelPrev )
			pItem->m_pSelPrev->m_pSelNext = pItem->m_pSelNext;
		else
			m_pSelFirst = pItem->m_pSelNext;

		if ( pItem->m_pSelNext )
			pItem->m_pSelNext = pItem->m_pSelNext->m_pSelPrev = pItem->m_pSelPrev;
		else
			m_pSelLast = pItem->m_pSelPrev;
	}

	if ( pItem->IsVisible() )
	{
		if ( bInvalidate ) Invalidate();
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

BOOL CBrowseTreeCtrl::DeselectAll(CBrowseTreeItem* pExcept, CBrowseTreeItem* pParent, BOOL bInvalidate)
{
	if ( pParent == NULL ) pParent = m_pRoot;
	CBrowseTreeItem** pChild = pParent->m_pList;

	BOOL bChanged = FALSE;

	for ( int nCount = pParent->m_nCount ; nCount ; nCount--, pChild++ )
	{
		if ( *pChild != pExcept && (*pChild)->m_bSelected )
		{
			Select( *pChild, TS_FALSE, FALSE );
			bChanged = TRUE;
		}

		if ( (*pChild)->m_nCount ) bChanged |= DeselectAll( pExcept, *pChild, FALSE );
	}

	if ( bInvalidate && bChanged && pParent == m_pRoot ) Invalidate();

	return bChanged;
}

int CBrowseTreeCtrl::GetSelectedCount() const
{
	return m_nSelected;
}

CBrowseTreeItem* CBrowseTreeCtrl::GetFirstSelected() const
{
	return m_pSelFirst;
}

CBrowseTreeItem* CBrowseTreeCtrl::GetLastSelected() const
{
	return m_pSelLast;
}

BOOL CBrowseTreeCtrl::Highlight(CBrowseTreeItem* pItem)
{
	m_pFocus = pItem;
	
	for ( CBrowseTreeItem* pParent = m_pFocus->m_pParent ; pParent ; pParent = pParent->m_pParent )
	{
		Expand( pParent, TS_TRUE, FALSE );
		
		pParent->m_bContract2 = pParent->m_bContract1;
		pParent->m_bContract1 = FALSE;
	}
	
	CollapseRecursive( m_pRoot );
	
	for ( pParent = m_pFocus->m_pParent ; pParent ; pParent = pParent->m_pParent )
	{
		pParent->m_bContract1 = pParent->m_bContract2;
	}
	
	CRect rcItem, rcClient;
	
	if ( GetRect( m_pFocus, &rcItem ) )
	{
		GetClientRect( &rcClient );
		
		if ( rcItem.top <= rcClient.top )
			ScrollBy( rcItem.top - rcClient.top );
		else if ( rcItem.bottom > rcClient.bottom )
			ScrollBy( rcItem.bottom - rcClient.bottom );
	}
	
	UpdateScroll();
	Invalidate();

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CBrowseTreeCtrl internal helpers

BOOL CBrowseTreeCtrl::CleanItems(CBrowseTreeItem* pItem, DWORD nCookie, BOOL bVisible)
{
	CBrowseTreeItem** pChild = pItem->m_pList + pItem->m_nCount - 1;
	BOOL bChanged = FALSE;

	for ( int nChild = pItem->m_nCount ; nChild ; nChild--, pChild-- )
	{
		if ( (*pChild)->m_nCleanCookie != nCookie )
		{
			if ( m_pFocus == *pChild ) m_pFocus = NULL;

			if ( (*pChild)->m_bSelected ) Select( *pChild, TS_FALSE, FALSE );
			bChanged |= DeselectAll( NULL, *pChild, FALSE );

			if ( bVisible )
			{
				m_nTotal -= (*pChild)->GetChildCount() + 1;
				bChanged = TRUE;
			}
			
			delete *pChild;
			MoveMemory( pChild, pChild + 1, 4 * ( pItem->m_nCount - nChild ) );
			pItem->m_nCount--;
		}
	}

	return bChanged;
}

void CBrowseTreeCtrl::NotifySelection()
{
	NMHDR pNM = { GetSafeHwnd(), GetDlgCtrlID(), BTN_SELCHANGED };
	GetOwner()->SendMessage( WM_NOTIFY, pNM.idFrom, (LPARAM)&pNM );
}

/////////////////////////////////////////////////////////////////////////////
// CBrowseTreeCtrl message handlers

void CBrowseTreeCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize( nType, cx, cy );
	m_nVisible = cy;
	UpdateScroll();
}

void CBrowseTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CRect rc;
	CBrowseTreeItem* pHit = HitTest( point, &rc );
	BOOL bChanged = FALSE;
	
	SetFocus();
	
	if ( pHit && pHit->m_nCount && point.x >= rc.left && point.x < rc.left + 16 )
	{
		bChanged = Expand( pHit, TS_UNKNOWN );
	}
	else if ( nFlags & MK_CONTROL )
	{
		if ( pHit ) bChanged = Select( pHit, TS_UNKNOWN );
	}
	else if ( nFlags & MK_SHIFT )
	{
		if ( pHit ) bChanged = Select( pHit );
	}
	else
	{
		if ( ( nFlags & MK_RBUTTON ) == 0 || ( pHit && pHit->m_bSelected == FALSE ) )
			bChanged = DeselectAll( pHit );
		if ( pHit ) bChanged |= Select( pHit );
	}
	
	if ( pHit ) m_pFocus = pHit;
	
	if ( bChanged ) NotifySelection();
}

void CBrowseTreeCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	OnLButtonDown( nFlags, point );

	if ( m_pFocus != NULL && m_pFocus->m_nCount )
	{
		if ( Expand( m_pFocus, TS_UNKNOWN ) ) NotifySelection();
	}
}

void CBrowseTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	OnLButtonDown( nFlags, point );
	CWnd::OnRButtonDown( nFlags, point );
}

void CBrowseTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	CWnd::OnMouseMove( nFlags, point );
}

void CBrowseTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	ReleaseCapture();

	CWnd::OnLButtonUp( nFlags, point );
}

void CBrowseTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	CBrowseTreeItem* pTo = NULL;
	BOOL bChanged = FALSE;
	CRect rc;
	
	if ( nChar == VK_HOME || ( nChar == VK_UP && m_pFocus == NULL ) )
	{
		if ( m_pRoot->m_nCount ) pTo = m_pRoot->m_pList[0];
	}
	else if ( nChar == VK_END || ( nChar == VK_DOWN && m_pFocus == NULL ) )
	{
		if ( m_pRoot->m_nCount ) pTo = m_pRoot->m_pList[ m_pRoot->m_nCount - 1 ];
	}
	else if ( nChar == VK_UP && m_pFocus != NULL )
	{
		if ( GetRect( m_pFocus, &rc ) )
		{
			CPoint pt( rc.left, ( rc.top + rc.bottom ) / 2 );
			pt.y -= ITEM_HEIGHT;
			pTo = HitTest( pt );
		}
	}
	else if ( nChar == VK_DOWN && m_pFocus != NULL )
	{
		if ( GetRect( m_pFocus, &rc ) )
		{
			CPoint pt( rc.left, ( rc.top + rc.bottom ) / 2 );
			pt.y += ITEM_HEIGHT;
			pTo = HitTest( pt );
		}
	}
	else if ( ( nChar == VK_LEFT || nChar == VK_SUBTRACT ) && m_pFocus != NULL )
	{
		while ( TRUE )
		{
			if ( m_pFocus->m_bExpanded && m_pFocus->m_nCount )
			{
				Expand( m_pFocus, TS_FALSE );
				break;
			}

			if ( m_pFocus->m_pParent == m_pRoot ) break;
			m_pFocus = m_pFocus->m_pParent;

			bChanged |= DeselectAll( m_pFocus );
			bChanged |= Select( m_pFocus );
		}

		Highlight( m_pFocus );
	}
	else if ( ( nChar == VK_RIGHT || nChar == VK_ADD ) && m_pFocus != NULL )
	{
		if ( ! m_pFocus->m_bExpanded && m_pFocus->m_nCount )
		{
			bChanged |= Expand( m_pFocus, TS_TRUE );
		}
	}
	else if ( _istalnum( nChar ) )
	{
		CBrowseTreeItem* pStart	= m_pFocus;
		CBrowseTreeItem* pBase	= pStart ? pStart->m_pParent : m_pRoot;
				
		for ( int nLoop = 0 ; nLoop < 2 ; nLoop++ )
		{
			CBrowseTreeItem** pChild = pBase->m_pList;

			for ( int nCount = pBase->m_nCount ; nCount ; nCount--, pChild++ )
			{
				if ( pStart != NULL )
				{
					if ( pStart == *pChild ) pStart = NULL;
				}
				else if ( toupper( (*pChild)->m_sText.GetAt( 0 ) ) == (int)nChar )
				{
					DeselectAll( m_pFocus = *pChild, NULL, FALSE );
					Select( m_pFocus, TS_TRUE, FALSE );
					Highlight( m_pFocus );
					NotifySelection();
					return;
				}
			}
		}
	}
	
	if ( pTo != NULL )
	{
		if ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0 || m_pFocus == NULL )
		{
			bChanged |= DeselectAll( m_pFocus = pTo );
			bChanged |= Select( m_pFocus );
		}
		else
		{
			bChanged |= Select( m_pFocus = pTo );
		}

		Highlight( m_pFocus );
	}
	
	if ( bChanged ) NotifySelection();
}

/////////////////////////////////////////////////////////////////////////////
// CBrowseTreeCtrl scrolling

void CBrowseTreeCtrl::UpdateScroll()
{
	SCROLLINFO pInfo;
	
	pInfo.cbSize	= sizeof(pInfo);
	pInfo.fMask		= SIF_PAGE | SIF_POS | SIF_RANGE;
	pInfo.nMin		= 0;
	pInfo.nMax		= m_nTotal * ITEM_HEIGHT;
	pInfo.nPage		= m_nVisible;
	pInfo.nPos		= m_nScroll = max( 0, min( m_nScroll, pInfo.nMax - (int)pInfo.nPage + 1 ) );
	
	SetScrollInfo( SB_VERT, &pInfo, IsWindowVisible() );
}

void CBrowseTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	switch ( nSBCode )
	{
	case SB_BOTTOM:
		ScrollTo( 0xFFFFFFFF );
		break;
	case SB_LINEDOWN:
		ScrollBy( 1 );
		break;
	case SB_LINEUP:
		ScrollBy( -1 );
		break;

⌨️ 快捷键说明

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