Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

CtrlBrowseTree.cpp

Go to the documentation of this file.
00001 //
00002 // CtrlBrowseTree.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 // CBrowseTreeCtrl construction
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 // CBrowseTreeCtrl operations
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 // CBrowseTreeCtrl expand
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 // CBrowseTreeCtrl selection
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 // CBrowseTreeCtrl internal helpers
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 // CBrowseTreeCtrl message handlers
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 // CBrowseTreeCtrl scrolling
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 // CBrowseTreeCtrl painting
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 // CBrowseTreeCtrl hit testing
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 // CBrowseTreeCtrl rect lookup
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 // CBrowseTreeCtrl virtual tree
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 // CBrowseTreeItem construction
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 // CBrowseTreeItem add
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 // CBrowseTreeItem delete
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 // CBrowseTreeItem clear
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 // CBrowseTreeItem visibility
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 // CBrowseTreeItem paint
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 // CBrowseTreeItem add XML
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 }

Generated on Thu Dec 15 10:39:34 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2