tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / data / table5.cxx
blob16ac890b7c5daf712ba6e1ecfd131fbb22b5c3c2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scitems.hxx>
21 #include <attrib.hxx>
22 #include <formulacell.hxx>
23 #include <table.hxx>
24 #include <column.hxx>
25 #include <document.hxx>
26 #include <drwlayer.hxx>
27 #include <global.hxx>
28 #include <stlpool.hxx>
29 #include <tabprotection.hxx>
30 #include <globstr.hrc>
31 #include <scresid.hxx>
32 #include <segmenttree.hxx>
33 #include <columniterator.hxx>
34 #include <globalnames.hxx>
35 #include <scmod.hxx>
36 #include <printopt.hxx>
37 #include <bcaslot.hxx>
38 #include <compressedarray.hxx>
39 #include <userdat.hxx>
40 #include <conditio.hxx>
41 #include <colorscale.hxx>
42 #include <cellform.hxx>
44 #include <com/sun/star/sheet/TablePageBreakData.hpp>
46 #include <editeng/brushitem.hxx>
47 #include <editeng/colritem.hxx>
48 #include <osl/diagnose.h>
49 #include <svl/numformat.hxx>
51 #include <algorithm>
52 #include <limits>
54 using ::com::sun::star::uno::Sequence;
55 using ::com::sun::star::sheet::TablePageBreakData;
56 using ::std::set;
58 void ScTable::UpdatePageBreaks(const ScRange* pUserArea)
60 if (rDocument.IsImportingXML())
61 return;
63 // pUserArea != NULL -> print area is specified. We need to force-update
64 // the page breaks.
66 if (!pUserArea)
68 if (!bPageSizeValid)
69 return;
71 // Always update breaks if force breaks option has changed
72 if (mbPageBreaksValid
73 && mbForceBreaks == ScModule::get()->GetPrintOptions().GetForceBreaks())
74 return;
77 SfxStyleSheetBase* pStyle
78 = rDocument.GetStyleSheetPool()->Find(aPageStyle, SfxStyleFamily::Page);
79 if (!pStyle)
81 OSL_FAIL("UpdatePageBreaks: Style not found");
82 return;
84 SfxItemSet* pStyleSet = &pStyle->GetItemSet();
86 SCCOL nStartCol = 0;
87 SCROW nStartRow = 0;
88 SCCOL nEndCol = rDocument.MaxCol();
89 SCROW nEndRow = rDocument.MaxRow();
90 if (pUserArea)
92 nStartCol = pUserArea->aStart.Col();
93 nStartRow = pUserArea->aStart.Row();
94 nEndCol = pUserArea->aEnd.Col();
95 nEndRow = pUserArea->aEnd.Row();
97 else
99 sal_uInt16 nAreaCount = GetPrintRangeCount();
100 if (nAreaCount > 1)
102 // Show nothing, when multiple ranges
104 for (SCCOL nX : GetColumnsRange(0, rDocument.MaxCol()))
105 RemoveColBreak(nX, true, false);
107 RemoveRowPageBreaks(0, rDocument.MaxRow() - 1);
109 return;
111 else if (nAreaCount == 1)
113 const ScRange* pArea = GetPrintRange(0);
114 if (pArea)
116 nStartCol = pArea->aStart.Col();
117 nStartRow = pArea->aStart.Row();
118 nEndCol = pArea->aEnd.Col();
119 nEndRow = pArea->aEnd.Row();
121 } // otherwise show everything
124 // get bSkipColBreaks/bSkipRowBreaks flags:
125 // fdo#40788 - print range scale settings can cause manual breaks to be
126 // ignored (see below). This behaviour may now be set by the user.
127 mbForceBreaks = ScModule::get()->GetPrintOptions().GetForceBreaks();
128 bool bSkipColBreaks = false;
129 bool bSkipRowBreaks = false;
131 if (!mbForceBreaks)
133 if (const SfxUInt16Item* pItem = pStyleSet->GetItemIfSet(ATTR_PAGE_SCALETOPAGES, false))
135 bSkipColBreaks = bSkipRowBreaks = pItem->GetValue() > 0;
138 const ScPageScaleToItem* pScaleToItem;
139 if (!bSkipColBreaks && (pScaleToItem = pStyleSet->GetItemIfSet(ATTR_PAGE_SCALETO, false)))
141 // #i54993# when fitting to width or height, ignore only manual breaks in that direction
142 if (pScaleToItem->GetWidth() > 0)
143 bSkipColBreaks = true;
144 if (pScaleToItem->GetHeight() > 0)
145 bSkipRowBreaks = true;
149 tools::Long nPageSizeX = aPageSizeTwips.Width();
150 tools::Long nPageSizeY = aPageSizeTwips.Height();
152 // Beginning: Remove breaks
154 for (SCCOL nX : GetColumnsRange(0, nStartCol - 1))
155 RemoveColBreak(nX, true, false);
156 RemoveRowPageBreaks(0, nStartRow - 1);
158 if (nStartCol > 0)
159 SetColBreak(nStartCol, true, false); // AREABREAK
160 if (nStartRow > 0)
161 SetRowBreak(nStartRow, true, false); // AREABREAK
163 // Middle part: Distribute breaks
165 bool bRepeatCol = (nRepeatStartX != SCCOL_REPEAT_NONE);
166 bool bColFound = false;
167 tools::Long nSizeX = 0;
168 for (SCCOL nX = nStartCol; nX <= nEndCol; nX++)
170 bool bStartOfPage = false;
171 tools::Long nThisX = ColHidden(nX) ? 0 : mpColWidth->GetValue(nX);
172 bool bManualBreak = HasColManualBreak(nX);
173 if ((nSizeX + nThisX > nPageSizeX) || (bManualBreak && !bSkipColBreaks))
175 SetColBreak(nX, true, false);
176 nSizeX = 0;
177 bStartOfPage = true;
179 else if (nX != nStartCol)
180 RemoveColBreak(nX, true, false);
181 else
182 bStartOfPage = true;
184 if (bStartOfPage && bRepeatCol && nX > nRepeatStartX && !bColFound)
186 // subtract size of repeat columns from page size
187 for (SCCOL i = nRepeatStartX; i <= nRepeatEndX; i++)
188 nPageSizeX -= ColHidden(i) ? 0 : mpColWidth->GetValue(i);
189 while (nX <= nRepeatEndX)
190 RemoveColBreak(++nX, true, false);
191 bColFound = true;
194 nSizeX += nThisX;
197 // Remove all page breaks in range.
198 RemoveRowPageBreaks(nStartRow + 1, nEndRow);
200 // And set new page breaks.
201 bool bRepeatRow = (nRepeatStartY != SCROW_REPEAT_NONE);
202 bool bRowFound = false;
203 tools::Long nSizeY = 0;
204 ScFlatBoolRowSegments::ForwardIterator aIterHidden(*mpHiddenRows);
205 ScFlatUInt16RowSegments::ForwardIterator aIterHeights(*mpRowHeights);
206 SCROW nNextManualBreak = GetNextManualBreak(nStartRow); // -1 => no more manual breaks
207 for (SCROW nY = nStartRow; nY <= nEndRow; ++nY)
209 bool bStartOfPage = false;
210 bool bThisRowHidden = false;
211 const bool bHasValue = aIterHidden.getValue(nY, bThisRowHidden);
212 assert(bHasValue);
213 (void)bHasValue;
214 tools::Long nThisY = 0;
215 if (!bThisRowHidden)
217 sal_uInt16 nTmp;
218 const bool bHasHeight = aIterHeights.getValue(nY, nTmp);
219 assert(bHasHeight);
220 if (bHasHeight)
221 nThisY = static_cast<tools::Long>(nTmp);
224 bool bManualBreak = false;
225 if (nNextManualBreak >= 0)
227 bManualBreak = (nY == nNextManualBreak);
228 if (nY >= nNextManualBreak)
229 // Query the next manual break position.
230 nNextManualBreak = GetNextManualBreak(nY + 1);
233 if ((nSizeY + nThisY > nPageSizeY) || (bManualBreak && !bSkipRowBreaks))
235 SetRowBreak(nY, true, false);
236 nSizeY = 0;
237 bStartOfPage = true;
239 else if (nY != nStartRow)
240 ; // page break already removed
241 else
242 bStartOfPage = true;
244 if (bStartOfPage && bRepeatRow && nY > nRepeatStartY && !bRowFound)
246 // subtract size of repeat rows from page size
247 tools::Long nHeights = GetTotalRowHeight(nRepeatStartY, nRepeatEndY);
248 #if OSL_DEBUG_LEVEL > 0
249 if (nHeights == ::std::numeric_limits<tools::Long>::max())
250 OSL_FAIL("ScTable::UpdatePageBreaks: row heights overflow");
251 #endif
252 nPageSizeY -= nHeights;
253 if (nY <= nRepeatEndY)
254 RemoveRowPageBreaks(nY, nRepeatEndY);
255 bRowFound = true;
258 if (bThisRowHidden)
260 // Hidden row range. Skip them unless there is a manual break.
261 SCROW nLastCommon = aIterHidden.getLastPos();
262 if (nNextManualBreak >= 0)
263 nLastCommon = ::std::min(nLastCommon, nNextManualBreak - 1);
264 nY = nLastCommon;
266 else
268 // Visible row range.
270 SCROW nLastHidden = aIterHidden.getLastPos();
271 SCROW nLastHeight = aIterHeights.getLastPos();
272 SCROW nLastCommon = ::std::min(nLastHidden, nLastHeight);
273 if (nNextManualBreak >= 0)
274 nLastCommon = ::std::min(nLastCommon, nNextManualBreak - 1);
276 if (nLastCommon > nY)
278 tools::Long nMaxMultiple = static_cast<tools::Long>(nLastCommon - nY);
279 tools::Long nMultiple = (nPageSizeY - nSizeY) / nThisY;
280 if (nMultiple > nMaxMultiple)
281 nMultiple = nMaxMultiple;
282 if (nMultiple > 1)
284 nSizeY += nThisY * (nMultiple - 1);
285 nY += nMultiple - 1;
290 nSizeY += nThisY;
293 // End: Remove Break
295 if (nEndCol < rDocument.MaxCol())
297 SetColBreak(nEndCol + 1, true, false); // AREABREAK
298 for (SCCOL nCol : GetColumnsRange(nEndCol + 2, rDocument.MaxCol()))
299 RemoveColBreak(nCol, true, false);
301 if (nEndRow < rDocument.MaxRow())
303 SetRowBreak(nEndRow + 1, true, false); // AREABREAK
304 if (nEndRow + 2 <= rDocument.MaxRow())
305 RemoveRowPageBreaks(nEndRow + 2, rDocument.MaxRow());
307 mbPageBreaksValid
308 = !pUserArea; // #i116881# the valid flag can only apply to the "no user area" case
311 void ScTable::RemoveManualBreaks()
313 maRowManualBreaks.clear();
314 maColManualBreaks.clear();
315 InvalidatePageBreaks();
317 SetStreamValid(false);
320 bool ScTable::HasManualBreaks() const
322 return !maRowManualBreaks.empty() || !maColManualBreaks.empty();
325 void ScTable::SetRowManualBreaks(::std::set<SCROW>&& rBreaks)
327 maRowManualBreaks = std::move(rBreaks);
328 InvalidatePageBreaks();
329 SetStreamValid(false);
332 void ScTable::SetColManualBreaks(::std::set<SCCOL>&& rBreaks)
334 maColManualBreaks = std::move(rBreaks);
335 InvalidatePageBreaks();
336 SetStreamValid(false);
339 void ScTable::GetAllRowBreaks(set<SCROW>& rBreaks, bool bPage, bool bManual) const
341 if (bPage)
342 rBreaks = maRowPageBreaks;
344 if (bManual)
346 copy(maRowManualBreaks.begin(), maRowManualBreaks.end(),
347 inserter(rBreaks, rBreaks.begin()));
351 void ScTable::GetAllColBreaks(set<SCCOL>& rBreaks, bool bPage, bool bManual) const
353 if (bPage)
354 rBreaks = maColPageBreaks;
356 if (bManual)
358 copy(maColManualBreaks.begin(), maColManualBreaks.end(),
359 inserter(rBreaks, rBreaks.begin()));
363 bool ScTable::HasRowPageBreak(SCROW nRow) const
365 if (!ValidRow(nRow))
366 return false;
368 return maRowPageBreaks.find(nRow) != maRowPageBreaks.end();
371 bool ScTable::HasColPageBreak(SCCOL nCol) const
373 if (!ValidCol(nCol))
374 return false;
376 return maColPageBreaks.find(nCol) != maColPageBreaks.end();
379 bool ScTable::HasRowManualBreak(SCROW nRow) const
381 if (!ValidRow(nRow))
382 return false;
384 return maRowManualBreaks.find(nRow) != maRowManualBreaks.end();
387 bool ScTable::HasColManualBreak(SCCOL nCol) const
389 if (!ValidCol(nCol))
390 return false;
392 return maColManualBreaks.find(nCol) != maColManualBreaks.end();
395 SCROW ScTable::GetNextManualBreak(SCROW nRow) const
397 set<SCROW>::const_iterator itr = maRowManualBreaks.lower_bound(nRow);
398 return itr == maRowManualBreaks.end() ? -1 : *itr;
401 void ScTable::RemoveRowPageBreaks(SCROW nStartRow, SCROW nEndRow)
403 if (!ValidRow(nStartRow) || !ValidRow(nEndRow))
404 return;
406 set<SCROW>::iterator low = maRowPageBreaks.lower_bound(nStartRow);
407 set<SCROW>::iterator high = maRowPageBreaks.upper_bound(nEndRow);
408 maRowPageBreaks.erase(low, high);
411 void ScTable::RemoveRowBreak(SCROW nRow, bool bPage, bool bManual)
413 if (!ValidRow(nRow))
414 return;
416 if (bPage)
417 maRowPageBreaks.erase(nRow);
419 if (bManual)
421 maRowManualBreaks.erase(nRow);
422 InvalidatePageBreaks();
426 void ScTable::RemoveColBreak(SCCOL nCol, bool bPage, bool bManual)
428 if (!ValidCol(nCol))
429 return;
431 if (bPage)
432 maColPageBreaks.erase(nCol);
434 if (bManual)
436 maColManualBreaks.erase(nCol);
437 InvalidatePageBreaks();
441 void ScTable::SetRowBreak(SCROW nRow, bool bPage, bool bManual)
443 if (!ValidRow(nRow))
444 return;
446 if (bPage)
447 maRowPageBreaks.insert(nRow);
449 if (bManual)
451 maRowManualBreaks.insert(nRow);
452 InvalidatePageBreaks();
456 void ScTable::SetColBreak(SCCOL nCol, bool bPage, bool bManual)
458 if (!ValidCol(nCol))
459 return;
461 if (bPage)
462 maColPageBreaks.insert(nCol);
464 if (bManual)
466 maColManualBreaks.insert(nCol);
467 InvalidatePageBreaks();
471 Sequence<TablePageBreakData> ScTable::GetRowBreakData() const
473 using ::std::inserter;
475 set<SCROW> aRowBreaks = maRowPageBreaks;
476 copy(maRowManualBreaks.begin(), maRowManualBreaks.end(),
477 inserter(aRowBreaks, aRowBreaks.begin()));
479 Sequence<TablePageBreakData> aSeq(aRowBreaks.size());
480 std::transform(aRowBreaks.begin(), aRowBreaks.end(), aSeq.getArray(), [this](const SCROW nRow) {
481 return TablePageBreakData(nRow, HasRowManualBreak(nRow));
484 return aSeq;
487 bool ScTable::RowHidden(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
489 if (!ValidRow(nRow))
491 if (pFirstRow)
492 *pFirstRow = nRow;
493 if (pLastRow)
494 *pLastRow = nRow;
495 return true;
498 ScFlatBoolRowSegments::RangeData aData;
499 if (!mpHiddenRows->getRangeData(nRow, aData))
501 // search failed.
502 if (pFirstRow)
503 *pFirstRow = nRow;
504 if (pLastRow)
505 *pLastRow = nRow;
506 return true;
509 if (pFirstRow)
510 *pFirstRow = aData.mnRow1;
511 if (pLastRow)
512 *pLastRow = aData.mnRow2;
514 return aData.mbValue;
517 bool ScTable::RowHiddenLeaf(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
519 if (!ValidRow(nRow))
521 if (pFirstRow)
522 *pFirstRow = nRow;
523 if (pLastRow)
524 *pLastRow = nRow;
525 return true;
528 ScFlatBoolRowSegments::RangeData aData;
529 if (!mpHiddenRows->getRangeDataLeaf(nRow, aData))
531 // search failed.
532 if (pFirstRow)
533 *pFirstRow = nRow;
534 if (pLastRow)
535 *pLastRow = nRow;
536 return true;
539 if (pFirstRow)
540 *pFirstRow = aData.mnRow1;
541 if (pLastRow)
542 *pLastRow = aData.mnRow2;
544 return aData.mbValue;
547 bool ScTable::HasHiddenRows(SCROW nStartRow, SCROW nEndRow) const
549 SCROW nRow = nStartRow;
550 while (nRow <= nEndRow)
552 SCROW nLastRow = -1;
553 bool bHidden = RowHidden(nRow, nullptr, &nLastRow);
554 if (bHidden)
555 return true;
557 nRow = nLastRow + 1;
559 return false;
562 bool ScTable::ColHidden(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const
564 if (!ValidCol(nCol))
565 return true;
567 ScFlatBoolColSegments::RangeData aData;
568 if (!mpHiddenCols->getRangeData(nCol, aData))
569 return true;
571 if (pFirstCol)
572 *pFirstCol = aData.mnCol1;
573 if (pLastCol)
574 *pLastCol = aData.mnCol2;
576 return aData.mbValue;
579 bool ScTable::SetRowHidden(SCROW nStartRow, SCROW nEndRow, bool bHidden)
581 bool bChanged = false;
582 if (bHidden)
583 bChanged = mpHiddenRows->setTrue(nStartRow, nEndRow);
584 else
585 bChanged = mpHiddenRows->setFalse(nStartRow, nEndRow);
587 // Cell anchored objects might change visibility
588 ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
589 if (pDrawLayer)
591 std::vector<SdrObject*> aRowDrawObjects;
592 aRowDrawObjects = pDrawLayer->GetObjectsAnchoredToRows(GetTab(), nStartRow, nEndRow);
593 for (auto aObj : aRowDrawObjects)
595 ScDrawObjData* pData = ScDrawLayer::GetObjData(aObj);
596 if (pData)
598 if (bHidden)
599 aObj->SetVisible(false);
600 else if (!GetDoc().ColHidden(pData->maStart.Col(), pData->maStart.Tab()))
602 // Only change visibility if object is not hidden by a hidden col
603 aObj->SetVisible(true);
609 if (bChanged)
611 SetStreamValid(false);
613 { // Scoped bulk broadcast.
614 // Only subtotal formula cells will accept the notification of
615 // SfxHintId::ScHiddenRowsChanged, leaving the bulk will track
616 // those and broadcast SfxHintId::ScDataChanged to notify all
617 // dependents.
618 ScBulkBroadcast aBulkBroadcast(rDocument.GetBASM(), SfxHintId::ScDataChanged);
619 for (SCCOL i = 0; i < aCol.size(); i++)
621 aCol[i].BroadcastRows(nStartRow, nEndRow, SfxHintId::ScHiddenRowsChanged);
626 return bChanged;
629 void ScTable::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, bool bHidden)
631 bool bChanged = false;
632 if (bHidden)
633 bChanged = mpHiddenCols->setTrue(nStartCol, nEndCol);
634 else
635 bChanged = mpHiddenCols->setFalse(nStartCol, nEndCol);
637 // Cell anchored objects might change visibility
638 ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
639 if (pDrawLayer)
641 std::vector<SdrObject*> aColDrawObjects;
642 aColDrawObjects = pDrawLayer->GetObjectsAnchoredToCols(GetTab(), nStartCol, nEndCol);
643 for (auto aObj : aColDrawObjects)
645 ScDrawObjData* pData = ScDrawLayer::GetObjData(aObj);
646 if (pData)
648 if (bHidden)
649 aObj->SetVisible(false);
650 else if (!GetDoc().RowHidden(pData->maStart.Row(), pData->maStart.Tab()))
652 // Only change visibility if object is not hidden by a hidden row
653 aObj->SetVisible(true);
659 if (bChanged)
660 SetStreamValid(false);
663 void ScTable::CopyColHidden(const ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol)
665 SCCOL nCol = nStartCol;
666 while (nCol <= nEndCol)
668 SCCOL nLastCol = -1;
669 bool bHidden = rTable.ColHidden(nCol, nullptr, &nLastCol);
670 if (nLastCol > nEndCol)
671 nLastCol = nEndCol;
673 SetColHidden(nCol, nLastCol, bHidden);
674 nCol = nLastCol + 1;
678 void ScTable::CopyRowHidden(const ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
680 SCROW nRow = nStartRow;
681 while (nRow <= nEndRow)
683 SCROW nLastRow = -1;
684 bool bHidden = rTable.RowHidden(nRow, nullptr, &nLastRow);
685 if (nLastRow > nEndRow)
686 nLastRow = nEndRow;
687 SetRowHidden(nRow, nLastRow, bHidden);
688 nRow = nLastRow + 1;
692 void ScTable::CopyRowHeight(const ScTable& rSrcTable, SCROW nStartRow, SCROW nEndRow,
693 SCROW nSrcOffset)
695 SCROW nRow = nStartRow;
696 ScFlatUInt16RowSegments::RangeData aSrcData;
697 while (nRow <= nEndRow)
699 if (!rSrcTable.mpRowHeights->getRangeData(nRow + nSrcOffset, aSrcData))
700 // Something is wrong !
701 return;
703 SCROW nLastRow = aSrcData.mnRow2 - nSrcOffset;
704 if (nLastRow > nEndRow)
705 nLastRow = nEndRow;
707 mpRowHeights->setValue(nRow, nLastRow, aSrcData.mnValue);
708 nRow = nLastRow + 1;
712 SCROW ScTable::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow) const
714 SCROW nRow = nStartRow;
715 ScFlatBoolRowSegments::RangeData aData;
716 while (nRow <= nEndRow)
718 if (!ValidRow(nRow))
719 break;
721 if (!mpHiddenRows->getRangeData(nRow, aData))
722 // failed to get range data.
723 break;
725 if (!aData.mbValue)
726 // visible row found
727 return nRow;
729 nRow = aData.mnRow2 + 1;
732 return ::std::numeric_limits<SCROW>::max();
735 SCROW ScTable::LastVisibleRow(SCROW nStartRow, SCROW nEndRow) const
737 SCROW nRow = nEndRow;
738 ScFlatBoolRowSegments::RangeData aData;
739 while (nRow >= nStartRow)
741 if (!ValidRow(nRow))
742 break;
744 if (!mpHiddenRows->getRangeData(nRow, aData))
745 // failed to get range data.
746 break;
748 if (!aData.mbValue)
749 // visible row found
750 return nRow;
752 nRow = aData.mnRow1 - 1;
755 return ::std::numeric_limits<SCROW>::max();
758 SCROW ScTable::CountVisibleRows(SCROW nStartRow, SCROW nEndRow) const
760 SCROW nCount = 0;
761 SCROW nRow = nStartRow;
762 ScFlatBoolRowSegments::RangeData aData;
763 while (nRow <= nEndRow)
765 if (!mpHiddenRows->getRangeData(nRow, aData))
766 break;
768 if (aData.mnRow2 > nEndRow)
769 aData.mnRow2 = nEndRow;
771 if (!aData.mbValue)
772 nCount += aData.mnRow2 - nRow + 1;
774 nRow = aData.mnRow2 + 1;
776 return nCount;
779 tools::Long ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZero) const
781 tools::Long nHeight = 0;
782 SCROW nRow = nStartRow;
783 ScFlatBoolRowSegments::RangeData aData;
784 while (nRow <= nEndRow)
786 if (!mpHiddenRows->getRangeData(nRow, aData))
787 break;
789 if (aData.mnRow2 > nEndRow)
790 aData.mnRow2 = nEndRow;
792 if (!(bHiddenAsZero && aData.mbValue))
793 // visible row range.
794 nHeight += mpRowHeights->getSumValue(nRow, aData.mnRow2);
796 nRow = aData.mnRow2 + 1;
799 return nHeight;
802 SCCOL ScTable::CountVisibleCols(SCCOL nStartCol, SCCOL nEndCol) const
804 assert(nStartCol <= nEndCol);
805 SCCOL nCount = 0;
806 SCCOL nCol = nStartCol;
807 ScFlatBoolColSegments::RangeData aData;
808 while (nCol <= nEndCol)
810 if (!mpHiddenCols->getRangeData(nCol, aData))
811 break;
813 if (aData.mnCol2 > nEndCol)
814 aData.mnCol2 = nEndCol;
816 if (!aData.mbValue)
817 nCount += aData.mnCol2 - nCol + 1;
819 nCol = aData.mnCol2 + 1;
821 return nCount;
824 SCCOLROW ScTable::LastHiddenColRow(SCCOLROW nPos, bool bCol) const
826 if (bCol)
828 SCCOL nCol = static_cast<SCCOL>(nPos);
829 if (ColHidden(nCol))
831 for (SCCOL i = nCol + 1; i <= rDocument.MaxCol(); ++i)
833 if (!ColHidden(i))
834 return i - 1;
838 else
840 SCROW nRow = static_cast<SCROW>(nPos);
841 SCROW nLastRow;
842 if (RowHidden(nRow, nullptr, &nLastRow))
843 return static_cast<SCCOLROW>(nLastRow);
845 return ::std::numeric_limits<SCCOLROW>::max();
848 bool ScTable::RowFiltered(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
850 if (!ValidRow(nRow))
851 return false;
853 ScFlatBoolRowSegments::RangeData aData;
854 if (!mpFilteredRows->getRangeData(nRow, aData))
855 // search failed.
856 return false;
858 if (pFirstRow)
859 *pFirstRow = aData.mnRow1;
860 if (pLastRow)
861 *pLastRow = aData.mnRow2;
863 return aData.mbValue;
866 bool ScTable::ColFiltered(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const
868 if (!ValidCol(nCol))
869 return false;
871 ScFlatBoolColSegments::RangeData aData;
872 if (!mpFilteredCols->getRangeData(nCol, aData))
873 // search failed.
874 return false;
876 if (pFirstCol)
877 *pFirstCol = aData.mnCol1;
878 if (pLastCol)
879 *pLastCol = aData.mnCol2;
881 return aData.mbValue;
884 bool ScTable::HasFilteredRows(SCROW nStartRow, SCROW nEndRow) const
886 SCROW nRow = nStartRow;
887 while (nRow <= nEndRow)
889 SCROW nLastRow = nRow;
890 bool bFiltered = RowFiltered(nRow, nullptr, &nLastRow);
891 if (bFiltered)
892 return true;
894 nRow = nLastRow + 1;
896 return false;
899 void ScTable::CopyColFiltered(const ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol)
901 SCCOL nCol = nStartCol;
902 while (nCol <= nEndCol)
904 SCCOL nLastCol = -1;
905 bool bFiltered = rTable.ColFiltered(nCol, nullptr, &nLastCol);
906 if (nLastCol > nEndCol)
907 nLastCol = nEndCol;
909 SetColFiltered(nCol, nLastCol, bFiltered);
910 nCol = nLastCol + 1;
914 void ScTable::CopyRowFiltered(const ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
916 SCROW nRow = nStartRow;
917 while (nRow <= nEndRow)
919 SCROW nLastRow = -1;
920 bool bFiltered = rTable.RowFiltered(nRow, nullptr, &nLastRow);
921 if (nLastRow > nEndRow)
922 nLastRow = nEndRow;
923 SetRowFiltered(nRow, nLastRow, bFiltered);
924 nRow = nLastRow + 1;
928 void ScTable::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, bool bFiltered)
930 if (bFiltered)
931 mpFilteredRows->setTrue(nStartRow, nEndRow);
932 else
933 mpFilteredRows->setFalse(nStartRow, nEndRow);
936 void ScTable::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, bool bFiltered)
938 if (bFiltered)
939 mpFilteredCols->setTrue(nStartCol, nEndCol);
940 else
941 mpFilteredCols->setFalse(nStartCol, nEndCol);
944 SCROW ScTable::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const
946 SCROW nRow = nStartRow;
947 ScFlatBoolRowSegments::RangeData aData;
948 while (nRow <= nEndRow)
950 if (!ValidRow(nRow))
951 break;
953 if (!mpFilteredRows->getRangeData(nRow, aData))
954 // failed to get range data.
955 break;
957 if (!aData.mbValue)
958 // non-filtered row found
959 return nRow;
961 nRow = aData.mnRow2 + 1;
964 return ::std::numeric_limits<SCROW>::max();
967 SCROW ScTable::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const
969 SCROW nRow = nEndRow;
970 ScFlatBoolRowSegments::RangeData aData;
971 while (nRow >= nStartRow)
973 if (!ValidRow(nRow))
974 break;
976 if (!mpFilteredRows->getRangeData(nRow, aData))
977 // failed to get range data.
978 break;
980 if (!aData.mbValue)
981 // non-filtered row found
982 return nRow;
984 nRow = aData.mnRow1 - 1;
987 return ::std::numeric_limits<SCROW>::max();
990 SCROW ScTable::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow) const
992 SCROW nCount = 0;
993 SCROW nRow = nStartRow;
994 ScFlatBoolRowSegments::RangeData aData;
995 while (nRow <= nEndRow)
997 if (!mpFilteredRows->getRangeData(nRow, aData))
998 break;
1000 if (aData.mnRow2 > nEndRow)
1001 aData.mnRow2 = nEndRow;
1003 if (!aData.mbValue)
1004 nCount += aData.mnRow2 - nRow + 1;
1006 nRow = aData.mnRow2 + 1;
1008 return nCount;
1011 Color ScTable::GetCellBackgroundColor(ScAddress aPos) const
1013 Color backgroundColor;
1014 bool bHasConditionalBackgroundColor = false;
1015 // Check background color from cond. formatting
1016 const ScPatternAttr* pPattern = GetDoc().GetPattern(aPos.Col(), aPos.Row(), aPos.Tab());
1017 if (pPattern)
1019 if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
1021 const SfxItemSet* pCondSet = GetDoc().GetCondResult(aPos.Col(), aPos.Row(), aPos.Tab());
1022 const SvxBrushItem* pBackgroundColor = &pPattern->GetItem(ATTR_BACKGROUND, pCondSet);
1023 backgroundColor = pBackgroundColor->GetColor();
1024 bHasConditionalBackgroundColor = true;
1028 // Color scale needs a different handling
1029 ScConditionalFormat* pCondFormat = GetDoc().GetCondFormat(aPos.Col(), aPos.Row(), aPos.Tab());
1030 if (pCondFormat)
1032 for (size_t i = 0; i < pCondFormat->size(); i++)
1034 auto aEntry = pCondFormat->GetEntry(i);
1035 if (aEntry->GetType() == ScFormatEntry::Type::Colorscale)
1037 const ScColorScaleFormat* pColFormat
1038 = static_cast<const ScColorScaleFormat*>(aEntry);
1039 std::optional<Color> oColor = pColFormat->GetColor(aPos);
1040 if (oColor)
1042 backgroundColor = oColor.value();
1043 bHasConditionalBackgroundColor = true;
1048 return bHasConditionalBackgroundColor ? backgroundColor
1049 : GetDoc().GetAttr(aPos, ATTR_BACKGROUND)->GetColor();
1052 Color ScTable::GetCellTextColor(ScAddress aPos) const
1054 // Check text & background color from cond. formatting
1055 const ScPatternAttr* pPattern = GetDoc().GetPattern(aPos.Col(), aPos.Row(), aPos.Tab());
1056 if (pPattern)
1058 if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
1060 const SfxItemSet* pCondSet = GetDoc().GetCondResult(aPos.Col(), aPos.Row(), aPos.Tab());
1061 const SvxColorItem* pColor = &pPattern->GetItem(ATTR_FONT_COLOR, pCondSet);
1062 return pColor->GetValue();
1065 if (pPattern->GetItem(ATTR_VALUE_FORMAT).GetValue())
1067 const SfxUInt32Item pItem = pPattern->GetItem(ATTR_VALUE_FORMAT);
1068 auto& rDoc = const_cast<ScDocument&>(GetDoc());
1069 const Color* pColor;
1070 ScRefCellValue aCell(rDoc, aPos);
1071 ScCellFormat::GetString(rDoc, aPos, pItem.GetValue(), &pColor, nullptr, false, false);
1072 if (pColor)
1073 return *pColor;
1077 const SvxColorItem* pColor = GetDoc().GetAttr(aPos, ATTR_FONT_COLOR);
1078 return pColor->GetValue();
1081 bool ScTable::IsManualRowHeight(SCROW nRow) const
1083 return bool(pRowFlags->GetValue(nRow) & CRFlags::ManualSize);
1086 namespace
1088 void lcl_syncFlags(const ScDocument* pDocument, ScFlatBoolColSegments& rColSegments,
1089 const ScFlatBoolRowSegments& rRowSegments,
1090 ScBitMaskCompressedArray<SCCOL, CRFlags>* pColFlags,
1091 ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlags, const CRFlags nFlagMask)
1093 CRFlags nFlagMaskComplement = ~nFlagMask;
1095 pRowFlags->AndValue(0, pDocument->MaxRow(), nFlagMaskComplement);
1096 pColFlags->AndValue(0, pDocument->MaxCol() + 1, nFlagMaskComplement);
1099 // row hidden flags.
1101 SCROW nRow = 0;
1102 ScFlatBoolRowSegments::RangeData aData;
1103 while (nRow <= pDocument->MaxRow())
1105 if (!rRowSegments.getRangeData(nRow, aData))
1106 break;
1108 if (aData.mbValue)
1109 pRowFlags->OrValue(nRow, aData.mnRow2, nFlagMask);
1111 nRow = aData.mnRow2 + 1;
1116 // column hidden flags.
1118 SCCOL nCol = 0;
1119 ScFlatBoolColSegments::RangeData aData;
1120 while (nCol <= pDocument->MaxCol())
1122 if (!rColSegments.getRangeData(nCol, aData))
1123 break;
1125 if (aData.mbValue)
1126 pColFlags->OrValue(nCol, aData.mnCol2, nFlagMask);
1128 nCol = aData.mnCol2 + 1;
1134 void ScTable::SyncColRowFlags()
1136 CRFlags nManualBreakComplement = ~CRFlags::ManualBreak;
1138 // Manual breaks.
1139 pRowFlags->AndValue(0, rDocument.MaxRow(), nManualBreakComplement);
1140 mpColFlags->AndValue(0, rDocument.MaxCol() + 1, nManualBreakComplement);
1142 for (const auto& rBreakPos : maRowManualBreaks)
1143 pRowFlags->OrValue(rBreakPos, CRFlags::ManualBreak);
1145 for (const auto& rBreakPos : maColManualBreaks)
1146 mpColFlags->OrValue(rBreakPos, CRFlags::ManualBreak);
1148 // Hidden flags.
1149 lcl_syncFlags(&rDocument, *mpHiddenCols, *mpHiddenRows, mpColFlags.get(), pRowFlags.get(),
1150 CRFlags::Hidden);
1151 lcl_syncFlags(&rDocument, *mpFilteredCols, *mpFilteredRows, mpColFlags.get(), pRowFlags.get(),
1152 CRFlags::Filtered);
1155 void ScTable::SetPageSize(const Size& rSize)
1157 if (!rSize.IsEmpty())
1159 if (aPageSizeTwips != rSize)
1160 InvalidatePageBreaks();
1162 bPageSizeValid = true;
1163 aPageSizeTwips = rSize;
1165 else
1166 bPageSizeValid = false;
1169 bool ScTable::IsProtected() const { return pTabProtection && pTabProtection->isProtected(); }
1171 void ScTable::SetProtection(const ScTableProtection* pProtect)
1173 if (pProtect)
1174 pTabProtection.reset(new ScTableProtection(*pProtect));
1175 else
1176 pTabProtection.reset();
1178 SetStreamValid(false);
1181 const ScTableProtection* ScTable::GetProtection() const { return pTabProtection.get(); }
1183 Size ScTable::GetPageSize() const
1185 if (bPageSizeValid)
1186 return aPageSizeTwips;
1187 else
1188 return Size(); // blank
1191 void ScTable::SetRepeatArea(SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow)
1193 // #i117952# page break calculation uses these values (set from ScPrintFunc), not pRepeatColRange/pRepeatRowRange
1194 if (nStartCol != nRepeatStartX || nEndCol != nRepeatEndX || nStartRow != nRepeatStartY
1195 || nEndRow != nRepeatEndY)
1196 InvalidatePageBreaks();
1198 nRepeatStartX = nStartCol;
1199 nRepeatEndX = nEndCol;
1200 nRepeatStartY = nStartRow;
1201 nRepeatEndY = nEndRow;
1204 void ScTable::StartListening(const ScAddress& rAddress, SvtListener* pListener)
1206 if (!ValidCol(rAddress.Col()))
1207 return;
1209 CreateColumnIfNotExists(rAddress.Col()).StartListening(*pListener, rAddress.Row());
1212 void ScTable::EndListening(const ScAddress& rAddress, SvtListener* pListener)
1214 if (!ValidCol(rAddress.Col()))
1215 return;
1217 if (rAddress.Col() < aCol.size())
1218 aCol[rAddress.Col()].EndListening(*pListener, rAddress.Row());
1221 void ScTable::StartListening(sc::StartListeningContext& rCxt, const ScAddress& rAddress,
1222 SvtListener& rListener)
1224 if (!ValidCol(rAddress.Col()))
1225 return;
1227 CreateColumnIfNotExists(rAddress.Col()).StartListening(rCxt, rAddress, rListener);
1230 void ScTable::EndListening(sc::EndListeningContext& rCxt, const ScAddress& rAddress,
1231 SvtListener& rListener)
1233 if (!ValidCol(rAddress.Col()))
1234 return;
1236 if (rAddress.Col() < aCol.size())
1237 aCol[rAddress.Col()].EndListening(rCxt, rAddress, rListener);
1240 void ScTable::SetPageStyle(const OUString& rName)
1242 if (aPageStyle == rName)
1243 return;
1245 OUString aStrNew = rName;
1246 SfxStyleSheetBasePool* pStylePool = rDocument.GetStyleSheetPool();
1247 SfxStyleSheetBase* pNewStyle = pStylePool->Find(aStrNew, SfxStyleFamily::Page);
1249 if (!pNewStyle)
1251 aStrNew = ScResId(STR_STYLENAME_STANDARD);
1252 pNewStyle = pStylePool->Find(aStrNew, SfxStyleFamily::Page);
1255 if (aPageStyle == aStrNew)
1256 return;
1258 SfxStyleSheetBase* pOldStyle = pStylePool->Find(aPageStyle, SfxStyleFamily::Page);
1259 if (pOldStyle && pNewStyle)
1261 SfxItemSet& rOldSet = pOldStyle->GetItemSet();
1262 SfxItemSet& rNewSet = pNewStyle->GetItemSet();
1263 auto getScaleValue = [](const SfxItemSet& rSet, sal_uInt16 nId) {
1264 return static_cast<const SfxUInt16Item&>(rSet.Get(nId)).GetValue();
1267 const sal_uInt16 nOldScale = getScaleValue(rOldSet, ATTR_PAGE_SCALE);
1268 const sal_uInt16 nOldScaleToPages = getScaleValue(rOldSet, ATTR_PAGE_SCALETOPAGES);
1269 const sal_uInt16 nNewScale = getScaleValue(rNewSet, ATTR_PAGE_SCALE);
1270 const sal_uInt16 nNewScaleToPages = getScaleValue(rNewSet, ATTR_PAGE_SCALETOPAGES);
1272 if ((nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages))
1273 InvalidateTextWidth(nullptr, nullptr, false, false);
1276 if (pNewStyle) // also without the old one (for UpdateStdNames)
1277 aPageStyle = aStrNew;
1279 SetStreamValid(false);
1282 void ScTable::PageStyleModified(const OUString& rNewName)
1284 aPageStyle = rNewName;
1285 InvalidateTextWidth(nullptr, nullptr, false, false); // don't know what was in the style before
1288 void ScTable::InvalidateTextWidth(const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
1289 bool bNumFormatChanged, bool bBroadcast)
1291 if (pAdrFrom && !pAdrTo)
1293 // Special case: only process the "from" cell.
1294 SCCOL nCol = pAdrFrom->Col();
1295 SCROW nRow = pAdrFrom->Row();
1296 if (nCol >= aCol.size())
1297 return;
1298 ScColumn& rCol = aCol[nCol];
1299 ScRefCellValue aCell = rCol.GetCellValue(nRow);
1300 if (aCell.isEmpty())
1301 return;
1303 rCol.SetTextWidth(nRow, TEXTWIDTH_DIRTY);
1305 if (bNumFormatChanged)
1306 rCol.SetScriptType(nRow, SvtScriptType::UNKNOWN);
1308 if (bBroadcast)
1309 { // Only with CalcAsShown
1310 switch (aCell.getType())
1312 case CELLTYPE_VALUE:
1313 rCol.Broadcast(nRow);
1314 break;
1315 case CELLTYPE_FORMULA:
1316 aCell.getFormula()->SetDirty();
1317 break;
1318 default:
1320 // added to avoid warnings
1325 return;
1328 const SCCOL nCol1 = pAdrFrom ? pAdrFrom->Col() : 0;
1329 const SCROW nRow1 = pAdrFrom ? pAdrFrom->Row() : 0;
1330 const SCCOL nCol2 = pAdrTo ? pAdrTo->Col() : aCol.size() - 1;
1331 const SCROW nRow2 = pAdrTo ? pAdrTo->Row() : rDocument.MaxRow();
1333 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1335 ScColumnTextWidthIterator aIter(GetDoc(), aCol[nCol], nRow1, nRow2);
1336 sc::ColumnBlockPosition blockPos; // cache mdds position
1337 InitColumnBlockPosition(blockPos, nCol);
1339 for (; aIter.hasCell(); aIter.next())
1341 SCROW nRow = aIter.getPos();
1342 aIter.setValue(TEXTWIDTH_DIRTY);
1343 ScRefCellValue aCell = aCol[nCol].GetCellValue(blockPos, nRow);
1344 if (aCell.isEmpty())
1345 continue;
1347 if (bNumFormatChanged)
1348 aCol[nCol].SetScriptType(nRow, SvtScriptType::UNKNOWN);
1350 if (bBroadcast)
1351 { // Only with CalcAsShown
1352 switch (aCell.getType())
1354 case CELLTYPE_VALUE:
1355 aCol[nCol].Broadcast(nRow);
1356 break;
1357 case CELLTYPE_FORMULA:
1358 aCell.getFormula()->SetDirty();
1359 break;
1360 default:
1362 // added to avoid warnings
1370 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */