diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sc/source/core/data/fillinfo.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sc/source/core/data/fillinfo.cxx')
-rw-r--r-- | sc/source/core/data/fillinfo.cxx | 1064 |
1 files changed, 1064 insertions, 0 deletions
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx new file mode 100644 index 000000000..a6fa1b318 --- /dev/null +++ b/sc/source/core/data/fillinfo.cxx @@ -0,0 +1,1064 @@ +/* -*- 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->GetItemCount2( ATTR_ROTATE_VALUE ) > 0; +} + +void initRowInfo(const ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow, + double fRowScale, SCROW nRow1, SCTAB nTab, SCROW& rYExtra, SCSIZE& rArrRow, SCROW& rRow2) +{ + sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight; + 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 = ScGlobal::nStdRowHeight; + } + + 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->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 bFound = false; + bool bAnyCondition = false; + for(const auto& rCondFormat : rCondFormats) + { + ScConditionalFormat* pCondForm = rCondFormList.GetFormat(rCondFormat); + if(!pCondForm) + continue; + + ScCondFormatData aData = pCondForm->GetData( + pInfo->maCell, rAddr); + if (!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(); + + } + bFound = true; + + } + // if style is not there, treat like no condition + } + + if(aData.mxColorScale) + { + pInfo->mxColorScale = aData.mxColorScale; + bFound = true; + } + + if(aData.pDataBar) + { + pInfo->pDataBar = aData.pDataBar.get(); + pTableInfo->addDataBarInfo(std::move(aData.pDataBar)); + bFound = true; + } + + if(aData.pIconSet) + { + pInfo->pIconSet = aData.pIconSet.get(); + pTableInfo->addIconSetInfo(std::move(aData.pIconSet)); + bFound = true; + } + + if (bFound) + 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->GetDefaultItem( ATTR_BACKGROUND ); + const ScMergeAttr* pDefMerge = + &pPool->GetDefaultItem( ATTR_MERGE ); + const SvxShadowItem* pDefShadow = + &pPool->GetDefaultItem( 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 ???? + + OSL_ENSURE( 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].pPattern; + } + else + { + nThisRow = MaxRow(); + pPattern = GetDefPattern(); + } + + 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 (pShadowAttr != pDefShadow) + bAnyShadow = true; + + const ScMergeAttr* pMergeAttr = &pPattern->GetItem(ATTR_MERGE); + bool bMerged = ( pMergeAttr != pDefMerge && *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); + 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 (pBackground != pDefBackground) // Column background == Default ? + pThisRowInfo->bEmptyBack = false; + if (bContainsCondFormat) + pThisRowInfo->bEmptyBack = false; + if (bAutoFilter) + pThisRowInfo->bAutoFilter = true; + if (bPivotButton || bPivotPopupButton) + pThisRowInfo->bPivotButton = true; + + ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol); + ScBasicCellInfo* pBasicInfo = &pThisRowInfo->basicCellInfo(nCol); + pInfo->pBackground = pBackground; + pInfo->pPatternAttr = pPattern; + pInfo->bMerged = bMerged; + pInfo->bHOverlapped = bHOverlapped; + pInfo->bVOverlapped = bVOverlapped; + pInfo->bAutoFilter = bAutoFilter; + pInfo->bPivotButton = bPivotButton; + pInfo->bPivotPopupButton = bPivotPopupButton; + pInfo->bFilterActive = bFilterActive; + pInfo->pLinesAttr = pLinesAttr; + pInfo->mpTLBRLine = pTLBRLine; + pInfo->mpBLTRLine = pBLTRLine; + pInfo->pShadowAttr = pShadowAttr; + // nWidth is no longer set individually + + if (bScenario) + { + pInfo->pBackground = 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.meType == 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->pBackground = 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; + pInfo->pBackground = &pPool->Put(SvxBrushItem(*pInfo->mxColorScale, ATTR_BACKGROUND)); + } + } + } + } + + // 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->pBackground = 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 (pInfo->pShadowAttr != pDefShadow) + bAnyShadow = true; + } + } + } + } + + 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) ) + { + if( const 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(); +} + +ScTableInfo::ScTableInfo(const SCSIZE capacity) + : mpRowInfo(new RowInfo[capacity]) + , mnArrCount(0) + , mnArrCapacity(capacity) + , mbPageMode(false) +{ + memset(static_cast<void*>(mpRowInfo.get()), 0, mnArrCapacity * sizeof(RowInfo)); +} + +ScTableInfo::~ScTableInfo() +{ + for( SCSIZE nIdx = 0; nIdx < mnArrCapacity; ++nIdx ) + mpRowInfo[ nIdx ].freeCellInfo(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |