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