1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/textrendering/texthandling/sfields/FLDSET.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,684 @@
1.4 +/*
1.5 +* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +#include <e32std.h>
1.23 +#include <e32base.h>
1.24 +
1.25 +#include "FLDSET.H"
1.26 +#include "FLDDEF.H"
1.27 +#include "FLDARRAY.H"
1.28 +#include "FLDSTD.H"
1.29 +
1.30 +
1.31 +EXPORT_C void CTextFieldSet::__DbgTestInvariant()const
1.32 +// Provides class invariants. Explanations below:
1.33 +//
1.34 + {
1.35 +#ifdef _DEBUG
1.36 + if (!iFieldArray)
1.37 + return;
1.38 +// check that every entry in the array has length >=0 and that all but the last have valid header handles
1.39 + TBool valid = ETrue;
1.40 + TInt index = iFieldArray->Count()-1;
1.41 + if (index<0)
1.42 + valid = EFalse;
1.43 + else
1.44 + {// check last entry: should have null fieldHeader, zero field length and non-negative PreFieldLen
1.45 + if ( (*iFieldArray)[index].iFieldHeader.iField
1.46 + ||(*iFieldArray)[index].iFieldValueLen!=0
1.47 + ||(*iFieldArray)[index].iPreFieldLen<0 )
1.48 + {
1.49 + valid = EFalse;
1.50 + }
1.51 + index--;
1.52 + // check the other entries: should have non-null fieldHeader and non-negative field length and PreFieldLen
1.53 + for (; (index>=0)&&(valid) ; index--)
1.54 + {
1.55 + if ((*iFieldArray)[index].iFieldValueLen<0
1.56 + ||(*iFieldArray)[index].iPreFieldLen<0 )
1.57 + {
1.58 + valid = EFalse;
1.59 + }
1.60 + }
1.61 + }
1.62 + __ASSERT_ALWAYS(valid,User::Invariant());
1.63 +#endif
1.64 + }
1.65 +
1.66 +
1.67 +EXPORT_C CTextFieldSet* CTextFieldSet::NewL(TInt aDocumentLength)
1.68 + {
1.69 + CTextFieldSet* self=new(ELeave) CTextFieldSet();
1.70 + CleanupStack::PushL(self);
1.71 + self->ConstructL(aDocumentLength);
1.72 + CleanupStack::Pop();
1.73 + return self;
1.74 + }
1.75 +
1.76 +
1.77 +EXPORT_C CTextFieldSet* CTextFieldSet::NewL(const MTextFieldFactory* aFactory,const CStreamStore& aFieldStore,TStreamId aStreamId)
1.78 + {
1.79 + CTextFieldSet* self=new(ELeave) CTextFieldSet();
1.80 + CleanupStack::PushL(self);
1.81 + self->SetFieldFactory(CONST_CAST(MTextFieldFactory*,aFactory));
1.82 + self->ConstructL(0);
1.83 + self->DoRestoreL(aFieldStore,aStreamId);
1.84 + CleanupStack::Pop();
1.85 + return self;
1.86 + }
1.87 +
1.88 +
1.89 +CTextFieldSet::CTextFieldSet()
1.90 + {}
1.91 +
1.92 +
1.93 +void CTextFieldSet::ConstructL(TInt aDocumentLength)
1.94 +// Creates an array in which to store all fields
1.95 +// Inserts an initial entry into the array to cover any text that lies after the last field
1.96 +//
1.97 + {
1.98 + iFieldArray = new(ELeave) CArrayFixSeg<TTextFieldEntry>(KFieldArrayGranularity);
1.99 + AddInitialFieldEntryL(iFieldArray,aDocumentLength);
1.100 +
1.101 + __TEST_INVARIANT;
1.102 + }
1.103 +
1.104 +
1.105 +EXPORT_C CTextFieldSet::~CTextFieldSet()
1.106 + {
1.107 + delete iRollbackInfo;
1.108 + if (iFieldArray)
1.109 + {
1.110 + TInt fieldCount=iFieldArray->Count();
1.111 + for (TInt index=fieldCount-1;index>=0;index--)
1.112 + delete (*iFieldArray)[index].iFieldHeader.iField.AsPtr(); // Delete the textField objects
1.113 + delete iFieldArray;
1.114 + }
1.115 + }
1.116 +
1.117 +
1.118 +EXPORT_C void CTextFieldSet::SetFieldFactory(MTextFieldFactory* aFactory)
1.119 + {
1.120 + iFieldFactory = aFactory;
1.121 + }
1.122 +
1.123 +
1.124 +EXPORT_C MTextFieldFactory* CTextFieldSet::FieldFactory()const
1.125 + {
1.126 + return iFieldFactory;
1.127 + }
1.128 +
1.129 +
1.130 +void CTextFieldSet::InsertEntryL(TInt aIndex,TTextFieldEntry& aEntry)
1.131 + {
1.132 + InsertEntryL(aIndex,aEntry,iFieldArray);
1.133 + }
1.134 +
1.135 +
1.136 +void CTextFieldSet::InsertEntryL(TInt aIndex,TTextFieldEntry& aEntry,CArrayFixSeg<TTextFieldEntry>* aArray)
1.137 +// if this function leaves it will be as if it had never been called...
1.138 +//
1.139 + {
1.140 + if (aEntry.iFieldHeader.iField.IsPtr())
1.141 + CleanupStack::PushL(aEntry.iFieldHeader.iField.AsPtr());
1.142 + aArray->InsertL(aIndex,aEntry); // insert new entry
1.143 + if (aEntry.iFieldHeader.iField.IsPtr())
1.144 + CleanupStack::Pop();
1.145 + }
1.146 +
1.147 +
1.148 +void CTextFieldSet::AppendEntryL(TTextFieldEntry& aEntry)
1.149 + {
1.150 + AppendEntryL(aEntry,iFieldArray);
1.151 + }
1.152 +
1.153 +
1.154 +void CTextFieldSet::AppendEntryL(TTextFieldEntry& aEntry,CArrayFixSeg<TTextFieldEntry>* aArray)
1.155 + {
1.156 + if (aEntry.iFieldHeader.iField.IsPtr())
1.157 + CleanupStack::PushL(aEntry.iFieldHeader.iField.AsPtr());
1.158 + aArray->AppendL(aEntry); // insert new entry
1.159 + if (aEntry.iFieldHeader.iField.IsPtr())
1.160 + CleanupStack::Pop();
1.161 + }
1.162 +
1.163 +
1.164 +TInt CTextFieldSet::EntryLen(TInt aIndex)const
1.165 + {
1.166 + return EntryLen((*iFieldArray)[aIndex]);
1.167 + }
1.168 +
1.169 +
1.170 +TInt CTextFieldSet::EntryLen(const TTextFieldEntry& aEntry)const
1.171 + {
1.172 + return aEntry.iPreFieldLen+aEntry.iFieldValueLen;
1.173 + }
1.174 +
1.175 +
1.176 +TTextFieldEntry CTextFieldSet::SplitEntry(TInt aIndex,TInt aOffset, TInt aRange)const
1.177 +// Splits the entry aIndex, returning the part demarked by the offset (from the start of the entry) and the range
1.178 +//
1.179 + {
1.180 + __TEST_INVARIANT;
1.181 +
1.182 + __ASSERT_DEBUG((aIndex>=0)&&(aIndex<iFieldArray->Count()),Panic(EIndexOutOfRange));
1.183 + TInt entryLength = EntryLen(aIndex);
1.184 + __ASSERT_DEBUG((aOffset>=0)&&(aOffset<=entryLength),Panic(EPosOutOfRange));
1.185 + __ASSERT_DEBUG((aRange>=0),Panic(ENegativeRange));
1.186 +
1.187 + if ((aOffset+aRange)>entryLength)
1.188 + aRange = entryLength-aOffset; // scale range down to entry size if neccessary
1.189 +
1.190 + if ((aOffset==0)&&(aRange==entryLength))
1.191 + return (*iFieldArray)[aIndex]; //entry does not need to be split
1.192 +
1.193 + TInt charsCopied=0;
1.194 + TTextFieldEntry entry;
1.195 + entry.iPreFieldLen = 0;
1.196 + entry.iFieldValueLen = 0;
1.197 + entry.iFieldHeader.iField = NULL;
1.198 + if (aOffset<(*iFieldArray)[aIndex].iPreFieldLen)
1.199 + {// At least some of the pre needs to be copied
1.200 + entry.iPreFieldLen = (*iFieldArray)[aIndex].iPreFieldLen-aOffset;
1.201 + if ((entry.iPreFieldLen)>aRange)
1.202 + entry.iPreFieldLen = aRange;
1.203 + charsCopied = entry.iPreFieldLen;
1.204 + }
1.205 +
1.206 + if (charsCopied<aRange)
1.207 + {// more to do, so at least some of the field needs to be copied
1.208 + if ((aOffset+aRange)==entryLength)
1.209 + {// whole field in range so copy it
1.210 + entry.iFieldValueLen = (*iFieldArray)[aIndex].iFieldValueLen;
1.211 + entry.iFieldHeader = (*iFieldArray)[aIndex].iFieldHeader;
1.212 + }
1.213 + else
1.214 + // only part of field in range so convert it to text
1.215 + entry.iPreFieldLen += aRange-charsCopied;
1.216 + }
1.217 + return entry;
1.218 + }
1.219 +
1.220 +
1.221 +void CTextFieldSet::AddInitialFieldEntryL(CArrayFixSeg<TTextFieldEntry>* aArray,TInt aDocumentLength)
1.222 +// Add initial entry
1.223 + {
1.224 + TTextFieldEntry initialEntry;
1.225 + initialEntry.iPreFieldLen = aDocumentLength;
1.226 + initialEntry.iFieldValueLen = 0;
1.227 + initialEntry.iFieldHeader.iFieldType = KNullUid;
1.228 + initialEntry.iFieldHeader.iField = NULL;
1.229 + aArray->AppendL(initialEntry);
1.230 + }
1.231 +
1.232 +
1.233 +EXPORT_C void CTextFieldSet::Reset()
1.234 +// deletes all fields (but not corresponding text) and reinitialises the field array
1.235 +//
1.236 + {
1.237 + __TEST_INVARIANT;
1.238 +
1.239 + for (TInt index=FieldCount()-1 ; index>=0 ; index--)
1.240 + delete (*iFieldArray)[index].iFieldHeader.iField.AsPtr(); // Delete the textField objects
1.241 + iFieldArray->Reset();
1.242 + AddInitialFieldEntryL(iFieldArray,0); // cannot leave in this context
1.243 + iFieldArray->Compress(); // compress array
1.244 +
1.245 + __TEST_INVARIANT;
1.246 + }
1.247 +
1.248 +
1.249 +EXPORT_C CTextField* CTextFieldSet::NewFieldL(TUid aFieldType)
1.250 + {
1.251 + if (iFieldFactory)
1.252 + return iFieldFactory->NewFieldL(aFieldType);
1.253 + else
1.254 + return NULL;
1.255 + }
1.256 +
1.257 +
1.258 +EXPORT_C TInt CTextFieldSet::InsertFieldL(TInt aPos,CTextField* aField,TUid aFieldType)
1.259 +// Inserts a field header aField at aPos (aField should be declared on the heap)
1.260 +// The field initially has zero length: Update must be called afterward
1.261 +//
1.262 + {
1.263 + __TEST_INVARIANT;
1.264 + __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
1.265 + __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
1.266 + __ASSERT_ALWAYS(aField,Panic(ENoTextField));
1.267 +
1.268 + TInt errLevel=KErrAlreadyExists;
1.269 + TTextFieldEntry entry;
1.270 + entry.iFieldHeader.iField = aField;
1.271 + entry.iFieldHeader.iFieldType = aFieldType;
1.272 + entry.iFieldValueLen = 0;
1.273 + TInt index; TInt offset;
1.274 + TBool inField = InField(aPos,index,offset);
1.275 + if (!inField)
1.276 + {// not inserting into a field
1.277 + entry.iPreFieldLen = offset;
1.278 + iFieldArray->InsertL(index,entry); // insert new entry
1.279 + (*iFieldArray)[index+1].iPreFieldLen -= offset; // update old entry
1.280 + errLevel = KErrNone;
1.281 + }
1.282 + else if (offset==0)
1.283 + {// at start of field
1.284 + entry.iPreFieldLen = (*iFieldArray)[index].iPreFieldLen;
1.285 + iFieldArray->InsertL(index,entry); // insert new entry
1.286 + (*iFieldArray)[index+1].iPreFieldLen = 0; // update old entry
1.287 + errLevel = KErrNone;
1.288 + }
1.289 +
1.290 + __TEST_INVARIANT;
1.291 + return errLevel;
1.292 + }
1.293 +
1.294 +
1.295 +EXPORT_C const CTextField* CTextFieldSet::TextField(TInt aPos)const
1.296 +// Return a handle to the concrete field at document position aPos.
1.297 +// Returns NULL if there is no field at position aPos.
1.298 +//
1.299 + {
1.300 + __TEST_INVARIANT;
1.301 +
1.302 + TInt index=-1;
1.303 + TInt offset=0;
1.304 + TBool inField=InField(aPos,index,offset);
1.305 + if (!inField)
1.306 + return NULL;
1.307 + TSwizzle<CTextField> field=(*iFieldArray)[index].iFieldHeader.iField;
1.308 + __ASSERT_DEBUG(field.IsPtr(),User::Invariant());
1.309 + return field.AsPtr();
1.310 + }
1.311 +
1.312 +
1.313 +EXPORT_C TInt CTextFieldSet::RemoveField(TInt aPos)
1.314 +// Removes the field from the array, adding it's content to the "before" of the next field.
1.315 +// After this function is called the text the field contained should be deleted. If this does
1.316 +// not happen this function acts as a "ConvertFieldToText()"
1.317 +//
1.318 + {
1.319 + __TEST_INVARIANT;
1.320 + __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
1.321 + __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
1.322 +
1.323 + TInt errLevel=KErrNone;
1.324 + TInt index; TInt offset;
1.325 + if (!InField(aPos,index,offset))
1.326 + errLevel = KErrNotFound;
1.327 + else
1.328 + // delete the field entry tidily
1.329 + DeleteFieldEntry(index);
1.330 +
1.331 + __TEST_INVARIANT;
1.332 + return errLevel;
1.333 + }
1.334 +
1.335 +
1.336 +EXPORT_C TInt CTextFieldSet::FieldCount() const
1.337 + {
1.338 + __TEST_INVARIANT;
1.339 +
1.340 + // return count-1 because there is always an entry in the array for the text at the
1.341 + // end of the document, after the last field (maybe just the end of doc char)
1.342 + return (iFieldArray->Count()-1);
1.343 + }
1.344 +
1.345 +
1.346 +EXPORT_C TInt CTextFieldSet::CharCount() const
1.347 +// returns the number of characters in the document according to the field array
1.348 + {
1.349 + __TEST_INVARIANT;
1.350 +
1.351 + TInt charCount = 0;
1.352 + for (TInt index=FieldCount() ; index>=0 ; index--)
1.353 + charCount += (*iFieldArray)[index].iPreFieldLen+(*iFieldArray)[index].iFieldValueLen;
1.354 + return charCount;
1.355 + }
1.356 +
1.357 +
1.358 +EXPORT_C TBool CTextFieldSet::FindFields(TInt aPos) const
1.359 +// Return ETrue if aPos is in a field
1.360 +//
1.361 + {
1.362 + TFindFieldInfo dummy;
1.363 + return (FindFields(dummy,aPos,0));
1.364 + }
1.365 +
1.366 +
1.367 +EXPORT_C TBool CTextFieldSet::FindFields(TFindFieldInfo& aInfo,TInt aPos, TInt aRange) const
1.368 +// Check whether aPos is in a field, then check whether any fields start in aRange
1.369 +//
1.370 + {
1.371 + __TEST_INVARIANT;
1.372 + __ASSERT_ALWAYS(aRange>=0,Panic(ENegativeRange));
1.373 + __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc));
1.374 + __ASSERT_ALWAYS(aPos+aRange<=CharCount(),Panic(EPosOutsideDoc));
1.375 +
1.376 + aInfo.iFieldCountInRange = 0;
1.377 + aInfo.iFirstFieldLen = 0;
1.378 + aInfo.iFirstFieldPos = 0;
1.379 + TInt pos=aPos; // position in doc
1.380 + // are we in a field to begin with?
1.381 + TInt index; TInt offset;
1.382 + if (InField(aPos,index,offset))
1.383 + {
1.384 + aInfo.iFieldCountInRange++;
1.385 + aInfo.iFirstFieldLen = (*iFieldArray)[index].iFieldValueLen;
1.386 + aInfo.iFirstFieldPos = aPos-offset;
1.387 + pos += (*iFieldArray)[index].iFieldValueLen-offset+(*iFieldArray)[index+1].iPreFieldLen;
1.388 + index++;
1.389 + }
1.390 + else
1.391 + pos += (*iFieldArray)[index].iPreFieldLen-offset;
1.392 + // step through array until aRange
1.393 + while (pos<aPos+aRange)
1.394 + // When entering this loop we're always at the beginning of a field value
1.395 + // set aFieldEntry to first field found (if fieldcount==0)
1.396 + // for each start of field encountered, fieldCount++
1.397 + {
1.398 + if (aInfo.iFieldCountInRange==0)
1.399 + {
1.400 + aInfo.iFirstFieldLen = (*iFieldArray)[index].iFieldValueLen;
1.401 + aInfo.iFirstFieldPos = pos;
1.402 + }
1.403 + aInfo.iFieldCountInRange++;
1.404 + pos += (*iFieldArray)[index].iFieldValueLen+(*iFieldArray)[index+1].iPreFieldLen;
1.405 + index++;
1.406 + }
1.407 + // (if sensing right) check that we haven't ended adjacent to one or more zero-length fields
1.408 + if ( (aRange==0) && (pos==aPos) && (index<(iFieldArray->Count()-1)) && ((*iFieldArray)[index].iFieldValueLen==0) )
1.409 + {
1.410 + aInfo.iFieldCountInRange++;
1.411 + index++;
1.412 + while ( ((*iFieldArray)[index].iPreFieldLen==0) && ((*iFieldArray)[index].iFieldValueLen==0) && (index<(iFieldArray->Count()-1)) )
1.413 + {
1.414 + aInfo.iFieldCountInRange++;
1.415 + index++;
1.416 + }
1.417 + }
1.418 +
1.419 + __ASSERT_DEBUG(aInfo.iFieldCountInRange<=FieldCount(),Panic(EDebug));
1.420 + return aInfo.iFieldCountInRange;
1.421 + }
1.422 +
1.423 +
1.424 +EXPORT_C TInt CTextFieldSet::NewFieldValueL(HBufC*& aBuf, TInt aPos)
1.425 +// Returns the new value of the field at aPos (if applicable).
1.426 +// The method might reallocate aBuf parameter, so don't forget to:
1.427 +// 1) Push aBuf parameter in the CleanupStack before the call. The call
1.428 +// may fail, then aBuf gets lost.
1.429 +// 2) Pop aBuf parameter from the CleanupStack after the call - aBuf may get
1.430 +// reallocated, so the pushed pointer becomes invalid.
1.431 +// 3) Push aBuf in the CleanupStack again.
1.432 + {
1.433 + __TEST_INVARIANT;
1.434 + __ASSERT_ALWAYS(aBuf,Panic(ENoBuffer));
1.435 + __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
1.436 + __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
1.437 +
1.438 + TInt errLevel = KErrNotFound;
1.439 + TInt index; TInt offset;
1.440 + if (InField(aPos,index,offset))
1.441 + {// There's a field at aPos
1.442 + TPtr bufPtr = aBuf->Des();
1.443 + TInt reqLen = (*iFieldArray)[index].iFieldHeader.iField->Value(bufPtr);
1.444 + while (reqLen>0)
1.445 + {// If more storage is required for the value then reallocate the buffer
1.446 + aBuf = aBuf->ReAllocL(reqLen); // for unicode compatability, rounds up
1.447 + TPtr pointer = aBuf->Des();
1.448 + reqLen = (*iFieldArray)[index].iFieldHeader.iField->Value(pointer);
1.449 + }
1.450 + // dont set new field length - this will be done in a subsequent NotifyInsert()
1.451 + errLevel = KErrNone;
1.452 + }
1.453 +
1.454 + __TEST_INVARIANT;
1.455 + return errLevel;
1.456 + }
1.457 +
1.458 +
1.459 +EXPORT_C void CTextFieldSet::NotifyInsertion(TInt aPos, TInt aNumberAdded)
1.460 +// Informs the array that aNumberAdded characters have been inserted in the document
1.461 +//
1.462 + {
1.463 + __TEST_INVARIANT;
1.464 + __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc));
1.465 + __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
1.466 + __ASSERT_ALWAYS(aNumberAdded>=0,Panic(EIllegalNegativeValue));
1.467 +
1.468 + TInt index; TInt offset;
1.469 + // are the extra characters in a field (matching away from fields)?
1.470 + if (!InField(aPos,index,offset))
1.471 + (*iFieldArray)[index].iPreFieldLen += aNumberAdded;
1.472 + else
1.473 + if (offset>0)
1.474 + (*iFieldArray)[index].iFieldValueLen += aNumberAdded;
1.475 + else
1.476 + (*iFieldArray)[index].iPreFieldLen += aNumberAdded;
1.477 +
1.478 + __TEST_INVARIANT;
1.479 + }
1.480 +
1.481 +
1.482 +EXPORT_C void CTextFieldSet::NotifyFieldUpdate(TInt aPos, TInt aNewFieldValueLength)
1.483 + {
1.484 + __TEST_INVARIANT;
1.485 + __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
1.486 + __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
1.487 + __ASSERT_ALWAYS(aNewFieldValueLength>=0,Panic(EIllegalNegativeValue));
1.488 +
1.489 + // Is the insert pos in a field? If so which?
1.490 + TInt index; TInt offset;
1.491 + __ASSERT_ALWAYS(InField(aPos,index,offset),Panic(EPosNotInField));
1.492 + // Update the length of the relevant field
1.493 + (*iFieldArray)[index].iFieldValueLen = aNewFieldValueLength;
1.494 +
1.495 + __TEST_INVARIANT;
1.496 + }
1.497 +
1.498 +
1.499 +EXPORT_C void CTextFieldSet::NotifyDeletion(TInt aPos,TInt aTotalRemoved)
1.500 +// Informs the array that aTotalRemoved characters have been removed from the document
1.501 +// Any fields wholely contained will be removed, those partially intersecting will just be shortened
1.502 +//
1.503 + {
1.504 + __TEST_INVARIANT;
1.505 + __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc));
1.506 + __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
1.507 + __ASSERT_ALWAYS(aTotalRemoved>=0,Panic(EIllegalNegativeValue));
1.508 +
1.509 + TInt charCount = CharCount();
1.510 +
1.511 + //There is a possibility that there exists hidden end-of-document character in rich text objects.
1.512 + //This is checked by the if statement & accordingly aTotalRemoved is decremented.
1.513 + //i.e. aPos + aTotalRemoved could be greater by 1 than the CharCount(),
1.514 + //this is because the aTotalRemoved might also include 1 hidden character. - DEF095911
1.515 + if(aPos+aTotalRemoved > charCount)
1.516 + aTotalRemoved--;
1.517 +
1.518 + __ASSERT_DEBUG(aPos+aTotalRemoved<=charCount, Panic(EPosOutsideDoc));
1.519 +
1.520 + int index = 0;
1.521 + int offset = 0;
1.522 + int cur_pos = aPos;
1.523 + int end_pos = aPos + aTotalRemoved;
1.524 + TBool in_field = InField(cur_pos,index,offset);
1.525 + TTextFieldEntry* field = NULL;
1.526 + int field_start = 0;
1.527 + int field_end = 0;
1.528 + if (index >= 0 && index < iFieldArray->Count())
1.529 + {
1.530 + field = &(*iFieldArray)[index];
1.531 + field_start = cur_pos - offset;
1.532 + if (!in_field)
1.533 + field_start += field->iPreFieldLen;
1.534 + field_end = field_start + field->iFieldValueLen;
1.535 + }
1.536 +
1.537 + while (field)
1.538 + {
1.539 + // Reduce the size of the gap before the field if any.
1.540 + int gap = Min(end_pos,field_start) - cur_pos;
1.541 + if (gap > 0)
1.542 + {
1.543 + cur_pos += gap;
1.544 + field->iPreFieldLen -= gap;
1.545 + }
1.546 + if (cur_pos >= end_pos)
1.547 + break;
1.548 +
1.549 + // Reduce the field length.
1.550 + int remove_start = cur_pos;
1.551 + int remove_end = Min(field_end,end_pos);
1.552 + cur_pos = field_end;
1.553 + field->iFieldValueLen -= (remove_end - remove_start);
1.554 +
1.555 + // Delete the field if it is now of zero length.
1.556 + int added_to_next = 0;
1.557 + if (field->iFieldValueLen == 0)
1.558 + {
1.559 + added_to_next = field->iPreFieldLen;
1.560 + DeleteFieldEntry(index);
1.561 + }
1.562 + else
1.563 + index++;
1.564 +
1.565 + // Move to the next field.
1.566 + if (index < iFieldArray->Count())
1.567 + {
1.568 + field = &(*iFieldArray)[index];
1.569 + field_start = cur_pos + field->iPreFieldLen - added_to_next;
1.570 + field_end = field_start + field->iFieldValueLen;
1.571 + }
1.572 + else
1.573 + field = NULL;
1.574 + }
1.575 +
1.576 + __TEST_INVARIANT;
1.577 + }
1.578 +
1.579 +
1.580 +TBool CTextFieldSet::InField(const TInt aPos, TInt& anIndex, TInt& anOffset) const
1.581 +// works out whether or not aPos is in a field (matching right),
1.582 +// sets anIndex to the index number of the field entry,
1.583 +// and sets anOffset to the distance aPos is into the field or its preceeding gap
1.584 +//
1.585 + {
1.586 + __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
1.587 + __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
1.588 +
1.589 + TBool inField;
1.590 + TInt currentPos = 0;
1.591 + anIndex = 0;
1.592 + TInt lengthOfDoc = CharCount();
1.593 + TInt lastFieldNum = iFieldArray->Count()-1;
1.594 + // Find the index of the entry containing aPos
1.595 + if (aPos == lengthOfDoc)
1.596 + {
1.597 + anIndex = lastFieldNum;
1.598 + currentPos = aPos;
1.599 + }
1.600 + else
1.601 + {
1.602 + anIndex = -1;
1.603 + while (aPos >= currentPos)
1.604 + {
1.605 + anIndex++;
1.606 + currentPos += (*iFieldArray)[anIndex].iPreFieldLen+(*iFieldArray)[anIndex].iFieldValueLen;
1.607 + }
1.608 + }
1.609 + // Check that we have not skipped over any zero-length fields
1.610 + if ( ((anIndex-1)>=0) && ((*iFieldArray)[anIndex-1].iFieldValueLen==0) )
1.611 + {
1.612 + TInt temp = currentPos - ((*iFieldArray)[anIndex].iPreFieldLen+(*iFieldArray)[anIndex].iFieldValueLen);
1.613 + if (temp==aPos)
1.614 + {// aPos is on a field boundary
1.615 + currentPos = temp;
1.616 + anIndex--;
1.617 + while ( ((anIndex-1)>=0)
1.618 + &&((*iFieldArray)[anIndex].iPreFieldLen==0)
1.619 + &&((*iFieldArray)[anIndex-1].iFieldValueLen==0) )
1.620 + {
1.621 + anIndex--;
1.622 + }
1.623 + }
1.624 + }
1.625 + // Move to the start of the field (end of prefield) in entry [anIndex]
1.626 + currentPos -= (*iFieldArray)[anIndex].iFieldValueLen;
1.627 + // Determine whether or not aPos is in the field of entry[anIndex]
1.628 + if (anIndex == lastFieldNum)
1.629 + inField = EFalse;
1.630 + else if (aPos >= currentPos)
1.631 + inField = ETrue;
1.632 + else
1.633 + inField = EFalse;
1.634 + // Calculate the offset
1.635 + if (inField)
1.636 + anOffset = aPos-currentPos;
1.637 + else
1.638 + anOffset = aPos+(*iFieldArray)[anIndex].iPreFieldLen-currentPos;
1.639 + return inField;
1.640 + }
1.641 +
1.642 +
1.643 +void CTextFieldSet::DeleteFieldEntry(TInt anIndex)
1.644 + {
1.645 + DeleteFieldEntry(iFieldArray,anIndex);
1.646 + }
1.647 +
1.648 +
1.649 +void CTextFieldSet::DeleteFieldEntry(CArrayFixSeg<TTextFieldEntry>* aArray,TInt anIndex)
1.650 +// remove the entry anIndex from the array but don't delete the text from the doc.
1.651 +//
1.652 + {
1.653 + __ASSERT_ALWAYS(anIndex<(aArray->Count()-1),Panic(EIndexOutOfRange));
1.654 +
1.655 + // add the entry's "before" to the "before" of the next entry.
1.656 + (*aArray)[anIndex+1].iPreFieldLen += (*aArray)[anIndex].iPreFieldLen;
1.657 + // add the field's length to the "before" of the next entry.
1.658 + (*aArray)[anIndex+1].iPreFieldLen += (*aArray)[anIndex].iFieldValueLen;
1.659 + if ((*aArray)[anIndex].iFieldHeader.iField.IsPtr())
1.660 + delete (*aArray)[anIndex].iFieldHeader.iField.AsPtr(); // delete the field
1.661 + aArray->Delete(anIndex); // remove the entry from the array
1.662 + }
1.663 +
1.664 +
1.665 +///////////////////////////////////////////////
1.666 +// TTextFieldEntry
1.667 +///////////////////////////////////////////////
1.668 +
1.669 +
1.670 +EXPORT_C void TTextFieldEntry::InternalizeL(RReadStream& aStream)
1.671 +// entry must have a header (ie cant be last entry in the array)
1.672 + {
1.673 + iPreFieldLen = aStream.ReadInt32L();
1.674 + iFieldValueLen = aStream.ReadInt32L();
1.675 + aStream>> iFieldHeader;
1.676 + }
1.677 +
1.678 +
1.679 +EXPORT_C void TTextFieldEntry::ExternalizeL(RWriteStream& aStream)const
1.680 +// entry must have a header (ie cant be last entry in the array)
1.681 + {
1.682 + aStream.WriteInt32L(iPreFieldLen);
1.683 + aStream.WriteInt32L(iFieldValueLen);
1.684 + aStream<< iFieldHeader;
1.685 + }
1.686 +
1.687 +