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