symhelp/helpmodel/src/HLPDB.CPP
changeset 0 1f04cf54edd8
--- /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);
+	}