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