/* -*- 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 <memory>
#include <com/sun/star/text/HoriOrientation.hpp>
#include <hintids.hxx>
 
#include <editeng/brushitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/protitem.hxx>
#include <editeng/boxitem.hxx>
#include <tools/fract.hxx>
#include <fmtfsize.hxx>
#include <fmtornt.hxx>
#include <doc.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentChartDataProviderAccess.hxx>
#include <DocumentContentOperationsManager.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <cntfrm.hxx>
#include <docsh.hxx>
#include <fesh.hxx>
#include <tabfrm.hxx>
#include <frmtool.hxx>
#include <pam.hxx>
#include <swtable.hxx>
#include <ndtxt.hxx>
#include <tblafmt.hxx>
#include <tblsel.hxx>
#include <fldbas.hxx>
#include <swundo.hxx>
#include <rowfrm.hxx>
#include <ddefld.hxx>
#include <hints.hxx>
#include <UndoTable.hxx>
#include <cellatr.hxx>
#include <mvsave.hxx>
#include <swtblfmt.hxx>
#include <swddetbl.hxx>
#include <poolfmt.hxx>
#include <tblrwcl.hxx>
#include <unochart.hxx>
#include <o3tl/numeric.hxx>
#include <calbck.hxx>
#include <docary.hxx>
 
using namespace com::sun::star;
using namespace com::sun::star::uno;
 
#define COLFUZZY 20
#define ROWFUZZY 10
 
#ifdef DBG_UTIL
#define CHECK_TABLE(t) (t).CheckConsistency();
#else
#define CHECK_TABLE(t)
#endif
 
// In order to set the Frame Formats for the Boxes, it's enough to look
// up the current one in the array. If it's already there return the new one.
struct CpyTabFrame
{
    union {
        SwFrameFormat* pFrameFormat; // for CopyCol
        SwTwips nSize;               // for DelCol
    } Value;
    SwTableBoxFormat *pNewFrameFormat;
 
    explicit CpyTabFrame(SwFrameFormat* pCurrentFrameFormat) : pNewFrameFormat( nullptr )
    {   Value.pFrameFormat = pCurrentFrameFormat; }
 
    bool operator==( const CpyTabFrame& rCpyTabFrame ) const
        { return  static_cast<sal_uLong>(Value.nSize) == static_cast<sal_uLong>(rCpyTabFrame.Value.nSize); }
    bool operator<( const CpyTabFrame& rCpyTabFrame ) const
        { return  static_cast<sal_uLong>(Value.nSize) < static_cast<sal_uLong>(rCpyTabFrame.Value.nSize); }
};
 
struct CR_SetBoxWidth
{
    SwSelBoxes m_Boxes;
    SwShareBoxFormats aShareFormats;
    SwTableNode* pTableNd;
    SwUndoTableNdsChg* pUndo;
    SwTwips nDiff, nSide, nMaxSize, nLowerDiff;
    TableChgMode nMode;
    sal_uInt16 nTableWidth, nRemainWidth, nBoxWidth;
    bool bBigger, bLeft, bSplittBox, bAnyBoxFnd;
 
    CR_SetBoxWidth( TableChgWidthHeightType eType, SwTwips nDif, SwTwips nSid, SwTwips nTableW,
                    SwTwips nMax, SwTableNode* pTNd )
        : pTableNd( pTNd ), pUndo( nullptr ),
        nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nLowerDiff( 0 ),
        nTableWidth( static_cast<sal_uInt16>(nTableW) ), nRemainWidth( 0 ), nBoxWidth( 0 ),
        bSplittBox( false ), bAnyBoxFnd( false )
    {
        bLeft = TableChgWidthHeightType::ColLeft == extractPosition( eType ) ||
                TableChgWidthHeightType::CellLeft == extractPosition( eType );
        bBigger = bool(eType & TableChgWidthHeightType::BiggerMode );
        nMode = pTableNd->GetTable().GetTableChgMode();
    }
    CR_SetBoxWidth( const CR_SetBoxWidth& rCpy )
        : pTableNd( rCpy.pTableNd ),
        pUndo( rCpy.pUndo ),
        nDiff( rCpy.nDiff ), nSide( rCpy.nSide ),
        nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ),
        nMode( rCpy.nMode ), nTableWidth( rCpy.nTableWidth ),
        nRemainWidth( rCpy.nRemainWidth ), nBoxWidth( rCpy.nBoxWidth ),
        bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft ),
        bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd )
    {
    }
 
    SwUndoTableNdsChg* CreateUndo( SwUndoId eUndoType )
    {
        return pUndo = new SwUndoTableNdsChg( eUndoType, m_Boxes, *pTableNd );
    }
 
    void LoopClear()
    {
        nLowerDiff = 0; nRemainWidth = 0;
    }
};
 
static bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                         SwTwips nDist, bool bCheck );
static bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                                SwTwips nDist, bool bCheck );
static bool lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                                SwTwips nDist, bool bCheck );
static bool lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                                SwTwips nDist, bool bCheck );
static bool lcl_DelSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                                SwTwips nDist, bool bCheck );
static bool lcl_DelOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                                SwTwips nDist, bool bCheck );
 
typedef bool (*FN_lcl_SetBoxWidth)(SwTableLine*, CR_SetBoxWidth&, SwTwips, bool );
 
#ifdef DBG_UTIL
 
#define CHECKBOXWIDTH                                           \
    {                                                           \
        SwTwips nSize = GetFrameFormat()->GetFrameSize().GetWidth();   \
        for (size_t nTmp = 0; nTmp < m_aLines.size(); ++nTmp)   \
            ::CheckBoxWidth( *m_aLines[ nTmp ], nSize );         \
    }
 
#define CHECKTABLELAYOUT                                            \
    {                                                               \
        for ( size_t i = 0; i < GetTabLines().size(); ++i )        \
        {                                                           \
            SwFrameFormat* pFormat = GetTabLines()[i]->GetFrameFormat();  \
            SwIterator<SwRowFrame,SwFormat> aIter( *pFormat );              \
            for (SwRowFrame* pFrame=aIter.First(); pFrame; pFrame=aIter.Next())\
            {                                                       \
                if ( pFrame->GetTabLine() == GetTabLines()[i] )       \
                {                                               \
                    OSL_ENSURE( pFrame->GetUpper()->IsTabFrame(),       \
                                "Table layout does not match table structure" );       \
                }                                               \
            }                                                       \
        }                                                           \
    }
 
#else
 
#define CHECKBOXWIDTH
#define CHECKTABLELAYOUT
 
#endif // DBG_UTIL
 
struct CR_SetLineHeight
{
    SwSelBoxes m_Boxes;
    SwShareBoxFormats aShareFormats;
    SwTableNode* pTableNd;
    SwUndoTableNdsChg* pUndo;
    SwTwips nMaxSpace, nMaxHeight;
    TableChgMode nMode;
    bool bBigger, bTop;
 
    CR_SetLineHeight( TableChgWidthHeightType eType, SwTableNode* pTNd )
        : pTableNd( pTNd ), pUndo( nullptr ),
        nMaxSpace( 0 ), nMaxHeight( 0 )
    {
        bTop = TableChgWidthHeightType::CellTop == extractPosition( eType );
        bBigger = bool(eType & TableChgWidthHeightType::BiggerMode );
        if( eType & TableChgWidthHeightType::InsertDeleteMode )
            bBigger = !bBigger;
        nMode = pTableNd->GetTable().GetTableChgMode();
    }
    CR_SetLineHeight( const CR_SetLineHeight& rCpy )
        : pTableNd( rCpy.pTableNd ), pUndo( rCpy.pUndo ),
        nMaxSpace( rCpy.nMaxSpace ), nMaxHeight( rCpy.nMaxHeight ),
        nMode( rCpy.nMode ),
        bBigger( rCpy.bBigger ), bTop( rCpy.bTop )
    {}
 
    SwUndoTableNdsChg* CreateUndo( SwUndoId nUndoType )
    {
        return pUndo = new SwUndoTableNdsChg( nUndoType, m_Boxes, *pTableNd );
    }
};
 
static bool lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
                         SwTwips nDist, bool bCheck );
static bool lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
                                SwTwips nDist, bool bCheck );
static bool lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam,
                                SwTwips nDist, bool bCheck );
 
typedef bool (*FN_lcl_SetLineHeight)(SwTableLine*, CR_SetLineHeight&, SwTwips, bool );
 
typedef o3tl::sorted_vector<CpyTabFrame> CpyTabFrames;
 
struct CpyPara
{
    std::shared_ptr< std::vector< std::vector< sal_uLong > > > pWidths;
    SwDoc* pDoc;
    SwTableNode* pTableNd;
    CpyTabFrames& rTabFrameArr;
    SwTableLine* pInsLine;
    SwTableBox* pInsBox;
    sal_uLong nOldSize, nNewSize;           // in order to correct the size attributes
    sal_uLong nMinLeft, nMaxRight;
    sal_uInt16 nCpyCnt, nInsPos;
    sal_uInt16 nLnIdx, nBoxIdx;
    sal_uInt8 nDelBorderFlag;
    bool bCpyContent;
 
    CpyPara( SwTableNode* pNd, sal_uInt16 nCopies, CpyTabFrames& rFrameArr )
        : pDoc( pNd->GetDoc() ), pTableNd( pNd ), rTabFrameArr(rFrameArr),
        pInsLine(nullptr), pInsBox(nullptr), nOldSize(0), nNewSize(0),
        nMinLeft(ULONG_MAX), nMaxRight(0),
        nCpyCnt(nCopies), nInsPos(0),
        nLnIdx(0), nBoxIdx(0),
        nDelBorderFlag(0), bCpyContent( true )
        {}
    CpyPara( const CpyPara& rPara, SwTableLine* pLine )
        : pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTableNd(rPara.pTableNd),
        rTabFrameArr(rPara.rTabFrameArr), pInsLine(pLine), pInsBox(rPara.pInsBox),
        nOldSize(0), nNewSize(rPara.nNewSize), nMinLeft( rPara.nMinLeft ),
        nMaxRight( rPara.nMaxRight ), nCpyCnt(rPara.nCpyCnt), nInsPos(0),
        nLnIdx( rPara.nLnIdx), nBoxIdx( rPara.nBoxIdx ),
        nDelBorderFlag( rPara.nDelBorderFlag ), bCpyContent( rPara.bCpyContent )
        {}
    CpyPara( const CpyPara& rPara, SwTableBox* pBox )
        : pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTableNd(rPara.pTableNd),
        rTabFrameArr(rPara.rTabFrameArr), pInsLine(rPara.pInsLine), pInsBox(pBox),
        nOldSize(rPara.nOldSize), nNewSize(rPara.nNewSize),
        nMinLeft( rPara.nMinLeft ), nMaxRight( rPara.nMaxRight ),
        nCpyCnt(rPara.nCpyCnt), nInsPos(0), nLnIdx(rPara.nLnIdx), nBoxIdx(rPara.nBoxIdx),
        nDelBorderFlag( rPara.nDelBorderFlag ), bCpyContent( rPara.bCpyContent )
        {}
};
 
static void lcl_CopyRow(FndLine_ & rFndLine, CpyPara *const pCpyPara);
 
static void lcl_CopyCol( FndBox_ & rFndBox, CpyPara *const pCpyPara)
{
    // Look up the Frame Format in the Frame Format Array
    SwTableBox* pBox = rFndBox.GetBox();
    CpyTabFrame aFindFrame(pBox->GetFrameFormat());
 
    sal_uInt16 nFndPos;
    if( pCpyPara->nCpyCnt )
    {
        CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.lower_bound( aFindFrame );
        nFndPos = itFind - pCpyPara->rTabFrameArr.begin();
        if( itFind == pCpyPara->rTabFrameArr.end() || !(*itFind == aFindFrame) )
        {
            // For nested copying, also save the new Format as an old one.
            SwTableBoxFormat* pNewFormat = static_cast<SwTableBoxFormat*>(pBox->ClaimFrameFormat());
 
            // Find the selected Boxes in the Line:
            FndLine_ const* pCmpLine = nullptr;
            SwFormatFrameSize aFrameSz( pNewFormat->GetFrameSize() );
 
            bool bDiffCount = false;
            if( pBox->GetTabLines().size() )
            {
                pCmpLine = rFndBox.GetLines().front().get();
                if ( pCmpLine->GetBoxes().size() != pCmpLine->GetLine()->GetTabBoxes().size() )
                    bDiffCount = true;
            }
 
            if( bDiffCount )
            {
                // The first Line should be enough
                FndBoxes_t const& rFndBoxes = pCmpLine->GetBoxes();
                long nSz = 0;
                for( auto n = rFndBoxes.size(); n; )
                {
                    nSz += rFndBoxes[--n]->GetBox()->
                            GetFrameFormat()->GetFrameSize().GetWidth();
                }
                aFrameSz.SetWidth( aFrameSz.GetWidth() -
                                            nSz / ( pCpyPara->nCpyCnt + 1 ) );
                pNewFormat->SetFormatAttr( aFrameSz );
                aFrameSz.SetWidth( nSz / ( pCpyPara->nCpyCnt + 1 ) );
 
                // Create a new Format for the new Box, specifying its size.
                aFindFrame.pNewFrameFormat = reinterpret_cast<SwTableBoxFormat*>(pNewFormat->GetDoc()->
                                            MakeTableLineFormat());
                *aFindFrame.pNewFrameFormat = *pNewFormat;
                aFindFrame.pNewFrameFormat->SetFormatAttr( aFrameSz );
            }
            else
            {
                aFrameSz.SetWidth( aFrameSz.GetWidth() / ( pCpyPara->nCpyCnt + 1 ) );
                pNewFormat->SetFormatAttr( aFrameSz );
 
                aFindFrame.pNewFrameFormat = pNewFormat;
                pCpyPara->rTabFrameArr.insert( aFindFrame );
                aFindFrame.Value.pFrameFormat = pNewFormat;
                pCpyPara->rTabFrameArr.insert( aFindFrame );
            }
        }
        else
        {
            aFindFrame = pCpyPara->rTabFrameArr[ nFndPos ];
            pBox->ChgFrameFormat( aFindFrame.pNewFrameFormat );
        }
    }
    else
    {
        CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.find( aFindFrame );
        if( pCpyPara->nDelBorderFlag &&
            itFind != pCpyPara->rTabFrameArr.end() )
            aFindFrame = *itFind;
        else
            aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
    }
 
    if (!rFndBox.GetLines().empty())
    {
        pBox = new SwTableBox( aFindFrame.pNewFrameFormat,
                    rFndBox.GetLines().size(), pCpyPara->pInsLine );
        pCpyPara->pInsLine->GetTabBoxes().insert( pCpyPara->pInsLine->GetTabBoxes().begin() + pCpyPara->nInsPos++, pBox );
        CpyPara aPara( *pCpyPara, pBox );
        aPara.nDelBorderFlag &= 7;
 
        for (auto const& pFndLine : rFndBox.GetLines())
        {
            lcl_CopyRow(*pFndLine, &aPara);
        }
    }
    else
    {
        ::InsTableBox( pCpyPara->pDoc, pCpyPara->pTableNd, pCpyPara->pInsLine,
                    aFindFrame.pNewFrameFormat, pBox, pCpyPara->nInsPos++ );
 
        const FndBoxes_t& rFndBxs = rFndBox.GetUpper()->GetBoxes();
        if( 8 > pCpyPara->nDelBorderFlag
                ? pCpyPara->nDelBorderFlag != 0
                : &rFndBox == rFndBxs[rFndBxs.size() - 1].get())
        {
            const SvxBoxItem& rBoxItem = pBox->GetFrameFormat()->GetBox();
            if( 8 > pCpyPara->nDelBorderFlag
                    ? rBoxItem.GetTop()
                    : rBoxItem.GetRight() )
            {
                aFindFrame.Value.pFrameFormat = pBox->GetFrameFormat();
 
                SvxBoxItem aNew( rBoxItem );
                if( 8 > pCpyPara->nDelBorderFlag )
                    aNew.SetLine( nullptr, SvxBoxItemLine::TOP );
                else
                    aNew.SetLine( nullptr, SvxBoxItemLine::RIGHT );
 
                if( 1 == pCpyPara->nDelBorderFlag ||
                    8 == pCpyPara->nDelBorderFlag )
                {
                    // For all Boxes that delete TopBorderLine, we copy after that
                    pBox = pCpyPara->pInsLine->GetTabBoxes()[
                                            pCpyPara->nInsPos - 1 ];
                }
 
                aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
 
                // Else we copy before that and the first Line keeps the TopLine
                // and we remove it at the original
                pBox->ClaimFrameFormat()->SetFormatAttr( aNew );
 
                if( !pCpyPara->nCpyCnt )
                    pCpyPara->rTabFrameArr.insert( aFindFrame );
            }
        }
    }
}
 
static void lcl_CopyRow(FndLine_& rFndLine, CpyPara *const pCpyPara)
{
    SwTableLine* pNewLine = new SwTableLine(
                            static_cast<SwTableLineFormat*>(rFndLine.GetLine()->GetFrameFormat()),
                        rFndLine.GetBoxes().size(), pCpyPara->pInsBox );
    if( pCpyPara->pInsBox )
    {
        SwTableLines& rLines = pCpyPara->pInsBox->GetTabLines();
        rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
    }
    else
    {
        SwTableLines& rLines = pCpyPara->pTableNd->GetTable().GetTabLines();
        rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
    }
 
    CpyPara aPara( *pCpyPara, pNewLine );
    for (auto const& it : rFndLine.GetBoxes())
    {
        lcl_CopyCol(*it, &aPara);
    }
 
    pCpyPara->nDelBorderFlag &= 0xf8;
}
 
static void lcl_InsCol( FndLine_* pFndLn, CpyPara& rCpyPara, sal_uInt16 nCpyCnt,
                bool bBehind )
{
    // Bug 29124: Not only copy in the BaseLines. If possible, we go down as far as possible
    FndBox_* pFBox;
    if( 1 == pFndLn->GetBoxes().size() &&
        !( pFBox = pFndLn->GetBoxes()[0].get() )->GetBox()->GetSttNd() )
    {
        // A Box with multiple Lines, so insert into these Lines
        for (auto &rpLine : pFBox->GetLines())
        {
            lcl_InsCol( rpLine.get(), rCpyPara, nCpyCnt, bBehind );
        }
    }
    else
    {
        rCpyPara.pInsLine = pFndLn->GetLine();
        SwTableBox* pBox = pFndLn->GetBoxes()[ bBehind ?
                    pFndLn->GetBoxes().size()-1 : 0 ]->GetBox();
        rCpyPara.nInsPos = pFndLn->GetLine()->GetBoxPos( pBox );
        if( bBehind )
            ++rCpyPara.nInsPos;
 
        for( sal_uInt16 n = 0; n < nCpyCnt; ++n )
        {
            if( n + 1 == nCpyCnt && bBehind )
                rCpyPara.nDelBorderFlag = 9;
            else
                rCpyPara.nDelBorderFlag = 8;
            for (auto const& it : pFndLn->GetBoxes())
            {
                lcl_CopyCol(*it, &rCpyPara);
            }
        }
    }
}
 
SwRowFrame* GetRowFrame( SwTableLine& rLine )
{
    SwIterator<SwRowFrame,SwFormat> aIter( *rLine.GetFrameFormat() );
    for( SwRowFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
        if( pFrame->GetTabLine() == &rLine )
            return pFrame;
    return nullptr;
}
 
bool SwTable::InsertCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt, bool bBehind )
{
    OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid Box List" );
    SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
    if( !pTableNd )
        return false;
 
    bool bRes = true;
    if( IsNewModel() )
        bRes = NewInsertCol( pDoc, rBoxes, nCnt, bBehind );
    else
    {
        // Find all Boxes/Lines
        FndBox_ aFndBox( nullptr, nullptr );
        {
            FndPara aPara( rBoxes, &aFndBox );
            ForEach_FndLineCopyCol( GetTabLines(), &aPara );
        }
        if( aFndBox.GetLines().empty() )
            return false;
 
        SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());    // Delete HTML Layout
 
        // Find Lines for the layout update
        aFndBox.SetTableLines( *this );
        aFndBox.DelFrames( *this );
 
        // TL_CHART2: nothing to be done since chart2 currently does not want to
        // get notified about new rows/cols.
 
        CpyTabFrames aTabFrameArr;
        CpyPara aCpyPara( pTableNd, nCnt, aTabFrameArr );
 
        for (auto & rpLine : aFndBox.GetLines())
        {
            lcl_InsCol( rpLine.get(), aCpyPara, nCnt, bBehind );
        }
 
        // clean up this Line's structure once again, generally all of them
        GCLines();
 
        // Update Layout
        aFndBox.MakeFrames( *this );
 
        CHECKBOXWIDTH;
        CHECKTABLELAYOUT;
        bRes = true;
    }
 
    SwChartDataProvider *pPCD = pDoc->getIDocumentChartDataProviderAccess().GetChartDataProvider();
    if (pPCD && nCnt)
        pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
    pDoc->UpdateCharts( GetFrameFormat()->GetName() );
 
    pDoc->GetDocShell()->GetFEShell()->UpdateTableStyleFormatting();
 
    return bRes;
}
 
bool SwTable::InsertRow_( SwDoc* pDoc, const SwSelBoxes& rBoxes,
                        sal_uInt16 nCnt, bool bBehind )
{
    OSL_ENSURE( pDoc && !rBoxes.empty() && nCnt, "No valid Box List" );
    SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
    if( !pTableNd )
        return false;
 
     // Find all Boxes/Lines
    FndBox_ aFndBox( nullptr, nullptr );
    {
        FndPara aPara( rBoxes, &aFndBox );
        ForEach_FndLineCopyCol( GetTabLines(), &aPara );
    }
    if( aFndBox.GetLines().empty() )
        return false;
 
    SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());   // Delete HTML Layout
 
    FndBox_* pFndBox = &aFndBox;
    {
        FndLine_* pFndLine;
        while( 1 == pFndBox->GetLines().size() &&
            1 == (pFndLine = pFndBox->GetLines()[0].get())->GetBoxes().size())
        {
            // Don't go down too far! One Line with Box needs to remain!
            FndBox_ *const pTmpBox = pFndLine->GetBoxes().front().get();
            if( !pTmpBox->GetLines().empty() )
                pFndBox = pTmpBox;
            else
                break;
        }
    }
 
    // Find Lines for the layout update
    const bool bLayout = !IsNewModel() &&
        nullptr != SwIterator<SwTabFrame,SwFormat>( *GetFrameFormat() ).First();
 
    if ( bLayout )
    {
        aFndBox.SetTableLines( *this );
        if( pFndBox != &aFndBox )
            aFndBox.DelFrames( *this );
        // TL_CHART2: nothing to be done since chart2 currently does not want to
        // get notified about new rows/cols.
    }
 
    CpyTabFrames aTabFrameArr;
    CpyPara aCpyPara( pTableNd, 0, aTabFrameArr );
 
    SwTableLine* pLine = pFndBox->GetLines()[ bBehind ?
                    pFndBox->GetLines().size()-1 : 0 ]->GetLine();
    if( &aFndBox == pFndBox )
        aCpyPara.nInsPos = GetTabLines().GetPos( pLine );
    else
    {
        aCpyPara.pInsBox = pFndBox->GetBox();
        aCpyPara.nInsPos = pFndBox->GetBox()->GetTabLines().GetPos( pLine );
    }
 
    if( bBehind )
    {
        ++aCpyPara.nInsPos;
        aCpyPara.nDelBorderFlag = 1;
    }
    else
        aCpyPara.nDelBorderFlag = 2;
 
    for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt )
    {
        if( bBehind )
            aCpyPara.nDelBorderFlag = 1;
        for (auto & rpFndLine : pFndBox->GetLines())
            lcl_CopyRow( *rpFndLine, &aCpyPara );
    }
 
    // clean up this Line's structure once again, generally all of them
    if( !pDoc->IsInReading() )
        GCLines();
 
    // Update Layout
    if ( bLayout )
    {
        if( pFndBox != &aFndBox )
            aFndBox.MakeFrames( *this );
        else
            aFndBox.MakeNewFrames( *this, nCnt, bBehind );
    }
 
    CHECKBOXWIDTH;
    CHECKTABLELAYOUT;
 
    SwChartDataProvider *pPCD = pDoc->getIDocumentChartDataProviderAccess().GetChartDataProvider();
    if (pPCD && nCnt)
        pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
    pDoc->UpdateCharts( GetFrameFormat()->GetName() );
 
    pDoc->GetDocShell()->GetFEShell()->UpdateTableStyleFormatting( pTableNd );
 
    return true;
}
 
static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset,
                            bool bFirst, SwShareBoxFormats& rShareFormats );
 
static void lcl_LastBoxSetWidthLine( SwTableLines &rLines, const long nOffset,
                                bool bFirst, SwShareBoxFormats& rShareFormats )
{
    for ( auto pLine : rLines )
        ::lcl_LastBoxSetWidth( pLine->GetTabBoxes(), nOffset, bFirst, rShareFormats );
}
 
static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset,
                            bool bFirst, SwShareBoxFormats& rShareFormats )
{
    SwTableBox& rBox = *(bFirst ? rBoxes.front() : rBoxes.back());
    if( !rBox.GetSttNd() )
        ::lcl_LastBoxSetWidthLine( rBox.GetTabLines(), nOffset,
                                    bFirst, rShareFormats );
 
    // Adapt the Box
    const SwFrameFormat *pBoxFormat = rBox.GetFrameFormat();
    SwFormatFrameSize aNew( pBoxFormat->GetFrameSize() );
    aNew.SetWidth( aNew.GetWidth() + nOffset );
    SwFrameFormat *pFormat = rShareFormats.GetFormat( *pBoxFormat, aNew );
    if( pFormat )
        rBox.ChgFrameFormat( static_cast<SwTableBoxFormat*>(pFormat) );
    else
    {
        pFormat = rBox.ClaimFrameFormat();
 
        pFormat->LockModify();
        pFormat->SetFormatAttr( aNew );
        pFormat->UnlockModify();
 
        rShareFormats.AddFormat( *pBoxFormat, *pFormat );
    }
}
 
void DeleteBox_( SwTable& rTable, SwTableBox* pBox, SwUndo* pUndo,
                bool bCalcNewSize, const bool bCorrBorder,
                SwShareBoxFormats* pShareFormats )
{
    do {
        SwTwips nBoxSz = bCalcNewSize ?
                pBox->GetFrameFormat()->GetFrameSize().GetWidth() : 0;
        SwTableLine* pLine = pBox->GetUpper();
        SwTableBoxes& rTableBoxes = pLine->GetTabBoxes();
        sal_uInt16 nDelPos = pLine->GetBoxPos( pBox );
        SwTableBox* pUpperBox = pBox->GetUpper()->GetUpper();
 
        // Special treatment for the border:
        if( bCorrBorder && 1 < rTableBoxes.size() )
        {
            const SvxBoxItem& rBoxItem = pBox->GetFrameFormat()->GetBox();
 
            if( rBoxItem.GetLeft() || rBoxItem.GetRight() )
            {
                bool bChgd = false;
 
                // JP 02.04.97: 1st part for Bug 36271
                // First the left/right edges
                if( nDelPos + 1 < static_cast<sal_uInt16>(rTableBoxes.size()) )
                {
                    SwTableBox* pNxtBox = rTableBoxes[ nDelPos + 1 ];
                    const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrameFormat()->GetBox();
 
                    SwTableBox* pPrvBox = nDelPos ? rTableBoxes[ nDelPos - 1 ] : nullptr;
 
                    if( pNxtBox->GetSttNd() && !rNxtBoxItem.GetLeft() &&
                        ( !pPrvBox || !pPrvBox->GetFrameFormat()->GetBox().GetRight()) )
                    {
                        SvxBoxItem aTmp( rNxtBoxItem );
                        aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
                                                         : rBoxItem.GetRight(),
                                                            SvxBoxItemLine::LEFT );
                        if( pShareFormats )
                            pShareFormats->SetAttr( *pNxtBox, aTmp );
                        else
                            pNxtBox->ClaimFrameFormat()->SetFormatAttr( aTmp );
                        bChgd = true;
                    }
                }
                if( !bChgd && nDelPos )
                {
                    SwTableBox* pPrvBox = rTableBoxes[ nDelPos - 1 ];
                    const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrameFormat()->GetBox();
 
                    SwTableBox* pNxtBox = nDelPos + 1 < static_cast<sal_uInt16>(rTableBoxes.size())
                                            ? rTableBoxes[ nDelPos + 1 ] : nullptr;
 
                    if( pPrvBox->GetSttNd() && !rPrvBoxItem.GetRight() &&
                        ( !pNxtBox || !pNxtBox->GetFrameFormat()->GetBox().GetLeft()) )
                    {
                        SvxBoxItem aTmp( rPrvBoxItem );
                        aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
                                                         : rBoxItem.GetRight(),
                                                            SvxBoxItemLine::RIGHT );
                        if( pShareFormats )
                            pShareFormats->SetAttr( *pPrvBox, aTmp );
                        else
                            pPrvBox->ClaimFrameFormat()->SetFormatAttr( aTmp );
                    }
                }
            }
        }
 
        // Delete the Box first, then the Nodes!
        SwStartNode* pSttNd = const_cast<SwStartNode*>(pBox->GetSttNd());
        if( pShareFormats )
            pShareFormats->RemoveFormat( *rTableBoxes[ nDelPos ]->GetFrameFormat() );
 
        // Before deleting the 'Table Box' from memory - delete any redlines attached to it
        if ( rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().HasExtraRedlineTable() )
            rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableCellRedline( rTable.GetFrameFormat()->GetDoc(), *(rTableBoxes[nDelPos]), true, USHRT_MAX );
        delete rTableBoxes[nDelPos];
        rTableBoxes.erase( rTableBoxes.begin() + nDelPos );
 
        if( pSttNd )
        {
            // Has the UndoObject been prepared to save the Section?
            if( pUndo && pUndo->IsDelBox() )
                static_cast<SwUndoTableNdsChg*>(pUndo)->SaveSection( pSttNd );
            else
                pSttNd->GetDoc()->getIDocumentContentOperations().DeleteSection( pSttNd );
        }
 
        // Also delete the Line?
        if( !rTableBoxes.empty() )
        {
            // Then adapt the Frame-SSize
            bool bLastBox = nDelPos == rTableBoxes.size();
            if( bLastBox )
                --nDelPos;
            pBox = rTableBoxes[nDelPos];
            if( bCalcNewSize )
            {
                SwFormatFrameSize aNew( pBox->GetFrameFormat()->GetFrameSize() );
                aNew.SetWidth( aNew.GetWidth() + nBoxSz );
                if( pShareFormats )
                    pShareFormats->SetSize( *pBox, aNew );
                else
                    pBox->ClaimFrameFormat()->SetFormatAttr( aNew );
 
                if( !pBox->GetSttNd() )
                {
                    // We need to this recursively in all Lines in all Cells!
                    SwShareBoxFormats aShareFormats;
                    ::lcl_LastBoxSetWidthLine( pBox->GetTabLines(), nBoxSz,
                                                !bLastBox,
                                                pShareFormats ? *pShareFormats
                                                           : aShareFormats );
                }
            }
            break;      // Stop deleting
        }
        // Delete the Line from the Table/Box
        if( !pUpperBox )
        {
            // Also delete the Line from the Table
            nDelPos = rTable.GetTabLines().GetPos( pLine );
            if( pShareFormats )
                pShareFormats->RemoveFormat( *rTable.GetTabLines()[ nDelPos ]->GetFrameFormat() );
 
            SwTableLine* pTabLineToDelete = rTable.GetTabLines()[ nDelPos ];
            // Before deleting the 'Table Line' from memory - delete any redlines attached to it
            if ( rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().HasExtraRedlineTable() )
                rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableRowRedline( rTable.GetFrameFormat()->GetDoc(), *pTabLineToDelete, true, USHRT_MAX );
            delete pTabLineToDelete;
            rTable.GetTabLines().erase( rTable.GetTabLines().begin() + nDelPos );
            break;      // we cannot delete more
        }
 
        // finally also delete the Line
        pBox = pUpperBox;
        nDelPos = pBox->GetTabLines().GetPos( pLine );
        if( pShareFormats )
            pShareFormats->RemoveFormat( *pBox->GetTabLines()[ nDelPos ]->GetFrameFormat() );
 
        SwTableLine* pTabLineToDelete = pBox->GetTabLines()[ nDelPos ];
        // Before deleting the 'Table Line' from memory - delete any redlines attached to it
        if ( rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().HasExtraRedlineTable() )
            rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableRowRedline( rTable.GetFrameFormat()->GetDoc(), *pTabLineToDelete, true, USHRT_MAX );
        delete pTabLineToDelete;
        pBox->GetTabLines().erase( pBox->GetTabLines().begin() + nDelPos );
    } while( pBox->GetTabLines().empty() );
}
 
static SwTableBox*
lcl_FndNxtPrvDelBox( const SwTableLines& rTableLns,
                                SwTwips nBoxStt, SwTwips nBoxWidth,
                                sal_uInt16 nLinePos, bool bNxt,
                                SwSelBoxes* pAllDelBoxes, size_t *const pCurPos)
{
    SwTableBox* pFndBox = nullptr;
    do {
        if( bNxt )
            ++nLinePos;
        else
            --nLinePos;
        SwTableLine* pLine = rTableLns[ nLinePos ];
        SwTwips nFndBoxWidth = 0;
        SwTwips nFndWidth = nBoxStt + nBoxWidth;
 
        pFndBox = pLine->GetTabBoxes()[ 0 ];
        for( auto pBox : pLine->GetTabBoxes() )
        {
            if ( nFndWidth <= 0 )
            {
                break;
            }
            pFndBox = pBox;
            nFndBoxWidth = pFndBox->GetFrameFormat()->GetFrameSize().GetWidth();
            nFndWidth -= nFndBoxWidth;
        }
 
        // Find the first ContentBox
        while( !pFndBox->GetSttNd() )
        {
            const SwTableLines& rLowLns = pFndBox->GetTabLines();
            if( bNxt )
                pFndBox = rLowLns.front()->GetTabBoxes().front();
            else
                pFndBox = rLowLns.back()->GetTabBoxes().front();
        }
 
        if( std::abs( nFndWidth ) > COLFUZZY ||
            std::abs( nBoxWidth - nFndBoxWidth ) > COLFUZZY )
            pFndBox = nullptr;
        else if( pAllDelBoxes )
        {
            // If the predecessor will also be deleted, there's nothing to do
            SwSelBoxes::const_iterator aFndIt = pAllDelBoxes->find( pFndBox);
            if( aFndIt == pAllDelBoxes->end() )
                break;
            size_t const nFndPos = aFndIt - pAllDelBoxes->begin() ;
 
            // else, we keep on searching.
            // We do not need to recheck the Box, however
            pFndBox = nullptr;
            if( nFndPos <= *pCurPos )
                --*pCurPos;
            pAllDelBoxes->erase( pAllDelBoxes->begin() + nFndPos );
        }
    } while( bNxt ? ( nLinePos + 1 < static_cast<sal_uInt16>(rTableLns.size()) ) : nLinePos != 0 );
    return pFndBox;
}
 
static void
lcl_SaveUpperLowerBorder( SwTable& rTable, const SwTableBox& rBox,
                                SwShareBoxFormats& rShareFormats,
                                SwSelBoxes* pAllDelBoxes = nullptr,
                                size_t *const pCurPos = nullptr )
{
//JP 16.04.97:  2. part for Bug 36271
    const SwTableLine* pLine = rBox.GetUpper();
    const SwTableBoxes& rTableBoxes = pLine->GetTabBoxes();
    const SwTableBox* pUpperBox = &rBox;
    sal_uInt16 nDelPos = pLine->GetBoxPos( pUpperBox );
    pUpperBox = rBox.GetUpper()->GetUpper();
    const SvxBoxItem& rBoxItem = rBox.GetFrameFormat()->GetBox();
 
    // then the top/bottom edges
    if( !rBoxItem.GetTop() && !rBoxItem.GetBottom() )
        return;
 
    bool bChgd = false;
    const SwTableLines* pTableLns;
    if( pUpperBox )
        pTableLns = &pUpperBox->GetTabLines();
    else
        pTableLns = &rTable.GetTabLines();
 
    sal_uInt16 nLnPos = pTableLns->GetPos( pLine );
 
    // Calculate the attribute position of the top-be-deleted Box and then
    // search in the top/bottom Line of the respective counterparts.
    SwTwips nBoxStt = 0;
    for( sal_uInt16 n = 0; n < nDelPos; ++n )
        nBoxStt += rTableBoxes[ n ]->GetFrameFormat()->GetFrameSize().GetWidth();
    SwTwips nBoxWidth = rBox.GetFrameFormat()->GetFrameSize().GetWidth();
 
    SwTableBox *pPrvBox = nullptr, *pNxtBox = nullptr;
    if( nLnPos )        // Predecessor?
        pPrvBox = ::lcl_FndNxtPrvDelBox( *pTableLns, nBoxStt, nBoxWidth,
                            nLnPos, false, pAllDelBoxes, pCurPos );
 
    if( nLnPos + 1 < static_cast<sal_uInt16>(pTableLns->size()) )     // Successor?
        pNxtBox = ::lcl_FndNxtPrvDelBox( *pTableLns, nBoxStt, nBoxWidth,
                            nLnPos, true, pAllDelBoxes, pCurPos );
 
    if( pNxtBox && pNxtBox->GetSttNd() )
    {
        const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrameFormat()->GetBox();
        if( !rNxtBoxItem.GetTop() && ( !pPrvBox ||
            !pPrvBox->GetFrameFormat()->GetBox().GetBottom()) )
        {
            SvxBoxItem aTmp( rNxtBoxItem );
            aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
                                            : rBoxItem.GetBottom(),
                                            SvxBoxItemLine::TOP );
            rShareFormats.SetAttr( *pNxtBox, aTmp );
            bChgd = true;
        }
    }
    if( !bChgd && pPrvBox && pPrvBox->GetSttNd() )
    {
        const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrameFormat()->GetBox();
        if( !rPrvBoxItem.GetTop() && ( !pNxtBox ||
            !pNxtBox->GetFrameFormat()->GetBox().GetTop()) )
        {
            SvxBoxItem aTmp( rPrvBoxItem );
            aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
                                            : rBoxItem.GetBottom(),
                                            SvxBoxItemLine::BOTTOM );
            rShareFormats.SetAttr( *pPrvBox, aTmp );
        }
    }
 
}
 
bool SwTable::DeleteSel(
    SwDoc*     pDoc
    ,
    const SwSelBoxes& rBoxes,
    const SwSelBoxes* pMerged, SwUndo* pUndo,
    const bool bDelMakeFrames, const bool bCorrBorder )
{
    OSL_ENSURE( pDoc, "No doc?" );
    SwTableNode* pTableNd = nullptr;
    if( !rBoxes.empty() )
    {
        pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
        if( !pTableNd )
            return false;
    }
 
    SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());    // Delete HTML Layout
 
    // Find Lines for the Layout update
    FndBox_ aFndBox( nullptr, nullptr );
    if ( bDelMakeFrames )
    {
        if( pMerged && !pMerged->empty() )
            aFndBox.SetTableLines( *pMerged, *this );
        else if( !rBoxes.empty() )
            aFndBox.SetTableLines( rBoxes, *this );
        aFndBox.DelFrames( *this );
    }
 
    SwShareBoxFormats aShareFormats;
 
    // First switch the Border, then delete
    if( bCorrBorder )
    {
        SwSelBoxes aBoxes( rBoxes );
        for (size_t n = 0; n < aBoxes.size(); ++n)
        {
            ::lcl_SaveUpperLowerBorder( *this, *rBoxes[ n ], aShareFormats,
                                        &aBoxes, &n );
        }
    }
 
    PrepareDelBoxes( rBoxes );
 
    SwChartDataProvider *pPCD = pDoc->getIDocumentChartDataProviderAccess().GetChartDataProvider();
    // Delete boxes from last to first
    for (size_t n = 0; n < rBoxes.size(); ++n)
    {
        size_t const nIdx = rBoxes.size() - 1 - n;
 
        // First adapt the data-sequence for chart if necessary
        // (needed to move the implementation cursor properly to its new
        // position which can't be done properly if the cell is already gone)
        if (pPCD && pTableNd)
            pPCD->DeleteBox( &pTableNd->GetTable(), *rBoxes[nIdx] );
 
        // ... then delete the boxes
        DeleteBox_( *this, rBoxes[nIdx], pUndo, true, bCorrBorder, &aShareFormats );
    }
 
    // then clean up the structure of all Lines
    GCLines();
 
    if( bDelMakeFrames && aFndBox.AreLinesToRestore( *this ) )
        aFndBox.MakeFrames( *this );
 
    // TL_CHART2: now inform chart that sth has changed
    pDoc->UpdateCharts( GetFrameFormat()->GetName() );
 
    CHECKTABLELAYOUT;
    CHECK_TABLE( *this );
 
    return true;
}
 
bool SwTable::OldSplitRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
                        bool bSameHeight )
{
    OSL_ENSURE( pDoc && !rBoxes.empty() && nCnt, "No valid values" );
    SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
    if( !pTableNd )
        return false;
 
    // TL_CHART2: splitting/merging of a number of cells or rows will usually make
    // the table too complex to be handled with chart.
    // Thus we tell the charts to use their own data provider and forget about this table
    pDoc->getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( this );
 
    SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());    // Delete HTML Layout
 
    // If the rows should get the same (min) height, we first have
    // to store the old row heights before deleting the frames
    long* pRowHeights = nullptr;
    if ( bSameHeight )
    {
        pRowHeights = new long[ rBoxes.size() ];
        for (size_t n = 0; n < rBoxes.size(); ++n)
        {
            SwTableBox* pSelBox = rBoxes[n];
            const SwRowFrame* pRow = GetRowFrame( *pSelBox->GetUpper() );
            OSL_ENSURE( pRow, "Where is the SwTableLine's Frame?" );
            SwRectFnSet aRectFnSet(pRow);
            pRowHeights[ n ] = aRectFnSet.GetHeight(pRow->getFrameArea());
        }
    }
 
    // Find Lines for the Layout update
    FndBox_ aFndBox( nullptr, nullptr );
    aFndBox.SetTableLines( rBoxes, *this );
    aFndBox.DelFrames( *this );
 
    for (size_t n = 0; n < rBoxes.size(); ++n)
    {
        SwTableBox* pSelBox = rBoxes[n];
        OSL_ENSURE( pSelBox, "Box is not within the Table" );
 
        // Insert nCnt new Lines into the Box
        SwTableLine* pInsLine = pSelBox->GetUpper();
        SwTableBoxFormat* pFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat());
 
        // Respect the Line's height, reset if needed
        SwFormatFrameSize aFSz( pInsLine->GetFrameFormat()->GetFrameSize() );
        if ( bSameHeight && ATT_VAR_SIZE == aFSz.GetHeightSizeType() )
            aFSz.SetHeightSizeType( ATT_MIN_SIZE );
 
        bool bChgLineSz = 0 != aFSz.GetHeight() || bSameHeight;
        if ( bChgLineSz )
            aFSz.SetHeight( ( bSameHeight ? pRowHeights[ n ] : aFSz.GetHeight() ) /
                             (nCnt + 1) );
 
        SwTableBox* pNewBox = new SwTableBox( pFrameFormat, nCnt, pInsLine );
        sal_uInt16 nBoxPos = pInsLine->GetBoxPos( pSelBox );
        pInsLine->GetTabBoxes()[nBoxPos] = pNewBox; // overwrite old one
 
        // Delete background/border attribute
        SwTableBox* pLastBox = pSelBox;         // To distribute the TextNodes!
        // If Areas are contained in the Box, it stays as is
        // !! If this is changed we need to adapt the Undo, too !!!
        bool bMoveNodes = true;
        {
            sal_uLong nSttNd = pLastBox->GetSttIdx() + 1,
                    nEndNd = pLastBox->GetSttNd()->EndOfSectionIndex();
            while( nSttNd < nEndNd )
                if( !pDoc->GetNodes()[ nSttNd++ ]->IsTextNode() )
                {
                    bMoveNodes = false;
                    break;
                }
        }
 
        SwTableBoxFormat* pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat());
        bool bChkBorder = nullptr != pCpyBoxFrameFormat->GetBox().GetTop();
        if( bChkBorder )
            pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->ClaimFrameFormat());
 
        for( sal_uInt16 i = 0; i <= nCnt; ++i )
        {
            // Create a new Line in the new Box
            SwTableLine* pNewLine = new SwTableLine(
                    static_cast<SwTableLineFormat*>(pInsLine->GetFrameFormat()), 1, pNewBox );
            if( bChgLineSz )
            {
                pNewLine->ClaimFrameFormat()->SetFormatAttr( aFSz );
            }
 
            pNewBox->GetTabLines().insert( pNewBox->GetTabLines().begin() + i, pNewLine );
            // then a new Box in the Line
            if( !i )        // hang up the original Box
            {
                pSelBox->SetUpper( pNewLine );
                pNewLine->GetTabBoxes().insert( pNewLine->GetTabBoxes().begin(), pSelBox );
            }
            else
            {
                ::InsTableBox( pDoc, pTableNd, pNewLine, pCpyBoxFrameFormat,
                                pLastBox, 0 );
 
                if( bChkBorder )
                {
                    pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pNewLine->GetTabBoxes()[ 0 ]->ClaimFrameFormat());
                    SvxBoxItem aTmp( pCpyBoxFrameFormat->GetBox() );
                    aTmp.SetLine( nullptr, SvxBoxItemLine::TOP );
                    pCpyBoxFrameFormat->SetFormatAttr( aTmp );
                    bChkBorder = false;
                }
 
                if( bMoveNodes )
                {
                    const SwNode* pEndNd = pLastBox->GetSttNd()->EndOfSectionNode();
                    if( pLastBox->GetSttIdx()+2 != pEndNd->GetIndex() )
                    {
                        // Move TextNodes
                        SwNodeRange aRg( *pLastBox->GetSttNd(), +2, *pEndNd );
                        pLastBox = pNewLine->GetTabBoxes()[0];  // reset
                        SwNodeIndex aInsPos( *pLastBox->GetSttNd(), 1 );
                        pDoc->GetNodes().MoveNodes(aRg, pDoc->GetNodes(), aInsPos, false);
                        pDoc->GetNodes().Delete( aInsPos ); // delete the empty one
                    }
                }
            }
        }
        // In Boxes with Lines, we can only have Size/Fillorder
        pFrameFormat = static_cast<SwTableBoxFormat*>(pNewBox->ClaimFrameFormat());
        pFrameFormat->ResetFormatAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
        pFrameFormat->ResetFormatAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
    }
 
    delete[] pRowHeights;
 
    GCLines();
 
    aFndBox.MakeFrames( *this );
 
    CHECKBOXWIDTH
    CHECKTABLELAYOUT
    return true;
}
 
bool SwTable::SplitCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt )
{
    OSL_ENSURE( pDoc && !rBoxes.empty() && nCnt, "No valid values" );
    SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
    if( !pTableNd )
        return false;
 
    // TL_CHART2: splitting/merging of a number of cells or rows will usually make
    // the table too complex to be handled with chart.
    // Thus we tell the charts to use their own data provider and forget about this table
    pDoc->getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( this );
 
    SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());    // Delete HTML Layout
    SwSelBoxes aSelBoxes(rBoxes);
    ExpandSelection( aSelBoxes );
 
    // Find Lines for the Layout update
    FndBox_ aFndBox( nullptr, nullptr );
    aFndBox.SetTableLines( aSelBoxes, *this );
    aFndBox.DelFrames( *this );
 
    CpyTabFrames aFrameArr;
    std::vector<SwTableBoxFormat*> aLastBoxArr;
    for (size_t n = 0; n < aSelBoxes.size(); ++n)
    {
        SwTableBox* pSelBox = aSelBoxes[n];
        OSL_ENSURE( pSelBox, "Box is not in the table" );
 
        // We don't want to split small table cells into very very small cells
        if( pSelBox->GetFrameFormat()->GetFrameSize().GetWidth()/( nCnt + 1 ) < 10 )
            continue;
 
        // Then split the nCnt Box up into nCnt Boxes
        SwTableLine* pInsLine = pSelBox->GetUpper();
        sal_uInt16 nBoxPos = pInsLine->GetBoxPos( pSelBox );
 
        // Find the Frame Format in the Frame Format Array
        SwTableBoxFormat* pLastBoxFormat;
        CpyTabFrame aFindFrame( static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat()) );
        CpyTabFrames::const_iterator itFind = aFrameArr.lower_bound( aFindFrame );
        const size_t nFndPos = itFind - aFrameArr.begin();
        if( itFind == aFrameArr.end() || !(*itFind == aFindFrame) )
        {
            // Change the FrameFormat
            aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->ClaimFrameFormat());
            SwTwips nBoxSz = aFindFrame.pNewFrameFormat->GetFrameSize().GetWidth();
            SwTwips nNewBoxSz = nBoxSz / ( nCnt + 1 );
            aFindFrame.pNewFrameFormat->SetFormatAttr( SwFormatFrameSize( ATT_VAR_SIZE,
                                                        nNewBoxSz, 0 ) );
            aFrameArr.insert( aFindFrame );
 
            pLastBoxFormat = aFindFrame.pNewFrameFormat;
            if( nBoxSz != ( nNewBoxSz * (nCnt + 1)))
            {
                // We have a remainder, so we need to define an own Format
                // for the last Box.
                pLastBoxFormat = new SwTableBoxFormat( *aFindFrame.pNewFrameFormat );
                pLastBoxFormat->SetFormatAttr( SwFormatFrameSize( ATT_VAR_SIZE,
                                nBoxSz - ( nNewBoxSz * nCnt ), 0 ) );
            }
            aLastBoxArr.insert( aLastBoxArr.begin() + nFndPos, pLastBoxFormat );
        }
        else
        {
            aFindFrame = aFrameArr[ nFndPos ];
            pSelBox->ChgFrameFormat( aFindFrame.pNewFrameFormat );
            pLastBoxFormat = aLastBoxArr[ nFndPos ];
        }
 
        // Insert the Boxes at the Position
        for( sal_uInt16 i = 1; i < nCnt; ++i )
            ::InsTableBox( pDoc, pTableNd, pInsLine, aFindFrame.pNewFrameFormat,
                        pSelBox, nBoxPos + i ); // insert after
 
        ::InsTableBox( pDoc, pTableNd, pInsLine, pLastBoxFormat,
                    pSelBox, nBoxPos + nCnt );  // insert after
 
        // Special treatment for the Border:
        const SvxBoxItem& aSelBoxItem = aFindFrame.pNewFrameFormat->GetBox();
        if( aSelBoxItem.GetRight() )
        {
            pInsLine->GetTabBoxes()[ nBoxPos + nCnt ]->ClaimFrameFormat();
 
            SvxBoxItem aTmp( aSelBoxItem );
            aTmp.SetLine( nullptr, SvxBoxItemLine::RIGHT );
            aFindFrame.pNewFrameFormat->SetFormatAttr( aTmp );
 
            // Remove the Format from the "cache"
            for( auto i = aFrameArr.size(); i; )
            {
                const CpyTabFrame& rCTF = aFrameArr[ --i ];
                if( rCTF.pNewFrameFormat == aFindFrame.pNewFrameFormat ||
                    rCTF.Value.pFrameFormat == aFindFrame.pNewFrameFormat )
                {
                    aFrameArr.erase( aFrameArr.begin() + i );
                    aLastBoxArr.erase( aLastBoxArr.begin() + i );
                }
            }
        }
    }
 
    // Update Layout
    aFndBox.MakeFrames( *this );
 
    CHECKBOXWIDTH
    CHECKTABLELAYOUT
    return true;
}
 
/*
 * >> MERGE <<
 * Algorithm:
 *    If we only have one Line in the FndBox_, take this Line and test
 *    the Box count:
 * If we have more than one Box, we merge on Box level, meaning
 *      the new Box will be as wide as the old ones.
 * All Lines that are above/under the Area, are inserted into
 *        the Box as Line + Box.
 * All Lines that come before/after the Area, are inserted into
 *          the Boxes Left/Right.
 *
 * >> MERGE <<
 */
static void lcl_CpyLines( sal_uInt16 nStt, sal_uInt16 nEnd,
                                SwTableLines& rLines,
                                SwTableBox* pInsBox,
                                sal_uInt16 nPos = USHRT_MAX )
{
    for( sal_uInt16 n = nStt; n < nEnd; ++n )
        rLines[n]->SetUpper( pInsBox );
    if( USHRT_MAX == nPos )
        nPos = pInsBox->GetTabLines().size();
    pInsBox->GetTabLines().insert( pInsBox->GetTabLines().begin() + nPos,
                             rLines.begin() + nStt, rLines.begin() + nEnd );
    rLines.erase( rLines.begin() + nStt, rLines.begin() + nEnd );
}
 
static void lcl_CpyBoxes( sal_uInt16 nStt, sal_uInt16 nEnd,
                                SwTableBoxes& rBoxes,
                                SwTableLine* pInsLine )
{
    for( sal_uInt16 n = nStt; n < nEnd; ++n )
        rBoxes[n]->SetUpper( pInsLine );
    sal_uInt16 nPos = pInsLine->GetTabBoxes().size();
    pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + nPos,
                              rBoxes.begin() + nStt, rBoxes.begin() + nEnd );
    rBoxes.erase( rBoxes.begin() + nStt, rBoxes.begin() + nEnd );
}
 
static void lcl_CalcWidth( SwTableBox* pBox )
{
    // Assertion: Every Line in the Box is as large
    SwFrameFormat* pFormat = pBox->ClaimFrameFormat();
    OSL_ENSURE( pBox->GetTabLines().size(), "Box does not have any Lines" );
 
    SwTableLine* pLine = pBox->GetTabLines()[0];
    OSL_ENSURE( pLine, "Box is not within a Line" );
 
    long nWidth = 0;
    for( auto pTabBox : pLine->GetTabBoxes() )
        nWidth += pTabBox->GetFrameFormat()->GetFrameSize().GetWidth();
 
    pFormat->SetFormatAttr( SwFormatFrameSize( ATT_VAR_SIZE, nWidth, 0 ));
 
    // Boxes with Lines can only have Size/Fillorder
    pFormat->ResetFormatAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
    pFormat->ResetFormatAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
}
 
struct InsULPara
{
    SwTableNode* pTableNd;
    SwTableLine* pInsLine;
    SwTableBox* pInsBox;
    bool bUL_LR : 1;        // Upper-Lower(true) or Left-Right(false) ?
    bool bUL : 1;           // Upper-Left(true) or Lower-Right(false) ?
 
    SwTableBox* pLeftBox;
 
    InsULPara( SwTableNode* pTNd,
                SwTableBox* pLeft,
                SwTableLine* pLine )
        : pTableNd( pTNd ), pInsLine( pLine ), pInsBox( nullptr ),
        pLeftBox( pLeft )
        {   bUL_LR = true; bUL = true; }
 
    void SetLeft( SwTableBox* pBox )
        { bUL_LR = false;   bUL = true; if( pBox ) pInsBox = pBox; }
    void SetRight( SwTableBox* pBox )
        { bUL_LR = false;   bUL = false; if( pBox ) pInsBox = pBox; }
    void SetLower( SwTableLine* pLine )
        { bUL_LR = true;    bUL = false; if( pLine ) pInsLine = pLine; }
};
 
static void lcl_Merge_MoveLine(FndLine_ & rFndLine, InsULPara *const pULPara);
 
static void lcl_Merge_MoveBox(FndBox_ & rFndBox, InsULPara *const pULPara)
{
    SwTableBoxes* pBoxes;
 
    sal_uInt16 nStt = 0, nEnd = rFndBox.GetLines().size();
    sal_uInt16 nInsPos = USHRT_MAX;
    if( !pULPara->bUL_LR )  // Left/Right
    {
        sal_uInt16 nPos;
        SwTableBox* pFndTableBox = rFndBox.GetBox();
        pBoxes = &pFndTableBox->GetUpper()->GetTabBoxes();
        if( pULPara->bUL )  // Left ?
        {
            // if there are Boxes before it, move them
            if( 0 != ( nPos = pFndTableBox->GetUpper()->GetBoxPos( pFndTableBox ) ) )
                lcl_CpyBoxes( 0, nPos, *pBoxes, pULPara->pInsLine );
        }
        else                // Right
            // if there are Boxes behind it, move them
            if( (nPos = pFndTableBox->GetUpper()->GetBoxPos( pFndTableBox )) +1 < static_cast<sal_uInt16>(pBoxes->size()) )
            {
                nInsPos = pULPara->pInsLine->GetTabBoxes().size();
                lcl_CpyBoxes( nPos+1, pBoxes->size(),
                                    *pBoxes, pULPara->pInsLine );
            }
    }
    // Upper/Lower and still deeper?
    else if (!rFndBox.GetLines().empty())
    {
        // Only search the Line from which we need to move
        nStt = pULPara->bUL ? 0 : rFndBox.GetLines().size()-1;
        nEnd = nStt+1;
    }
 
    pBoxes = &pULPara->pInsLine->GetTabBoxes();
 
    // Is there still a level to step down to?
    if (rFndBox.GetBox()->GetTabLines().size())
    {
        SwTableBox* pBox = new SwTableBox(
                static_cast<SwTableBoxFormat*>(rFndBox.GetBox()->GetFrameFormat()),
                0, pULPara->pInsLine );
        InsULPara aPara( *pULPara );
        aPara.pInsBox = pBox;
        for (FndLines_t::iterator it = rFndBox.GetLines().begin() + nStt;
             it != rFndBox.GetLines().begin() + nEnd; ++it )
        {
            lcl_Merge_MoveLine(**it, &aPara);
        }
        if( pBox->GetTabLines().size() )
        {
            if( USHRT_MAX == nInsPos )
                nInsPos = pBoxes->size();
            pBoxes->insert( pBoxes->begin() + nInsPos, pBox );
            lcl_CalcWidth( pBox );      // calculate the Box's width
        }
        else
            delete pBox;
    }
}
 
static void lcl_Merge_MoveLine(FndLine_& rFndLine, InsULPara *const pULPara)
{
    SwTableLines* pLines;
 
    sal_uInt16 nStt = 0, nEnd = rFndLine.GetBoxes().size();
    sal_uInt16 nInsPos = USHRT_MAX;
    if( pULPara->bUL_LR )   // UpperLower ?
    {
        sal_uInt16 nPos;
        SwTableLine* pFndLn = rFndLine.GetLine();
        pLines = pFndLn->GetUpper() ?
                        &pFndLn->GetUpper()->GetTabLines() :
                        &pULPara->pTableNd->GetTable().GetTabLines();
 
        SwTableBox* pLBx = rFndLine.GetBoxes().front()->GetBox();
        SwTableBox* pRBx = rFndLine.GetBoxes().back()->GetBox();
        sal_uInt16 nLeft = pFndLn->GetBoxPos( pLBx );
        sal_uInt16 nRight = pFndLn->GetBoxPos( pRBx );
 
        if( !nLeft || nRight == pFndLn->GetTabBoxes().size() )
        {
            if( pULPara->bUL )  // Upper ?
            {
                // If there are Lines before it, move them
                if( 0 != ( nPos = pLines->GetPos( pFndLn )) )
                    lcl_CpyLines( 0, nPos, *pLines, pULPara->pInsBox );
            }
            else
                // If there are Lines after it, move them
                if( (nPos = pLines->GetPos( pFndLn )) + 1 < static_cast<sal_uInt16>(pLines->size()) )
                {
                    nInsPos = pULPara->pInsBox->GetTabLines().size();
                    lcl_CpyLines( nPos+1, pLines->size(), *pLines,
                                        pULPara->pInsBox );
                }
        }
        else
        {
            // There are still Boxes on the left side, so put the Left-
            // and Merge-Box into one Box and Line, insert before/after
            // a Line with a Box, into which the upper/lower Lines are
            // inserted
            SwTableLine* pInsLine = pULPara->pLeftBox->GetUpper();
            SwTableBox* pLMBox = new SwTableBox(
                static_cast<SwTableBoxFormat*>(pULPara->pLeftBox->GetFrameFormat()), 0, pInsLine );
            SwTableLine* pLMLn = new SwTableLine(
                        static_cast<SwTableLineFormat*>(pInsLine->GetFrameFormat()), 2, pLMBox );
            pLMLn->ClaimFrameFormat()->ResetFormatAttr( RES_FRM_SIZE );
 
            pLMBox->GetTabLines().insert( pLMBox->GetTabLines().begin(), pLMLn );
 
            lcl_CpyBoxes( 0, 2, pInsLine->GetTabBoxes(), pLMLn );
 
            pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pLMBox );
 
            if( pULPara->bUL )  // Upper ?
            {
                // If there are Lines before it, move them
                if( 0 != ( nPos = pLines->GetPos( pFndLn )) )
                    lcl_CpyLines( 0, nPos, *pLines, pLMBox, 0 );
            }
            else
                // If there are Lines after it, move them
                if( (nPos = pLines->GetPos( pFndLn )) + 1 < static_cast<sal_uInt16>(pLines->size()) )
                    lcl_CpyLines( nPos+1, pLines->size(), *pLines,
                                        pLMBox );
            lcl_CalcWidth( pLMBox );        // calculate the Box's width
        }
    }
    // Left/Right
    else
    {
        // Find only the Line from which we need to move
        nStt = pULPara->bUL ? 0 : rFndLine.GetBoxes().size()-1;
        nEnd = nStt+1;
    }
    pLines = &pULPara->pInsBox->GetTabLines();
 
    SwTableLine* pNewLine = new SwTableLine(
        static_cast<SwTableLineFormat*>(rFndLine.GetLine()->GetFrameFormat()), 0, pULPara->pInsBox );
    InsULPara aPara( *pULPara );       // copying
    aPara.pInsLine = pNewLine;
    FndBoxes_t & rLineBoxes = rFndLine.GetBoxes();
    for (FndBoxes_t::iterator it = rLineBoxes.begin() + nStt;
         it != rLineBoxes.begin() + nEnd; ++it)
    {
        lcl_Merge_MoveBox(**it, &aPara);
    }
 
    if( !pNewLine->GetTabBoxes().empty() )
    {
        if( USHRT_MAX == nInsPos )
            nInsPos = pLines->size();
        pLines->insert( pLines->begin() + nInsPos, pNewLine );
    }
    else
        delete pNewLine;
}
 
static void lcl_BoxSetHeadCondColl( const SwTableBox* pBox );
 
bool SwTable::OldMerge( SwDoc* pDoc, const SwSelBoxes& rBoxes,
                        SwTableBox* pMergeBox, SwUndoTableMerge* pUndo )
{
    OSL_ENSURE( !rBoxes.empty() && pMergeBox, "no valid values" );
    SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
    if( !pTableNd )
        return false;
 
    // Find all Boxes/Lines
    FndBox_ aFndBox( nullptr, nullptr );
    {
        FndPara aPara( rBoxes, &aFndBox );
        ForEach_FndLineCopyCol( GetTabLines(), &aPara );
    }
    if( aFndBox.GetLines().empty() )
        return false;
 
    // TL_CHART2: splitting/merging of a number of cells or rows will usually make
    // the table too complex to be handled with chart.
    // Thus we tell the charts to use their own data provider and forget about this table
    pDoc->getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( this );
 
    SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());    // Delete HTML Layout
 
    if( pUndo )
        pUndo->SetSelBoxes( rBoxes );
 
    // Find Lines for the Layout update
    aFndBox.SetTableLines( *this );
    aFndBox.DelFrames( *this );
 
    FndBox_* pFndBox = &aFndBox;
    while( 1 == pFndBox->GetLines().size() &&
            1 == pFndBox->GetLines().front()->GetBoxes().size() )
    {
        pFndBox = pFndBox->GetLines().front()->GetBoxes().front().get();
    }
 
    SwTableLine* pInsLine = new SwTableLine(
                static_cast<SwTableLineFormat*>(pFndBox->GetLines().front()->GetLine()->GetFrameFormat()), 0,
                !pFndBox->GetUpper() ? nullptr : pFndBox->GetBox() );
    pInsLine->ClaimFrameFormat()->ResetFormatAttr( RES_FRM_SIZE );
 
    // Add the new Line
    SwTableLines* pLines =  pFndBox->GetUpper() ?
                  &pFndBox->GetBox()->GetTabLines() :  &GetTabLines();
 
    SwTableLine* pNewLine = pFndBox->GetLines().front()->GetLine();
    sal_uInt16 nInsPos = pLines->GetPos( pNewLine );
    pLines->insert( pLines->begin() + nInsPos, pInsLine );
 
    SwTableBox* pLeftBox = new SwTableBox( static_cast<SwTableBoxFormat*>(pMergeBox->GetFrameFormat()), 0, pInsLine );
    SwTableBox* pRightBox = new SwTableBox( static_cast<SwTableBoxFormat*>(pMergeBox->GetFrameFormat()), 0, pInsLine );
    pMergeBox->SetUpper( pInsLine );
    pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pLeftBox );
    pLeftBox->ClaimFrameFormat();
    pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + 1, pMergeBox);
    pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + 2, pRightBox );
    pRightBox->ClaimFrameFormat();
 
    // This contains all Lines that are above the selected Area,
    // thus they form a Upper/Lower Line
    InsULPara aPara( pTableNd, pLeftBox, pInsLine );
 
    // Move the overlapping upper/lower Lines of the selected Area
    for (auto & it : pFndBox->GetLines().front()->GetBoxes())
    {
        lcl_Merge_MoveBox(*it, &aPara);
    }
    aPara.SetLower( pInsLine );
    const auto nEnd = pFndBox->GetLines().size()-1;
    for (auto & it : pFndBox->GetLines()[nEnd]->GetBoxes())
    {
        lcl_Merge_MoveBox(*it, &aPara);
    }
 
    // Move the Boxes extending into the selected Area from left/right
    aPara.SetLeft( pLeftBox );
    for (auto & rpFndLine : pFndBox->GetLines())
    {
        lcl_Merge_MoveLine( *rpFndLine, &aPara );
    }
 
    aPara.SetRight( pRightBox );
    for (auto & rpFndLine : pFndBox->GetLines())
    {
        lcl_Merge_MoveLine( *rpFndLine, &aPara );
    }
 
    if( pLeftBox->GetTabLines().empty() )
        DeleteBox_( *this, pLeftBox, nullptr, false, false );
    else
    {
        lcl_CalcWidth( pLeftBox );      // calculate the Box's width
        if( pUndo && pLeftBox->GetSttNd() )
            pUndo->AddNewBox( pLeftBox->GetSttIdx() );
    }
    if( pRightBox->GetTabLines().empty() )
        DeleteBox_( *this, pRightBox, nullptr, false, false );
    else
    {
        lcl_CalcWidth( pRightBox );     // calculate the Box's width
        if( pUndo && pRightBox->GetSttNd() )
            pUndo->AddNewBox( pRightBox->GetSttIdx() );
    }
 
    DeleteSel( pDoc, rBoxes, nullptr, nullptr, false, false );
 
    // Clean up this Line's structure once again, generally all of them
    GCLines();
 
    for( SwTableBoxes::iterator it = GetTabLines()[0]->GetTabBoxes().begin();
             it != GetTabLines()[0]->GetTabBoxes().end(); ++it)
        lcl_BoxSetHeadCondColl(*it);
 
    aFndBox.MakeFrames( *this );
 
    CHECKBOXWIDTH
    CHECKTABLELAYOUT
 
    return true;
}
 
static void lcl_CheckRowSpan( SwTable &rTable )
{
    const long nLineCount = static_cast<long>(rTable.GetTabLines().size());
    long nMaxSpan = nLineCount;
    long nMinSpan = 1;
    while( nMaxSpan )
    {
        SwTableLine* pLine = rTable.GetTabLines()[ nLineCount - nMaxSpan ];
        for( auto pBox : pLine->GetTabBoxes() )
        {
            long nRowSpan = pBox->getRowSpan();
            if( nRowSpan > nMaxSpan )
                pBox->setRowSpan( nMaxSpan );
            else if( nRowSpan < nMinSpan )
                pBox->setRowSpan( nMinSpan > 0 ? nMaxSpan : nMinSpan );
        }
        --nMaxSpan;
        nMinSpan = -nMaxSpan;
    }
}
 
static sal_uInt16 lcl_GetBoxOffset( const FndBox_& rBox )
{
    // Find the first Box
    const FndBox_* pFirstBox = &rBox;
    while (!pFirstBox->GetLines().empty())
    {
        pFirstBox = pFirstBox->GetLines().front()->GetBoxes().front().get();
    }
 
    sal_uInt16 nRet = 0;
    // Calculate the position relative to above via the Lines
    const SwTableBox* pBox = pFirstBox->GetBox();
    do {
        const SwTableBoxes& rBoxes = pBox->GetUpper()->GetTabBoxes();
        for( auto pCmp : rBoxes )
        {
            if (pBox==pCmp)
                break;
            nRet = nRet + static_cast<sal_uInt16>(pCmp->GetFrameFormat()->GetFrameSize().GetWidth());
        }
        pBox = pBox->GetUpper()->GetUpper();
    } while( pBox );
    return nRet;
}
 
static sal_uInt16 lcl_GetLineWidth( const FndLine_& rLine )
{
    sal_uInt16 nRet = 0;
    for( auto n = rLine.GetBoxes().size(); n; )
    {
        nRet = nRet + static_cast<sal_uInt16>(rLine.GetBoxes()[--n]->GetBox()
                            ->GetFrameFormat()->GetFrameSize().GetWidth());
    }
    return nRet;
}
 
static void lcl_CalcNewWidths(const FndLines_t& rFndLines, CpyPara& rPara)
{
    rPara.pWidths.reset();
    const size_t nLineCount = rFndLines.size();
    if( nLineCount )
    {
        rPara.pWidths = std::make_shared< std::vector< std::vector< sal_uLong > > >
                        ( nLineCount );
        // First we collect information about the left/right borders of all
        // selected cells
        for( size_t nLine = 0; nLine < nLineCount; ++nLine )
        {
            std::vector< sal_uLong > &rWidth = (*rPara.pWidths.get())[ nLine ];
            const FndLine_ *pFndLine = rFndLines[ nLine ].get();
            if( pFndLine && pFndLine->GetBoxes().size() )
            {
                const SwTableLine *pLine = pFndLine->GetLine();
                if( pLine && !pLine->GetTabBoxes().empty() )
                {
                    size_t nBoxCount = pLine->GetTabBoxes().size();
                    sal_uLong nPos = 0;
                    // The first selected box...
                    const SwTableBox *const pSel =
                        pFndLine->GetBoxes().front()->GetBox();
                    size_t nBox = 0;
                    // Sum up the width of all boxes before the first selected box
                    while( nBox < nBoxCount )
                    {
                        SwTableBox* pBox = pLine->GetTabBoxes()[nBox++];
                        if( pBox != pSel )
                            nPos += pBox->GetFrameFormat()->GetFrameSize().GetWidth();
                        else
                            break;
                    }
                    // nPos is now the left border of the first selected box
                    if( rPara.nMinLeft > nPos )
                        rPara.nMinLeft = nPos;
                    nBoxCount = pFndLine->GetBoxes().size();
                    rWidth = std::vector< sal_uLong >( nBoxCount+2 );
                    rWidth[ 0 ] = nPos;
                    // Add now the widths of all selected boxes and store
                    // the positions in the vector
                    for( nBox = 0; nBox < nBoxCount; )
                    {
                        nPos += pFndLine->GetBoxes()[nBox]
                            ->GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
                        rWidth[ ++nBox ] = nPos;
                    }
                    // nPos: The right border of the last selected box
                    if( rPara.nMaxRight < nPos )
                        rPara.nMaxRight = nPos;
                    if( nPos <= rWidth[ 0 ] )
                        rWidth.clear();
                }
            }
        }
    }
    // Second step: calculate the new widths for the copied cells
    sal_uLong nSelSize = rPara.nMaxRight - rPara.nMinLeft;
    if( nSelSize )
    {
        for( size_t nLine = 0; nLine < nLineCount; ++nLine )
        {
            std::vector< sal_uLong > &rWidth = (*rPara.pWidths.get())[ nLine ];
            const size_t nCount = rWidth.size();
            if( nCount > 2 )
            {
                rWidth[ nCount - 1 ] = rPara.nMaxRight;
                sal_uLong nLastPos = 0;
                for( size_t nBox = 0; nBox < nCount; ++nBox )
                {
                    sal_uInt64 nNextPos = rWidth[ nBox ];
                    nNextPos -= rPara.nMinLeft;
                    nNextPos *= rPara.nNewSize;
                    nNextPos /= nSelSize;
                    rWidth[ nBox ] = static_cast<sal_uLong>(nNextPos - nLastPos);
                    nLastPos = static_cast<sal_uLong>(nNextPos);
                }
            }
        }
    }
}
 
static void
lcl_CopyLineToDoc(FndLine_ const& rpFndLn, CpyPara *const pCpyPara);
 
static void lcl_CopyBoxToDoc(FndBox_ const& rFndBox, CpyPara *const pCpyPara)
{
    // Calculation of new size
    sal_uLong nRealSize;
    sal_uLong nDummy1 = 0;
    sal_uLong nDummy2 = 0;
    if( pCpyPara->pTableNd->GetTable().IsNewModel() )
    {
        if( pCpyPara->nBoxIdx == 1 )
            nDummy1 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][0];
        nRealSize = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx++];
        if( pCpyPara->nBoxIdx == (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx].size()-1 )
            nDummy2 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx];
    }
    else
    {
        nRealSize = pCpyPara->nNewSize;
        nRealSize *= rFndBox.GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
        if (pCpyPara->nOldSize == 0)
            throw o3tl::divide_by_zero();
        nRealSize /= pCpyPara->nOldSize;
    }
 
    sal_uLong nSize;
    bool bDummy = nDummy1 > 0;
    if( bDummy )
        nSize = nDummy1;
    else
    {
        nSize = nRealSize;
        nRealSize = 0;
    }
    do
    {
        // Find the Frame Format in the list of all Frame Formats
        CpyTabFrame aFindFrame(static_cast<SwTableBoxFormat*>(rFndBox.GetBox()->GetFrameFormat()));
 
        SwFormatFrameSize aFrameSz;
        CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.lower_bound( aFindFrame );
        const CpyTabFrames::size_type nFndPos = itFind - pCpyPara->rTabFrameArr.begin();
        if( itFind == pCpyPara->rTabFrameArr.end() || !(*itFind == aFindFrame) ||
            ( aFrameSz = ( aFindFrame = pCpyPara->rTabFrameArr[ nFndPos ]).pNewFrameFormat->
                GetFrameSize()).GetWidth() != static_cast<SwTwips>(nSize) )
        {
            // It doesn't exist yet, so copy it
            aFindFrame.pNewFrameFormat = pCpyPara->pDoc->MakeTableBoxFormat();
            aFindFrame.pNewFrameFormat->CopyAttrs( *rFndBox.GetBox()->GetFrameFormat() );
            if( !pCpyPara->bCpyContent )
                aFindFrame.pNewFrameFormat->ResetFormatAttr(  RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
            aFrameSz.SetWidth( nSize );
            aFindFrame.pNewFrameFormat->SetFormatAttr( aFrameSz );
            pCpyPara->rTabFrameArr.insert( aFindFrame );
        }
 
        SwTableBox* pBox;
        if (!rFndBox.GetLines().empty())
        {
            pBox = new SwTableBox( aFindFrame.pNewFrameFormat,
                        rFndBox.GetLines().size(), pCpyPara->pInsLine );
            pCpyPara->pInsLine->GetTabBoxes().insert( pCpyPara->pInsLine->GetTabBoxes().begin() + pCpyPara->nInsPos++, pBox );
            CpyPara aPara( *pCpyPara, pBox );
            aPara.nNewSize = nSize;     // get the size
            for (auto const& rpFndLine : rFndBox.GetLines())
            {
                lcl_CopyLineToDoc( *rpFndLine, &aPara );
            }
        }
        else
        {
            // Create an empty Box
            pCpyPara->pDoc->GetNodes().InsBoxen( pCpyPara->pTableNd, pCpyPara->pInsLine,
                            aFindFrame.pNewFrameFormat,
                            pCpyPara->pDoc->GetDfltTextFormatColl(),
                            nullptr, pCpyPara->nInsPos );
            pBox = pCpyPara->pInsLine->GetTabBoxes()[ pCpyPara->nInsPos ];
            if( bDummy )
                pBox->setDummyFlag( true );
            else if( pCpyPara->bCpyContent )
            {
                // Copy the content into this empty Box
                pBox->setRowSpan(rFndBox.GetBox()->getRowSpan());
 
                // We can also copy formulas and values, if we copy the content
                {
                    SfxItemSet aBoxAttrSet( pCpyPara->pDoc->GetAttrPool(),
                                            svl::Items<RES_BOXATR_FORMAT, RES_BOXATR_VALUE>{} );
                    aBoxAttrSet.Put(rFndBox.GetBox()->GetFrameFormat()->GetAttrSet());
                    if( aBoxAttrSet.Count() )
                    {
                        const SfxPoolItem* pItem;
                        SvNumberFormatter* pN = pCpyPara->pDoc->GetNumberFormatter( false );
                        if( pN && pN->HasMergeFormatTable() && SfxItemState::SET == aBoxAttrSet.
                            GetItemState( RES_BOXATR_FORMAT, false, &pItem ) )
                        {
                            sal_uLong nOldIdx = static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue();
                            sal_uLong nNewIdx = pN->GetMergeFormatIndex( nOldIdx );
                            if( nNewIdx != nOldIdx )
                                aBoxAttrSet.Put( SwTableBoxNumFormat( nNewIdx ));
                        }
                        pBox->ClaimFrameFormat()->SetFormatAttr( aBoxAttrSet );
                    }
                }
                SwDoc* pFromDoc = rFndBox.GetBox()->GetFrameFormat()->GetDoc();
                SwNodeRange aCpyRg( *rFndBox.GetBox()->GetSttNd(), 1,
                        *rFndBox.GetBox()->GetSttNd()->EndOfSectionNode() );
                SwNodeIndex aInsIdx( *pBox->GetSttNd(), 1 );
 
                pFromDoc->GetDocumentContentOperationsManager().CopyWithFlyInFly( aCpyRg, 0, aInsIdx, nullptr, false );
                // Delete the initial TextNode
                pCpyPara->pDoc->GetNodes().Delete( aInsIdx );
            }
            ++pCpyPara->nInsPos;
        }
        if( nRealSize )
        {
            bDummy = false;
            nSize = nRealSize;
            nRealSize = 0;
        }
        else
        {
            bDummy = true;
            nSize = nDummy2;
            nDummy2 = 0;
        }
    }
    while( nSize );
}
 
static void
lcl_CopyLineToDoc(const FndLine_& rFndLine, CpyPara *const pCpyPara)
{
    // Find the Frame Format in the list of all Frame Formats
    CpyTabFrame aFindFrame( rFndLine.GetLine()->GetFrameFormat() );
    CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.find( aFindFrame );
    if( itFind == pCpyPara->rTabFrameArr.end() )
    {
        // It doesn't exist yet, so copy it
        aFindFrame.pNewFrameFormat = reinterpret_cast<SwTableBoxFormat*>(pCpyPara->pDoc->MakeTableLineFormat());
        aFindFrame.pNewFrameFormat->CopyAttrs( *rFndLine.GetLine()->GetFrameFormat() );
        pCpyPara->rTabFrameArr.insert( aFindFrame );
    }
    else
        aFindFrame = *itFind;
 
    SwTableLine* pNewLine = new SwTableLine( reinterpret_cast<SwTableLineFormat*>(aFindFrame.pNewFrameFormat),
                        rFndLine.GetBoxes().size(), pCpyPara->pInsBox );
    if( pCpyPara->pInsBox )
    {
        SwTableLines& rLines = pCpyPara->pInsBox->GetTabLines();
        rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
    }
    else
    {
        SwTableLines& rLines = pCpyPara->pTableNd->GetTable().GetTabLines();
        rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine);
    }
 
    CpyPara aPara( *pCpyPara, pNewLine );
 
    if( pCpyPara->pTableNd->GetTable().IsNewModel() )
    {
        aPara.nOldSize = 0; // will not be used
        aPara.nBoxIdx = 1;
    }
    else if( rFndLine.GetBoxes().size() ==
                    rFndLine.GetLine()->GetTabBoxes().size() )
    {
        // Get the Parent's size
        const SwFrameFormat* pFormat;
 
        if( rFndLine.GetLine()->GetUpper() )
            pFormat = rFndLine.GetLine()->GetUpper()->GetFrameFormat();
        else
            pFormat = pCpyPara->pTableNd->GetTable().GetFrameFormat();
        aPara.nOldSize = pFormat->GetFrameSize().GetWidth();
    }
    else
        // Calculate it
        for (auto &rpBox : rFndLine.GetBoxes())
        {
            aPara.nOldSize += rpBox->GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
        }
 
    const FndBoxes_t& rBoxes = rFndLine.GetBoxes();
    for (auto const& it : rBoxes)
    {
        lcl_CopyBoxToDoc(*it, &aPara);
    }
    if( pCpyPara->pTableNd->GetTable().IsNewModel() )
        ++pCpyPara->nLnIdx;
}
 
void SwTable::CopyHeadlineIntoTable( SwTableNode& rTableNd )
{
    // Find all Boxes/Lines
    SwSelBoxes aSelBoxes;
    SwTableBox* pBox = GetTabSortBoxes()[ 0 ];
    pBox = GetTableBox( pBox->GetSttNd()->StartOfSectionNode()->GetIndex() + 1 );
    SelLineFromBox( pBox, aSelBoxes );
 
    FndBox_ aFndBox( nullptr, nullptr );
    {
        FndPara aPara( aSelBoxes, &aFndBox );
        ForEach_FndLineCopyCol( GetTabLines(), &aPara );
    }
    if( aFndBox.GetLines().empty() )
        return;
 
    {
        // Convert Table formulas to their relative representation
        SwTableFormulaUpdate aMsgHint( this );
        aMsgHint.m_eFlags = TBL_RELBOXNAME;
        GetFrameFormat()->GetDoc()->getIDocumentFieldsAccess().UpdateTableFields( &aMsgHint );
    }
 
    CpyTabFrames aCpyFormat;
    CpyPara aPara( &rTableNd, 1, aCpyFormat );
    aPara.nNewSize = aPara.nOldSize = rTableNd.GetTable().GetFrameFormat()->GetFrameSize().GetWidth();
    // Copy
    if( IsNewModel() )
        lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
    for (auto & rpFndLine : aFndBox.GetLines())
    {
         lcl_CopyLineToDoc( *rpFndLine, &aPara );
    }
    if( rTableNd.GetTable().IsNewModel() )
    {   // The copied line must not contain any row span attributes > 1
        SwTableLine* pLine = rTableNd.GetTable().GetTabLines()[0];
        OSL_ENSURE( !pLine->GetTabBoxes().empty(), "Empty Table Line" );
        for( auto pTableBox : pLine->GetTabBoxes() )
        {
            OSL_ENSURE( pTableBox, "Missing Table Box" );
            pTableBox->setRowSpan( 1 );
        }
    }
}
 
bool SwTable::MakeCopy( SwDoc* pInsDoc, const SwPosition& rPos,
                        const SwSelBoxes& rSelBoxes,
                        bool bCpyName ) const
{
    // Find all Boxes/Lines
    FndBox_ aFndBox( nullptr, nullptr );
    {
        FndPara aPara( rSelBoxes, &aFndBox );
        ForEach_FndLineCopyCol( const_cast<SwTableLines&>(GetTabLines()), &aPara );
    }
    if( aFndBox.GetLines().empty() )
        return false;
 
    // First copy the PoolTemplates for the Table, so that the Tables are
    // actually copied and have valid values.
    SwDoc* pSrcDoc = GetFrameFormat()->GetDoc();
    if( pSrcDoc != pInsDoc )
    {
        pInsDoc->CopyTextColl( *pSrcDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TABLE ) );
        pInsDoc->CopyTextColl( *pSrcDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TABLE_HDLN ) );
    }
 
    SwTable* pNewTable = const_cast<SwTable*>(pInsDoc->InsertTable(
            SwInsertTableOptions( SwInsertTableFlags::HeadlineNoBorder, 1 ),
            rPos, 1, 1, GetFrameFormat()->GetHoriOrient().GetHoriOrient(),
            nullptr, nullptr, false, IsNewModel() ));
    if( !pNewTable )
        return false;
 
    SwNodeIndex aIdx( rPos.nNode, -1 );
    SwTableNode* pTableNd = aIdx.GetNode().FindTableNode();
    ++aIdx;
    OSL_ENSURE( pTableNd, "Where is the TableNode now?" );
 
    pTableNd->GetTable().SetRowsToRepeat( GetRowsToRepeat() );
 
    pNewTable->SetTableStyleName(pTableNd->GetTable().GetTableStyleName());
 
    if( auto pSwDDETable = dynamic_cast<const SwDDETable*>(this) )
    {
        // A DDE-Table is being copied
        // Does the new Document actually have it's FieldType?
        SwFieldType* pFieldType = pInsDoc->getIDocumentFieldsAccess().InsertFieldType(
                                    *pSwDDETable->GetDDEFieldType() );
        OSL_ENSURE( pFieldType, "unknown FieldType" );
 
        // Change the Table Pointer at the Node
        pNewTable = new SwDDETable( *pNewTable,
                                 static_cast<SwDDEFieldType*>(pFieldType) );
        pTableNd->SetNewTable( std::unique_ptr<SwTable>(pNewTable), false );
    }
 
    pNewTable->GetFrameFormat()->CopyAttrs( *GetFrameFormat() );
    pNewTable->SetTableChgMode( GetTableChgMode() );
 
    // Destroy the already created Frames
    pTableNd->DelFrames();
 
    {
        // Conver the Table formulas to their relative representation
        SwTableFormulaUpdate aMsgHint( this );
        aMsgHint.m_eFlags = TBL_RELBOXNAME;
        pSrcDoc->getIDocumentFieldsAccess().UpdateTableFields( &aMsgHint );
    }
 
    SwTableNumFormatMerge aTNFM( *pSrcDoc, *pInsDoc );
 
    // Also copy Names or enforce a new unique one
    if( bCpyName )
        pNewTable->GetFrameFormat()->SetName( GetFrameFormat()->GetName() );
 
    CpyTabFrames aCpyFormat;
    CpyPara aPara( pTableNd, 1, aCpyFormat );
    aPara.nNewSize = aPara.nOldSize = GetFrameFormat()->GetFrameSize().GetWidth();
 
    if( IsNewModel() )
        lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
    // Copy
    for (auto & rpFndLine : aFndBox.GetLines())
    {
         lcl_CopyLineToDoc( *rpFndLine, &aPara );
    }
 
    // Set the "right" margin above/below
    {
        FndLine_* pFndLn = aFndBox.GetLines().front().get();
        SwTableLine* pLn = pFndLn->GetLine();
        const SwTableLine* pTmp = pLn;
        sal_uInt16 nLnPos = GetTabLines().GetPos( pTmp );
        if( USHRT_MAX != nLnPos && nLnPos )
        {
            // There is a Line before it
            SwCollectTableLineBoxes aLnPara( false, SplitTable_HeadlineOption::BorderCopy );
 
            pLn = GetTabLines()[ nLnPos - 1 ];
            for( SwTableBoxes::iterator it = pLn->GetTabBoxes().begin();
                     it != pLn->GetTabBoxes().end(); ++it)
                sw_Box_CollectBox( *it, &aLnPara );
 
            if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
                                lcl_GetLineWidth( *pFndLn )) )
            {
                aLnPara.SetValues( true );
                pLn = pNewTable->GetTabLines()[ 0 ];
                for( SwTableBoxes::iterator it = pLn->GetTabBoxes().begin();
                         it != pLn->GetTabBoxes().end(); ++it)
                    sw_BoxSetSplitBoxFormats(*it, &aLnPara );
            }
        }
 
        pFndLn = aFndBox.GetLines().back().get();
        pLn = pFndLn->GetLine();
        pTmp = pLn;
        nLnPos = GetTabLines().GetPos( pTmp );
        if( nLnPos < GetTabLines().size() - 1 )
        {
            // There is a Line following it
            SwCollectTableLineBoxes aLnPara( true, SplitTable_HeadlineOption::BorderCopy );
 
            pLn = GetTabLines()[ nLnPos + 1 ];
            for( SwTableBoxes::iterator it = pLn->GetTabBoxes().begin();
                     it != pLn->GetTabBoxes().end(); ++it)
                sw_Box_CollectBox( *it, &aLnPara );
 
            if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
                                lcl_GetLineWidth( *pFndLn )) )
            {
                aLnPara.SetValues( false );
                pLn = pNewTable->GetTabLines().back();
                for( SwTableBoxes::iterator it = pLn->GetTabBoxes().begin();
                         it != pLn->GetTabBoxes().end(); ++it)
                    sw_BoxSetSplitBoxFormats(*it, &aLnPara );
            }
        }
    }
 
    // We need to delete the initial Box
    DeleteBox_( *pNewTable, pNewTable->GetTabLines().back()->GetTabBoxes()[0],
                nullptr, false, false );
 
    if( pNewTable->IsNewModel() )
        lcl_CheckRowSpan( *pNewTable );
    // Clean up
    pNewTable->GCLines();
 
    pTableNd->MakeFrames( &aIdx );  // re-generate the Frames
 
    CHECKTABLELAYOUT
 
    return true;
}
 
// Find the next Box with content from this Line
SwTableBox* SwTableLine::FindNextBox( const SwTable& rTable,
                     const SwTableBox* pSrchBox, bool bOvrTableLns ) const
{
    const SwTableLine* pLine = this;            // for M800
    SwTableBox* pBox;
    sal_uInt16 nFndPos;
    if( !GetTabBoxes().empty() && pSrchBox &&
        USHRT_MAX != ( nFndPos = GetBoxPos( pSrchBox )) &&
        nFndPos + 1 != static_cast<sal_uInt16>(GetTabBoxes().size()) )
    {
        pBox = GetTabBoxes()[ nFndPos + 1 ];
        while( !pBox->GetTabLines().empty() )
            pBox = pBox->GetTabLines().front()->GetTabBoxes()[0];
        return pBox;
    }
 
    if( GetUpper() )
    {
        nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
        OSL_ENSURE( USHRT_MAX != nFndPos, "Line is not in the Table" );
        // Is there another Line?
        if( nFndPos+1 >= static_cast<sal_uInt16>(GetUpper()->GetTabLines().size()) )
            return GetUpper()->GetUpper()->FindNextBox( rTable, GetUpper(), bOvrTableLns );
        pLine = GetUpper()->GetTabLines()[nFndPos+1];
    }
    else if( bOvrTableLns )       // Over a Table's the "BaseLines"??
    {
        // Search for the next Line in the Table
        nFndPos = rTable.GetTabLines().GetPos( pLine );
        if( nFndPos + 1 >= static_cast<sal_uInt16>(rTable.GetTabLines().size()) )
            return nullptr;           // there are no more Boxes
 
        pLine = rTable.GetTabLines()[ nFndPos+1 ];
    }
    else
        return nullptr;
 
    if( !pLine->GetTabBoxes().empty() )
    {
        pBox = pLine->GetTabBoxes().front();
        while( !pBox->GetTabLines().empty() )
            pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
        return pBox;
    }
    return pLine->FindNextBox( rTable, nullptr, bOvrTableLns );
}
 
// Find the previous Box from this Line
SwTableBox* SwTableLine::FindPreviousBox( const SwTable& rTable,
                         const SwTableBox* pSrchBox, bool bOvrTableLns ) const
{
    const SwTableLine* pLine = this;            // for M800
    SwTableBox* pBox;
    sal_uInt16 nFndPos;
    if( !GetTabBoxes().empty() && pSrchBox &&
        USHRT_MAX != ( nFndPos = GetBoxPos( pSrchBox )) &&
        nFndPos )
    {
        pBox = GetTabBoxes()[ nFndPos - 1 ];
        while( !pBox->GetTabLines().empty() )
        {
            pLine = pBox->GetTabLines().back();
            pBox = pLine->GetTabBoxes().back();
        }
        return pBox;
    }
 
    if( GetUpper() )
    {
        nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
        OSL_ENSURE( USHRT_MAX != nFndPos, "Line is not in the Table" );
        // Is there another Line?
        if( !nFndPos )
            return GetUpper()->GetUpper()->FindPreviousBox( rTable, GetUpper(), bOvrTableLns );
        pLine = GetUpper()->GetTabLines()[nFndPos-1];
    }
    else if( bOvrTableLns )       // Over a Table's the "BaseLines"??
    {
        // Search for the next Line in the Table
        nFndPos = rTable.GetTabLines().GetPos( pLine );
        if( !nFndPos )
            return nullptr;           // there are no more Boxes
 
        pLine = rTable.GetTabLines()[ nFndPos-1 ];
    }
    else
        return nullptr;
 
    if( !pLine->GetTabBoxes().empty() )
    {
        pBox = pLine->GetTabBoxes().back();
        while( !pBox->GetTabLines().empty() )
        {
            pLine = pBox->GetTabLines().back();
            pBox = pLine->GetTabBoxes().back();
        }
        return pBox;
    }
    return pLine->FindPreviousBox( rTable, nullptr, bOvrTableLns );
}
 
// Find the next Box with content from this Line
SwTableBox* SwTableBox::FindNextBox( const SwTable& rTable,
                         const SwTableBox* pSrchBox, bool bOvrTableLns ) const
{
    if( !pSrchBox  && GetTabLines().empty() )
        return const_cast<SwTableBox*>(this);
    return GetUpper()->FindNextBox( rTable, pSrchBox ? pSrchBox : this,
                                        bOvrTableLns );
 
}
 
// Find the next Box with content from this Line
SwTableBox* SwTableBox::FindPreviousBox( const SwTable& rTable,
                         const SwTableBox* pSrchBox ) const
{
    if( !pSrchBox && GetTabLines().empty() )
        return const_cast<SwTableBox*>(this);
    return GetUpper()->FindPreviousBox( rTable, pSrchBox ? pSrchBox : this );
}
 
static void lcl_BoxSetHeadCondColl( const SwTableBox* pBox )
{
    // We need to adapt the paragraphs with conditional templates in the HeadLine
    const SwStartNode* pSttNd = pBox->GetSttNd();
    if( pSttNd )
        pSttNd->CheckSectionCondColl();
    else
        for( const SwTableLine* pLine : pBox->GetTabLines() )
            sw_LineSetHeadCondColl( pLine );
}
 
void sw_LineSetHeadCondColl( const SwTableLine* pLine )
{
    for( const SwTableBox* pBox : pLine->GetTabBoxes() )
        lcl_BoxSetHeadCondColl(pBox);
}
 
static SwTwips lcl_GetDistance( SwTableBox* pBox, bool bLeft )
{
    bool bFirst = true;
    SwTwips nRet = 0;
    SwTableLine* pLine;
    while( pBox && nullptr != ( pLine = pBox->GetUpper() ) )
    {
        sal_uInt16 nStt = 0, nPos = pLine->GetBoxPos( pBox );
 
        if( bFirst && !bLeft )
            ++nPos;
        bFirst = false;
 
        while( nStt < nPos )
            nRet += pLine->GetTabBoxes()[ nStt++ ]->GetFrameFormat()
                            ->GetFrameSize().GetWidth();
        pBox = pLine->GetUpper();
    }
    return nRet;
}
 
static bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                         SwTwips nDist, bool bCheck )
{
    SwTableBoxes& rBoxes = pLine->GetTabBoxes();
    for( auto pBox : rBoxes )
    {
        SwFrameFormat* pFormat = pBox->GetFrameFormat();
        const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
        SwTwips nWidth = rSz.GetWidth();
        bool bGreaterBox = false;
 
        if( bCheck )
        {
            for( auto pLn : pBox->GetTabLines() )
                if( !::lcl_SetSelBoxWidth( pLn, rParam, nDist, true ))
                    return false;
 
            // Collect all "ContentBoxes"
            bGreaterBox = (TableChgMode::FixedWidthChangeAbs != rParam.nMode)
                       && ((nDist + (rParam.bLeft ? 0 : nWidth)) >= rParam.nSide);
            if (bGreaterBox
                || (!rParam.bBigger
                    && (std::abs(nDist + ((rParam.nMode != TableChgMode::FixedWidthChangeAbs && rParam.bLeft) ? 0 : nWidth) - rParam.nSide) < COLFUZZY)))
            {
                rParam.bAnyBoxFnd = true;
                SwTwips nLowerDiff;
                if( bGreaterBox && TableChgMode::FixedWidthChangeProp == rParam.nMode )
                {
                    // The "other Boxes" have been adapted, so change by this value
                    nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
                    nLowerDiff *= rParam.nDiff;
                    nLowerDiff /= rParam.nMaxSize;
                    nLowerDiff = rParam.nDiff - nLowerDiff;
                }
                else
                    nLowerDiff = rParam.nDiff;
 
                if( nWidth < nLowerDiff || nWidth - nLowerDiff < MINLAY )
                    return false;
            }
        }
        else
        {
            SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
            for( auto pLn : pBox->GetTabLines() )
            {
                rParam.nLowerDiff = 0;
                lcl_SetSelBoxWidth( pLn, rParam, nDist, false );
 
                if( nLowerDiff < rParam.nLowerDiff )
                    nLowerDiff = rParam.nLowerDiff;
            }
            rParam.nLowerDiff = nOldLower;
 
            if( nLowerDiff ||
                 (bGreaterBox = !nOldLower && TableChgMode::FixedWidthChangeAbs != rParam.nMode &&
                    ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide) ||
                ( std::abs( nDist + ( (rParam.nMode != TableChgMode::FixedWidthChangeAbs && rParam.bLeft) ? 0 : nWidth )
                            - rParam.nSide ) < COLFUZZY ))
            {
                // This column contains the Cursor - so decrease/increase
                SwFormatFrameSize aNew( rSz );
 
                if( !nLowerDiff )
                {
                    if( bGreaterBox && TableChgMode::FixedWidthChangeProp == rParam.nMode )
                    {
                        // The "other Boxes" have been adapted, so change by this value
                        nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
                        nLowerDiff *= rParam.nDiff;
                        nLowerDiff /= rParam.nMaxSize;
                        nLowerDiff = rParam.nDiff - nLowerDiff;
                    }
                    else
                        nLowerDiff = rParam.nDiff;
                }
 
                rParam.nLowerDiff += nLowerDiff;
 
                if( rParam.bBigger )
                    aNew.SetWidth( nWidth + nLowerDiff );
                else
                    aNew.SetWidth( nWidth - nLowerDiff );
                rParam.aShareFormats.SetSize( *pBox, aNew );
                break;
            }
        }
 
        if( rParam.bLeft && rParam.nMode != TableChgMode::FixedWidthChangeAbs && nDist >= rParam.nSide )
            break;
 
        nDist += nWidth;
 
        // If it gets bigger, then that's it
        if( ( TableChgMode::FixedWidthChangeAbs == rParam.nMode || !rParam.bLeft ) &&
                nDist >= rParam.nSide )
            break;
    }
    return true;
}
 
static bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                                SwTwips nDist, bool bCheck )
{
    SwTableBoxes& rBoxes = pLine->GetTabBoxes();
    for( auto pBox : rBoxes )
    {
        SwFrameFormat* pFormat = pBox->GetFrameFormat();
        const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
        SwTwips nWidth = rSz.GetWidth();
 
        if( bCheck )
        {
            for( auto pLn : pBox->GetTabLines() )
                if( !::lcl_SetOtherBoxWidth( pLn, rParam, nDist, true ))
                    return false;
 
            if( rParam.bBigger && ( TableChgMode::FixedWidthChangeAbs == rParam.nMode
                    ? std::abs( nDist - rParam.nSide ) < COLFUZZY
                    : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
                                     : nDist >= rParam.nSide - COLFUZZY )) )
            {
                rParam.bAnyBoxFnd = true;
                SwTwips nDiff;
                if( TableChgMode::FixedWidthChangeProp == rParam.nMode )        // Table fixed, proportional
                {
                    // calculate relative
                    nDiff = nWidth;
                    nDiff *= rParam.nDiff;
                    nDiff /= rParam.nMaxSize;
                }
                else
                    nDiff = rParam.nDiff;
 
                if( nWidth < nDiff || nWidth - nDiff < MINLAY )
                    return false;
            }
        }
        else
        {
            SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
            for( auto pLn : pBox->GetTabLines() )
            {
                rParam.nLowerDiff = 0;
                lcl_SetOtherBoxWidth( pLn, rParam, nDist, false );
 
                if( nLowerDiff < rParam.nLowerDiff )
                    nLowerDiff = rParam.nLowerDiff;
            }
            rParam.nLowerDiff = nOldLower;
 
            if( nLowerDiff ||
                ( TableChgMode::FixedWidthChangeAbs == rParam.nMode
                        ? std::abs( nDist - rParam.nSide ) < COLFUZZY
                        : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
                                         : nDist >= rParam.nSide - COLFUZZY)
                 ) )
            {
                SwFormatFrameSize aNew( rSz );
 
                if( !nLowerDiff )
                {
                    if( TableChgMode::FixedWidthChangeProp == rParam.nMode )        // Table fixed, proportional
                    {
                        // calculate relative
                        nLowerDiff = nWidth;
                        nLowerDiff *= rParam.nDiff;
                        nLowerDiff /= rParam.nMaxSize;
                    }
                    else
                        nLowerDiff = rParam.nDiff;
                }
 
                rParam.nLowerDiff += nLowerDiff;
 
                if( rParam.bBigger )
                    aNew.SetWidth( nWidth - nLowerDiff );
                else
                    aNew.SetWidth( nWidth + nLowerDiff );
 
                rParam.aShareFormats.SetSize( *pBox, aNew );
            }
        }
 
        nDist += nWidth;
        if( ( TableChgMode::FixedWidthChangeAbs == rParam.nMode || rParam.bLeft ) &&
            nDist > rParam.nSide )
            break;
    }
    return true;
}
 
static bool lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                            SwTwips nDist, bool bCheck )
{
    SwTableBoxes& rBoxes = pLine->GetTabBoxes();
    for( size_t n = 0; n < rBoxes.size(); ++n )
    {
        SwTableBox* pBox = rBoxes[ n ];
        SwTableBoxFormat* pFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
        const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
        SwTwips nWidth = rSz.GetWidth();
 
        int nCmp {0};
 
        if( bCheck )
        {
            for( size_t i = 0; i < pBox->GetTabLines().size(); ++i )
                if( !::lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam,
                                            nDist, true ))
                    return false;
 
            // Collect all "ContentBoxes"
            if( std::abs( nDist + ( rParam.bLeft ? 0 : nWidth )
                    - rParam.nSide ) < COLFUZZY )
                nCmp = 1;
            else if( nDist + ( rParam.bLeft ? 0 : nWidth/2 ) > rParam.nSide )
                nCmp = 2;
 
            if( nCmp )
            {
                rParam.bAnyBoxFnd = true;
                if( pFormat->GetProtect().IsContentProtected() )
                    return false;
 
                if( rParam.bSplittBox &&
                    nWidth - rParam.nDiff <= COLFUZZY +
                        ( 567 / 2 /*leave room for at least 0.5 cm*/) )
                    return false;
 
                if( pBox->GetSttNd() )
                {
                    rParam.m_Boxes.insert(pBox);
                }
 
                break;
            }
        }
        else
        {
            SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
            for( auto pLn : pBox->GetTabLines() )
            {
                rParam.nLowerDiff = 0;
                lcl_InsSelBox( pLn, rParam, nDist, false );
 
                if( nLowerDiff < rParam.nLowerDiff )
                    nLowerDiff = rParam.nLowerDiff;
            }
            rParam.nLowerDiff = nOldLower;
 
            if( nLowerDiff )
                nCmp = 1;
            else if( std::abs( nDist + ( rParam.bLeft ? 0 : nWidth )
                                - rParam.nSide ) < COLFUZZY )
                nCmp = 2;
            else if( nDist + nWidth / 2 > rParam.nSide )
                nCmp = 3;
 
            if( nCmp )
            {
                // This column contains the Cursor - so decrease/increase
                if( 1 == nCmp )
                {
                    if( !rParam.bSplittBox )
                    {
                        // the current Box on
                        SwFormatFrameSize aNew( rSz );
                        aNew.SetWidth( nWidth + rParam.nDiff );
                        rParam.aShareFormats.SetSize( *pBox, aNew );
                    }
                }
                else
                {
                    OSL_ENSURE( pBox->GetSttNd(), "This must be an EndBox!");
 
                    if( !rParam.bLeft && 3 != nCmp )
                        ++n;
 
                    ::InsTableBox( pFormat->GetDoc(), rParam.pTableNd,
                                        pLine, pFormat, pBox, n );
 
                    SwTableBox* pNewBox = rBoxes[ n ];
                    SwFormatFrameSize aNew( rSz );
                    aNew.SetWidth( rParam.nDiff );
                    rParam.aShareFormats.SetSize( *pNewBox, aNew );
 
                    // Special case: There is no space in the other Boxes, but in the Cell
                    if( rParam.bSplittBox )
                    {
                        // the current Box on
                        SwFormatFrameSize aNewSize( rSz );
                        aNewSize.SetWidth( nWidth - rParam.nDiff );
                        rParam.aShareFormats.SetSize( *pBox, aNewSize );
                    }
 
                    // Special treatment for the Border
                    // The right one needs to be removed
                    {
                        const SvxBoxItem& rBoxItem = pBox->GetFrameFormat()->GetBox();
                        if( rBoxItem.GetRight() )
                        {
                            SvxBoxItem aTmp( rBoxItem );
                            aTmp.SetLine( nullptr, SvxBoxItemLine::RIGHT );
                            rParam.aShareFormats.SetAttr( rParam.bLeft
                                                            ? *pNewBox
                                                            : *pBox, aTmp );
                        }
                    }
                }
 
                rParam.nLowerDiff = rParam.nDiff;
                break;
            }
        }
 
        if( rParam.bLeft && rParam.nMode != TableChgMode::FixedWidthChangeAbs && nDist >= rParam.nSide )
            break;
 
        nDist += nWidth;
    }
    return true;
}
 
static bool lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
                                SwTwips nDist, bool bCheck )
{
    // Special case: There is no space in the other Boxes, but in the cell
    if( rParam.bSplittBox )
        return true;
 
    SwTableBoxes& rBoxes = pLine->GetTabBoxes();
 
    // Table fixed, proportional
    if( !rParam.nRemainWidth && TableChgMode::FixedWidthChangeProp == rParam.nMode )
    {
        // Find the right width to which the relative width adjustment
        // corresponds to
        SwTwips nTmpDist = nDist;
        for( auto pBox : rBoxes )
        {
            SwTwips nWidth = pBox->GetFrameFormat()->GetFrameSize().GetWidth();
            if( (nTmpDist + nWidth / 2 ) > rParam.nSide )
            {
                rParam.nRemainWidth = rParam.bLeft
                                        ? sal_uInt16(nTmpDist)
                                        : sal_uInt16(rParam.nTableWidth - nTmpDist);
                break;
            }
            nTmpDist += nWidth;
        }
    }
 
    for( SwTableBoxes::size_type n = 0; n < rBoxes.size(); ++n )
    {
        SwTableBox* pBox = rBoxes[ n ];
        SwFrameFormat* pFormat = pBox->GetFrameFormat();
        const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
        SwTwips nWidth = rSz.GetWidth();
 
        if( bCheck )
        {
            for( auto pLn : pBox->GetTabLines() )
                if( !::lcl_InsOtherBox( pLn, rParam, nDist, true ))
                    return false;
 
            if(
                rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide &&
                                (TableChgMode::FixedWidthChangeAbs != rParam.nMode ||
                                (n < rBoxes.size() &&
                                  (nDist + nWidth + rBoxes[ n+1 ]->
                                   GetFrameFormat()->GetFrameSize().GetWidth() / 2)
                                  > rParam.nSide) ))
                             : (nDist + nWidth / 2 ) > rParam.nSide
                )
            {
                rParam.bAnyBoxFnd = true;
                SwTwips nDiff;
                if( TableChgMode::FixedWidthChangeProp == rParam.nMode )        // Table fixed, proportional
                {
                    // calculate relatively
                    nDiff = nWidth;
                    nDiff *= rParam.nDiff;
                    nDiff /= rParam.nRemainWidth;
 
                    if( nWidth < nDiff || nWidth - nDiff < MINLAY )
                        return false;
                }
                else
                {
                    nDiff = rParam.nDiff;
 
                    // See if the left or right Box is big enough to give up space.
                    // We're inserting a Box before or after.
                    SwTwips nTmpWidth = nWidth;
                    if( rParam.bLeft && pBox->GetUpper()->GetUpper() )
                    {
                        const SwTableBox* pTmpBox = pBox;
                        sal_uInt16 nBoxPos = n;
                        while( !nBoxPos && pTmpBox->GetUpper()->GetUpper() )
                        {
                            pTmpBox = pTmpBox->GetUpper()->GetUpper();
                            nBoxPos = pTmpBox->GetUpper()->GetBoxPos( pTmpBox );
                        }
                        nTmpWidth = pTmpBox->GetFrameFormat()->GetFrameSize().GetWidth();
                    }
 
                    if( nTmpWidth < nDiff || nTmpWidth - nDiff < MINLAY )
                        return false;
                    break;
                }
            }
        }
        else
        {
            SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
            for( auto pLn : pBox->GetTabLines() )
            {
                rParam.nLowerDiff = 0;
                lcl_InsOtherBox( pLn, rParam, nDist, false );
 
                if( nLowerDiff < rParam.nLowerDiff )
                    nLowerDiff = rParam.nLowerDiff;
            }
            rParam.nLowerDiff = nOldLower;
 
            if( nLowerDiff ||
                (rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide &&
                                (TableChgMode::FixedWidthChangeAbs != rParam.nMode ||
                                (n < rBoxes.size() &&
                                  (nDist + nWidth + rBoxes[ n+1 ]->
                                   GetFrameFormat()->GetFrameSize().GetWidth() / 2)
                                  > rParam.nSide) ))
                              : (nDist + nWidth / 2 ) > rParam.nSide ))
            {
                if( !nLowerDiff )
                {
                    if( TableChgMode::FixedWidthChangeProp == rParam.nMode )        // Table fixed, proportional
                    {
                        // Calculate relatively
                        nLowerDiff = nWidth;
                        nLowerDiff *= rParam.nDiff;
                        nLowerDiff /= rParam.nRemainWidth;
                    }
                    else
                        nLowerDiff = rParam.nDiff;
                }
 
                SwFormatFrameSize aNew( rSz );
                rParam.nLowerDiff += nLowerDiff;
 
                if( rParam.bBigger )
                    aNew.SetWidth( nWidth - nLowerDiff );
                else
                    aNew.SetWidth( nWidth + nLowerDiff );
                rParam.aShareFormats.SetSize( *pBox, aNew );
 
                if( TableChgMode::FixedWidthChangeAbs == rParam.nMode )
                    break;
            }
        }
 
        nDist += nWidth;
    }
    return true;
}
 
// The position comparison's result
//  SwComparePosition::Before,             // Box comes before
//  SwComparePosition::Behind,             // Box comes after
//  SwComparePosition::Inside,             // Box is completely within start/end
//  SwComparePosition::Outside,            // Box overlaps start/end completely
//  SwComparePosition::Equal,              // Box and start/end are the same
//  SwComparePosition::OverlapBefore,      // Box overlapps the start
//  SwComparePosition::OverlapBehind       // Box overlapps the end
SwComparePosition CheckBoxInRange( sal_uInt16 nStt, sal_uInt16 nEnd,
                                    sal_uInt16 nBoxStt, sal_uInt16 nBoxEnd )
{
    // Still treat COLFUZZY!
    SwComparePosition nRet;
    if( nBoxStt + COLFUZZY < nStt )
    {
        if( nBoxEnd > nStt + COLFUZZY )
        {
            if( nBoxEnd >= nEnd + COLFUZZY )
                nRet = SwComparePosition::Outside;
            else
                nRet = SwComparePosition::OverlapBefore;
        }
        else
            nRet = SwComparePosition::Before;
    }
    else if( nEnd > nBoxStt + COLFUZZY )
    {
        if( nEnd + COLFUZZY >= nBoxEnd )
        {
            if( COLFUZZY > std::abs( long(nEnd) - long(nBoxEnd) ) &&
                COLFUZZY > std::abs( long(nStt) - long(nBoxStt) ) )
                nRet = SwComparePosition::Equal;
            else
                nRet = SwComparePosition::Inside;
        }
        else
            nRet = SwComparePosition::OverlapBehind;
    }
    else
        nRet = SwComparePosition::Behind;
 
    return nRet;
}
 
static void lcl_DelSelBox_CorrLowers( SwTableLine& rLine, CR_SetBoxWidth& rParam,
                                SwTwips nWidth )
{
    // 1. step: Calculate own width
    SwTableBoxes& rBoxes = rLine.GetTabBoxes();
    SwTwips nBoxWidth = 0;
 
    for( auto n = rBoxes.size(); n; )
        nBoxWidth += rBoxes[ --n ]->GetFrameFormat()->GetFrameSize().GetWidth();
 
    if( COLFUZZY < std::abs( nWidth - nBoxWidth ))
    {
        // Thus, they need to be adjusted
        for( auto n = rBoxes.size(); n; )
        {
            SwTableBox* pBox = rBoxes[ --n ];
            SwFormatFrameSize aNew( pBox->GetFrameFormat()->GetFrameSize() );
            long nDiff = aNew.GetWidth();
            nDiff *= nWidth;
            nDiff /= nBoxWidth;
            aNew.SetWidth( nDiff );
 
            rParam.aShareFormats.SetSize( *pBox, aNew );
 
            if( !pBox->GetSttNd() )
            {
                // Has Lower itself, so also adjust that
                for( auto i = pBox->GetTabLines().size(); i; )
                    ::lcl_DelSelBox_CorrLowers( *pBox->GetTabLines()[ --i ],
                                                rParam, nDiff  );
            }
        }
    }
}
 
static void lcl_ChgBoxSize( SwTableBox& rBox, CR_SetBoxWidth& rParam,
                    const SwFormatFrameSize& rOldSz,
                    sal_uInt16& rDelWidth, SwTwips nDist )
{
    long nDiff = 0;
    bool bSetSize = false;
 
    switch( rParam.nMode )
    {
    case TableChgMode::FixedWidthChangeAbs:     // Fixed width table, change neighbor
        nDiff = rDelWidth + rParam.nLowerDiff;
        bSetSize = true;
        break;
 
    case TableChgMode::FixedWidthChangeProp:    // Fixed width table, change all neighbors
        if( !rParam.nRemainWidth )
        {
            // Calculate
            if( rParam.bLeft )
                rParam.nRemainWidth = sal_uInt16(nDist);
            else
                rParam.nRemainWidth = sal_uInt16(rParam.nTableWidth - nDist);
        }
 
        // Calculate relatively
        nDiff = rOldSz.GetWidth();
        nDiff *= rDelWidth + rParam.nLowerDiff;
        nDiff /= rParam.nRemainWidth;
 
        bSetSize = true;
        break;
 
    case TableChgMode::VarWidthChangeAbs:     // Variable table, change all neighbors
        if( COLFUZZY < std::abs( rParam.nBoxWidth -
                            ( rDelWidth + rParam.nLowerDiff )))
        {
            nDiff = rDelWidth + rParam.nLowerDiff - rParam.nBoxWidth;
            if( 0 < nDiff )
                rDelWidth = rDelWidth - sal_uInt16(nDiff);
            else
                rDelWidth = rDelWidth + sal_uInt16(-nDiff);
            bSetSize = true;
        }
        break;
    }
 
    if( bSetSize )
    {
        SwFormatFrameSize aNew( rOldSz );
        aNew.SetWidth( aNew.GetWidth() + nDiff );
        rParam.aShareFormats.SetSize( rBox, aNew );
 
        // Change the Lower once again
        for( auto i = rBox.GetTabLines().size(); i; )
            ::lcl_DelSelBox_CorrLowers( *rBox.GetTabLines()[ --i ], rParam,
                                            aNew.GetWidth() );
    }
}
 
static bool lcl_DeleteBox_Recursive( CR_SetBoxWidth& rParam, SwTableBox& rBox,
                            bool bCheck )
{
    bool bRet = true;
    if( rBox.GetSttNd() )
    {
        if( bCheck )
        {
            rParam.bAnyBoxFnd = true;
            if( rBox.GetFrameFormat()->GetProtect().IsContentProtected() )
                bRet = false;
            else
            {
                SwTableBox* pBox = &rBox;
                rParam.m_Boxes.insert(pBox);
            }
        }
        else
            ::DeleteBox_( rParam.pTableNd->GetTable(), &rBox,
                            rParam.pUndo, false, true, &rParam.aShareFormats );
    }
    else
    {
        // We need to delete these sequentially via the ContentBoxes
        for( auto i = rBox.GetTabLines().size(); i; )
        {
            SwTableLine& rLine = *rBox.GetTabLines()[ --i ];
            for( auto n = rLine.GetTabBoxes().size(); n; )
            {
                if (!::lcl_DeleteBox_Recursive( rParam,
                                *rLine.GetTabBoxes()[ --n ], bCheck ))
                {
                    return false;
                }
            }
        }
    }
    return bRet;
}
 
static bool lcl_DelSelBox( SwTableLine* pTabLine, CR_SetBoxWidth& rParam,
                    SwTwips nDist, bool bCheck )
{
    SwTableBoxes& rBoxes = pTabLine->GetTabBoxes();
    SwTableBoxes::size_type n;
    SwTableBoxes::size_type nCntEnd;
 
    sal_uInt16 nBoxChkStt, nBoxChkEnd, nDelWidth = 0;
    if( rParam.bLeft )
    {
        n = rBoxes.size();
        nCntEnd = 0;
        nBoxChkStt = static_cast<sal_uInt16>(rParam.nSide);
        nBoxChkEnd = static_cast<sal_uInt16>(rParam.nSide + rParam.nBoxWidth);
    }
    else
    {
        n = 0;
        nCntEnd = rBoxes.size();
        nBoxChkStt = static_cast<sal_uInt16>(rParam.nSide - rParam.nBoxWidth);
        nBoxChkEnd = static_cast<sal_uInt16>(rParam.nSide);
    }
 
    while( n != nCntEnd )
    {
        SwTableBox* pBox;
        if( rParam.bLeft )
            pBox = rBoxes[ --n ];
        else
            pBox = rBoxes[ n++ ];
 
        SwFrameFormat* pFormat = pBox->GetFrameFormat();
        const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
        long nWidth = rSz.GetWidth();
        bool bDelBox = false, bChgLowers = false;
 
        // Test the Box width and react accordingly
        SwComparePosition ePosType = ::CheckBoxInRange(
                            nBoxChkStt, nBoxChkEnd,
                            sal_uInt16(rParam.bLeft ? nDist - nWidth : nDist),
                            sal_uInt16(rParam.bLeft ? nDist : nDist + nWidth));
 
        switch( ePosType )
        {
        case SwComparePosition::Before:
            if( bCheck )
            {
                if( rParam.bLeft )
                    return true;
            }
            else if( rParam.bLeft )
            {
                ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
                if( TableChgMode::FixedWidthChangeAbs == rParam.nMode )
                    n = nCntEnd;
            }
            break;
 
        case SwComparePosition::Behind:
            if( bCheck )
            {
                if( !rParam.bLeft )
                    return true;
            }
            else if( !rParam.bLeft )
            {
                ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
                if( TableChgMode::FixedWidthChangeAbs == rParam.nMode )
                    n = nCntEnd;
            }
            break;
 
        case SwComparePosition::Outside:           // Box fully overlaps start/end
        case SwComparePosition::Inside:            // Box is completely within start/end
        case SwComparePosition::Equal:             // Box and start/end are the same
            bDelBox = true;
            break;
 
        case SwComparePosition::OverlapBefore:     // Box overlaps the start
            if( nBoxChkStt <= ( nDist + (rParam.bLeft ? - nWidth / 2
                                                      : nWidth / 2 )))
            {
                if( !pBox->GetSttNd() )
                    bChgLowers = true;
                else
                    bDelBox = true;
            }
            else if( !bCheck && rParam.bLeft )
            {
                if( !pBox->GetSttNd() )
                    bChgLowers = true;
                else
                {
                    ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
                    if( TableChgMode::FixedWidthChangeAbs == rParam.nMode )
                        n = nCntEnd;
                }
            }
            break;
 
        case SwComparePosition::OverlapBehind:     // Box overlaps the end
            // JP 10.02.99:
            // Delete generally or (like in OVERLAP_BEFORE) only delete the one who reaches up to the half into the delete Box?
            if( !pBox->GetSttNd() )
                bChgLowers = true;
            else
                bDelBox = true;
            break;
        default: break;
        }
 
        if( bDelBox )
        {
            nDelWidth = nDelWidth + sal_uInt16(nWidth);
            if( bCheck )
            {
                // The last/first Box can only be deleted for the variable Table,
                // if it's as large as the change in the Table.
                if( (( TableChgMode::VarWidthChangeAbs != rParam.nMode ||
                        nDelWidth != rParam.nBoxWidth ) &&
                     COLFUZZY > std::abs( rParam.bLeft
                                    ? nWidth - nDist
                                    : (nDist + nWidth - rParam.nTableWidth )))
                    || !::lcl_DeleteBox_Recursive(rParam, *pBox, bCheck))
                {
                    return false;
                }
 
                if( pFormat->GetProtect().IsContentProtected() )
                    return false;
            }
            else
            {
                ::lcl_DeleteBox_Recursive(rParam, *pBox, bCheck);
 
                if( !rParam.bLeft )
                {
                    --n;
                    --nCntEnd;
                }
            }
        }
        else if( bChgLowers )
        {
            bool bFirst = true, bCorrLowers = false;
            long nLowerDiff = 0;
            long nOldLower = rParam.nLowerDiff;
            sal_uInt16 nOldRemain = rParam.nRemainWidth;
 
            for( auto i = pBox->GetTabLines().size(); i; )
            {
                rParam.nLowerDiff = nDelWidth + nOldLower;
                rParam.nRemainWidth = nOldRemain;
                SwTableLine* pLine = pBox->GetTabLines()[ --i ];
                if( !::lcl_DelSelBox( pLine, rParam, nDist, bCheck ))
                    return false;
 
                // Do the Box and its Lines still exist?
                if( n < rBoxes.size() &&
                    pBox == rBoxes[ rParam.bLeft ? n : n-1 ] &&
                    i < pBox->GetTabLines().size() &&
                    pLine == pBox->GetTabLines()[ i ] )
                {
                    if( !bFirst && !bCorrLowers &&
                        COLFUZZY < std::abs( nLowerDiff - rParam.nLowerDiff ) )
                        bCorrLowers = true;
 
                    // The largest deletion width counts, but only if we don't
                    // delete the whole Line
                    if( nLowerDiff < rParam.nLowerDiff )
                        nLowerDiff = rParam.nLowerDiff;
 
                    bFirst = false;
                }
            }
            rParam.nLowerDiff = nOldLower;
            rParam.nRemainWidth = nOldRemain;
 
            // Did we delete all Boxes? Then the deletion width = the Box width, of course
            if( !nLowerDiff )
                nLowerDiff = nWidth;
 
            // Adjust deletion width!
            nDelWidth = nDelWidth + sal_uInt16(nLowerDiff);
 
            if( !bCheck )
            {
                // Has the Box already been removed?
                if( n > rBoxes.size() ||
                    pBox != rBoxes[ ( rParam.bLeft ? n : n-1 ) ] )
                {
                    // Then change the loop variable when deleting to the right
                    if( !rParam.bLeft )
                    {
                        --n;
                        --nCntEnd;
                    }
                }
                else
                {
                    // Or else we need to adapt the Box's size
                    SwFormatFrameSize aNew( rSz );
                    bool bCorrRel = false;
 
                    if( TableChgMode::VarWidthChangeAbs != rParam.nMode )
                    {
                        switch( ePosType )
                        {
                        case SwComparePosition::OverlapBefore:    // Box overlaps the start
                            if( TableChgMode::FixedWidthChangeProp == rParam.nMode )
                                bCorrRel = rParam.bLeft;
                            else if( rParam.bLeft ) // TableChgMode::FixedWidthChangeAbs
                            {
                                nLowerDiff = nLowerDiff - nDelWidth;
                                bCorrLowers = true;
                                n = nCntEnd;
                            }
                            break;
 
                        case SwComparePosition::OverlapBehind:    // Box overlaps the end
                            if( TableChgMode::FixedWidthChangeProp == rParam.nMode )
                                bCorrRel = !rParam.bLeft;
                            else if( !rParam.bLeft )    // TableChgMode::FixedWidthChangeAbs
                            {
                                nLowerDiff = nLowerDiff - nDelWidth;
                                bCorrLowers = true;
                                n = nCntEnd;
                            }
                            break;
 
                        default:
                            OSL_ENSURE( !pBox, "we should never reach this!" );
                            break;
                        }
                    }
 
                    if( bCorrRel )
                    {
                        if( !rParam.nRemainWidth )
                        {
                            // Calculate
                            if( rParam.bLeft )
                                rParam.nRemainWidth = sal_uInt16(nDist - nLowerDiff);
                            else
                                rParam.nRemainWidth = sal_uInt16(rParam.nTableWidth - nDist
                                                                - nLowerDiff );
                        }
 
                        long nDiff = aNew.GetWidth() - nLowerDiff;
                        nDiff *= nDelWidth + rParam.nLowerDiff;
                        nDiff /= rParam.nRemainWidth;
 
                        aNew.SetWidth( aNew.GetWidth() - nLowerDiff + nDiff );
                    }
                    else
                        aNew.SetWidth( aNew.GetWidth() - nLowerDiff );
                    rParam.aShareFormats.SetSize( *pBox, aNew );
 
                    if( bCorrLowers )
                    {
                        // Adapt the Lower once again
                        for( auto i = pBox->GetTabLines().size(); i; )
                            ::lcl_DelSelBox_CorrLowers( *pBox->
                                GetTabLines()[ --i ], rParam, aNew.GetWidth() );
                    }
                }
            }
        }
 
        if( rParam.bLeft )
            nDist -= nWidth;
        else
            nDist += nWidth;
    }
    rParam.nLowerDiff = nDelWidth;
    return true;
}
 
// Dummy function for the method SetColWidth
static bool lcl_DelOtherBox( SwTableLine* , CR_SetBoxWidth& , SwTwips , bool )
{
    return true;
}
 
static void lcl_AjustLines( SwTableLine* pLine, CR_SetBoxWidth& rParam )
{
    SwTableBoxes& rBoxes = pLine->GetTabBoxes();
    for( auto pBox : rBoxes )
    {
        SwFormatFrameSize aSz( pBox->GetFrameFormat()->GetFrameSize() );
        SwTwips nWidth = aSz.GetWidth();
        nWidth *= rParam.nDiff;
        nWidth /= rParam.nMaxSize;
        aSz.SetWidth( nWidth );
        rParam.aShareFormats.SetSize( *pBox, aSz );
 
        for( auto pLn : pBox->GetTabLines() )
            ::lcl_AjustLines( pLn, rParam );
    }
}
 
#ifdef DBG_UTIL
void CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize )
{
    const SwTableBoxes& rBoxes = rLine.GetTabBoxes();
 
    SwTwips nCurrentSize = 0;
    // See if the tables have a correct width
    for (SwTableBoxes::const_iterator i(rBoxes.begin()); i != rBoxes.end(); ++i)
    {
        const SwTableBox* pBox = *i;
        const SwTwips nBoxW = pBox->GetFrameFormat()->GetFrameSize().GetWidth();
        nCurrentSize += nBoxW;
 
        for( auto pLn : pBox->GetTabLines() )
            CheckBoxWidth( *pLn, nBoxW );
    }
 
    if (sal::static_int_cast< unsigned long >(std::abs(nCurrentSize - nSize)) >
        (COLFUZZY * rBoxes.size()))
    {
        OSL_FAIL( "Line's Boxes are too small or too large" );
    }
}
#endif
 
static FndBox_* lcl_SaveInsDelData( CR_SetBoxWidth& rParam, SwUndo** ppUndo,
                                SwTableSortBoxes& rTmpLst, SwTwips nDistStt )
{
    // Find all Boxes/Lines
    SwTable& rTable = rParam.pTableNd->GetTable();
 
    if (rParam.m_Boxes.empty())
    {
        // Get the Boxes
        if( rParam.bBigger )
            for( auto pLn : rTable.GetTabLines() )
                ::lcl_DelSelBox( pLn, rParam, nDistStt, true );
        else
            for( auto pLn : rTable.GetTabLines() )
                ::lcl_InsSelBox( pLn, rParam, nDistStt, true );
    }
 
    // Prevent deleting the whole Table
    if (rParam.bBigger
        && rParam.m_Boxes.size() == rTable.GetTabSortBoxes().size())
    {
        return nullptr;
    }
 
    FndBox_* pFndBox = new FndBox_( nullptr, nullptr );
    if( rParam.bBigger )
        pFndBox->SetTableLines( rParam.m_Boxes, rTable );
    else
    {
        FndPara aPara(rParam.m_Boxes, pFndBox);
        ForEach_FndLineCopyCol( rTable.GetTabLines(), &aPara );
        OSL_ENSURE( pFndBox->GetLines().size(), "Where are the Boxes" );
        pFndBox->SetTableLines( rTable );
 
        if( ppUndo )
            rTmpLst.insert( rTable.GetTabSortBoxes() );
    }
 
    // Find Lines for the Layout update
    pFndBox->DelFrames( rTable );
 
    // TL_CHART2: this function get called from SetColWidth exclusively,
    // thus it is currently speculated that nothing needs to be done here.
    // Note: that SetColWidth is currently not completely understood though :-(
 
    return pFndBox;
}
 
bool SwTable::SetColWidth( SwTableBox& rCurrentBox, TableChgWidthHeightType eType,
                        SwTwips nAbsDiff, SwTwips nRelDiff, SwUndo** ppUndo )
{
    SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());    // Delete HTML Layout
 
    const SwFormatFrameSize& rSz = GetFrameFormat()->GetFrameSize();
    const SvxLRSpaceItem& rLR = GetFrameFormat()->GetLRSpace();
 
    std::unique_ptr<FndBox_> xFndBox;                // for insertion/deletion
    SwTableSortBoxes aTmpLst;       // for Undo
    bool bBigger,
        bRet = false,
        bLeft = TableChgWidthHeightType::ColLeft == extractPosition( eType ) ||
                TableChgWidthHeightType::CellLeft == extractPosition( eType ),
        bInsDel = bool(eType & TableChgWidthHeightType::InsertDeleteMode );
    sal_uLong nBoxIdx = rCurrentBox.GetSttIdx();
 
    // Get the current Box's edge
    // Only needed for manipulating the width
    const SwTwips nDist = ::lcl_GetDistance( &rCurrentBox, bLeft );
    SwTwips nDistStt = 0;
    CR_SetBoxWidth aParam( eType, nRelDiff, nDist, rSz.GetWidth(),
                            bLeft ? nDist : rSz.GetWidth() - nDist,
                            const_cast<SwTableNode*>(rCurrentBox.GetSttNd()->FindTableNode()) );
    bBigger = aParam.bBigger;
 
    FN_lcl_SetBoxWidth fnSelBox, fnOtherBox;
    if( bInsDel )
    {
        if( bBigger )
        {
            fnSelBox = lcl_DelSelBox;
            fnOtherBox = lcl_DelOtherBox;
            aParam.nBoxWidth = static_cast<sal_uInt16>(rCurrentBox.GetFrameFormat()->GetFrameSize().GetWidth());
            if( bLeft )
                nDistStt = rSz.GetWidth();
        }
        else
        {
            fnSelBox = lcl_InsSelBox;
            fnOtherBox = lcl_InsOtherBox;
        }
    }
    else
    {
        fnSelBox = lcl_SetSelBoxWidth;
        fnOtherBox = lcl_SetOtherBoxWidth;
    }
 
    switch( extractPosition(eType) )
    {
    case TableChgWidthHeightType::ColRight:
    case TableChgWidthHeightType::ColLeft:
        if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
        {
            if( bInsDel )
                bBigger = !bBigger;
 
            // First test if we have room at all
            bool bChgLRSpace = true;
            if( bBigger )
            {
                if( GetFrameFormat()->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) &&
                    !rSz.GetWidthPercent() )
                {
                    // silence -Wsign-compare on Android with the static cast
                    bRet = rSz.GetWidth() < static_cast<unsigned short>(USHRT_MAX) - nRelDiff;
                    bChgLRSpace = bLeft ? rLR.GetLeft() >= nAbsDiff
                                        : rLR.GetRight() >= nAbsDiff;
                }
                else
                    bRet = bLeft ? rLR.GetLeft() >= nAbsDiff
                                 : rLR.GetRight() >= nAbsDiff;
 
                if( !bRet && bInsDel &&
                    // Is the room on the other side?
                    ( bLeft ? rLR.GetRight() >= nAbsDiff
                            : rLR.GetLeft() >= nAbsDiff ))
                {
                    bRet = true; bLeft = !bLeft;
                }
 
                if( !bRet )
                {
                    // Then call itself recursively; only with another mode (proportional)
                    TableChgMode eOld = m_eTableChgMode;
                    m_eTableChgMode = TableChgMode::FixedWidthChangeProp;
 
                    bRet = SetColWidth( rCurrentBox, eType, nAbsDiff, nRelDiff,
                                        ppUndo );
                    m_eTableChgMode = eOld;
                    return bRet;
                }
            }
            else
            {
                bRet = true;
                for( auto const & n: m_aLines )
                {
                    aParam.LoopClear();
                    if( !(*fnSelBox)( n, aParam, nDistStt, true ))
                    {
                        bRet = false;
                        break;
                    }
                }
            }
 
            if( bRet )
            {
                if( bInsDel )
                {
                    xFndBox.reset(::lcl_SaveInsDelData( aParam, ppUndo,
                                                    aTmpLst, nDistStt));
                    if (aParam.bBigger &&
                        aParam.m_Boxes.size() == m_TabSortContentBoxes.size())
                    {
                        // This whole Table is to be deleted!
                        GetFrameFormat()->GetDoc()->DeleteRowCol(aParam.m_Boxes);
                        return false;
                    }
 
                    if( ppUndo )
                        *ppUndo = aParam.CreateUndo(
                                        aParam.bBigger ? SwUndoId::COL_DELETE
                                                       : SwUndoId::TABLE_INSCOL );
                }
                else if( ppUndo )
                    *ppUndo = new SwUndoAttrTable( *aParam.pTableNd, true );
 
                long nFrameWidth = LONG_MAX;
                LockModify();
                SwFormatFrameSize aSz( rSz );
                SvxLRSpaceItem aLR( rLR );
                if( bBigger )
                {
                    // If the Table does not have any room to grow, we need to create some!
                    // silence -Wsign-compare on Android with the static cast
                    if( aSz.GetWidth() + nRelDiff > static_cast<unsigned short>(USHRT_MAX) )
                    {
                        // Break down to USHRT_MAX / 2
                        CR_SetBoxWidth aTmpPara( TableChgWidthHeightType::ColLeft, aSz.GetWidth() / 2,
                                        0, aSz.GetWidth(), aSz.GetWidth(), aParam.pTableNd );
                        for( size_t nLn = 0; nLn < m_aLines.size(); ++nLn )
                            ::lcl_AjustLines( m_aLines[ nLn ], aTmpPara );
                        aSz.SetWidth( aSz.GetWidth() / 2 );
                        aParam.nDiff = nRelDiff /= 2;
                        aParam.nSide /= 2;
                        aParam.nMaxSize /= 2;
                    }
 
                    if( bLeft )
                        aLR.SetLeft( sal_uInt16( aLR.GetLeft() - nAbsDiff ) );
                    else
                        aLR.SetRight( sal_uInt16( aLR.GetRight() - nAbsDiff ) );
                }
                else if( bLeft )
                    aLR.SetLeft( sal_uInt16( aLR.GetLeft() + nAbsDiff ) );
                else
                    aLR.SetRight( sal_uInt16( aLR.GetRight() + nAbsDiff ) );
 
                if( bChgLRSpace )
                    GetFrameFormat()->SetFormatAttr( aLR );
                const SwFormatHoriOrient& rHOri = GetFrameFormat()->GetHoriOrient();
                if( text::HoriOrientation::FULL == rHOri.GetHoriOrient() ||
                    (text::HoriOrientation::LEFT == rHOri.GetHoriOrient() && aLR.GetLeft()) ||
                    (text::HoriOrientation::RIGHT == rHOri.GetHoriOrient() && aLR.GetRight()))
                {
                    SwFormatHoriOrient aHOri( rHOri );
                    aHOri.SetHoriOrient( text::HoriOrientation::NONE );
                    GetFrameFormat()->SetFormatAttr( aHOri );
 
                    // If the Table happens to contain relative values (USHORT_MAX),
                    // we need to convert them to absolute ones now.
                    // Bug 61494
                    if( GetFrameFormat()->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) &&
                        !rSz.GetWidthPercent() )
                    {
                        SwTabFrame* pTabFrame = SwIterator<SwTabFrame,SwFormat>( *GetFrameFormat() ).First();
                        if( pTabFrame &&
                            pTabFrame->getFramePrintArea().Width() != rSz.GetWidth() )
                        {
                            nFrameWidth = pTabFrame->getFramePrintArea().Width();
                            if( bBigger )
                                nFrameWidth += nAbsDiff;
                            else
                                nFrameWidth -= nAbsDiff;
                        }
                    }
                }
 
                if( bBigger )
                    aSz.SetWidth( aSz.GetWidth() + nRelDiff );
                else
                    aSz.SetWidth( aSz.GetWidth() - nRelDiff );
 
                if( rSz.GetWidthPercent() )
                    aSz.SetWidthPercent( static_cast<sal_uInt8>(( aSz.GetWidth() * 100 ) /
                        ( aSz.GetWidth() + aLR.GetRight() + aLR.GetLeft())));
 
                GetFrameFormat()->SetFormatAttr( aSz );
                aParam.nTableWidth = sal_uInt16( aSz.GetWidth() );
 
                UnlockModify();
 
                for( sal_uInt16 n = m_aLines.size(); n; )
                {
                    --n;
                    aParam.LoopClear();
                    (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
                }
 
                // If the Table happens to contain relative values (USHORT_MAX),
                // we need to convert them to absolute ones now.
                // Bug 61494
                if( LONG_MAX != nFrameWidth )
                {
                    SwFormatFrameSize aAbsSz( aSz );
                    aAbsSz.SetWidth( nFrameWidth );
                    GetFrameFormat()->SetFormatAttr( aAbsSz );
                }
            }
        }
        else if( bInsDel ||
                ( bLeft ? nDist != 0 : std::abs( rSz.GetWidth() - nDist ) > COLFUZZY ) )
        {
            bRet = true;
            if( bLeft && TableChgMode::FixedWidthChangeAbs == m_eTableChgMode && !bInsDel )
                aParam.bBigger = !bBigger;
 
            // First test if we have room at all
            if( bInsDel )
            {
                if( aParam.bBigger )
                {
                    for( auto const & n: m_aLines )
                    {
                        aParam.LoopClear();
                        if( !(*fnSelBox)( n, aParam, nDistStt, true ))
                        {
                            bRet = false;
                            break;
                        }
                    }
                }
                else
                {
                    bRet = bLeft ? nDist != 0 : ( rSz.GetWidth() - nDist ) > COLFUZZY;
                    if( bRet )
                    {
                        for( auto const & n: m_aLines )
                        {
                            aParam.LoopClear();
                            if( !(*fnOtherBox)( n, aParam, 0, true ))
                            {
                                bRet = false;
                                break;
                            }
                        }
                        if( bRet && !aParam.bAnyBoxFnd )
                            bRet = false;
                    }
 
                    if( !bRet && rCurrentBox.GetFrameFormat()->GetFrameSize().GetWidth()
                        - nRelDiff > COLFUZZY +
                            ( 567 / 2 /*leave room for at least 0.5 cm*/) )
                    {
                        // Consume the space from the current Cell
                        aParam.bSplittBox = true;
                        // We also need to test this!
                        bRet = true;
 
                        for( auto const & n: m_aLines )
                        {
                            aParam.LoopClear();
                            if( !(*fnSelBox)( n, aParam, nDistStt, true ))
                            {
                                bRet = false;
                                break;
                            }
                        }
                    }
                }
            }
            else if( aParam.bBigger )
            {
                for( auto const & n: m_aLines )
                {
                    aParam.LoopClear();
                    if( !(*fnOtherBox)( n, aParam, 0, true ))
                    {
                        bRet = false;
                        break;
                    }
                }
            }
            else
            {
                for( auto const & n: m_aLines )
                {
                    aParam.LoopClear();
                    if( !(*fnSelBox)( n, aParam, nDistStt, true ))
                    {
                        bRet = false;
                        break;
                    }
                }
            }
 
            // If true, set it
            if( bRet )
            {
                CR_SetBoxWidth aParam1( aParam );
                if( bInsDel )
                {
                    aParam1.bBigger = !aParam.bBigger;
                    xFndBox.reset(::lcl_SaveInsDelData(aParam, ppUndo, aTmpLst, nDistStt));
                    if( ppUndo )
                        *ppUndo = aParam.CreateUndo(
                                        aParam.bBigger ? SwUndoId::TABLE_DELBOX
                                                       : SwUndoId::TABLE_INSCOL );
                }
                else if( ppUndo )
                    *ppUndo = new SwUndoAttrTable( *aParam.pTableNd, true );
 
                if( bInsDel
                    ? ( TableChgMode::FixedWidthChangeAbs == m_eTableChgMode ? (bBigger && bLeft) : bLeft )
                    : ( TableChgMode::FixedWidthChangeAbs != m_eTableChgMode && bLeft ) )
                {
                    for( sal_uInt16 n = m_aLines.size(); n; )
                    {
                        --n;
                        aParam.LoopClear();
                        aParam1.LoopClear();
                        (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
                        (*fnOtherBox)( m_aLines[ n ], aParam1, nDistStt, false );
                    }
                }
                else
                {
                    for( sal_uInt16 n = m_aLines.size(); n; )
                    {
                        --n;
                        aParam.LoopClear();
                        aParam1.LoopClear();
                        (*fnOtherBox)( m_aLines[ n ], aParam1, nDistStt, false );
                        (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
                    }
                }
            }
        }
        break;
 
    case TableChgWidthHeightType::CellRight:
    case TableChgWidthHeightType::CellLeft:
        if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
        {
            // Then call itself recursively; only with another mode (proportional)
            TableChgMode eOld = m_eTableChgMode;
            m_eTableChgMode = TableChgMode::FixedWidthChangeAbs;
 
            bRet = SetColWidth( rCurrentBox, eType, nAbsDiff, nRelDiff,
                                ppUndo );
            m_eTableChgMode = eOld;
            return bRet;
        }
        else if( bInsDel || ( bLeft ? nDist != 0
                                    : (rSz.GetWidth() - nDist) > COLFUZZY ))
        {
            if( bLeft && TableChgMode::FixedWidthChangeAbs == m_eTableChgMode && !bInsDel )
                aParam.bBigger = !bBigger;
 
            // First, see if there is enough room at all
            SwTableBox* pBox = &rCurrentBox;
            SwTableLine* pLine = rCurrentBox.GetUpper();
            while( pLine->GetUpper() )
            {
                const SwTableBoxes::size_type nPos = pLine->GetBoxPos( pBox );
                if( bLeft ? nPos != 0 : nPos + 1 != pLine->GetTabBoxes().size() )
                    break;
 
                pBox = pLine->GetUpper();
                pLine = pBox->GetUpper();
            }
 
            if( pLine->GetUpper() )
            {
                // We need to correct the distance once again!
                aParam.nSide -= ::lcl_GetDistance( pLine->GetUpper(), true );
 
                if( bLeft )
                    aParam.nMaxSize = aParam.nSide;
                else
                    aParam.nMaxSize = pLine->GetUpper()->GetFrameFormat()->
                                    GetFrameSize().GetWidth() - aParam.nSide;
            }
 
            // First, see if there is enough room at all
            if( bInsDel )
            {
                bRet = bLeft ? nDist != 0 : ( rSz.GetWidth() - nDist ) > COLFUZZY;
                if( bRet && !aParam.bBigger )
                {
                    bRet = (*fnOtherBox)( pLine, aParam, 0, true );
                    if( bRet && !aParam.bAnyBoxFnd )
                        bRet = false;
                }
 
                if( !bRet && !aParam.bBigger && rCurrentBox.GetFrameFormat()->
                    GetFrameSize().GetWidth() - nRelDiff > COLFUZZY +
                        ( 567 / 2 /*leave room for at least 0.5 cm*/) )
                {
                    // Consume the room from the current Cell
                    aParam.bSplittBox = true;
                    bRet = true;
                }
            }
            else
            {
                FN_lcl_SetBoxWidth fnTmp = aParam.bBigger ? fnOtherBox : fnSelBox;
                bRet = (*fnTmp)( pLine, aParam, nDistStt, true );
            }
 
            // If true, set it
            if( bRet )
            {
                CR_SetBoxWidth aParam1( aParam );
                if( bInsDel )
                {
                    aParam1.bBigger = !aParam.bBigger;
                    xFndBox.reset(::lcl_SaveInsDelData(aParam, ppUndo, aTmpLst, nDistStt));
                    if( ppUndo )
                        *ppUndo = aParam.CreateUndo(
                                        aParam.bBigger ? SwUndoId::TABLE_DELBOX
                                                       : SwUndoId::TABLE_INSCOL );
                }
                else if( ppUndo )
                    *ppUndo = new SwUndoAttrTable( *aParam.pTableNd, true );
 
                if( bInsDel
                    ? ( TableChgMode::FixedWidthChangeAbs == m_eTableChgMode ? (bBigger && bLeft) : bLeft )
                    : ( TableChgMode::FixedWidthChangeAbs != m_eTableChgMode && bLeft ) )
                {
                    (*fnSelBox)( pLine, aParam, nDistStt, false );
                    (*fnOtherBox)( pLine, aParam1, nDistStt, false );
                }
                else
                {
                    (*fnOtherBox)( pLine, aParam1, nDistStt, false );
                    (*fnSelBox)( pLine, aParam, nDistStt, false );
                }
            }
        }
        break;
        default: break;
    }
 
    if( xFndBox )
    {
        // Clean up the structure of all Lines
        GCLines();
 
        // Update Layout
        if( !bBigger || xFndBox->AreLinesToRestore( *this ) )
            xFndBox->MakeFrames( *this );
 
        // TL_CHART2: it is currently unclear if sth has to be done here.
        // The function name hints that nothing needs to be done, on the other
        // hand there is a case where sth gets deleted.  :-(
 
        xFndBox.reset();
 
        if (ppUndo && *ppUndo && aParam.pUndo)
        {
            aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<sal_uInt16>(m_eTableChgMode), eType,
                                            nAbsDiff, nRelDiff );
            if( !aParam.bBigger )
                aParam.pUndo->SaveNewBoxes( *aParam.pTableNd, aTmpLst );
        }
    }
 
#if defined DBG_UTIL
    if( bRet )
    {
        CHECKBOXWIDTH
        CHECKTABLELAYOUT
    }
#endif
 
    return bRet;
}
 
static FndBox_* lcl_SaveInsDelData( CR_SetLineHeight& rParam, SwUndo** ppUndo,
                                SwTableSortBoxes& rTmpLst )
{
    // Find all Boxes/Lines
    SwTable& rTable = rParam.pTableNd->GetTable();
 
    OSL_ENSURE( !rParam.m_Boxes.empty(), "We can't go on without Boxes!" );
 
    // Prevent deleting the whole Table
    if (!rParam.bBigger
        && rParam.m_Boxes.size() == rTable.GetTabSortBoxes().size())
    {
        return nullptr;
    }
 
    FndBox_* pFndBox = new FndBox_( nullptr, nullptr );
    if( !rParam.bBigger )
        pFndBox->SetTableLines( rParam.m_Boxes, rTable );
    else
    {
        FndPara aPara(rParam.m_Boxes, pFndBox);
        ForEach_FndLineCopyCol( rTable.GetTabLines(), &aPara );
        OSL_ENSURE( pFndBox->GetLines().size(), "Where are the Boxes?" );
        pFndBox->SetTableLines( rTable );
 
        if( ppUndo )
            rTmpLst.insert( rTable.GetTabSortBoxes() );
    }
 
    // Find Lines for the Layout update
    pFndBox->DelFrames( rTable );
 
    // TL_CHART2: it is currently unclear if sth has to be done here.
 
    return pFndBox;
}
 
void SetLineHeight( SwTableLine& rLine, SwTwips nOldHeight, SwTwips nNewHeight,
                    bool bMinSize )
{
    SwLayoutFrame* pLineFrame = GetRowFrame( rLine );
    OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
 
    SwFrameFormat* pFormat = rLine.ClaimFrameFormat();
 
    SwTwips nMyNewH, nMyOldH = pLineFrame->getFrameArea().Height();
    if( !nOldHeight )                       // the BaseLine and absolute
        nMyNewH = nMyOldH + nNewHeight;
    else
    {
        // Calculate as exactly as possible
        Fraction aTmp( nMyOldH );
        aTmp *= Fraction( nNewHeight, nOldHeight );
        aTmp += Fraction( 1, 2 );       // round up if needed
        nMyNewH = long(aTmp);
    }
 
    SwFrameSize eSize = ATT_MIN_SIZE;
    if( !bMinSize &&
        ( nMyOldH - nMyNewH ) > ( CalcRowRstHeight( pLineFrame ) + ROWFUZZY ))
        eSize = ATT_FIX_SIZE;
 
    pFormat->SetFormatAttr( SwFormatFrameSize( eSize, 0, nMyNewH ) );
 
    // First adapt all internal ones
    for( auto pBox : rLine.GetTabBoxes() )
    {
        for( auto pLine : pBox->GetTabLines() )
            SetLineHeight( *pLine, nMyOldH, nMyNewH, bMinSize );
    }
}
 
static bool lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
                             SwTwips nDist, bool bCheck )
{
    bool bRet = true;
    if( !bCheck )
    {
        // Set line height
        SetLineHeight( *pLine, 0, rParam.bBigger ? nDist : -nDist,
                        rParam.bBigger );
    }
    else if( !rParam.bBigger )
    {
        // Calculate the new relative size by means of the old one
        SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
        OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
        SwTwips nRstHeight = CalcRowRstHeight( pLineFrame );
        if( (nRstHeight + ROWFUZZY) < nDist )
            bRet = false;
    }
    return bRet;
}
 
static bool lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
                                SwTwips nDist, bool bCheck )
{
    bool bRet = true;
    if( bCheck )
    {
        if( rParam.bBigger )
        {
            // Calculate the new relative size by means of the old one
            SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
            OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
 
            if( TableChgMode::FixedWidthChangeProp == rParam.nMode )
            {
                nDist *= pLineFrame->getFrameArea().Height();
                nDist /= rParam.nMaxHeight;
            }
            bRet = nDist <= CalcRowRstHeight( pLineFrame );
        }
    }
    else
    {
        // Set line height
        // pLine is the following/preceding, thus adjust it
        if( TableChgMode::FixedWidthChangeProp == rParam.nMode )
        {
            SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
            OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine??" );
 
            // Calculate the new relative size by means of the old one
            // If the selected Box get bigger, adjust via the max space else
            // via the max height.
            if( (true) /*!rParam.bBigger*/ )
            {
                nDist *= pLineFrame->getFrameArea().Height();
                nDist /= rParam.nMaxHeight;
            }
            else
            {
                // Calculate the new relative size by means of the old one
                nDist *= CalcRowRstHeight( pLineFrame );
                nDist /= rParam.nMaxSpace;
            }
        }
        SetLineHeight( *pLine, 0, rParam.bBigger ? -nDist : nDist,
                        !rParam.bBigger );
    }
    return bRet;
}
 
static bool lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam,
                            SwTwips nDist, bool bCheck )
{
    if( !bCheck )
    {
        SwTableBoxes& rBoxes = pLine->GetTabBoxes();
        SwDoc* pDoc = pLine->GetFrameFormat()->GetDoc();
        if( !rParam.bBigger )
        {
            for (size_t n = rBoxes.size(); n; )
            {
                ::lcl_SaveUpperLowerBorder( rParam.pTableNd->GetTable(),
                                                    *rBoxes[ --n ],
                                                    rParam.aShareFormats );
            }
            for (size_t n = rBoxes.size(); n; )
            {
                ::DeleteBox_( rParam.pTableNd->GetTable(),
                                    rBoxes[ --n ], rParam.pUndo, false,
                                    false, &rParam.aShareFormats );
            }
        }
        else
        {
            // Insert Line
            SwTableLine* pNewLine = new SwTableLine( static_cast<SwTableLineFormat*>(pLine->GetFrameFormat()),
                                        rBoxes.size(), pLine->GetUpper() );
            SwTableLines* pLines;
            if( pLine->GetUpper() )
                pLines = &pLine->GetUpper()->GetTabLines();
            else
                pLines = &rParam.pTableNd->GetTable().GetTabLines();
            sal_uInt16 nPos = pLines->GetPos( pLine );
            if( !rParam.bTop )
                ++nPos;
            pLines->insert( pLines->begin() + nPos, pNewLine );
 
            SwFrameFormat* pNewFormat = pNewLine->ClaimFrameFormat();
            pNewFormat->SetFormatAttr( SwFormatFrameSize( ATT_MIN_SIZE, 0, nDist ) );
 
            // And once again calculate the Box count
            SwTableBoxes& rNewBoxes = pNewLine->GetTabBoxes();
            for( SwTableBoxes::size_type n = 0; n < rBoxes.size(); ++n )
            {
                SwTwips nWidth = 0;
                SwTableBox* pOld = rBoxes[ n ];
                if( !pOld->GetSttNd() )
                {
                    // Not a normal content Box, so fall back to the 1st next Box
                    nWidth = pOld->GetFrameFormat()->GetFrameSize().GetWidth();
                    while( !pOld->GetSttNd() )
                        pOld = pOld->GetTabLines()[ 0 ]->GetTabBoxes()[ 0 ];
                }
                ::InsTableBox( pDoc, rParam.pTableNd, pNewLine,
                                    static_cast<SwTableBoxFormat*>(pOld->GetFrameFormat()), pOld, n );
 
                // Special treatment for the border:
                // The top one needs to be removed
                const SvxBoxItem& rBoxItem = pOld->GetFrameFormat()->GetBox();
                if( rBoxItem.GetTop() )
                {
                    SvxBoxItem aTmp( rBoxItem );
                    aTmp.SetLine( nullptr, SvxBoxItemLine::TOP );
                    rParam.aShareFormats.SetAttr( rParam.bTop
                                                ? *pOld
                                                : *rNewBoxes[ n ], aTmp );
                }
 
                if( nWidth )
                    rParam.aShareFormats.SetAttr( *rNewBoxes[ n ],
                                SwFormatFrameSize( ATT_FIX_SIZE, nWidth, 0 ) );
            }
        }
    }
    else
    {
        // Collect Boxes!
        SwTableBoxes& rBoxes = pLine->GetTabBoxes();
        for( auto n = rBoxes.size(); n; )
        {
            SwTableBox* pBox = rBoxes[ --n ];
            if( pBox->GetFrameFormat()->GetProtect().IsContentProtected() )
                return false;
 
            if( pBox->GetSttNd() )
            {
                rParam.m_Boxes.insert(pBox);
            }
            else
            {
                for( auto i = pBox->GetTabLines().size(); i; )
                    lcl_InsDelSelLine( pBox->GetTabLines()[ --i ],
                                        rParam, 0, true );
            }
        }
    }
    return true;
}
 
bool SwTable::SetRowHeight( SwTableBox& rCurrentBox, TableChgWidthHeightType eType,
                        SwTwips nAbsDiff, SwTwips nRelDiff,SwUndo** ppUndo )
{
    SwTableLine* pLine = rCurrentBox.GetUpper();
 
    SwTableLine* pBaseLine = pLine;
    while( pBaseLine->GetUpper() )
        pBaseLine = pBaseLine->GetUpper()->GetUpper();
 
    std::unique_ptr<FndBox_> xFndBox;                // for insertion/deletion
    SwTableSortBoxes aTmpLst;       // for Undo
    bool bBigger,
        bRet = false,
        bTop = TableChgWidthHeightType::CellTop == extractPosition( eType ),
        bInsDel = bool(eType & TableChgWidthHeightType::InsertDeleteMode );
    sal_uInt16 nBaseLinePos = GetTabLines().GetPos( pBaseLine );
    sal_uLong nBoxIdx = rCurrentBox.GetSttIdx();
 
    CR_SetLineHeight aParam( eType,
                        const_cast<SwTableNode*>(rCurrentBox.GetSttNd()->FindTableNode()) );
    bBigger = aParam.bBigger;
 
    FN_lcl_SetLineHeight fnSelLine, fnOtherLine = lcl_SetOtherLineHeight;
    if( bInsDel )
        fnSelLine = lcl_InsDelSelLine;
    else
        fnSelLine = lcl_SetSelLineHeight;
 
    SwTableLines* pLines = &m_aLines;
 
    // How do we get to the height?
    switch( extractPosition(eType) )
    {
    case TableChgWidthHeightType::CellTop:
    case TableChgWidthHeightType::CellBottom:
        if( pLine == pBaseLine )
            break;  // it doesn't work then!
 
        // Is a nested Line (Box!)
        pLines = &pLine->GetUpper()->GetTabLines();
        nBaseLinePos = pLines->GetPos( pLine );
        pBaseLine = pLine;
        SAL_FALLTHROUGH;
 
    case TableChgWidthHeightType::RowBottom:
        {
            if( bInsDel && !bBigger )       // By how much does it get higher?
            {
                nAbsDiff = GetRowFrame( *pBaseLine )->getFrameArea().Height();
            }
 
            if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
            {
                // First test if we have room at all
                if( bBigger )
                    bRet = true;
                else
                    bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
                                        nAbsDiff, true );
 
                if( bRet )
                {
                    if( bInsDel )
                    {
                        if (aParam.m_Boxes.empty())
                        {
                            ::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ],
                                                    aParam, 0, true );
                        }
 
                        xFndBox.reset(::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst ));
 
                        // delete complete table when last row is deleted
                        if( !bBigger &&
                            aParam.m_Boxes.size() == m_TabSortContentBoxes.size())
                        {
                            GetFrameFormat()->GetDoc()->DeleteRowCol(aParam.m_Boxes);
                            return false;
                        }
 
                        if( ppUndo )
                            *ppUndo = aParam.CreateUndo(
                                        bBigger ? SwUndoId::TABLE_INSROW
                                                : SwUndoId::ROW_DELETE );
                    }
                    else if( ppUndo )
                        *ppUndo = new SwUndoAttrTable( *aParam.pTableNd, true );
 
                    (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
                                    nAbsDiff, false );
                }
            }
            else
            {
                bRet = true;
                SwTableLines::size_type nStt;
                SwTableLines::size_type nEnd;
                if( bTop )
                {
                    nStt = 0;
                    nEnd = nBaseLinePos;
                }
                else
                {
                    nStt = nBaseLinePos + 1;
                    nEnd = pLines->size();
                }
 
                // Get the current Lines' height
                if( TableChgMode::FixedWidthChangeProp == m_eTableChgMode )
                {
                    for( auto n = nStt; n < nEnd; ++n )
                    {
                        SwLayoutFrame* pLineFrame = GetRowFrame( *(*pLines)[ n ] );
                        OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine??" );
                        aParam.nMaxSpace += CalcRowRstHeight( pLineFrame );
                        aParam.nMaxHeight += pLineFrame->getFrameArea().Height();
                    }
                    if( bBigger && aParam.nMaxSpace < nAbsDiff )
                        bRet = false;
                }
                else
                {
                    if( bTop ? nEnd != 0 : nStt < nEnd  )
                    {
                        if( bTop )
                            nStt = nEnd - 1;
                        else
                            nEnd = nStt + 1;
                    }
                    else
                        bRet = false;
                }
 
                if( bRet )
                {
                    if( bBigger )
                    {
                        for( auto n = nStt; n < nEnd; ++n )
                        {
                            if( !(*fnOtherLine)( (*pLines)[ n ], aParam,
                                                    nAbsDiff, true ))
                            {
                                bRet = false;
                                break;
                            }
                        }
                    }
                    else
                        bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
                                                nAbsDiff, true );
                }
 
                if( bRet )
                {
                    // Adjust
                    if( bInsDel )
                    {
                        if (aParam.m_Boxes.empty())
                        {
                            ::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ],
                                                    aParam, 0, true );
                        }
                        xFndBox.reset(::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst ));
                        if( ppUndo )
                            *ppUndo = aParam.CreateUndo(
                                        bBigger ? SwUndoId::TABLE_INSROW
                                                : SwUndoId::ROW_DELETE );
                    }
                    else if( ppUndo )
                        *ppUndo = new SwUndoAttrTable( *aParam.pTableNd, true );
 
                    CR_SetLineHeight aParam1( aParam );
 
                    if( bTop )
                    {
                        (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
                                        nAbsDiff, false );
                        for( auto n = nStt; n < nEnd; ++n )
                            (*fnOtherLine)( (*pLines)[ n ], aParam1,
                                            nAbsDiff, false );
                    }
                    else
                    {
                        for( auto n = nStt; n < nEnd; ++n )
                            (*fnOtherLine)( (*pLines)[ n ], aParam1,
                                            nAbsDiff, false );
                        (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
                                        nAbsDiff, false );
                    }
                }
                else
                {
                    // Then call itself recursively; only with another mode (proportional)
                    TableChgMode eOld = m_eTableChgMode;
                    m_eTableChgMode = TableChgMode::VarWidthChangeAbs;
 
                    bRet = SetRowHeight( rCurrentBox, eType, nAbsDiff,
                                        nRelDiff, ppUndo );
 
                    m_eTableChgMode = eOld;
                    xFndBox.reset();
                }
            }
        }
        break;
        default: break;
    }
 
    if( xFndBox )
    {
        // then clean up the structure of all Lines
        GCLines();
 
        // Update Layout
        if( bBigger || xFndBox->AreLinesToRestore( *this ) )
            xFndBox->MakeFrames( *this );
 
        // TL_CHART2: it is currently unclear if sth has to be done here.
 
        xFndBox.reset();
 
        if (ppUndo && *ppUndo && aParam.pUndo)
        {
            aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<sal_uInt16>(m_eTableChgMode), eType,
                                            nAbsDiff, nRelDiff );
            if( bBigger )
                aParam.pUndo->SaveNewBoxes( *aParam.pTableNd, aTmpLst );
        }
    }
 
    CHECKTABLELAYOUT
 
    return bRet;
}
 
SwFrameFormat* SwShareBoxFormat::GetFormat( long nWidth ) const
{
    SwFrameFormat *pRet = nullptr, *pTmp;
    for( auto n = aNewFormats.size(); n; )
        if( ( pTmp = aNewFormats[ --n ])->GetFrameSize().GetWidth()
                == nWidth )
        {
            pRet = pTmp;
            break;
        }
    return pRet;
}
 
SwFrameFormat* SwShareBoxFormat::GetFormat( const SfxPoolItem& rItem ) const
{
    const SfxPoolItem* pItem;
    sal_uInt16 nWhich = rItem.Which();
    SwFrameFormat *pRet = nullptr, *pTmp;
    const SfxPoolItem& rFrameSz = pOldFormat->GetFormatAttr( RES_FRM_SIZE, false );
    for( auto n = aNewFormats.size(); n; )
        if( SfxItemState::SET == ( pTmp = aNewFormats[ --n ])->
            GetItemState( nWhich, false, &pItem ) && *pItem == rItem &&
            pTmp->GetFormatAttr( RES_FRM_SIZE, false ) == rFrameSz )
        {
            pRet = pTmp;
            break;
        }
    return pRet;
}
 
void SwShareBoxFormat::AddFormat( SwFrameFormat& rNew )
{
    aNewFormats.push_back( &rNew );
}
 
bool SwShareBoxFormat::RemoveFormat( const SwFrameFormat& rFormat )
{
    // returns true, if we can delete
    if( pOldFormat == &rFormat )
        return true;
 
    std::vector<SwFrameFormat*>::iterator it = std::find( aNewFormats.begin(), aNewFormats.end(), &rFormat );
    if( aNewFormats.end() != it )
        aNewFormats.erase( it );
    return aNewFormats.empty();
}
 
SwShareBoxFormats::~SwShareBoxFormats()
{
}
 
SwFrameFormat* SwShareBoxFormats::GetFormat( const SwFrameFormat& rFormat, long nWidth ) const
{
    sal_uInt16 nPos;
    return Seek_Entry( rFormat, &nPos )
                    ? m_ShareArr[ nPos ]->GetFormat(nWidth)
                    : nullptr;
}
SwFrameFormat* SwShareBoxFormats::GetFormat( const SwFrameFormat& rFormat,
                                     const SfxPoolItem& rItem ) const
{
    sal_uInt16 nPos;
    return Seek_Entry( rFormat, &nPos )
                    ? m_ShareArr[ nPos ]->GetFormat(rItem)
                    : nullptr;
}
 
void SwShareBoxFormats::AddFormat( const SwFrameFormat& rOld, SwFrameFormat& rNew )
{
    sal_uInt16 nPos;
    SwShareBoxFormat* pEntry;
    if( !Seek_Entry( rOld, &nPos ))
    {
        pEntry = new SwShareBoxFormat( rOld );
        m_ShareArr.insert(m_ShareArr.begin() + nPos, std::unique_ptr<SwShareBoxFormat>(pEntry));
    }
    else
        pEntry = m_ShareArr[ nPos ].get();
 
    pEntry->AddFormat( rNew );
}
 
void SwShareBoxFormats::ChangeFrameFormat( SwTableBox* pBox, SwTableLine* pLn,
                                    SwFrameFormat& rFormat )
{
    SwClient aCl;
    SwFrameFormat* pOld = nullptr;
    if( pBox )
    {
        pOld = pBox->GetFrameFormat();
        pOld->Add( &aCl );
        pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(&rFormat) );
    }
    else if( pLn )
    {
        pOld = pLn->GetFrameFormat();
        pOld->Add( &aCl );
        pLn->ChgFrameFormat( static_cast<SwTableLineFormat*>(&rFormat) );
    }
    if( pOld && pOld->HasOnlyOneListener() )
    {
        RemoveFormat( *pOld );
        delete pOld;
    }
}
 
void SwShareBoxFormats::SetSize( SwTableBox& rBox, const SwFormatFrameSize& rSz )
{
    SwFrameFormat *pBoxFormat = rBox.GetFrameFormat(),
             *pRet = GetFormat( *pBoxFormat, rSz.GetWidth() );
    if( pRet )
        ChangeFrameFormat( &rBox, nullptr, *pRet );
    else
    {
        pRet = rBox.ClaimFrameFormat();
        pRet->SetFormatAttr( rSz );
        AddFormat( *pBoxFormat, *pRet );
    }
}
 
void SwShareBoxFormats::SetAttr( SwTableBox& rBox, const SfxPoolItem& rItem )
{
    SwFrameFormat *pBoxFormat = rBox.GetFrameFormat(),
             *pRet = GetFormat( *pBoxFormat, rItem );
    if( pRet )
        ChangeFrameFormat( &rBox, nullptr, *pRet );
    else
    {
        pRet = rBox.ClaimFrameFormat();
        pRet->SetFormatAttr( rItem );
        AddFormat( *pBoxFormat, *pRet );
    }
}
 
void SwShareBoxFormats::SetAttr( SwTableLine& rLine, const SfxPoolItem& rItem )
{
    SwFrameFormat *pLineFormat = rLine.GetFrameFormat(),
             *pRet = GetFormat( *pLineFormat, rItem );
    if( pRet )
        ChangeFrameFormat( nullptr, &rLine, *pRet );
    else
    {
        pRet = rLine.ClaimFrameFormat();
        pRet->SetFormatAttr( rItem );
        AddFormat( *pLineFormat, *pRet );
    }
}
 
void SwShareBoxFormats::RemoveFormat( const SwFrameFormat& rFormat )
{
    for (auto i = m_ShareArr.size(); i; )
    {
        if (m_ShareArr[ --i ]->RemoveFormat(rFormat))
        {
            m_ShareArr.erase( m_ShareArr.begin() + i );
        }
    }
}
 
bool SwShareBoxFormats::Seek_Entry( const SwFrameFormat& rFormat, sal_uInt16* pPos ) const
{
    sal_uIntPtr nIdx = reinterpret_cast<sal_uIntPtr>(&rFormat);
    auto nO = m_ShareArr.size();
    decltype(nO) nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            const auto nM = nU + ( nO - nU ) / 2;
            sal_uIntPtr nFormat = reinterpret_cast<sal_uIntPtr>(&m_ShareArr[ nM ]->GetOldFormat());
            if( nFormat == nIdx )
            {
                if( pPos )
                    *pPos = nM;
                return true;
            }
            else if( nFormat < nIdx )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pPos )
                    *pPos = nU;
                return false;
            }
            else
                nO = nM - 1;
        }
    }
    if( pPos )
        *pPos = nU;
    return false;
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V690 The 'CR_SetBoxWidth' class implements a copy constructor, but lacks the '=' operator. It is dangerous to use such a class.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V690 The 'CR_SetLineHeight' class implements a copy constructor, but lacks the '=' operator. It is dangerous to use such a class.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.

V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.