LibreOffice Module sc (master) 1
table2.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <algorithm>
21#include <memory>
22#include <table.hxx>
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>
37#include <postit.hxx>
38#include <sheetevents.hxx>
39#include <segmenttree.hxx>
40#include <dbdata.hxx>
41#include <tokenarray.hxx>
42#include <clipcontext.hxx>
43#include <types.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>
53#include <refdata.hxx>
54#include <docsh.hxx>
55
56#include <scitems.hxx>
57#include <editeng/boxitem.hxx>
58#include <editeng/editobj.hxx>
59#include <o3tl/safeint.hxx>
61#include <osl/diagnose.h>
62#include <sal/log.hxx>
63#include <svl/poolcach.hxx>
65#include <math.h>
66
67namespace {
68
69class ColumnRegroupFormulaCells
70{
71 ScColContainer& mrCols;
72 std::vector<ScAddress>* mpGroupPos;
73
74public:
75 ColumnRegroupFormulaCells( ScColContainer& rCols, std::vector<ScAddress>* pGroupPos ) :
76 mrCols(rCols), mpGroupPos(pGroupPos) {}
77
78 void operator() (SCCOL nCol)
79 {
80 mrCols[nCol].RegroupFormulaCells(mpGroupPos);
81 }
82};
83
84}
85
86sal_uInt16 ScTable::GetTextWidth(SCCOL nCol, SCROW nRow) const
87{
88 return aCol[nCol].GetTextWidth(nRow);
89}
90
91bool ScTable::SetOutlineTable( const ScOutlineTable* pNewOutline )
92{
93 sal_uInt16 nOldSizeX = 0;
94 sal_uInt16 nOldSizeY = 0;
95 sal_uInt16 nNewSizeX = 0;
96 sal_uInt16 nNewSizeY = 0;
97
98 if (pOutlineTable)
99 {
100 nOldSizeX = pOutlineTable->GetColArray().GetDepth();
101 nOldSizeY = pOutlineTable->GetRowArray().GetDepth();
102 pOutlineTable.reset();
103 }
104
105 if (pNewOutline)
106 {
107 pOutlineTable.reset(new ScOutlineTable( *pNewOutline ));
108 nNewSizeX = pOutlineTable->GetColArray().GetDepth();
109 nNewSizeY = pOutlineTable->GetRowArray().GetDepth();
110 }
111
112 return ( nNewSizeX != nOldSizeX || nNewSizeY != nOldSizeY ); // changed size?
113}
114
116{
117 if (!pOutlineTable)
118 pOutlineTable.reset(new ScOutlineTable);
119}
120
121void ScTable::SetSheetEvents( std::unique_ptr<ScSheetEvents> pNew )
122{
123 pSheetEvents = std::move(pNew);
124
125 SetCalcNotification( false ); // discard notifications before the events were set
126
127 SetStreamValid(false);
128}
129
131{
132 bCalcNotification = bSet;
133}
134
135bool ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize ) const
136{
137 if ( nStartCol==0 && nEndCol==rDocument.MaxCol() && pOutlineTable )
138 if (!pOutlineTable->TestInsertRow(nSize))
139 return false;
140
141 SCCOL maxCol = ClampToAllocatedColumns(nEndCol);
142 for (SCCOL i=nStartCol; i<=maxCol; i++)
143 if (!aCol[i].TestInsertRow(nStartRow, nSize))
144 return false;
145
146 if( maxCol != nEndCol )
147 if (!aDefaultColData.TestInsertRow(nSize))
148 return false;
149
150 return true;
151}
152
153void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize )
154{
155 if (nStartCol==0 && nEndCol==rDocument.MaxCol())
156 {
157 if (mpRowHeights && pRowFlags)
158 {
159 mpRowHeights->insertSegment(nStartRow, nSize);
160 CRFlags nNewFlags = pRowFlags->Insert( nStartRow, nSize);
161 // only copy manual size flag, clear all others
162 if (nNewFlags != CRFlags::NONE && (nNewFlags != CRFlags::ManualSize))
163 pRowFlags->SetValue( nStartRow, nStartRow + nSize - 1,
164 nNewFlags & CRFlags::ManualSize);
165 }
166
167 if (pOutlineTable)
168 pOutlineTable->InsertRow( nStartRow, nSize );
169
170 mpFilteredRows->insertSegment(nStartRow, nSize);
171 mpHiddenRows->insertSegment(nStartRow, nSize);
172
173 if (!maRowManualBreaks.empty())
174 {
175 // Copy all breaks up to nStartRow (non-inclusive).
176 ::std::set<SCROW>::iterator itr1 = maRowManualBreaks.lower_bound(nStartRow);
177 ::std::set<SCROW> aNewBreaks(maRowManualBreaks.begin(), itr1);
178
179 // Copy all breaks from nStartRow (inclusive) to the last element,
180 // but add nSize to each value.
181 ::std::set<SCROW>::iterator itr2 = maRowManualBreaks.end();
182 for (; itr1 != itr2; ++itr1)
183 aNewBreaks.insert(static_cast<SCROW>(*itr1 + nSize));
184
185 maRowManualBreaks.swap(aNewBreaks);
186 }
187 }
188
189 for (SCCOL j : GetAllocatedColumnsRange(nStartCol, nEndCol))
190 aCol[j].InsertRow( nStartRow, nSize );
191 aDefaultColData.InsertRow( nStartRow, nSize );
192
193 mpCondFormatList->InsertRow(nTab, nStartCol, nEndCol, nStartRow, nSize);
194
196
197 // TODO: In the future we may want to check if the table has been
198 // really modified before setting the stream invalid.
199 SetStreamValid(false);
200}
201
203 const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
204 bool* pUndoOutline, std::vector<ScAddress>* pGroupPos )
205{
206 if (nStartCol==0 && nEndCol==rDocument.MaxCol())
207 {
208 if (pRowFlags)
209 pRowFlags->Remove( nStartRow, nSize);
210
211 if (mpRowHeights)
212 mpRowHeights->removeSegment(nStartRow, nStartRow+nSize);
213
214 if (pOutlineTable)
215 if (pOutlineTable->DeleteRow( nStartRow, nSize ))
216 if (pUndoOutline)
217 *pUndoOutline = true;
218
219 mpFilteredRows->removeSegment(nStartRow, nStartRow+nSize);
220 mpHiddenRows->removeSegment(nStartRow, nStartRow+nSize);
221
222 if (!maRowManualBreaks.empty())
223 {
224 // Erase all manual breaks between nStartRow and nStartRow + nSize - 1 (inclusive).
225 std::set<SCROW>::iterator itr1 = maRowManualBreaks.lower_bound(nStartRow);
226 std::set<SCROW>::iterator itr2 = maRowManualBreaks.upper_bound(static_cast<SCROW>(nStartRow + nSize - 1));
227 maRowManualBreaks.erase(itr1, itr2);
228
229 // Copy all breaks from the 1st element up to nStartRow to the new container.
230 itr1 = maRowManualBreaks.lower_bound(nStartRow);
231 ::std::set<SCROW> aNewBreaks(maRowManualBreaks.begin(), itr1);
232
233 // Copy all breaks from nStartRow to the last element, but subtract each value by nSize.
234 itr2 = maRowManualBreaks.end();
235 for (; itr1 != itr2; ++itr1)
236 aNewBreaks.insert(static_cast<SCROW>(*itr1 - nSize));
237
238 maRowManualBreaks.swap(aNewBreaks);
239 }
240 }
241
242 { // scope for bulk broadcast
243 ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
244 for (SCCOL j=nStartCol; j<=ClampToAllocatedColumns(nEndCol); j++)
245 aCol[j].DeleteRow(nStartRow, nSize, pGroupPos);
246 }
247
248 std::vector<SCCOL> aRegroupCols;
249 rRegroupCols.getColumns(nTab, aRegroupCols);
250 std::for_each(
251 aRegroupCols.begin(), aRegroupCols.end(), ColumnRegroupFormulaCells(aCol, pGroupPos));
252
254
255 // TODO: In the future we may want to check if the table has been
256 // really modified before setting the stream invalid.
257 SetStreamValid(false);
258}
259
260bool ScTable::TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ) const
261{
262 if ( nSize > o3tl::make_unsigned(rDocument.MaxCol()) )
263 return false;
264
265 if ( nStartRow==0 && nEndRow==rDocument.MaxRow() && pOutlineTable
266 && ! pOutlineTable->TestInsertCol(nSize) )
267 return false;
268
269 auto range = GetAllocatedColumnsRange( rDocument.MaxCol() - static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() );
270 for (auto it = range.rbegin(); it != range.rend(); ++it )
271 if (! aCol[*it].TestInsertCol(nStartRow, nEndRow))
272 return false;
273
274 return true;
275}
276
278 const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize )
279{
280 if (nStartRow==0 && nEndRow==rDocument.MaxRow())
281 {
282 if (mpColWidth && mpColFlags)
283 {
284 mpColWidth->InsertPreservingSize(nStartCol, nSize, STD_COL_WIDTH);
285 // The inserted columns have the same widths as the columns, which were selected for insert.
286 for (SCSIZE i=0; i < std::min(rDocument.MaxCol()-nSize-nStartCol, nSize); ++i)
287 mpColWidth->SetValue(nStartCol + i, mpColWidth->GetValue(nStartCol+i+nSize));
288 mpColFlags->InsertPreservingSize(nStartCol, nSize, CRFlags::NONE);
289 }
290 if (pOutlineTable)
291 pOutlineTable->InsertCol( nStartCol, nSize );
292
293 mpHiddenCols->insertSegment(nStartCol, static_cast<SCCOL>(nSize));
294 mpFilteredCols->insertSegment(nStartCol, static_cast<SCCOL>(nSize));
295
296 if (!maColManualBreaks.empty())
297 {
298 // Copy all breaks up to nStartCol (non-inclusive).
299 ::std::set<SCCOL>::iterator itr1 = maColManualBreaks.lower_bound(nStartCol);
300 ::std::set<SCCOL> aNewBreaks(maColManualBreaks.begin(), itr1);
301
302 // Copy all breaks from nStartCol (inclusive) to the last element,
303 // but add nSize to each value.
304 ::std::set<SCCOL>::iterator itr2 = maColManualBreaks.end();
305 for (; itr1 != itr2; ++itr1)
306 aNewBreaks.insert(static_cast<SCCOL>(*itr1 + nSize));
307
308 maColManualBreaks.swap(aNewBreaks);
309 }
310 }
311
312 // Make sure there are enough columns at the end.
313 CreateColumnIfNotExists(std::min<SCCOL>(rDocument.MaxCol(), std::max(nStartCol, aCol.size()) + nSize - 1 ));
314 if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow()))
315 {
316 // Move existing columns back, this will swap last empty columns in the inserted place.
317 for (SCCOL nCol = aCol.size() - 1 - nSize; nCol >= nStartCol; --nCol)
318 aCol[nCol].SwapCol(aCol[nCol+nSize]);
319 }
320 else
321 {
322 for (SCSIZE i=0; static_cast<SCCOL>(i+nSize)+nStartCol < aCol.size(); i++)
323 aCol[aCol.size() - 1 - nSize - i].MoveTo(nStartRow, nEndRow, aCol[aCol.size() - 1 - i]);
324 }
325
326 std::vector<SCCOL> aRegroupCols;
327 rRegroupCols.getColumns(nTab, aRegroupCols);
328 std::for_each(aRegroupCols.begin(), aRegroupCols.end(), ColumnRegroupFormulaCells(aCol, nullptr));
329
330 if (nStartCol>0) // copy old attributes
331 {
332 sal_uInt16 nWhichArray[2];
333 nWhichArray[0] = ATTR_MERGE;
334 nWhichArray[1] = 0;
335
337 for (SCSIZE i=0; i<nSize; i++)
338 {
339 aCol[nStartCol-1].CopyToColumn(aCxt, nStartRow, nEndRow, InsertDeleteFlags::ATTRIB,
340 false, aCol[nStartCol+i] );
341 aCol[nStartCol+i].RemoveFlags( nStartRow, nEndRow,
343 aCol[nStartCol+i].ClearItems( nStartRow, nEndRow, nWhichArray );
344 }
345 }
346
347 mpCondFormatList->InsertCol(nTab, nStartRow, nEndRow, nStartCol, nSize);
348
350
351 // TODO: In the future we may want to check if the table has been
352 // really modified before setting the stream invalid.
353 SetStreamValid(false);
354}
355
357 const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize, bool* pUndoOutline )
358{
359 if (nStartRow==0 && nEndRow==rDocument.MaxRow())
360 {
361 if (mpColWidth && mpColFlags)
362 {
363 assert( nStartCol + nSize <= o3tl::make_unsigned(rDocument.MaxCol()+1) ); // moving 0 if ==rDocument.MaxCol()+1 is correct
364 mpColWidth->RemovePreservingSize(nStartCol, nSize, STD_COL_WIDTH);
365 mpColFlags->RemovePreservingSize(nStartCol, nSize, CRFlags::NONE);
366 }
367 if (pOutlineTable)
368 if (pOutlineTable->DeleteCol( nStartCol, nSize ))
369 if (pUndoOutline)
370 *pUndoOutline = true;
371
372 SCCOL nRmSize = nStartCol + static_cast<SCCOL>(nSize);
373 mpHiddenCols->removeSegment(nStartCol, nRmSize);
374 mpFilteredCols->removeSegment(nStartCol, nRmSize);
375
376 if (!maColManualBreaks.empty())
377 {
378 // Erase all manual breaks between nStartCol and nStartCol + nSize - 1 (inclusive).
379 std::set<SCCOL>::iterator itr1 = maColManualBreaks.lower_bound(nStartCol);
380 std::set<SCCOL>::iterator itr2 = maColManualBreaks.upper_bound(static_cast<SCCOL>(nStartCol + nSize - 1));
381 maColManualBreaks.erase(itr1, itr2);
382
383 // Copy all breaks from the 1st element up to nStartCol to the new container.
384 itr1 = maColManualBreaks.lower_bound(nStartCol);
385 ::std::set<SCCOL> aNewBreaks(maColManualBreaks.begin(), itr1);
386
387 // Copy all breaks from nStartCol to the last element, but subtract each value by nSize.
388 itr2 = maColManualBreaks.end();
389 for (; itr1 != itr2; ++itr1)
390 aNewBreaks.insert(static_cast<SCCOL>(*itr1 - nSize));
391
392 maColManualBreaks.swap(aNewBreaks);
393 }
394 }
395
396 for (SCCOL col = nStartCol; col <= ClampToAllocatedColumns(nStartCol + nSize - 1); ++col)
397 aCol[col].DeleteArea(nStartRow, nEndRow, InsertDeleteFlags::ALL, false);
398
399 if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow()))
400 {
401 for (SCCOL nCol = nStartCol + nSize; nCol < aCol.size(); ++nCol)
402 aCol[nCol].SwapCol(aCol[nCol - nSize]);
403 }
404 else
405 {
406 for (SCSIZE i=0; static_cast<SCCOL>(i+nSize)+nStartCol < aCol.size(); i++)
407 aCol[nStartCol + nSize + i].MoveTo(nStartRow, nEndRow, aCol[nStartCol + i]);
408 }
409
410 std::vector<SCCOL> aRegroupCols;
411 rRegroupCols.getColumns(nTab, aRegroupCols);
412 std::for_each(aRegroupCols.begin(), aRegroupCols.end(), ColumnRegroupFormulaCells(aCol, nullptr));
413
415
416 // TODO: In the future we may want to check if the table has been
417 // really modified before setting the stream invalid.
418 SetStreamValid(false);
419}
420
422 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, InsertDeleteFlags nDelFlag,
423 bool bBroadcast, sc::ColumnSpanSet* pBroadcastSpans )
424{
425 if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
426 if (nRow2 > rDocument.MaxRow()) nRow2 = rDocument.MaxRow();
427 if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
428 {
429 { // scope for bulk broadcast
430 ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
431 for (SCCOL i = nCol1; i <= nCol2; i++)
432 aCol[i].DeleteArea(nRow1, nRow2, nDelFlag, bBroadcast, pBroadcastSpans);
433 }
434
435 // Do not set protected cell in a protected table
436
437 if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) )
438 {
439 ScPatternAttr aPattern(rDocument.GetPool());
440 aPattern.GetItemSet().Put( ScProtectionAttr( false ) );
441 ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
442 }
443
444 if( nDelFlag & InsertDeleteFlags::ATTRIB )
445 mpCondFormatList->DeleteArea( nCol1, nRow1, nCol2, nRow2 );
446 }
447
448 // TODO: In the future we may want to check if the table has been
449 // really modified before setting the stream invalid.
450 SetStreamValid(false);
451}
452
453void ScTable::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
454{
455 { // scope for bulk broadcast
456 ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
457 for (SCCOL i=0; i < aCol.size(); i++)
458 aCol[i].DeleteSelection(nDelFlag, rMark, bBroadcast);
459 }
460
461 ScRangeList aRangeList;
462 rMark.FillRangeListWithMarks(&aRangeList, false);
463
464 for (size_t i = 0; i < aRangeList.size(); ++i)
465 {
466 const ScRange & rRange = aRangeList[i];
467
468 if((nDelFlag & InsertDeleteFlags::ATTRIB) && rRange.aStart.Tab() == nTab)
469 mpCondFormatList->DeleteArea( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row() );
470 }
471
472 // Do not set protected cell in a protected sheet
473
474 if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) )
475 {
478 aSet.Put( ScProtectionAttr( false ) );
479 SfxItemPoolCache aCache( pPool, &aSet );
480 ApplySelectionCache( &aCache, rMark );
481 }
482
483 // TODO: In the future we may want to check if the table has been
484 // really modified before setting the stream invalid.
485 SetStreamValid(false);
486}
487
488// pTable = Clipboard
490 sc::CopyToClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
491 ScTable* pTable )
492{
493 if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
494 return;
495
496 // copy content
497 //local range names need to be copied first for formula cells
498 if (!pTable->mpRangeName && mpRangeName)
499 pTable->mpRangeName.reset( new ScRangeName(*mpRangeName) );
500
501 nCol2 = ClampToAllocatedColumns(nCol2);
502
503 for ( SCCOL i = nCol1; i <= nCol2; i++)
504 aCol[i].CopyToClip(rCxt, nRow1, nRow2, pTable->CreateColumnIfNotExists(i)); // notes are handled at column level
505
506 // copy widths/heights, and only "hidden", "filtered" and "manual" flags
507 // also for all preceding columns/rows, to have valid positions for drawing objects
508
509 if (mpColWidth && pTable->mpColWidth)
510 pTable->mpColWidth->CopyFrom(*mpColWidth, 0, nCol2);
511
512 pTable->CopyColHidden(*this, 0, nCol2);
513 pTable->CopyColFiltered(*this, 0, nCol2);
514 if (pDBDataNoName)
515 pTable->SetAnonymousDBData(std::unique_ptr<ScDBData>(new ScDBData(*pDBDataNoName)));
516
517 if (pRowFlags && pTable->pRowFlags && mpRowHeights && pTable->mpRowHeights)
518 {
519 pTable->pRowFlags->CopyFromAnded( *pRowFlags, 0, nRow2, CRFlags::ManualSize);
520 pTable->CopyRowHeight(*this, 0, nRow2, 0);
521 }
522
523 pTable->CopyRowHidden(*this, 0, nRow2);
524 pTable->CopyRowFiltered(*this, 0, nRow2);
525
526 // If necessary replace formulas with values
527
528 if ( IsProtected() )
529 for (SCCOL i = nCol1; i <= nCol2; i++)
530 pTable->aCol[i].RemoveProtected(nRow1, nRow2);
531
533}
534
536 sc::CopyToClipContext& rCxt, const ScRangeList& rRanges, ScTable* pTable )
537{
538 for ( size_t i = 0, nListSize = rRanges.size(); i < nListSize; ++i )
539 {
540 const ScRange & r = rRanges[ i ];
541 CopyToClip( rCxt, r.aStart.Col(), r.aStart.Row(), r.aEnd.Col(), r.aEnd.Row(), pTable);
542 }
543}
544
546 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const SvNumberFormatterMergeMap& rMap, ScTable* pDestTab )
547{
548 if (nCol1 > nCol2 || nRow1 > nRow2)
549 return;
550
551 const SCCOL nFirstUnallocated = std::clamp<SCCOL>(GetAllocatedColumnsCount(), nCol1, nCol2 + 1);
552 if (nFirstUnallocated > nCol1)
553 pDestTab->CreateColumnIfNotExists(nFirstUnallocated - 1);
554
555 for (SCCOL i = nCol1; i < nFirstUnallocated; ++i)
556 {
557 ScColumn& rSrcCol = aCol[i];
558 ScColumn& rDestCol = pDestTab->aCol[i];
559 rSrcCol.CopyStaticToDocument(nRow1, nRow2, rMap, rDestCol);
560 }
561
562 // Maybe copy this table's default attrs to dest not limiting to already allocated in dest?
563 const SCCOL nLastInDest = std::min<SCCOL>(pDestTab->GetAllocatedColumnsCount() - 1, nCol2);
564 for (SCCOL i = nFirstUnallocated; i <= nLastInDest; ++i)
565 {
566 ScColumn& rDestCol = pDestTab->aCol[i];
567 rDestCol.maCellTextAttrs.set_empty(nRow1, nRow2);
568 rDestCol.maCells.set_empty(nRow1, nRow2);
569 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
570 {
571 sal_uInt32 nNumFmt = aDefaultColData.GetPattern(nRow)->GetNumberFormat(
573 SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt);
574 if (itNum != rMap.end())
575 nNumFmt = itNum->second;
576
577 rDestCol.SetNumberFormat(nRow, nNumFmt);
578 }
579 rDestCol.CellStorageModified();
580 }
581}
582
583void ScTable::CopyCellToDocument(SCCOL nSrcCol, SCROW nSrcRow, SCCOL nDestCol, SCROW nDestRow, ScTable& rDestTab )
584{
585 if (!ValidColRow(nSrcCol, nSrcRow) || !ValidColRow(nDestCol, nDestRow))
586 return;
587
588 if (nSrcCol >= GetAllocatedColumnsCount())
589 {
590 if (nDestCol < rDestTab.GetAllocatedColumnsCount())
591 {
592 ScColumn& rDestCol = rDestTab.aCol[nDestCol];
593 rDestCol.maCells.set_empty(nDestRow, nDestRow);
594 rDestCol.maCellTextAttrs.set_empty(nDestRow, nDestRow);
595 rDestCol.maCellNotes.set_empty(nDestRow, nDestRow);
596 rDestCol.CellStorageModified();
597 }
598 return;
599 }
600
601 ScColumn& rSrcCol = aCol[nSrcCol];
602 ScColumn& rDestCol = rDestTab.CreateColumnIfNotExists(nDestCol);
603 rSrcCol.CopyCellToDocument(nSrcRow, nDestRow, rDestCol);
604}
605
606namespace {
607
608bool CheckAndDeduplicateCondFormat(ScDocument& rDocument, ScConditionalFormat* pOldFormat, const ScConditionalFormat* pNewFormat, SCTAB nTab)
609{
610 if (!pOldFormat)
611 return false;
612
613 if (pOldFormat->EqualEntries(*pNewFormat, true))
614 {
615 const ScRangeList& rNewRangeList = pNewFormat->GetRange();
616 ScRangeList& rDstRangeList = pOldFormat->GetRangeList();
617 for (size_t i = 0; i < rNewRangeList.size(); ++i)
618 {
619 rDstRangeList.Join(rNewRangeList[i]);
620 }
621 rDocument.AddCondFormatData(rNewRangeList, nTab, pOldFormat->GetKey());
622 return true;
623 }
624
625 return false;
626}
627
628}
629
630void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
631 SCCOL nDx, SCROW nDy, const ScTable* pTable)
632{
633 ScRange aOldRange( nCol1 - nDx, nRow1 - nDy, pTable->nTab, nCol2 - nDx, nRow2 - nDy, pTable->nTab);
634 ScRange aNewRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
635 bool bSameDoc = rDocument.GetStyleSheetPool() == pTable->rDocument.GetStyleSheetPool();
636
637 for(const auto& rxCondFormat : *pTable->mpCondFormatList)
638 {
639 const ScRangeList& rCondFormatRange = rxCondFormat->GetRange();
640 if(!rCondFormatRange.Intersects( aOldRange ))
641 continue;
642
643 ScRangeList aIntersectedRange = rCondFormatRange.GetIntersectedRange(aOldRange);
644 std::unique_ptr<ScConditionalFormat> pNewFormat = rxCondFormat->Clone(&rDocument);
645
646 pNewFormat->SetRange(aIntersectedRange);
648 aRefCxt.meMode = URM_COPY;
649 aRefCxt.maRange = aNewRange;
650 aRefCxt.mnColDelta = nDx;
651 aRefCxt.mnRowDelta = nDy;
652 aRefCxt.mnTabDelta = nTab - pTable->nTab;
653 pNewFormat->UpdateReference(aRefCxt, true);
654
655 if (bSameDoc && pTable->nTab == nTab && CheckAndDeduplicateCondFormat(rDocument, mpCondFormatList->GetFormat(rxCondFormat->GetKey()), pNewFormat.get(), nTab))
656 {
657 continue;
658 }
659 sal_uLong nMax = 0;
660 bool bDuplicate = false;
661 for(const auto& rxCond : *mpCondFormatList)
662 {
663 // Check if there is the same format in the destination
664 // If there is, then simply expand its range
665 if (CheckAndDeduplicateCondFormat(rDocument, rxCond.get(), pNewFormat.get(), nTab))
666 {
667 bDuplicate = true;
668 break;
669 }
670
671 if (rxCond->GetKey() > nMax)
672 nMax = rxCond->GetKey();
673 }
674 // Do not add duplicate entries
675 if (bDuplicate)
676 {
677 continue;
678 }
679
680 pNewFormat->SetKey(nMax + 1);
681 auto pNewFormatTmp = pNewFormat.get();
682 mpCondFormatList->InsertNew(std::move(pNewFormat));
683
684 if(!bSameDoc)
685 {
686 for(size_t i = 0, n = pNewFormatTmp->size();
687 i < n; ++i)
688 {
689 OUString aStyleName;
690 const ScFormatEntry* pEntry = pNewFormatTmp->GetEntry(i);
691 if(pEntry->GetType() == ScFormatEntry::Type::Condition ||
693 aStyleName = static_cast<const ScCondFormatEntry*>(pEntry)->GetStyle();
694 else if(pEntry->GetType() == ScFormatEntry::Type::Date)
695 aStyleName = static_cast<const ScCondDateFormatEntry*>(pEntry)->GetStyleName();
696
697 if(!aStyleName.isEmpty())
698 {
699 if(rDocument.GetStyleSheetPool()->Find(aStyleName, SfxStyleFamily::Para))
700 continue;
701
703 pTable->rDocument.GetStyleSheetPool(), aStyleName, SfxStyleFamily::Para );
704 }
705 }
706 }
707
708 rDocument.AddCondFormatData( pNewFormatTmp->GetRange(), nTab, pNewFormatTmp->GetKey() );
709 }
710}
711
713{
714 if (!ValidCol(nCol))
715 return false;
716
718 return true;
719}
720
721// pTable is source
722
724 sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
725 SCCOL nDx, SCROW nDy, ScTable* pTable )
726{
727 if (nCol2 > rDocument.MaxCol())
728 nCol2 = rDocument.MaxCol();
729 if (nRow2 > rDocument.MaxRow())
730 nRow2 = rDocument.MaxRow();
731
732 if (!(ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2)))
733 return;
734
736 for ( SCCOL i = nCol1; i <= nCol2; i++)
737 {
738 pTable->CreateColumnIfNotExists(i - nDx);
739 aCol[i].CopyFromClip(rCxt, nRow1, nRow2, nDy, pTable->aCol[i - nDx]); // notes are handles at column level
740 }
741
743 {
744 // make sure that there are no old references to the cond formats
745 sal_uInt16 nWhichArray[2];
746 nWhichArray[0] = ATTR_CONDITIONAL;
747 nWhichArray[1] = 0;
748 for ( SCCOL i = nCol1; i <= nCol2; ++i)
749 aCol[i].ClearItems(nRow1, nRow2, nWhichArray);
750 }
751
753 return;
754
755 if (nRow1==0 && nRow2==rDocument.MaxRow() && mpColWidth && pTable->mpColWidth)
756 mpColWidth->CopyFrom(*pTable->mpColWidth, nCol1, nCol2, nCol1 - nDx);
757
758 if (nCol1==0 && nCol2==rDocument.MaxCol() && mpRowHeights && pTable->mpRowHeights &&
759 pRowFlags && pTable->pRowFlags)
760 {
761 CopyRowHeight(*pTable, nRow1, nRow2, -nDy);
762 // Must copy CRFlags::ManualSize bit too, otherwise pRowHeight doesn't make sense
763 for (SCROW j=nRow1; j<=nRow2; j++)
764 {
765 if ( pTable->pRowFlags->GetValue(j-nDy) & CRFlags::ManualSize )
766 pRowFlags->OrValue( j, CRFlags::ManualSize);
767 else
768 pRowFlags->AndValue( j, ~CRFlags::ManualSize);
769 }
770 }
771
772 // Do not set protected cell in a protected sheet
774 {
775 ScPatternAttr aPattern(rDocument.GetPool());
776 aPattern.GetItemSet().Put( ScProtectionAttr( false ) );
777 ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
778 }
779
780 // create deep copies for conditional formatting
781 CopyConditionalFormat( nCol1, nRow1, nCol2, nRow2, nDx, nDy, pTable);
782}
783
785 sc::MixDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
786 ScPasteFunc nFunction, bool bSkipEmpty, const ScTable* pSrcTab )
787{
788 for (SCCOL i=nCol1; i<=nCol2; i++)
789 aCol[i].MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, pSrcTab->aCol[i]);
790}
791
792// Selection form this document
794 sc::MixDocContext& rCxt, const ScMarkData& rMark, ScPasteFunc nFunction,
795 bool bSkipEmpty, const ScTable* pSrcTab )
796{
797 for (SCCOL i=0; i < aCol.size(); i++)
798 aCol[i].MixMarked(rCxt, rMark, nFunction, bSkipEmpty, pSrcTab->aCol[i]);
799}
800
801namespace {
802
803class TransClipHandler
804{
805 ScTable& mrClipTab;
806 const ScTable& mrSrcTab;
807 SCTAB mnSrcTab;
808 SCCOL mnCol1;
809 SCCOL mnSrcCol;
810 size_t mnTopRow;
811 size_t mnEndRow;
812 SCROW mnTransRow;
813 SCROW mnFilteredRows = 0;
814 SCROW mnRowDestOffset = 0;
815 bool mbAsLink;
816 bool mbWasCut;
817 bool mbIncludeFiltered;
819
820 ScAddress getDestPos(size_t nRow) const
821 {
822 return ScAddress(static_cast<SCCOL>(mnCol1 + nRow - mnTopRow), mnTransRow,
823 mrClipTab.GetTab());
824 }
825
826 ScFormulaCell* createRefCell(size_t nSrcRow, const ScAddress& rDestPos) const
827 {
828 ScAddress aSrcPos(mnSrcCol, nSrcRow, mnSrcTab);
829 ScSingleRefData aRef;
830 aRef.InitAddress(aSrcPos); // Absolute reference.
831 aRef.SetFlag3D(true);
832
833 ScTokenArray aArr(mrClipTab.GetDoc());
834 aArr.AddSingleReference(aRef);
835 return new ScFormulaCell(mrClipTab.GetDoc(), rDestPos, aArr);
836 }
837
838 void setLink(size_t nRow)
839 {
840 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
841 mrClipTab.SetFormulaCell(nTransCol, mnTransRow,
842 createRefCell(nRow, getDestPos(nRow)));
843 }
844
845public:
846 TransClipHandler(ScTable& rClipTab, const ScTable& rSrcTab, SCTAB nSrcTab, SCCOL nCol1,
847 SCCOL nSrcCol, size_t nTopRow, size_t nEndRow, SCROW nCombinedStartRow,
848 SCROW nRowDestOffset, bool bAsLink, bool bWasCut,
849 const InsertDeleteFlags& nFlags, const bool bIncludeFiltered,
850 std::vector<SCROW>& rFilteredRows)
851 : mrClipTab(rClipTab)
852 , mrSrcTab(rSrcTab)
853 , mnSrcTab(nSrcTab)
854 , mnCol1(nCol1)
855 , mnSrcCol(nSrcCol)
856 , mnTopRow(nTopRow)
857 , mnEndRow(nEndRow)
858 , mnTransRow(nSrcCol - nCol1 + nCombinedStartRow)
859 , mnRowDestOffset(nRowDestOffset)
860 , mbAsLink(bAsLink)
861 , mbWasCut(bWasCut)
862 , mbIncludeFiltered(bIncludeFiltered)
863 , mnFlags(nFlags)
864 {
865 // Create list of filtered rows.
866 if (!mbIncludeFiltered)
867 {
868 for (SCROW curRow = nTopRow; curRow <= static_cast<SCROW>(mnEndRow); ++curRow)
869 {
870 // maybe this loop could be optimized
871 bool bFiltered = mrSrcTab.RowFiltered(curRow, nullptr, nullptr);
872 if (bFiltered)
873 rFilteredRows.push_back(curRow);
874 }
875 }
876 }
877
878 void operator() (size_t nRow, double fVal)
879 {
880 bool bFiltered = mrSrcTab.RowFiltered(nRow, nullptr, nullptr);
881 if (!mbIncludeFiltered && bFiltered)
882 {
883 mnFilteredRows++;
884 return;
885 }
886
887 if (mbAsLink)
888 {
889 setLink(nRow);
890 return;
891 }
892
893 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
894 mrClipTab.SetValue(nTransCol, mnTransRow, fVal);
895 }
896
897 void operator() (size_t nRow, const svl::SharedString& rStr)
898 {
899 bool bFiltered = mrSrcTab.RowFiltered(nRow, nullptr, nullptr);
900 if (!mbIncludeFiltered && bFiltered)
901 {
902 mnFilteredRows++;
903 return;
904 }
905
906 if (mbAsLink)
907 {
908 setLink(nRow);
909 return;
910 }
911
912 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
913 mrClipTab.SetRawString(nTransCol, mnTransRow, rStr);
914 }
915
916 void operator() (size_t nRow, const EditTextObject* p)
917 {
918 bool bFiltered = mrSrcTab.RowFiltered(nRow, nullptr, nullptr);
919 if (!mbIncludeFiltered && bFiltered)
920 {
921 mnFilteredRows++;
922 return;
923 }
924
925 if (mbAsLink)
926 {
927 setLink(nRow);
928 return;
929 }
930
931 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
932 mrClipTab.SetEditText(nTransCol, mnTransRow, ScEditUtil::Clone(*p, mrClipTab.GetDoc()));
933 }
934
935 void operator() (size_t nRow, const ScFormulaCell* p)
936 {
937 bool bFiltered = mrSrcTab.RowFiltered(nRow, nullptr, nullptr);
938 if (!mbIncludeFiltered && bFiltered)
939 {
940 mnFilteredRows++;
941 return;
942 }
943
944 if (mbAsLink)
945 {
946 setLink(nRow);
947 return;
948 }
949
950 ScFormulaCell* pNew = new ScFormulaCell(*p, mrClipTab.GetDoc(),
951 getDestPos(nRow - mnFilteredRows + mnRowDestOffset),
953
954 // rotate reference
955 // for Cut, the references are later adjusted through UpdateTranspose
956
957 if (!mbWasCut)
958 pNew->TransposeReference();
959
960 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
961 mrClipTab.SetFormulaCell(nTransCol, mnTransRow, pNew);
962 }
963
964 // empty cells
965 void operator()(const int /*type*/, size_t nRow, size_t nDataSize)
966 {
967 for (size_t curRow = nRow; curRow < nRow + nDataSize; ++curRow)
968 {
969 bool bFiltered = mrSrcTab.RowFiltered(curRow, nullptr, nullptr);
970 if (!mbIncludeFiltered && bFiltered)
971 {
972 mnFilteredRows++;
973 continue;
974 }
975
976 if (mbAsLink && mnFlags == InsertDeleteFlags::ALL)
977 {
978 // with InsertDeleteFlags::ALL, also create links (formulas) for empty cells
979 setLink(nRow);
980 continue;
981 }
982 }
983 }
984};
985}
986
987void ScTable::TransposeClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
988 SCROW nCombinedStartRow, SCROW nRowDestOffset, ScTable* pTransClip,
989 InsertDeleteFlags nFlags, bool bAsLink, bool bIncludeFiltered)
990{
991 bool bWasCut = rDocument.IsCutMode();
992
993 for (SCCOL nCol : GetWritableColumnsRange(nCol1, nCol2))
994 {
995 std::vector<SCROW> aFilteredRows;
996
997 TransClipHandler aFunc(*pTransClip, *this, nTab, nCol1, nCol, nRow1, nRow2,
998 nCombinedStartRow, nRowDestOffset, bAsLink, bWasCut, nFlags,
999 bIncludeFiltered, aFilteredRows);
1000
1001 const sc::CellStoreType& rCells = aCol[nCol].maCells;
1002
1003 // Loop through all rows by iterator and call aFunc operators
1004 sc::ParseAll(rCells.begin(), rCells, nRow1, nRow2, aFunc,
1005 aFunc);
1006
1007 // Attributes
1008 if (nFlags & InsertDeleteFlags::ATTRIB)
1009 TransposeColPatterns(pTransClip, nCol1, nCol, nRow1, nRow2, nCombinedStartRow,
1010 bIncludeFiltered, aFilteredRows, nRowDestOffset);
1011
1012 // Cell Notes - fdo#68381 paste cell notes on Transpose
1013 if ((nFlags & InsertDeleteFlags::NOTE) && rDocument.HasColNotes(nCol, nTab))
1014 TransposeColNotes(pTransClip, nCol1, nCol, nRow1, nRow2, nCombinedStartRow,
1015 bIncludeFiltered, nRowDestOffset);
1016 }
1017}
1018
1019static void lcl_SetTransposedPatternInRows(ScTable* pTransClip, SCROW nAttrRow1, SCROW nAttrRow2,
1020 SCCOL nCol1, SCROW nRow1, SCROW nCombinedStartRow, SCCOL nCol,
1021 const ScPatternAttr& rPatternAttr, bool bIncludeFiltered,
1022 const std::vector<SCROW>& rFilteredRows,
1023 SCROW nRowDestOffset)
1024{
1025 for (SCROW nRow = nAttrRow1; nRow <= nAttrRow2; nRow++)
1026 {
1027 size_t nFilteredRowAdjustment = 0;
1028 if (!bIncludeFiltered)
1029 {
1030 // aFilteredRows is sorted thus lower_bound() can be used.
1031 // lower_bound() has a logarithmic complexity O(log(n))
1032 auto itRow1 = std::lower_bound(rFilteredRows.begin(), rFilteredRows.end(), nRow1);
1033 auto itRow = std::lower_bound(rFilteredRows.begin(), rFilteredRows.end(), nRow);
1034 bool bRefRowIsFiltered = itRow != rFilteredRows.end() && *itRow == nRow;
1035 if (bRefRowIsFiltered)
1036 continue;
1037
1038 // How many filtered rows are between the formula cell and the reference?
1039 // distance() has a constant complexity O(1) for vectors
1040 nFilteredRowAdjustment = std::distance(itRow1, itRow);
1041 }
1042
1043 pTransClip->SetPattern(
1044 static_cast<SCCOL>(nCol1 + nRow - nRow1 - nFilteredRowAdjustment + nRowDestOffset),
1045 static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), rPatternAttr);
1046 }
1047}
1048
1049void ScTable::TransposeColPatterns(ScTable* pTransClip, SCCOL nCol1, SCCOL nCol, SCROW nRow1,
1050 SCROW nRow2, SCROW nCombinedStartRow, bool bIncludeFiltered,
1051 const std::vector<SCROW>& rFilteredRows, SCROW nRowDestOffset)
1052{
1053 SCROW nAttrRow1 = {}; // spurious -Werror=maybe-uninitialized
1054 SCROW nAttrRow2 = {}; // spurious -Werror=maybe-uninitialized
1055 const ScPatternAttr* pPattern;
1056 std::unique_ptr<ScAttrIterator> pAttrIter(aCol[nCol].CreateAttrIterator( nRow1, nRow2 ));
1057 while ( (pPattern = pAttrIter->Next( nAttrRow1, nAttrRow2 )) != nullptr )
1058 {
1059 if ( !IsDefaultItem( pPattern ) )
1060 {
1061 const SfxItemSet& rSet = pPattern->GetItemSet();
1062 if ( rSet.GetItemState( ATTR_MERGE, false ) == SfxItemState::DEFAULT &&
1063 rSet.GetItemState( ATTR_MERGE_FLAG, false ) == SfxItemState::DEFAULT &&
1064 rSet.GetItemState( ATTR_BORDER, false ) == SfxItemState::DEFAULT )
1065 {
1066 // Set pattern in cells from nAttrRow1 to nAttrRow2
1067 // no borders or merge items involved - use pattern as-is
1068 lcl_SetTransposedPatternInRows(pTransClip, nAttrRow1, nAttrRow2, nCol1, nRow1,
1069 nCombinedStartRow, nCol, *pPattern,
1070 bIncludeFiltered, rFilteredRows, nRowDestOffset);
1071 }
1072 else
1073 {
1074 // transpose borders and merge values, remove merge flags (refreshed after pasting)
1075 ScPatternAttr aNewPattern( *pPattern );
1076 SfxItemSet& rNewSet = aNewPattern.GetItemSet();
1077
1078 const SvxBoxItem& rOldBox = rSet.Get(ATTR_BORDER);
1079 if ( rOldBox.GetTop() || rOldBox.GetBottom() || rOldBox.GetLeft() || rOldBox.GetRight() )
1080 {
1081 SvxBoxItem aNew( ATTR_BORDER );
1082 aNew.SetLine( rOldBox.GetLine( SvxBoxItemLine::TOP ), SvxBoxItemLine::LEFT );
1083 aNew.SetLine( rOldBox.GetLine( SvxBoxItemLine::LEFT ), SvxBoxItemLine::TOP );
1084 aNew.SetLine( rOldBox.GetLine( SvxBoxItemLine::BOTTOM ), SvxBoxItemLine::RIGHT );
1085 aNew.SetLine( rOldBox.GetLine( SvxBoxItemLine::RIGHT ), SvxBoxItemLine::BOTTOM );
1086 aNew.SetDistance( rOldBox.GetDistance( SvxBoxItemLine::TOP ), SvxBoxItemLine::LEFT );
1087 aNew.SetDistance( rOldBox.GetDistance( SvxBoxItemLine::LEFT ), SvxBoxItemLine::TOP );
1088 aNew.SetDistance( rOldBox.GetDistance( SvxBoxItemLine::BOTTOM ), SvxBoxItemLine::RIGHT );
1089 aNew.SetDistance( rOldBox.GetDistance( SvxBoxItemLine::RIGHT ), SvxBoxItemLine::BOTTOM );
1090 rNewSet.Put( aNew );
1091 }
1092
1093 const ScMergeAttr& rOldMerge = rSet.Get(ATTR_MERGE);
1094 if (rOldMerge.IsMerged())
1095 rNewSet.Put( ScMergeAttr( std::min(
1096 static_cast<SCCOL>(rOldMerge.GetRowMerge()),
1097 static_cast<SCCOL>(rDocument.MaxCol()+1 - (nAttrRow2-nRow1))),
1098 std::min(
1099 static_cast<SCROW>(rOldMerge.GetColMerge()),
1100 static_cast<SCROW>(rDocument.MaxRow()+1 - (nCol-nCol1)))));
1101 const ScMergeFlagAttr& rOldFlag = rSet.Get(ATTR_MERGE_FLAG);
1102 if (rOldFlag.IsOverlapped())
1103 {
1104 ScMF nNewFlags = rOldFlag.GetValue() & ~ScMF( ScMF::Hor | ScMF::Ver );
1105 if ( nNewFlags != ScMF::NONE )
1106 rNewSet.Put( ScMergeFlagAttr( nNewFlags ) );
1107 else
1108 rNewSet.ClearItem( ATTR_MERGE_FLAG );
1109 }
1110
1111 // Set pattern in cells from nAttrRow1 to nAttrRow2
1112 lcl_SetTransposedPatternInRows(pTransClip, nAttrRow1, nAttrRow2, nCol1, nRow1,
1113 nCombinedStartRow, nCol, aNewPattern,
1114 bIncludeFiltered, rFilteredRows, nRowDestOffset);
1115 }
1116 }
1117 }
1118}
1119
1120void ScTable::TransposeColNotes(ScTable* pTransClip, SCCOL nCol1, SCCOL nCol, SCROW nRow1,
1121 SCROW nRow2, SCROW nCombinedStartRow, bool bIncludeFiltered,
1122 SCROW nRowDestOffset)
1123{
1124 sc::CellNoteStoreType::const_iterator itBlk = aCol[nCol].maCellNotes.begin(), itBlkEnd = aCol[nCol].maCellNotes.end();
1125
1126 // Locate the top row position.
1127 size_t nOffsetInBlock = 0;
1128 size_t nBlockStart = 0, nBlockEnd = 0, nRowPos = static_cast<size_t>(nRow1);
1129 for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd)
1130 {
1131 nBlockEnd = nBlockStart + itBlk->size;
1132 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1133 {
1134 // Found.
1135 nOffsetInBlock = nRowPos - nBlockStart;
1136 break;
1137 }
1138 }
1139
1140 if (itBlk == itBlkEnd)
1141 // Specified range found
1142 return;
1143
1144 nRowPos = static_cast<size_t>(nRow2); // End row position.
1145 SCCOL nFilteredRows = 0;
1146
1147 // Keep processing until we hit the end row position.
1148 sc::cellnote_block::const_iterator itData, itDataEnd;
1149 for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd, nOffsetInBlock = 0)
1150 {
1151 nBlockEnd = nBlockStart + itBlk->size;
1152
1153 if (itBlk->data)
1154 {
1155 itData = sc::cellnote_block::begin(*itBlk->data);
1156 std::advance(itData, nOffsetInBlock);
1157
1158 // selected area is smaller than the iteration block
1159 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1160 {
1161 // This block contains the end row. Only process partially.
1162 size_t nOffsetEnd = nRowPos - nBlockStart + 1;
1163 itDataEnd = sc::cellnote_block::begin(*itBlk->data);
1164 std::advance(itDataEnd, nOffsetEnd);
1165 size_t curRow = nBlockStart + nOffsetInBlock;
1166 for (; itData != itDataEnd; ++itData, ++curRow)
1167 {
1168 bool bFiltered = this->RowFiltered(curRow, nullptr, nullptr);
1169 if (!bIncludeFiltered && bFiltered)
1170 {
1171 nFilteredRows++;
1172 continue;
1173 }
1174
1175 ScAddress aDestPos(
1176 static_cast<SCCOL>(nCol1 + curRow - nRow1 - nFilteredRows + nRowDestOffset),
1177 static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), pTransClip->nTab);
1178 pTransClip->rDocument.ReleaseNote(aDestPos);
1179 ScPostIt* pNote = *itData;
1180 if (pNote)
1181 {
1182 std::unique_ptr<ScPostIt> pClonedNote = pNote->Clone( ScAddress(nCol, curRow, nTab), pTransClip->rDocument, aDestPos, true );
1183 pTransClip->rDocument.SetNote(aDestPos, std::move(pClonedNote));
1184 }
1185 }
1186 break; // we reached the last valid block
1187 }
1188 else
1189 {
1190 itDataEnd = sc::cellnote_block::end(*itBlk->data);
1191 size_t curRow = nBlockStart + nOffsetInBlock;
1192 for (; itData != itDataEnd; ++itData, ++curRow)
1193 {
1194 bool bFiltered = this->RowFiltered(curRow, nullptr, nullptr);
1195 if (!bIncludeFiltered && bFiltered)
1196 {
1197 nFilteredRows++;
1198 continue;
1199 }
1200
1201 ScAddress aDestPos(
1202 static_cast<SCCOL>(nCol1 + curRow - nRow1 - nFilteredRows + nRowDestOffset),
1203 static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), pTransClip->nTab);
1204 pTransClip->rDocument.ReleaseNote(aDestPos);
1205 ScPostIt* pNote = *itData;
1206 if (pNote)
1207 {
1208 std::unique_ptr<ScPostIt> pClonedNote = pNote->Clone( ScAddress(nCol, curRow, nTab), pTransClip->rDocument, aDestPos, true );
1209 pTransClip->rDocument.SetNote(aDestPos, std::move(pClonedNote));
1210 }
1211 }
1212 }
1213 }
1214 else // remove dest notes for rows without notes
1215 {
1216 for (size_t curRow = nBlockStart + nOffsetInBlock;
1217 curRow <= nBlockEnd && curRow <= nRowPos; ++curRow)
1218 {
1219 bool bFiltered = this->RowFiltered(curRow, nullptr, nullptr);
1220 if (!bIncludeFiltered && bFiltered && curRow < nBlockEnd)
1221 {
1222 nFilteredRows++;
1223 continue;
1224 }
1225
1226 ScAddress aDestPos(
1227 static_cast<SCCOL>(nCol1 + curRow - nRow1 - nFilteredRows + nRowDestOffset),
1228 static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), pTransClip->nTab);
1229 pTransClip->rDocument.ReleaseNote(aDestPos);
1230 }
1231 }
1232 }
1233}
1234
1236{
1237 if (!ValidCol(nCol))
1238 return nullptr;
1239
1240 return &CreateColumnIfNotExists(nCol);
1241}
1242
1244{
1245 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1246 return nullptr;
1247
1248 return &aCol[nCol];
1249}
1250
1252{
1253 std::shared_ptr<const sc::ColumnSet> pColSet = rCxt.getColumnSet();
1254 if (!pColSet)
1255 {
1256 for (SCCOL i=0; i < aCol.size(); i++)
1257 aCol[i].StartListeners(rCxt, bAll);
1258 }
1259 else if (pColSet->hasTab( nTab))
1260 {
1261 std::vector<SCCOL> aColumns;
1262 pColSet->getColumns( nTab, aColumns);
1263 for (auto i : aColumns)
1264 {
1265 if (0 <= i && i < aCol.size())
1266 aCol[i].StartListeners(rCxt, bAll);
1267 }
1268 }
1269}
1270
1272 sc::StartListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1273{
1274 nCol2 = ClampToAllocatedColumns(nCol2);
1275 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1276 aCol[nCol].AttachFormulaCells(rCxt, nRow1, nRow2);
1277}
1278
1280 sc::EndListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1281{
1282 nCol2 = ClampToAllocatedColumns(nCol2);
1283 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1284 aCol[nCol].DetachFormulaCells(rCxt, nRow1, nRow2);
1285}
1286
1288 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans )
1289{
1290 if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
1291 if (nCol2 > rDocument.MaxCol()) nCol2 = rDocument.MaxCol();
1292 if (nRow2 > rDocument.MaxRow()) nRow2 = rDocument.MaxRow();
1293 if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
1294 for (SCCOL i = nCol1; i <= nCol2; i++)
1295 aCol[i].SetDirtyFromClip(nRow1, nRow2, rBroadcastSpans);
1296}
1297
1300 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1301{
1302 if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
1303 if (nCol2 > rDocument.MaxCol()) nCol2 = rDocument.MaxCol();
1304 if (nRow2 > rDocument.MaxRow()) nRow2 = rDocument.MaxRow();
1305 if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
1306 for (SCCOL i = nCol1; i <= nCol2; i++)
1307 aCol[i].StartListeningFormulaCells(rStartCxt, rEndCxt, nRow1, nRow2);
1308}
1309
1311 sc::CopyToDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1312 InsertDeleteFlags nFlags, bool bMarked, ScTable* pDestTab, const ScMarkData* pMarkData,
1313 bool bAsLink, bool bColRowFlags, bool bGlobalNamesToLocal, bool bCopyCaptions )
1314{
1315 if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
1316 return;
1317
1318 const bool bToUndoDoc = pDestTab->rDocument.IsUndo();
1319 const bool bFromUndoDoc = rDocument.IsUndo();
1320
1321 if ((bToUndoDoc || bFromUndoDoc) && (nFlags & InsertDeleteFlags::CONTENTS) && mpRangeName)
1322 {
1323 // Copying formulas may create sheet-local named expressions on the
1324 // destination sheet. Add existing to Undo first.
1325 // During Undo restore the previous named expressions.
1326 pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName())));
1327 if (!pDestTab->rDocument.IsClipOrUndo())
1328 {
1329 ScDocShell* pDocSh = static_cast<ScDocShell*>(pDestTab->rDocument.GetDocumentShell());
1330 if (pDocSh)
1332 }
1333 }
1334
1335 if (nFlags != InsertDeleteFlags::NONE)
1336 {
1337 InsertDeleteFlags nTempFlags( nFlags &
1339 // tdf#102364 - in some pathological cases CopyToTable() replacing cells with new cells
1340 // can lead to repetitive splitting and rejoining of the same formula group, which can get
1341 // quadratically expensive with large groups. So do the grouping just once at the end.
1342 sc::DelayFormulaGroupingSwitch delayGrouping( pDestTab->rDocument, true );
1343 for (SCCOL i = nCol1; i <= ClampToAllocatedColumns(nCol2); i++)
1344 aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bToUndoDoc ? nFlags : nTempFlags, bMarked,
1345 pDestTab->CreateColumnIfNotExists(i), pMarkData, bAsLink, bGlobalNamesToLocal);
1346 }
1347
1348 if (!bColRowFlags) // Column widths/Row heights/Flags
1349 return;
1350
1351 if (bToUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB))
1352 {
1353 pDestTab->mpCondFormatList.reset(new ScConditionalFormatList(pDestTab->rDocument, *mpCondFormatList));
1354 }
1355
1356 if (pDBDataNoName)
1357 {
1358 std::unique_ptr<ScDBData> pNewDBData(new ScDBData(*pDBDataNoName));
1359 SCCOL aCol1, aCol2;
1360 SCROW aRow1, aRow2;
1361 SCTAB aTab;
1362 pNewDBData->GetArea(aTab, aCol1, aRow1, aCol2, aRow2);
1363 pNewDBData->MoveTo(pDestTab->nTab, aCol1, aRow1, aCol2, aRow2);
1364 pDestTab->SetAnonymousDBData(std::move(pNewDBData));
1365 }
1366 // Charts have to be adjusted when hide/show
1368
1369 bool bFlagChange = false;
1370
1371 bool bWidth = (nRow1==0 && nRow2==rDocument.MaxRow() && mpColWidth && pDestTab->mpColWidth);
1372 bool bHeight = (nCol1==0 && nCol2==rDocument.MaxCol() && mpRowHeights && pDestTab->mpRowHeights);
1373
1374 if (bWidth || bHeight)
1375 {
1376 if (bWidth)
1377 {
1378 auto destTabColWidthIt = pDestTab->mpColWidth->begin() + nCol1;
1379 auto thisTabColWidthIt = mpColWidth->begin() + nCol1;
1380 pDestTab->mpColWidth->CopyFrom(*mpColWidth, nCol1, nCol2);
1381 pDestTab->mpColFlags->CopyFrom(*mpColFlags, nCol1, nCol2);
1382 for (SCCOL i = nCol1; i <= nCol2; ++i)
1383 {
1384 bool bThisHidden = ColHidden(i);
1385 bool bHiddenChange = (pDestTab->ColHidden(i) != bThisHidden);
1386 bool bChange = bHiddenChange || (*destTabColWidthIt != *thisTabColWidthIt);
1387 pDestTab->SetColHidden(i, i, bThisHidden);
1388 //TODO: collect changes?
1389 if (bHiddenChange && pCharts)
1390 pCharts->SetRangeDirty(ScRange( i, 0, nTab, i, rDocument.MaxRow(), nTab ));
1391
1392 if (bChange)
1393 bFlagChange = true;
1394
1395 ++destTabColWidthIt;
1396 ++thisTabColWidthIt;
1397 }
1398 pDestTab->SetColManualBreaks( std::set(maColManualBreaks) );
1399 }
1400
1401 if (bHeight)
1402 {
1403 bool bChange = pDestTab->GetRowHeight(nRow1, nRow2) != GetRowHeight(nRow1, nRow2);
1404
1405 if (bChange)
1406 bFlagChange = true;
1407
1408 pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
1409 pDestTab->pRowFlags->CopyFrom(*pRowFlags, nRow1, nRow2);
1410
1411 // Hidden flags.
1412 for (SCROW i = nRow1; i <= nRow2; ++i)
1413 {
1414 SCROW nLastRow;
1415 bool bHidden = RowHidden(i, nullptr, &nLastRow);
1416 if (nLastRow >= nRow2)
1417 // the last row shouldn't exceed the upper bound the caller specified.
1418 nLastRow = nRow2;
1419
1420 bool bHiddenChanged = pDestTab->SetRowHidden(i, nLastRow, bHidden);
1421 if (bHiddenChanged && pCharts)
1422 // Hidden flags differ.
1423 pCharts->SetRangeDirty(ScRange(0, i, nTab, rDocument.MaxCol(), nLastRow, nTab));
1424
1425 if (bHiddenChanged)
1426 bFlagChange = true;
1427
1428 // Jump to the last row of the identical flag segment.
1429 i = nLastRow;
1430 }
1431
1432 // Filtered flags.
1433 for (SCROW i = nRow1; i <= nRow2; ++i)
1434 {
1435 SCROW nLastRow;
1436 bool bFiltered = RowFiltered(i, nullptr, &nLastRow);
1437 if (nLastRow >= nRow2)
1438 // the last row shouldn't exceed the upper bound the caller specified.
1439 nLastRow = nRow2;
1440 pDestTab->SetRowFiltered(i, nLastRow, bFiltered);
1441 i = nLastRow;
1442 }
1443 pDestTab->SetRowManualBreaks( std::set(maRowManualBreaks) );
1444 }
1445 }
1446
1447 if (bFlagChange)
1448 pDestTab->InvalidatePageBreaks();
1449
1450 if(nFlags & InsertDeleteFlags::ATTRIB)
1451 {
1452 pDestTab->mpCondFormatList->DeleteArea(nCol1, nRow1, nCol2, nRow2);
1453 pDestTab->CopyConditionalFormat(nCol1, nRow1, nCol2, nRow2, 0, 0, this);
1454 }
1455
1456 if(nFlags & InsertDeleteFlags::OUTLINE) // also only when bColRowFlags
1457 pDestTab->SetOutlineTable( pOutlineTable.get() );
1458
1459 if (nFlags & InsertDeleteFlags::SPARKLINES)
1460 {
1461 CopySparklinesToTable(nCol1, nRow1, nCol2, nRow2, pDestTab);
1462 }
1463
1464 if (!bToUndoDoc && bCopyCaptions && (nFlags & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)))
1465 {
1466 bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
1467 CopyCaptionsToTable( nCol1, nRow1, nCol2, nRow2, pDestTab, bCloneCaption);
1468 }
1469}
1470
1471void ScTable::CopySparklinesToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab)
1472{
1473 if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
1474 return;
1475
1476 nCol2 = ClampToAllocatedColumns(nCol2);
1477 for (SCCOL i = nCol1; i <= nCol2; i++)
1478 {
1479 aCol[i].CopyCellSparklinesToDocument(nRow1, nRow2, pDestTab->CreateColumnIfNotExists(i));
1480 }
1481}
1482
1483void ScTable::CopyCaptionsToTable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab,
1484 bool bCloneCaption )
1485{
1486 if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
1487 return;
1488
1489 nCol2 = ClampToAllocatedColumns(nCol2);
1490 for (SCCOL i = nCol1; i <= nCol2; i++)
1491 {
1492 aCol[i].CopyCellNotesToDocument(nRow1, nRow2, pDestTab->CreateColumnIfNotExists(i), bCloneCaption);
1493 pDestTab->aCol[i].UpdateNoteCaptions(nRow1, nRow2);
1494 }
1495}
1496
1498 sc::CopyToDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1499 InsertDeleteFlags nFlags, bool bMarked, ScTable* pDestTab )
1500{
1501 if (!(ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2)))
1502 return;
1503
1504 bool bWidth = (nRow1==0 && nRow2==rDocument.MaxRow() && mpColWidth && pDestTab->mpColWidth);
1505 bool bHeight = (nCol1==0 && nCol2==rDocument.MaxCol() && mpRowHeights && pDestTab->mpRowHeights);
1506
1507 if ((nFlags & InsertDeleteFlags::CONTENTS) && mpRangeName)
1508 {
1509 // Undo sheet-local named expressions created during copying
1510 // formulas. If mpRangeName is not set then the Undo wasn't even
1511 // set to an empty ScRangeName map so don't "undo" that.
1512 pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName())));
1513 if (!pDestTab->rDocument.IsClipOrUndo())
1514 {
1515 ScDocShell* pDocSh = static_cast<ScDocShell*>(pDestTab->rDocument.GetDocumentShell());
1516 if (pDocSh)
1518 }
1519
1520 }
1521
1522 for ( SCCOL i = 0; i < aCol.size(); i++)
1523 {
1524 auto& rDestCol = pDestTab->CreateColumnIfNotExists(i);
1525 if ( i >= nCol1 && i <= nCol2 )
1526 aCol[i].UndoToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rDestCol);
1527 else
1528 aCol[i].CopyToColumn(rCxt, 0, rDocument.MaxRow(), InsertDeleteFlags::FORMULA, false, rDestCol);
1529 }
1530
1531 if (nFlags & InsertDeleteFlags::ATTRIB)
1532 pDestTab->mpCondFormatList.reset(new ScConditionalFormatList(pDestTab->rDocument, *mpCondFormatList));
1533
1534 if (!(bWidth||bHeight))
1535 return;
1536
1537 if (bWidth)
1538 {
1539 pDestTab->mpColWidth->CopyFrom(*mpColWidth, nCol1, nCol2);
1540 pDestTab->SetColManualBreaks( std::set(maColManualBreaks) );
1541 }
1542 if (bHeight)
1543 {
1544 pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
1545 pDestTab->SetRowManualBreaks( std::set(maRowManualBreaks) );
1546 }
1547}
1548
1549void ScTable::CopyUpdated( const ScTable* pPosTab, ScTable* pDestTab ) const
1550{
1551 pDestTab->CreateColumnIfNotExists(aCol.size()-1);
1552 for (SCCOL i=0; i < aCol.size(); i++)
1553 aCol[i].CopyUpdated( pPosTab->FetchColumn(i), pDestTab->aCol[i] );
1554}
1555
1557{
1558 bTableAreaValid = false;
1559 bTableAreaVisibleValid = false;
1560}
1561
1563{
1564 mbPageBreaksValid = false;
1565}
1566
1567void ScTable::CopyScenarioTo( ScTable* pDestTab ) const
1568{
1569 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1570
1571 for (SCCOL i=0; i < aCol.size(); i++)
1573}
1574
1576{
1577 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1578
1579 SCCOL nEndCol = pSrcTab->aCol.size();
1580 CreateColumnIfNotExists(nEndCol);
1581 for (SCCOL i=0; i < nEndCol; i++)
1582 aCol[i].CopyScenarioFrom( pSrcTab->aCol[i] );
1583}
1584
1585void ScTable::MarkScenarioIn( ScMarkData& rDestMark, ScScenarioFlags nNeededBits ) const
1586{
1587 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1588
1589 if ( ( nScenarioFlags & nNeededBits ) != nNeededBits ) // Are all Bits set?
1590 return;
1591
1592 for (SCCOL i=0; i < aCol.size(); i++)
1593 aCol[i].MarkScenarioIn( rDestMark );
1594}
1595
1596bool ScTable::HasScenarioRange( const ScRange& rRange ) const
1597{
1598 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1599
1600 ScRange aTabRange = rRange;
1601 aTabRange.aStart.SetTab( nTab );
1602 aTabRange.aEnd.SetTab( nTab );
1603
1604 const ScRangeList* pList = GetScenarioRanges();
1605
1606 if (pList)
1607 {
1608 for ( size_t j = 0, n = pList->size(); j < n; j++ )
1609 {
1610 const ScRange & rR = (*pList)[j];
1611 if ( rR.Intersects( aTabRange ) )
1612 return true;
1613 }
1614 }
1615
1616 return false;
1617}
1618
1620{
1621 pScenarioRanges.reset();
1622}
1623
1625{
1626 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1627
1628 if (!pScenarioRanges)
1629 {
1630 const_cast<ScTable*>(this)->pScenarioRanges.reset(new ScRangeList);
1632 MarkScenarioIn( aMark, ScScenarioFlags::NONE ); // always
1633 aMark.FillRangeListWithMarks( pScenarioRanges.get(), false );
1634 }
1635 return pScenarioRanges.get();
1636}
1637
1638bool ScTable::TestCopyScenarioTo( const ScTable* pDestTab ) const
1639{
1640 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1641
1642 if (!pDestTab->IsProtected())
1643 return true;
1644
1645 bool bOk = true;
1646 for (SCCOL i=0; i < aCol.size() && bOk; i++)
1647 bOk = aCol[i].TestCopyScenarioTo( pDestTab->aCol[i] );
1648 return bOk;
1649}
1650
1651bool ScTable::SetString( SCCOL nCol, SCROW nRow, SCTAB nTabP, const OUString& rString,
1652 const ScSetStringParam * pParam )
1653{
1654 if (!ValidColRow(nCol,nRow))
1655 {
1656 return false;
1657 }
1658
1660 nRow, nTabP, rString, rDocument.GetAddressConvention(), pParam);
1661}
1662
1663bool ScTable::SetEditText( SCCOL nCol, SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
1664{
1665 if (!ValidColRow(nCol, nRow))
1666 {
1667 return false;
1668 }
1669
1670 CreateColumnIfNotExists(nCol).SetEditText(nRow, std::move(pEditText));
1671 return true;
1672}
1673
1674void ScTable::SetEditText( SCCOL nCol, SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
1675{
1676 if (!ValidColRow(nCol, nRow))
1677 return;
1678
1679 CreateColumnIfNotExists(nCol).SetEditText(nRow, rEditText, pEditPool);
1680}
1681
1682SCROW ScTable::GetFirstEditTextRow( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
1683{
1684 if (!ValidCol(nCol1) || !ValidCol(nCol2) || nCol2 < nCol1)
1685 return -1;
1686
1687 if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow2 < nRow1)
1688 return -1;
1689
1690 nCol2 = ClampToAllocatedColumns(nCol2);
1691 SCROW nFirst = rDocument.MaxRow()+1;
1692 for (SCCOL i = nCol1; i <= nCol2; ++i)
1693 {
1694 const ScColumn& rCol = aCol[i];
1695 SCROW nThisFirst = -1;
1696 if (const_cast<ScColumn&>(rCol).HasEditCells(nRow1, nRow2, nThisFirst))
1697 {
1698 if (nThisFirst == nRow1)
1699 return nRow1;
1700
1701 if (nThisFirst < nFirst)
1702 nFirst = nThisFirst;
1703 }
1704 }
1705
1706 return nFirst == (rDocument.MaxRow()+1) ? -1 : nFirst;
1707}
1708
1710{
1711 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1712 return;
1713
1714 aCol[nCol].Delete(nRow);
1715}
1716
1718 SCCOL nCol, SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
1719{
1720 if (!ValidColRow(nCol, nRow))
1721 return;
1722
1723 CreateColumnIfNotExists(nCol).SetFormula(nRow, rArray, eGram);
1724}
1725
1727 SCCOL nCol, SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
1728{
1729 if (!ValidColRow(nCol, nRow))
1730 return;
1731
1732 CreateColumnIfNotExists(nCol).SetFormula(nRow, rFormula, eGram);
1733}
1734
1736{
1737 if (!ValidColRow(nCol, nRow))
1738 {
1739 delete pCell;
1740 return nullptr;
1741 }
1742
1744}
1745
1746bool ScTable::SetFormulaCells( SCCOL nCol, SCROW nRow, std::vector<ScFormulaCell*>& rCells )
1747{
1748 if (!ValidCol(nCol))
1749 return false;
1750
1751 return CreateColumnIfNotExists(nCol).SetFormulaCells(nRow, rCells);
1752}
1753
1755{
1756 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1757 return svl::SharedString();
1758
1759 return aCol[nCol].GetSharedString(nRow);
1760}
1761
1762void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
1763{
1764 if (ValidColRow(nCol, nRow))
1765 CreateColumnIfNotExists(nCol).SetValue(nRow, rVal);
1766}
1767
1769{
1770 if (ValidColRow(nCol, nRow))
1771 CreateColumnIfNotExists(nCol).SetRawString(nRow, rStr);
1772}
1773
1774OUString ScTable::GetString( SCCOL nCol, SCROW nRow, const ScInterpreterContext* pContext ) const
1775{
1776 if (ValidColRow(nCol,nRow) && nCol < GetAllocatedColumnsCount())
1777 return aCol[nCol].GetString( nRow, pContext );
1778 else
1779 return OUString();
1780}
1781
1782double* ScTable::GetValueCell( SCCOL nCol, SCROW nRow )
1783{
1784 if (!ValidColRow(nCol, nRow))
1785 return nullptr;
1786
1787 return CreateColumnIfNotExists(nCol).GetValueCell(nRow);
1788}
1789
1790OUString ScTable::GetInputString( SCCOL nCol, SCROW nRow, bool bForceSystemLocale ) const
1791{
1792 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
1793 return aCol[nCol].GetInputString( nRow, bForceSystemLocale );
1794 else
1795 return OUString();
1796}
1797
1798double ScTable::GetValue( SCCOL nCol, SCROW nRow ) const
1799{
1800 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
1801 return aCol[nCol].GetValue( nRow );
1802 return 0.0;
1803}
1804
1806{
1807 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1808 return nullptr;
1809
1810 return aCol[nCol].GetEditText(nRow);
1811}
1812
1814{
1815 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1816 return;
1817
1818 return aCol[nCol].RemoveEditTextCharAttribs(nRow, rAttr);
1819}
1820
1821OUString ScTable::GetFormula( SCCOL nCol, SCROW nRow ) const
1822{
1823 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
1824 return aCol[nCol].GetFormula( nRow );
1825 else
1826 return OUString();
1827}
1828
1830{
1831 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1832 return nullptr;
1833
1834 return aCol[nCol].GetFormulaCell(nRow);
1835}
1836
1838{
1839 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1840 return nullptr;
1841
1842 return aCol[nCol].GetFormulaCell(nRow);
1843}
1844
1845// Sparklines
1846
1847std::shared_ptr<sc::Sparkline> ScTable::GetSparkline(SCCOL nCol, SCROW nRow)
1848{
1849 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1850 return std::shared_ptr<sc::Sparkline>();
1851
1852 sc::SparklineCell* pSparklineCell = aCol[nCol].GetSparklineCell(nRow);
1853 if (!pSparklineCell)
1854 return std::shared_ptr<sc::Sparkline>();
1855
1856 return pSparklineCell->getSparkline();
1857}
1858
1859sc::Sparkline* ScTable::CreateSparkline(SCCOL nCol, SCROW nRow, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup)
1860{
1861 if (!ValidCol(nCol))
1862 return nullptr;
1863
1864 ScColumn& rColumn = CreateColumnIfNotExists(nCol);
1865
1866 std::shared_ptr<sc::Sparkline> pSparkline(new sc::Sparkline(nCol, nRow, pSparklineGroup));
1867 rColumn.CreateSparklineCell(nRow, pSparkline);
1868
1869 return pSparkline.get();
1870}
1871
1873{
1874 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1875 return false;
1876
1877 aCol[nCol].DeleteSparkline(nRow);
1878
1879 return true;
1880}
1881
1883{
1884 return maSparklineList;
1885}
1886
1887// Notes
1888
1889std::unique_ptr<ScPostIt> ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
1890{
1891 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1892 return nullptr;
1893
1894 return aCol[nCol].ReleaseNote(nRow);
1895}
1896
1898{
1899 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1900 return nullptr;
1901 return aCol[nCol].GetCellNote(nRow);
1902}
1903
1904void ScTable::SetNote( SCCOL nCol, SCROW nRow, std::unique_ptr<ScPostIt> pNote )
1905{
1906 if (!ValidColRow(nCol, nRow))
1907 return;
1908
1909 CreateColumnIfNotExists(nCol).SetCellNote(nRow, std::move(pNote));
1910}
1911
1912size_t ScTable::GetNoteCount( SCCOL nCol ) const
1913{
1914 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1915 return 0;
1916
1917 return aCol[nCol].GetNoteCount();
1918}
1919
1920SCROW ScTable::GetNotePosition( SCCOL nCol, size_t nIndex ) const
1921{
1922 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1923 return -1;
1924
1925 return aCol[nCol].GetNotePosition(nIndex);
1926}
1927
1929{
1930 for (SCCOL i = 0; i < aCol.size(); ++i)
1932}
1933
1934void ScTable::ForgetNoteCaptions( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bPreserveData )
1935{
1936 if (!ValidCol(nCol1) || !ValidCol(nCol2))
1937 return;
1938 if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
1939 for (SCCOL i = nCol1; i <= nCol2; ++i)
1940 aCol[i].ForgetNoteCaptions(nRow1, nRow2, bPreserveData);
1941}
1942
1943void ScTable::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
1944{
1945 for (SCCOL nCol = 0; nCol < aCol.size(); ++nCol)
1946 aCol[nCol].GetAllNoteEntries(rNotes);
1947}
1948
1949void ScTable::GetNotesInRange( const ScRange& rRange, std::vector<sc::NoteEntry>& rNotes ) const
1950{
1951 SCROW nStartRow = rRange.aStart.Row();
1952 SCROW nEndRow = rRange.aEnd.Row();
1953 SCCOL nEndCol = ClampToAllocatedColumns(rRange.aEnd.Col());
1954 for (SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; ++nCol)
1955 {
1956 aCol[nCol].GetNotesInRange(nStartRow, nEndRow, rNotes);
1957 }
1958}
1959
1960CommentCaptionState ScTable::GetAllNoteCaptionsState(const ScRange& rRange, std::vector<sc::NoteEntry>& rNotes )
1961{
1962 SCROW nStartRow = rRange.aStart.Row();
1963 SCROW nEndRow = rRange.aEnd.Row();
1964 bool bIsFirstNoteShownState = true; // because of error: -Werror=maybe-uninitialized
1965 bool bFirstControl = true;
1966
1968 assert(pTab);
1969 const SCCOL nEndCol = pTab->ClampToAllocatedColumns(rRange.aEnd.Col());
1970 for (SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; ++nCol)
1971 {
1972 if (bFirstControl && rDocument.HasColNotes(nCol, nTab)) // detect status of first note caption
1973 {
1974 aCol[nCol].GetNotesInRange(nStartRow, nEndRow, rNotes);
1975 bIsFirstNoteShownState = rNotes.begin()->mpNote->IsCaptionShown();
1976 bFirstControl = false;
1977 }
1978
1979 if (rDocument.HasColNotes(nCol, nTab))
1980 {
1981 aCol[nCol].GetNotesInRange(nStartRow, nEndRow, rNotes);
1982
1983 bool bIsMixedState = std::any_of(rNotes.begin(), rNotes.end(), [bIsFirstNoteShownState](const sc::NoteEntry& rNote) {
1984 // compare the first note caption with others
1985 return bIsFirstNoteShownState != rNote.mpNote->IsCaptionShown(); });
1986 if (bIsMixedState)
1988 }
1989 }
1990 return bIsFirstNoteShownState ? CommentCaptionState::ALLSHOWN : CommentCaptionState::ALLHIDDEN;
1991}
1992
1994{
1995 for (auto const & pCol : aCol)
1996 pCol->GetUnprotectedCells(0, rDocument.MaxRow(), rRangeList);
1997}
1998
1999bool ScTable::ContainsNotesInRange( const ScRange& rRange ) const
2000{
2001 SCROW nStartRow = rRange.aStart.Row();
2002 SCROW nEndRow = rRange.aEnd.Row();
2003 SCCOL nEndCol = ClampToAllocatedColumns(rRange.aEnd.Col());
2004 for (SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; ++nCol)
2005 {
2006 bool bContainsNote = !aCol[nCol].IsNotesEmptyBlock(nStartRow, nEndRow);
2007 if(bContainsNote)
2008 return true;
2009 }
2010
2011 return false;
2012}
2013
2015{
2016 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
2017 return aCol[nCol].GetCellType( nRow );
2018 return CELLTYPE_NONE;
2019}
2020
2022{
2023 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
2024 return ScRefCellValue();
2025
2026 return aCol[nCol].GetCellValue(nRow);
2027}
2028
2030{
2031 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
2032 return ScRefCellValue();
2033
2034 return aCol[nCol].GetCellValue(rBlockPos, nRow);
2035}
2036
2037void ScTable::GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const
2038{
2039 rCol = 0;
2040 rRow = rDocument.MaxRow()+1;
2041 while (rCol < (aCol.size() - 1) && aCol[rCol].IsEmptyData() )
2042 ++rCol;
2043 SCCOL nCol = rCol;
2044 while (nCol < aCol.size() && rRow > 0)
2045 {
2046 if (!aCol[nCol].IsEmptyData())
2047 rRow = ::std::min( rRow, aCol[nCol].GetFirstDataPos());
2048 ++nCol;
2049 }
2050}
2051
2052void ScTable::GetLastDataPos(SCCOL& rCol, SCROW& rRow) const
2053{
2054 rCol = aCol.size() - 1;
2055 rRow = 0;
2056 while (aCol[rCol].IsEmptyData() && (rCol > 0))
2057 rCol--;
2058 SCCOL nCol = rCol;
2059 while (nCol >= 0 && rRow < rDocument.MaxRow())
2060 rRow = ::std::max( rRow, aCol[nCol--].GetLastDataPos());
2061}
2062
2063bool ScTable::HasData( SCCOL nCol, SCROW nRow ) const
2064{
2065 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
2066 return aCol[nCol].HasDataAt( nRow );
2067 else
2068 return false;
2069}
2070
2071bool ScTable::HasStringData( SCCOL nCol, SCROW nRow ) const
2072{
2073 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
2074 return aCol[nCol].HasStringData( nRow );
2075 else
2076 return false;
2077}
2078
2079bool ScTable::HasValueData( SCCOL nCol, SCROW nRow ) const
2080{
2081 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
2082 return aCol[nCol].HasValueData( nRow );
2083 else
2084 return false;
2085}
2086
2087bool ScTable::HasStringCells( SCCOL nStartCol, SCROW nStartRow,
2088 SCCOL nEndCol, SCROW nEndRow ) const
2089{
2090 if (ValidCol(nEndCol))
2091 {
2092 nEndCol = ClampToAllocatedColumns(nEndCol);
2093 for (SCCOL nCol = nStartCol; nCol <= nEndCol; nCol++)
2094 if (aCol[nCol].HasStringCells(nStartRow, nEndRow))
2095 return true;
2096 }
2097
2098 return false;
2099}
2100
2102{
2103 for (SCCOL i=0; i < aCol.size(); i++)
2104 aCol[i].SetDirtyVar();
2105}
2106
2108{
2109 sc::AutoCalcSwitch aACSwitch(rDocument, false);
2110
2111 for (SCCOL i = 0; i < aCol.size(); i++)
2113}
2114
2116{
2117 sc::AutoCalcSwitch aACSwitch(rDocument, false);
2118
2119 for (SCCOL i=0; i < aCol.size(); i++)
2120 aCol[i].SetAllFormulasDirty(rCxt);
2121}
2122
2124{
2125 sc::AutoCalcSwitch aSwitch(rDocument, false);
2126 SCCOL nCol2 = rRange.aEnd.Col();
2127 nCol2 = ClampToAllocatedColumns(nCol2);
2128 for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
2129 aCol[i].SetDirty(rRange.aStart.Row(), rRange.aEnd.Row(), eMode);
2130}
2131
2133{
2134 sc::AutoCalcSwitch aSwitch(rDocument, false);
2135 const SCCOL nCol2 = ClampToAllocatedColumns(rRange.aEnd.Col());
2136 for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
2137 aCol[i].SetTableOpDirty( rRange );
2138}
2139
2141{
2142 sc::AutoCalcSwitch aSwitch(rDocument, false);
2143 for (SCCOL i=0; i < aCol.size(); i++)
2145}
2146
2148{
2149 sc::AutoCalcSwitch aSwitch(rDocument, false);
2150 ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
2151 for (SCCOL i=0; i < aCol.size(); i++)
2153}
2154
2156{
2157 sc::AutoCalcSwitch aSwitch(rDocument, false);
2158 for (SCCOL i = 0; i < aCol.size(); ++i)
2160}
2161
2162bool ScTable::BroadcastBroadcasters( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SfxHintId nHint )
2163{
2164 bool bBroadcasted = false;
2165 sc::AutoCalcSwitch aSwitch(rDocument, false);
2166 nCol2 = ClampToAllocatedColumns(nCol2);
2167 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2168 bBroadcasted |= aCol[nCol].BroadcastBroadcasters( nRow1, nRow2, nHint);
2169 return bBroadcasted;
2170}
2171
2172void ScTable::SetLoadingMedium(bool bLoading)
2173{
2174 mpRowHeights->enableTreeSearch(!bLoading);
2175}
2176
2178{
2179 for (SCCOL i=0; i < aCol.size(); i++)
2180 aCol[i].CalcAll();
2181
2182 mpCondFormatList->CalcAll();
2183}
2184
2186{
2187 for (SCCOL i = 0; i < aCol.size(); ++i)
2188 aCol[i].CompileAll(rCxt);
2189
2191 mpCondFormatList->CompileAll();
2192}
2193
2195{
2196 if (mpRangeName)
2197 mpRangeName->CompileUnresolvedXML(rCxt);
2198
2199 for (SCCOL i=0; i < aCol.size(); i++)
2200 {
2201 aCol[i].CompileXML(rCxt, rProgress);
2202 }
2203
2205 mpCondFormatList->CompileXML();
2206}
2207
2209{
2210 bool bCompiled = false;
2211 for (SCCOL i = 0; i < aCol.size(); ++i)
2212 {
2213 if (aCol[i].CompileErrorCells(rCxt, nErrCode))
2214 bCompiled = true;
2215 }
2216
2217 return bCompiled;
2218}
2219
2220void ScTable::CalcAfterLoad( sc::CompileFormulaContext& rCxt, bool bStartListening )
2221{
2222 for (SCCOL i = 0; i < aCol.size(); ++i)
2223 aCol[i].CalcAfterLoad(rCxt, bStartListening);
2224}
2225
2226void ScTable::ResetChanged( const ScRange& rRange )
2227{
2228 SCCOL nStartCol = rRange.aStart.Col();
2229 SCROW nStartRow = rRange.aStart.Row();
2230 SCCOL nEndCol = ClampToAllocatedColumns(rRange.aEnd.Col());
2231 SCROW nEndRow = rRange.aEnd.Row();
2232
2233 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2234 aCol[nCol].ResetChanged(nStartRow, nEndRow);
2235}
2236
2237// Attribute
2238
2239const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich ) const
2240{
2241 if (!ValidColRow(nCol, nRow))
2242 return nullptr;
2243 return &ColumnData(nCol).GetAttr( nRow, nWhich );
2244}
2245
2246const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich, SCROW& nStartRow, SCROW& nEndRow ) const
2247{
2248 if (!ValidColRow(nCol, nRow))
2249 return nullptr;
2250 return &ColumnData(nCol).GetAttr( nRow, nWhich, nStartRow, nEndRow );
2251}
2252
2253sal_uInt32 ScTable::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const
2254{
2255 if (ValidColRow(rPos.Col(), rPos.Row()))
2256 return ColumnData(rPos.Col()).GetNumberFormat(rContext, rPos.Row());
2257 return 0;
2258}
2259
2260sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nRow ) const
2261{
2263}
2264
2265sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
2266{
2267 if (!ValidCol(nCol) || !ValidRow(nStartRow) || !ValidRow(nEndRow))
2268 return 0;
2269
2270 return ColumnData(nCol).GetNumberFormat(nStartRow, nEndRow);
2271}
2272
2273void ScTable::SetNumberFormat( SCCOL nCol, SCROW nRow, sal_uInt32 nNumberFormat )
2274{
2275 if (!ValidColRow(nCol, nRow))
2276 return;
2277
2278 CreateColumnIfNotExists(nCol).SetNumberFormat(nRow, nNumberFormat);
2279}
2280
2282{
2283 if (!ValidColRow(nCol,nRow))
2284 return nullptr;
2285 return ColumnData(nCol).GetPattern( nRow );
2286}
2287
2288const ScPatternAttr* ScTable::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
2289{
2290 if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow))
2291 return ColumnData(nCol).GetMostUsedPattern( nStartRow, nEndRow );
2292 return nullptr;
2293}
2294
2295bool ScTable::HasAttrib( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, HasAttrFlags nMask ) const
2296{
2297 for(SCCOL nCol = nCol1; nCol <= nCol2 && nCol < aCol.size(); ++nCol )
2298 if( aCol[nCol].HasAttrib( nRow1, nRow2, nMask ))
2299 return true;
2300 if( nCol2 >= aCol.size())
2301 return aDefaultColData.HasAttrib( nRow1, nRow2, nMask );
2302 return false;
2303}
2304
2305bool ScTable::HasAttrib( SCCOL nCol, SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow, SCROW* nEndRow ) const
2306{
2307 return ColumnData(nCol).HasAttrib( nRow, nMask, nStartRow, nEndRow );
2308}
2309
2310bool ScTable::HasAttribSelection( const ScMarkData& rMark, HasAttrFlags nMask ) const
2311{
2312 std::vector<sc::ColRowSpan> aSpans = rMark.GetMarkedColSpans();
2313
2314 for (const sc::ColRowSpan & aSpan : aSpans)
2315 {
2316 for (SCCOLROW j = aSpan.mnStart; j <= aSpan.mnEnd; ++j)
2317 {
2318 if (aCol[j].HasAttribSelection(rMark, nMask))
2319 return true;
2320 }
2321 }
2322 return false;
2323}
2324
2325bool ScTable::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
2326 SCCOL& rEndCol, SCROW& rEndRow,
2327 bool bRefresh )
2328{
2329 if (!(ValidCol(nStartCol) && ValidCol(rEndCol)))
2330 {
2331 OSL_FAIL("ScTable::ExtendMerge: invalid column number");
2332 return false;
2333 }
2334 if( rEndCol >= aCol.size())
2335 assert( !aDefaultColData.GetAttr( nStartRow, ATTR_MERGE ).IsMerged());
2336 bool bFound = false;
2337 SCCOL nOldEndX = ClampToAllocatedColumns(rEndCol);
2338 SCROW nOldEndY = rEndRow;
2339 for (SCCOL i=nStartCol; i<=nOldEndX; i++)
2340 bFound |= aCol[i].ExtendMerge( i, nStartRow, nOldEndY, rEndCol, rEndRow, bRefresh );
2341 return bFound;
2342}
2343
2344void ScTable::SetMergedCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2345{
2346 ScMergeAttr aAttr(nCol2-nCol1+1, nRow2-nRow1+1);
2347 ApplyAttr(nCol1, nRow1, aAttr);
2348
2349 if (nCol1 < nCol2)
2350 ApplyFlags(nCol1+1, nRow1, nCol2, nRow2, ScMF::Hor);
2351
2352 if (nRow1 < nRow2)
2353 ApplyFlags(nCol1, nRow1+1, nCol1, nRow2, ScMF::Ver);
2354
2355 if (nCol1 < nCol2 && nRow1 < nRow2)
2356 ApplyFlags(nCol1+1, nRow1+1, nCol2, nRow2, ScMF::Hor | ScMF::Ver);
2357}
2358
2359bool ScTable::IsBlockEmpty( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
2360{
2361 if (!(ValidCol(nCol1) && ValidCol(nCol2)))
2362 {
2363 OSL_FAIL("ScTable::IsBlockEmpty: invalid column number");
2364 return false;
2365 }
2366 nCol2 = ClampToAllocatedColumns(nCol2);
2367 bool bEmpty = true;
2368 for (SCCOL i=nCol1; i<=nCol2 && bEmpty; i++)
2369 {
2370 bEmpty = aCol[i].IsEmptyData( nRow1, nRow2 );
2371 if (bEmpty)
2372 {
2373 bEmpty = aCol[i].IsSparklinesEmptyBlock(nRow1, nRow2);
2374 }
2375 if (bEmpty)
2376 {
2377 bEmpty = aCol[i].IsNotesEmptyBlock(nRow1, nRow2);
2378 }
2379 }
2380 return bEmpty;
2381}
2382
2383SCSIZE ScTable::FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2,
2384 SCCOL nCol, SCROW nAttrRow1, SCROW nAttrRow2, SCSIZE nArrY,
2385 const ScPatternAttr* pPattern, const SfxItemSet* pCondSet )
2386{
2387 // Return value = new nArrY
2388
2389 ScRotateDir nRotDir = pPattern->GetRotateDir( pCondSet );
2390 if ( nRotDir != ScRotateDir::NONE )
2391 {
2392 bool bHit = true;
2393 if ( nCol+1 < nX1 ) // column to the left
2394 bHit = ( nRotDir != ScRotateDir::Left );
2395 else if ( nCol > nX2+1 ) // column to the right
2396 bHit = ( nRotDir != ScRotateDir::Right ); // ScRotateDir::Standard may now also be extended to the left
2397
2398 if ( bHit )
2399 {
2400 double nFactor = 0.0;
2401 if ( nCol > nX2+1 )
2402 {
2403 Degree100 nRotVal = pPattern->
2404 GetItem( ATTR_ROTATE_VALUE, pCondSet ).GetValue();
2405 double nRealOrient = toRadians(nRotVal);
2406 double nCos = cos( nRealOrient );
2407 double nSin = sin( nRealOrient );
2408 //TODO: limit !!!
2409 //TODO: additional factor for varying PPT X/Y !!!
2410
2411 // for ScRotateDir::Left this gives a negative value,
2412 // if the mode is considered
2413 nFactor = -fabs( nCos / nSin );
2414 }
2415
2416 for ( SCROW nRow = nAttrRow1; nRow <= nAttrRow2; nRow++ )
2417 {
2418 if (!RowHidden(nRow))
2419 {
2420 bool bHitOne = true;
2421 if ( nCol > nX2+1 )
2422 {
2423 // Does the rotated cell extend into the visible range?
2424
2425 SCCOL nTouchedCol = nCol;
2426 tools::Long nWidth = static_cast<tools::Long>(mpRowHeights->getValue(nRow) * nFactor);
2427 OSL_ENSURE(nWidth <= 0, "Wrong direction");
2428 while ( nWidth < 0 && nTouchedCol > 0 )
2429 {
2430 --nTouchedCol;
2431 nWidth += GetColWidth( nTouchedCol );
2432 }
2433 if ( nTouchedCol > nX2 )
2434 bHitOne = false;
2435 }
2436
2437 if (bHitOne)
2438 {
2439 while ( nArrY<nArrCount && pRowInfo[nArrY].nRowNo < nRow )
2440 ++nArrY;
2441 if ( nArrY<nArrCount && pRowInfo[nArrY].nRowNo == nRow )
2442 pRowInfo[nArrY].nRotMaxCol = nCol;
2443 }
2444 }
2445 }
2446 }
2447 }
2448
2449 return nArrY;
2450}
2451
2452void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2 )
2453{
2454 if ( !mpColWidth || !mpRowHeights || !mpColFlags || !pRowFlags )
2455 {
2456 OSL_FAIL( "Row/column info missing" );
2457 return;
2458 }
2459
2460 // nRotMaxCol is initialized to SC_ROTMAX_NONE, nRowNo is already set
2461
2462 SCROW nY1 = pRowInfo[0].nRowNo;
2463 SCROW nY2 = pRowInfo[nArrCount-1].nRowNo;
2464
2465 for (SCCOL nCol : GetColumnsRange(0, rDocument.MaxCol()))
2466 {
2467 if (!ColHidden(nCol))
2468 {
2469 SCSIZE nArrY = 0;
2470 ScDocAttrIterator aIter( rDocument, nTab, nCol, nY1, nCol, nY2 );
2471 SCCOL nAttrCol;
2472 SCROW nAttrRow1, nAttrRow2;
2473 const ScPatternAttr* pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
2474 while ( pPattern )
2475 {
2476 if ( const ScCondFormatItem* pCondItem = pPattern->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL ) )
2477 {
2478 // Run through all formats, so that each cell does not have to be
2479 // handled individually
2480
2481 const ScCondFormatIndexes& rCondFormatData = pCondItem->GetCondFormatData();
2483 if (mpCondFormatList && pStylePool && !rCondFormatData.empty())
2484 {
2485 for(const auto& rItem : rCondFormatData)
2486 {
2487 const ScConditionalFormat* pFormat = mpCondFormatList->GetFormat(rItem);
2488 if ( pFormat )
2489 {
2490 size_t nEntryCount = pFormat->size();
2491 for (size_t nEntry=0; nEntry<nEntryCount; nEntry++)
2492 {
2493 const ScFormatEntry* pEntry = pFormat->GetEntry(nEntry);
2494 if(pEntry->GetType() != ScFormatEntry::Type::Condition &&
2496 continue;
2497
2498 OUString aStyleName = static_cast<const ScCondFormatEntry*>(pEntry)->GetStyle();
2499 if (!aStyleName.isEmpty())
2500 {
2501 SfxStyleSheetBase* pStyleSheet =
2502 pStylePool->Find( aStyleName, SfxStyleFamily::Para );
2503 if ( pStyleSheet )
2504 {
2505 FillMaxRot( pRowInfo, nArrCount, nX1, nX2,
2506 nCol, nAttrRow1, nAttrRow2,
2507 nArrY, pPattern, &pStyleSheet->GetItemSet() );
2508 // not changing nArrY
2509 }
2510 }
2511 }
2512 }
2513 }
2514 }
2515 }
2516
2517 nArrY = FillMaxRot( pRowInfo, nArrCount, nX1, nX2,
2518 nCol, nAttrRow1, nAttrRow2,
2519 nArrY, pPattern, nullptr );
2520
2521 pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
2522 }
2523 }
2524 }
2525}
2526
2527bool ScTable::HasBlockMatrixFragment( const SCCOL nCol1, SCROW nRow1, const SCCOL nCol2, SCROW nRow2,
2528 bool bNoMatrixAtAll ) const
2529{
2530 using namespace sc;
2531
2532 if ( !IsColValid( nCol1 ) )
2533 return false;
2534
2535 const SCCOL nMaxCol2 = std::min<SCCOL>( nCol2, aCol.size() - 1 );
2536
2537 MatrixEdge nEdges = MatrixEdge::Nothing;
2538
2539 if ( nCol1 == nMaxCol2 )
2540 { // left and right column
2542 nEdges = aCol[nCol1].GetBlockMatrixEdges( nRow1, nRow2, n, bNoMatrixAtAll );
2543 if ((nEdges != MatrixEdge::Nothing) && (((nEdges & n)!=n) || (nEdges & (MatrixEdge::Inside|MatrixEdge::Open))))
2544 return true; // left or right edge is missing or open
2545 }
2546 else
2547 { // left column
2548 nEdges = aCol[nCol1].GetBlockMatrixEdges(nRow1, nRow2, MatrixEdge::Left, bNoMatrixAtAll);
2549 if ((nEdges != MatrixEdge::Nothing) && ((!(nEdges & MatrixEdge::Left)) || (nEdges & (MatrixEdge::Inside|MatrixEdge::Open))))
2550 return true; // left edge missing or open
2551 // right column
2552 nEdges = aCol[nMaxCol2].GetBlockMatrixEdges(nRow1, nRow2, MatrixEdge::Right, bNoMatrixAtAll);
2553 if ((nEdges != MatrixEdge::Nothing) && ((!(nEdges & MatrixEdge::Right)) || (nEdges & (MatrixEdge::Inside|MatrixEdge::Open))))
2554 return true; // right edge is missing or open
2555 }
2556
2557 if (bNoMatrixAtAll)
2558 {
2559 for (SCCOL i=nCol1; i<=nMaxCol2; i++)
2560 {
2561 nEdges = aCol[i].GetBlockMatrixEdges( nRow1, nRow2, MatrixEdge::Nothing, bNoMatrixAtAll);
2562 if (nEdges != MatrixEdge::Nothing
2563 && (nEdges != (MatrixEdge::Top | MatrixEdge::Left | MatrixEdge::Bottom | MatrixEdge::Right)))
2564 return true;
2565 }
2566 }
2567 else if ( nRow1 == nRow2 )
2568 { // Row on top and on bottom
2569 bool bOpen = false;
2570 const MatrixEdge n = MatrixEdge::Bottom | MatrixEdge::Top;
2571 for ( SCCOL i=nCol1; i<=nMaxCol2; i++)
2572 {
2573 nEdges = aCol[i].GetBlockMatrixEdges( nRow1, nRow1, n, bNoMatrixAtAll );
2574 if (nEdges != MatrixEdge::Nothing)
2575 {
2576 if ( (nEdges & n) != n )
2577 return true; // Top or bottom edge missing
2578 if (nEdges & MatrixEdge::Left)
2579 bOpen = true; // left edge open, continue
2580 else if ( !bOpen )
2581 return true; // Something exist that has not been opened
2582 if (nEdges & MatrixEdge::Right)
2583 bOpen = false; // Close right edge
2584 }
2585 }
2586 if ( bOpen )
2587 return true;
2588 }
2589 else
2590 {
2591 int j;
2592 MatrixEdge n;
2593 SCROW nR;
2594 // first top row, then bottom row
2595 for ( j=0, n = MatrixEdge::Top, nR=nRow1; j<2;
2596 j++, n = MatrixEdge::Bottom, nR=nRow2)
2597 {
2598 bool bOpen = false;
2599 for ( SCCOL i=nCol1; i<=nMaxCol2; i++)
2600 {
2601 nEdges = aCol[i].GetBlockMatrixEdges( nR, nR, n, bNoMatrixAtAll );
2602 if ( nEdges != MatrixEdge::Nothing)
2603 {
2604 // in top row no top edge respectively
2605 // in bottom row no bottom edge
2606 if ( (nEdges & n) != n )
2607 return true;
2608 if (nEdges & MatrixEdge::Left)
2609 bOpen = true; // open left edge, continue
2610 else if ( !bOpen )
2611 return true; // Something exist that has not been opened
2612 if (nEdges & MatrixEdge::Right)
2613 bOpen = false; // Close right edge
2614 }
2615 }
2616 if ( bOpen )
2617 return true;
2618 }
2619 }
2620 return false;
2621}
2622
2624{
2625 std::vector<sc::ColRowSpan> aSpans = rMark.GetMarkedColSpans();
2626 ScRangeList rangeList = rMark.GetMarkedRanges();
2627
2628 for (const sc::ColRowSpan & aSpan : aSpans)
2629 {
2630 SCCOL nEndCol = ClampToAllocatedColumns(aSpan.mnEnd);
2631 for ( SCCOLROW j=aSpan.mnStart; j<=nEndCol; j++ )
2632 {
2633 if ( aCol[j].HasSelectionMatrixFragment(rMark, rangeList) )
2634 return true;
2635 }
2636 }
2637 return false;
2638}
2639
2640bool ScTable::IsBlockEditable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2,
2641 SCROW nRow2, bool* pOnlyNotBecauseOfMatrix /* = NULL */,
2642 bool bNoMatrixAtAll ) const
2643{
2644 if ( !ValidColRow( nCol2, nRow2 ) )
2645 {
2646 SAL_WARN("sc", "IsBlockEditable: invalid column or row " << nCol2 << " " << nRow2);
2647 if (pOnlyNotBecauseOfMatrix)
2648 *pOnlyNotBecauseOfMatrix = false;
2649 return false;
2650 }
2651
2652 bool bIsEditable = true;
2653 if ( nLockCount )
2654 bIsEditable = false;
2655 else if ( IsProtected() && !rDocument.IsScenario(nTab) )
2656 {
2657 bIsEditable = !HasAttrib( nCol1, nRow1, nCol2, nRow2, HasAttrFlags::Protected );
2658 if (!bIsEditable)
2659 {
2660 // An enhanced protection permission may override the attribute.
2661 if (pTabProtection)
2662 bIsEditable = pTabProtection->isBlockEditable( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab));
2663 }
2664 if (bIsEditable)
2665 {
2666 // If Sheet is protected and cells are not protected then
2667 // check the active scenario protect flag if this range is
2668 // on the active scenario range. Note the 'copy back' must also
2669 // be set to apply protection.
2670 sal_uInt16 nScenTab = nTab+1;
2671 while(rDocument.IsScenario(nScenTab))
2672 {
2673 ScRange aEditRange(nCol1, nRow1, nScenTab, nCol2, nRow2, nScenTab);
2674 if(rDocument.IsActiveScenario(nScenTab) && rDocument.HasScenarioRange(nScenTab, aEditRange))
2675 {
2676 ScScenarioFlags nFlags;
2677 rDocument.GetScenarioFlags(nScenTab,nFlags);
2678 bIsEditable = !((nFlags & ScScenarioFlags::Protected) && (nFlags & ScScenarioFlags::TwoWay));
2679 break;
2680 }
2681 nScenTab++;
2682 }
2683 }
2684 }
2685 else if (rDocument.IsScenario(nTab))
2686 {
2687 // Determine if the preceding sheet is protected
2688 SCTAB nActualTab = nTab;
2689 do
2690 {
2691 nActualTab--;
2692 }
2693 while(rDocument.IsScenario(nActualTab));
2694
2695 if(rDocument.IsTabProtected(nActualTab))
2696 {
2697 ScRange aEditRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
2698 if(rDocument.HasScenarioRange(nTab, aEditRange))
2699 {
2700 ScScenarioFlags nFlags;
2702 bIsEditable = !(nFlags & ScScenarioFlags::Protected);
2703 }
2704 }
2705 }
2706 if ( bIsEditable )
2707 {
2708 if (HasBlockMatrixFragment( nCol1, nRow1, nCol2, nRow2, bNoMatrixAtAll))
2709 {
2710 bIsEditable = false;
2711 if ( pOnlyNotBecauseOfMatrix )
2712 *pOnlyNotBecauseOfMatrix = true;
2713 }
2714 else if ( pOnlyNotBecauseOfMatrix )
2715 *pOnlyNotBecauseOfMatrix = false;
2716 }
2717 else if ( pOnlyNotBecauseOfMatrix )
2718 *pOnlyNotBecauseOfMatrix = false;
2719 return bIsEditable;
2720}
2721
2723 bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
2724{
2725 bool bIsEditable = true;
2726 if ( nLockCount )
2727 bIsEditable = false;
2728 else if ( IsProtected() && !rDocument.IsScenario(nTab) )
2729 {
2730 ScRangeList aRanges;
2731 rMark.FillRangeListWithMarks( &aRanges, false );
2732 bIsEditable = !HasAttribSelection( rMark, HasAttrFlags::Protected );
2733 if (!bIsEditable)
2734 {
2735 // An enhanced protection permission may override the attribute.
2736 if (pTabProtection)
2737 bIsEditable = pTabProtection->isSelectionEditable( aRanges);
2738 }
2739 if (bIsEditable)
2740 {
2741 // If Sheet is protected and cells are not protected then
2742 // check the active scenario protect flag if this area is
2743 // in the active scenario range.
2744 SCTAB nScenTab = nTab+1;
2745 while(rDocument.IsScenario(nScenTab) && bIsEditable)
2746 {
2747 if(rDocument.IsActiveScenario(nScenTab))
2748 {
2749 for (size_t i=0, nRange = aRanges.size(); (i < nRange) && bIsEditable; i++ )
2750 {
2751 const ScRange & rRange = aRanges[ i ];
2752 if(rDocument.HasScenarioRange(nScenTab, rRange))
2753 {
2754 ScScenarioFlags nFlags;
2755 rDocument.GetScenarioFlags(nScenTab,nFlags);
2756 bIsEditable = !((nFlags & ScScenarioFlags::Protected) && (nFlags & ScScenarioFlags::TwoWay));
2757 }
2758 }
2759 }
2760 nScenTab++;
2761 }
2762 }
2763 }
2764 else if (rDocument.IsScenario(nTab))
2765 {
2766 // Determine if the preceding sheet is protected
2767 SCTAB nActualTab = nTab;
2768 do
2769 {
2770 nActualTab--;
2771 }
2772 while(rDocument.IsScenario(nActualTab));
2773
2774 if(rDocument.IsTabProtected(nActualTab))
2775 {
2776 ScRangeList aRanges;
2777 rMark.FillRangeListWithMarks( &aRanges, false );
2778 for (size_t i = 0, nRange = aRanges.size(); (i < nRange) && bIsEditable; i++)
2779 {
2780 const ScRange & rRange = aRanges[ i ];
2781 if(rDocument.HasScenarioRange(nTab, rRange))
2782 {
2783 ScScenarioFlags nFlags;
2785 bIsEditable = !(nFlags & ScScenarioFlags::Protected);
2786 }
2787 }
2788 }
2789 }
2790 if ( bIsEditable )
2791 {
2792 if ( HasSelectionMatrixFragment( rMark ) )
2793 {
2794 bIsEditable = false;
2795 if ( pOnlyNotBecauseOfMatrix )
2796 *pOnlyNotBecauseOfMatrix = true;
2797 }
2798 else if ( pOnlyNotBecauseOfMatrix )
2799 *pOnlyNotBecauseOfMatrix = false;
2800 }
2801 else if ( pOnlyNotBecauseOfMatrix )
2802 *pOnlyNotBecauseOfMatrix = false;
2803 return bIsEditable;
2804}
2805
2807{
2808 ++nLockCount;
2809}
2810
2812{
2813 if (nLockCount)
2814 --nLockCount;
2815 else
2816 {
2817 OSL_FAIL("UnlockTable without LockTable");
2818 }
2819}
2820
2821void ScTable::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
2822{
2823 std::vector<sc::ColRowSpan> aSpans = rMark.GetMarkedColSpans();
2824
2825 for (const sc::ColRowSpan & rSpan : aSpans)
2826 {
2827 SCCOL maxCol = ClampToAllocatedColumns(rSpan.mnEnd);
2828 for (SCCOL i = rSpan.mnStart; i <= maxCol; ++i)
2829 {
2830 aCol[i].MergeSelectionPattern( rState, rMark, bDeep );
2831 }
2832 }
2833}
2834
2836 SCCOL nCol2, SCROW nRow2, bool bDeep ) const
2837{
2838 const SCCOL nEndCol = ClampToAllocatedColumns(nCol2);
2839 for (SCCOL i=nCol1; i<=nEndCol; i++)
2840 aCol[i].MergePatternArea( rState, nRow1, nRow2, bDeep );
2841 if (nEndCol != nCol2)
2842 aDefaultColData.MergePatternArea( rState, nRow1, nRow2, bDeep );
2843}
2844
2845void ScTable::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, ScLineFlags& rFlags,
2846 SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const
2847{
2848 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
2849 {
2850 PutInOrder(nStartCol, nEndCol);
2851 PutInOrder(nStartRow, nEndRow);
2852 nEndCol = ClampToAllocatedColumns(nEndCol);
2853 for (SCCOL i=nStartCol; i<=nEndCol; i++)
2854 aCol[i].MergeBlockFrame( pLineOuter, pLineInner, rFlags,
2855 nStartRow, nEndRow, (i==nStartCol), nEndCol-i );
2856 }
2857}
2858
2859void ScTable::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
2860 SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow)
2861{
2862 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
2863 {
2864 PutInOrder(nStartCol, nEndCol);
2865 PutInOrder(nStartRow, nEndRow);
2866 CreateColumnIfNotExists(nEndCol);
2867 for (SCCOL i=nStartCol; i<=nEndCol; i++)
2868 aCol[i].ApplyBlockFrame(rLineOuter, pLineInner,
2869 nStartRow, nEndRow, (i==nStartCol), nEndCol-i);
2870 }
2871}
2872
2873void ScTable::ApplyPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr )
2874{
2875 if (ValidColRow(nCol,nRow))
2876 CreateColumnIfNotExists(nCol).ApplyPattern( nRow, rAttr );
2877}
2878
2879void ScTable::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2880 const ScPatternAttr& rAttr, ScEditDataArray* pDataArray,
2881 bool* const pIsChanged )
2882{
2883 if (!ValidColRow(nStartCol, nStartRow) || !ValidColRow(nEndCol, nEndRow))
2884 return;
2885 PutInOrder(nStartCol, nEndCol);
2886 PutInOrder(nStartRow, nEndRow);
2887 SCCOL maxCol = nEndCol;
2888 if( nEndCol == GetDoc().MaxCol())
2889 {
2890 // For the same unallocated columns until the end we can change just the default.
2891 maxCol = std::max( nStartCol, aCol.size()) - 1;
2892 if( maxCol >= 0 )
2893 CreateColumnIfNotExists(maxCol); // Allocate needed different columns before changing the default.
2894 aDefaultColData.ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
2895 }
2896 for (SCCOL i = nStartCol; i <= maxCol; i++)
2897 CreateColumnIfNotExists(i).ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
2898}
2899
2900namespace
2901{
2902 std::vector<ScAttrEntry> duplicateScAttrEntries(ScDocument& rDocument, const std::vector<ScAttrEntry>& rOrigData)
2903 {
2904 std::vector<ScAttrEntry> aData(rOrigData);
2905 for (size_t nIdx = 0; nIdx < aData.size(); ++nIdx)
2906 {
2907 ScPatternAttr aNewPattern(*aData[nIdx].pPattern);
2908 aData[nIdx].pPattern = &rDocument.GetPool()->Put(aNewPattern);
2909 }
2910 return aData;
2911 }
2912}
2913
2914void ScTable::SetAttrEntries( SCCOL nStartCol, SCCOL nEndCol, std::vector<ScAttrEntry> && vNewData)
2915{
2916 if (!ValidCol(nStartCol) || !ValidCol(nEndCol))
2917 return;
2918 if ( nEndCol == rDocument.MaxCol() )
2919 {
2920 if ( nStartCol < aCol.size() )
2921 {
2922 // If we would like set all columns to same attrs, then change only attrs for not existing columns
2923 nEndCol = aCol.size() - 1;
2924 for (SCCOL i = nStartCol; i <= nEndCol; i++)
2925 aCol[i].SetAttrEntries(duplicateScAttrEntries(rDocument, vNewData));
2926 aDefaultColData.SetAttrEntries(std::move(vNewData));
2927 }
2928 else
2929 {
2930 CreateColumnIfNotExists( nStartCol - 1 );
2931 aDefaultColData.SetAttrEntries(std::move(vNewData));
2932 }
2933 }
2934 else
2935 {
2936 CreateColumnIfNotExists( nEndCol );
2937 for (SCCOL i = nStartCol; i < nEndCol; i++) // all but last need a copy
2938 aCol[i].SetAttrEntries(duplicateScAttrEntries(rDocument, vNewData));
2939 aCol[nEndCol].SetAttrEntries( std::move(vNewData));
2940 }
2941}
2942
2943
2944
2946 const ScPatternAttr& rPattern, SvNumFormatType nNewType )
2947{
2948 SCCOL nEndCol = rRange.aEnd.Col();
2949 for ( SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; nCol++ )
2950 {
2951 aCol[nCol].ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
2952 }
2953}
2954
2955void ScTable::AddCondFormatData( const ScRangeList& rRangeList, sal_uInt32 nIndex )
2956{
2957 size_t n = rRangeList.size();
2958 for(size_t i = 0; i < n; ++i)
2959 {
2960 const ScRange & rRange = rRangeList[i];
2961 SCCOL nColStart = rRange.aStart.Col();
2962 SCCOL nColEnd = rRange.aEnd.Col();
2963 SCROW nRowStart = rRange.aStart.Row();
2964 SCROW nRowEnd = rRange.aEnd.Row();
2965 for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
2966 {
2967 CreateColumnIfNotExists(nCol).AddCondFormat(nRowStart, nRowEnd, nIndex);
2968 }
2969 }
2970}
2971
2972void ScTable::RemoveCondFormatData( const ScRangeList& rRangeList, sal_uInt32 nIndex )
2973{
2974 size_t n = rRangeList.size();
2975 for(size_t i = 0; i < n; ++i)
2976 {
2977 const ScRange & rRange = rRangeList[i];
2978 SCCOL nColStart = rRange.aStart.Col();
2979 SCCOL nColEnd = ClampToAllocatedColumns(rRange.aEnd.Col());
2980 SCROW nRowStart = rRange.aStart.Row();
2981 SCROW nRowEnd = rRange.aEnd.Row();
2982 for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
2983 {
2984 aCol[nCol].RemoveCondFormat(nRowStart, nRowEnd, nIndex);
2985 }
2986 }
2987}
2988
2990 const ScPatternAttr& rAttr, const ScCondFormatIndexes& rCondFormatIndexes )
2991{
2992 CreateColumnIfNotExists(nCol).SetPatternArea( nStartRow, nEndRow, rAttr);
2993
2994 for (const auto& rIndex : rCondFormatIndexes)
2995 {
2996 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
2997 if (pCondFormat)
2998 {
2999 ScRangeList aRange = pCondFormat->GetRange();
3000 aRange.Join( ScRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab));
3001 pCondFormat->SetRange(aRange);
3002 }
3003 }
3004}
3005
3006void ScTable::ApplyStyle( SCCOL nCol, SCROW nRow, const ScStyleSheet* rStyle )
3007{
3008 if (ValidColRow(nCol,nRow))
3009 // If column not exists then we need to create it
3010 CreateColumnIfNotExists( nCol ).ApplyStyle( nRow, rStyle );
3011}
3012
3013void ScTable::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScStyleSheet& rStyle )
3014{
3015 if (!(ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow)))
3016 return;
3017
3018 PutInOrder(nStartCol, nEndCol);
3019 PutInOrder(nStartRow, nEndRow);
3020 if ( nEndCol == rDocument.MaxCol() )
3021 {
3022 if ( nStartCol < aCol.size() )
3023 {
3024 // If we would like set all columns to specific style, then change only default style for not existing columns
3025 nEndCol = aCol.size() - 1;
3026 for (SCCOL i = nStartCol; i <= nEndCol; i++)
3027 aCol[i].ApplyStyleArea(nStartRow, nEndRow, rStyle);
3028 aDefaultColData.ApplyStyleArea(nStartRow, nEndRow, rStyle );
3029 }
3030 else
3031 {
3032 CreateColumnIfNotExists( nStartCol - 1 );
3033 aDefaultColData.ApplyStyleArea(nStartRow, nEndRow, rStyle );
3034 }
3035 }
3036 else
3037 {
3038 CreateColumnIfNotExists( nEndCol );
3039 for (SCCOL i = nStartCol; i <= nEndCol; i++)
3040 aCol[i].ApplyStyleArea(nStartRow, nEndRow, rStyle);
3041 }
3042}
3043
3045{
3046 for (SCCOL i=0; i < aCol.size(); i++)
3047 aCol[i].ApplySelectionStyle( rStyle, rMark );
3048}
3049
3051 const ::editeng::SvxBorderLine* pLine, bool bColorOnly )
3052{
3053 if ( bColorOnly && !pLine )
3054 return;
3055
3056 for (SCCOL i=0; i < aCol.size(); i++)
3057 aCol[i].ApplySelectionLineStyle( rMark, pLine, bColorOnly );
3058}
3059
3060const ScStyleSheet* ScTable::GetStyle( SCCOL nCol, SCROW nRow ) const
3061{
3062 if ( !ValidColRow( nCol, nRow ) )
3063 return nullptr;
3064 return ColumnData(nCol).GetStyle( nRow );
3065}
3066
3067const ScStyleSheet* ScTable::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
3068{
3069 rFound = false;
3070
3071 bool bEqual = true;
3072 bool bColFound;
3073
3074 const ScStyleSheet* pStyle = nullptr;
3075 const ScStyleSheet* pNewStyle;
3076
3077 for (SCCOL i=0; i < aCol.size() && bEqual; i++)
3078 if (rMark.HasMultiMarks(i))
3079 {
3080 pNewStyle = aCol[i].GetSelectionStyle( rMark, bColFound );
3081 if (bColFound)
3082 {
3083 rFound = true;
3084 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
3085 bEqual = false;
3086 pStyle = pNewStyle;
3087 }
3088 }
3089
3090 return bEqual ? pStyle : nullptr;
3091}
3092
3093const ScStyleSheet* ScTable::GetAreaStyle( bool& rFound, SCCOL nCol1, SCROW nRow1,
3094 SCCOL nCol2, SCROW nRow2 ) const
3095{
3096 rFound = false;
3097
3098 bool bEqual = true;
3099 bool bColFound;
3100
3101 const ScStyleSheet* pStyle = nullptr;
3102 const ScStyleSheet* pNewStyle;
3103 nCol2 = ClampToAllocatedColumns(nCol2);
3104 for (SCCOL i=nCol1; i<=nCol2 && bEqual; i++)
3105 {
3106 pNewStyle = aCol[i].GetAreaStyle(bColFound, nRow1, nRow2);
3107 if (bColFound)
3108 {
3109 rFound = true;
3110 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
3111 bEqual = false;
3112 pStyle = pNewStyle;
3113 }
3114 }
3115
3116 return bEqual ? pStyle : nullptr;
3117}
3118
3119bool ScTable::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
3120{
3121 bool bIsUsed = false;
3122
3123 for ( SCCOL i=0; i < aCol.size(); i++ )
3124 {
3125 if ( aCol[i].IsStyleSheetUsed( rStyle ) )
3126 {
3127 bIsUsed = true;
3128 }
3129 }
3130
3131 return bIsUsed;
3132}
3133
3134void ScTable::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, bool bRemoved,
3135 OutputDevice* pDev,
3136 double nPPTX, double nPPTY,
3137 const Fraction& rZoomX, const Fraction& rZoomY )
3138{
3140 for (SCCOL i = 0; i < aCol.size(); ++i)
3141 aCol[i].FindStyleSheet(pStyleSheet, aUsedRows, bRemoved);
3142
3143 sc::RowHeightContext aCxt(rDocument.MaxRow(), nPPTX, nPPTY, rZoomX, rZoomY, pDev);
3144 SCROW nRow = 0;
3145 while (nRow <= rDocument.MaxRow())
3146 {
3148 if (!aUsedRows.getRangeData(nRow, aData))
3149 // search failed!
3150 return;
3151
3152 SCROW nEndRow = aData.mnRow2;
3153 if (aData.mbValue)
3154 SetOptimalHeight(aCxt, nRow, nEndRow, true);
3155
3156 nRow = nEndRow + 1;
3157 }
3158}
3159
3160bool ScTable::ApplyFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
3161 ScMF nFlags )
3162{
3163 bool bChanged = false;
3164 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
3165 for (SCCOL i = nStartCol; i <= nEndCol; i++)
3166 bChanged |= CreateColumnIfNotExists(i).ApplyFlags(nStartRow, nEndRow, nFlags);
3167 return bChanged;
3168}
3169
3170bool ScTable::RemoveFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
3171 ScMF nFlags )
3172{
3173 if (!ValidColRow(nStartCol, nStartRow) || !ValidColRow(nEndCol, nEndRow))
3174 return false;
3175 bool bChanged = false;
3176 nEndCol = ClampToAllocatedColumns(nEndCol);
3177 for (SCCOL i = nStartCol; i <= nEndCol; i++)
3178 bChanged |= aCol[i].RemoveFlags(nStartRow, nEndRow, nFlags);
3179 return bChanged;
3180}
3181
3182void ScTable::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr )
3183{
3184 if (ValidColRow(rPos.Col(),rPos.Row()))
3185 CreateColumnIfNotExists(rPos.Col()).SetPattern(rPos.Row(), rAttr);
3186}
3187
3188const ScPatternAttr* ScTable::SetPattern( SCCOL nCol, SCROW nRow, std::unique_ptr<ScPatternAttr> pAttr )
3189{
3190 if (ValidColRow(nCol,nRow))
3191 return CreateColumnIfNotExists(nCol).SetPattern(nRow, std::move(pAttr));
3192 return nullptr;
3193}
3194
3195void ScTable::SetPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr )
3196{
3197 if (ValidColRow(nCol,nRow))
3198 CreateColumnIfNotExists(nCol).SetPattern(nRow, rAttr);
3199}
3200
3201void ScTable::ApplyAttr( SCCOL nCol, SCROW nRow, const SfxPoolItem& rAttr )
3202{
3203 if (ValidColRow(nCol,nRow))
3204 CreateColumnIfNotExists(nCol).ApplyAttr( nRow, rAttr );
3205}
3206
3208 ScEditDataArray* pDataArray, bool* const pIsChanged )
3209{
3210 if(!rMark.GetTableSelect(nTab))
3211 return;
3212 SCCOL lastChangeCol;
3213 if( rMark.GetArea().aEnd.Col() == GetDoc().MaxCol())
3214 {
3215 // For the same unallocated columns until the end we can change just the default.
3216 lastChangeCol = rMark.GetStartOfEqualColumns( GetDoc().MaxCol(), aCol.size()) - 1;
3217 if( lastChangeCol >= 0 )
3218 CreateColumnIfNotExists(lastChangeCol); // Allocate needed different columns before changing the default.
3219 aDefaultColData.ApplySelectionCache( pCache, rMark, pDataArray, pIsChanged, GetDoc().MaxCol());
3220 }
3221 else // need to allocate all columns affected
3222 {
3223 lastChangeCol = rMark.GetArea().aEnd.Col();
3224 CreateColumnIfNotExists(lastChangeCol);
3225 }
3226
3227 for (SCCOL i=0; i <= lastChangeCol; i++)
3228 aCol[i].ApplySelectionCache( pCache, rMark, pDataArray, pIsChanged );
3229}
3230
3231void ScTable::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
3232{
3233 if(!rMark.GetTableSelect(nTab))
3234 return;
3235 SCCOL lastChangeCol;
3236 if( rMark.GetArea().aEnd.Col() == GetDoc().MaxCol())
3237 {
3238 // For the same unallocated columns until the end we can change just the default.
3239 lastChangeCol = rMark.GetStartOfEqualColumns( GetDoc().MaxCol(), aCol.size()) - 1;
3240 if( lastChangeCol >= 0 )
3241 CreateColumnIfNotExists(lastChangeCol); // Allocate needed different columns before changing the default.
3242 aDefaultColData.ChangeSelectionIndent( bIncrement, rMark, GetDoc().MaxCol());
3243 }
3244 else
3245 {
3246 lastChangeCol = rMark.GetArea().aEnd.Col();
3247 CreateColumnIfNotExists(lastChangeCol);
3248 }
3249
3250 for (SCCOL i=0; i <= lastChangeCol; i++)
3251 aCol[i].ChangeSelectionIndent( bIncrement, rMark );
3252}
3253
3254void ScTable::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
3255{
3256 if(!rMark.GetTableSelect(nTab))
3257 return;
3258 SCCOL lastChangeCol;
3259 if( rMark.GetArea().aEnd.Col() == GetDoc().MaxCol())
3260 {
3261 // For the same unallocated columns until the end we can change just the default.
3262 lastChangeCol = rMark.GetStartOfEqualColumns( GetDoc().MaxCol(), aCol.size()) - 1;
3263 if( lastChangeCol >= 0 )
3264 CreateColumnIfNotExists(lastChangeCol); // Allocate needed different columns before changing the default.
3265 aDefaultColData.ClearSelectionItems( pWhich, rMark, GetDoc().MaxCol());
3266 }
3267 else
3268 {
3269 lastChangeCol = rMark.GetArea().aEnd.Col();
3270 CreateColumnIfNotExists(lastChangeCol);
3271 }
3272
3273 for (SCCOL i=0; i <= lastChangeCol; i++)
3274 aCol[i].ClearSelectionItems( pWhich, rMark );
3275}
3276
3277// Column widths / Row heights
3278
3279void ScTable::SetColWidth( SCCOL nCol, sal_uInt16 nNewWidth )
3280{
3281 if (ValidCol(nCol) && mpColWidth)
3282 {
3283 if (!nNewWidth)
3284 {
3285 nNewWidth = STD_COL_WIDTH;
3286 }
3287
3288 if ( nNewWidth != mpColWidth->GetValue(nCol) )
3289 {
3290 mpColWidth->SetValue(nCol, nNewWidth);
3292 }
3293 }
3294 else
3295 {
3296 OSL_FAIL("Invalid column number or no widths");
3297 }
3298}
3299
3300void ScTable::SetColWidthOnly( SCCOL nCol, sal_uInt16 nNewWidth )
3301{
3302 if (!ValidCol(nCol) || !mpColWidth)
3303 return;
3304
3305 if (!nNewWidth)
3306 nNewWidth = STD_COL_WIDTH;
3307
3308 if (nNewWidth != mpColWidth->GetValue(nCol))
3309 mpColWidth->SetValue(nCol, nNewWidth);
3310}
3311
3312void ScTable::SetRowHeight( SCROW nRow, sal_uInt16 nNewHeight )
3313{
3314 if (ValidRow(nRow) && mpRowHeights)
3315 {
3316 if (!nNewHeight)
3317 {
3318 OSL_FAIL("SetRowHeight: Row height zero");
3319 nNewHeight = ScGlobal::nStdRowHeight;
3320 }
3321
3322 sal_uInt16 nOldHeight = mpRowHeights->getValue(nRow);
3323 if ( nNewHeight != nOldHeight )
3324 {
3325 mpRowHeights->setValue(nRow, nRow, nNewHeight);
3327 }
3328 }
3329 else
3330 {
3331 OSL_FAIL("Invalid row number or no heights");
3332 }
3333}
3334
3335namespace {
3336
3341bool lcl_pixelSizeChanged(
3342 ScFlatUInt16RowSegments& rRowHeights, SCROW nStartRow, SCROW nEndRow,
3343 sal_uInt16 nNewHeight, double nPPTY, bool bApi)
3344{
3345 tools::Long nNewPix = static_cast<tools::Long>(nNewHeight * nPPTY);
3346
3347 ScFlatUInt16RowSegments::ForwardIterator aFwdIter(rRowHeights);
3348 for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
3349 {
3350 sal_uInt16 nHeight;
3351 if (!aFwdIter.getValue(nRow, nHeight))
3352 break;
3353
3354 if (nHeight != nNewHeight)
3355 {
3356 tools::Long nOldPix = static_cast<tools::Long>(nHeight * nPPTY);
3357
3358 // Heuristic: Don't bother when handling interactive input, if changing just one row and
3359 // the height will shrink.
3360 bool bChanged = (nNewPix != nOldPix) && (bApi || nEndRow - nStartRow > 0 || nNewPix > nOldPix);
3361 if (bChanged)
3362 return true;
3363 }
3364
3365 // Skip ahead to the last position of the current range.
3366 nRow = aFwdIter.getLastPos();
3367 }
3368 return false;
3369}
3370
3371}
3372
3373bool ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nNewHeight,
3374 double nPPTY, bool bApi )
3375{
3376 bool bChanged = false;
3377 if (ValidRow(nStartRow) && ValidRow(nEndRow) && mpRowHeights)
3378 {
3379 if (!nNewHeight)
3380 {
3381 OSL_FAIL("SetRowHeight: Row height zero");
3382 nNewHeight = ScGlobal::nStdRowHeight;
3383 }
3384
3385 bool bSingle = false; // true = process every row for its own
3386 ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
3387 if (pDrawLayer)
3388 if (pDrawLayer->HasObjectsInRows( nTab, nStartRow, nEndRow ))
3389 bSingle = true;
3390
3391 if (bSingle)
3392 {
3394 if (mpRowHeights->getRangeData(nStartRow, aData) &&
3395 nNewHeight == aData.mnValue && nEndRow <= aData.mnRow2)
3396 {
3397 bSingle = false; // no difference in this range
3398 }
3399 }
3400
3401 // No idea why 20 is used here
3402 if (!bSingle || nEndRow - nStartRow < 20)
3403 {
3404 bChanged = lcl_pixelSizeChanged(*mpRowHeights, nStartRow, nEndRow, nNewHeight, nPPTY, bApi);
3405 if (bChanged)
3406 mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
3407 }
3408 else
3409 {
3410 SCROW nMid = (nStartRow + nEndRow) / 2;
3411 // No idea why nPPTY is ignored in these recursive calls and instead 1.0 is used
3412 if (SetRowHeightRange(nStartRow, nMid, nNewHeight, 1.0, bApi))
3413 bChanged = true;
3414 if (SetRowHeightRange(nMid + 1, nEndRow, nNewHeight, 1.0, bApi))
3415 bChanged = true;
3416 }
3417
3418 if (bChanged)
3420 }
3421 else
3422 {
3423 OSL_FAIL("Invalid row number or no heights");
3424 }
3425
3426 return bChanged;
3427}
3428
3429void ScTable::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nNewHeight )
3430{
3431 if (!ValidRow(nStartRow) || !ValidRow(nEndRow) || !mpRowHeights)
3432 return;
3433
3434 if (!nNewHeight)
3435 nNewHeight = ScGlobal::nStdRowHeight;
3436
3437 mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
3438}
3439
3440void ScTable::SetManualHeight( SCROW nStartRow, SCROW nEndRow, bool bManual )
3441{
3442 if (ValidRow(nStartRow) && ValidRow(nEndRow) && pRowFlags)
3443 {
3444 if (bManual)
3445 pRowFlags->OrValue( nStartRow, nEndRow, CRFlags::ManualSize);
3446 else
3447 pRowFlags->AndValue( nStartRow, nEndRow, ~CRFlags::ManualSize);
3448 }
3449 else
3450 {
3451 OSL_FAIL("Invalid row number or no column flags");
3452 }
3453}
3454
3455sal_uInt16 ScTable::GetColWidth( SCCOL nCol, bool bHiddenAsZero ) const
3456{
3457 OSL_ENSURE(ValidCol(nCol),"wrong column number");
3458
3459 if (ValidCol(nCol) && mpColFlags && mpColWidth)
3460 {
3461 if (bHiddenAsZero && ColHidden(nCol))
3462 return 0;
3463 else
3464 return mpColWidth->GetValue(nCol);
3465 }
3466 else
3467 return sal_uInt16(STD_COL_WIDTH);
3468}
3469
3470tools::Long ScTable::GetColWidth( SCCOL nStartCol, SCCOL nEndCol ) const
3471{
3472 if (!ValidCol(nStartCol) || !ValidCol(nEndCol) || nStartCol > nEndCol)
3473 return 0;
3474
3475 tools::Long nW = 0;
3476 bool bHidden = false;
3477 SCCOL nLastHiddenCol = -1;
3478 auto colWidthIt = mpColWidth->begin() + nStartCol;
3479 for (SCCOL nCol = nStartCol; nCol <= nEndCol; (++nCol <= nEndCol) ? ++colWidthIt : (void)false)
3480 {
3481 if (nCol > nLastHiddenCol)
3482 bHidden = ColHidden(nCol, nullptr, &nLastHiddenCol);
3483
3484 if (bHidden)
3485 continue;
3486
3487 nW += *colWidthIt;
3488 }
3489 return nW;
3490}
3491
3492sal_uInt16 ScTable::GetOriginalWidth( SCCOL nCol ) const // always the set value
3493{
3494 OSL_ENSURE(ValidCol(nCol),"wrong column number");
3495
3496 if (ValidCol(nCol) && mpColWidth)
3497 return mpColWidth->GetValue(nCol);
3498 else
3499 return sal_uInt16(STD_COL_WIDTH);
3500}
3501
3502sal_uInt16 ScTable::GetCommonWidth( SCCOL nEndCol ) const
3503{
3504 // get the width that is used in the largest continuous column range (up to nEndCol)
3505
3506 if ( !ValidCol(nEndCol) )
3507 {
3508 OSL_FAIL("wrong column");
3509 nEndCol = rDocument.MaxCol();
3510 }
3511
3512 sal_uInt16 nMaxWidth = 0;
3513 sal_uInt16 nMaxCount = 0;
3514 SCCOL nRangeStart = 0;
3515 while ( nRangeStart <= nEndCol )
3516 {
3517 // skip hidden columns
3518 while ( nRangeStart <= nEndCol && ColHidden(nRangeStart) )
3519 ++nRangeStart;
3520 if ( nRangeStart <= nEndCol )
3521 {
3522 sal_uInt16 nThisCount = 0;
3523 auto colWidthIt = mpColWidth->begin() + nRangeStart;
3524 sal_uInt16 nThisWidth = *colWidthIt;
3525 SCCOL nRangeEnd = nRangeStart;
3526 while ( nRangeEnd <= nEndCol && *colWidthIt == nThisWidth )
3527 {
3528 ++nThisCount;
3529 ++nRangeEnd;
3530 ++colWidthIt;
3531
3532 // skip hidden columns
3533 while ( nRangeEnd <= nEndCol && ColHidden(nRangeEnd) )
3534 {
3535 ++nRangeEnd;
3536 ++colWidthIt;
3537 }
3538 }
3539
3540 if ( nThisCount > nMaxCount )
3541 {
3542 nMaxCount = nThisCount;
3543 nMaxWidth = nThisWidth;
3544 }
3545
3546 nRangeStart = nRangeEnd; // next range
3547 }
3548 }
3549
3550 return nMaxWidth;
3551}
3552
3553sal_uInt16 ScTable::GetRowHeight( SCROW nRow, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
3554{
3555 SAL_WARN_IF(!ValidRow(nRow), "sc", "Invalid row number " << nRow);
3556
3557 if (ValidRow(nRow) && mpRowHeights)
3558 {
3559 if (bHiddenAsZero && RowHidden( nRow, pStartRow, pEndRow))
3560 return 0;
3561 else
3562 {
3564 if (!mpRowHeights->getRangeData(nRow, aData))
3565 {
3566 if (pStartRow)
3567 *pStartRow = nRow;
3568 if (pEndRow)
3569 *pEndRow = nRow;
3570 // TODO: What should we return in case the search fails?
3571 return 0;
3572 }
3573
3574 // If bHiddenAsZero, pStartRow and pEndRow were initialized to
3575 // boundaries of a non-hidden segment. Assume that the previous and
3576 // next segment are hidden then and limit the current height
3577 // segment.
3578 if (pStartRow)
3579 *pStartRow = (bHiddenAsZero ? std::max( *pStartRow, aData.mnRow1) : aData.mnRow1);
3580 if (pEndRow)
3581 *pEndRow = (bHiddenAsZero ? std::min( *pEndRow, aData.mnRow2) : aData.mnRow2);
3582 return aData.mnValue;
3583 }
3584 }
3585 else
3586 {
3587 if (pStartRow)
3588 *pStartRow = nRow;
3589 if (pEndRow)
3590 *pEndRow = nRow;
3592 }
3593}
3594
3595tools::Long ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow, bool bHiddenAsZero ) const
3596{
3597 OSL_ENSURE(ValidRow(nStartRow) && ValidRow(nEndRow),"wrong row number");
3598
3599 if (ValidRow(nStartRow) && ValidRow(nEndRow) && mpRowHeights)
3600 {
3601 tools::Long nHeight = 0;
3602 SCROW nRow = nStartRow;
3603 while (nRow <= nEndRow)
3604 {
3605 SCROW nLastRow = -1;
3606 if (!( ( RowHidden(nRow, nullptr, &nLastRow) ) && bHiddenAsZero ) )
3607 {
3608 if (nLastRow > nEndRow)
3609 nLastRow = nEndRow;
3610 nHeight += mpRowHeights->getSumValue(nRow, nLastRow);
3611 }
3612 nRow = nLastRow + 1;
3613 }
3614 return nHeight;
3615 }
3616 else
3617 return (nEndRow - nStartRow + 1) * static_cast<tools::Long>(ScGlobal::nStdRowHeight);
3618}
3619
3620tools::Long ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale ) const
3621{
3622 OSL_ENSURE(ValidRow(nStartRow) && ValidRow(nEndRow),"wrong row number");
3623
3624 if (ValidRow(nStartRow) && ValidRow(nEndRow) && mpRowHeights)
3625 {
3626 tools::Long nHeight = 0;
3627 SCROW nRow = nStartRow;
3628 while (nRow <= nEndRow)
3629 {
3630 SCROW nLastRow = -1;
3631 if (!RowHidden(nRow, nullptr, &nLastRow))
3632 {
3633 if (nLastRow > nEndRow)
3634 nLastRow = nEndRow;
3635
3636 // #i117315# can't use getSumValue, because individual values must be rounded
3638 while (nRow <= nLastRow)
3639 {
3640 sal_uInt16 nRowVal;
3641 if (!aSegmentIter.getValue(nRow, nRowVal))
3642 return nHeight; // shouldn't happen
3643
3644 SCROW nSegmentEnd = std::min( nLastRow, aSegmentIter.getLastPos() );
3645
3646 // round-down a single height value, multiply resulting (pixel) values
3647 tools::Long nOneHeight = static_cast<tools::Long>( nRowVal * fScale );
3648 nHeight += nOneHeight * ( nSegmentEnd + 1 - nRow );
3649
3650 nRow = nSegmentEnd + 1;
3651 }
3652 }
3653 nRow = nLastRow + 1;
3654 }
3655 return nHeight;
3656 }
3657 else
3658 return static_cast<tools::Long>((nEndRow - nStartRow + 1) * ScGlobal::nStdRowHeight * fScale);
3659}
3660
3661sal_uInt16 ScTable::GetOriginalHeight( SCROW nRow ) const // non-0 even if hidden
3662{
3663 OSL_ENSURE(ValidRow(nRow),"wrong row number");
3664
3665 if (ValidRow(nRow) && mpRowHeights)
3666 return mpRowHeights->getValue(nRow);
3667 else
3669}
3670
3671// Column/Row -Flags
3672
3674{
3675 if (!ValidRow(nRow))
3676 return 0;
3677
3678 SCROW nLastRow = -1;
3679 if (!RowHidden(nRow, nullptr, &nLastRow) || !ValidRow(nLastRow))
3680 return 0;
3681
3682 return nLastRow - nRow + 1;
3683}
3684
3685//TODO: combine ShowRows / DBShowRows
3686
3687void ScTable::ShowCol(SCCOL nCol, bool bShow)
3688{
3689 if (ValidCol(nCol))
3690 {
3691 bool bWasVis = !ColHidden(nCol);
3692 if (bWasVis != bShow)
3693 {
3694 SetColHidden(nCol, nCol, !bShow);
3695
3697 if ( pCharts )
3698 pCharts->SetRangeDirty(ScRange( nCol, 0, nTab, nCol, rDocument.MaxRow(), nTab ));
3699 }
3700 }
3701 else
3702 {
3703 OSL_FAIL("Invalid column number or no flags");
3704 }
3705}
3706
3707void ScTable::ShowRow(SCROW nRow, bool bShow)
3708{
3709 if (ValidRow(nRow) && pRowFlags)
3710 {
3711 bool bWasVis = !RowHidden(nRow);
3712 if (bWasVis != bShow)
3713 {
3714 SetRowHidden(nRow, nRow, !bShow);
3715 if (bShow)
3716 SetRowFiltered(nRow, nRow, false);
3718 if ( pCharts )
3719 pCharts->SetRangeDirty(ScRange( 0, nRow, nTab, rDocument.MaxCol(), nRow, nTab ));
3720
3722 }
3723 }
3724 else
3725 {
3726 OSL_FAIL("Invalid row number or no flags");
3727 }
3728}
3729
3730void ScTable::DBShowRow(SCROW nRow, bool bShow)
3731{
3732 if (ValidRow(nRow) && pRowFlags)
3733 {
3734 // Always set filter flag; unchanged when Hidden
3735 bool bChanged = SetRowHidden(nRow, nRow, !bShow);
3736 SetRowFiltered(nRow, nRow, !bShow);
3737
3738 if (bChanged)
3739 {
3741 if ( pCharts )
3742 pCharts->SetRangeDirty(ScRange( 0, nRow, nTab, rDocument.MaxCol(), nRow, nTab ));
3743
3744 if (pOutlineTable)
3745 UpdateOutlineRow( nRow, nRow, bShow );
3746
3748 }
3749 }
3750 else
3751 {
3752 OSL_FAIL("Invalid row number or no flags");
3753 }
3754}
3755
3756void ScTable::DBShowRows(SCROW nRow1, SCROW nRow2, bool bShow)
3757{
3758 SCROW nStartRow = nRow1;
3759 while (nStartRow <= nRow2)
3760 {
3761 SCROW nEndRow = -1;
3762 bool bWasVis = !RowHiddenLeaf(nStartRow, nullptr, &nEndRow);
3763 if (nEndRow > nRow2)
3764 nEndRow = nRow2;
3765
3766 bool bChanged = ( bWasVis != bShow );
3767
3768 SetRowHidden(nStartRow, nEndRow, !bShow);
3769 SetRowFiltered(nStartRow, nEndRow, !bShow);
3770
3771 if ( bChanged )
3772 {
3774 if ( pCharts )
3775 pCharts->SetRangeDirty(ScRange( 0, nStartRow, nTab, rDocument.MaxCol(), nEndRow, nTab ));
3776 }
3777
3778 nStartRow = nEndRow + 1;
3779 }
3780
3781 // #i12341# For Show/Hide rows, the outlines are updated separately from the outside.
3782 // For filtering, the changes aren't visible to the caller, so UpdateOutlineRow has
3783 // to be done here.
3784 if (pOutlineTable)
3785 UpdateOutlineRow( nRow1, nRow2, bShow );
3786}
3787
3788void ScTable::ShowRows(SCROW nRow1, SCROW nRow2, bool bShow)
3789{
3790 SCROW nStartRow = nRow1;
3791
3792 // #i116164# if there are no drawing objects within the row range, a single HeightChanged call is enough
3793 ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
3794 bool bHasObjects = pDrawLayer && pDrawLayer->HasObjectsInRows( nTab, nRow1, nRow2 );
3795
3796 while (nStartRow <= nRow2)
3797 {
3798 SCROW nEndRow = -1;
3799 bool bWasVis = !RowHiddenLeaf(nStartRow, nullptr, &nEndRow);
3800 if (nEndRow > nRow2)
3801 nEndRow = nRow2;
3802
3803 bool bChanged = ( bWasVis != bShow );
3804
3805 SetRowHidden(nStartRow, nEndRow, !bShow);
3806 if (bShow)
3807 SetRowFiltered(nStartRow, nEndRow, false);
3808
3809 if ( bChanged )
3810 {
3812 if ( pCharts )
3813 pCharts->SetRangeDirty(ScRange( 0, nStartRow, nTab, rDocument.MaxCol(), nEndRow, nTab ));
3814
3816 }
3817
3818 nStartRow = nEndRow + 1;
3819 }
3820
3821 if ( !bHasObjects )
3822 {
3823 // #i116164# set the flags for the whole range at once
3824 SetRowHidden(nRow1, nRow2, !bShow);
3825 if (bShow)
3826 SetRowFiltered(nRow1, nRow2, false);
3827 }
3828}
3829
3830bool ScTable::IsDataFiltered(SCCOL nColStart, SCROW nRowStart, SCCOL nColEnd, SCROW nRowEnd) const
3831{
3832 assert(nColStart <= nColEnd && nRowStart <= nRowEnd
3833 && "range must be normalized to obtain a valid result");
3834 for (SCROW i = nRowStart; i <= nRowEnd; ++i)
3835 {
3836 if (RowHidden(i))
3837 return true;
3838 }
3839 for (SCCOL i = nColStart; i <= nColEnd; ++i)
3840 {
3841 if (ColHidden(i))
3842 return true;
3843 }
3844 return false;
3845}
3846
3847bool ScTable::IsDataFiltered(const ScRange& rRange) const
3848{
3849 ScRange aNormalized(rRange.aStart, rRange.aEnd);
3850 return IsDataFiltered(aNormalized.aStart.Col(), aNormalized.aStart.Row(),
3851 aNormalized.aEnd.Col(), aNormalized.aEnd.Row());
3852}
3853
3854void ScTable::SetRowFlags( SCROW nRow, CRFlags nNewFlags )
3855{
3856 if (ValidRow(nRow) && pRowFlags)
3857 pRowFlags->SetValue( nRow, nNewFlags);
3858 else
3859 {
3860 OSL_FAIL("Invalid row number or no flags");
3861 }
3862}
3863
3864void ScTable::SetRowFlags( SCROW nStartRow, SCROW nEndRow, CRFlags nNewFlags )
3865{
3866 if (ValidRow(nStartRow) && ValidRow(nEndRow) && pRowFlags)
3867 pRowFlags->SetValue( nStartRow, nEndRow, nNewFlags);
3868 else
3869 {
3870 OSL_FAIL("Invalid row number(s) or no flags");
3871 }
3872}
3873
3875{
3876 if (ValidCol(nCol) && mpColFlags)
3877 return mpColFlags->GetValue(nCol);
3878 else
3879 return CRFlags::NONE;
3880}
3881
3883{
3884 if (ValidRow(nRow) && pRowFlags)
3885 return pRowFlags->GetValue(nRow);
3886 else
3887 return CRFlags::NONE;
3888}
3889
3891{
3892 SCROW nLastFound = 0;
3893 if (pRowFlags)
3894 {
3895 SCROW nRow = pRowFlags->GetLastAnyBitAccess( CRFlags::All );
3896 if (ValidRow(nRow))
3897 nLastFound = nRow;
3898 }
3899
3900 if (!maRowManualBreaks.empty())
3901 nLastFound = ::std::max(nLastFound, *maRowManualBreaks.rbegin());
3902
3903 if (mpHiddenRows)
3904 {
3905 SCROW nRow = mpHiddenRows->findLastTrue();
3906 if (ValidRow(nRow))
3907 nLastFound = ::std::max(nLastFound, nRow);
3908 }
3909
3910 if (mpFilteredRows)
3911 {
3912 SCROW nRow = mpFilteredRows->findLastTrue();
3913 if (ValidRow(nRow))
3914 nLastFound = ::std::max(nLastFound, nRow);
3915 }
3916
3917 return nLastFound;
3918}
3919
3921{
3922 if ( !mpColFlags )
3923 return 0;
3924
3925 SCCOL nLastFound = 0;
3926 auto colWidthIt = mpColWidth->begin() + 1;
3927 for (SCCOL nCol = 1; nCol <= GetDoc().MaxCol(); (++nCol <= GetDoc().MaxCol()) ? ++colWidthIt : (void)false)
3928 if ((mpColFlags->GetValue(nCol) & CRFlags::All) || (*colWidthIt != STD_COL_WIDTH))
3929 nLastFound = nCol;
3930
3931 return nLastFound;
3932}
3933
3935{
3936 if ( !pRowFlags )
3937 return 0;
3938
3939 SCROW nLastFlags = GetLastFlaggedRow();
3940
3941 // Find the last row position where the height is NOT the standard row
3942 // height.
3943 // KOHEI: Test this to make sure it does what it's supposed to.
3944 SCROW nLastHeight = mpRowHeights->findLastTrue(ScGlobal::nStdRowHeight);
3945 if (!ValidRow(nLastHeight))
3946 nLastHeight = 0;
3947
3948 return std::max( nLastFlags, nLastHeight);
3949}
3950
3951bool ScTable::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, bool bShow )
3952{
3954 {
3955 return pOutlineTable->GetColArray().ManualAction( nStartCol, nEndCol, bShow, *this, true );
3956 }
3957 else
3958 return false;
3959}
3960
3961bool ScTable::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, bool bShow )
3962{
3963 if (pOutlineTable && pRowFlags)
3964 return pOutlineTable->GetRowArray().ManualAction( nStartRow, nEndRow, bShow, *this, false );
3965 else
3966 return false;
3967}
3968
3969void ScTable::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
3970{
3971 // Column-wise expansion
3972
3973 while (rX1 > 0 && ColHidden(rX1-1))
3974 --rX1;
3975
3976 while (rX2 < rDocument.MaxCol() && ColHidden(rX2+1))
3977 ++rX2;
3978
3979 // Row-wise expansion
3980
3981 if (rY1 > 0)
3982 {
3984 if (mpHiddenRows->getRangeData(rY1-1, aData) && aData.mbValue)
3985 {
3986 SCROW nStartRow = aData.mnRow1;
3987 if (ValidRow(nStartRow))
3988 rY1 = nStartRow;
3989 }
3990 }
3991 if (rY2 < rDocument.MaxRow())
3992 {
3993 SCROW nEndRow = -1;
3994 if (RowHidden(rY2+1, nullptr, &nEndRow) && ValidRow(nEndRow))
3995 rY2 = nEndRow;
3996 }
3997}
3998
3999void ScTable::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
4000{
4001 while ( rX2>rX1 && ColHidden(rX2) )
4002 --rX2;
4003 while ( rX2>rX1 && ColHidden(rX1) )
4004 ++rX1;
4005
4006 if (rY1 < rY2)
4007 {
4009 if (mpHiddenRows->getRangeData(rY2, aData) && aData.mbValue)
4010 {
4011 SCROW nStartRow = aData.mnRow1;
4012 if (ValidRow(nStartRow) && nStartRow >= rY1)
4013 rY2 = nStartRow;
4014 }
4015 }
4016
4017 if (rY1 < rY2)
4018 {
4019 SCROW nEndRow = -1;
4020 if (RowHidden(rY1, nullptr, &nEndRow) && ValidRow(nEndRow) && nEndRow <= rY2)
4021 rY1 = nEndRow;
4022 }
4023}
4024
4025// Auto-Outline
4026
4027template< typename T >
4028static short DiffSign( T a, T b )
4029{
4030 return (a<b) ? -1 :
4031 (a>b) ? 1 : 0;
4032}
4033
4034namespace {
4035
4036class OutlineArrayFinder
4037{
4038 ScRange maRef;
4039 SCCOL mnCol;
4040 SCTAB mnTab;
4042 bool mbSizeChanged;
4043
4044public:
4045 OutlineArrayFinder(const ScRange& rRef, SCCOL nCol, SCTAB nTab, ScOutlineArray* pArray, bool bSizeChanged) :
4046 maRef(rRef), mnCol(nCol), mnTab(nTab), mpArray(pArray),
4047 mbSizeChanged(bSizeChanged) {}
4048
4049 bool operator() (size_t nRow, const ScFormulaCell* pCell)
4050 {
4051 SCROW nRow2 = static_cast<SCROW>(nRow);
4052
4053 if (!pCell->HasRefListExpressibleAsOneReference(maRef))
4054 return false;
4055
4056 if (maRef.aStart.Row() != nRow2 || maRef.aEnd.Row() != nRow2 ||
4057 maRef.aStart.Tab() != mnTab || maRef.aEnd.Tab() != mnTab)
4058 return false;
4059
4060 if (DiffSign(maRef.aStart.Col(), mnCol) != DiffSign(maRef.aEnd.Col(), mnCol))
4061 return false;
4062
4063 return mpArray->Insert(maRef.aStart.Col(), maRef.aEnd.Col(), mbSizeChanged);
4064 }
4065};
4066
4067}
4068
4069void ScTable::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
4070{
4071 typedef mdds::flat_segment_tree<SCROW, bool> UsedRowsType;
4072
4073 bool bSizeChanged = false;
4074
4075 SCCOL nCol;
4076 SCROW nRow;
4077 bool bFound;
4078 ScRange aRef;
4079
4080 nEndCol = ClampToAllocatedColumns(nEndCol);
4081
4083
4084 // Rows
4085
4086 UsedRowsType aUsed(0, rDocument.MaxRow()+1, false);
4087 for (nCol=nStartCol; nCol<=nEndCol; nCol++)
4088 aCol[nCol].FindUsed(nStartRow, nEndRow, aUsed);
4089 aUsed.build_tree();
4090
4091 ScOutlineArray& rRowArray = pOutlineTable->GetRowArray();
4092 for (nRow=nStartRow; nRow<=nEndRow; nRow++)
4093 {
4094 bool bUsed = false;
4095 SCROW nLastRow = nRow;
4096 aUsed.search_tree(nRow, bUsed, nullptr, &nLastRow);
4097 if (!bUsed)
4098 {
4099 nRow = nLastRow;
4100 continue;
4101 }
4102
4103 bFound = false;
4104 for (nCol=nStartCol; nCol<=nEndCol && !bFound; nCol++)
4105 {
4106 ScRefCellValue aCell = aCol[nCol].GetCellValue(nRow);
4107
4108 if (aCell.getType() != CELLTYPE_FORMULA)
4109 continue;
4110
4112 continue;
4113
4114 if ( aRef.aStart.Col() == nCol && aRef.aEnd.Col() == nCol &&
4115 aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab &&
4116 DiffSign( aRef.aStart.Row(), nRow ) ==
4117 DiffSign( aRef.aEnd.Row(), nRow ) )
4118 {
4119 if (rRowArray.Insert( aRef.aStart.Row(), aRef.aEnd.Row(), bSizeChanged ))
4120 {
4121 bFound = true;
4122 }
4123 }
4124 }
4125 }
4126
4127 // Column
4128 ScOutlineArray& rColArray = pOutlineTable->GetColArray();
4129 for (nCol=nStartCol; nCol<=nEndCol; nCol++)
4130 {
4131 if (aCol[nCol].IsEmptyData())
4132 continue;
4133
4134 OutlineArrayFinder aFunc(aRef, nCol, nTab, &rColArray, bSizeChanged);
4135 sc::FindFormula(aCol[nCol].maCells, nStartRow, nEndRow, aFunc);
4136 }
4137}
4138
4139 // CopyData - for Query in other range
4140
4141void ScTable::CopyData( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
4142 SCCOL nDestCol, SCROW nDestRow, SCTAB nDestTab )
4143{
4144 //TODO: if used for multiple rows, optimize after columns!
4145
4146 ScAddress aSrc( nStartCol, nStartRow, nTab );
4147 ScAddress aDest( nDestCol, nDestRow, nDestTab );
4148 ScRange aRange( aSrc, aDest );
4149 bool bThisTab = ( nDestTab == nTab );
4150 SCROW nDestY = nDestRow;
4151 for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
4152 {
4153 aSrc.SetRow( nRow );
4154 aDest.SetRow( nDestY );
4155 SCCOL nDestX = nDestCol;
4156 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
4157 {
4158 aSrc.SetCol( nCol );
4159 aDest.SetCol( nDestX );
4160 ScCellValue aCell;
4161 aCell.assign(rDocument, ScAddress(nCol, nRow, nTab));
4162
4163 if (aCell.getType() == CELLTYPE_FORMULA)
4164 {
4166 aCxt.meMode = URM_COPY;
4167 aCxt.maRange = aRange;
4168 aCxt.mnColDelta = nDestCol - nStartCol;
4169 aCxt.mnRowDelta = nDestRow - nStartRow;
4170 aCxt.mnTabDelta = nDestTab - nTab;
4171 aCell.getFormula()->UpdateReference(aCxt);
4172 aCell.getFormula()->aPos = aDest;
4173 }
4174
4175 if (bThisTab)
4176 {
4177 aCell.release(CreateColumnIfNotExists(nDestX), nDestY);
4178 SetPattern( nDestX, nDestY, *GetPattern( nCol, nRow ) );
4179 }
4180 else
4181 {
4182 aCell.release(rDocument, aDest);
4183 rDocument.SetPattern( aDest, *GetPattern( nCol, nRow ) );
4184 }
4185
4186 ++nDestX;
4187 }
4188 ++nDestY;
4189 }
4190}
4191
4193{
4194 ScRange aRef;
4195
4196 if (pCell->HasOneReference(aRef))
4197 {
4198 if (aRef.aStart.Col()==aRef.aEnd.Col() && aRef.aStart.Tab()==aRef.aEnd.Tab())
4199 {
4200 SCROW nEndRow;
4201 if (!RowFiltered(aRef.aStart.Row(), nullptr, &nEndRow))
4202 // row not filtered.
4203 nEndRow = ::std::numeric_limits<SCROW>::max();
4204
4205 if (!ValidRow(nEndRow) || nEndRow < aRef.aEnd.Row())
4206 return true; // at least partly visible
4207 return false; // completely invisible
4208 }
4209 }
4210
4211 return true; // somehow different
4212}
4213
4215{
4216 return ScGlobal::getCharClass().uppercase(GetInputString(nCol, nRow).trim());
4217}
4218
4219// Calculate the size of the sheet and set the size on DrawPage
4220
4221void ScTable::SetDrawPageSize(bool bResetStreamValid, bool bUpdateNoteCaptionPos,
4222 ScObjectHandling eObjectHandling)
4223{
4224 ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
4225 if( pDrawLayer )
4226 {
4227 const sal_Int64 nMax = ::std::numeric_limits<tools::Long>::max();
4228 // #i113884# Avoid int32 overflow with possible negative results than can cause bad effects.
4229 // If the draw page size is smaller than all rows, only the bottom of the sheet is affected.
4232 nMax);
4235 nMax);
4236
4237 if ( IsLayoutRTL() ) // IsNegativePage
4238 x = -x;
4239
4240 pDrawLayer->SetPageSize(static_cast<sal_uInt16>(nTab), Size(x, y), bUpdateNoteCaptionPos,
4241 eObjectHandling);
4242 }
4243
4244 // #i102616# actions that modify the draw page size count as sheet modification
4245 // (exception: InitDrawLayer)
4246 if (bResetStreamValid)
4247 SetStreamValid(false);
4248}
4249
4250void ScTable::SetRangeName(std::unique_ptr<ScRangeName> pNew)
4251{
4252 mpRangeName = std::move(pNew);
4253
4254 //fdo#39792: mark stream as invalid, otherwise new ScRangeName will not be written to file
4255 SetStreamValid(false);
4256}
4257
4259{
4260 if (!mpRangeName)
4261 mpRangeName.reset(new ScRangeName);
4262 return mpRangeName.get();
4263}
4264
4265tools::Long ScTable::GetRowOffset( SCROW nRow, bool bHiddenAsZero ) const
4266{
4267 tools::Long n = 0;
4268 if ( mpHiddenRows && mpRowHeights )
4269 {
4270 if (nRow == 0)
4271 return 0;
4272 else if (nRow == 1)
4273 return GetRowHeight(0, nullptr, nullptr, bHiddenAsZero );
4274
4275 n = GetTotalRowHeight(0, nRow-1, bHiddenAsZero);
4276#if OSL_DEBUG_LEVEL > 0
4277 if (n == ::std::numeric_limits<tools::Long>::max())
4278 OSL_FAIL("ScTable::GetRowOffset: row heights overflow");
4279#endif
4280 }
4281 else
4282 {
4283 OSL_FAIL("GetRowOffset: Data missing");
4284 }
4285 return n;
4286}
4287
4289{
4290 tools::Long nSum = 0;
4291
4293
4294 ScFlatUInt16RowSegments::RangeData aRowHeightRange;
4295 aRowHeightRange.mnRow2 = -1;
4296 aRowHeightRange.mnValue = 1; // silence MSVC C4701
4297
4298 for (SCROW nRow = 0; nRow <= rDocument.MaxRow(); ++nRow)
4299 {
4300 if (!mpHiddenRows->getRangeData(nRow, aData))
4301 // Failed to fetch the range data for whatever reason.
4302 break;
4303
4304 if (aData.mbValue)
4305 {
4306 // This row is hidden. Skip ahead all hidden rows.
4307 nRow = aData.mnRow2;
4308 continue;
4309 }
4310
4311 if (aRowHeightRange.mnRow2 < nRow)
4312 {
4313 if (!mpRowHeights->getRangeData(nRow, aRowHeightRange))
4314 // Failed to fetch the range data for whatever reason.
4315 break;
4316 }
4317
4318 // find the last common row between hidden & height spans
4319 SCROW nLastCommon = std::min(aData.mnRow2, aRowHeightRange.mnRow2);
4320 assert (nLastCommon >= nRow);
4321 SCROW nCommon = nLastCommon - nRow + 1;
4322
4323 // how much further to go ?
4324 tools::Long nPixelsLeft = nHeight - nSum;
4325 tools::Long nCommonPixels = static_cast<tools::Long>(aRowHeightRange.mnValue) * nCommon;
4326
4327 // are we in the zone ?
4328 if (nCommonPixels > nPixelsLeft)
4329 {
4330 nRow += (nPixelsLeft + aRowHeightRange.mnValue - 1) / aRowHeightRange.mnValue;
4331
4332 // FIXME: finding this next row is far from elegant,
4333 // we have a single caller, which subtracts one as well(!?)
4334 if (nRow >= rDocument.MaxRow())
4335 return rDocument.MaxRow();
4336
4337 if (!mpHiddenRows->getRangeData(nRow, aData))
4338 // Failed to fetch the range data for whatever reason.
4339 break;
4340
4341 if (aData.mbValue)
4342 // These rows are hidden.
4343 nRow = aData.mnRow2 + 1;
4344
4345 return nRow <= rDocument.MaxRow() ? nRow : rDocument.MaxRow();
4346 }
4347
4348 // skip the range and keep hunting
4349 nSum += nCommonPixels;
4350 nRow = nLastCommon;
4351 }
4352 return -1;
4353}
4354
4355tools::Long ScTable::GetColOffset( SCCOL nCol, bool bHiddenAsZero ) const
4356{
4357 tools::Long n = 0;
4358 if ( mpColWidth )
4359 {
4360 auto colWidthIt = mpColWidth->begin();
4361 for (SCCOL i = 0; i < nCol; (++i < nCol) ? ++colWidthIt : (void)false)
4362 if (!( bHiddenAsZero && ColHidden(i) ))
4363 n += *colWidthIt;
4364 }
4365 else
4366 {
4367 OSL_FAIL("GetColumnOffset: Data missing");
4368 }
4369 return n;
4370}
4371
4372/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:105
bool ValidCol(SCCOL nCol, SCCOL nMaxCol)
Definition: address.hxx:99
void PutInOrder(T &nStart, T &nEnd)
Definition: address.hxx:150
ScMF
Definition: attrib.hxx:34
SbxDimArrayRef mpArray
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
SCTAB Tab() const
Definition: address.hxx:283
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void SetTab(SCTAB nTabP)
Definition: address.hxx:295
SCCOL Col() const
Definition: address.hxx:279
void SetRangeDirty(const ScRange &rRange)
Definition: chartlis.cxx:571
SCCOL size() const
ScColumnVector::const_iterator begin() const
ScColumnVector::const_iterator end() const
void ApplyStyleArea(SCROW nStartRow, SCROW nEndRow, const ScStyleSheet &rStyle)
Definition: column.hxx:982
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.hxx:952
const SfxPoolItem & GetAttr(SCROW nRow, sal_uInt16 nWhich) const
Definition: column.hxx:957
SCROW ApplySelectionCache(SfxItemPoolCache *pCache, const ScMarkData &rMark, ScEditDataArray *pDataArray, bool *const pIsChanged, SCCOL nCol)
Definition: column.cxx:383
void SetAttrEntries(std::vector< ScAttrEntry > &&vNewData)
Definition: column.hxx:1033
bool HasAttrib(SCROW nRow1, SCROW nRow2, HasAttrFlags nMask) const
Definition: column.hxx:917
void ClearSelectionItems(const sal_uInt16 *pWhich, const ScMarkData &rMark, SCCOL nCol)
Definition: column.cxx:426
bool TestInsertRow(SCSIZE nSize) const
Definition: column.hxx:1038
void MergePatternArea(ScMergePatternState &rState, SCROW nRow1, SCROW nRow2, bool bDeep) const
Definition: column.hxx:934
void InsertRow(SCROW nStartRow, SCSIZE nSize)
Definition: column.hxx:1043
void ApplyPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr &rPatAttr, ScEditDataArray *pDataArray=nullptr, bool *const pIsChanged=nullptr)
Definition: column.cxx:482
const ScStyleSheet * GetStyle(SCROW nRow) const
Definition: column.hxx:987
const ScPatternAttr * GetMostUsedPattern(SCROW nStartRow, SCROW nEndRow) const
Definition: column.cxx:337
void ChangeSelectionIndent(bool bIncrement, const ScMarkData &rMark, SCCOL nCol)
Definition: column.cxx:408
sal_uInt32 GetNumberFormat(const ScInterpreterContext &rContext, SCROW nRow) const
Definition: column.hxx:967
void CreateSparklineCell(SCROW nRow, std::shared_ptr< sc::Sparkline > const &pSparkline)
Definition: column2.cxx:2029
bool ApplyFlags(SCROW nStartRow, SCROW nEndRow, ScMF nFlags)
Definition: column.hxx:1002
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1648
void ApplyPattern(SCROW nRow, const ScPatternAttr &rPatAttr)
Definition: column.cxx:467
void SetValue(SCROW nRow, double fVal)
Definition: column3.cxx:3042
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:187
void SetFormula(SCROW nRow, const ScTokenArray &rArray, formula::FormulaGrammar::Grammar eGram)
Definition: column3.cxx:2384
ScFormulaCell * SetFormulaCell(SCROW nRow, ScFormulaCell *pCell, sc::StartListeningType eListenType=sc::SingleCellListening, bool bInheritNumFormatIfNeeded=true)
Takes ownership of pCell.
Definition: column3.cxx:2420
bool SetFormulaCells(SCROW nRow, std::vector< ScFormulaCell * > &rCells)
Definition: column3.cxx:2458
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1122
void SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr &)
Definition: column.hxx:1027
BroadcastMode
Broadcast mode for SetDirty(SCROW,SCROW,BroadcastMode).
Definition: column.hxx:242
sc::CellNoteStoreType maCellNotes
Definition: column.hxx:190
void SetNumberFormat(SCROW nRow, sal_uInt32 nNumberFormat)
Definition: column2.cxx:3257
void ApplyAttr(SCROW nRow, const SfxPoolItem &rAttr)
Definition: column.cxx:620
const ScPatternAttr * SetPattern(SCROW nRow, std::unique_ptr< ScPatternAttr >)
Definition: column.hxx:1017
void ApplyStyle(SCROW nRow, const ScStyleSheet *rStyle)
Definition: column.cxx:516
sc::CellStoreType maCells
Definition: column.hxx:196
void AddCondFormat(SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex)
Definition: column.hxx:972
void CopyStaticToDocument(SCROW nRow1, SCROW nRow2, const SvNumberFormatterMergeMap &rMap, ScColumn &rDestCol)
Definition: column.cxx:964
void SetCellNote(SCROW nRow, std::unique_ptr< ScPostIt > pNote)
Definition: column2.cxx:2188
double * GetValueCell(SCROW nRow)
Definition: column3.cxx:3091
void SetEditText(SCROW nRow, std::unique_ptr< EditTextObject > pEditText)
Definition: column3.cxx:2322
bool SetString(SCROW nRow, SCTAB nTab, const OUString &rString, formula::FormulaGrammar::AddressConvention eConv, const ScSetStringParam *pParam=nullptr)
Returns true if the cell format was set as well.
Definition: column3.cxx:2302
void CopyCellToDocument(SCROW nSrcRow, SCROW nDestRow, ScColumn &rDestCol)
Definition: column.cxx:1089
void SetRawString(SCROW nRow, const OUString &rStr)
Definition: column3.cxx:2993
const OUString & GetStyleName() const
Definition: conditio.hxx:513
ScRangeList & GetRangeList()
Definition: conditio.hxx:560
bool EqualEntries(const ScConditionalFormat &r, bool bIgnoreSrcPos=false) const
Definition: conditio.cxx:1730
const ScRangeList & GetRange() const
Definition: conditio.hxx:558
void SetRange(const ScRangeList &rRanges)
Definition: conditio.cxx:1749
std::unique_ptr< ScConditionalFormat > Clone(ScDocument *pNewDoc=nullptr) const
Definition: conditio.cxx:1711
sal_uInt32 GetKey() const
Definition: conditio.hxx:590
const ScFormatEntry * GetEntry(sal_uInt16 nPos) const
Definition: conditio.cxx:1789
size_t size() const
Definition: conditio.cxx:1775
const ScPatternAttr * GetNext(SCCOL &rCol, SCROW &rRow1, SCROW &rRow2)
Definition: dociter.cxx:1584
void SetAreasChangedNeedBroadcast()
Definition: docsh.hxx:389
SC_DLLPUBLIC bool IsScenario(SCTAB nTab) const
Definition: documen3.cxx:438
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:897
bool IsUndo() const
Definition: document.hxx:1591
ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2544
void SetNote(const ScAddress &rPos, std::unique_ptr< ScPostIt > pNote)
Definition: document.cxx:6743
SC_DLLPUBLIC bool IsTabProtected(SCTAB nTab) const
Definition: documen3.cxx:1919
SC_DLLPUBLIC bool HasColNotes(SCCOL nCol, SCTAB nTab) const
Definition: document.cxx:6789
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:891
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6169
bool IsCutMode()
Definition: document.cxx:2060
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:500
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:892
SC_DLLPUBLIC ScChartListenerCollection * GetChartListenerCollection() const
Definition: document.hxx:2228
bool HasScenarioRange(SCTAB nTab, const ScRange &rRange) const
Definition: documen3.cxx:873
ScInterpreterContext & GetNonThreadedContext() const
Definition: document.hxx:616
SC_DLLPUBLIC std::unique_ptr< ScPostIt > ReleaseNote(const ScAddress &rPos)
Definition: document.cxx:6828
ScBroadcastAreaSlotMachine * GetBASM() const
Definition: document.hxx:2226
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1082
bool IsClipOrUndo() const
Definition: document.hxx:1590
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1081
SC_DLLPUBLIC ScStyleSheetPool * GetStyleSheetPool() const
Definition: document.cxx:6174
SC_DLLPUBLIC void SetPattern(const ScAddress &, const ScPatternAttr &rAttr)
Definition: document.cxx:5124
SC_DLLPUBLIC void AddCondFormatData(const ScRangeList &rRange, SCTAB nTab, sal_uInt32 nIndex)
Definition: document.cxx:4884
void GetScenarioFlags(SCTAB nTab, ScScenarioFlags &rFlags) const
Definition: documen3.cxx:485
SC_DLLPUBLIC bool IsActiveScenario(SCTAB nTab) const
Definition: documen3.cxx:886
void SetPageSize(sal_uInt16 nPageNo, const Size &rSize, bool bUpdateNoteCaptionPos, const ScObjectHandling eObjectHandling=ScObjectHandling::RecalcPosMode)
Definition: drwlayer.cxx:570
bool HasObjectsInRows(SCTAB nTab, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:1488
static std::unique_ptr< EditTextObject > Clone(const EditTextObject &rSrc, ScDocument &rDestDoc)
Definition: editutil.cxx:189
bool getRangeData(SCROW nRow, RangeData &rData) const
bool getValue(SCROW nPos, sal_uInt16 &rVal)
virtual Type GetType() const =0
bool HasOneReference(ScRange &r) const
bool UpdateReference(const sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc=nullptr, const ScAddress *pUndoCellPos=nullptr)
void TransposeReference()
bool HasRefListExpressibleAsOneReference(ScRange &rRange) const
ScAddress aPos
static SC_DLLPUBLIC sal_uInt16 nStdRowHeight
Definition: global.hxx:595
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1062
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
const ScRange & GetArea() const
Definition: markdata.hxx:85
bool HasMultiMarks(SCCOL nCol) const
Definition: markdata.cxx:617
void FillRangeListWithMarks(ScRangeList *pList, bool bClear, SCTAB nForTab=-1) const
Create a range list of marks.
Definition: markdata.cxx:372
ScRangeList GetMarkedRanges() const
Definition: markdata.cxx:450
bool GetTableSelect(SCTAB nTab) const
Definition: markdata.cxx:169
std::vector< sc::ColRowSpan > GetMarkedColSpans() const
Definition: markdata.cxx:481
SCCOL GetStartOfEqualColumns(SCCOL nLastCol, SCCOL nMinCol=0) const
Definition: markdata.cxx:593
SCCOL GetColMerge() const
Definition: attrib.hxx:68
bool IsMerged() const
Definition: attrib.hxx:71
SCROW GetRowMerge() const
Definition: attrib.hxx:69
ScMF GetValue() const
Definition: attrib.hxx:97
bool IsOverlapped() const
Definition: attrib.hxx:101
bool Insert(SCCOLROW nStartPos, SCCOLROW nEndPos, bool &rSizeChanged, bool bHidden=false)
Definition: olinetab.cxx:197
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1301
ScRotateDir GetRotateDir(const SfxItemSet *pCondSet) const
Definition: patattr.cxx:1371
SfxItemSet & GetItemSet()
Definition: patattr.hxx:155
Additional class containing cell annotation data.
Definition: postit.hxx:58
std::unique_ptr< ScPostIt > Clone(const ScAddress &rOwnPos, ScDocument &rDestDoc, const ScAddress &rDestPos, bool bCloneCaption) const
Clones this note and its caption object, if specified.
Definition: postit.cxx:513
bool Intersects(const ScRange &) const
Definition: rangelst.cxx:1077
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:152
ScRangeList GetIntersectedRange(const ScRange &rRange) const
Definition: rangelst.cxx:1165
size_t size() const
Definition: rangelst.hxx:89
ScAddress aEnd
Definition: address.hxx:498
bool Intersects(const ScRange &rRange) const
Definition: address.hxx:734
ScAddress aStart
Definition: address.hxx:497
void CopyStyleFrom(ScStyleSheetPool *pSrcPool, const OUString &rName, SfxStyleFamily eFamily)
Definition: stlpool.cxx:128
std::unique_ptr< ScFlatBoolColSegments > mpHiddenCols
Definition: table.hxx:188
void CopyScenarioFrom(const ScTable *pSrcTab)
Definition: table2.cxx:1575
const ScStyleSheet * GetSelectionStyle(const ScMarkData &rMark, bool &rFound) const
Definition: table2.cxx:3067
void ApplySelectionCache(SfxItemPoolCache *pCache, const ScMarkData &rMark, ScEditDataArray *pDataArray=nullptr, bool *const pIsChanged=nullptr)
Definition: table2.cxx:3207
ScRangeName * GetRangeName() const
Definition: table2.cxx:4258
void UnlockTable()
Definition: table2.cxx:2811