LCOV - code coverage report
Current view: top level - libreoffice/sw/source/core/txtnode - thints.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 735 1214 60.5 %
Date: 2012-12-27 Functions: 30 52 57.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10