textrendering/texthandling/stext/Txtparse.cpp
changeset 0 1fb32624e06b
child 40 91ef7621b7fc
equal deleted inserted replaced
-1:000000000000 0:1fb32624e06b
       
     1 /*
       
     2 * Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "TXTRICH.H"
       
    20 #include "TXTSTD.H"
       
    21 #include "ParseLst.h"
       
    22 
       
    23 
       
    24 // Install and activate a particular parser, app provides instance
       
    25 EXPORT_C void CRichText::ActivateParserL(MParser* aParser)
       
    26 	{
       
    27 	CParserList* activeParserList = (CParserList*)Dll::Tls();
       
    28 	if (!activeParserList)
       
    29 		{
       
    30 		CreateParserETextTLSL();
       
    31 		activeParserList = (CParserList*)Dll::Tls();
       
    32 		}
       
    33 	activeParserList->ActivateParserL(aParser);
       
    34 	}
       
    35 
       
    36 
       
    37 // Deactivate and deinstall a particular parser, identified by ptr to instance
       
    38 EXPORT_C void CRichText::DeactivateParser(MParser* aParser)
       
    39 	{
       
    40 	CParserList* activeParserList = (CParserList*)Dll::Tls();
       
    41 	__ASSERT_DEBUG(activeParserList, Panic(EParserListNotInitialized));
       
    42 	activeParserList->DeactivateParser(aParser);
       
    43 	if ((activeParserList->iRefCount == 0) && (activeParserList->iNumberInList == 0))
       
    44 		{
       
    45 		Dll::FreeTls();
       
    46 		delete activeParserList;
       
    47 		}
       
    48 	}
       
    49 
       
    50 
       
    51 // Install and activate a parser in the default set
       
    52 EXPORT_C void CRichText::ActivateDefaultParserL(MParser* aParser)
       
    53 	{
       
    54 	CParserList* activeParserList = (CParserList*)Dll::Tls();
       
    55 	if (!activeParserList)
       
    56 		{
       
    57 		CreateParserETextTLSL();
       
    58 		activeParserList = (CParserList*)Dll::Tls();
       
    59 		}
       
    60 	activeParserList->ActivateDefaultParserL(aParser);
       
    61 	}
       
    62 
       
    63 
       
    64 // Deactivate and deinstall the standard set of default parsers
       
    65 EXPORT_C void CRichText::DeactivateParserDefaults()
       
    66 	{
       
    67 	CParserList* activeParserList = (CParserList*)Dll::Tls();
       
    68 	if (activeParserList)
       
    69 		{
       
    70 		activeParserList->DeactivateParserDefaults();
       
    71 		if ((activeParserList->iRefCount == 0) && (activeParserList->iNumberInList == 0))
       
    72 			{
       
    73 			Dll::FreeTls();
       
    74 			delete activeParserList;
       
    75 			}
       
    76 		}
       
    77 	}
       
    78 
       
    79 
       
    80 // Create ParserLst instance and retain ownership of it but pass address to EText TLS
       
    81 void CRichText::CreateParserETextTLSL()
       
    82 	{
       
    83 	__ASSERT_DEBUG(Dll::Tls() == NULL, Panic(EParserListAlreadyExists));
       
    84 	CParserList* activeParserList = new (ELeave) CParserList;
       
    85 	CleanupStack::PushL(activeParserList);
       
    86 	TInt err = Dll::SetTls(activeParserList);
       
    87 	User::LeaveIfError(err);
       
    88 	CleanupStack::Pop(activeParserList);
       
    89 	}
       
    90 
       
    91 
       
    92 // Set observer callback to tell whenever the object has been edited.
       
    93 // If set set then the parser system is active for this instance, otherwise not.
       
    94 
       
    95  
       
    96 
       
    97 EXPORT_C void CRichText::SetEditObserver(MEditObserver* aEditObserver)
       
    98 /** Sets the rich text object's edit observer. The observer's EditObserver() function 
       
    99 is called by the rich text object each time the object's text content is edited 
       
   100 (e.g. after a paste, insert, delete, reset etc.).
       
   101 
       
   102 @param aEditObserver Pointer to the edit observer. */
       
   103 	{
       
   104 	iParserData->iEditObserver = aEditObserver;
       
   105 	}
       
   106 
       
   107 	
       
   108 EXPORT_C TBool CRichText::ParseText(TInt& aStartOfTags, TInt& aLength, TBool aForceScanAllText)
       
   109 	{
       
   110 	__ASSERT_ALWAYS(iIndex.IsPtr(),Panic(EParserListTextIndexNotInitialized));
       
   111 	TBool foundSomething = EFalse;
       
   112 	if (iParserData->iActiveParserList && iParserData->iEditObserver)
       
   113 		{
       
   114 		if (aForceScanAllText)
       
   115 			foundSomething = iParserData->iActiveParserList->ParseThisText(*this,0,DocumentLength(),
       
   116 																		   aStartOfTags,aLength);
       
   117 		else if (iParserData->HaveRange())
       
   118 			foundSomething = iParserData->iActiveParserList->ParseThisText(*this,iParserData->StartParse(),
       
   119 									iParserData->EndParse() - iParserData->StartParse(),
       
   120 									aStartOfTags,aLength);
       
   121 		// All parsers have scanned the area
       
   122 		iParserData->KillRange();
       
   123 		}
       
   124 	return foundSomething;
       
   125 	}
       
   126 
       
   127 
       
   128 // Given a cursor position, is there a tag under it and, if so, give me details	
       
   129 TBool CRichText::DoCursorOverTag(TInt aPos, MParser*& aParser, TInt& aTagStart, TInt& aLength) const
       
   130 	{
       
   131 	TCharFormatX format;
       
   132 	TCharFormatXMask varies;
       
   133 	TBool success = EFalse;
       
   134 	TBuf<1> buf;
       
   135 
       
   136 	__ASSERT_DEBUG(iParserData->iActiveParserList, Panic(EParserListNotInitialized));
       
   137 	__ASSERT_DEBUG(iParserData->iEditObserver, Panic(EParserListNotActive));
       
   138 	GetExtendedCharFormat(format, varies, aPos, 1);
       
   139 	Extract(buf, aPos, 1);
       
   140 	if ((format.iParserTag) && (buf[0] != 0x2029))
       
   141 		{
       
   142 		aParser = iParserData->iActiveParserList->ParserWithThisTag(format.iParserTag);
       
   143 		if (aParser == NULL)
       
   144 			{ // Parser has been deactivated
       
   145 			return EFalse;
       
   146 			}
       
   147 		// Get extent of tag (or set of contiguous tags for same parser)
       
   148 		TInt pos = aPos;
       
   149 		TInt startScan;
       
   150 		TInt scanLength;
       
   151 		// need to check backwards
       
   152 		TUint tag = format.iParserTag;	// Stash tag before overwriting it
       
   153 		for (; pos > 0; pos--)
       
   154 			{
       
   155 			GetExtendedCharFormat(format, varies, pos - 1, 1);
       
   156 			Extract(buf, aPos, 1);
       
   157 			if ((format.iParserTag != tag) || (buf[0] == 0x2029))
       
   158 				break;
       
   159 			}
       
   160 		startScan = pos;
       
   161 		// Now forwards
       
   162 		TInt len = DocumentLength();
       
   163 		while (pos < len)
       
   164 			{
       
   165 			TPtrC ptr;
       
   166 			GetTextAndExtendedFormat(ptr, format, pos);
       
   167 			if (format.iParserTag != tag)
       
   168 				break;
       
   169 			pos += ptr.Length();
       
   170 			}
       
   171 		if (pos > len)
       
   172 			pos = len;
       
   173 		scanLength = pos - startScan;
       
   174 		// Now use the parser that found it originally to isolate the exact range
       
   175 		// of the tag from the range that could contain several
       
   176 		for (;;)
       
   177 			{
       
   178 			TInt result = aParser->ParseThisText(*this, EFalse, startScan, scanLength, aTagStart, aLength);
       
   179 			// Check we haven't gone past it (failed to find it this time)
       
   180 			if (!result || (aTagStart > aPos))
       
   181 				break;
       
   182 			if ((aPos >= aTagStart) && (aPos < aTagStart + aLength))
       
   183 				{
       
   184 				// We've found it
       
   185 				success = ETrue;
       
   186 				break;
       
   187 				}
       
   188 			// Not yet, skip over that one
       
   189 			startScan += aLength;
       
   190 			scanLength -= aLength;
       
   191 			if (scanLength < 0)
       
   192 				break;
       
   193 			}
       
   194 	
       
   195 		}
       
   196 	return success;
       
   197 	}
       
   198 
       
   199 
       
   200 EXPORT_C TBool CRichText::CursorOverTag(TInt aPos, MParser*& aParser, TInt& aTagStart, TInt& aLength) const
       
   201 	{
       
   202 	TBool over = EFalse;
       
   203 
       
   204 	if (iParserData->iActiveParserList && iParserData->iEditObserver)
       
   205 		{
       
   206 		iParserData->iLastKnownCursor = aPos;
       
   207 		if (DoCursorOverTag(aPos, aParser, aTagStart, aLength))
       
   208 			{
       
   209 			over = ETrue;
       
   210 			}
       
   211 		if (aPos && DoCursorOverTag(aPos - 1, aParser, aTagStart, aLength))
       
   212 			{
       
   213 			over = ETrue;
       
   214 			}
       
   215 		}
       
   216 	return over && 
       
   217 		aParser->ConfirmCursorOverTag(*this, aTagStart, aLength, aPos);
       
   218 	}
       
   219 
       
   220 
       
   221 EXPORT_C TInt CRichText::PositionOfNextTag(TInt aPos, const MParser * aParser) const
       
   222 	{
       
   223 	if (iParserData->iActiveParserList && iParserData->iEditObserver)
       
   224 		{
       
   225 		MParser* parser;
       
   226 		TInt tagStart;
       
   227 		TInt length;
       
   228 		TInt newPos = aPos;
       
   229 		TUint tag = 0;
       
   230 		if (aParser)
       
   231 			tag = iParserData->iActiveParserList->TagForThisParser(aParser);
       
   232 		if (DoCursorOverTag(newPos, parser, tagStart, length))
       
   233 			newPos = tagStart + length;	// To get past the current tag
       
   234 		TPtrC ptr;
       
   235 		TCharFormatX format;
       
   236 		while (newPos < DocumentLength())
       
   237 			{
       
   238 			GetTextAndExtendedFormat(ptr, format, newPos);
       
   239 			if (format.iParserTag &&(!aParser || format.iParserTag == tag))
       
   240 				return newPos;
       
   241 			newPos += ptr.Length();
       
   242 			}
       
   243 		}
       
   244 
       
   245 	return KErrNotFound;
       
   246 	}
       
   247 
       
   248 
       
   249 EXPORT_C TInt CRichText::PositionOfNextTag(TInt aPos) const
       
   250 	{
       
   251 	return PositionOfNextTag(aPos, NULL);
       
   252 	}
       
   253 
       
   254 
       
   255 EXPORT_C TInt CRichText::PositionOfPrevTag(TInt aPos, const MParser * aParser) const
       
   256 	{
       
   257 	if (iParserData->iActiveParserList && iParserData->iEditObserver)
       
   258 		{
       
   259 		MParser* parser;
       
   260 		TInt tagStart;
       
   261 		TInt length;
       
   262 		TInt newPos = aPos;
       
   263 		TUint tag = 0;
       
   264 		if (aParser)
       
   265 			tag = iParserData->iActiveParserList->TagForThisParser(aParser);
       
   266 		if (DoCursorOverTag(newPos, parser, tagStart, length))
       
   267 			newPos = tagStart;	// To get past the current tag
       
   268 		TCharFormatX format;
       
   269 		TCharFormatXMask varies;
       
   270 		
       
   271 		for (; newPos > 0; newPos--)
       
   272 			{
       
   273 			GetExtendedCharFormat(format, varies, newPos - 1, 1);
       
   274 			if (format.iParserTag &&(!aParser || format.iParserTag == tag))
       
   275 				{
       
   276 				if (DoCursorOverTag(newPos - 1, parser, tagStart, length))
       
   277 					return tagStart;
       
   278 				}
       
   279 			}
       
   280 		}
       
   281 
       
   282 	return KErrNotFound;
       
   283 	}
       
   284 
       
   285 
       
   286 EXPORT_C TInt CRichText::PositionOfPrevTag(TInt aPos) const
       
   287 	{
       
   288 	return PositionOfPrevTag(aPos, NULL);
       
   289 	}
       
   290 
       
   291 
       
   292 void CRichText::OverrideFormatForParsersIfApplicable(TPtrC& aText, TCharFormatX& aFormat, TInt aStartPos) const
       
   293 	{
       
   294 	if (aFormat.iParserTag && iParserData->iActiveParserList && iParserData->iEditObserver)
       
   295 		{
       
   296 		// Replace format
       
   297 		TInt start = -1;
       
   298 		TInt length = 0;
       
   299 		TInt curPos = iParserData->iLastKnownCursor;
       
   300 		if (curPos > DocumentLength())
       
   301 			curPos = DocumentLength();  // This shouldn't be neccesary but it makes it more
       
   302 										// bulletproof if the calls from outside are made in
       
   303 										// the wrong order
       
   304 		if (curPos != -1)
       
   305 			{
       
   306 			TCharFormatX format;
       
   307 			TCharFormatXMask varies;
       
   308 			MParser* parser;
       
   309 
       
   310 			GetExtendedCharFormat(format, varies, curPos, 1);
       
   311 			// If char at curpos has a tag then cursor is over that tag, get extents of tag
       
   312 			if (CParserList::ReformatOnRollover(format.iParserTag))
       
   313 				DoCursorOverTag(curPos, parser, start, length);
       
   314 			else if (curPos)
       
   315 				{
       
   316 				GetExtendedCharFormat(format, varies, curPos - 1, 1);
       
   317 				// Try the char "before" curpos
       
   318 				if (CParserList::ReformatOnRollover(format.iParserTag))
       
   319 					DoCursorOverTag(curPos - 1, parser, start, length);
       
   320 				}
       
   321 			}
       
   322 
       
   323 		MParser* parser = iParserData->iActiveParserList->ParserWithThisTag(aFormat.iParserTag);
       
   324 		
       
   325 		if (length && (aStartPos >= start) && (aStartPos < start + length))
       
   326 			{
       
   327 			if (start + length < aStartPos + aText.Length())
       
   328 				aText.Set(aText.Left(start + length - aStartPos));
       
   329 			if (parser != NULL)
       
   330 				{
       
   331 				// Only accept the rollover format if the parser agrees 
       
   332 				// with the framework match of a tag
       
   333 				if (parser->ConfirmCursorOverTag(*this, start, length, curPos))
       
   334 					parser->GetRolloverFormat(aFormat.iCharFormat);
       
   335 				else 
       
   336 					// Reset format to recognised format if parser disagrees
       
   337 					// with the framework match as the tag is still in view
       
   338 					// and must be formatted as in the else clause below.
       
   339 					parser->GetRecogniseFormat(aFormat.iCharFormat);
       
   340 				}
       
   341 			}
       
   342 		else
       
   343 			{
       
   344 			if (length && (start > aStartPos))
       
   345 				aText.Set(aText.Left(start - aStartPos));
       
   346 			if (parser != NULL)
       
   347 				parser->GetRecogniseFormat(aFormat.iCharFormat);
       
   348 			}
       
   349 		}
       
   350 	}
       
   351 
       
   352 
       
   353 void CRichText::CallEditObserver(TInt aStart, TInt aExtent) const
       
   354 	{
       
   355 	if (iParserData->iEditObserver)
       
   356 		iParserData->iEditObserver->EditObserver(aStart, aExtent);
       
   357 	}