xref: /aoo41x/main/sw/source/core/txtnode/thints.cxx (revision c0286415)
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->GetFmtFld().GetField();
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->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFmtFld(), 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->GetFmtFld().GetField()->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 
1641 	const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
1642 
1643 	if (!IsDefaultItem(&rInnerItem) &&  !IsInvalidItem(&rInnerItem))
1644 		return bRet;
1645 
1646 	if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 )
1647 	{
1648 		return bRet;
1649 	}
1650 
1651 	SwNumRule* pCurrNum = GetNumRule(false);
1652 
1653 	int nLevel = GetActualListLevel();
1654 
1655 	if (nLevel != -1 && pCurrNum)
1656 	{
1657 		const SwNumFmt* pCurrNumFmt = pCurrNum->GetNumFmt(static_cast<sal_uInt16>(nLevel));
1658 		if (pCurrNumFmt)
1659 		{
1660 			if (pCurrNumFmt->IsItemize() && lcl_IsIgnoredCharFmtForBullets(nWhich))
1661 				return bRet;
1662 			if (pCurrNumFmt->IsEnumeration() && lcl_IsIgnoredCharFmtForNumbering(nWhich))
1663 				return bRet;
1664 			SwCharFmt* pCurrCharFmt =pCurrNumFmt->GetCharFmt();
1665 
1666 			if (pCurrCharFmt && pCurrCharFmt->GetItemState(nWhich,false) != SFX_ITEM_SET)
1667 			{
1668 				pCurrCharFmt->SetFmtAttr(*pItem);
1669 				SwNumFmt aNewNumFmt(*pCurrNumFmt);
1670 				aNewNumFmt.SetCharFmt(pCurrCharFmt);
1671 				pCurrNum->Set(nLevel,aNewNumFmt);
1672 				bRet = true;
1673 			}
1674 		}
1675 	}
1676 
1677 
1678 	return bRet;
1679 }
1680 //End of modification, by easyfan
1681 
1682 // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1683 // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
1684 sal_Bool SwTxtNode::SetAttr( const SfxItemSet& rSet, xub_StrLen nStt,
1685                          xub_StrLen nEnd, const SetAttrMode nMode )
1686 {
1687 	if( !rSet.Count() )
1688 		return sal_False;
1689 
1690 	// teil die Sets auf (fuer Selektion in Nodes)
1691 	const SfxItemSet* pSet = &rSet;
1692 	SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1693 
1694 	// gesamter Bereich
1695     if ( !nStt && (nEnd == m_Text.Len()) &&
1696          !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
1697 	{
1698 		// sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1699 		// (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1700 		int bHasCharFmts = sal_False;
1701         if ( HasHints() )
1702         {
1703             for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
1704             {
1705                 if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
1706                 {
1707 					bHasCharFmts = sal_True;
1708 					break;
1709                 }
1710             }
1711         }
1712 
1713 		if( !bHasCharFmts )
1714 		{
1715             aTxtSet.Put( rSet );
1716             // If there are any character attributes in rSet,
1717             // we want to set them at the paragraph:
1718 			if( aTxtSet.Count() != rSet.Count() )
1719 			{
1720                 sal_Bool bRet = SetAttr( rSet );
1721           		if( !aTxtSet.Count() )
1722 		    		return bRet;
1723 			}
1724 
1725             // check for auto style:
1726             const SfxPoolItem* pItem;
1727             const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem );
1728             if ( bAutoStyle )
1729             {
1730                 boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
1731                 sal_Bool bRet = SetAttr( *pAutoStyleSet );
1732           		if( 1 == aTxtSet.Count() )
1733 		    		return bRet;
1734             }
1735 
1736             // Continue with the text attributes:
1737 			pSet = &aTxtSet;
1738 		}
1739 	}
1740 
1741     GetOrCreateSwpHints();
1742 
1743     SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
1744 
1745     sal_uInt16 nCount = 0;
1746 	SfxItemIter aIter( *pSet );
1747 	const SfxPoolItem* pItem = aIter.GetCurItem();
1748 
1749     do
1750     {
1751         if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1752         {
1753             const sal_uInt16 nWhich = pItem->Which();
1754             ASSERT( isCHRATR(nWhich) || isTXTATR(nWhich),
1755                     "SwTxtNode::SetAttr(): unknown attribute" );
1756             if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1757             {
1758                 if ((RES_TXTATR_CHARFMT == nWhich) &&
1759                     (GetDoc()->GetDfltCharFmt() ==
1760                      static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
1761                 {
1762                     SwIndex aIndex( this, nStt );
1763                     RstAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1764                     DontExpandFmt( aIndex );
1765                 }
1766                 else
1767                 {
1768                     if (isCHRATR(nWhich) ||
1769                         (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1770                     {
1771                         aCharSet.Put( *pItem );
1772                     }
1773                     else
1774                     {
1775 
1776                         SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
1777                                 const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1778                         if ( pNew )
1779                         {
1780                             if ( nEnd != nStt && !pNew->GetEnd() )
1781                             {
1782                                 ASSERT(false,
1783                                     "Attribut without end, but area marked");
1784                                 DestroyAttr( pNew ); // do not insert
1785                             }
1786                             else if ( InsertHint( pNew, nMode ) )
1787                             {
1788                                 ++nCount;
1789                             }
1790                         }
1791                     }
1792                 }
1793             }
1794         }
1795         if ( aIter.IsAtEnd() )
1796             break;
1797         pItem = aIter.NextItem();
1798     } while( true );
1799 
1800     if ( aCharSet.Count() )
1801     {
1802         SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
1803         if ( InsertHint( pTmpNew, nMode ) )
1804         {
1805             ++nCount;
1806         }
1807     }
1808 
1809     TryDeleteSwpHints();
1810 
1811 	return nCount ? sal_True : sal_False;
1812 }
1813 
1814 void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1815 {
1816     if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
1817 	{
1818         const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1819         if ( !pCFSet )
1820             return;
1821         SfxWhichIter aIter( *pCFSet );
1822         sal_uInt16 nWhich = aIter.FirstWhich();
1823         while( nWhich )
1824         {
1825             if( ( nWhich < RES_CHRATR_END ||
1826                   RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
1827                 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
1828                 rSet.Put( pCFSet->Get( nWhich ) );
1829             nWhich = aIter.NextWhich();
1830         }
1831     }
1832     else
1833     	rSet.Put( rAttr );
1834 }
1835 
1836 void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1837 {
1838 	if( RES_TXTATR_CHARFMT == rAttr.Which() ||
1839 		RES_TXTATR_INETFMT == rAttr.Which() ||
1840         RES_TXTATR_AUTOFMT == rAttr.Which() )
1841 	{
1842         const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1843 
1844         if ( pCFSet )
1845         {
1846             SfxWhichIter aIter( *pCFSet );
1847             sal_uInt16 nWhich = aIter.FirstWhich();
1848             while( nWhich )
1849             {
1850                 if( ( nWhich < RES_CHRATR_END ||
1851                       ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
1852                     ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
1853                     rSet.Put( pCFSet->Get( nWhich ) );
1854                 nWhich = aIter.NextWhich();
1855             }
1856         }
1857     }
1858 
1859 	// aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
1860 
1861 /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
1862  z.B
1863 			1234567890123456789
1864 			  |------------| 		Font1
1865 				 |------|			Font2
1866 					^  ^
1867 					|--|		Abfragebereich: -> Gueltig ist Font2
1868 */
1869     rSet.Put( rAttr );
1870 }
1871 
1872 struct SwPoolItemEndPair
1873 {
1874 public:
1875     const SfxPoolItem* mpItem;
1876     xub_StrLen mnEndPos;
1877 
1878     SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
1879 };
1880 
1881 // --> OD 2008-01-16 #newlistlevelattrs#
1882 void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
1883                                             SfxItemSet& rSet )
1884 {
1885     if ( rTxtNode.AreListLevelIndentsApplicable() )
1886     {
1887         const SwNumRule* pRule = rTxtNode.GetNumRule();
1888         if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
1889         {
1890             const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
1891             if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1892             {
1893                 SvxLRSpaceItem aLR( RES_LR_SPACE );
1894                 aLR.SetTxtLeft( rFmt.GetIndentAt() );
1895                 aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
1896                 rSet.Put( aLR );
1897             }
1898         }
1899     }
1900 }
1901 
1902 // erfrage die Attribute vom TextNode ueber den Bereich
1903 // --> OD 2008-01-16 #newlistlevelattrs#
1904 sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd,
1905                          sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt,
1906                          const bool bMergeIndentValuesOfNumRule ) const
1907 {
1908     if( HasHints() )
1909     {
1910 		/* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
1911 		 * sind. Dabei gibt es folgende Faelle:
1912 		 * 	UnEindeutig wenn: (wenn != Format-Attribut)
1913 		 * 		- das Attribut liegt vollstaendig im Bereich
1914 		 * 		- das Attributende liegt im Bereich
1915 		 * 		- der Attributanfang liegt im Bereich:
1916 		 * Eindeutig (im Set mergen):
1917 		 *		- das Attrib umfasst den Bereich
1918 		 * nichts tun:
1919 		 * 		das Attribut liegt ausserhalb des Bereiches
1920 		 */
1921 
1922 		void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
1923 			= bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
1924 							 : &lcl_MergeAttr;
1925 
1926 		// dann besorge mal die Auto-(Fmt)Attribute
1927 		SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
1928 		if( !bOnlyTxtAttr )
1929         {
1930 			SwCntntNode::GetAttr( aFmtSet );
1931             // --> OD 2008-01-16 #newlistlevelattrs#
1932             if ( bMergeIndentValuesOfNumRule )
1933             {
1934                 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
1935             }
1936             // <--
1937         }
1938 
1939         const sal_uInt16 nSize = m_pSwpHints->Count();
1940 
1941         if( nStt == nEnd )             // kein Bereich:
1942 		{
1943             for (sal_uInt16 n = 0; n < nSize; ++n)
1944             {
1945                 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
1946                 const xub_StrLen nAttrStart = *pHt->GetStart();
1947 				if( nAttrStart > nEnd ) 		// ueber den Bereich hinaus
1948 					break;
1949 
1950                 const xub_StrLen* pAttrEnd = pHt->GetEnd();
1951                 if ( ! pAttrEnd ) // no attributes without end
1952 					continue;
1953 
1954                 if( ( nAttrStart < nStt &&
1955                         ( pHt->DontExpand() ? nStt < *pAttrEnd
1956                                             : nStt <= *pAttrEnd )) ||
1957                     ( nStt == nAttrStart &&
1958                         ( nAttrStart == *pAttrEnd || !nStt )))
1959 					(*fnMergeAttr)( rSet, pHt->GetAttr() );
1960 			}
1961 		}
1962 		else							// es ist ein Bereich definiert
1963 		{
1964             // --> FME 2007-03-13 #i75299#
1965             ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
1966             // <--
1967 
1968 			const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
1969                                    static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
1970 
1971             for (sal_uInt16 n = 0; n < nSize; ++n)
1972             {
1973                 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
1974                 const xub_StrLen nAttrStart = *pHt->GetStart();
1975 				if( nAttrStart > nEnd ) 		// ueber den Bereich hinaus
1976 					break;
1977 
1978                 const xub_StrLen* pAttrEnd = pHt->GetEnd();
1979                 if ( ! pAttrEnd ) // no attributes without end
1980 					continue;
1981 
1982 				sal_Bool bChkInvalid = sal_False;
1983                 if( nAttrStart <= nStt )       // vor oder genau Start
1984 				{
1985                     if( *pAttrEnd <= nStt )    // liegt davor
1986 						continue;
1987 
1988 					if( nEnd <= *pAttrEnd )		// hinter oder genau Ende
1989 						(*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
1990 					else
1991 //					else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
1992 						// uneindeutig
1993 						bChkInvalid = sal_True;
1994 				}
1995 				else if( nAttrStart < nEnd 		// reicht in den Bereich
1996 )//						 && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
1997 					bChkInvalid = sal_True;
1998 
1999 				if( bChkInvalid )
2000 				{
2001 					// uneindeutig ?
2002                     ::std::auto_ptr< SfxItemIter > pItemIter;
2003                     const SfxPoolItem* pItem = 0;
2004 
2005                     if ( RES_TXTATR_AUTOFMT == pHt->Which() )
2006                     {
2007                         const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
2008                         if ( pAutoSet )
2009                         {
2010                             pItemIter.reset( new SfxItemIter( *pAutoSet ) );
2011                             pItem = pItemIter->GetCurItem();
2012                         }
2013                     }
2014                     else
2015                         pItem = &pHt->GetAttr();
2016 
2017                     const sal_uInt16 nHintEnd = *pAttrEnd;
2018 
2019                     while ( pItem )
2020                     {
2021                         const sal_uInt16 nHintWhich = pItem->Which();
2022                         ASSERT(!isUNKNOWNATR(nHintWhich),
2023                                 "SwTxtNode::GetAttr(): unkonwn attribute?");
2024 
2025                         if ( !pAttrArr.get() )
2026                         {
2027                             pAttrArr.reset(
2028                                 new std::vector< SwPoolItemEndPair >(coArrSz));
2029                         }
2030 
2031                         std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
2032                         if (isCHRATR(nHintWhich) ||
2033                             isTXTATR_WITHEND(nHintWhich))
2034                         {
2035                             pPrev += nHintWhich - RES_CHRATR_BEGIN;
2036                         }
2037                         else
2038                         {
2039                             pPrev = pAttrArr->end();
2040                         }
2041 
2042 #if OSL_DEBUG_LEVEL > 1
2043                         SwPoolItemEndPair aTmp = *pPrev;
2044 #endif
2045 
2046                         if( pPrev != pAttrArr->end() )
2047                         {
2048                             if( !pPrev->mpItem )
2049                             {
2050                                 if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
2051                                 {
2052                                     if( nAttrStart > nStt )
2053                                     {
2054                                         rSet.InvalidateItem( nHintWhich );
2055                                         pPrev->mpItem = (SfxPoolItem*)-1;
2056                                     }
2057                                     else
2058                                     {
2059                                         pPrev->mpItem = pItem;
2060                                         pPrev->mnEndPos = nHintEnd;
2061                                     }
2062                                 }
2063                             }
2064                             else if( (SfxPoolItem*)-1 != pPrev->mpItem )
2065                             {
2066                                 if( pPrev->mnEndPos == nAttrStart &&
2067                                     *pPrev->mpItem == *pItem )
2068                                 {
2069                                     pPrev->mpItem = pItem;
2070                                     pPrev->mnEndPos = nHintEnd;
2071                                 }
2072                                 else
2073                                 {
2074                                     rSet.InvalidateItem( nHintWhich );
2075                                     pPrev->mpItem = (SfxPoolItem*)-1;
2076                                 }
2077                             }
2078                         }
2079 
2080                         pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
2081                                     ? pItemIter->NextItem() : 0;
2082                     } // end while
2083                 }
2084 			}
2085 
2086             if ( pAttrArr.get() )
2087 			{
2088                 for (sal_uInt16 n = 0; n < coArrSz; ++n)
2089                 {
2090                     const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
2091                     if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
2092                     {
2093                         const sal_uInt16 nWh =
2094                             static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2095 
2096                         if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
2097                         {
2098                             if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
2099                                 (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2100                         }
2101                         else
2102                             // uneindeutig
2103                             rSet.InvalidateItem( nWh );
2104                     }
2105                 }
2106 			}
2107 		}
2108 		if( aFmtSet.Count() )
2109 		{
2110 			// aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
2111 			aFmtSet.Differentiate( rSet );
2112 			// jetzt alle zusammen "mergen"
2113 			rSet.Put( aFmtSet );
2114 		}
2115 	}
2116 	else if( !bOnlyTxtAttr )
2117     {
2118 		// dann besorge mal die Auto-(Fmt)Attribute
2119 		SwCntntNode::GetAttr( rSet );
2120         // --> OD 2008-01-16 #newlistlevelattrs#
2121         if ( bMergeIndentValuesOfNumRule )
2122         {
2123             lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
2124         }
2125         // <--
2126     }
2127 
2128 	return rSet.Count() ? sal_True : sal_False;
2129 }
2130 
2131 
2132 namespace
2133 {
2134 
2135 typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t;
2136 typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t;
2137 
2138 
2139 struct IsAutoStyle
2140 {
2141     bool
2142     operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2143     const
2144     {
2145         return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2146     }
2147 };
2148 
2149 
2150 /** Removes from io_rAttrSet all items that are set by style on the
2151     given span.
2152   */
2153 struct RemovePresentAttrs
2154 {
2155     RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2156         : m_rAttrSet(io_rAttrSet)
2157     {
2158     }
2159 
2160     void
2161     operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2162     const
2163     {
2164         if (!i_rAttrSpan.second)
2165         {
2166             return;
2167         }
2168 
2169         const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second);
2170         SfxItemIter aIter(m_rAttrSet);
2171         const SfxPoolItem* pItem(aIter.GetCurItem());
2172         while (pItem)
2173         {
2174             const sal_uInt16 nWhich(pItem->Which());
2175             if (CharFmt::IsItemIncluded(nWhich, pAutoStyle))
2176             {
2177                 m_rAttrSet.ClearItem(nWhich);
2178             }
2179 
2180             if (aIter.IsAtEnd())
2181             {
2182                 break;
2183             }
2184             pItem = aIter.NextItem();
2185         }
2186     }
2187 
2188 private:
2189     SfxItemSet& m_rAttrSet;
2190 };
2191 
2192 
2193 /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
2194     addition inserts dummy spans with pointer to format equal to 0 for
2195     all gaps (i.e. spans not covered by any style). This simplifies
2196     creation of autostyles for all needed spans, but it means all code
2197     that tries to access the pointer has to check if it's non-null!
2198  */
2199 void
2200 lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength,
2201         AttrSpanMap_t& o_rSpanMap)
2202 {
2203     sal_uInt16 nLastEnd(0);
2204 
2205     for (sal_uInt16 i(0); i != i_rHints.Count(); ++i)
2206     {
2207         const SwTxtAttr* const pHint(i_rHints[i]);
2208         const sal_uInt16 nWhich(pHint->Which());
2209         if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2210         {
2211             const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->GetEnd());
2212             o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
2213 
2214             // < not != because there may be multiple CHARFMT at same range
2215             if (nLastEnd < aSpan.first)
2216             {
2217                 // insert dummy span covering the gap
2218                 o_rSpanMap.insert(AttrSpanMap_t::value_type(
2219                             AttrSpan_t(nLastEnd, aSpan.first), 0));
2220             }
2221 
2222             nLastEnd = aSpan.second;
2223         }
2224     }
2225 
2226     // no hints at the end (special case: no hints at all in i_rHints)
2227     if (nLastEnd != nLength && nLength != 0)
2228     {
2229         o_rSpanMap.insert(
2230             AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), 0));
2231     }
2232 }
2233 
2234 
2235 void
2236 lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2237 {
2238     o_rClearIds.reserve(i_rAttrSet.Count());
2239     SfxItemIter aIter(i_rAttrSet);
2240     const SfxPoolItem* pItem(aIter.GetCurItem());
2241     while (true)
2242     {
2243         o_rClearIds.push_back(pItem->Which());
2244 
2245         if (aIter.IsAtEnd())
2246         {
2247             break;
2248         }
2249         pItem = aIter.NextItem();
2250     }
2251 }
2252 
2253 struct SfxItemSetClearer
2254 {
2255     SfxItemSet & m_rItemSet;
2256     SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2257     void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2258 };
2259 
2260 }
2261 
2262 
2263 /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion
2264     of items to automatic styles.
2265  */
2266 void
2267 SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
2268 {
2269     typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2270     AttrSpanMap_t aAttrSpanMap;
2271 
2272     if (i_rAttrSet.Count() == 0)
2273     {
2274         return;
2275     }
2276 
2277     // 1. Identify all spans in hints' array
2278 
2279     lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap);
2280 
2281     // 2. Go through all spans and insert new attrs
2282 
2283     AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2284     const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2285     while (aCurRange != aEnd)
2286     {
2287         typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2288             AttrSpanMapRange_t;
2289         AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2290 
2291         // 2a. Collect attributes to insert
2292 
2293         SfxItemSet aCurSet(i_rAttrSet);
2294         std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2295 
2296         // 2b. Insert automatic style containing the collected attributes
2297 
2298         if (aCurSet.Count() != 0)
2299         {
2300             AttrSpanMap_iterator_t aAutoStyleIt(
2301                     std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2302             if (aAutoStyleIt != aRange.second)
2303             {
2304                 // there already is an automatic style on that span:
2305                 // create new one and remove the original one
2306                 SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second));
2307                 const boost::shared_ptr<SfxItemSet> pOldStyle(
2308                         static_cast<const SwFmtAutoFmt&>(
2309                             pAutoStyle->GetAttr()).GetStyleHandle());
2310                 aCurSet.Put(*pOldStyle);
2311 
2312                 // remove the old hint
2313                 m_pSwpHints->Delete(pAutoStyle);
2314                 DestroyAttr(pAutoStyle);
2315             }
2316             m_pSwpHints->Insert(
2317                     MakeTxtAttr(*GetDoc(), aCurSet,
2318                         aCurRange->first.first, aCurRange->first.second));
2319         }
2320 
2321         aCurRange = aRange.second;
2322     }
2323 
2324     // 3. Clear items from the node
2325     std::vector<sal_uInt16> aClearedIds;
2326     lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2327     ClearItemsFromAttrSet(aClearedIds);
2328 }
2329 
2330 void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
2331 {
2332 	SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2333     if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2334 		aThisSet.Put( *GetpSwAttrSet() );
2335 
2336     GetOrCreateSwpHints();
2337 
2338 	if( pNd == this )
2339 	{
2340         impl_FmtToTxtAttr(aThisSet);
2341     }
2342 	else
2343 	{
2344         // There are five possible combinations of items from this and
2345         // pNd (pNd is the 'main' node):
2346         //
2347         //  case    pNd     this     action
2348         //  ----------------------------------------------------
2349         //     1     -       -      do nothing
2350         //     2     -       a      convert item to attr of this
2351         //     3     a       -      convert item to attr of pNd
2352         //     4     a       a      clear item in this
2353         //     5     a       b      convert item to attr of this
2354 
2355 		SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
2356         if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2357 			aNdSet.Put( *pNd->GetpSwAttrSet() );
2358 
2359         pNd->GetOrCreateSwpHints();
2360 
2361         std::vector<sal_uInt16> aProcessedIds;
2362 
2363 		if( aThisSet.Count() )
2364 		{
2365 			SfxItemIter aIter( aThisSet );
2366 			const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
2367             SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2368             std::vector<sal_uInt16> aClearWhichIds;
2369 
2370 			while( true )
2371 			{
2372 				if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) )
2373                 {
2374                     if (*pItem == *pNdItem) // 4
2375                     {
2376                         aClearWhichIds.push_back( pItem->Which() );
2377                     }
2378                     else    // 5
2379                     {
2380                         aConvertSet.Put(*pItem);
2381                     }
2382                     aProcessedIds.push_back(pItem->Which());
2383                 }
2384                 else    // 2
2385                 {
2386                     aConvertSet.Put(*pItem);
2387                 }
2388 
2389 				if( aIter.IsAtEnd() )
2390 					break;
2391 				pItem = aIter.NextItem();
2392 			}
2393 
2394             // 4/ clear items of this that are set with the same value on pNd
2395             ClearItemsFromAttrSet( aClearWhichIds );
2396 
2397             // 2, 5/ convert all other items to attrs
2398             impl_FmtToTxtAttr(aConvertSet);
2399         }
2400 
2401         {
2402             std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2403                     SfxItemSetClearer(aNdSet));
2404 
2405             // 3/ convert items to attrs
2406             pNd->impl_FmtToTxtAttr(aNdSet);
2407 
2408             if( aNdSet.Count() )
2409             {
2410                 SwFmtChg aTmp1( pNd->GetFmtColl() );
2411                 pNd->NotifyClients( &aTmp1, &aTmp1 );
2412             }
2413         }
2414     }
2415 
2416     SetCalcHiddenCharFlags();
2417 
2418     pNd->TryDeleteSwpHints();
2419 }
2420 
2421 /*************************************************************************
2422  *						SwpHints::CalcFlags()
2423  *************************************************************************/
2424 
2425 void SwpHints::CalcFlags()
2426 {
2427     m_bDDEFields = m_bFootnote = false;
2428     const sal_uInt16 nSize = Count();
2429     const SwTxtAttr* pAttr;
2430     for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2431     {
2432         switch( ( pAttr = (*this)[ nPos ])->Which() )
2433         {
2434         case RES_TXTATR_FTN:
2435             m_bFootnote = true;
2436             if ( m_bDDEFields )
2437                 return;
2438             break;
2439         case RES_TXTATR_FIELD:
2440             {
2441                 const SwField* pFld = pAttr->GetFmtFld().GetField();
2442                 if( RES_DDEFLD == pFld->GetTyp()->Which() )
2443                 {
2444                     m_bDDEFields = true;
2445                     if ( m_bFootnote )
2446                         return;
2447                 }
2448             }
2449             break;
2450         }
2451     }
2452 }
2453 
2454 /*************************************************************************
2455  *						SwpHints::CalcVisibleFlag()
2456  *************************************************************************/
2457 
2458 bool SwpHints::CalcHiddenParaField()
2459 {
2460     m_bCalcHiddenParaField = false;
2461     bool bOldHasHiddenParaField = m_bHasHiddenParaField;
2462     bool bNewHasHiddenParaField  = false;
2463 	const sal_uInt16	nSize = Count();
2464 	const SwTxtAttr *pTxtHt;
2465 
2466 	for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2467 	{
2468 		pTxtHt = (*this)[ nPos ];
2469 		const sal_uInt16 nWhich = pTxtHt->Which();
2470 
2471 		if( RES_TXTATR_FIELD == nWhich )
2472 		{
2473 			const SwFmtFld& rFld = pTxtHt->GetFmtFld();
2474             if( RES_HIDDENPARAFLD == rFld.GetField()->GetTyp()->Which() )
2475 			{
2476 				if( !((SwHiddenParaField*)rFld.GetField())->IsHidden() )
2477                 {
2478                     SetHiddenParaField(false);
2479                     return bOldHasHiddenParaField != bNewHasHiddenParaField;
2480                 }
2481                 else
2482                 {
2483                     bNewHasHiddenParaField = true;
2484                 }
2485             }
2486         }
2487     }
2488     SetHiddenParaField( bNewHasHiddenParaField );
2489     return bOldHasHiddenParaField != bNewHasHiddenParaField;
2490 }
2491 
2492 
2493 /*************************************************************************
2494  *						SwpHints::NoteInHistory()
2495  *************************************************************************/
2496 
2497 void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
2498 {
2499     if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2500 }
2501 
2502 /*************************************************************************
2503  *                      SwpHints::MergePortions( )
2504  *************************************************************************/
2505 
2506 bool SwpHints::MergePortions( SwTxtNode& rNode )
2507 {
2508     if ( !Count() )
2509         return false;
2510 
2511     // sort before merging
2512     SwpHintsArray::Resort();
2513 
2514     bool bRet = false;
2515     typedef std::multimap< int, SwTxtAttr* > PortionMap;
2516     PortionMap aPortionMap;
2517     xub_StrLen nLastPorStart = STRING_LEN;
2518     sal_uInt16 i = 0;
2519     int nKey = 0;
2520 
2521     // get portions by start position:
2522     for ( i = 0; i < Count(); ++i )
2523     {
2524         SwTxtAttr *pHt = GetTextHint( i );
2525         if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2526              RES_TXTATR_AUTOFMT != pHt->Which() )
2527              //&&
2528              //RES_TXTATR_INETFMT != pHt->Which() )
2529             continue;
2530 
2531         const xub_StrLen nPorStart = *pHt->GetStart();
2532         if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
2533             ++nKey;
2534         nLastPorStart = nPorStart;
2535         aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
2536     }
2537 
2538     // check if portion i can be merged with portion i+1:
2539     i = 0;
2540     int j = i + 1;
2541     while ( i <= nKey )
2542     {
2543         std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2544         std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2545         PortionMap::iterator aIter1 = aRange1.first;
2546         PortionMap::iterator aIter2 = aRange2.first;
2547 
2548         bool bMerge = true;
2549         const sal_uInt16 nAttributesInPor1  = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
2550         const sal_uInt16 nAttributesInPor2  = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
2551 
2552         if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
2553         {
2554             while ( aIter1 != aRange1.second )
2555             {
2556                 const SwTxtAttr* p1 = (*aIter1).second;
2557                 const SwTxtAttr* p2 = (*aIter2).second;
2558                 if ( *p1->GetEnd() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
2559                 {
2560                     bMerge = false;
2561                     break;
2562                 }
2563                 ++aIter1;
2564                 ++aIter2;
2565             }
2566         }
2567         else
2568         {
2569             bMerge = false;
2570         }
2571 
2572         if ( bMerge )
2573         {
2574             // erase all elements with key i + 1
2575             xub_StrLen nNewPortionEnd = 0;
2576             for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2577             {
2578                 SwTxtAttr* p2 = (*aIter2).second;
2579                 nNewPortionEnd = *p2->GetEnd();
2580 
2581                 const sal_uInt16 nCountBeforeDelete = Count();
2582                 Delete( p2 );
2583 
2584                 // robust: check if deletion actually took place before destroying attribute:
2585                 if ( Count() < nCountBeforeDelete )
2586                     rNode.DestroyAttr( p2 );
2587             }
2588             aPortionMap.erase( aRange2.first, aRange2.second );
2589             ++j;
2590 
2591             // change all attributes with key i
2592             aRange1 = aPortionMap.equal_range( i );
2593             for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2594             {
2595                 SwTxtAttr* p1 = (*aIter1).second;
2596                 NoteInHistory( p1 );
2597                 *p1->GetEnd() = nNewPortionEnd;
2598                 NoteInHistory( p1, true );
2599                 bRet = true;
2600             }
2601         }
2602         else
2603         {
2604             ++i;
2605             j = i + 1;
2606         }
2607     }
2608 
2609     if ( bRet )
2610     {
2611         SwpHintsArray::Resort();
2612     }
2613 
2614     return bRet;
2615 }
2616 
2617 // check if there is already a character format and adjust the sort numbers
2618 void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
2619 {
2620     const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
2621     const xub_StrLen nHtEnd   = *rNewCharFmt.GetEnd();
2622     sal_uInt16 nSortNumber = 0;
2623 
2624     for ( sal_uInt16 i = 0; i < rHints.Count(); ++i )
2625     {
2626         const SwTxtAttr* pOtherHt = rHints[i];
2627 
2628         const xub_StrLen nOtherStart = *pOtherHt->GetStart();
2629 
2630         if ( nOtherStart > nHtStart )
2631             break;
2632 
2633         if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2634         {
2635             const xub_StrLen nOtherEnd = *pOtherHt->GetEnd();
2636 
2637             if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2638             {
2639                 const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber();
2640                 nSortNumber = nOtherSortNum + 1;
2641             }
2642         }
2643     }
2644 
2645     if ( nSortNumber > 0 )
2646         rNewCharFmt.SetSortNumber( nSortNumber );
2647 }
2648 
2649 /*************************************************************************
2650  *						SwpHints::Insert()
2651  *************************************************************************/
2652 
2653 /*
2654  * Try to insert the new hint.
2655  * Depending on the type of the hint, this either always succeeds, or may fail.
2656  * Depending on the type of the hint, other hints may be deleted or
2657  * overwritten.
2658  * The return value indicates successful insertion.
2659  */
2660 bool SwpHints::TryInsertHint( SwTxtAttr* const pHint, SwTxtNode &rNode,
2661         const SetAttrMode nMode )
2662 {
2663     if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked...
2664     {
2665         ASSERT(false, "hints array full :-(");
2666         return false;
2667     }
2668 
2669 	// Felder bilden eine Ausnahme:
2670 	// 1) Sie koennen nie ueberlappen
2671 	// 2) Wenn zwei Felder genau aneinander liegen,
2672 	//	  sollen sie nicht zu einem verschmolzen werden.
2673 	// Wir koennen also auf die while-Schleife verzichten
2674 
2675     xub_StrLen *pHtEnd = pHint->GetEnd();
2676     sal_uInt16 nWhich = pHint->Which();
2677 
2678 	switch( nWhich )
2679 	{
2680 	case RES_TXTATR_CHARFMT:
2681     {
2682         // Check if character format contains hidden attribute:
2683         const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
2684         const SfxPoolItem* pItem;
2685         if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
2686             rNode.SetCalcHiddenCharFlags();
2687 
2688         ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
2689 		break;
2690     }
2691     // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary
2692     case RES_TXTATR_AUTOFMT:
2693     {
2694         // Check if auto style contains hidden attribute:
2695         const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
2696         if ( pHiddenItem )
2697             rNode.SetCalcHiddenCharFlags();
2698         break;
2699     }
2700     // <--
2701     case RES_TXTATR_INETFMT:
2702         static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
2703 		break;
2704 	case RES_TXTATR_FIELD:
2705 		{
2706 			sal_Bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
2707 			((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
2708 			SwDoc* pDoc = rNode.GetDoc();
2709 			const SwField* pFld = ((SwTxtFld*)pHint)->GetFmtFld().GetField();
2710 
2711 			if( !pDoc->IsNewFldLst() )
2712 			{
2713 				// was fuer ein Feld ist es denn ??
2714 				// bestimmte Felder mussen am Doc das Calculations-Flag updaten
2715 				switch( pFld->GetTyp()->Which() )
2716 				{
2717 				case RES_DBFLD:
2718 				case RES_SETEXPFLD:
2719 				case RES_HIDDENPARAFLD:
2720 				case RES_HIDDENTXTFLD:
2721 				case RES_DBNUMSETFLD:
2722 				case RES_DBNEXTSETFLD:
2723 					{
2724 						if( bDelFirst )
2725 							pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pHint );
2726 						if( rNode.GetNodes().IsDocNodes() )
2727 							pDoc->InsDelFldInFldLst( sal_True, *(SwTxtFld*)pHint );
2728 					}
2729 					break;
2730 				case RES_DDEFLD:
2731 					if( rNode.GetNodes().IsDocNodes() )
2732 						((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2733 					break;
2734 				}
2735 			}
2736 
2737             // gehts ins normale Nodes-Array?
2738             if( rNode.GetNodes().IsDocNodes() )
2739             {
2740                 sal_Bool bInsFldType = sal_False;
2741                 switch( pFld->GetTyp()->Which() )
2742                 {
2743                 case RES_SETEXPFLD:
2744                     bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
2745                     if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
2746                     {
2747                         // bevor die ReferenzNummer gesetzt wird, sollte
2748                         // das Feld am richtigen FeldTypen haengen!
2749                         SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
2750                                     pDoc->InsertFldType( *pFld->GetTyp() );
2751                         if( pFldType != pFld->GetTyp() )
2752                         {
2753                             SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)->GetFmtFld();
2754                             pFmtFld->RegisterToFieldType( *pFldType );
2755                             pFmtFld->GetField()->ChgTyp( pFldType );
2756                         }
2757                         pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
2758                     }
2759                     break;
2760                 case RES_USERFLD:
2761                     bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
2762                     break;
2763 
2764                 case RES_DDEFLD:
2765                     if( pDoc->IsNewFldLst() )
2766                         ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2767                     bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
2768                     break;
2769 
2770                 case RES_POSTITFLD:
2771                     if ( pDoc->GetDocShell() )
2772                         pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_INSERTED ) );
2773                     break;
2774                 }
2775                 if( bInsFldType )
2776                     pDoc->InsDeletedFldType( *pFld->GetTyp() );
2777             }
2778         }
2779         break;
2780     case RES_TXTATR_FTN :
2781 		((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
2782 		break;
2783 	case RES_TXTATR_REFMARK:
2784 		((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
2785 		if( rNode.GetNodes().IsDocNodes() )
2786 		{
2787             // search for a reference with the same name
2788 			SwTxtAttr* pTmpHt;
2789 			xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
2790 			for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n )
2791             {
2792                 if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
2793 					pHint->GetAttr() == pTmpHt->GetAttr() &&
2794 					0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
2795 					0 != ( pTmpHintEnd = pHint->GetEnd() ) )
2796 				{
2797 					SwComparePosition eCmp = ::ComparePosition(
2798 							*pTmpHt->GetStart(), *pTmpHtEnd,
2799 							*pHint->GetStart(), *pTmpHintEnd );
2800 					sal_Bool bDelOld = sal_True, bChgStart = sal_False, bChgEnd = sal_False;
2801 					switch( eCmp )
2802 					{
2803 					case POS_BEFORE:
2804 					case POS_BEHIND:	bDelOld = sal_False; break;
2805 
2806 					case POS_OUTSIDE:	bChgStart = bChgEnd = sal_True; break;
2807 
2808 					case POS_COLLIDE_END:
2809 					case POS_OVERLAP_BEFORE:	bChgStart = sal_True; break;
2810 					case POS_COLLIDE_START:
2811 					case POS_OVERLAP_BEHIND:    bChgEnd = sal_True; break;
2812                     default: break;
2813 					}
2814 
2815 					if( bChgStart )
2816 						*pHint->GetStart() = *pTmpHt->GetStart();
2817 					if( bChgEnd )
2818 						*pTmpHintEnd = *pTmpHtEnd;
2819 
2820 					if( bDelOld )
2821                     {
2822                         NoteInHistory( pTmpHt );
2823 						rNode.DestroyAttr( Cut( n-- ) );
2824 						--nEnd;
2825 					}
2826 				}
2827             }
2828 		}
2829 		break;
2830 	case RES_TXTATR_TOXMARK:
2831 		((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
2832 		break;
2833 
2834 	case RES_TXTATR_CJK_RUBY:
2835         static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode);
2836 		break;
2837 
2838     case RES_TXTATR_META:
2839     case RES_TXTATR_METAFIELD:
2840         static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode );
2841         break;
2842 
2843     case RES_CHRATR_HIDDEN:
2844         rNode.SetCalcHiddenCharFlags();
2845         break;
2846 	}
2847 
2848 	if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
2849 		pHint->SetDontExpand( sal_True );
2850 
2851 	// SwTxtAttrs ohne Ende werden sonderbehandelt:
2852 	// Sie werden natuerlich in das Array insertet, aber sie werden nicht
2853 	// in die pPrev/Next/On/Off-Verkettung aufgenommen.
2854 	// Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
2855 	xub_StrLen nHtStart = *pHint->GetStart();
2856 	if( !pHtEnd )
2857     {
2858         SwpHintsArray::Insert( pHint );
2859 		CalcFlags();
2860 #ifdef DBG_UTIL
2861         if( !rNode.GetDoc()->IsInReading() )
2862             CHECK;
2863 #endif
2864 		// ... und die Abhaengigen benachrichtigen
2865 		if ( rNode.GetDepends() )
2866 		{
2867 			SwUpdateAttr aHint( nHtStart, nHtStart, nWhich );
2868 			rNode.ModifyNotification( 0, &aHint );
2869         }
2870         return true;
2871     }
2872 
2873 	// ----------------------------------------------------------------
2874 	// Ab hier gibt es nur noch pHint mit einem EndIdx !!!
2875 
2876     if( *pHtEnd < nHtStart )
2877 	{
2878 		ASSERT( *pHtEnd >= nHtStart,
2879 					"+SwpHints::Insert: invalid hint, end < start" );
2880 
2881 		// Wir drehen den Quatsch einfach um:
2882 		*pHint->GetStart() = *pHtEnd;
2883 		*pHtEnd = nHtStart;
2884 		nHtStart = *pHint->GetStart();
2885 	}
2886 
2887     // I need this value later on for notification but the pointer may become invalid
2888     const xub_StrLen nHintEnd = *pHtEnd;
2889     const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
2890 
2891     // handle nesting attributes: inserting may fail due to overlap!
2892     if (pHint->IsNesting())
2893     {
2894         const bool bRet(
2895             TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint)));
2896         if (!bRet) return false;
2897     }
2898     // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
2899     // These attributes may be inserted directly.
2900     // Also attributes without length may be inserted directly.
2901     // SETATTR_NOHINTADJUST is set e.g., during undo.
2902     // Portion building in not necessary during XML import.
2903     else
2904     if ( !bNoHintAdjustMode &&
2905          !pHint->IsOverlapAllowedAttr() &&
2906          !rNode.GetDoc()->IsInXMLImport() &&
2907          ( RES_TXTATR_AUTOFMT == nWhich ||
2908            RES_TXTATR_CHARFMT == nWhich ) )
2909     {
2910         ASSERT( nWhich != RES_TXTATR_AUTOFMT ||
2911                 static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
2912                 &rNode.GetDoc()->GetAttrPool(),
2913                 "AUTOSTYLES - Pool mismatch" )
2914 
2915         BuildPortions( rNode, *pHint, nMode );
2916 
2917         if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
2918             MergePortions( rNode );
2919     }
2920     else
2921     {
2922         // There may be more than one character style at the current position.
2923         // Take care of the sort number.
2924         // Special case ruby portion: During import, the ruby attribute is set
2925         // multiple times
2926         // Special case hyperlink: During import, the ruby attribute is set
2927         // multiple times
2928         // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
2929         // character attributes directly
2930         if ( ( RES_TXTATR_CHARFMT  == nWhich && !bNoHintAdjustMode ) )
2931         {
2932             BuildPortions( rNode, *pHint, nMode );
2933         }
2934         else
2935         {
2936             // --> FME 2007-11-08 #i82989# Check sort numbers in NoHintAdjustMode
2937             if ( RES_TXTATR_CHARFMT == nWhich )
2938                 lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
2939             // <--
2940 
2941             SwpHintsArray::Insert( pHint );
2942             NoteInHistory( pHint, true );
2943         }
2944     }
2945 
2946     // ... und die Abhaengigen benachrichtigen
2947 	if ( rNode.GetDepends() )
2948 	{
2949 		SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich );
2950 		rNode.ModifyNotification( 0, &aHint );
2951 	}
2952 
2953 #ifdef DBG_UTIL
2954     if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
2955         CHECK;
2956 #endif
2957 
2958     return true;
2959 }
2960 
2961 /*************************************************************************
2962  *						SwpHints::DeleteAtPos()
2963  *************************************************************************/
2964 
2965 void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
2966 {
2967     SwTxtAttr *pHint = GetTextHint(nPos);
2968     // ChainDelete( pHint );
2969     NoteInHistory( pHint );
2970     SwpHintsArray::DeleteAtPos( nPos );
2971 
2972     if( RES_TXTATR_FIELD == pHint->Which() )
2973     {
2974         const SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFmtFld().GetField()->GetTyp();
2975         if( RES_DDEFLD == pFldTyp->Which() )
2976         {
2977             const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
2978             if( pNd && pNd->GetNodes().IsDocNodes() )
2979                 ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
2980             ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
2981         }
2982         else if( RES_POSTITFLD == pFldTyp->Which() )
2983         {
2984             const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_REMOVED ) );
2985         }
2986         else if ( m_bHasHiddenParaField &&
2987                  RES_HIDDENPARAFLD == pFldTyp->Which() )
2988         {
2989             m_bCalcHiddenParaField = true;
2990         }
2991     }
2992 
2993     CalcFlags();
2994     CHECK;
2995 }
2996 
2997 // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
2998 // Ist er nicht im Array, so gibt es ein ASSERT !!
2999 
3000 void SwpHints::Delete( SwTxtAttr* pTxtHt )
3001 {
3002 	// Attr 2.0: SwpHintsArr::Delete( pTxtHt );
3003 	const sal_uInt16 nPos = GetStartOf( pTxtHt );
3004 	ASSERT( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
3005 	if( USHRT_MAX != nPos )
3006 		DeleteAtPos( nPos );
3007 }
3008 
3009 void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
3010 {
3011     if ( HasHints() )
3012     {
3013         sal_uInt16 nPos = 0;
3014         while ( nPos < m_pSwpHints->Count() )
3015         {
3016             SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
3017             bool bDel = false;
3018 
3019             switch( pDel->Which() )
3020             {
3021             case RES_TXTATR_FLYCNT:
3022             case RES_TXTATR_FTN:
3023                 break;
3024 
3025             case RES_TXTATR_FIELD:
3026                 if( bDelFields )
3027                     bDel = true;
3028                 break;
3029             default:
3030                 bDel = true; break;
3031             }
3032 
3033             if( bDel )
3034             {
3035                 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
3036 				DestroyAttr( pDel );
3037 			}
3038 			else
3039 				++nPos;
3040 		}
3041 	}
3042 }
3043 
3044 sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
3045                            sal_uInt16 nScript ) const
3046 {
3047 	sal_uInt16 nRet = LANGUAGE_DONTKNOW;
3048 
3049     if ( ! nScript )
3050     {
3051         nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
3052     }
3053 
3054     // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0
3055     const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
3056     // <--
3057 
3058     if ( HasHints() )
3059     {
3060         const xub_StrLen nEnd = nBegin + nLen;
3061         for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
3062         {
3063 			// ist der Attribut-Anfang schon groesser als der Idx ?
3064             const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
3065             const xub_StrLen nAttrStart = *pHt->GetStart();
3066 			if( nEnd < nAttrStart )
3067 				break;
3068 
3069 			const sal_uInt16 nWhich = pHt->Which();
3070 
3071             if( nWhichId == nWhich ||
3072                     ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
3073             {
3074 				const xub_StrLen *pEndIdx = pHt->GetEnd();
3075 				// Ueberlappt das Attribut den Bereich?
3076 
3077 				if( pEndIdx &&
3078 					nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
3079 					 	: (( nAttrStart < nBegin &&
3080 								( pHt->DontExpand() ? nBegin < *pEndIdx
3081 													: nBegin <= *pEndIdx )) ||
3082 							( nBegin == nAttrStart &&
3083 								( nAttrStart == *pEndIdx || !nBegin ))) )
3084 				{
3085                     const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
3086                     sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
3087 
3088 					// Umfasst das Attribut den Bereich komplett?
3089 					if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
3090 						nRet = nLng;
3091 					else if( LANGUAGE_DONTKNOW == nRet )
3092 						nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
3093 				}
3094 			}
3095 		}
3096 	}
3097 	if( LANGUAGE_DONTKNOW == nRet )
3098 	{
3099 		nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
3100 		if( LANGUAGE_DONTKNOW == nRet )
3101             nRet = static_cast<sal_uInt16>(GetAppLanguage());
3102 	}
3103 	return nRet;
3104 }
3105 
3106 
3107 sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
3108 {
3109     sal_Unicode cRet = CH_TXTATR_BREAKWORD;
3110     switch ( rAttr.Which() )
3111     {
3112         case RES_TXTATR_FTN:
3113         case RES_TXTATR_REFMARK:
3114         case RES_TXTATR_TOXMARK:
3115         case RES_TXTATR_META:
3116         case RES_TXTATR_METAFIELD:
3117             cRet = CH_TXTATR_INWORD;
3118         break;
3119 
3120         case RES_TXTATR_FIELD:
3121         case RES_TXTATR_FLYCNT:
3122         {
3123             cRet = CH_TXTATR_BREAKWORD;
3124 
3125             // #i78149: PostIt fields should not break words for spell and grammar checking
3126             if (rAttr.Which() == RES_TXTATR_FIELD &&
3127                 RES_POSTITFLD == rAttr.GetFmtFld().GetField()->GetTyp()->Which())
3128                 cRet = CH_TXTATR_INWORD;
3129         }
3130         break;
3131 
3132         default:
3133             ASSERT(false, "GetCharOfTxtAttr: unknown attr");
3134             break;
3135     }
3136     return cRet;
3137 }
3138 
3139 
3140