/* -*- 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 <svx/svdobj.hxx>
#include <osl/diagnose.h>
#include <comphelper/lok.hxx>
#include <init.hxx>
#include <fesh.hxx>
#include <tabcol.hxx>
#include <pagefrm.hxx>
#include <rootfrm.hxx>
#include <cntfrm.hxx>
#include <doc.hxx>
#include <frmtool.hxx>
#include <swtable.hxx>
#include <viewimp.hxx>
#include <dview.hxx>
#include <flyfrm.hxx>
#include <node.hxx>
#include <pam.hxx>
#include <sectfrm.hxx>
#include <fmtpdsc.hxx>
#include <fmtsrnd.hxx>
#include <fmtcntnt.hxx>
#include <fmtfsize.hxx>
#include <tabfrm.hxx>
#include <flyfrms.hxx>
#include <txtfrm.hxx>
#include <mdiexp.hxx>
#include <pagedesc.hxx>
#include <fmtanchr.hxx>
#include <environmentofanchoredobject.hxx>
#include <ndtxt.hxx>
#include <dflyobj.hxx>
#include <dcontact.hxx>
#include <UndoInsert.hxx>
#include <formatflysplit.hxx>
using namespace com::sun::star;
namespace
{
/**
* This mutex is only used for the paste listeners, where the solar mutex can't
* be used.
*/
osl::Mutex& GetPasteMutex()
{
static osl::Mutex aMutex;
return aMutex;
}
}
void SwFEShell::EndAllActionAndCall()
{
for(SwViewShell& rCurrentShell : GetRingContainer())
{
if( dynamic_cast<const SwCursorShell*>( &rCurrentShell) != nullptr )
{
static_cast<SwFEShell*>(&rCurrentShell)->EndAction();
static_cast<SwFEShell*>(&rCurrentShell)->CallChgLnk();
}
else
rCurrentShell.EndAction();
}
}
// Determine the Content's nearest to the point
Point SwFEShell::GetContentPos( const Point& rPoint, bool bNext ) const
{
CurrShell aCurr( const_cast<SwFEShell*>(this) );
return GetLayout()->GetNextPrevContentPos( rPoint, bNext );
}
const SwRect& SwFEShell::GetAnyCurRect( CurRectType eType, const Point* pPt,
const uno::Reference < embed::XEmbeddedObject >& xObj ) const
{
const SwFrame *pFrame = Imp()->HasDrawView()
? ::GetFlyFromMarked( &Imp()->GetDrawView()->GetMarkedObjectList(),
const_cast<SwFEShell*>(this))
: nullptr;
if( !pFrame )
{
if( pPt )
{
SwPosition aPos( *GetCursor()->GetPoint() );
Point aPt( *pPt );
GetLayout()->GetModelPositionForViewPoint( &aPos, aPt );
SwContentNode *pNd = aPos.GetNode().GetContentNode();
std::pair<Point, bool> const tmp(*pPt, true);
pFrame = pNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
}
else
{
const bool bOldCallbackActionEnabled = GetLayout()->IsCallbackActionEnabled();
if( bOldCallbackActionEnabled )
GetLayout()->SetCallbackActionEnabled( false );
pFrame = GetCurrFrame();
if( bOldCallbackActionEnabled )
GetLayout()->SetCallbackActionEnabled( true );
}
}
if( !pFrame )
return GetLayout()->getFrameArea();
bool bFrame = true;
switch ( eType )
{
case CurRectType::PagePrt:
bFrame = false;
[[fallthrough]];
case CurRectType::Page :
pFrame = pFrame->FindPageFrame();
break;
case CurRectType::PageCalc:
{
DisableCallbackAction a(const_cast<SwRootFrame&>(*pFrame->getRootFrame()));
pFrame->Calc(Imp()->GetShell()->GetOut());
pFrame = pFrame->FindPageFrame();
pFrame->Calc(Imp()->GetShell()->GetOut());
}
break;
case CurRectType::FlyEmbeddedPrt:
bFrame = false;
[[fallthrough]];
case CurRectType::FlyEmbedded:
{
const SwFrame *pFlyFrame = xObj.is() ? FindFlyFrame(xObj) : nullptr;
pFrame = pFlyFrame ? pFlyFrame
: pFrame->IsFlyFrame()
? pFrame
: pFrame->FindFlyFrame();
break;
}
case CurRectType::SectionOutsideTable :
if( pFrame->IsInTab() )
pFrame = pFrame->FindTabFrame();
else {
OSL_FAIL( "Missing Table" );
}
[[fallthrough]];
case CurRectType::SectionPrt:
case CurRectType::Section:
if( pFrame->IsInSct() )
pFrame = pFrame->FindSctFrame();
else {
OSL_FAIL( "Missing section" );
}
if( CurRectType::SectionPrt == eType )
bFrame = false;
break;
case CurRectType::HeaderFooter:
pFrame = pFrame->FindFooterOrHeader();
if( nullptr == pFrame )
return GetLayout()->getFrameArea();
break;
case CurRectType::PagesArea:
return GetLayout()->GetPagesArea();
default:
break;
}
return bFrame ? pFrame->getFrameArea() : pFrame->getFramePrintArea();
}
sal_uInt16 SwFEShell::GetPageNumber( const Point &rPoint ) const
{
const SwFrame *pPage = GetLayout()->Lower();
while ( pPage && !pPage->getFrameArea().Contains( rPoint ) )
pPage = pPage->GetNext();
if ( pPage )
return static_cast<const SwPageFrame*>(pPage)->GetPhyPageNum();
else
return 0;
}
bool SwFEShell::GetPageNumber( tools::Long nYPos, bool bAtCursorPos, sal_uInt16& rPhyNum, sal_uInt16& rVirtNum, OUString &rDisplay) const
{
const SwFrame *pPage;
if ( bAtCursorPos ) // get page of Cursor
{
pPage = GetCurrFrame( false );
if ( pPage )
pPage = pPage->FindPageFrame();
}
else if ( nYPos > -1 ) // determine page via the position
{
pPage = GetLayout()->Lower();
while( pPage && (pPage->getFrameArea().Bottom() < nYPos ||
nYPos < pPage->getFrameArea().Top() ) )
pPage = pPage->GetNext();
}
else // first visible page
{
pPage = Imp()->GetFirstVisPage(GetOut());
if ( pPage && static_cast<const SwPageFrame*>(pPage)->IsEmptyPage() )
pPage = pPage->GetNext();
}
if( pPage )
{
rPhyNum = static_cast<const SwPageFrame*>(pPage)->GetPhyPageNum();
rVirtNum = static_cast<const SwPageFrame*>(pPage)->GetVirtPageNum();
const SvxNumberType& rNum = static_cast<const SwPageFrame*>(pPage)->GetPageDesc()->GetNumType();
rDisplay = rNum.GetNumStr( rVirtNum );
}
return nullptr != pPage;
}
bool SwFEShell::IsDirectlyInSection() const
{
SwFrame* pFrame = GetCurrFrame( false );
return pFrame && pFrame->GetUpper() && pFrame->GetUpper()->IsSctFrame();
}
FrameTypeFlags SwFEShell::GetFrameType( const Point *pPt, bool bStopAtFly ) const
{
FrameTypeFlags nReturn = FrameTypeFlags::NONE;
const SwFrame *pFrame;
if ( pPt )
{
SwPosition aPos( *GetCursor()->GetPoint() );
Point aPt( *pPt );
GetLayout()->GetModelPositionForViewPoint( &aPos, aPt );
SwContentNode *pNd = aPos.GetNode().GetContentNode();
std::pair<Point, bool> const tmp(*pPt, true);
pFrame = pNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
}
else
pFrame = GetCurrFrame( false );
while ( pFrame )
{
switch ( pFrame->GetType() )
{
case SwFrameType::Column:
if( pFrame->GetUpper()->IsSctFrame() )
{
// Check, if isn't not only a single column
// from a section with footnotes at the end.
if( pFrame->GetNext() || pFrame->GetPrev() )
// Sectioncolumns
nReturn |= ( nReturn & FrameTypeFlags::TABLE ) ?
FrameTypeFlags::COLSECTOUTTAB : FrameTypeFlags::COLSECT;
}
else // only pages and frame columns
nReturn |= FrameTypeFlags::COLUMN;
break;
case SwFrameType::Page:
nReturn |= FrameTypeFlags::PAGE;
if( static_cast<const SwPageFrame*>(pFrame)->IsFootnotePage() )
nReturn |= FrameTypeFlags::FTNPAGE;
break;
case SwFrameType::Header:
nReturn |= FrameTypeFlags::HEADER;
break;
case SwFrameType::Footer:
nReturn |= FrameTypeFlags::FOOTER;
break;
case SwFrameType::Body:
if( pFrame->GetUpper()->IsPageFrame() ) // not for ColumnFrames
nReturn |= FrameTypeFlags::BODY;
break;
case SwFrameType::Ftn:
nReturn |= FrameTypeFlags::FOOTNOTE;
break;
case SwFrameType::Fly:
if( static_cast<const SwFlyFrame*>(pFrame)->IsFlyLayFrame() )
nReturn |= FrameTypeFlags::FLY_FREE;
else if ( static_cast<const SwFlyFrame*>(pFrame)->IsFlyAtContentFrame() )
nReturn |= FrameTypeFlags::FLY_ATCNT;
else
{
OSL_ENSURE( static_cast<const SwFlyFrame*>(pFrame)->IsFlyInContentFrame(),
"New frametype?" );
nReturn |= FrameTypeFlags::FLY_INCNT;
}
nReturn |= FrameTypeFlags::FLY_ANY;
if( bStopAtFly )
return nReturn;
break;
case SwFrameType::Tab:
case SwFrameType::Row:
case SwFrameType::Cell:
nReturn |= FrameTypeFlags::TABLE;
break;
default:
/* do nothing */
break;
}
if ( pFrame->IsFlyFrame() )
pFrame = static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame();
else
pFrame = pFrame->GetUpper();
}
return nReturn;
}
void SwFEShell::ShellGetFocus()
{
::SetShell( this );
SwCursorShell::ShellGetFocus();
if ( HasDrawView() )
{
if (!comphelper::LibreOfficeKit::isActive())
Imp()->GetDrawView()->showMarkHandles();
if ( Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0 )
FrameNotify( this, FLY_DRAG_START );
}
}
void SwFEShell::ShellLoseFocus()
{
SwCursorShell::ShellLoseFocus();
if ( HasDrawView() && Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0 )
{
if (!comphelper::LibreOfficeKit::isActive())
Imp()->GetDrawView()->hideMarkHandles();
FrameNotify( this, FLY_DRAG_END );
}
}
sal_uInt16 SwFEShell::GetPhyPageNum() const
{
SwFrame *pFrame = GetCurrFrame();
if ( pFrame )
return pFrame->GetPhyPageNum();
return 0;
}
sal_uInt16 SwFEShell::GetVirtPageNum() const
{
SwFrame *pFrame = GetCurrFrame();
if ( pFrame )
return pFrame->GetVirtPageNum();
return 0;
}
static void lcl_SetAPageOffset( sal_uInt16 nOffset, SwPageFrame* pPage, SwFEShell* pThis )
{
pThis->StartAllAction();
OSL_ENSURE( pPage->FindFirstBodyContent(),
"SwFEShell _SetAPageOffset() without ContentFrame" );
SwFormatPageDesc aDesc( pPage->GetPageDesc() );
aDesc.SetNumOffset( nOffset );
SwFrame *pFrame = pThis->GetCurrFrame( false );
if ( pFrame->IsInTab() )
pThis->GetDoc()->SetAttr( aDesc, *pFrame->FindTabFrame()->GetFormat() );
else
{
pThis->GetDoc()->getIDocumentContentOperations().InsertPoolItem(
*pThis->GetCursor(), aDesc, SetAttrMode::DEFAULT, pThis->GetLayout());
}
pThis->EndAllAction();
}
void SwFEShell::SetNewPageOffset( sal_uInt16 nOffset )
{
GetLayout()->SetVirtPageNum( true );
const SwPageFrame *pPage = GetCurrFrame( false )->FindPageFrame();
lcl_SetAPageOffset( nOffset, const_cast<SwPageFrame*>(pPage), this );
}
void SwFEShell::SetPageOffset( sal_uInt16 nOffset )
{
const SwPageFrame *pPage = GetCurrFrame( false )->FindPageFrame();
const SwRootFrame* pDocLayout = GetLayout();
while ( pPage )
{
const SwFrame *pFlow = pPage->FindFirstBodyContent();
if ( pFlow )
{
if ( pFlow->IsInTab() )
pFlow = pFlow->FindTabFrame();
const SwFormatPageDesc& rPgDesc = pFlow->GetPageDescItem();
if ( rPgDesc.GetNumOffset() )
{
pDocLayout->SetVirtPageNum( true );
lcl_SetAPageOffset( nOffset, const_cast<SwPageFrame*>(pPage), this );
break;
}
}
pPage = static_cast<const SwPageFrame*>(pPage->GetPrev());
}
}
sal_uInt16 SwFEShell::GetPageOffset() const
{
const SwPageFrame *pPage = GetCurrFrame()->FindPageFrame();
while ( pPage )
{
const SwFrame *pFlow = pPage->FindFirstBodyContent();
if ( pFlow )
{
if ( pFlow->IsInTab() )
pFlow = pFlow->FindTabFrame();
::std::optional<sal_uInt16> oNumOffset = pFlow->GetPageDescItem().GetNumOffset();
if ( oNumOffset )
return *oNumOffset;
}
pPage = static_cast<const SwPageFrame*>(pPage->GetPrev());
}
return 0;
}
void SwFEShell::InsertLabel( const SwLabelType eType, const OUString &rText, const OUString& rSeparator,
const OUString& rNumberSeparator,
const bool bBefore, const sal_uInt16 nId,
const OUString& rCharacterStyle,
const bool bCpyBrd )
{
// get node index of cursor position, SwDoc can do everything else itself
SwContentFrame *pCnt = SwLabelType::Draw==eType ? nullptr : GetCurrFrame( false );
if( SwLabelType::Draw!=eType && !pCnt )
return;
StartAllAction();
SwRewriter aRewriter(SwUndoInsertLabel::CreateRewriter(rText));
StartUndo(SwUndoId::INSERTLABEL, &aRewriter);
SwNodeOffset nIdx(0);
bool bInnerCntIsFly = false;
SwFlyFrameFormat* pFlyFormat = nullptr;
switch( eType )
{
case SwLabelType::Object:
case SwLabelType::Fly:
bInnerCntIsFly = pCnt->IsInFly();
if (bInnerCntIsFly)
{
// pass down index to the startnode for flys
nIdx = pCnt->FindFlyFrame()->
GetFormat()->GetContent().GetContentIdx()->GetIndex();
}
break;
case SwLabelType::Table:
if( pCnt->IsInTab() )
{
// pass down index to the TableNode for tables
SwTabFrame* pTabFrame = pCnt->FindTabFrame();
const SwTable& rTable = *pTabFrame->GetTable();
nIdx = rTable.GetTabSortBoxes()[ 0 ]
->GetSttNd()->FindTableNode()->GetIndex();
SwFlyFrame* pFly = pTabFrame->FindFlyFrame();
if (pFly && pFly->IsFlySplitAllowed())
{
// This table is in a split fly, but we will insert a label, which means this is not
// a floating table anymore, disable the "can split" bit, it'll be hidden on the UI
// anyway.
SwFrameFormat* pFormat = pFly->GetFrameFormat();
SfxItemSetFixed<RES_FLY_SPLIT, RES_FLY_SPLIT> aSet(GetDoc()->GetAttrPool());
SwFormatFlySplit aSplit(false);
aSet.Put(aSplit);
// SwUndoFormatAttr is created for us.
GetDoc()->SetFlyFrameAttr(*pFormat, aSet);
}
}
break;
case SwLabelType::Draw:
if( Imp()->GetDrawView() )
{
SwDrawView *pDView = Imp()->GetDrawView();
const SdrMarkList& rMrkList = pDView->GetMarkedObjectList();
// copy marked drawing objects to
// local list to perform the corresponding action for each object
std::vector<SdrObject*> aDrawObjs;
{
for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
{
SdrObject* pDrawObj = rMrkList.GetMark(i)->GetMarkedSdrObj();
if( pDrawObj )
aDrawObjs.push_back( pDrawObj );
}
}
// loop on marked drawing objects
while ( !aDrawObjs.empty() )
{
SdrObject* pDrawObj = aDrawObjs.back();
assert(pDrawObj);
if ( dynamic_cast<const SwVirtFlyDrawObj*>( pDrawObj) == nullptr &&
dynamic_cast<const SwFlyDrawObj*>( pDrawObj) == nullptr )
{
SwFlyFrameFormat *pFormat =
GetDoc()->InsertDrawLabel( rText, rSeparator, rNumberSeparator, nId, rCharacterStyle, *pDrawObj );
if( !pFlyFormat )
pFlyFormat = pFormat;
}
aDrawObjs.pop_back();
}
}
break;
default:
OSL_ENSURE( false, "Cursor neither in table nor in fly." );
}
if( nIdx )
{
pFlyFormat = GetDoc()->InsertLabel(eType, rText, rSeparator,
rNumberSeparator, bBefore, nId,
nIdx, rCharacterStyle, bCpyBrd);
}
if (pFlyFormat)
{
const Point aPt(GetCursorDocPos());
if (SwFlyFrame* pFrame = pFlyFormat->GetFrame(&aPt))
SelectFlyFrame(*pFrame);
}
EndUndo();
EndAllActionAndCall();
}
bool SwFEShell::Sort(const SwSortOptions& rOpt)
{
if( !HasSelection() )
return false;
CurrShell aCurr( this );
bool bRet = false;
StartAllAction();
if(IsTableMode())
{
// Sort table
// check if Point/Mark of current Cursor are in one table
SwFrame *pFrame = GetCurrFrame( false );
OSL_ENSURE( pFrame->FindTabFrame(), "Cursor not in table." );
// search boxes via the layout
SwSelBoxes aBoxes;
GetTableSel(*this, aBoxes);
// The Cursor should be removed from the deletion area.
// Always put them behind/on the table; via the
// document position they will always be set to the old position
while( !pFrame->IsCellFrame() )
pFrame = pFrame->GetUpper();
{
/* ParkCursor->ParkCursorTab */
ParkCursorInTab();
}
// call sorting on document
bRet = mxDoc->SortTable(aBoxes, rOpt);
}
else
{
// Sort text nothing else
for(SwPaM& rPaM : GetCursor()->GetRingContainer())
{
SwPaM* pPam = &rPaM;
auto [pStart, pEnd] = pPam->StartEnd(); // SwPosition*
SwNodeIndex aPrevIdx( pStart->GetNode(), -1 );
SwNodeOffset nOffset = pEnd->GetNodeIndex() - pStart->GetNodeIndex();
const sal_Int32 nCntStt = pStart->GetContentIndex();
// Sorting
bRet = mxDoc->SortText(*pPam, rOpt);
// put selection again
pPam->DeleteMark();
pPam->GetPoint()->Assign( aPrevIdx.GetNode(), SwNodeOffset(+1) );
SwContentNode* pCNd = pPam->GetPointContentNode();
sal_Int32 nLen = pCNd->Len();
if( nLen > nCntStt )
nLen = nCntStt;
pPam->GetPoint()->SetContent(nLen );
pPam->SetMark();
pPam->GetPoint()->Adjust(nOffset);
pCNd = pPam->GetPointContentNode();
pPam->GetPoint()->SetContent( pCNd->Len() );
}
}
EndAllAction();
return bRet;
}
bool SwFEShell::IsColRightToLeft() const
{
SwFrame* pFrame = GetCurrFrame();
while (pFrame)
{
pFrame = pFrame->GetUpper();
if (pFrame && pFrame->IsColumnFrame())
{
return pFrame->IsRightToLeft();
}
}
return false;
}
sal_uInt16 SwFEShell::GetCurColNum_( const SwFrame *pFrame,
SwGetCurColNumPara* pPara )
{
sal_uInt16 nRet = 0;
while ( pFrame )
{
pFrame = pFrame->GetUpper();
if( pFrame && pFrame->IsColumnFrame() )
{
const SwFrame *pCurFrame = pFrame;
do {
++nRet;
pFrame = pFrame->GetPrev();
} while ( pFrame );
if( pPara )
{
// now search the format, determining the columness
pFrame = pCurFrame->GetUpper();
while( pFrame )
{
if( ( SwFrameType::Page | SwFrameType::Fly | SwFrameType::Section ) & pFrame->GetType() )
{
pPara->pFrameFormat = static_cast<const SwLayoutFrame*>(pFrame)->GetFormat();
pPara->pPrtRect = &pFrame->getFramePrintArea();
break;
}
pFrame = pFrame->GetUpper();
}
if( !pFrame )
{
pPara->pFrameFormat = nullptr;
pPara->pPrtRect = nullptr;
}
}
break;
}
}
return nRet;
}
sal_uInt16 SwFEShell::GetCurColNum( SwGetCurColNumPara* pPara ) const
{
OSL_ENSURE( GetCurrFrame(), "Cursor parked?" );
return GetCurColNum_( GetCurrFrame(), pPara );
}
sal_uInt16 SwFEShell::GetCurOutColNum() const
{
sal_uInt16 nRet = 0;
SwFrame* pFrame = GetCurrFrame();
OSL_ENSURE( pFrame, "Cursor parked?" );
if( pFrame )
{
pFrame = pFrame->IsInTab() ? static_cast<SwFrame*>(pFrame->FindTabFrame())
: static_cast<SwFrame*>(pFrame->FindSctFrame());
OSL_ENSURE( pFrame, "No Tab, no Sect" );
if( pFrame )
nRet = GetCurColNum_( pFrame, nullptr );
}
return nRet;
}
SwFEShell::SwFEShell( SwDoc& rDoc, vcl::Window *pWindow, const SwViewOption *pOptions )
: SwEditShell( rDoc, pWindow, pOptions )
, m_bCheckForOLEInCaption(false)
, m_aPasteListeners(GetPasteMutex())
, m_eTableInsertMode(SwTable::SEARCH_NONE)
, m_bTableCopied(false)
{
}
SwFEShell::SwFEShell( SwEditShell& rShell, vcl::Window *pWindow )
: SwEditShell( rShell, pWindow )
, m_bCheckForOLEInCaption(false)
, m_aPasteListeners(GetPasteMutex())
, m_eTableInsertMode(SwTable::SEARCH_NONE)
, m_bTableCopied(false)
{
}
SwFEShell::~SwFEShell()
{
}
// #i17567# - adjustments for allowing
// negative vertical positions for fly frames anchored to paragraph/to character.
// #i22305# - adjustments for option 'Follow text flow'
// for to frame anchored objects.
// #i22341# - adjustments for vertical alignment at top of line
// for to character anchored objects.
void SwFEShell::CalcBoundRect( SwRect& _orRect,
const RndStdIds _nAnchorId,
const sal_Int16 _eHoriRelOrient,
const sal_Int16 _eVertRelOrient,
const SwFormatAnchor* _pToCharContentPos,
const bool _bFollowTextFlow,
bool _bMirror,
Point* _opRef,
Size* _opPercent,
const SwFormatFrameSize* pFormatFrameSize) const
{
const SwFrame* pFrame;
const SwFlyFrame* pFly;
if( _opRef )
{
pFrame = GetCurrFrame();
pFly = pFrame->FindFlyFrame();
if( nullptr != pFly )
pFrame = pFly->GetAnchorFrame();
}
else
{
pFly = GetSelectedOrCurrFlyFrame();
pFrame = pFly ? pFly->GetAnchorFrame() : GetCurrFrame();
}
bool bWrapThrough = false;
if ( pFly )
{
SwFlyFrameFormat* pFormat = const_cast<SwFlyFrameFormat*>(pFly->GetFormat());
const SwFormatSurround& rSurround = pFormat->GetSurround();
bWrapThrough = rSurround.GetSurround() == css::text::WrapTextMode_THROUGH;
}
const SwPageFrame* pPage = pFrame->FindPageFrame();
_bMirror = _bMirror && !pPage->OnRightPage();
Point aPos;
bool bVertic = false;
bool bRTL = false;
bool bVerticalL2R = false;
if ((RndStdIds::FLY_AT_PAGE == _nAnchorId) || (RndStdIds::FLY_AT_FLY == _nAnchorId)) // LAYER_IMPL
{
const SwFrame* pTmp = pFrame;
// #i22305#
if ((RndStdIds::FLY_AT_PAGE == _nAnchorId) ||
((RndStdIds::FLY_AT_FLY == _nAnchorId) && !_bFollowTextFlow))
{
pFrame = pPage;
}
else
{
pFrame = pFrame->FindFlyFrame();
}
if ( !pFrame )
pFrame = pTmp;
_orRect = pFrame->getFrameArea();
SwRectFnSet aRectFnSet(pFrame);
bRTL = pFrame->IsRightToLeft();
if ( bRTL )
aPos = pFrame->getFrameArea().TopRight();
else
aPos = aRectFnSet.GetPos(pFrame->getFrameArea());
if( aRectFnSet.IsVert() || aRectFnSet.IsVertL2R() )
{
bVertic = aRectFnSet.IsVert();
bVerticalL2R = aRectFnSet.IsVertL2R();
_bMirror = false; // no mirroring in vertical environment
switch ( _eHoriRelOrient )
{
case text::RelOrientation::PAGE_RIGHT:
case text::RelOrientation::FRAME_RIGHT: aPos.AdjustY(pFrame->getFramePrintArea().Height() );
[[fallthrough]];
case text::RelOrientation::PRINT_AREA:
case text::RelOrientation::PAGE_PRINT_AREA: aPos.AdjustY(pFrame->getFramePrintArea().Top() ); break;
default: break;
}
}
else if ( _bMirror )
{
switch ( _eHoriRelOrient )
{
case text::RelOrientation::PRINT_AREA:
case text::RelOrientation::PAGE_PRINT_AREA: aPos.AdjustX(pFrame->getFramePrintArea().Width() );
[[fallthrough]];
case text::RelOrientation::PAGE_RIGHT:
case text::RelOrientation::FRAME_RIGHT: aPos.AdjustX(pFrame->getFramePrintArea().Left() ); break;
default: aPos.AdjustX(pFrame->getFrameArea().Width() );
}
}
else if ( bRTL )
{
switch ( _eHoriRelOrient )
{
case text::RelOrientation::PRINT_AREA:
case text::RelOrientation::PAGE_PRINT_AREA: aPos.AdjustX(pFrame->getFramePrintArea().Width() );
[[fallthrough]];
case text::RelOrientation::PAGE_LEFT:
case text::RelOrientation::FRAME_LEFT: aPos.AdjustX(pFrame->getFramePrintArea().Left() -
pFrame->getFrameArea().Width() ); break;
default: break;
}
}
else
{
switch ( _eHoriRelOrient )
{
case text::RelOrientation::PAGE_RIGHT:
case text::RelOrientation::FRAME_RIGHT: aPos.AdjustX(pFrame->getFramePrintArea().Width() );
[[fallthrough]];
case text::RelOrientation::PRINT_AREA:
case text::RelOrientation::PAGE_PRINT_AREA: aPos.AdjustX(pFrame->getFramePrintArea().Left() ); break;
default:break;
}
}
if ( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
{
switch ( _eVertRelOrient )
{
case text::RelOrientation::PRINT_AREA:
case text::RelOrientation::PAGE_PRINT_AREA:
{
aPos.AdjustX( -(pFrame->GetRightMargin()) );
}
break;
}
}
else if ( aRectFnSet.IsVertL2R() )
{
switch ( _eVertRelOrient )
{
case text::RelOrientation::PRINT_AREA:
case text::RelOrientation::PAGE_PRINT_AREA:
{
aPos.AdjustX(pFrame->GetLeftMargin() );
}
break;
}
}
else
{
switch ( _eVertRelOrient )
{
case text::RelOrientation::PRINT_AREA:
case text::RelOrientation::PAGE_PRINT_AREA:
{
if ( pFrame->IsPageFrame() )
{
aPos.setY(
static_cast<const SwPageFrame*>(pFrame)->PrtWithoutHeaderAndFooter().Top() );
}
else
{
aPos.AdjustY(pFrame->getFramePrintArea().Top() );
}
}
break;
}
}
if ( _opPercent )
*_opPercent = pFrame->getFramePrintArea().SSize();
}
else
{
const SwFrame* pUpper = ( pFrame->IsPageFrame() || pFrame->IsFlyFrame() ) ?
pFrame : pFrame->GetUpper();
SwRectFnSet aRectFnSet(pUpper);
if ( _opPercent )
{
// If the size is relative from page, then full size should be counted from the page frame.
if (pFormatFrameSize && pFormatFrameSize->GetWidthPercentRelation() == text::RelOrientation::PAGE_FRAME)
_opPercent->setWidth(pPage->getFrameArea().Width());
else
_opPercent->setWidth(pUpper->getFramePrintArea().Width());
if (pFormatFrameSize && pFormatFrameSize->GetHeightPercentRelation() == text::RelOrientation::PAGE_FRAME)
// If the size is relative from page, then full size should be counted from the page frame.
_opPercent->setHeight(pPage->getFrameArea().Height());
else
_opPercent->setHeight(pUpper->getFramePrintArea().Height());
}
bRTL = pFrame->IsRightToLeft();
if ( bRTL )
aPos = pFrame->getFrameArea().TopRight();
else
aPos = aRectFnSet.GetPos(pFrame->getFrameArea());
// #i17567# - allow negative positions
// for fly frames anchor to paragraph/to character.
if ((_nAnchorId == RndStdIds::FLY_AT_PARA) || (_nAnchorId == RndStdIds::FLY_AT_CHAR))
{
// The rectangle, the fly frame can be positioned in, is determined
// horizontally by the frame area of the horizontal environment
// and vertically by the printing area of the vertical environment,
// if the object follows the text flow, or by the frame area of the
// vertical environment, if the object doesn't follow the text flow.
// new class <SwEnvironmentOfAnchoredObject>
objectpositioning::SwEnvironmentOfAnchoredObject aEnvOfObj(
_bFollowTextFlow );
const SwLayoutFrame& rHoriEnvironLayFrame =
aEnvOfObj.GetHoriEnvironmentLayoutFrame( *pFrame );
const SwLayoutFrame& rVertEnvironLayFrame =
aEnvOfObj.GetVertEnvironmentLayoutFrame( *pFrame );
const SwRect& aHoriEnvironRect( rHoriEnvironLayFrame.getFrameArea() );
SwRect aVertEnvironRect;
if ( _bFollowTextFlow )
{
aVertEnvironRect = rVertEnvironLayFrame.getFramePrintArea();
aVertEnvironRect.Pos() += rVertEnvironLayFrame.getFrameArea().Pos();
// #i18732# - adjust vertical 'virtual' anchor position
// (<aPos.Y()> respectively <aPos.X()>), if object is vertical aligned
// to page areas.
if ( _eVertRelOrient == text::RelOrientation::PAGE_FRAME || _eVertRelOrient == text::RelOrientation::PAGE_PRINT_AREA )
{
if ( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
{
aPos.setX( aVertEnvironRect.Right() );
}
else if ( aRectFnSet.IsVertL2R() )
{
aPos.setX( aVertEnvironRect.Left() );
}
else
{
aPos.setY( aVertEnvironRect.Top() );
}
}
}
else
{
OSL_ENSURE( rVertEnvironLayFrame.IsPageFrame(),
"<SwFEShell::CalcBoundRect(..)> - not following text flow, but vertical environment *not* page!" );
aVertEnvironRect = rVertEnvironLayFrame.getFrameArea();
// #i18732# - adjustment vertical 'virtual' anchor position
// (<aPos.Y()> respectively <aPos.X()>), if object is vertical aligned
// to page areas.
if (_eVertRelOrient == text::RelOrientation::PAGE_FRAME
|| _eVertRelOrient == text::RelOrientation::PAGE_PRINT_AREA
|| _eVertRelOrient == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
{
if ( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
{
aPos.setX( aVertEnvironRect.Right() );
if ( _eVertRelOrient == text::RelOrientation::PAGE_PRINT_AREA )
{
aPos.setX(aPos.getX() - rVertEnvironLayFrame.GetRightMargin());
}
}
else if ( aRectFnSet.IsVertL2R() )
{
aPos.setX( aVertEnvironRect.Left() );
if ( _eVertRelOrient == text::RelOrientation::PAGE_PRINT_AREA )
{
aPos.setX(aPos.getX() + rVertEnvironLayFrame.GetLeftMargin());
}
}
else
{
aPos.setY( aVertEnvironRect.Top() );
if ( _eVertRelOrient == text::RelOrientation::PAGE_PRINT_AREA )
{
aPos.setY(aPos.getY() + rVertEnvironLayFrame.GetTopMargin());
// add height of page header
const SwFrame* pTmpFrame = rVertEnvironLayFrame.Lower();
if ( pTmpFrame->IsHeaderFrame() )
{
aPos.setY(aPos.getY() + pTmpFrame->getFrameArea().Height());
}
}
else if (_eVertRelOrient == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
{
if (rVertEnvironLayFrame.IsPageFrame())
{
auto& rPageFrame = static_cast<const SwPageFrame&>(rVertEnvironLayFrame);
aPos.setY(rPageFrame.PrtWithoutHeaderAndFooter().Bottom());
}
else
{
aPos.AdjustY(rVertEnvironLayFrame.getFramePrintArea().Bottom());
}
}
}
}
}
// #i22341# - adjust vertical 'virtual' anchor position
// (<aPos.Y()> respectively <aPos.X()>), if object is anchored to
// character and vertical aligned at character or top of line
// <pFrame>, which is the anchor frame or the proposed anchor frame,
// doesn't have to be a text frame (e.g. edit a to-page anchored
// fly frame). Thus, assure this.
const SwTextFrame* pTextFrame = pFrame->DynCastTextFrame();
if ( pTextFrame &&
(_nAnchorId == RndStdIds::FLY_AT_CHAR) &&
( _eVertRelOrient == text::RelOrientation::CHAR ||
_eVertRelOrient == text::RelOrientation::TEXT_LINE ) )
{
SwTwips nTop = 0;
if ( _eVertRelOrient == text::RelOrientation::CHAR )
{
SwRect aChRect;
if ( _pToCharContentPos )
{
pTextFrame->GetAutoPos( aChRect, *_pToCharContentPos->GetContentAnchor() );
}
else
{
// No content position provided. Thus, use a default one.
SwPosition aDefaultContentPos(*(pTextFrame->GetTextNodeFirst()));
pTextFrame->GetAutoPos( aChRect, aDefaultContentPos );
}
nTop = aRectFnSet.GetBottom(aChRect);
}
else
{
if ( _pToCharContentPos )
{
pTextFrame->GetTopOfLine( nTop, *_pToCharContentPos->GetContentAnchor() );
}
else
{
// No content position provided. Thus, use a default one.
SwPosition aDefaultContentPos(*(pTextFrame->GetTextNodeFirst()));
pTextFrame->GetTopOfLine( nTop, aDefaultContentPos );
}
}
if ( aRectFnSet.IsVert() || aRectFnSet.IsVertL2R() )
{
aPos.setX(nTop);
}
else
{
aPos.setY(nTop);
}
}
// #i26945# - adjust horizontal 'virtual' anchor
// position (<aPos.X()> respectively <aPos.Y()>), if object is
// anchored to character and horizontal aligned at character.
if ( pTextFrame &&
(_nAnchorId == RndStdIds::FLY_AT_CHAR) &&
_eHoriRelOrient == text::RelOrientation::CHAR )
{
SwTwips nLeft = 0;
SwRect aChRect;
if ( _pToCharContentPos )
{
pTextFrame->GetAutoPos( aChRect, *_pToCharContentPos->GetContentAnchor() );
}
else
{
// No content position provided. Thus, use a default one.
SwPosition aDefaultContentPos(*(pTextFrame->GetTextNodeFirst()));
pTextFrame->GetAutoPos( aChRect, aDefaultContentPos );
}
nLeft = aRectFnSet.GetLeft(aChRect);
if ( aRectFnSet.IsVert() || aRectFnSet.IsVertL2R() )
{
aPos.setY(nLeft);
}
else
{
aPos.setX(nLeft);
}
}
if ( aRectFnSet.IsVert() || aRectFnSet.IsVertL2R() )
{
_orRect = SwRect( aVertEnvironRect.Left(),
aHoriEnvironRect.Top(),
aVertEnvironRect.Width(),
aHoriEnvironRect.Height() );
}
else
{
_orRect = SwRect( aHoriEnvironRect.Left(),
aVertEnvironRect.Top(),
aHoriEnvironRect.Width(),
aVertEnvironRect.Height() );
}
}
else
{
if( _opRef && pFly && pFly->IsFlyInContentFrame() )
*_opRef = static_cast<const SwFlyInContentFrame*>( pFly )->GetRefPoint();
_orRect = pUpper->getFrameArea();
if( !pUpper->IsBodyFrame() )
{
_orRect += pUpper->getFramePrintArea().Pos();
_orRect.SSize( pUpper->getFramePrintArea().SSize() );
if ( pUpper->IsCellFrame() )//MA_FLY_HEIGHT
{
const SwFrame* pTab = pUpper->FindTabFrame();
tools::Long nBottom = aRectFnSet.GetPrtBottom(*pTab->GetUpper());
aRectFnSet.SetBottom( _orRect, nBottom );
}
}
// only use 90% of height for character bound
{
if( aRectFnSet.IsVert() || aRectFnSet.IsVertL2R() )
_orRect.Width( (_orRect.Width()*9)/10 );
else
_orRect.Height( (_orRect.Height()*9)/10 );
}
}
const SwTwips nBaseOfstForFly = ( pFrame->IsTextFrame() && pFly ) ?
static_cast<const SwTextFrame*>(pFrame)->GetBaseOffsetForFly( !bWrapThrough ) :
0;
if( aRectFnSet.IsVert() || aRectFnSet.IsVertL2R() )
{
bVertic = aRectFnSet.IsVert();
bVerticalL2R = aRectFnSet.IsVertL2R();
_bMirror = false;
switch ( _eHoriRelOrient )
{
case text::RelOrientation::FRAME_RIGHT:
{
aPos.setY(aPos.getY() + pFrame->getFramePrintArea().Height());
aPos += aRectFnSet.GetPos(pFrame->getFramePrintArea());
break;
}
case text::RelOrientation::PRINT_AREA:
{
aPos += aRectFnSet.GetPos(pFrame->getFramePrintArea());
aPos.setY(aPos.getY() + nBaseOfstForFly);
break;
}
case text::RelOrientation::PAGE_RIGHT:
{
aPos.setY(pPage->getFrameArea().Top() + pPage->getFramePrintArea().Bottom());
break;
}
case text::RelOrientation::PAGE_PRINT_AREA:
{
aPos.setY(pPage->getFrameArea().Top() + pPage->getFramePrintArea().Top());
break;
}
case text::RelOrientation::PAGE_LEFT:
case text::RelOrientation::PAGE_FRAME:
{
aPos.setY(pPage->getFrameArea().Top());
break;
}
case text::RelOrientation::FRAME:
{
aPos.setY(aPos.getY() + nBaseOfstForFly);
break;
}
default: break;
}
}
else if( _bMirror )
{
switch ( _eHoriRelOrient )
{
case text::RelOrientation::FRAME_RIGHT: aPos.setX(aPos.getX() + pFrame->getFramePrintArea().Left()); break;
case text::RelOrientation::FRAME:
case text::RelOrientation::FRAME_LEFT: aPos.setX(aPos.getX() + pFrame->getFrameArea().Width()); break;
case text::RelOrientation::PRINT_AREA: aPos.setX(aPos.getX() + pFrame->getFramePrintArea().Right()); break;
case text::RelOrientation::PAGE_LEFT:
case text::RelOrientation::PAGE_FRAME: aPos.setX(pPage->getFrameArea().Right()); break;
case text::RelOrientation::PAGE_PRINT_AREA: aPos.setX(pPage->getFrameArea().Left()
+ pPage->getFramePrintArea().Left()); break;
default: break;
}
}
else if ( bRTL )
{
switch ( _eHoriRelOrient )
{
case text::RelOrientation::FRAME_LEFT:
aPos.setX(pFrame->getFrameArea().Left() +
pFrame->getFramePrintArea().Left());
break;
case text::RelOrientation::PRINT_AREA:
aPos.setX(pFrame->getFrameArea().Left() + pFrame->getFramePrintArea().Left() +
pFrame->getFramePrintArea().Width());
aPos.setX(aPos.getX() + nBaseOfstForFly);
break;
case text::RelOrientation::PAGE_LEFT:
aPos.setX(pPage->getFrameArea().Left() + pPage->getFramePrintArea().Left());
break;
case text::RelOrientation::PAGE_PRINT_AREA:
aPos.setX(pPage->getFrameArea().Left() + pPage->getFramePrintArea().Left() +
pPage->getFramePrintArea().Width());
break;
case text::RelOrientation::PAGE_RIGHT:
case text::RelOrientation::PAGE_FRAME:
aPos.setX(pPage->getFrameArea().Right());
break;
case text::RelOrientation::FRAME:
aPos.setX(aPos.getX() + nBaseOfstForFly);
break;
default: break;
}
}
else
{
switch ( _eHoriRelOrient )
{
case text::RelOrientation::FRAME_RIGHT:
aPos.AdjustX(pFrame->getFramePrintArea().Width() );
aPos += pFrame->getFramePrintArea().Pos();
break;
case text::RelOrientation::PRINT_AREA:
aPos += pFrame->getFramePrintArea().Pos();
aPos.setX(aPos.getX() + nBaseOfstForFly);
break;
case text::RelOrientation::PAGE_RIGHT:
aPos.setX(pPage->getFrameArea().Left() + pPage->getFramePrintArea().Right());
break;
case text::RelOrientation::PAGE_PRINT_AREA:
aPos.setX(pPage->getFrameArea().Left() + pPage->getFramePrintArea().Left());
break;
case text::RelOrientation::PAGE_LEFT:
case text::RelOrientation::PAGE_FRAME:
aPos.setX(pPage->getFrameArea().Left());
break;
case text::RelOrientation::FRAME:
aPos.setX(aPos.getX() + nBaseOfstForFly);
break;
default: break;
}
}
}
if( _opRef )
return;
if( bVertic && !bVerticalL2R )
_orRect.Pos( aPos.getX() - _orRect.Width() - _orRect.Left(), _orRect.Top() - aPos.getY() );
else if( bVerticalL2R )
_orRect.Pos( _orRect.Left() - aPos.getX(), _orRect.Top() - aPos.getY() );
else if ( bRTL )
_orRect.Pos( - ( _orRect.Right() - aPos.getX() ), _orRect.Top() - aPos.getY() );
else
_orRect.Pos( _orRect.Left() - aPos.getX(), _orRect.Top() - aPos.getY() );
if( _bMirror )
_orRect.Pos( -_orRect.Right(), _orRect.Top() );
}
Size SwFEShell::GetGraphicDefaultSize() const
{
Size aRet;
SwFlyFrame *pFly = GetSelectedFlyFrame();
if ( pFly )
{
// #i32951# - due to issue #i28701# no format of a
// newly inserted Writer fly frame or its anchor frame is performed
// any more. Thus, it could be possible (e.g. on insert of a horizontal
// line) that the anchor frame isn't formatted and its printing area
// size is (0,0). If this is the case the printing area of the upper
// of the anchor frame is taken.
const SwFrame* pAnchorFrame = pFly->GetAnchorFrame();
aRet = pAnchorFrame->getFramePrintArea().SSize();
if ( aRet.IsEmpty() && pAnchorFrame->GetUpper() )
{
aRet = pAnchorFrame->GetUpper()->getFramePrintArea().SSize();
}
SwRect aBound;
CalcBoundRect( aBound, pFly->GetFormat()->GetAnchor().GetAnchorId());
if ( pFly->GetAnchorFrame()->IsVertical() )
aRet.setWidth( aBound.Width() );
else
aRet.setHeight( aBound.Height() );
}
return aRet;
}
bool SwFEShell::IsFrameVertical(const bool bEnvironment, bool& bRTL, bool& bVertL2R) const
{
bool bVert = false;
bRTL = false;
bVertL2R = false;
if ( Imp()->HasDrawView() )
{
const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
if( rMrkList.GetMarkCount() != 1 )
return bVert;
SdrObject* pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
if ( !pObj )
{
OSL_FAIL( "<SwFEShell::IsFrameVertical(..)> - missing SdrObject instance in marked object list -> This is a serious situation" );
return bVert;
}
// #i26791#
SwContact* pContact = GetUserCall( pObj );
if ( !pContact )
{
OSL_FAIL( "<SwFEShell::IsFrameVertical(..)> - missing SwContact instance at marked object -> This is a serious situation" );
return bVert;
}
const SwFrame* pRef = pContact->GetAnchoredObj( pObj )->GetAnchorFrame();
if ( !pRef )
{
OSL_FAIL( "<SwFEShell::IsFrameVertical(..)> - missing anchor frame at marked object -> This is a serious situation" );
return bVert;
}
if ( !bEnvironment )
if ( auto pVirtFly = dynamic_cast<const SwVirtFlyDrawObj*>( pObj) )
pRef = pVirtFly->GetFlyFrame();
bVert = pRef->IsVertical();
bRTL = pRef->IsRightToLeft();
bVertL2R = pRef->IsVertLR();
}
return bVert;
}
void SwFEShell::MoveObjectIfActive( svt::EmbeddedObjectRef&, const Point& )
{
// does not do anything, only avoids crash if the method is used for wrong shell
}
void SwFEShell::ToggleHeaderFooterEdit()
{
// Clear objects selection
if ( Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0 )
{
Imp()->GetDrawView()->UnmarkAll();
ClearMark();
}
SwCursorShell::ToggleHeaderFooterEdit();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1051 Consider checking for misprints. It's possible that the 'pFormat' should be checked here.