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