Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / sc / source / core / data / fillinfo.cxx
blobd3739b2878efc0c112efd740b4201185c11487cb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4 * This file is part of the LibreOffice project.
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 * This file incorporates work covered by the following license notice:
12 * Licensed to the Apache Software Foundation (ASF) under one or more
13 * contributor license agreements. See the NOTICE file distributed
14 * with this work for additional information regarding copyright
15 * ownership. The ASF licenses this file to you under the Apache
16 * License, Version 2.0 (the "License"); you may not use this file
17 * except in compliance with the License. You may obtain a copy of
18 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <scitems.hxx>
22 #include <editeng/boxitem.hxx>
23 #include <editeng/lineitem.hxx>
24 #include <editeng/shaditem.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <svx/framelink.hxx>
27 #include <osl/diagnose.h>
29 #include <fillinfo.hxx>
30 #include <document.hxx>
31 #include <table.hxx>
32 #include <attrib.hxx>
33 #include <attarray.hxx>
34 #include <markarr.hxx>
35 #include <markdata.hxx>
36 #include <patattr.hxx>
37 #include <poolhelp.hxx>
38 #include <docpool.hxx>
39 #include <conditio.hxx>
40 #include <stlpool.hxx>
41 #include <cellvalue.hxx>
42 #include <mtvcellfunc.hxx>
44 #include <algorithm>
45 #include <limits>
46 #include <vector>
47 #include <memory>
49 // Similar as in output.cxx
51 static void lcl_GetMergeRange( SCCOL nX, SCROW nY, SCSIZE nArrY,
52 const ScDocument* pDoc, RowInfo* pRowInfo,
53 SCCOL nX1, SCROW nY1, SCTAB nTab,
54 SCCOL& rStartX, SCROW& rStartY, SCCOL& rEndX, SCROW& rEndY )
56 ScCellInfo* pInfo = &pRowInfo[nArrY].cellInfo(nX);
58 rStartX = nX;
59 rStartY = nY;
60 bool bHOver = pInfo->bHOverlapped;
61 bool bVOver = pInfo->bVOverlapped;
62 SCCOL nLastCol;
63 SCROW nLastRow;
65 while (bHOver) // nY constant
67 --rStartX;
68 if (rStartX >= nX1 && !pDoc->ColHidden(rStartX, nTab, nullptr, &nLastCol))
70 bHOver = pRowInfo[nArrY].cellInfo(rStartX).bHOverlapped;
71 bVOver = pRowInfo[nArrY].cellInfo(rStartX).bVOverlapped;
73 else
75 ScMF nOverlap = pDoc->GetAttr( rStartX, rStartY, nTab, ATTR_MERGE_FLAG )->GetValue();
76 bHOver = bool(nOverlap & ScMF::Hor);
77 bVOver = bool(nOverlap & ScMF::Ver);
81 while (bVOver)
83 --rStartY;
85 if (nArrY>0)
86 --nArrY; // local copy !
88 if (rStartX >= nX1 && rStartY >= nY1 &&
89 !pDoc->ColHidden(rStartX, nTab, nullptr, &nLastCol) &&
90 !pDoc->RowHidden(rStartY, nTab, nullptr, &nLastRow) &&
91 pRowInfo[nArrY].nRowNo == rStartY)
93 bVOver = pRowInfo[nArrY].cellInfo(rStartX).bVOverlapped;
95 else
97 ScMF nOverlap = pDoc->GetAttr(
98 rStartX, rStartY, nTab, ATTR_MERGE_FLAG )->GetValue();
99 bVOver = bool(nOverlap & ScMF::Ver);
103 const ScMergeAttr* pMerge;
104 if (rStartX >= nX1 && rStartY >= nY1 &&
105 !pDoc->ColHidden(rStartX, nTab, nullptr, &nLastCol) &&
106 !pDoc->RowHidden(rStartY, nTab, nullptr, &nLastRow) &&
107 pRowInfo[nArrY].nRowNo == rStartY)
109 pMerge = &pRowInfo[nArrY].cellInfo(rStartX).pPatternAttr->
110 GetItem(ATTR_MERGE);
112 else
113 pMerge = pDoc->GetAttr(rStartX,rStartY,nTab,ATTR_MERGE);
115 rEndX = rStartX + pMerge->GetColMerge() - 1;
116 rEndY = rStartY + pMerge->GetRowMerge() - 1;
119 namespace {
121 class RowInfoFiller
123 ScDocument& mrDoc;
124 SCTAB mnTab;
125 RowInfo* mpRowInfo;
126 SCCOL mnCol;
127 SCSIZE mnArrY;
128 SCCOL mnStartCol;
129 SCROW mnHiddenEndRow;
130 bool mbHiddenRow;
132 bool isHidden(size_t nRow)
134 SCROW nThisRow = static_cast<SCROW>(nRow);
135 if (nThisRow > mnHiddenEndRow)
136 mbHiddenRow = mrDoc.RowHidden(nThisRow, mnTab, nullptr, &mnHiddenEndRow);
137 return mbHiddenRow;
140 void alignArray(size_t nRow)
142 while (mpRowInfo[mnArrY].nRowNo < static_cast<SCROW>(nRow))
143 ++mnArrY;
146 void setInfo(size_t nRow, const ScRefCellValue& rCell)
148 alignArray(nRow);
150 RowInfo& rThisRowInfo = mpRowInfo[mnArrY];
151 if(mnCol >= mnStartCol-1)
152 rThisRowInfo.cellInfo(mnCol).maCell = rCell;
153 rThisRowInfo.basicCellInfo(mnCol).bEmptyCellText = false;
154 ++mnArrY;
157 public:
158 RowInfoFiller(ScDocument& rDoc, SCTAB nTab, RowInfo* pRowInfo, SCCOL nCol, SCSIZE nArrY, SCCOL nStartCol) :
159 mrDoc(rDoc), mnTab(nTab), mpRowInfo(pRowInfo), mnCol(nCol), mnArrY(nArrY), mnStartCol(nStartCol),
160 mnHiddenEndRow(-1), mbHiddenRow(false) {}
162 void operator() (size_t nRow, double fVal)
164 if (!isHidden(nRow))
165 setInfo(nRow, ScRefCellValue(fVal));
168 void operator() (size_t nRow, const svl::SharedString& rStr)
170 if (!isHidden(nRow))
171 setInfo(nRow, ScRefCellValue(&rStr));
174 void operator() (size_t nRow, const EditTextObject* p)
176 if (!isHidden(nRow))
177 setInfo(nRow, ScRefCellValue(p));
180 void operator() (size_t nRow, const ScFormulaCell* p)
182 if (!isHidden(nRow))
183 setInfo(nRow, ScRefCellValue(const_cast<ScFormulaCell*>(p)));
187 bool isRotateItemUsed(const ScDocumentPool *pPool)
189 ItemSurrogates aSurrogates;
190 pPool->GetItemSurrogates(aSurrogates, ATTR_ROTATE_VALUE);
191 return aSurrogates.size() > 0;
194 void initRowInfo(const ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow,
195 double fRowScale, SCROW nRow1, SCTAB nTab, SCROW& rYExtra, SCSIZE& rArrRow, SCROW& rRow2)
197 sal_uInt16 nDocHeight = pDoc->GetSheetOptimalMinRowHeight(nTab);
198 SCROW nDocHeightEndRow = -1;
199 for (SCROW nSignedY=nRow1-1; nSignedY<=rYExtra; nSignedY++)
201 SCROW nY;
202 if (nSignedY >= 0)
203 nY = nSignedY;
204 else
205 nY = pDoc->MaxRow()+1; // invalid
207 if (nY > nDocHeightEndRow)
209 if (pDoc->ValidRow(nY))
210 nDocHeight = pDoc->GetRowHeight( nY, nTab, nullptr, &nDocHeightEndRow );
211 else
212 nDocHeight = pDoc->GetSheetOptimalMinRowHeight(nTab);
215 if ( rArrRow==0 || nDocHeight || nY > pDoc->MaxRow() )
217 RowInfo* pThisRowInfo = &pRowInfo[rArrRow];
218 // pThisRowInfo->pCellInfo is set below using allocCellInfo()
220 sal_uInt16 nHeight = static_cast<sal_uInt16>(
221 std::clamp(
222 nDocHeight * fRowScale, 1.0, double(std::numeric_limits<sal_uInt16>::max())));
224 pThisRowInfo->nRowNo = nY; //TODO: case < 0 ?
225 pThisRowInfo->nHeight = nHeight;
226 pThisRowInfo->bEmptyBack = true;
227 pThisRowInfo->bChanged = true;
228 pThisRowInfo->bAutoFilter = false;
229 pThisRowInfo->bPivotButton = false;
230 pThisRowInfo->bPivotToggle = false;
231 pThisRowInfo->nRotMaxCol = SC_ROTMAX_NONE;
233 ++rArrRow;
234 if (rArrRow >= nMaxRow)
236 OSL_FAIL("FillInfo: Range too big" );
237 rYExtra = nSignedY; // End
238 rRow2 = rYExtra - 1; // Adjust range
241 else
242 if (nSignedY == rYExtra) // hidden additional line?
243 ++rYExtra;
247 void initCellInfo(RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nStartCol, SCCOL nRotMax,
248 const SvxShadowItem* pDefShadow)
250 for (SCSIZE nArrRow = 0; nArrRow < nArrCount; ++nArrRow)
252 RowInfo& rThisRowInfo = pRowInfo[nArrRow];
253 // A lot of memory (and performance allocating and initializing it) can
254 // be saved if we do not allocate CellInfo for columns before nStartCol.
255 // But code in ScOutputData::SetCellRotation(), ScOutputData::DrawRotatedFrame()
256 // and ScOutputData::SetCellRotations() accesses those. That depends on
257 // nRotMaxCol being set to something else than none, and the value is already
258 // initialized here. So allocate all those cells starting from column 0 only if needed.
259 SCCOL nMinCol = rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE ? 0 : nStartCol;
260 rThisRowInfo.allocCellInfo( nMinCol, nRotMax + 1 );
262 for (SCCOL nCol = nMinCol-1; nCol <= nRotMax+1; ++nCol) // Preassign cell info
264 ScCellInfo& rInfo = rThisRowInfo.cellInfo(nCol);
265 rInfo.pShadowAttr = pDefShadow;
270 void initColWidths(RowInfo* pRowInfo, const ScDocument* pDoc, double fColScale, SCTAB nTab, SCCOL nCol2, SCCOL nRotMax)
272 for (SCCOL nCol=nCol2+2; nCol<=nRotMax+1; nCol++) // Add remaining widths
274 if ( pDoc->ValidCol(nCol) )
276 if (!pDoc->ColHidden(nCol, nTab))
278 sal_uInt16 nThisWidth = static_cast<sal_uInt16>(pDoc->GetColWidth( nCol, nTab ) * fColScale);
279 if (!nThisWidth)
280 nThisWidth = 1;
282 pRowInfo[0].basicCellInfo(nCol).nWidth = nThisWidth;
288 bool handleConditionalFormat(ScConditionalFormatList& rCondFormList, const ScCondFormatIndexes& rCondFormats,
289 ScCellInfo* pInfo, ScTableInfo* pTableInfo, ScStyleSheetPool* pStlPool,
290 const ScAddress& rAddr, bool& bHidden, bool& bHideFormula, bool bTabProtect)
292 bool bAnyCondition = false;
293 for(const auto& rCondFormat : rCondFormats)
295 ScConditionalFormat* pCondForm = rCondFormList.GetFormat(rCondFormat);
296 if(!pCondForm)
297 continue;
299 ScCondFormatData aData = pCondForm->GetData(
300 pInfo->maCell, rAddr);
301 if (!bAnyCondition && !aData.aStyleName.isEmpty())
303 SfxStyleSheetBase* pStyleSheet =
304 pStlPool->Find( aData.aStyleName, SfxStyleFamily::Para );
305 if ( pStyleSheet )
307 //TODO: cache Style-Sets !!!
308 pInfo->pConditionSet = &pStyleSheet->GetItemSet();
309 bAnyCondition = true;
311 // TODO: moggi: looks like there is a bug around bHidden and bHideFormula
312 // They are normally for the whole pattern and not for a single cell
313 // we need to check already here for protected cells
314 const ScProtectionAttr* pProtAttr;
315 if ( bTabProtect && (pProtAttr = pInfo->pConditionSet->GetItemIfSet( ATTR_PROTECTION )) )
317 bHidden = pProtAttr->GetHideCell();
318 bHideFormula = pProtAttr->GetHideFormula();
322 // if style is not there, treat like no condition
325 if(aData.mxColorScale && !pInfo->mxColorScale)
327 pInfo->mxColorScale = aData.mxColorScale;
330 if(aData.pDataBar && !pInfo->pDataBar)
332 pInfo->pDataBar = aData.pDataBar.get();
333 pTableInfo->addDataBarInfo(std::move(aData.pDataBar));
336 if(aData.pIconSet && !pInfo->pIconSet)
338 pInfo->pIconSet = aData.pIconSet.get();
339 pTableInfo->addIconSetInfo(std::move(aData.pIconSet));
342 if (bAnyCondition && pInfo->mxColorScale && pInfo->pIconSet && pInfo->pDataBar)
343 break;
346 return bAnyCondition;
351 void ScDocument::FillInfo(
352 ScTableInfo& rTabInfo, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
353 SCTAB nTab, double fColScale, double fRowScale, bool bPageMode, bool bFormulaMode,
354 const ScMarkData* pMarkData )
356 OSL_ENSURE( maTabs[nTab], "Table does not exist" );
358 bool bLayoutRTL = IsLayoutRTL( nTab );
360 ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
361 ScStyleSheetPool* pStlPool = mxPoolHelper->GetStylePool();
363 RowInfo* pRowInfo = rTabInfo.mpRowInfo.get();
365 const SvxBrushItem* pDefBackground =
366 &pPool->GetUserOrPoolDefaultItem( ATTR_BACKGROUND );
367 const ScMergeAttr* pDefMerge =
368 &pPool->GetUserOrPoolDefaultItem( ATTR_MERGE );
369 const SvxShadowItem* pDefShadow =
370 &pPool->GetUserOrPoolDefaultItem( ATTR_SHADOW );
372 SCSIZE nArrRow;
373 SCSIZE nArrCount;
374 bool bAnyMerged = false;
375 bool bAnyShadow = false;
376 bool bAnyCondition = false;
377 bool bAnyPreview = false;
379 bool bTabProtect = IsTabProtected(nTab);
381 // first only the entries for the entire column
383 nArrRow=0;
384 SCROW nYExtra = nRow2+1;
385 initRowInfo(this, pRowInfo, rTabInfo.mnArrCapacity, fRowScale, nRow1,
386 nTab, nYExtra, nArrRow, nRow2);
387 nArrCount = nArrRow; // incl. Dummys
389 // Rotated text...
391 // Is Attribute really used in document?
392 bool bAnyItem = isRotateItemUsed(pPool);
394 SCCOL nRotMax = nCol2;
395 if ( bAnyItem && HasAttrib( 0, nRow1, nTab, MaxCol(), nRow2+1, nTab,
396 HasAttrFlags::Rotate | HasAttrFlags::Conditional ) )
398 //TODO: check Conditionals also for HasAttrFlags::Rotate ????
400 assert( nArrCount>2 && "nArrCount too small" );
401 FindMaxRotCol( nTab, &pRowInfo[1], nArrCount-1, nCol1, nCol2 );
402 // FindMaxRotCol sets nRotMaxCol
404 for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
405 if (pRowInfo[nArrRow].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nArrRow].nRotMaxCol > nRotMax)
406 nRotMax = pRowInfo[nArrRow].nRotMaxCol;
409 // Allocate cell information only after the test rotation
410 // to nRotMax due to nRotateDir Flag
411 initCellInfo(pRowInfo, nArrCount, nCol1, nRotMax, pDefShadow);
413 initColWidths(pRowInfo, this, fColScale, nTab, nCol2, nRotMax);
415 ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
416 if (pCondFormList)
417 pCondFormList->startRendering();
419 SCCOL nLastHiddenCheckedCol = -2;
420 bool bColHidden = false;
421 for (SCCOL nCol=-1; nCol<=nCol2+1; nCol++) // collect basic info also for all previous cols, and left & right + 1
423 if (ValidCol(nCol))
425 // #i58049#, #i57939# Hidden columns must be skipped here, or their attributes
426 // will disturb the output
428 if (nCol > nLastHiddenCheckedCol)
429 bColHidden = ColHidden(nCol, nTab, nullptr, &nLastHiddenCheckedCol);
430 // TODO: Optimize this loop.
431 if (!bColHidden)
433 sal_uInt16 nColWidth = GetColWidth( nCol, nTab, false ); // false=no need to check for hidden, checked above
434 sal_uInt16 nThisWidth = static_cast<sal_uInt16>(std::clamp(nColWidth * fColScale, 1.0, double(std::numeric_limits<sal_uInt16>::max())));
436 pRowInfo[0].basicCellInfo(nCol).nWidth = nThisWidth; //TODO: this should be enough
438 const ScAttrArray* pThisAttrArr; // Attribute
439 if (nCol < maTabs[nTab]->GetAllocatedColumnsCount())
441 ScColumn* pThisCol = &maTabs[nTab]->aCol[nCol]; // Column data
443 nArrRow = 1;
444 // Iterate between rows nY1 and nY2 and pick up non-empty
445 // cells that are not hidden.
446 RowInfoFiller aFunc(*this, nTab, pRowInfo, nCol, nArrRow, nCol1);
447 sc::ParseAllNonEmpty(pThisCol->maCells.begin(), pThisCol->maCells, nRow1, nRow2,
448 aFunc);
450 pThisAttrArr = pThisCol->pAttrArray.get();
452 else
453 pThisAttrArr = &maTabs[nTab]->aDefaultColData.AttrArray();
455 if (nCol+1 >= nCol1) // Attribute/Blockmark from nX1-1
457 nArrRow = 0;
459 SCROW nCurRow=nRow1; // single rows
460 if (nCurRow>0)
461 --nCurRow; // 1 more on top
462 else
463 nArrRow = 1;
465 SCROW nThisRow;
466 SCSIZE nIndex;
467 if ( pThisAttrArr->Count() )
468 (void) pThisAttrArr->Search( nCurRow, nIndex );
469 else
470 nIndex = 0;
474 const ScPatternAttr* pPattern = nullptr;
475 if ( pThisAttrArr->Count() )
477 nThisRow = pThisAttrArr->mvData[nIndex].nEndRow; // End of range
478 pPattern = pThisAttrArr->mvData[nIndex].getScPatternAttr();
480 else
482 nThisRow = MaxRow();
483 pPattern = &getCellAttributeHelper().getDefaultCellAttribute();
486 const SvxBrushItem* pBackground = &pPattern->GetItem(ATTR_BACKGROUND);
487 const SvxBoxItem* pLinesAttr = &pPattern->GetItem(ATTR_BORDER);
489 const SvxLineItem* pTLBRLine = &pPattern->GetItem( ATTR_BORDER_TLBR );
490 const SvxLineItem* pBLTRLine = &pPattern->GetItem( ATTR_BORDER_BLTR );
492 const SvxShadowItem* pShadowAttr = &pPattern->GetItem(ATTR_SHADOW);
493 if (!SfxPoolItem::areSame(pShadowAttr, pDefShadow))
494 bAnyShadow = true;
496 const ScMergeAttr* pMergeAttr = &pPattern->GetItem(ATTR_MERGE);
497 bool bMerged = !SfxPoolItem::areSame( pMergeAttr, pDefMerge );
498 ScMF nOverlap = pPattern->GetItemSet().
499 Get(ATTR_MERGE_FLAG).GetValue();
500 bool bHOverlapped(nOverlap & ScMF::Hor);
501 bool bVOverlapped(nOverlap & ScMF::Ver);
502 bool bAutoFilter(nOverlap & ScMF::Auto);
503 bool bPivotButton(nOverlap & ScMF::Button);
504 bool bScenario(nOverlap & ScMF::Scenario);
505 bool bPivotPopupButton(nOverlap & ScMF::ButtonPopup);
506 bool bFilterActive(nOverlap & ScMF::HiddenMember);
507 bool bPivotCollapseButton(nOverlap & ScMF::DpCollapse);
508 bool bPivotExpandButton(nOverlap & ScMF::DpExpand);
509 bool bPivotPopupButtonMulti(nOverlap & ScMF::ButtonPopup2);
510 if (bMerged||bHOverlapped||bVOverlapped)
511 bAnyMerged = true; // internal
513 bool bHidden, bHideFormula;
514 if (bTabProtect)
516 const ScProtectionAttr& rProtAttr = pPattern->GetItem(ATTR_PROTECTION);
517 bHidden = rProtAttr.GetHideCell();
518 bHideFormula = rProtAttr.GetHideFormula();
520 else
521 bHidden = bHideFormula = false;
523 const ScCondFormatIndexes& rCondFormats = pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
524 bool bContainsCondFormat = !rCondFormats.empty();
528 SCROW nLastHiddenRow = -1;
529 bool bRowHidden = RowHidden(nCurRow, nTab, nullptr, &nLastHiddenRow);
530 if ( nArrRow==0 || !bRowHidden )
532 if ( GetPreviewCellStyle( nCol, nCurRow, nTab ) != nullptr )
533 bAnyPreview = true;
534 RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
535 if (!SfxPoolItem::areSame(pBackground, pDefBackground)) // Column background == Default ?
536 pThisRowInfo->bEmptyBack = false;
537 if (bContainsCondFormat)
538 pThisRowInfo->bEmptyBack = false;
539 if (bAutoFilter)
540 pThisRowInfo->bAutoFilter = true;
541 if (bPivotButton || bPivotPopupButton || bPivotPopupButtonMulti)
542 pThisRowInfo->bPivotButton = true;
543 if (bPivotCollapseButton || bPivotExpandButton)
544 pThisRowInfo->bPivotToggle = true;
546 ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol);
547 ScBasicCellInfo* pBasicInfo = &pThisRowInfo->basicCellInfo(nCol);
548 pInfo->maBackground = SfxPoolItemHolder(*pPool, pBackground);
549 pInfo->pPatternAttr = pPattern;
550 pInfo->bMerged = bMerged;
551 pInfo->bHOverlapped = bHOverlapped;
552 pInfo->bVOverlapped = bVOverlapped;
553 pInfo->bAutoFilter = bAutoFilter;
554 pInfo->bPivotButton = bPivotButton;
555 pInfo->bPivotPopupButton = bPivotPopupButton;
556 pInfo->bPivotCollapseButton = bPivotCollapseButton;
557 pInfo->bPivotExpandButton = bPivotExpandButton;
558 pInfo->bPivotPopupButtonMulti = bPivotPopupButtonMulti;
559 pInfo->bFilterActive = bFilterActive;
560 pInfo->pLinesAttr = pLinesAttr;
561 pInfo->mpTLBRLine = pTLBRLine;
562 pInfo->mpBLTRLine = pBLTRLine;
563 pInfo->pShadowAttr = pShadowAttr;
564 // nWidth is no longer set individually
566 if (bScenario)
568 pInfo->maBackground = SfxPoolItemHolder(*pPool, ScGlobal::GetButtonBrushItem());
569 pThisRowInfo->bEmptyBack = false;
572 if (bContainsCondFormat && pCondFormList)
574 bAnyCondition |= handleConditionalFormat(*pCondFormList, rCondFormats,
575 pInfo, &rTabInfo, pStlPool, ScAddress(nCol, nCurRow, nTab),
576 bHidden, bHideFormula, bTabProtect);
579 if (bHidden || (bFormulaMode && bHideFormula && pInfo->maCell.getType() == CELLTYPE_FORMULA))
580 pBasicInfo->bEmptyCellText = true;
582 ++nArrRow;
584 else if (nLastHiddenRow >= 0)
586 nCurRow = nLastHiddenRow;
587 if (nCurRow > nThisRow)
588 nCurRow = nThisRow;
590 ++nCurRow;
592 while (nCurRow <= nThisRow && nCurRow <= nYExtra);
593 ++nIndex;
595 while ( nIndex < pThisAttrArr->Count() && nThisRow < nYExtra );
597 if (pMarkData && pMarkData->IsMultiMarked())
599 // Block marks
600 ScMarkArray aThisMarkArr(pMarkData->GetMarkArray( nCol ));
601 nArrRow = 1;
602 nCurRow = nRow1; // single rows
604 if ( aThisMarkArr.Search( nRow1, nIndex ) )
608 nThisRow=aThisMarkArr.mvData[nIndex].nRow; // End of range
612 if ( !RowHidden( nCurRow,nTab ) )
614 ++nArrRow;
616 ++nCurRow;
618 while (nCurRow <= nThisRow && nCurRow <= nRow2);
619 ++nIndex;
621 while ( nIndex < aThisMarkArr.mvData.size() && nThisRow < nRow2 );
625 else // columns in front
627 for (nArrRow=1; nArrRow+1<nArrCount; nArrRow++)
628 pRowInfo[nArrRow].basicCellInfo(nCol).nWidth = nThisWidth; //TODO: or check only 0 ??
632 else
633 pRowInfo[0].basicCellInfo(nCol).nWidth = STD_COL_WIDTH;
634 // STD_COL_WIDTH farthest to the left and right is needed for DrawExtraShadow
637 if (pCondFormList)
638 pCondFormList->endRendering();
640 // evaluate conditional formatting
641 std::vector< std::unique_ptr<ScPatternAttr> > aAltPatterns;
642 // favour preview over condition
643 if (bAnyCondition || bAnyPreview)
645 for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
647 for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++) // 1 more left and right
649 ScCellInfo* pInfo = &pRowInfo[nArrRow].cellInfo(nCol);
650 ScPatternAttr* pModifiedPatt = nullptr;
652 if ( ValidCol(nCol) && pRowInfo[nArrRow].nRowNo <= MaxRow() )
654 if ( ScStyleSheet* pPreviewStyle = GetPreviewCellStyle( nCol, pRowInfo[nArrRow].nRowNo, nTab ) )
656 aAltPatterns.push_back( std::make_unique<ScPatternAttr>( *pInfo->pPatternAttr ) );
657 pModifiedPatt = aAltPatterns.back().get();
658 pModifiedPatt->SetStyleSheet( pPreviewStyle );
661 // favour preview over condition
662 const SfxItemSet* pCondSet = pModifiedPatt ? &pModifiedPatt->GetItemSet() : pInfo->pConditionSet;
664 if (pCondSet)
666 // Background
667 if ( const SvxBrushItem* pItem = pCondSet->GetItemIfSet( ATTR_BACKGROUND ) )
669 pInfo->maBackground = SfxPoolItemHolder(*pPool, pItem);
670 pRowInfo[nArrRow].bEmptyBack = false;
673 // Border
674 if ( const SvxBoxItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER ) )
675 pInfo->pLinesAttr = pItem;
677 if ( const SvxLineItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER_TLBR ) )
678 pInfo->mpTLBRLine = pItem;
679 if ( const SvxLineItem* pItem = pCondSet->GetItemIfSet( ATTR_BORDER_BLTR ) )
680 pInfo->mpBLTRLine = pItem;
682 // Shadow
683 if ( const SvxShadowItem* pItem = pCondSet->GetItemIfSet( ATTR_SHADOW ) )
685 pInfo->pShadowAttr = pItem;
686 bAnyShadow = true;
689 if( bAnyCondition && pInfo->mxColorScale)
691 pRowInfo[nArrRow].bEmptyBack = false;
692 const SvxBrushItem aBrushItem(*pInfo->mxColorScale, ATTR_BACKGROUND);
693 pInfo->maBackground = SfxPoolItemHolder(*pPool, &aBrushItem);
699 // End conditional formatting
701 // Adjust data from merged cells
703 if (bAnyMerged)
705 for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
707 RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
708 SCROW nSignedY = nArrRow ? pThisRowInfo->nRowNo : nRow1-1;
710 for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++) // 1 more left and right
712 ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol);
714 if (pInfo->bMerged || pInfo->bHOverlapped || pInfo->bVOverlapped)
716 SCCOL nStartX;
717 SCROW nStartY;
718 SCCOL nEndX;
719 SCROW nEndY;
720 lcl_GetMergeRange( nCol,nSignedY, nArrRow, this,pRowInfo, nCol1,nRow1,nTab,
721 nStartX,nStartY, nEndX,nEndY );
722 const ScPatternAttr* pStartPattern = GetPattern( nStartX,nStartY,nTab );
723 const SfxItemSet* pStartCond = GetCondResult( nStartX,nStartY,nTab );
725 // Copy Background (or in output.cxx)
727 const SvxBrushItem* pBrushItem = nullptr;
728 if ( !pStartCond ||
729 !(pBrushItem = pStartCond->GetItemIfSet(ATTR_BACKGROUND)) )
730 pBrushItem = &pStartPattern->GetItem(ATTR_BACKGROUND);
731 pInfo->maBackground = SfxPoolItemHolder(*pPool, pBrushItem);
732 pRowInfo[nArrRow].bEmptyBack = false;
734 // Shadow
736 const SvxShadowItem* pShadowItem = nullptr;
737 if ( !pStartCond ||
738 !(pShadowItem = pStartCond->GetItemIfSet(ATTR_SHADOW)) )
739 pShadowItem = &pStartPattern->GetItem(ATTR_SHADOW);
740 pInfo->pShadowAttr = pShadowItem;
741 if (!SfxPoolItem::areSame(pInfo->pShadowAttr, pDefShadow))
742 bAnyShadow = true;
744 const ScCondFormatIndexes& rCondFormatIndex
745 = pStartPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
747 if (pCondFormList && !pStartCond && !rCondFormatIndex.empty())
749 for (const auto& rItem : rCondFormatIndex)
751 const ScConditionalFormat* pCondForm = pCondFormList->GetFormat(rItem);
752 if (pCondForm)
754 ScCondFormatData aData = pCondForm->GetData(
755 pInfo->maCell, ScAddress(nStartX, nStartY, nTab));
757 // Color scale
758 if (aData.mxColorScale && !pInfo->mxColorScale)
759 pInfo->mxColorScale = aData.mxColorScale;
768 if (bAnyShadow) // distribute Shadow
770 for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
772 bool bTop = ( nArrRow == 0 );
773 bool bBottom = ( nArrRow+1 == nArrCount );
775 for (SCCOL nCol=nCol1-1; nCol<=nCol2+1; nCol++) // 1 more left and right
777 bool bLeft = ( nCol == nCol1-1 );
778 bool bRight = ( nCol == nCol2+1 );
780 ScCellInfo* pInfo = &pRowInfo[nArrRow].cellInfo(nCol);
781 const SvxShadowItem* pThisAttr = pInfo->pShadowAttr;
782 SvxShadowLocation eLoc = pThisAttr ? pThisAttr->GetLocation() : SvxShadowLocation::NONE;
783 if (eLoc != SvxShadowLocation::NONE)
785 // or test on != eLoc
787 SCCOL nDxPos = 1;
788 SCCOL nDxNeg = -1;
790 while ( nCol+nDxPos < nCol2+1 && pRowInfo[0].basicCellInfo(nCol+nDxPos).nWidth == 0 )
791 ++nDxPos;
792 while ( nCol+nDxNeg > nCol1-1 && pRowInfo[0].basicCellInfo(nCol+nDxNeg).nWidth == 0 )
793 --nDxNeg;
795 bool bLeftDiff = !bLeft &&
796 pRowInfo[nArrRow].cellInfo(nCol+nDxNeg).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
797 bool bRightDiff = !bRight &&
798 pRowInfo[nArrRow].cellInfo(nCol+nDxPos).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
799 bool bTopDiff = !bTop &&
800 pRowInfo[nArrRow-1].cellInfo(nCol).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
801 bool bBottomDiff = !bBottom &&
802 pRowInfo[nArrRow+1].cellInfo(nCol).pShadowAttr->GetLocation() == SvxShadowLocation::NONE;
804 if ( bLayoutRTL )
806 switch (eLoc)
808 case SvxShadowLocation::BottomRight: eLoc = SvxShadowLocation::BottomLeft; break;
809 case SvxShadowLocation::BottomLeft: eLoc = SvxShadowLocation::BottomRight; break;
810 case SvxShadowLocation::TopRight: eLoc = SvxShadowLocation::TopLeft; break;
811 case SvxShadowLocation::TopLeft: eLoc = SvxShadowLocation::TopRight; break;
812 default:
814 // added to avoid warnings
819 switch (eLoc)
821 case SvxShadowLocation::BottomRight:
822 if (bBottomDiff)
824 pRowInfo[nArrRow+1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
825 pRowInfo[nArrRow+1].cellInfo(nCol).eHShadowPart =
826 bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
828 if (bRightDiff)
830 pRowInfo[nArrRow].cellInfo(nCol+1).pVShadowOrigin = pThisAttr;
831 pRowInfo[nArrRow].cellInfo(nCol+1).eVShadowPart =
832 bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
834 if (bBottomDiff && bRightDiff)
836 pRowInfo[nArrRow+1].cellInfo(nCol+1).pHShadowOrigin = pThisAttr;
837 pRowInfo[nArrRow+1].cellInfo(nCol+1).eHShadowPart = SC_SHADOW_CORNER;
839 break;
841 case SvxShadowLocation::BottomLeft:
842 if (bBottomDiff)
844 pRowInfo[nArrRow+1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
845 pRowInfo[nArrRow+1].cellInfo(nCol).eHShadowPart =
846 bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
848 if (bLeftDiff)
850 pRowInfo[nArrRow].cellInfo(nCol-1).pVShadowOrigin = pThisAttr;
851 pRowInfo[nArrRow].cellInfo(nCol-1).eVShadowPart =
852 bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
854 if (bBottomDiff && bLeftDiff)
856 pRowInfo[nArrRow+1].cellInfo(nCol-1).pHShadowOrigin = pThisAttr;
857 pRowInfo[nArrRow+1].cellInfo(nCol-1).eHShadowPart = SC_SHADOW_CORNER;
859 break;
861 case SvxShadowLocation::TopRight:
862 if (bTopDiff)
864 pRowInfo[nArrRow-1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
865 pRowInfo[nArrRow-1].cellInfo(nCol).eHShadowPart =
866 bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
868 if (bRightDiff)
870 pRowInfo[nArrRow].cellInfo(nCol+1).pVShadowOrigin = pThisAttr;
871 pRowInfo[nArrRow].cellInfo(nCol+1).eVShadowPart =
872 bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
874 if (bTopDiff && bRightDiff)
876 pRowInfo[nArrRow-1].cellInfo(nCol+1).pHShadowOrigin = pThisAttr;
877 pRowInfo[nArrRow-1].cellInfo(nCol+1).eHShadowPart = SC_SHADOW_CORNER;
879 break;
881 case SvxShadowLocation::TopLeft:
882 if (bTopDiff)
884 pRowInfo[nArrRow-1].cellInfo(nCol).pHShadowOrigin = pThisAttr;
885 pRowInfo[nArrRow-1].cellInfo(nCol).eHShadowPart =
886 bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
888 if (bLeftDiff)
890 pRowInfo[nArrRow].cellInfo(nCol-1).pVShadowOrigin = pThisAttr;
891 pRowInfo[nArrRow].cellInfo(nCol-1).eVShadowPart =
892 bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
894 if (bTopDiff && bLeftDiff)
896 pRowInfo[nArrRow-1].cellInfo(nCol-1).pHShadowOrigin = pThisAttr;
897 pRowInfo[nArrRow-1].cellInfo(nCol-1).eHShadowPart = SC_SHADOW_CORNER;
899 break;
901 default:
902 OSL_FAIL("wrong Shadow-Enum");
909 rTabInfo.mnArrCount = sal::static_int_cast<sal_uInt16>(nArrCount);
910 rTabInfo.mbPageMode = bPageMode;
912 // *** create the frame border array ***
914 // RowInfo structs are filled in the range [ 0 , nArrCount-1 ],
915 // each RowInfo contains ScCellInfo structs in the range [ nCol1-1 , nCol2+1 ]
916 // and ScBasicCellInfo structs in the range [ -1, nCol2+1 ]
918 size_t nColCount = nCol2 - nCol1 + 1 + 2;
919 size_t nRowCount = nArrCount;
921 svx::frame::Array& rArray = rTabInfo.maArray;
922 rArray.Initialize( nColCount, nRowCount );
924 for( size_t nRow = 0; nRow < nRowCount; ++nRow )
926 sal_uInt16 nCellInfoY = static_cast< sal_uInt16 >( nRow );
927 RowInfo& rThisRowInfo = pRowInfo[ nCellInfoY ];
929 for( SCCOL nCol = nCol1 - 1; nCol <= nCol2 + 1; ++nCol ) // 1 more left and right
931 const ScCellInfo& rInfo = rThisRowInfo.cellInfo( nCol );
932 const SvxBoxItem* pBox = rInfo.pLinesAttr;
933 const SvxLineItem* pTLBR = rInfo.mpTLBRLine;
934 const SvxLineItem* pBLTR = rInfo.mpBLTRLine;
936 size_t colToIndex = -(nCol1 - 1);
937 // These are rArray indexes (0-based), not really rows/columns.
938 size_t nX = nCol + colToIndex;
939 size_t nFirstCol = nX;
940 size_t nFirstRow = nRow;
942 // *** merged cells *** -------------------------------------------
944 if( !rArray.IsMerged( nX, nRow ) && (rInfo.bMerged || rInfo.bHOverlapped || rInfo.bVOverlapped) )
946 // *** insert merged range in svx::frame::Array ***
948 /* #i69369# top-left cell of a merged range may be located in
949 a hidden column or row. Use lcl_GetMergeRange() to find the
950 complete merged range, then calculate dimensions and
951 document position of the visible range. */
953 // note: document rows must be looked up in RowInfo structs
955 // current column and row in document coordinates
956 SCCOL nCurrDocCol = nCol;
957 SCROW nCurrDocRow = static_cast< SCROW >( (nCellInfoY > 0) ? rThisRowInfo.nRowNo : (nRow1 - 1) );
959 // find entire merged range in document, returns signed document coordinates
960 SCCOL nFirstRealDocColS, nLastRealDocColS;
961 SCROW nFirstRealDocRowS, nLastRealDocRowS;
962 lcl_GetMergeRange( nCurrDocCol, nCurrDocRow,
963 nCellInfoY, this, pRowInfo, nCol1,nRow1,nTab,
964 nFirstRealDocColS, nFirstRealDocRowS, nLastRealDocColS, nLastRealDocRowS );
966 // *complete* merged range in document coordinates
967 SCCOL nFirstRealDocCol = nFirstRealDocColS;
968 SCROW nFirstRealDocRow = nFirstRealDocRowS;
969 SCCOL nLastRealDocCol = nLastRealDocColS;
970 SCROW nLastRealDocRow = nLastRealDocRowS;
972 // first visible column (nCol1-1 is first processed document column)
973 SCCOL nFirstDocCol = (nCol1 > 0) ? ::std::max< SCCOL >( nFirstRealDocCol, nCol1 - 1 ) : nFirstRealDocCol;
974 nFirstCol = nFirstDocCol + colToIndex;
976 // last visible column (nCol2+1 is last processed document column)
977 SCCOL nLastDocCol = (nCol2 < MaxCol()) ? ::std::min< SCCOL >( nLastRealDocCol, nCol2 + 1 ) : nLastRealDocCol;
978 size_t nLastCol = nLastDocCol + colToIndex;
980 // first visible row
981 sal_uInt16 nFirstCellInfoY = nCellInfoY;
982 while( ((nFirstCellInfoY > 1) && (pRowInfo[ nFirstCellInfoY - 1 ].nRowNo >= nFirstRealDocRow)) ||
983 ((nFirstCellInfoY == 1) && (static_cast< SCROW >( nRow1 - 1 ) >= nFirstRealDocRow)) )
984 --nFirstCellInfoY;
985 SCROW nFirstDocRow = (nFirstCellInfoY > 0) ? pRowInfo[ nFirstCellInfoY ].nRowNo : static_cast< SCROW >( nRow1 - 1 );
986 nFirstRow = static_cast< size_t >( nFirstCellInfoY );
988 // last visible row
989 sal_uInt16 nLastCellInfoY = nCellInfoY;
990 while( (sal::static_int_cast<SCSIZE>(nLastCellInfoY + 1) < nArrCount) &&
991 (pRowInfo[ nLastCellInfoY + 1 ].nRowNo <= nLastRealDocRow) )
992 ++nLastCellInfoY;
993 SCROW nLastDocRow = (nLastCellInfoY > 0) ? pRowInfo[ nLastCellInfoY ].nRowNo : static_cast< SCROW >( nRow1 - 1 );
994 size_t nLastRow = static_cast< size_t >( nLastCellInfoY );
996 // insert merged range
997 rArray.SetMergedRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
999 // *** find additional size not included in svx::frame::Array ***
1001 // additional space before first column
1002 if( nFirstCol == 0 )
1004 tools::Long nSize = 0;
1005 for( SCCOL nDocCol = nFirstRealDocCol; nDocCol < nFirstDocCol; ++nDocCol )
1006 nSize += std::max( tools::Long(GetColWidth( nDocCol, nTab ) * fColScale), tools::Long(1) );
1007 rArray.SetAddMergedLeftSize( nX, nRow, nSize );
1009 // additional space after last column
1010 if( nLastCol + 1 == nColCount )
1012 tools::Long nSize = 0;
1013 for( SCCOL nDocCol = nLastDocCol + 1; nDocCol <= nLastRealDocCol; ++nDocCol )
1014 nSize += std::max( tools::Long(GetColWidth( nDocCol, nTab ) * fColScale), tools::Long(1) );
1015 rArray.SetAddMergedRightSize( nX, nRow, nSize );
1017 // additional space above first row
1018 if( nFirstRow == 0 )
1020 tools::Long nSize = 0;
1021 for( SCROW nDocRow = nFirstRealDocRow; nDocRow < nFirstDocRow; ++nDocRow )
1022 nSize += std::max( tools::Long(GetRowHeight( nDocRow, nTab ) * fRowScale), tools::Long(1) );
1023 rArray.SetAddMergedTopSize( nX, nRow, nSize );
1025 // additional space beyond last row
1026 if( nLastRow + 1 == nRowCount )
1028 tools::Long nSize = 0;
1029 for( SCROW nDocRow = nLastDocRow + 1; nDocRow <= nLastRealDocRow; ++nDocRow )
1030 nSize += std::max( tools::Long(GetRowHeight( nDocRow, nTab ) * fRowScale), tools::Long(1) );
1031 rArray.SetAddMergedBottomSize( nX, nRow, nSize );
1034 // *** use line attributes from real origin cell ***
1036 if( (nFirstRealDocCol != nCurrDocCol) || (nFirstRealDocRow != nCurrDocRow) )
1038 if( const ScPatternAttr* pPattern = GetPattern( nFirstRealDocCol, nFirstRealDocRow, nTab ) )
1040 const SfxItemSet* pCond = GetCondResult( nFirstRealDocCol, nFirstRealDocRow, nTab );
1041 pBox = &pPattern->GetItem( ATTR_BORDER, pCond );
1042 pTLBR = &pPattern->GetItem( ATTR_BORDER_TLBR, pCond );
1043 pBLTR = &pPattern->GetItem( ATTR_BORDER_BLTR, pCond );
1045 else
1047 pBox = nullptr;
1048 pTLBR = pBLTR = nullptr;
1053 // *** borders *** ------------------------------------------------
1055 if( pBox )
1057 rArray.SetCellStyleLeft( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetLeft(), fColScale ) );
1058 rArray.SetCellStyleRight( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetRight(), fColScale ) );
1059 rArray.SetCellStyleTop( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetTop(), fRowScale ) );
1060 rArray.SetCellStyleBottom( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetBottom(), fRowScale ) );
1063 if( pTLBR )
1064 rArray.SetCellStyleTLBR( nFirstCol, nFirstRow, svx::frame::Style( pTLBR->GetLine(), fRowScale ) );
1065 if( pBLTR )
1066 rArray.SetCellStyleBLTR( nFirstCol, nFirstRow, svx::frame::Style( pBLTR->GetLine(), fRowScale ) );
1070 /* Mirror the entire frame array. */
1071 if( bLayoutRTL )
1072 rArray.MirrorSelfX();
1075 /// We seem to need to allocate three extra rows here, not sure why
1077 ScTableInfo::ScTableInfo(SCROW nStartRow, SCROW nEndRow, bool bHintOnly)
1078 : mnArrCount(0)
1079 , mnArrCapacity(nEndRow - nStartRow + 4)
1080 , mbPageMode(false)
1082 assert(nStartRow >= 0);
1083 assert(nEndRow >= nStartRow);
1084 if (bHintOnly && mnArrCapacity > 1024)
1086 SAL_INFO("sc.core", "ScTableInfo excessive capacity: " << mnArrCapacity << " start: " << nStartRow << " end: " << nEndRow);
1087 mnArrCapacity = 1024;
1089 mpRowInfo.reset(new RowInfo[mnArrCapacity] {});
1092 ScTableInfo::~ScTableInfo()
1094 for( SCSIZE nIdx = 0; nIdx < mnArrCapacity; ++nIdx )
1095 mpRowInfo[ nIdx ].freeCellInfo();
1098 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */