00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "CoolInterface.h"
00025 #include "LiveList.h"
00026
00027 #ifdef _DEBUG
00028 #undef THIS_FILE
00029 static char THIS_FILE[]=__FILE__;
00030 #define new DEBUG_NEW
00031 #endif
00032
00033
00035
00036
00037 CLiveList::CLiveList(int nColumns)
00038 {
00039 m_nColumns = nColumns;
00040 }
00041
00042 CLiveList::~CLiveList()
00043 {
00044 Clear();
00045 }
00046
00048
00049
00050 void CLiveList::Clear()
00051 {
00052 for ( POSITION pos = m_pItems.GetStartPosition() ; pos ; )
00053 {
00054 CLiveItem* pItem;
00055 DWORD nParam;
00056
00057 m_pItems.GetNextAssoc( pos, nParam, pItem );
00058 delete pItem;
00059 }
00060 m_pItems.RemoveAll();
00061 }
00062
00064
00065
00066 CLiveItem* CLiveList::Add(DWORD nParam)
00067 {
00068 CLiveItem* pItem = new CLiveItem( m_nColumns, nParam );
00069 m_pItems.SetAt( nParam, pItem );
00070 return pItem;
00071 }
00072
00073 CLiveItem* CLiveList::Add(LPVOID pParam)
00074 {
00075 return Add( (DWORD)pParam );
00076 }
00077
00079
00080
00081 void CLiveList::Apply(CListCtrl* pCtrl, BOOL bSort)
00082 {
00083 BOOL bModified = FALSE;
00084
00085 for ( int nItem = 0 ; nItem < pCtrl->GetItemCount() ; nItem++ )
00086 {
00087 DWORD nParam = (DWORD)pCtrl->GetItemData( nItem );
00088 CLiveItem* pItem = NULL;
00089
00090 if ( m_pItems.Lookup( nParam, pItem ) )
00091 {
00092 if ( pItem->Update( pCtrl, nItem, m_nColumns ) ) bModified = TRUE;
00093
00094 delete pItem;
00095 m_pItems.RemoveKey( nParam );
00096 }
00097 else
00098 {
00099 pCtrl->DeleteItem( nItem-- );
00100 bModified = TRUE;
00101 }
00102 }
00103
00104 int nCount = pCtrl->GetItemCount();
00105
00106 for ( POSITION pos = m_pItems.GetStartPosition() ; pos ; )
00107 {
00108 CLiveItem* pItem;
00109 DWORD nParam;
00110
00111 m_pItems.GetNextAssoc( pos, nParam, pItem );
00112
00113 pItem->Add( pCtrl, nCount++, m_nColumns );
00114 bModified = TRUE;
00115
00116 delete pItem;
00117 }
00118
00119 m_pItems.RemoveAll();
00120
00121 if ( bModified && bSort ) Sort( pCtrl, -1 );
00122 }
00123
00125
00126
00127 CLiveItem::CLiveItem(int nColumns, DWORD nParam)
00128 {
00129 m_pColumn = new CString[ nColumns ];
00130 m_nParam = nParam;
00131 m_nImage = 0;
00132 m_nMaskOverlay = 0;
00133 m_nMaskState = 0;
00134 }
00135
00136 CLiveItem::~CLiveItem()
00137 {
00138 delete [] m_pColumn;
00139 }
00140
00142
00143
00144 void CLiveItem::Set(int nColumn, LPCTSTR pszText)
00145 {
00146 m_pColumn[ nColumn ] = pszText;
00147 }
00148
00150
00151
00152 void CLiveItem::Format(int nColumn, LPCTSTR pszFormat, ...)
00153 {
00154 static TCHAR szBuffer[1024];
00155 va_list pArgs;
00156
00157 va_start( pArgs, pszFormat );
00158 _vsntprintf( szBuffer, sizeof( szBuffer ) / sizeof( TCHAR ), pszFormat, pArgs );
00159 szBuffer[ sizeof( szBuffer ) / sizeof( TCHAR ) - 1 ] = 0;
00160 va_end( pArgs );
00161
00162 m_pColumn[ nColumn ] = szBuffer;
00163 }
00164
00166
00167
00168 int CLiveItem::Add(CListCtrl* pCtrl, int nItem, int nColumns)
00169 {
00170 LV_ITEM pItem;
00171
00172 ZeroMemory( &pItem, sizeof(pItem) );
00173 pItem.mask = LVIF_PARAM|LVIF_TEXT|LVIF_IMAGE|LVIF_STATE;
00174 pItem.iItem = nItem >= 0 ? nItem : pCtrl->GetItemCount();
00175 pItem.lParam = (LPARAM)m_nParam;
00176 pItem.iImage = m_nImage;
00177 pItem.state = INDEXTOOVERLAYMASK( m_nMaskOverlay ) | INDEXTOSTATEIMAGEMASK( m_nMaskState );
00178 pItem.stateMask = LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
00179 pItem.pszText = (LPTSTR)(LPCTSTR)m_pColumn[0];
00180 pItem.iItem = pCtrl->InsertItem( &pItem );
00181 pItem.mask = LVIF_TEXT;
00182
00183 for ( pItem.iSubItem = 1 ; pItem.iSubItem < nColumns ; pItem.iSubItem++ )
00184 {
00185 pItem.pszText = (LPTSTR)(LPCTSTR)m_pColumn[ pItem.iSubItem ];
00186 pCtrl->SetItem( &pItem );
00187 }
00188
00189 return pItem.iItem;
00190 }
00191
00193
00194
00195 BOOL CLiveItem::Update(CListCtrl* pCtrl, int nItem, int nColumns)
00196 {
00197 BOOL bModified = FALSE;
00198 LV_ITEM pItem;
00199
00200 ZeroMemory( &pItem, sizeof(pItem) );
00201 pItem.mask = LVIF_PARAM|LVIF_IMAGE|LVIF_STATE;
00202 pItem.iItem = nItem;
00203 pItem.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK;
00204
00205 if ( ! pCtrl->GetItem( &pItem ) || pItem.lParam != (LPARAM)m_nParam ) return FALSE;
00206
00207 if ( m_nImage != pItem.iImage )
00208 {
00209 pItem.iImage = m_nImage;
00210 bModified = TRUE;
00211 }
00212
00213 if ( ( pItem.state & (LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK) ) != ( INDEXTOOVERLAYMASK( m_nMaskOverlay ) | INDEXTOSTATEIMAGEMASK( m_nMaskState ) ) )
00214 {
00215 pItem.state = INDEXTOOVERLAYMASK( m_nMaskOverlay ) | INDEXTOSTATEIMAGEMASK( m_nMaskState );
00216 pItem.stateMask = LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
00217 bModified = TRUE;
00218 }
00219
00220 if ( bModified ) pCtrl->SetItem( &pItem );
00221
00222 for ( int nColumn = 0 ; nColumn < nColumns ; nColumn++ )
00223 {
00224 if ( pCtrl->GetItemText( nItem, nColumn ) != m_pColumn[ nColumn ] )
00225 {
00226 pCtrl->SetItemText( nItem, nColumn, m_pColumn[ nColumn ] );
00227 bModified = TRUE;
00228 }
00229 }
00230
00231 return bModified;
00232 }
00233
00234
00236
00237
00238 CBitmap CLiveList::m_bmSortAsc;
00239 CBitmap CLiveList::m_bmSortDesc;
00240
00241 void CLiveList::Sort(CListCtrl* pCtrl, int nColumn, BOOL bGraphic)
00242 {
00243 int nOldColumn = GetWindowLong( pCtrl->GetSafeHwnd(), GWL_USERDATA );
00244 BOOL bWaiting = FALSE;
00245
00246 if ( nColumn == -1 )
00247 {
00248 nColumn = nOldColumn;
00249 }
00250 else
00251 {
00252 if ( nColumn == abs( nOldColumn ) - 1 )
00253 {
00254 if ( nOldColumn > 0 )
00255 nColumn = 0 - nOldColumn;
00256 else
00257 nColumn = 0;
00258 }
00259 else
00260 {
00261 nColumn++;
00262 }
00263
00264 SetWindowLong( pCtrl->GetSafeHwnd(), GWL_USERDATA, nColumn );
00265
00266 bWaiting = TRUE;
00267 theApp.BeginWaitCursor();
00268 }
00269
00270 #ifdef IDB_SORT_ASC
00271 if ( bGraphic )
00272 {
00273 if ( m_bmSortAsc.m_hObject == NULL )
00274 {
00275 m_bmSortAsc.LoadMappedBitmap( IDB_SORT_ASC );
00276 m_bmSortDesc.LoadMappedBitmap( IDB_SORT_DESC );
00277 }
00278
00279 CHeaderCtrl* pHeader = (CHeaderCtrl*)CWnd::FromHandle( (HWND)pCtrl->SendMessage( LVM_GETHEADER ) );
00280
00281 for ( int nCol = 0 ; ; nCol++ )
00282 {
00283 HDITEM pColumn;
00284
00285 ZeroMemory( &pColumn, sizeof(pColumn) );
00286 pColumn.mask = HDI_BITMAP|HDI_FORMAT;
00287
00288 if ( !pHeader->GetItem( nCol, &pColumn ) ) break;
00289
00290 if ( nCol == abs( nColumn ) - 1 )
00291 {
00292 pColumn.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT;
00293 pColumn.hbm = (HBITMAP)( nColumn > 0 ? m_bmSortAsc.GetSafeHandle() : m_bmSortDesc.GetSafeHandle() );
00294 }
00295 else
00296 {
00297 pColumn.fmt &= ~HDF_BITMAP;
00298 pColumn.hbm = NULL;
00299 }
00300
00301 pHeader->SetItem( nCol, &pColumn );
00302 }
00303 }
00304 #endif
00305
00306 if ( nColumn ) pCtrl->SendMessage( LVM_SORTITEMS, (WPARAM)pCtrl, (LPARAM)SortCallback );
00307
00308 if ( bWaiting ) theApp.EndWaitCursor();
00309 }
00310
00312
00313
00314 int CALLBACK CLiveList::SortCallback(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
00315 {
00316 CListCtrl* pList = (CListCtrl*)lParamSort;
00317 int nColumn = (int)GetWindowLong( pList->GetSafeHwnd(), GWL_USERDATA );
00318 LV_FINDINFO pFind;
00319 int nA, nB;
00320
00321 pFind.flags = LVFI_PARAM;
00322 pFind.lParam = lParam1;
00323 nA = pList->FindItem( &pFind );
00324 pFind.lParam = lParam2;
00325 nB = pList->FindItem( &pFind );
00326
00327 CString sA, sB;
00328
00329 BOOL bInv = ( nColumn > 0 ) ? TRUE : FALSE;
00330 nColumn = ( bInv ? nColumn : -nColumn ) - 1;
00331
00332 sA = pList->GetItemText( nA, nColumn );
00333 sB = pList->GetItemText( nB, nColumn );
00334
00335 return bInv ? SortProc( sB, sA ) : SortProc( sA, sB );
00336 }
00337
00338 int CLiveList::SortProc(LPCTSTR sA, LPCTSTR sB, BOOL bNumeric)
00339 {
00340 if ( bNumeric || ( IsNumber( sA ) && IsNumber( sB ) ) )
00341 {
00342 double nA = 0, nB = 0;
00343
00344 if ( *sA == '(' || *sA == 'Q' )
00345 _stscanf( sA+1, _T("%lf"), &nA );
00346 else
00347 _stscanf( sA, _T("%lf (%lf)"), &nA, &nA );
00348
00349 if ( *sB == '(' || *sB == 'Q' )
00350 _stscanf( sB+1, _T("%lf"), &nB );
00351 else
00352 _stscanf( sB, _T("%lf (%lf)"), &nB, &nB );
00353
00354 if ( _tcsstr( sA, _T(" K") ) ) nA *= 1024;
00355 if ( _tcsstr( sA, _T(" M") ) ) nA *= 1024*1024;
00356 if ( _tcsstr( sA, _T(" G") ) ) nA *= 1024*1024*1024;
00357 if ( _tcsstr( sA, _T(" T") ) ) nA *= 1099511627776.0f;
00358
00359 if ( _tcsstr( sB, _T(" K") ) ) nB *= 1024;
00360 if ( _tcsstr( sB, _T(" M") ) ) nB *= 1024*1024;
00361 if ( _tcsstr( sB, _T(" G") ) ) nB *= 1024*1024*1024;
00362 if ( _tcsstr( sB, _T(" T") ) ) nB *= 1099511627776.0f;
00363
00364 if ( nA < nB )
00365 return -1;
00366 else if ( nA > nB )
00367 return 1;
00368 else
00369 return 0;
00370 }
00371 else
00372 {
00373 return _tcsicoll( sA, sB );
00374 }
00375 }
00376
00377 BOOL CLiveList::IsNumber(LPCTSTR pszString)
00378 {
00379 if ( ! *pszString ) return FALSE;
00380
00381
00382 if ( *pszString == '(' && _tcsstr( pszString, _T(" source") ) != NULL ) return TRUE;
00383 if ( *pszString == 'Q' && _istdigit( pszString[1] ) ) return TRUE;
00384
00385 BOOL bSpace = FALSE;
00386 int nNonDigit = 0;
00387
00388 for ( ; *pszString ; pszString++ )
00389 {
00390 if ( _istdigit( *pszString ) || *pszString == '.' )
00391 {
00392
00393 }
00394 else if ( *pszString == ' ' )
00395 {
00396 if ( bSpace ) return FALSE;
00397 bSpace = TRUE;
00398 }
00399 else if ( *pszString == 'k' && ( ! pszString[1] || pszString[1] == '~' ) )
00400 {
00401
00402 return TRUE;
00403 }
00404 else if ( *pszString == '(' || *pszString == ')' )
00405 {
00406 }
00407 else
00408 {
00409 if ( ! bSpace ) return FALSE;
00410 if ( ++nNonDigit > 4 ) return FALSE;
00411 }
00412 }
00413
00414 return TRUE;
00415 }
00416
00418
00419
00420 #define MAX_DRAG_SIZE 128
00421 #define MAX_DRAG_SIZE_2 (MAX_DRAG_SIZE/2)
00422
00423 COLORREF CLiveList::crDrag = RGB( 250, 255, 250 );
00424
00425 CImageList* CLiveList::CreateDragImage(CListCtrl* pList, const CPoint& ptMouse)
00426 {
00427 CRect rcClient, rcOne, rcAll( 32000, 32000, -32000, -32000 );
00428 int nIndex;
00429
00430 if ( pList->GetSelectedCount() == 0 ) return NULL;
00431
00432 pList->SetFocus();
00433 pList->GetClientRect( &rcClient );
00434
00435 for ( nIndex = -1 ; ( nIndex = pList->GetNextItem( nIndex, LVNI_SELECTED ) ) >= 0 ; )
00436 {
00437 pList->GetItemRect( nIndex, rcOne, LVIR_BOUNDS );
00438
00439 if ( rcOne.IntersectRect( &rcClient, &rcOne ) )
00440 {
00441 rcAll.left = min( rcAll.left, rcOne.left );
00442 rcAll.top = min( rcAll.top, rcOne.top );
00443 rcAll.right = max( rcAll.right, rcOne.right );
00444 rcAll.bottom = max( rcAll.bottom, rcOne.bottom );
00445 }
00446
00447 pList->SetItemState( nIndex, 0, LVIS_FOCUSED );
00448 }
00449
00450 BOOL bClipped = rcAll.Height() > MAX_DRAG_SIZE;
00451
00452 if ( bClipped )
00453 {
00454 rcAll.left = max( rcAll.left, ptMouse.x - MAX_DRAG_SIZE_2 );
00455 rcAll.right = max( rcAll.right, ptMouse.x + MAX_DRAG_SIZE_2 );
00456 rcAll.top = max( rcAll.top, ptMouse.y - MAX_DRAG_SIZE_2 );
00457 rcAll.bottom = max( rcAll.bottom, ptMouse.y + MAX_DRAG_SIZE_2 );
00458 }
00459
00460 CClientDC dcClient( pList );
00461 CBitmap bmAll, bmDrag;
00462 CDC dcAll, dcDrag;
00463
00464 if ( ! dcAll.CreateCompatibleDC( &dcClient ) )
00465 return NULL;
00466 if ( ! bmAll.CreateCompatibleBitmap( &dcClient, rcClient.Width(), rcClient.Height() ) )
00467 return NULL;
00468
00469 if ( ! dcDrag.CreateCompatibleDC( &dcClient ) )
00470 return NULL;
00471 if ( ! bmDrag.CreateCompatibleBitmap( &dcClient, rcAll.Width(), rcAll.Height() ) )
00472 return NULL;
00473
00474 CBitmap *pOldAll = dcAll.SelectObject( &bmAll );
00475
00476 dcAll.FillSolidRect( &rcClient, crDrag );
00477
00478 COLORREF crBack = pList->GetBkColor();
00479 pList->SetBkColor( crDrag );
00480 pList->SendMessage( WM_PAINT, (WPARAM)dcAll.GetSafeHdc() );
00481 pList->SetBkColor( crBack );
00482
00483 CBitmap *pOldDrag = dcDrag.SelectObject( &bmDrag );
00484
00485 dcDrag.FillSolidRect( 0, 0, rcAll.Width(), rcAll.Height(), crDrag );
00486
00487 CRgn pRgn;
00488
00489 if ( bClipped )
00490 {
00491 CPoint ptMiddle( ptMouse.x - rcAll.left, ptMouse.y - rcAll.top );
00492 pRgn.CreateEllipticRgn( ptMiddle.x - MAX_DRAG_SIZE_2, ptMiddle.y - MAX_DRAG_SIZE_2,
00493 ptMiddle.x + MAX_DRAG_SIZE_2, ptMiddle.y + MAX_DRAG_SIZE_2 );
00494 dcDrag.SelectClipRgn( &pRgn );
00495 }
00496
00497 for ( nIndex = -1 ; ( nIndex = pList->GetNextItem( nIndex, LVNI_SELECTED ) ) >= 0 ; )
00498 {
00499 pList->GetItemRect( nIndex, rcOne, LVIR_BOUNDS );
00500
00501 if ( rcOne.IntersectRect( &rcAll, &rcOne ) )
00502 {
00503 dcDrag.BitBlt( rcOne.left - rcAll.left, rcOne.top - rcAll.top,
00504 rcOne.Width(), rcOne.Height(), &dcAll, rcOne.left, rcOne.top, SRCCOPY );
00505 }
00506 }
00507
00508 dcDrag.SelectObject( pOldDrag );
00509 dcAll.SelectObject( pOldAll );
00510
00511 dcDrag.DeleteDC();
00512 bmAll.DeleteObject();
00513 dcAll.DeleteDC();
00514
00515 CImageList* pAll = new CImageList();
00516 pAll->Create( rcAll.Width(), rcAll.Height(), ILC_COLOR16|ILC_MASK, 1, 1 );
00517 pAll->Add( &bmDrag, crDrag );
00518
00519 bmDrag.DeleteObject();
00520
00521 pAll->BeginDrag( 0, ptMouse - rcAll.TopLeft() );
00522
00523 return pAll;
00524 }