Files
libreoffice/sw/source/core/doc/docfly.cxx

1086 lines
37 KiB
C++
Raw Normal View History

2000-09-18 23:08:29 +00:00
/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
2000-09-18 23:08:29 +00:00
*
* $RCSfile: docfly.cxx,v $
2000-09-18 23:08:29 +00:00
*
* $Revision: 1.28 $
2000-09-18 23:08:29 +00:00
*
* last change: $Author: rt $ $Date: 2006-07-25 12:29:45 $
2000-09-18 23:08:29 +00:00
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
2000-09-18 23:08:29 +00:00
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
2000-09-18 23:08:29 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
2000-09-18 23:08:29 +00:00
*
* This library 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 for more details.
2000-09-18 23:08:29 +00:00
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
2000-09-18 23:08:29 +00:00
*
************************************************************************/
#pragma hdrstop
#ifndef _HINTIDS_HXX
#include <hintids.hxx>
#endif
#ifndef _SFXITEMITER_HXX //autogen
#include <svtools/itemiter.hxx>
#endif
#ifndef _SVDOBJ_HXX //autogen
#include <svx/svdobj.hxx>
#endif
#ifndef _SVDPAGE_HXX //autogen
#include <svx/svdpage.hxx>
#endif
#ifndef _SVDMODEL_HXX //autogen
#include <svx/svdmodel.hxx>
#endif
#ifndef _SVDCAPT_HXX //autogen
#include <svx/svdocapt.hxx>
#endif
#ifndef _SVDMARK_HXX //autogen
#include <svx/svdmark.hxx>
#endif
#ifndef _FMTFSIZE_HXX //autogen
#include <fmtfsize.hxx>
#endif
#ifndef _FMTORNT_HXX //autogen
#include <fmtornt.hxx>
#endif
#ifndef _FMTSRND_HXX //autogen
#include <fmtsrnd.hxx>
#endif
#ifndef _DCONTACT_HXX //autogen
#include <dcontact.hxx>
#endif
#include <ndgrf.hxx>
#ifndef _DOC_HXX //autogen
#include <doc.hxx>
#endif
#ifndef _NDINDEX_HXX //autogen
#include <ndindex.hxx>
#endif
#ifndef _NODE_HXX //autogen
#include <node.hxx>
#endif
#ifndef _DOCARY_HXX
#include <docary.hxx>
#endif
#ifndef _FMTCNTNT_HXX //autogen
#include <fmtcntnt.hxx>
#endif
#ifndef _FMTANCHR_HXX //autogen
#include <fmtanchr.hxx>
#endif
#ifndef _TXTFLCNT_HXX //autogen
#include <txtflcnt.hxx>
#endif
#ifndef _FMTFLCNT_HXX //autogen
#include <fmtflcnt.hxx>
#endif
#ifndef _FMTORNT_HXX //autogen
#include <fmtornt.hxx>
#endif
#ifndef _TXTFRM_HXX //autogen
#include <txtfrm.hxx>
#endif
#ifndef _PAGEFRM_HXX //autogen
#include <pagefrm.hxx>
#endif
#ifndef _ROOTFRM_HXX //autogen
#include <rootfrm.hxx>
#endif
#ifndef _FLYFRMS_HXX //autogen
#include <flyfrms.hxx>
#endif
#ifndef _FRMTOOL_HXX //autogen
#include <frmtool.hxx>
#endif
#ifndef _FRMFMT_HXX //autogen
#include <frmfmt.hxx>
#endif
#ifndef _NDTXT_HXX //autogen
#include <ndtxt.hxx>
#endif
#ifndef _PAM_HXX //autogen
#include <pam.hxx>
#endif
#ifndef _TBLSEL_HXX //autogen
#include <tblsel.hxx>
#endif
#ifndef _SWUNDO_HXX //autogen
#include <swundo.hxx>
#endif
#ifndef _SWTABLE_HXX //autogen
#include <swtable.hxx>
#endif
#ifndef _CRSTATE_HXX
#include <crstate.hxx>
#endif
#ifndef _UNDOBJ_HXX //autogen
#include <undobj.hxx>
#endif
#ifndef _FMTCNCT_HXX //autogen
#include <fmtcnct.hxx>
#endif
#ifndef _DFLYOBJ_HXX
#include <dflyobj.hxx>
#endif
2000-09-18 23:08:29 +00:00
extern USHORT GetHtmlMode( const SwDocShell* );
/*-----------------17.02.98 08:35-------------------
--------------------------------------------------*/
USHORT SwDoc::GetFlyCount(FlyCntType eType ) const
{
const SwSpzFrmFmts& rFmts = *GetSpzFrmFmts();
USHORT nSize = rFmts.Count();
USHORT nCount = 0;
const SwNodeIndex* pIdx;
for ( USHORT i = 0; i < nSize; i++)
{
const SwFrmFmt* pFlyFmt = rFmts[ i ];
if( RES_FLYFRMFMT == pFlyFmt->Which()
&& 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() )
&& pIdx->GetNodes().IsDocNodes()
)
{
const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ];
switch( eType )
{
case FLYCNTTYPE_FRM:
if(!pNd->IsNoTxtNode())
nCount++;
break;
case FLYCNTTYPE_GRF:
if( pNd->IsGrfNode() )
nCount++;
break;
case FLYCNTTYPE_OLE:
if(pNd->IsOLENode())
nCount++;
break;
default:
nCount++;
}
}
}
return nCount;
}
/*-----------------17.02.98 08:35-------------------
--------------------------------------------------*/
SwFrmFmt* SwDoc::GetFlyNum( USHORT nIdx, FlyCntType eType )
{
SwSpzFrmFmts& rFmts = *GetSpzFrmFmts();
SwFrmFmt* pRetFmt = 0;
USHORT nSize = rFmts.Count();
const SwNodeIndex* pIdx;
USHORT nCount = 0;
for( USHORT i = 0; !pRetFmt && i < nSize; ++i )
{
SwFrmFmt* pFlyFmt = rFmts[ i ];
if( RES_FLYFRMFMT == pFlyFmt->Which()
&& 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() )
&& pIdx->GetNodes().IsDocNodes()
)
{
const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ];
switch( eType )
{
case FLYCNTTYPE_FRM:
if( !pNd->IsNoTxtNode() && nIdx == nCount++)
pRetFmt = pFlyFmt;
break;
case FLYCNTTYPE_GRF:
if(pNd->IsGrfNode() && nIdx == nCount++ )
pRetFmt = pFlyFmt;
break;
case FLYCNTTYPE_OLE:
if(pNd->IsOLENode() && nIdx == nCount++)
pRetFmt = pFlyFmt;
break;
default:
if(nIdx == nCount++)
pRetFmt = pFlyFmt;
}
}
}
return pRetFmt;
}
/* */
/***********************************************************************
#* Class : SwDoc
#* Methode : SetFlyFrmAnchor
#* Beschreibung: Das Ankerattribut des FlyFrms aendert sich.
#* Datum : MA 01. Feb. 94
#* Update : JP 09.03.98
#***********************************************************************/
Point lcl_FindAnchorLayPos( SwDoc& rDoc, const SwFmtAnchor& rAnch,
const SwFrmFmt* pFlyFmt )
{
Point aRet;
if( rDoc.GetRootFrm() )
switch( rAnch.GetAnchorId() )
{
case FLY_IN_CNTNT:
if( pFlyFmt && rAnch.GetCntntAnchor() )
{
const SwFrm* pOld = ((SwFlyFrmFmt*)pFlyFmt)->GetFrm( &aRet, FALSE );
if( pOld )
aRet = pOld->Frm().Pos();
}
break;
case FLY_AT_CNTNT:
case FLY_AUTO_CNTNT: // LAYER_IMPL
if( rAnch.GetCntntAnchor() )
{
const SwPosition *pPos = rAnch.GetCntntAnchor();
const SwCntntNode* pNd = pPos->nNode.GetNode().GetCntntNode();
const SwFrm* pOld = pNd ? pNd->GetFrm( &aRet, 0, FALSE ) : 0;
if( pOld )
aRet = pOld->Frm().Pos();
}
break;
case FLY_AT_FLY: // LAYER_IMPL
if( rAnch.GetCntntAnchor() )
{
const SwFlyFrmFmt* pFmt = (SwFlyFrmFmt*)rAnch.GetCntntAnchor()->
nNode.GetNode().GetFlyFmt();
const SwFrm* pOld = pFmt ? pFmt->GetFrm( &aRet, FALSE ) : 0;
if( pOld )
aRet = pOld->Frm().Pos();
}
break;
case FLY_PAGE:
{
USHORT nPgNum = rAnch.GetPageNum();
const SwPageFrm *pPage = (SwPageFrm*)rDoc.GetRootFrm()->Lower();
for( USHORT i = 1; (i <= nPgNum) && pPage; ++i,
pPage = (const SwPageFrm*)pPage->GetNext() )
if( i == nPgNum )
{
aRet = pPage->Frm().Pos();
break;
}
}
break;
default:
break;
2000-09-18 23:08:29 +00:00
}
return aRet;
}
#define MAKEFRMS 0
#define IGNOREANCHOR 1
#define DONTMAKEFRMS 2
sal_Int8 SwDoc::SetFlyFrmAnchor( SwFrmFmt& rFmt, SfxItemSet& rSet, BOOL bNewFrms )
2000-09-18 23:08:29 +00:00
{
//Ankerwechsel sind fast immer in alle 'Richtungen' erlaubt.
//Ausnahme: Absatz- bzw. Zeichengebundene Rahmen duerfen wenn sie in
//Kopf-/Fusszeilen stehen nicht Seitengebunden werden.
const SwFmtAnchor &rOldAnch = rFmt.GetAnchor();
const RndStdIds nOld = rOldAnch.GetAnchorId();
SwFmtAnchor aNewAnch( (SwFmtAnchor&)rSet.Get( RES_ANCHOR ) );
RndStdIds nNew = aNewAnch.GetAnchorId();
// ist der neue ein gueltiger Anker?
if( !aNewAnch.GetCntntAnchor() && (FLY_AT_FLY == nNew ||
FLY_AT_CNTNT == nNew || FLY_IN_CNTNT == nNew ||
FLY_AUTO_CNTNT == nNew ))
return IGNOREANCHOR;
if( nOld == nNew )
return DONTMAKEFRMS;
2000-09-18 23:08:29 +00:00
Point aOldAnchorPos( ::lcl_FindAnchorLayPos( *this, rOldAnch, &rFmt ));
Point aNewAnchorPos( ::lcl_FindAnchorLayPos( *this, aNewAnch, 0 ));
//Die alten Frms vernichten. Dabei werden die Views implizit gehidet und
//doppeltes hiden waere so eine art Show!
rFmt.DelFrms();
if( FLY_IN_CNTNT == nOld )
{
//Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet
//werden. Leider reisst dies neben den Frms auch noch das Format mit
//in sein Grab. Um dass zu unterbinden loesen wir vorher die
//Verbindung zwischen Attribut und Format.
const SwPosition *pPos = rOldAnch.GetCntntAnchor();
SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode();
ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." );
const xub_StrLen nIdx = pPos->nContent.GetIndex();
SwTxtAttr * pHnt = pTxtNode->GetTxtAttr( nIdx, RES_TXTATR_FLYCNT );
#ifndef PRODUCT
ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT,
"Missing FlyInCnt-Hint." );
ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == &rFmt,
"Wrong TxtFlyCnt-Hint." );
#endif
((SwFmtFlyCnt&)pHnt->GetFlyCnt()).SetFlyFmt();
//Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet
//werden.
pTxtNode->Delete( RES_TXTATR_FLYCNT, nIdx, nIdx );
}
//Endlich kann das Attribut gesetzt werden. Es muss das erste Attribut
//sein; Undo depends on it!
rFmt.SetAttr( aNewAnch );
//Positionskorrekturen
const SfxPoolItem* pItem;
switch( nNew )
{
case FLY_IN_CNTNT:
//Wenn keine Positionsattribute hereinkommen, dann muss dafuer
//gesorgt werden, das keine unerlaubte automatische Ausrichtung
//bleibt.
{
const SwPosition *pPos = aNewAnch.GetCntntAnchor();
SwTxtNode *pNd = pPos->nNode.GetNode().GetTxtNode();
ASSERT( pNd, "Crsr steht nicht auf TxtNode." );
pNd->Insert( SwFmtFlyCnt( (SwFlyFrmFmt*)&rFmt ),
pPos->nContent.GetIndex(), 0 );
}
if( SFX_ITEM_SET != rSet.GetItemState( RES_VERT_ORIENT, FALSE, &pItem ))
{
SwFmtVertOrient aOldV( rFmt.GetVertOrient() );
BOOL bSet = TRUE;
switch( aOldV.GetVertOrient() )
{
case VERT_LINE_TOP: aOldV.SetVertOrient( VERT_TOP ); break;
case VERT_LINE_CENTER: aOldV.SetVertOrient( VERT_CENTER); break;
case VERT_LINE_BOTTOM: aOldV.SetVertOrient( VERT_BOTTOM); break;
case VERT_NONE: aOldV.SetVertOrient( VERT_CENTER); break;
default:
bSet = FALSE;
}
if( bSet )
rSet.Put( aOldV );
}
break;
case FLY_AT_CNTNT:
case FLY_AUTO_CNTNT: // LAYER_IMPL
case FLY_AT_FLY: // LAYER_IMPL
case FLY_PAGE:
{
//Wenn keine Positionsattribute hereinschneien korrigieren wir
//die Position so, dass die Dokumentkoordinaten des Flys erhalten
//bleiben.
//Chg: Wenn sich in den Positionsattributen lediglich die
//Ausrichtung veraendert (FRAME vs. PRTAREA), dann wird die
//Position ebenfalls korrigiert.
if( SFX_ITEM_SET != rSet.GetItemState( RES_HORI_ORIENT, FALSE, &pItem ))
pItem = 0;
SwFmtHoriOrient aOldH( rFmt.GetHoriOrient() );
if( HORI_NONE == aOldH.GetHoriOrient() && ( !pItem ||
aOldH.GetPos() == ((SwFmtHoriOrient*)pItem)->GetPos() ))
{
SwTwips nPos = FLY_IN_CNTNT == nOld ? 0 : aOldH.GetPos();
nPos += aOldAnchorPos.X() - aNewAnchorPos.X();
if( pItem )
{
SwFmtHoriOrient* pH = (SwFmtHoriOrient*)pItem;
aOldH.SetHoriOrient( pH->GetHoriOrient() );
aOldH.SetRelationOrient( pH->GetRelationOrient() );
}
aOldH.SetPos( nPos );
rSet.Put( aOldH );
}
if( SFX_ITEM_SET != rSet.GetItemState( RES_VERT_ORIENT, FALSE, &pItem ))
pItem = 0;
SwFmtVertOrient aOldV( rFmt.GetVertOrient() );
// OD 2004-05-14 #i28922# - correction: compare <aOldV.GetVertOrient()
// with <VERT_NONE>
if( VERT_NONE == aOldV.GetVertOrient() && (!pItem ||
2000-09-18 23:08:29 +00:00
aOldV.GetPos() == ((SwFmtVertOrient*)pItem)->GetPos() ) )
{
SwTwips nPos = FLY_IN_CNTNT == nOld ? 0 : aOldV.GetPos();
nPos += aOldAnchorPos.Y() - aNewAnchorPos.Y();
if( pItem )
{
SwFmtVertOrient* pV = (SwFmtVertOrient*)pItem;
aOldV.SetVertOrient( pV->GetVertOrient() );
aOldV.SetRelationOrient( pV->GetRelationOrient() );
}
aOldV.SetPos( nPos );
rSet.Put( aOldV );
}
}
break;
default:
break;
2000-09-18 23:08:29 +00:00
}
if( bNewFrms )
rFmt.MakeFrms();
return MAKEFRMS;
2000-09-18 23:08:29 +00:00
}
BOOL SwDoc::SetFlyFrmAttr( SwFrmFmt& rFlyFmt, SfxItemSet& rSet )
{
if( !rSet.Count() )
return FALSE;
_UndoFmtAttr* pSaveUndo = 0;
const bool bDoesUndo = DoesUndo();
2000-09-18 23:08:29 +00:00
if( DoesUndo() )
{
ClearRedo();
pSaveUndo = new _UndoFmtAttr( rFlyFmt );
// --> FME 2004-10-13 #i32968#
// Inserting columns in the frame causes MakeFrmFmt to put two
// objects of type SwUndoFrmFmt on the undo stack. We don't want them.
DoUndo( FALSE );
// <--
2000-09-18 23:08:29 +00:00
}
//Ist das Ankerattribut dabei? Falls ja ueberlassen wir die Verarbeitung
//desselben einer Spezialmethode. Sie Returnt TRUE wenn der Fly neu
//erzeugt werden muss (z.B. weil ein Wechsel des FlyTyps vorliegt).
sal_Int8 nMakeFrms = SFX_ITEM_SET == rSet.GetItemState( RES_ANCHOR, FALSE )?
SetFlyFrmAnchor( rFlyFmt, rSet, FALSE ) : DONTMAKEFRMS;
2000-09-18 23:08:29 +00:00
const SfxPoolItem* pItem;
SfxItemIter aIter( rSet );
SfxItemSet aTmpSet( GetAttrPool(), aFrmFmtSetRange );
USHORT nWhich = aIter.GetCurItem()->Which();
do {
switch( nWhich )
{
case RES_FILL_ORDER:
case RES_BREAK:
case RES_PAGEDESC:
case RES_CNTNT:
case RES_FOOTER:
ASSERT( !this, ":-) Unbekanntes Attribut fuer Fly." );
// kein break;
case RES_CHAIN:
rSet.ClearItem( nWhich );
break;
case RES_ANCHOR:
if( DONTMAKEFRMS != nMakeFrms )
break;
2000-09-18 23:08:29 +00:00
default:
if( !IsInvalidItem( aIter.GetCurItem() ) && ( SFX_ITEM_SET !=
rFlyFmt.GetAttrSet().GetItemState( nWhich, TRUE, &pItem ) ||
*pItem != *aIter.GetCurItem() ))
aTmpSet.Put( *aIter.GetCurItem() );
break;
}
if( aIter.IsAtEnd() )
break;
} while( 0 != ( nWhich = aIter.NextItem()->Which() ) );
if( aTmpSet.Count() )
rFlyFmt.SetAttr( aTmpSet );
if( MAKEFRMS == nMakeFrms )
2000-09-18 23:08:29 +00:00
rFlyFmt.MakeFrms();
if( pSaveUndo )
{
// --> FME 2004-10-13 #i32968#
DoUndo( bDoesUndo );
// <--
2000-09-18 23:08:29 +00:00
if( pSaveUndo->pUndo )
AppendUndo( pSaveUndo->pUndo );
delete pSaveUndo;
}
SetModified();
return aTmpSet.Count() || MAKEFRMS == nMakeFrms;
2000-09-18 23:08:29 +00:00
}
/***************************************************************************
* Methode : BOOL SwDoc::SetFrmFmtToFly( SwFlyFrm&, SwFrmFmt& )
* Beschreibung:
* Erstellt : OK 14.04.94 15:40
* Aenderung : JP 23.04.98
***************************************************************************/
BOOL SwDoc::SetFrmFmtToFly( SwFrmFmt& rFmt, SwFrmFmt& rNewFmt,
SfxItemSet* pSet, BOOL bKeepOrient )
{
BOOL bChgAnchor = FALSE, bFrmSz = FALSE;
const SwFmtFrmSize aFrmSz( rFmt.GetFrmSize() );
const SwFmtVertOrient aVert( rFmt.GetVertOrient() );
const SwFmtHoriOrient aHori( rFmt.GetHoriOrient() );
SwUndoSetFlyFmt* pUndo = 0;
if( DoesUndo() )
{
ClearRedo();
AppendUndo( pUndo = new SwUndoSetFlyFmt( rFmt, rNewFmt ) );
// --> FME 2004-10-13 #i32968#
// Inserting columns in the section causes MakeFrmFmt to put two
// objects of type SwUndoFrmFmt on the undo stack. We don't want them.
DoUndo( FALSE );
// <--
2000-09-18 23:08:29 +00:00
}
//Erstmal die Spalten setzen, sonst gibts nix als Aerger mit dem
//Set/Reset/Abgleich usw.
const SfxPoolItem* pItem;
if( SFX_ITEM_SET != rNewFmt.GetAttrSet().GetItemState( RES_COL ))
rFmt.ResetAttr( RES_COL );
if( rFmt.DerivedFrom() != &rNewFmt )
{
rFmt.SetDerivedFrom( &rNewFmt );
// 1. wenn nicht automatisch -> ignorieren, sonst -> wech
// 2. wech damit, MB!
if( SFX_ITEM_SET == rNewFmt.GetAttrSet().GetItemState( RES_FRM_SIZE, FALSE ))
{
rFmt.ResetAttr( RES_FRM_SIZE );
bFrmSz = TRUE;
}
const SfxItemSet* pAsk = pSet;
if( !pAsk ) pAsk = &rNewFmt.GetAttrSet();
if( SFX_ITEM_SET == pAsk->GetItemState( RES_ANCHOR, FALSE, &pItem )
&& ((SwFmtAnchor*)pItem)->GetAnchorId() !=
rFmt.GetAnchor().GetAnchorId() )
{
if( pSet )
bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, *pSet, FALSE );
2000-09-18 23:08:29 +00:00
else
{
//JP 23.04.98: muss den FlyFmt-Range haben, denn im SetFlyFrmAnchor
// werden Attribute in diesen gesetzt!
SfxItemSet aFlySet( *rNewFmt.GetAttrSet().GetPool(),
rNewFmt.GetAttrSet().GetRanges() );
aFlySet.Put( *pItem );
bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, aFlySet, FALSE);
2000-09-18 23:08:29 +00:00
}
}
}
//Hori und Vert nur dann resetten, wenn in der Vorlage eine
//automatische Ausrichtung eingestellt ist, anderfalls den alten Wert
//wieder hineinstopfen.
//JP 09.06.98: beim Update der RahmenVorlage sollte der Fly NICHT
// seine Orientierng verlieren (diese wird nicht geupdatet!)
//OS: #96584# HORI_NONE and VERT_NONE are allowed now
if (!bKeepOrient)
2000-09-18 23:08:29 +00:00
{
rFmt.ResetAttr(RES_VERT_ORIENT);
rFmt.ResetAttr(RES_HORI_ORIENT);
2000-09-18 23:08:29 +00:00
}
rFmt.ResetAttr( RES_PRINT, RES_SURROUND );
rFmt.ResetAttr( RES_LR_SPACE, RES_UL_SPACE );
rFmt.ResetAttr( RES_BACKGROUND, RES_COL );
rFmt.ResetAttr( RES_URL, RES_EDIT_IN_READONLY );
if( !bFrmSz )
rFmt.SetAttr( aFrmSz );
if( bChgAnchor )
rFmt.MakeFrms();
if( pUndo )
rFmt.Remove( pUndo );
SetModified();
// --> FME 2004-10-13 #i32968#
if ( pUndo )
DoUndo( TRUE );
// <--
2000-09-18 23:08:29 +00:00
return bChgAnchor;
}
void SwDoc::GetGrfNms( const SwFlyFrmFmt& rFmt, String* pGrfName,
String* pFltName ) const
{
SwNodeIndex aIdx( *rFmt.GetCntnt().GetCntntIdx(), 1 );
const SwGrfNode* pGrfNd = aIdx.GetNode().GetGrfNode();
if( pGrfNd && pGrfNd->IsLinkedFile() )
pGrfNd->GetFileFilterNms( pGrfName, pFltName );
}
/*************************************************************************
|*
|* SwDoc::ChgAnchor()
|*
|* Ersterstellung MA 10. Jan. 95
|* Letzte Aenderung JP 08.07.98
|*
*************************************************************************/
sal_Bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList,
RndStdIds _eAnchorType,
const sal_Bool _bSameOnly,
const sal_Bool _bPosCorr )
2000-09-18 23:08:29 +00:00
{
ASSERT( GetRootFrm(), "Ohne Layout geht gar nichts" );
if ( !_rMrkList.GetMarkCount() ||
_rMrkList.GetMark( 0 )->GetMarkedSdrObj()->GetUpGroup() )
{
return false;
}
2000-09-18 23:08:29 +00:00
StartUndo( UNDO_INSATTR );
BOOL bUnmark = FALSE;
for ( USHORT i = 0; i < _rMrkList.GetMarkCount(); ++i )
2000-09-18 23:08:29 +00:00
{
SdrObject* pObj = _rMrkList.GetMark( i )->GetMarkedSdrObj();
if ( !pObj->ISA(SwVirtFlyDrawObj) )
2000-09-18 23:08:29 +00:00
{
SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
2000-09-18 23:08:29 +00:00
// OD 27.06.2003 #108784# - consider, that drawing object has
// no user call. E.g.: a 'virtual' drawing object is disconnected by
// the anchor type change of the 'master' drawing object.
// Continue with next selected object and assert, if this isn't excepted.
if ( !pContact )
{
#ifndef PRODUCT
bool bNoUserCallExcepted =
pObj->ISA(SwDrawVirtObj) &&
!static_cast<SwDrawVirtObj*>(pObj)->IsConnected();
ASSERT( bNoUserCallExcepted, "SwDoc::ChgAnchor(..) - no contact at selected drawing object" );
#endif
continue;
}
// OD 2004-03-29 #i26791#
const SwFrm* pOldAnchorFrm = pContact->GetAnchorFrm( pObj );
const SwFrm* pNewAnchorFrm = pOldAnchorFrm;
2000-09-18 23:08:29 +00:00
// --> OD 2006-03-01 #i54336#
// Instead of only keeping the index position for an as-character
// anchored object the complete <SwPosition> is kept, because the
// anchor index position could be moved, if the object again is
// anchored as character.
// xub_StrLen nIndx = STRING_NOTFOUND;
const SwPosition* pOldAsCharAnchorPos( 0L );
const RndStdIds eOldAnchorType = pContact->GetAnchorId();
if ( !_bSameOnly && eOldAnchorType == FLY_IN_CNTNT )
2000-09-18 23:08:29 +00:00
{
pOldAsCharAnchorPos = new SwPosition( pContact->GetCntntAnchor() );
2000-09-18 23:08:29 +00:00
}
// <--
2000-09-18 23:08:29 +00:00
if ( _bSameOnly )
_eAnchorType = eOldAnchorType;
2000-09-18 23:08:29 +00:00
const bool bChanges = FLY_IN_CNTNT != _eAnchorType;
SwFmtAnchor aNewAnch( _eAnchorType );
Rectangle aObjRect( pContact->GetAnchoredObj( pObj )->GetObjRect().SVRect() );
const Point aPt( aObjRect.TopLeft() );
2000-09-18 23:08:29 +00:00
switch ( _eAnchorType )
2000-09-18 23:08:29 +00:00
{
case FLY_AT_CNTNT:
case FLY_AUTO_CNTNT:
{
const Point aNewPoint = pOldAnchorFrm &&
( pOldAnchorFrm->IsVertical() ||
pOldAnchorFrm->IsRightToLeft() )
? aObjRect.TopRight()
: aPt;
// OD 18.06.2003 #108784# - allow drawing objects in header/footer
pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aNewPoint, false );
if ( pNewAnchorFrm->IsTxtFrm() && ((SwTxtFrm*)pNewAnchorFrm)->IsFollow() )
{
pNewAnchorFrm = ((SwTxtFrm*)pNewAnchorFrm)->FindMaster();
}
if ( pNewAnchorFrm->IsProtected() )
{
pNewAnchorFrm = 0;
}
else
{
SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() );
aNewAnch.SetType( _eAnchorType );
aNewAnch.SetAnchor( &aPos );
}
2000-09-18 23:08:29 +00:00
}
break;
case FLY_AT_FLY: // LAYER_IMPL
{
//Ausgehend von der linken oberen Ecke des Fly den
//dichtesten SwFlyFrm suchen.
SwFrm *pTxtFrm;
{
SwCrsrMoveState aState( MV_SETONLYTEXT );
SwPosition aPos( GetNodes() );
Point aPoint( aPt );
aPoint.X() -= 1;
GetRootFrm()->GetCrsrOfst( &aPos, aPoint, &aState );
// OD 20.06.2003 #108784# - consider that drawing objects
// can be in header/footer. Thus, <GetFrm()> by left-top-corner
2000-09-18 23:08:29 +00:00
pTxtFrm = aPos.nNode.GetNode().
GetCntntNode()->GetFrm( &aPt, 0, FALSE );
2000-09-18 23:08:29 +00:00
}
const SwFrm *pTmp = ::FindAnchor( pTxtFrm, aPt );
pNewAnchorFrm = pTmp->FindFlyFrm();
if( pNewAnchorFrm && !pNewAnchorFrm->IsProtected() )
2000-09-18 23:08:29 +00:00
{
const SwFrmFmt *pTmpFmt = ((SwFlyFrm*)pNewAnchorFrm)->GetFmt();
2000-09-18 23:08:29 +00:00
const SwFmtCntnt& rCntnt = pTmpFmt->GetCntnt();
SwPosition aPos( *rCntnt.GetCntntIdx() );
aNewAnch.SetAnchor( &aPos );
break;
}
aNewAnch.SetType( FLY_PAGE );
// no break
}
case FLY_PAGE:
{
pNewAnchorFrm = GetRootFrm()->Lower();
while ( pNewAnchorFrm && !pNewAnchorFrm->Frm().IsInside( aPt ) )
pNewAnchorFrm = pNewAnchorFrm->GetNext();
if ( !pNewAnchorFrm )
2000-09-18 23:08:29 +00:00
continue;
aNewAnch.SetPageNum( ((SwPageFrm*)pNewAnchorFrm)->GetPhyPageNum());
2000-09-18 23:08:29 +00:00
}
break;
case FLY_IN_CNTNT:
if( _bSameOnly ) // Positions/Groessenaenderung
2000-09-18 23:08:29 +00:00
{
if( !pOldAnchorFrm )
2000-09-18 23:08:29 +00:00
{
pContact->ConnectToLayout();
pOldAnchorFrm = pContact->GetAnchorFrm();
2000-09-18 23:08:29 +00:00
}
((SwTxtFrm*)pOldAnchorFrm)->Prepare();
2000-09-18 23:08:29 +00:00
}
else // Ankerwechsel
{
// OD 18.06.2003 #108784# - allow drawing objects in header/footer
pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aPt, false );
if( pNewAnchorFrm->IsProtected() )
2000-09-18 23:08:29 +00:00
{
pNewAnchorFrm = 0;
2000-09-18 23:08:29 +00:00
break;
}
bUnmark = ( 0 != i );
Point aPoint( aPt );
aPoint.X() -= 1; // nicht im DrawObj landen!!
aNewAnch.SetType( FLY_IN_CNTNT );
SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() );
if ( pNewAnchorFrm->Frm().IsInside( aPoint ) )
2000-09-18 23:08:29 +00:00
{
// es muss ein TextNode gefunden werden, denn nur dort
// ist ein inhaltsgebundenes DrawObjekt zu verankern
SwCrsrMoveState aState( MV_SETONLYTEXT );
GetRootFrm()->GetCrsrOfst( &aPos, aPoint, &aState );
}
else
{
SwCntntNode &rCNd = (SwCntntNode&)
*((SwCntntFrm*)pNewAnchorFrm)->GetNode();
if ( pNewAnchorFrm->Frm().Bottom() < aPt.Y() )
2000-09-18 23:08:29 +00:00
rCNd.MakeStartIndex( &aPos.nContent );
else
rCNd.MakeEndIndex( &aPos.nContent );
}
aNewAnch.SetAnchor( &aPos );
SetAttr( aNewAnch, *pContact->GetFmt() );
// OD 2004-04-13 #i26791# - adjust vertical positioning to
// 'center to baseline'
SetAttr( SwFmtVertOrient( 0, VERT_CENTER, FRAME ), *pContact->GetFmt() );
2000-09-18 23:08:29 +00:00
SwTxtNode *pNd = aPos.nNode.GetNode().GetTxtNode();
ASSERT( pNd, "Crsr steht nicht auf TxtNode." );
pNd->Insert( SwFmtFlyCnt( pContact->GetFmt() ),
aPos.nContent.GetIndex(), 0 );
}
break;
default:
ASSERT( !this, "unexpected AnchorId." );
}
if ( (FLY_IN_CNTNT != _eAnchorType) &&
pNewAnchorFrm &&
( !_bSameOnly || pNewAnchorFrm != pOldAnchorFrm ) )
2000-09-18 23:08:29 +00:00
{
// OD 2004-04-06 #i26791# - Direct object positioning no longer
// needed. Apply of attributes (method call <SetAttr(..)>) takes
// care of the invalidation of the object position.
2000-09-18 23:08:29 +00:00
SetAttr( aNewAnch, *pContact->GetFmt() );
if ( _bPosCorr )
2000-09-18 23:08:29 +00:00
{
// --> OD 2004-08-24 #i33313# - consider not connected
// 'virtual' drawing objects
if ( pObj->ISA(SwDrawVirtObj) &&
!static_cast<SwDrawVirtObj*>(pObj)->IsConnected() )
{
SwRect aNewObjRect( aObjRect );
static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( 0L ))
->AdjustPositioningAttr( pNewAnchorFrm,
&aNewObjRect );
}
else
{
static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( pObj ))
->AdjustPositioningAttr( pNewAnchorFrm );
}
2000-09-18 23:08:29 +00:00
}
}
// --> OD 2006-03-01 #i54336#
if ( pNewAnchorFrm && pOldAsCharAnchorPos )
2000-09-18 23:08:29 +00:00
{
//Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet
//werden. Leider reisst dies neben den Frms auch noch das Format mit
//in sein Grab. Um dass zu unterbinden loesen wir vorher die
//Verbindung zwischen Attribut und Format.
const xub_StrLen nIndx( pOldAsCharAnchorPos->nContent.GetIndex() );
SwTxtNode* pTxtNode( pOldAsCharAnchorPos->nNode.GetNode().GetTxtNode() );
ASSERT( pTxtNode, "<SwDoc::ChgAnchor(..)> - missing previous anchor text node for as-character anchored object" );
ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." );
SwTxtAttr* pHnt = pTxtNode->GetTxtAttr( nIndx, RES_TXTATR_FLYCNT );
2000-09-18 23:08:29 +00:00
((SwFmtFlyCnt&)pHnt->GetFlyCnt()).SetFlyFmt();
//Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet
//werden.
pTxtNode->Delete( RES_TXTATR_FLYCNT, nIndx, nIndx );
delete pOldAsCharAnchorPos;
2000-09-18 23:08:29 +00:00
}
// <--
2000-09-18 23:08:29 +00:00
}
}
EndUndo( UNDO_END );
SetModified();
return bUnmark;
}
/* -----------------23.07.98 13:56-------------------
*
* --------------------------------------------------*/
int SwDoc::Chainable( const SwFrmFmt &rSource, const SwFrmFmt &rDest )
{
//Die Source darf noch keinen Follow haben.
const SwFmtChain &rOldChain = rSource.GetChain();
if ( rOldChain.GetNext() )
return SW_CHAIN_SOURCE_CHAINED;
//Ziel darf natuerlich nicht gleich Source sein und es
//darf keine geschlossene Kette entstehen.
const SwFrmFmt *pFmt = &rDest;
do {
if( pFmt == &rSource )
2000-09-18 23:08:29 +00:00
return SW_CHAIN_SELF;
pFmt = pFmt->GetChain().GetNext();
} while ( pFmt );
//Auch eine Verkettung von Innen nach aussen oder von aussen
//nach innen ist nicht zulaessig.
if( rDest.IsLowerOf( rSource ) || rSource .IsLowerOf( rDest ) )
return SW_CHAIN_SELF;
//Das Ziel darf noch keinen Master haben.
const SwFmtChain &rChain = rDest.GetChain();
if( rChain.GetPrev() )
return SW_CHAIN_IS_IN_CHAIN;
//Das Ziel muss leer sein.
const SwNodeIndex* pCntIdx = rDest.GetCntnt().GetCntntIdx();
if( !pCntIdx )
return SW_CHAIN_NOT_FOUND;
SwNodeIndex aNxtIdx( *pCntIdx, 1 );
const SwTxtNode* pTxtNd = aNxtIdx.GetNode().GetTxtNode();
if( !pTxtNd )
return SW_CHAIN_NOT_FOUND;
const ULONG nFlySttNd = pCntIdx->GetIndex();
if( 2 != ( pCntIdx->GetNode().EndOfSectionIndex() - nFlySttNd ) ||
pTxtNd->GetTxt().Len() )
return SW_CHAIN_NOT_EMPTY;
USHORT nArrLen = GetSpzFrmFmts()->Count();
for( USHORT n = 0; n < nArrLen; ++n )
{
const SwFmtAnchor& rAnchor = (*GetSpzFrmFmts())[ n ]->GetAnchor();
ULONG nTstSttNd;
// OD 11.12.2003 #i20622# - to-frame anchored objects are allowed.
if ( ( rAnchor.GetAnchorId() == FLY_AT_CNTNT ||
rAnchor.GetAnchorId() == FLY_AUTO_CNTNT ) &&
0 != rAnchor.GetCntntAnchor() &&
nFlySttNd <= ( nTstSttNd =
rAnchor.GetCntntAnchor()->nNode.GetIndex() ) &&
nTstSttNd < nFlySttNd + 2 )
2000-09-18 23:08:29 +00:00
{
return SW_CHAIN_NOT_EMPTY;
2000-09-18 23:08:29 +00:00
}
}
//Auf die richtige Area muessen wir auch noch einen Blick werfen.
//Beide Flys muessen im selben Bereich (Body, Head/Foot, Fly) sitzen
//Wenn die Source nicht der selektierte Rahmen ist, so reicht es
//Wenn ein passender gefunden wird (Der Wunsch kann z.B. von der API
//kommen).
// both in the same fly, header, footer or on the page?
const SwFmtAnchor &rSrcAnchor = rSource.GetAnchor(),
&rDstAnchor = rDest.GetAnchor();
ULONG nEndOfExtras = GetNodes().GetEndOfExtras().GetIndex();
BOOL bAllowed = FALSE;
if( FLY_PAGE == rSrcAnchor.GetAnchorId() )
{
if( FLY_PAGE == rDstAnchor.GetAnchorId() ||
( rDstAnchor.GetCntntAnchor() &&
rDstAnchor.GetCntntAnchor()->nNode.GetIndex() > nEndOfExtras ))
bAllowed = TRUE;
}
else if( rSrcAnchor.GetCntntAnchor() && rDstAnchor.GetCntntAnchor() )
{
const SwNodeIndex &rSrcIdx = rSrcAnchor.GetCntntAnchor()->nNode,
&rDstIdx = rDstAnchor.GetCntntAnchor()->nNode;
const SwStartNode* pSttNd = 0;
if( rSrcIdx == rDstIdx ||
( !pSttNd &&
0 != ( pSttNd = rSrcIdx.GetNode().FindFlyStartNode() ) &&
pSttNd == rDstIdx.GetNode().FindFlyStartNode() ) ||
( !pSttNd &&
0 != ( pSttNd = rSrcIdx.GetNode().FindFooterStartNode() ) &&
pSttNd == rDstIdx.GetNode().FindFooterStartNode() ) ||
( !pSttNd &&
0 != ( pSttNd = rSrcIdx.GetNode().FindHeaderStartNode() ) &&
pSttNd == rDstIdx.GetNode().FindHeaderStartNode() ) ||
( !pSttNd && rDstIdx.GetIndex() > nEndOfExtras &&
rSrcIdx.GetIndex() > nEndOfExtras ))
bAllowed = TRUE;
}
2000-09-18 23:08:29 +00:00
return bAllowed ? SW_CHAIN_OK : SW_CHAIN_WRONG_AREA;
2000-09-18 23:08:29 +00:00
}
/* -----------------23.07.98 13:56-------------------
*
* --------------------------------------------------*/
int SwDoc::Chain( SwFrmFmt &rSource, const SwFrmFmt &rDest )
{
int nErr = Chainable( rSource, rDest );
if ( !nErr )
{
StartUndo( UNDO_CHAINE );
SwFlyFrmFmt& rDestFmt = (SwFlyFrmFmt&)rDest;
//Follow an den Master haengen.
SwFmtChain aChain = rDestFmt.GetChain();
aChain.SetPrev( &(SwFlyFrmFmt&)rSource );
SetAttr( aChain, rDestFmt );
SfxItemSet aSet( GetAttrPool(), RES_FRM_SIZE, RES_FRM_SIZE,
RES_CHAIN, RES_CHAIN, 0 );
//Follow an den Master haengen.
aChain.SetPrev( &(SwFlyFrmFmt&)rSource );
SetAttr( aChain, rDestFmt );
//Master an den Follow haengen und dafuer sorgen, dass der Master
//eine fixierte Hoehe hat.
aChain = rSource.GetChain();
aChain.SetNext( &rDestFmt );
aSet.Put( aChain );
SwFmtFrmSize aSize( rSource.GetFrmSize() );
if ( aSize.GetHeightSizeType() != ATT_FIX_SIZE )
2000-09-18 23:08:29 +00:00
{
SwClientIter aIter( rSource );
SwFlyFrm *pFly = (SwFlyFrm*)aIter.First( TYPE(SwFlyFrm) );
if ( pFly )
aSize.SetHeight( pFly->Frm().Height() );
aSize.SetHeightSizeType( ATT_FIX_SIZE );
2000-09-18 23:08:29 +00:00
aSet.Put( aSize );
}
SetAttr( aSet, rSource );
EndUndo( UNDO_CHAINE );
}
return nErr;
}
/* -----------------23.07.98 13:56-------------------
*
* --------------------------------------------------*/
void SwDoc::Unchain( SwFrmFmt &rFmt )
{
SwFmtChain aChain( rFmt.GetChain() );
if ( aChain.GetNext() )
{
StartUndo( UNDO_UNCHAIN );
SwFrmFmt *pFollow = aChain.GetNext();
aChain.SetNext( 0 );
SetAttr( aChain, rFmt );
aChain = pFollow->GetChain();
aChain.SetPrev( 0 );
SetAttr( aChain, *pFollow );
EndUndo( UNDO_UNCHAIN );
}
}