xref: /trunk/main/sw/source/core/txtnode/thints.cxx (revision 56b35d86)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <hintids.hxx>
29 #include <sot/factory.hxx>
30 #include <editeng/xmlcnitm.hxx>
31 #include <svl/whiter.hxx>
32 #include <svl/itemiter.hxx>
33 #include <svl/stylepool.hxx>
34 #include <editeng/fontitem.hxx>
35 #include <editeng/langitem.hxx>
36 #include <editeng/emphitem.hxx>
37 #include <editeng/charscaleitem.hxx>
38 #include <editeng/charrotateitem.hxx>
39 // --> OD 2008-01-16 #newlistlevelattrs#
40 #include <editeng/lrspitem.hxx>
41 // <--
42 #include <txtinet.hxx>
43 #include <txtflcnt.hxx>
44 #include <fmtfld.hxx>
45 #include <fmtanchr.hxx>
46 #include <fmtinfmt.hxx>
47 #include <txtatr.hxx>
48 #include <fchrfmt.hxx>
49 #include <fmtautofmt.hxx>
50 #include <fmtflcnt.hxx>
51 #include <fmtftn.hxx>
52 #include <txttxmrk.hxx>
53 #include <txtrfmrk.hxx>
54 #include <txtftn.hxx>
55 #include <txtfld.hxx>
56 #include <txtannotationfld.hxx>
57 #include <charatr.hxx>
58 #include <charfmt.hxx>
59 #include <frmfmt.hxx>
60 #include <ftnidx.hxx>
61 #include <fmtruby.hxx>
62 #include <fmtmeta.hxx>
63 #include <breakit.hxx>
64 #include <doc.hxx>
65 #include <IDocumentUndoRedo.hxx>
66 #include <errhdl.hxx>
67 #include <fldbas.hxx>
68 #include <pam.hxx>
69 #include <ndtxt.hxx>
70 #include <txtfrm.hxx>
71 #include <rolbck.hxx>			// fuer	SwRegHistory
72 #include <ddefld.hxx>
73 #include <docufld.hxx>
74 #include <expfld.hxx>
75 #include <usrfld.hxx>
76 #include <poolfmt.hxx>
77 #include <swfont.hxx>
78 #include <istyleaccess.hxx>
79 // OD 26.06.2003 #108784#
80 #include <dcontact.hxx>
81 #include <docsh.hxx>
82 #include <svl/smplhint.hxx>
83 #include <algorithm>
84 #include <map>
85 
86 #ifdef DBG_UTIL
87 #define CHECK    Check();
88 #else
89 #define CHECK
90 #endif
91 
92 using namespace ::com::sun::star::i18n;
93 
94 
95 SwpHints::SwpHints()
96     : m_pHistory(0)
97     , m_bFontChange(true)
98     , m_bInSplitNode(false)
99     , m_bCalcHiddenParaField(false)
100     , m_bHasHiddenParaField(false)
101     , m_bFootnote(false)
102     , m_bDDEFields(false)
103 {
104 }
105 
106 struct TxtAttrDeleter
107 {
108     SwAttrPool & m_rPool;
109     TxtAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { }
110     void operator() (SwTxtAttr * const pAttr)
111     {
112         if (RES_TXTATR_META == pAttr->Which() ||
113             RES_TXTATR_METAFIELD == pAttr->Which())
114         {
115             static_cast<SwTxtMeta *>(pAttr)->ChgTxtNode(0); // prevents ASSERT
116         }
117         SwTxtAttr::Destroy( pAttr, m_rPool );
118     }
119 };
120 
121 struct TxtAttrContains
122 {
123     xub_StrLen m_nPos;
124     TxtAttrContains( const xub_StrLen nPos ) : m_nPos( nPos ) { }
125     bool operator() (SwTxtAttrEnd * const pAttr)
126     {
127         return (*pAttr->GetStart() < m_nPos) && (m_nPos < *pAttr->End());
128     }
129 };
130 
131 // a:       |-----|
132 // b:
133 //    |---|               => valid: b before a
134 //    |-----|             => valid: start == end; b before a
135 //    |---------|         => invalid: overlap (1)
136 //    |-----------|       => valid: same end; b around a
137 //    |-----------------| => valid: b around a
138 //          |---|         => valid; same start; b within a
139 //          |-----|       => valid; same start and end; b around or within a?
140 //          |-----------| => valid: same start: b around a
141 //            |-|         => valid: b within a
142 //            |---|       => valid: same end; b within a
143 //            |---------| => invalid: overlap (2)
144 //                |-----| => valid: end == start; b after a
145 //                  |---| => valid: b after a
146 // ===> 2 invalid overlap cases
147 static
148 bool isOverlap(const xub_StrLen nStart1, const xub_StrLen nEnd1,
149                const xub_StrLen nStart2, const xub_StrLen nEnd2)
150 {
151     return
152         ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2))  // (1)
153      || ((nStart1 < nStart2) && (nStart2 < nEnd1) && (nEnd1 < nEnd2)); // (2)
154 }
155 
156 /// #i106930#: now asymmetric: empty hint1 is _not_ nested, but empty hint2 is
157 static
158 bool isNestedAny(const xub_StrLen nStart1, const xub_StrLen nEnd1,
159                  const xub_StrLen nStart2, const xub_StrLen nEnd2)
160 {
161     return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
162         // same start/end: nested except if hint1 empty and hint2 not empty
163         ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
164         : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
165 }
166 
167 static
168 bool isSelfNestable(const sal_uInt16 nWhich)
169 {
170     if ((RES_TXTATR_INETFMT  == nWhich) ||
171         (RES_TXTATR_CJK_RUBY == nWhich) ||
172         (RES_TXTATR_INPUTFIELD == nWhich))
173         return false;
174     ASSERT((RES_TXTATR_META  == nWhich) ||
175            (RES_TXTATR_METAFIELD  == nWhich), "???");
176     return true;
177 }
178 
179 static
180 bool isSplittable(const sal_uInt16 nWhich)
181 {
182     if ((RES_TXTATR_INETFMT  == nWhich) ||
183         (RES_TXTATR_CJK_RUBY == nWhich))
184         return true;
185     ASSERT((RES_TXTATR_META  == nWhich) ||
186            (RES_TXTATR_METAFIELD  == nWhich) ||
187            (RES_TXTATR_INPUTFIELD  == nWhich), "???");
188     return false;
189 }
190 
191 enum Split_t { FAIL, SPLIT_NEW, SPLIT_OTHER };
192 /**
193   Calculate splitting policy for overlapping hints, based on what kind of
194   hint is inserted, and what kind of existing hint overlaps.
195   */
196 static Split_t
197 splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
198 {
199     if (!isSplittable(nWhichOther))
200     {
201         if (!isSplittable(nWhichNew))
202             return FAIL;
203         else
204             return SPLIT_NEW;
205     }
206     else
207     {
208         if ( RES_TXTATR_INPUTFIELD == nWhichNew )
209             return FAIL;
210         else if ( (RES_TXTATR_INETFMT  == nWhichNew) &&
211                   (RES_TXTATR_CJK_RUBY == nWhichOther) )
212             return SPLIT_NEW;
213         else
214             return SPLIT_OTHER;
215     }
216 }
217 
218 void SwTxtINetFmt::InitINetFmt(SwTxtNode & rNode)
219 {
220     ChgTxtNode(&rNode);
221     SwCharFmt * const pFmt(
222          rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_INET_NORMAL) );
223     pFmt->Add( this );
224 }
225 
226 void SwTxtRuby::InitRuby(SwTxtNode & rNode)
227 {
228     ChgTxtNode(&rNode);
229     SwCharFmt * const pFmt(
230         rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_RUBYTEXT) );
231     pFmt->Add( this );
232 }
233 
234 /**
235   Create a new nesting text hint.
236  */
237 static SwTxtAttrNesting *
238 MakeTxtAttrNesting(SwTxtNode & rNode, SwTxtAttrNesting & rNesting,
239         const xub_StrLen nStart, const xub_StrLen nEnd)
240 {
241     SwTxtAttr * const pNew( MakeTxtAttr(
242             *rNode.GetDoc(), rNesting.GetAttr(), nStart, nEnd ) );
243     switch (pNew->Which())
244     {
245         case RES_TXTATR_INETFMT:
246         {
247             static_cast<SwTxtINetFmt*>(pNew)->InitINetFmt(rNode);
248             break;
249         }
250         case RES_TXTATR_CJK_RUBY:
251         {
252             static_cast<SwTxtRuby*>(pNew)->InitRuby(rNode);
253             break;
254         }
255         default:
256             ASSERT(false, "MakeTxtAttrNesting: what the hell is that?");
257             break;
258     }
259     return static_cast<SwTxtAttrNesting*>(pNew);
260 }
261 
262 typedef ::std::vector<SwTxtAttrNesting *> NestList_t;
263 
264 static void
265 lcl_DoSplitNew(NestList_t & rSplits, SwTxtNode & rNode,
266     const xub_StrLen nNewStart,
267     const xub_StrLen nOtherStart, const xub_StrLen nOtherEnd, bool bOtherDummy)
268 {
269     const bool bSplitAtStart(nNewStart < nOtherStart);
270     const xub_StrLen nSplitPos( (bSplitAtStart) ? nOtherStart : nOtherEnd );
271     // first find the portion that is split (not necessarily the last one!)
272     NestList_t::iterator const iter(
273         ::std::find_if( rSplits.begin(), rSplits.end(),
274             TxtAttrContains(nSplitPos) ) );
275     if (iter != rSplits.end()) // already split here?
276     {
277         const xub_StrLen nStartPos( // skip other's dummy character!
278             (bSplitAtStart && bOtherDummy) ? nSplitPos + 1 : nSplitPos );
279         SwTxtAttrNesting * const pNew( MakeTxtAttrNesting(
280                 rNode, **iter, nStartPos, *(*iter)->GetEnd() ) );
281         *(*iter)->GetEnd() = nSplitPos;
282         rSplits.insert(iter + 1, pNew);
283     }
284 }
285 
286 /**
287   Insert nesting hint into the hints array. Also calls NoteInHistory.
288   @param    rNewHint    the hint to be inserted (must not overlap existing!)
289  */
290 void SwpHints::InsertNesting(SwTxtAttrNesting & rNewHint)
291 {
292     SwpHintsArray::Insert(& rNewHint);
293     NoteInHistory( & rNewHint, true );
294 }
295 
296 /**
297 
298 The following hints correspond to well-formed XML elements in ODF:
299 RES_TXTATR_INETFMT, RES_TXTATR_CJK_RUBY, RES_TXTATR_META, RES_TXTATR_METAFIELD
300 
301 The writer core must ensure that these do not overlap; if they did,
302 the document would not be storable as ODF.
303 
304 Also, a Hyperlink must not be nested within another Hyperlink,
305 and a Ruby must not be nested within another Ruby.
306 
307 The ODF export in xmloff will only put a hyperlink into a ruby, never a ruby
308 into a hyperlink.
309 
310 Unfortunately the UNO API for Hyperlink and Ruby consists of the properties
311 Hyperlink* and Ruby* of the css.text.CharacterProperties service.  In other
312 words, they are treated as formatting attributes, not as content entites.
313 Furthermore, for API users it is not possible to easily test whether a certain
314 range would be overlapping with other nested attributes, and most importantly,
315 <em>which ones</em>, so we can hardly refuse to insert these in cases of
316 overlap.
317 
318 It is possible to split Hyperlink and Ruby into multiple portions, such that
319 the result is properly nested.
320 
321 meta and meta-field must not be split, because they have xml:id.
322 
323 These constraints result in the following design:
324 
325 RES_TXTATR_INETFMT:
326     always succeeds
327     inserts n attributes split at RES_TXTATR_CJK_RUBY, RES_TXTATR_META,
328         RES_TXTATR_METAFIELD
329     may replace existing RES_TXTATR_INETFMT at overlap
330 RES_TXTATR_CJK_RUBY:
331     always succeeds
332     inserts n attributes split at RES_TXTATR_META, RES_TXTATR_METAFIELD
333     may replace existing RES_TXTATR_CJK_RUBY at overlap
334     may split existing overlapping RES_TXTATR_INETFMT
335 RES_TXTATR_META:
336     may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
337     may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
338     inserts 1 attribute
339 RES_TXTATR_METAFIELD:
340     may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
341     may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
342     inserts 1 attribute
343 
344 The nesting is expressed by the position of the hints.
345 RES_TXTATR_META and RES_TXTATR_METAFIELD have a CH_TXTATR, and there can
346 only be one such hint starting and ending at a given position.
347 Only RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY lack a CH_TXTATR.
348 The interpretation given is that RES_TXTATR_CJK_RUBY is always around
349 a RES_TXTATR_INETFMT at the same start and end position (which corresponds
350 with the UNO API).
351 Both of these are always around a nesting hint with CH_TXTATR at the same
352 start and end position (if they should be inside, then the start should be
353 after the CH_TXTATR).
354 It would probably be a bad idea to add another nesting hint without
355 CH_TXTATR; on the other hand, it would be difficult adding a CH_TXTATR to
356 RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY, due to the overwriting and
357 splitting of exising hints that is necessary for backward compatibility.
358 
359     @param rNode    the text node
360     @param rHint    the hint to be inserted
361     @returns        true iff hint was successfully inserted
362 */
363 bool
364 SwpHints::TryInsertNesting( SwTxtNode & rNode, SwTxtAttrNesting & rNewHint )
365 {
366 //    INVARIANT:  the nestable hints in the array are properly nested
367     const sal_uInt16 nNewWhich( rNewHint.Which() );
368     const xub_StrLen nNewStart( *rNewHint.GetStart() );
369     const xub_StrLen nNewEnd  ( *rNewHint.GetEnd()   );
370     const bool bNewSelfNestable( isSelfNestable(nNewWhich) );
371 
372     ASSERT( (RES_TXTATR_INETFMT   == nNewWhich) ||
373             (RES_TXTATR_CJK_RUBY  == nNewWhich) ||
374             (RES_TXTATR_META      == nNewWhich) ||
375             (RES_TXTATR_METAFIELD == nNewWhich) ||
376             (RES_TXTATR_INPUTFIELD == nNewWhich),
377         "TryInsertNesting: Expecting INETFMT or RUBY or META or METAFIELD or INPUTFIELD" );
378 
379     NestList_t OverlappingExisting; // existing hints to be split
380     NestList_t OverwrittenExisting; // existing hints to be replaced
381     NestList_t SplitNew;            // new hints to be inserted
382 
383     SplitNew.push_back(& rNewHint);
384 
385     // pass 1: split the inserted hint into fragments if necessary
386     for ( sal_uInt16 i = 0; i < GetEndCount(); ++i )
387     {
388         SwTxtAttr * const pOther = GetEnd(i);
389 
390         if (pOther->IsNesting())
391         {
392             const sal_uInt16 nOtherWhich( pOther->Which() );
393             const xub_StrLen nOtherStart( *(pOther)->GetStart() );
394             const xub_StrLen nOtherEnd  ( *(pOther)->GetEnd()   );
395             if (isOverlap(nNewStart, nNewEnd, nOtherStart, nOtherEnd ))
396             {
397                 switch (splitPolicy(nNewWhich, nOtherWhich))
398                 {
399                     case FAIL:
400                         OSL_TRACE("cannot insert hint: overlap detected");
401                         ::std::for_each(SplitNew.begin(), SplitNew.end(),
402                             TxtAttrDeleter(*rNode.GetDoc()));
403                         return false;
404                     case SPLIT_NEW:
405                         lcl_DoSplitNew(SplitNew, rNode, nNewStart,
406                             nOtherStart, nOtherEnd, pOther->HasDummyChar());
407                         break;
408                     case SPLIT_OTHER:
409                         OverlappingExisting.push_back(
410                             static_cast<SwTxtAttrNesting*>(pOther));
411                         break;
412                     default:
413                         ASSERT(false, "bad code monkey");
414                         break;
415                 }
416             }
417             else if (isNestedAny(nNewStart, nNewEnd, nOtherStart, nOtherEnd))
418             {
419                 if (!bNewSelfNestable && (nNewWhich == nOtherWhich))
420                 {
421                 // ruby and hyperlink: if there is nesting, _overwrite_
422                 OverwrittenExisting.push_back(
423                     static_cast<SwTxtAttrNesting*>(pOther));
424                 }
425                 else if ((nNewStart == nOtherStart) && pOther->HasDummyChar())
426                 {
427                     if (rNewHint.HasDummyChar())
428                     {
429                         ASSERT(false,
430                                 "ERROR: inserting duplicate CH_TXTATR hint");
431                         return false;
432                     } else if (nNewEnd < nOtherEnd) {
433                         // other has dummy char, new is inside other, but
434                         // new contains the other's dummy char?
435                         // should be corrected because it may lead to problems
436                         // in SwXMeta::createEnumeration
437                         // SplitNew is sorted, so this is the first split
438                         xub_StrLen *const pStart(SplitNew.front()->GetStart());
439                         ASSERT(*pStart == nNewStart, "how did that happen?");
440                         *pStart = nNewStart + 1;
441                     }
442                 }
443             }
444         }
445     }
446 
447     ASSERT (isSplittable(nNewWhich) || SplitNew.size() == 1,
448             "splitting the unsplittable ???");
449 
450     // pass 2: split existing hints that overlap/nest with new hint
451     // do not iterate over hints array, but over remembered set of overlapping
452     // hints, to keep things simple w.r.t. insertion/removal
453     // N.B: if there is a hint that splits the inserted hint, then
454     // that hint would also have already split any hint in OverlappingExisting
455     // so any hint in OverlappingExisting can be split at most by one hint
456     // in SplitNew, or even not at all (this is not true for existing hints
457     // that go _around_ new hint, which is the raison d'^etre for pass 4)
458     for (NestList_t::iterator itOther = OverlappingExisting.begin();
459             itOther != OverlappingExisting.end(); ++itOther)
460     {
461         const xub_StrLen nOtherStart( *(*itOther)->GetStart() );
462         const xub_StrLen nOtherEnd  ( *(*itOther)->GetEnd()   );
463 
464         for (NestList_t::iterator itNew = SplitNew.begin();
465                 itNew != SplitNew.end(); ++itNew)
466         {
467             const xub_StrLen nSplitNewStart( *(*itNew)->GetStart() );
468             const xub_StrLen nSplitNewEnd  ( *(*itNew)->GetEnd()   );
469             // 4 cases: within, around, overlap l, overlap r, (OTHER: no action)
470             const bool bRemoveOverlap(
471                 !bNewSelfNestable && (nNewWhich == (*itOther)->Which()) );
472 
473             switch (ComparePosition(nSplitNewStart, nSplitNewEnd,
474                                     nOtherStart,    nOtherEnd))
475             {
476                 case POS_INSIDE:
477                     {
478                         ASSERT(!bRemoveOverlap,
479                             "this one should be in OverwrittenExisting?");
480                     }
481                     break;
482                 case POS_OUTSIDE:
483                 case POS_EQUAL:
484                     {
485                         ASSERT(false, "existing hint inside new hint: why?");
486                     }
487                     break;
488                 case POS_OVERLAP_BEFORE:
489                     {
490                         Delete( *itOther ); // this also does NoteInHistory!
491                         *(*itOther)->GetStart() = nSplitNewEnd;
492                         InsertNesting( **itOther );
493                         if (!bRemoveOverlap)
494                         {
495                             if ( USHRT_MAX == Count() )
496                             {
497                                 ASSERT(false, "hints array full :-(");
498                                 return false;
499                             }
500                             SwTxtAttrNesting * const pOtherLeft(
501                                 MakeTxtAttrNesting( rNode, **itOther,
502                                     nOtherStart, nSplitNewEnd ) );
503                             InsertNesting( *pOtherLeft );
504                         }
505                     }
506                     break;
507                 case POS_OVERLAP_BEHIND:
508                     {
509                         Delete( *itOther ); // this also does NoteInHistory!
510                         *(*itOther)->GetEnd() = nSplitNewStart;
511                         InsertNesting( **itOther );
512                         if (!bRemoveOverlap)
513                         {
514                             if ( USHRT_MAX == Count() )
515                             {
516                                 ASSERT(false, "hints array full :-(");
517                                 return false;
518                             }
519                             SwTxtAttrNesting * const pOtherRight(
520                                 MakeTxtAttrNesting( rNode, **itOther,
521                                     nSplitNewStart, nOtherEnd ) );
522                             InsertNesting( *pOtherRight );
523                         }
524                     }
525                     break;
526                 default:
527                     break; // overlap resolved by splitting new: nothing to do
528             }
529         }
530     }
531 
532     if ( USHRT_MAX - SplitNew.size() <= Count() )
533     {
534         ASSERT(false, "hints array full :-(");
535         return false;
536     }
537 
538     // pass 3: insert new hints
539     for (NestList_t::iterator iter = SplitNew.begin();
540             iter != SplitNew.end(); ++iter)
541     {
542         InsertNesting(**iter);
543     }
544 
545     // pass 4: handle overwritten hints
546     // RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY should displace attributes
547     // of the same kind.
548     for (NestList_t::iterator itOther = OverwrittenExisting.begin();
549             itOther != OverwrittenExisting.end(); ++itOther)
550     {
551         const xub_StrLen nOtherStart( *(*itOther)->GetStart() );
552         const xub_StrLen nOtherEnd  ( *(*itOther)->GetEnd()   );
553 
554         // overwritten portion is given by start/end of inserted hint
555         if ((nNewStart <= nOtherStart) && (nOtherEnd <= nNewEnd))
556         {
557             Delete(*itOther);
558             rNode.DestroyAttr( *itOther );
559         }
560         else
561         {
562             ASSERT((nOtherStart < nNewStart) && (nNewEnd < nOtherEnd), "huh?");
563         // scenario: there is a RUBY, and contained within that a META;
564         // now a RUBY is inserted within the META => the exising RUBY is split:
565         // here it is not possible to simply insert the left/right fragment
566         // of the existing RUBY because they <em>overlap</em> with the META!
567             Delete( *itOther ); // this also does NoteInHistory!
568             *(*itOther)->GetEnd() = nNewStart;
569             bool bSuccess( TryInsertNesting(rNode, **itOther) );
570             ASSERT(bSuccess, "recursive call 1 failed?");
571             SwTxtAttrNesting * const pOtherRight(
572                 MakeTxtAttrNesting(
573                     rNode, **itOther, nNewEnd, nOtherEnd ) );
574             bSuccess = TryInsertNesting(rNode, *pOtherRight);
575             ASSERT(bSuccess, "recursive call 2 failed?");
576         }
577 
578     }
579 
580     return true;
581 }
582 
583 
584 // This function takes care for the following text attribute:
585 // RES_TXTATR_CHARFMT, RES_TXTATR_AUTOFMT
586 // These attributes have to be handled in a special way (Portion building).
587 //
588 // The new attribute will be split by any existing RES_TXTATR_AUTOFMT or
589 // RES_TXTATR_CHARFMT. The new attribute itself will
590 // split any existing RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT.
591 
592 void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint,
593         const SetAttrMode nMode )
594 {
595     const sal_uInt16 nWhich = rNewHint.Which();
596 
597     const xub_StrLen nThisStart = *rNewHint.GetStart();
598     const xub_StrLen nThisEnd =   *rNewHint.GetEnd();
599     const bool bNoLengthAttribute = nThisStart == nThisEnd;
600 
601     std::vector<SwTxtAttr*> aInsDelHints;
602     std::vector<SwTxtAttr*>::iterator aIter;
603 
604     ASSERT( RES_TXTATR_CHARFMT == rNewHint.Which() ||
605             RES_TXTATR_AUTOFMT == rNewHint.Which(),
606             "Expecting CHARFMT or AUTOFMT" );
607 
608     //
609     // 2. Find the hints which cover the start and end position
610     // of the new hint. These hints have to be split into two portions:
611     //
612     if ( !bNoLengthAttribute ) // nothing to do for no length attributes
613     {
614         for ( sal_uInt16 i = 0; i < Count(); ++i )
615         {
616             SwTxtAttr* pOther = GetTextHint(i);
617 
618             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
619                  RES_TXTATR_AUTOFMT != pOther->Which() )
620                 continue;
621 
622             xub_StrLen nOtherStart = *pOther->GetStart();
623             const xub_StrLen nOtherEnd = *pOther->GetEnd();
624 
625             // Check if start of new attribute overlaps with pOther:
626             // Split pOther if necessary:
627             if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
628             {
629                 SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
630                         pOther->GetAttr(), nOtherStart, nThisStart );
631                 if ( RES_TXTATR_CHARFMT == pOther->Which() )
632                     static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
633                 aInsDelHints.push_back( pNewAttr );
634 
635                 NoteInHistory( pOther );
636                 *pOther->GetStart() = nThisStart;
637                 NoteInHistory( pOther, true );
638 
639                 nOtherStart = nThisStart;
640             }
641 
642             // Check if end of new attribute overlaps with pOther:
643             // Split pOther if necessary:
644             if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
645             {
646                 SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
647                         pOther->GetAttr(), nOtherStart, nThisEnd );
648                 if ( RES_TXTATR_CHARFMT == pOther->Which() )
649                     static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
650                 aInsDelHints.push_back( pNewAttr );
651 
652                 NoteInHistory( pOther );
653                 *pOther->GetStart() = nThisEnd;
654                 NoteInHistory( pOther, true );
655             }
656         }
657 
658         // Insert the newly created attributes:
659         for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
660         {
661             SwpHintsArray::Insert( *aIter );
662             NoteInHistory( *aIter, true );
663         }
664     }
665 
666 #ifdef DBG_UTIL
667     if( !rNode.GetDoc()->IsInReading() )
668         CHECK;
669 #endif
670 
671     //
672     // 4. Split rNewHint into 1 ... n new hints:
673     //
674     std::set<xub_StrLen> aBounds;
675     aBounds.insert( nThisStart );
676     aBounds.insert( nThisEnd );
677 
678     if ( !bNoLengthAttribute ) // nothing to do for no length attributes
679     {
680         for ( sal_uInt16 i = 0; i < Count(); ++i )
681         {
682             const SwTxtAttr* pOther = GetTextHint(i);
683 
684             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
685                  RES_TXTATR_AUTOFMT != pOther->Which() )
686                 continue;
687 
688             const xub_StrLen nOtherStart = *pOther->GetStart();
689             const xub_StrLen nOtherEnd = *pOther->End();
690 
691             aBounds.insert( nOtherStart );
692             aBounds.insert( nOtherEnd );
693         }
694     }
695 
696     std::set<xub_StrLen>::iterator aStartIter = aBounds.lower_bound( nThisStart );
697     std::set<xub_StrLen>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
698     xub_StrLen nPorStart = *aStartIter;
699     ++aStartIter;
700     bool bDestroyHint = true;
701 
702     //
703     // Insert the 1...n new parts of the new attribute:
704     //
705     while ( aStartIter != aEndIter || bNoLengthAttribute )
706     {
707         ASSERT( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" )
708 
709         const xub_StrLen nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
710         aInsDelHints.clear();
711 
712         // Get all hints that are in [nPorStart, nPorEnd[:
713         for ( sal_uInt16 i = 0; i < Count(); ++i )
714         {
715             SwTxtAttr *pOther = GetTextHint(i);
716 
717             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
718                  RES_TXTATR_AUTOFMT != pOther->Which() )
719                 continue;
720 
721             const xub_StrLen nOtherStart = *pOther->GetStart();
722 
723             if ( nOtherStart > nPorStart )
724                 break;
725 
726             if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
727             {
728                 ASSERT( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" )
729                 aInsDelHints.push_back( pOther );
730             }
731         }
732 
733         SwTxtAttr* pNewAttr = 0;
734         if ( RES_TXTATR_CHARFMT == nWhich )
735         {
736             // pNewHint can be inserted after calculating the sort value.
737             // This should ensure, that pNewHint comes behind the already present
738             // character style
739             sal_uInt16 nCharStyleCount = 0;
740             aIter = aInsDelHints.begin();
741             while ( aIter != aInsDelHints.end() )
742             {
743                 if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
744                 {
745                     // --> FME 2007-02-16 #i74589#
746                     const SwFmtCharFmt& rOtherCharFmt = (*aIter)->GetCharFmt();
747                     const SwFmtCharFmt& rThisCharFmt = rNewHint.GetCharFmt();
748                     const bool bSameCharFmt = rOtherCharFmt.GetCharFmt() == rThisCharFmt.GetCharFmt();
749                     // <--
750 
751                     // --> OD 2009-03-24 #i90311#
752                     // Do not remove existing character format hint during XML import
753                     if ( !rNode.GetDoc()->IsInXMLImport() &&
754                          ( !( nsSetAttrMode::SETATTR_DONTREPLACE & nMode ) ||
755                            bNoLengthAttribute ||
756                            bSameCharFmt ) )
757                     // <--
758                     {
759                         // Remove old hint
760                         Delete( *aIter );
761                         rNode.DestroyAttr( *aIter );
762                     }
763                     else
764                         ++nCharStyleCount;
765                 }
766                 else
767                 {
768                     // remove all attributes from auto styles, which are explicitely set in
769                     // the new character format:
770                     ASSERT( RES_TXTATR_AUTOFMT == (*aIter)->Which(), "AUTOSTYLES - Misc trouble" )
771                     SwTxtAttr* pOther = *aIter;
772                     boost::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFmtAutoFmt&>(pOther->GetAttr()).GetStyleHandle();
773 
774                     // For each attribute in the automatic style check if it
775                     // is also set the the new character style:
776                     SfxItemSet aNewSet( *pOldStyle->GetPool(),
777                         aCharAutoFmtSetRange);
778                     SfxItemIter aItemIter( *pOldStyle );
779                     const SfxPoolItem* pItem = aItemIter.GetCurItem();
780                     while( sal_True )
781                     {
782                         if ( !CharFmt::IsItemIncluded( pItem->Which(), &rNewHint ) )
783                         {
784                             aNewSet.Put( *pItem );
785                         }
786 
787                         if( aItemIter.IsAtEnd() )
788                             break;
789 
790                         pItem = aItemIter.NextItem();
791                     }
792 
793                     // Remove old hint
794                     Delete( pOther );
795                     rNode.DestroyAttr( pOther );
796 
797                     // Create new AutoStyle
798                     if ( aNewSet.Count() )
799                     {
800                         pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
801                                 aNewSet, nPorStart, nPorEnd );
802                         SwpHintsArray::Insert( pNewAttr );
803                         NoteInHistory( pNewAttr, true );
804                     }
805                 }
806                 ++aIter;
807             }
808 
809             // If there is no current hint and start and end of rNewHint
810             // is ok, we do not need to create a new txtattr.
811             if ( nPorStart == nThisStart &&
812                  nPorEnd == nThisEnd &&
813                  !nCharStyleCount )
814             {
815                 pNewAttr = &rNewHint;
816                 bDestroyHint = false;
817             }
818             else
819             {
820                 pNewAttr = MakeTxtAttr( *rNode.GetDoc(), rNewHint.GetAttr(),
821                         nPorStart, nPorEnd );
822                 static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( nCharStyleCount );
823             }
824         }
825         else
826         {
827             // Find the current autostyle. Mix attributes if necessary.
828             SwTxtAttr* pCurrentAutoStyle = 0;
829             SwTxtAttr* pCurrentCharFmt = 0;
830             aIter = aInsDelHints.begin();
831             while ( aIter != aInsDelHints.end() )
832             {
833                 if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
834                     pCurrentAutoStyle = *aIter;
835                 else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
836                     pCurrentCharFmt = *aIter;
837                 ++aIter;
838             }
839 
840             boost::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFmtAutoFmt&>(rNewHint.GetAttr()).GetStyleHandle();
841             if ( pCurrentAutoStyle )
842             {
843                 boost::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFmtAutoFmt&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
844 
845                 // Merge attributes
846                 SfxItemSet aNewSet( *pCurrentStyle );
847                 aNewSet.Put( *pNewStyle );
848 
849                 // --> FME 2007-4-11 #i75750# Remove attributes already set at whole paragraph
850                 // --> FME 2007-09-24 #i81764# This should not be applied for no length attributes!!! <--
851                 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
852                 {
853                     SfxItemIter aIter2( aNewSet );
854                     const SfxPoolItem* pItem = aIter2.GetCurItem();
855                     const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
856 
857                     do
858                     {
859                         const SfxPoolItem* pTmpItem = 0;
860                         if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) &&
861                              pTmpItem == pItem )
862                         {
863                             // Do not clear item if the attribute is set in a character format:
864                             if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
865                                 aNewSet.ClearItem( pItem->Which() );
866                         }
867                     }
868                     while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
869                 }
870                 // <--
871 
872                 // Remove old hint
873                 Delete( pCurrentAutoStyle );
874                 rNode.DestroyAttr( pCurrentAutoStyle );
875 
876                 // Create new AutoStyle
877                 if ( aNewSet.Count() )
878                     pNewAttr = MakeTxtAttr( *rNode.GetDoc(), aNewSet,
879                             nPorStart, nPorEnd );
880             }
881             else
882             {
883                 // Remove any attributes which are already set at the whole paragraph:
884                 bool bOptimizeAllowed = true;
885 
886                 SfxItemSet* pNewSet = 0;
887                 // --> FME 2007-4-11 #i75750# Remove attributes already set at whole paragraph
888                 // --> FME 2007-09-24 #i81764# This should not be applied for no length attributes!!! <--
889                 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
890                 {
891                     SfxItemIter aIter2( *pNewStyle );
892                     const SfxPoolItem* pItem = aIter2.GetCurItem();
893                     const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
894 
895                     do
896                     {
897                         const SfxPoolItem* pTmpItem = 0;
898                         if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) &&
899                              pTmpItem == pItem )
900                         {
901                             // Do not clear item if the attribute is set in a character format:
902                             if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
903                             {
904                                 if ( !pNewSet )
905                                     pNewSet = pNewStyle->Clone( sal_True );
906                                 pNewSet->ClearItem( pItem->Which() );
907                             }
908                         }
909                     }
910                     while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
911 
912                     if ( pNewSet )
913                     {
914                         bOptimizeAllowed = false;
915                         if ( pNewSet->Count() )
916                             pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
917                         else
918                             pNewStyle.reset();
919 
920                         delete pNewSet;
921                     }
922                 }
923                 // <--
924 
925                 // Create new AutoStyle
926                 // If there is no current hint and start and end of rNewHint
927                 // is ok, we do not need to create a new txtattr.
928                 if ( bOptimizeAllowed &&
929                      nPorStart == nThisStart &&
930                      nPorEnd == nThisEnd )
931                 {
932                     pNewAttr = &rNewHint;
933                     bDestroyHint = false;
934                 }
935                 else if ( pNewStyle.get() )
936                 {
937                     pNewAttr = MakeTxtAttr( *rNode.GetDoc(), *pNewStyle,
938                             nPorStart, nPorEnd );
939                 }
940             }
941         }
942 
943         if ( pNewAttr )
944         {
945             SwpHintsArray::Insert( pNewAttr );
946 //            if ( bDestroyHint )
947                 NoteInHistory( pNewAttr, true );
948         }
949 
950         if ( !bNoLengthAttribute )
951         {
952             nPorStart = *aStartIter;
953             ++aStartIter;
954         }
955         else
956             break;
957     }
958 
959     if ( bDestroyHint )
960         rNode.DestroyAttr( &rNewHint );
961 }
962 
963 /*************************************************************************
964  *						SwTxtNode::MakeTxtAttr()
965  *************************************************************************/
966 
967 SwTxtAttr* MakeRedlineTxtAttr( SwDoc & rDoc, SfxPoolItem & rAttr )
968 {
969     // this is intended _only_ for special-purpose redline attributes!
970     switch (rAttr.Which())
971     {
972         case RES_CHRATR_COLOR:
973         case RES_CHRATR_WEIGHT:
974         case RES_CHRATR_CJK_WEIGHT:
975         case RES_CHRATR_CTL_WEIGHT:
976         case RES_CHRATR_POSTURE:
977         case RES_CHRATR_CJK_POSTURE:
978         case RES_CHRATR_CTL_POSTURE:
979         case RES_CHRATR_UNDERLINE:
980         case RES_CHRATR_CROSSEDOUT:
981         case RES_CHRATR_CASEMAP:
982         case RES_CHRATR_BACKGROUND:
983             break;
984         default:
985             ASSERT(false, "unsupported redline attribute");
986             break;
987     }
988 
989     // Put new attribute into pool
990     // FIXME: this const_cast is evil!
991     SfxPoolItem& rNew =
992         const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
993     return new SwTxtAttrEnd( rNew, 0, 0 );
994 }
995 
996 // create new text attribute
997 SwTxtAttr* MakeTxtAttr(
998     SwDoc & rDoc,
999     SfxPoolItem& rAttr,
1000     xub_StrLen const nStt,
1001     xub_StrLen const nEnd,
1002     CopyOrNew_t const bIsCopy,
1003     SwTxtNode *const pTxtNode )
1004 {
1005     if ( isCHRATR(rAttr.Which()) )
1006     {
1007         // Somebody wants to build a SwTxtAttr for a character attribute.
1008         // Sorry, this is not allowed any longer.
1009         // You'll get a brand new autostyle attribute:
1010         SfxItemSet aItemSet( rDoc.GetAttrPool(),
1011                 RES_CHRATR_BEGIN, RES_CHRATR_END );
1012         aItemSet.Put( rAttr );
1013         return MakeTxtAttr( rDoc, aItemSet, nStt, nEnd );
1014     }
1015     else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
1016               static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()->
1017                 GetPool() != &rDoc.GetAttrPool() )
1018     {
1019         // If the attribute is an auto-style which refers to a pool that is
1020         // different from rDoc's pool, we have to correct this:
1021         const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle();
1022         ::std::auto_ptr<const SfxItemSet> pNewSet(
1023                 pAutoStyle->SfxItemSet::Clone( sal_True, &rDoc.GetAttrPool() ));
1024         SwTxtAttr* pNew = MakeTxtAttr( rDoc, *pNewSet, nStt, nEnd );
1025         return pNew;
1026     }
1027 
1028     // Put new attribute into pool
1029     // FIXME: this const_cast is evil!
1030     SfxPoolItem& rNew =
1031         const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
1032 
1033 	SwTxtAttr* pNew = 0;
1034 	switch( rNew.Which() )
1035 	{
1036     case RES_TXTATR_CHARFMT:
1037 		{
1038 			SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
1039 			if( !rFmtCharFmt.GetCharFmt() )
1040             {
1041                 rFmtCharFmt.SetCharFmt( rDoc.GetDfltCharFmt() );
1042             }
1043 
1044 			pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
1045 		}
1046 		break;
1047 	case RES_TXTATR_INETFMT:
1048 		pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
1049 		break;
1050 
1051     case RES_TXTATR_FIELD:
1052         pNew = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt );
1053         break;
1054 
1055     case RES_TXTATR_ANNOTATION:
1056         {
1057             pNew = new SwTxtAnnotationFld( static_cast<SwFmtFld &>(rNew), nStt );
1058             if ( bIsCopy == COPY )
1059             {
1060                 // On copy of the annotation field do not keep the annotated text range by removing
1061                 // the relation to its annotation mark (relation established via annotation field's name).
1062                 // If the annotation mark is also copied, the relation and thus the annotated text range will be reestablished,
1063                 // when the annotation mark is created and inserted into the document.
1064                 const_cast<SwPostItField*>(dynamic_cast< const SwPostItField* >(pNew->GetFmtFld().GetField()))->SetName( String() );
1065             }
1066         }
1067         break;
1068 
1069     case RES_TXTATR_INPUTFIELD:
1070         pNew = new SwTxtInputFld( static_cast<SwFmtFld &>(rNew), nStt, nEnd );
1071         break;
1072 
1073 	case RES_TXTATR_FLYCNT:
1074 		{
1075 			// erst hier wird das Frame-Format kopiert (mit Inhalt) !!
1076 			pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
1077 			// Kopie von einem Text-Attribut
1078             if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() )
1079             {
1080                 // then the format must be copied
1081                 static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc );
1082             }
1083         }
1084         break;
1085 	case RES_TXTATR_FTN:
1086 		pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
1087 		// ggfs. SeqNo kopieren
1088 		if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
1089 			((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
1090 		break;
1091 	case RES_TXTATR_REFMARK:
1092 		pNew = nStt == nEnd
1093 				? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
1094 				: new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
1095 		break;
1096 	case RES_TXTATR_TOXMARK:
1097 		pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd );
1098 		break;
1099 	case RES_TXTATR_CJK_RUBY:
1100 		pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd );
1101 		break;
1102     case RES_TXTATR_META:
1103     case RES_TXTATR_METAFIELD:
1104         pNew = SwTxtMeta::CreateTxtMeta( rDoc.GetMetaFieldManager(), pTxtNode,
1105                 static_cast<SwFmtMeta&>(rNew), nStt, nEnd, bIsCopy );
1106         break;
1107     default:
1108         ASSERT(RES_TXTATR_AUTOFMT == rNew.Which(), "unknown attribute");
1109         pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
1110         break;
1111     }
1112 
1113     return pNew;
1114 }
1115 
1116 SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet,
1117                         xub_StrLen nStt, xub_StrLen nEnd )
1118 {
1119     IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
1120     const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
1121     SwFmtAutoFmt aNewAutoFmt;
1122     aNewAutoFmt.SetStyleHandle( pAutoStyle );
1123     SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd );
1124     return pNew;
1125 }
1126 
1127 
1128 // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
1129 void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
1130 {
1131 	if( pAttr )
1132 	{
1133 		// einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
1134 		SwDoc* pDoc = GetDoc();
1135 		sal_uInt16 nDelMsg = 0;
1136 		switch( pAttr->Which() )
1137 		{
1138 		case RES_TXTATR_FLYCNT:
1139 			{
1140 				// siehe auch die Anmerkung "Loeschen von Formaten
1141 				// zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFmt()
1142 				SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1143 				if( pFmt )		// vom Undo auf 0 gesetzt ??
1144 					pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt );
1145 			}
1146 			break;
1147 
1148         case RES_CHRATR_HIDDEN:
1149             SetCalcHiddenCharFlags();
1150             break;
1151 
1152 		case RES_TXTATR_FTN:
1153 			((SwTxtFtn*)pAttr)->SetStartNode( 0 );
1154 			nDelMsg = RES_FOOTNOTE_DELETED;
1155 			break;
1156 
1157 		case RES_TXTATR_FIELD:
1158 		case RES_TXTATR_ANNOTATION:
1159 		case RES_TXTATR_INPUTFIELD:
1160 			if( !pDoc->IsInDtor() )
1161 			{
1162 				// Wenn wir ein HiddenParaField sind, dann muessen wir
1163 				// ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
1164 				const SwField* pFld = pAttr->GetFmtFld().GetField();
1165 
1166 				//JP 06-08-95: DDE-Felder bilden eine Ausnahme
1167 				ASSERT( RES_DDEFLD == pFld->GetTyp()->Which() ||
1168 						this == ((SwTxtFld*)pAttr)->GetpTxtNode(),
1169 						"Wo steht denn dieses Feld?" )
1170 
1171 				// bestimmte Felder mussen am Doc das Calculations-Flag updaten
1172 				switch( pFld->GetTyp()->Which() )
1173 				{
1174 				case RES_HIDDENPARAFLD:
1175                     SetCalcHiddenParaField();
1176 					// kein break !
1177 				case RES_DBSETNUMBERFLD:
1178 				case RES_GETEXPFLD:
1179 				case RES_DBFLD:
1180 				case RES_SETEXPFLD:
1181 				case RES_HIDDENTXTFLD:
1182 				case RES_DBNUMSETFLD:
1183 				case RES_DBNEXTSETFLD:
1184 					if( !pDoc->IsNewFldLst() && GetNodes().IsDocNodes() )
1185 						pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pAttr );
1186 					break;
1187 				case RES_DDEFLD:
1188 					if( GetNodes().IsDocNodes() &&
1189 						((SwTxtFld*)pAttr)->GetpTxtNode() )
1190 						((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt();
1191 					break;
1192 				case RES_POSTITFLD:
1193 					{
1194 						const_cast<SwFmtFld&>(pAttr->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFmtFld(), SWFMTFLD_REMOVED ) );
1195 						break;
1196 					}
1197 				}
1198 			}
1199 			nDelMsg = RES_FIELD_DELETED;
1200 			break;
1201 
1202 		case RES_TXTATR_TOXMARK:
1203             static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
1204 			break;
1205 
1206 		case RES_TXTATR_REFMARK:
1207 			nDelMsg = RES_REFMARK_DELETED;
1208 			break;
1209 
1210         case RES_TXTATR_META:
1211         case RES_TXTATR_METAFIELD:
1212             static_cast<SwTxtMeta*>(pAttr)->ChgTxtNode(0);
1213             break;
1214 
1215         default:
1216             break;
1217 		}
1218 
1219 		if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() )
1220 		{
1221 			SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() );
1222 			pDoc->GetUnoCallBack()->ModifyNotification( &aMsgHint, &aMsgHint );
1223 		}
1224 
1225         SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() );
1226     }
1227 }
1228 
1229 /*************************************************************************
1230  *						SwTxtNode::Insert()
1231  *************************************************************************/
1232 
1233 SwTxtAttr* SwTxtNode::InsertItem(
1234     SfxPoolItem& rAttr,
1235     const xub_StrLen nStart,
1236     const xub_StrLen nEnd,
1237     const SetAttrMode nMode )
1238 {
1239    // character attributes will be inserted as automatic styles:
1240     ASSERT( !isCHRATR(rAttr.Which()), "AUTOSTYLES - "
1241         "SwTxtNode::InsertItem should not be called with character attributes");
1242 
1243     SwTxtAttr *const pNew =
1244         MakeTxtAttr(
1245             *GetDoc(),
1246             rAttr,
1247             nStart,
1248             nEnd,
1249             (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW,
1250             this );
1251 
1252     if ( pNew )
1253     {
1254         const bool bSuccess( InsertHint( pNew, nMode ) );
1255         // N.B.: also check that the hint is actually in the hints array,
1256         // because hints of certain types may be merged after successful
1257         // insertion, and thus destroyed!
1258         if (!bSuccess || ( USHRT_MAX == m_pSwpHints->GetPos( pNew ) ))
1259         {
1260             return 0;
1261         }
1262     }
1263 
1264     return pNew;
1265 }
1266 
1267 // take ownership of pAttr; if insertion fails, delete pAttr
1268 bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode )
1269 {
1270     bool bHiddenPara = false;
1271 
1272     ASSERT( pAttr && *pAttr->GetStart() <= Len(), "StartIdx out of bounds!" );
1273     ASSERT( !pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()),
1274             "EndIdx out of bounds!" );
1275 
1276     // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR)
1277     const enum IDocumentContentOperations::InsertFlags nInsertFlags =
1278         (nMode & nsSetAttrMode::SETATTR_FORCEHINTEXPAND)
1279         ? static_cast<IDocumentContentOperations::InsertFlags>(
1280                 IDocumentContentOperations::INS_FORCEHINTEXPAND |
1281                 IDocumentContentOperations::INS_EMPTYEXPAND)
1282         : IDocumentContentOperations::INS_EMPTYEXPAND;
1283 
1284     // need this after TryInsertHint, when pAttr may be deleted
1285     const xub_StrLen nStart( *pAttr->GetStart() );
1286     const bool bDummyChar( pAttr->HasDummyChar() );
1287     if (bDummyChar)
1288     {
1289         sal_uInt16 nInsMode = nMode;
1290         switch( pAttr->Which() )
1291         {
1292         case RES_TXTATR_FLYCNT:
1293             {
1294                 SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
1295                 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1296                 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1297                 {
1298                     // Wir muessen zuerst einfuegen, da in SetAnchor()
1299                     // dem FlyFrm GetStart() uebermittelt wird.
1300                     //JP 11.05.98: falls das Anker-Attribut schon richtig
1301                     // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
1302                     // des Zeichens. Sonst muesste das immer  ausserhalb
1303                     // erfolgen (Fehleranfaellig !)
1304                     const SwFmtAnchor* pAnchor = 0;
1305                     pFmt->GetItemState( RES_ANCHOR, sal_False,
1306                         (const SfxPoolItem**)&pAnchor );
1307 
1308                     SwIndex aIdx( this, *pAttr->GetStart() );
1309                     const sal_Unicode c = GetCharOfTxtAttr(*pAttr);
1310                     InsertText( c, aIdx, nInsertFlags );
1311                     nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1312 
1313                     if (pAnchor &&
1314                         (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
1315                         pAnchor->GetCntntAnchor() &&
1316                         pAnchor->GetCntntAnchor()->nNode == *this &&
1317                         pAnchor->GetCntntAnchor()->nContent == aIdx )
1318                     {
1319                         const_cast<SwIndex&>(
1320                             pAnchor->GetCntntAnchor()->nContent)--;
1321                     }
1322                 }
1323                 pFly->SetAnchor( this );
1324 
1325                 // Format-Pointer kann sich im SetAnchor geaendert haben!
1326                 // (Kopieren in andere Docs!)
1327                 pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1328                 SwDoc *pDoc = pFmt->GetDoc();
1329 
1330                 // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
1331                 // But don't allow control objects in header/footer
1332                 if( RES_DRAWFRMFMT == pFmt->Which() &&
1333                     pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) )
1334                 {
1335                     SwDrawContact* pDrawContact =
1336                         static_cast<SwDrawContact*>(pFmt->FindContactObj());
1337                     if ( pDrawContact &&
1338                          pDrawContact->GetMaster() &&
1339                          ::CheckControlLayer( pDrawContact->GetMaster() ) )
1340                     {
1341                         // das soll nicht meoglich sein; hier verhindern
1342                         // Der Dtor des TxtHints loescht nicht das Zeichen.
1343                         // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1344                         // dieses explizit loeschen
1345                         if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1346                         {
1347                             // loesche das Zeichen aus dem String !
1348                             ASSERT( ( CH_TXTATR_BREAKWORD ==
1349                                         m_Text.GetChar(*pAttr->GetStart() ) ||
1350                                       CH_TXTATR_INWORD ==
1351                                         m_Text.GetChar(*pAttr->GetStart())),
1352                                     "where is my attribute character?" );
1353                             m_Text.Erase( *pAttr->GetStart(), 1 );
1354                             // Indizies Updaten
1355                             SwIndex aTmpIdx( this, *pAttr->GetStart() );
1356                             Update( aTmpIdx, 1, sal_True );
1357                         }
1358                         // do not record deletion of Format!
1359                         ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1360                         DestroyAttr( pAttr );
1361                         return false;
1362                     }
1363                 }
1364                 break;
1365             }
1366 
1367         case RES_TXTATR_FTN :
1368             {
1369                 // Fussnoten, man kommt an alles irgendwie heran.
1370                 // CntntNode erzeugen und in die Inserts-Section stellen
1371                 SwDoc *pDoc = GetDoc();
1372                 SwNodes &rNodes = pDoc->GetNodes();
1373 
1374                 // FussNote in nicht Content-/Redline-Bereich einfuegen ??
1375                 if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
1376                 {
1377                     // das soll nicht meoglich sein; hier verhindern
1378                     // Der Dtor des TxtHints loescht nicht das Zeichen.
1379                     // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1380                     // dieses explizit loeschen
1381                     if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1382                     {
1383                         // loesche das Zeichen aus dem String !
1384                         ASSERT( ( CH_TXTATR_BREAKWORD ==
1385                             m_Text.GetChar(*pAttr->GetStart() ) ||
1386                             CH_TXTATR_INWORD ==
1387                             m_Text.GetChar(*pAttr->GetStart())),
1388                             "where is my attribute character?" );
1389                         m_Text.Erase( *pAttr->GetStart(), 1 );
1390                         // Indizies Updaten
1391                         SwIndex aTmpIdx( this, *pAttr->GetStart() );
1392                         Update( aTmpIdx, 1, sal_True );
1393                     }
1394                     DestroyAttr( pAttr );
1395                     return false;
1396                 }
1397 
1398                 // wird eine neue Fussnote eingefuegt ??
1399                 sal_Bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
1400                 if( bNewFtn )
1401                 {
1402                     ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
1403                     SwRegHistory* pHist = GetpSwpHints()
1404                         ? GetpSwpHints()->GetHistory() : 0;
1405                     if( pHist )
1406                         pHist->ChangeNodeIndex( GetIndex() );
1407                 }
1408                 else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
1409                 {
1410                     // loesche alle Frames der Section, auf die der StartNode zeigt
1411                     sal_uLong nSttIdx =
1412                         ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex();
1413                     sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
1414                     SwCntntNode* pCNd;
1415                     for( ; nSttIdx < nEndIdx; ++nSttIdx )
1416                         if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() ))
1417                             pCNd->DelFrms();
1418                 }
1419 
1420                 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1421                 {
1422                     // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
1423                     // entstehen koennen und das Attribut im _SortArr_ am
1424                     // Dokument nicht eingetrage wird.
1425                     SwIndex aNdIdx( this, *pAttr->GetStart() );
1426                     const sal_Unicode c = GetCharOfTxtAttr(*pAttr);
1427                     InsertText( c, aNdIdx, nInsertFlags );
1428                     nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1429                 }
1430 
1431                 // Wir tragen uns am FtnIdx-Array des Docs ein ...
1432                 SwTxtFtn* pTxtFtn = 0;
1433                 if( !bNewFtn )
1434                 {
1435                     // eine alte Ftn wird umgehaengt (z.B. SplitNode)
1436                     for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().Count(); ++n )
1437                         if( pAttr == pDoc->GetFtnIdxs()[n] )
1438                         {
1439                             // neuen Index zuweisen, dafuer aus dem SortArray
1440                             // loeschen und neu eintragen
1441                             pTxtFtn = pDoc->GetFtnIdxs()[n];
1442                             pDoc->GetFtnIdxs().Remove( n );
1443                             break;
1444                         }
1445                         // wenn ueber Undo der StartNode gesetzt wurde, kann
1446                         // der Index noch gar nicht in der Verwaltung stehen !!
1447                 }
1448                 if( !pTxtFtn )
1449                     pTxtFtn = (SwTxtFtn*)pAttr;
1450 
1451                 // fuers Update der Nummern und zum Sortieren
1452                 // muss der Node gesetzt sein.
1453                 ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
1454 
1455                 // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
1456                 if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
1457                 {
1458 #ifdef DBG_UTIL
1459                     const sal_Bool bSuccess =
1460 #endif
1461                         pDoc->GetFtnIdxs().Insert( pTxtFtn );
1462 #ifdef DBG_UTIL
1463                     ASSERT( bSuccess, "FtnIdx nicht eingetragen." );
1464 #endif
1465                 }
1466                 SwNodeIndex aTmpIndex( *this );
1467                 pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
1468                 ((SwTxtFtn*)pAttr)->SetSeqRefNo();
1469             }
1470             break;
1471 
1472             case RES_TXTATR_FIELD:
1473                 {
1474                     // fuer HiddenParaFields Benachrichtigungsmechanismus
1475                     // anwerfen
1476                     if( RES_HIDDENPARAFLD == pAttr->GetFmtFld().GetField()->GetTyp()->Which() )
1477                     {
1478                         bHiddenPara = true;
1479                     }
1480                 }
1481                 break;
1482 
1483         }
1484         // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_..
1485         // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
1486         // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits
1487         // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
1488         if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1489         {
1490             SwIndex aIdx( this, *pAttr->GetStart() );
1491             InsertText( GetCharOfTxtAttr(*pAttr), aIdx, nInsertFlags );
1492 
1493             // adjust end of hint to account for inserted CH_TXTATR
1494             xub_StrLen * const pEnd(pAttr->GetEnd());
1495             if (pEnd)
1496             {
1497                 *pEnd = *pEnd + 1;
1498             }
1499         }
1500     }
1501 
1502     // handle attributes which provide content
1503     xub_StrLen nEnd = nStart;
1504     bool bInputFieldStartCharInserted = false;
1505     bool bInputFieldEndCharInserted = false;
1506     const bool bHasContent( pAttr->HasContent() );
1507     if ( bHasContent )
1508     {
1509         switch( pAttr->Which() )
1510         {
1511         case RES_TXTATR_INPUTFIELD:
1512             {
1513                 SwTxtInputFld* pTxtInputFld = dynamic_cast<SwTxtInputFld*>(pAttr);
1514                 if ( pTxtInputFld )
1515                 {
1516                     if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
1517                     {
1518                         SwIndex aIdx( this, *pAttr->GetStart() );
1519                         InsertText( CH_TXT_ATR_INPUTFIELDSTART, aIdx, nInsertFlags );
1520                         const String aContent = pTxtInputFld->GetFieldContent();
1521                         InsertText( aContent, aIdx, nInsertFlags );
1522                         InsertText( CH_TXT_ATR_INPUTFIELDEND, aIdx, nInsertFlags );
1523 
1524                         xub_StrLen * const pEnd(pAttr->GetEnd());
1525                         ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1526                         if ( pEnd != NULL )
1527                         {
1528                             *pEnd = *pEnd + 2 + aContent.Len();
1529                             nEnd = *pEnd;
1530                         }
1531                     }
1532                     else
1533                     {
1534                         // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted.
1535                         if ( m_Text.GetChar( *(pAttr->GetStart()) ) != CH_TXT_ATR_INPUTFIELDSTART )
1536                         {
1537                             SwIndex aIdx( this, *pAttr->GetStart() );
1538                             InsertText( CH_TXT_ATR_INPUTFIELDSTART, aIdx, nInsertFlags );
1539                             bInputFieldStartCharInserted = true;
1540                             xub_StrLen * const pEnd(pAttr->GetEnd());
1541                             ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1542                             if ( pEnd != NULL )
1543                             {
1544                                 *pEnd = *pEnd + 1;
1545                                 nEnd = *pEnd;
1546                             }
1547                         }
1548 
1549                         xub_StrLen * const pEnd(pAttr->GetEnd());
1550                         ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1551                         if ( pEnd != NULL
1552                              && m_Text.GetChar( *(pEnd) - 1 ) != CH_TXT_ATR_INPUTFIELDEND )
1553                         {
1554                             SwIndex aIdx( this, *(pEnd) );
1555                             InsertText( CH_TXT_ATR_INPUTFIELDEND, aIdx, nInsertFlags );
1556                             bInputFieldEndCharInserted = true;
1557                             *pEnd = *pEnd + 1;
1558                             nEnd = *pEnd;
1559                         }
1560                     }
1561                 }
1562             }
1563             break;
1564         default:
1565             break;
1566         }
1567     }
1568 
1569     GetOrCreateSwpHints();
1570 
1571     // handle overlap with an existing InputField
1572     bool bInsertHint = true;
1573     {
1574         const SwTxtInputFld* pTxtInputFld = GetOverlappingInputFld( *pAttr );
1575         if ( pTxtInputFld != NULL )
1576         {
1577             if ( pAttr->End() == NULL )
1578             {
1579                 bInsertHint = false;
1580             }
1581             else
1582             {
1583                 if ( *(pAttr->GetStart()) > *(pTxtInputFld->GetStart()) )
1584                 {
1585                     *(pAttr->GetStart()) = *(pTxtInputFld->GetStart());
1586                 }
1587                 if ( *(pAttr->End()) < *(pTxtInputFld->End()) )
1588                 {
1589                     *(pAttr->GetEnd()) = *(pTxtInputFld->End());
1590                 }
1591             }
1592         }
1593     }
1594 
1595     // 4263: AttrInsert durch TextInsert => kein Adjust
1596     const bool bRet = bInsertHint
1597                       ? m_pSwpHints->TryInsertHint( pAttr, *this, nMode )
1598                       : false;
1599 
1600     if ( !bRet )
1601     {
1602         if ( bDummyChar
1603              && !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
1604         {
1605             // undo insertion of dummy character
1606             // N.B. cannot insert the dummy character after inserting the hint,
1607             // because if the hint has no extent it will be moved in InsertText,
1608             // resulting in infinite recursion
1609             ASSERT( ( CH_TXTATR_BREAKWORD == m_Text.GetChar(nStart) ||
1610                 CH_TXTATR_INWORD    == m_Text.GetChar(nStart) ),
1611                 "where is my attribute character?" );
1612             SwIndex aIdx( this, nStart );
1613             EraseText( aIdx, 1 );
1614         }
1615 
1616         if ( bHasContent )
1617         {
1618             if ( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode)
1619                  && (nEnd - nStart) > 0 )
1620             {
1621                 SwIndex aIdx( this, nStart );
1622                 EraseText( aIdx, (nEnd - nStart) );
1623             }
1624             else
1625             {
1626                 if ( bInputFieldEndCharInserted
1627                      && (nEnd - nStart) > 0 )
1628                 {
1629                     SwIndex aIdx( this, nEnd - 1 );
1630                     EraseText( aIdx, 1 );
1631                 }
1632 
1633                 if ( bInputFieldStartCharInserted )
1634                 {
1635                     SwIndex aIdx( this, nStart );
1636                     EraseText( aIdx, 1 );
1637                 }
1638             }
1639         }
1640     }
1641 
1642     if ( bHiddenPara )
1643     {
1644         SetCalcHiddenParaField();
1645     }
1646 
1647     return bRet;
1648 }
1649 
1650 
1651 /*************************************************************************
1652  *                        SwTxtNode::DeleteAttribute()
1653  *************************************************************************/
1654 
1655 void SwTxtNode::DeleteAttribute( SwTxtAttr * const pAttr )
1656 {
1657     if ( !HasHints() )
1658     {
1659         ASSERT(false, "DeleteAttribute called, but text node without hints?");
1660         return;
1661     }
1662 
1663     if ( pAttr->HasDummyChar() )
1664     {
1665         // Unbedingt Copy-konstruieren!
1666         const SwIndex aIdx( this, *pAttr->GetStart() );
1667         // erase the CH_TXTATR, which will also delete pAttr
1668         EraseText( aIdx, 1 );
1669     }
1670     else if ( pAttr->HasContent() )
1671     {
1672         const SwIndex aIdx( this, *pAttr->GetStart() );
1673         ASSERT( pAttr->End() != NULL, "<SwTxtNode::DeleteAttribute(..)> - missing End() at <SwTxtAttr> instance which has content" );
1674         EraseText( aIdx, *pAttr->End() - *pAttr->GetStart() );
1675     }
1676     else
1677     {
1678         // create MsgHint before start/end become invalid
1679         SwUpdateAttr aHint(
1680             *pAttr->GetStart(),
1681             *pAttr->GetEnd(),
1682             pAttr->Which());
1683 
1684         m_pSwpHints->Delete( pAttr );
1685         SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
1686         NotifyClients( 0, &aHint );
1687 
1688         TryDeleteSwpHints();
1689     }
1690 }
1691 
1692 /*************************************************************************
1693  *                        SwTxtNode::DeleteAttributes()
1694  *************************************************************************/
1695 
1696 //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
1697 void SwTxtNode::DeleteAttributes(
1698     const sal_uInt16 nWhich,
1699     const xub_StrLen nStart,
1700     const xub_StrLen nEnd )
1701 {
1702     if ( !HasHints() )
1703         return;
1704 
1705     for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ )
1706     {
1707         SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos );
1708         const xub_StrLen nHintStart = *(pTxtHt->GetStart());
1709         if (nStart < nHintStart)
1710         {
1711             break; // sorted by start
1712         }
1713         else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) )
1714         {
1715             if ( nWhich == RES_CHRATR_HIDDEN  )
1716             {
1717                 ASSERT(false, "hey, that's a CHRATR! how did that get in?");
1718                 SetCalcHiddenCharFlags();
1719             }
1720             else if ( nWhich == RES_TXTATR_CHARFMT )
1721             {
1722                 // Check if character format contains hidden attribute:
1723                 const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt();
1724                 const SfxPoolItem* pItem;
1725                 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
1726                     SetCalcHiddenCharFlags();
1727             }
1728             // Recalc hidden flags if necessary
1729             else if ( nWhich == RES_TXTATR_AUTOFMT )
1730             {
1731                 // Check if auto style contains hidden attribute:
1732                 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
1733                 if ( pHiddenItem )
1734                     SetCalcHiddenCharFlags();
1735             }
1736 
1737             xub_StrLen const * const pEndIdx = pTxtHt->GetEnd();
1738 
1739             if ( pTxtHt->HasDummyChar() )
1740             {
1741                 // Unbedingt Copy-konstruieren!
1742                 const SwIndex aIdx( this, nStart );
1743                 // erase the CH_TXTATR, which will also delete pTxtHt
1744                 EraseText( aIdx, 1 );
1745             }
1746             else if ( pTxtHt->HasContent() )
1747             {
1748                 const SwIndex aIdx( this, nStart );
1749                 ASSERT( pTxtHt->End() != NULL, "<SwTxtNode::DeleteAttributes(..)> - missing End() at <SwTxtAttr> instance which has content" );
1750                 EraseText( aIdx, *pTxtHt->End() - nStart );
1751             }
1752             else if( *pEndIdx == nEnd )
1753             {
1754                 // den MsgHint jetzt fuettern, weil gleich sind
1755                 // Start und End weg.
1756                 // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
1757                 // da dies das Feld im Dtor selbst erledigt.
1758                 SwUpdateAttr aHint(
1759                     nStart,
1760                     *pEndIdx,
1761                     nWhich);
1762 
1763                 m_pSwpHints->DeleteAtPos( nPos );    // gefunden, loeschen,
1764                 SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() );
1765                 NotifyClients( 0, &aHint );
1766             }
1767         }
1768     }
1769     TryDeleteSwpHints();
1770 }
1771 
1772 /*************************************************************************
1773  *						SwTxtNode::DelSoftHyph()
1774  *************************************************************************/
1775 
1776 void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd )
1777 {
1778     xub_StrLen nFndPos = nStt, nEndPos = nEnd;
1779 	while( STRING_NOTFOUND !=
1780             ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) &&
1781 			nFndPos < nEndPos )
1782 	{
1783 		const SwIndex aIdx( this, nFndPos );
1784         EraseText( aIdx, 1 );
1785 		--nEndPos;
1786 	}
1787 }
1788 
1789 //Modify here for #119405, by easyfan, 2012-05-24
1790 //In MS Word, the font underline setting of the paragraph end position wont affect the formatting of numbering, so we ignore it
1791 bool lcl_IsIgnoredCharFmtForNumbering(const sal_uInt16 nWhich)
1792 {
1793 	return (nWhich ==  RES_CHRATR_UNDERLINE);
1794 }
1795 
1796 //In MS Word, following properties of the paragraph end position wont affect the formatting of bullets, so we ignore them:
1797 //Font underline;
1798 //Font Italic of Western, CJK and CTL;
1799 //Font Bold of Wertern, CJK and CTL;
1800 bool lcl_IsIgnoredCharFmtForBullets(const sal_uInt16 nWhich)
1801 {
1802 	return (nWhich ==  RES_CHRATR_UNDERLINE || nWhich ==  RES_CHRATR_POSTURE || nWhich ==  RES_CHRATR_WEIGHT
1803 		|| nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT
1804 		|| nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT);
1805 }
1806 
1807 //Condition for expanding char set to character style of specified number rule level:
1808 //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwCntntNode::SwPAttrSet);
1809 //The node should have applied a number rule;
1810 //The node should be counted in a list, if not, make it to be;
1811 //The item should not conflict to any exist and non-default item inside the character of specified number rule level;
1812 //The item should not be ignored depend on the exact number rule type;
1813 bool SwTxtNode::TryCharSetExpandToNum(const SfxItemSet& aCharSet)
1814 {
1815 	bool bRet = false;
1816 	SfxItemIter aIter( aCharSet );
1817         const SfxPoolItem* pItem = aIter.FirstItem();
1818         const sal_uInt16 nWhich = pItem->Which();
1819 
1820 	const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
1821 
1822 	if (!IsDefaultItem(&rInnerItem) &&  !IsInvalidItem(&rInnerItem))
1823 		return bRet;
1824 
1825 	if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 )
1826 	{
1827 		return bRet;
1828 	}
1829 
1830 	SwNumRule* pCurrNum = GetNumRule(false);
1831 
1832 	int nLevel = GetActualListLevel();
1833 
1834 	if (nLevel != -1 && pCurrNum)
1835 	{
1836 		const SwNumFmt* pCurrNumFmt = pCurrNum->GetNumFmt(static_cast<sal_uInt16>(nLevel));
1837 		if (pCurrNumFmt)
1838 		{
1839 			if (pCurrNumFmt->IsItemize() && lcl_IsIgnoredCharFmtForBullets(nWhich))
1840 				return bRet;
1841 			if (pCurrNumFmt->IsEnumeration() && lcl_IsIgnoredCharFmtForNumbering(nWhich))
1842 				return bRet;
1843 			SwCharFmt* pCurrCharFmt =pCurrNumFmt->GetCharFmt();
1844 
1845 			if (pCurrCharFmt && pCurrCharFmt->GetItemState(nWhich,false) != SFX_ITEM_SET)
1846 			{
1847 				pCurrCharFmt->SetFmtAttr(*pItem);
1848 				SwNumFmt aNewNumFmt(*pCurrNumFmt);
1849 				aNewNumFmt.SetCharFmt(pCurrCharFmt);
1850 				pCurrNum->Set(nLevel,aNewNumFmt);
1851 				bRet = true;
1852 			}
1853 		}
1854 	}
1855 
1856 
1857 	return bRet;
1858 }
1859 //End of modification, by easyfan
1860 
1861 // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1862 // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
1863 sal_Bool SwTxtNode::SetAttr(
1864     const SfxItemSet& rSet,
1865     const xub_StrLen nStt,
1866     const xub_StrLen nEnd,
1867     const SetAttrMode nMode )
1868 {
1869 	if( !rSet.Count() )
1870 		return sal_False;
1871 
1872 	// teil die Sets auf (fuer Selektion in Nodes)
1873 	const SfxItemSet* pSet = &rSet;
1874 	SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1875 
1876 	// gesamter Bereich
1877     if ( !nStt && (nEnd == m_Text.Len()) &&
1878          !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
1879 	{
1880 		// sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1881 		// (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1882 		int bHasCharFmts = sal_False;
1883         if ( HasHints() )
1884         {
1885             for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
1886             {
1887                 if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
1888                 {
1889 					bHasCharFmts = sal_True;
1890 					break;
1891                 }
1892             }
1893         }
1894 
1895 		if( !bHasCharFmts )
1896 		{
1897             aTxtSet.Put( rSet );
1898             // If there are any character attributes in rSet,
1899             // we want to set them at the paragraph:
1900 			if( aTxtSet.Count() != rSet.Count() )
1901 			{
1902                 sal_Bool bRet = SetAttr( rSet );
1903           		if( !aTxtSet.Count() )
1904 		    		return bRet;
1905 			}
1906 
1907             // check for auto style:
1908             const SfxPoolItem* pItem;
1909             const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem );
1910             if ( bAutoStyle )
1911             {
1912                 boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
1913                 sal_Bool bRet = SetAttr( *pAutoStyleSet );
1914           		if( 1 == aTxtSet.Count() )
1915 		    		return bRet;
1916             }
1917 
1918             // Continue with the text attributes:
1919 			pSet = &aTxtSet;
1920 		}
1921 	}
1922 
1923     GetOrCreateSwpHints();
1924 
1925     SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
1926 
1927     sal_uInt16 nCount = 0;
1928 	SfxItemIter aIter( *pSet );
1929 	const SfxPoolItem* pItem = aIter.GetCurItem();
1930 
1931     do
1932     {
1933         if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1934         {
1935             const sal_uInt16 nWhich = pItem->Which();
1936             ASSERT( isCHRATR(nWhich) || isTXTATR(nWhich),
1937                     "SwTxtNode::SetAttr(): unknown attribute" );
1938             if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1939             {
1940                 if ((RES_TXTATR_CHARFMT == nWhich) &&
1941                     (GetDoc()->GetDfltCharFmt() ==
1942                      static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
1943                 {
1944                     SwIndex aIndex( this, nStt );
1945                     RstTxtAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1946                     DontExpandFmt( aIndex );
1947                 }
1948                 else
1949                 {
1950                     if (isCHRATR(nWhich) ||
1951                         (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1952                     {
1953                         aCharSet.Put( *pItem );
1954                     }
1955                     else
1956                     {
1957 
1958                         SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
1959                                 const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1960                         if ( pNew )
1961                         {
1962                             if ( nEnd != nStt && !pNew->GetEnd() )
1963                             {
1964                                 ASSERT(false,
1965                                     "Attribut without end, but area marked");
1966                                 DestroyAttr( pNew ); // do not insert
1967                             }
1968                             else if ( InsertHint( pNew, nMode ) )
1969                             {
1970                                 ++nCount;
1971                             }
1972                         }
1973                     }
1974                 }
1975             }
1976         }
1977         if ( aIter.IsAtEnd() )
1978             break;
1979         pItem = aIter.NextItem();
1980     } while( true );
1981 
1982     if ( aCharSet.Count() )
1983     {
1984         SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
1985         if ( InsertHint( pTmpNew, nMode ) )
1986         {
1987             ++nCount;
1988         }
1989     }
1990 
1991     TryDeleteSwpHints();
1992 
1993 	return nCount ? sal_True : sal_False;
1994 }
1995 
1996 void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1997 {
1998     if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
1999 	{
2000         const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
2001         if ( !pCFSet )
2002             return;
2003         SfxWhichIter aIter( *pCFSet );
2004         sal_uInt16 nWhich = aIter.FirstWhich();
2005         while( nWhich )
2006         {
2007             if( ( nWhich < RES_CHRATR_END ||
2008                   RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
2009                 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
2010                 rSet.Put( pCFSet->Get( nWhich ) );
2011             nWhich = aIter.NextWhich();
2012         }
2013     }
2014     else
2015     	rSet.Put( rAttr );
2016 }
2017 
2018 void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2019 {
2020 	if( RES_TXTATR_CHARFMT == rAttr.Which() ||
2021 		RES_TXTATR_INETFMT == rAttr.Which() ||
2022         RES_TXTATR_AUTOFMT == rAttr.Which() )
2023 	{
2024         const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
2025 
2026         if ( pCFSet )
2027         {
2028             SfxWhichIter aIter( *pCFSet );
2029             sal_uInt16 nWhich = aIter.FirstWhich();
2030             while( nWhich )
2031             {
2032                 if( ( nWhich < RES_CHRATR_END ||
2033                       ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
2034                     ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
2035                     rSet.Put( pCFSet->Get( nWhich ) );
2036                 nWhich = aIter.NextWhich();
2037             }
2038         }
2039     }
2040 
2041 	// aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
2042 
2043 /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
2044  z.B
2045 			1234567890123456789
2046 			  |------------| 		Font1
2047 				 |------|			Font2
2048 					^  ^
2049 					|--|		Abfragebereich: -> Gueltig ist Font2
2050 */
2051     rSet.Put( rAttr );
2052 }
2053 
2054 struct SwPoolItemEndPair
2055 {
2056 public:
2057     const SfxPoolItem* mpItem;
2058     xub_StrLen mnEndPos;
2059 
2060     SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
2061 };
2062 
2063 // --> OD 2008-01-16 #newlistlevelattrs#
2064 void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
2065                                             SfxItemSet& rSet )
2066 {
2067     if ( rTxtNode.AreListLevelIndentsApplicable() )
2068     {
2069         const SwNumRule* pRule = rTxtNode.GetNumRule();
2070         if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
2071         {
2072             const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
2073             if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2074             {
2075                 SvxLRSpaceItem aLR( RES_LR_SPACE );
2076                 aLR.SetTxtLeft( rFmt.GetIndentAt() );
2077                 aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
2078                 rSet.Put( aLR );
2079             }
2080         }
2081     }
2082 }
2083 
2084 // erfrage die Attribute vom TextNode ueber den Bereich
2085 // --> OD 2008-01-16 #newlistlevelattrs#
2086 sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd,
2087                          sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt,
2088                          const bool bMergeIndentValuesOfNumRule ) const
2089 {
2090     if( HasHints() )
2091     {
2092 		/* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
2093 		 * sind. Dabei gibt es folgende Faelle:
2094 		 * 	UnEindeutig wenn: (wenn != Format-Attribut)
2095 		 * 		- das Attribut liegt vollstaendig im Bereich
2096 		 * 		- das Attributende liegt im Bereich
2097 		 * 		- der Attributanfang liegt im Bereich:
2098 		 * Eindeutig (im Set mergen):
2099 		 *		- das Attrib umfasst den Bereich
2100 		 * nichts tun:
2101 		 * 		das Attribut liegt ausserhalb des Bereiches
2102 		 */
2103 
2104 		void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
2105 			= bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
2106 							 : &lcl_MergeAttr;
2107 
2108 		// dann besorge mal die Auto-(Fmt)Attribute
2109 		SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
2110 		if( !bOnlyTxtAttr )
2111         {
2112 			SwCntntNode::GetAttr( aFmtSet );
2113             // --> OD 2008-01-16 #newlistlevelattrs#
2114             if ( bMergeIndentValuesOfNumRule )
2115             {
2116                 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
2117             }
2118             // <--
2119         }
2120 
2121         const sal_uInt16 nSize = m_pSwpHints->Count();
2122 
2123         if( nStt == nEnd )             // kein Bereich:
2124 		{
2125             for (sal_uInt16 n = 0; n < nSize; ++n)
2126             {
2127                 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
2128                 const xub_StrLen nAttrStart = *pHt->GetStart();
2129 				if( nAttrStart > nEnd ) 		// ueber den Bereich hinaus
2130 					break;
2131 
2132                 const xub_StrLen* pAttrEnd = pHt->End();
2133                 if ( ! pAttrEnd ) // no attributes without end
2134 					continue;
2135 
2136                 if( ( nAttrStart < nStt &&
2137                         ( pHt->DontExpand() ? nStt < *pAttrEnd
2138                                             : nStt <= *pAttrEnd )) ||
2139                     ( nStt == nAttrStart &&
2140                         ( nAttrStart == *pAttrEnd || !nStt )))
2141 					(*fnMergeAttr)( rSet, pHt->GetAttr() );
2142 			}
2143 		}
2144 		else							// es ist ein Bereich definiert
2145 		{
2146             // --> FME 2007-03-13 #i75299#
2147             ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
2148             // <--
2149 
2150 			const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
2151                                    static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
2152 
2153             for (sal_uInt16 n = 0; n < nSize; ++n)
2154             {
2155                 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
2156                 const xub_StrLen nAttrStart = *pHt->GetStart();
2157 				if( nAttrStart > nEnd ) 		// ueber den Bereich hinaus
2158 					break;
2159 
2160                 const xub_StrLen* pAttrEnd = pHt->End();
2161                 if ( ! pAttrEnd ) // no attributes without end
2162 					continue;
2163 
2164 				sal_Bool bChkInvalid = sal_False;
2165                 if( nAttrStart <= nStt )       // vor oder genau Start
2166 				{
2167                     if( *pAttrEnd <= nStt )    // liegt davor
2168 						continue;
2169 
2170 					if( nEnd <= *pAttrEnd )		// hinter oder genau Ende
2171 						(*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
2172 					else
2173 //					else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
2174 						// uneindeutig
2175 						bChkInvalid = sal_True;
2176 				}
2177 				else if( nAttrStart < nEnd 		// reicht in den Bereich
2178 )//						 && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
2179 					bChkInvalid = sal_True;
2180 
2181 				if( bChkInvalid )
2182 				{
2183 					// uneindeutig ?
2184                     ::std::auto_ptr< SfxItemIter > pItemIter;
2185                     const SfxPoolItem* pItem = 0;
2186 
2187                     if ( RES_TXTATR_AUTOFMT == pHt->Which() )
2188                     {
2189                         const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
2190                         if ( pAutoSet )
2191                         {
2192                             pItemIter.reset( new SfxItemIter( *pAutoSet ) );
2193                             pItem = pItemIter->GetCurItem();
2194                         }
2195                     }
2196                     else
2197                         pItem = &pHt->GetAttr();
2198 
2199                     const sal_uInt16 nHintEnd = *pAttrEnd;
2200 
2201                     while ( pItem )
2202                     {
2203                         const sal_uInt16 nHintWhich = pItem->Which();
2204                         ASSERT(!isUNKNOWNATR(nHintWhich),
2205                                 "SwTxtNode::GetAttr(): unknown attribute?");
2206 
2207                         if ( !pAttrArr.get() )
2208                         {
2209                             pAttrArr.reset(
2210                                 new std::vector< SwPoolItemEndPair >(coArrSz));
2211                         }
2212 
2213                         std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
2214                         if (isCHRATR(nHintWhich) ||
2215                             isTXTATR_WITHEND(nHintWhich))
2216                         {
2217                             pPrev += nHintWhich - RES_CHRATR_BEGIN;
2218                         }
2219                         else
2220                         {
2221                             pPrev = pAttrArr->end();
2222                         }
2223 
2224 #if OSL_DEBUG_LEVEL > 1
2225                         SwPoolItemEndPair aTmp = *pPrev;
2226 #endif
2227 
2228                         if( pPrev != pAttrArr->end() )
2229                         {
2230                             if( !pPrev->mpItem )
2231                             {
2232                                 if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
2233                                 {
2234                                     if( nAttrStart > nStt )
2235                                     {
2236                                         rSet.InvalidateItem( nHintWhich );
2237                                         pPrev->mpItem = (SfxPoolItem*)-1;
2238                                     }
2239                                     else
2240                                     {
2241                                         pPrev->mpItem = pItem;
2242                                         pPrev->mnEndPos = nHintEnd;
2243                                     }
2244                                 }
2245                             }
2246                             else if( (SfxPoolItem*)-1 != pPrev->mpItem )
2247                             {
2248                                 if( pPrev->mnEndPos == nAttrStart &&
2249                                     *pPrev->mpItem == *pItem )
2250                                 {
2251                                     pPrev->mpItem = pItem;
2252                                     pPrev->mnEndPos = nHintEnd;
2253                                 }
2254                                 else
2255                                 {
2256                                     rSet.InvalidateItem( nHintWhich );
2257                                     pPrev->mpItem = (SfxPoolItem*)-1;
2258                                 }
2259                             }
2260                         }
2261 
2262                         pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
2263                                     ? pItemIter->NextItem() : 0;
2264                     } // end while
2265                 }
2266 			}
2267 
2268             if ( pAttrArr.get() )
2269 			{
2270                 for (sal_uInt16 n = 0; n < coArrSz; ++n)
2271                 {
2272                     const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
2273                     if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
2274                     {
2275                         const sal_uInt16 nWh =
2276                             static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2277 
2278                         if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
2279                         {
2280                             if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
2281                                 (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2282                         }
2283                         else
2284                             // uneindeutig
2285                             rSet.InvalidateItem( nWh );
2286                     }
2287                 }
2288 			}
2289 		}
2290 		if( aFmtSet.Count() )
2291 		{
2292 			// aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
2293 			aFmtSet.Differentiate( rSet );
2294 			// jetzt alle zusammen "mergen"
2295 			rSet.Put( aFmtSet );
2296 		}
2297 	}
2298 	else if( !bOnlyTxtAttr )
2299     {
2300 		// dann besorge mal die Auto-(Fmt)Attribute
2301 		SwCntntNode::GetAttr( rSet );
2302         // --> OD 2008-01-16 #newlistlevelattrs#
2303         if ( bMergeIndentValuesOfNumRule )
2304         {
2305             lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
2306         }
2307         // <--
2308     }
2309 
2310 	return rSet.Count() ? sal_True : sal_False;
2311 }
2312 
2313 
2314 namespace
2315 {
2316 
2317 typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t;
2318 typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t;
2319 
2320 
2321 struct IsAutoStyle
2322 {
2323     bool
2324     operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2325     const
2326     {
2327         return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2328     }
2329 };
2330 
2331 
2332 /** Removes from io_rAttrSet all items that are set by style on the
2333     given span.
2334   */
2335 struct RemovePresentAttrs
2336 {
2337     RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2338         : m_rAttrSet(io_rAttrSet)
2339     {
2340     }
2341 
2342     void
2343     operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2344     const
2345     {
2346         if (!i_rAttrSpan.second)
2347         {
2348             return;
2349         }
2350 
2351         const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second);
2352         SfxItemIter aIter(m_rAttrSet);
2353         const SfxPoolItem* pItem(aIter.GetCurItem());
2354         while (pItem)
2355         {
2356             const sal_uInt16 nWhich(pItem->Which());
2357             if (CharFmt::IsItemIncluded(nWhich, pAutoStyle))
2358             {
2359                 m_rAttrSet.ClearItem(nWhich);
2360             }
2361 
2362             if (aIter.IsAtEnd())
2363             {
2364                 break;
2365             }
2366             pItem = aIter.NextItem();
2367         }
2368     }
2369 
2370 private:
2371     SfxItemSet& m_rAttrSet;
2372 };
2373 
2374 
2375 /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
2376     addition inserts dummy spans with pointer to format equal to 0 for
2377     all gaps (i.e. spans not covered by any style). This simplifies
2378     creation of autostyles for all needed spans, but it means all code
2379     that tries to access the pointer has to check if it's non-null!
2380  */
2381 void
2382 lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength,
2383         AttrSpanMap_t& o_rSpanMap)
2384 {
2385     sal_uInt16 nLastEnd(0);
2386 
2387     for (sal_uInt16 i(0); i != i_rHints.Count(); ++i)
2388     {
2389         const SwTxtAttr* const pHint(i_rHints[i]);
2390         const sal_uInt16 nWhich(pHint->Which());
2391         if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2392         {
2393             const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->End());
2394             o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
2395 
2396             // < not != because there may be multiple CHARFMT at same range
2397             if (nLastEnd < aSpan.first)
2398             {
2399                 // insert dummy span covering the gap
2400                 o_rSpanMap.insert(AttrSpanMap_t::value_type(
2401                             AttrSpan_t(nLastEnd, aSpan.first), 0));
2402             }
2403 
2404             nLastEnd = aSpan.second;
2405         }
2406     }
2407 
2408     // no hints at the end (special case: no hints at all in i_rHints)
2409     if (nLastEnd != nLength && nLength != 0)
2410     {
2411         o_rSpanMap.insert(
2412             AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), 0));
2413     }
2414 }
2415 
2416 
2417 void
2418 lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2419 {
2420     o_rClearIds.reserve(i_rAttrSet.Count());
2421     SfxItemIter aIter(i_rAttrSet);
2422     const SfxPoolItem* pItem(aIter.GetCurItem());
2423     while (true)
2424     {
2425         o_rClearIds.push_back(pItem->Which());
2426 
2427         if (aIter.IsAtEnd())
2428         {
2429             break;
2430         }
2431         pItem = aIter.NextItem();
2432     }
2433 }
2434 
2435 struct SfxItemSetClearer
2436 {
2437     SfxItemSet & m_rItemSet;
2438     SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2439     void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2440 };
2441 
2442 }
2443 
2444 
2445 /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion
2446     of items to automatic styles.
2447  */
2448 void
2449 SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
2450 {
2451     typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2452     AttrSpanMap_t aAttrSpanMap;
2453 
2454     if (i_rAttrSet.Count() == 0)
2455     {
2456         return;
2457     }
2458 
2459     // 1. Identify all spans in hints' array
2460 
2461     lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap);
2462 
2463     // 2. Go through all spans and insert new attrs
2464 
2465     AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2466     const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2467     while (aCurRange != aEnd)
2468     {
2469         typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2470             AttrSpanMapRange_t;
2471         AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2472 
2473         // 2a. Collect attributes to insert
2474 
2475         SfxItemSet aCurSet(i_rAttrSet);
2476         std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2477 
2478         // 2b. Insert automatic style containing the collected attributes
2479 
2480         if (aCurSet.Count() != 0)
2481         {
2482             AttrSpanMap_iterator_t aAutoStyleIt(
2483                     std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2484             if (aAutoStyleIt != aRange.second)
2485             {
2486                 // there already is an automatic style on that span:
2487                 // create new one and remove the original one
2488                 SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second));
2489                 const boost::shared_ptr<SfxItemSet> pOldStyle(
2490                         static_cast<const SwFmtAutoFmt&>(
2491                             pAutoStyle->GetAttr()).GetStyleHandle());
2492                 aCurSet.Put(*pOldStyle);
2493 
2494                 // remove the old hint
2495                 m_pSwpHints->Delete(pAutoStyle);
2496                 DestroyAttr(pAutoStyle);
2497             }
2498             m_pSwpHints->Insert(
2499                     MakeTxtAttr(*GetDoc(), aCurSet,
2500                         aCurRange->first.first, aCurRange->first.second));
2501         }
2502 
2503         aCurRange = aRange.second;
2504     }
2505 
2506     // 3. Clear items from the node
2507     std::vector<sal_uInt16> aClearedIds;
2508     lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2509     ClearItemsFromAttrSet(aClearedIds);
2510 }
2511 
2512 void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
2513 {
2514 	SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2515     if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2516 		aThisSet.Put( *GetpSwAttrSet() );
2517 
2518     GetOrCreateSwpHints();
2519 
2520 	if( pNd == this )
2521 	{
2522         impl_FmtToTxtAttr(aThisSet);
2523     }
2524 	else
2525 	{
2526         // There are five possible combinations of items from this and
2527         // pNd (pNd is the 'main' node):
2528         //
2529         //  case    pNd     this     action
2530         //  ----------------------------------------------------
2531         //     1     -       -      do nothing
2532         //     2     -       a      convert item to attr of this
2533         //     3     a       -      convert item to attr of pNd
2534         //     4     a       a      clear item in this
2535         //     5     a       b      convert item to attr of this
2536 
2537 		SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
2538         if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2539 			aNdSet.Put( *pNd->GetpSwAttrSet() );
2540 
2541         pNd->GetOrCreateSwpHints();
2542 
2543         std::vector<sal_uInt16> aProcessedIds;
2544 
2545 		if( aThisSet.Count() )
2546 		{
2547 			SfxItemIter aIter( aThisSet );
2548 			const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
2549             SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2550             std::vector<sal_uInt16> aClearWhichIds;
2551 
2552 			while( true )
2553 			{
2554 				if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) )
2555                 {
2556                     if (*pItem == *pNdItem) // 4
2557                     {
2558                         aClearWhichIds.push_back( pItem->Which() );
2559                     }
2560                     else    // 5
2561                     {
2562                         aConvertSet.Put(*pItem);
2563                     }
2564                     aProcessedIds.push_back(pItem->Which());
2565                 }
2566                 else    // 2
2567                 {
2568                     aConvertSet.Put(*pItem);
2569                 }
2570 
2571 				if( aIter.IsAtEnd() )
2572 					break;
2573 				pItem = aIter.NextItem();
2574 			}
2575 
2576             // 4/ clear items of this that are set with the same value on pNd
2577             ClearItemsFromAttrSet( aClearWhichIds );
2578 
2579             // 2, 5/ convert all other items to attrs
2580             impl_FmtToTxtAttr(aConvertSet);
2581         }
2582 
2583         {
2584             std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2585                     SfxItemSetClearer(aNdSet));
2586 
2587             // 3/ convert items to attrs
2588             pNd->impl_FmtToTxtAttr(aNdSet);
2589 
2590             if( aNdSet.Count() )
2591             {
2592                 SwFmtChg aTmp1( pNd->GetFmtColl() );
2593                 pNd->NotifyClients( &aTmp1, &aTmp1 );
2594             }
2595         }
2596     }
2597 
2598     SetCalcHiddenCharFlags();
2599 
2600     pNd->TryDeleteSwpHints();
2601 }
2602 
2603 /*************************************************************************
2604  *						SwpHints::CalcFlags()
2605  *************************************************************************/
2606 
2607 void SwpHints::CalcFlags()
2608 {
2609     m_bDDEFields = m_bFootnote = false;
2610     const sal_uInt16 nSize = Count();
2611     const SwTxtAttr* pAttr;
2612     for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2613     {
2614         switch( ( pAttr = (*this)[ nPos ])->Which() )
2615         {
2616         case RES_TXTATR_FTN:
2617             m_bFootnote = true;
2618             if ( m_bDDEFields )
2619                 return;
2620             break;
2621         case RES_TXTATR_FIELD:
2622             {
2623                 const SwField* pFld = pAttr->GetFmtFld().GetField();
2624                 if( RES_DDEFLD == pFld->GetTyp()->Which() )
2625                 {
2626                     m_bDDEFields = true;
2627                     if ( m_bFootnote )
2628                         return;
2629                 }
2630             }
2631             break;
2632         }
2633     }
2634 }
2635 
2636 /*************************************************************************
2637  *						SwpHints::CalcVisibleFlag()
2638  *************************************************************************/
2639 
2640 bool SwpHints::CalcHiddenParaField()
2641 {
2642     m_bCalcHiddenParaField = false;
2643     bool bOldHasHiddenParaField = m_bHasHiddenParaField;
2644     bool bNewHasHiddenParaField  = false;
2645     const sal_uInt16	nSize = Count();
2646     const SwTxtAttr *pTxtHt;
2647 
2648     for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2649     {
2650         pTxtHt = (*this)[ nPos ];
2651         const sal_uInt16 nWhich = pTxtHt->Which();
2652 
2653         if( RES_TXTATR_FIELD == nWhich )
2654         {
2655             const SwFmtFld& rFld = pTxtHt->GetFmtFld();
2656             if( RES_HIDDENPARAFLD == rFld.GetField()->GetTyp()->Which() )
2657             {
2658                 if( !((SwHiddenParaField*)rFld.GetField())->IsHidden() )
2659                 {
2660                     SetHiddenParaField(false);
2661                     return bOldHasHiddenParaField != bNewHasHiddenParaField;
2662                 }
2663                 else
2664                 {
2665                     bNewHasHiddenParaField = true;
2666                 }
2667             }
2668         }
2669     }
2670     SetHiddenParaField( bNewHasHiddenParaField );
2671     return bOldHasHiddenParaField != bNewHasHiddenParaField;
2672 }
2673 
2674 
2675 /*************************************************************************
2676  *						SwpHints::NoteInHistory()
2677  *************************************************************************/
2678 
2679 void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
2680 {
2681     if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2682 }
2683 
2684 /*************************************************************************
2685  *                      SwpHints::MergePortions( )
2686  *************************************************************************/
2687 
2688 bool SwpHints::MergePortions( SwTxtNode& rNode )
2689 {
2690     if ( !Count() )
2691         return false;
2692 
2693     // sort before merging
2694     SwpHintsArray::Resort();
2695 
2696     bool bRet = false;
2697     typedef std::multimap< int, SwTxtAttr* > PortionMap;
2698     PortionMap aPortionMap;
2699     xub_StrLen nLastPorStart = STRING_LEN;
2700     sal_uInt16 i = 0;
2701     int nKey = 0;
2702 
2703     // get portions by start position:
2704     for ( i = 0; i < Count(); ++i )
2705     {
2706         SwTxtAttr *pHt = GetTextHint( i );
2707         if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2708              RES_TXTATR_AUTOFMT != pHt->Which() )
2709              //&&
2710              //RES_TXTATR_INETFMT != pHt->Which() )
2711             continue;
2712 
2713         const xub_StrLen nPorStart = *pHt->GetStart();
2714         if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
2715             ++nKey;
2716         nLastPorStart = nPorStart;
2717         aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
2718     }
2719 
2720     // check if portion i can be merged with portion i+1:
2721     i = 0;
2722     int j = i + 1;
2723     while ( i <= nKey )
2724     {
2725         std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2726         std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2727         PortionMap::iterator aIter1 = aRange1.first;
2728         PortionMap::iterator aIter2 = aRange2.first;
2729 
2730         bool bMerge = true;
2731         const sal_uInt16 nAttributesInPor1  = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
2732         const sal_uInt16 nAttributesInPor2  = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
2733 
2734         if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
2735         {
2736             while ( aIter1 != aRange1.second )
2737             {
2738                 const SwTxtAttr* p1 = (*aIter1).second;
2739                 const SwTxtAttr* p2 = (*aIter2).second;
2740                 if ( *p1->End() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
2741                 {
2742                     bMerge = false;
2743                     break;
2744                 }
2745                 ++aIter1;
2746                 ++aIter2;
2747             }
2748         }
2749         else
2750         {
2751             bMerge = false;
2752         }
2753 
2754         if ( bMerge )
2755         {
2756             // erase all elements with key i + 1
2757             xub_StrLen nNewPortionEnd = 0;
2758             for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2759             {
2760                 SwTxtAttr* p2 = (*aIter2).second;
2761                 nNewPortionEnd = *p2->GetEnd();
2762 
2763                 const sal_uInt16 nCountBeforeDelete = Count();
2764                 Delete( p2 );
2765 
2766                 // robust: check if deletion actually took place before destroying attribute:
2767                 if ( Count() < nCountBeforeDelete )
2768                     rNode.DestroyAttr( p2 );
2769             }
2770             aPortionMap.erase( aRange2.first, aRange2.second );
2771             ++j;
2772 
2773             // change all attributes with key i
2774             aRange1 = aPortionMap.equal_range( i );
2775             for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2776             {
2777                 SwTxtAttr* p1 = (*aIter1).second;
2778                 NoteInHistory( p1 );
2779                 *p1->GetEnd() = nNewPortionEnd;
2780                 NoteInHistory( p1, true );
2781                 bRet = true;
2782             }
2783         }
2784         else
2785         {
2786             ++i;
2787             j = i + 1;
2788         }
2789     }
2790 
2791     if ( bRet )
2792     {
2793         SwpHintsArray::Resort();
2794     }
2795 
2796     return bRet;
2797 }
2798 
2799 // check if there is already a character format and adjust the sort numbers
2800 void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
2801 {
2802     const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
2803     const xub_StrLen nHtEnd   = *rNewCharFmt.GetEnd();
2804     sal_uInt16 nSortNumber = 0;
2805 
2806     for ( sal_uInt16 i = 0; i < rHints.Count(); ++i )
2807     {
2808         const SwTxtAttr* pOtherHt = rHints[i];
2809 
2810         const xub_StrLen nOtherStart = *pOtherHt->GetStart();
2811 
2812         if ( nOtherStart > nHtStart )
2813             break;
2814 
2815         if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2816         {
2817             const xub_StrLen nOtherEnd = *pOtherHt->End();
2818 
2819             if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2820             {
2821                 const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber();
2822                 nSortNumber = nOtherSortNum + 1;
2823             }
2824         }
2825     }
2826 
2827     if ( nSortNumber > 0 )
2828         rNewCharFmt.SetSortNumber( nSortNumber );
2829 }
2830 
2831 /*************************************************************************
2832  *						SwpHints::Insert()
2833  *************************************************************************/
2834 
2835 /*
2836  * Try to insert the new hint.
2837  * Depending on the type of the hint, this either always succeeds, or may fail.
2838  * Depending on the type of the hint, other hints may be deleted or
2839  * overwritten.
2840  * The return value indicates successful insertion.
2841  */
2842 bool SwpHints::TryInsertHint(
2843     SwTxtAttr* const pHint,
2844     SwTxtNode &rNode,
2845     const SetAttrMode nMode )
2846 {
2847     if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked...
2848     {
2849         ASSERT(false, "hints array full :-(");
2850         return false;
2851     }
2852 
2853 	// Felder bilden eine Ausnahme:
2854 	// 1) Sie koennen nie ueberlappen
2855 	// 2) Wenn zwei Felder genau aneinander liegen,
2856 	//	  sollen sie nicht zu einem verschmolzen werden.
2857 	// Wir koennen also auf die while-Schleife verzichten
2858 
2859     xub_StrLen *pHtEnd = pHint->GetEnd();
2860     sal_uInt16 nWhich = pHint->Which();
2861 
2862 	switch( nWhich )
2863 	{
2864 	case RES_TXTATR_CHARFMT:
2865     {
2866         // Check if character format contains hidden attribute:
2867         const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
2868         const SfxPoolItem* pItem;
2869         if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
2870             rNode.SetCalcHiddenCharFlags();
2871 
2872         ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
2873 		break;
2874     }
2875     // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary
2876     case RES_TXTATR_AUTOFMT:
2877     {
2878         // Check if auto style contains hidden attribute:
2879         const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
2880         if ( pHiddenItem )
2881             rNode.SetCalcHiddenCharFlags();
2882         break;
2883     }
2884     // <--
2885 
2886     case RES_TXTATR_INETFMT:
2887         static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
2888         break;
2889 
2890 	case RES_TXTATR_FIELD:
2891 	case RES_TXTATR_ANNOTATION:
2892 	case RES_TXTATR_INPUTFIELD:
2893 		{
2894 			sal_Bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
2895 			((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
2896 			SwDoc* pDoc = rNode.GetDoc();
2897 			const SwField* pFld = ((SwTxtFld*)pHint)->GetFmtFld().GetField();
2898 
2899 			if( !pDoc->IsNewFldLst() )
2900 			{
2901 				// was fuer ein Feld ist es denn ??
2902 				// bestimmte Felder mussen am Doc das Calculations-Flag updaten
2903 				switch( pFld->GetTyp()->Which() )
2904 				{
2905 				case RES_DBFLD:
2906 				case RES_SETEXPFLD:
2907 				case RES_HIDDENPARAFLD:
2908 				case RES_HIDDENTXTFLD:
2909 				case RES_DBNUMSETFLD:
2910 				case RES_DBNEXTSETFLD:
2911 					{
2912 						if( bDelFirst )
2913 							pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pHint );
2914 						if( rNode.GetNodes().IsDocNodes() )
2915 							pDoc->InsDelFldInFldLst( sal_True, *(SwTxtFld*)pHint );
2916 					}
2917 					break;
2918 				case RES_DDEFLD:
2919 					if( rNode.GetNodes().IsDocNodes() )
2920 						((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2921 					break;
2922 				}
2923 			}
2924 
2925             // gehts ins normale Nodes-Array?
2926             if( rNode.GetNodes().IsDocNodes() )
2927             {
2928                 sal_Bool bInsFldType = sal_False;
2929                 switch( pFld->GetTyp()->Which() )
2930                 {
2931                 case RES_SETEXPFLD:
2932                     bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
2933                     if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
2934                     {
2935                         // bevor die ReferenzNummer gesetzt wird, sollte
2936                         // das Feld am richtigen FeldTypen haengen!
2937                         SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
2938                                     pDoc->InsertFldType( *pFld->GetTyp() );
2939                         if( pFldType != pFld->GetTyp() )
2940                         {
2941                             SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)->GetFmtFld();
2942                             pFmtFld->RegisterToFieldType( *pFldType );
2943                             pFmtFld->GetField()->ChgTyp( pFldType );
2944                         }
2945                         pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
2946                     }
2947                     break;
2948                 case RES_USERFLD:
2949                     bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
2950                     break;
2951 
2952                 case RES_DDEFLD:
2953                     if( pDoc->IsNewFldLst() )
2954                         ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2955                     bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
2956                     break;
2957 
2958                 case RES_POSTITFLD:
2959                     if ( pDoc->GetDocShell() )
2960                         pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_INSERTED ) );
2961                     break;
2962                 }
2963                 if( bInsFldType )
2964                     pDoc->InsDeletedFldType( *pFld->GetTyp() );
2965             }
2966         }
2967         break;
2968     case RES_TXTATR_FTN :
2969 		((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
2970 		break;
2971 	case RES_TXTATR_REFMARK:
2972 		((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
2973 		if( rNode.GetNodes().IsDocNodes() )
2974 		{
2975             // search for a reference with the same name
2976 			SwTxtAttr* pTmpHt;
2977 			xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
2978 			for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n )
2979             {
2980                 if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
2981 					pHint->GetAttr() == pTmpHt->GetAttr() &&
2982 					0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
2983 					0 != ( pTmpHintEnd = pHint->GetEnd() ) )
2984 				{
2985 					SwComparePosition eCmp = ::ComparePosition(
2986 							*pTmpHt->GetStart(), *pTmpHtEnd,
2987 							*pHint->GetStart(), *pTmpHintEnd );
2988 					sal_Bool bDelOld = sal_True, bChgStart = sal_False, bChgEnd = sal_False;
2989 					switch( eCmp )
2990 					{
2991 					case POS_BEFORE:
2992 					case POS_BEHIND:	bDelOld = sal_False; break;
2993 
2994 					case POS_OUTSIDE:	bChgStart = bChgEnd = sal_True; break;
2995 
2996 					case POS_COLLIDE_END:
2997 					case POS_OVERLAP_BEFORE:	bChgStart = sal_True; break;
2998 					case POS_COLLIDE_START:
2999 					case POS_OVERLAP_BEHIND:    bChgEnd = sal_True; break;
3000                     default: break;
3001 					}
3002 
3003 					if( bChgStart )
3004 						*pHint->GetStart() = *pTmpHt->GetStart();
3005 					if( bChgEnd )
3006 						*pTmpHintEnd = *pTmpHtEnd;
3007 
3008 					if( bDelOld )
3009                     {
3010                         NoteInHistory( pTmpHt );
3011 						rNode.DestroyAttr( Cut( n-- ) );
3012 						--nEnd;
3013 					}
3014 				}
3015             }
3016 		}
3017 		break;
3018 	case RES_TXTATR_TOXMARK:
3019 		((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
3020 		break;
3021 
3022 	case RES_TXTATR_CJK_RUBY:
3023         static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode);
3024 		break;
3025 
3026     case RES_TXTATR_META:
3027     case RES_TXTATR_METAFIELD:
3028         static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode );
3029         break;
3030 
3031     case RES_CHRATR_HIDDEN:
3032         rNode.SetCalcHiddenCharFlags();
3033         break;
3034 	}
3035 
3036 	if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
3037 		pHint->SetDontExpand( sal_True );
3038 
3039 	// SwTxtAttrs ohne Ende werden sonderbehandelt:
3040 	// Sie werden natuerlich in das Array insertet, aber sie werden nicht
3041 	// in die pPrev/Next/On/Off-Verkettung aufgenommen.
3042 	// Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
3043 	xub_StrLen nHtStart = *pHint->GetStart();
3044 	if( !pHtEnd )
3045     {
3046         SwpHintsArray::Insert( pHint );
3047 		CalcFlags();
3048 #ifdef DBG_UTIL
3049         if( !rNode.GetDoc()->IsInReading() )
3050             CHECK;
3051 #endif
3052         // ... und die Abhaengigen benachrichtigen
3053         if(rNode.GetDepends())
3054         {
3055             SwUpdateAttr aHint(
3056                 nHtStart,
3057                 nHtStart,
3058                 nWhich);
3059 
3060             rNode.ModifyNotification(0,&aHint);
3061         }
3062 
3063         return true;
3064     }
3065 
3066 	// ----------------------------------------------------------------
3067 	// Ab hier gibt es nur noch pHint mit einem EndIdx !!!
3068 
3069     if( *pHtEnd < nHtStart )
3070 	{
3071 		ASSERT( *pHtEnd >= nHtStart,
3072 					"+SwpHints::Insert: invalid hint, end < start" );
3073 
3074 		// Wir drehen den Quatsch einfach um:
3075 		*pHint->GetStart() = *pHtEnd;
3076 		*pHtEnd = nHtStart;
3077 		nHtStart = *pHint->GetStart();
3078 	}
3079 
3080     // I need this value later on for notification but the pointer may become invalid
3081     const xub_StrLen nHintEnd = *pHtEnd;
3082     const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
3083 
3084     // handle nesting attributes: inserting may fail due to overlap!
3085     if (pHint->IsNesting())
3086     {
3087         const bool bRet(
3088             TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint)));
3089         if (!bRet) return false;
3090     }
3091     // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
3092     // These attributes may be inserted directly.
3093     // Also attributes without length may be inserted directly.
3094     // SETATTR_NOHINTADJUST is set e.g., during undo.
3095     // Portion building in not necessary during XML import.
3096     else
3097     if ( !bNoHintAdjustMode &&
3098          !pHint->IsOverlapAllowedAttr() &&
3099          !rNode.GetDoc()->IsInXMLImport() &&
3100          ( RES_TXTATR_AUTOFMT == nWhich ||
3101            RES_TXTATR_CHARFMT == nWhich ) )
3102     {
3103         ASSERT( nWhich != RES_TXTATR_AUTOFMT ||
3104                 static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
3105                 &rNode.GetDoc()->GetAttrPool(),
3106                 "AUTOSTYLES - Pool mismatch" )
3107 
3108         BuildPortions( rNode, *pHint, nMode );
3109 
3110         if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
3111             MergePortions( rNode );
3112     }
3113     else
3114     {
3115         // There may be more than one character style at the current position.
3116         // Take care of the sort number.
3117         // Special case ruby portion: During import, the ruby attribute is set
3118         // multiple times
3119         // Special case hyperlink: During import, the ruby attribute is set
3120         // multiple times
3121         // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
3122         // character attributes directly
3123         if ( ( RES_TXTATR_CHARFMT  == nWhich && !bNoHintAdjustMode ) )
3124         {
3125             BuildPortions( rNode, *pHint, nMode );
3126         }
3127         else
3128         {
3129             // --> FME 2007-11-08 #i82989# Check sort numbers in NoHintAdjustMode
3130             if ( RES_TXTATR_CHARFMT == nWhich )
3131                 lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
3132             // <--
3133 
3134             SwpHintsArray::Insert( pHint );
3135             NoteInHistory( pHint, true );
3136         }
3137     }
3138 
3139     // ... und die Abhaengigen benachrichtigen
3140     if ( rNode.GetDepends() )
3141     {
3142         SwUpdateAttr aHint(
3143             // rNode.GetDoc()->GetAttrPool(),
3144             nHtStart,
3145             nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd,
3146             nWhich);
3147 
3148         rNode.ModifyNotification( 0, &aHint );
3149     }
3150 
3151 #ifdef DBG_UTIL
3152     if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
3153         CHECK;
3154 #endif
3155 
3156     return true;
3157 }
3158 
3159 /*************************************************************************
3160  *						SwpHints::DeleteAtPos()
3161  *************************************************************************/
3162 
3163 void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
3164 {
3165     SwTxtAttr *pHint = GetTextHint(nPos);
3166     // ChainDelete( pHint );
3167     NoteInHistory( pHint );
3168     SwpHintsArray::DeleteAtPos( nPos );
3169 
3170     if( pHint->Which() == RES_TXTATR_FIELD )
3171     {
3172         const SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFmtFld().GetField()->GetTyp();
3173         if( RES_DDEFLD == pFldTyp->Which() )
3174         {
3175             const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
3176             if( pNd && pNd->GetNodes().IsDocNodes() )
3177                 ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
3178             ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
3179         }
3180         else if ( m_bHasHiddenParaField &&
3181                  RES_HIDDENPARAFLD == pFldTyp->Which() )
3182         {
3183             m_bCalcHiddenParaField = true;
3184         }
3185     }
3186     else if ( pHint->Which() == RES_TXTATR_ANNOTATION )
3187     {
3188         const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_REMOVED ) );
3189     }
3190 
3191     CalcFlags();
3192     CHECK;
3193 }
3194 
3195 // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
3196 // Ist er nicht im Array, so gibt es ein ASSERT !!
3197 
3198 void SwpHints::Delete( SwTxtAttr* pTxtHt )
3199 {
3200 	// Attr 2.0: SwpHintsArr::Delete( pTxtHt );
3201 	const sal_uInt16 nPos = GetStartOf( pTxtHt );
3202 	ASSERT( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
3203 	if( USHRT_MAX != nPos )
3204 		DeleteAtPos( nPos );
3205 }
3206 
3207 void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
3208 {
3209     if ( HasHints() )
3210     {
3211         sal_uInt16 nPos = 0;
3212         while ( nPos < m_pSwpHints->Count() )
3213         {
3214             SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
3215             bool bDel = false;
3216 
3217             switch( pDel->Which() )
3218             {
3219             case RES_TXTATR_FLYCNT:
3220             case RES_TXTATR_FTN:
3221                 break;
3222 
3223             case RES_TXTATR_FIELD:
3224             case RES_TXTATR_ANNOTATION:
3225             case RES_TXTATR_INPUTFIELD:
3226                 if( bDelFields )
3227                     bDel = true;
3228                 break;
3229             default:
3230                 bDel = true; break;
3231             }
3232 
3233             if( bDel )
3234             {
3235                 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
3236 				DestroyAttr( pDel );
3237 			}
3238 			else
3239 				++nPos;
3240 		}
3241 	}
3242 }
3243 
3244 sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
3245                            sal_uInt16 nScript ) const
3246 {
3247 	sal_uInt16 nRet = LANGUAGE_DONTKNOW;
3248 
3249     if ( ! nScript )
3250     {
3251         nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
3252     }
3253 
3254     // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0
3255     const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
3256     // <--
3257 
3258     if ( HasHints() )
3259     {
3260         const xub_StrLen nEnd = nBegin + nLen;
3261         for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
3262         {
3263 			// ist der Attribut-Anfang schon groesser als der Idx ?
3264             const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
3265             const xub_StrLen nAttrStart = *pHt->GetStart();
3266 			if( nEnd < nAttrStart )
3267 				break;
3268 
3269 			const sal_uInt16 nWhich = pHt->Which();
3270 
3271             if( nWhichId == nWhich ||
3272                     ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
3273             {
3274 				const xub_StrLen *pEndIdx = pHt->End();
3275 				// Ueberlappt das Attribut den Bereich?
3276 
3277 				if( pEndIdx &&
3278 					nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
3279 					 	: (( nAttrStart < nBegin &&
3280 								( pHt->DontExpand() ? nBegin < *pEndIdx
3281 													: nBegin <= *pEndIdx )) ||
3282 							( nBegin == nAttrStart &&
3283 								( nAttrStart == *pEndIdx || !nBegin ))) )
3284 				{
3285                     const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
3286                     sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
3287 
3288 					// Umfasst das Attribut den Bereich komplett?
3289 					if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
3290 						nRet = nLng;
3291 					else if( LANGUAGE_DONTKNOW == nRet )
3292 						nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
3293 				}
3294 			}
3295 		}
3296 	}
3297 	if( LANGUAGE_DONTKNOW == nRet )
3298 	{
3299 		nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
3300 		if( LANGUAGE_DONTKNOW == nRet )
3301             nRet = static_cast<sal_uInt16>(GetAppLanguage());
3302 	}
3303 	return nRet;
3304 }
3305 
3306 
3307 sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
3308 {
3309     sal_Unicode cRet = CH_TXTATR_BREAKWORD;
3310     switch ( rAttr.Which() )
3311     {
3312         case RES_TXTATR_FTN:
3313         case RES_TXTATR_REFMARK:
3314         case RES_TXTATR_TOXMARK:
3315         case RES_TXTATR_META:
3316         case RES_TXTATR_METAFIELD:
3317         case RES_TXTATR_ANNOTATION:
3318             cRet = CH_TXTATR_INWORD;
3319         break;
3320 
3321         case RES_TXTATR_FIELD:
3322         case RES_TXTATR_FLYCNT:
3323         {
3324             cRet = CH_TXTATR_BREAKWORD;
3325         }
3326         break;
3327 
3328         default:
3329             ASSERT(false, "GetCharOfTxtAttr: unknown attr");
3330             break;
3331     }
3332     return cRet;
3333 }
3334 
3335 
3336