/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
//determine new anchor
Point aTmpPnt( rPt ); switch( nNew )
{ case RndStdIds::FLY_AS_CHAR: // also include this? case RndStdIds::FLY_AT_PARA: case RndStdIds::FLY_AT_CHAR: // LAYER_IMPL
{ // starting from the upper-left corner of the Fly, // search nearest ContentFrame const SwFrame* pFrame = rFrame.IsFlyFrame() ? static_cast<const SwFlyFrame&>(rFrame).GetAnchorFrame()
: &rFrame;
pNewAnch = ::FindAnchor( pFrame, aTmpPnt ); if( pNewAnch->IsProtected() )
{
bRet = false; break;
}
SwPosition aPos( pNewAnch->IsTextFrame()
? *static_cast<SwTextFrame const*>(pNewAnch)->GetTextNodeForParaProps()
: *static_cast<const SwNoTextFrame*>(pNewAnch)->GetNode() ); if ((RndStdIds::FLY_AT_CHAR == nNew) || (RndStdIds::FLY_AS_CHAR == nNew))
{ // textnode should be found, as only in those // a content bound frame can be anchored
SwCursorMoveState aState( CursorMoveState::SetOnlyText );
aTmpPnt.setX(aTmpPnt.getX() - 1); // do not land in the fly! if( !pNewAnch->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState ) )
{
assert(pNewAnch->IsTextFrame()); // because AT_CHAR/AS_CHAR
SwTextFrame const*const pTextFrame( static_cast<SwTextFrame const*>(pNewAnch)); if( pNewAnch->getFrameArea().Bottom() < aTmpPnt.Y() )
{
aPos = pTextFrame->MapViewToModelPos(TextFrameIndex(0));
} else
{
aPos = pTextFrame->MapViewToModelPos(
TextFrameIndex(pTextFrame->GetText().getLength()));
}
} else
{ if ( SwCursorShell::PosInsideInputField( aPos ) )
{
aPos.SetContent( SwCursorShell::StartOfInputFieldAtPos( aPos ) );
}
}
}
aNewAnch.SetAnchor( &aPos );
} break;
case RndStdIds::FLY_AT_FLY: // LAYER_IMPL
{ // starting from the upper-left corner of the Fly // search nearest SwFlyFrame
SwCursorMoveState aState( CursorMoveState::SetOnlyText );
SwPosition aPos( rDoc.GetNodes() );
aTmpPnt.setX(aTmpPnt.getX() - 1); // do not land in the fly!
rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState );
pNewAnch = ::FindAnchor(
aPos.GetNode().GetContentNode()->getLayoutFrame(rFrame.getRootFrame(), nullptr, nullptr),
aTmpPnt )->FindFlyFrame();
void SwFEShell::SelectFlyFrame( SwFlyFrame& rFrame )
{
CurrShell aCurr( this );
// The frame is new, thus select it. // !! Always select the frame, if it's not selected. // - it could be a new "old" one because the anchor was changed // - "old" frames have had to be selected previously otherwise they could // not have been changed // The frames should not be selected by the document position, because // it should have been selected!
SwViewShellImp *pImpl = Imp(); if( !GetWin() ) return;
OSL_ENSURE( rFrame.IsFlyFrame(), "SelectFlyFrame wants a Fly" );
// nothing to be done if the Fly already was selected if (GetSelectedFlyFrame() == &rFrame) return;
// assure the anchor is drawn if( rFrame.IsFlyInContentFrame() && rFrame.GetAnchorFrame() )
rFrame.GetAnchorFrame()->SetCompletePaint();
const SwEndNode* pFlyEnd = pFlyStart->GetNode().EndOfSectionNode(); if (!pFlyEnd)
{ return;
}
// Create an empty paragraph after the table, so the frame's SwNodes section is non-empty after // MoveNodeRange(). Undo would ensure it's non-empty and then node offsets won't match.
IDocumentContentOperations& rIDCO = GetDoc()->getIDocumentContentOperations();
{
SwNodeIndex aInsertIndex(*pFlyEnd);
--aInsertIndex;
SwPosition aInsertPos(aInsertIndex);
StartAllAction();
rIDCO.AppendTextNode(aInsertPos); // Make sure that a layout frame is created for the node, so the fly frame is not deleted, // during MoveNodeRange(), either.
EndAllAction();
}
// Move the content outside of the text frame.
SwNodeIndex aInsertPos(*pAnchor);
rIDCO.MoveNodeRange(aRange, aInsertPos.GetNode(), SwMoveFlags::CREATEUNDOOBJ);
// Get selected fly
SwFlyFrame* SwFEShell::GetSelectedFlyFrame() const
{ if ( Imp()->HasDrawView() )
{ // A Fly is only accessible if it is selected const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList(); if( rMrkList.GetMarkCount() != 1 ) return nullptr;
// Get current fly in which the cursor is positioned
SwFlyFrame* SwFEShell::GetCurrFlyFrame(constbool bCalcFrame) const
{
SwContentFrame *pContent = GetCurrFrame(bCalcFrame); return pContent ? pContent->FindFlyFrame() : nullptr;
}
// Get selected fly, but if none Get current fly in which the cursor is positioned
SwFlyFrame* SwFEShell::GetSelectedOrCurrFlyFrame() const
{
SwFlyFrame *pFly = GetSelectedFlyFrame(); if (pFly) return pFly; return GetCurrFlyFrame();
}
// Returns non-null pointer, if the current Fly could be anchored to another one (so it is inside) const SwFrameFormat* SwFEShell::IsFlyInFly()
{
CurrShell aCurr( this );
// Determine reference point in document coordinates
SwFlyFrame *pFly = GetCurrFlyFrame(false); if (!pFly) return;
//SwSaveHdl aSaveX( Imp() );
// Set an anchor starting from the absolute position for paragraph bound Flys // Anchor and new RelPos will be calculated and set by the Fly if ( pFly->IsFlyAtContentFrame() )
{ if(pFly->IsFlyFreeFrame() && static_cast< SwFlyFreeFrame* >(pFly)->isTransformableSwFrame())
{ // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used), // we need to correct the absolute position (rAbsPos) which was created in // transformed coordinates to untransformed state
TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(pFly)->getTransformableSwFrame()); const SwRect aUntransformedFrameArea(pTransformableSwFrame->getUntransformedFrameArea()); const Point aNewAbsPos(
rAbsPos.X() + aUntransformedFrameArea.Left() - pFly->getFrameArea().Left(),
rAbsPos.Y() + aUntransformedFrameArea.Top() - pFly->getFrameArea().Top()); static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos(aNewAbsPos);
} else
{ static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos( rAbsPos );
}
} else
{ const SwFrame *pAnch = pFly->GetAnchorFrame();
Point aOrient( pAnch->getFrameArea().Pos() );
if ( pFly->IsFlyInContentFrame() )
aOrient.setX(rAbsPos.getX());
// calculate RelPos.
aOrient.setX(rAbsPos.getX() - aOrient.getX());
aOrient.setY(rAbsPos.getY() - aOrient.getY());
pFly->ChgRelPos( aOrient );
}
CallChgLnk(); // call the AttrChangeNotify on the UI-side.
}
Point SwFEShell::FindAnchorPos( const Point& rAbsPos, bool bMoveIt )
{
Point aRet;
// set <pFooterOrHeader> also for drawing // objects, but not for control objects. // Necessary for moving 'anchor symbol' at the user interface inside header/footer. elseif ( !::CheckControlLayer( pObj ) )
{
SwContentFrame *pContent = GetCurrFrame( false ); if( !pContent ) return aRet;
pFooterOrHeader = pContent->FindFooterOrHeader();
}
if( pNewAnch && !pNewAnch->IsProtected() )
{ const SwFlyFrame* pCheck = (bFlyFrame || bTextBox) ? pNewAnch->FindFlyFrame() : nullptr; // If we land inside the frame, make sure // that the frame does not land inside its own content while( pCheck )
{ if( pCheck == pFly ) break; const SwFrame *pTmp = pCheck->GetAnchorFrame();
pCheck = pTmp ? pTmp->FindFlyFrame() : nullptr;
}
// Do not switch from header/footer to another area, // do not switch to a header/footer if( !pCheck &&
pFooterOrHeader == pNewAnch->FindFooterOrHeader() )
{
aRet = pNewAnch->GetFrameAnchorPos( ::HasWrap( pObj ) );
if( bMoveIt )
{
StartAllAction(); // --> 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.
{
std::unique_ptr<SwHandleAnchorNodeChg> pHandleAnchorNodeChg;
SwFlyFrameFormat* pFlyFrameFormat( dynamic_cast<SwFlyFrameFormat*>(pFormat) ); if ( pFlyFrameFormat )
{
pHandleAnchorNodeChg.reset( new SwHandleAnchorNodeChg( *pFlyFrameFormat, aAnch ));
}
pFormat->GetDoc().SetAttr( aAnch, *pFormat ); if (SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT,
pObj))
{ if (SdrObjList* pObjList = pObj->getChildrenOfSdrObject())
{ for (const rtl::Reference<SdrObject>& pChild : *pObjList)
SwTextBoxHelper::changeAnchor(pFormat, pChild.get());
} else
SwTextBoxHelper::syncFlyFrameAttr(
*pFormat, pFormat->GetAttrSet(), pObj);
}
} // #i28701# - no call of method // <CheckCharRectAndTopOfLine()> for to-character anchored // Writer fly frame needed. This method call can cause a // format of the anchor frame, which is no longer intended. // Instead clear the anchor character rectangle and // the top of line values for all to-character anchored objects.
pAnchoredObj->ClearCharRectAndTopOfLine();
EndAllAction();
}
}
SwPaM* pCursor = GetCursor(); const Point aPt( GetCursorDocPos() );
SwSelBoxes aBoxes; bool bMoveContent = true; if( IsTableMode() )
{
GetTableSel( *this, aBoxes ); if( !aBoxes.empty() )
{ // Cursor should be removed from the removal area. // Always put it after/on the table; via the // document position they will be set to the old // position
ParkCursor( *aBoxes[0]->GetSttNd() );
// #i127787# pCurrentCursor will be deleted in ParkCursor, // we better get the current pCurrentCursor instead of working with the // deleted one:
pCursor = GetCursor();
} else
bMoveContent = false;
} elseif( !pCursor->HasMark() && !pCursor->IsMultiSelection() )
bMoveContent = false;
if ( RndStdIds::FLY_AT_PAGE != eRndId )
{ // First as with page link. Paragraph/character link on if // everything was shifted. Then the position is valid! // JP 13.05.98: if necessary also convert the horizontal/vertical // orientation, to prevent correction during re-anchoring
pOldAnchor.reset(new SwFormatAnchor( rAnch )); const_cast<SfxItemSet&>(rSet).Put( SwFormatAnchor( RndStdIds::FLY_AT_PAGE, 1 ) );
pRet = GetDoc()->MakeFlyAndMove( *pCursor, rSet, &aBoxes, pParent );
KillPams();
if( pOldAnchor )
{ if( pRet )
{ // calculate new position // JP 24.03.97: also go via page links // anchor should not lie in the shifted area
pRet->DelFrames();
// shifting of table selection is not Undo-capable. therefore // changing the anchors should not be recorded boolconst bDoesUndo =
GetDoc()->GetIDocumentUndoRedo().DoesUndo();
SwUndoId nLastUndoId(SwUndoId::EMPTY); if (bDoesUndo &&
GetDoc()->GetIDocumentUndoRedo().GetLastUndoInfo(nullptr,
& nLastUndoId))
{ if (SwUndoId::INSLAYFMT == nLastUndoId)
{
GetDoc()->GetIDocumentUndoRedo().DoUndo(false);
}
}
GetDoc()->SetFlyFrameAttr( *pRet, const_cast<SfxItemSet&>(rSet) );
GetDoc()->GetIDocumentUndoRedo().DoUndo(bDoesUndo);
}
}
GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::INSLAYFMT, nullptr );
} else /* If called from a shell try to propagate an existing adjust item from rPos to the content node of the
new frame. */
pRet = GetDoc()->MakeFlySection( eRndId, &rPos, &rSet, pParent, true );
namespace
{ /// If pCursor points to an as-char anchored graphic node, then set the node's anchor position on /// pAnchor and rPam. bool SetAnchorOnGrfNodeForAsChar(SwShellCursor *pCursor, SwFormatAnchor* pAnchor, std::optional<SwPaM>& rPam)
{ const SwPosition* pPoint = pCursor->GetPoint(); if (pAnchor->GetAnchorId() != RndStdIds::FLY_AS_CHAR)
{ returnfalse;
}
if (!pPoint->GetNode().IsGrfNode())
{ returnfalse;
}
SwFrameFormat* pFrameFormat = pPoint->GetNode().GetFlyFormat(); if (!pFrameFormat)
{ returnfalse;
}
const SwPosition* pContentAnchor = pFrameFormat->GetAnchor().GetContentAnchor(); if (!pContentAnchor)
{ returnfalse;
}
// Has the anchor not been set or been set incompletely?
std::optional<SwPaM> oPam; if( pFlyAttrSet )
{ if( const SwFormatAnchor* pItem = pFlyAttrSet->GetItemIfSet( RES_ANCHOR, false ) )
{
SwFormatAnchor* pAnchor = const_cast<SwFormatAnchor*>(pItem); switch( pAnchor->GetAnchorId())
{ case RndStdIds::FLY_AT_PARA: case RndStdIds::FLY_AT_CHAR: // LAYER_IMPL case RndStdIds::FLY_AS_CHAR: if( !pAnchor->GetAnchorNode() )
{ if (SetAnchorOnGrfNodeForAsChar(pCursor, pAnchor, oPam))
{ // Don't anchor the image on the previous image, rather insert them next // to each other. break;
}
if( pFrame )
{ // add a redline to the anchor point at tracked insertion of picture if ( IsRedlineOn() )
{ const SwPosition & rPos(*pFormat->GetAnchor().GetContentAnchor());
SwPaM aPaM(rPos.GetNode(), rPos.GetContentIndex(),
rPos.GetNode(), rPos.GetContentIndex() + 1);
GetDoc()->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPaM ), true);
}
// fdo#36681: Invalidate the content and layout to refresh // the picture anchoring properly
SwPageFrame* pPageFrame = pFrame->FindPageFrameOfAnchor();
pPageFrame->InvalidateFlyLayout();
pPageFrame->InvalidateContent();
// All attributes in the "baskets" will be filled with the attributes of the // current FlyFrames. Attributes which cannot be filled due to being at the // wrong place or which are ambiguous (multiple selections) will be removed. bool SwFEShell::GetFlyFrameAttr( SfxItemSet &rSet ) const
{
SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame(); if (!pFly)
{
OSL_ENSURE( false, "GetFlyFrameAttr, no Fly selected." ); returnfalse;
}
SfxItemSet SwFEShell::makeItemSetFromFormatAnchor(SfxItemPool& rPool, const SwFormatAnchor &rAnchor)
{ // The set also includes VERT/HORI_ORIENT, because the align // shall be changed in FEShell::SetFlyFrameAttr/SetFlyFrameAnchor, // possibly as a result of the anchor change.
SfxItemSet aSet(SfxItemSet::makeFixedSfxItemSet<RES_VERT_ORIENT, RES_ANCHOR>(rPool));
aSet.Put(rAnchor); return aSet;
}
// MA we do not allow to clip the Fly, as the OLE server can // request various wishes. Clipping is done via the formatting. // Correct display is done by scaling. // Scaling is done by SwNoTextFrame::Format by calling // SwWrtShell::CalcAndSetScale() if ( rRect.SSize() != pFly->getFramePrintArea().SSize() && !bSizeProt )
{
Size aSz( rRect.SSize() );
//JP 28.02.2001: Task 74707 - ask for fly in fly with automatic size
// set the new Size at the fly themself if ( !pFly->getFramePrintArea().IsEmpty() )
{
aSz.AdjustWidth(pFly->getFrameArea().Width() - pFly->getFramePrintArea().Width() );
aSz.AdjustHeight(pFly->getFrameArea().Height()- pFly->getFramePrintArea().Height() );
}
aResult = pFly->ChgSize( aSz );
// if the object changes, the contour is outside the object
SwFrame* pLower = pFly->Lower();
assert(pLower && pLower->IsNoTextFrame());
SwNoTextNode *pNd = static_cast<SwNoTextFrame*>(pLower)->GetNode()->GetNoTextNode();
assert(pNd);
pNd->SetContour( nullptr );
ClrContourCache();
}
// if only the size is to be adjusted, a position is transported with // allocated values
Point aPt( pFly->getFramePrintArea().Pos() );
aPt += pFly->getFrameArea().Pos(); if ( rRect.Top() != LONG_MIN && rRect.Pos() != aPt && !bPosProt )
{
aPt = rRect.Pos();
aPt.setX(aPt.getX() - pFly->getFramePrintArea().Left());
aPt.setY(aPt.getY() - pFly->getFramePrintArea().Top());
// in case of paragraph-bound Flys, starting from the new position, // a new anchor is to be set. The anchor and the new RelPos are // calculated by the Fly and set if( pFly->IsFlyAtContentFrame() ) static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos( aPt ); else
{ const SwFrameFormat *pFormat = pFly->GetFormat(); const SwFormatVertOrient &rVert = pFormat->GetVertOrient(); const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient(); const tools::Long lXDiff = aPt.getX() - pFly->getFrameArea().Left(); const tools::Long lYDiff = aPt.getY() - pFly->getFrameArea().Top(); const Point aTmp( rHori.GetPos() + lXDiff,
rVert.GetPos() + lYDiff );
pFly->ChgRelPos( aTmp );
}
}
SwFlyFrameFormat *pFlyFrameFormat = pFly->GetFormat();
OSL_ENSURE( pFlyFrameFormat, "fly frame format missing!" ); if ( pFlyFrameFormat )
pFlyFrameFormat->SetLastFlyFramePrtRectPos( pFly->getFramePrintArea().Pos() ); //stores the value of last Prt rect
EndAllAction();
return aResult;
}
SwFrameFormat* SwFEShell::WizardGetFly()
{ // do not search the Fly via the layout. Now we can delete a frame // without a valid layout. ( e.g. for the wizards )
sw::SpzFrameFormats& rSpzArr = *mxDoc->GetSpzFrameFormats(); if( !rSpzArr.empty() )
{
SwNode& rCursorNd = GetCursor()->GetPoint()->GetNode(); if( rCursorNd > mxDoc->GetNodes().GetEndOfExtras() ) // Cursor is in the body area! return nullptr;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.