xref: /aoo42x/main/sw/source/core/txtnode/thints.cxx (revision 69a74367)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <hintids.hxx>
29 #include <sot/factory.hxx>
30 #include <editeng/xmlcnitm.hxx>
31 #include <svl/whiter.hxx>
32 #include <svl/itemiter.hxx>
33 #include <svl/stylepool.hxx>
34 #include <editeng/fontitem.hxx>
35 #include <editeng/langitem.hxx>
36 #include <editeng/emphitem.hxx>
37 #include <editeng/charscaleitem.hxx>
38 #include <editeng/charrotateitem.hxx>
39 // --> OD 2008-01-16 #newlistlevelattrs#
40 #include <editeng/lrspitem.hxx>
41 // <--
42 #include <txtinet.hxx>
43 #include <txtflcnt.hxx>
44 #include <fmtfld.hxx>
45 #include <fmtanchr.hxx>
46 #include <fmtinfmt.hxx>
47 #include <txtatr.hxx>
48 #include <fchrfmt.hxx>
49 #include <fmtautofmt.hxx>
50 #include <fmtflcnt.hxx>
51 #include <fmtftn.hxx>
52 #include <txttxmrk.hxx>
53 #include <txtrfmrk.hxx>
54 #include <txtftn.hxx>
55 #include <txtfld.hxx>
56 #include <charatr.hxx>
57 #include <charfmt.hxx>
58 #include <frmfmt.hxx>
59 #include <ftnidx.hxx>
60 #include <fmtruby.hxx>
61 #include <fmtmeta.hxx>
62 #include <breakit.hxx>
63 #include <doc.hxx>
64 #include <IDocumentUndoRedo.hxx>
65 #include <errhdl.hxx>
66 #include <fldbas.hxx>
67 #include <pam.hxx>
68 #include <ndtxt.hxx>
69 #include <txtfrm.hxx>
70 #include <rolbck.hxx>			// fuer	SwRegHistory
71 #include <ddefld.hxx>
72 #include <docufld.hxx>
73 #include <expfld.hxx>
74 #include <usrfld.hxx>
75 #include <poolfmt.hxx>
76 #include <swfont.hxx>
77 #include <istyleaccess.hxx>
78 // OD 26.06.2003 #108784#
79 #include <dcontact.hxx>
80 #include <docsh.hxx>
81 #include <svl/smplhint.hxx>
82 #include <algorithm>
83 #include <map>
84 
85 #ifdef DBG_UTIL
86 #define CHECK    Check();
87 #else
88 #define CHECK
89 #endif
90 
91 using namespace ::com::sun::star::i18n;
92 
93 
94 SwpHints::SwpHints()
95     : m_pHistory(0)
96     , m_bFontChange(true)
97     , m_bInSplitNode(false)
98     , m_bCalcHiddenParaField(false)
99     , m_bHasHiddenParaField(false)
100     , m_bFootnote(false)
101     , m_bDDEFields(false)
102 {
103 }
104 
105 struct TxtAttrDeleter
106 {
107     SwAttrPool & m_rPool;
108     TxtAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { }
109     void operator() (SwTxtAttr * const pAttr)
110     {
111         if (RES_TXTATR_META == pAttr->Which() ||
112             RES_TXTATR_METAFIELD == pAttr->Which())
113         {
114             static_cast<SwTxtMeta *>(pAttr)->ChgTxtNode(0); // prevents ASSERT
115         }
116         SwTxtAttr::Destroy( pAttr, m_rPool );
117     }
118 };
119 
120 struct TxtAttrContains
121 {
122     xub_StrLen m_nPos;
123     TxtAttrContains( const xub_StrLen nPos ) : m_nPos( nPos ) { }
124     bool operator() (SwTxtAttrEnd * const pAttr)
125     {
126         return (*pAttr->GetStart() < m_nPos) && (m_nPos < *pAttr->End());
127     }
128 };
129 
130 // a:       |-----|
131 // b:
132 //    |---|               => valid: b before a
133 //    |-----|             => valid: start == end; b before a
134 //    |---------|         => invalid: overlap (1)
135 //    |-----------|       => valid: same end; b around a
136 //    |-----------------| => valid: b around a
137 //          |---|         => valid; same start; b within a
138 //          |-----|       => valid; same start and end; b around or within a?
139 //          |-----------| => valid: same start: b around a
140 //            |-|         => valid: b within a
141 //            |---|       => valid: same end; b within a
142 //            |---------| => invalid: overlap (2)
143 //                |-----| => valid: end == start; b after a
144 //                  |---| => valid: b after a
145 // ===> 2 invalid overlap cases
146 static
147 bool isOverlap(const xub_StrLen nStart1, const xub_StrLen nEnd1,
148                const xub_StrLen nStart2, const xub_StrLen nEnd2)
149 {
150     return
151         ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2))  // (1)
152      || ((nStart1 < nStart2) && (nStart2 < nEnd1) && (nEnd1 < nEnd2)); // (2)
153 }
154 
155 /// #i106930#: now asymmetric: empty hint1 is _not_ nested, but empty hint2 is
156 static
157 bool isNestedAny(const xub_StrLen nStart1, const xub_StrLen nEnd1,
158                  const xub_StrLen nStart2, const xub_StrLen nEnd2)
159 {
160     return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
161         // same start/end: nested except if hint1 empty and hint2 not empty
162         ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
163         : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
164 }
165 
166 static
167 bool isSelfNestable(const sal_uInt16 nWhich)
168 {
169     if ((RES_TXTATR_INETFMT  == nWhich) ||
170         (RES_TXTATR_CJK_RUBY == nWhich) ||
171         (RES_TXTATR_INPUTFIELD == nWhich))
172         return false;
173     ASSERT((RES_TXTATR_META  == nWhich) ||
174            (RES_TXTATR_METAFIELD  == nWhich), "???");
175     return true;
176 }
177 
178 static
179 bool isSplittable(const sal_uInt16 nWhich)
180 {
181     if ((RES_TXTATR_INETFMT  == nWhich) ||
182         (RES_TXTATR_CJK_RUBY == nWhich))
183         return true;
184     ASSERT((RES_TXTATR_META  == nWhich) ||
185            (RES_TXTATR_METAFIELD  == nWhich) ||
186            (RES_TXTATR_INPUTFIELD  == nWhich), "???");
187     return false;
188 }
189 
190 enum Split_t { FAIL, SPLIT_NEW, SPLIT_OTHER };
191 /**
192   Calculate splitting policy for overlapping hints, based on what kind of
193   hint is inserted, and what kind of existing hint overlaps.
194   */
195 static Split_t
196 splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
197 {
198     if (!isSplittable(nWhichOther))
199     {
200         if (!isSplittable(nWhichNew))
201             return FAIL;
202         else
203             return SPLIT_NEW;
204     }
205     else
206     {
207         if ( RES_TXTATR_INPUTFIELD == nWhichNew )
208             return FAIL;
209         else 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 bNewSelfNestable( isSelfNestable(nNewWhich) );
370 
371     ASSERT( (RES_TXTATR_INETFMT   == nNewWhich) ||
372             (RES_TXTATR_CJK_RUBY  == nNewWhich) ||
373             (RES_TXTATR_META      == nNewWhich) ||
374             (RES_TXTATR_METAFIELD == nNewWhich) ||
375             (RES_TXTATR_INPUTFIELD == nNewWhich),
376         "TryInsertNesting: Expecting INETFMT or RUBY or META or METAFIELD or INPUTFIELD" );
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->End();
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(
997     SwDoc & rDoc,
998     SfxPoolItem& rAttr,
999     xub_StrLen const nStt,
1000     xub_StrLen const nEnd,
1001     CopyOrNew_t const bIsCopy,
1002     SwTxtNode *const pTxtNode )
1003 {
1004     if ( isCHRATR(rAttr.Which()) )
1005     {
1006         // Somebody wants to build a SwTxtAttr for a character attribute.
1007         // Sorry, this is not allowed any longer.
1008         // You'll get a brand new autostyle attribute:
1009         SfxItemSet aItemSet( rDoc.GetAttrPool(),
1010                 RES_CHRATR_BEGIN, RES_CHRATR_END );
1011         aItemSet.Put( rAttr );
1012         return MakeTxtAttr( rDoc, aItemSet, nStt, nEnd );
1013     }
1014     else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
1015               static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()->
1016                 GetPool() != &rDoc.GetAttrPool() )
1017     {
1018         // If the attribute is an auto-style which refers to a pool that is
1019         // different from rDoc's pool, we have to correct this:
1020         const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle();
1021         ::std::auto_ptr<const SfxItemSet> pNewSet(
1022                 pAutoStyle->SfxItemSet::Clone( sal_True, &rDoc.GetAttrPool() ));
1023         SwTxtAttr* pNew = MakeTxtAttr( rDoc, *pNewSet, nStt, nEnd );
1024         return pNew;
1025     }
1026 
1027     // Put new attribute into pool
1028     // FIXME: this const_cast is evil!
1029     SfxPoolItem& rNew =
1030         const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
1031 
1032 	SwTxtAttr* pNew = 0;
1033 	switch( rNew.Which() )
1034 	{
1035     case RES_TXTATR_CHARFMT:
1036 		{
1037 			SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
1038 			if( !rFmtCharFmt.GetCharFmt() )
1039             {
1040                 rFmtCharFmt.SetCharFmt( rDoc.GetDfltCharFmt() );
1041             }
1042 
1043 			pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
1044 		}
1045 		break;
1046 	case RES_TXTATR_INETFMT:
1047 		pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
1048 		break;
1049     case RES_TXTATR_FIELD:
1050         pNew = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt );
1051         break;
1052     case RES_TXTATR_INPUTFIELD:
1053         pNew = new SwTxtInputFld( static_cast<SwFmtFld &>(rNew), nStt, nEnd );
1054         break;
1055 	case RES_TXTATR_FLYCNT:
1056 		{
1057 			// erst hier wird das Frame-Format kopiert (mit Inhalt) !!
1058 			pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
1059 			// Kopie von einem Text-Attribut
1060             if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() )
1061             {
1062                 // then the format must be copied
1063                 static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc );
1064             }
1065         }
1066         break;
1067 	case RES_TXTATR_FTN:
1068 		pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
1069 		// ggfs. SeqNo kopieren
1070 		if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
1071 			((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
1072 		break;
1073 	case RES_TXTATR_REFMARK:
1074 		pNew = nStt == nEnd
1075 				? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
1076 				: new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
1077 		break;
1078 	case RES_TXTATR_TOXMARK:
1079 		pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd );
1080 		break;
1081 	case RES_TXTATR_CJK_RUBY:
1082 		pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd );
1083 		break;
1084     case RES_TXTATR_META:
1085     case RES_TXTATR_METAFIELD:
1086         pNew = SwTxtMeta::CreateTxtMeta( rDoc.GetMetaFieldManager(), pTxtNode,
1087                 static_cast<SwFmtMeta&>(rNew), nStt, nEnd, bIsCopy );
1088         break;
1089     default:
1090         ASSERT(RES_TXTATR_AUTOFMT == rNew.Which(), "unknown attribute");
1091         pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
1092         break;
1093     }
1094 
1095     return pNew;
1096 }
1097 
1098 SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet,
1099                         xub_StrLen nStt, xub_StrLen nEnd )
1100 {
1101     IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
1102     const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
1103     SwFmtAutoFmt aNewAutoFmt;
1104     aNewAutoFmt.SetStyleHandle( pAutoStyle );
1105     SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd );
1106     return pNew;
1107 }
1108 
1109 
1110 // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
1111 void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
1112 {
1113 	if( pAttr )
1114 	{
1115 		// einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
1116 		SwDoc* pDoc = GetDoc();
1117 		sal_uInt16 nDelMsg = 0;
1118 		switch( pAttr->Which() )
1119 		{
1120 		case RES_TXTATR_FLYCNT:
1121 			{
1122 				// siehe auch die Anmerkung "Loeschen von Formaten
1123 				// zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFmt()
1124 				SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1125 				if( pFmt )		// vom Undo auf 0 gesetzt ??
1126 					pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt );
1127 			}
1128 			break;
1129 
1130         case RES_CHRATR_HIDDEN:
1131             SetCalcHiddenCharFlags();
1132             break;
1133 
1134 		case RES_TXTATR_FTN:
1135 			((SwTxtFtn*)pAttr)->SetStartNode( 0 );
1136 			nDelMsg = RES_FOOTNOTE_DELETED;
1137 			break;
1138 
1139 		case RES_TXTATR_FIELD:
1140 		case RES_TXTATR_INPUTFIELD:
1141 			if( !pDoc->IsInDtor() )
1142 			{
1143 				// Wenn wir ein HiddenParaField sind, dann muessen wir
1144 				// ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
1145 				const SwField* pFld = pAttr->GetFmtFld().GetField();
1146 
1147 				//JP 06-08-95: DDE-Felder bilden eine Ausnahme
1148 				ASSERT( RES_DDEFLD == pFld->GetTyp()->Which() ||
1149 						this == ((SwTxtFld*)pAttr)->GetpTxtNode(),
1150 						"Wo steht denn dieses Feld?" )
1151 
1152 				// bestimmte Felder mussen am Doc das Calculations-Flag updaten
1153 				switch( pFld->GetTyp()->Which() )
1154 				{
1155 				case RES_HIDDENPARAFLD:
1156                     SetCalcHiddenParaField();
1157 					// kein break !
1158 				case RES_DBSETNUMBERFLD:
1159 				case RES_GETEXPFLD:
1160 				case RES_DBFLD:
1161 				case RES_SETEXPFLD:
1162 				case RES_HIDDENTXTFLD:
1163 				case RES_DBNUMSETFLD:
1164 				case RES_DBNEXTSETFLD:
1165 					if( !pDoc->IsNewFldLst() && GetNodes().IsDocNodes() )
1166 						pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pAttr );
1167 					break;
1168 				case RES_DDEFLD:
1169 					if( GetNodes().IsDocNodes() &&
1170 						((SwTxtFld*)pAttr)->GetpTxtNode() )
1171 						((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt();
1172 					break;
1173 				case RES_POSTITFLD:
1174 					{
1175 						const_cast<SwFmtFld&>(pAttr->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFmtFld(), SWFMTFLD_REMOVED ) );
1176 						break;
1177 					}
1178 				}
1179 			}
1180 			nDelMsg = RES_FIELD_DELETED;
1181 			break;
1182 
1183 		case RES_TXTATR_TOXMARK:
1184             static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
1185 			break;
1186 
1187 		case RES_TXTATR_REFMARK:
1188 			nDelMsg = RES_REFMARK_DELETED;
1189 			break;
1190 
1191         case RES_TXTATR_META:
1192         case RES_TXTATR_METAFIELD:
1193             static_cast<SwTxtMeta*>(pAttr)->ChgTxtNode(0);
1194             break;
1195 
1196         default:
1197             break;
1198 		}
1199 
1200 		if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() )
1201 		{
1202 			SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() );
1203 			pDoc->GetUnoCallBack()->ModifyNotification( &aMsgHint, &aMsgHint );
1204 		}
1205 
1206         SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() );
1207     }
1208 }
1209 
1210 /*************************************************************************
1211  *						SwTxtNode::Insert()
1212  *************************************************************************/
1213 
1214 SwTxtAttr*
1215 SwTxtNode::InsertItem( SfxPoolItem& rAttr,
1216       const xub_StrLen nStart, const xub_StrLen nEnd, const SetAttrMode nMode )
1217 {
1218    // character attributes will be inserted as automatic styles:
1219     ASSERT( !isCHRATR(rAttr.Which()), "AUTOSTYLES - "
1220         "SwTxtNode::InsertItem should not be called with character attributes");
1221 
1222     SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(), rAttr, nStart, nEnd,
1223             (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW, this );
1224 
1225     if ( pNew )
1226     {
1227         const bool bSuccess( InsertHint( pNew, nMode ) );
1228         // N.B.: also check that the hint is actually in the hints array,
1229         // because hints of certain types may be merged after succesful
1230         // insertion, and thus destroyed!
1231         if (!bSuccess || ( USHRT_MAX == m_pSwpHints->GetPos( pNew ) ))
1232         {
1233             return 0;
1234         }
1235     }
1236 
1237     return pNew;
1238 }
1239 
1240 // take ownership of pAttr; if insertion fails, delete pAttr
1241 bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode )
1242 {
1243     bool bHiddenPara = false;
1244 
1245     ASSERT( pAttr && *pAttr->GetStart() <= Len(), "StartIdx out of bounds!" );
1246     ASSERT( !pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()),
1247             "EndIdx out of bounds!" );
1248 
1249     // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR)
1250     const enum IDocumentContentOperations::InsertFlags nInsertFlags =
1251         (nMode & nsSetAttrMode::SETATTR_FORCEHINTEXPAND)
1252         ? static_cast<IDocumentContentOperations::InsertFlags>(
1253                 IDocumentContentOperations::INS_FORCEHINTEXPAND |
1254                 IDocumentContentOperations::INS_EMPTYEXPAND)
1255         : IDocumentContentOperations::INS_EMPTYEXPAND;
1256 
1257     // need this after TryInsertHint, when pAttr may be deleted
1258     const xub_StrLen nStart( *pAttr->GetStart() );
1259     const bool bDummyChar( pAttr->HasDummyChar() );
1260     if (bDummyChar)
1261     {
1262         sal_uInt16 nInsMode = nMode;
1263         switch( pAttr->Which() )
1264         {
1265         case RES_TXTATR_FLYCNT:
1266             {
1267                 SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
1268                 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1269                 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1270                 {
1271                     // Wir muessen zuerst einfuegen, da in SetAnchor()
1272                     // dem FlyFrm GetStart() uebermittelt wird.
1273                     //JP 11.05.98: falls das Anker-Attribut schon richtig
1274                     // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
1275                     // des Zeichens. Sonst muesste das immer  ausserhalb
1276                     // erfolgen (Fehleranfaellig !)
1277                     const SwFmtAnchor* pAnchor = 0;
1278                     pFmt->GetItemState( RES_ANCHOR, sal_False,
1279                         (const SfxPoolItem**)&pAnchor );
1280 
1281                     SwIndex aIdx( this, *pAttr->GetStart() );
1282                     const sal_Unicode c = GetCharOfTxtAttr(*pAttr);
1283                     InsertText( c, aIdx, nInsertFlags );
1284                     nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1285 
1286                     if (pAnchor &&
1287                         (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
1288                         pAnchor->GetCntntAnchor() &&
1289                         pAnchor->GetCntntAnchor()->nNode == *this &&
1290                         pAnchor->GetCntntAnchor()->nContent == aIdx )
1291                     {
1292                         const_cast<SwIndex&>(
1293                             pAnchor->GetCntntAnchor()->nContent)--;
1294                     }
1295                 }
1296                 pFly->SetAnchor( this );
1297 
1298                 // Format-Pointer kann sich im SetAnchor geaendert haben!
1299                 // (Kopieren in andere Docs!)
1300                 pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1301                 SwDoc *pDoc = pFmt->GetDoc();
1302 
1303                 // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
1304                 // But don't allow control objects in header/footer
1305                 if( RES_DRAWFRMFMT == pFmt->Which() &&
1306                     pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) )
1307                 {
1308                     SwDrawContact* pDrawContact =
1309                         static_cast<SwDrawContact*>(pFmt->FindContactObj());
1310                     if ( pDrawContact &&
1311                          pDrawContact->GetMaster() &&
1312                          ::CheckControlLayer( pDrawContact->GetMaster() ) )
1313                     {
1314                         // das soll nicht meoglich sein; hier verhindern
1315                         // Der Dtor des TxtHints loescht nicht das Zeichen.
1316                         // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1317                         // dieses explizit loeschen
1318                         if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1319                         {
1320                             // loesche das Zeichen aus dem String !
1321                             ASSERT( ( CH_TXTATR_BREAKWORD ==
1322                                         m_Text.GetChar(*pAttr->GetStart() ) ||
1323                                       CH_TXTATR_INWORD ==
1324                                         m_Text.GetChar(*pAttr->GetStart())),
1325                                     "where is my attribute character?" );
1326                             m_Text.Erase( *pAttr->GetStart(), 1 );
1327                             // Indizies Updaten
1328                             SwIndex aTmpIdx( this, *pAttr->GetStart() );
1329                             Update( aTmpIdx, 1, sal_True );
1330                         }
1331                         // do not record deletion of Format!
1332                         ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1333                         DestroyAttr( pAttr );
1334                         return false;
1335                     }
1336                 }
1337                 break;
1338             }
1339 
1340         case RES_TXTATR_FTN :
1341             {
1342                 // Fussnoten, man kommt an alles irgendwie heran.
1343                 // CntntNode erzeugen und in die Inserts-Section stellen
1344                 SwDoc *pDoc = GetDoc();
1345                 SwNodes &rNodes = pDoc->GetNodes();
1346 
1347                 // FussNote in nicht Content-/Redline-Bereich einfuegen ??
1348                 if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
1349                 {
1350                     // das soll nicht meoglich sein; hier verhindern
1351                     // Der Dtor des TxtHints loescht nicht das Zeichen.
1352                     // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1353                     // dieses explizit loeschen
1354                     if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1355                     {
1356                         // loesche das Zeichen aus dem String !
1357                         ASSERT( ( CH_TXTATR_BREAKWORD ==
1358                             m_Text.GetChar(*pAttr->GetStart() ) ||
1359                             CH_TXTATR_INWORD ==
1360                             m_Text.GetChar(*pAttr->GetStart())),
1361                             "where is my attribute character?" );
1362                         m_Text.Erase( *pAttr->GetStart(), 1 );
1363                         // Indizies Updaten
1364                         SwIndex aTmpIdx( this, *pAttr->GetStart() );
1365                         Update( aTmpIdx, 1, sal_True );
1366                     }
1367                     DestroyAttr( pAttr );
1368                     return false;
1369                 }
1370 
1371                 // wird eine neue Fussnote eingefuegt ??
1372                 sal_Bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
1373                 if( bNewFtn )
1374                 {
1375                     ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
1376                     SwRegHistory* pHist = GetpSwpHints()
1377                         ? GetpSwpHints()->GetHistory() : 0;
1378                     if( pHist )
1379                         pHist->ChangeNodeIndex( GetIndex() );
1380                 }
1381                 else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
1382                 {
1383                     // loesche alle Frames der Section, auf die der StartNode zeigt
1384                     sal_uLong nSttIdx =
1385                         ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex();
1386                     sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
1387                     SwCntntNode* pCNd;
1388                     for( ; nSttIdx < nEndIdx; ++nSttIdx )
1389                         if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() ))
1390                             pCNd->DelFrms();
1391                 }
1392 
1393                 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1394                 {
1395                     // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
1396                     // entstehen koennen und das Attribut im _SortArr_ am
1397                     // Dokument nicht eingetrage wird.
1398                     SwIndex aNdIdx( this, *pAttr->GetStart() );
1399                     const sal_Unicode c = GetCharOfTxtAttr(*pAttr);
1400                     InsertText( c, aNdIdx, nInsertFlags );
1401                     nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1402                 }
1403 
1404                 // Wir tragen uns am FtnIdx-Array des Docs ein ...
1405                 SwTxtFtn* pTxtFtn = 0;
1406                 if( !bNewFtn )
1407                 {
1408                     // eine alte Ftn wird umgehaengt (z.B. SplitNode)
1409                     for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().Count(); ++n )
1410                         if( pAttr == pDoc->GetFtnIdxs()[n] )
1411                         {
1412                             // neuen Index zuweisen, dafuer aus dem SortArray
1413                             // loeschen und neu eintragen
1414                             pTxtFtn = pDoc->GetFtnIdxs()[n];
1415                             pDoc->GetFtnIdxs().Remove( n );
1416                             break;
1417                         }
1418                         // wenn ueber Undo der StartNode gesetzt wurde, kann
1419                         // der Index noch gar nicht in der Verwaltung stehen !!
1420                 }
1421                 if( !pTxtFtn )
1422                     pTxtFtn = (SwTxtFtn*)pAttr;
1423 
1424                 // fuers Update der Nummern und zum Sortieren
1425                 // muss der Node gesetzt sein.
1426                 ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
1427 
1428                 // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
1429                 if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
1430                 {
1431 #ifdef DBG_UTIL
1432                     const sal_Bool bSuccess =
1433 #endif
1434                         pDoc->GetFtnIdxs().Insert( pTxtFtn );
1435 #ifdef DBG_UTIL
1436                     ASSERT( bSuccess, "FtnIdx nicht eingetragen." );
1437 #endif
1438                 }
1439                 SwNodeIndex aTmpIndex( *this );
1440                 pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
1441                 ((SwTxtFtn*)pAttr)->SetSeqRefNo();
1442             }
1443             break;
1444 
1445             case RES_TXTATR_FIELD:
1446                 {
1447                     // fuer HiddenParaFields Benachrichtigungsmechanismus
1448                     // anwerfen
1449                     if( RES_HIDDENPARAFLD == pAttr->GetFmtFld().GetField()->GetTyp()->Which() )
1450                     {
1451                         bHiddenPara = true;
1452                     }
1453                 }
1454                 break;
1455 
1456         }
1457         // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_..
1458         // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
1459         // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits
1460         // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
1461         if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1462         {
1463             SwIndex aIdx( this, *pAttr->GetStart() );
1464             InsertText( GetCharOfTxtAttr(*pAttr), aIdx, nInsertFlags );
1465 
1466             // adjust end of hint to account for inserted CH_TXTATR
1467             xub_StrLen * const pEnd(pAttr->GetEnd());
1468             if (pEnd)
1469             {
1470                 *pEnd = *pEnd + 1;
1471             }
1472         }
1473     }
1474 
1475     // handle attributes which provide content
1476     xub_StrLen nEnd = nStart;
1477     bool bInputFieldStartCharInserted = false;
1478     bool bInputFieldEndCharInserted = false;
1479     const bool bHasContent( pAttr->HasContent() );
1480     if ( bHasContent )
1481     {
1482         switch( pAttr->Which() )
1483         {
1484         case RES_TXTATR_INPUTFIELD:
1485             {
1486                 SwTxtInputFld* pTxtInputFld = dynamic_cast<SwTxtInputFld*>(pAttr);
1487                 if ( pTxtInputFld )
1488                 {
1489                     if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
1490                     {
1491                         SwIndex aIdx( this, *pAttr->GetStart() );
1492                         InsertText( CH_TXT_ATR_INPUTFIELDSTART, aIdx, nInsertFlags );
1493                         const String aContent = pTxtInputFld->GetFieldContent();
1494                         InsertText( aContent, aIdx, nInsertFlags );
1495                         InsertText( CH_TXT_ATR_INPUTFIELDEND, aIdx, nInsertFlags );
1496 
1497                         xub_StrLen * const pEnd(pAttr->GetEnd());
1498                         ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1499                         if ( pEnd != NULL )
1500                         {
1501                             *pEnd = *pEnd + 2 + aContent.Len();
1502                             nEnd = *pEnd;
1503                         }
1504                     }
1505                     else
1506                     {
1507                         // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted.
1508                         if ( m_Text.GetChar( *(pAttr->GetStart()) ) != CH_TXT_ATR_INPUTFIELDSTART )
1509                         {
1510                             SwIndex aIdx( this, *pAttr->GetStart() );
1511                             InsertText( CH_TXT_ATR_INPUTFIELDSTART, aIdx, nInsertFlags );
1512                             bInputFieldStartCharInserted = true;
1513                             xub_StrLen * const pEnd(pAttr->GetEnd());
1514                             ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1515                             if ( pEnd != NULL )
1516                             {
1517                                 *pEnd = *pEnd + 1;
1518                                 nEnd = *pEnd;
1519                             }
1520                         }
1521 
1522                         xub_StrLen * const pEnd(pAttr->GetEnd());
1523                         ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1524                         if ( pEnd != NULL
1525                              && m_Text.GetChar( *(pEnd) - 1 ) != CH_TXT_ATR_INPUTFIELDEND )
1526                         {
1527                             SwIndex aIdx( this, *(pEnd) );
1528                             InsertText( CH_TXT_ATR_INPUTFIELDEND, aIdx, nInsertFlags );
1529                             bInputFieldEndCharInserted = true;
1530                             *pEnd = *pEnd + 1;
1531                             nEnd = *pEnd;
1532                         }
1533                     }
1534                 }
1535             }
1536             break;
1537         default:
1538             break;
1539         }
1540     }
1541 
1542     GetOrCreateSwpHints();
1543 
1544     // handle overlap with an existing InputField
1545     bool bInsertHint = true;
1546     {
1547         const SwTxtInputFld* pTxtInputFld = GetOverlappingInputFld( *pAttr );
1548         if ( pTxtInputFld != NULL )
1549         {
1550             if ( pAttr->End() == NULL )
1551             {
1552                 bInsertHint = false;
1553             }
1554             else
1555             {
1556                 if ( *(pAttr->GetStart()) > *(pTxtInputFld->GetStart()) )
1557                 {
1558                     *(pAttr->GetStart()) = *(pTxtInputFld->GetStart());
1559                 }
1560                 if ( *(pAttr->End()) < *(pTxtInputFld->End()) )
1561                 {
1562                     *(pAttr->GetEnd()) = *(pTxtInputFld->End());
1563                 }
1564             }
1565         }
1566     }
1567 
1568     // 4263: AttrInsert durch TextInsert => kein Adjust
1569     const bool bRet = bInsertHint
1570                       ? m_pSwpHints->TryInsertHint( pAttr, *this, nMode )
1571                       : false;
1572 
1573     if ( !bRet )
1574     {
1575         if ( bDummyChar
1576              && !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
1577         {
1578             // undo insertion of dummy character
1579             // N.B. cannot insert the dummy character after inserting the hint,
1580             // because if the hint has no extent it will be moved in InsertText,
1581             // resulting in infinite recursion
1582             ASSERT( ( CH_TXTATR_BREAKWORD == m_Text.GetChar(nStart) ||
1583                 CH_TXTATR_INWORD    == m_Text.GetChar(nStart) ),
1584                 "where is my attribute character?" );
1585             SwIndex aIdx( this, nStart );
1586             EraseText( aIdx, 1 );
1587         }
1588 
1589         if ( bHasContent )
1590         {
1591             if ( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode)
1592                  && (nEnd - nStart) > 0 )
1593             {
1594                 SwIndex aIdx( this, nStart );
1595                 EraseText( aIdx, (nEnd - nStart) );
1596             }
1597             else
1598             {
1599                 if ( bInputFieldEndCharInserted
1600                      && (nEnd - nStart) > 0 )
1601                 {
1602                     SwIndex aIdx( this, nEnd - 1 );
1603                     EraseText( aIdx, 1 );
1604                 }
1605 
1606                 if ( bInputFieldStartCharInserted )
1607                 {
1608                     SwIndex aIdx( this, nStart );
1609                     EraseText( aIdx, 1 );
1610                 }
1611             }
1612         }
1613     }
1614 
1615     if ( bHiddenPara )
1616     {
1617         SetCalcHiddenParaField();
1618     }
1619 
1620     return bRet;
1621 }
1622 
1623 
1624 /*************************************************************************
1625  *                        SwTxtNode::DeleteAttribute()
1626  *************************************************************************/
1627 
1628 void SwTxtNode::DeleteAttribute( SwTxtAttr * const pAttr )
1629 {
1630     if ( !HasHints() )
1631     {
1632         ASSERT(false, "DeleteAttribute called, but text node without hints?");
1633         return;
1634     }
1635 
1636     if ( pAttr->HasDummyChar() )
1637     {
1638         // Unbedingt Copy-konstruieren!
1639         const SwIndex aIdx( this, *pAttr->GetStart() );
1640         // erase the CH_TXTATR, which will also delete pAttr
1641         EraseText( aIdx, 1 );
1642     }
1643     else if ( pAttr->HasContent() )
1644     {
1645         const SwIndex aIdx( this, *pAttr->GetStart() );
1646         ASSERT( pAttr->End() != NULL, "<SwTxtNode::DeleteAttribute(..)> - missing End() at <SwTxtAttr> instance which has content" );
1647         EraseText( aIdx, *pAttr->End() - *pAttr->GetStart() );
1648     }
1649     else
1650     {
1651         // create MsgHint before start/end become invalid
1652         SwUpdateAttr aHint(
1653                 *pAttr->GetStart(), *pAttr->GetEnd(), pAttr->Which() );
1654         m_pSwpHints->Delete( pAttr );
1655         SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
1656         NotifyClients( 0, &aHint );
1657 
1658         TryDeleteSwpHints();
1659     }
1660 }
1661 
1662 /*************************************************************************
1663  *                        SwTxtNode::DeleteAttributes()
1664  *************************************************************************/
1665 
1666 //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
1667 void SwTxtNode::DeleteAttributes(
1668     const sal_uInt16 nWhich,
1669     const xub_StrLen nStart,
1670     const xub_StrLen nEnd )
1671 {
1672     if ( !HasHints() )
1673         return;
1674 
1675     for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ )
1676     {
1677         SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos );
1678         const xub_StrLen nHintStart = *(pTxtHt->GetStart());
1679         if (nStart < nHintStart)
1680         {
1681             break; // sorted by start
1682         }
1683         else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) )
1684         {
1685             if ( nWhich == RES_CHRATR_HIDDEN  )
1686             {
1687                 ASSERT(false, "hey, that's a CHRATR! how did that get in?");
1688                 SetCalcHiddenCharFlags();
1689             }
1690             else if ( nWhich == RES_TXTATR_CHARFMT )
1691             {
1692                 // Check if character format contains hidden attribute:
1693                 const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt();
1694                 const SfxPoolItem* pItem;
1695                 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
1696                     SetCalcHiddenCharFlags();
1697             }
1698             // Recalc hidden flags if necessary
1699             else if ( nWhich == RES_TXTATR_AUTOFMT )
1700             {
1701                 // Check if auto style contains hidden attribute:
1702                 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
1703                 if ( pHiddenItem )
1704                     SetCalcHiddenCharFlags();
1705             }
1706 
1707             xub_StrLen const * const pEndIdx = pTxtHt->GetEnd();
1708 
1709             if ( pTxtHt->HasDummyChar() )
1710             {
1711                 // Unbedingt Copy-konstruieren!
1712                 const SwIndex aIdx( this, nStart );
1713                 // erase the CH_TXTATR, which will also delete pTxtHt
1714                 EraseText( aIdx, 1 );
1715             }
1716             else if ( pTxtHt->HasContent() )
1717             {
1718                 const SwIndex aIdx( this, nStart );
1719                 ASSERT( pTxtHt->End() != NULL, "<SwTxtNode::DeleteAttributes(..)> - missing End() at <SwTxtAttr> instance which has content" );
1720                 EraseText( aIdx, *pTxtHt->End() - nStart );
1721             }
1722             else if( *pEndIdx == nEnd )
1723             {
1724                 // den MsgHint jetzt fuettern, weil gleich sind
1725                 // Start und End weg.
1726                 // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
1727                 // da dies das Feld im Dtor selbst erledigt.
1728                 SwUpdateAttr aHint( nStart, *pEndIdx, nWhich );
1729                 m_pSwpHints->DeleteAtPos( nPos );    // gefunden, loeschen,
1730                 SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() );
1731                 NotifyClients( 0, &aHint );
1732             }
1733         }
1734     }
1735     TryDeleteSwpHints();
1736 }
1737 
1738 /*************************************************************************
1739  *						SwTxtNode::DelSoftHyph()
1740  *************************************************************************/
1741 
1742 void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd )
1743 {
1744     xub_StrLen nFndPos = nStt, nEndPos = nEnd;
1745 	while( STRING_NOTFOUND !=
1746             ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) &&
1747 			nFndPos < nEndPos )
1748 	{
1749 		const SwIndex aIdx( this, nFndPos );
1750         EraseText( aIdx, 1 );
1751 		--nEndPos;
1752 	}
1753 }
1754 
1755 //Modify here for #119405, by easyfan, 2012-05-24
1756 //In MS Word, the font underline setting of the paragraph end position wont affect the formatting of numbering, so we ignore it
1757 bool lcl_IsIgnoredCharFmtForNumbering(const sal_uInt16 nWhich)
1758 {
1759 	return (nWhich ==  RES_CHRATR_UNDERLINE);
1760 }
1761 
1762 //In MS Word, following properties of the paragraph end position wont affect the formatting of bullets, so we ignore them:
1763 //Font underline;
1764 //Font Italic of Western, CJK and CTL;
1765 //Font Bold of Wertern, CJK and CTL;
1766 bool lcl_IsIgnoredCharFmtForBullets(const sal_uInt16 nWhich)
1767 {
1768 	return (nWhich ==  RES_CHRATR_UNDERLINE || nWhich ==  RES_CHRATR_POSTURE || nWhich ==  RES_CHRATR_WEIGHT
1769 		|| nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT
1770 		|| nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT);
1771 }
1772 
1773 //Condition for expanding char set to character style of specified number rule level:
1774 //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwCntntNode::SwPAttrSet);
1775 //The node should have applied a number rule;
1776 //The node should be counted in a list, if not, make it to be;
1777 //The item should not conflict to any exist and non-default item inside the character of specified number rule level;
1778 //The item should not be ignored depend on the exact number rule type;
1779 bool SwTxtNode::TryCharSetExpandToNum(const SfxItemSet& aCharSet)
1780 {
1781 	bool bRet = false;
1782 	SfxItemIter aIter( aCharSet );
1783         const SfxPoolItem* pItem = aIter.FirstItem();
1784         const sal_uInt16 nWhich = pItem->Which();
1785 
1786 	const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
1787 
1788 	if (!IsDefaultItem(&rInnerItem) &&  !IsInvalidItem(&rInnerItem))
1789 		return bRet;
1790 
1791 	if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 )
1792 	{
1793 		return bRet;
1794 	}
1795 
1796 	SwNumRule* pCurrNum = GetNumRule(false);
1797 
1798 	int nLevel = GetActualListLevel();
1799 
1800 	if (nLevel != -1 && pCurrNum)
1801 	{
1802 		const SwNumFmt* pCurrNumFmt = pCurrNum->GetNumFmt(static_cast<sal_uInt16>(nLevel));
1803 		if (pCurrNumFmt)
1804 		{
1805 			if (pCurrNumFmt->IsItemize() && lcl_IsIgnoredCharFmtForBullets(nWhich))
1806 				return bRet;
1807 			if (pCurrNumFmt->IsEnumeration() && lcl_IsIgnoredCharFmtForNumbering(nWhich))
1808 				return bRet;
1809 			SwCharFmt* pCurrCharFmt =pCurrNumFmt->GetCharFmt();
1810 
1811 			if (pCurrCharFmt && pCurrCharFmt->GetItemState(nWhich,false) != SFX_ITEM_SET)
1812 			{
1813 				pCurrCharFmt->SetFmtAttr(*pItem);
1814 				SwNumFmt aNewNumFmt(*pCurrNumFmt);
1815 				aNewNumFmt.SetCharFmt(pCurrCharFmt);
1816 				pCurrNum->Set(nLevel,aNewNumFmt);
1817 				bRet = true;
1818 			}
1819 		}
1820 	}
1821 
1822 
1823 	return bRet;
1824 }
1825 //End of modification, by easyfan
1826 
1827 // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1828 // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
1829 sal_Bool SwTxtNode::SetAttr(
1830     const SfxItemSet& rSet,
1831     const xub_StrLen nStt,
1832     const xub_StrLen nEnd,
1833     const SetAttrMode nMode )
1834 {
1835 	if( !rSet.Count() )
1836 		return sal_False;
1837 
1838 	// teil die Sets auf (fuer Selektion in Nodes)
1839 	const SfxItemSet* pSet = &rSet;
1840 	SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1841 
1842 	// gesamter Bereich
1843     if ( !nStt && (nEnd == m_Text.Len()) &&
1844          !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
1845 	{
1846 		// sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1847 		// (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1848 		int bHasCharFmts = sal_False;
1849         if ( HasHints() )
1850         {
1851             for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
1852             {
1853                 if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
1854                 {
1855 					bHasCharFmts = sal_True;
1856 					break;
1857                 }
1858             }
1859         }
1860 
1861 		if( !bHasCharFmts )
1862 		{
1863             aTxtSet.Put( rSet );
1864             // If there are any character attributes in rSet,
1865             // we want to set them at the paragraph:
1866 			if( aTxtSet.Count() != rSet.Count() )
1867 			{
1868                 sal_Bool bRet = SetAttr( rSet );
1869           		if( !aTxtSet.Count() )
1870 		    		return bRet;
1871 			}
1872 
1873             // check for auto style:
1874             const SfxPoolItem* pItem;
1875             const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem );
1876             if ( bAutoStyle )
1877             {
1878                 boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
1879                 sal_Bool bRet = SetAttr( *pAutoStyleSet );
1880           		if( 1 == aTxtSet.Count() )
1881 		    		return bRet;
1882             }
1883 
1884             // Continue with the text attributes:
1885 			pSet = &aTxtSet;
1886 		}
1887 	}
1888 
1889     GetOrCreateSwpHints();
1890 
1891     SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
1892 
1893     sal_uInt16 nCount = 0;
1894 	SfxItemIter aIter( *pSet );
1895 	const SfxPoolItem* pItem = aIter.GetCurItem();
1896 
1897     do
1898     {
1899         if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1900         {
1901             const sal_uInt16 nWhich = pItem->Which();
1902             ASSERT( isCHRATR(nWhich) || isTXTATR(nWhich),
1903                     "SwTxtNode::SetAttr(): unknown attribute" );
1904             if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1905             {
1906                 if ((RES_TXTATR_CHARFMT == nWhich) &&
1907                     (GetDoc()->GetDfltCharFmt() ==
1908                      static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
1909                 {
1910                     SwIndex aIndex( this, nStt );
1911                     RstTxtAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1912                     DontExpandFmt( aIndex );
1913                 }
1914                 else
1915                 {
1916                     if (isCHRATR(nWhich) ||
1917                         (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1918                     {
1919                         aCharSet.Put( *pItem );
1920                     }
1921                     else
1922                     {
1923 
1924                         SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
1925                                 const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1926                         if ( pNew )
1927                         {
1928                             if ( nEnd != nStt && !pNew->GetEnd() )
1929                             {
1930                                 ASSERT(false,
1931                                     "Attribut without end, but area marked");
1932                                 DestroyAttr( pNew ); // do not insert
1933                             }
1934                             else if ( InsertHint( pNew, nMode ) )
1935                             {
1936                                 ++nCount;
1937                             }
1938                         }
1939                     }
1940                 }
1941             }
1942         }
1943         if ( aIter.IsAtEnd() )
1944             break;
1945         pItem = aIter.NextItem();
1946     } while( true );
1947 
1948     if ( aCharSet.Count() )
1949     {
1950         SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
1951         if ( InsertHint( pTmpNew, nMode ) )
1952         {
1953             ++nCount;
1954         }
1955     }
1956 
1957     TryDeleteSwpHints();
1958 
1959 	return nCount ? sal_True : sal_False;
1960 }
1961 
1962 void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1963 {
1964     if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
1965 	{
1966         const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1967         if ( !pCFSet )
1968             return;
1969         SfxWhichIter aIter( *pCFSet );
1970         sal_uInt16 nWhich = aIter.FirstWhich();
1971         while( nWhich )
1972         {
1973             if( ( nWhich < RES_CHRATR_END ||
1974                   RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
1975                 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
1976                 rSet.Put( pCFSet->Get( nWhich ) );
1977             nWhich = aIter.NextWhich();
1978         }
1979     }
1980     else
1981     	rSet.Put( rAttr );
1982 }
1983 
1984 void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1985 {
1986 	if( RES_TXTATR_CHARFMT == rAttr.Which() ||
1987 		RES_TXTATR_INETFMT == rAttr.Which() ||
1988         RES_TXTATR_AUTOFMT == rAttr.Which() )
1989 	{
1990         const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1991 
1992         if ( pCFSet )
1993         {
1994             SfxWhichIter aIter( *pCFSet );
1995             sal_uInt16 nWhich = aIter.FirstWhich();
1996             while( nWhich )
1997             {
1998                 if( ( nWhich < RES_CHRATR_END ||
1999                       ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
2000                     ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
2001                     rSet.Put( pCFSet->Get( nWhich ) );
2002                 nWhich = aIter.NextWhich();
2003             }
2004         }
2005     }
2006 
2007 	// aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
2008 
2009 /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
2010  z.B
2011 			1234567890123456789
2012 			  |------------| 		Font1
2013 				 |------|			Font2
2014 					^  ^
2015 					|--|		Abfragebereich: -> Gueltig ist Font2
2016 */
2017     rSet.Put( rAttr );
2018 }
2019 
2020 struct SwPoolItemEndPair
2021 {
2022 public:
2023     const SfxPoolItem* mpItem;
2024     xub_StrLen mnEndPos;
2025 
2026     SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
2027 };
2028 
2029 // --> OD 2008-01-16 #newlistlevelattrs#
2030 void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
2031                                             SfxItemSet& rSet )
2032 {
2033     if ( rTxtNode.AreListLevelIndentsApplicable() )
2034     {
2035         const SwNumRule* pRule = rTxtNode.GetNumRule();
2036         if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
2037         {
2038             const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
2039             if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2040             {
2041                 SvxLRSpaceItem aLR( RES_LR_SPACE );
2042                 aLR.SetTxtLeft( rFmt.GetIndentAt() );
2043                 aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
2044                 rSet.Put( aLR );
2045             }
2046         }
2047     }
2048 }
2049 
2050 // erfrage die Attribute vom TextNode ueber den Bereich
2051 // --> OD 2008-01-16 #newlistlevelattrs#
2052 sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd,
2053                          sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt,
2054                          const bool bMergeIndentValuesOfNumRule ) const
2055 {
2056     if( HasHints() )
2057     {
2058 		/* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
2059 		 * sind. Dabei gibt es folgende Faelle:
2060 		 * 	UnEindeutig wenn: (wenn != Format-Attribut)
2061 		 * 		- das Attribut liegt vollstaendig im Bereich
2062 		 * 		- das Attributende liegt im Bereich
2063 		 * 		- der Attributanfang liegt im Bereich:
2064 		 * Eindeutig (im Set mergen):
2065 		 *		- das Attrib umfasst den Bereich
2066 		 * nichts tun:
2067 		 * 		das Attribut liegt ausserhalb des Bereiches
2068 		 */
2069 
2070 		void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
2071 			= bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
2072 							 : &lcl_MergeAttr;
2073 
2074 		// dann besorge mal die Auto-(Fmt)Attribute
2075 		SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
2076 		if( !bOnlyTxtAttr )
2077         {
2078 			SwCntntNode::GetAttr( aFmtSet );
2079             // --> OD 2008-01-16 #newlistlevelattrs#
2080             if ( bMergeIndentValuesOfNumRule )
2081             {
2082                 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
2083             }
2084             // <--
2085         }
2086 
2087         const sal_uInt16 nSize = m_pSwpHints->Count();
2088 
2089         if( nStt == nEnd )             // kein Bereich:
2090 		{
2091             for (sal_uInt16 n = 0; n < nSize; ++n)
2092             {
2093                 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
2094                 const xub_StrLen nAttrStart = *pHt->GetStart();
2095 				if( nAttrStart > nEnd ) 		// ueber den Bereich hinaus
2096 					break;
2097 
2098                 const xub_StrLen* pAttrEnd = pHt->End();
2099                 if ( ! pAttrEnd ) // no attributes without end
2100 					continue;
2101 
2102                 if( ( nAttrStart < nStt &&
2103                         ( pHt->DontExpand() ? nStt < *pAttrEnd
2104                                             : nStt <= *pAttrEnd )) ||
2105                     ( nStt == nAttrStart &&
2106                         ( nAttrStart == *pAttrEnd || !nStt )))
2107 					(*fnMergeAttr)( rSet, pHt->GetAttr() );
2108 			}
2109 		}
2110 		else							// es ist ein Bereich definiert
2111 		{
2112             // --> FME 2007-03-13 #i75299#
2113             ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
2114             // <--
2115 
2116 			const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
2117                                    static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
2118 
2119             for (sal_uInt16 n = 0; n < nSize; ++n)
2120             {
2121                 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
2122                 const xub_StrLen nAttrStart = *pHt->GetStart();
2123 				if( nAttrStart > nEnd ) 		// ueber den Bereich hinaus
2124 					break;
2125 
2126                 const xub_StrLen* pAttrEnd = pHt->End();
2127                 if ( ! pAttrEnd ) // no attributes without end
2128 					continue;
2129 
2130 				sal_Bool bChkInvalid = sal_False;
2131                 if( nAttrStart <= nStt )       // vor oder genau Start
2132 				{
2133                     if( *pAttrEnd <= nStt )    // liegt davor
2134 						continue;
2135 
2136 					if( nEnd <= *pAttrEnd )		// hinter oder genau Ende
2137 						(*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
2138 					else
2139 //					else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
2140 						// uneindeutig
2141 						bChkInvalid = sal_True;
2142 				}
2143 				else if( nAttrStart < nEnd 		// reicht in den Bereich
2144 )//						 && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
2145 					bChkInvalid = sal_True;
2146 
2147 				if( bChkInvalid )
2148 				{
2149 					// uneindeutig ?
2150                     ::std::auto_ptr< SfxItemIter > pItemIter;
2151                     const SfxPoolItem* pItem = 0;
2152 
2153                     if ( RES_TXTATR_AUTOFMT == pHt->Which() )
2154                     {
2155                         const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
2156                         if ( pAutoSet )
2157                         {
2158                             pItemIter.reset( new SfxItemIter( *pAutoSet ) );
2159                             pItem = pItemIter->GetCurItem();
2160                         }
2161                     }
2162                     else
2163                         pItem = &pHt->GetAttr();
2164 
2165                     const sal_uInt16 nHintEnd = *pAttrEnd;
2166 
2167                     while ( pItem )
2168                     {
2169                         const sal_uInt16 nHintWhich = pItem->Which();
2170                         ASSERT(!isUNKNOWNATR(nHintWhich),
2171                                 "SwTxtNode::GetAttr(): unkonwn attribute?");
2172 
2173                         if ( !pAttrArr.get() )
2174                         {
2175                             pAttrArr.reset(
2176                                 new std::vector< SwPoolItemEndPair >(coArrSz));
2177                         }
2178 
2179                         std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
2180                         if (isCHRATR(nHintWhich) ||
2181                             isTXTATR_WITHEND(nHintWhich))
2182                         {
2183                             pPrev += nHintWhich - RES_CHRATR_BEGIN;
2184                         }
2185                         else
2186                         {
2187                             pPrev = pAttrArr->end();
2188                         }
2189 
2190 #if OSL_DEBUG_LEVEL > 1
2191                         SwPoolItemEndPair aTmp = *pPrev;
2192 #endif
2193 
2194                         if( pPrev != pAttrArr->end() )
2195                         {
2196                             if( !pPrev->mpItem )
2197                             {
2198                                 if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
2199                                 {
2200                                     if( nAttrStart > nStt )
2201                                     {
2202                                         rSet.InvalidateItem( nHintWhich );
2203                                         pPrev->mpItem = (SfxPoolItem*)-1;
2204                                     }
2205                                     else
2206                                     {
2207                                         pPrev->mpItem = pItem;
2208                                         pPrev->mnEndPos = nHintEnd;
2209                                     }
2210                                 }
2211                             }
2212                             else if( (SfxPoolItem*)-1 != pPrev->mpItem )
2213                             {
2214                                 if( pPrev->mnEndPos == nAttrStart &&
2215                                     *pPrev->mpItem == *pItem )
2216                                 {
2217                                     pPrev->mpItem = pItem;
2218                                     pPrev->mnEndPos = nHintEnd;
2219                                 }
2220                                 else
2221                                 {
2222                                     rSet.InvalidateItem( nHintWhich );
2223                                     pPrev->mpItem = (SfxPoolItem*)-1;
2224                                 }
2225                             }
2226                         }
2227 
2228                         pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
2229                                     ? pItemIter->NextItem() : 0;
2230                     } // end while
2231                 }
2232 			}
2233 
2234             if ( pAttrArr.get() )
2235 			{
2236                 for (sal_uInt16 n = 0; n < coArrSz; ++n)
2237                 {
2238                     const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
2239                     if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
2240                     {
2241                         const sal_uInt16 nWh =
2242                             static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2243 
2244                         if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
2245                         {
2246                             if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
2247                                 (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2248                         }
2249                         else
2250                             // uneindeutig
2251                             rSet.InvalidateItem( nWh );
2252                     }
2253                 }
2254 			}
2255 		}
2256 		if( aFmtSet.Count() )
2257 		{
2258 			// aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
2259 			aFmtSet.Differentiate( rSet );
2260 			// jetzt alle zusammen "mergen"
2261 			rSet.Put( aFmtSet );
2262 		}
2263 	}
2264 	else if( !bOnlyTxtAttr )
2265     {
2266 		// dann besorge mal die Auto-(Fmt)Attribute
2267 		SwCntntNode::GetAttr( rSet );
2268         // --> OD 2008-01-16 #newlistlevelattrs#
2269         if ( bMergeIndentValuesOfNumRule )
2270         {
2271             lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
2272         }
2273         // <--
2274     }
2275 
2276 	return rSet.Count() ? sal_True : sal_False;
2277 }
2278 
2279 
2280 namespace
2281 {
2282 
2283 typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t;
2284 typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t;
2285 
2286 
2287 struct IsAutoStyle
2288 {
2289     bool
2290     operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2291     const
2292     {
2293         return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2294     }
2295 };
2296 
2297 
2298 /** Removes from io_rAttrSet all items that are set by style on the
2299     given span.
2300   */
2301 struct RemovePresentAttrs
2302 {
2303     RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2304         : m_rAttrSet(io_rAttrSet)
2305     {
2306     }
2307 
2308     void
2309     operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2310     const
2311     {
2312         if (!i_rAttrSpan.second)
2313         {
2314             return;
2315         }
2316 
2317         const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second);
2318         SfxItemIter aIter(m_rAttrSet);
2319         const SfxPoolItem* pItem(aIter.GetCurItem());
2320         while (pItem)
2321         {
2322             const sal_uInt16 nWhich(pItem->Which());
2323             if (CharFmt::IsItemIncluded(nWhich, pAutoStyle))
2324             {
2325                 m_rAttrSet.ClearItem(nWhich);
2326             }
2327 
2328             if (aIter.IsAtEnd())
2329             {
2330                 break;
2331             }
2332             pItem = aIter.NextItem();
2333         }
2334     }
2335 
2336 private:
2337     SfxItemSet& m_rAttrSet;
2338 };
2339 
2340 
2341 /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
2342     addition inserts dummy spans with pointer to format equal to 0 for
2343     all gaps (i.e. spans not covered by any style). This simplifies
2344     creation of autostyles for all needed spans, but it means all code
2345     that tries to access the pointer has to check if it's non-null!
2346  */
2347 void
2348 lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength,
2349         AttrSpanMap_t& o_rSpanMap)
2350 {
2351     sal_uInt16 nLastEnd(0);
2352 
2353     for (sal_uInt16 i(0); i != i_rHints.Count(); ++i)
2354     {
2355         const SwTxtAttr* const pHint(i_rHints[i]);
2356         const sal_uInt16 nWhich(pHint->Which());
2357         if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2358         {
2359             const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->End());
2360             o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
2361 
2362             // < not != because there may be multiple CHARFMT at same range
2363             if (nLastEnd < aSpan.first)
2364             {
2365                 // insert dummy span covering the gap
2366                 o_rSpanMap.insert(AttrSpanMap_t::value_type(
2367                             AttrSpan_t(nLastEnd, aSpan.first), 0));
2368             }
2369 
2370             nLastEnd = aSpan.second;
2371         }
2372     }
2373 
2374     // no hints at the end (special case: no hints at all in i_rHints)
2375     if (nLastEnd != nLength && nLength != 0)
2376     {
2377         o_rSpanMap.insert(
2378             AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), 0));
2379     }
2380 }
2381 
2382 
2383 void
2384 lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2385 {
2386     o_rClearIds.reserve(i_rAttrSet.Count());
2387     SfxItemIter aIter(i_rAttrSet);
2388     const SfxPoolItem* pItem(aIter.GetCurItem());
2389     while (true)
2390     {
2391         o_rClearIds.push_back(pItem->Which());
2392 
2393         if (aIter.IsAtEnd())
2394         {
2395             break;
2396         }
2397         pItem = aIter.NextItem();
2398     }
2399 }
2400 
2401 struct SfxItemSetClearer
2402 {
2403     SfxItemSet & m_rItemSet;
2404     SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2405     void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2406 };
2407 
2408 }
2409 
2410 
2411 /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion
2412     of items to automatic styles.
2413  */
2414 void
2415 SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
2416 {
2417     typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2418     AttrSpanMap_t aAttrSpanMap;
2419 
2420     if (i_rAttrSet.Count() == 0)
2421     {
2422         return;
2423     }
2424 
2425     // 1. Identify all spans in hints' array
2426 
2427     lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap);
2428 
2429     // 2. Go through all spans and insert new attrs
2430 
2431     AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2432     const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2433     while (aCurRange != aEnd)
2434     {
2435         typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2436             AttrSpanMapRange_t;
2437         AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2438 
2439         // 2a. Collect attributes to insert
2440 
2441         SfxItemSet aCurSet(i_rAttrSet);
2442         std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2443 
2444         // 2b. Insert automatic style containing the collected attributes
2445 
2446         if (aCurSet.Count() != 0)
2447         {
2448             AttrSpanMap_iterator_t aAutoStyleIt(
2449                     std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2450             if (aAutoStyleIt != aRange.second)
2451             {
2452                 // there already is an automatic style on that span:
2453                 // create new one and remove the original one
2454                 SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second));
2455                 const boost::shared_ptr<SfxItemSet> pOldStyle(
2456                         static_cast<const SwFmtAutoFmt&>(
2457                             pAutoStyle->GetAttr()).GetStyleHandle());
2458                 aCurSet.Put(*pOldStyle);
2459 
2460                 // remove the old hint
2461                 m_pSwpHints->Delete(pAutoStyle);
2462                 DestroyAttr(pAutoStyle);
2463             }
2464             m_pSwpHints->Insert(
2465                     MakeTxtAttr(*GetDoc(), aCurSet,
2466                         aCurRange->first.first, aCurRange->first.second));
2467         }
2468 
2469         aCurRange = aRange.second;
2470     }
2471 
2472     // 3. Clear items from the node
2473     std::vector<sal_uInt16> aClearedIds;
2474     lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2475     ClearItemsFromAttrSet(aClearedIds);
2476 }
2477 
2478 void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
2479 {
2480 	SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2481     if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2482 		aThisSet.Put( *GetpSwAttrSet() );
2483 
2484     GetOrCreateSwpHints();
2485 
2486 	if( pNd == this )
2487 	{
2488         impl_FmtToTxtAttr(aThisSet);
2489     }
2490 	else
2491 	{
2492         // There are five possible combinations of items from this and
2493         // pNd (pNd is the 'main' node):
2494         //
2495         //  case    pNd     this     action
2496         //  ----------------------------------------------------
2497         //     1     -       -      do nothing
2498         //     2     -       a      convert item to attr of this
2499         //     3     a       -      convert item to attr of pNd
2500         //     4     a       a      clear item in this
2501         //     5     a       b      convert item to attr of this
2502 
2503 		SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
2504         if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2505 			aNdSet.Put( *pNd->GetpSwAttrSet() );
2506 
2507         pNd->GetOrCreateSwpHints();
2508 
2509         std::vector<sal_uInt16> aProcessedIds;
2510 
2511 		if( aThisSet.Count() )
2512 		{
2513 			SfxItemIter aIter( aThisSet );
2514 			const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
2515             SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2516             std::vector<sal_uInt16> aClearWhichIds;
2517 
2518 			while( true )
2519 			{
2520 				if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) )
2521                 {
2522                     if (*pItem == *pNdItem) // 4
2523                     {
2524                         aClearWhichIds.push_back( pItem->Which() );
2525                     }
2526                     else    // 5
2527                     {
2528                         aConvertSet.Put(*pItem);
2529                     }
2530                     aProcessedIds.push_back(pItem->Which());
2531                 }
2532                 else    // 2
2533                 {
2534                     aConvertSet.Put(*pItem);
2535                 }
2536 
2537 				if( aIter.IsAtEnd() )
2538 					break;
2539 				pItem = aIter.NextItem();
2540 			}
2541 
2542             // 4/ clear items of this that are set with the same value on pNd
2543             ClearItemsFromAttrSet( aClearWhichIds );
2544 
2545             // 2, 5/ convert all other items to attrs
2546             impl_FmtToTxtAttr(aConvertSet);
2547         }
2548 
2549         {
2550             std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2551                     SfxItemSetClearer(aNdSet));
2552 
2553             // 3/ convert items to attrs
2554             pNd->impl_FmtToTxtAttr(aNdSet);
2555 
2556             if( aNdSet.Count() )
2557             {
2558                 SwFmtChg aTmp1( pNd->GetFmtColl() );
2559                 pNd->NotifyClients( &aTmp1, &aTmp1 );
2560             }
2561         }
2562     }
2563 
2564     SetCalcHiddenCharFlags();
2565 
2566     pNd->TryDeleteSwpHints();
2567 }
2568 
2569 /*************************************************************************
2570  *						SwpHints::CalcFlags()
2571  *************************************************************************/
2572 
2573 void SwpHints::CalcFlags()
2574 {
2575     m_bDDEFields = m_bFootnote = false;
2576     const sal_uInt16 nSize = Count();
2577     const SwTxtAttr* pAttr;
2578     for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2579     {
2580         switch( ( pAttr = (*this)[ nPos ])->Which() )
2581         {
2582         case RES_TXTATR_FTN:
2583             m_bFootnote = true;
2584             if ( m_bDDEFields )
2585                 return;
2586             break;
2587         case RES_TXTATR_FIELD:
2588             {
2589                 const SwField* pFld = pAttr->GetFmtFld().GetField();
2590                 if( RES_DDEFLD == pFld->GetTyp()->Which() )
2591                 {
2592                     m_bDDEFields = true;
2593                     if ( m_bFootnote )
2594                         return;
2595                 }
2596             }
2597             break;
2598         }
2599     }
2600 }
2601 
2602 /*************************************************************************
2603  *						SwpHints::CalcVisibleFlag()
2604  *************************************************************************/
2605 
2606 bool SwpHints::CalcHiddenParaField()
2607 {
2608     m_bCalcHiddenParaField = false;
2609     bool bOldHasHiddenParaField = m_bHasHiddenParaField;
2610     bool bNewHasHiddenParaField  = false;
2611 	const sal_uInt16	nSize = Count();
2612 	const SwTxtAttr *pTxtHt;
2613 
2614 	for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2615 	{
2616 		pTxtHt = (*this)[ nPos ];
2617 		const sal_uInt16 nWhich = pTxtHt->Which();
2618 
2619 		if( RES_TXTATR_FIELD == nWhich )
2620 		{
2621 			const SwFmtFld& rFld = pTxtHt->GetFmtFld();
2622             if( RES_HIDDENPARAFLD == rFld.GetField()->GetTyp()->Which() )
2623 			{
2624 				if( !((SwHiddenParaField*)rFld.GetField())->IsHidden() )
2625                 {
2626                     SetHiddenParaField(false);
2627                     return bOldHasHiddenParaField != bNewHasHiddenParaField;
2628                 }
2629                 else
2630                 {
2631                     bNewHasHiddenParaField = true;
2632                 }
2633             }
2634         }
2635     }
2636     SetHiddenParaField( bNewHasHiddenParaField );
2637     return bOldHasHiddenParaField != bNewHasHiddenParaField;
2638 }
2639 
2640 
2641 /*************************************************************************
2642  *						SwpHints::NoteInHistory()
2643  *************************************************************************/
2644 
2645 void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
2646 {
2647     if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2648 }
2649 
2650 /*************************************************************************
2651  *                      SwpHints::MergePortions( )
2652  *************************************************************************/
2653 
2654 bool SwpHints::MergePortions( SwTxtNode& rNode )
2655 {
2656     if ( !Count() )
2657         return false;
2658 
2659     // sort before merging
2660     SwpHintsArray::Resort();
2661 
2662     bool bRet = false;
2663     typedef std::multimap< int, SwTxtAttr* > PortionMap;
2664     PortionMap aPortionMap;
2665     xub_StrLen nLastPorStart = STRING_LEN;
2666     sal_uInt16 i = 0;
2667     int nKey = 0;
2668 
2669     // get portions by start position:
2670     for ( i = 0; i < Count(); ++i )
2671     {
2672         SwTxtAttr *pHt = GetTextHint( i );
2673         if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2674              RES_TXTATR_AUTOFMT != pHt->Which() )
2675              //&&
2676              //RES_TXTATR_INETFMT != pHt->Which() )
2677             continue;
2678 
2679         const xub_StrLen nPorStart = *pHt->GetStart();
2680         if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
2681             ++nKey;
2682         nLastPorStart = nPorStart;
2683         aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
2684     }
2685 
2686     // check if portion i can be merged with portion i+1:
2687     i = 0;
2688     int j = i + 1;
2689     while ( i <= nKey )
2690     {
2691         std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2692         std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2693         PortionMap::iterator aIter1 = aRange1.first;
2694         PortionMap::iterator aIter2 = aRange2.first;
2695 
2696         bool bMerge = true;
2697         const sal_uInt16 nAttributesInPor1  = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
2698         const sal_uInt16 nAttributesInPor2  = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
2699 
2700         if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
2701         {
2702             while ( aIter1 != aRange1.second )
2703             {
2704                 const SwTxtAttr* p1 = (*aIter1).second;
2705                 const SwTxtAttr* p2 = (*aIter2).second;
2706                 if ( *p1->End() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
2707                 {
2708                     bMerge = false;
2709                     break;
2710                 }
2711                 ++aIter1;
2712                 ++aIter2;
2713             }
2714         }
2715         else
2716         {
2717             bMerge = false;
2718         }
2719 
2720         if ( bMerge )
2721         {
2722             // erase all elements with key i + 1
2723             xub_StrLen nNewPortionEnd = 0;
2724             for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2725             {
2726                 SwTxtAttr* p2 = (*aIter2).second;
2727                 nNewPortionEnd = *p2->GetEnd();
2728 
2729                 const sal_uInt16 nCountBeforeDelete = Count();
2730                 Delete( p2 );
2731 
2732                 // robust: check if deletion actually took place before destroying attribute:
2733                 if ( Count() < nCountBeforeDelete )
2734                     rNode.DestroyAttr( p2 );
2735             }
2736             aPortionMap.erase( aRange2.first, aRange2.second );
2737             ++j;
2738 
2739             // change all attributes with key i
2740             aRange1 = aPortionMap.equal_range( i );
2741             for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2742             {
2743                 SwTxtAttr* p1 = (*aIter1).second;
2744                 NoteInHistory( p1 );
2745                 *p1->GetEnd() = nNewPortionEnd;
2746                 NoteInHistory( p1, true );
2747                 bRet = true;
2748             }
2749         }
2750         else
2751         {
2752             ++i;
2753             j = i + 1;
2754         }
2755     }
2756 
2757     if ( bRet )
2758     {
2759         SwpHintsArray::Resort();
2760     }
2761 
2762     return bRet;
2763 }
2764 
2765 // check if there is already a character format and adjust the sort numbers
2766 void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
2767 {
2768     const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
2769     const xub_StrLen nHtEnd   = *rNewCharFmt.GetEnd();
2770     sal_uInt16 nSortNumber = 0;
2771 
2772     for ( sal_uInt16 i = 0; i < rHints.Count(); ++i )
2773     {
2774         const SwTxtAttr* pOtherHt = rHints[i];
2775 
2776         const xub_StrLen nOtherStart = *pOtherHt->GetStart();
2777 
2778         if ( nOtherStart > nHtStart )
2779             break;
2780 
2781         if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2782         {
2783             const xub_StrLen nOtherEnd = *pOtherHt->End();
2784 
2785             if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2786             {
2787                 const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber();
2788                 nSortNumber = nOtherSortNum + 1;
2789             }
2790         }
2791     }
2792 
2793     if ( nSortNumber > 0 )
2794         rNewCharFmt.SetSortNumber( nSortNumber );
2795 }
2796 
2797 /*************************************************************************
2798  *						SwpHints::Insert()
2799  *************************************************************************/
2800 
2801 /*
2802  * Try to insert the new hint.
2803  * Depending on the type of the hint, this either always succeeds, or may fail.
2804  * Depending on the type of the hint, other hints may be deleted or
2805  * overwritten.
2806  * The return value indicates successful insertion.
2807  */
2808 bool SwpHints::TryInsertHint( SwTxtAttr* const pHint, SwTxtNode &rNode,
2809         const SetAttrMode nMode )
2810 {
2811     if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked...
2812     {
2813         ASSERT(false, "hints array full :-(");
2814         return false;
2815     }
2816 
2817 	// Felder bilden eine Ausnahme:
2818 	// 1) Sie koennen nie ueberlappen
2819 	// 2) Wenn zwei Felder genau aneinander liegen,
2820 	//	  sollen sie nicht zu einem verschmolzen werden.
2821 	// Wir koennen also auf die while-Schleife verzichten
2822 
2823     xub_StrLen *pHtEnd = pHint->GetEnd();
2824     sal_uInt16 nWhich = pHint->Which();
2825 
2826 	switch( nWhich )
2827 	{
2828 	case RES_TXTATR_CHARFMT:
2829     {
2830         // Check if character format contains hidden attribute:
2831         const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
2832         const SfxPoolItem* pItem;
2833         if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
2834             rNode.SetCalcHiddenCharFlags();
2835 
2836         ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
2837 		break;
2838     }
2839     // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary
2840     case RES_TXTATR_AUTOFMT:
2841     {
2842         // Check if auto style contains hidden attribute:
2843         const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
2844         if ( pHiddenItem )
2845             rNode.SetCalcHiddenCharFlags();
2846         break;
2847     }
2848     // <--
2849     case RES_TXTATR_INETFMT:
2850         static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
2851 		break;
2852 	case RES_TXTATR_FIELD:
2853 	case RES_TXTATR_INPUTFIELD:
2854 		{
2855 			sal_Bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
2856 			((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
2857 			SwDoc* pDoc = rNode.GetDoc();
2858 			const SwField* pFld = ((SwTxtFld*)pHint)->GetFmtFld().GetField();
2859 
2860 			if( !pDoc->IsNewFldLst() )
2861 			{
2862 				// was fuer ein Feld ist es denn ??
2863 				// bestimmte Felder mussen am Doc das Calculations-Flag updaten
2864 				switch( pFld->GetTyp()->Which() )
2865 				{
2866 				case RES_DBFLD:
2867 				case RES_SETEXPFLD:
2868 				case RES_HIDDENPARAFLD:
2869 				case RES_HIDDENTXTFLD:
2870 				case RES_DBNUMSETFLD:
2871 				case RES_DBNEXTSETFLD:
2872 					{
2873 						if( bDelFirst )
2874 							pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pHint );
2875 						if( rNode.GetNodes().IsDocNodes() )
2876 							pDoc->InsDelFldInFldLst( sal_True, *(SwTxtFld*)pHint );
2877 					}
2878 					break;
2879 				case RES_DDEFLD:
2880 					if( rNode.GetNodes().IsDocNodes() )
2881 						((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2882 					break;
2883 				}
2884 			}
2885 
2886             // gehts ins normale Nodes-Array?
2887             if( rNode.GetNodes().IsDocNodes() )
2888             {
2889                 sal_Bool bInsFldType = sal_False;
2890                 switch( pFld->GetTyp()->Which() )
2891                 {
2892                 case RES_SETEXPFLD:
2893                     bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
2894                     if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
2895                     {
2896                         // bevor die ReferenzNummer gesetzt wird, sollte
2897                         // das Feld am richtigen FeldTypen haengen!
2898                         SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
2899                                     pDoc->InsertFldType( *pFld->GetTyp() );
2900                         if( pFldType != pFld->GetTyp() )
2901                         {
2902                             SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)->GetFmtFld();
2903                             pFmtFld->RegisterToFieldType( *pFldType );
2904                             pFmtFld->GetField()->ChgTyp( pFldType );
2905                         }
2906                         pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
2907                     }
2908                     break;
2909                 case RES_USERFLD:
2910                     bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
2911                     break;
2912 
2913                 case RES_DDEFLD:
2914                     if( pDoc->IsNewFldLst() )
2915                         ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2916                     bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
2917                     break;
2918 
2919                 case RES_POSTITFLD:
2920                     if ( pDoc->GetDocShell() )
2921                         pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_INSERTED ) );
2922                     break;
2923                 }
2924                 if( bInsFldType )
2925                     pDoc->InsDeletedFldType( *pFld->GetTyp() );
2926             }
2927         }
2928         break;
2929     case RES_TXTATR_FTN :
2930 		((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
2931 		break;
2932 	case RES_TXTATR_REFMARK:
2933 		((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
2934 		if( rNode.GetNodes().IsDocNodes() )
2935 		{
2936             // search for a reference with the same name
2937 			SwTxtAttr* pTmpHt;
2938 			xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
2939 			for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n )
2940             {
2941                 if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
2942 					pHint->GetAttr() == pTmpHt->GetAttr() &&
2943 					0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
2944 					0 != ( pTmpHintEnd = pHint->GetEnd() ) )
2945 				{
2946 					SwComparePosition eCmp = ::ComparePosition(
2947 							*pTmpHt->GetStart(), *pTmpHtEnd,
2948 							*pHint->GetStart(), *pTmpHintEnd );
2949 					sal_Bool bDelOld = sal_True, bChgStart = sal_False, bChgEnd = sal_False;
2950 					switch( eCmp )
2951 					{
2952 					case POS_BEFORE:
2953 					case POS_BEHIND:	bDelOld = sal_False; break;
2954 
2955 					case POS_OUTSIDE:	bChgStart = bChgEnd = sal_True; break;
2956 
2957 					case POS_COLLIDE_END:
2958 					case POS_OVERLAP_BEFORE:	bChgStart = sal_True; break;
2959 					case POS_COLLIDE_START:
2960 					case POS_OVERLAP_BEHIND:    bChgEnd = sal_True; break;
2961                     default: break;
2962 					}
2963 
2964 					if( bChgStart )
2965 						*pHint->GetStart() = *pTmpHt->GetStart();
2966 					if( bChgEnd )
2967 						*pTmpHintEnd = *pTmpHtEnd;
2968 
2969 					if( bDelOld )
2970                     {
2971                         NoteInHistory( pTmpHt );
2972 						rNode.DestroyAttr( Cut( n-- ) );
2973 						--nEnd;
2974 					}
2975 				}
2976             }
2977 		}
2978 		break;
2979 	case RES_TXTATR_TOXMARK:
2980 		((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
2981 		break;
2982 
2983 	case RES_TXTATR_CJK_RUBY:
2984         static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode);
2985 		break;
2986 
2987     case RES_TXTATR_META:
2988     case RES_TXTATR_METAFIELD:
2989         static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode );
2990         break;
2991 
2992     case RES_CHRATR_HIDDEN:
2993         rNode.SetCalcHiddenCharFlags();
2994         break;
2995 	}
2996 
2997 	if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
2998 		pHint->SetDontExpand( sal_True );
2999 
3000 	// SwTxtAttrs ohne Ende werden sonderbehandelt:
3001 	// Sie werden natuerlich in das Array insertet, aber sie werden nicht
3002 	// in die pPrev/Next/On/Off-Verkettung aufgenommen.
3003 	// Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
3004 	xub_StrLen nHtStart = *pHint->GetStart();
3005 	if( !pHtEnd )
3006     {
3007         SwpHintsArray::Insert( pHint );
3008 		CalcFlags();
3009 #ifdef DBG_UTIL
3010         if( !rNode.GetDoc()->IsInReading() )
3011             CHECK;
3012 #endif
3013 		// ... und die Abhaengigen benachrichtigen
3014 		if ( rNode.GetDepends() )
3015 		{
3016 			SwUpdateAttr aHint( nHtStart, nHtStart, nWhich );
3017 			rNode.ModifyNotification( 0, &aHint );
3018         }
3019         return true;
3020     }
3021 
3022 	// ----------------------------------------------------------------
3023 	// Ab hier gibt es nur noch pHint mit einem EndIdx !!!
3024 
3025     if( *pHtEnd < nHtStart )
3026 	{
3027 		ASSERT( *pHtEnd >= nHtStart,
3028 					"+SwpHints::Insert: invalid hint, end < start" );
3029 
3030 		// Wir drehen den Quatsch einfach um:
3031 		*pHint->GetStart() = *pHtEnd;
3032 		*pHtEnd = nHtStart;
3033 		nHtStart = *pHint->GetStart();
3034 	}
3035 
3036     // I need this value later on for notification but the pointer may become invalid
3037     const xub_StrLen nHintEnd = *pHtEnd;
3038     const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
3039 
3040     // handle nesting attributes: inserting may fail due to overlap!
3041     if (pHint->IsNesting())
3042     {
3043         const bool bRet(
3044             TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint)));
3045         if (!bRet) return false;
3046     }
3047     // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
3048     // These attributes may be inserted directly.
3049     // Also attributes without length may be inserted directly.
3050     // SETATTR_NOHINTADJUST is set e.g., during undo.
3051     // Portion building in not necessary during XML import.
3052     else
3053     if ( !bNoHintAdjustMode &&
3054          !pHint->IsOverlapAllowedAttr() &&
3055          !rNode.GetDoc()->IsInXMLImport() &&
3056          ( RES_TXTATR_AUTOFMT == nWhich ||
3057            RES_TXTATR_CHARFMT == nWhich ) )
3058     {
3059         ASSERT( nWhich != RES_TXTATR_AUTOFMT ||
3060                 static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
3061                 &rNode.GetDoc()->GetAttrPool(),
3062                 "AUTOSTYLES - Pool mismatch" )
3063 
3064         BuildPortions( rNode, *pHint, nMode );
3065 
3066         if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
3067             MergePortions( rNode );
3068     }
3069     else
3070     {
3071         // There may be more than one character style at the current position.
3072         // Take care of the sort number.
3073         // Special case ruby portion: During import, the ruby attribute is set
3074         // multiple times
3075         // Special case hyperlink: During import, the ruby attribute is set
3076         // multiple times
3077         // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
3078         // character attributes directly
3079         if ( ( RES_TXTATR_CHARFMT  == nWhich && !bNoHintAdjustMode ) )
3080         {
3081             BuildPortions( rNode, *pHint, nMode );
3082         }
3083         else
3084         {
3085             // --> FME 2007-11-08 #i82989# Check sort numbers in NoHintAdjustMode
3086             if ( RES_TXTATR_CHARFMT == nWhich )
3087                 lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
3088             // <--
3089 
3090             SwpHintsArray::Insert( pHint );
3091             NoteInHistory( pHint, true );
3092         }
3093     }
3094 
3095     // ... und die Abhaengigen benachrichtigen
3096 	if ( rNode.GetDepends() )
3097 	{
3098 		SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich );
3099 		rNode.ModifyNotification( 0, &aHint );
3100 	}
3101 
3102 #ifdef DBG_UTIL
3103     if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
3104         CHECK;
3105 #endif
3106 
3107     return true;
3108 }
3109 
3110 /*************************************************************************
3111  *						SwpHints::DeleteAtPos()
3112  *************************************************************************/
3113 
3114 void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
3115 {
3116     SwTxtAttr *pHint = GetTextHint(nPos);
3117     // ChainDelete( pHint );
3118     NoteInHistory( pHint );
3119     SwpHintsArray::DeleteAtPos( nPos );
3120 
3121     if( RES_TXTATR_FIELD == pHint->Which() )
3122     {
3123         const SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFmtFld().GetField()->GetTyp();
3124         if( RES_DDEFLD == pFldTyp->Which() )
3125         {
3126             const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
3127             if( pNd && pNd->GetNodes().IsDocNodes() )
3128                 ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
3129             ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
3130         }
3131         else if( RES_POSTITFLD == pFldTyp->Which() )
3132         {
3133             const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_REMOVED ) );
3134         }
3135         else if ( m_bHasHiddenParaField &&
3136                  RES_HIDDENPARAFLD == pFldTyp->Which() )
3137         {
3138             m_bCalcHiddenParaField = true;
3139         }
3140     }
3141 
3142     CalcFlags();
3143     CHECK;
3144 }
3145 
3146 // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
3147 // Ist er nicht im Array, so gibt es ein ASSERT !!
3148 
3149 void SwpHints::Delete( SwTxtAttr* pTxtHt )
3150 {
3151 	// Attr 2.0: SwpHintsArr::Delete( pTxtHt );
3152 	const sal_uInt16 nPos = GetStartOf( pTxtHt );
3153 	ASSERT( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
3154 	if( USHRT_MAX != nPos )
3155 		DeleteAtPos( nPos );
3156 }
3157 
3158 void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
3159 {
3160     if ( HasHints() )
3161     {
3162         sal_uInt16 nPos = 0;
3163         while ( nPos < m_pSwpHints->Count() )
3164         {
3165             SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
3166             bool bDel = false;
3167 
3168             switch( pDel->Which() )
3169             {
3170             case RES_TXTATR_FLYCNT:
3171             case RES_TXTATR_FTN:
3172                 break;
3173 
3174             case RES_TXTATR_FIELD:
3175             case RES_TXTATR_INPUTFIELD:
3176                 if( bDelFields )
3177                     bDel = true;
3178                 break;
3179             default:
3180                 bDel = true; break;
3181             }
3182 
3183             if( bDel )
3184             {
3185                 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
3186 				DestroyAttr( pDel );
3187 			}
3188 			else
3189 				++nPos;
3190 		}
3191 	}
3192 }
3193 
3194 sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
3195                            sal_uInt16 nScript ) const
3196 {
3197 	sal_uInt16 nRet = LANGUAGE_DONTKNOW;
3198 
3199     if ( ! nScript )
3200     {
3201         nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
3202     }
3203 
3204     // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0
3205     const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
3206     // <--
3207 
3208     if ( HasHints() )
3209     {
3210         const xub_StrLen nEnd = nBegin + nLen;
3211         for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
3212         {
3213 			// ist der Attribut-Anfang schon groesser als der Idx ?
3214             const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
3215             const xub_StrLen nAttrStart = *pHt->GetStart();
3216 			if( nEnd < nAttrStart )
3217 				break;
3218 
3219 			const sal_uInt16 nWhich = pHt->Which();
3220 
3221             if( nWhichId == nWhich ||
3222                     ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
3223             {
3224 				const xub_StrLen *pEndIdx = pHt->End();
3225 				// Ueberlappt das Attribut den Bereich?
3226 
3227 				if( pEndIdx &&
3228 					nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
3229 					 	: (( nAttrStart < nBegin &&
3230 								( pHt->DontExpand() ? nBegin < *pEndIdx
3231 													: nBegin <= *pEndIdx )) ||
3232 							( nBegin == nAttrStart &&
3233 								( nAttrStart == *pEndIdx || !nBegin ))) )
3234 				{
3235                     const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
3236                     sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
3237 
3238 					// Umfasst das Attribut den Bereich komplett?
3239 					if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
3240 						nRet = nLng;
3241 					else if( LANGUAGE_DONTKNOW == nRet )
3242 						nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
3243 				}
3244 			}
3245 		}
3246 	}
3247 	if( LANGUAGE_DONTKNOW == nRet )
3248 	{
3249 		nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
3250 		if( LANGUAGE_DONTKNOW == nRet )
3251             nRet = static_cast<sal_uInt16>(GetAppLanguage());
3252 	}
3253 	return nRet;
3254 }
3255 
3256 
3257 sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
3258 {
3259     sal_Unicode cRet = CH_TXTATR_BREAKWORD;
3260     switch ( rAttr.Which() )
3261     {
3262         case RES_TXTATR_FTN:
3263         case RES_TXTATR_REFMARK:
3264         case RES_TXTATR_TOXMARK:
3265         case RES_TXTATR_META:
3266         case RES_TXTATR_METAFIELD:
3267             cRet = CH_TXTATR_INWORD;
3268         break;
3269 
3270         case RES_TXTATR_FIELD:
3271         case RES_TXTATR_FLYCNT:
3272         {
3273             cRet = CH_TXTATR_BREAKWORD;
3274 
3275             // #i78149: PostIt fields should not break words for spell and grammar checking
3276             if (rAttr.Which() == RES_TXTATR_FIELD &&
3277                 RES_POSTITFLD == rAttr.GetFmtFld().GetField()->GetTyp()->Which())
3278                 cRet = CH_TXTATR_INWORD;
3279         }
3280         break;
3281 
3282         default:
3283             ASSERT(false, "GetCharOfTxtAttr: unknown attr");
3284             break;
3285     }
3286     return cRet;
3287 }
3288 
3289 
3290