00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "CoolInterface.h"
00026 #include "CtrlBrowseTree.h"
00027 #include "ShellIcons.h"
00028 #include "G2Packet.h"
00029 #include "Schema.h"
00030 #include "SchemaCache.h"
00031 #include "XML.h"
00032
00033 #ifdef _DEBUG
00034 #define new DEBUG_NEW
00035 #undef THIS_FILE
00036 static char THIS_FILE[] = __FILE__;
00037 #endif
00038
00039 IMPLEMENT_DYNAMIC(CBrowseTreeCtrl, CWnd)
00040
00041 BEGIN_MESSAGE_MAP(CBrowseTreeCtrl, CWnd)
00042 ON_WM_SIZE()
00043 ON_WM_VSCROLL()
00044 ON_WM_ERASEBKGND()
00045 ON_WM_PAINT()
00046 ON_WM_LBUTTONDOWN()
00047 ON_WM_LBUTTONDBLCLK()
00048 ON_WM_MOUSEWHEEL()
00049 ON_WM_KEYDOWN()
00050 ON_WM_RBUTTONDOWN()
00051 ON_WM_MOUSEMOVE()
00052 ON_WM_LBUTTONUP()
00053 END_MESSAGE_MAP()
00054
00055 #define ITEM_HEIGHT 16
00056
00057
00059
00060
00061 CBrowseTreeCtrl::CBrowseTreeCtrl()
00062 {
00063 m_pRoot = new CBrowseTreeItem();
00064 m_pRoot->m_bExpanded = TRUE;
00065
00066 m_nTotal = 0;
00067 m_nVisible = 0;
00068 m_nScroll = 0;
00069 m_nSelected = 0;
00070 m_pSelFirst = NULL;
00071 m_pSelLast = NULL;
00072 m_pFocus = NULL;
00073 m_nCleanCookie = 0;
00074 }
00075
00076 CBrowseTreeCtrl::~CBrowseTreeCtrl()
00077 {
00078 delete m_pRoot;
00079 }
00080
00082
00083
00084 BOOL CBrowseTreeCtrl::Create(CWnd* pParentWnd)
00085 {
00086 CRect rect( 0, 0, 0, 0 );
00087 return CWnd::Create( NULL, _T("CBrowseTreeCtrl"),
00088 WS_CHILD|WS_TABSTOP|WS_VSCROLL, rect, pParentWnd, IDC_BROWSE_TREE, NULL );
00089 }
00090
00091 void CBrowseTreeCtrl::Clear(BOOL bGUI)
00092 {
00093 CSingleLock lRoot( &m_csRoot, TRUE );
00094
00095 if ( m_pRoot->m_nCount == 0 ) return;
00096
00097 m_pRoot->Clear();
00098
00099 m_nTotal = 0;
00100 m_nSelected = 0;
00101 m_pSelFirst = NULL;
00102 m_pSelLast = NULL;
00103 m_pFocus = NULL;
00104
00105 if ( bGUI )
00106 {
00107 UpdateScroll();
00108 Invalidate();
00109 }
00110 }
00111
00113
00114
00115 BOOL CBrowseTreeCtrl::Expand(CBrowseTreeItem* pItem, TRISTATE bExpand, BOOL bInvalidate)
00116 {
00117 CSingleLock lRoot( &m_csRoot, TRUE );
00118
00119 if ( pItem == NULL ) return FALSE;
00120
00121 switch ( bExpand )
00122 {
00123 case TS_UNKNOWN:
00124 pItem->m_bExpanded = ! pItem->m_bExpanded;
00125 break;
00126 case TS_TRUE:
00127 if ( pItem->m_bExpanded ) return FALSE;
00128 pItem->m_bExpanded = TRUE;
00129 break;
00130 case TS_FALSE:
00131 if ( ! pItem->m_bExpanded ) return FALSE;
00132 pItem->m_bExpanded = FALSE;
00133 break;
00134 }
00135
00136 if ( ! pItem->IsVisible() ) return FALSE;
00137
00138 if ( pItem->m_bExpanded )
00139 {
00140 m_nTotal += pItem->GetChildCount();
00141 }
00142 else
00143 {
00144 m_nTotal -= pItem->GetChildCount();
00145 DeselectAll( NULL, pItem, FALSE );
00146 }
00147
00148 pItem->m_bContract1 = pItem->m_bExpanded == TRUE && bExpand == TS_TRUE && bInvalidate == FALSE;
00149
00150 if ( pItem->m_bContract1 == FALSE )
00151 {
00152 for ( CBrowseTreeItem* pParent = pItem ; pParent != NULL ; pParent = pParent->m_pParent )
00153 pParent->m_bContract1 = FALSE;
00154 }
00155
00156 if ( bInvalidate )
00157 {
00158 UpdateScroll();
00159 Invalidate();
00160 }
00161
00162 return TRUE;
00163 }
00164
00165 BOOL CBrowseTreeCtrl::CollapseRecursive(CBrowseTreeItem* pItem)
00166 {
00167 CSingleLock lRoot( &m_csRoot, TRUE );
00168 BOOL bChanged = FALSE;
00169
00170 if ( pItem != m_pRoot && pItem->m_bExpanded && pItem->m_bContract1 )
00171 {
00172 bChanged |= Expand( pItem, TS_FALSE, FALSE );
00173 }
00174
00175 CBrowseTreeItem** pChild = pItem->m_pList;
00176
00177 for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
00178 {
00179 bChanged |= CollapseRecursive( *pChild );
00180 }
00181
00182 return bChanged;
00183 }
00184
00186
00187
00188 BOOL CBrowseTreeCtrl::Select(CBrowseTreeItem* pItem, TRISTATE bSelect, BOOL bInvalidate)
00189 {
00190 CSingleLock lRoot( &m_csRoot, TRUE );
00191
00192 if ( pItem == NULL ) return FALSE;
00193
00194 switch ( bSelect )
00195 {
00196 case TS_UNKNOWN:
00197 pItem->m_bSelected = ! pItem->m_bSelected;
00198 break;
00199 case TS_TRUE:
00200 if ( pItem->m_bSelected ) return FALSE;
00201 pItem->m_bSelected = TRUE;
00202 break;
00203 case TS_FALSE:
00204 if ( ! pItem->m_bSelected ) return FALSE;
00205 pItem->m_bSelected = FALSE;
00206 break;
00207 }
00208
00209 if ( pItem->m_bSelected )
00210 {
00211 m_nSelected++;
00212
00213 if ( m_pSelLast )
00214 {
00215 m_pSelLast->m_pSelNext = pItem;
00216 pItem->m_pSelPrev = m_pSelLast;
00217 pItem->m_pSelNext = NULL;
00218 m_pSelLast = pItem;
00219 }
00220 else
00221 {
00222 m_pSelFirst = m_pSelLast = pItem;
00223 pItem->m_pSelPrev = pItem->m_pSelNext = NULL;
00224 }
00225 }
00226 else
00227 {
00228 m_nSelected--;
00229
00230 if ( pItem->m_pSelPrev )
00231 pItem->m_pSelPrev->m_pSelNext = pItem->m_pSelNext;
00232 else
00233 m_pSelFirst = pItem->m_pSelNext;
00234
00235 if ( pItem->m_pSelNext )
00236 pItem->m_pSelNext = pItem->m_pSelNext->m_pSelPrev = pItem->m_pSelPrev;
00237 else
00238 m_pSelLast = pItem->m_pSelPrev;
00239 }
00240
00241 if ( pItem->IsVisible() )
00242 {
00243 if ( bInvalidate ) Invalidate();
00244 return TRUE;
00245 }
00246 else
00247 {
00248 return FALSE;
00249 }
00250 }
00251
00252 BOOL CBrowseTreeCtrl::DeselectAll(CBrowseTreeItem* pExcept, CBrowseTreeItem* pParent, BOOL bInvalidate)
00253 {
00254 CSingleLock lRoot( &m_csRoot, TRUE );
00255
00256 if ( pParent == NULL ) pParent = m_pRoot;
00257 CBrowseTreeItem** pChild = pParent->m_pList;
00258
00259 BOOL bChanged = FALSE;
00260
00261 for ( int nCount = pParent->m_nCount ; nCount ; nCount--, pChild++ )
00262 {
00263 if ( *pChild != pExcept && (*pChild)->m_bSelected )
00264 {
00265 Select( *pChild, TS_FALSE, FALSE );
00266 bChanged = TRUE;
00267 }
00268
00269 if ( (*pChild)->m_nCount ) bChanged |= DeselectAll( pExcept, *pChild, FALSE );
00270 }
00271
00272 if ( bInvalidate && bChanged && pParent == m_pRoot ) Invalidate();
00273
00274 return bChanged;
00275 }
00276
00277 int CBrowseTreeCtrl::GetSelectedCount() const
00278 {
00279 return m_nSelected;
00280 }
00281
00282 CBrowseTreeItem* CBrowseTreeCtrl::GetFirstSelected() const
00283 {
00284 return m_pSelFirst;
00285 }
00286
00287 CBrowseTreeItem* CBrowseTreeCtrl::GetLastSelected() const
00288 {
00289 return m_pSelLast;
00290 }
00291
00292 BOOL CBrowseTreeCtrl::Highlight(CBrowseTreeItem* pItem)
00293 {
00294 CSingleLock lRoot( &m_csRoot, TRUE );
00295
00296 m_pFocus = pItem;
00297
00298 for ( CBrowseTreeItem* pParent = m_pFocus->m_pParent ; pParent ; pParent = pParent->m_pParent )
00299 {
00300 Expand( pParent, TS_TRUE, FALSE );
00301
00302 pParent->m_bContract2 = pParent->m_bContract1;
00303 pParent->m_bContract1 = FALSE;
00304 }
00305
00306 CollapseRecursive( m_pRoot );
00307
00308 for ( CBrowseTreeItem* pParent = m_pFocus->m_pParent ; pParent ; pParent = pParent->m_pParent )
00309 {
00310 pParent->m_bContract1 = pParent->m_bContract2;
00311 }
00312
00313 CRect rcItem, rcClient;
00314
00315 if ( GetRect( m_pFocus, &rcItem ) )
00316 {
00317 GetClientRect( &rcClient );
00318
00319 if ( rcItem.top <= rcClient.top )
00320 ScrollBy( rcItem.top - rcClient.top );
00321 else if ( rcItem.bottom > rcClient.bottom )
00322 ScrollBy( rcItem.bottom - rcClient.bottom );
00323 }
00324
00325 UpdateScroll();
00326 Invalidate();
00327
00328 return TRUE;
00329 }
00330
00332
00333
00334 BOOL CBrowseTreeCtrl::CleanItems(CBrowseTreeItem* pItem, DWORD nCookie, BOOL bVisible)
00335 {
00336 CSingleLock lRoot( &m_csRoot, TRUE );
00337
00338 CBrowseTreeItem** pChild = pItem->m_pList + pItem->m_nCount - 1;
00339 BOOL bChanged = FALSE;
00340
00341 for ( int nChild = pItem->m_nCount ; nChild ; nChild--, pChild-- )
00342 {
00343 if ( (*pChild)->m_nCleanCookie != nCookie )
00344 {
00345 if ( m_pFocus == *pChild ) m_pFocus = NULL;
00346
00347 if ( (*pChild)->m_bSelected ) Select( *pChild, TS_FALSE, FALSE );
00348 bChanged |= DeselectAll( NULL, *pChild, FALSE );
00349
00350 if ( bVisible )
00351 {
00352 m_nTotal -= (*pChild)->GetChildCount() + 1;
00353 bChanged = TRUE;
00354 }
00355
00356 delete *pChild;
00357 MoveMemory( pChild, pChild + 1, 4 * ( pItem->m_nCount - nChild ) );
00358 pItem->m_nCount--;
00359 }
00360 }
00361
00362 return bChanged;
00363 }
00364
00365 void CBrowseTreeCtrl::NotifySelection()
00366 {
00367 NMHDR pNM = { GetSafeHwnd(), GetDlgCtrlID(), BTN_SELCHANGED };
00368 GetOwner()->SendMessage( WM_NOTIFY, pNM.idFrom, (LPARAM)&pNM );
00369 }
00370
00372
00373
00374 void CBrowseTreeCtrl::OnSize(UINT nType, int cx, int cy)
00375 {
00376 CWnd::OnSize( nType, cx, cy );
00377 m_nVisible = cy;
00378 UpdateScroll();
00379 }
00380
00381 void CBrowseTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
00382 {
00383 CSingleLock lRoot( &m_csRoot, TRUE );
00384
00385 CRect rc;
00386 CBrowseTreeItem* pHit = HitTest( point, &rc );
00387 BOOL bChanged = FALSE;
00388
00389 SetFocus();
00390
00391 if ( pHit && pHit->m_nCount && point.x >= rc.left && point.x < rc.left + 16 )
00392 {
00393 bChanged = Expand( pHit, TS_UNKNOWN );
00394 }
00395 else if ( nFlags & MK_CONTROL )
00396 {
00397 if ( pHit ) bChanged = Select( pHit, TS_UNKNOWN );
00398 }
00399 else if ( nFlags & MK_SHIFT )
00400 {
00401 if ( pHit ) bChanged = Select( pHit );
00402 }
00403 else
00404 {
00405 if ( ( nFlags & MK_RBUTTON ) == 0 || ( pHit && pHit->m_bSelected == FALSE ) )
00406 bChanged = DeselectAll( pHit );
00407 if ( pHit ) bChanged |= Select( pHit );
00408 }
00409
00410 if ( pHit ) m_pFocus = pHit;
00411
00412 if ( bChanged )
00413 {
00414 lRoot.Unlock();
00415 NotifySelection();
00416 }
00417 }
00418
00419 void CBrowseTreeCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
00420 {
00421 CSingleLock lRoot( &m_csRoot, TRUE );
00422
00423 OnLButtonDown( nFlags, point );
00424
00425 if ( m_pFocus != NULL && m_pFocus->m_nCount )
00426 {
00427 if ( Expand( m_pFocus, TS_UNKNOWN ) )
00428 {
00429 lRoot.Unlock();
00430 NotifySelection();
00431 }
00432 }
00433 }
00434
00435 void CBrowseTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point)
00436 {
00437 OnLButtonDown( nFlags, point );
00438 CWnd::OnRButtonDown( nFlags, point );
00439 }
00440
00441 void CBrowseTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
00442 {
00443 CWnd::OnMouseMove( nFlags, point );
00444 }
00445
00446 void CBrowseTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
00447 {
00448 ReleaseCapture();
00449
00450 CWnd::OnLButtonUp( nFlags, point );
00451 }
00452
00453 void CBrowseTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
00454 {
00455 CSingleLock lRoot( &m_csRoot, TRUE );
00456 CBrowseTreeItem* pTo = NULL;
00457 BOOL bChanged = FALSE;
00458 CRect rc;
00459
00460 if ( nChar == VK_HOME || ( nChar == VK_UP && m_pFocus == NULL ) )
00461 {
00462 if ( m_pRoot->m_nCount ) pTo = m_pRoot->m_pList[0];
00463 }
00464 else if ( nChar == VK_END || ( nChar == VK_DOWN && m_pFocus == NULL ) )
00465 {
00466 if ( m_pRoot->m_nCount ) pTo = m_pRoot->m_pList[ m_pRoot->m_nCount - 1 ];
00467 }
00468 else if ( nChar == VK_UP && m_pFocus != NULL )
00469 {
00470 if ( GetRect( m_pFocus, &rc ) )
00471 {
00472 CPoint pt( rc.left, ( rc.top + rc.bottom ) / 2 );
00473 pt.y -= ITEM_HEIGHT;
00474 pTo = HitTest( pt );
00475 }
00476 }
00477 else if ( nChar == VK_DOWN && m_pFocus != NULL )
00478 {
00479 if ( GetRect( m_pFocus, &rc ) )
00480 {
00481 CPoint pt( rc.left, ( rc.top + rc.bottom ) / 2 );
00482 pt.y += ITEM_HEIGHT;
00483 pTo = HitTest( pt );
00484 }
00485 }
00486 else if ( ( nChar == VK_LEFT || nChar == VK_SUBTRACT ) && m_pFocus != NULL )
00487 {
00488 while ( TRUE )
00489 {
00490 if ( m_pFocus->m_bExpanded && m_pFocus->m_nCount )
00491 {
00492 Expand( m_pFocus, TS_FALSE );
00493 break;
00494 }
00495
00496 if ( m_pFocus->m_pParent == m_pRoot ) break;
00497 m_pFocus = m_pFocus->m_pParent;
00498
00499 bChanged |= DeselectAll( m_pFocus );
00500 bChanged |= Select( m_pFocus );
00501 }
00502
00503 Highlight( m_pFocus );
00504 }
00505 else if ( ( nChar == VK_RIGHT || nChar == VK_ADD ) && m_pFocus != NULL )
00506 {
00507 if ( ! m_pFocus->m_bExpanded && m_pFocus->m_nCount )
00508 {
00509 bChanged |= Expand( m_pFocus, TS_TRUE );
00510 }
00511 }
00512 else if ( _istalnum( nChar ) )
00513 {
00514 CBrowseTreeItem* pStart = m_pFocus;
00515 CBrowseTreeItem* pBase = pStart ? pStart->m_pParent : m_pRoot;
00516
00517 for ( int nLoop = 0 ; nLoop < 2 ; nLoop++ )
00518 {
00519 CBrowseTreeItem** pChild = pBase->m_pList;
00520
00521 for ( int nCount = pBase->m_nCount ; nCount ; nCount--, pChild++ )
00522 {
00523 if ( pStart != NULL )
00524 {
00525 if ( pStart == *pChild ) pStart = NULL;
00526 }
00527 else if ( toupper( (*pChild)->m_sText.GetAt( 0 ) ) == (int)nChar )
00528 {
00529 DeselectAll( m_pFocus = *pChild, NULL, FALSE );
00530 Select( m_pFocus, TS_TRUE, FALSE );
00531 Highlight( m_pFocus );
00532 lRoot.Unlock();
00533 NotifySelection();
00534 return;
00535 }
00536 }
00537 }
00538 }
00539
00540 if ( pTo != NULL )
00541 {
00542 if ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0 || m_pFocus == NULL )
00543 {
00544 bChanged |= DeselectAll( m_pFocus = pTo );
00545 bChanged |= Select( m_pFocus );
00546 }
00547 else
00548 {
00549 bChanged |= Select( m_pFocus = pTo );
00550 }
00551
00552 Highlight( m_pFocus );
00553 }
00554
00555 if ( bChanged )
00556 {
00557 lRoot.Unlock();
00558 NotifySelection();
00559 }
00560 }
00561
00563
00564
00565 void CBrowseTreeCtrl::UpdateScroll()
00566 {
00567 CSingleLock lRoot( &m_csRoot, TRUE );
00568 SCROLLINFO pInfo;
00569
00570 pInfo.cbSize = sizeof(pInfo);
00571 pInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
00572 pInfo.nMin = 0;
00573 pInfo.nMax = m_nTotal * ITEM_HEIGHT;
00574 pInfo.nPage = m_nVisible;
00575 pInfo.nPos = m_nScroll = max( 0, min( m_nScroll, pInfo.nMax - (int)pInfo.nPage + 1 ) );
00576
00577 SetScrollInfo( SB_VERT, &pInfo, IsWindowVisible() );
00578 }
00579
00580 void CBrowseTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
00581 {
00582 switch ( nSBCode )
00583 {
00584 case SB_BOTTOM:
00585 ScrollTo( 0xFFFFFFFF );
00586 break;
00587 case SB_LINEDOWN:
00588 ScrollBy( 1 );
00589 break;
00590 case SB_LINEUP:
00591 ScrollBy( -1 );
00592 break;
00593 case SB_PAGEDOWN:
00594 ScrollBy( m_nVisible );
00595 break;
00596 case SB_PAGEUP:
00597 ScrollBy( -m_nVisible );
00598 break;
00599 case SB_THUMBPOSITION:
00600 case SB_THUMBTRACK:
00601 ScrollTo( nPos );
00602 break;
00603 case SB_TOP:
00604 ScrollTo( 0 );
00605 break;
00606 }
00607 }
00608
00609 BOOL CBrowseTreeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
00610 {
00611 ScrollBy( zDelta * 3 * -ITEM_HEIGHT / WHEEL_DELTA );
00612 return TRUE;
00613 }
00614
00615 void CBrowseTreeCtrl::ScrollBy(int nDelta)
00616 {
00617 ScrollTo( max( 0, m_nScroll + nDelta ) );
00618 }
00619
00620 void CBrowseTreeCtrl::ScrollTo(int nPosition)
00621 {
00622 CSingleLock lRoot( &m_csRoot, TRUE );
00623
00624 if ( nPosition == m_nScroll ) return;
00625 m_nScroll = nPosition;
00626
00627 UpdateScroll();
00628
00629 CRect rc;
00630 GetClientRect( &rc );
00631 RedrawWindow( &rc, NULL, RDW_INVALIDATE );
00632 }
00633
00635
00636
00637 BOOL CBrowseTreeCtrl::OnEraseBkgnd(CDC* pDC)
00638 {
00639 return TRUE;
00640 }
00641
00642 void CBrowseTreeCtrl::OnPaint()
00643 {
00644 CSingleLock lRoot( &m_csRoot, TRUE );
00645 CPaintDC dc( this );
00646
00647 CRect rcClient;
00648 GetClientRect( &rcClient );
00649
00650 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00651
00652 CBrowseTreeItem** pChild = m_pRoot->m_pList;
00653
00654 CFont* pOldFont = (CFont*)dc.SelectObject( &CoolInterface.m_fntNormal );
00655
00656 for ( int nCount = m_pRoot->m_nCount ; nCount && pt.y < rcClient.bottom ; nCount--, pChild++ )
00657 {
00658 Paint( dc, rcClient, pt, *pChild );
00659 }
00660
00661 dc.SelectObject( pOldFont );
00662
00663 dc.FillSolidRect( &rcClient, CoolInterface.m_crWindow );
00664 }
00665
00666 void CBrowseTreeCtrl::Paint(CDC& dc, CRect& rcClient, CPoint& pt, CBrowseTreeItem* pItem)
00667 {
00668 CRect rc( pt.x, pt.y, pt.x, pt.y + ITEM_HEIGHT );
00669 pt.y += ITEM_HEIGHT;
00670
00671 if ( rc.top >= rcClient.bottom )
00672 {
00673 return;
00674 }
00675 else if ( rc.bottom >= rcClient.top )
00676 {
00677 if ( pItem->m_bBold ) dc.SelectObject( &CoolInterface.m_fntBold );
00678
00679 rc.right += 32 + dc.GetTextExtent( pItem->m_sText ).cx + 6;
00680
00681 if ( dc.RectVisible( &rc ) )
00682 {
00683 pItem->Paint( dc, rc, FALSE );
00684 dc.ExcludeClipRect( &rc );
00685 }
00686
00687 if ( pItem->m_bBold ) dc.SelectObject( &CoolInterface.m_fntNormal );
00688 }
00689
00690 if ( pItem->m_bExpanded && pItem->m_nCount )
00691 {
00692 pt.x += 16;
00693
00694 CBrowseTreeItem** pChild = pItem->m_pList;
00695
00696 for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
00697 {
00698 Paint( dc, rcClient, pt, *pChild );
00699 if ( pt.y >= rcClient.bottom ) break;
00700 }
00701
00702 pt.x -= 16;
00703 }
00704 }
00705
00707
00708
00709 CBrowseTreeItem* CBrowseTreeCtrl::HitTest(const POINT& point, RECT* pRect) const
00710 {
00711 CSingleLock lRoot( (CCriticalSection*)&m_csRoot, TRUE );
00712 CRect rcClient;
00713
00714 GetClientRect( &rcClient );
00715
00716 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00717
00718 CBrowseTreeItem** pChild = m_pRoot->m_pList;
00719
00720 for ( int nCount = m_pRoot->m_nCount ; nCount && pt.y < rcClient.bottom ; nCount--, pChild++ )
00721 {
00722 CBrowseTreeItem* pItem = HitTest( rcClient, pt, *pChild, point, pRect );
00723 if ( pItem ) return pItem;
00724 }
00725
00726 return NULL;
00727 }
00728
00729 CBrowseTreeItem* CBrowseTreeCtrl::HitTest(CRect& rcClient, CPoint& pt, CBrowseTreeItem* pItem, const POINT& point, RECT* pRect) const
00730 {
00731 CRect rc( rcClient.left, pt.y, rcClient.right, pt.y + ITEM_HEIGHT );
00732 pt.y += ITEM_HEIGHT;
00733
00734 if ( rc.top >= rcClient.bottom + ITEM_HEIGHT )
00735 {
00736 return NULL;
00737 }
00738 else if ( rc.bottom >= rcClient.top - ITEM_HEIGHT )
00739 {
00740 if ( rc.PtInRect( point ) )
00741 {
00742 if ( pRect )
00743 {
00744 CopyMemory( pRect, &rc, sizeof(RECT) );
00745 pRect->left = pt.x;
00746 }
00747 return pItem;
00748 }
00749 }
00750
00751 if ( pItem->m_bExpanded && pItem->m_nCount )
00752 {
00753 pt.x += 16;
00754
00755 CBrowseTreeItem** pChild = pItem->m_pList;
00756
00757 for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
00758 {
00759 CBrowseTreeItem* pItem = HitTest( rcClient, pt, *pChild, point, pRect );
00760 if ( pItem ) return pItem;
00761 if ( pt.y >= rcClient.bottom + ITEM_HEIGHT ) break;
00762 }
00763
00764 pt.x -= 16;
00765 }
00766
00767 return NULL;
00768 }
00769
00771
00772
00773 BOOL CBrowseTreeCtrl::GetRect(CBrowseTreeItem* pItem, RECT* pRect)
00774 {
00775 CSingleLock lRoot( &m_csRoot, TRUE );
00776 CRect rcClient;
00777
00778 GetClientRect( &rcClient );
00779
00780 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00781
00782 CBrowseTreeItem** pChild = m_pRoot->m_pList;
00783
00784 for ( int nCount = m_pRoot->m_nCount ; nCount ; nCount--, pChild++ )
00785 {
00786 if ( GetRect( pt, *pChild, pItem, pRect ) ) return TRUE;
00787 }
00788
00789 return FALSE;
00790 }
00791
00792 BOOL CBrowseTreeCtrl::GetRect(CPoint& pt, CBrowseTreeItem* pItem, CBrowseTreeItem* pFind, RECT* pRect)
00793 {
00794 if ( pItem == pFind )
00795 {
00796 pRect->left = pt.x;
00797 pRect->top = pt.y;
00798 pRect->right = pt.x;
00799 pRect->bottom = pt.y = pRect->top + ITEM_HEIGHT;
00800
00801 CClientDC dc( this );
00802 CFont* pOld = (CFont*)dc.SelectObject( pItem->m_bBold ?
00803 &CoolInterface.m_fntBold : &CoolInterface.m_fntNormal );
00804 pRect->right += 33 + dc.GetTextExtent( pItem->m_sText ).cx + 4;
00805 dc.SelectObject( pOld );
00806
00807 return TRUE;
00808 }
00809 else
00810 {
00811 pt.y += ITEM_HEIGHT;
00812 }
00813
00814 if ( pItem->m_bExpanded && pItem->m_nCount )
00815 {
00816 pt.x += 16;
00817
00818 CBrowseTreeItem** pChild = pItem->m_pList;
00819
00820 for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
00821 {
00822 if ( GetRect( pt, *pChild, pFind, pRect ) ) return TRUE;
00823 }
00824
00825 pt.x -= 16;
00826 }
00827
00828 return FALSE;
00829 }
00830
00832
00833
00834 void CBrowseTreeCtrl::OnTreePacket(CG2Packet* pPacket)
00835 {
00836 CSingleLock lRoot( &m_csRoot, TRUE );
00837
00838 Clear( FALSE );
00839
00840 pPacket->Seek( 0 );
00841 OnTreePacket( pPacket, pPacket->m_nLength, m_pRoot );
00842 m_nTotal = m_pRoot->GetChildCount();
00843
00844 Invalidate();
00845 }
00846
00847 void CBrowseTreeCtrl::OnTreePacket(CG2Packet* pPacket, DWORD nFinish, CBrowseTreeItem* pItem)
00848 {
00849 BOOL bCompound;
00850 CHAR szType[9];
00851 DWORD nLength;
00852
00853 while ( pPacket->m_nPosition < nFinish &&
00854 pPacket->ReadPacket( szType, nLength, &bCompound ) )
00855 {
00856 DWORD nNext = pPacket->m_nPosition + nLength;
00857
00858 if ( ( strcmp( szType, "PF" ) == 0 || strcmp( szType, "VF" ) == 0 ) && bCompound == TRUE )
00859 {
00860 CBrowseTreeItem* pChild = new CBrowseTreeItem( pItem );
00861 OnTreePacket( pPacket, nNext, pChild );
00862 pChild->m_bExpanded = ( pItem == m_pRoot );
00863 pItem->Add( pChild );
00864 }
00865 else if ( strcmp( szType, "DN" ) == 0 && bCompound == FALSE )
00866 {
00867 pItem->m_sText = pPacket->ReadString( nLength );
00868 }
00869 else if ( strcmp( szType, "MD" ) == 0 && bCompound == FALSE )
00870 {
00871 CXMLElement* pXML = CXMLElement::FromString( pPacket->ReadString( nLength ) );
00872 if ( pXML != NULL ) pItem->AddXML( pXML );
00873 }
00874 else if ( strcmp( szType, "FILES" ) == 0 && bCompound == FALSE )
00875 {
00876 if ( pItem->m_pFiles != NULL ) delete [] pItem->m_pFiles;
00877
00878 pItem->m_nFiles = nLength / 4;
00879 pItem->m_pFiles = new DWORD[ pItem->m_nFiles ];
00880
00881 for ( DWORD nCount = pItem->m_nFiles ; nCount ; nCount-- )
00882 {
00883 pItem->m_pFiles[ nCount - 1 ] = pPacket->ReadLongBE();
00884 }
00885 }
00886
00887 pPacket->m_nPosition = nNext;
00888 }
00889 }
00890
00891
00893
00894
00895 CBrowseTreeItem::CBrowseTreeItem(CBrowseTreeItem* pParent)
00896 {
00897 m_pParent = pParent;
00898 m_pList = NULL;
00899 m_nCount = 0;
00900 m_nBuffer = 0;
00901 m_pSelPrev = NULL;
00902 m_pSelNext = NULL;
00903 m_nCleanCookie = 0;
00904
00905 m_bExpanded = FALSE;
00906 m_bSelected = FALSE;
00907 m_bContract1 = FALSE;
00908 m_bContract2 = FALSE;
00909
00910 m_nCookie = 0;
00911 m_bBold = FALSE;
00912 m_nIcon16 = -1;
00913
00914 m_pSchema = NULL;
00915 m_pFiles = NULL;
00916 m_nFiles = 0;
00917 }
00918
00919 CBrowseTreeItem::~CBrowseTreeItem()
00920 {
00921 if ( m_pFiles != NULL )
00922 {
00923 delete [] m_pFiles;
00924 }
00925
00926 if ( m_pList != NULL )
00927 {
00928 Clear();
00929 delete [] m_pList;
00930 }
00931 }
00932
00934
00935
00936 CBrowseTreeItem* CBrowseTreeItem::Add(LPCTSTR pszName)
00937 {
00938 if ( m_nCount == m_nBuffer )
00939 {
00940 if ( m_nBuffer ) m_nBuffer += min( m_nBuffer, 16 ); else m_nBuffer = 4;
00941
00942 CBrowseTreeItem** pList = new CBrowseTreeItem*[ m_nBuffer ];
00943
00944 if ( m_nCount ) CopyMemory( pList, m_pList, m_nCount * 4 );
00945 if ( m_pList ) delete [] m_pList;
00946
00947 m_pList = pList;
00948 }
00949
00950 if ( m_nCount == 0 ) return m_pList[ m_nCount++ ] = new CBrowseTreeItem( this );
00951
00952 int nFirst = 0;
00953 for ( int nLast = m_nCount - 1 ; nLast >= nFirst ; )
00954 {
00955 int nMiddle = ( nFirst + nLast ) >> 1;
00956
00957 CBrowseTreeItem* pItem = m_pList[ nMiddle ];
00958
00959 if ( _tcsicoll( pszName, pItem->m_sText ) >= 0 )
00960 {
00961 nFirst = nMiddle + 1;
00962 }
00963 else
00964 {
00965 nLast = nMiddle - 1;
00966 }
00967 }
00968
00969 MoveMemory( m_pList + nFirst + 1, m_pList + nFirst, ( m_nCount - nFirst ) << 2 );
00970 m_nCount++;
00971
00972 return m_pList[ nFirst ] = new CBrowseTreeItem( this );
00973 }
00974
00975 CBrowseTreeItem* CBrowseTreeItem::Add(CBrowseTreeItem* pNewItem)
00976 {
00977 if ( m_nCount == m_nBuffer )
00978 {
00979 if ( m_nBuffer ) m_nBuffer += min( m_nBuffer, 16 ); else m_nBuffer = 4;
00980
00981 CBrowseTreeItem** pList = new CBrowseTreeItem*[ m_nBuffer ];
00982
00983 if ( m_nCount ) CopyMemory( pList, m_pList, m_nCount * 4 );
00984 if ( m_pList ) delete [] m_pList;
00985
00986 m_pList = pList;
00987 }
00988
00989 if ( m_nCount == 0 ) return m_pList[ m_nCount++ ] = pNewItem;
00990
00991 int nFirst = 0;
00992 for ( int nLast = m_nCount - 1 ; nLast >= nFirst ; )
00993 {
00994 int nMiddle = ( nFirst + nLast ) >> 1;
00995
00996 CBrowseTreeItem* pItem = m_pList[ nMiddle ];
00997
00998 if ( _tcsicoll( pNewItem->m_sText, pItem->m_sText ) >= 0 )
00999 {
01000 nFirst = nMiddle + 1;
01001 }
01002 else
01003 {
01004 nLast = nMiddle - 1;
01005 }
01006 }
01007
01008 MoveMemory( m_pList + nFirst + 1, m_pList + nFirst, ( m_nCount - nFirst ) << 2 );
01009 m_nCount++;
01010
01011 return m_pList[ nFirst ] = pNewItem;
01012 }
01013
01015
01016
01017 void CBrowseTreeItem::Delete()
01018 {
01019 m_pParent->Delete( this );
01020 }
01021
01022 void CBrowseTreeItem::Delete(CBrowseTreeItem* pItem)
01023 {
01024 ASSERT( pItem->m_bSelected == FALSE );
01025
01026 CBrowseTreeItem** pChild = m_pList;
01027
01028 for ( int nChild = m_nCount ; nChild ; nChild--, pChild++ )
01029 {
01030 if ( *pChild == pItem )
01031 {
01032 MoveMemory( pChild, pChild + 1, 4 * ( nChild - 1 ) );
01033 m_nCount--;
01034 break;
01035 }
01036 }
01037
01038 delete pItem;
01039 }
01040
01041 void CBrowseTreeItem::Delete(int nItem)
01042 {
01043 if ( nItem < 0 || nItem >= m_nCount ) return;
01044
01045 ASSERT( m_pList[ nItem ]->m_bSelected == FALSE );
01046 delete m_pList[ nItem ];
01047 MoveMemory( m_pList + nItem, m_pList + nItem + 1, 4 * ( m_nCount - nItem - 1 ) );
01048 m_nCount--;
01049 }
01050
01052
01053
01054 void CBrowseTreeItem::Clear()
01055 {
01056 if ( m_pList )
01057 {
01058 for ( int nChild = 0 ; nChild < m_nCount ; nChild++ ) delete m_pList[ nChild ];
01059 delete [] m_pList;
01060 }
01061
01062 m_pList = NULL;
01063 m_nCount = 0;
01064 m_nBuffer = 0;
01065 }
01066
01068
01069
01070 BOOL CBrowseTreeItem::IsVisible() const
01071 {
01072 for ( CBrowseTreeItem* pRoot = m_pParent ; pRoot ; pRoot = pRoot->m_pParent )
01073 {
01074 if ( ! pRoot->m_bExpanded ) return FALSE;
01075 }
01076
01077 return TRUE;
01078 }
01079
01080 int CBrowseTreeItem::GetChildCount() const
01081 {
01082 int nCount = m_nCount;
01083
01084 CBrowseTreeItem** pChild = m_pList;
01085
01086 for ( int nChild = m_nCount ; nChild ; nChild--, pChild++ )
01087 {
01088 if ( (*pChild)->m_bExpanded ) nCount += (*pChild)->GetChildCount();
01089 }
01090
01091 return nCount;
01092 }
01093
01095
01096
01097 void CBrowseTreeItem::Paint(CDC& dc, CRect& rc, BOOL bTarget, COLORREF crBack) const
01098 {
01099 if ( crBack == CLR_NONE ) crBack = CoolInterface.m_crWindow;
01100
01101 if ( m_nCount )
01102 {
01103 ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
01104 m_bExpanded ? SHI_MINUS : SHI_PLUS,
01105 dc.GetSafeHdc(), rc.left, rc.top, 16, 16,
01106 crBack, CLR_NONE, ILD_NORMAL );
01107 }
01108 else
01109 {
01110 dc.FillSolidRect( rc.left, rc.top, 16, 16, crBack );
01111 }
01112
01113 int nImage = ( m_bExpanded && m_nCount ) ? SHI_FOLDER_OPEN : SHI_FOLDER_CLOSED;
01114 if ( m_nIcon16 >= 0 ) nImage = m_nIcon16;
01115
01116 UINT nIconStyle = ( m_bSelected || bTarget ) ? ILD_SELECTED : ILD_NORMAL;
01117
01118 ImageList_DrawEx( ShellIcons.GetHandle( 16 ), nImage,
01119 dc.GetSafeHdc(), rc.left + 16, rc.top, 16, 16,
01120 crBack, CLR_DEFAULT, nIconStyle );
01121
01122 crBack = ( m_bSelected || bTarget ) ? CoolInterface.m_crHighlight : crBack;
01123 COLORREF crText = ( m_bSelected || bTarget ) ? CoolInterface.m_crHiText : CoolInterface.m_crText;
01124
01125 dc.SetTextColor( crText );
01126 dc.SetBkColor( crBack );
01127 dc.SetBkMode( OPAQUE );
01128
01129 rc.left += 32;
01130 dc.ExtTextOut( rc.left + 3, rc.top + 1, ETO_OPAQUE|ETO_CLIPPED, &rc,
01131 m_sText, NULL );
01132 rc.left -= 32;
01133 }
01134
01136
01137
01138 void CBrowseTreeItem::AddXML(CXMLElement* pXML)
01139 {
01140 CString strURI = pXML->GetAttributeValue( CXMLAttribute::schemaName );
01141
01142 if ( m_pSchema = SchemaCache.Get( strURI ) )
01143 {
01144 m_bBold = strURI == CSchema::uriFavouritesFolder;
01145 m_nIcon16 = m_pSchema->m_nIcon16;
01146
01147 if ( CXMLElement* pBody = pXML->GetFirstElement() )
01148 {
01149 m_sText = pBody->GetAttributeValue( m_pSchema->GetFirstMemberName() );
01150 }
01151 }
01152
01153 if ( m_sText.IsEmpty() ) m_sText = _T("Unnamed");
01154
01155 if ( pXML != NULL ) delete pXML;
01156 }