1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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 
41 #include <com/sun/star/sheet/TablePageBreakData.hpp>
42 
43 #include <osl/diagnose.h>
44 
45 #include <algorithm>
46 #include <limits>
47 
48 using ::com::sun::star::uno::Sequence;
49 using ::com::sun::star::sheet::TablePageBreakData;
50 using ::std::set;
51 
UpdatePageBreaks(const ScRange * pUserArea)52 void ScTable::UpdatePageBreaks(const ScRange* pUserArea)
53 {
54     if (rDocument.IsImportingXML())
55         return;
56 
57     // pUserArea != NULL -> print area is specified.  We need to force-update
58     // the page breaks.
59 
60     if (!pUserArea)
61     {
62         if (!bPageSizeValid)
63             return;
64 
65         // Always update breaks if force breaks option has changed
66         if (mbPageBreaksValid && mbForceBreaks == SC_MOD()->GetPrintOptions().GetForceBreaks())
67             return;
68     }
69 
70     SfxStyleSheetBase* pStyle
71         = rDocument.GetStyleSheetPool()->Find(aPageStyle, SfxStyleFamily::Page);
72     if (!pStyle)
73     {
74         OSL_FAIL("UpdatePageBreaks: Style not found");
75         return;
76     }
77     SfxItemSet* pStyleSet = &pStyle->GetItemSet();
78     const SfxPoolItem* pItem;
79 
80     SCCOL nStartCol = 0;
81     SCROW nStartRow = 0;
82     SCCOL nEndCol = rDocument.MaxCol();
83     SCROW nEndRow = rDocument.MaxRow();
84     if (pUserArea)
85     {
86         nStartCol = pUserArea->aStart.Col();
87         nStartRow = pUserArea->aStart.Row();
88         nEndCol = pUserArea->aEnd.Col();
89         nEndRow = pUserArea->aEnd.Row();
90     }
91     else
92     {
93         sal_uInt16 nAreaCount = GetPrintRangeCount();
94         if (nAreaCount > 1)
95         {
96             // Show nothing, when multiple ranges
97 
98             for (SCCOL nX : GetColumnsRange(0, rDocument.MaxCol()))
99                 RemoveColBreak(nX, true, false);
100 
101             RemoveRowPageBreaks(0, rDocument.MaxRow() - 1);
102 
103             return;
104         }
105         else if (nAreaCount == 1)
106         {
107             const ScRange* pArea = GetPrintRange(0);
108             if (pArea)
109             {
110                 nStartCol = pArea->aStart.Col();
111                 nStartRow = pArea->aStart.Row();
112                 nEndCol = pArea->aEnd.Col();
113                 nEndRow = pArea->aEnd.Row();
114             }
115         } // otherwise show everything
116     }
117 
118     // get bSkipColBreaks/bSkipRowBreaks flags:
119     // fdo#40788 - print range scale settings can cause manual breaks to be
120     // ignored (see below). This behaviour may now be set by the user.
121     mbForceBreaks = SC_MOD()->GetPrintOptions().GetForceBreaks();
122     bool bSkipColBreaks = false;
123     bool bSkipRowBreaks = false;
124 
125     if (!mbForceBreaks)
126     {
127         if (pStyleSet->GetItemState(ATTR_PAGE_SCALETOPAGES, false, &pItem) == SfxItemState::SET)
128         {
129             OSL_ENSURE(dynamic_cast<const SfxUInt16Item*>(pItem) != nullptr, "invalid Item");
130             bSkipColBreaks = bSkipRowBreaks
131                 = static_cast<const SfxUInt16Item*>(pItem)->GetValue() > 0;
132         }
133 
134         if (!bSkipColBreaks
135             && pStyleSet->GetItemState(ATTR_PAGE_SCALETO, false, &pItem) == SfxItemState::SET)
136         {
137             // #i54993# when fitting to width or height, ignore only manual breaks in that direction
138             const ScPageScaleToItem* pScaleToItem = static_cast<const ScPageScaleToItem*>(pItem);
139             if (pScaleToItem->GetWidth() > 0)
140                 bSkipColBreaks = true;
141             if (pScaleToItem->GetHeight() > 0)
142                 bSkipRowBreaks = true;
143         }
144     }
145 
146     tools::Long nPageSizeX = aPageSizeTwips.Width();
147     tools::Long nPageSizeY = aPageSizeTwips.Height();
148 
149     //  Beginning: Remove breaks
150 
151     for (SCCOL nX : GetColumnsRange(0, nStartCol - 1))
152         RemoveColBreak(nX, true, false);
153     RemoveRowPageBreaks(0, nStartRow - 1);
154 
155     if (nStartCol > 0)
156         SetColBreak(nStartCol, true, false); // AREABREAK
157     if (nStartRow > 0)
158         SetRowBreak(nStartRow, true, false); // AREABREAK
159 
160     //  Middle part: Distribute breaks
161 
162     bool bRepeatCol = (nRepeatStartX != SCCOL_REPEAT_NONE);
163     bool bColFound = false;
164     tools::Long nSizeX = 0;
165     for (SCCOL nX = nStartCol; nX <= nEndCol; nX++)
166     {
167         bool bStartOfPage = false;
168         tools::Long nThisX = ColHidden(nX) ? 0 : mpColWidth->GetValue(nX);
169         bool bManualBreak = HasColManualBreak(nX);
170         if ((nSizeX + nThisX > nPageSizeX) || (bManualBreak && !bSkipColBreaks))
171         {
172             SetColBreak(nX, true, false);
173             nSizeX = 0;
174             bStartOfPage = true;
175         }
176         else if (nX != nStartCol)
177             RemoveColBreak(nX, true, false);
178         else
179             bStartOfPage = true;
180 
181         if (bStartOfPage && bRepeatCol && nX > nRepeatStartX && !bColFound)
182         {
183             // subtract size of repeat columns from page size
184             for (SCCOL i = nRepeatStartX; i <= nRepeatEndX; i++)
185                 nPageSizeX -= ColHidden(i) ? 0 : mpColWidth->GetValue(i);
186             while (nX <= nRepeatEndX)
187                 RemoveColBreak(++nX, true, false);
188             bColFound = true;
189         }
190 
191         nSizeX += nThisX;
192     }
193 
194     // Remove all page breaks in range.
195     RemoveRowPageBreaks(nStartRow + 1, nEndRow);
196 
197     // And set new page breaks.
198     bool bRepeatRow = (nRepeatStartY != SCROW_REPEAT_NONE);
199     bool bRowFound = false;
200     tools::Long nSizeY = 0;
201     ScFlatBoolRowSegments::ForwardIterator aIterHidden(*mpHiddenRows);
202     ScFlatUInt16RowSegments::ForwardIterator aIterHeights(*mpRowHeights);
203     SCROW nNextManualBreak = GetNextManualBreak(nStartRow); // -1 => no more manual breaks
204     for (SCROW nY = nStartRow; nY <= nEndRow; ++nY)
205     {
206         bool bStartOfPage = false;
207         bool bThisRowHidden = false;
208         const bool bHasValue = aIterHidden.getValue(nY, bThisRowHidden);
209         assert(bHasValue);
210         (void)bHasValue;
211         tools::Long nThisY = 0;
212         if (!bThisRowHidden)
213         {
214             sal_uInt16 nTmp;
215             const bool bHasHeight = aIterHeights.getValue(nY, nTmp);
216             assert(bHasHeight);
217             if (bHasHeight)
218                 nThisY = static_cast<tools::Long>(nTmp);
219         }
220 
221         bool bManualBreak = false;
222         if (nNextManualBreak >= 0)
223         {
224             bManualBreak = (nY == nNextManualBreak);
225             if (nY >= nNextManualBreak)
226                 // Query the next manual break position.
227                 nNextManualBreak = GetNextManualBreak(nY + 1);
228         }
229 
230         if ((nSizeY + nThisY > nPageSizeY) || (bManualBreak && !bSkipRowBreaks))
231         {
232             SetRowBreak(nY, true, false);
233             nSizeY = 0;
234             bStartOfPage = true;
235         }
236         else if (nY != nStartRow)
237             ; // page break already removed
238         else
239             bStartOfPage = true;
240 
241         if (bStartOfPage && bRepeatRow && nY > nRepeatStartY && !bRowFound)
242         {
243             // subtract size of repeat rows from page size
244             tools::ULong nHeights = GetTotalRowHeight(nRepeatStartY, nRepeatEndY);
245 #if OSL_DEBUG_LEVEL > 0
246             if (nHeights == ::std::numeric_limits<tools::ULong>::max())
247                 OSL_FAIL("ScTable::UpdatePageBreaks: row heights overflow");
248 #endif
249             nPageSizeY -= nHeights;
250             if (nY <= nRepeatEndY)
251                 RemoveRowPageBreaks(nY, nRepeatEndY);
252             bRowFound = true;
253         }
254 
255         if (bThisRowHidden)
256         {
257             // Hidden row range.  Skip them unless there is a manual break.
258             SCROW nLastCommon = aIterHidden.getLastPos();
259             if (nNextManualBreak >= 0)
260                 nLastCommon = ::std::min(nLastCommon, nNextManualBreak - 1);
261             nY = nLastCommon;
262         }
263         else
264         {
265             // Visible row range.
266 
267             SCROW nLastHidden = aIterHidden.getLastPos();
268             SCROW nLastHeight = aIterHeights.getLastPos();
269             SCROW nLastCommon = ::std::min(nLastHidden, nLastHeight);
270             if (nNextManualBreak >= 0)
271                 nLastCommon = ::std::min(nLastCommon, nNextManualBreak - 1);
272 
273             if (nLastCommon > nY)
274             {
275                 tools::Long nMaxMultiple = static_cast<tools::Long>(nLastCommon - nY);
276                 tools::Long nMultiple = (nPageSizeY - nSizeY) / nThisY;
277                 if (nMultiple > nMaxMultiple)
278                     nMultiple = nMaxMultiple;
279                 if (nMultiple > 1)
280                 {
281                     nSizeY += nThisY * (nMultiple - 1);
282                     nY += nMultiple - 1;
283                 }
284             }
285         }
286 
287         nSizeY += nThisY;
288     }
289 
290     //  End: Remove Break
291 
292     if (nEndCol < rDocument.MaxCol())
293     {
294         SetColBreak(nEndCol + 1, true, false); // AREABREAK
295         for (SCCOL nCol : GetColumnsRange(nEndCol + 2, rDocument.MaxCol()))
296             RemoveColBreak(nCol, true, false);
297     }
298     if (nEndRow < rDocument.MaxRow())
299     {
300         SetRowBreak(nEndRow + 1, true, false); // AREABREAK
301         if (nEndRow + 2 <= rDocument.MaxRow())
302             RemoveRowPageBreaks(nEndRow + 2, rDocument.MaxRow());
303     }
304     mbPageBreaksValid
305         = !pUserArea; // #i116881# the valid flag can only apply to the "no user area" case
306 }
307 
RemoveManualBreaks()308 void ScTable::RemoveManualBreaks()
309 {
310     maRowManualBreaks.clear();
311     maColManualBreaks.clear();
312     InvalidatePageBreaks();
313 
314     SetStreamValid(false);
315 }
316 
HasManualBreaks() const317 bool ScTable::HasManualBreaks() const
318 {
319     return !maRowManualBreaks.empty() || !maColManualBreaks.empty();
320 }
321 
SetRowManualBreaks(const::std::set<SCROW> & rBreaks)322 void ScTable::SetRowManualBreaks(const ::std::set<SCROW>& rBreaks)
323 {
324     maRowManualBreaks = rBreaks;
325     InvalidatePageBreaks();
326     SetStreamValid(false);
327 }
328 
SetColManualBreaks(const::std::set<SCCOL> & rBreaks)329 void ScTable::SetColManualBreaks(const ::std::set<SCCOL>& rBreaks)
330 {
331     maColManualBreaks = rBreaks;
332     InvalidatePageBreaks();
333     SetStreamValid(false);
334 }
335 
GetAllRowBreaks(set<SCROW> & rBreaks,bool bPage,bool bManual) const336 void ScTable::GetAllRowBreaks(set<SCROW>& rBreaks, bool bPage, bool bManual) const
337 {
338     if (bPage)
339         rBreaks = maRowPageBreaks;
340 
341     if (bManual)
342     {
343         using namespace std;
344         copy(maRowManualBreaks.begin(), maRowManualBreaks.end(),
345              inserter(rBreaks, rBreaks.begin()));
346     }
347 }
348 
GetAllColBreaks(set<SCCOL> & rBreaks,bool bPage,bool bManual) const349 void ScTable::GetAllColBreaks(set<SCCOL>& rBreaks, bool bPage, bool bManual) const
350 {
351     if (bPage)
352         rBreaks = maColPageBreaks;
353 
354     if (bManual)
355     {
356         using namespace std;
357         copy(maColManualBreaks.begin(), maColManualBreaks.end(),
358              inserter(rBreaks, rBreaks.begin()));
359     }
360 }
361 
HasRowPageBreak(SCROW nRow) const362 bool ScTable::HasRowPageBreak(SCROW nRow) const
363 {
364     if (!ValidRow(nRow))
365         return false;
366 
367     return maRowPageBreaks.find(nRow) != maRowPageBreaks.end();
368 }
369 
HasColPageBreak(SCCOL nCol) const370 bool ScTable::HasColPageBreak(SCCOL nCol) const
371 {
372     if (!ValidCol(nCol))
373         return false;
374 
375     return maColPageBreaks.find(nCol) != maColPageBreaks.end();
376 }
377 
HasRowManualBreak(SCROW nRow) const378 bool ScTable::HasRowManualBreak(SCROW nRow) const
379 {
380     if (!ValidRow(nRow))
381         return false;
382 
383     return maRowManualBreaks.find(nRow) != maRowManualBreaks.end();
384 }
385 
HasColManualBreak(SCCOL nCol) const386 bool ScTable::HasColManualBreak(SCCOL nCol) const
387 {
388     if (!ValidCol(nCol))
389         return false;
390 
391     return maColManualBreaks.find(nCol) != maColManualBreaks.end();
392 }
393 
GetNextManualBreak(SCROW nRow) const394 SCROW ScTable::GetNextManualBreak(SCROW nRow) const
395 {
396     set<SCROW>::const_iterator itr = maRowManualBreaks.lower_bound(nRow);
397     return itr == maRowManualBreaks.end() ? -1 : *itr;
398 }
399 
RemoveRowPageBreaks(SCROW nStartRow,SCROW nEndRow)400 void ScTable::RemoveRowPageBreaks(SCROW nStartRow, SCROW nEndRow)
401 {
402     using namespace std;
403 
404     if (!ValidRow(nStartRow) || !ValidRow(nEndRow))
405         return;
406 
407     set<SCROW>::iterator low = maRowPageBreaks.lower_bound(nStartRow);
408     set<SCROW>::iterator high = maRowPageBreaks.upper_bound(nEndRow);
409     maRowPageBreaks.erase(low, high);
410 }
411 
RemoveRowBreak(SCROW nRow,bool bPage,bool bManual)412 void ScTable::RemoveRowBreak(SCROW nRow, bool bPage, bool bManual)
413 {
414     if (!ValidRow(nRow))
415         return;
416 
417     if (bPage)
418         maRowPageBreaks.erase(nRow);
419 
420     if (bManual)
421     {
422         maRowManualBreaks.erase(nRow);
423         InvalidatePageBreaks();
424     }
425 }
426 
RemoveColBreak(SCCOL nCol,bool bPage,bool bManual)427 void ScTable::RemoveColBreak(SCCOL nCol, bool bPage, bool bManual)
428 {
429     if (!ValidCol(nCol))
430         return;
431 
432     if (bPage)
433         maColPageBreaks.erase(nCol);
434 
435     if (bManual)
436     {
437         maColManualBreaks.erase(nCol);
438         InvalidatePageBreaks();
439     }
440 }
441 
SetRowBreak(SCROW nRow,bool bPage,bool bManual)442 void ScTable::SetRowBreak(SCROW nRow, bool bPage, bool bManual)
443 {
444     if (!ValidRow(nRow))
445         return;
446 
447     if (bPage)
448         maRowPageBreaks.insert(nRow);
449 
450     if (bManual)
451     {
452         maRowManualBreaks.insert(nRow);
453         InvalidatePageBreaks();
454     }
455 }
456 
SetColBreak(SCCOL nCol,bool bPage,bool bManual)457 void ScTable::SetColBreak(SCCOL nCol, bool bPage, bool bManual)
458 {
459     if (!ValidCol(nCol))
460         return;
461 
462     if (bPage)
463         maColPageBreaks.insert(nCol);
464 
465     if (bManual)
466     {
467         maColManualBreaks.insert(nCol);
468         InvalidatePageBreaks();
469     }
470 }
471 
GetRowBreakData() const472 Sequence<TablePageBreakData> ScTable::GetRowBreakData() const
473 {
474     using ::std::copy;
475     using ::std::inserter;
476 
477     set<SCROW> aRowBreaks = maRowPageBreaks;
478     copy(maRowManualBreaks.begin(), maRowManualBreaks.end(),
479          inserter(aRowBreaks, aRowBreaks.begin()));
480 
481     sal_Int32 i = 0;
482     Sequence<TablePageBreakData> aSeq(aRowBreaks.size());
483 
484     for (const SCROW nRow : aRowBreaks)
485     {
486         TablePageBreakData aData;
487         aData.Position = nRow;
488         aData.ManualBreak = HasRowManualBreak(nRow);
489         aSeq[i] = aData;
490         ++i;
491     }
492 
493     return aSeq;
494 }
495 
RowHidden(SCROW nRow,SCROW * pFirstRow,SCROW * pLastRow) const496 bool ScTable::RowHidden(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
497 {
498     if (!ValidRow(nRow))
499     {
500         if (pFirstRow)
501             *pFirstRow = nRow;
502         if (pLastRow)
503             *pLastRow = nRow;
504         return true;
505     }
506 
507     ScFlatBoolRowSegments::RangeData aData;
508     if (!mpHiddenRows->getRangeData(nRow, aData))
509     {
510         // search failed.
511         if (pFirstRow)
512             *pFirstRow = nRow;
513         if (pLastRow)
514             *pLastRow = nRow;
515         return true;
516     }
517 
518     if (pFirstRow)
519         *pFirstRow = aData.mnRow1;
520     if (pLastRow)
521         *pLastRow = aData.mnRow2;
522 
523     return aData.mbValue;
524 }
525 
RowHiddenLeaf(SCROW nRow,SCROW * pFirstRow,SCROW * pLastRow) const526 bool ScTable::RowHiddenLeaf(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
527 {
528     if (!ValidRow(nRow))
529     {
530         if (pFirstRow)
531             *pFirstRow = nRow;
532         if (pLastRow)
533             *pLastRow = nRow;
534         return true;
535     }
536 
537     ScFlatBoolRowSegments::RangeData aData;
538     if (!mpHiddenRows->getRangeDataLeaf(nRow, aData))
539     {
540         // search failed.
541         if (pFirstRow)
542             *pFirstRow = nRow;
543         if (pLastRow)
544             *pLastRow = nRow;
545         return true;
546     }
547 
548     if (pFirstRow)
549         *pFirstRow = aData.mnRow1;
550     if (pLastRow)
551         *pLastRow = aData.mnRow2;
552 
553     return aData.mbValue;
554 }
555 
HasHiddenRows(SCROW nStartRow,SCROW nEndRow) const556 bool ScTable::HasHiddenRows(SCROW nStartRow, SCROW nEndRow) const
557 {
558     SCROW nRow = nStartRow;
559     while (nRow <= nEndRow)
560     {
561         SCROW nLastRow = -1;
562         bool bHidden = RowHidden(nRow, nullptr, &nLastRow);
563         if (bHidden)
564             return true;
565 
566         nRow = nLastRow + 1;
567     }
568     return false;
569 }
570 
ColHidden(SCCOL nCol,SCCOL * pFirstCol,SCCOL * pLastCol) const571 bool ScTable::ColHidden(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const
572 {
573     if (!ValidCol(nCol))
574         return true;
575 
576     ScFlatBoolColSegments::RangeData aData;
577     if (!mpHiddenCols->getRangeData(nCol, aData))
578         return true;
579 
580     if (pFirstCol)
581         *pFirstCol = aData.mnCol1;
582     if (pLastCol)
583         *pLastCol = aData.mnCol2;
584 
585     return aData.mbValue;
586 }
587 
SetRowHidden(SCROW nStartRow,SCROW nEndRow,bool bHidden)588 bool ScTable::SetRowHidden(SCROW nStartRow, SCROW nEndRow, bool bHidden)
589 {
590     bool bChanged = false;
591     if (bHidden)
592         bChanged = mpHiddenRows->setTrue(nStartRow, nEndRow);
593     else
594         bChanged = mpHiddenRows->setFalse(nStartRow, nEndRow);
595 
596     // Cell anchored objects might change visibility
597     ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
598     if (pDrawLayer)
599     {
600         std::vector<SdrObject*> aRowDrawObjects;
601         aRowDrawObjects = pDrawLayer->GetObjectsAnchoredToRows(GetTab(), nStartRow, nEndRow);
602         for (auto aObj : aRowDrawObjects)
603         {
604             ScDrawObjData* pData = ScDrawLayer::GetObjData(aObj);
605             if (pData)
606             {
607                 if (bHidden)
608                     aObj->SetVisible(false);
609                 else if (!GetDoc().ColHidden(pData->maStart.Col(), pData->maStart.Tab()))
610                 {
611                     // Only change visibility if object is not hidden by a hidden col
612                     aObj->SetVisible(true);
613                 }
614             }
615         }
616     }
617 
618     if (bChanged)
619     {
620         SetStreamValid(false);
621 
622         { // Scoped bulk broadcast.
623             // Only subtotal formula cells will accept the notification of
624             // SfxHintId::ScHiddenRowsChanged, leaving the bulk will track
625             // those and broadcast SfxHintId::ScDataChanged to notify all
626             // dependents.
627             ScBulkBroadcast aBulkBroadcast(rDocument.GetBASM(), SfxHintId::ScDataChanged);
628             for (SCCOL i = 0; i < aCol.size(); i++)
629             {
630                 aCol[i].BroadcastRows(nStartRow, nEndRow, SfxHintId::ScHiddenRowsChanged);
631             }
632         }
633     }
634 
635     return bChanged;
636 }
637 
SetColHidden(SCCOL nStartCol,SCCOL nEndCol,bool bHidden)638 void ScTable::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, bool bHidden)
639 {
640     bool bChanged = false;
641     if (bHidden)
642         bChanged = mpHiddenCols->setTrue(nStartCol, nEndCol);
643     else
644         bChanged = mpHiddenCols->setFalse(nStartCol, nEndCol);
645 
646     // Cell anchored objects might change visibility
647     ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
648     if (pDrawLayer)
649     {
650         std::vector<SdrObject*> aColDrawObjects;
651         aColDrawObjects = pDrawLayer->GetObjectsAnchoredToCols(GetTab(), nStartCol, nEndCol);
652         for (auto aObj : aColDrawObjects)
653         {
654             ScDrawObjData* pData = ScDrawLayer::GetObjData(aObj);
655             if (pData)
656             {
657                 if (bHidden)
658                     aObj->SetVisible(false);
659                 else if (!GetDoc().RowHidden(pData->maStart.Row(), pData->maStart.Tab()))
660                 {
661                     // Only change visibility if object is not hidden by a hidden row
662                     aObj->SetVisible(true);
663                 }
664             }
665         }
666     }
667 
668     if (bChanged)
669         SetStreamValid(false);
670 }
671 
CopyColHidden(const ScTable & rTable,SCCOL nStartCol,SCCOL nEndCol)672 void ScTable::CopyColHidden(const ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol)
673 {
674     SCCOL nCol = nStartCol;
675     while (nCol <= nEndCol)
676     {
677         SCCOL nLastCol = -1;
678         bool bHidden = rTable.ColHidden(nCol, nullptr, &nLastCol);
679         if (nLastCol > nEndCol)
680             nLastCol = nEndCol;
681 
682         SetColHidden(nCol, nLastCol, bHidden);
683         nCol = nLastCol + 1;
684     }
685 }
686 
CopyRowHidden(const ScTable & rTable,SCROW nStartRow,SCROW nEndRow)687 void ScTable::CopyRowHidden(const ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
688 {
689     SCROW nRow = nStartRow;
690     while (nRow <= nEndRow)
691     {
692         SCROW nLastRow = -1;
693         bool bHidden = rTable.RowHidden(nRow, nullptr, &nLastRow);
694         if (nLastRow > nEndRow)
695             nLastRow = nEndRow;
696         SetRowHidden(nRow, nLastRow, bHidden);
697         nRow = nLastRow + 1;
698     }
699 }
700 
CopyRowHeight(const ScTable & rSrcTable,SCROW nStartRow,SCROW nEndRow,SCROW nSrcOffset)701 void ScTable::CopyRowHeight(const ScTable& rSrcTable, SCROW nStartRow, SCROW nEndRow,
702                             SCROW nSrcOffset)
703 {
704     SCROW nRow = nStartRow;
705     ScFlatUInt16RowSegments::RangeData aSrcData;
706     while (nRow <= nEndRow)
707     {
708         if (!rSrcTable.mpRowHeights->getRangeData(nRow + nSrcOffset, aSrcData))
709             // Something is wrong !
710             return;
711 
712         SCROW nLastRow = aSrcData.mnRow2 - nSrcOffset;
713         if (nLastRow > nEndRow)
714             nLastRow = nEndRow;
715 
716         mpRowHeights->setValue(nRow, nLastRow, aSrcData.mnValue);
717         nRow = nLastRow + 1;
718     }
719 }
720 
FirstVisibleRow(SCROW nStartRow,SCROW nEndRow) const721 SCROW ScTable::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow) const
722 {
723     SCROW nRow = nStartRow;
724     ScFlatBoolRowSegments::RangeData aData;
725     while (nRow <= nEndRow)
726     {
727         if (!ValidRow(nRow))
728             break;
729 
730         if (!mpHiddenRows->getRangeData(nRow, aData))
731             // failed to get range data.
732             break;
733 
734         if (!aData.mbValue)
735             // visible row found
736             return nRow;
737 
738         nRow = aData.mnRow2 + 1;
739     }
740 
741     return ::std::numeric_limits<SCROW>::max();
742 }
743 
LastVisibleRow(SCROW nStartRow,SCROW nEndRow) const744 SCROW ScTable::LastVisibleRow(SCROW nStartRow, SCROW nEndRow) const
745 {
746     SCROW nRow = nEndRow;
747     ScFlatBoolRowSegments::RangeData aData;
748     while (nRow >= nStartRow)
749     {
750         if (!ValidRow(nRow))
751             break;
752 
753         if (!mpHiddenRows->getRangeData(nRow, aData))
754             // failed to get range data.
755             break;
756 
757         if (!aData.mbValue)
758             // visible row found
759             return nRow;
760 
761         nRow = aData.mnRow1 - 1;
762     }
763 
764     return ::std::numeric_limits<SCROW>::max();
765 }
766 
CountVisibleRows(SCROW nStartRow,SCROW nEndRow) const767 SCROW ScTable::CountVisibleRows(SCROW nStartRow, SCROW nEndRow) const
768 {
769     SCROW nCount = 0;
770     SCROW nRow = nStartRow;
771     ScFlatBoolRowSegments::RangeData aData;
772     while (nRow <= nEndRow)
773     {
774         if (!mpHiddenRows->getRangeData(nRow, aData))
775             break;
776 
777         if (aData.mnRow2 > nEndRow)
778             aData.mnRow2 = nEndRow;
779 
780         if (!aData.mbValue)
781             nCount += aData.mnRow2 - nRow + 1;
782 
783         nRow = aData.mnRow2 + 1;
784     }
785     return nCount;
786 }
787 
GetTotalRowHeight(SCROW nStartRow,SCROW nEndRow,bool bHiddenAsZero) const788 sal_uInt32 ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZero) const
789 {
790     sal_uInt32 nHeight = 0;
791     SCROW nRow = nStartRow;
792     ScFlatBoolRowSegments::RangeData aData;
793     while (nRow <= nEndRow)
794     {
795         if (!mpHiddenRows->getRangeData(nRow, aData))
796             break;
797 
798         if (aData.mnRow2 > nEndRow)
799             aData.mnRow2 = nEndRow;
800 
801         if (!(bHiddenAsZero && aData.mbValue))
802             // visible row range.
803             nHeight += mpRowHeights->getSumValue(nRow, aData.mnRow2);
804 
805         nRow = aData.mnRow2 + 1;
806     }
807 
808     return nHeight;
809 }
810 
LastHiddenColRow(SCCOLROW nPos,bool bCol) const811 SCCOLROW ScTable::LastHiddenColRow(SCCOLROW nPos, bool bCol) const
812 {
813     if (bCol)
814     {
815         SCCOL nCol = static_cast<SCCOL>(nPos);
816         if (ColHidden(nCol))
817         {
818             for (SCCOL i = nCol + 1; i <= rDocument.MaxCol(); ++i)
819             {
820                 if (!ColHidden(i))
821                     return i - 1;
822             }
823         }
824     }
825     else
826     {
827         SCROW nRow = static_cast<SCROW>(nPos);
828         SCROW nLastRow;
829         if (RowHidden(nRow, nullptr, &nLastRow))
830             return static_cast<SCCOLROW>(nLastRow);
831     }
832     return ::std::numeric_limits<SCCOLROW>::max();
833 }
834 
RowFiltered(SCROW nRow,SCROW * pFirstRow,SCROW * pLastRow) const835 bool ScTable::RowFiltered(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const
836 {
837     if (!ValidRow(nRow))
838         return false;
839 
840     ScFlatBoolRowSegments::RangeData aData;
841     if (!mpFilteredRows->getRangeData(nRow, aData))
842         // search failed.
843         return false;
844 
845     if (pFirstRow)
846         *pFirstRow = aData.mnRow1;
847     if (pLastRow)
848         *pLastRow = aData.mnRow2;
849 
850     return aData.mbValue;
851 }
852 
ColFiltered(SCCOL nCol,SCCOL * pFirstCol,SCCOL * pLastCol) const853 bool ScTable::ColFiltered(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const
854 {
855     if (!ValidCol(nCol))
856         return false;
857 
858     ScFlatBoolColSegments::RangeData aData;
859     if (!mpFilteredCols->getRangeData(nCol, aData))
860         // search failed.
861         return false;
862 
863     if (pFirstCol)
864         *pFirstCol = aData.mnCol1;
865     if (pLastCol)
866         *pLastCol = aData.mnCol2;
867 
868     return aData.mbValue;
869 }
870 
HasFilteredRows(SCROW nStartRow,SCROW nEndRow) const871 bool ScTable::HasFilteredRows(SCROW nStartRow, SCROW nEndRow) const
872 {
873     SCROW nRow = nStartRow;
874     while (nRow <= nEndRow)
875     {
876         SCROW nLastRow = nRow;
877         bool bFiltered = RowFiltered(nRow, nullptr, &nLastRow);
878         if (bFiltered)
879             return true;
880 
881         nRow = nLastRow + 1;
882     }
883     return false;
884 }
885 
CopyColFiltered(const ScTable & rTable,SCCOL nStartCol,SCCOL nEndCol)886 void ScTable::CopyColFiltered(const ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol)
887 {
888     SCCOL nCol = nStartCol;
889     while (nCol <= nEndCol)
890     {
891         SCCOL nLastCol = -1;
892         bool bFiltered = rTable.ColFiltered(nCol, nullptr, &nLastCol);
893         if (nLastCol > nEndCol)
894             nLastCol = nEndCol;
895 
896         SetColFiltered(nCol, nLastCol, bFiltered);
897         nCol = nLastCol + 1;
898     }
899 }
900 
CopyRowFiltered(const ScTable & rTable,SCROW nStartRow,SCROW nEndRow)901 void ScTable::CopyRowFiltered(const ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
902 {
903     SCROW nRow = nStartRow;
904     while (nRow <= nEndRow)
905     {
906         SCROW nLastRow = -1;
907         bool bFiltered = rTable.RowFiltered(nRow, nullptr, &nLastRow);
908         if (nLastRow > nEndRow)
909             nLastRow = nEndRow;
910         SetRowFiltered(nRow, nLastRow, bFiltered);
911         nRow = nLastRow + 1;
912     }
913 }
914 
SetRowFiltered(SCROW nStartRow,SCROW nEndRow,bool bFiltered)915 void ScTable::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, bool bFiltered)
916 {
917     if (bFiltered)
918         mpFilteredRows->setTrue(nStartRow, nEndRow);
919     else
920         mpFilteredRows->setFalse(nStartRow, nEndRow);
921 }
922 
SetColFiltered(SCCOL nStartCol,SCCOL nEndCol,bool bFiltered)923 void ScTable::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, bool bFiltered)
924 {
925     if (bFiltered)
926         mpFilteredCols->setTrue(nStartCol, nEndCol);
927     else
928         mpFilteredCols->setFalse(nStartCol, nEndCol);
929 }
930 
FirstNonFilteredRow(SCROW nStartRow,SCROW nEndRow) const931 SCROW ScTable::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const
932 {
933     SCROW nRow = nStartRow;
934     ScFlatBoolRowSegments::RangeData aData;
935     while (nRow <= nEndRow)
936     {
937         if (!ValidRow(nRow))
938             break;
939 
940         if (!mpFilteredRows->getRangeData(nRow, aData))
941             // failed to get range data.
942             break;
943 
944         if (!aData.mbValue)
945             // non-filtered row found
946             return nRow;
947 
948         nRow = aData.mnRow2 + 1;
949     }
950 
951     return ::std::numeric_limits<SCROW>::max();
952 }
953 
LastNonFilteredRow(SCROW nStartRow,SCROW nEndRow) const954 SCROW ScTable::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const
955 {
956     SCROW nRow = nEndRow;
957     ScFlatBoolRowSegments::RangeData aData;
958     while (nRow >= nStartRow)
959     {
960         if (!ValidRow(nRow))
961             break;
962 
963         if (!mpFilteredRows->getRangeData(nRow, aData))
964             // failed to get range data.
965             break;
966 
967         if (!aData.mbValue)
968             // non-filtered row found
969             return nRow;
970 
971         nRow = aData.mnRow1 - 1;
972     }
973 
974     return ::std::numeric_limits<SCROW>::max();
975 }
976 
CountNonFilteredRows(SCROW nStartRow,SCROW nEndRow) const977 SCROW ScTable::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow) const
978 {
979     SCROW nCount = 0;
980     SCROW nRow = nStartRow;
981     ScFlatBoolRowSegments::RangeData aData;
982     while (nRow <= nEndRow)
983     {
984         if (!mpFilteredRows->getRangeData(nRow, aData))
985             break;
986 
987         if (aData.mnRow2 > nEndRow)
988             aData.mnRow2 = nEndRow;
989 
990         if (!aData.mbValue)
991             nCount += aData.mnRow2 - nRow + 1;
992 
993         nRow = aData.mnRow2 + 1;
994     }
995     return nCount;
996 }
997 
IsManualRowHeight(SCROW nRow) const998 bool ScTable::IsManualRowHeight(SCROW nRow) const
999 {
1000     return bool(pRowFlags->GetValue(nRow) & CRFlags::ManualSize);
1001 }
1002 
1003 namespace
1004 {
lcl_syncFlags(const ScDocument * pDocument,ScFlatBoolColSegments & rColSegments,const ScFlatBoolRowSegments & rRowSegments,ScBitMaskCompressedArray<SCCOL,CRFlags> * pColFlags,ScBitMaskCompressedArray<SCROW,CRFlags> * pRowFlags,const CRFlags nFlagMask)1005 void lcl_syncFlags(const ScDocument* pDocument, ScFlatBoolColSegments& rColSegments,
1006                    const ScFlatBoolRowSegments& rRowSegments,
1007                    ScBitMaskCompressedArray<SCCOL, CRFlags>* pColFlags,
1008                    ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlags, const CRFlags nFlagMask)
1009 {
1010     using ::sal::static_int_cast;
1011 
1012     CRFlags nFlagMaskComplement = ~nFlagMask;
1013 
1014     pRowFlags->AndValue(0, pDocument->MaxRow(), nFlagMaskComplement);
1015     pColFlags->AndValue(0, pDocument->MaxCol() + 1, nFlagMaskComplement);
1016 
1017     {
1018         // row hidden flags.
1019 
1020         SCROW nRow = 0;
1021         ScFlatBoolRowSegments::RangeData aData;
1022         while (nRow <= pDocument->MaxRow())
1023         {
1024             if (!rRowSegments.getRangeData(nRow, aData))
1025                 break;
1026 
1027             if (aData.mbValue)
1028                 pRowFlags->OrValue(nRow, aData.mnRow2, nFlagMask);
1029 
1030             nRow = aData.mnRow2 + 1;
1031         }
1032     }
1033 
1034     {
1035         // column hidden flags.
1036 
1037         SCCOL nCol = 0;
1038         ScFlatBoolColSegments::RangeData aData;
1039         while (nCol <= pDocument->MaxCol())
1040         {
1041             if (!rColSegments.getRangeData(nCol, aData))
1042                 break;
1043 
1044             if (aData.mbValue)
1045                 pColFlags->OrValue(nCol, aData.mnCol2, nFlagMask);
1046 
1047             nCol = aData.mnCol2 + 1;
1048         }
1049     }
1050 }
1051 }
1052 
SyncColRowFlags()1053 void ScTable::SyncColRowFlags()
1054 {
1055     CRFlags nManualBreakComplement = ~CRFlags::ManualBreak;
1056 
1057     // Manual breaks.
1058     pRowFlags->AndValue(0, rDocument.MaxRow(), nManualBreakComplement);
1059     mpColFlags->AndValue(0, rDocument.MaxCol() + 1, nManualBreakComplement);
1060 
1061     for (const auto& rBreakPos : maRowManualBreaks)
1062         pRowFlags->OrValue(rBreakPos, CRFlags::ManualBreak);
1063 
1064     for (const auto& rBreakPos : maColManualBreaks)
1065         mpColFlags->OrValue(rBreakPos, CRFlags::ManualBreak);
1066 
1067     // Hidden flags.
1068     lcl_syncFlags(&rDocument, *mpHiddenCols, *mpHiddenRows, mpColFlags.get(), pRowFlags.get(),
1069                   CRFlags::Hidden);
1070     lcl_syncFlags(&rDocument, *mpFilteredCols, *mpFilteredRows, mpColFlags.get(), pRowFlags.get(),
1071                   CRFlags::Filtered);
1072 }
1073 
SetPageSize(const Size & rSize)1074 void ScTable::SetPageSize(const Size& rSize)
1075 {
1076     if (!rSize.IsEmpty())
1077     {
1078         if (aPageSizeTwips != rSize)
1079             InvalidatePageBreaks();
1080 
1081         bPageSizeValid = true;
1082         aPageSizeTwips = rSize;
1083     }
1084     else
1085         bPageSizeValid = false;
1086 }
1087 
IsProtected() const1088 bool ScTable::IsProtected() const { return pTabProtection && pTabProtection->isProtected(); }
1089 
SetProtection(const ScTableProtection * pProtect)1090 void ScTable::SetProtection(const ScTableProtection* pProtect)
1091 {
1092     if (pProtect)
1093         pTabProtection.reset(new ScTableProtection(*pProtect));
1094     else
1095         pTabProtection.reset();
1096 
1097     SetStreamValid(false);
1098 }
1099 
GetProtection() const1100 const ScTableProtection* ScTable::GetProtection() const { return pTabProtection.get(); }
1101 
GetPageSize() const1102 Size ScTable::GetPageSize() const
1103 {
1104     if (bPageSizeValid)
1105         return aPageSizeTwips;
1106     else
1107         return Size(); // blank
1108 }
1109 
SetRepeatArea(SCCOL nStartCol,SCCOL nEndCol,SCROW nStartRow,SCROW nEndRow)1110 void ScTable::SetRepeatArea(SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow)
1111 {
1112     // #i117952# page break calculation uses these values (set from ScPrintFunc), not pRepeatColRange/pRepeatRowRange
1113     if (nStartCol != nRepeatStartX || nEndCol != nRepeatEndX || nStartRow != nRepeatStartY
1114         || nEndRow != nRepeatEndY)
1115         InvalidatePageBreaks();
1116 
1117     nRepeatStartX = nStartCol;
1118     nRepeatEndX = nEndCol;
1119     nRepeatStartY = nStartRow;
1120     nRepeatEndY = nEndRow;
1121 }
1122 
StartListening(const ScAddress & rAddress,SvtListener * pListener)1123 void ScTable::StartListening(const ScAddress& rAddress, SvtListener* pListener)
1124 {
1125     if (!ValidCol(rAddress.Col()))
1126         return;
1127 
1128     CreateColumnIfNotExists(rAddress.Col()).StartListening(*pListener, rAddress.Row());
1129 }
1130 
EndListening(const ScAddress & rAddress,SvtListener * pListener)1131 void ScTable::EndListening(const ScAddress& rAddress, SvtListener* pListener)
1132 {
1133     if (!ValidCol(rAddress.Col()))
1134         return;
1135 
1136     if (rAddress.Col() < aCol.size())
1137         aCol[rAddress.Col()].EndListening(*pListener, rAddress.Row());
1138 }
1139 
StartListening(sc::StartListeningContext & rCxt,const ScAddress & rAddress,SvtListener & rListener)1140 void ScTable::StartListening(sc::StartListeningContext& rCxt, const ScAddress& rAddress,
1141                              SvtListener& rListener)
1142 {
1143     if (!ValidCol(rAddress.Col()))
1144         return;
1145 
1146     CreateColumnIfNotExists(rAddress.Col()).StartListening(rCxt, rAddress, rListener);
1147 }
1148 
EndListening(sc::EndListeningContext & rCxt,const ScAddress & rAddress,SvtListener & rListener)1149 void ScTable::EndListening(sc::EndListeningContext& rCxt, const ScAddress& rAddress,
1150                            SvtListener& rListener)
1151 {
1152     if (!ValidCol(rAddress.Col()))
1153         return;
1154 
1155     if (rAddress.Col() < aCol.size())
1156         aCol[rAddress.Col()].EndListening(rCxt, rAddress, rListener);
1157 }
1158 
SetPageStyle(const OUString & rName)1159 void ScTable::SetPageStyle(const OUString& rName)
1160 {
1161     if (aPageStyle == rName)
1162         return;
1163 
1164     OUString aStrNew = rName;
1165     SfxStyleSheetBasePool* pStylePool = rDocument.GetStyleSheetPool();
1166     SfxStyleSheetBase* pNewStyle = pStylePool->Find(aStrNew, SfxStyleFamily::Page);
1167 
1168     if (!pNewStyle)
1169     {
1170         aStrNew = ScResId(STR_STYLENAME_STANDARD);
1171         pNewStyle = pStylePool->Find(aStrNew, SfxStyleFamily::Page);
1172     }
1173 
1174     if (aPageStyle == aStrNew)
1175         return;
1176 
1177     SfxStyleSheetBase* pOldStyle = pStylePool->Find(aPageStyle, SfxStyleFamily::Page);
1178     if (pOldStyle && pNewStyle)
1179     {
1180         SfxItemSet& rOldSet = pOldStyle->GetItemSet();
1181         SfxItemSet& rNewSet = pNewStyle->GetItemSet();
1182         auto getScaleValue = [](const SfxItemSet& rSet, sal_uInt16 nId) {
1183             return static_cast<const SfxUInt16Item&>(rSet.Get(nId)).GetValue();
1184         };
1185 
1186         const sal_uInt16 nOldScale = getScaleValue(rOldSet, ATTR_PAGE_SCALE);
1187         const sal_uInt16 nOldScaleToPages = getScaleValue(rOldSet, ATTR_PAGE_SCALETOPAGES);
1188         const sal_uInt16 nNewScale = getScaleValue(rNewSet, ATTR_PAGE_SCALE);
1189         const sal_uInt16 nNewScaleToPages = getScaleValue(rNewSet, ATTR_PAGE_SCALETOPAGES);
1190 
1191         if ((nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages))
1192             InvalidateTextWidth(nullptr, nullptr, false, false);
1193     }
1194 
1195     if (pNewStyle) // also without the old one (for UpdateStdNames)
1196         aPageStyle = aStrNew;
1197 
1198     SetStreamValid(false);
1199 }
1200 
PageStyleModified(const OUString & rNewName)1201 void ScTable::PageStyleModified(const OUString& rNewName)
1202 {
1203     aPageStyle = rNewName;
1204     InvalidateTextWidth(nullptr, nullptr, false, false); // don't know what was in the style before
1205 }
1206 
InvalidateTextWidth(const ScAddress * pAdrFrom,const ScAddress * pAdrTo,bool bNumFormatChanged,bool bBroadcast)1207 void ScTable::InvalidateTextWidth(const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
1208                                   bool bNumFormatChanged, bool bBroadcast)
1209 {
1210     if (pAdrFrom && !pAdrTo)
1211     {
1212         // Special case: only process the "from" cell.
1213         SCCOL nCol = pAdrFrom->Col();
1214         SCROW nRow = pAdrFrom->Row();
1215         if (nCol >= aCol.size())
1216             return;
1217         ScColumn& rCol = aCol[nCol];
1218         ScRefCellValue aCell = rCol.GetCellValue(nRow);
1219         if (aCell.isEmpty())
1220             return;
1221 
1222         rCol.SetTextWidth(nRow, TEXTWIDTH_DIRTY);
1223 
1224         if (bNumFormatChanged)
1225             rCol.SetScriptType(nRow, SvtScriptType::UNKNOWN);
1226 
1227         if (bBroadcast)
1228         { // Only with CalcAsShown
1229             switch (aCell.meType)
1230             {
1231                 case CELLTYPE_VALUE:
1232                     rCol.Broadcast(nRow);
1233                     break;
1234                 case CELLTYPE_FORMULA:
1235                     aCell.mpFormula->SetDirty();
1236                     break;
1237                 default:
1238                 {
1239                     // added to avoid warnings
1240                 }
1241             }
1242         }
1243 
1244         return;
1245     }
1246 
1247     const SCCOL nCol1 = pAdrFrom ? pAdrFrom->Col() : 0;
1248     const SCROW nRow1 = pAdrFrom ? pAdrFrom->Row() : 0;
1249     const SCCOL nCol2 = pAdrTo ? pAdrTo->Col() : aCol.size() - 1;
1250     const SCROW nRow2 = pAdrTo ? pAdrTo->Row() : rDocument.MaxRow();
1251 
1252     for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1253     {
1254         ScColumnTextWidthIterator aIter(GetDoc(), aCol[nCol], nRow1, nRow2);
1255         sc::ColumnBlockPosition blockPos; // cache mdds position
1256         InitColumnBlockPosition(blockPos, nCol);
1257 
1258         for (; aIter.hasCell(); aIter.next())
1259         {
1260             SCROW nRow = aIter.getPos();
1261             aIter.setValue(TEXTWIDTH_DIRTY);
1262             ScRefCellValue aCell = aCol[nCol].GetCellValue(blockPos, nRow);
1263             if (aCell.isEmpty())
1264                 continue;
1265 
1266             if (bNumFormatChanged)
1267                 aCol[nCol].SetScriptType(nRow, SvtScriptType::UNKNOWN);
1268 
1269             if (bBroadcast)
1270             { // Only with CalcAsShown
1271                 switch (aCell.meType)
1272                 {
1273                     case CELLTYPE_VALUE:
1274                         aCol[nCol].Broadcast(nRow);
1275                         break;
1276                     case CELLTYPE_FORMULA:
1277                         aCell.mpFormula->SetDirty();
1278                         break;
1279                     default:
1280                     {
1281                         // added to avoid warnings
1282                     }
1283                 }
1284             }
1285         }
1286     }
1287 }
1288 
1289 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1290