1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
22 #include <formulacell.hxx>
25 #include <document.hxx>
26 #include <drwlayer.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>
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>
54 using ::com::sun::star::uno::Sequence
;
55 using ::com::sun::star::sheet::TablePageBreakData
;
58 void ScTable::UpdatePageBreaks(const ScRange
* pUserArea
)
60 if (rDocument
.IsImportingXML())
63 // pUserArea != NULL -> print area is specified. We need to force-update
71 // Always update breaks if force breaks option has changed
73 && mbForceBreaks
== ScModule::get()->GetPrintOptions().GetForceBreaks())
77 SfxStyleSheetBase
* pStyle
78 = rDocument
.GetStyleSheetPool()->Find(aPageStyle
, SfxStyleFamily::Page
);
81 OSL_FAIL("UpdatePageBreaks: Style not found");
84 SfxItemSet
* pStyleSet
= &pStyle
->GetItemSet();
88 SCCOL nEndCol
= rDocument
.MaxCol();
89 SCROW nEndRow
= rDocument
.MaxRow();
92 nStartCol
= pUserArea
->aStart
.Col();
93 nStartRow
= pUserArea
->aStart
.Row();
94 nEndCol
= pUserArea
->aEnd
.Col();
95 nEndRow
= pUserArea
->aEnd
.Row();
99 sal_uInt16 nAreaCount
= GetPrintRangeCount();
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);
111 else if (nAreaCount
== 1)
113 const ScRange
* pArea
= GetPrintRange(0);
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;
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);
159 SetColBreak(nStartCol
, true, false); // AREABREAK
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);
179 else if (nX
!= nStartCol
)
180 RemoveColBreak(nX
, true, false);
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);
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
);
214 tools::Long nThisY
= 0;
218 const bool bHasHeight
= aIterHeights
.getValue(nY
, nTmp
);
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);
239 else if (nY
!= nStartRow
)
240 ; // page break already removed
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");
252 nPageSizeY
-= nHeights
;
253 if (nY
<= nRepeatEndY
)
254 RemoveRowPageBreaks(nY
, nRepeatEndY
);
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);
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
;
284 nSizeY
+= nThisY
* (nMultiple
- 1);
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());
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
342 rBreaks
= maRowPageBreaks
;
346 copy(maRowManualBreaks
.begin(), maRowManualBreaks
.end(),
347 inserter(rBreaks
, rBreaks
.begin()));
351 void ScTable::GetAllColBreaks(set
<SCCOL
>& rBreaks
, bool bPage
, bool bManual
) const
354 rBreaks
= maColPageBreaks
;
358 copy(maColManualBreaks
.begin(), maColManualBreaks
.end(),
359 inserter(rBreaks
, rBreaks
.begin()));
363 bool ScTable::HasRowPageBreak(SCROW nRow
) const
368 return maRowPageBreaks
.find(nRow
) != maRowPageBreaks
.end();
371 bool ScTable::HasColPageBreak(SCCOL nCol
) const
376 return maColPageBreaks
.find(nCol
) != maColPageBreaks
.end();
379 bool ScTable::HasRowManualBreak(SCROW nRow
) const
384 return maRowManualBreaks
.find(nRow
) != maRowManualBreaks
.end();
387 bool ScTable::HasColManualBreak(SCCOL nCol
) const
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
))
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
)
417 maRowPageBreaks
.erase(nRow
);
421 maRowManualBreaks
.erase(nRow
);
422 InvalidatePageBreaks();
426 void ScTable::RemoveColBreak(SCCOL nCol
, bool bPage
, bool bManual
)
432 maColPageBreaks
.erase(nCol
);
436 maColManualBreaks
.erase(nCol
);
437 InvalidatePageBreaks();
441 void ScTable::SetRowBreak(SCROW nRow
, bool bPage
, bool bManual
)
447 maRowPageBreaks
.insert(nRow
);
451 maRowManualBreaks
.insert(nRow
);
452 InvalidatePageBreaks();
456 void ScTable::SetColBreak(SCCOL nCol
, bool bPage
, bool bManual
)
462 maColPageBreaks
.insert(nCol
);
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
));
487 bool ScTable::RowHidden(SCROW nRow
, SCROW
* pFirstRow
, SCROW
* pLastRow
) const
498 ScFlatBoolRowSegments::RangeData aData
;
499 if (!mpHiddenRows
->getRangeData(nRow
, aData
))
510 *pFirstRow
= aData
.mnRow1
;
512 *pLastRow
= aData
.mnRow2
;
514 return aData
.mbValue
;
517 bool ScTable::RowHiddenLeaf(SCROW nRow
, SCROW
* pFirstRow
, SCROW
* pLastRow
) const
528 ScFlatBoolRowSegments::RangeData aData
;
529 if (!mpHiddenRows
->getRangeDataLeaf(nRow
, aData
))
540 *pFirstRow
= aData
.mnRow1
;
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
)
553 bool bHidden
= RowHidden(nRow
, nullptr, &nLastRow
);
562 bool ScTable::ColHidden(SCCOL nCol
, SCCOL
* pFirstCol
, SCCOL
* pLastCol
) const
567 ScFlatBoolColSegments::RangeData aData
;
568 if (!mpHiddenCols
->getRangeData(nCol
, aData
))
572 *pFirstCol
= aData
.mnCol1
;
574 *pLastCol
= aData
.mnCol2
;
576 return aData
.mbValue
;
579 bool ScTable::SetRowHidden(SCROW nStartRow
, SCROW nEndRow
, bool bHidden
)
581 bool bChanged
= false;
583 bChanged
= mpHiddenRows
->setTrue(nStartRow
, nEndRow
);
585 bChanged
= mpHiddenRows
->setFalse(nStartRow
, nEndRow
);
587 // Cell anchored objects might change visibility
588 ScDrawLayer
* pDrawLayer
= rDocument
.GetDrawLayer();
591 std::vector
<SdrObject
*> aRowDrawObjects
;
592 aRowDrawObjects
= pDrawLayer
->GetObjectsAnchoredToRows(GetTab(), nStartRow
, nEndRow
);
593 for (auto aObj
: aRowDrawObjects
)
595 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(aObj
);
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);
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
618 ScBulkBroadcast
aBulkBroadcast(rDocument
.GetBASM(), SfxHintId::ScDataChanged
);
619 for (SCCOL i
= 0; i
< aCol
.size(); i
++)
621 aCol
[i
].BroadcastRows(nStartRow
, nEndRow
, SfxHintId::ScHiddenRowsChanged
);
629 void ScTable::SetColHidden(SCCOL nStartCol
, SCCOL nEndCol
, bool bHidden
)
631 bool bChanged
= false;
633 bChanged
= mpHiddenCols
->setTrue(nStartCol
, nEndCol
);
635 bChanged
= mpHiddenCols
->setFalse(nStartCol
, nEndCol
);
637 // Cell anchored objects might change visibility
638 ScDrawLayer
* pDrawLayer
= rDocument
.GetDrawLayer();
641 std::vector
<SdrObject
*> aColDrawObjects
;
642 aColDrawObjects
= pDrawLayer
->GetObjectsAnchoredToCols(GetTab(), nStartCol
, nEndCol
);
643 for (auto aObj
: aColDrawObjects
)
645 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(aObj
);
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);
660 SetStreamValid(false);
663 void ScTable::CopyColHidden(const ScTable
& rTable
, SCCOL nStartCol
, SCCOL nEndCol
)
665 SCCOL nCol
= nStartCol
;
666 while (nCol
<= nEndCol
)
669 bool bHidden
= rTable
.ColHidden(nCol
, nullptr, &nLastCol
);
670 if (nLastCol
> nEndCol
)
673 SetColHidden(nCol
, nLastCol
, bHidden
);
678 void ScTable::CopyRowHidden(const ScTable
& rTable
, SCROW nStartRow
, SCROW nEndRow
)
680 SCROW nRow
= nStartRow
;
681 while (nRow
<= nEndRow
)
684 bool bHidden
= rTable
.RowHidden(nRow
, nullptr, &nLastRow
);
685 if (nLastRow
> nEndRow
)
687 SetRowHidden(nRow
, nLastRow
, bHidden
);
692 void ScTable::CopyRowHeight(const ScTable
& rSrcTable
, SCROW nStartRow
, SCROW nEndRow
,
695 SCROW nRow
= nStartRow
;
696 ScFlatUInt16RowSegments::RangeData aSrcData
;
697 while (nRow
<= nEndRow
)
699 if (!rSrcTable
.mpRowHeights
->getRangeData(nRow
+ nSrcOffset
, aSrcData
))
700 // Something is wrong !
703 SCROW nLastRow
= aSrcData
.mnRow2
- nSrcOffset
;
704 if (nLastRow
> nEndRow
)
707 mpRowHeights
->setValue(nRow
, nLastRow
, aSrcData
.mnValue
);
712 SCROW
ScTable::FirstVisibleRow(SCROW nStartRow
, SCROW nEndRow
) const
714 SCROW nRow
= nStartRow
;
715 ScFlatBoolRowSegments::RangeData aData
;
716 while (nRow
<= nEndRow
)
721 if (!mpHiddenRows
->getRangeData(nRow
, aData
))
722 // failed to get range data.
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
)
744 if (!mpHiddenRows
->getRangeData(nRow
, aData
))
745 // failed to get range data.
752 nRow
= aData
.mnRow1
- 1;
755 return ::std::numeric_limits
<SCROW
>::max();
758 SCROW
ScTable::CountVisibleRows(SCROW nStartRow
, SCROW nEndRow
) const
761 SCROW nRow
= nStartRow
;
762 ScFlatBoolRowSegments::RangeData aData
;
763 while (nRow
<= nEndRow
)
765 if (!mpHiddenRows
->getRangeData(nRow
, aData
))
768 if (aData
.mnRow2
> nEndRow
)
769 aData
.mnRow2
= nEndRow
;
772 nCount
+= aData
.mnRow2
- nRow
+ 1;
774 nRow
= aData
.mnRow2
+ 1;
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
))
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;
802 SCCOL
ScTable::CountVisibleCols(SCCOL nStartCol
, SCCOL nEndCol
) const
804 assert(nStartCol
<= nEndCol
);
806 SCCOL nCol
= nStartCol
;
807 ScFlatBoolColSegments::RangeData aData
;
808 while (nCol
<= nEndCol
)
810 if (!mpHiddenCols
->getRangeData(nCol
, aData
))
813 if (aData
.mnCol2
> nEndCol
)
814 aData
.mnCol2
= nEndCol
;
817 nCount
+= aData
.mnCol2
- nCol
+ 1;
819 nCol
= aData
.mnCol2
+ 1;
824 SCCOLROW
ScTable::LastHiddenColRow(SCCOLROW nPos
, bool bCol
) const
828 SCCOL nCol
= static_cast<SCCOL
>(nPos
);
831 for (SCCOL i
= nCol
+ 1; i
<= rDocument
.MaxCol(); ++i
)
840 SCROW nRow
= static_cast<SCROW
>(nPos
);
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
853 ScFlatBoolRowSegments::RangeData aData
;
854 if (!mpFilteredRows
->getRangeData(nRow
, aData
))
859 *pFirstRow
= aData
.mnRow1
;
861 *pLastRow
= aData
.mnRow2
;
863 return aData
.mbValue
;
866 bool ScTable::ColFiltered(SCCOL nCol
, SCCOL
* pFirstCol
, SCCOL
* pLastCol
) const
871 ScFlatBoolColSegments::RangeData aData
;
872 if (!mpFilteredCols
->getRangeData(nCol
, aData
))
877 *pFirstCol
= aData
.mnCol1
;
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
);
899 void ScTable::CopyColFiltered(const ScTable
& rTable
, SCCOL nStartCol
, SCCOL nEndCol
)
901 SCCOL nCol
= nStartCol
;
902 while (nCol
<= nEndCol
)
905 bool bFiltered
= rTable
.ColFiltered(nCol
, nullptr, &nLastCol
);
906 if (nLastCol
> nEndCol
)
909 SetColFiltered(nCol
, nLastCol
, bFiltered
);
914 void ScTable::CopyRowFiltered(const ScTable
& rTable
, SCROW nStartRow
, SCROW nEndRow
)
916 SCROW nRow
= nStartRow
;
917 while (nRow
<= nEndRow
)
920 bool bFiltered
= rTable
.RowFiltered(nRow
, nullptr, &nLastRow
);
921 if (nLastRow
> nEndRow
)
923 SetRowFiltered(nRow
, nLastRow
, bFiltered
);
928 void ScTable::SetRowFiltered(SCROW nStartRow
, SCROW nEndRow
, bool bFiltered
)
931 mpFilteredRows
->setTrue(nStartRow
, nEndRow
);
933 mpFilteredRows
->setFalse(nStartRow
, nEndRow
);
936 void ScTable::SetColFiltered(SCCOL nStartCol
, SCCOL nEndCol
, bool bFiltered
)
939 mpFilteredCols
->setTrue(nStartCol
, nEndCol
);
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
)
953 if (!mpFilteredRows
->getRangeData(nRow
, aData
))
954 // failed to get range data.
958 // non-filtered row found
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
)
976 if (!mpFilteredRows
->getRangeData(nRow
, aData
))
977 // failed to get range data.
981 // non-filtered row found
984 nRow
= aData
.mnRow1
- 1;
987 return ::std::numeric_limits
<SCROW
>::max();
990 SCROW
ScTable::CountNonFilteredRows(SCROW nStartRow
, SCROW nEndRow
) const
993 SCROW nRow
= nStartRow
;
994 ScFlatBoolRowSegments::RangeData aData
;
995 while (nRow
<= nEndRow
)
997 if (!mpFilteredRows
->getRangeData(nRow
, aData
))
1000 if (aData
.mnRow2
> nEndRow
)
1001 aData
.mnRow2
= nEndRow
;
1004 nCount
+= aData
.mnRow2
- nRow
+ 1;
1006 nRow
= aData
.mnRow2
+ 1;
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());
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());
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
);
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());
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);
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
);
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.
1102 ScFlatBoolRowSegments::RangeData aData
;
1103 while (nRow
<= pDocument
->MaxRow())
1105 if (!rRowSegments
.getRangeData(nRow
, aData
))
1109 pRowFlags
->OrValue(nRow
, aData
.mnRow2
, nFlagMask
);
1111 nRow
= aData
.mnRow2
+ 1;
1116 // column hidden flags.
1119 ScFlatBoolColSegments::RangeData aData
;
1120 while (nCol
<= pDocument
->MaxCol())
1122 if (!rColSegments
.getRangeData(nCol
, aData
))
1126 pColFlags
->OrValue(nCol
, aData
.mnCol2
, nFlagMask
);
1128 nCol
= aData
.mnCol2
+ 1;
1134 void ScTable::SyncColRowFlags()
1136 CRFlags nManualBreakComplement
= ~CRFlags::ManualBreak
;
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
);
1149 lcl_syncFlags(&rDocument
, *mpHiddenCols
, *mpHiddenRows
, mpColFlags
.get(), pRowFlags
.get(),
1151 lcl_syncFlags(&rDocument
, *mpFilteredCols
, *mpFilteredRows
, mpColFlags
.get(), pRowFlags
.get(),
1155 void ScTable::SetPageSize(const Size
& rSize
)
1157 if (!rSize
.IsEmpty())
1159 if (aPageSizeTwips
!= rSize
)
1160 InvalidatePageBreaks();
1162 bPageSizeValid
= true;
1163 aPageSizeTwips
= rSize
;
1166 bPageSizeValid
= false;
1169 bool ScTable::IsProtected() const { return pTabProtection
&& pTabProtection
->isProtected(); }
1171 void ScTable::SetProtection(const ScTableProtection
* pProtect
)
1174 pTabProtection
.reset(new ScTableProtection(*pProtect
));
1176 pTabProtection
.reset();
1178 SetStreamValid(false);
1181 const ScTableProtection
* ScTable::GetProtection() const { return pTabProtection
.get(); }
1183 Size
ScTable::GetPageSize() const
1186 return aPageSizeTwips
;
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()))
1209 CreateColumnIfNotExists(rAddress
.Col()).StartListening(*pListener
, rAddress
.Row());
1212 void ScTable::EndListening(const ScAddress
& rAddress
, SvtListener
* pListener
)
1214 if (!ValidCol(rAddress
.Col()))
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()))
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()))
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
)
1245 OUString aStrNew
= rName
;
1246 SfxStyleSheetBasePool
* pStylePool
= rDocument
.GetStyleSheetPool();
1247 SfxStyleSheetBase
* pNewStyle
= pStylePool
->Find(aStrNew
, SfxStyleFamily::Page
);
1251 aStrNew
= ScResId(STR_STYLENAME_STANDARD
);
1252 pNewStyle
= pStylePool
->Find(aStrNew
, SfxStyleFamily::Page
);
1255 if (aPageStyle
== aStrNew
)
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())
1298 ScColumn
& rCol
= aCol
[nCol
];
1299 ScRefCellValue aCell
= rCol
.GetCellValue(nRow
);
1300 if (aCell
.isEmpty())
1303 rCol
.SetTextWidth(nRow
, TEXTWIDTH_DIRTY
);
1305 if (bNumFormatChanged
)
1306 rCol
.SetScriptType(nRow
, SvtScriptType::UNKNOWN
);
1309 { // Only with CalcAsShown
1310 switch (aCell
.getType())
1312 case CELLTYPE_VALUE
:
1313 rCol
.Broadcast(nRow
);
1315 case CELLTYPE_FORMULA
:
1316 aCell
.getFormula()->SetDirty();
1320 // added to avoid warnings
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())
1347 if (bNumFormatChanged
)
1348 aCol
[nCol
].SetScriptType(nRow
, SvtScriptType::UNKNOWN
);
1351 { // Only with CalcAsShown
1352 switch (aCell
.getType())
1354 case CELLTYPE_VALUE
:
1355 aCol
[nCol
].Broadcast(nRow
);
1357 case CELLTYPE_FORMULA
:
1358 aCell
.getFormula()->SetDirty();
1362 // added to avoid warnings
1370 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */