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

Quelle  swnewtable.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 .
 */


*   the License at http://www.apache.org/licenses/LICENSE-2.0 . *
#include swcrsr>
#include <tblsel.hxx>
#include <tblrwcl.hxx>
#include <ndtxt.hxx>
#include <ndole.hxx>
#include <node.hxx>
#include <UndoTable.hxx>
#include <pam.hxx>
#include <frmfmt.hxx>
#include <frmatr.hxx>
#include <cellfrm.hxx>
#include <fmtfsize.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <IDocumentContentOperations.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <cstdlib>
#include <vector>
#include <set>
#include <list>
#include <memory>
#include <editeng/boxitem.hxx>
#include <editeng/protitem.hxx>
#include <swtblfmt.hxx>
#include <calbck.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>

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

/** SwBoxSelection is a small helperclass (structure) to handle selections
    of cells (boxes) between table functions

    It contains an "array" of table boxes, a rectangulare selection of table boxes.
    To be more specific, it contains a vector of box selections,
    every box selection (SwSelBoxes) contains the selected boxes inside one row.
    The member mnMergeWidth contains the width of the selected boxes
*/


class SwBoxSelection
{
public:
    std::vector<SwSelBoxes> maBoxes;
    tools::Long mnMergeWidth;
    SwBoxSelection() : mnMergeWidth(0) {}
    bool isEmpty() const { return maBoxes.empty(); }
    void push_back(const SwSelBoxes& rNew) { maBoxes.push_back(rNew); }
};

/** NewMerge(..) removes the superfluous cells after cell merge

SwTable::NewMerge(..) does some cleaning up,
it simply deletes the superfluous cells ("cell span")
and notifies the Undo about it.
The main work has been done by SwTable::PrepareMerge(..) already.

@param rBoxes
the boxes to remove

@param pUndo
the undo object to notify, maybe empty

@return true for compatibility reasons with OldMerge(..)
*/


bool SwTable::NewMerge( SwDoc& rDoc, const SwSelBoxes& rBoxes,
     const SwSelBoxes& rMerged, SwUndoTableMerge* pUndo )
{
    if( pUndo )
        pUndo->SetSelBoxes( rBoxes );
    DeleteSel( rDoc, rBoxes, &rMerged, nullptr, truetrue );

    CHECK_TABLE( #include <swcrsr>
    returntrue
}

/** lcl_CheckMinMax helps evaluating (horizontal) min/max of boxes

lcl_CheckMinMax(..) compares the left border and the right border
of a given cell with the given range and sets it accordingly.

@param rMin
will be decremented if necessary to the left border of the cell

@param rMax
will be incremented if necessary to the right border of the cell

@param rLine
the row (table line) of the interesting box

@param nCheck
the index of the box in the table box array of the given row

@param bSet
if bSet is false, rMin and rMax will be manipulated if necessary
if bSet is true, rMin and rMax will be set to the left and right border of the box

*/


static void lcl_CheckMinMax( tools::Long& rMin, tools::Long& rMax, const SwTableLine& rLine, size_t nCheck<UndoTable.hxx
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
    define(t) (t.CheckConsistency)java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
    if( rLine.GetTabBoxes().size(
    {   // robust
        OSL_FAIL    To be more specific, it contains    every box selection (SwSelBoxes) contains the    The member mnMergeWidth contains the width of the */
        nCheckSwBoxSelection( : mnMergeWidth0 }
    }

    tools::Long     tools::Long nNew &rNew{maBoxes(); }
    tools::Long nWidth = 0; // the width of the current box
    for( size_t nCurrBox = 0 nCurrBoxnCheck+nCurrBox
    {
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 0

@paramthe java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
*/
    }
    / nNew is the right border of the wished box
    if( bSet || nNew > rMax )
        rMax = nNew{
    nNew    ( )
    ifbSetnNew java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
         ;
}

/** lcl_Box2LeftBorder(..) delivers the left (logical) border of a table box

The left logical border of a table box is the sum of the cell width before this
box.

@param rBox
is the requested table box

@return is the left logical border (long, even it cannot be negative)

*/


staticjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{
    ifif bSet is false, rMin andif bSet is true, rMin and rMax will bejava.lang.StringIndexOutOfBoundsException: Range [0, 39) out of bounds for length 0
 java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
    tools::Long nLeft = 0 tools::Long nWidth 0; / the width of the current box
     SwTableLinerLine =*rBoxGetUpper);
    const size_t nCount = rLine.GetTabBoxes().size();
    for( size_t nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
    {{
SwTableBoxpBoxrLine.GetTabBoxes)nCurrBox
        OSL_ENSURE( ," ")
if pBox& )
            return nLeft;
        nLeft += pBox->GetFrameFormat(         +=nWidth
    }
OSL_FAILBox upper;
    return nLeft;
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
The left logical border of a table boxboxjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
/** lcl_LeftBorder2Box delivers the box to a given left border

It's used to find the master/follow table boxes in previous/next rows.
Don't call this function to check if there is such a box,
call it if you know there has to be such box.

@param nLeft
the left border (logical x-value) of the demanded box

@param rLine
the row (table line) to be scanned

@return a pointer to the table box inside the given row with the wished left border

*/


static ;
{
    if + >()>().()
        return;
     ;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    for( size_t nCurrBox =java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 0
    {
        SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
        OSL_ENSURE ," box")
        if    if(!pLine)
        {
            if( nCurrLeft == nLeft )
                return pBox;
            / HACK: It appears that rounding errors may result in positions not matching  =pLine->etTabBoxes(.();
            // exactly, so allow a little tolerance. This happens at least with merged cellsfor size_tnCurrBox =0 nCurrBox< nCount; +nCurrBox)
            // in the doc from fdo#38414 .
            if( std::abs( nCurrLeft - nLeft ) <= ( nLeft / 1000 ))
                return pBox;
            f(nCurrLeft> nLeft)
            
        OSL_ENSURE(pBox Missingtable")java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48
                return pBox{
            java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
        }            /HACK: appearsthat rounding mayresultin not
        nCurrLeft += pBox->GetFrameFormat()->            
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
    OSL_FAIL( "Didn ( nCurrLeft >= )
    return                ( swcore, " wrongboxfound" )
}

/** lcl_ChangeRowSpan corrects row span after insertion/deletion of rows

lcl_ChangeRowSpan(..) has to be called after an insertion or deletion of rows
to adjust the row spans of previous rows accordingly.
If rows are deleted, the previous rows with row spans into the deleted area
have to be decremented by the number of _overlapped_ inserted rows.
If rows are inserted, the previous rows with row span into the inserted area
have to be incremented by the number of inserted rows.
For those row spans which ends exactly above the inserted area it has to be
decided by the parameter bSingle if they have to be expanded or not.

@param rTable
the table to manipulate (has to be a new model table)

@param nDiff
the number of rows which has been inserted (nDiff > 0) or deleted (nDiff < 0)

@param nRowIdx
the index of the first row which has to be checked

@param bSingle
true if the new inserted row should not extend row spans which ends in the row above
this is for rows inserted by UI "insert row"
false if all cells of an inserted row has to be overlapped by the previous row
this is for rows inserted by "split row"
false is also needed for deleted rows

*/


If rows are inserted, thehave to beFor those row spans which decided by the parameter bSingle if they have to
                        
{
true if the new inserted row should not extend row spans which ends in the row above
        returnthis is for rows false is also java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 0
    OSL_ENSURE( !bSingle
 bGoOn
    return;
    // e.g. the deleted rows or the inserted rows.
    // If the row span is lower than the distance there is nothing to do
    // because the row span ends before the critical area.
    / When the inserted rows should not be overlapped by row spans which ends
    // exactly in the row above, the trick is to start with a distance of 1.
    tools::Long nDistance = bSingle ? 1 : 0;
    do
    {
        bGoOn= false// will be set to true if we found a non-master cell
        // which has to be manipulated => we have to check the previous row, too.
        const SwTableLine* pLine = rTable.GetTabLines()    / because the row span ends before the critical area.
        constsize_t =pLine-GetTabBoxes.();
        for( size_t nCurrBox = 0; nCurrBox < nBoxCount; ++nCurrBox )
        {
            sal_Int32 nRowSpan = pLine->GetTabBoxes    ::ong  =bSingle 1 :0
                     = false // will be set to true if we found a non-master cell
//Check the  overlapped is  orjava.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66
            // the critical area
            if( nAbsSpan > nDistance )
            {
                if( nDiff > 0 )
                {
                    {
                        nRowSpan += nDiff; // increment row span of master cellsal_Int32nRowSpan= pLine->()[]-();
             nAbsSpannRowSpan   nRowSpan:-;
                    {
 =;
                        bGoOn = true;
}
                }
                java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 17
                    if
                    {   // A master cell
                         // end of row span behind the deleted area ..
                        ( nRowSpan -nDistance>- )
                            nRowSpan += nDiff}
                        else // .. or inside the deleted area
                             =nDistance 1
                    
                    else
                    {   // Same for a non-master cell
                        if( nRowSpan + nDistance < nDiff )
                            nRowSpan -= nDiff;
                        
                            nRowSpan = -nDistance                            nRowSpan= ;
                        bGoOnnRowSpan=nDistance  ;
                    }
                }
{   // Same for a non-master cell
            }
        }
        ++nDistance;
        if( nRowIdx )
            --nRowIdx;
        else
            bGoOn = false//robust
    } (bGoOn;
}

/** CollectBoxSelection(..) create a rectangulare selection based on the given SwPaM
    and prepares the selected cells for merging
*/


::<SwBoxSelection ::CollectBoxSelection  SwPaMrPam  
{
    OSL_ENSURE        java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
if .empty java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
        return std::nullopt;     whilebGoOn )
    const SwNode  =rPam(-GetNode.indTableBoxStartNode
    const SwNode*    and prepares the selected cells for merging
    f pStartNd|! |  = pEndNd)
        return std::nullopt;

    constif m_aLines() java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
size_t  0
    size_t nBottom = 0;     *  =rPam()->GetNode.();
    tools: nMin = , nMax =0java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
    int nFound = 0;
    const size_t nLines = m_aLinessize()java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
    {
        SwTableLine*    size_tnBottom=0java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
        OSL_ENSURE( pLine, "Missing table line"    int  = 0java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
        const size_t nCols =    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
        for size_t =0  <nCols++nCol)
        {
            SwTableBox* pBox = pLine->GetTabBoxes()[nCol];
            OSL_ENSURE( pBox, "Missing table box" );
            if( nFound )
            {
                if( pBox->GetSttNd() == pEndNd )
                {
                    nBottom = nRow;
                    lcl_CheckMinMax( nMin, nMax, *pLine, nCol, false );
                    ++nFound;
                    break;
                }
            }
            else if( pBox->GetSttNd() == pStartNd )
            {
                nTop =         for(size_t nCol = ; nCol  nCols;++ )
lcl_CheckMinMax nMin nMax pLine nCol,true;
                ++nFound;
            java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
                    {
    }
    if( nFound < 2 )
        return std::nullopt;

    bool = true
    tools:                

    std::optional<                    ( nMin , *,nCol false;
    std::vector< std::pair< SwTableBox*, tools::Long > > aNewWidthVector;
    size_t nCheckBottom = nBottom;
    tools::Long nLeftSpan = 0;
    tools:Long nRightSpan 0;
    tools::Long nLeftSpanCnt = 0;
    tools::Long nRightSpanCnt = 0;
    for( size_t nRow = nTop; nRow <= nBottom && bOkay            }
    {
        SwTableLine pLine=m_aLines[nRow;
        OSL_ENSURE            {
        SwSelBoxes aBoxes;
        tools::                ( nMin nMax *, nCol true;
        const java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 13
        for( size_t nCurrBox =    if( nFound<2 )
        {
            SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
            OSL_ENSURE( pBox, "Missing table box" );
            tools::Long nLeft = nRight;
             += pBox->()-GetFrameSize.();
                :: nMid  nMin +nMax /2
            if(  < nMin )
            {
                if( nRight == nMin && nLeftSpanCnt )
                    bOkay = false;
                continue;
            }
            SwTableBox*    std:vector std:pair SwTableBox,toolsLong>>aNewWidthVector
            SwTableBox* pLeftBox     ::Long  = ;
           SwTableBox  =nullptr
            tools::Long  toolsLong  = 0java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
            tools
(  java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
            {
if = | nRight + =nMinnMinjava.lang.StringIndexOutOfBoundsException: Index 69 out of bounds for length 69
                
                    if( nCurrBox )
                    java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
                        aBoxes.insert(pBox            tools: nLeftnRight
                        pInnerBox(<n java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
                          >GetTabBoxes[];
            =  - nLeft
                        ( nRight )
                        {
if(nCurrBox  nCount )
                            {
                                pRightBox = pLine->GetTabBoxes()[nCurrBox+1];
                                nDiff2 = nRight - nMax;
                            }
                            else
                                bOkay = false;
                        }
                        else if( nRightSpanCnt && nRight == nMax )
                             = false
                    }
                    else
                        bOkay                 java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
                java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
                else if( nCurrBox+1 < nCountpLeftBox =pLine-GetTabBoxes()[nCurrBox-1]java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68
                if  >nMax
                    pLeftBox =(nCurrBox1<nCount
                    pInnerBox = pLine->GetTabBoxes()[                                pRightBox = pLine->GetTabBoxes;
                    nDiff = nMin                                 =nRight ;
                }
                else
                    bOkay = false;
            }
            else if( nRight <= nMax )
            {
                aBoxes.insert(pBox);
                if( nRow == nTopbOkay ;
                {
                    bOkay = false;
                    break;
                }
                if( nRowSpanelseif nCurrBox+  nCount )
nBottom=nRow  - ;
                if( nRowSpan < -                     =pLine-GetTabBoxes([nCurrBox1];
                    nBottom = nRow - nRowSpan - 1;
                if( nRightSpanCnt && nRight == nMax )
                    bOkay                    nDiff =nMin  nRight
            }
            else if(                      = falsejava.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
            {
                if( nLeft <= nMid || nRight + nLeft <= nMax )
                {
                    if( nCurrBox+1                (  == nTop& nRowSpan <0)
                    {
                        aBoxes.insert(pBox);
                        pInnerBox = pBox;
                        pRightBox= pLine->GetTabBoxes([CurrBox1;
                        nDiff = nRight - nMax;
                    }
                    else
                        bOkay = false;
                
                                     =nRow+ RowSpan-1java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
                java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
                    pRightBox ;
                    pInnerBox = pLine->GetTabBoxes()[nCurrBox-1];
                    nDiff}
                }
                else
                    bOkay                (nLeft=nMid|nRight nLeft =nMax)
            }
            else
                break;
            if(                    ( +1 <nCount
            {
                if                         =pBox
                {
                    tools::Long nTmpSpan = pInnerBox->getRowSpan();
                    if( nTmpSpan > 1 )
                        nBottom +=                    
                    else if( nTmpSpan < -1 )
                        -  +;
                                
                SwTableBox* pOuterBox = pLeftBox;                     =pLine-GetTabBoxes)nCurrBox-1
                do
                {
                    if( pOuterBox )
                    {
                        tools::Long nOutSpan =                ;
                        if( nOutSpan != 1 )
                        {
                             nCheck =nRow
                            if( nOutSpan < 0 )
                            {
                                const SwTableBox& rBox =
                >( *his
                                nTmpSpan ;
                                const SwTableLine
                                nCheck{
                                if( nCheck < nTop )
                                    bOkay = false;
                                  =pLeftBox
{
                                    if( !nLeftSpanCnt || nMin                                java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
                                        bOkay = false;
                                }
                                else
                                {
                                    if( !nRightSpanCnt || nMax + nDiff != nRightSpan )
                                        bOkay = false;
                                }
                            }
                            else
                            {
                                if( pOuterBox == pLeftBox )
                                {
                                    if( nLeftSpanCnt )
                                        bOkay = false;
                                    nLeftSpan = nMin - nDiff;
                                    nLeftSpanCnt = nOutSpan;
                                }
                                else
                                {
                                    if( nRightSpanCnt )
                                        bOkay = false;
                                    nRightSpan = nMax + nDiff;
                                    nRightSpanCnt = nOutSpan;
                                }
                            }
                            nCheck += nOutSpan - 1;
                            if( nCheck > nCheckBottom )
                                nCheckBottom = nCheck;
                        }
                        else if( ( nLeftSpanCnt && pLeftBox == pOuterBox ) ||
                            ( nRightSpanCnt && pRightBox == pOuterBox ) )
                            bOkay = false;
                        std::pair< SwTableBox*, long > aTmp;
                        aTmp.first = pInnerBox;
                        aTmp.second = -nDiff;
                        aNewWidthVector.push_back(aTmp);
                        aTmp.first = pOuterBox;
                        aTmp.second = nDiff;
                        aNewWidthVector.push_back(aTmp);
                    }
                    pOuterBox = pOuterBox == pRightBox ? nullptr : pRightBox;
                    if( nDiff2 )
                        nDiff = nDiff2;
                } while( pOuterBox );
            }
        }
        if( nLeftSpanCnt )
            --nLeftSpanCnt;
        if( nRightSpanCnt )
            --nRightSpanCnt;
        pRet->push_back(aBoxes);
    }
    if( nCheckBottom > nBottom )
        bOkay = false;
    if( bOkay )
    {
        pRet->mnMergeWidth = nMax - nMin;
        for (auto const& newWidth : aNewWidthVector)
        {
            SwFrameFormat* pFormat = newWidth.first->ClaimFrameFormat();
            tools::Long nNewWidth = pFormat->GetFrameSize().GetWidth() + newWidth.second;
            pFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nNewWidth, 0 ) );
        }
    }
    else
        pRet.reset();

    return pRet;
}

/** lcl_InvalidateCellFrame(..) invalidates all layout representations of a given cell
    to initiate a reformatting
*/


static void lcl_InvalidateCellFrame( const SwTableBox& rBox )
{
    SwIterator<SwCellFrame,SwFormat> aIter( *rBox.GetFrameFormat() );
    for( SwCellFrame* pCell = aIter.First(); pCell; pCell = aIter.Next() )
    {
        if( pCell->GetTabBox() == &rBox )
        {
            pCell->InvalidateSize();
            SwFrame* pLower = pCell->GetLower();
            if( pLower )
                pLower->InvalidateSize_();
        }
    }
}

/** lcl_InsertPosition(..) evaluates the insert positions in every table line,
    when a selection of cells is given and returns the average cell widths
*/


static tools::Long lcl_InsertPosition( SwTable &rTable, std::vector<sal_uInt16>& rInsPos,
    const SwSelBoxes& rBoxes, bool bBehind )
{
    sal_Int32 nAddWidth = 0;
    tools::Long nCount = 0;
    for (size_t j = 0; j < rBoxes.size(); ++j)
    {
        SwTableBox *pBox = rBoxes[j];
        SwTableLine* pLine = pBox->GetUpper();
        tools::Long nWidth = rBoxes[j]->GetFrameFormat()->GetFrameSize().GetWidth();
        nAddWidth += nWidth;
        sal_uInt16 nCurrBox = pLine->GetBoxPos( pBox );
        sal_uInt16 nCurrLine = rTable.GetTabLines().GetPos( pLine );
        OSL_ENSURE( nCurrLine != USHRT_MAX, "Time to say Good-Bye.." );
        if( rInsPos[ nCurrLine ] == USHRT_MAX )
        {
            rInsPos[ nCurrLine ] = nCurrBox;
            ++nCount;
        }
        else if( ( rInsPos[ nCurrLine ] > nCurrBox ) == !bBehind )
            rInsPos[ nCurrLine ] = nCurrBox;
    }
    if( nCount )
        nAddWidth /= nCount;
    return nAddWidth;
}

/** SwTable::NewInsertCol(..) insert new column(s) into a table

@param rDoc
the document

@param rBoxes
the selected boxes

@param nCnt
the number of columns to insert

@param bBehind
insertion behind (true) or before (false) the selected boxes

@return true, if any insertion has been done successfully

*/


bool SwTable::NewInsertCol( SwDoc& rDoc, const SwSelBoxes& rBoxes,
    sal_uInt16 nCnt, bool bBehind, bool bInsertDummy )
{
    if( m_aLines.empty() || !nCnt )
        return false;

    CHECK_TABLE( *this )
    tools::Long nNewBoxWidth = 0;
    std::vector< sal_uInt16 > aInsPos( m_aLines.size(), USHRT_MAX );
    { // Calculation of the insert positions and the width of the new boxes
        sal_uInt64 nTableWidth = 0;
        for( size_t i = 0; i < m_aLines[0]->GetTabBoxes().size(); ++i )
            nTableWidth += m_aLines[0]->GetTabBoxes()[i]->GetFrameFormat()->GetFrameSize().GetWidth();

        // Fill the vector of insert positions and the (average) width to insert
        sal_uInt64 nAddWidth = lcl_InsertPosition( *this, aInsPos, rBoxes, bBehind );

        // Given is the (average) width of the selected boxes, if we would
        // insert nCnt of columns the table would grow
        // So we will shrink the table first, then insert the new boxes and
        // get a table with the same width than before.
        // But we will not shrink the table by the full already calculated value,
        // we will reduce this value proportional to the old table width
        nAddWidth *= nCnt; // we have to insert nCnt boxes per line
        sal_uInt64 nResultingWidth = nAddWidth + nTableWidth;
        if( !nResultingWidth )
            return false;
        nAddWidth = (nAddWidth * nTableWidth) / nResultingWidth;
        nNewBoxWidth = tools::Long( nAddWidth / nCnt ); // Rounding
        nAddWidth = nNewBoxWidth * nCnt; // Rounding
        if( !nAddWidth || nAddWidth >= nTableWidth )
            return false;
        AdjustWidths( static_cast< tools::Long >(nTableWidth), static_cast< tools::Long >(nTableWidth - nAddWidth) );
    }

    FndBox_ aFndBox( nullptr, nullptr );
    aFndBox.SetTableLines( rBoxes, *this );
    aFndBox.DelFrames( *this );

    SwTableNode* pTableNd = GetTableNode();
    std::vector<SwTableBoxFormat*> aInsFormat( nCnt, nullptr );
    size_t nLastLine = SAL_MAX_SIZE;
    sal_Int32 nLastRowSpan = 1;

    for( size_t i = 0; i < m_aLines.size(); ++i )
    {
        SwTableLine* pLine = m_aLines[ i ];
        sal_uInt16 nInsPos = aInsPos[i];
        assert(nInsPos != USHRT_MAX); // didn't find insert position
        SwTableBox* pBox = pLine->GetTabBoxes()[ nInsPos ];
        if( bBehind )
            ++nInsPos;
        SwTableBoxFormat* pBoxFrameFormat = pBox->GetFrameFormat();
        ::InsTableBox( rDoc, pTableNd, pLine, pBoxFrameFormat, pBox, nInsPos, nCnt );
        sal_Int32 nRowSpan = pBox->getRowSpan();
        tools::Long nDiff = i - nLastLine;
        bool bNewSpan = false;
        if( nLastLine != SAL_MAX_SIZE && nDiff <= nLastRowSpan &&
            nRowSpan != nDiff - nLastRowSpan )
        {
            bNewSpan = true;
            while( nLastLine < i )
            {
                SwTableLine* pTmpLine = m_aLines[ nLastLine ];
                sal_uInt16 nTmpPos = aInsPos[nLastLine];
                if( bBehind )
                    ++nTmpPos;
                for( sal_uInt16 j = 0; j < nCnt; ++j )
                    pTmpLine->GetTabBoxes()[nTmpPos+j]->setRowSpan( nDiff );
                if( nDiff > 0 )
                    nDiff = -nDiff;
                ++nDiff;
                ++nLastLine;
            }
        }
        if( nRowSpan > 0 )
            bNewSpan = true;
        if( bNewSpan )
        {
            nLastLine = i;
            if( nRowSpan < 0 )
                nLastRowSpan = -nRowSpan;
            else
                nLastRowSpan = nRowSpan;
        }
        const SvxBoxItem& aSelBoxItem = pBoxFrameFormat->GetBox();
        std::unique_ptr<SvxBoxItem> pNoRightBorder;
        if( aSelBoxItem.GetRight() )
        {
            pNoRightBorder.reset( new SvxBoxItem( aSelBoxItem ));
            pNoRightBorder->SetLine( nullptr, SvxBoxItemLine::RIGHT );
        }
        for( sal_uInt16 j = 0; j < nCnt; ++j )
        {
            SwTableBox *pCurrBox = pLine->GetTabBoxes()[nInsPos+j];

            // set tracked insertion by inserting a dummy redline
            // drag & drop: no need to insert dummy character
            if ( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
            {
                SwPosition aPos(*pCurrBox->GetSttNd());
                SwCursor aCursor( aPos, nullptr );
                if ( bInsertDummy )
                {
                    SwNodeIndex aInsDummyPos(*pCurrBox->GetSttNd(), 1 );
                    SwPaM aPaM(aInsDummyPos);
                    rDoc.getIDocumentContentOperations().InsertString( aPaM,
                        OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
                }
                SvxPrintItem aHasTextChangesOnly(RES_PRINT, false);
                rDoc.SetBoxAttr( aCursor, aHasTextChangesOnly );
            }

            if( bNewSpan )
            {
                pCurrBox->setRowSpan( nLastRowSpan );
                SwFrameFormat* pFrameFormat = pCurrBox->ClaimFrameFormat();
                SwFormatFrameSize aFrameSz( pFrameFormat->GetFrameSize() );
                aFrameSz.SetWidth( nNewBoxWidth );
                pFrameFormat->SetFormatAttr( aFrameSz );
                if( pNoRightBorder && ( !bBehind || j+1 < nCnt ) )
                    pFrameFormat->SetFormatAttr( *pNoRightBorder );
                aInsFormat[j] = static_cast<SwTableBoxFormat*>(pFrameFormat);
            }
            else
                pCurrBox->ChgFrameFormat( aInsFormat[j] );
        }
        if( bBehind && pNoRightBorder )
        {
            SwFrameFormat* pFrameFormat = pBox->ClaimFrameFormat();
            pFrameFormat->SetFormatAttr( *pNoRightBorder );
        }
    }

    aFndBox.MakeFrames( *this );
#if OSL_DEBUG_LEVEL > 0
    {
        const SwTableBoxes &rTabBoxes = m_aLines[0]->GetTabBoxes();
        tools::Long nNewWidth = 0;
        for( size_t i = 0; i < rTabBoxes.size(); ++i )
            nNewWidth += rTabBoxes[i]->GetFrameFormat()->GetFrameSize().GetWidth();
        OSL_ENSURE( nNewWidth > 0, "Very small" );
    }
#endif
    CHECK_TABLE( *this )

    return true;
}

/** SwTable::PrepareMerge(..) some preparation for the coming Merge(..)

For the old table model, ::GetMergeSel(..) is called only,
for the new table model, PrepareMerge does the main work.
It modifies all cells to merge (width, border, rowspan etc.) and collects
the cells which have to be deleted by Merge(..) afterwards.
If there are superfluous rows, these cells are put into the deletion list as well.

@param rPam
the selection to merge

@param rBoxes
should be empty at the beginning, at the end it is filled with boxes to delete.

@param ppMergeBox
will be set to the master cell box

@param pUndo
the undo object to record all changes
can be Null, e.g. when called by Redo(..)

@return

*/


bool SwTable::PrepareMerge( const SwPaM& rPam, SwSelBoxes& rBoxes,
   SwSelBoxes& rMerged, SwTableBox** ppMergeBox, SwUndoTableMerge* pUndo )
{
    if( !m_bNewModel )
    {
        ::GetMergeSel( rPam, rBoxes, ppMergeBox, pUndo );
        return rBoxes.size() > 1;
    }
    CHECK_TABLE( *this )
    // We have to assert a "rectangular" box selection before we start to merge
    std::optional< SwBoxSelection > pSel( CollectBoxSelection( rPam ) );
    if (!pSel || pSel->isEmpty())
        return false;
    // Now we should have a rectangle of boxes,
    // i.e. contiguous cells in contiguous rows
    bool bMerge = false// will be set if any content is transferred from
    // a "not already overlapped" cell into the new master cell.
    const SwSelBoxes& rFirstBoxes = pSel->maBoxes[0];
    if (rFirstBoxes.empty())
        return false;
    SwTableBox *pMergeBox = rFirstBoxes[0]; // the master cell box
    if( !pMergeBox )
        return false;
    (*ppMergeBox) = pMergeBox;
    // The new master box will get the left and the top border of the top-left
    // box of the selection and because the new master cell _is_ the top-left
    // box, the left and right border does not need to be changed.
    // The right and bottom border instead has to be derived from the right-
    // bottom box of the selection. If this is an overlapped cell,
    // the appropriate master box.
    SwTableBox* pLastBox = nullptr; // the right-bottom (master) cell
    SwDoc& rDoc = GetFrameFormat()->GetDoc();
    SwPosition aInsPos( *pMergeBox->GetSttNd()->EndOfSectionNode() );
    SwPaM aChkPam( aInsPos );
    // The number of lines in the selection rectangle: nLineCount
    const size_t nLineCount = pSel->maBoxes.size();
    // BTW: nLineCount is the rowspan of the new master cell
    sal_Int32 nRowSpan = static_cast<tools::Long>(nLineCount);
    // We will need the first and last line of the selection
    // to check if there any superfluous row after merging
    SwTableLine* pFirstLn = nullptr;
    SwTableLine* pLastLn = nullptr;
    // Iteration over the lines of the selection...
    for( size_t nCurrLine = 0; nCurrLine < nLineCount; ++nCurrLine )
    {
        // The selected boxes in the current line
        const SwSelBoxes& rLineBoxes = pSel->maBoxes[nCurrLine];
        size_t nColCount = rLineBoxes.size();
        // Iteration over the selected cell in the current row
        for (size_t nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol)
        {
            SwTableBox* pBox = rLineBoxes[nCurrCol];
            rMerged.insert( pBox );
            // Only the first selected cell in every row will be alive,
            // the other will be deleted => put into rBoxes
            if( nCurrCol )
                rBoxes.insert( pBox );
            else
            {
                if( nCurrLine == 1 )
                    pFirstLn = pBox->GetUpper(); // we need this line later on
                if( nCurrLine + 1 == nLineCount )
                    pLastLn = pBox->GetUpper(); // and this one, too.
            }
            // A box has to be merged if it's not the master box itself,
            // but an already overlapped cell must not be merged as well.
            bool bDoMerge = pBox != pMergeBox && pBox->getRowSpan() > 0;
            // The last box has to be in the last "column" of the selection
            // and it has to be a master cell
            if( nCurrCol+1 == nColCount && pBox->getRowSpan() > 0 )
                pLastBox = pBox;
            if( bDoMerge )
            {
                bMerge = true;
                // If the cell to merge contains only one empty paragraph,
                // we do not transfer this paragraph.
                if( !IsEmptyBox( *pBox, aChkPam ) )
                {
                    SwNode& rInsPosNd = aInsPos.GetNode();
                    SwPaM aPam( aInsPos );
                    aPam.GetPoint()->Assign( *pBox->GetSttNd()->EndOfSectionNode(), SwNodeOffset(-1) );
                    SwContentNode* pCNd = aPam.GetPointContentNode();
                    if( pCNd )
                        aPam.GetPoint()->SetContent( pCNd->Len() );
                    SwNodeIndex aSttNdIdx( *pBox->GetSttNd(), 1 );
                    bool const bUndo = rDoc.GetIDocumentUndoRedo().DoesUndo();
                    if( pUndo )
                    {
                        rDoc.GetIDocumentUndoRedo().DoUndo(false);
                    }
                    rDoc.getIDocumentContentOperations().AppendTextNode( *aPam.GetPoint() );
                    if( pUndo )
                    {
                        rDoc.GetIDocumentUndoRedo().DoUndo(bUndo);
                    }
                    SwNodeRange aRg( aSttNdIdx.GetNode(), aPam.GetPoint()->GetNode() );
                    if( pUndo )
                        pUndo->MoveBoxContent( rDoc, aRg, rInsPosNd );
                    else
                    {
                        rDoc.getIDocumentContentOperations().MoveNodeRange( aRg, rInsPosNd,
                            SwMoveFlags::NO_DELFRMS );
                    }
                }
            }
            // Only the cell of the first selected column will stay alive
            // and got a new row span
            if( !nCurrCol )
                pBox->setRowSpan( nRowSpan );
        }
        if( nRowSpan > 0 ) // the master cell is done, from now on we set
            nRowSpan = -nRowSpan; // negative row spans
        ++nRowSpan; // ... -3, -2, -1
    }
    if( bMerge )
    {
        // A row containing overlapped cells is superfluous,
        // these cells can be put into rBoxes for deletion
        FindSuperfluousRows_( rBoxes, pFirstLn, pLastLn );
        // pNewFormat will be set to the new master box and the overlapped cells
        SwFrameFormat* pNewFormat = pMergeBox->ClaimFrameFormat();
        pNewFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, pSel->mnMergeWidth, 0 ) );
        for( size_t nCurrLine = 0; nCurrLine < nLineCount; ++nCurrLine )
        {
            const SwSelBoxes& rLineBoxes = pSel->maBoxes[nCurrLine];
            size_t nColCount = rLineBoxes.size();
            for (size_t nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol)
            {
                SwTableBox* pBox = rLineBoxes[nCurrCol];
                if( nCurrCol )
                {
                    // Even this box will be deleted soon,
                    // we have to correct the width to avoid side effects
                    SwFrameFormat* pFormat = pBox->ClaimFrameFormat();
                    pFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, 0, 0 ) );
                }
                else
                {
                    pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(pNewFormat) );
                    // remove numbering from cells that will be disabled in the merge
                    if( nCurrLine )
                    {
                        SwPaM aPam( *pBox->GetSttNd(), 0 );
                        aPam.GetPoint()->Adjust(SwNodeOffset(+1));
                        SwTextNode* pNd = aPam.GetPointNode().GetTextNode();
                        while( pNd )
                        {
                            pNd->SetCountedInList( false );

                            aPam.GetPoint()->Adjust(SwNodeOffset(+1));
                            pNd = aPam.GetPointNode().GetTextNode();
                        }
                    }
                }
            }
        }
        if( pLastBox ) // Robust
        {
            // The new borders of the master cell...
            SvxBoxItem aBox( pMergeBox->GetFrameFormat()->GetBox() );
            bool bOld = aBox.GetRight() || aBox.GetBottom();
            const SvxBoxItem& rBox = pLastBox->GetFrameFormat()->GetBox();
            aBox.SetLine( rBox.GetRight(), SvxBoxItemLine::RIGHT );
            aBox.SetLine( rBox.GetBottom(), SvxBoxItemLine::BOTTOM );
            if( bOld || aBox.GetLeft() || aBox.GetTop() || aBox.GetRight() || aBox.GetBottom() )
                (*ppMergeBox)->GetFrameFormat()->SetFormatAttr( aBox );
        }

        if( pUndo )
            pUndo->AddNewBox( pMergeBox->GetSttIdx() );
    }
    return bMerge;
}

/** SwTable::FindSuperfluousRows_(..) is looking for superfluous rows, i.e. rows
    containing overlapped cells only.
*/


void SwTable::FindSuperfluousRows_( SwSelBoxes& rBoxes,
    SwTableLine* pFirstLn, SwTableLine* pLastLn )
{
    if( !pFirstLn || !pLastLn )
    {
        if( rBoxes.empty() )
            return;
        pFirstLn = rBoxes[0]->GetUpper();
        pLastLn = rBoxes.back()->GetUpper();
    }
    sal_uInt16 nFirstLn = GetTabLines().GetPos( pFirstLn );
    sal_uInt16 nLastLn = GetTabLines().GetPos( pLastLn );
    for( sal_uInt16 nRow = nFirstLn; nRow <= nLastLn; ++nRow )
    {
        SwTableLine* pLine = m_aLines[nRow];
        OSL_ENSURE( pLine, "Missing table line" );
        const size_t nCols = pLine->GetTabBoxes().size();
        bool bSuperfl = true;
        for( size_t nCol = 0; nCol < nCols; ++nCol )
        {
            SwTableBox *pBox = pLine->GetTabBoxes()[nCol];
            if( pBox->getRowSpan() > 0 &&
                rBoxes.end() == rBoxes.find( pBox ) )
            {
                bSuperfl = false;
                break;
            }
        }
        if( bSuperfl )
        {
            for( size_t nCol = 0; nCol < nCols; ++nCol )
            {
                SwTableBox* pBox = pLine->GetTabBoxes()[nCol];
                rBoxes.insert( pBox );
            }
        }
    }
}

/** SwTableBox::FindStartOfRowSpan(..) returns the "master" cell, the cell which
    overlaps the given cell, it maybe the cell itself.
*/


SwTableBox& SwTableBox::FindStartOfRowSpan( const SwTable& rTable, sal_uInt16 nMaxStep )
{
    if( getRowSpan() > 0 || !nMaxStep )
        return *this;

    tools::Long nLeftBorder = lcl_Box2LeftBorder( *this );
    SwTableBox* pBox = this;
    const SwTableLine* pMyUpper = GetUpper();
    sal_uInt16 nLine = rTable.GetTabLines().GetPos( pMyUpper );
    if( nLine && nLine < rTable.GetTabLines().size() )
    {
        SwTableBox* pNext;
        do
        {
            pNext = lcl_LeftBorder2Box( nLeftBorder, rTable.GetTabLines()[--nLine] );
            if( pNext )
                pBox = pNext;
        } while( nLine && --nMaxStep && pNext && pBox->getRowSpan() < 1 );
    }

    return *pBox;
}

/** SwTableBox::FindEndOfRowSpan(..) returns the last overlapped cell if there is
    any. Otherwise the cell itself will returned.
*/


SwTableBox& SwTableBox::FindEndOfRowSpan( const SwTable& rTable, sal_uInt16 nMaxStep )
{
    tools::Long nAbsSpan = getRowSpan();
    if( nAbsSpan < 0 )
        nAbsSpan = -nAbsSpan;
    if( nAbsSpan == 1 || !nMaxStep )
        return *this;

    if( nMaxStep > --nAbsSpan )
        nMaxStep = o3tl::narrowing<sal_uInt16>(nAbsSpan);
    const SwTableLine* pMyUpper = GetUpper();
    sal_uInt16 nLine = rTable.GetTabLines().GetPos( pMyUpper );
    nMaxStep = nLine + nMaxStep;
    if( nMaxStep >= rTable.GetTabLines().size() )
        nMaxStep = rTable.GetTabLines().size() - 1;
    tools::Long nLeftBorder = lcl_Box2LeftBorder( *this );
    SwTableBox* pBox =
        lcl_LeftBorder2Box( nLeftBorder, rTable.GetTabLines()[ nMaxStep ] );
    if ( !pBox )
        pBox = this;

    return *pBox;
}

/** lcl_getAllMergedBoxes(..) collects all overlapped boxes to a given (master) box
*/


static void lcl_getAllMergedBoxes( const SwTable& rTable, SwSelBoxes& rBoxes, SwTableBox& rBox )
{
    SwTableBox* pBox = &rBox;
    OSL_ENSURE( pBox == &rBox.FindStartOfRowSpan( rTable ), "Not a master box" );
    rBoxes.insert( pBox );
    if( pBox->getRowSpan() == 1 )
        return;
    const SwTableLine* pMyUpper = pBox->GetUpper();
    sal_uInt16 nLine = rTable.GetTabLines().GetPos( pMyUpper );
    tools::Long nLeftBorder = lcl_Box2LeftBorder( *pBox );
    sal_uInt16 nCount = rTable.GetTabLines().size();
    while( ++nLine < nCount && pBox && pBox->getRowSpan() != -1 )
    {
        pBox = lcl_LeftBorder2Box( nLeftBorder, rTable.GetTabLines()[nLine] );
        if( pBox )
            rBoxes.insert( pBox );
    }
}

/** lcl_UnMerge(..) manipulates the row span attribute of a given master cell
    and its overlapped cells to split them into several pieces.
*/


static void lcl_UnMerge( const SwTable& rTable, SwTableBox& rBox, size_t nCnt,
    bool bSameHeight )
{
    SwSelBoxes aBoxes;
    lcl_getAllMergedBoxes( rTable, aBoxes, rBox );
    size_t const nCount = aBoxes.size();
    if( nCount < 2 )
        return;
    if( nCnt > nCount )
        nCnt = nCount;
    std::unique_ptr<size_t[]> const pSplitIdx(new size_t[nCnt]);
    if( bSameHeight )
    {
        std::unique_ptr<SwTwips[]> const pHeights(new SwTwips[nCount]);
        SwTwips nHeight = 0;
        for (size_t i = 0; i < nCount; ++i)
        {
            SwTableLine* pLine = aBoxes[ i ]->GetUpper();
            SwFrameFormat *pRowFormat = pLine->GetFrameFormat();
            pHeights[ i ] = pRowFormat->GetFrameSize().GetHeight();
            nHeight += pHeights[ i ];
        }
        SwTwips nSumH = 0;
        size_t nIdx = 0;
        for (size_t i = 1; i <= nCnt; ++i)
        {
            SwTwips nSplit = ( i * nHeight ) / nCnt;
            while( nSumH < nSplit && nIdx < nCount )
                nSumH += pHeights[ nIdx++ ];
            pSplitIdx[ i - 1 ] = nIdx;
        }
    }
    else
    {
        for (size_t i = 1; i <= nCnt; ++i)
        {
            pSplitIdx[ i - 1 ] = ( i * nCount ) / nCnt;
        }
    }
    size_t nIdx = 0;
    for (size_t i = 0; i < nCnt; ++i)
    {
        size_t nNextIdx = pSplitIdx[ i ];
        aBoxes[ nIdx ]->setRowSpan( nNextIdx - nIdx );
        lcl_InvalidateCellFrame( *aBoxes[ nIdx ] );
        while( ++nIdx < nNextIdx )
            aBoxes[ nIdx ]->setRowSpan( nIdx - nNextIdx );
    }
}

/** lcl_FillSelBoxes(..) puts all boxes of a given line into the selection structure
*/


static void lcl_FillSelBoxes( SwSelBoxes &rBoxes, SwTableLine &rLine )
{
    const size_t nBoxCount = rLine.GetTabBoxes().size();
    for( size_t i = 0; i < nBoxCount; ++i )
        rBoxes.insert( rLine.GetTabBoxes()[i] );
}

/** SwTable::InsertSpannedRow(..) inserts "superfluous" rows, i.e. rows containing
    overlapped cells only. This is a preparation for an upcoming split.
*/


void SwTable::InsertSpannedRow( SwDoc& rDoc, sal_uInt16 nRowIdx, sal_uInt16 nCnt )
{
    CHECK_TABLE( *this )
    OSL_ENSURE( nCnt && nRowIdx < GetTabLines().size(), "Wrong call of InsertSpannedRow" );
    SwSelBoxes aBoxes;
    SwTableLine& rLine = *GetTabLines()[ nRowIdx ];
    lcl_FillSelBoxes( aBoxes, rLine );
    SwFormatFrameSize aFSz( rLine.GetFrameFormat()->GetFrameSize() );
    if( SwFrameSize::Variable != aFSz.GetHeightSizeType() )
    {
        SwFrameFormat* pFrameFormat = rLine.ClaimFrameFormat();
        tools::Long nNewHeight = aFSz.GetHeight() / ( nCnt + 1 );
        if( !nNewHeight )
            ++nNewHeight;
        aFSz.SetHeight( nNewHeight );
        pFrameFormat->SetFormatAttr( aFSz );
    }
    InsertRow_( rDoc, aBoxes, nCnt, truetrue );
    const size_t nBoxCount = rLine.GetTabBoxes().size();
    for( sal_uInt16 n = 0; n < nCnt; ++n )
    {
        SwTableLine *pNewLine = GetTabLines()[ nRowIdx + nCnt - n ];
        for( size_t nCurrBox = 0; nCurrBox < nBoxCount; ++nCurrBox )
        {
            sal_Int32 nRowSpan = rLine.GetTabBoxes()[nCurrBox]->getRowSpan();
            if( nRowSpan > 0 )
                nRowSpan = - nRowSpan;
            pNewLine->GetTabBoxes()[ nCurrBox ]->setRowSpan( nRowSpan - n );
        }
    }
    lcl_ChangeRowSpan( *this, nCnt, nRowIdx, false );
    CHECK_TABLE( *this )
}

typedef std::pair< sal_uInt16, sal_uInt16 > SwLineOffset;
typedef std::vector< SwLineOffset > SwLineOffsetArray;

/*
* When a couple of table boxes has to be split,
* lcl_SophisticatedFillLineIndices delivers the information where and how many
* rows have to be inserted.
* Input
*     rTable: the table to manipulate
*     rBoxes: an array of boxes to split
*     nCnt:   how many parts are wanted
* Output
*     rArr:   a list of pairs ( line index, number of lines to insert )
*/

static void lcl_SophisticatedFillLineIndices( SwLineOffsetArray &rArr,
    const SwTable& rTable, const SwSelBoxes& rBoxes, sal_uInt16 nCnt )
{
    std::list< SwLineOffset > aBoxes;
    SwLineOffset aLnOfs( USHRT_MAX, USHRT_MAX );
    for (size_t i = 0; i < rBoxes.size(); ++i)
    {   // Collect all end line indices and the row spans
        const SwTableBox &rBox = rBoxes[ i ]->FindStartOfRowSpan( rTable );
        OSL_ENSURE( rBox.getRowSpan() > 0, "Didn't I say 'StartOfRowSpan' ??" );
        if( nCnt > rBox.getRowSpan() )
        {
            const SwTableLine *pLine = rBox.GetUpper();
            const sal_uInt16 nEnd = sal_uInt16( rBox.getRowSpan() +
                rTable.GetTabLines().GetPos(  pLine ) );
            // The next if statement is a small optimization
            if( aLnOfs.first != nEnd || aLnOfs.second != rBox.getRowSpan() )
            {
                aLnOfs.first = nEnd; // ok, this is the line behind the box
                aLnOfs.second = sal_uInt16( rBox.getRowSpan() ); // the row span
                aBoxes.insert( aBoxes.end(), aLnOfs );
            }
        }
    }
    // As I said, I noted the line index _behind_ the last line of the boxes
    // in the resulting array the index has to be _on_ the line
    // nSum is to evaluate the wished value
    sal_uInt16 nSum = 1;
    while( !aBoxes.empty() )
    {
        // I. step:
        // Looking for the "smallest" line end with the smallest row span
        std::list< SwLineOffset >::iterator pCurr = aBoxes.begin();
        aLnOfs = *pCurr; // the line end and row span of the first box
        while( ++pCurr != aBoxes.end() )
        {
            if( aLnOfs.first > pCurr->first )
            {   // Found a smaller line end
                aLnOfs.first = pCurr->first;
                aLnOfs.second = pCurr->second; // row span
            }
            else if( aLnOfs.first == pCurr->first &&
                     aLnOfs.second < pCurr->second )
                aLnOfs.second = pCurr->second; // Found a smaller row span
        }
        OSL_ENSURE( aLnOfs.second < nCnt, "Clean-up failed" );
        aLnOfs.second = nCnt - aLnOfs.second; // the number of rows to insert
        rArr.emplace_back( aLnOfs.first - nSum, aLnOfs.second );
        // the correction has to be incremented because in the following
        // loops the line ends were manipulated
        nSum = nSum + aLnOfs.second;

        pCurr = aBoxes.begin();
        while( pCurr != aBoxes.end() )
        {
            if( pCurr->first == aLnOfs.first )
            {   // These boxes can be removed because the last insertion
                // of rows will expand their row span above the needed value
                pCurr = aBoxes.erase(pCurr);
            }
            else
            {
                bool bBefore = ( pCurr->first - pCurr->second < aLnOfs.first );
                // Manipulation of the end line indices as if the rows are
                // already inserted
                pCurr->first =                                 SwTableLine pTmpL=rBoxGetUpper(;
                if( bBefore )
                {   // If the insertion is inside the box,
                   // its row span has to be incremented
                    pCurr->second = pCurr-                                        = false
                    if( pCurr->second >= nCnt )
{   // if the row span is bigger than the split factor
                        // this box is done
                        pCurr = aBoxes.erase(pCurr                                }
                    }                            
                    else
                        ++pCurr;                                   ( nLeftSpanCnt)
                }
                else
                    ++pCurr;
            }
        }
    }
}

typedef std::set< SwTwips > SwSplitLines;

/** lcl_CalculateSplitLineHeights(..) delivers all y-positions where table rows have
    to be split to fulfill the requested "split same height"
*/


 sal_uInt16lcl_CalculateSplitLineHeights( wSplitLines&CurrSwSplitLinesrNew
    const SwTableelse
{
    if( nCnt < 2 )
return0
    std::vector< SwLineOffset >  nRightSpanCnt  ;
    SwLineOffset aLnOfs                            
    sal_uInt16 if nCheck>nCheckBottom 
    sal_uInt16 nLast = 0; // becomes the index of the last line of the splitting
    for (size_t i = 0; i < rBoxes.size(); ++                             &pRightBox  ) )
    {   // Collect all pairs (start+end) of line indices to split
const rBox[  -FindStartOfRowSpan rTable;
"DidntStartOfRowSpan'?" )
        const SwTableLine *pLine = rBox.GetUpper();
        const sal_uInt16 nStart = rTable.GetTabLines()                        . = nDiff
( rBox.() +nStart 1)java.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77
        // The next if statement is a small optimizationpOuterBox  pOuterBox = pRightBox ?nullptr pRightBox
        if( aLnOfs.first != nStartnDiff  ;
        {
            aLnOfs.first = nStart;
            aLnOfs.second = nEnd;
            aBoxes.push_back( aLnOfs );
ifnStart  )
                nFirst = nStart;
if(nEnd nLast )
nLast=nEnd
        }
    }

    if (nFirst =        >   - ;
    {
        assert(aBoxes.emptySwFrameFormat*pFormat newWidthfirst-();
return;
    }

    pFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nNewWidth, 0 ) );
    std::unique_ptr<SwTwips[]>pLines(newSwTwips  + 1 -nFirst;
    for( sal_uInt16 i = nFirst; i <= nLast; ++i )
    {
        bool bLayoutAvailable = false;
        nHeight
        rCurr.}
        pLines[ java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
    forauto rSplit )
        {
        SwTwips nBase = rSplit.first <= nFirst        java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
                        ifpLower
        SwTwips nDiff    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
        for( sal_uInt16 i = 1; i < nCntand returns the average cell widths
        java.lang.StringIndexOutOfBoundsException: Range [9, 10) out of bounds for length 9
SwTwipsnSplit nBase +(i*nDiff)/nCnt
.insertnSplit;
        }
    }
    return nFirst;
}

/** lcl_LineIndex(..) delivers the line index of the line behind or above
    the box selection.
*/


static
n =;
{
    sal_uInt16
    sal_uInt16 nSpan = USHRT_MAX;
    for
    the selected boxes
        SwTableBox@param nCnt
        const SwTableLine* java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
        sal_uInt16
        ifUSHRT_MAX= )
{
            if( bBehind )
            {
                if( nPosif .()| !nCnt )

                sal_Int32 nRowSpan = pBox->getRowSpan
                if( nRowSpan < 2 )
                    nSpan = 0;
if  )
                nTabl =m_aLines]>([]>(>(.(;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
                    if/
                        nSpan = nEndOfRowSpan;
                }
            }
            else if( nPos < nDirect )
                nDirect = nPos;
        }
    }
    if( nSpan && nSpan < USHRT_MAX )
        returnnSpan;
    return nDirect;
}

/** SwTable::NewSplitRow(..) splits all selected boxes horizontally.
*/


bool SwTable          nAddWidthnTableWidth  java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64
                           bool bSameHeight )
{
    CHECK_TABLE( *this )
    ++nCnt;
    FndBox_ aFndBox( nullptr, nullptr );
    aFndBox.SetTableLines( rBoxes, *this );

    if( bSameHeight      aFndBox nullptr, nullptr;
    {
        SwSplitLines aRowLines
        SwSplitLines aSplitLines;
        sal_uInt16 nFirst = lcl_CalculateSplitLineHeights(     nLastLine SAL_MAX_SIZE
            *this,
        aFndBox.DelFrames( *this );
        SwTwips nLast = 0;
        SwSplitLines::iterator  assertnInsPos!USHRT_MAX);//java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68
        forconst auto&             n;
        {
            while  ! .end &* <rCurr
            
               (rDoc ,  ;
                SwTableLine* pRow = GetTabLines()[ nFirst ];
        (  !  &nDiff  &java.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 65
                 bNewSpan truejava.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
                aFSz                *pTmpLine=[nLastLine;
                aFSz.SetHeight(                 (bBehind
                pRowFormat-                (  j =0 j  nCnt+j)
                nLast = *pSplit;
                ++pSplit;
                +nFirst
}
            if                      nDiff
                ++pSplit;
            SwTableLine        ( nRowSpan  java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
SwFrameFormat  = pRow-ClaimFrameFormat
            SwFormatFrameSize aFSznLastRowSpan nRowSpan
            aFSz.                 = ;
aFSzSetHeight Curr- )java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
            pRowFormat->SetFormatAttr( aFSz );
nLast;
            ++nFirst;
        }
    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
    else
    {
        aFndBox.DelFrames /java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
        bSameHeight =            
    }
    if( !bSameHeight )
    {
         aLineOffs
        lcl_SophisticatedFillLineIndices( aLineOffs, *this, rBoxes, nCnt );
SwLineOffsetArray: pCurraLineOffsrbegin() )java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
            
        {i( java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
            InsertSpannedRow( rDoc, pCurr->first, pCurr->second );
            ++pCurr;
        }
    }

stdset> aIndices
    for (size_t i = 0; i < rBoxes.size(                    pFrameFormat-SetFormatAttr( *pNoRightBorder)
    {
        OSL_ENSURE( rBoxes[i]->getRowSpan            else
        if( rBoxesi]->getRowSpan() > 1 )
            aIndices.insert( i );
    }

    forconst auto& rCurrBox : aIndices )
        lcl_UnMerge( *this, *rBoxes[rCurrBox], nCnt, bSameHeight );

    CHECK_TABLE( *}
/ update the
    aFndBox.MakeFrames( *this );

    return true;
}

/** SwTable::InsertRow(..) inserts one or more rows before or behind the selected
    boxes.
*/


bool SwTable::InsertRow( SwDoc& the cells which have to be deleted by Merge(..) afterwards.
                        sal_uInt16 nCnt, bool@param rPam
{
    bool bRet = false;
    if( IsNewModel() )
    {
        CHECK_TABLE( 
        sal_uInt16 nRowIdx = lcl_LineIndex*/
boolSwTablePrepareMergeconstSwPaMrPam & rBoxes

            FndBox_ aFndBox( nullptr, nullptrif(! )
            aFndBox.SetTableLines( rBoxes, *this );
       .DelFrames * );

            bRet         :( rPam rBoxes ppMergeBox pUndo;
            SwTableLine *pLine = GetTabLines()    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
            SwSelBoxes aLineBoxes;/java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47
            lcl_FillSelBoxes( aLineBoxes, *pLine );
            InsertRow_( rDocifrFirstBoxes()
    >(.()java.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 65
             nOfs bBehind
            for( sal_uInt16 n =    // The new master box will get the left and the top border of the top-left
            {
                SwTableLine *pNewLine = GetTabLines()[ nRowIdxSwTableBox pLastBox  nullptr // the right-bottom (master) cell
                for (;
                {
                    sal_Int32 nRowSpan = pLine->GetTabBoxes()[nCurrBox]->getRowSpan();
                    if( bBehind )
                    {
if(nRowSpan=1| nRowSpan =- )
                            nRowSpan    
                        else if( nRowSpan > 1 )
                        {
nRowSpan=- nRowSpan;

        /The  in current
                            
                            // renumbering of next list elements
                            SwTableBox* pBox = pNewLine->GetTabBoxes()[nCurrBox];
                            java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 9
                            SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
            / the other will be deleted => put into rBoxes
                            {
                                SwPaM aPam( *pCNd->GetTextNode(rBoxes.( pBox;
                                rDoc.DelNumRules( aPam );
                            }
                        }
                    }
                    else
                    {
                        if( nRowSpan > 0 )
                            nRowSpan = n + 1;
                        else
                            --nRowSpan            ( + nColCount>(> java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
                                    
                    pNewLine->                if( !IsEmptyBox(  )java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
}
            }aPam(-Assign*>(->() (-1 ;
            if( bBehind )
                ++nRowIdxaPamGetPoint)>( >Len)
            if( nRowIdx )
                lcl_ChangeRowSpan( *this, nCnt, --nRowIdx, true );
            // update the layout
            aFndBox.MakeFrames( *this );
        }
        CHECK_TABLE( *this )
    }
    else
        bRet = InsertRow_( rDoc, rBoxes,.().DoUndo);
    return bRet;
}

/** SwTable::PrepareDelBoxes(..) adjusts the row span attributes for an upcoming
    deletion of table cells and invalidates the layout of these cells.
*/


void SwTable::PrepareDelBoxes( const SwSelBoxes& rBoxes )
{
    if IsNewModel java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
        return;

    for (size_t i = 0; i < rBoxes.size()(  >0)
    {
SwTableBox pBox=[];
        sal_Int32    java.lang.StringIndexOutOfBoundsException: Range [5, 6) out of bounds for length 5
        if( nRowSpan        / these cells can be put into rBoxes for deletion
        {
            tools::Long nLeft = lcl_Box2LeftBorder( *pBox        
            SwTableLine *pLine = pBox->GetUpper();
            sal_uInt16 nLinePos = GetTabLines().GetPos( pLine);
            OSL_ENSURE( nLinePos < USHRT_MAX {
            if( nRowSpan > 1            const& rLineBoxes  >maBoxesnCurrLine];
            {
                if( ++nLinePos < GetTabLines().size() )
                {
                    pLine = GetTabLines{
                    pBox = lcl_LeftBorder2Box( nLeft, pLine );
                                        SwFrameFormat =pBox-ClaimFrameFormat;
                    if( pBox )
                        pBox->else
                }
            }
            else if( nLinePos > 0 )
            {
                java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
                {
                    pLine = GetTabLines()[ --nLinePos ];
                    pBox = lcl_LeftBorder2Box( nLeft, pLine );
                    OSL_ENSURE
                    if( pBox )
}
                        nRowSpan = pBox->getRowSpan();
                        
                        {
                            lcl_InvalidateCellFrame * );
                            --nRowSpan;
                        }
                        else
                            ++nRowSpan;
                        pBox->setRowSpan(  ifbOld|aBox( |aBox()| aBox.( | aBoxGetBottom)
                    }
                    else
                        nRowSpan
}
whilenRowSpan <  >0 )
            }
        }
    }
}

/** lcl_SearchSelBox(..) adds cells of a given table row to the selection structure
    if it overlaps with the given x-position range
*/


static void lcl_SearchSelBox( const SwTable
                       SwTableLine& rLine,            ;
{
    tools::Long nLeft = 0;
:  =0
         size_tnCols=pLine-GetTabBoxes(.size();
    const size_t nCount = rLine.GetTabBoxes().size();
forsize_tnCurrBox  0  <nCount+ java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
    {
        SwTableBox* pBox = rLine.                .nd( =rBoxes( pBox) java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
        OSL_ENSURE( pBox, "Missing table box" );
        ( bSuperfl
        nRight += nWidth;
        if( nRight > nMin )
        java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
            bool
                
                
                       nRight - nMin > nMin - nLeft;
            else
                  nLeft=nMid |nRight  <nMax nLeft;
            sal_Int32 nRowSpan = pBox-    if getRowSpan( >  | nMaxStep
            if( bAdd &java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
                 !ChkProtected ||
                !pBox->GetFrameFormat()->GetProtect().IsContentProtected() ) )
            {
 const  .(;
                rBoxes.insert( pBox );
ifbColumn&  =1& nOldCnt.())
                {
                    SwTableBox *pMasterBox = pBox->getRowSpan() > 0 ? pBox    {
                        : &pBox->FindStartOfRowSpan( rTable
                    ( rTablerBoxes,* )
                }
            }
        }
        if( nRight >= nMax )
            break;
        nLeft
    }
}

/** void SwTable::CreateSelection(..) fills the selection structure with table cells
    for a given SwPaM, ie. start and end position inside a table
*/


 :CreateSelection SwPaM , & ,
    const           nAbsSpan
{
    OSL_ENSURE( m_bNewModel, "Don't call me for old tables" );
    if(nMaxStep -nAbsSpan)
        return;
    const SwNode* pStartNd        nMaxStep o3tl::narrowing<>nAbsSpan
    const SwNode* pEndNd = rPam.GetMark()->GetNode().FindTableBoxStartNode();
    if( !pStartNd || !pEndNd )

    CreateSelection( pStartNd, pEndNd, rBoxesnMaxStep=.GetTabLines.()-;
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1

/** void SwTable::CreateSelection(..) fills the selection structure with table cells
    for given start and end nodes inside a table
*/

void SwTable::CreateSelection(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    SwSelBoxes& rBoxes, const SearchType eSearch,java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
{
    rBoxes.clear();
/java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
    const size_t nLines = m_aLines.size();
/java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52
    // nBottom becomes the line number of the lower box
    size_t nTop = 0;
    size_t nBottom = 0    constSwTableLinepMyUpper >GetUpper(;
    // nUpperMin becomes the left border value of the upper box
    // nUpperMax becomes the right border of the upper box
    al_uInt16nCount.GetTabLines
    tools::Long nUpperMin = 0, nUpperMax = 0;
    toolsLongnLowerMin 0,nLowerMax=0;
        if pBox)
    }
    int nFound = 0;
    for( size_t nRow = 0; nFound    and its overlapped cells to split them into several pieces.
    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
        SwTableLine* pLine = m_aLines[nRow];
        OSL_ENSURE( pLine, "Missing const = aBoxes.();
        const size_t nCols = pLine-;
        for( size_t nCol = 0; nCol < nCols; ++nCol )
        {
                    stdS[>const(newn])java.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
            OSL_ENSURE( pBox, "Missing table box" );
           ifpBox-GetSttNd)= pEndNd | pBox->etSttNd)= pStartNd)
            {
                if( !bChkProtectednHeight [ i ;
                    !pBox->GetFrameFormat()->GetProtect().IsContentProtected() )
                    rBoxes.insertfor(size_t=1  = ; +i
                if(             nSplit  *nHeight/nCnt
--> --------------------

--> maximum size reached

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

Messung V0.5
C=92 H=83 G=87

¤ Dauer der Verarbeitung: 0.24 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.