blob: 89b9cc1bcbd08fc61247cc52563d5e445305635c [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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 <txtannotationfld.hxx>
#include <docfld.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
*
****************************************************************************/
// constructor for default item in attribute-pool
SwFmtFld::SwFmtFld( sal_uInt16 nWhich )
: SfxPoolItem( nWhich )
, SwClient()
, SfxBroadcaster()
, mpField( NULL )
, mpTxtFld( NULL )
{
}
SwFmtFld::SwFmtFld( const SwField &rFld )
: SfxPoolItem( RES_TXTATR_FIELD )
, SwClient( rFld.GetTyp() )
, SfxBroadcaster()
, mpField( rFld.CopyField() )
, mpTxtFld( NULL )
{
if ( GetField()->GetTyp()->Which() == RES_INPUTFLD )
{
// input field in-place editing
SetWhich( RES_TXTATR_INPUTFIELD );
dynamic_cast<SwInputField*>(GetField())->SetFmtFld( *this );
}
else if ( GetField()->GetTyp()->Which() == RES_POSTITFLD )
{
// text annotation field
SetWhich( RES_TXTATR_ANNOTATION );
}
}
// #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()
, mpField( NULL )
, mpTxtFld( NULL )
{
if ( rAttr.GetField() )
{
rAttr.GetField()->GetTyp()->Add(this);
mpField = rAttr.GetField()->CopyField();
if ( GetField()->GetTyp()->Which() == RES_INPUTFLD )
{
// input field in-place editing
SetWhich( RES_TXTATR_INPUTFIELD );
dynamic_cast<SwInputField*>(GetField())->SetFmtFld( *this );
}
else if ( GetField()->GetTyp()->Which() == RES_POSTITFLD )
{
// text annotation field
SetWhich( RES_TXTATR_ANNOTATION );
}
}
}
SwFmtFld::~SwFmtFld()
{
SwFieldType* pType = mpField ? mpField->GetTyp() : 0;
if (pType && pType->Which() == RES_DBFLD)
pType = 0; // DB-Feldtypen zerstoeren sich selbst
Broadcast( SwFmtFldHint( this, SWFMTFLD_REMOVED ) );
delete mpField;
// 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::SetField(SwField * _pField)
{
if (NULL != mpField)
delete mpField;
mpField = _pField;
if ( GetField()->GetTyp()->Which() == RES_INPUTFLD )
{
dynamic_cast<SwInputField* >(GetField())->SetFmtFld( *this );
}
Broadcast( SwFmtFldHint( this, SWFMTFLD_CHANGED ) );
}
void SwFmtFld::SetTxtFld( SwTxtFld& rTxtFld )
{
mpTxtFld = &rTxtFld;
}
void SwFmtFld::ClearTxtFld()
{
mpTxtFld = NULL;
}
int SwFmtFld::operator==( const SfxPoolItem& rAttr ) const
{
ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
return ( ( mpField && ((SwFmtFld&)rAttr).GetField()
&& mpField->GetTyp() == ((SwFmtFld&)rAttr).GetField()->GetTyp()
&& mpField->GetFormat() == ((SwFmtFld&)rAttr).GetField()->GetFormat() ) )
|| ( !mpField && !((SwFmtFld&)rAttr).GetField() );
}
SfxPoolItem* SwFmtFld::Clone( SfxItemPool* ) const
{
return new SwFmtFld( *this );
}
void SwFmtFld::SwClientNotify( const SwModify&, const SfxHint& rHint )
{
if( !mpTxtFld )
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 = mpTxtFld->GetTxtNode();
pPaM->GetPoint()->nNode = rTxtNode;
pPaM->GetPoint()->nContent.Assign( (SwTxtNode*)&rTxtNode, *mpTxtFld->GetStart() );
String const aEntry( GetField()->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 ( mpTxtFld == NULL )
return;
if( pNew != NULL
&& pNew->Which() == RES_OBJECTDYING )
{
// don't do anything, especially not expand!
return;
}
SwTxtNode* pTxtNd = (SwTxtNode*) &mpTxtFld->GetTxtNode();
ASSERT( 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 == GetField()->GetTyp()->Which() )
{
dynamic_cast<SwGetRefField*>(GetField())->UpdateField( mpTxtFld );
}
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 (GetField()->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 == GetField()->GetTyp()->Which() )
{
SwUserFieldType* pType = (SwUserFieldType*) GetField()->GetTyp();
if ( !pType->IsValid() )
{
SwCalc aCalc( *pTxtNd->GetDoc() );
pType->GetValue( aCalc );
}
}
const bool bForceNotify = (pOld == NULL) && (pNew == NULL);
mpTxtFld->ExpandTxtFld( bForceNotify );
}
sal_Bool SwFmtFld::GetInfo( SfxPoolItem& rInfo ) const
{
const SwTxtNode* pTxtNd;
if( RES_AUTOFMT_DOCNODE != rInfo.Which() ||
!mpTxtFld || 0 == ( pTxtNd = mpTxtFld->GetpTxtNode() ) ||
&pTxtNd->GetNodes() != ((SwAutoFmtGetDocNode&)rInfo).pNodes )
return sal_True;
((SwAutoFmtGetDocNode&)rInfo).pCntntNode = pTxtNd;
return sal_False;
}
bool SwFmtFld::IsFldInDoc() const
{
return mpTxtFld != NULL
&& mpTxtFld->IsFldInDoc();
}
sal_Bool SwFmtFld::IsProtect() const
{
return mpTxtFld != NULL
&& mpTxtFld->GetpTxtNode() != NULL
&& mpTxtFld->GetpTxtNode()->IsProtect();
}
SwTxtFld::SwTxtFld(
SwFmtFld & rAttr,
xub_StrLen const nStartPos,
const bool bIsClipboardDoc )
: SwTxtAttr( rAttr, nStartPos )
, m_aExpand( rAttr.GetField()->ExpandField( bIsClipboardDoc ) )
, m_pTxtNode( NULL )
{
rAttr.SetTxtFld( *this );
SetHasDummyChar(true);
}
SwTxtFld::~SwTxtFld( )
{
SwFmtFld & rFmtFld( static_cast<SwFmtFld &>(GetAttr()) );
if ( this == rFmtFld.GetTxtFld() )
{
rFmtFld.ClearTxtFld();
}
}
bool SwTxtFld::IsFldInDoc() const
{
return GetpTxtNode() != NULL
&& GetpTxtNode()->GetNodes().IsDocNodes();
}
void SwTxtFld::ExpandTxtFld( const bool bForceNotify ) const
{
ASSERT( m_pTxtNode, "SwTxtFld: where is my TxtNode?" );
const SwField* pFld = GetFmtFld().GetField();
const 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
// 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() ) )
{
if( m_pTxtNode->CalcHiddenParaField() )
{
m_pTxtNode->ModifyNotification( 0, 0 );
}
if ( !bForceNotify )
{
// done, if no further notification forced.
return;
}
}
}
m_aExpand = aNewExpand;
const_cast<SwTxtFld*>(this)->NotifyContentChange( const_cast<SwFmtFld&>(GetFmtFld()) );
}
void SwTxtFld::CopyTxtFld( SwTxtFld *pDest ) const
{
ASSERT( m_pTxtNode, "SwTxtFld: where is my TxtNode?" );
ASSERT( pDest->m_pTxtNode, "SwTxtFld: where is pDest's TxtNode?" );
IDocumentFieldsAccess* pIDFA = m_pTxtNode->getIDocumentFieldsAccess();
IDocumentFieldsAccess* pDestIDFA = pDest->m_pTxtNode->getIDocumentFieldsAccess();
SwFmtFld& rDestFmtFld = (SwFmtFld&)pDest->GetFmtFld();
const sal_uInt16 nFldWhich = rDestFmtFld.GetField()->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( *rDestFmtFld.GetField()->GetTyp() );
}
// Sonderbehandlung fuer DDE-Felder
if( RES_DDEFLD == nFldWhich )
{
if( rDestFmtFld.GetTxtFld() )
{
((SwDDEFieldType*)rDestFmtFld.GetField()->GetTyp())->DecRefCnt();
}
((SwDDEFieldType*)pFldType)->IncRefCnt();
}
ASSERT( pFldType, "unbekannter FieldType" );
pFldType->Add( &rDestFmtFld ); // ummelden
rDestFmtFld.GetField()->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*)rDestFmtFld.GetField())->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*)rDestFmtFld.GetField())->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);
}
}
/*static*/
void SwTxtFld::GetPamForTxtFld(
const SwTxtFld& rTxtFld,
boost::shared_ptr< SwPaM >& rPamForTxtFld )
{
if ( rTxtFld.GetpTxtNode() == NULL )
{
ASSERT( false, "<SwTxtFld::GetPamForField> - missing <SwTxtNode>" );
return;
}
const SwTxtNode& rTxtNode = rTxtFld.GetTxtNode();
rPamForTxtFld.reset( new SwPaM( rTxtNode,
( (rTxtFld.End() != NULL) ? *(rTxtFld.End()) : ( *(rTxtFld.GetStart()) + 1 ) ),
rTxtNode,
*(rTxtFld.GetStart()) ) );
}
/*static*/
void SwTxtFld::DeleteTxtFld( const SwTxtFld& rTxtFld )
{
if ( rTxtFld.GetpTxtNode() != NULL )
{
boost::shared_ptr< SwPaM > pPamForTxtFld;
GetPamForTxtFld( rTxtFld, pPamForTxtFld );
if ( pPamForTxtFld.get() != NULL )
{
rTxtFld.GetTxtNode().GetDoc()->DeleteAndJoin( *pPamForTxtFld );
}
}
}
// input field in-place editing
SwTxtInputFld::SwTxtInputFld(
SwFmtFld & rAttr,
xub_StrLen const nStart,
xub_StrLen const nEnd,
const bool bIsClipboardDoc )
: SwTxtFld( rAttr, nStart, bIsClipboardDoc )
, m_nEnd( nEnd )
, m_bLockNotifyContentChange( false )
{
SetHasDummyChar( false );
SetHasContent( true );
SetDontExpand( true );
SetLockExpandFlag( true );
SetDontExpandStartAttr( true );
SetNesting( true );
}
SwTxtInputFld::~SwTxtInputFld()
{
}
xub_StrLen* SwTxtInputFld::GetEnd()
{
return &m_nEnd;
}
void SwTxtInputFld::LockNotifyContentChange()
{
m_bLockNotifyContentChange = true;
}
void SwTxtInputFld::UnlockNotifyContentChange()
{
m_bLockNotifyContentChange = false;
}
void SwTxtInputFld::NotifyContentChange( SwFmtFld& rFmtFld )
{
if ( !m_bLockNotifyContentChange )
{
LockNotifyContentChange();
SwTxtFld::NotifyContentChange( rFmtFld );
UpdateTextNodeContent( GetFieldContent() );
UnlockNotifyContentChange();
}
}
const String SwTxtInputFld::GetFieldContent() const
{
return GetFmtFld().GetField()->ExpandField(false);
}
void SwTxtInputFld::UpdateFieldContent()
{
if ( IsFldInDoc()
&& (*GetStart()) != (*End()) )
{
ASSERT( (*End()) - (*GetStart()) >= 2,
"<SwTxtInputFld::UpdateFieldContent()> - Are CH_TXT_ATR_INPUTFIELDSTART and/or CH_TXT_ATR_INPUTFIELDEND missing?" );
// skip CH_TXT_ATR_INPUTFIELDSTART character
const xub_StrLen nIdx = (*GetStart()) + 1;
// skip CH_TXT_ATR_INPUTFIELDEND character
const xub_StrLen nLen = static_cast<xub_StrLen>(std::max( 0, ( (*End()) - 1 - nIdx ) ));
const String aNewFieldContent = GetTxtNode().GetExpandTxt( nIdx, nLen );
const SwInputField* pInputFld = dynamic_cast<const SwInputField*>(GetFmtFld().GetField());
ASSERT( pInputFld != NULL,
"<SwTxtInputFld::GetContent()> - Missing <SwInputFld> instance!" );
if ( pInputFld != NULL )
{
const_cast<SwInputField*>(pInputFld)->applyFieldContent( aNewFieldContent );
// trigger update of fields for scenarios in which the Input Field's content is part of e.g. a table formula
GetTxtNode().GetDoc()->GetUpdtFlds().SetFieldsDirty( sal_True );
}
}
}
void SwTxtInputFld::UpdateTextNodeContent( const String& rNewContent )
{
if ( !IsFldInDoc() )
{
ASSERT( false, "<SwTxtInputFld::UpdateTextNodeContent(..)> - misusage as Input Field is not in document content." );
return;
}
ASSERT( (*End()) - (*GetStart()) >= 2,
"<SwTxtInputFld::UpdateTextNodeContent(..)> - Are CH_TXT_ATR_INPUTFIELDSTART and/or CH_TXT_ATR_INPUTFIELDEND missing?" );
// skip CH_TXT_ATR_INPUTFIELDSTART character
const xub_StrLen nIdx = (*GetStart()) + 1;
// skip CH_TXT_ATR_INPUTFIELDEND character
const xub_StrLen nDelLen = static_cast<xub_StrLen>(std::max( 0, ( (*End()) - 1 - nIdx ) ));
SwIndex aIdx( &GetTxtNode(), nIdx );
GetTxtNode().ReplaceText( aIdx, nDelLen, rNewContent );
}
// text annotation field
SwTxtAnnotationFld::SwTxtAnnotationFld(
SwFmtFld & rAttr,
xub_StrLen const nStart,
const bool bIsClipboardDoc )
: SwTxtFld( rAttr, nStart, bIsClipboardDoc )
{
}
SwTxtAnnotationFld::~SwTxtAnnotationFld()
{
}
::sw::mark::IMark* SwTxtAnnotationFld::GetAnnotationMark(
SwDoc* pDoc ) const
{
const SwPostItField* pPostItField = dynamic_cast<const SwPostItField*>(GetFmtFld().GetField());
ASSERT( pPostItField != NULL, "<SwTxtAnnotationFld::GetAnnotationMark()> - field missing" );
if ( pPostItField == NULL )
{
return NULL;
}
if ( pDoc == NULL )
{
pDoc = static_cast<const SwPostItFieldType*>(pPostItField->GetTyp())->GetDoc();
}
ASSERT( pDoc != NULL, "<SwTxtAnnotationFld::GetAnnotationMark()> - missing document" );
if ( pDoc == NULL )
{
return NULL;
}
IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess();
IDocumentMarkAccess::const_iterator_t pMark = pMarksAccess->findAnnotationMark( pPostItField->GetName() );
return pMark != pMarksAccess->getAnnotationMarksEnd()
? pMark->get()
: NULL;
}