summaryrefslogtreecommitdiff
path: root/bf_sw/source/core/txtnode/sw_thints.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bf_sw/source/core/txtnode/sw_thints.cxx')
-rw-r--r--bf_sw/source/core/txtnode/sw_thints.cxx1881
1 files changed, 1881 insertions, 0 deletions
diff --git a/bf_sw/source/core/txtnode/sw_thints.cxx b/bf_sw/source/core/txtnode/sw_thints.cxx
new file mode 100644
index 000000000..00dd00f28
--- /dev/null
+++ b/bf_sw/source/core/txtnode/sw_thints.cxx
@@ -0,0 +1,1881 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+
+#include <hintids.hxx>
+
+#include <bf_svtools/whiter.hxx>
+#include <bf_svtools/itemiter.hxx>
+#include <bf_svx/langitem.hxx>
+#include <bf_svx/emphitem.hxx>
+
+#include <txtinet.hxx>
+#include <txtflcnt.hxx>
+#include <fmtanchr.hxx>
+#include <fmtfld.hxx>
+#include <fmtinfmt.hxx>
+#include <txtatr.hxx>
+#include <fchrfmt.hxx>
+#include <fmtflcnt.hxx>
+#include <fmtftn.hxx>
+#include <txttxmrk.hxx>
+#include <txtrfmrk.hxx>
+#include <txtftn.hxx>
+#include <txtfld.hxx>
+#include <charfmt.hxx>
+#include <frmfmt.hxx>
+#include <ftnidx.hxx>
+#include <breakit.hxx>
+
+#include <horiornt.hxx>
+
+#include <doc.hxx>
+#include <pam.hxx>
+#include <ndtxt.hxx>
+#include <hints.hxx> // fuer SwFmtChg
+#include <ddefld.hxx>
+#include <docufld.hxx>
+#include <expfld.hxx>
+#include <usrfld.hxx>
+#include <poolfmt.hxx>
+// OD 26.06.2003 #108784#
+#include <dcontact.hxx>
+
+#include <algorithm>
+namespace binfilter {
+
+#ifdef DBG_UTIL
+#define CHECK Check();
+#else
+#define CHECK
+#endif
+
+using namespace ::com::sun::star::i18n;
+
+/*************************************************************************
+ * SwTxtNode::MakeTxtAttr()
+ *************************************************************************/
+
+ // lege ein neues TextAttribut an und fuege es SwpHints-Array ein
+/*N*/ SwTxtAttr* SwTxtNode::MakeTxtAttr( const SfxPoolItem& rAttr,
+/*N*/ xub_StrLen nStt, xub_StrLen nEnd, BOOL bPool )
+/*N*/ {
+/*N*/ // das neue Attribut im Pool anlegen
+/*N*/ const SfxPoolItem& rNew = bPool ? GetDoc()->GetAttrPool().Put( rAttr ) :
+/*N*/ rAttr;
+/*N*/
+/*N*/ SwTxtAttr* pNew = 0;
+/*N*/ switch( rNew.Which() )
+/*N*/ {
+/*N*/ case RES_CHRATR_CASEMAP:
+/*N*/ case RES_CHRATR_COLOR:
+/*N*/ case RES_CHRATR_CHARSETCOLOR:
+/*N*/ case RES_CHRATR_CONTOUR:
+/*N*/ case RES_CHRATR_CROSSEDOUT:
+/*N*/ case RES_CHRATR_ESCAPEMENT:
+/*N*/ case RES_CHRATR_KERNING:
+/*N*/ case RES_CHRATR_SHADOWED:
+/*N*/ case RES_CHRATR_AUTOKERN:
+/*N*/ case RES_CHRATR_WORDLINEMODE:
+/*N*/ case RES_CHRATR_UNDERLINE:
+/*N*/ case RES_CHRATR_FONT:
+/*N*/ case RES_CHRATR_CTL_FONT:
+/*N*/ case RES_CHRATR_CJK_FONT:
+/*N*/ case RES_CHRATR_FONTSIZE:
+/*N*/ case RES_CHRATR_CTL_FONTSIZE:
+/*N*/ case RES_CHRATR_CJK_FONTSIZE:
+/*N*/ case RES_CHRATR_LANGUAGE:
+/*N*/ case RES_CHRATR_CTL_LANGUAGE:
+/*N*/ case RES_CHRATR_CJK_LANGUAGE:
+/*N*/ case RES_CHRATR_POSTURE:
+/*N*/ case RES_CHRATR_CTL_POSTURE:
+/*N*/ case RES_CHRATR_CJK_POSTURE:
+/*N*/ case RES_CHRATR_WEIGHT:
+/*N*/ case RES_CHRATR_CTL_WEIGHT:
+/*N*/ case RES_CHRATR_CJK_WEIGHT:
+/*N*/ case RES_CHRATR_EMPHASIS_MARK:
+/*N*/ case RES_CHRATR_NOHYPHEN:
+/*N*/ case RES_CHRATR_BLINK:
+/*N*/ case RES_CHRATR_BACKGROUND:
+/*N*/ case RES_CHRATR_ROTATE:
+/*N*/ case RES_CHRATR_SCALEW:
+/*N*/ case RES_CHRATR_RELIEF:
+/*N*/ pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
+/*N*/ break;
+/*N*/ case RES_TXTATR_CHARFMT:
+/*N*/ {
+/*N*/ SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
+/*N*/ if( !rFmtCharFmt.GetCharFmt() )
+/*?*/ rFmtCharFmt.SetCharFmt( GetDoc()->GetDfltCharFmt() );
+/*N*/
+/*N*/ pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
+/*N*/ }
+/*N*/ break;
+/*N*/ case RES_TXTATR_INETFMT:
+/*N*/ pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
+/*N*/ break;
+/*N*/ case RES_TXTATR_FIELD:
+/*N*/ pNew = new SwTxtFld( (SwFmtFld&)rNew, nStt );
+/*N*/ break;
+/*N*/ case RES_TXTATR_FLYCNT:
+/*N*/ {
+/*N*/ // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
+/*N*/ pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
+/*N*/ // Kopie von einem Text-Attribut
+/*N*/ if( ((SwFmtFlyCnt&)rAttr).GetTxtFlyCnt() )
+/*N*/ // dann muss das Format Kopiert werden
+/*N*/ ((SwTxtFlyCnt*)pNew)->CopyFlyFmt( GetDoc() );
+/*N*/ }
+/*N*/ break;
+/*N*/ case RES_TXTATR_FTN:
+/*N*/ pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
+/*N*/ // ggfs. SeqNo kopieren
+/*N*/ if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
+/*?*/ ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
+/*N*/ break;
+/*?*/ case RES_TXTATR_HARDBLANK:
+/*?*/ break;
+/*?*/ case RES_CHRATR_TWO_LINES:
+/*?*/ break;
+/*N*/ case RES_TXTATR_REFMARK:
+/*N*/ pNew = nStt == nEnd
+/*N*/ ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
+/*N*/ : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
+/*N*/ break;
+/*N*/ case RES_TXTATR_TOXMARK:
+/*N*/ pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd );
+/*N*/ break;
+/*N*/ case RES_UNKNOWNATR_CONTAINER:
+/*?*/ case RES_TXTATR_UNKNOWN_CONTAINER:
+/*?*/ break;
+/*N*/ case RES_TXTATR_CJK_RUBY:
+/*N*/ pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd );
+/*N*/ break;
+/*N*/ }
+/*N*/ OSL_ENSURE( pNew, "was fuer ein TextAttribut soll hier angelegt werden?" );
+/*N*/ return pNew;
+/*N*/ }
+
+// loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
+/*N*/ void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
+/*N*/ {
+/*N*/ if( pAttr )
+/*N*/ {
+/*N*/ // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
+/*N*/ SwDoc* pDoc = GetDoc();
+/*N*/ USHORT nDelMsg = 0;
+/*N*/ switch( pAttr->Which() )
+/*N*/ {
+/*N*/ case RES_TXTATR_FLYCNT:
+/*N*/ {
+/*N*/ // siehe auch die Anmerkung "Loeschen von Formaten
+/*N*/ // zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFmt()
+/*N*/ SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
+/*N*/ if( pFmt ) // vom Undo auf 0 gesetzt ??
+/*N*/ pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt );
+/*N*/ }
+/*N*/ break;
+/*N*/
+/*N*/ case RES_TXTATR_FTN:
+/*N*/ ((SwTxtFtn*)pAttr)->SetStartNode( 0 );
+/*N*/ nDelMsg = RES_FOOTNOTE_DELETED;
+/*N*/ break;
+/*N*/
+/*N*/ case RES_TXTATR_FIELD:
+/*N*/ if( !pDoc->IsInDtor() )
+/*N*/ {
+/*N*/ // Wenn wir ein HiddenParaField sind, dann muessen wir
+/*N*/ // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
+/*N*/ const SwField* pFld = pAttr->GetFld().GetFld();
+/*N*/
+/*N*/ //JP 06-08-95: DDE-Felder bilden eine Ausnahme
+/*N*/ OSL_ENSURE( RES_DDEFLD == pFld->GetTyp()->Which() ||
+/*N*/ this == ((SwTxtFld*)pAttr)->GetpTxtNode(),
+/*N*/ "Wo steht denn dieses Feld?" );
+/*N*/
+/*N*/ // bestimmte Felder mussen am Doc das Calculations-Flag updaten
+/*N*/ switch( pFld->GetTyp()->Which() )
+/*N*/ {
+/*?*/ case RES_HIDDENPARAFLD:
+/*?*/ SetCalcVisible();
+/*?*/ // kein break !
+/*?*/ case RES_DBSETNUMBERFLD:
+/*?*/ case RES_GETEXPFLD:
+/*?*/ case RES_DBFLD:
+/*?*/ case RES_SETEXPFLD:
+/*?*/ case RES_HIDDENTXTFLD:
+/*?*/ case RES_DBNUMSETFLD:
+/*?*/ case RES_DBNEXTSETFLD:
+/*?*/ if( !pDoc->IsNewFldLst() && GetNodes().IsDocNodes() )
+/*?*/ pDoc->InsDelFldInFldLst( FALSE, *(SwTxtFld*)pAttr );
+/*?*/ break;
+/*?*/ case RES_DDEFLD:
+/*?*/ if( GetNodes().IsDocNodes() &&
+/*?*/ ((SwTxtFld*)pAttr)->GetpTxtNode() )
+/*?*/ ((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt();
+/*?*/ break;
+/*N*/ }
+/*N*/ }
+/*N*/ nDelMsg = RES_FIELD_DELETED;
+/*N*/ break;
+/*N*/
+/*N*/ case RES_TXTATR_TOXMARK:
+/*N*/ nDelMsg = RES_TOXMARK_DELETED;
+/*N*/ break;
+/*N*/
+/*N*/ case RES_TXTATR_REFMARK:
+/*N*/ nDelMsg = RES_REFMARK_DELETED;
+/*N*/ break;
+/*N*/ }
+/*N*/
+/*N*/ if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() )
+/*N*/ {
+/*N*/ SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() );
+/*N*/ pDoc->GetUnoCallBack()->Modify( &aMsgHint, &aMsgHint );
+/*N*/ }
+/*N*/
+/*N*/ pAttr->RemoveFromPool( pDoc->GetAttrPool() );
+/*N*/ delete pAttr;
+/*N*/ }
+/*N*/ }
+
+/*************************************************************************
+ * SwTxtNode::Insert()
+ *************************************************************************/
+
+// lege ein neues TextAttribut an und fuege es ins SwpHints-Array ein
+/*N*/ SwTxtAttr* SwTxtNode::Insert( const SfxPoolItem& rAttr,
+/*N*/ xub_StrLen nStt, xub_StrLen nEnd, USHORT nMode )
+/*N*/ {
+/*N*/ SwTxtAttr* pNew = MakeTxtAttr( rAttr, nStt, nEnd );
+/*N*/ return (pNew && Insert( pNew, nMode )) ? pNew : 0;
+/*N*/ }
+
+// uebernehme den Pointer auf das Text-Attribut
+
+/*N*/ BOOL SwTxtNode::Insert( SwTxtAttr *pAttr, USHORT nMode )
+/*N*/ {
+/*N*/ BOOL bHiddenPara = FALSE;
+/*N*/
+/*N*/ OSL_ENSURE( *pAttr->GetStart() <= Len(), "StartIdx hinter Len!" );
+/*N*/
+/*N*/ if( !pAttr->GetEnd() )
+/*N*/ {
+/*N*/ USHORT nInsMode = nMode;
+/*N*/ switch( pAttr->Which() )
+/*N*/ {
+/*N*/ case RES_TXTATR_FLYCNT:
+/*N*/ {
+/*N*/ SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
+/*N*/ SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
+/*N*/ if( !(SETATTR_NOTXTATRCHR & nInsMode) )
+/*N*/ {
+/*N*/ // Wir muessen zuerst einfuegen, da in SetAnchor()
+/*N*/ // dem FlyFrm GetStart() uebermittelt wird.
+/*N*/ //JP 11.05.98: falls das Anker-Attribut schon richtig
+/*N*/ // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
+/*N*/ // des Zeichens. Sonst muesste das immer ausserhalb
+/*N*/ // erfolgen (Fehleranfaellig !)
+/*N*/ const SwFmtAnchor* pAnchor = 0;
+/*N*/ pFmt->GetItemState( RES_ANCHOR, FALSE,
+/*N*/ (const SfxPoolItem**)&pAnchor );
+/*N*/
+/*N*/ SwIndex aIdx( this, *pAttr->GetStart() );
+/*N*/ Insert( GetCharOfTxtAttr(*pAttr), aIdx );
+/*N*/ nInsMode |= SETATTR_NOTXTATRCHR;
+/*N*/
+/*N*/ if( pAnchor && FLY_IN_CNTNT == pAnchor->GetAnchorId() &&
+/*N*/ pAnchor->GetCntntAnchor() &&
+/*N*/ pAnchor->GetCntntAnchor()->nNode == *this &&
+/*N*/ pAnchor->GetCntntAnchor()->nContent == aIdx )
+/*N*/ ((SwIndex&)pAnchor->GetCntntAnchor()->nContent)--;
+/*N*/ }
+/*N*/ pFly->SetAnchor( this );
+/*N*/
+/*N*/ // Format-Pointer kann sich im SetAnchor geaendert haben!
+/*N*/ // (Kopieren in andere Docs!)
+/*N*/ pFmt = pAttr->GetFlyCnt().GetFrmFmt();
+/*N*/ SwDoc *pDoc = pFmt->GetDoc();
+/*N*/
+/*N*/ // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
+/*N*/ // But don't allow control objects in header/footer
+/*N*/ if( RES_DRAWFRMFMT == pFmt->Which() &&
+/*N*/ pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) )
+/*N*/ {
+/*N*/ SwDrawContact* pDrawContact =
+/*N*/ static_cast<SwDrawContact*>(pFmt->FindContactObj());
+/*N*/ if ( pDrawContact &&
+/*N*/ pDrawContact->GetMaster() &&
+/*N*/ ::binfilter::CheckControlLayer( pDrawContact->GetMaster() ) )
+/*N*/ {
+/*N*/ // das soll nicht meoglich sein; hier verhindern
+/*N*/ // Der Dtor des TxtHints loescht nicht das Zeichen.
+/*N*/ // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
+/*N*/ // dieses explizit loeschen
+/*?*/ if( SETATTR_NOTXTATRCHR & nInsMode )
+/*?*/ {
+/*?*/ // loesche das Zeichen aus dem String !
+/*?*/ OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
+/*?*/ aText.GetChar(*pAttr->GetStart() ) ||
+/*?*/ CH_TXTATR_INWORD ==
+/*?*/ aText.GetChar(*pAttr->GetStart())),
+/*?*/ "where is my attribu character" );
+/*?*/ aText.Erase( *pAttr->GetStart(), 1 );
+/*?*/ // Indizies Updaten
+/*?*/ SwIndex aTmpIdx( this, *pAttr->GetStart() );
+/*?*/ Update( aTmpIdx, 1, TRUE );
+/*?*/ }
+/*?*/ DestroyAttr( pAttr );
+/*?*/ return FALSE;
+/*N*/ }
+/*N*/ }
+/*N*/ break;
+/*N*/ }
+/*N*/ case RES_TXTATR_FTN :
+/*N*/ {
+/*N*/ // Fussnoten, man kommt an alles irgendwie heran.
+/*N*/ // CntntNode erzeugen und in die Inserts-Section stellen
+/*N*/ SwDoc *pDoc = GetDoc();
+/*N*/ SwNodes &rNodes = pDoc->GetNodes();
+/*N*/
+/*N*/ // FussNote in nicht Content-/Redline-Bereich einfuegen ??
+/*N*/ if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
+/*N*/ {
+/*N*/ // das soll nicht meoglich sein; hier verhindern
+/*N*/ // Der Dtor des TxtHints loescht nicht das Zeichen.
+/*N*/ // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
+/*N*/ // dieses explizit loeschen
+/*?*/ if( SETATTR_NOTXTATRCHR & nInsMode )
+/*?*/ {
+/*?*/ // loesche das Zeichen aus dem String !
+/*?*/ OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
+/*?*/ aText.GetChar(*pAttr->GetStart() ) ||
+/*?*/ CH_TXTATR_INWORD ==
+/*?*/ aText.GetChar(*pAttr->GetStart())),
+/*?*/ "where is my attribu character" );
+/*?*/ aText.Erase( *pAttr->GetStart(), 1 );
+/*?*/ // Indizies Updaten
+/*?*/ SwIndex aTmpIdx( this, *pAttr->GetStart() );
+/*?*/ Update( aTmpIdx, 1, TRUE );
+/*?*/ }
+/*?*/ DestroyAttr( pAttr );
+/*?*/ return FALSE;
+/*N*/ }
+/*N*/
+/*N*/ // wird eine neue Fussnote eingefuegt ??
+/*N*/ BOOL bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
+/*N*/ if( bNewFtn )
+/*N*/ ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
+/*N*/ else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
+/*N*/ {
+/*N*/ // loesche alle Frames der Section, auf die der StartNode zeigt
+/*N*/ ULONG nSttIdx =
+/*N*/ ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex();
+/*N*/ ULONG nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
+/*N*/ SwCntntNode* pCNd;
+/*N*/ for( ; nSttIdx < nEndIdx; ++nSttIdx )
+/*N*/ if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() ))
+/*N*/ pCNd->DelFrms();
+/*N*/ }
+/*N*/
+/*N*/ if( !(SETATTR_NOTXTATRCHR & nInsMode) )
+/*N*/ {
+/*N*/ // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
+/*N*/ // entstehen koennen und das Attribut im _SortArr_ am
+/*N*/ // Dokument nicht eingetrage wird.
+/*N*/ SwIndex aNdIdx( this, *pAttr->GetStart() );
+/*N*/ Insert( GetCharOfTxtAttr(*pAttr), aNdIdx );
+/*N*/ nInsMode |= SETATTR_NOTXTATRCHR;
+/*N*/ }
+/*N*/
+/*N*/ // Wir tragen uns am FtnIdx-Array des Docs ein ...
+/*N*/ SwTxtFtn* pTxtFtn = 0;
+/*N*/ if( !bNewFtn )
+/*N*/ {
+/*N*/ // eine alte Ftn wird umgehaengt (z.B. SplitNode)
+/*N*/ for( USHORT n = 0; n < pDoc->GetFtnIdxs().Count(); ++n )
+/*?*/ if( pAttr == pDoc->GetFtnIdxs()[n] )
+/*?*/ {
+/*?*/ // neuen Index zuweisen, dafuer aus dem SortArray
+/*?*/ // loeschen und neu eintragen
+/*?*/ pTxtFtn = pDoc->GetFtnIdxs()[n];
+/*?*/ pDoc->GetFtnIdxs().Remove( n );
+/*?*/ break;
+/*?*/ }
+/*N*/ // wenn ueber Undo der StartNode gesetzt wurde, kann
+/*N*/ // der Index noch gar nicht in der Verwaltung stehen !!
+/*N*/ }
+/*N*/ if( !pTxtFtn )
+/*N*/ pTxtFtn = (SwTxtFtn*)pAttr;
+/*N*/
+/*N*/ // fuers Update der Nummern und zum Sortieren
+/*N*/ // muss der Node gesetzt sein.
+/*N*/ ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
+/*N*/
+/*N*/ // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
+/*N*/ if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
+/*N*/ {
+/*N*/ #ifdef DBG_UTIL
+/*N*/ const BOOL bSuccess =
+/*N*/ #endif
+/*N*/ pDoc->GetFtnIdxs().Insert( pTxtFtn );
+/*N*/ #ifdef DBG_UTIL
+/*N*/ OSL_ENSURE( bSuccess, "FtnIdx nicht eingetragen." );
+/*N*/ #endif
+/*N*/ }
+/*N*/ SwNodeIndex aTmpIndex( *this );
+/*N*/ pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
+/*N*/ ((SwTxtFtn*)pAttr)->SetSeqRefNo();
+/*N*/ }
+/*N*/ break;
+/*N*/
+/*N*/ case RES_TXTATR_FIELD:
+/*N*/ {
+/*N*/ // fuer HiddenParaFields Benachrichtigungsmechanismus
+/*N*/ // anwerfen
+/*N*/ if( RES_HIDDENPARAFLD ==
+/*N*/ pAttr->GetFld().GetFld()->GetTyp()->Which() )
+/*N*/ bHiddenPara = TRUE;
+/*N*/ }
+/*N*/ break;
+/*N*/
+/*N*/ }
+/*N*/ // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_..
+/*N*/ // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
+/*N*/ // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits
+/*N*/ // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
+/*N*/ if( !(SETATTR_NOTXTATRCHR & nInsMode) )
+/*N*/ {
+/*N*/ SwIndex aIdx( this, *pAttr->GetStart() );
+/*N*/ Insert( GetCharOfTxtAttr(*pAttr), aIdx );
+/*N*/ }
+/*N*/ }
+/*N*/ else
+/*N*/ {
+/*N*/ OSL_ENSURE( *pAttr->GetEnd() <= Len(), "EndIdx hinter Len!" );
+/*N*/ }
+/*N*/
+/*N*/ if ( !pSwpHints )
+/*N*/ pSwpHints = new SwpHints();
+/*N*/
+/*N*/ // 4263: AttrInsert durch TextInsert => kein Adjust
+/*N*/ pSwpHints->Insert( pAttr, *this, nMode );
+/*N*/
+/*N*/ // 47375: In pSwpHints->Insert wird u.a. Merge gerufen und das Hints-Array
+/*N*/ // von ueberfluessigen Hints befreit, dies kann u.U. sogar der frisch
+/*N*/ // eingefuegte Hint pAttr sein, der dann zerstoert wird!!
+/*N*/ if( USHRT_MAX == pSwpHints->GetPos( pAttr ) )
+/*N*/ return FALSE;
+/*N*/
+/*N*/ if(bHiddenPara)
+/*N*/ SetCalcVisible();
+/*N*/ return TRUE;
+/*N*/ }
+
+/*************************************************************************
+ * SwTxtNode::Delete()
+ *************************************************************************/
+
+/*N*/ void SwTxtNode::Delete( SwTxtAttr *pAttr, BOOL bThisOnly )
+/*N*/ {
+/*N*/ if ( !pSwpHints )
+/*N*/ return;
+/*N*/ if( bThisOnly )
+/*N*/ {
+/*?*/ xub_StrLen* pEndIdx = pAttr->GetEnd();
+/*?*/ if( !pEndIdx )
+/*?*/ {
+/*?*/ // hat es kein Ende kann es nur das sein, was hier steht!
+/*?*/ // Unbedingt Copy-konstruieren!
+/*?*/ const SwIndex aIdx( this, *pAttr->GetStart() );
+/*?*/ Erase( aIdx, 1 );
+/*?*/ }
+/*?*/ else
+/*?*/ {
+/*?*/ // den MsgHint jetzt fuettern, weil gleich sind
+/*?*/ // Start und End weg.
+/*?*/ SwUpdateAttr aHint( *pAttr->GetStart(), *pEndIdx, pAttr->Which() );
+/*?*/ pSwpHints->Delete( pAttr );
+/*?*/ pAttr->RemoveFromPool( GetDoc()->GetAttrPool() );
+/*?*/ delete pAttr;
+/*?*/ SwModify::Modify( 0, &aHint ); // die Frames benachrichtigen
+/*?*/
+/*?*/ if( pSwpHints && pSwpHints->CanBeDeleted() )
+/*?*/ DELETEZ( pSwpHints );
+/*?*/ }
+/*?*/
+/*?*/ return;
+/*N*/ }
+/*N*/ Delete( pAttr->Which(), *pAttr->GetStart(), *pAttr->GetAnyEnd() );
+/*N*/ }
+
+/*************************************************************************
+ * SwTxtNode::Delete()
+ *************************************************************************/
+
+/*N*/ void SwTxtNode::Delete( USHORT nTxtWhich, xub_StrLen nStart, xub_StrLen nEnd )
+/*N*/ {
+/*N*/ if ( !pSwpHints )
+/*N*/ return;
+/*N*/
+/*N*/ const xub_StrLen *pEndIdx;
+/*N*/ const xub_StrLen *pSttIdx;
+/*N*/ SwTxtAttr* pTxtHt;
+/*N*/
+/*N*/ for( USHORT nPos = 0; pSwpHints && nPos < pSwpHints->Count(); nPos++ )
+/*N*/ {
+/*N*/ pTxtHt = pSwpHints->GetHt( nPos );
+/*N*/ const USHORT nWhich = pTxtHt->Which();
+/*N*/ if( nWhich == nTxtWhich &&
+/*N*/ *( pSttIdx = pTxtHt->GetStart()) == nStart )
+/*N*/ {
+/*N*/ pEndIdx = pTxtHt->GetEnd();
+/*N*/
+/*N*/ // Text-Attribute sind voellig dynamisch, so dass diese nur
+/*N*/ // mit ihrer Start-Position verglichen werden.
+/*N*/ if( !pEndIdx )
+/*N*/ {
+/*N*/ // Unbedingt Copy-konstruieren!
+/*?*/ const SwIndex aIdx( this, *pSttIdx );
+/*?*/ Erase( aIdx, 1 );
+/*?*/ break;
+/*N*/ }
+/*N*/ else if( *pEndIdx == nEnd )
+/*N*/ {
+/*N*/ // den MsgHint jetzt fuettern, weil gleich sind
+/*N*/ // Start und End weg.
+/*N*/ // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
+/*N*/ // da dies das Feld im Dtor selbst erledigt.
+/*N*/ SwUpdateAttr aHint( *pSttIdx, *pEndIdx, nTxtWhich );
+/*N*/ pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen,
+/*N*/ pTxtHt->RemoveFromPool( GetDoc()->GetAttrPool() );
+/*N*/ delete pTxtHt;
+/*N*/ SwModify::Modify( 0, &aHint ); // die Frames benachrichtigen
+/*N*/ break;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ if( pSwpHints && pSwpHints->CanBeDeleted() )
+/*N*/ DELETEZ( pSwpHints );
+/*N*/ }
+
+/*************************************************************************
+ * SwTxtNode::DelSoftHyph()
+ *************************************************************************/
+
+// setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
+// dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
+/*N*/ BOOL SwTxtNode::SetAttr( const SfxItemSet& rSet, xub_StrLen nStt,
+/*N*/ xub_StrLen nEnd, USHORT nMode )
+/*N*/ {
+/*N*/ if( !rSet.Count() )
+/*N*/ return FALSE;
+/*N*/
+/*N*/ // teil die Sets auf (fuer Selektion in Nodes)
+/*N*/ const SfxItemSet* pSet = &rSet;
+/*N*/ SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
+/*N*/
+/*N*/ // gesamter Bereich
+/*N*/ if( !nStt && nEnd == aText.Len() && !(nMode & SETATTR_NOFORMATATTR ) )
+/*N*/ {
+/*N*/ // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
+/*N*/ // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
+/*N*/ int bHasCharFmts = FALSE;
+/*N*/ if( pSwpHints )
+/*N*/ for( USHORT n = 0; n < pSwpHints->Count(); ++n )
+/*N*/ if( (*pSwpHints)[ n ]->IsCharFmtAttr() )
+/*N*/ {
+/*N*/ bHasCharFmts = TRUE;
+/*N*/ break;
+/*N*/ }
+/*N*/
+/*N*/ if( !bHasCharFmts )
+/*N*/ {
+/*N*/ aTxtSet.Put( rSet );
+/*N*/ if( aTxtSet.Count() != rSet.Count() )
+/*N*/ {
+/*N*/ BOOL bRet = SwCntntNode::SetAttr( rSet );
+/*N*/ if( !aTxtSet.Count() )
+/*N*/ return bRet;
+/*N*/ }
+/*N*/ pSet = &aTxtSet;
+/*N*/ }
+/*N*/ }
+/*N*/
+/*N*/ if ( !pSwpHints )
+/*N*/ pSwpHints = new SwpHints();
+/*N*/
+/*N*/ USHORT nWhich, nCount = 0;
+/*N*/ SwTxtAttr* pNew;
+/*N*/ SfxItemIter aIter( *pSet );
+/*N*/ const SfxPoolItem* pItem = aIter.GetCurItem();
+/*N*/ do {
+/*N*/ if( pItem && (SfxPoolItem*)-1 != pItem &&
+/*N*/ (( RES_CHRATR_BEGIN <= ( nWhich = pItem->Which()) &&
+/*N*/ RES_CHRATR_END > nWhich ) ||
+/*N*/ ( RES_TXTATR_BEGIN <= nWhich && RES_TXTATR_END > nWhich ) ||
+/*N*/ ( RES_UNKNOWNATR_BEGIN <= nWhich && RES_UNKNOWNATR_END > nWhich )) )
+/*N*/ {
+/*N*/ if( !( RES_TXTATR_CHARFMT == pItem->Which()
+ && GetDoc()->GetDfltCharFmt()==((SwFmtCharFmt*)pItem)->GetCharFmt()
+ )
+ )
+/*N*/ {
+/*N*/ pNew = MakeTxtAttr( *pItem, nStt, nEnd );
+/*N*/ if( pNew )
+/*N*/ {
+/*N*/ // Attribut ohne Ende, aber Bereich markiert ?
+/*N*/ if( nEnd != nStt && !pNew->GetEnd() )
+/*N*/ {
+/*?*/ OSL_ENSURE( !this, "Attribut ohne Ende aber Bereich vorgegeben" );
+/*?*/ DestroyAttr( pNew ); // nicht einfuegen
+/*N*/ }
+/*N*/ else if( Insert( pNew, nMode ))
+/*N*/ ++nCount;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ if( aIter.IsAtEnd() )
+/*N*/ break;
+/*?*/ pItem = aIter.NextItem();
+/*N*/ } while( TRUE );
+/*N*/
+/*N*/ if( pSwpHints && pSwpHints->CanBeDeleted() )
+/*?*/ DELETEZ( pSwpHints );
+/*N*/
+/*N*/ return nCount ? TRUE : FALSE;
+/*N*/ }
+
+/*N*/ BOOL lcl_Included( const USHORT nWhich, const SwTxtAttr *pAttr )
+/*N*/ {
+/*N*/ #if OSL_DEBUG_LEVEL > 1
+/*N*/ static long nTest = 0;
+/*N*/ ++nTest;
+/*N*/ #endif
+/*N*/ BOOL bRet;
+/*N*/ SwCharFmt* pFmt = RES_TXTATR_INETFMT == pAttr->Which() ?
+/*N*/ ((SwTxtINetFmt*)pAttr)->GetCharFmt() :
+/*N*/ pAttr->GetCharFmt().GetCharFmt();
+/*N*/ if( pFmt )
+/*N*/ bRet = SFX_ITEM_SET == pFmt->GetAttrSet().GetItemState( nWhich, TRUE );
+/*N*/ else
+/*N*/ bRet = FALSE;
+/*N*/ return bRet;
+/*N*/ }
+
+/*N*/ void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
+/*N*/ {
+/*N*/ rSet.Put( rAttr );
+/*N*/ }
+
+/*N*/ void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
+/*N*/ {
+/*N*/ if( RES_TXTATR_CHARFMT == rAttr.Which() ||
+/*N*/ RES_TXTATR_INETFMT == rAttr.Which() )
+/*N*/ {
+/*N*/ // aus der Vorlage die Attribute holen:
+/*N*/ SwCharFmt* pFmt = RES_TXTATR_INETFMT == rAttr.Which() ?
+/*N*/ ((SwFmtINetFmt&)rAttr).GetTxtINetFmt()->GetCharFmt() :
+/*N*/ ((SwFmtCharFmt&)rAttr).GetCharFmt();
+/*N*/ if( pFmt )
+/*N*/ {
+/*N*/ const SfxItemSet& rCFSet = pFmt->GetAttrSet();
+/*N*/ SfxWhichIter aIter( rCFSet );
+/*N*/ register USHORT nWhich = aIter.FirstWhich();
+/*N*/ while( nWhich )
+/*N*/ {
+/*N*/ if( ( nWhich < RES_CHRATR_END ) &&
+/*N*/ ( SFX_ITEM_SET == rCFSet.GetItemState( nWhich, TRUE ) ) )
+/*N*/ rSet.Put( rCFSet.Get( nWhich ) );
+/*N*/ nWhich = aIter.NextWhich();
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/
+/*N*/ // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
+ /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
+ z.B
+ 1234567890123456789
+ |------------| Font1
+ |------| Font2
+ ^ ^
+ |--| Abfragebereich: -> Gueltig ist Font2
+ */
+/*N*/ rSet.Put( rAttr );
+/*N*/ }
+
+// erfrage die Attribute vom TextNode ueber den Bereich
+/*N*/ BOOL SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStart, xub_StrLen nEnd,
+/*N*/ BOOL bOnlyTxtAttr, BOOL bGetFromChrFmt ) const
+/*N*/ {
+/*N*/ if( pSwpHints )
+/*N*/ {
+ /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
+ * sind. Dabei gibt es folgende Faelle:
+ * UnEindeutig wenn: (wenn != Format-Attribut)
+ * - das Attribut liegt vollstaendig im Bereich
+ * - das Attributende liegt im Bereich
+ * - der Attributanfang liegt im Bereich:
+ * Eindeutig (im Set mergen):
+ * - das Attrib umfasst den Bereich
+ * nichts tun:
+ * das Attribut liegt ausserhalb des Bereiches
+ */
+/*N*/
+/*N*/ void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
+/*N*/ = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
+/*N*/ : &lcl_MergeAttr;
+/*N*/
+/*N*/ // dann besorge mal die Auto-(Fmt)Attribute
+/*N*/ SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
+/*N*/ if( !bOnlyTxtAttr )
+/*N*/ SwCntntNode::GetAttr( aFmtSet );
+/*N*/
+/*N*/ const USHORT nSize = pSwpHints->Count();
+/*N*/ register USHORT n;
+/*N*/ register xub_StrLen nAttrStart;
+/*N*/ register const xub_StrLen* pAttrEnd;
+/*N*/
+/*N*/ if( nStart == nEnd ) // kein Bereich:
+/*N*/ {
+/*N*/ for( n = 0; n < nSize; ++n ) //
+/*N*/ {
+/*N*/ const SwTxtAttr* pHt = (*pSwpHints)[n];
+/*N*/ nAttrStart = *pHt->GetStart();
+/*N*/ if( nAttrStart > nEnd ) // ueber den Bereich hinaus
+/*N*/ break;
+/*N*/
+/*N*/ if( 0 == ( pAttrEnd = pHt->GetEnd() )) // nie Attribute ohne Ende
+/*N*/ continue;
+/*N*/
+/*N*/ if( ( nAttrStart < nStart &&
+/*N*/ ( pHt->DontExpand() ? nStart < *pAttrEnd
+/*N*/ : nStart <= *pAttrEnd )) ||
+/*N*/ ( nStart == nAttrStart &&
+/*N*/ ( nAttrStart == *pAttrEnd || !nStart )))
+/*N*/ (*fnMergeAttr)( rSet, pHt->GetAttr() );
+/*N*/ }
+/*N*/ }
+/*N*/ else // es ist ein Bereich definiert
+/*N*/ {
+/*N*/ SwTxtAttr** aAttrArr = 0;
+/*N*/ const USHORT coArrSz = RES_TXTATR_WITHEND_END - RES_CHRATR_BEGIN +
+/*N*/ ( RES_UNKNOWNATR_END -
+/*N*/ RES_UNKNOWNATR_BEGIN );
+/*N*/
+/*N*/ for( n = 0; n < nSize; ++n )
+/*N*/ {
+/*N*/ const SwTxtAttr* pHt = (*pSwpHints)[n];
+/*N*/ nAttrStart = *pHt->GetStart();
+/*N*/ if( nAttrStart > nEnd ) // ueber den Bereich hinaus
+/*N*/ break;
+/*N*/
+/*N*/ if( 0 == ( pAttrEnd = pHt->GetEnd() )) // nie Attribute ohne Ende
+/*N*/ continue;
+/*N*/
+/*N*/ BOOL bChkInvalid = FALSE;
+/*N*/ if( nAttrStart <= nStart ) // vor oder genau Start
+/*N*/ {
+/*N*/ if( *pAttrEnd <= nStart ) // liegt davor
+/*N*/ continue;
+/*N*/
+/*N*/ if( nEnd <= *pAttrEnd ) // hinter oder genau Ende
+/*N*/ (*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
+/*N*/ else
+/*N*/ // uneindeutig
+/*N*/ bChkInvalid = TRUE;
+/*N*/ }
+/*N*/ else if( nAttrStart < nEnd ) // reicht in den Bereich
+/*N*/ bChkInvalid = TRUE;
+/*N*/
+/*N*/ if( bChkInvalid )
+/*N*/ {
+/*?*/ // uneindeutig ?
+/*?*/ if( !aAttrArr )
+/*?*/ {
+/*?*/ aAttrArr = new SwTxtAttr* [ coArrSz ];
+/*?*/ memset( aAttrArr, 0, sizeof( SwTxtAttr* ) * coArrSz );
+/*?*/ }
+/*?*/
+/*?*/ const SwTxtAttr** ppPrev;
+/*?*/ if( RES_CHRATR_BEGIN <= pHt->Which() &&
+/*?*/ pHt->Which() < RES_TXTATR_WITHEND_END )
+/*?*/ ppPrev = (const SwTxtAttr**)&aAttrArr[
+/*?*/ pHt->Which() - RES_CHRATR_BEGIN ];
+/*?*/ else if( RES_UNKNOWNATR_BEGIN <= pHt->Which() &&
+/*?*/ pHt->Which() < RES_UNKNOWNATR_END )
+/*?*/ ppPrev = (const SwTxtAttr**)&aAttrArr[
+/*?*/ pHt->Which() - RES_UNKNOWNATR_BEGIN
+/*?*/ + ( RES_TXTATR_WITHEND_END -
+/*?*/ RES_CHRATR_BEGIN ) ];
+/*?*/ else
+/*?*/ ppPrev = 0;
+/*?*/
+/*?*/ if( !*ppPrev )
+/*?*/ {
+/*?*/ if( nAttrStart > nStart )
+/*?*/ {
+/*?*/ rSet.InvalidateItem( pHt->Which() );
+/*?*/ *ppPrev = (SwTxtAttr*)-1;
+/*?*/ }
+/*?*/ else
+/*?*/ *ppPrev = pHt;
+/*?*/ }
+/*?*/ else if( (SwTxtAttr*)-1 != *ppPrev )
+/*?*/ {
+/*?*/ if( *(*ppPrev)->GetEnd() == nAttrStart &&
+/*?*/ (*ppPrev)->GetAttr() == pHt->GetAttr() )
+/*?*/ *ppPrev = pHt;
+/*?*/ else
+/*?*/ {
+/*?*/ rSet.InvalidateItem( pHt->Which() );
+/*?*/ *ppPrev = (SwTxtAttr*)-1;
+/*?*/ }
+/*?*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ if( aAttrArr )
+/*N*/ {
+/*?*/ const SwTxtAttr* pAttr;
+/*?*/ for( n = 0; n < coArrSz; ++n )
+/*?*/ if( 0 != ( pAttr = aAttrArr[ n ] ) &&
+/*?*/ (SwTxtAttr*)-1 != pAttr )
+/*?*/ {
+/*?*/ USHORT nWh;
+/*?*/ if( n < (RES_TXTATR_WITHEND_END -
+/*?*/ RES_CHRATR_BEGIN ))
+/*?*/ nWh = n + RES_CHRATR_BEGIN;
+/*?*/ else
+/*?*/ nWh = n - ( RES_TXTATR_WITHEND_END -
+/*?*/ RES_CHRATR_BEGIN ) +
+/*?*/ RES_UNKNOWNATR_BEGIN;
+/*?*/
+/*?*/ if( nEnd <= *pAttr->GetEnd() ) // hinter oder genau Ende
+/*?*/ {
+/*?*/ if( pAttr->GetAttr() != aFmtSet.Get( nWh ) )
+/*?*/ (*fnMergeAttr)( rSet, pAttr->GetAttr() );
+/*?*/ }
+/*?*/ else
+/*?*/ // uneindeutig
+/*?*/ rSet.InvalidateItem( nWh );
+/*?*/ }
+/*?*/ delete [] aAttrArr;
+/*N*/ }
+/*N*/ }
+/*N*/ if( aFmtSet.Count() )
+/*N*/ {
+/*N*/ // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
+/*N*/ aFmtSet.Differentiate( rSet );
+/*N*/ // jetzt alle zusammen "mergen"
+/*N*/ rSet.Put( aFmtSet );
+/*N*/ }
+/*N*/ }
+/*N*/ else if( !bOnlyTxtAttr )
+/*N*/ // dann besorge mal die Auto-(Fmt)Attribute
+/*N*/ SwCntntNode::GetAttr( rSet );
+/*N*/
+/*N*/ return rSet.Count() ? TRUE : FALSE;
+/*N*/ }
+
+/*N*/ void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
+/*N*/ {
+/*N*/ SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
+/*N*/ if( GetpSwAttrSet() && GetpSwAttrSet()->Count() )
+/*?*/ aThisSet.Put( *GetpSwAttrSet() );
+/*N*/
+/*N*/ if ( !pSwpHints )
+/*N*/ pSwpHints = new SwpHints();
+/*N*/
+/*N*/ if( pNd == this )
+/*N*/ {
+/*N*/ }
+/*N*/ else
+/*N*/ {
+/*N*/ SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
+/*N*/ if( pNd->GetpSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
+/*?*/ aNdSet.Put( *pNd->GetpSwAttrSet() );
+/*N*/
+/*N*/ if ( !pNd->pSwpHints )
+/*N*/ pNd->pSwpHints = new SwpHints();
+/*N*/ }
+/*N*/
+/*N*/ if( pNd->pSwpHints->CanBeDeleted() )
+/*N*/ DELETEZ( pNd->pSwpHints );
+/*N*/ }
+
+/*************************************************************************
+ * SwpHints::CalcFlags()
+ *************************************************************************/
+
+/*N*/ void SwpHints::CalcFlags()
+/*N*/ {
+/*N*/ bDDEFlds = bFtn = FALSE;
+/*N*/ const USHORT nSize = Count();
+/*N*/ const SwTxtAttr* pAttr;
+/*N*/ for( USHORT nPos = 0; nPos < nSize; ++nPos )
+/*N*/ switch( ( pAttr = (*this)[ nPos ])->Which() )
+/*N*/ {
+/*N*/ case RES_TXTATR_FTN:
+/*N*/ bFtn = TRUE;
+/*N*/ if( bDDEFlds )
+/*N*/ return;
+/*N*/ break;
+/*N*/ case RES_TXTATR_FIELD:
+/*N*/ {
+/*N*/ const SwField* pFld = pAttr->GetFld().GetFld();
+/*N*/ if( RES_DDEFLD == pFld->GetTyp()->Which() )
+/*N*/ {
+/*N*/ bDDEFlds = TRUE;
+/*N*/ if( bFtn )
+/*N*/ return;
+/*N*/ }
+/*N*/ }
+/*N*/ break;
+/*N*/ }
+/*N*/ }
+
+/*************************************************************************
+ * SwpHints::CalcVisibleFlag()
+ *************************************************************************/
+
+/*N*/ BOOL SwpHints::CalcVisibleFlag()
+/*N*/ {
+/*N*/ BOOL bOldVis = bVis;
+/*N*/ bCalcVis = FALSE;
+/*N*/ BOOL bNewVis = TRUE;
+/*N*/ const USHORT nSize = Count();
+/*N*/ const SwTxtAttr *pTxtHt;
+/*N*/
+/*N*/ for( USHORT nPos = 0; nPos < nSize; ++nPos )
+/*N*/ {
+/*N*/ pTxtHt = (*this)[ nPos ];
+/*N*/ const USHORT nWhich = pTxtHt->Which();
+/*N*/
+/*N*/ if( RES_TXTATR_FIELD == nWhich )
+/*N*/ {
+/*N*/ const SwFmtFld& rFld = pTxtHt->GetFld();
+/*N*/ if( RES_HIDDENPARAFLD == rFld.GetFld()->GetTyp()->Which())
+/*N*/ {
+/*N*/ if( !((SwHiddenParaField*)rFld.GetFld())->IsHidden() )
+/*N*/ {
+/*N*/ SetVisible(TRUE);
+/*N*/ return !bOldVis;
+/*N*/ }
+/*N*/ else
+/*N*/ bNewVis = FALSE;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ SetVisible( bNewVis );
+/*N*/ return bOldVis != bNewVis;
+/*N*/ }
+
+/*************************************************************************
+ * SwpHints::Resort()
+ *************************************************************************/
+
+// Ein Hint hat seinen Anfangswert geaendert.
+// Hat sich dadurch die Sortierreihenfolge
+// geaendert, so wird solange umsortiert, bis
+// sie wieder stimmt.
+
+/*N*/ BOOL SwpHints::Resort( const USHORT nPos )
+/*N*/ {
+/*N*/ const SwTxtAttr *pTmp;
+/*N*/
+/*N*/ if ( ( nPos+1 < Count() &&
+/*N*/ *(*this)[nPos]->GetStart() > *(*this)[nPos+1]->GetStart() ) ||
+/*N*/ ( nPos > 0 &&
+/*N*/ *(*this)[nPos]->GetStart() < *(*this)[nPos-1]->GetStart() ) )
+/*N*/ {
+/*?*/ pTmp = (*this)[nPos];
+/*?*/ DeleteAtPos( nPos );
+/*?*/ SwpHintsArr::Insert( pTmp );
+/*?*/ // Wenn tatsaechlich umsortiert wurde, muss die
+/*?*/ // Position i nochmal bearbeitet werden.
+/*?*/ return TRUE;
+/*N*/ }
+/*N*/ return FALSE;
+/*N*/ }
+
+/*************************************************************************
+ * SwpHints::ClearDummies()
+ *************************************************************************/
+
+/*
+ * ClearDummies: Hints, die genau den gleichen Bereich umfassen wie
+ * ein nachfolgender mit gleichem Attribut oder eine nachfolgende Zeichen-
+ * vorlage, muessen entfernt werden.
+ * Solche Hints entstehen, wenn sie urspruenglich einen groesseren, den
+ * Nachfolger umfassenden Bereich hatten, die Aussenanteile aber durch
+ * SwTxtNode::RstAttr oder SwTxtNode::Update geloescht wurden.
+ */
+
+/*N*/ void SwpHints::ClearDummies( SwTxtNode &rNode )
+/*N*/ {
+/*N*/ USHORT i = 0;
+/*N*/ while ( i < Count() )
+/*N*/ {
+/*N*/ SwTxtAttr *pHt = GetHt( i++ );
+/*N*/ const USHORT nWhich = pHt->Which();
+/*N*/ const xub_StrLen *pEnd = pHt->GetEnd();
+/*N*/ if ( pEnd && !pHt->IsOverlapAllowedAttr() && !pHt->IsCharFmtAttr() )
+/*N*/ for( USHORT j = i; j < Count(); ++j )
+/*N*/ {
+/*N*/ SwTxtAttr *pOther = GetHt(j);
+/*N*/ if ( *pOther->GetStart() > *pHt->GetStart() )
+/*N*/ break;
+/*N*/
+/*N*/ if( pOther->Which() == nWhich || pOther->IsCharFmtAttr() )
+/*N*/ {
+/*N*/ //JP 03.10.95: nicht zusammenfassen, zu kompliziert
+/*N*/ // fuer WIN95-Compiler!!
+/*?*/ if( *pEnd == *pOther->GetEnd() &&
+/*?*/ ( pOther->Which() == nWhich ||
+/*?*/ lcl_Included( nWhich, pOther ) ) )
+/*?*/ {
+/*?*/ rNode.DestroyAttr( Cut( --i ) );
+/*?*/ break;
+/*?*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ }
+
+/*************************************************************************
+ * SwpHints::Merge( )
+ *************************************************************************/
+
+/*
+ * Merge: Gleichartigen, gleichwertige Hints, die aneinandergrenzen,
+ * koennen verschmolzen werden, wenn an ihrer gemeinsamen Kante nicht ein
+ * gleichartiges Attribut endet oder beginnt, welches einen von der beiden
+ * Kandidaten umfasst, auch Zeichenvorlage duerfen nicht ueberlappt werden.
+ */
+
+/*
+ * And here a smarter version of good old Merge(..)
+ * If a SwTxtAttr is given, only the merging between this attribute and the
+ * neighbours are checked. This saves time, if no attribute is given (in more
+ * complex situations), the whole attribute array is checked as before.
+ */
+
+/*N*/ BOOL SwpHints::Merge( SwTxtNode &rNode, SwTxtAttr* pAttr )
+/*N*/ {
+/*N*/ USHORT i;
+/*N*/ BOOL bMerged = FALSE;
+/*N*/ if( pAttr && USHRT_MAX != ( i = GetPos( pAttr ) ) )
+/*N*/ {
+/*N*/ const xub_StrLen *pEnd = pAttr->GetEnd();
+/*N*/ if ( pEnd && !pAttr->IsDontMergeAttr() )
+/*N*/ {
+/*N*/ USHORT j = i;
+/*N*/ const USHORT nWhich = pAttr->Which();
+/*N*/ const USHORT nStart = *pAttr->GetStart();
+/*N*/ const USHORT nEnd = *pEnd;
+/*N*/ SwTxtAttr *pPrev;
+/*N*/ SwTxtAttr *pNext;
+/*N*/ USHORT nEndIdx = aHtEnd.C40_GETPOS( SwTxtAttr, pAttr );
+/*N*/ OSL_ENSURE( USHRT_MAX != nEndIdx, "Missing end index" );
+/*N*/ if( nEndIdx )
+/*N*/ {
+/*N*/ // If there's a attribute with same start and which-id,
+/*N*/ // it's not possible to merge with a previous attribute.
+/*N*/ pPrev = pAttr;
+/*N*/ while( j )
+/*N*/ {
+/*N*/ SwTxtAttr *pOther = GetHt(--j);
+/*N*/ if ( *pOther->GetStart() < nStart )
+/*N*/ break;
+/*N*/ if( pOther->Which() == nWhich || pOther->IsCharFmtAttr()
+/*N*/ || pAttr->IsCharFmtAttr() )
+/*N*/ {
+/*N*/ pPrev = NULL;
+/*N*/ break;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ else
+/*N*/ pPrev = NULL;
+/*N*/ if( i + 1 < Count() )
+/*N*/ {
+/*N*/ // If there's a attribute with same end and which-id,
+/*N*/ // it's not possible to merge with a following attribute.
+/*N*/ j = nEndIdx + 1;
+/*N*/ pNext = pAttr;
+/*N*/ while( j < Count() )
+/*N*/ {
+/*N*/ SwTxtAttr *pOther = GetEnd( j++ );
+/*N*/ if( !pOther->GetEnd() )
+/*N*/ continue;
+/*N*/ if( *pOther->GetEnd() > nEnd )
+/*N*/ break;
+/*N*/ if( pOther->Which() == nWhich || pOther->IsCharFmtAttr()
+/*N*/ || pAttr->IsCharFmtAttr() )
+/*N*/ {
+/*N*/ pNext = NULL;
+/*N*/ break;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ else
+/*N*/ pNext = NULL;
+/*N*/ if( pPrev )
+/*N*/ {
+/*N*/ pPrev = NULL;
+/*N*/ j = nEndIdx;
+/*N*/ do
+/*N*/ {
+/*N*/ // Looking for a previous attribute with the same which-id
+/*N*/ // which ends exact at the start of the given attribute
+/*N*/ SwTxtAttr *pOther = GetEnd( --j );
+/*N*/ pEnd = pOther->GetEnd();
+/*N*/ if( !pEnd || *pEnd > nStart )
+/*N*/ continue;
+/*N*/ if( *pEnd < nStart )
+/*N*/ break;
+/*N*/ if( pOther->Which() == nWhich )
+/*N*/ {
+/*N*/ if( pOther->GetAttr() == pAttr->GetAttr() )
+/*N*/ {
+/*N*/ bMerged = TRUE;
+/*N*/ pPrev = pOther;
+/*N*/ }
+/*N*/ else
+/*N*/ pPrev = NULL;
+/*N*/ break;
+/*N*/ }
+/*N*/ if( pOther->IsCharFmtAttr() || pAttr->IsCharFmtAttr() )
+/*N*/ {
+/*N*/ pPrev = NULL;
+/*N*/ break;
+/*N*/ }
+/*N*/ } while ( j );
+/*N*/ }
+/*N*/ if( pNext )
+/*N*/ {
+/*N*/ j = i + 1;
+/*N*/ pNext = NULL;
+/*N*/ while( j < Count() )
+/*N*/ {
+/*N*/ // Looking for a following attribute with the same which-id
+/*N*/ // which starts at the end of the given attribute
+/*N*/ SwTxtAttr *pOther = GetStart( j++ );
+/*N*/ pEnd = pOther->GetEnd();
+/*N*/ if( !pEnd || *pOther->GetStart() < nEnd )
+/*N*/ continue;
+/*N*/ if( *pOther->GetStart() > nEnd )
+/*N*/ break;
+/*N*/ if( pOther->Which() == nWhich )
+/*N*/ {
+/*N*/ if( pOther->GetAttr() == pAttr->GetAttr() )
+/*N*/ {
+/*N*/ bMerged = TRUE;
+/*N*/ pNext = pOther;
+/*N*/ }
+/*N*/ else
+/*N*/ pNext = NULL;
+/*N*/ break;
+/*N*/ }
+/*?*/ if( pOther->IsCharFmtAttr() || pAttr->IsCharFmtAttr() )
+/*?*/ {
+/*?*/ pNext = NULL;
+/*?*/ break;
+/*?*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ if( bMerged )
+/*N*/ {
+/*N*/ if( pNext )
+/*N*/ {
+/*N*/ if ( pPrev == pNext )
+/*N*/ pPrev = NULL;
+/*N*/
+/*?*/ *pAttr->GetEnd() = *pNext->GetEnd();
+/*?*/ pAttr->SetDontExpand( FALSE );
+/*?*/ rNode.DestroyAttr( Cut( j - 1 ) );
+/*N*/ }
+/*N*/ if( pPrev )
+/*N*/ {
+/*N*/ *pPrev->GetEnd() = *pAttr->GetEnd();
+/*N*/ pPrev->SetDontExpand( FALSE );
+/*N*/ rNode.DestroyAttr( Cut( i ) );
+/*N*/ }
+/*N*/ return TRUE;
+/*N*/ }
+/*N*/ return FALSE;
+/*N*/ }
+/*N*/ }
+/*N*/ i = 0;
+/*N*/ while ( i < Count() )
+/*N*/ {
+/*N*/ SwTxtAttr *pHt = GetHt( i++ );
+/*N*/ const xub_StrLen *pEnd = pHt->GetEnd();
+/*N*/ if ( pEnd && !pHt->IsDontMergeAttr() )
+/*N*/ {
+/*N*/ const USHORT nWhich = pHt->Which();
+/*N*/ for ( USHORT j = i; j < Count(); j++ )
+/*N*/ {
+/*N*/ SwTxtAttr *pOther = GetHt(j);
+/*N*/ if ( *pOther->GetStart() > *pEnd )
+/*N*/ break; // keine beruehrenden Attribute mehr vorhanden
+/*N*/
+/*N*/ if( *pOther->GetStart() == *pEnd &&
+/*N*/ ( pOther->Which() == nWhich ||
+/*N*/ pOther->IsCharFmtAttr() ||
+/*N*/ ( pHt->IsCharFmtAttr() && !pHt->IsDontMergeAttr() )))
+/*N*/ {
+/*?*/ // Beruehrendes Attribut gefunden mit gleichem Typ bzw.
+/*?*/ // Zeichenvorlage.
+/*?*/ // Bei Attribut mit anderem Wert bzw. Zeichenvorlage
+/*?*/ // ist keine Verschmelzung mehr moeglich
+/*?*/ if( pOther->Which() == nWhich &&
+/*?*/ pOther->GetAttr() == pHt->GetAttr() )
+/*?*/ {
+/*?*/ // Unser Partner pOther erfuellt alle Voraussetzungen,
+/*?*/ // jetzt muessen wir uns selbst noch ueberpruefen, ob wir
+/*?*/ // nicht von einem gleichartigen Attribut oder einer
+/*?*/ // Zeichenvorlage umfasst werden, die das gleiche Ende
+/*?*/ // wie wir selbst haben.
+/*?*/ BOOL bMerge = TRUE;
+/*?*/ for ( USHORT k = 0; k+1 < i; k++ )
+/*?*/ {
+/*?*/ SwTxtAttr *pAnOther = GetHt(k);
+/*?*/ if( ( pAnOther->Which() == nWhich ||
+/*?*/ pAnOther->IsCharFmtAttr() ||
+/*?*/ pHt->IsCharFmtAttr() )
+/*?*/ && pAnOther->GetEnd()
+/*?*/ && *pAnOther->GetEnd() == *pEnd )
+/*?*/ {
+/*?*/ bMerge = FALSE; // kein Verschmelzen von i+j
+/*?*/ break;
+/*?*/ }
+/*?*/ }
+/*?*/ if ( bMerge )
+/*?*/ {
+/*?*/ *pHt->GetEnd() = *pOther->GetEnd();
+/*?*/ pHt->SetDontExpand( FALSE );
+/*?*/ rNode.DestroyAttr( Cut( j ) );
+/*?*/ --i;
+/*?*/ bMerged = TRUE;
+/*?*/ }
+/*?*/ }
+/*?*/ break;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ if ( bMerged )
+/*?*/ ClearDummies( rNode );
+/*N*/ return bMerged;
+/*N*/ }
+
+/*************************************************************************
+ * SwpHints::Insert()
+ *************************************************************************/
+
+/*
+ * Insert: Der neue Hint wird immer eingefuegt. Wenn dabei ein
+ * ueberlappender oder gleicher Hintbereich mit gleichem Attribut
+ * und Wert gefunden, wird der neue Hint entsprechend veraendert
+ * und der alte herausgenommen (und zerstoert:
+ * SwpHints::Destroy()).
+ */
+
+/*N*/ void SwpHints::Insert( SwTxtAttr *pHint, SwTxtNode &rNode, USHORT nMode )
+/*N*/ {
+/*N*/ // Irgendwann ist immer Schluss
+/*N*/ if( USHRT_MAX == Count() )
+/*N*/ return;
+/*N*/
+/*N*/ // Felder bilden eine Ausnahme:
+/*N*/ // 1) Sie koennen nie ueberlappen
+/*N*/ // 2) Wenn zwei Felder genau aneinander liegen,
+/*N*/ // sollen sie nicht zu einem verschmolzen werden.
+/*N*/ // Wir koennen also auf die while-Schleife verzichten
+/*N*/
+/*N*/ xub_StrLen *pHtEnd = pHint->GetEnd();
+/*N*/ USHORT nWhich = pHint->Which();
+/*N*/
+/*N*/ switch( nWhich )
+/*N*/ {
+/*N*/ case RES_TXTATR_CHARFMT:
+/*N*/ ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
+/*N*/ break;
+/*N*/ case RES_TXTATR_INETFMT:
+/*N*/ {
+/*N*/ ((SwTxtINetFmt*)pHint)->ChgTxtNode( &rNode );
+/*N*/ SwCharFmt* pFmt = rNode.GetDoc()->GetCharFmtFromPool( RES_POOLCHR_INET_NORMAL );
+/*N*/ pFmt->Add( (SwTxtINetFmt*)pHint );
+/*N*/ }
+/*N*/ break;
+/*N*/ case RES_TXTATR_FIELD:
+/*N*/ {
+/*N*/ BOOL bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
+/*N*/ ((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
+/*N*/ SwDoc* pDoc = rNode.GetDoc();
+/*N*/ const SwField* pFld = ((SwTxtFld*)pHint)->GetFld().GetFld();
+/*N*/
+/*N*/ if( !pDoc->IsNewFldLst() )
+/*N*/ {
+/*N*/ // was fuer ein Feld ist es denn ??
+/*N*/ // bestimmte Felder mussen am Doc das Calculations-Flag updaten
+/*N*/ switch( pFld->GetTyp()->Which() )
+/*N*/ {
+/*N*/ case RES_DBFLD:
+/*N*/ case RES_SETEXPFLD:
+/*N*/ case RES_HIDDENPARAFLD:
+/*N*/ case RES_HIDDENTXTFLD:
+/*N*/ case RES_DBNUMSETFLD:
+/*N*/ case RES_DBNEXTSETFLD:
+/*N*/ {
+/*N*/ if( bDelFirst )
+/*?*/ pDoc->InsDelFldInFldLst( FALSE, *(SwTxtFld*)pHint );
+/*N*/ if( rNode.GetNodes().IsDocNodes() )
+/*N*/ pDoc->InsDelFldInFldLst( TRUE, *(SwTxtFld*)pHint );
+/*N*/ }
+/*N*/ break;
+/*?*/ case RES_DDEFLD:
+/*?*/ if( rNode.GetNodes().IsDocNodes() )
+/*?*/ ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
+/*?*/ break;
+/*N*/ }
+/*N*/ }
+/*N*/
+/*N*/ // gehts ins normale Nodes-Array?
+/*N*/ if( rNode.GetNodes().IsDocNodes() )
+/*N*/ {
+/*N*/ switch( pFld->GetTyp()->Which() )
+/*N*/ {
+/*N*/ case RES_SETEXPFLD:
+/*N*/ if( GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
+/*N*/ {
+/*N*/ // bevor die ReferenzNummer gesetzt wird, sollte
+/*N*/ // das Feld am richtigen FeldTypen haengen!
+/*N*/ SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
+/*N*/ pDoc->InsertFldType( *pFld->GetTyp() );
+/*N*/ pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
+/*N*/ }
+/*N*/ break;
+/*N*/ case RES_USERFLD:
+/*N*/ break;
+/*N*/
+/*N*/ case RES_DDEFLD:
+/*N*/ if( pDoc->IsNewFldLst() )
+/*N*/ ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
+/*N*/ break;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ break;
+/*N*/ case RES_TXTATR_FTN :
+/*N*/ ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
+/*N*/ break;
+/*N*/ case RES_TXTATR_REFMARK:
+/*N*/ ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
+/*N*/ break;
+/*N*/ case RES_TXTATR_TOXMARK:
+/*N*/ ((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
+/*N*/ break;
+/*N*/
+/*N*/ case RES_TXTATR_CJK_RUBY:
+/*N*/ break;
+/*N*/ }
+/*N*/
+/*N*/ if( SETATTR_DONTEXPAND & nMode )
+/*N*/ pHint->SetDontExpand( TRUE );
+/*N*/
+/*N*/ // SwTxtAttrs ohne Ende werden sonderbehandelt:
+/*N*/ // Sie werden natuerlich in das Array insertet, aber sie werden nicht
+/*N*/ // in die pPrev/Next/On/Off-Verkettung aufgenommen.
+/*N*/ // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
+/*N*/ xub_StrLen nHtStart = *pHint->GetStart();
+/*N*/ if( !pHtEnd )
+/*N*/ {
+/*N*/ SwpHintsArr::Insert( pHint );
+/*N*/ CalcFlags();
+/*N*/ #ifdef DBG_UTIL
+/*N*/ if( !rNode.GetDoc()->IsInReading() )
+/*N*/ CHECK;
+/*N*/ #endif
+/*N*/ // ... und die Abhaengigen benachrichtigen
+/*N*/ if ( rNode.GetDepends() )
+/*N*/ {
+/*N*/ SwUpdateAttr aHint( nHtStart, nHtStart, nWhich );
+/*N*/ rNode.Modify( 0, &aHint );
+/*N*/ }
+/*N*/ return;
+/*N*/ }
+/*N*/
+/*N*/ // ----------------------------------------------------------------
+/*N*/ // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
+/*N*/
+/*N*/ SwTxtAttr *pMerge = pHint; // For a smarter Merge-function
+/*N*/
+/*N*/ BOOL bResort = FALSE;
+/*N*/
+/*N*/ if( *pHtEnd < nHtStart )
+/*N*/ {
+/*?*/ OSL_ENSURE( *pHtEnd >= nHtStart,
+/*?*/ "+SwpHints::Insert: invalid hint, end < start" );
+/*?*/
+/*?*/ // Wir drehen den Quatsch einfach um:
+/*?*/ *pHint->GetStart() = *pHtEnd;
+/*?*/ *pHtEnd = nHtStart;
+/*?*/ nHtStart = *pHint->GetStart();
+/*N*/ }
+/*N*/
+/*N*/ // AMA: Damit wir endlich mit ueberlappenden Hints fertig werden ...
+/*N*/ // das neue Verfahren:
+/*N*/
+/*N*/ if( !(SETATTR_NOHINTADJUST & nMode) && !pHint->IsOverlapAllowedAttr() )
+/*N*/ {
+/*N*/ const SfxPoolItem* pParaItem;
+/*N*/ xub_StrLen nMaxEnd = *pHtEnd;
+/*N*/ xub_StrLen nHtEnd = *pHtEnd;
+/*N*/ BOOL bParaAttr = rNode.GetpSwAttrSet() &&
+/*N*/ ( SFX_ITEM_SET == rNode.GetpSwAttrSet()->GetItemState( nWhich,
+/*N*/ FALSE, &pParaItem ) ) && ( pParaItem == &pHint->GetAttr() );
+/*N*/ BOOL bReplace = !( SETATTR_DONTREPLACE & nMode );
+/*N*/ ::binfilter::SwpHtStart_SAR *pTmpHints = 0;
+/*N*/
+/*N*/ USHORT i;
+/*N*/ // Wir wollen zwar von nHtStart bis nMaxEnd, muessen aber ggf.
+/*N*/ // stueckeln (Attribute duerfen keine Zeichenvorlagen ueberlappen).
+/*N*/ // Das erste Stueck wird also von nHtStart bis zum ersten Start/Ende
+/*N*/ // einer Zeichenvorlage gehen usw. bis nHtEnd = nMaxEnd erreicht ist.
+/*N*/ do {
+/*N*/ BOOL bINet = nWhich == RES_TXTATR_INETFMT;
+/*N*/ BOOL bForgetAttr = bParaAttr;
+/*N*/ // Muessen wir uns aufspalten?
+/*N*/ if ( !bINet && !pHint->IsDontMergeAttr() )
+/*N*/ {
+/*N*/ // Ab der zweiten Runde muessen wir zunaechst einen neuen
+/*N*/ // Hint erzeugen.
+/*N*/ if ( nHtEnd != nMaxEnd )
+/*N*/ {
+/*?*/ pMerge = NULL; // No way to use the smarter Merge()
+/*?*/ pHint = rNode.MakeTxtAttr( bParaAttr ? *pParaItem :
+/*?*/ pHint->GetAttr(),
+/*?*/ nHtStart, nMaxEnd );
+/*?*/ nHtEnd = *pHint->GetEnd();
+/*N*/ }
+/*N*/
+/*N*/ for ( i = 0; i < Count(); i++)
+/*N*/ {
+/*N*/ SwTxtAttr *pOther = GetHt(i);
+/*N*/ // Wir suchen nach Zeichenvorlagen, die uns schneiden
+/*N*/ // oder in uns liegen
+/*N*/ BOOL bOtherFmt = pOther->IsCharFmtAttr();
+/*N*/ if( bOtherFmt ||
+/*N*/ ( RES_TXTATR_CHARFMT == nWhich && pOther->GetEnd() ) )
+/*N*/ {
+/*N*/ if( bForgetAttr && bOtherFmt &&
+/*N*/ *pOther->GetStart() <= nHtStart &&
+/*N*/ *pOther->GetEnd() >= nHtStart )
+/*N*/ bForgetAttr = FALSE;
+ /* Die Flags bCheckInclude und bOtherFmt sollen die
+ * Anzahl der Aufrufe von lcl_Include minimieren, da
+ * dieses wg. IsVisitedURL() teuer ist. */
+/*N*/ BOOL bCheckInclude = FALSE;
+/*N*/ if( *pOther->GetStart() > nHtStart
+/*N*/ && *pOther->GetStart() < nHtEnd
+/*N*/ && ( bReplace || *pOther->GetEnd() > nHtEnd ) )
+/*N*/ {
+/*?*/ if( bOtherFmt )
+/*?*/ nHtEnd = *pOther->GetStart();
+/*N*/ }
+/*N*/ if( *pOther->GetEnd() > nHtStart
+/*N*/ && *pOther->GetEnd() < nHtEnd
+/*N*/ && ( bReplace || *pOther->GetStart() < nHtStart ) )
+/*N*/ {
+/*?*/ if( bOtherFmt || ( !bCheckInclude &&
+/*?*/ !lcl_Included( pOther->Which(), pHint ) ) )
+/*?*/ nHtEnd = *pOther->GetEnd();
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ *pHint->GetEnd() = nHtEnd;
+/*N*/ }
+/*N*/
+/*N*/ i = 0;
+/*N*/ while(i < Count())
+/*N*/ {
+/*N*/ SwTxtAttr *pOther = GetHt(i);
+/*N*/ const USHORT nOtherWhich = pOther->Which();
+/*N*/ BOOL bCheckInclude = pHint->IsCharFmtAttr() &&
+/*N*/ pOther->IsCharFmtAttr() &&
+/*N*/ nWhich != nOtherWhich;
+/*N*/
+/*N*/ BOOL bOtherCharFmt = RES_TXTATR_CHARFMT == nOtherWhich;
+/*N*/ if( nOtherWhich == nWhich || bCheckInclude )
+/*N*/ {
+/*N*/ if(0 == pOther->GetEnd())
+/*N*/ {
+/*?*/ if( *pOther->GetStart() == nHtStart &&
+/*?*/ nOtherWhich == nWhich &&
+/*?*/ pOther->GetAttr() == pHint->GetAttr() )
+/*?*/ {
+/*?*/ // Gibts schon, alten raus.
+/*?*/ rNode.DestroyAttr( Cut(i) );
+/*?*/ }
+/*?*/ else
+/*?*/ ++i;
+/*?*/ continue;
+/*N*/ }
+/*N*/ else
+/*N*/ {
+/*N*/ // Attribute mit Anfang und Ende.
+/*N*/ const Range aHintRg( nHtStart, nHtEnd );
+/*N*/ const Range aOtherRg( *pOther->GetStart(),
+/*N*/ *pOther->GetEnd() );
+/*N*/
+/*N*/ if( aOtherRg.IsInside( aHintRg.Min() ) ||
+/*N*/ aHintRg.IsInside( aOtherRg.Min() ) )
+/*N*/ {
+/*N*/ // aBig umspannt beide Ranges
+/*N*/ const Range aBig(
+/*N*/ Min( aHintRg.Min(), aOtherRg.Min()),
+/*N*/ Max( aHintRg.Max(), aOtherRg.Max()));
+/*N*/
+/*N*/ // Gleiches Attribut
+/*N*/ // oder Zeichenvorlage:
+/*N*/ // Bereiche duerfen nicht ueberlappen.
+/*N*/
+/*N*/ // Zuerst wurde geprueft, ob sich der neue mit dem
+/*N*/ // alten ueberschneidet, danach gibt es nur noch
+/*N*/ // drei Faelle zu beachten:
+/*N*/ // 1) der neue umschliesst den alten
+/*N*/ // 2) der neue ueberlappt den alten hinten
+/*N*/ // 3) der neue ueberlappt den alten vorne
+/*N*/
+/*N*/ BOOL bNoINet = RES_TXTATR_INETFMT != nOtherWhich ||
+/*N*/ nWhich == nOtherWhich;
+/*N*/
+/*N*/ // 1) der neue umschliesst den alten
+/*N*/ if( aBig == aHintRg )
+/*N*/ {
+/*N*/ BOOL bTmpReplace = bReplace ||
+/*N*/ ( aHintRg == aOtherRg &&
+/*N*/ nWhich == nOtherWhich &&
+/*N*/ !pHint->IsCharFmtAttr() );
+/*N*/ if( bNoINet && bTmpReplace &&
+/*N*/ ( !bOtherCharFmt || nWhich == nOtherWhich ) )
+/*N*/ {
+/*N*/ if( !bCheckInclude ||
+/*N*/ lcl_Included( nOtherWhich, pHint ) )
+/*N*/ {
+/*N*/ rNode.DestroyAttr( Cut(i) );
+/*N*/ }
+/*N*/ else
+/*N*/ ++i;
+/*N*/ continue;
+/*N*/ }
+/*N*/ }
+/*N*/ else if( !bReplace && aBig == aOtherRg )
+/*?*/ bForgetAttr = FALSE;
+/*N*/ // 2) der neue ueberlappt hinten
+/*N*/ else if( aBig.Max() == aHintRg.Max() )
+/*N*/ {
+/*N*/ if( bNoINet &&
+/*N*/ ( !bOtherCharFmt || RES_TXTATR_CHARFMT != nWhich ) &&
+/*N*/ ( bReplace || aHintRg.Max() != aOtherRg.Max() ) )
+/*N*/ {
+/*N*/ if( ( bCheckInclude &&
+/*N*/ lcl_Included( nOtherWhich, pHint ) ) ||
+/*N*/ ( !bCheckInclude && !bOtherCharFmt ) )
+/*N*/ {
+/*N*/ if( nMaxEnd == nHtStart )
+/*N*/ bForgetAttr = FALSE;
+/*N*/ *pOther->GetEnd() = nHtStart;
+/*N*/ bResort = TRUE;
+/*N*/ // ChainDelEnd( pOther );
+/*N*/ // ChainEnds( pOther );
+/*N*/ }
+/*N*/ else if( bINet &&
+/*N*/ aHintRg.Max() != aOtherRg.Max() &&
+/*N*/ aHintRg.Min() < aOtherRg.Max() )
+/*N*/ {
+/*N*/ // Wenn ein INetFmt eingefuegt wird, muss
+/*N*/ // sich ein anderes Attribut ggf. aufspal-
+/*N*/ // ten. Es wird beiseite gestellt und in
+/*N*/ // einem spaeteren Durchgang eingefuegt.
+/*N*/ // Beim Einfuegen spaltet es sich selbst.
+/*?*/ if( !pTmpHints )
+/*?*/ pTmpHints = new ::binfilter::SwpHtStart_SAR();
+/*?*/ pTmpHints->C40_INSERT( SwTxtAttr, pOther,
+/*?*/ pTmpHints->Count() );
+/*?*/ Cut( i );
+/*?*/ continue;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ // 3) der neue ueberlappt vorne
+/*N*/ else if( aBig.Min() == aHintRg.Min() )
+/*N*/ {
+/*N*/ if( bNoINet &&
+/*N*/ ( RES_TXTATR_CHARFMT != nOtherWhich ||
+/*N*/ RES_TXTATR_CHARFMT != nWhich ) &&
+/*N*/ ( bReplace || aHintRg.Min() != aOtherRg.Min() ) )
+/*N*/ {
+/*N*/ if( ( bCheckInclude &&
+/*N*/ lcl_Included( nOtherWhich, pHint ) ) ||
+/*N*/ ( !bCheckInclude && !bOtherCharFmt ) )
+/*N*/ {
+/*N*/
+/*N*/ *pOther->GetStart() = nHtEnd;
+/*N*/
+/*N*/ // ChainDelStart( pOther );
+/*N*/ // ChainStarts( pOther );
+/*N*/
+/*N*/ const BOOL bOk = Resort(i);
+/*N*/ if( bOk )
+/*N*/ continue;
+/*N*/ }
+/*N*/ else if( bINet &&
+/*N*/ aHintRg.Min() != aOtherRg.Min() &&
+/*N*/ aHintRg.Max() > aOtherRg.Min() )
+/*N*/ {
+/*?*/ // Wenn ein INetFmt eingefuegt wird, muss
+/*?*/ // sich ein anderes Attribut ggf. aufspal-
+/*?*/ // ten. Es wird beiseite gestellt und in
+/*?*/ // einem spaeteren Durchgang eingefuegt.
+/*?*/ // Beim Einfuegen spaltet es sich selbst.
+/*?*/ if( !pTmpHints )
+/*?*/ pTmpHints = new ::binfilter::SwpHtStart_SAR();
+/*?*/ pTmpHints->C40_INSERT( SwTxtAttr, pOther,
+/*?*/ pTmpHints->Count() );
+/*?*/ Cut( i );
+/*?*/ continue;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ else
+/*N*/ bForgetAttr = FALSE;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ ++i;
+/*N*/ }
+/*N*/
+/*N*/ ClearDummies( rNode );
+/*N*/ // Nur wenn wir nicht sowieso schon durch die Absatzattribute
+/*N*/ // gueltig sind, werden wir eingefuegt ...
+/*N*/ if( bForgetAttr )
+/*N*/ {
+/*?*/ rNode.DestroyAttr( pHint );
+/*?*/ pMerge = NULL; // No smart Merge()
+/*N*/ }
+/*N*/ else
+/*N*/ {
+/*N*/ SwpHintsArr::Insert( pHint );
+/*N*/ bResort = FALSE;
+/*N*/ }
+/*N*/ // InsertChain( pHint );
+/*N*/
+/*N*/ // ... und die Abhaengigen benachrichtigen
+/*N*/ if ( rNode.GetDepends() )
+/*N*/ {
+/*N*/ SwUpdateAttr aHint( nHtStart, nHtEnd, nWhich );
+/*N*/ rNode.Modify( 0, &aHint );
+/*N*/ }
+/*N*/ // Falls es noch 'ne Runde gibt:
+/*N*/ nHtStart = nHtEnd;
+/*N*/ if( nMaxEnd > nHtEnd )
+/*N*/ continue;
+/*N*/ if( !pTmpHints )
+/*N*/ break;
+/*?*/ pMerge = NULL; // No smart Merge()
+/*?*/ pHint = pTmpHints->GetObject(0);
+/*?*/ nWhich = pHint->Which();
+/*?*/ nHtStart = *pHint->GetStart();
+/*?*/ nHtEnd = *pHint->GetEnd();
+/*?*/ nMaxEnd = nHtEnd;
+/*?*/ bParaAttr = FALSE;
+/*?*/ pTmpHints->Remove(0);
+/*?*/ if( !pTmpHints->Count() )
+/*?*/ {
+/*?*/ delete pTmpHints;
+/*?*/ pTmpHints = NULL;
+/*?*/ }
+/*N*/ } while ( TRUE );
+/*N*/
+/*N*/ if( bResort )
+/*?*/ SwpHintsArr::Resort();
+/*N*/
+/*N*/ // Jetzt wollen wir mal gucken, ob wir das SwpHintsArray nicht
+/*N*/ // etwas vereinfachen koennen ...
+/*N*/ Merge( rNode, pMerge );
+/*N*/ }
+/*N*/ else
+/*N*/ {
+/*N*/ SwpHintsArr::Insert( pHint );
+/*N*/ // InsertChain( pHint );
+/*N*/
+/*N*/ // ... und die Abhaengigen benachrichtigen
+/*N*/ if ( rNode.GetDepends() )
+/*N*/ {
+/*N*/ SwUpdateAttr aHint( nHtStart,
+/*N*/ nHtStart == *pHtEnd ? *pHtEnd + 1 : *pHtEnd, nWhich );
+/*N*/ rNode.Modify( 0, &aHint );
+/*N*/ }
+/*N*/ }
+/*N*/ #ifdef DBG_UTIL
+/*N*/ if( !rNode.GetDoc()->IsInReading() )
+/*N*/ CHECK;
+/*N*/ #endif
+/*N*/ }
+
+/*************************************************************************
+ * SwpHints::DeleteAtPos()
+ *************************************************************************/
+
+/*N*/ void SwpHints::DeleteAtPos( const USHORT nPos )
+/*N*/ {
+/*N*/ SwTxtAttr *pHint = GetHt(nPos);
+/*N*/ // ChainDelete( pHint );
+/*N*/ SwpHintsArr::DeleteAtPos( nPos );
+/*N*/
+/*N*/ if( RES_TXTATR_FIELD == pHint->Which() )
+/*N*/ {
+/*N*/ SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFld().GetFld()->GetTyp();
+/*N*/ if( RES_DDEFLD == pFldTyp->Which() )
+/*N*/ {
+/*?*/ const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
+/*?*/ if( pNd && pNd->GetNodes().IsDocNodes() )
+/*?*/ ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
+/*?*/ ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
+/*N*/ }
+/*N*/ else if( !bVis && RES_HIDDENPARAFLD == pFldTyp->Which() )
+/*N*/ bCalcVis = TRUE;
+/*N*/ }
+/*N*/ CalcFlags();
+/*N*/ CHECK;
+/*N*/ }
+
+// Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
+// Ist er nicht im Array, so gibt es ein ASSERT !!
+
+/*N*/ void SwpHints::Delete( SwTxtAttr* pTxtHt )
+/*N*/ {
+/*N*/ // Attr 2.0: SwpHintsArr::Delete( pTxtHt );
+/*N*/ const USHORT nPos = GetStartOf( pTxtHt );
+/*N*/ OSL_ENSURE( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
+/*N*/ if( USHRT_MAX != nPos )
+/*N*/ DeleteAtPos( nPos );
+/*N*/ }
+
+/*N*/ #ifdef VERTICAL_LAYOUT
+/*N*/ USHORT SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
+/*N*/ USHORT nScript ) const
+/*N*/ #else
+/*N*/ USHORT SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen) const
+/*N*/ #endif
+/*N*/ {
+/*N*/ USHORT nWhichId = RES_CHRATR_LANGUAGE;
+/*N*/ USHORT nRet = LANGUAGE_DONTKNOW;
+/*N*/ if( pSwpHints )
+/*N*/ {
+/*N*/ #ifdef VERTICAL_LAYOUT
+/*N*/ if ( ! nScript )
+/*N*/ nScript = pBreakIt->GetRealScriptOfText( aText, nBegin );
+/*N*/
+/*N*/ nWhichId = GetWhichOfScript( nWhichId, nScript );
+/*N*/ #else
+/*N*/ nWhichId = GetWhichOfScript( nWhichId,
+/*N*/ pBreakIt->GetRealScriptOfText( aText, nBegin ));
+/*N*/ #endif
+/*N*/
+/*N*/ xub_StrLen nEnd = nBegin + nLen;
+/*N*/ for( USHORT i = 0, nSize = pSwpHints->Count(); i < nSize; ++i )
+/*N*/ {
+/*N*/ // ist der Attribut-Anfang schon groesser als der Idx ?
+/*N*/ const SwTxtAttr *pHt = pSwpHints->operator[](i);
+/*N*/ xub_StrLen nAttrStart = *pHt->GetStart();
+/*N*/ if( nEnd < nAttrStart )
+/*N*/ break;
+/*N*/
+/*N*/ const USHORT nWhich = pHt->Which();
+/*N*/
+/*N*/ if( ( pHt->IsCharFmtAttr() && lcl_Included( nWhichId, pHt ) )
+/*N*/ || nWhichId == nWhich )
+/*N*/ {
+/*N*/ const xub_StrLen *pEndIdx = pHt->GetEnd();
+/*N*/ // Ueberlappt das Attribut den Bereich?
+/*N*/
+/*N*/ if( pEndIdx &&
+/*N*/ nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
+/*N*/ : (( nAttrStart < nBegin &&
+/*N*/ ( pHt->DontExpand() ? nBegin < *pEndIdx
+/*N*/ : nBegin <= *pEndIdx )) ||
+/*N*/ ( nBegin == nAttrStart &&
+/*N*/ ( nAttrStart == *pEndIdx || !nBegin ))) )
+/*N*/ {
+/*N*/ const SfxPoolItem* pItem;
+/*N*/ if( RES_TXTATR_CHARFMT == nWhich )
+/*N*/ pItem = &pHt->GetCharFmt().GetCharFmt()->GetAttr( nWhichId );
+/*N*/ else if( RES_TXTATR_INETFMT == nWhich )
+/*?*/ pItem = &((SwTxtINetFmt*)pHt)->GetCharFmt()->GetAttr( nWhichId );
+/*N*/ else
+/*N*/ pItem = &pHt->GetAttr();
+/*N*/
+/*N*/ USHORT nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
+/*N*/
+/*N*/ // Umfasst das Attribut den Bereich komplett?
+/*N*/ if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
+/*N*/ nRet = nLng;
+/*N*/ else if( LANGUAGE_DONTKNOW == nRet )
+/*N*/ nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ if( LANGUAGE_DONTKNOW == nRet )
+/*N*/ {
+/*N*/ if( !pSwpHints )
+/*N*/ nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE,
+/*N*/ pBreakIt->GetRealScriptOfText( aText, nBegin ));
+/*N*/
+/*N*/ nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
+/*N*/ if( LANGUAGE_DONTKNOW == nRet )
+/*N*/ nRet = GetAppLanguage();
+/*N*/ }
+/*N*/ return nRet;
+/*N*/ }
+
+/*N*/ sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
+/*N*/ {
+/*N*/ sal_Unicode cRet = CH_TXTATR_BREAKWORD;
+/*N*/ switch ( rAttr.Which() )
+/*N*/ {
+/*N*/ case RES_TXTATR_REFMARK:
+/*N*/ case RES_TXTATR_TOXMARK:
+/*N*/ case RES_TXTATR_FTN:
+/*N*/ cRet = CH_TXTATR_INWORD;
+/*N*/ break;
+/*N*/ }
+/*N*/ return cRet;
+/*N*/ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */