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