2006/07/24 11:47:54 od 1.57.132.1: #b6449874# method <SwFlyAtCntFrm::MakeAll()> - on temporary consideration of wrapping style influence to avoid loop situation in iterative positioning process apply to all objects, anchored at the anchor frame, the temporary consideration of wrapping style influence.
1571 lines
56 KiB
C++
1571 lines
56 KiB
C++
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: flycnt.cxx,v $
|
|
*
|
|
* $Revision: 1.58 $
|
|
*
|
|
* last change: $Author: rt $ $Date: 2006-07-26 08:17:09 $
|
|
*
|
|
* The Contents of this file are made available subject to
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
*
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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
|
|
*
|
|
************************************************************************/
|
|
|
|
#pragma hdrstop
|
|
|
|
|
|
#ifndef _BIGINT_HXX //autogen
|
|
#include <tools/bigint.hxx>
|
|
#endif
|
|
#include "pagefrm.hxx"
|
|
#include "rootfrm.hxx"
|
|
#include "cntfrm.hxx"
|
|
#include "flyfrm.hxx"
|
|
#include "txtfrm.hxx"
|
|
#include "doc.hxx"
|
|
#include "viewsh.hxx"
|
|
#include "viewimp.hxx"
|
|
#include "pam.hxx"
|
|
#include "frmfmt.hxx"
|
|
#include "frmtool.hxx"
|
|
#include "dflyobj.hxx"
|
|
#include "hints.hxx"
|
|
#include "ndtxt.hxx"
|
|
#include "swundo.hxx"
|
|
#include "errhdl.hxx"
|
|
|
|
#ifndef _SVX_ULSPITEM_HXX //autogen
|
|
#include <svx/ulspitem.hxx>
|
|
#endif
|
|
#ifndef _SVX_LRSPITEM_HXX //autogen
|
|
#include <svx/lrspitem.hxx>
|
|
#endif
|
|
|
|
#ifndef _FMTANCHR_HXX //autogen
|
|
#include <fmtanchr.hxx>
|
|
#endif
|
|
#ifndef _FMTORNT_HXX //autogen
|
|
#include <fmtornt.hxx>
|
|
#endif
|
|
#ifndef _FMTFSIZE_HXX //autogen
|
|
#include <fmtfsize.hxx>
|
|
#endif
|
|
#ifndef _FMTSRND_HXX //autogen
|
|
#include <fmtsrnd.hxx>
|
|
#endif
|
|
#ifndef _NODE_HXX //autogen
|
|
#include <node.hxx>
|
|
#endif
|
|
#include "tabfrm.hxx"
|
|
#include "flyfrms.hxx"
|
|
#include "crstate.hxx"
|
|
#include "sectfrm.hxx"
|
|
|
|
// OD 29.10.2003 #113049#
|
|
#ifndef _TOCNTNTANCHOREDOBJECTPOSITION_HXX
|
|
#include <tocntntanchoredobjectposition.hxx>
|
|
#endif
|
|
// OD 2004-05-24 #i28701#
|
|
#ifndef _DCONTACT_HXX
|
|
#include <dcontact.hxx>
|
|
#endif
|
|
#ifndef _SORTEDOBJS_HXX
|
|
#include <sortedobjs.hxx>
|
|
#endif
|
|
// --> OD 2005-09-29 #125370#,#125957#
|
|
#ifndef _LAYOUTER_HXX
|
|
#include <layouter.hxx>
|
|
#endif
|
|
// <--
|
|
// --> OD 2005-11-17 #i56300#
|
|
#ifndef _OBJECTFORMATTERTXTFRM_HXX
|
|
#include <objectformattertxtfrm.hxx>
|
|
#endif
|
|
// <--
|
|
// --> OD 2006-03-06 #125892#
|
|
#ifndef _HANDLEANCHORNODECHG_HXX
|
|
#include <HandleAnchorNodeChg.hxx>
|
|
#endif
|
|
// <--
|
|
|
|
/*************************************************************************
|
|
|*
|
|
|* SwFlyAtCntFrm::SwFlyAtCntFrm()
|
|
|*
|
|
|* Ersterstellung MA 11. Nov. 92
|
|
|* Letzte Aenderung MA 09. Apr. 99
|
|
|*
|
|
|*************************************************************************/
|
|
|
|
SwFlyAtCntFrm::SwFlyAtCntFrm( SwFlyFrmFmt *pFmt, SwFrm *pAnch ) :
|
|
SwFlyFreeFrm( pFmt, pAnch )
|
|
{
|
|
bAtCnt = TRUE;
|
|
bAutoPosition = FLY_AUTO_CNTNT == pFmt->GetAnchor().GetAnchorId();
|
|
}
|
|
|
|
// --> OD 2004-06-29 #i28701#
|
|
TYPEINIT1(SwFlyAtCntFrm,SwFlyFreeFrm);
|
|
// <--
|
|
/*************************************************************************
|
|
|*
|
|
|* SwFlyAtCntFrm::Modify()
|
|
|*
|
|
|* Ersterstellung MA 08. Feb. 93
|
|
|* Letzte Aenderung MA 23. Nov. 94
|
|
|*
|
|
|*************************************************************************/
|
|
|
|
void SwFlyAtCntFrm::Modify( SfxPoolItem *pOld, SfxPoolItem *pNew )
|
|
{
|
|
USHORT nWhich = pNew ? pNew->Which() : 0;
|
|
const SwFmtAnchor *pAnch = 0;
|
|
|
|
if( RES_ATTRSET_CHG == nWhich && SFX_ITEM_SET ==
|
|
((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_ANCHOR, FALSE,
|
|
(const SfxPoolItem**)&pAnch ))
|
|
; // Beim GetItemState wird der AnkerPointer gesetzt !
|
|
|
|
else if( RES_ANCHOR == nWhich )
|
|
{
|
|
//Ankerwechsel, ich haenge mich selbst um.
|
|
//Es darf sich nicht um einen Wechsel des Ankertyps handeln,
|
|
//dies ist nur ueber die SwFEShell moeglich.
|
|
pAnch = (const SwFmtAnchor*)pNew;
|
|
}
|
|
|
|
if( pAnch )
|
|
{
|
|
ASSERT( pAnch->GetAnchorId() == GetFmt()->GetAnchor().GetAnchorId(),
|
|
"Unzulaessiger Wechsel des Ankertyps." );
|
|
|
|
//Abmelden, neuen Anker besorgen und 'dranhaengen.
|
|
SwRect aOld( GetObjRectWithSpaces() );
|
|
SwPageFrm *pOldPage = FindPageFrm();
|
|
const SwFrm *pOldAnchor = GetAnchorFrm();
|
|
SwCntntFrm *pCntnt = (SwCntntFrm*)GetAnchorFrm();
|
|
AnchorFrm()->RemoveFly( this );
|
|
|
|
const BOOL bBodyFtn = (pCntnt->IsInDocBody() || pCntnt->IsInFtn());
|
|
|
|
//Den neuen Anker anhand des NodeIdx suchen, am alten und
|
|
//neuen NodeIdx kann auch erkannt werden, in welche Richtung
|
|
//gesucht werden muss.
|
|
const SwNodeIndex aNewIdx( pAnch->GetCntntAnchor()->nNode );
|
|
SwNodeIndex aOldIdx( *pCntnt->GetNode() );
|
|
|
|
//fix: Umstellung, ehemals wurde in der do-while-Schleife nach vorn bzw.
|
|
//nach hinten gesucht; je nachdem wie welcher Index kleiner war.
|
|
//Das kann aber u.U. zu einer Endlosschleife fuehren. Damit
|
|
//wenigstens die Schleife unterbunden wird suchen wir nur in eine
|
|
//Richtung. Wenn der neue Anker nicht gefunden wird koennen wir uns
|
|
//immer noch vom Node einen Frame besorgen. Die Change, dass dies dann
|
|
//der richtige ist, ist gut.
|
|
const bool bNext = aOldIdx < aNewIdx;
|
|
// --> OD 2006-02-28 #125892#
|
|
// consider the case that at found anchor frame candidate already a
|
|
// fly frame of the given fly format is registered.
|
|
// --> OD 2006-03-15 #133407# - consider, that <pCntnt> is the already
|
|
// the new anchor frame.
|
|
bool bFound( aOldIdx == aNewIdx );
|
|
// <--
|
|
while ( pCntnt && !bFound )
|
|
{
|
|
do
|
|
{
|
|
if ( bNext )
|
|
pCntnt = pCntnt->GetNextCntntFrm();
|
|
else
|
|
pCntnt = pCntnt->GetPrevCntntFrm();
|
|
} while ( pCntnt &&
|
|
!( bBodyFtn == ( pCntnt->IsInDocBody() ||
|
|
pCntnt->IsInFtn() ) ) );
|
|
if ( pCntnt )
|
|
aOldIdx = *pCntnt->GetNode();
|
|
|
|
// --> OD 2006-02-28 #125892#
|
|
// check, if at found anchor frame candidate already a fly frame
|
|
// of the given fly frame format is registered.
|
|
bFound = aOldIdx == aNewIdx;
|
|
if ( bFound && pCntnt->GetDrawObjs() )
|
|
{
|
|
SwFrmFmt* pMyFlyFrmFmt( &GetFrmFmt() );
|
|
SwSortedObjs &rObjs = *pCntnt->GetDrawObjs();
|
|
for( sal_uInt16 i = 0; i < rObjs.Count(); ++i)
|
|
{
|
|
SwFlyFrm* pFlyFrm = dynamic_cast<SwFlyFrm*>(rObjs[i]);
|
|
if ( pFlyFrm &&
|
|
&(pFlyFrm->GetFrmFmt()) == pMyFlyFrmFmt )
|
|
{
|
|
bFound = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// <--
|
|
}
|
|
// <--
|
|
if ( !pCntnt )
|
|
{
|
|
SwCntntNode *pNode = aNewIdx.GetNode().GetCntntNode();
|
|
pCntnt = pNode->GetFrm( &pOldAnchor->Frm().Pos(), 0, FALSE );
|
|
ASSERT( pCntnt, "Neuen Anker nicht gefunden" );
|
|
}
|
|
//Flys haengen niemals an einem Follow sondern immer am
|
|
//Master, den suchen wir uns jetzt.
|
|
SwCntntFrm* pFlow = pCntnt;
|
|
while ( pFlow->IsFollow() )
|
|
pFlow = pFlow->FindMaster();
|
|
pCntnt = pFlow;
|
|
|
|
//und schwupp angehaengt das teil...
|
|
pCntnt->AppendFly( this );
|
|
if ( pOldPage && pOldPage != FindPageFrm() )
|
|
NotifyBackground( pOldPage, aOld, PREP_FLY_LEAVE );
|
|
|
|
//Fix(3495)
|
|
_InvalidatePos();
|
|
InvalidatePage();
|
|
SetNotifyBack();
|
|
// --> OD 2004-06-24 #i28701# - reset member <maLastCharRect> and
|
|
// <mnLastTopOfLine> for to-character anchored objects.
|
|
ClearCharRectAndTopOfLine();
|
|
}
|
|
else
|
|
SwFlyFrm::Modify( pOld, pNew );
|
|
}
|
|
|
|
/*************************************************************************
|
|
|*
|
|
|* SwFlyAtCntFrm::MakeAll()
|
|
|*
|
|
|* Beschreibung Bei einem Absatzgebunden Fly kann es durchaus sein,
|
|
|* das der Anker auf die Veraenderung des Flys reagiert. Auf diese
|
|
|* Reaktion hat der Fly natuerlich auch wieder zu reagieren.
|
|
|* Leider kann dies zu Oszillationen fuehren z.b. Der Fly will nach
|
|
|* unten, dadurch kann der Inhalt nach oben, der TxtFrm wird kleiner,
|
|
|* der Fly muss wieder hoeher woduch der Text wieder nach unten
|
|
|* verdraengt wird...
|
|
|* Um derartige Oszillationen zu vermeiden, wird ein kleiner Positions-
|
|
|* stack aufgebaut. Wenn der Fly ein Position erreicht, die er bereits
|
|
|* einmal einnahm, so brechen wir den Vorgang ab. Um keine Risiken
|
|
|* einzugehen, wird der Positionsstack so aufgebaut, dass er fuenf
|
|
|* Positionen zurueckblickt.
|
|
|* Wenn der Stack ueberlaeuft, wird ebenfalls abgebrochen.
|
|
|* Der Abbruch fuer dazu, dass der Fly am Ende eine unguenste Position
|
|
|* einnimmt. Damit es nicht durch einen wiederholten Aufruf von
|
|
|* Aussen zu einer 'grossen Oszillation' kommen kann wird im Abbruch-
|
|
|* fall das Attribut des Rahmens auf automatische Ausrichtung oben
|
|
|* eingestellt.
|
|
|*
|
|
|* Ersterstellung MA 12. Nov. 92
|
|
|* Letzte Aenderung MA 20. Sep. 96
|
|
|*
|
|
|*************************************************************************/
|
|
//Wir brauchen ein Paar Hilfsklassen zur Kontrolle der Ozillation und ein paar
|
|
//Funktionen um die Uebersicht zu gewaehrleisten.
|
|
// OD 2004-08-25 #i3317# - re-factoring of the position stack
|
|
class SwOszControl
|
|
{
|
|
static const SwFlyFrm *pStk1;
|
|
static const SwFlyFrm *pStk2;
|
|
static const SwFlyFrm *pStk3;
|
|
static const SwFlyFrm *pStk4;
|
|
static const SwFlyFrm *pStk5;
|
|
|
|
const SwFlyFrm *pFly;
|
|
// --> OD 2004-08-25 #i3317#
|
|
sal_uInt8 mnPosStackSize;
|
|
std::vector<Point*> maObjPositions;
|
|
// <--
|
|
|
|
public:
|
|
SwOszControl( const SwFlyFrm *pFrm );
|
|
~SwOszControl();
|
|
bool ChkOsz();
|
|
static FASTBOOL IsInProgress( const SwFlyFrm *pFly );
|
|
};
|
|
const SwFlyFrm *SwOszControl::pStk1 = 0;
|
|
const SwFlyFrm *SwOszControl::pStk2 = 0;
|
|
const SwFlyFrm *SwOszControl::pStk3 = 0;
|
|
const SwFlyFrm *SwOszControl::pStk4 = 0;
|
|
const SwFlyFrm *SwOszControl::pStk5 = 0;
|
|
|
|
SwOszControl::SwOszControl( const SwFlyFrm *pFrm )
|
|
: pFly( pFrm ),
|
|
// --> OD 2004-08-25 #i3317#
|
|
mnPosStackSize( 20 )
|
|
// <--
|
|
{
|
|
if ( !SwOszControl::pStk1 )
|
|
SwOszControl::pStk1 = pFly;
|
|
else if ( !SwOszControl::pStk2 )
|
|
SwOszControl::pStk2 = pFly;
|
|
else if ( !SwOszControl::pStk3 )
|
|
SwOszControl::pStk3 = pFly;
|
|
else if ( !SwOszControl::pStk4 )
|
|
SwOszControl::pStk4 = pFly;
|
|
else if ( !SwOszControl::pStk5 )
|
|
SwOszControl::pStk5 = pFly;
|
|
}
|
|
|
|
SwOszControl::~SwOszControl()
|
|
{
|
|
if ( SwOszControl::pStk1 == pFly )
|
|
SwOszControl::pStk1 = 0;
|
|
else if ( SwOszControl::pStk2 == pFly )
|
|
SwOszControl::pStk2 = 0;
|
|
else if ( SwOszControl::pStk3 == pFly )
|
|
SwOszControl::pStk3 = 0;
|
|
else if ( SwOszControl::pStk4 == pFly )
|
|
SwOszControl::pStk4 = 0;
|
|
else if ( SwOszControl::pStk5 == pFly )
|
|
SwOszControl::pStk5 = 0;
|
|
// --> OD 2004-08-25 #i3317#
|
|
while ( !maObjPositions.empty() )
|
|
{
|
|
Point* pPos = maObjPositions.back();
|
|
delete pPos;
|
|
|
|
maObjPositions.pop_back();
|
|
}
|
|
// <--
|
|
}
|
|
|
|
FASTBOOL SwOszControl::IsInProgress( const SwFlyFrm *pFly )
|
|
{
|
|
if ( SwOszControl::pStk1 && !pFly->IsLowerOf( SwOszControl::pStk1 ) )
|
|
return TRUE;
|
|
if ( SwOszControl::pStk2 && !pFly->IsLowerOf( SwOszControl::pStk2 ) )
|
|
return TRUE;
|
|
if ( SwOszControl::pStk3 && !pFly->IsLowerOf( SwOszControl::pStk3 ) )
|
|
return TRUE;
|
|
if ( SwOszControl::pStk4 && !pFly->IsLowerOf( SwOszControl::pStk4 ) )
|
|
return TRUE;
|
|
if ( SwOszControl::pStk5 && !pFly->IsLowerOf( SwOszControl::pStk5 ) )
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
bool SwOszControl::ChkOsz()
|
|
{
|
|
bool bOscillationDetected = false;
|
|
|
|
if ( maObjPositions.size() == mnPosStackSize )
|
|
{
|
|
// position stack is full -> oscillation
|
|
bOscillationDetected = true;
|
|
}
|
|
else
|
|
{
|
|
Point* pNewObjPos = new Point( pFly->GetObjRect().Pos() );
|
|
for ( std::vector<Point*>::iterator aObjPosIter = maObjPositions.begin();
|
|
aObjPosIter != maObjPositions.end();
|
|
++aObjPosIter )
|
|
{
|
|
if ( *(pNewObjPos) == *(*aObjPosIter) )
|
|
{
|
|
// position already occured -> oscillation
|
|
bOscillationDetected = true;
|
|
delete pNewObjPos;
|
|
break;
|
|
}
|
|
}
|
|
if ( !bOscillationDetected )
|
|
{
|
|
maObjPositions.push_back( pNewObjPos );
|
|
}
|
|
}
|
|
|
|
return bOscillationDetected;
|
|
}
|
|
|
|
//
|
|
// SwFlyAtCntFrm::MakeAll wants to calculate the section, if it contains
|
|
// the anchor frame. We do not want to calculate the section, if there
|
|
// is a table between the anchor frame and the section frame
|
|
//
|
|
void lcl_CalcUpperSection( const SwFrm& rFrm )
|
|
{
|
|
if( rFrm.IsInSct() )
|
|
{
|
|
// Do not calculate the section, if there is a table between
|
|
// the anchor and the section.
|
|
ASSERT( rFrm.IsInSct(), "lcl_SectionBeforeTable without section" )
|
|
const SwFrm* pUpper = rFrm.GetUpper();
|
|
while ( pUpper )
|
|
{
|
|
if ( pUpper->IsSctFrm() || pUpper->IsCellFrm() )
|
|
break;
|
|
pUpper = pUpper->GetUpper();
|
|
}
|
|
|
|
ASSERT( pUpper, "lcl_SectionBeforeTable without section" )
|
|
if ( pUpper->IsSctFrm() )
|
|
pUpper->Calc();
|
|
}
|
|
}
|
|
|
|
|
|
void SwFlyAtCntFrm::MakeAll()
|
|
{
|
|
// OD 2004-01-19 #110582#
|
|
if ( !GetFmt()->GetDoc()->IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !SwOszControl::IsInProgress( this ) && !IsLocked() && !IsColLocked() )
|
|
{
|
|
// --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
|
|
if( !GetPageFrm() && GetAnchorFrm() && GetAnchorFrm()->IsInFly() )
|
|
{
|
|
SwFlyFrm* pFly = AnchorFrm()->FindFlyFrm();
|
|
SwPageFrm *pPage = pFly ? pFly->FindPageFrm() : NULL;
|
|
if( pPage )
|
|
pPage->AppendFlyToPage( this );
|
|
}
|
|
// --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
|
|
if( GetPageFrm() )
|
|
{
|
|
bSetCompletePaintOnInvalidate = TRUE;
|
|
{
|
|
SwFlyFrmFmt *pFmt = (SwFlyFrmFmt*)GetFmt();
|
|
const SwFmtFrmSize &rFrmSz = GetFmt()->GetFrmSize();
|
|
if( rFrmSz.GetHeightPercent() != 0xFF &&
|
|
rFrmSz.GetHeightPercent() >= 100 )
|
|
{
|
|
pFmt->LockModify();
|
|
SwFmtSurround aMain( pFmt->GetSurround() );
|
|
if ( aMain.GetSurround() == SURROUND_NONE )
|
|
{
|
|
aMain.SetSurround( SURROUND_THROUGHT );
|
|
pFmt->SetAttr( aMain );
|
|
}
|
|
pFmt->UnlockModify();
|
|
}
|
|
}
|
|
|
|
SwOszControl aOszCntrl( this );
|
|
|
|
// --> OD 2005-02-22 #i43255#
|
|
// --> OD 2005-06-07 #i50356# - format the anchor frame, which
|
|
// contains the anchor position. E.g., for at-character anchored
|
|
// object this can be the follow frame of the anchor frame.
|
|
const bool bFormatAnchor =
|
|
!static_cast<const SwTxtFrm*>( GetAnchorFrmContainingAnchPos() )->IsAnyJoinLocked() &&
|
|
!ConsiderObjWrapInfluenceOnObjPos() &&
|
|
!ConsiderObjWrapInfluenceOfOtherObjs();
|
|
// <--
|
|
|
|
const SwFrm* pFooter = GetAnchorFrm()->FindFooterOrHeader();
|
|
if( pFooter && !pFooter->IsFooterFrm() )
|
|
pFooter = NULL;
|
|
bool bOsz = false;
|
|
FASTBOOL bExtra = Lower() && Lower()->IsColumnFrm();
|
|
// --> OD 2004-08-25 #i3317# - boolean, to apply temporarly the
|
|
// 'straightforward positioning process' for the frame due to its
|
|
// overlapping with a previous column.
|
|
bool bConsiderWrapInfluenceDueToOverlapPrevCol( false );
|
|
// <--
|
|
// --> OD 2004-10-22 #i35911# - boolean, to apply temporarly the
|
|
// 'straightforward positioning process' for the frame due to fact
|
|
// that it causes the complete content of its layout environment
|
|
// to move forward.
|
|
// --> OD 2005-01-14 #i40444# - extend usage of this boolean:
|
|
// apply temporarly the 'straightforward positioning process' for
|
|
// the frame due to the fact that the frame clears the area for
|
|
// the anchor frame, thus it has to move forward.
|
|
bool bConsiderWrapInfluenceDueToMovedFwdAnchor( false );
|
|
// <--
|
|
do {
|
|
SWRECTFN( this )
|
|
Point aOldPos( (Frm().*fnRect->fnGetPos)() );
|
|
SwFlyFreeFrm::MakeAll();
|
|
const bool bPosChgDueToOwnFormat =
|
|
aOldPos != (Frm().*fnRect->fnGetPos)();
|
|
// --> OD 2004-08-25 #i3317#
|
|
if ( !ConsiderObjWrapInfluenceOnObjPos() &&
|
|
OverlapsPrevColumn() )
|
|
{
|
|
bConsiderWrapInfluenceDueToOverlapPrevCol = true;
|
|
}
|
|
// <--
|
|
// OD 2004-05-12 #i28701# - no format of anchor frame, if
|
|
// wrapping style influence is considered on object positioning
|
|
if ( bFormatAnchor )
|
|
{
|
|
SwTxtFrm* pAnchPosAnchorFrm =
|
|
dynamic_cast<SwTxtFrm*>(GetAnchorFrmContainingAnchPos());
|
|
ASSERT( pAnchPosAnchorFrm,
|
|
"<SwFlyAtCntFrm::MakeAll()> - anchor frame of wrong type -> crash" );
|
|
// --> OD 2006-01-27 #i58182# - For the usage of new method
|
|
// <SwObjectFormatterTxtFrm::CheckMovedFwdCondition(..)>
|
|
// to check move forward of anchor frame due to the object
|
|
// positioning it's needed to know, if the object is anchored
|
|
// at the master frame before the anchor frame is formatted.
|
|
const bool bAnchoredAtMaster( !pAnchPosAnchorFrm->IsFollow() );
|
|
// <--
|
|
|
|
// --> OD 2005-11-17 #i56300#
|
|
// perform complete format of anchor text frame and its
|
|
// previous frames, which have become invalid due to the
|
|
// fly frame format.
|
|
SwObjectFormatterTxtFrm::FormatAnchorFrmAndItsPrevs( *pAnchPosAnchorFrm );
|
|
// <--
|
|
// --> OD 2004-10-22 #i35911#
|
|
// --> OD 2005-01-14 #i40444#
|
|
// --> OD 2006-01-27 #i58182# - usage of new method
|
|
// <SwObjectFormatterTxtFrm::CheckMovedFwdCondition(..)>
|
|
sal_uInt32 nToPageNum( 0L );
|
|
bool bDummy( false );
|
|
if ( SwObjectFormatterTxtFrm::CheckMovedFwdCondition(
|
|
*this, GetPageFrm()->GetPhyPageNum(),
|
|
bAnchoredAtMaster, nToPageNum, bDummy ) )
|
|
{
|
|
bConsiderWrapInfluenceDueToMovedFwdAnchor = true;
|
|
// --> OD 2005-09-29 #125370#,#125957# - mark anchor text frame
|
|
// directly, that it is moved forward by object positioning.
|
|
SwTxtFrm* pAnchorTxtFrm( static_cast<SwTxtFrm*>(AnchorFrm()) );
|
|
const SwPageFrm* pAnchorPageFrm =
|
|
pAnchPosAnchorFrm->FindPageFrm();
|
|
bool bInsert( true );
|
|
sal_uInt32 nAnchorFrmToPageNum( 0L );
|
|
const SwDoc& rDoc = *(GetFrmFmt().GetDoc());
|
|
if ( SwLayouter::FrmMovedFwdByObjPos(
|
|
rDoc, *pAnchorTxtFrm, nAnchorFrmToPageNum ) )
|
|
{
|
|
if ( nAnchorFrmToPageNum < nToPageNum )
|
|
SwLayouter::RemoveMovedFwdFrm( rDoc, *pAnchorTxtFrm );
|
|
else
|
|
bInsert = false;
|
|
}
|
|
if ( bInsert )
|
|
{
|
|
SwLayouter::InsertMovedFwdFrm( rDoc, *pAnchorTxtFrm,
|
|
nToPageNum );
|
|
}
|
|
// <--
|
|
}
|
|
// <--
|
|
}
|
|
|
|
if ( aOldPos != (Frm().*fnRect->fnGetPos)() ||
|
|
( !GetValidPosFlag() &&
|
|
( pFooter || bPosChgDueToOwnFormat ) ) )
|
|
{
|
|
bOsz = aOszCntrl.ChkOsz();
|
|
|
|
// --> OD 2006-04-13 #b6403541#
|
|
// special loop prevention for dedicated document:
|
|
if ( bOsz &&
|
|
HasFixSize() && IsClipped() &&
|
|
GetAnchorFrm()->GetUpper()->IsCellFrm() )
|
|
{
|
|
SwFrmFmt* pFmt = GetFmt();
|
|
const SwFmtFrmSize& rFrmSz = pFmt->GetFrmSize();
|
|
if ( rFrmSz.GetWidthPercent() &&
|
|
rFrmSz.GetHeightPercent() == 0xFF )
|
|
{
|
|
SwFmtSurround aSurround( pFmt->GetSurround() );
|
|
if ( aSurround.GetSurround() == SURROUND_NONE )
|
|
{
|
|
pFmt->LockModify();
|
|
aSurround.SetSurround( SURROUND_THROUGHT );
|
|
pFmt->SetAttr( aSurround );
|
|
pFmt->UnlockModify();
|
|
bOsz = false;
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
ASSERT( false,
|
|
"<SwFlyAtCntFrm::MakeAll()> - special loop prevention for dedicated document of b6403541 applied" );
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
// <--
|
|
}
|
|
|
|
if ( bExtra && Lower() && !Lower()->GetValidPosFlag() )
|
|
{
|
|
// Wenn ein mehrspaltiger Rahmen wg. Positionswechsel ungueltige
|
|
// Spalten hinterlaesst, so drehen wir lieber hier eine weitere
|
|
// Runde und formatieren unseren Inhalt via FormatWidthCols nochmal.
|
|
_InvalidateSize();
|
|
bExtra = FALSE; // Sicherhaltshalber gibt es nur eine Ehrenrunde.
|
|
}
|
|
} while ( !IsValid() && !bOsz &&
|
|
// --> OD 2004-08-25 #i3317#
|
|
!bConsiderWrapInfluenceDueToOverlapPrevCol &&
|
|
// <--
|
|
// --> OD 2005-01-14 #i40444#
|
|
!bConsiderWrapInfluenceDueToMovedFwdAnchor &&
|
|
// <--
|
|
GetFmt()->GetDoc()->IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) );
|
|
|
|
// --> OD 2004-08-25 #i3317# - instead of attribute change apply
|
|
// temporarly the 'straightforward positioning process'.
|
|
if ( bOsz || bConsiderWrapInfluenceDueToOverlapPrevCol ||
|
|
// --> OD 2005-01-14 #i40444#
|
|
bConsiderWrapInfluenceDueToMovedFwdAnchor )
|
|
// <--
|
|
{
|
|
SetTmpConsiderWrapInfluence( true );
|
|
SetRestartLayoutProcess( true );
|
|
// --> OD 2006-07-24 #b6449874#
|
|
SetTmpConsiderWrapInfluenceOfOtherObjs( true );
|
|
// <--
|
|
}
|
|
// <--
|
|
bSetCompletePaintOnInvalidate = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** method to determine, if a <MakeAll()> on the Writer fly frame is possible
|
|
|
|
OD 2004-05-11 #i28701#
|
|
|
|
@author OD
|
|
*/
|
|
bool SwFlyAtCntFrm::IsFormatPossible() const
|
|
{
|
|
return SwFlyFreeFrm::IsFormatPossible() &&
|
|
!SwOszControl::IsInProgress( this );
|
|
}
|
|
|
|
/*************************************************************************
|
|
|*
|
|
|* FindAnchor() und Hilfsfunktionen.
|
|
|*
|
|
|* Beschreibung: Sucht ausgehend von pOldAnch einen Anker fuer
|
|
|* Absatzgebundene Objekte.
|
|
|* Wird beim Draggen von Absatzgebundenen Objekten zur Ankeranzeige sowie
|
|
|* fuer Ankerwechsel benoetigt.
|
|
|* Ersterstellung MA 22. Jun. 93
|
|
|* Letzte Aenderung MA 30. Jan. 95
|
|
|*
|
|
|*************************************************************************/
|
|
|
|
class SwDistance
|
|
{
|
|
public:
|
|
SwTwips nMain, nSub;
|
|
SwDistance() { nMain = nSub = 0; }
|
|
SwDistance& operator=( const SwDistance &rTwo )
|
|
{ nMain = rTwo.nMain; nSub = rTwo.nSub; return *this; }
|
|
BOOL operator<( const SwDistance& rTwo )
|
|
{ return nMain < rTwo.nMain || ( nMain == rTwo.nMain && nSub &&
|
|
rTwo.nSub && nSub < rTwo.nSub ); }
|
|
BOOL operator<=( const SwDistance& rTwo )
|
|
{ return nMain < rTwo.nMain || ( nMain == rTwo.nMain && ( !nSub ||
|
|
!rTwo.nSub || nSub <= rTwo.nSub ) ); }
|
|
};
|
|
|
|
const SwFrm * MA_FASTCALL lcl_CalcDownDist( SwDistance &rRet,
|
|
const Point &rPt,
|
|
const SwCntntFrm *pCnt )
|
|
{
|
|
rRet.nSub = 0;
|
|
//Wenn der Point direkt innerhalb des Cnt steht ist die Sache klar und
|
|
//der Cntnt hat automatisch eine Entfernung von 0
|
|
if ( pCnt->Frm().IsInside( rPt ) )
|
|
{
|
|
rRet.nMain = 0;
|
|
return pCnt;
|
|
}
|
|
else
|
|
{
|
|
const SwLayoutFrm *pUp = pCnt->IsInTab() ? pCnt->FindTabFrm()->GetUpper() : pCnt->GetUpper();
|
|
// einspaltige Bereiche muessen zu ihrem Upper durchschalten
|
|
while( pUp->IsSctFrm() )
|
|
pUp = pUp->GetUpper();
|
|
SWRECTFN( pUp )
|
|
//Dem Textflus folgen.
|
|
if ( pUp->Frm().IsInside( rPt ) )
|
|
{
|
|
// OD 26.09.2003 - <rPt> point is inside environment of given content frame
|
|
if( bVert )
|
|
rRet.nMain = pCnt->Frm().Left() + pCnt->Frm().Width() -rPt.X();
|
|
else
|
|
rRet.nMain = rPt.Y() - pCnt->Frm().Top();
|
|
return pCnt;
|
|
}
|
|
else if ( rPt.Y() <= pUp->Frm().Top() )
|
|
{
|
|
// OD 26.09.2003 - <rPt> point is above environment of given content frame
|
|
// OD: correct for vertical layout?
|
|
rRet.nMain = LONG_MAX;
|
|
}
|
|
else if( rPt.X() < pUp->Frm().Left() &&
|
|
rPt.Y() <= ( bVert ? pUp->Frm().Top() : pUp->Frm().Bottom() ) )
|
|
{
|
|
// OD 26.09.2003 - <rPt> point is left of environment of given content frame
|
|
// OD: seems not to be correct for vertical layout!?
|
|
const SwFrm *pLay = pUp->GetLeaf( MAKEPAGE_NONE, FALSE, pCnt );
|
|
if( !pLay ||
|
|
(bVert && (pLay->Frm().Top() + pLay->Prt().Bottom()) <rPt.Y())||
|
|
(!bVert && (pLay->Frm().Left() + pLay->Prt().Right())<rPt.X()) )
|
|
{
|
|
// OD 26.09.2003 - <rPt> point is in left border of environment
|
|
if( bVert )
|
|
rRet.nMain = pCnt->Frm().Left() + pCnt->Frm().Width()
|
|
- rPt.X();
|
|
else
|
|
rRet.nMain = rPt.Y() - pCnt->Frm().Top();
|
|
return pCnt;
|
|
}
|
|
else
|
|
rRet.nMain = LONG_MAX;
|
|
}
|
|
else
|
|
{
|
|
rRet.nMain = bVert ? pCnt->Frm().Left() + pCnt->Frm().Width() -
|
|
(pUp->Frm().Left() + pUp->Prt().Left())
|
|
: (pUp->Frm().Top() + pUp->Prt().Bottom()) - pCnt->Frm().Top();
|
|
|
|
const SwFrm *pPre = pCnt;
|
|
const SwFrm *pLay = pUp->GetLeaf( MAKEPAGE_NONE, TRUE, pCnt );
|
|
SwTwips nFrmTop, nPrtHeight;
|
|
BOOL bSct;
|
|
const SwSectionFrm *pSect = pUp->FindSctFrm();
|
|
if( pSect )
|
|
{
|
|
rRet.nSub = rRet.nMain;
|
|
rRet.nMain = 0;
|
|
}
|
|
if( pSect && !pSect->IsAnLower( pLay ) )
|
|
{
|
|
bSct = FALSE;
|
|
const SwSectionFrm* pNxtSect = pLay ? pLay->FindSctFrm() : 0;
|
|
if( pSect->IsAnFollow( pNxtSect ) )
|
|
{
|
|
if( pLay->IsVertical() )
|
|
{
|
|
nFrmTop = pLay->Frm().Left() + pLay->Frm().Width();
|
|
nPrtHeight = pLay->Prt().Width();
|
|
}
|
|
else
|
|
{
|
|
nFrmTop = pLay->Frm().Top();
|
|
nPrtHeight = pLay->Prt().Height();
|
|
}
|
|
pSect = pNxtSect;
|
|
}
|
|
else
|
|
{
|
|
pLay = pSect->GetUpper();
|
|
if( pLay->IsVertical() )
|
|
{
|
|
nFrmTop = pSect->Frm().Left();
|
|
nPrtHeight = pSect->Frm().Left() - pLay->Frm().Left()
|
|
- pLay->Prt().Left();
|
|
}
|
|
else
|
|
{
|
|
nFrmTop = pSect->Frm().Bottom();
|
|
nPrtHeight = pLay->Frm().Top() + pLay->Prt().Top()
|
|
+ pLay->Prt().Height() - pSect->Frm().Top()
|
|
- pSect->Frm().Height();
|
|
}
|
|
pSect = 0;
|
|
}
|
|
}
|
|
else if( pLay )
|
|
{
|
|
if( pLay->IsVertical() )
|
|
{
|
|
nFrmTop = pLay->Frm().Left() + pLay->Frm().Width();
|
|
nPrtHeight = pLay->Prt().Width();
|
|
}
|
|
else
|
|
{
|
|
nFrmTop = pLay->Frm().Top();
|
|
nPrtHeight = pLay->Prt().Height();
|
|
}
|
|
bSct = 0 != pSect;
|
|
}
|
|
while ( pLay && !pLay->Frm().IsInside( rPt ) &&
|
|
( pLay->Frm().Top() <= rPt.Y() || pLay->IsInFly() ||
|
|
( pLay->IsInSct() &&
|
|
pLay->FindSctFrm()->GetUpper()->Frm().Top() <= rPt.Y())) )
|
|
{
|
|
if ( pLay->IsFtnContFrm() )
|
|
{
|
|
if ( !((SwLayoutFrm*)pLay)->Lower() )
|
|
{
|
|
SwFrm *pDel = (SwFrm*)pLay;
|
|
pDel->Cut();
|
|
delete pDel;
|
|
return pPre;
|
|
}
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if( bSct || pSect )
|
|
rRet.nSub += nPrtHeight;
|
|
else
|
|
rRet.nMain += nPrtHeight;
|
|
pPre = pLay;
|
|
pLay = pLay->GetLeaf( MAKEPAGE_NONE, TRUE, pCnt );
|
|
if( pSect && !pSect->IsAnLower( pLay ) )
|
|
{ // If we're leaving a SwSectionFrm, the next Leaf-Frm
|
|
// is the part of the upper below the SectionFrm.
|
|
const SwSectionFrm* pNxtSect = pLay ?
|
|
pLay->FindSctFrm() : NULL;
|
|
bSct = FALSE;
|
|
if( pSect->IsAnFollow( pNxtSect ) )
|
|
{
|
|
pSect = pNxtSect;
|
|
if( pLay->IsVertical() )
|
|
{
|
|
nFrmTop = pLay->Frm().Left() + pLay->Frm().Width();
|
|
nPrtHeight = pLay->Prt().Width();
|
|
}
|
|
else
|
|
{
|
|
nFrmTop = pLay->Frm().Top();
|
|
nPrtHeight = pLay->Prt().Height();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pLay = pSect->GetUpper();
|
|
if( pLay->IsVertical() )
|
|
{
|
|
nFrmTop = pSect->Frm().Left();
|
|
nPrtHeight = pSect->Frm().Left() -
|
|
pLay->Frm().Left() - pLay->Prt().Left();
|
|
}
|
|
else
|
|
{
|
|
nFrmTop = pSect->Frm().Bottom();
|
|
nPrtHeight = pLay->Frm().Top()+pLay->Prt().Top()
|
|
+ pLay->Prt().Height() - pSect->Frm().Top()
|
|
- pSect->Frm().Height();
|
|
}
|
|
pSect = 0;
|
|
}
|
|
}
|
|
else if( pLay )
|
|
{
|
|
if( pLay->IsVertical() )
|
|
{
|
|
nFrmTop = pLay->Frm().Left() + pLay->Frm().Width();
|
|
nPrtHeight = pLay->Prt().Width();
|
|
}
|
|
else
|
|
{
|
|
nFrmTop = pLay->Frm().Top();
|
|
nPrtHeight = pLay->Prt().Height();
|
|
}
|
|
bSct = 0 != pSect;
|
|
}
|
|
}
|
|
}
|
|
if ( pLay )
|
|
{
|
|
if ( pLay->Frm().IsInside( rPt ) )
|
|
{
|
|
SwTwips nDiff = pLay->IsVertical() ? ( nFrmTop - rPt.X() )
|
|
: ( rPt.Y() - nFrmTop );
|
|
if( bSct || pSect )
|
|
rRet.nSub += nDiff;
|
|
else
|
|
rRet.nMain += nDiff;
|
|
}
|
|
if ( pLay->IsFtnContFrm() && !((SwLayoutFrm*)pLay)->Lower() )
|
|
{
|
|
SwFrm *pDel = (SwFrm*)pLay;
|
|
pDel->Cut();
|
|
delete pDel;
|
|
return 0;
|
|
}
|
|
return pLay;
|
|
}
|
|
else
|
|
rRet.nMain = LONG_MAX;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//Bug 3985, optimierungsproblem, vergleiche auch trvlfrm.cxx lcl_FindCntnt()
|
|
#pragma optimize("e",off)
|
|
|
|
ULONG MA_FASTCALL lcl_FindCntDiff( const Point &rPt, const SwLayoutFrm *pLay,
|
|
const SwCntntFrm *& rpCnt,
|
|
const BOOL bBody, const BOOL bFtn )
|
|
{
|
|
//Sucht unterhalb von pLay den dichtesten Cnt zum Point. Der Bezugspunkt
|
|
//der Cntnts ist immer die linke obere Ecke.
|
|
//Der Cnt soll moeglichst ueber dem Point liegen.
|
|
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
Point arPoint( rPt );
|
|
#endif
|
|
|
|
rpCnt = 0;
|
|
ULONG nDistance = ULONG_MAX;
|
|
ULONG nNearest = ULONG_MAX;
|
|
const SwCntntFrm *pCnt = pLay->ContainsCntnt();
|
|
|
|
while ( pCnt && (bBody != pCnt->IsInDocBody() || bFtn != pCnt->IsInFtn()))
|
|
{
|
|
pCnt = pCnt->GetNextCntntFrm();
|
|
if ( !pLay->IsAnLower( pCnt ) )
|
|
pCnt = 0;
|
|
}
|
|
const SwCntntFrm *pNearest = pCnt;
|
|
if ( pCnt )
|
|
{
|
|
do
|
|
{
|
|
//Jetzt die Entfernung zwischen den beiden Punkten berechnen.
|
|
//'Delta' X^2 + 'Delta'Y^2 = 'Entfernung'^2
|
|
sal_uInt32 dX = Max( pCnt->Frm().Left(), rPt.X() ) -
|
|
Min( pCnt->Frm().Left(), rPt.X() ),
|
|
dY = Max( pCnt->Frm().Top(), rPt.Y() ) -
|
|
Min( pCnt->Frm().Top(), rPt.Y() );
|
|
BigInt dX1( dX ), dY1( dY );
|
|
dX1 *= dX1; dY1 *= dY1;
|
|
const ULONG nDiff = ::SqRt( dX1 + dY1 );
|
|
if ( pCnt->Frm().Top() <= rPt.Y() )
|
|
{
|
|
if ( nDiff < nDistance )
|
|
{ //Der ist dichter dran
|
|
nDistance = nNearest = nDiff;
|
|
rpCnt = pNearest = pCnt;
|
|
}
|
|
}
|
|
else if ( nDiff < nNearest )
|
|
{
|
|
nNearest = nDiff;
|
|
pNearest = pCnt;
|
|
}
|
|
pCnt = pCnt->GetNextCntntFrm();
|
|
while ( pCnt &&
|
|
(bBody != pCnt->IsInDocBody() || bFtn != pCnt->IsInFtn()))
|
|
pCnt = pCnt->GetNextCntntFrm();
|
|
|
|
} while ( pCnt && pLay->IsAnLower( pCnt ) );
|
|
}
|
|
if ( nDistance == ULONG_MAX )
|
|
{ rpCnt = pNearest;
|
|
return nNearest;
|
|
}
|
|
return nDistance;
|
|
}
|
|
|
|
#pragma optimize("e",on)
|
|
|
|
const SwCntntFrm * MA_FASTCALL lcl_FindCnt( const Point &rPt, const SwCntntFrm *pCnt,
|
|
const BOOL bBody, const BOOL bFtn )
|
|
{
|
|
//Sucht ausgehen von pCnt denjenigen CntntFrm, dessen linke obere
|
|
//Ecke am dichtesten am Point liegt.
|
|
//Liefert _immer_ einen CntntFrm zurueck.
|
|
|
|
//Zunaechst wird versucht den dichtesten Cntnt innerhalt derjenigen
|
|
//Seite zu suchen innerhalb derer der Cntnt steht.
|
|
//Ausgehend von der Seite muessen die Seiten in beide
|
|
//Richtungen beruecksichtigt werden.
|
|
//Falls moeglich wird ein Cntnt geliefert, dessen Y-Position ueber der
|
|
//des Point sitzt.
|
|
const SwCntntFrm *pRet, *pNew;
|
|
const SwLayoutFrm *pLay = pCnt->FindPageFrm();
|
|
ULONG nDist;
|
|
|
|
nDist = ::lcl_FindCntDiff( rPt, pLay, pNew, bBody, bFtn );
|
|
if ( pNew )
|
|
pRet = pNew;
|
|
else
|
|
{ pRet = pCnt;
|
|
nDist = ULONG_MAX;
|
|
}
|
|
const SwCntntFrm *pNearest = pRet;
|
|
ULONG nNearest = nDist;
|
|
|
|
if ( pLay )
|
|
{
|
|
const SwLayoutFrm *pPge = pLay;
|
|
ULONG nOldNew = ULONG_MAX;
|
|
for ( USHORT i = 0; pPge->GetPrev() && (i < 3); ++i )
|
|
{
|
|
pPge = (SwLayoutFrm*)pPge->GetPrev();
|
|
const ULONG nNew = ::lcl_FindCntDiff( rPt, pPge, pNew, bBody, bFtn );
|
|
if ( nNew < nDist )
|
|
{
|
|
if ( pNew->Frm().Top() <= rPt.Y() )
|
|
{
|
|
pRet = pNearest = pNew;
|
|
nDist = nNearest = nNew;
|
|
}
|
|
else if ( nNew < nNearest )
|
|
{
|
|
pNearest = pNew;
|
|
nNearest = nNew;
|
|
}
|
|
}
|
|
else if ( nOldNew != ULONG_MAX && nNew > nOldNew )
|
|
break;
|
|
else
|
|
nOldNew = nNew;
|
|
|
|
}
|
|
pPge = pLay;
|
|
nOldNew = ULONG_MAX;
|
|
for ( USHORT j = 0; pPge->GetNext() && (j < 3); ++j )
|
|
{
|
|
pPge = (SwLayoutFrm*)pPge->GetNext();
|
|
const ULONG nNew = ::lcl_FindCntDiff( rPt, pPge, pNew, bBody, bFtn );
|
|
if ( nNew < nDist )
|
|
{
|
|
if ( pNew->Frm().Top() <= rPt.Y() )
|
|
{
|
|
pRet = pNearest = pNew;
|
|
nDist = nNearest = nNew;
|
|
}
|
|
else if ( nNew < nNearest )
|
|
{
|
|
pNearest = pNew;
|
|
nNearest = nNew;
|
|
}
|
|
}
|
|
else if ( nOldNew != ULONG_MAX && nNew > nOldNew )
|
|
break;
|
|
else
|
|
nOldNew = nNew;
|
|
}
|
|
}
|
|
if ( (pRet->Frm().Top() > rPt.Y()) )
|
|
return pNearest;
|
|
else
|
|
return pRet;
|
|
}
|
|
|
|
void lcl_PointToPrt( Point &rPoint, const SwFrm *pFrm )
|
|
{
|
|
SwRect aTmp( pFrm->Prt() );
|
|
aTmp += pFrm->Frm().Pos();
|
|
if ( rPoint.X() < aTmp.Left() )
|
|
rPoint.X() = aTmp.Left();
|
|
else if ( rPoint.X() > aTmp.Right() )
|
|
rPoint.X() = aTmp.Right();
|
|
if ( rPoint.Y() < aTmp.Top() )
|
|
rPoint.Y() = aTmp.Top();
|
|
else if ( rPoint.Y() > aTmp.Bottom() )
|
|
rPoint.Y() = aTmp.Bottom();
|
|
|
|
}
|
|
|
|
const SwCntntFrm *FindAnchor( const SwFrm *pOldAnch, const Point &rNew,
|
|
const BOOL bBodyOnly )
|
|
{
|
|
//Zu der angegebenen DokumentPosition wird der dichteste Cnt im
|
|
//Textfluss gesucht. AusgangsFrm ist der uebergebene Anker.
|
|
const SwCntntFrm* pCnt;
|
|
if ( pOldAnch->IsCntntFrm() )
|
|
{
|
|
pCnt = (const SwCntntFrm*)pOldAnch;
|
|
}
|
|
else
|
|
{
|
|
Point aTmp( rNew );
|
|
SwLayoutFrm *pTmpLay = (SwLayoutFrm*)pOldAnch;
|
|
if( pTmpLay->IsRootFrm() )
|
|
{
|
|
SwRect aTmpRect( aTmp, Size(0,0) );
|
|
pTmpLay = (SwLayoutFrm*)::FindPage( aTmpRect, pTmpLay->Lower() );
|
|
}
|
|
pCnt = pTmpLay->GetCntntPos( aTmp, FALSE, bBodyOnly );
|
|
}
|
|
|
|
//Beim Suchen darauf achten, dass die Bereiche sinnvoll erhalten
|
|
//bleiben. D.h. in diesem Fall nicht in Header/Footer hinein und
|
|
//nicht aus Header/Footer hinaus.
|
|
const BOOL bBody = pCnt->IsInDocBody() || bBodyOnly;
|
|
const BOOL bFtn = !bBodyOnly && pCnt->IsInFtn();
|
|
|
|
Point aNew( rNew );
|
|
if ( bBody )
|
|
{
|
|
//#38848 Vom Seitenrand in den Body ziehen.
|
|
const SwFrm *pPage = pCnt->FindPageFrm();
|
|
::lcl_PointToPrt( aNew, pPage->GetUpper() );
|
|
SwRect aTmp( aNew, Size( 0, 0 ) );
|
|
pPage = ::FindPage( aTmp, pPage );
|
|
::lcl_PointToPrt( aNew, pPage );
|
|
}
|
|
|
|
if ( pCnt->IsInDocBody() == bBody && pCnt->Frm().IsInside( aNew ) )
|
|
return pCnt;
|
|
else if ( pOldAnch->IsInDocBody() || pOldAnch->IsPageFrm() )
|
|
{
|
|
//Vielleicht befindet sich der gewuenschte Anker ja auf derselben
|
|
//Seite wie der aktuelle Anker.
|
|
//So gibt es kein Problem mit Spalten.
|
|
Point aTmp( aNew );
|
|
const SwCntntFrm *pTmp = pCnt->FindPageFrm()->
|
|
GetCntntPos( aTmp, FALSE, TRUE, FALSE );
|
|
if ( pTmp && pTmp->Frm().IsInside( aNew ) )
|
|
return pTmp;
|
|
}
|
|
|
|
//Ausgehend vom Anker suche ich jetzt in beide Richtungen bis ich
|
|
//den jeweils dichtesten gefunden habe.
|
|
//Nicht die direkte Entfernung ist relevant sondern die Strecke die
|
|
//im Textfluss zurueckgelegt werden muss.
|
|
const SwCntntFrm *pUpLst;
|
|
const SwCntntFrm *pUpFrm = pCnt;
|
|
SwDistance nUp, nUpLst;
|
|
::lcl_CalcDownDist( nUp, aNew, pUpFrm );
|
|
SwDistance nDown = nUp;
|
|
BOOL bNegAllowed = TRUE;//Einmal aus dem negativen Bereich heraus lassen.
|
|
do
|
|
{
|
|
pUpLst = pUpFrm; nUpLst = nUp;
|
|
pUpFrm = pUpLst->GetPrevCntntFrm();
|
|
while ( pUpFrm &&
|
|
(bBody != pUpFrm->IsInDocBody() || bFtn != pUpFrm->IsInFtn()))
|
|
pUpFrm = pUpFrm->GetPrevCntntFrm();
|
|
if ( pUpFrm )
|
|
{
|
|
::lcl_CalcDownDist( nUp, aNew, pUpFrm );
|
|
//Wenn die Distanz innnerhalb einer Tabelle waechst, so lohnt es
|
|
//sich weiter zu suchen.
|
|
if ( pUpLst->IsInTab() && pUpFrm->IsInTab() )
|
|
{
|
|
while ( pUpFrm && ((nUpLst < nUp && pUpFrm->IsInTab()) ||
|
|
bBody != pUpFrm->IsInDocBody()) )
|
|
{
|
|
pUpFrm = pUpFrm->GetPrevCntntFrm();
|
|
if ( pUpFrm )
|
|
::lcl_CalcDownDist( nUp, aNew, pUpFrm );
|
|
}
|
|
}
|
|
}
|
|
if ( !pUpFrm )
|
|
nUp.nMain = LONG_MAX;
|
|
if ( nUp.nMain >= 0 && LONG_MAX != nUp.nMain )
|
|
{
|
|
bNegAllowed = FALSE;
|
|
if ( nUpLst.nMain < 0 ) //nicht den falschen erwischen, wenn der Wert
|
|
//gerade von negativ auf positiv gekippt ist.
|
|
{ pUpLst = pUpFrm;
|
|
nUpLst = nUp;
|
|
}
|
|
}
|
|
} while ( pUpFrm && ( ( bNegAllowed && nUp.nMain < 0 ) || ( nUp <= nUpLst ) ) );
|
|
|
|
const SwCntntFrm *pDownLst;
|
|
const SwCntntFrm *pDownFrm = pCnt;
|
|
SwDistance nDownLst;
|
|
if ( nDown.nMain < 0 )
|
|
nDown.nMain = LONG_MAX;
|
|
do
|
|
{
|
|
pDownLst = pDownFrm; nDownLst = nDown;
|
|
pDownFrm = pDownLst->GetNextCntntFrm();
|
|
while ( pDownFrm &&
|
|
(bBody != pDownFrm->IsInDocBody() || bFtn != pDownFrm->IsInFtn()))
|
|
pDownFrm = pDownFrm->GetNextCntntFrm();
|
|
if ( pDownFrm )
|
|
{
|
|
::lcl_CalcDownDist( nDown, aNew, pDownFrm );
|
|
if ( nDown.nMain < 0 )
|
|
nDown.nMain = LONG_MAX;
|
|
//Wenn die Distanz innnerhalb einer Tabelle waechst, so lohnt es
|
|
//sich weiter zu suchen.
|
|
if ( pDownLst->IsInTab() && pDownFrm->IsInTab() )
|
|
{
|
|
while ( pDownFrm && ( ( nDown.nMain != LONG_MAX && nDownLst < nDownLst
|
|
&& pDownFrm->IsInTab()) || bBody != pDownFrm->IsInDocBody() ) )
|
|
{
|
|
pDownFrm = pDownFrm->GetNextCntntFrm();
|
|
if ( pDownFrm )
|
|
::lcl_CalcDownDist( nDown, aNew, pDownFrm );
|
|
if ( nDown.nMain < 0 )
|
|
nDown.nMain = LONG_MAX;
|
|
}
|
|
}
|
|
}
|
|
if ( !pDownFrm )
|
|
nDown.nMain = LONG_MAX;
|
|
|
|
} while ( pDownFrm && nDown <= nDownLst &&
|
|
nDown.nMain != LONG_MAX && nDownLst.nMain != LONG_MAX );
|
|
|
|
//Wenn ich in beide Richtungen keinen gefunden habe, so suche ich mir
|
|
//denjenigen Cntnt dessen linke obere Ecke dem Point am naechsten liegt.
|
|
//Eine derartige Situation tritt z.b. auf, wenn der Point nicht im Text-
|
|
//fluss sondern in irgendwelchen Raendern steht.
|
|
if ( nDownLst.nMain == LONG_MAX && nUpLst.nMain == LONG_MAX )
|
|
{
|
|
// #102861# If an OLE objects, which is contained in a fly frame
|
|
// is resized in inplace mode and the new Position is outside the
|
|
// fly frame, we do not want to leave our fly frame.
|
|
if ( pCnt->IsInFly() )
|
|
return pCnt;
|
|
|
|
return ::lcl_FindCnt( aNew, pCnt, bBody, bFtn );
|
|
}
|
|
else
|
|
return nDownLst < nUpLst ? pDownLst : pUpLst;
|
|
}
|
|
|
|
/*************************************************************************
|
|
|*
|
|
|* SwFlyAtCntFrm::SetAbsPos()
|
|
|*
|
|
|* Ersterstellung MA 22. Jun. 93
|
|
|* Letzte Aenderung MA 11. Sep. 98
|
|
|*
|
|
|*************************************************************************/
|
|
|
|
void SwFlyAtCntFrm::SetAbsPos( const Point &rNew )
|
|
{
|
|
SwPageFrm *pOldPage = FindPageFrm();
|
|
const SwRect aOld( GetObjRectWithSpaces() );
|
|
Point aNew( rNew );
|
|
|
|
if( GetAnchorFrm()->IsVertical() || GetAnchorFrm()->IsRightToLeft() )
|
|
|
|
aNew.X() += Frm().Width();
|
|
SwCntntFrm *pCnt = (SwCntntFrm*)::FindAnchor( GetAnchorFrm(), aNew );
|
|
if( pCnt->IsProtected() )
|
|
pCnt = (SwCntntFrm*)GetAnchorFrm();
|
|
|
|
SwPageFrm *pPage = 0;
|
|
SWRECTFN( pCnt )
|
|
const sal_Bool bRTL = pCnt->IsRightToLeft();
|
|
|
|
if( ( bVert != GetAnchorFrm()->IsVertical() ) ||
|
|
( bRTL != GetAnchorFrm()->IsRightToLeft() ) )
|
|
{
|
|
if( bVert || bRTL )
|
|
aNew.X() += Frm().Width();
|
|
else
|
|
aNew.X() -= Frm().Width();
|
|
}
|
|
|
|
if ( pCnt->IsInDocBody() )
|
|
{
|
|
//#38848 Vom Seitenrand in den Body ziehen.
|
|
pPage = pCnt->FindPageFrm();
|
|
::lcl_PointToPrt( aNew, pPage->GetUpper() );
|
|
SwRect aTmp( aNew, Size( 0, 0 ) );
|
|
pPage = (SwPageFrm*)::FindPage( aTmp, pPage );
|
|
::lcl_PointToPrt( aNew, pPage );
|
|
}
|
|
|
|
//RelPos einstellen, nur auf Wunsch invalidieren.
|
|
//rNew ist eine Absolute Position. Um die RelPos korrekt einzustellen
|
|
//muessen wir uns die Entfernung von rNew zum Anker im Textfluss besorgen.
|
|
//!!!!!Hier kann Optimiert werden: FindAnchor koennte die RelPos mitliefern!
|
|
const SwFrm *pFrm = 0;
|
|
SwTwips nY;
|
|
if ( pCnt->Frm().IsInside( aNew ) )
|
|
{
|
|
if( bVert )
|
|
nY = pCnt->Frm().Left()+pCnt->Frm().Width()-rNew.X()-Frm().Width();
|
|
else
|
|
nY = rNew.Y() - pCnt->Frm().Top();
|
|
}
|
|
else
|
|
{
|
|
SwDistance aDist;
|
|
pFrm = ::lcl_CalcDownDist( aDist, aNew, pCnt );
|
|
nY = aDist.nMain + aDist.nSub;
|
|
}
|
|
|
|
SwTwips nX = 0;
|
|
|
|
if ( pCnt->IsFollow() )
|
|
{
|
|
//Flys haengen niemals an einem Follow sondern immer am
|
|
//Master, den suchen wir uns jetzt.
|
|
const SwCntntFrm *pOriginal = pCnt;
|
|
const SwCntntFrm *pFollow = pCnt;
|
|
while ( pCnt->IsFollow() )
|
|
{
|
|
do
|
|
{ pCnt = pCnt->GetPrevCntntFrm();
|
|
} while ( pCnt->GetFollow() != pFollow );
|
|
pFollow = pCnt;
|
|
}
|
|
SwTwips nDiff = 0;
|
|
do
|
|
{ const SwFrm *pUp = pFollow->GetUpper();
|
|
if( pUp->IsVertical() )
|
|
nDiff += pFollow->Frm().Left() + pFollow->Frm().Width()
|
|
- pUp->Frm().Left() - pUp->Prt().Left();
|
|
else
|
|
nDiff += pUp->Prt().Height() - pFollow->GetRelPos().Y();
|
|
pFollow = pFollow->GetFollow();
|
|
} while ( pFollow != pOriginal );
|
|
nY += nDiff;
|
|
if( bVert )
|
|
nX = pCnt->Frm().Top() - pOriginal->Frm().Top();
|
|
else
|
|
nX = pCnt->Frm().Left() - pOriginal->Frm().Left();
|
|
}
|
|
|
|
if ( nY == LONG_MAX )
|
|
{
|
|
if( bVert )
|
|
nY = pCnt->Frm().Left() + pCnt->Frm().Width() - rNew.X();
|
|
else
|
|
nY = rNew.Y() - pCnt->Frm().Top();
|
|
}
|
|
|
|
SwFlyFrmFmt *pFmt = (SwFlyFrmFmt*)GetFmt();
|
|
const SwFmtSurround& rSurround = pFmt->GetSurround();
|
|
const FASTBOOL bWrapThrough =
|
|
rSurround.GetSurround() == SURROUND_THROUGHT;
|
|
SwTwips nBaseOfstForFly = 0;
|
|
const SwFrm* pTmpFrm = pFrm ? pFrm : pCnt;
|
|
if ( pTmpFrm->IsTxtFrm() )
|
|
nBaseOfstForFly =
|
|
((SwTxtFrm*)pTmpFrm)->GetBaseOfstForFly( !bWrapThrough );
|
|
|
|
if( bVert )
|
|
{
|
|
if( !pFrm )
|
|
nX += rNew.Y() - pCnt->Frm().Top() - nBaseOfstForFly;
|
|
else
|
|
nX = rNew.Y() - pFrm->Frm().Top() - nBaseOfstForFly;
|
|
}
|
|
else
|
|
{
|
|
if( !pFrm )
|
|
{
|
|
if ( pCnt->IsRightToLeft() )
|
|
nX += pCnt->Frm().Right() - rNew.X() - Frm().Width() +
|
|
nBaseOfstForFly;
|
|
else
|
|
nX += rNew.X() - pCnt->Frm().Left() - nBaseOfstForFly;
|
|
}
|
|
else
|
|
{
|
|
if ( pFrm->IsRightToLeft() )
|
|
nX += pFrm->Frm().Right() - rNew.X() - Frm().Width() +
|
|
nBaseOfstForFly;
|
|
else
|
|
nX = rNew.X() - pFrm->Frm().Left() - nBaseOfstForFly;
|
|
}
|
|
}
|
|
GetFmt()->GetDoc()->StartUndo( UNDO_START );
|
|
|
|
if( pCnt != GetAnchorFrm() || ( IsAutoPos() && pCnt->IsTxtFrm() &&
|
|
GetFmt()->GetDoc()->IsHTMLMode() ) )
|
|
{
|
|
//Das Ankerattribut auf den neuen Cnt setzen.
|
|
SwFmtAnchor aAnch( pFmt->GetAnchor() );
|
|
SwPosition *pPos = (SwPosition*)aAnch.GetCntntAnchor();
|
|
if( IsAutoPos() && pCnt->IsTxtFrm() )
|
|
{
|
|
SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
|
|
Point aPt( rNew );
|
|
if( pCnt->GetCrsrOfst( pPos, aPt, &eTmpState )
|
|
&& pPos->nNode == *pCnt->GetNode() )
|
|
{
|
|
ResetLastCharRectHeight();
|
|
if( REL_CHAR == pFmt->GetVertOrient().GetRelationOrient() )
|
|
nY = LONG_MAX;
|
|
if( REL_CHAR == pFmt->GetHoriOrient().GetRelationOrient() )
|
|
nX = LONG_MAX;
|
|
}
|
|
else
|
|
{
|
|
pPos->nNode = *pCnt->GetNode();
|
|
pPos->nContent.Assign( pCnt->GetNode(), 0 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPos->nNode = *pCnt->GetNode();
|
|
pPos->nContent.Assign( pCnt->GetNode(), 0 );
|
|
}
|
|
|
|
// --> OD 2006-02-27 #125892#
|
|
// handle change of anchor node:
|
|
// if count of the anchor frame also change, the fly frames have to be
|
|
// re-created. Thus, delete all fly frames except the <this> before the
|
|
// anchor attribute is change and re-create them afterwards.
|
|
{
|
|
SwHandleAnchorNodeChg aHandleAnchorNodeChg( *pFmt, aAnch, this );
|
|
pFmt->GetDoc()->SetAttr( aAnch, *pFmt );
|
|
}
|
|
// <--
|
|
}
|
|
// --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
|
|
else if ( pPage && pPage != GetPageFrm() )
|
|
GetPageFrm()->MoveFly( this, pPage );
|
|
|
|
const Point aRelPos = bVert ? Point( -nY, nX ) : Point( nX, nY );
|
|
ChgRelPos( aRelPos );
|
|
|
|
GetFmt()->GetDoc()->EndUndo( UNDO_END );
|
|
|
|
if ( pOldPage != FindPageFrm() )
|
|
::Notify_Background( GetVirtDrawObj(), pOldPage, aOld, PREP_FLY_LEAVE,
|
|
FALSE );
|
|
}
|
|
|
|
// OD 2004-08-12 #i32795# - Note: method no longer used in <flyincnt.cxx>
|
|
//void DeepCalc( const SwFrm *pFrm )
|
|
//{
|
|
// if( pFrm->IsSctFrm() ||
|
|
// ( pFrm->IsFlyFrm() && ((SwFlyFrm*)pFrm)->IsFlyInCntFrm() ) )
|
|
// return;
|
|
// const SwFlowFrm *pFlow = SwFlowFrm::CastFlowFrm( pFrm );
|
|
// if( pFlow && pFlow->IsAnyJoinLocked() )
|
|
// return;
|
|
|
|
// USHORT nCnt = 0;
|
|
|
|
// FASTBOOL bContinue = FALSE;
|
|
// do
|
|
// {
|
|
// if ( ++nCnt == 10 )
|
|
// {
|
|
// ASSERT( !nCnt, "DeepCalc: Loop detected1?" );
|
|
// break;
|
|
// }
|
|
|
|
// const FASTBOOL bSetComplete = !pFrm->IsValid();
|
|
// const SwRect aOldFrm( pFrm->Frm() );
|
|
// const SwRect aOldPrt( pFrm->Prt() );
|
|
|
|
// const SwFrm *pUp = pFrm->GetUpper();
|
|
// if ( pUp )
|
|
// {
|
|
// //Nicht weiter wenn der Up ein Fly mit Spalten ist.
|
|
// if( ( !pUp->IsFlyFrm() || !((SwLayoutFrm*)pUp)->Lower() ||
|
|
// !((SwLayoutFrm*)pUp)->Lower()->IsColumnFrm() ) &&
|
|
// !pUp->IsSctFrm() )
|
|
// {
|
|
// SWRECTFN( pUp )
|
|
// const Point aPt( (pUp->Frm().*fnRect->fnGetPos)() );
|
|
// ::DeepCalc( pUp );
|
|
// bContinue = aPt != (pUp->Frm().*fnRect->fnGetPos)();
|
|
// }
|
|
// }
|
|
// else
|
|
// pUp = pFrm;
|
|
|
|
// pFrm->Calc();
|
|
// if ( bSetComplete && (aOldFrm != pFrm->Frm() || aOldPrt != pFrm->Prt()))
|
|
// pFrm->SetCompletePaint();
|
|
|
|
// if ( pUp->IsFlyFrm() )
|
|
// {
|
|
// if ( ((SwFlyFrm*)pUp)->IsLocked() ||
|
|
// (((SwFlyFrm*)pUp)->IsFlyAtCntFrm() &&
|
|
// SwOszControl::IsInProgress( (const SwFlyFrm*)pUp )) )
|
|
// {
|
|
// bContinue = FALSE;
|
|
// }
|
|
// }
|
|
// } while ( bContinue );
|
|
//}
|
|
|
|
/** method to assure that anchored object is registered at the correct
|
|
page frame
|
|
|
|
OD 2004-07-02 #i28701#
|
|
takes over functionality of deleted method <SwFlyAtCntFrm::AssertPage()>
|
|
|
|
@author OD
|
|
*/
|
|
void SwFlyAtCntFrm::RegisterAtCorrectPage()
|
|
{
|
|
SwPageFrm* pPageFrm( 0L );
|
|
if ( GetVertPosOrientFrm() )
|
|
{
|
|
pPageFrm = const_cast<SwPageFrm*>(GetVertPosOrientFrm()->FindPageFrm());
|
|
}
|
|
if ( pPageFrm && GetPageFrm() != pPageFrm )
|
|
{
|
|
if ( GetPageFrm() )
|
|
GetPageFrm()->MoveFly( this, pPageFrm );
|
|
else
|
|
pPageFrm->AppendFlyToPage( this );
|
|
}
|
|
}
|
|
|
|
// OD 2004-03-23 #i26791#
|
|
//void SwFlyAtCntFrm::MakeFlyPos()
|
|
void SwFlyAtCntFrm::MakeObjPos()
|
|
{
|
|
// OD 02.10.2002 #102646#
|
|
// if fly frame position is valid, nothing is to do. Thus, return
|
|
if ( bValidPos )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// OD 2004-03-24 #i26791# - validate position flag here.
|
|
bValidPos = TRUE;
|
|
|
|
// --> OD 2004-10-22 #i35911# - no calculation of new position, if
|
|
// anchored object is marked that it clears its environment and its
|
|
// environment is already cleared.
|
|
// --> OD 2006-01-02 #125977# - before checking for cleared environment
|
|
// check, if member <mpVertPosOrientFrm> is set.
|
|
if ( GetVertPosOrientFrm() &&
|
|
ClearedEnvironment() && HasClearedEnvironment() )
|
|
{
|
|
return;
|
|
}
|
|
// <--
|
|
|
|
// OD 29.10.2003 #113049# - use new class to position object
|
|
objectpositioning::SwToCntntAnchoredObjectPosition
|
|
aObjPositioning( *GetVirtDrawObj() );
|
|
aObjPositioning.CalcPosition();
|
|
|
|
SetVertPosOrientFrm ( aObjPositioning.GetVertPosOrientFrm() );
|
|
}
|
|
|
|
// OD 2004-05-12 #i28701#
|
|
bool SwFlyAtCntFrm::_InvalidationAllowed( const InvalidationType _nInvalid ) const
|
|
{
|
|
bool bAllowed( SwFlyFreeFrm::_InvalidationAllowed( _nInvalid ) );
|
|
|
|
// forbiddance of base instance can't be over ruled.
|
|
if ( bAllowed )
|
|
{
|
|
if ( _nInvalid == INVALID_POS ||
|
|
_nInvalid == INVALID_ALL )
|
|
{
|
|
bAllowed = InvalidationOfPosAllowed();
|
|
}
|
|
}
|
|
|
|
return bAllowed;
|
|
}
|