--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/symhelp/helpmodel/src/HLPDB.CPP Tue Jan 26 15:15:23 2010 +0200
@@ -0,0 +1,393 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "HLPDB.H"
+
+// System includes
+#include <fbs.h>
+
+// User includes
+#include "HLPMODEL.H"
+#include "hlppanic.h"
+#include "Hlpsqlconsts.h"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "hlpmodel_internal.h"
+#endif
+
+// Constants
+const TInt KHlpModelNumberOfImageTableColumnsForV6Point0HelpFile = 2;
+const TInt KHlpModelNumberOfImagesInV6Point0HelpFile = 1;
+
+
+//
+// ----> CHlpDatabase
+//
+
+CHlpDatabase::CHlpDatabase(RFs& aFs)
+: iFs(aFs)
+ {
+ }
+
+CHlpDatabase::~CHlpDatabase()
+ {
+ Close();
+ iImageTable.Close();
+
+ delete iView;
+ delete iDatabase;
+ delete iStore;
+ delete iUids;
+ }
+
+void CHlpDatabase::ConstructL()
+ {
+ iView = new(ELeave) RDbView;
+ iUids = new(ELeave) CArrayFixFlat<TUid>(2);
+ iDatabase = new(ELeave) RDbStoreDatabase;
+ }
+
+CHlpDatabase* CHlpDatabase::NewLC(RFs& aFs)
+ {
+ CHlpDatabase* self = new(ELeave) CHlpDatabase(aFs);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+CHlpDatabase* CHlpDatabase::NewLC(RFs& aFs, const TDesC& aFileName)
+ {
+ CHlpDatabase* self = CHlpDatabase::NewLC(aFs);
+ self->OpenL(aFileName);
+ return self;
+ }
+
+//
+//
+//
+
+void CHlpDatabase::OpenL(const TDesC& aFileName)
+ {
+ iFileName = aFileName;
+ iStore = CPermanentFileStore::OpenL(iFs, aFileName, EFileRead);
+
+ // Restore the dictionary
+ CStreamDictionary* dictionary = CStreamDictionary::NewLC();
+ RStoreReadStream in;
+ in.OpenLC(*iStore, iStore->Root());
+ dictionary->InternalizeL(in);
+ CleanupStack::PopAndDestroy(); // in
+
+ // Restore the database
+ iDatabase->OpenL(iStore, dictionary->At(KUidHlpDbStream));
+
+ // Open image table
+ _LIT(KImageTable, "IMAGE");
+ _LIT(KImageIndex, "IMAGEIDX");
+ User::LeaveIfError(iImageTable.Open(*iDatabase, KImageTable, RDbRowSet::EReadOnly));
+ User::LeaveIfError(iImageTable.SetIndex(KImageIndex));
+
+ // Fetch the image row
+ CDbColSet* columnSet = iImageTable.ColSetL();
+
+ // We can identify v6 help files by the number of columns in the image table.
+ // Since v6 help files only have one image for all zoom sizes, then we
+ // can identify this via the number of columns being 2.
+ iOldHelpFileFormat = (columnSet->Count() == KHlpModelNumberOfImageTableColumnsForV6Point0HelpFile);
+ delete columnSet;
+
+ // Restore the Uid list
+ TStreamId uidStream = dictionary->At(KUidHlpUidStream);
+ in.OpenLC(*iStore, uidStream);
+
+ TUid uid;
+ TKeyArrayFix key(_FOFF(TUid, iUid), ECmpTUint32);
+ const TInt count = in.ReadInt32L();
+ for (TInt i=0; i < count; i++)
+ {
+ uid.iUid = in.ReadInt32L();
+#ifdef _DEBUG
+ iUids->InsertIsqL(uid, key);
+#else
+ iUids->InsertIsqAllowDuplicatesL(uid, key);
+#endif
+ }
+ CleanupStack::PopAndDestroy(2); // in, dictionary
+
+ TEntry entry;
+ User::LeaveIfError(iFs.Entry(aFileName, entry));
+ iHelpFileUid = entry.MostDerivedUid();
+ }
+
+void CHlpDatabase::Close()
+ {
+ if (iView)
+ iView->Close();
+ if (iDatabase)
+ iDatabase->Close();
+ }
+
+//
+//
+//
+
+void CHlpDatabase::AppendCategoryListL(CDesCArray& aList)
+ {
+ _LIT(KCategoryTable, "TOPIC");
+
+ // Open the topic table so that we can use it to build the category list
+ RDbTable table;
+ User::LeaveIfError(table.Open(*iDatabase, KCategoryTable, RDbRowSet::EReadOnly));
+ CleanupClosePushL(table);
+
+ // Now build the list
+ if (table.FirstL())
+ {
+ // Get the column of the category
+ CDbColSet* columnSet = table.ColSetL();
+ TDbColNo categoryColumn = columnSet->ColNo(KSQLCategoryColumn);
+ delete columnSet;
+
+ TInt posNotReferenced = KErrNotFound;
+ TBuf<KMaxTitleColumn> title;
+ do
+ {
+ // Add the stuff
+ table.GetL();
+ title = table.ColDes(categoryColumn);
+ if (aList.Find(title, posNotReferenced)) // Returns something other than 0 if not found
+ aList.AppendL(title); // Not found, so append
+ }
+ while (table.NextL());
+ }
+
+ // Finally, close the table
+ CleanupStack::PopAndDestroy(&table);
+ }
+
+TInt CHlpDatabase::TopicIdSearchL(const TUid aCategoryUid, const TUint aTopicId)
+ {
+ const TInt KNumLength = 20;
+ const TInt KMaxParamLength = (2*KNumLength) + 20; // 20 for numbers, + 20 for ' = ' and ' AND ' etc.
+ TBuf<KNumLength> num;
+
+ HBufC* sqlStatement = HBufC::NewLC(KSQLTopicSearchProlog().Length() + KMaxParamLength);
+ TPtr pSql(sqlStatement->Des());
+ pSql.Append(KSQLTopicSearchProlog);
+
+ pSql.Append(KSQLTopicIdColumn);
+ pSql.Append(KSQLEqualOperator);
+ num.Num(aTopicId);
+ pSql.Append(num);
+
+ pSql.Append(KSQLAndOperator);
+ pSql.Append(KSQLCategoryUidColumn);
+ pSql.Append(KSQLEqualOperator);
+ num.Num(STATIC_CAST(TUint, aCategoryUid.iUid));
+ pSql.Append(num);
+
+ iView->Close();
+ User::LeaveIfError(iView->Prepare(Database(), TDbQuery(pSql, EDbCompareFolded), TDbWindow::EUnlimited, RDbRowSet::EReadOnly));
+ User::LeaveIfError(iView->EvaluateAll());
+ CleanupStack::PopAndDestroy(); // sqlStatement
+ if (iView->CountL())
+ {
+ iView->FirstL();
+ iView->GetL();
+ return ETopicAvailable; // View is prepared
+ }
+
+ return ETopicNotFound;
+ }
+
+TInt CHlpDatabase::ContextSearchL(const TDesC& aContext)
+ {
+ _LIT(KContextSearch, "SELECT CONTEXT, TOPICID FROM CONTEXT");
+ _LIT(KSpecificContext, " WHERE CONTEXT='%S'");
+
+ TInt specificContextLength = aContext.Length();
+ HBufC* sqlStatement = HBufC::NewLC(KContextSearch().Length() + KSpecificContext().Length() + specificContextLength);
+ TPtr pStatement = sqlStatement->Des();
+ pStatement.Append(KContextSearch);
+ if (specificContextLength)
+ {
+ HBufC* specificContext = HBufC::NewLC(KSpecificContext().Length() + specificContextLength);
+ TPtr pContext = specificContext->Des();
+ pContext.Format(KSpecificContext, &aContext);
+ pStatement.Append(pContext);
+ CleanupStack::PopAndDestroy(specificContext);
+ }
+
+ iView->Close();
+ User::LeaveIfError(iView->Prepare(Database(), TDbQuery(pStatement, EDbCompareFolded), TDbWindow::EUnlimited, RDbRowSet::EReadOnly));
+ User::LeaveIfError(iView->EvaluateAll());
+ CleanupStack::PopAndDestroy(sqlStatement);
+
+ if (iView->CountL())
+ {
+ // Get the topic id from the context table
+ CDbColSet* columnSet = iView->ColSetL();
+ TDbColNo topicIdCol = columnSet->ColNo(KSQLTopicIdColumn);
+ delete columnSet;
+
+ // Get the topic id as a descriptor
+ iView->FirstL();
+ iView->GetL();
+ TUint topicId = iView->ColUint(topicIdCol);
+
+ _LIT(KTopicSearch, "SELECT TOPICTITLE, TOPICID, CATEGORY, TOPICTEXT, TOPICMARKUP FROM TOPIC WHERE TOPICID=%d");
+ sqlStatement = HBufC::NewLC(KTopicSearch().Length() + 16); // 16 for the topic id
+ pStatement.Set(sqlStatement->Des());
+ pStatement.Format(KTopicSearch, topicId);
+
+ // Prepare the topic table with the correct record...
+ iView->Close(); // Finished with this view now
+ User::LeaveIfError(iView->Prepare(Database(), TDbQuery(pStatement, EDbCompareFolded), TDbWindow::EUnlimited, RDbRowSet::EReadOnly));
+ User::LeaveIfError(iView->EvaluateAll());
+ CleanupStack::PopAndDestroy(); // sqlStatement
+
+ return ETopicAvailable;
+ }
+
+ return ETopicNotFound;
+ }
+
+/** This method is called within the CHlpPicture::RestoreL() method and
+is responsible for finding the right bitmap to be retrieved and for reading
+in a pointer to that bitmap.
+
+@param aImageId The ID of the bitmap to be retrieved.
+@param aZoomState The current zoom state.
+@return A pointer to a CFbsBitmap object.
+@pre A valid zoom state is passed to the function.
+@post A pointer to the referenced bitmap is returned. */
+CFbsBitmap* CHlpDatabase::ImageForIdLC(TInt aImageId, THlpZoomState aZoomState)
+{
+ if (!iImageTable.FirstL())
+ User::Leave(KErrNotFound);
+
+ if (!iImageTable.SeekL(aImageId))
+ User::Leave(KErrNotFound);
+
+ // Fetch the image row
+ iImageTable.GetL();
+
+ // Work out which column the image is in
+ CDbColSet* columnSet = iImageTable.ColSetL();
+ CleanupStack::PushL(columnSet);
+
+ TDbColNo imageColumn = KDbNullColNo;
+ if (iOldHelpFileFormat)
+ {
+ // OLD HELP FILE FORMAT
+ // Retrieve bitmap from bitmap column in image table
+ // and store it in the 'imageColumn variable'
+ imageColumn = columnSet->ColNo(KSQLImageColumn);
+ }
+ else
+ {
+ // NEW HELP FILE FORMAT
+ // Depending on whether the number of bitmaps is 1 or 3,
+ // the bitmap from the appropriate column is retrieved
+ // and stored in the 'imageColumn' variable
+
+ // Stores the number of bitmaps per image table row.
+ const TInt bitmapCount = ImageCountForIdL(aImageId);
+ __ASSERT_DEBUG(bitmapCount <= KHlpModelMaximumNumberOfImagesForV6Point2Files, User::Invariant());
+
+ if (bitmapCount == KHlpModelDefaultNumberOfImagesForV6Point2Files)
+ imageColumn = columnSet->ColNo(KSQLImage0Column);
+ else if (bitmapCount == KHlpModelMaximumNumberOfImagesForV6Point2Files)
+ {
+ switch(aZoomState)
+ {
+ case EHlpZoomStateSmall:
+ imageColumn = columnSet->ColNo(KSQLImage0Column);
+ break;
+ default:
+ case EHlpZoomStateMedium:
+ imageColumn = columnSet->ColNo(KSQLImage1Column);
+ break;
+ case EHlpZoomStateLarge:
+ imageColumn = columnSet->ColNo(KSQLImage2Column);
+ break;
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(columnSet);
+
+ // Load the image from the blob
+ CFbsBitmap* bitmap = new(ELeave) CFbsBitmap();
+ CleanupStack::PushL(bitmap);
+
+ // Read the column from the blob
+ RDbColReadStream blob;
+ blob.OpenLC(iImageTable, imageColumn);
+ blob >> *bitmap;
+ CleanupStack::PopAndDestroy(); // blob
+ return bitmap;
+ }
+
+/** This method is called within the CHlpDatabase::ImageForIdLC()
+method and is responsible for returning the number of bitmaps stored
+in the image-table row, as referenced by the aImageId argument.
+
+@param aImageId The ID of the bitmap, used for retrieving image-table
+column information.
+@return An integer value that reflects the number of bitmaps within a
+particular image-table row.
+@pre None.
+@post The integer number at the image-table row referenced by
+aImageId is returned.
+@see RDbTable::GetL()
+@see RDbTable::ColSetL() */
+TInt CHlpDatabase::ImageCountForIdL(TInt aImageId)
+ {
+ if (!iImageTable.FirstL())
+ User::Leave(KErrNotFound);
+
+ if (!iImageTable.SeekL(aImageId))
+ User::Leave(KErrNotFound);
+
+ // Fetch the image row
+ iImageTable.GetL();
+
+ TInt count = KErrNotFound;
+ if (iOldHelpFileFormat)
+ count = KHlpModelNumberOfImagesInV6Point0HelpFile;
+ else
+ {
+ // Work out which column the image count is in,
+ // and assign it to 'imageCountColumn'.
+ CDbColSet* columnSet = iImageTable.ColSetL();
+ TDbColNo imageCountColumn = columnSet->ColNo(KSQLImageCountColumn);
+ delete columnSet;
+ //
+ count = iImageTable.ColUint(imageCountColumn);
+ }
+ return count;
+ }
+
+//
+//
+//
+
+TBool CHlpDatabase::MatchUidL(TUid aUid)
+ {
+ __ASSERT_ALWAYS(iUids, Panic(EHlpFault));
+ TInt index = KErrNotFound;
+ TKeyArrayFix key(_FOFF(TUid, iUid), ECmpTUint32);
+ // For some bizare reason, findisq returns 0 when the item was found.
+ return (iUids->FindIsq(aUid, key, index) == KErrNone);
+ }