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 sl@0: #include sl@0: sl@0: #include "TXTRICH.H" sl@0: #include "TXTINDEX.H" sl@0: #include "TXTSTD.H" sl@0: #include "TXTRTPFL.H" sl@0: #include "ParseLst.h" sl@0: #include "TXTCLIPBOARD.H" sl@0: sl@0: #include "OstTraceDefinitions.h" sl@0: #ifdef OST_TRACE_COMPILER_IN_USE sl@0: #include "TXTRICHTraces.h" sl@0: #endif sl@0: sl@0: #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS sl@0: #include "TXTETEXT_INTERNAL.H" sl@0: #include "TXTRICH_INTERNAL.H" sl@0: #endif sl@0: sl@0: EXPORT_C void CRichText::__DbgTestInvariant()const sl@0: // Provides class invariants. Explanations below: sl@0: // sl@0: { sl@0: #ifdef _DEBUG sl@0: // ASSERT: The global format layers are never null. sl@0: if (iGlobalParaFormatLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_DUMP, CRICHTEXT_DBGTESTINVARIANT, "Invariant" ); sl@0: } sl@0: __ASSERT_DEBUG(iGlobalParaFormatLayer != NULL, User::Invariant()); sl@0: if (iGlobalCharFormatLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_DUMP, DUP1_CRICHTEXT_DBGTESTINVARIANT, "Invariant" ); sl@0: } sl@0: __ASSERT_DEBUG(iGlobalCharFormatLayer != NULL, User::Invariant()); sl@0: if (IndexPresent()) sl@0: { sl@0: // ASSERT: The sum of para lengths == the length as described by the document storage. sl@0: TInt cumulativeParaLength = 0; sl@0: TInt maxPara = iIndex->iParaIx->Count(); sl@0: for (TInt offset = 0; offset < maxPara; offset++) sl@0: { sl@0: TParaAttribsEntry entry = (*iIndex->iParaIx)[offset]; sl@0: cumulativeParaLength += entry.iLength; sl@0: } sl@0: if (cumulativeParaLength != (DocumentLength() + 1)) sl@0: { sl@0: OstTrace0( TRACE_DUMP, DUP2_CRICHTEXT_DBGTESTINVARIANT, "Invariant" ); sl@0: } sl@0: __ASSERT_DEBUG(cumulativeParaLength == (DocumentLength() + 1), User::Invariant()); sl@0: } sl@0: // Change here for defect INC005336. sl@0: // This defect is present when the assertion below fails. sl@0: if ((iParserData != NULL) && sl@0: (iParserData->HaveRange()) && sl@0: (iParserData->EndParse() > DocumentLength())) sl@0: { sl@0: OstTrace0( TRACE_DUMP, DUP3_CRICHTEXT_DBGTESTINVARIANT, "Invariant" ); sl@0: } sl@0: __ASSERT_DEBUG( (iParserData == NULL) || \ sl@0: (!iParserData->HaveRange()) || \ sl@0: (iParserData->EndParse() <= DocumentLength()), User::Invariant()); sl@0: #endif sl@0: } sl@0: sl@0: EXPORT_C CRichText* CRichText::NewL(const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer, sl@0: TDocumentStorage aStorage,TInt aDefaultTextGranularity,TParaType aParaType) sl@0: /** Allocates and constructs an empty rich text object, with a global character sl@0: and paragraph format layer. A single end-of-document delimiter is inserted. sl@0: No style list is allocated. sl@0: sl@0: @param aGlobalParaLayer Pointer to the paragraph format layer referenced by sl@0: the rich text object. Must not be NULL, or a panic occurs. sl@0: @param aGlobalCharLayer Pointer to the character format layer referenced by sl@0: the rich text object. Must not be NULL, or a panic occurs. sl@0: @param aStorage The type of in-memory buffer to use. Defaults to ESegmentedStorage sl@0: which should rarely need to be changed. sl@0: @param aDefaultTextGranularity Specifies the granularity of the in-memory buffer. sl@0: Default is EDefaultTextGranularity bytes (=256), and this should rarely need sl@0: to be changed. sl@0: @param aParaType This argument indicates whether you are using a single paragraph sl@0: or multiple paragraphs, and thus affects the granularity of aggregate objects sl@0: used internally for storing paragraph attributes. Default = EMultiPara. sl@0: @return The rich text object. */ sl@0: { sl@0: // Create new rich text containing just a single end-of-document character. sl@0: if (aGlobalParaLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_NEWL, "ENullFormatLayerHandle" ); sl@0: } sl@0: __ASSERT_ALWAYS(aGlobalParaLayer != NULL, Panic(ENullFormatLayerHandle)); sl@0: if (aGlobalCharLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP1_CRICHTEXT_NEWL, "ENullFormatLayerHandle" ); sl@0: } sl@0: __ASSERT_ALWAYS(aGlobalCharLayer != NULL, Panic(ENullFormatLayerHandle)); sl@0: sl@0: CRichText* self = new(ELeave) CRichText(aGlobalParaLayer, aGlobalCharLayer); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aStorage, aDefaultTextGranularity, aParaType); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: // Create new rich text that supports Paragraph Styles, containing just a single end-of-document character. sl@0: EXPORT_C CRichText* CRichText::NewL(const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer, sl@0: const CStyleList& aStyleList, sl@0: TDocumentStorage aStorage,TInt aDefaultTextGranularity,TParaType aParaType) sl@0: /** Allocates and constructs an empty rich text object which supports styles. It sl@0: is constructed with a global character and paragraph format layer and a style sl@0: list. A single end-of-document delimiter is inserted. The rich text object sl@0: takes ownership of the style list. sl@0: sl@0: Note: sl@0: sl@0: A rich text object not constructed with a style list may still use styles, sl@0: by calling SetStyleListExternallyOwned() at any time after construction. In sl@0: this case, the rich text object does not own the style list. sl@0: sl@0: @param aGlobalParaLayer Pointer to the paragraph format layer referenced by sl@0: the rich text object. Must not be NULL, or a panic occurs. sl@0: @param aGlobalCharLayer Pointer to the character format layer referenced by sl@0: the rich text object. Must not be NULL, or a panic occurs. sl@0: @param aStyleList Style list. Holds the set of paragraph styles which can be sl@0: used in the rich text object. sl@0: @param aStorage The type of in-memory buffer to use. Defaults to ESegmentedStorage sl@0: which should rarely need to be changed. sl@0: @param aDefaultTextGranularity Specifies the granularity of the in-memory buffer. sl@0: Default is EDefaultTextGranularity bytes (=256), and this should rarely need sl@0: to be changed. sl@0: @param aParaType This argument indicates whether you are using a single paragraph sl@0: or multiple paragraphs, and thus affects the granularity of aggregate objects sl@0: used internally for storing paragraph attributes. Default = EMultiPara. sl@0: @return The new rich text object. */ sl@0: { sl@0: if (aGlobalParaLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_NEWL, "ENullFormatLayerHandle" ); sl@0: } sl@0: __ASSERT_ALWAYS(aGlobalParaLayer != NULL, Panic(ENullFormatLayerHandle)); sl@0: if (aGlobalCharLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP3_CRICHTEXT_NEWL, "ENullFormatLayerHandle" ); sl@0: } sl@0: __ASSERT_ALWAYS(aGlobalCharLayer != NULL, Panic(ENullFormatLayerHandle)); sl@0: sl@0: CRichText* self = new(ELeave) CRichText(aGlobalParaLayer, aGlobalCharLayer, CONST_CAST(CStyleList*, &aStyleList)); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aStorage, aDefaultTextGranularity, aParaType); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: // Restore into a new rich text object, using the specified global layers. sl@0: EXPORT_C CRichText* CRichText::NewL(const CStreamStore& aStore,TStreamId aStreamId, sl@0: const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer, sl@0: MTextFieldFactory* aFieldFactory, sl@0: TDocumentStorage aStorage) sl@0: /** Allocates and constructs a rich text object with a field factory. Its text sl@0: content is internalized from a stream store. sl@0: sl@0: Note: sl@0: sl@0: A rich text object not constructed with a field factory may still support sl@0: the addition of fields, by calling SetFieldFactory(), defined in the base sl@0: class CPlainText. sl@0: sl@0: @param aStore Stream store from which the object is restored. sl@0: @param aStreamId ID of the stream store. sl@0: @param aGlobalParaLayer Pointer to the paragraph format layer referenced by sl@0: the rich text object. Must not be NULL, or a panic occurs. sl@0: @param aGlobalCharLayer Pointer to the character format layer referenced by sl@0: the rich text object. Must not be NULL, or a panic occurs. sl@0: @param aFieldFactory Pointer to a field factory. A field factory must be provided sl@0: if the text object supports fields. sl@0: @param aStorage The type of in-memory buffer to use. Defaults to ESegmentedStorage sl@0: which should rarely need to be changed. sl@0: @return The new rich text object. */ sl@0: { sl@0: if (aGlobalParaLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP4_CRICHTEXT_NEWL, "ENullFormatLayerHandle" ); sl@0: } sl@0: __ASSERT_ALWAYS(aGlobalParaLayer != NULL, Panic(ENullFormatLayerHandle)); sl@0: if (aGlobalCharLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP5_CRICHTEXT_NEWL, "ENullFormatLayerHandle" ); sl@0: } sl@0: __ASSERT_ALWAYS(aGlobalCharLayer != NULL, Panic(ENullFormatLayerHandle)); sl@0: sl@0: CRichText* self = new(ELeave) CRichText(aGlobalParaLayer, aGlobalCharLayer); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aStore, aStreamId, NULL, NULL, aFieldFactory, aStorage); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: EXPORT_C CRichText* CRichText::NewL(const CStreamStore& aStore, TStreamId aStreamId, sl@0: const CParaFormatLayer* aGlobalParaLayer, const CCharFormatLayer* aGlobalCharLayer, sl@0: MPictureFactory* aPictureFactory, MRichTextStoreResolver* aStoreResolver, sl@0: MTextFieldFactory* aFieldFactory, sl@0: TDocumentStorage aStorage) sl@0: /** Allocates and constructs a rich text object with a field factory and a picture sl@0: factory. Its text content is internalized from a stream store. sl@0: sl@0: Note: sl@0: sl@0: A rich text object not constructed with a field factory may still support sl@0: the addition of fields, by calling SetFieldFactory(), defined in the base sl@0: class CPlainText. sl@0: sl@0: @param aStore Stream store from which the object is restored. sl@0: @param aStreamId ID of the stream store. sl@0: @param aGlobalParaLayer Pointer to the paragraph format layer referenced by sl@0: the rich text object. Must not be NULL, or a panic occurs. sl@0: @param aGlobalCharLayer Pointer to the character format layer referenced by sl@0: the rich text object. Must not be NULL, or a panic occurs. sl@0: @param aPictureFactory The picture factory. This is needed to load pictures sl@0: into memory, (see PictureHandleL()). If a store resolver is specified (not sl@0: NULL), then a factory must also be specified, or a panic occurs. sl@0: @param aStoreResolver A store resolver. This determines which file store the sl@0: picture is stored in. It is used to get from a reference to an embedded picture sl@0: within a CRichText object to the actual picture itself. Picture loading is sl@0: done by the picture factory. sl@0: @param aFieldFactory Pointer to a field factory. A field factory must be provided sl@0: if the text object supports fields. sl@0: @param aStorage The type of in-memory buffer to use. Defaults to ESegmentedStorage sl@0: which should rarely need to be changed. sl@0: @return The new rich text object. */ sl@0: { sl@0: // Restore a new rich text from the specified stream, that uses the specified global layers, and the sl@0: // specified picture header factory and store, if this rich text supports pictures. sl@0: if (!aPictureFactory && aStoreResolver) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP6_CRICHTEXT_NEWL, "EInvalidPictureFactorySettings" ); sl@0: } sl@0: __ASSERT_ALWAYS(!(!aPictureFactory && aStoreResolver), Panic(EInvalidPictureFactorySettings)); sl@0: if (aGlobalParaLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP7_CRICHTEXT_NEWL, "ENullFormatLayerHandle" ); sl@0: } sl@0: __ASSERT_ALWAYS(aGlobalParaLayer != NULL, Panic(ENullFormatLayerHandle)); sl@0: if (aGlobalCharLayer == NULL) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP8_CRICHTEXT_NEWL, "ENullFormatLayerHandle" ); sl@0: } sl@0: __ASSERT_ALWAYS(aGlobalCharLayer != NULL, Panic(ENullFormatLayerHandle)); sl@0: sl@0: CRichText* self = new(ELeave) CRichText(aGlobalParaLayer, aGlobalCharLayer); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aStore, aStreamId, aPictureFactory, aStoreResolver, aFieldFactory, aStorage); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: EXPORT_C CRichText::CRichText(const CParaFormatLayer* aGlobalParaLayer, const CCharFormatLayer* aGlobalCharLayer, sl@0: CStyleList* aStyleList): sl@0: CGlobalText(aGlobalParaLayer, aGlobalCharLayer), sl@0: iStyleList(aStyleList) sl@0: { sl@0: } sl@0: sl@0: sl@0: EXPORT_C void CRichText::ConstructL(TDocumentStorage aStorage, TInt aDefaultTextGranularity, TParaType aParaType) sl@0: // Initialises and updates the index following the CPlainText::ConstructL sl@0: // insertion of the end-of-document character. sl@0: // sl@0: { sl@0: CPlainText::ConstructL(aStorage, aDefaultTextGranularity); sl@0: SetParaTypeIsSingle(aParaType == ESinglePara); sl@0: iParserData = new(ELeave) CParserData(DocumentLength()); sl@0: TInt a; sl@0: TInt b; sl@0: ParseText(a, b, ETrue); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: sl@0: EXPORT_C void CRichText::ConstructL(const CStreamStore& aStore,TStreamId aStreamId, sl@0: MPictureFactory* aPictureFactory, MRichTextStoreResolver* aStoreResolver, sl@0: MTextFieldFactory* aFieldFactory, sl@0: TDocumentStorage aStorage) sl@0: // Initialises and updates the index following the CPlainText::ConstructL sl@0: // insertion of the end-of-document character. sl@0: // Sets the picture header factory if provided. sl@0: // sl@0: { sl@0: CPlainText::ConstructL(aStore, aStreamId, aFieldFactory, aStorage); sl@0: SetPictureFactory(aPictureFactory, aStoreResolver); sl@0: if (iParserData == NULL) sl@0: iParserData = new(ELeave) CParserData(DocumentLength()); sl@0: TInt a; sl@0: TInt b; sl@0: ParseText(a, b, ETrue); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: sl@0: EXPORT_C CRichText::~CRichText() sl@0: /** The destructor frees all resources owned by the rich text object, prior to sl@0: its destruction. */ sl@0: { sl@0: // We cannot call DestroyParserSystem() here because it applies to all instances in the thread sl@0: delete iParserData; sl@0: KillStyleList(); sl@0: KillIndex(); sl@0: } sl@0: sl@0: sl@0: void CRichText::KillStyleList() sl@0: // Free up the style table sl@0: // sl@0: { sl@0: if (StyleListPresent() && !StyleListExternallyOwned()) sl@0: { sl@0: delete iStyleList.AsPtr(); sl@0: iStyleList = NULL; sl@0: } sl@0: } sl@0: sl@0: sl@0: void CRichText::KillIndex() sl@0: // Delete the rich text index if it's resident in memory. sl@0: // sl@0: { sl@0: if (IndexPresent()) sl@0: delete iIndex.AsPtr(); sl@0: iIndex=NULL; sl@0: } sl@0: sl@0: sl@0: TBool CRichText::CreateEmptyMarkupComponentL() sl@0: // If necessary, creates an empty markup component. sl@0: // Returns ETrue if the markup component was created as a result of this function, sl@0: // otherwise returns EFalse. sl@0: // sl@0: { sl@0: if (IndexPresent()) sl@0: return EFalse; sl@0: TInt paraGran = (ParaTypeIsSingle()) ? KSingleParaGranularity : KMultiParaGranularity; sl@0: TInt phrGran = (ParaTypeIsSingle()) ? KSmallPhraseGranularity : KLargePhraseGranularity; sl@0: iIndex = CRichTextIndex::NewL(iGlobalParaFormatLayer, iGlobalCharFormatLayer, *this,paraGran,phrGran); sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: void CRichText::CreateAndGenerateMarkupComponentL() sl@0: // Checks if the rich text index needs to be created and does so if necessary. sl@0: // Called by all public rich text functions that manipulate specific formatting. sl@0: // sl@0: { sl@0: if (CreateEmptyMarkupComponentL()) sl@0: { sl@0: TRAPD(ret, GenerateMarkupL()); sl@0: if (ret != KErrNone) sl@0: {// destroy this partially set markup component sl@0: delete iIndex.AsPtr(); sl@0: iIndex = NULL; sl@0: User::Leave(ret); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: void CRichText::GenerateMarkupL() sl@0: // Generate markup data corresponding to the current text content. sl@0: // sl@0: { sl@0: TInt remainingLength = DocumentLength(); sl@0: TInt startPos = 0; sl@0: while (remainingLength) sl@0: { sl@0: TPtrC buf = Read(startPos); sl@0: TInt consumed = buf.Length(); sl@0: if (consumed > remainingLength) sl@0: { sl@0: consumed = remainingLength; sl@0: buf.Set(buf.Ptr(), consumed); sl@0: } sl@0: iIndex->InsertL(startPos, buf, *iGlobalParaFormatLayer); sl@0: remainingLength -= consumed; sl@0: startPos += consumed; sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRichText::CopyToStoreL(CStreamStore& aStore,CStreamDictionary& aDictionary,TInt aPos,TInt aLength) const sl@0: /** Copies a portion of the rich text object, with components to the clipboard. sl@0: sl@0: A panic occurs in the following circumstances: sl@0: sl@0: aPos is an invalid document position 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 rich 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: { sl@0: TStreamId plainTextId = CPlainText::DoCopyToStoreL(aStore,aDictionary,aPos,aLength); sl@0: TStreamId id = DoCopyToStoreL(aStore,aPos,aLength,plainTextId,FALSE); sl@0: aDictionary.AssignL(KClipboardUidTypeRichText,id); sl@0: TStreamId idStyles = DoCopyToStoreL(aStore,aPos,aLength,plainTextId,TRUE); sl@0: aDictionary.AssignL(KClipboardUidTypeRichTextWithStyles,idStyles); sl@0: } sl@0: } sl@0: sl@0: sl@0: // Copy the selected region of rich text, with components, to the specified store. sl@0: TStreamId CRichText::DoCopyToStoreL(CStreamStore& aStore,TInt aPos,TInt aLength,TStreamId aPlainTextId,TBool aCopyStyles) const sl@0: { sl@0: __TEST_INVARIANT; sl@0: sl@0: TInt documentLength = DocumentLength(); sl@0: if (aPos < 0 || aPos > documentLength) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_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_CRICHTEXT_DOCOPYTOSTOREL, "ECopyToClipboardNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0,Panic(ECopyToClipboardNegativeLength)); sl@0: if (aPos + aLength > documentLength) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_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,aPlainTextId); sl@0: RStoreWriteStream stream(*map); sl@0: TStreamId id = stream.CreateLC(aStore); sl@0: CopyToStreamL(stream,aPos,aLength,aPlainTextId,aCopyStyles); sl@0: stream.CommitL(); 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: EXPORT_C void CRichText::CopyComponentsL(CStreamStore& aStore,CStoreMap& aMap,TInt aPos,TInt aLength,TStreamId aPlainTextId) const sl@0: { sl@0: if (aPlainTextId == KNullStreamId) sl@0: CPlainText::CopyComponentsL(aStore,aMap,aPos,aLength); sl@0: if (IndexPresent()) sl@0: iIndex->StorePicturesL(aStore,aMap,aPos,aLength); sl@0: } sl@0: sl@0: sl@0: // Copy the selected region of rich text and components to the specified stream. sl@0: EXPORT_C void CRichText::CopyToStreamL(RWriteStream& aStream,TInt aPos,TInt aLength) const sl@0: { sl@0: __TEST_INVARIANT; sl@0: CopyToStreamL(aStream, aPos, aLength, KNullStreamId); sl@0: } sl@0: sl@0: sl@0: /* sl@0: Copy the selected region of rich text and components to the specified stream. sl@0: If aPlainTextId is NULL the plain text component is stored in-line, sl@0: otherwise the reference to the plain text stream component is stored. sl@0: */ sl@0: EXPORT_C void CRichText::CopyToStreamL(RWriteStream& aStream,TInt aPos,TInt aLength,TStreamId aPlainTextId) const sl@0: { sl@0: CopyToStreamL(aStream,aPos,aLength,aPlainTextId,TRUE); sl@0: } sl@0: sl@0: sl@0: void CRichText::CopyToStreamL(RWriteStream& aStream,TInt aPos,TInt aLength,TStreamId aPlainTextId,TBool aCopyStyles) const sl@0: { sl@0: if (aPlainTextId == KNullStreamId) sl@0: { sl@0: aStream.WriteUint8L(TRUE); sl@0: CPlainText::CopyToStreamL(aStream,aPos,aLength); sl@0: } sl@0: else sl@0: { sl@0: aStream.WriteUint8L(FALSE); sl@0: aStream << aPlainTextId; sl@0: } sl@0: sl@0: if (!IndexPresent()) sl@0: CONST_CAST(CRichText*,this)->CreateAndGenerateMarkupComponentL(); sl@0: aStream.WriteUint8L(TRUE); sl@0: iIndex->CopyToStreamL(aStream,aPos,aLength,aCopyStyles); sl@0: } sl@0: sl@0: EXPORT_C TInt CRichText::PasteFromStoreL(const CStreamStore& aStore, const CStreamDictionary& aDictionary, TInt aPos, CParagraphStyle::TStylePasteMode aStylePasteMode) sl@0: /** Pastes the contents of the clipboard into the rich text object at the sl@0: specified document position. Returns the number of characters pasted. sl@0: sl@0: If the text in the clipboard has been formatted using styles, the sl@0: aStylePasteMode argument indicates whether the styles should be preserved sl@0: or discarded. If the argument is not specified, the pasted rich text sl@0: retains all formatting specified in the styles, and any new style sl@0: definitions are added to the style list of the rich text object into which sl@0: it is pasted. sl@0: sl@0: @param aStore The stream store from which to paste the rich text. sl@0: @param aDictionary The stream dictionary. sl@0: @param aPos The document position at which to paste the rich text. Must be sl@0: valid, or a panic occurs. sl@0: @param aStylePasteMode Indicates whether styles in the pasted text should be sl@0: preserved or discarded. sl@0: @return The number of characters pasted. */ sl@0: { sl@0: return DoPasteRtFromStoreL(aStore, aDictionary, aPos, aStylePasteMode); sl@0: } sl@0: sl@0: sl@0: EXPORT_C TInt CRichText::PasteFromStoreL(const CStreamStore& aStore, const CStreamDictionary& aDictionary, TInt aPos) sl@0: // Paste the lesser of i) aMaxPasteLength ii) the entire clipboard contents. sl@0: // Return a count of the number of characters pasted. sl@0: // sl@0: { sl@0: return DoPasteRtFromStoreL(aStore, aDictionary, aPos, CParagraphStyle::EAddNewStyles); sl@0: } sl@0: sl@0: sl@0: TInt CRichText::DoPasteRtFromStoreL(const CStreamStore& aStore, const CStreamDictionary& aDictionary, TInt aPos, CParagraphStyle::TStylePasteMode aStylePasteMode) sl@0: // Paste the rich text data from the specified clipboard, inserting it into this sl@0: // instance at character position aPos. Returns the number of characters pasted. sl@0: // May be 0. sl@0: // sl@0: { sl@0: __TEST_INVARIANT; sl@0: if (aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_DOPASTERTFROMSTOREL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: TUid type = KClipboardUidTypeRichTextWithStyles; sl@0: TStreamId id = aDictionary.At(type); sl@0: if (id == KNullStreamId) sl@0: { sl@0: type = KClipboardUidTypeRichText; sl@0: id = aDictionary.At(type); sl@0: } sl@0: if (id == KNullStreamId) sl@0: { sl@0: type = KClipboardUidTypePlainText; sl@0: id = aDictionary.At(type); sl@0: } sl@0: TInt consumed = 0; sl@0: if (id == KNullStreamId) sl@0: return consumed; sl@0: if (type == KClipboardUidTypeRichText || type == KClipboardUidTypeRichTextWithStyles) sl@0: consumed = PasteRichTextFromStoreL(aStore, aDictionary, id, aPos, aStylePasteMode); sl@0: else if (type == KClipboardUidTypePlainText) sl@0: consumed = PastePlainTextFromStoreL(aStore, id, aPos); sl@0: sl@0: if (consumed) sl@0: { sl@0: iParserData->MergeRange(aPos,0,consumed); sl@0: CallEditObserver(aPos, consumed); sl@0: } sl@0: sl@0: SetHasChanged(ETrue); sl@0: __TEST_INVARIANT; sl@0: return consumed; sl@0: } sl@0: sl@0: sl@0: TInt CRichText::PasteRichTextFromStoreL(const CStreamStore& aStore, const CStreamDictionary& aDictionary, TStreamId& aRichTextStreamId, TInt aPos,CParagraphStyle::TStylePasteMode aStylePasteMode) sl@0: // Paste the plain text stream, then open and paste the rich text markup from the specified stream. sl@0: // sl@0: { sl@0: if (!IndexPresent()) sl@0: CreateAndGenerateMarkupComponentL(); // create the index if it does not already exist sl@0: TStreamId id = aDictionary.At(KClipboardUidTypePlainText); sl@0: // ASSERT: We have rich text, so the plain text stream must exist. sl@0: if (id == KNullStreamId) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_PASTERICHTEXTFROMSTOREL, "EClipboardIntegrity" ); sl@0: } sl@0: __ASSERT_ALWAYS(id != KNullStreamId,Panic(EClipboardIntegrity)); sl@0: TInt consumed = CPlainText::DoPasteFromStoreL(aStore, id, aPos); sl@0: TRAPD(ret, CompletePasteRichTextFromStoreL(aStore, aRichTextStreamId, aPos, aStylePasteMode)); sl@0: if (ret != KErrNone) sl@0: { sl@0: CPlainText::Delete(aPos,consumed); sl@0: OstTrace1( TRACE_FATAL, DUP1_CRICHTEXT_PASTERICHTEXTFROMSTOREL, "Leave code=%d", ret ); sl@0: User::Leave(ret); sl@0: } sl@0: return consumed; sl@0: } sl@0: sl@0: sl@0: void CRichText::CompletePasteRichTextFromStoreL(const CStreamStore& aStore, TStreamId& aRichTextStreamId, TInt aPos, CParagraphStyle::TStylePasteMode aStylePasteMode) sl@0: // sl@0: { sl@0: RStoreReadStream stream; sl@0: stream.OpenLC(aStore, aRichTextStreamId); sl@0: TBool plainTextInline = (TBool)stream.ReadUint8L(); sl@0: if (!plainTextInline) sl@0: { sl@0: TStreamId dummy; sl@0: stream >> dummy; sl@0: } sl@0: TBool markupPresentInClipboard = (TBool)stream.ReadUint8L(); sl@0: if (markupPresentInClipboard) sl@0: iIndex->PasteFromStreamL(aStore, stream, aPos,aStylePasteMode, iGlobalParaFormatLayer, iGlobalCharFormatLayer); sl@0: CleanupStack::PopAndDestroy(); // stream sl@0: } sl@0: sl@0: sl@0: TInt CRichText::PastePlainTextFromStoreL(const CStreamStore& aStore, TStreamId& anId, TInt aPos) sl@0: // Paste the plain text stream, then update the rich text index to show any paragraph delimiters pasted. sl@0: // sl@0: { sl@0: TInt consumed = CPlainText::DoPasteFromStoreL(aStore, anId, aPos); sl@0: // sl@0: if (IndexPresent()) sl@0: { sl@0: TRAPD(ret, CompletePastePlainTextL(aPos, consumed)); sl@0: if (ret != KErrNone) sl@0: { sl@0: CPlainText::Delete(aPos,consumed); sl@0: User::Leave(ret); sl@0: } sl@0: } sl@0: return consumed; sl@0: } sl@0: sl@0: void CRichText::CompletePastePlainTextL(TInt aPos, TInt aCharacterCount) sl@0: // Updates the rich text index following the pasting of global text. sl@0: // sl@0: { sl@0: HBufC* buf = HBufC::NewLC(aCharacterCount); sl@0: TPtr bf = buf->Des(); sl@0: Extract(bf, aPos, aCharacterCount); sl@0: iIndex->InsertL(aPos, bf, *iGlobalParaFormatLayer); sl@0: CleanupStack::PopAndDestroy(); // buf sl@0: } sl@0: sl@0: EXPORT_C void CRichText::Reset() sl@0: /** Resets the document's contents to a single end-of-document delimiter. Also sl@0: deletes the style list if owned by the object. */ sl@0: { sl@0: // Resets document contents to single end-of-document charcter, sl@0: // and resets the index to match document content. sl@0: TInt length = DocumentLength(); sl@0: CPlainText::Reset(); // remove all content bar eod character sl@0: KillStyleList(); // does not get destroyed if externally owned sl@0: KillIndex(); sl@0: SetHasChanged(ETrue); sl@0: iParserData->KillRange(); sl@0: iParserData->iLastKnownCursor = -1; sl@0: CallEditObserver(0, -length); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: EXPORT_C void CRichText::InsertL(TInt aPos, 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: The insertion position must be valid or a panic occurs.Note:A panic sl@0: occurs if the text object is in an "insert pending" state (i.e. sl@0: SetInsertCharFormatL() has been called and has not been sl@0: cancelled using CancelInsertCharFormat()) and aPos is not sl@0: the same as the insertion point. sl@0: sl@0: @param aPos The document position at which to insert the character/descriptor. sl@0: @param aChar The character to insert. Must not be a picture character or a sl@0: panic occurs. sl@0: @param aBuf The descriptor to insert. */ sl@0: { sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_INSERTL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: if (aChar == EPictureCharacter) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP1_CRICHTEXT_INSERTL, "ENonOverloadedInsertCalledWithPictureCharacter" ); sl@0: } sl@0: __ASSERT_ALWAYS(aChar!= EPictureCharacter, Panic(ENonOverloadedInsertCalledWithPictureCharacter)); sl@0: sl@0: if (aChar < 0x10000) sl@0: { sl@0: TBuf<1> content; sl@0: content.Append(aChar); sl@0: RtInsertL(aPos, 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("CRichText::InsertL(), %X expand to %X %X."), TUint(aChar), high, low); sl@0: sl@0: TBuf<2> content; sl@0: content.Append(high); sl@0: content.Append(low); sl@0: RtInsertL(aPos, content); sl@0: } sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: sl@0: EXPORT_C void CRichText::InsertL(TInt aPos, const TDesC& aBuf) sl@0: // Inserts the contents of aBuf into the text component at character position aPos. sl@0: // sl@0: { sl@0: __ETEXT_WATCH(INSERT_DESC); sl@0: sl@0: RtInsertL(aPos, aBuf); sl@0: sl@0: __ETEXT_WATCH_END(INSERT_DESC); sl@0: } sl@0: sl@0: sl@0: EXPORT_C void CRichText::RtInsertL(TInt aPos, const TDesC& aBuf) sl@0: // Inserts the contents a aBuf into the text component at position aPos. sl@0: // Updates the index accordingly, and accounts for all embedded paragraph delimiters sl@0: // in the passed buffer aBuf. sl@0: // sl@0: { sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_RTINSERTL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: int length = aBuf.Length(); sl@0: CPlainText::InsertL(aPos, aBuf); sl@0: if (IndexPresent()) sl@0: { sl@0: TRAPD(ret, iIndex->InsertL(aPos, aBuf, *iGlobalParaFormatLayer)); sl@0: if (ret != KErrNone) sl@0: { sl@0: CPlainText::Delete(aPos,length); sl@0: User::Leave(ret); sl@0: } sl@0: SetHasChanged(ETrue); sl@0: } sl@0: sl@0: iParserData->MergeRange(aPos,0,length); sl@0: CallEditObserver(aPos,length); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: sl@0: EXPORT_C void CRichText::InsertL(TInt aPos,const TPictureHeader& aHeader) sl@0: /**Inserts a picture header into the text object at a specified document sl@0: position. The picture header specified must reference a valid picture, or sl@0: a panic occurs. sl@0: sl@0: A panic also occurs if the text object is in an "insert pending" state sl@0: (SetInsertCharFormatL() has been called and has not been cancelled using sl@0: CancelInsertCharFormat()) and aPos is not the same as the insertion point. sl@0: sl@0: This method takes ownership of a picture referenced in aHeader. sl@0: sl@0: @param aPos The document position at which to insert the picture header. Must sl@0: be valid, or a panic occurs. sl@0: @param aHeader A picture header. This holds a pointer to the picture to insert, sl@0: and information about the picture. */ sl@0: { sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_INSERTL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: CleanupStack::PushL(aHeader.iPicture); sl@0: sl@0: if (!IndexPresent()) sl@0: CreateAndGenerateMarkupComponentL(); sl@0: TBuf<1> picture; sl@0: picture.Append(EPictureCharacter); sl@0: CPlainText::InsertL(aPos, picture); sl@0: sl@0: CleanupStack::Pop(aHeader.iPicture); sl@0: sl@0: TBool pictureOwnershipTaken(EFalse); sl@0: TRAPD(ret, iIndex->InsertL(aPos, aHeader,pictureOwnershipTaken)); sl@0: if (ret != KErrNone) sl@0: { sl@0: if(!pictureOwnershipTaken) sl@0: { sl@0: const_cast (aHeader).DeletePicture(); sl@0: } sl@0: CPlainText::Delete(aPos,picture.Length()); // remove the picture place-holder sl@0: User::Leave(ret); sl@0: } sl@0: sl@0: SetHasChanged(ETrue); sl@0: iParserData->MergeRange(aPos,0,1); sl@0: CallEditObserver(aPos,1); sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: sl@0: EXPORT_C TBool CRichText::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. Can leave because paragraphs may be merged sl@0: and reformatted by the function. sl@0: sl@0: @param aPos The start of the range of characters to delete. 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 as a result of the sl@0: delete, indicating that the formatting of part of the resulting paragraph sl@0: may have changed. */ sl@0: { sl@0: // Deletes aRange number of characters from the text component sl@0: // and the corresponding index data. sl@0: // Delete commences at, and includes, character position aPos. sl@0: __TEST_INVARIANT; sl@0: sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_DELETEL, "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_CRICHTEXT_DELETEL, "EDebugDeleteZeroLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0, Panic(EDebugDeleteZeroLength)); sl@0: if (aPos + (aLength - 1) > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_DELETEL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + (aLength - 1) <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: TBool requireMerge = EFalse; sl@0: if (!IndexPresent()) sl@0: CPlainText::Delete(aPos,aLength); sl@0: else sl@0: { sl@0: iIndex->CancelInsertCharFormat(); sl@0: TIndexDeleteInfo info; sl@0: iIndex->SetForDeleteL(info, aPos, aLength); sl@0: CPlainText::Delete(aPos,aLength); sl@0: requireMerge = iIndex->DeleteNow(info); sl@0: } sl@0: iParserData->MergeRange(aPos,aLength,0); sl@0: CallEditObserver(aPos,-aLength); sl@0: sl@0: __TEST_INVARIANT; sl@0: return requireMerge; sl@0: } sl@0: sl@0: EXPORT_C void CRichText::DeleteParagraph(TInt aPos, TInt aLength) sl@0: /** Deletes one or more whole paragraphs of text. No paragraphs can be merged together sl@0: by this function, so it cannot leave it must only be used to delete entire sl@0: paragraphs. sl@0: sl@0: @param aPos The document position of the start of the first paragraph to delete. sl@0: Must be a valid position or a panic occurs. sl@0: @param aLength The number of characters to delete. */ sl@0: { sl@0: // Use to remove entire paragraphs of text. sl@0: // Leave-safe if called in this context. sl@0: // MUST NOT CALL if not in this context. sl@0: __TEST_INVARIANT; sl@0: sl@0: // Store the length of the text before we commence with deletions. sl@0: TInt initialDocLen=DocumentLength(); sl@0: sl@0: if (aPos < 0 || aPos > initialDocLen) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_DELETEPARAGRAPH, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= initialDocLen, Panic(ECharPosBeyondDocument)); sl@0: if (aPos + aLength > initialDocLen + 1) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP1_CRICHTEXT_DELETEPARAGRAPH, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + aLength <= initialDocLen + 1, Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (aLength <= 0) sl@0: return; sl@0: sl@0: if (IndexPresent()) sl@0: iIndex->DeleteParagraph(aPos, aLength); sl@0: CPlainText::Delete(aPos,aLength); sl@0: sl@0: // Change here for defect INC005336. sl@0: // Previously the MergeRange call (see else line) was incorrectly handling sl@0: // the scenario where all but the first paragraph was deleted e.g. pasting sl@0: // multi line buffer into a single line text control in a new email on Techview sl@0: // emulator. sl@0: // This was because the deletion in the two lines above would delete the sl@0: // 'end-of-text' maker causing the iEndParse member of CParserData to sl@0: // index the char right after the end of test marker. This would panic sl@0: // plugin parsers thatsubsquently executed. sl@0: sl@0: if (aPos+aLength > initialDocLen) sl@0: // When deletion includes the end-of-text marker, adjust start sl@0: // supplied so that it appears to MergeRange that we are sl@0: // deleting the paragraph and CR just before it which belongs sl@0: // to the previous paragraph and not the end-of-text marker. sl@0: // This is actually the end result of the deletion anyway! sl@0: iParserData->MergeRange(initialDocLen-aLength,aLength,0); sl@0: else sl@0: // All other deletions which don't. sl@0: iParserData->MergeRange(aPos,aLength,0); sl@0: sl@0: CallEditObserver(aPos,-aLength); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: EXPORT_C void CRichText::DeleteFromParagraph(TInt aPos, TInt aLength) sl@0: /** Removes a range of characters from within a single paragraph only. Should not sl@0: be used for deleting an entire paragraph or paragraphs because this may cause sl@0: it to leave. Otherwise, it is guaranteed not to leave. sl@0: sl@0: @param aPos The document position of the start of the range of characters sl@0: to delete. Must be a valid document position, or a panic occurs. sl@0: @param aLength The number of characters to delete. The sum of aPos and aLength sl@0: must be less than the document length, or a panic occurs. */ sl@0: { sl@0: // Removes aLength characters from *within* a single paragraph only. sl@0: // Guaranteed not to leave if this pre-condition holds true. sl@0: __TEST_INVARIANT; sl@0: sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_DELETEFROMPARAGRAPH, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: if (aPos + (aLength - 1) > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP1_CRICHTEXT_DELETEFROMPARAGRAPH, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + (aLength - 1) <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (aLength <= 0) sl@0: return; sl@0: sl@0: if (IndexPresent()) sl@0: iIndex->DeleteFromParagraph(aPos, aLength); sl@0: CPlainText::Delete(aPos,aLength); sl@0: iParserData->MergeRange(aPos,aLength,0); sl@0: CallEditObserver(aPos,-aLength); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: EXPORT_C TInt CRichText::ParagraphCount()const sl@0: /** Gets a count of the number of paragraphs in the text object. sl@0: sl@0: Note: sl@0: sl@0: The paragraph delimiter which terminates every text object means this function sl@0: always returns a count of at least one. sl@0: sl@0: @return The number of paragraphs in the document. */ sl@0: { sl@0: // Returns a count of the number of paragraphs sl@0: // in the document. sl@0: // sl@0: __TEST_INVARIANT; sl@0: sl@0: if (IndexPresent()) sl@0: return iIndex->ParagraphCount(); sl@0: else sl@0: return CPlainText::ParagraphCount(); sl@0: } sl@0: sl@0: sl@0: EXPORT_C TEtextComponentInfo CRichText::ComponentInfo() const sl@0: /** Gets information about the number of components contained in the text object sl@0: (the field count, the picture count and the style count). sl@0: sl@0: @return Contains the component information. */ sl@0: { sl@0: return TEtextComponentInfo(FieldCount(), PictureCount(), StyleCount()); sl@0: } sl@0: sl@0: EXPORT_C TInt CRichText::CharPosOfParagraph(TInt& aLength, TInt aParaOffset) const sl@0: /** Finds the length and the start position of a paragraph identified by its sl@0: paragraph number. The first paragraph is numbered zero. sl@0: sl@0: Notes: sl@0: sl@0: if aParaOffset is invalid, (equal to or greater than the total number of sl@0: paragraphs), the function's return value is EScanEndOfData (= -1) sl@0: sl@0: @param aLength On return contains the length of the specified paragraph. sl@0: @param aParaOffset The paragraph number. The first paragraph is numbered zero. sl@0: @return The document position of the first character in the paragraph. */ sl@0: { sl@0: // Returns the character position of the first character of paragraph aParaOffset, sl@0: // where aParaOffset specifies the nth paragraph. sl@0: // The length of this nth paragraph is written to aLength. sl@0: // sl@0: // If aParaOffset specifies a paragraph that does not exist, EScanEndOfData is returned. sl@0: // sl@0: __TEST_INVARIANT; sl@0: sl@0: if (IndexPresent()) sl@0: return iIndex->CharPosOfParagraph(aLength, aParaOffset); sl@0: else sl@0: return CPlainText::CharPosOfParagraph(aLength, aParaOffset); sl@0: } sl@0: sl@0: EXPORT_C TInt CRichText::ParagraphNumberForPos(TInt& aPos) const sl@0: /** Gets the number of the paragraph which contains a document position. sl@0: Paragraph numbering begins at zero. sl@0: sl@0: @param aPos A document position. Must be valid or a panic occurs. On return, sl@0: contains the document position of the first character in the paragraph in sl@0: which it is located. sl@0: @return The number of the paragraph containing the specified document position. */ sl@0: { sl@0: // Returns the paragraph offset for the specified character position aPos. sl@0: // aPos is in turn modified to hold the character position of the first character sl@0: // of this paragraph. If aPos is already on a paragraph boundary then do nothing. sl@0: // sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_PARAGRAPHNUMBERFORPOS, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (IndexPresent()) sl@0: return iIndex->ParagraphNumberForPos(aPos); sl@0: else sl@0: return CPlainText::ParagraphNumberForPos(aPos); sl@0: } sl@0: sl@0: /** Applies character formatting to a zero length selection, for example sl@0: turning bold on. This has the effect that the formatting will be applied to sl@0: text subsequently inserted at the position. This "insert pending" state is sl@0: cancelled by calling CancelInsertCharFormat(). sl@0: sl@0: Note 1: After calling this function, if text is inserted at a different sl@0: position to aPos, a panic will occur, unless CancelInsertCharFormat() has been sl@0: called before the insertion to cancel the "insert pending" state. sl@0: sl@0: Note 2: If the insert character format is being set for the end of the sl@0: paragraph, the paragraph delimiter is set to that format as well. This helps sl@0: end-of-paragraph behaviour be more similar to other places. sl@0: sl@0: @param aFormat The character format values to apply. sl@0: @param aMask Character format mask specifying the attributes affected. sl@0: @param aPos The document position at which to insert the character format. sl@0: @pre aPos must be a valid position, or a panic will occur. */ sl@0: EXPORT_C void CRichText::SetInsertCharFormatL(const TCharFormat& aFormat, sl@0: const TCharFormatMask& aMask, TInt aPos) sl@0: { sl@0: SetExtendedInsertCharFormatL(aFormat, aMask,aPos); sl@0: } sl@0: sl@0: void CancelInsertCharFormat(TAny* aCRichTextIndex) sl@0: { sl@0: reinterpret_cast(aCRichTextIndex)->CancelInsertCharFormat(); sl@0: } sl@0: sl@0: void CRichText::SetExtendedInsertCharFormatL(const TCharFormatX& aFormat, const TCharFormatXMask& aMask, TInt aPos) sl@0: { sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_SETEXTENDEDINSERTCHARFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: CreateAndGenerateMarkupComponentL(); sl@0: CRichTextIndex* index = iIndex.AsPtr(); sl@0: if (index->InsertCharFormatIsActive()) sl@0: { sl@0: TCharFormatX format = aFormat; sl@0: TCharFormatXMask mask = aMask; sl@0: CCharFormatLayer* currentLayer = index->GetCurrentInsertCharFormat(); sl@0: currentLayer->Sense(format,mask); sl@0: CCharFormatLayer* newLayer = CCharFormatLayer::NewCopyBaseL(currentLayer); sl@0: CleanupStack::PushL(newLayer); sl@0: newLayer->SetL(format,mask); sl@0: if (Read(aPos, 1)[0] == EParagraphDelimiter) sl@0: index->ApplyCharFormatL(aFormat, aMask, aPos, 1, EFalse); sl@0: if (index->InsertCharFormatIsActive()) sl@0: { sl@0: currentLayer = index->GetCurrentInsertCharFormat(); sl@0: currentLayer->Swap(*newLayer); sl@0: } sl@0: CleanupStack::PopAndDestroy(newLayer); sl@0: } sl@0: else sl@0: { sl@0: TCleanupItem cleanup(::CancelInsertCharFormat, index); sl@0: CleanupStack::PushL(cleanup); sl@0: index->NewInsertCharFormatL(aFormat, aMask, aPos); sl@0: if (Read(aPos, 1)[0] == EParagraphDelimiter) sl@0: index->ApplyCharFormatL(aFormat, aMask, aPos, 1, EFalse); sl@0: CleanupStack::Pop(); sl@0: } sl@0: SetHasChanged(TRUE); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::ExtendedInterface(TAny*& aInterface, TUid aInterfaceId) sl@0: /** sl@0: Returns the interface corresponding to the specified UID if it exists, or 0 if not. sl@0: Overridden versions should base call rather than returning 0. sl@0: For KUidRichText, CRichText will be returned if rich text is supported. 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: { sl@0: if(KUidRichText == aInterfaceId) sl@0: { sl@0: aInterface = REINTERPRET_CAST(TAny*, this); sl@0: } sl@0: else sl@0: { sl@0: CGlobalText::ExtendedInterface(aInterface, aInterfaceId); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C TBool CRichText::DelSetInsertCharFormatL(TInt aPos, TInt aLength) sl@0: /** Deletes a range of characters. The range affected is from aPos to sl@0: aPos+(aLength-1) inclusive. It differs from DeleteL() in that this function sl@0: preserves the formatting of the deleted character at position aPos, so that sl@0: any text subsequently inserted at aPos will have that formatting applied to it. sl@0: sl@0: A panic occurs if: sl@0: sl@0: after calling this function, text is inserted at a different position to aPos, sl@0: without calling CancelInsertCharFormat() before the insertion sl@0: sl@0: aPos is invalid sl@0: sl@0: aLength is negative sl@0: sl@0: the range goes beyond the end of the document sl@0: sl@0: @param aPos The document position of the first character to delete. sl@0: @param aLength The number of characters to delete. sl@0: @return ETrue if two paragraphs have been merged as a result of the deletion; sl@0: EFalse if there has been no paragraph merge. */ sl@0: { sl@0: // Delete aLength characters, commencing at, and including, aPos. sl@0: // If aPos is on a phrase boundary, and the whole phrase or more is deleted then sl@0: // remember temporarily the phrase format. This is applied to any content that is sl@0: // immediately inserted. sl@0: // sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_DELSETINSERTCHARFORMATL, "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_CRICHTEXT_DELSETINSERTCHARFORMATL, "EDebugDeleteZeroLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0, Panic(EDebugDeleteZeroLength)); sl@0: if (aPos + (aLength - 1) > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_DELSETINSERTCHARFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + (aLength - 1) <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: TBool parasMerged = EFalse; sl@0: if (!IndexPresent()) sl@0: CPlainText::DeleteL(aPos, aLength); sl@0: else sl@0: { sl@0: parasMerged = iIndex->DelSetInsertCharFormatL(aPos, aLength); sl@0: CPlainText::Delete(aPos,aLength); sl@0: SetHasChanged(ETrue); sl@0: } sl@0: iParserData->MergeRange(aPos,aLength,0); sl@0: CallEditObserver(aPos,-aLength); sl@0: sl@0: __TEST_INVARIANT; sl@0: return parasMerged; sl@0: } sl@0: sl@0: EXPORT_C void CRichText::CancelInsertCharFormat() sl@0: /** Cancels the "insert pending" state set by a call to SetInsertCharFormatL() sl@0: or DelSetInsertCharFormatL(). sl@0: sl@0: This function removes the restriction on the text insertion position imposed sl@0: by these two functions. It is recommended that it is called before every cursor sl@0: movement, scroll, paste, etc. This call is a small overhead, and has no effect sl@0: if not applicable. */ sl@0: { sl@0: // Cancels the transitory state where a specified character format sl@0: // is applied *on top of* any inherited formatting. eg, when bold is on. sl@0: // Cancel when: (1) the text position is altered. (2) the first character sl@0: // has been inserted following the setting of this state. sl@0: // sl@0: if (IndexPresent() && iIndex->InsertCharFormatIsActive()) sl@0: { sl@0: iIndex->CancelInsertCharFormat(); sl@0: SetHasChanged(ETrue); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRichText::ApplyParaFormatL(const CParaFormat* aFormat, const TParaFormatMask& aMask, TInt aPos, TInt aLength) sl@0: /** Applies paragraph formatting to a range of paragraphs. The attributes which sl@0: are set in the mask are taken from aFormat and applied. The attributes which sl@0: are not set in the mask are not changed. sl@0: sl@0: The region affected consists of every paragraph containing one or more sl@0: characters in the range aPos to aPos+(aLength-1). sl@0: sl@0: @param aFormat Contains the paragraph format attribute values to apply. sl@0: @param aMask Specifies which paragraph format attributes should be affected. sl@0: @param aPos The document position of the start of the range. sl@0: @param aLength The number of characters in the range. */ sl@0: { sl@0: // Applies the specified format attributes to the paragraphs covering sl@0: // character position aPos to aPos+aLength-1. sl@0: // sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_APPLYPARAFORMATL, "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_CRICHTEXT_APPLYPARAFORMATL, "EApplyParaFormatNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0,Panic(EApplyParaFormatNegativeLength)); sl@0: if (aPos + (aLength - 1) > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_APPLYPARAFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + (aLength - 1) <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: CreateAndGenerateMarkupComponentL(); sl@0: iIndex->ApplyParaFormatL(aFormat, aMask, aPos, aLength); sl@0: SetHasChanged(ETrue); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: EXPORT_C void CRichText::ApplyCharFormatL(const TCharFormat& aFormat, const TCharFormatMask& aMask, TInt aPos, TInt aLength) sl@0: /** Applies character formatting to a range of characters. The attributes which sl@0: are set in the mask are read from aFormat and applied. The attributes which sl@0: are not set in the mask are not changed. The range of characters affected sl@0: is from aPos to aPos+(aLength-1) inclusive. The sum of aPos and aLength sl@0: must be less than or equal to the document length, or a panic occurs. sl@0: sl@0: @param aFormat Contains the character format attribute values to apply. sl@0: @param aMask Bitmask specifying which character format attributes should be sl@0: applied. sl@0: @param aPos Document position from which to apply the new character formatting. sl@0: Must be greater than or equal to zero, or a panic occurs. sl@0: @param aLength The number of characters to which the new formatting should sl@0: be applied. Must be greater than or equal to zero, or a panic occurs. If the sl@0: length is zero, the function has the same effect as SetInsertCharFormatL(). */ sl@0: { sl@0: // Applies the specified character formatting to the characters conatined within the range sl@0: // aPos to aPos+(aLength-1). sl@0: // If aLength is zero, the SetInsertCharFormat state is called. sl@0: // sl@0: __ETEXT_WATCH(APPLY_CHAR_FORMAT); sl@0: __TEST_INVARIANT; sl@0: sl@0: TInt document_length = DocumentLength(); sl@0: if (aPos < 0) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_APPLYCHARFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0,Panic(ECharPosBeyondDocument)); sl@0: if (aLength < 0) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP1_CRICHTEXT_APPLYCHARFORMATL, "EApplyCharFormatNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0,Panic(EApplyCharFormatNegativeLength)); sl@0: if (aPos + aLength - 1 > document_length) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_APPLYCHARFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + aLength - 1 <= document_length,Panic(ECharPosBeyondDocument)); sl@0: sl@0: //If some characters are highlighted AND current position + highlighted txt = document length sl@0: // Fix for INC097216. Compensate for the changes introduced to Form in defect fix INC087637, sl@0: // which now considers the height of the EOD character; meaning that this character now sl@0: // needs to be formatted along with rest of text. sl@0: if ((aLength > 0) && (aPos + aLength == document_length)) sl@0: { sl@0: aLength++; sl@0: } sl@0: sl@0: DoApplyExtendedCharFormatL(aFormat, aMask, aPos, aLength); sl@0: sl@0: __TEST_INVARIANT; sl@0: __ETEXT_WATCH_END(APPLY_CHAR_FORMAT); sl@0: } sl@0: sl@0: // This method is used internally only. It does not format the EOD character. sl@0: void CRichText::ApplyExtendedCharFormatL(const TCharFormatX& aFormat,const TCharFormatXMask& aMask,TInt aPos,TInt aLength) sl@0: { sl@0: TInt document_length = DocumentLength(); sl@0: if (aPos < 0) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_APPLYEXTENDEDCHARFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0,Panic(ECharPosBeyondDocument)); sl@0: if (aLength < 0) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP1_CRICHTEXT_APPLYEXTENDEDCHARFORMATL, "EApplyCharFormatNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0,Panic(EApplyCharFormatNegativeLength)); sl@0: if (aPos + aLength - 1 > document_length) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_APPLYEXTENDEDCHARFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + aLength - 1 <= document_length,Panic(ECharPosBeyondDocument)); sl@0: sl@0: DoApplyExtendedCharFormatL(aFormat, aMask, aPos, aLength); sl@0: } sl@0: sl@0: // Apply the extended character formatting. sl@0: void CRichText::DoApplyExtendedCharFormatL(const TCharFormatX& aFormat,const TCharFormatXMask& aMask,TInt aPos,TInt aLength) sl@0: { sl@0: if (aLength > 0) sl@0: { sl@0: CreateAndGenerateMarkupComponentL(); sl@0: iIndex->ApplyCharFormatL(aFormat,aMask,aPos,aLength); sl@0: SetHasChanged(ETrue); sl@0: } sl@0: else sl@0: SetExtendedInsertCharFormatL(aFormat,aMask,aPos); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::SetStyleListExternallyOwned(const CStyleList& aStyleList) sl@0: /** Assigns an externally owned style list to the rich text object. sl@0: Replaces any previous style list used by the object. Calls sl@0: SetStyleListExternallyOwned(ETrue). sl@0: sl@0: @param aExternallyOwned The style list to assign to this rich text object. sl@0: Not owned by the rich text object. */ sl@0: { sl@0: CStyleList* styleList = CONST_CAST(CStyleList*, &aStyleList); sl@0: iStyleList = styleList; sl@0: SetStyleListExternallyOwned(ETrue); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::ApplyParagraphStyleL(const CParagraphStyle& aStyle, TInt aPos, TInt aLength, CParagraphStyle::TApplyParaStyleMode aMode) sl@0: /** Applies a specified paragraph style to a range of paragraphs. The region sl@0: affected consists of every paragraph containing one or more characters in the sl@0: range aPos to aPos+(aLength-1). sl@0: sl@0: A panic occurs if: sl@0: sl@0: aPos is invalid, or sl@0: sl@0: aLength is negative, or sl@0: sl@0: the range goes beyond the end of the document, or sl@0: sl@0: the rich text object has no style list sl@0: sl@0: @param aStyle The style to apply. sl@0: @param aPos The document position of the start of the range. sl@0: @param aLength The number of characters in the range. sl@0: @param aMode Controls what specific formatting, if any, should be preserved sl@0: when the style is applied. */ sl@0: { sl@0: // Applies the specified paragraph style to the paragraphs covering sl@0: // character positions aPos to aPos+aLength-1. sl@0: // sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_APPLYPARAGRAPHSTYLEL, "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_CRICHTEXT_APPLYPARAGRAPHSTYLEL, "EApplyParaStyleNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0, Panic(EApplyParaStyleNegativeLength)); sl@0: if (aPos + (aLength - 1) > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_APPLYPARAGRAPHSTYLEL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + (aLength - 1) <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: if (!StyleListPresent()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP3_CRICHTEXT_APPLYPARAGRAPHSTYLEL, "ERichTextNotSetForUsingStyles" ); sl@0: } sl@0: __ASSERT_ALWAYS(StyleListPresent(), Panic(ERichTextNotSetForUsingStyles)); sl@0: sl@0: CreateAndGenerateMarkupComponentL(); sl@0: iIndex->ApplyParagraphStyleL(aStyle, aPos, aLength, iGlobalCharFormatLayer, aMode); sl@0: SetHasChanged(ETrue); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: EXPORT_C void CRichText::NotifyStyleChangedL(const CParagraphStyle* aTo, const CParagraphStyle* aFrom) sl@0: /** Removes a style from every paragraph in the document to which it applies, sl@0: and replaces it with another. sl@0: sl@0: If style aTo is NULL, aFrom is replaced by the global character and paragraph sl@0: format layers, so that in effect, style aFrom is removed. Any specific sl@0: formatting which has been applied to the paragraphs is retained. sl@0: sl@0: Notes: sl@0: sl@0: This function should be called on the text content object after changing a sl@0: style in the style list. sl@0: sl@0: A panic occurs if the rich text object does not use a style list (this can sl@0: be tested for using StyleListPresent()). sl@0: sl@0: @param aTo The new paragraph style to apply. sl@0: @param aFrom The paragraph style to remove. */ sl@0: { sl@0: // Update the rich text index following the change of an applied paragraph style. sl@0: // sl@0: __TEST_INVARIANT; sl@0: if (!StyleListPresent()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_NOTIFYSTYLECHANGEDL, "ERichTextNotSetForUsingStyles" ); sl@0: } sl@0: __ASSERT_ALWAYS(StyleListPresent(), Panic(ERichTextNotSetForUsingStyles)); sl@0: sl@0: CreateAndGenerateMarkupComponentL(); sl@0: iIndex->NotifyStyleChangedL(aTo, aFrom, *iGlobalParaFormatLayer, *iGlobalCharFormatLayer); sl@0: SetHasChanged(ETrue); sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: EXPORT_C const CParaFormatLayer* CRichText::ParagraphStyle(TBool& aStyleChangesOverRange, TInt aPos, TInt aLength) const sl@0: /** Gets a pointer to the first paragraph style encountered in the specified sl@0: range. sl@0: sl@0: @param aStyleChangesOverRange On return, set to ETrue if more than one paragraph sl@0: style is used over the specified range of characters. Otherwise EFalse sl@0: @param aPos The document position of the start of the range. Must be valid. sl@0: @param aLength The number of characters in the range. Must be greater than sl@0: or equal to zero. sl@0: @return Pointer to the paragraph style which applies to the paragraph containing sl@0: document position aPos. Its type (returned by CParaFormatLayer::Type()) sl@0: indicates whether this object is a style, or just a paragraph format layer. */ sl@0: { sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_PARAGRAPHSTYLE, "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_CRICHTEXT_PARAGRAPHSTYLE, "EParagraphStyleNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0,Panic(EParagraphStyleNegativeLength)); sl@0: if (aPos + (aLength - 1) > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_PARAGRAPHSTYLE, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + (aLength - 1) <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (IndexPresent()) sl@0: return iIndex->ParagraphStyle(aStyleChangesOverRange, aPos, aLength); sl@0: else sl@0: { sl@0: aStyleChangesOverRange = EFalse; sl@0: return iGlobalParaFormatLayer; sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRichText::SetHasChanged(TBool aHasChanged) sl@0: /** Sets whether the document's content or formatting has changed. This function sl@0: is called with an value of ETrue by all functions which modify the text content sl@0: or formatting. Use CEditableText::HasChanged() to test whether the document sl@0: has changed. sl@0: sl@0: @param aHasChanged ETrue if the text object has been changed, EFalse if not. */ sl@0: { sl@0: // Replaces the base class method of the same name. sl@0: // sl@0: if (aHasChanged && IndexPresent()) sl@0: iIndex->DocumentChanged(); sl@0: CGlobalText::SetHasChanged(aHasChanged); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::RemoveSpecificParaFormatL(TInt aPos, TInt aLength) sl@0: /** Removes all specific paragraph formatting from a range of paragraphs. This sl@0: does not remove formatting from the object's global paragraph format layer. sl@0: The region affected consists of every paragraph containing one or more sl@0: characters in the range covered by document position aPos to aPos+(aLength-1) sl@0: inclusive. sl@0: sl@0: A panic occurs in the following situations: sl@0: sl@0: the position is negative, sl@0: sl@0: the length is negative, sl@0: sl@0: the range goes beyond the end of the document sl@0: sl@0: @param aPos The document position of the start of the range. sl@0: @param aLength The number of characters in the range. */ sl@0: { sl@0: // Removes all specific paragraph formatting from the selected region. sl@0: // sl@0: __ETEXT_WATCH(REMOVE_PARA_FORMAT); sl@0: sl@0: __TEST_INVARIANT; sl@0: sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_REMOVESPECIFICPARAFORMATL, "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_CRICHTEXT_REMOVESPECIFICPARAFORMATL, "ERemoveSpecificParaFormatNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0, Panic(ERemoveSpecificParaFormatNegativeLength)); sl@0: if (aPos + (aLength - 1) > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_REMOVESPECIFICPARAFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + (aLength - 1) <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (IndexPresent()) sl@0: { sl@0: iIndex->RemoveSpecificParaFormatL(aPos, aLength); sl@0: SetHasChanged(ETrue); sl@0: } sl@0: sl@0: __TEST_INVARIANT; sl@0: sl@0: __ETEXT_WATCH_END(REMOVE_PARA_FORMAT); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::RemoveSpecificCharFormatL(TInt aPos, TInt aLength) sl@0: /** Removes all specific character formatting from a range of characters (does sl@0: not remove the formatting which has been taken from the object's global character sl@0: format layer). A panic occurs in the following situations: sl@0: sl@0: the position is negative, sl@0: sl@0: the length is negative, sl@0: sl@0: the range goes beyond the end of the document sl@0: sl@0: @param aPos The document position of the start of the region affected. sl@0: @param aLength The number of characters in the region affected. If zero, the sl@0: function has no effect. */ sl@0: { sl@0: __TEST_INVARIANT; sl@0: sl@0: TInt document_length = DocumentLength(); sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_REMOVESPECIFICCHARFORMATL, "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_CRICHTEXT_REMOVESPECIFICCHARFORMATL, "ERemoveSpecificParaFormatNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0, Panic(ERemoveSpecificParaFormatNegativeLength)); sl@0: if (aPos + (aLength - 1) > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_REMOVESPECIFICCHARFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + (aLength - 1) <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: // in correspondance to INC097216, character format removing considers the height of end of document sl@0: // character sl@0: if (aPos + aLength == document_length) sl@0: { sl@0: aLength++; sl@0: } sl@0: sl@0: if (aLength > 0 && IndexPresent()) sl@0: { sl@0: iIndex->RemoveSpecificCharFormatL(aPos, aLength); sl@0: SetHasChanged(ETrue); sl@0: } sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: EXPORT_C void CRichText::GetChars(TPtrC& aText, TCharFormat& aFormat, TInt aPos) const sl@0: /** Gets a constant pointer descriptor to a portion of the text object sl@0: with constant character formatting. sl@0: sl@0: The view starts at the document position specified, and ends at: the sl@0: last character which shares the same character formatting, orthe end sl@0: of the document, orthe end of the segment, if segmented storage is sl@0: being usedwhichever occurs first. Also fills a character format object sl@0: with the character formatting of the range of characters. sl@0: sl@0: @param aView On return, a constant pointer to a portion of the text. sl@0: @param aFormat On return, contains the character formatting of the text. sl@0: @param aPos The start position for the view. Must be a valid document sl@0: position, or a panic occurs. */ sl@0: { sl@0: // Get a run of text and its format, starting at aPos. sl@0: __ETEXT_WATCH(GET_CHARS) sl@0: TCharFormatX format; sl@0: GetTextAndExtendedFormat(aText, format, aPos); sl@0: OverrideFormatForParsersIfApplicable(aText, format, aPos); sl@0: aFormat = format.iCharFormat; sl@0: OverrideFormatOfInlineTextIfApplicable(aText, aFormat, aPos); sl@0: __ETEXT_WATCH_END(GET_CHARS) sl@0: } sl@0: sl@0: sl@0: void CRichText::GetTextAndExtendedFormat(TPtrC& aText,TCharFormatX& aFormat,TInt aPos) 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, CRICHTEXT_GETTEXTANDEXTENDEDFORMAT, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= documentLength, Panic(ECharPosBeyondDocument)); sl@0: if (!IndexPresent()) sl@0: { sl@0: aText.Set(Read(aPos)); sl@0: iGlobalCharFormatLayer->SenseEffective(aFormat); sl@0: } sl@0: else sl@0: { sl@0: int phrase_length = iIndex->GetChars(aFormat,aPos); sl@0: aText.Set(Read(aPos,phrase_length)); sl@0: } sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: EXPORT_C TInt CRichText::GetPictureSizeInTwips(TSize& aSize, TInt aPos) const sl@0: /** Gets the size of a picture located at a specified document position. sl@0: sl@0: @param aSize On return, contains the size of the picture located at aPos. sl@0: @param aPos Document position of the picture. Must be a valid position. sl@0: @return KErrNotFound if there is no picture at the specified document position, sl@0: KErrNone if there is. */ sl@0: { sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_GETPICTURESIZEINTWIPS, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (IndexPresent()) sl@0: return iIndex->GetPictureSizeInTwips(aSize, aPos); sl@0: else sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: EXPORT_C CPicture* CRichText::PictureHandleL(TInt aPos, MLayDoc::TForcePictureLoad aForceLoad) const sl@0: /** Gets a pointer to the picture located at a specified document position, if sl@0: one exists. If the picture is not in memory, the function loads it (if the sl@0: second argument has a value of MLayDoc::EForceLoadTrue). sl@0: sl@0: Note: sl@0: sl@0: In order to load the picture, a picture factory and a store resolver must sl@0: have been set. sl@0: sl@0: @param aPos Document position of the picture character. Must be a valid position. sl@0: @param aForceLoad If the picture is not loaded into memory, sl@0: MLayDoc::EForceLoadTrue loads it using the picture factory; sl@0: MLayDoc::EForceLoadFalse does not, and in this case, the function returns NULL. sl@0: @return A pointer to the picture located at aPos. NULL if aPos does not specify sl@0: a picture character, or if there is a picture at aPos which is not in memory, sl@0: and the second argument is MLayDoc::EForceLoadFalse. */ sl@0: { sl@0: __ETEXT_WATCH(PICTURE_HANDLE); sl@0: sl@0: __TEST_INVARIANT; sl@0: if (aPos<0 || aPos>DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_PICTUREHANDLEL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (IndexPresent()) sl@0: return iIndex->PictureHandleL(aPos, aForceLoad); sl@0: else sl@0: return NULL; sl@0: sl@0: __ETEXT_WATCH_END(PICTURE_HANDLE); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::GetParagraphFormatL(CParaFormat* aFormat, TInt aPos) const sl@0: /** Gets the effective paragraph formatting which applies to the paragraph which sl@0: contains a specified document position. On return, aFormat is filled with sl@0: values for all paragraph format attributes. sl@0: sl@0: @param aFormat On return, filled with the paragraph's effective paragraph sl@0: formatting. sl@0: @param aPos Any document position within the paragraph of interest. */ sl@0: { sl@0: __ETEXT_WATCH(GET_PARAGRAPH_FORMAT) sl@0: sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_GETPARAGRAPHFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (!IndexPresent()) sl@0: CGlobalText::GetParagraphFormatL(aFormat, aPos); sl@0: else sl@0: { sl@0: aFormat->Reset(); sl@0: iIndex->GetParagraphFormatL(aFormat, aPos); sl@0: } sl@0: sl@0: __ETEXT_WATCH_END(GET_PARAGRAPH_FORMAT) sl@0: } sl@0: sl@0: EXPORT_C void CRichText::GetSpecificParagraphFormatL(CParaFormat* aFormat, sl@0: TParaFormatMask& aMask, sl@0: TInt aPos) const sl@0: // Fills aFormat with the effective Paragraph format attributes for the paragraph sl@0: // in which character position aPos is contained. sl@0: // sl@0: { sl@0: __ETEXT_WATCH(GET_PARAGRAPH_FORMAT) sl@0: sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_GETSPECIFICPARAGRAPHFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: aFormat->Reset(); sl@0: aMask.ClearAll(); sl@0: if (IndexPresent()) sl@0: iIndex->GetSpecificParagraphFormatL(aFormat, aMask, aPos); sl@0: sl@0: __ETEXT_WATCH_END(GET_PARAGRAPH_FORMAT) sl@0: } sl@0: sl@0: EXPORT_C void CRichText::GetParaFormatL(CParaFormat* aFormat, TParaFormatMask& aVaries, TInt aPos, TInt aLength, sl@0: CParaFormat::TParaFormatGetMode aMode) const sl@0: /** Gets the effective paragraph formatting which applies to a range of paragraphs. sl@0: The region involved is every paragraph containing one or more characters in sl@0: the range aPos to aPos+(aLength-1) inclusive. On return, aFormat is filled sl@0: with values for all paragraph format attributes and the mask indicates the sl@0: values that change over the region, and whose value is therefore indeterminate. sl@0: sl@0: Note: sl@0: sl@0: If aMode has a value of EFixedAttributes, the function cannot leave. sl@0: sl@0: @param aFormat Must not be NULL or a panic occurs. On return, contains the sl@0: effective paragraph formatting for the range of paragraphs. sl@0: @param aVaries On return, a bitmask indicating which paragraph format attributes sl@0: vary over the range of characters selected. sl@0: @param aPos The document position of the start of the range. sl@0: @param aLength The number of characters in the range. sl@0: @param aMode The default, EAllAttributes means that values for all paragraph sl@0: format attributes are written to aFormat. EFixedAttributes means that tabs, sl@0: bullets and borders are not written to aFormat. */ sl@0: { sl@0: // Senses the paragraph format of para(s) covered by the region aPos to aPos+aLength-1. sl@0: // aFormat takes the values of all attributes, and the mask aMask indicates those values that change sl@0: // over the selected region, and are therefore *indeterminate*. sl@0: // Application: seeding paragraph formatting dialogs. sl@0: // sl@0: __TEST_INVARIANT; sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_GETPARAFORMATL, "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_CRICHTEXT_GETPARAFORMATL, "EGetParaFormatNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0, Panic(EGetParaFormatNegativeLength)); sl@0: if (aPos + aLength > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_GETPARAFORMATL, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + aLength <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (IndexPresent()) sl@0: iIndex->GetParaFormatL(aFormat, aVaries, aPos, aLength, aMode); sl@0: else sl@0: CGlobalText::GetParaFormatL(aFormat, aVaries, aPos, aLength, aMode); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::GetCharFormat(TCharFormat& aFormat, TCharFormatMask& aVaries, TInt aPos, TInt aLength) const sl@0: /** Gets the effective character formatting which applies to a range of sl@0: characters. The range of characters involved is from aPos to aPos+(aLength-1) sl@0: inclusive. On return, aFormat is filled with values for all character format sl@0: attributes, and on return, the mask indicates the values that change over the sl@0: region, and whose value is therefore indeterminate. sl@0: sl@0: The length value can be zero. In this case, the character formatting sensed sl@0: is that of the character immediately to the left of the position specified. sl@0: sl@0: @param aFormat On return, contains the character format values for the range sl@0: of characters. sl@0: @param aVaries On return, indicates which character format attributes vary sl@0: over the range. sl@0: @param aPos Document position of the start of the range. Must be valid or a sl@0: panic occurs. sl@0: @param aLength Number of characters in the range. Must be greater than or equal sl@0: to zero, or a panic occurs. */ sl@0: { sl@0: // Senses the character formatting of the phrase(s) covered by the region aPos to aPos+aLength-1. sl@0: // May be called with zero length. sl@0: // aFormat takes the values of all character format attributes, and the mask aMask indicates those sl@0: // values that change over the selected region, and are therefore *indeterminate*. sl@0: // Application: seeding character formatting dialogs. sl@0: // sl@0: TCharFormatX format; sl@0: TCharFormatXMask varies; sl@0: GetExtendedCharFormat(format, varies, aPos, aLength); sl@0: aFormat = format.iCharFormat; sl@0: varies.ClearExtendedAttribs(); sl@0: aVaries = varies; sl@0: } sl@0: sl@0: sl@0: void CRichText::GetExtendedCharFormat(TCharFormatX& aFormat, TCharFormatXMask& aVaries, TInt aPos, TInt aLength) const sl@0: { sl@0: __TEST_INVARIANT; sl@0: int document_length = DocumentLength(); sl@0: if (aPos < 0 || aPos > document_length) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_GETEXTENDEDCHARFORMAT, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= document_length, Panic(ECharPosBeyondDocument)); sl@0: if (aLength < 0) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP1_CRICHTEXT_GETEXTENDEDCHARFORMAT, "EGetCharFormatNegativeLength" ); sl@0: } sl@0: __ASSERT_ALWAYS(aLength >= 0, Panic(EGetCharFormatNegativeLength)); sl@0: if (aPos + aLength - 1 > document_length) sl@0: { sl@0: OstTrace0( TRACE_FATAL, DUP2_CRICHTEXT_GETEXTENDEDCHARFORMAT, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos + aLength - 1 <= document_length, Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (IndexPresent()) sl@0: iIndex->GetCharFormat(aFormat, aVaries, aPos, aLength); sl@0: else sl@0: { sl@0: iGlobalCharFormatLayer->SenseEffective(aFormat); sl@0: aVaries.ClearAll(); sl@0: } sl@0: } sl@0: sl@0: sl@0: void CRichText::GetSpecificCharFormatLeftRight(TCharFormat& aFormat, sl@0: TCharFormatMask& aMask, sl@0: TInt aPos, sl@0: TBool aLeft) const sl@0: { sl@0: __ETEXT_WATCH(GET_SPECIFIC_CHARS); sl@0: sl@0: __TEST_INVARIANT; sl@0: sl@0: if (aPos < 0 || aPos > DocumentLength()) sl@0: { sl@0: OstTrace0( TRACE_FATAL, CRICHTEXT_GETSPECIFICCHARFORMATLEFTRIGHT, "ECharPosBeyondDocument" ); sl@0: } sl@0: __ASSERT_ALWAYS(aPos >= 0 && aPos <= DocumentLength(), Panic(ECharPosBeyondDocument)); sl@0: sl@0: if (IndexPresent()) sl@0: { sl@0: TCharFormatX format; sl@0: TCharFormatXMask mask; sl@0: iIndex->GetSpecificCharFormatDirection(format, mask, aPos, aLeft); sl@0: aFormat = format.iCharFormat; sl@0: mask.ClearExtendedAttribs(); sl@0: aMask = mask; sl@0: } sl@0: sl@0: __ETEXT_WATCH_END(GET_SPECIFIC_CHARS); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::GetSpecificCharFormat(TCharFormat& aFormat, TCharFormatMask& aMask, TInt aPos) const sl@0: /** Gets the specific character formatting which applies to the character to the sl@0: left of a document position. Specific formatting is just the formatting which sl@0: has been applied over the object's global format layers - it is not the sl@0: same as the effective formatting. sl@0: sl@0: @param aFormat On return contains the specific character formatting which sl@0: applies to the character to the left of the document position. sl@0: @param aMask On return, indicates which character format attributes have been sl@0: applied specifically, (not taken from the global layers). sl@0: @param aPos The document position. Must be valid or a panic occurs. */ sl@0: { sl@0: // Return the format attributes store in the specific layer only, for the specified document position. sl@0: // THIS IS NOT THE EFFECTIVE FORMAT, BUT THE SPECIFIC FORMATTING ONLY. sl@0: // sl@0: GetSpecificCharFormatLeftRight(aFormat, aMask, aPos, ETrue); sl@0: } sl@0: sl@0: EXPORT_C void CRichText::GetSpecificCharFormatRight(TCharFormat& aFormat, TCharFormatMask& aMask, TInt aPos) const sl@0: /** Gets the specific character formatting which applies to the character logically sl@0: after a document position. Note that this is not necessarily the character sl@0: to the right of the document position, because right to left text is supported. sl@0: sl@0: Specific formatting is just the formatting which has been applied over the sl@0: object's global format layers it is not the same as the effective formatting. sl@0: sl@0: @param aFormat On return, contains the specific character formatting which sl@0: applies to the character logically after the document position. sl@0: @param aMask On return, indicates which character format attributes have been sl@0: applied specifically, (not taken from the global layers). sl@0: @param aPos The document position. Must be valid or a panic occurs. */ sl@0: { sl@0: GetSpecificCharFormatLeftRight(aFormat, aMask, aPos, EFalse); sl@0: } sl@0: sl@0: TBool CRichText::IndexPresent()const sl@0: // Returns ETrue if the rich text index is present, otherwise sl@0: // returns EFalse. sl@0: // sl@0: { sl@0: return iIndex.IsPtr() && iIndex.AsPtr(); sl@0: } sl@0: sl@0: sl@0: EXPORT_C TInt CRichText::PictureCount() const sl@0: /** Gets a count of the number of pictures contained in the rich text object. sl@0: sl@0: @return The picture count. */ sl@0: {return (IndexPresent()) ? iIndex->iPictureCount : 0;} sl@0: sl@0: sl@0: void CRichText::SetParaTypeIsSingle(TBool aBool) sl@0: { sl@0: if (aBool) sl@0: iFlags |= KParaTypeIsSingle; sl@0: else sl@0: iFlags &= ~KParaTypeIsSingle; sl@0: } sl@0: sl@0: sl@0: TBool CRichText::ParaTypeIsSingle() const sl@0: {return iFlags & KParaTypeIsSingle;} sl@0: sl@0: sl@0: EXPORT_C void CRichText::AppendTakingSolePictureOwnershipL(const CRichText& aSource) sl@0: /** Appends a rich text object to this one. The text is appended immediately after sl@0: the end-of-text paragraph delimiter. The incoming text's formatting is set sl@0: to be based on the global formatting of this rich text object. sl@0: sl@0: Notes: sl@0: sl@0: If this rich text object is empty (e.g. because it is newly initialised, or sl@0: has been reset), then the end-of-text delimiter of the incoming rich text sl@0: is not appended. This avoids the possibility of having a trailing paragraph sl@0: delimiter, giving one more empty line than would typically be desired. sl@0: sl@0: If the incoming rich text contains pictures which have been loaded into memory, sl@0: their sole ownership is transferred to the current rich text object. In aSource, sl@0: these picture handles are set to NULL. sl@0: sl@0: @param aSource The rich text object to append. */ sl@0: { sl@0: // Appends the specified rich text object to this one. sl@0: // If this rich text is empty or has been newly initialised or reset, then the final paragraph delimiter sl@0: // of the incoming rich text is NOT appended, thus avoiding the prospect of having a trailing, empty sl@0: // paragraph delimiter, giving one more empty line than would typically be desired. sl@0: // sl@0: __ETEXT_WATCH(APPEND_RICH_TEXT); sl@0: sl@0: // Append the text sl@0: const TInt thisDocumentLength = DocumentLength(); sl@0: MPictureFactory* factory = NULL; sl@0: MRichTextStoreResolver* resolver = NULL; sl@0: if (thisDocumentLength == 0) // this is an empty document sl@0: { sl@0: factory = iPictureFactory; sl@0: resolver = iStoreResolver; sl@0: Reset(); // destroy the markup component if it exists. Makes the job easier sl@0: } sl@0: // sl@0: PrepareAppendMarkupL(aSource); // requires no rollback - objects in a (bigger) stable state sl@0: // sl@0: TRAPD(ret, DoAppendTakingSolePictureOwnershipL(aSource)); sl@0: if (ret != KErrNone) sl@0: { sl@0: CPlainText::Delete(thisDocumentLength,DocumentLength() - thisDocumentLength); sl@0: User::Leave(ret); sl@0: } sl@0: if (thisDocumentLength == 0) sl@0: { sl@0: DeleteParagraph(0, 1); // remove excess first paragraph from empty documents sl@0: SetPictureFactory(factory, resolver); sl@0: } sl@0: int new_length = DocumentLength() - thisDocumentLength; sl@0: iParserData->MergeRange(thisDocumentLength,0,new_length); sl@0: CallEditObserver(thisDocumentLength,new_length); sl@0: sl@0: __TEST_INVARIANT; sl@0: sl@0: __ETEXT_WATCH_END(APPEND_RICH_TEXT); sl@0: } sl@0: sl@0: sl@0: void CRichText::DoAppendTakingSolePictureOwnershipL(const CRichText& aSource) sl@0: { sl@0: TInt lengthRemaining = aSource.DocumentLength() + 1; // we want to append the para delimiters also! sl@0: TInt consumed = 0; sl@0: FOREVER sl@0: { sl@0: TPtrC view = aSource.Read(consumed); sl@0: if (view.Length() > lengthRemaining) sl@0: view.Set(view.Ptr(), lengthRemaining); sl@0: CPlainText::DoPtInsertL(DocumentLength() + 1, view); // insert AFTER the final paragraph delimiter sl@0: TInt viewLength = view.Length(); sl@0: lengthRemaining -= viewLength; sl@0: if (lengthRemaining == 0) sl@0: break; sl@0: consumed += viewLength; sl@0: } sl@0: sl@0: if (IndexPresent()) sl@0: { sl@0: if (!aSource.IndexPresent()) sl@0: { sl@0: OstTrace0( TRACE_DUMP, DUP1_CRICHTEXT_DOAPPENDTAKINGSOLEPICTUREOWNERSHIPL, "Invariant" ); sl@0: } sl@0: __ASSERT_DEBUG(aSource.IndexPresent(), User::Invariant()); // PrepareAppend should have sorted this sl@0: sl@0: TGlobalLayerInfoAppend info(GlobalParaFormatLayer(), GlobalCharFormatLayer(), aSource.GlobalParaFormatLayer(), aSource.GlobalCharFormatLayer()); sl@0: iIndex->AppendTakingSolePictureOwnershipL(aSource.iIndex, info); sl@0: } sl@0: sl@0: __TEST_INVARIANT; sl@0: } sl@0: sl@0: sl@0: void CRichText::PrepareAppendMarkupL(const CRichText& aSource) sl@0: // Guarantees that both the component and aggregate objects have a valid markup component. sl@0: // sl@0: { sl@0: if (aSource.HasMarkupData() && !HasMarkupData()) sl@0: CreateAndGenerateMarkupComponentL(); sl@0: else if (IndexPresent()) sl@0: CONST_CAST(CRichText&, aSource).CreateAndGenerateMarkupComponentL(); sl@0: } sl@0: sl@0: sl@0: EXPORT_C void CRichText::AppendParagraphL(TInt aReplicas) sl@0: /** Appends one or more empty paragraphs to the document. The new paragraphs take sl@0: on the formatting specified in the global format layers. sl@0: sl@0: @param aReplicas The number of empty paragraphs to append to the document. sl@0: By default, a single paragraph. */ sl@0: { sl@0: // Inserts an empty paragraph at the end of the document. sl@0: // The new paragraph takes on the format as described sl@0: // by the global format layers. sl@0: // sl@0: __ETEXT_WATCH(APPEND_PARAGRAPH); sl@0: sl@0: __TEST_INVARIANT; sl@0: sl@0: TInt documentLength = DocumentLength(); sl@0: if (aReplicas == 1) sl@0: CPlainText::InsertL(documentLength, CEditableText::EParagraphDelimiter); sl@0: else sl@0: { sl@0: HBufC* bb = HBufC::NewLC(aReplicas); sl@0: TPtr buf = bb->Des(); sl@0: buf.Fill(CEditableText::EParagraphDelimiter, aReplicas); sl@0: CPlainText::InsertL(documentLength, buf); sl@0: CleanupStack::PopAndDestroy(); // bb sl@0: } sl@0: // sl@0: if (IndexPresent()) sl@0: { sl@0: TRAPD(ret, sl@0: iIndex->AppendParagraphL(iGlobalParaFormatLayer, iGlobalCharFormatLayer, aReplicas)); sl@0: if (ret != KErrNone) sl@0: { sl@0: CPlainText::Delete(DocumentLength() - aReplicas, aReplicas); sl@0: User::Leave(ret); sl@0: } sl@0: SetHasChanged(ETrue); sl@0: } sl@0: sl@0: int new_length = DocumentLength() - documentLength; sl@0: iParserData->MergeRange(documentLength,0,new_length); sl@0: CallEditObserver(documentLength,new_length); sl@0: __TEST_INVARIANT; sl@0: sl@0: __ETEXT_WATCH_END(APPEND_PARAGRAPH); sl@0: }