diff -r 000000000000 -r bde4ae8d615e os/textandloc/textrendering/texthandling/sfields/FLDSTRM.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/textandloc/textrendering/texthandling/sfields/FLDSTRM.CPP Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,481 @@ +/* +* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include + +#include +#include + +#include "FLDDEF.H" +#include "FLDSET.H" +#include "FLDARRAY.H" + +#include "FLDSTD.H" + + + +EXPORT_C TFieldMapExternalizer::TFieldMapExternalizer(const CStoreMap& aMap) + : iMap(&aMap) + {} + +EXPORT_C void TFieldMapExternalizer::ExternalizeL(const TStreamRef& aRef,RWriteStream& aStream) const +// Write the stream id bound to aRef to aStream. If not bound, write KNullStreamId +// + { + TSwizzleC swizzle=aRef; + aStream<At(swizzle); + } + + +EXPORT_C TStreamId CTextFieldSet::StoreL(CStreamStore& aStore)const +// Save the fields and the fieldSet in their own streams +// Encapsulates the storing of its components. +// + { + CStoreMap* map=CStoreMap::NewLC(aStore); + StoreFieldsL(aStore,*map); // binds id's to swizzles +// + // create custom externalizer over the map + TFieldMapExternalizer fMap(*map); + RStoreWriteStream stream(fMap); + TStreamId id=stream.CreateLC(aStore); + stream<< *this; + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream +// + map->Reset(); + CleanupStack::PopAndDestroy(); // map + return id; + } + + +EXPORT_C void CTextFieldSet::StoreFieldsL(CStreamStore& aStore,CStoreMap& aMap)const +// Stores all fields in the set +// + {StoreFieldsL(aStore,aMap,iFieldArray);} + + +void CTextFieldSet::StoreFieldsL(CStreamStore& aStore,CStoreMap& aMap,CArrayFixSeg* aArray)const +// Stores all fields contained in the set provided +// + { + __TEST_INVARIANT; + + for (TInt i=0 ; i<(aArray->Count()-1) ; i++) + { + TStreamId id=(*aArray)[i].iFieldHeader.iField->StoreL(aStore); + if (id!=KNullStreamId) + aMap.BindL((*aArray)[i].iFieldHeader.iField,id); + } + } + + +EXPORT_C void CTextFieldSet::ExternalizeL(RWriteStream& aStream)const + { + __TEST_INVARIANT; + + ExternalizeL(aStream,iFieldArray); + } + + +void CTextFieldSet::ExternalizeL(RWriteStream& aStream,CArrayFixSeg* aArray)const + { + TInt numFieldEntries = aArray->Count(); + aStream.WriteInt32L(numFieldEntries); + // write out fields + for (TInt i=0 ; iCount()==1,Panic(EArrayNotEmptyOnRestore)); // array must be empty + __ASSERT_ALWAYS((*iFieldArray)[0].iPreFieldLen==0,Panic(EArrayNotEmptyOnRestore)); + + // retrieve the headstream from the store + RStoreReadStream stream; + stream.OpenLC(aFieldStore,aStreamId); + // restore the set, then the individual fields + stream>> *this; // internalize the field set (the headers) + CleanupStack::PopAndDestroy(); // stream + DoRestoreFieldsL(iFieldArray,aFieldStore); // restore the fields individually from their own streams + } + + +EXPORT_C void CTextFieldSet::InternalizeL(RReadStream& aStream) + { + InternalizeL(iFieldArray,aStream); + + __TEST_INVARIANT; + } + + +void CTextFieldSet::InternalizeL(CArrayFixSeg* aArray,RReadStream& aStream) + {// assume the array is empty + TInt numFieldEntries = aStream.ReadInt32L(); + // read in the fields + TTextFieldEntry entry; + for (TInt i=0 ; i> entry; + InsertEntryL(i,entry,aArray); // insert new entry + } + // read in the last entry: the bit after the last field. This will not contain a field + (*aArray)[numFieldEntries-1].iPreFieldLen = aStream.ReadInt32L(); + } + + +void CTextFieldSet::DoRestoreFieldsL(CArrayFixSeg* aArray,const CStreamStore& aFieldStore,TInt aStartIndex) +// This fn is called after all FieldHeaders have been internalized - the Swizzles hold the stream id's. +// One by one the fields are created (with the factory) and then have their settings streamed in from the store. +// If no factory exists all fields are converted to text. +// + { + TInt ii=aArray->Count()-2; // -2 because we skip the last (empty) entry + while (ii>=aStartIndex) + { + if ((*aArray)[ii].iFieldHeader.iField.IsId()) + {// restore the field only if it isn't the very last (dummy) entry + if (iFieldFactory==NULL) + // no factory - convert the field to text + DeleteFieldEntry(aArray,ii); + else + { + TStreamId id = (*aArray)[ii].iFieldHeader.iField.AsId(); + (*aArray)[ii].iFieldHeader.iField = iFieldFactory->NewFieldL((*aArray)[ii].iFieldHeader.iFieldType); + if ((*aArray)[ii].iFieldHeader.iField!=NULL) + (*aArray)[ii].iFieldHeader.iField->RestoreL(aFieldStore,id); + else + DeleteFieldEntry(aArray,ii); // handle "field type not recognised" by converting field to text + } + } + ii--; + } + } + + +/***************************************** cut & paste *******************************************/ + + +EXPORT_C TStreamId CTextFieldSet::CopyToStoreL(CStreamStore& aStore,TInt aPos,TInt aLength)const +// Copy any fields in the selected region to the specified store, returning the id of the head-stream. +// + { + __TEST_INVARIANT; + __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutOfRange)); + __ASSERT_ALWAYS(aLength>=0,Panic(ENegativeRange)); + __ASSERT_DEBUG((aPos+aLength)<=CharCount(),Panic(EPosOutOfRange)); + + // Create a store map and store the fields themselves + CStoreMap* map=CStoreMap::NewLC(aStore); + CopyComponentsL(aStore,*map,aPos,aLength); + + // Create a head-stream in which to store the field entries and do so + RStoreWriteStream stream(*map); + TStreamId id=stream.CreateLC(aStore); + CopyToStreamL(stream,aPos,aLength); + + // tidy up + stream.CommitL(); + map->Reset(); + CleanupStack::PopAndDestroy(2); // map, stream + return id; + } + + +EXPORT_C void CTextFieldSet::CopyComponentsL(CStreamStore& aStore,CStoreMap& aMap,TInt aPos,TInt aLength)const +// Stores all fields in the set +// + { + __TEST_INVARIANT; + __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutOfRange)); + __ASSERT_ALWAYS(aLength>=0,Panic(ENegativeRange)); + __ASSERT_DEBUG((aPos+aLength)<=CharCount(),Panic(EPosOutOfRange)); + + // Create an array of the fields to be cut/copied + CArrayFixSeg* tempArray = new(ELeave) CArrayFixSeg(KFieldArrayGranularity); + CleanupStack::PushL(tempArray); + CopyToArrayL(tempArray,aPos,aLength); + + // stream the required fields in their own streams + StoreFieldsL(aStore,aMap,tempArray); + CleanupStack::PopAndDestroy(); // tempArray + } + + +EXPORT_C void CTextFieldSet::CopyToStreamL(RWriteStream& aStream,TInt aPos,TInt aLength)const +// Stores all fields in the set +// + { + __TEST_INVARIANT; + __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutOfRange)); + __ASSERT_ALWAYS(aLength>=0,Panic(ENegativeRange)); + __ASSERT_DEBUG((aPos+aLength)<=CharCount(),Panic(EPosOutOfRange)); + + // Create an array of the fields to be cut/copied + CArrayFixSeg* tempArray = new(ELeave) CArrayFixSeg(KFieldArrayGranularity); + CleanupStack::PushL(tempArray); + CopyToArrayL(tempArray,aPos,aLength); + + // stream the field entries in the temp array + ExternalizeL(aStream,tempArray); + CleanupStack::PopAndDestroy(); // tempArray + } + + +void CTextFieldSet::CopyToArrayL(CArrayFixSeg* aArray,TInt aPos,TInt aLength)const + { + TInt index; TInt offset; + if (InField(aPos,index,offset)) + offset += (*iFieldArray)[index].iPreFieldLen; // make offset relative to start of entry + // split first entry in range + TTextFieldEntry entry = SplitEntry(index,offset,aLength); + index++; + TInt charsCopied=EntryLen(entry); + // split second if neccessary + if ((!entry.iFieldHeader.iField)&&(charsCopiedAppendEntryL(entry,aArray); // append the first entry to the storage array + // write out all whole entries + while (charsCopiedAppendEntryL((*iFieldArray)[index],aArray); + charsCopied += EntryLen(index); + index++; + } + // split last entry if neccessary + if (charsCopied>aLength) + {// The last entry needs to be split + // first get back to the beginning of the entry + index--; + charsCopied -= EntryLen(index); + entry = SplitEntry(index,0,aLength-charsCopied); // split up the last entry as required + ((CTextFieldSet*)this)->AppendEntryL(entry,aArray); // append the last entry to the storage array + } + // add an empty last entry if neccessary + TInt numFieldEntries = aArray->Count(); + if (((*aArray)[numFieldEntries-1].iFieldHeader.iField) || ((*aArray)[numFieldEntries-1].iFieldValueLen!=0)) + { + entry.iPreFieldLen = 0; + entry.iFieldValueLen = 0; + entry.iFieldHeader.iFieldType = KNullUid; + entry.iFieldHeader.iField = NULL; + ((CTextFieldSet*)this)->AppendEntryL(entry,aArray); + numFieldEntries++; + } + } + + +EXPORT_C void CTextFieldSet::PasteFromStoreL(const CStreamStore& aFieldStore,TStreamId aStreamId,TInt aPos,TInt aMaxLen) +// Paste from aStore into the document at insert position aPos. +// Optionally the pasted text can be clipped to a maximum length aMaxLen. +// + { + __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutOfRange)); + __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutOfRange)); + + // retrieve the headstream from the store + RStoreReadStream stream; + stream.OpenLC(aFieldStore,aStreamId); + + // restore the set... + PasteFromStreamL(stream,aPos,aMaxLen); // internalize the field set (the headers) + CleanupStack::PopAndDestroy(); // stream + + // ...then the individual fields + PasteComponentsL(aFieldStore,aPos); // restore the fields individually from their own streams + } + + +EXPORT_C void CTextFieldSet::PasteFromStreamL(RReadStream& aStream,TInt aPos,TInt aMaxLen) +// streams the field entries into a temporary array, which is returned. +// PasteComponents() must be called after this to actually carry out the paste... + { + // create a temporary array to stream in to, inserting the first entry + CArrayFixSeg* tempFieldArray = new(ELeave) CArrayFixSeg(KFieldArrayGranularity); + CleanupStack::PushL(tempFieldArray); + AddInitialFieldEntryL(tempFieldArray,0); + + // internalize the field entries + InternalizeL(tempFieldArray,aStream); + + // trim off any entries that lie beyond aMaxLength + if (aMaxLen!=ENoPasteLimit) + {// if aMaxLen is not ENoPasteLimit discard the excess fields + __ASSERT_ALWAYS(aMaxLen>=0,Panic(ELengthOutOfRange)); + // + TInt length=0; + TInt i=0; + for (i=0 ; (lengthCount()) ; i++) + length += EntryLen((*tempFieldArray)[i]); + if (aMaxLen==0) + {// make first entry zero len, delete all others + i++; + (*tempFieldArray)[i-1].iPreFieldLen = 0; + } + else if (length>aMaxLen) + // truncate the last field in range + (*tempFieldArray)[i-1].iPreFieldLen += (*tempFieldArray)[i-1].iFieldValueLen-(length-aMaxLen); + else if ((length==aMaxLen) && ((*tempFieldArray)[i-1].iFieldHeader.iField!=NULL)) + {// if the terminating entry has a field add a zero length entry, the mandatory last entry + i++; + (*tempFieldArray)[i-1].iPreFieldLen = 0; + } + // ensure the last entry is of the correct format + (*tempFieldArray)[i-1].iFieldValueLen = 0; + (*tempFieldArray)[i-1].iFieldHeader.iFieldType = KNullUid; + (*tempFieldArray)[i-1].iFieldHeader.iField = NULL; + // delete all the fields wholely out of range + for (TInt index=i ; indexCount() ; index++) + (*tempFieldArray)[index].iFieldHeader.iField = NULL; + tempFieldArray->Delete(i,tempFieldArray->Count()-i); // pos,count + } + + DoPasteL(tempFieldArray,aPos); + CleanupStack::PopAndDestroy(); // tempFieldArray + } + + +EXPORT_C void CTextFieldSet::PasteComponentsL(const CStreamStore& aFieldStore,TInt aPos) + { + // Restore the fields individually from their own streams + TInt index; TInt offset; + // We don't need to make any difference between in and not in field situation here + // all we need is the index + TBool isInField = InField(aPos,index,offset); + DoRestoreFieldsL(iFieldArray,aFieldStore,index); + } + + +void CTextFieldSet::DoPasteL(CArrayFixSeg* aSourceArray,TInt aPos) +// Insert into this instance, at character position aPos, the entire (field entry) contents of the field array aSourceArray. +// All iField objects in aSourceArray are ID's at this time. +// + { + // are we inserting into a field? + TInt numFieldEntries = aSourceArray->Count(); + TInt index; TInt offset; + + TBool inField = InField(aPos,index,offset); + // record the rollback info + RecordRollbackInfoL(index); + if ((inField)&&(offset!=0)) + {// everything we insert will become text - no chance of leaving + // insert all but last entry + TInt i=0; + for (; i1) + {// read 1st field & carry out split. + InsertEntryL(index,(*aSourceArray)[0]); // if this leaves the model will be intact + (*iFieldArray)[index].iPreFieldLen += offset; + (*iFieldArray)[index+1].iPreFieldLen -= offset; + index++; + } + // insert all other fields except last. + for (TInt i=1 ; iiEntryNum = aIndex; + iRollbackInfo->iPreFieldLen = (*iFieldArray)[aIndex].iPreFieldLen; + iRollbackInfo->iFieldValueLen = (*iFieldArray)[aIndex].iFieldValueLen; + iRollbackInfo->iTotalEntries = iFieldArray->Count(); + } + + +EXPORT_C void CTextFieldSet::RollbackPaste() +// Carries out rollback from a paste function +// This will only have an effect after a PasteFromStream() has been called +// nb it would be distasterous if this were called at random some time after a paste! +// + { + if (!iRollbackInfo) + return; // nothing to do + // remove added entries from array + TInt entriesToRemove=iFieldArray->Count()-iRollbackInfo->iTotalEntries; + TInt i=0; + for (i=iRollbackInfo->iEntryNum ; iiEntryNum+entriesToRemove ; i++) + { + if ((*iFieldArray)[i].iFieldHeader.iField.IsPtr()) + delete (*iFieldArray)[i].iFieldHeader.iField.AsPtr(); // Delete the textField object + iFieldArray->Delete(i); + } + // now right num entries, but wrong length - use backup info to correct length + (*iFieldArray)[i].iPreFieldLen = iRollbackInfo->iPreFieldLen; + (*iFieldArray)[i].iFieldValueLen = iRollbackInfo->iFieldValueLen; + + __ASSERT_DEBUG(iFieldArray->Count()==iRollbackInfo->iTotalEntries,Panic(EDebug)); + delete iRollbackInfo; + } +