summaryrefslogtreecommitdiff
path: root/sw/source/core/txtnode
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/txtnode')
-rw-r--r--sw/source/core/txtnode/SwGrammarContact.cxx205
-rw-r--r--sw/source/core/txtnode/atrfld.cxx424
-rw-r--r--sw/source/core/txtnode/atrflyin.cxx286
-rw-r--r--sw/source/core/txtnode/atrftn.cxx545
-rw-r--r--sw/source/core/txtnode/atrref.cxx105
-rw-r--r--sw/source/core/txtnode/atrtox.cxx99
-rw-r--r--sw/source/core/txtnode/chrfmt.cxx40
-rw-r--r--sw/source/core/txtnode/fmtatr2.cxx905
-rw-r--r--sw/source/core/txtnode/fntcache.cxx2651
-rw-r--r--sw/source/core/txtnode/fntcap.cxx846
-rw-r--r--sw/source/core/txtnode/modeltoviewhelper.cxx123
-rw-r--r--sw/source/core/txtnode/ndhints.cxx431
-rw-r--r--sw/source/core/txtnode/ndtxt.cxx4829
-rw-r--r--sw/source/core/txtnode/swfntcch.cxx90
-rw-r--r--sw/source/core/txtnode/swfont.cxx1243
-rw-r--r--sw/source/core/txtnode/thints.cxx3063
-rw-r--r--sw/source/core/txtnode/txatbase.cxx86
-rw-r--r--sw/source/core/txtnode/txatritr.cxx246
-rw-r--r--sw/source/core/txtnode/txtatr2.cxx353
-rw-r--r--sw/source/core/txtnode/txtedt.cxx2123
20 files changed, 18693 insertions, 0 deletions
diff --git a/sw/source/core/txtnode/SwGrammarContact.cxx b/sw/source/core/txtnode/SwGrammarContact.cxx
new file mode 100644
index 000000000000..14ff4233246f
--- /dev/null
+++ b/sw/source/core/txtnode/SwGrammarContact.cxx
@@ -0,0 +1,205 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include <vcl/timer.hxx>
+#include <hints.hxx>
+#include <IGrammarContact.hxx>
+#include <pam.hxx>
+#include <ndtxt.hxx>
+#include <SwGrammarMarkUp.hxx>
+#include <txtfrm.hxx>
+#include <rootfrm.hxx>
+#include <viewsh.hxx>
+
+/* SwGrammarContact
+ This class is responsible for the delayed display of grammar checks when a paragraph is edited
+ It's a client of the paragraph the cursor points to.
+ If the cursor position changes, updateCursorPosition has to be called
+ If the grammar checker wants to set a grammar marker at a paragraph, he has to request
+ the grammar list from this class. If the requested paragraph is not edited, it returns
+ the normal grammar list. But if the paragraph is the active one, a proxy list will be returned and
+ all changes are set in this proxy list. If the cursor leaves the paragraph the proxy list
+ will replace the old list. If the grammar checker has completed the paragraph ('setChecked')
+ then a timer is setup which replaces the old list as well.
+*/
+
+class SwGrammarContact : public IGrammarContact, public SwClient
+{
+ Timer aTimer;
+ SwGrammarMarkUp *mpProxyList;
+ bool mbFinished;
+ SwTxtNode* getMyTxtNode() { return (SwTxtNode*)GetRegisteredIn(); }
+ DECL_LINK( TimerRepaint, Timer * );
+
+public:
+ SwGrammarContact();
+ ~SwGrammarContact() { aTimer.Stop(); delete mpProxyList; }
+
+ // (pure) virtual functions of IGrammarContact
+ virtual void updateCursorPosition( const SwPosition& rNewPos );
+ virtual SwGrammarMarkUp* getGrammarCheck( SwTxtNode& rTxtNode, bool bCreate );
+ virtual void finishGrammarCheck( SwTxtNode& rTxtNode );
+protected:
+ // virtual function of SwClient
+ virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
+};
+
+SwGrammarContact::SwGrammarContact() : mpProxyList(0), mbFinished( false )
+{
+ aTimer.SetTimeout( 2000 ); // Repaint of grammar check after 'setChecked'
+ aTimer.SetTimeoutHdl( LINK(this, SwGrammarContact, TimerRepaint) );
+}
+
+IMPL_LINK( SwGrammarContact, TimerRepaint, Timer *, pTimer )
+{
+ if( pTimer )
+ {
+ pTimer->Stop();
+ if( GetRegisteredIn() )
+ { //Replace the old wrong list by the proxy list and repaint all frames
+ getMyTxtNode()->SetGrammarCheck( mpProxyList, true );
+ mpProxyList = 0;
+ SwTxtFrm::repaintTextFrames( *getMyTxtNode() );
+ }
+ }
+ return 0;
+}
+
+/* I'm always a client of the current paragraph */
+void SwGrammarContact::updateCursorPosition( const SwPosition& rNewPos )
+{
+ SwTxtNode* pTxtNode = rNewPos.nNode.GetNode().GetTxtNode();
+ if( pTxtNode != GetRegisteredIn() ) // paragraph has been changed
+ {
+ aTimer.Stop();
+ if( GetRegisteredIn() ) // My last paragraph has been left
+ {
+ if( mpProxyList )
+ { // replace old list by the proxy list and repaint
+ getMyTxtNode()->SetGrammarCheck( mpProxyList, true );
+ SwTxtFrm::repaintTextFrames( *getMyTxtNode() );
+ }
+ GetRegisteredInNonConst()->Remove( this ); // good bye old paragraph
+ mpProxyList = 0;
+ }
+ if( pTxtNode )
+ pTxtNode->Add( this ); // welcome new paragraph
+ }
+}
+
+/* deliver a grammar check list for the given text node */
+SwGrammarMarkUp* SwGrammarContact::getGrammarCheck( SwTxtNode& rTxtNode, bool bCreate )
+{
+ SwGrammarMarkUp *pRet = 0;
+ if( GetRegisteredIn() == &rTxtNode ) // hey, that's my current paragraph!
+ { // so you will get a proxy list...
+ if( bCreate )
+ {
+ if( mbFinished )
+ {
+ delete mpProxyList;
+ mpProxyList = 0;
+ }
+ if( !mpProxyList )
+ {
+ if( rTxtNode.GetGrammarCheck() )
+ mpProxyList = (SwGrammarMarkUp*)rTxtNode.GetGrammarCheck()->Clone();
+ else
+ {
+ mpProxyList = new SwGrammarMarkUp();
+ mpProxyList->SetInvalid( 0, STRING_LEN );
+ }
+ }
+ mbFinished = false;
+ }
+ pRet = mpProxyList;
+ }
+ else
+ {
+ pRet = rTxtNode.GetGrammarCheck(); // do you have already a list?
+ if( bCreate && !pRet ) // do you want to create a list?
+ {
+ pRet = new SwGrammarMarkUp();
+ pRet->SetInvalid( 0, STRING_LEN );
+ rTxtNode.SetGrammarCheck( pRet );
+ rTxtNode.SetGrammarCheckDirty( true );
+ }
+ }
+ return pRet;
+}
+
+void SwGrammarContact::Modify( const SfxPoolItem* pOld, const SfxPoolItem * )
+{
+ if( !pOld || pOld->Which() != RES_OBJECTDYING )
+ return;
+
+ SwPtrMsgPoolItem *pDead = (SwPtrMsgPoolItem *)pOld;
+ if( pDead->pObject == GetRegisteredIn() )
+ { // if my current paragraph dies, I throw the proxy list away
+ aTimer.Stop();
+ GetRegisteredInNonConst()->Remove( this );
+ delete mpProxyList;
+ mpProxyList = 0;
+ }
+}
+
+void SwGrammarContact::finishGrammarCheck( SwTxtNode& rTxtNode )
+{
+ if( &rTxtNode != GetRegisteredIn() ) // not my paragraph
+ SwTxtFrm::repaintTextFrames( rTxtNode ); // can be repainted directly
+ else
+ {
+ if( mpProxyList )
+ {
+ mbFinished = true;
+ aTimer.Start(); // will replace old list and repaint with delay
+ }
+ else if( getMyTxtNode()->GetGrammarCheck() )
+ { // all grammar problems seems to be gone, no delay needed
+ getMyTxtNode()->SetGrammarCheck( 0, true );
+ SwTxtFrm::repaintTextFrames( *getMyTxtNode() );
+ }
+ }
+}
+
+IGrammarContact* createGrammarContact()
+{
+ return new SwGrammarContact();
+}
+
+void finishGrammarCheck( SwTxtNode& rTxtNode )
+{
+ IGrammarContact* pGrammarContact = getGrammarContact( rTxtNode );
+ if( pGrammarContact )
+ pGrammarContact->finishGrammarCheck( rTxtNode );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/atrfld.cxx b/sw/source/core/txtnode/atrfld.cxx
new file mode 100644
index 000000000000..4f6488e570ea
--- /dev/null
+++ b/sw/source/core/txtnode/atrfld.cxx
@@ -0,0 +1,424 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include "fldbas.hxx" // fuer FieldType
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <docufld.hxx>
+#include <doc.hxx>
+
+#include "reffld.hxx"
+#include "ddefld.hxx"
+#include "usrfld.hxx"
+#include "expfld.hxx"
+#include "swfont.hxx" // fuer GetFldsColor
+#include "ndtxt.hxx" // SwTxtNode
+#include "calc.hxx" // Update fuer UserFields
+#include "hints.hxx"
+#include <IDocumentFieldsAccess.hxx>
+#include <fieldhint.hxx>
+#include <svl/smplhint.hxx>
+
+TYPEINIT3( SwFmtFld, SfxPoolItem, SwClient,SfxBroadcaster)
+TYPEINIT1(SwFmtFldHint, SfxHint);
+
+/****************************************************************************
+ *
+ * class SwFmtFld
+ *
+ ****************************************************************************/
+
+ // Konstruktor fuers Default vom Attribut-Pool
+SwFmtFld::SwFmtFld()
+ : SfxPoolItem( RES_TXTATR_FIELD ),
+ SwClient( 0 ),
+ pField( 0 ),
+ pTxtAttr( 0 )
+{
+}
+
+SwFmtFld::SwFmtFld( const SwField &rFld )
+ : SfxPoolItem( RES_TXTATR_FIELD ),
+ SwClient( rFld.GetTyp() ),
+ pTxtAttr( 0 )
+{
+ pField = rFld.CopyField();
+}
+
+// #i24434#
+// Since Items are used in ItemPool and in default constructed ItemSets with
+// full pool range, all items need to be clonable. Thus, this one needed to be
+// corrected
+SwFmtFld::SwFmtFld( const SwFmtFld& rAttr )
+ : SfxPoolItem( RES_TXTATR_FIELD ), SwClient(), SfxBroadcaster(),
+ pField( 0 ),
+ pTxtAttr( 0 )
+{
+ if(rAttr.GetFld())
+ {
+ rAttr.GetFld()->GetTyp()->Add(this);
+ pField = rAttr.GetFld()->CopyField();
+ }
+}
+
+SwFmtFld::~SwFmtFld()
+{
+ SwFieldType* pType = pField ? pField->GetTyp() : 0;
+
+ if (pType && pType->Which() == RES_DBFLD)
+ pType = 0; // DB-Feldtypen zerstoeren sich selbst
+
+ Broadcast( SwFmtFldHint( this, SWFMTFLD_REMOVED ) );
+ delete pField;
+
+ // bei einige FeldTypen muessen wir den FeldTypen noch loeschen
+ if( pType && pType->IsLastDepend() )
+ {
+ sal_Bool bDel = sal_False;
+ switch( pType->Which() )
+ {
+ case RES_USERFLD:
+ bDel = ((SwUserFieldType*)pType)->IsDeleted();
+ break;
+
+ case RES_SETEXPFLD:
+ bDel = ((SwSetExpFieldType*)pType)->IsDeleted();
+ break;
+
+ case RES_DDEFLD:
+ bDel = ((SwDDEFieldType*)pType)->IsDeleted();
+ break;
+ }
+
+ if( bDel )
+ {
+ // vorm loeschen erstmal austragen
+ pType->Remove( this );
+ delete pType;
+ }
+ }
+}
+
+void SwFmtFld::RegisterToFieldType( SwFieldType& rType )
+{
+ rType.Add(this);
+}
+
+
+// #111840#
+void SwFmtFld::SetFld(SwField * _pField)
+{
+ if (NULL != pField)
+ delete pField;
+
+ pField = _pField;
+ Broadcast( SwFmtFldHint( this, SWFMTFLD_CHANGED ) );
+}
+
+int SwFmtFld::operator==( const SfxPoolItem& rAttr ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
+ // OD 2004-05-14 #i29146# - correction: check, if <pField> and
+ // <((SwFmtFld&)rAttr).GetFld()> are set.
+ // OD 2004-05-14 #i29146# - items are equal, if both fields aren't set.
+ return ( pField && ((SwFmtFld&)rAttr).GetFld() &&
+ pField->GetTyp() == ((SwFmtFld&)rAttr).GetFld()->GetTyp() &&
+ pField->GetFormat() == ((SwFmtFld&)rAttr).GetFld()->GetFormat() ) ||
+ ( !pField && !((SwFmtFld&)rAttr).GetFld() );
+}
+
+SfxPoolItem* SwFmtFld::Clone( SfxItemPool* ) const
+{
+ return new SwFmtFld( *this );
+}
+
+void SwFmtFld::SwClientNotify( const SwModify&, const SfxHint& rHint )
+{
+ if( !pTxtAttr )
+ return;
+
+ const SwFieldHint* pHint = dynamic_cast<const SwFieldHint*>( &rHint );
+ if ( pHint )
+ {
+ // replace field content by text
+ SwPaM* pPaM = pHint->GetPaM();
+ SwDoc* pDoc = pPaM->GetDoc();
+ const SwTxtNode& rTxtNode = pTxtAttr->GetTxtNode();
+ pPaM->GetPoint()->nNode = rTxtNode;
+ pPaM->GetPoint()->nContent.Assign( (SwTxtNode*)&rTxtNode, *pTxtAttr->GetStart() );
+
+ String const aEntry( GetFld()->ExpandField( pDoc->IsClipBoard() ) );
+ pPaM->SetMark();
+ pPaM->Move( fnMoveForward );
+ pDoc->DeleteRange( *pPaM );
+ pDoc->InsertString( *pPaM, aEntry );
+ }
+}
+
+void SwFmtFld::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
+{
+ if( !pTxtAttr )
+ return;
+
+ // don't do anything, especially not expand!
+ if( pNew && pNew->Which() == RES_OBJECTDYING )
+ return;
+
+ SwTxtNode* pTxtNd = (SwTxtNode*)&pTxtAttr->GetTxtNode();
+ OSL_ENSURE( pTxtNd, "wo ist denn mein Node?" );
+ if( pNew )
+ {
+ switch( pNew->Which() )
+ {
+ case RES_TXTATR_FLDCHG:
+ // "Farbe hat sich geaendert !"
+ // this, this fuer "nur Painten"
+ pTxtNd->ModifyNotification( this, this );
+ return;
+ case RES_REFMARKFLD_UPDATE:
+ // GetReferenz-Felder aktualisieren
+ if( RES_GETREFFLD == GetFld()->GetTyp()->Which() )
+ {
+ // --> OD 2007-09-06 #i81002#
+// ((SwGetRefField*)GetFld())->UpdateField();
+ dynamic_cast<SwGetRefField*>(GetFld())->UpdateField( pTxtAttr );
+ // <--
+ }
+ break;
+ case RES_DOCPOS_UPDATE:
+ // Je nach DocPos aktualisieren (SwTxtFrm::Modify())
+ pTxtNd->ModifyNotification( pNew, this );
+ return;
+
+ case RES_ATTRSET_CHG:
+ case RES_FMT_CHG:
+ pTxtNd->ModifyNotification( pOld, pNew );
+ return;
+ default:
+ break;
+ }
+ }
+
+ switch (GetFld()->GetTyp()->Which())
+ {
+ case RES_HIDDENPARAFLD:
+ if( !pOld || RES_HIDDENPARA_PRINT != pOld->Which() )
+ break;
+ case RES_DBSETNUMBERFLD:
+ case RES_DBNUMSETFLD:
+ case RES_DBNEXTSETFLD:
+ case RES_DBNAMEFLD:
+ pTxtNd->ModifyNotification( 0, pNew);
+ return;
+ }
+
+ if( RES_USERFLD == GetFld()->GetTyp()->Which() )
+ {
+ SwUserFieldType* pType = (SwUserFieldType*)GetFld()->GetTyp();
+ if(!pType->IsValid())
+ {
+ SwCalc aCalc( *pTxtNd->GetDoc() );
+ pType->GetValue( aCalc );
+ }
+ }
+ pTxtAttr->Expand();
+}
+
+sal_Bool SwFmtFld::GetInfo( SfxPoolItem& rInfo ) const
+{
+ const SwTxtNode* pTxtNd;
+ if( RES_AUTOFMT_DOCNODE != rInfo.Which() ||
+ !pTxtAttr || 0 == ( pTxtNd = pTxtAttr->GetpTxtNode() ) ||
+ &pTxtNd->GetNodes() != ((SwAutoFmtGetDocNode&)rInfo).pNodes )
+ return sal_True;
+
+ ((SwAutoFmtGetDocNode&)rInfo).pCntntNode = pTxtNd;
+ return sal_False;
+}
+
+
+sal_Bool SwFmtFld::IsFldInDoc() const
+{
+ const SwTxtNode* pTxtNd;
+ return pTxtAttr && 0 != ( pTxtNd = pTxtAttr->GetpTxtNode() ) &&
+ pTxtNd->GetNodes().IsDocNodes();
+}
+
+sal_Bool SwFmtFld::IsProtect() const
+{
+ const SwTxtNode* pTxtNd;
+ return pTxtAttr && 0 != ( pTxtNd = pTxtAttr->GetpTxtNode() ) &&
+ pTxtNd->IsProtect();
+}
+
+/*************************************************************************
+|*
+|* SwTxtFld::SwTxtFld()
+|*
+|* Beschreibung Attribut fuer automatischen Text, Ctor
+|*
+*************************************************************************/
+
+SwTxtFld::SwTxtFld(SwFmtFld & rAttr, xub_StrLen const nStartPos)
+ : SwTxtAttr( rAttr, nStartPos )
+ , m_aExpand( rAttr.GetFld()->ExpandField(true) )
+ , m_pTxtNode( 0 )
+{
+ rAttr.pTxtAttr = this;
+ SetHasDummyChar(true);
+}
+
+SwTxtFld::~SwTxtFld( )
+{
+ SwFmtFld & rFmtFld( static_cast<SwFmtFld &>(GetAttr()) );
+ if (this == rFmtFld.pTxtAttr)
+ {
+ rFmtFld.pTxtAttr = 0; // #i110140# invalidate!
+ }
+}
+
+/*************************************************************************
+|*
+|* SwTxtFld::Expand()
+|*
+|* Beschreibung exandiert das Feld und tauscht den Text im Node
+|*
+*************************************************************************/
+
+void SwTxtFld::Expand() const
+{
+ // Wenn das expandierte Feld sich nicht veraendert hat, wird returnt
+ OSL_ENSURE( m_pTxtNode, "SwTxtFld: where is my TxtNode?" );
+
+ const SwField* pFld = GetFld().GetFld();
+ XubString aNewExpand(
+ pFld->ExpandField(m_pTxtNode->GetDoc()->IsClipBoard()) );
+
+ if( aNewExpand == m_aExpand )
+ {
+ // Bei Seitennummernfeldern
+ const sal_uInt16 nWhich = pFld->GetTyp()->Which();
+ if( RES_CHAPTERFLD != nWhich && RES_PAGENUMBERFLD != nWhich &&
+ RES_REFPAGEGETFLD != nWhich &&
+ // --> FME 2005-05-23 #122919# Page count fields to not use aExpand
+ // during formatting, therefore an invalidation of the text frame
+ // has to be triggered even if aNewExpand == aExpand:
+ ( RES_DOCSTATFLD != nWhich || DS_PAGE != static_cast<const SwDocStatField*>(pFld)->GetSubType() ) &&
+ // <--
+ ( RES_GETEXPFLD != nWhich || ((SwGetExpField*)pFld)->IsInBodyTxt() ) )
+ {
+ // BP: das muesste man noch optimieren!
+ //JP 12.06.97: stimmt, man sollte auf jedenfall eine Status-
+ // aenderung an die Frames posten
+ if( m_pTxtNode->CalcHiddenParaField() )
+ {
+ m_pTxtNode->ModifyNotification( 0, 0 );
+ }
+ return;
+ }
+ }
+
+ m_aExpand = aNewExpand;
+
+ // 0, this for formatting
+ m_pTxtNode->ModifyNotification( 0, const_cast<SwFmtFld*>( &GetFld() ) );
+}
+
+/*************************************************************************
+ * SwTxtFld::CopyFld()
+ *************************************************************************/
+
+void SwTxtFld::CopyFld( SwTxtFld *pDest ) const
+{
+ OSL_ENSURE( m_pTxtNode, "SwTxtFld: where is my TxtNode?" );
+ OSL_ENSURE( pDest->m_pTxtNode, "SwTxtFld: where is pDest's TxtNode?" );
+
+ IDocumentFieldsAccess* pIDFA = m_pTxtNode->getIDocumentFieldsAccess();
+ IDocumentFieldsAccess* pDestIDFA = pDest->m_pTxtNode->getIDocumentFieldsAccess();
+
+ SwFmtFld& rFmtFld = (SwFmtFld&)pDest->GetFld();
+ const sal_uInt16 nFldWhich = rFmtFld.GetFld()->GetTyp()->Which();
+
+ if( pIDFA != pDestIDFA )
+ {
+ // Die Hints stehen in unterschiedlichen Dokumenten,
+ // der Feldtyp muss im neuen Dokument angemeldet werden.
+ // Z.B: Kopieren ins ClipBoard.
+ SwFieldType* pFldType;
+ if( nFldWhich != RES_DBFLD && nFldWhich != RES_USERFLD &&
+ nFldWhich != RES_SETEXPFLD && nFldWhich != RES_DDEFLD &&
+ RES_AUTHORITY != nFldWhich )
+ pFldType = pDestIDFA->GetSysFldType( nFldWhich );
+ else
+ pFldType = pDestIDFA->InsertFldType( *rFmtFld.GetFld()->GetTyp() );
+
+ // Sonderbehandlung fuer DDE-Felder
+ if( RES_DDEFLD == nFldWhich )
+ {
+ if( rFmtFld.GetTxtFld() )
+ ((SwDDEFieldType*)rFmtFld.GetFld()->GetTyp())->DecRefCnt();
+ ((SwDDEFieldType*)pFldType)->IncRefCnt();
+ }
+
+ OSL_ENSURE( pFldType, "unbekannter FieldType" );
+ pFldType->Add( &rFmtFld ); // ummelden
+ rFmtFld.GetFld()->ChgTyp( pFldType );
+ }
+
+ // Expressionfelder Updaten
+ if( nFldWhich == RES_SETEXPFLD || nFldWhich == RES_GETEXPFLD ||
+ nFldWhich == RES_HIDDENTXTFLD )
+ {
+ SwTxtFld* pFld = (SwTxtFld*)this;
+ pDestIDFA->UpdateExpFlds( pFld, true );
+ }
+ // Tabellenfelder auf externe Darstellung
+ else if( RES_TABLEFLD == nFldWhich &&
+ ((SwTblField*)rFmtFld.GetFld())->IsIntrnlName() )
+ {
+ // erzeuge aus der internen (fuer CORE) die externe (fuer UI) Formel
+ const SwTableNode* pTblNd = m_pTxtNode->FindTableNode();
+ if( pTblNd ) // steht in einer Tabelle
+ ((SwTblField*)rFmtFld.GetFld())->PtrToBoxNm( &pTblNd->GetTable() );
+ }
+}
+
+void SwTxtFld::NotifyContentChange(SwFmtFld& rFmtFld)
+{
+ //if not in undo section notify the change
+ if (m_pTxtNode && m_pTxtNode->GetNodes().IsDocNodes())
+ {
+ m_pTxtNode->ModifyNotification(0, &rFmtFld);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/atrflyin.cxx b/sw/source/core/txtnode/atrflyin.cxx
new file mode 100644
index 000000000000..4a7319993d0a
--- /dev/null
+++ b/sw/source/core/txtnode/atrflyin.cxx
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include "hintids.hxx"
+#include "cntfrm.hxx" // _GetFly
+#include "doc.hxx"
+#include <IDocumentUndoRedo.hxx>
+#include "pam.hxx" // fuer SwTxtFlyCnt
+#include "flyfrm.hxx" // fuer SwTxtFlyCnt
+#include "ndtxt.hxx" // SwFlyFrmFmt
+#include "frmfmt.hxx" // SwFlyFrmFmt
+#include <fmtflcnt.hxx>
+#include <txtflcnt.hxx>
+#include <fmtanchr.hxx>
+#include "swfont.hxx"
+#include "txtfrm.hxx"
+#include "flyfrms.hxx"
+#include <objectformatter.hxx>
+#include <switerator.hxx>
+
+SwFmtFlyCnt::SwFmtFlyCnt( SwFrmFmt *pFrmFmt )
+ : SfxPoolItem( RES_TXTATR_FLYCNT ),
+ pTxtAttr( 0 ),
+ pFmt( pFrmFmt )
+{
+}
+
+int SwFmtFlyCnt::operator==( const SfxPoolItem& rAttr ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
+ return( pTxtAttr && ((SwFmtFlyCnt&)rAttr).pTxtAttr &&
+ *pTxtAttr->GetStart() == *((SwFmtFlyCnt&)rAttr).pTxtAttr->GetStart() &&
+ pFmt == ((SwFmtFlyCnt&)rAttr).GetFrmFmt() );
+}
+
+SfxPoolItem* SwFmtFlyCnt::Clone( SfxItemPool* ) const
+{
+ return new SwFmtFlyCnt( pFmt );
+}
+
+SwTxtFlyCnt::SwTxtFlyCnt( SwFmtFlyCnt& rAttr, xub_StrLen nStartPos )
+ : SwTxtAttr( rAttr, nStartPos )
+{
+ rAttr.pTxtAttr = this;
+ SetHasDummyChar(true);
+}
+
+
+
+/*************************************************************************
+ * SwTxtFlyCnt::MakeTxtHint()
+ *
+ * An dieser Stelle soll einmal der Gesamtzusammenhang bei der Erzeugung
+ * eines neuen SwTxtFlyCnt erlaeutert werden.
+ * Das MakeTxtHint() wird z.B. im SwTxtNode::Copy() gerufen.
+ * Fuer die komplette Verdopplung sind folgende Schritte notwendig:
+ * 1) Duplizieren des pFmt incl. Inhalt, Attributen etc.
+ * 2) Setzen des Ankers
+ * 3) Benachrichtigung
+ * Da fuer die Bewaeltigung der Aufgaben nicht immer alle Informationen
+ * bereitstehen und darueber hinaus bestimmte Methoden erst zu einem
+ * spaeteren Zeitpunkt gerufen werden duerfen (weil nocht nicht alle
+ * Nodeinformationen vorliegen), verteilt sich der Ablauf.
+ * ad 1) MakeTxtHint() wird durch den Aufruf von SwDoc::CopyLayout()
+ * der das neue FlyFrmFmt erzeugt und mit dem duplizierten Inhalt des
+ * FlyFrm verbunden.
+ * ad 2) SetAnchor() wird von SwTxtNode::Insert() gerufen und sorgt fuer das
+ * setzen des Ankers (die SwPosition des Dummy-Zeichens wird dem FlyFrmFmt
+ * per SetAttr bekannt gegeben). Dies kann nicht im MakeTxtHint erledigt
+ * werden, da der Zielnode unbestimmt ist.
+ * ad 3) _GetFlyFrm() wird im Formatierungsprozess vom LineIter gerufen
+ * und sucht den FlyFrm zum Dummyzeichen des aktuellen CntntFrm. Wird keiner
+ * gefunden, so wird ein neuer FlyFrm angelegt.
+ * Kritisch an diesem Vorgehen ist, dass das pCntnt->AppendFly() eine
+ * sofortige Neuformatierung von pCntnt anstoesst. Die Rekursion kommt
+ * allerdings durch den Lockmechanismus in SwTxtFrm::Format() nicht
+ * zu stande.
+ * Attraktiv ist der Umstand, dass niemand ueber die vom Node abhaengigen
+ * CntntFrms iterieren braucht, um die FlyInCntFrm anzulegen. Dies geschieht
+ * bei der Arbeit.
+ *************************************************************************/
+
+void SwTxtFlyCnt::CopyFlyFmt( SwDoc* pDoc )
+{
+ SwFrmFmt* pFmt = GetFlyCnt().GetFrmFmt();
+ OSL_ENSURE( pFmt, "von welchem Format soll ich eine Kopie erzeugen?" );
+ // Das FlyFrmFmt muss dupliziert werden.
+ // In CopyLayoutFmt (siehe doclay.cxx) wird das FlyFrmFmt erzeugt
+ // und der Inhalt dupliziert.
+
+ // disable undo while copying attribute
+ ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
+ SwFmtAnchor aAnchor( pFmt->GetAnchor() );
+ if ((FLY_AT_PAGE != aAnchor.GetAnchorId()) &&
+ (pDoc != pFmt->GetDoc())) // different documents?
+ {
+ // JP 03.06.96: dann sorge dafuer, das der koperierte Anker auf
+ // gueltigen Content zeigt! Die Umsetzung auf die
+ // richtige Position erfolgt spaeter.
+ SwNodeIndex aIdx( pDoc->GetNodes().GetEndOfExtras(), +2 );
+ SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
+ if( !pCNd )
+ pCNd = pDoc->GetNodes().GoNext( &aIdx );
+
+ SwPosition* pPos = (SwPosition*)aAnchor.GetCntntAnchor();
+ pPos->nNode = aIdx;
+ if (FLY_AS_CHAR == aAnchor.GetAnchorId())
+ {
+ pPos->nContent.Assign( pCNd, 0 );
+ }
+ else
+ {
+ pPos->nContent.Assign( 0, 0 );
+ OSL_ENSURE( !this, "CopyFlyFmt: Was fuer ein Anker?" );
+ }
+ }
+
+ SwFrmFmt* pNew = pDoc->CopyLayoutFmt( *pFmt, aAnchor, false, false );
+ ((SwFmtFlyCnt&)GetFlyCnt()).SetFlyFmt( pNew );
+}
+
+/*************************************************************************
+ * SwTxtFlyCnt::SetAnchor()
+ *
+ * SetAnchor() wird von SwTxtNode::Insert() gerufen und sorgt fuer das
+ * setzen des Ankers (die SwPosition des Dummy-Zeichens wird dem FlyFrmFmt
+ * per SetAttr bekannt gegeben). Dies kann nicht im MakeTxtHint erledigt
+ * werden, da der Zielnode unbestimmt ist.
+ * (siehe Kommentar in SwTxtFlyCnt::MakeTxtHint)
+ *************************************************************************/
+
+void SwTxtFlyCnt::SetAnchor( const SwTxtNode *pNode )
+{
+ // fuers Undo muss der neue Anker schon bekannt sein !
+
+ // Wir ermitteln den Index im Nodesarray zum Node
+
+ SwDoc* pDoc = (SwDoc*)pNode->GetDoc();
+
+ SwIndex aIdx( (SwTxtNode*)pNode, *GetStart() );
+ SwPosition aPos( *pNode->StartOfSectionNode(), aIdx );
+ SwFrmFmt* pFmt = GetFlyCnt().GetFrmFmt();
+ SwFmtAnchor aAnchor( pFmt->GetAnchor() );
+
+ if( !aAnchor.GetCntntAnchor() ||
+ !aAnchor.GetCntntAnchor()->nNode.GetNode().GetNodes().IsDocNodes() ||
+ &aAnchor.GetCntntAnchor()->nNode.GetNode() != (SwNode*)pNode )
+ aPos.nNode = *pNode;
+ else
+ aPos.nNode = aAnchor.GetCntntAnchor()->nNode;
+
+ aAnchor.SetType( FLY_AS_CHAR ); // default!
+ aAnchor.SetAnchor( &aPos );
+
+ // beim Ankerwechsel werden immer alle FlyFrms vom Attribut geloescht
+ // JP 25.04.95: wird innerhalb des SplitNodes die Frames verschoben
+ // koennen die Frames erhalten bleiben.
+ if( ( !pNode->GetpSwpHints() || !pNode->GetpSwpHints()->IsInSplitNode() )
+ && RES_DRAWFRMFMT != pFmt->Which() )
+ pFmt->DelFrms();
+
+ // stehen wir noch im falschen Dokument ?
+ if( pDoc != pFmt->GetDoc() )
+ {
+ // disable undo while copying attribute
+ ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
+ SwFrmFmt* pNew = pDoc->CopyLayoutFmt( *pFmt, aAnchor, false, false );
+
+ ::sw::UndoGuard const undoGuardFmt(
+ pFmt->GetDoc()->GetIDocumentUndoRedo());
+ pFmt->GetDoc()->DelLayoutFmt( pFmt );
+ ((SwFmtFlyCnt&)GetFlyCnt()).SetFlyFmt( pNew );
+ }
+ else if( pNode->GetpSwpHints() &&
+ pNode->GetpSwpHints()->IsInSplitNode() &&
+ RES_DRAWFRMFMT != pFmt->Which() )
+ {
+ pFmt->LockModify();
+ pFmt->SetFmtAttr( aAnchor ); // nur den Anker neu setzen
+ pFmt->UnlockModify();
+ }
+ else
+ pFmt->SetFmtAttr( aAnchor ); // nur den Anker neu setzen
+
+ // Am Node haengen u.a. abhaengige CntFrms.
+ // Fuer jeden CntFrm wird ein SwFlyInCntFrm angelegt.
+}
+
+/*************************************************************************
+ * SwTxtFlyCnt::_GetFlyFrm()
+ *
+ * _GetFlyFrm() wird im Formatierungsprozess vom LineIter gerufen
+ * und sucht den FlyFrm zum Dummyzeichen des aktuellen CntntFrm. Wird keiner
+ * gefunden, so wird ein neuer FlyFrm angelegt.
+ * (siehe Kommentar ind SwTxtFlyCnt::MakeTxtHint)
+ *************************************************************************/
+
+SwFlyInCntFrm *SwTxtFlyCnt::_GetFlyFrm( const SwFrm *pCurrFrm )
+{
+ SwFrmFmt* pFrmFmt = GetFlyCnt().GetFrmFmt();
+ if( RES_DRAWFRMFMT == pFrmFmt->Which() )
+ {
+ OSL_ENSURE( !this, "SwTxtFlyCnt::_GetFlyFrm: DrawInCnt-Baustelle!" );
+ return NULL;
+ }
+
+ SwIterator<SwFlyFrm,SwFmt> aIter( *GetFlyCnt().pFmt );
+ OSL_ENSURE( pCurrFrm->IsTxtFrm(), "SwTxtFlyCnt::_GetFlyFrm for TxtFrms only." );
+ SwFrm* pFrm = aIter.First();
+ if ( pFrm )
+ {
+ SwTxtFrm *pFirst = (SwTxtFrm*)pCurrFrm;
+ while ( pFirst->IsFollow() )
+ pFirst = pFirst->FindMaster();
+ do
+ {
+ SwTxtFrm *pTmp = pFirst;
+ do
+ { if( ( (SwFlyFrm*)pFrm )->GetAnchorFrm() == (SwFrm*) pTmp )
+ {
+ if ( pTmp != pCurrFrm )
+ {
+ pTmp->RemoveFly( (SwFlyFrm*)pFrm );
+ ((SwTxtFrm*)pCurrFrm)->AppendFly( (SwFlyFrm*)pFrm );
+ }
+ return (SwFlyInCntFrm*)pFrm;
+ }
+ pTmp = pTmp->GetFollow();
+ } while ( pTmp );
+
+ pFrm = aIter.Next();
+
+ } while( pFrm );
+ }
+
+ // Wir haben keinen passenden FlyFrm gefunden, deswegen wird ein
+ // neuer angelegt.
+ // Dabei wird eine sofortige Neuformatierung von pCurrFrm angestossen.
+ // Die Rekursion wird durch den Lockmechanismus in SwTxtFrm::Format()
+ // abgewuergt.
+ SwFrm* pCurrFrame = const_cast< SwFrm* >(pCurrFrm);
+ SwFlyInCntFrm *pFly = new SwFlyInCntFrm( (SwFlyFrmFmt*)pFrmFmt, pCurrFrame, pCurrFrame );
+ pCurrFrame->AppendFly( pFly );
+ pFly->RegistFlys();
+
+ // 7922: Wir muessen dafuer sorgen, dass der Inhalt des FlyInCnt
+ // nach seiner Konstruktion stramm durchformatiert wird.
+ // --> OD 2004-11-09 #i26945# - Use new object formatter to format Writer
+ // fly frame and its content.
+ SwObjectFormatter::FormatObj( *pFly, const_cast<SwFrm*>(pCurrFrm),
+ pCurrFrm->FindPageFrm() );
+ // <--
+
+ return pFly;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/atrftn.cxx b/sw/source/core/txtnode/atrftn.cxx
new file mode 100644
index 000000000000..fdea3387ae6a
--- /dev/null
+++ b/sw/source/core/txtnode/atrftn.cxx
@@ -0,0 +1,545 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+
+#define _SVSTDARR_USHORTS
+#define _SVSTDARR_USHORTSSORT
+#include <svl/svstdarr.hxx>
+#include <doc.hxx>
+#include <cntfrm.hxx> // OSL_ENSURE(in ~SwTxtFtn()
+#include <pagefrm.hxx> // RemoveFtn()
+#include <fmtftn.hxx>
+#include <txtftn.hxx>
+#include <ftnidx.hxx>
+#include <ftninfo.hxx>
+#include <swfont.hxx>
+#include <ndtxt.hxx>
+#include <poolfmt.hxx>
+#include <ftnfrm.hxx>
+#include <ndindex.hxx>
+#include <fmtftntx.hxx>
+#include <section.hxx>
+#include <switerator.hxx>
+
+/*************************************************************************
+|*
+|* class SwFmtFtn
+|*
+*************************************************************************/
+
+
+SwFmtFtn::SwFmtFtn( bool bEndNote )
+ : SfxPoolItem( RES_TXTATR_FTN ),
+ pTxtAttr( 0 ),
+ nNumber( 0 ),
+ m_bEndNote( bEndNote )
+{
+}
+
+
+int SwFmtFtn::operator==( const SfxPoolItem& rAttr ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
+ return nNumber == ((SwFmtFtn&)rAttr).nNumber &&
+ aNumber == ((SwFmtFtn&)rAttr).aNumber &&
+ m_bEndNote == ((SwFmtFtn&)rAttr).m_bEndNote;
+}
+
+
+SfxPoolItem* SwFmtFtn::Clone( SfxItemPool* ) const
+{
+ SwFmtFtn* pNew = new SwFmtFtn;
+ pNew->aNumber = aNumber;
+ pNew->nNumber = nNumber;
+ pNew->m_bEndNote = m_bEndNote;
+ return pNew;
+}
+
+void SwFmtFtn::SetEndNote( bool b )
+{
+ if ( b != m_bEndNote )
+ {
+ if ( GetTxtFtn() )
+ {
+ GetTxtFtn()->DelFrms(0);
+ }
+ m_bEndNote = b;
+ }
+}
+
+SwFmtFtn::~SwFmtFtn()
+{
+}
+
+
+void SwFmtFtn::GetFtnText( XubString& rStr ) const
+{
+ if( pTxtAttr->GetStartNode() )
+ {
+ SwNodeIndex aIdx( *pTxtAttr->GetStartNode(), 1 );
+ SwCntntNode* pCNd = aIdx.GetNode().GetTxtNode();
+ if( !pCNd )
+ pCNd = aIdx.GetNodes().GoNext( &aIdx );
+
+ if( pCNd->IsTxtNode() )
+ rStr = ((SwTxtNode*)pCNd)->GetExpandTxt();
+ }
+}
+
+ // returnt den anzuzeigenden String der Fuss-/Endnote
+XubString SwFmtFtn::GetViewNumStr( const SwDoc& rDoc, sal_Bool bInclStrings ) const
+{
+ XubString sRet( GetNumStr() );
+ if( !sRet.Len() )
+ {
+ // dann ist die Nummer von Interesse, also ueber die Info diese
+ // besorgen.
+ sal_Bool bMakeNum = sal_True;
+ const SwSectionNode* pSectNd = pTxtAttr
+ ? SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtAttr )
+ : 0;
+
+ if( pSectNd )
+ {
+ const SwFmtFtnEndAtTxtEnd& rFtnEnd = (SwFmtFtnEndAtTxtEnd&)
+ pSectNd->GetSection().GetFmt()->GetFmtAttr(
+ IsEndNote() ?
+ static_cast<sal_uInt16>(RES_END_AT_TXTEND) :
+ static_cast<sal_uInt16>(RES_FTN_AT_TXTEND) );
+
+ if( FTNEND_ATTXTEND_OWNNUMANDFMT == rFtnEnd.GetValue() )
+ {
+ bMakeNum = sal_False;
+ sRet = rFtnEnd.GetSwNumType().GetNumStr( GetNumber() );
+ if( bInclStrings )
+ {
+ sRet.Insert( rFtnEnd.GetPrefix(), 0 );
+ sRet += rFtnEnd.GetSuffix();
+ }
+ }
+ }
+
+ if( bMakeNum )
+ {
+ const SwEndNoteInfo* pInfo;
+ if( IsEndNote() )
+ pInfo = &rDoc.GetEndNoteInfo();
+ else
+ pInfo = &rDoc.GetFtnInfo();
+ sRet = pInfo->aFmt.GetNumStr( GetNumber() );
+ if( bInclStrings )
+ {
+ sRet.Insert( pInfo->GetPrefix(), 0 );
+ sRet += pInfo->GetSuffix();
+ }
+ }
+ }
+ return sRet;
+}
+
+/*************************************************************************
+ * class SwTxt/FmtFnt
+ *************************************************************************/
+
+SwTxtFtn::SwTxtFtn( SwFmtFtn& rAttr, xub_StrLen nStartPos )
+ : SwTxtAttr( rAttr, nStartPos )
+ , m_pStartNode( 0 )
+ , m_pTxtNode( 0 )
+ , m_nSeqNo( USHRT_MAX )
+{
+ rAttr.pTxtAttr = this;
+ SetHasDummyChar(true);
+}
+
+
+SwTxtFtn::~SwTxtFtn()
+{
+ SetStartNode( 0 );
+}
+
+
+
+void SwTxtFtn::SetStartNode( const SwNodeIndex *pNewNode, sal_Bool bDelNode )
+{
+ if( pNewNode )
+ {
+ if ( !m_pStartNode )
+ {
+ m_pStartNode = new SwNodeIndex( *pNewNode );
+ }
+ else
+ {
+ *m_pStartNode = *pNewNode;
+ }
+ }
+ else if ( m_pStartNode )
+ {
+ // Zwei Dinge muessen erledigt werden:
+ // 1) Die Fussnoten muessen bei ihren Seiten abgemeldet werden
+ // 2) Die Fussnoten-Sektion in den Inserts muss geloescht werden.
+ SwDoc* pDoc;
+ if ( m_pTxtNode )
+ {
+ pDoc = m_pTxtNode->GetDoc();
+ }
+ else
+ {
+ //JP 27.01.97: der sw3-Reader setzt einen StartNode aber das
+ // Attribut ist noch nicht im TextNode verankert.
+ // Wird es geloescht (z.B. bei Datei einfuegen mit
+ // Ftn in einen Rahmen), muss auch der Inhalt
+ // geloescht werden
+ pDoc = m_pStartNode->GetNodes().GetDoc();
+ }
+
+ // Wir duerfen die Fussnotennodes nicht loeschen
+ // und brauchen die Fussnotenframes nicht loeschen, wenn
+ // wir im ~SwDoc() stehen.
+ if( !pDoc->IsInDtor() )
+ {
+ if( bDelNode )
+ {
+ // 1) Die Section fuer die Fussnote wird beseitigt
+ // Es kann sein, dass die Inserts schon geloescht wurden.
+ pDoc->DeleteSection( &m_pStartNode->GetNode() );
+ }
+ else
+ // Werden die Nodes nicht geloescht mussen sie bei den Seiten
+ // abmeldet (Frms loeschen) werden, denn sonst bleiben sie
+ // stehen (Undo loescht sie nicht!)
+ DelFrms( 0 );
+ }
+ DELETEZ( m_pStartNode );
+
+ // loesche die Fussnote noch aus dem Array am Dokument
+ for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().Count(); ++n )
+ if( this == pDoc->GetFtnIdxs()[n] )
+ {
+ pDoc->GetFtnIdxs().Remove( n );
+ // gibt noch weitere Fussnoten
+ if( !pDoc->IsInDtor() && n < pDoc->GetFtnIdxs().Count() )
+ {
+ SwNodeIndex aTmp( pDoc->GetFtnIdxs()[n]->GetTxtNode() );
+ pDoc->GetFtnIdxs().UpdateFtn( aTmp );
+ }
+ break;
+ }
+ }
+}
+
+
+void SwTxtFtn::SetNumber( const sal_uInt16 nNewNum, const XubString* pStr )
+{
+ SwFmtFtn& rFtn = (SwFmtFtn&)GetFtn();
+ if( pStr && pStr->Len() )
+ rFtn.aNumber = *pStr;
+ else
+ {
+ rFtn.nNumber = nNewNum;
+ rFtn.aNumber = aEmptyStr;
+ }
+
+ OSL_ENSURE( m_pTxtNode, "SwTxtFtn: where is my TxtNode?" );
+ SwNodes &rNodes = m_pTxtNode->GetDoc()->GetNodes();
+ m_pTxtNode->ModifyNotification( 0, &rFtn );
+ if ( m_pStartNode )
+ {
+ // must iterate over all TxtNodes because of footnotes on other pages
+ SwNode* pNd;
+ sal_uLong nSttIdx = m_pStartNode->GetIndex() + 1;
+ sal_uLong nEndIdx = m_pStartNode->GetNode().EndOfSectionIndex();
+ for( ; nSttIdx < nEndIdx; ++nSttIdx )
+ {
+ // Es koennen ja auch Grafiken in der Fussnote stehen ...
+ if( ( pNd = rNodes[ nSttIdx ] )->IsTxtNode() )
+ ((SwTxtNode*)pNd)->ModifyNotification( 0, &rFtn );
+ }
+ }
+}
+
+// Die Fussnoten duplizieren
+void SwTxtFtn::CopyFtn(SwTxtFtn & rDest, SwTxtNode & rDestNode) const
+{
+ if (m_pStartNode && !rDest.GetStartNode())
+ {
+ // dest missing node section? create it here!
+ // (happens in SwTxtNode::CopyText if pDest == this)
+ rDest.MakeNewTextSection( rDestNode.GetNodes() );
+ }
+ if (m_pStartNode && rDest.GetStartNode())
+ {
+ // footnotes not necessarily in same document!
+ SwDoc *const pDstDoc = rDestNode.GetDoc();
+ SwNodes &rDstNodes = pDstDoc->GetNodes();
+
+ // copy only the content of the section
+ SwNodeRange aRg( *m_pStartNode, 1,
+ *m_pStartNode->GetNode().EndOfSectionNode() );
+
+ // insert at the end of rDest, i.e., the nodes are appended.
+ // nDestLen contains number of CntntNodes in rDest _before_ copy.
+ SwNodeIndex aStart( *(rDest.GetStartNode()) );
+ SwNodeIndex aEnd( *aStart.GetNode().EndOfSectionNode() );
+ sal_uLong nDestLen = aEnd.GetIndex() - aStart.GetIndex() - 1;
+
+ m_pTxtNode->GetDoc()->CopyWithFlyInFly( aRg, 0, aEnd, sal_True );
+
+ // in case the destination section was not empty, delete the old nodes
+ // before: Src: SxxxE, Dst: SnE
+ // now: Src: SxxxE, Dst: SnxxxE
+ // after: Src: SxxxE, Dst: SxxxE
+ aStart++;
+ rDstNodes.Delete( aStart, nDestLen );
+ }
+
+ // also copy user defined number string
+ if( GetFtn().aNumber.Len() )
+ {
+ const_cast<SwFmtFtn &>(rDest.GetFtn()).aNumber = GetFtn().aNumber;
+ }
+}
+
+
+ // lege eine neue leere TextSection fuer diese Fussnote an
+void SwTxtFtn::MakeNewTextSection( SwNodes& rNodes )
+{
+ if ( m_pStartNode )
+ return;
+
+ // Nun verpassen wir dem TxtNode noch die Fussnotenvorlage.
+ SwTxtFmtColl *pFmtColl;
+ const SwEndNoteInfo* pInfo;
+ sal_uInt16 nPoolId;
+
+ if( GetFtn().IsEndNote() )
+ {
+ pInfo = &rNodes.GetDoc()->GetEndNoteInfo();
+ nPoolId = RES_POOLCOLL_ENDNOTE;
+ }
+ else
+ {
+ pInfo = &rNodes.GetDoc()->GetFtnInfo();
+ nPoolId = RES_POOLCOLL_FOOTNOTE;
+ }
+
+ if( 0 == (pFmtColl = pInfo->GetFtnTxtColl() ) )
+ pFmtColl = rNodes.GetDoc()->GetTxtCollFromPool( nPoolId );
+
+ SwStartNode* pSttNd = rNodes.MakeTextSection( SwNodeIndex( rNodes.GetEndOfInserts() ),
+ SwFootnoteStartNode, pFmtColl );
+ m_pStartNode = new SwNodeIndex( *pSttNd );
+}
+
+
+void SwTxtFtn::DelFrms( const SwFrm* pSib )
+{
+ // delete the FtnFrames from the pages
+ OSL_ENSURE( m_pTxtNode, "SwTxtFtn: where is my TxtNode?" );
+ if ( !m_pTxtNode )
+ return;
+
+ const SwRootFrm* pRoot = pSib ? pSib->getRootFrm() : 0;
+ sal_Bool bFrmFnd = sal_False;
+ {
+ SwIterator<SwCntntFrm,SwTxtNode> aIter( *m_pTxtNode );
+ for( SwCntntFrm* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
+ {
+ if( pRoot != pFnd->getRootFrm() && pRoot )
+ continue;
+ SwPageFrm* pPage = pFnd->FindPageFrm();
+ if( pPage )
+ {
+ pPage->RemoveFtn( pFnd, this );
+ bFrmFnd = sal_True;
+ }
+ }
+ }
+ //JP 13.05.97: falls das Layout vorm loeschen der Fussnoten entfernt
+ // wird, sollte man das ueber die Fussnote selbst tun
+ if ( !bFrmFnd && m_pStartNode )
+ {
+ SwNodeIndex aIdx( *m_pStartNode );
+ SwCntntNode* pCNd = m_pTxtNode->GetNodes().GoNext( &aIdx );
+ if( pCNd )
+ {
+ SwIterator<SwCntntFrm,SwCntntNode> aIter( *pCNd );
+ for( SwCntntFrm* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
+ {
+ if( pRoot != pFnd->getRootFrm() && pRoot )
+ continue;
+ SwPageFrm* pPage = pFnd->FindPageFrm();
+
+ SwFrm *pFrm = pFnd->GetUpper();
+ while ( pFrm && !pFrm->IsFtnFrm() )
+ pFrm = pFrm->GetUpper();
+
+ SwFtnFrm *pFtn = (SwFtnFrm*)pFrm;
+ while ( pFtn && pFtn->GetMaster() )
+ pFtn = pFtn->GetMaster();
+ OSL_ENSURE( pFtn->GetAttr() == this, "Ftn mismatch error." );
+
+ while ( pFtn )
+ {
+ SwFtnFrm *pFoll = pFtn->GetFollow();
+ pFtn->Cut();
+ delete pFtn;
+ pFtn = pFoll;
+ }
+
+ // #i20556# During hiding of a section, the connection
+ // to the layout is already lost. pPage may be 0:
+ if ( pPage )
+ pPage->UpdateFtnNum();
+ }
+ }
+ }
+}
+
+
+sal_uInt16 SwTxtFtn::SetSeqRefNo()
+{
+ if( !m_pTxtNode )
+ return USHRT_MAX;
+
+ SwDoc* pDoc = m_pTxtNode->GetDoc();
+ if( pDoc->IsInReading() )
+ return USHRT_MAX;
+
+ sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count();
+
+ const sal_uInt8 nTmp = 255 < nFtnCnt ? 255 : static_cast<sal_uInt8>(nFtnCnt);
+ SvUShortsSort aArr( nTmp, nTmp );
+
+ // dann testmal, ob die Nummer schon vergeben ist oder ob eine neue
+ // bestimmt werden muss.
+ SwTxtFtn* pTxtFtn;
+ for( n = 0; n < nFtnCnt; ++n )
+ {
+ pTxtFtn = pDoc->GetFtnIdxs()[ n ];
+ if ( pTxtFtn != this )
+ {
+ aArr.Insert( pTxtFtn->m_nSeqNo );
+ }
+ }
+
+ // test if number is already in use
+ if ( USHRT_MAX != m_nSeqNo )
+ {
+ for( n = 0; n < aArr.Count(); ++n )
+ {
+ if ( aArr[ n ] > m_nSeqNo )
+ {
+ return m_nSeqNo; // free -> use
+ }
+ else if ( aArr[ n ] == m_nSeqNo )
+ {
+ break; // used -> create new one
+ }
+ }
+
+ if ( n == aArr.Count() )
+ {
+ return m_nSeqNo; // free -> use
+ }
+ }
+
+ // alle Nummern entsprechend geflag, also bestimme die richtige Nummer
+ for( n = 0; n < aArr.Count(); ++n )
+ if( n != aArr[ n ] )
+ break;
+
+ return m_nSeqNo = n;
+}
+
+void SwTxtFtn::SetUniqueSeqRefNo( SwDoc& rDoc )
+{
+ sal_uInt16 n, nStt = 0, nFtnCnt = rDoc.GetFtnIdxs().Count();
+
+ const sal_uInt8 nTmp = 255 < nFtnCnt ? 255 : static_cast<sal_uInt8>(nFtnCnt);
+ SvUShortsSort aArr( nTmp, nTmp );
+
+ // dann alle Nummern zusammensammeln die schon existieren
+ SwTxtFtn* pTxtFtn;
+ for( n = 0; n < nFtnCnt; ++n )
+ {
+ pTxtFtn = rDoc.GetFtnIdxs()[ n ];
+ if ( USHRT_MAX != pTxtFtn->m_nSeqNo )
+ {
+ aArr.Insert( pTxtFtn->m_nSeqNo );
+ }
+ }
+
+
+ for( n = 0; n < nFtnCnt; ++n )
+ {
+ pTxtFtn = rDoc.GetFtnIdxs()[ n ];
+ if ( USHRT_MAX == pTxtFtn->m_nSeqNo )
+ {
+ for( ; nStt < aArr.Count(); ++nStt )
+ {
+ if ( nStt != aArr[ nStt ] )
+ {
+ pTxtFtn->m_nSeqNo = nStt;
+ break;
+ }
+ }
+
+ if ( USHRT_MAX == pTxtFtn->m_nSeqNo )
+ {
+ break; // found nothing
+ }
+ }
+ }
+
+ // alle Nummern schon vergeben, also mit nStt++ weitermachen
+ for( ; n < nFtnCnt; ++n )
+ {
+ pTxtFtn = rDoc.GetFtnIdxs()[ n ];
+ if ( USHRT_MAX == pTxtFtn->m_nSeqNo )
+ {
+ pTxtFtn->m_nSeqNo = nStt++;
+ }
+ }
+}
+
+void SwTxtFtn::CheckCondColl()
+{
+//FEATURE::CONDCOLL
+ if( GetStartNode() )
+ ((SwStartNode&)GetStartNode()->GetNode()).CheckSectionCondColl();
+//FEATURE::CONDCOLL
+}
+
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/atrref.cxx b/sw/source/core/txtnode/atrref.cxx
new file mode 100644
index 000000000000..7adfc3ff591f
--- /dev/null
+++ b/sw/source/core/txtnode/atrref.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <hintids.hxx>
+#include <txtrfmrk.hxx>
+#include <fmtrfmrk.hxx>
+#include <swfont.hxx>
+
+
+/****************************************************************************
+ *
+ * class SwFmtRefMark
+ *
+ ****************************************************************************/
+
+SwFmtRefMark::~SwFmtRefMark( )
+{
+}
+
+SwFmtRefMark::SwFmtRefMark( const XubString& rName )
+ : SfxPoolItem( RES_TXTATR_REFMARK ),
+ pTxtAttr( 0 ),
+ aRefName( rName )
+{
+}
+
+SwFmtRefMark::SwFmtRefMark( const SwFmtRefMark& rAttr )
+ : SfxPoolItem( RES_TXTATR_REFMARK ),
+ pTxtAttr( 0 ),
+ aRefName( rAttr.aRefName )
+{
+}
+
+int SwFmtRefMark::operator==( const SfxPoolItem& rAttr ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
+ return aRefName == ((SwFmtRefMark&)rAttr).aRefName;
+}
+
+SfxPoolItem* SwFmtRefMark::Clone( SfxItemPool* ) const
+{
+ return new SwFmtRefMark( *this );
+}
+
+/*************************************************************************
+ * class SwTxtRefMark
+ *************************************************************************/
+
+// Attribut fuer Inhalts-/Positions-Referenzen im Text
+
+SwTxtRefMark::SwTxtRefMark( SwFmtRefMark& rAttr,
+ xub_StrLen const nStartPos, xub_StrLen const*const pEnd)
+ : SwTxtAttrEnd( rAttr, nStartPos, nStartPos )
+ , m_pTxtNode( 0 )
+ , m_pEnd( 0 )
+{
+ rAttr.pTxtAttr = this;
+ if ( pEnd )
+ {
+ m_nEnd = *pEnd;
+ m_pEnd = & m_nEnd;
+ }
+ else
+ {
+ SetHasDummyChar(true);
+ }
+ SetDontMoveAttr( true );
+ SetOverlapAllowedAttr( true );
+}
+
+xub_StrLen* SwTxtRefMark::GetEnd()
+{
+ return m_pEnd;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/atrtox.cxx b/sw/source/core/txtnode/atrtox.cxx
new file mode 100644
index 000000000000..1b3c989e23db
--- /dev/null
+++ b/sw/source/core/txtnode/atrtox.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <doc.hxx>
+#include <txttxmrk.hxx>
+#include <swfont.hxx>
+#include <tox.hxx>
+#include <ndtxt.hxx>
+
+SwTxtTOXMark::SwTxtTOXMark( SwTOXMark& rAttr,
+ xub_StrLen const nStartPos, xub_StrLen const*const pEnd)
+ : SwTxtAttrEnd( rAttr, nStartPos, nStartPos )
+ , m_pTxtNode( 0 )
+ , m_pEnd( 0 )
+{
+ rAttr.pTxtAttr = this;
+ if ( !rAttr.GetAlternativeText().Len() )
+ {
+ m_nEnd = *pEnd;
+ m_pEnd = & m_nEnd;
+ }
+ else
+ {
+ SetHasDummyChar(true);
+ }
+ SetDontMoveAttr( true );
+ SetOverlapAllowedAttr( true );
+}
+
+SwTxtTOXMark::~SwTxtTOXMark()
+{
+}
+
+xub_StrLen* SwTxtTOXMark::GetEnd()
+{
+ return m_pEnd;
+}
+
+void SwTxtTOXMark::CopyTOXMark( SwDoc* pDoc )
+{
+ SwTOXMark& rTOX = (SwTOXMark&)GetTOXMark();
+ TOXTypes eType = rTOX.GetTOXType()->GetType();
+ sal_uInt16 nCount = pDoc->GetTOXTypeCount( eType );
+ const SwTOXType* pType = 0;
+ const XubString& rNm = rTOX.GetTOXType()->GetTypeName();
+
+ // kein entsprechender Verzeichnistyp vorhanden -> anlegen
+ // sonst verwenden
+ for(sal_uInt16 i=0; i < nCount; ++i)
+ {
+ const SwTOXType* pSrcType = pDoc->GetTOXType(eType, i);
+ if(pSrcType->GetTypeName() == rNm )
+ {
+ pType = pSrcType;
+ break;
+ }
+ }
+ // kein entsprechender Typ vorhanden -> neu erzeugen
+ //
+ if(!pType)
+ {
+ pDoc->InsertTOXType( SwTOXType( eType, rNm ) );
+ pType = pDoc->GetTOXType(eType, 0);
+ }
+ // Verzeichnistyp umhaengen
+ //
+ ((SwTOXType*)pType)->Add( &rTOX );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/chrfmt.cxx b/sw/source/core/txtnode/chrfmt.cxx
new file mode 100644
index 000000000000..71d7e48f6d74
--- /dev/null
+++ b/sw/source/core/txtnode/chrfmt.cxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <charfmt.hxx>
+
+
+TYPEINIT1( SwCharFmt, SwFmt ); //rtti fuer SwCharFmt
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/fmtatr2.cxx b/sw/source/core/txtnode/fmtatr2.cxx
new file mode 100644
index 000000000000..ed7ab96e35e2
--- /dev/null
+++ b/sw/source/core/txtnode/fmtatr2.cxx
@@ -0,0 +1,905 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include "hintids.hxx"
+#include "unomid.h"
+
+#include <basic/sbxvar.hxx>
+#include <svl/macitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/stylepool.hxx>
+#include <fmtautofmt.hxx>
+#include <fchrfmt.hxx>
+#include <fmtinfmt.hxx>
+#include <txtatr.hxx>
+#include <fmtruby.hxx>
+#include <charfmt.hxx>
+#include <hints.hxx> // SwUpdateAttr
+#include <unostyle.hxx>
+#include <unoevent.hxx> // SwHyperlinkEventDescriptor
+#include <com/sun/star/text/RubyAdjust.hdl>
+
+#include <cmdid.h>
+#include <com/sun/star/uno/Any.h>
+#include <SwStyleNameMapper.hxx>
+
+#include <fmtmeta.hxx>
+#include <ndtxt.hxx> // for meta
+#include <doc.hxx> // for meta
+#include <unometa.hxx>
+#include <docsh.hxx>
+#include <svl/zforlist.hxx> // GetNumberFormat
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+
+using namespace ::com::sun::star;
+using ::rtl::OUString;
+
+TYPEINIT1_AUTOFACTORY(SwFmtINetFmt, SfxPoolItem);
+TYPEINIT1_AUTOFACTORY(SwFmtAutoFmt, SfxPoolItem);
+
+/*************************************************************************
+|*
+|* class SwFmtCharFmt
+|*
+*************************************************************************/
+
+SwFmtCharFmt::SwFmtCharFmt( SwCharFmt *pFmt )
+ : SfxPoolItem( RES_TXTATR_CHARFMT ),
+ SwClient(pFmt),
+ pTxtAttr( 0 )
+{
+}
+
+
+
+SwFmtCharFmt::SwFmtCharFmt( const SwFmtCharFmt& rAttr )
+ : SfxPoolItem( RES_TXTATR_CHARFMT ),
+ SwClient( rAttr.GetCharFmt() ),
+ pTxtAttr( 0 )
+{
+}
+
+
+
+SwFmtCharFmt::~SwFmtCharFmt() {}
+
+
+
+int SwFmtCharFmt::operator==( const SfxPoolItem& rAttr ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
+ return GetCharFmt() == ((SwFmtCharFmt&)rAttr).GetCharFmt();
+}
+
+
+
+SfxPoolItem* SwFmtCharFmt::Clone( SfxItemPool* ) const
+{
+ return new SwFmtCharFmt( *this );
+}
+
+
+
+// weiterleiten an das TextAttribut
+void SwFmtCharFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
+{
+ if( pTxtAttr )
+ pTxtAttr->ModifyNotification( pOld, pNew );
+}
+
+
+
+// weiterleiten an das TextAttribut
+sal_Bool SwFmtCharFmt::GetInfo( SfxPoolItem& rInfo ) const
+{
+ return pTxtAttr ? pTxtAttr->GetInfo( rInfo ) : sal_False;
+}
+bool SwFmtCharFmt::QueryValue( uno::Any& rVal, sal_uInt8 ) const
+{
+ String sCharFmtName;
+ if(GetCharFmt())
+ SwStyleNameMapper::FillProgName(GetCharFmt()->GetName(), sCharFmtName, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
+ rVal <<= OUString( sCharFmtName );
+ return true;
+}
+bool SwFmtCharFmt::PutValue( const uno::Any& , sal_uInt8 )
+{
+ OSL_FAIL("Zeichenvorlage kann mit PutValue nicht gesetzt werden!");
+ return false;
+}
+
+/*************************************************************************
+|*
+|* class SwFmtAutoFmt
+|*
+*************************************************************************/
+
+SwFmtAutoFmt::SwFmtAutoFmt( sal_uInt16 nInitWhich )
+ : SfxPoolItem( nInitWhich )
+{
+}
+
+SwFmtAutoFmt::SwFmtAutoFmt( const SwFmtAutoFmt& rAttr )
+ : SfxPoolItem( rAttr.Which() ), mpHandle( rAttr.mpHandle )
+{
+}
+
+SwFmtAutoFmt::~SwFmtAutoFmt()
+{
+}
+
+int SwFmtAutoFmt::operator==( const SfxPoolItem& rAttr ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "different attributes" );
+ return mpHandle == ((SwFmtAutoFmt&)rAttr).mpHandle;
+}
+
+SfxPoolItem* SwFmtAutoFmt::Clone( SfxItemPool* ) const
+{
+ return new SwFmtAutoFmt( *this );
+}
+
+bool SwFmtAutoFmt::QueryValue( uno::Any& rVal, sal_uInt8 ) const
+{
+ String sCharFmtName = StylePool::nameOf( mpHandle );
+ rVal <<= OUString( sCharFmtName );
+ return true;
+}
+
+bool SwFmtAutoFmt::PutValue( const uno::Any& , sal_uInt8 )
+{
+ //the format is not renameable via API
+ return false;
+}
+
+/*************************************************************************
+|*
+|* class SwFmtINetFmt
+|*
+*************************************************************************/
+
+SwFmtINetFmt::SwFmtINetFmt()
+ : SfxPoolItem( RES_TXTATR_INETFMT ),
+ pMacroTbl( 0 ),
+ pTxtAttr( 0 ),
+ nINetId( 0 ),
+ nVisitedId( 0 )
+{}
+
+SwFmtINetFmt::SwFmtINetFmt( const XubString& rURL, const XubString& rTarget )
+ : SfxPoolItem( RES_TXTATR_INETFMT ),
+ aURL( rURL ),
+ aTargetFrame( rTarget ),
+ pMacroTbl( 0 ),
+ pTxtAttr( 0 ),
+ nINetId( 0 ),
+ nVisitedId( 0 )
+{
+}
+
+SwFmtINetFmt::SwFmtINetFmt( const SwFmtINetFmt& rAttr )
+ : SfxPoolItem( RES_TXTATR_INETFMT ),
+ aURL( rAttr.GetValue() ),
+ aTargetFrame( rAttr.aTargetFrame ),
+ aINetFmt( rAttr.aINetFmt ),
+ aVisitedFmt( rAttr.aVisitedFmt ),
+ aName( rAttr.aName ),
+ pMacroTbl( 0 ),
+ pTxtAttr( 0 ),
+ nINetId( rAttr.nINetId ),
+ nVisitedId( rAttr.nVisitedId )
+{
+ if( rAttr.GetMacroTbl() )
+ pMacroTbl = new SvxMacroTableDtor( *rAttr.GetMacroTbl() );
+}
+
+SwFmtINetFmt::~SwFmtINetFmt()
+{
+ delete pMacroTbl;
+}
+
+
+
+int SwFmtINetFmt::operator==( const SfxPoolItem& rAttr ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
+ sal_Bool bRet = SfxPoolItem::operator==( (SfxPoolItem&) rAttr )
+ && aURL == ((SwFmtINetFmt&)rAttr).aURL
+ && aName == ((SwFmtINetFmt&)rAttr).aName
+ && aTargetFrame == ((SwFmtINetFmt&)rAttr).aTargetFrame
+ && aINetFmt == ((SwFmtINetFmt&)rAttr).aINetFmt
+ && aVisitedFmt == ((SwFmtINetFmt&)rAttr).aVisitedFmt
+ && nINetId == ((SwFmtINetFmt&)rAttr).nINetId
+ && nVisitedId == ((SwFmtINetFmt&)rAttr).nVisitedId;
+
+ if( !bRet )
+ return sal_False;
+
+ const SvxMacroTableDtor* pOther = ((SwFmtINetFmt&)rAttr).pMacroTbl;
+ if( !pMacroTbl )
+ return ( !pOther || !pOther->Count() );
+ if( !pOther )
+ return 0 == pMacroTbl->Count();
+
+ const SvxMacroTableDtor& rOwn = *pMacroTbl;
+ const SvxMacroTableDtor& rOther = *pOther;
+
+ // Anzahl unterschiedlich => auf jeden Fall ungleich
+ if( rOwn.Count() != rOther.Count() )
+ return sal_False;
+
+ // einzeln vergleichen; wegen Performance ist die Reihenfolge wichtig
+ for( sal_uInt16 nNo = 0; nNo < rOwn.Count(); ++nNo )
+ {
+ const SvxMacro *pOwnMac = rOwn.GetObject(nNo);
+ const SvxMacro *pOtherMac = rOther.GetObject(nNo);
+ if ( rOwn.GetKey(pOwnMac) != rOther.GetKey(pOtherMac) ||
+ pOwnMac->GetLibName() != pOtherMac->GetLibName() ||
+ pOwnMac->GetMacName() != pOtherMac->GetMacName() )
+ return sal_False;
+ }
+ return sal_True;
+}
+
+
+
+SfxPoolItem* SwFmtINetFmt::Clone( SfxItemPool* ) const
+{
+ return new SwFmtINetFmt( *this );
+}
+
+
+
+void SwFmtINetFmt::SetMacroTbl( const SvxMacroTableDtor* pNewTbl )
+{
+ if( pNewTbl )
+ {
+ if( pMacroTbl )
+ *pMacroTbl = *pNewTbl;
+ else
+ pMacroTbl = new SvxMacroTableDtor( *pNewTbl );
+ }
+ else if( pMacroTbl )
+ delete pMacroTbl, pMacroTbl = 0;
+}
+
+
+
+void SwFmtINetFmt::SetMacro( sal_uInt16 nEvent, const SvxMacro& rMacro )
+{
+ if( !pMacroTbl )
+ pMacroTbl = new SvxMacroTableDtor;
+
+ SvxMacro *pOldMacro;
+ if( 0 != ( pOldMacro = pMacroTbl->Get( nEvent )) )
+ {
+ delete pOldMacro;
+ pMacroTbl->Replace( nEvent, new SvxMacro( rMacro ) );
+ }
+ else
+ pMacroTbl->Insert( nEvent, new SvxMacro( rMacro ) );
+}
+
+
+
+const SvxMacro* SwFmtINetFmt::GetMacro( sal_uInt16 nEvent ) const
+{
+ const SvxMacro* pRet = 0;
+ if( pMacroTbl && pMacroTbl->IsKeyValid( nEvent ) )
+ pRet = pMacroTbl->Get( nEvent );
+ return pRet;
+}
+
+
+
+bool SwFmtINetFmt::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ bool bRet = true;
+ XubString sVal;
+ nMemberId &= ~CONVERT_TWIPS;
+ switch(nMemberId)
+ {
+ case MID_URL_URL:
+ sVal = aURL;
+ break;
+ case MID_URL_TARGET:
+ sVal = aTargetFrame;
+ break;
+ case MID_URL_HYPERLINKNAME:
+ sVal = aName;
+ break;
+ case MID_URL_VISITED_FMT:
+ sVal = aVisitedFmt;
+ if( !sVal.Len() && nVisitedId != 0 )
+ SwStyleNameMapper::FillUIName( nVisitedId, sVal );
+ if( sVal.Len() )
+ SwStyleNameMapper::FillProgName( sVal, sVal, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
+ break;
+ case MID_URL_UNVISITED_FMT:
+ sVal = aINetFmt;
+ if( !sVal.Len() && nINetId != 0 )
+ SwStyleNameMapper::FillUIName( nINetId, sVal );
+ if( sVal.Len() )
+ SwStyleNameMapper::FillProgName( sVal, sVal, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
+ break;
+ case MID_URL_HYPERLINKEVENTS:
+ {
+ // create (and return) event descriptor
+ SwHyperlinkEventDescriptor* pEvents =
+ new SwHyperlinkEventDescriptor();
+ pEvents->copyMacrosFromINetFmt(*this);
+ uno::Reference<container::XNameReplace> xNameReplace(pEvents);
+
+ // all others return a string; so we just set rVal here and exit
+ rVal <<= xNameReplace;
+ return bRet;
+ }
+ default:
+ break;
+ }
+ rVal <<= OUString(sVal);
+ return bRet;
+}
+bool SwFmtINetFmt::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ bool bRet = true;
+ nMemberId &= ~CONVERT_TWIPS;
+
+ // all properties except HyperlinkEvents are of type string, hence
+ // we treat HyperlinkEvents specially
+ if (MID_URL_HYPERLINKEVENTS == nMemberId)
+ {
+ uno::Reference<container::XNameReplace> xReplace;
+ rVal >>= xReplace;
+ if (xReplace.is())
+ {
+ // Create hyperlink event descriptor. Then copy events
+ // from argument into descriptor. Then copy events from
+ // the descriptor into the format.
+ SwHyperlinkEventDescriptor* pEvents = new SwHyperlinkEventDescriptor();
+ uno::Reference< lang::XServiceInfo> xHold = pEvents;
+ pEvents->copyMacrosFromNameReplace(xReplace);
+ pEvents->copyMacrosIntoINetFmt(*this);
+ }
+ else
+ {
+ // wrong type!
+ bRet = false;
+ }
+ }
+ else
+ {
+ // all string properties:
+ if(rVal.getValueType() != ::getCppuType((rtl::OUString*)0))
+ return false;
+ XubString sVal = *(rtl::OUString*)rVal.getValue();
+ switch(nMemberId)
+ {
+ case MID_URL_URL:
+ aURL = sVal;
+ break;
+ case MID_URL_TARGET:
+ aTargetFrame = sVal;
+ break;
+ case MID_URL_HYPERLINKNAME:
+ aName = sVal;
+ break;
+ case MID_URL_VISITED_FMT:
+ {
+ String aString;
+ SwStyleNameMapper::FillUIName( sVal, aString, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
+ aVisitedFmt = OUString ( aString );
+ nVisitedId = SwStyleNameMapper::GetPoolIdFromUIName( aVisitedFmt,
+ nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
+ }
+ break;
+ case MID_URL_UNVISITED_FMT:
+ {
+ String aString;
+ SwStyleNameMapper::FillUIName( sVal, aString, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
+ aINetFmt = OUString ( aString );
+ nINetId = SwStyleNameMapper::GetPoolIdFromUIName( aINetFmt, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
+ }
+ break;
+ default:
+ bRet = false;
+ }
+ }
+ return bRet;
+}
+
+
+/*************************************************************************
+|* class SwFmtRuby
+*************************************************************************/
+
+SwFmtRuby::SwFmtRuby( const String& rRubyTxt )
+ : SfxPoolItem( RES_TXTATR_CJK_RUBY ),
+ sRubyTxt( rRubyTxt ),
+ pTxtAttr( 0 ),
+ nCharFmtId( 0 ),
+ nPosition( 0 ),
+ nAdjustment( 0 )
+{
+}
+
+SwFmtRuby::SwFmtRuby( const SwFmtRuby& rAttr )
+ : SfxPoolItem( RES_TXTATR_CJK_RUBY ),
+ sRubyTxt( rAttr.sRubyTxt ),
+ sCharFmtName( rAttr.sCharFmtName ),
+ pTxtAttr( 0 ),
+ nCharFmtId( rAttr.nCharFmtId),
+ nPosition( rAttr.nPosition ),
+ nAdjustment( rAttr.nAdjustment )
+{
+}
+
+SwFmtRuby::~SwFmtRuby()
+{
+}
+
+SwFmtRuby& SwFmtRuby::operator=( const SwFmtRuby& rAttr )
+{
+ sRubyTxt = rAttr.sRubyTxt;
+ sCharFmtName = rAttr.sCharFmtName;
+ nCharFmtId = rAttr.nCharFmtId;
+ nPosition = rAttr.nPosition;
+ nAdjustment = rAttr.nAdjustment;
+ pTxtAttr = 0;
+ return *this;
+}
+
+int SwFmtRuby::operator==( const SfxPoolItem& rAttr ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
+ return sRubyTxt == ((SwFmtRuby&)rAttr).sRubyTxt &&
+ sCharFmtName == ((SwFmtRuby&)rAttr).sCharFmtName &&
+ nCharFmtId == ((SwFmtRuby&)rAttr).nCharFmtId &&
+ nPosition == ((SwFmtRuby&)rAttr).nPosition &&
+ nAdjustment == ((SwFmtRuby&)rAttr).nAdjustment;
+}
+
+SfxPoolItem* SwFmtRuby::Clone( SfxItemPool* ) const
+{
+ return new SwFmtRuby( *this );
+}
+
+bool SwFmtRuby::QueryValue( uno::Any& rVal,
+ sal_uInt8 nMemberId ) const
+{
+ bool bRet = true;
+ nMemberId &= ~CONVERT_TWIPS;
+ switch( nMemberId )
+ {
+ case MID_RUBY_TEXT: rVal <<= (OUString)sRubyTxt; break;
+ case MID_RUBY_ADJUST: rVal <<= (sal_Int16)nAdjustment; break;
+ case MID_RUBY_CHARSTYLE:
+ {
+ String aString;
+ SwStyleNameMapper::FillProgName(sCharFmtName, aString, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
+ rVal <<= OUString ( aString );
+ }
+ break;
+ case MID_RUBY_ABOVE:
+ {
+ sal_Bool bAbove = !nPosition;
+ rVal.setValue(&bAbove, ::getBooleanCppuType());
+ }
+ break;
+ default:
+ bRet = false;
+ }
+ return bRet;
+}
+bool SwFmtRuby::PutValue( const uno::Any& rVal,
+ sal_uInt8 nMemberId )
+{
+ bool bRet = true;
+ nMemberId &= ~CONVERT_TWIPS;
+ switch( nMemberId )
+ {
+ case MID_RUBY_TEXT:
+ {
+ OUString sTmp;
+ bRet = rVal >>= sTmp;
+ sRubyTxt = sTmp;
+ }
+ break;
+ case MID_RUBY_ADJUST:
+ {
+ sal_Int16 nSet = 0;
+ rVal >>= nSet;
+ if(nSet >= 0 && nSet <= text::RubyAdjust_INDENT_BLOCK)
+ nAdjustment = nSet;
+ else
+ bRet = false;
+ }
+ break;
+ case MID_RUBY_ABOVE:
+ {
+ const uno::Type& rType = ::getBooleanCppuType();
+ if(rVal.hasValue() && rVal.getValueType() == rType)
+ {
+ sal_Bool bAbove = *(sal_Bool*)rVal.getValue();
+ nPosition = bAbove ? 0 : 1;
+ }
+ }
+ break;
+ case MID_RUBY_CHARSTYLE:
+ {
+ OUString sTmp;
+ bRet = rVal >>= sTmp;
+ if(bRet)
+ sCharFmtName = SwStyleNameMapper::GetUIName(sTmp, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
+ }
+ break;
+ default:
+ bRet = false;
+ }
+ return bRet;
+}
+
+
+/*************************************************************************
+ class SwFmtMeta
+ ************************************************************************/
+
+SwFmtMeta * SwFmtMeta::CreatePoolDefault(const sal_uInt16 i_nWhich)
+{
+ return new SwFmtMeta(i_nWhich);
+}
+
+SwFmtMeta::SwFmtMeta(const sal_uInt16 i_nWhich)
+ : SfxPoolItem( i_nWhich )
+ , m_pMeta()
+ , m_pTxtAttr( 0 )
+{
+ OSL_ENSURE((RES_TXTATR_META == i_nWhich) || (RES_TXTATR_METAFIELD == i_nWhich),
+ "ERROR: SwFmtMeta: invalid which id!");
+}
+
+SwFmtMeta::SwFmtMeta( ::boost::shared_ptr< ::sw::Meta > const & i_pMeta,
+ const sal_uInt16 i_nWhich )
+ : SfxPoolItem( i_nWhich )
+ , m_pMeta( i_pMeta )
+ , m_pTxtAttr( 0 )
+{
+ OSL_ENSURE((RES_TXTATR_META == i_nWhich) || (RES_TXTATR_METAFIELD == i_nWhich),
+ "ERROR: SwFmtMeta: invalid which id!");
+ OSL_ENSURE(m_pMeta, "SwFmtMeta: no Meta ?");
+ // DO NOT call m_pMeta->SetFmtMeta(this) here; only from SetTxtAttr!
+}
+
+SwFmtMeta::~SwFmtMeta()
+{
+ if (m_pMeta && (m_pMeta->GetFmtMeta() == this))
+ {
+ NotifyChangeTxtNode(0);
+ m_pMeta->SetFmtMeta(0);
+ }
+}
+
+int SwFmtMeta::operator==( const SfxPoolItem & i_rOther ) const
+{
+ OSL_ENSURE( SfxPoolItem::operator==( i_rOther ), "i just copied this assert" );
+ return SfxPoolItem::operator==( i_rOther )
+ && (m_pMeta == static_cast<SwFmtMeta const &>( i_rOther ).m_pMeta);
+}
+
+SfxPoolItem * SwFmtMeta::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ // if this is indeed a copy, then DoCopy must be called later!
+ return (m_pMeta) // #i105148# pool default may be cloned also!
+ ? new SwFmtMeta( m_pMeta, Which() ) : new SwFmtMeta( Which() );
+}
+
+void SwFmtMeta::SetTxtAttr(SwTxtMeta * const i_pTxtAttr)
+{
+ OSL_ENSURE(!(m_pTxtAttr && i_pTxtAttr),
+ "SwFmtMeta::SetTxtAttr: already has text attribute?");
+ OSL_ENSURE( m_pTxtAttr || i_pTxtAttr ,
+ "SwFmtMeta::SetTxtAttr: no attribute to remove?");
+ m_pTxtAttr = i_pTxtAttr;
+ OSL_ENSURE(m_pMeta, "inserted SwFmtMeta has no sw::Meta?");
+ // the sw::Meta must be able to find the current text attribute!
+ if (m_pMeta)
+ {
+ if (i_pTxtAttr)
+ {
+ m_pMeta->SetFmtMeta(this);
+ }
+ else if (m_pMeta->GetFmtMeta() == this)
+ { // text attribute gone => de-register from text node!
+ NotifyChangeTxtNode(0);
+ m_pMeta->SetFmtMeta(0);
+ }
+ }
+}
+
+void SwFmtMeta::NotifyChangeTxtNode(SwTxtNode *const pTxtNode)
+{
+ // N.B.: do not reset m_pTxtAttr here: see call in nodes.cxx,
+ // where the hint is not deleted!
+ OSL_ENSURE(m_pMeta, "SwFmtMeta::NotifyChangeTxtNode: no Meta?");
+ if (m_pMeta && (m_pMeta->GetFmtMeta() == this))
+ { // do not call Modify, that would call SwXMeta::Modify!
+ m_pMeta->NotifyChangeTxtNode(pTxtNode);
+ }
+}
+
+// this SwFmtMeta has been cloned and points at the same sw::Meta as the source
+// this method copies the sw::Meta
+void SwFmtMeta::DoCopy(::sw::MetaFieldManager & i_rTargetDocManager,
+ SwTxtNode & i_rTargetTxtNode)
+{
+ OSL_ENSURE(m_pMeta, "DoCopy called for SwFmtMeta with no sw::Meta?");
+ if (m_pMeta)
+ {
+ const ::boost::shared_ptr< ::sw::Meta> pOriginal( m_pMeta );
+ if (RES_TXTATR_META == Which())
+ {
+ m_pMeta.reset( new ::sw::Meta(this) );
+ }
+ else
+ {
+ ::sw::MetaField *const pMetaField(
+ static_cast< ::sw::MetaField* >(pOriginal.get()));
+ m_pMeta = i_rTargetDocManager.makeMetaField( this,
+ pMetaField->m_nNumberFormat, pMetaField->IsFixedLanguage() );
+ }
+ // Meta must have a text node before calling RegisterAsCopyOf
+ m_pMeta->NotifyChangeTxtNode(& i_rTargetTxtNode);
+ // this cannot be done in Clone: a Clone is not necessarily a copy!
+ m_pMeta->RegisterAsCopyOf(*pOriginal);
+ }
+}
+
+
+namespace sw {
+
+/*************************************************************************
+ class sw::Meta
+ ************************************************************************/
+
+Meta::Meta(SwFmtMeta * const i_pFmt)
+ : ::sfx2::Metadatable()
+ , SwModify()
+ , m_pFmt( i_pFmt )
+{
+}
+
+Meta::~Meta()
+{
+}
+
+SwTxtMeta * Meta::GetTxtAttr() const
+{
+ return (m_pFmt) ? m_pFmt->GetTxtAttr() : 0;
+}
+
+SwTxtNode * Meta::GetTxtNode() const
+{
+ return m_pTxtNode;
+}
+
+void Meta::NotifyChangeTxtNodeImpl()
+{
+ if (m_pTxtNode && (GetRegisteredIn() != m_pTxtNode))
+ {
+ m_pTxtNode->Add(this);
+ }
+ else if (!m_pTxtNode && GetRegisteredIn())
+ {
+ GetRegisteredInNonConst()->Remove(this);
+ }
+}
+
+void Meta::NotifyChangeTxtNode(SwTxtNode *const pTxtNode)
+{
+ m_pTxtNode = pTxtNode;
+ NotifyChangeTxtNodeImpl();
+ if (!pTxtNode) // text node gone? invalidate UNO object!
+ {
+ SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
+ &static_cast<SwModify&>(*this) ); // cast to base class!
+ this->Modify(&aMsgHint, &aMsgHint);
+ }
+}
+
+// SwClient
+void Meta::Modify( const SfxPoolItem *pOld, const SfxPoolItem *pNew )
+{
+ NotifyClients(pOld, pNew);
+ if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
+ { // invalidate cached uno object
+ SetXMeta(uno::Reference<rdf::XMetadatable>(0));
+ }
+}
+
+// sfx2::Metadatable
+::sfx2::IXmlIdRegistry& Meta::GetRegistry()
+{
+ SwTxtNode * const pTxtNode( GetTxtNode() );
+ // GetRegistry may only be called on a meta that is actually in the
+ // document, which means it has a pointer to its text node
+ OSL_ENSURE(pTxtNode, "ERROR: GetRegistry: no text node?");
+ if (!pTxtNode)
+ throw uno::RuntimeException();
+ return pTxtNode->GetRegistry();
+}
+
+bool Meta::IsInClipboard() const
+{
+ const SwTxtNode * const pTxtNode( GetTxtNode() );
+// no text node: in UNDO OSL_ENSURE(pTxtNode, "IsInClipboard: no text node?");
+ return (pTxtNode) ? pTxtNode->IsInClipboard() : false;
+}
+
+bool Meta::IsInUndo() const
+{
+ const SwTxtNode * const pTxtNode( GetTxtNode() );
+// no text node: in UNDO OSL_ENSURE(pTxtNode, "IsInUndo: no text node?");
+ return (pTxtNode) ? pTxtNode->IsInUndo() : true;
+}
+
+bool Meta::IsInContent() const
+{
+ const SwTxtNode * const pTxtNode( GetTxtNode() );
+ OSL_ENSURE(pTxtNode, "IsInContent: no text node?");
+ return (pTxtNode) ? pTxtNode->IsInContent() : true;
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::rdf::XMetadatable >
+Meta::MakeUnoObject()
+{
+ return SwXMeta::CreateXMeta(*this);
+}
+
+/*************************************************************************
+ class sw::MetaField
+ ************************************************************************/
+
+MetaField::MetaField(SwFmtMeta * const i_pFmt,
+ const sal_uInt32 nNumberFormat, const bool bIsFixedLanguage)
+ : Meta(i_pFmt)
+ , m_nNumberFormat( nNumberFormat )
+ , m_bIsFixedLanguage( bIsFixedLanguage )
+{
+}
+
+void MetaField::GetPrefixAndSuffix(
+ ::rtl::OUString *const o_pPrefix, ::rtl::OUString *const o_pSuffix)
+{
+ try
+ {
+ const uno::Reference<rdf::XMetadatable> xMetaField( MakeUnoObject() );
+ OSL_ENSURE(dynamic_cast<SwXMetaField*>(xMetaField.get()),
+ "GetPrefixAndSuffix: no SwXMetaField?");
+ if (xMetaField.is())
+ {
+ SwTxtNode * const pTxtNode( GetTxtNode() );
+ SwDocShell const * const pShell(pTxtNode->GetDoc()->GetDocShell());
+ const uno::Reference<frame::XModel> xModel(
+ (pShell) ? pShell->GetModel() : 0, uno::UNO_SET_THROW);
+ getPrefixAndSuffix(xModel, xMetaField, o_pPrefix, o_pSuffix);
+ }
+ } catch (uno::Exception) {
+ OSL_FAIL("exception?");
+ }
+}
+
+sal_uInt32 MetaField::GetNumberFormat(::rtl::OUString const & rContent) const
+{
+ //TODO: this probably lacks treatment for some special cases
+ sal_uInt32 nNumberFormat( m_nNumberFormat );
+ SwTxtNode * const pTxtNode( GetTxtNode() );
+ if (pTxtNode)
+ {
+ SvNumberFormatter *const pNumberFormatter(
+ pTxtNode->GetDoc()->GetNumberFormatter() );
+ double number;
+ (void) pNumberFormatter->IsNumberFormat(
+ rContent, nNumberFormat, number );
+ }
+ return nNumberFormat;
+}
+
+void MetaField::SetNumberFormat(sal_uInt32 nNumberFormat)
+{
+ // effectively, the member is only a default:
+ // GetNumberFormat checks if the text actually conforms
+ m_nNumberFormat = nNumberFormat;
+}
+
+
+/*************************************************************************
+ class sw::MetaFieldManager
+ ************************************************************************/
+
+
+MetaFieldManager::MetaFieldManager()
+{
+}
+
+::boost::shared_ptr<MetaField>
+MetaFieldManager::makeMetaField(SwFmtMeta * const i_pFmt,
+ const sal_uInt32 nNumberFormat, const bool bIsFixedLanguage)
+{
+ const ::boost::shared_ptr<MetaField> pMetaField(
+ new MetaField(i_pFmt, nNumberFormat, bIsFixedLanguage) );
+ m_MetaFields.push_back(pMetaField);
+ return pMetaField;
+}
+
+struct IsInUndo
+{
+ bool operator()(::boost::weak_ptr<MetaField> const & pMetaField) {
+ return pMetaField.lock()->IsInUndo();
+ }
+};
+
+struct MakeUnoObject
+{
+ uno::Reference<text::XTextField>
+ operator()(::boost::weak_ptr<MetaField> const & pMetaField) {
+ return uno::Reference<text::XTextField>(
+ pMetaField.lock()->MakeUnoObject(), uno::UNO_QUERY);
+ }
+};
+
+::std::vector< uno::Reference<text::XTextField> >
+MetaFieldManager::getMetaFields()
+{
+ // erase deleted fields
+ const MetaFieldList_t::iterator iter(
+ ::std::remove_if(m_MetaFields.begin(), m_MetaFields.end(),
+ ::boost::bind(&::boost::weak_ptr<MetaField>::expired, _1)));
+ m_MetaFields.erase(iter, m_MetaFields.end());
+ // filter out fields in UNDO
+ MetaFieldList_t filtered(m_MetaFields.size());
+ const MetaFieldList_t::iterator iter2(
+ ::std::remove_copy_if(m_MetaFields.begin(), m_MetaFields.end(),
+ filtered.begin(), IsInUndo()));
+ filtered.erase(iter2, filtered.end());
+ // create uno objects
+ ::std::vector< uno::Reference<text::XTextField> > ret(filtered.size());
+ ::std::transform(filtered.begin(), filtered.end(), ret.begin(),
+ MakeUnoObject());
+ return ret;
+}
+
+} // namespace sw
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx
new file mode 100644
index 000000000000..b866f3b4973e
--- /dev/null
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -0,0 +1,2651 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <vcl/outdev.hxx>
+#include <vcl/print.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/i18n/CharacterIteratorMode.hdl>
+#include <com/sun/star/i18n/WordType.hdl>
+#include <breakit.hxx>
+#include <viewsh.hxx> // Bildschirmabgleich
+#include <viewopt.hxx> // Bildschirmabgleich abschalten, ViewOption
+#include <fntcache.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <swfont.hxx> // CH_BLANK + CH_BULLET
+#include <wrong.hxx>
+#include "dbg_lay.hxx"
+#include <txtfrm.hxx> // SwTxtFrm
+#include <pagefrm.hxx>
+#include <pagedesc.hxx> // SwPageDesc
+#include <tgrditem.hxx>
+#include <scriptinfo.hxx>
+#include <editeng/brshitem.hxx>
+#include <tools/shl.hxx>
+#include <swmodule.hxx>
+#include <accessibilityoptions.hxx>
+#include <svtools/accessibilityoptions.hxx>
+#include <doc.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <docsh.hxx>
+#include <poolfmt.hrc>
+
+using namespace ::com::sun::star;
+
+// globale Variablen, werden in FntCache.Hxx bekanntgegeben
+// Der FontCache wird in TxtInit.Cxx _TXTINIT erzeugt und in _TXTEXIT geloescht
+SwFntCache *pFntCache = NULL;
+// Letzter Font, der durch ChgFntCache eingestellt wurde.
+SwFntObj *pLastFont = NULL;
+// Die "MagicNumber", die den Fonts zur Identifizierung verpasst wird
+sal_uInt8* pMagicNo = NULL;
+
+Color *pWaveCol = 0;
+
+long SwFntObj::nPixWidth;
+MapMode* SwFntObj::pPixMap = NULL;
+OutputDevice* SwFntObj::pPixOut = NULL;
+
+extern sal_uInt16 UnMapDirection( sal_uInt16 nDir, const sal_Bool bVertFormat );
+sal_uInt16 GetDefaultFontHeight( SwDrawTextInfo &rInf )
+{
+ SwDocShell* pDocShell = rInf.GetShell()->GetDoc()->GetDocShell();
+ SfxStyleSheetBasePool* pBasePool = pDocShell->GetStyleSheetPool();
+
+ String aString(SW_RES(STR_POOLCOLL_STANDARD));
+
+ SfxStyleSheetBase* pStyle = pBasePool->Find( aString, (SfxStyleFamily)SFX_STYLE_FAMILY_PARA );
+ SfxItemSet& aTmpSet = pStyle->GetItemSet();
+ SvxFontHeightItem &aDefaultFontItem = (SvxFontHeightItem&)aTmpSet.Get(RES_CHRATR_CJK_FONTSIZE);
+ return (sal_uInt16)aDefaultFontItem.GetHeight();
+}
+
+
+
+/*************************************************************************
+|*
+|* SwFntCache::Flush()
+|*
+|*************************************************************************/
+
+void SwFntCache::Flush( )
+{
+ if ( pLastFont )
+ {
+ pLastFont->Unlock();
+ pLastFont = NULL;
+ }
+ SwCache::Flush( );
+}
+
+/*************************************************************************
+|*
+|* SwFntObj::SwFntObj(), ~SwFntObj()
+|*
+|*************************************************************************/
+
+SwFntObj::SwFntObj( const SwSubFont &rFont, const void *pOwn, ViewShell *pSh ) :
+ SwCacheObj( (void*)pOwn ),
+ aFont( rFont ),
+ pScrFont( NULL ),
+ pPrtFont( &aFont ),
+ pPrinter( NULL ),
+ nPropWidth( rFont.GetPropWidth() )
+{
+ nZoom = pSh ? pSh->GetViewOptions()->GetZoom() : USHRT_MAX;
+ nGuessedLeading = USHRT_MAX;
+ nExtLeading = USHRT_MAX;
+ nPrtAscent = USHRT_MAX;
+ nPrtHeight = USHRT_MAX;
+ bPaintBlank = ( UNDERLINE_NONE != aFont.GetUnderline()
+ || UNDERLINE_NONE != aFont.GetOverline()
+ || STRIKEOUT_NONE != aFont.GetStrikeout() )
+ && !aFont.IsWordLineMode();
+ aFont.SetLanguage(rFont.GetLanguage());
+}
+
+SwFntObj::~SwFntObj()
+{
+ if ( pScrFont != pPrtFont )
+ delete pScrFont;
+ if ( pPrtFont != &aFont )
+ delete pPrtFont;
+}
+
+void SwFntObj::CreatePrtFont( const OutputDevice& rPrt )
+{
+ if ( nPropWidth != 100 && pPrinter != &rPrt )
+ {
+ if( pScrFont != pPrtFont )
+ delete pScrFont;
+ if( pPrtFont != &aFont )
+ delete pPrtFont;
+
+ const Font aOldFnt( rPrt.GetFont() );
+ ((OutputDevice&)rPrt).SetFont( aFont );
+ const FontMetric aWinMet( rPrt.GetFontMetric() );
+ ((OutputDevice&)rPrt).SetFont( aOldFnt );
+ long nWidth = ( aWinMet.GetSize().Width() * nPropWidth ) / 100;
+
+ if( !nWidth )
+ ++nWidth;
+ pPrtFont = new Font( aFont );
+ pPrtFont->SetSize( Size( nWidth, aFont.GetSize().Height() ) );
+ pScrFont = NULL;
+ }
+}
+
+/*************************************************************************
+ *
+ * bool lcl_IsFontAdjustNecessary( rOutDev, rRefDev )
+ *
+ * returns whether we have to adjust the output font to resemble
+ * the formatting font
+ *
+ * _Not_ necessary if
+ *
+ * 1. RefDef == OutDev (text formatting, online layout...)
+ * 2. PDF export from online layout
+ * 3. Prospect/PagePreview pringing
+ *
+ *************************************************************************/
+
+bool lcl_IsFontAdjustNecessary( const OutputDevice& rOutDev,
+ const OutputDevice& rRefDev )
+{
+ return &rRefDev != &rOutDev &&
+ OUTDEV_WINDOW != rRefDev.GetOutDevType() &&
+ ( OUTDEV_PRINTER != rRefDev.GetOutDevType() ||
+ OUTDEV_PRINTER != rOutDev.GetOutDevType() );
+}
+
+struct CalcLinePosData
+{
+ SwDrawTextInfo& rInf;
+ Font& rFont;
+ xub_StrLen nCnt;
+ const sal_Bool bSwitchH2V;
+ const sal_Bool bSwitchL2R;
+ long nHalfSpace;
+ sal_Int32* pKernArray;
+ const sal_Bool bBidiPor;
+
+ CalcLinePosData( SwDrawTextInfo& _rInf, Font& _rFont,
+ xub_StrLen _nCnt, const sal_Bool _bSwitchH2V, const sal_Bool _bSwitchL2R,
+ long _nHalfSpace, sal_Int32* _pKernArray, const sal_Bool _bBidiPor) :
+ rInf( _rInf ),
+ rFont( _rFont ),
+ nCnt( _nCnt ),
+ bSwitchH2V( _bSwitchH2V ),
+ bSwitchL2R( _bSwitchL2R ),
+ nHalfSpace( _nHalfSpace ),
+ pKernArray( _pKernArray ),
+ bBidiPor( _bBidiPor )
+ {
+ }
+};
+
+/** Function: lcl_calcLinePos
+
+ Computes the start and end position of an underline. This function is called
+ from the DrawText-method (for underlining misspelled words or smarttag terms).
+*/
+
+void lcl_calcLinePos( const CalcLinePosData &rData,
+ Point &rStart, Point &rEnd, xub_StrLen nStart, xub_StrLen nWrLen )
+{
+ long nBlank = 0;
+ const xub_StrLen nEnd = nStart + nWrLen;
+ const long nTmpSpaceAdd = rData.rInf.GetSpace() / SPACING_PRECISION_FACTOR;
+
+ if ( nEnd < rData.nCnt
+ && CH_BLANK == rData.rInf.GetText().GetChar( rData.rInf.GetIdx() + nEnd ) )
+ {
+ if( nEnd + 1 == rData.nCnt )
+ nBlank -= nTmpSpaceAdd;
+ else
+ nBlank -= rData.nHalfSpace;
+ }
+
+ // determine start, end and length of wave line
+ sal_Int32 nKernStart = nStart ? rData.pKernArray[ sal_uInt16( nStart - 1 ) ] : 0;
+ sal_Int32 nKernEnd = rData.pKernArray[ sal_uInt16( nEnd - 1 ) ];
+
+ sal_uInt16 nDir = rData.bBidiPor ? 1800 :
+ UnMapDirection( rData.rFont.GetOrientation(), rData.bSwitchH2V );
+
+ switch ( nDir )
+ {
+ case 0 :
+ rStart.X() += nKernStart;
+ rEnd.X() = nBlank + rData.rInf.GetPos().X() + nKernEnd;
+ rEnd.Y() = rData.rInf.GetPos().Y();
+ break;
+ case 900 :
+ rStart.Y() -= nKernStart;
+ rEnd.X() = rData.rInf.GetPos().X();
+ rEnd.Y() = nBlank + rData.rInf.GetPos().Y() - nKernEnd;
+ break;
+ case 1800 :
+ rStart.X() -= nKernStart;
+ rEnd.X() = rData.rInf.GetPos().X() - nKernEnd - nBlank;
+ rEnd.Y() = rData.rInf.GetPos().Y();
+ break;
+ case 2700 :
+ rStart.Y() += nKernStart;
+ rEnd.X() = rData.rInf.GetPos().X();
+ rEnd.Y() = nBlank + rData.rInf.GetPos().Y() + nKernEnd;
+ break;
+ }
+
+ if ( rData.bSwitchL2R )
+ {
+ rData.rInf.GetFrm()->SwitchLTRtoRTL( rStart );
+ rData.rInf.GetFrm()->SwitchLTRtoRTL( rEnd );
+ }
+
+ if ( rData.bSwitchH2V )
+ {
+ rData.rInf.GetFrm()->SwitchHorizontalToVertical( rStart );
+ rData.rInf.GetFrm()->SwitchHorizontalToVertical( rEnd );
+ }
+}
+
+/*************************************************************************
+ *
+ * sal_uInt16 SwFntObj::GetFontAscent( const OutputDevice& rOut )
+ *
+ * Beschreibung: liefern den Ascent des Fonts auf dem
+ * gewuenschten Outputdevice zurueck, ggf. muss der Bildschirmfont erst
+ * erzeugt werden.
+ *************************************************************************/
+
+sal_uInt16 SwFntObj::GetFontAscent( const ViewShell *pSh, const OutputDevice& rOut )
+{
+ sal_uInt16 nRet = 0;
+ const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
+
+ if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
+ {
+ CreateScrFont( *pSh, rOut );
+ OSL_ENSURE( USHRT_MAX != nScrAscent, "nScrAscent is going berzerk" );
+ nRet = nScrAscent;
+ }
+ else
+ {
+ if ( nPrtAscent == USHRT_MAX ) // DruckerAscent noch nicht bekannt?
+ {
+ CreatePrtFont( rOut );
+ const Font aOldFnt( rRefDev.GetFont() );
+ ((OutputDevice&)rRefDev).SetFont( *pPrtFont );
+ const FontMetric aOutMet( rRefDev.GetFontMetric() );
+ nPrtAscent = (sal_uInt16) aOutMet.GetAscent();
+ ( (OutputDevice&)rRefDev).SetFont( aOldFnt );
+ }
+
+ nRet = nPrtAscent;
+ }
+
+#if !defined(MACOSX) // #i89844# extleading is below the line for Mac
+ // TODO: move extleading below the line for all platforms too
+ nRet += GetFontLeading( pSh, rRefDev );
+#endif
+
+ OSL_ENSURE( USHRT_MAX != nRet, "GetFontAscent returned USHRT_MAX" );
+ return nRet;
+}
+
+/*************************************************************************
+ *
+ * sal_uInt16 SwFntObj::GetFontHeight( const OutputDevice* pOut )
+ *
+ * Beschreibung: liefern die H?he des Fonts auf dem
+ * gewuenschten Outputdevice zurueck, ggf. muss der Bildschirmfont erst
+ * erzeugt werden.
+ *************************************************************************/
+
+sal_uInt16 SwFntObj::GetFontHeight( const ViewShell* pSh, const OutputDevice& rOut )
+{
+ sal_uInt16 nRet = 0;
+ const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
+
+ if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
+ {
+ CreateScrFont( *pSh, rOut );
+ OSL_ENSURE( USHRT_MAX != nScrHeight, "nScrHeight is going berzerk" );
+ nRet = nScrHeight + GetFontLeading( pSh, rRefDev );
+ }
+ else
+ {
+ if ( nPrtHeight == USHRT_MAX ) // PrinterHeight noch nicht bekannt?
+ {
+ CreatePrtFont( rOut );
+ const Font aOldFnt( rRefDev.GetFont() );
+ ((OutputDevice&)rRefDev).SetFont( *pPrtFont );
+ nPrtHeight = static_cast<sal_uInt16>(rRefDev.GetTextHeight());
+
+#if OSL_DEBUG_LEVEL > 1
+ // Check if vcl did not change the meading of GetTextHeight
+ const FontMetric aOutMet( rRefDev.GetFontMetric() );
+ long nTmpPrtHeight = (sal_uInt16)aOutMet.GetAscent() + aOutMet.GetDescent();
+ (void) nTmpPrtHeight;
+ // #i106098#: do not compare with == here due to rounding error
+ OSL_ENSURE( abs(nTmpPrtHeight - nPrtHeight) < 3,
+ "GetTextHeight != Ascent + Descent" );
+#endif
+
+ ((OutputDevice&)rRefDev).SetFont( aOldFnt );
+ }
+
+ nRet = nPrtHeight + GetFontLeading( pSh, rRefDev );
+ }
+
+ OSL_ENSURE( USHRT_MAX != nRet, "GetFontHeight returned USHRT_MAX" );
+ return nRet;
+}
+
+sal_uInt16 SwFntObj::GetFontLeading( const ViewShell *pSh, const OutputDevice& rOut )
+{
+ sal_uInt16 nRet = 0;
+
+ if ( pSh )
+ {
+ if ( USHRT_MAX == nGuessedLeading || USHRT_MAX == nExtLeading )
+ {
+ const Font aOldFnt( rOut.GetFont() );
+ ((OutputDevice&)rOut).SetFont( *pPrtFont );
+ const FontMetric aMet( rOut.GetFontMetric() );
+ ((OutputDevice&)rOut).SetFont( aOldFnt );
+ bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
+ GuessLeading( *pSh, aMet );
+ nExtLeading = static_cast<sal_uInt16>(aMet.GetExtLeading());
+ }
+
+ const IDocumentSettingAccess& rIDSA = *pSh->getIDocumentSettingAccess();
+ const bool bBrowse = ( pSh->GetWin() &&
+ pSh->GetViewOptions()->getBrowseMode() &&
+ !pSh->GetViewOptions()->IsPrtFormat() );
+
+ if ( !bBrowse && rIDSA.get(IDocumentSettingAccess::ADD_EXT_LEADING) )
+ nRet = nExtLeading;
+ else
+ nRet = nGuessedLeading;
+ }
+
+ OSL_ENSURE( USHRT_MAX != nRet, "GetFontLeading returned USHRT_MAX" );
+ return nRet;
+}
+
+
+/*************************************************************************
+ *
+ * SwFntObj::CreateScrFont( const ViewShell& rSh, const OutputDevice& rOut )
+ *
+ * pOut is the output device, not the reference device
+ *
+ *************************************************************************/
+
+void SwFntObj::CreateScrFont( const ViewShell& rSh, const OutputDevice& rOut )
+{
+ if ( pScrFont )
+ return;
+
+ // any changes to the output device are reset at the end of the function
+ OutputDevice* pOut = (OutputDevice*)&rOut;
+
+ // Save old font
+ Font aOldOutFont( pOut->GetFont() );
+
+ nScrHeight = USHRT_MAX;
+
+ // Condition for output font / refdev font adjustment
+ OutputDevice* pPrt = &rSh.GetRefDev();
+
+ if( !rSh.GetWin() ||
+ !rSh.GetViewOptions()->getBrowseMode() ||
+ rSh.GetViewOptions()->IsPrtFormat() )
+ {
+ // After CreatePrtFont pPrtFont is the font which is actually used
+ // by the reference device
+ CreatePrtFont( *pPrt );
+ pPrinter = pPrt;
+
+ // save old reference device font
+ Font aOldPrtFnt( pPrt->GetFont() );
+
+ // set the font used at the reference device at the reference device
+ // and the output device
+ pPrt->SetFont( *pPrtFont );
+ pOut->SetFont( *pPrtFont );
+
+ // This should be the default for pScrFont.
+ pScrFont = pPrtFont;
+
+ FontMetric aMet = pPrt->GetFontMetric( );
+ //Don't loose "faked" properties of the logical font that don't truly
+ //exist in the physical font metrics which vcl which fake up for us
+ aMet.SetWeight(pScrFont->GetWeight());
+ aMet.SetItalic(pScrFont->GetItalic());
+
+ bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
+
+ if ( USHRT_MAX == nGuessedLeading )
+ GuessLeading( rSh, aMet );
+
+ if ( USHRT_MAX == nExtLeading )
+ nExtLeading = static_cast<sal_uInt16>(aMet.GetExtLeading());
+
+ // reset the original reference device font
+ pPrt->SetFont( aOldPrtFnt );
+ }
+ else
+ {
+ bSymbol = RTL_TEXTENCODING_SYMBOL == aFont.GetCharSet();
+ if ( nGuessedLeading == USHRT_MAX )
+ nGuessedLeading = 0;
+
+ // no external leading in browse mode
+ if ( nExtLeading == USHRT_MAX )
+ nExtLeading = 0;
+
+ pScrFont = pPrtFont;
+ }
+
+ // Zoomfaktor ueberpruefen, z.B. wg. PrtOle2 beim Speichern
+ {
+ // Sollte der Zoomfaktor des OutputDevices nicht mit dem der View-
+ // Options uebereinstimmen, so darf dieser Font nicht gecacht
+ // werden, deshalb wird der Zoomfaktor auf einen "ungueltigen" Wert
+ // gesetzt.
+ long nTmp;
+ if( pOut->GetMapMode().GetScaleX().IsValid() &&
+ pOut->GetMapMode().GetScaleY().IsValid() &&
+ pOut->GetMapMode().GetScaleX() == pOut->GetMapMode().GetScaleY() )
+ {
+ nTmp = ( 100 * pOut->GetMapMode().GetScaleX().GetNumerator() ) /
+ pOut->GetMapMode().GetScaleX().GetDenominator();
+ }
+ else
+ nTmp = 0;
+ if( nTmp != nZoom )
+ nZoom = USHRT_MAX - 1;
+ }
+
+ nScrAscent = (sal_uInt16)pOut->GetFontMetric().GetAscent();
+ if ( USHRT_MAX == nScrHeight )
+ nScrHeight = (sal_uInt16)pOut->GetTextHeight();
+
+ // reset original output device font
+ pOut->SetFont( aOldOutFont );
+}
+
+
+void SwFntObj::GuessLeading( const ViewShell&
+#if defined(WNT) || defined(PM2)
+ rSh
+#endif
+ , const FontMetric& rMet )
+{
+ // If leading >= 5, this seems to be enough leading.
+ // Nothing has to be done.
+ if ( rMet.GetIntLeading() >= 5 )
+ {
+ nGuessedLeading = 0;
+ return;
+ }
+
+#if defined(WNT) || defined(PM2)
+ OutputDevice *pWin = rSh.GetWin() ?
+ rSh.GetWin() :
+ GetpApp()->GetDefaultDevice();
+ if ( pWin )
+ {
+ MapMode aTmpMap( MAP_TWIP );
+ MapMode aOldMap = pWin->GetMapMode( );
+ pWin->SetMapMode( aTmpMap );
+ const Font aOldFnt( pWin->GetFont() );
+ pWin->SetFont( *pPrtFont );
+ const FontMetric aWinMet( pWin->GetFontMetric() );
+ const sal_uInt16 nWinHeight = sal_uInt16( aWinMet.GetSize().Height() );
+ if( pPrtFont->GetName().Search( aWinMet.GetName() ) < USHRT_MAX )
+ {
+ // Wenn das Leading auf dem Window auch 0 ist, dann
+ // muss es auch so bleiben (vgl. StarMath!).
+ long nTmpLeading = (long)aWinMet.GetIntLeading();
+ // einen Versuch haben wir noch wg. 31003:
+ if( nTmpLeading <= 0 )
+ {
+ pWin->SetFont( rMet );
+ nTmpLeading = (long)pWin->GetFontMetric().GetIntLeading();
+ if( nTmpLeading < 0 )
+ nGuessedLeading = 0;
+ else
+ nGuessedLeading = sal_uInt16(nTmpLeading);
+ }
+ else
+ {
+ nGuessedLeading = sal_uInt16(nTmpLeading);
+ // Manta-Hack #50153#:
+ // Wer beim Leading luegt, luegt moeglicherweise auch beim
+ // Ascent/Descent, deshalb wird hier ggf. der Font ein wenig
+ // tiefergelegt, ohne dabei seine Hoehe zu aendern.
+ long nDiff = Min( rMet.GetDescent() - aWinMet.GetDescent(),
+ aWinMet.GetAscent() - rMet.GetAscent() - nTmpLeading );
+ if( nDiff > 0 )
+ {
+ OSL_ENSURE( nPrtAscent < USHRT_MAX, "GuessLeading: PrtAscent-Fault" );
+ if ( nPrtAscent < USHRT_MAX )
+ nPrtAscent = nPrtAscent + (sal_uInt16)(( 2 * nDiff ) / 5);
+ }
+ }
+ }
+ else
+ {
+ // Wenn alle Stricke reissen, nehmen wir 15% der
+ // Hoehe, ein von CL empirisch ermittelter Wert.
+ nGuessedLeading = (nWinHeight * 15) / 100;
+ }
+ pWin->SetFont( aOldFnt );
+ pWin->SetMapMode( aOldMap );
+ }
+ else
+#endif
+ nGuessedLeading = 0;
+}
+
+/*************************************************************************
+ *
+ * void SwFntObj::SetDeviceFont( const OutputDevice *pOut ),
+ *
+ * Beschreibung: stellt den Font am gewuenschten OutputDevice ein,
+ * am Bildschirm muss eventuell erst den Abgleich durchgefuehrt werden.
+ *
+ *************************************************************************/
+
+void SwFntObj::SetDevFont( const ViewShell *pSh, OutputDevice& rOut )
+{
+ const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
+
+ if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
+ {
+ CreateScrFont( *pSh, rOut );
+ if( !GetScrFont()->IsSameInstance( rOut.GetFont() ) )
+ rOut.SetFont( *pScrFont );
+ if( pPrinter && ( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) )
+ pPrinter->SetFont( *pPrtFont );
+ }
+ else
+ {
+ CreatePrtFont( rOut );
+ if( !pPrtFont->IsSameInstance( rOut.GetFont() ) )
+ rOut.SetFont( *pPrtFont );
+ }
+
+ // Here, we actually do not need the leading values, but by calling
+ // GetFontLeading() we assure that the values are calculated for later use.
+ GetFontLeading( pSh, rRefDev );
+}
+
+#define WRONG_SHOW_MIN 5
+#define WRONG_SHOW_SMALL 11
+#define WRONG_SHOW_MEDIUM 15
+
+/*************************************************************************
+ *
+ * void SwFntObj::DrawText( ... )
+ *
+ * Beschreibung: Textausgabe
+ * auf dem Bildschirm => DrawTextArray
+ * auf dem Drucker, !Kerning => DrawText
+ * auf dem Drucker + Kerning => DrawStretchText
+ *
+ *************************************************************************/
+
+sal_uInt8 lcl_WhichPunctuation( xub_Unicode cChar )
+{
+ if ( ( cChar < 0x3001 || cChar > 0x3002 ) &&
+ ( cChar < 0x3008 || cChar > 0x3011 ) &&
+ ( cChar < 0x3014 || cChar > 0x301F ) &&
+ 0xFF62 != cChar && 0xFF63 != cChar )
+ // no punctuation
+ return SwScriptInfo::NONE;
+ else if ( 0x3001 == cChar || 0x3002 == cChar ||
+ 0x3009 == cChar || 0x300B == cChar ||
+ 0x300D == cChar || 0x300F == cChar ||
+ 0x3011 == cChar || 0x3015 == cChar ||
+ 0x3017 == cChar || 0x3019 == cChar ||
+ 0x301B == cChar || 0x301E == cChar ||
+ 0x301F == cChar || 0xFF63 == cChar )
+ // right punctuation
+ return SwScriptInfo::SPECIAL_RIGHT;
+
+ return SwScriptInfo::SPECIAL_LEFT;
+}
+
+static sal_Bool lcl_IsMonoSpaceFont( const OutputDevice& rOut )
+{
+ const String aStr1( xub_Unicode( 0x3008 ) );
+ const String aStr2( xub_Unicode( 0x307C ) );
+ const long nWidth1 = rOut.GetTextWidth( aStr1 );
+ const long nWidth2 = rOut.GetTextWidth( aStr2 );
+ return nWidth1 == nWidth2;
+}
+
+// ER 09.07.95 20:34
+// mit -Ox Optimierung stuerzt's unter win95 ab
+// JP 12.07.95: unter WNT auch (i386); Alpha ??
+// global optimization off
+#ifdef _MSC_VER
+#pragma optimize("g",off)
+#endif
+
+/* This helper structure (SwForbidden) contains the already marked parts of the string
+ to avoid double lines (e.g grammar + spell check error) */
+
+typedef std::vector< std::pair< xub_StrLen, xub_StrLen > > SwForbidden;
+
+static void lcl_DrawLineForWrongListData(
+ SwForbidden &rForbidden,
+ const SwDrawTextInfo &rInf,
+ const SwWrongList *pWList,
+ const CalcLinePosData &rCalcLinePosData,
+ const Size &rPrtFontSize )
+{
+ if (!pWList)
+ return;
+
+ xub_StrLen nStart = rInf.GetIdx();
+ xub_StrLen nWrLen = rInf.GetLen();
+
+ // check if respective data is available in the current text range
+ if (pWList->Check( nStart, nWrLen ))
+ {
+ // get line color to use...
+ Color aLineColor;
+ if (pWList == rInf.GetWrong()) // ... for spell checking
+ aLineColor = SwViewOption::GetSpellColor();
+ else if (pWList == rInf.GetGrammarCheck()) // ... for grammar checking
+ // currently there is no specific color for grammar check errors available in the configuration
+ aLineColor = Color( COL_LIGHTBLUE );
+ else if (pWList == rInf.GetSmartTags()) // ... for smart tags
+ aLineColor = SwViewOption::GetSmarttagColor();
+
+ long nHght = rInf.GetOut().LogicToPixel( rPrtFontSize ).Height();
+
+ // Draw wavy lines for spell and grammar errors only if font is large enough.
+ // Lines for smart tags will always be drawn.
+ if (pWList == rInf.GetSmartTags() || WRONG_SHOW_MIN < nHght)
+ {
+ SwForbidden::iterator pIter = rForbidden.begin();
+ if (rInf.GetOut().GetConnectMetaFile())
+ rInf.GetOut().Push();
+
+ const Color aCol( rInf.GetOut().GetLineColor() );
+ const sal_Bool bColSave = aCol != aLineColor;
+ if (bColSave)
+ rInf.GetOut().SetLineColor( aLineColor );
+
+ // iterate over all ranges stored in the respective SwWrongList
+ do
+ {
+ nStart = nStart - rInf.GetIdx();
+
+ const xub_StrLen nEnd = nStart + nWrLen;
+ xub_StrLen nNext = nStart;
+ while( nNext < nEnd )
+ {
+ while( pIter != rForbidden.end() && pIter->second <= nNext )
+ ++pIter;
+ xub_StrLen nNextStart = nNext;
+ xub_StrLen nNextEnd = nEnd;
+ if( pIter == rForbidden.end() || nNextEnd <= pIter->first )
+ {
+ // No overlapping mark up found
+ std::pair< xub_StrLen, xub_StrLen > aNew;
+ aNew.first = nNextStart;
+ aNew.second = nNextEnd;
+ rForbidden.insert( pIter, aNew );
+ pIter = rForbidden.begin();
+ nNext = nEnd;
+ }
+ else
+ {
+ nNext = pIter->second;
+ if( nNextStart < pIter->first )
+ {
+ nNextEnd = pIter->first;
+ pIter->first = nNextStart;
+ }
+ else
+ continue;
+ }
+ // determine line pos
+ Point aStart( rInf.GetPos() );
+ Point aEnd;
+ lcl_calcLinePos( rCalcLinePosData, aStart, aEnd, nNextStart, nNextEnd - nNextStart );
+
+ // draw line for smart tags?
+ if (pWList == rInf.GetSmartTags())
+ {
+ aStart.Y() +=30;
+ aEnd.Y() +=30;
+
+ LineInfo aLineInfo( LINE_DASH );
+ aLineInfo.SetDistance( 40 );
+ aLineInfo.SetDashLen( 1 );
+ aLineInfo.SetDashCount(1);
+
+ rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo );
+ }
+ else // draw wavy lines for spell or grammar errors
+ {
+ // get wavy line type to use
+ sal_uInt16 nWave =
+ WRONG_SHOW_MEDIUM < nHght ? WAVE_NORMAL :
+ ( WRONG_SHOW_SMALL < nHght ? WAVE_SMALL : WAVE_FLAT );
+
+ rInf.GetOut().DrawWaveLine( aStart, aEnd, nWave );
+ }
+ }
+
+ nStart = nEnd + rInf.GetIdx();
+ nWrLen = rInf.GetIdx() + rInf.GetLen() - nStart;
+ }
+ while (nWrLen && pWList->Check( nStart, nWrLen ));
+
+ if (bColSave)
+ rInf.GetOut().SetLineColor( aCol );
+
+ if (rInf.GetOut().GetConnectMetaFile())
+ rInf.GetOut().Pop();
+ }
+ }
+}
+
+
+void SwFntObj::DrawText( SwDrawTextInfo &rInf )
+{
+ OSL_ENSURE( rInf.GetShell(), "SwFntObj::DrawText without shell" );
+
+ OutputDevice& rRefDev = rInf.GetShell()->GetRefDev();
+ OutputDevice* pWin = rInf.GetShell()->GetWin();
+
+ // true if pOut is the printer and the printer has been used for formatting
+ const sal_Bool bPrt = OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() &&
+ OUTDEV_PRINTER == rRefDev.GetOutDevType();
+ const sal_Bool bBrowse = ( pWin &&
+ rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
+ !rInf.GetShell()->GetViewOptions()->IsPrtFormat() &&
+ !rInf.GetBullet() &&
+ ( rInf.GetSpace() || !rInf.GetKern() ) &&
+ !rInf.GetWrong() &&
+ !rInf.GetGrammarCheck() &&
+ !rInf.GetSmartTags() &&
+ !rInf.GetGreyWave() );
+
+ // bDirectPrint indicates that we can enter the branch which calls
+ // the DrawText functions instead of calling the DrawTextArray functions
+ const sal_Bool bDirectPrint = bPrt || bBrowse;
+
+ // Condition for output font / refdev font adjustment
+ const sal_Bool bUseScrFont =
+ lcl_IsFontAdjustNecessary( rInf.GetOut(), rRefDev );
+
+ Font* pTmpFont = bUseScrFont ? pScrFont : pPrtFont;
+
+ //
+ // bDirectPrint and bUseScrFont should have these values:
+ //
+ // Outdev / RefDef | Printer | VirtPrinter | Window
+ // ----------------------------------------------------
+ // Printer | 1 - 0 | 0 - 1 | -
+ // ----------------------------------------------------
+ // VirtPrinter/PDF | 0 - 1 | 0 - 1 | -
+ // ----------------------------------------------------
+ // Window/VirtWindow| 0 - 1 | 0 - 1 | 1 - 0
+ //
+ // Exception: During painting of a Writer OLE object, we do not have
+ // a window. Therefore bUseSrcFont is always 0 in this case.
+ //
+
+#if OSL_DEBUG_LEVEL > 1
+
+ const sal_Bool bNoAdjust = bPrt ||
+ ( pWin &&
+ rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
+ !rInf.GetShell()->GetViewOptions()->IsPrtFormat() );
+
+ if ( OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() )
+ {
+ // Printer output
+ if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
+ {
+ OSL_ENSURE( bNoAdjust == 1 && bUseScrFont == 0, "Outdev Check failed" );
+ }
+ else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() )
+ {
+ OSL_ENSURE( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" );
+ }
+ else
+ {
+ OSL_FAIL( "Outdev Check failed" );
+ }
+ }
+ else if ( OUTDEV_VIRDEV == rInf.GetOut().GetOutDevType() && ! pWin )
+ {
+ // PDF export
+ if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
+ {
+ OSL_ENSURE( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" );
+ }
+ else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() )
+ {
+ OSL_ENSURE( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" );
+ }
+ else
+ {
+ OSL_FAIL( "Outdev Check failed" );
+ }
+ }
+ else if ( OUTDEV_WINDOW == rInf.GetOut().GetOutDevType() ||
+ ( OUTDEV_VIRDEV == rInf.GetOut().GetOutDevType() && pWin ) )
+ {
+ // Window or virtual window
+ if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
+ {
+ OSL_ENSURE( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" );
+ }
+ else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() )
+ {
+ OSL_ENSURE( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" );
+ }
+ else if ( OUTDEV_WINDOW == rRefDev.GetOutDevType() )
+ {
+ OSL_ENSURE( bNoAdjust == 1 && bUseScrFont == 0, "Outdev Check failed" );
+ }
+ else
+ {
+ OSL_FAIL( "Outdev Check failed" );
+ }
+ }
+ else
+ {
+ OSL_FAIL( "Outdev Check failed" );
+ }
+
+#endif
+
+ // robust: better use the printer font instead of using no font at all
+ OSL_ENSURE( pTmpFont, "No screen or printer font?" );
+ if ( ! pTmpFont )
+ pTmpFont = pPrtFont;
+
+ // HACK: UNDERLINE_WAVE darf nicht mehr missbraucht werden, daher
+ // wird die graue Wellenlinie des ExtendedAttributSets zunaechst
+ // in der Fontfarbe erscheinen.
+
+ const sal_Bool bSwitchH2V = rInf.GetFrm() && rInf.GetFrm()->IsVertical();
+ const sal_Bool bSwitchL2R = rInf.GetFrm() && rInf.GetFrm()->IsRightToLeft() &&
+ ! rInf.IsIgnoreFrmRTL();
+ const sal_uLong nMode = rInf.GetOut().GetLayoutMode();
+ const sal_Bool bBidiPor = ( bSwitchL2R !=
+ ( 0 != ( TEXT_LAYOUT_BIDI_RTL & nMode ) ) );
+
+ // be sure to have the correct layout mode at the printer
+ if ( pPrinter )
+ {
+ pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
+ pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
+ }
+
+ Point aPos( rInf.GetPos() );
+ if( !bPrt )
+ {
+ if( rInf.GetpOut() != pPixOut || rInf.GetOut().GetMapMode() != *pPixMap )
+ {
+ *pPixMap = rInf.GetOut().GetMapMode();
+ pPixOut = rInf.GetpOut();
+ Size aTmp( 1, 1 );
+ nPixWidth = rInf.GetOut().PixelToLogic( aTmp ).Width();
+ }
+
+ aPos.X() += rInf.GetFrm()->IsRightToLeft() ? 0 : nPixWidth;
+ }
+
+ Color aOldColor( pTmpFont->GetColor() );
+ sal_Bool bChgColor = rInf.ApplyAutoColor( pTmpFont );
+ if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
+ rInf.GetOut().SetFont( *pTmpFont );
+ if ( bChgColor )
+ pTmpFont->SetColor( aOldColor );
+
+ if ( STRING_LEN == rInf.GetLen() )
+ rInf.SetLen( rInf.GetText().Len() );
+
+
+ //
+ // ASIAN LINE AND CHARACTER GRID MODE START: snap to characters
+ //
+
+ if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() &&
+ SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ GETGRID( rInf.GetFrm()->FindPageFrm() )
+ if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars())
+ {
+ //for textgrid refactor
+ //const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
+ const SwDoc* pDoc = rInf.GetShell()->GetDoc();
+ const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc);
+ sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()];
+
+ if ( pPrinter )
+ pPrinter->GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+ else
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+
+ long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
+
+ const sal_uLong i = nWidthPerChar ?
+ ( nWidthPerChar - 1 ) / nGridWidth + 1:
+ 1;
+
+ nWidthPerChar = i * nGridWidth;
+
+ // position of first character, we take the printer position
+ long nCharWidth = pKernArray[ 0 ];
+ sal_uLong nHalfWidth = nWidthPerChar / 2;
+
+ long nNextFix;
+
+ // punctuation characters are not centered
+ xub_Unicode cChar = rInf.GetText().GetChar( rInf.GetIdx() );
+ sal_uInt8 nType = lcl_WhichPunctuation( cChar );
+ switch ( nType )
+ {
+ case SwScriptInfo::NONE :
+ aPos.X() += ( nWidthPerChar - nCharWidth ) / 2;
+ nNextFix = nCharWidth / 2;
+ break;
+ case SwScriptInfo::SPECIAL_RIGHT :
+ nNextFix = nHalfWidth;
+ break;
+ default:
+ aPos.X() += nWidthPerChar - nCharWidth;
+ nNextFix = nCharWidth - nHalfWidth;
+ }
+
+ // calculate offsets
+ for ( xub_StrLen j = 1; j < rInf.GetLen(); ++j )
+ {
+ long nScr = pKernArray[ j ] - pKernArray[ j - 1 ];
+ nNextFix += nWidthPerChar;
+
+ // punctuation characters are not centered
+ cChar = rInf.GetText().GetChar( rInf.GetIdx() + j );
+ nType = lcl_WhichPunctuation( cChar );
+ switch ( nType )
+ {
+ case SwScriptInfo::NONE :
+ pKernArray[ j - 1 ] = nNextFix - ( nScr / 2 );
+ break;
+ case SwScriptInfo::SPECIAL_RIGHT :
+ pKernArray[ j - 1 ] = nNextFix - nHalfWidth;
+ break;
+ default:
+ pKernArray[ j - 1 ] = nNextFix + nHalfWidth - nScr;
+ }
+ }
+
+ // the layout engine requires the total width of the output
+ pKernArray[ rInf.GetLen() - 1 ] = rInf.GetWidth() -
+ aPos.X() + rInf.GetPos().X() ;
+
+ if ( bSwitchH2V )
+ rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
+
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), rInf.GetLen() );
+
+ delete[] pKernArray;
+ return;
+ }
+ }
+
+ // For text grid refactor
+ // ASIAN LINE AND CHARACTER GRID MODE START: not snap to characters
+ //
+ if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() &&
+ SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ GETGRID( rInf.GetFrm()->FindPageFrm() )
+
+ if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
+ {
+ const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf );
+
+ const SwDoc* pDoc = rInf.GetShell()->GetDoc();
+ long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc);
+ if( SW_LATIN == rInf.GetFont()->GetActual() )
+ nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2;
+ else
+ nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight;
+
+ sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()];
+
+ if ( pPrinter )
+ pPrinter->GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+ else
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+ if ( bSwitchH2V )
+ rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
+ if ( rInf.GetSpace() || rInf.GetKanaComp())
+ {
+ long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
+ sal_Bool bSpecialJust = sal_False;
+ if ( rInf.GetFont() && rInf.GetLen() )
+ {
+ const SwScriptInfo* pSI = rInf.GetScriptInfo();
+ const sal_uInt8 nActual = rInf.GetFont()->GetActual();
+ ///Kana Compression
+ if( SW_CJK == nActual && rInf.GetKanaComp() &&
+ pSI && pSI->CountCompChg() &&
+ lcl_IsMonoSpaceFont( *(rInf.GetpOut()) ) )
+ {
+ pSI->Compress( pKernArray,rInf.GetIdx(), rInf.GetLen(),
+ rInf.GetKanaComp(), (sal_uInt16)aFont.GetSize().Height(),&aPos );
+ bSpecialJust = sal_True;
+ }
+ ///Asian Justification
+ if ( ( SW_CJK == nActual || SW_LATIN == nActual ) && nSpaceAdd )
+ {
+ LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
+ if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang)
+ {
+ long nSpaceSum = nSpaceAdd;
+ for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI )
+ {
+ pKernArray[ nI ] += nSpaceSum;
+ nSpaceSum += nSpaceAdd;
+ }
+ bSpecialJust = sal_True;
+ nSpaceAdd = 0;
+ }
+ }
+ long nGridAddSum = nGridWidthAdd;
+ for(xub_StrLen i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd )
+ {
+ pKernArray[i] += nGridAddSum;
+ }
+ long nKernSum = rInf.GetKern();
+ if ( bSpecialJust || rInf.GetKern() )
+ {
+ for( xub_StrLen i = 0; i < rInf.GetLen(); i++, nKernSum += rInf.GetKern() )
+ {
+ if ( CH_BLANK == rInf.GetText().GetChar(rInf.GetIdx()+i) )
+ nKernSum += nSpaceAdd;
+ pKernArray[i] += nKernSum;
+ }
+ ///With through/uderstr. Grouped style requires a blank at the end
+ ///of a text edition special measures:
+ if( bPaintBlank && rInf.GetLen() && (CH_BLANK ==
+ rInf.GetText().GetChar( rInf.GetIdx() + rInf.GetLen() - 1) ) )
+ {
+ ///If it concerns a singular, underlined space acts,
+ ///we must spend two:
+ if( 1 == rInf.GetLen() )
+ {
+ pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), 1 );
+ }
+ else
+ {
+ pKernArray[ rInf.GetLen() - 2] += nSpaceAdd;
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), rInf.GetLen() );
+ }
+ }
+ else
+ {
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), rInf.GetLen() );
+ }
+ }
+ else
+ {
+ Point aTmpPos( aPos );
+ xub_StrLen i;
+ xub_StrLen j = 0;
+ long nSpaceSum = 0;
+ for( i = 0; i < rInf.GetLen(); i++ )
+ {
+ if( CH_BLANK == rInf.GetText().GetChar( rInf.GetIdx() + i) )
+ {
+ nSpaceSum += nSpaceAdd;
+ if( j < i)
+ rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
+ rInf.GetIdx() + j, i - j );
+ j = i + 1;
+ pKernArray[i] = pKernArray[i] + nSpaceSum;
+ aTmpPos.X() = aPos.X() + pKernArray[ i ] + nKernSum;
+ }
+ }
+ if( j < i )
+ rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
+ rInf.GetIdx() +j , i - j );
+ }
+ }
+ }
+ else
+ {
+ //long nKernAdd = rInf.GetKern();
+ long nKernAdd = 0;
+ long nGridAddSum = nGridWidthAdd + nKernAdd;
+ for(xub_StrLen i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd + nKernAdd )
+ {
+ pKernArray[i] += nGridAddSum;
+ }
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), rInf.GetLen() );
+ }
+ delete[] pKernArray;
+ return;
+ }
+ }
+
+ //
+ // DIRECT PAINTING WITHOUT SCREEN ADJUSTMENT
+ //
+
+ if ( bDirectPrint )
+ {
+ const Fraction aTmp( 1, 1 );
+ sal_Bool bStretch = rInf.GetWidth() && ( rInf.GetLen() > 1 ) && bPrt
+ && ( aTmp != rInf.GetOut().GetMapMode().GetScaleX() );
+
+ if ( bSwitchL2R )
+ rInf.GetFrm()->SwitchLTRtoRTL( aPos );
+
+ if ( bSwitchH2V )
+ rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
+
+ // In the good old days we used to have a simple DrawText if the
+ // output device is the printer. Now we need a DrawTextArray if
+ // 1. KanaCompression is enabled
+ // 2. Justified alignment
+ // Simple kerning is handled by DrawStretchText
+ if( rInf.GetSpace() || rInf.GetKanaComp() )
+ {
+ sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ];
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+
+ if( bStretch )
+ {
+ xub_StrLen nZwi = rInf.GetLen() - 1;
+ long nDiff = rInf.GetWidth() - pKernArray[ nZwi ]
+ - rInf.GetLen() * rInf.GetKern();
+ long nRest = nDiff % nZwi;
+ long nAdd;
+ if( nRest < 0 )
+ {
+ nAdd = -1;
+ nRest += nZwi;
+ }
+ else
+ {
+ nAdd = +1;
+ nRest = nZwi - nRest;
+ }
+ nDiff /= nZwi;
+ long nSum = nDiff;
+ for( xub_StrLen i = 0; i < nZwi; )
+ {
+ pKernArray[ i ] += nSum;
+ if( ++i == nRest )
+ nDiff += nAdd;
+ nSum += nDiff;
+ }
+ }
+
+ //
+ // Modify Array for special justifications
+ //
+ long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
+ sal_Bool bSpecialJust = sal_False;
+
+ if ( rInf.GetFont() && rInf.GetLen() )
+ {
+ const SwScriptInfo* pSI = rInf.GetScriptInfo();
+ const sal_uInt8 nActual = rInf.GetFont()->GetActual();
+
+ // Kana Compression
+ if ( SW_CJK == nActual && rInf.GetKanaComp() &&
+ pSI && pSI->CountCompChg() &&
+ lcl_IsMonoSpaceFont( rInf.GetOut() ) )
+ {
+ pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
+ rInf.GetKanaComp(),
+ (sal_uInt16)aFont.GetSize().Height(), &aPos );
+ bSpecialJust = sal_True;
+ }
+
+ // Asian Justification
+ if ( SW_CJK == nActual && nSpaceAdd )
+ {
+ LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
+
+ if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang )
+ {
+ long nSpaceSum = nSpaceAdd;
+ for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI )
+ {
+ pKernArray[ nI ] += nSpaceSum;
+ nSpaceSum += nSpaceAdd;
+ }
+
+ bSpecialJust = sal_True;
+ nSpaceAdd = 0;
+ }
+ }
+
+ // Kashida Justification
+ if ( SW_CTL == nActual && nSpaceAdd )
+ {
+ if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
+ {
+ if ( pSI && pSI->CountKashida() &&
+ pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(),
+ rInf.GetLen(), nSpaceAdd ) != STRING_LEN )
+ {
+ bSpecialJust = sal_True;
+ nSpaceAdd = 0;
+ }
+ }
+ }
+
+ // Thai Justification
+ if ( SW_CTL == nActual && nSpaceAdd )
+ {
+ LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
+
+ if ( LANGUAGE_THAI == aLang )
+ {
+ // Use rInf.GetSpace() because it has more precision than
+ // nSpaceAdd:
+ SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0,
+ rInf.GetIdx(), rInf.GetLen(),
+ rInf.GetNumberOfBlanks(),
+ rInf.GetSpace() );
+
+ // adding space to blanks is already done
+ bSpecialJust = sal_True;
+ nSpaceAdd = 0;
+ }
+ }
+ }
+
+ long nKernSum = rInf.GetKern();
+
+ if ( bStretch || bPaintBlank || rInf.GetKern() || bSpecialJust )
+ {
+ for( xub_StrLen i = 0; i < rInf.GetLen(); i++,
+ nKernSum += rInf.GetKern() )
+ {
+ if ( CH_BLANK == rInf.GetText().GetChar(rInf.GetIdx()+i) )
+ nKernSum += nSpaceAdd;
+ pKernArray[i] += nKernSum;
+ }
+
+ // Bei durch/unterstr. Blocksatz erfordert ein Blank am Ende
+ // einer Textausgabe besondere Massnahmen:
+ if( bPaintBlank && rInf.GetLen() && ( CH_BLANK ==
+ rInf.GetText().GetChar( rInf.GetIdx()+rInf.GetLen()-1 ) ) )
+ {
+ // Wenn es sich um ein singulaeres, unterstrichenes Space
+ // handelt, muessen wir zwei ausgeben:
+ if( 1 == rInf.GetLen() )
+ {
+ pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
+
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), 1 );
+ }
+ else
+ {
+ pKernArray[ rInf.GetLen() - 2 ] += nSpaceAdd;
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), rInf.GetLen() );
+ }
+ }
+ else
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), rInf.GetLen() );
+ }
+ else
+ {
+ Point aTmpPos( aPos );
+ xub_StrLen j = 0;
+ xub_StrLen i;
+ for( i = 0; i < rInf.GetLen(); i++ )
+ {
+ if( CH_BLANK == rInf.GetText().GetChar( rInf.GetIdx()+i ) )
+ {
+ nKernSum += nSpaceAdd;
+ if( j < i )
+ rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
+ rInf.GetIdx() + j, i - j );
+ j = i + 1;
+ SwTwips nAdd = pKernArray[ i ] + nKernSum;
+ if ( ( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL ) == nMode )
+ nAdd *= -1;
+ aTmpPos.X() = aPos.X() + nAdd;
+ }
+ }
+ if( j < i )
+ rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
+ rInf.GetIdx() + j, i - j );
+ }
+ delete[] pKernArray;
+ }
+ else if( bStretch )
+ {
+ long nTmpWidth = rInf.GetWidth();
+ if( rInf.GetKern() && rInf.GetLen() && nTmpWidth > rInf.GetKern() )
+ nTmpWidth -= rInf.GetKern();
+ rInf.GetOut().DrawStretchText( aPos, nTmpWidth,
+ rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
+ }
+ else if( rInf.GetKern() )
+ {
+ const long nTmpWidth = GetTextSize( rInf ).Width();
+
+ const Color aSaveColor( pTmpFont->GetColor() );
+ const sal_Bool bColorChanged = rInf.ApplyAutoColor( pTmpFont );
+
+ if( bColorChanged )
+ {
+ if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
+ rInf.GetOut().SetFont( *pTmpFont );
+ pTmpFont->SetColor( aSaveColor );
+ }
+
+ rInf.GetOut().DrawStretchText( aPos, (sal_uInt16)nTmpWidth,
+ rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
+ }
+ else
+ rInf.GetOut().DrawText( aPos, rInf.GetText(),
+ rInf.GetIdx(), rInf.GetLen() );
+ }
+
+ //
+ // PAINTING WITH FORMATTING DEVICE/SCREEN ADJUSTMENT
+ //
+
+ else
+ {
+ const String* pStr = &rInf.GetText();
+ String aStr( aEmptyStr );
+ sal_Bool bBullet = rInf.GetBullet();
+ if( bSymbol )
+ bBullet = sal_False;
+ sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ];
+ CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
+ long nScrPos;
+
+ // get screen array
+ sal_Int32* pScrArray = new sal_Int32[ rInf.GetLen() ];
+ rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray,
+ rInf.GetIdx(), rInf.GetLen() );
+
+ // OLE: no printer available
+ // OSL_ENSURE( pPrinter, "DrawText needs pPrinter" )
+ if ( pPrinter )
+ {
+ // pTmpFont has already been set as current font for rInf.GetOut()
+ if ( pPrinter != rInf.GetpOut() || pTmpFont != pPrtFont )
+ {
+ if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
+ pPrinter->SetFont( *pPrtFont );
+ }
+ pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(),
+ rInf.GetLen() );
+ }
+ else
+ {
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+ }
+
+ //
+ // Modify Printer and ScreenArrays for special justifications
+ //
+ long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
+ bool bNoHalfSpace = false;
+
+ if ( rInf.GetFont() && rInf.GetLen() )
+ {
+ const sal_uInt8 nActual = rInf.GetFont()->GetActual();
+ const SwScriptInfo* pSI = rInf.GetScriptInfo();
+
+ // Kana Compression
+ if ( SW_CJK == nActual && rInf.GetKanaComp() &&
+ pSI && pSI->CountCompChg() &&
+ lcl_IsMonoSpaceFont( rInf.GetOut() ) )
+ {
+ Point aTmpPos( aPos );
+ pSI->Compress( pScrArray, rInf.GetIdx(), rInf.GetLen(),
+ rInf.GetKanaComp(),
+ (sal_uInt16)aFont.GetSize().Height(), &aTmpPos );
+ pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
+ rInf.GetKanaComp(),
+ (sal_uInt16)aFont.GetSize().Height(), &aPos );
+ }
+
+ // Asian Justification
+ if ( SW_CJK == nActual && nSpaceAdd )
+ {
+ LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
+
+ if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang )
+ {
+ long nSpaceSum = nSpaceAdd;
+ for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI )
+ {
+ pKernArray[ nI ] += nSpaceSum;
+ pScrArray[ nI ] += nSpaceSum;
+ nSpaceSum += nSpaceAdd;
+ }
+
+ nSpaceAdd = 0;
+ }
+ }
+
+ // Kashida Justification
+ if ( SW_CTL == nActual && nSpaceAdd )
+ {
+ if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
+ {
+ if ( pSI && pSI->CountKashida() &&
+ pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(),
+ rInf.GetLen(), nSpaceAdd ) != STRING_LEN )
+ nSpaceAdd = 0;
+ else
+ bNoHalfSpace = true;
+ }
+ }
+
+ // Thai Justification
+ if ( SW_CTL == nActual && nSpaceAdd )
+ {
+ LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
+
+ if ( LANGUAGE_THAI == aLang )
+ {
+ SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray,
+ pScrArray, rInf.GetIdx(),
+ rInf.GetLen(),
+ rInf.GetNumberOfBlanks(),
+ rInf.GetSpace() );
+
+ // adding space to blanks is already done
+ nSpaceAdd = 0;
+ }
+ }
+ }
+
+ nScrPos = pScrArray[ 0 ];
+
+ if( bBullet )
+ {
+ // !!! HACK !!!
+ // The Arabic layout engine requires some context of the string
+ // which should be painted.
+ xub_StrLen nCopyStart = rInf.GetIdx();
+ if ( nCopyStart )
+ --nCopyStart;
+
+ xub_StrLen nCopyLen = rInf.GetLen();
+ if ( nCopyStart + nCopyLen < rInf.GetText().Len() )
+ ++nCopyLen;
+
+ aStr = rInf.GetText().Copy( nCopyStart, nCopyLen );
+ pStr = &aStr;
+
+ for( xub_StrLen i = 0; i < aStr.Len(); ++i )
+ if( CH_BLANK == aStr.GetChar( i ) )
+ aStr.SetChar( i, CH_BULLET );
+ }
+
+ xub_StrLen nCnt = rInf.GetText().Len();
+ if ( nCnt < rInf.GetIdx() )
+ nCnt = 0;
+ else
+ nCnt = nCnt - rInf.GetIdx();
+ nCnt = Min( nCnt, rInf.GetLen() );
+ long nKernSum = rInf.GetKern();
+ xub_Unicode cChPrev = rInf.GetText().GetChar( rInf.GetIdx() );
+
+ // Wenn es sich um ein singulaeres, unterstrichenes Space
+ // im Blocksatz handelt, muessen wir zwei ausgeben:
+ if ( ( nCnt == 1 ) && rInf.GetSpace() && ( cChPrev == CH_BLANK ) )
+ {
+ pKernArray[0] = rInf.GetWidth() +
+ rInf.GetKern() +
+ ( rInf.GetSpace() / SPACING_PRECISION_FACTOR );
+
+ if ( bSwitchL2R )
+ rInf.GetFrm()->SwitchLTRtoRTL( aPos );
+
+ if ( bSwitchH2V )
+ rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
+
+ rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
+ pKernArray, rInf.GetIdx(), 1 );
+ if( bBullet )
+ rInf.GetOut().DrawTextArray( aPos, *pStr, pKernArray,
+ rInf.GetIdx() ? 1 : 0, 1 );
+ }
+ else
+ {
+ xub_Unicode nCh;
+
+ // Bei Pairkerning waechst der Printereinfluss auf die Positionierung
+ sal_uInt16 nMul = 3;
+
+ if ( pPrtFont->GetKerning() )
+ nMul = 1;
+
+ const sal_uInt16 nDiv = nMul+1;
+
+ // In nSpaceSum wird der durch Blocksatz auf die Spaces verteilte
+ // Zwischenraum aufsummiert.
+ // Die Spaces selbst werden im Normalfall in der Mitte des
+ // Zwischenraums positioniert, deshalb die nSpace/2-Mimik.
+ // Bei wortweiser Unterstreichung muessen sie am Anfang des
+ // Zwischenraums stehen, damit dieser nicht unterstrichen wird.
+ // Ein Space am Anfang oder am Ende des Textes muss allerdings
+ // vor bzw. hinter den kompletten Zwischenraum gesetzt werden,
+ // sonst wuerde das Durch-/Unterstreichen Luecken aufweisen.
+ long nSpaceSum = 0;
+ // in word line mode and for Arabic, we disable the half space trick:
+ const long nHalfSpace = pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2;
+ const long nOtherHalf = nSpaceAdd - nHalfSpace;
+ if ( nSpaceAdd && ( cChPrev == CH_BLANK ) )
+ nSpaceSum = nHalfSpace;
+ for ( xub_StrLen i=1; i<nCnt; ++i,nKernSum += rInf.GetKern() )
+ {
+ nCh = rInf.GetText().GetChar( rInf.GetIdx() + i );
+
+ OSL_ENSURE( pScrArray, "Where is the screen array?" );
+ long nScr;
+ nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
+
+ // Wenn vor uns ein (Ex-)SPACE ist, positionieren wir uns optimal,
+ // d.h. unseren rechten Rand auf die 100% Druckerposition,
+ // sind wir sogar selbst ein Ex-SPACE, so positionieren wir uns
+ // linksbuendig zur Druckerposition.
+ if ( nCh == CH_BLANK )
+ {
+ nScrPos = pKernArray[i-1] + nScr;
+
+ if ( cChPrev == CH_BLANK )
+ nSpaceSum += nOtherHalf;
+ if ( i + 1 == nCnt )
+ nSpaceSum += nSpaceAdd;
+ else
+ nSpaceSum += nHalfSpace;
+ }
+ else
+ {
+ if ( cChPrev == CH_BLANK )
+ {
+ nScrPos = pKernArray[i-1] + nScr;
+
+ // kein Pixel geht verloren:
+ nSpaceSum += nOtherHalf;
+ }
+ else if ( cChPrev == '-' )
+ nScrPos = pKernArray[i-1] + nScr;
+ else
+ {
+ nScrPos += nScr;
+ nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
+ }
+ }
+ cChPrev = nCh;
+ pKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum;
+ // In word line mode and for Arabic, we disabled the half space trick. If a portion
+ // ends with a blank, the full nSpaceAdd value has been added to the character in
+ // front of the blank. This leads to painting artifacts, therefore we remove the
+ // nSpaceAdd value again:
+ if ( (bNoHalfSpace || pPrtFont->IsWordLineMode()) && i+1 == nCnt && nCh == CH_BLANK )
+ pKernArray[i-1] = pKernArray[i-1] - nSpaceAdd;
+ }
+
+ // the layout engine requires the total width of the output
+ pKernArray[ rInf.GetLen() - 1 ] += nKernSum + nSpaceSum;
+
+ if( rInf.GetGreyWave() )
+ {
+ if( rInf.GetLen() )
+ {
+ long nHght = rInf.GetOut().LogicToPixel(
+ pPrtFont->GetSize() ).Height();
+ if( WRONG_SHOW_MIN < nHght )
+ {
+ if ( rInf.GetOut().GetConnectMetaFile() )
+ rInf.GetOut().Push();
+
+ sal_uInt16 nWave =
+ WRONG_SHOW_MEDIUM < nHght ? WAVE_NORMAL :
+ ( WRONG_SHOW_SMALL < nHght ? WAVE_SMALL :
+ WAVE_FLAT );
+ Color aCol( rInf.GetOut().GetLineColor() );
+ sal_Bool bColSave = aCol != *pWaveCol;
+ if ( bColSave )
+ rInf.GetOut().SetLineColor( *pWaveCol );
+
+ Point aEnd;
+ long nKernVal = pKernArray[ sal_uInt16( rInf.GetLen() - 1 ) ];
+
+ sal_uInt16 nDir = bBidiPor ?
+ 1800 :
+ UnMapDirection(
+ GetFont()->GetOrientation(),
+ bSwitchH2V );
+
+ switch ( nDir )
+ {
+ case 0 :
+ aEnd.X() = rInf.GetPos().X() + nKernVal;
+ aEnd.Y() = rInf.GetPos().Y();
+ break;
+ case 900 :
+ aEnd.X() = rInf.GetPos().X();
+ aEnd.Y() = rInf.GetPos().Y() - nKernVal;
+ break;
+ case 1800 :
+ aEnd.X() = rInf.GetPos().X() - nKernVal;
+ aEnd.Y() = rInf.GetPos().Y();
+ break;
+ case 2700 :
+ aEnd.X() = rInf.GetPos().X();
+ aEnd.Y() = rInf.GetPos().Y() + nKernVal;
+ break;
+ }
+
+ Point aCurrPos( rInf.GetPos() );
+
+ if ( bSwitchL2R )
+ {
+ rInf.GetFrm()->SwitchLTRtoRTL( aCurrPos );
+ rInf.GetFrm()->SwitchLTRtoRTL( aEnd );
+ }
+
+ if ( bSwitchH2V )
+ {
+ rInf.GetFrm()->SwitchHorizontalToVertical( aCurrPos );
+ rInf.GetFrm()->SwitchHorizontalToVertical( aEnd );
+ }
+ rInf.GetOut().DrawWaveLine( aCurrPos, aEnd, nWave );
+
+ if ( bColSave )
+ rInf.GetOut().SetLineColor( aCol );
+
+ if ( rInf.GetOut().GetConnectMetaFile() )
+ rInf.GetOut().Pop();
+ }
+ }
+ }
+ else if( !bSymbol && rInf.GetLen() )
+ {
+ // anything to do?
+ if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags())
+ {
+ CalcLinePosData aCalcLinePosData(rInf, *GetFont(),
+ nCnt, bSwitchH2V, bSwitchL2R,
+ nHalfSpace, pKernArray, bBidiPor);
+
+ SwForbidden aForbidden;
+ // draw line for smart tag data
+ lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetSmartTags(), aCalcLinePosData, Size() );
+ // draw wave line for spell check errors
+ // draw them BEFORE the grammar check lines to 'override' the latter in case of conflict.
+ // reason: some grammar errors can only be found if spelling errors are fixed,
+ // therefore we don't want the user to miss a spelling error.
+ lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetWrong(), aCalcLinePosData, pPrtFont->GetSize() );
+ // draw wave line for grammar check errors
+ lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetGrammarCheck(), aCalcLinePosData, pPrtFont->GetSize() );
+ }
+ }
+
+ xub_StrLen nOffs = 0;
+ xub_StrLen nLen = rInf.GetLen();
+
+ if( nOffs < nLen )
+ {
+ // If we paint bullets instead of spaces, we use a copy of
+ // the paragraph string. For the layout engine, the copy
+ // of the string has to be an environment of the range which
+ // is painted
+ xub_StrLen nTmpIdx = bBullet ?
+ ( rInf.GetIdx() ? 1 : 0 ) :
+ rInf.GetIdx();
+
+ if ( bSwitchL2R )
+ rInf.GetFrm()->SwitchLTRtoRTL( aPos );
+
+ if ( bSwitchH2V )
+ rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
+
+ rInf.GetOut().DrawTextArray( aPos, *pStr, pKernArray + nOffs,
+ nTmpIdx + nOffs , nLen - nOffs );
+ }
+ }
+ delete[] pScrArray;
+ delete[] pKernArray;
+ }
+}
+
+
+// Optimierung war fuer DrawText() ausgeschaltet
+#ifdef _MSC_VER
+#pragma optimize("",on)
+#endif
+
+
+/*************************************************************************
+ *
+ * Size SwFntObj::GetTextSize( const OutputDevice *pOut, const String &rTxt,
+ * const sal_uInt16 nIdx, const sal_uInt16 nLen, const short nKern = 0 );
+ *
+ * Beschreibung: ermittelt die TextSize (des Druckers)
+ *
+ *************************************************************************/
+
+Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
+{
+ Size aTxtSize;
+ const xub_StrLen nLn = ( STRING_LEN != rInf.GetLen() ) ? rInf.GetLen() :
+ rInf.GetText().Len();
+
+ // be sure to have the correct layout mode at the printer
+ if ( pPrinter )
+ {
+ pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
+ pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
+ }
+
+ if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
+ SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ GETGRID( rInf.GetFrm()->FindPageFrm() )
+ if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
+ {
+ const SwDoc* pDoc = rInf.GetShell()->GetDoc();
+ const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc);
+
+ OutputDevice* pOutDev;
+
+ if ( pPrinter )
+ {
+ if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
+ pPrinter->SetFont(*pPrtFont);
+ pOutDev = pPrinter;
+ }
+ else
+ pOutDev = rInf.GetpOut();
+
+ aTxtSize.Width() =
+ pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn );
+
+ OSL_ENSURE( !rInf.GetShell() ||
+ ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ),
+ "Leading values should be already calculated" );
+ aTxtSize.Height() = pOutDev->GetTextHeight() +
+ GetFontLeading( rInf.GetShell(), rInf.GetOut() );
+
+ long nWidthPerChar = aTxtSize.Width() / nLn;
+
+ const sal_uLong i = nWidthPerChar ?
+ ( nWidthPerChar - 1 ) / nGridWidth + 1:
+ 1;
+
+ aTxtSize.Width() = i * nGridWidth * nLn;
+ rInf.SetKanaDiff( 0 );
+ return aTxtSize;
+ }
+ }
+
+ //for textgrid refactor
+ if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
+ SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ GETGRID( rInf.GetFrm()->FindPageFrm() )
+ if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
+ {
+ const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf );
+
+ const SwDoc* pDoc = rInf.GetShell()->GetDoc();
+ long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc);
+ if( SW_LATIN == rInf.GetFont()->GetActual() )
+ nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2;
+ else
+ nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight;
+ OutputDevice* pOutDev;
+ if ( pPrinter )
+ {
+ if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
+ pPrinter->SetFont(*pPrtFont);
+ pOutDev = pPrinter;
+ }
+ else
+ pOutDev = rInf.GetpOut();
+ aTxtSize.Width() = pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn );
+ aTxtSize.Height() = pOutDev->GetTextHeight() +
+ GetFontLeading( rInf.GetShell(), rInf.GetOut() );
+ aTxtSize.Width() += (nLn) * long( nGridWidthAdd );
+ //if ( rInf.GetKern() && nLn )
+ // aTxtSize.Width() += ( nLn ) * long( rInf.GetKern() );
+
+ rInf.SetKanaDiff( 0 );
+ return aTxtSize;
+ }
+ }
+
+ const sal_Bool bCompress = rInf.GetKanaComp() && nLn &&
+ rInf.GetFont() &&
+ SW_CJK == rInf.GetFont()->GetActual() &&
+ rInf.GetScriptInfo() &&
+ rInf.GetScriptInfo()->CountCompChg() &&
+ lcl_IsMonoSpaceFont( rInf.GetOut() );
+
+ OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
+ CountCompChg()), "Compression without info" );
+
+ // This is the part used e.g., for cursor travelling
+ // See condition for DrawText or DrawTextArray (bDirectPrint)
+ if ( pPrinter && pPrinter != rInf.GetpOut() )
+ {
+ if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
+ pPrinter->SetFont(*pPrtFont);
+ aTxtSize.Width() = pPrinter->GetTextWidth( rInf.GetText(),
+ rInf.GetIdx(), nLn );
+ aTxtSize.Height() = pPrinter->GetTextHeight();
+ sal_Int32 *pKernArray = new sal_Int32[nLn];
+ CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
+ if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) )
+ rInf.GetOut().SetFont( *pScrFont );
+ long nScrPos;
+
+ pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(),nLn );
+ if( bCompress )
+ rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray,
+ rInf.GetIdx(), nLn, rInf.GetKanaComp(),
+ (sal_uInt16)aFont.GetSize().Height() ) );
+ else
+ rInf.SetKanaDiff( 0 );
+
+ if ( rInf.GetKanaDiff() )
+ nScrPos = pKernArray[ nLn - 1 ];
+ else
+ {
+ sal_Int32* pScrArray = new sal_Int32[ rInf.GetLen() ];
+ rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray,
+ rInf.GetIdx(), rInf.GetLen() );
+ nScrPos = pScrArray[ 0 ];
+ xub_StrLen nCnt = rInf.GetText().Len();
+ if ( nCnt < rInf.GetIdx() )
+ nCnt=0;
+ else
+ nCnt = nCnt - rInf.GetIdx();
+ nCnt = Min (nCnt, nLn);
+ xub_Unicode nChPrev = rInf.GetText().GetChar( rInf.GetIdx() );
+
+ xub_Unicode nCh;
+
+ // Bei Pairkerning waechst der Printereinfluss auf die Positionierung
+ sal_uInt16 nMul = 3;
+ if ( pPrtFont->GetKerning() )
+ nMul = 1;
+ const sal_uInt16 nDiv = nMul+1;
+ for( xub_StrLen i=1; i<nCnt; i++ )
+ {
+ nCh = rInf.GetText().GetChar( rInf.GetIdx() + i );
+ long nScr;
+ nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
+ if ( nCh == CH_BLANK )
+ nScrPos = pKernArray[i-1]+nScr;
+ else
+ {
+ if ( nChPrev == CH_BLANK || nChPrev == '-' )
+ nScrPos = pKernArray[i-1]+nScr;
+ else
+ {
+ nScrPos += nScr;
+ nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
+ }
+ }
+ nChPrev = nCh;
+ pKernArray[i-1] = nScrPos - nScr;
+ }
+ delete[] pScrArray;
+ }
+
+ delete[] pKernArray;
+ aTxtSize.Width() = nScrPos;
+ }
+ else
+ {
+ if( !pPrtFont->IsSameInstance( rInf.GetOut().GetFont() ) )
+ rInf.GetOut().SetFont( *pPrtFont );
+ if( bCompress )
+ {
+ sal_Int32 *pKernArray = new sal_Int32[nLn];
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), nLn );
+ rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray,
+ rInf.GetIdx(), nLn, rInf.GetKanaComp(),
+ (sal_uInt16) aFont.GetSize().Height() ) );
+ aTxtSize.Width() = pKernArray[ nLn - 1 ];
+ delete[] pKernArray;
+ }
+ else
+ {
+ aTxtSize.Width() = rInf.GetOut().GetTextWidth( rInf.GetText(),
+ rInf.GetIdx(), nLn );
+ rInf.SetKanaDiff( 0 );
+ }
+
+ aTxtSize.Height() = rInf.GetOut().GetTextHeight();
+ }
+
+ if ( rInf.GetKern() && nLn )
+ aTxtSize.Width() += ( nLn - 1 ) * long( rInf.GetKern() );
+
+ OSL_ENSURE( !rInf.GetShell() ||
+ ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ),
+ "Leading values should be already calculated" );
+ aTxtSize.Height() += GetFontLeading( rInf.GetShell(), rInf.GetOut() );
+ return aTxtSize;
+}
+
+
+xub_StrLen SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf )
+{
+ long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
+ const long nSperren = -rInf.GetSperren() / SPACING_PRECISION_FACTOR;
+ long nKern = rInf.GetKern();
+
+ if( 0 != nSperren )
+ nKern -= nSperren;
+
+ sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ];
+
+ // be sure to have the correct layout mode at the printer
+ if ( pPrinter )
+ {
+ pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
+ pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
+ pPrinter->GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+ }
+ else
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+
+ const SwScriptInfo* pSI = rInf.GetScriptInfo();
+ if ( rInf.GetFont() && rInf.GetLen() )
+ {
+ const sal_uInt8 nActual = rInf.GetFont()->GetActual();
+
+ // Kana Compression
+ if ( SW_CJK == nActual && rInf.GetKanaComp() &&
+ pSI && pSI->CountCompChg() &&
+ lcl_IsMonoSpaceFont( rInf.GetOut() ) )
+ {
+ pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
+ rInf.GetKanaComp(),
+ (sal_uInt16) aFont.GetSize().Height() );
+ }
+
+ // Asian Justification
+ if ( SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
+
+ if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang )
+ {
+ long nSpaceSum = nSpaceAdd;
+ for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI )
+ {
+ pKernArray[ nI ] += nSpaceSum;
+ nSpaceSum += nSpaceAdd;
+ }
+
+ nSpaceAdd = 0;
+ }
+
+ }
+
+ // Kashida Justification
+ if ( SW_CTL == nActual && rInf.GetSpace() )
+ {
+ if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
+ {
+ if ( pSI && pSI->CountKashida() &&
+ pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(),
+ nSpaceAdd ) != STRING_LEN )
+ nSpaceAdd = 0;
+ }
+ }
+
+ // Thai Justification
+ if ( SW_CTL == nActual && nSpaceAdd )
+ {
+ LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
+
+ if ( LANGUAGE_THAI == aLang )
+ {
+ SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0,
+ rInf.GetIdx(), rInf.GetLen(),
+ rInf.GetNumberOfBlanks(),
+ rInf.GetSpace() );
+
+ // adding space to blanks is already done
+ nSpaceAdd = 0;
+ }
+ }
+ }
+
+ long nLeft = 0;
+ long nRight = 0;
+ xub_StrLen nCnt = 0;
+ long nSpaceSum = 0;
+ long nKernSum = 0;
+
+ if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() &&
+ rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ GETGRID( rInf.GetFrm()->FindPageFrm() )
+ if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
+ {
+ const SwDoc* pDoc = rInf.GetShell()->GetDoc();
+ const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc);
+
+ long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
+
+ sal_uLong i = nWidthPerChar ?
+ ( nWidthPerChar - 1 ) / nGridWidth + 1:
+ 1;
+
+ nWidthPerChar = i * nGridWidth;
+
+ nCnt = (sal_uInt16)(rInf.GetOfst() / nWidthPerChar);
+ if ( 2 * ( rInf.GetOfst() - nCnt * nWidthPerChar ) > nWidthPerChar )
+ ++nCnt;
+
+ delete[] pKernArray;
+ return nCnt;
+ }
+ }
+
+ //for textgrid refactor
+ if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() &&
+ rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ GETGRID( rInf.GetFrm()->FindPageFrm() )
+ if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
+ {
+
+ const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf );
+
+ const SwDoc* pDoc = rInf.GetShell()->GetDoc();
+ long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc);
+ if( SW_LATIN == rInf.GetFont()->GetActual() )
+ nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2;
+ else
+ nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight;
+
+ for(xub_StrLen j = 0; j < rInf.GetLen(); j++)
+ {
+ long nScr = pKernArray[ j ] + ( nSpaceAdd + nGridWidthAdd ) * ( j + 1 );
+ if( nScr >= rInf.GetOfst())
+ {
+ nCnt = j;
+ break;
+ }
+ }
+ delete[] pKernArray;
+ return nCnt;
+ }
+ }
+
+ sal_uInt16 nItrMode = i18n::CharacterIteratorMode::SKIPCELL;
+ sal_Int32 nDone = 0;
+ LanguageType aLang = LANGUAGE_NONE;
+ bool bSkipCharacterCells = false;
+ xub_StrLen nIdx = rInf.GetIdx();
+ xub_StrLen nLastIdx = nIdx;
+ const xub_StrLen nEnd = rInf.GetIdx() + rInf.GetLen();
+
+ // --> OD 2009-12-29 #i105901#
+ // skip character cells for all script types
+ if ( pBreakIt->GetBreakIter().is() )
+ // <--
+ {
+ aLang = rInf.GetFont()->GetLanguage();
+ bSkipCharacterCells = true;
+ }
+
+ while ( ( nRight < long( rInf.GetOfst() ) ) && ( nIdx < nEnd ) )
+ {
+ if ( nSpaceAdd && CH_BLANK == rInf.GetText().GetChar( nIdx ) )
+ nSpaceSum += nSpaceAdd;
+
+ // go to next character (cell).
+ nLastIdx = nIdx;
+
+ if ( bSkipCharacterCells )
+ {
+ nIdx = (xub_StrLen)pBreakIt->GetBreakIter()->nextCharacters( rInf.GetText(),
+ nIdx, pBreakIt->GetLocale( aLang ), nItrMode, 1, nDone );
+ if ( nIdx <= nLastIdx )
+ break;
+ }
+ else
+ ++nIdx;
+
+ nLeft = nRight;
+ nRight = pKernArray[ nIdx - rInf.GetIdx() - 1 ] + nKernSum + nSpaceSum;
+
+ nKernSum += nKern;
+ }
+
+ // step back if position is before the middle of the character
+ // or if we do not want to go to the next character
+ if ( nIdx > rInf.GetIdx() &&
+ ( rInf.IsPosMatchesBounds() ||
+ ( ( nRight > long( rInf.GetOfst() ) ) &&
+ ( nRight - rInf.GetOfst() > rInf.GetOfst() - nLeft ) ) ) )
+ nCnt = nLastIdx - rInf.GetIdx(); // first half
+ else
+ nCnt = nIdx - rInf.GetIdx(); // second half
+
+ if ( pSI )
+ rInf.SetCursorBidiLevel( pSI->DirType( nLastIdx ) );
+
+ delete[] pKernArray;
+ return nCnt;
+}
+
+
+/*************************************************************************
+|*
+|* SwFntAccess::SwFntAccess()
+|*
+|*************************************************************************/
+
+SwFntAccess::SwFntAccess( const void* &rMagic,
+ sal_uInt16 &rIndex, const void *pOwn, ViewShell *pSh,
+ sal_Bool bCheck ) :
+ SwCacheAccess( *pFntCache, rMagic, rIndex ),
+ pShell( pSh )
+{
+ // Der benutzte CTor von SwCacheAccess sucht anhand rMagic+rIndex im Cache
+ if ( IsAvail() )
+ {
+ // Der schnellste Fall: ein bekannter Font ( rMagic ),
+ // bei dem Drucker und Zoom nicht ueberprueft werden brauchen.
+ if ( !bCheck )
+ return;
+
+ // Hier ist zwar der Font bekannt, muss aber noch ueberprueft werden.
+
+ }
+ else
+ // Hier ist der Font nicht bekannt, muss also gesucht werden.
+ bCheck = sal_False;
+
+
+ {
+ OutputDevice* pOut = 0;
+ sal_uInt16 nZoom = USHRT_MAX;
+
+ // Get the reference device
+ if ( pSh )
+ {
+ pOut = &pSh->GetRefDev();
+ nZoom = pSh->GetViewOptions()->GetZoom();
+ }
+
+ SwFntObj *pFntObj;
+ if ( bCheck )
+ {
+ pFntObj = Get();
+ if ( ( pFntObj->GetZoom( ) == nZoom ) &&
+ ( pFntObj->pPrinter == pOut ) &&
+ pFntObj->GetPropWidth() ==
+ ((SwSubFont*)pOwn)->GetPropWidth() )
+ return; // Die Ueberpruefung ergab: Drucker+Zoom okay.
+ pFntObj->Unlock( ); // Vergiss dies Objekt, es wurde leider
+ pObj = NULL; // eine Drucker/Zoomaenderung festgestellt.
+ }
+
+ // Search by font comparison, quite expensive!
+ // Look for same font and same printer
+ pFntObj = pFntCache->First();
+ while ( pFntObj && !( pFntObj->aFont == *(Font *)pOwn &&
+ pFntObj->GetZoom() == nZoom &&
+ pFntObj->GetPropWidth() ==
+ ((SwSubFont*)pOwn)->GetPropWidth() &&
+ ( !pFntObj->pPrinter || pFntObj->pPrinter == pOut ) ) )
+ pFntObj = pFntCache->Next( pFntObj );
+
+ if( pFntObj && pFntObj->pPrinter != pOut )
+ {
+ // Wir haben zwar einen ohne Drucker gefunden, mal sehen, ob es
+ // auch noch einen mit identischem Drucker gibt.
+ SwFntObj *pTmpObj = pFntObj;
+ while( pTmpObj && !( pTmpObj->aFont == *(Font *)pOwn &&
+ pTmpObj->GetZoom()==nZoom && pTmpObj->pPrinter==pOut &&
+ pTmpObj->GetPropWidth() ==
+ ((SwSubFont*)pOwn)->GetPropWidth() ) )
+ pTmpObj = pFntCache->Next( pTmpObj );
+ if( pTmpObj )
+ pFntObj = pTmpObj;
+ }
+
+ if ( !pFntObj ) // Font has not been found, create one
+ {
+ // Das Objekt muss neu angelegt werden, deshalb muss der Owner ein
+ // SwFont sein, spaeter wird als Owner die "MagicNumber" gehalten.
+ SwCacheAccess::pOwner = pOwn;
+ pFntObj = Get(); // hier wird via NewObj() angelegt und gelockt.
+ OSL_ENSURE(pFntObj, "No Font, no Fun.");
+ }
+ else // Font has been found, so we lock it.
+ {
+ pFntObj->Lock();
+ if( pFntObj->pPrinter != pOut ) // Falls bis dato kein Drucker bekannt
+ {
+ OSL_ENSURE( !pFntObj->pPrinter, "SwFntAccess: Printer Changed" );
+ pFntObj->CreatePrtFont( *pOut );
+ pFntObj->pPrinter = pOut;
+ pFntObj->pScrFont = NULL;
+ pFntObj->nGuessedLeading = USHRT_MAX;
+ pFntObj->nExtLeading = USHRT_MAX;
+ pFntObj->nPrtAscent = USHRT_MAX;
+ pFntObj->nPrtHeight = USHRT_MAX;
+ }
+ pObj = pFntObj;
+ }
+
+ // egal, ob neu oder gefunden, ab jetzt ist der Owner vom Objekt eine
+ // MagicNumber und wird auch dem aufrufenden SwFont bekanntgegeben,
+ // ebenso der Index fuer spaetere direkte Zugriffe
+ rMagic = pFntObj->GetOwner();
+ SwCacheAccess::pOwner = rMagic;
+ rIndex = pFntObj->GetCachePos();
+ }
+}
+
+SwCacheObj *SwFntAccess::NewObj( )
+{
+ // Ein neuer Font, eine neue "MagicNumber".
+ return new SwFntObj( *(SwSubFont *)pOwner, ++pMagicNo, pShell );
+}
+
+extern xub_StrLen lcl_CalcCaseMap( const SwFont& rFnt,
+ const XubString& rOrigString,
+ xub_StrLen nOfst,
+ xub_StrLen nLen,
+ xub_StrLen nIdx );
+
+xub_StrLen SwFont::GetTxtBreak( SwDrawTextInfo& rInf, long nTextWidth )
+{
+ ChgFnt( rInf.GetShell(), rInf.GetOut() );
+
+ const sal_Bool bCompress = rInf.GetKanaComp() && rInf.GetLen() &&
+ SW_CJK == GetActual() &&
+ rInf.GetScriptInfo() &&
+ rInf.GetScriptInfo()->CountCompChg() &&
+ lcl_IsMonoSpaceFont( rInf.GetOut() );
+
+ OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
+ CountCompChg()), "Compression without info" );
+
+ sal_uInt16 nTxtBreak = 0;
+ long nKern = 0;
+
+ sal_uInt16 nLn = ( rInf.GetLen() == STRING_LEN ? rInf.GetText().Len()
+ : rInf.GetLen() );
+
+ if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() &&
+ rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ GETGRID( rInf.GetFrm()->FindPageFrm() )
+ if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
+ {
+ const SwDoc* pDoc = rInf.GetShell()->GetDoc();
+ const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc);
+
+ sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()];
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+
+ long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
+
+ const sal_uLong i = nWidthPerChar ?
+ ( nWidthPerChar - 1 ) / nGridWidth + 1:
+ 1;
+
+ nWidthPerChar = i * nGridWidth;
+ long nCurrPos = nWidthPerChar;
+
+ while( nTxtBreak < rInf.GetLen() && nTextWidth >= nCurrPos )
+ {
+ nCurrPos += nWidthPerChar;
+ ++nTxtBreak;
+ }
+
+ delete[] pKernArray;
+ return nTxtBreak + rInf.GetIdx();
+ }
+ }
+
+ //for text grid enhancement
+ if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
+ SW_CJK == rInf.GetFont()->GetActual() )
+ {
+ GETGRID( rInf.GetFrm()->FindPageFrm() )
+ if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
+ {
+ const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf );
+
+ const SwDoc* pDoc = rInf.GetShell()->GetDoc();
+ long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc);
+ if( SW_LATIN == rInf.GetFont()->GetActual() )
+ nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2 ;
+ else
+ nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight;
+
+ sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()];
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), rInf.GetLen() );
+ long nCurrPos = pKernArray[nTxtBreak] + nGridWidthAdd;
+ while( nTxtBreak < rInf.GetLen() && nTextWidth >= nCurrPos)
+ {
+ nTxtBreak++;
+ nCurrPos = pKernArray[nTxtBreak] + nGridWidthAdd * ( nTxtBreak + 1 );
+ }
+ delete[] pKernArray;
+ return nTxtBreak + rInf.GetIdx();
+ }
+ }
+
+ if( aSub[nActual].IsCapital() && nLn )
+ nTxtBreak = GetCapitalBreak( rInf.GetShell(), rInf.GetpOut(),
+ rInf.GetScriptInfo(), rInf.GetText(), nTextWidth,0, rInf.GetIdx(),nLn );
+ else
+ {
+ nKern = CheckKerning();
+
+ const XubString* pTmpText;
+ XubString aTmpText;
+ xub_StrLen nTmpIdx;
+ xub_StrLen nTmpLen;
+ bool bTextReplaced = false;
+
+ if ( !aSub[nActual].IsCaseMap() )
+ {
+ pTmpText = &rInf.GetText();
+ nTmpIdx = rInf.GetIdx();
+ nTmpLen = nLn;
+ }
+ else
+ {
+ const XubString aSnippet( rInf.GetText(), rInf.GetIdx(), nLn );
+ aTmpText = aSub[nActual].CalcCaseMap( aSnippet );
+ const bool bTitle = SVX_CASEMAP_TITEL == aSub[nActual].GetCaseMap() &&
+ pBreakIt->GetBreakIter().is();
+
+ // Uaaaaahhhh!!! In title case mode, we would get wrong results
+ if ( bTitle && nLn )
+ {
+ // check if rInf.GetIdx() is begin of word
+ if ( !pBreakIt->GetBreakIter()->isBeginWord(
+ rInf.GetText(), rInf.GetIdx(),
+ pBreakIt->GetLocale( aSub[nActual].GetLanguage() ),
+ i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
+ {
+ // In this case, the beginning of aTmpText is wrong.
+ XubString aSnippetTmp( aSnippet, 0, 1 );
+ aSnippetTmp = aSub[nActual].CalcCaseMap( aSnippetTmp );
+ aTmpText.Erase( 0, aSnippetTmp.Len() );
+ aTmpText.Insert( aSnippet.GetChar( 0 ), 0 );
+ }
+ }
+
+ pTmpText = &aTmpText;
+ nTmpIdx = 0;
+ nTmpLen = aTmpText.Len();
+ bTextReplaced = true;
+ }
+
+ if( rInf.GetHyphPos() )
+ nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth,
+ '-', *rInf.GetHyphPos(),
+ nTmpIdx, nTmpLen, nKern );
+ else
+ nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth,
+ nTmpIdx, nTmpLen, nKern );
+
+ if ( bTextReplaced && STRING_LEN != nTxtBreak )
+ {
+ if ( nTmpLen != nLn )
+ nTxtBreak = lcl_CalcCaseMap( *this, rInf.GetText(),
+ rInf.GetIdx(), nLn, nTxtBreak );
+ else
+ nTxtBreak = nTxtBreak + rInf.GetIdx();
+ }
+ }
+
+ if ( ! bCompress )
+ return nTxtBreak;
+
+ nTxtBreak = nTxtBreak - rInf.GetIdx();
+
+ if( nTxtBreak < nLn )
+ {
+ if( !nTxtBreak && nLn )
+ nLn = 1;
+ else if( nLn > 2 * nTxtBreak )
+ nLn = 2 * nTxtBreak;
+ sal_Int32 *pKernArray = new sal_Int32[ nLn ];
+ rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
+ rInf.GetIdx(), nLn );
+ if( rInf.GetScriptInfo()->Compress( pKernArray, rInf.GetIdx(), nLn,
+ rInf.GetKanaComp(), (sal_uInt16)GetHeight( nActual ) ) )
+ {
+ long nKernAdd = nKern;
+ xub_StrLen nTmpBreak = nTxtBreak;
+ if( nKern && nTxtBreak )
+ nKern *= nTxtBreak - 1;
+ while( nTxtBreak<nLn && nTextWidth >= pKernArray[nTxtBreak] +nKern )
+ {
+ nKern += nKernAdd;
+ ++nTxtBreak;
+ }
+ if( rInf.GetHyphPos() )
+ *rInf.GetHyphPos() += nTxtBreak - nTmpBreak; // It's not perfect
+ }
+ delete[] pKernArray;
+ }
+ nTxtBreak = nTxtBreak + rInf.GetIdx();
+
+ return nTxtBreak;
+}
+
+extern Color aGlobalRetoucheColor;
+
+sal_Bool SwDrawTextInfo::ApplyAutoColor( Font* pFont )
+{
+ const Font& rFnt = pFont ? *pFont : GetOut().GetFont();
+ sal_Bool bPrt = GetShell() && ! GetShell()->GetWin();
+ ColorData nNewColor = COL_BLACK;
+ sal_Bool bChgFntColor = sal_False;
+ sal_Bool bChgLineColor = sal_False;
+
+ if( bPrt && GetShell() && GetShell()->GetViewOptions()->IsBlackFont() )
+ {
+ if ( COL_BLACK != rFnt.GetColor().GetColor() )
+ bChgFntColor = sal_True;
+
+ if ( (COL_BLACK != GetOut().GetLineColor().GetColor()) ||
+ (COL_BLACK != GetOut().GetOverlineColor().GetColor()) )
+ bChgLineColor = sal_True;
+ }
+ else
+ {
+ // FontColor has to be changed if:
+ // 1. FontColor = AUTO or 2. IsAlwaysAutoColor is set
+ // LineColor has to be changed if:
+ // 1. IsAlwaysAutoColor is set
+
+ bChgLineColor = ! bPrt && GetShell() &&
+ GetShell()->GetAccessibilityOptions()->IsAlwaysAutoColor();
+
+ bChgFntColor = COL_AUTO == rFnt.GetColor().GetColor() || bChgLineColor;
+
+ if ( bChgFntColor )
+ {
+ // check if current background has a user defined setting
+ const Color* pCol = GetFont() ? GetFont()->GetBackColor() : NULL;
+ if( ! pCol || COL_TRANSPARENT == pCol->GetColor() )
+ {
+ const SvxBrushItem* pItem;
+ SwRect aOrigBackRect;
+
+ /// OD 21.08.2002
+ /// consider, that [GetBackgroundBrush(...)] can set <pCol>
+ /// - see implementation in /core/layout/paintfrm.cxx
+ /// OD 21.08.2002 #99657#
+ /// There is a user defined setting for the background, if there
+ /// is a background brush and its color is *not* "no fill"/"auto fill".
+ if( GetFrm()->GetBackgroundBrush( pItem, pCol, aOrigBackRect, sal_False ) )
+ {
+ if ( !pCol )
+ {
+ pCol = &pItem->GetColor();
+ }
+
+ /// OD 30.08.2002 #99657#
+ /// determined color <pCol> can be <COL_TRANSPARENT>. Thus, check it.
+ if ( pCol->GetColor() == COL_TRANSPARENT)
+ pCol = NULL;
+ }
+ else
+ pCol = NULL;
+ }
+
+ // no user defined color at paragraph or font background
+ if ( ! pCol )
+ pCol = &aGlobalRetoucheColor;
+
+ if( GetShell() && GetShell()->GetWin() )
+ {
+ // here we determine the prefered window text color for painting
+ const SwViewOption* pViewOption = GetShell()->GetViewOptions();
+ if(pViewOption->IsPagePreview() &&
+ !SW_MOD()->GetAccessibilityOptions().GetIsForPagePreviews())
+ nNewColor = COL_BLACK;
+ else
+ // we take the font color from the appearence page
+ nNewColor = SwViewOption::GetFontColor().GetColor();
+ }
+
+ // change painting color depending of dark/bright background
+ Color aTmpColor( nNewColor );
+ if ( pCol->IsDark() && aTmpColor.IsDark() )
+ nNewColor = COL_WHITE;
+ else if ( pCol->IsBright() && aTmpColor.IsBright() )
+ nNewColor = COL_BLACK;
+ }
+ }
+
+ if ( bChgFntColor || bChgLineColor )
+ {
+ Color aNewColor( nNewColor );
+
+ if ( bChgFntColor )
+ {
+ if ( pFont && aNewColor != pFont->GetColor() )
+ {
+ // only set the new color at the font passed as argument
+ pFont->SetColor( aNewColor );
+ }
+ else if ( aNewColor != GetOut().GetFont().GetColor() )
+ {
+ // set new font with new color at output device
+ Font aFont( rFnt );
+ aFont.SetColor( aNewColor );
+ GetOut().SetFont( aFont );
+ }
+ }
+
+ // the underline and overline colors have to be set separately
+ if ( bChgLineColor )
+ {
+ // get current font color or color set at output device
+ aNewColor = pFont ? pFont->GetColor() : GetOut().GetFont().GetColor();
+ if ( aNewColor != GetOut().GetLineColor() )
+ GetOut().SetLineColor( aNewColor );
+ if ( aNewColor != GetOut().GetOverlineColor() )
+ GetOut().SetOverlineColor( aNewColor );
+ }
+
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/fntcap.cxx b/sw/source/core/txtnode/fntcap.cxx
new file mode 100644
index 000000000000..8a40614a3d93
--- /dev/null
+++ b/sw/source/core/txtnode/fntcap.cxx
@@ -0,0 +1,846 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <hintids.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/svxfont.hxx>
+
+#include <vcl/outdev.hxx>
+#include <com/sun/star/i18n/CharType.hdl>
+#include <com/sun/star/i18n/WordType.hdl>
+
+#include <vcl/print.hxx>
+#include <fntcache.hxx>
+#include <swfont.hxx>
+#include <breakit.hxx>
+#include <txtfrm.hxx> // SwTxtFrm
+#include <scriptinfo.hxx>
+
+using namespace ::com::sun::star::i18n;
+
+/*************************************************************************
+ * class SwCapitalInfo
+ *
+ * The information encapsulated in SwCapitalInfo is required
+ * by the ::Do functions. They contain the information about
+ * the original string, whereas rDo.GetInf() contains information
+ * about the display string.
+ *************************************************************************/
+
+class SwCapitalInfo
+{
+public:
+ explicit SwCapitalInfo( const XubString& rOrigText ) :
+ rString( rOrigText ), nIdx( 0 ), nLen( 0 ) {};
+ const XubString& rString;
+ xub_StrLen nIdx;
+ xub_StrLen nLen;
+};
+
+/*************************************************************************
+ * xub_StrLen lcl_CalcCaseMap()
+ *
+ * rFnt: required for CalcCaseMap
+ * rOrigString: The original string
+ * nOfst: Position of the substring in rOrigString
+ * nLen: Length if the substring in rOrigString
+ * nIdx: Referes to a position in the display string and should be mapped
+ * to a position in rOrigString
+ *************************************************************************/
+
+xub_StrLen lcl_CalcCaseMap( const SwFont& rFnt,
+ const XubString& rOrigString,
+ xub_StrLen nOfst,
+ xub_StrLen nLen,
+ xub_StrLen nIdx )
+{
+ int j = 0;
+ const xub_StrLen nEnd = nOfst + nLen;
+ OSL_ENSURE( nEnd <= rOrigString.Len(), "lcl_CalcCaseMap: Wrong parameters" );
+
+ // special case for title case:
+ const bool bTitle = SVX_CASEMAP_TITEL == rFnt.GetCaseMap() &&
+ pBreakIt->GetBreakIter().is();
+ for ( xub_StrLen i = nOfst; i < nEnd; ++i )
+ {
+ XubString aTmp( rOrigString, i, 1 );
+
+ if ( !bTitle ||
+ pBreakIt->GetBreakIter()->isBeginWord(
+ rOrigString, i,
+ pBreakIt->GetLocale( rFnt.GetLanguage() ),
+ WordType::ANYWORD_IGNOREWHITESPACES ) )
+ aTmp = rFnt.GetActualFont().CalcCaseMap( aTmp );
+
+ j += aTmp.Len();
+
+ if ( j > nIdx )
+ return i;
+ }
+
+ return nOfst + nLen;
+}
+
+/*************************************************************************
+ * class SwDoCapitals
+ *************************************************************************/
+
+class SwDoCapitals
+{
+protected:
+ SwDrawTextInfo &rInf;
+ SwCapitalInfo* pCapInf; // referes to additional information
+ // required by the ::Do function
+public:
+ SwDoCapitals ( SwDrawTextInfo &rInfo ) : rInf( rInfo ), pCapInf( 0 ) { }
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) = 0;
+ virtual void Do() = 0;
+ inline OutputDevice& GetOut() { return rInf.GetOut(); }
+ inline SwDrawTextInfo& GetInf() { return rInf; }
+ inline SwCapitalInfo* GetCapInf() const { return pCapInf; }
+ inline void SetCapInf( SwCapitalInfo& rNew ) { pCapInf = &rNew; }
+};
+
+/*************************************************************************
+ * class SwDoGetCapitalSize
+ *************************************************************************/
+
+class SwDoGetCapitalSize : public SwDoCapitals
+{
+protected:
+ Size aTxtSize;
+public:
+ SwDoGetCapitalSize( SwDrawTextInfo &rInfo ) : SwDoCapitals ( rInfo ) { }
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
+ virtual void Do();
+ const Size &GetSize() const { return aTxtSize; }
+};
+
+void SwDoGetCapitalSize::Init( SwFntObj *, SwFntObj * )
+{
+ aTxtSize.Height() = 0;
+ aTxtSize.Width() = 0;
+}
+
+void SwDoGetCapitalSize::Do()
+{
+ aTxtSize.Width() += rInf.GetSize().Width();
+ if( rInf.GetUpper() )
+ aTxtSize.Height() = rInf.GetSize().Height();
+}
+
+/*************************************************************************
+ * SwSubFont::GetCapitalSize()
+ *************************************************************************/
+
+Size SwSubFont::GetCapitalSize( SwDrawTextInfo& rInf )
+{
+ // Start:
+ const long nOldKern = rInf.GetKern();
+ rInf.SetKern( CheckKerning() );
+ Point aPos;
+ rInf.SetPos( aPos );
+ rInf.SetSpace( 0 );
+ rInf.SetDrawSpace( sal_False );
+ SwDoGetCapitalSize aDo( rInf );
+ DoOnCapitals( aDo );
+ Size aTxtSize( aDo.GetSize() );
+
+ // End:
+ if( !aTxtSize.Height() )
+ {
+ SV_STAT( nGetTextSize );
+ aTxtSize.Height() = short ( rInf.GetpOut()->GetTextHeight() );
+ }
+ rInf.SetKern( nOldKern );
+ return aTxtSize;
+}
+
+/*************************************************************************
+ * class SwDoGetCapitalBreak
+ *************************************************************************/
+
+class SwDoGetCapitalBreak : public SwDoCapitals
+{
+protected:
+ xub_StrLen *pExtraPos;
+ long nTxtWidth;
+ xub_StrLen nBreak;
+public:
+ SwDoGetCapitalBreak( SwDrawTextInfo &rInfo, long nWidth, xub_StrLen *pExtra)
+ : SwDoCapitals ( rInfo ), pExtraPos( pExtra ), nTxtWidth( nWidth ),
+ nBreak( STRING_LEN )
+ { }
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
+ virtual void Do();
+ xub_StrLen GetBreak() const { return nBreak; }
+};
+
+void SwDoGetCapitalBreak::Init( SwFntObj *, SwFntObj * )
+{
+}
+
+void SwDoGetCapitalBreak::Do()
+{
+ if ( nTxtWidth )
+ {
+ if ( rInf.GetSize().Width() < nTxtWidth )
+ nTxtWidth -= rInf.GetSize().Width();
+ else
+ {
+ xub_StrLen nEnd = rInf.GetEnd();
+ if( pExtraPos )
+ {
+ nBreak = GetOut().GetTextBreak( rInf.GetText(), nTxtWidth, '-',
+ *pExtraPos, rInf.GetIdx(), rInf.GetLen(), rInf.GetKern() );
+ if( *pExtraPos > nEnd )
+ *pExtraPos = nEnd;
+ }
+ else
+ nBreak = GetOut().GetTextBreak( rInf.GetText(), nTxtWidth,
+ rInf.GetIdx(), rInf.GetLen(), rInf.GetKern() );
+
+ if( nBreak > nEnd )
+ nBreak = nEnd;
+
+ // nBreak may be relative to the display string. It has to be
+ // calculated relative to the original string:
+ if ( GetCapInf() )
+ {
+ if ( GetCapInf()->nLen != rInf.GetLen() )
+ nBreak = lcl_CalcCaseMap( *rInf.GetFont(),
+ GetCapInf()->rString,
+ GetCapInf()->nIdx,
+ GetCapInf()->nLen, nBreak );
+ else
+ nBreak = nBreak + GetCapInf()->nIdx;
+ }
+
+ nTxtWidth = 0;
+ }
+ }
+}
+
+/*************************************************************************
+ * SwFont::GetCapitalBreak()
+ *************************************************************************/
+
+xub_StrLen SwFont::GetCapitalBreak( ViewShell* pSh, const OutputDevice* pOut,
+ const SwScriptInfo* pScript, const XubString& rTxt, long nTextWidth,
+ xub_StrLen *pExtra, const xub_StrLen nIdx, const xub_StrLen nLen )
+{
+ // Start:
+ Point aPos( 0, 0 );
+ SwDrawTextInfo aInfo(pSh, *(OutputDevice*)pOut, pScript, rTxt, nIdx, nLen,
+ 0, sal_False);
+ aInfo.SetPos( aPos );
+ aInfo.SetSpace( 0 );
+ aInfo.SetWrong( NULL );
+ aInfo.SetGrammarCheck( NULL );
+ aInfo.SetSmartTags( NULL ); // SMARTTAGS
+ aInfo.SetDrawSpace( sal_False );
+ aInfo.SetKern( CheckKerning() );
+ aInfo.SetKanaComp( pScript ? 0 : 100 );
+ aInfo.SetFont( this );
+
+ SwDoGetCapitalBreak aDo( aInfo, nTextWidth, pExtra );
+ DoOnCapitals( aDo );
+ return aDo.GetBreak();
+}
+
+/*************************************************************************
+ * class SwDoDrawCapital
+ *************************************************************************/
+
+class SwDoDrawCapital : public SwDoCapitals
+{
+protected:
+ SwFntObj *pUpperFnt;
+ SwFntObj *pLowerFnt;
+public:
+ SwDoDrawCapital( SwDrawTextInfo &rInfo ) :
+ SwDoCapitals( rInfo ), pUpperFnt(0), pLowerFnt(0)
+ { }
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
+ virtual void Do();
+ void DrawSpace( Point &rPos );
+};
+
+void SwDoDrawCapital::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
+{
+ pUpperFnt = pUpperFont;
+ pLowerFnt = pLowerFont;
+}
+
+void SwDoDrawCapital::Do()
+{
+ SV_STAT( nDrawText );
+ sal_uInt16 nOrgWidth = rInf.GetWidth();
+ rInf.SetWidth( sal_uInt16(rInf.GetSize().Width()) );
+ if ( rInf.GetUpper() )
+ pUpperFnt->DrawText( rInf );
+ else
+ {
+ sal_Bool bOldBullet = rInf.GetBullet();
+ rInf.SetBullet( sal_False );
+ pLowerFnt->DrawText( rInf );
+ rInf.SetBullet( bOldBullet );
+ }
+
+ OSL_ENSURE( pUpperFnt, "No upper font, dying soon!");
+ rInf.Shift( pUpperFnt->GetFont()->GetOrientation() );
+ rInf.SetWidth( nOrgWidth );
+}
+
+/*************************************************************************
+ * SwDoDrawCapital::DrawSpace()
+ *************************************************************************/
+
+void SwDoDrawCapital::DrawSpace( Point &rPos )
+{
+ static sal_Char const sDoubleSpace[] = " ";
+
+ long nDiff = rInf.GetPos().X() - rPos.X();
+
+ Point aPos( rPos );
+ const sal_Bool bSwitchL2R = rInf.GetFrm()->IsRightToLeft() &&
+ ! rInf.IsIgnoreFrmRTL();
+
+
+ if ( bSwitchL2R )
+ rInf.GetFrm()->SwitchLTRtoRTL( aPos );
+
+ const sal_uLong nMode = rInf.GetpOut()->GetLayoutMode();
+ const sal_Bool bBidiPor = ( bSwitchL2R !=
+ ( 0 != ( TEXT_LAYOUT_BIDI_RTL & nMode ) ) );
+
+ if ( bBidiPor )
+ nDiff = -nDiff;
+
+ if ( rInf.GetFrm()->IsVertical() )
+ rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
+
+ if ( nDiff )
+ {
+ rInf.ApplyAutoColor();
+ GetOut().DrawStretchText( aPos, nDiff,
+ XubString( sDoubleSpace, RTL_TEXTENCODING_MS_1252 ), 0, 2 );
+ }
+ rPos.X() = rInf.GetPos().X() + rInf.GetWidth();
+}
+
+/*************************************************************************
+ * SwSubFont::DrawCapital()
+ *************************************************************************/
+
+void SwSubFont::DrawCapital( SwDrawTextInfo &rInf )
+{
+ // Es wird vorausgesetzt, dass rPos bereits kalkuliert ist!
+ // hochgezogen in SwFont: const Point aPos( CalcPos(rPos) );
+ rInf.SetDrawSpace( GetUnderline() != UNDERLINE_NONE ||
+ GetOverline() != UNDERLINE_NONE ||
+ GetStrikeout() != STRIKEOUT_NONE );
+ SwDoDrawCapital aDo( rInf );
+ DoOnCapitals( aDo );
+}
+
+/*************************************************************************
+ * class SwDoDrawCapital
+ *************************************************************************/
+
+class SwDoCapitalCrsrOfst : public SwDoCapitals
+{
+protected:
+ SwFntObj *pUpperFnt;
+ SwFntObj *pLowerFnt;
+ xub_StrLen nCrsr;
+ sal_uInt16 nOfst;
+public:
+ SwDoCapitalCrsrOfst( SwDrawTextInfo &rInfo, const sal_uInt16 nOfs ) :
+ SwDoCapitals( rInfo ), pUpperFnt(0), pLowerFnt(0), nCrsr( 0 ), nOfst( nOfs )
+ { }
+ virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont );
+ virtual void Do();
+
+ void DrawSpace( const Point &rPos );
+ inline xub_StrLen GetCrsr(){ return nCrsr; }
+};
+
+void SwDoCapitalCrsrOfst::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
+{
+ pUpperFnt = pUpperFont;
+ pLowerFnt = pLowerFont;
+}
+
+void SwDoCapitalCrsrOfst::Do()
+{
+ if ( nOfst )
+ {
+ if ( nOfst > rInf.GetSize().Width() )
+ {
+ nOfst = nOfst - sal_uInt16(rInf.GetSize().Width());
+ nCrsr = nCrsr + rInf.GetLen();
+ }
+ else
+ {
+ SwDrawTextInfo aDrawInf( rInf.GetShell(), *rInf.GetpOut(),
+ rInf.GetScriptInfo(),
+ rInf.GetText(),
+ rInf.GetIdx(),
+ rInf.GetLen(), 0, sal_False );
+ aDrawInf.SetOfst( nOfst );
+ aDrawInf.SetKern( rInf.GetKern() );
+ aDrawInf.SetKanaComp( rInf.GetKanaComp() );
+ aDrawInf.SetFrm( rInf.GetFrm() );
+ aDrawInf.SetFont( rInf.GetFont() );
+
+ if ( rInf.GetUpper() )
+ {
+ aDrawInf.SetSpace( 0 );
+ nCrsr = nCrsr + pUpperFnt->GetCrsrOfst( aDrawInf );
+ }
+ else
+ {
+ aDrawInf.SetSpace( rInf.GetSpace() );
+ nCrsr = nCrsr + pLowerFnt->GetCrsrOfst( aDrawInf );
+ }
+ nOfst = 0;
+ }
+ }
+}
+
+/*************************************************************************
+ * SwSubFont::GetCapitalCrsrOfst()
+ *************************************************************************/
+
+xub_StrLen SwSubFont::GetCapitalCrsrOfst( SwDrawTextInfo& rInf )
+{
+ const long nOldKern = rInf.GetKern();
+ rInf.SetKern( CheckKerning() );
+ SwDoCapitalCrsrOfst aDo( rInf, rInf.GetOfst() );
+ Point aPos;
+ rInf.SetPos( aPos );
+ rInf.SetDrawSpace( sal_False );
+ DoOnCapitals( aDo );
+ rInf.SetKern( nOldKern );
+ return aDo.GetCrsr();
+}
+
+/*************************************************************************
+ * class SwDoDrawStretchCapital
+ *************************************************************************/
+
+class SwDoDrawStretchCapital : public SwDoDrawCapital
+{
+ const xub_StrLen nStrLen;
+ const sal_uInt16 nCapWidth;
+ const sal_uInt16 nOrgWidth;
+public:
+ virtual void Do();
+
+ SwDoDrawStretchCapital( SwDrawTextInfo &rInfo, const sal_uInt16 nCapitalWidth )
+ : SwDoDrawCapital( rInfo ),
+ nStrLen( rInfo.GetLen() ),
+ nCapWidth( nCapitalWidth ),
+ nOrgWidth( rInfo.GetWidth() )
+ { }
+};
+
+/*************************************************************************
+ * SwDoDrawStretchCapital
+ *************************************************************************/
+
+void SwDoDrawStretchCapital::Do()
+{
+ SV_STAT( nDrawStretchText );
+ sal_uInt16 nPartWidth = sal_uInt16(rInf.GetSize().Width());
+
+ if( rInf.GetLen() )
+ {
+ // 4023: Kapitaelchen und Kerning.
+ long nDiff = long(nOrgWidth) - long(nCapWidth);
+ if( nDiff )
+ {
+ nDiff *= rInf.GetLen();
+ nDiff /= (long) nStrLen;
+ nDiff += nPartWidth;
+ if( 0 < nDiff )
+ nPartWidth = sal_uInt16(nDiff);
+ }
+
+ rInf.ApplyAutoColor();
+
+ Point aPos( rInf.GetPos() );
+ const sal_Bool bSwitchL2R = rInf.GetFrm()->IsRightToLeft() &&
+ ! rInf.IsIgnoreFrmRTL();
+
+ if ( bSwitchL2R )
+ rInf.GetFrm()->SwitchLTRtoRTL( aPos );
+
+ if ( rInf.GetFrm()->IsVertical() )
+ rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
+
+ // Optimierung:
+ if( 1 >= rInf.GetLen() )
+ GetOut().DrawText( aPos, rInf.GetText(), rInf.GetIdx(),
+ rInf.GetLen() );
+ else
+ GetOut().DrawStretchText( aPos, nPartWidth,
+ rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
+ }
+ ((Point&)rInf.GetPos()).X() += nPartWidth;
+}
+
+/*************************************************************************
+ * SwSubFont::DrawStretchCapital()
+ *************************************************************************/
+
+void SwSubFont::DrawStretchCapital( SwDrawTextInfo &rInf )
+{
+ // Es wird vorausgesetzt, dass rPos bereits kalkuliert ist!
+ // hochgezogen in SwFont: const Point aPos( CalcPos(rPos) );
+
+ if( rInf.GetLen() == STRING_LEN )
+ rInf.SetLen( rInf.GetText().Len() );
+
+ const Point& rOldPos = rInf.GetPos();
+ const sal_uInt16 nCapWidth = (sal_uInt16)( GetCapitalSize( rInf ).Width() );
+ rInf.SetPos( rOldPos );
+
+ rInf.SetDrawSpace( GetUnderline() != UNDERLINE_NONE ||
+ GetOverline() != UNDERLINE_NONE ||
+ GetStrikeout() != STRIKEOUT_NONE );
+ SwDoDrawStretchCapital aDo( rInf, nCapWidth );
+ DoOnCapitals( aDo );
+}
+
+/*************************************************************************
+ * SwSubFont::DoOnCapitals() const
+ *************************************************************************/
+
+// JP 22.8.2001 - global optimization off - Bug 91245 / 91223
+#ifdef _MSC_VER
+#pragma optimize("g",off)
+#endif
+
+void SwSubFont::DoOnCapitals( SwDoCapitals &rDo )
+{
+ OSL_ENSURE( pLastFont, "SwFont::DoOnCapitals: No LastFont?!" );
+
+ Size aPartSize;
+ long nKana = 0;
+ const XubString aTxt( CalcCaseMap( rDo.GetInf().GetText() ) );
+ xub_StrLen nMaxPos = Min( sal_uInt16(rDo.GetInf().GetText().Len()
+ - rDo.GetInf().GetIdx()), rDo.GetInf().GetLen() );
+ rDo.GetInf().SetLen( nMaxPos );
+
+ const XubString& rOldText = rDo.GetInf().GetText();
+ rDo.GetInf().SetText( aTxt );
+ rDo.GetInf().SetSize( aPartSize );
+ xub_StrLen nPos = rDo.GetInf().GetIdx();
+ xub_StrLen nOldPos = nPos;
+ nMaxPos = nMaxPos + nPos;
+
+ // #107816#
+ // Look if the length of the original text and the ToUpper-converted
+ // text is different. If yes, do special handling.
+ XubString aNewText;
+ SwCapitalInfo aCapInf( rOldText );
+ sal_Bool bCaseMapLengthDiffers( aTxt.Len() != rOldText.Len() );
+ if ( bCaseMapLengthDiffers )
+ rDo.SetCapInf( aCapInf );
+
+ SwFntObj *pOldLast = pLastFont;
+ SwFntAccess *pBigFontAccess = NULL;
+ SwFntObj *pBigFont;
+ SwFntAccess *pSpaceFontAccess = NULL;
+ SwFntObj *pSpaceFont = NULL;
+
+ const void *pMagic2 = NULL;
+ sal_uInt16 nIndex2 = 0;
+ SwSubFont aFont( *this );
+ Point aStartPos( rDo.GetInf().GetPos() );
+
+ const sal_Bool bTextLines = aFont.GetUnderline() != UNDERLINE_NONE
+ || aFont.GetOverline() != UNDERLINE_NONE
+ || aFont.GetStrikeout() != STRIKEOUT_NONE;
+ const sal_Bool bWordWise = bTextLines && aFont.IsWordLineMode() &&
+ rDo.GetInf().GetDrawSpace();
+ const long nTmpKern = rDo.GetInf().GetKern();
+
+ if ( bTextLines )
+ {
+ if ( bWordWise )
+ {
+ aFont.SetWordLineMode( sal_False );
+ pSpaceFontAccess = new SwFntAccess( pMagic2, nIndex2, &aFont,
+ rDo.GetInf().GetShell() );
+ pSpaceFont = pSpaceFontAccess->Get();
+ }
+ else
+ pSpaceFont = pLastFont;
+
+ // Wir basteln uns einen Font fuer die Grossbuchstaben:
+ aFont.SetUnderline( UNDERLINE_NONE );
+ aFont.SetOverline( UNDERLINE_NONE );
+ aFont.SetStrikeout( STRIKEOUT_NONE );
+ pMagic2 = NULL;
+ nIndex2 = 0;
+ pBigFontAccess = new SwFntAccess( pMagic2, nIndex2, &aFont,
+ rDo.GetInf().GetShell() );
+ pBigFont = pBigFontAccess->Get();
+ }
+ else
+ pBigFont = pLastFont;
+
+ // Hier entsteht der Kleinbuchstabenfont:
+ aFont.SetProportion( sal_uInt8 (aFont.GetPropr() * SMALL_CAPS_PERCENTAGE ) / 100L);
+ pMagic2 = NULL;
+ nIndex2 = 0;
+ SwFntAccess *pSmallFontAccess = new SwFntAccess( pMagic2, nIndex2, &aFont,
+ rDo.GetInf().GetShell() );
+ SwFntObj *pSmallFont = pSmallFontAccess->Get();
+
+ rDo.Init( pBigFont, pSmallFont );
+ OutputDevice* pOutSize = pSmallFont->GetPrt();
+ if( !pOutSize )
+ pOutSize = &rDo.GetOut();
+ OutputDevice* pOldOut = &rDo.GetOut();
+
+ const LanguageType eLng = LANGUAGE_DONTKNOW == GetLanguage()
+ ? LANGUAGE_SYSTEM : GetLanguage();
+
+ if( nPos < nMaxPos )
+ {
+ nPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfCharBlock( rOldText, nPos,
+ pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
+ if( nPos == STRING_LEN )
+ nPos = nOldPos;
+ else if( nPos > nMaxPos )
+ nPos = nMaxPos;
+ }
+
+ while( nOldPos < nMaxPos )
+ {
+
+ // The lower ones...
+ if( nOldPos != nPos )
+ {
+ SV_STAT( nGetTextSize );
+ pLastFont = pSmallFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
+
+ // #107816#, #i14820#
+ if( bCaseMapLengthDiffers )
+ {
+ // Build an own 'changed' string for the given part of the
+ // source string and use it. That new string may differ in length
+ // from the source string.
+ const XubString aSnippet( rOldText, nOldPos, nPos - nOldPos);
+ aNewText = CalcCaseMap( aSnippet );
+ aCapInf.nIdx = nOldPos;
+ aCapInf.nLen = nPos - nOldPos;
+ rDo.GetInf().SetIdx( 0 );
+ rDo.GetInf().SetLen( aNewText.Len() );
+ rDo.GetInf().SetText( aNewText );
+ }
+ else
+ {
+ rDo.GetInf().SetIdx( nOldPos );
+ rDo.GetInf().SetLen( nPos - nOldPos );
+ }
+
+ rDo.GetInf().SetUpper( sal_False );
+ rDo.GetInf().SetOut( *pOutSize );
+ aPartSize = pSmallFont->GetTextSize( rDo.GetInf() );
+ nKana += rDo.GetInf().GetKanaDiff();
+ rDo.GetInf().SetOut( *pOldOut );
+ if( nTmpKern && nPos < nMaxPos )
+ aPartSize.Width() += nTmpKern;
+ rDo.Do();
+ nOldPos = nPos;
+ }
+ nPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextCharBlock( rOldText, nPos,
+ pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
+ if( nPos == STRING_LEN || nPos > nMaxPos )
+ nPos = nMaxPos;
+ OSL_ENSURE( nPos, "nextCharBlock not implemented?" );
+#if OSL_DEBUG_LEVEL > 1
+ if( !nPos )
+ nPos = nMaxPos;
+#endif
+ // The upper ones...
+ if( nOldPos != nPos )
+ {
+ const long nSpaceAdd = rDo.GetInf().GetSpace() / SPACING_PRECISION_FACTOR;
+
+ do
+ {
+ rDo.GetInf().SetUpper( sal_True );
+ pLastFont = pBigFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
+ xub_StrLen nTmp;
+ if( bWordWise )
+ {
+ nTmp = nOldPos;
+ while( nTmp < nPos && CH_BLANK == rOldText.GetChar( nTmp ) )
+ ++nTmp;
+ if( nOldPos < nTmp )
+ {
+ pLastFont = pSpaceFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(),
+ rDo.GetOut() );
+ ((SwDoDrawCapital&)rDo).DrawSpace( aStartPos );
+ pLastFont = pBigFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(),
+ rDo.GetOut() );
+
+ // #107816#, #i14820#
+ if( bCaseMapLengthDiffers )
+ {
+ // Build an own 'changed' string for the given part of the
+ // source string and use it. That new string may differ in length
+ // from the source string.
+ const XubString aSnippet( rOldText, nOldPos, nTmp - nOldPos);
+ aNewText = CalcCaseMap( aSnippet );
+ aCapInf.nIdx = nOldPos;
+ aCapInf.nLen = nTmp - nOldPos;
+ rDo.GetInf().SetIdx( 0 );
+ rDo.GetInf().SetLen( aNewText.Len() );
+ rDo.GetInf().SetText( aNewText );
+ }
+ else
+ {
+ rDo.GetInf().SetIdx( nOldPos );
+ rDo.GetInf().SetLen( nTmp - nOldPos );
+ }
+
+ rDo.GetInf().SetOut( *pOutSize );
+ aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
+ nKana += rDo.GetInf().GetKanaDiff();
+ rDo.GetInf().SetOut( *pOldOut );
+ if( nSpaceAdd )
+ aPartSize.Width() += nSpaceAdd * ( nTmp - nOldPos );
+ if( nTmpKern && nPos < nMaxPos )
+ aPartSize.Width() += nTmpKern;
+ rDo.Do();
+ aStartPos = rDo.GetInf().GetPos();
+ nOldPos = nTmp;
+ }
+
+ while( nTmp < nPos && CH_BLANK != rOldText.GetChar( nTmp ) )
+ ++nTmp;
+ }
+ else
+ nTmp = nPos;
+ if( nTmp > nOldPos )
+ {
+ // #107816#, #i14820#
+ if( bCaseMapLengthDiffers )
+ {
+ // Build an own 'changed' string for the given part of the
+ // source string and use it. That new string may differ in length
+ // from the source string.
+ const XubString aSnippet( rOldText, nOldPos, nTmp - nOldPos);
+ aNewText = CalcCaseMap( aSnippet );
+ aCapInf.nIdx = nOldPos;
+ aCapInf.nLen = nTmp - nOldPos;
+ rDo.GetInf().SetIdx( 0 );
+ rDo.GetInf().SetLen( aNewText.Len() );
+ rDo.GetInf().SetText( aNewText );
+ }
+ else
+ {
+ rDo.GetInf().SetIdx( nOldPos );
+ rDo.GetInf().SetLen( nTmp - nOldPos );
+ }
+
+ rDo.GetInf().SetOut( *pOutSize );
+ aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
+ nKana += rDo.GetInf().GetKanaDiff();
+ rDo.GetInf().SetOut( *pOldOut );
+ if( !bWordWise && rDo.GetInf().GetSpace() )
+ {
+ for( xub_StrLen nI = nOldPos; nI < nPos; ++nI )
+ {
+ if( CH_BLANK == rOldText.GetChar( nI ) )
+ aPartSize.Width() += nSpaceAdd;
+ }
+ }
+ if( nTmpKern && nPos < nMaxPos )
+ aPartSize.Width() += nTmpKern;
+ rDo.Do();
+ nOldPos = nTmp;
+ }
+ } while( nOldPos != nPos );
+ }
+ nPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfCharBlock( rOldText, nPos,
+ pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER);
+ if( nPos == STRING_LEN || nPos > nMaxPos )
+ nPos = nMaxPos;
+ OSL_ENSURE( nPos, "endOfCharBlock not implemented?" );
+#if OSL_DEBUG_LEVEL > 1
+ if( !nPos )
+ nPos = nMaxPos;
+#endif
+ }
+
+ // Aufraeumen:
+ if( pBigFont != pOldLast )
+ delete pBigFontAccess;
+
+ if( bTextLines )
+ {
+ if( rDo.GetInf().GetDrawSpace() )
+ {
+ pLastFont = pSpaceFont;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
+ ( (SwDoDrawCapital&) rDo ).DrawSpace( aStartPos );
+ }
+ if ( bWordWise )
+ delete pSpaceFontAccess;
+ }
+ pLastFont = pOldLast;
+ pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
+
+ delete pSmallFontAccess;
+ rDo.GetInf().SetText( rOldText );
+ rDo.GetInf().SetKanaDiff( nKana );
+}
+
+// JP 22.8.2001 - global optimization off - Bug 91245 / 91223
+#ifdef _MSC_VER
+#pragma optimize("g",on)
+#endif
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/modeltoviewhelper.cxx b/sw/source/core/txtnode/modeltoviewhelper.cxx
new file mode 100644
index 000000000000..8d4940b1ec67
--- /dev/null
+++ b/sw/source/core/txtnode/modeltoviewhelper.cxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+#include <modeltoviewhelper.hxx>
+
+namespace ModelToViewHelper
+{
+
+/** Converts a model position into a view position
+*/
+sal_uInt32 ConvertToViewPosition( const ConversionMap* pMap, sal_uInt32 nModelPos )
+{
+ sal_uInt32 nRet = nModelPos;
+
+ if ( !pMap )
+ return nRet;
+
+ // Search for entry behind nPos:
+ ConversionMap::const_iterator aIter;
+ for ( aIter = pMap->begin(); aIter != pMap->end(); ++aIter )
+ {
+ if ( (*aIter).first >= nModelPos )
+ {
+ const sal_uInt32 nPosModel = (*aIter).first;
+ const sal_uInt32 nPosExpand = (*aIter).second;
+
+ const sal_uInt32 nDistToNextModel = nPosModel - nModelPos;
+ nRet = nPosExpand - nDistToNextModel;
+ break;
+ }
+ }
+
+ return nRet;
+}
+
+
+/** Converts a view position into a model position
+*/
+ModelPosition ConvertToModelPosition( const ConversionMap* pMap, sal_uInt32 nViewPos )
+{
+ ModelPosition aRet;
+ aRet.mnPos = nViewPos;
+
+ if ( !pMap )
+ return aRet;
+
+ // Search for entry behind nPos:
+ ConversionMap::const_iterator aIter;
+ for ( aIter = pMap->begin(); aIter != pMap->end(); ++aIter )
+ {
+ if ( (*aIter).second > nViewPos )
+ {
+ const sal_uInt32 nPosModel = (*aIter).first;
+ const sal_uInt32 nPosExpand = (*aIter).second;
+
+ // If nViewPos is in front of first field, we are finished.
+ if ( aIter == pMap->begin() )
+ break;
+
+ --aIter;
+
+ // nPrevPosModel is the field position
+ const sal_uInt32 nPrevPosModel = (*aIter).first;
+ const sal_uInt32 nPrevPosExpand = (*aIter).second;
+
+ const sal_uInt32 nLengthModel = nPosModel - nPrevPosModel;
+ const sal_uInt32 nLengthExpand = nPosExpand - nPrevPosExpand;
+
+ const sal_uInt32 nFieldLengthExpand = nLengthExpand - nLengthModel + 1;
+ const sal_uInt32 nFieldEndExpand = nPrevPosExpand + nFieldLengthExpand;
+
+ // Check if nPos is outside of field:
+ if ( nFieldEndExpand <= nViewPos )
+ {
+ // nPos is outside of field:
+ const sal_uInt32 nDistToField = nViewPos - nFieldEndExpand + 1;
+ aRet.mnPos = nPrevPosModel + nDistToField;
+ }
+ else
+ {
+ // nViewPos is inside a field:
+ aRet.mnPos = nPrevPosModel;
+ aRet.mnSubPos = nViewPos - nPrevPosExpand;
+ aRet.mbIsField = true;
+ }
+
+ break;
+ }
+ }
+
+ return aRet;
+}
+
+} // namespace ModelToViewStringConverter end
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/ndhints.cxx b/sw/source/core/txtnode/ndhints.cxx
new file mode 100644
index 000000000000..d0e0974f2ed0
--- /dev/null
+++ b/sw/source/core/txtnode/ndhints.cxx
@@ -0,0 +1,431 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include "txatbase.hxx"
+#include "ndhints.hxx"
+#include <txtatr.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <pam.hxx>
+#endif
+
+
+_SV_IMPL_SORTAR_ALG( SwpHtStart, SwTxtAttr* )
+_SV_IMPL_SORTAR_ALG( SwpHtEnd, SwTxtAttr* )
+
+inline void DumpHints(const SwpHtStart &, const SwpHtEnd &) { }
+
+/*************************************************************************
+ * inline IsEqual()
+ *************************************************************************/
+
+inline sal_Bool IsEqual( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
+{
+ return (long)(&rHt1) == (long)(&rHt2);
+}
+
+/*************************************************************************
+ * IsLessStart()
+ *************************************************************************/
+
+// SV_IMPL_OP_PTRARR_SORT( SwpHtStart, SwTxtAttr* )
+// kein SV_IMPL_PTRARR_SORT( name,ArrElement )
+// unser SEEK_PTR_TO_OBJECT_NOTL( name,ArrElement )
+
+// Sortierreihenfolge: Start, Ende (umgekehrt!), Which-Wert (umgekehrt!),
+// als letztes die Adresse selbst
+
+static sal_Bool lcl_IsLessStart( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
+{
+ if ( *rHt1.GetStart() == *rHt2.GetStart() )
+ {
+ const xub_StrLen nHt1 = *rHt1.GetAnyEnd();
+ const xub_StrLen nHt2 = *rHt2.GetAnyEnd();
+ if ( nHt1 == nHt2 )
+ {
+ const sal_uInt16 nWhich1 = rHt1.Which();
+ const sal_uInt16 nWhich2 = rHt2.Which();
+ if ( nWhich1 == nWhich2 )
+ {
+ if ( RES_TXTATR_CHARFMT == nWhich1 )
+ {
+ const sal_uInt16 nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
+ const sal_uInt16 nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
+ OSL_ENSURE( nS1 != nS2, "AUTOSTYLES: lcl_IsLessStart trouble" );
+ if ( nS1 != nS2 ) // robust
+ return nS1 < nS2;
+ }
+
+ return (long)&rHt1 < (long)&rHt2;
+ }
+ // order is important! for requirements see hintids.hxx
+ return ( nWhich1 > nWhich2 );
+ }
+ return ( nHt1 > nHt2 );
+ }
+ return ( *rHt1.GetStart() < *rHt2.GetStart() );
+}
+
+/*************************************************************************
+ * inline IsLessEnd()
+ *************************************************************************/
+
+// Zuerst nach Ende danach nach Ptr
+static sal_Bool lcl_IsLessEnd( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
+{
+ const xub_StrLen nHt1 = *rHt1.GetAnyEnd();
+ const xub_StrLen nHt2 = *rHt2.GetAnyEnd();
+ if ( nHt1 == nHt2 )
+ {
+ if ( *rHt1.GetStart() == *rHt2.GetStart() )
+ {
+ const sal_uInt16 nWhich1 = rHt1.Which();
+ const sal_uInt16 nWhich2 = rHt2.Which();
+ if ( nWhich1 == nWhich2 )
+ {
+ if ( RES_TXTATR_CHARFMT == nWhich1 )
+ {
+ const sal_uInt16 nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
+ const sal_uInt16 nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
+ OSL_ENSURE( nS1 != nS2, "AUTOSTYLES: lcl_IsLessEnd trouble" );
+ if ( nS1 != nS2 ) // robust
+ return nS1 > nS2;
+ }
+
+ return (long)&rHt1 > (long)&rHt2;
+ }
+ // order is important! for requirements see hintids.hxx
+ return ( nWhich1 < nWhich2 );
+ }
+ else
+ return ( *rHt1.GetStart() > *rHt2.GetStart() );
+ }
+ return ( nHt1 < nHt2 );
+}
+
+/*************************************************************************
+ * SwpHtStart::Seek_Entry()
+ *************************************************************************/
+
+sal_Bool SwpHtStart::Seek_Entry( const SwTxtAttr *pElement, sal_uInt16 *pPos ) const
+{
+ sal_uInt16 nOben = Count(), nMitte, nUnten = 0;
+ if( nOben > 0 )
+ {
+ nOben--;
+ while( nUnten <= nOben )
+ {
+ nMitte = nUnten + ( nOben - nUnten ) / 2;
+ const SwTxtAttr *pMitte = (*this)[nMitte];
+ if( IsEqual( *pMitte, *pElement ) )
+ {
+ *pPos = nMitte;
+ return sal_True;
+ }
+ else
+ if( lcl_IsLessStart( *pMitte, *pElement ) )
+ nUnten = nMitte + 1;
+ else
+ if( nMitte == 0 )
+ {
+ *pPos = nUnten;
+ return sal_False;
+ }
+ else
+ nOben = nMitte - 1;
+ }
+ }
+ *pPos = nUnten;
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwpHtEnd::Seek_Entry()
+ *************************************************************************/
+
+sal_Bool SwpHtEnd::Seek_Entry( const SwTxtAttr *pElement, sal_uInt16 *pPos ) const
+{
+ sal_uInt16 nOben = Count(), nMitte, nUnten = 0;
+ if( nOben > 0 )
+ {
+ nOben--;
+ while( nUnten <= nOben )
+ {
+ nMitte = nUnten + ( nOben - nUnten ) / 2;
+ const SwTxtAttr *pMitte = (*this)[nMitte];
+ if( IsEqual( *pMitte, *pElement ) )
+ {
+ *pPos = nMitte;
+ return sal_True;
+ }
+ else
+ if( lcl_IsLessEnd( *pMitte, *pElement ) )
+ nUnten = nMitte + 1;
+ else
+ if( nMitte == 0 )
+ {
+ *pPos = nUnten;
+ return sal_False;
+ }
+ else
+ nOben = nMitte - 1;
+ }
+ }
+ *pPos = nUnten;
+ return sal_False;
+}
+
+/*************************************************************************
+ * class SwpHintsArr
+ *************************************************************************/
+
+void SwpHintsArray::Insert( const SwTxtAttr *pHt )
+{
+ Resort();
+#if OSL_DEBUG_LEVEL > 1
+ sal_uInt16 nPos;
+ OSL_ENSURE(!m_HintStarts.Seek_Entry( pHt, &nPos ),
+ "Insert: hint already in HtStart");
+ OSL_ENSURE(!m_HintEnds.Seek_Entry( pHt, &nPos ),
+ "Insert: hint already in HtEnd");
+#endif
+ m_HintStarts.Insert( pHt );
+ m_HintEnds.Insert( pHt );
+}
+
+void SwpHintsArray::DeleteAtPos( const sal_uInt16 nPos )
+{
+ // optimization: nPos is the position in the Starts array
+ const SwTxtAttr *pHt = m_HintStarts[ nPos ];
+ m_HintStarts.Remove( nPos );
+
+ Resort();
+
+ sal_uInt16 nEndPos;
+ m_HintEnds.Seek_Entry( pHt, &nEndPos );
+ m_HintEnds.Remove( nEndPos );
+}
+
+#if OSL_DEBUG_LEVEL > 1
+
+/*************************************************************************
+ * SwpHintsArray::Check()
+ *************************************************************************/
+
+
+#define CHECK_ERR(cond, text) \
+ if(!(cond)) \
+ { \
+ OSL_ENSURE(!this, text); \
+ DumpHints(m_HintStarts, m_HintEnds); \
+ return !(const_cast<SwpHintsArray*>(this))->Resort(); \
+ }
+
+bool SwpHintsArray::Check() const
+{
+ // 1) gleiche Anzahl in beiden Arrays
+ CHECK_ERR( m_HintStarts.Count() == m_HintEnds.Count(),
+ "HintsCheck: wrong sizes" );
+ xub_StrLen nLastStart = 0;
+ xub_StrLen nLastEnd = 0;
+
+ const SwTxtAttr *pLastStart = 0;
+ const SwTxtAttr *pLastEnd = 0;
+
+ for( sal_uInt16 i = 0; i < Count(); ++i )
+ {
+ // --- Start-Kontrolle ---
+
+ // 2a) gueltiger Pointer? vgl. DELETEFF
+ const SwTxtAttr *pHt = m_HintStarts[i];
+ CHECK_ERR( 0xFF != *(unsigned char*)pHt, "HintsCheck: start ptr was deleted" );
+
+ // 3a) Stimmt die Start-Sortierung?
+ xub_StrLen nIdx = *pHt->GetStart();
+ CHECK_ERR( nIdx >= nLastStart, "HintsCheck: starts are unsorted" );
+
+ // 4a) IsLessStart-Konsistenz
+ if( pLastStart )
+ CHECK_ERR( lcl_IsLessStart( *pLastStart, *pHt ), "HintsCheck: IsLastStart" );
+
+ nLastStart = nIdx;
+ pLastStart = pHt;
+
+ // --- End-Kontrolle ---
+
+ // 2b) gueltiger Pointer? vgl. DELETEFF
+ const SwTxtAttr *pHtEnd = m_HintEnds[i];
+ CHECK_ERR( 0xFF != *(unsigned char*)pHtEnd, "HintsCheck: end ptr was deleted" );
+
+ // 3b) Stimmt die End-Sortierung?
+ nIdx = *pHtEnd->GetAnyEnd();
+ CHECK_ERR( nIdx >= nLastEnd, "HintsCheck: ends are unsorted" );
+ nLastEnd = nIdx;
+
+ // 4b) IsLessEnd-Konsistenz
+ if( pLastEnd )
+ CHECK_ERR( lcl_IsLessEnd( *pLastEnd, *pHtEnd ), "HintsCheck: IsLastEnd" );
+
+ nLastEnd = nIdx;
+ pLastEnd = pHtEnd;
+
+ // --- Ueberkreuzungen ---
+
+ // 5) gleiche Pointer in beiden Arrays
+ if( !m_HintStarts.Seek_Entry( pHt, &nIdx ) )
+ nIdx = STRING_LEN;
+
+ CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetStartOf" );
+
+ // 6) gleiche Pointer in beiden Arrays
+ if( !m_HintEnds.Seek_Entry( pHt, &nIdx ) )
+ nIdx = STRING_LEN;
+
+ CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetEndOf" );
+
+ // 7a) character attributes in array?
+ sal_uInt16 nWhich = pHt->Which();
+ CHECK_ERR( !isCHRATR(nWhich),
+ "HintsCheck: Character attribute in start array" );
+
+ // 7b) character attributes in array?
+ nWhich = pHtEnd->Which();
+ CHECK_ERR( !isCHRATR(nWhich),
+ "HintsCheck: Character attribute in end array" );
+
+ // 8) style portion check
+ const SwTxtAttr* pHtThis = m_HintStarts[i];
+ const SwTxtAttr* pHtLast = i > 0 ? m_HintStarts[i-1] : 0;
+ CHECK_ERR( 0 == i ||
+ ( RES_TXTATR_CHARFMT != pHtLast->Which() && RES_TXTATR_AUTOFMT != pHtLast->Which() ) ||
+ ( RES_TXTATR_CHARFMT != pHtThis->Which() && RES_TXTATR_AUTOFMT != pHtThis->Which() ) ||
+ ( *pHtThis->GetStart() >= *pHtLast->GetEnd() ) ||
+ ( ( ( (*pHtThis->GetStart() == *pHtLast->GetStart())
+ && (*pHtThis->GetEnd() == *pHtLast->GetEnd())
+ ) // same range
+ || (*pHtThis->GetStart() == *pHtThis->GetEnd())
+ )
+ && ( (pHtThis->Which() != RES_TXTATR_AUTOFMT)
+ || (pHtLast->Which() != RES_TXTATR_AUTOFMT)
+ ) // never two AUTOFMT on same range
+ ),
+ "HintsCheck: Portion inconsistency. "
+ "This can be temporarily ok during undo operations" );
+
+ // 9) nesting portion check
+ if (pHtThis->IsNesting())
+ {
+ for ( sal_uInt16 j = 0; j < Count(); ++j )
+ {
+ SwTxtAttr const * const pOther( m_HintStarts[j] );
+ if ( pOther->IsNesting() && (i != j) )
+ {
+ SwComparePosition cmp = ComparePosition(
+ *pHtThis->GetStart(), *pHtThis->GetEnd(),
+ *pOther->GetStart(), *pOther->GetEnd());
+ CHECK_ERR( (POS_OVERLAP_BEFORE != cmp) &&
+ (POS_OVERLAP_BEHIND != cmp),
+ "HintsCheck: overlapping nesting hints!!!" );
+ }
+ }
+ }
+
+ // 10) dummy char check (unfortunately cannot check SwTxtNode::m_Text)
+ if (pHtThis->HasDummyChar())
+ {
+ for ( sal_uInt16 j = 0; j < i; ++j )
+ {
+ SwTxtAttr const * const pOther( m_HintStarts[j] );
+ if (pOther->HasDummyChar())
+ {
+ CHECK_ERR( (*pOther->GetStart() != *pHtThis->GetStart()),
+ "HintsCheck: multiple hints claim same CH_TXTATR!");
+ }
+ }
+ }
+ }
+ return true;
+}
+
+#endif /* PRODUCT */
+
+/*************************************************************************
+ * SwpHintsArray::Resort()
+ *************************************************************************/
+
+// Resort() wird vor jedem Insert und Delete gerufen.
+// Wenn Textmasse geloescht wird, so werden die Indizes in
+// ndtxt.cxx angepasst. Leider erfolgt noch keine Neusortierung
+// auf gleichen Positionen.
+
+bool SwpHintsArray::Resort()
+{
+ bool bResort = false;
+ const SwTxtAttr *pLast = 0;
+ sal_uInt16 i;
+
+ for ( i = 0; i < m_HintStarts.Count(); ++i )
+ {
+ const SwTxtAttr *pHt = m_HintStarts[i];
+ if( pLast && !lcl_IsLessStart( *pLast, *pHt ) )
+ {
+ m_HintStarts.Remove( i );
+ m_HintStarts.Insert( pHt );
+ pHt = m_HintStarts[i];
+ if ( pHt != pLast )
+ --i;
+ bResort = true;
+ }
+ pLast = pHt;
+ }
+
+ pLast = 0;
+ for ( i = 0; i < m_HintEnds.Count(); ++i )
+ {
+ const SwTxtAttr *pHt = m_HintEnds[i];
+ if( pLast && !lcl_IsLessEnd( *pLast, *pHt ) )
+ {
+ m_HintEnds.Remove( i );
+ m_HintEnds.Insert( pHt );
+ pHt = m_HintEnds[i]; // normalerweise == pLast
+ // Wenn die Unordnung etwas groesser ist (24200),
+ // muessen wir Position i erneut vergleichen.
+ if ( pLast != pHt )
+ --i;
+ bResort = true;
+ }
+ pLast = pHt;
+ }
+ return bResort;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
new file mode 100644
index 000000000000..52e99ff519e8
--- /dev/null
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -0,0 +1,4829 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+#include <hintids.hxx>
+#include <hints.hxx>
+
+#include <editeng/fontitem.hxx>
+#include <editeng/brkitem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <svl/urihelper.hxx>
+#ifndef _SVSTDARR_HXX
+#define _SVSTDARR_ULONGS
+#include <svl/svstdarr.hxx>
+#endif
+#include <svl/ctloptions.hxx>
+#include <swmodule.hxx>
+#include <txtfld.hxx>
+#include <txtinet.hxx>
+#include <fmtinfmt.hxx>
+#include <fmtpdsc.hxx>
+#include <txtatr.hxx>
+#include <fmtrfmrk.hxx>
+#include <txttxmrk.hxx>
+#include <fchrfmt.hxx>
+#include <txtftn.hxx>
+#include <fmtflcnt.hxx>
+#include <fmtfld.hxx>
+#include <frmatr.hxx>
+#include <charatr.hxx>
+#include <ftnidx.hxx>
+#include <ftninfo.hxx>
+#include <fmtftn.hxx>
+#include <fmtmeta.hxx>
+#include <charfmt.hxx>
+#include <ndtxt.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <docary.hxx>
+#include <pam.hxx> // fuer SwPosition
+#include <fldbas.hxx>
+#include <paratr.hxx>
+#include <txtfrm.hxx>
+#include <ftnfrm.hxx>
+#include <ftnboss.hxx>
+#include <rootfrm.hxx>
+#include <pagedesc.hxx> // fuer SwPageDesc
+#include <expfld.hxx> // fuer SwTblField
+#include <section.hxx> // fuer SwSection
+#include <mvsave.hxx>
+#include <swcache.hxx>
+#include <SwGrammarMarkUp.hxx>
+#include <dcontact.hxx>
+#include <redline.hxx>
+#include <doctxm.hxx>
+#include <IMark.hxx>
+#include <scriptinfo.hxx>
+#include <istyleaccess.hxx>
+#include <SwStyleNameMapper.hxx>
+#include <numrule.hxx>
+#include <swtable.hxx>
+#include <docsh.hxx>
+#include <SwNodeNum.hxx>
+#include <svl/intitem.hxx>
+#include <list.hxx>
+#include <switerator.hxx>
+#include <attrhint.hxx>
+
+
+using namespace ::com::sun::star;
+
+
+SV_DECL_PTRARR( TmpHints, SwTxtAttr*, 0, 4 )
+
+TYPEINIT1( SwTxtNode, SwCntntNode )
+
+SV_DECL_PTRARR(SwpHts,SwTxtAttr*,1,1)
+
+// Leider ist das SwpHints nicht ganz wasserdicht:
+// Jeder darf an den Hints rumfummeln, ohne die Sortierreihenfolge
+// und Verkettung sicherstellen zu muessen.
+#if OSL_DEBUG_LEVEL > 1
+#define CHECK_SWPHINTS(pNd) { if( pNd->GetpSwpHints() && \
+ !pNd->GetDoc()->IsInReading() ) \
+ pNd->GetpSwpHints()->Check(); }
+#else
+#define CHECK_SWPHINTS(pNd)
+#endif
+
+SwTxtNode *SwNodes::MakeTxtNode( const SwNodeIndex & rWhere,
+ SwTxtFmtColl *pColl,
+ SwAttrSet* pAutoAttr )
+{
+ OSL_ENSURE( pColl, "Collectionpointer ist 0." );
+
+ SwTxtNode *pNode = new SwTxtNode( rWhere, pColl, pAutoAttr );
+
+ SwNodeIndex aIdx( *pNode );
+
+ // #125329#
+ // call method <UpdateOutlineNode(..)> only for the document nodes array
+ if ( IsDocNodes() )
+ UpdateOutlineNode(*pNode);
+
+ //Wenn es noch kein Layout gibt oder in einer versteckten Section
+ // stehen, brauchen wir uns um das MakeFrms nicht bemuehen.
+ const SwSectionNode* pSectNd;
+ if( !GetDoc()->GetCurrentViewShell() || //swmod 071108//swmod 071225
+ ( 0 != (pSectNd = pNode->FindSectionNode()) &&
+ pSectNd->GetSection().IsHiddenFlag() ))
+ return pNode;
+
+ SwNodeIndex aTmp( rWhere );
+ do {
+ // max. 2 Durchlaeufe:
+ // 1. den Nachfolger nehmen
+ // 2. den Vorgaenger
+
+ SwNode * pNd = & aTmp.GetNode();
+ switch (pNd->GetNodeType())
+ {
+ case ND_TABLENODE:
+ ((SwTableNode*)pNd)->MakeFrms( aIdx );
+ return pNode;
+
+ case ND_SECTIONNODE:
+ if( ((SwSectionNode*)pNd)->GetSection().IsHidden() ||
+ ((SwSectionNode*)pNd)->IsCntntHidden() )
+ {
+ SwNodeIndex aTmpIdx( *pNode );
+ pNd = FindPrvNxtFrmNode( aTmpIdx, pNode );
+ if( !pNd )
+ return pNode;
+ aTmp = *pNd;
+ break;
+ }
+ ((SwSectionNode*)pNd)->MakeFrms( aIdx );
+ return pNode;
+
+ case ND_TEXTNODE:
+ case ND_GRFNODE:
+ case ND_OLENODE:
+ ((SwCntntNode*)pNd)->MakeFrms( *pNode );
+ return pNode;
+
+ case ND_ENDNODE:
+ if( pNd->StartOfSectionNode()->IsSectionNode() &&
+ aTmp.GetIndex() < rWhere.GetIndex() )
+ {
+ if( pNd->StartOfSectionNode()->GetSectionNode()->GetSection().IsHiddenFlag())
+ {
+ if( !GoPrevSection( &aTmp, sal_True, sal_False ) ||
+ aTmp.GetNode().FindTableNode() !=
+ pNode->FindTableNode() )
+ return pNode; // schade, das wars
+ }
+ else
+ aTmp = *pNd->StartOfSectionNode();
+ break;
+ }
+ else if( pNd->StartOfSectionNode()->IsTableNode() &&
+ aTmp.GetIndex() < rWhere.GetIndex() )
+ {
+ // wir stehen hinter einem TabellenNode
+ aTmp = *pNd->StartOfSectionNode();
+ break;
+ }
+ // kein break !!!
+ default:
+ if( rWhere == aTmp )
+ aTmp -= 2;
+ else
+ return pNode;
+ break;
+ }
+ } while( sal_True );
+}
+
+// --------------------
+// SwTxtNode
+// --------------------
+
+SwTxtNode::SwTxtNode( const SwNodeIndex &rWhere,
+ SwTxtFmtColl *pTxtColl,
+ const SfxItemSet* pAutoAttr )
+ : SwCntntNode( rWhere, ND_TEXTNODE, pTxtColl ),
+ m_pSwpHints( 0 ),
+ mpNodeNum( 0 ),
+ m_bLastOutlineState( false ),
+ m_bNotifiable( false ),
+ // #i70748#
+ mbEmptyListStyleSetDueToSetOutlineLevelAttr( false ),
+ mbInSetOrResetAttr( false ),
+ mpList( 0 )
+{
+ InitSwParaStatistics( true );
+
+ // soll eine Harte-Attributierung gesetzt werden?
+ if( pAutoAttr )
+ SetAttr( *pAutoAttr );
+
+ if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 )
+ {
+ // #i101516#
+ // apply paragraph style's assigned outline style list level as
+ // list level of the paragraph, if it has none set already.
+ if ( !HasAttrListLevel() &&
+ pTxtColl && pTxtColl->IsAssignedToListLevelOfOutlineStyle() )
+ {
+ SetAttrListLevel( pTxtColl->GetAssignedOutlineStyleLevel() );
+ }
+ AddToList();
+ }
+ GetNodes().UpdateOutlineNode(*this);
+
+ m_bNotifiable = true;
+
+ m_bContainsHiddenChars = m_bHiddenCharsHidePara = false;
+ m_bRecalcHiddenCharFlags = true;
+}
+
+SwTxtNode::~SwTxtNode()
+{
+ // delete loescht nur die Pointer, nicht die Arrayelemente!
+ if ( m_pSwpHints )
+ {
+ // damit Attribute die ihren Inhalt entfernen nicht doppelt
+ // geloescht werden.
+ SwpHints* pTmpHints = m_pSwpHints;
+ m_pSwpHints = 0;
+
+ for( sal_uInt16 j = pTmpHints->Count(); j; )
+ // erst muss das Attribut aus dem Array entfernt werden,
+ // denn sonst wuerde es sich selbst loeschen (Felder) !!!!
+ DestroyAttr( pTmpHints->GetTextHint( --j ) );
+
+ delete pTmpHints;
+ }
+
+ RemoveFromList();
+
+ InitSwParaStatistics( false );
+}
+
+SwCntntFrm *SwTxtNode::MakeFrm( SwFrm* pSib )
+{
+ SwCntntFrm *pFrm = new SwTxtFrm( this, pSib );
+ return pFrm;
+}
+
+xub_StrLen SwTxtNode::Len() const
+{
+ return m_Text.Len();
+}
+
+/*---------------------------------------------------------------------------
+ * lcl_ChangeFtnRef
+ * After a split node, it's necessary to actualize the ref-pointer of the
+ * ftnfrms.
+ * --------------------------------------------------------------------------*/
+
+void lcl_ChangeFtnRef( SwTxtNode &rNode )
+{
+ SwpHints *pSwpHints = rNode.GetpSwpHints();
+ if( pSwpHints && rNode.GetDoc()->GetCurrentViewShell() ) //swmod 071108//swmod 071225
+ {
+ SwTxtAttr* pHt;
+ SwCntntFrm* pFrm = NULL;
+ // OD 07.11.2002 #104840# - local variable to remember first footnote
+ // of node <rNode> in order to invalidate position of its first content.
+ // Thus, in its <MakeAll()> it will checked its position relative to its reference.
+ SwFtnFrm* pFirstFtnOfNode = 0;
+ for( sal_uInt16 j = pSwpHints->Count(); j; )
+ {
+ pHt = pSwpHints->GetTextHint(--j);
+ if (RES_TXTATR_FTN == pHt->Which())
+ {
+ if( !pFrm )
+ {
+ pFrm = SwIterator<SwCntntFrm,SwTxtNode>::FirstElement( rNode );
+ if( !pFrm )
+ return;
+ }
+ SwTxtFtn *pAttr = (SwTxtFtn*)pHt;
+ OSL_ENSURE( pAttr->GetStartNode(), "FtnAtr ohne StartNode." );
+ SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
+ SwCntntNode *pNd = aIdx.GetNode().GetCntntNode();
+ if ( !pNd )
+ pNd = pFrm->GetAttrSet()->GetDoc()->
+ GetNodes().GoNextSection( &aIdx, sal_True, sal_False );
+ if ( !pNd )
+ continue;
+
+ SwIterator<SwCntntFrm,SwCntntNode> aIter( *pNd );
+ SwCntntFrm* pCntnt = aIter.First();
+ if( pCntnt )
+ {
+ OSL_ENSURE( pCntnt->getRootFrm() == pFrm->getRootFrm(),
+ "lcl_ChangeFtnRef: Layout double?" );
+ SwFtnFrm *pFtn = pCntnt->FindFtnFrm();
+ if( pFtn && pFtn->GetAttr() == pAttr )
+ {
+ while( pFtn->GetMaster() )
+ pFtn = pFtn->GetMaster();
+ // #104840# - remember footnote frame
+ pFirstFtnOfNode = pFtn;
+ while ( pFtn )
+ {
+ pFtn->SetRef( pFrm );
+ pFtn = pFtn->GetFollow();
+ ((SwTxtFrm*)pFrm)->SetFtn( sal_True );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ while( 0 != (pCntnt = aIter.Next()) )
+ {
+ SwFtnFrm *pDbgFtn = pCntnt->FindFtnFrm();
+ OSL_ENSURE( !pDbgFtn || pDbgFtn->GetRef() == pFrm,
+ "lcl_ChangeFtnRef: Who's that guy?" );
+ }
+#endif
+ }
+ }
+ } // end of for-loop on <SwpHints>
+ // #104840# - invalidate
+ if ( pFirstFtnOfNode )
+ {
+ SwCntntFrm* pCntnt = pFirstFtnOfNode->ContainsCntnt();
+ if ( pCntnt )
+ {
+ pCntnt->_InvalidatePos();
+ }
+ }
+ }
+}
+
+SwCntntNode *SwTxtNode::SplitCntntNode( const SwPosition &rPos )
+{
+ bool parentIsOutline = IsOutline();
+
+ // lege den Node "vor" mir an
+ const xub_StrLen nSplitPos = rPos.nContent.GetIndex();
+ const xub_StrLen nTxtLen = m_Text.Len();
+ SwTxtNode* const pNode =
+ _MakeNewTxtNode( rPos.nNode, sal_False, nSplitPos==nTxtLen );
+
+ // the first paragraph gets the XmlId,
+ // _except_ if it is empty and the second is not empty
+ if (nSplitPos != 0) {
+ pNode->RegisterAsCopyOf(*this, true);
+ if (nSplitPos == nTxtLen)
+ {
+ this->RemoveMetadataReference();
+ // NB: SwUndoSplitNode will call pNode->JoinNext,
+ // which is sufficient even in this case!
+ }
+ }
+
+ ResetAttr( RES_PARATR_LIST_ISRESTART );
+ ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
+ ResetAttr( RES_PARATR_LIST_ISCOUNTED );
+ if ( GetNumRule() == 0 || (parentIsOutline && !IsOutline()) )
+ {
+ ResetAttr( RES_PARATR_LIST_ID );
+ ResetAttr( RES_PARATR_LIST_LEVEL );
+ }
+
+ if ( GetDepends() && m_Text.Len() && (nTxtLen / 2) < nSplitPos )
+ {
+// JP 25.04.95: Optimierung fuer SplitNode:
+// Wird am Ende vom Node gesplittet, dann verschiebe die
+// Frames vom akt. auf den neuen und erzeuge fuer den akt.
+// neue. Dadurch entfaellt das neu aufbauen vom Layout.
+
+ LockModify(); // Benachrichtigungen abschalten
+
+ // werden FlyFrames mit verschoben, so muessen diese nicht ihre
+ // Frames zerstoeren. Im SwTxtFly::SetAnchor wird es abgefragt!
+ if ( HasHints() )
+ {
+ pNode->GetOrCreateSwpHints().SetInSplitNode(true);
+ }
+
+ //Ersten Teil des Inhalts in den neuen Node uebertragen und
+ //im alten Node loeschen.
+ SwIndex aIdx( this );
+ CutText( pNode, aIdx, nSplitPos );
+
+ if( GetWrong() )
+ {
+ pNode->SetWrong( GetWrong()->SplitList( nSplitPos ) );
+ }
+ SetWrongDirty( true );
+
+ if( GetGrammarCheck() )
+ {
+ pNode->SetGrammarCheck( GetGrammarCheck()->SplitGrammarList( nSplitPos ) );
+ }
+ SetGrammarCheckDirty( true );
+
+ SetWordCountDirty( true );
+
+ // SMARTTAGS
+ if( GetSmartTags() )
+ {
+ pNode->SetSmartTags( GetSmartTags()->SplitList( nSplitPos ) );
+ }
+ SetSmartTagDirty( true );
+
+ if ( pNode->HasHints() )
+ {
+ if ( pNode->m_pSwpHints->CanBeDeleted() )
+ {
+ delete pNode->m_pSwpHints;
+ pNode->m_pSwpHints = 0;
+ }
+ else
+ {
+ pNode->m_pSwpHints->SetInSplitNode(false);
+ }
+
+ // alle zeichengebundenen Rahmen, die im neuen Absatz laden
+ // muessen aus den alten Frame entfernt werden:
+ // JP 01.10.96: alle leeren und nicht zu expandierenden
+ // Attribute loeschen
+ if ( HasHints() )
+ {
+ for ( sal_uInt16 j = m_pSwpHints->Count(); j; )
+ {
+ SwTxtAttr* const pHt = m_pSwpHints->GetTextHint( --j );
+ if ( RES_TXTATR_FLYCNT == pHt ->Which() )
+ {
+ pHt->GetFlyCnt().GetFrmFmt()->DelFrms();
+ }
+ else if ( pHt->DontExpand() )
+ {
+ const xub_StrLen* const pEnd = pHt->GetEnd();
+ if (pEnd && *pHt->GetStart() == *pEnd )
+ {
+ // delete it!
+ m_pSwpHints->DeleteAtPos( j );
+ DestroyAttr( pHt );
+ }
+ }
+ }
+ }
+
+ }
+
+ SwIterator<SwCntntFrm,SwTxtNode> aIter( *this );
+ for( SwCntntFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
+ {
+ pFrm->RegisterToNode( *pNode );
+ if( pFrm->IsTxtFrm() && !pFrm->IsFollow() && ((SwTxtFrm*)pFrm)->GetOfst() )
+ ((SwTxtFrm*)pFrm)->SetOfst( 0 );
+ }
+
+ if ( IsInCache() )
+ {
+ SwFrm::GetCache().Delete( this );
+ SetInCache( sal_False );
+ }
+
+ UnlockModify(); // Benachrichtigungen wieder freischalten
+
+ // If there is an accessible layout we must call modify even
+ // with length zero, because we have to notify about the changed
+ // text node.
+ const SwRootFrm *pRootFrm;
+ if ( (nTxtLen != nSplitPos) ||
+ ( (pRootFrm = pNode->GetDoc()->GetCurrentLayout()) != 0 &&
+ pRootFrm->IsAnyShellAccessible() ) ) //swmod 080218
+ {
+ // dann sage den Frames noch, das am Ende etwas "geloescht" wurde
+ if( 1 == nTxtLen - nSplitPos )
+ {
+ SwDelChr aHint( nSplitPos );
+ pNode->NotifyClients( 0, &aHint );
+ }
+ else
+ {
+ SwDelTxt aHint( nSplitPos, nTxtLen - nSplitPos );
+ pNode->NotifyClients( 0, &aHint );
+ }
+ }
+ if ( HasHints() )
+ {
+ MoveTxtAttr_To_AttrSet();
+ }
+ pNode->MakeFrms( *this ); // neue Frames anlegen.
+ lcl_ChangeFtnRef( *this );
+ }
+ else
+ {
+ SwWrongList *pList = GetWrong();
+ SetWrong( 0, false );
+ SetWrongDirty( true );
+
+ SwGrammarMarkUp *pList3 = GetGrammarCheck();
+ SetGrammarCheck( 0, false );
+ SetGrammarCheckDirty( true );
+
+ SetWordCountDirty( true );
+
+ // SMARTTAGS
+ SwWrongList *pList2 = GetSmartTags();
+ SetSmartTags( 0, false );
+ SetSmartTagDirty( true );
+
+ SwIndex aIdx( this );
+ CutText( pNode, aIdx, nSplitPos );
+
+ // JP 01.10.96: alle leeren und nicht zu expandierenden
+ // Attribute loeschen
+ if ( HasHints() )
+ {
+ for ( sal_uInt16 j = m_pSwpHints->Count(); j; )
+ {
+ SwTxtAttr* const pHt = m_pSwpHints->GetTextHint( --j );
+ const xub_StrLen* const pEnd = pHt->GetEnd();
+ if ( pHt->DontExpand() && pEnd && (*pHt->GetStart() == *pEnd) )
+ {
+ // delete it!
+ m_pSwpHints->DeleteAtPos( j );
+ DestroyAttr( pHt );
+ }
+ }
+ MoveTxtAttr_To_AttrSet();
+ }
+
+ if( pList )
+ {
+ pNode->SetWrong( pList->SplitList( nSplitPos ) );
+ SetWrong( pList, false );
+ }
+
+ if( pList3 )
+ {
+ pNode->SetGrammarCheck( pList3->SplitGrammarList( nSplitPos ) );
+ SetGrammarCheck( pList3, false );
+ }
+
+ // SMARTTAGS
+ if( pList2 )
+ {
+ pNode->SetSmartTags( pList2->SplitList( nSplitPos ) );
+ SetSmartTags( pList2, false );
+ }
+
+ if ( GetDepends() )
+ {
+ MakeFrms( *pNode ); // neue Frames anlegen.
+ }
+ lcl_ChangeFtnRef( *pNode );
+ }
+
+ {
+ //Hint fuer Pagedesc versenden. Das mueste eigntlich das Layout im
+ //Paste der Frames selbst erledigen, aber das fuehrt dann wiederum
+ //zu weiteren Folgefehlern, die mit Laufzeitkosten geloest werden
+ //muesten. #56977# #55001# #56135#
+ const SfxPoolItem *pItem;
+ if( GetDepends() && SFX_ITEM_SET == pNode->GetSwAttrSet().
+ GetItemState( RES_PAGEDESC, sal_True, &pItem ) )
+ {
+ pNode->ModifyNotification( (SfxPoolItem*)pItem, (SfxPoolItem*)pItem );
+ }
+ }
+ return pNode;
+}
+
+void SwTxtNode::MoveTxtAttr_To_AttrSet()
+{
+ OSL_ENSURE( m_pSwpHints, "MoveTxtAttr_To_AttrSet without SwpHints?" );
+ for ( sal_uInt16 i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
+ {
+ SwTxtAttr *pHt = m_pSwpHints->GetTextHint(i);
+
+ if( *pHt->GetStart() )
+ break;
+
+ const xub_StrLen* pHtEndIdx = pHt->GetEnd();
+
+ if( !pHtEndIdx )
+ continue;
+
+ if ( *pHtEndIdx < m_Text.Len() || pHt->IsCharFmtAttr() )
+ break;
+
+ if( !pHt->IsDontMoveAttr() &&
+ SetAttr( pHt->GetAttr() ) )
+ {
+ m_pSwpHints->DeleteAtPos(i);
+ DestroyAttr( pHt );
+ --i;
+ }
+ }
+
+}
+
+SwCntntNode *SwTxtNode::JoinNext()
+{
+ SwNodes& rNds = GetNodes();
+ SwNodeIndex aIdx( *this );
+ if( SwCntntNode::CanJoinNext( &aIdx ) )
+ {
+ SwDoc* pDoc = rNds.GetDoc();
+ SvULongs aBkmkArr( 15, 15 );
+ _SaveCntntIdx( pDoc, aIdx.GetIndex(), USHRT_MAX, aBkmkArr, SAVEFLY );
+ SwTxtNode *pTxtNode = aIdx.GetNode().GetTxtNode();
+ xub_StrLen nOldLen = m_Text.Len();
+
+ // METADATA: merge
+ this->JoinMetadatable(*pTxtNode, !this->Len(), !pTxtNode->Len());
+
+ SwWrongList *pList = GetWrong();
+ if( pList )
+ {
+ pList->JoinList( pTxtNode->GetWrong(), nOldLen );
+ SetWrongDirty( true );
+ SetWrong( 0, false );
+ }
+ else
+ {
+ pList = pTxtNode->GetWrong();
+ if( pList )
+ {
+ pList->Move( 0, nOldLen );
+ SetWrongDirty( true );
+ pTxtNode->SetWrong( 0, false );
+ }
+ }
+
+ SwGrammarMarkUp *pList3 = GetGrammarCheck();
+ if( pList3 )
+ {
+ pList3->JoinGrammarList( pTxtNode->GetGrammarCheck(), nOldLen );
+ SetGrammarCheckDirty( true );
+ SetGrammarCheck( 0, false );
+ }
+ else
+ {
+ pList3 = pTxtNode->GetGrammarCheck();
+ if( pList3 )
+ {
+ pList3->MoveGrammar( 0, nOldLen );
+ SetGrammarCheckDirty( true );
+ pTxtNode->SetGrammarCheck( 0, false );
+ }
+ }
+
+ // SMARTTAGS
+ SwWrongList *pList2 = GetSmartTags();
+ if( pList2 )
+ {
+ pList2->JoinList( pTxtNode->GetSmartTags(), nOldLen );
+ SetSmartTagDirty( true );
+ SetSmartTags( 0, false );
+ }
+ else
+ {
+ pList2 = pTxtNode->GetSmartTags();
+ if( pList2 )
+ {
+ pList2->Move( 0, nOldLen );
+ SetSmartTagDirty( true );
+ pTxtNode->SetSmartTags( 0, false );
+ }
+ }
+
+ { // wg. SwIndex
+ pTxtNode->CutText( this, SwIndex(pTxtNode), pTxtNode->Len() );
+ }
+ // verschiebe noch alle Bookmarks/TOXMarks
+ if( aBkmkArr.Count() )
+ _RestoreCntntIdx( pDoc, aBkmkArr, GetIndex(), nOldLen );
+
+ if( pTxtNode->HasAnyIndex() )
+ {
+ // alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben
+ pDoc->CorrAbs( aIdx, SwPosition( *this ), nOldLen, sal_True );
+ }
+ rNds.Delete(aIdx);
+ SetWrong( pList, false );
+ SetGrammarCheck( pList3, false );
+ SetSmartTags( pList2, false ); // SMARTTAGS
+ InvalidateNumRule();
+ }
+ else {
+ OSL_FAIL( "kein TxtNode." );
+ }
+
+ return this;
+}
+
+SwCntntNode *SwTxtNode::JoinPrev()
+{
+ SwNodes& rNds = GetNodes();
+ SwNodeIndex aIdx( *this );
+ if( SwCntntNode::CanJoinPrev( &aIdx ) )
+ {
+ SwDoc* pDoc = rNds.GetDoc();
+ SvULongs aBkmkArr( 15, 15 );
+ _SaveCntntIdx( pDoc, aIdx.GetIndex(), USHRT_MAX, aBkmkArr, SAVEFLY );
+ SwTxtNode *pTxtNode = aIdx.GetNode().GetTxtNode();
+ xub_StrLen nLen = pTxtNode->Len();
+
+ SwWrongList *pList = pTxtNode->GetWrong();
+ if( pList )
+ {
+ pList->JoinList( GetWrong(), Len() );
+ SetWrongDirty( true );
+ pTxtNode->SetWrong( 0, false );
+ SetWrong( NULL );
+ }
+ else
+ {
+ pList = GetWrong();
+ if( pList )
+ {
+ pList->Move( 0, nLen );
+ SetWrongDirty( true );
+ SetWrong( 0, false );
+ }
+ }
+
+ SwGrammarMarkUp *pList3 = pTxtNode->GetGrammarCheck();
+ if( pList3 )
+ {
+ pList3->JoinGrammarList( GetGrammarCheck(), Len() );
+ SetGrammarCheckDirty( true );
+ pTxtNode->SetGrammarCheck( 0, false );
+ SetGrammarCheck( NULL );
+ }
+ else
+ {
+ pList3 = GetGrammarCheck();
+ if( pList3 )
+ {
+ pList3->MoveGrammar( 0, nLen );
+ SetGrammarCheckDirty( true );
+ SetGrammarCheck( 0, false );
+ }
+ }
+
+ // SMARTTAGS
+ SwWrongList *pList2 = pTxtNode->GetSmartTags();
+ if( pList2 )
+ {
+ pList2->JoinList( GetSmartTags(), Len() );
+ SetSmartTagDirty( true );
+ pTxtNode->SetSmartTags( 0, false );
+ SetSmartTags( NULL );
+ }
+ else
+ {
+ pList2 = GetSmartTags();
+ if( pList2 )
+ {
+ pList2->Move( 0, nLen );
+ SetSmartTagDirty( true );
+ SetSmartTags( 0, false );
+ }
+ }
+
+ { // wg. SwIndex
+ pTxtNode->CutText( this, SwIndex(this), SwIndex(pTxtNode), nLen );
+ }
+ // verschiebe noch alle Bookmarks/TOXMarks
+ if( aBkmkArr.Count() )
+ _RestoreCntntIdx( pDoc, aBkmkArr, GetIndex() );
+
+ if( pTxtNode->HasAnyIndex() )
+ {
+ // alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben
+ pDoc->CorrAbs( aIdx, SwPosition( *this ), nLen, sal_True );
+ }
+ rNds.Delete(aIdx);
+ SetWrong( pList, false );
+ SetGrammarCheck( pList3, false );
+ SetSmartTags( pList2, false );
+ InvalidateNumRule();
+ }
+ else {
+ OSL_FAIL( "kein TxtNode." );
+ }
+
+ return this;
+}
+
+// erzeugt einen AttrSet mit Bereichen fuer Frame-/Para/Char-Attributen
+void SwTxtNode::NewAttrSet( SwAttrPool& rPool )
+{
+ OSL_ENSURE( !mpAttrSet.get(), "AttrSet ist doch gesetzt" );
+ SwAttrSet aNewAttrSet( rPool, aTxtNodeSetRange );
+
+ // put names of parent style and conditional style:
+ const SwFmtColl* pAnyFmtColl = &GetAnyFmtColl();
+ const SwFmtColl* pFmtColl = GetFmtColl();
+ String sVal;
+ SwStyleNameMapper::FillProgName( pAnyFmtColl->GetName(), sVal, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
+ SfxStringItem aAnyFmtColl( RES_FRMATR_STYLE_NAME, sVal );
+ if ( pFmtColl != pAnyFmtColl )
+ SwStyleNameMapper::FillProgName( pFmtColl->GetName(), sVal, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
+ SfxStringItem aFmtColl( RES_FRMATR_CONDITIONAL_STYLE_NAME, sVal );
+ aNewAttrSet.Put( aAnyFmtColl );
+ aNewAttrSet.Put( aFmtColl );
+
+ aNewAttrSet.SetParent( &pAnyFmtColl->GetAttrSet() );
+ mpAttrSet = GetDoc()->GetIStyleAccess().getAutomaticStyle( aNewAttrSet, IStyleAccess::AUTO_STYLE_PARA );
+}
+
+
+// override SwIndexReg::Update => text hints do not need SwIndex for start/end!
+void SwTxtNode::Update( SwIndex const & rPos, const xub_StrLen nChangeLen,
+ const bool bNegative, const bool bDelete )
+{
+ SetAutoCompleteWordDirty( sal_True );
+
+ ::std::auto_ptr<TmpHints> pCollector;
+ const xub_StrLen nChangePos = rPos.GetIndex();
+
+ if ( HasHints() )
+ {
+ if ( bNegative )
+ {
+ const xub_StrLen nChangeEnd = nChangePos + nChangeLen;
+ for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
+ {
+ SwTxtAttr * const pHint = m_pSwpHints->GetTextHint(n);
+ xub_StrLen * const pStart = pHint->GetStart();
+ if ( *pStart > nChangePos )
+ {
+ if ( *pStart > nChangeEnd )
+ {
+ *pStart = *pStart - nChangeLen;
+ }
+ else
+ {
+ *pStart = nChangePos;
+ }
+ }
+
+ xub_StrLen * const pEnd = pHint->GetEnd();
+ if (pEnd)
+ {
+ if ( *pEnd > nChangePos )
+ {
+ if( *pEnd > nChangeEnd )
+ {
+ *pEnd = *pEnd - nChangeLen;
+ }
+ else
+ {
+ *pEnd = nChangePos;
+ }
+ }
+ }
+ }
+
+ m_pSwpHints->MergePortions( *this );
+ }
+ else
+ {
+ bool bNoExp = false;
+ bool bResort = false;
+ const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
+ static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
+
+ sal_Bool aDontExp[ coArrSz ];
+ memset( &aDontExp, 0, coArrSz * sizeof(sal_Bool) );
+
+ for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
+ {
+ SwTxtAttr * const pHint = m_pSwpHints->GetTextHint(n);
+ xub_StrLen * const pStart = pHint->GetStart();
+ xub_StrLen * const pEnd = pHint->GetEnd();
+ if ( *pStart >= nChangePos )
+ {
+ *pStart = *pStart + nChangeLen;
+ if ( pEnd )
+ {
+ *pEnd = *pEnd + nChangeLen;
+ }
+ }
+ else if ( pEnd && (*pEnd >= nChangePos) )
+ {
+ if ( (*pEnd > nChangePos) || IsIgnoreDontExpand() )
+ {
+ *pEnd = *pEnd + nChangeLen;
+ }
+ else // *pEnd == nChangePos
+ {
+ sal_uInt16 nWhPos;
+ const sal_uInt16 nWhich = pHint->Which();
+
+ OSL_ENSURE(!isCHRATR(nWhich), "Update: char attr hint?");
+ if (isCHRATR(nWhich) || isTXTATR_WITHEND(nWhich))
+ {
+ nWhPos = static_cast<sal_uInt16>(nWhich -
+ RES_CHRATR_BEGIN);
+ }
+ else
+ continue;
+
+ if( aDontExp[ nWhPos ] )
+ continue;
+
+ if ( pHint->DontExpand() )
+ {
+ pHint->SetDontExpand( false );
+ bResort = true;
+ if ( pHint->IsCharFmtAttr() )
+ {
+ bNoExp = true;
+ aDontExp[ static_cast<sal_uInt16>(RES_TXTATR_CHARFMT) - static_cast<sal_uInt16>(RES_CHRATR_BEGIN) ]
+ = sal_True;
+ aDontExp[ static_cast<sal_uInt16>(RES_TXTATR_INETFMT) - static_cast<sal_uInt16>(RES_CHRATR_BEGIN) ]
+ = sal_True;
+ }
+ else
+ aDontExp[ nWhPos ] = sal_True;
+ }
+ else if( bNoExp )
+ {
+ if ( !pCollector.get() )
+ {
+ pCollector.reset( new TmpHints );
+ }
+ sal_uInt16 nCollCnt = pCollector->Count();
+ for( sal_uInt16 i = 0; i < nCollCnt; ++i )
+ {
+ SwTxtAttr *pTmp = (*pCollector)[ i ];
+ if( nWhich == pTmp->Which() )
+ {
+ pCollector->Remove( i );
+ SwTxtAttr::Destroy( pTmp,
+ GetDoc()->GetAttrPool() );
+ break;
+ }
+ }
+ SwTxtAttr * const pTmp = MakeTxtAttr( *GetDoc(),
+ pHint->GetAttr(),
+ nChangePos, nChangePos + nChangeLen);
+ pCollector->C40_INSERT( SwTxtAttr, pTmp, pCollector->Count() );
+ }
+ else
+ {
+ *pEnd = *pEnd + nChangeLen;
+ }
+ }
+ }
+ }
+ if ( bResort )
+ {
+ m_pSwpHints->Resort();
+ }
+ }
+ }
+
+ SwIndexReg aTmpIdxReg;
+ if ( !bNegative && !bDelete )
+ {
+ const SwRedlineTbl& rTbl = GetDoc()->GetRedlineTbl();
+ for ( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
+ {
+ SwRedline *const pRedl = rTbl[ i ];
+ if ( pRedl->HasMark() )
+ {
+ SwPosition* const pEnd = pRedl->End();
+ if ( this == &pEnd->nNode.GetNode() &&
+ *pRedl->GetPoint() != *pRedl->GetMark() )
+ {
+ SwIndex & rIdx = pEnd->nContent;
+ if (nChangePos == rIdx.GetIndex())
+ {
+ rIdx.Assign( &aTmpIdxReg, rIdx.GetIndex() );
+ }
+ }
+ }
+ else if ( this == &pRedl->GetPoint()->nNode.GetNode() )
+ {
+ SwIndex & rIdx = pRedl->GetPoint()->nContent;
+ if (nChangePos == rIdx.GetIndex())
+ {
+ rIdx.Assign( &aTmpIdxReg, rIdx.GetIndex() );
+ // mst: FIXME: why does this adjust the unused position???
+ SwIndex * pIdx;
+ if ( &pRedl->GetBound( true ) == pRedl->GetPoint() )
+ {
+ pRedl->GetBound( false ) = pRedl->GetBound( true );
+ pIdx = &pRedl->GetBound( false ).nContent;
+ }
+ else
+ {
+ pRedl->GetBound( true ) = pRedl->GetBound( false );
+ pIdx = &pRedl->GetBound( true ).nContent;
+ }
+ pIdx->Assign( &aTmpIdxReg, pIdx->GetIndex() );
+ }
+ }
+ }
+
+ const IDocumentMarkAccess* const pMarkAccess = getIDocumentMarkAccess();
+ for(IDocumentMarkAccess::const_iterator_t ppMark =
+ pMarkAccess->getMarksBegin();
+ ppMark != pMarkAccess->getMarksEnd();
+ ppMark++)
+ {
+ // Bookmarks must never grow to either side, when
+ // editing (directly) to the left or right (#i29942#)!
+ // And a bookmark with same start and end must remain
+ // to the left of the inserted text (used in XML import).
+ const ::sw::mark::IMark* const pMark = ppMark->get();
+ const SwPosition* pEnd = &pMark->GetMarkEnd();
+ SwIndex & rIdx = const_cast<SwIndex&>(pEnd->nContent);
+ if( this == &pEnd->nNode.GetNode() &&
+ rPos.GetIndex() == rIdx.GetIndex() )
+ {
+ rIdx.Assign( &aTmpIdxReg, rIdx.GetIndex() );
+ }
+ }
+ }
+
+ // base class
+ SwIndexReg::Update( rPos, nChangeLen, bNegative, bDelete );
+
+ if ( pCollector.get() )
+ {
+ const sal_uInt16 nCount = pCollector->Count();
+ for ( sal_uInt16 i = 0; i < nCount; ++i )
+ {
+ m_pSwpHints->TryInsertHint( (*pCollector)[ i ], *this );
+ }
+ }
+
+ aTmpIdxReg.MoveTo( *this );
+}
+
+void SwTxtNode::_ChgTxtCollUpdateNum( const SwTxtFmtColl *pOldColl,
+ const SwTxtFmtColl *pNewColl)
+{
+ SwDoc* pDoc = GetDoc();
+ OSL_ENSURE( pDoc, "Kein Doc?" );
+ // erfrage die OutlineLevel und update gegebenenfalls das Nodes-Array,
+ // falls sich die Level geaendert haben !
+ const int nOldLevel = pOldColl && pOldColl->IsAssignedToListLevelOfOutlineStyle() ?
+ pOldColl->GetAssignedOutlineStyleLevel() : MAXLEVEL;
+ const int nNewLevel = pNewColl && pNewColl->IsAssignedToListLevelOfOutlineStyle() ?
+ pNewColl->GetAssignedOutlineStyleLevel() : MAXLEVEL;
+
+ if ( MAXLEVEL != nNewLevel )
+ {
+ SetAttrListLevel(nNewLevel);
+ }
+
+ {
+ if (pDoc)
+ pDoc->GetNodes().UpdateOutlineNode(*this);
+ }
+
+
+ SwNodes& rNds = GetNodes();
+ // Update beim Level 0 noch die Fussnoten !!
+ if( ( !nNewLevel || !nOldLevel) && pDoc->GetFtnIdxs().Count() &&
+ FTNNUM_CHAPTER == pDoc->GetFtnInfo().eNum &&
+ rNds.IsDocNodes() )
+ {
+ SwNodeIndex aTmpIndex( rNds, GetIndex());
+
+ pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
+ }
+
+ if( RES_CONDTXTFMTCOLL == pNewColl->Which() )
+ {
+ // Erfrage die akt. Condition des TextNodes:
+ ChkCondColl();
+ }
+}
+
+// Wenn man sich genau am Ende einer Text- bzw. INetvorlage befindet,
+// bekommt diese das DontExpand-Flag verpasst
+
+sal_Bool SwTxtNode::DontExpandFmt( const SwIndex& rIdx, bool bFlag,
+ sal_Bool bFmtToTxtAttributes )
+{
+ const xub_StrLen nIdx = rIdx.GetIndex();
+ if ( bFmtToTxtAttributes && nIdx == m_Text.Len() )
+ {
+ FmtToTxtAttr( this );
+ }
+
+ sal_Bool bRet = sal_False;
+ if ( HasHints() )
+ {
+ const sal_uInt16 nEndCnt = m_pSwpHints->GetEndCount();
+ sal_uInt16 nPos = nEndCnt;
+ while( nPos )
+ {
+ SwTxtAttr *pTmp = m_pSwpHints->GetEnd( --nPos );
+ xub_StrLen *pEnd = pTmp->GetEnd();
+ if( !pEnd || *pEnd > nIdx )
+ continue;
+ if( nIdx != *pEnd )
+ nPos = 0;
+ else if( bFlag != pTmp->DontExpand() && !pTmp->IsLockExpandFlag()
+ && *pEnd > *pTmp->GetStart())
+ {
+ bRet = sal_True;
+ m_pSwpHints->NoteInHistory( pTmp );
+ pTmp->SetDontExpand( bFlag );
+ }
+ }
+ }
+ return bRet;
+}
+
+static bool lcl_GetTxtAttrDefault(xub_StrLen const nIndex,
+ xub_StrLen const nHintStart, xub_StrLen const nHintEnd)
+{
+ return ((nHintStart <= nIndex) && (nIndex < nHintEnd));
+}
+static bool lcl_GetTxtAttrExpand(xub_StrLen const nIndex,
+ xub_StrLen const nHintStart, xub_StrLen const nHintEnd)
+{
+ return ((nHintStart < nIndex) && (nIndex <= nHintEnd));
+}
+static bool lcl_GetTxtAttrParent(xub_StrLen const nIndex,
+ xub_StrLen const nHintStart, xub_StrLen const nHintEnd)
+{
+ return ((nHintStart < nIndex) && (nIndex < nHintEnd));
+}
+
+static void
+lcl_GetTxtAttrs(
+ ::std::vector<SwTxtAttr *> *const pVector, SwTxtAttr **const ppTxtAttr,
+ SwpHints *const pSwpHints,
+ xub_StrLen const nIndex, RES_TXTATR const nWhich,
+ enum SwTxtNode::GetTxtAttrMode const eMode)
+{
+ sal_uInt16 const nSize = (pSwpHints) ? pSwpHints->Count() : 0;
+ xub_StrLen nPreviousIndex(0); // index of last hint with nWhich
+ bool (*pMatchFunc)(xub_StrLen const, xub_StrLen const, xub_StrLen const)=0;
+ switch (eMode)
+ {
+ case SwTxtNode::DEFAULT: pMatchFunc = &lcl_GetTxtAttrDefault; break;
+ case SwTxtNode::EXPAND: pMatchFunc = &lcl_GetTxtAttrExpand; break;
+ case SwTxtNode::PARENT: pMatchFunc = &lcl_GetTxtAttrParent; break;
+ default: OSL_ASSERT(false);
+ }
+
+ for( sal_uInt16 i = 0; i < nSize; ++i )
+ {
+ SwTxtAttr *const pHint = pSwpHints->GetTextHint(i);
+ xub_StrLen const nHintStart( *(pHint->GetStart()) );
+ if (nIndex < nHintStart)
+ {
+ return; // hints are sorted by start, so we are done...
+ }
+
+ if (pHint->Which() != nWhich)
+ {
+ continue;
+ }
+
+ xub_StrLen const*const pEndIdx = pHint->GetEnd();
+ OSL_ENSURE(pEndIdx || pHint->HasDummyChar(),
+ "hint with no end and no dummy char?");
+ // Wenn bExpand gesetzt ist, wird das Verhalten bei Eingabe
+ // simuliert, d.h. der Start wuede verschoben, das Ende expandiert,
+ bool const bContained( (pEndIdx)
+ ? (*pMatchFunc)(nIndex, nHintStart, *pEndIdx)
+ : (nHintStart == nIndex) );
+ if (bContained)
+ {
+ if (pVector)
+ {
+ if (nPreviousIndex < nHintStart)
+ {
+ pVector->clear(); // clear hints that are outside pHint
+ nPreviousIndex = nHintStart;
+ }
+ pVector->push_back(pHint);
+ }
+ else
+ {
+ *ppTxtAttr = pHint; // and possibly overwrite outer hint
+ }
+ if (!pEndIdx)
+ {
+ break;
+ }
+ }
+ }
+}
+
+::std::vector<SwTxtAttr *>
+SwTxtNode::GetTxtAttrsAt(xub_StrLen const nIndex, RES_TXTATR const nWhich,
+ enum GetTxtAttrMode const eMode) const
+{
+ ::std::vector<SwTxtAttr *> ret;
+ lcl_GetTxtAttrs(& ret, 0, m_pSwpHints, nIndex, nWhich, eMode);
+ return ret;
+}
+
+SwTxtAttr *
+SwTxtNode::GetTxtAttrAt(xub_StrLen const nIndex, RES_TXTATR const nWhich,
+ enum GetTxtAttrMode const eMode) const
+{
+ OSL_ENSURE( (nWhich == RES_TXTATR_META)
+ || (nWhich == RES_TXTATR_METAFIELD)
+ || (nWhich == RES_TXTATR_AUTOFMT)
+ || (nWhich == RES_TXTATR_INETFMT)
+ || (nWhich == RES_TXTATR_CJK_RUBY)
+ || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER),
+ "GetTxtAttrAt() will give wrong result for this hint!");
+
+ SwTxtAttr * pRet(0);
+ lcl_GetTxtAttrs(0, & pRet, m_pSwpHints, nIndex, nWhich, eMode);
+ return pRet;
+}
+
+/*************************************************************************
+ * CopyHint()
+ *************************************************************************/
+
+SwCharFmt* lcl_FindCharFmt( const SwCharFmts* pCharFmts, const XubString& rName )
+{
+ if( rName.Len() )
+ {
+ SwCharFmt* pFmt;
+ sal_uInt16 nArrLen = pCharFmts->Count();
+ for( sal_uInt16 i = 1; i < nArrLen; i++ )
+ {
+ pFmt = (*pCharFmts)[ i ];
+ if( pFmt->GetName().CompareTo( rName ) == COMPARE_EQUAL )
+ return pFmt;
+ }
+ }
+ return NULL;
+}
+
+void lcl_CopyHint( const sal_uInt16 nWhich, const SwTxtAttr * const pHt,
+ SwTxtAttr *const pNewHt, SwDoc *const pOtherDoc, SwTxtNode *const pDest )
+{
+ OSL_ENSURE( nWhich == pHt->Which(), "Falsche Hint-Id" );
+ switch( nWhich )
+ {
+ // copy nodesarray section with footnote content
+ case RES_TXTATR_FTN :
+ OSL_ENSURE(pDest, "lcl_CopyHint: no destination text node?");
+ static_cast<const SwTxtFtn*>(pHt)->CopyFtn(
+ *static_cast<SwTxtFtn*>(pNewHt), *pDest);
+ break;
+
+ // Beim Kopieren von Feldern in andere Dokumente
+ // muessen die Felder bei ihren neuen Feldtypen angemeldet werden.
+
+ // TabellenFormel muessen relativ kopiert werden.
+ case RES_TXTATR_FIELD :
+ {
+ const SwFmtFld& rFld = pHt->GetFld();
+ if( pOtherDoc )
+ {
+ static_cast<const SwTxtFld*>(pHt)->CopyFld(
+ static_cast<SwTxtFld*>(pNewHt) );
+ }
+
+ // Tabellenformel ??
+ if( RES_TABLEFLD == rFld.GetFld()->GetTyp()->Which()
+ && static_cast<const SwTblField*>(rFld.GetFld())->IsIntrnlName())
+ {
+ // wandel die interne in eine externe Formel um
+ const SwTableNode* const pDstTblNd =
+ static_cast<const SwTxtFld*>(pHt)->
+ GetTxtNode().FindTableNode();
+ if( pDstTblNd )
+ {
+ SwTblField* const pTblFld = const_cast<SwTblField*>(
+ static_cast<const SwTblField*>(
+ pNewHt->GetFld().GetFld()));
+ pTblFld->PtrToBoxNm( &pDstTblNd->GetTable() );
+ }
+ }
+ }
+ break;
+
+ case RES_TXTATR_TOXMARK :
+ if( pOtherDoc && pDest && pDest->GetpSwpHints()
+ && USHRT_MAX != pDest->GetpSwpHints()->GetPos( pNewHt ) )
+ {
+ // Beim Kopieren von TOXMarks(Client) in andere Dokumente
+ // muss der Verzeichnis (Modify) ausgetauscht werden
+ static_cast<SwTxtTOXMark*>(pNewHt)->CopyTOXMark( pOtherDoc );
+ }
+ break;
+
+ case RES_TXTATR_CHARFMT :
+ // Wenn wir es mit einer Zeichenvorlage zu tun haben,
+ // muessen wir natuerlich auch die Formate kopieren.
+ if( pDest && pDest->GetpSwpHints()
+ && USHRT_MAX != pDest->GetpSwpHints()->GetPos( pNewHt ) )
+ {
+ SwCharFmt* pFmt =
+ static_cast<SwCharFmt*>(pHt->GetCharFmt().GetCharFmt());
+
+ if( pFmt && pOtherDoc )
+ {
+ pFmt = pOtherDoc->CopyCharFmt( *pFmt );
+ }
+ const_cast<SwFmtCharFmt&>( static_cast<const SwFmtCharFmt&>(
+ pNewHt->GetCharFmt() ) ).SetCharFmt( pFmt );
+ }
+ break;
+ case RES_TXTATR_INETFMT :
+ {
+ // Wenn wir es mit benutzerdefinierten INet-Zeichenvorlagen
+ // zu tun haben, muessen wir natuerlich auch die Formate kopieren.
+ if( pOtherDoc && pDest && pDest->GetpSwpHints()
+ && USHRT_MAX != pDest->GetpSwpHints()->GetPos( pNewHt ) )
+ {
+ const SwDoc* const pDoc = static_cast<const SwTxtINetFmt*>(pHt)
+ ->GetTxtNode().GetDoc();
+ if ( pDoc )
+ {
+ const SwCharFmts* pCharFmts = pDoc->GetCharFmts();
+ const SwFmtINetFmt& rFmt = pHt->GetINetFmt();
+ SwCharFmt* pFmt;
+ pFmt = lcl_FindCharFmt( pCharFmts, rFmt.GetINetFmt() );
+ if( pFmt )
+ pOtherDoc->CopyCharFmt( *pFmt );
+ pFmt = lcl_FindCharFmt( pCharFmts, rFmt.GetVisitedFmt() );
+ if( pFmt )
+ pOtherDoc->CopyCharFmt( *pFmt );
+ }
+ }
+ //JP 24.04.98: Bug 49753 - ein TextNode muss am Attribut
+ // gesetzt sein, damit die Vorlagen erzeugt
+ // werden koenne
+ SwTxtINetFmt* const pINetHt = static_cast<SwTxtINetFmt*>(pNewHt);
+ if ( !pINetHt->GetpTxtNode() )
+ {
+ pINetHt->ChgTxtNode( pDest );
+ }
+
+ //JP 22.10.97: Bug 44875 - Verbindung zum Format herstellen
+ pINetHt->GetCharFmt();
+ break;
+ }
+ case RES_TXTATR_META:
+ case RES_TXTATR_METAFIELD:
+ OSL_ENSURE(pNewHt, "copying Meta should not fail!");
+ OSL_ENSURE(pDest && (CH_TXTATR_INWORD ==
+ pDest->GetTxt().GetChar(*pNewHt->GetStart())),
+ "missing CH_TXTATR?");
+ break;
+ }
+}
+
+/*************************************************************************
+|* SwTxtNode::CopyAttr()
+|* Beschreibung kopiert Attribute an der Position nStart in pDest.
+|* BP 7.6.93: Es werden mit Absicht nur die Attribute _mit_ EndIdx
+|* kopiert! CopyAttr wird vornehmlich dann gerufen,
+|* wenn Attribute fuer einen Node mit leerem String
+|* gesetzt werden sollen.
+*************************************************************************/
+
+void SwTxtNode::CopyAttr( SwTxtNode *pDest, const xub_StrLen nTxtStartIdx,
+ const xub_StrLen nOldPos )
+{
+ if ( HasHints() ) // keine Attribute, keine Kekse
+ {
+ SwDoc* const pOtherDoc = (pDest->GetDoc() != GetDoc()) ?
+ pDest->GetDoc() : 0;
+
+ for ( sal_uInt16 i = 0; i < m_pSwpHints->Count(); i++ )
+ {
+ SwTxtAttr *const pHt = m_pSwpHints->GetTextHint(i);
+ xub_StrLen const nAttrStartIdx = *pHt->GetStart();
+ if ( nTxtStartIdx < nAttrStartIdx )
+ break; // ueber das Textende, da nLen == 0
+
+ const xub_StrLen *const pEndIdx = pHt->GetEnd();
+ if ( pEndIdx && !pHt->HasDummyChar() )
+ {
+ if( ( *pEndIdx > nTxtStartIdx ||
+ ( *pEndIdx == nTxtStartIdx &&
+ nAttrStartIdx == nTxtStartIdx ) ) )
+ {
+ sal_uInt16 const nWhich = pHt->Which();
+ if ( RES_TXTATR_REFMARK != nWhich )
+ {
+ // attribute in the area => copy
+ SwTxtAttr *const pNewHt = pDest->InsertItem(
+ pHt->GetAttr(), nOldPos, nOldPos,
+ nsSetAttrMode::SETATTR_IS_COPY);
+ if ( pNewHt )
+ {
+ lcl_CopyHint( nWhich, pHt, pNewHt,
+ pOtherDoc, pDest );
+ }
+ }
+ else if( !pOtherDoc ? GetDoc()->IsCopyIsMove()
+ : 0 == pOtherDoc->GetRefMark(
+ pHt->GetRefMark().GetRefName() ) )
+ {
+ pDest->InsertItem( pHt->GetAttr(), nOldPos, nOldPos,
+ nsSetAttrMode::SETATTR_IS_COPY);
+ }
+ }
+ }
+ }
+ }
+
+ if( this != pDest )
+ {
+ // Frames benachrichtigen, sonst verschwinden die Ftn-Nummern
+ SwUpdateAttr aHint( nOldPos, nOldPos, 0 );
+ pDest->ModifyNotification( 0, &aHint );
+ }
+}
+
+/*************************************************************************
+|* SwTxtNode::Copy()
+|* Beschreibung kopiert Zeichen und Attibute in pDest,
+|* wird angehaengt
+*************************************************************************/
+
+// --> OD 2008-11-18 #i96213#
+// introduction of new optional parameter to control, if all attributes have to be copied.
+void SwTxtNode::CopyText( SwTxtNode *const pDest,
+ const SwIndex &rStart,
+ const xub_StrLen nLen,
+ const bool bForceCopyOfAllAttrs )
+{
+ SwIndex aIdx( pDest, pDest->m_Text.Len() );
+ CopyText( pDest, aIdx, rStart, nLen, bForceCopyOfAllAttrs );
+}
+
+// --> OD 2008-11-18 #i96213#
+// introduction of new optional parameter to control, if all attributes have to be copied.
+void SwTxtNode::CopyText( SwTxtNode *const pDest,
+ const SwIndex &rDestStart,
+ const SwIndex &rStart,
+ xub_StrLen nLen,
+ const bool bForceCopyOfAllAttrs )
+{
+ xub_StrLen nTxtStartIdx = rStart.GetIndex();
+ xub_StrLen nDestStart = rDestStart.GetIndex(); // alte Pos merken
+
+ if (pDest->GetDoc()->IsClipBoard() && this->GetNum())
+ {
+ // #i111677# cache expansion of source (for clipboard)
+ pDest->m_pNumStringCache.reset(
+ new ::rtl::OUString(this->GetNumString()));
+ }
+
+ if( !nLen )
+ {
+ // wurde keine Laenge angegeben, dann Kopiere die Attribute
+ // an der Position rStart.
+ CopyAttr( pDest, nTxtStartIdx, nDestStart );
+
+ // harte Absatz umspannende Attribute kopieren
+ if( HasSwAttrSet() )
+ {
+ // alle, oder nur die CharAttribute ?
+ // --> OD 2008-11-18 #i96213#
+ if ( !bForceCopyOfAllAttrs &&
+ ( nDestStart ||
+ pDest->HasSwAttrSet() ||
+ nLen != pDest->GetTxt().Len() ) )
+ // <--
+ {
+ SfxItemSet aCharSet( pDest->GetDoc()->GetAttrPool(),
+ RES_CHRATR_BEGIN, RES_CHRATR_END-1,
+ RES_TXTATR_INETFMT, RES_TXTATR_INETFMT,
+ RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
+ RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
+ 0 );
+ aCharSet.Put( *GetpSwAttrSet() );
+ if( aCharSet.Count() )
+ {
+ pDest->SetAttr( aCharSet, nDestStart, nDestStart );
+ }
+ }
+ else
+ {
+ GetpSwAttrSet()->CopyToModify( *pDest );
+ }
+ }
+ return;
+ }
+
+ // 1. Text kopieren
+ const xub_StrLen oldLen = pDest->m_Text.Len();
+ //JP 15.02.96: Bug 25537 - Attributbehandlung am Ende fehlt! Darum
+ // ueber die InsertMethode den Text einfuegen und nicht
+ // selbst direkt
+ pDest->InsertText( m_Text.Copy( nTxtStartIdx, nLen ), rDestStart,
+ IDocumentContentOperations::INS_EMPTYEXPAND );
+
+ // um reale Groesse Updaten !
+ nLen = pDest->m_Text.Len() - oldLen;
+ if ( !nLen ) // string not longer?
+ return;
+
+ SwDoc* const pOtherDoc = (pDest->GetDoc() != GetDoc()) ?
+ pDest->GetDoc() : 0;
+
+ // harte Absatz umspannende Attribute kopieren
+ if( HasSwAttrSet() )
+ {
+ // alle, oder nur die CharAttribute ?
+ // --> OD 2008-11-18 #i96213#
+ if ( !bForceCopyOfAllAttrs &&
+ ( nDestStart ||
+ pDest->HasSwAttrSet() ||
+ nLen != pDest->GetTxt().Len() ) )
+ // <--
+ {
+ SfxItemSet aCharSet( pDest->GetDoc()->GetAttrPool(),
+ RES_CHRATR_BEGIN, RES_CHRATR_END-1,
+ RES_TXTATR_INETFMT, RES_TXTATR_INETFMT,
+ RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
+ RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
+ 0 );
+ aCharSet.Put( *GetpSwAttrSet() );
+ if( aCharSet.Count() )
+ {
+ pDest->SetAttr( aCharSet, nDestStart, nDestStart + nLen );
+ }
+ }
+ else
+ {
+ GetpSwAttrSet()->CopyToModify( *pDest );
+ }
+ }
+
+ bool const bUndoNodes = !pOtherDoc
+ && GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
+
+ // Ende erst jetzt holen, weil beim Kopieren in sich selbst der
+ // Start-Index und alle Attribute vorher aktualisiert werden.
+ nTxtStartIdx = rStart.GetIndex();
+ const xub_StrLen nEnd = nTxtStartIdx + nLen;
+
+ // 2. Attribute kopieren
+ // durch das Attribute-Array, bis der Anfang des Geltungsbereiches
+ // des Attributs hinter dem zu kopierenden Bereich liegt
+ const sal_uInt16 nSize = m_pSwpHints ? m_pSwpHints->Count() : 0;
+
+ // wird in sich selbst kopiert, dann kann beim Einfuegen ein
+ // Attribut geloescht werden. Darum erst ins Tmp-Array kopieren und
+ // dann erst ins eigene uebertragen.
+ SwpHts aArr( 5 );
+
+ // Del-Array fuer alle RefMarks ohne Ausdehnung
+ SwpHts aRefMrkArr;
+
+ sal_uInt16 nDeletedDummyChars(0);
+ //Achtung: kann ungueltig sein!!
+ for (sal_uInt16 n = 0; ( n < nSize ); ++n)
+ {
+ const xub_StrLen nAttrStartIdx = *(*m_pSwpHints)[n]->GetStart();
+ if (!( nAttrStartIdx < nEnd))
+ break;
+
+ SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(n);
+ const xub_StrLen * const pEndIdx = pHt->GetEnd();
+ const sal_uInt16 nWhich = pHt->Which();
+
+ // JP 26.04.94: REFMARK's werden nie kopiert. Hat das Refmark aber
+ // keinen Bereich umspannt, so steht im Text ein 255
+ // dieses muss entfernt werden. Trick: erst kopieren,
+ // erkennen und sammeln, nach dem kopieren Loeschen.
+ // Nimmt sein Zeichen mit ins Grab !!
+ // JP 14.08.95: Duerfen RefMarks gemovt werden?
+ int bCopyRefMark = RES_TXTATR_REFMARK == nWhich && ( bUndoNodes ||
+ (!pOtherDoc ? GetDoc()->IsCopyIsMove()
+ : 0 == pOtherDoc->GetRefMark(
+ pHt->GetRefMark().GetRefName() )));
+
+ if( pEndIdx && RES_TXTATR_REFMARK == nWhich && !bCopyRefMark )
+ {
+ continue;
+ }
+
+ xub_StrLen nAttrStt;
+ xub_StrLen nAttrEnd;
+
+ if( nAttrStartIdx < nTxtStartIdx )
+ {
+ // start is before selection
+ // copy hints with end and CH_TXTATR only if dummy char is copied
+ if ( pEndIdx && (*pEndIdx > nTxtStartIdx) && !pHt->HasDummyChar() )
+ {
+ // attribute with extent and the end is in the selection
+ nAttrStt = nDestStart;
+ nAttrEnd = (*pEndIdx > nEnd)
+ ? rDestStart.GetIndex()
+ : nDestStart + (*pEndIdx) - nTxtStartIdx;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ else
+ {
+ // start is in the selection
+ nAttrStt = nDestStart + ( nAttrStartIdx - nTxtStartIdx );
+ if( pEndIdx )
+ {
+ nAttrEnd = *pEndIdx > nEnd
+ ? rDestStart.GetIndex()
+ : nDestStart + ( *pEndIdx - nTxtStartIdx );
+ }
+ else
+ {
+ nAttrEnd = nAttrStt;
+ }
+ }
+
+ SwTxtAttr * pNewHt = 0;
+
+ if( pDest == this )
+ {
+ // copy the hint here, but insert it later
+ pNewHt = MakeTxtAttr( *GetDoc(), pHt->GetAttr(),
+ nAttrStt, nAttrEnd, COPY, pDest );
+
+ lcl_CopyHint(nWhich, pHt, pNewHt, 0, pDest);
+ aArr.C40_INSERT( SwTxtAttr, pNewHt, aArr.Count() );
+ }
+ else
+ {
+ pNewHt = pDest->InsertItem( pHt->GetAttr(), nAttrStt - nDeletedDummyChars,
+ nAttrEnd - nDeletedDummyChars,
+ nsSetAttrMode::SETATTR_NOTXTATRCHR
+ | nsSetAttrMode::SETATTR_IS_COPY);
+ if (pNewHt)
+ {
+ lcl_CopyHint( nWhich, pHt, pNewHt, pOtherDoc, pDest );
+ }
+ else if (pHt->HasDummyChar())
+ {
+ // The attribute that has failed to be copied would insert
+ // dummy char, so positions of the following attributes have
+ // to be shifted by one to compensate for that missing char.
+ ++nDeletedDummyChars;
+ }
+ }
+
+ if( RES_TXTATR_REFMARK == nWhich && !pEndIdx && !bCopyRefMark )
+ {
+ aRefMrkArr.C40_INSERT( SwTxtAttr, pNewHt, aRefMrkArr.Count() );
+ }
+ }
+
+ // nur falls im Array Attribute stehen (kann nur beim Kopieren
+ // sich selbst passieren!!)
+ for ( sal_uInt16 i = 0; i < aArr.Count(); ++i )
+ {
+ InsertHint( aArr[ i ], nsSetAttrMode::SETATTR_NOTXTATRCHR );
+ }
+
+ if( pDest->GetpSwpHints() )
+ {
+ for ( sal_uInt16 i = 0; i < aRefMrkArr.Count(); ++i )
+ {
+ SwTxtAttr * const pNewHt = aRefMrkArr[i];
+ if( pNewHt->GetEnd() )
+ {
+ pDest->GetpSwpHints()->Delete( pNewHt );
+ pDest->DestroyAttr( pNewHt );
+ }
+ else
+ {
+ const SwIndex aIdx( pDest, *pNewHt->GetStart() );
+ pDest->EraseText( aIdx, 1 );
+ }
+ }
+ }
+
+ CHECK_SWPHINTS(this);
+}
+
+
+void SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx,
+ const IDocumentContentOperations::InsertFlags nMode )
+{
+ OSL_ENSURE( rIdx <= m_Text.Len(), "SwTxtNode::InsertText: invalid index." );
+ OSL_ENSURE( (sal_uLong)m_Text.Len() + (sal_uLong)rStr.Len() <= STRING_LEN,
+ "SwTxtNode::InsertText: node text with insertion > STRING_LEN." );
+
+ xub_StrLen aPos = rIdx.GetIndex();
+ xub_StrLen nLen = m_Text.Len() - aPos;
+ m_Text.Insert( rStr, aPos );
+ nLen = m_Text.Len() - aPos - nLen;
+
+ if ( !nLen ) return;
+
+ sal_Bool bOldExpFlg = IsIgnoreDontExpand();
+ if (nMode & IDocumentContentOperations::INS_FORCEHINTEXPAND)
+ {
+ SetIgnoreDontExpand( sal_True );
+ }
+
+ Update( rIdx, nLen ); // text content changed!
+
+ if (nMode & IDocumentContentOperations::INS_FORCEHINTEXPAND)
+ {
+ SetIgnoreDontExpand( bOldExpFlg );
+ }
+
+ // analog zu Insert(char) in txtedt.cxx:
+ // 1) bei bHintExp leere Hints an rIdx.GetIndex suchen und aufspannen
+ // 2) bei bHintExp == sal_False mitgezogene Feldattribute zuruecksetzen
+
+ if ( HasHints() )
+ {
+ for ( sal_uInt16 i = 0; i < m_pSwpHints->Count() &&
+ rIdx >= *(*m_pSwpHints)[i]->GetStart(); ++i )
+ {
+ SwTxtAttr * const pHt = m_pSwpHints->GetTextHint( i );
+ xub_StrLen * const pEndIdx = pHt->GetEnd();
+ if( !pEndIdx )
+ continue;
+
+ if( rIdx == *pEndIdx )
+ {
+ if ( (nMode & IDocumentContentOperations::INS_NOHINTEXPAND) ||
+ (!(nMode & IDocumentContentOperations::INS_FORCEHINTEXPAND)
+ && pHt->DontExpand()) )
+ {
+ // bei leeren Attributen auch Start veraendern
+ if( rIdx == *pHt->GetStart() )
+ *pHt->GetStart() = *pHt->GetStart() - nLen;
+ *pEndIdx = *pEndIdx - nLen;
+ m_pSwpHints->DeleteAtPos(i);
+ InsertHint( pHt, nsSetAttrMode::SETATTR_NOHINTADJUST );
+ }
+ // empty hints at insert position?
+ else if ( (nMode & IDocumentContentOperations::INS_EMPTYEXPAND)
+ && (*pEndIdx == *pHt->GetStart()) )
+ {
+ *pHt->GetStart() = *pHt->GetStart() - nLen;
+ const sal_uInt16 nAktLen = m_pSwpHints->Count();
+ m_pSwpHints->DeleteAtPos(i);
+ InsertHint( pHt/* AUTOSTYLES:, nsSetAttrMode::SETATTR_NOHINTADJUST*/ );
+ if ( nAktLen > m_pSwpHints->Count() && i )
+ {
+ --i;
+ }
+ continue;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ if ( !(nMode & IDocumentContentOperations::INS_NOHINTEXPAND) &&
+ rIdx == nLen && *pHt->GetStart() == rIdx.GetIndex() &&
+ !pHt->IsDontExpandStartAttr() )
+ {
+ // Kein Feld, am Absatzanfang, HintExpand
+ m_pSwpHints->DeleteAtPos(i);
+ *pHt->GetStart() = *pHt->GetStart() - nLen;
+ InsertHint( pHt, nsSetAttrMode::SETATTR_NOHINTADJUST );
+ }
+ }
+ TryDeleteSwpHints();
+ }
+
+ if ( GetDepends() )
+ {
+ SwInsTxt aHint( aPos, nLen );
+ NotifyClients( 0, &aHint );
+ }
+
+ // By inserting a character, the hidden flags
+ // at the TxtNode can become invalid:
+ SetCalcHiddenCharFlags();
+
+ CHECK_SWPHINTS(this);
+}
+
+/*************************************************************************
+|*
+|* SwTxtNode::Cut()
+|*
+|* Beschreibung text.doc
+|*
+*************************************************************************/
+
+void SwTxtNode::CutText( SwTxtNode * const pDest,
+ const SwIndex & rStart, const xub_StrLen nLen )
+{
+ if(pDest)
+ {
+ SwIndex aDestStt( pDest, pDest->GetTxt().Len() );
+ CutImpl( pDest, aDestStt, rStart, nLen, false );
+ }
+ else
+ {
+ OSL_FAIL("mst: entering dead and bitrotted code; fasten your seatbelts!");
+ EraseText( rStart, nLen );
+ }
+}
+
+
+void SwTxtNode::CutImpl( SwTxtNode * const pDest, const SwIndex & rDestStart,
+ const SwIndex & rStart, xub_StrLen nLen, const bool bUpdate )
+{
+ if(!pDest)
+ {
+ OSL_FAIL("mst: entering dead and bitrotted code; fasten your seatbelts!");
+ EraseText( rStart, nLen );
+ return;
+ }
+
+ // nicht im Dokument verschieben ?
+ if( GetDoc() != pDest->GetDoc() )
+ {
+ OSL_FAIL("mst: entering dead and bitrotted code; fasten your seatbelts!");
+ CopyText( pDest, rDestStart, rStart, nLen);
+ EraseText(rStart, nLen);
+ return;
+ }
+
+ if( !nLen )
+ {
+ // wurde keine Laenge angegeben, dann Kopiere die Attribute
+ // an der Position rStart.
+ CopyAttr( pDest, rStart.GetIndex(), rDestStart.GetIndex() );
+ return;
+ }
+
+ xub_StrLen nTxtStartIdx = rStart.GetIndex();
+ xub_StrLen nDestStart = rDestStart.GetIndex(); // alte Pos merken
+ const xub_StrLen nInitSize = pDest->m_Text.Len();
+
+ // wird in sich selbst verschoben, muss es gesondert behandelt werden !!
+ if( pDest == this )
+ {
+ OSL_FAIL("mst: entering dead and bitrotted code; fasten your seatbelts!");
+ m_Text.Insert( m_Text, nTxtStartIdx, nLen, nDestStart );
+ m_Text.Erase( nTxtStartIdx + (nDestStart<nTxtStartIdx ? nLen : 0), nLen );
+
+ const xub_StrLen nEnd = rStart.GetIndex() + nLen;
+
+ // dann suche mal alle Attribute zusammen, die im verschobenen
+ // Bereich liegen. Diese werden in das extra Array verschoben,
+ // damit sich die Indizies beim Updaten nicht veraendern !!!
+ SwpHts aArr( 5 );
+
+ // 2. Attribute verschieben
+ // durch das Attribute-Array, bis der Anfang des Geltungsbereiches
+ // des Attributs hinter dem zu verschiebenden Bereich liegt
+ sal_uInt16 nAttrCnt = 0;
+ while ( m_pSwpHints && nAttrCnt < m_pSwpHints->Count() )
+ {
+ SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(nAttrCnt);
+ const xub_StrLen nAttrStartIdx = *pHt->GetStart();
+ if (!( nAttrStartIdx < nEnd ))
+ break;
+ const xub_StrLen * const pEndIdx = pHt->GetEnd();
+ const sal_uInt16 nWhich = pHt->Which();
+ SwTxtAttr *pNewHt = 0;
+
+ if(nAttrStartIdx < nTxtStartIdx)
+ {
+ // Anfang liegt vor dem Bereich
+ if ( RES_TXTATR_REFMARK != nWhich && !pHt->HasDummyChar() &&
+ pEndIdx && *pEndIdx > nTxtStartIdx )
+ {
+ // Attribut mit einem Bereich
+ // und das Ende des Attribut liegt im Bereich
+ pNewHt = MakeTxtAttr( *GetDoc(), pHt->GetAttr(), 0,
+ *pEndIdx > nEnd
+ ? nLen
+ : *pEndIdx - nTxtStartIdx );
+ }
+ }
+ else
+ {
+ // der Anfang liegt vollstaendig im Bereich
+ if( !pEndIdx || *pEndIdx < nEnd )
+ {
+ // Attribut verschieben
+ m_pSwpHints->Delete( pHt );
+ // die Start/End Indicies neu setzen
+ *pHt->GetStart() = nAttrStartIdx - nTxtStartIdx;
+ if( pEndIdx )
+ *pHt->GetEnd() = *pEndIdx - nTxtStartIdx;
+ aArr.C40_INSERT( SwTxtAttr, pHt, aArr.Count() );
+ continue; // while-Schleife weiter, ohne ++ !
+ }
+ // das Ende liegt dahinter
+ else if (RES_TXTATR_REFMARK != nWhich && !pHt->HasDummyChar())
+ {
+ pNewHt = MakeTxtAttr( *GetDoc(), pHt->GetAttr(),
+ nAttrStartIdx - nTxtStartIdx,
+ !pEndIdx ? 0
+ : ( *pEndIdx > nEnd
+ ? nLen
+ : *pEndIdx - nTxtStartIdx ));
+ }
+ }
+ if( pNewHt )
+ {
+ // die Daten kopieren
+ lcl_CopyHint( nWhich, pHt, pNewHt, 0, this );
+ aArr.C40_INSERT( SwTxtAttr, pNewHt, aArr.Count() );
+ }
+ ++nAttrCnt;
+ }
+
+ if( bUpdate )
+ {
+ // Update aller Indizies
+ Update( rDestStart, nLen, sal_False, sal_True );
+ }
+
+ CHECK_SWPHINTS(this);
+
+ Update( rStart, nLen, sal_True, sal_True );
+
+ CHECK_SWPHINTS(this);
+
+ // dann setze die kopierten/geloeschten Attribute in den Node
+ if( nDestStart <= nTxtStartIdx )
+ {
+ nTxtStartIdx = nTxtStartIdx + nLen;
+ }
+ else
+ {
+ nDestStart = nDestStart - nLen;
+ }
+
+ for ( sal_uInt16 n = 0; n < aArr.Count(); ++n )
+ {
+ SwTxtAttr *const pNewHt = aArr[n];
+ *pNewHt->GetStart() = nDestStart + *pNewHt->GetStart();
+ xub_StrLen * const pEndIdx = pNewHt->GetEnd();
+ if ( pEndIdx )
+ {
+ *pEndIdx = nDestStart + *pEndIdx;
+ }
+ InsertHint( pNewHt, nsSetAttrMode::SETATTR_NOTXTATRCHR );
+ }
+ }
+ else
+ {
+ pDest->m_Text.Insert( m_Text, nTxtStartIdx, nLen, nDestStart );
+ m_Text.Erase( nTxtStartIdx, nLen );
+ nLen = pDest->m_Text.Len() - nInitSize; // update w/ current size!
+ if( !nLen ) // String nicht gewachsen ??
+ return;
+
+ if( bUpdate )
+ {
+ // Update aller Indizies
+ pDest->Update( rDestStart, nLen, sal_False, sal_True);
+ }
+
+ CHECK_SWPHINTS(pDest);
+
+ const xub_StrLen nEnd = rStart.GetIndex() + nLen;
+ SwDoc* const pOtherDoc = (pDest->GetDoc() != GetDoc())
+ ? pDest->GetDoc() : 0;
+ bool const bUndoNodes = !pOtherDoc
+ && GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
+
+ OSL_ENSURE(!pOtherDoc,
+ "mst: entering dead and bitrotted code; fasten your seatbelts!");
+
+ // harte Absatz umspannende Attribute kopieren
+ if( HasSwAttrSet() )
+ {
+ // alle, oder nur die CharAttribute ?
+ if( nInitSize || pDest->HasSwAttrSet() ||
+ nLen != pDest->GetTxt().Len() )
+ {
+ SfxItemSet aCharSet( pDest->GetDoc()->GetAttrPool(),
+ RES_CHRATR_BEGIN, RES_CHRATR_END-1,
+ RES_TXTATR_INETFMT, RES_TXTATR_INETFMT,
+ RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
+ RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
+ 0 );
+ aCharSet.Put( *GetpSwAttrSet() );
+ if( aCharSet.Count() )
+ pDest->SetAttr( aCharSet, nDestStart, nDestStart + nLen );
+ }
+ else
+ {
+ GetpSwAttrSet()->CopyToModify( *pDest );
+ }
+ }
+
+ // 2. Attribute verschieben
+ // durch das Attribute-Array, bis der Anfang des Geltungsbereiches
+ // des Attributs hinter dem zu verschiebenden Bereich liegt
+ sal_uInt16 nAttrCnt = 0;
+ while ( m_pSwpHints && (nAttrCnt < m_pSwpHints->Count()) )
+ {
+ SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(nAttrCnt);
+ const xub_StrLen nAttrStartIdx = *pHt->GetStart();
+ if (!( nAttrStartIdx < nEnd ))
+ break;
+ const xub_StrLen * const pEndIdx = pHt->GetEnd();
+ const sal_uInt16 nWhich = pHt->Which();
+ SwTxtAttr *pNewHt = 0;
+
+ // if the hint has a dummy character, then it must not be split!
+ if(nAttrStartIdx < nTxtStartIdx)
+ {
+ // Anfang liegt vor dem Bereich
+ if( !pHt->HasDummyChar() && ( RES_TXTATR_REFMARK != nWhich
+ || bUndoNodes ) && pEndIdx && *pEndIdx > nTxtStartIdx )
+ {
+ // Attribut mit einem Bereich
+ // und das Ende des Attribut liegt im Bereich
+ pNewHt = MakeTxtAttr( *pDest->GetDoc(), pHt->GetAttr(),
+ nDestStart,
+ nDestStart + (
+ *pEndIdx > nEnd
+ ? nLen
+ : *pEndIdx - nTxtStartIdx ) );
+ }
+ }
+ else
+ {
+ // der Anfang liegt vollstaendig im Bereich
+ if( !pEndIdx || *pEndIdx < nEnd ||
+ (!pOtherDoc && !bUndoNodes && RES_TXTATR_REFMARK == nWhich)
+ || pHt->HasDummyChar() )
+ {
+ // do not delete note and later add it -> sidebar flickering
+ if ( GetDoc()->GetDocShell() )
+ {
+ GetDoc()->GetDocShell()->Broadcast( SfxSimpleHint(SFX_HINT_USER04));
+ }
+ // Attribut verschieben
+ m_pSwpHints->Delete( pHt );
+ // die Start/End Indicies neu setzen
+ *pHt->GetStart() =
+ nDestStart + (nAttrStartIdx - nTxtStartIdx);
+ if( pEndIdx )
+ {
+ *pHt->GetEnd() = nDestStart + (
+ *pEndIdx > nEnd
+ ? nLen
+ : *pEndIdx - nTxtStartIdx );
+ }
+ pDest->InsertHint( pHt,
+ nsSetAttrMode::SETATTR_NOTXTATRCHR
+ | nsSetAttrMode::SETATTR_DONTREPLACE );
+ if ( GetDoc()->GetDocShell() )
+ {
+ GetDoc()->GetDocShell()->Broadcast( SfxSimpleHint(SFX_HINT_USER04));
+ }
+ continue; // while-Schleife weiter, ohne ++ !
+ }
+ // das Ende liegt dahinter
+ else if( RES_TXTATR_REFMARK != nWhich || bUndoNodes )
+ {
+ pNewHt = MakeTxtAttr( *GetDoc(), pHt->GetAttr(),
+ nDestStart + (nAttrStartIdx - nTxtStartIdx),
+ !pEndIdx ? 0
+ : nDestStart + ( *pEndIdx > nEnd
+ ? nLen
+ : *pEndIdx - nTxtStartIdx ));
+ }
+ }
+ if ( pNewHt )
+ {
+ const bool bSuccess( pDest->InsertHint( pNewHt,
+ nsSetAttrMode::SETATTR_NOTXTATRCHR
+ | nsSetAttrMode::SETATTR_DONTREPLACE
+ | nsSetAttrMode::SETATTR_IS_COPY) );
+ if (bSuccess)
+ {
+ lcl_CopyHint( nWhich, pHt, pNewHt, pOtherDoc, pDest );
+ }
+ }
+ ++nAttrCnt;
+ }
+ // sollten jetzt noch leere Attribute rumstehen, dann haben diese
+ // eine hoehere Praezedenz. Also herausholen und das Array updaten.
+ // Die dabei entstehenden leeren Hints werden von den gesicherten
+ // "uebergeplaettet". (Bug: 6977)
+ if( m_pSwpHints && nAttrCnt < m_pSwpHints->Count() )
+ {
+ SwpHts aArr( 5 );
+ while ( nAttrCnt < m_pSwpHints->Count() )
+ {
+ SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(nAttrCnt);
+ if ( nEnd != *pHt->GetStart() )
+ break;
+ const xub_StrLen * const pEndIdx = pHt->GetEnd();
+ if ( pEndIdx && *pEndIdx == nEnd )
+ {
+ aArr.C40_INSERT( SwTxtAttr, pHt, aArr.Count() );
+ m_pSwpHints->Delete( pHt );
+ }
+ else
+ {
+ ++nAttrCnt;
+ }
+ }
+ Update( rStart, nLen, sal_True, sal_True );
+
+ for ( sal_uInt16 n = 0; n < aArr.Count(); ++n )
+ {
+ SwTxtAttr * const pHt = aArr[ n ];
+ *pHt->GetStart() = *pHt->GetEnd() = rStart.GetIndex();
+ InsertHint( pHt );
+ }
+ }
+ else
+ {
+ Update( rStart, nLen, sal_True, sal_True );
+ }
+
+ CHECK_SWPHINTS(this);
+ }
+
+ TryDeleteSwpHints();
+
+ // Frames benachrichtigen;
+ SwInsTxt aInsHint( nDestStart, nLen );
+ pDest->ModifyNotification( 0, &aInsHint );
+ SwDelTxt aDelHint( nTxtStartIdx, nLen );
+ ModifyNotification( 0, &aDelHint );
+}
+
+
+void SwTxtNode::EraseText(const SwIndex &rIdx, const xub_StrLen nCount,
+ const IDocumentContentOperations::InsertFlags nMode )
+{
+ OSL_ENSURE( rIdx <= m_Text.Len(), "SwTxtNode::EraseText: invalid index." );
+
+ const xub_StrLen nStartIdx = rIdx.GetIndex();
+ const xub_StrLen nCnt = (STRING_LEN == nCount)
+ ? m_Text.Len() - nStartIdx : nCount;
+ const xub_StrLen nEndIdx = nStartIdx + nCnt;
+ m_Text.Erase( nStartIdx, nCnt );
+
+ /* GCAttr(); alle leeren weggwerfen ist zu brutal.
+ * Es duerfen nur die wegggeworfen werden,
+ * die im Bereich liegen und nicht am Ende des Bereiches liegen
+ */
+
+ for ( sal_uInt16 i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
+ {
+ SwTxtAttr *pHt = m_pSwpHints->GetTextHint(i);
+
+ const xub_StrLen nHintStart = *pHt->GetStart();
+
+ if ( nHintStart < nStartIdx )
+ continue;
+
+ if ( nHintStart > nEndIdx )
+ break; // hints are sorted by end, so break here
+
+ const xub_StrLen* pHtEndIdx = pHt->GetEnd();
+ const sal_uInt16 nWhich = pHt->Which();
+
+ if( !pHtEndIdx )
+ {
+ OSL_ENSURE(pHt->HasDummyChar(),
+ "attribute with neither end nor CH_TXTATR?");
+ if (isTXTATR(nWhich) &&
+ (nHintStart >= nStartIdx) && (nHintStart < nEndIdx))
+ {
+ m_pSwpHints->DeleteAtPos(i);
+ DestroyAttr( pHt );
+ --i;
+ }
+ continue;
+ }
+
+ OSL_ENSURE(!( (nHintStart < nEndIdx) && (*pHtEndIdx > nEndIdx)
+ && pHt->HasDummyChar() )
+ // next line: deleting exactly dummy char: DeleteAttributes
+ || ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx)),
+ "ERROR: deleting left-overlapped attribute with CH_TXTATR");
+
+ // Delete the hint if:
+ // 1. The hint ends before the deletion end position or
+ // 2. The hint ends at the deletion end position and
+ // we are not in empty expand mode and
+ // the hint is a [toxmark|refmark|ruby] text attribute
+ // 3. deleting exactly the dummy char of an hint with end and dummy
+ // char deletes the hint
+ if ( (*pHtEndIdx < nEndIdx)
+ || ( (*pHtEndIdx == nEndIdx) &&
+ !(IDocumentContentOperations::INS_EMPTYEXPAND & nMode) &&
+ ( (RES_TXTATR_TOXMARK == nWhich) ||
+ (RES_TXTATR_REFMARK == nWhich) ||
+ // --> FME 2006-03-03 #i62668# Ruby text attribute must be
+ // treated just like toxmark and refmarks
+ (RES_TXTATR_CJK_RUBY == nWhich) ) )
+ // <--
+ || ( (nHintStart < nEndIdx) &&
+ pHt->HasDummyChar() )
+ )
+ {
+ m_pSwpHints->DeleteAtPos(i);
+ DestroyAttr( pHt );
+ --i;
+ }
+ }
+
+ OSL_ENSURE(rIdx.GetIndex() == nStartIdx, "huh? start index has changed?");
+
+ TryDeleteSwpHints();
+
+ Update( rIdx, nCnt, sal_True );
+
+ if( 1 == nCnt )
+ {
+ SwDelChr aHint( nStartIdx );
+ NotifyClients( 0, &aHint );
+ }
+ else
+ {
+ SwDelTxt aHint( nStartIdx, nCnt );
+ NotifyClients( 0, &aHint );
+ }
+
+ OSL_ENSURE(rIdx.GetIndex() == nStartIdx, "huh? start index has changed?");
+
+ // By deleting a character, the hidden flags
+ // at the TxtNode can become invalid:
+ SetCalcHiddenCharFlags();
+
+ CHECK_SWPHINTS(this);
+}
+
+/***********************************************************************
+#* Class : SwTxtNode
+#* Methode : GCAttr
+#*
+#* Beschreibung
+#* text.doc
+#***********************************************************************/
+
+void SwTxtNode::GCAttr()
+{
+ if ( !HasHints() )
+ return;
+
+ bool bChanged = false;
+ sal_uInt16 nMin = m_Text.Len(),
+ nMax = 0;
+ sal_Bool bAll = nMin != 0; // Bei leeren Absaetzen werden nur die
+ // INet-Formate entfernt.
+
+ for ( sal_uInt16 i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
+ {
+ SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(i);
+
+ // wenn Ende und Start gleich sind --> loeschen
+ const xub_StrLen * const pEndIdx = pHt->GetEnd();
+ if (pEndIdx && !pHt->HasDummyChar() && (*pEndIdx == *pHt->GetStart())
+ && ( bAll || pHt->Which() == RES_TXTATR_INETFMT ) )
+ {
+ bChanged = true;
+ nMin = Min( nMin, *pHt->GetStart() );
+ nMax = Max( nMax, *pHt->GetEnd() );
+ DestroyAttr( m_pSwpHints->Cut(i) );
+ --i;
+ }
+ else
+ {
+ pHt->SetDontExpand( false );
+ }
+ }
+ TryDeleteSwpHints();
+
+ if(bChanged)
+ {
+ //TxtFrm's reagieren auf aHint, andere auf aNew
+ SwUpdateAttr aHint( nMin, nMax, 0 );
+ NotifyClients( 0, &aHint );
+ SwFmtChg aNew( GetTxtColl() );
+ NotifyClients( 0, &aNew );
+ }
+}
+
+// #i23726#
+SwNumRule* SwTxtNode::_GetNumRule(sal_Bool bInParent) const
+{
+ SwNumRule* pRet = 0;
+
+ const SfxPoolItem* pItem = GetNoCondAttr( RES_PARATR_NUMRULE, bInParent );
+ bool bNoNumRule = false;
+ if ( pItem )
+ {
+ String sNumRuleName = static_cast<const SwNumRuleItem *>(pItem)->GetValue();
+ if (sNumRuleName.Len() > 0)
+ {
+ pRet = GetDoc()->FindNumRulePtr( sNumRuleName );
+ }
+ else // numbering is turned off
+ bNoNumRule = true;
+ }
+
+ if ( !bNoNumRule )
+ {
+ if ( pRet && pRet == GetDoc()->GetOutlineNumRule() &&
+ ( !HasSwAttrSet() ||
+ SFX_ITEM_SET !=
+ GetpSwAttrSet()->GetItemState( RES_PARATR_NUMRULE, sal_False ) ) )
+ {
+ SwTxtFmtColl* pColl = GetTxtColl();
+ if ( pColl )
+ {
+ const SwNumRuleItem& rDirectItem = pColl->GetNumRule( sal_False );
+ if ( rDirectItem.GetValue().Len() == 0 )
+ {
+ pRet = 0L;
+ }
+ }
+ }
+ }
+
+ return pRet;
+}
+
+SwNumRule* SwTxtNode::GetNumRule(sal_Bool bInParent) const
+{
+ SwNumRule * pRet = _GetNumRule(bInParent);
+
+ return pRet;
+}
+
+void SwTxtNode::NumRuleChgd()
+{
+ if ( IsInList() )
+ {
+ SwNumRule* pNumRule = GetNumRule();
+ if ( pNumRule && pNumRule != GetNum()->GetNumRule() )
+ {
+ mpNodeNum->ChangeNumRule( *pNumRule );
+ }
+ }
+
+ if( IsInCache() )
+ {
+ SwFrm::GetCache().Delete( this );
+ SetInCache( sal_False );
+ }
+ SetInSwFntCache( sal_False );
+
+ // Sending "noop" modify in order to cause invalidations of registered
+ // <SwTxtFrm> instances to get the list style change respectively the change
+ // in the list tree reflected in the layout.
+ // Important note:
+ {
+ SvxLRSpaceItem& rLR = (SvxLRSpaceItem&)GetSwAttrSet().GetLRSpace();
+ NotifyClients( &rLR, &rLR );
+ }
+}
+
+// -> #i27615#
+sal_Bool SwTxtNode::IsNumbered() const
+{
+ sal_Bool bResult = sal_False;
+
+ SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
+ if ( pRule && IsCountedInList() )
+ bResult = sal_True;
+
+ return bResult;
+}
+
+bool SwTxtNode::HasMarkedLabel() const
+{
+ bool bResult = false;
+
+ if ( IsInList() )
+ {
+ bResult =
+ GetDoc()->getListByName( GetListId() )->IsListLevelMarked( GetActualListLevel() );
+ }
+
+ return bResult;
+}
+// <- #i27615#
+
+SwTxtNode* SwTxtNode::_MakeNewTxtNode( const SwNodeIndex& rPos, sal_Bool bNext,
+ sal_Bool bChgFollow )
+{
+ /* hartes PageBreak/PageDesc/ColumnBreak aus AUTO-Set ignorieren */
+ SwAttrSet* pNewAttrSet = 0;
+ // --> OD 2007-07-10 #i75353#
+ bool bClearHardSetNumRuleWhenFmtCollChanges( false );
+ // <--
+ if( HasSwAttrSet() )
+ {
+ pNewAttrSet = new SwAttrSet( *GetpSwAttrSet() );
+ const SfxItemSet* pTmpSet = GetpSwAttrSet();
+
+ if( bNext ) // der naechste erbt keine Breaks!
+ pTmpSet = pNewAttrSet;
+
+ // PageBreaks/PageDesc/ColBreak rausschmeissen.
+ sal_Bool bRemoveFromCache = sal_False;
+ std::vector<sal_uInt16> aClearWhichIds;
+ if ( bNext )
+ bRemoveFromCache = ( 0 != pNewAttrSet->ClearItem( RES_PAGEDESC ) );
+ else
+ aClearWhichIds.push_back( RES_PAGEDESC );
+
+ if( SFX_ITEM_SET == pTmpSet->GetItemState( RES_BREAK, sal_False ) )
+ {
+ if ( bNext )
+ pNewAttrSet->ClearItem( RES_BREAK );
+ else
+ aClearWhichIds.push_back( RES_BREAK );
+ bRemoveFromCache = sal_True;
+ }
+ if( SFX_ITEM_SET == pTmpSet->GetItemState( RES_KEEP, sal_False ) )
+ {
+ if ( bNext )
+ pNewAttrSet->ClearItem( RES_KEEP );
+ else
+ aClearWhichIds.push_back( RES_KEEP );
+ bRemoveFromCache = sal_True;
+ }
+ if( SFX_ITEM_SET == pTmpSet->GetItemState( RES_PARATR_SPLIT, sal_False ) )
+ {
+ if ( bNext )
+ pNewAttrSet->ClearItem( RES_PARATR_SPLIT );
+ else
+ aClearWhichIds.push_back( RES_PARATR_SPLIT );
+ bRemoveFromCache = sal_True;
+ }
+ if(SFX_ITEM_SET == pTmpSet->GetItemState(RES_PARATR_NUMRULE, sal_False))
+ {
+ SwNumRule * pRule = GetNumRule();
+
+ if (pRule && IsOutline())
+ {
+ if ( bNext )
+ pNewAttrSet->ClearItem(RES_PARATR_NUMRULE);
+ else
+ {
+ // --> OD 2007-07-10 #i75353#
+ // No clear of hard set numbering rule at an outline paragraph at this point.
+ // Only if the paragraph style changes - see below.
+ bClearHardSetNumRuleWhenFmtCollChanges = true;
+ // <--
+ }
+ bRemoveFromCache = sal_True;
+ }
+ }
+
+ if ( 0 != aClearWhichIds.size() )
+ bRemoveFromCache = 0 != ClearItemsFromAttrSet( aClearWhichIds );
+
+ if( !bNext && bRemoveFromCache && IsInCache() )
+ {
+ SwFrm::GetCache().Delete( this );
+ SetInCache( sal_False );
+ }
+ }
+ SwNodes& rNds = GetNodes();
+
+ SwTxtFmtColl* pColl = GetTxtColl();
+
+ SwTxtNode *pNode = new SwTxtNode( rPos, pColl, pNewAttrSet );
+
+ if( pNewAttrSet )
+ delete pNewAttrSet;
+
+ const SwNumRule* pRule = GetNumRule();
+ if( pRule && pRule == pNode->GetNumRule() && rNds.IsDocNodes() ) // #115901#
+ {
+ // --> OD 2005-10-18 #i55459#
+ // - correction: parameter <bNext> has to be checked, as it was in the
+ // previous implementation.
+ if ( !bNext && !IsCountedInList() )
+ SetCountedInList(true);
+ // <--
+ }
+
+ // jetzt kann es sein, das durch die Nummerierung dem neuen Node eine
+ // Vorlage aus dem Pool zugewiesen wurde. Dann darf diese nicht
+ // nochmal uebergeplaettet werden !!
+ if( pColl != pNode->GetTxtColl() ||
+ ( bChgFollow && pColl != GetTxtColl() ))
+ return pNode; // mehr duerfte nicht gemacht werden oder ????
+
+ pNode->_ChgTxtCollUpdateNum( 0, pColl ); // fuer Nummerierung/Gliederung
+ if( bNext || !bChgFollow )
+ return pNode;
+
+ SwTxtFmtColl *pNextColl = &pColl->GetNextTxtFmtColl();
+ // --> OD 2009-08-12 #i101870#
+ // perform action on different paragraph styles before applying the new paragraph style
+ if (pNextColl != pColl)
+ {
+ // --> OD 2007-07-10 #i75353#
+ if ( bClearHardSetNumRuleWhenFmtCollChanges )
+ {
+ std::vector<sal_uInt16> aClearWhichIds;
+ aClearWhichIds.push_back( RES_PARATR_NUMRULE );
+ if ( ClearItemsFromAttrSet( aClearWhichIds ) != 0 && IsInCache() )
+ {
+ SwFrm::GetCache().Delete( this );
+ SetInCache( sal_False );
+ }
+ }
+ // <--
+ }
+ // <--
+ ChgFmtColl( pNextColl );
+
+ return pNode;
+}
+
+SwCntntNode* SwTxtNode::AppendNode( const SwPosition & rPos )
+{
+ // Position hinter dem eingefuegt wird
+ SwNodeIndex aIdx( rPos.nNode, 1 );
+ SwTxtNode* pNew = _MakeNewTxtNode( aIdx, sal_True );
+
+ // reset list attributes at appended text node
+ pNew->ResetAttr( RES_PARATR_LIST_ISRESTART );
+ pNew->ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
+ pNew->ResetAttr( RES_PARATR_LIST_ISCOUNTED );
+ if ( pNew->GetNumRule() == 0 )
+ {
+ pNew->ResetAttr( RES_PARATR_LIST_ID );
+ pNew->ResetAttr( RES_PARATR_LIST_LEVEL );
+ }
+
+ if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 )
+ {
+ AddToList();
+ }
+
+ if( GetDepends() )
+ MakeFrms( *pNew );
+ return pNew;
+}
+
+/*************************************************************************
+ * SwTxtNode::GetTxtAttr
+ *************************************************************************/
+
+SwTxtAttr * SwTxtNode::GetTxtAttrForCharAt( const xub_StrLen nIndex,
+ const RES_TXTATR nWhich ) const
+{
+ if ( HasHints() )
+ {
+ for ( sal_uInt16 i = 0; i < m_pSwpHints->Count(); ++i )
+ {
+ SwTxtAttr * const pHint = m_pSwpHints->GetTextHint(i);
+ const xub_StrLen nStartPos = *pHint->GetStart();
+ if ( nIndex < nStartPos )
+ {
+ return 0;
+ }
+ if ( (nIndex == nStartPos) && pHint->HasDummyChar() )
+ {
+ return ( RES_TXTATR_END == nWhich || nWhich == pHint->Which() )
+ ? pHint : 0;
+ }
+ }
+ }
+ return 0;
+}
+
+// -> #i29560#
+sal_Bool SwTxtNode::HasNumber() const
+{
+ sal_Bool bResult = sal_False;
+
+ const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
+ if ( pRule )
+ {
+ SwNumFmt aFmt(pRule->Get( static_cast<sal_uInt16>(GetActualListLevel())));
+
+ // #i40041#
+ bResult = aFmt.IsEnumeration() &&
+ SVX_NUM_NUMBER_NONE != aFmt.GetNumberingType();
+ }
+
+ return bResult;
+}
+
+sal_Bool SwTxtNode::HasBullet() const
+{
+ sal_Bool bResult = sal_False;
+
+ const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
+ if ( pRule )
+ {
+ SwNumFmt aFmt(pRule->Get( static_cast<sal_uInt16>(GetActualListLevel())));
+
+ bResult = aFmt.IsItemize();
+ }
+
+ return bResult;
+}
+// <- #i29560#
+
+// --> OD 2005-11-17 #128041# - introduce parameter <_bInclPrefixAndSuffixStrings>
+//i53420 added max outline parameter
+XubString SwTxtNode::GetNumString( const bool _bInclPrefixAndSuffixStrings, const unsigned int _nRestrictToThisLevel ) const
+{
+ if (GetDoc()->IsClipBoard() && m_pNumStringCache.get())
+ {
+ // #i111677# do not expand number strings in clipboard documents
+ return *m_pNumStringCache;
+ }
+ const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
+ if ( pRule &&
+ IsCountedInList() )
+ {
+ SvxNumberType const& rNumberType(
+ pRule->Get( static_cast<sal_uInt16>(GetActualListLevel()) ) );
+ if (rNumberType.IsTxtFmt() ||
+ // #b6432095#
+ (style::NumberingType::NUMBER_NONE == rNumberType.GetNumberingType()))
+ {
+ return pRule->MakeNumString( GetNum()->GetNumberVector(),
+ _bInclPrefixAndSuffixStrings ? sal_True : sal_False,
+ sal_False,
+ _nRestrictToThisLevel );
+ }
+ }
+
+ return aEmptyStr;
+}
+
+long SwTxtNode::GetLeftMarginWithNum( sal_Bool bTxtLeft ) const
+{
+ long nRet = 0;
+ const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
+ if( pRule )
+ {
+ const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
+
+ if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+ {
+ nRet = rFmt.GetAbsLSpace();
+
+ if( !bTxtLeft )
+ {
+ if( 0 > rFmt.GetFirstLineOffset() &&
+ nRet > -rFmt.GetFirstLineOffset() )
+ nRet = nRet + rFmt.GetFirstLineOffset();
+ else
+ nRet = 0;
+ }
+
+ if( pRule->IsAbsSpaces() )
+ nRet = nRet - GetSwAttrSet().GetLRSpace().GetLeft();
+ }
+ else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ if ( AreListLevelIndentsApplicable() )
+ {
+ nRet = rFmt.GetIndentAt();
+ // --> OD 2008-06-06 #i90401#
+ // Only negative first line indents have consider for the left margin
+ if ( !bTxtLeft &&
+ rFmt.GetFirstLineIndent() < 0 )
+ {
+ nRet = nRet + rFmt.GetFirstLineIndent();
+ }
+ }
+ }
+ }
+
+ return nRet;
+}
+
+sal_Bool SwTxtNode::GetFirstLineOfsWithNum( short& rFLOffset ) const
+{
+ sal_Bool bRet( sal_False );
+ // --> OD 2009-09-08 #i95907#, #b6879723#
+ rFLOffset = 0;
+ // <--
+
+ // --> OD 2005-11-02 #i51089 - TUNING#
+ const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
+ if ( pRule )
+ {
+ if ( IsCountedInList() )
+ {
+ const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
+ if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+ {
+ rFLOffset = pRule->Get( static_cast<sal_uInt16>(GetActualListLevel() )).GetFirstLineOffset();
+
+ if (!getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
+ {
+ SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
+ rFLOffset = rFLOffset + aItem.GetTxtFirstLineOfst();
+ }
+ }
+ else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ if ( AreListLevelIndentsApplicable() )
+ {
+ rFLOffset = static_cast<sal_uInt16>(rFmt.GetFirstLineIndent());
+ }
+ else if (!getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
+ {
+ SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
+ rFLOffset = aItem.GetTxtFirstLineOfst();
+ }
+ }
+ }
+
+ bRet = sal_True;
+ }
+ else
+ {
+ rFLOffset = GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst();
+ }
+
+ return bRet;
+}
+
+// --> OD 2010-01-05 #b6884103#
+SwTwips SwTxtNode::GetAdditionalIndentForStartingNewList() const
+{
+ SwTwips nAdditionalIndent = 0;
+
+ const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
+ if ( pRule )
+ {
+ const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
+ if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+ {
+ nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
+
+ if (getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
+ {
+ nAdditionalIndent = nAdditionalIndent -
+ GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst();
+ }
+ }
+ else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ if ( AreListLevelIndentsApplicable() )
+ {
+ nAdditionalIndent = rFmt.GetIndentAt() + rFmt.GetFirstLineIndent();
+ }
+ else
+ {
+ nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
+ if (getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
+ {
+ nAdditionalIndent = nAdditionalIndent -
+ GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst();
+ }
+ }
+ }
+ }
+ else
+ {
+ nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
+ }
+
+ return nAdditionalIndent;
+}
+
+// --> OD 2008-12-02 #i96772#
+void SwTxtNode::ClearLRSpaceItemDueToListLevelIndents( SvxLRSpaceItem& o_rLRSpaceItem ) const
+{
+ if ( AreListLevelIndentsApplicable() )
+ {
+ const SwNumRule* pRule = GetNumRule();
+ if ( pRule && GetActualListLevel() >= 0 )
+ {
+ const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
+ if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ SvxLRSpaceItem aLR( RES_LR_SPACE );
+ o_rLRSpaceItem = aLR;
+ }
+ }
+ }
+}
+
+// --> OD 2008-07-01 #i91133#
+long SwTxtNode::GetLeftMarginForTabCalculation() const
+{
+ long nLeftMarginForTabCalc = 0;
+
+ bool bLeftMarginForTabCalcSetToListLevelIndent( false );
+ const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0;
+ if( pRule )
+ {
+ const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
+ if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ if ( AreListLevelIndentsApplicable() )
+ {
+ nLeftMarginForTabCalc = rFmt.GetIndentAt();
+ bLeftMarginForTabCalcSetToListLevelIndent = true;
+ }
+ }
+ }
+ if ( !bLeftMarginForTabCalcSetToListLevelIndent )
+ {
+ nLeftMarginForTabCalc = GetSwAttrSet().GetLRSpace().GetTxtLeft();
+ }
+
+ return nLeftMarginForTabCalc;
+}
+
+void SwTxtNode::Replace0xFF( XubString& rTxt, xub_StrLen& rTxtStt,
+ xub_StrLen nEndPos, sal_Bool bExpandFlds ) const
+{
+ if( GetpSwpHints() )
+ {
+ sal_Unicode cSrchChr = CH_TXTATR_BREAKWORD;
+ for( int nSrchIter = 0; 2 > nSrchIter; ++nSrchIter,
+ cSrchChr = CH_TXTATR_INWORD )
+ {
+ xub_StrLen nPos = rTxt.Search( cSrchChr );
+ while( STRING_NOTFOUND != nPos && nPos < nEndPos )
+ {
+ const SwTxtAttr* const pAttr =
+ GetTxtAttrForCharAt( rTxtStt + nPos );
+ if( pAttr )
+ {
+ switch( pAttr->Which() )
+ {
+ case RES_TXTATR_FIELD:
+ rTxt.Erase( nPos, 1 );
+ if( bExpandFlds )
+ {
+ const XubString aExpand(
+ static_cast<SwTxtFld const*>(pAttr)->GetFld()
+ .GetFld()->ExpandField(true));
+ rTxt.Insert( aExpand, nPos );
+ nPos = nPos + aExpand.Len();
+ nEndPos = nEndPos + aExpand.Len();
+ rTxtStt = rTxtStt - aExpand.Len();
+ }
+ ++rTxtStt;
+ break;
+ case RES_TXTATR_FTN:
+ rTxt.Erase( nPos, 1 );
+ if( bExpandFlds )
+ {
+ const SwFmtFtn& rFtn = pAttr->GetFtn();
+ XubString sExpand;
+ if( rFtn.GetNumStr().Len() )
+ sExpand = rFtn.GetNumStr();
+ else if( rFtn.IsEndNote() )
+ sExpand = GetDoc()->GetEndNoteInfo().aFmt.
+ GetNumStr( rFtn.GetNumber() );
+ else
+ sExpand = GetDoc()->GetFtnInfo().aFmt.
+ GetNumStr( rFtn.GetNumber() );
+ rTxt.Insert( sExpand, nPos );
+ nPos = nPos + sExpand.Len();
+ nEndPos = nEndPos + sExpand.Len();
+ rTxtStt = rTxtStt - sExpand.Len();
+ }
+ ++rTxtStt;
+ break;
+ default:
+ rTxt.Erase( nPos, 1 );
+ ++rTxtStt;
+ }
+ }
+ else
+ ++nPos, ++nEndPos;
+ nPos = rTxt.Search( cSrchChr, nPos );
+ }
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtNode::GetExpandTxt
+ * Expand fields
+ *************************************************************************/
+// --> OD 2007-11-15 #i83479# - handling of new parameters
+XubString SwTxtNode::GetExpandTxt( const xub_StrLen nIdx,
+ const xub_StrLen nLen,
+ const bool bWithNum,
+ const bool bAddSpaceAfterListLabelStr,
+ const bool bWithSpacesForLevel ) const
+{
+ XubString aTxt( GetTxt().Copy( nIdx, nLen ) );
+ xub_StrLen nTxtStt = nIdx;
+ Replace0xFF( aTxt, nTxtStt, aTxt.Len(), sal_True );
+ if( bWithNum )
+ {
+ XubString aListLabelStr = GetNumString();
+ if ( aListLabelStr.Len() > 0 )
+ {
+ if ( bAddSpaceAfterListLabelStr )
+ {
+ const sal_Unicode aSpace = ' ';
+ aTxt.Insert( aSpace, 0 );
+ }
+ aTxt.Insert( GetNumString(), 0 );
+ }
+ }
+
+ if ( bWithSpacesForLevel && GetActualListLevel() > 0 )
+ {
+ int nLevel( GetActualListLevel() );
+ while ( nLevel > 0 )
+ {
+ const sal_Unicode aSpace = ' ';
+ aTxt.Insert( aSpace , 0 );
+ aTxt.Insert( aSpace , 0 );
+ --nLevel;
+ }
+ }
+
+ return aTxt;
+}
+
+sal_Bool SwTxtNode::GetExpandTxt( SwTxtNode& rDestNd, const SwIndex* pDestIdx,
+ xub_StrLen nIdx, xub_StrLen nLen, sal_Bool bWithNum,
+ sal_Bool bWithFtn, sal_Bool bReplaceTabsWithSpaces ) const
+{
+ if( &rDestNd == this )
+ return sal_False;
+
+ SwIndex aDestIdx( &rDestNd, rDestNd.GetTxt().Len() );
+ if( pDestIdx )
+ aDestIdx = *pDestIdx;
+ xub_StrLen nDestStt = aDestIdx.GetIndex();
+
+ // Text einfuegen
+ String sTmpText = GetTxt();
+ if( bReplaceTabsWithSpaces )
+ sTmpText.SearchAndReplaceAll('\t', ' ');
+
+ // mask hidden characters
+ const xub_Unicode cChar = CH_TXTATR_BREAKWORD;
+ sal_uInt16 nHiddenChrs =
+ SwScriptInfo::MaskHiddenRanges( *this, sTmpText, 0, sTmpText.Len(), cChar );
+
+ sTmpText = sTmpText.Copy( nIdx, nLen );
+ rDestNd.InsertText( sTmpText, aDestIdx );
+ nLen = aDestIdx.GetIndex() - nDestStt;
+
+ // alle FontAttribute mit CHARSET Symbol in dem Bereich setzen
+ if ( HasHints() )
+ {
+ xub_StrLen nInsPos = nDestStt - nIdx;
+ for ( sal_uInt16 i = 0; i < m_pSwpHints->Count(); i++ )
+ {
+ const SwTxtAttr* pHt = (*m_pSwpHints)[i];
+ const xub_StrLen nAttrStartIdx = *pHt->GetStart();
+ const sal_uInt16 nWhich = pHt->Which();
+ if (nIdx + nLen <= nAttrStartIdx)
+ break; // ueber das Textende
+
+ const xub_StrLen *pEndIdx = pHt->GetEnd();
+ if( pEndIdx && *pEndIdx > nIdx &&
+ ( RES_CHRATR_FONT == nWhich ||
+ RES_TXTATR_CHARFMT == nWhich ||
+ RES_TXTATR_AUTOFMT == nWhich ))
+ {
+ const SvxFontItem* const pFont =
+ static_cast<const SvxFontItem*>(
+ CharFmt::GetItem( *pHt, RES_CHRATR_FONT ));
+ if ( pFont && RTL_TEXTENCODING_SYMBOL == pFont->GetCharSet() )
+ {
+ // attribute in area => copy
+ rDestNd.InsertItem( *const_cast<SvxFontItem*>(pFont),
+ nInsPos + nAttrStartIdx, nInsPos + *pEndIdx );
+ }
+ }
+ else if ( pHt->HasDummyChar() && (nAttrStartIdx >= nIdx) )
+ {
+ aDestIdx = nInsPos + nAttrStartIdx;
+ switch( nWhich )
+ {
+ case RES_TXTATR_FIELD:
+ {
+ XubString const aExpand(
+ static_cast<SwTxtFld const*>(pHt)->GetFld().GetFld()
+ ->ExpandField(true));
+ if( aExpand.Len() )
+ {
+ aDestIdx++; // dahinter einfuegen;
+ rDestNd.InsertText( aExpand, aDestIdx );
+ aDestIdx = nInsPos + nAttrStartIdx;
+ nInsPos = nInsPos + aExpand.Len();
+ }
+ rDestNd.EraseText( aDestIdx, 1 );
+ --nInsPos;
+ }
+ break;
+
+ case RES_TXTATR_FTN:
+ {
+ if ( bWithFtn )
+ {
+ const SwFmtFtn& rFtn = pHt->GetFtn();
+ XubString sExpand;
+ if( rFtn.GetNumStr().Len() )
+ sExpand = rFtn.GetNumStr();
+ else if( rFtn.IsEndNote() )
+ sExpand = GetDoc()->GetEndNoteInfo().aFmt.
+ GetNumStr( rFtn.GetNumber() );
+ else
+ sExpand = GetDoc()->GetFtnInfo().aFmt.
+ GetNumStr( rFtn.GetNumber() );
+ if( sExpand.Len() )
+ {
+ aDestIdx++; // insert behind
+ SvxEscapementItem aItem(
+ SVX_ESCAPEMENT_SUPERSCRIPT );
+ rDestNd.InsertItem(aItem,
+ aDestIdx.GetIndex(),
+ aDestIdx.GetIndex() );
+ rDestNd.InsertText( sExpand, aDestIdx,
+ IDocumentContentOperations::INS_EMPTYEXPAND);
+ aDestIdx = nInsPos + nAttrStartIdx;
+ nInsPos = nInsPos + sExpand.Len();
+ }
+ }
+ rDestNd.EraseText( aDestIdx, 1 );
+ --nInsPos;
+ }
+ break;
+
+ default:
+ rDestNd.EraseText( aDestIdx, 1 );
+ --nInsPos;
+ }
+ }
+ }
+ }
+
+ if( bWithNum )
+ {
+ aDestIdx = nDestStt;
+ rDestNd.InsertText( GetNumString(), aDestIdx );
+ }
+
+ if ( nHiddenChrs > 0 )
+ {
+ aDestIdx = 0;
+ while ( aDestIdx < rDestNd.GetTxt().Len() )
+ {
+ if ( cChar == rDestNd.GetTxt().GetChar( aDestIdx.GetIndex() ) )
+ {
+ xub_StrLen nIndex = aDestIdx.GetIndex();
+ while ( nIndex < rDestNd.GetTxt().Len() &&
+ cChar == rDestNd.GetTxt().GetChar( ++nIndex ) )
+ ;
+ rDestNd.EraseText( aDestIdx, nIndex - aDestIdx.GetIndex() );
+ }
+ else
+ ++aDestIdx;
+ }
+ }
+
+ return sal_True;
+}
+
+const ModelToViewHelper::ConversionMap*
+ SwTxtNode::BuildConversionMap( rtl::OUString& rRetText ) const
+{
+ const rtl::OUString& rNodeText = GetTxt();
+ rRetText = rNodeText;
+ ModelToViewHelper::ConversionMap* pConversionMap = 0;
+
+ const SwpHints* pSwpHints2 = GetpSwpHints();
+ xub_StrLen nPos = 0;
+
+ for ( sal_uInt16 i = 0; pSwpHints2 && i < pSwpHints2->Count(); ++i )
+ {
+ const SwTxtAttr* pAttr = (*pSwpHints2)[i];
+ if ( RES_TXTATR_FIELD == pAttr->Which() )
+ {
+ const XubString aExpand(
+ static_cast<SwTxtFld const*>(pAttr)->GetFld().GetFld()
+ ->ExpandField(true));
+ if ( aExpand.Len() > 0 )
+ {
+ const xub_StrLen nFieldPos = *pAttr->GetStart();
+ rRetText = rRetText.replaceAt( nPos + nFieldPos, 1, aExpand );
+ if ( !pConversionMap )
+ pConversionMap = new ModelToViewHelper::ConversionMap;
+ pConversionMap->push_back(
+ ModelToViewHelper::ConversionMapEntry(
+ nFieldPos, nPos + nFieldPos ) );
+ nPos += ( aExpand.Len() - 1 );
+ }
+ }
+ }
+
+ if ( pConversionMap && pConversionMap->size() )
+ pConversionMap->push_back(
+ ModelToViewHelper::ConversionMapEntry(
+ rNodeText.getLength()+1, rRetText.getLength()+1 ) );
+
+ return pConversionMap;
+}
+
+XubString SwTxtNode::GetRedlineTxt( xub_StrLen nIdx, xub_StrLen nLen,
+ sal_Bool bExpandFlds, sal_Bool bWithNum ) const
+{
+ SvUShorts aRedlArr;
+ const SwDoc* pDoc = GetDoc();
+ sal_uInt16 nRedlPos = pDoc->GetRedlinePos( *this, nsRedlineType_t::REDLINE_DELETE );
+ if( USHRT_MAX != nRedlPos )
+ {
+ // es existiert fuer den Node irgendein Redline-Delete-Object
+ const sal_uLong nNdIdx = GetIndex();
+ for( ; nRedlPos < pDoc->GetRedlineTbl().Count() ; ++nRedlPos )
+ {
+ const SwRedline* pTmp = pDoc->GetRedlineTbl()[ nRedlPos ];
+ if( nsRedlineType_t::REDLINE_DELETE == pTmp->GetType() )
+ {
+ const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
+ if( pRStt->nNode < nNdIdx )
+ {
+ if( pREnd->nNode > nNdIdx )
+ // Absatz ist komplett geloescht
+ return aEmptyStr;
+ else if( pREnd->nNode == nNdIdx )
+ {
+ // von 0 bis nContent ist alles geloescht
+ aRedlArr.Insert( xub_StrLen(0), aRedlArr.Count() );
+ aRedlArr.Insert( pREnd->nContent.GetIndex(), aRedlArr.Count() );
+ }
+ }
+ else if( pRStt->nNode == nNdIdx )
+ {
+ aRedlArr.Insert( pRStt->nContent.GetIndex(), aRedlArr.Count() );
+ if( pREnd->nNode == nNdIdx )
+ aRedlArr.Insert( pREnd->nContent.GetIndex(), aRedlArr.Count() );
+ else
+ {
+ aRedlArr.Insert( GetTxt().Len(), aRedlArr.Count() );
+ break; // mehr kann nicht kommen
+ }
+ }
+ else
+ break; // mehr kann nicht kommen
+ }
+ }
+ }
+
+ XubString aTxt( GetTxt().Copy( nIdx, nLen ) );
+
+ xub_StrLen nTxtStt = nIdx, nIdxEnd = nIdx + aTxt.Len();
+ for( sal_uInt16 n = 0; n < aRedlArr.Count(); n += 2 )
+ {
+ xub_StrLen nStt = aRedlArr[ n ], nEnd = aRedlArr[ n+1 ];
+ if( ( nIdx <= nStt && nStt <= nIdxEnd ) ||
+ ( nIdx <= nEnd && nEnd <= nIdxEnd ))
+ {
+ if( nStt < nIdx ) nStt = nIdx;
+ if( nIdxEnd < nEnd ) nEnd = nIdxEnd;
+ xub_StrLen nDelCnt = nEnd - nStt;
+ aTxt.Erase( nStt - nTxtStt, nDelCnt );
+ Replace0xFF( aTxt, nTxtStt, nStt - nTxtStt, bExpandFlds );
+ nTxtStt = nTxtStt + nDelCnt;
+ }
+ else if( nStt >= nIdxEnd )
+ break;
+ }
+ Replace0xFF( aTxt, nTxtStt, aTxt.Len(), bExpandFlds );
+
+ if( bWithNum )
+ aTxt.Insert( GetNumString(), 0 );
+ return aTxt;
+}
+
+/*************************************************************************
+ * SwTxtNode::ReplaceText
+ *************************************************************************/
+
+void SwTxtNode::ReplaceText( const SwIndex& rStart, const xub_StrLen nDelLen,
+ const XubString& rText )
+{
+ OSL_ENSURE( rStart.GetIndex() < m_Text.Len() &&
+ rStart.GetIndex() + nDelLen <= m_Text.Len(),
+ "SwTxtNode::ReplaceText: index out of bounds" );
+ const xub_StrLen nStartPos = rStart.GetIndex();
+ xub_StrLen nEndPos = nStartPos + nDelLen;
+ xub_StrLen nLen = nDelLen;
+ for ( xub_StrLen nPos = nStartPos; nPos < nEndPos; ++nPos )
+ {
+ if ( ( CH_TXTATR_BREAKWORD == m_Text.GetChar( nPos ) ) ||
+ ( CH_TXTATR_INWORD == m_Text.GetChar( nPos ) ) )
+ {
+ SwTxtAttr *const pHint = GetTxtAttrForCharAt( nPos );
+ if (pHint)
+ {
+ OSL_ENSURE(!( pHint->GetEnd() && pHint->HasDummyChar()
+ && (*pHint->GetStart() < nEndPos)
+ && (*pHint->GetEnd() > nEndPos) ),
+ "ReplaceText: ERROR: "
+ "deleting left-overlapped attribute with CH_TXTATR");
+ DeleteAttribute( pHint );
+ --nEndPos;
+ --nLen;
+ }
+ }
+ }
+
+ sal_Bool bOldExpFlg = IsIgnoreDontExpand();
+ SetIgnoreDontExpand( sal_True );
+
+ if( nLen && rText.Len() )
+ {
+ // dann das 1. Zeichen ersetzen den Rest loschen und einfuegen
+ // Dadurch wird die Attributierung des 1. Zeichen expandiert!
+ m_Text.SetChar( nStartPos, rText.GetChar( 0 ) );
+
+ ((SwIndex&)rStart)++;
+ m_Text.Erase( rStart.GetIndex(), nLen - 1 );
+ Update( rStart, nLen - 1, true );
+
+ XubString aTmpTxt( rText ); aTmpTxt.Erase( 0, 1 );
+ m_Text.Insert( aTmpTxt, rStart.GetIndex() );
+ Update( rStart, aTmpTxt.Len(), false );
+ }
+ else
+ {
+ m_Text.Erase( nStartPos, nLen );
+ Update( rStart, nLen, true );
+
+ m_Text.Insert( rText, nStartPos );
+ Update( rStart, rText.Len(), false );
+ }
+
+ SetIgnoreDontExpand( bOldExpFlg );
+ SwDelTxt aDelHint( nStartPos, nDelLen );
+ NotifyClients( 0, &aDelHint );
+
+ SwInsTxt aHint( nStartPos, rText.Len() );
+ NotifyClients( 0, &aHint );
+}
+
+namespace {
+ // Helper method for special handling of modified attributes at text node.
+ // The following is handled:
+ // (1) on changing the paragraph style - RES_FMT_CHG:
+ // Check, if list style of the text node is changed. If yes, add respectively
+ // remove the text node to the corresponding list.
+ // (2) on changing the attributes - RES_ATTRSET_CHG:
+ // Same as (1).
+ // (3) on changing the list style - RES_PARATR_NUMRULE:
+ // Same as (1).
+ void HandleModifyAtTxtNode( SwTxtNode& rTxtNode,
+ const SfxPoolItem* pOldValue,
+ const SfxPoolItem* pNewValue )
+ {
+ const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() :
+ pNewValue ? pNewValue->Which() : 0 ;
+ bool bNumRuleSet = false;
+ bool bParagraphStyleChanged = false;
+ String sNumRule;
+ String sOldNumRule;
+ switch ( nWhich )
+ {
+ case RES_FMT_CHG:
+ {
+ bParagraphStyleChanged = true;
+ if( rTxtNode.GetNodes().IsDocNodes() )
+ {
+ // #i70748#
+ const SwNumRule* pFormerNumRuleAtTxtNode =
+ rTxtNode.GetNum() ? rTxtNode.GetNum()->GetNumRule() : 0;
+ if ( pFormerNumRuleAtTxtNode )
+ {
+ sOldNumRule = pFormerNumRuleAtTxtNode->GetName();
+ }
+ // #i70748#
+ if ( rTxtNode.IsEmptyListStyleDueToSetOutlineLevelAttr() )
+ {
+ const SwNumRuleItem& rNumRuleItem = rTxtNode.GetTxtColl()->GetNumRule();
+ if ( rNumRuleItem.GetValue().Len() > 0 )
+ {
+ rTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ }
+ }
+
+ const SwNumRule* pNumRuleAtTxtNode = rTxtNode.GetNumRule();
+ if ( pNumRuleAtTxtNode )
+ {
+ bNumRuleSet = true;
+ sNumRule = pNumRuleAtTxtNode->GetName();
+ }
+ }
+ break;
+ }
+ case RES_ATTRSET_CHG:
+ {
+ const SfxPoolItem* pItem = 0;
+ // #i70748#
+ const SwNumRule* pFormerNumRuleAtTxtNode =
+ rTxtNode.GetNum() ? rTxtNode.GetNum()->GetNumRule() : 0;
+ if ( pFormerNumRuleAtTxtNode )
+ {
+ sOldNumRule = pFormerNumRuleAtTxtNode->GetName();
+ }
+
+ if ( dynamic_cast<const SwAttrSetChg*>(pNewValue)->GetChgSet()->GetItemState( RES_PARATR_NUMRULE, sal_False, &pItem ) ==
+ SFX_ITEM_SET )
+ {
+ // #i70748#
+ rTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ bNumRuleSet = true;
+ }
+ // #i70748#
+ // The new list style set at the paragraph.
+ const SwNumRule* pNumRuleAtTxtNode = rTxtNode.GetNumRule();
+ if ( pNumRuleAtTxtNode )
+ {
+ sNumRule = pNumRuleAtTxtNode->GetName();
+ }
+ break;
+ }
+ case RES_PARATR_NUMRULE:
+ {
+ if ( rTxtNode.GetNodes().IsDocNodes() )
+ {
+ const SwNumRule* pFormerNumRuleAtTxtNode =
+ rTxtNode.GetNum() ? rTxtNode.GetNum()->GetNumRule() : 0;
+ if ( pFormerNumRuleAtTxtNode )
+ {
+ sOldNumRule = pFormerNumRuleAtTxtNode->GetName();
+ }
+
+ if ( pNewValue )
+ {
+ // #i70748#
+ rTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ bNumRuleSet = true;
+ }
+ // --> OD 2008-12-17 #i70748#
+ // The new list style set at the paragraph.
+ const SwNumRule* pNumRuleAtTxtNode = rTxtNode.GetNumRule();
+ if ( pNumRuleAtTxtNode )
+ {
+ sNumRule = pNumRuleAtTxtNode->GetName();
+ }
+ }
+ break;
+ }
+ }
+ if ( sNumRule != sOldNumRule )
+ {
+ if ( bNumRuleSet )
+ {
+ if ( sNumRule.Len() == 0 )
+ {
+ rTxtNode.RemoveFromList();
+ if ( bParagraphStyleChanged )
+ {
+ SvUShortsSort aResetAttrsArray;
+ aResetAttrsArray.Insert( RES_PARATR_LIST_ID );
+ aResetAttrsArray.Insert( RES_PARATR_LIST_LEVEL );
+ aResetAttrsArray.Insert( RES_PARATR_LIST_ISRESTART );
+ aResetAttrsArray.Insert( RES_PARATR_LIST_RESTARTVALUE );
+ aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED );
+ SwPaM aPam( rTxtNode );
+ // --> OD 2008-11-28 #i96644#
+ // suppress side effect "send data changed events"
+ rTxtNode.GetDoc()->ResetAttrs( aPam, sal_False,
+ &aResetAttrsArray,
+ false );
+ }
+ }
+ else
+ {
+ rTxtNode.RemoveFromList();
+ // If new list style is the outline style, apply outline
+ // level as the list level.
+ if ( sNumRule ==
+ String::CreateFromAscii( SwNumRule::GetOutlineRuleName() ) )
+ {
+ // --> OD 2008-09-10 #i70748#
+ OSL_ENSURE( rTxtNode.GetTxtColl()->IsAssignedToListLevelOfOutlineStyle(),
+ "<HandleModifyAtTxtNode()> - text node with outline style, but its paragraph style is not assigned to outline style." );
+ int nNewListLevel =
+ rTxtNode.GetTxtColl()->GetAssignedOutlineStyleLevel();
+ if ( 0 <= nNewListLevel && nNewListLevel < MAXLEVEL )
+ {
+ rTxtNode.SetAttrListLevel( nNewListLevel );
+ }
+ }
+ rTxtNode.AddToList();
+ }
+ }
+ else // <sNumRule.Len() == 0 && sOldNumRule.Len() != 0>
+ {
+ rTxtNode.RemoveFromList();
+ if ( bParagraphStyleChanged )
+ {
+ SvUShortsSort aResetAttrsArray;
+ aResetAttrsArray.Insert( RES_PARATR_LIST_ID );
+ aResetAttrsArray.Insert( RES_PARATR_LIST_LEVEL );
+ aResetAttrsArray.Insert( RES_PARATR_LIST_ISRESTART );
+ aResetAttrsArray.Insert( RES_PARATR_LIST_RESTARTVALUE );
+ aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED );
+ SwPaM aPam( rTxtNode );
+ // --> OD 2008-11-28 #i96644#
+ // suppress side effect "send data changed events"
+ rTxtNode.GetDoc()->ResetAttrs( aPam, sal_False,
+ &aResetAttrsArray,
+ false );
+ // <--
+ // --> OD 2008-11-19 #i70748#
+ if ( dynamic_cast<const SfxUInt16Item &>(rTxtNode.GetAttr( RES_PARATR_OUTLINELEVEL, sal_False )).GetValue() > 0 )
+ {
+ rTxtNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
+ }
+ // <--
+ }
+ }
+ }
+ else if ( sNumRule.Len() > 0 && !rTxtNode.IsInList() )
+ {
+ rTxtNode.AddToList();
+ }
+ }
+ // End of method <HandleModifyAtTxtNode>
+}
+
+void SwTxtNode::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
+{
+ bool bWasNotifiable = m_bNotifiable;
+ m_bNotifiable = false;
+
+ // Bug 24616/24617:
+ // Modify ueberladen, damit beim Loeschen von Vorlagen diese
+ // wieder richtig verwaltet werden (Outline-Numerierung!!)
+ // Bug25481:
+ // bei Nodes im Undo nie _ChgTxtCollUpdateNum rufen.
+ if( pOldValue && pNewValue && RES_FMT_CHG == pOldValue->Which() &&
+ GetRegisteredIn() == ((SwFmtChg*)pNewValue)->pChangedFmt &&
+ GetNodes().IsDocNodes() )
+ {
+ _ChgTxtCollUpdateNum(
+ (SwTxtFmtColl*)((SwFmtChg*)pOldValue)->pChangedFmt,
+ (SwTxtFmtColl*)((SwFmtChg*)pNewValue)->pChangedFmt );
+ }
+
+ if ( !mbInSetOrResetAttr )
+ {
+ HandleModifyAtTxtNode( *this, pOldValue, pNewValue );
+ }
+
+ SwCntntNode::Modify( pOldValue, pNewValue );
+
+ SwDoc * pDoc = GetDoc();
+ // --> OD 2005-11-02 #125329# - assure that text node is in document nodes array
+ if ( pDoc && !pDoc->IsInDtor() && &pDoc->GetNodes() == &GetNodes() )
+ // <--
+ {
+ pDoc->GetNodes().UpdateOutlineNode(*this);
+ }
+
+ m_bNotifiable = bWasNotifiable;
+
+ if (pOldValue && (RES_REMOVE_UNO_OBJECT == pOldValue->Which()))
+ { // invalidate cached uno object
+ SetXParagraph(::com::sun::star::uno::Reference<
+ ::com::sun::star::text::XTextContent>(0));
+ }
+}
+
+SwFmtColl* SwTxtNode::ChgFmtColl( SwFmtColl *pNewColl )
+{
+ OSL_ENSURE( pNewColl,"ChgFmtColl: Collectionpointer ist 0." );
+ OSL_ENSURE( HAS_BASE( SwTxtFmtColl, pNewColl ),
+ "ChgFmtColl: ist kein Text-Collectionpointer." );
+
+ SwTxtFmtColl *pOldColl = GetTxtColl();
+ if( pNewColl != pOldColl )
+ {
+ SetCalcHiddenCharFlags();
+ SwCntntNode::ChgFmtColl( pNewColl );
+#if OSL_DEBUG_LEVEL > 1
+ OSL_ENSURE( !mbInSetOrResetAttr,
+ "DEBUG OSL_ENSURE(ON - <SwTxtNode::ChgFmtColl(..)> called during <Set/ResetAttr(..)>" );
+#endif
+ if ( !mbInSetOrResetAttr )
+ {
+ SwFmtChg aTmp1( pOldColl );
+ SwFmtChg aTmp2( pNewColl );
+ HandleModifyAtTxtNode( *this, &aTmp1, &aTmp2 );
+ }
+ }
+
+ // nur wenn im normalen Nodes-Array
+ if( GetNodes().IsDocNodes() )
+ {
+ _ChgTxtCollUpdateNum( pOldColl, static_cast<SwTxtFmtColl *>(pNewColl) );
+ }
+
+ GetNodes().UpdateOutlineNode(*this);
+
+ return pOldColl;
+}
+
+SwNodeNum* SwTxtNode::CreateNum() const
+{
+ if ( !mpNodeNum )
+ {
+ mpNodeNum = new SwNodeNum( const_cast<SwTxtNode*>(this) );
+ }
+ return mpNodeNum;
+}
+
+SwNumberTree::tNumberVector SwTxtNode::GetNumberVector() const
+{
+ if ( GetNum() )
+ {
+ return GetNum()->GetNumberVector();
+ }
+ else
+ {
+ SwNumberTree::tNumberVector aResult;
+ return aResult;
+ }
+}
+
+bool SwTxtNode::IsOutline() const
+{
+ bool bResult = false;
+
+ if ( GetAttrOutlineLevel() > 0 )
+ {
+ bResult = !IsInRedlines();
+ }
+ else
+ {
+ const SwNumRule* pRule( GetNum() ? GetNum()->GetNumRule() : 0L );
+ if ( pRule && pRule->IsOutlineRule() )
+ {
+ bResult = !IsInRedlines();
+ }
+ }
+
+ return bResult;
+}
+
+bool SwTxtNode::IsOutlineStateChanged() const
+{
+ return IsOutline() != m_bLastOutlineState;
+}
+
+void SwTxtNode::UpdateOutlineState()
+{
+ m_bLastOutlineState = IsOutline();
+}
+
+//#outline level, zhaojianwei
+int SwTxtNode::GetAttrOutlineLevel() const
+{
+ return ((const SfxUInt16Item &)GetAttr(RES_PARATR_OUTLINELEVEL)).GetValue();
+}
+void SwTxtNode::SetAttrOutlineLevel(int nLevel)
+{
+ OSL_ENSURE( 0 <= nLevel && nLevel <= MAXLEVEL ,"SwTxtNode: Level Out Of Range" );//#outline level,zhaojianwei
+ if ( 0 <= nLevel && nLevel <= MAXLEVEL )
+ {
+ SetAttr( SfxUInt16Item( RES_PARATR_OUTLINELEVEL,
+ static_cast<sal_uInt16>(nLevel) ) );
+ }
+}
+//<-end
+
+// --> OD 2008-11-19 #i70748#
+bool SwTxtNode::IsEmptyListStyleDueToSetOutlineLevelAttr()
+{
+ return mbEmptyListStyleSetDueToSetOutlineLevelAttr;
+}
+
+void SwTxtNode::SetEmptyListStyleDueToSetOutlineLevelAttr()
+{
+ if ( !mbEmptyListStyleSetDueToSetOutlineLevelAttr )
+ {
+ SetAttr( SwNumRuleItem() );
+ mbEmptyListStyleSetDueToSetOutlineLevelAttr = true;
+ }
+}
+
+void SwTxtNode::ResetEmptyListStyleDueToResetOutlineLevelAttr()
+{
+ if ( mbEmptyListStyleSetDueToSetOutlineLevelAttr )
+ {
+ ResetAttr( RES_PARATR_NUMRULE );
+ mbEmptyListStyleSetDueToSetOutlineLevelAttr = false;
+ }
+}
+// <--
+
+
+void SwTxtNode::SetAttrListLevel( int nLevel )
+{
+ if ( nLevel < 0 || nLevel >= MAXLEVEL )
+ {
+ OSL_FAIL( "<SwTxtNode::SetAttrListLevel()> - value of parameter <nLevel> is out of valid range" );
+ return;
+ }
+
+ SfxInt16Item aNewListLevelItem( RES_PARATR_LIST_LEVEL,
+ static_cast<sal_Int16>(nLevel) );
+ SetAttr( aNewListLevelItem );
+}
+
+bool SwTxtNode::HasAttrListLevel() const
+{
+ return GetpSwAttrSet() &&
+ GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_LEVEL, sal_False ) == SFX_ITEM_SET;
+}
+
+int SwTxtNode::GetAttrListLevel() const
+{
+ int nAttrListLevel = 0;
+
+ const SfxInt16Item& aListLevelItem =
+ dynamic_cast<const SfxInt16Item&>(GetAttr( RES_PARATR_LIST_LEVEL ));
+ nAttrListLevel = static_cast<int>(aListLevelItem.GetValue());
+
+ return nAttrListLevel;
+}
+
+int SwTxtNode::GetActualListLevel() const
+{
+ return GetNum() ? GetNum()->GetLevelInListTree() : -1;
+}
+
+void SwTxtNode::SetListRestart( bool bRestart )
+{
+// CreateNum()->SetRestart(bRestart);
+ if ( !bRestart )
+ {
+ // attribute not contained in paragraph style's attribute set. Thus,
+ // it can be reset to the attribute pool default by resetting the attribute.
+ ResetAttr( RES_PARATR_LIST_ISRESTART );
+ }
+ else
+ {
+ SfxBoolItem aNewIsRestartItem( RES_PARATR_LIST_ISRESTART,
+ sal_True );
+ SetAttr( aNewIsRestartItem );
+ }
+}
+
+bool SwTxtNode::IsListRestart() const
+{
+// return GetNum() ? GetNum()->IsRestart() : false;
+ const SfxBoolItem& aIsRestartItem =
+ dynamic_cast<const SfxBoolItem&>(GetAttr( RES_PARATR_LIST_ISRESTART ));
+
+ return aIsRestartItem.GetValue() ? true : false;
+}
+
+/** Returns if the paragraph has a visible numbering or bullet.
+ This includes all kinds of numbering/bullet/outlines.
+ The concrete list label string has to be checked, too.
+ */
+bool SwTxtNode::HasVisibleNumberingOrBullet() const
+{
+ bool bRet = false;
+
+ const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
+ if ( pRule && IsCountedInList())
+ {
+ // --> OD 2008-03-19 #i87154#
+ // Correction of #newlistlevelattrs#:
+ // The numbering type has to be checked for bullet lists.
+ const SwNumFmt& rFmt = pRule->Get( static_cast<sal_uInt16>(GetActualListLevel() ));
+ if ( SVX_NUM_NUMBER_NONE != rFmt.GetNumberingType() ||
+ pRule->MakeNumString( *(GetNum()) ).Len() > 0 )
+ {
+ bRet = true;
+ }
+ // <--
+ }
+
+ return bRet;
+}
+
+void SwTxtNode::SetAttrListRestartValue( SwNumberTree::tSwNumTreeNumber nNumber )
+{
+// CreateNum()->SetStart(nNumber);
+ const bool bChanged( HasAttrListRestartValue()
+ ? GetAttrListRestartValue() != nNumber
+ : nNumber != USHRT_MAX );
+
+ if ( bChanged || !HasAttrListRestartValue() )
+ {
+ if ( nNumber == USHRT_MAX )
+ {
+ ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
+ }
+ else
+ {
+ SfxInt16Item aNewListRestartValueItem( RES_PARATR_LIST_RESTARTVALUE,
+ static_cast<sal_Int16>(nNumber) );
+ SetAttr( aNewListRestartValueItem );
+ }
+ }
+}
+
+bool SwTxtNode::HasAttrListRestartValue() const
+{
+ return GetpSwAttrSet() &&
+ GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_RESTARTVALUE, sal_False ) == SFX_ITEM_SET;
+}
+SwNumberTree::tSwNumTreeNumber SwTxtNode::GetAttrListRestartValue() const
+{
+ OSL_ENSURE( HasAttrListRestartValue(),
+ "<SwTxtNode::GetAttrListRestartValue()> - only ask for list restart value, if attribute is set at text node." );
+
+ const SfxInt16Item& aListRestartValueItem =
+ dynamic_cast<const SfxInt16Item&>(GetAttr( RES_PARATR_LIST_RESTARTVALUE ));
+ return static_cast<SwNumberTree::tSwNumTreeNumber>(aListRestartValueItem.GetValue());
+}
+
+SwNumberTree::tSwNumTreeNumber SwTxtNode::GetActualListStartValue() const
+{
+// return GetNum() ? GetNum()->GetStart() : 1;
+ SwNumberTree::tSwNumTreeNumber nListRestartValue = 1;
+
+ if ( IsListRestart() && HasAttrListRestartValue() )
+ {
+ nListRestartValue = GetAttrListRestartValue();
+ }
+ else
+ {
+ SwNumRule* pRule = GetNumRule();
+ if ( pRule )
+ {
+ const SwNumFmt* pFmt =
+ pRule->GetNumFmt( static_cast<sal_uInt16>(GetAttrListLevel()) );
+ if ( pFmt )
+ {
+ nListRestartValue = pFmt->GetStart();
+ }
+ }
+ }
+
+ return nListRestartValue;
+}
+
+bool SwTxtNode::IsNotifiable() const
+{
+ return m_bNotifiable && IsNotificationEnabled();
+}
+
+bool SwTxtNode::IsNotificationEnabled() const
+{
+ bool bResult = false;
+ const SwDoc * pDoc = GetDoc();
+ if( pDoc )
+ {
+ bResult = pDoc->IsInReading() || pDoc->IsInDtor() ? false : true;
+ }
+ return bResult;
+}
+
+void SwTxtNode::SetCountedInList( bool bCounted )
+{
+ if ( bCounted )
+ {
+ // attribute not contained in paragraph style's attribute set. Thus,
+ // it can be reset to the attribute pool default by resetting the attribute.
+ ResetAttr( RES_PARATR_LIST_ISCOUNTED );
+ }
+ else
+ {
+ SfxBoolItem aIsCountedInListItem( RES_PARATR_LIST_ISCOUNTED, sal_False );
+ SetAttr( aIsCountedInListItem );
+ }
+}
+
+bool SwTxtNode::IsCountedInList() const
+{
+ const SfxBoolItem& aIsCountedInListItem =
+ dynamic_cast<const SfxBoolItem&>(GetAttr( RES_PARATR_LIST_ISCOUNTED ));
+
+ return aIsCountedInListItem.GetValue() ? true : false;
+}
+
+void SwTxtNode::AddToList()
+{
+ if ( IsInList() )
+ {
+ OSL_FAIL( "<SwTxtNode::AddToList()> - the text node is already added to a list. Serious defect -> please inform OD" );
+ return;
+ }
+
+ const String sListId = GetListId();
+ if ( sListId.Len() > 0 )
+ {
+ SwList* pList = GetDoc()->getListByName( sListId );
+ if ( pList == 0 )
+ {
+ // Create corresponding list.
+ SwNumRule* pNumRule = GetNumRule();
+ if ( pNumRule )
+ {
+ pList = GetDoc()->createList( sListId, GetNumRule()->GetName() );
+ }
+ }
+ OSL_ENSURE( pList != 0,
+ "<SwTxtNode::AddToList()> - no list for given list id. Serious defect -> please inform OD" );
+ if ( pList )
+ {
+ pList->InsertListItem( *CreateNum(), GetAttrListLevel() );
+ mpList = pList;
+ }
+ }
+}
+
+void SwTxtNode::RemoveFromList()
+{
+ if ( IsInList() )
+ {
+ mpList->RemoveListItem( *mpNodeNum );
+ mpList = 0;
+ delete mpNodeNum;
+ mpNodeNum = 0L;
+ }
+}
+
+bool SwTxtNode::IsInList() const
+{
+ return GetNum() != 0 && GetNum()->GetParent() != 0;
+}
+
+bool SwTxtNode::IsFirstOfNumRule() const
+{
+ bool bResult = false;
+
+ if ( GetNum() && GetNum()->GetNumRule())
+ bResult = GetNum()->IsFirst();
+
+ return bResult;
+}
+
+void SwTxtNode::SetListId( const String sListId )
+{
+ const SfxStringItem& rListIdItem =
+ dynamic_cast<const SfxStringItem&>(GetAttr( RES_PARATR_LIST_ID ));
+ if ( rListIdItem.GetValue() != sListId )
+ {
+ if ( sListId.Len() == 0 )
+ {
+ ResetAttr( RES_PARATR_LIST_ID );
+ }
+ else
+ {
+ SfxStringItem aNewListIdItem( RES_PARATR_LIST_ID, sListId );
+ SetAttr( aNewListIdItem );
+ }
+ }
+}
+
+String SwTxtNode::GetListId() const
+{
+ String sListId;
+
+ const SfxStringItem& rListIdItem =
+ dynamic_cast<const SfxStringItem&>(GetAttr( RES_PARATR_LIST_ID ));
+ sListId = rListIdItem.GetValue();
+
+ // As long as no explicit list id attribute is set, use the list id of
+ // the list, which has been created for the applied list style.
+ if ( sListId.Len() == 0 )
+ {
+ SwNumRule* pRule = GetNumRule();
+ if ( pRule )
+ {
+ sListId = pRule->GetDefaultListId();
+ }
+ }
+
+ return sListId;
+}
+
+/** Determines, if the list level indent attributes can be applied to the
+ paragraph.
+
+ The list level indents can be applied to the paragraph under the one
+ of following conditions:
+ - the list style is directly applied to the paragraph and the paragraph
+ has no own indent attributes.
+ - the list style is applied to the paragraph through one of its paragraph
+ styles, the paragraph has no own indent attributes and on the paragraph
+ style hierarchy from the paragraph to the paragraph style with the
+ list style no indent attributes are found.
+
+ @author OD
+
+ @return boolean
+*/
+bool SwTxtNode::AreListLevelIndentsApplicable() const
+{
+ bool bAreListLevelIndentsApplicable( true );
+
+ if ( !GetNum() || !GetNum()->GetNumRule() )
+ {
+ // no list style applied to paragraph
+ bAreListLevelIndentsApplicable = false;
+ }
+ else if ( HasSwAttrSet() &&
+ GetpSwAttrSet()->GetItemState( RES_LR_SPACE, sal_False ) == SFX_ITEM_SET )
+ {
+ // paragraph has hard-set indent attributes
+ bAreListLevelIndentsApplicable = false;
+ }
+ else if ( HasSwAttrSet() &&
+ GetpSwAttrSet()->GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET )
+ {
+ // list style is directly applied to paragraph and paragraph has no
+ // hard-set indent attributes
+ bAreListLevelIndentsApplicable = true;
+ }
+ else
+ {
+ // list style is applied through one of the paragraph styles and
+ // paragraph has no hard-set indent attributes
+
+ // check, paragraph's
+ const SwTxtFmtColl* pColl = GetTxtColl();
+ while ( pColl )
+ {
+ if ( pColl->GetAttrSet().GetItemState( RES_LR_SPACE, sal_False ) == SFX_ITEM_SET )
+ {
+ // indent attributes found in the paragraph style hierarchy.
+ bAreListLevelIndentsApplicable = false;
+ break;
+ }
+
+ if ( pColl->GetAttrSet().GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET )
+ {
+ // paragraph style with the list style found and until now no
+ // indent attributes are found in the paragraph style hierarchy.
+ bAreListLevelIndentsApplicable = true;
+ break;
+ }
+
+ pColl = dynamic_cast<const SwTxtFmtColl*>(pColl->DerivedFrom());
+ OSL_ENSURE( pColl,
+ "<SwTxtNode::AreListLevelIndentsApplicable()> - something wrong in paragraph's style hierarchy. The applied list style is not found." );
+ }
+ }
+
+ return bAreListLevelIndentsApplicable;
+}
+
+/** Retrieves the list tab stop position, if the paragraph's list level defines
+ one and this list tab stop has to merged into the tap stops of the paragraph
+
+ @author OD
+
+ @param nListTabStopPosition
+ output parameter - containing the list tab stop position
+
+ @return boolean - indicating, if a list tab stop position is provided
+*/
+bool SwTxtNode::GetListTabStopPosition( long& nListTabStopPosition ) const
+{
+ bool bListTanStopPositionProvided( false );
+
+ const SwNumRule* pNumRule = GetNum() ? GetNum()->GetNumRule() : 0;
+ if ( pNumRule && HasVisibleNumberingOrBullet() && GetActualListLevel() >= 0 )
+ {
+ const SwNumFmt& rFmt = pNumRule->Get( static_cast<sal_uInt16>(GetActualListLevel()) );
+ if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT &&
+ rFmt.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB )
+ {
+ bListTanStopPositionProvided = true;
+ nListTabStopPosition = rFmt.GetListtabPos();
+
+ if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT) )
+ {
+ // tab stop position are treated to be relative to the "before text"
+ // indent value of the paragraph. Thus, adjust <nListTabStopPos>.
+ if ( AreListLevelIndentsApplicable() )
+ {
+ nListTabStopPosition -= rFmt.GetIndentAt();
+ }
+ else if (!getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
+ {
+ SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
+ nListTabStopPosition -= aItem.GetTxtLeft();
+ }
+ }
+ }
+ }
+
+ return bListTanStopPositionProvided;
+}
+
+/** Retrieves the character following the list label, if the paragraph's
+ list level defines one.
+
+ @author OD
+
+ @return XubString - the list tab stop position
+*/
+XubString SwTxtNode::GetLabelFollowedBy() const
+{
+ XubString aLabelFollowedBy;
+
+ const SwNumRule* pNumRule = GetNum() ? GetNum()->GetNumRule() : 0;
+ if ( pNumRule && HasVisibleNumberingOrBullet() && GetActualListLevel() >= 0 )
+ {
+ const SwNumFmt& rFmt = pNumRule->Get( static_cast<sal_uInt16>(GetActualListLevel()) );
+ if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ switch ( rFmt.GetLabelFollowedBy() )
+ {
+ case SvxNumberFormat::LISTTAB:
+ {
+ const sal_Unicode aTab = '\t';
+ aLabelFollowedBy.Insert( aTab, 0 );
+ }
+ break;
+ case SvxNumberFormat::SPACE:
+ {
+ const sal_Unicode aSpace = ' ';
+ aLabelFollowedBy.Insert( aSpace, 0 );
+ }
+ break;
+ case SvxNumberFormat::NOTHING:
+ {
+ // intentionally left blank.
+ }
+ break;
+ default:
+ {
+ OSL_FAIL( "<SwTxtNode::GetLabelFollowedBy()> - unknown SvxNumberFormat::GetLabelFollowedBy() return value" );
+ }
+ }
+ }
+ }
+
+ return aLabelFollowedBy;
+}
+
+void SwTxtNode::CalcHiddenCharFlags() const
+{
+ xub_StrLen nStartPos;
+ xub_StrLen nEndPos;
+ // Update of the flags is done inside GetBoundsOfHiddenRange()
+ SwScriptInfo::GetBoundsOfHiddenRange( *this, 0, nStartPos, nEndPos );
+}
+
+// --> FME 2004-06-08 #i12836# enhanced pdf export
+bool SwTxtNode::IsHidden() const
+{
+ if ( HasHiddenParaField() || HasHiddenCharAttribute( true ) )
+ return true;
+
+ const SwSectionNode* pSectNd = FindSectionNode();
+ if ( pSectNd && pSectNd->GetSection().IsHiddenFlag() )
+ return true;
+
+ return false;
+}
+// <--
+
+namespace {
+ // Helper class for special handling of setting attributes at text node:
+ // In constructor an instance of the helper class recognize whose attributes
+ // are set and perform corresponding actions before the intrinsic set of
+ // attributes has been taken place.
+ // In the destructor - after the attributes have been set at the text
+ // node - corresponding actions are performed.
+ // The following is handled:
+ // (1) When the list style attribute - RES_PARATR_NUMRULE - is set,
+ // (A) list style attribute is empty -> the text node is removed from
+ // its list.
+ // (B) list style attribute is not empty
+ // (a) text node has no list style -> add text node to its list after
+ // the attributes have been set.
+ // (b) text node has list style -> change of list style is notified
+ // after the attributes have been set.
+ // (2) When the list id attribute - RES_PARATR_LIST_ID - is set and changed,
+ // the text node is removed from its current list before the attributes
+ // are set and added to its new list after the attributes have been set.
+ // (3) Notify list tree, if list level - RES_PARATR_LIST_LEVEL - is set
+ // and changed after the attributes have been set
+ // (4) Notify list tree, if list restart - RES_PARATR_LIST_ISRESTART - is set
+ // and changed after the attributes have been set
+ // (5) Notify list tree, if list restart value - RES_PARATR_LIST_RESTARTVALUE -
+ // is set and changed after the attributes have been set
+ // (6) Notify list tree, if count in list - RES_PARATR_LIST_ISCOUNTED - is set
+ // and changed after the attributes have been set
+ // (7) Set or Reset emtpy list style due to changed outline level - RES_PARATR_OUTLINELEVEL.
+ class HandleSetAttrAtTxtNode
+ {
+ public:
+ HandleSetAttrAtTxtNode( SwTxtNode& rTxtNode,
+ const SfxPoolItem& pItem );
+ HandleSetAttrAtTxtNode( SwTxtNode& rTxtNode,
+ const SfxItemSet& rItemSet );
+ ~HandleSetAttrAtTxtNode();
+
+ private:
+ SwTxtNode& mrTxtNode;
+ bool mbAddTxtNodeToList;
+ bool mbUpdateListLevel;
+ bool mbUpdateListRestart;
+ bool mbUpdateListCount;
+ // --> OD 2008-11-19 #i70748#
+ bool mbOutlineLevelSet;
+ // <--
+ };
+
+ HandleSetAttrAtTxtNode::HandleSetAttrAtTxtNode( SwTxtNode& rTxtNode,
+ const SfxPoolItem& pItem )
+ : mrTxtNode( rTxtNode ),
+ mbAddTxtNodeToList( false ),
+ mbUpdateListLevel( false ),
+ mbUpdateListRestart( false ),
+ mbUpdateListCount( false ),
+ // --> OD 2008-11-19 #i70748#
+ mbOutlineLevelSet( false )
+ // <--
+ {
+ switch ( pItem.Which() )
+ {
+ // handle RES_PARATR_NUMRULE
+ case RES_PARATR_NUMRULE:
+ {
+ mrTxtNode.RemoveFromList();
+
+ const SwNumRuleItem& pNumRuleItem =
+ dynamic_cast<const SwNumRuleItem&>(pItem);
+ if ( pNumRuleItem.GetValue().Len() > 0 )
+ {
+ mbAddTxtNodeToList = true;
+ // --> OD 2010-05-12 #i105562#
+ //
+ mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ // <--
+ }
+ }
+ break;
+
+ // handle RES_PARATR_LIST_ID
+ case RES_PARATR_LIST_ID:
+ {
+ const SfxStringItem& pListIdItem =
+ dynamic_cast<const SfxStringItem&>(pItem);
+ OSL_ENSURE( pListIdItem.GetValue().Len() > 0,
+ "<HandleSetAttrAtTxtNode(..)> - empty list id attribute not excepted. Serious defect -> please inform OD." );
+ const String sListIdOfTxtNode = rTxtNode.GetListId();
+ if ( pListIdItem.GetValue() != sListIdOfTxtNode )
+ {
+ mbAddTxtNodeToList = true;
+ if ( mrTxtNode.IsInList() )
+ {
+ mrTxtNode.RemoveFromList();
+ }
+ }
+ }
+ break;
+
+ // handle RES_PARATR_LIST_LEVEL
+ case RES_PARATR_LIST_LEVEL:
+ {
+ const SfxInt16Item& aListLevelItem =
+ dynamic_cast<const SfxInt16Item&>(pItem);
+ if ( aListLevelItem.GetValue() != mrTxtNode.GetAttrListLevel() )
+ {
+ mbUpdateListLevel = true;
+ }
+ }
+ break;
+
+ // handle RES_PARATR_LIST_ISRESTART
+ case RES_PARATR_LIST_ISRESTART:
+ {
+ const SfxBoolItem& aListIsRestartItem =
+ dynamic_cast<const SfxBoolItem&>(pItem);
+ if ( aListIsRestartItem.GetValue() !=
+ (mrTxtNode.IsListRestart() ? sal_True : sal_False) )
+ {
+ mbUpdateListRestart = true;
+ }
+ }
+ break;
+
+ // handle RES_PARATR_LIST_RESTARTVALUE
+ case RES_PARATR_LIST_RESTARTVALUE:
+ {
+ const SfxInt16Item& aListRestartValueItem =
+ dynamic_cast<const SfxInt16Item&>(pItem);
+ if ( !mrTxtNode.HasAttrListRestartValue() ||
+ aListRestartValueItem.GetValue() != mrTxtNode.GetAttrListRestartValue() )
+ {
+ mbUpdateListRestart = true;
+ }
+ }
+ break;
+
+ // handle RES_PARATR_LIST_ISCOUNTED
+ case RES_PARATR_LIST_ISCOUNTED:
+ {
+ const SfxBoolItem& aIsCountedInListItem =
+ dynamic_cast<const SfxBoolItem&>(pItem);
+ if ( aIsCountedInListItem.GetValue() !=
+ (mrTxtNode.IsCountedInList() ? sal_True : sal_False) )
+ {
+ mbUpdateListCount = true;
+ }
+ }
+ break;
+
+ // --> OD 2008-11-19 #i70748#
+ // handle RES_PARATR_OUTLINELEVEL
+ case RES_PARATR_OUTLINELEVEL:
+ {
+ const SfxUInt16Item& aOutlineLevelItem =
+ dynamic_cast<const SfxUInt16Item&>(pItem);
+ if ( aOutlineLevelItem.GetValue() != mrTxtNode.GetAttrOutlineLevel() )
+ {
+ mbOutlineLevelSet = true;
+ }
+ }
+ break;
+ // <--
+ }
+
+ }
+
+ HandleSetAttrAtTxtNode::HandleSetAttrAtTxtNode( SwTxtNode& rTxtNode,
+ const SfxItemSet& rItemSet )
+ : mrTxtNode( rTxtNode ),
+ mbAddTxtNodeToList( false ),
+ mbUpdateListLevel( false ),
+ mbUpdateListRestart( false ),
+ mbUpdateListCount( false ),
+ // --> OD 2008-11-19 #i70748#
+ mbOutlineLevelSet( false )
+ // <--
+ {
+ const SfxPoolItem* pItem = 0;
+ // handle RES_PARATR_NUMRULE
+ if ( rItemSet.GetItemState( RES_PARATR_NUMRULE, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ mrTxtNode.RemoveFromList();
+
+ const SwNumRuleItem* pNumRuleItem =
+ dynamic_cast<const SwNumRuleItem*>(pItem);
+ if ( pNumRuleItem->GetValue().Len() > 0 )
+ {
+ mbAddTxtNodeToList = true;
+ // --> OD 2008-11-19 #i70748#
+ mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ // <--
+ }
+ }
+
+ // handle RES_PARATR_LIST_ID
+ if ( rItemSet.GetItemState( RES_PARATR_LIST_ID, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ const SfxStringItem* pListIdItem =
+ dynamic_cast<const SfxStringItem*>(pItem);
+ const String sListIdOfTxtNode = mrTxtNode.GetListId();
+ if ( pListIdItem &&
+ pListIdItem->GetValue() != sListIdOfTxtNode )
+ {
+ mbAddTxtNodeToList = true;
+ if ( mrTxtNode.IsInList() )
+ {
+ mrTxtNode.RemoveFromList();
+ }
+ }
+ }
+
+ // handle RES_PARATR_LIST_LEVEL
+ if ( rItemSet.GetItemState( RES_PARATR_LIST_LEVEL, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ const SfxInt16Item* pListLevelItem =
+ dynamic_cast<const SfxInt16Item*>(pItem);
+ if ( pListLevelItem->GetValue() != mrTxtNode.GetAttrListLevel() )
+ {
+ mbUpdateListLevel = true;
+ }
+ }
+
+ // handle RES_PARATR_LIST_ISRESTART
+ if ( rItemSet.GetItemState( RES_PARATR_LIST_ISRESTART, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ const SfxBoolItem* pListIsRestartItem =
+ dynamic_cast<const SfxBoolItem*>(pItem);
+ if ( pListIsRestartItem->GetValue() !=
+ (mrTxtNode.IsListRestart() ? sal_True : sal_False) )
+ {
+ mbUpdateListRestart = true;
+ }
+ }
+
+ // handle RES_PARATR_LIST_RESTARTVALUE
+ if ( rItemSet.GetItemState( RES_PARATR_LIST_RESTARTVALUE, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ const SfxInt16Item* pListRestartValueItem =
+ dynamic_cast<const SfxInt16Item*>(pItem);
+ if ( !mrTxtNode.HasAttrListRestartValue() ||
+ pListRestartValueItem->GetValue() != mrTxtNode.GetAttrListRestartValue() )
+ {
+ mbUpdateListRestart = true;
+ }
+ }
+
+ // handle RES_PARATR_LIST_ISCOUNTED
+ if ( rItemSet.GetItemState( RES_PARATR_LIST_ISCOUNTED, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ const SfxBoolItem* pIsCountedInListItem =
+ dynamic_cast<const SfxBoolItem*>(pItem);
+ if ( pIsCountedInListItem->GetValue() !=
+ (mrTxtNode.IsCountedInList() ? sal_True : sal_False) )
+ {
+ mbUpdateListCount = true;
+ }
+ }
+
+ // --> OD 2008-11-19 #i70748#
+ // handle RES_PARATR_OUTLINELEVEL
+ if ( rItemSet.GetItemState( RES_PARATR_OUTLINELEVEL, sal_False, &pItem ) == SFX_ITEM_SET )
+ {
+ const SfxUInt16Item* pOutlineLevelItem =
+ dynamic_cast<const SfxUInt16Item*>(pItem);
+ if ( pOutlineLevelItem->GetValue() != mrTxtNode.GetAttrOutlineLevel() )
+ {
+ mbOutlineLevelSet = true;
+ }
+ }
+ // <--
+ }
+
+ HandleSetAttrAtTxtNode::~HandleSetAttrAtTxtNode()
+ {
+ if ( mbAddTxtNodeToList )
+ {
+ SwNumRule* pNumRuleAtTxtNode = mrTxtNode.GetNumRule();
+ if ( pNumRuleAtTxtNode )
+ {
+ mrTxtNode.AddToList();
+ }
+ }
+ else
+ {
+ if ( mbUpdateListLevel && mrTxtNode.IsInList() )
+ {
+ const_cast<SwNodeNum*>(mrTxtNode.GetNum())->SetLevelInListTree(
+ mrTxtNode.GetAttrListLevel() );
+ }
+
+ if ( mbUpdateListRestart && mrTxtNode.IsInList() )
+ {
+ SwNodeNum* pNodeNum = const_cast<SwNodeNum*>(mrTxtNode.GetNum());
+ pNodeNum->InvalidateMe();
+ pNodeNum->NotifyInvalidSiblings();
+ }
+
+ if ( mbUpdateListCount && mrTxtNode.IsInList() )
+ {
+ const_cast<SwNodeNum*>(mrTxtNode.GetNum())->InvalidateAndNotifyTree();
+ }
+ }
+
+ // --> OD 2008-11-19 #i70748#
+ if ( mbOutlineLevelSet )
+ {
+ if ( mrTxtNode.GetAttrOutlineLevel() == 0 )
+ {
+ mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ }
+ else
+ {
+ const SfxPoolItem* pItem = 0;
+ if ( mrTxtNode.GetSwAttrSet().GetItemState( RES_PARATR_NUMRULE,
+ sal_True, &pItem )
+ != SFX_ITEM_SET )
+ {
+ mrTxtNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
+ }
+ }
+ }
+ // <--
+ }
+ // End of class <HandleSetAttrAtTxtNode>
+}
+
+sal_Bool SwTxtNode::SetAttr( const SfxPoolItem& pItem )
+{
+ const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
+ mbInSetOrResetAttr = true;
+
+ HandleSetAttrAtTxtNode aHandleSetAttr( *this, pItem );
+
+ sal_Bool bRet = SwCntntNode::SetAttr( pItem );
+
+ mbInSetOrResetAttr = bOldIsSetOrResetAttr;
+
+ return bRet;
+}
+
+sal_Bool SwTxtNode::SetAttr( const SfxItemSet& rSet )
+{
+ const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
+ mbInSetOrResetAttr = true;
+
+ HandleSetAttrAtTxtNode aHandleSetAttr( *this, rSet );
+
+ sal_Bool bRet = SwCntntNode::SetAttr( rSet );
+
+ mbInSetOrResetAttr = bOldIsSetOrResetAttr;
+
+ return bRet;
+}
+
+namespace {
+ // Helper class for special handling of resetting attributes at text node:
+ // In constructor an instance of the helper class recognize whose attributes
+ // are reset and perform corresponding actions before the intrinsic reset of
+ // attributes has been taken place.
+ // In the destructor - after the attributes have been reset at the text
+ // node - corresponding actions are performed.
+ // The following is handled:
+ // (1) When the list style attribute - RES_PARATR_NUMRULE - is reset,
+ // the text is removed from its list before the attributes have been reset.
+ // (2) When the list id attribute - RES_PARATR_LIST_ID - is reset,
+ // the text is removed from its list before the attributes have been reset.
+ // (3) Notify list tree, if list level - RES_PARATR_LIST_LEVEL - is reset.
+ // (4) Notify list tree, if list restart - RES_PARATR_LIST_ISRESTART - is reset.
+ // (5) Notify list tree, if list restart value - RES_PARATR_LIST_RESTARTVALUE - is reset.
+ // (6) Notify list tree, if count in list - RES_PARATR_LIST_ISCOUNTED - is reset.
+ // (7) Reset empty list style, if outline level attribute - RES_PARATR_OUTLINELEVEL - is reset.
+ class HandleResetAttrAtTxtNode
+ {
+ public:
+ HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode,
+ const sal_uInt16 nWhich1,
+ const sal_uInt16 nWhich2 );
+ HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode,
+ const SvUShorts& rWhichArr );
+ HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode );
+
+ ~HandleResetAttrAtTxtNode();
+
+ private:
+ SwTxtNode& mrTxtNode;
+ bool mbListStyleOrIdReset;
+ bool mbUpdateListLevel;
+ bool mbUpdateListRestart;
+ bool mbUpdateListCount;
+ };
+
+ HandleResetAttrAtTxtNode::HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode,
+ const sal_uInt16 nWhich1,
+ const sal_uInt16 nWhich2 )
+ : mrTxtNode( rTxtNode ),
+ mbListStyleOrIdReset( false ),
+ mbUpdateListLevel( false ),
+ mbUpdateListRestart( false ),
+ mbUpdateListCount( false )
+ {
+ bool bRemoveFromList( false );
+ if ( nWhich2 != 0 && nWhich2 > nWhich1 )
+ {
+ // RES_PARATR_NUMRULE and RES_PARATR_LIST_ID
+ if ( nWhich1 <= RES_PARATR_NUMRULE && RES_PARATR_NUMRULE <= nWhich2 )
+ {
+ bRemoveFromList = mrTxtNode.GetNumRule() != 0;
+ mbListStyleOrIdReset = true;
+ }
+ else if ( nWhich1 <= RES_PARATR_LIST_ID && RES_PARATR_LIST_ID <= nWhich2 )
+ {
+ bRemoveFromList = mrTxtNode.GetpSwAttrSet() &&
+ mrTxtNode.GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_ID, sal_False ) == SFX_ITEM_SET;
+ // --> OD 2008-10-20 #i92898#
+ mbListStyleOrIdReset = true;
+ // <--
+ }
+
+ if ( !bRemoveFromList )
+ {
+ // RES_PARATR_LIST_LEVEL
+ mbUpdateListLevel = ( nWhich1 <= RES_PARATR_LIST_LEVEL &&
+ RES_PARATR_LIST_LEVEL <= nWhich2 &&
+ mrTxtNode.HasAttrListLevel() );
+
+ // RES_PARATR_LIST_ISRESTART and RES_PARATR_LIST_RESTARTVALUE
+ mbUpdateListRestart =
+ ( nWhich1 <= RES_PARATR_LIST_ISRESTART && RES_PARATR_LIST_ISRESTART <= nWhich2 &&
+ mrTxtNode.IsListRestart() ) ||
+ ( nWhich1 <= RES_PARATR_LIST_RESTARTVALUE && RES_PARATR_LIST_RESTARTVALUE <= nWhich2 &&
+ mrTxtNode.HasAttrListRestartValue() );
+
+ // RES_PARATR_LIST_ISCOUNTED
+ mbUpdateListCount =
+ ( nWhich1 <= RES_PARATR_LIST_ISCOUNTED && RES_PARATR_LIST_ISCOUNTED <= nWhich2 &&
+ !mrTxtNode.IsCountedInList() );
+ }
+
+ // --> OD 2008-11-19 #i70748#
+ // RES_PARATR_OUTLINELEVEL
+ if ( nWhich1 <= RES_PARATR_OUTLINELEVEL && RES_PARATR_OUTLINELEVEL <= nWhich2 )
+ {
+ mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ }
+ // <--
+ }
+ else
+ {
+ // RES_PARATR_NUMRULE and RES_PARATR_LIST_ID
+ if ( nWhich1 == RES_PARATR_NUMRULE )
+ {
+ bRemoveFromList = mrTxtNode.GetNumRule() != 0;
+ mbListStyleOrIdReset = true;
+ }
+ else if ( nWhich1 == RES_PARATR_LIST_ID )
+ {
+ bRemoveFromList = mrTxtNode.GetpSwAttrSet() &&
+ mrTxtNode.GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_ID, sal_False ) == SFX_ITEM_SET;
+ // --> OD 2008-10-20 #i92898#
+ mbListStyleOrIdReset = true;
+ // <--
+ }
+ // --> OD 2008-11-19 #i70748#
+ // RES_PARATR_OUTLINELEVEL
+ else if ( nWhich1 == RES_PARATR_OUTLINELEVEL )
+ {
+ mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ }
+ // <--
+
+ if ( !bRemoveFromList )
+ {
+ // RES_PARATR_LIST_LEVEL
+ mbUpdateListLevel = nWhich1 == RES_PARATR_LIST_LEVEL &&
+ mrTxtNode.HasAttrListLevel();
+
+ // RES_PARATR_LIST_ISRESTART and RES_PARATR_LIST_RESTARTVALUE
+ mbUpdateListRestart = ( nWhich1 == RES_PARATR_LIST_ISRESTART &&
+ mrTxtNode.IsListRestart() ) ||
+ ( nWhich1 == RES_PARATR_LIST_RESTARTVALUE &&
+ mrTxtNode.HasAttrListRestartValue() );
+
+ // RES_PARATR_LIST_ISCOUNTED
+ mbUpdateListCount = nWhich1 == RES_PARATR_LIST_ISCOUNTED &&
+ !mrTxtNode.IsCountedInList();
+ }
+ }
+
+ if ( bRemoveFromList && mrTxtNode.IsInList() )
+ {
+ mrTxtNode.RemoveFromList();
+ }
+ }
+
+ HandleResetAttrAtTxtNode::HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode,
+ const SvUShorts& rWhichArr )
+ : mrTxtNode( rTxtNode ),
+ mbListStyleOrIdReset( false ),
+ mbUpdateListLevel( false ),
+ mbUpdateListRestart( false ),
+ mbUpdateListCount( false )
+ {
+ bool bRemoveFromList( false );
+ {
+ const sal_uInt16 nEnd = rWhichArr.Count();
+ for ( sal_uInt16 n = 0; n < nEnd; ++n )
+ {
+ // RES_PARATR_NUMRULE and RES_PARATR_LIST_ID
+ if ( rWhichArr[ n ] == RES_PARATR_NUMRULE )
+ {
+ bRemoveFromList = bRemoveFromList ||
+ mrTxtNode.GetNumRule() != 0;
+ mbListStyleOrIdReset = true;
+ }
+ else if ( rWhichArr[ n ] == RES_PARATR_LIST_ID )
+ {
+ bRemoveFromList = bRemoveFromList ||
+ ( mrTxtNode.GetpSwAttrSet() &&
+ mrTxtNode.GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_ID, sal_False ) == SFX_ITEM_SET );
+ // --> OD 2008-10-20 #i92898#
+ mbListStyleOrIdReset = true;
+ // <--
+ }
+ // --> OD 2008-11-19 #i70748#
+ // RES_PARATR_OUTLINELEVEL
+ else if ( rWhichArr[ n ] == RES_PARATR_OUTLINELEVEL )
+ {
+ mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ }
+ // <--
+
+ if ( !bRemoveFromList )
+ {
+ // RES_PARATR_LIST_LEVEL
+ mbUpdateListLevel = mbUpdateListLevel ||
+ ( rWhichArr[ n ] == RES_PARATR_LIST_LEVEL &&
+ mrTxtNode.HasAttrListLevel() );
+
+ // RES_PARATR_LIST_ISRESTART and RES_PARATR_LIST_RESTARTVALUE
+ mbUpdateListRestart = mbUpdateListRestart ||
+ ( rWhichArr[ n ] == RES_PARATR_LIST_ISRESTART &&
+ mrTxtNode.IsListRestart() ) ||
+ ( rWhichArr[ n ] == RES_PARATR_LIST_RESTARTVALUE &&
+ mrTxtNode.HasAttrListRestartValue() );
+
+ // RES_PARATR_LIST_ISCOUNTED
+ mbUpdateListCount = mbUpdateListCount ||
+ ( rWhichArr[ n ] == RES_PARATR_LIST_ISCOUNTED &&
+ !mrTxtNode.IsCountedInList() );
+ }
+ }
+ }
+
+ if ( bRemoveFromList && mrTxtNode.IsInList() )
+ {
+ mrTxtNode.RemoveFromList();
+ }
+ }
+
+ HandleResetAttrAtTxtNode::HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode )
+ : mrTxtNode( rTxtNode ),
+ mbListStyleOrIdReset( false ),
+ mbUpdateListLevel( false ),
+ mbUpdateListRestart( false ),
+ mbUpdateListCount( false )
+ {
+ mbListStyleOrIdReset = true;
+ if ( rTxtNode.IsInList() )
+ {
+ rTxtNode.RemoveFromList();
+ }
+ // --> OD 2008-11-19 #i70748#
+ mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
+ // <--
+ }
+
+ HandleResetAttrAtTxtNode::~HandleResetAttrAtTxtNode()
+ {
+ if ( mbListStyleOrIdReset && !mrTxtNode.IsInList() )
+ {
+ // check, if in spite of the reset of the list style or the list id
+ // the paragraph still has to be added to a list.
+ if ( mrTxtNode.GetNumRule() &&
+ mrTxtNode.GetListId().Len() > 0 )
+ {
+ // --> OD 2009-01-14 #i96062#
+ // If paragraph has no list level attribute set and list style
+ // is the outline style, apply outline level as the list level.
+ if ( !mrTxtNode.HasAttrListLevel() &&
+ mrTxtNode.GetNumRule()->GetName() ==
+ String::CreateFromAscii( SwNumRule::GetOutlineRuleName() ) &&
+ mrTxtNode.GetTxtColl()->IsAssignedToListLevelOfOutlineStyle() )
+ {
+ int nNewListLevel = mrTxtNode.GetTxtColl()->GetAssignedOutlineStyleLevel();
+ if ( 0 <= nNewListLevel && nNewListLevel < MAXLEVEL )
+ {
+ mrTxtNode.SetAttrListLevel( nNewListLevel );
+ }
+ }
+ // <--
+ mrTxtNode.AddToList();
+ }
+ // --> OD 2008-11-19 #i70748#
+ // --> OD 2010-05-12 #i105562#
+ else if ( mrTxtNode.GetpSwAttrSet() &&
+ dynamic_cast<const SfxUInt16Item &>(mrTxtNode.GetAttr( RES_PARATR_OUTLINELEVEL, sal_False )).GetValue() > 0 )
+ {
+ mrTxtNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
+ }
+ // <--
+ }
+
+ if ( mrTxtNode.IsInList() )
+ {
+ if ( mbUpdateListLevel )
+ {
+ SwNodeNum* pNodeNum = const_cast<SwNodeNum*>(mrTxtNode.GetNum());
+ pNodeNum->SetLevelInListTree( mrTxtNode.GetAttrListLevel() );
+ }
+
+ if ( mbUpdateListRestart )
+ {
+ SwNodeNum* pNodeNum = const_cast<SwNodeNum*>(mrTxtNode.GetNum());
+ pNodeNum->InvalidateMe();
+ pNodeNum->NotifyInvalidSiblings();
+ }
+
+ if ( mbUpdateListCount )
+ {
+ SwNodeNum* pNodeNum = const_cast<SwNodeNum*>(mrTxtNode.GetNum());
+ pNodeNum->InvalidateAndNotifyTree();
+ }
+ }
+ }
+ // End of class <HandleResetAttrAtTxtNode>
+}
+
+sal_Bool SwTxtNode::ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 )
+{
+ const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
+ mbInSetOrResetAttr = true;
+
+ HandleResetAttrAtTxtNode aHandleResetAttr( *this, nWhich1, nWhich2 );
+
+ sal_Bool bRet = SwCntntNode::ResetAttr( nWhich1, nWhich2 );
+
+ mbInSetOrResetAttr = bOldIsSetOrResetAttr;
+
+ return bRet;
+}
+
+sal_Bool SwTxtNode::ResetAttr( const SvUShorts& rWhichArr )
+{
+ const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
+ mbInSetOrResetAttr = true;
+
+ HandleResetAttrAtTxtNode aHandleResetAttr( *this, rWhichArr );
+
+ sal_Bool bRet = SwCntntNode::ResetAttr( rWhichArr );
+
+ mbInSetOrResetAttr = bOldIsSetOrResetAttr;
+
+ return bRet;
+}
+
+sal_uInt16 SwTxtNode::ResetAllAttr()
+{
+ const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
+ mbInSetOrResetAttr = true;
+
+ HandleResetAttrAtTxtNode aHandleResetAttr( *this );
+
+ sal_uInt16 nRet = SwCntntNode::ResetAllAttr();
+
+ mbInSetOrResetAttr = bOldIsSetOrResetAttr;
+
+ return nRet;
+}
+// <--
+
+// sw::Metadatable
+::sfx2::IXmlIdRegistry& SwTxtNode::GetRegistry()
+{
+ return GetDoc()->GetXmlIdRegistry();
+}
+
+bool SwTxtNode::IsInClipboard() const
+{
+ return GetDoc()->IsClipBoard();
+}
+
+bool SwTxtNode::IsInUndo() const
+{
+ return GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
+}
+
+bool SwTxtNode::IsInContent() const
+{
+ return !GetDoc()->IsInHeaderFooter( SwNodeIndex(*this) );
+}
+
+void SwTxtNode::SwClientNotify( const SwModify& rModify, const SfxHint& rHint )
+{
+ const SwAttrHint* pHint = dynamic_cast<const SwAttrHint*>(&rHint);
+ if ( pHint && pHint->GetId() == RES_CONDTXTFMTCOLL && &rModify == GetRegisteredIn() )
+ ChkCondColl();
+}
+
+#include <unoparagraph.hxx>
+
+uno::Reference< rdf::XMetadatable >
+SwTxtNode::MakeUnoObject()
+{
+ const uno::Reference<rdf::XMetadatable> xMeta(
+ SwXParagraph::CreateXParagraph(*GetDoc(), *this), uno::UNO_QUERY);
+ return xMeta;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/swfntcch.cxx b/sw/source/core/txtnode/swfntcch.cxx
new file mode 100644
index 000000000000..8a421ba1ff79
--- /dev/null
+++ b/sw/source/core/txtnode/swfntcch.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <viewsh.hxx>
+#include "swfntcch.hxx"
+#include "fmtcol.hxx"
+#include "swfont.hxx"
+
+// aus atrstck.cxx
+extern const sal_uInt8 StackPos[];
+
+// globale Variablen, werden in SwFntCch.Hxx bekanntgegeben
+// Der FontCache wird in TxtInit.Cxx _TXTINIT erzeugt und in _TXTEXIT geloescht
+SwFontCache *pSwFontCache = NULL;
+
+/*************************************************************************
+|*
+|* SwFontObj::SwFontObj(), ~SwFontObj()
+|*
+|*************************************************************************/
+
+SwFontObj::SwFontObj( const void *pOwn, ViewShell *pSh ) :
+ SwCacheObj( (void*)pOwn ),
+ aSwFont( &((SwTxtFmtColl *)pOwn)->GetAttrSet(), pSh ? pSh->getIDocumentSettingAccess() : 0 )
+{
+ aSwFont.GoMagic( pSh, aSwFont.GetActual() );
+ const SwAttrSet& rAttrSet = ((SwTxtFmtColl *)pOwn)->GetAttrSet();
+ for (sal_uInt16 i = RES_CHRATR_BEGIN; i < RES_CHRATR_END; i++)
+ pDefaultArray[ StackPos[ i ] ] = &rAttrSet.Get( i, sal_True );
+}
+
+SwFontObj::~SwFontObj()
+{
+}
+
+/*************************************************************************
+|*
+|* SwFontAccess::SwFontAccess()
+|*
+|*************************************************************************/
+
+SwFontAccess::SwFontAccess( const void *pOwn, ViewShell *pSh ) :
+ SwCacheAccess( *pSwFontCache, pOwn,
+ ((SwTxtFmtColl*)pOwn)->IsInSwFntCache() ),
+ pShell( pSh )
+{
+}
+
+SwFontObj *SwFontAccess::Get( )
+{
+ return (SwFontObj *) SwCacheAccess::Get( );
+}
+
+SwCacheObj *SwFontAccess::NewObj( )
+{
+ ((SwTxtFmtColl*)pOwner)->SetInSwFntCache( sal_True );
+ return new SwFontObj( pOwner, pShell );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/swfont.cxx b/sw/source/core/txtnode/swfont.cxx
new file mode 100644
index 000000000000..cfa8036ecdce
--- /dev/null
+++ b/sw/source/core/txtnode/swfont.cxx
@@ -0,0 +1,1243 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <hintids.hxx>
+
+#include <com/sun/star/i18n/ScriptType.hdl>
+#include <vcl/outdev.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <editeng/unolingu.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/blnkitem.hxx>
+#include <editeng/nhypitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/akrnitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/cntritem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/cscoitem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/emphitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <editeng/twolinesitem.hxx>
+#include <editeng/charhiddenitem.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <vcl/window.hxx>
+#include <charatr.hxx>
+#include <viewsh.hxx> // Bildschirmabgleich
+#include <swfont.hxx>
+#include <fntcache.hxx> // FontCache
+#include <txtfrm.hxx> // SwTxtFrm
+#include <scriptinfo.hxx>
+
+#if defined(WNT) || defined(PM2)
+#define FNT_LEADING_HACK
+#endif
+
+#if defined(WNT)
+#define FNT_ATM_HACK
+#endif
+
+#if OSL_DEBUG_LEVEL > 1
+// globale Variable
+SvStatistics aSvStat;
+#endif
+
+using namespace ::com::sun::star;
+
+/************************************************************************
+ * Hintergrundbrush setzen, z.B. bei Zeichenvorlagen
+ ***********************************************************************/
+
+void SwFont::SetBackColor( Color* pNewColor )
+{
+ delete pBackColor;
+ pBackColor = pNewColor;
+ bFntChg = sal_True;
+ aSub[SW_LATIN].pMagic = aSub[SW_CJK].pMagic = aSub[SW_CTL].pMagic = 0;
+}
+
+// maps directions for vertical layout
+sal_uInt16 MapDirection( sal_uInt16 nDir, const sal_Bool bVertFormat )
+{
+ if ( bVertFormat )
+ {
+ switch ( nDir )
+ {
+ case 0 :
+ nDir = 2700;
+ break;
+ case 900 :
+ nDir = 0;
+ break;
+ case 2700 :
+ nDir = 1800;
+ break;
+#if OSL_DEBUG_LEVEL > 1
+ default :
+ OSL_FAIL( "Unsupported direction" );
+ break;
+#endif
+ }
+ }
+ return nDir;
+}
+
+// maps the absolute direction set at the font to its logical conterpart
+// in the rotated environment
+sal_uInt16 UnMapDirection( sal_uInt16 nDir, const sal_Bool bVertFormat )
+{
+ if ( bVertFormat )
+ {
+ switch ( nDir )
+ {
+ case 0 :
+ nDir = 900;
+ break;
+ case 1800 :
+ nDir = 2700;
+ break;
+ case 2700 :
+ nDir = 0;
+ break;
+#if OSL_DEBUG_LEVEL > 1
+ default :
+ OSL_FAIL( "Unsupported direction" );
+ break;
+#endif
+ }
+ }
+ return nDir;
+}
+
+sal_uInt16 SwFont::GetOrientation( const sal_Bool bVertFormat ) const
+{
+ return UnMapDirection( aSub[nActual].GetOrientation(), bVertFormat );
+}
+
+void SwFont::SetVertical( sal_uInt16 nDir, const sal_Bool bVertFormat )
+{
+ // map direction if frame has vertical layout
+ nDir = MapDirection( nDir, bVertFormat );
+
+ if( nDir != aSub[0].GetOrientation() )
+ {
+ bFntChg = sal_True;
+ aSub[0].SetVertical( nDir, bVertFormat );
+ aSub[1].SetVertical( nDir, bVertFormat || nDir > 1000 );
+ aSub[2].SetVertical( nDir, bVertFormat );
+ }
+}
+
+/*************************************************************************
+ Escapement:
+ frEsc: Fraction, Grad des Escapements
+ Esc = resultierendes Escapement
+ A1 = Original-Ascent (nOrgAscent)
+ A2 = verkleinerter Ascent (nEscAscent)
+ Ax = resultierender Ascent (GetAscent())
+ H1 = Original-Hoehe (nOrgHeight)
+ H2 = verkleinerter Hoehe (nEscHeight)
+ Hx = resultierender Hoehe (GetHeight())
+ Bx = resultierende Baseline fuer die Textausgabe (CalcPos())
+ (Vorsicht: Y - A1!)
+
+ Escapement:
+ Esc = H1 * frEsc;
+
+ Hochstellung:
+ Ax = A2 + Esc;
+ Hx = H2 + Esc;
+ Bx = A1 - Esc;
+
+ Tiefstellung:
+ Ax = A1;
+ Hx = A1 + Esc + (H2 - A2);
+ Bx = A1 + Esc;
+
+*************************************************************************/
+
+/*************************************************************************
+ * SwSubFont::CalcEscAscent( const sal_uInt16 nOldAscent )
+ *************************************************************************/
+
+// nEsc ist der Prozentwert
+sal_uInt16 SwSubFont::CalcEscAscent( const sal_uInt16 nOldAscent ) const
+{
+ if( DFLT_ESC_AUTO_SUPER != GetEscapement() &&
+ DFLT_ESC_AUTO_SUB != GetEscapement() )
+ {
+ const long nAscent = nOldAscent +
+ ( (long) nOrgHeight * GetEscapement() ) / 100L;
+ if ( nAscent>0 )
+ return ( Max( sal_uInt16 (nAscent), nOrgAscent ));
+ }
+ return nOrgAscent;
+}
+
+/*************************************************************************
+ * SwFont::SetDiffFnt()
+ *************************************************************************/
+
+void SwFont::SetDiffFnt( const SfxItemSet *pAttrSet,
+ const IDocumentSettingAccess *pIDocumentSettingAccess )
+{
+ delete pBackColor;
+ pBackColor = NULL;
+
+ if( pAttrSet )
+ {
+ const SfxPoolItem* pItem;
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_FONT,
+ sal_True, &pItem ))
+ {
+ const SvxFontItem *pFont = (const SvxFontItem *)pItem;
+ aSub[SW_LATIN].SetFamily( pFont->GetFamily() );
+ aSub[SW_LATIN].Font::SetName( pFont->GetFamilyName() );
+ aSub[SW_LATIN].Font::SetStyleName( pFont->GetStyleName() );
+ aSub[SW_LATIN].Font::SetPitch( pFont->GetPitch() );
+ aSub[SW_LATIN].Font::SetCharSet( pFont->GetCharSet() );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_FONTSIZE,
+ sal_True, &pItem ))
+ {
+ const SvxFontHeightItem *pHeight = (const SvxFontHeightItem *)pItem;
+ aSub[SW_LATIN].SvxFont::SetPropr( 100 );
+ aSub[SW_LATIN].aSize = aSub[SW_LATIN].Font::GetSize();
+ Size aTmpSize = aSub[SW_LATIN].aSize;
+ aTmpSize.Height() = pHeight->GetHeight();
+ aSub[SW_LATIN].SetSize( aTmpSize );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_POSTURE,
+ sal_True, &pItem ))
+ aSub[SW_LATIN].Font::SetItalic( ((SvxPostureItem*)pItem)->GetPosture() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_WEIGHT,
+ sal_True, &pItem ))
+ aSub[SW_LATIN].Font::SetWeight( ((SvxWeightItem*)pItem)->GetWeight() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_LANGUAGE,
+ sal_True, &pItem ))
+ aSub[SW_LATIN].SetLanguage( ((SvxLanguageItem*)pItem)->GetLanguage() );
+
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CJK_FONT,
+ sal_True, &pItem ))
+ {
+ const SvxFontItem *pFont = (const SvxFontItem *)pItem;
+ aSub[SW_CJK].SetFamily( pFont->GetFamily() );
+ aSub[SW_CJK].Font::SetName( pFont->GetFamilyName() );
+ aSub[SW_CJK].Font::SetStyleName( pFont->GetStyleName() );
+ aSub[SW_CJK].Font::SetPitch( pFont->GetPitch() );
+ aSub[SW_CJK].Font::SetCharSet( pFont->GetCharSet() );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CJK_FONTSIZE,
+ sal_True, &pItem ))
+ {
+ const SvxFontHeightItem *pHeight = (const SvxFontHeightItem *)pItem;
+ aSub[SW_CJK].SvxFont::SetPropr( 100 );
+ aSub[SW_CJK].aSize = aSub[SW_CJK].Font::GetSize();
+ Size aTmpSize = aSub[SW_CJK].aSize;
+ aTmpSize.Height() = pHeight->GetHeight();
+ aSub[SW_CJK].SetSize( aTmpSize );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CJK_POSTURE,
+ sal_True, &pItem ))
+ aSub[SW_CJK].Font::SetItalic( ((SvxPostureItem*)pItem)->GetPosture() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CJK_WEIGHT,
+ sal_True, &pItem ))
+ aSub[SW_CJK].Font::SetWeight( ((SvxWeightItem*)pItem)->GetWeight() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CJK_LANGUAGE,
+ sal_True, &pItem ))
+ {
+ LanguageType eNewLang = ((SvxLanguageItem*)pItem)->GetLanguage();
+ aSub[SW_CJK].SetLanguage( eNewLang );
+ aSub[SW_LATIN].SetCJKContextLanguage( eNewLang );
+ aSub[SW_CJK].SetCJKContextLanguage( eNewLang );
+ aSub[SW_CTL].SetCJKContextLanguage( eNewLang );
+ }
+
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CTL_FONT,
+ sal_True, &pItem ))
+ {
+ const SvxFontItem *pFont = (const SvxFontItem *)pItem;
+ aSub[SW_CTL].SetFamily( pFont->GetFamily() );
+ aSub[SW_CTL].Font::SetName( pFont->GetFamilyName() );
+ aSub[SW_CTL].Font::SetStyleName( pFont->GetStyleName() );
+ aSub[SW_CTL].Font::SetPitch( pFont->GetPitch() );
+ aSub[SW_CTL].Font::SetCharSet( pFont->GetCharSet() );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CTL_FONTSIZE,
+ sal_True, &pItem ))
+ {
+ const SvxFontHeightItem *pHeight = (const SvxFontHeightItem *)pItem;
+ aSub[SW_CTL].SvxFont::SetPropr( 100 );
+ aSub[SW_CTL].aSize = aSub[SW_CTL].Font::GetSize();
+ Size aTmpSize = aSub[SW_CTL].aSize;
+ aTmpSize.Height() = pHeight->GetHeight();
+ aSub[SW_CTL].SetSize( aTmpSize );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CTL_POSTURE,
+ sal_True, &pItem ))
+ aSub[SW_CTL].Font::SetItalic( ((SvxPostureItem*)pItem)->GetPosture() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CTL_WEIGHT,
+ sal_True, &pItem ))
+ aSub[SW_CTL].Font::SetWeight( ((SvxWeightItem*)pItem)->GetWeight() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CTL_LANGUAGE,
+ sal_True, &pItem ))
+ aSub[SW_CTL].SetLanguage( ((SvxLanguageItem*)pItem)->GetLanguage() );
+
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_UNDERLINE,
+ sal_True, &pItem ))
+ {
+ SetUnderline( ((SvxUnderlineItem*)pItem)->GetLineStyle() );
+ SetUnderColor( ((SvxUnderlineItem*)pItem)->GetColor() );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_OVERLINE,
+ sal_True, &pItem ))
+ {
+ SetOverline( ((SvxOverlineItem*)pItem)->GetLineStyle() );
+ SetOverColor( ((SvxOverlineItem*)pItem)->GetColor() );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CROSSEDOUT,
+ sal_True, &pItem ))
+ SetStrikeout( ((SvxCrossedOutItem*)pItem)->GetStrikeout() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_COLOR,
+ sal_True, &pItem ))
+ SetColor( ((SvxColorItem*)pItem)->GetValue() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_EMPHASIS_MARK,
+ sal_True, &pItem ))
+ SetEmphasisMark( ((SvxEmphasisMarkItem*)pItem)->GetEmphasisMark() );
+
+ SetTransparent( sal_True );
+ SetAlign( ALIGN_BASELINE );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CONTOUR,
+ sal_True, &pItem ))
+ SetOutline( ((SvxContourItem*)pItem)->GetValue() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_SHADOWED,
+ sal_True, &pItem ))
+ SetShadow( ((SvxShadowedItem*)pItem)->GetValue() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_RELIEF,
+ sal_True, &pItem ))
+ SetRelief( (FontRelief)((SvxCharReliefItem*)pItem)->GetValue() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_SHADOWED,
+ sal_True, &pItem ))
+ SetPropWidth(((SvxShadowedItem*)pItem)->GetValue() ? 50 : 100 );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_AUTOKERN,
+ sal_True, &pItem ))
+ {
+ if( ((SvxAutoKernItem*)pItem)->GetValue() )
+ {
+ SetAutoKern( ( !pIDocumentSettingAccess ||
+ !pIDocumentSettingAccess->get(IDocumentSettingAccess::KERN_ASIAN_PUNCTUATION) ) ?
+ KERNING_FONTSPECIFIC :
+ KERNING_ASIAN );
+ }
+ else
+ SetAutoKern( 0 );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_WORDLINEMODE,
+ sal_True, &pItem ))
+ SetWordLineMode( ((SvxWordLineModeItem*)pItem)->GetValue() );
+
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_ESCAPEMENT,
+ sal_True, &pItem ))
+ {
+ const SvxEscapementItem *pEsc = (const SvxEscapementItem *)pItem;
+ SetEscapement( pEsc->GetEsc() );
+ if( aSub[SW_LATIN].IsEsc() )
+ SetProportion( pEsc->GetProp() );
+ }
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_CASEMAP,
+ sal_True, &pItem ))
+ SetCaseMap( ((SvxCaseMapItem*)pItem)->GetCaseMap() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_KERNING,
+ sal_True, &pItem ))
+ SetFixKerning( ((SvxKerningItem*)pItem)->GetValue() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_NOHYPHEN,
+ sal_True, &pItem ))
+ SetNoHyph( ((SvxNoHyphenItem*)pItem)->GetValue() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_BLINK,
+ sal_True, &pItem ))
+ SetBlink( ((SvxBlinkItem*)pItem)->GetValue() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_ROTATE,
+ sal_True, &pItem ))
+ SetVertical( ((SvxCharRotateItem*)pItem)->GetValue() );
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_BACKGROUND,
+ sal_True, &pItem ))
+ pBackColor = new Color( ((SvxBrushItem*)pItem)->GetColor() );
+ else
+ pBackColor = NULL;
+ const SfxPoolItem* pTwoLinesItem = 0;
+ if( SFX_ITEM_SET ==
+ pAttrSet->GetItemState( RES_CHRATR_TWO_LINES, sal_True, &pTwoLinesItem ))
+ if ( ((SvxTwoLinesItem*)pTwoLinesItem)->GetValue() )
+ SetVertical( 0 );
+ }
+ else
+ {
+ Invalidate();
+ bNoHyph = sal_False;
+ bBlink = sal_False;
+ }
+ bPaintBlank = sal_False;
+ bPaintWrong = sal_False;
+ OSL_ENSURE( aSub[SW_LATIN].IsTransparent(), "SwFont: Transparent revolution" );
+}
+
+/*************************************************************************
+ * class SwFont
+ *************************************************************************/
+
+SwFont::SwFont( const SwFont &rFont )
+{
+ aSub[SW_LATIN] = rFont.aSub[SW_LATIN];
+ aSub[SW_CJK] = rFont.aSub[SW_CJK];
+ aSub[SW_CTL] = rFont.aSub[SW_CTL];
+ nActual = rFont.nActual;
+ pBackColor = rFont.pBackColor ? new Color( *rFont.pBackColor ) : NULL;
+ aUnderColor = rFont.GetUnderColor();
+ aOverColor = rFont.GetOverColor();
+ nToxCnt = 0;
+ nRefCnt = 0;
+ m_nMetaCount = 0;
+ bFntChg = rFont.bFntChg;
+ bOrgChg = rFont.bOrgChg;
+ bPaintBlank = rFont.bPaintBlank;
+ bPaintWrong = sal_False;
+ bURL = rFont.bURL;
+ bGreyWave = rFont.bGreyWave;
+ bNoColReplace = rFont.bNoColReplace;
+ bNoHyph = rFont.bNoHyph;
+ bBlink = rFont.bBlink;
+}
+
+SwFont::SwFont( const SwAttrSet* pAttrSet,
+ const IDocumentSettingAccess* pIDocumentSettingAccess )
+{
+ nActual = SW_LATIN;
+ nToxCnt = 0;
+ nRefCnt = 0;
+ m_nMetaCount = 0;
+ bPaintBlank = sal_False;
+ bPaintWrong = sal_False;
+ bURL = sal_False;
+ bGreyWave = sal_False;
+ bNoColReplace = sal_False;
+ bNoHyph = pAttrSet->GetNoHyphenHere().GetValue();
+ bBlink = pAttrSet->GetBlink().GetValue();
+ bOrgChg = sal_True;
+ {
+ const SvxFontItem& rFont = pAttrSet->GetFont();
+ aSub[SW_LATIN].SetFamily( rFont.GetFamily() );
+ aSub[SW_LATIN].SetName( rFont.GetFamilyName() );
+ aSub[SW_LATIN].SetStyleName( rFont.GetStyleName() );
+ aSub[SW_LATIN].SetPitch( rFont.GetPitch() );
+ aSub[SW_LATIN].SetCharSet( rFont.GetCharSet() );
+ aSub[SW_LATIN].SvxFont::SetPropr( 100 ); // 100% der FontSize
+ Size aTmpSize = aSub[SW_LATIN].aSize;
+ aTmpSize.Height() = pAttrSet->GetSize().GetHeight();
+ aSub[SW_LATIN].SetSize( aTmpSize );
+ aSub[SW_LATIN].SetItalic( pAttrSet->GetPosture().GetPosture() );
+ aSub[SW_LATIN].SetWeight( pAttrSet->GetWeight().GetWeight() );
+ aSub[SW_LATIN].SetLanguage( pAttrSet->GetLanguage().GetLanguage() );
+ }
+
+ {
+ const SvxFontItem& rFont = pAttrSet->GetCJKFont();
+ aSub[SW_CJK].SetFamily( rFont.GetFamily() );
+ aSub[SW_CJK].SetName( rFont.GetFamilyName() );
+ aSub[SW_CJK].SetStyleName( rFont.GetStyleName() );
+ aSub[SW_CJK].SetPitch( rFont.GetPitch() );
+ aSub[SW_CJK].SetCharSet( rFont.GetCharSet() );
+ aSub[SW_CJK].SvxFont::SetPropr( 100 ); // 100% der FontSize
+ Size aTmpSize = aSub[SW_CJK].aSize;
+ aTmpSize.Height() = pAttrSet->GetCJKSize().GetHeight();
+ aSub[SW_CJK].SetSize( aTmpSize );
+ aSub[SW_CJK].SetItalic( pAttrSet->GetCJKPosture().GetPosture() );
+ aSub[SW_CJK].SetWeight( pAttrSet->GetCJKWeight().GetWeight() );
+ LanguageType eNewLang = pAttrSet->GetCJKLanguage().GetLanguage();
+ aSub[SW_CJK].SetLanguage( eNewLang );
+ aSub[SW_LATIN].SetCJKContextLanguage( eNewLang );
+ aSub[SW_CJK].SetCJKContextLanguage( eNewLang );
+ aSub[SW_CTL].SetCJKContextLanguage( eNewLang );
+ }
+
+ {
+ const SvxFontItem& rFont = pAttrSet->GetCTLFont();
+ aSub[SW_CTL].SetFamily( rFont.GetFamily() );
+ aSub[SW_CTL].SetName( rFont.GetFamilyName() );
+ aSub[SW_CTL].SetStyleName( rFont.GetStyleName() );
+ aSub[SW_CTL].SetPitch( rFont.GetPitch() );
+ aSub[SW_CTL].SetCharSet( rFont.GetCharSet() );
+ aSub[SW_CTL].SvxFont::SetPropr( 100 ); // 100% der FontSize
+ Size aTmpSize = aSub[SW_CTL].aSize;
+ aTmpSize.Height() = pAttrSet->GetCTLSize().GetHeight();
+ aSub[SW_CTL].SetSize( aTmpSize );
+ aSub[SW_CTL].SetItalic( pAttrSet->GetCTLPosture().GetPosture() );
+ aSub[SW_CTL].SetWeight( pAttrSet->GetCTLWeight().GetWeight() );
+ aSub[SW_CTL].SetLanguage( pAttrSet->GetCTLLanguage().GetLanguage() );
+ }
+
+ const FontUnderline eUnderline = pAttrSet->GetUnderline().GetLineStyle();
+ if ( pAttrSet->GetCharHidden().GetValue() )
+ SetUnderline( UNDERLINE_DOTTED );
+ else
+ SetUnderline( eUnderline );
+ SetUnderColor( pAttrSet->GetUnderline().GetColor() );
+ SetOverline( pAttrSet->GetOverline().GetLineStyle() );
+ SetOverColor( pAttrSet->GetOverline().GetColor() );
+ SetEmphasisMark( pAttrSet->GetEmphasisMark().GetEmphasisMark() );
+ SetStrikeout( pAttrSet->GetCrossedOut().GetStrikeout() );
+ SetColor( pAttrSet->GetColor().GetValue() );
+ SetTransparent( sal_True );
+ SetAlign( ALIGN_BASELINE );
+ SetOutline( pAttrSet->GetContour().GetValue() );
+ SetShadow( pAttrSet->GetShadowed().GetValue() );
+ SetPropWidth( pAttrSet->GetCharScaleW().GetValue() );
+ SetRelief( (FontRelief)pAttrSet->GetCharRelief().GetValue() );
+ if( pAttrSet->GetAutoKern().GetValue() )
+ {
+ SetAutoKern( ( !pIDocumentSettingAccess ||
+ !pIDocumentSettingAccess->get(IDocumentSettingAccess::KERN_ASIAN_PUNCTUATION) ) ?
+ KERNING_FONTSPECIFIC :
+ KERNING_ASIAN );
+ }
+ else
+ SetAutoKern( 0 );
+ SetWordLineMode( pAttrSet->GetWordLineMode().GetValue() );
+ const SvxEscapementItem &rEsc = pAttrSet->GetEscapement();
+ SetEscapement( rEsc.GetEsc() );
+ if( aSub[SW_LATIN].IsEsc() )
+ SetProportion( rEsc.GetProp() );
+ SetCaseMap( pAttrSet->GetCaseMap().GetCaseMap() );
+ SetFixKerning( pAttrSet->GetKerning().GetValue() );
+ const SfxPoolItem* pItem;
+ if( SFX_ITEM_SET == pAttrSet->GetItemState( RES_CHRATR_BACKGROUND,
+ sal_True, &pItem ))
+ pBackColor = new Color( ((SvxBrushItem*)pItem)->GetColor() );
+ else
+ pBackColor = NULL;
+ const SvxTwoLinesItem& rTwoLinesItem = pAttrSet->Get2Lines();
+ if ( ! rTwoLinesItem.GetValue() )
+ SetVertical( pAttrSet->GetCharRotate().GetValue() );
+ else
+ SetVertical( 0 );
+}
+
+SwSubFont& SwSubFont::operator=( const SwSubFont &rFont )
+{
+ SvxFont::operator=( rFont );
+ pMagic = rFont.pMagic;
+ nFntIndex = rFont.nFntIndex;
+ nOrgHeight = rFont.nOrgHeight;
+ nOrgAscent = rFont.nOrgAscent;
+ nPropWidth = rFont.nPropWidth;
+ aSize = rFont.aSize;
+ return *this;
+}
+
+SwFont& SwFont::operator=( const SwFont &rFont )
+{
+ aSub[SW_LATIN] = rFont.aSub[SW_LATIN];
+ aSub[SW_CJK] = rFont.aSub[SW_CJK];
+ aSub[SW_CTL] = rFont.aSub[SW_CTL];
+ nActual = rFont.nActual;
+ delete pBackColor;
+ pBackColor = rFont.pBackColor ? new Color( *rFont.pBackColor ) : NULL;
+ aUnderColor = rFont.GetUnderColor();
+ aOverColor = rFont.GetOverColor();
+ nToxCnt = 0;
+ nRefCnt = 0;
+ m_nMetaCount = 0;
+ bFntChg = rFont.bFntChg;
+ bOrgChg = rFont.bOrgChg;
+ bPaintBlank = rFont.bPaintBlank;
+ bPaintWrong = sal_False;
+ bURL = rFont.bURL;
+ bGreyWave = rFont.bGreyWave;
+ bNoColReplace = rFont.bNoColReplace;
+ bNoHyph = rFont.bNoHyph;
+ bBlink = rFont.bBlink;
+ return *this;
+}
+
+/*************************************************************************
+ * SwFont::GoMagic()
+ *************************************************************************/
+
+void SwFont::GoMagic( ViewShell *pSh, sal_uInt8 nWhich )
+{
+ SwFntAccess aFntAccess( aSub[nWhich].pMagic, aSub[nWhich].nFntIndex,
+ &aSub[nWhich], pSh, sal_True );
+}
+
+/*************************************************************************
+ * SwSubFont::IsSymbol()
+ *************************************************************************/
+
+sal_Bool SwSubFont::IsSymbol( ViewShell *pSh )
+{
+ SwFntAccess aFntAccess( pMagic, nFntIndex, this, pSh, sal_False );
+ return aFntAccess.Get()->IsSymbol();
+}
+
+/*************************************************************************
+ * SwSubFont::ChgFnt()
+ *************************************************************************/
+
+sal_Bool SwSubFont::ChgFnt( ViewShell *pSh, OutputDevice& rOut )
+{
+ if ( pLastFont )
+ pLastFont->Unlock();
+ SwFntAccess aFntAccess( pMagic, nFntIndex, this, pSh, sal_True );
+ SV_STAT( nChangeFont );
+
+ pLastFont = aFntAccess.Get();
+
+ pLastFont->SetDevFont( pSh, rOut );
+
+ pLastFont->Lock();
+ return UNDERLINE_NONE != GetUnderline() ||
+ UNDERLINE_NONE != GetOverline() ||
+ STRIKEOUT_NONE != GetStrikeout();
+}
+
+/*************************************************************************
+ * SwFont::ChgPhysFnt()
+ *************************************************************************/
+
+void SwFont::ChgPhysFnt( ViewShell *pSh, OutputDevice& rOut )
+{
+ if( bOrgChg && aSub[nActual].IsEsc() )
+ {
+ const sal_uInt8 nOldProp = aSub[nActual].GetPropr();
+ SetProportion( 100 );
+ ChgFnt( pSh, rOut );
+ SwFntAccess aFntAccess( aSub[nActual].pMagic, aSub[nActual].nFntIndex,
+ &aSub[nActual], pSh );
+ aSub[nActual].nOrgHeight = aFntAccess.Get()->GetFontHeight( pSh, rOut );
+ aSub[nActual].nOrgAscent = aFntAccess.Get()->GetFontAscent( pSh, rOut );
+ SetProportion( nOldProp );
+ bOrgChg = sal_False;
+ }
+
+ if( bFntChg )
+ {
+ ChgFnt( pSh, rOut );
+ bFntChg = bOrgChg;
+ }
+ if( rOut.GetTextLineColor() != aUnderColor )
+ rOut.SetTextLineColor( aUnderColor );
+ if( rOut.GetOverlineColor() != aOverColor )
+ rOut.SetOverlineColor( aOverColor );
+}
+
+/*************************************************************************
+ * SwFont::CalcEscHeight()
+ * Height = MaxAscent + MaxDescent
+ * MaxAscent = Max (T1_ascent, T2_ascent + (Esc * T1_height) );
+ * MaxDescent = Max (T1_height-T1_ascent,
+ * T2_height-T2_ascent - (Esc * T1_height)
+ *************************************************************************/
+
+sal_uInt16 SwSubFont::CalcEscHeight( const sal_uInt16 nOldHeight,
+ const sal_uInt16 nOldAscent ) const
+{
+ if( DFLT_ESC_AUTO_SUPER != GetEscapement() &&
+ DFLT_ESC_AUTO_SUB != GetEscapement() )
+ {
+ long nDescent = nOldHeight - nOldAscent -
+ ( (long) nOrgHeight * GetEscapement() ) / 100L;
+ const sal_uInt16 nDesc = ( nDescent>0 ) ? Max ( sal_uInt16(nDescent),
+ sal_uInt16(nOrgHeight - nOrgAscent) ) : nOrgHeight - nOrgAscent;
+ return ( nDesc + CalcEscAscent( nOldAscent ) );
+ }
+ return nOrgHeight;
+}
+
+short SwSubFont::_CheckKerning( )
+{
+ short nKernx = - short( Font::GetSize().Height() / 6 );
+
+ if ( nKernx < GetFixKerning() )
+ return GetFixKerning();
+ return nKernx;
+}
+
+/*************************************************************************
+ * SwSubFont::GetAscent()
+ *************************************************************************/
+
+sal_uInt16 SwSubFont::GetAscent( ViewShell *pSh, const OutputDevice& rOut )
+{
+ sal_uInt16 nAscent;
+ SwFntAccess aFntAccess( pMagic, nFntIndex, this, pSh );
+ nAscent = aFntAccess.Get()->GetFontAscent( pSh, rOut );
+ if( GetEscapement() )
+ nAscent = CalcEscAscent( nAscent );
+ return nAscent;
+}
+
+/*************************************************************************
+ * SwSubFont::GetHeight()
+ *************************************************************************/
+
+sal_uInt16 SwSubFont::GetHeight( ViewShell *pSh, const OutputDevice& rOut )
+{
+ SV_STAT( nGetTextSize );
+ SwFntAccess aFntAccess( pMagic, nFntIndex, this, pSh );
+ const sal_uInt16 nHeight = aFntAccess.Get()->GetFontHeight( pSh, rOut );
+ if ( GetEscapement() )
+ {
+ const sal_uInt16 nAscent = aFntAccess.Get()->GetFontAscent( pSh, rOut );
+ return CalcEscHeight( nHeight, nAscent ); // + nLeading;
+ }
+ return nHeight; // + nLeading;
+}
+
+/*************************************************************************
+ * SwSubFont::_GetTxtSize()
+ *************************************************************************/
+Size SwSubFont::_GetTxtSize( SwDrawTextInfo& rInf )
+{
+ // Robust: Eigentlich sollte der Font bereits eingestellt sein, aber
+ // sicher ist sicher ...
+ if ( !pLastFont || pLastFont->GetOwner()!=pMagic ||
+ !IsSameInstance( rInf.GetpOut()->GetFont() ) )
+ ChgFnt( rInf.GetShell(), rInf.GetOut() );
+
+ SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() );
+
+ Size aTxtSize;
+ xub_StrLen nLn = ( rInf.GetLen() == STRING_LEN ? rInf.GetText().Len()
+ : rInf.GetLen() );
+ rInf.SetLen( nLn );
+ if( IsCapital() && nLn )
+ aTxtSize = GetCapitalSize( rInf );
+ else
+ {
+ SV_STAT( nGetTextSize );
+ long nOldKern = rInf.GetKern();
+ const XubString &rOldTxt = rInf.GetText();
+ rInf.SetKern( CheckKerning() );
+ if ( !IsCaseMap() )
+ aTxtSize = pLastFont->GetTextSize( rInf );
+ else
+ {
+ String aTmp = CalcCaseMap( rInf.GetText() );
+ const XubString &rOldStr = rInf.GetText();
+ sal_Bool bCaseMapLengthDiffers(aTmp.Len() != rOldStr.Len());
+
+ if(bCaseMapLengthDiffers && rInf.GetLen())
+ {
+ // #108203#
+ // If the length of the original string and the CaseMapped one
+ // are different, it is necessary to handle the given text part as
+ // a single snippet since it�s size may differ, too.
+ xub_StrLen nOldIdx(rInf.GetIdx());
+ xub_StrLen nOldLen(rInf.GetLen());
+ const XubString aSnippet(rOldStr, nOldIdx, nOldLen);
+ XubString aNewText(CalcCaseMap(aSnippet));
+
+ rInf.SetText( aNewText );
+ rInf.SetIdx( 0 );
+ rInf.SetLen( aNewText.Len() );
+
+ aTxtSize = pLastFont->GetTextSize( rInf );
+
+ rInf.SetIdx( nOldIdx );
+ rInf.SetLen( nOldLen );
+ }
+ else
+ {
+ rInf.SetText( aTmp );
+ aTxtSize = pLastFont->GetTextSize( rInf );
+ }
+
+ rInf.SetText( rOldStr );
+ }
+ rInf.SetKern( nOldKern );
+ rInf.SetText( rOldTxt );
+ // 15142: Ein Wort laenger als eine Zeile, beim Zeilenumbruch
+ // hochgestellt, muss seine effektive Hoehe melden.
+ if( GetEscapement() )
+ {
+ const sal_uInt16 nAscent = pLastFont->GetFontAscent( rInf.GetShell(),
+ rInf.GetOut() );
+ aTxtSize.Height() =
+ (long)CalcEscHeight( (sal_uInt16)aTxtSize.Height(), nAscent);
+ }
+ }
+
+ if (1==rInf.GetLen() && CH_TXT_ATR_FIELDSTART==rInf.GetText().GetChar(rInf.GetIdx()))
+ {
+ xub_StrLen nOldIdx(rInf.GetIdx());
+ xub_StrLen nOldLen(rInf.GetLen());
+ String aNewText=String::CreateFromAscii(CH_TXT_ATR_SUBST_FIELDSTART);
+ rInf.SetText( aNewText );
+ rInf.SetIdx( 0 );
+ rInf.SetLen( aNewText.Len() );
+ aTxtSize = pLastFont->GetTextSize( rInf );
+ rInf.SetIdx( nOldIdx );
+ rInf.SetLen( nOldLen );
+ }
+ else if (1==rInf.GetLen() && CH_TXT_ATR_FIELDEND==rInf.GetText().GetChar(rInf.GetIdx()))
+ {
+ xub_StrLen nOldIdx(rInf.GetIdx());
+ xub_StrLen nOldLen(rInf.GetLen());
+ String aNewText=String::CreateFromAscii(CH_TXT_ATR_SUBST_FIELDEND);
+ rInf.SetText( aNewText );
+ rInf.SetIdx( 0 );
+ rInf.SetLen( aNewText.Len() );
+ aTxtSize = pLastFont->GetTextSize( rInf );
+ rInf.SetIdx( nOldIdx );
+ rInf.SetLen( nOldLen );
+ }
+
+ return aTxtSize;
+}
+
+/*************************************************************************
+ * SwSubFont::_DrawText()
+ *************************************************************************/
+
+void SwSubFont::_DrawText( SwDrawTextInfo &rInf, const sal_Bool bGrey )
+{
+ rInf.SetGreyWave( bGrey );
+ xub_StrLen nLn = rInf.GetText().Len();
+ if( !rInf.GetLen() || !nLn )
+ return;
+ if( STRING_LEN == rInf.GetLen() )
+ rInf.SetLen( nLn );
+
+ FontUnderline nOldUnder = UNDERLINE_NONE;
+ SwUnderlineFont* pUnderFnt = 0;
+
+ if( rInf.GetUnderFnt() )
+ {
+ nOldUnder = GetUnderline();
+ SetUnderline( UNDERLINE_NONE );
+ pUnderFnt = rInf.GetUnderFnt();
+ }
+
+ if( !pLastFont || pLastFont->GetOwner()!=pMagic )
+ ChgFnt( rInf.GetShell(), rInf.GetOut() );
+
+ SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() );
+
+ Point aPos( rInf.GetPos() );
+ const Point &rOld = rInf.GetPos();
+ rInf.SetPos( aPos );
+
+ if( GetEscapement() )
+ CalcEsc( rInf, aPos );
+
+ rInf.SetKern( CheckKerning() + rInf.GetSperren() / SPACING_PRECISION_FACTOR );
+
+ if( IsCapital() )
+ DrawCapital( rInf );
+ else
+ {
+ SV_STAT( nDrawText );
+ if ( !IsCaseMap() )
+ pLastFont->DrawText( rInf );
+ else
+ {
+ const XubString &rOldStr = rInf.GetText();
+ XubString aString( CalcCaseMap( rOldStr ) );
+ sal_Bool bCaseMapLengthDiffers(aString.Len() != rOldStr.Len());
+
+ if(bCaseMapLengthDiffers && rInf.GetLen())
+ {
+ // #108203#
+ // If the length of the original string and the CaseMapped one
+ // are different, it is necessary to handle the given text part as
+ // a single snippet since it�s size may differ, too.
+ xub_StrLen nOldIdx(rInf.GetIdx());
+ xub_StrLen nOldLen(rInf.GetLen());
+ const XubString aSnippet(rOldStr, nOldIdx, nOldLen);
+ XubString aNewText = CalcCaseMap(aSnippet);
+
+ rInf.SetText( aNewText );
+ rInf.SetIdx( 0 );
+ rInf.SetLen( aNewText.Len() );
+
+ pLastFont->DrawText( rInf );
+
+ rInf.SetIdx( nOldIdx );
+ rInf.SetLen( nOldLen );
+ }
+ else
+ {
+ rInf.SetText( aString );
+ pLastFont->DrawText( rInf );
+ }
+
+ rInf.SetText( rOldStr );
+ }
+ }
+
+ if( pUnderFnt && nOldUnder != UNDERLINE_NONE )
+ {
+static sal_Char const sDoubleSpace[] = " ";
+ Size aFontSize = _GetTxtSize( rInf );
+ const XubString &rOldStr = rInf.GetText();
+ XubString aStr( sDoubleSpace, RTL_TEXTENCODING_MS_1252 );
+
+ xub_StrLen nOldIdx = rInf.GetIdx();
+ xub_StrLen nOldLen = rInf.GetLen();
+ long nSpace = 0;
+ if( rInf.GetSpace() )
+ {
+ xub_StrLen nTmpEnd = nOldIdx + nOldLen;
+ if( nTmpEnd > rOldStr.Len() )
+ nTmpEnd = rOldStr.Len();
+
+ const SwScriptInfo* pSI = rInf.GetScriptInfo();
+
+ const sal_Bool bAsianFont =
+ ( rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() );
+ for( xub_StrLen nTmp = nOldIdx; nTmp < nTmpEnd; ++nTmp )
+ {
+ if( CH_BLANK == rOldStr.GetChar( nTmp ) || bAsianFont ||
+ ( nTmp + 1 < rOldStr.Len() && pSI &&
+ i18n::ScriptType::ASIAN == pSI->ScriptType( nTmp + 1 ) ) )
+ ++nSpace;
+ }
+
+ // if next portion if a hole portion we do not consider any
+ // extra space added because the last character was ASIAN
+ if ( nSpace && rInf.IsSpaceStop() && bAsianFont )
+ --nSpace;
+
+ nSpace *= rInf.GetSpace() / SPACING_PRECISION_FACTOR;
+ }
+
+ rInf.SetWidth( sal_uInt16(aFontSize.Width() + nSpace) );
+ rInf.SetText( aStr );
+ rInf.SetIdx( 0 );
+ rInf.SetLen( 2 );
+ SetUnderline( nOldUnder );
+ rInf.SetUnderFnt( 0 );
+
+ // set position for underline font
+ rInf.SetPos( pUnderFnt->GetPos() );
+
+ pUnderFnt->GetFont()._DrawStretchText( rInf );
+
+ rInf.SetUnderFnt( pUnderFnt );
+ rInf.SetText( rOldStr );
+ rInf.SetIdx( nOldIdx );
+ rInf.SetLen( nOldLen );
+ }
+
+ rInf.SetPos( rOld );
+}
+
+void SwSubFont::_DrawStretchText( SwDrawTextInfo &rInf )
+{
+ if( !rInf.GetLen() || !rInf.GetText().Len() )
+ return;
+
+ FontUnderline nOldUnder = UNDERLINE_NONE;
+ SwUnderlineFont* pUnderFnt = 0;
+
+ if( rInf.GetUnderFnt() )
+ {
+ nOldUnder = GetUnderline();
+ SetUnderline( UNDERLINE_NONE );
+ pUnderFnt = rInf.GetUnderFnt();
+ }
+
+ if ( !pLastFont || pLastFont->GetOwner() != pMagic )
+ ChgFnt( rInf.GetShell(), rInf.GetOut() );
+
+ SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() );
+
+ rInf.ApplyAutoColor();
+
+ Point aPos( rInf.GetPos() );
+
+ if( GetEscapement() )
+ CalcEsc( rInf, aPos );
+
+ rInf.SetKern( CheckKerning() + rInf.GetSperren() / SPACING_PRECISION_FACTOR );
+ const Point &rOld = rInf.GetPos();
+ rInf.SetPos( aPos );
+
+ if( IsCapital() )
+ DrawStretchCapital( rInf );
+ else
+ {
+ SV_STAT( nDrawStretchText );
+
+ if ( rInf.GetFrm() )
+ {
+ if ( rInf.GetFrm()->IsRightToLeft() )
+ rInf.GetFrm()->SwitchLTRtoRTL( aPos );
+
+ if ( rInf.GetFrm()->IsVertical() )
+ rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
+ }
+
+ if ( !IsCaseMap() )
+ rInf.GetOut().DrawStretchText( aPos, rInf.GetWidth(),
+ rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
+ else
+ rInf.GetOut().DrawStretchText( aPos, rInf.GetWidth(), CalcCaseMap(
+ rInf.GetText() ), rInf.GetIdx(), rInf.GetLen() );
+ }
+
+ if( pUnderFnt && nOldUnder != UNDERLINE_NONE )
+ {
+static sal_Char const sDoubleSpace[] = " ";
+ const XubString &rOldStr = rInf.GetText();
+ XubString aStr( sDoubleSpace, RTL_TEXTENCODING_MS_1252 );
+ xub_StrLen nOldIdx = rInf.GetIdx();
+ xub_StrLen nOldLen = rInf.GetLen();
+ rInf.SetText( aStr );
+ rInf.SetIdx( 0 );
+ rInf.SetLen( 2 );
+ SetUnderline( nOldUnder );
+ rInf.SetUnderFnt( 0 );
+
+ // set position for underline font
+ rInf.SetPos( pUnderFnt->GetPos() );
+
+ pUnderFnt->GetFont()._DrawStretchText( rInf );
+
+ rInf.SetUnderFnt( pUnderFnt );
+ rInf.SetText( rOldStr );
+ rInf.SetIdx( nOldIdx );
+ rInf.SetLen( nOldLen );
+ }
+
+ rInf.SetPos( rOld );
+}
+
+/*************************************************************************
+ * SwSubFont::_GetCrsrOfst()
+ *************************************************************************/
+
+xub_StrLen SwSubFont::_GetCrsrOfst( SwDrawTextInfo& rInf )
+{
+ if ( !pLastFont || pLastFont->GetOwner()!=pMagic )
+ ChgFnt( rInf.GetShell(), rInf.GetOut() );
+
+ SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() );
+
+ xub_StrLen nLn = rInf.GetLen() == STRING_LEN ? rInf.GetText().Len()
+ : rInf.GetLen();
+ rInf.SetLen( nLn );
+ xub_StrLen nCrsr = 0;
+ if( IsCapital() && nLn )
+ nCrsr = GetCapitalCrsrOfst( rInf );
+ else
+ {
+ const XubString &rOldTxt = rInf.GetText();
+ long nOldKern = rInf.GetKern();
+ rInf.SetKern( CheckKerning() );
+ SV_STAT( nGetTextSize );
+ if ( !IsCaseMap() )
+ nCrsr = pLastFont->GetCrsrOfst( rInf );
+ else
+ {
+ String aTmp = CalcCaseMap( rInf.GetText() );
+ rInf.SetText( aTmp );
+ nCrsr = pLastFont->GetCrsrOfst( rInf );
+ }
+ rInf.SetKern( nOldKern );
+ rInf.SetText( rOldTxt );
+ }
+ return nCrsr;
+}
+
+/*************************************************************************
+ * SwSubFont::CalcEsc()
+ *************************************************************************/
+
+void SwSubFont::CalcEsc( SwDrawTextInfo& rInf, Point& rPos )
+{
+ long nOfst;
+
+ sal_uInt16 nDir = UnMapDirection(
+ GetOrientation(), rInf.GetFrm() && rInf.GetFrm()->IsVertical() );
+
+ switch ( GetEscapement() )
+ {
+ case DFLT_ESC_AUTO_SUB :
+ nOfst = nOrgHeight - nOrgAscent -
+ pLastFont->GetFontHeight( rInf.GetShell(), rInf.GetOut() ) +
+ pLastFont->GetFontAscent( rInf.GetShell(), rInf.GetOut() );
+
+ switch ( nDir )
+ {
+ case 0 :
+ rPos.Y() += nOfst;
+ break;
+ case 900 :
+ rPos.X() += nOfst;
+ break;
+ case 2700 :
+ rPos.X() -= nOfst;
+ break;
+ }
+
+ break;
+ case DFLT_ESC_AUTO_SUPER :
+ nOfst = pLastFont->GetFontAscent( rInf.GetShell(), rInf.GetOut() ) -
+ nOrgAscent;
+
+
+ switch ( nDir )
+ {
+ case 0 :
+ rPos.Y() += nOfst;
+ break;
+ case 900 :
+ rPos.X() += nOfst;
+ break;
+ case 2700 :
+ rPos.X() -= nOfst;
+ break;
+ }
+
+ break;
+ default :
+ nOfst = ((long)nOrgHeight * GetEscapement()) / 100L;
+
+ switch ( nDir )
+ {
+ case 0 :
+ rPos.Y() -= nOfst;
+ break;
+ case 900 :
+ rPos.X() -= nOfst;
+ break;
+ case 2700 :
+ rPos.X() += nOfst;
+ break;
+ }
+ }
+}
+
+// used during painting of small capitals
+void SwDrawTextInfo::Shift( sal_uInt16 nDir )
+{
+#if OSL_DEBUG_LEVEL > 1
+ OSL_ENSURE( bPos, "DrawTextInfo: Undefined Position" );
+ OSL_ENSURE( bSize, "DrawTextInfo: Undefined Width" );
+#endif
+
+ const sal_Bool bBidiPor = ( GetFrm() && GetFrm()->IsRightToLeft() ) !=
+ ( 0 != ( TEXT_LAYOUT_BIDI_RTL & GetpOut()->GetLayoutMode() ) );
+
+ nDir = bBidiPor ?
+ 1800 :
+ UnMapDirection( nDir, GetFrm() && GetFrm()->IsVertical() );
+
+ switch ( nDir )
+ {
+ case 0 :
+ ((Point*)pPos)->X() += GetSize().Width();
+ break;
+ case 900 :
+ OSL_ENSURE( ((Point*)pPos)->Y() >= GetSize().Width(), "Going underground" );
+ ((Point*)pPos)->Y() -= GetSize().Width();
+ break;
+ case 1800 :
+ ((Point*)pPos)->X() -= GetSize().Width();
+ break;
+ case 2700 :
+ ((Point*)pPos)->Y() += GetSize().Width();
+ break;
+ }
+}
+
+/*************************************************************************
+ * SwUnderlineFont::~SwUnderlineFont
+ *
+ * Used for the "continuous underline" feature.
+ *************************************************************************/
+
+SwUnderlineFont::SwUnderlineFont( SwFont& rFnt, const Point& rPoint )
+ : aPos( rPoint ), pFnt( &rFnt )
+{
+};
+
+SwUnderlineFont::~SwUnderlineFont()
+{
+ delete pFnt;
+}
+
+//Helper for filters to find true lineheight of a font
+long AttrSetToLineHeight( const IDocumentSettingAccess& rIDocumentSettingAccess,
+ const SwAttrSet &rSet,
+ const OutputDevice &rOut, sal_Int16 nScript)
+{
+ SwFont aFont(&rSet, &rIDocumentSettingAccess);
+ sal_uInt8 nActual;
+ switch (nScript)
+ {
+ default:
+ case i18n::ScriptType::LATIN:
+ nActual = SW_LATIN;
+ break;
+ case i18n::ScriptType::ASIAN:
+ nActual = SW_CJK;
+ break;
+ case i18n::ScriptType::COMPLEX:
+ nActual = SW_CTL;
+ break;
+ }
+ aFont.SetActual(nActual);
+
+ OutputDevice &rMutableOut = const_cast<OutputDevice &>(rOut);
+ const Font aOldFont(rMutableOut.GetFont());
+
+ rMutableOut.SetFont(aFont.GetActualFont());
+ long nHeight = rMutableOut.GetTextHeight();
+
+ rMutableOut.SetFont(aOldFont);
+ return nHeight;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx
new file mode 100644
index 000000000000..3ca7d01e1981
--- /dev/null
+++ b/sw/source/core/txtnode/thints.cxx
@@ -0,0 +1,3063 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <hintids.hxx>
+#include <sot/factory.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <svl/whiter.hxx>
+#include <svl/itemiter.hxx>
+#include <svl/stylepool.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/emphitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <txtinet.hxx>
+#include <txtflcnt.hxx>
+#include <fmtfld.hxx>
+#include <fmtanchr.hxx>
+#include <fmtinfmt.hxx>
+#include <txtatr.hxx>
+#include <fchrfmt.hxx>
+#include <fmtautofmt.hxx>
+#include <fmtflcnt.hxx>
+#include <fmtftn.hxx>
+#include <txttxmrk.hxx>
+#include <txtrfmrk.hxx>
+#include <txtftn.hxx>
+#include <txtfld.hxx>
+#include <charatr.hxx>
+#include <charfmt.hxx>
+#include <frmfmt.hxx>
+#include <ftnidx.hxx>
+#include <fmtruby.hxx>
+#include <fmtmeta.hxx>
+#include <breakit.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <fldbas.hxx>
+#include <pam.hxx>
+#include <ndtxt.hxx>
+#include <txtfrm.hxx>
+#include <rolbck.hxx> // fuer SwRegHistory
+#include <ddefld.hxx>
+#include <docufld.hxx>
+#include <expfld.hxx>
+#include <usrfld.hxx>
+#include <poolfmt.hxx>
+#include <swfont.hxx>
+#include <istyleaccess.hxx>
+// OD 26.06.2003 #108784#
+#include <dcontact.hxx>
+#include <docsh.hxx>
+#include <svl/smplhint.hxx>
+#include <algorithm>
+#include <map>
+
+#if OSL_DEBUG_LEVEL > 1
+#define CHECK Check();
+#else
+#define CHECK
+#endif
+
+using namespace ::com::sun::star::i18n;
+
+
+SwpHints::SwpHints()
+ : m_pHistory(0)
+ , m_bFontChange(true)
+ , m_bInSplitNode(false)
+ , m_bCalcHiddenParaField(false)
+ , m_bHasHiddenParaField(false)
+ , m_bFootnote(false)
+ , m_bDDEFields(false)
+{
+}
+
+struct TxtAttrDeleter
+{
+ SwAttrPool & m_rPool;
+ TxtAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { }
+ void operator() (SwTxtAttr * const pAttr)
+ {
+ if (RES_TXTATR_META == pAttr->Which() ||
+ RES_TXTATR_METAFIELD == pAttr->Which())
+ {
+ static_cast<SwTxtMeta *>(pAttr)->ChgTxtNode(0); // prevents ASSERT
+ }
+ SwTxtAttr::Destroy( pAttr, m_rPool );
+ }
+};
+
+struct TxtAttrContains
+{
+ xub_StrLen m_nPos;
+ TxtAttrContains( const xub_StrLen nPos ) : m_nPos( nPos ) { }
+ bool operator() (SwTxtAttrEnd * const pAttr)
+ {
+ return (*pAttr->GetStart() < m_nPos) && (m_nPos < *pAttr->GetEnd());
+ }
+};
+
+// a: |-----|
+// b:
+// |---| => valid: b before a
+// |-----| => valid: start == end; b before a
+// |---------| => invalid: overlap (1)
+// |-----------| => valid: same end; b around a
+// |-----------------| => valid: b around a
+// |---| => valid; same start; b within a
+// |-----| => valid; same start and end; b around or within a?
+// |-----------| => valid: same start: b around a
+// |-| => valid: b within a
+// |---| => valid: same end; b within a
+// |---------| => invalid: overlap (2)
+// |-----| => valid: end == start; b after a
+// |---| => valid: b after a
+// ===> 2 invalid overlap cases
+static
+bool isOverlap(const xub_StrLen nStart1, const xub_StrLen nEnd1,
+ const xub_StrLen nStart2, const xub_StrLen nEnd2)
+{
+ return
+ ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2)) // (1)
+ || ((nStart1 < nStart2) && (nStart2 < nEnd1) && (nEnd1 < nEnd2)); // (2)
+}
+
+/// #i106930#: now asymmetric: empty hint1 is _not_ nested, but empty hint2 is
+static
+bool isNestedAny(const xub_StrLen nStart1, const xub_StrLen nEnd1,
+ const xub_StrLen nStart2, const xub_StrLen nEnd2)
+{
+ return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
+ // same start/end: nested except if hint1 empty and hint2 not empty
+ ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
+ : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
+}
+
+static
+bool isSelfNestable(const sal_uInt16 nWhich)
+{
+ if ((RES_TXTATR_INETFMT == nWhich) ||
+ (RES_TXTATR_CJK_RUBY == nWhich))
+ return false;
+ OSL_ENSURE((RES_TXTATR_META == nWhich) ||
+ (RES_TXTATR_METAFIELD == nWhich), "???");
+ return true;
+}
+
+static
+bool isSplittable(const sal_uInt16 nWhich)
+{
+ if ((RES_TXTATR_INETFMT == nWhich) ||
+ (RES_TXTATR_CJK_RUBY == nWhich))
+ return true;
+ OSL_ENSURE((RES_TXTATR_META == nWhich) ||
+ (RES_TXTATR_METAFIELD == nWhich), "???");
+ return false;
+}
+
+enum Split_t { FAIL, SPLIT_NEW, SPLIT_OTHER };
+/**
+ Calculate splitting policy for overlapping hints, based on what kind of
+ hint is inserted, and what kind of existing hint overlaps.
+ */
+static Split_t
+splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
+{
+ if (!isSplittable(nWhichOther))
+ {
+ if (!isSplittable(nWhichNew))
+ return FAIL;
+ else
+ return SPLIT_NEW;
+ }
+ else
+ {
+ if ((RES_TXTATR_INETFMT == nWhichNew) &&
+ (RES_TXTATR_CJK_RUBY == nWhichOther))
+ return SPLIT_NEW;
+ else
+ return SPLIT_OTHER;
+ }
+}
+
+void SwTxtINetFmt::InitINetFmt(SwTxtNode & rNode)
+{
+ ChgTxtNode(&rNode);
+ SwCharFmt * const pFmt(
+ rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_INET_NORMAL) );
+ pFmt->Add( this );
+}
+
+void SwTxtRuby::InitRuby(SwTxtNode & rNode)
+{
+ ChgTxtNode(&rNode);
+ SwCharFmt * const pFmt(
+ rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_RUBYTEXT) );
+ pFmt->Add( this );
+}
+
+/**
+ Create a new nesting text hint.
+ */
+static SwTxtAttrNesting *
+MakeTxtAttrNesting(SwTxtNode & rNode, SwTxtAttrNesting & rNesting,
+ const xub_StrLen nStart, const xub_StrLen nEnd)
+{
+ SwTxtAttr * const pNew( MakeTxtAttr(
+ *rNode.GetDoc(), rNesting.GetAttr(), nStart, nEnd ) );
+ switch (pNew->Which())
+ {
+ case RES_TXTATR_INETFMT:
+ {
+ static_cast<SwTxtINetFmt*>(pNew)->InitINetFmt(rNode);
+ break;
+ }
+ case RES_TXTATR_CJK_RUBY:
+ {
+ static_cast<SwTxtRuby*>(pNew)->InitRuby(rNode);
+ break;
+ }
+ default:
+ OSL_FAIL("MakeTxtAttrNesting: what the hell is that?");
+ break;
+ }
+ return static_cast<SwTxtAttrNesting*>(pNew);
+}
+
+typedef ::std::vector<SwTxtAttrNesting *> NestList_t;
+
+static void
+lcl_DoSplitNew(NestList_t & rSplits, SwTxtNode & rNode,
+ const xub_StrLen nNewStart,
+ const xub_StrLen nOtherStart, const xub_StrLen nOtherEnd, bool bOtherDummy)
+{
+ const bool bSplitAtStart(nNewStart < nOtherStart);
+ const xub_StrLen nSplitPos( (bSplitAtStart) ? nOtherStart : nOtherEnd );
+ // first find the portion that is split (not necessarily the last one!)
+ NestList_t::iterator const iter(
+ ::std::find_if( rSplits.begin(), rSplits.end(),
+ TxtAttrContains(nSplitPos) ) );
+ if (iter != rSplits.end()) // already split here?
+ {
+ const xub_StrLen nStartPos( // skip other's dummy character!
+ (bSplitAtStart && bOtherDummy) ? nSplitPos + 1 : nSplitPos );
+ SwTxtAttrNesting * const pNew( MakeTxtAttrNesting(
+ rNode, **iter, nStartPos, *(*iter)->GetEnd() ) );
+ *(*iter)->GetEnd() = nSplitPos;
+ rSplits.insert(iter + 1, pNew);
+ }
+}
+
+/**
+ Insert nesting hint into the hints array. Also calls NoteInHistory.
+ @param rNewHint the hint to be inserted (must not overlap existing!)
+ */
+void SwpHints::InsertNesting(SwTxtAttrNesting & rNewHint)
+{
+ SwpHintsArray::Insert(& rNewHint);
+ NoteInHistory( & rNewHint, true );
+}
+
+/**
+
+The following hints correspond to well-formed XML elements in ODF:
+RES_TXTATR_INETFMT, RES_TXTATR_CJK_RUBY, RES_TXTATR_META, RES_TXTATR_METAFIELD
+
+The writer core must ensure that these do not overlap; if they did,
+the document would not be storable as ODF.
+
+Also, a Hyperlink must not be nested within another Hyperlink,
+and a Ruby must not be nested within another Ruby.
+
+The ODF export in xmloff will only put a hyperlink into a ruby, never a ruby
+into a hyperlink.
+
+Unfortunately the UNO API for Hyperlink and Ruby consists of the properties
+Hyperlink* and Ruby* of the css.text.CharacterProperties service. In other
+words, they are treated as formatting attributes, not as content entites.
+Furthermore, for API users it is not possible to easily test whether a certain
+range would be overlapping with other nested attributes, and most importantly,
+<em>which ones</em>, so we can hardly refuse to insert these in cases of
+overlap.
+
+It is possible to split Hyperlink and Ruby into multiple portions, such that
+the result is properly nested.
+
+meta and meta-field must not be split, because they have xml:id.
+
+These constraints result in the following design:
+
+RES_TXTATR_INETFMT:
+ always succeeds
+ inserts n attributes split at RES_TXTATR_CJK_RUBY, RES_TXTATR_META,
+ RES_TXTATR_METAFIELD
+ may replace existing RES_TXTATR_INETFMT at overlap
+RES_TXTATR_CJK_RUBY:
+ always succeeds
+ inserts n attributes split at RES_TXTATR_META, RES_TXTATR_METAFIELD
+ may replace existing RES_TXTATR_CJK_RUBY at overlap
+ may split existing overlapping RES_TXTATR_INETFMT
+RES_TXTATR_META:
+ may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
+ may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
+ inserts 1 attribute
+RES_TXTATR_METAFIELD:
+ may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
+ may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
+ inserts 1 attribute
+
+The nesting is expressed by the position of the hints.
+RES_TXTATR_META and RES_TXTATR_METAFIELD have a CH_TXTATR, and there can
+only be one such hint starting and ending at a given position.
+Only RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY lack a CH_TXTATR.
+The interpretation given is that RES_TXTATR_CJK_RUBY is always around
+a RES_TXTATR_INETFMT at the same start and end position (which corresponds
+with the UNO API).
+Both of these are always around a nesting hint with CH_TXTATR at the same
+start and end position (if they should be inside, then the start should be
+after the CH_TXTATR).
+It would probably be a bad idea to add another nesting hint without
+CH_TXTATR; on the other hand, it would be difficult adding a CH_TXTATR to
+RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY, due to the overwriting and
+splitting of exising hints that is necessary for backward compatibility.
+
+ @param rNode the text node
+ @param rHint the hint to be inserted
+ @returns true iff hint was successfully inserted
+*/
+bool
+SwpHints::TryInsertNesting( SwTxtNode & rNode, SwTxtAttrNesting & rNewHint )
+{
+// INVARIANT: the nestable hints in the array are properly nested
+ const sal_uInt16 nNewWhich( rNewHint.Which() );
+ const xub_StrLen nNewStart( *rNewHint.GetStart() );
+ const xub_StrLen nNewEnd ( *rNewHint.GetEnd() );
+//??? const bool bNoLengthAttribute( nNewStart == nNewEnd );
+ const bool bNewSelfNestable( isSelfNestable(nNewWhich) );
+
+ OSL_ENSURE( (RES_TXTATR_INETFMT == nNewWhich) ||
+ (RES_TXTATR_CJK_RUBY == nNewWhich) ||
+ (RES_TXTATR_META == nNewWhich) ||
+ (RES_TXTATR_METAFIELD == nNewWhich),
+ "TryInsertNesting: Expecting INETFMT or RUBY or META or METAFIELD" );
+
+ NestList_t OverlappingExisting; // existing hints to be split
+ NestList_t OverwrittenExisting; // existing hints to be replaced
+ NestList_t SplitNew; // new hints to be inserted
+
+ SplitNew.push_back(& rNewHint);
+
+ // pass 1: split the inserted hint into fragments if necessary
+ for ( sal_uInt16 i = 0; i < GetEndCount(); ++i )
+ {
+ SwTxtAttr * const pOther = GetEnd(i);
+
+ if (pOther->IsNesting())
+ {
+ const sal_uInt16 nOtherWhich( pOther->Which() );
+ const xub_StrLen nOtherStart( *(pOther)->GetStart() );
+ const xub_StrLen nOtherEnd ( *(pOther)->GetEnd() );
+ if (isOverlap(nNewStart, nNewEnd, nOtherStart, nOtherEnd ))
+ {
+ switch (splitPolicy(nNewWhich, nOtherWhich))
+ {
+ case FAIL:
+ OSL_TRACE("cannot insert hint: overlap detected");
+ ::std::for_each(SplitNew.begin(), SplitNew.end(),
+ TxtAttrDeleter(*rNode.GetDoc()));
+ return false;
+ case SPLIT_NEW:
+ lcl_DoSplitNew(SplitNew, rNode, nNewStart,
+ nOtherStart, nOtherEnd, pOther->HasDummyChar());
+ break;
+ case SPLIT_OTHER:
+ OverlappingExisting.push_back(
+ static_cast<SwTxtAttrNesting*>(pOther));
+ break;
+ default:
+ OSL_FAIL("bad code monkey");
+ break;
+ }
+ }
+ else if (isNestedAny(nNewStart, nNewEnd, nOtherStart, nOtherEnd))
+ {
+ if (!bNewSelfNestable && (nNewWhich == nOtherWhich))
+ {
+ // ruby and hyperlink: if there is nesting, _overwrite_
+ OverwrittenExisting.push_back(
+ static_cast<SwTxtAttrNesting*>(pOther));
+ }
+ else if ((nNewStart == nOtherStart) && pOther->HasDummyChar())
+ {
+ if (rNewHint.HasDummyChar())
+ {
+ OSL_FAIL("ERROR: inserting duplicate CH_TXTATR hint");
+ return false;
+ } else if (nNewEnd < nOtherEnd) {
+ // other has dummy char, new is inside other, but
+ // new contains the other's dummy char?
+ // should be corrected because it may lead to problems
+ // in SwXMeta::createEnumeration
+ // SplitNew is sorted, so this is the first split
+ xub_StrLen *const pStart(SplitNew.front()->GetStart());
+ OSL_ENSURE(*pStart == nNewStart, "how did that happen?");
+ *pStart = nNewStart + 1;
+ }
+ }
+ }
+ }
+ }
+
+ OSL_ENSURE(isSplittable(nNewWhich) || SplitNew.size() == 1,
+ "splitting the unsplittable ???");
+
+ // pass 2: split existing hints that overlap/nest with new hint
+ // do not iterate over hints array, but over remembered set of overlapping
+ // hints, to keep things simple w.r.t. insertion/removal
+ // N.B: if there is a hint that splits the inserted hint, then
+ // that hint would also have already split any hint in OverlappingExisting
+ // so any hint in OverlappingExisting can be split at most by one hint
+ // in SplitNew, or even not at all (this is not true for existing hints
+ // that go _around_ new hint, which is the raison d'^etre for pass 4)
+ for (NestList_t::iterator itOther = OverlappingExisting.begin();
+ itOther != OverlappingExisting.end(); ++itOther)
+ {
+ const xub_StrLen nOtherStart( *(*itOther)->GetStart() );
+ const xub_StrLen nOtherEnd ( *(*itOther)->GetEnd() );
+
+ for (NestList_t::iterator itNew = SplitNew.begin();
+ itNew != SplitNew.end(); ++itNew)
+ {
+ const xub_StrLen nSplitNewStart( *(*itNew)->GetStart() );
+ const xub_StrLen nSplitNewEnd ( *(*itNew)->GetEnd() );
+ // 4 cases: within, around, overlap l, overlap r, (OTHER: no action)
+ const bool bRemoveOverlap(
+ !bNewSelfNestable && (nNewWhich == (*itOther)->Which()) );
+
+ switch (ComparePosition(nSplitNewStart, nSplitNewEnd,
+ nOtherStart, nOtherEnd))
+ {
+ case POS_INSIDE:
+ {
+ OSL_ENSURE(!bRemoveOverlap,
+ "this one should be in OverwrittenExisting?");
+ }
+ break;
+ case POS_OUTSIDE:
+ case POS_EQUAL:
+ {
+ OSL_FAIL("existing hint inside new hint: why?");
+ }
+ break;
+ case POS_OVERLAP_BEFORE:
+ {
+ Delete( *itOther ); // this also does NoteInHistory!
+ *(*itOther)->GetStart() = nSplitNewEnd;
+ InsertNesting( **itOther );
+ if (!bRemoveOverlap)
+ {
+ if ( USHRT_MAX == Count() )
+ {
+ OSL_FAIL("hints array full :-(");
+ return false;
+ }
+ SwTxtAttrNesting * const pOtherLeft(
+ MakeTxtAttrNesting( rNode, **itOther,
+ nOtherStart, nSplitNewEnd ) );
+ InsertNesting( *pOtherLeft );
+ }
+ }
+ break;
+ case POS_OVERLAP_BEHIND:
+ {
+ Delete( *itOther ); // this also does NoteInHistory!
+ *(*itOther)->GetEnd() = nSplitNewStart;
+ InsertNesting( **itOther );
+ if (!bRemoveOverlap)
+ {
+ if ( USHRT_MAX == Count() )
+ {
+ OSL_FAIL("hints array full :-(");
+ return false;
+ }
+ SwTxtAttrNesting * const pOtherRight(
+ MakeTxtAttrNesting( rNode, **itOther,
+ nSplitNewStart, nOtherEnd ) );
+ InsertNesting( *pOtherRight );
+ }
+ }
+ break;
+ default:
+ break; // overlap resolved by splitting new: nothing to do
+ }
+ }
+ }
+
+ if ( USHRT_MAX - SplitNew.size() <= Count() )
+ {
+ OSL_FAIL("hints array full :-(");
+ return false;
+ }
+
+ // pass 3: insert new hints
+ for (NestList_t::iterator iter = SplitNew.begin();
+ iter != SplitNew.end(); ++iter)
+ {
+ InsertNesting(**iter);
+ }
+
+ // pass 4: handle overwritten hints
+ // RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY should displace attributes
+ // of the same kind.
+ for (NestList_t::iterator itOther = OverwrittenExisting.begin();
+ itOther != OverwrittenExisting.end(); ++itOther)
+ {
+ const xub_StrLen nOtherStart( *(*itOther)->GetStart() );
+ const xub_StrLen nOtherEnd ( *(*itOther)->GetEnd() );
+
+ // overwritten portion is given by start/end of inserted hint
+ if ((nNewStart <= nOtherStart) && (nOtherEnd <= nNewEnd))
+ {
+ Delete(*itOther);
+ rNode.DestroyAttr( *itOther );
+ }
+ else
+ {
+ OSL_ENSURE((nOtherStart < nNewStart) && (nNewEnd < nOtherEnd), "huh?");
+ // scenario: there is a RUBY, and contained within that a META;
+ // now a RUBY is inserted within the META => the exising RUBY is split:
+ // here it is not possible to simply insert the left/right fragment
+ // of the existing RUBY because they <em>overlap</em> with the META!
+ Delete( *itOther ); // this also does NoteInHistory!
+ *(*itOther)->GetEnd() = nNewStart;
+ bool bSuccess( TryInsertNesting(rNode, **itOther) );
+ OSL_ENSURE(bSuccess, "recursive call 1 failed?");
+ SwTxtAttrNesting * const pOtherRight(
+ MakeTxtAttrNesting(
+ rNode, **itOther, nNewEnd, nOtherEnd ) );
+ bSuccess = TryInsertNesting(rNode, *pOtherRight);
+ OSL_ENSURE(bSuccess, "recursive call 2 failed?");
+ (void)bSuccess;
+ }
+
+ }
+
+ return true;
+}
+
+
+// This function takes care for the following text attribute:
+// RES_TXTATR_CHARFMT, RES_TXTATR_AUTOFMT
+// These attributes have to be handled in a special way (Portion building).
+//
+// The new attribute will be split by any existing RES_TXTATR_AUTOFMT or
+// RES_TXTATR_CHARFMT. The new attribute itself will
+// split any existing RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT.
+
+void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint,
+ const SetAttrMode nMode )
+{
+ const sal_uInt16 nWhich = rNewHint.Which();
+
+ const xub_StrLen nThisStart = *rNewHint.GetStart();
+ const xub_StrLen nThisEnd = *rNewHint.GetEnd();
+ const bool bNoLengthAttribute = nThisStart == nThisEnd;
+
+ std::vector<SwTxtAttr*> aInsDelHints;
+ std::vector<SwTxtAttr*>::iterator aIter;
+
+ OSL_ENSURE( RES_TXTATR_CHARFMT == rNewHint.Which() ||
+ RES_TXTATR_AUTOFMT == rNewHint.Which(),
+ "Expecting CHARFMT or AUTOFMT" );
+
+ //
+ // 2. Find the hints which cover the start and end position
+ // of the new hint. These hints have to be split into two portions:
+ //
+ if ( !bNoLengthAttribute ) // nothing to do for no length attributes
+ {
+ for ( sal_uInt16 i = 0; i < Count(); ++i )
+ {
+ SwTxtAttr* pOther = GetTextHint(i);
+
+ if ( RES_TXTATR_CHARFMT != pOther->Which() &&
+ RES_TXTATR_AUTOFMT != pOther->Which() )
+ continue;
+
+ xub_StrLen nOtherStart = *pOther->GetStart();
+ const xub_StrLen nOtherEnd = *pOther->GetEnd();
+
+ // Check if start of new attribute overlaps with pOther:
+ // Split pOther if necessary:
+ if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
+ {
+ SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
+ pOther->GetAttr(), nOtherStart, nThisStart );
+ if ( RES_TXTATR_CHARFMT == pOther->Which() )
+ static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
+ aInsDelHints.push_back( pNewAttr );
+
+ NoteInHistory( pOther );
+ *pOther->GetStart() = nThisStart;
+ NoteInHistory( pOther, true );
+
+ nOtherStart = nThisStart;
+ }
+
+ // Check if end of new attribute overlaps with pOther:
+ // Split pOther if necessary:
+ if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
+ {
+ SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
+ pOther->GetAttr(), nOtherStart, nThisEnd );
+ if ( RES_TXTATR_CHARFMT == pOther->Which() )
+ static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
+ aInsDelHints.push_back( pNewAttr );
+
+ NoteInHistory( pOther );
+ *pOther->GetStart() = nThisEnd;
+ NoteInHistory( pOther, true );
+ }
+ }
+
+ // Insert the newly created attributes:
+ for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
+ {
+ SwpHintsArray::Insert( *aIter );
+ NoteInHistory( *aIter, true );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ if( !rNode.GetDoc()->IsInReading() )
+ CHECK;
+#endif
+
+ //
+ // 4. Split rNewHint into 1 ... n new hints:
+ //
+ std::set<xub_StrLen> aBounds;
+ aBounds.insert( nThisStart );
+ aBounds.insert( nThisEnd );
+
+ if ( !bNoLengthAttribute ) // nothing to do for no length attributes
+ {
+ for ( sal_uInt16 i = 0; i < Count(); ++i )
+ {
+ const SwTxtAttr* pOther = GetTextHint(i);
+
+ if ( RES_TXTATR_CHARFMT != pOther->Which() &&
+ RES_TXTATR_AUTOFMT != pOther->Which() )
+ continue;
+
+ const xub_StrLen nOtherStart = *pOther->GetStart();
+ const xub_StrLen nOtherEnd = *pOther->GetEnd();
+
+ aBounds.insert( nOtherStart );
+ aBounds.insert( nOtherEnd );
+ }
+ }
+
+ std::set<xub_StrLen>::iterator aStartIter = aBounds.lower_bound( nThisStart );
+ std::set<xub_StrLen>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
+ xub_StrLen nPorStart = *aStartIter;
+ ++aStartIter;
+ bool bDestroyHint = true;
+
+ //
+ // Insert the 1...n new parts of the new attribute:
+ //
+ while ( aStartIter != aEndIter || bNoLengthAttribute )
+ {
+ OSL_ENSURE( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" );
+
+ const xub_StrLen nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
+ aInsDelHints.clear();
+
+ // Get all hints that are in [nPorStart, nPorEnd[:
+ for ( sal_uInt16 i = 0; i < Count(); ++i )
+ {
+ SwTxtAttr *pOther = GetTextHint(i);
+
+ if ( RES_TXTATR_CHARFMT != pOther->Which() &&
+ RES_TXTATR_AUTOFMT != pOther->Which() )
+ continue;
+
+ const xub_StrLen nOtherStart = *pOther->GetStart();
+
+ if ( nOtherStart > nPorStart )
+ break;
+
+ if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
+ {
+ OSL_ENSURE( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" );
+ aInsDelHints.push_back( pOther );
+ }
+ }
+
+ SwTxtAttr* pNewAttr = 0;
+ if ( RES_TXTATR_CHARFMT == nWhich )
+ {
+ // pNewHint can be inserted after calculating the sort value.
+ // This should ensure, that pNewHint comes behind the already present
+ // character style
+ sal_uInt16 nCharStyleCount = 0;
+ aIter = aInsDelHints.begin();
+ while ( aIter != aInsDelHints.end() )
+ {
+ if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
+ {
+ // --> FME 2007-02-16 #i74589#
+ const SwFmtCharFmt& rOtherCharFmt = (*aIter)->GetCharFmt();
+ const SwFmtCharFmt& rThisCharFmt = rNewHint.GetCharFmt();
+ const bool bSameCharFmt = rOtherCharFmt.GetCharFmt() == rThisCharFmt.GetCharFmt();
+ // <--
+
+ // --> OD 2009-03-24 #i90311#
+ // Do not remove existing character format hint during XML import
+ if ( !rNode.GetDoc()->IsInXMLImport() &&
+ ( !( nsSetAttrMode::SETATTR_DONTREPLACE & nMode ) ||
+ bNoLengthAttribute ||
+ bSameCharFmt ) )
+ // <--
+ {
+ // Remove old hint
+ Delete( *aIter );
+ rNode.DestroyAttr( *aIter );
+ }
+ else
+ ++nCharStyleCount;
+ }
+ else
+ {
+ // remove all attributes from auto styles, which are explicitely set in
+ // the new character format:
+ OSL_ENSURE( RES_TXTATR_AUTOFMT == (*aIter)->Which(), "AUTOSTYLES - Misc trouble" );
+ SwTxtAttr* pOther = *aIter;
+ boost::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFmtAutoFmt&>(pOther->GetAttr()).GetStyleHandle();
+
+ // For each attribute in the automatic style check if it
+ // is also set the the new character style:
+ SfxItemSet aNewSet( *pOldStyle->GetPool(),
+ aCharAutoFmtSetRange);
+ SfxItemIter aItemIter( *pOldStyle );
+ const SfxPoolItem* pItem = aItemIter.GetCurItem();
+ while( sal_True )
+ {
+ if ( !CharFmt::IsItemIncluded( pItem->Which(), &rNewHint ) )
+ {
+ aNewSet.Put( *pItem );
+ }
+
+ if( aItemIter.IsAtEnd() )
+ break;
+
+ pItem = aItemIter.NextItem();
+ }
+
+ // Remove old hint
+ Delete( pOther );
+ rNode.DestroyAttr( pOther );
+
+ // Create new AutoStyle
+ if ( aNewSet.Count() )
+ {
+ pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
+ aNewSet, nPorStart, nPorEnd );
+ SwpHintsArray::Insert( pNewAttr );
+ NoteInHistory( pNewAttr, true );
+ }
+ }
+ ++aIter;
+ }
+
+ // If there is no current hint and start and end of rNewHint
+ // is ok, we do not need to create a new txtattr.
+ if ( nPorStart == nThisStart &&
+ nPorEnd == nThisEnd &&
+ !nCharStyleCount )
+ {
+ pNewAttr = &rNewHint;
+ bDestroyHint = false;
+ }
+ else
+ {
+ pNewAttr = MakeTxtAttr( *rNode.GetDoc(), rNewHint.GetAttr(),
+ nPorStart, nPorEnd );
+ static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( nCharStyleCount );
+ }
+ }
+ else
+ {
+ // Find the current autostyle. Mix attributes if necessary.
+ SwTxtAttr* pCurrentAutoStyle = 0;
+ SwTxtAttr* pCurrentCharFmt = 0;
+ aIter = aInsDelHints.begin();
+ while ( aIter != aInsDelHints.end() )
+ {
+ if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
+ pCurrentAutoStyle = *aIter;
+ else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
+ pCurrentCharFmt = *aIter;
+ ++aIter;
+ }
+
+ boost::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFmtAutoFmt&>(rNewHint.GetAttr()).GetStyleHandle();
+ if ( pCurrentAutoStyle )
+ {
+ boost::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFmtAutoFmt&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
+
+ // Merge attributes
+ SfxItemSet aNewSet( *pCurrentStyle );
+ aNewSet.Put( *pNewStyle );
+
+ // --> FME 2007-4-11 #i75750# Remove attributes already set at whole paragraph
+ // --> FME 2007-09-24 #i81764# This should not be applied for no length attributes!!! <--
+ if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
+ {
+ SfxItemIter aIter2( aNewSet );
+ const SfxPoolItem* pItem = aIter2.GetCurItem();
+ const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
+
+ do
+ {
+ const SfxPoolItem* pTmpItem = 0;
+ if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) &&
+ pTmpItem == pItem )
+ {
+ // Do not clear item if the attribute is set in a character format:
+ if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
+ aNewSet.ClearItem( pItem->Which() );
+ }
+ }
+ while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
+ }
+ // <--
+
+ // Remove old hint
+ Delete( pCurrentAutoStyle );
+ rNode.DestroyAttr( pCurrentAutoStyle );
+
+ // Create new AutoStyle
+ if ( aNewSet.Count() )
+ pNewAttr = MakeTxtAttr( *rNode.GetDoc(), aNewSet,
+ nPorStart, nPorEnd );
+ }
+ else
+ {
+ // Remove any attributes which are already set at the whole paragraph:
+ bool bOptimizeAllowed = true;
+
+ SfxItemSet* pNewSet = 0;
+ // --> FME 2007-4-11 #i75750# Remove attributes already set at whole paragraph
+ // --> FME 2007-09-24 #i81764# This should not be applied for no length attributes!!! <--
+ if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
+ {
+ SfxItemIter aIter2( *pNewStyle );
+ const SfxPoolItem* pItem = aIter2.GetCurItem();
+ const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
+
+ do
+ {
+ const SfxPoolItem* pTmpItem = 0;
+ if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) &&
+ pTmpItem == pItem )
+ {
+ // Do not clear item if the attribute is set in a character format:
+ if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
+ {
+ if ( !pNewSet )
+ pNewSet = pNewStyle->Clone( sal_True );
+ pNewSet->ClearItem( pItem->Which() );
+ }
+ }
+ }
+ while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
+
+ if ( pNewSet )
+ {
+ bOptimizeAllowed = false;
+ if ( pNewSet->Count() )
+ pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
+ else
+ pNewStyle.reset();
+
+ delete pNewSet;
+ }
+ }
+ // <--
+
+ // Create new AutoStyle
+ // If there is no current hint and start and end of rNewHint
+ // is ok, we do not need to create a new txtattr.
+ if ( bOptimizeAllowed &&
+ nPorStart == nThisStart &&
+ nPorEnd == nThisEnd )
+ {
+ pNewAttr = &rNewHint;
+ bDestroyHint = false;
+ }
+ else if ( pNewStyle.get() )
+ {
+ pNewAttr = MakeTxtAttr( *rNode.GetDoc(), *pNewStyle,
+ nPorStart, nPorEnd );
+ }
+ }
+ }
+
+ if ( pNewAttr )
+ {
+ SwpHintsArray::Insert( pNewAttr );
+// if ( bDestroyHint )
+ NoteInHistory( pNewAttr, true );
+ }
+
+ if ( !bNoLengthAttribute )
+ {
+ nPorStart = *aStartIter;
+ ++aStartIter;
+ }
+ else
+ break;
+ }
+
+ if ( bDestroyHint )
+ rNode.DestroyAttr( &rNewHint );
+}
+
+/*************************************************************************
+ * SwTxtNode::MakeTxtAttr()
+ *************************************************************************/
+
+SwTxtAttr* MakeRedlineTxtAttr( SwDoc & rDoc, SfxPoolItem & rAttr )
+{
+ // this is intended _only_ for special-purpose redline attributes!
+ switch (rAttr.Which())
+ {
+ case RES_CHRATR_COLOR:
+ case RES_CHRATR_WEIGHT:
+ case RES_CHRATR_CJK_WEIGHT:
+ case RES_CHRATR_CTL_WEIGHT:
+ case RES_CHRATR_POSTURE:
+ case RES_CHRATR_CJK_POSTURE:
+ case RES_CHRATR_CTL_POSTURE:
+ case RES_CHRATR_UNDERLINE:
+ case RES_CHRATR_CROSSEDOUT:
+ case RES_CHRATR_CASEMAP:
+ case RES_CHRATR_BACKGROUND:
+ break;
+ default:
+ OSL_FAIL("unsupported redline attribute");
+ break;
+ }
+
+ // Put new attribute into pool
+ // FIXME: this const_cast is evil!
+ SfxPoolItem& rNew =
+ const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
+ return new SwTxtAttrEnd( rNew, 0, 0 );
+}
+
+// create new text attribute
+SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, SfxPoolItem& rAttr,
+ xub_StrLen const nStt, xub_StrLen const nEnd,
+ CopyOrNew_t const bIsCopy, SwTxtNode *const pTxtNode)
+{
+ if ( isCHRATR(rAttr.Which()) )
+ {
+ // Somebody wants to build a SwTxtAttr for a character attribute.
+ // Sorry, this is not allowed any longer.
+ // You'll get a brand new autostyle attribute:
+ SfxItemSet aItemSet( rDoc.GetAttrPool(),
+ RES_CHRATR_BEGIN, RES_CHRATR_END );
+ aItemSet.Put( rAttr );
+ return MakeTxtAttr( rDoc, aItemSet, nStt, nEnd );
+ }
+ else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
+ static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()->
+ GetPool() != &rDoc.GetAttrPool() )
+ {
+ // If the attribute is an auto-style which refers to a pool that is
+ // different from rDoc's pool, we have to correct this:
+ const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle();
+ ::std::auto_ptr<const SfxItemSet> pNewSet(
+ pAutoStyle->SfxItemSet::Clone( sal_True, &rDoc.GetAttrPool() ));
+ SwTxtAttr* pNew = MakeTxtAttr( rDoc, *pNewSet, nStt, nEnd );
+ return pNew;
+ }
+
+ // Put new attribute into pool
+ // FIXME: this const_cast is evil!
+ SfxPoolItem& rNew =
+ const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
+
+ SwTxtAttr* pNew = 0;
+ switch( rNew.Which() )
+ {
+ case RES_TXTATR_CHARFMT:
+ {
+ SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
+ if( !rFmtCharFmt.GetCharFmt() )
+ {
+ rFmtCharFmt.SetCharFmt( rDoc.GetDfltCharFmt() );
+ }
+
+ pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
+ }
+ break;
+ case RES_TXTATR_INETFMT:
+ pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
+ break;
+ case RES_TXTATR_FIELD:
+ pNew = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt );
+ break;
+ case RES_TXTATR_FLYCNT:
+ {
+ // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
+ pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
+ // Kopie von einem Text-Attribut
+ if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() )
+ {
+ // then the format must be copied
+ static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc );
+ }
+ }
+ break;
+ case RES_TXTATR_FTN:
+ pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
+ // ggfs. SeqNo kopieren
+ if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
+ ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
+ break;
+ case RES_TXTATR_REFMARK:
+ pNew = nStt == nEnd
+ ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
+ : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
+ break;
+ case RES_TXTATR_TOXMARK:
+ pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd );
+ break;
+ case RES_TXTATR_CJK_RUBY:
+ pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd );
+ break;
+ case RES_TXTATR_META:
+ case RES_TXTATR_METAFIELD:
+ pNew = SwTxtMeta::CreateTxtMeta( rDoc.GetMetaFieldManager(), pTxtNode,
+ static_cast<SwFmtMeta&>(rNew), nStt, nEnd, bIsCopy );
+ break;
+ default:
+ OSL_ENSURE(RES_TXTATR_AUTOFMT == rNew.Which(), "unknown attribute");
+ pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
+ break;
+ }
+
+ return pNew;
+}
+
+SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet,
+ xub_StrLen nStt, xub_StrLen nEnd )
+{
+ IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
+ const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
+ SwFmtAutoFmt aNewAutoFmt;
+ aNewAutoFmt.SetStyleHandle( pAutoStyle );
+ SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd );
+ return pNew;
+}
+
+
+// loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
+void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
+{
+ if( pAttr )
+ {
+ // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
+ SwDoc* pDoc = GetDoc();
+ sal_uInt16 nDelMsg = 0;
+ switch( pAttr->Which() )
+ {
+ case RES_TXTATR_FLYCNT:
+ {
+ // siehe auch die Anmerkung "Loeschen von Formaten
+ // zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFmt()
+ SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
+ if( pFmt ) // vom Undo auf 0 gesetzt ??
+ pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt );
+ }
+ break;
+
+ case RES_CHRATR_HIDDEN:
+ SetCalcHiddenCharFlags();
+ break;
+
+ case RES_TXTATR_FTN:
+ ((SwTxtFtn*)pAttr)->SetStartNode( 0 );
+ nDelMsg = RES_FOOTNOTE_DELETED;
+ break;
+
+ case RES_TXTATR_FIELD:
+ if( !pDoc->IsInDtor() )
+ {
+ // Wenn wir ein HiddenParaField sind, dann muessen wir
+ // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
+ const SwField* pFld = pAttr->GetFld().GetFld();
+
+ //JP 06-08-95: DDE-Felder bilden eine Ausnahme
+ OSL_ENSURE( RES_DDEFLD == pFld->GetTyp()->Which() ||
+ this == ((SwTxtFld*)pAttr)->GetpTxtNode(),
+ "Wo steht denn dieses Feld?" );
+
+ // bestimmte Felder mussen am Doc das Calculations-Flag updaten
+ switch( pFld->GetTyp()->Which() )
+ {
+ case RES_HIDDENPARAFLD:
+ SetCalcHiddenParaField();
+ // 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( sal_False, *(SwTxtFld*)pAttr );
+ break;
+ case RES_DDEFLD:
+ if( GetNodes().IsDocNodes() &&
+ ((SwTxtFld*)pAttr)->GetpTxtNode() )
+ ((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt();
+ break;
+ case RES_POSTITFLD:
+ {
+ const_cast<SwFmtFld&>(pAttr->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFld(), SWFMTFLD_REMOVED ) );
+ break;
+ }
+ }
+ }
+ nDelMsg = RES_FIELD_DELETED;
+ break;
+
+ case RES_TXTATR_TOXMARK:
+ static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
+ break;
+
+ case RES_TXTATR_REFMARK:
+ nDelMsg = RES_REFMARK_DELETED;
+ break;
+
+ case RES_TXTATR_META:
+ case RES_TXTATR_METAFIELD:
+ static_cast<SwTxtMeta*>(pAttr)->ChgTxtNode(0);
+ break;
+
+ default:
+ break;
+ }
+
+ if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() )
+ {
+ SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() );
+ pDoc->GetUnoCallBack()->ModifyNotification( &aMsgHint, &aMsgHint );
+ }
+
+ SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() );
+ }
+}
+
+/*************************************************************************
+ * SwTxtNode::Insert()
+ *************************************************************************/
+
+SwTxtAttr*
+SwTxtNode::InsertItem( SfxPoolItem& rAttr,
+ const xub_StrLen nStart, const xub_StrLen nEnd, const SetAttrMode nMode )
+{
+ // character attributes will be inserted as automatic styles:
+ OSL_ENSURE( !isCHRATR(rAttr.Which()), "AUTOSTYLES - "
+ "SwTxtNode::InsertItem should not be called with character attributes");
+
+ SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(), rAttr, nStart, nEnd,
+ (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW, this );
+
+ if ( pNew )
+ {
+ const bool bSuccess( InsertHint( pNew, nMode ) );
+ // N.B.: also check that the hint is actually in the hints array,
+ // because hints of certain types may be merged after succesful
+ // insertion, and thus destroyed!
+ if (!bSuccess || ( USHRT_MAX == m_pSwpHints->GetPos( pNew ) ))
+ {
+ return 0;
+ }
+ }
+
+ return pNew;
+}
+
+// take ownership of pAttr; if insertion fails, delete pAttr
+bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode )
+{
+ sal_Bool bHiddenPara = sal_False;
+
+ OSL_ENSURE( pAttr && *pAttr->GetStart() <= Len(), "StartIdx out of bounds!" );
+ OSL_ENSURE( !pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()),
+ "EndIdx out of bounds!" );
+
+ // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR)
+ const enum IDocumentContentOperations::InsertFlags nInsertFlags =
+ (nMode & nsSetAttrMode::SETATTR_FORCEHINTEXPAND)
+ ? static_cast<IDocumentContentOperations::InsertFlags>(
+ IDocumentContentOperations::INS_FORCEHINTEXPAND |
+ IDocumentContentOperations::INS_EMPTYEXPAND)
+ : IDocumentContentOperations::INS_EMPTYEXPAND;
+
+ // need this after TryInsertHint, when pAttr may be deleted
+ const xub_StrLen nStart( *pAttr->GetStart() );
+ const bool bDummyChar( pAttr->HasDummyChar() );
+ if (bDummyChar)
+ {
+ sal_uInt16 nInsMode = nMode;
+ switch( pAttr->Which() )
+ {
+ case RES_TXTATR_FLYCNT:
+ {
+ SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
+ SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
+ if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
+ {
+ // Wir muessen zuerst einfuegen, da in SetAnchor()
+ // dem FlyFrm GetStart() uebermittelt wird.
+ //JP 11.05.98: falls das Anker-Attribut schon richtig
+ // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
+ // des Zeichens. Sonst muesste das immer ausserhalb
+ // erfolgen (Fehleranfaellig !)
+ const SwFmtAnchor* pAnchor = 0;
+ pFmt->GetItemState( RES_ANCHOR, sal_False,
+ (const SfxPoolItem**)&pAnchor );
+
+ SwIndex aIdx( this, *pAttr->GetStart() );
+ const sal_Unicode c = GetCharOfTxtAttr(*pAttr);
+ InsertText( c, aIdx, nInsertFlags );
+ nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
+
+ if (pAnchor &&
+ (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
+ pAnchor->GetCntntAnchor() &&
+ pAnchor->GetCntntAnchor()->nNode == *this &&
+ pAnchor->GetCntntAnchor()->nContent == aIdx )
+ {
+ const_cast<SwIndex&>(
+ pAnchor->GetCntntAnchor()->nContent)--;
+ }
+ }
+ pFly->SetAnchor( this );
+
+ // Format-Pointer kann sich im SetAnchor geaendert haben!
+ // (Kopieren in andere Docs!)
+ pFmt = pAttr->GetFlyCnt().GetFrmFmt();
+ SwDoc *pDoc = pFmt->GetDoc();
+
+ // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
+ // But don't allow control objects in header/footer
+ if( RES_DRAWFRMFMT == pFmt->Which() &&
+ pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) )
+ {
+ SwDrawContact* pDrawContact =
+ static_cast<SwDrawContact*>(pFmt->FindContactObj());
+ if ( pDrawContact &&
+ pDrawContact->GetMaster() &&
+ ::CheckControlLayer( pDrawContact->GetMaster() ) )
+ {
+ // das soll nicht meoglich sein; hier verhindern
+ // Der Dtor des TxtHints loescht nicht das Zeichen.
+ // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
+ // dieses explizit loeschen
+ if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
+ {
+ // loesche das Zeichen aus dem String !
+ OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
+ m_Text.GetChar(*pAttr->GetStart() ) ||
+ CH_TXTATR_INWORD ==
+ m_Text.GetChar(*pAttr->GetStart())),
+ "where is my attribute character?" );
+ m_Text.Erase( *pAttr->GetStart(), 1 );
+ // Indizies Updaten
+ SwIndex aTmpIdx( this, *pAttr->GetStart() );
+ Update( aTmpIdx, 1, sal_True );
+ }
+ // do not record deletion of Format!
+ ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
+ DestroyAttr( pAttr );
+ return false;
+ }
+ }
+ break;
+ }
+
+ case RES_TXTATR_FTN :
+ {
+ // Fussnoten, man kommt an alles irgendwie heran.
+ // CntntNode erzeugen und in die Inserts-Section stellen
+ SwDoc *pDoc = GetDoc();
+ SwNodes &rNodes = pDoc->GetNodes();
+
+ // FussNote in nicht Content-/Redline-Bereich einfuegen ??
+ if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
+ {
+ // das soll nicht meoglich sein; hier verhindern
+ // Der Dtor des TxtHints loescht nicht das Zeichen.
+ // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
+ // dieses explizit loeschen
+ if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
+ {
+ // loesche das Zeichen aus dem String !
+ OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
+ m_Text.GetChar(*pAttr->GetStart() ) ||
+ CH_TXTATR_INWORD ==
+ m_Text.GetChar(*pAttr->GetStart())),
+ "where is my attribute character?" );
+ m_Text.Erase( *pAttr->GetStart(), 1 );
+ // Indizies Updaten
+ SwIndex aTmpIdx( this, *pAttr->GetStart() );
+ Update( aTmpIdx, 1, sal_True );
+ }
+ DestroyAttr( pAttr );
+ return false;
+ }
+
+ // wird eine neue Fussnote eingefuegt ??
+ sal_Bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
+ if( bNewFtn )
+ {
+ ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
+ SwRegHistory* pHist = GetpSwpHints()
+ ? GetpSwpHints()->GetHistory() : 0;
+ if( pHist )
+ pHist->ChangeNodeIndex( GetIndex() );
+ }
+ else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
+ {
+ // loesche alle Frames der Section, auf die der StartNode zeigt
+ sal_uLong nSttIdx =
+ ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex();
+ sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
+ SwCntntNode* pCNd;
+ for( ; nSttIdx < nEndIdx; ++nSttIdx )
+ if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() ))
+ pCNd->DelFrms();
+ }
+
+ if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
+ {
+ // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
+ // entstehen koennen und das Attribut im _SortArr_ am
+ // Dokument nicht eingetrage wird.
+ SwIndex aNdIdx( this, *pAttr->GetStart() );
+ const sal_Unicode c = GetCharOfTxtAttr(*pAttr);
+ InsertText( c, aNdIdx, nInsertFlags );
+ nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
+ }
+
+ // Wir tragen uns am FtnIdx-Array des Docs ein ...
+ SwTxtFtn* pTxtFtn = 0;
+ if( !bNewFtn )
+ {
+ // eine alte Ftn wird umgehaengt (z.B. SplitNode)
+ for( sal_uInt16 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;
+ }
+ // wenn ueber Undo der StartNode gesetzt wurde, kann
+ // der Index noch gar nicht in der Verwaltung stehen !!
+ }
+ if( !pTxtFtn )
+ pTxtFtn = (SwTxtFtn*)pAttr;
+
+ // fuers Update der Nummern und zum Sortieren
+ // muss der Node gesetzt sein.
+ ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
+
+ // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
+ if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ const sal_Bool bSuccess =
+#endif
+ pDoc->GetFtnIdxs().Insert( pTxtFtn );
+#if OSL_DEBUG_LEVEL > 1
+ OSL_ENSURE( bSuccess, "FtnIdx nicht eingetragen." );
+#endif
+ }
+ SwNodeIndex aTmpIndex( *this );
+ pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
+ ((SwTxtFtn*)pAttr)->SetSeqRefNo();
+ }
+ break;
+
+ case RES_TXTATR_FIELD:
+ {
+ // fuer HiddenParaFields Benachrichtigungsmechanismus
+ // anwerfen
+ if( RES_HIDDENPARAFLD ==
+ pAttr->GetFld().GetFld()->GetTyp()->Which() )
+ bHiddenPara = sal_True;
+ }
+ break;
+
+ }
+ // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_..
+ // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
+ // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits
+ // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
+ if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
+ {
+ SwIndex aIdx( this, *pAttr->GetStart() );
+ InsertText( GetCharOfTxtAttr(*pAttr), aIdx, nInsertFlags );
+
+ // adjust end of hint to account for inserted CH_TXTATR
+ xub_StrLen * const pEnd(pAttr->GetEnd());
+ if (pEnd)
+ {
+ *pEnd = *pEnd + 1;
+ }
+ }
+ }
+
+ GetOrCreateSwpHints();
+
+ // 4263: AttrInsert durch TextInsert => kein Adjust
+ const bool bRet = m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
+
+ if (!bRet && bDummyChar)
+ {
+ // undo insertion of dummy character
+ // N.B. cannot insert the dummy character after inserting the hint,
+ // because if the hint has no extent it will be moved in InsertText,
+ // resulting in infinite recursion
+ if ( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
+ {
+ OSL_ENSURE( ( CH_TXTATR_BREAKWORD == m_Text.GetChar(nStart) ||
+ CH_TXTATR_INWORD == m_Text.GetChar(nStart) ),
+ "where is my attribute character?" );
+ SwIndex aIdx( this, nStart );
+ EraseText( aIdx, 1 );
+ }
+ }
+
+ if ( bHiddenPara )
+ {
+ SetCalcHiddenParaField();
+ }
+
+ return bRet;
+}
+
+
+/*************************************************************************
+ * SwTxtNode::DeleteAttribute()
+ *************************************************************************/
+
+void SwTxtNode::DeleteAttribute( SwTxtAttr * const pAttr )
+{
+ if ( !HasHints() )
+ {
+ OSL_FAIL("DeleteAttribute called, but text node without hints?");
+ return;
+ }
+
+ if ( pAttr->HasDummyChar() )
+ {
+ // Unbedingt Copy-konstruieren!
+ const SwIndex aIdx( this, *pAttr->GetStart() );
+ // erase the CH_TXTATR, which will also delete pAttr
+ EraseText( aIdx, 1 );
+ }
+ else
+ {
+ // create MsgHint before start/end become invalid
+ SwUpdateAttr aHint(
+ *pAttr->GetStart(), *pAttr->GetEnd(), pAttr->Which() );
+ m_pSwpHints->Delete( pAttr );
+ SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
+ NotifyClients( 0, &aHint );
+
+ TryDeleteSwpHints();
+ }
+}
+
+/*************************************************************************
+ * SwTxtNode::DeleteAttributes()
+ *************************************************************************/
+
+//FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
+void SwTxtNode::DeleteAttributes( const sal_uInt16 nWhich,
+ const xub_StrLen nStart, const xub_StrLen nEnd )
+{
+ if ( !HasHints() )
+ return;
+
+ for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ )
+ {
+ SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos );
+ const xub_StrLen nHintStart = *(pTxtHt->GetStart());
+ if (nStart < nHintStart)
+ {
+ break; // sorted by start
+ }
+ else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) )
+ {
+ if ( nWhich == RES_CHRATR_HIDDEN )
+ {
+ OSL_FAIL("hey, that's a CHRATR! how did that get in?");
+ SetCalcHiddenCharFlags();
+ }
+ else if ( nWhich == RES_TXTATR_CHARFMT )
+ {
+ // Check if character format contains hidden attribute:
+ const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt();
+ const SfxPoolItem* pItem;
+ if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
+ SetCalcHiddenCharFlags();
+ }
+ // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary
+ else if ( nWhich == RES_TXTATR_AUTOFMT )
+ {
+ // Check if auto style contains hidden attribute:
+ const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
+ if ( pHiddenItem )
+ SetCalcHiddenCharFlags();
+ }
+ // <--
+
+ xub_StrLen const * const pEndIdx = pTxtHt->GetEnd();
+
+ if ( pTxtHt->HasDummyChar() )
+ {
+ // Unbedingt Copy-konstruieren!
+ const SwIndex aIdx( this, nStart );
+ // erase the CH_TXTATR, which will also delete pTxtHt
+ EraseText( aIdx, 1 );
+ }
+ else if( *pEndIdx == nEnd )
+ {
+ // den MsgHint jetzt fuettern, weil gleich sind
+ // Start und End weg.
+ // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
+ // da dies das Feld im Dtor selbst erledigt.
+ SwUpdateAttr aHint( nStart, *pEndIdx, nWhich );
+ m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen,
+ SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() );
+ NotifyClients( 0, &aHint );
+ }
+ }
+ }
+ TryDeleteSwpHints();
+}
+
+/*************************************************************************
+ * SwTxtNode::DelSoftHyph()
+ *************************************************************************/
+
+void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd )
+{
+ xub_StrLen nFndPos = nStt, nEndPos = nEnd;
+ while( STRING_NOTFOUND !=
+ ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) &&
+ nFndPos < nEndPos )
+ {
+ const SwIndex aIdx( this, nFndPos );
+ EraseText( aIdx, 1 );
+ --nEndPos;
+ }
+}
+
+// setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
+// dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
+sal_Bool SwTxtNode::SetAttr( const SfxItemSet& rSet, xub_StrLen nStt,
+ xub_StrLen nEnd, const SetAttrMode nMode )
+{
+ if( !rSet.Count() )
+ return sal_False;
+
+ // teil die Sets auf (fuer Selektion in Nodes)
+ const SfxItemSet* pSet = &rSet;
+ SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
+
+ // gesamter Bereich
+ if ( !nStt && (nEnd == m_Text.Len()) &&
+ !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
+ {
+ // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
+ // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
+ int bHasCharFmts = sal_False;
+ if ( HasHints() )
+ {
+ for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
+ {
+ if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
+ {
+ bHasCharFmts = sal_True;
+ break;
+ }
+ }
+ }
+
+ if( !bHasCharFmts )
+ {
+ aTxtSet.Put( rSet );
+ // If there are any character attributes in rSet,
+ // we want to set them at the paragraph:
+ if( aTxtSet.Count() != rSet.Count() )
+ {
+ sal_Bool bRet = SetAttr( rSet );
+ if( !aTxtSet.Count() )
+ return bRet;
+ }
+
+ // check for auto style:
+ const SfxPoolItem* pItem;
+ const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem );
+ if ( bAutoStyle )
+ {
+ boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
+ sal_Bool bRet = SetAttr( *pAutoStyleSet );
+ if( 1 == aTxtSet.Count() )
+ return bRet;
+ }
+
+ // Continue with the text attributes:
+ pSet = &aTxtSet;
+ }
+ }
+
+ GetOrCreateSwpHints();
+
+ SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
+
+ sal_uInt16 nCount = 0;
+ SfxItemIter aIter( *pSet );
+ const SfxPoolItem* pItem = aIter.GetCurItem();
+
+ do
+ {
+ if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
+ {
+ const sal_uInt16 nWhich = pItem->Which();
+ OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
+ "SwTxtNode::SetAttr(): unknown attribute" );
+ if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
+ {
+ if ((RES_TXTATR_CHARFMT == nWhich) &&
+ (GetDoc()->GetDfltCharFmt() ==
+ static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
+ {
+ SwIndex aIndex( this, nStt );
+ RstAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
+ DontExpandFmt( aIndex );
+ }
+ else
+ {
+ if (isCHRATR(nWhich) ||
+ (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
+ {
+ aCharSet.Put( *pItem );
+ }
+ else
+ {
+
+ SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
+ const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
+ if ( pNew )
+ {
+ if ( nEnd != nStt && !pNew->GetEnd() )
+ {
+ OSL_FAIL("Attribut without end, but area marked");
+ DestroyAttr( pNew ); // do not insert
+ }
+ else if ( InsertHint( pNew, nMode ) )
+ {
+ ++nCount;
+ }
+ }
+ }
+ }
+ }
+ }
+ if ( aIter.IsAtEnd() )
+ break;
+ pItem = aIter.NextItem();
+ } while( true );
+
+ if ( aCharSet.Count() )
+ {
+ SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
+ if ( InsertHint( pTmpNew, nMode ) )
+ {
+ ++nCount;
+ }
+ }
+
+ TryDeleteSwpHints();
+
+ return nCount ? sal_True : sal_False;
+}
+
+void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
+{
+ if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
+ {
+ const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
+ if ( !pCFSet )
+ return;
+ SfxWhichIter aIter( *pCFSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while( nWhich )
+ {
+ if( ( nWhich < RES_CHRATR_END ||
+ RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
+ ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
+ rSet.Put( pCFSet->Get( nWhich ) );
+ nWhich = aIter.NextWhich();
+ }
+ }
+ else
+ rSet.Put( rAttr );
+}
+
+void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
+{
+ if( RES_TXTATR_CHARFMT == rAttr.Which() ||
+ RES_TXTATR_INETFMT == rAttr.Which() ||
+ RES_TXTATR_AUTOFMT == rAttr.Which() )
+ {
+ const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
+
+ if ( pCFSet )
+ {
+ SfxWhichIter aIter( *pCFSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while( nWhich )
+ {
+ if( ( nWhich < RES_CHRATR_END ||
+ ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
+ ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
+ rSet.Put( pCFSet->Get( nWhich ) );
+ nWhich = aIter.NextWhich();
+ }
+ }
+ }
+
+ // 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
+*/
+ rSet.Put( rAttr );
+}
+
+struct SwPoolItemEndPair
+{
+public:
+ const SfxPoolItem* mpItem;
+ xub_StrLen mnEndPos;
+
+ SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
+};
+
+void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
+ SfxItemSet& rSet )
+{
+ if ( rTxtNode.AreListLevelIndentsApplicable() )
+ {
+ const SwNumRule* pRule = rTxtNode.GetNumRule();
+ if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
+ {
+ const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
+ if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ SvxLRSpaceItem aLR( RES_LR_SPACE );
+ aLR.SetTxtLeft( rFmt.GetIndentAt() );
+ aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
+ rSet.Put( aLR );
+ }
+ }
+ }
+}
+
+// erfrage die Attribute vom TextNode ueber den Bereich
+sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd,
+ sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt,
+ const bool bMergeIndentValuesOfNumRule ) const
+{
+ if( HasHints() )
+ {
+ /* 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
+ */
+
+ void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
+ = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
+ : &lcl_MergeAttr;
+
+ // dann besorge mal die Auto-(Fmt)Attribute
+ SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
+ if( !bOnlyTxtAttr )
+ {
+ SwCntntNode::GetAttr( aFmtSet );
+ if ( bMergeIndentValuesOfNumRule )
+ {
+ lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
+ }
+ }
+
+ const sal_uInt16 nSize = m_pSwpHints->Count();
+
+ if( nStt == nEnd ) // kein Bereich:
+ {
+ for (sal_uInt16 n = 0; n < nSize; ++n)
+ {
+ const SwTxtAttr* pHt = (*m_pSwpHints)[n];
+ const xub_StrLen nAttrStart = *pHt->GetStart();
+ if( nAttrStart > nEnd ) // ueber den Bereich hinaus
+ break;
+
+ const xub_StrLen* pAttrEnd = pHt->GetEnd();
+ if ( ! pAttrEnd ) // no attributes without end
+ continue;
+
+ if( ( nAttrStart < nStt &&
+ ( pHt->DontExpand() ? nStt < *pAttrEnd
+ : nStt <= *pAttrEnd )) ||
+ ( nStt == nAttrStart &&
+ ( nAttrStart == *pAttrEnd || !nStt )))
+ (*fnMergeAttr)( rSet, pHt->GetAttr() );
+ }
+ }
+ else // es ist ein Bereich definiert
+ {
+ // --> FME 2007-03-13 #i75299#
+ ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
+ // <--
+
+ const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
+ static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
+
+ for (sal_uInt16 n = 0; n < nSize; ++n)
+ {
+ const SwTxtAttr* pHt = (*m_pSwpHints)[n];
+ const xub_StrLen nAttrStart = *pHt->GetStart();
+ if( nAttrStart > nEnd ) // ueber den Bereich hinaus
+ break;
+
+ const xub_StrLen* pAttrEnd = pHt->GetEnd();
+ if ( ! pAttrEnd ) // no attributes without end
+ continue;
+
+ sal_Bool bChkInvalid = sal_False;
+ if( nAttrStart <= nStt ) // vor oder genau Start
+ {
+ if( *pAttrEnd <= nStt ) // liegt davor
+ continue;
+
+ if( nEnd <= *pAttrEnd ) // hinter oder genau Ende
+ (*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
+ else
+// else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
+ // uneindeutig
+ bChkInvalid = sal_True;
+ }
+ else if( nAttrStart < nEnd // reicht in den Bereich
+)// && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
+ bChkInvalid = sal_True;
+
+ if( bChkInvalid )
+ {
+ // uneindeutig ?
+ ::std::auto_ptr< SfxItemIter > pItemIter;
+ const SfxPoolItem* pItem = 0;
+
+ if ( RES_TXTATR_AUTOFMT == pHt->Which() )
+ {
+ const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
+ if ( pAutoSet )
+ {
+ pItemIter.reset( new SfxItemIter( *pAutoSet ) );
+ pItem = pItemIter->GetCurItem();
+ }
+ }
+ else
+ pItem = &pHt->GetAttr();
+
+ const sal_uInt16 nHintEnd = *pAttrEnd;
+
+ while ( pItem )
+ {
+ const sal_uInt16 nHintWhich = pItem->Which();
+ OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
+ "SwTxtNode::GetAttr(): unknown attribute?");
+
+ if ( !pAttrArr.get() )
+ {
+ pAttrArr.reset(
+ new std::vector< SwPoolItemEndPair >(coArrSz));
+ }
+
+ std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
+ if (isCHRATR(nHintWhich) ||
+ isTXTATR_WITHEND(nHintWhich))
+ {
+ pPrev += nHintWhich - RES_CHRATR_BEGIN;
+ }
+ else
+ {
+ pPrev = pAttrArr->end();
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ SwPoolItemEndPair aTmp = *pPrev;
+#endif
+
+ if( pPrev != pAttrArr->end() )
+ {
+ if( !pPrev->mpItem )
+ {
+ if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
+ {
+ if( nAttrStart > nStt )
+ {
+ rSet.InvalidateItem( nHintWhich );
+ pPrev->mpItem = (SfxPoolItem*)-1;
+ }
+ else
+ {
+ pPrev->mpItem = pItem;
+ pPrev->mnEndPos = nHintEnd;
+ }
+ }
+ }
+ else if( (SfxPoolItem*)-1 != pPrev->mpItem )
+ {
+ if( pPrev->mnEndPos == nAttrStart &&
+ *pPrev->mpItem == *pItem )
+ {
+ pPrev->mpItem = pItem;
+ pPrev->mnEndPos = nHintEnd;
+ }
+ else
+ {
+ rSet.InvalidateItem( nHintWhich );
+ pPrev->mpItem = (SfxPoolItem*)-1;
+ }
+ }
+ }
+
+ pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
+ ? pItemIter->NextItem() : 0;
+ } // end while
+ }
+ }
+
+ if ( pAttrArr.get() )
+ {
+ for (sal_uInt16 n = 0; n < coArrSz; ++n)
+ {
+ const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
+ if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
+ {
+ const sal_uInt16 nWh =
+ static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
+
+ if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
+ {
+ if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
+ (*fnMergeAttr)( rSet, *rItemPair.mpItem );
+ }
+ else
+ // uneindeutig
+ rSet.InvalidateItem( nWh );
+ }
+ }
+ }
+ }
+ if( aFmtSet.Count() )
+ {
+ // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
+ aFmtSet.Differentiate( rSet );
+ // jetzt alle zusammen "mergen"
+ rSet.Put( aFmtSet );
+ }
+ }
+ else if( !bOnlyTxtAttr )
+ {
+ // dann besorge mal die Auto-(Fmt)Attribute
+ SwCntntNode::GetAttr( rSet );
+ if ( bMergeIndentValuesOfNumRule )
+ {
+ lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
+ }
+ }
+
+ return rSet.Count() ? sal_True : sal_False;
+}
+
+
+namespace
+{
+
+typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t;
+typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t;
+
+
+struct IsAutoStyle
+{
+ bool
+ operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
+ const
+ {
+ return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
+ }
+};
+
+
+/** Removes from io_rAttrSet all items that are set by style on the
+ given span.
+ */
+struct RemovePresentAttrs
+{
+ RemovePresentAttrs(SfxItemSet& io_rAttrSet)
+ : m_rAttrSet(io_rAttrSet)
+ {
+ }
+
+ void
+ operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
+ const
+ {
+ if (!i_rAttrSpan.second)
+ {
+ return;
+ }
+
+ const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second);
+ SfxItemIter aIter(m_rAttrSet);
+ const SfxPoolItem* pItem(aIter.GetCurItem());
+ while (pItem)
+ {
+ const sal_uInt16 nWhich(pItem->Which());
+ if (CharFmt::IsItemIncluded(nWhich, pAutoStyle))
+ {
+ m_rAttrSet.ClearItem(nWhich);
+ }
+
+ if (aIter.IsAtEnd())
+ {
+ break;
+ }
+ pItem = aIter.NextItem();
+ }
+ }
+
+private:
+ SfxItemSet& m_rAttrSet;
+};
+
+
+/** Collects all style-covered spans from i_rHints to o_rSpanMap. In
+ addition inserts dummy spans with pointer to format equal to 0 for
+ all gaps (i.e. spans not covered by any style). This simplifies
+ creation of autostyles for all needed spans, but it means all code
+ that tries to access the pointer has to check if it's non-null!
+ */
+void
+lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength,
+ AttrSpanMap_t& o_rSpanMap)
+{
+ sal_uInt16 nLastEnd(0);
+
+ for (sal_uInt16 i(0); i != i_rHints.Count(); ++i)
+ {
+ const SwTxtAttr* const pHint(i_rHints[i]);
+ const sal_uInt16 nWhich(pHint->Which());
+ if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
+ {
+ const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->GetEnd());
+ o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
+
+ if (aSpan.first != nLastEnd)
+ {
+ // insert dummy span covering the gap
+ o_rSpanMap.insert(AttrSpanMap_t::value_type(
+ AttrSpan_t(nLastEnd, aSpan.first), 0));
+ }
+
+ nLastEnd = aSpan.second;
+ }
+ }
+
+ // no hints at the end (special case: no hints at all in i_rHints)
+ if (nLastEnd != nLength && nLength != 0)
+ {
+ o_rSpanMap.insert(
+ AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), 0));
+ }
+}
+
+
+void
+lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
+{
+ o_rClearIds.reserve(i_rAttrSet.Count());
+ SfxItemIter aIter(i_rAttrSet);
+ const SfxPoolItem* pItem(aIter.GetCurItem());
+ while (pItem)
+ {
+ o_rClearIds.push_back(pItem->Which());
+
+ if (aIter.IsAtEnd())
+ {
+ break;
+ }
+ pItem = aIter.NextItem();
+ }
+}
+
+struct SfxItemSetClearer
+{
+ SfxItemSet & m_rItemSet;
+ SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
+ void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
+};
+
+}
+
+
+/** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion
+ of items to automatic styles.
+ */
+void
+SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
+{
+ typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
+ AttrSpanMap_t aAttrSpanMap;
+
+ if (i_rAttrSet.Count() == 0)
+ {
+ return;
+ }
+
+ // 1. Identify all spans in hints' array
+
+ lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap);
+
+ // 2. Go through all spans and insert new attrs
+
+ AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
+ const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
+ while (aCurRange != aEnd)
+ {
+ typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
+ AttrSpanMapRange_t;
+ AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
+
+ // 2a. Collect attributes to insert
+
+ SfxItemSet aCurSet(i_rAttrSet);
+ std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
+
+ // 2b. Insert automatic style containing the collected attributes
+
+ if (aCurSet.Count() != 0)
+ {
+ AttrSpanMap_iterator_t aAutoStyleIt(
+ std::find_if(aRange.first, aRange.second, IsAutoStyle()));
+ if (aAutoStyleIt != aRange.second)
+ {
+ // there already is an automatic style on that span:
+ // create new one and remove the original one
+ SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second));
+ const boost::shared_ptr<SfxItemSet> pOldStyle(
+ static_cast<const SwFmtAutoFmt&>(
+ pAutoStyle->GetAttr()).GetStyleHandle());
+ aCurSet.Put(*pOldStyle);
+
+ // remove the old hint
+ m_pSwpHints->Delete(pAutoStyle);
+ DestroyAttr(pAutoStyle);
+ }
+ m_pSwpHints->Insert(
+ MakeTxtAttr(*GetDoc(), aCurSet,
+ aCurRange->first.first, aCurRange->first.second));
+ }
+
+ aCurRange = aRange.second;
+ }
+
+ // 3. Clear items from the node
+ std::vector<sal_uInt16> aClearedIds;
+ lcl_FillWhichIds(i_rAttrSet, aClearedIds);
+ ClearItemsFromAttrSet(aClearedIds);
+}
+
+void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
+{
+ SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
+ if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
+ aThisSet.Put( *GetpSwAttrSet() );
+
+ GetOrCreateSwpHints();
+
+ if( pNd == this )
+ {
+ impl_FmtToTxtAttr(aThisSet);
+ }
+ else
+ {
+ // There are five possible combinations of items from this and
+ // pNd (pNd is the 'main' node):
+ //
+ // case pNd this action
+ // ----------------------------------------------------
+ // 1 - - do nothing
+ // 2 - a convert item to attr of this
+ // 3 a - convert item to attr of pNd
+ // 4 a a clear item in this
+ // 5 a b convert item to attr of this
+
+ SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
+ if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
+ aNdSet.Put( *pNd->GetpSwAttrSet() );
+
+ pNd->GetOrCreateSwpHints();
+
+ std::vector<sal_uInt16> aProcessedIds;
+
+ if( aThisSet.Count() )
+ {
+ SfxItemIter aIter( aThisSet );
+ const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
+ SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
+ std::vector<sal_uInt16> aClearWhichIds;
+
+ while( true )
+ {
+ if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) )
+ {
+ if (*pItem == *pNdItem) // 4
+ {
+ aClearWhichIds.push_back( pItem->Which() );
+ }
+ else // 5
+ {
+ aConvertSet.Put(*pItem);
+ }
+ aProcessedIds.push_back(pItem->Which());
+ }
+ else // 2
+ {
+ aConvertSet.Put(*pItem);
+ }
+
+ if( aIter.IsAtEnd() )
+ break;
+ pItem = aIter.NextItem();
+ }
+
+ // 4/ clear items of this that are set with the same value on pNd
+ ClearItemsFromAttrSet( aClearWhichIds );
+
+ // 2, 5/ convert all other items to attrs
+ impl_FmtToTxtAttr(aConvertSet);
+ }
+
+ {
+ std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
+ SfxItemSetClearer(aNdSet));
+
+ // 3/ convert items to attrs
+ pNd->impl_FmtToTxtAttr(aNdSet);
+
+ if( aNdSet.Count() )
+ {
+ SwFmtChg aTmp1( pNd->GetFmtColl() );
+ pNd->NotifyClients( &aTmp1, &aTmp1 );
+ }
+ }
+ }
+
+ SetCalcHiddenCharFlags();
+
+ pNd->TryDeleteSwpHints();
+}
+
+/*************************************************************************
+ * SwpHints::CalcFlags()
+ *************************************************************************/
+
+void SwpHints::CalcFlags()
+{
+ m_bDDEFields = m_bFootnote = false;
+ const sal_uInt16 nSize = Count();
+ const SwTxtAttr* pAttr;
+ for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
+ {
+ switch( ( pAttr = (*this)[ nPos ])->Which() )
+ {
+ case RES_TXTATR_FTN:
+ m_bFootnote = true;
+ if ( m_bDDEFields )
+ return;
+ break;
+ case RES_TXTATR_FIELD:
+ {
+ const SwField* pFld = pAttr->GetFld().GetFld();
+ if( RES_DDEFLD == pFld->GetTyp()->Which() )
+ {
+ m_bDDEFields = true;
+ if ( m_bFootnote )
+ return;
+ }
+ }
+ break;
+ }
+ }
+}
+
+/*************************************************************************
+ * SwpHints::CalcVisibleFlag()
+ *************************************************************************/
+
+bool SwpHints::CalcHiddenParaField()
+{
+ m_bCalcHiddenParaField = false;
+ bool bOldHasHiddenParaField = m_bHasHiddenParaField;
+ bool bNewHasHiddenParaField = false;
+ const sal_uInt16 nSize = Count();
+ const SwTxtAttr *pTxtHt;
+
+ for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
+ {
+ pTxtHt = (*this)[ nPos ];
+ const sal_uInt16 nWhich = pTxtHt->Which();
+
+ if( RES_TXTATR_FIELD == nWhich )
+ {
+ const SwFmtFld& rFld = pTxtHt->GetFld();
+ if( RES_HIDDENPARAFLD == rFld.GetFld()->GetTyp()->Which() )
+ {
+ if( !((SwHiddenParaField*)rFld.GetFld())->IsHidden() )
+ {
+ SetHiddenParaField(false);
+ return bOldHasHiddenParaField != bNewHasHiddenParaField;
+ }
+ else
+ {
+ bNewHasHiddenParaField = true;
+ }
+ }
+ }
+ }
+ SetHiddenParaField( bNewHasHiddenParaField );
+ return bOldHasHiddenParaField != bNewHasHiddenParaField;
+}
+
+
+/*************************************************************************
+ * SwpHints::NoteInHistory()
+ *************************************************************************/
+
+void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
+{
+ if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
+}
+
+/*************************************************************************
+ * SwpHints::MergePortions( )
+ *************************************************************************/
+
+bool SwpHints::MergePortions( SwTxtNode& rNode )
+{
+ if ( !Count() )
+ return false;
+
+ // sort before merging
+ SwpHintsArray::Resort();
+
+ bool bRet = false;
+ typedef std::multimap< int, SwTxtAttr* > PortionMap;
+ PortionMap aPortionMap;
+ xub_StrLen nLastPorStart = STRING_LEN;
+ sal_uInt16 i = 0;
+ int nKey = 0;
+
+ // get portions by start position:
+ for ( i = 0; i < Count(); ++i )
+ {
+ SwTxtAttr *pHt = GetTextHint( i );
+ if ( RES_TXTATR_CHARFMT != pHt->Which() &&
+ RES_TXTATR_AUTOFMT != pHt->Which() )
+ //&&
+ //RES_TXTATR_INETFMT != pHt->Which() )
+ continue;
+
+ const xub_StrLen nPorStart = *pHt->GetStart();
+ if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
+ ++nKey;
+ nLastPorStart = nPorStart;
+ aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
+ }
+
+ // check if portion i can be merged with portion i+1:
+ i = 0;
+ int j = i + 1;
+ while ( i <= nKey )
+ {
+ std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
+ std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
+ PortionMap::iterator aIter1 = aRange1.first;
+ PortionMap::iterator aIter2 = aRange2.first;
+
+ bool bMerge = true;
+ const sal_uInt16 nAttributesInPor1 = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
+ const sal_uInt16 nAttributesInPor2 = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
+
+ if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
+ {
+ while ( aIter1 != aRange1.second )
+ {
+ const SwTxtAttr* p1 = (*aIter1).second;
+ const SwTxtAttr* p2 = (*aIter2).second;
+ if ( *p1->GetEnd() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
+ {
+ bMerge = false;
+ break;
+ }
+ ++aIter1;
+ ++aIter2;
+ }
+ }
+ else
+ {
+ bMerge = false;
+ }
+
+ if ( bMerge )
+ {
+ // erase all elements with key i + 1
+ xub_StrLen nNewPortionEnd = 0;
+ for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
+ {
+ SwTxtAttr* p2 = (*aIter2).second;
+ nNewPortionEnd = *p2->GetEnd();
+
+ const sal_uInt16 nCountBeforeDelete = Count();
+ Delete( p2 );
+
+ // robust: check if deletion actually took place before destroying attribute:
+ if ( Count() < nCountBeforeDelete )
+ rNode.DestroyAttr( p2 );
+ }
+ aPortionMap.erase( aRange2.first, aRange2.second );
+ ++j;
+
+ // change all attributes with key i
+ aRange1 = aPortionMap.equal_range( i );
+ for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
+ {
+ SwTxtAttr* p1 = (*aIter1).second;
+ NoteInHistory( p1 );
+ *p1->GetEnd() = nNewPortionEnd;
+ NoteInHistory( p1, true );
+ bRet = true;
+ }
+ }
+ else
+ {
+ ++i;
+ j = i + 1;
+ }
+ }
+
+ if ( bRet )
+ {
+ SwpHintsArray::Resort();
+ }
+
+ return bRet;
+}
+
+// check if there is already a character format and adjust the sort numbers
+void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
+{
+ const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
+ const xub_StrLen nHtEnd = *rNewCharFmt.GetEnd();
+ sal_uInt16 nSortNumber = 0;
+
+ for ( sal_uInt16 i = 0; i < rHints.Count(); ++i )
+ {
+ const SwTxtAttr* pOtherHt = rHints[i];
+
+ const xub_StrLen nOtherStart = *pOtherHt->GetStart();
+
+ if ( nOtherStart > nHtStart )
+ break;
+
+ if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
+ {
+ const xub_StrLen nOtherEnd = *pOtherHt->GetEnd();
+
+ if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
+ {
+ const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber();
+ nSortNumber = nOtherSortNum + 1;
+ }
+ }
+ }
+
+ if ( nSortNumber > 0 )
+ rNewCharFmt.SetSortNumber( nSortNumber );
+}
+
+/*************************************************************************
+ * SwpHints::Insert()
+ *************************************************************************/
+
+/*
+ * Try to insert the new hint.
+ * Depending on the type of the hint, this either always succeeds, or may fail.
+ * Depending on the type of the hint, other hints may be deleted or
+ * overwritten.
+ * The return value indicates successful insertion.
+ */
+bool SwpHints::TryInsertHint( SwTxtAttr* const pHint, SwTxtNode &rNode,
+ const SetAttrMode nMode )
+{
+ if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked...
+ {
+ OSL_FAIL("hints array full :-(");
+ return false;
+ }
+
+ // Felder bilden eine Ausnahme:
+ // 1) Sie koennen nie ueberlappen
+ // 2) Wenn zwei Felder genau aneinander liegen,
+ // sollen sie nicht zu einem verschmolzen werden.
+ // Wir koennen also auf die while-Schleife verzichten
+
+ xub_StrLen *pHtEnd = pHint->GetEnd();
+ sal_uInt16 nWhich = pHint->Which();
+
+ switch( nWhich )
+ {
+ case RES_TXTATR_CHARFMT:
+ {
+ // Check if character format contains hidden attribute:
+ const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
+ const SfxPoolItem* pItem;
+ if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
+ rNode.SetCalcHiddenCharFlags();
+
+ ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
+ break;
+ }
+ // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary
+ case RES_TXTATR_AUTOFMT:
+ {
+ // Check if auto style contains hidden attribute:
+ const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
+ if ( pHiddenItem )
+ rNode.SetCalcHiddenCharFlags();
+ break;
+ }
+ // <--
+ case RES_TXTATR_INETFMT:
+ static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
+ break;
+ case RES_TXTATR_FIELD:
+ {
+ sal_Bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
+ ((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
+ SwDoc* pDoc = rNode.GetDoc();
+ const SwField* pFld = ((SwTxtFld*)pHint)->GetFld().GetFld();
+
+ if( !pDoc->IsNewFldLst() )
+ {
+ // was fuer ein Feld ist es denn ??
+ // bestimmte Felder mussen am Doc das Calculations-Flag updaten
+ switch( pFld->GetTyp()->Which() )
+ {
+ case RES_DBFLD:
+ case RES_SETEXPFLD:
+ case RES_HIDDENPARAFLD:
+ case RES_HIDDENTXTFLD:
+ case RES_DBNUMSETFLD:
+ case RES_DBNEXTSETFLD:
+ {
+ if( bDelFirst )
+ pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pHint );
+ if( rNode.GetNodes().IsDocNodes() )
+ pDoc->InsDelFldInFldLst( sal_True, *(SwTxtFld*)pHint );
+ }
+ break;
+ case RES_DDEFLD:
+ if( rNode.GetNodes().IsDocNodes() )
+ ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
+ break;
+ }
+ }
+
+ // gehts ins normale Nodes-Array?
+ if( rNode.GetNodes().IsDocNodes() )
+ {
+ sal_Bool bInsFldType = sal_False;
+ switch( pFld->GetTyp()->Which() )
+ {
+ case RES_SETEXPFLD:
+ bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
+ if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
+ {
+ // bevor die ReferenzNummer gesetzt wird, sollte
+ // das Feld am richtigen FeldTypen haengen!
+ SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
+ pDoc->InsertFldType( *pFld->GetTyp() );
+ if( pFldType != pFld->GetTyp() )
+ {
+ SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)
+ ->GetFld();
+ pFmtFld->RegisterToFieldType( *pFldType );
+ pFmtFld->GetFld()->ChgTyp( pFldType );
+ }
+ pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
+ }
+ break;
+ case RES_USERFLD:
+ bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
+ break;
+
+ case RES_DDEFLD:
+ if( pDoc->IsNewFldLst() )
+ ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
+ bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
+ break;
+
+ case RES_POSTITFLD:
+ if ( pDoc->GetDocShell() )
+ pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_INSERTED ) );
+ break;
+ }
+ if( bInsFldType )
+ pDoc->InsDeletedFldType( *pFld->GetTyp() );
+ }
+ }
+ break;
+ case RES_TXTATR_FTN :
+ ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
+ break;
+ case RES_TXTATR_REFMARK:
+ ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
+ if( rNode.GetNodes().IsDocNodes() )
+ {
+ // search for a reference with the same name
+ SwTxtAttr* pTmpHt;
+ xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
+ for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n )
+ {
+ if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
+ pHint->GetAttr() == pTmpHt->GetAttr() &&
+ 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
+ 0 != ( pTmpHintEnd = pHint->GetEnd() ) )
+ {
+ SwComparePosition eCmp = ::ComparePosition(
+ *pTmpHt->GetStart(), *pTmpHtEnd,
+ *pHint->GetStart(), *pTmpHintEnd );
+ sal_Bool bDelOld = sal_True, bChgStart = sal_False, bChgEnd = sal_False;
+ switch( eCmp )
+ {
+ case POS_BEFORE:
+ case POS_BEHIND: bDelOld = sal_False; break;
+
+ case POS_OUTSIDE: bChgStart = bChgEnd = sal_True; break;
+
+ case POS_COLLIDE_END:
+ case POS_OVERLAP_BEFORE: bChgStart = sal_True; break;
+ case POS_COLLIDE_START:
+ case POS_OVERLAP_BEHIND: bChgEnd = sal_True; break;
+ default: break;
+ }
+
+ if( bChgStart )
+ *pHint->GetStart() = *pTmpHt->GetStart();
+ if( bChgEnd )
+ *pTmpHintEnd = *pTmpHtEnd;
+
+ if( bDelOld )
+ {
+ NoteInHistory( pTmpHt );
+ rNode.DestroyAttr( Cut( n-- ) );
+ --nEnd;
+ }
+ }
+ }
+ }
+ break;
+ case RES_TXTATR_TOXMARK:
+ ((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
+ break;
+
+ case RES_TXTATR_CJK_RUBY:
+ static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode);
+ break;
+
+ case RES_TXTATR_META:
+ case RES_TXTATR_METAFIELD:
+ static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode );
+ break;
+
+ case RES_CHRATR_HIDDEN:
+ rNode.SetCalcHiddenCharFlags();
+ break;
+ }
+
+ if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
+ pHint->SetDontExpand( sal_True );
+
+ // SwTxtAttrs ohne Ende werden sonderbehandelt:
+ // Sie werden natuerlich in das Array insertet, aber sie werden nicht
+ // in die pPrev/Next/On/Off-Verkettung aufgenommen.
+ // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
+ xub_StrLen nHtStart = *pHint->GetStart();
+ if( !pHtEnd )
+ {
+ SwpHintsArray::Insert( pHint );
+ CalcFlags();
+#if OSL_DEBUG_LEVEL > 1
+ if( !rNode.GetDoc()->IsInReading() )
+ CHECK;
+#endif
+ // ... und die Abhaengigen benachrichtigen
+ if ( rNode.GetDepends() )
+ {
+ SwUpdateAttr aHint( nHtStart, nHtStart, nWhich );
+ rNode.ModifyNotification( 0, &aHint );
+ }
+ return true;
+ }
+
+ // ----------------------------------------------------------------
+ // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
+
+ if( *pHtEnd < nHtStart )
+ {
+ OSL_ENSURE( *pHtEnd >= nHtStart,
+ "+SwpHints::Insert: invalid hint, end < start" );
+
+ // Wir drehen den Quatsch einfach um:
+ *pHint->GetStart() = *pHtEnd;
+ *pHtEnd = nHtStart;
+ nHtStart = *pHint->GetStart();
+ }
+
+ // I need this value later on for notification but the pointer may become invalid
+ const xub_StrLen nHintEnd = *pHtEnd;
+ const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
+
+ // handle nesting attributes: inserting may fail due to overlap!
+ if (pHint->IsNesting())
+ {
+ const bool bRet(
+ TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint)));
+ if (!bRet) return false;
+ }
+ // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
+ // These attributes may be inserted directly.
+ // Also attributes without length may be inserted directly.
+ // SETATTR_NOHINTADJUST is set e.g., during undo.
+ // Portion building in not necessary during XML import.
+ else
+ if ( !bNoHintAdjustMode &&
+ !pHint->IsOverlapAllowedAttr() &&
+ !rNode.GetDoc()->IsInXMLImport() &&
+ ( RES_TXTATR_AUTOFMT == nWhich ||
+ RES_TXTATR_CHARFMT == nWhich ) )
+ {
+ OSL_ENSURE( nWhich != RES_TXTATR_AUTOFMT ||
+ static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
+ &rNode.GetDoc()->GetAttrPool(),
+ "AUTOSTYLES - Pool mismatch" );
+
+ BuildPortions( rNode, *pHint, nMode );
+
+ if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
+ MergePortions( rNode );
+ }
+ else
+ {
+ // There may be more than one character style at the current position.
+ // Take care of the sort number.
+ // Special case ruby portion: During import, the ruby attribute is set
+ // multiple times
+ // Special case hyperlink: During import, the ruby attribute is set
+ // multiple times
+ // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
+ // character attributes directly
+ if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) )
+ {
+ BuildPortions( rNode, *pHint, nMode );
+ }
+ else
+ {
+ // --> FME 2007-11-08 #i82989# Check sort numbers in NoHintAdjustMode
+ if ( RES_TXTATR_CHARFMT == nWhich )
+ lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
+ // <--
+
+ SwpHintsArray::Insert( pHint );
+ NoteInHistory( pHint, true );
+ }
+ }
+
+ // ... und die Abhaengigen benachrichtigen
+ if ( rNode.GetDepends() )
+ {
+ SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich );
+ rNode.ModifyNotification( 0, &aHint );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
+ CHECK;
+#endif
+
+ return true;
+}
+
+/*************************************************************************
+ * SwpHints::DeleteAtPos()
+ *************************************************************************/
+
+void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
+{
+ SwTxtAttr *pHint = GetTextHint(nPos);
+ // ChainDelete( pHint );
+ NoteInHistory( pHint );
+ SwpHintsArray::DeleteAtPos( nPos );
+
+ if( RES_TXTATR_FIELD == pHint->Which() )
+ {
+ SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFld().GetFld()->GetTyp();
+ if( RES_DDEFLD == pFldTyp->Which() )
+ {
+ const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
+ if( pNd && pNd->GetNodes().IsDocNodes() )
+ ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
+ ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
+ }
+ else if( RES_POSTITFLD == pFldTyp->Which() )
+ {
+ const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_REMOVED ) );
+ }
+ else if ( m_bHasHiddenParaField &&
+ RES_HIDDENPARAFLD == pFldTyp->Which() )
+ {
+ m_bCalcHiddenParaField = true;
+ }
+ }
+
+ CalcFlags();
+ CHECK;
+}
+
+// Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
+// Ist er nicht im Array, so gibt es ein OSL_ENSURE(!!
+
+void SwpHints::Delete( SwTxtAttr* pTxtHt )
+{
+ // Attr 2.0: SwpHintsArr::Delete( pTxtHt );
+ const sal_uInt16 nPos = GetStartOf( pTxtHt );
+ OSL_ENSURE( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
+ if( USHRT_MAX != nPos )
+ DeleteAtPos( nPos );
+}
+
+void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
+{
+ if ( HasHints() )
+ {
+ sal_uInt16 nPos = 0;
+ while ( nPos < m_pSwpHints->Count() )
+ {
+ SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
+ bool bDel = false;
+
+ switch( pDel->Which() )
+ {
+ case RES_TXTATR_FLYCNT:
+ case RES_TXTATR_FTN:
+ break;
+
+ case RES_TXTATR_FIELD:
+ if( bDelFields )
+ bDel = true;
+ break;
+ default:
+ bDel = true; break;
+ }
+
+ if( bDel )
+ {
+ m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
+ DestroyAttr( pDel );
+ }
+ else
+ ++nPos;
+ }
+ }
+}
+
+sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
+ sal_uInt16 nScript ) const
+{
+ sal_uInt16 nRet = LANGUAGE_DONTKNOW;
+
+ if ( ! nScript )
+ {
+ nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
+ }
+
+ // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0
+ const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
+ // <--
+
+ if ( HasHints() )
+ {
+ const xub_StrLen nEnd = nBegin + nLen;
+ for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
+ {
+ // ist der Attribut-Anfang schon groesser als der Idx ?
+ const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
+ const xub_StrLen nAttrStart = *pHt->GetStart();
+ if( nEnd < nAttrStart )
+ break;
+
+ const sal_uInt16 nWhich = pHt->Which();
+
+ if( nWhichId == nWhich ||
+ ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
+ {
+ const xub_StrLen *pEndIdx = pHt->GetEnd();
+ // Ueberlappt das Attribut den Bereich?
+
+ if( pEndIdx &&
+ nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
+ : (( nAttrStart < nBegin &&
+ ( pHt->DontExpand() ? nBegin < *pEndIdx
+ : nBegin <= *pEndIdx )) ||
+ ( nBegin == nAttrStart &&
+ ( nAttrStart == *pEndIdx || !nBegin ))) )
+ {
+ const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
+ sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
+
+ // Umfasst das Attribut den Bereich komplett?
+ if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
+ nRet = nLng;
+ else if( LANGUAGE_DONTKNOW == nRet )
+ nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
+ }
+ }
+ }
+ }
+ if( LANGUAGE_DONTKNOW == nRet )
+ {
+ nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
+ if( LANGUAGE_DONTKNOW == nRet )
+ nRet = static_cast<sal_uInt16>(GetAppLanguage());
+ }
+ return nRet;
+}
+
+
+sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
+{
+ sal_Unicode cRet = CH_TXTATR_BREAKWORD;
+ switch ( rAttr.Which() )
+ {
+ case RES_TXTATR_FTN:
+ case RES_TXTATR_REFMARK:
+ case RES_TXTATR_TOXMARK:
+ case RES_TXTATR_META:
+ case RES_TXTATR_METAFIELD:
+ cRet = CH_TXTATR_INWORD;
+ break;
+
+ case RES_TXTATR_FIELD:
+ case RES_TXTATR_FLYCNT:
+ {
+ cRet = CH_TXTATR_BREAKWORD;
+
+ // #i78149: PostIt fields should not break words for spell and grammar checking
+ if (rAttr.Which() == RES_TXTATR_FIELD &&
+ RES_POSTITFLD == rAttr.GetFld().GetFld()->GetTyp()->Which())
+ cRet = CH_TXTATR_INWORD;
+ }
+ break;
+
+ default:
+ OSL_FAIL("GetCharOfTxtAttr: unknown attr");
+ break;
+ }
+ return cRet;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/txatbase.cxx b/sw/source/core/txtnode/txatbase.cxx
new file mode 100644
index 000000000000..ae370d5afe42
--- /dev/null
+++ b/sw/source/core/txtnode/txatbase.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <svl/itempool.hxx>
+#include <txatbase.hxx>
+#include <fmtfld.hxx>
+#include <docufld.hxx>
+
+SwTxtAttr::SwTxtAttr( SfxPoolItem& rAttr, xub_StrLen nStart )
+ : m_pAttr( &rAttr )
+ , m_nStart( nStart )
+ , m_bDontExpand( false )
+ , m_bLockExpandFlag( false )
+ , m_bDontMoveAttr( false )
+ , m_bCharFmtAttr( false )
+ , m_bOverlapAllowedAttr( false )
+ , m_bPriorityAttr( false )
+ , m_bDontExpandStart( false )
+ , m_bNesting( false )
+ , m_bHasDummyChar( false )
+{
+}
+
+SwTxtAttr::~SwTxtAttr( )
+{
+}
+
+xub_StrLen* SwTxtAttr::GetEnd()
+{
+ return 0;
+}
+
+void SwTxtAttr::Destroy( SwTxtAttr * pToDestroy, SfxItemPool& rPool )
+{
+ if (!pToDestroy) return;
+ SfxPoolItem * const pAttr = pToDestroy->m_pAttr;
+ delete pToDestroy;
+ rPool.Remove( *pAttr );
+}
+
+int SwTxtAttr::operator==( const SwTxtAttr& rAttr ) const
+{
+ return GetAttr() == rAttr.GetAttr();
+}
+
+SwTxtAttrEnd::SwTxtAttrEnd( SfxPoolItem& rAttr,
+ xub_StrLen nStart, xub_StrLen nEnd ) :
+ SwTxtAttr( rAttr, nStart ), m_nEnd( nEnd )
+{
+}
+
+xub_StrLen* SwTxtAttrEnd::GetEnd()
+{
+ return & m_nEnd;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/txatritr.cxx b/sw/source/core/txtnode/txatritr.cxx
new file mode 100644
index 000000000000..5bbab28687ce
--- /dev/null
+++ b/sw/source/core/txtnode/txatritr.cxx
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <hintids.hxx>
+
+#include <com/sun/star/i18n/ScriptType.hdl>
+#include <tools/string.hxx>
+#include <editeng/langitem.hxx>
+#include <txatritr.hxx>
+#include <fchrfmt.hxx>
+#include <charfmt.hxx>
+#include <breakit.hxx>
+#include <ndtxt.hxx>
+#include <txatbase.hxx>
+
+using namespace ::com::sun::star::i18n;
+
+
+SwScriptIterator::SwScriptIterator( const String& rStr, xub_StrLen nStt, sal_Bool bFrwrd )
+ : rText( rStr ),
+ nChgPos( rStr.Len() ),
+ nCurScript( ScriptType::WEAK ),
+ bForward( bFrwrd )
+{
+ if( pBreakIt->GetBreakIter().is() )
+ {
+ if ( ! bFrwrd && nStt )
+ --nStt;
+
+ xub_StrLen nPos = nStt;
+ nCurScript = pBreakIt->GetBreakIter()->getScriptType( rText, nPos );
+ if( ScriptType::WEAK == nCurScript )
+ {
+ if( nPos )
+ {
+ nPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfScript(
+ rText, nPos, nCurScript );
+ if( nPos && nPos < rText.Len() )
+ {
+ nStt = --nPos;
+ nCurScript = pBreakIt->GetBreakIter()->getScriptType( rText,nPos);
+ }
+ }
+ }
+
+ nChgPos = bForward ?
+ (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( rText, nStt, nCurScript ) :
+ (xub_StrLen)pBreakIt->GetBreakIter()->beginOfScript( rText, nStt, nCurScript );
+ }
+}
+
+sal_Bool SwScriptIterator::Next()
+{
+ sal_Bool bRet = sal_False;
+ if( pBreakIt->GetBreakIter().is() )
+ {
+ if ( bForward && nChgPos < rText.Len() )
+ {
+ nCurScript = pBreakIt->GetBreakIter()->getScriptType( rText, nChgPos );
+ nChgPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(
+ rText, nChgPos, nCurScript );
+ bRet = sal_True;
+ }
+ else if ( ! bForward && nChgPos )
+ {
+ --nChgPos;
+ nCurScript = pBreakIt->GetBreakIter()->getScriptType( rText, nChgPos );
+ nChgPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfScript(
+ rText, nChgPos, nCurScript );
+ bRet = sal_True;
+ }
+ }
+ else
+ nChgPos = rText.Len();
+ return bRet;
+}
+
+// --------------------------------------------------------------------
+
+SwTxtAttrIterator::SwTxtAttrIterator( const SwTxtNode& rTNd, sal_uInt16 nWhchId,
+ xub_StrLen nStt,
+ sal_Bool bUseGetWhichOfScript )
+ : aSIter( rTNd.GetTxt(), nStt ), rTxtNd( rTNd ),
+ pParaItem( 0 ), nChgPos( nStt ), nAttrPos( 0 ), nWhichId( nWhchId ),
+ bIsUseGetWhichOfScript( bUseGetWhichOfScript )
+{
+ SearchNextChg();
+}
+
+sal_Bool SwTxtAttrIterator::Next()
+{
+ sal_Bool bRet = sal_False;
+ if( nChgPos < aSIter.GetText().Len() )
+ {
+ bRet = sal_True;
+ if( aStack.Count() )
+ {
+ do {
+ const SwTxtAttr* pHt = (SwTxtAttr*)aStack[ 0 ];
+ sal_uInt16 nEndPos = *pHt->GetEnd();
+ if( nChgPos >= nEndPos )
+ aStack.Remove( 0 );
+ else
+ break;
+ } while( aStack.Count() );
+ }
+
+ if( aStack.Count() )
+ {
+ sal_uInt16 nSavePos = nAttrPos;
+ SearchNextChg();
+ if( aStack.Count() )
+ {
+ const SwTxtAttr* pHt = (SwTxtAttr*)aStack[ 0 ];
+ sal_uInt16 nEndPos = *pHt->GetEnd();
+ if( nChgPos >= nEndPos )
+ {
+ nChgPos = nEndPos;
+ nAttrPos = nSavePos;
+
+ if( RES_TXTATR_CHARFMT == pHt->Which() )
+ {
+ sal_uInt16 nWId = bIsUseGetWhichOfScript ?
+ GetWhichOfScript( nWhichId,
+ aSIter.GetCurrScript() ) : nWhichId;
+ pCurItem = &pHt->GetCharFmt().GetCharFmt()->GetFmtAttr(nWId);
+ }
+ else
+ pCurItem = &pHt->GetAttr();
+
+ aStack.Remove( 0 );
+ }
+ }
+ }
+ else
+ SearchNextChg();
+ }
+ return bRet;
+}
+
+void SwTxtAttrIterator::AddToStack( const SwTxtAttr& rAttr )
+{
+ void* pAdd = (void*)&rAttr;
+ sal_uInt16 nIns = 0, nEndPos = *rAttr.GetEnd();
+ for( ; nIns < aStack.Count(); ++nIns )
+ if( *((SwTxtAttr*)aStack[ nIns ] )->GetEnd() > nEndPos )
+ break;
+
+ aStack.Insert( pAdd, nIns );
+}
+
+void SwTxtAttrIterator::SearchNextChg()
+{
+ sal_uInt16 nWh = 0;
+ if( nChgPos == aSIter.GetScriptChgPos() )
+ {
+ aSIter.Next();
+ pParaItem = 0;
+ nAttrPos = 0; // must be restart at the beginning, because
+ // some attributes can start before or inside
+ // the current scripttype!
+ aStack.Remove( 0, aStack.Count() );
+ }
+ if( !pParaItem )
+ {
+ nWh = bIsUseGetWhichOfScript ?
+ GetWhichOfScript( nWhichId,
+ aSIter.GetCurrScript() ) : nWhichId;
+ pParaItem = &rTxtNd.GetSwAttrSet().Get( nWh );
+ }
+
+ xub_StrLen nStt = nChgPos;
+ nChgPos = aSIter.GetScriptChgPos();
+ pCurItem = pParaItem;
+
+ const SwpHints* pHts = rTxtNd.GetpSwpHints();
+ if( pHts )
+ {
+ if( !nWh )
+ {
+ nWh = bIsUseGetWhichOfScript ?
+ GetWhichOfScript( nWhichId,
+ aSIter.GetCurrScript() ) : nWhichId;
+ }
+
+ const SfxPoolItem* pItem = 0;
+ for( ; nAttrPos < pHts->Count(); ++nAttrPos )
+ {
+ const SwTxtAttr* pHt = (*pHts)[ nAttrPos ];
+ const sal_uInt16* pEnd = pHt->GetEnd();
+ const sal_uInt16 nHtStt = *pHt->GetStart();
+ if( nHtStt < nStt && ( !pEnd || *pEnd <= nStt ))
+ continue;
+
+ if( nHtStt >= nChgPos )
+ break;
+
+ pItem = CharFmt::GetItem( *pHt, nWh );
+ if ( pItem )
+ {
+ if( nHtStt > nStt )
+ {
+ if( nChgPos > nHtStt )
+ nChgPos = nHtStt;
+ break;
+ }
+ AddToStack( *pHt );
+ pCurItem = pItem;
+ if( *pEnd < nChgPos )
+ nChgPos = *pEnd;
+ }
+ }
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/txtatr2.cxx b/sw/source/core/txtnode/txtatr2.cxx
new file mode 100644
index 000000000000..5db0ab4b6f4a
--- /dev/null
+++ b/sw/source/core/txtnode/txtatr2.cxx
@@ -0,0 +1,353 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include <hintids.hxx>
+#include <hints.hxx>
+#include <sfx2/objsh.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <editeng/twolinesitem.hxx>
+#include <txtinet.hxx>
+#include <txtatr.hxx>
+#include <fchrfmt.hxx>
+#include <fmtinfmt.hxx>
+#include <charfmt.hxx>
+#include <ndtxt.hxx> // SwCharFmt, SwTxtNode
+#include <poolfmt.hxx> // RES_POOLCHR_INET_...
+#include <doc.hxx> // SwDoc
+#include <fmtruby.hxx>
+#include <fmtmeta.hxx>
+
+
+TYPEINIT1(SwTxtINetFmt,SwClient);
+TYPEINIT1(SwTxtRuby,SwClient);
+
+
+/*************************************************************************
+ * class SwTxtCharFmt
+ *************************************************************************/
+
+SwTxtCharFmt::SwTxtCharFmt( SwFmtCharFmt& rAttr,
+ xub_StrLen nStt, xub_StrLen nEnde )
+ : SwTxtAttrEnd( rAttr, nStt, nEnde )
+ , m_pTxtNode( 0 )
+ , m_nSortNumber( 0 )
+{
+ rAttr.pTxtAttr = this;
+ SetCharFmtAttr( sal_True );
+}
+
+SwTxtCharFmt::~SwTxtCharFmt( )
+{
+}
+
+void SwTxtCharFmt::ModifyNotification( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
+{
+ sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
+ OSL_ENSURE( isCHRATR(nWhich) || (RES_OBJECTDYING == nWhich)
+ || (RES_ATTRSET_CHG == nWhich) || (RES_FMT_CHG == nWhich),
+ "SwTxtCharFmt::Modify(): unknown Modify");
+
+ if ( m_pTxtNode )
+ {
+ SwUpdateAttr aUpdateAttr( *GetStart(), *GetEnd(), nWhich );
+ m_pTxtNode->ModifyNotification( &aUpdateAttr, &aUpdateAttr );
+ }
+}
+
+bool SwTxtCharFmt::GetInfo( SfxPoolItem& rInfo ) const
+{
+ if ( RES_AUTOFMT_DOCNODE != rInfo.Which() || !m_pTxtNode ||
+ &m_pTxtNode->GetNodes() != static_cast<SwAutoFmtGetDocNode&>(rInfo).pNodes )
+ {
+ return true;
+ }
+
+ static_cast<SwAutoFmtGetDocNode&>(rInfo).pCntntNode = m_pTxtNode;
+ return false;
+}
+
+
+/*************************************************************************
+ * class SwTxtAttrNesting
+ *************************************************************************/
+
+SwTxtAttrNesting::SwTxtAttrNesting( SfxPoolItem & i_rAttr,
+ const xub_StrLen i_nStart, const xub_StrLen i_nEnd )
+ : SwTxtAttrEnd( i_rAttr, i_nStart, i_nEnd )
+{
+ SetDontExpand( true ); // never expand this attribute
+ // lock the expand flag: simple guarantee that nesting will not be
+ // invalidated by expand operations
+ SetLockExpandFlag( true );
+ SetDontExpandStartAttr( true );
+ SetNesting( true );
+}
+
+SwTxtAttrNesting::~SwTxtAttrNesting()
+{
+}
+
+
+/*************************************************************************
+ * class SwTxtINetFmt
+ *************************************************************************/
+
+SwTxtINetFmt::SwTxtINetFmt( SwFmtINetFmt& rAttr,
+ xub_StrLen nStart, xub_StrLen nEnd )
+ : SwTxtAttrNesting( rAttr, nStart, nEnd )
+ , SwClient( 0 )
+ , m_pTxtNode( 0 )
+ , m_bVisited( false )
+ , m_bVisitedValid( false )
+{
+ rAttr.pTxtAttr = this;
+ SetCharFmtAttr( true );
+}
+
+SwTxtINetFmt::~SwTxtINetFmt( )
+{
+}
+
+SwCharFmt* SwTxtINetFmt::GetCharFmt()
+{
+ const SwFmtINetFmt& rFmt = SwTxtAttrEnd::GetINetFmt();
+ SwCharFmt* pRet = NULL;
+
+ if( rFmt.GetValue().Len() )
+ {
+ const SwDoc* pDoc = GetTxtNode().GetDoc();
+ if( !IsVisitedValid() )
+ {
+ SetVisited( pDoc->IsVisitedURL( rFmt.GetValue() ) );
+ SetVisitedValid( true );
+ }
+ sal_uInt16 nId;
+ const String& rStr = IsVisited() ? rFmt.GetVisitedFmt()
+ : rFmt.GetINetFmt();
+ if( rStr.Len() )
+ nId = IsVisited() ? rFmt.GetVisitedFmtId() : rFmt.GetINetFmtId();
+ else
+ nId = static_cast<sal_uInt16>(IsVisited() ? RES_POOLCHR_INET_VISIT : RES_POOLCHR_INET_NORMAL);
+
+ // JP 10.02.2000, Bug 72806: dont modify the doc for getting the
+ // correct charstyle.
+ sal_Bool bResetMod = !pDoc->IsModified();
+ Link aOle2Lnk;
+ if( bResetMod )
+ {
+ aOle2Lnk = pDoc->GetOle2Link();
+ ((SwDoc*)pDoc)->SetOle2Link( Link() );
+ }
+
+ pRet = IsPoolUserFmt( nId )
+ ? ((SwDoc*)pDoc)->FindCharFmtByName( rStr )
+ : ((SwDoc*)pDoc)->GetCharFmtFromPool( nId );
+
+ if( bResetMod )
+ {
+ ((SwDoc*)pDoc)->ResetModified();
+ ((SwDoc*)pDoc)->SetOle2Link( aOle2Lnk );
+ }
+ }
+
+ if( pRet )
+ pRet->Add( this );
+ else if( GetRegisteredIn() )
+ GetRegisteredInNonConst()->Remove( this );
+
+ return pRet;
+}
+
+void SwTxtINetFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
+{
+ sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
+ OSL_ENSURE( isCHRATR(nWhich) || (RES_OBJECTDYING == nWhich)
+ || (RES_ATTRSET_CHG == nWhich) || (RES_FMT_CHG == nWhich),
+ "SwTxtINetFmt::Modify(): unknown Modify");
+
+ if ( m_pTxtNode )
+ {
+ SwUpdateAttr aUpdateAttr( *GetStart(), *GetEnd(), nWhich );
+ m_pTxtNode->ModifyNotification( &aUpdateAttr, &aUpdateAttr );
+ }
+}
+
+ // erfrage vom Modify Informationen
+sal_Bool SwTxtINetFmt::GetInfo( SfxPoolItem& rInfo ) const
+{
+ if ( RES_AUTOFMT_DOCNODE != rInfo.Which() || !m_pTxtNode ||
+ &m_pTxtNode->GetNodes() != static_cast<SwAutoFmtGetDocNode&>(rInfo).pNodes )
+ {
+ return sal_True;
+ }
+
+ static_cast<SwAutoFmtGetDocNode&>(rInfo).pCntntNode = m_pTxtNode;
+ return sal_False;
+}
+
+sal_Bool SwTxtINetFmt::IsProtect( ) const
+{
+ return m_pTxtNode && m_pTxtNode->IsProtect();
+}
+
+/*************************************************************************
+ * class SwTxtRuby
+ *************************************************************************/
+
+SwTxtRuby::SwTxtRuby( SwFmtRuby& rAttr,
+ xub_StrLen nStart, xub_StrLen nEnd )
+ : SwTxtAttrNesting( rAttr, nStart, nEnd )
+ , SwClient( 0 )
+ , m_pTxtNode( 0 )
+{
+ rAttr.pTxtAttr = this;
+}
+
+SwTxtRuby::~SwTxtRuby()
+{
+}
+
+void SwTxtRuby::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
+{
+ sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
+ OSL_ENSURE( isCHRATR(nWhich) || (RES_OBJECTDYING == nWhich)
+ || (RES_ATTRSET_CHG == nWhich) || (RES_FMT_CHG == nWhich),
+ "SwTxtRuby::Modify(): unknown Modify");
+
+ if ( m_pTxtNode )
+ {
+ SwUpdateAttr aUpdateAttr( *GetStart(), *GetEnd(), nWhich );
+ m_pTxtNode->ModifyNotification( &aUpdateAttr, &aUpdateAttr );
+ }
+}
+
+sal_Bool SwTxtRuby::GetInfo( SfxPoolItem& rInfo ) const
+{
+ if( RES_AUTOFMT_DOCNODE != rInfo.Which() || !m_pTxtNode ||
+ &m_pTxtNode->GetNodes() != static_cast<SwAutoFmtGetDocNode&>(rInfo).pNodes )
+ {
+ return sal_True;
+ }
+
+ static_cast<SwAutoFmtGetDocNode&>(rInfo).pCntntNode = m_pTxtNode;
+ return sal_False;
+}
+
+SwCharFmt* SwTxtRuby::GetCharFmt()
+{
+ const SwFmtRuby& rFmt = SwTxtAttrEnd::GetRuby();
+ SwCharFmt* pRet = 0;
+
+ if( rFmt.GetText().Len() )
+ {
+ const SwDoc* pDoc = GetTxtNode().GetDoc();
+ const String& rStr = rFmt.GetCharFmtName();
+ sal_uInt16 nId = RES_POOLCHR_RUBYTEXT;
+ if ( rStr.Len() )
+ nId = rFmt.GetCharFmtId();
+
+ // JP 10.02.2000, Bug 72806: dont modify the doc for getting the
+ // correct charstyle.
+ sal_Bool bResetMod = !pDoc->IsModified();
+ Link aOle2Lnk;
+ if( bResetMod )
+ {
+ aOle2Lnk = pDoc->GetOle2Link();
+ ((SwDoc*)pDoc)->SetOle2Link( Link() );
+ }
+
+ pRet = IsPoolUserFmt( nId )
+ ? ((SwDoc*)pDoc)->FindCharFmtByName( rStr )
+ : ((SwDoc*)pDoc)->GetCharFmtFromPool( nId );
+
+ if( bResetMod )
+ {
+ ((SwDoc*)pDoc)->ResetModified();
+ ((SwDoc*)pDoc)->SetOle2Link( aOle2Lnk );
+ }
+ }
+
+ if( pRet )
+ pRet->Add( this );
+ else if( GetRegisteredIn() )
+ GetRegisteredInNonConst()->Remove( this );
+
+ return pRet;
+}
+
+
+/*************************************************************************
+ * class SwTxtMeta
+ *************************************************************************/
+
+SwTxtMeta *
+SwTxtMeta::CreateTxtMeta(
+ ::sw::MetaFieldManager & i_rTargetDocManager,
+ SwTxtNode *const i_pTargetTxtNode,
+ SwFmtMeta & i_rAttr,
+ xub_StrLen const i_nStart, xub_StrLen const i_nEnd, bool const i_bIsCopy)
+{
+ if (COPY == i_bIsCopy)
+ { // i_rAttr is already cloned, now call DoCopy to copy the sw::Meta
+ OSL_ENSURE(i_pTargetTxtNode, "cannot copy Meta without target node");
+ i_rAttr.DoCopy(i_rTargetDocManager, *i_pTargetTxtNode);
+ }
+ SwTxtMeta *const pTxtMeta(new SwTxtMeta(i_rAttr, i_nStart, i_nEnd));
+ return pTxtMeta;
+}
+
+SwTxtMeta::SwTxtMeta( SwFmtMeta & i_rAttr,
+ const xub_StrLen i_nStart, const xub_StrLen i_nEnd )
+ : SwTxtAttrNesting( i_rAttr, i_nStart, i_nEnd )
+{
+ i_rAttr.SetTxtAttr( this );
+ SetHasDummyChar(true);
+}
+
+SwTxtMeta::~SwTxtMeta()
+{
+ SwFmtMeta & rFmtMeta( static_cast<SwFmtMeta &>(GetAttr()) );
+ if (rFmtMeta.GetTxtAttr() == this)
+ {
+ rFmtMeta.SetTxtAttr(0);
+ }
+}
+
+void SwTxtMeta::ChgTxtNode(SwTxtNode * const pNode)
+{
+ SwFmtMeta & rFmtMeta( static_cast<SwFmtMeta &>(GetAttr()) );
+ if (rFmtMeta.GetTxtAttr() == this)
+ {
+ rFmtMeta.NotifyChangeTxtNode(pNode);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
new file mode 100644
index 000000000000..917ae6c83068
--- /dev/null
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -0,0 +1,2123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include <hintids.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/itemiter.hxx>
+#include <editeng/splwrap.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/hangulhanja.hxx>
+#include <SwSmartTagMgr.hxx>
+#include <linguistic/lngprops.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <unotools/charclass.hxx>
+#include <dlelstnr.hxx>
+#include <swmodule.hxx>
+#include <splargs.hxx>
+#include <viewopt.hxx>
+#include <acmplwrd.hxx>
+#include <doc.hxx> // GetDoc()
+#include <docsh.hxx>
+#include <txtfld.hxx>
+#include <fmtfld.hxx>
+#include <txatbase.hxx>
+#include <charatr.hxx>
+#include <fldbas.hxx>
+#include <pam.hxx>
+#include <hints.hxx>
+#include <ndtxt.hxx>
+#include <txtfrm.hxx>
+#include <SwGrammarMarkUp.hxx>
+
+#include <txttypes.hxx>
+#include <breakit.hxx>
+#include <crstate.hxx>
+#include <UndoOverwrite.hxx>
+#include <txatritr.hxx>
+#include <redline.hxx> // SwRedline
+#include <docary.hxx> // SwRedlineTbl
+#include <scriptinfo.hxx>
+#include <docstat.hxx>
+#include <editsh.hxx>
+#include <unotextmarkup.hxx>
+#include <txtatr.hxx>
+#include <fmtautofmt.hxx>
+#include <istyleaccess.hxx>
+
+#include <unomid.h>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/i18n/WordType.hdl>
+#include <com/sun/star/i18n/ScriptType.hdl>
+#include <com/sun/star/i18n/TransliterationModules.hpp>
+#include <com/sun/star/i18n/TransliterationModulesExtra.hpp>
+
+#include <vector>
+
+using rtl::OUString;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::linguistic2;
+using namespace ::com::sun::star::smarttags;
+
+// Wir ersparen uns in Hyphenate ein GetFrm()
+// Achtung: in edlingu.cxx stehen die Variablen!
+extern const SwTxtNode *pLinguNode;
+extern SwTxtFrm *pLinguFrm;
+
+bool lcl_IsSkippableWhiteSpace( xub_Unicode cCh )
+{
+ return 0x3000 == cCh ||
+ ' ' == cCh ||
+ '\t' == cCh ||
+ 0x0a == cCh;
+}
+
+/*
+ * This has basically the same function as SwScriptInfo::MaskHiddenRanges,
+ * only for deleted redlines
+ */
+
+sal_uInt16 lcl_MaskRedlines( const SwTxtNode& rNode, XubString& rText,
+ const xub_StrLen nStt, const xub_StrLen nEnd,
+ const xub_Unicode cChar )
+{
+ sal_uInt16 nNumOfMaskedRedlines = 0;
+
+ const SwDoc& rDoc = *rNode.GetDoc();
+ sal_uInt16 nAct = rDoc.GetRedlinePos( rNode, USHRT_MAX );
+
+ for ( ; nAct < rDoc.GetRedlineTbl().Count(); nAct++ )
+ {
+ const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
+
+ if ( pRed->Start()->nNode > rNode.GetIndex() )
+ break;
+
+ if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
+ {
+ xub_StrLen nRedlineEnd;
+ xub_StrLen nRedlineStart;
+
+ pRed->CalcStartEnd( rNode.GetIndex(), nRedlineStart, nRedlineEnd );
+
+ if ( nRedlineEnd < nStt || nRedlineStart > nEnd )
+ continue;
+
+ while ( nRedlineStart < nRedlineEnd && nRedlineStart < nEnd )
+ {
+ if ( nRedlineStart >= nStt && nRedlineStart < nEnd )
+ {
+ rText.SetChar( nRedlineStart, cChar );
+ ++nNumOfMaskedRedlines;
+ }
+ ++nRedlineStart;
+ }
+ }
+ }
+
+ return nNumOfMaskedRedlines;
+}
+
+/*
+ * Used for spell checking. Deleted redlines and hidden characters are masked
+ */
+
+sal_uInt16 lcl_MaskRedlinesAndHiddenText( const SwTxtNode& rNode, XubString& rText,
+ const xub_StrLen nStt, const xub_StrLen nEnd,
+ const xub_Unicode cChar = CH_TXTATR_INWORD,
+ bool bCheckShowHiddenChar = true )
+{
+ sal_uInt16 nRedlinesMasked = 0;
+ sal_uInt16 nHiddenCharsMasked = 0;
+
+ const SwDoc& rDoc = *rNode.GetDoc();
+ const bool bShowChg = 0 != IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() );
+
+ // If called from word count or from spell checking, deleted redlines
+ // should be masked:
+ if ( bShowChg )
+ {
+ nRedlinesMasked = lcl_MaskRedlines( rNode, rText, nStt, nEnd, cChar );
+ }
+
+ const bool bHideHidden = !SW_MOD()->GetViewOption(rDoc.get(IDocumentSettingAccess::HTML_MODE))->IsShowHiddenChar();
+
+ // If called from word count, we want to mask the hidden ranges even
+ // if they are visible:
+ if ( !bCheckShowHiddenChar || bHideHidden )
+ {
+ nHiddenCharsMasked =
+ SwScriptInfo::MaskHiddenRanges( rNode, rText, nStt, nEnd, cChar );
+ }
+
+ return nRedlinesMasked + nHiddenCharsMasked;
+}
+
+/*
+ * Used for spell checking. Calculates a rectangle for repaint.
+ */
+
+static SwRect lcl_CalculateRepaintRect( SwTxtFrm& rTxtFrm, xub_StrLen nChgStart, xub_StrLen nChgEnd )
+{
+ SwRect aRect;
+
+ SwTxtNode *pNode = rTxtFrm.GetTxtNode();
+
+ SwNodeIndex aNdIdx( *pNode );
+ SwPosition aPos( aNdIdx, SwIndex( pNode, nChgEnd ) );
+ SwCrsrMoveState aTmpState( MV_NONE );
+ aTmpState.b2Lines = sal_True;
+ rTxtFrm.GetCharRect( aRect, aPos, &aTmpState );
+ // information about end of repaint area
+ Sw2LinesPos* pEnd2Pos = aTmpState.p2Lines;
+
+ const SwTxtFrm *pEndFrm = &rTxtFrm;
+
+ while( pEndFrm->HasFollow() &&
+ nChgEnd >= pEndFrm->GetFollow()->GetOfst() )
+ pEndFrm = pEndFrm->GetFollow();
+
+ if ( pEnd2Pos )
+ {
+ // we are inside a special portion, take left border
+ SWRECTFN( pEndFrm )
+ (aRect.*fnRect->fnSetTop)( (pEnd2Pos->aLine.*fnRect->fnGetTop)() );
+ if ( pEndFrm->IsRightToLeft() )
+ (aRect.*fnRect->fnSetLeft)( (pEnd2Pos->aPortion.*fnRect->fnGetLeft)() );
+ else
+ (aRect.*fnRect->fnSetLeft)( (pEnd2Pos->aPortion.*fnRect->fnGetRight)() );
+ (aRect.*fnRect->fnSetWidth)( 1 );
+ (aRect.*fnRect->fnSetHeight)( (pEnd2Pos->aLine.*fnRect->fnGetHeight)() );
+ delete pEnd2Pos;
+ }
+
+ aTmpState.p2Lines = NULL;
+ SwRect aTmp;
+ aPos = SwPosition( aNdIdx, SwIndex( pNode, nChgStart ) );
+ rTxtFrm.GetCharRect( aTmp, aPos, &aTmpState );
+
+ // i63141: GetCharRect(..) could cause a formatting,
+ // during the formatting SwTxtFrms could be joined, deleted, created...
+ // => we have to reinit pStartFrm and pEndFrm after the formatting
+ const SwTxtFrm* pStartFrm = &rTxtFrm;
+ while( pStartFrm->HasFollow() &&
+ nChgStart >= pStartFrm->GetFollow()->GetOfst() )
+ pStartFrm = pStartFrm->GetFollow();
+ pEndFrm = pStartFrm;
+ while( pEndFrm->HasFollow() &&
+ nChgEnd >= pEndFrm->GetFollow()->GetOfst() )
+ pEndFrm = pEndFrm->GetFollow();
+
+ // information about start of repaint area
+ Sw2LinesPos* pSt2Pos = aTmpState.p2Lines;
+ if ( pSt2Pos )
+ {
+ // we are inside a special portion, take right border
+ SWRECTFN( pStartFrm )
+ (aTmp.*fnRect->fnSetTop)( (pSt2Pos->aLine.*fnRect->fnGetTop)() );
+ if ( pStartFrm->IsRightToLeft() )
+ (aTmp.*fnRect->fnSetLeft)( (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
+ else
+ (aTmp.*fnRect->fnSetLeft)( (pSt2Pos->aPortion.*fnRect->fnGetLeft)() );
+ (aTmp.*fnRect->fnSetWidth)( 1 );
+ (aTmp.*fnRect->fnSetHeight)( (pSt2Pos->aLine.*fnRect->fnGetHeight)() );
+ delete pSt2Pos;
+ }
+
+ sal_Bool bSameFrame = sal_True;
+
+ if( rTxtFrm.HasFollow() )
+ {
+ if( pEndFrm != pStartFrm )
+ {
+ bSameFrame = sal_False;
+ SwRect aStFrm( pStartFrm->PaintArea() );
+ {
+ SWRECTFN( pStartFrm )
+ (aTmp.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
+ (aTmp.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
+ (aTmp.*fnRect->fnSetBottom)( (aStFrm.*fnRect->fnGetBottom)() );
+ }
+ aStFrm = pEndFrm->PaintArea();
+ {
+ SWRECTFN( pEndFrm )
+ (aRect.*fnRect->fnSetTop)( (aStFrm.*fnRect->fnGetTop)() );
+ (aRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
+ (aRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
+ }
+ aRect.Union( aTmp );
+ while( sal_True )
+ {
+ pStartFrm = pStartFrm->GetFollow();
+ if( pStartFrm == pEndFrm )
+ break;
+ aRect.Union( pStartFrm->PaintArea() );
+ }
+ }
+ }
+ if( bSameFrame )
+ {
+ SWRECTFN( pStartFrm )
+ if( (aTmp.*fnRect->fnGetTop)() == (aRect.*fnRect->fnGetTop)() )
+ (aRect.*fnRect->fnSetLeft)( (aTmp.*fnRect->fnGetLeft)() );
+ else
+ {
+ SwRect aStFrm( pStartFrm->PaintArea() );
+ (aRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
+ (aRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
+ (aRect.*fnRect->fnSetTop)( (aTmp.*fnRect->fnGetTop)() );
+ }
+
+ if( aTmp.Height() > aRect.Height() )
+ aRect.Height( aTmp.Height() );
+ }
+
+ return aRect;
+}
+
+/*
+ * Used for automatic styles. Used during RstAttr.
+ */
+
+static bool lcl_HaveCommonAttributes( IStyleAccess& rStyleAccess,
+ const SfxItemSet* pSet1,
+ sal_uInt16 nWhichId,
+ const SfxItemSet& rSet2,
+ boost::shared_ptr<SfxItemSet>& pStyleHandle )
+{
+ bool bRet = false;
+
+ SfxItemSet* pNewSet = 0;
+
+ if ( !pSet1 )
+ {
+ OSL_ENSURE( nWhichId, "lcl_HaveCommonAttributes not used correctly" );
+ if ( SFX_ITEM_SET == rSet2.GetItemState( nWhichId, sal_False ) )
+ {
+ pNewSet = rSet2.Clone( sal_True );
+ pNewSet->ClearItem( nWhichId );
+ }
+ }
+ else if ( pSet1->Count() )
+ {
+ SfxItemIter aIter( *pSet1 );
+ const SfxPoolItem* pItem = aIter.GetCurItem();
+ while( sal_True )
+ {
+ if ( SFX_ITEM_SET == rSet2.GetItemState( pItem->Which(), sal_False ) )
+ {
+ if ( !pNewSet )
+ pNewSet = rSet2.Clone( sal_True );
+ pNewSet->ClearItem( pItem->Which() );
+ }
+
+ if( aIter.IsAtEnd() )
+ break;
+
+ pItem = aIter.NextItem();
+ }
+ }
+
+ if ( pNewSet )
+ {
+ if ( pNewSet->Count() )
+ pStyleHandle = rStyleAccess.getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
+ delete pNewSet;
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+inline sal_Bool InRange(xub_StrLen nIdx, xub_StrLen nStart, xub_StrLen nEnd) {
+ return ((nIdx >=nStart) && (nIdx <= nEnd));
+}
+
+/*
+ * void SwTxtNode::RstAttr(const SwIndex &rIdx, sal_uInt16 nLen)
+ *
+ * Deletes all attributes, starting at position rIdx, for length nLen.
+ */
+
+/* 5 cases:
+ * 1) The attribute is completely in the deletion range:
+ * -> delete it
+ * 2) The end of the attribute is in the deletion range:
+ * -> delete it, then re-insert it with new end
+ * 3) The start of the attribute is in the deletion range:
+ * -> delete it, then re-insert it with new start
+ * 4) The attribute contains the deletion range:
+ * Split, i.e.,
+ * -> Delete, re-insert from old start to start of deletion range
+ * -> insert new attribute from end of deletion range to old end
+ * 5) The attribute is outside the deletion range
+ * -> nothing to do
+ */
+
+void SwTxtNode::RstAttr(const SwIndex &rIdx, xub_StrLen nLen, sal_uInt16 nWhich,
+ const SfxItemSet* pSet, sal_Bool bInclRefToxMark )
+{
+ // Attribute?
+ if ( !GetpSwpHints() )
+ return;
+
+ sal_uInt16 i = 0;
+ xub_StrLen nStt = rIdx.GetIndex();
+ xub_StrLen nEnd = nStt + nLen;
+ xub_StrLen nAttrStart;
+ SwTxtAttr *pHt;
+
+ sal_Bool bChanged = sal_False;
+
+ // nMin and nMax initialized to maximum / minimum (inverse)
+ xub_StrLen nMin = m_Text.Len();
+ xub_StrLen nMax = nStt;
+
+ const sal_Bool bNoLen = !nMin;
+
+ // We have to remember the "new" attributes, which have
+ // been introduced by splitting surrounding attributes (case 4).
+ // They may not be forgotten inside the "Forget" function
+ //std::vector< const SwTxtAttr* > aNewAttributes;
+
+ // iterate over attribute array until start of attribute is behind
+ // deletion range
+ while ((i < m_pSwpHints->Count()) &&
+ ((( nAttrStart = *(*m_pSwpHints)[i]->GetStart()) < nEnd ) || nLen==0) )
+ {
+ pHt = m_pSwpHints->GetTextHint(i);
+
+ // attributes without end stay in!
+ xub_StrLen * const pAttrEnd = pHt->GetEnd();
+ if ( !pAttrEnd /*|| pHt->HasDummyChar()*/ ) // see bInclRefToxMark
+ {
+ i++;
+ continue;
+ }
+
+ // Default behavior is to process all attributes:
+ bool bSkipAttr = false;;
+ boost::shared_ptr<SfxItemSet> pStyleHandle;
+
+ // 1. case: We want to reset only the attributes listed in pSet:
+ if ( pSet )
+ {
+ bSkipAttr = SFX_ITEM_SET != pSet->GetItemState( pHt->Which(), sal_False );
+ if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
+ {
+ // if the current attribute is an autostyle, we have to check if the autostyle
+ // and pSet have any attributes in common. If so, pStyleHandle will contain
+ // a handle to AutoStyle / pSet:
+ bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), pSet, 0, *static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
+ }
+ }
+ else if ( nWhich )
+ {
+ // 2. case: We want to reset only the attributes with WhichId nWhich:
+ bSkipAttr = nWhich != pHt->Which();
+ if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
+ {
+ bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), 0, nWhich, *static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
+ }
+ }
+ else if ( !bInclRefToxMark )
+ {
+ // 3. case: Reset all attributes except from ref/toxmarks:
+ // skip hints with CH_TXTATR here
+ // (deleting those is ONLY allowed for UNDO!)
+ bSkipAttr = RES_TXTATR_REFMARK == pHt->Which()
+ || RES_TXTATR_TOXMARK == pHt->Which()
+ || RES_TXTATR_META == pHt->Which()
+ || RES_TXTATR_METAFIELD == pHt->Which();
+ }
+
+ if ( bSkipAttr )
+ {
+ i++;
+ continue;
+ }
+
+ if( nStt <= nAttrStart ) // Faelle: 1,3,5
+ {
+ if( nEnd > nAttrStart
+ || ( nEnd == *pAttrEnd && nEnd==nAttrStart ) )
+ {
+ // Faelle: 1,3
+ if ( nMin > nAttrStart )
+ nMin = nAttrStart;
+ if ( nMax < *pAttrEnd )
+ nMax = *pAttrEnd;
+ // Falls wir nur ein nichtaufgespanntes Attribut entfernen,
+ // tun wir mal so, als ob sich nichts geaendert hat.
+ bChanged = bChanged || nEnd > nAttrStart || bNoLen;
+ if( *pAttrEnd <= nEnd ) // Fall: 1
+ {
+ const xub_StrLen nAttrEnd = *pAttrEnd;
+
+ m_pSwpHints->DeleteAtPos(i);
+ DestroyAttr( pHt );
+
+ if ( pStyleHandle.get() )
+ {
+ SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
+ *pStyleHandle, nAttrStart, nAttrEnd );
+ InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
+ }
+
+ // if the last attribute is a Field, the HintsArray is
+ // deleted!
+ if ( !m_pSwpHints )
+ break;
+
+ //JP 26.11.96:
+ // beim DeleteAtPos wird ein Resort ausgefuehrt!!
+ // darum muessen wir wieder bei 0 anfangen!!!
+ // ueber den Fall 3 koennen Attribute nach hinten
+ // verschoben worden sein; damit stimmt jetzt das i
+ // nicht mehr!!!
+ i = 0;
+
+ continue;
+ }
+ else // Fall: 3
+ {
+ m_pSwpHints->NoteInHistory( pHt );
+ *pHt->GetStart() = nEnd;
+ m_pSwpHints->NoteInHistory( pHt, sal_True );
+
+ if ( pStyleHandle.get() && nAttrStart < nEnd )
+ {
+ SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
+ *pStyleHandle, nAttrStart, nEnd );
+ InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
+ }
+
+ bChanged = sal_True;
+ }
+ }
+ }
+ else // Faelle: 2,4,5
+ if( *pAttrEnd > nStt ) // Faelle: 2,4
+ {
+ if( *pAttrEnd < nEnd ) // Fall: 2
+ {
+ if ( nMin > nAttrStart )
+ nMin = nAttrStart;
+ if ( nMax < *pAttrEnd )
+ nMax = *pAttrEnd;
+ bChanged = sal_True;
+
+ const xub_StrLen nAttrEnd = *pAttrEnd;
+
+ m_pSwpHints->NoteInHistory( pHt );
+ *pAttrEnd = nStt;
+ m_pSwpHints->NoteInHistory( pHt, sal_True );
+
+ if ( pStyleHandle.get() )
+ {
+ SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
+ *pStyleHandle, nStt, nAttrEnd );
+ InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
+ }
+ }
+ else if( nLen ) // Fall: 4
+ { // bei Lange 0 werden beide Hints vom Insert(Ht)
+ // wieder zu einem zusammengezogen !!!!
+ if ( nMin > nAttrStart )
+ nMin = nAttrStart;
+ if ( nMax < *pAttrEnd )
+ nMax = *pAttrEnd;
+ bChanged = sal_True;
+ xub_StrLen nTmpEnd = *pAttrEnd;
+ m_pSwpHints->NoteInHistory( pHt );
+ *pAttrEnd = nStt;
+ m_pSwpHints->NoteInHistory( pHt, sal_True );
+
+ if ( pStyleHandle.get() && nStt < nEnd )
+ {
+ SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
+ *pStyleHandle, nStt, nEnd );
+ InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
+ }
+
+ if( nEnd < nTmpEnd )
+ {
+ SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
+ pHt->GetAttr(), nEnd, nTmpEnd );
+ if ( pNew )
+ {
+ SwTxtCharFmt* pCharFmt = dynamic_cast<SwTxtCharFmt*>(pHt);
+ if ( pCharFmt )
+ static_cast<SwTxtCharFmt*>(pNew)->SetSortNumber( pCharFmt->GetSortNumber() );
+
+ InsertHint( pNew,
+ nsSetAttrMode::SETATTR_NOHINTADJUST );
+ }
+
+ // jetzt kein i+1, weil das eingefuegte Attribut
+ // ein anderes auf die Position geschoben hat !
+ continue;
+ }
+ }
+ }
+ ++i;
+ }
+
+ TryDeleteSwpHints();
+ if (bChanged)
+ {
+ if ( HasHints() )
+ {
+ m_pSwpHints->Resort();
+ }
+ //TxtFrm's reagieren auf aHint, andere auf aNew
+ SwUpdateAttr aHint( nMin, nMax, 0 );
+ NotifyClients( 0, &aHint );
+ SwFmtChg aNew( GetFmtColl() );
+ NotifyClients( 0, &aNew );
+ }
+}
+
+/*************************************************************************
+ * SwTxtNode::GetCurWord()
+ *
+ * Aktuelles Wort zurueckliefern:
+ * Wir suchen immer von links nach rechts, es wird also das Wort
+ * vor nPos gesucht. Es sei denn, wir befinden uns am Anfang des
+ * Absatzes, dann wird das erste Wort zurueckgeliefert.
+ * Wenn dieses erste Wort nur aus Whitespaces besteht, returnen wir
+ * einen leeren String.
+ *************************************************************************/
+
+XubString SwTxtNode::GetCurWord( xub_StrLen nPos ) const
+{
+ OSL_ENSURE( nPos <= m_Text.Len(), "SwTxtNode::GetCurWord: invalid index." );
+
+ if (!m_Text.Len())
+ return m_Text;
+
+ Boundary aBndry;
+ const uno::Reference< XBreakIterator > &rxBreak = pBreakIt->GetBreakIter();
+ if (rxBreak.is())
+ {
+ sal_Int16 nWordType = WordType::DICTIONARY_WORD;
+ lang::Locale aLocale( pBreakIt->GetLocale( GetLang( nPos ) ) );
+#ifdef DEBUG
+ sal_Bool bBegin = rxBreak->isBeginWord( m_Text, nPos, aLocale, nWordType );
+ sal_Bool bEnd = rxBreak->isEndWord ( m_Text, nPos, aLocale, nWordType );
+ (void)bBegin;
+ (void)bEnd;
+#endif
+ aBndry =
+ rxBreak->getWordBoundary( m_Text, nPos, aLocale, nWordType, sal_True );
+
+ // if no word was found use previous word (if any)
+ if (aBndry.startPos == aBndry.endPos)
+ {
+ aBndry = rxBreak->previousWord( m_Text, nPos, aLocale, nWordType );
+ }
+ }
+
+ // check if word was found and if it uses a symbol font, if so
+ // enforce returning an empty string
+ if (aBndry.endPos != aBndry.startPos && IsSymbol( (xub_StrLen)aBndry.startPos ))
+ aBndry.endPos = aBndry.startPos;
+
+ return m_Text.Copy( static_cast<xub_StrLen>(aBndry.startPos),
+ static_cast<xub_StrLen>(aBndry.endPos - aBndry.startPos) );
+}
+
+SwScanner::SwScanner( const SwTxtNode& rNd, const String& rTxt, const LanguageType* pLang,
+ const ModelToViewHelper::ConversionMap* pConvMap,
+ sal_uInt16 nType, xub_StrLen nStart, xub_StrLen nEnde, sal_Bool bClp )
+ : rNode( rNd ), rText( rTxt), pLanguage( pLang ), pConversionMap( pConvMap ), nLen( 0 ), nWordType( nType ), bClip( bClp )
+{
+ OSL_ENSURE( rText.Len(), "SwScanner: EmptyString" );
+ nStartPos = nBegin = nStart;
+ nEndPos = nEnde;
+
+ if ( pLanguage )
+ {
+ aCurrLang = *pLanguage;
+ }
+ else
+ {
+ ModelToViewHelper::ModelPosition aModelBeginPos = ModelToViewHelper::ConvertToModelPosition( pConversionMap, nBegin );
+ const xub_StrLen nModelBeginPos = (xub_StrLen)aModelBeginPos.mnPos;
+ aCurrLang = rNd.GetLang( nModelBeginPos );
+ }
+}
+
+sal_Bool SwScanner::NextWord()
+{
+ nBegin = nBegin + nLen;
+ Boundary aBound;
+
+ CharClass& rCC = GetAppCharClass();
+ lang::Locale aOldLocale = rCC.getLocale();
+
+ while ( true )
+ {
+ // skip non-letter characters:
+ while ( nBegin < rText.Len() )
+ {
+ if ( !lcl_IsSkippableWhiteSpace( rText.GetChar( nBegin ) ) )
+ {
+ if ( !pLanguage )
+ {
+ const sal_uInt16 nNextScriptType = pBreakIt->GetBreakIter()->getScriptType( rText, nBegin );
+ ModelToViewHelper::ModelPosition aModelBeginPos = ModelToViewHelper::ConvertToModelPosition( pConversionMap, nBegin );
+ const xub_StrLen nBeginModelPos = (xub_StrLen)aModelBeginPos.mnPos;
+ aCurrLang = rNode.GetLang( nBeginModelPos, 1, nNextScriptType );
+ }
+
+ if ( nWordType != i18n::WordType::WORD_COUNT )
+ {
+ rCC.setLocale( pBreakIt->GetLocale( aCurrLang ) );
+ if ( rCC.isLetterNumeric( rText.GetChar( nBegin ) ) )
+ break;
+ }
+ else
+ break;
+ }
+ ++nBegin;
+ }
+
+ if ( nBegin >= rText.Len() || nBegin >= nEndPos )
+ return sal_False;
+
+ // get the word boundaries
+ aBound = pBreakIt->GetBreakIter()->getWordBoundary( rText, nBegin,
+ pBreakIt->GetLocale( aCurrLang ), nWordType, sal_True );
+ OSL_ENSURE( aBound.endPos >= aBound.startPos, "broken aBound result" );
+
+ //no word boundaries could be found
+ if(aBound.endPos == aBound.startPos)
+ return sal_False;
+
+ //if a word before is found it has to be searched for the next
+ if(aBound.endPos == nBegin)
+ ++nBegin;
+ else
+ break;
+ } // end while( true )
+
+ rCC.setLocale( aOldLocale );
+
+ // #i89042, as discussed with HDU: don't evaluate script changes for word count. Use whole word.
+ if ( nWordType == i18n::WordType::WORD_COUNT )
+ {
+ nBegin = Max( static_cast< xub_StrLen >(aBound.startPos), nBegin );
+ nLen = 0;
+ if (static_cast< xub_StrLen >(aBound.endPos) > nBegin)
+ nLen = static_cast< xub_StrLen >(aBound.endPos) - nBegin;
+ }
+ else
+ {
+ // we have to differenciate between these cases:
+ if ( aBound.startPos <= nBegin )
+ {
+ OSL_ENSURE( aBound.endPos >= nBegin, "Unexpected aBound result" );
+
+ // restrict boundaries to script boundaries and nEndPos
+ const sal_uInt16 nCurrScript = pBreakIt->GetBreakIter()->getScriptType( rText, nBegin );
+ XubString aTmpWord = rText.Copy( nBegin, static_cast<xub_StrLen>(aBound.endPos - nBegin) );
+ const sal_Int32 nScriptEnd = nBegin +
+ pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
+ const sal_Int32 nEnd = Min( aBound.endPos, nScriptEnd );
+
+ // restrict word start to last script change position
+ sal_Int32 nScriptBegin = 0;
+ if ( aBound.startPos < nBegin )
+ {
+ // search from nBegin backwards until the next script change
+ aTmpWord = rText.Copy( static_cast<xub_StrLen>(aBound.startPos),
+ static_cast<xub_StrLen>(nBegin - aBound.startPos + 1) );
+ nScriptBegin = aBound.startPos +
+ pBreakIt->GetBreakIter()->beginOfScript( aTmpWord, nBegin - aBound.startPos,
+ nCurrScript );
+ }
+
+ nBegin = (xub_StrLen)Max( aBound.startPos, nScriptBegin );
+ nLen = (xub_StrLen)(nEnd - nBegin);
+ }
+ else
+ {
+ const sal_uInt16 nCurrScript = pBreakIt->GetBreakIter()->getScriptType( rText, aBound.startPos );
+ XubString aTmpWord = rText.Copy( static_cast<xub_StrLen>(aBound.startPos),
+ static_cast<xub_StrLen>(aBound.endPos - aBound.startPos) );
+ const sal_Int32 nScriptEnd = aBound.startPos +
+ pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
+ const sal_Int32 nEnd = Min( aBound.endPos, nScriptEnd );
+ nBegin = (xub_StrLen)aBound.startPos;
+ nLen = (xub_StrLen)(nEnd - nBegin);
+ }
+ }
+
+ // optionally clip the result of getWordBoundaries:
+ if ( bClip )
+ {
+ aBound.startPos = Max( (xub_StrLen)aBound.startPos, nStartPos );
+ aBound.endPos = Min( (xub_StrLen)aBound.endPos, nEndPos );
+ nBegin = (xub_StrLen)aBound.startPos;
+ nLen = (xub_StrLen)(aBound.endPos - nBegin);
+ }
+
+ if( ! nLen )
+ return sal_False;
+
+ aWord = rText.Copy( nBegin, nLen );
+
+ return sal_True;
+}
+
+sal_uInt16 SwTxtNode::Spell(SwSpellArgs* pArgs)
+{
+ // Die Aehnlichkeiten zu SwTxtFrm::_AutoSpell sind beabsichtigt ...
+ // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
+
+ uno::Reference<beans::XPropertySet> xProp( GetLinguPropertySet() );
+
+ xub_StrLen nBegin, nEnd;
+
+ // modify string according to redline information and hidden text
+ const XubString aOldTxt( m_Text );
+ const bool bRestoreString =
+ lcl_MaskRedlinesAndHiddenText( *this, m_Text, 0, m_Text.Len() ) > 0;
+
+ if ( pArgs->pStartNode != this )
+ nBegin = 0;
+ else
+ nBegin = pArgs->pStartIdx->GetIndex();
+
+ nEnd = ( pArgs->pEndNode != this )
+ ? m_Text.Len()
+ : pArgs->pEndIdx->GetIndex();
+
+ pArgs->xSpellAlt = NULL;
+
+ // 4 cases:
+ //
+ // 1. IsWrongDirty = 0 and GetWrong = 0
+ // Everything is checked and correct
+ // 2. IsWrongDirty = 0 and GetWrong = 1
+ // Everything is checked and errors are identified in the wrong list
+ // 3. IsWrongDirty = 1 and GetWrong = 0
+ // Nothing has been checked
+ // 4. IsWrongDirty = 1 and GetWrong = 1
+ // Text has been checked but there is an invalid range in the wrong list
+ //
+ // Nothing has to be done for case 1.
+ if ( ( IsWrongDirty() || GetWrong() ) && m_Text.Len() )
+ {
+ if ( nBegin > m_Text.Len() )
+ {
+ nBegin = m_Text.Len();
+ }
+ if ( nEnd > m_Text.Len() )
+ {
+ nEnd = m_Text.Len();
+ }
+ //
+ if(!IsWrongDirty())
+ {
+ xub_StrLen nTemp = GetWrong()->NextWrong( nBegin );
+ if(nTemp > nEnd)
+ {
+ // reset original text
+ if ( bRestoreString )
+ {
+ m_Text = aOldTxt;
+ }
+ return 0;
+ }
+ if(nTemp > nBegin)
+ nBegin = nTemp;
+
+ }
+
+ // In case 2. we pass the wrong list to the scanned, because only
+ // the words in the wrong list have to be checked
+ SwScanner aScanner( *this, m_Text, 0, 0,
+ WordType::DICTIONARY_WORD,
+ nBegin, nEnd );
+ while( !pArgs->xSpellAlt.is() && aScanner.NextWord() )
+ {
+ const XubString& rWord = aScanner.GetWord();
+
+ // get next language for next word, consider language attributes
+ // within the word
+ LanguageType eActLang = aScanner.GetCurrentLanguage();
+
+ if( rWord.Len() > 0 && LANGUAGE_NONE != eActLang )
+ {
+ if (pArgs->xSpeller.is())
+ {
+ SvxSpellWrapper::CheckSpellLang( pArgs->xSpeller, eActLang );
+ pArgs->xSpellAlt = pArgs->xSpeller->spell( rWord, eActLang,
+ Sequence< PropertyValue >() );
+ }
+ if( (pArgs->xSpellAlt).is() )
+ {
+ if( IsSymbol( aScanner.GetBegin() ) )
+ {
+ pArgs->xSpellAlt = NULL;
+ }
+ else
+ {
+ // make sure the selection build later from the
+ // data below does not include footnotes and other
+ // "in word" character to the left and right in order
+ // to preserve those. Therefore count those "in words"
+ // in order to modify the selection accordingly.
+ const sal_Unicode* pChar = rWord.GetBuffer();
+ xub_StrLen nLeft = 0;
+ while (pChar && *pChar++ == CH_TXTATR_INWORD)
+ ++nLeft;
+ pChar = rWord.Len() ? rWord.GetBuffer() + rWord.Len() - 1 : 0;
+ xub_StrLen nRight = 0;
+ while (pChar && *pChar-- == CH_TXTATR_INWORD)
+ ++nRight;
+
+ pArgs->pStartNode = this;
+ pArgs->pEndNode = this;
+ pArgs->pStartIdx->Assign(this, aScanner.GetEnd() - nRight );
+ pArgs->pEndIdx->Assign(this, aScanner.GetBegin() + nLeft );
+ }
+ }
+ }
+ }
+ }
+
+ // reset original text
+ if ( bRestoreString )
+ {
+ m_Text = aOldTxt;
+ }
+
+ return pArgs->xSpellAlt.is() ? 1 : 0;
+}
+
+void SwTxtNode::SetLanguageAndFont( const SwPaM &rPaM,
+ LanguageType nLang, sal_uInt16 nLangWhichId,
+ const Font *pFont, sal_uInt16 nFontWhichId )
+{
+ sal_uInt16 aRanges[] = {
+ nLangWhichId, nLangWhichId,
+ nFontWhichId, nFontWhichId,
+ 0, 0, 0 };
+ if (!pFont)
+ aRanges[2] = aRanges[3] = 0; // clear entries with font WhichId
+
+ SwEditShell *pEditShell = GetDoc()->GetEditShell();
+ SfxItemSet aSet( pEditShell->GetAttrPool(), aRanges );
+ aSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
+
+ DBG_ASSERT( pFont, "target font missing?" );
+ if (pFont)
+ {
+ SvxFontItem aFontItem = (SvxFontItem&) aSet.Get( nFontWhichId );
+ aFontItem.SetFamilyName( pFont->GetName());
+ aFontItem.SetFamily( pFont->GetFamily());
+ aFontItem.SetStyleName( pFont->GetStyleName());
+ aFontItem.SetPitch( pFont->GetPitch());
+ aFontItem.SetCharSet( pFont->GetCharSet() );
+ aSet.Put( aFontItem );
+ }
+
+ GetDoc()->InsertItemSet( rPaM, aSet, 0 );
+ // SetAttr( aSet ); <- Does not set language attribute of empty paragraphs correctly,
+ // <- because since there is no selection the flag to garbage
+ // <- collect all attributes is set, and therefore attributes spanned
+ // <- over empty selection are removed.
+
+}
+
+sal_uInt16 SwTxtNode::Convert( SwConversionArgs &rArgs )
+{
+ // get range of text within node to be converted
+ // (either all the text or the the text within the selection
+ // when the conversion was started)
+ xub_StrLen nTextBegin, nTextEnd;
+ //
+ if ( rArgs.pStartNode != this )
+ {
+ nTextBegin = 0;
+ }
+ else
+ nTextBegin = rArgs.pStartIdx->GetIndex();
+ if (nTextBegin > m_Text.Len())
+ {
+ nTextBegin = m_Text.Len();
+ }
+
+ nTextEnd = ( rArgs.pEndNode != this )
+ ? m_Text.Len()
+ : ::std::min( rArgs.pEndIdx->GetIndex(), m_Text.Len() );
+
+ rArgs.aConvText = rtl::OUString();
+
+ // modify string according to redline information and hidden text
+ const XubString aOldTxt( m_Text );
+ const bool bRestoreString =
+ lcl_MaskRedlinesAndHiddenText( *this, m_Text, 0, m_Text.Len() ) > 0;
+
+ sal_Bool bFound = sal_False;
+ xub_StrLen nBegin = nTextBegin;
+ xub_StrLen nLen = 0;
+ LanguageType nLangFound = LANGUAGE_NONE;
+ if (!m_Text.Len())
+ {
+ if (rArgs.bAllowImplicitChangesForNotConvertibleText)
+ {
+ // create SwPaM with mark & point spanning empty paragraph
+ //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
+ SwPaM aCurPaM( *this, 0 );
+
+ SetLanguageAndFont( aCurPaM,
+ rArgs.nConvTargetLang, RES_CHRATR_CJK_LANGUAGE,
+ rArgs.pTargetFont, RES_CHRATR_CJK_FONT );
+ }
+ }
+ else
+ {
+ SwLanguageIterator aIter( *this, nBegin );
+
+ // find non zero length text portion of appropriate language
+ do {
+ nLangFound = aIter.GetLanguage();
+ sal_Bool bLangOk = (nLangFound == rArgs.nConvSrcLang) ||
+ (editeng::HangulHanjaConversion::IsChinese( nLangFound ) &&
+ editeng::HangulHanjaConversion::IsChinese( rArgs.nConvSrcLang ));
+
+ xub_StrLen nChPos = aIter.GetChgPos();
+ // the position at the end of the paragraph returns -1
+ // which becomes 65535 when converted to xub_StrLen,
+ // and thus must be cut to the end of the actual string.
+ if (nChPos == (xub_StrLen) -1)
+ {
+ nChPos = m_Text.Len();
+ }
+
+ nLen = nChPos - nBegin;
+ bFound = bLangOk && nLen > 0;
+ if (!bFound)
+ {
+ // create SwPaM with mark & point spanning the attributed text
+ //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
+ SwPaM aCurPaM( *this, nBegin );
+ aCurPaM.SetMark();
+ aCurPaM.GetPoint()->nContent = nBegin + nLen;
+
+ // check script type of selected text
+ SwEditShell *pEditShell = GetDoc()->GetEditShell();
+ pEditShell->Push(); // save current cursor on stack
+ pEditShell->SetSelection( aCurPaM );
+ sal_Bool bIsAsianScript = (SCRIPTTYPE_ASIAN == pEditShell->GetScriptType());
+ pEditShell->Pop( sal_False ); // restore cursor from stack
+
+ if (!bIsAsianScript && rArgs.bAllowImplicitChangesForNotConvertibleText)
+ {
+ SetLanguageAndFont( aCurPaM,
+ rArgs.nConvTargetLang, RES_CHRATR_CJK_LANGUAGE,
+ rArgs.pTargetFont, RES_CHRATR_CJK_FONT );
+ }
+ nBegin = nChPos; // start of next language portion
+ }
+ } while (!bFound && aIter.Next()); /* loop while nothing was found and still sth is left to be searched */
+ }
+
+ // keep resulting text within selection / range of text to be converted
+ if (nBegin < nTextBegin)
+ nBegin = nTextBegin;
+ if (nBegin + nLen > nTextEnd)
+ nLen = nTextEnd - nBegin;
+ sal_Bool bInSelection = nBegin < nTextEnd;
+
+ if (bFound && bInSelection) // convertible text found within selection/range?
+ {
+ const XubString aTxtPortion = m_Text.Copy( nBegin, nLen );
+ DBG_ASSERT( m_Text.Len() > 0, "convertible text portion missing!" );
+ rArgs.aConvText = m_Text.Copy( nBegin, nLen );
+ rArgs.nConvTextLang = nLangFound;
+
+ // position where to start looking in next iteration (after current ends)
+ rArgs.pStartNode = this;
+ rArgs.pStartIdx->Assign(this, nBegin + nLen );
+ // end position (when we have travelled over the whole document)
+ rArgs.pEndNode = this;
+ rArgs.pEndIdx->Assign(this, nBegin );
+ }
+
+ // restore original text
+ if ( bRestoreString )
+ {
+ m_Text = aOldTxt;
+ }
+
+ return rArgs.aConvText.getLength() ? 1 : 0;
+}
+
+// Die Aehnlichkeiten zu SwTxtNode::Spell sind beabsichtigt ...
+// ACHTUNG: Ev. Bugs in beiden Routinen fixen!
+SwRect SwTxtFrm::_AutoSpell( const SwCntntNode* pActNode, const SwViewOption& rViewOpt, xub_StrLen nActPos )
+{
+ SwRect aRect;
+#if OSL_DEBUG_LEVEL > 1
+ static sal_Bool bStop = sal_False;
+ if ( bStop )
+ return aRect;
+#endif
+ // Die Aehnlichkeiten zu SwTxtNode::Spell sind beabsichtigt ...
+ // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
+ SwTxtNode *pNode = GetTxtNode();
+ if( pNode != pActNode || !nActPos )
+ nActPos = STRING_LEN;
+
+ SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
+
+ // modify string according to redline information and hidden text
+ const XubString aOldTxt( pNode->GetTxt() );
+ const bool bRestoreString =
+ lcl_MaskRedlinesAndHiddenText( *pNode, pNode->m_Text,
+ 0, pNode->GetTxt().Len() ) > 0;
+
+ // a change of data indicates that at least one word has been modified
+ const sal_Bool bRedlineChg =
+ ( pNode->GetTxt().GetBuffer() != aOldTxt.GetBuffer() );
+
+ xub_StrLen nBegin = 0;
+ xub_StrLen nEnd = pNode->GetTxt().Len();
+ xub_StrLen nInsertPos = 0;
+ xub_StrLen nChgStart = STRING_LEN;
+ xub_StrLen nChgEnd = 0;
+ xub_StrLen nInvStart = STRING_LEN;
+ xub_StrLen nInvEnd = 0;
+
+ const sal_Bool bAddAutoCmpl = pNode->IsAutoCompleteWordDirty() &&
+ rViewOpt.IsAutoCompleteWords();
+
+ if( pNode->GetWrong() )
+ {
+ nBegin = pNode->GetWrong()->GetBeginInv();
+ if( STRING_LEN != nBegin )
+ {
+ nEnd = pNode->GetWrong()->GetEndInv();
+ if ( nEnd > pNode->GetTxt().Len() )
+ {
+ nEnd = pNode->GetTxt().Len();
+ }
+ }
+
+ // get word around nBegin, we start at nBegin - 1
+ if ( STRING_LEN != nBegin )
+ {
+ if ( nBegin )
+ --nBegin;
+
+ LanguageType eActLang = pNode->GetLang( nBegin );
+ Boundary aBound =
+ pBreakIt->GetBreakIter()->getWordBoundary( pNode->GetTxt(), nBegin,
+ pBreakIt->GetLocale( eActLang ),
+ WordType::DICTIONARY_WORD, sal_True );
+ nBegin = xub_StrLen(aBound.startPos);
+ }
+
+ // get the position in the wrong list
+ nInsertPos = pNode->GetWrong()->GetWrongPos( nBegin );
+
+ // sometimes we have to skip one entry
+ if( nInsertPos < pNode->GetWrong()->Count() &&
+ nBegin == pNode->GetWrong()->Pos( nInsertPos ) +
+ pNode->GetWrong()->Len( nInsertPos ) )
+ nInsertPos++;
+ }
+
+ sal_Bool bFresh = nBegin < nEnd;
+
+ if( nBegin < nEnd )
+ {
+ //! register listener to LinguServiceEvents now in order to get
+ //! notified about relevant changes in the future
+ SwModule *pModule = SW_MOD();
+ if (!pModule->GetLngSvcEvtListener().is())
+ pModule->CreateLngSvcEvtListener();
+
+ uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
+ SwDoc* pDoc = pNode->GetDoc();
+
+ SwScanner aScanner( *pNode, pNode->GetTxt(), 0, 0,
+ WordType::DICTIONARY_WORD, nBegin, nEnd);
+
+ while( aScanner.NextWord() )
+ {
+ const XubString& rWord = aScanner.GetWord();
+ nBegin = aScanner.GetBegin();
+ xub_StrLen nLen = aScanner.GetLen();
+
+ // get next language for next word, consider language attributes
+ // within the word
+ LanguageType eActLang = aScanner.GetCurrentLanguage();
+
+ sal_Bool bSpell = sal_True;
+ bSpell = xSpell.is() ? xSpell->hasLanguage( eActLang ) : sal_False;
+ if( bSpell && rWord.Len() > 0 )
+ {
+ // check for: bAlter => xHyphWord.is()
+ DBG_ASSERT(!bSpell || xSpell.is(), "NULL pointer");
+
+ if( !xSpell->isValid( rWord, eActLang, Sequence< PropertyValue >() ) )
+ {
+ xub_StrLen nSmartTagStt = nBegin;
+ xub_StrLen nDummy = 1;
+ if ( !pNode->GetSmartTags() || !pNode->GetSmartTags()->InWrongWord( nSmartTagStt, nDummy ) )
+ {
+ if( !pNode->GetWrong() )
+ {
+ pNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
+ pNode->GetWrong()->SetInvalid( 0, nEnd );
+ }
+ if( pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
+ nBegin, nLen, nInsertPos, nActPos ) )
+ pNode->GetWrong()->Insert( rtl::OUString(), 0, nBegin, nLen, nInsertPos++ );
+ else
+ {
+ nInvStart = nBegin;
+ nInvEnd = nBegin + nLen;
+ }
+ }
+ }
+ else if( bAddAutoCmpl && rACW.GetMinWordLen() <= rWord.Len() )
+ {
+ if ( bRedlineChg )
+ {
+ XubString rNewWord( rWord );
+ rACW.InsertWord( rNewWord, *pDoc );
+ }
+ else
+ rACW.InsertWord( rWord, *pDoc );
+ }
+ }
+ }
+ }
+
+ // reset original text
+ // i63141 before calling GetCharRect(..) with formatting!
+ if ( bRestoreString )
+ {
+ pNode->m_Text = aOldTxt;
+ }
+ if( pNode->GetWrong() )
+ {
+ if( bFresh )
+ pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
+ nEnd, 0, nInsertPos, nActPos );
+
+ //
+ // Calculate repaint area:
+ //
+ if( nChgStart < nChgEnd )
+ {
+ aRect = lcl_CalculateRepaintRect( *this, nChgStart, nChgEnd );
+ }
+
+ pNode->GetWrong()->SetInvalid( nInvStart, nInvEnd );
+ pNode->SetWrongDirty( STRING_LEN != pNode->GetWrong()->GetBeginInv() );
+ if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
+ pNode->SetWrong( NULL );
+ }
+ else
+ pNode->SetWrongDirty( false );
+
+ if( bAddAutoCmpl )
+ pNode->SetAutoCompleteWordDirty( false );
+
+ return aRect;
+}
+
+/** Function: SmartTagScan
+
+ Function scans words in current text and checks them in the
+ smarttag libraries. If the check returns true to bounds of the
+ recognized words are stored into a list which is used later for drawing
+ the underline.
+
+ @param SwCntntNode* pActNode
+
+ @param xub_StrLen nActPos
+
+ @return SwRect: Repaint area
+*/
+SwRect SwTxtFrm::SmartTagScan( SwCntntNode* /*pActNode*/, xub_StrLen /*nActPos*/ )
+{
+ SwRect aRet;
+ SwTxtNode *pNode = GetTxtNode();
+ const rtl::OUString& rText = pNode->GetTxt();
+
+ // Iterate over language portions
+ SmartTagMgr& rSmartTagMgr = SwSmartTagMgr::Get();
+
+ SwWrongList* pSmartTagList = pNode->GetSmartTags();
+
+ xub_StrLen nBegin = 0;
+ xub_StrLen nEnd = static_cast< xub_StrLen >(rText.getLength());
+
+ if ( pSmartTagList )
+ {
+ if ( pSmartTagList->GetBeginInv() != STRING_LEN )
+ {
+ nBegin = pSmartTagList->GetBeginInv();
+ nEnd = Min( pSmartTagList->GetEndInv(), (xub_StrLen)rText.getLength() );
+
+ if ( nBegin < nEnd )
+ {
+ const LanguageType aCurrLang = pNode->GetLang( nBegin );
+ const com::sun::star::lang::Locale aCurrLocale = pBreakIt->GetLocale( aCurrLang );
+ nBegin = static_cast< xub_StrLen >(pBreakIt->GetBreakIter()->beginOfSentence( rText, nBegin, aCurrLocale ));
+ nEnd = static_cast< xub_StrLen >(Min( rText.getLength(), pBreakIt->GetBreakIter()->endOfSentence( rText, nEnd, aCurrLocale ) ));
+ }
+ }
+ }
+
+ const sal_uInt16 nNumberOfEntries = pSmartTagList ? pSmartTagList->Count() : 0;
+ sal_uInt16 nNumberOfRemovedEntries = 0;
+ sal_uInt16 nNumberOfInsertedEntries = 0;
+
+ // clear smart tag list between nBegin and nEnd:
+ if ( 0 != nNumberOfEntries )
+ {
+ xub_StrLen nChgStart = STRING_LEN;
+ xub_StrLen nChgEnd = 0;
+ const sal_uInt16 nCurrentIndex = pSmartTagList->GetWrongPos( nBegin );
+ pSmartTagList->Fresh( nChgStart, nChgEnd, nBegin, nEnd - nBegin, nCurrentIndex, STRING_LEN );
+ nNumberOfRemovedEntries = nNumberOfEntries - pSmartTagList->Count();
+ }
+
+ if ( nBegin < nEnd )
+ {
+ // Expand the string:
+ rtl::OUString aExpandText;
+ const ModelToViewHelper::ConversionMap* pConversionMap =
+ pNode->BuildConversionMap( aExpandText );
+
+ // Ownership ov ConversionMap is passed to SwXTextMarkup object!
+ Reference< com::sun::star::text::XTextMarkup > xTextMarkup =
+ new SwXTextMarkup( *pNode, pConversionMap );
+
+ Reference< ::com::sun::star::frame::XController > xController = pNode->GetDoc()->GetDocShell()->GetController();
+
+ xub_StrLen nLangBegin = nBegin;
+ xub_StrLen nLangEnd = nEnd;
+
+ // smart tag recognization has to be done for each language portion:
+ SwLanguageIterator aIter( *pNode, nLangBegin );
+
+ do
+ {
+ const LanguageType nLang = aIter.GetLanguage();
+ const com::sun::star::lang::Locale aLocale = pBreakIt->GetLocale( nLang );
+ nLangEnd = Min( nEnd, aIter.GetChgPos() );
+
+ const sal_uInt32 nExpandBegin = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nLangBegin );
+ const sal_uInt32 nExpandEnd = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nLangEnd );
+
+ rSmartTagMgr.Recognize( aExpandText, xTextMarkup, xController, aLocale, nExpandBegin, nExpandEnd - nExpandBegin );
+
+ nLangBegin = nLangEnd;
+ }
+ while ( aIter.Next() && nLangEnd < nEnd );
+
+ pSmartTagList = pNode->GetSmartTags();
+
+ const sal_uInt16 nNumberOfEntriesAfterRecognize = pSmartTagList ? pSmartTagList->Count() : 0;
+ nNumberOfInsertedEntries = nNumberOfEntriesAfterRecognize - ( nNumberOfEntries - nNumberOfRemovedEntries );
+ }
+
+ if( pSmartTagList )
+ {
+ //
+ // Update WrongList stuff
+ //
+ pSmartTagList->SetInvalid( STRING_LEN, 0 );
+ pNode->SetSmartTagDirty( STRING_LEN != pSmartTagList->GetBeginInv() );
+
+ if( !pSmartTagList->Count() && !pNode->IsSmartTagDirty() )
+ pNode->SetSmartTags( NULL );
+
+ //
+ // Calculate repaint area:
+ //
+#if OSL_DEBUG_LEVEL > 1
+ const sal_uInt16 nNumberOfEntriesAfterRecognize2 = pSmartTagList->Count();
+ (void) nNumberOfEntriesAfterRecognize2;
+#endif
+ if ( nBegin < nEnd && ( 0 != nNumberOfRemovedEntries ||
+ 0 != nNumberOfInsertedEntries ) )
+ {
+ aRet = lcl_CalculateRepaintRect( *this, nBegin, nEnd );
+ }
+ }
+ else
+ pNode->SetSmartTagDirty( false );
+
+ return aRet;
+}
+
+// Wird vom CollectAutoCmplWords gerufen
+void SwTxtFrm::CollectAutoCmplWrds( SwCntntNode* pActNode, xub_StrLen nActPos )
+{
+ SwTxtNode *pNode = GetTxtNode();
+ if( pNode != pActNode || !nActPos )
+ nActPos = STRING_LEN;
+
+ SwDoc* pDoc = pNode->GetDoc();
+ SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
+
+ xub_StrLen nBegin = 0;
+ xub_StrLen nEnd = pNode->GetTxt().Len();
+ xub_StrLen nLen;
+ sal_Bool bACWDirty = sal_False, bAnyWrd = sal_False;
+
+ if( nBegin < nEnd )
+ {
+ sal_uInt16 nCnt = 200;
+ SwScanner aScanner( *pNode, pNode->GetTxt(), 0, 0,
+ WordType::DICTIONARY_WORD, nBegin, nEnd );
+ while( aScanner.NextWord() )
+ {
+ nBegin = aScanner.GetBegin();
+ nLen = aScanner.GetLen();
+ if( rACW.GetMinWordLen() <= nLen )
+ {
+ const XubString& rWord = aScanner.GetWord();
+
+ if( nActPos < nBegin || ( nBegin + nLen ) < nActPos )
+ {
+ if( rACW.GetMinWordLen() <= rWord.Len() )
+ rACW.InsertWord( rWord, *pDoc );
+ bAnyWrd = sal_True;
+ }
+ else
+ bACWDirty = sal_True;
+ }
+ if( !--nCnt )
+ {
+ if ( Application::AnyInput( INPUT_ANY ) )
+ return;
+ nCnt = 100;
+ }
+ }
+ }
+
+ if( bAnyWrd && !bACWDirty )
+ pNode->SetAutoCompleteWordDirty( sal_False );
+}
+
+/*************************************************************************
+ * SwTxtNode::Hyphenate
+ *************************************************************************/
+// Findet den TxtFrm und sucht dessen CalcHyph
+
+sal_Bool SwTxtNode::Hyphenate( SwInterHyphInfo &rHyphInf )
+{
+ // Abkuerzung: am Absatz ist keine Sprache eingestellt:
+ if ( LANGUAGE_NONE == sal_uInt16( GetSwAttrSet().GetLanguage().GetLanguage() )
+ && USHRT_MAX == GetLang( 0, m_Text.Len() ) )
+ {
+ if( !rHyphInf.IsCheck() )
+ rHyphInf.SetNoLang( sal_True );
+ return sal_False;
+ }
+
+ if( pLinguNode != this )
+ {
+ pLinguNode = this;
+ pLinguFrm = (SwTxtFrm*)getLayoutFrm( GetDoc()->GetCurrentLayout(), (Point*)(rHyphInf.GetCrsrPos()) );
+ }
+ SwTxtFrm *pFrm = pLinguFrm;
+ if( pFrm )
+ pFrm = &(pFrm->GetFrmAtOfst( rHyphInf.nStart ));
+ else
+ {
+ // 4935: Seit der Trennung ueber Sonderbereiche sind Faelle
+ // moeglich, in denen kein Frame zum Node vorliegt.
+ // Also keinOSL_ENSURE
+#if OSL_DEBUG_LEVEL > 1
+ OSL_ENSURE( pFrm, "!SwTxtNode::Hyphenate: can't find any frame" );
+#endif
+ return sal_False;
+ }
+
+ while( pFrm )
+ {
+ if( pFrm->Hyphenate( rHyphInf ) )
+ {
+ // Das Layout ist nicht robust gegen "Direktformatierung"
+ // (7821, 7662, 7408); vgl. layact.cxx,
+ // SwLayAction::_TurboAction(), if( !pCnt->IsValid() ...
+ pFrm->SetCompletePaint();
+ return sal_True;
+ }
+ pFrm = (SwTxtFrm*)(pFrm->GetFollow());
+ if( pFrm )
+ {
+ rHyphInf.nLen = rHyphInf.nLen - (pFrm->GetOfst() - rHyphInf.nStart);
+ rHyphInf.nStart = pFrm->GetOfst();
+ }
+ }
+ return sal_False;
+}
+
+struct TransliterationChgData
+{
+ xub_StrLen nStart;
+ xub_StrLen nLen;
+ String sChanged;
+ Sequence< sal_Int32 > aOffsets;
+};
+
+// change text to Upper/Lower/Hiragana/Katagana/...
+void SwTxtNode::TransliterateText(
+ utl::TransliterationWrapper& rTrans,
+ xub_StrLen nStt, xub_StrLen nEnd,
+ SwUndoTransliterate* pUndo )
+{
+ if (nStt < nEnd && pBreakIt->GetBreakIter().is())
+ {
+ // since we don't use Hiragana/Katakana or half-width/full-width transliterations here
+ // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will
+ // occasionaly miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES
+ // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the
+ // proper thing to do.
+ const sal_Int16 nWordType = WordType::ANYWORD_IGNOREWHITESPACES;
+
+ //! In order to have less trouble with changing text size, e.g. because
+ //! of ligatures or � (German small sz) being resolved, we need to process
+ //! the text replacements from end to start.
+ //! This way the offsets for the yet to be changed words will be
+ //! left unchanged by the already replaced text.
+ //! For this we temporarily save the changes to be done in this vector
+ std::vector< TransliterationChgData > aChanges;
+ TransliterationChgData aChgData;
+
+ if (rTrans.getType() == (sal_uInt32)TransliterationModulesExtra::TITLE_CASE)
+ {
+ // for 'capitalize every word' we need to iterate over each word
+
+ Boundary aSttBndry;
+ Boundary aEndBndry;
+ aSttBndry = pBreakIt->GetBreakIter()->getWordBoundary(
+ GetTxt(), nStt,
+ pBreakIt->GetLocale( GetLang( nStt ) ),
+ nWordType,
+ sal_True /*prefer forward direction*/);
+ aEndBndry = pBreakIt->GetBreakIter()->getWordBoundary(
+ GetTxt(), nEnd,
+ pBreakIt->GetLocale( GetLang( nEnd ) ),
+ nWordType,
+ sal_False /*prefer backward direction*/);
+
+ // prevent backtracking to the previous word if selection is at word boundary
+ if (aSttBndry.endPos <= nStt)
+ {
+ aSttBndry = pBreakIt->GetBreakIter()->nextWord(
+ GetTxt(), aSttBndry.endPos,
+ pBreakIt->GetLocale( GetLang( aSttBndry.endPos ) ),
+ nWordType);
+ }
+ // prevent advancing to the next word if selection is at word boundary
+ if (aEndBndry.startPos >= nEnd)
+ {
+ aEndBndry = pBreakIt->GetBreakIter()->previousWord(
+ GetTxt(), aEndBndry.startPos,
+ pBreakIt->GetLocale( GetLang( aEndBndry.startPos ) ),
+ nWordType);
+ }
+
+ Boundary aCurWordBndry( aSttBndry );
+ while (aCurWordBndry.startPos <= aEndBndry.startPos)
+ {
+ nStt = (xub_StrLen)aCurWordBndry.startPos;
+ nEnd = (xub_StrLen)aCurWordBndry.endPos;
+ sal_Int32 nLen = nEnd - nStt;
+ DBG_ASSERT( nLen > 0, "invalid word length of 0" );
+#if OSL_DEBUG_LEVEL > 1
+ String aText( GetTxt().Copy( nStt, nLen ) );
+#endif
+
+ Sequence <sal_Int32> aOffsets;
+ String sChgd( rTrans.transliterate( GetTxt(), GetLang( nStt ), nStt, nLen, &aOffsets ));
+
+ if (!m_Text.Equals( sChgd, nStt, nLen ))
+ {
+ aChgData.nStart = nStt;
+ aChgData.nLen = nLen;
+ aChgData.sChanged = sChgd;
+ aChgData.aOffsets = aOffsets;
+ aChanges.push_back( aChgData );
+ }
+
+ aCurWordBndry = pBreakIt->GetBreakIter()->nextWord(
+ GetTxt(), nEnd,
+ pBreakIt->GetLocale( GetLang( nEnd ) ),
+ nWordType);
+ }
+ }
+ else if (rTrans.getType() == (sal_uInt32)TransliterationModulesExtra::SENTENCE_CASE)
+ {
+ // for 'sentence case' we need to iterate sentence by sentence
+
+ sal_Int32 nLastStart = pBreakIt->GetBreakIter()->beginOfSentence(
+ GetTxt(), nEnd,
+ pBreakIt->GetLocale( GetLang( nEnd ) ) );
+ sal_Int32 nLastEnd = pBreakIt->GetBreakIter()->endOfSentence(
+ GetTxt(), nLastStart,
+ pBreakIt->GetLocale( GetLang( nLastStart ) ) );
+
+ // extend nStt, nEnd to the current sentence boundaries
+ sal_Int32 nCurrentStart = pBreakIt->GetBreakIter()->beginOfSentence(
+ GetTxt(), nStt,
+ pBreakIt->GetLocale( GetLang( nStt ) ) );
+ sal_Int32 nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
+ GetTxt(), nCurrentStart,
+ pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
+
+ // prevent backtracking to the previous sentence if selection starts at end of a sentence
+ if (nCurrentEnd <= nStt)
+ {
+ // now nCurrentStart is probably located on a non-letter word. (unless we
+ // are in Asian text with no spaces...)
+ // Thus to get the real sentence start we should locate the next real word,
+ // that is one found by DICTIONARY_WORD
+ i18n::Boundary aBndry = pBreakIt->GetBreakIter()->nextWord(
+ GetTxt(), nCurrentEnd,
+ pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
+ i18n::WordType::DICTIONARY_WORD);
+
+ // now get new current sentence boundaries
+ nCurrentStart = pBreakIt->GetBreakIter()->beginOfSentence(
+ GetTxt(), aBndry.startPos,
+ pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
+ nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
+ GetTxt(), nCurrentStart,
+ pBreakIt->GetLocale( GetLang( nCurrentStart) ) );
+ }
+ // prevent advancing to the next sentence if selection ends at start of a sentence
+ if (nLastStart >= nEnd)
+ {
+ // now nCurrentStart is probably located on a non-letter word. (unless we
+ // are in Asian text with no spaces...)
+ // Thus to get the real sentence start we should locate the previous real word,
+ // that is one found by DICTIONARY_WORD
+ i18n::Boundary aBndry = pBreakIt->GetBreakIter()->previousWord(
+ GetTxt(), nLastStart,
+ pBreakIt->GetLocale( GetLang( nLastStart) ),
+ i18n::WordType::DICTIONARY_WORD);
+ nLastEnd = pBreakIt->GetBreakIter()->endOfSentence(
+ GetTxt(), aBndry.startPos,
+ pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
+ if (nCurrentEnd > nLastEnd)
+ nCurrentEnd = nLastEnd;
+ }
+
+ while (nCurrentStart < nLastEnd)
+ {
+ sal_Int32 nLen = nCurrentEnd - nCurrentStart;
+ DBG_ASSERT( nLen > 0, "invalid word length of 0" );
+#if OSL_DEBUG_LEVEL > 1
+ String aText( GetTxt().Copy( nCurrentStart, nLen ) );
+#endif
+
+ Sequence <sal_Int32> aOffsets;
+ String sChgd( rTrans.transliterate( GetTxt(),
+ GetLang( nCurrentStart ), nCurrentStart, nLen, &aOffsets ));
+
+ if (!m_Text.Equals( sChgd, nStt, nLen ))
+ {
+ aChgData.nStart = nCurrentStart;
+ aChgData.nLen = nLen;
+ aChgData.sChanged = sChgd;
+ aChgData.aOffsets = aOffsets;
+ aChanges.push_back( aChgData );
+ }
+
+ Boundary aFirstWordBndry;
+ aFirstWordBndry = pBreakIt->GetBreakIter()->nextWord(
+ GetTxt(), nCurrentEnd,
+ pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
+ nWordType);
+ nCurrentStart = aFirstWordBndry.startPos;
+ nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
+ GetTxt(), nCurrentStart,
+ pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
+ }
+ }
+ else
+ {
+ // here we may transliterate over complete language portions...
+
+ SwLanguageIterator* pIter;
+ if( rTrans.needLanguageForTheMode() )
+ pIter = new SwLanguageIterator( *this, nStt );
+ else
+ pIter = 0;
+
+ xub_StrLen nEndPos;
+ sal_uInt16 nLang;
+ do {
+ if( pIter )
+ {
+ nLang = pIter->GetLanguage();
+ nEndPos = pIter->GetChgPos();
+ if( nEndPos > nEnd )
+ nEndPos = nEnd;
+ }
+ else
+ {
+ nLang = LANGUAGE_SYSTEM;
+ nEndPos = nEnd;
+ }
+ xub_StrLen nLen = nEndPos - nStt;
+
+ Sequence <sal_Int32> aOffsets;
+ String sChgd( rTrans.transliterate( m_Text, nLang, nStt, nLen, &aOffsets ));
+
+ if (!m_Text.Equals( sChgd, nStt, nLen ))
+ {
+ aChgData.nStart = nStt;
+ aChgData.nLen = nLen;
+ aChgData.sChanged = sChgd;
+ aChgData.aOffsets = aOffsets;
+ aChanges.push_back( aChgData );
+ }
+
+ nStt = nEndPos;
+ } while( nEndPos < nEnd && pIter && pIter->Next() );
+ delete pIter;
+ }
+
+ if (aChanges.size() > 0)
+ {
+ // now apply the changes from end to start to leave the offsets of the
+ // yet unchanged text parts remain the same.
+ for (size_t i = 0; i < aChanges.size(); ++i)
+ {
+ TransliterationChgData &rData = aChanges[ aChanges.size() - 1 - i ];
+ if (pUndo)
+ pUndo->AddChanges( *this, rData.nStart, rData.nLen, rData.aOffsets );
+ ReplaceTextOnly( rData.nStart, rData.nLen, rData.sChanged, rData.aOffsets );
+ }
+ }
+ }
+}
+
+void SwTxtNode::ReplaceTextOnly( xub_StrLen nPos, xub_StrLen nLen,
+ const XubString& rText,
+ const Sequence<sal_Int32>& rOffsets )
+{
+ m_Text.Replace( nPos, nLen, rText );
+
+ xub_StrLen nTLen = rText.Len();
+ const sal_Int32* pOffsets = rOffsets.getConstArray();
+ // now look for no 1-1 mapping -> move the indizies!
+ xub_StrLen nI, nMyOff;
+ for( nI = 0, nMyOff = nPos; nI < nTLen; ++nI, ++nMyOff )
+ {
+ xub_StrLen nOff = (xub_StrLen)pOffsets[ nI ];
+ if( nOff < nMyOff )
+ {
+ // something is inserted
+ xub_StrLen nCnt = 1;
+ while( nI + nCnt < nTLen && nOff == pOffsets[ nI + nCnt ] )
+ ++nCnt;
+
+ Update( SwIndex( this, nMyOff ), nCnt, sal_False );
+ nMyOff = nOff;
+ //nMyOff -= nCnt;
+ nI += nCnt - 1;
+ }
+ else if( nOff > nMyOff )
+ {
+ // something is deleted
+ Update( SwIndex( this, nMyOff+1 ), nOff - nMyOff, sal_True );
+ nMyOff = nOff;
+ }
+ }
+ if( nMyOff < nLen )
+ // something is deleted at the end
+ Update( SwIndex( this, nMyOff ), nLen - nMyOff, sal_True );
+
+ // notify the layout!
+ SwDelTxt aDelHint( nPos, nTLen );
+ NotifyClients( 0, &aDelHint );
+
+ SwInsTxt aHint( nPos, nTLen );
+ NotifyClients( 0, &aHint );
+}
+
+void SwTxtNode::CountWords( SwDocStat& rStat,
+ xub_StrLen nStt, xub_StrLen nEnd ) const
+{
+ sal_Bool isCountAll = ( (0 == nStt) && (GetTxt().Len() == nEnd) );
+
+ ++rStat.nAllPara; // #i93174#: count _all_ paragraphs
+ if( nStt >= nEnd )
+ { // empty node or empty selection or bad call
+ return;
+ }
+ if ( IsHidden() )
+ { // not counting hidden paras
+ return;
+ }
+ // Shortcut when counting whole paragraph and current count is clean
+ if ( isCountAll && !IsWordCountDirty() )
+ {
+ // accumulate into DocStat record to return the values
+ rStat.nWord += GetParaNumberOfWords();
+ rStat.nChar += GetParaNumberOfChars();
+ rStat.nCharExcludingSpaces += GetParaNumberOfCharsExcludingSpaces();
+ return;
+ }
+
+ // make a copy of the text
+ String& rTextCopy = const_cast<String&>(m_Text);
+
+ // mask out the redlined and hidden text with ' '
+ const xub_Unicode cChar(' ');
+ const sal_uInt16 nNumOfMaskedChars = lcl_MaskRedlinesAndHiddenText( *this, rTextCopy, nStt, nEnd, cChar, false );
+
+ // expand text into pConversionMap for scanner
+ rtl::OUString aExpandText;
+ const ModelToViewHelper::ConversionMap* pConversionMap = BuildConversionMap( aExpandText );
+
+ // map start and end points onto the ConversionMap
+ const sal_uInt32 nExpandBegin = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nStt );
+ const sal_uInt32 nExpandEnd = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nEnd );
+
+ if ( aExpandText.getLength() <= 0 )
+ {
+ OSL_ENSURE(aExpandText.getLength() >= 0, "Node text expansion error: length < 0." );
+ return;
+ }
+
+ //do the count
+ // all counts exclude hidden paras and hidden+redlined within para
+ // definition of space/white chars in SwScanner (and BreakIter!)
+ // uses both lcl_IsSkippableWhiteSpace and BreakIter getWordBoundary in SwScanner
+ sal_uInt32 nTmpWords = 0; // count of all contiguous blocks of non-white chars
+ sal_uInt32 nTmpChars = 0; // count of all chars
+ sal_uInt32 nTmpCharsExcludingSpaces = 0; // all non-white chars
+
+ ++rStat.nPara; // count of non-empty paras
+
+ // count words in masked and expanded text:
+ if( pBreakIt->GetBreakIter().is() )
+ {
+ const String aScannerText( aExpandText );
+ // zero is NULL for pLanguage -----------v last param = true for clipping
+ SwScanner aScanner( *this, aScannerText, 0, pConversionMap, i18n::WordType::WORD_COUNT,
+ (xub_StrLen)nExpandBegin, (xub_StrLen)nExpandEnd, true );
+
+ // used to filter out scanner returning almost empty strings (len=1; unichar=0x0001)
+ const rtl::OUString aBreakWord( CH_TXTATR_BREAKWORD );
+
+ while ( aScanner.NextWord() )
+ {
+ // 1 is len(CH_TXTATR_BREAKWORD) : match returns length of match
+ if( 1 != aExpandText.match(aBreakWord, aScanner.GetBegin() ))
+ {
+ ++nTmpWords;
+ nTmpCharsExcludingSpaces += aScanner.GetLen();
+ }
+ }
+ }
+
+ nTmpChars = nExpandEnd - nExpandBegin - nNumOfMaskedChars;
+
+ // no nTmpCharsExcludingSpaces adjust needed neither for blanked out MaskedChars
+ // nor for mid-word selection - set scanner bClip = true at creation
+
+ // count words in numbering string if started at beginning of para:
+ if ( nStt == 0 )
+ {
+ // count outline number label - ? no expansion into map
+ // always counts all of number-ish label
+ const String aNumString = GetNumString();
+ const xub_StrLen nNumStringLen = aNumString.Len();
+ if ( nNumStringLen > 0 )
+ {
+ LanguageType aLanguage = GetLang( 0 );
+
+ SwScanner aScanner( *this, aNumString, &aLanguage, 0,
+ i18n::WordType::WORD_COUNT, 0, nNumStringLen, true );
+
+ while ( aScanner.NextWord() )
+ {
+ ++nTmpWords;
+ nTmpCharsExcludingSpaces += aScanner.GetLen();
+ }
+
+ nTmpChars += nNumStringLen;
+ }
+ else if ( HasBullet() )
+ {
+ ++nTmpWords;
+ ++nTmpChars;
+ ++nTmpCharsExcludingSpaces;
+ }
+ }
+
+ delete pConversionMap;
+
+ // If counting the whole para then update cached values and mark clean
+ if ( isCountAll )
+ {
+ SetParaNumberOfWords( nTmpWords );
+ SetParaNumberOfChars( nTmpChars );
+ SetParaNumberOfCharsExcludingSpaces( nTmpCharsExcludingSpaces );
+ SetWordCountDirty( false );
+ }
+ // accumulate into DocStat record to return the values
+ rStat.nWord += nTmpWords;
+ rStat.nChar += nTmpChars;
+ rStat.nCharExcludingSpaces += nTmpCharsExcludingSpaces;
+}
+
+//
+// Paragraph statistics start
+//
+struct SwParaIdleData_Impl
+{
+ SwWrongList* pWrong; // for spell checking
+ SwGrammarMarkUp* pGrammarCheck; // for grammar checking / proof reading
+ SwWrongList* pSmartTags;
+ sal_uLong nNumberOfWords;
+ sal_uLong nNumberOfChars;
+ sal_uLong nNumberOfCharsExcludingSpaces;
+ bool bWordCountDirty;
+ bool bWrongDirty; // Ist das Wrong-Feld auf invalid?
+ bool bGrammarCheckDirty;
+ bool bSmartTagDirty;
+ bool bAutoComplDirty; // die ACompl-Liste muss angepasst werden
+
+ SwParaIdleData_Impl() :
+ pWrong ( 0 ),
+ pGrammarCheck ( 0 ),
+ pSmartTags ( 0 ),
+ nNumberOfWords ( 0 ),
+ nNumberOfChars ( 0 ),
+ nNumberOfCharsExcludingSpaces ( 0 ),
+ bWordCountDirty ( true ),
+ bWrongDirty ( true ),
+ bGrammarCheckDirty ( true ),
+ bSmartTagDirty ( true ),
+ bAutoComplDirty ( true ) {};
+};
+
+void SwTxtNode::InitSwParaStatistics( bool bNew )
+{
+ if ( bNew )
+ {
+ m_pParaIdleData_Impl = new SwParaIdleData_Impl;
+ }
+ else if ( m_pParaIdleData_Impl )
+ {
+ delete m_pParaIdleData_Impl->pWrong;
+ delete m_pParaIdleData_Impl->pGrammarCheck;
+ delete m_pParaIdleData_Impl->pSmartTags;
+ delete m_pParaIdleData_Impl;
+ m_pParaIdleData_Impl = 0;
+ }
+}
+
+void SwTxtNode::SetWrong( SwWrongList* pNew, bool bDelete )
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ if ( bDelete )
+ {
+ delete m_pParaIdleData_Impl->pWrong;
+ }
+ m_pParaIdleData_Impl->pWrong = pNew;
+ }
+}
+
+SwWrongList* SwTxtNode::GetWrong()
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : 0;
+}
+
+// --> OD 2008-05-27 #i71360#
+const SwWrongList* SwTxtNode::GetWrong() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : 0;
+}
+// <--
+
+void SwTxtNode::SetGrammarCheck( SwGrammarMarkUp* pNew, bool bDelete )
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ if ( bDelete )
+ {
+ delete m_pParaIdleData_Impl->pGrammarCheck;
+ }
+ m_pParaIdleData_Impl->pGrammarCheck = pNew;
+ }
+}
+
+SwGrammarMarkUp* SwTxtNode::GetGrammarCheck()
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pGrammarCheck : 0;
+}
+
+void SwTxtNode::SetSmartTags( SwWrongList* pNew, bool bDelete )
+{
+ OSL_ENSURE( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(),
+ "Weird - we have a smart tag list without any recognizers?" );
+
+ if ( m_pParaIdleData_Impl )
+ {
+ if ( bDelete )
+ {
+ delete m_pParaIdleData_Impl->pSmartTags;
+ }
+ m_pParaIdleData_Impl->pSmartTags = pNew;
+ }
+}
+
+SwWrongList* SwTxtNode::GetSmartTags()
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pSmartTags : 0;
+}
+
+void SwTxtNode::SetParaNumberOfWords( sal_uLong nNew ) const
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ m_pParaIdleData_Impl->nNumberOfWords = nNew;
+ }
+}
+sal_uLong SwTxtNode::GetParaNumberOfWords() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfWords : 0;
+}
+void SwTxtNode::SetParaNumberOfChars( sal_uLong nNew ) const
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ m_pParaIdleData_Impl->nNumberOfChars = nNew;
+ }
+}
+sal_uLong SwTxtNode::GetParaNumberOfChars() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfChars : 0;
+}
+void SwTxtNode::SetWordCountDirty( bool bNew ) const
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ m_pParaIdleData_Impl->bWordCountDirty = bNew;
+ }
+}
+
+sal_uLong SwTxtNode::GetParaNumberOfCharsExcludingSpaces() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces : 0;
+}
+
+void SwTxtNode::SetParaNumberOfCharsExcludingSpaces( sal_uLong nNew ) const
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces = nNew;
+ }
+}
+
+bool SwTxtNode::IsWordCountDirty() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bWordCountDirty : 0;
+}
+void SwTxtNode::SetWrongDirty( bool bNew ) const
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ m_pParaIdleData_Impl->bWrongDirty = bNew;
+ }
+}
+bool SwTxtNode::IsWrongDirty() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bWrongDirty : 0;
+}
+void SwTxtNode::SetGrammarCheckDirty( bool bNew ) const
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ m_pParaIdleData_Impl->bGrammarCheckDirty = bNew;
+ }
+}
+bool SwTxtNode::IsGrammarCheckDirty() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bGrammarCheckDirty : 0;
+}
+void SwTxtNode::SetSmartTagDirty( bool bNew ) const
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ m_pParaIdleData_Impl->bSmartTagDirty = bNew;
+ }
+}
+bool SwTxtNode::IsSmartTagDirty() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bSmartTagDirty : 0;
+}
+void SwTxtNode::SetAutoCompleteWordDirty( bool bNew ) const
+{
+ if ( m_pParaIdleData_Impl )
+ {
+ m_pParaIdleData_Impl->bAutoComplDirty = bNew;
+ }
+}
+bool SwTxtNode::IsAutoCompleteWordDirty() const
+{
+ return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bAutoComplDirty : 0;
+}
+//
+// Paragraph statistics end
+//
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */