Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


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.22 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge