examples/SFExamples/Wikipedia/src/WikiDb.cpp

00001 // 
00002 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
00003 // All rights reserved.
00004 // This component and the accompanying materials are made available
00005 // under the terms of the License "Eclipse Public License v1.0"
00006 // which accompanies this distribution, and is available
00007 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
00008 // 
00009 // Initial Contributors:
00010 // Nokia Corporation - initial contribution.
00011 // 
00012 // Contributors:
00013 // 
00014 // Description:
00015 // 
00016 
00017 
00018 #include "WikiDb.h"
00019 
00020 _LIT(KCopyleftNotice, "<hr><small>All text is available under the terms of the <a href=http://en.wikipedia.org/wiki/Wikipedia:Text_of_the_GNU_Free_Documentation_License>GNU Free Documentation License</a>.<br>(See <a href=http://en.wikipedia.org/wiki/Wikipedia:Copyrights>Copyrights</a> for details.)</small>");
00021 
00022 CWikiDb::CWikiDb() : CActive( EPriorityIdle )
00023         {
00024         CActiveScheduler::Add( this );
00025         }
00026 
00027 CWikiDb::~CWikiDb()
00028         {
00029         Cancel();
00030         iQueryBuf.Close();
00031         iCountBuf.Close();
00032         iUtf8Chars.Close();
00033         iArticleText.Close();
00034         iStatement.Close();
00035         iCountStatement.Close();
00036         iDatabase.Close();
00037         delete iCurArticleTitle;
00038         }
00039 
00040 CWikiDb* CWikiDb::NewL()
00041         {
00042         CWikiDb* db = new (ELeave)CWikiDb();
00043         CleanupStack::PushL(db);
00044         db->ConstructL();
00045         CleanupStack::Pop(db);
00046         return db;
00047         }
00048 
00049 void CWikiDb::ConstructL() 
00050         {
00051         User::LeaveIfError( iDatabase.Open( KSqlDbName ) );
00052         iQueryBuf.CreateL(KMaxCharByCharSqlQueryLen);
00053         iCountBuf.CreateL(KMaxCharByCharSqlQueryLen);
00054         iUtf8Chars.CreateL(KMaxCharByCharQueryLen);
00055         iArticleText.CreateL(KMaxArticleTextLen);
00056     iCurArticleTitle = HBufC::NewL( 0 );        
00057         }
00058 
00059 
00060 // prepares the statements...
00061 void CWikiDb::SearchL(const TDesC& aPrefix, MWikiCountObserver* aObserver)
00062         {
00063         iObserver = aObserver;
00064         SetPageAndItemL( EInitialise );
00065         HBufC* quoted = EscapeL(aPrefix);
00066         CleanupStack::PushL(quoted);
00067         User::LeaveIfError(CnvUtfConverter::ConvertFromUnicodeToUtf8(iUtf8Chars, *quoted));
00068         CleanupStack::PopAndDestroy(quoted);
00069         iQueryBuf.SetLength(0);
00070         iQueryBuf.Format(KWikiSqlStmtJustTitle, &iUtf8Chars);
00071         RunQueryL();
00072         StartRecordCountL();
00073         }
00074 
00075 void CWikiDb::PageUpL( const TDesC& aPrefix )
00076         {
00077         TInt prevPage = iCurPage - 1;
00078         TInt offset = prevPage * KItemsPerPage;
00079         SetPageAndItemL( EPageUp );
00080         HBufC* quoted = EscapeL( aPrefix );
00081         CleanupStack::PushL( quoted );  
00082         User::LeaveIfError( CnvUtfConverter::ConvertFromUnicodeToUtf8( iUtf8Chars, *quoted ) );
00083         CleanupStack::PopAndDestroy( quoted );  
00084         iQueryBuf.SetLength(0);
00085         iQueryBuf.Format( KWikiSqlStmtTitleOffset, &iUtf8Chars, offset );
00086         RunQueryL();
00087         }
00088 
00093 TBool CWikiDb::Next()
00094         {
00095         TBool found = ETrue;
00096         if ( iAtNextItem )
00097                 {
00098                 // We have previously called Next(), so we don't need to call it again
00099                 iAtNextItem = EFalse;           
00100                 }
00101         else
00102                 {
00103                 // Call Next() as normal
00104                 TInt res = iStatement.Next();
00105                 found = ( res == KSqlAtRow );
00106                 }
00107         if ( found )
00108                 {
00109                 SetPageAndItemL( ENextItem );
00110                 }
00111         return found;
00112         }
00113 
00114 
00118 const TInt CWikiDb::GetTitle(TPtrC& aTitle)
00119         {
00120         return iStatement.ColumnText(0, aTitle);
00121         }
00122 
00126 const TDesC8& CWikiDb::GetArticleContentL()
00127         {
00128         TPtrC ptr;
00129         GetTitle(ptr);
00130         EnsureArticleFormattedL(ptr);
00131         return iArticleText;
00132         }
00133 
00134 
00138 const TDesC8& CWikiDb::GetArticleContentL(const TDesC& aTitle)
00139         {
00140         EnsureArticleFormattedL(aTitle);
00141         return iArticleText;
00142         }
00143 
00147 const TDesC8& CWikiDb::GetArticleContentL(const TDesC8& aTitle)
00148         {
00149         EnsureArticleFormattedL(aTitle);
00150         return iArticleText;
00151         }
00152 
00153 
00158 void CWikiDb::EnsureArticleFormattedL(const TDesC& aTitle)
00159         {
00160         TBuf8<128> titleUtf8;
00161         User::LeaveIfError(CnvUtfConverter::ConvertFromUnicodeToUtf8(titleUtf8, aTitle));
00162         EnsureArticleFormattedL(titleUtf8);
00163         }
00164 
00165 void CWikiDb::EnsureArticleFormattedL(const TDesC8& aTitleUtf8)
00166         {
00167         HBufC8* quoted = EscapeL(aTitleUtf8);
00168         CleanupStack::PushL(quoted);
00169         RSqlStatement stmt;
00170         CleanupClosePushL(stmt);
00171         TBuf8<256> getArticleQuery;
00172         getArticleQuery.Format(KWikiSqlStmtGetArticle, quoted);
00173 
00174         stmt.PrepareL(iDatabase, getArticleQuery);
00175         TInt res = stmt.Next();
00176         if ( res != KSqlAtRow ) 
00177                 {
00178                 User::Leave(KErrNotFound);
00179                 }
00180         TPtrC8 content;
00181         TPtrC8 links;
00182         stmt.ColumnBinary(0, content);
00183         stmt.ColumnBinary(1, links);
00184         
00185         // format into html
00186         iArticleText.SetLength(0);
00187         _LIT(KHtmlEncodingMeta, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
00188         iArticleText.Append(KHtmlEncodingMeta);
00189         iArticleText.AppendFormat(KTitleFormat, &aTitleUtf8);
00190         iArticleText.Append(content);
00191         iArticleText.Append(KHtmlParagpraph);
00192 
00193         _LIT8(KChars, " _|");
00194         TBuf8<3> chars;
00195         chars.Copy(KChars); 
00196         
00197         TBuf8<256> articleNameWithUnderscores;
00198         ReplaceChar(aTitleUtf8, articleNameWithUnderscores, chars[0], chars[1]);
00199 
00200         // parse links field
00201         TInt linksLen = links.Length();
00202         TInt lastLinkEnd = 0;
00203         for ( TInt i = 0; i < linksLen; i++ ) {
00204                 if ( links[i] == chars[2] )
00205                         {
00206                         // end of a link
00207                         TPtrC8 link = links.Mid(lastLinkEnd, i - lastLinkEnd);
00208                         lastLinkEnd = i+1;
00209                         TBuf8<256> linkWithUnderscores;
00210                         ReplaceChar(link, linkWithUnderscores, chars[0], chars[1]);
00211                         // Append to the article
00212                         iArticleText.AppendFormat(KLinkFormat, &articleNameWithUnderscores, &linkWithUnderscores, &link);
00213                         }
00214         }
00215 
00216         iArticleText.AppendFormat(KFullArticleLinkFormat, &articleNameWithUnderscores);
00217         iArticleText.Append(KCopyleftNotice);
00218         // TODO append link to the full article
00219         CleanupStack::PopAndDestroy( &stmt );
00220         CleanupStack::PopAndDestroy(quoted);
00221         }
00222 
00223 void CWikiDb::ReplaceChar(const TDesC8& aSource, TDes8& aTarget, const TChar& aToReplace, const TChar& aReplacement)
00224         {
00225         TInt len = aSource.Length();
00226         for ( TInt i = 0 ; i < len; i++ )
00227                 {
00228                 TChar ch = aSource[i];
00229                 if ( ch == aToReplace ) 
00230                         {
00231                         aTarget.Append(aReplacement);
00232                         }
00233                 else 
00234                         {
00235                         aTarget.Append(ch);
00236                         }
00237                 }
00238         }
00239 
00240 void CWikiDb::DoCancel()
00241         {
00242         iRequestCode = ECancel;
00243         }
00244 
00245 void CWikiDb::RunL()
00246         {
00247         switch ( iRequestCode ) 
00248                 {
00249                 case ECancel:
00250                         break;
00251                         
00252                 case ERecordCount:
00253                         {
00254                         RunRecCountQueryL();                    
00255                         TraverseRecCountL();
00256                         }
00257                         break;  
00258                         
00259                 case ERecordCountNext:
00260                         {
00261                         TInt found = iCountStatement.Next();
00262                         if ( found == KSqlAtRow )
00263                                 {
00264                                 iNumRecords++;
00265                                 TraverseRecCountL();
00266                                 }
00267                         else
00268                                 {
00269                                 iObserver->CountUpdatedL( iStatus.Int() );                              
00270                                 }
00271                         }
00272                         break;
00273                 }
00274         }
00275 
00276 void CWikiDb::SetCurrentArticleL( const TDesC& aTitle )
00277         {
00278         delete iCurArticleTitle;
00279         iCurArticleTitle = aTitle.AllocL();
00280         }
00281 
00282 const TDesC8& CWikiDb::GetCurrentArticleContentL()
00283         {
00284         return GetArticleContentL( *iCurArticleTitle );
00285         }
00286 
00287 TBool CWikiDb::DoesNextItemExist()
00288         {
00289         if ( iAtNextItem )
00290                 {
00291                 return iAtNextItem;
00292                 }
00293         TInt res = iStatement.Next();
00294         iAtNextItem = ( res == KSqlAtRow );
00295         return iAtNextItem;
00296         }
00297 
00298 void CWikiDb::RunQueryL()
00299         {
00300         iStatement.Close();
00301         iStatement.PrepareL( iDatabase, iQueryBuf );
00302         }
00303 
00304 void CWikiDb::RunRecCountQueryL()
00305         {
00306         iCountStatement.Close();
00307         iCountStatement.PrepareL( iDatabase, iCountBuf );
00308         }
00309 
00310 void CWikiDb::SetPageAndItemL( const TPageState aPageState )
00311         {
00312         switch ( aPageState )
00313                 {
00314                 case EInitialise:
00315                         {
00316                         // Initialise the page and item at -1 values - which means
00317                         // the cursor is currently not on a page or item
00318                         iCurPage = -1;
00319                         iCurItem = -1;
00320                         iAtNextItem = EFalse;
00321                         iNumRecords = 0;
00322                         }
00323                         break;
00324                 
00325                 case EPageUp:
00326                         {
00327                         // Get the number of the previous page
00328                         TInt prevPage = iCurPage - 1;
00329 
00330                         // Set the current item to be one before the first item in the previous page
00331                         // The cursor will be placed at the first item in the previous page
00332                         // when Next() is called
00333                         iCurItem = ( prevPage * KItemsPerPage ) -1;
00334 
00335                         // Set the current page to be one before the previous page
00336                         // The page will be set when the cursor is placed at the first item
00337                         // in the previous page (see above)
00338                         iCurPage = prevPage - 1;
00339                         iAtNextItem = EFalse;
00340                         }
00341                         break;
00342                         
00343                 case ENextItem:
00344                         {
00345                         // Set the cursor to the next item
00346                         iCurItem++;
00347                         
00348                         // Increment the page count if we are on a new page
00349                         if ( iCurItem % KItemsPerPage == 0 )
00350                                 {
00351                                 iCurPage++;
00352                                 }                       
00353                         }
00354                         break;
00355                         
00356                 default:
00357                         break;
00358                 }
00359         }
00360 
00361 const TUint16 KSingleQuote = 0x0027;
00362 HBufC* CWikiDb::EscapeL( const TDesC& aQuery) const
00363         {
00364     TInt len = aQuery.Length();
00365     HBufC* buf = HBufC::NewLC( len * 2 + 4 );
00366     TPtr ptr = (buf->Des());
00367     for( TInt i=0;i<len;i++ )
00368         {
00369         if( aQuery[i] == KSingleQuote )
00370             {
00371             ptr.Append(aQuery[i]);
00372             ptr.Append(aQuery[i]);
00373             }
00374         else
00375             {
00376             ptr.Append(aQuery[ i ]);
00377             }
00378         }
00379     CleanupStack::Pop(buf);
00380     return buf;
00381         }
00382 
00383 HBufC8* CWikiDb::EscapeL( const TDesC8& aQuery) const
00384         {
00385         TInt len = aQuery.Length();
00386         HBufC8* buf = HBufC8::NewLC( len * 2 + 4 );
00387         TPtr8 ptr = (buf->Des());
00388         for( TInt i=0;i<len;i++ )
00389             {
00390             if( aQuery[i] == KSingleQuote )
00391                 {
00392                 ptr.Append(aQuery[i]);
00393                 ptr.Append(aQuery[i]);
00394                 }
00395             else
00396                 {
00397                 ptr.Append(aQuery[ i ]);
00398                 }
00399             }
00400         CleanupStack::Pop(buf);
00401         return buf;
00402         }
00403 
00404 void CWikiDb::StartRecordCountL()
00405         {
00406         if ( IsActive() )
00407                 {
00408                 Cancel();
00409                 }
00410         
00411         TBool syncCount = ETrue;
00412         TSqlScalarFullSelectQuery fullSelectQuery(iDatabase);
00413         iCountBuf.Zero();
00414         switch (iUtf8Chars.Length())
00415                 {
00416                 case 0:
00417                         {
00418                         iCountBuf.Append(KCountAll);
00419                         break;
00420                         }
00421                 case 1:
00422                         {
00423                         iCountBuf.AppendFormat(KCountWith1Char, &iUtf8Chars);
00424                         break;
00425                         }
00426                 case 2:
00427                         {
00428                         iCountBuf.AppendFormat(KCountWith2Chars, &iUtf8Chars);
00429                         break;
00430                         }
00431                 case 3:
00432                         {
00433                         iCountBuf.AppendFormat(KCountWith3Chars, &iUtf8Chars);
00434                         break;
00435                         }
00436                 case 4:
00437                         {
00438                         iCountBuf.AppendFormat(KCountWith4Chars, &iUtf8Chars);
00439                         break;
00440                         }
00441                 case 5:
00442                         {
00443                         iCountBuf.AppendFormat(KCountWith5Chars, &iUtf8Chars);
00444                         break;
00445                         }
00446                 default:
00447                         {
00448                         iCountBuf.SetLength( 0 );
00449                         iCountBuf.Copy( iQueryBuf );
00450                         TRequestStatus* status = &iStatus;
00451                         iStatus = KRequestPending;
00452                         iRequestCode = ERecordCount;
00453                         SetActive();
00454                         User::RequestComplete( status, KErrNone );
00455                         syncCount = EFalse;
00456                         break;
00457                         }
00458                 }
00459         
00460         if ( syncCount )
00461                 {
00462                 TRAPD( err, iNumRecords = fullSelectQuery.SelectIntL( iCountBuf ) );
00463                 switch ( err )
00464                         {
00465                         case KErrNotFound:
00466                                 iNumRecords = 0;
00467                                 break;
00468                                 
00469                         case KErrNone:
00470                                 // Do nothing
00471                                 break;
00472                                 
00473                         default:
00474                                 User::Leave( err );
00475                                 break;
00476                         }
00477                 iObserver->CountUpdatedL( KErrNone );
00478                 }
00479         }
00480 
00481 void CWikiDb::TraverseRecCountL()
00482         {
00483         if ( IsActive() )
00484                 {
00485                 Cancel();
00486                 }       
00487         TRequestStatus* status = &iStatus;
00488         iStatus = KRequestPending;
00489         iRequestCode = ERecordCountNext;
00490         SetActive();
00491         User::RequestComplete( status, KErrNone );      
00492         }
00493 
00494 // End of file

Generated by  doxygen 1.6.2