1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 .
23 #include <patattr.hxx>
24 #include <docpool.hxx>
25 #include <formulacell.hxx>
26 #include <document.hxx>
27 #include <drwlayer.hxx>
28 #include <olinetab.hxx>
29 #include <stlpool.hxx>
30 #include <attarray.hxx>
31 #include <markdata.hxx>
32 #include <dociter.hxx>
33 #include <conditio.hxx>
34 #include <chartlis.hxx>
35 #include <fillinfo.hxx>
36 #include <bcaslot.hxx>
38 #include <sheetevents.hxx>
39 #include <segmenttree.hxx>
41 #include <tokenarray.hxx>
42 #include <clipcontext.hxx>
44 #include <editutil.hxx>
45 #include <mtvcellfunc.hxx>
46 #include <refupdatecontext.hxx>
47 #include <scopetools.hxx>
48 #include <tabprotection.hxx>
49 #include <columnspanset.hxx>
50 #include <rowheightcontext.hxx>
51 #include <listenercontext.hxx>
52 #include <compressedarray.hxx>
54 #include <refdata.hxx>
57 #include <scitems.hxx>
58 #include <editeng/boxitem.hxx>
59 #include <editeng/editobj.hxx>
60 #include <o3tl/safeint.hxx>
61 #include <o3tl/unit_conversion.hxx>
62 #include <osl/diagnose.h>
63 #include <svl/poolcach.hxx>
64 #include <unotools/charclass.hxx>
69 class ColumnRegroupFormulaCells
71 ScColContainer
& mrCols
;
72 std::vector
<ScAddress
>* mpGroupPos
;
75 ColumnRegroupFormulaCells( ScColContainer
& rCols
, std::vector
<ScAddress
>* pGroupPos
) :
76 mrCols(rCols
), mpGroupPos(pGroupPos
) {}
78 void operator() (SCCOL nCol
)
80 mrCols
[nCol
].RegroupFormulaCells(mpGroupPos
);
86 sal_uInt16
ScTable::GetTextWidth(SCCOL nCol
, SCROW nRow
) const
88 return aCol
[nCol
].GetTextWidth(nRow
);
91 bool ScTable::SetOutlineTable( const ScOutlineTable
* pNewOutline
)
93 sal_uInt16 nOldSizeX
= 0;
94 sal_uInt16 nOldSizeY
= 0;
95 sal_uInt16 nNewSizeX
= 0;
96 sal_uInt16 nNewSizeY
= 0;
100 nOldSizeX
= pOutlineTable
->GetColArray().GetDepth();
101 nOldSizeY
= pOutlineTable
->GetRowArray().GetDepth();
102 pOutlineTable
.reset();
107 pOutlineTable
.reset(new ScOutlineTable( *pNewOutline
));
108 nNewSizeX
= pOutlineTable
->GetColArray().GetDepth();
109 nNewSizeY
= pOutlineTable
->GetRowArray().GetDepth();
112 return ( nNewSizeX
!= nOldSizeX
|| nNewSizeY
!= nOldSizeY
); // changed size?
115 void ScTable::StartOutlineTable()
118 pOutlineTable
.reset(new ScOutlineTable
);
121 void ScTable::SetSheetEvents( std::unique_ptr
<ScSheetEvents
> pNew
)
123 pSheetEvents
= std::move(pNew
);
125 SetCalcNotification( false ); // discard notifications before the events were set
127 SetStreamValid(false);
130 void ScTable::SetCalcNotification( bool bSet
)
132 bCalcNotification
= bSet
;
135 bool ScTable::TestInsertRow( SCCOL nStartCol
, SCCOL nEndCol
, SCROW nStartRow
, SCSIZE nSize
) const
139 if ( nStartCol
==0 && nEndCol
==rDocument
.MaxCol() && pOutlineTable
)
140 bTest
= pOutlineTable
->TestInsertRow(nSize
);
142 for (SCCOL i
=nStartCol
; (i
<=nEndCol
) && bTest
; i
++)
143 bTest
= CreateColumnIfNotExists(i
).TestInsertRow(nStartRow
, nSize
);
148 void ScTable::InsertRow( SCCOL nStartCol
, SCCOL nEndCol
, SCROW nStartRow
, SCSIZE nSize
)
150 if (nStartCol
==0 && nEndCol
==rDocument
.MaxCol())
152 if (mpRowHeights
&& pRowFlags
)
154 mpRowHeights
->insertSegment(nStartRow
, nSize
);
155 CRFlags nNewFlags
= pRowFlags
->Insert( nStartRow
, nSize
);
156 // only copy manual size flag, clear all others
157 if (nNewFlags
!= CRFlags::NONE
&& (nNewFlags
!= CRFlags::ManualSize
))
158 pRowFlags
->SetValue( nStartRow
, nStartRow
+ nSize
- 1,
159 nNewFlags
& CRFlags::ManualSize
);
163 pOutlineTable
->InsertRow( nStartRow
, nSize
);
165 mpFilteredRows
->insertSegment(nStartRow
, nSize
);
166 mpHiddenRows
->insertSegment(nStartRow
, nSize
);
168 if (!maRowManualBreaks
.empty())
170 // Copy all breaks up to nStartRow (non-inclusive).
171 ::std::set
<SCROW
>::iterator itr1
= maRowManualBreaks
.lower_bound(nStartRow
);
172 ::std::set
<SCROW
> aNewBreaks(maRowManualBreaks
.begin(), itr1
);
174 // Copy all breaks from nStartRow (inclusive) to the last element,
175 // but add nSize to each value.
176 ::std::set
<SCROW
>::iterator itr2
= maRowManualBreaks
.end();
177 for (; itr1
!= itr2
; ++itr1
)
178 aNewBreaks
.insert(static_cast<SCROW
>(*itr1
+ nSize
));
180 maRowManualBreaks
.swap(aNewBreaks
);
184 for (SCCOL j
=nStartCol
; j
<=nEndCol
; j
++)
185 aCol
[j
].InsertRow( nStartRow
, nSize
);
187 mpCondFormatList
->InsertRow(nTab
, nStartCol
, nEndCol
, nStartRow
, nSize
);
189 InvalidatePageBreaks();
191 // TODO: In the future we may want to check if the table has been
192 // really modified before setting the stream invalid.
193 SetStreamValid(false);
196 void ScTable::DeleteRow(
197 const sc::ColumnSet
& rRegroupCols
, SCCOL nStartCol
, SCCOL nEndCol
, SCROW nStartRow
, SCSIZE nSize
,
198 bool* pUndoOutline
, std::vector
<ScAddress
>* pGroupPos
)
200 if (nStartCol
==0 && nEndCol
==rDocument
.MaxCol())
203 pRowFlags
->Remove( nStartRow
, nSize
);
206 mpRowHeights
->removeSegment(nStartRow
, nStartRow
+nSize
);
209 if (pOutlineTable
->DeleteRow( nStartRow
, nSize
))
211 *pUndoOutline
= true;
213 mpFilteredRows
->removeSegment(nStartRow
, nStartRow
+nSize
);
214 mpHiddenRows
->removeSegment(nStartRow
, nStartRow
+nSize
);
216 if (!maRowManualBreaks
.empty())
218 // Erase all manual breaks between nStartRow and nStartRow + nSize - 1 (inclusive).
219 std::set
<SCROW
>::iterator itr1
= maRowManualBreaks
.lower_bound(nStartRow
);
220 std::set
<SCROW
>::iterator itr2
= maRowManualBreaks
.upper_bound(static_cast<SCROW
>(nStartRow
+ nSize
- 1));
221 maRowManualBreaks
.erase(itr1
, itr2
);
223 // Copy all breaks from the 1st element up to nStartRow to the new container.
224 itr1
= maRowManualBreaks
.lower_bound(nStartRow
);
225 ::std::set
<SCROW
> aNewBreaks(maRowManualBreaks
.begin(), itr1
);
227 // Copy all breaks from nStartRow to the last element, but subtract each value by nSize.
228 itr2
= maRowManualBreaks
.end();
229 for (; itr1
!= itr2
; ++itr1
)
230 aNewBreaks
.insert(static_cast<SCROW
>(*itr1
- nSize
));
232 maRowManualBreaks
.swap(aNewBreaks
);
236 { // scope for bulk broadcast
237 ScBulkBroadcast
aBulkBroadcast( rDocument
.GetBASM(), SfxHintId::ScDataChanged
);
238 for (SCCOL j
=nStartCol
; j
<=nEndCol
; j
++)
239 aCol
[j
].DeleteRow(nStartRow
, nSize
, pGroupPos
);
242 std::vector
<SCCOL
> aRegroupCols
;
243 rRegroupCols
.getColumns(nTab
, aRegroupCols
);
245 aRegroupCols
.begin(), aRegroupCols
.end(), ColumnRegroupFormulaCells(aCol
, pGroupPos
));
247 InvalidatePageBreaks();
249 // TODO: In the future we may want to check if the table has been
250 // really modified before setting the stream invalid.
251 SetStreamValid(false);
254 bool ScTable::TestInsertCol( SCROW nStartRow
, SCROW nEndRow
, SCSIZE nSize
) const
256 if ( nSize
> o3tl::make_unsigned(rDocument
.MaxCol()) )
259 if ( nStartRow
==0 && nEndRow
==rDocument
.MaxRow() && pOutlineTable
260 && ! pOutlineTable
->TestInsertCol(nSize
) )
263 auto range
= GetColumnsRange( rDocument
.MaxCol() - static_cast<SCCOL
>(nSize
) + 1, rDocument
.MaxCol() );
264 for (auto it
= range
.rbegin(); it
!= range
.rend(); ++it
)
265 if (! aCol
[*it
].TestInsertCol(nStartRow
, nEndRow
))
271 void ScTable::InsertCol(
272 const sc::ColumnSet
& rRegroupCols
, SCCOL nStartCol
, SCROW nStartRow
, SCROW nEndRow
, SCSIZE nSize
)
274 if (nStartRow
==0 && nEndRow
==rDocument
.MaxRow())
276 if (mpColWidth
&& mpColFlags
)
278 mpColWidth
->InsertPreservingSize(nStartCol
, nSize
, STD_COL_WIDTH
);
279 // The inserted columns have the same widths as the columns, which were selected for insert.
280 for (SCSIZE i
=0; i
< std::min(rDocument
.MaxCol()-nSize
-nStartCol
, nSize
); ++i
)
281 mpColWidth
->SetValue(nStartCol
+ i
, mpColWidth
->GetValue(nStartCol
+i
+nSize
));
282 mpColFlags
->InsertPreservingSize(nStartCol
, nSize
, CRFlags::NONE
);
285 pOutlineTable
->InsertCol( nStartCol
, nSize
);
287 mpHiddenCols
->insertSegment(nStartCol
, static_cast<SCCOL
>(nSize
));
288 mpFilteredCols
->insertSegment(nStartCol
, static_cast<SCCOL
>(nSize
));
290 if (!maColManualBreaks
.empty())
292 // Copy all breaks up to nStartCol (non-inclusive).
293 ::std::set
<SCCOL
>::iterator itr1
= maColManualBreaks
.lower_bound(nStartCol
);
294 ::std::set
<SCCOL
> aNewBreaks(maColManualBreaks
.begin(), itr1
);
296 // Copy all breaks from nStartCol (inclusive) to the last element,
297 // but add nSize to each value.
298 ::std::set
<SCCOL
>::iterator itr2
= maColManualBreaks
.end();
299 for (; itr1
!= itr2
; ++itr1
)
300 aNewBreaks
.insert(static_cast<SCCOL
>(*itr1
+ nSize
));
302 maColManualBreaks
.swap(aNewBreaks
);
306 if ((nStartRow
== 0) && (nEndRow
== rDocument
.MaxRow()))
308 for (SCSIZE i
=0; i
< nSize
; i
++)
309 for (SCCOL nCol
= aCol
.size() - 1; nCol
> nStartCol
; nCol
--)
310 aCol
[nCol
].SwapCol(aCol
[nCol
-1]);
314 for (SCSIZE i
=0; static_cast<SCCOL
>(i
+nSize
)+nStartCol
< aCol
.size(); i
++)
315 aCol
[aCol
.size() - 1 - nSize
- i
].MoveTo(nStartRow
, nEndRow
, aCol
[aCol
.size() - 1 - i
]);
318 std::vector
<SCCOL
> aRegroupCols
;
319 rRegroupCols
.getColumns(nTab
, aRegroupCols
);
320 std::for_each(aRegroupCols
.begin(), aRegroupCols
.end(), ColumnRegroupFormulaCells(aCol
, nullptr));
322 if (nStartCol
>0) // copy old attributes
324 sal_uInt16 nWhichArray
[2];
325 nWhichArray
[0] = ATTR_MERGE
;
328 sc::CopyToDocContext
aCxt(rDocument
);
329 for (SCSIZE i
=0; i
<nSize
; i
++)
331 aCol
[nStartCol
-1].CopyToColumn(aCxt
, nStartRow
, nEndRow
, InsertDeleteFlags::ATTRIB
,
332 false, aCol
[nStartCol
+i
] );
333 aCol
[nStartCol
+i
].RemoveFlags( nStartRow
, nEndRow
,
334 ScMF::Hor
| ScMF::Ver
| ScMF::Auto
);
335 aCol
[nStartCol
+i
].ClearItems( nStartRow
, nEndRow
, nWhichArray
);
339 mpCondFormatList
->InsertCol(nTab
, nStartRow
, nEndRow
, nStartCol
, nSize
);
341 InvalidatePageBreaks();
343 // TODO: In the future we may want to check if the table has been
344 // really modified before setting the stream invalid.
345 SetStreamValid(false);
348 void ScTable::DeleteCol(
349 const sc::ColumnSet
& rRegroupCols
, SCCOL nStartCol
, SCROW nStartRow
, SCROW nEndRow
, SCSIZE nSize
, bool* pUndoOutline
)
351 if (nStartRow
==0 && nEndRow
==rDocument
.MaxRow())
353 if (mpColWidth
&& mpColFlags
)
355 assert( nStartCol
+ nSize
<= o3tl::make_unsigned(rDocument
.MaxCol()+1) ); // moving 0 if ==rDocument.MaxCol()+1 is correct
356 mpColWidth
->RemovePreservingSize(nStartCol
, nSize
, STD_COL_WIDTH
);
357 mpColFlags
->RemovePreservingSize(nStartCol
, nSize
, CRFlags::NONE
);
360 if (pOutlineTable
->DeleteCol( nStartCol
, nSize
))
362 *pUndoOutline
= true;
364 SCCOL nRmSize
= nStartCol
+ static_cast<SCCOL
>(nSize
);
365 mpHiddenCols
->removeSegment(nStartCol
, nRmSize
);
366 mpFilteredCols
->removeSegment(nStartCol
, nRmSize
);
368 if (!maColManualBreaks
.empty())
370 // Erase all manual breaks between nStartCol and nStartCol + nSize - 1 (inclusive).
371 std::set
<SCCOL
>::iterator itr1
= maColManualBreaks
.lower_bound(nStartCol
);
372 std::set
<SCCOL
>::iterator itr2
= maColManualBreaks
.upper_bound(static_cast<SCCOL
>(nStartCol
+ nSize
- 1));
373 maColManualBreaks
.erase(itr1
, itr2
);
375 // Copy all breaks from the 1st element up to nStartCol to the new container.
376 itr1
= maColManualBreaks
.lower_bound(nStartCol
);
377 ::std::set
<SCCOL
> aNewBreaks(maColManualBreaks
.begin(), itr1
);
379 // Copy all breaks from nStartCol to the last element, but subtract each value by nSize.
380 itr2
= maColManualBreaks
.end();
381 for (; itr1
!= itr2
; ++itr1
)
382 aNewBreaks
.insert(static_cast<SCCOL
>(*itr1
- nSize
));
384 maColManualBreaks
.swap(aNewBreaks
);
388 for (SCSIZE i
= 0; i
< nSize
; i
++)
389 aCol
[nStartCol
+ i
].DeleteArea(nStartRow
, nEndRow
, InsertDeleteFlags::ALL
, false);
391 if ((nStartRow
== 0) && (nEndRow
== rDocument
.MaxRow()))
393 for (SCSIZE i
=0; i
< nSize
; i
++)
394 for (SCCOL nCol
= nStartCol
; nCol
< aCol
.size() - 1; nCol
++)
395 aCol
[nCol
].SwapCol(aCol
[nCol
+1]);
399 for (SCSIZE i
=0; static_cast<SCCOL
>(i
+nSize
)+nStartCol
< aCol
.size(); i
++)
400 aCol
[nStartCol
+ nSize
+ i
].MoveTo(nStartRow
, nEndRow
, aCol
[nStartCol
+ i
]);
403 std::vector
<SCCOL
> aRegroupCols
;
404 rRegroupCols
.getColumns(nTab
, aRegroupCols
);
405 std::for_each(aRegroupCols
.begin(), aRegroupCols
.end(), ColumnRegroupFormulaCells(aCol
, nullptr));
407 InvalidatePageBreaks();
409 // TODO: In the future we may want to check if the table has been
410 // really modified before setting the stream invalid.
411 SetStreamValid(false);
414 void ScTable::DeleteArea(
415 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
, InsertDeleteFlags nDelFlag
,
416 bool bBroadcast
, sc::ColumnSpanSet
* pBroadcastSpans
)
418 if ( nCol2
>= aCol
.size() ) nCol2
= aCol
.size() - 1;
419 if (nRow2
> rDocument
.MaxRow()) nRow2
= rDocument
.MaxRow();
420 if (ValidColRow(nCol1
, nRow1
) && ValidColRow(nCol2
, nRow2
))
422 { // scope for bulk broadcast
423 ScBulkBroadcast
aBulkBroadcast( rDocument
.GetBASM(), SfxHintId::ScDataChanged
);
424 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
425 aCol
[i
].DeleteArea(nRow1
, nRow2
, nDelFlag
, bBroadcast
, pBroadcastSpans
);
428 // Do not set protected cell in a protected table
430 if ( IsProtected() && (nDelFlag
& InsertDeleteFlags::ATTRIB
) )
432 ScPatternAttr
aPattern(rDocument
.GetPool());
433 aPattern
.GetItemSet().Put( ScProtectionAttr( false ) );
434 ApplyPatternArea( nCol1
, nRow1
, nCol2
, nRow2
, aPattern
);
437 if( nDelFlag
& InsertDeleteFlags::ATTRIB
)
438 mpCondFormatList
->DeleteArea( nCol1
, nRow1
, nCol2
, nRow2
);
441 // TODO: In the future we may want to check if the table has been
442 // really modified before setting the stream invalid.
443 SetStreamValid(false);
446 void ScTable::DeleteSelection( InsertDeleteFlags nDelFlag
, const ScMarkData
& rMark
, bool bBroadcast
)
448 { // scope for bulk broadcast
449 ScBulkBroadcast
aBulkBroadcast( rDocument
.GetBASM(), SfxHintId::ScDataChanged
);
450 for (SCCOL i
=0; i
< aCol
.size(); i
++)
451 aCol
[i
].DeleteSelection(nDelFlag
, rMark
, bBroadcast
);
454 ScRangeList aRangeList
;
455 rMark
.FillRangeListWithMarks(&aRangeList
, false);
457 for (size_t i
= 0; i
< aRangeList
.size(); ++i
)
459 const ScRange
& rRange
= aRangeList
[i
];
461 if((nDelFlag
& InsertDeleteFlags::ATTRIB
) && rRange
.aStart
.Tab() == nTab
)
462 mpCondFormatList
->DeleteArea( rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aEnd
.Col(), rRange
.aEnd
.Row() );
465 // Do not set protected cell in a protected sheet
467 if ( IsProtected() && (nDelFlag
& InsertDeleteFlags::ATTRIB
) )
469 ScDocumentPool
* pPool
= rDocument
.GetPool();
470 SfxItemSetFixed
<ATTR_PATTERN_START
, ATTR_PATTERN_END
> aSet( *pPool
);
471 aSet
.Put( ScProtectionAttr( false ) );
472 SfxItemPoolCache
aCache( pPool
, &aSet
);
473 ApplySelectionCache( &aCache
, rMark
);
476 // TODO: In the future we may want to check if the table has been
477 // really modified before setting the stream invalid.
478 SetStreamValid(false);
481 // pTable = Clipboard
482 void ScTable::CopyToClip(
483 sc::CopyToClipContext
& rCxt
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
486 if (!ValidColRow(nCol1
, nRow1
) || !ValidColRow(nCol2
, nRow2
))
490 //local range names need to be copied first for formula cells
491 if (!pTable
->mpRangeName
&& mpRangeName
)
492 pTable
->mpRangeName
.reset( new ScRangeName(*mpRangeName
) );
494 nCol2
= ClampToAllocatedColumns(nCol2
);
496 for ( SCCOL i
= nCol1
; i
<= nCol2
; i
++)
497 aCol
[i
].CopyToClip(rCxt
, nRow1
, nRow2
, pTable
->CreateColumnIfNotExists(i
)); // notes are handled at column level
499 // copy widths/heights, and only "hidden", "filtered" and "manual" flags
500 // also for all preceding columns/rows, to have valid positions for drawing objects
502 if (mpColWidth
&& pTable
->mpColWidth
)
503 pTable
->mpColWidth
->CopyFrom(*mpColWidth
, 0, nCol2
);
505 pTable
->CopyColHidden(*this, 0, nCol2
);
506 pTable
->CopyColFiltered(*this, 0, nCol2
);
508 pTable
->SetAnonymousDBData(std::unique_ptr
<ScDBData
>(new ScDBData(*pDBDataNoName
)));
510 if (pRowFlags
&& pTable
->pRowFlags
&& mpRowHeights
&& pTable
->mpRowHeights
)
512 pTable
->pRowFlags
->CopyFromAnded( *pRowFlags
, 0, nRow2
, CRFlags::ManualSize
);
513 pTable
->CopyRowHeight(*this, 0, nRow2
, 0);
516 pTable
->CopyRowHidden(*this, 0, nRow2
);
517 pTable
->CopyRowFiltered(*this, 0, nRow2
);
519 // If necessary replace formulas with values
522 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
523 pTable
->aCol
[i
].RemoveProtected(nRow1
, nRow2
);
525 mpCondFormatList
->startRendering();
526 mpCondFormatList
->updateValues();
527 pTable
->mpCondFormatList
.reset(new ScConditionalFormatList(pTable
->rDocument
, *mpCondFormatList
));
528 mpCondFormatList
->endRendering();
531 void ScTable::CopyToClip(
532 sc::CopyToClipContext
& rCxt
, const ScRangeList
& rRanges
, ScTable
* pTable
)
534 for ( size_t i
= 0, nListSize
= rRanges
.size(); i
< nListSize
; ++i
)
536 const ScRange
& r
= rRanges
[ i
];
537 CopyToClip( rCxt
, r
.aStart
.Col(), r
.aStart
.Row(), r
.aEnd
.Col(), r
.aEnd
.Row(), pTable
);
541 void ScTable::CopyStaticToDocument(
542 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
, const SvNumberFormatterMergeMap
& rMap
, ScTable
* pDestTab
)
544 if (nCol1
> nCol2
|| nRow1
> nRow2
)
547 const SCCOL nFirstUnallocated
= std::clamp
<SCCOL
>(GetAllocatedColumnsCount(), nCol1
, nCol2
+ 1);
548 if (nFirstUnallocated
> nCol1
)
549 pDestTab
->CreateColumnIfNotExists(nFirstUnallocated
- 1);
551 for (SCCOL i
= nCol1
; i
< nFirstUnallocated
; ++i
)
553 ScColumn
& rSrcCol
= aCol
[i
];
554 ScColumn
& rDestCol
= pDestTab
->aCol
[i
];
555 rSrcCol
.CopyStaticToDocument(nRow1
, nRow2
, rMap
, rDestCol
);
558 // Maybe copy this table's default attrs to dest not limiting to already allocated in dest?
559 const SCCOL nLastInDest
= std::min
<SCCOL
>(pDestTab
->GetAllocatedColumnsCount() - 1, nCol2
);
560 for (SCCOL i
= nFirstUnallocated
; i
<= nLastInDest
; ++i
)
562 ScColumn
& rDestCol
= pDestTab
->aCol
[i
];
563 rDestCol
.maCellTextAttrs
.set_empty(nRow1
, nRow2
);
564 rDestCol
.maCells
.set_empty(nRow1
, nRow2
);
565 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
567 sal_uInt32 nNumFmt
= aDefaultColAttrArray
.GetPattern(nRow
)->GetNumberFormat(
568 rDocument
.GetNonThreadedContext().GetFormatTable());
569 SvNumberFormatterMergeMap::const_iterator itNum
= rMap
.find(nNumFmt
);
570 if (itNum
!= rMap
.end())
571 nNumFmt
= itNum
->second
;
573 rDestCol
.SetNumberFormat(nRow
, nNumFmt
);
575 rDestCol
.CellStorageModified();
579 void ScTable::CopyCellToDocument(SCCOL nSrcCol
, SCROW nSrcRow
, SCCOL nDestCol
, SCROW nDestRow
, ScTable
& rDestTab
)
581 if (!ValidColRow(nSrcCol
, nSrcRow
) || !ValidColRow(nDestCol
, nDestRow
))
584 if (nSrcCol
>= GetAllocatedColumnsCount())
586 if (nDestCol
< rDestTab
.GetAllocatedColumnsCount())
588 ScColumn
& rDestCol
= rDestTab
.aCol
[nDestCol
];
589 rDestCol
.maCells
.set_empty(nDestRow
, nDestRow
);
590 rDestCol
.maCellTextAttrs
.set_empty(nDestRow
, nDestRow
);
591 rDestCol
.maCellNotes
.set_empty(nDestRow
, nDestRow
);
592 rDestCol
.CellStorageModified();
597 ScColumn
& rSrcCol
= aCol
[nSrcCol
];
598 ScColumn
& rDestCol
= rDestTab
.CreateColumnIfNotExists(nDestCol
);
599 rSrcCol
.CopyCellToDocument(nSrcRow
, nDestRow
, rDestCol
);
604 bool CheckAndDeduplicateCondFormat(ScDocument
& rDocument
, ScConditionalFormat
* pOldFormat
, const ScConditionalFormat
* pNewFormat
, SCTAB nTab
)
609 if (pOldFormat
->EqualEntries(*pNewFormat
, true))
611 const ScRangeList
& rNewRangeList
= pNewFormat
->GetRange();
612 ScRangeList
& rDstRangeList
= pOldFormat
->GetRangeList();
613 for (size_t i
= 0; i
< rNewRangeList
.size(); ++i
)
615 rDstRangeList
.Join(rNewRangeList
[i
]);
617 rDocument
.AddCondFormatData(rNewRangeList
, nTab
, pOldFormat
->GetKey());
626 void ScTable::CopyConditionalFormat( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
627 SCCOL nDx
, SCROW nDy
, const ScTable
* pTable
)
629 ScRange
aOldRange( nCol1
- nDx
, nRow1
- nDy
, pTable
->nTab
, nCol2
- nDx
, nRow2
- nDy
, pTable
->nTab
);
630 ScRange
aNewRange( nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
);
631 bool bSameDoc
= rDocument
.GetStyleSheetPool() == pTable
->rDocument
.GetStyleSheetPool();
633 for(const auto& rxCondFormat
: *pTable
->mpCondFormatList
)
635 const ScRangeList
& rCondFormatRange
= rxCondFormat
->GetRange();
636 if(!rCondFormatRange
.Intersects( aOldRange
))
639 ScRangeList aIntersectedRange
= rCondFormatRange
.GetIntersectedRange(aOldRange
);
640 std::unique_ptr
<ScConditionalFormat
> pNewFormat
= rxCondFormat
->Clone(&rDocument
);
642 pNewFormat
->SetRange(aIntersectedRange
);
643 sc::RefUpdateContext
aRefCxt(rDocument
);
644 aRefCxt
.meMode
= URM_COPY
;
645 aRefCxt
.maRange
= aNewRange
;
646 aRefCxt
.mnColDelta
= nDx
;
647 aRefCxt
.mnRowDelta
= nDy
;
648 aRefCxt
.mnTabDelta
= nTab
- pTable
->nTab
;
649 pNewFormat
->UpdateReference(aRefCxt
, true);
651 if (bSameDoc
&& pTable
->nTab
== nTab
&& CheckAndDeduplicateCondFormat(rDocument
, mpCondFormatList
->GetFormat(rxCondFormat
->GetKey()), pNewFormat
.get(), nTab
))
656 bool bDuplicate
= false;
657 for(const auto& rxCond
: *mpCondFormatList
)
659 // Check if there is the same format in the destination
660 // If there is, then simply expand its range
661 if (CheckAndDeduplicateCondFormat(rDocument
, rxCond
.get(), pNewFormat
.get(), nTab
))
667 if (rxCond
->GetKey() > nMax
)
668 nMax
= rxCond
->GetKey();
670 // Do not add duplicate entries
676 pNewFormat
->SetKey(nMax
+ 1);
677 auto pNewFormatTmp
= pNewFormat
.get();
678 mpCondFormatList
->InsertNew(std::move(pNewFormat
));
682 for(size_t i
= 0, n
= pNewFormatTmp
->size();
686 const ScFormatEntry
* pEntry
= pNewFormatTmp
->GetEntry(i
);
687 if(pEntry
->GetType() == ScFormatEntry::Type::Condition
||
688 pEntry
->GetType() == ScFormatEntry::Type::ExtCondition
)
689 aStyleName
= static_cast<const ScCondFormatEntry
*>(pEntry
)->GetStyle();
690 else if(pEntry
->GetType() == ScFormatEntry::Type::Date
)
691 aStyleName
= static_cast<const ScCondDateFormatEntry
*>(pEntry
)->GetStyleName();
693 if(!aStyleName
.isEmpty())
695 if(rDocument
.GetStyleSheetPool()->Find(aStyleName
, SfxStyleFamily::Para
))
698 rDocument
.GetStyleSheetPool()->CopyStyleFrom(
699 pTable
->rDocument
.GetStyleSheetPool(), aStyleName
, SfxStyleFamily::Para
);
704 rDocument
.AddCondFormatData( pNewFormatTmp
->GetRange(), nTab
, pNewFormatTmp
->GetKey() );
708 bool ScTable::InitColumnBlockPosition( sc::ColumnBlockPosition
& rBlockPos
, SCCOL nCol
)
713 CreateColumnIfNotExists(nCol
).InitBlockPosition(rBlockPos
);
719 void ScTable::CopyFromClip(
720 sc::CopyFromClipContext
& rCxt
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
721 SCCOL nDx
, SCROW nDy
, ScTable
* pTable
)
723 if (nCol2
> rDocument
.MaxCol())
724 nCol2
= rDocument
.MaxCol();
725 if (nRow2
> rDocument
.MaxRow())
726 nRow2
= rDocument
.MaxRow();
728 if (!(ValidColRow(nCol1
, nRow1
) && ValidColRow(nCol2
, nRow2
)))
731 CreateColumnIfNotExists(nCol2
);
732 for ( SCCOL i
= nCol1
; i
<= nCol2
; i
++)
734 pTable
->CreateColumnIfNotExists(i
- nDx
);
735 aCol
[i
].CopyFromClip(rCxt
, nRow1
, nRow2
, nDy
, pTable
->aCol
[i
- nDx
]); // notes are handles at column level
738 if (rCxt
.getInsertFlag() & InsertDeleteFlags::ATTRIB
)
740 // make sure that there are no old references to the cond formats
741 sal_uInt16 nWhichArray
[2];
742 nWhichArray
[0] = ATTR_CONDITIONAL
;
744 for ( SCCOL i
= nCol1
; i
<= nCol2
; ++i
)
745 aCol
[i
].ClearItems(nRow1
, nRow2
, nWhichArray
);
748 if ((rCxt
.getInsertFlag() & InsertDeleteFlags::ATTRIB
) == InsertDeleteFlags::NONE
)
751 if (nRow1
==0 && nRow2
==rDocument
.MaxRow() && mpColWidth
&& pTable
->mpColWidth
)
752 mpColWidth
->CopyFrom(*pTable
->mpColWidth
, nCol1
, nCol2
, nCol1
- nDx
);
754 if (nCol1
==0 && nCol2
==rDocument
.MaxCol() && mpRowHeights
&& pTable
->mpRowHeights
&&
755 pRowFlags
&& pTable
->pRowFlags
)
757 CopyRowHeight(*pTable
, nRow1
, nRow2
, -nDy
);
758 // Must copy CRFlags::ManualSize bit too, otherwise pRowHeight doesn't make sense
759 for (SCROW j
=nRow1
; j
<=nRow2
; j
++)
761 if ( pTable
->pRowFlags
->GetValue(j
-nDy
) & CRFlags::ManualSize
)
762 pRowFlags
->OrValue( j
, CRFlags::ManualSize
);
764 pRowFlags
->AndValue( j
, ~CRFlags::ManualSize
);
768 // Do not set protected cell in a protected sheet
769 if (IsProtected() && (rCxt
.getInsertFlag() & InsertDeleteFlags::ATTRIB
))
771 ScPatternAttr
aPattern(rDocument
.GetPool());
772 aPattern
.GetItemSet().Put( ScProtectionAttr( false ) );
773 ApplyPatternArea( nCol1
, nRow1
, nCol2
, nRow2
, aPattern
);
776 // create deep copies for conditional formatting
777 CopyConditionalFormat( nCol1
, nRow1
, nCol2
, nRow2
, nDx
, nDy
, pTable
);
780 void ScTable::MixData(
781 sc::MixDocContext
& rCxt
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
782 ScPasteFunc nFunction
, bool bSkipEmpty
, const ScTable
* pSrcTab
)
784 for (SCCOL i
=nCol1
; i
<=nCol2
; i
++)
785 aCol
[i
].MixData(rCxt
, nRow1
, nRow2
, nFunction
, bSkipEmpty
, pSrcTab
->aCol
[i
]);
788 // Selection form this document
789 void ScTable::MixMarked(
790 sc::MixDocContext
& rCxt
, const ScMarkData
& rMark
, ScPasteFunc nFunction
,
791 bool bSkipEmpty
, const ScTable
* pSrcTab
)
793 for (SCCOL i
=0; i
< aCol
.size(); i
++)
794 aCol
[i
].MixMarked(rCxt
, rMark
, nFunction
, bSkipEmpty
, pSrcTab
->aCol
[i
]);
799 class TransClipHandler
802 const ScTable
& mrSrcTab
;
809 SCROW mnFilteredRows
= 0;
810 SCROW mnRowDestOffset
= 0;
813 bool mbIncludeFiltered
;
814 InsertDeleteFlags mnFlags
;
816 ScAddress
getDestPos(size_t nRow
) const
818 return ScAddress(static_cast<SCCOL
>(mnCol1
+ nRow
- mnTopRow
), mnTransRow
,
822 ScFormulaCell
* createRefCell(size_t nSrcRow
, const ScAddress
& rDestPos
) const
824 ScAddress
aSrcPos(mnSrcCol
, nSrcRow
, mnSrcTab
);
825 ScSingleRefData aRef
;
826 aRef
.InitAddress(aSrcPos
); // Absolute reference.
827 aRef
.SetFlag3D(true);
829 ScTokenArray
aArr(mrClipTab
.GetDoc());
830 aArr
.AddSingleReference(aRef
);
831 return new ScFormulaCell(mrClipTab
.GetDoc(), rDestPos
, aArr
);
834 void setLink(size_t nRow
)
836 SCCOL nTransCol
= mnCol1
+ nRow
- mnTopRow
- mnFilteredRows
+ mnRowDestOffset
;
837 mrClipTab
.SetFormulaCell(nTransCol
, mnTransRow
,
838 createRefCell(nRow
, getDestPos(nRow
)));
842 TransClipHandler(ScTable
& rClipTab
, const ScTable
& rSrcTab
, SCTAB nSrcTab
, SCCOL nCol1
,
843 SCCOL nSrcCol
, size_t nTopRow
, size_t nEndRow
, SCROW nCombinedStartRow
,
844 SCROW nRowDestOffset
, bool bAsLink
, bool bWasCut
,
845 const InsertDeleteFlags
& nFlags
, const bool bIncludeFiltered
,
846 std::vector
<SCROW
>& rFilteredRows
)
847 : mrClipTab(rClipTab
)
854 , mnTransRow(nSrcCol
- nCol1
+ nCombinedStartRow
)
855 , mnRowDestOffset(nRowDestOffset
)
858 , mbIncludeFiltered(bIncludeFiltered
)
861 // Create list of filtered rows.
862 if (!mbIncludeFiltered
)
864 for (SCROW curRow
= nTopRow
; curRow
<= static_cast<SCROW
>(mnEndRow
); ++curRow
)
866 // maybe this loop could be optimized
867 bool bFiltered
= mrSrcTab
.RowFiltered(curRow
, nullptr, nullptr);
869 rFilteredRows
.push_back(curRow
);
874 void operator() (size_t nRow
, double fVal
)
876 bool bFiltered
= mrSrcTab
.RowFiltered(nRow
, nullptr, nullptr);
877 if (!mbIncludeFiltered
&& bFiltered
)
889 SCCOL nTransCol
= mnCol1
+ nRow
- mnTopRow
- mnFilteredRows
+ mnRowDestOffset
;
890 mrClipTab
.SetValue(nTransCol
, mnTransRow
, fVal
);
893 void operator() (size_t nRow
, const svl::SharedString
& rStr
)
895 bool bFiltered
= mrSrcTab
.RowFiltered(nRow
, nullptr, nullptr);
896 if (!mbIncludeFiltered
&& bFiltered
)
908 SCCOL nTransCol
= mnCol1
+ nRow
- mnTopRow
- mnFilteredRows
+ mnRowDestOffset
;
909 mrClipTab
.SetRawString(nTransCol
, mnTransRow
, rStr
);
912 void operator() (size_t nRow
, const EditTextObject
* p
)
914 bool bFiltered
= mrSrcTab
.RowFiltered(nRow
, nullptr, nullptr);
915 if (!mbIncludeFiltered
&& bFiltered
)
927 SCCOL nTransCol
= mnCol1
+ nRow
- mnTopRow
- mnFilteredRows
+ mnRowDestOffset
;
928 mrClipTab
.SetEditText(nTransCol
, mnTransRow
, ScEditUtil::Clone(*p
, mrClipTab
.GetDoc()));
931 void operator() (size_t nRow
, const ScFormulaCell
* p
)
933 bool bFiltered
= mrSrcTab
.RowFiltered(nRow
, nullptr, nullptr);
934 if (!mbIncludeFiltered
&& bFiltered
)
946 ScFormulaCell
* pNew
= new ScFormulaCell(*p
, mrClipTab
.GetDoc(),
947 getDestPos(nRow
- mnFilteredRows
+ mnRowDestOffset
),
948 ScCloneFlags::StartListening
);
951 // for Cut, the references are later adjusted through UpdateTranspose
954 pNew
->TransposeReference();
956 SCCOL nTransCol
= mnCol1
+ nRow
- mnTopRow
- mnFilteredRows
+ mnRowDestOffset
;
957 mrClipTab
.SetFormulaCell(nTransCol
, mnTransRow
, pNew
);
961 void operator()(const int /*type*/, size_t nRow
, size_t nDataSize
)
963 for (size_t curRow
= nRow
; curRow
< nRow
+ nDataSize
; ++curRow
)
965 bool bFiltered
= mrSrcTab
.RowFiltered(curRow
, nullptr, nullptr);
966 if (!mbIncludeFiltered
&& bFiltered
)
972 if (mbAsLink
&& mnFlags
== InsertDeleteFlags::ALL
)
974 // with InsertDeleteFlags::ALL, also create links (formulas) for empty cells
983 void ScTable::TransposeClip(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
984 SCROW nCombinedStartRow
, SCROW nRowDestOffset
, ScTable
* pTransClip
,
985 InsertDeleteFlags nFlags
, bool bAsLink
, bool bIncludeFiltered
)
987 bool bWasCut
= rDocument
.IsCutMode();
989 for (SCCOL nCol
=nCol1
; nCol
<=nCol2
; nCol
++)
991 std::vector
<SCROW
> aFilteredRows
;
993 TransClipHandler
aFunc(*pTransClip
, *this, nTab
, nCol1
, nCol
, nRow1
, nRow2
,
994 nCombinedStartRow
, nRowDestOffset
, bAsLink
, bWasCut
, nFlags
,
995 bIncludeFiltered
, aFilteredRows
);
997 const sc::CellStoreType
& rCells
= aCol
[nCol
].maCells
;
999 // Loop through all rows by iterator and call aFunc operators
1000 sc::ParseAll(rCells
.begin(), rCells
, nRow1
, nRow2
, aFunc
,
1004 if (nFlags
& InsertDeleteFlags::ATTRIB
)
1005 TransposeColPatterns(pTransClip
, nCol1
, nCol
, nRow1
, nRow2
, nCombinedStartRow
,
1006 bIncludeFiltered
, aFilteredRows
, nRowDestOffset
);
1008 // Cell Notes - fdo#68381 paste cell notes on Transpose
1009 if ((nFlags
& InsertDeleteFlags::NOTE
) && rDocument
.HasColNotes(nCol
, nTab
))
1010 TransposeColNotes(pTransClip
, nCol1
, nCol
, nRow1
, nRow2
, nCombinedStartRow
,
1011 bIncludeFiltered
, nRowDestOffset
);
1015 static void lcl_SetTransposedPatternInRows(ScTable
* pTransClip
, SCROW nAttrRow1
, SCROW nAttrRow2
,
1016 SCCOL nCol1
, SCROW nRow1
, SCROW nCombinedStartRow
, SCCOL nCol
,
1017 const ScPatternAttr
& rPatternAttr
, bool bIncludeFiltered
,
1018 const std::vector
<SCROW
>& rFilteredRows
,
1019 SCROW nRowDestOffset
)
1021 for (SCROW nRow
= nAttrRow1
; nRow
<= nAttrRow2
; nRow
++)
1023 size_t nFilteredRowAdjustment
= 0;
1024 if (!bIncludeFiltered
)
1026 // aFilteredRows is sorted thus lower_bound() can be used.
1027 // lower_bound() has a logarithmic complexity O(log(n))
1028 auto itRow1
= std::lower_bound(rFilteredRows
.begin(), rFilteredRows
.end(), nRow1
);
1029 auto itRow
= std::lower_bound(rFilteredRows
.begin(), rFilteredRows
.end(), nRow
);
1030 bool bRefRowIsFiltered
= itRow
!= rFilteredRows
.end() && *itRow
== nRow
;
1031 if (bRefRowIsFiltered
)
1034 // How many filtered rows are between the formula cell and the reference?
1035 // distance() has a constant complexity O(1) for vectors
1036 nFilteredRowAdjustment
= std::distance(itRow1
, itRow
);
1039 pTransClip
->SetPattern(
1040 static_cast<SCCOL
>(nCol1
+ nRow
- nRow1
- nFilteredRowAdjustment
+ nRowDestOffset
),
1041 static_cast<SCROW
>(nCombinedStartRow
+ nCol
- nCol1
), rPatternAttr
);
1045 void ScTable::TransposeColPatterns(ScTable
* pTransClip
, SCCOL nCol1
, SCCOL nCol
, SCROW nRow1
,
1046 SCROW nRow2
, SCROW nCombinedStartRow
, bool bIncludeFiltered
,
1047 const std::vector
<SCROW
>& rFilteredRows
, SCROW nRowDestOffset
)
1049 SCROW nAttrRow1
= {}; // spurious -Werror=maybe-uninitialized
1050 SCROW nAttrRow2
= {}; // spurious -Werror=maybe-uninitialized
1051 const ScPatternAttr
* pPattern
;
1052 std::unique_ptr
<ScAttrIterator
> pAttrIter(aCol
[nCol
].CreateAttrIterator( nRow1
, nRow2
));
1053 while ( (pPattern
= pAttrIter
->Next( nAttrRow1
, nAttrRow2
)) != nullptr )
1055 if ( !IsDefaultItem( pPattern
) )
1057 const SfxItemSet
& rSet
= pPattern
->GetItemSet();
1058 if ( rSet
.GetItemState( ATTR_MERGE
, false ) == SfxItemState::DEFAULT
&&
1059 rSet
.GetItemState( ATTR_MERGE_FLAG
, false ) == SfxItemState::DEFAULT
&&
1060 rSet
.GetItemState( ATTR_BORDER
, false ) == SfxItemState::DEFAULT
)
1062 // Set pattern in cells from nAttrRow1 to nAttrRow2
1063 // no borders or merge items involved - use pattern as-is
1064 lcl_SetTransposedPatternInRows(pTransClip
, nAttrRow1
, nAttrRow2
, nCol1
, nRow1
,
1065 nCombinedStartRow
, nCol
, *pPattern
,
1066 bIncludeFiltered
, rFilteredRows
, nRowDestOffset
);
1070 // transpose borders and merge values, remove merge flags (refreshed after pasting)
1071 ScPatternAttr
aNewPattern( *pPattern
);
1072 SfxItemSet
& rNewSet
= aNewPattern
.GetItemSet();
1074 const SvxBoxItem
& rOldBox
= rSet
.Get(ATTR_BORDER
);
1075 if ( rOldBox
.GetTop() || rOldBox
.GetBottom() || rOldBox
.GetLeft() || rOldBox
.GetRight() )
1077 SvxBoxItem
aNew( ATTR_BORDER
);
1078 aNew
.SetLine( rOldBox
.GetLine( SvxBoxItemLine::TOP
), SvxBoxItemLine::LEFT
);
1079 aNew
.SetLine( rOldBox
.GetLine( SvxBoxItemLine::LEFT
), SvxBoxItemLine::TOP
);
1080 aNew
.SetLine( rOldBox
.GetLine( SvxBoxItemLine::BOTTOM
), SvxBoxItemLine::RIGHT
);
1081 aNew
.SetLine( rOldBox
.GetLine( SvxBoxItemLine::RIGHT
), SvxBoxItemLine::BOTTOM
);
1082 aNew
.SetDistance( rOldBox
.GetDistance( SvxBoxItemLine::TOP
), SvxBoxItemLine::LEFT
);
1083 aNew
.SetDistance( rOldBox
.GetDistance( SvxBoxItemLine::LEFT
), SvxBoxItemLine::TOP
);
1084 aNew
.SetDistance( rOldBox
.GetDistance( SvxBoxItemLine::BOTTOM
), SvxBoxItemLine::RIGHT
);
1085 aNew
.SetDistance( rOldBox
.GetDistance( SvxBoxItemLine::RIGHT
), SvxBoxItemLine::BOTTOM
);
1086 rNewSet
.Put( aNew
);
1089 const ScMergeAttr
& rOldMerge
= rSet
.Get(ATTR_MERGE
);
1090 if (rOldMerge
.IsMerged())
1091 rNewSet
.Put( ScMergeAttr( std::min(
1092 static_cast<SCCOL
>(rOldMerge
.GetRowMerge()),
1093 static_cast<SCCOL
>(rDocument
.MaxCol()+1 - (nAttrRow2
-nRow1
))),
1095 static_cast<SCROW
>(rOldMerge
.GetColMerge()),
1096 static_cast<SCROW
>(rDocument
.MaxRow()+1 - (nCol
-nCol1
)))));
1097 const ScMergeFlagAttr
& rOldFlag
= rSet
.Get(ATTR_MERGE_FLAG
);
1098 if (rOldFlag
.IsOverlapped())
1100 ScMF nNewFlags
= rOldFlag
.GetValue() & ~ScMF( ScMF::Hor
| ScMF::Ver
);
1101 if ( nNewFlags
!= ScMF::NONE
)
1102 rNewSet
.Put( ScMergeFlagAttr( nNewFlags
) );
1104 rNewSet
.ClearItem( ATTR_MERGE_FLAG
);
1107 // Set pattern in cells from nAttrRow1 to nAttrRow2
1108 lcl_SetTransposedPatternInRows(pTransClip
, nAttrRow1
, nAttrRow2
, nCol1
, nRow1
,
1109 nCombinedStartRow
, nCol
, aNewPattern
,
1110 bIncludeFiltered
, rFilteredRows
, nRowDestOffset
);
1116 void ScTable::TransposeColNotes(ScTable
* pTransClip
, SCCOL nCol1
, SCCOL nCol
, SCROW nRow1
,
1117 SCROW nRow2
, SCROW nCombinedStartRow
, bool bIncludeFiltered
,
1118 SCROW nRowDestOffset
)
1120 sc::CellNoteStoreType::const_iterator itBlk
= aCol
[nCol
].maCellNotes
.begin(), itBlkEnd
= aCol
[nCol
].maCellNotes
.end();
1122 // Locate the top row position.
1123 size_t nOffsetInBlock
= 0;
1124 size_t nBlockStart
= 0, nBlockEnd
= 0, nRowPos
= static_cast<size_t>(nRow1
);
1125 for (; itBlk
!= itBlkEnd
; ++itBlk
, nBlockStart
= nBlockEnd
)
1127 nBlockEnd
= nBlockStart
+ itBlk
->size
;
1128 if (nBlockStart
<= nRowPos
&& nRowPos
< nBlockEnd
)
1131 nOffsetInBlock
= nRowPos
- nBlockStart
;
1136 if (itBlk
== itBlkEnd
)
1137 // Specified range found
1140 nRowPos
= static_cast<size_t>(nRow2
); // End row position.
1141 SCCOL nFilteredRows
= 0;
1143 // Keep processing until we hit the end row position.
1144 sc::cellnote_block::const_iterator itData
, itDataEnd
;
1145 for (; itBlk
!= itBlkEnd
; ++itBlk
, nBlockStart
= nBlockEnd
, nOffsetInBlock
= 0)
1147 nBlockEnd
= nBlockStart
+ itBlk
->size
;
1151 itData
= sc::cellnote_block::begin(*itBlk
->data
);
1152 std::advance(itData
, nOffsetInBlock
);
1154 // selected area is smaller than the iteration block
1155 if (nBlockStart
<= nRowPos
&& nRowPos
< nBlockEnd
)
1157 // This block contains the end row. Only process partially.
1158 size_t nOffsetEnd
= nRowPos
- nBlockStart
+ 1;
1159 itDataEnd
= sc::cellnote_block::begin(*itBlk
->data
);
1160 std::advance(itDataEnd
, nOffsetEnd
);
1161 size_t curRow
= nBlockStart
+ nOffsetInBlock
;
1162 for (; itData
!= itDataEnd
; ++itData
, ++curRow
)
1164 bool bFiltered
= this->RowFiltered(curRow
, nullptr, nullptr);
1165 if (!bIncludeFiltered
&& bFiltered
)
1172 static_cast<SCCOL
>(nCol1
+ curRow
- nRow1
- nFilteredRows
+ nRowDestOffset
),
1173 static_cast<SCROW
>(nCombinedStartRow
+ nCol
- nCol1
), pTransClip
->nTab
);
1174 pTransClip
->rDocument
.ReleaseNote(aDestPos
);
1175 ScPostIt
* pNote
= *itData
;
1178 std::unique_ptr
<ScPostIt
> pClonedNote
= pNote
->Clone( ScAddress(nCol
, curRow
, nTab
), pTransClip
->rDocument
, aDestPos
, true );
1179 pTransClip
->rDocument
.SetNote(aDestPos
, std::move(pClonedNote
));
1182 break; // we reached the last valid block
1186 itDataEnd
= sc::cellnote_block::end(*itBlk
->data
);
1187 size_t curRow
= nBlockStart
+ nOffsetInBlock
;
1188 for (; itData
!= itDataEnd
; ++itData
, ++curRow
)
1190 bool bFiltered
= this->RowFiltered(curRow
, nullptr, nullptr);
1191 if (!bIncludeFiltered
&& bFiltered
)
1198 static_cast<SCCOL
>(nCol1
+ curRow
- nRow1
- nFilteredRows
+ nRowDestOffset
),
1199 static_cast<SCROW
>(nCombinedStartRow
+ nCol
- nCol1
), pTransClip
->nTab
);
1200 pTransClip
->rDocument
.ReleaseNote(aDestPos
);
1201 ScPostIt
* pNote
= *itData
;
1204 std::unique_ptr
<ScPostIt
> pClonedNote
= pNote
->Clone( ScAddress(nCol
, curRow
, nTab
), pTransClip
->rDocument
, aDestPos
, true );
1205 pTransClip
->rDocument
.SetNote(aDestPos
, std::move(pClonedNote
));
1210 else // remove dest notes for rows without notes
1212 for (size_t curRow
= nBlockStart
+ nOffsetInBlock
;
1213 curRow
<= nBlockEnd
&& curRow
<= nRowPos
; ++curRow
)
1215 bool bFiltered
= this->RowFiltered(curRow
, nullptr, nullptr);
1216 if (!bIncludeFiltered
&& bFiltered
&& curRow
< nBlockEnd
)
1223 static_cast<SCCOL
>(nCol1
+ curRow
- nRow1
- nFilteredRows
+ nRowDestOffset
),
1224 static_cast<SCROW
>(nCombinedStartRow
+ nCol
- nCol1
), pTransClip
->nTab
);
1225 pTransClip
->rDocument
.ReleaseNote(aDestPos
);
1231 ScColumn
* ScTable::FetchColumn( SCCOL nCol
)
1233 if (!ValidCol(nCol
))
1236 return &CreateColumnIfNotExists(nCol
);
1239 const ScColumn
* ScTable::FetchColumn( SCCOL nCol
) const
1241 if (!ValidCol(nCol
) || nCol
>= GetAllocatedColumnsCount())
1247 void ScTable::StartListeners( sc::StartListeningContext
& rCxt
, bool bAll
)
1249 std::shared_ptr
<const sc::ColumnSet
> pColSet
= rCxt
.getColumnSet();
1252 for (SCCOL i
=0; i
< aCol
.size(); i
++)
1253 aCol
[i
].StartListeners(rCxt
, bAll
);
1255 else if (pColSet
->hasTab( nTab
))
1257 std::vector
<SCCOL
> aColumns
;
1258 pColSet
->getColumns( nTab
, aColumns
);
1259 for (auto i
: aColumns
)
1261 if (0 <= i
&& i
< aCol
.size())
1262 aCol
[i
].StartListeners(rCxt
, bAll
);
1267 void ScTable::AttachFormulaCells(
1268 sc::StartListeningContext
& rCxt
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
1270 nCol2
= ClampToAllocatedColumns(nCol2
);
1271 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
1272 aCol
[nCol
].AttachFormulaCells(rCxt
, nRow1
, nRow2
);
1275 void ScTable::DetachFormulaCells(
1276 sc::EndListeningContext
& rCxt
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
1278 nCol2
= ClampToAllocatedColumns(nCol2
);
1279 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
1280 aCol
[nCol
].DetachFormulaCells(rCxt
, nRow1
, nRow2
, nullptr);
1283 void ScTable::SetDirtyFromClip(
1284 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
, sc::ColumnSpanSet
& rBroadcastSpans
)
1286 if ( nCol2
>= aCol
.size() ) nCol2
= aCol
.size() - 1;
1287 if (nCol2
> rDocument
.MaxCol()) nCol2
= rDocument
.MaxCol();
1288 if (nRow2
> rDocument
.MaxRow()) nRow2
= rDocument
.MaxRow();
1289 if (ValidColRow(nCol1
, nRow1
) && ValidColRow(nCol2
, nRow2
))
1290 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
1291 aCol
[i
].SetDirtyFromClip(nRow1
, nRow2
, rBroadcastSpans
);
1294 void ScTable::StartListeningFormulaCells(
1295 sc::StartListeningContext
& rStartCxt
, sc::EndListeningContext
& rEndCxt
,
1296 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
1298 if ( nCol2
>= aCol
.size() ) nCol2
= aCol
.size() - 1;
1299 if (nCol2
> rDocument
.MaxCol()) nCol2
= rDocument
.MaxCol();
1300 if (nRow2
> rDocument
.MaxRow()) nRow2
= rDocument
.MaxRow();
1301 if (ValidColRow(nCol1
, nRow1
) && ValidColRow(nCol2
, nRow2
))
1302 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
1303 aCol
[i
].StartListeningFormulaCells(rStartCxt
, rEndCxt
, nRow1
, nRow2
);
1306 void ScTable::CopyToTable(
1307 sc::CopyToDocContext
& rCxt
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1308 InsertDeleteFlags nFlags
, bool bMarked
, ScTable
* pDestTab
, const ScMarkData
* pMarkData
,
1309 bool bAsLink
, bool bColRowFlags
, bool bGlobalNamesToLocal
, bool bCopyCaptions
)
1311 if (!ValidColRow(nCol1
, nRow1
) || !ValidColRow(nCol2
, nRow2
))
1314 const bool bToUndoDoc
= pDestTab
->rDocument
.IsUndo();
1315 const bool bFromUndoDoc
= rDocument
.IsUndo();
1317 if ((bToUndoDoc
|| bFromUndoDoc
) && (nFlags
& InsertDeleteFlags::CONTENTS
) && mpRangeName
)
1319 // Copying formulas may create sheet-local named expressions on the
1320 // destination sheet. Add existing to Undo first.
1321 // During Undo restore the previous named expressions.
1322 pDestTab
->SetRangeName( std::unique_ptr
<ScRangeName
>( new ScRangeName( *GetRangeName())));
1323 if (!pDestTab
->rDocument
.IsClipOrUndo())
1325 ScDocShell
* pDocSh
= static_cast<ScDocShell
*>(pDestTab
->rDocument
.GetDocumentShell());
1327 pDocSh
->SetAreasChangedNeedBroadcast();
1331 if (nFlags
!= InsertDeleteFlags::NONE
)
1333 InsertDeleteFlags
nTempFlags( nFlags
&
1334 ~InsertDeleteFlags( InsertDeleteFlags::NOTE
| InsertDeleteFlags::ADDNOTES
));
1335 // tdf#102364 - in some pathological cases CopyToTable() replacing cells with new cells
1336 // can lead to repetitive splitting and rejoining of the same formula group, which can get
1337 // quadratically expensive with large groups. So do the grouping just once at the end.
1338 sc::DelayFormulaGroupingSwitch
delayGrouping( pDestTab
->rDocument
, true );
1339 for (SCCOL i
= nCol1
; i
<= ClampToAllocatedColumns(nCol2
); i
++)
1340 aCol
[i
].CopyToColumn(rCxt
, nRow1
, nRow2
, bToUndoDoc
? nFlags
: nTempFlags
, bMarked
,
1341 pDestTab
->CreateColumnIfNotExists(i
), pMarkData
, bAsLink
, bGlobalNamesToLocal
);
1344 if (!bColRowFlags
) // Column widths/Row heights/Flags
1347 if (bToUndoDoc
&& (nFlags
& InsertDeleteFlags::ATTRIB
))
1349 pDestTab
->mpCondFormatList
.reset(new ScConditionalFormatList(pDestTab
->rDocument
, *mpCondFormatList
));
1354 std::unique_ptr
<ScDBData
> pNewDBData(new ScDBData(*pDBDataNoName
));
1358 pNewDBData
->GetArea(aTab
, aCol1
, aRow1
, aCol2
, aRow2
);
1359 pNewDBData
->MoveTo(pDestTab
->nTab
, aCol1
, aRow1
, aCol2
, aRow2
);
1360 pDestTab
->SetAnonymousDBData(std::move(pNewDBData
));
1362 // Charts have to be adjusted when hide/show
1363 ScChartListenerCollection
* pCharts
= pDestTab
->rDocument
.GetChartListenerCollection();
1365 bool bFlagChange
= false;
1367 bool bWidth
= (nRow1
==0 && nRow2
==rDocument
.MaxRow() && mpColWidth
&& pDestTab
->mpColWidth
);
1368 bool bHeight
= (nCol1
==0 && nCol2
==rDocument
.MaxCol() && mpRowHeights
&& pDestTab
->mpRowHeights
);
1370 if (bWidth
|| bHeight
)
1374 auto destTabColWidthIt
= pDestTab
->mpColWidth
->begin() + nCol1
;
1375 auto thisTabColWidthIt
= mpColWidth
->begin() + nCol1
;
1376 pDestTab
->mpColWidth
->CopyFrom(*mpColWidth
, nCol1
, nCol2
);
1377 pDestTab
->mpColFlags
->CopyFrom(*mpColFlags
, nCol1
, nCol2
);
1378 for (SCCOL i
= nCol1
; i
<= nCol2
; ++i
)
1380 bool bThisHidden
= ColHidden(i
);
1381 bool bHiddenChange
= (pDestTab
->ColHidden(i
) != bThisHidden
);
1382 bool bChange
= bHiddenChange
|| (*destTabColWidthIt
!= *thisTabColWidthIt
);
1383 pDestTab
->SetColHidden(i
, i
, bThisHidden
);
1384 //TODO: collect changes?
1385 if (bHiddenChange
&& pCharts
)
1386 pCharts
->SetRangeDirty(ScRange( i
, 0, nTab
, i
, rDocument
.MaxRow(), nTab
));
1391 ++destTabColWidthIt
;
1392 ++thisTabColWidthIt
;
1394 pDestTab
->SetColManualBreaks( std::set(maColManualBreaks
) );
1399 bool bChange
= pDestTab
->GetRowHeight(nRow1
, nRow2
) != GetRowHeight(nRow1
, nRow2
);
1404 pDestTab
->CopyRowHeight(*this, nRow1
, nRow2
, 0);
1405 pDestTab
->pRowFlags
->CopyFrom(*pRowFlags
, nRow1
, nRow2
);
1408 for (SCROW i
= nRow1
; i
<= nRow2
; ++i
)
1411 bool bHidden
= RowHidden(i
, nullptr, &nLastRow
);
1412 if (nLastRow
>= nRow2
)
1413 // the last row shouldn't exceed the upper bound the caller specified.
1416 bool bHiddenChanged
= pDestTab
->SetRowHidden(i
, nLastRow
, bHidden
);
1417 if (bHiddenChanged
&& pCharts
)
1418 // Hidden flags differ.
1419 pCharts
->SetRangeDirty(ScRange(0, i
, nTab
, rDocument
.MaxCol(), nLastRow
, nTab
));
1424 // Jump to the last row of the identical flag segment.
1429 for (SCROW i
= nRow1
; i
<= nRow2
; ++i
)
1432 bool bFiltered
= RowFiltered(i
, nullptr, &nLastRow
);
1433 if (nLastRow
>= nRow2
)
1434 // the last row shouldn't exceed the upper bound the caller specified.
1436 pDestTab
->SetRowFiltered(i
, nLastRow
, bFiltered
);
1439 pDestTab
->SetRowManualBreaks( std::set(maRowManualBreaks
) );
1444 pDestTab
->InvalidatePageBreaks();
1446 if(nFlags
& InsertDeleteFlags::ATTRIB
)
1448 pDestTab
->mpCondFormatList
->DeleteArea(nCol1
, nRow1
, nCol2
, nRow2
);
1449 pDestTab
->CopyConditionalFormat(nCol1
, nRow1
, nCol2
, nRow2
, 0, 0, this);
1452 if(nFlags
& InsertDeleteFlags::OUTLINE
) // also only when bColRowFlags
1453 pDestTab
->SetOutlineTable( pOutlineTable
.get() );
1455 if (!bToUndoDoc
&& bCopyCaptions
&& (nFlags
& (InsertDeleteFlags::NOTE
| InsertDeleteFlags::ADDNOTES
)))
1457 bool bCloneCaption
= (nFlags
& InsertDeleteFlags::NOCAPTIONS
) == InsertDeleteFlags::NONE
;
1458 CopyCaptionsToTable( nCol1
, nRow1
, nCol2
, nRow2
, pDestTab
, bCloneCaption
);
1462 void ScTable::CopyCaptionsToTable( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
, ScTable
* pDestTab
,
1463 bool bCloneCaption
)
1465 if (!ValidColRow(nCol1
, nRow1
) || !ValidColRow(nCol2
, nRow2
))
1468 nCol2
= ClampToAllocatedColumns(nCol2
);
1469 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
1471 aCol
[i
].CopyCellNotesToDocument(nRow1
, nRow2
, pDestTab
->CreateColumnIfNotExists(i
), bCloneCaption
);
1472 pDestTab
->aCol
[i
].UpdateNoteCaptions(nRow1
, nRow2
);
1476 void ScTable::UndoToTable(
1477 sc::CopyToDocContext
& rCxt
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1478 InsertDeleteFlags nFlags
, bool bMarked
, ScTable
* pDestTab
)
1480 if (!(ValidColRow(nCol1
, nRow1
) && ValidColRow(nCol2
, nRow2
)))
1483 bool bWidth
= (nRow1
==0 && nRow2
==rDocument
.MaxRow() && mpColWidth
&& pDestTab
->mpColWidth
);
1484 bool bHeight
= (nCol1
==0 && nCol2
==rDocument
.MaxCol() && mpRowHeights
&& pDestTab
->mpRowHeights
);
1486 if ((nFlags
& InsertDeleteFlags::CONTENTS
) && mpRangeName
)
1488 // Undo sheet-local named expressions created during copying
1489 // formulas. If mpRangeName is not set then the Undo wasn't even
1490 // set to an empty ScRangeName map so don't "undo" that.
1491 pDestTab
->SetRangeName( std::unique_ptr
<ScRangeName
>( new ScRangeName( *GetRangeName())));
1492 if (!pDestTab
->rDocument
.IsClipOrUndo())
1494 ScDocShell
* pDocSh
= static_cast<ScDocShell
*>(pDestTab
->rDocument
.GetDocumentShell());
1496 pDocSh
->SetAreasChangedNeedBroadcast();
1501 for ( SCCOL i
= 0; i
< aCol
.size(); i
++)
1503 auto& rDestCol
= pDestTab
->CreateColumnIfNotExists(i
);
1504 if ( i
>= nCol1
&& i
<= nCol2
)
1505 aCol
[i
].UndoToColumn(rCxt
, nRow1
, nRow2
, nFlags
, bMarked
, rDestCol
);
1507 aCol
[i
].CopyToColumn(rCxt
, 0, rDocument
.MaxRow(), InsertDeleteFlags::FORMULA
, false, rDestCol
);
1510 if (nFlags
& InsertDeleteFlags::ATTRIB
)
1511 pDestTab
->mpCondFormatList
.reset(new ScConditionalFormatList(pDestTab
->rDocument
, *mpCondFormatList
));
1513 if (!(bWidth
||bHeight
))
1518 pDestTab
->mpColWidth
->CopyFrom(*mpColWidth
, nCol1
, nCol2
);
1519 pDestTab
->SetColManualBreaks( std::set(maColManualBreaks
) );
1523 pDestTab
->CopyRowHeight(*this, nRow1
, nRow2
, 0);
1524 pDestTab
->SetRowManualBreaks( std::set(maRowManualBreaks
) );
1528 void ScTable::CopyUpdated( const ScTable
* pPosTab
, ScTable
* pDestTab
) const
1530 pPosTab
->CreateColumnIfNotExists(aCol
.size()-1);
1531 pDestTab
->CreateColumnIfNotExists(aCol
.size()-1);
1532 for (SCCOL i
=0; i
< aCol
.size(); i
++)
1533 aCol
[i
].CopyUpdated( pPosTab
->aCol
[i
], pDestTab
->aCol
[i
] );
1536 void ScTable::InvalidateTableArea()
1538 bTableAreaValid
= false;
1539 bTableAreaVisibleValid
= false;
1542 void ScTable::InvalidatePageBreaks()
1544 mbPageBreaksValid
= false;
1547 void ScTable::CopyScenarioTo( const ScTable
* pDestTab
) const
1549 OSL_ENSURE( bScenario
, "bScenario == FALSE" );
1551 for (SCCOL i
=0; i
< aCol
.size(); i
++)
1552 aCol
[i
].CopyScenarioTo( pDestTab
->CreateColumnIfNotExists(i
) );
1555 void ScTable::CopyScenarioFrom( const ScTable
* pSrcTab
)
1557 OSL_ENSURE( bScenario
, "bScenario == FALSE" );
1559 SCCOL nEndCol
= pSrcTab
->aCol
.size();
1560 CreateColumnIfNotExists(nEndCol
);
1561 for (SCCOL i
=0; i
< nEndCol
; i
++)
1562 aCol
[i
].CopyScenarioFrom( pSrcTab
->aCol
[i
] );
1565 void ScTable::MarkScenarioIn( ScMarkData
& rDestMark
, ScScenarioFlags nNeededBits
) const
1567 OSL_ENSURE( bScenario
, "bScenario == FALSE" );
1569 if ( ( nScenarioFlags
& nNeededBits
) != nNeededBits
) // Are all Bits set?
1572 for (SCCOL i
=0; i
< aCol
.size(); i
++)
1573 aCol
[i
].MarkScenarioIn( rDestMark
);
1576 bool ScTable::HasScenarioRange( const ScRange
& rRange
) const
1578 OSL_ENSURE( bScenario
, "bScenario == FALSE" );
1580 ScRange aTabRange
= rRange
;
1581 aTabRange
.aStart
.SetTab( nTab
);
1582 aTabRange
.aEnd
.SetTab( nTab
);
1584 const ScRangeList
* pList
= GetScenarioRanges();
1588 for ( size_t j
= 0, n
= pList
->size(); j
< n
; j
++ )
1590 const ScRange
& rR
= (*pList
)[j
];
1591 if ( rR
.Intersects( aTabRange
) )
1599 void ScTable::InvalidateScenarioRanges()
1601 pScenarioRanges
.reset();
1604 const ScRangeList
* ScTable::GetScenarioRanges() const
1606 OSL_ENSURE( bScenario
, "bScenario == FALSE" );
1608 if (!pScenarioRanges
)
1610 const_cast<ScTable
*>(this)->pScenarioRanges
.reset(new ScRangeList
);
1611 ScMarkData
aMark(rDocument
.GetSheetLimits());
1612 MarkScenarioIn( aMark
, ScScenarioFlags::NONE
); // always
1613 aMark
.FillRangeListWithMarks( pScenarioRanges
.get(), false );
1615 return pScenarioRanges
.get();
1618 bool ScTable::TestCopyScenarioTo( const ScTable
* pDestTab
) const
1620 OSL_ENSURE( bScenario
, "bScenario == FALSE" );
1622 if (!pDestTab
->IsProtected())
1626 for (SCCOL i
=0; i
< aCol
.size() && bOk
; i
++)
1627 bOk
= aCol
[i
].TestCopyScenarioTo( pDestTab
->aCol
[i
] );
1631 bool ScTable::SetString( SCCOL nCol
, SCROW nRow
, SCTAB nTabP
, const OUString
& rString
,
1632 const ScSetStringParam
* pParam
)
1634 if (!ValidColRow(nCol
,nRow
))
1639 return CreateColumnIfNotExists(nCol
).SetString(
1640 nRow
, nTabP
, rString
, rDocument
.GetAddressConvention(), pParam
);
1643 bool ScTable::SetEditText( SCCOL nCol
, SCROW nRow
, std::unique_ptr
<EditTextObject
> pEditText
)
1645 if (!ValidColRow(nCol
, nRow
))
1650 CreateColumnIfNotExists(nCol
).SetEditText(nRow
, std::move(pEditText
));
1654 void ScTable::SetEditText( SCCOL nCol
, SCROW nRow
, const EditTextObject
& rEditText
, const SfxItemPool
* pEditPool
)
1656 if (!ValidColRow(nCol
, nRow
))
1659 CreateColumnIfNotExists(nCol
).SetEditText(nRow
, rEditText
, pEditPool
);
1662 SCROW
ScTable::GetFirstEditTextRow( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) const
1664 if (!ValidCol(nCol1
) || !ValidCol(nCol2
) || nCol2
< nCol1
)
1667 if (!ValidRow(nRow1
) || !ValidRow(nRow2
) || nRow2
< nRow1
)
1670 nCol2
= ClampToAllocatedColumns(nCol2
);
1671 SCROW nFirst
= rDocument
.MaxRow()+1;
1672 for (SCCOL i
= nCol1
; i
<= nCol2
; ++i
)
1674 const ScColumn
& rCol
= aCol
[i
];
1675 SCROW nThisFirst
= -1;
1676 if (const_cast<ScColumn
&>(rCol
).HasEditCells(nRow1
, nRow2
, nThisFirst
))
1678 if (nThisFirst
== nRow1
)
1681 if (nThisFirst
< nFirst
)
1682 nFirst
= nThisFirst
;
1686 return nFirst
== (rDocument
.MaxRow()+1) ? -1 : nFirst
;
1689 void ScTable::SetEmptyCell( SCCOL nCol
, SCROW nRow
)
1691 if (!ValidColRow(nCol
, nRow
) || nCol
>= GetAllocatedColumnsCount())
1694 aCol
[nCol
].Delete(nRow
);
1697 void ScTable::SetFormula(
1698 SCCOL nCol
, SCROW nRow
, const ScTokenArray
& rArray
, formula::FormulaGrammar::Grammar eGram
)
1700 if (!ValidColRow(nCol
, nRow
))
1703 CreateColumnIfNotExists(nCol
).SetFormula(nRow
, rArray
, eGram
);
1706 void ScTable::SetFormula(
1707 SCCOL nCol
, SCROW nRow
, const OUString
& rFormula
, formula::FormulaGrammar::Grammar eGram
)
1709 if (!ValidColRow(nCol
, nRow
))
1712 CreateColumnIfNotExists(nCol
).SetFormula(nRow
, rFormula
, eGram
);
1715 ScFormulaCell
* ScTable::SetFormulaCell( SCCOL nCol
, SCROW nRow
, ScFormulaCell
* pCell
)
1717 if (!ValidColRow(nCol
, nRow
))
1723 return CreateColumnIfNotExists(nCol
).SetFormulaCell(nRow
, pCell
, sc::ConvertToGroupListening
);
1726 bool ScTable::SetFormulaCells( SCCOL nCol
, SCROW nRow
, std::vector
<ScFormulaCell
*>& rCells
)
1728 if (!ValidCol(nCol
))
1731 return CreateColumnIfNotExists(nCol
).SetFormulaCells(nRow
, rCells
);
1734 svl::SharedString
ScTable::GetSharedString( SCCOL nCol
, SCROW nRow
) const
1736 if (!ValidColRow(nCol
, nRow
) || nCol
>= GetAllocatedColumnsCount())
1737 return svl::SharedString();
1739 return aCol
[nCol
].GetSharedString(nRow
);
1742 void ScTable::SetValue( SCCOL nCol
, SCROW nRow
, const double& rVal
)
1744 if (ValidColRow(nCol
, nRow
))
1745 CreateColumnIfNotExists(nCol
).SetValue(nRow
, rVal
);
1748 void ScTable::SetRawString( SCCOL nCol
, SCROW nRow
, const svl::SharedString
& rStr
)
1750 if (ValidColRow(nCol
, nRow
))
1751 CreateColumnIfNotExists(nCol
).SetRawString(nRow
, rStr
);
1754 OUString
ScTable::GetString( SCCOL nCol
, SCROW nRow
, const ScInterpreterContext
* pContext
) const
1756 if (ValidColRow(nCol
,nRow
) && nCol
< GetAllocatedColumnsCount())
1757 return aCol
[nCol
].GetString( nRow
, pContext
);
1762 double* ScTable::GetValueCell( SCCOL nCol
, SCROW nRow
)
1764 if (!ValidColRow(nCol
, nRow
))
1767 return CreateColumnIfNotExists(nCol
).GetValueCell(nRow
);
1770 OUString
ScTable::GetInputString( SCCOL nCol
, SCROW nRow
, const svl::SharedString
** pShared
) const
1772 if (ValidColRow(nCol
, nRow
) && nCol
< GetAllocatedColumnsCount())
1773 return aCol
[nCol
].GetInputString( nRow
, pShared
);
1778 double ScTable::GetValue( SCCOL nCol
, SCROW nRow
) const
1780 if (ValidColRow(nCol
, nRow
) && nCol
< GetAllocatedColumnsCount())
1781 return aCol
[nCol
].GetValue( nRow
);
1785 const EditTextObject
* ScTable::GetEditText( SCCOL nCol
, SCROW nRow
) const
1787 if (!ValidColRow(nCol
, nRow
) || nCol
>= GetAllocatedColumnsCount())
1790 return aCol
[nCol
].GetEditText(nRow
);
1793 void ScTable::RemoveEditTextCharAttribs( SCCOL nCol
, SCROW nRow
, const ScPatternAttr
& rAttr
)
1795 if (!ValidColRow(nCol
, nRow
) || nCol
>= GetAllocatedColumnsCount())
1798 return aCol
[nCol
].RemoveEditTextCharAttribs(nRow
, rAttr
);
1801 OUString
ScTable::GetFormula( SCCOL nCol
, SCROW nRow
) const
1803 if (ValidColRow(nCol
, nRow
) && nCol
< GetAllocatedColumnsCount())
1804 return aCol
[nCol
].GetFormula( nRow
);
1809 const ScFormulaCell
* ScTable::GetFormulaCell( SCCOL nCol
, SCROW nRow
) const
1811 if (!ValidColRow(nCol
, nRow
) || nCol
>= GetAllocatedColumnsCount())
1814 return aCol
[nCol
].GetFormulaCell(nRow
);
1817 ScFormulaCell
* ScTable::GetFormulaCell( SCCOL nCol
, SCROW nRow
)
1819 if (!ValidColRow(nCol
, nRow
))
1821 return CreateColumnIfNotExists(nCol
).GetFormulaCell(nRow
);
1824 std::unique_ptr
<ScPostIt
> ScTable::ReleaseNote( SCCOL nCol
, SCROW nRow
)
1826 if (!ValidCol(nCol
) || nCol
>= GetAllocatedColumnsCount())
1829 return aCol
[nCol
].ReleaseNote(nRow
);
1832 ScPostIt
* ScTable::GetNote( SCCOL nCol
, SCROW nRow
)
1834 if (!ValidCol(nCol
) || nCol
>= GetAllocatedColumnsCount())
1836 return aCol
[nCol
].GetCellNote(nRow
);
1839 void ScTable::SetNote( SCCOL nCol
, SCROW nRow
, std::unique_ptr
<ScPostIt
> pNote
)
1841 if (!ValidColRow(nCol
, nRow
))
1844 CreateColumnIfNotExists(nCol
).SetCellNote(nRow
, std::move(pNote
));
1847 size_t ScTable::GetNoteCount( SCCOL nCol
) const
1849 if (!ValidCol(nCol
) || nCol
>= GetAllocatedColumnsCount())
1852 return aCol
[nCol
].GetNoteCount();
1855 SCROW
ScTable::GetNotePosition( SCCOL nCol
, size_t nIndex
) const
1857 if (!ValidCol(nCol
) || nCol
>= GetAllocatedColumnsCount())
1860 return aCol
[nCol
].GetNotePosition(nIndex
);
1863 void ScTable::CreateAllNoteCaptions()
1865 for (SCCOL i
= 0; i
< aCol
.size(); ++i
)
1866 aCol
[i
].CreateAllNoteCaptions();
1869 void ScTable::ForgetNoteCaptions( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
, bool bPreserveData
)
1871 if (!ValidCol(nCol1
) || !ValidCol(nCol2
))
1873 if ( nCol2
>= aCol
.size() ) nCol2
= aCol
.size() - 1;
1874 for (SCCOL i
= nCol1
; i
<= nCol2
; ++i
)
1875 aCol
[i
].ForgetNoteCaptions(nRow1
, nRow2
, bPreserveData
);
1878 void ScTable::GetAllNoteEntries( std::vector
<sc::NoteEntry
>& rNotes
) const
1880 for (SCCOL nCol
= 0; nCol
< aCol
.size(); ++nCol
)
1881 aCol
[nCol
].GetAllNoteEntries(rNotes
);
1884 void ScTable::GetNotesInRange( const ScRange
& rRange
, std::vector
<sc::NoteEntry
>& rNotes
) const
1886 SCROW nStartRow
= rRange
.aStart
.Row();
1887 SCROW nEndRow
= rRange
.aEnd
.Row();
1888 SCCOL nEndCol
= ClampToAllocatedColumns(rRange
.aEnd
.Col());
1889 for (SCCOL nCol
= rRange
.aStart
.Col(); nCol
<= nEndCol
; ++nCol
)
1891 aCol
[nCol
].GetNotesInRange(nStartRow
, nEndRow
, rNotes
);
1895 CommentCaptionState
ScTable::GetAllNoteCaptionsState(const ScRange
& rRange
, std::vector
<sc::NoteEntry
>& rNotes
)
1897 SCROW nStartRow
= rRange
.aStart
.Row();
1898 SCROW nEndRow
= rRange
.aEnd
.Row();
1899 bool bIsFirstNoteShownState
= true; // because of error: -Werror=maybe-uninitialized
1900 bool bFirstControl
= true;
1902 ScTable
* pTab
= rDocument
.FetchTable(nTab
);
1904 const SCCOL nEndCol
= pTab
->ClampToAllocatedColumns(rRange
.aEnd
.Col());
1905 for (SCCOL nCol
= rRange
.aStart
.Col(); nCol
<= nEndCol
; ++nCol
)
1907 if (bFirstControl
&& rDocument
.HasColNotes(nCol
, nTab
)) // detect status of first note caption
1909 aCol
[nCol
].GetNotesInRange(nStartRow
, nEndRow
, rNotes
);
1910 bIsFirstNoteShownState
= rNotes
.begin()->mpNote
->IsCaptionShown();
1911 bFirstControl
= false;
1914 if (rDocument
.HasColNotes(nCol
, nTab
))
1916 aCol
[nCol
].GetNotesInRange(nStartRow
, nEndRow
, rNotes
);
1918 bool bIsMixedState
= std::any_of(rNotes
.begin(), rNotes
.end(), [bIsFirstNoteShownState
](const sc::NoteEntry
& rNote
) {
1919 // compare the first note caption with others
1920 return bIsFirstNoteShownState
!= rNote
.mpNote
->IsCaptionShown(); });
1922 return CommentCaptionState::MIXED
;
1925 return bIsFirstNoteShownState
? CommentCaptionState::ALLSHOWN
: CommentCaptionState::ALLHIDDEN
;
1928 void ScTable::GetUnprotectedCells( ScRangeList
& rRangeList
) const
1930 for (auto const & pCol
: aCol
)
1931 pCol
->GetUnprotectedCells(0, rDocument
.MaxRow(), rRangeList
);
1934 bool ScTable::ContainsNotesInRange( const ScRange
& rRange
) const
1936 SCROW nStartRow
= rRange
.aStart
.Row();
1937 SCROW nEndRow
= rRange
.aEnd
.Row();
1938 SCCOL nEndCol
= ClampToAllocatedColumns(rRange
.aEnd
.Col());
1939 for (SCCOL nCol
= rRange
.aStart
.Col(); nCol
<= nEndCol
; ++nCol
)
1941 bool bContainsNote
= !aCol
[nCol
].IsNotesEmptyBlock(nStartRow
, nEndRow
);
1949 CellType
ScTable::GetCellType( SCCOL nCol
, SCROW nRow
) const
1951 if (ValidColRow(nCol
, nRow
) && nCol
< GetAllocatedColumnsCount())
1952 return aCol
[nCol
].GetCellType( nRow
);
1953 return CELLTYPE_NONE
;
1956 ScRefCellValue
ScTable::GetCellValue( SCCOL nCol
, SCROW nRow
) const
1958 if (!ValidColRow(nCol
, nRow
) || nCol
>= GetAllocatedColumnsCount())
1959 return ScRefCellValue();
1961 return aCol
[nCol
].GetCellValue(nRow
);
1964 ScRefCellValue
ScTable::GetCellValue( SCCOL nCol
, sc::ColumnBlockPosition
& rBlockPos
, SCROW nRow
)
1966 if (!ValidColRow(nCol
, nRow
) || nCol
>= GetAllocatedColumnsCount())
1967 return ScRefCellValue();
1969 return aCol
[nCol
].GetCellValue(rBlockPos
, nRow
);
1972 void ScTable::GetFirstDataPos(SCCOL
& rCol
, SCROW
& rRow
) const
1975 rRow
= rDocument
.MaxRow()+1;
1976 while (rCol
< (aCol
.size() - 1) && aCol
[rCol
].IsEmptyData() )
1979 while (nCol
< aCol
.size() && rRow
> 0)
1981 if (!aCol
[nCol
].IsEmptyData())
1982 rRow
= ::std::min( rRow
, aCol
[nCol
].GetFirstDataPos());
1987 void ScTable::GetLastDataPos(SCCOL
& rCol
, SCROW
& rRow
) const
1989 rCol
= aCol
.size() - 1;
1991 while (aCol
[rCol
].IsEmptyData() && (rCol
> 0))
1994 while (nCol
>= 0 && rRow
< rDocument
.MaxRow())
1995 rRow
= ::std::max( rRow
, aCol
[nCol
--].GetLastDataPos());
1998 bool ScTable::HasData( SCCOL nCol
, SCROW nRow
) const
2000 if (ValidColRow(nCol
, nRow
) && nCol
< GetAllocatedColumnsCount())
2001 return aCol
[nCol
].HasDataAt( nRow
);
2006 bool ScTable::HasStringData( SCCOL nCol
, SCROW nRow
) const
2008 if (ValidColRow(nCol
, nRow
) && nCol
< GetAllocatedColumnsCount())
2009 return aCol
[nCol
].HasStringData( nRow
);
2014 bool ScTable::HasValueData( SCCOL nCol
, SCROW nRow
) const
2016 if (ValidColRow(nCol
, nRow
) && nCol
< GetAllocatedColumnsCount())
2017 return aCol
[nCol
].HasValueData( nRow
);
2022 bool ScTable::HasStringCells( SCCOL nStartCol
, SCROW nStartRow
,
2023 SCCOL nEndCol
, SCROW nEndRow
) const
2025 if (ValidCol(nEndCol
))
2027 nEndCol
= ClampToAllocatedColumns(nEndCol
);
2028 for (SCCOL nCol
= nStartCol
; nCol
<= nEndCol
; nCol
++)
2029 if (aCol
[nCol
].HasStringCells(nStartRow
, nEndRow
))
2036 void ScTable::SetDirtyVar()
2038 for (SCCOL i
=0; i
< aCol
.size(); i
++)
2039 aCol
[i
].SetDirtyVar();
2042 void ScTable::CheckVectorizationState()
2044 sc::AutoCalcSwitch
aACSwitch(rDocument
, false);
2046 for (SCCOL i
= 0; i
< aCol
.size(); i
++)
2047 aCol
[i
].CheckVectorizationState();
2050 void ScTable::SetAllFormulasDirty( const sc::SetFormulaDirtyContext
& rCxt
)
2052 sc::AutoCalcSwitch
aACSwitch(rDocument
, false);
2054 for (SCCOL i
=0; i
< aCol
.size(); i
++)
2055 aCol
[i
].SetAllFormulasDirty(rCxt
);
2058 void ScTable::SetDirty( const ScRange
& rRange
, ScColumn::BroadcastMode eMode
)
2060 bool bOldAutoCalc
= rDocument
.GetAutoCalc();
2061 rDocument
.SetAutoCalc( false ); // avoid multiple recalculations
2062 SCCOL nCol2
= rRange
.aEnd
.Col();
2063 nCol2
= ClampToAllocatedColumns(nCol2
);
2064 for (SCCOL i
=rRange
.aStart
.Col(); i
<=nCol2
; i
++)
2065 aCol
[i
].SetDirty(rRange
.aStart
.Row(), rRange
.aEnd
.Row(), eMode
);
2066 rDocument
.SetAutoCalc( bOldAutoCalc
);
2069 void ScTable::SetTableOpDirty( const ScRange
& rRange
)
2071 bool bOldAutoCalc
= rDocument
.GetAutoCalc();
2072 rDocument
.SetAutoCalc( false ); // no multiple recalculation
2073 const SCCOL nCol2
= ClampToAllocatedColumns(rRange
.aEnd
.Col());
2074 for (SCCOL i
=rRange
.aStart
.Col(); i
<=nCol2
; i
++)
2075 aCol
[i
].SetTableOpDirty( rRange
);
2076 rDocument
.SetAutoCalc( bOldAutoCalc
);
2079 void ScTable::SetDirtyAfterLoad()
2081 bool bOldAutoCalc
= rDocument
.GetAutoCalc();
2082 rDocument
.SetAutoCalc( false ); // avoid multiple recalculations
2083 for (SCCOL i
=0; i
< aCol
.size(); i
++)
2084 aCol
[i
].SetDirtyAfterLoad();
2085 rDocument
.SetAutoCalc( bOldAutoCalc
);
2088 void ScTable::SetDirtyIfPostponed()
2090 sc::AutoCalcSwitch
aSwitch(rDocument
, false);
2091 ScBulkBroadcast
aBulkBroadcast( rDocument
.GetBASM(), SfxHintId::ScDataChanged
);
2092 for (SCCOL i
=0; i
< aCol
.size(); i
++)
2093 aCol
[i
].SetDirtyIfPostponed();
2096 void ScTable::BroadcastRecalcOnRefMove()
2098 sc::AutoCalcSwitch
aSwitch(rDocument
, false);
2099 for (SCCOL i
= 0; i
< aCol
.size(); ++i
)
2100 aCol
[i
].BroadcastRecalcOnRefMove();
2103 bool ScTable::BroadcastBroadcasters( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
, SfxHintId nHint
)
2105 bool bBroadcasted
= false;
2106 sc::AutoCalcSwitch
aSwitch(rDocument
, false);
2107 nCol2
= ClampToAllocatedColumns(nCol2
);
2108 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
2109 bBroadcasted
|= aCol
[nCol
].BroadcastBroadcasters( nRow1
, nRow2
, nHint
);
2110 return bBroadcasted
;
2113 void ScTable::SetLoadingMedium(bool bLoading
)
2115 mpRowHeights
->enableTreeSearch(!bLoading
);
2118 void ScTable::CalcAll()
2120 for (SCCOL i
=0; i
< aCol
.size(); i
++)
2123 mpCondFormatList
->CalcAll();
2126 void ScTable::CompileAll( sc::CompileFormulaContext
& rCxt
)
2128 for (SCCOL i
= 0; i
< aCol
.size(); ++i
)
2129 aCol
[i
].CompileAll(rCxt
);
2131 if(mpCondFormatList
)
2132 mpCondFormatList
->CompileAll();
2135 void ScTable::CompileXML( sc::CompileFormulaContext
& rCxt
, ScProgress
& rProgress
)
2138 mpRangeName
->CompileUnresolvedXML(rCxt
);
2140 for (SCCOL i
=0; i
< aCol
.size(); i
++)
2142 aCol
[i
].CompileXML(rCxt
, rProgress
);
2145 if(mpCondFormatList
)
2146 mpCondFormatList
->CompileXML();
2149 bool ScTable::CompileErrorCells( sc::CompileFormulaContext
& rCxt
, FormulaError nErrCode
)
2151 bool bCompiled
= false;
2152 for (SCCOL i
= 0; i
< aCol
.size(); ++i
)
2154 if (aCol
[i
].CompileErrorCells(rCxt
, nErrCode
))
2161 void ScTable::CalcAfterLoad( sc::CompileFormulaContext
& rCxt
, bool bStartListening
)
2163 for (SCCOL i
= 0; i
< aCol
.size(); ++i
)
2164 aCol
[i
].CalcAfterLoad(rCxt
, bStartListening
);
2167 void ScTable::ResetChanged( const ScRange
& rRange
)
2169 SCCOL nStartCol
= rRange
.aStart
.Col();
2170 SCROW nStartRow
= rRange
.aStart
.Row();
2171 SCCOL nEndCol
= ClampToAllocatedColumns(rRange
.aEnd
.Col());
2172 SCROW nEndRow
= rRange
.aEnd
.Row();
2174 for (SCCOL nCol
=nStartCol
; nCol
<=nEndCol
; nCol
++)
2175 aCol
[nCol
].ResetChanged(nStartRow
, nEndRow
);
2180 const SfxPoolItem
* ScTable::GetAttr( SCCOL nCol
, SCROW nRow
, sal_uInt16 nWhich
) const
2182 if (ValidColRow(nCol
, nRow
) && nCol
< GetAllocatedColumnsCount())
2183 return &aCol
[nCol
].GetAttr( nRow
, nWhich
);
2188 sal_uInt32
ScTable::GetNumberFormat( const ScInterpreterContext
& rContext
, const ScAddress
& rPos
) const
2190 if (ValidColRow(rPos
.Col(), rPos
.Row()))
2192 if (rPos
.Col() < GetAllocatedColumnsCount())
2193 return aCol
[rPos
.Col()].GetNumberFormat(rContext
, rPos
.Row());
2194 return aDefaultColAttrArray
.GetPattern(rPos
.Row())
2195 ->GetNumberFormat(rContext
.GetFormatTable());
2200 sal_uInt32
ScTable::GetNumberFormat( SCCOL nCol
, SCROW nRow
) const
2202 if (ValidColRow(nCol
,nRow
))
2203 return CreateColumnIfNotExists(nCol
).GetNumberFormat(rDocument
.GetNonThreadedContext(), nRow
);
2208 sal_uInt32
ScTable::GetNumberFormat( SCCOL nCol
, SCROW nStartRow
, SCROW nEndRow
) const
2210 if (!ValidCol(nCol
) || !ValidRow(nStartRow
) || !ValidRow(nEndRow
))
2213 return CreateColumnIfNotExists(nCol
).GetNumberFormat(nStartRow
, nEndRow
);
2216 void ScTable::SetNumberFormat( SCCOL nCol
, SCROW nRow
, sal_uInt32 nNumberFormat
)
2218 if (!ValidColRow(nCol
, nRow
))
2221 CreateColumnIfNotExists(nCol
).SetNumberFormat(nRow
, nNumberFormat
);
2224 const ScPatternAttr
* ScTable::GetPattern( SCCOL nCol
, SCROW nRow
) const
2226 if (ValidColRow(nCol
,nRow
))
2227 return CreateColumnIfNotExists(nCol
).GetPattern( nRow
);
2230 OSL_FAIL("wrong column or row");
2231 return rDocument
.GetDefPattern(); // for safety
2235 const ScPatternAttr
* ScTable::GetMostUsedPattern( SCCOL nCol
, SCROW nStartRow
, SCROW nEndRow
) const
2237 if ( ValidColRow( nCol
, nStartRow
) && ValidRow( nEndRow
) && (nStartRow
<= nEndRow
)
2238 && nCol
< GetAllocatedColumnsCount())
2239 return aCol
[nCol
].GetMostUsedPattern( nStartRow
, nEndRow
);
2244 bool ScTable::HasAttrib( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
, HasAttrFlags nMask
) const
2246 for(SCCOL nCol
= nCol1
; nCol
<= nCol2
&& nCol
< aCol
.size(); ++nCol
)
2247 if( aCol
[nCol
].HasAttrib( nRow1
, nRow2
, nMask
))
2249 if( nCol2
>= aCol
.size())
2250 return aDefaultColAttrArray
.HasAttrib( nRow1
, nRow2
, nMask
);
2254 bool ScTable::HasAttribSelection( const ScMarkData
& rMark
, HasAttrFlags nMask
) const
2256 std::vector
<sc::ColRowSpan
> aSpans
= rMark
.GetMarkedColSpans();
2258 for (const sc::ColRowSpan
& aSpan
: aSpans
)
2260 for (SCCOLROW j
= aSpan
.mnStart
; j
<= aSpan
.mnEnd
; ++j
)
2262 if (aCol
[j
].HasAttribSelection(rMark
, nMask
))
2269 bool ScTable::ExtendMerge( SCCOL nStartCol
, SCROW nStartRow
,
2270 SCCOL
& rEndCol
, SCROW
& rEndRow
,
2273 if (!(ValidCol(nStartCol
) && ValidCol(rEndCol
)))
2275 OSL_FAIL("ScTable::ExtendMerge: invalid column number");
2278 if ( nStartCol
>= aCol
.size() )
2280 OSL_FAIL("ScTable::ExtendMerge: invalid nStartCol");
2283 bool bFound
= false;
2284 SCCOL nOldEndX
= std::min( rEndCol
, static_cast<SCCOL
>(aCol
.size()-1) );
2285 SCROW nOldEndY
= rEndRow
;
2286 for (SCCOL i
=nStartCol
; i
<=nOldEndX
; i
++)
2287 bFound
|= aCol
[i
].ExtendMerge( i
, nStartRow
, nOldEndY
, rEndCol
, rEndRow
, bRefresh
);
2291 void ScTable::SetMergedCells( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
2293 ScMergeAttr
aAttr(nCol2
-nCol1
+1, nRow2
-nRow1
+1);
2294 ApplyAttr(nCol1
, nRow1
, aAttr
);
2297 ApplyFlags(nCol1
+1, nRow1
, nCol2
, nRow2
, ScMF::Hor
);
2300 ApplyFlags(nCol1
, nRow1
+1, nCol1
, nRow2
, ScMF::Ver
);
2302 if (nCol1
< nCol2
&& nRow1
< nRow2
)
2303 ApplyFlags(nCol1
+1, nRow1
+1, nCol2
, nRow2
, ScMF::Hor
| ScMF::Ver
);
2306 bool ScTable::IsBlockEmpty( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
, bool bIgnoreNotes
) const
2308 if (!(ValidCol(nCol1
) && ValidCol(nCol2
)))
2310 OSL_FAIL("ScTable::IsBlockEmpty: invalid column number");
2313 nCol2
= ClampToAllocatedColumns(nCol2
);
2315 for (SCCOL i
=nCol1
; i
<=nCol2
&& bEmpty
; i
++)
2317 bEmpty
= aCol
[i
].IsEmptyBlock( nRow1
, nRow2
);
2318 if (!bIgnoreNotes
&& bEmpty
)
2320 bEmpty
= aCol
[i
].IsNotesEmptyBlock(nRow1
, nRow2
);
2326 SCSIZE
ScTable::FillMaxRot( RowInfo
* pRowInfo
, SCSIZE nArrCount
, SCCOL nX1
, SCCOL nX2
,
2327 SCCOL nCol
, SCROW nAttrRow1
, SCROW nAttrRow2
, SCSIZE nArrY
,
2328 const ScPatternAttr
* pPattern
, const SfxItemSet
* pCondSet
)
2330 // Return value = new nArrY
2332 ScRotateDir nRotDir
= pPattern
->GetRotateDir( pCondSet
);
2333 if ( nRotDir
!= ScRotateDir::NONE
)
2336 if ( nCol
+1 < nX1
) // column to the left
2337 bHit
= ( nRotDir
!= ScRotateDir::Left
);
2338 else if ( nCol
> nX2
+1 ) // column to the right
2339 bHit
= ( nRotDir
!= ScRotateDir::Right
); // ScRotateDir::Standard may now also be extended to the left
2343 double nFactor
= 0.0;
2346 Degree100 nRotVal
= pPattern
->
2347 GetItem( ATTR_ROTATE_VALUE
, pCondSet
).GetValue();
2348 double nRealOrient
= toRadians(nRotVal
);
2349 double nCos
= cos( nRealOrient
);
2350 double nSin
= sin( nRealOrient
);
2352 //TODO: additional factor for varying PPT X/Y !!!
2354 // for ScRotateDir::Left this gives a negative value,
2355 // if the mode is considered
2356 nFactor
= -fabs( nCos
/ nSin
);
2359 for ( SCROW nRow
= nAttrRow1
; nRow
<= nAttrRow2
; nRow
++ )
2361 if (!RowHidden(nRow
))
2363 bool bHitOne
= true;
2366 // Does the rotated cell extend into the visible range?
2368 SCCOL nTouchedCol
= nCol
;
2369 tools::Long nWidth
= static_cast<tools::Long
>(mpRowHeights
->getValue(nRow
) * nFactor
);
2370 OSL_ENSURE(nWidth
<= 0, "Wrong direction");
2371 while ( nWidth
< 0 && nTouchedCol
> 0 )
2374 nWidth
+= GetColWidth( nTouchedCol
);
2376 if ( nTouchedCol
> nX2
)
2382 while ( nArrY
<nArrCount
&& pRowInfo
[nArrY
].nRowNo
< nRow
)
2384 if ( nArrY
<nArrCount
&& pRowInfo
[nArrY
].nRowNo
== nRow
)
2385 pRowInfo
[nArrY
].nRotMaxCol
= nCol
;
2395 void ScTable::FindMaxRotCol( RowInfo
* pRowInfo
, SCSIZE nArrCount
, SCCOL nX1
, SCCOL nX2
)
2397 if ( !mpColWidth
|| !mpRowHeights
|| !mpColFlags
|| !pRowFlags
)
2399 OSL_FAIL( "Row/column info missing" );
2403 // nRotMaxCol is initialized to SC_ROTMAX_NONE, nRowNo is already set
2405 SCROW nY1
= pRowInfo
[0].nRowNo
;
2406 SCROW nY2
= pRowInfo
[nArrCount
-1].nRowNo
;
2408 for (SCCOL nCol
: GetColumnsRange(0, rDocument
.MaxCol()))
2410 if (!ColHidden(nCol
))
2413 ScDocAttrIterator
aIter( rDocument
, nTab
, nCol
, nY1
, nCol
, nY2
);
2415 SCROW nAttrRow1
, nAttrRow2
;
2416 const ScPatternAttr
* pPattern
= aIter
.GetNext( nAttrCol
, nAttrRow1
, nAttrRow2
);
2419 const SfxPoolItem
* pCondItem
;
2420 if ( pPattern
->GetItemSet().GetItemState( ATTR_CONDITIONAL
, true, &pCondItem
)
2421 == SfxItemState::SET
)
2423 // Run through all formats, so that each cell does not have to be
2424 // handled individually
2426 const ScCondFormatIndexes
& rCondFormatData
= static_cast<const ScCondFormatItem
*>(pCondItem
)->GetCondFormatData();
2427 ScStyleSheetPool
* pStylePool
= rDocument
.GetStyleSheetPool();
2428 if (mpCondFormatList
&& pStylePool
&& !rCondFormatData
.empty())
2430 for(const auto& rItem
: rCondFormatData
)
2432 const ScConditionalFormat
* pFormat
= mpCondFormatList
->GetFormat(rItem
);
2435 size_t nEntryCount
= pFormat
->size();
2436 for (size_t nEntry
=0; nEntry
<nEntryCount
; nEntry
++)
2438 const ScFormatEntry
* pEntry
= pFormat
->GetEntry(nEntry
);
2439 if(pEntry
->GetType() != ScFormatEntry::Type::Condition
&&
2440 pEntry
->GetType() != ScFormatEntry::Type::ExtCondition
)
2443 OUString aStyleName
= static_cast<const ScCondFormatEntry
*>(pEntry
)->GetStyle();
2444 if (!aStyleName
.isEmpty())
2446 SfxStyleSheetBase
* pStyleSheet
=
2447 pStylePool
->Find( aStyleName
, SfxStyleFamily::Para
);
2450 FillMaxRot( pRowInfo
, nArrCount
, nX1
, nX2
,
2451 nCol
, nAttrRow1
, nAttrRow2
,
2452 nArrY
, pPattern
, &pStyleSheet
->GetItemSet() );
2453 // not changing nArrY
2462 nArrY
= FillMaxRot( pRowInfo
, nArrCount
, nX1
, nX2
,
2463 nCol
, nAttrRow1
, nAttrRow2
,
2464 nArrY
, pPattern
, nullptr );
2466 pPattern
= aIter
.GetNext( nAttrCol
, nAttrRow1
, nAttrRow2
);
2472 bool ScTable::HasBlockMatrixFragment( const SCCOL nCol1
, SCROW nRow1
, const SCCOL nCol2
, SCROW nRow2
,
2473 bool bNoMatrixAtAll
) const
2477 if ( !IsColValid( nCol1
) )
2480 const SCCOL nMaxCol2
= std::min
<SCCOL
>( nCol2
, aCol
.size() - 1 );
2482 MatrixEdge nEdges
= MatrixEdge::Nothing
;
2484 if ( nCol1
== nMaxCol2
)
2485 { // left and right column
2486 const MatrixEdge n
= MatrixEdge::Left
| MatrixEdge::Right
;
2487 nEdges
= aCol
[nCol1
].GetBlockMatrixEdges( nRow1
, nRow2
, n
, bNoMatrixAtAll
);
2488 if ((nEdges
!= MatrixEdge::Nothing
) && (((nEdges
& n
)!=n
) || (nEdges
& (MatrixEdge::Inside
|MatrixEdge::Open
))))
2489 return true; // left or right edge is missing or open
2493 nEdges
= aCol
[nCol1
].GetBlockMatrixEdges(nRow1
, nRow2
, MatrixEdge::Left
, bNoMatrixAtAll
);
2494 if ((nEdges
!= MatrixEdge::Nothing
) && ((!(nEdges
& MatrixEdge::Left
)) || (nEdges
& (MatrixEdge::Inside
|MatrixEdge::Open
))))
2495 return true; // left edge missing or open
2497 nEdges
= aCol
[nMaxCol2
].GetBlockMatrixEdges(nRow1
, nRow2
, MatrixEdge::Right
, bNoMatrixAtAll
);
2498 if ((nEdges
!= MatrixEdge::Nothing
) && ((!(nEdges
& MatrixEdge::Right
)) || (nEdges
& (MatrixEdge::Inside
|MatrixEdge::Open
))))
2499 return true; // right edge is missing or open
2504 for (SCCOL i
=nCol1
; i
<=nMaxCol2
; i
++)
2506 nEdges
= aCol
[i
].GetBlockMatrixEdges( nRow1
, nRow2
, MatrixEdge::Nothing
, bNoMatrixAtAll
);
2507 if (nEdges
!= MatrixEdge::Nothing
2508 && (nEdges
!= (MatrixEdge::Top
| MatrixEdge::Left
| MatrixEdge::Bottom
| MatrixEdge::Right
)))
2512 else if ( nRow1
== nRow2
)
2513 { // Row on top and on bottom
2515 const MatrixEdge n
= MatrixEdge::Bottom
| MatrixEdge::Top
;
2516 for ( SCCOL i
=nCol1
; i
<=nMaxCol2
; i
++)
2518 nEdges
= aCol
[i
].GetBlockMatrixEdges( nRow1
, nRow1
, n
, bNoMatrixAtAll
);
2519 if (nEdges
!= MatrixEdge::Nothing
)
2521 if ( (nEdges
& n
) != n
)
2522 return true; // Top or bottom edge missing
2523 if (nEdges
& MatrixEdge::Left
)
2524 bOpen
= true; // left edge open, continue
2526 return true; // Something exist that has not been opened
2527 if (nEdges
& MatrixEdge::Right
)
2528 bOpen
= false; // Close right edge
2539 // first top row, then bottom row
2540 for ( j
=0, n
= MatrixEdge::Top
, nR
=nRow1
; j
<2;
2541 j
++, n
= MatrixEdge::Bottom
, nR
=nRow2
)
2544 for ( SCCOL i
=nCol1
; i
<=nMaxCol2
; i
++)
2546 nEdges
= aCol
[i
].GetBlockMatrixEdges( nR
, nR
, n
, bNoMatrixAtAll
);
2547 if ( nEdges
!= MatrixEdge::Nothing
)
2549 // in top row no top edge respectively
2550 // in bottom row no bottom edge
2551 if ( (nEdges
& n
) != n
)
2553 if (nEdges
& MatrixEdge::Left
)
2554 bOpen
= true; // open left edge, continue
2556 return true; // Something exist that has not been opened
2557 if (nEdges
& MatrixEdge::Right
)
2558 bOpen
= false; // Close right edge
2568 bool ScTable::HasSelectionMatrixFragment( const ScMarkData
& rMark
) const
2570 std::vector
<sc::ColRowSpan
> aSpans
= rMark
.GetMarkedColSpans();
2572 for (const sc::ColRowSpan
& aSpan
: aSpans
)
2574 SCCOL nEndCol
= ClampToAllocatedColumns(aSpan
.mnEnd
);
2575 for ( SCCOLROW j
=aSpan
.mnStart
; j
<=nEndCol
; j
++ )
2577 if ( aCol
[j
].HasSelectionMatrixFragment(rMark
) )
2584 bool ScTable::IsBlockEditable( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
,
2585 SCROW nRow2
, bool* pOnlyNotBecauseOfMatrix
/* = NULL */,
2586 bool bNoMatrixAtAll
) const
2588 if ( !ValidColRow( nCol2
, nRow2
) )
2590 SAL_WARN("sc", "IsBlockEditable: invalid column or row " << nCol2
<< " " << nRow2
);
2591 if (pOnlyNotBecauseOfMatrix
)
2592 *pOnlyNotBecauseOfMatrix
= false;
2595 nCol1
= ClampToAllocatedColumns(nCol1
);
2596 nCol2
= ClampToAllocatedColumns(nCol2
);
2598 bool bIsEditable
= true;
2600 bIsEditable
= false;
2601 else if ( IsProtected() && !rDocument
.IsScenario(nTab
) )
2603 bIsEditable
= !HasAttrib( nCol1
, nRow1
, nCol2
, nRow2
, HasAttrFlags::Protected
);
2606 // An enhanced protection permission may override the attribute.
2608 bIsEditable
= pTabProtection
->isBlockEditable( ScRange( nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
));
2612 // If Sheet is protected and cells are not protected then
2613 // check the active scenario protect flag if this range is
2614 // on the active scenario range. Note the 'copy back' must also
2615 // be set to apply protection.
2616 sal_uInt16 nScenTab
= nTab
+1;
2617 while(rDocument
.IsScenario(nScenTab
))
2619 ScRange
aEditRange(nCol1
, nRow1
, nScenTab
, nCol2
, nRow2
, nScenTab
);
2620 if(rDocument
.IsActiveScenario(nScenTab
) && rDocument
.HasScenarioRange(nScenTab
, aEditRange
))
2622 ScScenarioFlags nFlags
;
2623 rDocument
.GetScenarioFlags(nScenTab
,nFlags
);
2624 bIsEditable
= !((nFlags
& ScScenarioFlags::Protected
) && (nFlags
& ScScenarioFlags::TwoWay
));
2631 else if (rDocument
.IsScenario(nTab
))
2633 // Determine if the preceding sheet is protected
2634 SCTAB nActualTab
= nTab
;
2639 while(rDocument
.IsScenario(nActualTab
));
2641 if(rDocument
.IsTabProtected(nActualTab
))
2643 ScRange
aEditRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
);
2644 if(rDocument
.HasScenarioRange(nTab
, aEditRange
))
2646 ScScenarioFlags nFlags
;
2647 rDocument
.GetScenarioFlags(nTab
,nFlags
);
2648 bIsEditable
= !(nFlags
& ScScenarioFlags::Protected
);
2654 if (HasBlockMatrixFragment( nCol1
, nRow1
, nCol2
, nRow2
, bNoMatrixAtAll
))
2656 bIsEditable
= false;
2657 if ( pOnlyNotBecauseOfMatrix
)
2658 *pOnlyNotBecauseOfMatrix
= true;
2660 else if ( pOnlyNotBecauseOfMatrix
)
2661 *pOnlyNotBecauseOfMatrix
= false;
2663 else if ( pOnlyNotBecauseOfMatrix
)
2664 *pOnlyNotBecauseOfMatrix
= false;
2668 bool ScTable::IsSelectionEditable( const ScMarkData
& rMark
,
2669 bool* pOnlyNotBecauseOfMatrix
/* = NULL */ ) const
2671 bool bIsEditable
= true;
2673 bIsEditable
= false;
2674 else if ( IsProtected() && !rDocument
.IsScenario(nTab
) )
2676 ScRangeList aRanges
;
2677 rMark
.FillRangeListWithMarks( &aRanges
, false );
2678 bIsEditable
= !HasAttribSelection( rMark
, HasAttrFlags::Protected
);
2681 // An enhanced protection permission may override the attribute.
2683 bIsEditable
= pTabProtection
->isSelectionEditable( aRanges
);
2687 // If Sheet is protected and cells are not protected then
2688 // check the active scenario protect flag if this area is
2689 // in the active scenario range.
2690 SCTAB nScenTab
= nTab
+1;
2691 while(rDocument
.IsScenario(nScenTab
) && bIsEditable
)
2693 if(rDocument
.IsActiveScenario(nScenTab
))
2695 for (size_t i
=0, nRange
= aRanges
.size(); (i
< nRange
) && bIsEditable
; i
++ )
2697 const ScRange
& rRange
= aRanges
[ i
];
2698 if(rDocument
.HasScenarioRange(nScenTab
, rRange
))
2700 ScScenarioFlags nFlags
;
2701 rDocument
.GetScenarioFlags(nScenTab
,nFlags
);
2702 bIsEditable
= !((nFlags
& ScScenarioFlags::Protected
) && (nFlags
& ScScenarioFlags::TwoWay
));
2710 else if (rDocument
.IsScenario(nTab
))
2712 // Determine if the preceding sheet is protected
2713 SCTAB nActualTab
= nTab
;
2718 while(rDocument
.IsScenario(nActualTab
));
2720 if(rDocument
.IsTabProtected(nActualTab
))
2722 ScRangeList aRanges
;
2723 rMark
.FillRangeListWithMarks( &aRanges
, false );
2724 for (size_t i
= 0, nRange
= aRanges
.size(); (i
< nRange
) && bIsEditable
; i
++)
2726 const ScRange
& rRange
= aRanges
[ i
];
2727 if(rDocument
.HasScenarioRange(nTab
, rRange
))
2729 ScScenarioFlags nFlags
;
2730 rDocument
.GetScenarioFlags(nTab
,nFlags
);
2731 bIsEditable
= !(nFlags
& ScScenarioFlags::Protected
);
2738 if ( HasSelectionMatrixFragment( rMark
) )
2740 bIsEditable
= false;
2741 if ( pOnlyNotBecauseOfMatrix
)
2742 *pOnlyNotBecauseOfMatrix
= true;
2744 else if ( pOnlyNotBecauseOfMatrix
)
2745 *pOnlyNotBecauseOfMatrix
= false;
2747 else if ( pOnlyNotBecauseOfMatrix
)
2748 *pOnlyNotBecauseOfMatrix
= false;
2752 void ScTable::LockTable()
2757 void ScTable::UnlockTable()
2763 OSL_FAIL("UnlockTable without LockTable");
2767 void ScTable::MergeSelectionPattern( ScMergePatternState
& rState
, const ScMarkData
& rMark
, bool bDeep
) const
2769 std::vector
<sc::ColRowSpan
> aSpans
= rMark
.GetMarkedColSpans();
2771 for (const sc::ColRowSpan
& rSpan
: aSpans
)
2773 for (SCCOLROW i
= rSpan
.mnStart
; i
<= rSpan
.mnEnd
; ++i
)
2775 CreateColumnIfNotExists(i
).MergeSelectionPattern( rState
, rMark
, bDeep
);
2780 void ScTable::MergePatternArea( ScMergePatternState
& rState
, SCCOL nCol1
, SCROW nRow1
,
2781 SCCOL nCol2
, SCROW nRow2
, bool bDeep
) const
2783 nCol2
= ClampToAllocatedColumns(nCol2
);
2784 for (SCCOL i
=nCol1
; i
<=nCol2
; i
++)
2785 aCol
[i
].MergePatternArea( rState
, nRow1
, nRow2
, bDeep
);
2788 void ScTable::MergeBlockFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
, ScLineFlags
& rFlags
,
2789 SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
) const
2791 if (ValidColRow(nStartCol
, nStartRow
) && ValidColRow(nEndCol
, nEndRow
))
2793 PutInOrder(nStartCol
, nEndCol
);
2794 PutInOrder(nStartRow
, nEndRow
);
2795 nEndCol
= ClampToAllocatedColumns(nEndCol
);
2796 for (SCCOL i
=nStartCol
; i
<=nEndCol
; i
++)
2797 aCol
[i
].MergeBlockFrame( pLineOuter
, pLineInner
, rFlags
,
2798 nStartRow
, nEndRow
, (i
==nStartCol
), nEndCol
-i
);
2802 void ScTable::ApplyBlockFrame(const SvxBoxItem
& rLineOuter
, const SvxBoxInfoItem
* pLineInner
,
2803 SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
)
2805 if (ValidColRow(nStartCol
, nStartRow
) && ValidColRow(nEndCol
, nEndRow
))
2807 PutInOrder(nStartCol
, nEndCol
);
2808 PutInOrder(nStartRow
, nEndRow
);
2809 nEndCol
= ClampToAllocatedColumns(nEndCol
);
2810 for (SCCOL i
=nStartCol
; i
<=nEndCol
; i
++)
2811 aCol
[i
].ApplyBlockFrame(rLineOuter
, pLineInner
,
2812 nStartRow
, nEndRow
, (i
==nStartCol
), nEndCol
-i
);
2816 void ScTable::ApplyPattern( SCCOL nCol
, SCROW nRow
, const ScPatternAttr
& rAttr
)
2818 if (ValidColRow(nCol
,nRow
))
2819 CreateColumnIfNotExists(nCol
).ApplyPattern( nRow
, rAttr
);
2822 void ScTable::ApplyPatternArea( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
,
2823 const ScPatternAttr
& rAttr
, ScEditDataArray
* pDataArray
,
2824 bool* const pIsChanged
)
2826 if (ValidColRow(nStartCol
, nStartRow
) && ValidColRow(nEndCol
, nEndRow
))
2828 PutInOrder(nStartCol
, nEndCol
);
2829 PutInOrder(nStartRow
, nEndRow
);
2830 for (SCCOL i
= nStartCol
; i
<= nEndCol
; i
++)
2831 CreateColumnIfNotExists(i
).ApplyPatternArea(nStartRow
, nEndRow
, rAttr
, pDataArray
, pIsChanged
);
2835 void ScTable::ApplyPatternIfNumberformatIncompatible( const ScRange
& rRange
,
2836 const ScPatternAttr
& rPattern
, SvNumFormatType nNewType
)
2838 SCCOL nEndCol
= rRange
.aEnd
.Col();
2839 for ( SCCOL nCol
= rRange
.aStart
.Col(); nCol
<= nEndCol
; nCol
++ )
2841 aCol
[nCol
].ApplyPatternIfNumberformatIncompatible( rRange
, rPattern
, nNewType
);
2845 void ScTable::AddCondFormatData( const ScRangeList
& rRangeList
, sal_uInt32 nIndex
)
2847 size_t n
= rRangeList
.size();
2848 for(size_t i
= 0; i
< n
; ++i
)
2850 const ScRange
& rRange
= rRangeList
[i
];
2851 SCCOL nColStart
= rRange
.aStart
.Col();
2852 SCCOL nColEnd
= rRange
.aEnd
.Col();
2853 SCROW nRowStart
= rRange
.aStart
.Row();
2854 SCROW nRowEnd
= rRange
.aEnd
.Row();
2855 for(SCCOL nCol
= nColStart
; nCol
<= nColEnd
; ++nCol
)
2857 CreateColumnIfNotExists(nCol
).AddCondFormat(nRowStart
, nRowEnd
, nIndex
);
2862 void ScTable::RemoveCondFormatData( const ScRangeList
& rRangeList
, sal_uInt32 nIndex
)
2864 size_t n
= rRangeList
.size();
2865 for(size_t i
= 0; i
< n
; ++i
)
2867 const ScRange
& rRange
= rRangeList
[i
];
2868 SCCOL nColStart
= rRange
.aStart
.Col();
2869 SCCOL nColEnd
= ClampToAllocatedColumns(rRange
.aEnd
.Col());
2870 SCROW nRowStart
= rRange
.aStart
.Row();
2871 SCROW nRowEnd
= rRange
.aEnd
.Row();
2872 for(SCCOL nCol
= nColStart
; nCol
<= nColEnd
; ++nCol
)
2874 aCol
[nCol
].RemoveCondFormat(nRowStart
, nRowEnd
, nIndex
);
2879 void ScTable::SetPatternAreaCondFormat( SCCOL nCol
, SCROW nStartRow
, SCROW nEndRow
,
2880 const ScPatternAttr
& rAttr
, const ScCondFormatIndexes
& rCondFormatIndexes
)
2882 aCol
[nCol
].SetPatternArea( nStartRow
, nEndRow
, rAttr
);
2884 for (const auto& rIndex
: rCondFormatIndexes
)
2886 ScConditionalFormat
* pCondFormat
= mpCondFormatList
->GetFormat(rIndex
);
2889 ScRangeList aRange
= pCondFormat
->GetRange();
2890 aRange
.Join( ScRange( nCol
, nStartRow
, nTab
, nCol
, nEndRow
, nTab
));
2891 pCondFormat
->SetRange(aRange
);
2896 void ScTable::ApplyStyle( SCCOL nCol
, SCROW nRow
, const ScStyleSheet
* rStyle
)
2898 if (ValidColRow(nCol
,nRow
))
2899 // If column not exists then we need to create it
2900 CreateColumnIfNotExists( nCol
).ApplyStyle( nRow
, rStyle
);
2903 void ScTable::ApplyStyleArea( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
, const ScStyleSheet
& rStyle
)
2905 if (!(ValidColRow(nStartCol
, nStartRow
) && ValidColRow(nEndCol
, nEndRow
)))
2908 PutInOrder(nStartCol
, nEndCol
);
2909 PutInOrder(nStartRow
, nEndRow
);
2910 if ( nEndCol
== rDocument
.MaxCol() )
2912 if ( nStartCol
< aCol
.size() )
2914 // If we would like set all columns to specific style, then change only default style for not existing columns
2915 nEndCol
= aCol
.size() - 1;
2916 for (SCCOL i
= nStartCol
; i
<= nEndCol
; i
++)
2917 aCol
[i
].ApplyStyleArea(nStartRow
, nEndRow
, rStyle
);
2918 aDefaultColAttrArray
.ApplyStyleArea(nStartRow
, nEndRow
, rStyle
);
2922 CreateColumnIfNotExists( nStartCol
- 1 );
2923 aDefaultColAttrArray
.ApplyStyleArea(nStartRow
, nEndRow
, rStyle
);
2928 CreateColumnIfNotExists( nEndCol
);
2929 for (SCCOL i
= nStartCol
; i
<= nEndCol
; i
++)
2930 aCol
[i
].ApplyStyleArea(nStartRow
, nEndRow
, rStyle
);
2934 void ScTable::ApplySelectionStyle(const ScStyleSheet
& rStyle
, const ScMarkData
& rMark
)
2936 for (SCCOL i
=0; i
< aCol
.size(); i
++)
2937 aCol
[i
].ApplySelectionStyle( rStyle
, rMark
);
2940 void ScTable::ApplySelectionLineStyle( const ScMarkData
& rMark
,
2941 const ::editeng::SvxBorderLine
* pLine
, bool bColorOnly
)
2943 if ( bColorOnly
&& !pLine
)
2946 for (SCCOL i
=0; i
< aCol
.size(); i
++)
2947 aCol
[i
].ApplySelectionLineStyle( rMark
, pLine
, bColorOnly
);
2950 const ScStyleSheet
* ScTable::GetStyle( SCCOL nCol
, SCROW nRow
) const
2952 if ( !ValidColRow( nCol
, nRow
) )
2954 if ( nCol
< aCol
.size() )
2955 return aCol
[nCol
].GetStyle( nRow
);
2957 return aDefaultColAttrArray
.GetPattern( nRow
)->GetStyleSheet();
2960 const ScStyleSheet
* ScTable::GetSelectionStyle( const ScMarkData
& rMark
, bool& rFound
) const
2967 const ScStyleSheet
* pStyle
= nullptr;
2968 const ScStyleSheet
* pNewStyle
;
2970 for (SCCOL i
=0; i
< aCol
.size() && bEqual
; i
++)
2971 if (rMark
.HasMultiMarks(i
))
2973 pNewStyle
= aCol
[i
].GetSelectionStyle( rMark
, bColFound
);
2977 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
2983 return bEqual
? pStyle
: nullptr;
2986 const ScStyleSheet
* ScTable::GetAreaStyle( bool& rFound
, SCCOL nCol1
, SCROW nRow1
,
2987 SCCOL nCol2
, SCROW nRow2
) const
2994 const ScStyleSheet
* pStyle
= nullptr;
2995 const ScStyleSheet
* pNewStyle
;
2996 nCol2
= ClampToAllocatedColumns(nCol2
);
2997 for (SCCOL i
=nCol1
; i
<=nCol2
&& bEqual
; i
++)
2999 pNewStyle
= aCol
[i
].GetAreaStyle(bColFound
, nRow1
, nRow2
);
3003 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
3009 return bEqual
? pStyle
: nullptr;
3012 bool ScTable::IsStyleSheetUsed( const ScStyleSheet
& rStyle
) const
3014 bool bIsUsed
= false;
3016 for ( SCCOL i
=0; i
< aCol
.size(); i
++ )
3018 if ( aCol
[i
].IsStyleSheetUsed( rStyle
) )
3027 void ScTable::StyleSheetChanged( const SfxStyleSheetBase
* pStyleSheet
, bool bRemoved
,
3029 double nPPTX
, double nPPTY
,
3030 const Fraction
& rZoomX
, const Fraction
& rZoomY
)
3032 ScFlatBoolRowSegments
aUsedRows(rDocument
.MaxRow());
3033 for (SCCOL i
= 0; i
< aCol
.size(); ++i
)
3034 aCol
[i
].FindStyleSheet(pStyleSheet
, aUsedRows
, bRemoved
);
3036 sc::RowHeightContext
aCxt(rDocument
.MaxRow(), nPPTX
, nPPTY
, rZoomX
, rZoomY
, pDev
);
3038 while (nRow
<= rDocument
.MaxRow())
3040 ScFlatBoolRowSegments::RangeData aData
;
3041 if (!aUsedRows
.getRangeData(nRow
, aData
))
3045 SCROW nEndRow
= aData
.mnRow2
;
3047 SetOptimalHeight(aCxt
, nRow
, nEndRow
, true);
3053 bool ScTable::ApplyFlags( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
,
3056 bool bChanged
= false;
3057 if (ValidColRow(nStartCol
, nStartRow
) && ValidColRow(nEndCol
, nEndRow
))
3058 for (SCCOL i
= nStartCol
; i
<= nEndCol
; i
++)
3059 bChanged
|= CreateColumnIfNotExists(i
).ApplyFlags(nStartRow
, nEndRow
, nFlags
);
3063 bool ScTable::RemoveFlags( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
,
3066 if (!ValidColRow(nStartCol
, nStartRow
) || !ValidColRow(nEndCol
, nEndRow
))
3068 bool bChanged
= false;
3069 nEndCol
= ClampToAllocatedColumns(nEndCol
);
3070 for (SCCOL i
= nStartCol
; i
<= nEndCol
; i
++)
3071 bChanged
|= aCol
[i
].RemoveFlags(nStartRow
, nEndRow
, nFlags
);
3075 void ScTable::SetPattern( const ScAddress
& rPos
, const ScPatternAttr
& rAttr
)
3077 if (ValidColRow(rPos
.Col(),rPos
.Row()))
3078 CreateColumnIfNotExists(rPos
.Col()).SetPattern(rPos
.Row(), rAttr
);
3081 const ScPatternAttr
* ScTable::SetPattern( SCCOL nCol
, SCROW nRow
, std::unique_ptr
<ScPatternAttr
> pAttr
)
3083 if (ValidColRow(nCol
,nRow
))
3084 return CreateColumnIfNotExists(nCol
).SetPattern(nRow
, std::move(pAttr
));
3088 void ScTable::SetPattern( SCCOL nCol
, SCROW nRow
, const ScPatternAttr
& rAttr
)
3090 if (ValidColRow(nCol
,nRow
))
3091 CreateColumnIfNotExists(nCol
).SetPattern(nRow
, rAttr
);
3094 void ScTable::ApplyAttr( SCCOL nCol
, SCROW nRow
, const SfxPoolItem
& rAttr
)
3096 if (ValidColRow(nCol
,nRow
))
3097 CreateColumnIfNotExists(nCol
).ApplyAttr( nRow
, rAttr
);
3100 void ScTable::ApplySelectionCache( SfxItemPoolCache
* pCache
, const ScMarkData
& rMark
,
3101 ScEditDataArray
* pDataArray
, bool* const pIsChanged
)
3103 for (SCCOL i
=0; i
< aCol
.size(); i
++)
3104 aCol
[i
].ApplySelectionCache( pCache
, rMark
, pDataArray
, pIsChanged
);
3107 void ScTable::ChangeSelectionIndent( bool bIncrement
, const ScMarkData
& rMark
)
3109 for (SCCOL i
=0; i
< aCol
.size(); i
++)
3110 aCol
[i
].ChangeSelectionIndent( bIncrement
, rMark
);
3113 void ScTable::ClearSelectionItems( const sal_uInt16
* pWhich
, const ScMarkData
& rMark
)
3115 for (SCCOL i
=0; i
< aCol
.size(); i
++)
3116 aCol
[i
].ClearSelectionItems( pWhich
, rMark
);
3119 // Column widths / Row heights
3121 void ScTable::SetColWidth( SCCOL nCol
, sal_uInt16 nNewWidth
)
3123 if (ValidCol(nCol
) && mpColWidth
)
3127 nNewWidth
= STD_COL_WIDTH
;
3130 if ( nNewWidth
!= mpColWidth
->GetValue(nCol
) )
3132 mpColWidth
->SetValue(nCol
, nNewWidth
);
3133 InvalidatePageBreaks();
3138 OSL_FAIL("Invalid column number or no widths");
3142 void ScTable::SetColWidthOnly( SCCOL nCol
, sal_uInt16 nNewWidth
)
3144 if (!ValidCol(nCol
) || !mpColWidth
)
3148 nNewWidth
= STD_COL_WIDTH
;
3150 if (nNewWidth
!= mpColWidth
->GetValue(nCol
))
3151 mpColWidth
->SetValue(nCol
, nNewWidth
);
3154 void ScTable::SetRowHeight( SCROW nRow
, sal_uInt16 nNewHeight
)
3156 if (ValidRow(nRow
) && mpRowHeights
)
3160 OSL_FAIL("SetRowHeight: Row height zero");
3161 nNewHeight
= ScGlobal::nStdRowHeight
;
3164 sal_uInt16 nOldHeight
= mpRowHeights
->getValue(nRow
);
3165 if ( nNewHeight
!= nOldHeight
)
3167 mpRowHeights
->setValue(nRow
, nRow
, nNewHeight
);
3168 InvalidatePageBreaks();
3173 OSL_FAIL("Invalid row number or no heights");
3180 * Check if the new pixel size is different from the old size between
3183 bool lcl_pixelSizeChanged(
3184 ScFlatUInt16RowSegments
& rRowHeights
, SCROW nStartRow
, SCROW nEndRow
,
3185 sal_uInt16 nNewHeight
, double nPPTY
, bool bApi
)
3187 tools::Long nNewPix
= static_cast<tools::Long
>(nNewHeight
* nPPTY
);
3189 ScFlatUInt16RowSegments::ForwardIterator
aFwdIter(rRowHeights
);
3190 for (SCROW nRow
= nStartRow
; nRow
<= nEndRow
; ++nRow
)
3193 if (!aFwdIter
.getValue(nRow
, nHeight
))
3196 if (nHeight
!= nNewHeight
)
3198 tools::Long nOldPix
= static_cast<tools::Long
>(nHeight
* nPPTY
);
3200 // Heuristic: Don't bother when handling interactive input, if changing just one row and
3201 // the height will shrink.
3202 bool bChanged
= (nNewPix
!= nOldPix
) && (bApi
|| nEndRow
- nStartRow
> 0 || nNewPix
> nOldPix
);
3207 // Skip ahead to the last position of the current range.
3208 nRow
= aFwdIter
.getLastPos();
3215 bool ScTable::SetRowHeightRange( SCROW nStartRow
, SCROW nEndRow
, sal_uInt16 nNewHeight
,
3216 double nPPTY
, bool bApi
)
3218 bool bChanged
= false;
3219 if (ValidRow(nStartRow
) && ValidRow(nEndRow
) && mpRowHeights
)
3223 OSL_FAIL("SetRowHeight: Row height zero");
3224 nNewHeight
= ScGlobal::nStdRowHeight
;
3227 bool bSingle
= false; // true = process every row for its own
3228 ScDrawLayer
* pDrawLayer
= rDocument
.GetDrawLayer();
3230 if (pDrawLayer
->HasObjectsInRows( nTab
, nStartRow
, nEndRow
))
3235 ScFlatUInt16RowSegments::RangeData aData
;
3236 if (mpRowHeights
->getRangeData(nStartRow
, aData
) &&
3237 nNewHeight
== aData
.mnValue
&& nEndRow
<= aData
.mnRow2
)
3239 bSingle
= false; // no difference in this range
3243 // No idea why 20 is used here
3244 if (!bSingle
|| nEndRow
- nStartRow
< 20)
3246 bChanged
= lcl_pixelSizeChanged(*mpRowHeights
, nStartRow
, nEndRow
, nNewHeight
, nPPTY
, bApi
);
3248 mpRowHeights
->setValue(nStartRow
, nEndRow
, nNewHeight
);
3252 SCROW nMid
= (nStartRow
+ nEndRow
) / 2;
3253 // No idea why nPPTY is ignored in these recursive calls and instead 1.0 is used
3254 if (SetRowHeightRange(nStartRow
, nMid
, nNewHeight
, 1.0, bApi
))
3256 if (SetRowHeightRange(nMid
+ 1, nEndRow
, nNewHeight
, 1.0, bApi
))
3261 InvalidatePageBreaks();
3265 OSL_FAIL("Invalid row number or no heights");
3271 void ScTable::SetRowHeightOnly( SCROW nStartRow
, SCROW nEndRow
, sal_uInt16 nNewHeight
)
3273 if (!ValidRow(nStartRow
) || !ValidRow(nEndRow
) || !mpRowHeights
)
3277 nNewHeight
= ScGlobal::nStdRowHeight
;
3279 mpRowHeights
->setValue(nStartRow
, nEndRow
, nNewHeight
);
3282 void ScTable::SetManualHeight( SCROW nStartRow
, SCROW nEndRow
, bool bManual
)
3284 if (ValidRow(nStartRow
) && ValidRow(nEndRow
) && pRowFlags
)
3287 pRowFlags
->OrValue( nStartRow
, nEndRow
, CRFlags::ManualSize
);
3289 pRowFlags
->AndValue( nStartRow
, nEndRow
, ~CRFlags::ManualSize
);
3293 OSL_FAIL("Invalid row number or no column flags");
3297 sal_uInt16
ScTable::GetColWidth( SCCOL nCol
, bool bHiddenAsZero
) const
3299 OSL_ENSURE(ValidCol(nCol
),"wrong column number");
3301 if (ValidCol(nCol
) && mpColFlags
&& mpColWidth
)
3303 if (bHiddenAsZero
&& ColHidden(nCol
))
3306 return mpColWidth
->GetValue(nCol
);
3309 return sal_uInt16(STD_COL_WIDTH
);
3312 sal_uLong
ScTable::GetColWidth( SCCOL nStartCol
, SCCOL nEndCol
) const
3314 if (!ValidCol(nStartCol
) || !ValidCol(nEndCol
) || nStartCol
> nEndCol
)
3318 bool bHidden
= false;
3319 SCCOL nLastHiddenCol
= -1;
3320 auto colWidthIt
= mpColWidth
->begin() + nStartCol
;
3321 for (SCCOL nCol
= nStartCol
; nCol
<= nEndCol
; (++nCol
<= nEndCol
) ? ++colWidthIt
: (void)false)
3323 if (nCol
> nLastHiddenCol
)
3324 bHidden
= ColHidden(nCol
, nullptr, &nLastHiddenCol
);
3334 sal_uInt16
ScTable::GetOriginalWidth( SCCOL nCol
) const // always the set value
3336 OSL_ENSURE(ValidCol(nCol
),"wrong column number");
3338 if (ValidCol(nCol
) && mpColWidth
)
3339 return mpColWidth
->GetValue(nCol
);
3341 return sal_uInt16(STD_COL_WIDTH
);
3344 sal_uInt16
ScTable::GetCommonWidth( SCCOL nEndCol
) const
3346 // get the width that is used in the largest continuous column range (up to nEndCol)
3348 if ( !ValidCol(nEndCol
) )
3350 OSL_FAIL("wrong column");
3351 nEndCol
= rDocument
.MaxCol();
3354 sal_uInt16 nMaxWidth
= 0;
3355 sal_uInt16 nMaxCount
= 0;
3356 SCCOL nRangeStart
= 0;
3357 while ( nRangeStart
<= nEndCol
)
3359 // skip hidden columns
3360 while ( nRangeStart
<= nEndCol
&& ColHidden(nRangeStart
) )
3362 if ( nRangeStart
<= nEndCol
)
3364 sal_uInt16 nThisCount
= 0;
3365 auto colWidthIt
= mpColWidth
->begin() + nRangeStart
;
3366 sal_uInt16 nThisWidth
= *colWidthIt
;
3367 SCCOL nRangeEnd
= nRangeStart
;
3368 while ( nRangeEnd
<= nEndCol
&& *colWidthIt
== nThisWidth
)
3374 // skip hidden columns
3375 while ( nRangeEnd
<= nEndCol
&& ColHidden(nRangeEnd
) )
3382 if ( nThisCount
> nMaxCount
)
3384 nMaxCount
= nThisCount
;
3385 nMaxWidth
= nThisWidth
;
3388 nRangeStart
= nRangeEnd
; // next range
3395 sal_uInt16
ScTable::GetRowHeight( SCROW nRow
, SCROW
* pStartRow
, SCROW
* pEndRow
, bool bHiddenAsZero
) const
3397 SAL_WARN_IF(!ValidRow(nRow
), "sc", "Invalid row number " << nRow
);
3399 if (ValidRow(nRow
) && mpRowHeights
)
3401 if (bHiddenAsZero
&& RowHidden( nRow
, pStartRow
, pEndRow
))
3405 ScFlatUInt16RowSegments::RangeData aData
;
3406 if (!mpRowHeights
->getRangeData(nRow
, aData
))
3412 // TODO: What should we return in case the search fails?
3416 // If bHiddenAsZero, pStartRow and pEndRow were initialized to
3417 // boundaries of a non-hidden segment. Assume that the previous and
3418 // next segment are hidden then and limit the current height
3421 *pStartRow
= (bHiddenAsZero
? std::max( *pStartRow
, aData
.mnRow1
) : aData
.mnRow1
);
3423 *pEndRow
= (bHiddenAsZero
? std::min( *pEndRow
, aData
.mnRow2
) : aData
.mnRow2
);
3424 return aData
.mnValue
;
3433 return ScGlobal::nStdRowHeight
;
3437 sal_uLong
ScTable::GetRowHeight( SCROW nStartRow
, SCROW nEndRow
, bool bHiddenAsZero
) const
3439 OSL_ENSURE(ValidRow(nStartRow
) && ValidRow(nEndRow
),"wrong row number");
3441 if (ValidRow(nStartRow
) && ValidRow(nEndRow
) && mpRowHeights
)
3443 sal_uLong nHeight
= 0;
3444 SCROW nRow
= nStartRow
;
3445 while (nRow
<= nEndRow
)
3447 SCROW nLastRow
= -1;
3448 if (!( ( RowHidden(nRow
, nullptr, &nLastRow
) ) && bHiddenAsZero
) )
3450 if (nLastRow
> nEndRow
)
3452 nHeight
+= mpRowHeights
->getSumValue(nRow
, nLastRow
);
3454 nRow
= nLastRow
+ 1;
3459 return (nEndRow
- nStartRow
+ 1) * static_cast<sal_uLong
>(ScGlobal::nStdRowHeight
);
3462 sal_uLong
ScTable::GetScaledRowHeight( SCROW nStartRow
, SCROW nEndRow
, double fScale
) const
3464 OSL_ENSURE(ValidRow(nStartRow
) && ValidRow(nEndRow
),"wrong row number");
3466 if (ValidRow(nStartRow
) && ValidRow(nEndRow
) && mpRowHeights
)
3468 sal_uLong nHeight
= 0;
3469 SCROW nRow
= nStartRow
;
3470 while (nRow
<= nEndRow
)
3472 SCROW nLastRow
= -1;
3473 if (!RowHidden(nRow
, nullptr, &nLastRow
))
3475 if (nLastRow
> nEndRow
)
3478 // #i117315# can't use getSumValue, because individual values must be rounded
3479 ScFlatUInt16RowSegments::ForwardIterator
aSegmentIter(*mpRowHeights
);
3480 while (nRow
<= nLastRow
)
3483 if (!aSegmentIter
.getValue(nRow
, nRowVal
))
3484 return nHeight
; // shouldn't happen
3486 SCROW nSegmentEnd
= std::min( nLastRow
, aSegmentIter
.getLastPos() );
3488 // round-down a single height value, multiply resulting (pixel) values
3489 sal_uLong nOneHeight
= static_cast<sal_uLong
>( nRowVal
* fScale
);
3490 nHeight
+= nOneHeight
* ( nSegmentEnd
+ 1 - nRow
);
3492 nRow
= nSegmentEnd
+ 1;
3495 nRow
= nLastRow
+ 1;
3500 return static_cast<sal_uLong
>((nEndRow
- nStartRow
+ 1) * ScGlobal::nStdRowHeight
* fScale
);
3503 sal_uInt16
ScTable::GetOriginalHeight( SCROW nRow
) const // non-0 even if hidden
3505 OSL_ENSURE(ValidRow(nRow
),"wrong row number");
3507 if (ValidRow(nRow
) && mpRowHeights
)
3508 return mpRowHeights
->getValue(nRow
);
3510 return ScGlobal::nStdRowHeight
;
3513 // Column/Row -Flags
3515 SCROW
ScTable::GetHiddenRowCount( SCROW nRow
) const
3517 if (!ValidRow(nRow
))
3520 SCROW nLastRow
= -1;
3521 if (!RowHidden(nRow
, nullptr, &nLastRow
) || !ValidRow(nLastRow
))
3524 return nLastRow
- nRow
+ 1;
3527 //TODO: combine ShowRows / DBShowRows
3529 void ScTable::ShowCol(SCCOL nCol
, bool bShow
)
3533 bool bWasVis
= !ColHidden(nCol
);
3534 if (bWasVis
!= bShow
)
3536 SetColHidden(nCol
, nCol
, !bShow
);
3538 ScChartListenerCollection
* pCharts
= rDocument
.GetChartListenerCollection();
3540 pCharts
->SetRangeDirty(ScRange( nCol
, 0, nTab
, nCol
, rDocument
.MaxRow(), nTab
));
3545 OSL_FAIL("Invalid column number or no flags");
3549 void ScTable::ShowRow(SCROW nRow
, bool bShow
)
3551 if (ValidRow(nRow
) && pRowFlags
)
3553 bool bWasVis
= !RowHidden(nRow
);
3554 if (bWasVis
!= bShow
)
3556 SetRowHidden(nRow
, nRow
, !bShow
);
3558 SetRowFiltered(nRow
, nRow
, false);
3559 ScChartListenerCollection
* pCharts
= rDocument
.GetChartListenerCollection();
3561 pCharts
->SetRangeDirty(ScRange( 0, nRow
, nTab
, rDocument
.MaxCol(), nRow
, nTab
));
3563 InvalidatePageBreaks();
3568 OSL_FAIL("Invalid row number or no flags");
3572 void ScTable::DBShowRow(SCROW nRow
, bool bShow
)
3574 if (ValidRow(nRow
) && pRowFlags
)
3576 // Always set filter flag; unchanged when Hidden
3577 bool bChanged
= SetRowHidden(nRow
, nRow
, !bShow
);
3578 SetRowFiltered(nRow
, nRow
, !bShow
);
3582 ScChartListenerCollection
* pCharts
= rDocument
.GetChartListenerCollection();
3584 pCharts
->SetRangeDirty(ScRange( 0, nRow
, nTab
, rDocument
.MaxCol(), nRow
, nTab
));
3587 UpdateOutlineRow( nRow
, nRow
, bShow
);
3589 InvalidatePageBreaks();
3594 OSL_FAIL("Invalid row number or no flags");
3598 void ScTable::DBShowRows(SCROW nRow1
, SCROW nRow2
, bool bShow
)
3600 SCROW nStartRow
= nRow1
;
3601 while (nStartRow
<= nRow2
)
3604 bool bWasVis
= !RowHiddenLeaf(nStartRow
, nullptr, &nEndRow
);
3605 if (nEndRow
> nRow2
)
3608 bool bChanged
= ( bWasVis
!= bShow
);
3610 SetRowHidden(nStartRow
, nEndRow
, !bShow
);
3611 SetRowFiltered(nStartRow
, nEndRow
, !bShow
);
3615 ScChartListenerCollection
* pCharts
= rDocument
.GetChartListenerCollection();
3617 pCharts
->SetRangeDirty(ScRange( 0, nStartRow
, nTab
, rDocument
.MaxCol(), nEndRow
, nTab
));
3620 nStartRow
= nEndRow
+ 1;
3623 // #i12341# For Show/Hide rows, the outlines are updated separately from the outside.
3624 // For filtering, the changes aren't visible to the caller, so UpdateOutlineRow has
3627 UpdateOutlineRow( nRow1
, nRow2
, bShow
);
3630 void ScTable::ShowRows(SCROW nRow1
, SCROW nRow2
, bool bShow
)
3632 SCROW nStartRow
= nRow1
;
3634 // #i116164# if there are no drawing objects within the row range, a single HeightChanged call is enough
3635 ScDrawLayer
* pDrawLayer
= rDocument
.GetDrawLayer();
3636 bool bHasObjects
= pDrawLayer
&& pDrawLayer
->HasObjectsInRows( nTab
, nRow1
, nRow2
);
3638 while (nStartRow
<= nRow2
)
3641 bool bWasVis
= !RowHiddenLeaf(nStartRow
, nullptr, &nEndRow
);
3642 if (nEndRow
> nRow2
)
3645 bool bChanged
= ( bWasVis
!= bShow
);
3647 SetRowHidden(nStartRow
, nEndRow
, !bShow
);
3649 SetRowFiltered(nStartRow
, nEndRow
, false);
3653 ScChartListenerCollection
* pCharts
= rDocument
.GetChartListenerCollection();
3655 pCharts
->SetRangeDirty(ScRange( 0, nStartRow
, nTab
, rDocument
.MaxCol(), nEndRow
, nTab
));
3657 InvalidatePageBreaks();
3660 nStartRow
= nEndRow
+ 1;
3665 // #i116164# set the flags for the whole range at once
3666 SetRowHidden(nRow1
, nRow2
, !bShow
);
3668 SetRowFiltered(nRow1
, nRow2
, false);
3672 bool ScTable::IsDataFiltered(SCCOL nColStart
, SCROW nRowStart
, SCCOL nColEnd
, SCROW nRowEnd
) const
3674 assert(nColStart
<= nColEnd
&& nRowStart
<= nRowEnd
3675 && "range must be normalized to obtain a valid result");
3676 for (SCROW i
= nRowStart
; i
<= nRowEnd
; ++i
)
3681 for (SCCOL i
= nColStart
; i
<= nColEnd
; ++i
)
3689 bool ScTable::IsDataFiltered(const ScRange
& rRange
) const
3691 ScRange
aNormalized(rRange
.aStart
, rRange
.aEnd
);
3692 return IsDataFiltered(aNormalized
.aStart
.Col(), aNormalized
.aStart
.Row(),
3693 aNormalized
.aEnd
.Col(), aNormalized
.aEnd
.Row());
3696 void ScTable::SetRowFlags( SCROW nRow
, CRFlags nNewFlags
)
3698 if (ValidRow(nRow
) && pRowFlags
)
3699 pRowFlags
->SetValue( nRow
, nNewFlags
);
3702 OSL_FAIL("Invalid row number or no flags");
3706 void ScTable::SetRowFlags( SCROW nStartRow
, SCROW nEndRow
, CRFlags nNewFlags
)
3708 if (ValidRow(nStartRow
) && ValidRow(nEndRow
) && pRowFlags
)
3709 pRowFlags
->SetValue( nStartRow
, nEndRow
, nNewFlags
);
3712 OSL_FAIL("Invalid row number(s) or no flags");
3716 CRFlags
ScTable::GetColFlags( SCCOL nCol
) const
3718 if (ValidCol(nCol
) && mpColFlags
)
3719 return mpColFlags
->GetValue(nCol
);
3721 return CRFlags::NONE
;
3724 CRFlags
ScTable::GetRowFlags( SCROW nRow
) const
3726 if (ValidRow(nRow
) && pRowFlags
)
3727 return pRowFlags
->GetValue(nRow
);
3729 return CRFlags::NONE
;
3732 SCROW
ScTable::GetLastFlaggedRow() const
3734 SCROW nLastFound
= 0;
3737 SCROW nRow
= pRowFlags
->GetLastAnyBitAccess( CRFlags::All
);
3742 if (!maRowManualBreaks
.empty())
3743 nLastFound
= ::std::max(nLastFound
, *maRowManualBreaks
.rbegin());
3747 SCROW nRow
= mpHiddenRows
->findLastTrue();
3749 nLastFound
= ::std::max(nLastFound
, nRow
);
3754 SCROW nRow
= mpFilteredRows
->findLastTrue();
3756 nLastFound
= ::std::max(nLastFound
, nRow
);
3762 SCCOL
ScTable::GetLastChangedCol() const
3767 SCCOL nLastFound
= 0;
3768 const auto nColSize
= aCol
.size();
3769 auto colWidthIt
= mpColWidth
->begin() + 1;
3770 for (SCCOL nCol
= 1; nCol
< nColSize
; (++nCol
< nColSize
) ? ++colWidthIt
: (void)false)
3771 if ((mpColFlags
->GetValue(nCol
) & CRFlags::All
) || (*colWidthIt
!= STD_COL_WIDTH
))
3777 SCROW
ScTable::GetLastChangedRow() const
3782 SCROW nLastFlags
= GetLastFlaggedRow();
3784 // Find the last row position where the height is NOT the standard row
3786 // KOHEI: Test this to make sure it does what it's supposed to.
3787 SCROW nLastHeight
= mpRowHeights
->findLastTrue(ScGlobal::nStdRowHeight
);
3788 if (!ValidRow(nLastHeight
))
3791 return std::max( nLastFlags
, nLastHeight
);
3794 bool ScTable::UpdateOutlineCol( SCCOL nStartCol
, SCCOL nEndCol
, bool bShow
)
3796 if (pOutlineTable
&& mpColFlags
)
3798 return pOutlineTable
->GetColArray().ManualAction( nStartCol
, nEndCol
, bShow
, *this, true );
3804 bool ScTable::UpdateOutlineRow( SCROW nStartRow
, SCROW nEndRow
, bool bShow
)
3806 if (pOutlineTable
&& pRowFlags
)
3807 return pOutlineTable
->GetRowArray().ManualAction( nStartRow
, nEndRow
, bShow
, *this, false );
3812 void ScTable::ExtendHidden( SCCOL
& rX1
, SCROW
& rY1
, SCCOL
& rX2
, SCROW
& rY2
)
3814 // Column-wise expansion
3816 while (rX1
> 0 && ColHidden(rX1
-1))
3819 while (rX2
< rDocument
.MaxCol() && ColHidden(rX2
+1))
3822 // Row-wise expansion
3826 ScFlatBoolRowSegments::RangeData aData
;
3827 if (mpHiddenRows
->getRangeData(rY1
-1, aData
) && aData
.mbValue
)
3829 SCROW nStartRow
= aData
.mnRow1
;
3830 if (ValidRow(nStartRow
))
3834 if (rY2
< rDocument
.MaxRow())
3837 if (RowHidden(rY2
+1, nullptr, &nEndRow
) && ValidRow(nEndRow
))
3842 void ScTable::StripHidden( SCCOL
& rX1
, SCROW
& rY1
, SCCOL
& rX2
, SCROW
& rY2
)
3844 while ( rX2
>rX1
&& ColHidden(rX2
) )
3846 while ( rX2
>rX1
&& ColHidden(rX1
) )
3851 ScFlatBoolRowSegments::RangeData aData
;
3852 if (mpHiddenRows
->getRangeData(rY2
, aData
) && aData
.mbValue
)
3854 SCROW nStartRow
= aData
.mnRow1
;
3855 if (ValidRow(nStartRow
) && nStartRow
>= rY1
)
3863 if (RowHidden(rY1
, nullptr, &nEndRow
) && ValidRow(nEndRow
) && nEndRow
<= rY2
)
3870 template< typename T
>
3871 static short DiffSign( T a
, T b
)
3879 class OutlineArrayFinder
3884 ScOutlineArray
* mpArray
;
3888 OutlineArrayFinder(const ScRange
& rRef
, SCCOL nCol
, SCTAB nTab
, ScOutlineArray
* pArray
, bool bSizeChanged
) :
3889 maRef(rRef
), mnCol(nCol
), mnTab(nTab
), mpArray(pArray
),
3890 mbSizeChanged(bSizeChanged
) {}
3892 bool operator() (size_t nRow
, const ScFormulaCell
* pCell
)
3894 SCROW nRow2
= static_cast<SCROW
>(nRow
);
3896 if (!pCell
->HasRefListExpressibleAsOneReference(maRef
))
3899 if (maRef
.aStart
.Row() != nRow2
|| maRef
.aEnd
.Row() != nRow2
||
3900 maRef
.aStart
.Tab() != mnTab
|| maRef
.aEnd
.Tab() != mnTab
)
3903 if (DiffSign(maRef
.aStart
.Col(), mnCol
) != DiffSign(maRef
.aEnd
.Col(), mnCol
))
3906 return mpArray
->Insert(maRef
.aStart
.Col(), maRef
.aEnd
.Col(), mbSizeChanged
);
3912 void ScTable::DoAutoOutline( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
)
3914 typedef mdds::flat_segment_tree
<SCROW
, bool> UsedRowsType
;
3916 bool bSizeChanged
= false;
3923 nEndCol
= ClampToAllocatedColumns(nEndCol
);
3925 StartOutlineTable();
3929 UsedRowsType
aUsed(0, rDocument
.MaxRow()+1, false);
3930 for (nCol
=nStartCol
; nCol
<=nEndCol
; nCol
++)
3931 aCol
[nCol
].FindUsed(nStartRow
, nEndRow
, aUsed
);
3934 ScOutlineArray
& rRowArray
= pOutlineTable
->GetRowArray();
3935 for (nRow
=nStartRow
; nRow
<=nEndRow
; nRow
++)
3938 SCROW nLastRow
= nRow
;
3939 aUsed
.search_tree(nRow
, bUsed
, nullptr, &nLastRow
);
3947 for (nCol
=nStartCol
; nCol
<=nEndCol
&& !bFound
; nCol
++)
3949 ScRefCellValue aCell
= aCol
[nCol
].GetCellValue(nRow
);
3951 if (aCell
.meType
!= CELLTYPE_FORMULA
)
3954 if (!aCell
.mpFormula
->HasRefListExpressibleAsOneReference(aRef
))
3957 if ( aRef
.aStart
.Col() == nCol
&& aRef
.aEnd
.Col() == nCol
&&
3958 aRef
.aStart
.Tab() == nTab
&& aRef
.aEnd
.Tab() == nTab
&&
3959 DiffSign( aRef
.aStart
.Row(), nRow
) ==
3960 DiffSign( aRef
.aEnd
.Row(), nRow
) )
3962 if (rRowArray
.Insert( aRef
.aStart
.Row(), aRef
.aEnd
.Row(), bSizeChanged
))
3971 ScOutlineArray
& rColArray
= pOutlineTable
->GetColArray();
3972 for (nCol
=nStartCol
; nCol
<=nEndCol
; nCol
++)
3974 if (aCol
[nCol
].IsEmptyData())
3977 OutlineArrayFinder
aFunc(aRef
, nCol
, nTab
, &rColArray
, bSizeChanged
);
3978 sc::FindFormula(aCol
[nCol
].maCells
, nStartRow
, nEndRow
, aFunc
);
3982 // CopyData - for Query in other range
3984 void ScTable::CopyData( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
,
3985 SCCOL nDestCol
, SCROW nDestRow
, SCTAB nDestTab
)
3987 //TODO: if used for multiple rows, optimize after columns!
3989 ScAddress
aSrc( nStartCol
, nStartRow
, nTab
);
3990 ScAddress
aDest( nDestCol
, nDestRow
, nDestTab
);
3991 ScRange
aRange( aSrc
, aDest
);
3992 bool bThisTab
= ( nDestTab
== nTab
);
3993 SCROW nDestY
= nDestRow
;
3994 for (SCROW nRow
=nStartRow
; nRow
<=nEndRow
; nRow
++)
3996 aSrc
.SetRow( nRow
);
3997 aDest
.SetRow( nDestY
);
3998 SCCOL nDestX
= nDestCol
;
3999 for (SCCOL nCol
=nStartCol
; nCol
<=nEndCol
; nCol
++)
4001 aSrc
.SetCol( nCol
);
4002 aDest
.SetCol( nDestX
);
4004 aCell
.assign(rDocument
, ScAddress(nCol
, nRow
, nTab
));
4006 if (aCell
.meType
== CELLTYPE_FORMULA
)
4008 sc::RefUpdateContext
aCxt(rDocument
);
4009 aCxt
.meMode
= URM_COPY
;
4010 aCxt
.maRange
= aRange
;
4011 aCxt
.mnColDelta
= nDestCol
- nStartCol
;
4012 aCxt
.mnRowDelta
= nDestRow
- nStartRow
;
4013 aCxt
.mnTabDelta
= nDestTab
- nTab
;
4014 aCell
.mpFormula
->UpdateReference(aCxt
);
4015 aCell
.mpFormula
->aPos
= aDest
;
4020 aCell
.release(CreateColumnIfNotExists(nDestX
), nDestY
);
4021 SetPattern( nDestX
, nDestY
, *GetPattern( nCol
, nRow
) );
4025 aCell
.release(rDocument
, aDest
);
4026 rDocument
.SetPattern( aDest
, *GetPattern( nCol
, nRow
) );
4035 bool ScTable::RefVisible(const ScFormulaCell
* pCell
)
4039 if (pCell
->HasOneReference(aRef
))
4041 if (aRef
.aStart
.Col()==aRef
.aEnd
.Col() && aRef
.aStart
.Tab()==aRef
.aEnd
.Tab())
4044 if (!RowFiltered(aRef
.aStart
.Row(), nullptr, &nEndRow
))
4045 // row not filtered.
4046 nEndRow
= ::std::numeric_limits
<SCROW
>::max();
4048 if (!ValidRow(nEndRow
) || nEndRow
< aRef
.aEnd
.Row())
4049 return true; // at least partly visible
4050 return false; // completely invisible
4054 return true; // somehow different
4057 OUString
ScTable::GetUpperCellString(SCCOL nCol
, SCROW nRow
)
4059 return ScGlobal::getCharClass().uppercase(GetInputString(nCol
, nRow
).trim());
4062 // Calculate the size of the sheet and set the size on DrawPage
4064 void ScTable::SetDrawPageSize(bool bResetStreamValid
, bool bUpdateNoteCaptionPos
,
4065 ScObjectHandling eObjectHandling
)
4067 ScDrawLayer
* pDrawLayer
= rDocument
.GetDrawLayer();
4070 const sal_Int64 nMax
= ::std::numeric_limits
<tools::Long
>::max();
4071 // #i113884# Avoid int32 overflow with possible negative results than can cause bad effects.
4072 // If the draw page size is smaller than all rows, only the bottom of the sheet is affected.
4073 tools::Long x
= std::min(o3tl::convert(GetColOffset(rDocument
.MaxCol() + 1),
4074 o3tl::Length::twip
, o3tl::Length::mm100
),
4076 tools::Long y
= std::min(o3tl::convert(GetRowOffset(rDocument
.MaxRow() + 1),
4077 o3tl::Length::twip
, o3tl::Length::mm100
),
4080 if ( IsLayoutRTL() ) // IsNegativePage
4083 pDrawLayer
->SetPageSize(static_cast<sal_uInt16
>(nTab
), Size(x
, y
), bUpdateNoteCaptionPos
,
4087 // #i102616# actions that modify the draw page size count as sheet modification
4088 // (exception: InitDrawLayer)
4089 if (bResetStreamValid
)
4090 SetStreamValid(false);
4093 void ScTable::SetRangeName(std::unique_ptr
<ScRangeName
> pNew
)
4095 mpRangeName
= std::move(pNew
);
4097 //fdo#39792: mark stream as invalid, otherwise new ScRangeName will not be written to file
4098 SetStreamValid(false);
4101 ScRangeName
* ScTable::GetRangeName() const
4104 mpRangeName
.reset(new ScRangeName
);
4105 return mpRangeName
.get();
4108 sal_uLong
ScTable::GetRowOffset( SCROW nRow
, bool bHiddenAsZero
) const
4111 if ( mpHiddenRows
&& mpRowHeights
)
4116 return GetRowHeight(0, nullptr, nullptr, bHiddenAsZero
);
4118 n
= GetTotalRowHeight(0, nRow
-1, bHiddenAsZero
);
4119 #if OSL_DEBUG_LEVEL > 0
4120 if (n
== ::std::numeric_limits
<tools::ULong
>::max())
4121 OSL_FAIL("ScTable::GetRowOffset: row heights overflow");
4126 OSL_FAIL("GetRowOffset: Data missing");
4131 SCROW
ScTable::GetRowForHeight(sal_uLong nHeight
) const
4135 ScFlatBoolRowSegments::RangeData aData
;
4137 ScFlatUInt16RowSegments::RangeData aRowHeightRange
;
4138 aRowHeightRange
.mnRow2
= -1;
4139 aRowHeightRange
.mnValue
= 0; // silence MSVC C4701
4141 for (SCROW nRow
= 0; nRow
<= rDocument
.MaxRow(); ++nRow
)
4143 if (!mpHiddenRows
->getRangeData(nRow
, aData
))
4144 // Failed to fetch the range data for whatever reason.
4149 // This row is hidden. Skip ahead all hidden rows.
4150 nRow
= aData
.mnRow2
;
4154 if (aRowHeightRange
.mnRow2
< nRow
)
4156 if (!mpRowHeights
->getRangeData(nRow
, aRowHeightRange
))
4157 // Failed to fetch the range data for whatever reason.
4161 // find the last common row between hidden & height spans
4162 SCROW nLastCommon
= std::min(aData
.mnRow2
, aRowHeightRange
.mnRow2
);
4163 assert (nLastCommon
>= nRow
);
4164 SCROW nCommon
= nLastCommon
- nRow
+ 1;
4166 // how much further to go ?
4167 sal_uLong nPixelsLeft
= nHeight
- nSum
;
4168 sal_uLong nCommonPixels
= static_cast<sal_uLong
>(aRowHeightRange
.mnValue
) * nCommon
;
4170 // are we in the zone ?
4171 if (nCommonPixels
> nPixelsLeft
)
4173 nRow
+= (nPixelsLeft
+ aRowHeightRange
.mnValue
- 1) / aRowHeightRange
.mnValue
;
4175 // FIXME: finding this next row is far from elegant,
4176 // we have a single caller, which subtracts one as well(!?)
4177 if (nRow
>= rDocument
.MaxRow())
4178 return rDocument
.MaxRow();
4180 if (!mpHiddenRows
->getRangeData(nRow
, aData
))
4181 // Failed to fetch the range data for whatever reason.
4185 // These rows are hidden.
4186 nRow
= aData
.mnRow2
+ 1;
4188 return nRow
<= rDocument
.MaxRow() ? nRow
: rDocument
.MaxRow();
4191 // skip the range and keep hunting
4192 nSum
+= nCommonPixels
;
4198 sal_uLong
ScTable::GetColOffset( SCCOL nCol
, bool bHiddenAsZero
) const
4203 auto colWidthIt
= mpColWidth
->begin();
4204 for (SCCOL i
= 0; i
< nCol
; (++i
< nCol
) ? ++colWidthIt
: (void)false)
4205 if (!( bHiddenAsZero
&& ColHidden(i
) ))
4210 OSL_FAIL("GetColumnOffset: Data missing");
4215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */