12e48f91d4
Change-Id: I69cf0cc769861a24a7239ad82c0c46a12dbed5f1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168811 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Jenkins
2281 lines
76 KiB
C++
2281 lines
76 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <hintids.hxx>
|
|
#include <o3tl/any.hxx>
|
|
#include <svl/itemiter.hxx>
|
|
#include <vcl/imapobj.hxx>
|
|
#include <editeng/protitem.hxx>
|
|
#include <svx/svdogrp.hxx>
|
|
#include <svx/svdouno.hxx>
|
|
#include <tools/globname.hxx>
|
|
#include <sot/exchange.hxx>
|
|
#include <com/sun/star/form/FormButtonType.hpp>
|
|
#include <com/sun/star/beans/XPropertySet.hpp>
|
|
#include <com/sun/star/embed/XEmbeddedObject.hpp>
|
|
#include <comphelper/types.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <comphelper/scopeguard.hxx>
|
|
#include <fmtanchr.hxx>
|
|
#include <fmtcntnt.hxx>
|
|
#include <fmtornt.hxx>
|
|
#include <fmturl.hxx>
|
|
#include <fmtfsize.hxx>
|
|
#include <fesh.hxx>
|
|
#include <rootfrm.hxx>
|
|
#include <pagefrm.hxx>
|
|
#include <cntfrm.hxx>
|
|
#include <txtfrm.hxx>
|
|
#include <viewimp.hxx>
|
|
#include <viscrs.hxx>
|
|
#include <doc.hxx>
|
|
#include <IDocumentDrawModelAccess.hxx>
|
|
#include <IDocumentUndoRedo.hxx>
|
|
#include <IDocumentState.hxx>
|
|
#include <IDocumentLayoutAccess.hxx>
|
|
#include <IDocumentRedlineAccess.hxx>
|
|
#include <redline.hxx>
|
|
#include <dview.hxx>
|
|
#include <dflyobj.hxx>
|
|
#include <dcontact.hxx>
|
|
#include <frmfmt.hxx>
|
|
#include <flyfrm.hxx>
|
|
#include <ndtxt.hxx>
|
|
#include <swtable.hxx>
|
|
#include <ndgrf.hxx>
|
|
#include <flyfrms.hxx>
|
|
#include <fldbas.hxx>
|
|
#include <fmtfld.hxx>
|
|
#include <swundo.hxx>
|
|
#include <txatbase.hxx>
|
|
#include <frame.hxx>
|
|
#include <notxtfrm.hxx>
|
|
#include <HandleAnchorNodeChg.hxx>
|
|
#include <frmatr.hxx>
|
|
#include <fmtsrnd.hxx>
|
|
#include <ndole.hxx>
|
|
#include <fefly.hxx>
|
|
#include <fmtcnct.hxx>
|
|
#include <frameformats.hxx>
|
|
#include <textboxhelper.hxx>
|
|
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
// Based on the request, changes to the specific layouts will be made, to
|
|
// fit to the format
|
|
static bool lcl_SetNewFlyPos( const SwNode& rNode, SwFormatAnchor& rAnchor,
|
|
const Point& rPt )
|
|
{
|
|
bool bRet = false;
|
|
const SwStartNode* pStNode = rNode.FindFlyStartNode();
|
|
if( pStNode )
|
|
{
|
|
SwPosition aPos( *pStNode );
|
|
rAnchor.SetAnchor( &aPos );
|
|
bRet = true;
|
|
}
|
|
else
|
|
{
|
|
const SwContentNode *pCntNd = rNode.GetContentNode();
|
|
std::pair<Point, bool> const tmp(rPt, false);
|
|
const SwContentFrame* pCFrame = pCntNd ? pCntNd->getLayoutFrame(
|
|
pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
|
|
nullptr, &tmp) : nullptr;
|
|
const SwPageFrame *pPg = pCFrame ? pCFrame->FindPageFrame() : nullptr;
|
|
|
|
rAnchor.SetPageNum( pPg ? pPg->GetPhyPageNum() : 1 );
|
|
rAnchor.SetType( RndStdIds::FLY_AT_PAGE );
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
static bool lcl_FindAnchorPos(
|
|
SwDoc& rDoc,
|
|
const Point& rPt,
|
|
const SwFrame& rFrame,
|
|
SfxItemSet& rSet )
|
|
{
|
|
bool bRet = true;
|
|
SwFormatAnchor aNewAnch( rSet.Get( RES_ANCHOR ) );
|
|
RndStdIds nNew = aNewAnch.GetAnchorId();
|
|
const SwFrame *pNewAnch;
|
|
|
|
//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();
|
|
|
|
if( pNewAnch && &rFrame != pNewAnch && !pNewAnch->IsProtected() )
|
|
{
|
|
aPos.Assign( *static_cast<const SwFlyFrame*>(pNewAnch)->GetFormat()->GetContent().
|
|
GetContentIdx() );
|
|
aNewAnch.SetAnchor( &aPos );
|
|
break;
|
|
}
|
|
}
|
|
|
|
nNew = RndStdIds::FLY_AT_PAGE;
|
|
aNewAnch.SetType( nNew );
|
|
[[fallthrough]];
|
|
|
|
case RndStdIds::FLY_AT_PAGE:
|
|
pNewAnch = rFrame.FindPageFrame();
|
|
aNewAnch.SetPageNum( pNewAnch->GetPhyPageNum() );
|
|
break;
|
|
|
|
default:
|
|
OSL_ENSURE( false, "Wrong Id for new anchor." );
|
|
}
|
|
|
|
rSet.Put( aNewAnch );
|
|
return bRet;
|
|
}
|
|
|
|
//! also used in unoframe.cxx
|
|
|
|
bool sw_ChkAndSetNewAnchor(
|
|
const SwFlyFrame& rFly,
|
|
SfxItemSet& rSet )
|
|
{
|
|
const SwFrameFormat& rFormat = *rFly.GetFormat();
|
|
const SwFormatAnchor &rOldAnch = rFormat.GetAnchor();
|
|
const RndStdIds nOld = rOldAnch.GetAnchorId();
|
|
|
|
RndStdIds nNew = rSet.Get( RES_ANCHOR ).GetAnchorId();
|
|
|
|
if( nOld == nNew )
|
|
return false;
|
|
|
|
SwDoc* pDoc = const_cast<SwDoc*>(rFormat.GetDoc());
|
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
OSL_ENSURE( !(nNew == RndStdIds::FLY_AT_PAGE &&
|
|
(RndStdIds::FLY_AT_PARA==nOld || RndStdIds::FLY_AT_CHAR==nOld || RndStdIds::FLY_AS_CHAR==nOld ) &&
|
|
pDoc->IsInHeaderFooter( *rOldAnch.GetAnchorNode() )),
|
|
"forbidden anchor change in Head/Foot." );
|
|
#endif
|
|
|
|
return ::lcl_FindAnchorPos( *pDoc, rFly.getFrameArea().Pos(), rFly, rSet );
|
|
}
|
|
|
|
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();
|
|
|
|
if( pImpl->GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0 )
|
|
pImpl->GetDrawView()->UnmarkAll();
|
|
|
|
pImpl->GetDrawView()->MarkObj( rFrame.GetVirtDrawObj(),
|
|
pImpl->GetPageView() );
|
|
|
|
rFrame.SelectionHasChanged(this);
|
|
|
|
KillPams();
|
|
ClearMark();
|
|
SelFlyGrabCursor();
|
|
}
|
|
|
|
void SwFEShell::UnfloatFlyFrame()
|
|
{
|
|
GetIDocumentUndoRedo().StartUndo(SwUndoId::DELLAYFMT, nullptr);
|
|
comphelper::ScopeGuard g([this]
|
|
{ GetIDocumentUndoRedo().EndUndo(SwUndoId::DELLAYFMT, nullptr); });
|
|
|
|
SwFlyFrame* pFly = GetSelectedFlyFrame();
|
|
if (!pFly)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SwFrameFormat* pFlyFormat = pFly->GetFrameFormat();
|
|
const SwFormatContent& rContent = pFlyFormat->GetContent();
|
|
const SwNodeIndex* pFlyStart = rContent.GetContentIdx();
|
|
if (!pFlyStart)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
SwNodeRange aRange(pFlyStart->GetNode(), SwNodeOffset(1), *pFlyEnd, SwNodeOffset(-1));
|
|
const SwFormatAnchor& rAnchor = pFlyFormat->GetAnchor();
|
|
SwNode* pAnchor = rAnchor.GetAnchorNode();
|
|
if (!pAnchor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Move the content outside of the text frame.
|
|
SwNodeIndex aInsertPos(*pAnchor);
|
|
rIDCO.MoveNodeRange(aRange, aInsertPos.GetNode(), SwMoveFlags::CREATEUNDOOBJ);
|
|
|
|
// Remove the fly frame frame.
|
|
IDocumentLayoutAccess& rIDLA = pFlyFormat->getIDocumentLayoutAccess();
|
|
rIDLA.DelLayoutFormat(pFlyFormat);
|
|
}
|
|
|
|
// 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;
|
|
|
|
SdrObject *pO = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
|
|
|
|
SwVirtFlyDrawObj *pFlyObj = dynamic_cast<SwVirtFlyDrawObj*>(pO);
|
|
|
|
return pFlyObj ? pFlyObj->GetFlyFrame() : nullptr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Get current fly in which the cursor is positioned
|
|
SwFlyFrame* SwFEShell::GetCurrFlyFrame(const bool 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 );
|
|
|
|
if ( !Imp()->HasDrawView() )
|
|
return nullptr;
|
|
|
|
const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
|
|
if ( !rMrkList.GetMarkCount() )
|
|
{
|
|
SwFlyFrame *pFly = GetCurrFlyFrame(false);
|
|
if (!pFly)
|
|
return nullptr;
|
|
return pFly->GetFormat();
|
|
}
|
|
else if ( rMrkList.GetMarkCount() != 1 )
|
|
return nullptr;
|
|
|
|
SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
|
|
SwContact* pContact = GetUserCall( pObj );
|
|
if (!pContact)
|
|
return nullptr;
|
|
|
|
SwFrameFormat *pFormat = FindFrameFormat( pObj );
|
|
if( pFormat && RndStdIds::FLY_AT_FLY == pFormat->GetAnchor().GetAnchorId() )
|
|
{
|
|
const SwFrame* pFly;
|
|
if (SwVirtFlyDrawObj* pFlyObj = dynamic_cast<SwVirtFlyDrawObj *>(pObj))
|
|
{
|
|
pFly = pFlyObj->GetFlyFrame()->GetAnchorFrame();
|
|
}
|
|
else
|
|
{
|
|
pFly = static_cast<SwDrawContact*>(pContact)->GetAnchorFrame(pObj);
|
|
}
|
|
|
|
assert(pFly && "IsFlyInFly: Where's my anchor?");
|
|
OSL_ENSURE( pFly->IsFlyFrame(), "IsFlyInFly: Funny anchor!" );
|
|
return static_cast<const SwFlyFrame*>(pFly)->GetFormat();
|
|
}
|
|
|
|
Point aTmpPos = pObj->GetCurrentBoundRect().TopLeft();
|
|
|
|
SwFrame *pTextFrame;
|
|
{
|
|
SwCursorMoveState aState( CursorMoveState::SetOnlyText );
|
|
SwNodeIndex aSwNodeIndex( GetDoc()->GetNodes() );
|
|
SwPosition aPos( aSwNodeIndex );
|
|
Point aPoint( aTmpPos );
|
|
aPoint.setX(aPoint.getX() - 1); //do not land in the fly!!
|
|
GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState );
|
|
// determine text frame by left-top-corner of object
|
|
SwContentNode *pNd = aPos.GetNode().GetContentNode();
|
|
std::pair<Point, bool> const tmp(aTmpPos, false);
|
|
pTextFrame = pNd ? pNd->getLayoutFrame(GetLayout(), nullptr, &tmp) : nullptr;
|
|
}
|
|
const SwFrame *pTmp = pTextFrame ? ::FindAnchor(pTextFrame, aTmpPos) : nullptr;
|
|
const SwFlyFrame *pFly = pTmp ? pTmp->FindFlyFrame() : nullptr;
|
|
if( pFly )
|
|
return pFly->GetFormat();
|
|
return nullptr;
|
|
}
|
|
|
|
void SwFEShell::SetFlyPos( const Point& rAbsPos )
|
|
{
|
|
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;
|
|
|
|
CurrShell aCurr( this );
|
|
|
|
if ( !Imp()->HasDrawView() )
|
|
return aRet;
|
|
|
|
const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
|
|
if (rMrkList.GetMarkCount() != 1)
|
|
return aRet;
|
|
|
|
SdrObject* pObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
|
|
|
|
SwContact* pContact = ::GetUserCall( pObj );
|
|
if (!pContact)
|
|
return aRet;
|
|
|
|
assert(pObj);
|
|
|
|
// #i28701#
|
|
SwAnchoredObject* pAnchoredObj = pContact->GetAnchoredObj( pObj );
|
|
SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
|
|
const RndStdIds nAnchorId = pFormat->GetAnchor().GetAnchorId();
|
|
|
|
if ( RndStdIds::FLY_AS_CHAR == nAnchorId )
|
|
return aRet;
|
|
|
|
bool bFlyFrame = dynamic_cast<SwVirtFlyDrawObj *>(pObj) != nullptr;
|
|
|
|
bool bTextBox = false;
|
|
if (pFormat->Which() == RES_DRAWFRMFMT)
|
|
{
|
|
bTextBox = SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, pObj);
|
|
}
|
|
|
|
SwFlyFrame* pFly = nullptr;
|
|
const SwFrame* pFooterOrHeader = nullptr;
|
|
|
|
if( bFlyFrame )
|
|
{
|
|
// Calculate reference point in document coordinates
|
|
SwContentFrame *pContent = GetCurrFrame( false );
|
|
if( !pContent )
|
|
return aRet;
|
|
pFly = pContent->FindFlyFrame();
|
|
if ( !pFly )
|
|
return aRet;
|
|
const SwFrame* pOldAnch = pFly->GetAnchorFrame();
|
|
if( !pOldAnch )
|
|
return aRet;
|
|
if ( RndStdIds::FLY_AT_PAGE != nAnchorId )
|
|
{
|
|
pFooterOrHeader = pContent->FindFooterOrHeader();
|
|
}
|
|
}
|
|
else if (bTextBox)
|
|
{
|
|
auto pFlyFormat
|
|
= dynamic_cast<const SwFlyFrameFormat*>(SwTextBoxHelper::getOtherTextBoxFormat(
|
|
pFormat, RES_DRAWFRMFMT, pObj));
|
|
if (pFlyFormat)
|
|
{
|
|
pFly = pFlyFormat->GetFrame();
|
|
}
|
|
}
|
|
|
|
// set <pFooterOrHeader> also for drawing
|
|
// objects, but not for control objects.
|
|
// Necessary for moving 'anchor symbol' at the user interface inside header/footer.
|
|
else if ( !::CheckControlLayer( pObj ) )
|
|
{
|
|
SwContentFrame *pContent = GetCurrFrame( false );
|
|
if( !pContent )
|
|
return aRet;
|
|
pFooterOrHeader = pContent->FindFooterOrHeader();
|
|
}
|
|
|
|
// Search nearest SwFlyFrame starting from the upper-left corner
|
|
// of the fly
|
|
SwContentFrame *pTextFrame = nullptr;
|
|
{
|
|
SwCursorMoveState aState( CursorMoveState::SetOnlyText );
|
|
SwPosition aPos( GetDoc()->GetNodes().GetEndOfExtras() );
|
|
Point aTmpPnt( rAbsPos );
|
|
GetLayout()->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState );
|
|
if (aPos.GetNode() != GetDoc()->GetNodes().GetEndOfExtras()
|
|
&& (nAnchorId != RndStdIds::FLY_AT_CHAR || !PosInsideInputField(aPos)))
|
|
{
|
|
SwContentNode* pCNode = aPos.GetNode().GetContentNode();
|
|
assert(pCNode);
|
|
pTextFrame = pCNode->getLayoutFrame(GetLayout(), &aPos, nullptr);
|
|
}
|
|
}
|
|
const SwFrame *pNewAnch = nullptr;
|
|
if( pTextFrame != nullptr )
|
|
{
|
|
if ( RndStdIds::FLY_AT_PAGE == nAnchorId )
|
|
{
|
|
pNewAnch = pTextFrame->FindPageFrame();
|
|
}
|
|
else
|
|
{
|
|
pNewAnch = ::FindAnchor( pTextFrame, rAbsPos );
|
|
|
|
if( RndStdIds::FLY_AT_FLY == nAnchorId ) // LAYER_IMPL
|
|
{
|
|
pNewAnch = pNewAnch->FindFlyFrame();
|
|
}
|
|
}
|
|
}
|
|
|
|
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 || (nAnchorId == RndStdIds::FLY_AT_CHAR) )
|
|
{
|
|
SwFormatAnchor aAnch( pFormat->GetAnchor() );
|
|
switch ( nAnchorId )
|
|
{
|
|
case RndStdIds::FLY_AT_PARA:
|
|
{
|
|
SwPosition pos(pTextFrame->IsTextFrame()
|
|
? *static_cast<SwTextFrame const*>(pTextFrame)->GetTextNodeForParaProps()
|
|
: *static_cast<const SwNoTextFrame*>(pTextFrame)->GetNode());
|
|
aAnch.SetAnchor( &pos );
|
|
break;
|
|
}
|
|
case RndStdIds::FLY_AT_PAGE:
|
|
{
|
|
aAnch.SetPageNum( static_cast<const SwPageFrame*>(pNewAnch)->
|
|
GetPhyPageNum() );
|
|
break;
|
|
}
|
|
|
|
case RndStdIds::FLY_AT_FLY:
|
|
{
|
|
SwPosition aPos( *static_cast<const SwFlyFrame*>(pNewAnch)->GetFormat()->
|
|
GetContent().GetContentIdx() );
|
|
aAnch.SetAnchor( &aPos );
|
|
break;
|
|
}
|
|
|
|
case RndStdIds::FLY_AT_CHAR:
|
|
{
|
|
SwPosition pos = *aAnch.GetContentAnchor();
|
|
Point aTmpPnt( rAbsPos );
|
|
if( pTextFrame->GetModelPositionForViewPoint( &pos, aTmpPnt ) )
|
|
{
|
|
SwRect aTmpRect;
|
|
pTextFrame->GetCharRect( aTmpRect, pos );
|
|
aRet = aTmpRect.Pos();
|
|
}
|
|
else
|
|
{
|
|
pos = static_cast<SwTextFrame const*>(pTextFrame)->MapViewToModelPos(TextFrameIndex(0));
|
|
}
|
|
aAnch.SetAnchor( &pos );
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
SwRect aTmpRect( aRet, rAbsPos );
|
|
if( aTmpRect.HasArea() )
|
|
MakeVisible( aTmpRect );
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
//TODO: That doesn't seem to be intended
|
|
if( COL_TRANSPARENT != GetOut()->GetLineColor() )
|
|
{
|
|
OSL_FAIL( "Hey, Joe: Where's my Null Pen?" );
|
|
GetOut()->SetLineColor( COL_TRANSPARENT );
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return aRet;
|
|
}
|
|
|
|
const SwFrameFormat *SwFEShell::NewFlyFrame( const SfxItemSet& rSet, bool bAnchValid,
|
|
SwFrameFormat *pParent )
|
|
{
|
|
CurrShell aCurr( this );
|
|
StartAllAction();
|
|
|
|
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;
|
|
}
|
|
else if( !pCursor->HasMark() && !pCursor->IsMultiSelection() )
|
|
bMoveContent = false;
|
|
|
|
const SwPosition& rPos = *pCursor->Start();
|
|
|
|
SwFormatAnchor& rAnch = const_cast<SwFormatAnchor&>(rSet.Get( RES_ANCHOR ));
|
|
RndStdIds eRndId = rAnch.GetAnchorId();
|
|
switch( eRndId )
|
|
{
|
|
case RndStdIds::FLY_AT_PAGE:
|
|
if( !rAnch.GetPageNum() ) //HotFix: Bug in UpdateByExample
|
|
rAnch.SetPageNum( 1 );
|
|
break;
|
|
|
|
case RndStdIds::FLY_AT_FLY:
|
|
case RndStdIds::FLY_AT_PARA:
|
|
case RndStdIds::FLY_AT_CHAR:
|
|
case RndStdIds::FLY_AS_CHAR:
|
|
if( !bAnchValid )
|
|
{
|
|
if( RndStdIds::FLY_AT_FLY != eRndId )
|
|
{
|
|
rAnch.SetAnchor( &rPos );
|
|
}
|
|
else if( lcl_SetNewFlyPos( rPos.GetNode(), rAnch, aPt ) )
|
|
{
|
|
eRndId = RndStdIds::FLY_AT_PAGE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
OSL_ENSURE( false, "What is the purpose of this Fly?" );
|
|
break;
|
|
}
|
|
|
|
SwFlyFrameFormat *pRet;
|
|
if( bMoveContent )
|
|
{
|
|
GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::INSLAYFMT, nullptr );
|
|
std::unique_ptr<SwFormatAnchor> pOldAnchor;
|
|
bool bHOriChgd = false, bVOriChgd = false;
|
|
std::shared_ptr<SwFormatVertOrient> aOldV;
|
|
std::shared_ptr<SwFormatHoriOrient> aOldH;
|
|
|
|
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 ) );
|
|
|
|
const SwFormatHoriOrient* pHoriOrientItem;
|
|
if( (pHoriOrientItem = rSet.GetItemIfSet( RES_HORI_ORIENT, false ))
|
|
&& text::HoriOrientation::NONE == pHoriOrientItem->GetHoriOrient() )
|
|
{
|
|
bHOriChgd = true;
|
|
aOldH.reset(pHoriOrientItem->Clone());
|
|
const_cast<SfxItemSet&>(rSet).Put( SwFormatHoriOrient( 0, text::HoriOrientation::LEFT ) );
|
|
}
|
|
const SwFormatVertOrient* pVertOrientItem;
|
|
if( (pVertOrientItem = rSet.GetItemIfSet( RES_VERT_ORIENT, false ))
|
|
&& text::VertOrientation::NONE == pVertOrientItem->GetVertOrient() )
|
|
{
|
|
bVOriChgd = true;
|
|
aOldV.reset(pVertOrientItem->Clone());
|
|
const_cast<SfxItemSet&>(rSet).Put( SwFormatVertOrient( 0, text::VertOrientation::TOP ) );
|
|
}
|
|
}
|
|
|
|
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();
|
|
|
|
const SwFrame* pAnch = ::FindAnchor( GetLayout(), aPt );
|
|
SwPosition aPos( pAnch->IsTextFrame()
|
|
? *static_cast<SwTextFrame const*>(pAnch)->GetTextNodeForParaProps()
|
|
: *static_cast<const SwNoTextFrame*>(pAnch)->GetNode() );
|
|
|
|
if ( RndStdIds::FLY_AS_CHAR == eRndId )
|
|
{
|
|
assert(pAnch->IsTextFrame());
|
|
aPos = static_cast<SwTextFrame const*>(pAnch)->MapViewToModelPos(TextFrameIndex(0));
|
|
}
|
|
pOldAnchor->SetAnchor( &aPos );
|
|
|
|
// shifting of table selection is not Undo-capable. therefore
|
|
// changing the anchors should not be recorded
|
|
bool const bDoesUndo =
|
|
GetDoc()->GetIDocumentUndoRedo().DoesUndo();
|
|
SwUndoId nLastUndoId(SwUndoId::EMPTY);
|
|
if (bDoesUndo &&
|
|
GetDoc()->GetIDocumentUndoRedo().GetLastUndoInfo(nullptr,
|
|
& nLastUndoId))
|
|
{
|
|
if (SwUndoId::INSLAYFMT == nLastUndoId)
|
|
{
|
|
GetDoc()->GetIDocumentUndoRedo().DoUndo(false);
|
|
}
|
|
}
|
|
|
|
const_cast<SfxItemSet&>(rSet).Put( std::move(pOldAnchor) );
|
|
|
|
if( bHOriChgd )
|
|
const_cast<SfxItemSet&>(rSet).Put( *aOldH );
|
|
if( bVOriChgd )
|
|
const_cast<SfxItemSet&>(rSet).Put( *aOldV );
|
|
|
|
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 );
|
|
|
|
if( pRet )
|
|
{
|
|
SwFlyFrame* pFrame = pRet->GetFrame( &aPt );
|
|
if( pFrame )
|
|
SelectFlyFrame( *pFrame );
|
|
else
|
|
{
|
|
GetLayout()->SetAssertFlyPages();
|
|
pRet = nullptr;
|
|
}
|
|
}
|
|
EndAllActionAndCall();
|
|
|
|
return pRet;
|
|
}
|
|
|
|
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)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!pPoint->GetNode().IsGrfNode())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SwFrameFormat* pFrameFormat = pPoint->GetNode().GetFlyFormat();
|
|
if (!pFrameFormat)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const SwPosition* pContentAnchor = pFrameFormat->GetAnchor().GetContentAnchor();
|
|
if (!pContentAnchor)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SwPosition aPosition(*pContentAnchor);
|
|
++aPosition.nContent;
|
|
pAnchor->SetAnchor(&aPosition);
|
|
rPam.emplace(aPosition);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void SwFEShell::Insert( const OUString& rGrfName, const OUString& rFltName,
|
|
const Graphic* pGraphic,
|
|
const SfxItemSet* pFlyAttrSet )
|
|
{
|
|
SwFlyFrameFormat* pFormat = nullptr;
|
|
CurrShell aCurr( this );
|
|
StartAllAction();
|
|
SwShellCursor *pStartCursor = dynamic_cast<SwShellCursor*>(GetCursor());
|
|
SwShellCursor *pCursor = pStartCursor;
|
|
do
|
|
{
|
|
if (!pCursor)
|
|
break;
|
|
|
|
// 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;
|
|
}
|
|
|
|
pAnchor->SetAnchor( pCursor->GetPoint() );
|
|
}
|
|
break;
|
|
case RndStdIds::FLY_AT_FLY:
|
|
if( !pAnchor->GetAnchorNode() )
|
|
{
|
|
lcl_SetNewFlyPos( pCursor->GetPointNode(),
|
|
*pAnchor, GetCursorDocPos() );
|
|
}
|
|
break;
|
|
case RndStdIds::FLY_AT_PAGE:
|
|
if( !pAnchor->GetPageNum() )
|
|
{
|
|
pAnchor->SetPageNum( pCursor->GetPageNum(
|
|
true, &pCursor->GetPtPos() ) );
|
|
}
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pFormat = GetDoc()->getIDocumentContentOperations().InsertGraphic(
|
|
oPam.has_value() ? *oPam : *pCursor, rGrfName,
|
|
rFltName, pGraphic,
|
|
pFlyAttrSet,
|
|
nullptr, nullptr );
|
|
OSL_ENSURE(pFormat, "IDocumentContentOperations::InsertGraphic failed.");
|
|
|
|
pCursor = pCursor->GetNext();
|
|
} while( pCursor != pStartCursor );
|
|
|
|
EndAllAction();
|
|
|
|
if( !pFormat )
|
|
return;
|
|
|
|
const Point aPt( GetCursorDocPos() );
|
|
SwFlyFrame* pFrame = pFormat->GetFrame( &aPt );
|
|
|
|
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();
|
|
|
|
SelectFlyFrame( *pFrame );
|
|
}
|
|
else
|
|
GetLayout()->SetAssertFlyPages();
|
|
}
|
|
|
|
SwFlyFrameFormat* SwFEShell::InsertObject( const svt::EmbeddedObjectRef& xObj,
|
|
SfxItemSet* pFlyAttrSet )
|
|
{
|
|
SwFlyFrameFormat* pFormat = nullptr;
|
|
CurrShell aCurr( this );
|
|
StartAllAction();
|
|
{
|
|
for(const SwPaM& rPaM : GetCursor()->GetRingContainer())
|
|
{
|
|
pFormat = GetDoc()->getIDocumentContentOperations().InsertEmbObject(
|
|
rPaM, xObj, pFlyAttrSet );
|
|
OSL_ENSURE(pFormat, "IDocumentContentOperations::InsertEmbObject failed.");
|
|
}
|
|
}
|
|
EndAllAction();
|
|
|
|
if( pFormat )
|
|
{
|
|
const Point aPt( GetCursorDocPos() );
|
|
SwFlyFrame* pFrame = pFormat->GetFrame( &aPt );
|
|
|
|
if( pFrame )
|
|
SelectFlyFrame( *pFrame );
|
|
else
|
|
GetLayout()->SetAssertFlyPages();
|
|
}
|
|
|
|
return pFormat;
|
|
}
|
|
|
|
void SwFEShell::InsertDrawObj( SdrObject& rDrawObj,
|
|
const Point& rInsertPosition )
|
|
{
|
|
CurrShell aCurr( this );
|
|
|
|
SfxItemSet rFlyAttrSet( GetDoc()->GetAttrPool(), aFrameFormatSetRange );
|
|
rFlyAttrSet.Put( SwFormatAnchor( RndStdIds::FLY_AT_PARA ));
|
|
// #i89920#
|
|
rFlyAttrSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) );
|
|
rDrawObj.SetLayer( getIDocumentDrawModelAccess().GetHeavenId() );
|
|
|
|
// find anchor position
|
|
SwPaM aPam( mxDoc->GetNodes() );
|
|
{
|
|
SwCursorMoveState aState( CursorMoveState::SetOnlyText );
|
|
Point aTmpPt( rInsertPosition );
|
|
GetLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aTmpPt, &aState );
|
|
const SwFrame* pFrame = aPam.GetPointContentNode()->getLayoutFrame(GetLayout(), nullptr, nullptr);
|
|
const Point aRelPos( rInsertPosition.X() - pFrame->getFrameArea().Left(),
|
|
rInsertPosition.Y() - pFrame->getFrameArea().Top() );
|
|
rDrawObj.SetRelativePos( aRelPos );
|
|
::lcl_FindAnchorPos( *GetDoc(), rInsertPosition, *pFrame, rFlyAttrSet );
|
|
}
|
|
// insert drawing object into the document creating a new <SwDrawFrameFormat> instance
|
|
SwDrawFrameFormat* pFormat = GetDoc()->getIDocumentContentOperations().InsertDrawObj( aPam, rDrawObj, rFlyAttrSet );
|
|
|
|
// move object to visible layer
|
|
SwContact* pContact = static_cast<SwContact*>(rDrawObj.GetUserCall());
|
|
if ( pContact )
|
|
{
|
|
pContact->MoveObjToVisibleLayer( &rDrawObj );
|
|
}
|
|
|
|
if (pFormat)
|
|
{
|
|
pFormat->SetFormatName(rDrawObj.GetName());
|
|
// select drawing object
|
|
Imp()->GetDrawView()->MarkObj( &rDrawObj, Imp()->GetPageView() );
|
|
}
|
|
else
|
|
{
|
|
GetLayout()->SetAssertFlyPages();
|
|
}
|
|
}
|
|
|
|
void SwFEShell::GetPageObjs( std::vector<SwFrameFormat*>& rFillArr )
|
|
{
|
|
rFillArr.clear();
|
|
|
|
for(sw::SpzFrameFormat* pFormat : *mxDoc->GetSpzFrameFormats() )
|
|
{
|
|
if (RndStdIds::FLY_AT_PAGE == pFormat->GetAnchor().GetAnchorId())
|
|
{
|
|
rFillArr.push_back( pFormat );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SwFEShell::SetPageObjsNewPage( std::vector<SwFrameFormat*>& rFillArr )
|
|
{
|
|
if( rFillArr.empty() )
|
|
return;
|
|
|
|
StartAllAction();
|
|
StartUndo();
|
|
|
|
SwRootFrame* pTmpRootFrame = GetLayout();
|
|
sal_uInt16 nMaxPage = pTmpRootFrame->GetPageNum();
|
|
bool bTmpAssert = false;
|
|
for( auto pFormat : rFillArr )
|
|
{
|
|
if (mxDoc->GetSpzFrameFormats()->IsAlive(static_cast<sw::SpzFrameFormat*>(pFormat)))
|
|
{
|
|
// FlyFormat is still valid, therefore process
|
|
|
|
SwFormatAnchor aNewAnchor( pFormat->GetAnchor() );
|
|
if (RndStdIds::FLY_AT_PAGE != aNewAnchor.GetAnchorId())
|
|
// Anchor has been changed, therefore: do not change!
|
|
continue;
|
|
sal_uInt16 nNewPage = aNewAnchor.GetPageNum() + 1;
|
|
if (nNewPage > nMaxPage)
|
|
{
|
|
if ( RES_DRAWFRMFMT == pFormat->Which() )
|
|
pFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS));
|
|
else
|
|
pFormat->DelFrames();
|
|
bTmpAssert = true;
|
|
}
|
|
aNewAnchor.SetPageNum(nNewPage);
|
|
mxDoc->SetAttr( aNewAnchor, *pFormat );
|
|
}
|
|
}
|
|
|
|
if( bTmpAssert )
|
|
pTmpRootFrame->SetAssertFlyPages();
|
|
|
|
EndUndo();
|
|
EndAllAction();
|
|
}
|
|
|
|
// 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." );
|
|
return false;
|
|
}
|
|
|
|
CurrShell aCurr( const_cast<SwFEShell*>(this) );
|
|
|
|
if( !rSet.Set( pFly->GetFormat()->GetAttrSet() ) )
|
|
return false;
|
|
|
|
// now examine all attributes. Remove forbidden attributes, then
|
|
// get all remaining attributes and enter them
|
|
|
|
if( const SwFormatAnchor* pAnchor = rSet.GetItemIfSet( RES_ANCHOR, false ) )
|
|
{
|
|
RndStdIds eType = pAnchor->GetAnchorId();
|
|
|
|
if ( RndStdIds::FLY_AT_PAGE != eType )
|
|
{
|
|
// OD 12.11.2003 #i22341# - content anchor of anchor item is needed.
|
|
// Thus, don't overwrite anchor item by default constructed anchor item.
|
|
if ( RndStdIds::FLY_AS_CHAR == eType )
|
|
{
|
|
rSet.ClearItem( RES_OPAQUE );
|
|
rSet.ClearItem( RES_SURROUND );
|
|
}
|
|
}
|
|
}
|
|
rSet.SetParent( pFly->GetFormat()->GetAttrSet().GetParent() );
|
|
// attributes must be removed
|
|
rSet.ClearItem( RES_FILL_ORDER );
|
|
rSet.ClearItem( RES_CNTNT );
|
|
//MA: remove first (Template by example etc.)
|
|
rSet.ClearItem( RES_CHAIN );
|
|
return true;
|
|
}
|
|
|
|
// Attributes of the current fly will change.
|
|
bool SwFEShell::SetFlyFrameAttr( SfxItemSet& rSet )
|
|
{
|
|
CurrShell aCurr( this );
|
|
bool bRet = false;
|
|
|
|
if( rSet.Count() )
|
|
{
|
|
SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame();
|
|
OSL_ENSURE(pFly, "SetFlyFrameAttr, no Fly selected.");
|
|
if (pFly)
|
|
{
|
|
StartAllAction();
|
|
const Point aPt( pFly->getFrameArea().Pos() );
|
|
|
|
if( SfxItemState::SET == rSet.GetItemState( RES_ANCHOR, false ))
|
|
sw_ChkAndSetNewAnchor( *pFly, rSet );
|
|
SwFlyFrameFormat* pFlyFormat = pFly->GetFormat();
|
|
|
|
if( GetDoc()->SetFlyFrameAttr( *pFlyFormat, rSet ))
|
|
{
|
|
bRet = true;
|
|
SwFlyFrame* pFrame = pFlyFormat->GetFrame( &aPt );
|
|
if( pFrame )
|
|
SelectFlyFrame( *pFrame );
|
|
else
|
|
GetLayout()->SetAssertFlyPages();
|
|
}
|
|
|
|
EndAllActionAndCall();
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
SfxItemSetFixed<RES_VERT_ORIENT, RES_ANCHOR> 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.
|
|
SfxItemSetFixed<RES_VERT_ORIENT, RES_ANCHOR> aSet(rPool);
|
|
aSet.Put(rAnchor);
|
|
return aSet;
|
|
}
|
|
|
|
bool SwFEShell::SetDrawingAttr( SfxItemSet& rSet )
|
|
{
|
|
bool bRet = false;
|
|
CurrShell aCurr( this );
|
|
if ( !rSet.Count() ||
|
|
!Imp()->HasDrawView() )
|
|
return bRet;
|
|
|
|
const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
|
|
if ( rMrkList.GetMarkCount() != 1 )
|
|
return bRet;
|
|
|
|
StartUndo();
|
|
SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
|
|
SwFrameFormat *pFormat = FindFrameFormat( pObj );
|
|
StartAllAction();
|
|
if( SfxItemState::SET == rSet.GetItemState( RES_ANCHOR, false ))
|
|
{
|
|
RndStdIds nNew = rSet.Get( RES_ANCHOR ).GetAnchorId();
|
|
if ( nNew != pFormat->GetAnchor().GetAnchorId() )
|
|
{
|
|
ChgAnchor( nNew );
|
|
// #i26791# - clear anchor attribute in item set,
|
|
// because method <ChgAnchor(..)> takes care of it.
|
|
rSet.ClearItem( RES_ANCHOR );
|
|
}
|
|
}
|
|
|
|
if( GetDoc()->SetFlyFrameAttr( *pFormat, rSet ))
|
|
{
|
|
bRet = true;
|
|
SelectObj( Point(), 0, pObj );
|
|
}
|
|
EndAllActionAndCall();
|
|
EndUndo();
|
|
return bRet;
|
|
}
|
|
|
|
// Reset attributes contained in the set.
|
|
void SwFEShell::ResetFlyFrameAttr( const SfxItemSet* pSet )
|
|
{
|
|
CurrShell aCurr( this );
|
|
|
|
SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame();
|
|
OSL_ENSURE( pFly, "SetFlyFrameAttr, no Fly selected." );
|
|
if( !pFly )
|
|
return;
|
|
|
|
StartAllAction();
|
|
|
|
SfxItemIter aIter( *pSet );
|
|
for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
|
|
{
|
|
if( !IsInvalidItem( pItem ) )
|
|
{
|
|
sal_uInt16 nWhich = pItem->Which();
|
|
if( RES_ANCHOR != nWhich && RES_CHAIN != nWhich && RES_CNTNT != nWhich )
|
|
pFly->GetFormat()->ResetFormatAttr( nWhich );
|
|
}
|
|
}
|
|
|
|
EndAllActionAndCall();
|
|
GetDoc()->getIDocumentState().SetModified();
|
|
}
|
|
|
|
// Returns frame-format if frame, otherwise 0
|
|
SwFrameFormat* SwFEShell::GetSelectedFrameFormat() const
|
|
{
|
|
SwFrameFormat* pRet = nullptr;
|
|
SwLayoutFrame *pFly = GetSelectedFlyFrame();
|
|
if( pFly && ( pRet = static_cast<SwFrameFormat*>(pFly->GetFormat()->DerivedFrom()) ) ==
|
|
GetDoc()->GetDfltFrameFormat() )
|
|
pRet = nullptr;
|
|
return pRet;
|
|
}
|
|
|
|
void SwFEShell::SetFrameFormat( SwFrameFormat *pNewFormat, bool bKeepOrient, Point const * pDocPos )
|
|
{
|
|
SwFlyFrame *pFly = nullptr;
|
|
if(pDocPos)
|
|
{
|
|
const SwFrameFormat* pFormat = GetFormatFromObj( *pDocPos );
|
|
|
|
if (const SwFlyFrameFormat* pFlyFormat = dynamic_cast<const SwFlyFrameFormat*>(pFormat))
|
|
pFly = pFlyFormat->GetFrame();
|
|
}
|
|
else
|
|
pFly = GetSelectedFlyFrame();
|
|
OSL_ENSURE( pFly, "SetFrameFormat: no frame" );
|
|
if( !pFly )
|
|
return;
|
|
|
|
StartAllAction();
|
|
CurrShell aCurr( this );
|
|
|
|
SwFlyFrameFormat* pFlyFormat = pFly->GetFormat();
|
|
const Point aPt( pFly->getFrameArea().Pos() );
|
|
|
|
std::optional<SfxItemSet> oSet;
|
|
const SfxPoolItem* pItem;
|
|
if( SfxItemState::SET == pNewFormat->GetItemState( RES_ANCHOR, false, &pItem ))
|
|
{
|
|
oSet.emplace( GetDoc()->GetAttrPool(), aFrameFormatSetRange );
|
|
oSet->Put( *pItem );
|
|
if( !sw_ChkAndSetNewAnchor( *pFly, *oSet ))
|
|
{
|
|
oSet.reset();
|
|
}
|
|
}
|
|
|
|
if( GetDoc()->SetFrameFormatToFly( *pFlyFormat, *pNewFormat, oSet ? &*oSet : nullptr, bKeepOrient ))
|
|
{
|
|
SwFlyFrame* pFrame = pFlyFormat->GetFrame( &aPt );
|
|
if( pFrame )
|
|
SelectFlyFrame( *pFrame );
|
|
else
|
|
GetLayout()->SetAssertFlyPages();
|
|
}
|
|
oSet.reset();
|
|
|
|
EndAllActionAndCall();
|
|
}
|
|
|
|
const SwFrameFormat* SwFEShell::GetFlyFrameFormat() const
|
|
{
|
|
const SwFlyFrame* pFly = GetSelectedOrCurrFlyFrame();
|
|
if (pFly)
|
|
return pFly->GetFormat();
|
|
return nullptr;
|
|
}
|
|
|
|
SwFrameFormat* SwFEShell::GetFlyFrameFormat()
|
|
{
|
|
SwFlyFrame* pFly = GetSelectedOrCurrFlyFrame();
|
|
if (pFly)
|
|
return pFly->GetFormat();
|
|
return nullptr;
|
|
}
|
|
|
|
SwRect SwFEShell::GetFlyRect() const
|
|
{
|
|
SwFlyFrame *pFly = GetCurrFlyFrame(false);
|
|
if (!pFly)
|
|
{
|
|
SwRect aRect;
|
|
return aRect;
|
|
}
|
|
else
|
|
return pFly->getFrameArea();
|
|
}
|
|
|
|
SwRect SwFEShell::GetObjRect() const
|
|
{
|
|
if( Imp()->HasDrawView() )
|
|
return SwRect(Imp()->GetDrawView()->GetAllMarkedRect());
|
|
else
|
|
{
|
|
SwRect aRect;
|
|
return aRect;
|
|
}
|
|
}
|
|
|
|
void SwFEShell::SetObjRect( const SwRect& rRect )
|
|
{
|
|
if ( Imp()->HasDrawView() )
|
|
{
|
|
Imp()->GetDrawView()->SetAllMarkedRect( rRect.SVRect() );
|
|
CallChgLnk(); // call AttrChangeNotify on the UI-side.
|
|
}
|
|
}
|
|
|
|
Size SwFEShell::RequestObjectResize( const SwRect &rRect, const uno::Reference < embed::XEmbeddedObject >& xObj )
|
|
{
|
|
Size aResult;
|
|
|
|
SwFlyFrame *pFly = FindFlyFrame( xObj );
|
|
if ( !pFly )
|
|
{
|
|
aResult = rRect.SSize();
|
|
return aResult;
|
|
}
|
|
|
|
aResult = pFly->getFramePrintArea().SSize();
|
|
|
|
bool bPosProt = pFly->GetFormat()->GetProtect().IsPosProtected();
|
|
bool bSizeProt = pFly->GetFormat()->GetProtect().IsSizeProtected();
|
|
|
|
StartAllAction();
|
|
|
|
// 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
|
|
|
|
const SwFrame* pAnchor;
|
|
const SwFormatFrameSize& rFrameSz = pFly->GetFormat()->GetFrameSize();
|
|
if (m_bCheckForOLEInCaption &&
|
|
0 != rFrameSz.GetWidthPercent() &&
|
|
nullptr != (pAnchor = pFly->GetAnchorFrame()) &&
|
|
pAnchor->IsTextFrame() &&
|
|
!pAnchor->GetNext() && !pAnchor->GetPrev() &&
|
|
pAnchor->GetUpper()->IsFlyFrame())
|
|
{
|
|
// search for a sequence field:
|
|
sw::MergedAttrIter iter(*static_cast<SwTextFrame const*>(pAnchor));
|
|
for (SwTextAttr const* pHint = iter.NextAttr(); pHint; pHint = iter.NextAttr())
|
|
{
|
|
const SfxPoolItem* pItem = &pHint->GetAttr();
|
|
if( RES_TXTATR_FIELD == pItem->Which()
|
|
&& SwFieldTypesEnum::Sequence == static_cast<const SwFormatField*>(pItem)->GetField()->GetTypeId() )
|
|
{
|
|
// sequence field found
|
|
SwFlyFrame* pChgFly = const_cast<SwFlyFrame*>(static_cast<const SwFlyFrame*>(pAnchor->GetUpper()));
|
|
// calculate the changed size:
|
|
// width must change, height can change
|
|
Size aNewSz( aSz.Width() + pChgFly->getFrameArea().Width() -
|
|
pFly->getFramePrintArea().Width(), aSz.Height() );
|
|
|
|
SwFrameFormat *pFormat = pChgFly->GetFormat();
|
|
SwFormatFrameSize aFrameSz( pFormat->GetFrameSize() );
|
|
aFrameSz.SetWidth( aNewSz.Width() );
|
|
if( SwFrameSize::Minimum != aFrameSz.GetHeightSizeType() )
|
|
{
|
|
aNewSz.AdjustHeight(pChgFly->getFrameArea().Height() -
|
|
pFly->getFramePrintArea().Height() );
|
|
if( std::abs( aNewSz.Height() - pChgFly->getFrameArea().Height()) > 1 )
|
|
aFrameSz.SetHeight( aNewSz.Height() );
|
|
}
|
|
// via Doc for the Undo!
|
|
pFormat->GetDoc()->SetAttr( aFrameSz, *pFormat );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
assert(pFly->Lower()->IsNoTextFrame());
|
|
SwNoTextNode *pNd = static_cast<SwNoTextFrame*>(pFly->Lower())->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;
|
|
|
|
for( auto pFormat : rSpzArr )
|
|
{
|
|
const SwNodeIndex* pIdx = pFormat->GetContent( false ).GetContentIdx();
|
|
SwStartNode* pSttNd;
|
|
if( pIdx &&
|
|
nullptr != ( pSttNd = pIdx->GetNode().GetStartNode() ) &&
|
|
*pSttNd < rCursorNd &&
|
|
rCursorNd < *pSttNd->EndOfSectionNode() )
|
|
{
|
|
// found: return immediately
|
|
return pFormat;
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void SwFEShell::SetFlyName( const OUString& rName )
|
|
{
|
|
SwLayoutFrame *pFly = GetSelectedFlyFrame();
|
|
if( pFly )
|
|
GetDoc()->SetFlyName( *static_cast<SwFlyFrameFormat*>(pFly->GetFormat()), rName );
|
|
else {
|
|
OSL_ENSURE( false, "no FlyFrame selected" );
|
|
}
|
|
}
|
|
|
|
OUString SwFEShell::GetFlyName() const
|
|
{
|
|
SwLayoutFrame *pFly = GetSelectedFlyFrame();
|
|
if( pFly )
|
|
return pFly->GetFormat()->GetName();
|
|
|
|
OSL_ENSURE( false, "no FlyFrame selected" );
|
|
return OUString();
|
|
}
|
|
|
|
uno::Reference < embed::XEmbeddedObject > SwFEShell::GetOleRef() const
|
|
{
|
|
uno::Reference < embed::XEmbeddedObject > xObj;
|
|
SwFlyFrame * pFly = GetSelectedFlyFrame();
|
|
if (pFly && pFly->Lower() && pFly->Lower()->IsNoTextFrame())
|
|
{
|
|
SwOLENode *pNd = static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetOLENode();
|
|
if (pNd)
|
|
xObj = pNd->GetOLEObj().GetOleRef();
|
|
}
|
|
return xObj;
|
|
}
|
|
|
|
OUString SwFEShell::GetUniqueGrfName() const
|
|
{
|
|
return GetDoc()->GetUniqueGrfName();
|
|
}
|
|
|
|
const SwFrameFormat* SwFEShell::IsURLGrfAtPos( const Point& rPt, OUString* pURL,
|
|
OUString *pTargetFrameName,
|
|
OUString *pDescription ) const
|
|
{
|
|
if( !Imp()->HasDrawView() )
|
|
return nullptr;
|
|
|
|
SdrPageView* pPV;
|
|
const SwFrameFormat* pRet = nullptr;
|
|
SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
|
|
|
|
const auto nOld = pDView->GetHitTolerancePixel();
|
|
pDView->SetHitTolerancePixel( 2 );
|
|
|
|
SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO);
|
|
SwVirtFlyDrawObj* pFlyObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
|
|
if (pFlyObj)
|
|
{
|
|
SwFlyFrame *pFly = pFlyObj->GetFlyFrame();
|
|
const SwFormatURL &rURL = pFly->GetFormat()->GetURL();
|
|
if( !rURL.GetURL().isEmpty() || rURL.GetMap() )
|
|
{
|
|
bool bSetTargetFrameName = pTargetFrameName != nullptr;
|
|
bool bSetDescription = pDescription != nullptr;
|
|
if ( rURL.GetMap() )
|
|
{
|
|
IMapObject *pObject = pFly->GetFormat()->GetIMapObject( rPt, pFly );
|
|
if ( pObject && !pObject->GetURL().isEmpty() )
|
|
{
|
|
if( pURL )
|
|
*pURL = pObject->GetURL();
|
|
if ( bSetTargetFrameName && !pObject->GetTarget().isEmpty() )
|
|
{
|
|
bSetTargetFrameName = false;
|
|
*pTargetFrameName = pObject->GetTarget();
|
|
}
|
|
if ( bSetDescription )
|
|
{
|
|
bSetDescription = false;
|
|
*pDescription = pObject->GetAltText();
|
|
}
|
|
pRet = pFly->GetFormat();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pURL )
|
|
{
|
|
*pURL = rURL.GetURL();
|
|
if( rURL.IsServerMap() )
|
|
{
|
|
// append the relative pixel position !!
|
|
Point aPt( rPt );
|
|
aPt -= pFly->getFrameArea().Pos();
|
|
// without MapMode-Offset, without Offset, o ... !!!!!
|
|
aPt = GetOut()->LogicToPixel(
|
|
aPt, MapMode( MapUnit::MapTwip ) );
|
|
*pURL = *pURL + "?" + OUString::number( aPt.getX() )
|
|
+ "," + OUString::number(aPt.getY() );
|
|
}
|
|
}
|
|
pRet = pFly->GetFormat();
|
|
}
|
|
if ( bSetTargetFrameName )
|
|
*pTargetFrameName = rURL.GetTargetFrameName();
|
|
if ( bSetDescription )
|
|
*pDescription = pFly->GetFormat()->GetName();
|
|
}
|
|
}
|
|
pDView->SetHitTolerancePixel( nOld );
|
|
return pRet;
|
|
}
|
|
|
|
const Graphic *SwFEShell::GetGrfAtPos( const Point &rPt,
|
|
OUString &rName, bool &rbLink ) const
|
|
{
|
|
if( !Imp()->HasDrawView() )
|
|
return nullptr;
|
|
|
|
SdrPageView* pPV;
|
|
SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
|
|
|
|
SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV);
|
|
SwVirtFlyDrawObj* pFlyObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
|
|
if (pFlyObj)
|
|
{
|
|
SwFlyFrame *pFly = pFlyObj->GetFlyFrame();
|
|
if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
|
|
{
|
|
SwGrfNode *const pNd = static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetGrfNode();
|
|
if ( pNd )
|
|
{
|
|
if ( pNd->IsGrfLink() )
|
|
{
|
|
// halfway ready graphic?
|
|
::sfx2::SvLinkSource* pLnkObj = pNd->GetLink()->GetObj();
|
|
if( pLnkObj && pLnkObj->IsPending() )
|
|
return nullptr;
|
|
rbLink = true;
|
|
}
|
|
|
|
pNd->GetFileFilterNms( &rName, nullptr );
|
|
if ( rName.isEmpty() )
|
|
rName = pFly->GetFormat()->GetName();
|
|
return &pNd->GetGrf(true);
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const SwFrameFormat* SwFEShell::GetFormatFromObj( const Point& rPt, SwRect** pRectToFill ) const
|
|
{
|
|
SwFrameFormat* pRet = nullptr;
|
|
|
|
if( Imp()->HasDrawView() )
|
|
{
|
|
SdrPageView* pPView;
|
|
|
|
SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
|
|
|
|
const auto nOld = pDView->GetHitTolerancePixel();
|
|
// tolerance for Drawing-SS
|
|
pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
|
|
|
|
SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
|
|
if (pObj)
|
|
{
|
|
// first check it:
|
|
if (SwVirtFlyDrawObj* pFlyObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
|
|
pRet = pFlyObj->GetFormat();
|
|
else if ( pObj->GetUserCall() ) //not for group objects
|
|
pRet = static_cast<SwDrawContact*>(pObj->GetUserCall())->GetFormat();
|
|
if(pRet && pRectToFill)
|
|
**pRectToFill = SwRect(pObj->GetCurrentBoundRect());
|
|
}
|
|
pDView->SetHitTolerancePixel( nOld );
|
|
}
|
|
return pRet;
|
|
}
|
|
|
|
// returns a format too, if the point is over the text of any fly
|
|
const SwFrameFormat* SwFEShell::GetFormatFromAnyObj( const Point& rPt ) const
|
|
{
|
|
const SwFrameFormat* pRet = GetFormatFromObj( rPt );
|
|
if( !pRet || RES_FLYFRMFMT == pRet->Which() )
|
|
{
|
|
SwPosition aPos( *GetCursor()->GetPoint() );
|
|
Point aPt( rPt );
|
|
GetLayout()->GetModelPositionForViewPoint( &aPos, aPt );
|
|
SwContentNode *pNd = aPos.GetNode().GetContentNode();
|
|
std::pair<Point, bool> const tmp(rPt, false);
|
|
SwFrame* pFrame = pNd->getLayoutFrame(GetLayout(), nullptr, &tmp)->FindFlyFrame();
|
|
pRet = pFrame ? static_cast<SwLayoutFrame*>(pFrame)->GetFormat() : nullptr;
|
|
}
|
|
return pRet;
|
|
}
|
|
|
|
ObjCntType SwFEShell::GetObjCntType( const SdrObject& rObj )
|
|
{
|
|
ObjCntType eType = OBJCNT_NONE;
|
|
|
|
// investigate 'master' drawing object, if method
|
|
// is called for a 'virtual' drawing object.
|
|
const SdrObject* pInvestigatedObj;
|
|
if (const SwDrawVirtObj* pDrawVirtObj = dynamic_cast<const SwDrawVirtObj*>( &rObj))
|
|
{
|
|
pInvestigatedObj = &(pDrawVirtObj->GetReferencedObj());
|
|
}
|
|
else
|
|
{
|
|
pInvestigatedObj = &rObj;
|
|
}
|
|
|
|
if( SdrInventor::FmForm == pInvestigatedObj->GetObjInventor() )
|
|
{
|
|
eType = OBJCNT_CONTROL;
|
|
uno::Reference< awt::XControlModel > xModel =
|
|
static_cast<const SdrUnoObj&>(*pInvestigatedObj).GetUnoControlModel();
|
|
if( xModel.is() )
|
|
{
|
|
uno::Any aVal;
|
|
OUString sName(u"ButtonType"_ustr);
|
|
uno::Reference< beans::XPropertySet > xSet(xModel, uno::UNO_QUERY);
|
|
|
|
uno::Reference< beans::XPropertySetInfo > xInfo = xSet->getPropertySetInfo();
|
|
if(xInfo->hasPropertyByName( sName ))
|
|
{
|
|
aVal = xSet->getPropertyValue( sName );
|
|
if( aVal.hasValue() && form::FormButtonType_URL == *o3tl::doAccess<form::FormButtonType>(aVal) )
|
|
eType = OBJCNT_URLBUTTON;
|
|
}
|
|
}
|
|
}
|
|
else if (const SwVirtFlyDrawObj *pFlyObj = dynamic_cast<const SwVirtFlyDrawObj*>(pInvestigatedObj))
|
|
{
|
|
const SwFlyFrame *pFly = pFlyObj->GetFlyFrame();
|
|
if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
|
|
{
|
|
if (static_cast<const SwNoTextFrame*>(pFly->Lower())->GetNode()->GetGrfNode())
|
|
eType = OBJCNT_GRF;
|
|
else
|
|
eType = OBJCNT_OLE;
|
|
}
|
|
else
|
|
eType = OBJCNT_FLY;
|
|
}
|
|
else if ( dynamic_cast<const SdrObjGroup*>( pInvestigatedObj) != nullptr )
|
|
{
|
|
SwDrawContact* pDrawContact( dynamic_cast<SwDrawContact*>(GetUserCall( pInvestigatedObj ) ) );
|
|
if ( !pDrawContact )
|
|
{
|
|
OSL_FAIL( "<SwFEShell::GetObjCntType(..)> - missing draw contact object" );
|
|
eType = OBJCNT_NONE;
|
|
}
|
|
else
|
|
{
|
|
SwFrameFormat* pFrameFormat( pDrawContact->GetFormat() );
|
|
if ( !pFrameFormat )
|
|
{
|
|
OSL_FAIL( "<SwFEShell::GetObjCntType(..)> - missing frame format" );
|
|
eType = OBJCNT_NONE;
|
|
}
|
|
else if ( RndStdIds::FLY_AS_CHAR != pFrameFormat->GetAnchor().GetAnchorId() )
|
|
{
|
|
eType = OBJCNT_GROUPOBJ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
eType = OBJCNT_SIMPLE;
|
|
return eType;
|
|
}
|
|
|
|
ObjCntType SwFEShell::GetObjCntType( const Point &rPt, SdrObject *&rpObj ) const
|
|
{
|
|
ObjCntType eType = OBJCNT_NONE;
|
|
|
|
if( Imp()->HasDrawView() )
|
|
{
|
|
SdrPageView* pPView;
|
|
|
|
SwDrawView *pDView = const_cast<SwDrawView*>(Imp()->GetDrawView());
|
|
|
|
const auto nOld = pDView->GetHitTolerancePixel();
|
|
// tolerance for Drawing-SS
|
|
pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );
|
|
|
|
SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE);
|
|
if (pObj)
|
|
{
|
|
rpObj = pObj;
|
|
eType = GetObjCntType( *rpObj );
|
|
}
|
|
|
|
pDView->SetHitTolerancePixel( nOld );
|
|
}
|
|
return eType;
|
|
}
|
|
|
|
ObjCntType SwFEShell::GetObjCntTypeOfSelection() const
|
|
{
|
|
ObjCntType eType = OBJCNT_NONE;
|
|
|
|
if( Imp()->HasDrawView() )
|
|
{
|
|
const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
|
|
for( size_t i = 0, nE = rMrkList.GetMarkCount(); i < nE; ++i )
|
|
{
|
|
SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
|
|
if( !pObj )
|
|
continue;
|
|
ObjCntType eTmp = GetObjCntType( *pObj );
|
|
if( !i )
|
|
{
|
|
eType = eTmp;
|
|
}
|
|
else if( eTmp != eType )
|
|
{
|
|
eType = OBJCNT_DONTCARE;
|
|
// once DontCare, always DontCare!
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return eType;
|
|
}
|
|
|
|
void SwFEShell::ReplaceSdrObj( const OUString& rGrfName, const Graphic* pGrf )
|
|
{
|
|
CurrShell aCurr( this );
|
|
|
|
const SdrMarkList *pMrkList;
|
|
if( !(Imp()->HasDrawView() && 1 ==
|
|
( pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList())->GetMarkCount()) )
|
|
return;
|
|
|
|
SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
|
|
assert(pObj);
|
|
SwFrameFormat *pFormat = FindFrameFormat( pObj );
|
|
|
|
// store attributes, then set the graphic
|
|
SfxItemSet aFrameSet( mxDoc->GetAttrPool(),
|
|
pFormat->GetAttrSet().GetRanges() );
|
|
aFrameSet.Set( pFormat->GetAttrSet() );
|
|
|
|
// set size and position?
|
|
if( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
|
|
{
|
|
// then let's do it:
|
|
const tools::Rectangle &rBound = pObj->GetSnapRect();
|
|
Point aRelPos( pObj->GetRelativePos() );
|
|
|
|
const tools::Long nWidth = rBound.Right() - rBound.Left();
|
|
const tools::Long nHeight= rBound.Bottom() - rBound.Top();
|
|
aFrameSet.Put( SwFormatFrameSize( SwFrameSize::Minimum,
|
|
std::max( nWidth, tools::Long(MINFLY) ),
|
|
std::max( nHeight, tools::Long(MINFLY) )));
|
|
|
|
if( SfxItemState::SET != aFrameSet.GetItemState( RES_HORI_ORIENT ))
|
|
aFrameSet.Put( SwFormatHoriOrient( aRelPos.getX(), text::HoriOrientation::NONE, text::RelOrientation::FRAME ));
|
|
|
|
if( SfxItemState::SET != aFrameSet.GetItemState( RES_VERT_ORIENT ))
|
|
aFrameSet.Put( SwFormatVertOrient( aRelPos.getY(), text::VertOrientation::NONE, text::RelOrientation::FRAME ));
|
|
|
|
}
|
|
|
|
pObj->GetOrdNum();
|
|
|
|
StartAllAction();
|
|
StartUndo();
|
|
|
|
// delete "Sdr-Object", insert the graphic instead
|
|
DelSelectedObj();
|
|
|
|
GetDoc()->getIDocumentContentOperations().InsertGraphic(
|
|
*GetCursor(), rGrfName, u""_ustr, pGrf, &aFrameSet, nullptr, nullptr);
|
|
|
|
EndUndo();
|
|
EndAllAction();
|
|
}
|
|
|
|
static sal_uInt16 SwFormatGetPageNum(const SwFlyFrameFormat * pFormat)
|
|
{
|
|
assert(pFormat != nullptr && "invalid argument");
|
|
|
|
SwFlyFrame * pFrame = pFormat->GetFrame();
|
|
|
|
sal_uInt16 aResult;
|
|
|
|
if (pFrame != nullptr)
|
|
aResult = pFrame->GetPhyPageNum();
|
|
else
|
|
aResult = pFormat->GetAnchor().GetPageNum();
|
|
|
|
return aResult;
|
|
}
|
|
|
|
void SwFEShell::GetConnectableFrameFormats(SwFrameFormat & rFormat,
|
|
std::u16string_view rReference,
|
|
bool bSuccessors,
|
|
std::vector< OUString > & aPrevPageVec,
|
|
std::vector< OUString > & aThisPageVec,
|
|
std::vector< OUString > & aNextPageVec,
|
|
std::vector< OUString > & aRestVec)
|
|
{
|
|
StartAction();
|
|
|
|
SwFormatChain rChain = rFormat.GetChain();
|
|
SwFrameFormat * pOldChainNext = rChain.GetNext();
|
|
SwFrameFormat * pOldChainPrev = rChain.GetPrev();
|
|
|
|
if (pOldChainNext)
|
|
mxDoc->Unchain(rFormat);
|
|
|
|
if (pOldChainPrev)
|
|
mxDoc->Unchain(*pOldChainPrev);
|
|
|
|
/* potential successors resp. predecessors */
|
|
std::vector<const SwFrameFormat *> aTmpSpzArray = mxDoc->GetFlyFrameFormats(FLYCNTTYPE_FRM, false);
|
|
|
|
for (auto it = aTmpSpzArray.begin(); it != aTmpSpzArray.end(); ++it)
|
|
{
|
|
/*
|
|
pFormat is a potential successor of rFormat if it is chainable after
|
|
rFormat.
|
|
|
|
pFormat is a potential predecessor of rFormat if rFormat is chainable
|
|
after pFormat.
|
|
*/
|
|
|
|
SwChainRet nChainState;
|
|
|
|
if (bSuccessors)
|
|
nChainState = mxDoc->Chainable(rFormat, **it);
|
|
else
|
|
nChainState = mxDoc->Chainable(**it, rFormat);
|
|
|
|
if (nChainState != SwChainRet::OK)
|
|
*it = nullptr;
|
|
}
|
|
std::erase(aTmpSpzArray, nullptr);
|
|
|
|
if (!aTmpSpzArray.empty())
|
|
{
|
|
aPrevPageVec.clear();
|
|
aThisPageVec.clear();
|
|
aNextPageVec.clear();
|
|
aRestVec.clear();
|
|
|
|
/* number of page rFormat resides on */
|
|
sal_uInt16 nPageNum = SwFormatGetPageNum(static_cast<SwFlyFrameFormat *>(&rFormat));
|
|
|
|
for (const auto& rpFormat : aTmpSpzArray)
|
|
{
|
|
const OUString aString = rpFormat->GetName();
|
|
|
|
/* rFormat is not a valid successor or predecessor of
|
|
itself */
|
|
if (aString != rReference && aString != rFormat.GetName())
|
|
{
|
|
sal_uInt16 nNum1 =
|
|
SwFormatGetPageNum(static_cast<const SwFlyFrameFormat *>(rpFormat));
|
|
|
|
if (nNum1 == nPageNum -1)
|
|
aPrevPageVec.push_back(aString);
|
|
else if (nNum1 == nPageNum)
|
|
aThisPageVec.push_back(aString);
|
|
else if (nNum1 == nPageNum + 1)
|
|
aNextPageVec.push_back(aString);
|
|
else
|
|
aRestVec.push_back(aString);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (pOldChainNext)
|
|
mxDoc->Chain(rFormat, *pOldChainNext);
|
|
|
|
if (pOldChainPrev)
|
|
mxDoc->Chain(*pOldChainPrev, rFormat);
|
|
|
|
EndAction();
|
|
}
|
|
|
|
// #i73249#
|
|
OUString SwFEShell::GetObjTitle() const
|
|
{
|
|
if ( Imp()->HasDrawView() )
|
|
{
|
|
const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
|
|
if ( pMrkList->GetMarkCount() == 1 )
|
|
{
|
|
const SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
|
|
const SwFrameFormat* pFormat = FindFrameFormat( pObj );
|
|
if ( pFormat->Which() == RES_FLYFRMFMT )
|
|
{
|
|
return static_cast<const SwFlyFrameFormat*>(pFormat)->GetObjTitle();
|
|
}
|
|
return pObj->GetTitle();
|
|
}
|
|
}
|
|
|
|
return OUString();
|
|
}
|
|
|
|
void SwFEShell::SetObjTitle( const OUString& rTitle )
|
|
{
|
|
if ( !Imp()->HasDrawView() )
|
|
return;
|
|
|
|
const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
|
|
if ( pMrkList->GetMarkCount() != 1 )
|
|
return;
|
|
|
|
SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
|
|
SwFrameFormat* pFormat = FindFrameFormat( pObj );
|
|
if ( pFormat->Which() == RES_FLYFRMFMT )
|
|
{
|
|
GetDoc()->SetFlyFrameTitle( dynamic_cast<SwFlyFrameFormat&>(*pFormat),
|
|
rTitle );
|
|
}
|
|
else
|
|
{
|
|
pObj->SetTitle( rTitle );
|
|
}
|
|
}
|
|
|
|
OUString SwFEShell::GetObjDescription() const
|
|
{
|
|
if ( Imp()->HasDrawView() )
|
|
{
|
|
const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
|
|
if ( pMrkList->GetMarkCount() == 1 )
|
|
{
|
|
const SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
|
|
const SwFrameFormat* pFormat = FindFrameFormat( pObj );
|
|
if ( pFormat->Which() == RES_FLYFRMFMT )
|
|
{
|
|
return dynamic_cast<const SwFlyFrameFormat&>(*pFormat).GetObjDescription();
|
|
}
|
|
return pObj->GetDescription();
|
|
}
|
|
}
|
|
|
|
return OUString();
|
|
}
|
|
|
|
void SwFEShell::SetObjDescription( const OUString& rDescription )
|
|
{
|
|
if ( !Imp()->HasDrawView() )
|
|
return;
|
|
|
|
const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList();
|
|
if ( pMrkList->GetMarkCount() != 1 )
|
|
return;
|
|
|
|
SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj();
|
|
SwFrameFormat* pFormat = FindFrameFormat( pObj );
|
|
if ( pFormat->Which() == RES_FLYFRMFMT )
|
|
{
|
|
GetDoc()->SetFlyFrameDescription(dynamic_cast<SwFlyFrameFormat&>(*pFormat),
|
|
rDescription);
|
|
}
|
|
else
|
|
{
|
|
pObj->SetDescription( rDescription );
|
|
}
|
|
}
|
|
|
|
bool SwFEShell::IsObjDecorative() const
|
|
{
|
|
if (!Imp()->HasDrawView())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SdrMarkList const& rMarkList(Imp()->GetDrawView()->GetMarkedObjectList());
|
|
if (rMarkList.GetMarkCount() != 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SdrObject const*const pObj(rMarkList.GetMark(0)->GetMarkedSdrObj());
|
|
SwFrameFormat const*const pFormat(FindFrameFormat(pObj));
|
|
if (pFormat->Which() == RES_FLYFRMFMT)
|
|
{
|
|
return dynamic_cast<const SwFlyFrameFormat&>(*pFormat).GetAttrSet().Get(RES_DECORATIVE).GetValue();
|
|
}
|
|
return pObj->IsDecorative();
|
|
}
|
|
|
|
void SwFEShell::SetObjDecorative(bool const isDecorative)
|
|
{
|
|
if (!Imp()->HasDrawView())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SdrMarkList const& rMarkList(Imp()->GetDrawView()->GetMarkedObjectList());
|
|
if (rMarkList.GetMarkCount() != 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SdrObject *const pObj(rMarkList.GetMark(0)->GetMarkedSdrObj());
|
|
SwFrameFormat *const pFormat(FindFrameFormat(pObj));
|
|
if (pFormat->Which() == RES_FLYFRMFMT)
|
|
{
|
|
GetDoc()->SetFlyFrameDecorative(dynamic_cast<SwFlyFrameFormat&>(*pFormat),
|
|
isDecorative);
|
|
}
|
|
else
|
|
{
|
|
pObj->SetDecorative(isDecorative);
|
|
}
|
|
}
|
|
|
|
|
|
void SwFEShell::AlignFormulaToBaseline( const uno::Reference < embed::XEmbeddedObject >& xObj )
|
|
{
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
SvGlobalName aCLSID( xObj->getClassID() );
|
|
const bool bStarMath = ( SotExchange::IsMath( aCLSID ) != 0 );
|
|
OSL_ENSURE( bStarMath, "AlignFormulaToBaseline should only be called for Math objects" );
|
|
|
|
if ( !bStarMath )
|
|
return;
|
|
#endif
|
|
|
|
SwFlyFrame * pFly = FindFlyFrame( xObj );
|
|
OSL_ENSURE( pFly , "No fly frame!" );
|
|
SwFrameFormat * pFrameFormat = pFly ? pFly->GetFormat() : nullptr;
|
|
|
|
// baseline to baseline alignment should only be applied to formulas anchored as char
|
|
if ( !pFly || !pFrameFormat || RndStdIds::FLY_AS_CHAR != pFrameFormat->GetAnchor().GetAnchorId() )
|
|
return;
|
|
|
|
// get baseline from Math object
|
|
uno::Any aBaseline;
|
|
if( svt::EmbeddedObjectRef::TryRunningState( xObj ) )
|
|
{
|
|
uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY );
|
|
if ( xSet.is() )
|
|
{
|
|
try
|
|
{
|
|
aBaseline = xSet->getPropertyValue(u"BaseLine"_ustr);
|
|
}
|
|
catch ( uno::Exception& )
|
|
{
|
|
OSL_FAIL( "Baseline could not be retrieved from Starmath!" );
|
|
}
|
|
}
|
|
}
|
|
|
|
sal_Int32 nBaseline = ::comphelper::getINT32(aBaseline);
|
|
nBaseline = o3tl::toTwips( nBaseline, o3tl::Length::mm100 );
|
|
|
|
OSL_ENSURE( nBaseline > 0, "Wrong value of Baseline while retrieving from Starmath!" );
|
|
//nBaseline must be moved by aPrt position
|
|
const SwFlyFrameFormat *pFlyFrameFormat = pFly->GetFormat();
|
|
OSL_ENSURE( pFlyFrameFormat, "fly frame format missing!" );
|
|
if ( pFlyFrameFormat )
|
|
nBaseline += pFlyFrameFormat->GetLastFlyFramePrtRectPos().Y();
|
|
|
|
const SwFormatVertOrient &rVert = pFrameFormat->GetVertOrient();
|
|
SwFormatVertOrient aVert( rVert );
|
|
aVert.SetPos( -nBaseline );
|
|
aVert.SetVertOrient( css::text::VertOrientation::NONE );
|
|
|
|
pFrameFormat->LockModify();
|
|
pFrameFormat->SetFormatAttr( aVert );
|
|
pFrameFormat->UnlockModify();
|
|
pFly->InvalidatePos();
|
|
|
|
}
|
|
|
|
void SwFEShell::AlignAllFormulasToBaseline()
|
|
{
|
|
StartAllAction();
|
|
|
|
SwStartNode *pStNd;
|
|
SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
|
|
while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
|
|
{
|
|
++aIdx;
|
|
SwOLENode *pOleNode = aIdx.GetNode().GetOLENode();
|
|
if ( pOleNode )
|
|
{
|
|
const uno::Reference < embed::XEmbeddedObject > & xObj( pOleNode->GetOLEObj().GetOleRef() );
|
|
if (xObj.is())
|
|
{
|
|
SvGlobalName aCLSID( xObj->getClassID() );
|
|
if ( SotExchange::IsMath( aCLSID ) )
|
|
AlignFormulaToBaseline( xObj );
|
|
}
|
|
}
|
|
|
|
aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
|
|
}
|
|
|
|
EndAllAction();
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|