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 // When delete column(s), initialize the last columns from the default attributes
404 for (SCCOL nCol = aCol.size() < static_cast<SCCOL>(nSize) ? 0 : aCol.size() - nSize; nCol < aCol.size(); ++nCol)
405 aCol[nCol].Init(nCol, aCol[nCol].GetTab(), rDocument, false);
406 }
407 else
408 {
409 for (SCSIZE i=0; static_cast<SCCOL>(i+nSize)+nStartCol < aCol.size(); i++)
410 aCol[nStartCol + nSize + i].MoveTo(nStartRow, nEndRow, aCol[nStartCol + i]);
411 }
412
413 std::vector<SCCOL> aRegroupCols;
414 rRegroupCols.getColumns(nTab, aRegroupCols);
415 std::for_each(aRegroupCols.begin(), aRegroupCols.end(), ColumnRegroupFormulaCells(aCol, nullptr));
416
418
419 // TODO: In the future we may want to check if the table has been
420 // really modified before setting the stream invalid.
421 SetStreamValid(false);
422}
423
425 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, InsertDeleteFlags nDelFlag,
426 bool bBroadcast, sc::ColumnSpanSet* pBroadcastSpans )
427{
428 if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
429 if (nRow2 > rDocument.MaxRow()) nRow2 = rDocument.MaxRow();
430 if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
431 {
432 { // scope for bulk broadcast
433 ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
434 for (SCCOL i = nCol1; i <= nCol2; i++)
435 aCol[i].DeleteArea(nRow1, nRow2, nDelFlag, bBroadcast, pBroadcastSpans);
436 }
437
438 // Do not set protected cell in a protected table
439
440 if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) )
441 {
442 ScPatternAttr aPattern(rDocument.GetPool());
443 aPattern.GetItemSet().Put( ScProtectionAttr( false ) );
444 ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
445 }
446
447 if( nDelFlag & InsertDeleteFlags::ATTRIB )
448 mpCondFormatList->DeleteArea( nCol1, nRow1, nCol2, nRow2 );
449 }
450
451 // TODO: In the future we may want to check if the table has been
452 // really modified before setting the stream invalid.
453 SetStreamValid(false);
454}
455
456void ScTable::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
457{
458 { // scope for bulk broadcast
459 ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
460 for (SCCOL i=0; i < aCol.size(); i++)
461 aCol[i].DeleteSelection(nDelFlag, rMark, bBroadcast);
462 }
463
464 ScRangeList aRangeList;
465 rMark.FillRangeListWithMarks(&aRangeList, false);
466
467 for (size_t i = 0; i < aRangeList.size(); ++i)
468 {
469 const ScRange & rRange = aRangeList[i];
470
471 if((nDelFlag & InsertDeleteFlags::ATTRIB) && rRange.aStart.Tab() == nTab)
472 mpCondFormatList->DeleteArea( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row() );
473 }
474
475 // Do not set protected cell in a protected sheet
476
477 if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) )
478 {
481 aSet.Put( ScProtectionAttr( false ) );
482 SfxItemPoolCache aCache( pPool, &aSet );
483 ApplySelectionCache( &aCache, rMark );
484 }
485
486 // TODO: In the future we may want to check if the table has been
487 // really modified before setting the stream invalid.
488 SetStreamValid(false);
489}
490
491// pTable = Clipboard
493 sc::CopyToClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
494 ScTable* pTable )
495{
496 if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
497 return;
498
499 // copy content
500 //local range names need to be copied first for formula cells
501 if (!pTable->mpRangeName && mpRangeName)
502 pTable->mpRangeName.reset( new ScRangeName(*mpRangeName) );
503
504 nCol2 = ClampToAllocatedColumns(nCol2);
505
506 for ( SCCOL i = nCol1; i <= nCol2; i++)
507 aCol[i].CopyToClip(rCxt, nRow1, nRow2, pTable->CreateColumnIfNotExists(i)); // notes are handled at column level
508
509 // copy widths/heights, and only "hidden", "filtered" and "manual" flags
510 // also for all preceding columns/rows, to have valid positions for drawing objects
511
512 if (mpColWidth && pTable->mpColWidth)
513 pTable->mpColWidth->CopyFrom(*mpColWidth, 0, nCol2);
514
515 pTable->CopyColHidden(*this, 0, nCol2);
516 pTable->CopyColFiltered(*this, 0, nCol2);
517 if (pDBDataNoName)
518 pTable->SetAnonymousDBData(std::unique_ptr<ScDBData>(new ScDBData(*pDBDataNoName)));
519
520 if (pRowFlags && pTable->pRowFlags && mpRowHeights && pTable->mpRowHeights)
521 {
522 pTable->pRowFlags->CopyFromAnded( *pRowFlags, 0, nRow2, CRFlags::ManualSize);
523 pTable->CopyRowHeight(*this, 0, nRow2, 0);
524 }
525
526 pTable->CopyRowHidden(*this, 0, nRow2);
527 pTable->CopyRowFiltered(*this, 0, nRow2);
528
529 // If necessary replace formulas with values
530
531 if ( IsProtected() )
532 for (SCCOL i = nCol1; i <= nCol2; i++)
533 pTable->aCol[i].RemoveProtected(nRow1, nRow2);
534
535 mpCondFormatList->startRendering();
536 mpCondFormatList->updateValues();
538 mpCondFormatList->endRendering();
539}
540
542 sc::CopyToClipContext& rCxt, const ScRangeList& rRanges, ScTable* pTable )
543{
544 for ( size_t i = 0, nListSize = rRanges.size(); i < nListSize; ++i )
545 {
546 const ScRange & r = rRanges[ i ];
547 CopyToClip( rCxt, r.aStart.Col(), r.aStart.Row(), r.aEnd.Col(), r.aEnd.Row(), pTable);
548 }
549}
550
552 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const SvNumberFormatterMergeMap& rMap, ScTable* pDestTab )
553{
554 if (nCol1 > nCol2 || nRow1 > nRow2)
555 return;
556
557 const SCCOL nFirstUnallocated = std::clamp<SCCOL>(GetAllocatedColumnsCount(), nCol1, nCol2 + 1);
558 if (nFirstUnallocated > nCol1)
559 pDestTab->CreateColumnIfNotExists(nFirstUnallocated - 1);
560
561 for (SCCOL i = nCol1; i < nFirstUnallocated; ++i)
562 {
563 ScColumn& rSrcCol = aCol[i];
564 ScColumn& rDestCol = pDestTab->aCol[i];
565 rSrcCol.CopyStaticToDocument(nRow1, nRow2, rMap, rDestCol);
566 }
567
568 // Maybe copy this table's default attrs to dest not limiting to already allocated in dest?
569 const SCCOL nLastInDest = std::min<SCCOL>(pDestTab->GetAllocatedColumnsCount() - 1, nCol2);
570 for (SCCOL i = nFirstUnallocated; i <= nLastInDest; ++i)
571 {
572 ScColumn& rDestCol = pDestTab->aCol[i];
573 rDestCol.maCellTextAttrs.set_empty(nRow1, nRow2);
574 rDestCol.maCells.set_empty(nRow1, nRow2);
575 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
576 {
577 sal_uInt32 nNumFmt = aDefaultColData.GetPattern(nRow)->GetNumberFormat(
579 SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt);
580 if (itNum != rMap.end())
581 nNumFmt = itNum->second;
582
583 rDestCol.SetNumberFormat(nRow, nNumFmt);
584 }
585 rDestCol.CellStorageModified();
586 }
587}
588
589void ScTable::CopyCellToDocument(SCCOL nSrcCol, SCROW nSrcRow, SCCOL nDestCol, SCROW nDestRow, ScTable& rDestTab )
590{
591 if (!ValidColRow(nSrcCol, nSrcRow) || !ValidColRow(nDestCol, nDestRow))
592 return;
593
594 if (nSrcCol >= GetAllocatedColumnsCount())
595 {
596 if (nDestCol < rDestTab.GetAllocatedColumnsCount())
597 {
598 ScColumn& rDestCol = rDestTab.aCol[nDestCol];
599 rDestCol.maCells.set_empty(nDestRow, nDestRow);
600 rDestCol.maCellTextAttrs.set_empty(nDestRow, nDestRow);
601 rDestCol.maCellNotes.set_empty(nDestRow, nDestRow);
602 rDestCol.CellStorageModified();
603 }
604 return;
605 }
606
607 ScColumn& rSrcCol = aCol[nSrcCol];
608 ScColumn& rDestCol = rDestTab.CreateColumnIfNotExists(nDestCol);
609 rSrcCol.CopyCellToDocument(nSrcRow, nDestRow, rDestCol);
610}
611
612namespace {
613
614bool CheckAndDeduplicateCondFormat(ScDocument& rDocument, ScConditionalFormat* pOldFormat, const ScConditionalFormat* pNewFormat, SCTAB nTab)
615{
616 if (!pOldFormat)
617 return false;
618
619 if (pOldFormat->EqualEntries(*pNewFormat, true))
620 {
621 const ScRangeList& rNewRangeList = pNewFormat->GetRange();
622 ScRangeList& rDstRangeList = pOldFormat->GetRangeList();
623 for (size_t i = 0; i < rNewRangeList.size(); ++i)
624 {
625 rDstRangeList.Join(rNewRangeList[i]);
626 }
627 rDocument.AddCondFormatData(rNewRangeList, nTab, pOldFormat->GetKey());
628 return true;
629 }
630
631 return false;
632}
633
634}
635
636void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
637 SCCOL nDx, SCROW nDy, const ScTable* pTable)
638{
639 ScRange aOldRange( nCol1 - nDx, nRow1 - nDy, pTable->nTab, nCol2 - nDx, nRow2 - nDy, pTable->nTab);
640 ScRange aNewRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
641 bool bSameDoc = rDocument.GetStyleSheetPool() == pTable->rDocument.GetStyleSheetPool();
642
643 for(const auto& rxCondFormat : *pTable->mpCondFormatList)
644 {
645 const ScRangeList& rCondFormatRange = rxCondFormat->GetRange();
646 if(!rCondFormatRange.Intersects( aOldRange ))
647 continue;
648
649 ScRangeList aIntersectedRange = rCondFormatRange.GetIntersectedRange(aOldRange);
650 std::unique_ptr<ScConditionalFormat> pNewFormat = rxCondFormat->Clone(&rDocument);
651
652 pNewFormat->SetRange(aIntersectedRange);
654 aRefCxt.meMode = URM_COPY;
655 aRefCxt.maRange = aNewRange;
656 aRefCxt.mnColDelta = nDx;
657 aRefCxt.mnRowDelta = nDy;
658 aRefCxt.mnTabDelta = nTab - pTable->nTab;
659 pNewFormat->UpdateReference(aRefCxt, true);
660
661 if (bSameDoc && pTable->nTab == nTab && CheckAndDeduplicateCondFormat(rDocument, mpCondFormatList->GetFormat(rxCondFormat->GetKey()), pNewFormat.get(), nTab))
662 {
663 continue;
664 }
665 sal_uLong nMax = 0;
666 bool bDuplicate = false;
667 for(const auto& rxCond : *mpCondFormatList)
668 {
669 // Check if there is the same format in the destination
670 // If there is, then simply expand its range
671 if (CheckAndDeduplicateCondFormat(rDocument, rxCond.get(), pNewFormat.get(), nTab))
672 {
673 bDuplicate = true;
674 break;
675 }
676
677 if (rxCond->GetKey() > nMax)
678 nMax = rxCond->GetKey();
679 }
680 // Do not add duplicate entries
681 if (bDuplicate)
682 {
683 continue;
684 }
685
686 pNewFormat->SetKey(nMax + 1);
687 auto pNewFormatTmp = pNewFormat.get();
688 mpCondFormatList->InsertNew(std::move(pNewFormat));
689
690 if(!bSameDoc)
691 {
692 for(size_t i = 0, n = pNewFormatTmp->size();
693 i < n; ++i)
694 {
695 OUString aStyleName;
696 const ScFormatEntry* pEntry = pNewFormatTmp->GetEntry(i);
697 if(pEntry->GetType() == ScFormatEntry::Type::Condition ||
699 aStyleName = static_cast<const ScCondFormatEntry*>(pEntry)->GetStyle();
700 else if(pEntry->GetType() == ScFormatEntry::Type::Date)
701 aStyleName = static_cast<const ScCondDateFormatEntry*>(pEntry)->GetStyleName();
702
703 if(!aStyleName.isEmpty())
705 pTable->rDocument.GetStyleSheetPool(), aStyleName, SfxStyleFamily::Para, true );
706 }
707 }
708
709 rDocument.AddCondFormatData( pNewFormatTmp->GetRange(), nTab, pNewFormatTmp->GetKey() );
710 }
711}
712
714{
715 if (!ValidCol(nCol))
716 return false;
717
719 return true;
720}
721
722// pTable is source
723
725 sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
726 SCCOL nDx, SCROW nDy, ScTable* pTable )
727{
728 if (nCol2 > rDocument.MaxCol())
729 nCol2 = rDocument.MaxCol();
730 if (nRow2 > rDocument.MaxRow())
731 nRow2 = rDocument.MaxRow();
732
733 if (!(ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2)))
734 return;
735
737 for ( SCCOL i = nCol1; i <= nCol2; i++)
738 {
739 pTable->CreateColumnIfNotExists(i - nDx);
740 aCol[i].CopyFromClip(rCxt, nRow1, nRow2, nDy, pTable->aCol[i - nDx]); // notes are handles at column level
741 }
742
744 {
745 // make sure that there are no old references to the cond formats
746 sal_uInt16 nWhichArray[2];
747 nWhichArray[0] = ATTR_CONDITIONAL;
748 nWhichArray[1] = 0;
749 for ( SCCOL i = nCol1; i <= nCol2; ++i)
750 aCol[i].ClearItems(nRow1, nRow2, nWhichArray);
751 }
752
754 return;
755
756 if (nRow1==0 && nRow2==rDocument.MaxRow() && mpColWidth && pTable->mpColWidth)
757 mpColWidth->CopyFrom(*pTable->mpColWidth, nCol1, nCol2, nCol1 - nDx);
758
759 if (nCol1==0 && nCol2==rDocument.MaxCol() && mpRowHeights && pTable->mpRowHeights &&
760 pRowFlags && pTable->pRowFlags)
761 {
762 CopyRowHeight(*pTable, nRow1, nRow2, -nDy);
763 // Must copy CRFlags::ManualSize bit too, otherwise pRowHeight doesn't make sense
764 for (SCROW j=nRow1; j<=nRow2; j++)
765 {
766 if ( pTable->pRowFlags->GetValue(j-nDy) & CRFlags::ManualSize )
767 pRowFlags->OrValue( j, CRFlags::ManualSize);
768 else
769 pRowFlags->AndValue( j, ~CRFlags::ManualSize);
770 }
771 }
772
773 // Do not set protected cell in a protected sheet
775 {
776 ScPatternAttr aPattern(rDocument.GetPool());
777 aPattern.GetItemSet().Put( ScProtectionAttr( false ) );
778 ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
779 }
780
781 // create deep copies for conditional formatting
782 CopyConditionalFormat( nCol1, nRow1, nCol2, nRow2, nDx, nDy, pTable);
783}
784
786 sc::MixDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
787 ScPasteFunc nFunction, bool bSkipEmpty, const ScTable* pSrcTab )
788{
789 for (SCCOL i=nCol1; i<=nCol2; i++)
790 aCol[i].MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, pSrcTab->aCol[i]);
791}
792
793// Selection form this document
795 sc::MixDocContext& rCxt, const ScMarkData& rMark, ScPasteFunc nFunction,
796 bool bSkipEmpty, const ScTable* pSrcTab )
797{
798 for (SCCOL i=0; i < aCol.size(); i++)
799 aCol[i].MixMarked(rCxt, rMark, nFunction, bSkipEmpty, pSrcTab->aCol[i]);
800}
801
802namespace {
803
804class TransClipHandler
805{
806 ScTable& mrClipTab;
807 const ScTable& mrSrcTab;
808 SCTAB mnSrcTab;
809 SCCOL mnCol1;
810 SCCOL mnSrcCol;
811 size_t mnTopRow;
812 size_t mnEndRow;
813 SCROW mnTransRow;
814 SCROW mnFilteredRows = 0;
815 SCROW mnRowDestOffset = 0;
816 bool mbAsLink;
817 bool mbWasCut;
818 bool mbIncludeFiltered;
820
821 ScAddress getDestPos(size_t nRow) const
822 {
823 return ScAddress(static_cast<SCCOL>(mnCol1 + nRow - mnTopRow), mnTransRow,
824 mrClipTab.GetTab());
825 }
826
827 ScFormulaCell* createRefCell(size_t nSrcRow, const ScAddress& rDestPos) const
828 {
829 ScAddress aSrcPos(mnSrcCol, nSrcRow, mnSrcTab);
830 ScSingleRefData aRef;
831 aRef.InitAddress(aSrcPos); // Absolute reference.
832 aRef.SetFlag3D(true);
833
834 ScTokenArray aArr(mrClipTab.GetDoc());
835 aArr.AddSingleReference(aRef);
836 return new ScFormulaCell(mrClipTab.GetDoc(), rDestPos, aArr);
837 }
838
839 void setLink(size_t nRow)
840 {
841 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
842 mrClipTab.SetFormulaCell(nTransCol, mnTransRow,
843 createRefCell(nRow, getDestPos(nRow)));
844 }
845
846public:
847 TransClipHandler(ScTable& rClipTab, const ScTable& rSrcTab, SCTAB nSrcTab, SCCOL nCol1,
848 SCCOL nSrcCol, size_t nTopRow, size_t nEndRow, SCROW nCombinedStartRow,
849 SCROW nRowDestOffset, bool bAsLink, bool bWasCut,
850 const InsertDeleteFlags& nFlags, const bool bIncludeFiltered,
851 std::vector<SCROW>& rFilteredRows)
852 : mrClipTab(rClipTab)
853 , mrSrcTab(rSrcTab)
854 , mnSrcTab(nSrcTab)
855 , mnCol1(nCol1)
856 , mnSrcCol(nSrcCol)
857 , mnTopRow(nTopRow)
858 , mnEndRow(nEndRow)
859 , mnTransRow(nSrcCol - nCol1 + nCombinedStartRow)
860 , mnRowDestOffset(nRowDestOffset)
861 , mbAsLink(bAsLink)
862 , mbWasCut(bWasCut)
863 , mbIncludeFiltered(bIncludeFiltered)
864 , mnFlags(nFlags)
865 {
866 // Create list of filtered rows.
867 if (!mbIncludeFiltered)
868 {
869 for (SCROW curRow = nTopRow; curRow <= static_cast<SCROW>(mnEndRow); ++curRow)
870 {
871 // maybe this loop could be optimized
872 bool bFiltered = mrSrcTab.RowFiltered(curRow, nullptr, nullptr);
873 if (bFiltered)
874 rFilteredRows.push_back(curRow);
875 }
876 }
877 }
878
879 void operator() (size_t nRow, double fVal)
880 {
881 bool bFiltered = mrSrcTab.RowFiltered(nRow, nullptr, nullptr);
882 if (!mbIncludeFiltered && bFiltered)
883 {
884 mnFilteredRows++;
885 return;
886 }
887
888 if (mbAsLink)
889 {
890 setLink(nRow);
891 return;
892 }
893
894 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
895 mrClipTab.SetValue(nTransCol, mnTransRow, fVal);
896 }
897
898 void operator() (size_t nRow, const svl::SharedString& rStr)
899 {
900 bool bFiltered = mrSrcTab.RowFiltered(nRow, nullptr, nullptr);
901 if (!mbIncludeFiltered && bFiltered)
902 {
903 mnFilteredRows++;
904 return;
905 }
906
907 if (mbAsLink)
908 {
909 setLink(nRow);
910 return;
911 }
912
913 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
914 mrClipTab.SetRawString(nTransCol, mnTransRow, rStr);
915 }
916
917 void operator() (size_t nRow, const EditTextObject* p)
918 {
919 bool bFiltered = mrSrcTab.RowFiltered(nRow, nullptr, nullptr);
920 if (!mbIncludeFiltered && bFiltered)
921 {
922 mnFilteredRows++;
923 return;
924 }
925
926 if (mbAsLink)
927 {
928 setLink(nRow);
929 return;
930 }
931
932 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
933 mrClipTab.SetEditText(nTransCol, mnTransRow, ScEditUtil::Clone(*p, mrClipTab.GetDoc()));
934 }
935
936 void operator() (size_t nRow, const ScFormulaCell* p)
937 {
938 bool bFiltered = mrSrcTab.RowFiltered(nRow, nullptr, nullptr);
939 if (!mbIncludeFiltered && bFiltered)
940 {
941 mnFilteredRows++;
942 return;
943 }
944
945 if (mbAsLink)
946 {
947 setLink(nRow);
948 return;
949 }
950
951 ScFormulaCell* pNew = new ScFormulaCell(*p, mrClipTab.GetDoc(),
952 getDestPos(nRow - mnFilteredRows + mnRowDestOffset),
954
955 // rotate reference
956 // for Cut, the references are later adjusted through UpdateTranspose
957
958 if (!mbWasCut)
959 pNew->TransposeReference();
960
961 SCCOL nTransCol = mnCol1 + nRow - mnTopRow - mnFilteredRows + mnRowDestOffset;
962 mrClipTab.SetFormulaCell(nTransCol, mnTransRow, pNew);
963 }
964
965 // empty cells
966 void operator()(const int /*type*/, size_t nRow, size_t nDataSize)
967 {
968 for (size_t curRow = nRow; curRow < nRow + nDataSize; ++curRow)
969 {
970 bool bFiltered = mrSrcTab.RowFiltered(curRow, nullptr, nullptr);
971 if (!mbIncludeFiltered && bFiltered)
972 {
973 mnFilteredRows++;
974 continue;
975 }
976
977 if (mbAsLink && mnFlags == InsertDeleteFlags::ALL)
978 {
979 // with InsertDeleteFlags::ALL, also create links (formulas) for empty cells
980 setLink(nRow);
981 continue;
982 }
983 }
984 }
985};
986}
987
988void ScTable::TransposeClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
989 SCROW nCombinedStartRow, SCROW nRowDestOffset, ScTable* pTransClip,
990 InsertDeleteFlags nFlags, bool bAsLink, bool bIncludeFiltered)
991{
992 bool bWasCut = rDocument.IsCutMode();
993
994 for (SCCOL nCol : GetWritableColumnsRange(nCol1, nCol2))
995 {
996 std::vector<SCROW> aFilteredRows;
997
998 TransClipHandler aFunc(*pTransClip, *this, nTab, nCol1, nCol, nRow1, nRow2,
999 nCombinedStartRow, nRowDestOffset, bAsLink, bWasCut, nFlags,
1000 bIncludeFiltered, aFilteredRows);
1001
1002 const sc::CellStoreType& rCells = aCol[nCol].maCells;
1003
1004 // Loop through all rows by iterator and call aFunc operators
1005 sc::ParseAll(rCells.begin(), rCells, nRow1, nRow2, aFunc,
1006 aFunc);
1007
1008 // Attributes
1009 if (nFlags & InsertDeleteFlags::ATTRIB)
1010 TransposeColPatterns(pTransClip, nCol1, nCol, nRow1, nRow2, nCombinedStartRow,
1011 bIncludeFiltered, aFilteredRows, nRowDestOffset);
1012
1013 // Cell Notes - fdo#68381 paste cell notes on Transpose
1014 if ((nFlags & InsertDeleteFlags::NOTE) && rDocument.HasColNotes(nCol, nTab))
1015 TransposeColNotes(pTransClip, nCol1, nCol, nRow1, nRow2, nCombinedStartRow,
1016 bIncludeFiltered, nRowDestOffset);
1017 }
1018}
1019
1020static void lcl_SetTransposedPatternInRows(ScTable* pTransClip, SCROW nAttrRow1, SCROW nAttrRow2,
1021 SCCOL nCol1, SCROW nRow1, SCROW nCombinedStartRow, SCCOL nCol,
1022 const ScPatternAttr& rPatternAttr, bool bIncludeFiltered,
1023 const std::vector<SCROW>& rFilteredRows,
1024 SCROW nRowDestOffset)
1025{
1026 for (SCROW nRow = nAttrRow1; nRow <= nAttrRow2; nRow++)
1027 {
1028 size_t nFilteredRowAdjustment = 0;
1029 if (!bIncludeFiltered)
1030 {
1031 // aFilteredRows is sorted thus lower_bound() can be used.
1032 // lower_bound() has a logarithmic complexity O(log(n))
1033 auto itRow1 = std::lower_bound(rFilteredRows.begin(), rFilteredRows.end(), nRow1);
1034 auto itRow = std::lower_bound(rFilteredRows.begin(), rFilteredRows.end(), nRow);
1035 bool bRefRowIsFiltered = itRow != rFilteredRows.end() && *itRow == nRow;
1036 if (bRefRowIsFiltered)
1037 continue;
1038
1039 // How many filtered rows are between the formula cell and the reference?
1040 // distance() has a constant complexity O(1) for vectors
1041 nFilteredRowAdjustment = std::distance(itRow1, itRow);
1042 }
1043
1044 pTransClip->SetPattern(
1045 static_cast<SCCOL>(nCol1 + nRow - nRow1 - nFilteredRowAdjustment + nRowDestOffset),
1046 static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), rPatternAttr);
1047 }
1048}
1049
1050void ScTable::TransposeColPatterns(ScTable* pTransClip, SCCOL nCol1, SCCOL nCol, SCROW nRow1,
1051 SCROW nRow2, SCROW nCombinedStartRow, bool bIncludeFiltered,
1052 const std::vector<SCROW>& rFilteredRows, SCROW nRowDestOffset)
1053{
1054 SCROW nAttrRow1 = {}; // spurious -Werror=maybe-uninitialized
1055 SCROW nAttrRow2 = {}; // spurious -Werror=maybe-uninitialized
1056 const ScPatternAttr* pPattern;
1057 std::unique_ptr<ScAttrIterator> pAttrIter(aCol[nCol].CreateAttrIterator( nRow1, nRow2 ));
1058 while ( (pPattern = pAttrIter->Next( nAttrRow1, nAttrRow2 )) != nullptr )
1059 {
1060 if ( !IsDefaultItem( pPattern ) )
1061 {
1062 const SfxItemSet& rSet = pPattern->GetItemSet();
1063 if ( rSet.GetItemState( ATTR_MERGE, false ) == SfxItemState::DEFAULT &&
1064 rSet.GetItemState( ATTR_MERGE_FLAG, false ) == SfxItemState::DEFAULT &&
1065 rSet.GetItemState( ATTR_BORDER, false ) == SfxItemState::DEFAULT )
1066 {
1067 // Set pattern in cells from nAttrRow1 to nAttrRow2
1068 // no borders or merge items involved - use pattern as-is
1069 lcl_SetTransposedPatternInRows(pTransClip, nAttrRow1, nAttrRow2, nCol1, nRow1,
1070 nCombinedStartRow, nCol, *pPattern,
1071 bIncludeFiltered, rFilteredRows, nRowDestOffset);
1072 }
1073 else
1074 {
1075 // transpose borders and merge values, remove merge flags (refreshed after pasting)
1076 ScPatternAttr aNewPattern( *pPattern );
1077 SfxItemSet& rNewSet = aNewPattern.GetItemSet();
1078
1079 const SvxBoxItem& rOldBox = rSet.Get(ATTR_BORDER);
1080 if ( rOldBox.GetTop() || rOldBox.GetBottom() || rOldBox.GetLeft() || rOldBox.GetRight() )
1081 {
1082 SvxBoxItem aNew( ATTR_BORDER );
1083 aNew.SetLine( rOldBox.GetLine( SvxBoxItemLine::TOP ), SvxBoxItemLine::LEFT );
1084 aNew.SetLine( rOldBox.GetLine( SvxBoxItemLine::LEFT ), SvxBoxItemLine::TOP );
1085 aNew.SetLine( rOldBox.GetLine( SvxBoxItemLine::BOTTOM ), SvxBoxItemLine::RIGHT );
1086 aNew.SetLine( rOldBox.GetLine( SvxBoxItemLine::RIGHT ), SvxBoxItemLine::BOTTOM );
1087 aNew.SetDistance( rOldBox.GetDistance( SvxBoxItemLine::TOP ), SvxBoxItemLine::LEFT );
1088 aNew.SetDistance( rOldBox.GetDistance( SvxBoxItemLine::LEFT ), SvxBoxItemLine::TOP );
1089 aNew.SetDistance( rOldBox.GetDistance( SvxBoxItemLine::BOTTOM ), SvxBoxItemLine::RIGHT );
1090 aNew.SetDistance( rOldBox.GetDistance( SvxBoxItemLine::RIGHT ), SvxBoxItemLine::BOTTOM );
1091 rNewSet.Put( aNew );
1092 }
1093
1094 const ScMergeAttr& rOldMerge = rSet.Get(ATTR_MERGE);
1095 if (rOldMerge.IsMerged())
1096 rNewSet.Put( ScMergeAttr( std::min(
1097 static_cast<SCCOL>(rOldMerge.GetRowMerge()),
1098 static_cast<SCCOL>(rDocument.MaxCol()+1 - (nAttrRow2-nRow1))),
1099 std::min(
1100 static_cast<SCROW>(rOldMerge.GetColMerge()),
1101 static_cast<SCROW>(rDocument.MaxRow()+1 - (nCol-nCol1)))));
1102 const ScMergeFlagAttr& rOldFlag = rSet.Get(ATTR_MERGE_FLAG);
1103 if (rOldFlag.IsOverlapped())
1104 {
1105 ScMF nNewFlags = rOldFlag.GetValue() & ~ScMF( ScMF::Hor | ScMF::Ver );
1106 if ( nNewFlags != ScMF::NONE )
1107 rNewSet.Put( ScMergeFlagAttr( nNewFlags ) );
1108 else
1109 rNewSet.ClearItem( ATTR_MERGE_FLAG );
1110 }
1111
1112 // Set pattern in cells from nAttrRow1 to nAttrRow2
1113 lcl_SetTransposedPatternInRows(pTransClip, nAttrRow1, nAttrRow2, nCol1, nRow1,
1114 nCombinedStartRow, nCol, aNewPattern,
1115 bIncludeFiltered, rFilteredRows, nRowDestOffset);
1116 }
1117 }
1118 }
1119}
1120
1121void ScTable::TransposeColNotes(ScTable* pTransClip, SCCOL nCol1, SCCOL nCol, SCROW nRow1,
1122 SCROW nRow2, SCROW nCombinedStartRow, bool bIncludeFiltered,
1123 SCROW nRowDestOffset)
1124{
1125 sc::CellNoteStoreType::const_iterator itBlk = aCol[nCol].maCellNotes.begin(), itBlkEnd = aCol[nCol].maCellNotes.end();
1126
1127 // Locate the top row position.
1128 size_t nOffsetInBlock = 0;
1129 size_t nBlockStart = 0, nBlockEnd = 0, nRowPos = static_cast<size_t>(nRow1);
1130 for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd)
1131 {
1132 nBlockEnd = nBlockStart + itBlk->size;
1133 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1134 {
1135 // Found.
1136 nOffsetInBlock = nRowPos - nBlockStart;
1137 break;
1138 }
1139 }
1140
1141 if (itBlk == itBlkEnd)
1142 // Specified range found
1143 return;
1144
1145 nRowPos = static_cast<size_t>(nRow2); // End row position.
1146 SCCOL nFilteredRows = 0;
1147
1148 // Keep processing until we hit the end row position.
1149 sc::cellnote_block::const_iterator itData, itDataEnd;
1150 for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd, nOffsetInBlock = 0)
1151 {
1152 nBlockEnd = nBlockStart + itBlk->size;
1153
1154 if (itBlk->data)
1155 {
1156 itData = sc::cellnote_block::begin(*itBlk->data);
1157 std::advance(itData, nOffsetInBlock);
1158
1159 // selected area is smaller than the iteration block
1160 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1161 {
1162 // This block contains the end row. Only process partially.
1163 size_t nOffsetEnd = nRowPos - nBlockStart + 1;
1164 itDataEnd = sc::cellnote_block::begin(*itBlk->data);
1165 std::advance(itDataEnd, nOffsetEnd);
1166 size_t curRow = nBlockStart + nOffsetInBlock;
1167 for (; itData != itDataEnd; ++itData, ++curRow)
1168 {
1169 bool bFiltered = this->RowFiltered(curRow, nullptr, nullptr);
1170 if (!bIncludeFiltered && bFiltered)
1171 {
1172 nFilteredRows++;
1173 continue;
1174 }
1175
1176 ScAddress aDestPos(
1177 static_cast<SCCOL>(nCol1 + curRow - nRow1 - nFilteredRows + nRowDestOffset),
1178 static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), pTransClip->nTab);
1179 pTransClip->rDocument.ReleaseNote(aDestPos);
1180 ScPostIt* pNote = *itData;
1181 if (pNote)
1182 {
1183 std::unique_ptr<ScPostIt> pClonedNote = pNote->Clone( ScAddress(nCol, curRow, nTab), pTransClip->rDocument, aDestPos, true );
1184 pTransClip->rDocument.SetNote(aDestPos, std::move(pClonedNote));
1185 }
1186 }
1187 break; // we reached the last valid block
1188 }
1189 else
1190 {
1191 itDataEnd = sc::cellnote_block::end(*itBlk->data);
1192 size_t curRow = nBlockStart + nOffsetInBlock;
1193 for (; itData != itDataEnd; ++itData, ++curRow)
1194 {
1195 bool bFiltered = this->RowFiltered(curRow, nullptr, nullptr);
1196 if (!bIncludeFiltered && bFiltered)
1197 {
1198 nFilteredRows++;
1199 continue;
1200 }
1201
1202 ScAddress aDestPos(
1203 static_cast<SCCOL>(nCol1 + curRow - nRow1 - nFilteredRows + nRowDestOffset),
1204 static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), pTransClip->nTab);
1205 pTransClip->rDocument.ReleaseNote(aDestPos);
1206 ScPostIt* pNote = *itData;
1207 if (pNote)
1208 {
1209 std::unique_ptr<ScPostIt> pClonedNote = pNote->Clone( ScAddress(nCol, curRow, nTab), pTransClip->rDocument, aDestPos, true );
1210 pTransClip->rDocument.SetNote(aDestPos, std::move(pClonedNote));
1211 }
1212 }
1213 }
1214 }
1215 else // remove dest notes for rows without notes
1216 {
1217 for (size_t curRow = nBlockStart + nOffsetInBlock;
1218 curRow <= nBlockEnd && curRow <= nRowPos; ++curRow)
1219 {
1220 bool bFiltered = this->RowFiltered(curRow, nullptr, nullptr);
1221 if (!bIncludeFiltered && bFiltered && curRow < nBlockEnd)
1222 {
1223 nFilteredRows++;
1224 continue;
1225 }
1226
1227 ScAddress aDestPos(
1228 static_cast<SCCOL>(nCol1 + curRow - nRow1 - nFilteredRows + nRowDestOffset),
1229 static_cast<SCROW>(nCombinedStartRow + nCol - nCol1), pTransClip->nTab);
1230 pTransClip->rDocument.ReleaseNote(aDestPos);
1231 }
1232 }
1233 }
1234}
1235
1237{
1238 if (!ValidCol(nCol))
1239 return nullptr;
1240
1241 return &CreateColumnIfNotExists(nCol);
1242}
1243
1245{
1246 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1247 return nullptr;
1248
1249 return &aCol[nCol];
1250}
1251
1253{
1254 std::shared_ptr<const sc::ColumnSet> pColSet = rCxt.getColumnSet();
1255 if (!pColSet)
1256 {
1257 for (SCCOL i=0; i < aCol.size(); i++)
1258 aCol[i].StartListeners(rCxt, bAll);
1259 }
1260 else if (pColSet->hasTab( nTab))
1261 {
1262 std::vector<SCCOL> aColumns;
1263 pColSet->getColumns( nTab, aColumns);
1264 for (auto i : aColumns)
1265 {
1266 if (0 <= i && i < aCol.size())
1267 aCol[i].StartListeners(rCxt, bAll);
1268 }
1269 }
1270}
1271
1273 sc::StartListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1274{
1275 nCol2 = ClampToAllocatedColumns(nCol2);
1276 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1277 aCol[nCol].AttachFormulaCells(rCxt, nRow1, nRow2);
1278}
1279
1281 sc::EndListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1282{
1283 nCol2 = ClampToAllocatedColumns(nCol2);
1284 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1285 aCol[nCol].DetachFormulaCells(rCxt, nRow1, nRow2);
1286}
1287
1289 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans )
1290{
1291 if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
1292 if (nCol2 > rDocument.MaxCol()) nCol2 = rDocument.MaxCol();
1293 if (nRow2 > rDocument.MaxRow()) nRow2 = rDocument.MaxRow();
1294 if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
1295 for (SCCOL i = nCol1; i <= nCol2; i++)
1296 aCol[i].SetDirtyFromClip(nRow1, nRow2, rBroadcastSpans);
1297}
1298
1301 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1302{
1303 if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
1304 if (nCol2 > rDocument.MaxCol()) nCol2 = rDocument.MaxCol();
1305 if (nRow2 > rDocument.MaxRow()) nRow2 = rDocument.MaxRow();
1306 if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
1307 for (SCCOL i = nCol1; i <= nCol2; i++)
1308 aCol[i].StartListeningFormulaCells(rStartCxt, rEndCxt, nRow1, nRow2);
1309}
1310
1312 sc::CopyToDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1313 InsertDeleteFlags nFlags, bool bMarked, ScTable* pDestTab, const ScMarkData* pMarkData,
1314 bool bAsLink, bool bColRowFlags, bool bGlobalNamesToLocal, bool bCopyCaptions )
1315{
1316 if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
1317 return;
1318
1319 const bool bToUndoDoc = pDestTab->rDocument.IsUndo();
1320 const bool bFromUndoDoc = rDocument.IsUndo();
1321
1322 if ((bToUndoDoc || bFromUndoDoc) && (nFlags & InsertDeleteFlags::CONTENTS) && mpRangeName)
1323 {
1324 // Copying formulas may create sheet-local named expressions on the
1325 // destination sheet. Add existing to Undo first.
1326 // During Undo restore the previous named expressions.
1327 pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName())));
1328 if (!pDestTab->rDocument.IsClipOrUndo())
1329 {
1330 ScDocShell* pDocSh = static_cast<ScDocShell*>(pDestTab->rDocument.GetDocumentShell());
1331 if (pDocSh)
1333 }
1334 }
1335
1336 if (nFlags != InsertDeleteFlags::NONE)
1337 {
1338 InsertDeleteFlags nTempFlags( nFlags &
1340 // tdf#102364 - in some pathological cases CopyToTable() replacing cells with new cells
1341 // can lead to repetitive splitting and rejoining of the same formula group, which can get
1342 // quadratically expensive with large groups. So do the grouping just once at the end.
1343 sc::DelayFormulaGroupingSwitch delayGrouping( pDestTab->rDocument, true );
1344 for (SCCOL i = nCol1; i <= ClampToAllocatedColumns(nCol2); i++)
1345 aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bToUndoDoc ? nFlags : nTempFlags, bMarked,
1346 pDestTab->CreateColumnIfNotExists(i), pMarkData, bAsLink, bGlobalNamesToLocal);
1347 }
1348
1349 if (!bColRowFlags) // Column widths/Row heights/Flags
1350 return;
1351
1352 if (bToUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB))
1353 {
1354 pDestTab->mpCondFormatList.reset(new ScConditionalFormatList(pDestTab->rDocument, *mpCondFormatList));
1355 }
1356
1357 if (pDBDataNoName)
1358 {
1359 std::unique_ptr<ScDBData> pNewDBData(new ScDBData(*pDBDataNoName));
1360 SCCOL aCol1, aCol2;
1361 SCROW aRow1, aRow2;
1362 SCTAB aTab;
1363 pNewDBData->GetArea(aTab, aCol1, aRow1, aCol2, aRow2);
1364 pNewDBData->MoveTo(pDestTab->nTab, aCol1, aRow1, aCol2, aRow2);
1365 pDestTab->SetAnonymousDBData(std::move(pNewDBData));
1366 }
1367 // Charts have to be adjusted when hide/show
1369
1370 bool bFlagChange = false;
1371
1372 bool bWidth = (nRow1==0 && nRow2==rDocument.MaxRow() && mpColWidth && pDestTab->mpColWidth);
1373 bool bHeight = (nCol1==0 && nCol2==rDocument.MaxCol() && mpRowHeights && pDestTab->mpRowHeights);
1374
1375 if (bWidth || bHeight)
1376 {
1377 if (bWidth)
1378 {
1379 auto destTabColWidthIt = pDestTab->mpColWidth->begin() + nCol1;
1380 auto thisTabColWidthIt = mpColWidth->begin() + nCol1;
1381 pDestTab->mpColWidth->CopyFrom(*mpColWidth, nCol1, nCol2);
1382 pDestTab->mpColFlags->CopyFrom(*mpColFlags, nCol1, nCol2);
1383 for (SCCOL i = nCol1; i <= nCol2; ++i)
1384 {
1385 bool bThisHidden = ColHidden(i);
1386 bool bHiddenChange = (pDestTab->ColHidden(i) != bThisHidden);
1387 bool bChange = bHiddenChange || (*destTabColWidthIt != *thisTabColWidthIt);
1388 pDestTab->SetColHidden(i, i, bThisHidden);
1389 //TODO: collect changes?
1390 if (bHiddenChange && pCharts)
1391 pCharts->SetRangeDirty(ScRange( i, 0, nTab, i, rDocument.MaxRow(), nTab ));
1392
1393 if (bChange)
1394 bFlagChange = true;
1395
1396 ++destTabColWidthIt;
1397 ++thisTabColWidthIt;
1398 }
1399 pDestTab->SetColManualBreaks( std::set(maColManualBreaks) );
1400 }
1401
1402 if (bHeight)
1403 {
1404 bool bChange = pDestTab->GetRowHeight(nRow1, nRow2) != GetRowHeight(nRow1, nRow2);
1405
1406 if (bChange)
1407 bFlagChange = true;
1408
1409 pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
1410 pDestTab->pRowFlags->CopyFrom(*pRowFlags, nRow1, nRow2);
1411
1412 // Hidden flags.
1413 for (SCROW i = nRow1; i <= nRow2; ++i)
1414 {
1415 SCROW nLastRow;
1416 bool bHidden = RowHidden(i, nullptr, &nLastRow);
1417 if (nLastRow >= nRow2)
1418 // the last row shouldn't exceed the upper bound the caller specified.
1419 nLastRow = nRow2;
1420
1421 bool bHiddenChanged = pDestTab->SetRowHidden(i, nLastRow, bHidden);
1422 if (bHiddenChanged && pCharts)
1423 // Hidden flags differ.
1424 pCharts->SetRangeDirty(ScRange(0, i, nTab, rDocument.MaxCol(), nLastRow, nTab));
1425
1426 if (bHiddenChanged)
1427 bFlagChange = true;
1428
1429 // Jump to the last row of the identical flag segment.
1430 i = nLastRow;
1431 }
1432
1433 // Filtered flags.
1434 for (SCROW i = nRow1; i <= nRow2; ++i)
1435 {
1436 SCROW nLastRow;
1437 bool bFiltered = RowFiltered(i, nullptr, &nLastRow);
1438 if (nLastRow >= nRow2)
1439 // the last row shouldn't exceed the upper bound the caller specified.
1440 nLastRow = nRow2;
1441 pDestTab->SetRowFiltered(i, nLastRow, bFiltered);
1442 i = nLastRow;
1443 }
1444 pDestTab->SetRowManualBreaks( std::set(maRowManualBreaks) );
1445 }
1446 }
1447
1448 if (bFlagChange)
1449 pDestTab->InvalidatePageBreaks();
1450
1451 if(nFlags & InsertDeleteFlags::ATTRIB)
1452 {
1453 pDestTab->mpCondFormatList->DeleteArea(nCol1, nRow1, nCol2, nRow2);
1454 pDestTab->CopyConditionalFormat(nCol1, nRow1, nCol2, nRow2, 0, 0, this);
1455 }
1456
1457 if(nFlags & InsertDeleteFlags::OUTLINE) // also only when bColRowFlags
1458 pDestTab->SetOutlineTable( pOutlineTable.get() );
1459
1460 if (nFlags & InsertDeleteFlags::SPARKLINES)
1461 {
1462 CopySparklinesToTable(nCol1, nRow1, nCol2, nRow2, pDestTab);
1463 }
1464
1465 if (!bToUndoDoc && bCopyCaptions && (nFlags & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)))
1466 {
1467 bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
1468 CopyCaptionsToTable( nCol1, nRow1, nCol2, nRow2, pDestTab, bCloneCaption);
1469 }
1470}
1471
1472void ScTable::CopySparklinesToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab)
1473{
1474 if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
1475 return;
1476
1477 nCol2 = ClampToAllocatedColumns(nCol2);
1478 for (SCCOL i = nCol1; i <= nCol2; i++)
1479 {
1480 aCol[i].CopyCellSparklinesToDocument(nRow1, nRow2, pDestTab->CreateColumnIfNotExists(i));
1481 }
1482}
1483
1484void ScTable::CopyCaptionsToTable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab,
1485 bool bCloneCaption )
1486{
1487 if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
1488 return;
1489
1490 nCol2 = ClampToAllocatedColumns(nCol2);
1491 for (SCCOL i = nCol1; i <= nCol2; i++)
1492 {
1493 aCol[i].CopyCellNotesToDocument(nRow1, nRow2, pDestTab->CreateColumnIfNotExists(i), bCloneCaption);
1494 pDestTab->aCol[i].UpdateNoteCaptions(nRow1, nRow2);
1495 }
1496}
1497
1499 sc::CopyToDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1500 InsertDeleteFlags nFlags, bool bMarked, ScTable* pDestTab )
1501{
1502 if (!(ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2)))
1503 return;
1504
1505 bool bWidth = (nRow1==0 && nRow2==rDocument.MaxRow() && mpColWidth && pDestTab->mpColWidth);
1506 bool bHeight = (nCol1==0 && nCol2==rDocument.MaxCol() && mpRowHeights && pDestTab->mpRowHeights);
1507
1508 if ((nFlags & InsertDeleteFlags::CONTENTS) && mpRangeName)
1509 {
1510 // Undo sheet-local named expressions created during copying
1511 // formulas. If mpRangeName is not set then the Undo wasn't even
1512 // set to an empty ScRangeName map so don't "undo" that.
1513 pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName())));
1514 if (!pDestTab->rDocument.IsClipOrUndo())
1515 {
1516 ScDocShell* pDocSh = static_cast<ScDocShell*>(pDestTab->rDocument.GetDocumentShell());
1517 if (pDocSh)
1519 }
1520
1521 }
1522
1523 for ( SCCOL i = 0; i < aCol.size(); i++)
1524 {
1525 auto& rDestCol = pDestTab->CreateColumnIfNotExists(i);
1526 if ( i >= nCol1 && i <= nCol2 )
1527 aCol[i].UndoToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rDestCol);
1528 else
1529 aCol[i].CopyToColumn(rCxt, 0, rDocument.MaxRow(), InsertDeleteFlags::FORMULA, false, rDestCol);
1530 }
1531
1532 if (nFlags & InsertDeleteFlags::ATTRIB)
1533 pDestTab->mpCondFormatList.reset(new ScConditionalFormatList(pDestTab->rDocument, *mpCondFormatList));
1534
1535 if (!(bWidth||bHeight))
1536 return;
1537
1538 if (bWidth)
1539 {
1540 pDestTab->mpColWidth->CopyFrom(*mpColWidth, nCol1, nCol2);
1541 pDestTab->SetColManualBreaks( std::set(maColManualBreaks) );
1542 }
1543 if (bHeight)
1544 {
1545 pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
1546 pDestTab->SetRowManualBreaks( std::set(maRowManualBreaks) );
1547 }
1548}
1549
1550void ScTable::CopyUpdated( const ScTable* pPosTab, ScTable* pDestTab ) const
1551{
1552 pDestTab->CreateColumnIfNotExists(aCol.size()-1);
1553 for (SCCOL i=0; i < aCol.size(); i++)
1554 aCol[i].CopyUpdated( pPosTab->FetchColumn(i), pDestTab->aCol[i] );
1555}
1556
1558{
1559 bTableAreaValid = false;
1560 bTableAreaVisibleValid = false;
1561}
1562
1564{
1565 mbPageBreaksValid = false;
1566}
1567
1568void ScTable::CopyScenarioTo( ScTable* pDestTab ) const
1569{
1570 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1571
1572 for (SCCOL i=0; i < aCol.size(); i++)
1574}
1575
1577{
1578 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1579
1580 SCCOL nEndCol = pSrcTab->aCol.size();
1581 CreateColumnIfNotExists(nEndCol);
1582 for (SCCOL i=0; i < nEndCol; i++)
1583 aCol[i].CopyScenarioFrom( pSrcTab->aCol[i] );
1584}
1585
1586void ScTable::MarkScenarioIn( ScMarkData& rDestMark, ScScenarioFlags nNeededBits ) const
1587{
1588 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1589
1590 if ( ( nScenarioFlags & nNeededBits ) != nNeededBits ) // Are all Bits set?
1591 return;
1592
1593 for (SCCOL i=0; i < aCol.size(); i++)
1594 aCol[i].MarkScenarioIn( rDestMark );
1595}
1596
1597bool ScTable::HasScenarioRange( const ScRange& rRange ) const
1598{
1599 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1600
1601 ScRange aTabRange = rRange;
1602 aTabRange.aStart.SetTab( nTab );
1603 aTabRange.aEnd.SetTab( nTab );
1604
1605 const ScRangeList* pList = GetScenarioRanges();
1606
1607 if (pList)
1608 {
1609 for ( size_t j = 0, n = pList->size(); j < n; j++ )
1610 {
1611 const ScRange & rR = (*pList)[j];
1612 if ( rR.Intersects( aTabRange ) )
1613 return true;
1614 }
1615 }
1616
1617 return false;
1618}
1619
1621{
1622 pScenarioRanges.reset();
1623}
1624
1626{
1627 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1628
1629 if (!pScenarioRanges)
1630 {
1631 const_cast<ScTable*>(this)->pScenarioRanges.reset(new ScRangeList);
1633 MarkScenarioIn( aMark, ScScenarioFlags::NONE ); // always
1634 aMark.FillRangeListWithMarks( pScenarioRanges.get(), false );
1635 }
1636 return pScenarioRanges.get();
1637}
1638
1639bool ScTable::TestCopyScenarioTo( const ScTable* pDestTab ) const
1640{
1641 OSL_ENSURE( bScenario, "bScenario == FALSE" );
1642
1643 if (!pDestTab->IsProtected())
1644 return true;
1645
1646 bool bOk = true;
1647 for (SCCOL i=0; i < aCol.size() && bOk; i++)
1648 bOk = aCol[i].TestCopyScenarioTo( pDestTab->aCol[i] );
1649 return bOk;
1650}
1651
1652bool ScTable::SetString( SCCOL nCol, SCROW nRow, SCTAB nTabP, const OUString& rString,
1653 const ScSetStringParam * pParam )
1654{
1655 if (!ValidColRow(nCol,nRow))
1656 {
1657 return false;
1658 }
1659
1661 nRow, nTabP, rString, rDocument.GetAddressConvention(), pParam);
1662}
1663
1664bool ScTable::SetEditText( SCCOL nCol, SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
1665{
1666 if (!ValidColRow(nCol, nRow))
1667 {
1668 return false;
1669 }
1670
1671 CreateColumnIfNotExists(nCol).SetEditText(nRow, std::move(pEditText));
1672 return true;
1673}
1674
1675void ScTable::SetEditText( SCCOL nCol, SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
1676{
1677 if (!ValidColRow(nCol, nRow))
1678 return;
1679
1680 CreateColumnIfNotExists(nCol).SetEditText(nRow, rEditText, pEditPool);
1681}
1682
1683SCROW ScTable::GetFirstEditTextRow( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
1684{
1685 if (!ValidCol(nCol1) || !ValidCol(nCol2) || nCol2 < nCol1)
1686 return -1;
1687
1688 if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow2 < nRow1)
1689 return -1;
1690
1691 nCol2 = ClampToAllocatedColumns(nCol2);
1692 SCROW nFirst = rDocument.MaxRow()+1;
1693 for (SCCOL i = nCol1; i <= nCol2; ++i)
1694 {
1695 const ScColumn& rCol = aCol[i];
1696 SCROW nThisFirst = -1;
1697 if (const_cast<ScColumn&>(rCol).HasEditCells(nRow1, nRow2, nThisFirst))
1698 {
1699 if (nThisFirst == nRow1)
1700 return nRow1;
1701
1702 if (nThisFirst < nFirst)
1703 nFirst = nThisFirst;
1704 }
1705 }
1706
1707 return nFirst == (rDocument.MaxRow()+1) ? -1 : nFirst;
1708}
1709
1711{
1712 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1713 return;
1714
1715 aCol[nCol].Delete(nRow);
1716}
1717
1719 SCCOL nCol, SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
1720{
1721 if (!ValidColRow(nCol, nRow))
1722 return;
1723
1724 CreateColumnIfNotExists(nCol).SetFormula(nRow, rArray, eGram);
1725}
1726
1728 SCCOL nCol, SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
1729{
1730 if (!ValidColRow(nCol, nRow))
1731 return;
1732
1733 CreateColumnIfNotExists(nCol).SetFormula(nRow, rFormula, eGram);
1734}
1735
1737{
1738 if (!ValidColRow(nCol, nRow))
1739 {
1740 delete pCell;
1741 return nullptr;
1742 }
1743
1745}
1746
1747bool ScTable::SetFormulaCells( SCCOL nCol, SCROW nRow, std::vector<ScFormulaCell*>& rCells )
1748{
1749 if (!ValidCol(nCol))
1750 return false;
1751
1752 return CreateColumnIfNotExists(nCol).SetFormulaCells(nRow, rCells);
1753}
1754
1756{
1757 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1758 return svl::SharedString();
1759
1760 return aCol[nCol].GetSharedString(nRow);
1761}
1762
1763void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
1764{
1765 if (ValidColRow(nCol, nRow))
1766 CreateColumnIfNotExists(nCol).SetValue(nRow, rVal);
1767}
1768
1770{
1771 if (ValidColRow(nCol, nRow))
1772 CreateColumnIfNotExists(nCol).SetRawString(nRow, rStr);
1773}
1774
1775OUString ScTable::GetString( SCCOL nCol, SCROW nRow, const ScInterpreterContext* pContext ) const
1776{
1777 if (ValidColRow(nCol,nRow) && nCol < GetAllocatedColumnsCount())
1778 return aCol[nCol].GetString( nRow, pContext );
1779 else
1780 return OUString();
1781}
1782
1783double* ScTable::GetValueCell( SCCOL nCol, SCROW nRow )
1784{
1785 if (!ValidColRow(nCol, nRow))
1786 return nullptr;
1787
1788 return CreateColumnIfNotExists(nCol).GetValueCell(nRow);
1789}
1790
1791OUString ScTable::GetInputString( SCCOL nCol, SCROW nRow, bool bForceSystemLocale ) const
1792{
1793 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
1794 return aCol[nCol].GetInputString( nRow, bForceSystemLocale );
1795 else
1796 return OUString();
1797}
1798
1799double ScTable::GetValue( SCCOL nCol, SCROW nRow ) const
1800{
1801 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
1802 return aCol[nCol].GetValue( nRow );
1803 return 0.0;
1804}
1805
1807{
1808 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1809 return nullptr;
1810
1811 return aCol[nCol].GetEditText(nRow);
1812}
1813
1815{
1816 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1817 return;
1818
1819 return aCol[nCol].RemoveEditTextCharAttribs(nRow, rAttr);
1820}
1821
1822OUString ScTable::GetFormula( SCCOL nCol, SCROW nRow ) const
1823{
1824 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
1825 return aCol[nCol].GetFormula( nRow );
1826 else
1827 return OUString();
1828}
1829
1831{
1832 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1833 return nullptr;
1834
1835 return aCol[nCol].GetFormulaCell(nRow);
1836}
1837
1839{
1840 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
1841 return nullptr;
1842
1843 return aCol[nCol].GetFormulaCell(nRow);
1844}
1845
1846// Sparklines
1847
1848std::shared_ptr<sc::Sparkline> ScTable::GetSparkline(SCCOL nCol, SCROW nRow)
1849{
1850 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1851 return std::shared_ptr<sc::Sparkline>();
1852
1853 sc::SparklineCell* pSparklineCell = aCol[nCol].GetSparklineCell(nRow);
1854 if (!pSparklineCell)
1855 return std::shared_ptr<sc::Sparkline>();
1856
1857 return pSparklineCell->getSparkline();
1858}
1859
1860sc::Sparkline* ScTable::CreateSparkline(SCCOL nCol, SCROW nRow, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup)
1861{
1862 if (!ValidCol(nCol))
1863 return nullptr;
1864
1865 ScColumn& rColumn = CreateColumnIfNotExists(nCol);
1866
1867 std::shared_ptr<sc::Sparkline> pSparkline(new sc::Sparkline(nCol, nRow, pSparklineGroup));
1868 rColumn.CreateSparklineCell(nRow, pSparkline);
1869
1870 return pSparkline.get();
1871}
1872
1874{
1875 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1876 return false;
1877
1878 aCol[nCol].DeleteSparkline(nRow);
1879
1880 return true;
1881}
1882
1884{
1885 return maSparklineList;
1886}
1887
1888// Notes
1889
1890std::unique_ptr<ScPostIt> ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
1891{
1892 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1893 return nullptr;
1894
1895 return aCol[nCol].ReleaseNote(nRow);
1896}
1897
1899{
1900 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1901 return nullptr;
1902 return aCol[nCol].GetCellNote(nRow);
1903}
1904
1905void ScTable::SetNote( SCCOL nCol, SCROW nRow, std::unique_ptr<ScPostIt> pNote )
1906{
1907 if (!ValidColRow(nCol, nRow))
1908 return;
1909
1910 CreateColumnIfNotExists(nCol).SetCellNote(nRow, std::move(pNote));
1911}
1912
1913size_t ScTable::GetNoteCount( SCCOL nCol ) const
1914{
1915 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1916 return 0;
1917
1918 return aCol[nCol].GetNoteCount();
1919}
1920
1921SCROW ScTable::GetNotePosition( SCCOL nCol, size_t nIndex ) const
1922{
1923 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
1924 return -1;
1925
1926 return aCol[nCol].GetNotePosition(nIndex);
1927}
1928
1930{
1931 for (SCCOL i = 0; i < aCol.size(); ++i)
1933}
1934
1935void ScTable::ForgetNoteCaptions( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bPreserveData )
1936{
1937 if (!ValidCol(nCol1) || !ValidCol(nCol2))
1938 return;
1939 if ( nCol2 >= aCol.size() ) nCol2 = aCol.size() - 1;
1940 for (SCCOL i = nCol1; i <= nCol2; ++i)
1941 aCol[i].ForgetNoteCaptions(nRow1, nRow2, bPreserveData);
1942}
1943
1944void ScTable::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
1945{
1946 for (SCCOL nCol = 0; nCol < aCol.size(); ++nCol)
1947 aCol[nCol].GetAllNoteEntries(rNotes);
1948}
1949
1950void ScTable::GetNotesInRange( const ScRange& rRange, std::vector<sc::NoteEntry>& rNotes ) const
1951{
1952 SCROW nStartRow = rRange.aStart.Row();
1953 SCROW nEndRow = rRange.aEnd.Row();
1954 SCCOL nEndCol = ClampToAllocatedColumns(rRange.aEnd.Col());
1955 for (SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; ++nCol)
1956 {
1957 aCol[nCol].GetNotesInRange(nStartRow, nEndRow, rNotes);
1958 }
1959}
1960
1961CommentCaptionState ScTable::GetAllNoteCaptionsState(const ScRange& rRange, std::vector<sc::NoteEntry>& rNotes )
1962{
1963 SCROW nStartRow = rRange.aStart.Row();
1964 SCROW nEndRow = rRange.aEnd.Row();
1965 bool bIsFirstNoteShownState = true; // because of error: -Werror=maybe-uninitialized
1966 bool bFirstControl = true;
1967
1969 assert(pTab);
1970 const SCCOL nEndCol = pTab->ClampToAllocatedColumns(rRange.aEnd.Col());
1971 for (SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; ++nCol)
1972 {
1973 if (bFirstControl && rDocument.HasColNotes(nCol, nTab)) // detect status of first note caption
1974 {
1975 aCol[nCol].GetNotesInRange(nStartRow, nEndRow, rNotes);
1976 bIsFirstNoteShownState = rNotes.begin()->mpNote->IsCaptionShown();
1977 bFirstControl = false;
1978 }
1979
1980 if (rDocument.HasColNotes(nCol, nTab))
1981 {
1982 aCol[nCol].GetNotesInRange(nStartRow, nEndRow, rNotes);
1983
1984 bool bIsMixedState = std::any_of(rNotes.begin(), rNotes.end(), [bIsFirstNoteShownState](const sc::NoteEntry& rNote) {
1985 // compare the first note caption with others
1986 return bIsFirstNoteShownState != rNote.mpNote->IsCaptionShown(); });
1987 if (bIsMixedState)
1989 }
1990 }
1991 return bIsFirstNoteShownState ? CommentCaptionState::ALLSHOWN : CommentCaptionState::ALLHIDDEN;
1992}
1993
1995{
1996 for (auto const & pCol : aCol)
1997 pCol->GetUnprotectedCells(0, rDocument.MaxRow(), rRangeList);
1998}
1999
2000bool ScTable::ContainsNotesInRange( const ScRange& rRange ) const
2001{
2002 SCROW nStartRow = rRange.aStart.Row();
2003 SCROW nEndRow = rRange.aEnd.Row();
2004 SCCOL nEndCol = ClampToAllocatedColumns(rRange.aEnd.Col());
2005 for (SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; ++nCol)
2006 {
2007 bool bContainsNote = !aCol[nCol].IsNotesEmptyBlock(nStartRow, nEndRow);
2008 if(bContainsNote)
2009 return true;
2010 }
2011
2012 return false;
2013}
2014
2016{
2017 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
2018 return aCol[nCol].GetCellType( nRow );
2019 return CELLTYPE_NONE;
2020}
2021
2023{
2024 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
2025 return ScRefCellValue();
2026
2027 return aCol[nCol].GetCellValue(nRow);
2028}
2029
2031{
2032 if (!ValidColRow(nCol, nRow) || nCol >= GetAllocatedColumnsCount())
2033 return ScRefCellValue();
2034
2035 return aCol[nCol].GetCellValue(rBlockPos, nRow);
2036}
2037
2038void ScTable::GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const
2039{
2040 rCol = 0;
2041 rRow = rDocument.MaxRow()+1;
2042 while (rCol < (aCol.size() - 1) && aCol[rCol].IsEmptyData() )
2043 ++rCol;
2044 SCCOL nCol = rCol;
2045 while (nCol < aCol.size() && rRow > 0)
2046 {
2047 if (!aCol[nCol].IsEmptyData())
2048 rRow = ::std::min( rRow, aCol[nCol].GetFirstDataPos());
2049 ++nCol;
2050 }
2051}
2052
2053void ScTable::GetLastDataPos(SCCOL& rCol, SCROW& rRow) const
2054{
2055 rCol = aCol.size() - 1;
2056 rRow = 0;
2057 while (aCol[rCol].IsEmptyData() && (rCol > 0))
2058 rCol--;
2059 SCCOL nCol = rCol;
2060 while (nCol >= 0 && rRow < rDocument.MaxRow())
2061 rRow = ::std::max( rRow, aCol[nCol--].GetLastDataPos());
2062}
2063
2064bool ScTable::HasData( SCCOL nCol, SCROW nRow ) const
2065{
2066 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
2067 return aCol[nCol].HasDataAt( nRow );
2068 else
2069 return false;
2070}
2071
2072bool ScTable::HasStringData( SCCOL nCol, SCROW nRow ) const
2073{
2074 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
2075 return aCol[nCol].HasStringData( nRow );
2076 else
2077 return false;
2078}
2079
2080bool ScTable::HasValueData( SCCOL nCol, SCROW nRow ) const
2081{
2082 if (ValidColRow(nCol, nRow) && nCol < GetAllocatedColumnsCount())
2083 return aCol[nCol].HasValueData( nRow );
2084 else
2085 return false;
2086}
2087
2088bool ScTable::HasStringCells( SCCOL nStartCol, SCROW nStartRow,
2089 SCCOL nEndCol, SCROW nEndRow ) const
2090{
2091 if (ValidCol(nEndCol))
2092 {
2093 nEndCol = ClampToAllocatedColumns(nEndCol);
2094 for (SCCOL nCol = nStartCol; nCol <= nEndCol; nCol++)
2095 if (aCol[nCol].HasStringCells(nStartRow, nEndRow))
2096 return true;
2097 }
2098
2099 return false;
2100}
2101
2103{
2104 for (SCCOL i=0; i < aCol.size(); i++)
2105 aCol[i].SetDirtyVar();
2106}
2107
2109{
2110 sc::AutoCalcSwitch aACSwitch(rDocument, false);
2111
2112 for (SCCOL i = 0; i < aCol.size(); i++)
2114}
2115
2117{
2118 sc::AutoCalcSwitch aACSwitch(rDocument, false);
2119
2120 for (SCCOL i=0; i < aCol.size(); i++)
2121 aCol[i].SetAllFormulasDirty(rCxt);
2122}
2123
2125{
2126 sc::AutoCalcSwitch aSwitch(rDocument, false);
2127 SCCOL nCol2 = rRange.aEnd.Col();
2128 nCol2 = ClampToAllocatedColumns(nCol2);
2129 for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
2130 aCol[i].SetDirty(rRange.aStart.Row(), rRange.aEnd.Row(), eMode);
2131}
2132
2134{
2135 sc::AutoCalcSwitch aSwitch(rDocument, false);
2136 const SCCOL nCol2 = ClampToAllocatedColumns(rRange.aEnd.Col());
2137 for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
2138 aCol[i].SetTableOpDirty( rRange );
2139}
2140
2142{
2143 sc::AutoCalcSwitch aSwitch(rDocument, false);
2144 for (SCCOL i=0; i < aCol.size(); i++)
2146}
2147
2149{
2150 sc::AutoCalcSwitch aSwitch(rDocument, false);
2151 ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged);
2152 for (SCCOL i=0; i < aCol.size(); i++)
2154}
2155
2157{
2158 sc::AutoCalcSwitch aSwitch(rDocument, false);
2159 for (SCCOL i = 0; i < aCol.size(); ++i)
2161}
2162
2163bool ScTable::BroadcastBroadcasters( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SfxHintId nHint )
2164{
2165 bool bBroadcasted = false;
2166 sc::AutoCalcSwitch aSwitch(rDocument, false);
2167 nCol2 = ClampToAllocatedColumns(nCol2);
2168 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2169 bBroadcasted |= aCol[nCol].BroadcastBroadcasters( nRow1, nRow2, nHint);
2170 return bBroadcasted;
2171}
2172
2173void ScTable::SetLoadingMedium(bool bLoading)
2174{
2175 mpRowHeights->enableTreeSearch(!bLoading);
2176}
2177
2179{
2180 for (SCCOL i=0; i < aCol.size(); i++)
2181 aCol[i].CalcAll();
2182
2183 mpCondFormatList->CalcAll();
2184}
2185
2187{
2188 for (SCCOL i = 0; i < aCol.size(); ++i)
2189 aCol[i].CompileAll(rCxt);
2190
2192 mpCondFormatList->CompileAll();
2193}
2194
2196{
2197 if (mpRangeName)
2198 mpRangeName->CompileUnresolvedXML(rCxt);
2199
2200 for (SCCOL i=0; i < aCol.size(); i++)
2201 {
2202 aCol[i].CompileXML(rCxt, rProgress);
2203 }
2204
2206 mpCondFormatList->CompileXML();
2207}
2208
2210{
2211 bool bCompiled = false;
2212 for (SCCOL i = 0; i < aCol.size(); ++i)
2213 {
2214 if (aCol[i].CompileErrorCells(rCxt, nErrCode))
2215 bCompiled = true;
2216 }
2217
2218 return bCompiled;
2219}
2220
2221void ScTable::CalcAfterLoad( sc::CompileFormulaContext& rCxt, bool bStartListening )
2222{
2223 for (SCCOL i = 0; i < aCol.size(); ++i)
2224 aCol[i].CalcAfterLoad(rCxt, bStartListening);
2225}
2226
2227void ScTable::ResetChanged( const ScRange& rRange )
2228{
2229 SCCOL nStartCol = rRange.aStart.Col();
2230 SCROW nStartRow = rRange.aStart.Row();
2231 SCCOL nEndCol = ClampToAllocatedColumns(rRange.aEnd.Col());
2232 SCROW nEndRow = rRange.aEnd.Row();
2233
2234 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2235 aCol[nCol].ResetChanged(nStartRow, nEndRow);
2236}
2237
2238// Attribute
2239
2240const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich ) const
2241{
2242 if (!ValidColRow(nCol, nRow))
2243 return nullptr;
2244 return &ColumnData(nCol).GetAttr( nRow, nWhich );
2245}
2246
2247const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich, SCROW& nStartRow, SCROW& nEndRow ) const
2248{
2249 if (!ValidColRow(nCol, nRow))
2250 return nullptr;
2251 return &ColumnData(nCol).GetAttr( nRow, nWhich, nStartRow, nEndRow );
2252}
2253
2254sal_uInt32 ScTable::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const
2255{
2256 if (ValidColRow(rPos.Col(), rPos.Row()))
2257 return ColumnData(rPos.Col()).GetNumberFormat(rContext, rPos.Row());
2258 return 0;
2259}
2260
2261sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nRow ) const
2262{
2264}
2265
2266sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
2267{
2268 if (!ValidCol(nCol) || !ValidRow(nStartRow) || !ValidRow(nEndRow))
2269 return 0;
2270
2271 return ColumnData(nCol).GetNumberFormat(nStartRow, nEndRow);
2272}
2273
2274void ScTable::SetNumberFormat( SCCOL nCol, SCROW nRow, sal_uInt32 nNumberFormat )
2275{
2276 if (!ValidColRow(nCol, nRow))
2277 return;
2278
2279 CreateColumnIfNotExists(nCol).SetNumberFormat(nRow, nNumberFormat);
2280}
2281
2283{
2284 if (!ValidColRow(nCol,nRow))
2285 return nullptr;
2286 return ColumnData(nCol).GetPattern( nRow );
2287}
2288
2289const ScPatternAttr* ScTable::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
2290{
2291 if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow))
2292 return ColumnData(nCol).GetMostUsedPattern( nStartRow, nEndRow );
2293 return nullptr;
2294}
2295
2296bool ScTable::HasAttrib( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, HasAttrFlags nMask ) const
2297{
2298 for(SCCOL nCol = nCol1; nCol <= nCol2 && nCol < aCol.size(); ++nCol )
2299 if( aCol[nCol].HasAttrib( nRow1, nRow2, nMask ))
2300 return true;
2301 if( nCol2 >= aCol.size())
2302 return aDefaultColData.HasAttrib( nRow1, nRow2, nMask );
2303 return false;
2304}
2305
2306bool ScTable::HasAttrib( SCCOL nCol, SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow, SCROW* nEndRow ) const
2307{
2308 return ColumnData(nCol).HasAttrib( nRow, nMask, nStartRow, nEndRow );
2309}
2310
2311bool ScTable::HasAttribSelection( const ScMarkData& rMark, HasAttrFlags nMask ) const
2312{
2313 std::vector<sc::ColRowSpan> aSpans = rMark.GetMarkedColSpans();
2314
2315 for (const sc::ColRowSpan & aSpan : aSpans)
2316 {
2317 for (SCCOLROW j = aSpan.mnStart; j <= aSpan.mnEnd; ++j)
2318 {
2319 if (aCol[j].HasAttribSelection(rMark, nMask))
2320 return true;
2321 }
2322 }
2323 return false;
2324}
2325
2326bool ScTable::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
2327 SCCOL& rEndCol, SCROW& rEndRow,
2328 bool bRefresh )
2329{
2330 if (!(ValidCol(nStartCol) && ValidCol(rEndCol)))
2331 {
2332 OSL_FAIL("ScTable::ExtendMerge: invalid column number");
2333 return false;
2334 }
2335 if( rEndCol >= aCol.size())
2336 assert( !aDefaultColData.GetAttr( nStartRow, ATTR_MERGE ).IsMerged());
2337 bool bFound = false;
2338 SCCOL nOldEndX = ClampToAllocatedColumns(rEndCol);
2339 SCROW nOldEndY = rEndRow;
2340 for (SCCOL i=nStartCol; i<=nOldEndX; i++)
2341 bFound |= aCol[i].ExtendMerge( i, nStartRow, nOldEndY, rEndCol, rEndRow, bRefresh );
2342 return bFound;
2343}
2344
2345void ScTable::SetMergedCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2346{
2347 ScMergeAttr aAttr(nCol2-nCol1+1, nRow2-nRow1+1);
2348 ApplyAttr(nCol1, nRow1, aAttr);
2349
2350 if (nCol1 < nCol2)
2351 ApplyFlags(nCol1+1, nRow1, nCol2, nRow2, ScMF::Hor);
2352
2353 if (nRow1 < nRow2)
2354 ApplyFlags(nCol1, nRow1+1, nCol1, nRow2, ScMF::Ver);
2355
2356 if (nCol1 < nCol2 && nRow1 < nRow2)
2357 ApplyFlags(nCol1+1, nRow1+1, nCol2, nRow2, ScMF::Hor | ScMF::Ver);
2358}
2359
2360bool ScTable::IsBlockEmpty( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
2361{
2362 if (!(ValidCol(nCol1) && ValidCol(nCol2)))
2363 {
2364 OSL_FAIL("ScTable::IsBlockEmpty: invalid column number");
2365 return false;
2366 }
2367 nCol2 = ClampToAllocatedColumns(nCol2);
2368 bool bEmpty = true;
2369 for (SCCOL i=nCol1; i<=nCol2 && bEmpty; i++)
2370 {
2371 bEmpty = aCol[i].IsEmptyData( nRow1, nRow2 );
2372 if (bEmpty)
2373 {
2374 bEmpty = aCol[i].IsSparklinesEmptyBlock(nRow1, nRow2);
2375 }
2376 if (bEmpty)
2377 {
2378 bEmpty = aCol[i].IsNotesEmptyBlock(nRow1, nRow2);
2379 }
2380 }
2381 return bEmpty;
2382}
2383
2384SCSIZE ScTable::FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2,
2385 SCCOL nCol, SCROW nAttrRow1, SCROW nAttrRow2, SCSIZE nArrY,
2386 const ScPatternAttr* pPattern, const SfxItemSet* pCondSet )
2387{
2388 // Return value = new nArrY
2389
2390 ScRotateDir nRotDir = pPattern->GetRotateDir( pCondSet );
2391 if ( nRotDir != ScRotateDir::NONE )
2392 {
2393 bool bHit = true;
2394 if ( nCol+1 < nX1 ) // column to the left
2395 bHit = ( nRotDir != ScRotateDir::Left );
2396 else if ( nCol > nX2+1 ) // column to the right
2397 bHit = ( nRotDir != ScRotateDir::Right ); // ScRotateDir::Standard may now also be extended to the left
2398
2399 if ( bHit )
2400 {
2401 double nFactor = 0.0;
2402 if ( nCol > nX2+1 )
2403 {
2404 Degree100 nRotVal = pPattern->
2405 GetItem( ATTR_ROTATE_VALUE, pCondSet ).GetValue();
2406 double nRealOrient = toRadians(nRotVal);
2407 double nCos = cos( nRealOrient );
2408 double nSin = sin( nRealOrient );
2409 //TODO: limit !!!
2410 //TODO: additional factor for varying PPT X/Y !!!
2411
2412 // for ScRotateDir::Left this gives a negative value,
2413 // if the mode is considered
2414 nFactor = -fabs( nCos / nSin );
2415 }
2416
2417 for ( SCROW nRow = nAttrRow1; nRow <= nAttrRow2; nRow++ )
2418 {
2419 if (!RowHidden(nRow))
2420 {
2421 bool bHitOne = true;
2422 if ( nCol > nX2+1 )
2423 {
2424 // Does the rotated cell extend into the visible range?
2425
2426 SCCOL nTouchedCol = nCol;
2427 tools::Long nWidth = static_cast<tools::Long>(mpRowHeights->getValue(nRow) * nFactor);
2428 OSL_ENSURE(nWidth <= 0, "Wrong direction");
2429 while ( nWidth < 0 && nTouchedCol > 0 )
2430 {
2431 --nTouchedCol;
2432 nWidth += GetColWidth( nTouchedCol );
2433 }
2434 if ( nTouchedCol > nX2 )
2435 bHitOne = false;
2436 }
2437
2438 if (bHitOne)
2439 {
2440 while ( nArrY<nArrCount && pRowInfo[nArrY].nRowNo < nRow )
2441 ++nArrY;
2442 if ( nArrY<nArrCount && pRowInfo[nArrY].nRowNo == nRow )
2443 pRowInfo[nArrY].nRotMaxCol = nCol;
2444 }
2445 }
2446 }
2447 }
2448 }
2449
2450 return nArrY;
2451}
2452
2453void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2 )
2454{
2455 if ( !mpColWidth || !mpRowHeights || !mpColFlags || !pRowFlags )
2456 {
2457 OSL_FAIL( "Row/column info missing" );
2458 return;
2459 }
2460
2461 // nRotMaxCol is initialized to SC_ROTMAX_NONE, nRowNo is already set
2462
2463 SCROW nY1 = pRowInfo[0].nRowNo;
2464 SCROW nY2 = pRowInfo[nArrCount-1].nRowNo;
2465
2466 for (SCCOL nCol : GetColumnsRange(0, rDocument.MaxCol()))
2467 {
2468 if (!ColHidden(nCol))
2469 {
2470 SCSIZE nArrY = 0;
2471 ScDocAttrIterator aIter( rDocument, nTab, nCol, nY1, nCol, nY2 );
2472 SCCOL nAttrCol;
2473 SCROW nAttrRow1, nAttrRow2;
2474 const ScPatternAttr* pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
2475 while ( pPattern )
2476 {
2477 if ( const ScCondFormatItem* pCondItem = pPattern->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL ) )
2478 {
2479 // Run through all formats, so that each cell does not have to be
2480 // handled individually
2481
2482 const ScCondFormatIndexes& rCondFormatData = pCondItem->GetCondFormatData();
2484 if (mpCondFormatList && pStylePool && !rCondFormatData.empty())
2485 {
2486 for(const auto& rItem : rCondFormatData)
2487 {
2488 const ScConditionalFormat* pFormat = mpCondFormatList->GetFormat(rItem);
2489 if ( pFormat )
2490 {
2491 size_t nEntryCount = pFormat->size();
2492 for (size_t nEntry=0; nEntry<nEntryCount; nEntry++)
2493 {
2494 const ScFormatEntry* pEntry = pFormat->GetEntry(nEntry);
2495 if(pEntry->GetType() != ScFormatEntry::Type::Condition &&
2497 continue;
2498
2499 OUString aStyleName = static_cast<const ScCondFormatEntry*>(pEntry)->GetStyle();
2500 if (!aStyleName.isEmpty())
2501 {
2502 SfxStyleSheetBase* pStyleSheet =
2503 pStylePool->Find( aStyleName, SfxStyleFamily::Para );
2504 if ( pStyleSheet )
2505 {
2506 FillMaxRot( pRowInfo, nArrCount, nX1, nX2,
2507 nCol, nAttrRow1, nAttrRow2,
2508 nArrY, pPattern, &pStyleSheet->GetItemSet() );
2509 // not changing nArrY
2510 }
2511 }
2512 }
2513 }
2514 }
2515 }
2516 }
2517
2518 nArrY = FillMaxRot( pRowInfo, nArrCount, nX1, nX2,
2519 nCol, nAttrRow1, nAttrRow2,
2520 nArrY, pPattern, nullptr );
2521
2522 pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
2523 }
2524 }
2525 }
2526}
2527
2528bool ScTable::HasBlockMatrixFragment( const SCCOL nCol1, SCROW nRow1, const SCCOL nCol2, SCROW nRow2,
2529 bool bNoMatrixAtAll ) const
2530{
2531 using namespace sc;
2532
2533 if ( !IsColValid( nCol1 ) )
2534 return false;
2535
2536 const SCCOL nMaxCol2 = std::min<SCCOL>( nCol2, aCol.size() - 1 );
2537
2538 MatrixEdge nEdges = MatrixEdge::Nothing;
2539
2540 if ( nCol1 == nMaxCol2 )
2541 { // left and right column
2543 nEdges = aCol[nCol1].GetBlockMatrixEdges( nRow1, nRow2, n, bNoMatrixAtAll );
2544 if ((nEdges != MatrixEdge::Nothing) && (((nEdges & n)!=n) || (nEdges & (MatrixEdge::Inside|MatrixEdge::Open))))
2545 return true; // left or right edge is missing or open
2546 }
2547 else
2548 { // left column
2549 nEdges = aCol[nCol1].GetBlockMatrixEdges(nRow1, nRow2, MatrixEdge::Left, bNoMatrixAtAll);
2550 if ((nEdges != MatrixEdge::Nothing) && ((!(nEdges & MatrixEdge::Left)) || (nEdges & (MatrixEdge::Inside|MatrixEdge::Open))))
2551 return true; // left edge missing or open
2552 // right column
2553 nEdges = aCol[nMaxCol2].GetBlockMatrixEdges(nRow1, nRow2, MatrixEdge::Right, bNoMatrixAtAll);
2554 if ((nEdges != MatrixEdge::Nothing) && ((!(nEdges & MatrixEdge::Right)) || (nEdges & (MatrixEdge::Inside|MatrixEdge::Open))))
2555 return true; // right edge is missing or open
2556 }
2557
2558 if (bNoMatrixAtAll)
2559 {
2560 for (SCCOL i=nCol1; i<=nMaxCol2; i++)
2561 {
2562 nEdges = aCol[i].GetBlockMatrixEdges( nRow1, nRow2, MatrixEdge::Nothing, bNoMatrixAtAll);
2563 if (nEdges != MatrixEdge::Nothing
2564 && (nEdges != (MatrixEdge::Top | MatrixEdge::Left | MatrixEdge::Bottom | MatrixEdge::Right)))
2565 return true;
2566 }
2567 }
2568 else if ( nRow1 == nRow2 )
2569 { // Row on top and on bottom
2570 bool bOpen = false;
2571 const MatrixEdge n = MatrixEdge::Bottom | MatrixEdge::Top;
2572 for ( SCCOL i=nCol1; i<=nMaxCol2; i++)
2573 {
2574 nEdges = aCol[i].GetBlockMatrixEdges( nRow1, nRow1, n, bNoMatrixAtAll );
2575 if (nEdges != MatrixEdge::Nothing)
2576 {
2577 if ( (nEdges & n) != n )
2578 return true; // Top or bottom edge missing
2579 if (nEdges & MatrixEdge::Left)
2580 bOpen = true; // left edge open, continue
2581 else if ( !bOpen )
2582 return true; // Something exist that has not been opened
2583 if (nEdges & MatrixEdge::Right)
2584 bOpen = false; // Close right edge
2585 }
2586 }
2587 if ( bOpen )
2588 return true;
2589 }
2590 else
2591 {
2592 int j;
2593 MatrixEdge n;
2594 SCROW nR;
2595 // first top row, then bottom row
2596 for ( j=0, n = MatrixEdge::Top, nR=nRow1; j<2;
2597 j++, n = MatrixEdge::Bottom, nR=nRow2)
2598 {
2599 bool bOpen = false;
2600 for ( SCCOL i=nCol1; i<=nMaxCol2; i++)
2601 {
2602 nEdges = aCol[i].GetBlockMatrixEdges( nR, nR, n, bNoMatrixAtAll );
2603 if ( nEdges != MatrixEdge::Nothing)
2604 {
2605 // in top row no top edge respectively
2606 // in bottom row no bottom edge
2607 if ( (nEdges & n) != n )
2608 return true;
2609 if (nEdges & MatrixEdge::Left)
2610 bOpen = true; // open left edge, continue
2611 else if ( !bOpen )
2612 return true; // Something exist that has not been opened
2613 if (nEdges & MatrixEdge::Right)
2614 bOpen = false; // Close right edge
2615 }
2616 }
2617 if ( bOpen )
2618 return true;
2619 }
2620 }
2621 return false;
2622}
2623
2625{
2626 std::vector<sc::ColRowSpan> aSpans = rMark.GetMarkedColSpans();
2627 ScRangeList rangeList = rMark.GetMarkedRanges();
2628
2629 for (const sc::ColRowSpan & aSpan : aSpans)
2630 {
2631 SCCOL nEndCol = ClampToAllocatedColumns(aSpan.mnEnd);
2632 for ( SCCOLROW j=aSpan.mnStart; j<=nEndCol; j++ )
2633 {
2634 if ( aCol[j].HasSelectionMatrixFragment(rMark, rangeList) )
2635 return true;
2636 }
2637 }
2638 return false;
2639}
2640
2641bool ScTable::IsBlockEditable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2,
2642 SCROW nRow2, bool* pOnlyNotBecauseOfMatrix /* = NULL */,
2643 bool bNoMatrixAtAll ) const
2644{
2645 if ( !ValidColRow( nCol2, nRow2 ) )
2646 {
2647 SAL_WARN("sc", "IsBlockEditable: invalid column or row " << nCol2 << " " << nRow2);
2648 if (pOnlyNotBecauseOfMatrix)
2649 *pOnlyNotBecauseOfMatrix = false;
2650 return false;
2651 }
2652
2653 bool bIsEditable = true;
2654 if ( nLockCount )
2655 bIsEditable = false;
2656 else if ( IsProtected() && !rDocument.IsScenario(nTab) )
2657 {
2658 bIsEditable = !HasAttrib( nCol1, nRow1, nCol2, nRow2, HasAttrFlags::Protected );
2659 if (!bIsEditable)
2660 {
2661 // An enhanced protection permission may override the attribute.
2662 if (pTabProtection)
2663 bIsEditable = pTabProtection->isBlockEditable( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab));
2664 }
2665 if (bIsEditable)
2666 {
2667 // If Sheet is protected and cells are not protected then
2668 // check the active scenario protect flag if this range is
2669 // on the active scenario range. Note the 'copy back' must also
2670 // be set to apply protection.
2671 sal_uInt16 nScenTab = nTab+1;
2672 while(rDocument.IsScenario(nScenTab))
2673 {
2674 ScRange aEditRange(nCol1, nRow1, nScenTab, nCol2, nRow2, nScenTab);
2675 if(rDocument.IsActiveScenario(nScenTab) && rDocument.HasScenarioRange(nScenTab, aEditRange))
2676 {
2677 ScScenarioFlags nFlags;
2678 rDocument.GetScenarioFlags(nScenTab,nFlags);
2679 bIsEditable = !((nFlags & ScScenarioFlags::Protected) && (nFlags & ScScenarioFlags::TwoWay));
2680 break;
2681 }
2682 nScenTab++;
2683 }
2684 }
2685 }
2686 else if (rDocument.IsScenario(nTab))
2687 {
2688 // Determine if the preceding sheet is protected
2689 SCTAB nActualTab = nTab;
2690 do
2691 {
2692 nActualTab--;
2693 }
2694 while(rDocument.IsScenario(nActualTab));
2695
2696 if(rDocument.IsTabProtected(nActualTab))
2697 {
2698 ScRange aEditRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
2699 if(rDocument.HasScenarioRange(nTab, aEditRange))
2700 {
2701 ScScenarioFlags nFlags;
2703 bIsEditable = !(nFlags & ScScenarioFlags::Protected);
2704 }
2705 }
2706 }
2707 if ( bIsEditable )
2708 {
2709 if (HasBlockMatrixFragment( nCol1, nRow1, nCol2, nRow2, bNoMatrixAtAll))
2710 {
2711 bIsEditable = false;
2712 if ( pOnlyNotBecauseOfMatrix )
2713 *pOnlyNotBecauseOfMatrix = true;
2714 }
2715 else if ( pOnlyNotBecauseOfMatrix )
2716 *pOnlyNotBecauseOfMatrix = false;
2717 }
2718 else if ( pOnlyNotBecauseOfMatrix )
2719 *pOnlyNotBecauseOfMatrix = false;
2720 return bIsEditable;
2721}
2722
2724 bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
2725{
2726 bool bIsEditable = true;
2727 if ( nLockCount )
2728 bIsEditable = false;
2729 else if ( IsProtected() && !rDocument.IsScenario(nTab) )
2730 {
2731 ScRangeList aRanges;
2732 rMark.FillRangeListWithMarks( &aRanges, false );
2733 bIsEditable = !HasAttribSelection( rMark, HasAttrFlags::Protected );
2734 if (!bIsEditable)
2735 {
2736 // An enhanced protection permission may override the attribute.
2737 if (pTabProtection)
2738 bIsEditable = pTabProtection->isSelectionEditable( aRanges);
2739 }
2740 if (bIsEditable)
2741 {
2742 // If Sheet is protected and cells are not protected then
2743 // check the active scenario protect flag if this area is
2744 // in the active scenario range.
2745 SCTAB nScenTab = nTab+1;
2746 while(rDocument.IsScenario(nScenTab) && bIsEditable)
2747 {
2748 if(rDocument.IsActiveScenario(nScenTab))
2749 {
2750 for (size_t i=0, nRange = aRanges.size(); (i < nRange) && bIsEditable; i++ )
2751 {
2752 const ScRange & rRange = aRanges[ i ];
2753 if(rDocument.HasScenarioRange(nScenTab, rRange))
2754 {
2755 ScScenarioFlags nFlags;
2756 rDocument.GetScenarioFlags(nScenTab,nFlags);
2757 bIsEditable = !((nFlags & ScScenarioFlags::Protected) && (nFlags & ScScenarioFlags::TwoWay));
2758 }
2759 }
2760 }
2761 nScenTab++;
2762 }
2763 }
2764 }
2765 else if (rDocument.IsScenario(nTab))
2766 {
2767 // Determine if the preceding sheet is protected
2768 SCTAB nActualTab = nTab;
2769 do
2770 {
2771 nActualTab--;
2772 }
2773 while(rDocument.IsScenario(nActualTab));
2774
2775 if(rDocument.IsTabProtected(nActualTab))
2776 {
2777 ScRangeList aRanges;
2778 rMark.FillRangeListWithMarks( &aRanges, false );
2779 for (size_t i = 0, nRange = aRanges.size(); (i < nRange) && bIsEditable; i++)
2780 {
2781 const ScRange & rRange = aRanges[ i ];
2782 if(rDocument.HasScenarioRange(nTab, rRange))
2783 {
2784 ScScenarioFlags nFlags;
2786 bIsEditable = !(nFlags & ScScenarioFlags::Protected);
2787 }
2788 }
2789 }
2790 }
2791 if ( bIsEditable )
2792 {
2793 if ( HasSelectionMatrixFragment( rMark ) )
2794 {
2795 bIsEditable = false;
2796 if ( pOnlyNotBecauseOfMatrix )
2797 *pOnlyNotBecauseOfMatrix = true;
2798 }
2799 else if ( pOnlyNotBecauseOfMatrix )
2800 *pOnlyNotBecauseOfMatrix = false;
2801 }
2802 else if ( pOnlyNotBecauseOfMatrix )
2803 *pOnlyNotBecauseOfMatrix = false;
2804 return bIsEditable;
2805}
2806
2808{
2809 ++nLockCount;
2810}
2811
2813{
2814 if (nLockCount)
2815 --nLockCount;
2816 else
2817 {
2818 OSL_FAIL("UnlockTable without LockTable");
2819 }
2820}
2821
2822void ScTable::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
2823{
2824 std::vector<sc::ColRowSpan> aSpans = rMark.GetMarkedColSpans();
2825
2826 for (const sc::ColRowSpan & rSpan : aSpans)
2827 {
2828 SCCOL maxCol = ClampToAllocatedColumns(rSpan.mnEnd);
2829 for (SCCOL i = rSpan.mnStart; i <= maxCol; ++i)
2830 {
2831 aCol[i].MergeSelectionPattern( rState, rMark, bDeep );
2832 }
2833 }
2834}
2835
2837 SCCOL nCol2, SCROW nRow2, bool bDeep ) const
2838{
2839 const SCCOL nEndCol = ClampToAllocatedColumns(nCol2);
2840 for (SCCOL i=nCol1; i<=nEndCol; i++)
2841 aCol[i].MergePatternArea( rState, nRow1, nRow2, bDeep );
2842 if (nEndCol != nCol2)
2843 aDefaultColData.MergePatternArea( rState, nRow1, nRow2, bDeep );
2844}
2845
2846void ScTable::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, ScLineFlags& rFlags,
2847 SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const
2848{
2849 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
2850 {
2851 PutInOrder(nStartCol, nEndCol);
2852 PutInOrder(nStartRow, nEndRow);
2853 nEndCol = ClampToAllocatedColumns(nEndCol);
2854 for (SCCOL i=nStartCol; i<=nEndCol; i++)
2855 aCol[i].MergeBlockFrame( pLineOuter, pLineInner, rFlags,
2856 nStartRow, nEndRow, (i==nStartCol), nEndCol-i );
2857 }
2858}
2859
2860void ScTable::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
2861 SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow)
2862{
2863 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
2864 {
2865 PutInOrder(nStartCol, nEndCol);
2866 PutInOrder(nStartRow, nEndRow);
2867 CreateColumnIfNotExists(nEndCol);
2868 for (SCCOL i=nStartCol; i<=nEndCol; i++)
2869 aCol[i].ApplyBlockFrame(rLineOuter, pLineInner,
2870 nStartRow, nEndRow, (i==nStartCol), nEndCol-i);
2871 }
2872}
2873
2874void ScTable::ApplyPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr )
2875{
2876 if (ValidColRow(nCol,nRow))
2877 CreateColumnIfNotExists(nCol).ApplyPattern( nRow, rAttr );
2878}
2879
2880void ScTable::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2881 const ScPatternAttr& rAttr, ScEditDataArray* pDataArray,
2882 bool* const pIsChanged )
2883{
2884 if (!ValidColRow(nStartCol, nStartRow) || !ValidColRow(nEndCol, nEndRow))
2885 return;
2886 PutInOrder(nStartCol, nEndCol);
2887 PutInOrder(nStartRow, nEndRow);
2888 SCCOL maxCol = nEndCol;
2889 if( nEndCol == GetDoc().MaxCol())
2890 {
2891 // For the same unallocated columns until the end we can change just the default.
2892 maxCol = std::max( nStartCol, aCol.size()) - 1;
2893 if( maxCol >= 0 )
2894 CreateColumnIfNotExists(maxCol); // Allocate needed different columns before changing the default.
2895 aDefaultColData.ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
2896 }
2897 for (SCCOL i = nStartCol; i <= maxCol; i++)
2898 CreateColumnIfNotExists(i).ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
2899}
2900
2901namespace
2902{
2903 std::vector<ScAttrEntry> duplicateScAttrEntries(ScDocument& rDocument, const std::vector<ScAttrEntry>& rOrigData)
2904 {
2905 std::vector<ScAttrEntry> aData(rOrigData);
2906 for (size_t nIdx = 0; nIdx < aData.size(); ++nIdx)
2907 {
2908 aData[nIdx].pPattern = &rDocument.GetPool()->Put(*aData[nIdx].pPattern);
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 = GetOptimalMinRowHeight();
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 = GetOptimalMinRowHeight();
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 = GetOptimalMinRowHeight();
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;
3591 return GetOptimalMinRowHeight();
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>(GetOptimalMinRowHeight());
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) * GetOptimalMinRowHeight() * 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
3668 return GetOptimalMinRowHeight();
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(GetOptimalMinRowHeight());
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:995
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.hxx:965
const SfxPoolItem & GetAttr(SCROW nRow, sal_uInt16 nWhich) const
Definition: column.hxx:970
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:1046
bool HasAttrib(SCROW nRow1, SCROW nRow2, HasAttrFlags nMask) const
Definition: column.hxx:930
void ClearSelectionItems(const sal_uInt16 *pWhich, const ScMarkData &rMark, SCCOL nCol)
Definition: column.cxx:426
bool TestInsertRow(SCSIZE nSize) const
Definition: column.hxx:1051
void MergePatternArea(ScMergePatternState &rState, SCROW nRow1, SCROW nRow2, bool bDeep) const
Definition: column.hxx:947
void InsertRow(SCROW nStartRow, SCSIZE nSize)
Definition: column.hxx:1056
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:1000
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:980
void CreateSparklineCell(SCROW nRow, std::shared_ptr< sc::Sparkline > const &pSparkline)
Definition: column2.cxx:2061
bool ApplyFlags(SCROW nStartRow, SCROW nEndRow, ScMF nFlags)
Definition: column.hxx:1015
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1680
void ApplyPattern(SCROW nRow, const ScPatternAttr &rPatAttr)
Definition: column.cxx:467
void SetValue(SCROW nRow, double fVal)
Definition: column3.cxx:3026
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:188
void SetFormula(SCROW nRow, const ScTokenArray &rArray, formula::FormulaGrammar::Grammar eGram)
Definition: column3.cxx:2421
ScFormulaCell * SetFormulaCell(SCROW nRow, ScFormulaCell *pCell, sc::StartListeningType eListenType=sc::SingleCellListening, bool bInheritNumFormatIfNeeded=true)
Takes ownership of pCell.
Definition: column3.cxx:2457
bool SetFormulaCells(SCROW nRow, std::vector< ScFormulaCell * > &rCells)
Definition: column3.cxx:2495
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1159
void SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr &)
Definition: column.hxx:1040
BroadcastMode
Broadcast mode for SetDirty(SCROW,SCROW,BroadcastMode).
Definition: column.hxx:243
sc::CellNoteStoreType maCellNotes
Definition: column.hxx:191
void SetNumberFormat(SCROW nRow, sal_uInt32 nNumberFormat)
Definition: column2.cxx:3289
void ApplyAttr(SCROW nRow, const SfxPoolItem &rAttr)
Definition: column.cxx:620
const ScPatternAttr * SetPattern(SCROW nRow, std::unique_ptr< ScPatternAttr >)
Definition: column.hxx:1030
void ApplyStyle(SCROW nRow, const ScStyleSheet *rStyle)
Definition: column.cxx:516
sc::CellStoreType maCells
Definition: column.hxx:197
void AddCondFormat(SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex)
Definition: column.hxx:985
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:2220
double * GetValueCell(SCROW nRow)
Definition: column3.cxx:3075
void SetEditText(SCROW nRow, std::unique_ptr< EditTextObject > pEditText)
Definition: column3.cxx:2359
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:2339
void CopyCellToDocument(SCROW nSrcRow, SCROW nDestRow, ScColumn &rDestCol)
Definition: column.cxx:1089
void SetRawString(SCROW nRow, const OUString &rStr)
Definition: column3.cxx:2977
const OUString & GetStyleName() const
Definition: conditio.hxx:514
ScRangeList & GetRangeList()
Definition: conditio.hxx:561
bool EqualEntries(const ScConditionalFormat &r, bool bIgnoreSrcPos=false) const
Definition: conditio.cxx:1743
const ScRangeList & GetRange() const
Definition: conditio.hxx:559
void SetRange(const ScRangeList &rRanges)
Definition: conditio.cxx:1762
std::unique_ptr< ScConditionalFormat > Clone(ScDocument *pNewDoc=nullptr) const
Definition: conditio.cxx:1724
sal_uInt32 GetKey() const
Definition: conditio.hxx:591
const ScFormatEntry * GetEntry(sal_uInt16 nPos) const
Definition: conditio.cxx:1802
size_t size() const
Definition: conditio.cxx:1788
const ScPatternAttr * GetNext(SCCOL &rCol, SCROW &rRow1, SCROW &rRow2)
Definition: dociter.cxx:1588
void SetAreasChangedNeedBroadcast()
Definition: docsh.hxx:389
SC_DLLPUBLIC bool IsScenario(SCTAB nTab) const
Definition: documen3.cxx:432
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:898
bool IsUndo() const
Definition: document.hxx:1593
SC_DLLPUBLIC ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2509
void SetNote(const ScAddress &rPos, std::unique_ptr< ScPostIt > pNote)
Definition: document.cxx:6599
SC_DLLPUBLIC bool IsTabProtected(SCTAB nTab) const
Definition: documen3.cxx:1905
SC_DLLPUBLIC bool HasColNotes(SCCOL nCol, SCTAB nTab) const
Definition: document.cxx:6652
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6050
bool IsCutMode()
Definition: document.cxx:2030
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:492
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:893
SC_DLLPUBLIC ScChartListenerCollection * GetChartListenerCollection() const
Definition: document.hxx:2233
bool HasScenarioRange(SCTAB nTab, const ScRange &rRange) const
Definition: documen3.cxx:866
ScInterpreterContext & GetNonThreadedContext() const
Definition: document.hxx:617
SC_DLLPUBLIC std::unique_ptr< ScPostIt > ReleaseNote(const ScAddress &rPos)
Definition: document.cxx:6689
ScBroadcastAreaSlotMachine * GetBASM() const
Definition: document.hxx:2231
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1084
bool IsClipOrUndo() const
Definition: document.hxx:1592
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
SC_DLLPUBLIC ScStyleSheetPool * GetStyleSheetPool() const
Definition: document.cxx:6055
SC_DLLPUBLIC void SetPattern(const ScAddress &, const ScPatternAttr &rAttr)
Definition: document.cxx:5008
SC_DLLPUBLIC void AddCondFormatData(const ScRangeList &rRange, SCTAB nTab, sal_uInt32 nIndex)
Definition: document.cxx:4790
void GetScenarioFlags(SCTAB nTab, ScScenarioFlags &rFlags) const
Definition: documen3.cxx:480
SC_DLLPUBLIC bool IsActiveScenario(SCTAB nTab) const
Definition: documen3.cxx:880
void SetPageSize(sal_uInt16 nPageNo, const Size &rSize, bool bUpdateNoteCaptionPos, const ScObjectHandling eObjectHandling=ScObjectHandling::RecalcPosMode)
Definition: drwlayer.cxx:644
bool HasObjectsInRows(SCTAB nTab, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:1575
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 const CharClass & getCharClass()
Definition: global.cxx:1064
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:71
bool IsMerged() const
Definition: attrib.hxx:74
SCROW GetRowMerge() const
Definition: attrib.hxx:72
ScMF GetValue() const
Definition: attrib.hxx:100
bool IsOverlapped() const
Definition: attrib.hxx:104
bool Insert(SCCOLROW nStartPos, SCCOLROW nEndPos, bool &rSizeChanged, bool bHidden=false)
Definition: olinetab.cxx:197
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1398
ScRotateDir GetRotateDir(const SfxItemSet *pCondSet) const
Definition: patattr.cxx:1468
SfxItemSet & GetItemSet()
Definition: patattr.hxx:192
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:484
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(SfxStyleSheetBasePool *pSrcPool, const OUString &rName, SfxStyleFamily eFamily, bool bNewStyleHierarchy=false)
Definition: stlpool.cxx:128
std::unique_ptr< ScFlatBoolColSegments > mpHiddenCols
Definition: table.hxx:199
void CopyScenarioFrom(const ScTable *pSrcTab)
Definition: table2.cxx:1576