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