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

Quelle  gctable.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 <hintids.hxx>
#include <tblrwcl.hxx>
#include <algorithm>
#include <editeng/borderline.hxx>
#include <editeng/boxitem.hxx>
#include <osl/diagnose.h>

using namespace ::editeng;

static const SvxBorderLine* GetLineTB( const SvxBoxItem* pBox, bool bTop )
{
    return bTop ? pBox->GetTop() : pBox->GetBottom();
}

bool SwGCBorder_BoxBrd::CheckLeftBorderOfFormat( const SwFrameFormat& rFormat )
{
    ifconst SvxBoxItem* pItem = rFormat.GetItemIfSet( RES_BOX ) )
    {
        const SvxBorderLine* pBrd = pItem->GetLeft();
        if( pBrd )
        {
            if( *m_pBorderLine == *pBrd )
                m_bAnyBorderFind = true;
            return true;
        }
    }
    return false;
}

static bool lcl_GCBorder_ChkBoxBrd_B( const SwTableBox* pBox, SwGCBorder_BoxBrd* pPara );

static bool lcl_GCBorder_ChkBoxBrd_L( const SwTableLine* pLine, SwGCBorder_BoxBrd* pPara )
{
    const SwTableBox* pBox = pLine->GetTabBoxes().front();
    return lcl_GCBorder_ChkBoxBrd_B( pBox, pPara );
}

static bool lcl_GCBorder_ChkBoxBrd_B( const SwTableBox* pBox, SwGCBorder_BoxBrd* pPara )
{
    if( !pBox->GetTabLines().empty() )
    {
        forauto pLine : pBox->GetTabLines() )
        {
            if (!lcl_GCBorder_ChkBoxBrd_L( pLine, pPara ))
            {
                return false;
            }
        }
        return true;
    }

    return pPara->CheckLeftBorderOfFormat( *pBox->GetFrameFormat() );
}

static void lcl_GCBorder_GetLastBox_B( const SwTableBox* pBox, SwTableBoxes* pPara );

static void lcl_GCBorder_GetLastBox_L( const SwTableLine* pLine, SwTableBoxes* pPara )
{
    const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
    SwTableBox* pBox = rBoxes.back();
    lcl_GCBorder_GetLastBox_B( pBox, pPara );
}

static void lcl_GCBorder_GetLastBox_B( const SwTableBox* pBox, SwTableBoxes* pPara )
{
    const SwTableLines& rLines = pBox->GetTabLines();
    if( !rLines.empty() )
    {
        forconst SwTableLine* pLine : rLines )
            lcl_GCBorder_GetLastBox_L( pLine, pPara );
    }
    else
        pPara->push_back( const_cast<SwTableBox*>(pBox) );
}

// Find the "end" of the passed BorderLine. Returns the "Layout"Pos!
static sal_uInt16 lcl_FindEndPosOfBorder( const SwCollectTableLineBoxes& rCollTLB,
                        const SvxBorderLine& rBrdLn, size_t& rStt, bool bTop )
{
    sal_uInt16 nPos, nLastPos = 0;
    for( size_t nEnd = rCollTLB.Count(); rStt < nEnd; ++rStt )
    {
        const SvxBorderLine* pBrd;
        const SwTableBox& rBox = rCollTLB.GetBox( rStt, &nPos );
        const SvxBoxItem* pItem = rBox.GetFrameFormat()->GetItemIfSet(RES_BOX);

        if( !pItem )
            break;
        pBrd = GetLineTB( pItem, bTop );
        if( !pBrd || *pBrd != rBrdLn )
            break;
        nLastPos = nPos;
    }
    return nLastPos;
}

static const SvxBorderLine* lcl_GCBorder_GetBorder( const SwTableBox& rBox,
                                                bool bTop,
                                                const SvxBoxItem** ppItem )
{
    *ppItem = rBox.GetFrameFormat()->GetItemIfSet( RES_BOX );
    if (*ppItem)
        return GetLineTB( *ppItem, bTop );
    return nullptr;
}

static void lcl_GCBorder_DelBorder( const SwCollectTableLineBoxes& rCollTLB,
                                size_t& rStt, bool bTop,
                                const SvxBorderLine& rLine,
                                const SvxBoxItem* pItem,
                                sal_uInt16 nEndPos,
                                SwShareBoxFormats* pShareFormats )
{
    SwTableBox* pBox = const_cast<SwTableBox*>(&rCollTLB.GetBox( rStt ));
    sal_uInt16 nNextPos;
    const SvxBorderLine* pLn = &rLine;

    do {
        if( pLn && *pLn == rLine )
        {
            SvxBoxItem aBox( *pItem );
            if( bTop )
                aBox.SetLine( nullptr, SvxBoxItemLine::TOP );
            else
                aBox.SetLine( nullptr, SvxBoxItemLine::BOTTOM );

            if( pShareFormats )
                pShareFormats->SetAttr( *pBox, aBox );
            else
                pBox->ClaimFrameFormat()->SetFormatAttr( aBox );
        }

        if( ++rStt >= rCollTLB.Count() )
            break;

        pBox = const_cast<SwTableBox*>(&rCollTLB.GetBox( rStt, &nNextPos ));
        if( nNextPos > nEndPos )
            break;

        pLn = lcl_GCBorder_GetBorder( *pBox, bTop, &pItem );

    } whiletrue );
}

static void lcl_GC_Box_Border( const SwTableBox* pBox, SwGCLineBorder* pPara );

void sw_GC_Line_Border( const SwTableLine* pLine, SwGCLineBorder* pGCPara )
{
    // First the right edge with the left edge of the succeeding Box within this Line
    {
        SwGCBorder_BoxBrd aBPara;
        const SvxBorderLine* pBrd;
        const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
        for( SwTableBoxes::size_type n = 0, nBoxes = rBoxes.size() - 1; n < nBoxes; ++n )
        {
            SwTableBoxes aBoxes;
            {
                SwTableBox* pBox = rBoxes[ n ];
                if( pBox->GetSttNd() )
                    aBoxes.insert( aBoxes.begin(), pBox );
                else
                    lcl_GCBorder_GetLastBox_B( pBox, &aBoxes );
            }

            for( SwTableBoxes::size_type i = aBoxes.size(); i; )
            {
                SwTableBox* pBox = aBoxes[ --i ];
                ifconst SvxBoxItem* pItem = pBox->GetFrameFormat()->GetItemIfSet( RES_BOX ) )
                {
                    pBrd = pItem->GetRight();
                    if( pBrd )
                    {
                        aBPara.SetBorder( *pBrd );
                        const SwTableBox* pNextBox = rBoxes[n+1];
                        if( lcl_GCBorder_ChkBoxBrd_B( pNextBox, &aBPara ) &&
                            aBPara.IsAnyBorderFound() )
                        {
                            SvxBoxItem aBox( *pItem );
                            aBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
                            if( pGCPara->pShareFormats )
                                pGCPara->pShareFormats->SetAttr( *pBox, aBox );
                            else
                                pBox->ClaimFrameFormat()->SetFormatAttr( aBox );
                        }
                    }
                }
            }

            aBoxes.clear();
        }
    }

    // And now the own bottom edge with the succeeding top edge
    if( !pGCPara->IsLastLine() )
    {
        SwCollectTableLineBoxes aBottom( false );
        SwCollectTableLineBoxes aTop( true );

        sw_Line_CollectBox( pLine, &aBottom );

        const SwTableLine* pNextLine = (*pGCPara->pLines)[ pGCPara->nLinePos+1 ];
        sw_Line_CollectBox( pNextLine, &aTop );

        // remove all "duplicated" Lines that are the same
        sal_uInt16 nBtmPos, nTopPos;

        size_t nSttBtm {0};
        size_t nSttTop {0};
        const size_t nEndBtm {aBottom.Count()};
        const size_t nEndTop {aTop.Count()};

        const SwTableBox *pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
        const SwTableBox *pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
        const SvxBoxItem *pBtmItem = nullptr, *pTopItem = nullptr;
        const SvxBorderLine *pBtmLine(nullptr), *pTopLine(nullptr);
        bool bGetTopItem = true, bGetBtmItem = true;

        do {
            if( bGetBtmItem )
                pBtmLine = lcl_GCBorder_GetBorder( *pBtmBox, false, &pBtmItem );
            if( bGetTopItem )
                pTopLine = lcl_GCBorder_GetBorder( *pTopBox, true, &pTopItem );

            if( pTopLine && pBtmLine && *pTopLine == *pBtmLine )
            {
                // We can remove one, but which one?
                const size_t nSavSttBtm {nSttBtm};
                const size_t nSavSttTop {nSttTop};
                sal_uInt16 nBtmEndPos = ::lcl_FindEndPosOfBorder( aBottom,
                                                *pTopLine, nSttBtm, false );
                if( !nBtmEndPos ) nBtmEndPos = nBtmPos;
                sal_uInt16 nTopEndPos = ::lcl_FindEndPosOfBorder( aTop,
                                                *pTopLine, nSttTop, true );
                if( !nTopEndPos ) nTopEndPos = nTopPos;

                if( nTopEndPos <= nBtmEndPos )
                {
                    // Delete the TopBorders until BottomEndPos
                    nSttTop = nSavSttTop;
                    if( nTopPos <= nBtmEndPos )
                        lcl_GCBorder_DelBorder( aTop, --nSttTop, true,
                                            *pBtmLine, pTopItem, nBtmEndPos,
                                            pGCPara->pShareFormats );
                    else
                        nSttBtm = nSavSttBtm;
                }
                else
                {
                    // Else delete the BottomBorders until TopEndPos
                    nSttBtm = nSavSttBtm;
                    if( nBtmPos <= nTopEndPos )
                        lcl_GCBorder_DelBorder( aBottom, --nSttBtm, false,
                                            *pTopLine, pBtmItem, nTopEndPos,
                                            pGCPara->pShareFormats );
                    else
                        nSttTop = nSavSttTop;
                }
                nTopPos = nBtmPos;
            }

            if( nTopPos == nBtmPos )
            {
                if( nSttBtm >= nEndBtm || nSttTop >= nEndTop )
                    break;

                pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
                pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
                bGetTopItem = bGetBtmItem = true;
            }
            else if( nTopPos < nBtmPos )
            {
                if( nSttTop >= nEndTop )
                    break;
                pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
                bGetTopItem = true;
                bGetBtmItem = false;
            }
            else
            {
                if( nSttBtm >= nEndBtm )
                    break;
                pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
                bGetTopItem = false;
                bGetBtmItem = true;
            }

        } whiletrue );
    }

    forconst auto& rpBox : pLine->GetTabBoxes() )
        lcl_GC_Box_Border(rpBox, pGCPara );

    ++pGCPara->nLinePos;
}

static void lcl_GC_Box_Border( const SwTableBox* pBox, SwGCLineBorder* pPara )
{
    if( !pBox->GetTabLines().empty() )
    {
        SwGCLineBorder aPara( *pBox );
        aPara.pShareFormats = pPara->pShareFormats;
        forconst SwTableLine* pLine : pBox->GetTabLines() )
            sw_GC_Line_Border( pLine, &aPara );
    }
}

namespace {

struct GCLinePara
{
    SwTableLines* pLns;
    SwShareBoxFormats* pShareFormats;

    GCLinePara( SwTableLines& rLns, GCLinePara* pPara = nullptr )
        : pLns( &rLns ), pShareFormats( pPara ? pPara->pShareFormats : nullptr )
    {}
};

}

static bool lcl_MergeGCLine(SwTableLine* pLine, GCLinePara* pPara);

static bool lcl_MergeGCBox(SwTableBox* pTableBox, GCLinePara* pPara)
{
    if( !pTableBox->GetTabLines().empty() )
    {
        // ATTENTION: The Line count can change!
        GCLinePara aPara( pTableBox->GetTabLines(), pPara );
        for( SwTableLines::size_type n = 0;
            n < pTableBox->GetTabLines().size() && lcl_MergeGCLine( pTableBox->GetTabLines()[n], &aPara );
            ++n )
            ;

        if( 1 == pTableBox->GetTabLines().size() )
        {
            // we have a box with a single line, so we just replace it by the line's boxes
            SwTableLine* pInsLine = pTableBox->GetUpper();
            SwTableLine* pCpyLine = pTableBox->GetTabLines()[0];
            SwTableBoxes::iterator it = std::find( pInsLine->GetTabBoxes().begin(), pInsLine->GetTabBoxes().end(), pTableBox );
            forauto pTabBox : pCpyLine->GetTabBoxes() )
                pTabBox->SetUpper( pInsLine );

            SfxPoolItem const* pRowBrush(nullptr);
            pCpyLine->GetFrameFormat()->GetItemState(RES_BACKGROUND, true, &pRowBrush);
            if (pRowBrush)
            {
                for (auto pBox : pCpyLine->GetTabBoxes())
                {
                    if (pBox->GetFrameFormat()->GetItemState(RES_BACKGROUND) != SfxItemState::SET)
                    {   // set inner row background on inner cell
                        pBox->ClaimFrameFormat();
                        pBox->GetFrameFormat()->SetFormatAttr(*pRowBrush);
                    }
                }
            }

            // remove the old box from its parent line
            it = pInsLine->GetTabBoxes().erase( it );
            // insert the nested line's boxes in its place
            pInsLine->GetTabBoxes().insert( it, pCpyLine->GetTabBoxes().begin(), pCpyLine->GetTabBoxes().end());
            pCpyLine->GetTabBoxes().clear();
            // destroy the removed box
            delete pTableBox;

            return false// set up anew
        }
    }
    return true;
}

static bool lcl_MergeGCLine(SwTableLine* pLn, GCLinePara* pGCPara)
{
    SwTableBoxes::size_type nBoxes = pLn->GetTabBoxes().size();
    if( nBoxes )
    {
        while( 1 == nBoxes )
        {
            // We have a Box with Lines
            SwTableBox* pBox = pLn->GetTabBoxes().front();
            if( pBox->GetTabLines().empty() )
                break;

            SwTableLine* pLine = pBox->GetTabLines()[0];

            // pLine turns into the current Line (that is rpLine), the rest is moved
            // into the LinesArray past the current one.
            // The LinesArray is in pPara!
            SwTableLines::size_type nLines = pBox->GetTabLines().size();

            SwTableLines& rLns = *pGCPara->pLns;
            sal_uInt16 nInsPos = rLns.GetPos( pLn );
            OSL_ENSURE( USHRT_MAX != nInsPos, "Could not find Line!" );

            SwTableBox* pUpper = pLn->GetUpper();

            rLns.erase( rLns.begin() + nInsPos );      // remove the Line from the array
            rLns.insert( rLns.begin() + nInsPos, pBox->GetTabLines().begin(), pBox->GetTabLines().end() );

            // JP 31.03.99: Bug 60000
            // Pass the attributes of the to-be-deleted Lines to the "inserted" one
            const SfxPoolItem* pItem;
            if( SfxItemState::SET == pLn->GetFrameFormat()->GetItemState(
                                    RES_BACKGROUND, true, &pItem ))
            {
                SwTableLines& rBoxLns = pBox->GetTabLines();
                forauto pBoxLine : rBoxLns )
                    if( SfxItemState::SET != pBoxLine->GetFrameFormat()->
                            GetItemState( RES_BACKGROUND ))
                        pGCPara->pShareFormats->SetAttr( *pBoxLine, *pItem );
            }

            pBox->GetTabLines().erase( pBox->GetTabLines().begin(), pBox->GetTabLines().begin() + nLines );  // Remove Lines from the array

            delete pLn;

            // Set the dependency anew
            while( nLines-- )
                rLns[ nInsPos++ ]->SetUpper( pUpper );

            pLn = pLine;                        // and set up anew
            nBoxes = pLn->GetTabBoxes().size();
        }

        // ATTENTION: The number of boxes can change!
        SwTableBoxes::size_type nLen = 0;
        while (nLen < pLn->GetTabBoxes().size())
        {
            if( !lcl_MergeGCBox( pLn->GetTabBoxes()[nLen], pGCPara ))
            {
                if (nLen == 0)
                    break;
                --nLen;
                continue;
            }
            ++nLen;
        }
    }
    return true;
}

// Clean structure a bit
void SwTable::GCLines()
{
    // ATTENTION: The Line count can change!
    GCLinePara aPara( GetTabLines() );
    SwShareBoxFormats aShareFormats;
    aPara.pShareFormats = &aShareFormats;
    for( SwTableLines::size_type n = 0; n < GetTabLines().size() &&
            lcl_MergeGCLine( GetTabLines()[n], &aPara ); ++n )
        ;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=88 H=85 G=86

¤ Dauer der Verarbeitung: 0.6 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.