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

Quelle  table5.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 <scitems.hxx>
#include <attrib.hxx>
#include <formulacell.hxx>
#include <table.hxx>
#include <column.hxx>
#include <document.hxx>
#include <drwlayer.hxx>
#include <global.hxx>
#include <stlpool.hxx>
#include <tabprotection.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <segmenttree.hxx>
#include <columniterator.hxx>
#include <globalnames.hxx>
#include <scmod.hxx>
#include <printopt.hxx>
#include <bcaslot.hxx>
#include <compressedarray.hxx>
#include <userdat.hxx>
#include <conditio.hxx>
#include <colorscale.hxx>
#include <cellform.hxx>

#include <com/sun/star/sheet/TablePageBreakData.hpp>

#include <editeng/brushitem.hxx>
#include <editeng/colritem.hxx>
#include <osl/diagnose.h>
#include <svl/numformat.hxx>

#include <algorithm>
#include <limits>

using ::com::sun::star::uno::Sequence;
using ::com::sun::star::sheet::TablePageBreakData;
using ::std::set;

void ScTable::UpdatePageBreaks(const ScRange* pUserArea)
{
    if (rDocument.IsImportingXML())
        return;

    // pUserArea != NULL -> print area is specified.  We need to force-update
    // the page breaks.

    if (!pUserArea)
    {
        if (!bPageSizeValid)
            return;

        // Always update breaks if force breaks option has changed
        if (mbPageBreaksValid
            && mbForceBreaks == ScModule::get()->GetPrintOptions().GetForceBreaks())
            return;
    }

    SfxStyleSheetBase* pStyle
        = rDocument.GetStyleSheetPool()->Find(aPageStyle, SfxStyleFamily::Page);
    if (!pStyle)
    {
        OSL_FAIL("UpdatePageBreaks: Style not found");
        return;
    }
    SfxItemSet* pStyleSet = &pStyle->GetItemSet();

    SCCOL nStartCol = 0;
    SCROW nStartRow = 0;
    SCCOL nEndCol = rDocument.MaxCol();
    SCROW nEndRow = rDocument.MaxRow();
    if (pUserArea)
    {
        nStartCol = pUserArea->aStart.Col();
        nStartRow = pUserArea->aStart.Row();
        nEndCol = pUserArea->aEnd.Col();
        nEndRow = pUserArea->aEnd.Row();
    }
    else
    {
        sal_uInt16 nAreaCount = GetPrintRangeCount();
        if (nAreaCount > 1)
        {
            // Show nothing, when multiple ranges

            for (SCCOL nX : GetColumnsRange(0, rDocument.MaxCol()))
                RemoveColBreak(nX, truefalse);

            RemoveRowPageBreaks(0, rDocument.MaxRow() - 1);

            return;
        }
        else if (nAreaCount == 1)
        {
            const ScRange* pArea = GetPrintRange(0);
            if (pArea)
            {
                nStartCol = pArea->aStart.Col();
                nStartRow = pArea->aStart.Row();
                nEndCol = pArea->aEnd.Col();
                nEndRow = pArea->aEnd.Row();
            }
        } // otherwise show everything
    }

    // get bSkipColBreaks/bSkipRowBreaks flags:
    // fdo#40788 - print range scale settings can cause manual breaks to be
    // ignored (see below). This behaviour may now be set by the user.
    mbForceBreaks = ScModule::get()->GetPrintOptions().GetForceBreaks();
    bool bSkipColBreaks = false;
    bool bSkipRowBreaks = false;

    if (!mbForceBreaks)
    {
        if (const SfxUInt16Item* pItem = pStyleSet->GetItemIfSet(ATTR_PAGE_SCALETOPAGES, false))
        {
            bSkipColBreaks = bSkipRowBreaks = pItem->GetValue() > 0;
        }

        const ScPageScaleToItem* pScaleToItem;
        if (!bSkipColBreaks && (pScaleToItem = pStyleSet->GetItemIfSet(ATTR_PAGE_SCALETO, false)))
        {
            // #i54993# when fitting to width or height, ignore only manual breaks in that direction
            if (pScaleToItem->GetWidth() > 0)
                bSkipColBreaks = true;
            if (pScaleToItem->GetHeight() > 0)
                bSkipRowBreaks = true;
        }
    }

    tools::Long nPageSizeX = aPageSizeTwips.Width();
    tools::Long nPageSizeY = aPageSizeTwips.Height();

    //  Beginning: Remove breaks

    for (SCCOL nX : GetColumnsRange(0, nStartCol - 1))
        RemoveColBreak(nX, truefalse);
    RemoveRowPageBreaks(0, nStartRow - 1);

    if (nStartCol > 0)
        SetColBreak(nStartCol, truefalse); // AREABREAK
    if (nStartRow > 0)
        SetRowBreak(nStartRow, truefalse); // AREABREAK

    //  Middle part: Distribute breaks

    bool bRepeatCol = (nRepeatStartX != SCCOL_REPEAT_NONE);
    bool bColFound = false;
    tools::Long nSizeX = 0;
    for (SCCOL nX = nStartCol; nX <= nEndCol; nX++)
    {
        bool bStartOfPage = false;
        tools::Long nThisX = ColHidden(nX) ? 0 : mpColWidth->GetValue(nX);
        bool bManualBreak = HasColManualBreak(nX);
        if ((nSizeX + nThisX > nPageSizeX) || (bManualBreak && !bSkipColBreaks))
        {
            SetColBreak(nX, truefalse);
            nSizeX = 0;
            bStartOfPage = true;
        }
        else if (nX != nStartCol)
            RemoveColBreak(nX, truefalse);
        else
            bStartOfPage = true;

        if (bStartOfPage && bRepeatCol && nX > nRepeatStartX && !bColFound)
        {
            // subtract size of repeat columns from page size
            for (SCCOL i = nRepeatStartX; i <= nRepeatEndX; i++)
                nPageSizeX -= ColHidden(i) ? 0 : mpColWidth->GetValue(i);
            while (nX <= nRepeatEndX)
                RemoveColBreak(++nX, truefalse);
            bColFound = true;
        }

        nSizeX += nThisX;
    }

    // Remove all page breaks in range.
    RemoveRowPageBreaks(nStartRow + 1, nEndRow);

    // And set new page breaks.
    bool bRepeatRow = (nRepeatStartY != SCROW_REPEAT_NONE);
    bool bRowFound = false;
    tools::Long nSizeY = 0;
    ScFlatBoolRowSegments::ForwardIterator aIterHidden(*mpHiddenRows);
    ScFlatUInt16RowSegments::ForwardIterator aIterHeights(*mpRowHeights);
    SCROW nNextManualBreak = GetNextManualBreak(nStartRow); // -1 => no more manual breaks
    for (SCROW nY = nStartRow; nY <= nEndRow; ++nY)
    {
        bool bStartOfPage = false;
        bool bThisRowHidden = false;
        const bool bHasValue = aIterHidden.getValue(nY, bThisRowHidden);
        assert(bHasValue);
        (void)bHasValue;
        tools::Long nThisY = 0;
        if (!bThisRowHidden)
        {
            sal_uInt16 nTmp;
            const bool bHasHeight = aIterHeights.getValue(nY, nTmp);
            assert(bHasHeight);
            if (bHasHeight)
                nThisY = static_cast<tools::Long>(nTmp);
        }

        bool bManualBreak = false;
        if (nNextManualBreak >= 0)
        {
            bManualBreak = (nY == nNextManualBreak);
            if (nY >= nNextManualBreak)
                // Query the next manual break position.
                nNextManualBreak = GetNextManualBreak(nY + 1);
        }

        if ((nSizeY + nThisY > nPageSizeY) || (bManualBreak && !bSkipRowBreaks))
        {
            SetRowBreak(nY, truefalse);
            nSizeY = 0;
            bStartOfPage = true;
        }
        else if (nY != nStartRow)
            ; // page break already removed
        else
            bStartOfPage = true;

        if (bStartOfPage && bRepeatRow && nY > nRepeatStartY && !bRowFound)
        {
            // subtract size of repeat rows from page size
            tools::Long nHeights = GetTotalRowHeight(nRepeatStartY, nRepeatEndY);
#if OSL_DEBUG_LEVEL > 0
            if (nHeights == ::std::numeric_limits<tools::Long>::max())
                OSL_FAIL("ScTable::UpdatePageBreaks: row heights overflow");
#endif
            nPageSizeY -= nHeights;
            if (nY <= nRepeatEndY)
                RemoveRowPageBreaks(nY, nRepeatEndY);
            bRowFound = true;
        }

        if (bThisRowHidden)
        {
            // Hidden row range.  Skip them unless there is a manual break.
            SCROW nLastCommon = aIterHidden.getLastPos();
            if (nNextManualBreak >= 0)
                nLastCommon = ::std::min(nLastCommon, nNextManualBreak - 1);
            nY = nLastCommon;
        }
        else
        {
            // Visible row range.

            SCROW nLastHidden = aIterHidden.getLastPos();
            SCROW nLastHeight = aIterHeights.getLastPos();
            SCROW nLastCommon = ::std::min(nLastHidden, nLastHeight);
            if (nNextManualBreak >= 0)
                nLastCommon = ::std::min(nLastCommon, nNextManualBreak - 1);

            if (nLastCommon > nY)
            {
                tools::Long nMaxMultiple = static_cast<tools::Long>(nLastCommon - nY);
                tools::Long nMultiple = (nPageSizeY - nSizeY) / nThisY;
                if (nMultiple > nMaxMultiple)
                    nMultiple = nMaxMultiple;
                if (nMultiple > 1)
                {
                    nSizeY += nThisY * (nMultiple - 1);
                    nY += nMultiple - 1;
                }
            }
        }

        nSizeY += nThisY;
    }

    //  End: Remove Break

    if (nEndCol < rDocument.MaxCol())
    {
        SetColBreak(nEndCol + 1, truefalse); // AREABREAK
        for (SCCOL nCol : GetColumnsRange(nEndCol + 2, rDocument.MaxCol()))
            RemoveColBreak(nCol, truefalse);
    }
    if (nEndRow < rDocument.MaxRow())
    {
        SetRowBreak(nEndRow + 1, truefalse); // AREABREAK
        if (nEndRow + 2 <= rDocument.MaxRow())
            RemoveRowPageBreaks(nEndRow + 2, rDocument.MaxRow());
    }
    mbPageBreaksValid
        = !pUserArea; // #i116881# the valid flag can only apply to the "no user area" case
}

void ScTable::RemoveManualBreaks()
{
    maRowManualBreaks.clear();
    maColManualBreaks.clear();
    InvalidatePageBreaks();

    SetStreamValid(false);
}

bool ScTable::HasManualBreaks() const
{
    return !maRowManualBreaks.empty() || !maColManualBreaks.empty();
}

void ScTable::SetRowManualBreaks(::std::set<SCROW>&& rBreaks)
{
    maRowManualBreaks = std::move(rBreaks);
    InvalidatePageBreaks();
    SetStreamValid(false);
}

void ScTable::SetColManualBreaks(::std::set<SCCOL>&& rBreaks)
{
    maColManualBreaks = std::move(rBreaks);
    InvalidatePageBreaks();
    SetStreamValid(false);
}

void ScTable::GetAllRowBreaks(set<SCROW>& rBreaks, bool bPage, bool bManual) const
{
    if (bPage)
        rBreaks = maRowPageBreaks;

    if (bManual)
    {
        copy(maRowManualBreaks.begin(), maRowManualBreaks.end(),
             inserter(rBreaks, rBreaks.begin()));
    }
}

void ScTable::GetAllColBreaks(set<SCCOL>& rBreaks, bool bPage, bool bManual) const
{
    if (bPage)
        rBreaks = maColPageBreaks;

    if (bManual)
    {
        copy(maColManualBreaks.begin(), maColManualBreaks.end(),
             inserter(rBreaks, rBreaks.begin()));
    }
}

bool ScTable::HasRowPageBreak(SCROW nRow) const
{
    if (!ValidRow(nRow))
        return false;

    return maRowPageBreaks.find(nRow) != maRowPageBreaks.end();
}

bool ScTable::HasColPageBreak(SCCOL nCol) const
{
    if (!ValidCol(nCol))
        return false;

    return maColPageBreaks.find(nCol) != maColPageBreaks.end();
}

bool ScTable::HasRowManualBreak(SCROW nRow) const
{
    if (!ValidRow(nRow))
        return false;

    return maRowManualBreaks.find(nRow) != maRowManualBreaks.end();
}

bool ScTable::HasColManualBreak(SCCOL nCol) const
{
    if (!ValidCol(nCol))
        return false;

    return maColManualBreaks.find(nCol) != maColManualBreaks.end();
}

SCROW ScTable::GetNextManualBreak(SCROW nRow) const
{
    set<SCROW>::const_iterator itr = maRowManualBreaks.lower_bound(nRow);
    return itr == maRowManualBreaks.end() ? -1 : *itr;
}

void ScTable::RemoveRowPageBreaks(SCROW nStartRow, SCROW nEndRow)
{
    if (!ValidRow(nStartRow) || !ValidRow(nEndRow))
        return;

    set<SCROW>::iterator low = maRowPageBreaks.lower_bound(nStartRow);
    set<SCROW>::iterator high = maRowPageBreaks.upper_bound(nEndRow);
    maRowPageBreaks.erase(low, high);
}

void ScTable::RemoveRowBreak(SCROW nRow, bool bPage, bool bManual)
{
    if (!ValidRow(nRow))
        return;

    if (bPage)
        maRowPageBreaks.erase(nRow);

    if (bManual)
    {
        maRowManualBreaks.erase(nRow);
        InvalidatePageBreaks();
    }
}

void ScTable::RemoveColBreak(SCCOL nCol, bool bPage, bool bManual)
{
    if (!ValidCol(nCol))
        return;

    if (bPage)
        maColPageBreaks.erase(nCol);

    if (bManual)
    {
        maColManualBreaks.erase(nCol);
        InvalidatePageBreaks();
    }
}

void ScTable::SetRowBreak(SCROW nRow, bool bPage, bool bManual)
{
    if (!ValidRow(nRow))
        return;

    if (bPage)
        maRowPageBreaks.insert(nRow);

    if (bManual)
    {
        maRowManualBreaks.insert(nRow);
        InvalidatePageBreaks();
    }
}

void ScTable::SetColBreak(SCCOL nCol, bool bPage, bool bManual)
{
    if (!ValidCol(nCol))
        return;

    if (bPage)
        maColPageBreaks.insert(nCol);

    if (bManual)
    {
        maColManualBreaks.insert(nCol);
        InvalidatePageBreaks();
    }
}

Sequence<TablePageBreakData> ScTable::GetRowBreakData() const
{
    using ::std::inserter;

    set<SCROW> aRowBreaks = maRowPageBreaks;
    copy(maRowManualBreaks.begin(), maRowManualBreaks.end(),
         inserter(aRowBreaks, aRowBreaks.begin()));

    Sequence<TablePageBreakData> aSeq(aRowBreaks.size());
    std::transform(aRowBreaks.begin(), aRowBreaks.end(), aSeq.getArray(), [this](const SCROW nRow) {
        return TablePageBreakData(nRow, HasRowManualBreak(nRow));
    });

    return aSeq;
}

bool ScTable::RowHidden(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
{
    if (!ValidRow(nRow))
    {
        if (pFirstRow)
            *pFirstRow = nRow;
        if (pLastRow)
            *pLastRow = nRow;
        return true;
    }

    ScFlatBoolRowSegments::RangeData aData;
    if (!mpHiddenRows->getRangeData(nRow, aData))
    {
        // search failed.
        if (pFirstRow)
            *pFirstRow = nRow;
        if (pLastRow)
            *pLastRow = nRow;
        return true;
    }

    if (pFirstRow)
        *pFirstRow = aData.mnRow1;
    if (pLastRow)
        *pLastRow = aData.mnRow2;

    return aData.mbValue;
}

bool ScTable::RowHiddenLeaf(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
{
    if (!ValidRow(nRow))
    {
        if (pFirstRow)
            *pFirstRow = nRow;
        if (pLastRow)
            *pLastRow = nRow;
        return true;
    }

    ScFlatBoolRowSegments::RangeData aData;
    if (!mpHiddenRows->getRangeDataLeaf(nRow, aData))
    {
        // search failed.
        if (pFirstRow)
            *pFirstRow = nRow;
        if (pLastRow)
            *pLastRow = nRow;
        return true;
    }

    if (pFirstRow)
        *pFirstRow = aData.mnRow1;
    if (pLastRow)
        *pLastRow = aData.mnRow2;

    return aData.mbValue;
}

bool ScTable::HasHiddenRows(SCROW nStartRow, SCROW nEndRow) const
{
    SCROW nRow = nStartRow;
    while (nRow <= nEndRow)
    {
        SCROW nLastRow = -1;
        bool bHidden = RowHidden(nRow, nullptr, &nLastRow);
        if (bHidden)
            return true;

        nRow = nLastRow + 1;
    }
    return false;
}

bool ScTable::ColHidden(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const
{
    if (!ValidCol(nCol))
        return true;

    ScFlatBoolColSegments::RangeData aData;
    if (!mpHiddenCols->getRangeData(nCol, aData))
        return true;

    if (pFirstCol)
        *pFirstCol = aData.mnCol1;
    if (pLastCol)
        *pLastCol = aData.mnCol2;

    return aData.mbValue;
}

bool ScTable::SetRowHidden(SCROW nStartRow, SCROW nEndRow, bool bHidden)
{
    bool bChanged = false;
    if (bHidden)
        bChanged = mpHiddenRows->setTrue(nStartRow, nEndRow);
    else
        bChanged = mpHiddenRows->setFalse(nStartRow, nEndRow);

    // Cell anchored objects might change visibility
    ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
    if (pDrawLayer)
    {
        std::vector<SdrObject*> aRowDrawObjects;
        aRowDrawObjects = pDrawLayer->GetObjectsAnchoredToRows(GetTab(), nStartRow, nEndRow);
        for (auto aObj : aRowDrawObjects)
        {
            ScDrawObjData* pData = ScDrawLayer::GetObjData(aObj);
            if (pData)
            {
                if (bHidden)
                    aObj->SetVisible(false);
                else if (!GetDoc().ColHidden(pData->maStart.Col(), pData->maStart.Tab()))
                {
                    // Only change visibility if object is not hidden by a hidden col
                    aObj->SetVisible(true);
                }
            }
        }
    }

    if (bChanged)
    {
        SetStreamValid(false);

        { // Scoped bulk broadcast.
            // Only subtotal formula cells will accept the notification of
            // SfxHintId::ScHiddenRowsChanged, leaving the bulk will track
            // those and broadcast SfxHintId::ScDataChanged to notify all
            // dependents.
            ScBulkBroadcast aBulkBroadcast(rDocument.GetBASM(), SfxHintId::ScDataChanged);
            for (SCCOL i = 0; i < aCol.size(); i++)
            {
                aCol[i].BroadcastRows(nStartRow, nEndRow, SfxHintId::ScHiddenRowsChanged);
            }
        }
    }

    return bChanged;
}

void ScTable::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, bool bHidden)
{
    bool bChanged = false;
    if (bHidden)
        bChanged = mpHiddenCols->setTrue(nStartCol, nEndCol);
    else
        bChanged = mpHiddenCols->setFalse(nStartCol, nEndCol);

    // Cell anchored objects might change visibility
    ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
    if (pDrawLayer)
    {
        std::vector<SdrObject*> aColDrawObjects;
        aColDrawObjects = pDrawLayer->GetObjectsAnchoredToCols(GetTab(), nStartCol, nEndCol);
        for (auto aObj : aColDrawObjects)
        {
            ScDrawObjData* pData = ScDrawLayer::GetObjData(aObj);
            if (pData)
            {
                if (bHidden)
                    aObj->SetVisible(false);
                else if (!GetDoc().RowHidden(pData->maStart.Row(), pData->maStart.Tab()))
                {
                    // Only change visibility if object is not hidden by a hidden row
                    aObj->SetVisible(true);
                }
            }
        }
    }

    if (bChanged)
        SetStreamValid(false);
}

void ScTable::CopyColHidden(const ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol)
{
    SCCOL nCol = nStartCol;
    while (nCol <= nEndCol)
    {
        SCCOL nLastCol = -1;
        bool bHidden = rTable.ColHidden(nCol, nullptr, &nLastCol);
        if (nLastCol > nEndCol)
            nLastCol = nEndCol;

        SetColHidden(nCol, nLastCol, bHidden);
        nCol = nLastCol + 1;
    }
}

void ScTable::CopyRowHidden(const ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
{
    SCROW nRow = nStartRow;
    while (nRow <= nEndRow)
    {
        SCROW nLastRow = -1;
        bool bHidden = rTable.RowHidden(nRow, nullptr, &nLastRow);
        if (nLastRow > nEndRow)
            nLastRow = nEndRow;
        SetRowHidden(nRow, nLastRow, bHidden);
        nRow = nLastRow + 1;
    }
}

void ScTable::CopyRowHeight(const ScTable& rSrcTable, SCROW nStartRow, SCROW nEndRow,
                            SCROW nSrcOffset)
{
    SCROW nRow = nStartRow;
    ScFlatUInt16RowSegments::RangeData aSrcData;
    while (nRow <= nEndRow)
    {
        if (!rSrcTable.mpRowHeights->getRangeData(nRow + nSrcOffset, aSrcData))
            // Something is wrong !
            return;

        SCROW nLastRow = aSrcData.mnRow2 - nSrcOffset;
        if (nLastRow > nEndRow)
            nLastRow = nEndRow;

        mpRowHeights->setValue(nRow, nLastRow, aSrcData.mnValue);
        nRow = nLastRow + 1;
    }
}

SCROW ScTable::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow) const
{
    SCROW nRow = nStartRow;
    ScFlatBoolRowSegments::RangeData aData;
    while (nRow <= nEndRow)
    {
        if (!ValidRow(nRow))
            break;

        if (!mpHiddenRows->getRangeData(nRow, aData))
            // failed to get range data.
            break;

        if (!aData.mbValue)
            // visible row found
            return nRow;

        nRow = aData.mnRow2 + 1;
    }

    return ::std::numeric_limits<SCROW>::max();
}

SCROW ScTable::LastVisibleRow(SCROW nStartRow, SCROW nEndRow) const
{
    SCROW nRow = nEndRow;
    ScFlatBoolRowSegments::RangeData aData;
    while (nRow >= nStartRow)
    {
        if (!ValidRow(nRow))
            break;

        if (!mpHiddenRows->getRangeData(nRow, aData))
            // failed to get range data.
            break;

        if (!aData.mbValue)
            // visible row found
            return nRow;

        nRow = aData.mnRow1 - 1;
    }

    return ::std::numeric_limits<SCROW>::max();
}

SCROW ScTable::CountVisibleRows(SCROW nStartRow, SCROW nEndRow) const
{
    SCROW nCount = 0;
    SCROW nRow = nStartRow;
    ScFlatBoolRowSegments::RangeData aData;
    while (nRow <= nEndRow)
    {
        if (!mpHiddenRows->getRangeData(nRow, aData))
            break;

        if (aData.mnRow2 > nEndRow)
            aData.mnRow2 = nEndRow;

        if (!aData.mbValue)
            nCount += aData.mnRow2 - nRow + 1;

        nRow = aData.mnRow2 + 1;
    }
    return nCount;
}

tools::Long ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZero) const
{
    tools::Long nHeight = 0;
    SCROW nRow = nStartRow;
    ScFlatBoolRowSegments::RangeData aData;
    while (nRow <= nEndRow)
    {
        if (!mpHiddenRows->getRangeData(nRow, aData))
            break;

        if (aData.mnRow2 > nEndRow)
            aData.mnRow2 = nEndRow;

        if (!(bHiddenAsZero && aData.mbValue))
            // visible row range.
            nHeight += mpRowHeights->getSumValue(nRow, aData.mnRow2);

        nRow = aData.mnRow2 + 1;
    }

    return nHeight;
}

SCCOL ScTable::CountVisibleCols(SCCOL nStartCol, SCCOL nEndCol) const
{
    assert(nStartCol <= nEndCol);
    SCCOL nCount = 0;
    SCCOL nCol = nStartCol;
    ScFlatBoolColSegments::RangeData aData;
    while (nCol <= nEndCol)
    {
        if (!mpHiddenCols->getRangeData(nCol, aData))
            break;

        if (aData.mnCol2 > nEndCol)
            aData.mnCol2 = nEndCol;

        if (!aData.mbValue)
            nCount += aData.mnCol2 - nCol + 1;

        nCol = aData.mnCol2 + 1;
    }
    return nCount;
}

SCCOLROW ScTable::LastHiddenColRow(SCCOLROW nPos, bool bCol) const
{
    if (bCol)
    {
        SCCOL nCol = static_cast<SCCOL>(nPos);
        if (ColHidden(nCol))
        {
            for (SCCOL i = nCol + 1; i <= rDocument.MaxCol(); ++i)
            {
                if (!ColHidden(i))
                    return i - 1;
            }
        }
    }
    else
    {
        SCROW nRow = static_cast<SCROW>(nPos);
        SCROW nLastRow;
        if (RowHidden(nRow, nullptr, &nLastRow))
            return static_cast<SCCOLROW>(nLastRow);
    }
    return ::std::numeric_limits<SCCOLROW>::max();
}

bool ScTable::RowFiltered(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
{
    if (!ValidRow(nRow))
        return false;

    ScFlatBoolRowSegments::RangeData aData;
    if (!mpFilteredRows->getRangeData(nRow, aData))
        // search failed.
        return false;

    if (pFirstRow)
        *pFirstRow = aData.mnRow1;
    if (pLastRow)
        *pLastRow = aData.mnRow2;

    return aData.mbValue;
}

bool ScTable::ColFiltered(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const
{
    if (!ValidCol(nCol))
        return false;

    ScFlatBoolColSegments::RangeData aData;
    if (!mpFilteredCols->getRangeData(nCol, aData))
        // search failed.
        return false;

    if (pFirstCol)
        *pFirstCol = aData.mnCol1;
    if (pLastCol)
        *pLastCol = aData.mnCol2;

    return aData.mbValue;
}

bool ScTable::HasFilteredRows(SCROW nStartRow, SCROW nEndRow) const
{
    SCROW nRow = nStartRow;
    while (nRow <= nEndRow)
    {
        SCROW nLastRow = nRow;
        bool bFiltered = RowFiltered(nRow, nullptr, &nLastRow);
        if (bFiltered)
            return true;

        nRow = nLastRow + 1;
    }
    return false;
}

void ScTable::CopyColFiltered(const ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol)
{
    SCCOL nCol = nStartCol;
    while (nCol <= nEndCol)
    {
        SCCOL nLastCol = -1;
        bool bFiltered = rTable.ColFiltered(nCol, nullptr, &nLastCol);
        if (nLastCol > nEndCol)
            nLastCol = nEndCol;

        SetColFiltered(nCol, nLastCol, bFiltered);
        nCol = nLastCol + 1;
    }
}

void ScTable::CopyRowFiltered(const ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
{
    SCROW nRow = nStartRow;
    while (nRow <= nEndRow)
    {
        SCROW nLastRow = -1;
        bool bFiltered = rTable.RowFiltered(nRow, nullptr, &nLastRow);
        if (nLastRow > nEndRow)
            nLastRow = nEndRow;
        SetRowFiltered(nRow, nLastRow, bFiltered);
        nRow = nLastRow + 1;
    }
}

void ScTable::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, bool bFiltered)
{
    if (bFiltered)
        mpFilteredRows->setTrue(nStartRow, nEndRow);
    else
        mpFilteredRows->setFalse(nStartRow, nEndRow);
}

void ScTable::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, bool bFiltered)
{
    if (bFiltered)
        mpFilteredCols->setTrue(nStartCol, nEndCol);
    else
        mpFilteredCols->setFalse(nStartCol, nEndCol);
}

SCROW ScTable::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const
{
    SCROW nRow = nStartRow;
    ScFlatBoolRowSegments::RangeData aData;
    while (nRow <= nEndRow)
    {
        if (!ValidRow(nRow))
            break;

        if (!mpFilteredRows->getRangeData(nRow, aData))
            // failed to get range data.
            break;

        if (!aData.mbValue)
            // non-filtered row found
            return nRow;

        nRow = aData.mnRow2 + 1;
    }

    return ::std::numeric_limits<SCROW>::max();
}

SCROW ScTable::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const
{
    SCROW nRow = nEndRow;
    ScFlatBoolRowSegments::RangeData aData;
    while (nRow >= nStartRow)
    {
        if (!ValidRow(nRow))
            break;

        if (!mpFilteredRows->getRangeData(nRow, aData))
            // failed to get range data.
            break;

        if (!aData.mbValue)
            // non-filtered row found
            return nRow;

        nRow = aData.mnRow1 - 1;
    }

    return ::std::numeric_limits<SCROW>::max();
}

SCROW ScTable::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow) const
{
    SCROW nCount = 0;
    SCROW nRow = nStartRow;
    ScFlatBoolRowSegments::RangeData aData;
    while (nRow <= nEndRow)
    {
        if (!mpFilteredRows->getRangeData(nRow, aData))
            break;

        if (aData.mnRow2 > nEndRow)
            aData.mnRow2 = nEndRow;

        if (!aData.mbValue)
            nCount += aData.mnRow2 - nRow + 1;

        nRow = aData.mnRow2 + 1;
    }
    return nCount;
}

Color ScTable::GetCellBackgroundColor(ScAddress aPos) const
{
    Color backgroundColor;
    bool bHasConditionalBackgroundColor = false;
    // Check background color from cond. formatting
    const ScPatternAttr* pPattern = GetDoc().GetPattern(aPos.Col(), aPos.Row(), aPos.Tab());
    if (pPattern)
    {
        if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
        {
            const SfxItemSet* pCondSet = GetDoc().GetCondResult(aPos.Col(), aPos.Row(), aPos.Tab());
            const SvxBrushItem* pBackgroundColor = &pPattern->GetItem(ATTR_BACKGROUND, pCondSet);
            backgroundColor = pBackgroundColor->GetColor();
            bHasConditionalBackgroundColor = true;
        }
    }

    // Color scale needs a different handling
    ScConditionalFormat* pCondFormat = GetDoc().GetCondFormat(aPos.Col(), aPos.Row(), aPos.Tab());
    if (pCondFormat)
    {
        for (size_t i = 0; i < pCondFormat->size(); i++)
        {
            auto aEntry = pCondFormat->GetEntry(i);
            if (aEntry->GetType() == ScFormatEntry::Type::Colorscale)
            {
                const ScColorScaleFormat* pColFormat
                    = static_cast<const ScColorScaleFormat*>(aEntry);
                std::optional<Color> oColor = pColFormat->GetColor(aPos);
                if (oColor)
                {
                    backgroundColor = oColor.value();
                    bHasConditionalBackgroundColor = true;
                }
            }
        }
    }
    return bHasConditionalBackgroundColor ? backgroundColor
                                          : GetDoc().GetAttr(aPos, ATTR_BACKGROUND)->GetColor();
}

Color ScTable::GetCellTextColor(ScAddress aPos) const
{
    // Check text & background color from cond. formatting
    const ScPatternAttr* pPattern = GetDoc().GetPattern(aPos.Col(), aPos.Row(), aPos.Tab());
    if (pPattern)
    {
        if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
        {
            const SfxItemSet* pCondSet = GetDoc().GetCondResult(aPos.Col(), aPos.Row(), aPos.Tab());
            const SvxColorItem* pColor = &pPattern->GetItem(ATTR_FONT_COLOR, pCondSet);
            return pColor->GetValue();
        }

        if (pPattern->GetItem(ATTR_VALUE_FORMAT).GetValue())
        {
            const SfxUInt32Item pItem = pPattern->GetItem(ATTR_VALUE_FORMAT);
            auto& rDoc = const_cast<ScDocument&>(GetDoc());
            const Color* pColor;
            ScRefCellValue aCell(rDoc, aPos);
            ScCellFormat::GetString(rDoc, aPos, pItem.GetValue(), &pColor, nullptr, falsefalse);
            if (pColor)
                return *pColor;
        }
    }

    const SvxColorItem* pColor = GetDoc().GetAttr(aPos, ATTR_FONT_COLOR);
    return pColor->GetValue();
}

bool ScTable::IsManualRowHeight(SCROW nRow) const
{
    return bool(pRowFlags->GetValue(nRow) & CRFlags::ManualSize);
}

namespace
{
void lcl_syncFlags(const ScDocument* pDocument, ScFlatBoolColSegments& rColSegments,
                   const ScFlatBoolRowSegments& rRowSegments,
                   ScBitMaskCompressedArray<SCCOL, CRFlags>* pColFlags,
                   ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlags, const CRFlags nFlagMask)
{
    CRFlags nFlagMaskComplement = ~nFlagMask;

    pRowFlags->AndValue(0, pDocument->MaxRow(), nFlagMaskComplement);
    pColFlags->AndValue(0, pDocument->MaxCol() + 1, nFlagMaskComplement);

    {
        // row hidden flags.

        SCROW nRow = 0;
        ScFlatBoolRowSegments::RangeData aData;
        while (nRow <= pDocument->MaxRow())
        {
            if (!rRowSegments.getRangeData(nRow, aData))
                break;

            if (aData.mbValue)
                pRowFlags->OrValue(nRow, aData.mnRow2, nFlagMask);

            nRow = aData.mnRow2 + 1;
        }
    }

    {
        // column hidden flags.

        SCCOL nCol = 0;
        ScFlatBoolColSegments::RangeData aData;
        while (nCol <= pDocument->MaxCol())
        {
            if (!rColSegments.getRangeData(nCol, aData))
                break;

            if (aData.mbValue)
                pColFlags->OrValue(nCol, aData.mnCol2, nFlagMask);

            nCol = aData.mnCol2 + 1;
        }
    }
}
}

void ScTable::SyncColRowFlags()
{
    CRFlags nManualBreakComplement = ~CRFlags::ManualBreak;

    // Manual breaks.
    pRowFlags->AndValue(0, rDocument.MaxRow(), nManualBreakComplement);
    mpColFlags->AndValue(0, rDocument.MaxCol() + 1, nManualBreakComplement);

    for (const auto& rBreakPos : maRowManualBreaks)
        pRowFlags->OrValue(rBreakPos, CRFlags::ManualBreak);

    for (const auto& rBreakPos : maColManualBreaks)
        mpColFlags->OrValue(rBreakPos, CRFlags::ManualBreak);

    // Hidden flags.
    lcl_syncFlags(&rDocument, *mpHiddenCols, *mpHiddenRows, mpColFlags.get(), pRowFlags.get(),
                  CRFlags::Hidden);
    lcl_syncFlags(&rDocument, *mpFilteredCols, *mpFilteredRows, mpColFlags.get(), pRowFlags.get(),
                  CRFlags::Filtered);
}

void ScTable::SetPageSize(const Size& rSize)
{
    if (!rSize.IsEmpty())
    {
        if (aPageSizeTwips != rSize)
            InvalidatePageBreaks();

        bPageSizeValid = true;
        aPageSizeTwips = rSize;
    }
    else
        bPageSizeValid = false;
}

bool ScTable::IsProtected() const { return pTabProtection && pTabProtection->isProtected(); }

void ScTable::SetProtection(const ScTableProtection* pProtect)
{
    if (pProtect)
        pTabProtection.reset(new ScTableProtection(*pProtect));
    else
        pTabProtection.reset();

    SetStreamValid(false);
}

const ScTableProtection* ScTable::GetProtection() const { return pTabProtection.get(); }

Size ScTable::GetPageSize() const
{
    if (bPageSizeValid)
        return aPageSizeTwips;
    else
        return Size(); // blank
}

void ScTable::SetRepeatArea(SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow)
{
    // #i117952# page break calculation uses these values (set from ScPrintFunc), not pRepeatColRange/pRepeatRowRange
    if (nStartCol != nRepeatStartX || nEndCol != nRepeatEndX || nStartRow != nRepeatStartY
        || nEndRow != nRepeatEndY)
        InvalidatePageBreaks();

    nRepeatStartX = nStartCol;
    nRepeatEndX = nEndCol;
    nRepeatStartY = nStartRow;
    nRepeatEndY = nEndRow;
}

void ScTable::StartListening(const ScAddress& rAddress, SvtListener* pListener)
{
    if (!ValidCol(rAddress.Col()))
        return;

    CreateColumnIfNotExists(rAddress.Col()).StartListening(*pListener, rAddress.Row());
}

void ScTable::EndListening(const ScAddress& rAddress, SvtListener* pListener)
{
    if (!ValidCol(rAddress.Col()))
        return;

    if (rAddress.Col() < aCol.size())
        aCol[rAddress.Col()].EndListening(*pListener, rAddress.Row());
}

void ScTable::StartListening(sc::StartListeningContext& rCxt, const ScAddress&&nbsp;rAddress,
                             SvtListener& rListener)
{
    if (!ValidCol(rAddress.Col()))
        return;

    CreateColumnIfNotExists(rAddress.Col()).StartListening(rCxt, rAddress, rListener);
}

void ScTable::EndListening(sc::EndListeningContext& rCxt, const ScAddress& rAddress,
                           SvtListener& rListener)
{
    if (!ValidCol(rAddress.Col()))
        return;

    if (rAddress.Col() < aCol.size())
        aCol[rAddress.Col()].EndListening(rCxt, rAddress, rListener);
}

void ScTable::SetPageStyle(const OUString& rName)
{
    if (aPageStyle == rName)
        return;

    OUString aStrNew = rName;
    SfxStyleSheetBasePool* pStylePool = rDocument.GetStyleSheetPool();
    SfxStyleSheetBase* pNewStyle = pStylePool->Find(aStrNew, SfxStyleFamily::Page);

    if (!pNewStyle)
    {
        aStrNew = ScResId(STR_STYLENAME_STANDARD);
        pNewStyle = pStylePool->Find(aStrNew, SfxStyleFamily::Page);
    }

    if (aPageStyle == aStrNew)
        return;

    SfxStyleSheetBase* pOldStyle = pStylePool->Find(aPageStyle, SfxStyleFamily::Page);
    if (pOldStyle && pNewStyle)
    {
        SfxItemSet& rOldSet = pOldStyle->GetItemSet();
        SfxItemSet& rNewSet = pNewStyle->GetItemSet();
        auto getScaleValue = [](const SfxItemSet& rSet, sal_uInt16 nId) {
            return static_cast<const SfxUInt16Item&>(rSet.Get(nId)).GetValue();
        };

        const sal_uInt16 nOldScale = getScaleValue(rOldSet, ATTR_PAGE_SCALE);
        const sal_uInt16 nOldScaleToPages = getScaleValue(rOldSet, ATTR_PAGE_SCALETOPAGES);
        const sal_uInt16 nNewScale = getScaleValue(rNewSet, ATTR_PAGE_SCALE);
        const sal_uInt16 nNewScaleToPages = getScaleValue(rNewSet, ATTR_PAGE_SCALETOPAGES);

        if ((nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages))
            InvalidateTextWidth(nullptr, nullptr, falsefalse);
    }

    if (pNewStyle) // also without the old one (for UpdateStdNames)
        aPageStyle = aStrNew;

    SetStreamValid(false);
}

void ScTable::PageStyleModified(const OUString& rNewName)
{
    aPageStyle = rNewName;
    InvalidateTextWidth(nullptr, nullptr, falsefalse); // don't know what was in the style before
}

void ScTable::InvalidateTextWidth(const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
                                  bool bNumFormatChanged, bool bBroadcast)
{
    if (pAdrFrom && !pAdrTo)
    {
        // Special case: only process the "from" cell.
        SCCOL nCol = pAdrFrom->Col();
        SCROW nRow = pAdrFrom->Row();
        if (nCol >= aCol.size())
            return;
        ScColumn& rCol = aCol[nCol];
        ScRefCellValue aCell = rCol.GetCellValue(nRow);
        if (aCell.isEmpty())
            return;

        rCol.SetTextWidth(nRow, TEXTWIDTH_DIRTY);

        if (bNumFormatChanged)
            rCol.SetScriptType(nRow, SvtScriptType::UNKNOWN);

        if (bBroadcast)
        { // Only with CalcAsShown
            switch (aCell.getType())
            {
                case CELLTYPE_VALUE:
                    rCol.Broadcast(nRow);
                    break;
                case CELLTYPE_FORMULA:
                    aCell.getFormula()->SetDirty();
                    break;
                default:
                {
                    // added to avoid warnings
                }
            }
        }

        return;
    }

    const SCCOL nCol1 = pAdrFrom ? pAdrFrom->Col() : 0;
    const SCROW nRow1 = pAdrFrom ? pAdrFrom->Row() : 0;
    const SCCOL nCol2 = pAdrTo ? pAdrTo->Col() : aCol.size() - 1;
    const SCROW nRow2 = pAdrTo ? pAdrTo->Row() : rDocument.MaxRow();

    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
    {
        ScColumnTextWidthIterator aIter(GetDoc(), aCol[nCol], nRow1, nRow2);
        sc::ColumnBlockPosition blockPos; // cache mdds position
        InitColumnBlockPosition(blockPos, nCol);

        for (; aIter.hasCell(); aIter.next())
        {
            SCROW nRow = aIter.getPos();
            aIter.setValue(TEXTWIDTH_DIRTY);
            ScRefCellValue aCell = aCol[nCol].GetCellValue(blockPos, nRow);
            if (aCell.isEmpty())
                continue;

            if (bNumFormatChanged)
                aCol[nCol].SetScriptType(nRow, SvtScriptType::UNKNOWN);

            if (bBroadcast)
            { // Only with CalcAsShown
                switch (aCell.getType())
                {
                    case CELLTYPE_VALUE:
                        aCol[nCol].Broadcast(nRow);
                        break;
                    case CELLTYPE_FORMULA:
                        aCell.getFormula()->SetDirty();
                        break;
                    default:
                    {
                        // added to avoid warnings
                    }
                }
            }
        }
    }
}

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

Messung V0.5
C=86 H=97 G=91

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© 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.