sl@0: /*
sl@0: * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: * All rights reserved.
sl@0: * This component and the accompanying materials are made available
sl@0: * under the terms of "Eclipse Public License v1.0"
sl@0: * which accompanies this distribution, and is available
sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: *
sl@0: * Initial Contributors:
sl@0: * Nokia Corporation - initial contribution.
sl@0: *
sl@0: * Contributors:
sl@0: *
sl@0: * Description: 
sl@0: *
sl@0: */
sl@0: 
sl@0: 
sl@0: #include <e32std.h>
sl@0: #include <e32base.h>
sl@0: 
sl@0: #include <s32std.h>
sl@0: #include <s32strm.h>
sl@0: #include <s32stor.h>
sl@0: #include <s32mem.h>
sl@0: #include <s32file.h>
sl@0: #include <s32ucmp.h>
sl@0: 
sl@0: #include <fepitfr.h>
sl@0: 
sl@0: #include "FLDDEF.H"
sl@0: #include "FLDINFO.H"
sl@0: #include "FLDSET.H"
sl@0: 
sl@0: #include "TXTETEXT.H"
sl@0: #include "TXTRICH.H"
sl@0: #include "TXTOPT.H"
sl@0: #include "TXTFEP.H"
sl@0: #include "TXTPLAIN.H"
sl@0: #include "TXTSTD.H"
sl@0: #include "TXTRTPFL.H"
sl@0: #include "TXTCLIPBOARD.H"
sl@0: 
sl@0: #include "OstTraceDefinitions.h"
sl@0: #ifdef OST_TRACE_COMPILER_IN_USE
sl@0: #include "TXTETEXTTraces.h"
sl@0: #endif
sl@0: 
sl@0: #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
sl@0: #include "TXTETEXT_INTERNAL.H"
sl@0: #endif
sl@0: 
sl@0: const TUint KFieldCountLimit = 255;
sl@0: #define UNUSED_VAR(a) a = a
sl@0: 
sl@0: // Write some or all of the text in a buffer to a stream, writing the length first if aWriteLength is true.
sl@0: static void ExternalizeTextL(RWriteStream& aStream,const CBufBase& aText,TInt aPos,TInt aLength,TBool aWriteLength)
sl@0: 	{
sl@0: 	if (aWriteLength)
sl@0: 		aStream << TCardinality(aLength);
sl@0: 
sl@0: 	// Use the Standard Unicode Compression Scheme.
sl@0: 	RBufReadStream input_stream(aText,aPos * sizeof(TText));
sl@0: 	TMemoryStreamUnicodeSource source(input_stream);
sl@0: 	TUnicodeCompressor c;
sl@0: 	c.CompressL(aStream,source,KMaxTInt,aLength);
sl@0: 	input_stream.Close();
sl@0: 	}
sl@0: 
sl@0: // Read text from a stream and write it to a buffer.
sl@0: static void InternalizeTextL(RReadStream& aStream,CBufBase& aText,TInt aLength)
sl@0: 	{
sl@0: 	// Use the Standard Unicode Compression Scheme.
sl@0: 	RBufWriteStream output_stream(aText);
sl@0: 	TMemoryStreamUnicodeSink sink(output_stream);
sl@0: 	TUnicodeExpander e;
sl@0: 	e.ExpandL(sink,aStream,aLength);
sl@0: 	output_stream.CommitL();
sl@0: 	output_stream.Close();
sl@0: 	}
sl@0: 
sl@0: // Read text from a stream and write it to a buffer; read the length first.
sl@0: static void InternalizeTextL(RReadStream& aStream,CBufBase& aText)
sl@0: 	{
sl@0: 	TCardinality length;
sl@0: 	aStream >> length;
sl@0: 	InternalizeTextL(aStream,aText,length);
sl@0: 	}
sl@0: /**
sl@0: Returns the interface corresponding to the
sl@0: specified UID if it exists, or 0 if not. Overridden
sl@0: versions should base call rather than returning 0.
sl@0: 
sl@0: @param aInterfaceId The UID indicating the interface to return
sl@0: @param aInterface The interface corresponding to aInterfaceId
sl@0: if it is supported, or 0 if it is not
sl@0: */
sl@0: EXPORT_C void CEditableText::ExtendedInterface(TAny*& /*aInterface*/, TUid /*aInterfaceId*/) {}
sl@0: 
sl@0: /**
sl@0: Returns the interface corresponding to the
sl@0: specified UID if it exists, or 0 if not. Overridden
sl@0: versions should base call rather than returning 0.
sl@0: 
sl@0: @param aInterfaceId The UID indicating the interface to return
sl@0: @param aInterface The interface corresponding to aInterfaceId
sl@0: if it is supported, or 0 if it is not
sl@0: */
sl@0: EXPORT_C void CPlainText::ExtendedInterface(TAny*& /*aInterface*/, TUid /*aInterfaceId*/) {}
sl@0: 
sl@0: /**
sl@0:  @internalAll
sl@0:  @released
sl@0:  */
sl@0: EXPORT_C void CPlainText::Reserved_2() {}
sl@0: 
sl@0: //////////////////////////////////
sl@0: // CEditableText
sl@0: //////////////////////////////////
sl@0: 
sl@0: EXPORT_C CEditableText::~CEditableText()
sl@0: 	{
sl@0: 	delete iOptionalData;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C TInt CEditableText::ScanWords(TInt& /*aPos*/,TUint& /*aScanMask*/) const
sl@0: /** Scans the text from a specified document position to a location 
sl@0: determined by the flags specified in a bitmask. The function can scan 
sl@0: forwards or backwards to the beginning or end of a word.
sl@0: 
sl@0: @param aPos A valid document position from which to scan. On return, 
sl@0: contains the new document position. 
sl@0: @param aScanMask The scan mask to use. See the scanning enumeration defined 
sl@0: in class CPlainText. 
sl@0: @return The number of characters skipped to reach the new document position. 
sl@0: Notes: If the scan passes the end of text delimiter, on return, aPos is set 
sl@0: to EScanEndOfData  and the function's return value indicates the 
sl@0: number of characters skipped in passing the end of text delimiter. */
sl@0: 	{
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TInt CEditableText::ScanParas(TInt& /*aPos*/,TUint& /*aScanMask*/) const
sl@0: /** Scans the text from a specified document position to a location determined 
sl@0: by the flags specified in a bitmask. The function can scan forwards or backwards 
sl@0: to the beginning or end of a paragraph.
sl@0: 
sl@0: @param aPos A valid document position from which to scan. On return, contains 
sl@0: the new document position. 
sl@0: @param aScanMask The scan mask to use. See the scanning enumeration defined 
sl@0: in class CPlainText. 
sl@0: @return The number of characters skipped to reach the new document position. 
sl@0: Notes: If the scan passes the end of text delimiter, on return, aPos is set 
sl@0: to EScanEndOfData  and the function's return value indicates the 
sl@0: number of characters skipped in passing the end of text delimiter. */
sl@0: 	{
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: 
sl@0:  
sl@0: EXPORT_C void CEditableText::SetHasChanged(TBool aHasChanged)
sl@0: /** Sets whether a change has occurred to the editable text object. This is called 
sl@0: by functions which change the text object in some way.
sl@0: 
sl@0: @param aHasChanged ETrue if a change has occurred to the text object. EFalse 
sl@0: if no change has occurred. */
sl@0: 	{
sl@0: 	iHasChanged = aHasChanged;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // Save the editable text type identifier.
sl@0: void CEditableText::ExternalizeL(RWriteStream& aStream)const
sl@0: 	{
sl@0: 	aStream << KEditableTextUid;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CEditableText::InternalizeL(RReadStream& aStream)
sl@0: // Read from the stream, expecting the editable text type identifier
sl@0: //
sl@0: 	{
sl@0: 	TUid uid;
sl@0: 	aStream>> uid;
sl@0: 	if (uid!=KEditableTextUid)
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 	}
sl@0: 
sl@0: 
sl@0:  
sl@0: 
sl@0: EXPORT_C TStreamId CEditableText::StoreL(CStreamStore& aStore)const
sl@0: /** Stores the text and its components. The components (e.g. fields and pictures) 
sl@0: are stored in separate streams within the stream store.
sl@0: 
sl@0: @param aStore Stream store to which the text and text components are written. 
sl@0: @return The ID of the stream store. */
sl@0: 	{
sl@0: 	CStoreMap* map=CStoreMap::NewLC(aStore);
sl@0: 	StoreComponentsL(aStore,*map);
sl@0: //
sl@0: 	RStoreWriteStream stream(*map);
sl@0: 	TStreamId id=stream.CreateLC(aStore);
sl@0: 	stream<< *this;
sl@0: 	stream.CommitL();
sl@0: //
sl@0: 	map->Reset();
sl@0: 	CleanupStack::PopAndDestroy(2);  // map,stream
sl@0: 	return id;
sl@0: 	}
sl@0: 
sl@0: 
sl@0:  
sl@0: EXPORT_C void CEditableText::RestoreL(const CStreamStore& aStore,TStreamId aStreamId)
sl@0: /** Restores the text and its components from a stream store.
sl@0: 
sl@0: @param aStore Stream store containing the text and its components. 
sl@0: @param aStreamId The ID of the stream store in which the text was previously 
sl@0: stored. */
sl@0: 	{
sl@0: 	// Load text and field components only.  (Pictures, if present, are deferred loaded).
sl@0: 	__ETEXT_WATCH(RESTORE)
sl@0: 
sl@0: 	RStoreReadStream stream;
sl@0: 	stream.OpenLC(aStore,aStreamId);
sl@0: 	//
sl@0: 	stream>> *this;
sl@0: 	CleanupStack::PopAndDestroy();  // stream
sl@0: 	RestoreComponentsL(aStore);
sl@0: 
sl@0: 	__ETEXT_WATCH_END(RESTORE)
sl@0: 	}
sl@0: 
sl@0: TBool CEditableText::DeleteWithoutDestroyingFormatL(TInt aPos, TInt aLength)
sl@0: /** Deletes a range of characters. For rich text the format of the deleted character 
sl@0: at position aPos is preserved, so that any text subsequently inserted at aPos will have 
sl@0: that format applied to it.
sl@0: @param aPos The document position from which to begin deleting including aPos.
sl@0: @param aLength The number of characters to delete. Must be positive or a panic 
sl@0: occurs. The sum of aPos and aLength must be less than the document length, 
sl@0: or a panic occurs.  
sl@0: @return Indicates whether two paragraphs have been merged together as a result 
sl@0: of the delete, indicating that the resulting paragraph must be reformatted. 
sl@0: */	
sl@0: 	{
sl@0: 	TAny* richTextInterface = NULL;	
sl@0: 	ExtendedInterface(richTextInterface, KUidRichText);
sl@0: 
sl@0: 	if(richTextInterface)
sl@0: 		{
sl@0: 		return REINTERPRET_CAST(CRichText*, richTextInterface)->DelSetInsertCharFormatL(aPos, aLength);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		return DeleteL(aPos, aLength);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CEditableText::StartFepInlineEditL(TBool& aParagraphContainingStartPositionOfInlineTextHasChangedFormat,TInt& aNumberOfCharactersSuccessfullyDeleted,TInt& aNumberOfCharactersSuccessfullyInserted,TInt& aPositionOfInsertionPointInDocument,TInt aNewPositionOfInsertionPointInDocument,const TDesC& aInitialInlineText,TInt aPositionOfInlineTextInDocument,TInt aNumberOfCharactersToHide,MFepInlineTextFormatRetriever& aInlineTextFormatRetriever)
sl@0: /** @internalAll */	
sl@0: 	{
sl@0: 	if (aPositionOfInlineTextInDocument<0 || aNumberOfCharactersToHide<0 || aPositionOfInlineTextInDocument+aNumberOfCharactersToHide>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CEDITABLETEXT_STARTFEPINLINEEDITL, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPositionOfInlineTextInDocument>=0 && aNumberOfCharactersToHide>=0 && aPositionOfInlineTextInDocument+aNumberOfCharactersToHide<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 	if (InlineEditData()!=NULL)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, DUP1_CEDITABLETEXT_STARTFEPINLINEEDITL, "EAlreadyFepInlineEditing" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(InlineEditData()==NULL,Panic(EAlreadyFepInlineEditing));
sl@0: 	aParagraphContainingStartPositionOfInlineTextHasChangedFormat=EFalse;
sl@0: 	aNumberOfCharactersSuccessfullyDeleted=0;
sl@0: 	aNumberOfCharactersSuccessfullyInserted=0;
sl@0: 	CInlineEditData* const inlineEditData=new(ELeave) CInlineEditData;
sl@0: 	CleanupStack::PushL(inlineEditData);
sl@0: 	HBufC* hiddenText=NULL;
sl@0: 	CleanupStack::PushL(hiddenText);
sl@0: 	if (aNumberOfCharactersToHide>0)
sl@0: 		{
sl@0: 		CleanupStack::Pop(); // hiddenText
sl@0: 		hiddenText=HBufC::NewLC(aNumberOfCharactersToHide);
sl@0: 		TPtr hiddenTextAsWritableDescriptor=hiddenText->Des();
sl@0: 		Extract(hiddenTextAsWritableDescriptor,aPositionOfInlineTextInDocument,aNumberOfCharactersToHide);
sl@0: 		aParagraphContainingStartPositionOfInlineTextHasChangedFormat=DeleteWithoutDestroyingFormatL(aPositionOfInlineTextInDocument,aNumberOfCharactersToHide);
sl@0: 		aNumberOfCharactersSuccessfullyDeleted=aNumberOfCharactersToHide;
sl@0: 		aPositionOfInsertionPointInDocument=aPositionOfInlineTextInDocument;
sl@0: 		}
sl@0: 	inlineEditData->iPositionOfInlineTextInDocument=aPositionOfInlineTextInDocument;
sl@0: 	inlineEditData->iLengthOfInlineText=aInitialInlineText.Length();
sl@0: 	inlineEditData->iInlineText=aInitialInlineText.AllocL();
sl@0: 	inlineEditData->iHiddenText=hiddenText;
sl@0: 	CleanupStack::Pop(); // hiddentext now owned by inlineEditData. 
sl@0: 	inlineEditData->iInlineTextFormatRetriever=&aInlineTextFormatRetriever;
sl@0: 	InsertL(aPositionOfInlineTextInDocument,aInitialInlineText);
sl@0: 	SetAndTransferOwnershipOfInlineEditDataL(inlineEditData);
sl@0: 	CleanupStack::Pop(); // inlineEditData
sl@0: 	aNumberOfCharactersSuccessfullyInserted=inlineEditData->iLengthOfInlineText;
sl@0: 	aPositionOfInsertionPointInDocument=aNewPositionOfInsertionPointInDocument;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CEditableText::UpdateFepInlineTextL(TBool& aParagraphContainingStartPositionOfInlineTextHasChangedFormat,TInt& aNumberOfCharactersSuccessfullyDeleted,TInt& aNumberOfCharactersSuccessfullyInserted,TInt& aPositionOfInsertionPointInDocument,TInt aNewPositionOfInsertionPointInDocument,const TDesC& aNewInlineText)
sl@0: /** @internalAll */	
sl@0:     {
sl@0: 	CInlineEditData* const inlineEditData=InlineEditData();
sl@0: 	if (inlineEditData==NULL)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CEDITABLETEXT_UPDATEFEPINLINETEXTL, "ENotCurrentlyFepInlineEditing" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(inlineEditData!=NULL,Panic(ENotCurrentlyFepInlineEditing));
sl@0: 	aParagraphContainingStartPositionOfInlineTextHasChangedFormat=EFalse;
sl@0: 	aNumberOfCharactersSuccessfullyDeleted=0;
sl@0: 	aNumberOfCharactersSuccessfullyInserted=0;
sl@0: 	HBufC*& inlineText=inlineEditData->iInlineText;
sl@0: 	HBufC* oldInlineText=inlineText;
sl@0: 	if (oldInlineText!=NULL && inlineEditData->iLengthOfInlineText!=oldInlineText->Length())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, DUP1_CEDITABLETEXT_UPDATEFEPINLINETEXTL, "EDebug" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(oldInlineText==NULL || inlineEditData->iLengthOfInlineText==oldInlineText->Length(),Panic(EDebug));
sl@0: 	const TInt lengthOfNewInlineText=aNewInlineText.Length();
sl@0: 	if (oldInlineText!=NULL && *oldInlineText==aNewInlineText)
sl@0: 		{
sl@0: 		aNumberOfCharactersSuccessfullyDeleted=lengthOfNewInlineText;
sl@0: 		aNumberOfCharactersSuccessfullyInserted=lengthOfNewInlineText;
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		if (oldInlineText==NULL)
sl@0: 			{
sl@0: 			oldInlineText=HBufC::NewL(lengthOfNewInlineText);
sl@0: 			}
sl@0: 		else if (lengthOfNewInlineText>oldInlineText->Length())
sl@0: 			{
sl@0: 			oldInlineText=oldInlineText->ReAllocL(lengthOfNewInlineText);
sl@0: 			}
sl@0: 		CleanupStack::PushL(oldInlineText);
sl@0: 		inlineText=NULL; // sets inlineEditData->iLengthOfInlineText in case either the delete or the insert leaves
sl@0: 		const TInt positionOfInlineTextInDocument=inlineEditData->iPositionOfInlineTextInDocument;
sl@0: 		TInt& lengthOfInlineText=inlineEditData->iLengthOfInlineText;
sl@0: 		if (lengthOfInlineText>0)
sl@0: 			{
sl@0: 			aParagraphContainingStartPositionOfInlineTextHasChangedFormat=DeleteWithoutDestroyingFormatL(positionOfInlineTextInDocument,lengthOfInlineText);
sl@0: 			aNumberOfCharactersSuccessfullyDeleted=lengthOfInlineText;
sl@0: 			lengthOfInlineText=0; // sets inlineEditData->iLengthOfInlineText in case the insert leaves
sl@0: 			aPositionOfInsertionPointInDocument=inlineEditData->iPositionOfInlineTextInDocument;
sl@0: 			}
sl@0: 		InsertL(positionOfInlineTextInDocument,aNewInlineText);
sl@0: 		lengthOfInlineText=aNewInlineText.Length(); // sets inlineEditData->iLengthOfInlineText
sl@0: 		aNumberOfCharactersSuccessfullyInserted=lengthOfInlineText;
sl@0: 		inlineText=oldInlineText;
sl@0: 		CleanupStack::Pop(); // oldInlineText
sl@0: 		*oldInlineText=aNewInlineText;
sl@0: 		}
sl@0: 	aPositionOfInsertionPointInDocument=aNewPositionOfInsertionPointInDocument;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CEditableText::CommitFepInlineEditL(TBool& aParagraphContainingStartPositionOfInlineTextHasChangedFormat,TInt& aNumberOfCharactersSuccessfullyDeleted,TInt& aNumberOfCharactersSuccessfullyInserted,TInt& aPositionOfInsertionPointInDocument,TInt aNewPositionOfInsertionPointInDocument)
sl@0: /**
sl@0:  * @internalAll
sl@0:  */	
sl@0:     {
sl@0: 	const CInlineEditData* const inlineEditData=InlineEditData();
sl@0: 	if (inlineEditData==NULL)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_CEDITABLETEXT_COMMITFEPINLINEEDITL, "ENotCurrentlyFepInlineEditing" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(inlineEditData!=NULL,Panic(ENotCurrentlyFepInlineEditing));
sl@0: 	if (inlineEditData->iInlineText!=NULL && inlineEditData->iLengthOfInlineText!=inlineEditData->iInlineText->Length())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CEDITABLETEXT_COMMITFEPINLINEEDITL, "EDebug" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(inlineEditData->iInlineText==NULL || inlineEditData->iLengthOfInlineText==inlineEditData->iInlineText->Length(),Panic(EDebug));
sl@0: 	aParagraphContainingStartPositionOfInlineTextHasChangedFormat=EFalse;
sl@0: 	const TInt lengthOfInlineText=inlineEditData->iLengthOfInlineText;
sl@0: 	aNumberOfCharactersSuccessfullyDeleted=lengthOfInlineText;
sl@0: 	aNumberOfCharactersSuccessfullyInserted=lengthOfInlineText;
sl@0: 	aPositionOfInsertionPointInDocument=aNewPositionOfInsertionPointInDocument;
sl@0: 	DeleteInlineEditDataAndSetToNull();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CEditableText::CancelFepInlineEdit(TBool& aParagraphContainingStartPositionOfInlineTextHasChangedFormat,TInt& aNumberOfCharactersSuccessfullyDeleted,TInt& aNumberOfCharactersSuccessfullyInserted,TInt& aPositionOfInsertionPointInDocument,TInt aNewPositionOfInsertionPointInDocument)
sl@0: /**
sl@0:  * @internalAll
sl@0:  */	
sl@0:     {
sl@0: 	aParagraphContainingStartPositionOfInlineTextHasChangedFormat=EFalse;
sl@0: 	aNumberOfCharactersSuccessfullyDeleted=0;
sl@0: 	aNumberOfCharactersSuccessfullyInserted=0;
sl@0: 	const CInlineEditData* inlineEditData=InlineEditData();
sl@0: 	if (inlineEditData!=NULL)
sl@0: 		{
sl@0: 		const TInt positionOfInlineTextInDocument=inlineEditData->iPositionOfInlineTextInDocument;
sl@0: 		const TInt lengthOfInlineText=inlineEditData->iLengthOfInlineText;
sl@0: 		if (inlineEditData->iInlineText!=NULL && lengthOfInlineText!=inlineEditData->iInlineText->Length())
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, CEDITABLETEXT_CANCELFEPINLINEEDIT, "EDebug" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(inlineEditData->iInlineText==NULL || lengthOfInlineText==inlineEditData->iInlineText->Length(),Panic(EDebug));
sl@0: 		TRAPD(notUsed,
sl@0: 						if (lengthOfInlineText>0)
sl@0: 							{
sl@0: 							aParagraphContainingStartPositionOfInlineTextHasChangedFormat=DeleteWithoutDestroyingFormatL(positionOfInlineTextInDocument,lengthOfInlineText);
sl@0: 							aNumberOfCharactersSuccessfullyDeleted=lengthOfInlineText;
sl@0: 							aPositionOfInsertionPointInDocument=inlineEditData->iPositionOfInlineTextInDocument;
sl@0: 							}
sl@0: 						const HBufC* const hiddenText=inlineEditData->iHiddenText;
sl@0: 						if (hiddenText!=NULL)
sl@0: 							{
sl@0: 							if (hiddenText->Length()<=0)
sl@0: 							    {
sl@0: 							    OstTrace0( TRACE_DUMP, DUP1_CEDITABLETEXT_CANCELFEPINLINEEDIT, "EDebug" );
sl@0: 							    }
sl@0: 							__ASSERT_DEBUG(hiddenText->Length()>0, Panic(EDebug));
sl@0: 							InsertL(positionOfInlineTextInDocument,*hiddenText);
sl@0: 							aNumberOfCharactersSuccessfullyInserted=hiddenText->Length();
sl@0: 							aPositionOfInsertionPointInDocument=aNewPositionOfInsertionPointInDocument;
sl@0: 							}
sl@0: 			);
sl@0:         UNUSED_VAR(notUsed);
sl@0: 		DeleteInlineEditDataAndSetToNull();
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CEditableText::OverrideFormatOfInlineTextIfApplicable(TPtrC& aView,TCharFormat& aFormat,TInt aStartPos)const
sl@0: 	{
sl@0: 	const CInlineEditData* inlineEditData=InlineEditData();
sl@0: 	if (inlineEditData!=NULL)
sl@0: 		{
sl@0: 		const TInt positionOfInlineTextInDocument=inlineEditData->iPositionOfInlineTextInDocument;
sl@0: 		const TInt lengthOfInlineText=inlineEditData->iLengthOfInlineText;
sl@0: 		const TInt originalLengthOfView=aView.Length();
sl@0: 		TInt maximumLengthOfView=originalLengthOfView;
sl@0: 		if (aStartPos<positionOfInlineTextInDocument)
sl@0: 			{
sl@0: 			maximumLengthOfView=positionOfInlineTextInDocument-aStartPos;
sl@0: 			}
sl@0: 		else if (aStartPos<positionOfInlineTextInDocument+lengthOfInlineText)
sl@0: 			{
sl@0: 			inlineEditData->iInlineTextFormatRetriever->GetFormatOfFepInlineText(aFormat,maximumLengthOfView,aStartPos-positionOfInlineTextInDocument);
sl@0: 			}
sl@0: 		if (originalLengthOfView>maximumLengthOfView)
sl@0: 			{
sl@0: 			aView.Set(aView.Left(maximumLengthOfView));
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TInt CEditableText::GetPositionOfInlineTextInDocument() const
sl@0: 	{
sl@0: 	const CInlineEditData* inlineEditData=InlineEditData();
sl@0: 	if (inlineEditData==NULL)
sl@0: 		return KErrNotFound;
sl@0: 	return inlineEditData->iPositionOfInlineTextInDocument;	
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TInt CEditableText::GetLengthOfInlineText() const
sl@0: 	{
sl@0: 	const CInlineEditData* inlineEditData=InlineEditData();
sl@0: 	if (inlineEditData==NULL)
sl@0: 		return KErrNotFound;
sl@0: 	return inlineEditData->iLengthOfInlineText;		
sl@0: 	}
sl@0: 
sl@0: 
sl@0: //////////////////////////////////
sl@0: // TEtextComponentInfo
sl@0: //////////////////////////////////
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C TEtextComponentInfo::TEtextComponentInfo()
sl@0: 	: iFieldCount(0),iPictureCount(0),iStyleCount(0)
sl@0: /** C++ constructor overloaded function.
sl@0: 
sl@0: The object can be constructed either:by default this initializes the
sl@0: field, picture and style counts to zerowith a field, picture and style
sl@0: count
sl@0: 
sl@0: @param aFieldCount Specifies the number of fields in the text object.
sl@0: @param aPictureCount Specifies the number of pictures in the text object
sl@0: (rich text only).
sl@0: @param aStyleCount  Specifies the number of styles owned or referenced by
sl@0: the text object (rich text only). */
sl@0:     {}
sl@0: 
sl@0: 
sl@0: EXPORT_C TEtextComponentInfo::TEtextComponentInfo(TInt aFieldCount,TInt aPictureCount,TInt aStyleCount)
sl@0: 	: iFieldCount(aFieldCount),iPictureCount(aPictureCount),iStyleCount(aStyleCount)
sl@0: /** C++ constructor overloaded function. The object can be constructed either:
sl@0: 
sl@0: by default  this initializes the field, picture and style counts to zero
sl@0: 
sl@0: with a field, picture and style count
sl@0: 
sl@0: @param aFieldCount Specifies the number of fields in the text object. 
sl@0: @param aPictureCount Specifies the number of pictures in the text object (rich 
sl@0: text only). 
sl@0: @param aStyleCount Specifies the number of styles owned or referenced by the 
sl@0: text object (rich text only). */
sl@0: 	{}
sl@0: 
sl@0: 
sl@0: //////////////////////////////////
sl@0: // CPlainText
sl@0: //////////////////////////////////
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::__DbgTestInvariant()const
sl@0: // Provides class invariants.  Explanations below:
sl@0: //
sl@0: 	{
sl@0: #ifdef _DEBUG
sl@0: // ASSERT: Storage handle is good.
sl@0: 	__ASSERT_DEBUG(iByteStore!=NULL,User::Invariant());
sl@0: // ASSERT: The text component must be non-negative in length
sl@0: 	__ASSERT_DEBUG(DocumentLength()>=0,User::Invariant());
sl@0: #endif
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C CPlainText* CPlainText::NewL(TDocumentStorage aStorage,TInt aDefaultTextGranularity)
sl@0: /** Allocates and constructs a plain text object overloaded function.
sl@0: 
sl@0: The text object's contents may be restored from a stream store. If the
sl@0: text object supports fields, a field factory should be specified.
sl@0: 
sl@0: @param aStorage  The type of in-memory buffer to use. Defaults to ESegmentedStorage.
sl@0: @param aDefaultTextGranularity  Specifies the granularity of the in-memory 
sl@0: buffer. Default is EDefaultTextGranularity bytes (=256).
sl@0: @param aStore   Stream store from which the object is restored.
sl@0: @param aStreamId  ID of the stream store.
sl@0: @param aFieldFactory Pointer to a field factory. A field factory must be
sl@0: provided if the text object supports the addition of fields.
sl@0: @return Pointer to the new plain text object. */	
sl@0: 	{
sl@0: 	CPlainText* self=new(ELeave) CPlainText();
sl@0: 	CleanupStack::PushL(self);
sl@0: 	self->ConstructL(aStorage,aDefaultTextGranularity);
sl@0: 	CleanupStack::Pop();
sl@0: 	return self;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C CPlainText* CPlainText::NewL(const CStreamStore& aStore,TStreamId aStreamId,MTextFieldFactory* aFieldFactory,TDocumentStorage aStorage)
sl@0: /** Returns a handle to a new instance of this class, restored from the specified
sl@0: read stream.*/
sl@0: 	{
sl@0: 	CPlainText* self=new(ELeave) CPlainText();
sl@0: 	CleanupStack::PushL(self);
sl@0: 	self->ConstructL(aStore,aStreamId,aFieldFactory,aStorage);
sl@0: 	CleanupStack::Pop();
sl@0: 	return self;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C CPlainText::CPlainText()
sl@0: 	{
sl@0: 	SetHasChanged(EFalse);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ConstructL(TDocumentStorage aStorage,TInt aDefaultTextGranularity)
sl@0: /** Allocates storage of CBufFlat or CBufSeg, according
sl@0: to the parameter aStorage.
sl@0: Creates & initializes the field set.*/
sl@0: 	{
sl@0: 	DoConstructL(aStorage,aDefaultTextGranularity);
sl@0: 	InsertEodL();
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ConstructL(const CStreamStore& aStore,TStreamId aStreamId,MTextFieldFactory* aFieldFactory,
sl@0: 									 TDocumentStorage aStorage)
sl@0: /** Allocates storage of CBufFlat or CBufSeg, according
sl@0:  to the parameter aStorage, restoring contents from the specified read-stream aStream.*/
sl@0: 	{
sl@0: 	DoConstructL(aStorage,EDefaultTextGranularity,aFieldFactory);	
sl@0: 	RestoreL(aStore,aStreamId);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::DoConstructL(TDocumentStorage aStorage,TInt aDefaultTextGranularity,MTextFieldFactory* aFieldFactory)
sl@0: /** Allocates storage of CBufFlat or CBufSeg, according to the parameter aStorage.
sl@0: Creates & initializes the field set.*/
sl@0: 	{
sl@0: 	if (iByteStore!=NULL)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CPLAINTEXT_DOCONSTRUCTL, "EConstructCalledTwice" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(iByteStore==NULL,Panic(EConstructCalledTwice));
sl@0: 	
sl@0: 	iByteStore=(aStorage==ESegmentedStorage)
sl@0: 		? (CBufBase*)CBufSeg::NewL(aDefaultTextGranularity*sizeof(TText))
sl@0: 		: (CBufBase*)CBufFlat::NewL(aDefaultTextGranularity*sizeof(TText));
sl@0: 	if (aFieldFactory)
sl@0: 		SetFieldFactory(aFieldFactory);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C CPlainText::~CPlainText()
sl@0: /** The destructor frees the object's text storage and field set, prior to its 
sl@0: destruction. */
sl@0: 	{
sl@0: 	KillFieldSet();
sl@0: 	delete iByteStore;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CPlainText::KillFieldSet()
sl@0: /** Delete the field set if it is resident in memory.*/
sl@0: 	{
sl@0: 	if (FieldSetPresent())
sl@0: 		delete iFieldSet.AsPtr();
sl@0: 	iFieldSet=NULL;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: //
sl@0: // CPlainText - Persistence
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::StoreComponentsL(CStreamStore& aStore,CStoreMap& aMap)const
sl@0: /** Stores the plain text object's components to the stream store specified.
sl@0: 
sl@0: @param aStore Stream store to which the text object's components are written. 
sl@0: @param aMap A store map. This binds the address of each component to the stream 
sl@0: ID of aStore. This is needed to support the deferred loading of pictures in 
sl@0: rich text. */
sl@0: 	{
sl@0: 	// Store any field components, then store the field set out-of-line, if present.
sl@0: 	if (FieldSetPresent())
sl@0: 		{
sl@0: 		TStreamId id=iFieldSet->StoreL(aStore);
sl@0: 		aMap.BindL(iFieldSet,id);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::RestoreComponentsL(const CStreamStore& aStore)
sl@0: /** Restores the plain text object's field set from a stream store.
sl@0: 
sl@0: @param aStore The stream store from which the field set is restored. */
sl@0: 	{
sl@0: 	// Load the field set, and load any referenced pictures
sl@0: 	TStreamId id=iFieldSet.AsId();
sl@0: 	if (id!=KNullStreamId)
sl@0: 		{
sl@0: 		CreateFieldSetL(0);
sl@0: 		iFieldSet->SetFieldFactory(iFieldFactory);
sl@0: 		iFieldSet->RestoreL(aStore,id);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::StoreFieldComponentsL(CStreamStore& aStore,CStoreMap& aMap)const
sl@0: /** Stores the plain text object's field components to a stream store.
sl@0: 
sl@0: @param aStore Stream store to which the fields are written. 
sl@0: @param aMap A store map. This binds the address of each text component to the 
sl@0: stream ID of aStore. This is needed to support the deferred loading of pictures 
sl@0: in rich text. */
sl@0: 	{
sl@0: 	// 2' StoreComponents() 
sl@0: 	// Only has effect if a field set is present.
sl@0: 	if (FieldSetPresent())
sl@0: 		iFieldSet->StoreFieldsL(aStore,aMap);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::RestoreFieldComponentsL(const CStreamStore& aStore)
sl@0: /** Restores the plain text object's field set.
sl@0: 
sl@0: @param aStore The stream store from which the fields are restored. */
sl@0: 	{
sl@0: 	// 2' RestoreComponents()
sl@0: 	// Only has effect if a field set is present - (has been Internalized())
sl@0: 	if (FieldSetPresent())
sl@0: 		iFieldSet->RestoreFieldsL(aStore);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 	
sl@0: EXPORT_C void CPlainText::ExternalizeL(RWriteStream& aStream)const
sl@0: /** Externalises a plain text object to a write stream. The presence of this function 
sl@0: means that the standard templated operator<<() (defined in s32strm.h) is available 
sl@0: to externalise objects of this class.
sl@0: 
sl@0: @param aStream Stream to which the object should be externalised. */
sl@0: 	{
sl@0: 	// Store this object in the specified write-stream.
sl@0: 	CEditableText::ExternalizeL(aStream);
sl@0: 	DoExternalizeFieldDataL(aStream);
sl@0: 	DoExternalizePlainTextL(aStream);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::InternalizeL(RReadStream& aStream)
sl@0: /** Internalises the text object's text content and field set from a read stream. 
sl@0: The presence of this function means that the standard templated operator>>() 
sl@0: (defined in s32strm.h) is available to internalise objects of this class. 
sl@0: InternalizeL() has construct rather than assignment semantics. You should 
sl@0: not use it for fully initialised objects.
sl@0: 
sl@0: @param aStream Stream from which the object should be internalised. */
sl@0: 	{
sl@0: 	// Restores plain text from the specified read-stream.
sl@0: 	// Internalize has construction semantics, not assignment semantics.
sl@0: 	CEditableText::InternalizeL(aStream);
sl@0: 	DoInternalizeFieldDataL(aStream);
sl@0: 	DoInternalizePlainTextL(aStream);
sl@0: 	
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ExternalizeFieldDataL(RWriteStream& aStream)const
sl@0: /** Externalises the plain text object's field set.
sl@0: 
sl@0: @param aStream The stream to which the field set should be written. */
sl@0: 	{
sl@0: 	// Save just the field set
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	TUint fieldCount=(TUint)FieldCount();
sl@0: 	if(fieldCount<KFieldCountLimit)
sl@0: 		aStream.WriteUint8L(fieldCount);
sl@0: 	else
sl@0: 		{
sl@0: 		aStream.WriteUint8L(KFieldCountLimit);
sl@0: 		aStream.WriteUint32L(fieldCount);
sl@0: 		}
sl@0: 	if (fieldCount>0)
sl@0: 		aStream<< *iFieldSet;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::InternalizeFieldDataL(RReadStream& aStream)
sl@0: /** Internalizes the field set.
sl@0: 
sl@0: @param aStream The read stream from which the field set is read. */
sl@0: 	{
sl@0: 	// 2' InternalizeL()
sl@0: 	// Restores field records from the specified read-stream.
sl@0: 	// Internalize has construction semantics, not assignment semantics.
sl@0: 
sl@0: 	TUint fieldCount=aStream.ReadUint8L();
sl@0: 	if (fieldCount==KFieldCountLimit)
sl@0: 		fieldCount=aStream.ReadUint32L();
sl@0: 	if (fieldCount>0)
sl@0: 		{
sl@0: 		if (!iFieldSet)
sl@0: 			CreateFieldSetL(DocumentLength());
sl@0: 		aStream>> *iFieldSet;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::DoInternalizeFieldDataL(RReadStream& aStream)
sl@0: /** Read from the stream until the field data is identified, and consume it.*/
sl@0: 	{
sl@0: 	TUid uid=UidFromStreamL(aStream);
sl@0: 	while (uid!=KPlainTextFieldDataUid)
sl@0:  		{
sl@0: 		if (uid==KPlainTextCharacterDataUid)
sl@0: 			User::Leave(KErrCorrupt);  // There is no field Data !!!!!
sl@0: 		CPlainText::ConsumeAdornmentL(aStream);
sl@0: 		uid=UidFromStreamL(aStream);
sl@0: 		}
sl@0: 	if (FieldSetPresent())
sl@0: 		iFieldFactory=iFieldSet->FieldFactory();
sl@0: 	KillFieldSet();
sl@0: 	aStream>> iFieldSet;  // a swizzle
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::DoExternalizeFieldDataL(RWriteStream& aStream)const
sl@0: /** Write to the stream, the T.V. representing the field set.*/
sl@0: 	{
sl@0: 	aStream<< KPlainTextFieldDataUid;
sl@0: 	if (FieldSetPresent())
sl@0: 		aStream<< iFieldSet;
sl@0: 	else
sl@0: 		aStream<< KNullStreamId;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::DoExternalizePlainTextL(RWriteStream& aStream)const
sl@0: /** Write to the stream, the T.V. representing the plain text.*/
sl@0: 	{
sl@0: 	aStream<< KPlainTextCharacterDataUid;
sl@0: 	ExternalizePlainTextL(aStream);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ExternalizePlainTextL(RWriteStream& aStream)const
sl@0: 	
sl@0: /** Externalises the plain text object's text content (preceded by a length count) 
sl@0: to a write stream.
sl@0: 
sl@0: @param aStream Stream to which the text content should be externalised. */
sl@0: 	{
sl@0: 	// Save just the bytestore
sl@0: 	__TEST_INVARIANT;
sl@0: 	::ExternalizeTextL(aStream,*iByteStore,0,iByteStore->Size() / sizeof(TText),TRUE);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CPlainText::DoInternalizePlainTextL(RReadStream& aStream)
sl@0: /** Read from the stream until the character data is found, and consume it.*/
sl@0: 	{
sl@0: 	TUid uid=UidFromStreamL(aStream);
sl@0: 	while (uid!=KPlainTextCharacterDataUid)
sl@0: 		{
sl@0: 		CPlainText::ConsumeAdornmentL(aStream);
sl@0: 		uid=UidFromStreamL(aStream);
sl@0: 		}
sl@0: 	CPlainText::InternalizePlainTextL(aStream);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CPlainText::InternalizePlainTextL(RReadStream& aStream)
sl@0: /** Internalises an empty text object's text content from a read stream
sl@0: overloaded function.
sl@0: 
sl@0: This function has construct rather than assignment semantics. You
sl@0: should not use it for fully initialised objects.NoteThe overload which
sl@0: takes a length argument is not intended for general use and its use is
sl@0: deprecated.
sl@0: 
sl@0: @param aStream Stream from which the object should be internalised.
sl@0: @param  aLength Indicates the number of characters which should be
sl@0: read, after expansion from their compressed format. */	
sl@0:     {
sl@0: 	// Restores plain text content from the specified read-stream.
sl@0: 	// Internalize has construction semantics, not assignment semantics.
sl@0: 	::InternalizeTextL(aStream,*iByteStore);
sl@0: 	SetHasChanged(EFalse);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ExternalizePlainTextNoLengthCountL(RWriteStream& aStream)const
sl@0: /** Externalises the plain text object's text content to a write stream.
sl@0: 
sl@0: This function differs from ExternalizePlainTextL() in that 
sl@0: it does not precede the text content with a length count.
sl@0: This function is not intended for general use and is deprecated.
sl@0: @see void CPlainText::ExternalizePlainTextL(RWriteStream& aStream)const
sl@0: @deprecated */
sl@0: 	{
sl@0: 	::ExternalizeTextL(aStream,*iByteStore,0,iByteStore->Size() / sizeof(TText),FALSE);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::InternalizePlainTextL(RReadStream& aStream,TInt aLength)
sl@0: /** Internalises an empty text object's text content from a read stream's 
sl@0: overloaded function.
sl@0: 
sl@0: This function has construct rather than assignment semantics. You should not 
sl@0: use it for fully initialised objects.
sl@0: 
sl@0: Note
sl@0: 
sl@0: The overload which takes a length argument is not intended for general use 
sl@0: and its use is deprecated. 
sl@0: 
sl@0: @param aStream Stream from which the object should be internalised. 
sl@0: @param aLength Indicates the number of characters which should be read, after 
sl@0: expansion from their compressed format. 
sl@0: @deprecated */
sl@0: 	{
sl@0: 	::InternalizeTextL(aStream,*iByteStore,aLength);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // Copy the specified section of plain text to the specified store.
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::CopyToStoreL(CStreamStore& aStore,CStreamDictionary& aDictionary,TInt aPos,TInt aLength) const
sl@0: /** Copies plain text including fields, if present, to the clipboard.
sl@0: 
sl@0: A panic occurs in any of the following circumstances:
sl@0: 
sl@0: aPos is invalid
sl@0: 
sl@0: aLength is invalid (zero or less)
sl@0: 
sl@0: the sum of aPos and aLength is greater than or equal to the number of characters 
sl@0: in the document
sl@0: 
sl@0: @param aStore Stream store to which the text is written. 
sl@0: @param aDictionary The stream dictionary. 
sl@0: @param aPos The document position from which to begin copying. 
sl@0: @param aLength The number of characters to copy. */
sl@0: 	{
sl@0: 	if (aLength > 0)
sl@0: 		DoCopyToStoreL(aStore,aDictionary,aPos,aLength);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: TStreamId CPlainText::DoCopyToStoreL(CStreamStore& aStore,CStreamDictionary& aDictionary,TInt aPos,TInt aLength) const
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	TInt documentLength = DocumentLength();
sl@0: 	if (aPos < 0 || aPos > documentLength)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_DOCOPYTOSTOREL, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos >= 0 && aPos <= documentLength,Panic(ECharPosBeyondDocument));
sl@0: 	if (aLength < 0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_CPLAINTEXT_DOCOPYTOSTOREL, "ECopyToStreamNegativeLength" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aLength >= 0,Panic(ECopyToStreamNegativeLength));
sl@0: 	if (aPos + aLength > documentLength)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP2_CPLAINTEXT_DOCOPYTOSTOREL, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos + aLength <= documentLength,Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	if (aLength == 0)
sl@0: 		return KNullStreamId;
sl@0: 
sl@0: 	CStoreMap* map=CStoreMap::NewLC(aStore);
sl@0: 	CopyComponentsL(aStore,*map,aPos,aLength);
sl@0: 
sl@0: 	// create custom externalizer over the map
sl@0: 	TFieldMapExternalizer fMap(*map);
sl@0: 	RStoreWriteStream stream(fMap);
sl@0: 	TStreamId id=stream.CreateLC(aStore);
sl@0: 	CopyToStreamL(stream,aPos,aLength);
sl@0: 	stream.CommitL();
sl@0: 
sl@0: 	aDictionary.AssignL(KClipboardUidTypePlainText,id);
sl@0: 	map->Reset();
sl@0: 	CleanupStack::PopAndDestroy(2);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	return id;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CPlainText::CopyComponentsL(CStreamStore& aStore,CStoreMap& aMap,TInt aPos,TInt aLength)const
sl@0: // Copy/Paste 2' StoreComponentsL() - only if a field set is present.
sl@0: // 
sl@0: 	{
sl@0: 	if (FieldSetPresent())
sl@0: 		iFieldSet->CopyComponentsL(aStore,aMap,aPos,aLength);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // Write the plain text to the stream.
sl@0: void CPlainText::CopyToStreamL(RWriteStream& aStream,TInt aPos,TInt aLength)const
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	TInt documentLength = DocumentLength();
sl@0: 	if (aPos < 0 || aPos > documentLength)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_COPYTOSTREAML, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos >= 0 && aPos <= documentLength,Panic(ECharPosBeyondDocument));
sl@0: 	if (aLength < 0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_CPLAINTEXT_COPYTOSTREAML, "ECopyToStreamNegativeLength" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aLength >= 0,Panic(ECopyToStreamNegativeLength));
sl@0: 	if (aPos + aLength > documentLength)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP2_CPLAINTEXT_COPYTOSTREAML, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos + aLength <= documentLength,Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	aStream.WriteInt32L(aLength);
sl@0: 	::ExternalizeTextL(aStream,*iByteStore,aPos,aLength,FALSE);
sl@0: 
sl@0: 	// Write the field set if any.
sl@0: 	TBool fieldSetPresent = FieldSetPresent();
sl@0: 	aStream.WriteUint8L(fieldSetPresent != EFalse);
sl@0: 	if (fieldSetPresent)
sl@0: 		iFieldSet->CopyToStreamL(aStream,aPos,aLength);
sl@0: 	}
sl@0: 
sl@0: 
sl@0:  
sl@0: 
sl@0: EXPORT_C TInt CPlainText::PasteFromStoreL(const CStreamStore& aStore,const CStreamDictionary& aDictionary,TInt aPos)
sl@0: /** Pastes plain text and fields, if present, from the clipboard into the current 
sl@0: text object at the specified document position. The entire contents of the 
sl@0: store are pasted.
sl@0: 
sl@0: @param aStore The steam store from which to paste the text. 
sl@0: @param aDictionary The stream dictionary. 
sl@0: @param aPos Document position at which to paste. Must be valid or the function 
sl@0: raises a panic. 
sl@0: @return The number of characters pasted. */
sl@0: 	{
sl@0: 	// Paste the lesser of aMaxPasteLength and the entire clipboard contents.
sl@0: 	// Return the number of characters pasted.
sl@0: 	TStreamId id=aDictionary.At(KClipboardUidTypePlainText);
sl@0: 	return DoPasteFromStoreL(aStore,id,aPos);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: TInt CPlainText::DoPasteFromStoreL(const CStreamStore& aStore,TStreamId aStreamId,TInt aPos)
sl@0: 	{
sl@0: 	if (aPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_DOPASTEFROMSTOREL, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	TInt charsPasted=0;
sl@0: 	if (aStreamId!=KNullStreamId)
sl@0: 		{// There is a recognised type in the clipboard.
sl@0: 		RStoreReadStream stream;
sl@0: 		stream.OpenLC(aStore,aStreamId);
sl@0: 		charsPasted=PasteFromStreamL(stream,aPos);
sl@0: 		CleanupStack::PopAndDestroy();
sl@0: 		//
sl@0: 		PasteComponentsL(aStore,aPos);
sl@0: 		SetHasChanged(ETrue);
sl@0: 		}
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	return charsPasted;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CPlainText::PasteComponentsL(const CStreamStore& aStore,TInt aPos)
sl@0: // Copy/Paste 2' RestoreComponentsL() - only if a field set is present.
sl@0: //
sl@0: 	{
sl@0: 	if (FieldSetPresent())
sl@0: 		iFieldSet->PasteComponentsL(aStore,aPos);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // Paste everything in the stream.
sl@0: TInt CPlainText::PasteFromStreamL(RReadStream& aStream,TInt aPos)
sl@0: 	{
sl@0: 	TInt chars_read = 0;
sl@0: 	TInt error = KErrNone;
sl@0: 
sl@0: 	TRAP(error, chars_read=CPlainText::DoPasteFromStreamL(aStream, aPos));
sl@0: 
sl@0: 	UpdatePageTable(aPos,chars_read);
sl@0: 
sl@0: 	/*
sl@0: 	If there was an exception delete any inserted text and propagate the exception.
sl@0: 	Not deleting the text would cause the size of the text to be inconsistent with the size
sl@0: 	implied elsewhere, such as in the formatting information stored in CRichText objects.
sl@0: 	*/
sl@0: 	if (error != KErrNone)
sl@0: 		{
sl@0: 		DoPtDelete(aPos,chars_read);
sl@0: 		OstTrace1( TRACE_FATAL, DUP1_CPLAINTEXT_PASTEFROMSTREAML, "Leave code=%d", error );
sl@0: 		User::Leave(error);
sl@0: 		}
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	return chars_read;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: TInt CPlainText::DoPasteFromStreamL(RReadStream& aStream, TInt aPos)
sl@0: 	{
sl@0: 	TInt chars_read = 0;
sl@0: 
sl@0: 	CBufSeg* buffer = CBufSeg::NewL(512);
sl@0: 	CleanupStack::PushL(buffer);
sl@0: 	TInt length = aStream.ReadInt32L();
sl@0: 	::InternalizeTextL(aStream,*buffer,length);
sl@0: 
sl@0: 	/*
sl@0: 	Insert the text bit by bit so that memory consumed by the CPlainText object is freed from the buffer;
sl@0: 	this is important if pasting huge amounts of text.
sl@0: 	*/
sl@0: 	while (buffer->Size() > 0)
sl@0: 		{
sl@0: 		TPtr8 p8 = buffer->Ptr(0);
sl@0: 		TInt bytes = p8.Length();
sl@0: 		TInt chars = bytes / sizeof(TText);
sl@0: 		TPtrC p((TText*)p8.Ptr(),chars);	// platform dependency in the Unicode build; relies on little-endianness
sl@0: 		PtInsertL(aPos + chars_read,p);
sl@0: 		buffer->Delete(0,bytes);
sl@0: 		chars_read += chars;
sl@0: 		}
sl@0: 
sl@0: 	CleanupStack::PopAndDestroy();	// buffer
sl@0: 	buffer = NULL;
sl@0: 
sl@0: 	// If there's a field set, internalize it.
sl@0: 	if (aStream.ReadUint8L() != 0)	// next byte is non-zero if there's a field set
sl@0: 		{
sl@0: 		if (!FieldSetPresent())
sl@0: 			CreateFieldSetL(DocumentLength());
sl@0: 		iFieldSet->PasteFromStreamL(aStream,aPos,chars_read);
sl@0: 		}
sl@0: 	
sl@0: 	return chars_read;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CPlainText::InsertEodL()
sl@0: /** Inserts the end-of-document character upon document construction.*/
sl@0: 	{
sl@0: // ASSERT: The plain text component is empty.
sl@0: 	if (DocumentLength()!=-1)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, DUP1_CPLAINTEXT_INSERTEODL, "ECorruptTextStore" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(DocumentLength()==-1,Panic(ECorruptTextStore));
sl@0: 	TBuf<1> content;
sl@0: 	content.Append(EParagraphDelimiter);
sl@0: 	TPtrC eod(content);
sl@0: 	DoPtInsertL(0,eod);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0:  
sl@0: EXPORT_C void CPlainText::Reset()
sl@0: /** Deletes all text content, formatting and fields from the document, leaving 
sl@0: the single paragraph delimiter which terminates the text object. */
sl@0: 	{	
sl@0: 	// Resets document contents to a single end-of-document character, with no other content.
sl@0: 	// (No reset occurs if the component is already in the reset state.  Avoids an assertion
sl@0: 	// failure in the delete method, where length to delete !> 0).
sl@0: 	__TEST_INVARIANT;
sl@0: 		
sl@0: 	TInt content=DocumentLength();
sl@0: 	if (content>0)
sl@0: 		DoPtDelete(0,content);
sl@0: 	if (FieldSetPresent())
sl@0: 		KillFieldSet();
sl@0: 	SetHasChanged(ETrue);
sl@0: 	
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0:  
sl@0: 
sl@0: EXPORT_C TInt CPlainText::DocumentLength()const
sl@0: /** Gets the the number of characters in the text object.
sl@0: 
sl@0: Note: the count includes all non-printing characters but excludes the end 
sl@0: of text paragraph delimiter, so that the smallest possible return value is 
sl@0: zero.
sl@0: 
sl@0: @return The number of characters in the text object. */
sl@0: 	{return ((iByteStore->Size()/sizeof(TText))-1);}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::InsertL(TInt aInsertPos,const TChar& aChar)
sl@0: /** Inserts either a single character or a descriptor into the text object
sl@0: at a specified document position.
sl@0: 
sl@0: Updates the page table.
sl@0: 
sl@0: @param aPos The document position at which to insert the character/descriptor. 
sl@0: Must be valid, or a panic occurs.
sl@0: @param aChar The character to insert.
sl@0: @param aBuf The descriptor to insert. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aInsertPos<0 || aInsertPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_INSERTL, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aInsertPos>=0 && aInsertPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	TInt contentLength = 1;
sl@0: 	if (aChar < 0x10000)
sl@0: 		{
sl@0: 		TBuf<1> content;
sl@0: 		content.Append(aChar);
sl@0: 		DoPtInsertL(aInsertPos,content);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		TText16 high = TChar::GetHighSurrogate(aChar);
sl@0: 		TText16 low = TChar::GetLowSurrogate(aChar);
sl@0: 		RDebug::Print(_L("CPlainText::InsertL(%d), %X expand to %X %X."), aInsertPos, TUint(aChar), high, low);
sl@0: 	
sl@0: 		TBuf<2> content;
sl@0: 		contentLength = 2;
sl@0: 		content.Append(high);
sl@0: 		content.Append(low);
sl@0: 		DoPtInsertL(aInsertPos,content);
sl@0: 		}
sl@0: 	if (FieldSetPresent())
sl@0: 		iFieldSet->NotifyInsertion(aInsertPos,contentLength);
sl@0: 
sl@0: 	SetHasChanged(ETrue);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::InsertL(TInt aPos,const TDesC& aBuf)
sl@0: /** Inserts the contents of aBuf into the document at position aPos.*/	
sl@0: 	{
sl@0: 	PtInsertL(aPos,aBuf);
sl@0: 	SetHasChanged(ETrue);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::PtInsertL(TInt aPos,const TDesC& aBuf)
sl@0: /** Inserts the contents a aBuf into the document at position aInsertPos.
sl@0: Maintain field set.*/
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aPos<0 || aPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_PTINSERTL, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	DoPtInsertL(aPos,aBuf);
sl@0: 	if (FieldSetPresent())
sl@0: 		iFieldSet->NotifyInsertion(aPos,aBuf.Length());
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::DoPtInsertL(TInt aPos,const TDesC& aBuf)
sl@0: /** Inserts the contents a aBuf into the document at position aInsertPos.
sl@0: Maintain field set.*/
sl@0: 	{
sl@0: 	TPtrC8 buf((TUint8*)aBuf.Ptr(),aBuf.Size());
sl@0: 	iByteStore->InsertL(aPos*sizeof(TText),buf);
sl@0: 	UpdatePageTable(aPos,aBuf.Length());
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CPlainText::InsertL(TInt aPos,const CPlainText* aText)
sl@0: /** Insert the specified plain text object at the specified character position.
sl@0: (Called by CRichText::Insert()*/
sl@0: 	{
sl@0: 	TInt lengthRemaining=aText->DocumentLength();
sl@0: 	TInt readPos=0;
sl@0: 	FOREVER
sl@0: 		{
sl@0: 		TPtrC view=aText->Read(readPos);
sl@0: 		TInt consumed=view.Length();
sl@0: 		if (consumed>lengthRemaining)
sl@0: 			consumed=lengthRemaining;
sl@0: 		InsertL(aPos,view);
sl@0: 		lengthRemaining-=consumed;
sl@0: 		if (lengthRemaining==0)
sl@0: 			return;
sl@0: 		aPos+=consumed;
sl@0: 		readPos+=consumed;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TBool CPlainText::DeleteL(TInt aPos,TInt aLength)
sl@0: /** Deletes one or more characters beginning at, and including, the character at 
sl@0: a specified document position. Updates the page table. Any fields wholly contained 
sl@0: in the range of characters to delete are removed from the field set.
sl@0: 
sl@0: @param aPos The document position from which to begin deleting. Must be valid 
sl@0: or a panic occurs. 
sl@0: @param aLength The number of characters to delete. Must be positive or a panic 
sl@0: occurs. The sum of aPos and aLength must be less than the document length, 
sl@0: or a panic occurs. 
sl@0: @return Indicates whether two paragraphs have been merged together as a result 
sl@0: of the delete, indicating that the resulting paragraph must be reformatted. 
sl@0: Has no meaning for plain text, so always EFalse. */
sl@0: 	{
sl@0: 	return Delete(aPos,aLength);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: // A non-virtual non-leaving delete function for use inside ETEXT.
sl@0: TBool CPlainText::Delete(TInt aPos,TInt aLength)
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	TBool ret = DoPtDelete(aPos,aLength);
sl@0: 	if (FieldSetPresent())
sl@0: 		iFieldSet->NotifyDeletion(aPos,aLength);
sl@0: 	SetHasChanged(ETrue);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TBool CPlainText::DoPtDelete(TInt aPos,TInt aLength)
sl@0: /** Deletes aLength number of characters from the document,
sl@0:  commencing at, and including, position aPos.
sl@0:  The return value indicates if 2 paragraphs have been merged together
sl@0:  as a result of the delete, indicating that the resulting paragraph
sl@0:  must be reformatted.
sl@0:  In global text, this clearly has no reasonable meaning, so always returns
sl@0:  EFalse, so no reformatting occurs.*/
sl@0: 	{
sl@0: 	TInt documentLength=DocumentLength()+1;
sl@0: 	if (aPos<0 || aPos>documentLength)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_DOPTDELETE, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=documentLength,Panic(ECharPosBeyondDocument));
sl@0: 	if (aLength<0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_CPLAINTEXT_DOPTDELETE, "EDeleteNegativeLength" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aLength>=0,Panic(EDeleteNegativeLength));
sl@0: 	if (aPos+aLength>documentLength)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP2_CPLAINTEXT_DOPTDELETE, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos+aLength<=documentLength,Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	iByteStore->Delete(aPos*sizeof(TText),aLength*sizeof(TText));
sl@0: 	UpdatePageTable(aPos,-aLength);
sl@0: 
sl@0: 	return EFalse;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C TInt CPlainText::ImportTextFileL(TInt aPos,const TDes& aFileName,TTextOrganisation aTextOrganisation)
sl@0: /** Imports a plain text file into this text object.
sl@0: 
sl@0: Translates non-printing characters in the source text file into Symbian OS 
sl@0: special characters, for instance tabs are converted into 
sl@0: CEditableText::ETabCharacters, and form feeds into CEditableText::EPageBreaks. 
sl@0: Line feeds in the source text file are translated according to the 
sl@0: aTextOrganisation argument.
sl@0: 
sl@0: The function leaves if there is any problem in opening the file.
sl@0: 
sl@0: @param aPos Document position at which to insert the text. Must be a valid 
sl@0: position, or a panic occurs.
sl@0: @param aFileName The name of the text file to import.
sl@0: @param aTextOrganisation If EOrganiseByLine, a single line feed or a line feed 
sl@0: and carriage return is converted into a space character. A line feed which 
sl@0: is followed by another line feed is converted into a paragraph delimiter. 
sl@0: If EOrganiseByParagraph, all line feeds are converted into paragraph delimiters. 
sl@0: 
sl@0: @return The number of characters imported. */
sl@0: 	{
sl@0: 	TInt chars_inserted = 0;
sl@0: 	RFs file_session;
sl@0: 	TInt error = file_session.Connect();
sl@0: 	if (error == KErrNone)
sl@0: 		{
sl@0: 		RFile file;
sl@0: 		error = file.Open(file_session,aFileName,EFileStream | EFileRead | EFileShareReadersOnly);
sl@0: 		if (error == KErrNone)
sl@0: 			{
sl@0: 			RFileReadStream input_stream(file);
sl@0: 			TRAP(error,ImportTextL(aPos,input_stream,aTextOrganisation,KMaxTInt,KMaxTInt,&chars_inserted));
sl@0: 			input_stream.Close();
sl@0: 			}
sl@0: 		file.Close();
sl@0: 		file_session.Close();
sl@0: 		}
sl@0: 	if (error < 0)
sl@0: 	    {
sl@0: 	    OstTrace1( TRACE_FATAL, DUP1_CPLAINTEXT_IMPORTTEXTFILEL, "Leave code=%x", error );
sl@0: 	    }
sl@0: 	User::LeaveIfError(error);
sl@0: 	return chars_inserted;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ExportAsTextL(const TDes& aFileName,TTextOrganisation aTextOrganisation,TInt aLineWrap)const
sl@0: /** Writes the contents of the plain text object to a text file.
sl@0: 	
sl@0: The filename is given by aFileName. Any existing file with that name is 
sl@0: replaced. A wrap width can be specified. This is only used when exporting 
sl@0: by line (aTextOrganisation is EOrganiseByLine).
sl@0: 
sl@0: The function leaves if there is any problem in creating or replacing the file.
sl@0: 
sl@0: @param aFileName The name of the file to export the text to. If a file with 
sl@0: this name already exists, it is replaced. Otherwise, a new file is created.
sl@0: @param aTextOrganisation Defines how to translate line delimiters. If 
sl@0: EOrganiseByLine, lines wrap at the wrap width, as specified in aMaxLineLength. 
sl@0: If EOrganiseByParagraph, lines do not wrap and paragraph delimiters are 
sl@0: converted into CR/LF pairs.
sl@0: @param aMaxLineLength The maximum number of characters in each line, (only 
sl@0: relevant if the text organisation is EOrganiseByLine). */
sl@0: 	{
sl@0: 	if (aTextOrganisation != EOrganiseByParagraph && aLineWrap <= 0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CPLAINTEXT_EXPORTASTEXTL, "EExportLineWrapInvalid" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aTextOrganisation == EOrganiseByParagraph || aLineWrap > 0,Panic(EExportLineWrapInvalid));
sl@0: 	RFs file_session;
sl@0: 	TInt error = file_session.Connect();
sl@0: 	if (error == KErrNone)
sl@0: 		{
sl@0: 		RFile file;
sl@0: 		error = file.Replace(file_session,aFileName,EFileStream | EFileWrite | EFileShareExclusive);
sl@0: 		if (error == KErrNone)
sl@0: 			{
sl@0: 			RFileWriteStream output_stream(file);
sl@0: 			TRAP(error,output_stream.WriteUint16L(EByteOrderMark));
sl@0: 			if (error == KErrNone)
sl@0: 				TRAP(error,ExportTextL(0,output_stream,aTextOrganisation,KMaxTInt,DocumentLength(),aLineWrap));
sl@0: 			output_stream.Close();
sl@0: 			}
sl@0: 		file.Close();
sl@0: 		file_session.Close();
sl@0: 		}
sl@0: 	if (error < 0)
sl@0: 	    {
sl@0: 	    OstTrace1( TRACE_FATAL, DUP2_CPLAINTEXT_EXPORTASTEXTL, "Leave code=%x", error );
sl@0: 	    }
sl@0: 	User::LeaveIfError(error);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ImportTextL(TInt aPos,RReadStream& aInput,TTextOrganisation aTextOrganisation,
sl@0: 									  TInt aMaxOutputChars,TInt aMaxInputChars,
sl@0: 									  TInt* aOutputChars,TInt* aInputChars)
sl@0: /** Imports plain text from a stream into this text object.
sl@0: 
sl@0: Translates line feeds in the source text according to the
sl@0: aTextOrganisation argument.
sl@0: 
sl@0: @param aPos Document position at which to insert the text. Must be a valid 
sl@0: position, or a panic occurs.
sl@0: @param aInput Stream from which to read the text.
sl@0: @param aTextOrganisation If EOrganiseByLine, a single line feed 
sl@0: or a line feed and carriage return is converted into a space character. A 
sl@0: line feed which is followed by another line feed is converted into a paragraph
sl@0: delimiter. If EOrganiseByParagraph, all line feeds are converted 
sl@0: into paragraph delimiters.
sl@0: @param aMaxOutputChars The maximum number of characters to write to the text
sl@0: object.
sl@0: @param aMaxInputChars The maximum number of characters to read from the stream.
sl@0: @param aOutputChars  On return, the number of characters written to the text 
sl@0: object.
sl@0: @param aInputChars  On return, the number of characters read from the stream. */
sl@0:     {
sl@0: 	TImportExportParam param;
sl@0: 	param.iOrganisation = aTextOrganisation;
sl@0: 	param.iMaxOutputChars = aMaxOutputChars;
sl@0: 	param.iMaxInputChars = aMaxInputChars;
sl@0: 	TImportExportResult result;
sl@0: 	ImportTextL(aPos,aInput,param,result);
sl@0: 	if (aOutputChars)
sl@0: 		*aOutputChars = result.iOutputChars;
sl@0: 	if (aInputChars)
sl@0: 		*aInputChars = result.iInputChars;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ExportTextL(TInt aPos,RWriteStream& aOutput,TTextOrganisation aTextOrganisation,
sl@0: 									  TInt aMaxOutputChars,TInt aMaxInputChars,TInt aMaxLineLength,
sl@0: 									  TInt* aOutputChars,TInt* aInputChars) const
sl@0: /**  Writes plain text to a stream, optionally converting it from Unicode
sl@0: into a foreign encoding.
sl@0: 
sl@0: @since 6.1
sl@0: @param aPos A document position in the source plain text object from which 
sl@0: to start reading the text to export.
sl@0: @param aOutput  On return, the write stream to which the text is  written.
sl@0: @param aParam  Export parameters, including an optional foreign encoding to 
sl@0: convert the Unicode text into, a file  server connection, (this is needed for 
sl@0: the character conversion - if not specified, one will be created), a line 
sl@0: wrap width, and the maximum number of characters to export.
sl@0: @param aResult  On return, contains the number of characters read and written. */
sl@0:     {
sl@0: 	TImportExportParam param;
sl@0: 	param.iOrganisation = aTextOrganisation;
sl@0: 	param.iMaxOutputChars = aMaxOutputChars;
sl@0: 	param.iMaxInputChars = aMaxInputChars;
sl@0: 	param.iMaxLineLength = aMaxLineLength;
sl@0: 	TImportExportResult result;
sl@0: 	ExportTextL(aPos,aOutput,param,result);
sl@0: 	if (aOutputChars)
sl@0: 		*aOutputChars = result.iOutputChars;
sl@0: 	if (aInputChars)
sl@0: 		*aInputChars = result.iInputChars;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CPlainText::ImportTextL(TInt aPos,RReadStream& aInput,
sl@0: 									  const TImportExportParam& aParam,TImportExportResult& aResult)
sl@0: /** Imports plain text from a stream into this text object, optionally 
sl@0: converting it from a foreign encoding into Unicode.
sl@0: 
sl@0: @param aPos Document position at which to insert the text. Must be a valid 
sl@0: position, or a panic occurs.
sl@0: @param aInput Stream from which to read the text.
sl@0: @param aParam Import parameters, including the foreign encoding to convert 
sl@0: from, whether to guess the foreign encoding and the maximum number of characters 
sl@0: to import.
sl@0: @param aResult On return, contains the number of characters read and written 
sl@0: and the foreign encoding used by the imported text.
sl@0: @see CPlainText::TImportExportParam
sl@0: @see CPlainText::TImportExportResult */
sl@0: 	{
sl@0: 	CBufSeg* buffer = CBufSeg::NewL(512);
sl@0: 	CleanupStack::PushL(buffer);
sl@0: 	RBufWriteStream output(*buffer,0);
sl@0: 	TImportExportParam param = aParam;
sl@0: 	param.iOutputInternal = TRUE; // force output to internal format
sl@0: 	TPlainTextReader::TranslateL(param,aResult,output,aInput);
sl@0: 
sl@0: 	TInt chars_inserted = 0;
sl@0: 	while (buffer->Size() > 0)
sl@0: 		{
sl@0: 		TPtr8 p8 = buffer->Ptr(0);
sl@0: 		TInt bytes = p8.Length();
sl@0: 		TInt chars = bytes / sizeof(TText);
sl@0: 		TPtrC p((TText*)p8.Ptr(),chars);
sl@0: 		/*
sl@0: 		Insert text using the virtual function InsertL to allow derived classes
sl@0: 		like CRichText to update their attributes.
sl@0: 		*/
sl@0: 		InsertL(aPos + chars_inserted,p);
sl@0: 		buffer->Delete(0,bytes);
sl@0: 		chars_inserted += chars;
sl@0: 		}
sl@0: 
sl@0: 	CleanupStack::PopAndDestroy();	// buffer;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CPlainText::ExportTextL(TInt aPos,RWriteStream& aOutput,
sl@0: 									  const TImportExportParam& aParam,TImportExportResult& aResult) const
sl@0: /** Writes plain text to a stream, optionally converting it from Unicode into a 
sl@0: foreign encoding.
sl@0: 
sl@0: @param aPos A document position in the source plain text object from which 
sl@0: to start reading the text to export.
sl@0: @param aOutput On return, the write stream to which the text is written.
sl@0: @param aParam Export parameters, including an optional foreign encoding to 
sl@0: convert the Unicode text into, a file server connection, (this is needed for 
sl@0: the character conversion if not specified, one will be created), a line 
sl@0: wrap width, and the maximum number of characters to export.
sl@0: @param aResult On return, contains the number of characters read and written.
sl@0: @see CPlainText::TImportExportParam
sl@0: @see CPlainText::TImportExportResult */
sl@0: 	{
sl@0: 	TImportExportParam param = aParam;
sl@0: 	param.iInputInternal = TRUE; // force input to internal format
sl@0: 	param.iMaxInputChars = Min(param.iMaxInputChars,DocumentLength() - aPos); // ensure final paragraph delimiter is not exported
sl@0: 	RBufReadStream input(*iByteStore,aPos);
sl@0: 	TPlainTextWriter::TranslateL(param,aResult,aOutput,input);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TPtrC CPlainText::Read(TInt aStartPos)const
sl@0: /** Gets a read-only view of a portion of the text object.
sl@0: 
sl@0: The extent of the view is the range of characters starting at aStartPos and ending at whichever of the
sl@0: following document positions is reached first:
sl@0: 
sl@0: - The end of the document. 
sl@0: - The end of the segment if using segmented storage (the storage type is specified in the NewL(). 
sl@0: 
sl@0: Therefore, when using a segmented buffer to store the document, the length of the resultant view may be
sl@0: less than the requested length. In this case multiple calls to Read() may be necessary.
sl@0: 
sl@0: @param aStartPos The document position at which to begin reading. Must be valid or a panic occurs.
sl@0: @return Constant pointer to a section of the text object. 
sl@0: */	
sl@0:     {
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aStartPos<0 || aStartPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_CPLAINTEXT_READ, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aStartPos>=0 && aStartPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 	
sl@0: 	TPtr8 buf=iByteStore->Ptr(aStartPos*sizeof(TText));
sl@0: 	return TPtrC((TText*)buf.Ptr(),buf.Length()/sizeof(TText));
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TPtrC CPlainText::Read(TInt aStartPos,TInt aLength)const
sl@0:  /** Gets a read-only view of a portion of the text object.
sl@0: 
sl@0: The extent of the view is the range of characters starting at aStartPos and ending at whichever of the
sl@0: following document positions is reached first:
sl@0: 
sl@0: - The end of the document.
sl@0: - The end of the segment if using segmented storage (the storage type is specified in the NewL().
sl@0: - The sum of aStartPos and (aLength-1).
sl@0: 
sl@0: Therefore, when using a segmented buffer to store the document, the length of the resultant view may be
sl@0: less than the requested length. In this case multiple calls to Read() may be necessary.
sl@0: 
sl@0: @param aStartPos The document position at which to begin reading. Must be valid or a panic occurs. 
sl@0: @param aLength The number of characters to read, inclusive of the character at position aStartPos. 
sl@0: @return Constant pointer to a section of the text object.
sl@0: */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aStartPos<0 || aStartPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_READ, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aStartPos>=0 && aStartPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 	
sl@0: 	TPtr8 buf=iByteStore->Ptr(aStartPos*sizeof(TText));
sl@0: 	TInt length=Min(aLength,((TInt)buf.Length()/sizeof(TText)));
sl@0: 	return TPtrC((TText*)buf.Ptr(),length);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::Extract(TDes& aBuf,TInt aPos)const
sl@0: /**  Copies the contents of the text object into a descriptor overloaded
sl@0: function. The function copies all characters from and including the document
sl@0: position specified, to the end of the document or the end of the range
sl@0: of characters, if specified.
sl@0: 
sl@0: The buffer's maximum length must be greater than or equal to the number 
sl@0: of characters to extract, or a panic occurs.
sl@0: 
sl@0: @param aBuf A buffer; on return contains the extracted text.
sl@0: @param aPos The document position from which to copy. Must be valid or a 
sl@0: panic occurs.*/
sl@0:     {
sl@0: 	__TEST_INVARIANT;
sl@0: 	TInt documentLength=DocumentLength();
sl@0: 	if (aPos<0 || aPos>documentLength)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_EXTRACT, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=documentLength,Panic(ECharPosBeyondDocument));
sl@0: 	if (aBuf.MaxLength()<documentLength - aPos)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_CPLAINTEXT_EXTRACT, "EExtractBufferTooSmall" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aBuf.MaxLength()>=documentLength - aPos,Panic(EExtractBufferTooSmall));
sl@0: 
sl@0: 	DoExtract(aBuf,aPos,documentLength-aPos);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::Extract(TDes& aBuf,TInt aPos,TInt aLength)const
sl@0: /** Copies the contents of the text object into a descriptor-overloaded function. 
sl@0: The function copies all characters from and including the document position 
sl@0: specified, to the end of the document or the end of the range of characters, 
sl@0: if specified.
sl@0: 
sl@0: The buffer's maximum length must be greater than or equal to aLength, or a 
sl@0: panic ocurs.
sl@0: 
sl@0: @param aBuf A buffer; on return contains the extracted text. 
sl@0: @param aPos The document position from which to copy. Must be valid or a panic 
sl@0: occurs. 
sl@0: @param aLength The number of characters to copy. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aPos<0 || aPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP2_CPLAINTEXT_EXTRACT, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 	if (aBuf.MaxLength()<aLength)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP3_CPLAINTEXT_EXTRACT, "EExtractBufferTooSmall" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aBuf.MaxLength()>=aLength,Panic(EExtractBufferTooSmall));
sl@0: 
sl@0: 	DoExtract(aBuf,aPos,aLength);
sl@0: 	}
sl@0: 
sl@0: // Extract text, optionally discarding some characters such as control characters and soft hyphens or
sl@0: // inline text, depending on the flag.
sl@0: EXPORT_C void CPlainText::ExtractSelectively(TDes& aBuf,TInt aPos,TInt aLength,TUint aFlags)
sl@0: 	{
sl@0: 	if (aPos < 0 || aPos > DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_EXTRACTSELECTIVELY, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 	DoExtract(aBuf,aPos,aLength,aFlags);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CPlainText::DoExtract(TDes& aBuf,TInt aPos,TInt aLength,TUint aFlags) const
sl@0: /** Copies aLength characters, commencing at aPos, into the specified
sl@0: buffer aBuf.  If aLength is greater than the amount of data left,
sl@0: then all remaining characters are written.*/
sl@0: 	{
sl@0: 	aBuf.SetLength(0);
sl@0: 	TInt remainingLength=Min(aLength,DocumentLength()-aPos);
sl@0: 	TInt startPos=aPos;
sl@0: 	FOREVER
sl@0: 		{
sl@0: 		TPtrC textRead=Read(startPos);
sl@0: 		TInt lengthRead=textRead.Length();
sl@0: 		if (lengthRead>remainingLength)
sl@0: 			lengthRead=remainingLength;
sl@0: 		
sl@0: 		// Remove specific characters
sl@0: 		if (aFlags & EExtractVisible)
sl@0: 			{
sl@0: 			const TText* p = textRead.Ptr();
sl@0: 			const TText* q = p + lengthRead;
sl@0: 			while (p < q)
sl@0: 				{
sl@0: 				TChar c(*p++);
sl@0: 				if (c == EParagraphDelimiter || c == ELineBreak || c == ETabCharacter)
sl@0: 					aBuf.Append(' ');
sl@0: 				else if (c != EPotentialHyphen && c.IsPrint())
sl@0: 					aBuf.Append(c);
sl@0: 				}
sl@0: 			}
sl@0: 			
sl@0: 		// Remove inline text from the specified section
sl@0: 		else if (aFlags & EExcludeInlineEditedText)
sl@0: 			{
sl@0: 			const TInt inlineTextPos = GetPositionOfInlineTextInDocument();
sl@0: 			const TText* p = textRead.Ptr();
sl@0: 			
sl@0: 			if (inlineTextPos != KErrNotFound)
sl@0: 				{
sl@0: 				for (TInt i=aPos; i<(aPos+lengthRead); i++)
sl@0: 					{
sl@0: 		    		if (!((i >= inlineTextPos) && (i <= (inlineTextPos + GetLengthOfInlineText() - 1))))
sl@0: 		    			{
sl@0: 						TChar c(*p++);
sl@0: 						aBuf.Append(c);
sl@0: 						continue;
sl@0: 		    			}
sl@0: 		    		++p;
sl@0: 					}
sl@0: 				}
sl@0: 			else
sl@0: 				aBuf.Append(textRead.Ptr(),lengthRead);
sl@0: 			}
sl@0: 		else
sl@0: 			aBuf.Append(textRead.Ptr(),lengthRead);
sl@0: 		remainingLength-=lengthRead;
sl@0: 		if (remainingLength==0)
sl@0: 			return;
sl@0: 		startPos+=lengthRead;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::SetPageTable(TPageTable* aPageTable)
sl@0: /** Links the text object to a page table. A page table is an array of integers; 
sl@0: each integer represents the number of characters on a page. It is required 
sl@0: for pagination. The page table is updated when changes are made to the document, 
sl@0: e.g. after pasting from the clipboard, inserting, importing or deleting text.
sl@0: 
sl@0: The text object does not take ownership of the page table specified.
sl@0: 
sl@0: @param aPageTable The page table to be referenced by the text object. */
sl@0: 	{
sl@0: 	iPageTable=aPageTable;
sl@0: 	SetHasChanged(ETrue);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: void CPlainText::UpdatePageTable(TInt aPos,TInt aLength)
sl@0: // Adds aLength number of characters to the page in the page table
sl@0: // specified by the character position aPos.
sl@0: // Called from i) Insert  ii) Delete  iii) Paste from clipboard  iv) Text file import.
sl@0: //
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aPos<0 || aPos>DocumentLength()+1)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_UPDATEPAGETABLE, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength()+1,Panic(ECharPosBeyondDocument));
sl@0: 	
sl@0: 	if (iPageTable)
sl@0: 		(*iPageTable)[PageContainingPos(aPos)]+=aLength;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TInt CPlainText::PageContainingPos(TInt aPos)const
sl@0: /** Gets the number of the page which contains the specified document position. 
sl@0: If no page table has been set up, the function returns a value of zero. Use 
sl@0: SetPageTable() to set up the page table.
sl@0: 
sl@0: @param aPos A document position. Must be valid or a panic occurs. 
sl@0: @return The page number containing document position aPos. */
sl@0:     {
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aPos<0 || aPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_PAGECONTAININGPOS, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 
sl@0:     if (!iPageTable || (iPageTable->Count()<1))
sl@0:         return 0;
sl@0:     else
sl@0:         {
sl@0:         TInt pageOffset=0;
sl@0:         TInt charCount=(*iPageTable)[pageOffset];
sl@0:         while (charCount<=aPos)
sl@0:             {
sl@0:             pageOffset++;
sl@0:             charCount+=(*iPageTable)[pageOffset];
sl@0:             }
sl@0:         return pageOffset;
sl@0:         }
sl@0:     }
sl@0: 
sl@0: EXPORT_C TEtextComponentInfo CPlainText::ComponentInfo()const
sl@0: /** Gets information about the number of components contained in the text object. 
sl@0: For plain text, only the field count has relevance.
sl@0: 
sl@0: @return Contains the field count. */
sl@0: 	{return TEtextComponentInfo(FieldCount(),0,0);}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C TInt CPlainText::FieldCount() const
sl@0: /** Gets a count of the number of fields in the text object's field set.
sl@0: 
sl@0: @return The number of fields in the field set. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	return (FieldSetPresent())
sl@0: 		? iFieldSet->FieldCount()
sl@0: 		: 0;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CPlainText::InsertFieldL(TInt aPos,CTextField* aField,TUid aFieldType)
sl@0: /** Inserts a field into the text object at a specified document position. creating a zero-length field record.
sl@0:  Maintain the field set.
sl@0: 
sl@0: Note: After insertion, the field should be evaluated in order to make its contents 
sl@0: visible; use UpdateFieldL().
sl@0: 
sl@0: @param aPos The document position at which to insert the field. Must be valid, 
sl@0: or a panic occurs. 
sl@0: @param aField The field to insert, created by NewTextFieldL(). Must not be 
sl@0: NULL, or a panic occurs. 
sl@0: @param aFieldType Identifies the type of field to insert. For the built in 
sl@0: field types, see the UID values defined in flddef.h. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aPos<0 || aPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_INSERTFIELDL, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 	if (!aField)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_CPLAINTEXT_INSERTFIELDL, "ENoTextField" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aField,Panic(ENoTextField));
sl@0: 
sl@0: 	if (!FieldSetPresent())
sl@0: 		CreateFieldSetL(DocumentLength());
sl@0: 	iFieldSet->InsertFieldL(aPos,aField,aFieldType);
sl@0: 	SetHasChanged(ETrue);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CPlainText::UpdateFieldL(TInt aPos)
sl@0: /** Re-evaluates the field which covers the document position specified. Re-evaluating 
sl@0: a field means calculating the field's new value, then inserting that value 
sl@0: into the text object, replacing the previous value.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: fields have a maximum length of 20 characters.
sl@0: 
sl@0: the first time a field is updated, the position specified should be the position 
sl@0: at which the field was inserted.
sl@0: 
sl@0: @param aPos A document position in the field to be updated. Must be a valid 
sl@0: position, or a panic occurs. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aPos<0 || aPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_UPDATEFIELDL, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	if (!FieldSetPresent())
sl@0: 		return;
sl@0: 	TFindFieldInfo info;
sl@0: 	if (iFieldSet->FindFields(info,aPos))
sl@0: 		{// a field exists at aPos, so update it.
sl@0: 		HBufC* valueBuf=HBufC::NewL(KMaxFieldBufferSize); // will hold the new value,max length 20
sl@0: 		/*
sl@0: 		Don't put valueBuf on the cleanup stack before calling NewFieldValueL because NewFieldValueL
sl@0: 		sometimes changes valueBuf, in which case it itself puts it on the cleanup stack.
sl@0: 		*/
sl@0: 		iFieldSet->NewFieldValueL(valueBuf,info.iFirstFieldPos);  // get the new value
sl@0: 		CleanupStack::PushL(valueBuf);
sl@0: 		DoPtInsertL(info.iFirstFieldPos,*valueBuf);  // insert the new text into the document
sl@0: 		DoPtDelete(info.iFirstFieldPos+valueBuf->Length(),info.iFirstFieldLen);  // delete the old text of the field
sl@0: 		iFieldSet->NotifyFieldUpdate(aPos,valueBuf->Length());  // inform the field set
sl@0: 		CleanupStack::PopAndDestroy();
sl@0: 		}
sl@0: 	SetHasChanged(ETrue);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::UpdateAllFieldsL()
sl@0: /** Re-evaluates all of the fields in the text object. Re-evaluating a field means 
sl@0: calculating the field's new value, then inserting that value into the text 
sl@0: object, replacing the previous value.
sl@0: 
sl@0: Note: Fields have a maximum length of 20 characters. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	TInt numFields=FieldCount();
sl@0: 	TInt pos=0;
sl@0: 	TFindFieldInfo info;
sl@0: 	for (TInt item=0;item<numFields;item++)
sl@0: 		{
sl@0: 		// find the next field and go to its beginning
sl@0: 		iFieldSet->FindFields(info,pos,DocumentLength()-pos);
sl@0: 		pos=info.iFirstFieldPos;
sl@0: 		UpdateFieldL(pos);
sl@0: 		// the field has changed, find out its new length and go to the end of it
sl@0: 		iFieldSet->FindFields(info,pos);
sl@0: 		pos+=info.iFirstFieldLen;
sl@0: 		}
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C TBool CPlainText::RemoveField(TInt aPos)
sl@0: /** Removes the field covering the document position specified from the field set, 
sl@0: and deletes all text content associated with the field from the text object.
sl@0: 
sl@0: @param aPos A document position within the field to be deleted. Must be a 
sl@0: valid position or a panic occurs. 
sl@0: @return ETrue if a field was located at aPos. EFalse if no field was located 
sl@0: at aPos. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aPos<0 || aPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_REMOVEFIELD, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	TBool fieldRemoved=EFalse;
sl@0: 	
sl@0: 	if (FieldSetPresent())
sl@0: 		{
sl@0: 		TFindFieldInfo info;
sl@0: 		if (iFieldSet->FindFields(info,aPos))
sl@0: 			{// remove the field's record & associated text
sl@0: 			Delete(info.iFirstFieldPos,info.iFirstFieldLen);
sl@0: 			iFieldSet->RemoveField(aPos);
sl@0: 			fieldRemoved=ETrue;
sl@0: 			}
sl@0: 		}
sl@0: 	if (fieldRemoved)
sl@0: 		SetHasChanged(ETrue);
sl@0: 	
sl@0: 	__TEST_INVARIANT;
sl@0: 	return fieldRemoved;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C TBool CPlainText::FindFields(TInt aPos) const
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	if (FieldSetPresent())
sl@0: 		return iFieldSet->FindFields(aPos);
sl@0: 	else
sl@0: 		return EFalse;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C TBool CPlainText::FindFields(TFindFieldInfo& aInfo,TInt aPos,TInt aRange)const
sl@0: /** Tests whether a document position is located within a field overloaded
sl@0: function.
sl@0: 
sl@0: The second overload extracts information about all fields located
sl@0: within a range of characters.
sl@0: 
sl@0: @param aPos The document position. Must be valid or a panic occurs.
sl@0: @param aInfo  On return, contains the number of fields fully or partially 
sl@0: within the range of characters specified and the start position and length 
sl@0: of the first field found.
sl@0: @param   aRange The number of characters to search, beginning at aPos. Must 
sl@0: not be negative, or a panic occurs. The sum of aPos and aRange must be less 
sl@0: than the document length, or a panic occurs. The default range is zero. In 
sl@0: this case the function just returns information about the single field located 
sl@0: at the position specified.
sl@0: @return ETrue if aPos is located within a field, or if there were one or more 
sl@0: fields found in the range. EFalse if not. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	if (FieldSetPresent())
sl@0: 		return iFieldSet->FindFields(aInfo,aPos,aRange);
sl@0: 	else
sl@0: 		return EFalse;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C const CTextField* CPlainText::TextField(TInt aPos)const
sl@0: /** Returns a pointer to the field located at the specified document position.
sl@0: 
sl@0: @param aPos A document position within the field. Must be a valid document 
sl@0: position, or a panic occurs. 
sl@0: @return Pointer to the field which covers position aPos. NULL if there is no 
sl@0: field at the specified position. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	return (FieldSetPresent())
sl@0: 		? iFieldSet->TextField(aPos)
sl@0: 		: NULL;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C TBool CPlainText::ConvertFieldToText(TInt aPos)
sl@0: /** Converts the field containing the specified document position into text, leaving 
sl@0: its current value in the text object. Does not update the field beforehand.
sl@0: 
sl@0: @param aPos A document position within the field to convert. Must be a valid 
sl@0: position or a panic occurs. 
sl@0: @return ETrue if there was a field located at aPos. EFalse if there was no 
sl@0: field located at aPos. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 	if (aPos<0 || aPos>DocumentLength())
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CPLAINTEXT_CONVERTFIELDTOTEXT, "ECharPosBeyondDocument" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument));
sl@0: 
sl@0: 	TBool fieldConverted=EFalse;
sl@0: 	
sl@0: 	if (FieldSetPresent())
sl@0: 		{
sl@0: 		TFindFieldInfo info;
sl@0: 		iFieldSet->FindFields(info,aPos);
sl@0: 		if (iFieldSet->RemoveField(aPos))
sl@0: 			fieldConverted=ETrue;
sl@0: 		}
sl@0: 	if (fieldConverted)
sl@0: 		SetHasChanged(ETrue);
sl@0: 	
sl@0: 	__TEST_INVARIANT;
sl@0: 	return fieldConverted;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C void CPlainText::ConvertAllFieldsToText()
sl@0: /** Removes all fields from the text object's field set, leaving their current 
sl@0: text value in the text object. Does not update the fields beforehand. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	TInt fieldCount=FieldCount();
sl@0: 	TInt pos=0;
sl@0: 	for (TInt item=0;item<fieldCount;item++)
sl@0: 		{// Convert each field in turn.
sl@0: 		TFindFieldInfo info;
sl@0: 		iFieldSet->FindFields(info,pos);  // find the next field and go to its beginning
sl@0: 		pos=info.iFirstFieldPos;
sl@0: 		ConvertFieldToText(pos);
sl@0: 		}
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CPlainText::SetFieldFactory(MTextFieldFactory* aFactory)
sl@0: /** Sets up a field factory. A field factory is an instance of a class deriving 
sl@0: from MTextFieldFactory. It must implement a NewFieldL() function to create 
sl@0: and return fields of the desired type. The field factory's NewFieldL() function 
sl@0: is called by CPlainText::NewTextFieldL(). A field factory must be set up if 
sl@0: you intend to add any fields to the text object.
sl@0: 
sl@0: @param aFactory The field factory. */
sl@0: 	{
sl@0: 	// Set the FieldSet's header factory handle (this points to the built-in factory by default)
sl@0: 	//+ This function has no way to report failure, which can happen if CreateFieldSetL leaves. It ought to leave.
sl@0: 	
sl@0: 	// Create field set if necessary & set the factory
sl@0: 	int error = 0;
sl@0: 	if (!FieldSetPresent())
sl@0: 		TRAP(error,CreateFieldSetL(DocumentLength()));
sl@0: 	if (!error)
sl@0: 		iFieldSet->SetFieldFactory(aFactory);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: EXPORT_C CTextField* CPlainText::NewTextFieldL(TUid aFieldType)const
sl@0: /** Creates and returns a new field. Before calling this function, a field 
sl@0: factory should have been set up, either by calling SetFieldFactory(), or by 
sl@0: specifying one in the NewL(). The field factory's NewFieldL() function is 
sl@0: called to create a field of the type specified in the argument. A NULL field 
sl@0: is returned if no field factory has been set up.
sl@0: 
sl@0: @param aFieldType Identifies the field type. 
sl@0: @return Pointer to the new text field. NULL if no field factory has been set 
sl@0: up. */
sl@0: 	{
sl@0: 	__TEST_INVARIANT;
sl@0: 
sl@0: 	CTextField* field=NULL;
sl@0: 	if (FieldSetPresent())
sl@0: 		field=iFieldSet->NewFieldL(aFieldType);
sl@0: 
sl@0: 	__TEST_INVARIANT;
sl@0: 	return field;
sl@0: 	}
sl@0: 
sl@0: void CPlainText::CreateFieldSetL(TInt aDocumentLength)
sl@0: 	{
sl@0: 	iFieldSet = CTextFieldSet::NewL(aDocumentLength);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C const MTextFieldFactory* CPlainText::FieldFactory()const
sl@0: /** Gets a pointer to the field factory used by the text object. The field factory 
sl@0: may be set up using SetFieldFactory(), or may be specified in the NewL().
sl@0: 
sl@0: @return The field factory. NULL if no field factory has been set up. */
sl@0: 	{return (FieldSetPresent()) ? iFieldSet->FieldFactory() : NULL;}
sl@0: 
sl@0: CEditableTextOptionalData::CEditableTextOptionalData()
sl@0: 	{
sl@0: 	// do nothing
sl@0: 	}
sl@0: 
sl@0: CEditableTextOptionalData::~CEditableTextOptionalData()
sl@0: 	{
sl@0: 	delete iInlineEditData;
sl@0: 	}