|
1 /* |
|
2 * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32std.h> |
|
20 #include <e32base.h> |
|
21 |
|
22 #include "FLDSET.H" |
|
23 #include "FLDDEF.H" |
|
24 #include "FLDARRAY.H" |
|
25 #include "FLDSTD.H" |
|
26 |
|
27 |
|
28 EXPORT_C void CTextFieldSet::__DbgTestInvariant()const |
|
29 // Provides class invariants. Explanations below: |
|
30 // |
|
31 { |
|
32 #ifdef _DEBUG |
|
33 if (!iFieldArray) |
|
34 return; |
|
35 // check that every entry in the array has length >=0 and that all but the last have valid header handles |
|
36 TBool valid = ETrue; |
|
37 TInt index = iFieldArray->Count()-1; |
|
38 if (index<0) |
|
39 valid = EFalse; |
|
40 else |
|
41 {// check last entry: should have null fieldHeader, zero field length and non-negative PreFieldLen |
|
42 if ( (*iFieldArray)[index].iFieldHeader.iField |
|
43 ||(*iFieldArray)[index].iFieldValueLen!=0 |
|
44 ||(*iFieldArray)[index].iPreFieldLen<0 ) |
|
45 { |
|
46 valid = EFalse; |
|
47 } |
|
48 index--; |
|
49 // check the other entries: should have non-null fieldHeader and non-negative field length and PreFieldLen |
|
50 for (; (index>=0)&&(valid) ; index--) |
|
51 { |
|
52 if ((*iFieldArray)[index].iFieldValueLen<0 |
|
53 ||(*iFieldArray)[index].iPreFieldLen<0 ) |
|
54 { |
|
55 valid = EFalse; |
|
56 } |
|
57 } |
|
58 } |
|
59 __ASSERT_ALWAYS(valid,User::Invariant()); |
|
60 #endif |
|
61 } |
|
62 |
|
63 |
|
64 EXPORT_C CTextFieldSet* CTextFieldSet::NewL(TInt aDocumentLength) |
|
65 { |
|
66 CTextFieldSet* self=new(ELeave) CTextFieldSet(); |
|
67 CleanupStack::PushL(self); |
|
68 self->ConstructL(aDocumentLength); |
|
69 CleanupStack::Pop(); |
|
70 return self; |
|
71 } |
|
72 |
|
73 |
|
74 EXPORT_C CTextFieldSet* CTextFieldSet::NewL(const MTextFieldFactory* aFactory,const CStreamStore& aFieldStore,TStreamId aStreamId) |
|
75 { |
|
76 CTextFieldSet* self=new(ELeave) CTextFieldSet(); |
|
77 CleanupStack::PushL(self); |
|
78 self->SetFieldFactory(CONST_CAST(MTextFieldFactory*,aFactory)); |
|
79 self->ConstructL(0); |
|
80 self->DoRestoreL(aFieldStore,aStreamId); |
|
81 CleanupStack::Pop(); |
|
82 return self; |
|
83 } |
|
84 |
|
85 |
|
86 CTextFieldSet::CTextFieldSet() |
|
87 {} |
|
88 |
|
89 |
|
90 void CTextFieldSet::ConstructL(TInt aDocumentLength) |
|
91 // Creates an array in which to store all fields |
|
92 // Inserts an initial entry into the array to cover any text that lies after the last field |
|
93 // |
|
94 { |
|
95 iFieldArray = new(ELeave) CArrayFixSeg<TTextFieldEntry>(KFieldArrayGranularity); |
|
96 AddInitialFieldEntryL(iFieldArray,aDocumentLength); |
|
97 |
|
98 __TEST_INVARIANT; |
|
99 } |
|
100 |
|
101 |
|
102 EXPORT_C CTextFieldSet::~CTextFieldSet() |
|
103 { |
|
104 delete iRollbackInfo; |
|
105 if (iFieldArray) |
|
106 { |
|
107 TInt fieldCount=iFieldArray->Count(); |
|
108 for (TInt index=fieldCount-1;index>=0;index--) |
|
109 delete (*iFieldArray)[index].iFieldHeader.iField.AsPtr(); // Delete the textField objects |
|
110 delete iFieldArray; |
|
111 } |
|
112 } |
|
113 |
|
114 |
|
115 EXPORT_C void CTextFieldSet::SetFieldFactory(MTextFieldFactory* aFactory) |
|
116 { |
|
117 iFieldFactory = aFactory; |
|
118 } |
|
119 |
|
120 |
|
121 EXPORT_C MTextFieldFactory* CTextFieldSet::FieldFactory()const |
|
122 { |
|
123 return iFieldFactory; |
|
124 } |
|
125 |
|
126 |
|
127 void CTextFieldSet::InsertEntryL(TInt aIndex,TTextFieldEntry& aEntry) |
|
128 { |
|
129 InsertEntryL(aIndex,aEntry,iFieldArray); |
|
130 } |
|
131 |
|
132 |
|
133 void CTextFieldSet::InsertEntryL(TInt aIndex,TTextFieldEntry& aEntry,CArrayFixSeg<TTextFieldEntry>* aArray) |
|
134 // if this function leaves it will be as if it had never been called... |
|
135 // |
|
136 { |
|
137 if (aEntry.iFieldHeader.iField.IsPtr()) |
|
138 CleanupStack::PushL(aEntry.iFieldHeader.iField.AsPtr()); |
|
139 aArray->InsertL(aIndex,aEntry); // insert new entry |
|
140 if (aEntry.iFieldHeader.iField.IsPtr()) |
|
141 CleanupStack::Pop(); |
|
142 } |
|
143 |
|
144 |
|
145 void CTextFieldSet::AppendEntryL(TTextFieldEntry& aEntry) |
|
146 { |
|
147 AppendEntryL(aEntry,iFieldArray); |
|
148 } |
|
149 |
|
150 |
|
151 void CTextFieldSet::AppendEntryL(TTextFieldEntry& aEntry,CArrayFixSeg<TTextFieldEntry>* aArray) |
|
152 { |
|
153 if (aEntry.iFieldHeader.iField.IsPtr()) |
|
154 CleanupStack::PushL(aEntry.iFieldHeader.iField.AsPtr()); |
|
155 aArray->AppendL(aEntry); // insert new entry |
|
156 if (aEntry.iFieldHeader.iField.IsPtr()) |
|
157 CleanupStack::Pop(); |
|
158 } |
|
159 |
|
160 |
|
161 TInt CTextFieldSet::EntryLen(TInt aIndex)const |
|
162 { |
|
163 return EntryLen((*iFieldArray)[aIndex]); |
|
164 } |
|
165 |
|
166 |
|
167 TInt CTextFieldSet::EntryLen(const TTextFieldEntry& aEntry)const |
|
168 { |
|
169 return aEntry.iPreFieldLen+aEntry.iFieldValueLen; |
|
170 } |
|
171 |
|
172 |
|
173 TTextFieldEntry CTextFieldSet::SplitEntry(TInt aIndex,TInt aOffset, TInt aRange)const |
|
174 // Splits the entry aIndex, returning the part demarked by the offset (from the start of the entry) and the range |
|
175 // |
|
176 { |
|
177 __TEST_INVARIANT; |
|
178 |
|
179 __ASSERT_DEBUG((aIndex>=0)&&(aIndex<iFieldArray->Count()),Panic(EIndexOutOfRange)); |
|
180 TInt entryLength = EntryLen(aIndex); |
|
181 __ASSERT_DEBUG((aOffset>=0)&&(aOffset<=entryLength),Panic(EPosOutOfRange)); |
|
182 __ASSERT_DEBUG((aRange>=0),Panic(ENegativeRange)); |
|
183 |
|
184 if ((aOffset+aRange)>entryLength) |
|
185 aRange = entryLength-aOffset; // scale range down to entry size if neccessary |
|
186 |
|
187 if ((aOffset==0)&&(aRange==entryLength)) |
|
188 return (*iFieldArray)[aIndex]; //entry does not need to be split |
|
189 |
|
190 TInt charsCopied=0; |
|
191 TTextFieldEntry entry; |
|
192 entry.iPreFieldLen = 0; |
|
193 entry.iFieldValueLen = 0; |
|
194 entry.iFieldHeader.iField = NULL; |
|
195 if (aOffset<(*iFieldArray)[aIndex].iPreFieldLen) |
|
196 {// At least some of the pre needs to be copied |
|
197 entry.iPreFieldLen = (*iFieldArray)[aIndex].iPreFieldLen-aOffset; |
|
198 if ((entry.iPreFieldLen)>aRange) |
|
199 entry.iPreFieldLen = aRange; |
|
200 charsCopied = entry.iPreFieldLen; |
|
201 } |
|
202 |
|
203 if (charsCopied<aRange) |
|
204 {// more to do, so at least some of the field needs to be copied |
|
205 if ((aOffset+aRange)==entryLength) |
|
206 {// whole field in range so copy it |
|
207 entry.iFieldValueLen = (*iFieldArray)[aIndex].iFieldValueLen; |
|
208 entry.iFieldHeader = (*iFieldArray)[aIndex].iFieldHeader; |
|
209 } |
|
210 else |
|
211 // only part of field in range so convert it to text |
|
212 entry.iPreFieldLen += aRange-charsCopied; |
|
213 } |
|
214 return entry; |
|
215 } |
|
216 |
|
217 |
|
218 void CTextFieldSet::AddInitialFieldEntryL(CArrayFixSeg<TTextFieldEntry>* aArray,TInt aDocumentLength) |
|
219 // Add initial entry |
|
220 { |
|
221 TTextFieldEntry initialEntry; |
|
222 initialEntry.iPreFieldLen = aDocumentLength; |
|
223 initialEntry.iFieldValueLen = 0; |
|
224 initialEntry.iFieldHeader.iFieldType = KNullUid; |
|
225 initialEntry.iFieldHeader.iField = NULL; |
|
226 aArray->AppendL(initialEntry); |
|
227 } |
|
228 |
|
229 |
|
230 EXPORT_C void CTextFieldSet::Reset() |
|
231 // deletes all fields (but not corresponding text) and reinitialises the field array |
|
232 // |
|
233 { |
|
234 __TEST_INVARIANT; |
|
235 |
|
236 for (TInt index=FieldCount()-1 ; index>=0 ; index--) |
|
237 delete (*iFieldArray)[index].iFieldHeader.iField.AsPtr(); // Delete the textField objects |
|
238 iFieldArray->Reset(); |
|
239 AddInitialFieldEntryL(iFieldArray,0); // cannot leave in this context |
|
240 iFieldArray->Compress(); // compress array |
|
241 |
|
242 __TEST_INVARIANT; |
|
243 } |
|
244 |
|
245 |
|
246 EXPORT_C CTextField* CTextFieldSet::NewFieldL(TUid aFieldType) |
|
247 { |
|
248 if (iFieldFactory) |
|
249 return iFieldFactory->NewFieldL(aFieldType); |
|
250 else |
|
251 return NULL; |
|
252 } |
|
253 |
|
254 |
|
255 EXPORT_C TInt CTextFieldSet::InsertFieldL(TInt aPos,CTextField* aField,TUid aFieldType) |
|
256 // Inserts a field header aField at aPos (aField should be declared on the heap) |
|
257 // The field initially has zero length: Update must be called afterward |
|
258 // |
|
259 { |
|
260 __TEST_INVARIANT; |
|
261 __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc)); |
|
262 __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc)); |
|
263 __ASSERT_ALWAYS(aField,Panic(ENoTextField)); |
|
264 |
|
265 TInt errLevel=KErrAlreadyExists; |
|
266 TTextFieldEntry entry; |
|
267 entry.iFieldHeader.iField = aField; |
|
268 entry.iFieldHeader.iFieldType = aFieldType; |
|
269 entry.iFieldValueLen = 0; |
|
270 TInt index; TInt offset; |
|
271 TBool inField = InField(aPos,index,offset); |
|
272 if (!inField) |
|
273 {// not inserting into a field |
|
274 entry.iPreFieldLen = offset; |
|
275 iFieldArray->InsertL(index,entry); // insert new entry |
|
276 (*iFieldArray)[index+1].iPreFieldLen -= offset; // update old entry |
|
277 errLevel = KErrNone; |
|
278 } |
|
279 else if (offset==0) |
|
280 {// at start of field |
|
281 entry.iPreFieldLen = (*iFieldArray)[index].iPreFieldLen; |
|
282 iFieldArray->InsertL(index,entry); // insert new entry |
|
283 (*iFieldArray)[index+1].iPreFieldLen = 0; // update old entry |
|
284 errLevel = KErrNone; |
|
285 } |
|
286 |
|
287 __TEST_INVARIANT; |
|
288 return errLevel; |
|
289 } |
|
290 |
|
291 |
|
292 EXPORT_C const CTextField* CTextFieldSet::TextField(TInt aPos)const |
|
293 // Return a handle to the concrete field at document position aPos. |
|
294 // Returns NULL if there is no field at position aPos. |
|
295 // |
|
296 { |
|
297 __TEST_INVARIANT; |
|
298 |
|
299 TInt index=-1; |
|
300 TInt offset=0; |
|
301 TBool inField=InField(aPos,index,offset); |
|
302 if (!inField) |
|
303 return NULL; |
|
304 TSwizzle<CTextField> field=(*iFieldArray)[index].iFieldHeader.iField; |
|
305 __ASSERT_DEBUG(field.IsPtr(),User::Invariant()); |
|
306 return field.AsPtr(); |
|
307 } |
|
308 |
|
309 |
|
310 EXPORT_C TInt CTextFieldSet::RemoveField(TInt aPos) |
|
311 // Removes the field from the array, adding it's content to the "before" of the next field. |
|
312 // After this function is called the text the field contained should be deleted. If this does |
|
313 // not happen this function acts as a "ConvertFieldToText()" |
|
314 // |
|
315 { |
|
316 __TEST_INVARIANT; |
|
317 __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc)); |
|
318 __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc)); |
|
319 |
|
320 TInt errLevel=KErrNone; |
|
321 TInt index; TInt offset; |
|
322 if (!InField(aPos,index,offset)) |
|
323 errLevel = KErrNotFound; |
|
324 else |
|
325 // delete the field entry tidily |
|
326 DeleteFieldEntry(index); |
|
327 |
|
328 __TEST_INVARIANT; |
|
329 return errLevel; |
|
330 } |
|
331 |
|
332 |
|
333 EXPORT_C TInt CTextFieldSet::FieldCount() const |
|
334 { |
|
335 __TEST_INVARIANT; |
|
336 |
|
337 // return count-1 because there is always an entry in the array for the text at the |
|
338 // end of the document, after the last field (maybe just the end of doc char) |
|
339 return (iFieldArray->Count()-1); |
|
340 } |
|
341 |
|
342 |
|
343 EXPORT_C TInt CTextFieldSet::CharCount() const |
|
344 // returns the number of characters in the document according to the field array |
|
345 { |
|
346 __TEST_INVARIANT; |
|
347 |
|
348 TInt charCount = 0; |
|
349 for (TInt index=FieldCount() ; index>=0 ; index--) |
|
350 charCount += (*iFieldArray)[index].iPreFieldLen+(*iFieldArray)[index].iFieldValueLen; |
|
351 return charCount; |
|
352 } |
|
353 |
|
354 |
|
355 EXPORT_C TBool CTextFieldSet::FindFields(TInt aPos) const |
|
356 // Return ETrue if aPos is in a field |
|
357 // |
|
358 { |
|
359 TFindFieldInfo dummy; |
|
360 return (FindFields(dummy,aPos,0)); |
|
361 } |
|
362 |
|
363 |
|
364 EXPORT_C TBool CTextFieldSet::FindFields(TFindFieldInfo& aInfo,TInt aPos, TInt aRange) const |
|
365 // Check whether aPos is in a field, then check whether any fields start in aRange |
|
366 // |
|
367 { |
|
368 __TEST_INVARIANT; |
|
369 __ASSERT_ALWAYS(aRange>=0,Panic(ENegativeRange)); |
|
370 __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc)); |
|
371 __ASSERT_ALWAYS(aPos+aRange<=CharCount(),Panic(EPosOutsideDoc)); |
|
372 |
|
373 aInfo.iFieldCountInRange = 0; |
|
374 aInfo.iFirstFieldLen = 0; |
|
375 aInfo.iFirstFieldPos = 0; |
|
376 TInt pos=aPos; // position in doc |
|
377 // are we in a field to begin with? |
|
378 TInt index; TInt offset; |
|
379 if (InField(aPos,index,offset)) |
|
380 { |
|
381 aInfo.iFieldCountInRange++; |
|
382 aInfo.iFirstFieldLen = (*iFieldArray)[index].iFieldValueLen; |
|
383 aInfo.iFirstFieldPos = aPos-offset; |
|
384 pos += (*iFieldArray)[index].iFieldValueLen-offset+(*iFieldArray)[index+1].iPreFieldLen; |
|
385 index++; |
|
386 } |
|
387 else |
|
388 pos += (*iFieldArray)[index].iPreFieldLen-offset; |
|
389 // step through array until aRange |
|
390 while (pos<aPos+aRange) |
|
391 // When entering this loop we're always at the beginning of a field value |
|
392 // set aFieldEntry to first field found (if fieldcount==0) |
|
393 // for each start of field encountered, fieldCount++ |
|
394 { |
|
395 if (aInfo.iFieldCountInRange==0) |
|
396 { |
|
397 aInfo.iFirstFieldLen = (*iFieldArray)[index].iFieldValueLen; |
|
398 aInfo.iFirstFieldPos = pos; |
|
399 } |
|
400 aInfo.iFieldCountInRange++; |
|
401 pos += (*iFieldArray)[index].iFieldValueLen+(*iFieldArray)[index+1].iPreFieldLen; |
|
402 index++; |
|
403 } |
|
404 // (if sensing right) check that we haven't ended adjacent to one or more zero-length fields |
|
405 if ( (aRange==0) && (pos==aPos) && (index<(iFieldArray->Count()-1)) && ((*iFieldArray)[index].iFieldValueLen==0) ) |
|
406 { |
|
407 aInfo.iFieldCountInRange++; |
|
408 index++; |
|
409 while ( ((*iFieldArray)[index].iPreFieldLen==0) && ((*iFieldArray)[index].iFieldValueLen==0) && (index<(iFieldArray->Count()-1)) ) |
|
410 { |
|
411 aInfo.iFieldCountInRange++; |
|
412 index++; |
|
413 } |
|
414 } |
|
415 |
|
416 __ASSERT_DEBUG(aInfo.iFieldCountInRange<=FieldCount(),Panic(EDebug)); |
|
417 return aInfo.iFieldCountInRange; |
|
418 } |
|
419 |
|
420 |
|
421 EXPORT_C TInt CTextFieldSet::NewFieldValueL(HBufC*& aBuf, TInt aPos) |
|
422 // Returns the new value of the field at aPos (if applicable). |
|
423 // The method might reallocate aBuf parameter, so don't forget to: |
|
424 // 1) Push aBuf parameter in the CleanupStack before the call. The call |
|
425 // may fail, then aBuf gets lost. |
|
426 // 2) Pop aBuf parameter from the CleanupStack after the call - aBuf may get |
|
427 // reallocated, so the pushed pointer becomes invalid. |
|
428 // 3) Push aBuf in the CleanupStack again. |
|
429 { |
|
430 __TEST_INVARIANT; |
|
431 __ASSERT_ALWAYS(aBuf,Panic(ENoBuffer)); |
|
432 __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc)); |
|
433 __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc)); |
|
434 |
|
435 TInt errLevel = KErrNotFound; |
|
436 TInt index; TInt offset; |
|
437 if (InField(aPos,index,offset)) |
|
438 {// There's a field at aPos |
|
439 TPtr bufPtr = aBuf->Des(); |
|
440 TInt reqLen = (*iFieldArray)[index].iFieldHeader.iField->Value(bufPtr); |
|
441 while (reqLen>0) |
|
442 {// If more storage is required for the value then reallocate the buffer |
|
443 aBuf = aBuf->ReAllocL(reqLen); // for unicode compatability, rounds up |
|
444 TPtr pointer = aBuf->Des(); |
|
445 reqLen = (*iFieldArray)[index].iFieldHeader.iField->Value(pointer); |
|
446 } |
|
447 // dont set new field length - this will be done in a subsequent NotifyInsert() |
|
448 errLevel = KErrNone; |
|
449 } |
|
450 |
|
451 __TEST_INVARIANT; |
|
452 return errLevel; |
|
453 } |
|
454 |
|
455 |
|
456 EXPORT_C void CTextFieldSet::NotifyInsertion(TInt aPos, TInt aNumberAdded) |
|
457 // Informs the array that aNumberAdded characters have been inserted in the document |
|
458 // |
|
459 { |
|
460 __TEST_INVARIANT; |
|
461 __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc)); |
|
462 __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc)); |
|
463 __ASSERT_ALWAYS(aNumberAdded>=0,Panic(EIllegalNegativeValue)); |
|
464 |
|
465 TInt index; TInt offset; |
|
466 // are the extra characters in a field (matching away from fields)? |
|
467 if (!InField(aPos,index,offset)) |
|
468 (*iFieldArray)[index].iPreFieldLen += aNumberAdded; |
|
469 else |
|
470 if (offset>0) |
|
471 (*iFieldArray)[index].iFieldValueLen += aNumberAdded; |
|
472 else |
|
473 (*iFieldArray)[index].iPreFieldLen += aNumberAdded; |
|
474 |
|
475 __TEST_INVARIANT; |
|
476 } |
|
477 |
|
478 |
|
479 EXPORT_C void CTextFieldSet::NotifyFieldUpdate(TInt aPos, TInt aNewFieldValueLength) |
|
480 { |
|
481 __TEST_INVARIANT; |
|
482 __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc)); |
|
483 __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc)); |
|
484 __ASSERT_ALWAYS(aNewFieldValueLength>=0,Panic(EIllegalNegativeValue)); |
|
485 |
|
486 // Is the insert pos in a field? If so which? |
|
487 TInt index; TInt offset; |
|
488 __ASSERT_ALWAYS(InField(aPos,index,offset),Panic(EPosNotInField)); |
|
489 // Update the length of the relevant field |
|
490 (*iFieldArray)[index].iFieldValueLen = aNewFieldValueLength; |
|
491 |
|
492 __TEST_INVARIANT; |
|
493 } |
|
494 |
|
495 |
|
496 EXPORT_C void CTextFieldSet::NotifyDeletion(TInt aPos,TInt aTotalRemoved) |
|
497 // Informs the array that aTotalRemoved characters have been removed from the document |
|
498 // Any fields wholely contained will be removed, those partially intersecting will just be shortened |
|
499 // |
|
500 { |
|
501 __TEST_INVARIANT; |
|
502 __ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc)); |
|
503 __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc)); |
|
504 __ASSERT_ALWAYS(aTotalRemoved>=0,Panic(EIllegalNegativeValue)); |
|
505 |
|
506 TInt charCount = CharCount(); |
|
507 |
|
508 //There is a possibility that there exists hidden end-of-document character in rich text objects. |
|
509 //This is checked by the if statement & accordingly aTotalRemoved is decremented. |
|
510 //i.e. aPos + aTotalRemoved could be greater by 1 than the CharCount(), |
|
511 //this is because the aTotalRemoved might also include 1 hidden character. - DEF095911 |
|
512 if(aPos+aTotalRemoved > charCount) |
|
513 aTotalRemoved--; |
|
514 |
|
515 __ASSERT_DEBUG(aPos+aTotalRemoved<=charCount, Panic(EPosOutsideDoc)); |
|
516 |
|
517 int index = 0; |
|
518 int offset = 0; |
|
519 int cur_pos = aPos; |
|
520 int end_pos = aPos + aTotalRemoved; |
|
521 TBool in_field = InField(cur_pos,index,offset); |
|
522 TTextFieldEntry* field = NULL; |
|
523 int field_start = 0; |
|
524 int field_end = 0; |
|
525 if (index >= 0 && index < iFieldArray->Count()) |
|
526 { |
|
527 field = &(*iFieldArray)[index]; |
|
528 field_start = cur_pos - offset; |
|
529 if (!in_field) |
|
530 field_start += field->iPreFieldLen; |
|
531 field_end = field_start + field->iFieldValueLen; |
|
532 } |
|
533 |
|
534 while (field) |
|
535 { |
|
536 // Reduce the size of the gap before the field if any. |
|
537 int gap = Min(end_pos,field_start) - cur_pos; |
|
538 if (gap > 0) |
|
539 { |
|
540 cur_pos += gap; |
|
541 field->iPreFieldLen -= gap; |
|
542 } |
|
543 if (cur_pos >= end_pos) |
|
544 break; |
|
545 |
|
546 // Reduce the field length. |
|
547 int remove_start = cur_pos; |
|
548 int remove_end = Min(field_end,end_pos); |
|
549 cur_pos = field_end; |
|
550 field->iFieldValueLen -= (remove_end - remove_start); |
|
551 |
|
552 // Delete the field if it is now of zero length. |
|
553 int added_to_next = 0; |
|
554 if (field->iFieldValueLen == 0) |
|
555 { |
|
556 added_to_next = field->iPreFieldLen; |
|
557 DeleteFieldEntry(index); |
|
558 } |
|
559 else |
|
560 index++; |
|
561 |
|
562 // Move to the next field. |
|
563 if (index < iFieldArray->Count()) |
|
564 { |
|
565 field = &(*iFieldArray)[index]; |
|
566 field_start = cur_pos + field->iPreFieldLen - added_to_next; |
|
567 field_end = field_start + field->iFieldValueLen; |
|
568 } |
|
569 else |
|
570 field = NULL; |
|
571 } |
|
572 |
|
573 __TEST_INVARIANT; |
|
574 } |
|
575 |
|
576 |
|
577 TBool CTextFieldSet::InField(const TInt aPos, TInt& anIndex, TInt& anOffset) const |
|
578 // works out whether or not aPos is in a field (matching right), |
|
579 // sets anIndex to the index number of the field entry, |
|
580 // and sets anOffset to the distance aPos is into the field or its preceeding gap |
|
581 // |
|
582 { |
|
583 __ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc)); |
|
584 __ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc)); |
|
585 |
|
586 TBool inField; |
|
587 TInt currentPos = 0; |
|
588 anIndex = 0; |
|
589 TInt lengthOfDoc = CharCount(); |
|
590 TInt lastFieldNum = iFieldArray->Count()-1; |
|
591 // Find the index of the entry containing aPos |
|
592 if (aPos == lengthOfDoc) |
|
593 { |
|
594 anIndex = lastFieldNum; |
|
595 currentPos = aPos; |
|
596 } |
|
597 else |
|
598 { |
|
599 anIndex = -1; |
|
600 while (aPos >= currentPos) |
|
601 { |
|
602 anIndex++; |
|
603 currentPos += (*iFieldArray)[anIndex].iPreFieldLen+(*iFieldArray)[anIndex].iFieldValueLen; |
|
604 } |
|
605 } |
|
606 // Check that we have not skipped over any zero-length fields |
|
607 if ( ((anIndex-1)>=0) && ((*iFieldArray)[anIndex-1].iFieldValueLen==0) ) |
|
608 { |
|
609 TInt temp = currentPos - ((*iFieldArray)[anIndex].iPreFieldLen+(*iFieldArray)[anIndex].iFieldValueLen); |
|
610 if (temp==aPos) |
|
611 {// aPos is on a field boundary |
|
612 currentPos = temp; |
|
613 anIndex--; |
|
614 while ( ((anIndex-1)>=0) |
|
615 &&((*iFieldArray)[anIndex].iPreFieldLen==0) |
|
616 &&((*iFieldArray)[anIndex-1].iFieldValueLen==0) ) |
|
617 { |
|
618 anIndex--; |
|
619 } |
|
620 } |
|
621 } |
|
622 // Move to the start of the field (end of prefield) in entry [anIndex] |
|
623 currentPos -= (*iFieldArray)[anIndex].iFieldValueLen; |
|
624 // Determine whether or not aPos is in the field of entry[anIndex] |
|
625 if (anIndex == lastFieldNum) |
|
626 inField = EFalse; |
|
627 else if (aPos >= currentPos) |
|
628 inField = ETrue; |
|
629 else |
|
630 inField = EFalse; |
|
631 // Calculate the offset |
|
632 if (inField) |
|
633 anOffset = aPos-currentPos; |
|
634 else |
|
635 anOffset = aPos+(*iFieldArray)[anIndex].iPreFieldLen-currentPos; |
|
636 return inField; |
|
637 } |
|
638 |
|
639 |
|
640 void CTextFieldSet::DeleteFieldEntry(TInt anIndex) |
|
641 { |
|
642 DeleteFieldEntry(iFieldArray,anIndex); |
|
643 } |
|
644 |
|
645 |
|
646 void CTextFieldSet::DeleteFieldEntry(CArrayFixSeg<TTextFieldEntry>* aArray,TInt anIndex) |
|
647 // remove the entry anIndex from the array but don't delete the text from the doc. |
|
648 // |
|
649 { |
|
650 __ASSERT_ALWAYS(anIndex<(aArray->Count()-1),Panic(EIndexOutOfRange)); |
|
651 |
|
652 // add the entry's "before" to the "before" of the next entry. |
|
653 (*aArray)[anIndex+1].iPreFieldLen += (*aArray)[anIndex].iPreFieldLen; |
|
654 // add the field's length to the "before" of the next entry. |
|
655 (*aArray)[anIndex+1].iPreFieldLen += (*aArray)[anIndex].iFieldValueLen; |
|
656 if ((*aArray)[anIndex].iFieldHeader.iField.IsPtr()) |
|
657 delete (*aArray)[anIndex].iFieldHeader.iField.AsPtr(); // delete the field |
|
658 aArray->Delete(anIndex); // remove the entry from the array |
|
659 } |
|
660 |
|
661 |
|
662 /////////////////////////////////////////////// |
|
663 // TTextFieldEntry |
|
664 /////////////////////////////////////////////// |
|
665 |
|
666 |
|
667 EXPORT_C void TTextFieldEntry::InternalizeL(RReadStream& aStream) |
|
668 // entry must have a header (ie cant be last entry in the array) |
|
669 { |
|
670 iPreFieldLen = aStream.ReadInt32L(); |
|
671 iFieldValueLen = aStream.ReadInt32L(); |
|
672 aStream>> iFieldHeader; |
|
673 } |
|
674 |
|
675 |
|
676 EXPORT_C void TTextFieldEntry::ExternalizeL(RWriteStream& aStream)const |
|
677 // entry must have a header (ie cant be last entry in the array) |
|
678 { |
|
679 aStream.WriteInt32L(iPreFieldLen); |
|
680 aStream.WriteInt32L(iFieldValueLen); |
|
681 aStream<< iFieldHeader; |
|
682 } |
|
683 |
|
684 |