Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/source/core/frmedt/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 100 kB image not shown  

Quelle  tblsel.cxx

  Sprache: 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 <editeng/boxitem.hxx>
#include <editeng/protitem.hxx>
#include <osl/diagnose.h>

#include <hintids.hxx>
#include <fmtanchr.hxx>
#include <fmtfsize.hxx>
#include <frmatr.hxx>
#include <tblsel.hxx>
#include <crsrsh.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <pam.hxx>
#include <ndtxt.hxx>
#include <swtable.hxx>
#include <cntfrm.hxx>
#include <tabfrm.hxx>
#include <rowfrm.hxx>
#include <cellfrm.hxx>
#include <rootfrm.hxx>
#include <viscrs.hxx>
#include <swtblfmt.hxx>
#include <UndoTable.hxx>
#include <sectfrm.hxx>
#include <frmtool.hxx>
#include <calbck.hxx>
#include <frameformats.hxx>
#include <deque>
#include <memory>

// see also swtable.cxx
#define COLFUZZY 20L

// macros, determining how table boxes are merged:
//  - 1. remove empty lines, all boxes separated with blanks,
//      all lines separated with ParaBreak
//  - 2. remove all empty lines and remove all empty boxes at beginning and end,
//      all boxes separated with Blank,
//      all lines separated with ParaBreak
//  - 3. remove all empty boxes, all boxes separated with blanks,
//      all lines separated with ParaBreak

#undef      DEL_ONLY_EMPTY_LINES
#undef      DEL_EMPTY_BOXES_AT_START_AND_END

namespace {

struct CmpLPt
{
    Point aPos;
    const SwTableBox* pSelBox;
    bool bVert;

    CmpLPt( const Point& rPt, const SwTableBox* pBox, bool bVertical );

    bool operator<( const CmpLPt& rCmp ) const
    {
        if ( bVert )
            return X() > rCmp.X() || ( X() == rCmp.X() && Y() < rCmp.Y() );
        else
            return Y() < rCmp.Y() || ( Y() == rCmp.Y() && X() < rCmp.X() );
    }

    tools::Long X() const { return aPos.X(); }
    tools::Long Y() const { return aPos.Y(); }
};

}

typedef o3tl::sorted_vector<CmpLPt> MergePos;

namespace {

struct Sort_CellFrame
{
    const SwCellFrame* pFrame;

    explicit Sort_CellFrame( const SwCellFrame& rCFrame )
        : pFrame( &rCFrame ) {}
};

}

static const SwLayoutFrame *lcl_FindCellFrame( const SwLayoutFrame *pLay )
{
    while ( pLay && !pLay->IsCellFrame() )
        pLay = pLay->GetUpper();
    return pLay;
}

static const SwLayoutFrame *lcl_FindNextCellFrame( const SwLayoutFrame *pLay )
{
    // ensure we leave the cell (sections)
    const SwLayoutFrame *pTmp = pLay;
    do {
        pTmp = pTmp->GetNextLayoutLeaf();
    } while( pLay->IsAnLower( pTmp ) );

    while( pTmp && !pTmp->IsCellFrame() )
        pTmp = pTmp->GetUpper();
    return pTmp;
}

void GetTableSelCrs( const SwCursorShell &rShell, SwSelBoxes& rBoxes )
{
    rBoxes.clear();
    if( rShell.IsTableMode() && const_cast<SwCursorShell&>(rShell).UpdateTableSelBoxes())
    {
        rBoxes.insert(rShell.GetTableCursor()->GetSelectedBoxes());
    }
}

void GetTableSelCrs( const SwTableCursor& rTableCursor, SwSelBoxes& rBoxes )
{
    rBoxes.clear();

    if (rTableCursor.IsChgd() || !rTableCursor.GetSelectedBoxesCount())
    {
        SwTableCursor* pTCursor = const_cast<SwTableCursor*>(&rTableCursor);
        pTCursor->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout()->MakeTableCursors( *pTCursor );
    }

    if (rTableCursor.GetSelectedBoxesCount())
    {
        rBoxes.insert(rTableCursor.GetSelectedBoxes());
    }
}

void GetTableSel( const SwCursorShell& rShell, SwSelBoxes& rBoxes,
                const SwTableSearchType eSearchType )
{
    // get start and end cell
    if ( !rShell.IsTableMode() )
        rShell.GetCursor();

    GetTableSel( *rShell.getShellCursor(false), rBoxes, eSearchType );
}

void GetTableSel( const SwCursor& rCursor, SwSelBoxes& rBoxes,
                const SwTableSearchType eSearchType )
{
    // get start and end cell
    OSL_ENSURE( rCursor.GetPointContentNode() && rCursor.GetMarkContentNode(),
            "Tabselection not on Cnt." );

    // Row-selection:
    // Check for complex tables. If Yes, search selected boxes via
    // the layout. Otherwise via the table structure (for macros !!)
    const SwContentNode* pContentNd = rCursor.GetPointNode().GetContentNode();
    const SwTableNode* pTableNd = pContentNd ? pContentNd->FindTableNode() : nullptr;
    if( pTableNd && pTableNd->GetTable().IsNewModel() )
    {
        SwTable::SearchType eSearch;
        switch( SwTableSearchType::Col & eSearchType )
        {
            case SwTableSearchType::Row: eSearch = SwTable::SEARCH_ROW; break;
            case SwTableSearchType::Col: eSearch = SwTable::SEARCH_COL; break;
            default: eSearch = SwTable::SEARCH_NONE; break;
        }
        const bool bChkP( SwTableSearchType::Protect & eSearchType );
        pTableNd->GetTable().CreateSelection( rCursor, rBoxes, eSearch, bChkP );
        return;
    }
    if( SwTableSearchType::Row == ((~SwTableSearchType::Protect ) & eSearchType ) &&
        pTableNd && !pTableNd->GetTable().IsTableComplex() )
    {
        const SwTable& rTable = pTableNd->GetTable();
        const SwTableLines& rLines = rTable.GetTabLines();

        const SwNode& rMarkNode = rCursor.GetMarkNode();
        const SwNodeOffset nMarkSectionStart = rMarkNode.StartOfSectionIndex();
        const SwTableBox* pMarkBox = rTable.GetTableBox( nMarkSectionStart );

        OSL_ENSURE( pMarkBox, "Point in table, mark outside?" );

        const SwTableLine* pLine = pMarkBox ? pMarkBox->GetUpper() : nullptr;
        sal_uInt16 nSttPos = rLines.GetPos( pLine );
        OSL_ENSURE( USHRT_MAX != nSttPos, "Where is my row in the table?" );
        pLine = rTable.GetTableBox( rCursor.GetPointNode().StartOfSectionIndex() )->GetUpper();
        sal_uInt16 nEndPos = rLines.GetPos( pLine );
        OSL_ENSURE( USHRT_MAX != nEndPos, "Where is my row in the table?" );
        // pb: #i20193# if tableintable then nSttPos == nEndPos == USHRT_MAX
        if ( nSttPos != USHRT_MAX && nEndPos != USHRT_MAX )
        {
            if( nEndPos < nSttPos )     // exchange
                std::swap( nSttPos, nEndPos );

            bool bChkProtected( SwTableSearchType::Protect & eSearchType );
            for( ; nSttPos <= nEndPos; ++nSttPos )
            {
                pLine = rLines[ nSttPos ];
                forauto n = pLine->GetTabBoxes().size(); n ; )
                {
                    SwTableBox* pBox = pLine->GetTabBoxes()[ --n ];
                    // check for cell protection??
                    if( !bChkProtected ||
                        !pBox->GetFrameFormat()->GetProtect().IsContentProtected() )
                        rBoxes.insert( pBox );
                }
            }
        }
    }
    else
    {
        Point aPtPos, aMkPos;
        const SwShellCursor* pShCursor = dynamic_cast<const SwShellCursor*>(&rCursor);
        if( pShCursor )
        {
            aPtPos = pShCursor->GetPtPos();
            aMkPos = pShCursor->GetMkPos();
        }
        const SwContentNode *pCntNd = rCursor.GetPointContentNode();
        std::pair<Point, bool> tmp(aPtPos, true);
        const SwLayoutFrame *pStart = pCntNd ?
            pCntNd->getLayoutFrame(pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp)->GetUpper() : nullptr;
        pCntNd = rCursor.GetMarkContentNode();
        tmp.first = aMkPos;
        const SwLayoutFrame *pEnd = pCntNd ?
            pCntNd->getLayoutFrame(pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp)->GetUpper() : nullptr;
        if( pStart && pEnd )
            GetTableSel( pStart, pEnd, rBoxes, nullptr, eSearchType );
    }
}

void GetTableSel( const SwLayoutFrame* pStart, const SwLayoutFrame* pEnd,
                SwSelBoxes& rBoxes, SwCellFrames* pCells,
                const SwTableSearchType eSearchType )
{
    const SwTabFrame* pStartTab = pStart->FindTabFrame();
    if ( !pStartTab )
    {
        OSL_FAIL( "GetTableSel without start table" );
        return;
    }

    bool bChkProtected( SwTableSearchType::Protect & eSearchType );

    // #i55421# Reduced value 10
    int nLoopMax = 10;

    do {
        bool bTableIsValid = true;

        // First, compute tables and rectangles
        SwSelUnions aUnions;
        ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );

        Point aCurrentTopLeft( LONG_MAX, LONG_MAX );
        Point aCurrentTopRight( 0, LONG_MAX );
        Point aCurrentBottomLeft( LONG_MAX, 0 );
        Point aCurrentBottomRight( 0, 0 );
        const SwCellFrame* pCurrentTopLeftFrame     = nullptr;
        const SwCellFrame* pCurrentTopRightFrame    = nullptr;
        const SwCellFrame* pCurrentBottomLeftFrame  = nullptr;
        const SwCellFrame* pCurrentBottomRightFrame  = nullptr;

        // Now find boxes for each entry and emit
        for (size_t i = 0; i < aUnions.size() && bTableIsValid; ++i)
        {
            SwSelUnion *pUnion = &aUnions[i];
            const SwTabFrame *pTable = pUnion->GetTable();

            if( !pTable->isFrameAreaDefinitionValid() && nLoopMax )
            {
                bTableIsValid = false;
                break;
            }

            // Skip any repeated headlines in the follow:
            const SwLayoutFrame* pRow = pTable->IsFollow() ?
                                      pTable->GetFirstNonHeadlineRow() :
                                      static_cast<const SwLayoutFrame*>(pTable->Lower());

            while( pRow && bTableIsValid )
            {
                if( !pRow->isFrameAreaDefinitionValid() && nLoopMax )
                {
                    bTableIsValid = false;
                    break;
                }

                if ( pRow->getFrameArea().Overlaps( pUnion->GetUnion() ) )
                {
                    const SwLayoutFrame *pCell = pRow->FirstCell();

                    while (pCell && pRow->IsAnLower(pCell))
                    {
                        if( !pCell->isFrameAreaDefinitionValid() && nLoopMax )
                        {
                            bTableIsValid = false;
                            break;
                        }

                        OSL_ENSURE( pCell->IsCellFrame(), "Frame without Cell" );
                        if( ::IsFrameInTableSel( pUnion->GetUnion(), pCell ) )
                        {
                            SwTableBox* pBox = const_cast<SwTableBox*>(
                                static_cast<const SwCellFrame*>(pCell)->GetTabBox());
                            // check for cell protection??
                            if( !bChkProtected ||
                                !pBox->GetFrameFormat()->GetProtect().IsContentProtected() )
                                rBoxes.insert( pBox );

                            if ( pCells )
                            {
                                const Point aTopLeft( pCell->getFrameArea().TopLeft() );
                                const Point aTopRight( pCell->getFrameArea().TopRight() );
                                const Point aBottomLeft( pCell->getFrameArea().BottomLeft() );
                                const Point aBottomRight( pCell->getFrameArea().BottomRight() );

                                if ( aTopLeft.getY() < aCurrentTopLeft.getY() ||
                                     ( aTopLeft.getY() == aCurrentTopLeft.getY() &&
                                       aTopLeft.getX() <  aCurrentTopLeft.getX() ) )
                                {
                                    aCurrentTopLeft = aTopLeft;
                                    pCurrentTopLeftFrame = static_cast<const SwCellFrame*>( pCell );
                                }

                                if ( aTopRight.getY() < aCurrentTopRight.getY() ||
                                     ( aTopRight.getY() == aCurrentTopRight.getY() &&
                                       aTopRight.getX() >  aCurrentTopRight.getX() ) )
                                {
                                    aCurrentTopRight = aTopRight;
                                    pCurrentTopRightFrame = static_cast<const SwCellFrame*>( pCell );
                                }

                                if ( aBottomLeft.getY() > aCurrentBottomLeft.getY() ||
                                     ( aBottomLeft.getY() == aCurrentBottomLeft.getY() &&
                                       aBottomLeft.getX() <  aCurrentBottomLeft.getX() ) )
                                {
                                    aCurrentBottomLeft = aBottomLeft;
                                    pCurrentBottomLeftFrame = static_cast<const SwCellFrame*>( pCell );
                                }

                                if ( aBottomRight.getY() > aCurrentBottomRight.getY() ||
                                     ( aBottomRight.getY() == aCurrentBottomRight.getY() &&
                                       aBottomRight.getX() >  aCurrentBottomRight.getX() ) )
                                {
                                    aCurrentBottomRight = aBottomRight;
                                    pCurrentBottomRightFrame = static_cast<const SwCellFrame*>( pCell );
                                }

                            }
                        }
                        if ( pCell->GetNext() )
                        {
                            pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
                            const SwFrame* pLower = pCell->Lower();
                            if ( pLower && pLower->IsRowFrame() )
                                pCell = pCell->FirstCell();
                        }
                        else
                            pCell = ::lcl_FindNextCellFrame( pCell );
                    }
                }
                pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
            }
        }

        if ( pCells )
        {
            pCells->clear();
            pCells->push_back( const_cast< SwCellFrame* >(pCurrentTopLeftFrame) );
            pCells->push_back( const_cast< SwCellFrame* >(pCurrentTopRightFrame) );
            pCells->push_back( const_cast< SwCellFrame* >(pCurrentBottomLeftFrame) );
            pCells->push_back( const_cast< SwCellFrame* >(pCurrentBottomRightFrame) );
        }

        if( bTableIsValid )
            break;

        SwDeletionChecker aDelCheck( pStart );

        // otherwise quickly "calculate" the table layout and start over
        SwTabFrame *pTable = aUnions.front().GetTable();
        while( pTable )
        {
            if( pTable->isFrameAreaDefinitionValid() )
            {
                pTable->InvalidatePos();
            }

            pTable->SetONECalcLowers();
            pTable->Calc(pTable->getRootFrame()->GetCurrShell()->GetOut());
            pTable->SetCompletePaint();

            pTable = pTable->GetFollow();
            if( nullptr == pTable )
                break;
        }

        // --> Make code robust, check if pStart has
        // been deleted due to the formatting of the table:
        if ( aDelCheck.HasBeenDeleted() )
        {
            OSL_FAIL( "Current box has been deleted during GetTableSel()" );
            break;
        }

        rBoxes.clear();
        --nLoopMax;

    } whiletrue );
    OSL_ENSURE( nLoopMax, "Table layout is still invalid!" );
}

bool ChkChartSel( const SwNode& rSttNd, const SwNode& rEndNd )
{
    const SwTableNode* pTNd = rSttNd.FindTableNode();
    if( !pTNd )
        return false;

    Point aNullPos;
    SwNodeIndex aIdx( rSttNd );
    const SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
    if( !pCNd )
        pCNd = SwNodes::GoNextSection(&aIdx, falsefalse);

    // if table is invisible, return
    // (layout needed for forming table selection further down, so we can't
    //  continue with invisible tables)
    // #i22135# - Also the content of the table could be
    //                          invisible - e.g. in a hidden section
    // Robust: check, if content was found (e.g. empty table cells)
    if ( !pCNd || pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) == nullptr )
            return false;

    std::pair<Point, bool> tmp(aNullPos, true);
    const SwLayoutFrame *const pStart = pCNd->getLayoutFrame(
            pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
            nullptr, &tmp)->GetUpper();
    OSL_ENSURE( pStart, "without frame nothing works" );

    aIdx = rEndNd;
    pCNd = aIdx.GetNode().GetContentNode();
    if( !pCNd )
        pCNd = SwNodes::GoNextSection(&aIdx, falsefalse);

    // #i22135# - Robust: check, if content was found and if it's visible
    if ( !pCNd || pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) == nullptr )
    {
        return false;
    }

    const SwLayoutFrame *const pEnd = pCNd->getLayoutFrame(
            pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
            nullptr, &tmp)->GetUpper();
    OSL_ENSURE( pEnd, "without frame nothing works" );

    bool bValidChartSel;
    // #i55421# Reduced value 10
    int nLoopMax = 10;      //JP 28.06.99: max 100 loops - Bug 67292

    do {
        bool bTableIsValid = true;
        bValidChartSel = true;

        sal_uInt16 nRowCells = USHRT_MAX;

        // First, compute tables and rectangles
        SwSelUnions aUnions;
        ::MakeSelUnions( aUnions, pStart, pEnd, SwTableSearchType::NoUnionCorrect );

        // find boxes for each entry and emit
        forauto & rSelUnion : aUnions )
        {
            if (!bTableIsValid || !bValidChartSel)
                break;

            SwSelUnion *pUnion = &rSelUnion;
            const SwTabFrame *pTable = pUnion->GetTable();

            SwRectFnSet aRectFnSet(pTable);
            bool bRTL = pTable->IsRightToLeft();

            if( !pTable->isFrameAreaDefinitionValid() && nLoopMax  )
            {
                bTableIsValid = false;
                break;
            }

            std::deque< Sort_CellFrame > aCellFrames;

            // Skip any repeated headlines in the follow:
            const SwLayoutFrame* pRow = pTable->IsFollow() ?
                                      pTable->GetFirstNonHeadlineRow() :
                                      static_cast<const SwLayoutFrame*>(pTable->Lower());

            while( pRow && bTableIsValid && bValidChartSel )
            {
                if( !pRow->isFrameAreaDefinitionValid() && nLoopMax )
                {
                    bTableIsValid = false;
                    break;
                }

                if( pRow->getFrameArea().Overlaps( pUnion->GetUnion() ) )
                {
                    const SwLayoutFrame *pCell = pRow->FirstCell();

                    while (pCell && pRow->IsAnLower(pCell))
                    {
                        if( !pCell->isFrameAreaDefinitionValid() && nLoopMax  )
                        {
                            bTableIsValid = false;
                            break;
                        }

                        OSL_ENSURE( pCell->IsCellFrame(), "Frame without Cell" );
                        const SwRect& rUnion = pUnion->GetUnion(),
                                    & rFrameRect = pCell->getFrameArea();

                        const tools::Long nUnionRight = rUnion.Right();
                        const tools::Long nUnionBottom = rUnion.Bottom();
                        const tools::Long nFrameRight = rFrameRect.Right();
                        const tools::Long nFrameBottom = rFrameRect.Bottom();

                        // ignore if FrameRect is outside the union

                        const tools::Long nXFuzzy = aRectFnSet.IsVert() ? 0 : 20;
                        const tools::Long nYFuzzy = aRectFnSet.IsVert() ? 20 : 0;

                        if( !(  rUnion.Top()  + nYFuzzy > nFrameBottom ||
                                nUnionBottom < rFrameRect.Top() + nYFuzzy ||
                                rUnion.Left() + nXFuzzy > nFrameRight ||
                                nUnionRight < rFrameRect.Left() + nXFuzzy ))
                        {
                            // ok, rUnion is _not_ completely outside of rFrameRect

                            // if not completely inside the union, then
                            // for Chart it is an invalid selection
                            if( rUnion.Left()   <= rFrameRect.Left() + nXFuzzy &&
                                rFrameRect.Left() <= nUnionRight &&
                                rUnion.Left()   <= nFrameRight &&
                                nFrameRight       <= nUnionRight + nXFuzzy &&
                                rUnion.Top()    <= rFrameRect.Top() + nYFuzzy &&
                                rFrameRect.Top()  <= nUnionBottom &&
                                rUnion.Top()    <= nFrameBottom &&
                                nFrameBottom      <= nUnionBottom+ nYFuzzy )

                                aCellFrames.emplace_back( *static_cast<const SwCellFrame*>(pCell) );
                            else
                            {
                                bValidChartSel = false;
                                break;
                            }
                        }
                        if ( pCell->GetNext() )
                        {
                            pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
                            if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
                                pCell = pCell->FirstCell();
                        }
                        else
                            pCell = ::lcl_FindNextCellFrame( pCell );
                    }
                }
                pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
            }

            if( !bValidChartSel )
                break;

            // all cells of the (part) table together. Now check if
            // they're all adjacent
            size_t n;
            sal_uInt16 nCellCnt = 0;
            tools::Long nYPos = LONG_MAX;
            tools::Long nXPos = 0;
            tools::Long nHeight = 0;

            for( n = 0 ; n < aCellFrames.size(); ++n )
            {
                const Sort_CellFrame& rCF = aCellFrames[ n ];
                if( aRectFnSet.GetTop(rCF.pFrame->getFrameArea()) != nYPos )
                {
                    // new row
                    if( n )
                    {
                        if( USHRT_MAX == nRowCells )        // 1. row change
                            nRowCells = nCellCnt;
                        else if( nRowCells != nCellCnt )
                        {
                            bValidChartSel = false;
                            break;
                        }
                    }
                    nCellCnt = 1;
                    nYPos = aRectFnSet.GetTop(rCF.pFrame->getFrameArea());
                    nHeight = aRectFnSet.GetHeight(rCF.pFrame->getFrameArea());

                    nXPos = bRTL ?
                            aRectFnSet.GetLeft(rCF.pFrame->getFrameArea()) :
                            aRectFnSet.GetRight(rCF.pFrame->getFrameArea());
                }
                else if( nXPos == ( bRTL ?
                                    aRectFnSet.GetRight(rCF.pFrame->getFrameArea()) :
                                    aRectFnSet.GetLeft(rCF.pFrame->getFrameArea()) ) &&
                         nHeight == aRectFnSet.GetHeight(rCF.pFrame->getFrameArea()) )
                {
                    nXPos += ( bRTL ? -1 : 1 ) *
                             aRectFnSet.GetWidth(rCF.pFrame->getFrameArea());
                    ++nCellCnt;
                }
                else
                {
                    bValidChartSel = false;
                    break;
                }
            }
            if( bValidChartSel )
            {
                if( USHRT_MAX == nRowCells )
                    nRowCells = nCellCnt;
                else if( nRowCells != nCellCnt )
                    bValidChartSel = false;
            }
        }

        if( bTableIsValid )
            break;

        // otherwise quickly "calculate" table layout and start over
        SwTabFrame *pTable = aUnions.front().GetTable();

        for( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
        {
            if( pTable->isFrameAreaDefinitionValid() )
            {
                pTable->InvalidatePos();
            }

            pTable->SetONECalcLowers();
            pTable->Calc(pTable->getRootFrame()->GetCurrShell()->GetOut());
            pTable->SetCompletePaint();

            pTable = pTable->GetFollow();
            if( nullptr == pTable )
                break;
        }
        --nLoopMax;
    } whiletrue );

    OSL_ENSURE( nLoopMax, "table layout is still invalid!" );

    return bValidChartSel;
}

bool IsFrameInTableSel( const SwRect& rUnion, const SwFrame* pCell )
{
    OSL_ENSURE( pCell->IsCellFrame(), "Frame without Gazelle" );

    if( pCell->FindTabFrame()->IsVertical() )
        return   rUnion.Right() >= pCell->getFrameArea().Right() &&
                 rUnion.Left() <= pCell->getFrameArea().Left() &&
            (( rUnion.Top() <= pCell->getFrameArea().Top()+20 &&
               rUnion.Bottom() > pCell->getFrameArea().Top() ) ||
             ( rUnion.Top() >= pCell->getFrameArea().Top() &&
               rUnion.Bottom() < pCell->getFrameArea().Bottom() ));

    return
        rUnion.Top() <= pCell->getFrameArea().Top() &&
        rUnion.Bottom() >= pCell->getFrameArea().Bottom() &&

        (( rUnion.Left() <= pCell->getFrameArea().Left()+20 &&
           rUnion.Right() > pCell->getFrameArea().Left() ) ||

         ( rUnion.Left() >= pCell->getFrameArea().Left() &&
           rUnion.Right() < pCell->getFrameArea().Right() ));
}

bool GetAutoSumSel( const SwCursorShell& rShell, SwCellFrames& rBoxes )
{
    SwShellCursor* pCursor = rShell.m_pCurrentCursor;
    if ( rShell.IsTableMode() )
        pCursor = rShell.m_pTableCursor;

    std::pair<Point, bool> tmp(pCursor->GetPtPos(), true);
    const SwLayoutFrame *const pStart = pCursor->GetPointContentNode()->getLayoutFrame(
            rShell.GetLayout(), nullptr, &tmp)->GetUpper();
    tmp.first = pCursor->GetMkPos();
    const SwLayoutFrame *const pEnd = pCursor->GetMarkContentNode()->getLayoutFrame(
            rShell.GetLayout(), nullptr, &tmp)->GetUpper();

    const SwLayoutFrame* pSttCell = pStart;
    while( pSttCell && !pSttCell->IsCellFrame() )
        pSttCell = pSttCell->GetUpper();

    // First, compute tables and rectangles
    SwSelUnions aUnions;

    // by default, first test above and then to the left
    ::MakeSelUnions( aUnions, pStart, pEnd, SwTableSearchType::Col );

    bool bTstRow = true, bFound = false;

    // 1. check if box above contains value/formula
    for( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
    {
        SwSelUnion *pUnion = &aUnions[i];
        const SwTabFrame *pTable = pUnion->GetTable();

        // Skip any repeated headlines in the follow:
        const SwLayoutFrame* pRow = pTable->IsFollow() ?
                                  pTable->GetFirstNonHeadlineRow() :
                                  static_cast<const SwLayoutFrame*>(pTable->Lower());

        while( pRow )
        {
            if( pRow->getFrameArea().Overlaps( pUnion->GetUnion() ) )
            {
                const SwCellFrame* pUpperCell = nullptr;
                const SwLayoutFrame *pCell = pRow->FirstCell();

                while( pCell && pRow->IsAnLower( pCell ) )
                {
                    if( pCell == pSttCell )
                    {
                        sal_uInt16 nWhichId = 0;
                        for( size_t n = rBoxes.size(); n; )
                        {
                            nWhichId = rBoxes[ --n ]->GetTabBox()->IsFormulaOrValueBox();
                            if( USHRT_MAX != nWhichId )
                                break;
                        }

                        // all boxes together, do not check the
                        // row, if a formula or value was found
                        bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId;
                        bFound = true;
                        break;
                    }

                    OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" );
                    if( ::IsFrameInTableSel( pUnion->GetUnion(), pCell ) )
                        pUpperCell = static_cast<const SwCellFrame*>(pCell);

                    if( pCell->GetNext() )
                    {
                        pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
                        if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
                            pCell = pCell->FirstCell();
                    }
                    else
                        pCell = ::lcl_FindNextCellFrame( pCell );
                }

                if( pUpperCell )
                    rBoxes.push_back( const_cast< SwCellFrame* >(pUpperCell) );
            }
            if( bFound )
            {
                i = aUnions.size();
                break;
            }
            pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
        }
    }

    // 2. check if box on left contains value/formula
    if( bTstRow )
    {
        bFound = false;

        rBoxes.clear();
        aUnions.clear();
        ::MakeSelUnions( aUnions, pStart, pEnd, SwTableSearchType::Row );

        for( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
        {
            SwSelUnion *pUnion = &aUnions[i];
            const SwTabFrame *pTable = pUnion->GetTable();

            // Skip any repeated headlines in the follow:
            const SwLayoutFrame* pRow = pTable->IsFollow() ?
                                      pTable->GetFirstNonHeadlineRow() :
                                      static_cast<const SwLayoutFrame*>(pTable->Lower());

            while( pRow )
            {
                if( pRow->getFrameArea().Overlaps( pUnion->GetUnion() ) )
                {
                    const SwLayoutFrame *pCell = pRow->FirstCell();

                    while( pCell && pRow->IsAnLower( pCell ) )
                    {
                        if( pCell == pSttCell )
                        {
                            sal_uInt16 nWhichId = 0;
                            for( size_t n = rBoxes.size(); n; )
                            {
                                nWhichId = rBoxes[ --n ]
                                    ->GetTabBox()->IsFormulaOrValueBox();
                                if( USHRT_MAX != nWhichId )
                                    break;
                            }

                            // all boxes together, do not check the
                            // row if a formula or value was found
                            bFound = 0 != nWhichId && USHRT_MAX != nWhichId;
                            bTstRow = false;
                            break;
                        }

                        OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" );
                        if( ::IsFrameInTableSel( pUnion->GetUnion(), pCell ) )
                        {
                            SwCellFrame* pC = const_cast<SwCellFrame*>(static_cast<const SwCellFrame*>(pCell));
                            rBoxes.push_back( pC );
                        }
                        if( pCell->GetNext() )
                        {
                            pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
                            const SwFrame* pLower = pCell->Lower();
                            if ( pLower && pLower->IsRowFrame() )
                                pCell = pCell->FirstCell();
                        }
                        else
                            pCell = ::lcl_FindNextCellFrame( pCell );
                    }
                }
                if( !bTstRow )
                {
                    i = aUnions.size();
                    break;
                }

                pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
            }
        }
    }

    return bFound;
}

bool HasProtectedCells( const SwSelBoxes& rBoxes )
{
    bool bRet = false;
    for (size_t n = 0; n < rBoxes.size(); ++n)
    {
        if( rBoxes[ n ]->GetFrameFormat()->GetProtect().IsContentProtected() )
        {
            bRet = true;
            break;
        }
    }
    return bRet;
}

CmpLPt::CmpLPt( const Point& rPt, const SwTableBox* pBox, bool bVertical )
    : aPos( rPt ), pSelBox( pBox ), bVert( bVertical )
{}

static void lcl_InsTableBox( SwTableNode* pTableNd, SwDoc& rDoc, SwTableBox* pBox,
                        sal_uInt16 nInsPos, sal_uInt16 nCnt = 1 )
{
    OSL_ENSURE( pBox->GetSttNd(), "Box without Start-Node" );
    SwContentNode* pCNd = rDoc.GetNodes()[ pBox->GetSttIdx() + 1 ]
                                ->GetContentNode();
    if( pCNd && pCNd->IsTextNode() )
        rDoc.GetNodes().InsBoxen( pTableNd, pBox->GetUpper(),
                pBox->GetFrameFormat(),
                static_cast<SwTextNode*>(pCNd)->GetTextColl(),
                pCNd->GetpSwAttrSet(),
                nInsPos, nCnt );
    else
        rDoc.GetNodes().InsBoxen( pTableNd, pBox->GetUpper(),
                pBox->GetFrameFormat(),
                rDoc.GetDfltTextFormatColl(), nullptr,
                nInsPos, nCnt );
}

bool IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam )
{
    rPam.GetPoint()->Assign( *rBox.GetSttNd()->EndOfSectionNode() );
    rPam.Move( fnMoveBackward, GoInContent );
    rPam.SetMark();
    rPam.GetPoint()->Assign( *rBox.GetSttNd() );
    rPam.Move( fnMoveForward, GoInContent );
    bool bRet = *rPam.GetMark() == *rPam.GetPoint()
        && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->GetNodeIndex() );

    if( bRet )
    {
        // now check for paragraph bound flies
        const sw::SpzFrameFormats& rFormats = *rPam.GetDoc().GetSpzFrameFormats();
        SwNodeOffset nSttIdx = rPam.GetPoint()->GetNodeIndex(),
              nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(),
              nIdx;

        forauto pFormat : rFormats )
        {
            const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
            const SwNode* pAnchorNode = rAnchor.GetAnchorNode();
            if (pAnchorNode &&
                ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
                 (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
                nSttIdx <= ( nIdx = pAnchorNode->GetIndex() ) &&
                nIdx < nEndIdx )
            {
                bRet = false;
                break;
            }
        }
    }
    return bRet;
}

void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes,
                SwTableBox** ppMergeBox, SwUndoTableMerge* pUndo )
{
    rBoxes.clear();

    OSL_ENSURE( rPam.GetPointContentNode() && rPam.GetMarkContentNode(),
            "Tabselection not on Cnt." );

//JP 24.09.96:  Merge with repeating TableHeadLines does not work properly.
//              Why not use point 0,0? Then it is assured the first
//              headline is contained.
    Point aPt( 0, 0 );

    const SwContentNode* pCntNd = rPam.GetPointContentNode();
    std::pair<Point, boolconst tmp(aPt, true);
    const SwLayoutFrame *const pStart = pCntNd->getLayoutFrame(
            pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
            nullptr, &tmp)->GetUpper();
    pCntNd = rPam.GetMarkContentNode();
    const SwLayoutFrame *const pEnd = pCntNd->getLayoutFrame(
            pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
            nullptr, &tmp)->GetUpper();

    // First, compute tables and rectangles
    SwSelUnions aUnions;
    ::MakeSelUnions( aUnions, pStart, pEnd );
    if( aUnions.empty() )
        return;

    const SwTable *pTable = aUnions.front().GetTable()->GetTable();
    SwDoc& rDoc = const_cast<SwDoc&>(pStart->GetFormat()->GetDoc());
    SwTableNode* pTableNd = const_cast<SwTableNode*>(pTable->GetTabSortBoxes()[ 0 ]->
                                        GetSttNd()->FindTableNode());

    MergePos aPosArr;      // Sort-Array with the frame positions
    tools::Long nWidth;
    SwTableBox* pLastBox = nullptr;

    SwRectFnSet aRectFnSet(pStart->GetUpper());

    for ( auto & rSelUnion : aUnions )
    {
        const SwTabFrame *pTabFrame = rSelUnion.GetTable();

        SwRect &rUnion = rSelUnion.GetUnion();

        // Skip any repeated headlines in the follow:
        const SwLayoutFrame* pRow = pTabFrame->IsFollow() ?
                                  pTabFrame->GetFirstNonHeadlineRow() :
                                  static_cast<const SwLayoutFrame*>(pTabFrame->Lower());

        while ( pRow )
        {
            if ( pRow->getFrameArea().Overlaps( rUnion ) )
            {
                const SwLayoutFrame *pCell = pRow->FirstCell();

                while ( pCell && pRow->IsAnLower( pCell ) )
                {
                    OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" );
                    // overlap in full width?
                    if( rUnion.Top() <= pCell->getFrameArea().Top() &&
                        rUnion.Bottom() >= pCell->getFrameArea().Bottom() )
                    {
                        SwTableBox* pBox = const_cast<SwTableBox*>(static_cast<const SwCellFrame*>(pCell)->GetTabBox());

                        // only overlap to the right?
                        if( ( rUnion.Left() - COLFUZZY ) <= pCell->getFrameArea().Left() &&
                            ( rUnion.Right() - COLFUZZY ) > pCell->getFrameArea().Left() )
                        {
                            if( ( rUnion.Right() + COLFUZZY ) < pCell->getFrameArea().Right() )
                            {
                                sal_uInt16 nInsPos = pBox->GetUpper()->GetBoxPos( pBox )+1;
                                lcl_InsTableBox( pTableNd, rDoc, pBox, nInsPos );
                                pBox->ClaimFrameFormat();
                                SwFormatFrameSize aNew(
                                        pBox->GetFrameFormat()->GetFrameSize() );
                                nWidth = rUnion.Right() - pCell->getFrameArea().Left();
                                nWidth = nWidth * aNew.GetWidth() /
                                         pCell->getFrameArea().Width();
                                tools::Long nTmpWidth = aNew.GetWidth() - nWidth;
                                aNew.SetWidth( nWidth );
                                pBox->GetFrameFormat()->SetFormatAttr( aNew );
                                // this box is selected
                                pLastBox = pBox;
                                rBoxes.insert( pBox );
                                aPosArr.insert(
                                    CmpLPt( aRectFnSet.GetPos(pCell->getFrameArea()),
                                    pBox, aRectFnSet.IsVert() ) );

                                pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
                                aNew.SetWidth( nTmpWidth );
                                pBox->ClaimFrameFormat();
                                pBox->GetFrameFormat()->SetFormatAttr( aNew );

                                if( pUndo )
                                    pUndo->AddNewBox( pBox->GetSttIdx() );
                            }
                            else
                            {
                                // this box is selected
                                pLastBox = pBox;
                                rBoxes.insert( pBox );
                                aPosArr.insert(
                                    CmpLPt( aRectFnSet.GetPos(pCell->getFrameArea()),
                                    pBox, aRectFnSet.IsVert() ) );
                            }
                        }
                        // overlapping on left- or right-side
                        else if( ( rUnion.Left() - COLFUZZY ) >= pCell->getFrameArea().Left() &&
                                ( rUnion.Right() + COLFUZZY ) < pCell->getFrameArea().Right() )
                        {
                            sal_uInt16 nInsPos = pBox->GetUpper()->GetBoxPos( pBox )+1;
                            lcl_InsTableBox( pTableNd, rDoc, pBox, nInsPos, 2 );
                            pBox->ClaimFrameFormat();
                            SwFormatFrameSize aNew(
                                        pBox->GetFrameFormat()->GetFrameSize() );
                            tools::Long nLeft = rUnion.Left() - pCell->getFrameArea().Left();
                            nLeft = nLeft * aNew.GetWidth() /
                                    pCell->getFrameArea().Width();
                            tools::Long nRight = pCell->getFrameArea().Right() - rUnion.Right();
                            nRight = nRight * aNew.GetWidth() /
                                     pCell->getFrameArea().Width();
                            nWidth = aNew.GetWidth() - nLeft - nRight;

                            aNew.SetWidth( nLeft );
                            pBox->GetFrameFormat()->SetFormatAttr( aNew );

                            ifconst SvxBoxItem* pItem = pBox->GetFrameFormat()->GetAttrSet()
                                        .GetItemIfSet( RES_BOX, false ))
                            {
                                SvxBoxItem aBox( *pItem );
                                aBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
                                pBox->GetFrameFormat()->SetFormatAttr( aBox );
                            }

                            pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
                            aNew.SetWidth( nWidth );
                            pBox->ClaimFrameFormat();
                            pBox->GetFrameFormat()->SetFormatAttr( aNew );

                            if( pUndo )
                                pUndo->AddNewBox( pBox->GetSttIdx() );

                            // this box is selected
                            pLastBox = pBox;
                            rBoxes.insert( pBox );
                            aPosArr.insert(
                                CmpLPt( aRectFnSet.GetPos(pCell->getFrameArea()),
                                pBox, aRectFnSet.IsVert() ) );

                            pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ];
                            aNew.SetWidth( nRight );
                            pBox->ClaimFrameFormat();
                            pBox->GetFrameFormat()->SetFormatAttr( aNew );

                            if( pUndo )
                                pUndo->AddNewBox( pBox->GetSttIdx() );
                        }
                       // is right side of box part of the selected area?
                        else if( ( pCell->getFrameArea().Right() - COLFUZZY ) < rUnion.Right() &&
                                 ( pCell->getFrameArea().Right() - COLFUZZY ) > rUnion.Left() &&
                                 ( pCell->getFrameArea().Left() + COLFUZZY ) < rUnion.Left() )
                        {
                            // then we should insert a new box and adjust the widths
                            sal_uInt16 nInsPos = pBox->GetUpper()->GetBoxPos( pBox )+1;
                            lcl_InsTableBox( pTableNd, rDoc, pBox, nInsPos );

                            SwFormatFrameSize aNew(pBox->GetFrameFormat()->GetFrameSize() );
                            tools::Long nLeft = rUnion.Left() - pCell->getFrameArea().Left(),
                                nRight = pCell->getFrameArea().Right() - rUnion.Left();

                            nLeft = nLeft * aNew.GetWidth() /
                                    pCell->getFrameArea().Width();
                            nRight = nRight * aNew.GetWidth() /
                                    pCell->getFrameArea().Width();

                            aNew.SetWidth( nLeft );
                            pBox->ClaimFrameFormat()->SetFormatAttr( aNew );

                                // this box is selected
                            pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
                            aNew.SetWidth( nRight );
                            pBox->ClaimFrameFormat();
                            pBox->GetFrameFormat()->SetFormatAttr( aNew );

                            pLastBox = pBox;
                            rBoxes.insert( pBox );
                            aPosArr.insert( CmpLPt( Point( rUnion.Left(),
                                                pCell->getFrameArea().Top()), pBox, aRectFnSet.IsVert() ));

                            if( pUndo )
                                pUndo->AddNewBox( pBox->GetSttIdx() );
                        }
                    }
                    if ( pCell->GetNext() )
                    {
                        pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
                        // --> Check if table cell is not empty
                        if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
                            pCell = pCell->FirstCell();
                    }
                    else
                        pCell = ::lcl_FindNextCellFrame( pCell );
                }
            }
            pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
        }
    }

    // no SSelection / no boxes found
    if( 1 >= rBoxes.size() )
        return;

    // now search all horizontally adjacent boxes and connect
    // their contents with blanks. All vertically adjacent will be tied
    // together as paragraphs

    // 1. Solution: map array and all on same Y-level
    //      are separated with blanks
    //      all others are separated with paragraphs
    bool bCalcWidth = true;
    const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox;

    // JP 27.03.98:  Optimise - if boxes on one row are empty,
    //              then do not insert blanks or carriage returns
    //Block to assure SwPaM, SwPosition are deleted from stack
    {
        SwPaM aPam( rDoc.GetNodes() );

#if defined( DEL_ONLY_EMPTY_LINES )
        nWidth = pFirstBox->GetFrameFormat()->GetFrameSize().GetWidth();
        bool bEmptyLine = sal_True;
        sal_uInt16 n, nSttPos = 0;

        for( n = 0; n < aPosArr.Count(); ++n )
        {
            const CmpLPt& rPt = aPosArr[ n ];
            if( n && aPosArr[ n - 1 ].Y() == rPt.Y() )  // same Y level?
            {
                if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam ))
                    bEmptyLine = sal_False;
                if( bCalcWidth )
                    nWidth += rPt.pSelBox->GetFrameFormat()->GetFrameSize().GetWidth();
            }
            else
            {
                if( bCalcWidth && n )
                    bCalcWidth = false;     // one line is ready

                if( bEmptyLine && nSttPos < n )
                {
                    // now complete line is empty and should not
                    // be filled with blanks and be inserted as paragraph
                    if( pUndo )
                        for( sal_uInt16 i = nSttPos; i < n; ++i )
                            pUndo->SaveCollection( *aPosArr[ i ].pSelBox );

                    aPosArr.Remove( nSttPos, n - nSttPos );
                    n = nSttPos;
                }
                else
                    nSttPos = n;

                bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam );
            }
        }
        if( bEmptyLine && nSttPos < n )
        {
            if( pUndo )
                for( sal_uInt16 i = nSttPos; i < n; ++i )
                    pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
            aPosArr.Remove( nSttPos, n - nSttPos );
        }
#elif defined( DEL_EMPTY_BOXES_AT_START_AND_END )

        nWidth = pFirstBox->GetFrameFormat()->GetFrameSize().GetWidth();
        sal_uInt16 n, nSttPos = 0, nSEndPos = 0, nESttPos = 0;

        for( n = 0; n < aPosArr.Count(); ++n )
        {
            const CmpLPt& rPt = aPosArr[ n ];
            if( n && aPosArr[ n - 1 ].Y() == rPt.Y() )  // same Y level?
            {
                bool bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam );
                if( bEmptyBox )
                {
                    if( nSEndPos == n )     // beginning is empty
                        nESttPos = ++nSEndPos;
                }
                else                        // end could be empty
                    nESttPos = n+1;

                if( bCalcWidth )
                    nWidth += rPt.pSelBox->GetFrameFormat()->GetFrameSize().GetWidth();
            }
            else
            {
                if( bCalcWidth && n )
                    bCalcWidth = false;     // one line ready

                // first those at the beginning
                if( nSttPos < nSEndPos )
                {
                    // now the beginning of the line is empty and should
                    // not be filled with blanks
                    if( pUndo )
                        for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
                            pUndo->SaveCollection( *aPosArr[ i ].pSelBox );

                    sal_uInt16 nCnt = nSEndPos - nSttPos;
                    aPosArr.Remove( nSttPos, nCnt );
                    nESttPos -= nCnt;
                    n -= nCnt;
                }

                if( nESttPos < n )
                {
                    // now the beginning of the line is empty and should
                    // not be filled with blanks
                    if( pUndo )
                        for( sal_uInt16 i = nESttPos; i < n; ++i )
                            pUndo->SaveCollection( *aPosArr[ i ].pSelBox );

                    sal_uInt16 nCnt = n - nESttPos;
                    aPosArr.Remove( nESttPos, nCnt );
                    n -= nCnt;
                }

                nSttPos = nSEndPos = nESttPos = n;
                if( IsEmptyBox( *aPosArr[n].pSelBox, aPam ))
                    ++nSEndPos;
                else
                    ++nESttPos;
            }
        }

        // first those at the beginning
        if( nSttPos < nSEndPos )
        {
            // now the beginning of the line is empty and should
            // not be filled with blanks
            if( pUndo )
                for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
                    pUndo->SaveCollection( *aPosArr[ i ].pSelBox );

            sal_uInt16 nCnt = nSEndPos - nSttPos;
            aPosArr.Remove( nSttPos, nCnt );
            nESttPos -= nCnt;
            n -= nCnt;
        }
        if( nESttPos < n )
        {
            // now the beginning of the line is empty and should
            // not be filled with blanks
            if( pUndo )
                for( sal_uInt16 i = nESttPos; i < n; ++i )
                    pUndo->SaveCollection( *aPosArr[ i ].pSelBox );

            sal_uInt16 nCnt = n - nESttPos;
            aPosArr.Remove( nESttPos, nCnt );
        }
#else
// DEL_ALL_EMPTY_BOXES

        nWidth = 0;
        tools::Long nY = !aPosArr.empty() ?
                    ( aRectFnSet.IsVert() ?
                      aPosArr[ 0 ].X() :
                      aPosArr[ 0 ].Y() ) :
                  0;

        for( MergePos::size_type n = 0; n < aPosArr.size(); ++n )
        {
            const CmpLPt& rPt = aPosArr[ n ];
            if( bCalcWidth )
            {
                if( nY == ( aRectFnSet.IsVert() ? rPt.X() : rPt.Y() ) ) // same Y level?
                    nWidth += rPt.pSelBox->GetFrameFormat()->GetFrameSize().GetWidth();
                else
                    bCalcWidth = false;     // one line ready
            }

            if( IsEmptyBox( *rPt.pSelBox, aPam ) )
            {
                if( pUndo )
                    pUndo->SaveCollection( *rPt.pSelBox );

                aPosArr.erase( aPosArr.begin() + n );
                --n;
            }
        }
#endif
    }

    // first create new box
    {
        SwTableBox* pTmpBox = rBoxes[0];
        SwTableLine* pInsLine = pTmpBox->GetUpper();
        sal_uInt16 nInsPos = pInsLine->GetBoxPos( pTmpBox );

        lcl_InsTableBox( pTableNd, rDoc, pTmpBox, nInsPos );
        (*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ];
        pInsLine->GetTabBoxes().erase( pInsLine->GetTabBoxes().begin() + nInsPos );  // remove again
        (*ppMergeBox)->SetUpper( nullptr );
        (*ppMergeBox)->ClaimFrameFormat();

        // define the border: the upper/left side of the first box,
        // the lower/right side of the last box:
        if( pLastBox && pFirstBox )
        {
            SvxBoxItem aBox( pFirstBox->GetFrameFormat()->GetBox() );
            const SvxBoxItem& rBox = pLastBox->GetFrameFormat()->GetBox();
            aBox.SetLine( rBox.GetRight(), SvxBoxItemLine::RIGHT );
            aBox.SetLine( rBox.GetBottom(), SvxBoxItemLine::BOTTOM );
            if( aBox.GetLeft() || aBox.GetTop() ||
                aBox.GetRight() || aBox.GetBottom() )
                (*ppMergeBox)->GetFrameFormat()->SetFormatAttr( aBox );
        }
    }

    //Block to delete  SwPaM, SwPosition from stack
    if( !aPosArr.empty() )
    {
        SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() );

        SwPaM aPam( aInsPos );

        forconst auto &rPt : aPosArr )
        {
            aPam.GetPoint()->Assign( *rPt.pSelBox->GetSttNd()->
                                            EndOfSectionNode(), SwNodeOffset(-1) );
            SwContentNode* pCNd = aPam.GetPointContentNode();
            if( pCNd )
                aPam.GetPoint()->SetContent( pCNd->Len() );

            SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 );
            // one node should be kept in the box (otherwise the
            // section would be deleted during a move)
            bool const bUndo(rDoc.GetIDocumentUndoRedo().DoesUndo());
            if( pUndo )
            {
                rDoc.GetIDocumentUndoRedo().DoUndo(false);
            }
            rDoc.getIDocumentContentOperations().AppendTextNode( *aPam.GetPoint() );
            if( pUndo )
            {
                rDoc.GetIDocumentUndoRedo().DoUndo(bUndo);
            }
            SwNodeRange aRg( aSttNdIdx.GetNode(), aPam.GetPoint()->GetNode() );
            aInsPos.Adjust(SwNodeOffset(1));
            if( pUndo )
                pUndo->MoveBoxContent( rDoc, aRg, aInsPos.GetNode() );
            else
            {
                rDoc.getIDocumentContentOperations().MoveNodeRange( aRg, aInsPos.GetNode(),
                    SwMoveFlags::DEFAULT );
            }
            // where is now aInsPos ??

            if( bCalcWidth )
                bCalcWidth = false;     // one line is ready

            // skip the first TextNode
            aInsPos.Assign( *rDoc.GetNodes()[ aInsPos.GetNode().EndOfSectionIndex() - 2] );
            SwTextNode* pTextNd = aInsPos.GetNode().GetTextNode();
            if( pTextNd )
                aInsPos.SetContent( pTextNd->GetText().getLength());
        }

        // the MergeBox should contain the complete text
        // now erase the initial TextNode
        OSL_ENSURE( (*ppMergeBox)->GetSttIdx()+2 <
                (*ppMergeBox)->GetSttNd()->EndOfSectionIndex(),
                    "empty box" );
        SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 );
        rDoc.GetNodes().Delete( aIdx );
    }

    // set width of the box
    (*ppMergeBox)->GetFrameFormat()->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nWidth, 0 ));
    if( pUndo )
        pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() );
}

static bool lcl_CheckCol(FndBox_ const&, bool* pPara);

static bool lcl_CheckRow( const FndLine_& rFndLine, bool* pPara )
{
    for (auto const& it : rFndLine.GetBoxes())
    {
        lcl_CheckCol(*it, pPara);
    }
    return *pPara;
}

static bool lcl_CheckCol( FndBox_ const& rFndBox, bool* pPara )
{
    if (!rFndBox.GetBox()->GetSttNd())
    {
        if (rFndBox.GetLines().size() !=
            rFndBox.GetBox()->GetTabLines().size())
        {
            *pPara = false;
        }
        else
        {
            for (auto const& rpFndLine : rFndBox.GetLines())
            {
                lcl_CheckRow( *rpFndLine, pPara );
            }
        }
    }
    // is box protected ??
    else if (rFndBox.GetBox()->GetFrameFormat()->GetProtect().IsContentProtected())
        *pPara = false;
    return *pPara;
}

TableMergeErr CheckMergeSel( const SwPaM& rPam )
{
    SwSelBoxes aBoxes;
//JP 24.09.96:  Merge with repeating TableHeadLines does not work properly.
//              Why not use point 0,0? Then it is assured the first
//              headline is contained.

    Point aPt;
    const SwContentNode* pCntNd = rPam.GetPointContentNode();
    std::pair<Point, bool> tmp(aPt, true);
    const SwLayoutFrame *const pStart = pCntNd->getLayoutFrame(
            pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
            nullptr, &tmp)->GetUpper();
    pCntNd = rPam.GetMarkContentNode();
    const SwLayoutFrame *const pEnd = pCntNd->getLayoutFrame(
            pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
            nullptr, &tmp)->GetUpper();
    GetTableSel( pStart, pEnd, aBoxes, nullptr );
    return CheckMergeSel( aBoxes );
}

TableMergeErr CheckMergeSel( const SwSelBoxes& rBoxes )
{
    TableMergeErr eRet = TableMergeErr::NoSelection;
    if( !rBoxes.empty() )
    {
        eRet = TableMergeErr::Ok;

        FndBox_ aFndBox( nullptr, nullptr );
        FndPara aPara( rBoxes, &aFndBox );
        const SwTableNode* pTableNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode();
        ForEach_FndLineCopyCol( const_cast<SwTableLines&>(pTableNd->GetTable().GetTabLines()), &aPara );
        if( !aFndBox.GetLines().empty() )
        {
            bool bMergeSelOk = true;
            FndBox_* pFndBox = &aFndBox;
            FndLine_* pFndLine = nullptr;
            while( pFndBox && 1 == pFndBox->GetLines().size() )
            {
                pFndLine = pFndBox->GetLines().front().get();
                if( 1 == pFndLine->GetBoxes().size() )
                    pFndBox = pFndLine->GetBoxes().front().get();
                else
                    pFndBox = nullptr;
            }
            if( pFndBox )
            {
                for (auto const& it : pFndBox->GetLines())
                {
                    lcl_CheckRow(*it, &bMergeSelOk);
                }
            }
            else if( pFndLine )
            {
                for (auto const& it : pFndLine->GetBoxes())
                {
                    lcl_CheckCol(*it, &bMergeSelOk);
                }
            }
            if( !bMergeSelOk )
                eRet = TableMergeErr::TooComplex;
        }
        else
            eRet = TableMergeErr::NoSelection;
    }
    return eRet;
}

static SwTwips lcl_CalcWish( const SwLayoutFrame *pCell, tools::Long nWish,
                                                const tools::Long nAct )
{
    const SwLayoutFrame *pTmp = pCell;
    if ( !nWish )
        nWish = 1;

    const bool bRTL = pCell->IsRightToLeft();
    SwTwips nRet = bRTL ?
        nAct - pCell->getFrameArea().Width() :
        0;

    while ( pTmp )
    {
        while ( pTmp->GetPrev() )
        {
            pTmp = static_cast<const SwLayoutFrame*>(pTmp->GetPrev());
            sal_Int64 nTmp = pTmp->GetFormat()->GetFrameSize().GetWidth();
            // multiply in 64-bit to avoid overflow here!
            nRet += ( bRTL ? -1 : 1 ) * nTmp * nAct / nWish;
        }
        pTmp = pTmp->GetUpper()->GetUpper();
        if ( pTmp && !pTmp->IsCellFrame() )
            pTmp = nullptr;
    }
    return nRet;
}

static void lcl_FindStartEndRow( const SwLayoutFrame *&rpStart,
                             const SwLayoutFrame *&rpEnd,
                             const bool bChkProtected )
{
    // Put Start at beginning of a row.
    // Put End at the end of its row.
    rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetUpper()->Lower());
    while ( rpEnd->GetNext() )
        rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetNext());

    std::deque<const SwLayoutFrame *> aSttArr, aEndArr;
    const SwLayoutFrame *pTmp;
    for( pTmp = rpStart; (SwFrameType::Cell|SwFrameType::Row) & pTmp->GetType();
                pTmp = pTmp->GetUpper() )
    {
        aSttArr.push_front( pTmp );
    }
    for( pTmp = rpEnd; (SwFrameType::Cell|SwFrameType::Row) & pTmp->GetType();
                pTmp = pTmp->GetUpper() )
    {
        aEndArr.push_front( pTmp );
    }

    for( std::deque<const SwLayoutFrame *>::size_type n = 0; n < aEndArr.size() && n < aSttArr.size(); ++n )
        if( aSttArr[ n ] != aEndArr[ n ] )
        {
            // first unequal line or box - all odds are
            if( n & 1 )                 // 1, 3, 5, ... are boxes
            {
                rpStart = aSttArr[ n ];
                rpEnd = aEndArr[ n ];
            }
            else                                // 0, 2, 4, ... are lines
            {
                // check if start & end line are the first & last Line of the
                // box. If not return these cells.
                // Else the whole line with all Boxes has to be deleted.
                rpStart = aSttArr[ n+1 ];
                rpEnd = aEndArr[ n+1 ];
                if( n )
                {
                    const SwCellFrame* pCellFrame = static_cast<const SwCellFrame*>(aSttArr[ n-1 ]);
                    const SwTableLines& rLns = pCellFrame->
                                                GetTabBox()->GetTabLines();
                    if( rLns[ 0 ] == static_cast<const SwRowFrame*>(aSttArr[ n ])->GetTabLine() &&
                        rLns[ rLns.size() - 1 ] ==
                                    static_cast<const SwRowFrame*>(aEndArr[ n ])->GetTabLine() )
                    {
                        rpStart = rpEnd = pCellFrame;
                        while ( rpStart->GetPrev() )
                            rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetPrev());
                        while ( rpEnd->GetNext() )
                            rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetNext());
                    }
                }
            }
            break;
        }

    if( !bChkProtected )    // protected cell ?
        return;

    // Beginning and end should not be in protected cells
    while ( rpStart->GetFormat()->GetProtect().IsContentProtected() )
        rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetNext());
    while ( rpEnd->GetFormat()->GetProtect().IsContentProtected() )
        rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetPrev());
}

static void lcl_FindStartEndCol( const SwLayoutFrame *&rpStart,
                             const SwLayoutFrame *&rpEnd,
                             const bool bChkProtected )
{
    // Beginning and end vertical till the border of the table;
    // Consider the whole table, including master and follows.
    // In order to start we need the mother-tableFrame
    if( !rpStart )
        return;
    const SwTabFrame *pOrg = rpStart->FindTabFrame();
    const SwTabFrame *pTab = pOrg;

    SwRectFnSet aRectFnSet(pTab);

    bool bRTL = pTab->IsRightToLeft();
    const tools::Long nTmpWish = pOrg->GetFormat()->GetFrameSize().GetWidth();
    const tools::Long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1;

    while ( pTab->IsFollow() )
    {
        const SwFrame *pTmp = pTab->FindPrev();
        OSL_ENSURE( pTmp->IsTabFrame(), "Predecessor of Follow is not Master." );
        pTab = static_cast<const SwTabFrame*>(pTmp);
    }

    SwTwips nSX  = 0;
    SwTwips nSX2 = 0;

    if ( pTab->GetTable()->IsNewModel() )
    {
        nSX  = aRectFnSet.GetLeft(rpStart->getFrameArea());
        nSX2 = aRectFnSet.GetRight(rpStart->getFrameArea());
    }
    else
    {
        const SwTwips nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
        nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + aRectFnSet.GetPrtLeft(*pTab);
        nSX2 = nSX + (rpStart->GetFormat()->GetFrameSize().GetWidth() * nPrtWidth / nWish);
    }

    const SwLayoutFrame *pTmp = pTab->FirstCell();

    while ( pTmp &&
            (!pTmp->IsCellFrame() ||
             ( ( ! bRTL && aRectFnSet.GetLeft(pTmp->getFrameArea()) < nSX &&
                           aRectFnSet.GetRight(pTmp->getFrameArea())< nSX2 ) ||
               (   bRTL && aRectFnSet.GetLeft(pTmp->getFrameArea()) > nSX &&
                           aRectFnSet.GetRight(pTmp->getFrameArea())> nSX2 ) ) ) )
        pTmp = pTmp->GetNextLayoutLeaf();

    if ( pTmp )
        rpStart = pTmp;

    pTab = pOrg;

    const SwTabFrame* pLastValidTab = pTab;
    while ( pTab->GetFollow() )
    {

        // Check if pTab->GetFollow() is a valid follow table:
        // Only follow tables with at least on non-FollowFlowLine
        // should be considered.

        if ( pTab->HasFollowFlowLine() )
        {
            pTab = pTab->GetFollow();
            const SwFrame* pTmpRow = pTab->GetFirstNonHeadlineRow();
            if ( pTmpRow && pTmpRow->GetNext() )
                pLastValidTab = pTab;
        }
        else
            pLastValidTab = pTab = pTab->GetFollow();
    }
    pTab = pLastValidTab;

    SwTwips nEX = 0;

    if ( pTab->GetTable()->IsNewModel() )
    {
        nEX = aRectFnSet.GetLeft(rpEnd->getFrameArea());
    }
    else
    {
        const SwTwips nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
        nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + aRectFnSet.GetPrtLeft(*pTab);
    }

    SwFrame const*const pLastContent = pTab->FindLastContentOrTable();
    rpEnd = pLastContent ? pLastContent->GetUpper() : nullptr;
    // --> Made code robust. If pTab does not have a lower,
    // we would crash here.
    if ( !pLastContent ) return;

    while( !rpEnd->IsCellFrame() )
        rpEnd = rpEnd->GetUpper();

    while ( (   bRTL && aRectFnSet.GetLeft(rpEnd->getFrameArea()) < nEX ) ||
            ( ! bRTL && aRectFnSet.GetLeft(rpEnd->getFrameArea()) > nEX ) )
    {
        const SwLayoutFrame* pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
        if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) )
            break;
        rpEnd = pTmpLeaf;
    }

    if( !bChkProtected )    // check for protected cell ?
        return;

    // Beginning and end should not be in protected cells.
    // If necessary we should search backwards again
    while (rpStart && rpStart->GetFormat()->GetProtect().IsContentProtected())
    {
        const SwLayoutFrame *pTmpLeaf = rpStart->GetNextLayoutLeaf();
        while ( pTmpLeaf && aRectFnSet.GetLeft(pTmpLeaf->getFrameArea()) > nEX ) // first skip line
            pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
        while ( pTmpLeaf && aRectFnSet.GetLeft(pTmpLeaf->getFrameArea()) < nSX &&
                            aRectFnSet.GetRight(pTmpLeaf->getFrameArea())< nSX2 )
            pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
        const SwTabFrame *pTmpTab = rpStart->FindTabFrame();
        if ( !pTmpTab->IsAnLower( pTmpLeaf ) )
        {
            pTmpTab = pTmpTab->GetFollow();
            rpStart = pTmpTab->FirstCell();
            while ( rpStart &&
                    aRectFnSet.GetLeft(rpStart->getFrameArea()) < nSX &&
                    aRectFnSet.GetRight(rpStart->getFrameArea())< nSX2 )
                rpStart = rpStart->GetNextLayoutLeaf();
        }
        else
            rpStart = pTmpLeaf;
    }
    while (rpEnd && rpEnd->GetFormat()->GetProtect().IsContentProtected())
    {
        const SwLayoutFrame *pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
        while ( pTmpLeaf && aRectFnSet.GetLeft(pTmpLeaf->getFrameArea()) < nEX ) // skip the line for now
            pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
        while ( pTmpLeaf && aRectFnSet.GetLeft(pTmpLeaf->getFrameArea()) > nEX )
            pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
        const SwTabFrame *pTmpTab = rpEnd->FindTabFrame();
        if ( !pTmpTab->IsAnLower( pTmpLeaf ) )
        {
            pTmpTab = static_cast<const SwTabFrame*>(pTmpTab->FindPrev());
            OSL_ENSURE( pTmpTab->IsTabFrame(), "Predecessor of Follow not Master.");
            rpEnd = pTmpTab->FindLastContentOrTable()->GetUpper();
            while( !rpEnd->IsCellFrame() )
                rpEnd = rpEnd->GetUpper();
            while ( aRectFnSet.GetLeft(rpEnd->getFrameArea()) > nEX )
                rpEnd = rpEnd->GetPrevLayoutLeaf();
        }
        else
            rpEnd = pTmpLeaf;
    }
}

void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrame *pStart,
                    const SwLayoutFrame *pEnd, const SwTableSearchType eSearchType )
{
    while ( pStart && !pStart->IsCellFrame() )
        pStart = pStart->GetUpper();
    while ( pEnd && !pEnd->IsCellFrame() )
        pEnd = pEnd->GetUpper();

    if ( !pStart || !pEnd )
    {
        OSL_FAIL( "MakeSelUnions with pStart or pEnd not in CellFrame" );
        return;
    }

    const SwTabFrame *pTable = pStart->FindTabFrame();
    const SwTabFrame *pEndTable = pEnd->FindTabFrame();
    if( !pTable || !pEndTable )
        return;
    bool bExchange = false;

    if ( pTable != pEndTable )
    {
        if ( !pTable->IsAnFollow( pEndTable ) )
        {
            OSL_ENSURE( pEndTable->IsAnFollow( pTable ), "Tabchain in knots." );
            bExchange = true;
        }
    }
    else
    {
        SwRectFnSet aRectFnSet(pTable);
        tools::Long nSttTop = aRectFnSet.GetTop(pStart->getFrameArea());
        tools::Long nEndTop = aRectFnSet.GetTop(pEnd->getFrameArea());
        if( nSttTop == nEndTop )
        {
            if( aRectFnSet.GetLeft(pStart->getFrameArea()) >
                aRectFnSet.GetLeft(pEnd->getFrameArea()) )
                bExchange = true;
        }
        else if( aRectFnSet.IsVert() == ( nSttTop < nEndTop ) )
            bExchange = true;
    }
    if ( bExchange )
    {
        const SwLayoutFrame *pTmp = pStart;
        pStart = pEnd;
        pEnd = pTmp;
        // do no resort pTable and pEndTable, set new below
        // MA: 28. Dec. 93 Bug: 5190
    }

    // Beginning and end now nicely sorted, if required we
    // should move them
    if( SwTableSearchType::Row == ((~SwTableSearchType::Protect ) & eSearchType ) )
        ::lcl_FindStartEndRow( pStart, pEnd, bool(SwTableSearchType::Protect & eSearchType) );
    else if( SwTableSearchType::Col == ((~SwTableSearchType::Protect ) & eSearchType ) )
        ::lcl_FindStartEndCol( pStart, pEnd, bool(SwTableSearchType::Protect & eSearchType) );

    if ( !pEnd || !pStart ) return// Made code robust.

    // retrieve again, as they have been moved
    pTable = pStart->FindTabFrame();
    pEndTable = pEnd->FindTabFrame();

    const tools::Long nStSz = pStart->GetFormat()->GetFrameSize().GetWidth();
    const tools::Long nEdSz = pEnd->GetFormat()->GetFrameSize().GetWidth();
    const tools::Long nWish = std::max( tools::Long(1), pTable->GetFormat()->GetFrameSize().GetWidth() );
    while ( pTable )
    {
        SwRectFnSet aRectFnSet(pTable);
        const tools::Long nOfst = aRectFnSet.GetPrtLeft(*pTable);
        const tools::Long nPrtWidth = aRectFnSet.GetWidth(pTable->getFramePrintArea());
        tools::Long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst;
        tools::Long nEd1 = ::lcl_CalcWish( pEnd,   nWish, nPrtWidth ) + nOfst;

        if ( nSt1 <= nEd1 )
            nEd1 += static_cast<tools::Long>((nEdSz * nPrtWidth) / nWish) - 1;
        else
            nSt1 += static_cast<tools::Long>((nStSz * nPrtWidth) / nWish) - 1;

        tools::Long nSt2;
        tools::Long nEd2;
        if( pTable->IsAnLower( pStart ) )
            nSt2 = aRectFnSet.GetTop(pStart->getFrameArea());
        else
            nSt2 = aRectFnSet.GetTop(pTable->getFrameArea());
        if( pTable->IsAnLower( pEnd ) )
            nEd2 = aRectFnSet.GetBottom(pEnd->getFrameArea());
        else
            nEd2 = aRectFnSet.GetBottom(pTable->getFrameArea());
        Point aSt, aEd;
        if( nSt1 > nEd1 )
            std::swap( nSt1, nEd1 );
        if( nSt2 > nEd2 )
            std::swap( nSt2, nEd2 );
        if( aRectFnSet.IsVert() )
        {
            aSt = Point( nSt2, nSt1 );
            aEd = Point( nEd2, nEd1 );
        }
        else
        {
            aSt = Point( nSt1, nSt2 );
            aEd = Point( nEd1, nEd2 );
        }

        const Point aDiff( aEd - aSt );
        SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) );
        aUnion.Justify();

        if( !(SwTableSearchType::NoUnionCorrect & eSearchType ))
        {
            // Unfortunately the union contains rounding errors now, therefore
            // erroneous results could occur during split/merge.
            // To prevent these we will determine the first and last row
            // within the union and use their values for a new union
            const SwLayoutFrame* pRow = nullptr;
            if (pTable->IsFollow())
            {
                SwRowFrame* pRowFrame = pTable->GetFirstNonHeadlineRow();
                //tdf#159027: follow returns a frame without height if
                // merged cells are involved
                if (pRowFrame->getFrameArea().IsEmpty())
                    pRowFrame = static_cast<SwRowFrame*>(pRowFrame->GetNext());
                pRow = pRowFrame;
            }
            else
                pRow = static_cast<const SwLayoutFrame*>(pTable->Lower());

            while ( pRow && !pRow->getFrameArea().Overlaps( aUnion ) )
                pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());

            // #i31976#
            // A follow flow row may contain empty cells. These are not
            // considered by FirstCell(). Therefore we have to find
            // the first cell manually:
            const SwFrame* pTmpCell = nullptr;
            if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() )
            {
                const SwFrame* pTmpRow = pRow;
                while ( pTmpRow && pTmpRow->IsRowFrame() )
                {
                    pTmpCell = static_cast<const SwRowFrame*>(pTmpRow)->Lower();
                    pTmpRow  = static_cast<const SwCellFrame*>(pTmpCell)->Lower();
                }
                OSL_ENSURE( !pTmpCell || pTmpCell->IsCellFrame(), "Lower of rowframe != cellframe?!" );
            }

            const SwLayoutFrame* pFirst = pTmpCell ?
                                        static_cast<const SwLayoutFrame*>(pTmpCell) :
                                        pRow ?
                                        pRow->FirstCell() :
                                        nullptr;

            while ( pFirst && !::IsFrameInTableSel( aUnion, pFirst ) )
            {
                if ( pFirst->GetNext() )
                {
                    pFirst = static_cast<const SwLayoutFrame*>(pFirst->GetNext());
                    const SwFrame* pLower = pFirst->Lower();
                    if ( pLower && pLower->IsRowFrame() )
                        pFirst = pFirst->FirstCell();
                }
                else
                    pFirst = ::lcl_FindNextCellFrame( pFirst );
            }
            const SwLayoutFrame* pLast = nullptr;
            SwFrame const*const pLastContent = pTable->FindLastContentOrTable();
            if ( pLastContent )
                pLast = ::lcl_FindCellFrame( pLastContent->GetUpper() );

            while ( pLast && !::IsFrameInTableSel( aUnion, pLast ) )
                pLast = ::lcl_FindCellFrame( pLast->GetPrevLayoutLeaf() );

            if ( pFirst && pLast ) //Robust
            {
                aUnion = pFirst->getFrameArea();
                aUnion.Union( pLast->getFrameArea() );
            }
            else
                aUnion.Width( 0 );
        }

        if( aRectFnSet.GetWidth(aUnion) )
        {
            rUnions.emplace_back(aUnion, const_cast<SwTabFrame*>(pTable));
        }

        pTable = pTable->GetFollow();
        if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) )
            pTable = nullptr;
    }
}

bool CheckSplitCells( const SwCursorShell& rShell, sal_uInt16 nDiv,
                        const SwTableSearchType eSearchType )
{
    if( !rShell.IsTableMode() )
        rShell.GetCursor();

    return CheckSplitCells( *rShell.getShellCursor(false), nDiv, eSearchType );
}

bool CheckSplitCells( const SwCursor& rCursor, sal_uInt16 nDiv,
                        const SwTableSearchType eSearchType )
{
    if( 1 >= nDiv )
        return false;

    sal_uInt16 nMinValue = nDiv * MINLAY;

    // Get start and end cell
    Point aPtPos, aMkPos;
    const SwShellCursor* pShCursor = dynamic_cast<const SwShellCursor*>(&rCursor);
    if( pShCursor )
    {
        aPtPos = pShCursor->GetPtPos();
        aMkPos = pShCursor->GetMkPos();
    }

    const SwContentNode* pCntNd = rCursor.GetPointContentNode();
    std::pair<Point, bool> tmp(aPtPos, true);
    const SwLayoutFrame *const pStart = pCntNd->getLayoutFrame(
            pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
            nullptr, &tmp)->GetUpper();
    pCntNd = rCursor.GetMarkContentNode();
    tmp.first = aMkPos;
    const SwLayoutFrame *const pEnd = pCntNd->getLayoutFrame(
            pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
            nullptr, &tmp)->GetUpper();

    SwRectFnSet aRectFnSet(pStart->GetUpper());

    // First, compute tables and rectangles
    SwSelUnions aUnions;

    ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );

    // now search boxes for each entry and emit
    for ( const auto& rSelUnion : aUnions )
    {
        const SwTabFrame *pTable = rSelUnion.GetTable();

        // Skip any repeated headlines in the follow:
        const SwLayoutFrame* pRow = pTable->IsFollow() ?
                                  pTable->GetFirstNonHeadlineRow() :
                                  static_cast<const SwLayoutFrame*>(pTable->Lower());

        while ( pRow )
        {
            if ( pRow->getFrameArea().Overlaps( rSelUnion.GetUnion() ) )
            {
                const SwLayoutFrame *pCell = pRow->FirstCell();

                while ( pCell && pRow->IsAnLower( pCell ) )
                {
                    OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" );
                    if( ::IsFrameInTableSel( rSelUnion.GetUnion(), pCell ) )
                    {
                        if( aRectFnSet.GetWidth(pCell->getFrameArea()) < nMinValue )
                            return false;
                    }

                    if ( pCell->GetNext() )
                    {
                        pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
                        const SwFrame* pLower = pCell->Lower();
                        if ( pLower && pLower->IsRowFrame() )
                            pCell = pCell->FirstCell();
                    }
                    else
                        pCell = ::lcl_FindNextCellFrame( pCell );
                }
            }
            pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
        }
    }
    return true;
}

// These Classes copy the current table selections (rBoxes),
// into a new structure, retaining the table structure
// new: SS for targeted erasing/restoring of the layout

static void lcl_InsertRow( SwTableLine const &rLine, SwLayoutFrame *pUpper, SwFrame *pSibling )
{
    SwRowFrame *pRow = new SwRowFrame( rLine, pUpper );
    if ( pUpper->IsTabFrame() && static_cast<SwTabFrame*>(pUpper)->IsFollow() )
    {
        SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pUpper);
        pTabFrame->FindMaster()->InvalidatePos(); //can absorb the line

        if ( pSibling && pTabFrame->IsInHeadline( *pSibling ) )
        {
            // Skip any repeated headlines in the follow:
            pSibling = pTabFrame->GetFirstNonHeadlineRow();
        }
    }
    pRow->Paste( pUpper, pSibling );
    pRow->RegistFlys();
}

static void FndBoxCopyCol( SwTableBox* pBox, FndPara* pFndPara )
{
    std::unique_ptr<FndBox_> pFndBox(new FndBox_( pBox, pFndPara->pFndLine ));
    if( !pBox->GetTabLines().empty() )
    {
        FndPara aPara( *pFndPara, pFndBox.get() );
        ForEach_FndLineCopyCol( pFndBox->GetBox()->GetTabLines(), &aPara );
        if( pFndBox->GetLines().empty() )
        {
            return;
        }
    }
    else
    {
        if( pFndPara->rBoxes.find( pBox ) == pFndPara->rBoxes.end())
        {
            return;
        }
    }
    pFndPara->pFndLine->GetBoxes().push_back( std::move(pFndBox) );
}

static void FndLineCopyCol( SwTableLine* pLine, FndPara* pFndPara )
{
    std::unique_ptr<FndLine_> pFndLine(new FndLine_(pLine, pFndPara->pFndBox));
    FndPara aPara(*pFndPara, pFndLine.get());
    forauto& rpBox : pFndLine->GetLine()->GetTabBoxes() )
        FndBoxCopyCol(rpBox, &aPara );
    if( !pFndLine->GetBoxes().empty() )
    {
        pFndPara->pFndBox->GetLines().push_back( std::move(pFndLine) );
    }
}

void ForEach_FndLineCopyCol(SwTableLines& rLines, FndPara* pFndPara )
{
    for( SwTableLines::iterator it = rLines.begin(); it != rLines.end(); ++it )
        FndLineCopyCol( *it, pFndPara );
}

void FndBox_::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable )
{
    // Set pointers to lines before and after the area to process.
    // If the first/last lines are contained in the area, then the pointers
    // are 0. We first search for the positions of the first/last affected
    // lines in array of the SwTable. In order to use 0 for 'no line'
    // we adjust the positions by 1.

    sal_uInt16 nStPos = USHRT_MAX;
    sal_uInt16 nEndPos= 0;

    for (size_t i = 0; i < rBoxes.size(); ++i)
    {
        SwTableLine *pLine = rBoxes[i]->GetUpper();
        while ( pLine->GetUpper() )
            pLine = pLine->GetUpper()->GetUpper();
        const sal_uInt16 nPos = rTable.GetTabLines().GetPos(
                    const_cast<const SwTableLine*&>(pLine) ) + 1;

        OSL_ENSURE( nPos != USHRT_MAX, "TableLine not found." );

        if( nStPos > nPos )
            nStPos = nPos;

        if( nEndPos < nPos )
            nEndPos = nPos;
    }
    if (USHRT_MAX != nStPos && nStPos > 1)
        m_pLineBefore = rTable.GetTabLines()[nStPos - 2];
    if ( nEndPos < rTable.GetTabLines().size() )
        m_pLineBehind = rTable.GetTabLines()[nEndPos];
}

void FndBox_::SetTableLines( const SwTable &rTable )
{
    // Set pointers to lines before and after the area to process.
    // If the first/last lines are contained in the area, then the pointers
    // are 0. The positions of the first/last affected lines in the array
    // of the SwTable are in FndBox. In order to use 0 for 'no line'
    // we adjust the positions by 1.

    if( GetLines().empty() )
        return;

    SwTableLine* pTmpLine = GetLines().front()->GetLine();
    sal_uInt16 nPos = rTable.GetTabLines().GetPos( pTmpLine );
    OSL_ENSURE( USHRT_MAX != nPos, "Line is not in table" );
    if( nPos )
        m_pLineBefore = rTable.GetTabLines()[ nPos - 1 ];

    pTmpLine = GetLines().back()->GetLine();
    nPos = rTable.GetTabLines().GetPos( pTmpLine );
    OSL_ENSURE( USHRT_MAX != nPos, "Line is not in the table" );
    if( ++nPos < rTable.GetTabLines().size() )
        m_pLineBehind = rTable.GetTabLines()[nPos];
}

inline void UnsetFollow( SwFlowFrame *pTab )
{
    pTab->m_pPrecede = nullptr;
}

void FndBox_::DelFrames( SwTable &rTable )
{
    // All lines between pLineBefore and pLineBehind should be cut
    // from the layout and erased.
    // If this creates empty Follows we should destroy these.
    // If a master is destroyed, the follow should become master.
    // Always a TabFrame should remain.

    sal_uInt16 nStPos = 0;
    sal_uInt16 nEndPos= rTable.GetTabLines().size() - 1;
    if( rTable.IsNewModel() && m_pLineBefore )
        rTable.CheckRowSpan( m_pLineBefore, true );
    if ( m_pLineBefore )
    {
        nStPos = rTable.GetTabLines().GetPos(
                        const_cast<const SwTableLine*&>(m_pLineBefore) );
        OSL_ENSURE( nStPos != USHRT_MAX, "The fox stole the line!" );
        ++nStPos;
    }
    if( rTable.IsNewModel() && m_pLineBehind )
        rTable.CheckRowSpan( m_pLineBehind, false );
    if ( m_pLineBehind )
    {
        nEndPos = rTable.GetTabLines().GetPos(
                        const_cast<const SwTableLine*&>(m_pLineBehind) );
        OSL_ENSURE( nEndPos != USHRT_MAX, "The fox stole the line!" );
        if (nEndPos != 0)
            --nEndPos;
    }

    for ( sal_uInt16 i = nStPos; i <= nEndPos; ++i)
    {
        SwFrameFormat *pFormat = rTable.GetTabLines()[i]->GetFrameFormat();
        SwIterator<SwRowFrame,SwFormat> aIter( *pFormat );
        for ( SwRowFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
        {
                if ( pFrame->GetTabLine() == rTable.GetTabLines()[i] )
                {
                    bool bDel = true;
                    SwTabFrame *pUp = !pFrame->GetPrev() && !pFrame->GetNext() ?
                                            static_cast<SwTabFrame*>(pFrame->GetUpper()) : nullptr;
                    if ( !pUp )
                    {
                        const sal_uInt16 nRepeat =
                                static_cast<SwTabFrame*>(pFrame->GetUpper())->GetTable()->GetRowsToRepeat();
                        if ( nRepeat > 0 &&
                             static_cast<SwTabFrame*>(pFrame->GetUpper())->IsFollow() )
                        {
                            if ( !pFrame->GetNext() )
                            {
                                SwRowFrame* pFirstNonHeadline =
                                    static_cast<SwTabFrame*>(pFrame->GetUpper())->GetFirstNonHeadlineRow();
                                if ( pFirstNonHeadline == pFrame )
                                {
                                    pUp = static_cast<SwTabFrame*>(pFrame->GetUpper());
                                }
                            }
                        }
                    }
                    if ( pUp )
                    {
                        SwTabFrame *pFollow = pUp->GetFollow();
                        SwTabFrame *pPrev   = pUp->IsFollow() ? pUp : nullptr;
                        if ( pPrev )
                        {
                            SwFrame *pTmp = pPrev->FindPrev();
                            OSL_ENSURE( pTmp->IsTabFrame(),
                                    "Predecessor of Follow is no Master.");
                            pPrev = static_cast<SwTabFrame*>(pTmp);
                        }
                        if ( pPrev )
                        {
                            pPrev->SetFollow( pFollow );
                            // #i60340# Do not transfer the
                            // flag from pUp to pPrev. pUp may still have the
                            // flag set although there is not more follow flow
                            // line associated with pUp.
                            pPrev->SetFollowFlowLine( false );
                        }
                        else if ( pFollow )
                            ::UnsetFollow( pFollow );

                        // A TableFrame should always remain!
                        if ( pPrev || pFollow )
                        {
                            // OD 26.08.2003 #i18103# - if table is in a section,
                            // lock the section, to avoid its delete.
                            {
                                SwSectionFrame* pSctFrame = pUp->FindSctFrame();
                                bool bOldSectLock = false;
                                if ( pSctFrame )
                                {
                                    bOldSectLock = pSctFrame->IsColLocked();
                                    pSctFrame->ColLock();
                                }
                                pUp->Cut();
                                if ( pSctFrame && !bOldSectLock )
                                {
                                    pSctFrame->ColUnlock();
                                }
                            }
                            SwFrame::DestroyFrame(pUp);
                            bDel = false// Row goes to /dev/null.
                        }
                    }
                    if ( bDel )
                    {
                        SwFrame* pTabFrame = pFrame->GetUpper();
                        if ( pTabFrame->IsTabFrame() &&
                            !pFrame->GetNext() &&
                             static_cast<SwTabFrame*>(pTabFrame)->GetFollow() )
                        {
                            // We do not delete the follow flow line,
                            // this will be done automatically in the
                            // next turn.
                            static_cast<SwTabFrame*>(pTabFrame)->SetFollowFlowLine( false );
                        }
                        pFrame->Cut();
                        SwFrame::DestroyFrame(pFrame);
                    }
                }
        }
    }
}

static bool lcl_IsLineOfTableFrame( const SwTabFrame& rTable, const SwFrame& rChk )
{
    const SwTabFrame* pTableFrame = rChk.FindTabFrame();
    if( pTableFrame->IsFollow() )
        pTableFrame = pTableFrame->FindMaster( true );
    return &rTable == pTableFrame;
}

static void lcl_UpdateRepeatedHeadlines( SwTabFrame& rTabFrame, bool bCalcLowers )
{
    OSL_ENSURE( rTabFrame.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" );

    // Delete remaining headlines:
    SwRowFrame* pLower = nullptr;
    while ( nullptr != ( pLower = static_cast<SwRowFrame*>(rTabFrame.Lower()) ) && pLower->IsRepeatedHeadline() )
    {
        pLower->Cut();
        SwFrame::DestroyFrame(pLower);
    }

    // Insert fresh set of headlines:
    pLower = static_cast<SwRowFrame*>(rTabFrame.Lower());
    SwTable& rTable = *rTabFrame.GetTable();
    const sal_uInt16 nRepeat = rTable.GetRowsToRepeat();
    for ( sal_uInt16 nIdx = 0; nIdx < nRepeat; ++nIdx )
    {
        SwRowFrame* pHeadline = new SwRowFrame( *rTable.GetTabLines()[ nIdx ], &rTabFrame );
        pHeadline->SetRepeatedHeadline( true );
        pHeadline->Paste( &rTabFrame, pLower );
        pHeadline->RegistFlys();
    }

    if ( bCalcLowers )
        rTabFrame.SetCalcLowers();
}

void FndBox_::MakeFrames( SwTable &rTable )
{
    // All lines between pLineBefore and pLineBehind should be re-generated in layout.
    // And this for all instances of a table (for example in header/footer).
    sal_uInt16 nStPos = 0;
    sal_uInt16 nEndPos= rTable.GetTabLines().size() - 1;
    SwRootFrame* pLayout =
        rTable.GetFrameFormat()->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout();
    bool bHideChanges = pLayout && pLayout->IsHideRedlines();

    if ( m_pLineBefore )
    {
        nStPos = rTable.GetTabLines().GetPos(
                        const_cast<const SwTableLine*&>(m_pLineBefore) );
        OSL_ENSURE( nStPos != USHRT_MAX, "Fox stole the line!" );
        ++nStPos;

    }
    if ( m_pLineBehind )
    {
        nEndPos = rTable.GetTabLines().GetPos(
                        const_cast<const SwTableLine*&>(m_pLineBehind) );
        OSL_ENSURE( nEndPos != USHRT_MAX, "Fox stole the line!" );
        --nEndPos;
    }
    // now big insert operation for all tables.
    SwIterator<SwTabFrame,SwFormat> aTabIter( *rTable.GetFrameFormat() );
    for ( SwTabFrame *pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
    {
        if ( !pTable->IsFollow() )
        {
            SwRowFrame  *pSibling = nullptr;
            SwFrame  *pUpperFrame  = nullptr;
            int i;
            for ( i = rTable.GetTabLines().size()-1;
                    i >= 0 && !pSibling; --i )
            {
                SwTableLine *pLine = m_pLineBehind ? m_pLineBehind :
                                                    rTable.GetTabLines()[o3tl::narrowing<sal_uInt16>(i)];
                SwIterator<SwRowFrame,SwFormat> aIter( *pLine->GetFrameFormat() );
                pSibling = aIter.First();
                while ( pSibling && (
                            pSibling->GetTabLine() != pLine ||
                            !lcl_IsLineOfTableFrame( *pTable, *pSibling ) ||
                            pSibling->IsRepeatedHeadline() ||
                            // #i53647# If !pLineBehind,
                            // IsInSplitTableRow() should be checked.
                            ( m_pLineBehind && pSibling->IsInFollowFlowRow() ) ||
                            (!m_pLineBehind && pSibling->IsInSplitTableRow() ) ) )
                {
                    pSibling = aIter.Next();
                }
            }
            if ( pSibling )
            {
                pUpperFrame = pSibling->GetUpper();
                if ( !m_pLineBehind )
                    pSibling = nullptr;
            }
            else
// ???? or is this the last Follow of the table ????
                pUpperFrame = pTable;

            SwRedlineTable::size_type nRedlinePos = 0;
            for ( sal_uInt16 j = nStPos; j <= nEndPos; ++j )
            {
                SwTableLine * pLine = rTable.GetTabLines()[j];
                if ( ( !bHideChanges || !pLine->IsDeleted(nRedlinePos) ) &&
                            // tdf#159026 fix Undo crash with floating tables
                            pUpperFrame->GetUpper() )
                    ::lcl_InsertRow( *pLine,
                                static_cast<SwLayoutFrame*>(pUpperFrame), pSibling );
            }
            if ( pUpperFrame->IsTabFrame() )
                static_cast<SwTabFrame*>(pUpperFrame)->SetCalcLowers();
        }
        else if ( rTable.GetRowsToRepeat() > 0 )
        {
            // Insert new headlines:
            lcl_UpdateRepeatedHeadlines( *pTable, true );
        }
    }
}

void FndBox_::MakeNewFrames( SwTable &rTable, const sal_uInt16 nNumber,
                                            const bool bBehind )
{
    // Create Frames for newly inserted lines
    // bBehind == true:  before  pLineBehind
    //         == false: after   pLineBefore
    const sal_uInt16 nBfPos = m_pLineBefore ?
        rTable.GetTabLines().GetPos( const_cast<const SwTableLine*&>(m_pLineBefore) ) :
        USHRT_MAX;
    const sal_uInt16 nBhPos = m_pLineBehind ?
        rTable.GetTabLines().GetPos( const_cast<const SwTableLine*&>(m_pLineBehind) ) :
        USHRT_MAX;

    //nNumber: how often did we insert
    //nCnt:    how many were inserted nNumber times

    const sal_uInt16 nCnt =
        ((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().size()) -
         (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1);

    // search the Master-TabFrame
    SwIterator<SwTabFrame,SwFormat> aTabIter( *rTable.GetFrameFormat() );
    SwTabFrame *pTable;
    for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
    {
        if( !pTable->IsFollow() )
        {
            SwRowFrame* pSibling = nullptr;
            SwLayoutFrame *pUpperFrame   = nullptr;
            if ( bBehind )
            {
                if ( m_pLineBehind )
                {
                    SwIterator<SwRowFrame,SwFormat> aIter( *m_pLineBehind->GetFrameFormat() );
                    pSibling = aIter.First();
                    while ( pSibling && (
                                // only consider row frames associated with pLineBehind:
                                pSibling->GetTabLine() != m_pLineBehind ||
                                // only consider row frames that are in pTables Master-Follow chain:
                                !lcl_IsLineOfTableFrame( *pTable, *pSibling ) ||
                                // only consider row frames that are not repeated headlines:
                                pSibling->IsRepeatedHeadline() ||
                                // only consider row frames that are not follow flow rows
                                pSibling->IsInFollowFlowRow() ) )
                    {
                          pSibling = aIter.Next();
                    }
                }
                if ( pSibling )
                    pUpperFrame = pSibling->GetUpper();
                else
                {
                    while( pTable->GetFollow() )
                        pTable = pTable->GetFollow();
                    pUpperFrame = pTable;
                }
                const sal_uInt16 nMax = nBhPos != USHRT_MAX ?
                                    nBhPos : rTable.GetTabLines().size();

                sal_uInt16 i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt;

                for ( ; i < nMax; ++i )
                    ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrame, pSibling );
                if ( pUpperFrame->IsTabFrame() )
                    static_cast<SwTabFrame*>(pUpperFrame)->SetCalcLowers();
            }
            else // insert before
            {
                sal_uInt16 i;

                // We are looking for the frame that is behind the row frame
                // that should be inserted.
                for ( i = 0; !pSibling; ++i )
                {
                    SwTableLine* pLine = m_pLineBefore ? m_pLineBefore : rTable.GetTabLines()[i];

                    SwIterator<SwRowFrame,SwFormat> aIter( *pLine->GetFrameFormat() );
                    pSibling = aIter.First();

                    while ( pSibling && (
                            // only consider row frames associated with pLineBefore:
                            pSibling->GetTabLine() != pLine ||
                            // only consider row frames that are in pTables Master-Follow chain:
                            !lcl_IsLineOfTableFrame( *pTable, *pSibling ) ||
                            // only consider row frames that are not repeated headlines:
                            pSibling->IsRepeatedHeadline() ||
                            // 1. case: pLineBefore == 0:
                            // only consider row frames that are not follow flow rows
                            // 2. case: pLineBefore != 0:
                            // only consider row frames that are not split table rows
                            // #i37476# If !pLineBefore,
                            // check IsInFollowFlowRow instead of IsInSplitTableRow.
                            ( ( !m_pLineBefore && pSibling->IsInFollowFlowRow() ) ||
                              (  m_pLineBefore && pSibling->IsInSplitTableRow() ) ) ) )
                    {
                        pSibling = aIter.Next();
                    }
                }

                pUpperFrame = pSibling->GetUpper();
                if ( m_pLineBefore )
                    pSibling = static_cast<SwRowFrame*>( pSibling->GetNext() );

                sal_uInt16 nMax = nBhPos != USHRT_MAX ?
                                    nBhPos - nCnt :
                                    rTable.GetTabLines().size() - nCnt;

                i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0;
                for ( ; i < nMax; ++i )
                    ::lcl_InsertRow( *rTable.GetTabLines()[i],
                                pUpperFrame, pSibling );
                if ( pUpperFrame->IsTabFrame() )
                    static_cast<SwTabFrame*>(pUpperFrame)->SetCalcLowers();
            }
        }
    }

    // If necessary headlines should be processed. In order to
    // not to fragment good code, we iterate once more.
    const sal_uInt16 nRowsToRepeat = rTable.GetRowsToRepeat();
    if ( !(nRowsToRepeat > 0 &&
         ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) ||
           (  bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) )) )
        return;

    for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
    {
        if ( pTable->Lower() )
        {
            if ( pTable->IsFollow() )
            {
                lcl_UpdateRepeatedHeadlines( *pTable, true );
            }

            SwFrame* pLower = pTable->Lower();
            OSL_ENSURE( pLower && static_cast<SwRowFrame*>(pLower)->GetTabLine() ==
                    rTable.GetTabLines()[0], "MakeNewFrames: Table corruption!" );
        }
    }
}

bool FndBox_::AreLinesToRestore( const SwTable &rTable ) const
{
    // Should we call MakeFrames here?

    if ( !m_pLineBefore && !m_pLineBehind && !rTable.GetTabLines().empty() )
        return true;

    sal_uInt16 nBfPos;
    if(m_pLineBefore)
    {
        const SwTableLine* rLBefore = const_cast<const SwTableLine*>(m_pLineBefore);
        nBfPos = rTable.GetTabLines().GetPos( rLBefore );
    }
    else
        nBfPos = USHRT_MAX;

    sal_uInt16 nBhPos;
    if(m_pLineBehind)
    {
        const SwTableLine* rLBehind = const_cast<const SwTableLine*>(m_pLineBehind);
        nBhPos = rTable.GetTabLines().GetPos( rLBehind );
    }
    else
        nBhPos = USHRT_MAX;

    if ( nBfPos == nBhPos ) // Should never occur.
    {
        OSL_FAIL( "Table, erase but not on any area !?!" );
        return false;
    }

    if ( rTable.GetRowsToRepeat() > 0 )
    {
        // oops: should the repeated headline have been deleted??
        SwIterator<SwTabFrame,SwFormat> aIter( *rTable.GetFrameFormat() );
        for( SwTabFrame* pTable = aIter.First(); pTable; pTable = aIter.Next() )
        {
            if( pTable->IsFollow() )
            {
                // Insert new headlines:
                lcl_UpdateRepeatedHeadlines( *pTable, false );
            }
        }
    }

    // Some adjacent lines at the beginning of the table have been deleted:
    if ( nBfPos == USHRT_MAX && nBhPos == 0 )
        return false;

    // Some adjacent lines at the end of the table have been deleted:
    if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().size() - 1) )
        return false;

    // Some adjacent lines in the middle of the table have been deleted:
    if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos )
        return false;

    // The structure of the deleted lines is more complex due to split lines.
    // A call of MakeFrames() is necessary.
    return true;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5 in Prozent
C=91 H=81 G=85

¤ Dauer der Verarbeitung: 0.52 Sekunden  (vorverarbeitet am  2026-05-06) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.