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

Quelle  tblrwcl.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <memory>
#include <com/sun/star/text/HoriOrientation.hpp>
#include <officecfg/Office/Writer.hxx>
#include <osl/diagnose.h>
#include <svl/numformat.hxx>
#include <hintids.hxx>

#include <editeng/lrspitem.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 <docsh.hxx>
#include <fesh.hxx>
#include <tabfrm.hxx>
#include <frmatr.hxx>
#include <frmtool.hxx>
#include <pam.hxx>
#include <swtable.hxx>
#include <tblsel.hxx>
#include <fldbas.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;

#define COLFUZZY 20
#define ROWFUZZY 10

#ifdef DBG_UTIL
#define CHECK_TABLE(t) (t).CheckConsistency();
#else
#define CHECK_TABLE(t)
#endif

namespace {

// 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
{
    SwFrameFormat* pFrameFormat;
    SwTableBoxFormat *pNewFrameFormat;

    explicit CpyTabFrame(SwFrameFormat* pCurrentFrameFormat) : pNewFrameFormat( nullptr )
    {   pFrameFormat = pCurrentFrameFormat; }

    bool operator==( const CpyTabFrame& rCpyTabFrame ) const
        { return pFrameFormat == rCpyTabFrame.pFrameFormat; }
    bool operator<( const CpyTabFrame& rCpyTabFrame ) const
        { return pFrameFormat < rCpyTabFrame.pFrameFormat; }
};

struct CR_SetBoxWidth
{
    SwShareBoxFormats aShareFormats;
    SwTableNode* pTableNd;
    SwTwips nDiff, nSide, nMaxSize, nLowerDiff;
    TableChgMode nMode;
    bool bBigger, bLeft;

    CR_SetBoxWidth( TableChgWidthHeightType eType, SwTwips nDif, SwTwips nSid,
                    SwTwips nMax, SwTableNode* pTNd )
        : pTableNd( pTNd ),
        nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nLowerDiff( 0 )
    {
        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 ),
        nDiff( rCpy.nDiff ), nSide( rCpy.nSide ),
        nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ),
        nMode( rCpy.nMode ),
        bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft )
    {
    }

    void LoopClear()
    {
        nLowerDiff = 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 );

typedef bool (*FN_lcl_SetBoxWidth)(SwTableLine*, CR_SetBoxWidth&, SwTwips, bool );

namespace {

struct CR_SetLineHeight
{
    SwTableNode* pTableNd;
    SwTwips nMaxSpace, nMaxHeight;
    TableChgMode nMode;
    bool bBigger;

    CR_SetLineHeight( TableChgWidthHeightType eType, SwTableNode* pTNd )
        : pTableNd( pTNd ),
        nMaxSpace( 0 ), nMaxHeight( 0 )
    {
        bBigger = bool(eType & TableChgWidthHeightType::BiggerMode );
        nMode = pTableNd->GetTable().GetTableChgMode();
    }
    CR_SetLineHeight( const CR_SetLineHeight& rCpy )
        : pTableNd( rCpy.pTableNd ),
        nMaxSpace( rCpy.nMaxSpace ), nMaxHeight( rCpy.nMaxHeight ),
        nMode( rCpy.nMode ),
        bBigger( rCpy.bBigger )
    {}
};

}

static bool lcl_SetSelLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
                         SwTwips nDist, bool bCheck );
static bool lcl_SetOtherLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
                                SwTwips nDist, bool bCheck );

typedef bool (*FN_lcl_SetLineHeight)(SwTableLine*, CR_SetLineHeight&, SwTwips, bool );

typedef o3tl::sorted_vector<CpyTabFrame> CpyTabFrames;

namespace {

struct CpyPara
{
    std::shared_ptr< std::vector< std::vector< sal_uLong > > > pWidths;
    SwDoc& rDoc;
    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 )
        : rDoc( 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 ), rDoc(rPara.rDoc), 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 ), rDoc(rPara.rDoc), 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 SwTableLine* 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());

    if( pCpyPara->nCpyCnt )
    {
        sal_uInt16 nFndPos;
        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 = pBox->ClaimFrameFormat();

            // Find the selected Boxes in the Line:
            FndLine_ const* pCmpLine = nullptr;
            SwFormatFrameSize aFrameSz( pNewFormat->GetFrameSize() );

            bool bDiffCount = false;
            if( !pBox->GetTabLines().empty() )
            {
                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();
                tools::Long nSz = 0;
                forauto 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.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 = 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->rDoc, 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.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 = 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 SwTableLine* lcl_CopyRow(FndLine_& rFndLine, CpyPara *const pCpyPara)
{
    SwTableLine* pNewLine = new SwTableLine(
                        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;

    return pNewLine;
}

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);
            }
        }
    }
}

static 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& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
    bool bBehind, bool bInsertDummy )
{
    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( rDoc, rBoxes, nCnt, bBehind, bInsertDummy );
    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 );

#if defined DBG_UTIL
        CheckBoxWidth(GetTabLines(), *GetFrameFormat());;
        CheckTableLayout(GetTabLines());
#endif

        bRes = true;
    }

    SwChartDataProvider *pPCD = rDoc.getIDocumentChartDataProviderAccess().GetChartDataProvider();
    if (pPCD && nCnt)
        pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
    rDoc.UpdateCharts( GetFrameFormat()->GetName() );

    if (SwFEShell* pFEShell = rDoc.GetDocShell()->GetFEShell())
    {
        if (officecfg::Office::Writer::Table::Change::ApplyTableAutoFormat::get())
        {
            pFEShell->UpdateTableStyleFormatting();
        }
    }

    return bRes;
}

bool SwTable::InsertRow_( SwDoc& rDoc, const SwSelBoxes& rBoxes,
                        sal_uInt16 nCnt, bool bBehind, bool bInsertDummy )
{
    OSL_ENSURE( !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() )
        {
            pFndLine = pFndBox->GetLines()[0].get();
            if( 1 != pFndLine->GetBoxes().size() )
                break;
            // 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())
        {
            SwTableLine* pNewTableLine = lcl_CopyRow( *rpFndLine, &aCpyPara );

            // tracked insertion of empty table line
            if ( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
            {
                SvxPrintItem aSetTracking(RES_PRINT, false);
                SwPosition aPos(*pNewTableLine->GetTabBoxes()[0]->GetSttNd());
                SwCursor aCursor( aPos, nullptr );
                if ( bInsertDummy )
                {
                    SwPaM aPaM(*pNewTableLine->GetTabBoxes()[0]->GetSttNd(), SwNodeOffset(1));
                    rDoc.getIDocumentContentOperations().InsertString( aPaM,
                        OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
                }
                rDoc.SetRowNotTracked( aCursor, aSetTracking, /*bAll=*/false, /*bIns=*/true );
            }
        }
    }

    // clean up this Line's structure once again, generally all of them
    if( !rDoc.IsInReading() )
        GCLines();

    // Update Layout
    if ( bLayout )
    {
        if( pFndBox != &aFndBox )
            aFndBox.MakeFrames( *this );
        else
            aFndBox.MakeNewFrames( *this, nCnt, bBehind );
    }

#if defined DBG_UTIL
    CheckBoxWidth(GetTabLines(), *GetFrameFormat());;
    CheckTableLayout(GetTabLines());
#endif

    SwChartDataProvider *pPCD = rDoc.getIDocumentChartDataProviderAccess().GetChartDataProvider();
    if (pPCD && nCnt)
        pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
    rDoc.UpdateCharts( GetFrameFormat()->GetName() );

    if (SwFEShell* pFEShell = rDoc.GetDocShell()->GetFEShell())
    {
        if (officecfg::Office::Writer::Table::Change::ApplyTableAutoFormat::get())
        {
            pFEShell->UpdateTableStyleFormatting(pTableNd);
        }
    }

    return true;
}

static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const tools::Long nOffset,
                            bool bFirst, SwShareBoxFormats& rShareFormats );

static void lcl_LastBoxSetWidthLine( SwTableLines &rLines, const tools::Long nOffset,
                                bool bFirst, SwShareBoxFormats& rShareFormats )
{
    for ( auto pLine : rLines )
        ::lcl_LastBoxSetWidth( pLine->GetTabBoxes(), nOffset, bFirst, rShareFormats );
}

static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const tools::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 < o3tl::narrowing<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 < o3tl::narrowing<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
        rTable.GetFrameFormat()->GetDoc().getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableCellRedline( rTable.GetFrameFormat()->GetDoc(), *(rTableBoxes[nDelPos]), true, RedlineType::Any );
        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
            rTable.GetFrameFormat()->GetDoc().getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableRowRedline( rTable.GetFrameFormat()->GetDoc(), *pTabLineToDelete, true, RedlineType::Any );
            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
        rTable.GetFrameFormat()->GetDoc().getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableRowRedline( rTable.GetFrameFormat()->GetDoc(), *pTabLineToDelete, true, RedlineType::Any );
        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 ];
        forauto 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 < o3tl::narrowing<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 < o3tl::narrowing<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()) )
        return;

    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&     rDoc
    ,
    const SwSelBoxes& rBoxes,
    const SwSelBoxes* pMerged, SwUndo* pUndo,
    const bool bDelMakeFrames, const bool bCorrBorder )
{
    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 = rDoc.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
    rDoc.UpdateCharts( GetFrameFormat()->GetName() );

#if defined DBG_UTIL
    CheckTableLayout(GetTabLines());
#endif
    CHECK_TABLE( *this );

    return true;
}

bool SwTable::OldSplitRow( SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
                        bool bSameHeight )
{
    OSL_ENSURE( !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
    rDoc.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
    std::unique_ptr<tools::Long[]> pRowHeights;
    if ( bSameHeight )
    {
        pRowHeights.reset(new tools::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 = pSelBox->GetFrameFormat();

        // Respect the Line's height, reset if needed
        SwFormatFrameSize aFSz( pInsLine->GetFrameFormat()->GetFrameSize() );
        if ( bSameHeight && SwFrameSize::Variable == aFSz.GetHeightSizeType() )
            aFSz.SetHeightSizeType( SwFrameSize::Minimum );

        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;
        {
            SwNodeOffset nSttNd = pLastBox->GetSttIdx() + 1,
                    nEndNd = pLastBox->GetSttNd()->EndOfSectionIndex();
            while( nSttNd < nEndNd )
                if( !rDoc.GetNodes()[ nSttNd++ ]->IsTextNode() )
                {
                    bMoveNodes = false;
                    break;
                }
        }

        SwTableBoxFormat* pCpyBoxFrameFormat = pSelBox->GetFrameFormat();
        bool bChkBorder = nullptr != pCpyBoxFrameFormat->GetBox().GetTop();
        if( bChkBorder )
            pCpyBoxFrameFormat = pSelBox->ClaimFrameFormat();

        for( sal_uInt16 i = 0; i <= nCnt; ++i )
        {
            // Create a new Line in the new Box
            SwTableLine* pNewLine = new SwTableLine(
                    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( rDoc, pTableNd, pNewLine, pCpyBoxFrameFormat,
                                pLastBox, 0 );

                if( bChkBorder )
                {
                    pCpyBoxFrameFormat = 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()+SwNodeOffset(2) != pEndNd->GetIndex() )
                    {
                        // Move TextNodes
                        SwNodeRange aRg( *pLastBox->GetSttNd(), SwNodeOffset(+2), *pEndNd );
                        pLastBox = pNewLine->GetTabBoxes()[0];  // reset
                        SwNodeIndex aInsPos( *pLastBox->GetSttNd(), 1 );
                        rDoc.GetNodes().MoveNodes(aRg, rDoc.GetNodes(), aInsPos.GetNode(), false);
                        rDoc.GetNodes().Delete( aInsPos ); // delete the empty one
                    }
                }
            }
        }
        // In Boxes with Lines, we can only have Size/Fillorder
        pFrameFormat = pNewBox->ClaimFrameFormat();
        pFrameFormat->ResetFormatAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
        pFrameFormat->ResetFormatAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
    }

    pRowHeights.reset();

    GCLines();

    aFndBox.MakeFrames( *this );

#if defined DBG_UTIL
    CheckBoxWidth(GetTabLines(), *GetFrameFormat());;
    CheckTableLayout(GetTabLines());
#endif
    return true;
}

bool SwTable::SplitCol(SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt)
{
    OSL_ENSURE( !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
    rDoc.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( 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 = pSelBox->ClaimFrameFormat();
            SwTwips nBoxSz = aFindFrame.pNewFrameFormat->GetFrameSize().GetWidth();
            SwTwips nNewBoxSz = nBoxSz / ( nCnt + 1 );
            aFindFrame.pNewFrameFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable,
                                                        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( SwFrameSize::Variable,
                                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( rDoc, pTableNd, pInsLine, aFindFrame.pNewFrameFormat,
                        pSelBox, nBoxPos + i ); // insert after

        ::InsTableBox( rDoc, 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"
            forauto i = aFrameArr.size(); i; )
            {
                const CpyTabFrame& rCTF = aFrameArr[ --i ];
                if( rCTF.pNewFrameFormat == aFindFrame.pNewFrameFormat ||
                    rCTF.pFrameFormat == aFindFrame.pNewFrameFormat )
                {
                    aFrameArr.erase( aFrameArr.begin() + i );
                    aLastBoxArr.erase( aLastBoxArr.begin() + i );
                }
            }
        }
    }

    // Update Layout
    aFndBox.MakeFrames( *this );

#if defined DBG_UTIL
    CheckBoxWidth(GetTabLines(), *GetFrameFormat());;
    CheckTableLayout(GetTabLines());
#endif
    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" );

    tools::Long nWidth = 0;
    forauto pTabBox : pLine->GetTabBoxes() )
        nWidth += pTabBox->GetFrameFormat()->GetFrameSize().GetWidth();

    pFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, 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 );
}

namespace {

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 = trueif( pBox ) pInsBox = pBox; }
    void SetRight( SwTableBox* pBox )
        { bUL_LR = false;   bUL = falseif( pBox ) pInsBox = pBox; }
    void SetLower( SwTableLine* pLine )
        { bUL_LR = true;    bUL = falseif( 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
            nPos = pFndTableBox->GetUpper()->GetBoxPos( pFndTableBox );
            if( 0 != nPos )
                lcl_CpyBoxes( 0, nPos, *pBoxes, pULPara->pInsLine );
        }
        else                // Right
        {
            // if there are Boxes behind it, move them
            nPos = pFndTableBox->GetUpper()->GetBoxPos( pFndTableBox );
            if( nPos +1 < o3tl::narrowing<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().empty())
        return;

    SwTableBox* pBox = new SwTableBox(
            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().empty() )
    {
        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
                nPos = pLines->GetPos( pFndLn );
                if( 0 != nPos )
                    lcl_CpyLines( 0, nPos, *pLines, pULPara->pInsBox );
            }
            else
                // If there are Lines after it, move them
                if( (nPos = pLines->GetPos( pFndLn )) + 1 < o3tl::narrowing<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(
                pULPara->pLeftBox->GetFrameFormat(), 0, pInsLine );
            SwTableLine* pLMLn = new SwTableLine(
                        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
                nPos = pLines->GetPos( pFndLn );
                if( 0 != nPos )
                    lcl_CpyLines( 0, nPos, *pLines, pLMBox, 0 );
            }
            else
                // If there are Lines after it, move them
                if( (nPos = pLines->GetPos( pFndLn )) + 1 < o3tl::narrowing<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(
        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& rDoc, 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
    rDoc.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(
                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( pMergeBox->GetFrameFormat(), 0, pInsLine );
    SwTableBox* pRightBox = new SwTableBox( 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, falsefalse );
    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, falsefalse );
    else
    {
        lcl_CalcWidth( pRightBox );     // calculate the Box's width
        if( pUndo && pRightBox->GetSttNd() )
            pUndo->AddNewBox( pRightBox->GetSttIdx() );
    }

    DeleteSel( rDoc, rBoxes, nullptr, nullptr, falsefalse );

    // Clean up this Line's structure once again, generally all of them
    GCLines();

    forconst auto& rpBox : GetTabLines()[0]->GetTabBoxes() )
        lcl_BoxSetHeadCondColl(rpBox);

    aFndBox.MakeFrames( *this );

#if defined DBG_UTIL
    CheckBoxWidth(GetTabLines(), *GetFrameFormat());;
    CheckTableLayout(GetTabLines());
#endif

    return true;
}

static void lcl_CheckRowSpan( SwTable &rTable )
{
    const tools::Long nLineCount = static_cast<tools::Long>(rTable.GetTabLines().size());
    tools::Long nMaxSpan = nLineCount;
    tools::Long nMinSpan = 1;
    while( nMaxSpan )
    {
        SwTableLine* pLine = rTable.GetTabLines()[ nLineCount - nMaxSpan ];
        forauto pBox : pLine->GetTabBoxes() )
        {
            sal_Int32 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();
        forauto pCmp : rBoxes )
        {
            if (pBox==pCmp)
                break;
            nRet = nRet + o3tl::narrowing<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;
    forauto n = rLine.GetBoxes().size(); n; )
    {
        nRet = nRet + o3tl::narrowing<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)[ nLine ];
            const FndLine_ *pFndLine = rFndLines[ nLine ].get();
            if( pFndLine && !pFndLine->GetBoxes().empty() )
            {
                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; )
                    {
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=91 H=88 G=89

¤ Dauer der Verarbeitung: 0.92 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Entwurf

Ziele

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Ergonomie der
Schnittstellen

Diese beiden folgenden Angebotsgruppen bietet das Unternehmen

Angebot

Hier finden Sie eine Liste der Produkte des Unternehmens