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

CtrlSearchDetailPanel.cpp

Go to the documentation of this file.
00001 //
00002 // CtrlSearchDetailPanel.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 "MatchObjects.h"
00026 #include "QueryHit.h"
00027 #include "Buffer.h"
00028 #include "XML.h"
00029 #include "Schema.h"
00030 #include "SchemaCache.h"
00031 #include "Library.h"
00032 #include "SHA.h"
00033 
00034 #include "CoolInterface.h"
00035 #include "ImageServices.h"
00036 #include "ImageFile.h"
00037 #include "RichElement.h"
00038 #include "ShellIcons.h"
00039 #include "Emoticons.h"
00040 #include "Skin.h"
00041 #include "CtrlSearchDetailPanel.h"
00042 
00043 #ifdef _DEBUG
00044 #define new DEBUG_NEW
00045 #undef THIS_FILE
00046 static char THIS_FILE[] = __FILE__;
00047 #endif
00048 
00049 IMPLEMENT_DYNAMIC(CSearchDetailPanel, CWnd)
00050 
00051 BEGIN_MESSAGE_MAP(CSearchDetailPanel, CWnd)
00052         //{{AFX_MSG_MAP(CSearchDetailPanel)
00053         ON_WM_CREATE()
00054         ON_WM_DESTROY()
00055         ON_WM_SIZE()
00056         ON_WM_VSCROLL()
00057         ON_WM_PAINT()
00058         ON_WM_SETCURSOR()
00059         ON_WM_LBUTTONUP()
00060         ON_WM_LBUTTONDOWN()
00061         ON_WM_MOUSEWHEEL()
00062         ON_WM_ERASEBKGND()
00063         ON_NOTIFY(RVN_CLICK, IDC_REVIEW_VIEW, OnClickReview)
00064         //}}AFX_MSG_MAP
00065 END_MESSAGE_MAP()
00066 
00067 #define SIZE_INTERNAL   1982
00068 
00069 
00071 // CSearchDetailPanel construction
00072 
00073 CSearchDetailPanel::CSearchDetailPanel()
00074 {
00075         m_pMatches      = NULL;
00076         m_bValid        = FALSE;
00077         m_pFile         = NULL;
00078         m_hThread       = NULL;
00079         m_bThread       = FALSE;
00080         m_crLight       =       CCoolInterface::CalculateColour(
00081                                         CoolInterface.m_crTipBack, RGB( 255, 255, 255 ), 128 );
00082         m_nThumbSize = 0;
00083 
00084         // Try to get the number of lines to scroll when the mouse wheel is rotated
00085         if( !SystemParametersInfo ( SPI_GETWHEELSCROLLLINES, 0, &m_nScrollWheelLines, 0) )
00086         {
00087                 m_nScrollWheelLines = 3;
00088         }
00089 }
00090 
00091 CSearchDetailPanel::~CSearchDetailPanel()
00092 {
00093         ClearReviews();
00094 }
00095 
00097 // CSearchDetailPanel operations
00098 
00099 BOOL CSearchDetailPanel::Create(CWnd* pParentWnd) 
00100 {
00101         CRect rect( 0, 0, 0, 0 );
00102         return CWnd::Create( NULL, NULL, WS_CHILD|WS_VSCROLL|WS_CLIPCHILDREN, rect, pParentWnd, IDC_DETAIL_PANEL, NULL );
00103 }
00104 
00105 void CSearchDetailPanel::Update(CMatchFile* pFile)
00106 {
00107         CSingleLock pLock( &m_pSection, TRUE );
00108         
00109         CancelPreview();
00110         ClearReviews();
00111         
00112         if ( pFile == NULL || ( pFile->m_pBest == NULL ) )
00113         {
00114                 if ( m_bValid )
00115                 {
00116                         m_bValid = FALSE;
00117                         OnSize( SIZE_INTERNAL, 0, 0 );
00118                 }
00119                 return;
00120         }
00121         
00122         m_pMatches      = pFile->m_pList;
00123         m_bValid        = TRUE;
00124         m_pFile         = pFile;
00125         m_pSHA1         = pFile->m_pSHA1;
00126         m_sName         = pFile->m_pBest->m_sName;
00127         m_sSize         = pFile->m_sSize;
00128         m_nIcon32       = ShellIcons.Get( pFile->m_pBest->m_sName, 32 );
00129         m_nIcon48       = ShellIcons.Get( pFile->m_pBest->m_sName, 48 );
00130         m_nRating       = pFile->m_nRated ? pFile->m_nRating / pFile->m_nRated : 0;
00131         
00132         m_bCanPreview   = FALSE;
00133         m_pSchema               = NULL;
00134         
00135         DWORD nSpeed = 0;
00136         
00137         for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
00138         {
00139                 if ( m_pSchema == NULL ) m_pSchema = SchemaCache.Get( pHit->m_sSchemaURI );
00140                 nSpeed += pHit->m_nSpeed;
00141                 
00142                 if ( pHit->m_bSHA1 && pHit->m_bPush == TS_FALSE )
00143                 {
00144                         if ( pHit->m_bPreview )
00145                         {
00146                                 m_pPreviewURLs.AddTail( pHit->m_sPreview );
00147                                 m_bCanPreview = TRUE;
00148                         }
00149 #ifdef _DEBUG
00150                         else if (       _tcsistr( pHit->m_sName, _T(".mpg") ) ||
00151                                                 _tcsistr( pHit->m_sName, _T(".mpeg") ) ||
00152                                                 _tcsistr( pHit->m_sName, _T(".avi") ) ||
00153                                                 _tcsistr( pHit->m_sName, _T(".jpg") ) ||
00154                                                 _tcsistr( pHit->m_sName, _T(".jpeg") ) )
00155                         {
00156                                 CString strURL;
00157                                 strURL.Format( _T("http://%s:%i/gnutella/preview/v1?%s"),
00158                                         (LPCTSTR)CString( inet_ntoa( pHit->m_pAddress ) ), pHit->m_nPort,
00159                                         (LPCTSTR)CSHA::HashToString( &pHit->m_pSHA1, TRUE ) );
00160                                 m_pPreviewURLs.AddTail( strURL );
00161                                 m_bCanPreview = TRUE;
00162                         }
00163 #endif
00164                 }
00165                 
00166                 if ( pHit->m_nRating > 0 || pHit->m_sComments.GetLength() > 0 )
00167                 {
00168                         m_pReviews.AddTail( new Review( &pHit->m_pClientID,
00169                                 &pHit->m_pAddress, pHit->m_sNick, pHit->m_nRating, pHit->m_sComments ) );
00170                 }
00171         }
00172         
00173         m_pMetadata.Setup( m_pSchema );
00174         
00175         if ( m_pSchema != NULL )
00176         {
00177                 for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
00178                 {
00179                         if ( pHit->m_pXML != NULL && m_pSchema->CheckURI( pHit->m_sSchemaURI ) )
00180                         {
00181                                 m_pMetadata.Combine( pHit->m_pXML );
00182                         }
00183                 }
00184         }
00185         
00186         m_pMetadata.Vote();
00187         m_pMetadata.CreateLinks();
00188         m_pMetadata.Clean( 4096 );
00189         
00190         if ( IsWindowVisible() )
00191         {
00192                 CString strFormat, strPart;
00193                 m_sStatus.Empty();
00194                 
00195                 if ( pFile->m_nSources == 1 )
00196                 {
00197                         LoadString( strFormat, IDS_SEARCH_DETAILS_SOURCES_ONE );
00198                         strPart.Format( strFormat, (LPCTSTR)Settings.SmartVolume( nSpeed, TRUE, TRUE ) );
00199                         m_sStatus += strPart;
00200                 }
00201                 else
00202                 {
00203                         if ( pFile->m_nSources == 0 ) nSpeed = 0;
00204                         LoadString( strFormat, IDS_SEARCH_DETAILS_SOURCES_MANY );
00205                         strPart.Format( strFormat, pFile->m_nSources, (LPCTSTR)Settings.SmartVolume( nSpeed, TRUE, TRUE ) );
00206                         m_sStatus += strPart;
00207                 }
00208                 
00209                 if ( m_pReviews.GetCount() > 1 )
00210                 {
00211                         LoadString( strFormat, IDS_SEARCH_DETAILS_REVIEWS_MANY );
00212                         strPart.Format( strFormat, m_pReviews.GetCount() );
00213                         m_sStatus += strPart;
00214                 }
00215                 else if ( m_pReviews.GetCount() == 1 )
00216                 {
00217                         LoadString( strPart, IDS_SEARCH_DETAILS_REVIEWS_ONE );
00218                         m_sStatus += strPart;
00219                 }
00220                 
00221                 if ( pFile->m_pPreview != NULL && pFile->m_nPreview > 0 )
00222                 {
00223                         CImageServices pServices;
00224                         CImageFile pImage( &pServices );
00225                         
00226                         if ( pImage.LoadFromMemory( _T(".jpg"), (LPCVOID)pFile->m_pPreview, pFile->m_nPreview, FALSE, TRUE ) )
00227                         {
00228                                 pLock.Unlock();
00229                                 OnPreviewLoaded( &m_pSHA1, &pImage );
00230                         }
00231                 }
00232                 
00233                 OnSize( SIZE_INTERNAL, 0, 0 );
00234         }
00235 }
00236 
00237 void CSearchDetailPanel::ClearReviews()
00238 {
00239         for ( POSITION pos = m_pReviews.GetHeadPosition() ; pos ; )
00240         {
00241                 delete (Review*)m_pReviews.GetNext( pos );
00242         }
00243         
00244         m_pReviews.RemoveAll();
00245 }
00246 
00248 // CSearchDetailPanel message handlers
00249 
00250 int CSearchDetailPanel::OnCreate(LPCREATESTRUCT lpCreateStruct) 
00251 {
00252         if ( CWnd::OnCreate( lpCreateStruct ) == -1 ) return -1;
00253         return 0;
00254 }
00255 
00256 void CSearchDetailPanel::OnDestroy() 
00257 {
00258         ClearReviews();
00259 
00260         m_bThread = FALSE;
00261         CancelPreview();
00262         
00263         if ( m_hThread != NULL )
00264         {
00265                 m_pWakeup.SetEvent();
00266                 
00267         int nAttempt = 10;
00268                 for ( ; nAttempt > 0 ; nAttempt-- )
00269                 {
00270                         DWORD nCode;
00271                         if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
00272                         if ( nCode != STILL_ACTIVE ) break;
00273                         Sleep( 100 );
00274                 }
00275                 
00276                 if ( nAttempt == 0 )
00277                 {
00278                         TerminateThread( m_hThread, 0 );
00279                         theApp.Message( MSG_DEBUG, _T("WARNING: Terminating CSearchDetailPanel thread.") );
00280                         Sleep( 100 );
00281                 }
00282                 
00283                 m_hThread = NULL;
00284         }
00285         
00286         CWnd::OnDestroy();
00287 }
00288 
00289 void CSearchDetailPanel::OnSize(UINT nType, int cx, int cy) 
00290 {
00291         if ( nType != SIZE_INTERNAL ) CWnd::OnSize( nType, cx, cy );
00292         
00293         SCROLLINFO pInfo;
00294         CRect rc;
00295         
00296         GetWindowRect( &rc );
00297         rc.OffsetRect( -rc.left, -rc.top );
00298         rc.right -= GetSystemMetrics( SM_CXVSCROLL );
00299         
00300         int nThumbSize = rc.Height() - 16;
00301         nThumbSize = max( nThumbSize, 64 );
00302         nThumbSize = min( nThumbSize, 128 );
00303         rc.left += nThumbSize + 16;
00304         rc.right -= 8;
00305         
00306         CClientDC dc( this );
00307         int nHeight = 54 + m_pMetadata.Layout( &dc, rc.Width() );
00308         
00309         for ( POSITION pos = m_pReviews.GetHeadPosition() ; pos ; )
00310         {
00311                 Review* pReview = (Review*)m_pReviews.GetNext( pos );
00312                 CRect rcReview( rc.left, nHeight, rc.right, nHeight );
00313                 pReview->Layout( this, &rcReview );
00314                 nHeight += rcReview.Height();
00315         }
00316         
00317         if ( ! m_bValid ) nHeight = 0;
00318         
00319         pInfo.cbSize    = sizeof(pInfo);
00320         pInfo.fMask             = SIF_ALL & ~SIF_TRACKPOS;
00321         pInfo.nMin              = 0;
00322         pInfo.nMax              = nHeight;
00323         pInfo.nPage             = rc.Height();
00324         pInfo.nPos              = 0;
00325         pInfo.nPos              = max( 0, min( pInfo.nPos, pInfo.nMax - (int)pInfo.nPage + 1 ) );
00326         
00327         SetScrollInfo( SB_VERT, &pInfo, TRUE );
00328         
00329         Invalidate();
00330 }
00331 
00332 void CSearchDetailPanel::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
00333 {
00334         SCROLLINFO pScroll;
00335         
00336         ZeroMemory( &pScroll, sizeof(pScroll) );
00337         pScroll.cbSize  = sizeof(pScroll);
00338         pScroll.fMask   = SIF_ALL;
00339         
00340         GetScrollInfo( SB_VERT, &pScroll );
00341         
00342         switch ( nSBCode )
00343         {
00344         case SB_TOP:
00345                 pScroll.nPos = 0;
00346                 break;
00347         case SB_BOTTOM:
00348                 pScroll.nPos = pScroll.nMax - 1;
00349                 break;
00350         case SB_LINEUP:
00351                 pScroll.nPos -= 8;
00352                 break;
00353         case SB_LINEDOWN:
00354                 pScroll.nPos += 8;
00355                 break;
00356         case SB_PAGEUP:
00357                 pScroll.nPos -= pScroll.nPage;
00358                 break;
00359         case SB_PAGEDOWN:
00360                 pScroll.nPos += pScroll.nPage;
00361                 break;
00362         case SB_THUMBPOSITION:
00363         case SB_THUMBTRACK:
00364                 pScroll.nPos = nPos;
00365                 break;
00366         }
00367         
00368         pScroll.fMask   = SIF_POS;
00369         pScroll.nPos    = max( 0, min( pScroll.nPos, pScroll.nMax ) );
00370         
00371         SetScrollInfo( SB_VERT, &pScroll );
00372 
00373         for ( POSITION pos = m_pReviews.GetHeadPosition() ; pos ; )
00374         {
00375                 Review* pReview = (Review*)m_pReviews.GetNext( pos );
00376                 pReview->Reposition( pScroll.nPos );
00377         }
00378         
00379         Invalidate();
00380 }
00381 
00382 void CSearchDetailPanel::OnLButtonDown(UINT nFlags, CPoint point)
00383 {
00384         SetFocus();
00385 }
00386 
00387 BOOL CSearchDetailPanel::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
00388 {
00389         OnVScroll( SB_THUMBPOSITION, (int)( GetScrollPos( SB_VERT ) - zDelta / WHEEL_DELTA * m_nScrollWheelLines * 8 ), NULL );
00390         return TRUE;
00391 }
00392 
00393 BOOL CSearchDetailPanel::OnEraseBkgnd(CDC* pDC) 
00394 {
00395         return TRUE;
00396 }
00397 
00398 void CSearchDetailPanel::OnPaint() 
00399 {
00400         CSingleLock pLock( &m_pSection, TRUE );
00401         CPaintDC dc( this );
00402         CRect rcClient;
00403         CString str;
00404         
00405         GetClientRect( &rcClient );
00406         
00407         CFont* pOldFont = dc.GetCurrentFont();
00408         dc.SetBkColor( CoolInterface.m_crWindow );
00409         dc.SetBkMode( OPAQUE );
00410         dc.SetTextColor( CoolInterface.m_crText );
00411         
00412         if ( ! m_bValid )
00413         {
00414                 dc.SelectObject( &CoolInterface.m_fntNormal );
00415                 LoadString( str, IDS_SEARCH_DETAILS_EMPTY );
00416                 CSize sz = dc.GetTextExtent( str );
00417                 CPoint pt = rcClient.CenterPoint();
00418                 pt.x -= sz.cx / 2; pt.y -= sz.cy / 2;
00419                 dc.ExtTextOut( pt.x, pt.y, ETO_OPAQUE, &rcClient, str, NULL );
00420                 dc.SelectObject( pOldFont );
00421                 return;
00422         }
00423         
00424         CRect rcWork( 0, 0, 0, 0 );
00425         DrawThumbnail( &dc, rcClient, rcWork );
00426         
00427         dc.SetViewportOrg( 0, -GetScrollPos( SB_VERT ) );
00428         
00429         dc.SetBkColor( CoolInterface.m_crWindow );
00430         dc.SetTextColor( CoolInterface.m_crText );
00431         
00432         dc.SelectObject( &CoolInterface.m_fntCaption );
00433         DrawText( &dc, rcWork.left, rcWork.top, m_sName );
00434         
00435         CPoint ptStar( rcWork.right - 3, rcWork.top - 2 );
00436         
00437         if ( m_nRating > 1 )
00438         {
00439                 for ( int nRating = m_nRating - 1 ; nRating ; nRating-- )
00440                 {
00441                         ptStar.x -= 16;
00442                         ShellIcons.Draw( &dc, SHI_STAR, 16, ptStar.x, ptStar.y, CoolInterface.m_crWindow );
00443                 }
00444         }
00445         else if ( m_nRating == 1 )
00446         {
00447                 ptStar.x -= 16;
00448                 ShellIcons.Draw( &dc, SHI_FAKE, 16, ptStar.x, ptStar.y, CoolInterface.m_crWindow );
00449         }
00450         
00451         rcWork.top += 20;
00452         
00453         dc.FillSolidRect( rcWork.left, rcWork.top, rcWork.Width(), 1, CoolInterface.m_crMargin );
00454         dc.ExcludeClipRect( rcWork.left, rcWork.top, rcWork.right, rcWork.top + 1 );
00455         dc.SetBkColor( CoolInterface.m_crWindow );
00456         rcWork.top += 4;
00457         
00458         dc.SelectObject( &CoolInterface.m_fntBold );
00459         LoadString( str, IDS_TIP_SIZE );
00460         DrawText( &dc, rcWork.right - 125, rcWork.top, str + ':' );
00461         dc.SelectObject( &CoolInterface.m_fntNormal );
00462         DrawText( &dc, rcWork.right - 60, rcWork.top, m_sSize );
00463         if ( m_pReviews.GetCount() )
00464         {
00465                 dc.SelectObject( &CoolInterface.m_fntUnder );
00466                 dc.SetTextColor( RGB( 0, 0, 255 ) );
00467         }
00468         DrawText( &dc, rcWork.left, rcWork.top, m_sStatus, &m_rcStatus );
00469         rcWork.top += 18;
00470         
00471         m_pMetadata.Paint( &dc, &rcWork );
00472         
00473         dc.SetViewportOrg( 0, 0 );
00474         dc.SelectObject( &CoolInterface.m_fntCaption );
00475         dc.SetBkColor( CoolInterface.m_crWindow );
00476         dc.SetTextColor( 0 );
00477         
00478         for ( POSITION pos = m_pReviews.GetHeadPosition() ; pos ; )
00479         {
00480                 Review* pReview = (Review*)m_pReviews.GetNext( pos );
00481                 pReview->Paint( &dc, GetScrollPos( SB_VERT ) );
00482         }
00483         
00484         dc.SelectObject( pOldFont );
00485         dc.FillSolidRect( &rcClient, CoolInterface.m_crWindow );
00486 }
00487 
00488 void CSearchDetailPanel::DrawText(CDC* pDC, int nX, int nY, LPCTSTR pszText, RECT* pRect)
00489 {
00490         CSize sz = pDC->GetTextExtent( pszText, _tcslen( pszText ) );
00491         CRect rc( nX - 2, nY - 2, nX + sz.cx + 2, nY + sz.cy + 2 );
00492         
00493         pDC->ExtTextOut( nX, nY, ETO_CLIPPED|ETO_OPAQUE, &rc, pszText, _tcslen( pszText ), NULL );
00494         pDC->ExcludeClipRect( &rc );
00495         
00496         if ( pRect != NULL ) CopyMemory( pRect, &rc, sizeof(RECT) );
00497 }
00498 
00499 void CSearchDetailPanel::DrawThumbnail(CDC* pDC, CRect& rcClient, CRect& rcWork)
00500 {
00501         int nThumbSize = rcClient.Height() - 16;
00502         nThumbSize = max( nThumbSize, 64 );
00503         nThumbSize = min( nThumbSize, 128 );
00504         
00505         CRect rcThumb( rcClient.left + 8, rcClient.top + 8,
00506                 rcClient.left + 8 + nThumbSize, rcClient.top + 8 + nThumbSize );
00507         
00508         rcWork.CopyRect( &rcThumb );
00509         
00510         pDC->Draw3dRect( &rcWork, CoolInterface.m_crMargin, CoolInterface.m_crMargin );
00511         rcWork.DeflateRect( 1, 1 );
00512         m_nThumbSize = rcWork.Width();
00513         
00514         DrawThumbnail( pDC, rcWork );
00515         
00516         pDC->ExcludeClipRect( &rcThumb );
00517         
00518         rcWork.SetRect( rcThumb.right + 8, rcThumb.top, rcClient.right - 8, rcClient.bottom );
00519 }
00520 
00521 void CSearchDetailPanel::DrawThumbnail(CDC* pDC, CRect& rcThumb)
00522 {
00523         m_rcThumb = rcThumb;
00524         
00525         if ( m_bmThumb.m_hObject != NULL &&
00526                  m_szThumb.cx != m_nThumbSize && m_szThumb.cy != m_nThumbSize )
00527         {
00528                 CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
00529                 
00530                 if ( m_pMatches->FileToItem( m_pFile ) < 0xFFFFFFFF )
00531                 {
00532                         if ( m_pFile->m_pPreview != NULL && m_pFile->m_nPreview > 0 )
00533                         {
00534                                 CImageServices pServices;
00535                                 CImageFile pImage( &pServices );
00536                                 
00537                                 if ( pImage.LoadFromMemory( _T(".jpg"), (LPCVOID)m_pFile->m_pPreview, m_pFile->m_nPreview, FALSE, TRUE ) )
00538                                 {
00539                                         pLock.Unlock();
00540                                         OnPreviewLoaded( &m_pSHA1, &pImage );
00541                                 }
00542                         }
00543                 }
00544         }
00545         
00546         if ( m_bmThumb.m_hObject &&
00547                         ( m_szThumb.cx == m_nThumbSize || m_szThumb.cy == m_nThumbSize ) )
00548         {
00549                 CDC dcMem;
00550                 dcMem.CreateCompatibleDC( pDC );
00551                 
00552                 CBitmap* pOld = (CBitmap*)dcMem.SelectObject( &m_bmThumb );
00553                 
00554                 CPoint ptImage( ( rcThumb.left + rcThumb.right ) / 2 - m_szThumb.cx / 2,
00555                                                 ( rcThumb.top + rcThumb.bottom ) / 2 - m_szThumb.cy / 2 );
00556                 
00557                 pDC->BitBlt( ptImage.x, ptImage.y, m_szThumb.cx, m_szThumb.cy,
00558                         &dcMem, 0, 0, SRCCOPY );
00559                 pDC->ExcludeClipRect( ptImage.x, ptImage.y,
00560                         ptImage.x + m_szThumb.cx, ptImage.y + m_szThumb.cy );
00561                 
00562                 dcMem.SelectObject( pOld );
00563                 
00564                 pDC->FillSolidRect( &rcThumb, m_crLight );
00565         }
00566         else
00567         {
00568                 CPoint pt(      ( rcThumb.left + rcThumb.right ) / 2 - 24,
00569                                         ( rcThumb.top + rcThumb.bottom ) / 2 - 24 );
00570                 
00571                 if ( m_bCanPreview )
00572                 {
00573                         CString str;
00574                         LoadString( str, m_bIsPreviewing ? IDS_SEARCH_DETAILS_PREVIEWING : IDS_SEARCH_DETAILS_PREVIEW );
00575                         
00576                         pDC->SetBkColor( m_crLight );
00577                         pDC->SetTextColor( m_bIsPreviewing ? RGB( 255, 0, 0 ) : RGB( 0, 0, 255 ) );
00578                         pDC->SelectObject( m_bIsPreviewing ? &theApp.m_gdiFontBold : &theApp.m_gdiFontLine );
00579                         
00580                         CSize sz = pDC->GetTextExtent( str );
00581                         
00582                         if ( sz.cx + 4 < rcThumb.Width() )
00583                         {
00584                                 pt.y -= sz.cy / 2;
00585                                 CPoint ptText(
00586                                         ( rcThumb.left + rcThumb.right ) / 2 - sz.cx / 2,
00587                                         pt.y + 50 );
00588                                 DrawText( pDC, ptText.x, ptText.y, str );
00589                         }
00590                         else
00591                         {
00592                                 // split text to two lines and try to draw
00593                                 int nLength = str.GetLength();
00594                                 int nSpace = str.Find( ' ', nLength / 2 - 1 );
00595                                 CString strFirstHalf = str.Left( nSpace );
00596                                 str = str.Right( nLength - nSpace - 1 );
00597                                 sz = pDC->GetTextExtent( strFirstHalf );
00598 
00599                                 if ( sz.cx + 4 < rcThumb.Width() && pt.y + 50 < rcThumb.Height() )
00600                                 {
00601                                         pt.y -= sz.cy / 2;
00602                                         CPoint ptText(
00603                                                 ( rcThumb.left + rcThumb.right ) / 2 - sz.cx / 2,
00604                                                 pt.y + 50 );
00605                                         DrawText( pDC, ptText.x, ptText.y, strFirstHalf );
00606                                         CSize sz2 = pDC->GetTextExtent( str );
00607 
00608                                         if ( sz2.cx + 4 < rcThumb.Width() && 
00609                                                  pt.y + sz2.cy + 57 < rcThumb.Height() )
00610                                         {
00611                                                 pt.y -= sz2.cy / 2;
00612                                                 CPoint ptText(
00613                                                         ( rcThumb.left + rcThumb.right ) / 2 - sz2.cx / 2,
00614                                                         pt.y + sz.cy + 57 );
00615                                                 DrawText( pDC, ptText.x, ptText.y, str );                                               
00616                                         }
00617                                         else
00618                                                 // append ellipsis if the second half does not fit
00619                                                 DrawText( pDC, ptText.x + sz.cx + 1, ptText.y, _T("\x2026") );
00620                                 }
00621                         }
00622                 }
00623                 
00624                 if ( m_nIcon48 >= 0 )
00625                 {
00626                         ShellIcons.Draw( pDC, m_nIcon48, 48, pt.x, pt.y, m_crLight );
00627                 }
00628                 else if ( m_nIcon32 >= 0 )
00629                 {
00630                         pt.x += 8; pt.y += 8;
00631                         ShellIcons.Draw( pDC, m_nIcon32, 32, pt.x, pt.y, m_crLight );
00632                 }
00633                 
00634                 pDC->FillSolidRect( &rcThumb, m_crLight );
00635         }
00636 }
00637 
00638 BOOL CSearchDetailPanel::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
00639 {
00640         CPoint point;
00641         
00642         GetCursorPos( &point );
00643         ScreenToClient( &point );
00644         
00645         if ( m_bValid && m_bCanPreview && ! m_bIsPreviewing && m_rcThumb.PtInRect( point ) )
00646         {
00647                 SetCursor( AfxGetApp()->LoadCursor( IDC_HAND ) );
00648                 return TRUE;
00649         }
00650         
00651         point.y += GetScrollPos( SB_VERT );
00652         
00653         if ( m_bValid && m_pReviews.GetCount() > 0 && m_rcStatus.PtInRect( point ) )
00654         {
00655                 SetCursor( AfxGetApp()->LoadCursor( IDC_HAND ) );
00656                 return TRUE;
00657         }
00658         
00659         if ( m_bValid && m_pMetadata.HitTest( point, TRUE ) != NULL )
00660         {
00661                 SetCursor( AfxGetApp()->LoadCursor( IDC_HAND ) );
00662                 return TRUE;
00663         }
00664         
00665         return CWnd::OnSetCursor( pWnd, nHitTest, message );
00666 }
00667 
00668 void CSearchDetailPanel::OnLButtonUp(UINT nFlags, CPoint point) 
00669 {
00670         if ( m_bValid && m_bCanPreview && ! m_bIsPreviewing && m_rcThumb.PtInRect( point ) )
00671         {
00672                 RequestPreview();
00673         }
00674         
00675         point.y += GetScrollPos( SB_VERT );
00676         
00677         if ( m_bValid && m_pReviews.GetCount() > 0 && m_rcStatus.PtInRect( point ) )
00678         {
00679                 int nHeight = 54 + m_pMetadata.m_nHeight;
00680                 SetScrollPos( SB_VERT, nHeight );
00681                 OnVScroll( SB_THUMBPOSITION, nHeight, NULL );
00682                 Invalidate();
00683         }
00684         
00685         m_pMetadata.OnClick( point );
00686         
00687         CWnd::OnLButtonUp( nFlags, point );
00688 }
00689 
00691 // CSearchDetailPanel::Review construction
00692 
00693 CSearchDetailPanel::Review::Review(GGUID* pGUID, IN_ADDR* pAddress, LPCTSTR pszNick, int nRating, LPCTSTR pszComments)
00694 {
00695         m_pGUID         = *pGUID;
00696         m_nRating       = nRating;
00697         
00698         if ( pszNick != NULL && *pszNick != 0 )
00699         {
00700                 m_sNick.Format( _T("%s (%s)"), pszNick,
00701                         (LPCTSTR)CString( inet_ntoa( *pAddress ) ) );
00702         }
00703         else
00704         {
00705                 m_sNick = inet_ntoa( *pAddress );
00706         }
00707         
00708         if ( pszComments != NULL )
00709         {
00710                 m_pComments.m_szMargin = CSize( 6, 0 );
00711                 Emoticons.FormatText( &m_pComments, pszComments, TRUE );
00712         }
00713 }
00714 
00715 CSearchDetailPanel::Review::~Review()
00716 {
00717         if ( m_wndComments.m_hWnd != NULL ) m_wndComments.DestroyWindow();
00718 }
00719 
00720 void CSearchDetailPanel::Review::Layout(CSearchDetailPanel* pParent, CRect* pRect)
00721 {
00722         pRect->bottom += 22;
00723         
00724         if ( m_pComments.GetCount() )
00725         {
00726                 if ( m_wndComments.m_hWnd == NULL )
00727                 {
00728                         m_wndComments.Create( WS_CHILD, *pRect, pParent, IDC_REVIEW_VIEW );
00729                         m_wndComments.SetSelectable( TRUE );
00730                         m_wndComments.SetDocument( &m_pComments );
00731                 }
00732                 
00733                 pRect->bottom += m_wndComments.FullHeightMove( pRect->left, pRect->bottom, pRect->Width(), TRUE );
00734                 pRect->bottom += 4;
00735         }
00736         else
00737         {
00738                 pRect->bottom += 2;
00739         }
00740         
00741         m_rc.CopyRect( pRect );
00742 }
00743 
00744 void CSearchDetailPanel::Review::Reposition(int nScroll)
00745 {
00746         if ( m_wndComments.m_hWnd != NULL )
00747         {
00748                 m_wndComments.SetWindowPos( NULL, m_rc.left, m_rc.top - nScroll + 22, 0, 0,
00749                         SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE );
00750         }
00751 }
00752 
00753 void CSearchDetailPanel::Review::Paint(CDC* pDC, int nScroll)
00754 {
00755         CRect rc( &m_rc );
00756         rc.OffsetRect( 0, -nScroll );
00757         
00758         pDC->FillSolidRect( rc.left, rc.top, rc.Width(), 1, CoolInterface.m_crMargin );
00759         pDC->ExcludeClipRect( rc.left, rc.top, rc.right, rc.top + 1 );
00760         rc.top += 4;
00761         
00762         CString strFormat, strCaption;
00763         
00764         LoadString( strFormat, m_pComments.GetCount() > 0 ? IDS_SEARCH_DETAILS_WRITES : IDS_SEARCH_DETAILS_RATES );
00765         strCaption.Format( strFormat, (LPCTSTR)m_sNick );
00766         
00767         pDC->SetBkColor( CoolInterface.m_crWindow );
00768         DrawText( pDC, rc.left, rc.top, strCaption );
00769         
00770         CPoint ptStar( rc.right - 3, rc.top );
00771         
00772         if ( m_nRating > 1 )
00773         {
00774                 for ( int nRating = m_nRating - 1 ; nRating ; nRating-- )
00775                 {
00776                         ptStar.x -= 16;
00777                         ShellIcons.Draw( pDC, SHI_STAR, 16, ptStar.x, ptStar.y, CoolInterface.m_crWindow );
00778                 }
00779         }
00780         else if ( m_nRating == 1 )
00781         {
00782                 ptStar.x -= 16;
00783                 ShellIcons.Draw( pDC, SHI_FAKE, 16, ptStar.x, ptStar.y, CoolInterface.m_crWindow );
00784         }
00785         
00786         rc.top += 20;
00787 }
00788 
00789 void CSearchDetailPanel::OnClickReview(RVN_ELEMENTEVENT* pNotify, LRESULT *pResult)
00790 {
00791         if ( CRichElement* pElement = pNotify->pElement )
00792         {
00793                 theApp.InternalURI( pElement->m_sLink );
00794         }
00795 }
00796 
00798 // CSearchDetailPanel previewing functionality
00799 
00800 BOOL CSearchDetailPanel::RequestPreview()
00801 {
00802         CSingleLock pLock( &m_pSection, TRUE );
00803         
00804         if ( ! m_bValid || ! m_bCanPreview || m_pPreviewURLs.IsEmpty() ) return FALSE;
00805         
00806         if ( m_hThread == NULL )
00807         {
00808                 m_bThread = TRUE;
00809                 CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_IDLE );
00810                 m_hThread = pThread->m_hThread;
00811         }
00812         
00813         m_bRunPreview = TRUE;
00814         
00815         pLock.Unlock();
00816         
00817         m_pWakeup.SetEvent();
00818         
00819         return TRUE;
00820 }
00821 
00822 void CSearchDetailPanel::CancelPreview()
00823 {
00824         CSingleLock pLock( &m_pSection, TRUE );
00825         
00826         m_bRunPreview = FALSE;
00827         m_pPreviewURLs.RemoveAll();
00828         
00829         if ( m_bmThumb.m_hObject != NULL )
00830         {
00831                 m_bmThumb.DeleteObject();
00832                 Invalidate();
00833         }
00834         
00835         if ( m_bIsPreviewing )
00836         {
00837                 m_bIsPreviewing = FALSE;
00838                 Invalidate();
00839         }
00840         
00841         m_pRequest.Cancel();
00842 }
00843 
00844 UINT CSearchDetailPanel::ThreadStart(LPVOID pParam)
00845 {
00846         CSearchDetailPanel* pPanel = (CSearchDetailPanel*)pParam;
00847         pPanel->OnRun();
00848         return 0;
00849 }
00850 
00851 void CSearchDetailPanel::OnRun()
00852 {
00853         CSingleLock pLock( &m_pSection );
00854         CImageServices pServices;
00855         
00856         while ( m_bThread )
00857         {
00858                 pLock.Lock();
00859                 
00860                 if ( ! m_bValid || ! m_bRunPreview || m_pPreviewURLs.IsEmpty() )
00861                 {
00862                         if ( m_bIsPreviewing )
00863                         {
00864                                 m_bIsPreviewing = FALSE;
00865                                 Invalidate();
00866                         }
00867                         
00868                         pLock.Unlock();
00869                         WaitForSingleObject( m_pWakeup, INFINITE );
00870                         
00871                         continue;
00872                 }
00873                 
00874                 CString strURL  = m_pPreviewURLs.RemoveHead();
00875                 SHA1 pSHA1              = m_pSHA1;
00876                 
00877                 if ( ! m_bIsPreviewing )
00878                 {
00879                         m_bIsPreviewing = TRUE;
00880                         Invalidate();
00881                 }
00882                 
00883                 pLock.Unlock();
00884                 
00885                 BYTE* pBuffer;
00886                 DWORD nBuffer;
00887                 
00888                 if ( ExecuteRequest( strURL, &pBuffer, &nBuffer ) )
00889                 {
00890                         CImageFile pImage( &pServices );
00891                         
00892                         if ( pImage.LoadFromMemory( _T(".jpg"), (LPCVOID)pBuffer, nBuffer, FALSE, TRUE ) )
00893                         {
00894                                 OnPreviewLoaded( &pSHA1, &pImage );
00895                                 CachePreviewImage( &pSHA1, pBuffer, nBuffer );
00896                         }
00897                         else
00898                         {
00899                                 theApp.Message( MSG_ERROR, IDS_SEARCH_DETAILS_PREVIEW_FAILED, (LPCTSTR)strURL );
00900                         }
00901                         
00902                         free( pBuffer );
00903                 }
00904                 else
00905                 {
00906                         theApp.Message( MSG_ERROR, IDS_SEARCH_DETAILS_PREVIEW_FAILED, (LPCTSTR)strURL );
00907                 }
00908         }
00909 }
00910 
00911 BOOL CSearchDetailPanel::ExecuteRequest(CString strURL, BYTE** ppBuffer, DWORD* pnBuffer)
00912 {
00913         m_pRequest.Clear();
00914         m_pRequest.SetURL( strURL );
00915         m_pRequest.AddHeader( _T("Accept"), _T("image/jpeg") );
00916         m_pRequest.LimitContentLength( Settings.Search.MaxPreviewLength );
00917         
00918         if ( ! m_pRequest.Execute( FALSE ) )
00919         {
00920                 theApp.Message( MSG_DEBUG, _T("Preview failed: unable to execute request.") );
00921                 return FALSE;
00922         }
00923         
00924         int nCode = m_pRequest.GetStatusCode();
00925         
00926         if ( m_pRequest.GetStatusSuccess() == FALSE )
00927         {
00928                 theApp.Message( MSG_DEBUG, _T("Preview failed: HTTP status code %i"),
00929                         m_pRequest.GetStatusCode() );
00930                 return FALSE;
00931         }
00932         
00933         CString strURN = m_pRequest.GetHeader( _T("X-Previewed-URN") );
00934         
00935         if ( strURN.GetLength() )
00936         {
00937                 SHA1 pSHA1;
00938                 
00939                 if ( CSHA::HashFromURN( strURN, &pSHA1 ) && pSHA1 != m_pSHA1 )
00940                 {
00941                         theApp.Message( MSG_DEBUG, _T("Preview failed: wrong URN.") );
00942                         return FALSE;
00943                 }
00944         }
00945         
00946         CString strMIME = m_pRequest.GetHeader( _T("Content-Type") );
00947         
00948         if ( strMIME.CompareNoCase( _T("image/jpeg") ) != 0 )
00949         {
00950                 theApp.Message( MSG_DEBUG, _T("Preview failed: unacceptable content type.") );
00951                 return FALSE;
00952         }
00953         
00954         CBuffer* pBuffer = m_pRequest.GetResponseBuffer();
00955         if ( pBuffer == NULL ) return FALSE;
00956         
00957         *pnBuffer = pBuffer->m_nLength;
00958         *ppBuffer = (BYTE*)malloc( *pnBuffer );
00959         CopyMemory( *ppBuffer, pBuffer->m_pBuffer, *pnBuffer );
00960         
00961         return TRUE;
00962 }
00963 
00964 void CSearchDetailPanel::OnPreviewLoaded(SHA1* pSHA1, CImageFile* pImage)
00965 {
00966         if ( m_nThumbSize == 0 ) return;
00967         
00968         int nSize = m_nThumbSize * pImage->m_nWidth / pImage->m_nHeight;
00969         
00970         if ( nSize > m_nThumbSize )
00971         {
00972                 nSize = m_nThumbSize * pImage->m_nHeight / pImage->m_nWidth;
00973                 pImage->Resample( m_nThumbSize, nSize );
00974         }
00975         else
00976         {
00977                 pImage->Resample( nSize, m_nThumbSize );
00978         }
00979         
00980         CSingleLock pLock( &m_pSection, TRUE );
00981         
00982         if ( m_pSHA1 != *pSHA1 ) return;
00983         
00984         m_bCanPreview = m_bRunPreview = m_bIsPreviewing = FALSE;
00985         
00986         if ( m_bmThumb.m_hObject ) m_bmThumb.DeleteObject();
00987         
00988         m_bmThumb.Attach( pImage->CreateBitmap() );
00989         m_szThumb.cx = pImage->m_nWidth;
00990         m_szThumb.cy = pImage->m_nHeight;
00991         
00992         pLock.Unlock();
00993         Invalidate();
00994 }
00995 
00996 BOOL CSearchDetailPanel::CachePreviewImage(SHA1* pSHA1, LPBYTE pBuffer, DWORD nBuffer)
00997 {
00998         CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
00999         
01000         if ( m_pMatches->FileToItem( m_pFile ) != 0xFFFFFFFF )
01001         {
01002                 if ( m_pFile->m_pPreview != NULL ) delete [] m_pFile->m_pPreview;
01003                 
01004                 m_pFile->m_nPreview = nBuffer;
01005                 m_pFile->m_pPreview = new BYTE[ nBuffer ];
01006                 CopyMemory( m_pFile->m_pPreview, pBuffer, nBuffer );
01007                 
01008                 return TRUE;
01009         }
01010         
01011         return FALSE;
01012 }
01013 

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