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

LiveList.cpp

Go to the documentation of this file.
00001 //
00002 // LiveList.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 "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 // CLiveList construction
00036 
00037 CLiveList::CLiveList(int nColumns)
00038 {
00039         m_nColumns = nColumns;
00040 }
00041 
00042 CLiveList::~CLiveList()
00043 {
00044         Clear();
00045 }
00046 
00048 // CLiveList clear
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 // CLiveList add
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 // CLiveList apply
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 // CLiveItem construction
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 // CLiveItem set
00143 
00144 void CLiveItem::Set(int nColumn, LPCTSTR pszText)
00145 {
00146         m_pColumn[ nColumn ] = pszText;
00147 }
00148 
00150 // CLiveItem format
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 // CLiveItem add
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 // CLiveItem update
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 // CLiveList sort method
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 // CLiveList sort callback
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         // TODO: Is this the best way to do this?
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                         // if ( bSpace ) return FALSE;
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                         // Allows ###k and ###k~
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 // CLiveList dragging helper
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 }

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