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

Quelle  tblsel.cxx   Sprache: C

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


#include <editeng/boxitem.hxx>
#include <editeng/protitem.hxx>
#include <osl/diagnose.h>

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

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

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

#undef      DEL_ONLY_EMPTY_LINES
#undef      DEL_EMPTY_BOXES_AT_START_AND_END

namespace {

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

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

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

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

}

typedef o3tl::sorted_vector<CmpLPt> MergePos;

namespace {

struct Sort_CellFrame
{
    const SwCellFrame* pFrame;

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    bool bChkProtected( SwTableSearchType::Protect & eSearchType );

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

    do {
        bool bTableIsValid = true;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        if( bTableIsValid )
            break;

        SwDeletionChecker aDelCheck( pStart );

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

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

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

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

        rBoxes.clear();
        --nLoopMax;

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

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

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

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

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

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

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

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

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

    do {
        bool bTableIsValid = true;
        bValidChartSel = true;

        sal_uInt16 nRowCells = USHRT_MAX;

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

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

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

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

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

            std::deque< Sort_CellFrame > aCellFrames;

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

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

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

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

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

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

                        // ignore if FrameRect is outside the union

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

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

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

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

            if( !bValidChartSel )
                break;

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

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

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

        if( bTableIsValid )
            break;

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

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

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

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

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

    return bValidChartSel;
}

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

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

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

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

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

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

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

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

    // First, compute tables and rectangles
    SwSelUnions aUnions;

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

    bool bTstRow = true, bFound = false;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return bFound;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

    SwRectFnSet aRectFnSet(pStart->GetUpper());

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

        SwRect &rUnion = rSelUnion.GetUnion();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        SwPaM aPam( aInsPos );

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    SwRectFnSet aRectFnSet(pTab);

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

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

    SwTwips nSX  = 0;
    SwTwips nSX2 = 0;

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

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

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

    if ( pTmp )
        rpStart = pTmp;

    pTab = pOrg;

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

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

--> maximum size reached

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

Messung V0.5
C=94 H=85 G=89

¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Normalansicht

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Dauer der Verarbeitung:

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.