/* -*- 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(GetOut());
            pFrame = pFrame->FindPageFrame();
            pFrame->Calc(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::Footnote:
                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 UIName& 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 )
        {
            if (RndStdIds::FLY_AT_FLY == _nAnchorId || !pFormatFrameSize)
                *_opPercent = pFrame->getFramePrintArea().SSize();
            else
            {
                if (pFormatFrameSize->GetWidthPercentRelation() == text::RelOrientation::PAGE_FRAME)
                    _opPercent->setWidth(pFrame->getFrameArea().Width());
                else
                    _opPercent->setWidth(pFrame->getFramePrintArea().Width());

                if (pFormatFrameSize->GetHeightPercentRelation() == text::RelOrientation::PAGE_FRAME)
                     _opPercent->setHeight(pFrame->getFrameArea().Height());
                else
                    _opPercent->setHeight(pFrame->getFramePrintArea().Height());
            }
        }
    }
    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: */
