📄 ctrlbrowsetree.cpp
字号:
//
// 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 + -