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

📄 ctrllibrarytree.cpp

📁 p2p软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// CtrlLibraryTree.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 "ShellIcons.h"
#include "Library.h"
#include "LibraryFolders.h"
#include "CtrlLibraryTree.h"
#include "CtrlLibraryFrame.h"
#include "CtrlCoolTip.h"
#include "SharedFolder.h"
#include "AlbumFolder.h"
#include "Schema.h"

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

IMPLEMENT_DYNAMIC(CLibraryTreeCtrl, CWnd)

BEGIN_MESSAGE_MAP(CLibraryTreeCtrl, CWnd)
	//{{AFX_MSG_MAP(CLibraryTreeCtrl)
	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()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

#define ITEM_HEIGHT	16


/////////////////////////////////////////////////////////////////////////////
// CLibraryTreeCtrl construction

CLibraryTreeCtrl::CLibraryTreeCtrl()
{
	m_pRoot = new CLibraryTreeItem();
	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_bDrag			= FALSE;
	m_pDropItem		= NULL;
	m_nCleanCookie	= 0;
	m_pTip			= NULL;
}

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

/////////////////////////////////////////////////////////////////////////////
// CLibraryTreeCtrl operations

BOOL CLibraryTreeCtrl::Create(CWnd* pParentWnd) 
{
	CRect rect;
	return CWnd::Create( NULL, _T("CLibraryTreeCtrl"),
		WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL, rect, pParentWnd, IDC_LIBRARY_TREE, NULL );
}

void CLibraryTreeCtrl::SetToolTip(CCoolTipCtrl* pTip)
{
	if ( m_pTip ) m_pTip->Hide();
	m_pTip = pTip;
	if ( m_pTip ) m_pTip->SetOwner( this );
}

void CLibraryTreeCtrl::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;
	m_pDropItem		= NULL;

	if ( m_pTip ) m_pTip->Hide();

	// NotifySelection(); NOT NOTIFIED
	UpdateScroll();
	Invalidate();
}

/////////////////////////////////////////////////////////////////////////////
// CLibraryTreeCtrl expand

BOOL CLibraryTreeCtrl::Expand(CLibraryTreeItem* 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->m_pPhysical )
	{
		pItem->m_pPhysical->m_bExpanded = pItem->m_bExpanded;
	}
	else
	{
		pItem->m_pVirtual->m_bExpanded = pItem->m_bExpanded;
	}

	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 ( CLibraryTreeItem* pParent = pItem ; pParent != NULL ; pParent = pParent->m_pParent )
			pParent->m_bContract1 = FALSE;
	}

	if ( bInvalidate )
	{
		UpdateScroll();
		Invalidate();
	}

	return TRUE;
}

BOOL CLibraryTreeCtrl::CollapseRecursive(CLibraryTreeItem* pItem)
{
	BOOL bChanged = FALSE;

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

/////////////////////////////////////////////////////////////////////////////
// CLibraryTreeCtrl selection

BOOL CLibraryTreeCtrl::Select(CLibraryTreeItem* 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 CLibraryTreeCtrl::SelectAll(CLibraryTreeItem* pParent, BOOL bInvalidate)
{
	if ( pParent == NULL ) pParent = m_pRoot;
	else if ( pParent->m_bExpanded == FALSE ) return FALSE;
	
	CLibraryTreeItem** pChild = pParent->m_pList;
	BOOL bChanged = FALSE;
	
	for ( int nCount = pParent->m_nCount ; nCount ; nCount--, pChild++ )
	{
		if ( (*pChild)->m_bSelected == FALSE )
		{
			Select( *pChild, TS_TRUE, FALSE );
			bChanged = TRUE;
		}
		
		if ( (*pChild)->m_bExpanded && (*pChild)->m_nCount )
		{
			bChanged |= SelectAll( *pChild, FALSE );
		}
	}
	
	if ( bInvalidate && bChanged && pParent == m_pRoot ) Invalidate();
	
	return bChanged;
}

BOOL CLibraryTreeCtrl::DeselectAll(CLibraryTreeItem* pExcept, CLibraryTreeItem* pParent, BOOL bInvalidate)
{
	if ( pParent == NULL ) pParent = m_pRoot;
	
	CLibraryTreeItem** 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 CLibraryTreeCtrl::GetSelectedCount() const
{
	return m_nSelected;
}

CLibraryTreeItem* CLibraryTreeCtrl::GetFirstSelected() const
{
	return m_pSelFirst;
}

CLibraryTreeItem* CLibraryTreeCtrl::GetLastSelected() const
{
	return m_pSelLast;
}

BOOL CLibraryTreeCtrl::Highlight(CLibraryTreeItem* pItem)
{
	m_pFocus = pItem;
	
	for ( CLibraryTreeItem* 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;
}

/////////////////////////////////////////////////////////////////////////////
// CLibraryTreeCtrl internal helpers

BOOL CLibraryTreeCtrl::CleanItems(CLibraryTreeItem* pItem, DWORD nCookie, BOOL bVisible)
{
	CLibraryTreeItem** 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 CLibraryTreeCtrl::NotifySelection()
{
	NMHDR pNM = { GetSafeHwnd(), GetDlgCtrlID(), LTN_SELCHANGED };
	GetOwner()->SendMessage( WM_NOTIFY, pNM.idFrom, (LPARAM)&pNM );
}

/////////////////////////////////////////////////////////////////////////////
// CLibraryTreeCtrl search

CLibraryTreeItem* CLibraryTreeCtrl::GetFolderItem(LPVOID pSearch, CLibraryTreeItem* pParent)
{
	if ( pParent == NULL ) pParent = m_pRoot;

	CLibraryTreeItem** pChild = pParent->m_pList;

	for ( int nChild = pParent->m_nCount ; nChild ; nChild--, pChild++ )
	{
		if ( pSearch == (*pChild)->m_pPhysical ) return *pChild;
		if ( pSearch == (*pChild)->m_pVirtual  ) return *pChild;

		if ( (*pChild)->m_nCount )
		{
			CLibraryTreeItem* pFound = GetFolderItem( pSearch, *pChild );
			if ( pFound ) return pFound;
		}
	}
		
	return NULL;
}

/////////////////////////////////////////////////////////////////////////////
// CLibraryTreeCtrl message handlers

void CLibraryTreeCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize( nType, cx, cy );

	m_nVisible = cy;

	UpdateScroll();
}

void CLibraryTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CRect rc;
	CLibraryTreeItem* pHit = HitTest( point, &rc );
	BOOL bChanged = FALSE;
	
	SetFocus();

	if ( m_pTip ) m_pTip->Hide();

	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 );
	}
	
	m_pFocus = pHit;
	
	if ( pHit != NULL )
	{
		if ( m_pFocus->m_pVirtual && ( nFlags & MK_RBUTTON ) == 0 )
		{
			m_bDrag = TRUE;
			m_ptDrag = point;
			SetCapture();
		}
	}
	
	if ( bChanged ) NotifySelection();
}

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

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

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

void CLibraryTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	if ( m_bDrag & ( nFlags & MK_LBUTTON ) )
	{
		CSize szDiff = point - m_ptDrag;

		if ( abs( szDiff.cx ) > 5 || abs( szDiff.cy ) > 5 )
		{
			m_bDrag = FALSE;
			StartDragging( point );
		}
	}
	else if ( m_pTip != NULL )
	{
		if ( CLibraryTreeItem* pItem = HitTest( point ) )
		{
			m_pTip->Show( pItem->m_pPhysical ? (LPVOID)pItem->m_pPhysical : (LPVOID)pItem->m_pVirtual );
		}
		else
		{
			m_pTip->Hide();
		}
	}
	
	CWnd::OnMouseMove( nFlags, point );
}

void CLibraryTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	ReleaseCapture();
	m_bDrag = FALSE;

	CWnd::OnLButtonUp( nFlags, point );
}

void CLibraryTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	CLibraryTreeItem* pTo = NULL;
	BOOL bChanged = FALSE;
	CRect rc;
	
	if ( m_pTip ) m_pTip->Hide();

	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 ) )
	{
		CLibraryTreeItem* pStart	= m_pFocus;
		CLibraryTreeItem* pBase		= pStart ? pStart->m_pParent : m_pRoot;
				
		for ( int nLoop = 0 ; nLoop < 2 ; nLoop++ )
		{
			CLibraryTreeItem** 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 );

⌨️ 快捷键说明

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