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: 749 1214 61.7 %
Date: 2012-12-17 Functions: 31 52 59.6 %
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        4994 : 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        4994 :     , m_bDDEFields(false)
      91             : {
      92        4994 : }
      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          22 : bool isSelfNestable(const sal_uInt16 nWhich)
     157             : {
     158          22 :     if ((RES_TXTATR_INETFMT  == nWhich) ||
     159             :         (RES_TXTATR_CJK_RUBY == nWhich))
     160          22 :         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          22 : void SwTxtINetFmt::InitINetFmt(SwTxtNode & rNode)
     203             : {
     204          22 :     ChgTxtNode(&rNode);
     205             :     SwCharFmt * const pFmt(
     206          22 :          rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_INET_NORMAL) );
     207          22 :     pFmt->Add( this );
     208          22 : }
     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          22 : void SwpHints::InsertNesting(SwTxtAttrNesting & rNewHint)
     275             : {
     276          22 :     SwpHintsArray::Insert(& rNewHint);
     277          22 :     NoteInHistory( & rNewHint, true );
     278          22 : }
     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          22 : SwpHints::TryInsertNesting( SwTxtNode & rNode, SwTxtAttrNesting & rNewHint )
     349             : {
     350             : //    INVARIANT:  the nestable hints in the array are properly nested
     351          22 :     const sal_uInt16 nNewWhich( rNewHint.Which() );
     352          22 :     const xub_StrLen nNewStart( *rNewHint.GetStart() );
     353          22 :     const xub_StrLen nNewEnd  ( *rNewHint.GetEnd()   );
     354             : //???    const bool bNoLengthAttribute( nNewStart == nNewEnd );
     355          22 :     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          22 :     NestList_t OverlappingExisting; // existing hints to be split
     364          22 :     NestList_t OverwrittenExisting; // existing hints to be replaced
     365          22 :     NestList_t SplitNew;            // new hints to be inserted
     366             : 
     367          22 :     SplitNew.push_back(& rNewHint);
     368             : 
     369             :     // pass 1: split the inserted hint into fragments if necessary
     370         972 :     for ( sal_uInt16 i = 0; i < GetEndCount(); ++i )
     371             :     {
     372         950 :         SwTxtAttr * const pOther = GetEnd(i);
     373             : 
     374         950 :         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          66 :     for (NestList_t::iterator itOther = OverlappingExisting.begin();
     442          44 :             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          22 :     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         132 :     for (NestList_t::iterator iter = SplitNew.begin();
     523          88 :             iter != SplitNew.end(); ++iter)
     524             :     {
     525          22 :         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          66 :     for (NestList_t::iterator itOther = OverwrittenExisting.begin();
     532          44 :             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          22 :     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       20358 : void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint,
     577             :         const SetAttrMode nMode )
     578             : {
     579       20358 :     const sal_uInt16 nWhich = rNewHint.Which();
     580             : 
     581       20358 :     const xub_StrLen nThisStart = *rNewHint.GetStart();
     582       20358 :     const xub_StrLen nThisEnd =   *rNewHint.GetEnd();
     583       20358 :     const bool bNoLengthAttribute = nThisStart == nThisEnd;
     584             : 
     585       20358 :     std::vector<SwTxtAttr*> aInsDelHints;
     586       20358 :     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       20358 :     if ( !bNoLengthAttribute ) // nothing to do for no length attributes
     597             :     {
     598      167682 :         for ( sal_uInt16 i = 0; i < Count(); ++i )
     599             :         {
     600      148058 :             SwTxtAttr* pOther = GetTextHint(i);
     601             : 
     602      296098 :             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
     603      148040 :                  RES_TXTATR_AUTOFMT != pOther->Which() )
     604       29302 :                 continue;
     605             : 
     606      118756 :             xub_StrLen nOtherStart = *pOther->GetStart();
     607      118756 :             const xub_StrLen nOtherEnd = *pOther->GetEnd();
     608             : 
     609             :             // Check if start of new attribute overlaps with pOther:
     610             :             // Split pOther if necessary:
     611      118756 :             if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
     612             :             {
     613          56 :                 SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
     614         112 :                         pOther->GetAttr(), nOtherStart, nThisStart );
     615          56 :                 if ( RES_TXTATR_CHARFMT == pOther->Which() )
     616           0 :                     static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
     617          56 :                 aInsDelHints.push_back( pNewAttr );
     618             : 
     619          56 :                 NoteInHistory( pOther );
     620          56 :                 *pOther->GetStart() = nThisStart;
     621          56 :                 NoteInHistory( pOther, true );
     622             : 
     623          56 :                 nOtherStart = nThisStart;
     624             :             }
     625             : 
     626             :             // Check if end of new attribute overlaps with pOther:
     627             :             // Split pOther if necessary:
     628      118756 :             if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
     629             :             {
     630        1630 :                 SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
     631        3260 :                         pOther->GetAttr(), nOtherStart, nThisEnd );
     632        1630 :                 if ( RES_TXTATR_CHARFMT == pOther->Which() )
     633           0 :                     static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
     634        1630 :                 aInsDelHints.push_back( pNewAttr );
     635             : 
     636        1630 :                 NoteInHistory( pOther );
     637        1630 :                 *pOther->GetStart() = nThisEnd;
     638        1630 :                 NoteInHistory( pOther, true );
     639             :             }
     640             :         }
     641             : 
     642             :         // Insert the newly created attributes:
     643       21310 :         for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
     644             :         {
     645        1686 :             SwpHintsArray::Insert( *aIter );
     646        1686 :             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       20358 :     std::set<xub_StrLen> aBounds;
     659       20358 :     aBounds.insert( nThisStart );
     660       20358 :     aBounds.insert( nThisEnd );
     661             : 
     662       20358 :     if ( !bNoLengthAttribute ) // nothing to do for no length attributes
     663             :     {
     664      169368 :         for ( sal_uInt16 i = 0; i < Count(); ++i )
     665             :         {
     666      149744 :             const SwTxtAttr* pOther = GetTextHint(i);
     667             : 
     668      299470 :             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
     669      149726 :                  RES_TXTATR_AUTOFMT != pOther->Which() )
     670       29302 :                 continue;
     671             : 
     672      120442 :             const xub_StrLen nOtherStart = *pOther->GetStart();
     673      120442 :             const xub_StrLen nOtherEnd = *pOther->GetEnd();
     674             : 
     675      120442 :             aBounds.insert( nOtherStart );
     676      120442 :             aBounds.insert( nOtherEnd );
     677             :         }
     678             :     }
     679             : 
     680       20358 :     std::set<xub_StrLen>::iterator aStartIter = aBounds.lower_bound( nThisStart );
     681       20358 :     std::set<xub_StrLen>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
     682       20358 :     xub_StrLen nPorStart = *aStartIter;
     683       20358 :     ++aStartIter;
     684       20358 :     bool bDestroyHint = true;
     685             : 
     686             :     //
     687             :     // Insert the 1...n new parts of the new attribute:
     688             :     //
     689       61512 :     while ( aStartIter != aEndIter || bNoLengthAttribute )
     690             :     {
     691             :         OSL_ENSURE( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" );
     692             : 
     693       21530 :         const xub_StrLen nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
     694       21530 :         aInsDelHints.clear();
     695             : 
     696             :         // Get all hints that are in [nPorStart, nPorEnd[:
     697      189142 :         for ( sal_uInt16 i = 0; i < Count(); ++i )
     698             :         {
     699      170990 :             SwTxtAttr *pOther = GetTextHint(i);
     700             : 
     701      341962 :             if ( RES_TXTATR_CHARFMT != pOther->Which() &&
     702      170972 :                  RES_TXTATR_AUTOFMT != pOther->Which() )
     703       29394 :                 continue;
     704             : 
     705      141596 :             const xub_StrLen nOtherStart = *pOther->GetStart();
     706             : 
     707      141596 :             if ( nOtherStart > nPorStart )
     708             :                 break;
     709             : 
     710      138218 :             if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
     711             :             {
     712             :                 OSL_ENSURE( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" );
     713       16552 :                 aInsDelHints.push_back( pOther );
     714             :             }
     715             :         }
     716             : 
     717       21530 :         SwTxtAttr* pNewAttr = 0;
     718       21530 :         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          28 :             sal_uInt16 nCharStyleCount = 0;
     724          28 :             aIter = aInsDelHints.begin();
     725          56 :             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          28 :             if ( nPorStart == nThisStart &&
     794             :                  nPorEnd == nThisEnd &&
     795             :                  !nCharStyleCount )
     796             :             {
     797          28 :                 pNewAttr = &rNewHint;
     798          28 :                 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       21502 :             SwTxtAttr* pCurrentAutoStyle = 0;
     811       21502 :             SwTxtAttr* pCurrentCharFmt = 0;
     812       21502 :             aIter = aInsDelHints.begin();
     813       59556 :             while ( aIter != aInsDelHints.end() )
     814             :             {
     815       16552 :                 if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
     816       16540 :                     pCurrentAutoStyle = *aIter;
     817          12 :                 else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
     818          12 :                     pCurrentCharFmt = *aIter;
     819       16552 :                 ++aIter;
     820             :             }
     821             : 
     822       21502 :             boost::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFmtAutoFmt&>(rNewHint.GetAttr()).GetStyleHandle();
     823       21502 :             if ( pCurrentAutoStyle )
     824             :             {
     825       16540 :                 boost::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFmtAutoFmt&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
     826             : 
     827             :                 // Merge attributes
     828       16540 :                 SfxItemSet aNewSet( *pCurrentStyle );
     829       16540 :                 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       16540 :                 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
     834             :                 {
     835       10556 :                     SfxItemIter aIter2( aNewSet );
     836       10556 :                     const SfxPoolItem* pItem = aIter2.GetCurItem();
     837       10556 :                     const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
     838             : 
     839       41950 :                     do
     840             :                     {
     841       41950 :                         const SfxPoolItem* pTmpItem = 0;
     842       41950 :                         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       52506 :                     while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
     851             :                 }
     852             : 
     853             :                 // Remove old hint
     854       16540 :                 Delete( pCurrentAutoStyle );
     855       16540 :                 rNode.DestroyAttr( pCurrentAutoStyle );
     856             : 
     857             :                 // Create new AutoStyle
     858       16540 :                 if ( aNewSet.Count() )
     859       16540 :                     pNewAttr = MakeTxtAttr( *rNode.GetDoc(), aNewSet,
     860       33080 :                             nPorStart, nPorEnd );
     861             :             }
     862             :             else
     863             :             {
     864             :                 // Remove any attributes which are already set at the whole paragraph:
     865        4962 :                 bool bOptimizeAllowed = true;
     866             : 
     867        4962 :                 SfxItemSet* pNewSet = 0;
     868             :                 // #i75750# Remove attributes already set at whole paragraph
     869             :                 // #i81764# This should not be applied for no length attributes!!! <--
     870        4962 :                 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
     871             :                 {
     872        3536 :                     SfxItemIter aIter2( *pNewStyle );
     873        3536 :                     const SfxPoolItem* pItem = aIter2.GetCurItem();
     874        3536 :                     const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
     875             : 
     876        3722 :                     do
     877             :                     {
     878        3722 :                         const SfxPoolItem* pTmpItem = 0;
     879        3722 :                         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        3722 :                     while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
     892             : 
     893        3536 :                     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        3536 :                     }
     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        4962 :                 if ( bOptimizeAllowed &&
     909             :                      nPorStart == nThisStart &&
     910             :                      nPorEnd == nThisEnd )
     911             :                 {
     912        4666 :                     pNewAttr = &rNewHint;
     913        4666 :                     bDestroyHint = false;
     914             :                 }
     915         296 :                 else if ( pNewStyle.get() )
     916             :                 {
     917         296 :                     pNewAttr = MakeTxtAttr( *rNode.GetDoc(), *pNewStyle,
     918         592 :                             nPorStart, nPorEnd );
     919             :                 }
     920       21502 :             }
     921             :         }
     922             : 
     923       21530 :         if ( pNewAttr )
     924             :         {
     925       21530 :             SwpHintsArray::Insert( pNewAttr );
     926             : //            if ( bDestroyHint )
     927       21530 :                 NoteInHistory( pNewAttr, true );
     928             :         }
     929             : 
     930       21530 :         if ( !bNoLengthAttribute )
     931             :         {
     932       20796 :             nPorStart = *aStartIter;
     933       20796 :             ++aStartIter;
     934             :         }
     935             :         else
     936         734 :             break;
     937             :     }
     938             : 
     939       20358 :     if ( bDestroyHint )
     940       15664 :         rNode.DestroyAttr( &rNewHint );
     941       20358 : }
     942             : 
     943             : /*************************************************************************
     944             :  *                      SwTxtNode::MakeTxtAttr()
     945             :  *************************************************************************/
     946             : 
     947          20 : SwTxtAttr* MakeRedlineTxtAttr( SwDoc & rDoc, SfxPoolItem & rAttr )
     948             : {
     949             :     // this is intended _only_ for special-purpose redline attributes!
     950          20 :     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          20 :             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          20 :         const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
     973          20 :     return new SwTxtAttrEnd( rNew, 0, 0 );
     974             : }
     975             : 
     976             : // create new text attribute
     977       41175 : 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       41175 :     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         554 :         SfxItemSet aItemSet( rDoc.GetAttrPool(),
     987         554 :                 RES_CHRATR_BEGIN, RES_CHRATR_END );
     988         554 :         aItemSet.Put( rAttr );
     989         554 :         return MakeTxtAttr( rDoc, aItemSet, nStt, nEnd );
     990             :     }
     991      159626 :     else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
     992             :               static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()->
     993      119005 :                 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       40621 :         const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
    1008             : 
    1009       40621 :     SwTxtAttr* pNew = 0;
    1010       40621 :     switch( rNew.Which() )
    1011             :     {
    1012             :     case RES_TXTATR_CHARFMT:
    1013             :         {
    1014          28 :             SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
    1015          28 :             if( !rFmtCharFmt.GetCharFmt() )
    1016             :             {
    1017           0 :                 rFmtCharFmt.SetCharFmt( rDoc.GetDfltCharFmt() );
    1018             :             }
    1019             : 
    1020          28 :             pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
    1021             :         }
    1022          28 :         break;
    1023             :     case RES_TXTATR_INETFMT:
    1024          22 :         pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
    1025          22 :         break;
    1026             :     case RES_TXTATR_FIELD:
    1027             :         pNew = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt,
    1028         989 :                     rDoc.IsClipBoard() );
    1029         989 :         break;
    1030             :     case RES_TXTATR_FLYCNT:
    1031             :         {
    1032             :             // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
    1033         372 :             pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
    1034             :             // Kopie von einem Text-Attribut
    1035         372 :             if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() )
    1036             :             {
    1037             :                 // then the format must be copied
    1038           2 :                 static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc );
    1039             :             }
    1040             :         }
    1041         372 :         break;
    1042             :     case RES_TXTATR_FTN:
    1043          16 :         pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
    1044             :         // ggfs. SeqNo kopieren
    1045          16 :         if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
    1046           0 :             ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
    1047          16 :         break;
    1048             :     case RES_TXTATR_REFMARK:
    1049             :         pNew = nStt == nEnd
    1050           2 :                 ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
    1051           4 :                 : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
    1052           2 :         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       39192 :         pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
    1067       39192 :         break;
    1068             :     }
    1069             : 
    1070       40621 :     return pNew;
    1071             : }
    1072             : 
    1073       36920 : SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet,
    1074             :                         xub_StrLen nStt, xub_StrLen nEnd )
    1075             : {
    1076       36920 :     IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
    1077       36920 :     const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
    1078       36920 :     SwFmtAutoFmt aNewAutoFmt;
    1079       36920 :     aNewAutoFmt.SetStyleHandle( pAutoStyle );
    1080       36920 :     SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd );
    1081       36920 :     return pNew;
    1082             : }
    1083             : 
    1084             : 
    1085             : // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
    1086       39823 : void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
    1087             : {
    1088       39823 :     if( pAttr )
    1089             :     {
    1090             :         // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
    1091       39823 :         SwDoc* pDoc = GetDoc();
    1092       39823 :         sal_uInt16 nDelMsg = 0;
    1093       39823 :         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         122 :                 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
    1100         122 :                 if( pFmt )      // vom Undo auf 0 gesetzt ??
    1101         110 :                     pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt );
    1102             :             }
    1103         122 :             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         967 :             if( !pDoc->IsInDtor() )
    1116             :             {
    1117             :                 // Wenn wir ein HiddenParaField sind, dann muessen wir
    1118             :                 // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
    1119           4 :                 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           4 :                 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           4 :                         const_cast<SwFmtFld&>(pAttr->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFld(), SWFMTFLD_REMOVED ) );
    1150           4 :                         break;
    1151             :                     }
    1152             :                 }
    1153             :             }
    1154         967 :             nDelMsg = RES_FIELD_DELETED;
    1155         967 :             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           2 :             nDelMsg = RES_REFMARK_DELETED;
    1163           2 :             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       38726 :             break;
    1172             :         }
    1173             : 
    1174       39823 :         if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() )
    1175             :         {
    1176           4 :             SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() );
    1177           4 :             pDoc->GetUnoCallBack()->ModifyNotification( &aMsgHint, &aMsgHint );
    1178             :         }
    1179             : 
    1180       39823 :         SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() );
    1181             :     }
    1182       39823 : }
    1183             : 
    1184             : /*************************************************************************
    1185             :  *                      SwTxtNode::Insert()
    1186             :  *************************************************************************/
    1187             : 
    1188             : SwTxtAttr*
    1189         442 : 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         442 :     SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(), rAttr, nStart, nEnd,
    1197         884 :             (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW, this );
    1198             : 
    1199         442 :     if ( pNew )
    1200             :     {
    1201         442 :         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         442 :         if (!bSuccess || ( USHRT_MAX == m_pSwpHints->GetPos( pNew ) ))
    1206             :         {
    1207           2 :             return 0;
    1208             :         }
    1209             :     }
    1210             : 
    1211         440 :     return pNew;
    1212             : }
    1213             : 
    1214             : // take ownership of pAttr; if insertion fails, delete pAttr
    1215       22627 : bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode )
    1216             : {
    1217       22627 :     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       22627 :         : IDocumentContentOperations::INS_EMPTYEXPAND;
    1230             : 
    1231             :     // need this after TryInsertHint, when pAttr may be deleted
    1232       22627 :     const xub_StrLen nStart( *pAttr->GetStart() );
    1233       22627 :     const bool bDummyChar( pAttr->HasDummyChar() );
    1234       22627 :     if (bDummyChar)
    1235             :     {
    1236        1379 :         sal_uInt16 nInsMode = nMode;
    1237        1379 :         switch( pAttr->Which() )
    1238             :         {
    1239             :             case RES_TXTATR_FLYCNT:
    1240             :             {
    1241         372 :                 SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
    1242         372 :                 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
    1243         372 :                 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         370 :                     const SwFmtAnchor* pAnchor = 0;
    1252             :                     pFmt->GetItemState( RES_ANCHOR, sal_False,
    1253         370 :                                             (const SfxPoolItem**)&pAnchor );
    1254             : 
    1255         370 :                     SwIndex aIdx( this, *pAttr->GetStart() );
    1256         370 :                     const rtl::OUString c(GetCharOfTxtAttr(*pAttr));
    1257         370 :                     InsertText( c, aIdx, nInsertFlags );
    1258         370 :                     nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
    1259             : 
    1260        2574 :                     if (pAnchor &&
    1261         370 :                         (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
    1262         366 :                         pAnchor->GetCntntAnchor() &&
    1263        1102 :                         pAnchor->GetCntntAnchor()->nNode == *this &&
    1264         366 :                         pAnchor->GetCntntAnchor()->nContent == aIdx )
    1265             :                     {
    1266             :                         const_cast<SwIndex&>(
    1267         364 :                             pAnchor->GetCntntAnchor()->nContent)--;
    1268         370 :                     }
    1269             :                 }
    1270         372 :                 pFly->SetAnchor( this );
    1271             : 
    1272             :                 // Format-Pointer kann sich im SetAnchor geaendert haben!
    1273             :                 // (Kopieren in andere Docs!)
    1274         372 :                 pFmt = pAttr->GetFlyCnt().GetFrmFmt();
    1275         372 :                 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         410 :                 if( RES_DRAWFRMFMT == pFmt->Which() &&
    1280          38 :                     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         372 :                 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          16 :                 SwDoc *pDoc = GetDoc();
    1319          16 :                 SwNodes &rNodes = pDoc->GetNodes();
    1320             : 
    1321             :                 // FussNote in nicht Content-/Redline-Bereich einfuegen ??
    1322          16 :                 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          16 :                 bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
    1347          16 :                 if( bNewFtn )
    1348             :                 {
    1349          16 :                     ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
    1350          16 :                     SwRegHistory* pHist = GetpSwpHints()
    1351          16 :                         ? GetpSwpHints()->GetHistory() : 0;
    1352          16 :                     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          16 :                 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          16 :                     SwIndex aNdIdx( this, *pAttr->GetStart() );
    1373          16 :                     const rtl::OUString c(GetCharOfTxtAttr(*pAttr));
    1374          16 :                     InsertText( c, aNdIdx, nInsertFlags );
    1375          16 :                     nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
    1376             :                 }
    1377             : 
    1378             :                 // Wir tragen uns am FtnIdx-Array des Docs ein ...
    1379          16 :                 SwTxtFtn* pTxtFtn = 0;
    1380          16 :                 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          16 :                 if( !pTxtFtn )
    1396          16 :                     pTxtFtn = (SwTxtFtn*)pAttr;
    1397             : 
    1398             :                 // fuers Update der Nummern und zum Sortieren
    1399             :                 // muss der Node gesetzt sein.
    1400          16 :                 ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
    1401             : 
    1402             :                 // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
    1403          16 :                 if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
    1404             :                 {
    1405          16 :                     const bool bSuccess = pDoc->GetFtnIdxs().insert(pTxtFtn).second;
    1406             :                     OSL_ENSURE( bSuccess, "FtnIdx not inserted." );
    1407             :                     (void) bSuccess; // unused in non-debug
    1408             :                 }
    1409          16 :                 SwNodeIndex aTmpIndex( *this );
    1410          16 :                 pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
    1411          16 :                 ((SwTxtFtn*)pAttr)->SetSeqRefNo();
    1412             :             }
    1413          16 :             break;
    1414             : 
    1415             :             case RES_TXTATR_FIELD:
    1416             :                 {
    1417             :                     // fuer HiddenParaFields Benachrichtigungsmechanismus
    1418             :                     // anwerfen
    1419         989 :                     if( RES_HIDDENPARAFLD ==
    1420         989 :                         pAttr->GetFld().GetFld()->GetTyp()->Which() )
    1421           0 :                     bHiddenPara = true;
    1422             :                 }
    1423         989 :                 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        1379 :         if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
    1431             :         {
    1432         991 :             SwIndex aIdx( this, *pAttr->GetStart() );
    1433         991 :             InsertText( rtl::OUString(GetCharOfTxtAttr(*pAttr)), aIdx, nInsertFlags );
    1434             : 
    1435             :             // adjust end of hint to account for inserted CH_TXTATR
    1436         991 :             xub_StrLen * const pEnd(pAttr->GetEnd());
    1437         991 :             if (pEnd)
    1438             :             {
    1439           0 :                 *pEnd = *pEnd + 1;
    1440         991 :             }
    1441             :         }
    1442             :     }
    1443             : 
    1444       22627 :     GetOrCreateSwpHints();
    1445             : 
    1446             :     // 4263: AttrInsert durch TextInsert => kein Adjust
    1447       22627 :     const bool bRet = m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
    1448             : 
    1449       22627 :     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       22627 :     if ( bHiddenPara )
    1466             :     {
    1467           0 :         SetCalcHiddenParaField();
    1468             :     }
    1469             : 
    1470       22627 :     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          14 : void SwTxtNode::DeleteAttributes( const sal_uInt16 nWhich,
    1512             :     const xub_StrLen nStart, const xub_StrLen nEnd )
    1513             : {
    1514          14 :     if ( !HasHints() )
    1515          14 :         return;
    1516             : 
    1517          30 :     for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ )
    1518             :     {
    1519          16 :         SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos );
    1520          16 :         const xub_StrLen nHintStart = *(pTxtHt->GetStart());
    1521          16 :         if (nStart < nHintStart)
    1522             :         {
    1523           0 :             break; // sorted by start
    1524             :         }
    1525          16 :         else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) )
    1526             :         {
    1527          14 :             if ( nWhich == RES_CHRATR_HIDDEN  )
    1528             :             {
    1529             :                 OSL_FAIL("hey, that's a CHRATR! how did that get in?");
    1530           0 :                 SetCalcHiddenCharFlags();
    1531             :             }
    1532          14 :             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          14 :             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          14 :             xub_StrLen const * const pEndIdx = pTxtHt->GetEnd();
    1550             : 
    1551          14 :             if ( pTxtHt->HasDummyChar() )
    1552             :             {
    1553             :                 // Unbedingt Copy-konstruieren!
    1554          14 :                 const SwIndex aIdx( this, nStart );
    1555             :                 // erase the CH_TXTATR, which will also delete pTxtHt
    1556          14 :                 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          14 :     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       26939 : sal_Bool SwTxtNode::SetAttr( const SfxItemSet& rSet, xub_StrLen nStt,
    1594             :                          xub_StrLen nEnd, const SetAttrMode nMode )
    1595             : {
    1596       26939 :     if( !rSet.Count() )
    1597           0 :         return sal_False;
    1598             : 
    1599             :     // teil die Sets auf (fuer Selektion in Nodes)
    1600       26939 :     const SfxItemSet* pSet = &rSet;
    1601       26939 :     SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
    1602             : 
    1603             :     // gesamter Bereich
    1604       36947 :     if ( !nStt && (nEnd == m_Text.Len()) &&
    1605       10008 :          !(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        7248 :         bool bHasCharFmts = false;
    1610        7248 :         if ( HasHints() )
    1611             :         {
    1612        1014 :             for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
    1613             :             {
    1614         552 :                 if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
    1615             :                 {
    1616           4 :                     bHasCharFmts = true;
    1617           4 :                     break;
    1618             :                 }
    1619             :             }
    1620             :         }
    1621             : 
    1622        7248 :         if( !bHasCharFmts )
    1623             :         {
    1624        7244 :             aTxtSet.Put( rSet );
    1625             :             // If there are any character attributes in rSet,
    1626             :             // we want to set them at the paragraph:
    1627        7244 :             if( aTxtSet.Count() != rSet.Count() )
    1628             :             {
    1629        7204 :                 sal_Bool bRet = SetAttr( rSet );
    1630        7204 :                   if( !aTxtSet.Count() )
    1631        7204 :                     return bRet;
    1632             :             }
    1633             : 
    1634             :             // check for auto style:
    1635             :             const SfxPoolItem* pItem;
    1636          40 :             const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem );
    1637          40 :             if ( bAutoStyle )
    1638             :             {
    1639          12 :                 boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
    1640          12 :                 sal_Bool bRet = SetAttr( *pAutoStyleSet );
    1641          12 :                   if( 1 == aTxtSet.Count() )
    1642          12 :                     return bRet;
    1643             :             }
    1644             : 
    1645             :             // Continue with the text attributes:
    1646          28 :             pSet = &aTxtSet;
    1647             :         }
    1648             :     }
    1649             : 
    1650       19723 :     GetOrCreateSwpHints();
    1651             : 
    1652       19723 :     SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
    1653             : 
    1654       19723 :     sal_uInt16 nCount = 0;
    1655       19723 :     SfxItemIter aIter( *pSet );
    1656       19723 :     const SfxPoolItem* pItem = aIter.GetCurItem();
    1657             : 
    1658           0 :     do
    1659             :     {
    1660       19723 :         if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
    1661             :         {
    1662       19723 :             const sal_uInt16 nWhich = pItem->Which();
    1663             :             OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
    1664             :                     "SwTxtNode::SetAttr(): unknown attribute" );
    1665       19723 :             if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
    1666             :             {
    1667       19751 :                 if ((RES_TXTATR_CHARFMT == nWhich) &&
    1668          28 :                     (GetDoc()->GetDfltCharFmt() ==
    1669          28 :                      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       19723 :                     if (isCHRATR(nWhich) ||
    1678             :                         (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
    1679             :                     {
    1680       18672 :                         aCharSet.Put( *pItem );
    1681             :                     }
    1682             :                     else
    1683             :                     {
    1684             : 
    1685        1051 :                         SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
    1686        2102 :                                 const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
    1687        1051 :                         if ( pNew )
    1688             :                         {
    1689        1051 :                             if ( nEnd != nStt && !pNew->GetEnd() )
    1690             :                             {
    1691             :                                 OSL_FAIL("Attribut without end, but area marked");
    1692           0 :                                 DestroyAttr( pNew ); // do not insert
    1693             :                             }
    1694        1051 :                             else if ( InsertHint( pNew, nMode ) )
    1695             :                             {
    1696        1051 :                                 ++nCount;
    1697             :                             }
    1698             :                         }
    1699             :                     }
    1700             :                 }
    1701             :             }
    1702             :         }
    1703       19723 :         if ( aIter.IsAtEnd() )
    1704       19723 :             break;
    1705           0 :         pItem = aIter.NextItem();
    1706             :     } while( true );
    1707             : 
    1708       19723 :     if ( aCharSet.Count() )
    1709             :     {
    1710       18672 :         SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
    1711       18672 :         if ( InsertHint( pTmpNew, nMode ) )
    1712             :         {
    1713       18672 :             ++nCount;
    1714             :         }
    1715             :     }
    1716             : 
    1717       19723 :     TryDeleteSwpHints();
    1718             : 
    1719       19723 :     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        7970 : static void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
    1745             : {
    1746       23834 :     if( RES_TXTATR_CHARFMT == rAttr.Which() ||
    1747        7940 :         RES_TXTATR_INETFMT == rAttr.Which() ||
    1748        7924 :         RES_TXTATR_AUTOFMT == rAttr.Which() )
    1749             :     {
    1750        7970 :         const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
    1751             : 
    1752        7970 :         if ( pCFSet )
    1753             :         {
    1754        7970 :             SfxWhichIter aIter( *pCFSet );
    1755        7970 :             sal_uInt16 nWhich = aIter.FirstWhich();
    1756      350634 :             while( nWhich )
    1757             :             {
    1758      677312 :                 if( ( nWhich < RES_CHRATR_END ||
    1759       15894 :                       ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
    1760      326724 :                     ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
    1761       35750 :                     rSet.Put( pCFSet->Get( nWhich ) );
    1762      334694 :                 nWhich = aIter.NextWhich();
    1763        7970 :             }
    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        7970 :     rSet.Put( rAttr );
    1778        7970 : }
    1779             : 
    1780             : struct SwPoolItemEndPair
    1781             : {
    1782             : public:
    1783             :     const SfxPoolItem* mpItem;
    1784             :     xub_StrLen mnEndPos;
    1785             : 
    1786        1200 :     SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
    1787             : };
    1788             : 
    1789         267 : static void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
    1790             :                                             SfxItemSet& rSet )
    1791             : {
    1792         267 :     if ( rTxtNode.AreListLevelIndentsApplicable() )
    1793             :     {
    1794           6 :         const SwNumRule* pRule = rTxtNode.GetNumRule();
    1795           6 :         if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
    1796             :         {
    1797           6 :             const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
    1798           6 :             if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
    1799             :             {
    1800           6 :                 SvxLRSpaceItem aLR( RES_LR_SPACE );
    1801           6 :                 aLR.SetTxtLeft( rFmt.GetIndentAt() );
    1802           6 :                 aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
    1803           6 :                 rSet.Put( aLR );
    1804             :             }
    1805             :         }
    1806             :     }
    1807         267 : }
    1808             : 
    1809             : // erfrage die Attribute vom TextNode ueber den Bereich
    1810       29749 : 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       29749 :     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        8796 :                              : &lcl_MergeAttr;
    1831             : 
    1832             :         // dann besorge mal die Auto-(Fmt)Attribute
    1833        8796 :         SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
    1834        8796 :         if( !bOnlyTxtAttr )
    1835             :         {
    1836        8786 :             SwCntntNode::GetAttr( aFmtSet );
    1837        8786 :             if ( bMergeIndentValuesOfNumRule )
    1838             :             {
    1839         142 :                 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
    1840             :             }
    1841             :         }
    1842             : 
    1843        8796 :         const sal_uInt16 nSize = m_pSwpHints->Count();
    1844             : 
    1845        8796 :         if( nStt == nEnd )             // kein Bereich:
    1846             :         {
    1847      235308 :             for (sal_uInt16 n = 0; n < nSize; ++n)
    1848             :             {
    1849      231808 :                 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
    1850      231808 :                 const xub_StrLen nAttrStart = *pHt->GetStart();
    1851      231808 :                 if( nAttrStart > nEnd )         // ueber den Bereich hinaus
    1852          70 :                     break;
    1853             : 
    1854      231738 :                 const xub_StrLen* pAttrEnd = pHt->GetEnd();
    1855      231738 :                 if ( ! pAttrEnd ) // no attributes without end
    1856      228530 :                     continue;
    1857             : 
    1858        5242 :                 if( ( nAttrStart < nStt &&
    1859        2034 :                         ( pHt->DontExpand() ? nStt < *pAttrEnd
    1860             :                                             : nStt <= *pAttrEnd )) ||
    1861             :                     ( nStt == nAttrStart &&
    1862             :                         ( nAttrStart == *pAttrEnd || !nStt )))
    1863        3146 :                     (*fnMergeAttr)( rSet, pHt->GetAttr() );
    1864             :             }
    1865             :         }
    1866             :         else                            // es ist ein Bereich definiert
    1867             :         {
    1868             :             // #i75299#
    1869        5226 :             ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
    1870             : 
    1871             :             const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
    1872        5226 :                                    static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
    1873             : 
    1874       12702 :             for (sal_uInt16 n = 0; n < nSize; ++n)
    1875             :             {
    1876        7494 :                 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
    1877        7494 :                 const xub_StrLen nAttrStart = *pHt->GetStart();
    1878        7494 :                 if( nAttrStart > nEnd )         // ueber den Bereich hinaus
    1879          18 :                     break;
    1880             : 
    1881        7476 :                 const xub_StrLen* pAttrEnd = pHt->GetEnd();
    1882        7476 :                 if ( ! pAttrEnd ) // no attributes without end
    1883         316 :                     continue;
    1884             : 
    1885        7160 :                 bool bChkInvalid = false;
    1886        7160 :                 if( nAttrStart <= nStt )       // vor oder genau Start
    1887             :                 {
    1888        7018 :                     if( *pAttrEnd <= nStt )    // liegt davor
    1889        2182 :                         continue;
    1890             : 
    1891        4836 :                     if( nEnd <= *pAttrEnd )     // hinter oder genau Ende
    1892        4824 :                         (*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
    1893             :                     else
    1894             : //                  else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
    1895             :                         // uneindeutig
    1896          12 :                         bChkInvalid = true;
    1897             :                 }
    1898         142 :                 else if( nAttrStart < nEnd      // reicht in den Bereich
    1899             : )//                      && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
    1900          34 :                     bChkInvalid = true;
    1901             : 
    1902        4978 :                 if( bChkInvalid )
    1903             :                 {
    1904             :                     // uneindeutig ?
    1905          46 :                     ::std::auto_ptr< SfxItemIter > pItemIter;
    1906          46 :                     const SfxPoolItem* pItem = 0;
    1907             : 
    1908          46 :                     if ( RES_TXTATR_AUTOFMT == pHt->Which() )
    1909             :                     {
    1910          28 :                         const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
    1911          28 :                         if ( pAutoSet )
    1912             :                         {
    1913          28 :                             pItemIter.reset( new SfxItemIter( *pAutoSet ) );
    1914          28 :                             pItem = pItemIter->GetCurItem();
    1915             :                         }
    1916             :                     }
    1917             :                     else
    1918          18 :                         pItem = &pHt->GetAttr();
    1919             : 
    1920          46 :                     const sal_uInt16 nHintEnd = *pAttrEnd;
    1921             : 
    1922         154 :                     while ( pItem )
    1923             :                     {
    1924          62 :                         const sal_uInt16 nHintWhich = pItem->Which();
    1925             :                         OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
    1926             :                                 "SwTxtNode::GetAttr(): unknown attribute?");
    1927             : 
    1928          62 :                         if ( !pAttrArr.get() )
    1929             :                         {
    1930             :                             pAttrArr.reset(
    1931          24 :                                 new std::vector< SwPoolItemEndPair >(coArrSz));
    1932             :                         }
    1933             : 
    1934          62 :                         std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
    1935          80 :                         if (isCHRATR(nHintWhich) ||
    1936          18 :                             isTXTATR_WITHEND(nHintWhich))
    1937             :                         {
    1938          62 :                             pPrev += nHintWhich - RES_CHRATR_BEGIN;
    1939             :                         }
    1940             :                         else
    1941             :                         {
    1942           0 :                             pPrev = pAttrArr->end();
    1943             :                         }
    1944             : 
    1945          62 :                         if( pPrev != pAttrArr->end() )
    1946             :                         {
    1947          62 :                             if( !pPrev->mpItem )
    1948             :                             {
    1949          42 :                                 if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
    1950             :                                 {
    1951          42 :                                     if( nAttrStart > nStt )
    1952             :                                     {
    1953          26 :                                         rSet.InvalidateItem( nHintWhich );
    1954          26 :                                         pPrev->mpItem = (SfxPoolItem*)-1;
    1955             :                                     }
    1956             :                                     else
    1957             :                                     {
    1958          16 :                                         pPrev->mpItem = pItem;
    1959          16 :                                         pPrev->mnEndPos = nHintEnd;
    1960             :                                     }
    1961             :                                 }
    1962             :                             }
    1963          20 :                             else if( (SfxPoolItem*)-1 != pPrev->mpItem )
    1964             :                             {
    1965          26 :                                 if( pPrev->mnEndPos == nAttrStart &&
    1966          10 :                                     *pPrev->mpItem == *pItem )
    1967             :                                 {
    1968           4 :                                     pPrev->mpItem = pItem;
    1969           4 :                                     pPrev->mnEndPos = nHintEnd;
    1970             :                                 }
    1971             :                                 else
    1972             :                                 {
    1973          12 :                                     rSet.InvalidateItem( nHintWhich );
    1974          12 :                                     pPrev->mpItem = (SfxPoolItem*)-1;
    1975             :                                 }
    1976             :                             }
    1977             :                         }
    1978             : 
    1979         106 :                         pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
    1980         106 :                                     ? pItemIter->NextItem() : 0;
    1981          46 :                     } // end while
    1982             :                 }
    1983             :             }
    1984             : 
    1985        5226 :             if ( pAttrArr.get() )
    1986             :             {
    1987        1224 :                 for (sal_uInt16 n = 0; n < coArrSz; ++n)
    1988             :                 {
    1989        1200 :                     const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
    1990        1200 :                     if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
    1991             :                     {
    1992             :                         const sal_uInt16 nWh =
    1993           4 :                             static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
    1994             : 
    1995           4 :                         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           4 :                             rSet.InvalidateItem( nWh );
    2003             :                     }
    2004             :                 }
    2005        5226 :             }
    2006             :         }
    2007        8796 :         if( aFmtSet.Count() )
    2008             :         {
    2009             :             // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
    2010        3748 :             aFmtSet.Differentiate( rSet );
    2011             :             // jetzt alle zusammen "mergen"
    2012        3748 :             rSet.Put( aFmtSet );
    2013        8796 :         }
    2014             :     }
    2015       20953 :     else if( !bOnlyTxtAttr )
    2016             :     {
    2017             :         // dann besorge mal die Auto-(Fmt)Attribute
    2018       20953 :         SwCntntNode::GetAttr( rSet );
    2019       20953 :         if ( bMergeIndentValuesOfNumRule )
    2020             :         {
    2021         125 :             lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
    2022             :         }
    2023             :     }
    2024             : 
    2025       29749 :     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         354 :     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        3018 : SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
    2165             : {
    2166             :     typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
    2167        3018 :     AttrSpanMap_t aAttrSpanMap;
    2168             : 
    2169        3018 :     if (i_rAttrSet.Count() == 0)
    2170             :     {
    2171        3018 :         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        3018 : void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
    2228             : {
    2229        3018 :     SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
    2230        3018 :     if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
    2231          12 :         aThisSet.Put( *GetpSwAttrSet() );
    2232             : 
    2233        3018 :     GetOrCreateSwpHints();
    2234             : 
    2235        3018 :     if( pNd == this )
    2236             :     {
    2237        2664 :         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         354 :         SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
    2253         354 :         if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
    2254         272 :             aNdSet.Put( *pNd->GetpSwAttrSet() );
    2255             : 
    2256         354 :         pNd->GetOrCreateSwpHints();
    2257             : 
    2258         354 :         std::vector<sal_uInt16> aProcessedIds;
    2259             : 
    2260         354 :         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         354 :                     SfxItemSetClearer(aNdSet));
    2301             : 
    2302             :             // 3/ convert items to attrs
    2303         354 :             pNd->impl_FmtToTxtAttr(aNdSet);
    2304             : 
    2305         354 :             if( aNdSet.Count() )
    2306             :             {
    2307           0 :                 SwFmtChg aTmp1( pNd->GetFmtColl() );
    2308           0 :                 pNd->NotifyClients( &aTmp1, &aTmp1 );
    2309             :             }
    2310         354 :         }
    2311             :     }
    2312             : 
    2313        3018 :     SetCalcHiddenCharFlags();
    2314             : 
    2315        3018 :     pNd->TryDeleteSwpHints();
    2316        3018 : }
    2317             : 
    2318             : /*************************************************************************
    2319             :  *                      SwpHints::CalcFlags()
    2320             :  *************************************************************************/
    2321             : 
    2322       20387 : void SwpHints::CalcFlags()
    2323             : {
    2324       20387 :     m_bDDEFields = m_bFootnote = false;
    2325       20387 :     const sal_uInt16 nSize = Count();
    2326             :     const SwTxtAttr* pAttr;
    2327      379154 :     for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
    2328             :     {
    2329      358767 :         switch( ( pAttr = (*this)[ nPos ])->Which() )
    2330             :         {
    2331             :         case RES_TXTATR_FTN:
    2332          20 :             m_bFootnote = true;
    2333          20 :             if ( m_bDDEFields )
    2334           0 :                 return;
    2335          20 :             break;
    2336             :         case RES_TXTATR_FIELD:
    2337             :             {
    2338      245943 :                 const SwField* pFld = pAttr->GetFld().GetFld();
    2339      245943 :                 if( RES_DDEFLD == pFld->GetTyp()->Which() )
    2340             :                 {
    2341           0 :                     m_bDDEFields = true;
    2342           0 :                     if ( m_bFootnote )
    2343           0 :                         return;
    2344             :                 }
    2345             :             }
    2346      245943 :             break;
    2347             :         }
    2348             :     }
    2349             : }
    2350             : 
    2351             : /*************************************************************************
    2352             :  *                      SwpHints::CalcVisibleFlag()
    2353             :  *************************************************************************/
    2354             : 
    2355         126 : bool SwpHints::CalcHiddenParaField()
    2356             : {
    2357         126 :     m_bCalcHiddenParaField = false;
    2358         126 :     bool bOldHasHiddenParaField = m_bHasHiddenParaField;
    2359         126 :     bool bNewHasHiddenParaField  = false;
    2360         126 :     const sal_uInt16    nSize = Count();
    2361             :     const SwTxtAttr *pTxtHt;
    2362             : 
    2363         252 :     for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
    2364             :     {
    2365         126 :         pTxtHt = (*this)[ nPos ];
    2366         126 :         const sal_uInt16 nWhich = pTxtHt->Which();
    2367             : 
    2368         126 :         if( RES_TXTATR_FIELD == nWhich )
    2369             :         {
    2370         126 :             const SwFmtFld& rFld = pTxtHt->GetFld();
    2371         126 :             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         126 :     SetHiddenParaField( bNewHasHiddenParaField );
    2386         126 :     return bOldHasHiddenParaField != bNewHasHiddenParaField;
    2387             : }
    2388             : 
    2389             : 
    2390             : /*************************************************************************
    2391             :  *                      SwpHints::NoteInHistory()
    2392             :  *************************************************************************/
    2393             : 
    2394       48632 : void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
    2395             : {
    2396       48632 :     if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
    2397       48632 : }
    2398             : 
    2399             : /*************************************************************************
    2400             :  *                      SwpHints::MergePortions( )
    2401             :  *************************************************************************/
    2402             : 
    2403       20198 : bool SwpHints::MergePortions( SwTxtNode& rNode )
    2404             : {
    2405       20198 :     if ( !Count() )
    2406           0 :         return false;
    2407             : 
    2408             :     // sort before merging
    2409       20198 :     SwpHintsArray::Resort();
    2410             : 
    2411       20198 :     bool bRet = false;
    2412             :     typedef std::multimap< int, SwTxtAttr* > PortionMap;
    2413       20198 :     PortionMap aPortionMap;
    2414       20198 :     xub_StrLen nLastPorStart = STRING_LEN;
    2415       20198 :     sal_uInt16 i = 0;
    2416       20198 :     int nKey = 0;
    2417             : 
    2418             :     // get portions by start position:
    2419      175154 :     for ( i = 0; i < Count(); ++i )
    2420             :     {
    2421      154956 :         SwTxtAttr *pHt = GetTextHint( i );
    2422      309852 :         if ( RES_TXTATR_CHARFMT != pHt->Which() &&
    2423      154896 :              RES_TXTATR_AUTOFMT != pHt->Which() )
    2424             :              //&&
    2425             :              //RES_TXTATR_INETFMT != pHt->Which() )
    2426       29318 :             continue;
    2427             : 
    2428      125638 :         const xub_StrLen nPorStart = *pHt->GetStart();
    2429      125638 :         if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
    2430      105358 :             ++nKey;
    2431      125638 :         nLastPorStart = nPorStart;
    2432      125638 :         aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
    2433             :     }
    2434             : 
    2435             :     // check if portion i can be merged with portion i+1:
    2436       20198 :     i = 0;
    2437       20198 :     int j = i + 1;
    2438      166922 :     while ( i <= nKey )
    2439             :     {
    2440      126526 :         std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
    2441      126526 :         std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
    2442      126526 :         PortionMap::iterator aIter1 = aRange1.first;
    2443      126526 :         PortionMap::iterator aIter2 = aRange2.first;
    2444             : 
    2445      126526 :         bool bMerge = true;
    2446      126526 :         const sal_uInt16 nAttributesInPor1  = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
    2447      126526 :         const sal_uInt16 nAttributesInPor2  = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
    2448             : 
    2449      126526 :         if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
    2450             :         {
    2451      211554 :             while ( aIter1 != aRange1.second )
    2452             :             {
    2453      105292 :                 const SwTxtAttr* p1 = (*aIter1).second;
    2454      105292 :                 const SwTxtAttr* p2 = (*aIter2).second;
    2455      105292 :                 if ( *p1->GetEnd() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
    2456             :                 {
    2457      104322 :                     bMerge = false;
    2458      104322 :                     break;
    2459             :                 }
    2460         970 :                 ++aIter1;
    2461         970 :                 ++aIter2;
    2462      105292 :             }
    2463             :         }
    2464             :         else
    2465             :         {
    2466       21234 :             bMerge = false;
    2467             :         }
    2468             : 
    2469      126526 :         if ( bMerge )
    2470             :         {
    2471             :             // erase all elements with key i + 1
    2472         970 :             xub_StrLen nNewPortionEnd = 0;
    2473        1940 :             for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
    2474             :             {
    2475         970 :                 SwTxtAttr* p2 = (*aIter2).second;
    2476         970 :                 nNewPortionEnd = *p2->GetEnd();
    2477             : 
    2478         970 :                 const sal_uInt16 nCountBeforeDelete = Count();
    2479         970 :                 Delete( p2 );
    2480             : 
    2481             :                 // robust: check if deletion actually took place before destroying attribute:
    2482         970 :                 if ( Count() < nCountBeforeDelete )
    2483         970 :                     rNode.DestroyAttr( p2 );
    2484             :             }
    2485         970 :             aPortionMap.erase( aRange2.first, aRange2.second );
    2486         970 :             ++j;
    2487             : 
    2488             :             // change all attributes with key i
    2489         970 :             aRange1 = aPortionMap.equal_range( i );
    2490        1940 :             for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
    2491             :             {
    2492         970 :                 SwTxtAttr* p1 = (*aIter1).second;
    2493         970 :                 NoteInHistory( p1 );
    2494         970 :                 *p1->GetEnd() = nNewPortionEnd;
    2495         970 :                 NoteInHistory( p1, true );
    2496         970 :                 bRet = true;
    2497             :             }
    2498             :         }
    2499             :         else
    2500             :         {
    2501      125556 :             ++i;
    2502      125556 :             j = i + 1;
    2503             :         }
    2504             :     }
    2505             : 
    2506       20198 :     if ( bRet )
    2507             :     {
    2508         970 :         SwpHintsArray::Resort();
    2509             :     }
    2510             : 
    2511       20198 :     return bRet;
    2512             : }
    2513             : 
    2514             : // check if there is already a character format and adjust the sort numbers
    2515           6 : static void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
    2516             : {
    2517           6 :     const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
    2518           6 :     const xub_StrLen nHtEnd   = *rNewCharFmt.GetEnd();
    2519           6 :     sal_uInt16 nSortNumber = 0;
    2520             : 
    2521           6 :     for ( sal_uInt16 i = 0; i < rHints.Count(); ++i )
    2522             :     {
    2523           6 :         const SwTxtAttr* pOtherHt = rHints[i];
    2524             : 
    2525           6 :         const xub_StrLen nOtherStart = *pOtherHt->GetStart();
    2526             : 
    2527           6 :         if ( nOtherStart > nHtStart )
    2528           6 :             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           6 :     if ( nSortNumber > 0 )
    2543           0 :         rNewCharFmt.SetSortNumber( nSortNumber );
    2544           6 : }
    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       22627 : bool SwpHints::TryInsertHint( SwTxtAttr* const pHint, SwTxtNode &rNode,
    2558             :         const SetAttrMode nMode )
    2559             : {
    2560       22627 :     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       22627 :     xub_StrLen *pHtEnd = pHint->GetEnd();
    2573       22627 :     sal_uInt16 nWhich = pHint->Which();
    2574             : 
    2575       22627 :     switch( nWhich )
    2576             :     {
    2577             :     case RES_TXTATR_CHARFMT:
    2578             :     {
    2579             :         // Check if character format contains hidden attribute:
    2580          34 :         const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
    2581             :         const SfxPoolItem* pItem;
    2582          34 :         if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
    2583           0 :             rNode.SetCalcHiddenCharFlags();
    2584             : 
    2585          34 :         ((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       21192 :         const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
    2593       21192 :         if ( pHiddenItem )
    2594           2 :             rNode.SetCalcHiddenCharFlags();
    2595       21192 :         break;
    2596             :     }
    2597             :     case RES_TXTATR_INETFMT:
    2598          22 :         static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
    2599          22 :         break;
    2600             :     case RES_TXTATR_FIELD:
    2601             :         {
    2602         989 :             bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
    2603         989 :             ((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
    2604         989 :             SwDoc* pDoc = rNode.GetDoc();
    2605         989 :             const SwField* pFld = ((SwTxtFld*)pHint)->GetFld().GetFld();
    2606             : 
    2607         989 :             if( !pDoc->IsNewFldLst() )
    2608             :             {
    2609             :                 // was fuer ein Feld ist es denn ??
    2610             :                 // bestimmte Felder mussen am Doc das Calculations-Flag updaten
    2611           1 :                 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         989 :             if( rNode.GetNodes().IsDocNodes() )
    2635             :             {
    2636         989 :                 sal_Bool bInsFldType = sal_False;
    2637         989 :                 switch( pFld->GetTyp()->Which() )
    2638             :                 {
    2639             :                 case RES_SETEXPFLD:
    2640           2 :                     bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
    2641           2 :                     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           2 :                     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          18 :                     if ( pDoc->GetDocShell() )
    2669          18 :                         pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_INSERTED ) );
    2670          18 :                     break;
    2671             :                 }
    2672         989 :                 if( bInsFldType )
    2673           0 :                     pDoc->InsDeletedFldType( *pFld->GetTyp() );
    2674             :             }
    2675             :         }
    2676         989 :         break;
    2677             :     case RES_TXTATR_FTN :
    2678          16 :         ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
    2679          16 :         break;
    2680             :     case RES_TXTATR_REFMARK:
    2681           2 :         ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
    2682           2 :         if( rNode.GetNodes().IsDocNodes() )
    2683             :         {
    2684             :             // search for a reference with the same name
    2685             :             SwTxtAttr* pTmpHt;
    2686             :             xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
    2687           4 :             for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n )
    2688             :             {
    2689           2 :                 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           2 :         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       22627 :     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       22627 :     xub_StrLen nHtStart = *pHint->GetStart();
    2753       22627 :     if( !pHtEnd )
    2754             :     {
    2755        1379 :         SwpHintsArray::Insert( pHint );
    2756        1379 :         CalcFlags();
    2757             : #ifdef DBG_UTIL
    2758             :         if( !rNode.GetDoc()->IsInReading() )
    2759             :             CHECK;
    2760             : #endif
    2761             :         // ... und die Abhaengigen benachrichtigen
    2762        1379 :         if ( rNode.GetDepends() )
    2763             :         {
    2764         997 :             SwUpdateAttr aHint( nHtStart, nHtStart, nWhich );
    2765         997 :             rNode.ModifyNotification( 0, &aHint );
    2766             :         }
    2767        1379 :         return true;
    2768             :     }
    2769             : 
    2770             :     // ----------------------------------------------------------------
    2771             :     // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
    2772             : 
    2773       21248 :     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       21248 :     const xub_StrLen nHintEnd = *pHtEnd;
    2786       21248 :     const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
    2787             : 
    2788             :     // handle nesting attributes: inserting may fail due to overlap!
    2789       21248 :     if (pHint->IsNesting())
    2790             :     {
    2791             :         const bool bRet(
    2792          22 :             TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint)));
    2793          22 :         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             :     else
    2801       61950 :     if ( !bNoHintAdjustMode &&
    2802       20362 :          !pHint->IsOverlapAllowedAttr() &&
    2803       20362 :          !rNode.GetDoc()->IsInXMLImport() &&
    2804             :          ( RES_TXTATR_AUTOFMT == nWhich ||
    2805             :            RES_TXTATR_CHARFMT == nWhich ) )
    2806             :     {
    2807             :         OSL_ENSURE( nWhich != RES_TXTATR_AUTOFMT ||
    2808             :                 static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
    2809             :                 &rNode.GetDoc()->GetAttrPool(),
    2810             :                 "AUTOSTYLES - Pool mismatch" );
    2811             : 
    2812       20358 :         BuildPortions( rNode, *pHint, nMode );
    2813             : 
    2814       20358 :         if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
    2815       19624 :             MergePortions( rNode );
    2816             :     }
    2817             :     else
    2818             :     {
    2819             :         // There may be more than one character style at the current position.
    2820             :         // Take care of the sort number.
    2821             :         // Special case ruby portion: During import, the ruby attribute is set
    2822             :         // multiple times
    2823             :         // Special case hyperlink: During import, the ruby attribute is set
    2824             :         // multiple times
    2825             :         // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
    2826             :         // character attributes directly
    2827         868 :         if ( ( RES_TXTATR_CHARFMT  == nWhich && !bNoHintAdjustMode ) )
    2828             :         {
    2829           0 :             BuildPortions( rNode, *pHint, nMode );
    2830             :         }
    2831             :         else
    2832             :         {
    2833             :             // #i82989# Check sort numbers in NoHintAdjustMode
    2834         868 :             if ( RES_TXTATR_CHARFMT == nWhich )
    2835           6 :                 lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
    2836             : 
    2837         868 :             SwpHintsArray::Insert( pHint );
    2838         868 :             NoteInHistory( pHint, true );
    2839             :         }
    2840             :     }
    2841             : 
    2842             :     // ... und die Abhaengigen benachrichtigen
    2843       21248 :     if ( rNode.GetDepends() )
    2844             :     {
    2845       15960 :         SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich );
    2846       15960 :         rNode.ModifyNotification( 0, &aHint );
    2847             :     }
    2848             : 
    2849             : #ifdef DBG_UTIL
    2850             :     if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
    2851             :         CHECK;
    2852             : #endif
    2853             : 
    2854       21248 :     return true;
    2855             : }
    2856             : 
    2857             : /*************************************************************************
    2858             :  *                      SwpHints::DeleteAtPos()
    2859             :  *************************************************************************/
    2860             : 
    2861       19008 : void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
    2862             : {
    2863       19008 :     SwTxtAttr *pHint = GetTextHint(nPos);
    2864             :     // ChainDelete( pHint );
    2865       19008 :     NoteInHistory( pHint );
    2866       19008 :     SwpHintsArray::DeleteAtPos( nPos );
    2867             : 
    2868       19008 :     if( RES_TXTATR_FIELD == pHint->Which() )
    2869             :     {
    2870           4 :         SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFld().GetFld()->GetTyp();
    2871           4 :         if( RES_DDEFLD == pFldTyp->Which() )
    2872             :         {
    2873           0 :             const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
    2874           0 :             if( pNd && pNd->GetNodes().IsDocNodes() )
    2875           0 :                 ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
    2876           0 :             ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
    2877             :         }
    2878           4 :         else if( RES_POSTITFLD == pFldTyp->Which() )
    2879             :         {
    2880           4 :             const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_REMOVED ) );
    2881             :         }
    2882           0 :         else if ( m_bHasHiddenParaField &&
    2883           0 :                  RES_HIDDENPARAFLD == pFldTyp->Which() )
    2884             :         {
    2885           0 :             m_bCalcHiddenParaField = true;
    2886             :         }
    2887             :     }
    2888             : 
    2889       19008 :     CalcFlags();
    2890             :     CHECK;
    2891       19008 : }
    2892             : 
    2893             : // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
    2894             : // Ist er nicht im Array, so gibt es ein OSL_ENSURE(!!
    2895             : 
    2896       17510 : void SwpHints::Delete( SwTxtAttr* pTxtHt )
    2897             : {
    2898             :     // Attr 2.0: SwpHintsArr::Delete( pTxtHt );
    2899       17510 :     const sal_uInt16 nPos = GetStartOf( pTxtHt );
    2900             :     OSL_ENSURE( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
    2901       17510 :     if( USHRT_MAX != nPos )
    2902       17510 :         DeleteAtPos( nPos );
    2903       17510 : }
    2904             : 
    2905           0 : void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
    2906             : {
    2907           0 :     if ( HasHints() )
    2908             :     {
    2909           0 :         sal_uInt16 nPos = 0;
    2910           0 :         while ( nPos < m_pSwpHints->Count() )
    2911             :         {
    2912           0 :             SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
    2913           0 :             bool bDel = false;
    2914             : 
    2915           0 :             switch( pDel->Which() )
    2916             :             {
    2917             :             case RES_TXTATR_FLYCNT:
    2918             :             case RES_TXTATR_FTN:
    2919           0 :                 break;
    2920             : 
    2921             :             case RES_TXTATR_FIELD:
    2922           0 :                 if( bDelFields )
    2923           0 :                     bDel = true;
    2924           0 :                 break;
    2925             :             default:
    2926           0 :                 bDel = true; break;
    2927             :             }
    2928             : 
    2929           0 :             if( bDel )
    2930             :             {
    2931           0 :                 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
    2932           0 :                 DestroyAttr( pDel );
    2933             :             }
    2934             :             else
    2935           0 :                 ++nPos;
    2936             :         }
    2937             :     }
    2938           0 : }
    2939             : 
    2940       11995 : sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
    2941             :                            sal_uInt16 nScript ) const
    2942             : {
    2943       11995 :     sal_uInt16 nRet = LANGUAGE_DONTKNOW;
    2944             : 
    2945       11995 :     if ( ! nScript )
    2946             :     {
    2947        4381 :         nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
    2948             :     }
    2949             : 
    2950             :     // #i91465# Consider nScript if pSwpHints == 0
    2951       11995 :     const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
    2952             : 
    2953       11995 :     if ( HasHints() )
    2954             :     {
    2955        7356 :         const xub_StrLen nEnd = nBegin + nLen;
    2956       16083 :         for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
    2957             :         {
    2958             :             // ist der Attribut-Anfang schon groesser als der Idx ?
    2959       10352 :             const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
    2960       10352 :             const xub_StrLen nAttrStart = *pHt->GetStart();
    2961       10352 :             if( nEnd < nAttrStart )
    2962        1625 :                 break;
    2963             : 
    2964        8727 :             const sal_uInt16 nWhich = pHt->Which();
    2965             : 
    2966       23002 :             if( nWhichId == nWhich ||
    2967       14275 :                     ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
    2968             :             {
    2969        1083 :                 const xub_StrLen *pEndIdx = pHt->GetEnd();
    2970             :                 // Ueberlappt das Attribut den Bereich?
    2971             : 
    2972        1281 :                 if( pEndIdx &&
    2973             :                     nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
    2974             :                          : (( nAttrStart < nBegin &&
    2975         198 :                                 ( pHt->DontExpand() ? nBegin < *pEndIdx
    2976             :                                                     : nBegin <= *pEndIdx )) ||
    2977             :                             ( nBegin == nAttrStart &&
    2978             :                                 ( nAttrStart == *pEndIdx || !nBegin ))) )
    2979             :                 {
    2980        1005 :                     const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
    2981        1005 :                     sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
    2982             : 
    2983             :                     // Umfasst das Attribut den Bereich komplett?
    2984        1005 :                     if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
    2985        1005 :                         nRet = nLng;
    2986           0 :                     else if( LANGUAGE_DONTKNOW == nRet )
    2987           0 :                         nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
    2988             :                 }
    2989             :             }
    2990             :         }
    2991             :     }
    2992       11995 :     if( LANGUAGE_DONTKNOW == nRet )
    2993             :     {
    2994       11016 :         nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
    2995       11016 :         if( LANGUAGE_DONTKNOW == nRet )
    2996           0 :             nRet = static_cast<sal_uInt16>(GetAppLanguage());
    2997             :     }
    2998       11995 :     return nRet;
    2999             : }
    3000             : 
    3001             : 
    3002        1377 : sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
    3003             : {
    3004        1377 :     sal_Unicode cRet = CH_TXTATR_BREAKWORD;
    3005        1377 :     switch ( rAttr.Which() )
    3006             :     {
    3007             :         case RES_TXTATR_REFMARK:
    3008             :         case RES_TXTATR_TOXMARK:
    3009           2 :             cRet = CH_TXTATR_INWORD;
    3010           2 :         break;
    3011             : 
    3012             :         case RES_TXTATR_FIELD:
    3013             :         case RES_TXTATR_FLYCNT:
    3014             :         case RES_TXTATR_FTN:
    3015             :         case RES_TXTATR_META:
    3016             :         case RES_TXTATR_METAFIELD:
    3017             :         {
    3018        1375 :             cRet = CH_TXTATR_BREAKWORD;
    3019             : 
    3020             :             // #i78149: PostIt fields should not break words for spell and grammar checking
    3021        2364 :             if (rAttr.Which() == RES_TXTATR_FIELD &&
    3022         989 :                 RES_POSTITFLD == rAttr.GetFld().GetFld()->GetTyp()->Which())
    3023          18 :                 cRet = CH_TXTATR_INWORD;
    3024             :         }
    3025        1375 :         break;
    3026             : 
    3027             :         default:
    3028             :             OSL_FAIL("GetCharOfTxtAttr: unknown attr");
    3029           0 :             break;
    3030             :     }
    3031        1377 :     return cRet;
    3032             : }
    3033             : 
    3034             : 
    3035             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10