symhelp/helpmodel/src/HLPMODEL.CPP
changeset 0 1f04cf54edd8
equal deleted inserted replaced
-1:000000000000 0:1f04cf54edd8
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "HLPMODEL.H"
       
    17 
       
    18 // System includes
       
    19 #include <coehelp.h>
       
    20 #include <txtrich.h>
       
    21 #include <bautils.h>
       
    22 
       
    23 // User includes
       
    24 #include "hlppict.h"
       
    25 #include "HLPSRCH.H"
       
    26 #include "hlppanic.h"
       
    27 #include "Hlpsqlconsts.h"
       
    28 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    29 #include "hlpmodel_internal.h"
       
    30 #endif
       
    31 // For searching for help files
       
    32 _LIT(KHlpFileSpec,			"*.h*");
       
    33 _LIT(KDefaultHelpExtension, ".hlp");
       
    34 
       
    35 _LIT(KHlpFileSearchPath,	"\\Resource\\Help\\");
       
    36 
       
    37 #ifdef __SHOW_LOADING_INFO__
       
    38 _LIT(KFormat1, "\n%S %d: %c:%S%S");
       
    39 _LIT(KFormat2, "\n%S %d: %c:%S%S");
       
    40 _LIT(KCompareNewListWithMasterList, "compare master list");
       
    41 _LIT(KDeleteEntry, "deleting");
       
    42 _LIT(KGetNearestLanguageFile, "getting nearest languuage file for");
       
    43 _LIT(KAddNewEntryToMasterList, "adding to master list");
       
    44 _LIT(KLoadMasterList, "Loading");
       
    45 _LIT(KFoundEntry, "Found entry during dir scan");
       
    46 _LIT(KDuplicateEntry, "entry discarded as duplicate");
       
    47 _LIT(KAddNewEntry, "entry added to list");
       
    48 #endif
       
    49 
       
    50 
       
    51 // Typedefs
       
    52 typedef CArrayPtrFlat<CHlpFileEntry> CHlpFileList;
       
    53 
       
    54 // Constants
       
    55 const TInt KHlpModelNumericValueSize = 32;
       
    56 
       
    57 // Average number of pictures per Help Topic
       
    58 const TInt KAverageNumberOfPicturesInHelpTopic = 3;
       
    59 
       
    60 #define UNUSED_VAR(a) a = a
       
    61 //
       
    62 // ----> CHlpFileEntry (header)
       
    63 //
       
    64 
       
    65 class CHlpFileEntry : public CBase
       
    66 	{
       
    67 
       
    68 public:
       
    69 	static CHlpFileEntry* NewLC(TDriveUnit aDrive, const TDesC& aFile);
       
    70 
       
    71 	inline TDriveUnit Drive() const { return iDrive; }
       
    72 	inline const TDesC& FileName() const { return iFile; }
       
    73 	inline const TDesC& Name() const { return iName; }
       
    74 	void GetFullNameAndPath(TDes& aName) const;
       
    75 
       
    76 private:
       
    77 	CHlpFileEntry(TDriveUnit aDrive, const TDesC& aFile);
       
    78 
       
    79 private:
       
    80 	TName iName;
       
    81 	TName iFile;
       
    82 	TDriveUnit iDrive;
       
    83 	};
       
    84 
       
    85 
       
    86 
       
    87 //
       
    88 // ----> Static utility function (source)
       
    89 //
       
    90 
       
    91 //#define __SHOW_LOADING_INFO__
       
    92 
       
    93 #ifdef __SHOW_LOADING_INFO__
       
    94 static void PrintEntryL(const TDesC& aPrompt, const CHlpFileEntry& aEntry, TInt aNumber = -1)
       
    95 	{
       
    96 	TFileName pFileName(aEntry.FileName());
       
    97 	TChar driveLetter = '?';
       
    98 	RFs::DriveToChar(aEntry.Drive(), driveLetter);
       
    99 
       
   100 	HBufC* buf = HBufC::NewLC(aPrompt.Length() + pFileName.Length() + KHlpFileSearchPath().Length() + 40);
       
   101 	TDes pBuf(buf->Des());
       
   102 
       
   103 
       
   104 	if	(aNumber >= KErrNone)
       
   105 		pBuf.Format(KFormat1, &aPrompt, aNumber, driveLetter, &KHlpFileSearchPath(), &pFileName);
       
   106 	else
       
   107 		pBuf.Format(KFormat2, &aPrompt, driveLetter, &KHlpFileSearchPath(), &pFileName);
       
   108 
       
   109 	RDebug::Print(pBuf);
       
   110 
       
   111 	CleanupStack::PopAndDestroy();
       
   112 	}
       
   113 #define __PRINT_FILE(aPrompt, aEntry)				(PrintEntryL(aPrompt, aEntry))
       
   114 #define __PRINT_FILE_NO(aPrompt, aEntry, aNumber)	(PrintEntryL(aPrompt, aEntry, aNumber))
       
   115 #else
       
   116 #define __PRINT_FILE(aPrompt, aEntry)
       
   117 #define __PRINT_FILE_NO(aPrompt, aEntry, aNumber)
       
   118 #endif
       
   119 
       
   120 
       
   121 
       
   122 
       
   123 //
       
   124 // ----> CHlpFileEntry (source)
       
   125 //
       
   126 CHlpFileEntry::CHlpFileEntry(TDriveUnit aDrive, const TDesC& aFile)
       
   127 :iFile(aFile)
       
   128 ,iDrive(aDrive)
       
   129 	{
       
   130 	TParsePtrC parser(iFile);
       
   131 	iName.Copy(parser.Name());
       
   132 	}
       
   133 
       
   134 CHlpFileEntry* CHlpFileEntry::NewLC(TDriveUnit aDrive, const TDesC& aFile)
       
   135 	{
       
   136 	CHlpFileEntry* self = new(ELeave) CHlpFileEntry(aDrive, aFile);
       
   137 	CleanupStack::PushL(self);
       
   138 	return self;
       
   139 	}
       
   140 
       
   141 
       
   142 //
       
   143 //
       
   144 //
       
   145 void CHlpFileEntry::GetFullNameAndPath(TDes& aName) const
       
   146 	{
       
   147 	TChar driveLetter = '?';
       
   148 	RFs::DriveToChar(Drive(), driveLetter);
       
   149 	aName.Zero();
       
   150 	aName.Append(driveLetter);
       
   151 	aName.Append(':');
       
   152 	aName.Append(KHlpFileSearchPath);
       
   153 	aName.Append(FileName());
       
   154 	}
       
   155 
       
   156 
       
   157 //
       
   158 // ----> CHlpModel
       
   159 //
       
   160 
       
   161 CHlpModel::CHlpModel(RFs& aFs, MHlpModelObserver& aObserver)
       
   162 :	iFsSession(aFs), iObserver(&aObserver)
       
   163 	{
       
   164 	}
       
   165 
       
   166 EXPORT_C CHlpModel::~CHlpModel()
       
   167 /** Destructor. */
       
   168 	{
       
   169 	if	(iDatabases)
       
   170 		iDatabases->ResetAndDestroy();
       
   171 
       
   172 	NotifyHelpModelDestructionToPictures();
       
   173 	if	(iPictures)
       
   174 		iPictures->Reset();
       
   175 
       
   176 	delete iDatabases;
       
   177 	delete iPictures;
       
   178 	delete iSearch;
       
   179 	delete iCriterion;
       
   180 	delete iZoomFactors;
       
   181 	}
       
   182 
       
   183 void CHlpModel::NotifyHelpModelDestructionToPictures()
       
   184 	{
       
   185 	if	(!iPictures)
       
   186 		return;
       
   187 	const TInt count = iPictures->Count();
       
   188 	for (TInt i=0; i<count; i++)
       
   189 		{
       
   190 		CHlpPicture& picture = *iPictures->At(i);
       
   191 		picture.HandleHelpModelDestruction();
       
   192 		}
       
   193 	}
       
   194 
       
   195 
       
   196 void CHlpModel::ConstructL()
       
   197 	{
       
   198 	iDatabases = new(ELeave) CHlpDatabases(2);
       
   199 	iPictures = new(ELeave) CArrayPtrFlat<CHlpPicture>(KAverageNumberOfPicturesInHelpTopic);
       
   200 	iSearch = CHlpSQLSearch::NewL(*this);
       
   201 
       
   202 	// There must always be 3 default zoom ratios present in the array...
       
   203 	iZoomFactors = new(ELeave) CArrayFixFlat<TInt>(3);
       
   204 	iZoomFactors->AppendL(KHlpModelZoomFactorSmall);
       
   205 	iZoomFactors->AppendL(KHlpModelZoomFactorMedium);
       
   206 	iZoomFactors->AppendL(KHlpModelZoomFactorLarge);
       
   207 	}
       
   208 
       
   209 EXPORT_C CHlpModel* CHlpModel::NewL(RFs& aFs, MHlpModelObserver* aObserver)
       
   210 /** Allocates and creates a help model object.
       
   211 
       
   212 @param aFs Open file server handle
       
   213 @param aObserver Client callback interface to handle messages from the help
       
   214 model
       
   215 @return New help model object */
       
   216 	{
       
   217 	CHlpModel* self = CHlpModel::NewLC(aFs, aObserver);
       
   218 	CleanupStack::Pop();
       
   219 	return self;
       
   220 	}
       
   221 
       
   222 EXPORT_C CHlpModel* CHlpModel::NewLC(RFs& aFs, MHlpModelObserver* aObserver)
       
   223 /** Allocates and creates a help model object, leaving the object on the cleanup
       
   224 stack.
       
   225 
       
   226 @param aFs Open file server handle
       
   227 @param aObserver Client callback interface to handle messages from the help
       
   228 model
       
   229 @return New help model object */
       
   230 	{
       
   231 	CHlpModel* self = new(ELeave) CHlpModel(aFs, *aObserver);
       
   232 	CleanupStack::PushL(self);
       
   233 	self->ConstructL();
       
   234 	return self;
       
   235 	}
       
   236 
       
   237 
       
   238 //
       
   239 //
       
   240 //
       
   241 
       
   242 EXPORT_C void CHlpModel::OpenL()
       
   243 /** Opens all the help files in \\Resource\\Help. */
       
   244 	{
       
   245 	CHlpFileList* masterList = new(ELeave) CHlpFileList(5);
       
   246 	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfCHlpFileEntry,masterList));
       
   247 
       
   248 	TInt i = EDriveY;
       
   249 	FOREVER
       
   250 		{
       
   251 		// Make sure we go from Y -> A, then do Z last
       
   252 		if	(i < EDriveA)
       
   253 			i = EDriveZ;
       
   254 
       
   255 		if	(DiskPresent(i))
       
   256 			{
       
   257 			// This generates a list for a specific directory on the specified drive.
       
   258 			CHlpFileList* list = BuildListForDriveLC(TDriveUnit(i), iFsSession);
       
   259 
       
   260 			TInt newListCount = list->Count();
       
   261 			if(newListCount)
       
   262 				{
       
   263 				// compare the new list with our master list to check for duplicates
       
   264 				TInt masterCount = masterList->Count();
       
   265 				for(TInt j=masterCount-1; j>=0; j--)
       
   266 					{
       
   267 					CHlpFileEntry* entry = masterList->At(j);
       
   268 					__PRINT_FILE_NO(KCompareNewListWithMasterList, *entry, j);
       
   269 
       
   270 					newListCount = list->Count();
       
   271 					for(TInt k=newListCount-1; k>=0; k--)
       
   272 						{
       
   273 						CHlpFileEntry* newEntry = list->At(k);
       
   274 
       
   275 						if	(entry->FileName().CompareF(newEntry->FileName()) == 0)
       
   276 							{
       
   277 							// Names same, so nearest language file already in master list
       
   278 							__PRINT_FILE_NO(KDeleteEntry, *newEntry, k);
       
   279 							delete newEntry;
       
   280 							list->Delete(k);
       
   281 							}
       
   282 						}
       
   283 					}
       
   284 				}
       
   285 
       
   286 			// At this point, anything that is left in the new list should
       
   287 			// have it's nearest language file added to the master list...
       
   288 			newListCount = list->Count();
       
   289 			for(TInt k=newListCount-1; k>=0; k--)
       
   290 				{
       
   291 				//get nearest language file
       
   292 				__PRINT_FILE_NO(KGetNearestLanguageFile, *list->At(k), k);
       
   293 
       
   294 				TChar driveLetter = '?';
       
   295 				RFs::DriveToChar(list->At(k)->Drive(), driveLetter);
       
   296 
       
   297 				TFileName fileName;
       
   298 				fileName.Append(driveLetter);
       
   299 				fileName.Append(':');
       
   300 				fileName.Append(KHlpFileSearchPath);
       
   301 				fileName.Append(list->At(k)->Name());
       
   302 				fileName.Append(KDefaultHelpExtension);
       
   303 
       
   304 				BaflUtils::NearestLanguageFile(iFsSession, fileName);
       
   305 
       
   306 				//get drive and filename+extension of nearest language file
       
   307 				TParsePtrC parser(fileName);
       
   308 				if	(!parser.ExtPresent())
       
   309 					User::Leave(KErrCorrupt);
       
   310 				TPtrC drive=parser.Drive();
       
   311 				TPtrC name=parser.NameAndExt();
       
   312 
       
   313 				//create new CHlpFileEntry
       
   314 				CHlpFileEntry* entry = CHlpFileEntry::NewLC(drive, name);
       
   315 				__PRINT_FILE(KAddNewEntryToMasterList, *entry);
       
   316 
       
   317 				//add to master list
       
   318 				masterList->AppendL(entry);
       
   319 				CleanupStack::Pop(entry);
       
   320 				}
       
   321 
       
   322 			list->ResetAndDestroy();
       
   323 			CleanupStack::PopAndDestroy(list);
       
   324 			}
       
   325 
       
   326 		if	(i-- == EDriveZ)
       
   327 			break;
       
   328 		}
       
   329 	// The code below validates the masterList of help files and filters out unnecessary files based on the criteria specified below -
       
   330 	// i)   In case of two files - abc.hlp and abc.h01 - present in the master list,since abc.h01 is the latest version, it
       
   331 	//      will be picked. In other words abc.hlp will be removed from the list.
       
   332 	// ii)  if two files for different language code exist, both should remain in masterList
       
   333 	// iii) if the system language is changed, the file as per the new language should be retained and
       
   334 	//      default file with .hlp extension should be removed from the masterList
       
   335 	TLanguage language;
       
   336 	language = User::Language(); //gets the default language
       
   337 	TInt languageCode;
       
   338 	languageCode = language; // integer equivalent of the language code. For example, ELangEnglish is 01
       
   339 	for(TInt i=masterList->Count()-1; i >= 0; i--)
       
   340 		{
       
   341 		CHlpFileEntry* newEntry = masterList->At(i);
       
   342 		TPtrC ptrFile (newEntry->FileName());
       
   343 		TBufC<8> fileExtension(ptrFile.Right(2));
       
   344 		TLex lex(fileExtension);
       
   345 		TInt lexIntValue;
       
   346 		lex.Val(lexIntValue);
       
   347 		TParse parser;
       
   348 		TBool hlpFlag = ETrue;
       
   349 		User::LeaveIfError(parser.Set(ptrFile, NULL, NULL));
       
   350 
       
   351 		if(lexIntValue != language)
       
   352 			{
       
   353 			// Get the filename with language code in file extension
       
   354 			TBuf<256> fileName(newEntry->Name());
       
   355 			TBuf<10> name;
       
   356 			name.Format(_L(".h%02d"),languageCode);
       
   357 			fileName.Append(name);
       
   358 
       
   359 			// Get the filename with the .hlp extension
       
   360 			TBuf<256> defaultFileName(newEntry->Name());
       
   361 			TBuf<10> defaultName;
       
   362 			defaultName.Format(_L(".hlp"));
       
   363 			defaultFileName.Append(defaultName);
       
   364 
       
   365 			//Check the file against all the files in the list
       
   366 			for(TInt j = masterList->Count()-1; j >=0 ; j--)
       
   367 				{
       
   368 				CHlpFileEntry* entry = masterList->At(j);
       
   369 				// If two files with same name exist, delete one from the masterList
       
   370 				// and reset hlpFlag to EFalse
       
   371 				if(entry->FileName().CompareF(fileName)==0)
       
   372 					{
       
   373 					masterList->Delete(i);
       
   374 					hlpFlag = EFalse;
       
   375 					break;
       
   376 					}
       
   377 				}
       
   378 				if( (hlpFlag) && (parser.Ext().CompareF(KDefaultHelpExtension)!=0))
       
   379 					{
       
   380 					for(TInt k = masterList->Count()-1; k >=0 ; k--)
       
   381 						{
       
   382 						CHlpFileEntry* entry = masterList->At(k);
       
   383 						if(entry->FileName().CompareF(defaultFileName)==0)
       
   384 							{
       
   385 							masterList->Delete(i);
       
   386 							break;
       
   387 							}
       
   388 						}
       
   389 					}
       
   390 				}
       
   391 			}
       
   392 
       
   393 	// Load the master list
       
   394 	TFileName file;
       
   395 	TInt count = masterList->Count();
       
   396 
       
   397 	for (i=0; i<count; i++)
       
   398 		{
       
   399 		masterList->At(i)->GetFullNameAndPath(file);
       
   400 		__PRINT_FILE_NO(KLoadMasterList, *masterList->At(i), i);
       
   401 
       
   402 		// This will leave with KErrArgument if it's a bad file
       
   403 		TRAPD(error, OpenFileL(file));
       
   404 		UNUSED_VAR(error); // used to suppress build warnings
       
   405 		}
       
   406 
       
   407 	CleanupStack::PopAndDestroy(masterList);
       
   408 	}
       
   409 
       
   410 TBool CHlpModel::DiskPresent(TInt aDrive) const
       
   411 	{
       
   412 	TDriveList list;
       
   413 	if	(iFsSession.DriveList(list) < KErrNone)
       
   414 		return EFalse;
       
   415 
       
   416 	TDriveInfo info;
       
   417 	TInt error = iFsSession.Drive(info, aDrive);
       
   418 	if	(error < KErrNone)
       
   419 		return EFalse;
       
   420 
       
   421 	return (list[aDrive] && info.iType != EMediaNotPresent);
       
   422 	}
       
   423 
       
   424 void CHlpModel::ResetAndDestroyArrayOfCHlpFileEntry(TAny* aObject)
       
   425 	{
       
   426 	CArrayPtr<CHlpFileEntry>* array=REINTERPRET_CAST(CArrayPtr<CHlpFileEntry>*,aObject);
       
   427 	if (array)
       
   428 		array->ResetAndDestroy();
       
   429 	delete array;
       
   430 	}
       
   431 
       
   432 CHlpFileList* CHlpModel::BuildListForDriveLC(TDriveUnit aDrive, RFs& aFsSession) const
       
   433 //
       
   434 //	Generate a list of help files for the specified drive
       
   435 //
       
   436 	{
       
   437 	CHlpFileList* list = new(ELeave) CHlpFileList(5);
       
   438 	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfCHlpFileEntry,list));
       
   439 
       
   440 	// Generate the folder spec to search in
       
   441 	TFileName searchSpec;
       
   442 	TChar driveLetter;
       
   443 	User::LeaveIfError(RFs::DriveToChar(aDrive, driveLetter));
       
   444 	searchSpec.Append(driveLetter);
       
   445 	searchSpec.Append(':');
       
   446 	searchSpec.Append(KHlpFileSearchPath);
       
   447 	searchSpec.Append(KHlpFileSpec);
       
   448 
       
   449 	CDir* dirList;
       
   450 
       
   451 	TFindFile finder(aFsSession);
       
   452 	TInt ret = finder.FindWildByPath(searchSpec, NULL, dirList);
       
   453 	if	(ret < KErrNone)
       
   454 		{
       
   455 		if	(ret == KErrNotFound)
       
   456 			return list;
       
   457 		else
       
   458 			User::Leave(ret);
       
   459 		}
       
   460 	CleanupStack::PushL(dirList);
       
   461 
       
   462 	// Add files to help file list
       
   463 	TInt dirCount = dirList->Count();
       
   464 	for(TInt i=0; i<dirCount; i++)
       
   465 		{
       
   466 		CHlpFileEntry* newEntry = CHlpFileEntry::NewLC(aDrive, (*dirList)[i].iName);
       
   467 		__PRINT_FILE_NO(KFoundEntry, *newEntry, i);
       
   468 
       
   469 		//check if new file already in the list
       
   470 		TBool foundMatch=EFalse;
       
   471 		TInt existingEntryCount=list->Count();
       
   472 		for(TInt j=existingEntryCount-1; j>=0; j--)
       
   473 			{
       
   474 			if(list->At(j)->Name().CompareF(newEntry->Name())==0)
       
   475 				{
       
   476 				__PRINT_FILE_NO(KDuplicateEntry, *newEntry, i);
       
   477 				foundMatch=ETrue;
       
   478 				}
       
   479 			}
       
   480 
       
   481 		if(!foundMatch)
       
   482 			{
       
   483 			__PRINT_FILE_NO(KAddNewEntry, *newEntry, i);
       
   484 			list->AppendL(newEntry);
       
   485 			CleanupStack::Pop(newEntry);
       
   486 			}
       
   487 		else
       
   488 			CleanupStack::PopAndDestroy(newEntry);
       
   489 		}
       
   490 	CleanupStack::PopAndDestroy(dirList);
       
   491 
       
   492 	return list;
       
   493 	}
       
   494 
       
   495 EXPORT_C void CHlpModel::CloseL()
       
   496 /** Closes all open help files. */
       
   497 	{
       
   498 	const TInt KDatabaseCount = DatabaseCount();
       
   499 	for (TInt i=0; i<KDatabaseCount; i++)
       
   500 		iDatabases->At(i)->Close();
       
   501 	iDatabases->ResetAndDestroy();
       
   502 	}
       
   503 
       
   504 
       
   505 //
       
   506 //
       
   507 //
       
   508 
       
   509 /**
       
   510 Opens a specified help file.
       
   511 
       
   512 @param aFileName Help file to open
       
   513 */
       
   514 EXPORT_C void CHlpModel::OpenFileL(const TDesC& aFileName)
       
   515 	{
       
   516 	TEntry entry;
       
   517 	User::LeaveIfError(iFsSession.Entry(aFileName, entry));
       
   518 	if	(entry.IsDir())
       
   519 		{
       
   520 		return; // don't try and open directories as help files ;)
       
   521 		}
       
   522 
       
   523 	TParsePtrC parser(aFileName);
       
   524 	if (parser.Path() != KHlpFileSearchPath)
       
   525 		{ // given file is outside \\Resource\\Help\\ directory.
       
   526 		User::Leave(KErrArgument);
       
   527 		}
       
   528 
       
   529 	if	(!(entry[0] == KPermanentFileStoreLayoutUid && entry[1] == KUidHlpApp))
       
   530 		{
       
   531 		User::Leave(KErrArgument);
       
   532 		}
       
   533 
       
   534 	CHlpDatabase* newDatabase = CHlpDatabase::NewLC(iFsSession, aFileName);
       
   535  	iDatabases->AppendL(newDatabase);
       
   536 	CleanupStack::Pop(newDatabase);
       
   537 	}
       
   538 
       
   539 EXPORT_C void CHlpModel::CloseFileL(const TDesC& aFileName)
       
   540 /** Closes a specified help file.
       
   541 
       
   542 @param aFileName Help file to close */
       
   543 	{
       
   544 	const TInt KDatabaseCount = DatabaseCount();
       
   545 	for (TInt i=0; i<KDatabaseCount; i++)
       
   546 		{
       
   547 		CHlpDatabase* database = iDatabases->At(i);
       
   548 		if	(database->FileName() == aFileName)
       
   549 			{
       
   550 			delete database;
       
   551 			iDatabases->Delete(i);
       
   552 			return;
       
   553 			}
       
   554 		}
       
   555 	User::Leave(KErrNotFound);
       
   556 	}
       
   557 
       
   558 //
       
   559 //
       
   560 //
       
   561 
       
   562 EXPORT_C void CHlpModel::ContextSearchL(TCoeHelpContext& aContext)
       
   563 /** Searches for a topic with the specified help context.
       
   564 
       
   565 A successful search generates an ETopicAvailable event. The topic can then
       
   566 be retrieved using LoadTopicL().
       
   567 
       
   568 An unsuccessful search generates an ETopicNotFound event.
       
   569 
       
   570 @param aContext Help context to search for */
       
   571 	{
       
   572 	// Set up ready for search
       
   573 	ResetReadyForSearch();
       
   574 	SetSearchType(EContextSearch);
       
   575 
       
   576 	// See if we can find the specified context in any of the meta
       
   577 	// data that each database contains. This reduces the time taken to
       
   578 	// perform a search, as only the database which actually contains the
       
   579 	// correct information actually has the SQL executed on it (major time saver).
       
   580 	TInt db = MatchUidL(aContext.iMajor);
       
   581 	if	(db >= KErrNone)
       
   582 		{
       
   583 		// Search the specified database for the context. If this context is
       
   584 		// found then the view will be prepared ready for the caller to extract
       
   585 		// the topic.
       
   586 		iCurrentDb = db;
       
   587 		TInt searchResult = CurrentDatabase()->ContextSearchL(aContext.iContext);
       
   588 		ReportEventToObserverL(searchResult);
       
   589 		}
       
   590 	else
       
   591 		{
       
   592 		ReportEventToObserverL(ETopicNotFound);
       
   593 		}
       
   594 	}
       
   595 
       
   596 EXPORT_C void CHlpModel::CategoryUIDSearchL(TUid aCategoryUID)
       
   597 /** Searches for topics with the specified help category UID.
       
   598 
       
   599 A successful search generates an ETopicListAvailable event. The list can then
       
   600 be retrieved using LoadListL().
       
   601 
       
   602 An unsuccessful search generates an ETopicListNoneFound event.
       
   603 
       
   604 @param aCategoryUID Category UID to search for */
       
   605 	{
       
   606 	// Set up ready for search
       
   607 	ResetReadyForSearch();
       
   608 	SetSearchType(ETopicListForCategoryUID);
       
   609 
       
   610 	// See if we can find the specified category Uid in any of the meta
       
   611 	// data that each database contains. This reduces the time taken to
       
   612 	// perform a search, as only the database which actually contains the
       
   613 	// correct information actually has the SQL executed on it (major time saver).
       
   614 	TInt db=MatchUidL(aCategoryUID);
       
   615 	if	(db >= KErrNone)
       
   616 		{
       
   617 		iTransientCategoryUid = aCategoryUID;
       
   618 		iCurrentDb=db;
       
   619 
       
   620 		TBuf<32> buf;
       
   621 		buf.Num(STATIC_CAST(TUint, aCategoryUID.iUid));
       
   622 		DoSearchL(ETopicListForCategoryUID, buf);
       
   623 
       
   624 		// Reset the category uid after we've done the search (used in
       
   625 		// debug invariant state check)
       
   626 		iTransientCategoryUid = KNullUid;
       
   627 		}
       
   628 	else
       
   629 		{
       
   630 		ReportEventToObserverL(ETopicNotFound);
       
   631 		}
       
   632 	}
       
   633 
       
   634 EXPORT_C void CHlpModel::TopicSearchL(const CHlpItem& aHelpItem)
       
   635 /** Searches for a topic for the specified help item.
       
   636 
       
   637 A successful search generates an ETopicAvailable event. The topic can then
       
   638 be retrieved using LoadTopicL().
       
   639 
       
   640 An unsuccessful search generates an ETopicNotFound event.
       
   641 
       
   642 @param aHelpItem Help item to search for */
       
   643 	{
       
   644 	// aHelpItem contains the information required for a speedy retrieval
       
   645 	// of the specified topic from the help model. Using it's topic Id (iId)
       
   646 	// category uid (CategoryUid()) and help file uid (HelpFileUid()) we
       
   647 	// can run the search SQL on exactly the right database file, for exactly
       
   648 	// the right category, and exactly the right topic.
       
   649 
       
   650 	// if already searching, dont start another search
       
   651 	if(iFound && CurrentSearchType()==ETopicIdSearch)
       
   652 		return;
       
   653 
       
   654 	// Set up ready for search
       
   655 	ResetReadyForSearch();
       
   656 	SetSearchType(ETopicIdSearch);
       
   657 
       
   658 	TInt count = DatabaseCount();
       
   659 	for(TInt i=0; i<count; i++)
       
   660 		{
       
   661 		CHlpDatabase* database = iDatabases->At(i);
       
   662 		if	(database->HelpFileUid() == aHelpItem.HelpFileUid())
       
   663 			{
       
   664 			// Run the SQL on this database.
       
   665 			iCurrentDb = i;
       
   666 			TInt result = database->TopicIdSearchL(aHelpItem.CategoryUid(), STATIC_CAST(TUint, aHelpItem.iId));
       
   667 			iFound = (result == ETopicAvailable);
       
   668 			ReportEventToObserverL(result);
       
   669 			return;
       
   670 			}
       
   671 		}
       
   672 	ReportEventToObserverL(ETopicNotFound);
       
   673 	}
       
   674 
       
   675 EXPORT_C void CHlpModel::IndexSearchL(const CHlpItem& aHelpItem)
       
   676 /** Searches for index entries for the specified help item.
       
   677 
       
   678 A successful search generates an ETopicListAvailable event. The list can then
       
   679 be retrieved using LoadListL().
       
   680 
       
   681 An unsuccessful search generates an ETopicListNoneFound event.
       
   682 
       
   683 @param aHelpItem Help item to search for */
       
   684 	{
       
   685 	// Set up ready for search
       
   686 	ResetReadyForSearch();
       
   687 	SetSearchType(ETopicIdSearch);
       
   688 
       
   689 	TInt count = DatabaseCount();
       
   690 	for(TInt i=0; i<count; i++)
       
   691 		{
       
   692 		CHlpDatabase* database = iDatabases->At(i);
       
   693 		if	(database->HelpFileUid() == aHelpItem.HelpFileUid())
       
   694 			{
       
   695 			// Run the SQL on this database.
       
   696 			iCurrentDb = i;
       
   697 
       
   698 			TBuf<KHlpModelNumericValueSize> buf;
       
   699 			buf.Num(STATIC_CAST(TUint, aHelpItem.iId));
       
   700 			DoSearchL(EIndexSearch, buf);
       
   701 
       
   702 			return;
       
   703 			}
       
   704 		}
       
   705 	ReportEventToObserverL(EIndexSearchListNoneFound);
       
   706 	}
       
   707 
       
   708 //
       
   709 //
       
   710 //
       
   711 
       
   712 EXPORT_C void CHlpModel::SearchL(TInt aType, TUint32 aId)
       
   713 /** Searches using a specified type of search with a numeric criterion.
       
   714 
       
   715 @param aType Type of search. This is a search type (EIndexList etc.) enum
       
   716 value.
       
   717 @param aId Numeric search criterion */
       
   718 	{
       
   719 	if	(aType == ETopicListForCategoryUID)
       
   720 		iTransientCategoryUid = TUid::Uid(aId);
       
   721 
       
   722 	TBuf<KHlpModelNumericValueSize> buf;
       
   723 	buf.Num(STATIC_CAST(TUint, aId));
       
   724 	SearchL(aType, buf);
       
   725 	}
       
   726 
       
   727 EXPORT_C void CHlpModel::SearchL(TInt aType, HBufC* aCriterion)
       
   728 /** Searches using a specified type of search, allowing a NULL seach criterion.
       
   729 
       
   730 @param aType Type of search. This is a search type (EIndexList etc.) enum
       
   731 value.
       
   732 @param aCriterion String search criterion. This can be NULL if the search type
       
   733 requires no search criterion. */
       
   734 	{
       
   735 	// Kludge to remain source compatible in App Engines 5.2
       
   736 	// This function should be removed.
       
   737 	if	(aCriterion)
       
   738 		SearchL(aType, *aCriterion);
       
   739 	else
       
   740 		SearchL(aType, KNullDesC);
       
   741 	}
       
   742 
       
   743 EXPORT_C void CHlpModel::SearchL(TInt aType, const TDesC& aCriterion)
       
   744 //
       
   745 //	This function is the base of all the SearchL(...) methods, i.e. it is callled
       
   746 //	by SearchL(TInt, HBufC*) and also SearchL(TInt, TUint32)
       
   747 //
       
   748 /** Searches using a specified type of search with a string search criterion.
       
   749 
       
   750 Note that the full text search, EFullTextSearch, is asynchronous.
       
   751 
       
   752 @param aType Type of search. This is a search type (EIndexList etc.) enum
       
   753 value.
       
   754 @param aCriterion String search criterion */
       
   755 	{
       
   756 	// Set up ready for search
       
   757 	ResetReadyForSearch();
       
   758 
       
   759 	// Do the actual search itself.
       
   760 	DoSearchL(aType, aCriterion);
       
   761 	}
       
   762 
       
   763 EXPORT_C TInt CHlpModel::CancelSearch()
       
   764 /** Cancels a full text search.
       
   765 
       
   766 @return KErrNone if successful, KErrArgument if a search is not in progress */
       
   767 	{
       
   768 	iSearch->CancelEvaluator();
       
   769 
       
   770 	if	(CurrentSearchType() != EFullTextSearch)
       
   771 		return KErrArgument;
       
   772 
       
   773 	return KErrNone;
       
   774 	}
       
   775 
       
   776 //
       
   777 //
       
   778 //
       
   779 
       
   780 EXPORT_C void CHlpModel::LoadTopicL(CRichText& aRichText, TDes& aTitle)
       
   781 /** Gets the current help topic text and title.
       
   782 
       
   783 The function assumes that a successful search has already been performed.
       
   784 
       
   785 @param aRichText On return, the help topic text
       
   786 @param aTitle On return, the help topic title */
       
   787 	{
       
   788 	// Fetch the rich text
       
   789 	LoadTopicL(aRichText);
       
   790 
       
   791 	// Next get the title
       
   792 	RDbView& view		= CurrentDatabase()->View();
       
   793 	__ASSERT_ALWAYS(view.AtRow(), Panic(EHlpNoRowAtCursor));
       
   794 	CDbColSet* colset	= view.ColSetL();
       
   795 	TDbColNo topicTitle	= colset->ColNo(KSQLTopicTitleColumn);
       
   796 	delete colset;
       
   797 
       
   798 	view.FirstL();
       
   799 	view.GetL();
       
   800 	aTitle = view.ColDes(topicTitle);
       
   801 	}
       
   802 
       
   803 EXPORT_C void CHlpModel::LoadTopicL(CRichText& aRichText)
       
   804 /** Gets the current help topic text.
       
   805 
       
   806 The function assumes that a successful search has already been performed.
       
   807 
       
   808 @param aRichText On return, the help topic text */
       
   809 	{
       
   810 	RDbView& view		= CurrentDatabase()->View();
       
   811 	__ASSERT_ALWAYS(view.CountL(), Panic(EHlpTopicNoRowsInView));
       
   812 
       
   813 	CDbColSet* colset	= view.ColSetL();
       
   814 	TDbColNo topicCol	= colset->ColNo(KSQLTopicTextColumn);
       
   815 	TDbColNo markupCol	= colset->ColNo(KSQLTopicMarkupColumn);
       
   816 	delete colset;
       
   817 	view.FirstL();
       
   818 	view.GetL();
       
   819 
       
   820 	aRichText.Reset();
       
   821 	TInt len = view.ColLength(topicCol);
       
   822 	HBufC* buf = HBufC::NewLC(len);
       
   823 	TPtr pBuf(buf->Des());
       
   824 
       
   825 	RDbColReadStream stream;
       
   826 	stream.OpenLC(view, topicCol);
       
   827 	stream.ReadL(pBuf, len);
       
   828 	aRichText.InsertL(0, pBuf);
       
   829 	CleanupStack::PopAndDestroy(2); // stream & buf
       
   830 
       
   831 	if (!view.IsColNull(markupCol))
       
   832 		{
       
   833 		RDbColReadStream blob;
       
   834 		blob.OpenL(view, markupCol);
       
   835 
       
   836 		aRichText.SetPictureFactory(this, this);
       
   837 		CEmbeddedStore* embeddedStore = CEmbeddedStore::FromLC(blob);
       
   838 		iCurrentRichTextStore = embeddedStore;
       
   839 
       
   840 		RStoreReadStream readStream;
       
   841 		readStream.OpenLC(*embeddedStore, embeddedStore->Root());
       
   842 		aRichText.InternalizeMarkupDataL(readStream);
       
   843 		aRichText.DetachFromStoreL(CPicture::EDetachFull);
       
   844 		CleanupStack::PopAndDestroy(2); // embeddedStore, readStream
       
   845 		aRichText.SetPictureFactory(NULL, NULL);
       
   846 		iCurrentRichTextStore = NULL;
       
   847 		}
       
   848 	}
       
   849 
       
   850 EXPORT_C void CHlpModel::LoadTopicL(CHlpTopic* aTopic)
       
   851 /** Gets the current help topic.
       
   852 
       
   853 The function assumes that a successful search has already been performed.
       
   854 
       
   855 @param aTopic On return, the help topic. This is caller allocated. */
       
   856 	{
       
   857 	__ASSERT_ALWAYS(aTopic, Panic(EHlpNoTopic));
       
   858 
       
   859 	LoadTopicL(*(aTopic->TopicText()));
       
   860 
       
   861 	RDbView& view		= CurrentDatabase()->View();
       
   862 	CDbColSet* colset	= view.ColSetL();
       
   863 	TDbColNo topicTitle	= colset->ColNo(KSQLTopicTitleColumn);
       
   864 	TDbColNo topicId	= colset->ColNo(KSQLTopicIdColumn);
       
   865 	TDbColNo category	= colset->ColNo(KSQLCategoryColumn);
       
   866 	delete colset;
       
   867 
       
   868 	// Populate the topic's
       
   869 	aTopic->iTopicTitle = view.ColDes(topicTitle);
       
   870 	aTopic->iTopicId	= view.ColUint32(topicId);
       
   871 	aTopic->iCategory	= view.ColDes(category);
       
   872 	}
       
   873 
       
   874 EXPORT_C void CHlpModel::LoadListL(CHlpList* aList)
       
   875 /** Gets the current help list.
       
   876 
       
   877 The function assumes that a successful search has already been performed.
       
   878 
       
   879 @param aList On return, the help list. This is caller allocated. */
       
   880 	{
       
   881 	__ASSERT_ALWAYS(aList, Panic(EHlpNoHelpList));
       
   882 
       
   883 	// Clear all entries in the list
       
   884 	aList->Reset();
       
   885 
       
   886 	// This loop provides the mechanism by which we iterate through every database
       
   887 	// in the help model. We query each database in turn to find out a) if it has
       
   888 	// been searched in the first place (not every search results in *every* help
       
   889 	// file's database view being initialised) and b) if it actually contains any
       
   890 	// results.
       
   891 	const TInt KDatabaseCount = DatabaseCount();
       
   892 	for (TInt i=0; i < KDatabaseCount; i++)
       
   893 		{
       
   894 		// Get a help database pointer and it's view.
       
   895 		CHlpDatabase* currentDatabase = iDatabases->At(i);
       
   896 		RDbView& view = currentDatabase->View();
       
   897 
       
   898 		// Does this database meet the criteria described above (points a & b)?
       
   899 		if	(!currentDatabase->ViewReady() || !view.CountL())
       
   900 			continue; // Doesn't meet criteria, so skip this database
       
   901 
       
   902 		// Criteria satisifed, so look up the column id's we're interested in.
       
   903 		CDbColSet* colset		= view.ColSetL();
       
   904 		TDbColNo colTitle		= colset->ColNo(KSQLTopicTitleColumn);
       
   905 		TDbColNo colTopicId		= colset->ColNo(KSQLTopicIdColumn);
       
   906 		TDbColNo colCategoryId	= colset->ColNo(KSQLCategoryUidColumn);
       
   907 		TDbColNo colIndex		= colset->ColNo(KSQLIndexColumn);
       
   908 		TDbColNo colIndexId		= colset->ColNo(KSQLIndexIdColumn);
       
   909 		delete colset;
       
   910 
       
   911 		// Each topic is associated with a particular category. This information
       
   912 		// is cached with the help item so that we can ensure we restore the
       
   913 		// topic relating to the category searched (topic id's are not unique, they
       
   914 		// are assigned in increasing numerical order by the help compiler, on a
       
   915 		// category basis. Category ids, however, are unique, hence we need to store
       
   916 		// both in order to be able to restore the correct topic text).
       
   917 		view.FirstL();
       
   918 		view.GetL();
       
   919 
       
   920 		// Iterate through each row in this database's view, and store each entry
       
   921 		// as a help item in the list passed as a parameter to this function.
       
   922 		FOREVER
       
   923 			{
       
   924 			CHlpItem* item = NULL;
       
   925 
       
   926 			// This bit loads different content into the help item depending on the last performed
       
   927 			// search type.
       
   928 			switch (iSearchType)
       
   929 				{
       
   930 			case ECategoryList:
       
   931 			case ETopicListForCategory:
       
   932 			case ETopicListForCategoryUID:
       
   933 				item = CHlpItem::NewLC(view.ColDes(colTitle), view.ColUint32(colTopicId), TUid::Uid(view.ColUint(colCategoryId)), currentDatabase->HelpFileUid());
       
   934 				break;
       
   935 			case EIndexList:
       
   936 				item = CHlpItem::NewLC(view.ColDes(colIndex), view.ColUint32(colIndexId), currentDatabase->HelpFileUid());
       
   937 				break;
       
   938 			case EQuickSearch:
       
   939 			case EFullTextSearch:
       
   940 			case EIndexSearch:
       
   941 				item = CHlpItem::NewLC(view.ColDes(colTitle), view.ColUint32(colTopicId), TUid::Uid(view.ColUint(colCategoryId)), currentDatabase->HelpFileUid());
       
   942 				break;
       
   943 			default:
       
   944 				User::Leave(KErrNotSupported);
       
   945 				}
       
   946 
       
   947 			aList->AppendL(item);
       
   948 			CleanupStack::Pop(item);
       
   949 			view.NextL();
       
   950 			if	(view.AtEnd())
       
   951 				break;
       
   952 			view.GetL();
       
   953 			}
       
   954 		}
       
   955 	}
       
   956 
       
   957 EXPORT_C void CHlpModel::CategoryListL(CDesCArray* aList)
       
   958 /** Populates a list of available help categories.
       
   959 
       
   960 This can be called without needing to perform a prior search.
       
   961 
       
   962 @param aList On return, the list of available help categories. This is caller
       
   963 allocated. */
       
   964 	{
       
   965 	__ASSERT_ALWAYS(aList, Panic(EHlpNoCategoryList));
       
   966 
       
   967 	const TInt count = DatabaseCount();
       
   968 	for(TInt i=0; i<count; i++)
       
   969 		iDatabases->At(i)->AppendCategoryListL(*aList);
       
   970 	aList->Sort();
       
   971 	}
       
   972 
       
   973 //
       
   974 //
       
   975 //
       
   976 
       
   977 EXPORT_C void CHlpModel::SetZoomSizeL(THlpZoomState aState)
       
   978 /** Sets the zoom size to use for help text and pictures.
       
   979 
       
   980 @param aState Zoom size */
       
   981 	{
       
   982 	iZoomSize = aState;
       
   983 	const TInt count = iPictures->Count();
       
   984 	for (TInt i=0; i<count; i++)
       
   985 		{
       
   986 		// Fetch a picture from the array
       
   987 		CHlpPicture* picture = iPictures->At(i);
       
   988 		picture->HandleZoomChangedL(iZoomSize);
       
   989 		}
       
   990 	}
       
   991 
       
   992 EXPORT_C THlpZoomState CHlpModel::ZoomSize() const
       
   993 /** Gets the zoom size used for help text and pictures.
       
   994 
       
   995 @return Zoom size */
       
   996 	{
       
   997 	return iZoomSize;
       
   998 	}
       
   999 
       
  1000 /* Sets the iZoomFactors array to the appropriate
       
  1001 zoom factor value, depending on the current zoom state
       
  1002 as dictated by the aZoomState argument variable.
       
  1003 
       
  1004 The hlpmodel's THlpZoomState enumerated type is related to
       
  1005 the AppUI's TZoomStates enumerated type. This relation is required
       
  1006 so that the correct pixels to twips ratio can be used in the
       
  1007 CHlpPicture::GetOriginalSizeInTwips() method.
       
  1008 
       
  1009 Error Condition	: None.
       
  1010 @param aZoomState A zoom size.
       
  1011 @param aFactor The zoom factor that corresponds to the current zoom size.
       
  1012 @pre None.
       
  1013 @post The iZoomFactors data member has been populated with the appropriate
       
  1014 zoom factor values. */
       
  1015 EXPORT_C void CHlpModel::SetZoomFactors(THlpZoomState aZoomState, TInt aFactor)
       
  1016 /** Sets a zoom factor for a logical zoom size.
       
  1017 
       
  1018 @param aZoomState Logical zoom size for which to set the factor.
       
  1019 @param aFactor Zoom factor. For example, 2 specifies double size. */
       
  1020 	{
       
  1021 	__ASSERT_ALWAYS(iZoomFactors->Count() == 3, Panic(EHlpNotEnoughZoomRatios));
       
  1022 	//
       
  1023 	switch(aZoomState)
       
  1024 		{
       
  1025 	/*
       
  1026 	 * If zoom state is large, assign zoom factor 750
       
  1027 	 * to index 0 of 'iZoomFactors'
       
  1028 	 */
       
  1029 	case EHlpZoomStateSmall:
       
  1030 		iZoomFactors->At(EHlpZoomStateSmall) = aFactor;
       
  1031 		break;
       
  1032 
       
  1033 	default:
       
  1034 	/*
       
  1035 	 * If zoom state is large, assign zoom factor 1000
       
  1036 	 * to index 1 of 'iZoomFactors'
       
  1037 	 */
       
  1038 	case EHlpZoomStateMedium:
       
  1039 		iZoomFactors->At(EHlpZoomStateMedium) = aFactor;
       
  1040 		break;
       
  1041 	/*
       
  1042 	 * If zoom state is large, assign zoom factor 1250
       
  1043 	 * to index 2 of 'iZoomFactors'
       
  1044 	 */
       
  1045 	case EHlpZoomStateLarge:
       
  1046 		iZoomFactors->At(EHlpZoomStateLarge) = aFactor;
       
  1047 		break;
       
  1048 		}
       
  1049 	}
       
  1050 
       
  1051 /*
       
  1052 Accesses the iZoomFactors data member, and returns
       
  1053 the current zoom factor, depending on the value of
       
  1054 the current zoom state, which is to be used for the
       
  1055 pixel scaling of a picture in CHlpPicture::GetOriginalSizeInTwips().
       
  1056 Error Condition	: None
       
  1057 
       
  1058 @return The zoom factor, corresponding to the current zoom size.
       
  1059 @pre None.
       
  1060 @post Current zoom factor is returned. */
       
  1061 TInt CHlpModel::CurrentZoomFactor() const
       
  1062 	{
       
  1063 	__ASSERT_ALWAYS(iZoomFactors->Count() == 3, Panic(EHlpNotEnoughZoomRatios));
       
  1064 	//
       
  1065 	switch (iZoomSize)
       
  1066 		{
       
  1067 	case EHlpZoomStateSmall:
       
  1068 		return iZoomFactors->At(EHlpZoomStateSmall);
       
  1069 	default:
       
  1070 	case EHlpZoomStateMedium:
       
  1071 		return iZoomFactors->At(EHlpZoomStateMedium);
       
  1072 	case EHlpZoomStateLarge:
       
  1073 		return iZoomFactors->At(EHlpZoomStateLarge);
       
  1074 		}
       
  1075 	}
       
  1076 
       
  1077 /* Removes a CHlpPicture from the iPictures array.
       
  1078 
       
  1079 Error Condition	: None
       
  1080 
       
  1081 @param aHelpPicture A pointer to a CHlpPicture object.
       
  1082 @pre A valid CHlpPicture is passed to the function.
       
  1083 @post CHlpPicture's that are no longer displayed have been removed
       
  1084 from the iPictures data member. */
       
  1085 void CHlpModel::RemoveHelpPicture(CHlpPicture* aHelpPicture)
       
  1086 	{
       
  1087 	if (iPictures != 0)
       
  1088 	{
       
  1089 	const TInt count = iPictures->Count();
       
  1090 	__ASSERT_DEBUG(count > 0, User::Invariant());
       
  1091 	//
       
  1092 	for(TInt i=0; i<count; i++)
       
  1093 		{
       
  1094 		if	(aHelpPicture == iPictures->At(i))
       
  1095 			{
       
  1096 			iPictures->Delete(i);
       
  1097 			return;
       
  1098 			}
       
  1099 		}
       
  1100 	__ASSERT_DEBUG(EFalse, Panic(EHlpUnlocatedHelpPicture));
       
  1101 	}
       
  1102 	}
       
  1103 
       
  1104 
       
  1105 //
       
  1106 //
       
  1107 //
       
  1108 
       
  1109 /* This is a mixin callback required to restore pictures
       
  1110 from the help model database into the topic rich text.
       
  1111 Because pictures are stored in their own picture table within the
       
  1112 help database (this means that the same picture may be used many
       
  1113 times within the rich text, but will only actually appear once
       
  1114 in the database - a major space saver) the restoration function
       
  1115 must have a primed view so that it knows which database to use
       
  1116 as the source picture table.
       
  1117 
       
  1118 @param aHdr A reference to a picture header.
       
  1119 @param aDeferredPictureStore A stream store where the pictures are kept.
       
  1120 @pre A valid picture database must exist, so that the stream store can relate to.
       
  1121 @post A TInt pointer (index) to the picture table is inserted
       
  1122 in the rich text to indicate which picture needs restoring.
       
  1123 The CHlpPicture looks up this index in the picture table. */
       
  1124 void CHlpModel::NewPictureL(TPictureHeader& aHeader, const CStreamStore& aDeferredPictureStore) const
       
  1125 	{
       
  1126 	if	(aHeader.iPictureType != KUidHelpImage)
       
  1127 		User::Leave(KErrNotSupported);
       
  1128 	if	(!aHeader.iPicture.IsId())
       
  1129 		User::Leave(KErrBadHandle);
       
  1130 
       
  1131 	TStreamId id = aHeader.iPicture.AsId();
       
  1132 	CHlpPicture* picture = CHlpPicture::NewLC(aDeferredPictureStore, id, *CurrentDatabase(), *const_cast<CHlpModel*>(this));
       
  1133 	aHeader.iPicture = picture;
       
  1134 
       
  1135 	// Add picture to the picture array. We need to do this so that we can update the picture
       
  1136 	// when the zoom size is changed by the UI.
       
  1137 	iPictures->AppendL(picture);
       
  1138 
       
  1139 	CleanupStack::Pop(picture);
       
  1140 	}
       
  1141 
       
  1142 EXPORT_C const CStreamStore& CHlpModel::StreamStoreL(TInt /*aPos*/) const
       
  1143 /** Gets the current rich text store.
       
  1144 
       
  1145 @param aPos Unused
       
  1146 @return Current rich text store */
       
  1147 	{
       
  1148 	__ASSERT_ALWAYS(iCurrentRichTextStore, Panic(EHlpNoPictureStore));
       
  1149 	return *iCurrentRichTextStore;
       
  1150 	}
       
  1151 
       
  1152 //
       
  1153 //
       
  1154 //
       
  1155 
       
  1156 EXPORT_C TInt CHlpModel::MatchUidL(TUid aUid)
       
  1157 /** Searches the open help databases for the specified topic UID.
       
  1158 
       
  1159 @param aUid Topic UID to search for
       
  1160 @return Index of the database if the item was found, or KErrNotFound if not */
       
  1161 	{
       
  1162 	const TInt KDatabaseCount = DatabaseCount();
       
  1163 	for (TInt i=0; i<KDatabaseCount; i++)
       
  1164 		{
       
  1165 		if (iDatabases->At(i)->MatchUidL(aUid))
       
  1166 			return i;
       
  1167 		}
       
  1168 	return KErrNotFound;
       
  1169 	}
       
  1170 
       
  1171 EXPORT_C void CHlpModel::SetObserver(MHlpModelObserver* aObserver)
       
  1172 /** Sets the client callback interface.
       
  1173 
       
  1174 @param aObserver Client callback interface */
       
  1175 	{
       
  1176 	iObserver = aObserver;
       
  1177 	}
       
  1178 
       
  1179 //
       
  1180 //
       
  1181 //
       
  1182 
       
  1183 void CHlpModel::DoSearchL(TInt aType, const TDesC& aCriterion)
       
  1184 	{
       
  1185 	// Initialise the member data with the type of search we are about to perform,
       
  1186 	// and also setup the search criteria which is needed to peform multiple searches
       
  1187 	// across databases.
       
  1188 	SetSearchType(aType);
       
  1189 	SetCriterionL(aCriterion);
       
  1190 
       
  1191 	if	(!DatabaseCount())
       
  1192 		{
       
  1193 		ReportEventToObserverL(ETopicNotFound);
       
  1194 		return;
       
  1195 		}
       
  1196 
       
  1197 	// Prepare the searcher with the database to search
       
  1198 	iSearch->SetDatabase(*CurrentDatabase());
       
  1199 
       
  1200 	// Indicate that this database is being searched, and therefore it is guaranteed not
       
  1201 	// to have a null view
       
  1202 	CurrentDatabase()->SetViewReady(ETrue);
       
  1203 
       
  1204 	// Get the searcher to actually do the search, which includes
       
  1205 	// building the necessary SQL statement and then running the SQL on the
       
  1206 	// correct table.
       
  1207 	iSearch->SearchL(aType, *iCriterion);
       
  1208 	}
       
  1209 
       
  1210 void CHlpModel::DoNextSearchL()
       
  1211 //
       
  1212 //	This function is used to perform an incremental search (mirroring an inner join which
       
  1213 //	EPOC DBMS doesn't support) across multiple databases.
       
  1214 //
       
  1215 	{
       
  1216 	if	(iCurrentDb < DatabaseCount()-1)
       
  1217 		{
       
  1218 		// If we're peforming a category Uid-based search, then
       
  1219 		// we only run the sql seach on the databases that actually
       
  1220 		// hold meta data on the specified category.
       
  1221 		iCurrentDb++;
       
  1222 		if	(CurrentSearchType() == ETopicListForCategoryUID)
       
  1223 			{
       
  1224 			__ASSERT_DEBUG(iTransientCategoryUid != KNullUid, Panic(EHlpFault));
       
  1225 			TInt numberOfMatches = 0;
       
  1226 			do
       
  1227 				{
       
  1228 				if	(CurrentDatabase()->MatchUidL(iTransientCategoryUid))
       
  1229 					{
       
  1230 					// This database does have meta data on the specified category,
       
  1231 					// so it's worth running the check
       
  1232 					DoSearchL(CurrentSearchType(), *iCriterion);
       
  1233 					++numberOfMatches;
       
  1234 					}
       
  1235 				}
       
  1236 			while (++iCurrentDb < DatabaseCount());
       
  1237 			if	(numberOfMatches == 0)
       
  1238 				ReportEventToObserverL(ESearchComplete);
       
  1239 			}
       
  1240 		else
       
  1241 			{
       
  1242 			// Doesn't matter what type of search it is, we still
       
  1243 			// run the SQL :(
       
  1244 			DoSearchL(CurrentSearchType(), *iCriterion);
       
  1245 			}
       
  1246 		}
       
  1247 	else
       
  1248 		{
       
  1249 		ReportEventToObserverL(ESearchComplete);
       
  1250 		}
       
  1251 	}
       
  1252 
       
  1253 void CHlpModel::ResetReadyForSearch()
       
  1254 //
       
  1255 //	This function is called regardless of search type - it prepares all the necessary
       
  1256 //	variables ready for a search.
       
  1257 //
       
  1258 	{
       
  1259 	// Set to the first database
       
  1260 	iCurrentDb=0;
       
  1261 
       
  1262 	// Indicate that we've currently not found any results
       
  1263 	iFound=EFalse;
       
  1264 
       
  1265 	// Reset the database views to 'not yet ready'
       
  1266 	ResetViews();
       
  1267 	}
       
  1268 
       
  1269 void CHlpModel::ResetViews()
       
  1270 //
       
  1271 //	Go through each database and reset the "view ready" flag to EFalse
       
  1272 //	to indicate that this particular database's view has not yet been primed.
       
  1273 //
       
  1274 	{
       
  1275 	const TInt count = DatabaseCount();
       
  1276 	for(TInt i=0; i<count; i++)
       
  1277 		iDatabases->At(i)->SetViewReady(EFalse); // not ready
       
  1278 	}
       
  1279 
       
  1280 void CHlpModel::SetCriterionL(const TDesC& aCriterion)
       
  1281 //
       
  1282 //	Updates the internal iCriterion pointer to contain the new
       
  1283 //	criteria for searching.
       
  1284 //
       
  1285 	{
       
  1286 	HBufC* newCriteria = aCriterion.AllocL();
       
  1287 	delete iCriterion;
       
  1288 	iCriterion = newCriteria;
       
  1289 	}
       
  1290 
       
  1291 RDbView* CHlpModel::CurrentView() const
       
  1292 	{
       
  1293 	return &(CurrentDatabase()->View());
       
  1294 	}
       
  1295 
       
  1296 //
       
  1297 //
       
  1298 //
       
  1299 
       
  1300 void CHlpModel::HandleDbEventL(TInt aEvent)
       
  1301 //
       
  1302 //	Called by the SQL searcher. This function routes responses from the searcher
       
  1303 //	to the model observer, and performs and recursive searching that is required.
       
  1304 //
       
  1305 	{
       
  1306 	switch(aEvent)
       
  1307 		{
       
  1308 	case ENoRecordsFound:
       
  1309 		// No records were found for this search. If a context search was requested,
       
  1310 		// we indicate that nothing was found and let the observer of the database
       
  1311 		// perform any action. Otherwise, we search the next database in turn.
       
  1312 		if	(CurrentSearchType() != ETopicIdSearch &&
       
  1313 			 CurrentSearchType() != EContextSearch &&
       
  1314 			 CurrentSearchType() != EIndexSearch
       
  1315 			)
       
  1316 			DoNextSearchL();
       
  1317 		else
       
  1318 			ReportEventToObserverL(ENoRecordsFound);
       
  1319 		break;
       
  1320 	case ESearchComplete:
       
  1321 		// Indicate that at least some matching critera was found and then
       
  1322 		// either end the search, or search the next database.
       
  1323 		iFound=ETrue;
       
  1324 		if	(CurrentSearchType() != ETopicIdSearch &&
       
  1325 			 CurrentSearchType() != EContextSearch &&
       
  1326 			 CurrentSearchType() != EIndexSearch
       
  1327 			)
       
  1328 			DoNextSearchL();
       
  1329 		else
       
  1330 			ReportEventToObserverL(ESearchComplete);
       
  1331 		break;
       
  1332 	case ESearchInProgress:
       
  1333 		// Indicate to the observer that a search is in progress
       
  1334 		ReportEventToObserverL(ESearchInProgress);
       
  1335 		break;
       
  1336 	case EHlpSearchCancelled:
       
  1337 		// Indicate to the observer that a search was cancelled
       
  1338 		ReportEventToObserverL(EHlpSearchCancelled);
       
  1339 		break;
       
  1340 	default:
       
  1341 		__ASSERT_DEBUG(EFalse, Panic(EHlpFault));
       
  1342 		break;
       
  1343 		}
       
  1344 	}
       
  1345 
       
  1346 void CHlpModel::ReportEventToObserverL(TInt aEvent)
       
  1347 	{
       
  1348 	if	(!iObserver)
       
  1349 		return; // can't do anything without an observer
       
  1350 
       
  1351 	switch(aEvent)
       
  1352 		{
       
  1353 	case ESearchInProgress:
       
  1354 		iObserver->HandleModelEventL(EModelSearchInProgress);
       
  1355 		return;
       
  1356 	case EHlpSearchCancelled:
       
  1357 		iObserver->HandleModelEventL(EHlpSearchCancelled);
       
  1358 		return;
       
  1359 	default: // Keep GCC happy
       
  1360 		break;
       
  1361 		}
       
  1362 
       
  1363 	switch(CurrentSearchType())
       
  1364 		{
       
  1365 	case EIndexList:
       
  1366 		iObserver->HandleModelEventL((iFound?EIndexListAvailable:EIndexListNoneFound));
       
  1367 		break;
       
  1368 	case ECategoryList:
       
  1369 		iObserver->HandleModelEventL((iFound?ECategoryListAvailable:ECategoryListNoneFound));
       
  1370 		break;
       
  1371 	case ETopicListForCategory:
       
  1372 	case ETopicListForCategoryUID:
       
  1373 		iObserver->HandleModelEventL((iFound?ETopicListAvailable:ETopicListNoneFound));
       
  1374 		break;
       
  1375 	case EContextSearch:
       
  1376 		iObserver->HandleModelEventL(aEvent);
       
  1377 		break;
       
  1378 	case EIndexSearch:
       
  1379 		iObserver->HandleModelEventL((iFound?EIndexSearchListAvailable:EIndexSearchListNoneFound));
       
  1380 		break;
       
  1381 	case EQuickSearch:
       
  1382 	case EFullTextSearch:
       
  1383 		iObserver->HandleModelEventL((iFound?ESearchListAvailable:ESearchListNoneFound));
       
  1384 		break;
       
  1385 	case ETopicIdSearch:
       
  1386 		iObserver->HandleModelEventL((iFound?ETopicAvailable:ETopicNotFound));
       
  1387 		// event has been reported, reset now.
       
  1388 		iFound=EFalse;
       
  1389 		break;
       
  1390 	default:
       
  1391 		__ASSERT_DEBUG(EFalse, Panic(EHlpFault));
       
  1392 		break;
       
  1393 		}
       
  1394 	}
       
  1395 
       
  1396 
       
  1397 
       
  1398 
       
  1399 
       
  1400 
       
  1401 
       
  1402 
       
  1403 //
       
  1404 // ----> CHlpList
       
  1405 //
       
  1406 
       
  1407 EXPORT_C CHlpList::~CHlpList()
       
  1408 /** Destructor. */
       
  1409 	{
       
  1410 	if(iList)
       
  1411 		iList->ResetAndDestroy();
       
  1412 	delete iList;
       
  1413 	}
       
  1414 
       
  1415 void CHlpList::ConstructL()
       
  1416 	{
       
  1417 	iList = new(ELeave) CArrayPtrFlat<CHlpItem>(2);
       
  1418 	}
       
  1419 
       
  1420 EXPORT_C CHlpList* CHlpList::NewL()
       
  1421 /** Allocates and creates a new help list object.
       
  1422 
       
  1423 @return New help list object */
       
  1424 	{
       
  1425 	CHlpList* self = CHlpList::NewLC();
       
  1426 	CleanupStack::Pop(self);
       
  1427 	return self;
       
  1428 	}
       
  1429 
       
  1430 EXPORT_C CHlpList* CHlpList::NewLC()
       
  1431 /** Allocates and creates a new help list object, leaving the object on the cleanup
       
  1432 stack.
       
  1433 
       
  1434 @return New help list object */
       
  1435 	{
       
  1436 	CHlpList* self = new(ELeave) CHlpList;
       
  1437 	CleanupStack::PushL(self);
       
  1438 	self->ConstructL();
       
  1439 	return self;
       
  1440 	}
       
  1441 
       
  1442 EXPORT_C TInt CHlpList::MdcaCount() const
       
  1443 /** Gets the number of items in the list.
       
  1444 
       
  1445 @return Number of items in the list */
       
  1446 	{
       
  1447 	return iList->Count();
       
  1448 	}
       
  1449 
       
  1450 EXPORT_C TPtrC CHlpList::MdcaPoint(TInt aIndex) const
       
  1451 /** Gets the title of the item at the specified index.
       
  1452 
       
  1453 @param aIndex Item index
       
  1454 @return Title of the item */
       
  1455 	{
       
  1456 	return TPtrC(iList->At(aIndex)->iTitle->Des());
       
  1457 	}
       
  1458 
       
  1459 EXPORT_C TUint32 CHlpList::At(TInt aIndex) const
       
  1460 /** Gets the topic ID of the item at the specified index.
       
  1461 
       
  1462 @param aIndex Item index
       
  1463 @return Topic ID */
       
  1464 	{
       
  1465 	return iList->At(aIndex)->iId;
       
  1466 	}
       
  1467 
       
  1468 EXPORT_C void CHlpList::Reset()
       
  1469 /** Resets the list. */
       
  1470 	{
       
  1471 	iList->ResetAndDestroy();
       
  1472 	}
       
  1473 
       
  1474 EXPORT_C CHlpItem* CHlpList::Item(TInt aIndex) const
       
  1475 /** Gets the item at the specified index.
       
  1476 
       
  1477 @param aIndex Item index
       
  1478 @return Item */
       
  1479 	{
       
  1480 	return iList->At(aIndex);
       
  1481 	}
       
  1482 
       
  1483 EXPORT_C TInt CHlpList::Find(TUint32 aId)
       
  1484 /** Searches the list for a specified item ID.
       
  1485 
       
  1486 @param aId Item ID
       
  1487 @return Item index, or KErrNotFound if not found */
       
  1488 	{
       
  1489 	CHlpItem* item = new CHlpItem(aId);
       
  1490 	if	(!item)
       
  1491 		return KErrNoMemory;
       
  1492 
       
  1493 	TKeyArrayFix key(_FOFF(CHlpItem, iId), ECmpTUint32);
       
  1494 	TInt pos;
       
  1495 	TInt result = iList->Find(item, key, pos);
       
  1496 	delete item;
       
  1497 
       
  1498 	if (!result)
       
  1499 		return pos;
       
  1500 	else
       
  1501 		return KErrNotFound;
       
  1502 	}
       
  1503 
       
  1504 EXPORT_C void CHlpList::AppendL(CHlpItem* aItem)
       
  1505 /** Appends an item to the list.
       
  1506 
       
  1507 @param aItem Item to add */
       
  1508 	{
       
  1509 	__ASSERT_ALWAYS(aItem, Panic(EHlpNoItem));
       
  1510 	iList->AppendL(aItem);
       
  1511 	}
       
  1512 
       
  1513 
       
  1514 
       
  1515 
       
  1516 
       
  1517 //
       
  1518 // ----> CHlpItem - representing an individual item in the help file
       
  1519 //
       
  1520 
       
  1521 CHlpItem::CHlpItem(TUint32 aId)
       
  1522 :	iId(aId), iCategoryUid(KNullUid), iHelpFileUid(KNullUid)
       
  1523 	{
       
  1524 	}
       
  1525 
       
  1526 CHlpItem::CHlpItem(TUint32 aId, TUid aHelpFileUid)
       
  1527 :	iId(aId), iCategoryUid(KNullUid), iHelpFileUid(aHelpFileUid)
       
  1528 	{
       
  1529 	}
       
  1530 
       
  1531 CHlpItem::CHlpItem(TUint32 aId, TUid aCategoryId, TUid aHelpFileUid)
       
  1532 :	iId(aId), iCategoryUid(aCategoryId), iHelpFileUid(aHelpFileUid)
       
  1533 	{
       
  1534 	}
       
  1535 
       
  1536 EXPORT_C CHlpItem::~CHlpItem()
       
  1537 /** Destructor. */
       
  1538 	{
       
  1539 	delete iTitle;
       
  1540 	}
       
  1541 
       
  1542 void CHlpItem::ConstructL(const TDesC& aTitle)
       
  1543 	{
       
  1544 	iTitle = aTitle.AllocL();
       
  1545 	}
       
  1546 
       
  1547 CHlpItem* CHlpItem::NewL(const TDesC& aTitle, TUint32 aId, TUid aCategoryId, TUid aHelpFileUid)
       
  1548 /** Allocates and creates a new help item object.
       
  1549 
       
  1550 @param aTitle Item title
       
  1551 @param aId Item ID
       
  1552 @param aCategoryId Category ID
       
  1553 @param aHelpFileUid Help file UID
       
  1554 @return New help item object */
       
  1555 	{
       
  1556 	CHlpItem* self = NewLC(aTitle, aId, aCategoryId, aHelpFileUid);
       
  1557 	CleanupStack::Pop(self);
       
  1558 	return self;
       
  1559 	}
       
  1560 
       
  1561 CHlpItem* CHlpItem::NewLC(const TDesC& aTitle, TUint32 aId, TUid aCategoryId, TUid aHelpFileUid)
       
  1562 /** Allocates and creates a new help item object, leaving the object on the cleanup
       
  1563 stack.
       
  1564 
       
  1565 @param aTitle Item title
       
  1566 @param aId Item ID
       
  1567 @param aCategoryId Category ID
       
  1568 @param aHelpFileUid Help file UID
       
  1569 @return New help item object */
       
  1570 	{
       
  1571 	CHlpItem* self = new(ELeave) CHlpItem(aId, aCategoryId, aHelpFileUid);
       
  1572 	CleanupStack::PushL(self);
       
  1573 	self->ConstructL(aTitle);
       
  1574 	return self;
       
  1575 	}
       
  1576 
       
  1577 CHlpItem* CHlpItem::NewLC(const TDesC& aTitle, TUint32 aId, TUid aHelpFileUid)
       
  1578 /** Allocates and creates a new help item object, leaving the object on the cleanup
       
  1579 stack.
       
  1580 
       
  1581 This overload does not specify a category UID.
       
  1582 
       
  1583 @param aTitle Item title
       
  1584 @param aId Item ID
       
  1585 @param aHelpFileUid Help file UID
       
  1586 @return New help item object */
       
  1587 	{
       
  1588 	CHlpItem* self = new(ELeave) CHlpItem(aId, aHelpFileUid);
       
  1589 	CleanupStack::PushL(self);
       
  1590 	self->ConstructL(aTitle);
       
  1591 	return self;
       
  1592 	}
       
  1593 
       
  1594 
       
  1595 
       
  1596 
       
  1597 
       
  1598 
       
  1599 //
       
  1600 // ----> CHlpTopic
       
  1601 //
       
  1602 
       
  1603 EXPORT_C CHlpTopic::~CHlpTopic()
       
  1604 	{
       
  1605 	delete iTopicText;
       
  1606 	delete iGlobalCharFormatLayer;
       
  1607 	delete iGlobalParaFormatLayer;
       
  1608 	}
       
  1609 
       
  1610 void CHlpTopic::ConstructL()
       
  1611 	{
       
  1612 	// Create the necessary formatting layers for the rich text object.
       
  1613 	iGlobalParaFormatLayer	= CParaFormatLayer::NewL();
       
  1614 	iGlobalCharFormatLayer	= CCharFormatLayer::NewL();
       
  1615 	iTopicText				= CRichText::NewL(iGlobalParaFormatLayer, iGlobalCharFormatLayer);
       
  1616 	}
       
  1617 
       
  1618 EXPORT_C CHlpTopic* CHlpTopic::NewL()
       
  1619 /** Allocates and creates a new help topic object.
       
  1620 
       
  1621 @return New help topic object */
       
  1622 	{
       
  1623 	CHlpTopic* self = CHlpTopic::NewLC();
       
  1624 	CleanupStack::Pop(self);
       
  1625 	return self;
       
  1626 	}
       
  1627 
       
  1628 EXPORT_C CHlpTopic* CHlpTopic::NewLC()
       
  1629 /** Allocates and creates a new help topic object, leaving the object on the cleanup
       
  1630 stack.
       
  1631 
       
  1632 @return New help topic object */
       
  1633 	{
       
  1634 	CHlpTopic* self = new(ELeave) CHlpTopic();
       
  1635 	CleanupStack::PushL(self);
       
  1636 	self->ConstructL();
       
  1637 	return self;
       
  1638 	}
       
  1639 
       
  1640 EXPORT_C void CHlpTopic::RestoreL(RDbView* aView)
       
  1641 /** Restores the object from a database view.
       
  1642 
       
  1643 This only restores text and markup, not pictures. Help application authors
       
  1644 should use CHlpModel::LoadTopicL() instead.
       
  1645 
       
  1646 @param aView Database view */
       
  1647 	{
       
  1648 	// NOTE: This function does not restore pictures because it does not know
       
  1649 	// which help model database to use as the source for the picture table.
       
  1650 	// Use CHlpModel::LoadTopicL(...) instead
       
  1651 	__ASSERT_ALWAYS(aView, Panic(EHlpNoView));
       
  1652 	__ASSERT_ALWAYS(aView->AtRow(), Panic(EHlpNoRowAtCursor));
       
  1653 
       
  1654 	aView->FirstL();
       
  1655 	CDbColSet* colset	= aView->ColSetL();
       
  1656 	TDbColNo topicCol	= colset->ColNo(KSQLTopicTextColumn);
       
  1657 	TDbColNo markupCol	= colset->ColNo(KSQLTopicMarkupColumn);
       
  1658 	TDbColNo titleCol	= colset->ColNo(KSQLTopicTitleColumn);
       
  1659 	TDbColNo catCol		= colset->ColNo(KSQLCategoryColumn);
       
  1660 	TDbColNo idCol		= colset->ColNo(KSQLTopicIdColumn);
       
  1661 	delete colset;
       
  1662 
       
  1663 	aView->GetL();
       
  1664 
       
  1665 	TInt len = aView->ColLength(topicCol);
       
  1666 	HBufC* buf=HBufC::NewLC(len);
       
  1667 	TPtr pBuf(buf->Des());
       
  1668 
       
  1669 	RDbColReadStream stream;
       
  1670 	stream.OpenLC(*aView, topicCol);
       
  1671 	stream.ReadL(pBuf, len);
       
  1672 	iTopicText->Reset();
       
  1673 	iTopicText->InsertL(0, *buf);
       
  1674 	CleanupStack::PopAndDestroy(2); // stream, buf
       
  1675 
       
  1676 	if	(!aView->IsColNull(markupCol))
       
  1677 		{
       
  1678 		RDbColReadStream blob;
       
  1679 		blob.OpenL(*aView, markupCol);
       
  1680 		CEmbeddedStore* embeddedStore = CEmbeddedStore::FromLC(blob);
       
  1681 		RStoreReadStream readStream;
       
  1682 		readStream.OpenLC(*embeddedStore, embeddedStore->Root());
       
  1683 		iTopicText->InternalizeMarkupDataL(readStream);
       
  1684 		CleanupStack::PopAndDestroy(2); // embeddedStore, readStream
       
  1685 		}
       
  1686 
       
  1687 	iCategory.Append(aView->ColDes(catCol));
       
  1688 	iTopicTitle.Append(aView->ColDes(titleCol));
       
  1689 	iTopicId=aView->ColUint32(idCol);
       
  1690 	}
       
  1691 
       
  1692 EXPORT_C CRichText* CHlpTopic::TopicText()
       
  1693 /** Gets the topic text.
       
  1694 
       
  1695 @return Topic text */
       
  1696 	{
       
  1697 	return iTopicText;
       
  1698 	}
       
  1699 
       
  1700 EXPORT_C TDesC& CHlpTopic::TopicTitle()
       
  1701 /** Gets the topic title.
       
  1702 
       
  1703 @return Topic title */
       
  1704 	{
       
  1705 	return iTopicTitle;
       
  1706 	}
       
  1707 
       
  1708 EXPORT_C TDesC& CHlpTopic::Category()
       
  1709 /** Gets the topic category.
       
  1710 
       
  1711 @return Topic category */
       
  1712 	{
       
  1713 	return iCategory;
       
  1714 	}