1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
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
);
60 bool bHOver
= pInfo
->bHOverlapped
;
61 bool bVOver
= pInfo
->bVOverlapped
;
65 while (bHOver
) // nY constant
68 if (rStartX
>= nX1
&& !pDoc
->ColHidden(rStartX
, nTab
, nullptr, &nLastCol
))
70 bHOver
= pRowInfo
[nArrY
].cellInfo(rStartX
).bHOverlapped
;
71 bVOver
= pRowInfo
[nArrY
].cellInfo(rStartX
).bVOverlapped
;
75 ScMF nOverlap
= pDoc
->GetAttr( rStartX
, rStartY
, nTab
, ATTR_MERGE_FLAG
)->GetValue();
76 bHOver
= bool(nOverlap
& ScMF::Hor
);
77 bVOver
= bool(nOverlap
& ScMF::Ver
);
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
;
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
->
113 pMerge
= pDoc
->GetAttr(rStartX
,rStartY
,nTab
,ATTR_MERGE
);
115 rEndX
= rStartX
+ pMerge
->GetColMerge() - 1;
116 rEndY
= rStartY
+ pMerge
->GetRowMerge() - 1;
129 SCROW mnHiddenEndRow
;
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
);
140 void alignArray(size_t nRow
)
142 while (mpRowInfo
[mnArrY
].nRowNo
< static_cast<SCROW
>(nRow
))
146 void setInfo(size_t nRow
, const ScRefCellValue
& rCell
)
150 RowInfo
& rThisRowInfo
= mpRowInfo
[mnArrY
];
151 if(mnCol
>= mnStartCol
-1)
152 rThisRowInfo
.cellInfo(mnCol
).maCell
= rCell
;
153 rThisRowInfo
.basicCellInfo(mnCol
).bEmptyCellText
= false;
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
)
165 setInfo(nRow
, ScRefCellValue(fVal
));
168 void operator() (size_t nRow
, const svl::SharedString
& rStr
)
171 setInfo(nRow
, ScRefCellValue(&rStr
));
174 void operator() (size_t nRow
, const EditTextObject
* p
)
177 setInfo(nRow
, ScRefCellValue(p
));
180 void operator() (size_t nRow
, const ScFormulaCell
* p
)
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
++)
205 nY
= pDoc
->MaxRow()+1; // invalid
207 if (nY
> nDocHeightEndRow
)
209 if (pDoc
->ValidRow(nY
))
210 nDocHeight
= pDoc
->GetRowHeight( nY
, nTab
, nullptr, &nDocHeightEndRow
);
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
>(
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
;
234 if (rArrRow
>= nMaxRow
)
236 OSL_FAIL("FillInfo: Range too big" );
237 rYExtra
= nSignedY
; // End
238 rRow2
= rYExtra
- 1; // Adjust range
242 if (nSignedY
== rYExtra
) // hidden additional line?
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
);
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
);
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
);
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
)
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
);
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
384 SCROW nYExtra
= nRow2
+1;
385 initRowInfo(this, pRowInfo
, rTabInfo
.mnArrCapacity
, fRowScale
, nRow1
,
386 nTab
, nYExtra
, nArrRow
, nRow2
);
387 nArrCount
= nArrRow
; // incl. Dummys
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
);
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
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.
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
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
,
450 pThisAttrArr
= pThisCol
->pAttrArray
.get();
453 pThisAttrArr
= &maTabs
[nTab
]->aDefaultColData
.AttrArray();
455 if (nCol
+1 >= nCol1
) // Attribute/Blockmark from nX1-1
459 SCROW nCurRow
=nRow1
; // single rows
461 --nCurRow
; // 1 more on top
467 if ( pThisAttrArr
->Count() )
468 (void) pThisAttrArr
->Search( nCurRow
, nIndex
);
474 const ScPatternAttr
* pPattern
= nullptr;
475 if ( pThisAttrArr
->Count() )
477 nThisRow
= pThisAttrArr
->mvData
[nIndex
].nEndRow
; // End of range
478 pPattern
= pThisAttrArr
->mvData
[nIndex
].getScPatternAttr();
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
))
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
;
516 const ScProtectionAttr
& rProtAttr
= pPattern
->GetItem(ATTR_PROTECTION
);
517 bHidden
= rProtAttr
.GetHideCell();
518 bHideFormula
= rProtAttr
.GetHideFormula();
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 )
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;
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
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;
584 else if (nLastHiddenRow
>= 0)
586 nCurRow
= nLastHiddenRow
;
587 if (nCurRow
> nThisRow
)
592 while (nCurRow
<= nThisRow
&& nCurRow
<= nYExtra
);
595 while ( nIndex
< pThisAttrArr
->Count() && nThisRow
< nYExtra
);
597 if (pMarkData
&& pMarkData
->IsMultiMarked())
600 ScMarkArray
aThisMarkArr(pMarkData
->GetMarkArray( nCol
));
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
) )
618 while (nCurRow
<= nThisRow
&& nCurRow
<= nRow2
);
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 ??
633 pRowInfo
[0].basicCellInfo(nCol
).nWidth
= STD_COL_WIDTH
;
634 // STD_COL_WIDTH farthest to the left and right is needed for DrawExtraShadow
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
;
667 if ( const SvxBrushItem
* pItem
= pCondSet
->GetItemIfSet( ATTR_BACKGROUND
) )
669 pInfo
->maBackground
= SfxPoolItemHolder(*pPool
, pItem
);
670 pRowInfo
[nArrRow
].bEmptyBack
= false;
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
;
683 if ( const SvxShadowItem
* pItem
= pCondSet
->GetItemIfSet( ATTR_SHADOW
) )
685 pInfo
->pShadowAttr
= pItem
;
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
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
)
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;
729 !(pBrushItem
= pStartCond
->GetItemIfSet(ATTR_BACKGROUND
)) )
730 pBrushItem
= &pStartPattern
->GetItem(ATTR_BACKGROUND
);
731 pInfo
->maBackground
= SfxPoolItemHolder(*pPool
, pBrushItem
);
732 pRowInfo
[nArrRow
].bEmptyBack
= false;
736 const SvxShadowItem
* pShadowItem
= nullptr;
738 !(pShadowItem
= pStartCond
->GetItemIfSet(ATTR_SHADOW
)) )
739 pShadowItem
= &pStartPattern
->GetItem(ATTR_SHADOW
);
740 pInfo
->pShadowAttr
= pShadowItem
;
741 if (!SfxPoolItem::areSame(pInfo
->pShadowAttr
, pDefShadow
))
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
);
754 ScCondFormatData aData
= pCondForm
->GetData(
755 pInfo
->maCell
, ScAddress(nStartX
, nStartY
, nTab
));
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
790 while ( nCol
+nDxPos
< nCol2
+1 && pRowInfo
[0].basicCellInfo(nCol
+nDxPos
).nWidth
== 0 )
792 while ( nCol
+nDxNeg
> nCol1
-1 && pRowInfo
[0].basicCellInfo(nCol
+nDxNeg
).nWidth
== 0 )
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
;
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;
814 // added to avoid warnings
821 case SvxShadowLocation::BottomRight
:
824 pRowInfo
[nArrRow
+1].cellInfo(nCol
).pHShadowOrigin
= pThisAttr
;
825 pRowInfo
[nArrRow
+1].cellInfo(nCol
).eHShadowPart
=
826 bLeftDiff
? SC_SHADOW_HSTART
: SC_SHADOW_HORIZ
;
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
;
841 case SvxShadowLocation::BottomLeft
:
844 pRowInfo
[nArrRow
+1].cellInfo(nCol
).pHShadowOrigin
= pThisAttr
;
845 pRowInfo
[nArrRow
+1].cellInfo(nCol
).eHShadowPart
=
846 bRightDiff
? SC_SHADOW_HSTART
: SC_SHADOW_HORIZ
;
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
;
861 case SvxShadowLocation::TopRight
:
864 pRowInfo
[nArrRow
-1].cellInfo(nCol
).pHShadowOrigin
= pThisAttr
;
865 pRowInfo
[nArrRow
-1].cellInfo(nCol
).eHShadowPart
=
866 bLeftDiff
? SC_SHADOW_HSTART
: SC_SHADOW_HORIZ
;
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
;
881 case SvxShadowLocation::TopLeft
:
884 pRowInfo
[nArrRow
-1].cellInfo(nCol
).pHShadowOrigin
= pThisAttr
;
885 pRowInfo
[nArrRow
-1].cellInfo(nCol
).eHShadowPart
=
886 bRightDiff
? SC_SHADOW_HSTART
: SC_SHADOW_HORIZ
;
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
;
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
;
981 sal_uInt16 nFirstCellInfoY
= nCellInfoY
;
982 while( ((nFirstCellInfoY
> 1) && (pRowInfo
[ nFirstCellInfoY
- 1 ].nRowNo
>= nFirstRealDocRow
)) ||
983 ((nFirstCellInfoY
== 1) && (static_cast< SCROW
>( nRow1
- 1 ) >= nFirstRealDocRow
)) )
985 SCROW nFirstDocRow
= (nFirstCellInfoY
> 0) ? pRowInfo
[ nFirstCellInfoY
].nRowNo
: static_cast< SCROW
>( nRow1
- 1 );
986 nFirstRow
= static_cast< size_t >( nFirstCellInfoY
);
989 sal_uInt16 nLastCellInfoY
= nCellInfoY
;
990 while( (sal::static_int_cast
<SCSIZE
>(nLastCellInfoY
+ 1) < nArrCount
) &&
991 (pRowInfo
[ nLastCellInfoY
+ 1 ].nRowNo
<= nLastRealDocRow
) )
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
);
1048 pTLBR
= pBLTR
= nullptr;
1053 // *** borders *** ------------------------------------------------
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
) );
1064 rArray
.SetCellStyleTLBR( nFirstCol
, nFirstRow
, svx::frame::Style( pTLBR
->GetLine(), fRowScale
) );
1066 rArray
.SetCellStyleBLTR( nFirstCol
, nFirstRow
, svx::frame::Style( pBLTR
->GetLine(), fRowScale
) );
1070 /* Mirror the entire frame array. */
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
)
1079 , mnArrCapacity(nEndRow
- nStartRow
+ 4)
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: */