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 "Settings.h"
00025 #include "Emoticons.h"
00026 #include "ImageServices.h"
00027 #include "ImageFile.h"
00028 #include "XML.h"
00029
00030 #include "RichDocument.h"
00031 #include "RichElement.h"
00032
00033 #ifdef _DEBUG
00034 #undef THIS_FILE
00035 static char THIS_FILE[]=__FILE__;
00036 #define new DEBUG_NEW
00037 #endif
00038
00039 CEmoticons Emoticons;
00040
00041
00043
00044
00045 CEmoticons::CEmoticons()
00046 {
00047 m_pTokens = NULL;
00048 }
00049
00050 CEmoticons::~CEmoticons()
00051 {
00052 Clear();
00053 }
00054
00056
00057
00058 LPCTSTR CEmoticons::FindNext(LPCTSTR pszText, int* pnIndex)
00059 {
00060 LPCTSTR pszBest = NULL;
00061 int nIndex = 0, nBest;
00062
00063 if ( m_pTokens == NULL ) return NULL;
00064
00065 for ( LPCTSTR pszToken = m_pTokens ; *pszToken ; nIndex++ )
00066 {
00067 LPCTSTR pszFind = _tcsstr( pszText, pszToken );
00068
00069 if ( pszFind != NULL && ( pszBest == NULL || pszFind < pszBest ||
00070 ( pszFind == pszBest && _tcslen( GetText( nBest ) ) < _tcslen( pszToken ) ) ) )
00071 {
00072 pszBest = pszFind;
00073 nBest = nIndex;
00074 }
00075
00076 pszToken += _tcslen( pszToken ) + 1;
00077 }
00078
00079 if ( pszBest && pnIndex ) *pnIndex = nBest;
00080
00081 return pszBest;
00082 }
00083
00085
00086
00087 int CEmoticons::Lookup(LPCTSTR pszText, int nLen) const
00088 {
00089 TCHAR cSave = 0;
00090 int nIndex = 0;
00091
00092 if ( m_pTokens == NULL ) return -1;
00093
00094 if ( nLen >= 0 )
00095 {
00096 cSave = pszText[ nLen ];
00097 ((LPTSTR)pszText)[ nLen ] = 0;
00098 }
00099
00100 LPCTSTR pszToken = m_pTokens;
00101 for ( ; *pszToken ; nIndex++ )
00102 {
00103 if ( _tcscmp( pszToken, pszText ) == 0 )
00104 {
00105 break;
00106 }
00107
00108 pszToken += _tcslen( pszToken ) + 1;
00109 }
00110
00111 if ( nLen >= 0 ) ((LPTSTR)pszText)[ nLen ] = cSave;
00112
00113 return ( *pszToken != 0 ) ? nIndex : -1;
00114 }
00115
00117
00118
00119 LPCTSTR CEmoticons::GetText(int nIndex) const
00120 {
00121 if ( m_pTokens == NULL ) return NULL;
00122
00123 for ( LPCTSTR pszToken = m_pTokens ; *pszToken ; )
00124 {
00125 if ( nIndex-- <= 0 ) return pszToken;
00126
00127 pszToken += _tcslen( pszToken ) + 1;
00128 }
00129
00130 return NULL;
00131 }
00132
00134
00135
00136 void CEmoticons::Draw(CDC* pDC, int nIndex, int nX, int nY, COLORREF crBack)
00137 {
00138 if ( m_pTokens == NULL ) return;
00139 ImageList_DrawEx( m_pImage.m_hImageList, nIndex, pDC->GetSafeHdc(),
00140 nX, nY, 16, 16, crBack, CLR_DEFAULT, ILD_NORMAL );
00141
00142 }
00143
00145
00146
00147 CMenu* CEmoticons::CreateMenu()
00148 {
00149 CMenu* pMenu = new CMenu();
00150 pMenu->CreatePopupMenu();
00151
00152 int nCount = 0;
00153
00154 for ( int nPos = 0 ; nPos < m_pButtons.GetSize() ; nPos++ )
00155 {
00156 int nIndex = m_pButtons.GetAt( nPos );
00157
00158 if ( nCount > 0 && ( nCount % 12 ) == 0 )
00159 {
00160 pMenu->AppendMenu( MF_OWNERDRAW|MF_MENUBREAK, nIndex + 1, (LPCTSTR)NULL );
00161 }
00162 else
00163 {
00164 pMenu->AppendMenu( MF_OWNERDRAW, nIndex + 1, (LPCTSTR)NULL );
00165 }
00166
00167 nCount++;
00168 }
00169
00170 return pMenu;
00171 }
00172
00174
00175
00176 BOOL CEmoticons::Load()
00177 {
00178 Clear();
00179 m_pImage.Create( 16, 16, ILC_COLOR32|ILC_MASK, 1, 8 );
00180
00181 CString strFile = Settings.General.Path + _T("\\Data\\Emoticons.xml");
00182
00183 BOOL bSuccess = LoadTrillian( strFile );
00184 if ( ! bSuccess ) return FALSE;
00185
00186 BuildTokens();
00187
00188 return TRUE;
00189 }
00190
00192
00193
00194 void CEmoticons::Clear()
00195 {
00196 if ( m_pImage.m_hImageList != NULL ) m_pImage.DeleteImageList();
00197
00198 if ( m_pTokens != NULL ) delete [] m_pTokens;
00199 m_pTokens = NULL;
00200
00201 m_pIndex.RemoveAll();
00202 m_pButtons.RemoveAll();
00203 }
00204
00206
00207
00208 int CEmoticons::AddEmoticon(LPCTSTR pszText, CImageFile* pImage, CRect* pRect, COLORREF crBack, BOOL bButton)
00209 {
00210 ASSERT( pImage->m_bLoaded && pImage->m_nComponents == 3 );
00211
00212 if ( pRect->left < 0 || pRect->left + 16 > pImage->m_nWidth ) return -1;
00213 if ( pRect->top < 0 || pRect->top > pImage->m_nHeight + 16 ) return -1;
00214 if ( pRect->right != pRect->left + 16 ) return -1;
00215 if ( pRect->bottom != pRect->top + 16 ) return -1;
00216
00217 DWORD nPitch = pImage->m_nWidth * pImage->m_nComponents;
00218 while ( nPitch & 3 ) nPitch++;
00219
00220 BYTE* pSource = pImage->m_pImage;
00221 pSource += pRect->top * nPitch + pRect->left * pImage->m_nComponents;
00222
00223 HDC hDC = GetDC( 0 );
00224 CBitmap bmImage;
00225
00226 bmImage.CreateCompatibleBitmap( CDC::FromHandle( hDC ), 16, 16 );
00227
00228 BITMAPINFOHEADER pInfo;
00229 pInfo.biSize = sizeof(BITMAPINFOHEADER);
00230 pInfo.biWidth = 16;
00231 pInfo.biHeight = 16;
00232 pInfo.biPlanes = 1;
00233 pInfo.biBitCount = 24;
00234 pInfo.biCompression = BI_RGB;
00235 pInfo.biSizeImage = 16 * 16 * 3;
00236
00237 for ( int nY = 15 ; nY >= 0 ; nY-- )
00238 {
00239 SetDIBits( hDC, bmImage, nY, 1, pSource, (BITMAPINFO*)&pInfo, DIB_RGB_COLORS );
00240 pSource += nPitch;
00241 }
00242
00243 ReleaseDC( 0, hDC );
00244 int nIndex = m_pImage.Add( &bmImage, crBack );
00245 bmImage.DeleteObject();
00246
00247 m_pIndex.Add( pszText );
00248 if ( bButton ) m_pButtons.Add( nIndex );
00249
00250 return nIndex;
00251 }
00252
00254
00255
00256 void CEmoticons::BuildTokens()
00257 {
00258 int nLength = 2;
00259
00260 for ( int nIndex = 0 ; nIndex < m_pIndex.GetSize() ; nIndex++ )
00261 {
00262 nLength += m_pIndex.GetAt( nIndex ).GetLength() + 1;
00263 }
00264
00265 ASSERT( m_pTokens == NULL );
00266 LPTSTR pszOut = m_pTokens = new TCHAR[ nLength ];
00267
00268 for ( int nIndex = 0 ; nIndex < m_pIndex.GetSize() ; nIndex++ )
00269 {
00270 _tcscpy( pszOut, m_pIndex.GetAt( nIndex ) );
00271 pszOut += m_pIndex.GetAt( nIndex ).GetLength() + 1;
00272 }
00273
00274 *pszOut++ = 0;
00275 }
00276
00278
00279
00280 BOOL CEmoticons::LoadTrillian(LPCTSTR pszFile)
00281 {
00282 CString strPath, strValue;
00283
00284 CXMLElement* pXML = CXMLElement::FromFile( pszFile, TRUE );
00285 if ( pXML == NULL ) return FALSE;
00286
00287 strPath = pszFile;
00288 int nSlash = strPath.ReverseFind( '\\' );
00289 if ( nSlash >= 0 ) strPath = strPath.Left( nSlash + 1 );
00290
00291 CXMLElement* pBitmap = pXML->GetElementByName( _T("bitmap") );
00292
00293 if ( pBitmap == NULL )
00294 {
00295 delete pXML;
00296 return FALSE;
00297 }
00298
00299 strValue = pBitmap->GetAttributeValue( _T("file") );
00300
00301 nSlash = strValue.ReverseFind( '/' );
00302 if ( nSlash >= 0 ) strValue = strValue.Mid( nSlash + 1 );
00303 strValue = strPath + strValue;
00304
00305 CImageServices pServices;
00306 CImageFile pImage( &pServices );
00307
00308 if ( ! pImage.LoadFromFile( strValue ) ||
00309 ! pImage.EnsureRGB( GetSysColor( COLOR_WINDOW ) ) ||
00310 ! pImage.SwapRGB() )
00311 {
00312 delete pXML;
00313 return FALSE;
00314 }
00315
00316 COLORREF crBack = RGB( pImage.m_pImage[2], pImage.m_pImage[1], pImage.m_pImage[0] );
00317
00318 for ( POSITION pos = pXML->GetElementIterator() ; pos ; )
00319 {
00320 CXMLElement* pEmoticon = pXML->GetNextElement( pos );
00321 if ( ! pEmoticon->IsNamed( _T("emoticon") ) ) continue;
00322
00323 CXMLElement* pSource = pEmoticon->GetElementByName( _T("source") );
00324 CString strText = pEmoticon->GetAttributeValue( _T("text") );
00325 CRect rc( 0, 0, 0, 0 );
00326
00327 strValue = pSource->GetAttributeValue( _T("left"), _T("0") );
00328 _stscanf( strValue, _T("%i"), &rc.left );
00329 strValue = pSource->GetAttributeValue( _T("top"), _T("0") );
00330 _stscanf( strValue, _T("%i"), &rc.top );
00331 strValue = pSource->GetAttributeValue( _T("right"), _T("0") );
00332 _stscanf( strValue, _T("%i"), &rc.right );
00333 strValue = pSource->GetAttributeValue( _T("bottom"), _T("0") );
00334 _stscanf( strValue, _T("%i"), &rc.bottom );
00335
00336 BOOL bButton = pEmoticon->GetAttributeValue( _T("button") ).CompareNoCase( _T("yes") ) == 0;
00337
00338 AddEmoticon( strText, &pImage, &rc, crBack, bButton );
00339 }
00340
00341 delete pXML;
00342
00343 return TRUE;
00344 }
00345
00347
00348
00349 void CEmoticons::FormatText(CRichDocument* pDocument, LPCTSTR pszBody, BOOL bNewlines)
00350 {
00351 static LPCTSTR pszURLs[] = { _T("\r\n"), _T("http://"), _T("magnet:?"), _T("gnutella:"), _T("gnet:"), _T("ftp://"), _T("raza:"), _T("shareaza:"), _T("ed2k://"), _T("sig2dat:"), _T("www."), NULL };
00352 BOOL bBold = FALSE, bItalic = FALSE, bUnderline = FALSE;
00353 COLORREF cr = 0;
00354 CString str;
00355
00356 while ( *pszBody )
00357 {
00358 LPCTSTR pszToken = _tcschr( pszBody, '[' );
00359
00360 for ( int nURL = 0 ; pszURLs[ nURL ] != NULL ; nURL++ )
00361 {
00362 LPCTSTR pszFind = _tcsistr( pszBody, pszURLs[ nURL ] );
00363 if ( pszFind != NULL && ( pszToken == NULL || pszFind < pszToken ) ) pszToken = pszFind;
00364 }
00365
00366 int nEmoticon = -1;
00367 LPCTSTR pszEmoticon = FindNext( pszBody, &nEmoticon );
00368
00369 if ( pszEmoticon != NULL && ( pszToken == NULL || pszEmoticon < pszToken ) )
00370 {
00371 pszToken = pszEmoticon;
00372 }
00373
00374 if ( pszToken != pszBody )
00375 {
00376 if ( pszToken != NULL )
00377 {
00378 TCHAR cSave = *pszToken;
00379 *(LPTSTR)pszToken = 0;
00380 str = pszBody;
00381 *(LPTSTR)pszToken = cSave;
00382 }
00383 else
00384 {
00385 str = pszBody;
00386 }
00387
00388 pDocument->Add( retText, str, NULL,
00389 ( bBold ? retfBold : 0 ) |
00390 ( bItalic ? retfItalic : 0 ) |
00391 ( bUnderline ? retfUnderline : 0 ) |
00392 ( cr ? retfColour : 0 ) )->m_cColour = cr;
00393 }
00394
00395 if ( pszToken == NULL ) break;
00396
00397 pszBody = pszToken;
00398 if ( *pszBody == 0 ) break;
00399
00400 if ( pszEmoticon == pszBody )
00401 {
00402 str.Format( _T("%lu"), nEmoticon );
00403 pDocument->Add( retEmoticon, str );
00404 pszBody += _tcslen( GetText( nEmoticon ) );
00405 continue;
00406 }
00407 else if ( pszBody[0] == '\r' && pszBody[1] == '\n' )
00408 {
00409 if ( bNewlines )
00410 {
00411 pDocument->Add( retNewline, _T("4") );
00412 }
00413
00414 pszBody += 2;
00415 continue;
00416 }
00417 else if ( *pszBody != '[' )
00418 {
00419 for ( ; *pszToken ; pszToken++ )
00420 {
00421 if ( ! _istalnum( *pszToken ) &&
00422 _tcschr( _T(":@/?=&%._-+;~#"), *pszToken ) == NULL )
00423 {
00424 break;
00425 }
00426 }
00427
00428 TCHAR cSave = *pszToken;
00429 *(LPTSTR)pszToken = 0;
00430 str = pszBody;
00431 *(LPTSTR)pszToken = cSave;
00432
00433 if ( _tcsnicmp( str, _T("www."), 4 ) == 0 ) str = _T("http://") + str;
00434
00435 pDocument->Add( retLink, str, str,
00436 ( bBold ? retfBold : 0 ) |
00437 ( bItalic ? retfItalic : 0 ) |
00438 ( bUnderline ? retfUnderline : 0 ) );
00439
00440 pszBody = pszToken;
00441 }
00442 else if ( _tcsnicmp( pszBody, _T("[b]"), 3 ) == 0 )
00443 {
00444 bBold = TRUE;
00445 }
00446 else if ( _tcsnicmp( pszBody, _T("[/b]"), 4 ) == 0 )
00447 {
00448 bBold = FALSE;
00449 }
00450 else if ( _tcsnicmp( pszBody, _T("[i]"), 3 ) == 0 )
00451 {
00452 bItalic = TRUE;
00453 }
00454 else if ( _tcsnicmp( pszBody, _T("[/i]"), 4 ) == 0 )
00455 {
00456 bItalic = FALSE;
00457 }
00458 else if ( _tcsnicmp( pszBody, _T("[u]"), 3 ) == 0 )
00459 {
00460 bUnderline = TRUE;
00461 }
00462 else if ( _tcsnicmp( pszBody, _T("[/u]"), 4 ) == 0 )
00463 {
00464 bUnderline = FALSE;
00465 }
00466 else if ( _tcsnicmp( pszBody, _T("[/c]"), 4 ) == 0 )
00467 {
00468 cr = 0;
00469 }
00470 else if ( _tcsnicmp( pszBody, _T("[c:#"), 4 ) == 0 && _tcslen( pszBody ) >= 4 + 6 + 1 )
00471 {
00472 _tcsncpy( str.GetBuffer( 6 ), pszBody + 4, 6 );
00473 str.ReleaseBuffer( 6 );
00474 int nRed, nGreen, nBlue;
00475 _stscanf( str.Mid( 0, 2 ), _T("%x"), &nRed );
00476 _stscanf( str.Mid( 2, 2 ), _T("%x"), &nGreen );
00477 _stscanf( str.Mid( 4, 2 ), _T("%x"), &nBlue );
00478 cr = RGB( nRed, nGreen, nBlue );
00479 }
00480
00481 if ( *pszBody == '[' )
00482 {
00483 pszToken = _tcschr( pszBody, ']' );
00484 if ( pszToken != NULL ) pszBody = pszToken + 1;
00485 else pszBody ++;
00486 }
00487 }
00488 }