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

CtrlMatch.cpp

Go to the documentation of this file.
00001 //
00002 // CtrlMatch.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 "CtrlMatch.h"
00026 #include "MatchObjects.h"
00027 #include "QueryHit.h"
00028 #include "ShellIcons.h"
00029 #include "CoolInterface.h"
00030 #include "VendorCache.h"
00031 #include "Network.h"
00032 #include "Schema.h"
00033 #include "Skin.h"
00034 #include "WndBaseMatch.h"
00035 
00036 #ifdef _DEBUG
00037 #define new DEBUG_NEW
00038 #undef THIS_FILE
00039 static char THIS_FILE[] = __FILE__;
00040 #endif
00041 
00042 BEGIN_MESSAGE_MAP(CMatchCtrl, CWnd)
00043         ON_WM_CREATE()
00044         ON_WM_DESTROY()
00045         ON_WM_SIZE()
00046         ON_WM_ERASEBKGND()
00047         ON_WM_PAINT()
00048         ON_WM_VSCROLL()
00049         ON_WM_LBUTTONDOWN()
00050         ON_WM_MOUSEMOVE()
00051         ON_WM_LBUTTONUP()
00052         ON_WM_LBUTTONDBLCLK()
00053         ON_WM_KEYDOWN()
00054         ON_WM_RBUTTONDOWN()
00055         ON_WM_RBUTTONUP()
00056         ON_WM_SETCURSOR()
00057         ON_WM_MOUSEWHEEL()
00058         ON_WM_HSCROLL()
00059         ON_WM_TIMER()
00060         ON_NOTIFY(HDN_ITEMCHANGEDW, IDC_MATCH_HEADER, OnChangeHeader)
00061         ON_NOTIFY(HDN_ITEMCHANGEDA, IDC_MATCH_HEADER, OnChangeHeader)
00062         ON_NOTIFY(HDN_ENDDRAG, IDC_MATCH_HEADER, OnChangeHeader)
00063         ON_NOTIFY(HDN_ITEMCLICKW, IDC_MATCH_HEADER, OnClickHeader)
00064         ON_NOTIFY(HDN_ITEMCLICKA, IDC_MATCH_HEADER, OnClickHeader)
00065         ON_WM_SETFOCUS()
00066         ON_WM_KILLFOCUS()
00067 END_MESSAGE_MAP()
00068 
00069 #define HEADER_HEIGHT   20
00070 #define ITEM_HEIGHT             17
00071 
00072 
00074 // CMatchCtrl construction
00075 
00076 CMatchCtrl::CMatchCtrl()
00077 {
00078         m_pMatches              = NULL;
00079         m_sType                 = _T("Search");
00080         
00081         m_pSchema               = NULL;
00082         m_nTopIndex             = 0;
00083         m_nHitIndex             = 0;
00084         m_nBottomIndex  = 0xFFFFFFFF;
00085         m_nFocus                = 0xFFFFFFFF;
00086         m_nPageCount    = 1;
00087         m_nCurrentWidth = 0;
00088         m_nMessage              = 0;
00089         m_bSearchLink   = FALSE;
00090         m_bTips                 = TRUE;
00091 
00092         // Try to get the number of lines to scroll when the mouse wheel is rotated
00093         if( !SystemParametersInfo ( SPI_GETWHEELSCROLLLINES, 0, &m_nScrollWheelLines, 0) )
00094         {
00095                 m_nScrollWheelLines = 3;
00096         }
00097 }
00098 
00099 CMatchCtrl::~CMatchCtrl()
00100 {
00101 }
00102 
00104 // CMatchCtrl system
00105 
00106 BOOL CMatchCtrl::Create(CMatchList* pMatches, CWnd* pParentWnd)
00107 {
00108         CRect rect( 0, 0, 0, 0 );
00109         m_pMatches = pMatches;
00110         DWORD dwStyle = WS_CHILD|WS_VSCROLL|WS_TABSTOP|WS_VISIBLE;
00111         return CWnd::Create( NULL, NULL, dwStyle, rect, pParentWnd, IDC_MATCHES, NULL );
00112 }
00113 
00114 int CMatchCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
00115 {
00116         if ( CWnd::OnCreate( lpCreateStruct ) == -1 ) return -1;
00117         
00118         CRect rc;
00119         
00120         if ( ! m_wndHeader.Create( WS_CHILD|WS_VISIBLE|HDS_BUTTONS|HDS_DRAGDROP|HDS_HOTTRACK|HDS_FULLDRAG,
00121                 rc, this, IDC_MATCH_HEADER ) ) return -1;
00122         m_wndHeader.SetFont( &theApp.m_gdiFont );
00123         
00124         if ( ! m_wndTip.Create( this ) ) return -1;
00125         
00126         EnableToolTips( TRUE );
00127         
00128         InsertColumn( MATCH_COL_NAME, _T("File"), HDF_LEFT, 200 );
00129         InsertColumn( MATCH_COL_TYPE, _T("Extension"), HDF_CENTER, 40 );
00130         InsertColumn( MATCH_COL_SIZE, _T("Size"), HDF_CENTER, 60 );
00131         InsertColumn( MATCH_COL_RATING, _T("Rating"), HDF_CENTER, 12*5 );
00132         InsertColumn( MATCH_COL_STATUS, _T("Status"), HDF_CENTER, 16*3 );
00133         InsertColumn( MATCH_COL_COUNT, _T("Host/Count"), HDF_CENTER, 120 );
00134         InsertColumn( MATCH_COL_SPEED, _T("Speed"), HDF_CENTER, 60 );
00135         InsertColumn( MATCH_COL_CLIENT, _T("Client"), HDF_CENTER, 80 );
00136         
00137         CBitmap bmStar;
00138         bmStar.LoadBitmap( IDB_SMALL_STAR );
00139         if ( ! m_pStars.Create( 12, 12, ILC_COLOR16|ILC_MASK, 7, 0 ) )
00140                 m_pStars.Create( 12, 12, ILC_COLOR24|ILC_MASK, 7, 0 );
00141         m_pStars.Add( &bmStar, RGB( 0, 255, 0 ) );
00142         
00143         LoadColumnState();
00144         
00145         UpdateScroll();
00146         
00147         return 0;
00148 }
00149 
00150 void CMatchCtrl::OnDestroy() 
00151 {
00152         m_wndTip.DestroyWindow();
00153 
00154         SaveColumnState();
00155         CWnd::OnDestroy();
00156 }
00157 
00158 void CMatchCtrl::OnSize(UINT nType, int cx, int cy) 
00159 {
00160         CWnd::OnSize( nType, cx, cy );
00161         
00162         m_nCurrentWidth = cx;
00163 
00164         m_nPageCount = ( cy - HEADER_HEIGHT ) / ITEM_HEIGHT;
00165         if ( m_nPageCount < 1 ) m_nPageCount = 1;
00166         m_nBottomIndex = 0xFFFFFFFF;
00167 
00168         UpdateScroll();
00169 }
00170 
00172 // CMatchCtrl update
00173 
00174 void CMatchCtrl::Update()
00175 {
00176         CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
00177 
00178         if ( ! m_pMatches->m_bUpdated ) return;
00179 
00180         m_nCacheItems = m_pMatches->m_nItems;
00181         ScrollTo( GetScrollPos( SB_VERT ) );
00182 
00183         if ( m_pMatches->m_nUpdateMax >= m_nTopIndex &&
00184                  m_pMatches->m_nUpdateMin <= m_nBottomIndex )
00185         {
00186                 Invalidate();
00187         }
00188         
00189         m_pMatches->ClearUpdated();
00190 }
00191 
00192 void CMatchCtrl::DestructiveUpdate()
00193 {
00194         m_wndTip.Hide();
00195 }
00196 
00197 void CMatchCtrl::SelectSchema(CSchema* pSchema, CPtrList* pColumns)
00198 {
00199         SaveColumnState();
00200         
00201         m_pSchema = pSchema;
00202         m_pColumns.RemoveAll();
00203         
00204         while ( m_wndHeader.DeleteItem( MATCH_COL_MAX ) );
00205         int nColumn = MATCH_COL_MAX;
00206         
00207         if ( pSchema && pColumns )
00208         {
00209                 m_pColumns.AddTail( pColumns );
00210                 
00211                 for ( POSITION pos = m_pColumns.GetHeadPosition() ; pos ; nColumn++ )
00212                 {
00213                         CSchemaMember* pMember = (CSchemaMember*)m_pColumns.GetNext( pos );
00214                         InsertColumn( nColumn, pMember->m_sTitle, pMember->m_nColumnAlign, pMember->m_nColumnWidth );
00215                 }
00216         }
00217         
00218         m_pMatches->SelectSchema( pSchema, pColumns );
00219         
00220         LoadColumnState();
00221         
00222         Update();
00223 }
00224 
00225 void CMatchCtrl::SetBrowseMode()
00226 {
00227         SaveColumnState();
00228         m_sType = _T("Browse");
00229         HDITEM pZero = { HDI_WIDTH, 0 };
00230         m_wndHeader.SetItem( MATCH_COL_STATUS, &pZero );
00231         m_wndHeader.SetItem( MATCH_COL_COUNT, &pZero );
00232         m_wndHeader.SetItem( MATCH_COL_SPEED, &pZero );
00233         m_wndHeader.SetItem( MATCH_COL_CLIENT, &pZero );
00234         LoadColumnState();
00235 }
00236 
00237 BOOL CMatchCtrl::HitTestHeader(const CPoint& point)
00238 {
00239         CRect rc;
00240         m_wndHeader.GetWindowRect( &rc );
00241         return rc.PtInRect( point );
00242 }
00243 
00244 void CMatchCtrl::SetSortColumn(int nColumn, BOOL bDirection)
00245 {
00246         CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
00247         CWaitCursor pCursor;
00248         
00249         m_pMatches->SetSortColumn( nColumn, bDirection );
00250         Update();
00251         
00252         if ( m_bmSortAsc.m_hObject == NULL )
00253         {
00254                 m_bmSortAsc.LoadMappedBitmap( IDB_SORT_ASC );
00255                 m_bmSortDesc.LoadMappedBitmap( IDB_SORT_DESC );
00256         }
00257         
00258         HDITEM pColumn = { HDI_BITMAP|HDI_FORMAT };
00259         
00260         for ( int nCol = 0 ; m_wndHeader.GetItem( nCol, &pColumn ) ; nCol++ )
00261         {
00262                 if ( nCol == nColumn )
00263                 {
00264                         pColumn.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT;
00265                         pColumn.hbm = (HBITMAP)( bDirection ? m_bmSortAsc.GetSafeHandle() : m_bmSortDesc.GetSafeHandle() );
00266                 }
00267                 else
00268                 {
00269                         pColumn.fmt &= ~HDF_BITMAP;
00270                         pColumn.hbm = NULL;
00271                 }
00272                 
00273                 m_wndHeader.SetItem( nCol, &pColumn );
00274         }
00275 }
00276 
00277 void CMatchCtrl::SetMessage(UINT nMessageID, BOOL bLink)
00278 {
00279         CString strCurrentText;
00280         Skin.LoadString( strCurrentText, m_nMessage );
00281 
00282         if ( nMessageID == m_nMessage && m_bSearchLink == bLink && strCurrentText == m_sMessage ) return;
00283         
00284         m_bSearchLink = bLink;
00285         
00286         m_nMessage = nMessageID;
00287         m_sMessage = strCurrentText;
00288         
00289         if ( m_nCacheItems == 0 ) Invalidate();
00290 }
00291 
00292 void CMatchCtrl::SetMessage(LPCTSTR pszMessage, BOOL bLink)
00293 {
00294         if ( m_sMessage == pszMessage && m_bSearchLink == bLink ) return;
00295         
00296         m_bSearchLink = bLink;
00297         m_nMessage = 0;
00298         m_sMessage = pszMessage;
00299         
00300         if ( m_nCacheItems == 0 ) Invalidate();
00301 }
00302 
00303 void CMatchCtrl::EnableTips(BOOL bTips)
00304 {
00305         m_bTips = bTips;
00306 }
00307 
00309 // CMatchCtrl column utilities
00310 
00311 void CMatchCtrl::InsertColumn(int nColumn, LPCTSTR pszCaption, int nFormat, int nWidth)
00312 {
00313         HDITEM pItem = { HDI_TEXT|HDI_FORMAT|HDI_WIDTH };
00314         
00315         pItem.pszText           = (LPTSTR)pszCaption;
00316         pItem.cchTextMax        = _tcslen( pszCaption );
00317         pItem.fmt                       = nFormat;
00318         pItem.cxy                       = nWidth;
00319         
00320         m_wndHeader.InsertItem( nColumn, &pItem );
00321 }
00322 
00323 void CMatchCtrl::SaveColumnState()
00324 {
00325         HDITEM pItem = { HDI_WIDTH|HDI_ORDER };
00326         
00327         CString strOrdering, strWidths, strItem;
00328         
00329         for ( int nColumns = 0 ; m_wndHeader.GetItem( nColumns, &pItem ) ; nColumns++ )
00330         {
00331                 m_wndHeader.GetItem( nColumns, &pItem );
00332                 
00333                 strItem.Format( _T("%.2x"), pItem.iOrder );
00334                 strOrdering += strItem;
00335                 
00336                 strItem.Format( _T("%.4x"), pItem.cxy );
00337                 strWidths += strItem;
00338         }
00339         
00340         int nSort = m_pMatches->m_nSortColumn >= 0 ? 
00341                 ( m_pMatches->m_nSortColumn + 1 ) * m_pMatches->m_bSortDir : 0;
00342         
00343         LPCTSTR pszName = _T("Null");
00344         if ( m_pSchema ) pszName = m_pSchema->m_sSingular;
00345         
00346         strItem.Format( _T("CMatchCtrl.%s.%s.Ordering"), m_sType, pszName );
00347         theApp.WriteProfileString( _T("ListStates"), strItem, strOrdering );
00348         strItem.Format( _T("CMatchCtrl.%s.%s.Widths"), m_sType, pszName );
00349         theApp.WriteProfileString( _T("ListStates"), strItem, strWidths );
00350         strItem.Format( _T("CMatchCtrl.%s.%s.Sort"), m_sType, pszName );
00351         theApp.WriteProfileInt( _T("ListStates"), strItem, nSort );
00352 }
00353 
00354 BOOL CMatchCtrl::LoadColumnState()
00355 {
00356         CString strOrdering, strWidths, strItem;
00357         
00358         LPCTSTR pszName = _T("Null");
00359         if ( m_pSchema ) pszName = m_pSchema->m_sSingular;
00360         
00361         strItem.Format( _T("CMatchCtrl.%s.%s.Ordering"), m_sType, pszName );
00362         strOrdering = theApp.GetProfileString( _T("ListStates"), strItem, _T("") );
00363         strItem.Format( _T("CMatchCtrl.%s.%s.Widths"), m_sType, pszName );
00364         strWidths = theApp.GetProfileString( _T("ListStates"), strItem, _T("") );
00365         strItem.Format( _T("CMatchCtrl.%s.%s.Sort"), m_sType, pszName );
00366         int nSort = theApp.GetProfileInt( _T("ListStates"), strItem, - MATCH_COL_COUNT - 1 );
00367         
00368         HDITEM pItem = { HDI_WIDTH|HDI_ORDER };
00369         
00370         if ( _tcsncmp( strWidths, _T("0000"), 4 ) == 0 &&
00371                  _tcsncmp( strOrdering, _T("00"), 2 ) == 0 )
00372         {
00373                 strWidths = strWidths.Mid( 4 );
00374                 strOrdering = strOrdering.Mid( 2 );
00375         }
00376         
00377         for ( int nColumns = 0 ; m_wndHeader.GetItem( nColumns, &pItem ) ; nColumns++ )
00378         {
00379                 if ( strWidths.GetLength() < 4 || strOrdering.GetLength() < 2 ) return FALSE;
00380                 
00381                 _stscanf( strWidths.Left( 4 ), _T("%x"), &pItem.cxy );
00382                 _stscanf( strOrdering.Left( 2 ), _T("%x"), &pItem.iOrder );
00383                 
00384                 strWidths = strWidths.Mid( 4 );
00385                 strOrdering = strOrdering.Mid( 2 );
00386                 
00387                 m_wndHeader.SetItem( nColumns, &pItem );
00388         }
00389         
00390         SetSortColumn( abs( nSort ) - 1, nSort < 0 );
00391         
00392         return TRUE;
00393 }
00394 
00396 // CMatchCtrl scrolling
00397 
00398 void CMatchCtrl::UpdateScroll(DWORD nScroll)
00399 {
00400         SCROLLINFO pInfo;
00401         
00402         pInfo.cbSize    = sizeof(pInfo);
00403         pInfo.fMask             = SIF_ALL & ~SIF_TRACKPOS;
00404         pInfo.nMin              = 0;
00405         pInfo.nMax              = m_pMatches->m_nItems - 1;
00406         pInfo.nPage             = m_nPageCount;
00407         pInfo.nPos              = nScroll < 0xFFFFFFFF ? nScroll : GetScrollPos( SB_VERT );
00408         pInfo.nPos              = max( 0, min( pInfo.nPos, pInfo.nMax - (int)pInfo.nPage + 1 ) );
00409         
00410         SetScrollInfo( SB_VERT, &pInfo, TRUE );
00411         
00412         int nColumnWidth = 0;
00413         
00414         for ( int nColumn = m_wndHeader.GetItemCount() - 1 ; nColumn >= 0 ; nColumn-- )
00415         {
00416                 CRect rcCol;
00417                 Header_GetItemRect( m_wndHeader.GetSafeHwnd(), nColumn, &rcCol );
00418                 nColumnWidth = max( nColumnWidth, int(rcCol.right) );
00419         }
00420         
00421         pInfo.fMask             = SIF_ALL & ~SIF_TRACKPOS;
00422         pInfo.nMin              = 0;
00423         pInfo.nMax              = nColumnWidth - 1;
00424         pInfo.nPage             = m_nCurrentWidth;
00425         pInfo.nPos              = GetScrollPos( SB_HORZ );
00426         pInfo.nPos              = max( 0, min( pInfo.nPos, pInfo.nMax - (int)pInfo.nPage + 1 ) );
00427         
00428         SetScrollInfo( SB_HORZ, &pInfo, TRUE );
00429         
00430         CRect rc;
00431         m_wndHeader.GetWindowRect( &rc );
00432         ScreenToClient( &rc );
00433         
00434         if ( rc.left != -pInfo.nPos || rc.Width() != max( m_nCurrentWidth, pInfo.nMax ) )
00435         {
00436                 m_wndHeader.SetWindowPos( NULL, -pInfo.nPos, 0,
00437                         max( m_nCurrentWidth, pInfo.nMax ), HEADER_HEIGHT, SWP_NOZORDER );
00438         }
00439 }
00440 
00441 void CMatchCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
00442 {
00443         switch ( nSBCode )
00444         {
00445         case SB_BOTTOM:
00446                 ScrollTo( 0xFFFFFFFF );
00447                 break;
00448         case SB_LINEDOWN:
00449                 ScrollBy( 1 );
00450                 break;
00451         case SB_LINEUP:
00452                 ScrollBy( -1 );
00453                 break;
00454         case SB_PAGEDOWN:
00455                 ScrollBy( m_nPageCount );
00456                 break;
00457         case SB_PAGEUP:
00458                 ScrollBy( -m_nPageCount );
00459                 break;
00460         case SB_THUMBPOSITION:
00461         case SB_THUMBTRACK:
00462                 ScrollTo( nPos );
00463                 break;
00464         case SB_TOP:
00465                 ScrollTo( 0 );
00466                 break;
00467         }
00468 }
00469 
00470 void CMatchCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
00471 {
00472         SCROLLINFO pInfo;
00473 
00474         pInfo.cbSize    = sizeof(pInfo);
00475         pInfo.fMask             = SIF_ALL & ~SIF_TRACKPOS;
00476 
00477         GetScrollInfo( SB_HORZ, &pInfo );
00478         int nDelta = pInfo.nPos;
00479 
00480         switch ( nSBCode )
00481         {
00482         case SB_BOTTOM:
00483                 pInfo.nPos = pInfo.nMax - pInfo.nPage;
00484                 break;
00485         case SB_LINEDOWN:
00486                 pInfo.nPos ++;
00487                 break;
00488         case SB_LINEUP:
00489                 pInfo.nPos --;
00490                 break;
00491         case SB_PAGEDOWN:
00492                 pInfo.nPos += pInfo.nPage;
00493                 break;
00494         case SB_PAGEUP:
00495                 pInfo.nPos -= pInfo.nPage;
00496                 break;
00497         case SB_THUMBPOSITION:
00498         case SB_THUMBTRACK:
00499                 pInfo.nPos = nPos;
00500                 break;
00501         case SB_TOP:
00502                 pInfo.nPos = 0;
00503                 break;
00504         }
00505 
00506         pInfo.nPos = max( 0, min( pInfo.nPos, pInfo.nMax - (int)pInfo.nPage + 1 ) );
00507         if ( pInfo.nPos == nDelta ) return;
00508 
00509         SetScrollInfo( SB_HORZ, &pInfo, TRUE );
00510 
00511         m_wndHeader.SetWindowPos( NULL, -pInfo.nPos, 0,
00512                 max( m_nCurrentWidth, pInfo.nMax ), HEADER_HEIGHT, SWP_NOZORDER );
00513 
00514         RedrawWindow( NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW );
00515 }
00516 
00517 BOOL CMatchCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
00518 {
00519         ScrollBy( zDelta / WHEEL_DELTA * -m_nScrollWheelLines );
00520 
00521         return TRUE;
00522 }
00523 
00524 void CMatchCtrl::ScrollBy(int nDelta)
00525 {
00526         int nIndex = GetScrollPos( SB_VERT ) + nDelta;
00527         nIndex = max( 0, nIndex );
00528         ScrollTo( nIndex );
00529 }
00530 
00531 void CMatchCtrl::ScrollTo(DWORD nIndex)
00532 {
00533         DWORD nLimit = m_pMatches->m_nItems;
00534         if ( nLimit > (DWORD)m_nPageCount ) nLimit -= m_nPageCount;
00535         else nLimit = 0;
00536         nIndex = min( nIndex, nLimit );
00537         
00538         DWORD nScroll = 0;
00539         
00540         m_nTopIndex = 0;
00541         m_nHitIndex = 0;
00542         m_nBottomIndex = 0xFFFFFFFF;
00543         
00544         CMatchFile** ppFile = m_pMatches->m_pFiles;
00545         
00546         for ( DWORD nFiles = 0 ; nFiles < m_pMatches->m_nFiles ; nFiles++, ppFile++ )
00547         {
00548                 DWORD nCount = (*ppFile)->GetItemCount();
00549                 if ( ! nCount ) continue;
00550                 
00551                 m_nTopIndex = nFiles;
00552                 
00553                 if ( nIndex < nCount )
00554                 {
00555                         m_nHitIndex = nIndex;
00556                         nScroll += nIndex;
00557                         break;
00558                 }
00559                 
00560                 nIndex -= nCount;
00561                 nScroll += nCount;
00562         }
00563         
00564         UpdateScroll( nScroll );
00565         
00566         CRect rc;
00567         GetClientRect( &rc );
00568         rc.top += HEADER_HEIGHT;
00569         
00570         // RedrawWindow( &rc, NULL, RDW_INVALIDATE | RDW_UPDATENOW );
00571         RedrawWindow( &rc, NULL, RDW_INVALIDATE );
00572 }
00573 
00575 // CMatchCtrl painting
00576 
00577 BOOL CMatchCtrl::OnEraseBkgnd(CDC* pDC) 
00578 {
00579         return TRUE;
00580 }
00581 
00582 void CMatchCtrl::OnPaint() 
00583 {
00584         CSingleLock pLock( &m_pMatches->m_pSection );
00585         
00586         if ( ! pLock.Lock( 80 ) )
00587         {
00588                 PostMessage( WM_TIMER, 1 );
00589                 return;
00590         }
00591         
00592         CRect rcClient, rcItem;
00593         CPaintDC dc( this );
00594         if ( theApp.m_bRTL ) dc.SetTextAlign( TA_RTLREADING );
00595         
00596         GetClientRect( &rcClient );
00597         rcClient.top += HEADER_HEIGHT;
00598         
00599         dc.SetViewportOrg( -GetScrollPos( SB_HORZ ), 0 );
00600         
00601         INT nZeroInt, nColWidth;
00602         GetScrollRange( SB_HORZ, &nZeroInt, &nColWidth );
00603         rcClient.right = max( rcClient.right, LONG(nColWidth) );
00604         
00605         CFont* pOldFont = (CFont*)dc.SelectObject( &CoolInterface.m_fntNormal );
00606         
00607         m_nTrailWidth = dc.GetTextExtent( _T('\x2026') ).cx;
00608         
00609         rcItem.SetRect( rcClient.left, rcClient.top, rcClient.right, 0 );
00610         rcItem.top -= m_nHitIndex * ITEM_HEIGHT;
00611         rcItem.bottom = rcItem.top + ITEM_HEIGHT;
00612         
00613         CMatchFile** ppFile = m_pMatches->m_pFiles + m_nTopIndex;
00614         BOOL bFocus = ( GetFocus() == this );
00615         
00616     DWORD nIndex = m_nTopIndex;
00617         for (   ;
00618                         nIndex < m_pMatches->m_nFiles && rcItem.top < rcClient.bottom ;
00619                         nIndex++, ppFile++ )
00620         {
00621                 CMatchFile* pFile = *ppFile;
00622                 int nCount = pFile->GetFilteredCount();
00623                 
00624                 if ( ! nCount ) continue;
00625                 
00626                 if ( rcItem.top >= rcClient.top && dc.RectVisible( &rcItem ) )
00627                 {
00628                         DrawItem( dc, rcItem, pFile, NULL, bFocus && ( nIndex == m_nFocus ) );
00629                 }
00630                 
00631                 rcItem.top += ITEM_HEIGHT;
00632                 rcItem.bottom += ITEM_HEIGHT;
00633                 
00634                 if ( nCount > 1 && pFile->m_bExpanded )
00635                 {
00636                         for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
00637                         {
00638                                 if ( ! pHit->m_bFiltered ) continue;
00639                                 
00640                                 if ( rcItem.top >= rcClient.top && dc.RectVisible( &rcItem ) )
00641                                 {
00642                                         DrawItem( dc, rcItem, pFile, pHit, FALSE );
00643                                 }
00644                                 
00645                                 rcItem.top += ITEM_HEIGHT;
00646                                 rcItem.bottom += ITEM_HEIGHT;
00647                                 
00648                                 if ( rcItem.top >= rcClient.bottom ) break;
00649                         }
00650                 }
00651         }
00652         
00653         m_nBottomIndex = nIndex + 1;
00654         
00655         if ( m_pMatches->m_nFilteredFiles == 0 && m_sMessage.GetLength() )
00656         {
00657                 dc.SetViewportOrg( 0, 0 );
00658                 GetClientRect( &rcClient );
00659                 rcClient.top += HEADER_HEIGHT;
00660                 DrawEmptyMessage( dc, rcClient );
00661         }
00662         
00663         dc.SelectObject( pOldFont );
00664         
00665         rcItem.bottom = rcClient.bottom;
00666         
00667         if ( dc.RectVisible( &rcItem ) )
00668         {
00669                 dc.FillSolidRect( &rcItem, CoolInterface.m_crWindow );
00670         }
00671 }
00672 
00673 void CMatchCtrl::DrawItem(CDC& dc, CRect& rcRow, CMatchFile* pFile, CQueryHit* pHit, BOOL bFocus)
00674 {
00675         static TCHAR szBuffer[64];
00676         
00677         int nColumns    = m_wndHeader.GetItemCount();
00678         int nHits               = pHit ? 0 : pFile->GetFilteredCount();
00679         
00680         LPCTSTR pszName = pHit ? pHit->m_sName : pFile->m_pBest->m_sName;
00681         LPCTSTR pszType = _tcsrchr( pszName, '.' );
00682         int nNameLen    = pszType ? pszType - pszName : _tcslen( pszName );
00683         
00684         BOOL bSelected  = pHit ? pHit->m_bSelected : pFile->m_bSelected;
00685         BOOL bGrayed    = FALSE;
00686         COLORREF crWnd  = CoolInterface.m_crWindow;
00687         COLORREF crText = bSelected ? CoolInterface.m_crHighlight : CoolInterface.m_crText ;
00688         COLORREF crBack = crWnd;
00689         
00690         if ( pFile->m_bCollection )
00691         {
00692                 crWnd = crBack = CCoolInterface::CalculateColour( crBack, RGB( 0, 0, 255 ), 25 );
00693         }
00694         
00695         if ( pFile->m_bExisting == 1 )
00696         {
00697                 crText = pHit ? RGB( 0, 64, 0 ) : RGB( 0, 127, 0 );
00698         }
00699         else if ( pFile->m_bDownload || ( pHit && pHit->m_bDownload ) )
00700         {
00701                 crText = pHit ? RGB( 0, 0, 100 ) : RGB( 0, 0, 160 );
00702         }
00703 
00704         if ( bSelected )
00705         {
00706                 crBack = CoolInterface.m_crBackSel;
00707         }
00708         else if ( ( pHit && ( pHit->m_bBogus || pHit->m_sURL.IsEmpty() || ! pHit->m_bMatched ) ) ||
00709                                 pFile->m_bExisting == 2 || ( ! pHit && ! pFile->m_bOneValid ) ||
00710                           ( pHit && pHit->m_bPush == TS_TRUE && Network.IsStable() == FALSE ) )
00711         {
00712                 crText = GetSysColor( COLOR_3DSHADOW );
00713                 bGrayed = TRUE;
00714         }
00715         
00716         dc.SetBkMode( OPAQUE );
00717         dc.SetBkColor( crBack );
00718         
00719         dc.SelectObject( Settings.Search.HighlightNew && ( pHit ? pHit->m_bNew : pFile->m_bNew )
00720                 ? &theApp.m_gdiFontBold : &theApp.m_gdiFont );
00721         
00722         for ( int nColumn = 0 ; nColumn < nColumns ; nColumn++ )
00723         {
00724                 HDITEM pColumn = { HDI_FORMAT|HDI_WIDTH|HDI_ORDER };
00725                 CRect rcCol;
00726                 
00727                 Header_GetItem( m_wndHeader.GetSafeHwnd(), nColumn, &pColumn );
00728                 Header_GetItemRect( m_wndHeader.GetSafeHwnd(), nColumn, &rcCol );
00729                 
00730                 int nLeft = rcCol.left;
00731                 rcCol.top = rcRow.top;
00732                 rcCol.bottom = rcRow.bottom;
00733                 
00734                 LPCTSTR pszText = _T("");
00735                 UINT nIconStyle = 0;
00736                 int nText               = -1;
00737                 int nPosition;
00738                 
00739                 dc.SetTextColor( crText );
00740                 
00741                 switch ( nColumn )
00742                 {
00743                 case MATCH_COL_NAME:
00744                         if ( rcCol.Width() < 32 ) break;
00745 
00746                         pszText = pszName;
00747                         nText   = nNameLen;
00748                         
00749                         nIconStyle = bSelected ? ILD_SELECTED : ( bGrayed ? ILD_BLEND50 : ILD_NORMAL );
00750                         if ( pFile->m_bDRM ) nIconStyle |= INDEXTOOVERLAYMASK( SHI_O_COMMERCIAL );
00751                         
00752                         if ( ! pHit && nHits > 1 )
00753                         {
00754                                 ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
00755                                         pFile->m_bExpanded ? SHI_MINUS : SHI_PLUS,
00756                                         dc.GetSafeHdc(), rcCol.left, rcCol.top, 16, 16,
00757                                         crWnd, CLR_NONE, ILD_NORMAL );
00758 
00759                                 ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
00760                                         pFile->m_nShellIndex, dc.GetSafeHdc(), rcCol.left + 16, rcCol.top, 16, 16,
00761                                         crWnd, bSelected ? CLR_DEFAULT : crText,
00762                                         nIconStyle );
00763 
00764                                 dc.FillSolidRect( rcCol.left, rcCol.top + 16, 32, ITEM_HEIGHT - 16, crWnd );
00765                                 
00766                                 rcCol.left += 32;
00767                         }
00768                         else
00769                         {
00770                                 dc.FillSolidRect( rcCol.left, rcCol.top, ( pHit ? 24 : 16 ),
00771                                         ITEM_HEIGHT, crWnd );
00772                                 rcCol.left += ( pHit ? 24 : 16 );
00773                                 
00774                                 if ( ! pFile->m_bDRM )
00775                                 {
00776                                         if ( pHit && pHit->m_nPartial )
00777                                                 nIconStyle |= INDEXTOOVERLAYMASK( SHI_O_PARTIAL );
00778                                         else if ( nHits == 1 && pFile->m_pBest->m_nPartial )
00779                                                 nIconStyle |= INDEXTOOVERLAYMASK( SHI_O_PARTIAL );
00780                                 }
00781                                 
00782                                 ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
00783                                         pFile->m_nShellIndex, dc.GetSafeHdc(), rcCol.left, rcCol.top, 16, 16,
00784                                         crWnd, bSelected ? CLR_DEFAULT : crText,
00785                                         nIconStyle );
00786 
00787                                 dc.FillSolidRect( rcCol.left, rcCol.top + 16, 16, ITEM_HEIGHT - 16, crWnd );
00788 
00789                                 rcCol.left += 16;
00790                         }
00791 
00792                         dc.FillSolidRect( rcCol.left, rcCol.top, 1, ITEM_HEIGHT, crWnd );
00793                         rcCol.left += 1;
00794                         
00795                         if ( bSelected && bFocus )
00796                         {
00797                                 CRect rcFocus( &rcRow );
00798                                 rcFocus.left = rcCol.left;
00799                                 dc.Draw3dRect( &rcFocus, CoolInterface.m_crBorder, CoolInterface.m_crBorder );
00800                                 dc.ExcludeClipRect( rcFocus.left, rcFocus.top, rcFocus.right, rcFocus.top + 1 );
00801                                 dc.ExcludeClipRect( rcFocus.left, rcFocus.bottom - 1, rcFocus.right, rcFocus.bottom );
00802                                 dc.ExcludeClipRect( rcFocus.left, rcFocus.top + 1, rcFocus.left + 1, rcFocus.bottom - 1 );
00803                                 dc.ExcludeClipRect( rcFocus.right - 1, rcFocus.top + 1, rcFocus.right, rcFocus.bottom - 1 );
00804                         }
00805                         
00806                         break;
00807 
00808                 case MATCH_COL_TYPE:
00809                         if ( pszType ) pszText = pszType + 1;
00810                         break;
00811 
00812                 case MATCH_COL_SIZE:
00813                         pszText = pFile->m_sSize;
00814                         break;
00815                 
00816                 case MATCH_COL_STATUS:
00817                         if ( pHit )
00818                         {
00819                                 DrawStatus( dc, rcCol, pFile, pHit, bSelected, crBack );
00820                         }
00821                         else if ( nHits == 1 )
00822                         {
00823                                 DrawStatus( dc, rcCol, pFile, pFile->m_pBest, bSelected, crBack );
00824                         }
00825                         else
00826                         {
00827                                 DrawStatus( dc, rcCol, pFile, NULL, bSelected, crBack );
00828                         }
00829                         break;
00830                         
00831                 case MATCH_COL_RATING:
00832                         if ( pHit )
00833                         {
00834                                 DrawRating( dc, rcCol, pHit->m_nRating, bSelected, crBack );
00835                         }
00836                         else if ( nHits == 1 )
00837                         {
00838                                 DrawRating( dc, rcCol, pFile->m_pBest->m_nRating, bSelected, crBack );
00839                         }
00840                         else
00841                         {
00842                                 DrawRating( dc, rcCol,
00843                                         pFile->m_nRated ? pFile->m_nRating / pFile->m_nRated : 0,
00844                                         bSelected, crBack );
00845                         }
00846                         break;
00847                         
00848                 case MATCH_COL_COUNT:
00849                         if ( nHits == 1 || pHit != NULL )
00850                         {
00851                                 CQueryHit* ppHit = ( nHits == 1 || pHit == NULL ) ? pFile->m_pBest : pHit;
00852                                 
00853                                 if ( Settings.Search.ShowNames && ppHit->m_sNick.GetLength() )
00854                                 {
00855                                         if ( ppHit->m_nSources > 1 )
00856                                         {
00857                                                 _sntprintf( szBuffer, sizeof( szBuffer ) / sizeof( TCHAR ), _T("%s+%u"),
00858                                                         (LPCTSTR)ppHit->m_sNick,
00859                                                         ppHit->m_nSources - 1 );
00860                                                 szBuffer[ sizeof( szBuffer ) / sizeof( TCHAR ) - 1 ] = 0;
00861                                                 pszText = szBuffer;
00862                                         }
00863                                         else
00864                                         {
00865                                                 pszText = ppHit->m_sNick;
00866                                         }
00867                                 }
00868                                 else if( ( ppHit->m_nProtocol == PROTOCOL_ED2K ) && ( ppHit->m_bPush == TS_TRUE ) )
00869                                 {
00870                                         if ( ppHit->m_nSources > 1 )
00871                                         {
00872                                                 /*_stprintf( szBuffer, _T("%lu@%s+%lu"), ppHit->m_pClientID.w[2], 
00873                                                         (LPCTSTR)CString( inet_ntoa( (IN_ADDR&)ppHit->m_pClientID.w[0] ) ), 
00874                                                         ppHit->m_nSources - 1 );*/
00875                                                 _sntprintf( szBuffer, sizeof( szBuffer ) / sizeof( TCHAR ), _T("(%s)+%u"),
00876                                                         (LPCTSTR)CString( inet_ntoa( (IN_ADDR&)ppHit->m_pClientID.w[0] ) ), ppHit->m_nSources - 1 );
00877                                                 szBuffer[ sizeof( szBuffer ) / sizeof( TCHAR ) - 1 ] = 0;
00878                                         }
00879                                         else
00880                                         {
00881                                                 /*_stprintf( szBuffer, _T("%lu@%s"), ppHit->m_pClientID.w[2], 
00882                                                         (LPCTSTR)CString( inet_ntoa( (IN_ADDR&)ppHit->m_pClientID.w[0] ) ) );*/
00883                                                 _sntprintf( szBuffer, sizeof( szBuffer ) / sizeof( TCHAR ), _T("(%s)"),
00884                                                         (LPCTSTR)CString( inet_ntoa( (IN_ADDR&)ppHit->m_pClientID.w[0] ) ) );
00885                                                 szBuffer[ sizeof( szBuffer ) / sizeof( TCHAR ) - 1 ] = 0;
00886                                         }
00887                                         pszText = szBuffer;
00888                                         
00889                                 }
00890                                 else if ( ppHit->m_pAddress.S_un.S_addr )
00891                                 {
00892                                         if ( ppHit->m_nSources > 1 )
00893                                         {
00894                                                 _sntprintf( szBuffer, sizeof( szBuffer ) / sizeof( TCHAR ), _T("%s+%u"),
00895                                                         (LPCTSTR)CString( inet_ntoa( ppHit->m_pAddress ) ),
00896                                                         ppHit->m_nSources - 1 );
00897                                                 szBuffer[ sizeof( szBuffer ) / sizeof( TCHAR ) - 1 ] = 0;
00898                                                 pszText = szBuffer;
00899                                         }
00900                                         else
00901                                         {
00902                                                 MultiByteToWideChar( CP_ACP, 0, inet_ntoa( ppHit->m_pAddress ), -1, szBuffer, 64 );
00903                                                 pszText = szBuffer;
00904                                         }
00905                                 }
00906                                 else
00907                                 {
00908                                         if ( ppHit->m_nSources )
00909                                         {
00910                                                 CString strSource, strText;
00911                                                 LoadSourcesString( strSource, pFile->m_nSources );
00912                                                 strText.Format( _T("(%u %s)"), pFile->m_nSources, strSource );
00913                                                 _sntprintf( szBuffer, sizeof( szBuffer ) / sizeof( TCHAR ), strText, pFile->m_nSources );
00914                                                 szBuffer[ sizeof( szBuffer ) / sizeof( TCHAR ) - 1 ] = 0;
00915                                         }
00916                                         else
00917                                         {
00918                                                 // Not used?
00919                                                 pszText = _T("(Firewalled)");
00920                                         }
00921                                 }
00922                         }
00923                         else
00924                         {
00925                                 CString strSource, strText;
00926                                 LoadSourcesString( strSource, pFile->m_nSources );
00927                                 strText.Format( _T("(%u %s)"), pFile->m_nSources, strSource );
00928                                 _sntprintf( szBuffer, sizeof( szBuffer ) / sizeof( TCHAR ), strText, pFile->m_nSources );
00929                                 szBuffer[ sizeof( szBuffer ) / sizeof( TCHAR ) - 1 ] = 0;
00930                                 pszText = szBuffer;
00931                         }
00932                         break;
00933                         
00934                 case MATCH_COL_SPEED:
00935                         if ( pHit )
00936                         {
00937                                 if ( ! bSelected && pHit->m_bMeasured == TS_TRUE ) dc.SetTextColor( RGB( 0, 127, 0 ) );
00938                                 pszText = pHit->m_sSpeed;
00939                         }
00940                         else
00941                         {
00942                                 if ( ! bSelected && pFile->m_pBest->m_bMeasured == TS_TRUE ) dc.SetTextColor( RGB( 0, 127, 0 ) );
00943                                 pszText = pFile->m_sSpeed;
00944                         }
00945                         break;
00946 
00947                 case MATCH_COL_CLIENT:
00948                         if ( pHit )
00949                         {
00950                                 if ( ! bSelected && pHit->m_bBrowseHost ) dc.SetTextColor( RGB( 0, 127, 0 ) );
00951                                 pszText = pHit->m_pVendor->m_sName;
00952                         }
00953                         else if ( nHits == 1 )
00954                         {
00955                                 if ( ! bSelected && pFile->m_pBest->m_bBrowseHost ) dc.SetTextColor( RGB( 0, 127, 0 ) );
00956                                 pszText = pFile->m_pBest->m_pVendor->m_sName;
00957                         }
00958                         break;
00959 
00960                 default:
00961                         if ( pFile->m_pColumns == NULL ) break;
00962                         pszText = pFile->m_pColumns[ nColumn - MATCH_COL_MAX ];
00963                         nText = _tcslen( pszText );
00964                         nText = min( nText, 128 );
00965                         break;
00966 
00967                 }
00968 
00969                 if ( nText < 0 ) nText = _tcslen( pszText );
00970                 int nWidth = 0;
00971                 int nTrail = 0;
00972 
00973                 while ( nText )
00974                 {
00975                         nWidth = dc.GetTextExtent( pszText, nText ).cx + nTrail;
00976                         if ( nWidth <= rcCol.Width() - 4 ) break;
00977                         nTrail = m_nTrailWidth;
00978                         nText--;
00979                 }
00980                 
00981                 switch ( pColumn.fmt & HDF_JUSTIFYMASK )
00982                 {
00983                 default:
00984                         nPosition = rcCol.left + 4;
00985                         break;
00986                 case HDF_CENTER:
00987                         nPosition = ( rcCol.left + rcCol.right ) / 2 - nWidth / 2;
00988                         break;
00989                 case HDF_RIGHT:
00990                         nPosition = rcCol.right - 4 - nWidth;
00991                         break;
00992                 }
00993 
00994                 dc.SetBkColor( crBack );
00995 
00996                 if ( nTrail )
00997                 {
00998                         CString strTrail;
00999                         LPTSTR pszTrail = strTrail.GetBuffer( nText + 1 );
01000                         CopyMemory( pszTrail, pszText, nText * sizeof(TCHAR) );
01001                         pszTrail[ nText ] = _T('\x2026');
01002                         strTrail.ReleaseBuffer( nText + 1 );
01003                         dc.ExtTextOut( nPosition, rcCol.top + 2, ETO_CLIPPED|ETO_OPAQUE,
01004                                 &rcCol, strTrail, nText + 1, NULL );
01005                 }
01006                 else
01007                 {
01008                         dc.ExtTextOut( nPosition, rcCol.top + 2, ETO_CLIPPED|ETO_OPAQUE,
01009                                 &rcCol, pszText, nText, NULL );
01010                 }
01011 
01012                 dc.ExcludeClipRect( nLeft, rcCol.top, rcCol.right, rcCol.bottom  );
01013         }
01014 
01015         dc.FillSolidRect( &rcRow, crBack );
01016 }
01017 
01018 void CMatchCtrl::DrawStatus(CDC& dc, CRect& rcCol, CMatchFile* pFile, CQueryHit* pHit, BOOL bSelected, COLORREF crBack)
01019 {
01020         if ( rcCol.Width() < 16 * 3 ) return;
01021         
01022         int nLeft = rcCol.left;
01023         
01024         if ( rcCol.Width() > 16 * 6 )
01025                 nLeft = ( rcCol.left + rcCol.right ) / 2 - ( 16 * 6 ) / 2;
01026         
01027         int nPos = nLeft;
01028         TRISTATE bState;
01029         
01030         if ( bState = pHit ? pHit->m_bBusy : pFile->m_bBusy )
01031         {
01032                 ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
01033                         bState == TS_TRUE ? SHI_BUSY : SHI_TICK, dc.GetSafeHdc(), nPos,
01034                         rcCol.top, 16, 16, crBack, crBack, bSelected ? ILD_BLEND50 : ILD_NORMAL );
01035         }
01036         else
01037         {
01038                 dc.FillSolidRect( nPos, rcCol.top, 16, 16, crBack );
01039         }
01040         
01041         nPos += 16;
01042         
01043         if ( bState = pHit ? pHit->m_bPush : pFile->m_bPush )
01044         {
01045                 ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
01046                         bState == TS_TRUE ? SHI_FIREWALL : SHI_TICK, dc.GetSafeHdc(), nPos,
01047                         rcCol.top, 16, 16, crBack, crBack, bSelected ? ILD_BLEND50 : ILD_NORMAL );
01048         }
01049         else
01050         {
01051                 dc.FillSolidRect( nPos, rcCol.top, 16, 16, crBack );
01052         }
01053         
01054         nPos += 16;
01055         
01056         if ( bState = pHit ? pHit->m_bStable : pFile->m_bStable )
01057         {
01058                 ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
01059                         bState == TS_TRUE ? SHI_TICK : SHI_UNSTABLE, dc.GetSafeHdc(), nPos,
01060                         rcCol.top, 16, 16, crBack, crBack, bSelected ? ILD_BLEND50 : ILD_NORMAL );
01061         }
01062         else
01063         {
01064                 dc.FillSolidRect( nPos, rcCol.top, 16, 16, crBack );
01065         }
01066         
01067         nPos += 16;
01068 
01069         if ( nPos + 16 < rcCol.right )
01070         {
01071                 if ( pHit ? pHit->m_bPreview : pFile->m_bPreview )
01072                 {
01073                         ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
01074                                 SHI_PREVIEW, dc.GetSafeHdc(), nPos,
01075                                 rcCol.top, 16, 16, crBack, crBack, bSelected ? ILD_BLEND50 : ILD_NORMAL );
01076                 }
01077                 else
01078                 {
01079                         dc.FillSolidRect( nPos, rcCol.top, 16, 16, crBack );
01080                 }
01081 
01082                 nPos += 16;
01083         }
01084         
01085         if ( nPos + 16 < rcCol.right && pHit )
01086         {
01087                 if ( pHit->m_bBrowseHost )
01088                 {
01089                         ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
01090                                 SHI_BROWSE, dc.GetSafeHdc(), nPos,
01091                                 rcCol.top, 16, 16, crBack, crBack, bSelected ? ILD_BLEND50 : ILD_NORMAL );
01092                 }
01093                 else
01094                 {
01095                         dc.FillSolidRect( nPos, rcCol.top, 16, 16, crBack );
01096                 }
01097                 
01098                 nPos += 16;
01099         }
01100         
01101         if ( nPos + 16 < rcCol.right && pHit )
01102         {
01103                 if ( pHit->m_bChat )
01104                 {
01105                         ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
01106                                 SHI_CHAT, dc.GetSafeHdc(), nPos,
01107                                 rcCol.top, 16, 16, crBack, crBack, bSelected ? ILD_BLEND50 : ILD_NORMAL );
01108                 }
01109                 else
01110                 {
01111                         dc.FillSolidRect( nPos, rcCol.top, 16, 16, crBack );
01112                 }
01113 
01114                 nPos += 16;
01115         }
01116         
01117         dc.ExcludeClipRect( nLeft, rcCol.top, nPos, rcCol.top + 16 );
01118 }
01119 
01120 void CMatchCtrl::DrawRating(CDC& dc, CRect& rcCol, int nRating, BOOL bSelected, COLORREF crBack)
01121 {
01122         if ( nRating > 1 && nRating <= 6 )
01123         {
01124                 CPoint pt( rcCol.left, rcCol.top + 2 );
01125                 
01126                 if ( rcCol.Width() >= 12 * 5 )
01127                 {
01128                         pt.x += rcCol.Width() / 2;
01129                         pt.x -= 6 * ( --nRating );
01130                 }
01131                 else
01132                 {
01133                         nRating = min( nRating - 1, rcCol.Width() / 12 );
01134                 }
01135                 
01136                 while ( nRating-- )
01137                 {
01138                         ImageList_DrawEx( m_pStars, 0, dc, pt.x, pt.y, 12, 12, crBack,
01139                                 crBack, bSelected ? ILD_BLEND50 : ILD_NORMAL );
01140                         dc.ExcludeClipRect( pt.x, pt.y, pt.x + 12, pt.y + 12 );
01141                         pt.x += 12;
01142                 }
01143         }
01144         else if ( nRating == 1 && rcCol.Width() > 12 )
01145         {
01146                 CPoint pt( ( rcCol.left + rcCol.right ) / 2 - 6, rcCol.top + 2 );
01147                 ImageList_DrawEx( m_pStars, 6, dc, pt.x, pt.y, 12, 12, crBack,
01148                         crBack, bSelected ? ILD_BLEND50 : ILD_NORMAL );
01149                 dc.ExcludeClipRect( pt.x, pt.y, pt.x + 12, pt.y + 12 );
01150         }
01151         
01152         dc.FillSolidRect( &rcCol, crBack );
01153 }
01154 
01155 void CMatchCtrl::DrawEmptyMessage(CDC& dc, CRect& rcClient)
01156 {
01157         CPoint ptText;
01158         CRect rcText;
01159         CSize szText;
01160         
01161         rcText.SetRect( rcClient.left, 16, rcClient.right, 0 );
01162         rcText.bottom = ( rcClient.top + rcClient.bottom ) / 2;
01163         rcText.top = rcText.bottom - rcText.top;
01164 
01165         if ( ! m_bSearchLink ) rcText.OffsetRect( 0, rcText.Height() / 2 );
01166 
01167         dc.SetBkMode( TRANSPARENT );
01168         dc.SetBkColor( CoolInterface.m_crWindow );
01169         dc.SetTextColor( CoolInterface.m_crText );
01170         dc.SelectObject( &theApp.m_gdiFont );
01171         
01172         szText          = dc.GetTextExtent( m_sMessage );
01173         ptText.x        = ( rcText.left + rcText.right ) / 2 - szText.cx / 2;
01174         ptText.y        = ( rcText.top + rcText.bottom ) / 2 - szText.cy / 2;
01175         
01176         dc.ExtTextOut( ptText.x, ptText.y, ETO_CLIPPED|ETO_OPAQUE, &rcText, m_sMessage, NULL );
01177         dc.ExcludeClipRect( &rcText );
01178 
01179         if ( m_bSearchLink )
01180         {
01181                 CString strText;
01182                 Skin.LoadString( strText, IDS_SEARCH_AGAIN );
01183 
01184                 rcText.OffsetRect( 0, rcText.Height() );
01185 
01186                 dc.SelectObject( &theApp.m_gdiFontLine );
01187                 dc.SetTextColor( RGB( 0, 0, 255 ) );
01188 
01189                 szText          = dc.GetTextExtent( strText );
01190                 ptText.x        = ( rcText.left + rcText.right ) / 2 - szText.cx / 2;
01191                 ptText.y        = ( rcText.top + rcText.bottom ) / 2 - szText.cy / 2;
01192 
01193                 dc.ExtTextOut( ptText.x, ptText.y, ETO_CLIPPED|ETO_OPAQUE, &rcText, strText, NULL );
01194                 dc.ExcludeClipRect( &rcText );
01195         }
01196 }
01197 
01199 // CMatchCtrl mouse based interaction
01200 
01201 BOOL CMatchCtrl::HitTest(const CPoint& point, CMatchFile** poFile, CQueryHit** poHit, DWORD* pnIndex, CRect* pRect)
01202 {
01203         CSingleLock pLock( &m_pMatches->m_pSection );
01204         CRect rcClient, rcItem;
01205         
01206         if ( poFile ) *poFile = NULL;
01207         if ( poHit ) *poHit = NULL;
01208         if ( pnIndex ) *pnIndex = 0xFFFFFFFF;
01209         
01210         if ( ! pLock.Lock( 10 ) ) return FALSE;
01211         
01212         GetClientRect( &rcClient );
01213         rcClient.top += HEADER_HEIGHT;
01214         
01215         rcItem.SetRect( rcClient.left, rcClient.top, rcClient.right, 0 );
01216         rcItem.top -= m_nHitIndex * ITEM_HEIGHT;
01217         rcItem.bottom = rcItem.top + ITEM_HEIGHT;
01218         
01219         CMatchFile** ppFile = m_pMatches->m_pFiles + m_nTopIndex;
01220         
01221         for (   DWORD nIndex = m_nTopIndex ;
01222                         nIndex < m_pMatches->m_nFiles && rcItem.top < rcClient.bottom ;
01223                         nIndex++, ppFile++ )
01224         {
01225                 CMatchFile* pFile = *ppFile;
01226                 int nCount = pFile->GetFilteredCount();
01227                 
01228                 if ( ! nCount ) continue;
01229                 
01230                 if ( rcItem.top >= rcClient.top && rcItem.PtInRect( point ) )
01231                 {
01232                         *poFile = pFile;
01233                         if ( pnIndex ) *pnIndex = nIndex;
01234                         if ( pRect ) *pRect = rcItem;
01235                         return TRUE;
01236                 }
01237                 
01238                 rcItem.top += ITEM_HEIGHT;
01239                 rcItem.bottom += ITEM_HEIGHT;
01240                 
01241                 if ( nCount > 1 && pFile->m_bExpanded )
01242                 {
01243                         for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
01244                         {
01245                                 if ( ! pHit->m_bFiltered ) continue;
01246                                 
01247                                 if ( rcItem.top >= rcClient.top && rcItem.PtInRect( point ) )
01248                                 {
01249                                         *poFile = pFile;
01250                                         *poHit = pHit;
01251                                         if ( pnIndex ) *pnIndex = nIndex;
01252                                         if ( pRect ) *pRect = rcItem;
01253                                         return TRUE;
01254                                 }
01255                                 
01256                                 rcItem.top += ITEM_HEIGHT;
01257                                 rcItem.bottom += ITEM_HEIGHT;
01258                                 
01259                                 if ( rcItem.top >= rcClient.bottom ) break;
01260                         }
01261                 }
01262         }
01263         
01264         return FALSE;
01265 }
01266 
01267 BOOL CMatchCtrl::GetItemRect(CMatchFile* pFindFile, CQueryHit* pFindHit, CRect* pRect)
01268 {
01269         CSingleLock pLock( &m_pMatches->m_pSection );
01270         CRect rcClient, rcItem;
01271         
01272         if ( ! pLock.Lock( 10 ) ) return FALSE;
01273         
01274         GetClientRect( &rcClient );
01275         rcClient.top += HEADER_HEIGHT;
01276         
01277         rcItem.SetRect( rcClient.left, rcClient.top, rcClient.right, rcClient.top + ITEM_HEIGHT );
01278         rcItem.top -= m_nHitIndex * ITEM_HEIGHT;
01279         rcItem.bottom = rcItem.top + ITEM_HEIGHT;
01280         
01281         if ( m_nTopIndex > 0 )
01282         {
01283                 CMatchFile** ppFile = m_pMatches->m_pFiles + m_nTopIndex - 1;
01284                 
01285                 for ( DWORD nIndex = m_nTopIndex ; nIndex ; nIndex--, ppFile-- )
01286                 {
01287                         CMatchFile* pFile = *ppFile;
01288                         int nCount = pFile->GetFilteredCount();
01289                         
01290                         if ( ! nCount ) continue;
01291                         
01292                         rcItem.top -= ITEM_HEIGHT;
01293                         rcItem.bottom -= ITEM_HEIGHT;
01294                         
01295                         if ( nCount > 1 && pFile->m_bExpanded )
01296                         {
01297                                 for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
01298                                 {
01299                                         if ( ! pHit->m_bFiltered ) continue;
01300                                         
01301                                         rcItem.top -= ITEM_HEIGHT;
01302                                         rcItem.bottom -= ITEM_HEIGHT;
01303                                 }
01304                         }
01305                 }
01306         }
01307         
01308         CMatchFile** ppFile = ppFile = m_pMatches->m_pFiles;
01309         
01310         for ( DWORD nIndex = m_pMatches->m_nFiles ; nIndex ; nIndex--, ppFile++ )
01311         {
01312                 CMatchFile* pFile = *ppFile;
01313                 int nCount = pFile->GetFilteredCount();
01314                 
01315                 if ( ! nCount ) continue;
01316                 
01317                 if ( pFile == pFindFile )
01318                 {
01319                         *pRect = rcItem;
01320                         return TRUE;
01321                 }
01322                 
01323                 rcItem.top += ITEM_HEIGHT;
01324                 rcItem.bottom += ITEM_HEIGHT;
01325                 
01326                 if ( nCount > 1 && pFile->m_bExpanded )
01327                 {
01328                         for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
01329                         {
01330                                 if ( ! pHit->m_bFiltered ) continue;
01331                                 
01332                                 if ( pHit == pFindHit )
01333                                 {
01334                                         *pRect = rcItem;
01335                                         return TRUE;
01336                                 }
01337                                 
01338                                 rcItem.top += ITEM_HEIGHT;
01339                                 rcItem.bottom += ITEM_HEIGHT;
01340                         }
01341                 }
01342         }
01343         
01344         return FALSE;
01345 }
01346 
01347 void CMatchCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
01348 {
01349         CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
01350         CMatchFile* pFile;
01351         CQueryHit* pHit;
01352         DWORD nIndex;
01353         CRect rcItem;
01354         
01355         SetFocus();
01356         SetCapture();
01357         m_wndTip.Hide();
01358         
01359         HitTest( point, &pFile, &pHit, &nIndex, &rcItem );
01360         
01361         if ( pFile != NULL && pHit == NULL && pFile->GetFilteredCount() > 1 )
01362         {
01363                 CRect rcHeader;
01364                 Header_GetItemRect( m_wndHeader.GetSafeHwnd(), 0, &rcHeader );
01365                 
01366                 point.x += GetScrollPos( SB_HORZ );
01367                 
01368                 if ( point.x >= rcHeader.left && point.x <= rcHeader.left + 16 )
01369                 {
01370                         pFile->Expand( ! pFile->m_bExpanded );
01371                         NotifySelection();
01372                         Update();
01373                         return;
01374                 }
01375 
01376                 point.x -= GetScrollPos( SB_HORZ );
01377         }
01378         
01379         BOOL bChanged = FALSE;
01380         
01381         if ( ( nFlags & MK_SHIFT ) == 0 && ( nFlags & MK_CONTROL ) == 0 &&
01382                  ( nFlags & MK_RBUTTON ) == 0 )
01383         {
01384                 bChanged |= m_pMatches->ClearSelection();
01385                 m_nFocus = nIndex;
01386         }
01387         
01388         if ( pFile != NULL )
01389         {
01390                 BOOL bSelected = ( pHit != NULL ) ? pHit->m_bSelected : pFile->m_bSelected;
01391                 
01392                 if ( nFlags & MK_RBUTTON )
01393                 {
01394                         if ( ! bSelected )
01395                         {
01396                                 m_pMatches->ClearSelection();
01397                                 m_pMatches->Select( pFile, pHit, TRUE );
01398                                 m_nFocus = nIndex;
01399                         }
01400                 }
01401                 else
01402                 {
01403                         bChanged |= m_pMatches->Select( pFile, pHit, ! bSelected );
01404                 }
01405         }
01406         
01407         if ( bChanged ) NotifySelection();
01408         Update();
01409 }
01410 
01411 void CMatchCtrl::OnMouseMove(UINT nFlags, CPoint point) 
01412 {
01413         CRect rcCol;
01414         
01415         GetClientRect( &rcCol );
01416         rcCol.top += HEADER_HEIGHT;
01417         
01418         if ( m_bTips && rcCol.PtInRect( point ) && point.x >= rcCol.left + 16 )
01419         {
01420                 CSingleLock pLock( &m_pMatches->m_pSection );
01421                 if ( ! pLock.Lock( 100 ) ) return;
01422                 
01423                 CMatchFile* pFile;
01424                 CQueryHit* pHit;
01425                 
01426                 if ( HitTest( point, &pFile, &pHit ) && PixelTest( point ) )
01427                 {
01428                         m_wndTip.Show( pFile, pHit );
01429                         return;
01430                 }
01431         }
01432         
01433         m_wndTip.Hide();
01434 }
01435 
01436 BOOL CMatchCtrl::PixelTest(const CPoint& point)
01437 {
01438         POINT pNESW[4] = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };
01439         CClientDC dc( this );
01440         COLORREF crEmpty;
01441         CRect rc;
01442         
01443         crEmpty = CoolInterface.m_crWindow;
01444         if ( dc.GetPixel( point ) != crEmpty ) return TRUE;
01445         GetClientRect( &rc );
01446         
01447         for ( int nDirection = 0 ; nDirection < 4 ; nDirection++ )
01448         {
01449                 CPoint pt( point );
01450 
01451                 for ( int nLength = 16 ; nLength ; nLength-- )
01452                 {
01453                         pt += pNESW[ nDirection ];
01454                         if ( ! rc.PtInRect( pt ) ) break;
01455                         if ( dc.GetPixel( pt ) != crEmpty ) return TRUE;
01456                 }
01457         }
01458         
01459         return FALSE;
01460 }
01461 
01462 void CMatchCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
01463 {
01464         ReleaseCapture();
01465         
01466         if ( m_pMatches->m_nFilteredFiles == 0 && m_bSearchLink )
01467         {
01468                 CRect rc;
01469                 
01470                 GetClientRect( &rc );
01471                 rc.top += HEADER_HEIGHT;
01472                 
01473                 rc.left         = ( rc.left + rc.right ) / 2 - 64;
01474                 rc.right        = rc.left + 128;
01475                 rc.top          = ( rc.top + rc.bottom ) / 2;
01476                 rc.bottom       = rc.top + 16;
01477                 
01478                 if ( rc.PtInRect( point ) )
01479                 {
01480                         GetOwner()->PostMessage( WM_COMMAND, ID_SEARCH_SEARCH );
01481                         return;
01482                 }
01483         }
01484 }
01485 
01486 void CMatchCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
01487 {
01488         if ( point.x < 16 )
01489         {
01490                 OnLButtonDown( nFlags, point );
01491         }
01492         else
01493         {
01494                 CMatchFile* pFile       = NULL;
01495                 CQueryHit* pHit         = NULL;
01496                 CRect rcItem;
01497                 
01498                 if ( HitTest( point, &pFile, &pHit, NULL, &rcItem ) )
01499                 {
01500                         // TODO: Check if its on an action icon and take the appropriate action
01501                 }
01502                 
01503                 GetOwner()->PostMessage( WM_COMMAND, ID_SEARCH_DOWNLOAD );
01504         }
01505 }
01506 
01507 void CMatchCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
01508 {
01509         OnLButtonDown( nFlags, point );
01510         CWnd::OnRButtonDown( nFlags, point );
01511 }
01512 
01513 void CMatchCtrl::OnRButtonUp(UINT nFlags, CPoint point) 
01514 {
01515         OnLButtonUp( nFlags, point );
01516         CWnd::OnRButtonUp( nFlags, point );
01517 }
01518 
01519 BOOL CMatchCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
01520 {
01521         if ( m_pMatches->m_nFilteredFiles == 0 && m_bSearchLink )
01522         {
01523                 CPoint point;
01524                 CRect rc;
01525                 
01526                 GetClientRect( &rc );
01527                 rc.top += HEADER_HEIGHT;
01528                 
01529                 rc.left         = ( rc.left + rc.right ) / 2 - 64;
01530                 rc.right        = rc.left + 128;
01531                 rc.top          = ( rc.top + rc.bottom ) / 2;
01532                 rc.bottom       = rc.top + 16;
01533                 ClientToScreen( &rc );
01534                 
01535                 GetCursorPos( &point );
01536                 
01537                 if ( rc.PtInRect( point ) )
01538                 {
01539                         SetCursor( theApp.LoadCursor( IDC_HAND ) );
01540                         return TRUE;
01541                 }
01542         }
01543         
01544         return CWnd::OnSetCursor( pWnd, nHitTest, message );
01545 }
01546 
01548 // CMatchCtrl key based interaction
01549 
01550 void CMatchCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
01551 {
01552         BOOL bShift = ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0x8000;
01553         
01554         m_wndTip.Hide();
01555         
01556         switch ( nChar )
01557         {
01558         case VK_ESCAPE:
01559                 if ( m_pMatches->ClearSelection() ) NotifySelection();
01560                 Update();
01561                 return;
01562         case VK_HOME:
01563                 MoveFocus( -(int)m_pMatches->m_nItems, bShift );
01564                 return;
01565         case VK_END:
01566                 MoveFocus( m_pMatches->m_nItems, bShift );
01567                 return;
01568         case VK_PRIOR:
01569                 MoveFocus( -m_nPageCount, bShift );
01570                 return;
01571         case VK_NEXT:
01572                 MoveFocus( m_nPageCount, bShift );
01573                 return;
01574         case VK_UP:
01575                 MoveFocus( -1, bShift );
01576                 return;
01577         case VK_DOWN:
01578                 MoveFocus( 1, bShift );
01579                 return;
01580         case VK_RETURN:
01581                 GetOwner()->PostMessage( WM_COMMAND, ID_SEARCH_DOWNLOAD );
01582                 return;
01583         case VK_DELETE:
01584                 DoDelete();
01585                 return;
01586         case VK_LEFT:
01587         case VK_SUBTRACT:
01588                 DoExpand( FALSE );
01589                 break;
01590         case VK_RIGHT:
01591         case VK_ADD:
01592                 DoExpand( TRUE );
01593                 break;
01594         case VK_TAB:
01595                 if ( CBaseMatchWnd* pOwner = (CBaseMatchWnd*)GetOwner() )
01596                 {
01597                         if ( pOwner->IsKindOf( RUNTIME_CLASS(CBaseMatchWnd) ) )
01598                         {
01599                                 pOwner->m_wndFilter.SetFocus();
01600                         }
01601                 }
01602                 break;
01603         }
01604         
01605         CWnd::OnKeyDown( nChar, nRepCnt, nFlags );
01606 }
01607 
01608 void CMatchCtrl::MoveFocus(int nDelta, BOOL bShift)
01609 {
01610         CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
01611         
01612         if ( m_pMatches->m_nFiles == 0 || nDelta == 0 ) return;
01613         
01614         if ( m_nFocus >= m_pMatches->m_nFiles )
01615         {
01616                 m_nFocus = nDelta > 0 ? 0 : m_pMatches->m_nFiles - 1;
01617         }
01618         
01619         CMatchFile** ppFile = m_pMatches->m_pFiles + m_nFocus;
01620         int nSign = ( nDelta > 0 ) ? 1 : -1;
01621 
01622         for ( ; m_nFocus < m_pMatches->m_nFiles
01623                   ;     m_nFocus += nSign, ppFile += nSign )
01624         {
01625                 CMatchFile* pFile = *ppFile;
01626                 if ( pFile->GetItemCount() ) break;
01627         }
01628         
01629         if ( m_nFocus >= m_pMatches->m_nFiles )
01630         {
01631                 m_nFocus = nDelta > 0 ? m_pMatches->m_nFiles - 1 : 0;
01632                 return;
01633         }
01634         
01635         CMatchFile* pFocus = NULL;
01636         nDelta += nSign;
01637         
01638         for (   DWORD nPosition = m_nFocus ;
01639                         nPosition < m_pMatches->m_nFiles && nDelta != 0 ;
01640                         nPosition += nSign, ppFile += nSign )
01641         {
01642                 CMatchFile* pFile = *ppFile;
01643 
01644                 if ( pFile->GetItemCount() )
01645                 {
01646                         m_nFocus        = nPosition;
01647                         pFocus          = pFile;
01648                         nDelta          -= nSign;
01649                 }
01650         }
01651         
01652         if ( pFocus != NULL )
01653         {
01654                 CRect rcItem, rcClient;
01655                 BOOL bChanged = FALSE;
01656                                 
01657                 if ( ! bShift ) bChanged |= m_pMatches->ClearSelection();
01658                 bChanged |= m_pMatches->Select( pFocus, NULL, TRUE );
01659                                 
01660                 if ( GetItemRect( pFocus, NULL, &rcItem ) )
01661                 {
01662                         GetClientRect( &rcClient );
01663                         rcClient.top += HEADER_HEIGHT;
01664                         
01665                         if ( rcItem.top < rcClient.top )
01666                         {
01667                                 ScrollBy( ( rcItem.top - rcClient.top - ITEM_HEIGHT + 1 ) / ITEM_HEIGHT );
01668                         }
01669                         else if ( rcItem.bottom > rcClient.bottom )
01670                         {
01671                                 ScrollBy( ( rcItem.bottom - rcClient.bottom + ITEM_HEIGHT - 1 ) / ITEM_HEIGHT );
01672                         }
01673                 }
01674                 
01675                 if ( bChanged ) NotifySelection();
01676                 Update();
01677         }
01678 }
01679 
01680 void CMatchCtrl::DoDelete()
01681 {
01682         CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
01683         BOOL bChanged = FALSE;
01684         
01685         for ( POSITION pos = m_pMatches->m_pSelectedFiles.GetHeadPosition() ; pos ; )
01686         {
01687                 CMatchFile* pFile = (CMatchFile*)m_pMatches->m_pSelectedFiles.GetNext( pos );
01688                 bChanged |= m_pMatches->Select( pFile, NULL, FALSE );
01689                 
01690                 for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
01691                 {
01692                         pHit->m_bBogus = TRUE;
01693                 }
01694         }
01695         
01696         for ( POSITION pos = m_pMatches->m_pSelectedHits.GetHeadPosition() ; pos ; )
01697         {
01698                 CQueryHit* pHit = (CQueryHit*)m_pMatches->m_pSelectedHits.GetNext( pos );
01699                 m_pMatches->Select( NULL, pHit, FALSE );
01700                 pHit->m_bBogus = TRUE;
01701         }
01702         
01703         m_pMatches->Filter();
01704         
01705         m_wndTip.Hide();
01706         if ( bChanged ) NotifySelection();
01707         Update();
01708 }
01709 
01710 void CMatchCtrl::DoExpand(BOOL bExpand)
01711 {
01712         CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
01713         BOOL bChanged = FALSE;
01714         
01715         for ( POSITION pos = m_pMatches->m_pSelectedFiles.GetHeadPosition() ; pos ; )
01716         {
01717                 CMatchFile* pFile = (CMatchFile*)m_pMatches->m_pSelectedFiles.GetNext( pos );
01718 
01719                 bChanged |= pFile->Expand( bExpand );
01720         }
01721         
01722         m_wndTip.Hide();
01723         if ( bChanged ) NotifySelection();
01724         Update();
01725 }
01726 
01727 void CMatchCtrl::NotifySelection()
01728 {
01729         GetOwner()->PostMessage( WM_COMMAND, MAKELONG( GetDlgCtrlID(), LBN_SELCHANGE ), (LPARAM)GetSafeHwnd() );
01730 }
01731 
01733 // CMatchCtrl header interaction
01734 
01735 void CMatchCtrl::OnClickHeader(NMHDR* pNotifyStruct, LRESULT* pResult)
01736 {
01737         HD_NOTIFY* pNotify = (HD_NOTIFY*)pNotifyStruct;
01738         
01739         if ( m_pMatches->m_nSortColumn == pNotify->iItem )
01740         {
01741                 if ( m_pMatches->m_bSortDir == 1 )
01742                 {
01743                         SetSortColumn( -1 );
01744                 }
01745                 else
01746                 {
01747                         SetSortColumn( pNotify->iItem, FALSE );
01748                 }
01749         }
01750         else
01751         {
01752                 SetSortColumn( pNotify->iItem, TRUE );
01753         }
01754 }
01755 
01756 void CMatchCtrl::OnChangeHeader(NMHDR* pNotifyStruct, LRESULT* pResult)
01757 {
01758         Invalidate();
01759 }
01760 
01761 void CMatchCtrl::OnTimer(UINT nIDEvent) 
01762 {
01763         Invalidate();
01764 }
01765 
01766 void CMatchCtrl::OnSetFocus(CWnd* pOldWnd)
01767 {
01768         CWnd::OnSetFocus( pOldWnd );
01769         Invalidate();
01770 }
01771 
01772 void CMatchCtrl::OnKillFocus(CWnd* pNewWnd)
01773 {
01774         CWnd::OnKillFocus( pNewWnd );
01775         Invalidate();
01776 }

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