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 15 kB image not shown  

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


#include <pivot/PivotTableFormatOutput.hxx>
#include <pivot/DPOutLevelData.hxx>

#include <dpoutput.hxx>
#include <dpobject.hxx>
#include <dptabdat.hxx>
#include <dpcache.hxx>
#include <document.hxx>

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

namespace sc
{
namespace
{
class NameResolver
{
private:
    ScDPTableData& mrTableData;
    ScDPCache const& mrCache;

    std::unordered_map<sal_Int32, std::vector<OUString>> maNameCache;

    void fillNamesForDimension(std::vector<OUString>& rNames, sal_Int32 nDimension)
    {
        for (const auto& rItemData : mrCache.GetDimMemberValues(nDimension))
        {
            OUString sFormattedName;
            if (rItemData.HasStringData() || rItemData.IsEmpty())
                sFormattedName = rItemData.GetString();
            else
                sFormattedName = ScDPObject::GetFormattedString(&mrTableData, nDimension,
                                                                rItemData.GetValue());
            rNames.push_back(sFormattedName);
        }
    }

public:
    NameResolver(ScDPTableData& rTableData, ScDPCache const& rCache)
        : mrTableData(rTableData)
        , mrCache(rCache)
    {
    }

    OUString getNameForIndex(sal_uInt32 nIndex, sal_Int32 nDimension)
    {
        auto iterator = maNameCache.find(nDimension);
        if (iterator == maNameCache.end())
        {
            std::vector<OUString> aNames;
            fillNamesForDimension(aNames, nDimension);
            iterator = maNameCache.emplace(nDimension, aNames).first;
        }

        const std::vector<OUString>& rNames = iterator->second;
        if (nIndex >= rNames.size())
            return OUString();
        return rNames[nIndex];
    }
};

void initLines(std::vector<LineData>& rLines, std::vector<ScDPOutLevelData> const&&nbsp;rFields)
{
    for (size_t i = 0; i < rFields.size(); i++)
    {
        size_t nFieldLength(rFields[i].maResult.getLength());
        if (rLines.size() < nFieldLength)
            rLines.resize(nFieldLength);

        for (LineData& rLineData : rLines)
        {
            rLineData.maFields.resize(rFields.size());
        }
    }
}

Selection const* findSelection(PivotTableFormat const& rFormat, tools::Long nDimension)
{
    for (Selection const& rSelection : rFormat.getSelections())
    {
        if (rSelection.nField == nDimension)
            return &rSelection;
    }
    return nullptr;
}

void fillOutputFieldFromSelection(FormatOutputField& rOutputField, Selection const& rSelection,
                                  size_t nSelectionIndex, NameResolver& rNameResolver)
{
    if (rSelection.nIndices.empty())
    {
        rOutputField.bMatchesAll = true;
    }
    else
    {
        if (rSelection.nIndices.size() > 1 && rSelection.nIndices.size() > nSelectionIndex)
            rOutputField.nIndex = rSelection.nIndices[nSelectionIndex];
        else
            rOutputField.nIndex = rSelection.nIndices[0];

        if (rOutputField.nDimension == -2)
            rOutputField.aName = "DATA";
        else
            rOutputField.aName
                = rNameResolver.getNameForIndex(rOutputField.nIndex, rOutputField.nDimension);
    }
    rOutputField.bSet = true;
}

void initFormatOutputField(size_t nSelectionIndex, std::vector<FormatOutputField>& ;rOutputFields,
                           std::vector<ScDPOutLevelData> const& rFields,
                           PivotTableFormat const& rFormat, NameResolver& rNameResolver)
{
    rOutputFields.resize(rFields.size());
    for (size_t i = 0; i < rOutputFields.size(); i++)
    {
        FormatOutputField& rOutputField = rOutputFields[i];
        if (!rFields[i].mbDataLayout)
            rOutputField.nDimension = rFields[i].mnDim;

        Selection const* pSelection = findSelection(rFormat, rOutputField.nDimension);
        if (pSelection == nullptr)
            continue;

        fillOutputFieldFromSelection(rOutputField, *pSelection, nSelectionIndex, rNameResolver);
    }
}

// end anonymous namespace

void FormatOutput::prepare(SCTAB nTab, std::vector<ScDPOutLevelData> const& rColumnFields,
                           std::vector<ScDPOutLevelData> const& rRowFields,
                           bool bColumnFieldIsDataOnly)
{
    if (!mpFormats)
        return;

    // initialize row and column lines, so the number of fields matches the pivot table output
    initLines(maRowLines, rRowFields);

    if (rColumnFields.size() == 0 && bColumnFieldIsDataOnly)
    {
        maColumnLines.resize(1);
        maColumnLines[0].maFields.resize(1);
    }
    else
    {
        initLines(maColumnLines, rColumnFields);
    }

    // check the table data exists
    auto* pTableData = mrObject.GetTableData();
    if (!pTableData)
        return;

    ScDPFilteredCache const& rFilteredCache = pTableData->GetCacheTable();
    ScDPCache const& rCache = rFilteredCache.getCache();

    NameResolver aNameResolver(*pTableData, rCache);

    // Initialize format output entries (FormatOutputEntry) and set the data already available from output fields
    // (rColumnFields and rRowFields) and the pivot table format list (PivotTableFormat).

    for (PivotTableFormat const& rFormat : mpFormats->getVector())
    {
        size_t nMaxNumberOfIndices = 1;
        for (auto const& rSelection : rFormat.aSelections)
        {
            if (rSelection.nIndices.size() > 1)
                nMaxNumberOfIndices = rSelection.nIndices.size();
        }

        for (size_t nSelectionIndex = 0; nSelectionIndex < nMaxNumberOfIndices; nSelectionIndex++)
        {
            sc::FormatOutputEntry aEntry;
            aEntry.pPattern = rFormat.pPattern;
            aEntry.onTab = nTab;
            aEntry.eType = rFormat.eType;

            initFormatOutputField(nSelectionIndex, aEntry.aRowOutputFields, rRowFields, rFormat,
                                  aNameResolver);

            // If column fields list is empty, but there is a data field in columns that is not part of column fields
            if (rColumnFields.size() == 0 && bColumnFieldIsDataOnly)
            {
                // Initialize column output fields to have 1 data output field
                aEntry.aColumnOutputFields.resize(1);
                FormatOutputField& rOutputField = aEntry.aColumnOutputFields[0];
                rOutputField.nDimension = -2;
                Selection const* pSelection = findSelection(rFormat, -2);
                if (pSelection)
                    fillOutputFieldFromSelection(rOutputField, *pSelection, nSelectionIndex,
                                                 aNameResolver);
            }
            else
            {
                initFormatOutputField(nSelectionIndex, aEntry.aColumnOutputFields, rColumnFields,
                                      rFormat, aNameResolver);
            }

            maFormatOutputEntries.push_back(aEntry);
        }
    }
}

void FormatOutput::insertEmptyDataColumn(SCCOL nColPos, SCROW nRowPos)
{
    if (!mpFormats)
        return;

    LineData& rLine = maColumnLines[0];
    rLine.oLine = nColPos;
    rLine.oPosition = nRowPos;

    FieldData& rFieldData = rLine.maFields[0];
    rFieldData.nIndex = 0;
    rFieldData.bIsSet = true;
}

namespace
{
void fillLineAndFieldData(std::vector<LineData>& rLineDataVector, size_t nFieldIndex,
                          ScDPOutLevelData const& rField, tools::Long nMemberIndex,
                          sheet::MemberResult const& rMember, SCCOLROW nLine, SCCOLROW nPosition)
{
    LineData& rLine = rLineDataVector[nMemberIndex];
    rLine.oLine = nLine;
    rLine.oPosition = nPosition;

    FieldData& rFieldData = rLine.maFields[nFieldIndex];
    if (!rField.mbDataLayout)
        rFieldData.mnDimension = rField.mnDim;
    rFieldData.aName = rMember.Name;
    rFieldData.nIndex = nMemberIndex;
    rFieldData.bIsSet = true;
    rFieldData.bIsMember = rMember.Flags & sheet::MemberResultFlags::HASMEMBER;
    rFieldData.bSubtotal = rMember.Flags & sheet::MemberResultFlags::SUBTOTAL;
    rFieldData.bContinue = rMember.Flags & sheet::MemberResultFlags::CONTINUE;

    // Search previous entries for the name / value
    if (rFieldData.bContinue)
    {
        tools::Long nCurrent = nMemberIndex - 1;
        while (nCurrent >= 0 && rLineDataVector[nCurrent].maFields[nFieldIndex].bContinue)
            nCurrent--;

        if (nCurrent >= 0)
        {
            FieldData& rCurrentFieldData = rLineDataVector[nCurrent].maFields[nFieldIndex];
            rFieldData.aName = rCurrentFieldData.aName;
            rFieldData.nIndex = rCurrentFieldData.nIndex;
        }
    }
}
// end anonymous namespace

void FormatOutput::insertFieldMember(size_t nFieldIndex, ScDPOutLevelData constrField,
                                     tools::Long nMemberIndex, sheet::MemberResult const& rMember,
                                     SCCOL nColPos, SCROW nRowPos,
                                     sc::FormatResultDirection eResultDirection)
{
    if (!mpFormats)
        return;

    if (eResultDirection == sc::FormatResultDirection::ROW)
        fillLineAndFieldData(maRowLines, nFieldIndex, rField, nMemberIndex, rMember, nRowPos,
                             nColPos);
    else if (eResultDirection == sc::FormatResultDirection::COLUMN)
        fillLineAndFieldData(maColumnLines, nFieldIndex, rField, nMemberIndex, rMember, nColPos,
                             nRowPos);
}
namespace
{
void checkForMatchingLines(std::vector<LineData> const& rLines,
                           std::vector<FormatOutputField> const& rFormatOutputField,
                           FormatType eType,
                           std::vector<std::reference_wrapper<const LineData>>& rMatches,
                           std::vector<std::reference_wrapper<const LineData>>& rMaybeMatches)
{
    for (LineData const& rLineData : rLines)
    {
        size_t nMatch = 0;
        size_t nMaybeMatch = 0;
        size_t nNoOfFields = rLineData.maFields.size();

        for (size_t nIndex = 0; nIndex < nNoOfFields; nIndex++)
        {
            FieldData const& rFieldData = rLineData.maFields[nIndex];
            FormatOutputField const& rFormatEntry = rFormatOutputField[nIndex];
            bool bFieldMatch = false;
            bool bFieldMaybeMatch = false;

            tools::Long nDimension = rFieldData.mnDimension;
            if (nDimension == rFormatEntry.nDimension)
            {
                if (rFormatEntry.bSet)
                {
                    if (rFormatEntry.bMatchesAll && !rFieldData.bSubtotal)
                        bFieldMatch = true;
                    else if (nDimension == -2 && rFieldData.nIndex == rFormatEntry.nIndex)
                        bFieldMatch = true;
                    else if (nDimension != -2 && rFieldData.aName == rFormatEntry.aName)
                        bFieldMatch = true;
                }
                else if (!rFormatEntry.bSet && eType == FormatType::Data && !rFieldData.bIsMember
                         && !rFieldData.bContinue)
                {
                    bFieldMatch = true;
                }
                else
                {
                    bFieldMaybeMatch = true;
                }
            }

            if (!bFieldMatch && !bFieldMaybeMatch)
                break;

            if (bFieldMatch)
                nMatch++;

            if (bFieldMaybeMatch)
                nMaybeMatch++;
        }

        if (nMatch == nNoOfFields)
        {
            rMatches.push_back(std::cref(rLineData));
        }
        else if (nMatch + nMaybeMatch == nNoOfFields)
        {
            rMaybeMatches.push_back(std::cref(rLineData));
        }
    }
}

/** Check the lines in matches and maybe matches and output */
void evaluateMatches(ScDocument& rDocument,
                     std::vector<std::reference_wrapper<const LineData>> const& rMatches,
                     std::vector<std::reference_wrapper<const LineData>> const& rMaybeMatches,
                     std::vector<SCCOLROW>& aRows, std::vector<SCCOLROW>& aColumns,
                     FormatOutputEntry const& rOutputEntry, FormatResultDirection eResultDirection)
{
    // We expect that tab and pattern to be set or this method shouldn't be called at all
    assert(rOutputEntry.onTab);
    assert(rOutputEntry.pPattern);

    if (rMatches.empty() && rMaybeMatches.empty())
        return;

    bool bMaybeExists = rMatches.empty();

    auto const& rLineDataVector = bMaybeExists ? rMaybeMatches : rMatches;

    for (LineData const& rLineData : rLineDataVector)
    {
        // Can't continue if we don't have complete row/column data
        if (!rLineData.oLine || !rLineData.oPosition)
            continue;

        if (rOutputEntry.eType == FormatType::Label && !bMaybeExists)
        {
            // Primary axis is set to column (line) then row (position)
            SCCOLROW nColumn = *rLineData.oLine;
            SCCOLROW nRow = *rLineData.oPosition;

            // In row orientation, the primary axis is row, then column, so we need to swap
            if (eResultDirection == FormatResultDirection::ROW)
                std::swap(nRow, nColumn);

            // Set the pattern to the sheet
            rDocument.ApplyPattern(nColumn, nRow, *rOutputEntry.onTab, *rOutputEntry.pPattern);
        }
        else if (rOutputEntry.eType == FormatType::Data)
        {
            if (eResultDirection == FormatResultDirection::ROW)
                aRows.push_back(*rLineData.oLine);
            else if (eResultDirection == FormatResultDirection::COLUMN)
                aColumns.push_back(*rLineData.oLine);
        }
    }
}

// end anonymous namespace

void FormatOutput::apply(ScDocument& rDocument)
{
    if (!mpFormats)
        return;

    for (auto const& rOutputEntry : maFormatOutputEntries)
    {
        if (!rOutputEntry.onTab || !rOutputEntry.pPattern)
            continue;

        std::vector<SCCOLROW> aRows;
        std::vector<SCCOLROW> aColumns;
        {
            std::vector<std::reference_wrapper<const LineData>> rMatches;
            std::vector<std::reference_wrapper<const LineData>> rMaybeMatches;

            checkForMatchingLines(maRowLines, rOutputEntry.aRowOutputFields, rOutputEntry.eType,
                                  rMatches, rMaybeMatches);

            evaluateMatches(rDocument, rMatches, rMaybeMatches, aRows, aColumns, rOutputEntry,
                            FormatResultDirection::ROW);
        }

        {
            std::vector<std::reference_wrapper<const LineData>> rMatches;
            std::vector<std::reference_wrapper<const LineData>> rMaybeMatches;

            checkForMatchingLines(maColumnLines, rOutputEntry.aColumnOutputFields,
                                  rOutputEntry.eType, rMatches, rMaybeMatches);

            evaluateMatches(rDocument, rMatches, rMaybeMatches, aRows, aColumns, rOutputEntry,
                            FormatResultDirection::COLUMN);
        }

        if (!aColumns.empty() && !aRows.empty() && rOutputEntry.eType == FormatType::Data)
        {
            for (SCCOLROW nRow : aRows)
                for (SCCOLROW nColumn : aColumns)
                    rDocument.ApplyPattern(nColumn, nRow, *rOutputEntry.onTab,
                                           *rOutputEntry.pPattern);
        }
    }
}

// end sc

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

Messung V0.5
C=94 H=94 G=93

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