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

Quelle  fillinfo.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 <editeng/boxitem.hxx>
#include <editeng/lineitem.hxx>
#include <editeng/shaditem.hxx>
#include <editeng/brushitem.hxx>
#include <svx/framelink.hxx>
#include <osl/diagnose.h>

#include <fillinfo.hxx>
#include <document.hxx>
#include <table.hxx>
#include <attrib.hxx>
#include <attarray.hxx>
#include <markarr.hxx>
#include <markdata.hxx>
#include <patattr.hxx>
#include <poolhelp.hxx>
#include <docpool.hxx>
#include <conditio.hxx>
#include <stlpool.hxx>
#include <cellvalue.hxx>
#include <mtvcellfunc.hxx>

#include <algorithm>
#include <limits>
#include <vector>
#include <memory>

// Similar as in output.cxx

static void lcl_GetMergeRange( SCCOL nX, SCROW nY, SCSIZE nArrY,
                            const ScDocument* pDoc, RowInfo* pRowInfo,
                            SCCOL nX1, SCROW nY1, SCTAB nTab,
                            SCCOL& rStartX, SCROW& rStartY, SCCOL& rEndX, SCROW& rEndY )
{
    ScCellInfo* pInfo = &pRowInfo[nArrY].cellInfo(nX);

    rStartX = nX;
    rStartY = nY;
    bool bHOver = pInfo->bHOverlapped;
    bool bVOver = pInfo->bVOverlapped;
    SCCOL nLastCol;
    SCROW nLastRow;

    while (bHOver)              // nY constant
    {
        --rStartX;
        if (rStartX >= nX1 && !pDoc->ColHidden(rStartX, nTab, nullptr, &nLastCol))
        {
            bHOver = pRowInfo[nArrY].cellInfo(rStartX).bHOverlapped;
            bVOver = pRowInfo[nArrY].cellInfo(rStartX).bVOverlapped;
        }
        else
        {
            ScMF nOverlap = pDoc->GetAttr( rStartX, rStartY, nTab, ATTR_MERGE_FLAG )->GetValue();
            bHOver = bool(nOverlap & ScMF::Hor);
            bVOver = bool(nOverlap & ScMF::Ver);
        }
    }

    while (bVOver)
    {
        --rStartY;

        if (nArrY>0)
            --nArrY;                        // local copy !

        if (rStartX >= nX1 && rStartY >= nY1 &&
            !pDoc->ColHidden(rStartX, nTab, nullptr, &nLastCol) &&
            !pDoc->RowHidden(rStartY, nTab, nullptr, &nLastRow) &&
            pRowInfo[nArrY].nRowNo == rStartY)
        {
            bVOver = pRowInfo[nArrY].cellInfo(rStartX).bVOverlapped;
        }
        else
        {
            ScMF nOverlap = pDoc->GetAttr(
                                rStartX, rStartY, nTab, ATTR_MERGE_FLAG )->GetValue();
            bVOver = bool(nOverlap & ScMF::Ver);
        }
    }

    const ScMergeAttr* pMerge;
    if (rStartX >= nX1 && rStartY >= nY1 &&
        !pDoc->ColHidden(rStartX, nTab, nullptr, &nLastCol) &&
        !pDoc->RowHidden(rStartY, nTab, nullptr, &nLastRow) &&
        pRowInfo[nArrY].nRowNo == rStartY)
    {
        pMerge = &pRowInfo[nArrY].cellInfo(rStartX).pPatternAttr->
                                        GetItem(ATTR_MERGE);
    }
    else
        pMerge = pDoc->GetAttr(rStartX,rStartY,nTab,ATTR_MERGE);

    rEndX = rStartX + pMerge->GetColMerge() - 1;
    rEndY = rStartY + pMerge->GetRowMerge() - 1;
}

namespace {

class RowInfoFiller
{
    ScDocument& mrDoc;
    SCTAB mnTab;
    RowInfo* mpRowInfo;
    SCCOL mnCol;
    SCSIZE mnArrY;
    SCCOL mnStartCol;
    SCROW mnHiddenEndRow;
    bool mbHiddenRow;

    bool isHidden(size_t nRow)
    {
        SCROW nThisRow = static_cast<SCROW>(nRow);
        if (nThisRow > mnHiddenEndRow)
            mbHiddenRow = mrDoc.RowHidden(nThisRow, mnTab, nullptr, &mnHiddenEndRow);
        return mbHiddenRow;
    }

    void alignArray(size_t nRow)
    {
        while (mpRowInfo[mnArrY].nRowNo < static_cast<SCROW>(nRow))
            ++mnArrY;
    }

    void setInfo(size_t nRow, const ScRefCellValue& rCell)
    {
        alignArray(nRow);

        RowInfo& rThisRowInfo = mpRowInfo[mnArrY];
        if(mnCol >= mnStartCol-1)
            rThisRowInfo.cellInfo(mnCol).maCell = rCell;
        rThisRowInfo.basicCellInfo(mnCol).bEmptyCellText = false;
        ++mnArrY;
    }

public:
    RowInfoFiller(ScDocument& rDoc, SCTAB nTab, RowInfo* pRowInfo, SCCOL nCol, SCSIZE nArrY, SCCOL nStartCol) :
        mrDoc(rDoc), mnTab(nTab), mpRowInfo(pRowInfo), mnCol(nCol), mnArrY(nArrY), mnStartCol(nStartCol),
        mnHiddenEndRow(-1), mbHiddenRow(false) {}

    void operator() (size_t nRow, double fVal)
    {
        if (!isHidden(nRow))
            setInfo(nRow, ScRefCellValue(fVal));
    }

    void operator() (size_t nRow, const svl::SharedString& rStr)
    {
        if (!isHidden(nRow))
            setInfo(nRow, ScRefCellValue(&rStr));
    }

    void operator() (size_t nRow, const EditTextObject* p)
    {
        if (!isHidden(nRow))
            setInfo(nRow, ScRefCellValue(p));
    }

    void operator() (size_t nRow, const ScFormulaCell* p)
    {
        if (!isHidden(nRow))
            setInfo(nRow, ScRefCellValue(const_cast<ScFormulaCell*>(p)));
    }
};

bool isRotateItemUsed(const ScDocumentPool *pPool)
{
    return pPool->GetItemSurrogates(ATTR_ROTATE_VALUE).size() > 0;
}

void initRowInfo(const ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow,
        double fRowScale, SCROW nRow1, SCTAB nTab, SCROW& rYExtra, SCSIZE& rArrRow, SCROW&&nbsp;rRow2)
{
    sal_uInt16 nDocHeight = pDoc->GetSheetOptimalMinRowHeight(nTab);
    SCROW nDocHeightEndRow = -1;
    for (SCROW nSignedY=nRow1-1; nSignedY<=rYExtra; nSignedY++)
    {
        SCROW nY;
        if (nSignedY >= 0)
            nY = nSignedY;
        else
            nY = pDoc->MaxRow()+1;          // invalid

        if (nY > nDocHeightEndRow)
        {
            if (pDoc->ValidRow(nY))
                nDocHeight = pDoc->GetRowHeight( nY, nTab, nullptr, &nDocHeightEndRow );
            else
                nDocHeight = pDoc->GetSheetOptimalMinRowHeight(nTab);
        }

        if ( rArrRow==0 || nDocHeight || nY > pDoc->MaxRow() )
        {
            RowInfo* pThisRowInfo = &pRowInfo[rArrRow];
            // pThisRowInfo->pCellInfo is set below using allocCellInfo()

            sal_uInt16 nHeight = static_cast<sal_uInt16>(
                std::clamp(
                    nDocHeight * fRowScale, 1.0, double(std::numeric_limits<sal_uInt16>::max())));

            pThisRowInfo->nRowNo        = nY;               //TODO: case < 0 ?
            pThisRowInfo->nHeight       = nHeight;
            pThisRowInfo->bEmptyBack    = true;
            pThisRowInfo->bChanged      = true;
            pThisRowInfo->bAutoFilter   = false;
            pThisRowInfo->bPivotButton  = false;
            pThisRowInfo->bPivotToggle  = false;
            pThisRowInfo->nRotMaxCol    = SC_ROTMAX_NONE;

            ++rArrRow;
            if (rArrRow >= nMaxRow)
            {
                OSL_FAIL("FillInfo: Range too big" );
                rYExtra = nSignedY;                         // End
                rRow2 = rYExtra - 1;                        // Adjust range
            }
        }
        else
            if (nSignedY == rYExtra)                 // hidden additional line?
                ++rYExtra;
    }
}

void initCellInfo(RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nStartCol, SCCOL nRotMax,
        const SvxShadowItem* pDefShadow)
{
    for (SCSIZE nArrRow = 0; nArrRow < nArrCount; ++nArrRow)
    {
        RowInfo& rThisRowInfo = pRowInfo[nArrRow];
        // A lot of memory (and performance allocating and initializing it) can
        // be saved if we do not allocate CellInfo for columns before nStartCol.
        // But code in ScOutputData::SetCellRotation(), ScOutputData::DrawRotatedFrame()
        // and ScOutputData::SetCellRotations() accesses those. That depends on
        // nRotMaxCol being set to something else than none, and the value is already
        // initialized here. So allocate all those cells starting from column 0 only if needed.
        SCCOL nMinCol = rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE ? 0 : nStartCol;
        rThisRowInfo.allocCellInfo( nMinCol, nRotMax + 1 );

        for (SCCOL nCol = nMinCol-1; nCol <= nRotMax+1; ++nCol) // Preassign cell info
        {
            ScCellInfo& rInfo = rThisRowInfo.cellInfo(nCol);
            rInfo.pShadowAttr    = pDefShadow;
        }
    }
}

void initColWidths(RowInfo* pRowInfo, const ScDocument* pDoc, double fColScale, SCTAB nTab, SCCOL nCol2, SCCOL nRotMax)
{
    for (SCCOL nCol=nCol2+2; nCol<=nRotMax+1; nCol++)    // Add remaining widths
    {
        if ( pDoc->ValidCol(nCol) )
        {
            if (!pDoc->ColHidden(nCol, nTab))
            {
                sal_uInt16 nThisWidth = static_cast<sal_uInt16>(pDoc->GetColWidth( nCol, nTab ) * fColScale);
                if (!nThisWidth)
                    nThisWidth = 1;

                pRowInfo[0].basicCellInfo(nCol).nWidth = nThisWidth;
            }
        }
    }
}

bool handleConditionalFormat(ScConditionalFormatList& rCondFormList, const ScCondFormatIndexes& rCondFormats,
        ScCellInfo* pInfo, ScTableInfo* pTableInfo, ScStyleSheetPool* pStlPool,
        const ScAddress& rAddr, bool& bHidden, bool& bHideFormula, bool bTabProtect)
{
    bool bAnyCondition = false;
    for(const auto& rCondFormat : rCondFormats)
    {
        ScConditionalFormat* pCondForm = rCondFormList.GetFormat(rCondFormat);
        if(!pCondForm)
            continue;

        ScCondFormatData aData = pCondForm->GetData(
                pInfo->maCell, rAddr);
        if (!bAnyCondition && !aData.aStyleName.isEmpty())
        {
            SfxStyleSheetBase* pStyleSheet =
                pStlPool->Find( aData.aStyleName, SfxStyleFamily::Para );
            if ( pStyleSheet )
            {
                //TODO: cache Style-Sets !!!
                pInfo->pConditionSet = &pStyleSheet->GetItemSet();
                bAnyCondition = true;

                // TODO: moggi: looks like there is a bug around bHidden and bHideFormula
                //              They are normally for the whole pattern and not for a single cell
                // we need to check already here for protected cells
                const ScProtectionAttr* pProtAttr;
                if ( bTabProtect && (pProtAttr = pInfo->pConditionSet->GetItemIfSet( ATTR_PROTECTION )) )
                {
                    bHidden = pProtAttr->GetHideCell();
                    bHideFormula = pProtAttr->GetHideFormula();

                }
            }
            // if style is not there, treat like no condition
        }

        if(aData.mxColorScale && !pInfo->mxColorScale)
        {
            pInfo->mxColorScale = aData.mxColorScale;
        }

        if(aData.pDataBar && !pInfo->pDataBar)
        {
            pInfo->pDataBar = aData.pDataBar.get();
            pTableInfo->addDataBarInfo(std::move(aData.pDataBar));
        }

        if(aData.pIconSet && !pInfo->pIconSet)
        {
            pInfo->pIconSet = aData.pIconSet.get();
            pTableInfo->addIconSetInfo(std::move(aData.pIconSet));
        }

        if (bAnyCondition && pInfo->mxColorScale && pInfo->pIconSet && pInfo->pDataBar)
            break;
    }

    return bAnyCondition;
}

}

void ScDocument::FillInfo(
    ScTableInfo& rTabInfo, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
    SCTAB nTab, double fColScale, double fRowScale, bool bPageMode, bool bFormulaMode,
    const ScMarkData* pMarkData )
{
    OSL_ENSURE( maTabs[nTab], "Table does not exist" );

    bool bLayoutRTL = IsLayoutRTL( nTab );

    ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
    ScStyleSheetPool* pStlPool = mxPoolHelper->GetStylePool();

    RowInfo* pRowInfo = rTabInfo.mpRowInfo.get();

    const SvxBrushItem* pDefBackground =
            &pPool->GetUserOrPoolDefaultItem( ATTR_BACKGROUND );
    const ScMergeAttr* pDefMerge =
            &pPool->GetUserOrPoolDefaultItem( ATTR_MERGE );
    const SvxShadowItem* pDefShadow =
            &pPool->GetUserOrPoolDefaultItem( ATTR_SHADOW );

    SCSIZE nArrRow;
    SCSIZE nArrCount;
    bool bAnyMerged = false;
    bool bAnyShadow = false;
    bool bAnyCondition = false;
    bool bAnyPreview = false;

    bool bTabProtect = IsTabProtected(nTab);

    // first only the entries for the entire column

    nArrRow=0;
    SCROW nYExtra = nRow2+1;
    initRowInfo(this, pRowInfo, rTabInfo.mnArrCapacity, fRowScale, nRow1,
            nTab, nYExtra, nArrRow, nRow2);
    nArrCount = nArrRow;                                      // incl. Dummys

    // Rotated text...

    // Is Attribute really used in document?
    bool bAnyItem = isRotateItemUsed(pPool);

    SCCOL nRotMax = nCol2;
    if ( bAnyItem && HasAttrib( 0, nRow1, nTab, MaxCol(), nRow2+1, nTab,
                                HasAttrFlags::Rotate | HasAttrFlags::Conditional ) )
    {
        //TODO: check Conditionals also for HasAttrFlags::Rotate ????

        assert( nArrCount>2 && "nArrCount too small" );
        FindMaxRotCol( nTab, &pRowInfo[1], nArrCount-1, nCol1, nCol2 );
        //  FindMaxRotCol sets nRotMaxCol

        for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
            if (pRowInfo[nArrRow].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nArrRow].nRotMaxCol > nRotMax)
                nRotMax = pRowInfo[nArrRow].nRotMaxCol;
    }

    //  Allocate cell information only after the test rotation
    //  to nRotMax due to nRotateDir Flag
    initCellInfo(pRowInfo, nArrCount, nCol1, nRotMax, pDefShadow);

    initColWidths(pRowInfo, this, fColScale, nTab, nCol2, nRotMax);

    ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
    if (pCondFormList)
        pCondFormList->startRendering();

    SCCOL nLastHiddenCheckedCol = -2;
    bool bColHidden = false;
    for (SCCOL nCol=-1; nCol<=nCol2+1; nCol++) // collect basic info also for all previous cols, and left & right + 1
    {
        if (ValidCol(nCol))
        {
            // #i58049#, #i57939# Hidden columns must be skipped here, or their attributes
            // will disturb the output

            if (nCol > nLastHiddenCheckedCol)
                bColHidden = ColHidden(nCol, nTab, nullptr, &nLastHiddenCheckedCol);
            // TODO: Optimize this loop.
            if (!bColHidden)
            {
                sal_uInt16 nColWidth = GetColWidth( nCol, nTab, false ); // false=no need to check for hidden, checked above
                sal_uInt16 nThisWidth = static_cast<sal_uInt16>(std::clamp(nColWidth * fColScale, 1.0, double(std::numeric_limits<sal_uInt16>::max())));

                pRowInfo[0].basicCellInfo(nCol).nWidth = nThisWidth;           //TODO: this should be enough

                const ScAttrArray* pThisAttrArr; // Attribute
                if (nCol < maTabs[nTab]->GetAllocatedColumnsCount())
                {
                    ScColumn* pThisCol = &maTabs[nTab]->aCol[nCol]; // Column data

                    nArrRow = 1;
                    // Iterate between rows nY1 and nY2 and pick up non-empty
                    // cells that are not hidden.
                    RowInfoFiller aFunc(*this, nTab, pRowInfo, nCol, nArrRow, nCol1);
                    sc::ParseAllNonEmpty(pThisCol->maCells.begin(), pThisCol->maCells, nRow1, nRow2,
                                         aFunc);

                    pThisAttrArr = pThisCol->pAttrArray.get();
                }
                else
                    pThisAttrArr = &maTabs[nTab]->aDefaultColData.AttrArray();

                if (nCol+1 >= nCol1)                                // Attribute/Blockmark from nX1-1
                {
                    nArrRow = 0;

                    SCROW nCurRow=nRow1;                  // single rows
                    if (nCurRow>0)
                        --nCurRow;                      // 1 more on top
                    else
                        nArrRow = 1;

                    SCROW nThisRow;
                    SCSIZE nIndex;
                    if ( pThisAttrArr->Count() )
                        (void) pThisAttrArr->Search( nCurRow, nIndex );
                    else
                        nIndex = 0;

                    do
                    {
                        const ScPatternAttr* pPattern = nullptr;
                        if ( pThisAttrArr->Count() )
                        {
                            nThisRow = pThisAttrArr->mvData[nIndex].nEndRow;              // End of range
                            pPattern = pThisAttrArr->mvData[nIndex].getScPatternAttr();
                        }
                        else
                        {
                            nThisRow = MaxRow();
                            pPattern = &getCellAttributeHelper().getDefaultCellAttribute();
                        }

                        const SvxBrushItem* pBackground = &pPattern->GetItem(ATTR_BACKGROUND);
                        const SvxBoxItem* pLinesAttr = &pPattern->GetItem(ATTR_BORDER);

                        const SvxLineItem* pTLBRLine = &pPattern->GetItem( ATTR_BORDER_TLBR );
                        const SvxLineItem* pBLTRLine = &pPattern->GetItem( ATTR_BORDER_BLTR );

                        const SvxShadowItem* pShadowAttr = &pPattern->GetItem(ATTR_SHADOW);
                        if (!SfxPoolItem::areSame(pShadowAttr, pDefShadow))
                            bAnyShadow = true;

                        const ScMergeAttr* pMergeAttr = &pPattern->GetItem(ATTR_MERGE);
                        bool bMerged = !SfxPoolItem::areSame( pMergeAttr, pDefMerge );
                        ScMF nOverlap = pPattern->GetItemSet().
                                                        Get(ATTR_MERGE_FLAG).GetValue();
                        bool bHOverlapped(nOverlap & ScMF::Hor);
                        bool bVOverlapped(nOverlap & ScMF::Ver);
                        bool bAutoFilter(nOverlap & ScMF::Auto);
                        bool bPivotButton(nOverlap & ScMF::Button);
                        bool bScenario(nOverlap & ScMF::Scenario);
                        bool bPivotPopupButton(nOverlap & ScMF::ButtonPopup);
                        bool bFilterActive(nOverlap & ScMF::HiddenMember);
                        bool bPivotCollapseButton(nOverlap & ScMF::DpCollapse);
                        bool bPivotExpandButton(nOverlap & ScMF::DpExpand);
                        bool bPivotPopupButtonMulti(nOverlap & ScMF::ButtonPopup2);
                        if (bMerged||bHOverlapped||bVOverlapped)
                            bAnyMerged = true;                              // internal

                        bool bHidden, bHideFormula;
                        if (bTabProtect)
                        {
                            const ScProtectionAttr& rProtAttr = pPattern->GetItem(ATTR_PROTECTION);
                            bHidden = rProtAttr.GetHideCell();
                            bHideFormula = rProtAttr.GetHideFormula();
                        }
                        else
                            bHidden = bHideFormula = false;

                        const ScCondFormatIndexes& rCondFormats = pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
                        bool bContainsCondFormat = !rCondFormats.empty();

                        do
                        {
                            SCROW nLastHiddenRow = -1;
                            bool bRowHidden = RowHidden(nCurRow, nTab, nullptr, &nLastHiddenRow);
                            if ( nArrRow==0 || !bRowHidden )
                            {
                                if ( GetPreviewCellStyle( nCol, nCurRow, nTab  ) != nullptr )
                                    bAnyPreview = true;
                                RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
                                if (!SfxPoolItem::areSame(pBackground, pDefBackground))          // Column background == Default ?
                                    pThisRowInfo->bEmptyBack = false;
                                if (bContainsCondFormat)
                                    pThisRowInfo->bEmptyBack = false;
                                if (bAutoFilter)
                                    pThisRowInfo->bAutoFilter = true;
                                if (bPivotButton || bPivotPopupButton || bPivotPopupButtonMulti)
                                    pThisRowInfo->bPivotButton = true;
                                if (bPivotCollapseButton || bPivotExpandButton)
                                    pThisRowInfo->bPivotToggle = true;

                                ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol);
                                ScBasicCellInfo* pBasicInfo = &pThisRowInfo->basicCellInfo(nCol);
                                pInfo->maBackground = SfxPoolItemHolder(*pPool, pBackground);
                                pInfo->pPatternAttr = pPattern;
                                pInfo->bMerged      = bMerged;
                                pInfo->bHOverlapped = bHOverlapped;
                                pInfo->bVOverlapped = bVOverlapped;
                                pInfo->bAutoFilter  = bAutoFilter;
                                pInfo->bPivotButton  = bPivotButton;
                                pInfo->bPivotPopupButton = bPivotPopupButton;
                                pInfo->bPivotCollapseButton = bPivotCollapseButton;
                                pInfo->bPivotExpandButton = bPivotExpandButton;
                                pInfo->bPivotPopupButtonMulti = bPivotPopupButtonMulti;
                                pInfo->bFilterActive = bFilterActive;
                                pInfo->pLinesAttr   = pLinesAttr;
                                pInfo->mpTLBRLine   = pTLBRLine;
                                pInfo->mpBLTRLine   = pBLTRLine;
                                pInfo->pShadowAttr  = pShadowAttr;
                                // nWidth is no longer set individually

                                if (bScenario)
                                {
                                    pInfo->maBackground = SfxPoolItemHolder(*pPool, ScGlobal::GetButtonBrushItem());
                                    pThisRowInfo->bEmptyBack = false;
                                }

                                if (bContainsCondFormat && pCondFormList)
                                {
                                    bAnyCondition |= handleConditionalFormat(*pCondFormList, rCondFormats,
                                            pInfo, &rTabInfo, pStlPool, ScAddress(nCol, nCurRow, nTab),
                                            bHidden, bHideFormula, bTabProtect);
                                }

                                if (bHidden || (bFormulaMode && bHideFormula && pInfo->maCell.getType() == CELLTYPE_FORMULA))
                                    pBasicInfo->bEmptyCellText = true;

                                ++nArrRow;
                            }
                            else if (nLastHiddenRow >= 0)
                            {
                                nCurRow = nLastHiddenRow;
                                if (nCurRow > nThisRow)
                                    nCurRow = nThisRow;
                            }
                            ++nCurRow;
                        }
                        while (nCurRow <= nThisRow && nCurRow <= nYExtra);
                        ++nIndex;
                    }
                    while ( nIndex < pThisAttrArr->Count() && nThisRow < nYExtra );

                    if (pMarkData && pMarkData->IsMultiMarked())
                    {
                        //  Block marks
                        ScMarkArray aThisMarkArr(pMarkData->GetMarkArray( nCol ));
                        nArrRow = 1;
                        nCurRow = nRow1;                                      // single rows

                        if ( aThisMarkArr.Search( nRow1, nIndex ) )
                        {
                            do
                            {
                                nThisRow=aThisMarkArr.mvData[nIndex].nRow;      // End of range

                                do
                                {
                                    if ( !RowHidden( nCurRow,nTab ) )
                                    {
                                        ++nArrRow;
                                    }
                                    ++nCurRow;
                                }
                                while (nCurRow <= nThisRow && nCurRow <= nRow2);
                                ++nIndex;
                            }
                            while ( nIndex < aThisMarkArr.mvData.size() && nThisRow < nRow2 );
                        }
                    }
                }
                else                                    // columns in front
                {
                    for (nArrRow=1; nArrRow+1<nArrCount; nArrRow++)
                        pRowInfo[nArrRow].basicCellInfo(nCol).nWidth = nThisWidth; //TODO: or check only 0 ??
                }
            }
        }
        else
            pRowInfo[0].basicCellInfo(nCol).nWidth = STD_COL_WIDTH;
        // STD_COL_WIDTH farthest to the left and right is needed for DrawExtraShadow
    }

    if (pCondFormList)
        pCondFormList->endRendering();

    // evaluate conditional formatting
    std::vector< std::unique_ptr<ScPatternAttr> > aAltPatterns;
    // favour preview over condition
    if (bAnyCondition || bAnyPreview)
    {
        for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
        {
            for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++)                  // 1 more left and right
            {
                ScCellInfo* pInfo = &pRowInfo[nArrRow].cellInfo(nCol);
                ScPatternAttr* pModifiedPatt = nullptr;

                if ( ValidCol(nCol) && pRowInfo[nArrRow].nRowNo <= MaxRow() )
                {
                    if ( ScStyleSheet* pPreviewStyle = GetPreviewCellStyle( nCol, pRowInfo[nArrRow].nRowNo, nTab ) )
                    {
                        aAltPatterns.push_back( std::make_unique<ScPatternAttr>( *pInfo->pPatternAttr ) );
                        pModifiedPatt = aAltPatterns.back().get();
                        pModifiedPatt->SetStyleSheet( pPreviewStyle );
                    }
                }
                // favour preview over condition
                const SfxItemSet* pCondSet = pModifiedPatt ? &pModifiedPatt->GetItemSet() : pInfo->pConditionSet;

                if (pCondSet)
                {
                            // Background
                    if ( const SvxBrushItem* pItem = pCondSet->GetItemIfSet( ATTR_BACKGROUND ) )
                    {
                        pInfo->maBackground = SfxPoolItemHolder(*pPool, pItem);
                        pRowInfo[nArrRow].bEmptyBack = false;
                    }

                            // Border
                    if ( const SvxBoxItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER ) )
                        pInfo->pLinesAttr = pItem;

                    if ( const SvxLineItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER_TLBR ) )
                        pInfo->mpTLBRLine = pItem;
                    if ( const SvxLineItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER_BLTR ) )
                        pInfo->mpBLTRLine = pItem;

                            //  Shadow
                    if ( const SvxShadowItem* pItem = pCondSet->GetItemIfSet( ATTR_SHADOW ) )
                    {
                        pInfo->pShadowAttr = pItem;
                        bAnyShadow = true;
                    }
                }
                if( bAnyCondition && pInfo->mxColorScale)
                {
                    pRowInfo[nArrRow].bEmptyBack = false;
                    const SvxBrushItem aBrushItem(*pInfo->mxColorScale, ATTR_BACKGROUND);
                    pInfo->maBackground = SfxPoolItemHolder(*pPool, &aBrushItem);
                }
            }
        }
    }

    // End conditional formatting

                //      Adjust data from merged cells

    if (bAnyMerged)
    {
        for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
        {
            RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
            SCROW nSignedY = nArrRow ? pThisRowInfo->nRowNo : nRow1-1;

            for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++)                  // 1 more left and right
            {
                ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol);

                if (pInfo->bMerged || pInfo->bHOverlapped || pInfo->bVOverlapped)
                {
                    SCCOL nStartX;
                    SCROW nStartY;
                    SCCOL nEndX;
                    SCROW nEndY;
                    lcl_GetMergeRange( nCol,nSignedY, nArrRow, this,pRowInfo, nCol1,nRow1,nTab,
                                        nStartX,nStartY, nEndX,nEndY );
                    const ScPatternAttr* pStartPattern = GetPattern( nStartX,nStartY,nTab );
                    const SfxItemSet* pStartCond = GetCondResult( nStartX,nStartY,nTab );

                    // Copy Background (or in output.cxx)

                    const SvxBrushItem* pBrushItem = nullptr;
                    if ( !pStartCond ||
                        !(pBrushItem = pStartCond->GetItemIfSet(ATTR_BACKGROUND)) )
                        pBrushItem = &pStartPattern->GetItem(ATTR_BACKGROUND);
                    pInfo->maBackground = SfxPoolItemHolder(*pPool, pBrushItem);
                    pRowInfo[nArrRow].bEmptyBack = false;

                    // Shadow

                    const SvxShadowItem* pShadowItem = nullptr;
                    if ( !pStartCond ||
                        !(pShadowItem = pStartCond->GetItemIfSet(ATTR_SHADOW)) )
                        pShadowItem = &pStartPattern->GetItem(ATTR_SHADOW);
                    pInfo->pShadowAttr = pShadowItem;
                    if (!SfxPoolItem::areSame(pInfo->pShadowAttr, pDefShadow))
                        bAnyShadow = true;

                    const ScCondFormatIndexes& rCondFormatIndex
                        = pStartPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();

                    if (pCondFormList && !pStartCond && !rCondFormatIndex.empty())
                    {
                        for (const auto& rItem : rCondFormatIndex)
                        {
                            const ScConditionalFormat* pCondForm = pCondFormList->GetFormat(rItem);
                            if (pCondForm)
                            {
                                ScCondFormatData aData = pCondForm->GetData(
                                    pInfo->maCell, ScAddress(nStartX, nStartY, nTab));

                                // Color scale
                                if (aData.mxColorScale && !pInfo->mxColorScale)
                                    pInfo->mxColorScale = aData.mxColorScale;
                            }
                        }
                    }
                }
            }
        }
    }

    if (bAnyShadow)                             // distribute Shadow
    {
        for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
        {
            bool bTop = ( nArrRow == 0 );
            bool bBottom = ( nArrRow+1 == nArrCount );

            for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++)                  // 1 more left and right
            {
                bool bLeft = ( nCol == nCol1-1 );
                bool bRight = ( nCol == nCol2+1 );

                ScCellInfo* pInfo = &pRowInfo[nArrRow].cellInfo(nCol);
                const SvxShadowItem* pThisAttr = pInfo->pShadowAttr;
                SvxShadowLocation eLoc = pThisAttr ? pThisAttr->GetLocation() : SvxShadowLocation::NONE;
                if (eLoc != SvxShadowLocation::NONE)
                {
                    //  or test on != eLoc

                    SCCOL nDxPos = 1;
                    SCCOL nDxNeg = -1;

                    while ( nCol+nDxPos < nCol2+1 && pRowInfo[0].basicCellInfo(nCol+nDxPos).nWidth == 0 )
                        ++nDxPos;
                    while ( nCol+nDxNeg > nCol1-1 && pRowInfo[0].basicCellInfo(nCol+nDxNeg).nWidth == 0 )
                        --nDxNeg;

                    bool bLeftDiff = !bLeft &&
                            pRowInfo[nArrRow].cellInfo(nCol+nDxNeg).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
                    bool bRightDiff = !bRight &&
                            pRowInfo[nArrRow].cellInfo(nCol+nDxPos).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
                    bool bTopDiff = !bTop &&
                            pRowInfo[nArrRow-1].cellInfo(nCol).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
                    bool bBottomDiff = !bBottom &&
                            pRowInfo[nArrRow+1].cellInfo(nCol).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;

                    if ( bLayoutRTL )
                    {
                        switch (eLoc)
                        {
                            case SvxShadowLocation::BottomRight: eLoc = SvxShadowLocation::BottomLeft;  break;
                            case SvxShadowLocation::BottomLeft:  eLoc = SvxShadowLocation::BottomRight; break;
                            case SvxShadowLocation::TopRight:    eLoc = SvxShadowLocation::TopLeft;     break;
                            case SvxShadowLocation::TopLeft:     eLoc = SvxShadowLocation::TopRight;    break;
                            default:
                            {
                                // added to avoid warnings
                            }
                        }
                    }

                    switch (eLoc)
                    {
                        case SvxShadowLocation::BottomRight:
                            if (bBottomDiff)
                            {
                                pRowInfo[nArrRow+1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow+1].cellInfo(nCol).eHShadowPart =
                                                bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
                            }
                            if (bRightDiff)
                            {
                                pRowInfo[nArrRow].cellInfo(nCol+1).pVShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow].cellInfo(nCol+1).eVShadowPart =
                                                bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
                            }
                            if (bBottomDiff && bRightDiff)
                            {
                                pRowInfo[nArrRow+1].cellInfo(nCol+1).pHShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow+1].cellInfo(nCol+1).eHShadowPart = SC_SHADOW_CORNER;
                            }
                            break;

                        case SvxShadowLocation::BottomLeft:
                            if (bBottomDiff)
                            {
                                pRowInfo[nArrRow+1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow+1].cellInfo(nCol).eHShadowPart =
                                                bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
                            }
                            if (bLeftDiff)
                            {
                                pRowInfo[nArrRow].cellInfo(nCol-1).pVShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow].cellInfo(nCol-1).eVShadowPart =
                                                bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
                            }
                            if (bBottomDiff && bLeftDiff)
                            {
                                pRowInfo[nArrRow+1].cellInfo(nCol-1).pHShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow+1].cellInfo(nCol-1).eHShadowPart = SC_SHADOW_CORNER;
                            }
                            break;

                        case SvxShadowLocation::TopRight:
                            if (bTopDiff)
                            {
                                pRowInfo[nArrRow-1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow-1].cellInfo(nCol).eHShadowPart =
                                                bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
                            }
                            if (bRightDiff)
                            {
                                pRowInfo[nArrRow].cellInfo(nCol+1).pVShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow].cellInfo(nCol+1).eVShadowPart =
                                                bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
                            }
                            if (bTopDiff && bRightDiff)
                            {
                                pRowInfo[nArrRow-1].cellInfo(nCol+1).pHShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow-1].cellInfo(nCol+1).eHShadowPart = SC_SHADOW_CORNER;
                            }
                            break;

                        case SvxShadowLocation::TopLeft:
                            if (bTopDiff)
                            {
                                pRowInfo[nArrRow-1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow-1].cellInfo(nCol).eHShadowPart =
                                                bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
                            }
                            if (bLeftDiff)
                            {
                                pRowInfo[nArrRow].cellInfo(nCol-1).pVShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow].cellInfo(nCol-1).eVShadowPart =
                                                bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
                            }
                            if (bTopDiff && bLeftDiff)
                            {
                                pRowInfo[nArrRow-1].cellInfo(nCol-1).pHShadowOrigin = pThisAttr;
                                pRowInfo[nArrRow-1].cellInfo(nCol-1).eHShadowPart = SC_SHADOW_CORNER;
                            }
                            break;

                        default:
                            OSL_FAIL("wrong Shadow-Enum");
                    }
                }
            }
        }
    }

    rTabInfo.mnArrCount = sal::static_int_cast<sal_uInt16>(nArrCount);
    rTabInfo.mbPageMode = bPageMode;

    // *** create the frame border array ***

    // RowInfo structs are filled in the range [ 0 , nArrCount-1 ],
    // each RowInfo contains ScCellInfo structs in the range [ nCol1-1 , nCol2+1 ]
    // and ScBasicCellInfo structs in the range [ -1, nCol2+1 ]

    size_t nColCount = nCol2 - nCol1 + 1 + 2;
    size_t nRowCount = nArrCount;

    svx::frame::Array& rArray = rTabInfo.maArray;
    rArray.Initialize( nColCount, nRowCount );

    for( size_t nRow = 0; nRow < nRowCount; ++nRow )
    {
        sal_uInt16 nCellInfoY = static_cast< sal_uInt16 >( nRow );
        RowInfo& rThisRowInfo = pRowInfo[ nCellInfoY ];

        for( SCCOL nCol = nCol1 - 1; nCol <= nCol2 + 1; ++nCol ) // 1 more left and right
        {
            const ScCellInfo& rInfo = rThisRowInfo.cellInfo( nCol );
            const SvxBoxItem* pBox = rInfo.pLinesAttr;
            const SvxLineItem* pTLBR = rInfo.mpTLBRLine;
            const SvxLineItem* pBLTR = rInfo.mpBLTRLine;

            size_t colToIndex = -(nCol1 - 1);
            // These are rArray indexes (0-based), not really rows/columns.
            size_t nX = nCol + colToIndex;
            size_t nFirstCol = nX;
            size_t nFirstRow = nRow;

            // *** merged cells *** -------------------------------------------

            if( !rArray.IsMerged( nX, nRow ) && (rInfo.bMerged || rInfo.bHOverlapped || rInfo.bVOverlapped) )
            {
                // *** insert merged range in svx::frame::Array ***

                /*  #i69369# top-left cell of a merged range may be located in
                    a hidden column or row. Use lcl_GetMergeRange() to find the
                    complete merged range, then calculate dimensions and
                    document position of the visible range. */


                // note: document rows must be looked up in RowInfo structs

                // current column and row in document coordinates
                SCCOL nCurrDocCol = nCol;
                SCROW nCurrDocRow = static_cast< SCROW >( (nCellInfoY > 0) ? rThisRowInfo.nRowNo : (nRow1 - 1) );

                // find entire merged range in document, returns signed document coordinates
                SCCOL nFirstRealDocColS, nLastRealDocColS;
                SCROW nFirstRealDocRowS, nLastRealDocRowS;
                lcl_GetMergeRange( nCurrDocCol, nCurrDocRow,
                    nCellInfoY, this, pRowInfo, nCol1,nRow1,nTab,
                    nFirstRealDocColS, nFirstRealDocRowS, nLastRealDocColS, nLastRealDocRowS );

                // *complete* merged range in document coordinates
                SCCOL nFirstRealDocCol = nFirstRealDocColS;
                SCROW nFirstRealDocRow = nFirstRealDocRowS;
                SCCOL nLastRealDocCol  = nLastRealDocColS;
                SCROW nLastRealDocRow  = nLastRealDocRowS;

                // first visible column (nCol1-1 is first processed document column)
                SCCOL nFirstDocCol = (nCol1 > 0) ? ::std::max< SCCOL >( nFirstRealDocCol, nCol1 - 1 ) : nFirstRealDocCol;
                nFirstCol = nFirstDocCol + colToIndex;

                // last visible column (nCol2+1 is last processed document column)
                SCCOL nLastDocCol = (nCol2 < MaxCol()) ? ::std::min< SCCOL >( nLastRealDocCol, nCol2 + 1 ) : nLastRealDocCol;
                size_t nLastCol = nLastDocCol + colToIndex;

                // first visible row
                sal_uInt16 nFirstCellInfoY = nCellInfoY;
                while( ((nFirstCellInfoY > 1) && (pRowInfo[ nFirstCellInfoY - 1 ].nRowNo >= nFirstRealDocRow)) ||
                       ((nFirstCellInfoY == 1) && (static_cast< SCROW >( nRow1 - 1 ) >= nFirstRealDocRow)) )
                    --nFirstCellInfoY;
                SCROW nFirstDocRow = (nFirstCellInfoY > 0) ? pRowInfo[ nFirstCellInfoY ].nRowNo : static_cast< SCROW >( nRow1 - 1 );
                nFirstRow = static_cast< size_t >( nFirstCellInfoY );

                // last visible row
                sal_uInt16 nLastCellInfoY = nCellInfoY;
                while( (sal::static_int_cast<SCSIZE>(nLastCellInfoY + 1) < nArrCount) &&
                            (pRowInfo[ nLastCellInfoY + 1 ].nRowNo <= nLastRealDocRow) )
                    ++nLastCellInfoY;
                SCROW nLastDocRow = (nLastCellInfoY > 0) ? pRowInfo[ nLastCellInfoY ].nRowNo : static_cast< SCROW >( nRow1 - 1 );
                size_t nLastRow = static_cast< size_t >( nLastCellInfoY );

                // insert merged range
                rArray.SetMergedRange( nFirstCol, nFirstRow, nLastCol, nLastRow );

                // *** find additional size not included in svx::frame::Array ***

                // additional space before first column
                if( nFirstCol == 0 )
                {
                    tools::Long nSize = 0;
                    for( SCCOL nDocCol = nFirstRealDocCol; nDocCol < nFirstDocCol; ++nDocCol )
                        nSize += std::max( tools::Long(GetColWidth( nDocCol, nTab ) * fColScale), tools::Long(1) );
                    rArray.SetAddMergedLeftSize( nX, nRow, nSize );
                }
                // additional space after last column
                if( nLastCol + 1 == nColCount )
                {
                    tools::Long nSize = 0;
                    for( SCCOL nDocCol = nLastDocCol + 1; nDocCol <= nLastRealDocCol; ++nDocCol )
                        nSize += std::max( tools::Long(GetColWidth( nDocCol, nTab ) * fColScale), tools::Long(1) );
                    rArray.SetAddMergedRightSize( nX, nRow, nSize );
                }
                // additional space above first row
                if( nFirstRow == 0 )
                {
                    tools::Long nSize = 0;
                    for( SCROW nDocRow = nFirstRealDocRow; nDocRow < nFirstDocRow; ++nDocRow )
                        nSize += std::max( tools::Long(GetRowHeight( nDocRow, nTab ) * fRowScale), tools::Long(1) );
                    rArray.SetAddMergedTopSize( nX, nRow, nSize );
                }
                // additional space beyond last row
                if( nLastRow + 1 == nRowCount )
                {
                    tools::Long nSize = 0;
                    for( SCROW nDocRow = nLastDocRow + 1; nDocRow <= nLastRealDocRow; ++nDocRow )
                        nSize += std::max( tools::Long(GetRowHeight( nDocRow, nTab ) * fRowScale), tools::Long(1) );
                    rArray.SetAddMergedBottomSize( nX, nRow, nSize );
                }

                // *** use line attributes from real origin cell ***

                if( (nFirstRealDocCol != nCurrDocCol) || (nFirstRealDocRow != nCurrDocRow) )
                {
                    ifconst ScPatternAttr* pPattern = GetPattern( nFirstRealDocCol, nFirstRealDocRow, nTab ) )
                    {
                        const SfxItemSet* pCond = GetCondResult( nFirstRealDocCol, nFirstRealDocRow, nTab );
                        pBox = &pPattern->GetItem( ATTR_BORDER, pCond );
                        pTLBR = &pPattern->GetItem( ATTR_BORDER_TLBR, pCond );
                        pBLTR = &pPattern->GetItem( ATTR_BORDER_BLTR, pCond );
                    }
                    else
                    {
                        pBox = nullptr;
                        pTLBR = pBLTR = nullptr;
                    }
                }
            }

            // *** borders *** ------------------------------------------------

            if( pBox )
            {
                rArray.SetCellStyleLeft(   nFirstCol, nFirstRow, svx::frame::Style( pBox->GetLeft(),   fColScale ) );
                rArray.SetCellStyleRight(  nFirstCol, nFirstRow, svx::frame::Style( pBox->GetRight(),  fColScale ) );
                rArray.SetCellStyleTop(    nFirstCol, nFirstRow, svx::frame::Style( pBox->GetTop(),    fRowScale ) );
                rArray.SetCellStyleBottom( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetBottom(), fRowScale ) );
            }

            if( pTLBR )
                rArray.SetCellStyleTLBR( nFirstCol, nFirstRow, svx::frame::Style( pTLBR->GetLine(), fRowScale ) );
            if( pBLTR )
                rArray.SetCellStyleBLTR( nFirstCol, nFirstRow, svx::frame::Style( pBLTR->GetLine(), fRowScale ) );
        }
    }

    /*  Mirror the entire frame array. */
    if( bLayoutRTL )
        rArray.MirrorSelfX();
}

/// We seem to need to allocate three extra rows here, not sure why
///
ScTableInfo::ScTableInfo(SCROW nStartRow, SCROW nEndRow, bool bHintOnly)
    : mnArrCount(0)
    , mnArrCapacity(nEndRow - nStartRow + 4)
    , mbPageMode(false)
{
    assert(nStartRow >= 0);
    assert(nEndRow >= nStartRow);
    if (bHintOnly && mnArrCapacity > 1024)
    {
        SAL_INFO("sc.core""ScTableInfo excessive capacity: " << mnArrCapacity << " start: " << nStartRow << " end: " << nEndRow);
        mnArrCapacity = 1024;
    }
    mpRowInfo.reset(new RowInfo[mnArrCapacity] {});
}

ScTableInfo::~ScTableInfo()
{
    for( SCSIZE nIdx = 0; nIdx < mnArrCapacity; ++nIdx )
        mpRowInfo[ nIdx ].freeCellInfo();
}

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

Messung V0.5
C=92 H=80 G=86

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