LibreOffice Module sc (master) 1
attarray.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <attarray.hxx>
21#include <scitems.hxx>
23#include <editeng/boxitem.hxx>
24#include <editeng/lineitem.hxx>
25#include <editeng/shaditem.hxx>
26#include <editeng/editobj.hxx>
28#include <osl/diagnose.h>
29#include <svl/poolcach.hxx>
30#include <sfx2/objsh.hxx>
31
32#include <global.hxx>
33#include <document.hxx>
34#include <docpool.hxx>
35#include <patattr.hxx>
36#include <stlsheet.hxx>
37#include <stlpool.hxx>
38#include <markarr.hxx>
39#include <globstr.hrc>
40#include <scresid.hxx>
41#include <segmenttree.hxx>
42#include <editdataarray.hxx>
43#include <cellvalue.hxx>
44#include <editutil.hxx>
45#include <mtvelements.hxx>
46#include <memory>
47
48using ::editeng::SvxBorderLine;
49
50ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, ScAttrArray* pDefaultColAttrArray ) :
51 nCol( nNewCol ),
52 nTab( nNewTab ),
53 rDocument( rDoc )
54{
55 if ( nCol == -1 || !pDefaultColAttrArray || pDefaultColAttrArray->mvData.empty() )
56 return;
57
58 ScAddress aAdrStart( nCol, 0, nTab );
59 ScAddress aAdrEnd( nCol, 0, nTab );
60 mvData.resize( pDefaultColAttrArray->mvData.size() );
61 for ( size_t nIdx = 0; nIdx < pDefaultColAttrArray->mvData.size(); ++nIdx )
62 {
63 mvData[nIdx].nEndRow = pDefaultColAttrArray->mvData[nIdx].nEndRow;
64 ScPatternAttr aNewPattern( *(pDefaultColAttrArray->mvData[nIdx].pPattern) );
65 mvData[nIdx].pPattern = &rDocument.GetPool()->Put( aNewPattern );
66 bool bNumFormatChanged = false;
67 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
68 mvData[nIdx].pPattern->GetItemSet(), rDocument.GetDefPattern()->GetItemSet() ) )
69 {
70 aAdrStart.SetRow( nIdx ? mvData[nIdx-1].nEndRow+1 : 0 );
71 aAdrEnd.SetRow( mvData[nIdx].nEndRow );
72 rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
73 }
74 }
75}
76
78{
79#if DEBUG_SC_TESTATTRARRAY
80 TestData();
81#endif
82
83 ScDocumentPool* pDocPool = rDocument.GetPool();
84 for (auto const & rEntry : mvData)
85 pDocPool->Remove(*rEntry.pPattern);
86}
87
88#if DEBUG_SC_TESTATTRARRAY
89void ScAttrArray::TestData() const
90{
91
92 sal_uInt16 nErr = 0;
94 for (nPos=0; nPos<nCount; nPos++)
95 {
96 if (nPos > 0)
97 if (mvData[nPos].pPattern == mvData[nPos-1].pPattern || mvData[nPos].nRow <= mvData[nPos-1].nRow)
98 ++nErr;
99 if (mvData[nPos].pPattern->Which() != ATTR_PATTERN)
100 ++nErr;
101 }
102 if ( nPos && mvData[nPos-1].nRow != rDocument.MaxRow() )
103 ++nErr;
104
105 SAL_WARN_IF( nErr, "sc", nErr << " errors in attribute array, column " << nCol );
106}
107#endif
108
110{
111 if ( !mvData.empty() )
112 return;
113
114 SCSIZE nNewLimit = std::max<SCSIZE>( SC_ATTRARRAY_DELTA, nNeeded );
115 mvData.reserve( nNewLimit );
116 mvData.emplace_back();
117 mvData[0].nEndRow = rDocument.MaxRow();
118 mvData[0].pPattern = rDocument.GetDefPattern(); // no put
119}
120
121void ScAttrArray::Reset( const ScPatternAttr* pPattern )
122{
123 ScDocumentPool* pDocPool = rDocument.GetPool();
124 ScAddress aAdrStart( nCol, 0, nTab );
125 ScAddress aAdrEnd ( nCol, 0, nTab );
126
127 for (SCSIZE i=0; i<mvData.size(); i++)
128 {
129 // ensure that attributing changes text width of cell
130 const ScPatternAttr* pOldPattern = mvData[i].pPattern;
131 if ( nCol != -1 )
132 {
133 bool bNumFormatChanged;
134 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
135 pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
136 {
137 aAdrStart.SetRow( i ? mvData[i-1].nEndRow+1 : 0 );
138 aAdrEnd .SetRow( mvData[i].nEndRow );
139 rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
140 }
141 }
142 pDocPool->Remove(*pOldPattern);
143 }
144 mvData.resize(0);
145
147
148 mvData.resize(1);
149 const ScPatternAttr* pNewPattern = &pDocPool->Put(*pPattern);
150 mvData[0].nEndRow = rDocument.MaxRow();
151 mvData[0].pPattern = pNewPattern;
152}
153
155{
156 bool bRet = false;
157 if (nPos < mvData.size())
158 {
159 if (nPos > 0)
160 {
161 if (mvData[nPos - 1].pPattern == mvData[nPos].pPattern)
162 {
163 mvData[nPos - 1].nEndRow = mvData[nPos].nEndRow;
164 rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
165 mvData.erase(mvData.begin() + nPos);
166 nPos--;
167 bRet = true;
168 }
169 }
170 if (nPos + 1 < mvData.size())
171 {
172 if (mvData[nPos + 1].pPattern == mvData[nPos].pPattern)
173 {
174 mvData[nPos].nEndRow = mvData[nPos + 1].nEndRow;
175 rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
176 mvData.erase(mvData.begin() + nPos + 1);
177 bRet = true;
178 }
179 }
180 }
181 return bRet;
182}
183
184/*
185 * nCount is the number of runs of different attribute combinations;
186 * no attribute in a column => nCount==1, one attribute somewhere => nCount == 3
187 * (ie. one run with no attribute + one attribute + another run with no attribute)
188 * so a range of identical attributes is only one entry in ScAttrArray.
189 *
190 * Iterative implementation of Binary Search
191 * The same implementation was used inside ScMarkArray::Search().
192 */
193
194bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
195{
196/* auto it = std::lower_bound(mvData.begin(), mvData.end(), nRow,
197 [] (const ScAttrEntry &r1, SCROW nRow)
198 { return r1.nEndRow < nRow; } );
199 if (it != mvData.end())
200 nIndex = it - mvData.begin();
201 return it != mvData.end(); */
202
203 if (mvData.size() == 1)
204 {
205 nIndex = 0;
206 return true;
207 }
208
209 tools::Long nHi = static_cast<tools::Long>(mvData.size()) - 1;
210 tools::Long i = 0;
211 tools::Long nLo = 0;
212
213 while ( nLo <= nHi )
214 {
215 i = (nLo + nHi) / 2;
216
217 if (mvData[i].nEndRow < nRow)
218 {
219 // If [nRow] greater, ignore left half
220 nLo = i + 1;
221 }
222 else if ((i > 0) && (mvData[i - 1].nEndRow >= nRow))
223 {
224 // If [nRow] is smaller, ignore right half
225 nHi = i - 1;
226 }
227 else
228 {
229 // found
230 nIndex=static_cast<SCSIZE>(i);
231 return true;
232 }
233 }
234
235 nIndex=0;
236 return false;
237}
238
240{
241 if ( mvData.empty() )
242 {
243 if ( !rDocument.ValidRow(nRow) )
244 return nullptr;
245 return rDocument.GetDefPattern();
246 }
247 SCSIZE i;
248 if (Search( nRow, i ))
249 return mvData[i].pPattern;
250 else
251 return nullptr;
252}
253
255 SCROW& rEndRow, SCROW nRow ) const
256{
257 if ( mvData.empty() )
258 {
259 if ( !rDocument.ValidRow( nRow ) )
260 return nullptr;
261 rStartRow = 0;
262 rEndRow = rDocument.MaxRow();
263 return rDocument.GetDefPattern();
264 }
266 if ( Search( nRow, nIndex ) )
267 {
268 if ( nIndex > 0 )
269 rStartRow = mvData[nIndex-1].nEndRow + 1;
270 else
271 rStartRow = 0;
272 rEndRow = mvData[nIndex].nEndRow;
273 return mvData[nIndex].pPattern;
274 }
275 return nullptr;
276}
277
278void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
279{
280 if(!rDocument.ValidRow(nStartRow) || !rDocument.ValidRow(nEndRow))
281 return;
282
283 if(nEndRow < nStartRow)
284 return;
285
286 SCROW nTempStartRow = nStartRow;
287 SCROW nTempEndRow = nEndRow;
288
289 do
290 {
291 const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
292
293 std::unique_ptr<ScPatternAttr> pNewPattern;
294 if(pPattern)
295 {
296 pNewPattern.reset( new ScPatternAttr(*pPattern) );
297 SCROW nPatternStartRow;
298 SCROW nPatternEndRow;
299 GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
300
301 nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
302 if (const ScCondFormatItem* pItem = pPattern->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL ))
303 {
304 ScCondFormatIndexes const & rCondFormatData = pItem->GetCondFormatData();
305 if (rCondFormatData.find(nIndex) == rCondFormatData.end())
306 {
307 ScCondFormatIndexes aNewCondFormatData;
308 aNewCondFormatData.reserve(rCondFormatData.size()+1);
309 aNewCondFormatData = rCondFormatData;
310 aNewCondFormatData.insert(nIndex);
311 ScCondFormatItem aItem( std::move(aNewCondFormatData) );
312 pNewPattern->GetItemSet().Put( aItem );
313 }
314 }
315 else
316 {
318 pNewPattern->GetItemSet().Put( aItem );
319 }
320 }
321 else
322 {
323 pNewPattern.reset( new ScPatternAttr( rDocument.GetPool() ) );
325 pNewPattern->GetItemSet().Put( aItem );
326 nTempEndRow = nEndRow;
327 }
328
329 SetPatternArea( nTempStartRow, nTempEndRow, std::move(pNewPattern), true );
330 nTempStartRow = nTempEndRow + 1;
331 }
332 while(nTempEndRow < nEndRow);
333
334}
335
336void ScAttrArray::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
337{
338 if(!rDocument.ValidRow(nStartRow) || !rDocument.ValidRow(nEndRow))
339 return;
340
341 if(nEndRow < nStartRow)
342 return;
343
344 SCROW nTempStartRow = nStartRow;
345 SCROW nTempEndRow = nEndRow;
346
347 do
348 {
349 const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
350
351 if(pPattern)
352 {
353 SCROW nPatternStartRow;
354 SCROW nPatternEndRow;
355 GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
356
357 nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
358 if (const ScCondFormatItem* pItem = pPattern->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL ))
359 {
360 auto pPatternAttr = std::make_unique<ScPatternAttr>( *pPattern );
361 if (nIndex == 0)
362 {
363 ScCondFormatItem aItem;
364 pPatternAttr->GetItemSet().Put( aItem );
365 SetPatternArea( nTempStartRow, nTempEndRow, std::move(pPatternAttr), true );
366 }
367 else
368 {
369 ScCondFormatIndexes const & rCondFormatData = pItem->GetCondFormatData();
370 auto itr = rCondFormatData.find(nIndex);
371 if(itr != rCondFormatData.end())
372 {
373 ScCondFormatIndexes aNewCondFormatData(rCondFormatData);
374 aNewCondFormatData.erase_at(std::distance(rCondFormatData.begin(), itr));
375 ScCondFormatItem aItem( std::move(aNewCondFormatData) );
376 pPatternAttr->GetItemSet().Put( aItem );
377 SetPatternArea( nTempStartRow, nTempEndRow, std::move(pPatternAttr), true );
378 }
379 }
380 }
381 }
382 else
383 {
384 return;
385 }
386
387 nTempStartRow = nTempEndRow + 1;
388 }
389 while(nTempEndRow < nEndRow);
390
391}
392
394 const ScPatternAttr* pPattern, ScEditDataArray* pDataArray )
395{
396 assert( nCol != -1 );
397 // cache mdds position, this doesn't modify the mdds container, just EditTextObject's
400 for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
401 {
402 ScAddress aPos(nCol, nRow, nTab);
403 ScRefCellValue aCell(rDocument, aPos, blockPos);
404 if (aCell.getType() != CELLTYPE_EDIT || !aCell.getEditText())
405 continue;
406
407 std::unique_ptr<EditTextObject> pOldData;
408 if (pDataArray)
409 pOldData = aCell.getEditText()->Clone();
410
411 // Direct modification of cell content - something to watch out for if
412 // we decide to share edit text instances in the future.
413 ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject&>(*aCell.getEditText()), *pPattern);
414
415 if (pDataArray)
416 {
417 std::unique_ptr<EditTextObject> pNewData = aCell.getEditText()->Clone();
418 pDataArray->AddItem(nTab, nCol, nRow, std::move(pOldData), std::move(pNewData));
419 }
420 }
421}
422
424{
425 if ( mvData.empty() && nReserve )
426 {
427 try {
428 mvData.reserve(nReserve);
429 mvData.emplace_back();
430 mvData[0].nEndRow = rDocument.MaxRow();
431 mvData[0].pPattern = rDocument.GetDefPattern(); // no put
432 return true;
433 } catch (std::bad_alloc const &) {
434 return false;
435 }
436 }
437 else if ( mvData.capacity() < nReserve )
438 {
439 try {
440 mvData.reserve(nReserve);
441 return true;
442 } catch (std::bad_alloc const &) {
443 return false;
444 }
445 }
446 else
447 return false;
448}
449
450const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern,
451 bool bPutToPool, ScEditDataArray* pDataArray, bool bPassingOwnership )
452{
453 if (rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow))
454 {
455 if (bPutToPool)
456 {
457 if (bPassingOwnership)
458 pPattern = &rDocument.GetPool()->Put(std::unique_ptr<ScPatternAttr>(const_cast<ScPatternAttr*>(pPattern)));
459 else
460 pPattern = &rDocument.GetPool()->Put(*pPattern);
461 }
462 if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow()))
463 Reset(pPattern);
464 else
465 {
466 SCSIZE nNeeded = mvData.size() + 2;
467 SetDefaultIfNotInit( nNeeded );
468
469 ScAddress aAdrStart( nCol, 0, nTab );
470 ScAddress aAdrEnd ( nCol, 0, nTab );
471
472 SCSIZE ni = 0; // number of entries in beginning
473 SCSIZE nx = 0; // track position
474 SCROW ns = 0; // start row of track position
475 if ( nStartRow > 0 )
476 {
477 // skip beginning
479 Search( nStartRow, nIndex );
480 ni = nIndex;
481
482 if ( ni > 0 )
483 {
484 nx = ni;
485 ns = mvData[ni-1].nEndRow+1;
486 }
487 }
488
489 // ensure that attributing changes text width of cell
490 // otherwise, conditional formats need to be reset or deleted
492 while ( ns <= nEndRow )
493 {
494 if ( nCol != -1 && !bIsLoading )
495 {
496 const SfxItemSet& rNewSet = pPattern->GetItemSet();
497 const SfxItemSet& rOldSet = mvData[nx].pPattern->GetItemSet();
498 bool bNumFormatChanged;
499 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
500 rNewSet, rOldSet ) )
501 {
502 aAdrStart.SetRow( std::max(nStartRow,ns) );
503 aAdrEnd .SetRow( std::min(nEndRow,mvData[nx].nEndRow) );
504 rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
505 }
506 }
507 ns = mvData[nx].nEndRow + 1;
508 nx++;
509 }
510
511 // continue modifying data array
512
513 SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
514 bool bCombined = false;
515 bool bSplit = false;
516 if ( nStartRow > 0 )
517 {
518 nInsert = rDocument.MaxRow() + 1;
519 if ( mvData[ni].pPattern != pPattern )
520 {
521 if ( ni == 0 || (mvData[ni-1].nEndRow < nStartRow - 1) )
522 { // may be a split or a simple insert or just a shrink,
523 // row adjustment is done further down
524 if ( mvData[ni].nEndRow > nEndRow )
525 bSplit = true;
526 ni++;
527 nInsert = ni;
528 }
529 else if (mvData[ni - 1].nEndRow == nStartRow - 1)
530 nInsert = ni;
531 }
532 if ( ni > 0 && mvData[ni-1].pPattern == pPattern )
533 { // combine
534 mvData[ni-1].nEndRow = nEndRow;
535 nInsert = rDocument.MaxRow() + 1;
536 bCombined = true;
537 }
538 }
539 else
540 nInsert = 0;
541
542 SCSIZE nj = ni; // stop position of range to replace
543 while ( nj < mvData.size() && mvData[nj].nEndRow <= nEndRow )
544 nj++;
545 if ( !bSplit )
546 {
547 if ( nj < mvData.size() && mvData[nj].pPattern == pPattern )
548 { // combine
549 if ( ni > 0 )
550 {
551 if ( mvData[ni-1].pPattern == pPattern )
552 { // adjacent entries
553 mvData[ni-1].nEndRow = mvData[nj].nEndRow;
554 nj++;
555 }
556 else if ( ni == nInsert )
557 mvData[ni-1].nEndRow = nStartRow - 1; // shrink
558 }
559 nInsert = rDocument.MaxRow() + 1;
560 bCombined = true;
561 }
562 else if ( ni > 0 && ni == nInsert )
563 mvData[ni-1].nEndRow = nStartRow - 1; // shrink
564 }
565 ScDocumentPool* pDocPool = rDocument.GetPool();
566 if ( bSplit )
567 { // duplicate split entry in pool
568 pDocPool->Put( *mvData[ni-1].pPattern );
569 }
570 if ( ni < nj )
571 { // remove middle entries
572 for ( SCSIZE nk=ni; nk<nj; nk++)
573 { // remove entries from pool
574 pDocPool->Remove( *mvData[nk].pPattern );
575 }
576 if ( !bCombined )
577 { // replace one entry
578 mvData[ni].nEndRow = nEndRow;
579 mvData[ni].pPattern = pPattern;
580 ni++;
581 nInsert = rDocument.MaxRow() + 1;
582 }
583 if ( ni < nj )
584 { // remove entries
585 mvData.erase( mvData.begin() + ni, mvData.begin() + nj);
586 }
587 }
588
589 if ( nInsert < sal::static_int_cast<SCSIZE>(rDocument.MaxRow() + 1) )
590 { // insert or append new entry
591 if ( nInsert <= mvData.size() )
592 {
593 if ( !bSplit )
594 mvData.emplace(mvData.begin() + nInsert);
595 else
596 {
597 mvData.insert(mvData.begin() + nInsert, 2, ScAttrEntry());
598 mvData[nInsert+1] = mvData[nInsert-1];
599 }
600 }
601 if ( nInsert )
602 mvData[nInsert-1].nEndRow = nStartRow - 1;
603 mvData[nInsert].nEndRow = nEndRow;
604 mvData[nInsert].pPattern = pPattern;
605
606 // Remove character attributes from these cells if the pattern
607 // is applied during normal session.
608 if (pDataArray && nCol != -1)
609 RemoveCellCharAttribs(nStartRow, nEndRow, pPattern, pDataArray);
610 }
611
613 }
614 }
615
616#if DEBUG_SC_TESTATTRARRAY
617 TestData();
618#endif
619 return pPattern;
620}
621
622void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
623{
624 if (!(rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow)))
625 return;
626
628 SCSIZE nPos;
629 SCROW nStart=0;
630 if (!Search( nStartRow, nPos ))
631 {
632 OSL_FAIL("Search Failure");
633 return;
634 }
635
636 ScAddress aAdrStart( nCol, 0, nTab );
637 ScAddress aAdrEnd ( nCol, 0, nTab );
638
639 do
640 {
641 const ScPatternAttr* pOldPattern = mvData[nPos].pPattern;
642 std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pOldPattern));
643 pNewPattern->SetStyleSheet(const_cast<ScStyleSheet*>(&rStyle));
644 SCROW nY1 = nStart;
645 SCROW nY2 = mvData[nPos].nEndRow;
646 nStart = mvData[nPos].nEndRow + 1;
647
648 if ( *pNewPattern == *pOldPattern )
649 {
650 // keep the original pattern (might be default)
651 // pNewPattern is deleted below
652 nPos++;
653 }
654 else if ( nY1 < nStartRow || nY2 > nEndRow )
655 {
656 if (nY1 < nStartRow) nY1=nStartRow;
657 if (nY2 > nEndRow) nY2=nEndRow;
658 SetPatternArea( nY1, nY2, std::move(pNewPattern), true );
659 Search( nStart, nPos );
660 }
661 else
662 {
663 if ( nCol != -1 )
664 {
665 // ensure attributing changes text width of cell; otherwise
666 // there aren't (yet) template format changes
667 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
668 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
669
670 bool bNumFormatChanged;
671 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
672 rNewSet, rOldSet ) )
673 {
674 aAdrStart.SetRow( nPos ? mvData[nPos-1].nEndRow+1 : 0 );
675 aAdrEnd .SetRow( mvData[nPos].nEndRow );
676 rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
677 }
678 }
679
680 rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
681 mvData[nPos].pPattern = &rDocument.GetPool()->Put(*pNewPattern);
682 if (Concat(nPos))
683 Search(nStart, nPos);
684 else
685 nPos++;
686 }
687 }
688 while ((nStart <= nEndRow) && (nPos < mvData.size()));
689
691
692#if DEBUG_SC_TESTATTRARRAY
693 TestData();
694#endif
695}
696
697 // const cast, otherwise it will be too inefficient/complicated
698static void SetLineColor(SvxBorderLine const * dest, Color c)
699{
700 if (dest)
701 {
702 const_cast<SvxBorderLine*>(dest)->SetColor(c);
703 }
704}
705
706static void SetLine(const SvxBorderLine* dest, const SvxBorderLine* src)
707{
708 if (dest)
709 {
710 SvxBorderLine* pCast = const_cast<SvxBorderLine*>(dest);
711 pCast->SetBorderLineStyle( src->GetBorderLineStyle() );
712 pCast->SetWidth( src->GetWidth() );
713 }
714}
715
717 const SvxBorderLine* pLine, bool bColorOnly )
718{
719 if ( bColorOnly && !pLine )
720 return;
721
722 if (!(rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow)))
723 return;
724
725 SCSIZE nPos;
726 SCROW nStart=0;
728 if (!Search( nStartRow, nPos ))
729 {
730 OSL_FAIL("Search failure");
731 return;
732 }
733
734 do
735 {
736 const ScPatternAttr* pOldPattern = mvData[nPos].pPattern;
737 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
738 const SvxBoxItem* pBoxItem = rOldSet.GetItemIfSet( ATTR_BORDER );
739 const SvxLineItem* pTLBRItem = rOldSet.GetItemIfSet( ATTR_BORDER_TLBR );
740 const SvxLineItem* pBLTRItem = rOldSet.GetItemIfSet( ATTR_BORDER_BLTR );
741
742 if ( pBoxItem || pTLBRItem || pBLTRItem )
743 {
744 std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pOldPattern));
745 SfxItemSet& rNewSet = pNewPattern->GetItemSet();
746 SCROW nY1 = nStart;
747 SCROW nY2 = mvData[nPos].nEndRow;
748
749 std::unique_ptr<SvxBoxItem> pNewBoxItem( pBoxItem ? pBoxItem->Clone() : nullptr);
750 std::unique_ptr<SvxLineItem> pNewTLBRItem( pTLBRItem ? pTLBRItem->Clone() : nullptr);
751 std::unique_ptr<SvxLineItem> pNewBLTRItem(pBLTRItem ? pBLTRItem->Clone() : nullptr);
752
753 // fetch line and update attributes with parameters
754
755 if ( !pLine )
756 {
757 if( pNewBoxItem )
758 {
759 if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( nullptr, SvxBoxItemLine::TOP );
760 if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( nullptr, SvxBoxItemLine::BOTTOM );
761 if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( nullptr, SvxBoxItemLine::LEFT );
762 if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( nullptr, SvxBoxItemLine::RIGHT );
763 }
764 if( pNewTLBRItem && pNewTLBRItem->GetLine() )
765 pNewTLBRItem->SetLine( nullptr );
766 if( pNewBLTRItem && pNewBLTRItem->GetLine() )
767 pNewBLTRItem->SetLine( nullptr );
768 }
769 else
770 {
771 if ( bColorOnly )
772 {
773 Color aColor( pLine->GetColor() );
774 if( pNewBoxItem )
775 {
776 SetLineColor( pNewBoxItem->GetTop(), aColor );
777 SetLineColor( pNewBoxItem->GetBottom(), aColor );
778 SetLineColor( pNewBoxItem->GetLeft(), aColor );
779 SetLineColor( pNewBoxItem->GetRight(), aColor );
780 }
781 if( pNewTLBRItem )
782 SetLineColor( pNewTLBRItem->GetLine(), aColor );
783 if( pNewBLTRItem )
784 SetLineColor( pNewBLTRItem->GetLine(), aColor );
785 }
786 else
787 {
788 if( pNewBoxItem )
789 {
790 SetLine( pNewBoxItem->GetTop(), pLine );
791 SetLine( pNewBoxItem->GetBottom(), pLine );
792 SetLine( pNewBoxItem->GetLeft(), pLine );
793 SetLine( pNewBoxItem->GetRight(), pLine );
794 }
795 if( pNewTLBRItem )
796 SetLine( pNewTLBRItem->GetLine(), pLine );
797 if( pNewBLTRItem )
798 SetLine( pNewBLTRItem->GetLine(), pLine );
799 }
800 }
801 if( pNewBoxItem ) rNewSet.Put( std::move(pNewBoxItem) );
802 if( pNewTLBRItem ) rNewSet.Put( std::move(pNewTLBRItem) );
803 if( pNewBLTRItem ) rNewSet.Put( std::move(pNewBLTRItem) );
804
805 nStart = mvData[nPos].nEndRow + 1;
806
807 if ( nY1 < nStartRow || nY2 > nEndRow )
808 {
809 if (nY1 < nStartRow) nY1=nStartRow;
810 if (nY2 > nEndRow) nY2=nEndRow;
811 SetPatternArea( nY1, nY2, std::move(pNewPattern), true );
812 Search( nStart, nPos );
813 }
814 else
815 {
816 // remove from pool ?
817 rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
818 mvData[nPos].pPattern =
819 &rDocument.GetPool()->Put(std::move(pNewPattern));
820
821 if (Concat(nPos))
822 Search(nStart, nPos);
823 else
824 nPos++;
825 }
826 }
827 else
828 {
829 nStart = mvData[nPos].nEndRow + 1;
830 nPos++;
831 }
832 }
833 while ((nStart <= nEndRow) && (nPos < mvData.size()));
834}
835
836void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray, bool* const pIsChanged )
837{
838#if DEBUG_SC_TESTATTRARRAY
839 TestData();
840#endif
841
842 if (!(rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow)))
843 return;
844
845 SCSIZE nPos;
846 SCROW nStart=0;
848 if (!Search( nStartRow, nPos ))
849 {
850 OSL_FAIL("Search Failure");
851 return;
852 }
853
854 ScAddress aAdrStart( nCol, 0, nTab );
855 ScAddress aAdrEnd ( nCol, 0, nTab );
856
857 do
858 {
859 const ScPatternAttr* pOldPattern = mvData[nPos].pPattern;
860 const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pCache->ApplyTo( *pOldPattern ) );
861 if (pNewPattern != pOldPattern)
862 {
863 SCROW nY1 = nStart;
864 SCROW nY2 = mvData[nPos].nEndRow;
865 nStart = mvData[nPos].nEndRow + 1;
866
867 if(pIsChanged)
868 *pIsChanged = true;
869
870 if ( nY1 < nStartRow || nY2 > nEndRow )
871 {
872 if (nY1 < nStartRow) nY1=nStartRow;
873 if (nY2 > nEndRow) nY2=nEndRow;
874 SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray );
875 Search( nStart, nPos );
876 }
877 else
878 {
879 if ( nCol != -1 )
880 {
881 // ensure attributing changes text-width of cell
882
883 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
884 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
885
886 bool bNumFormatChanged;
887 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
888 rNewSet, rOldSet ) )
889 {
890 aAdrStart.SetRow( nPos ? mvData[nPos-1].nEndRow+1 : 0 );
891 aAdrEnd .SetRow( mvData[nPos].nEndRow );
892 rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
893 }
894 }
895
896 rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
897 mvData[nPos].pPattern = pNewPattern;
898 if (Concat(nPos))
899 Search(nStart, nPos);
900 else
901 ++nPos;
902 }
903 }
904 else
905 {
906 nStart = mvData[nPos].nEndRow + 1;
907 ++nPos;
908 }
909 }
910 while (nStart <= nEndRow);
911
913
914#if DEBUG_SC_TESTATTRARRAY
915 TestData();
916#endif
917}
918
919void ScAttrArray::SetAttrEntries(std::vector<ScAttrEntry> && vNewData)
920{
921 ScDocumentPool* pDocPool = rDocument.GetPool();
922 for (auto const & rEntry : mvData)
923 pDocPool->Remove(*rEntry.pPattern);
924
925 mvData = std::move(vNewData);
926
927#ifdef DBG_UTIL
928 SCROW lastEndRow = -1;
929 for(const auto& entry : mvData)
930 { // Verify that the data is not corrupted.
931 assert(entry.nEndRow > lastEndRow);
932 lastEndRow = entry.nEndRow;
933 }
934#endif
935}
936
937static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
938{
939 const SfxPoolItem* pNewItem;
940 const SfxPoolItem* pOldItem;
941 for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
942 {
943 // pMergeSet has no parent
944 SfxItemState eOldState = rMergeSet.GetItemState( nId, false, &pOldItem );
945
946 if ( eOldState == SfxItemState::DEFAULT )
947 {
948 SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
949 if ( eNewState == SfxItemState::SET )
950 {
951 if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
952 rMergeSet.InvalidateItem( nId );
953 }
954 }
955 else if ( eOldState == SfxItemState::SET ) // Item set
956 {
957 SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
958 if ( eNewState == SfxItemState::SET )
959 {
960 if ( pNewItem != pOldItem ) // Both pulled
961 rMergeSet.InvalidateItem( nId );
962 }
963 else // Default
964 {
965 if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
966 rMergeSet.InvalidateItem( nId );
967 }
968 }
969 // Dontcare remains Dontcare
970 }
971}
972
974 ScMergePatternState& rState, bool bDeep ) const
975{
976 if (!(rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow)))
977 return;
978
979 SCSIZE nPos = 0;
980 SCROW nStart=0;
981 if ( !mvData.empty() && !Search( nStartRow, nPos ) )
982 {
983 OSL_FAIL("Search failure");
984 return;
985 }
986
987 do
988 {
989 // similar patterns must not be repeated
990 const ScPatternAttr* pPattern = nullptr;
991 if ( !mvData.empty() )
992 pPattern = mvData[nPos].pPattern;
993 else
994 pPattern = rDocument.GetDefPattern();
995 if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
996 {
997 const SfxItemSet& rThisSet = pPattern->GetItemSet();
998 if (rState.pItemSet)
999 {
1000 rState.mbValidPatternId = false;
1001 if (bDeep)
1002 lcl_MergeDeep( *rState.pItemSet, rThisSet );
1003 else
1004 rState.pItemSet->MergeValues( rThisSet );
1005 }
1006 else
1007 {
1008 // first pattern - copied from parent
1009 rState.pItemSet.emplace( *rThisSet.GetPool(), rThisSet.GetRanges() );
1010 rState.pItemSet->Set( rThisSet, bDeep );
1011 rState.mnPatternId = pPattern->GetKey();
1012 }
1013
1014 rState.pOld2 = rState.pOld1;
1015 rState.pOld1 = pPattern;
1016 }
1017
1018 if ( !mvData.empty() )
1019 nStart = mvData[nPos].nEndRow + 1;
1020 else
1021 nStart = rDocument.MaxRow() + 1;
1022 ++nPos;
1023 }
1024 while (nStart <= nEndRow);
1025}
1026
1027// assemble border
1028
1029static bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
1030 sal_uInt8& rModified, const SvxBorderLine*& rpNew )
1031{
1032 if (rModified == SC_LINE_DONTCARE)
1033 return false; // don't go again
1034
1035 if (rModified == SC_LINE_EMPTY)
1036 {
1037 rModified = SC_LINE_SET;
1038 rpNew = pNewLine;
1039 return true; // initial value
1040 }
1041
1042 if (pOldLine == pNewLine)
1043 {
1044 rpNew = pOldLine;
1045 return false;
1046 }
1047
1048 if (pOldLine && pNewLine)
1049 if (*pOldLine == *pNewLine)
1050 {
1051 rpNew = pOldLine;
1052 return false;
1053 }
1054
1055 rModified = SC_LINE_DONTCARE;
1056 rpNew = nullptr;
1057 return true; // another line -> don't care
1058}
1059
1060static void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
1061 ScLineFlags& rFlags, const ScPatternAttr* pPattern,
1062 bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
1063{
1064 // right/bottom border set when connected together
1065 const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE);
1066 if ( rMerge.GetColMerge() == nDistRight + 1 )
1067 nDistRight = 0;
1068 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1069 nDistBottom = 0;
1070
1071 const SvxBoxItem* pCellFrame = &pPattern->GetItemSet().Get( ATTR_BORDER );
1072 const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
1073 const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
1074 const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
1075 const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
1076 const SvxBorderLine* pNew;
1077
1078 if (bTop)
1079 {
1080 if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
1081 pLineOuter->SetLine( pNew, SvxBoxItemLine::TOP );
1082 }
1083 else
1084 {
1085 if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
1086 pLineInner->SetLine( pNew, SvxBoxInfoItemLine::HORI );
1087 }
1088
1089 if (nDistBottom == 0)
1090 {
1091 if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
1092 pLineOuter->SetLine( pNew, SvxBoxItemLine::BOTTOM );
1093 }
1094 else
1095 {
1096 if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
1097 pLineInner->SetLine( pNew, SvxBoxInfoItemLine::HORI );
1098 }
1099
1100 if (bLeft)
1101 {
1102 if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
1103 pLineOuter->SetLine( pNew, SvxBoxItemLine::LEFT );
1104 }
1105 else
1106 {
1107 if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
1108 pLineInner->SetLine( pNew, SvxBoxInfoItemLine::VERT );
1109 }
1110
1111 if (nDistRight == 0)
1112 {
1113 if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
1114 pLineOuter->SetLine( pNew, SvxBoxItemLine::RIGHT );
1115 }
1116 else
1117 {
1118 if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
1119 pLineInner->SetLine( pNew, SvxBoxInfoItemLine::VERT );
1120 }
1121}
1122
1124 ScLineFlags& rFlags,
1125 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
1126{
1127 const ScPatternAttr* pPattern;
1128
1129 if (nStartRow == nEndRow)
1130 {
1131 pPattern = GetPattern( nStartRow );
1132 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true, 0 );
1133 }
1134 else if ( !mvData.empty() ) // non-default pattern
1135 {
1136 pPattern = GetPattern( nStartRow );
1137 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true,
1138 nEndRow-nStartRow );
1139
1140 SCSIZE nStartIndex;
1141 SCSIZE nEndIndex;
1142 Search( nStartRow+1, nStartIndex );
1143 Search( nEndRow-1, nEndIndex );
1144 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1145 {
1146 pPattern = mvData[i].pPattern;
1147 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false,
1148 nEndRow - std::min( mvData[i].nEndRow, static_cast<SCROW>(nEndRow-1) ) );
1149 // nDistBottom here always > 0
1150 }
1151
1152 pPattern = GetPattern( nEndRow );
1153 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false, 0 );
1154 }
1155 else
1156 {
1157 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, rDocument.GetDefPattern(), bLeft, nDistRight, true, 0 );
1158 }
1159}
1160
1161// apply border
1162
1163// ApplyFrame - on an entry into the array
1164
1166 const SvxBoxInfoItem* pBoxInfoItem,
1167 SCROW nStartRow, SCROW nEndRow,
1168 bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
1169{
1170 OSL_ENSURE( pBoxInfoItem, "Missing line attributes!" );
1171
1172 const ScPatternAttr* pPattern = GetPattern( nStartRow );
1173 const SvxBoxItem* pOldFrame = &pPattern->GetItemSet().Get( ATTR_BORDER );
1174
1175 // right/bottom border set when connected together
1176 const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE);
1177 if ( rMerge.GetColMerge() == nDistRight + 1 )
1178 nDistRight = 0;
1179 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1180 nDistBottom = 0;
1181
1182 SvxBoxItem aNewFrame( *pOldFrame );
1183 bool bRTL=rDocument.IsLayoutRTL(nTab);
1184 // fdo#37464 check if the sheet are RTL then replace right <=> left
1185 if (bRTL)
1186 {
1187 if( bLeft && nDistRight==0)
1188 {
1189 if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) )
1190 aNewFrame.SetLine( rBoxItem.GetLeft(), SvxBoxItemLine::RIGHT );
1191 if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) )
1192 aNewFrame.SetLine( rBoxItem.GetRight(), SvxBoxItemLine::LEFT );
1193 }
1194 else
1195 {
1196 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1197 aNewFrame.SetLine( (nDistRight==0) ? rBoxItem.GetLeft() : pBoxInfoItem->GetVert(),
1198 SvxBoxItemLine::RIGHT );
1199 if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1200 aNewFrame.SetLine( bLeft ? rBoxItem.GetRight() : pBoxInfoItem->GetVert(),
1201 SvxBoxItemLine::LEFT );
1202 }
1203 }
1204 else
1205 {
1206 if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1207 aNewFrame.SetLine( bLeft ? rBoxItem.GetLeft() : pBoxInfoItem->GetVert(),
1208 SvxBoxItemLine::LEFT );
1209 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1210 aNewFrame.SetLine( (nDistRight==0) ? rBoxItem.GetRight() : pBoxInfoItem->GetVert(),
1211 SvxBoxItemLine::RIGHT );
1212 }
1213 if ( bTop ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
1214 aNewFrame.SetLine( bTop ? rBoxItem.GetTop() : pBoxInfoItem->GetHori(),
1215 SvxBoxItemLine::TOP );
1216 if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
1217 aNewFrame.SetLine( (nDistBottom==0) ? rBoxItem.GetBottom() : pBoxInfoItem->GetHori(),
1218 SvxBoxItemLine::BOTTOM );
1219
1220 if (aNewFrame == *pOldFrame)
1221 {
1222 // nothing to do
1223 return false;
1224 }
1225 else
1226 {
1227 SfxItemPoolCache aCache( rDocument.GetPool(), &aNewFrame );
1228 ApplyCacheArea( nStartRow, nEndRow, &aCache );
1229
1230 return true;
1231 }
1232}
1233
1234void ScAttrArray::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
1235 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight)
1236{
1238 if (nStartRow == nEndRow)
1239 ApplyFrame(rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0);
1240 else
1241 {
1242 ApplyFrame(rLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1243 true, nEndRow-nStartRow);
1244
1245 if ( nEndRow > nStartRow+1 ) // inner part available?
1246 {
1247 SCSIZE nStartIndex;
1248 SCSIZE nEndIndex;
1249 Search( nStartRow+1, nStartIndex );
1250 Search( nEndRow-1, nEndIndex );
1251 SCROW nTmpStart = nStartRow+1;
1252 SCROW nTmpEnd;
1253 for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1254 {
1255 nTmpEnd = std::min( static_cast<SCROW>(nEndRow-1), mvData[i].nEndRow );
1256 bool bChanged = ApplyFrame(rLineOuter, pLineInner, nTmpStart, nTmpEnd,
1257 bLeft, nDistRight, false, nEndRow - nTmpEnd);
1258 nTmpStart = nTmpEnd+1;
1259 if (bChanged)
1260 {
1261 Search(nTmpStart, i);
1262 Search(nEndRow-1, nEndIndex);
1263 }
1264 else
1265 i++;
1266 }
1267 }
1268
1269 ApplyFrame(rLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0);
1270 }
1271}
1272
1273bool ScAttrArray::HasAttrib_Impl(const ScPatternAttr* pPattern, HasAttrFlags nMask, SCROW nRow1, SCROW nRow2, SCSIZE i) const
1274{
1275 bool bFound = false;
1276 if ( nMask & HasAttrFlags::Merged )
1277 {
1278 const ScMergeAttr* pMerge = &pPattern->GetItem( ATTR_MERGE );
1279 if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1280 bFound = true;
1281 }
1283 {
1284 const ScMergeFlagAttr* pMergeFlag = &pPattern->GetItem( ATTR_MERGE_FLAG );
1285 if ( (nMask & HasAttrFlags::Overlapped) && pMergeFlag->IsOverlapped() )
1286 bFound = true;
1287 if ( (nMask & HasAttrFlags::NotOverlapped) && !pMergeFlag->IsOverlapped() )
1288 bFound = true;
1289 if ( (nMask & HasAttrFlags::AutoFilter) && pMergeFlag->HasAutoFilter() )
1290 bFound = true;
1291 }
1292 if ( nMask & HasAttrFlags::Lines )
1293 {
1294 const SvxBoxItem* pBox = &pPattern->GetItem( ATTR_BORDER );
1295 if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1296 bFound = true;
1297 }
1298 if ( nMask & HasAttrFlags::Shadow )
1299 {
1300 const SvxShadowItem* pShadow = &pPattern->GetItem( ATTR_SHADOW );
1301 if ( pShadow->GetLocation() != SvxShadowLocation::NONE )
1302 bFound = true;
1303 }
1304 if ( nMask & HasAttrFlags::Conditional )
1305 {
1306 if ( !pPattern->GetItem( ATTR_CONDITIONAL ).GetCondFormatData().empty())
1307 bFound = true;
1308 }
1309 if ( nMask & HasAttrFlags::Protected )
1310 {
1311 const ScProtectionAttr* pProtect = &pPattern->GetItem( ATTR_PROTECTION );
1312 bool bFoundTemp = false;
1313 if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1314 bFoundTemp = true;
1315
1316 bool bContainsCondFormat = !mvData.empty() &&
1317 !pPattern->GetItem( ATTR_CONDITIONAL ).GetCondFormatData().empty();
1318 if ( bContainsCondFormat && nCol != -1 ) // rDocument.GetCondResult() is valid only for real columns.
1319 {
1320 SCROW nRowStartCond = std::max<SCROW>( nRow1, i ? mvData[i-1].nEndRow + 1: 0 );
1321 SCROW nRowEndCond = std::min<SCROW>( nRow2, mvData[i].nEndRow );
1322 bool bFoundCond = false;
1323 for(SCROW nRowCond = nRowStartCond; nRowCond <= nRowEndCond && !bFoundCond; ++nRowCond)
1324 {
1325 const SfxItemSet* pSet = rDocument.GetCondResult( nCol, nRowCond, nTab );
1326
1327 const ScProtectionAttr* pCondProtect;
1328 if( pSet && (pCondProtect = pSet->GetItemIfSet( ATTR_PROTECTION )) )
1329 {
1330 if( pCondProtect->GetProtection() || pCondProtect->GetHideCell() )
1331 bFoundCond = true;
1332 else
1333 break;
1334 }
1335 else
1336 {
1337 // well it is not true that we found one
1338 // but existing one + cell where conditional
1339 // formatting does not remove it
1340 // => we should use the existing protection setting
1341 bFoundCond = bFoundTemp;
1342 }
1343 }
1344 bFoundTemp = bFoundCond;
1345 }
1346
1347 if(bFoundTemp)
1348 bFound = true;
1349 }
1350 if ( nMask & HasAttrFlags::Rotate )
1351 {
1352 const ScRotateValueItem* pRotate = &pPattern->GetItem( ATTR_ROTATE_VALUE );
1353 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1354 // (see ScPatternAttr::GetCellOrientation)
1355 Degree100 nAngle = pRotate->GetValue();
1356 if ( nAngle && nAngle != 9000_deg100 && nAngle != 27000_deg100 )
1357 bFound = true;
1358 }
1359 if ( nMask & HasAttrFlags::NeedHeight )
1360 {
1361 if (pPattern->GetCellOrientation() != SvxCellOrientation::Standard)
1362 bFound = true;
1363 else if (pPattern->GetItem( ATTR_LINEBREAK ).GetValue())
1364 bFound = true;
1365 else if (pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Block)
1366 bFound = true;
1367
1368 else if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
1369 bFound = true;
1370 else if (pPattern->GetItem( ATTR_ROTATE_VALUE ).GetValue())
1371 bFound = true;
1372 }
1374 {
1375 const SvxShadowItem* pShadow = &pPattern->GetItem( ATTR_SHADOW );
1376 SvxShadowLocation eLoc = pShadow->GetLocation();
1377 if ( nMask & HasAttrFlags::ShadowRight )
1378 if ( eLoc == SvxShadowLocation::TopRight || eLoc == SvxShadowLocation::BottomRight )
1379 bFound = true;
1380 if ( nMask & HasAttrFlags::ShadowDown )
1381 if ( eLoc == SvxShadowLocation::BottomLeft || eLoc == SvxShadowLocation::BottomRight )
1382 bFound = true;
1383 }
1384 if ( nMask & HasAttrFlags::RightOrCenter )
1385 {
1386 // called only if the sheet is LTR, so physical=logical alignment can be assumed
1387 SvxCellHorJustify eHorJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();
1388 if ( eHorJust == SvxCellHorJustify::Right || eHorJust == SvxCellHorJustify::Center )
1389 bFound = true;
1390 }
1391
1392 return bFound;
1393}
1394
1395// Test if field contains specific attribute
1396bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const
1397{
1398 if (mvData.empty())
1399 {
1400 return HasAttrib_Impl(rDocument.GetDefPattern(), nMask, 0, rDocument.MaxRow(), 0);
1401 }
1402
1403 SCSIZE nStartIndex;
1404 SCSIZE nEndIndex;
1405 Search( nRow1, nStartIndex );
1406 if (nRow1 != nRow2)
1407 Search( nRow2, nEndIndex );
1408 else
1409 nEndIndex = nStartIndex;
1410 bool bFound = false;
1411
1412 for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1413 {
1414 const ScPatternAttr* pPattern = mvData[i].pPattern;
1415 bFound = HasAttrib_Impl(pPattern, nMask, nRow1, nRow2, i);
1416 }
1417
1418 return bFound;
1419}
1420
1421bool ScAttrArray::HasAttrib( SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow, SCROW* nEndRow ) const
1422{
1423 if (mvData.empty())
1424 {
1425 if( nStartRow )
1426 *nStartRow = 0;
1427 if( nEndRow )
1428 *nEndRow = rDocument.MaxRow();
1429 return HasAttrib_Impl(rDocument.GetDefPattern(), nMask, 0, rDocument.MaxRow(), 0);
1430 }
1431
1432 SCSIZE nIndex;
1433 Search( nRow, nIndex );
1434 if( nStartRow )
1435 *nStartRow = nIndex > 0 ? mvData[nIndex-1].nEndRow+1 : 0;
1436 if( nEndRow )
1437 *nEndRow = mvData[nIndex].nEndRow;
1438 const ScPatternAttr* pPattern = mvData[nIndex].pPattern;
1439 return HasAttrib_Impl(pPattern, nMask, nRow, nRow, nIndex);
1440}
1441
1443{
1444 if ( !mvData.empty() )
1445 {
1446 SCSIZE nIndex;
1447 Search(nRow, nIndex);
1448 const ScMergeAttr& rItem = mvData[nIndex].pPattern->GetItem(ATTR_MERGE);
1449
1450 return rItem.IsMerged();
1451 }
1452
1453 return rDocument.GetDefPattern()->GetItem(ATTR_MERGE).IsMerged();
1454}
1455
1459bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
1460 SCCOL& rPaintCol, SCROW& rPaintRow,
1461 bool bRefresh )
1462{
1463 assert( nCol != -1 );
1465 const ScPatternAttr* pPattern;
1466 const ScMergeAttr* pItem;
1467 SCSIZE nStartIndex;
1468 SCSIZE nEndIndex;
1469 Search( nStartRow, nStartIndex );
1470 Search( nEndRow, nEndIndex );
1471 bool bFound = false;
1472
1473 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1474 {
1475 pPattern = mvData[i].pPattern;
1476 pItem = &pPattern->GetItem( ATTR_MERGE );
1477 SCCOL nCountX = pItem->GetColMerge();
1478 SCROW nCountY = pItem->GetRowMerge();
1479 if (nCountX>1 || nCountY>1)
1480 {
1481 SCROW nThisRow = (i>0) ? mvData[i-1].nEndRow+1 : 0;
1482 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1483 SCROW nMergeEndRow = nThisRow + nCountY - 1;
1484 if (nMergeEndCol > rPaintCol && nMergeEndCol <= rDocument.MaxCol())
1485 rPaintCol = nMergeEndCol;
1486 if (nMergeEndRow > rPaintRow && nMergeEndRow <= rDocument.MaxRow())
1487 rPaintRow = nMergeEndRow;
1488 bFound = true;
1489
1490 if (bRefresh)
1491 {
1492 if ( nMergeEndCol > nThisCol )
1493 rDocument.ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, mvData[i].nEndRow,
1494 nTab, ScMF::Hor );
1495 if ( nMergeEndRow > nThisRow )
1496 rDocument.ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1497 nTab, ScMF::Ver );
1498 if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1499 rDocument.ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1501
1502 Search( nThisRow, i ); // Data changed
1503 Search( nStartRow, nStartIndex );
1504 Search( nEndRow, nEndIndex );
1505 }
1506 }
1507 }
1508
1509 return bFound;
1510}
1511
1513{
1514 assert( nCol != -1 );
1516 const ScPatternAttr* pPattern;
1517 const ScMergeAttr* pItem;
1518 SCSIZE nIndex;
1519
1520 Search( nStartRow, nIndex );
1521 SCROW nThisStart = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1522 if (nThisStart < nStartRow)
1523 nThisStart = nStartRow;
1524
1525 while ( nThisStart <= nEndRow )
1526 {
1527 SCROW nThisEnd = mvData[nIndex].nEndRow;
1528 if (nThisEnd > nEndRow)
1529 nThisEnd = nEndRow;
1530
1531 pPattern = mvData[nIndex].pPattern;
1532 pItem = &pPattern->GetItem( ATTR_MERGE );
1533 SCCOL nCountX = pItem->GetColMerge();
1534 SCROW nCountY = pItem->GetRowMerge();
1535 if (nCountX>1 || nCountY>1)
1536 {
1539
1540 OSL_ENSURE( nCountY==1 || nThisStart==nThisEnd, "What's up?" );
1541
1542 SCCOL nThisCol = nCol;
1543 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1544 SCROW nMergeEndRow = nThisEnd + nCountY - 1;
1545
1546 // ApplyAttr for areas
1547 for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
1548 rDocument.ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
1549
1550 ScPatternAttr aNewPattern( rDocument.GetPool() );
1551 SfxItemSet* pSet = &aNewPattern.GetItemSet();
1552 pSet->Put( *pFlagAttr );
1553 rDocument.ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
1554 nTab, aNewPattern );
1555
1556 Search( nThisEnd, nIndex ); // data changed
1557 }
1558
1559 ++nIndex;
1560 if ( nIndex < mvData.size() )
1561 nThisStart = mvData[nIndex-1].nEndRow+1;
1562 else
1563 nThisStart = rDocument.MaxRow()+1; // End
1564 }
1565}
1566
1568 const ScPatternAttr* pWantedPattern, bool bDefault )
1569{
1571 const ScPatternAttr* pOldPattern;
1572 const ScMergeFlagAttr* pItem;
1573
1574 SCSIZE nIndex;
1575 SCROW nRow;
1576 SCROW nThisRow;
1577 bool bFirstUse = true;
1578
1579 Search( nStartRow, nIndex );
1580 nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1581 while ( nThisRow <= nEndRow )
1582 {
1583 pOldPattern = mvData[nIndex].pPattern;
1584 if (pOldPattern != pWantedPattern) // FIXME: else-branch?
1585 {
1586 if (nThisRow < nStartRow) nThisRow = nStartRow;
1587 nRow = mvData[nIndex].nEndRow;
1588 SCROW nAttrRow = std::min( nRow, nEndRow );
1589 pItem = &pOldPattern->GetItem( ATTR_MERGE_FLAG );
1590
1591 if (pItem->IsOverlapped() || pItem->HasAutoFilter())
1592 {
1593 // default-constructing a ScPatternAttr for DeleteArea doesn't work
1594 // because it would have no cell style information.
1595 // Instead, the document's GetDefPattern is copied. Since it is passed as
1596 // pWantedPattern, no special treatment of default is needed here anymore.
1597 std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pWantedPattern ));
1598 pNewPattern->GetItemSet().Put( *pItem );
1599 SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
1600 }
1601 else
1602 {
1603 if ( !bDefault )
1604 {
1605 if (bFirstUse)
1606 bFirstUse = false;
1607 else
1608 // it's in the pool
1609 rDocument.GetPool()->Put( *pWantedPattern );
1610 }
1611 SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
1612 }
1613
1614 Search( nThisRow, nIndex ); // data changed
1615 }
1616
1617 ++nIndex;
1618 nThisRow = mvData[nIndex-1].nEndRow+1;
1619 }
1620}
1621
1622bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
1623{
1625 const ScPatternAttr* pOldPattern;
1626
1627 ScMF nOldValue;
1628 SCSIZE nIndex;
1629 SCROW nRow;
1630 SCROW nThisRow;
1631 bool bChanged = false;
1632
1633 Search( nStartRow, nIndex );
1634 nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1635 if (nThisRow < nStartRow) nThisRow = nStartRow;
1636
1637 while ( nThisRow <= nEndRow )
1638 {
1639 pOldPattern = mvData[nIndex].pPattern;
1640 nOldValue = pOldPattern->GetItem( ATTR_MERGE_FLAG ).GetValue();
1641 if ( (nOldValue | nFlags) != nOldValue )
1642 {
1643 nRow = mvData[nIndex].nEndRow;
1644 SCROW nAttrRow = std::min( nRow, nEndRow );
1645 auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
1646 pNewPattern->GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1647 SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
1648 Search( nThisRow, nIndex ); // data changed
1649 bChanged = true;
1650 }
1651
1652 ++nIndex;
1653 nThisRow = mvData[nIndex-1].nEndRow+1;
1654 }
1655
1656 return bChanged;
1657}
1658
1659bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
1660{
1662 const ScPatternAttr* pOldPattern;
1663
1664 ScMF nOldValue;
1665 SCSIZE nIndex;
1666 SCROW nRow;
1667 SCROW nThisRow;
1668 bool bChanged = false;
1669
1670 Search( nStartRow, nIndex );
1671 nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1672 if (nThisRow < nStartRow) nThisRow = nStartRow;
1673
1674 while ( nThisRow <= nEndRow )
1675 {
1676 pOldPattern = mvData[nIndex].pPattern;
1677 nOldValue = pOldPattern->GetItem( ATTR_MERGE_FLAG ).GetValue();
1678 if ( (nOldValue & ~nFlags) != nOldValue )
1679 {
1680 nRow = mvData[nIndex].nEndRow;
1681 SCROW nAttrRow = std::min( nRow, nEndRow );
1682 auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
1683 pNewPattern->GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1684 SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
1685 Search( nThisRow, nIndex ); // data changed
1686 bChanged = true;
1687 }
1688
1689 ++nIndex;
1690 nThisRow = mvData[nIndex-1].nEndRow+1;
1691 }
1692
1693 return bChanged;
1694}
1695
1696void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
1697{
1699 SCSIZE nIndex;
1700 SCROW nRow;
1701 SCROW nThisRow;
1702
1703 Search( nStartRow, nIndex );
1704 nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1705 if (nThisRow < nStartRow) nThisRow = nStartRow;
1706
1707 while ( nThisRow <= nEndRow )
1708 {
1709 const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
1710 if ( pOldPattern->HasItemsSet( pWhich ) )
1711 {
1712 auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
1713 pNewPattern->ClearItems( pWhich );
1714
1715 nRow = mvData[nIndex].nEndRow;
1716 SCROW nAttrRow = std::min( nRow, nEndRow );
1717 SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
1718 Search( nThisRow, nIndex ); // data changed
1719 }
1720
1721 ++nIndex;
1722 nThisRow = mvData[nIndex-1].nEndRow+1;
1723 }
1724}
1725
1726void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement )
1727{
1729 SCSIZE nIndex;
1730 Search( nStartRow, nIndex );
1731 SCROW nThisStart = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1732 if (nThisStart < nStartRow) nThisStart = nStartRow;
1733
1734 while ( nThisStart <= nEndRow )
1735 {
1736 const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
1737 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1738 const SvxHorJustifyItem* pItem;
1739
1740 bool bNeedJust = !( pItem = rOldSet.GetItemIfSet( ATTR_HOR_JUSTIFY, false ) )
1741 || (pItem->GetValue() != SvxCellHorJustify::Left &&
1742 pItem->GetValue() != SvxCellHorJustify::Right );
1743 sal_uInt16 nOldValue = rOldSet.Get( ATTR_INDENT ).GetValue();
1744 sal_uInt16 nNewValue = nOldValue;
1745 // To keep Increment indent from running outside the cell1659
1746 tools::Long nColWidth = static_cast<tools::Long>(
1748 if ( bIncrement )
1749 {
1750 if ( nNewValue < nColWidth-SC_INDENT_STEP )
1751 {
1752 nNewValue += SC_INDENT_STEP;
1753 if ( nNewValue > nColWidth-SC_INDENT_STEP )
1754 nNewValue = nColWidth-SC_INDENT_STEP;
1755 }
1756 }
1757 else
1758 {
1759 if ( nNewValue > 0 )
1760 {
1761 if ( nNewValue > SC_INDENT_STEP )
1762 nNewValue -= SC_INDENT_STEP;
1763 else
1764 nNewValue = 0;
1765 }
1766 }
1767
1768 if ( bNeedJust || nNewValue != nOldValue )
1769 {
1770 SCROW nThisEnd = mvData[nIndex].nEndRow;
1771 SCROW nAttrRow = std::min( nThisEnd, nEndRow );
1772 auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
1773 pNewPattern->GetItemSet().Put( ScIndentItem( nNewValue ) );
1774 if ( bNeedJust )
1775 pNewPattern->GetItemSet().Put(
1776 SvxHorJustifyItem( SvxCellHorJustify::Left, ATTR_HOR_JUSTIFY ) );
1777 SetPatternArea( nThisStart, nAttrRow, std::move(pNewPattern), true );
1778
1779 nThisStart = nThisEnd + 1;
1780 Search( nThisStart, nIndex ); // data changed
1781 }
1782 else
1783 {
1784 nThisStart = mvData[nIndex].nEndRow + 1;
1785 ++nIndex;
1786 }
1787 }
1788}
1789
1791{
1792 tools::Long nRet = nRow;
1793 if (rDocument.ValidRow(nRow))
1794 {
1795 if ( mvData.empty() )
1796 {
1797 if ( bUp )
1798 return -1;
1799 else
1800 return rDocument.MaxRow()+1;
1801 }
1802
1803 SCSIZE nIndex;
1804 Search(nRow, nIndex);
1805 while (mvData[nIndex].pPattern->
1806 GetItem(ATTR_PROTECTION).GetProtection())
1807 {
1808 if (bUp)
1809 {
1810 if (nIndex==0)
1811 return -1; // not found
1812 --nIndex;
1813 nRet = mvData[nIndex].nEndRow;
1814 }
1815 else
1816 {
1817 nRet = mvData[nIndex].nEndRow+1;
1818 ++nIndex;
1819 if (nIndex >= mvData.size())
1820 return rDocument.MaxRow()+1; // not found
1821 }
1822 }
1823 }
1824 return nRet;
1825}
1826
1827void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1828{
1830 SCROW nStart = 0;
1831 SCSIZE nPos = 0;
1832 while (nPos < mvData.size())
1833 {
1834 SCROW nEnd = mvData[nPos].nEndRow;
1835 if (mvData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1836 {
1837 rUsedRows.setTrue(nStart, nEnd);
1838
1839 if (bReset)
1840 {
1841 ScPatternAttr aNewPattern(*mvData[nPos].pPattern);
1842 rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
1843 aNewPattern.SetStyleSheet( static_cast<ScStyleSheet*>(
1845 Find( ScResId(STR_STYLENAME_STANDARD),
1846 SfxStyleFamily::Para,
1847 SfxStyleSearchBits::Auto | SfxStyleSearchBits::ScStandard ) ) );
1848 mvData[nPos].pPattern = &rDocument.GetPool()->Put(aNewPattern);
1849
1850 if (Concat(nPos))
1851 {
1852 Search(nStart, nPos);
1853 --nPos; // because ++ at end
1854 }
1855 }
1856 }
1857 nStart = nEnd + 1;
1858 ++nPos;
1859 }
1860}
1861
1863{
1864 if ( mvData.empty() )
1865 {
1867 if ( pStyle )
1868 {
1870 if ( pStyle == &rStyle )
1871 return true;
1872 }
1873 return false;
1874 }
1875
1876 bool bIsUsed = false;
1877 SCSIZE nPos = 0;
1878
1879 while ( nPos < mvData.size() )
1880 {
1881 const ScStyleSheet* pStyle = mvData[nPos].pPattern->GetStyleSheet();
1882 if ( pStyle )
1883 {
1885 if ( pStyle == &rStyle )
1886 {
1887 bIsUsed = true;
1888 }
1889 }
1890 nPos++;
1891 }
1892
1893 return bIsUsed;
1894}
1895
1897{
1898 if ( mvData.empty() )
1899 return true;
1900
1901 if (mvData.size() == 1)
1902 {
1903 return mvData[0].pPattern == rDocument.GetDefPattern();
1904 }
1905 else
1906 return false;
1907}
1908
1910{
1911 if ( mvData.empty() )
1912 return false;
1913
1914 bool bFound = false;
1915 SCSIZE nStart = 0;
1916
1917 // Skip first entry if more than 1 row.
1918 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1919
1920 SCSIZE nVisStart = 1;
1921 while ( nVisStart < mvData.size() && mvData[nVisStart].pPattern->IsVisibleEqual(*mvData[nVisStart-1].pPattern) )
1922 ++nVisStart;
1923 if ( nVisStart >= mvData.size() || mvData[nVisStart-1].nEndRow > 0 ) // more than 1 row?
1924 nStart = nVisStart;
1925
1926 while ( nStart < mvData.size() && !bFound )
1927 {
1928 if ( mvData[nStart].pPattern->IsVisible() )
1929 {
1930 rFirstRow = nStart ? ( mvData[nStart-1].nEndRow + 1 ) : 0;
1931 bFound = true;
1932 }
1933 else
1934 ++nStart;
1935 }
1936
1937 return bFound;
1938}
1939
1940// size (rows) of a range of attributes after cell content where the search is stopped
1941// (more than a default page size, 2*42 because it's as good as any number)
1942
1944
1945bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
1946{
1947 if ( mvData.empty() )
1948 {
1949 rLastRow = nLastData;
1950 return false;
1951 }
1952
1953 // #i30830# changed behavior:
1954 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1955 // below the last content cell
1956
1957 if ( nLastData == rDocument.MaxRow() )
1958 {
1959 rLastRow = rDocument.MaxRow(); // can't look for attributes below rDocument.MaxRow()
1960 return true;
1961 }
1962
1963 // Quick check: last data row in or immediately preceding a run that is the
1964 // last attribution down to the end, e.g. default style or column style.
1965 SCSIZE nPos = mvData.size() - 1;
1966 SCROW nStartRow = (nPos ? mvData[nPos-1].nEndRow + 1 : 0);
1967 if (nStartRow <= nLastData + 1)
1968 {
1969 // Ignore here a few rows if data happens to end within
1970 // SC_VISATTR_STOP rows before rDocument.MaxRow().
1971 rLastRow = nLastData;
1972 return false;
1973 }
1974
1975 // Find a run below last data row.
1976 bool bFound = false;
1977 Search( nLastData, nPos );
1978 while ( nPos < mvData.size() )
1979 {
1980 // find range of visually equal formats
1981 SCSIZE nEndPos = nPos;
1982 while ( nEndPos < mvData.size()-1 &&
1983 mvData[nEndPos].pPattern->IsVisibleEqual( *mvData[nEndPos+1].pPattern))
1984 ++nEndPos;
1985 SCROW nAttrStartRow = ( nPos > 0 ) ? ( mvData[nPos-1].nEndRow + 1 ) : 0;
1986 if ( nAttrStartRow <= nLastData )
1987 nAttrStartRow = nLastData + 1;
1988 SCROW nAttrSize = mvData[nEndPos].nEndRow + 1 - nAttrStartRow;
1989 if ( nAttrSize >= SC_VISATTR_STOP )
1990 break; // while, ignore this range and below
1991 else if ( mvData[nEndPos].pPattern->IsVisible() )
1992 {
1993 rLastRow = mvData[nEndPos].nEndRow;
1994 bFound = true;
1995 }
1996 nPos = nEndPos + 1;
1997 }
1998
1999 return bFound;
2000}
2001
2002bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
2003{
2004 if ( mvData.empty() )
2005 return rDocument.GetDefPattern()->IsVisible();
2006
2007 SCSIZE nIndex;
2008 Search( nStartRow, nIndex );
2009 SCROW nThisStart = nStartRow;
2010 bool bFound = false;
2011 while ( nIndex < mvData.size() && nThisStart <= nEndRow && !bFound )
2012 {
2013 if ( mvData[nIndex].pPattern->IsVisible() )
2014 bFound = true;
2015
2016 nThisStart = mvData[nIndex].nEndRow + 1;
2017 ++nIndex;
2018 }
2019
2020 return bFound;
2021}
2022
2024 SCROW nStartRow, SCROW nEndRow ) const
2025{
2026 if ( mvData.empty() && rOther.mvData.empty() )
2027 {
2028 const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern();
2029 const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern();
2030 return ( pDefPattern1 == pDefPattern2 || pDefPattern1->IsVisibleEqual( *pDefPattern2 ) );
2031 }
2032
2033 {
2034 const ScAttrArray* pNonDefault = nullptr;
2035 const ScPatternAttr* pDefPattern = nullptr;
2036 bool bDefNonDefCase = false;
2037 if ( mvData.empty() && !rOther.mvData.empty() )
2038 {
2039 pNonDefault = &rOther;
2040 pDefPattern = rDocument.GetDefPattern();
2041 bDefNonDefCase = true;
2042 }
2043 else if ( !mvData.empty() && rOther.mvData.empty() )
2044 {
2045 pNonDefault = this;
2046 pDefPattern = rOther.rDocument.GetDefPattern();
2047 bDefNonDefCase = true;
2048 }
2049
2050 if ( bDefNonDefCase )
2051 {
2052 bool bEqual = true;
2053 SCSIZE nPos = 0;
2054 if ( nStartRow > 0 )
2055 pNonDefault->Search( nStartRow, nPos );
2056
2057 while ( nPos < pNonDefault->Count() && bEqual )
2058 {
2059 const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern;
2060 bEqual = ( pNonDefPattern == pDefPattern ||
2061 pNonDefPattern->IsVisibleEqual( *pDefPattern ) );
2062
2063 if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break;
2064 ++nPos;
2065 }
2066 return bEqual;
2067 }
2068 }
2069
2070 bool bEqual = true;
2071 SCSIZE nThisPos = 0;
2072 SCSIZE nOtherPos = 0;
2073 if ( nStartRow > 0 )
2074 {
2075 Search( nStartRow, nThisPos );
2076 rOther.Search( nStartRow, nOtherPos );
2077 }
2078
2079 while ( nThisPos<mvData.size() && nOtherPos<rOther.Count() && bEqual )
2080 {
2081 SCROW nThisRow = mvData[nThisPos].nEndRow;
2082 SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow;
2083 const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern;
2084 const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern;
2085 bEqual = ( pThisPattern == pOtherPattern ||
2086 pThisPattern->IsVisibleEqual(*pOtherPattern) );
2087
2088 if ( nThisRow >= nOtherRow )
2089 {
2090 if ( nOtherRow >= nEndRow ) break;
2091 ++nOtherPos;
2092 }
2093 if ( nThisRow <= nOtherRow )
2094 {
2095 if ( nThisRow >= nEndRow ) break;
2096 ++nThisPos;
2097 }
2098 }
2099
2100 return bEqual;
2101}
2102
2103bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
2104{
2105 // summarised with IsVisibleEqual
2106 if ( mvData.empty() && rOther.mvData.empty() )
2107 {
2108 const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern();
2109 const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern();
2110 return ( pDefPattern1 == pDefPattern2 );
2111 }
2112
2113 {
2114 const ScAttrArray* pNonDefault = nullptr;
2115 const ScPatternAttr* pDefPattern = nullptr;
2116 bool bDefNonDefCase = false;
2117 if ( mvData.empty() && !rOther.mvData.empty() )
2118 {
2119 pNonDefault = &rOther;
2120 pDefPattern = rDocument.GetDefPattern();
2121 bDefNonDefCase = true;
2122 }
2123 else if ( !mvData.empty() && rOther.mvData.empty() )
2124 {
2125 pNonDefault = this;
2126 pDefPattern = rOther.rDocument.GetDefPattern();
2127 bDefNonDefCase = true;
2128 }
2129
2130 if ( bDefNonDefCase )
2131 {
2132 bool bEqual = true;
2133 SCSIZE nPos = 0;
2134 if ( nStartRow > 0 )
2135 pNonDefault->Search( nStartRow, nPos );
2136
2137 while ( nPos < pNonDefault->Count() && bEqual )
2138 {
2139 const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern;
2140 bEqual = ( pNonDefPattern == pDefPattern );
2141
2142 if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break;
2143 ++nPos;
2144 }
2145 return bEqual;
2146 }
2147 }
2148
2149 bool bEqual = true;
2150 SCSIZE nThisPos = 0;
2151 SCSIZE nOtherPos = 0;
2152 if ( nStartRow > 0 )
2153 {
2154 Search( nStartRow, nThisPos );
2155 rOther.Search( nStartRow, nOtherPos );
2156 }
2157
2158 while ( nThisPos<mvData.size() && nOtherPos<rOther.Count() && bEqual )
2159 {
2160 SCROW nThisRow = mvData[nThisPos].nEndRow;
2161 SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow;
2162 const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern;
2163 const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern;
2164 bEqual = ( pThisPattern == pOtherPattern );
2165
2166 if ( nThisRow >= nOtherRow )
2167 {
2168 if ( nOtherRow >= nEndRow ) break;
2169 ++nOtherPos;
2170 }
2171 if ( nThisRow <= nOtherRow )
2172 {
2173 if ( nThisRow >= nEndRow ) break;
2174 ++nThisPos;
2175 }
2176 }
2177
2178 return bEqual;
2179}
2180
2181bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2182{
2183 // Horizontal aggregate are not allowed to be moved out; if whole summary,
2184 // here is not recognized
2185
2186 bool bTest = true;
2187 if (!IsEmpty())
2188 {
2189 SCSIZE nIndex = 0;
2190 if ( nStartRow > 0 )
2191 Search( nStartRow, nIndex );
2192
2193 for ( ; nIndex < mvData.size(); nIndex++ )
2194 {
2195 if ( mvData[nIndex].pPattern->
2196 GetItem(ATTR_MERGE_FLAG).IsHorOverlapped() )
2197 {
2198 bTest = false; // may not be pushed out
2199 break;
2200 }
2201 if ( mvData[nIndex].nEndRow >= nEndRow ) // end of range
2202 break;
2203 }
2204 }
2205 return bTest;
2206}
2207
2209{
2210 // if 1st row pushed out is vertically overlapped, summary would be broken
2211
2212 // rDocument.MaxRow() + 1 - nSize = 1st row pushed out
2213
2214 if ( mvData.empty() )
2215 return !rDocument.GetDefPattern()->
2216 GetItem(ATTR_MERGE_FLAG).IsVerOverlapped();
2217
2218 SCSIZE nFirstLost = mvData.size()-1;
2219 while ( nFirstLost && mvData[nFirstLost-1].nEndRow >= sal::static_int_cast<SCROW>(rDocument.MaxRow() + 1 - nSize) )
2220 --nFirstLost;
2221
2222 return !mvData[nFirstLost].pPattern->
2223 GetItem(ATTR_MERGE_FLAG).IsVerOverlapped();
2224}
2225
2226void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2227{
2229
2230 SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // expand predecessor
2231 SCSIZE nIndex;
2232 Search( nSearch, nIndex );
2233
2234 // set ScMergeAttr may not be extended (so behind delete again)
2235
2236 bool bDoMerge = mvData[nIndex].pPattern->GetItem(ATTR_MERGE).IsMerged();
2237
2238 assert( !bDoMerge || nCol != -1 );
2239
2240 SCSIZE nRemove = 0;
2241 SCSIZE i;
2242 for (i = nIndex; i < mvData.size()-1; i++)
2243 {
2244 SCROW nNew = mvData[i].nEndRow + nSize;
2245 if ( nNew >= rDocument.MaxRow() ) // at end?
2246 {
2247 nNew = rDocument.MaxRow();
2248 if (!nRemove)
2249 nRemove = i+1; // remove the following?
2250 }
2251 mvData[i].nEndRow = nNew;
2252 }
2253
2254 // Remove entries at end ?
2255
2256 if (nRemove && nRemove < mvData.size())
2257 DeleteRange( nRemove, mvData.size()-1 );
2258
2259 if (bDoMerge) // extensively repair (again) ScMergeAttr
2260 {
2261 // ApplyAttr for areas
2262
2264 for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2265 rDocument.ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2266
2267 // reply inserts in this area not summarized
2268 }
2269
2270 // Don't duplicate the merge flags in the inserted row.
2271 // #i108488# ScMF::Scenario has to be allowed.
2272 RemoveFlags( nStartRow, nStartRow+nSize-1, ScMF::Hor | ScMF::Ver | ScMF::Auto | ScMF::Button );
2273}
2274
2275void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2276{
2278 bool bFirst=true;
2279 SCSIZE nStartIndex = 0;
2280 SCSIZE nEndIndex = 0;
2281 SCSIZE i;
2282
2283 for ( i = 0; i < mvData.size()-1; i++)
2284 if (mvData[i].nEndRow >= nStartRow && mvData[i].nEndRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2285 {
2286 if (bFirst)
2287 {
2288 nStartIndex = i;
2289 bFirst = false;
2290 }
2291 nEndIndex = i;
2292 }
2293 if (!bFirst)
2294 {
2295 SCROW nStart;
2296 if (nStartIndex==0)
2297 nStart = 0;
2298 else
2299 nStart = mvData[nStartIndex-1].nEndRow + 1;
2300
2301 if (nStart < nStartRow)
2302 {
2303 mvData[nStartIndex].nEndRow = nStartRow - 1;
2304 ++nStartIndex;
2305 }
2306 if (nEndIndex >= nStartIndex)
2307 {
2308 DeleteRange( nStartIndex, nEndIndex );
2309 if (nStartIndex > 0)
2310 if ( mvData[nStartIndex-1].pPattern == mvData[nStartIndex].pPattern )
2311 DeleteRange( nStartIndex-1, nStartIndex-1 );
2312 }
2313 }
2314 for (i = 0; i < mvData.size()-1; i++)
2315 if (mvData[i].nEndRow >= nStartRow)
2316 mvData[i].nEndRow -= nSize;
2317
2318 // Below does not follow the pattern to detect pressure ranges;
2319 // instead, only remove merge flags.
2321}
2322
2323void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2324{
2326 ScDocumentPool* pDocPool = rDocument.GetPool();
2327 for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2328 pDocPool->Remove(*mvData[i].pPattern);
2329
2330 mvData.erase(mvData.begin() + nStartIndex, mvData.begin() + nEndIndex + 1);
2331}
2332
2333void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2334{
2336 if ( nCol != -1 )
2337 RemoveAreaMerge( nStartRow, nEndRow ); // remove from combined flags
2338
2339 if ( !HasAttrib( nStartRow, nEndRow, HasAttrFlags::Overlapped | HasAttrFlags::AutoFilter) )
2340 SetPatternArea( nStartRow, nEndRow, rDocument.GetDefPattern() );
2341 else
2342 SetPatternAreaSafe( nStartRow, nEndRow, rDocument.GetDefPattern(), true ); // leave merge flags
2343}
2344
2346{
2348 const ScPatternAttr* pDefPattern = rDocument.GetDefPattern();
2349
2350 SCSIZE nIndex;
2351 SCROW nRow;
2352 SCROW nThisRow;
2353
2354 Search( nStartRow, nIndex );
2355 nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
2356 if (nThisRow < nStartRow) nThisRow = nStartRow;
2357
2358 while ( nThisRow <= nEndRow )
2359 {
2360 const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
2361
2362 if ( pOldPattern->GetItemSet().Count() ) // hard attributes ?
2363 {
2364 nRow = mvData[nIndex].nEndRow;
2365 SCROW nAttrRow = std::min( nRow, nEndRow );
2366
2367 auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
2368 SfxItemSet& rSet = pNewPattern->GetItemSet();
2369 for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2370 if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2372
2373 if ( *pNewPattern == *pDefPattern )
2374 SetPatternArea( nThisRow, nAttrRow, pDefPattern );
2375 else
2376 SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
2377
2378 Search( nThisRow, nIndex ); // data changed
2379 }
2380
2381 ++nIndex;
2382 nThisRow = mvData[nIndex-1].nEndRow+1;
2383 }
2384}
2385
2389void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2390{
2392 SCROW nStart = nStartRow;
2393 for (SCSIZE i = 0; i < mvData.size(); i++)
2394 {
2395 if ((mvData[i].nEndRow >= nStartRow) && (i == 0 || mvData[i-1].nEndRow < nEndRow))
2396 {
2397 // copy (bPutToPool=TRUE)
2398 rAttrArray.SetPatternArea( nStart, std::min( mvData[i].nEndRow, nEndRow ),
2399 mvData[i].pPattern, true );
2400 }
2401 nStart = std::max( nStart, mvData[i].nEndRow + 1 );
2402 }
2403 DeleteArea(nStartRow, nEndRow);
2404}
2405
2410 SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray& rAttrArray, ScMF nStripFlags) const
2411{
2412 nStartRow -= nDy; // Source
2413 nEndRow -= nDy;
2414
2415 SCROW nDestStart = std::max(static_cast<tools::Long>(static_cast<tools::Long>(nStartRow) + nDy), tools::Long(0));
2416 SCROW nDestEnd = std::min(static_cast<tools::Long>(static_cast<tools::Long>(nEndRow) + nDy), tools::Long(rDocument.MaxRow()));
2417
2418 ScDocumentPool* pSourceDocPool = rDocument.GetPool();
2419 ScDocumentPool* pDestDocPool = rAttrArray.rDocument.GetPool();
2420 bool bSamePool = (pSourceDocPool==pDestDocPool);
2421
2422 if ( mvData.empty() )
2423 {
2424 const ScPatternAttr* pNewPattern = &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2425 rAttrArray.SetPatternArea(nDestStart, nDestEnd, pNewPattern);
2426 return;
2427 }
2428
2429 for (SCSIZE i = 0; (i < mvData.size()) && (nDestStart <= nDestEnd); i++)
2430 {
2431 if (mvData[i].nEndRow >= nStartRow)
2432 {
2433 const ScPatternAttr* pOldPattern = mvData[i].pPattern;
2434 const ScPatternAttr* pNewPattern;
2435
2436 if (IsDefaultItem( pOldPattern ))
2437 {
2438 // default: nothing changed
2439
2440 pNewPattern = &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2441 }
2442 else if ( nStripFlags != ScMF::NONE )
2443 {
2444 ScPatternAttr aTmpPattern( *pOldPattern );
2445 ScMF nNewFlags = ScMF::NONE;
2446 if ( nStripFlags != ScMF::All )
2447 nNewFlags = aTmpPattern.GetItem(ATTR_MERGE_FLAG).GetValue() & ~nStripFlags;
2448
2449 if ( nNewFlags != ScMF::NONE )
2450 aTmpPattern.GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2451 else
2452 aTmpPattern.GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2453
2454 if (bSamePool)
2455 pNewPattern = &pDestDocPool->Put(aTmpPattern);
2456 else
2457 pNewPattern = aTmpPattern.PutInPool( &rAttrArray.rDocument, &rDocument );
2458 }
2459 else
2460 {
2461 if (bSamePool)
2462 pNewPattern = &pDestDocPool->Put(*pOldPattern);
2463 else
2464 pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument );
2465 }
2466
2467 rAttrArray.SetPatternArea(nDestStart,
2468 std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), pNewPattern);
2469 }
2470
2471 // when pasting from clipboard and skipping filtered rows, the adjusted
2472 // end position can be negative
2473 nDestStart = std::max(static_cast<tools::Long>(nDestStart), static_cast<tools::Long>(mvData[i].nEndRow + nDy + 1));
2474 }
2475}
2476
2481void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray& rAttrArray )
2482{
2483 nStartRow -= nDy; // Source
2484 nEndRow -= nDy;
2485
2486 SCROW nDestStart = std::max(static_cast<tools::Long>(static_cast<tools::Long>(nStartRow) + nDy), tools::Long(0));
2487 SCROW nDestEnd = std::min(static_cast<tools::Long>(static_cast<tools::Long>(nEndRow) + nDy), tools::Long(rDocument.MaxRow()));
2488
2489 if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HasAttrFlags::Overlapped ) )
2490 {
2491 CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2492 return;
2493 }
2494
2495 ScDocumentPool* pSourceDocPool = rDocument.GetPool();
2496 ScDocumentPool* pDestDocPool = rAttrArray.rDocument.GetPool();
2497 bool bSamePool = (pSourceDocPool==pDestDocPool);
2498
2499 if ( mvData.empty() )
2500 {
2501 const ScPatternAttr* pNewPattern;
2502 if (bSamePool)
2503 pNewPattern = &pDestDocPool->Put(*rDocument.GetDefPattern());
2504 else
2505 pNewPattern = rDocument.GetDefPattern()->PutInPool( &rAttrArray.rDocument, &rDocument );
2506
2507 rAttrArray.SetPatternAreaSafe(nDestStart, nDestEnd, pNewPattern, false);
2508 return;
2509 }
2510
2511
2512 for (SCSIZE i = 0; (i < mvData.size()) && (nDestStart <= nDestEnd); i++)
2513 {
2514 if (mvData[i].nEndRow >= nStartRow)
2515 {
2516 const ScPatternAttr* pOldPattern = mvData[i].pPattern;
2517 const ScPatternAttr* pNewPattern;
2518
2519 if (bSamePool)
2520 pNewPattern = &pDestDocPool->Put(*pOldPattern);
2521 else
2522 pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument );
2523
2524 rAttrArray.SetPatternAreaSafe(nDestStart,
2525 std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), pNewPattern, false);
2526 }
2527
2528 // when pasting from clipboard and skipping filtered rows, the adjusted
2529 // end position can be negative
2530 nDestStart = std::max(static_cast<tools::Long>(nDestStart), static_cast<tools::Long>(mvData[i].nEndRow + nDy + 1));
2531 }
2532}
2533
2535 SCROW nRow, const ScStyleSheet* pSearchStyle, bool bUp,
2536 const ScMarkArray* pMarkArray) const
2537{
2538 bool bFound = false;
2539
2540 if (pMarkArray)
2541 {
2542 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2543 if (!rDocument.ValidRow(nRow))
2544 return nRow;
2545 }
2546
2547 if ( mvData.empty() )
2548 {
2549 if (rDocument.GetDefPattern()->GetStyleSheet() == pSearchStyle)
2550 return nRow;
2551
2552 nRow = bUp ? -1 : rDocument.MaxRow() + 1;
2553 return nRow;
2554 }
2555
2556 SCSIZE nIndex;
2557 Search(nRow, nIndex);
2558 const ScPatternAttr* pPattern = mvData[nIndex].pPattern;
2559
2560 while (nIndex < mvData.size() && !bFound)
2561 {
2562 if (pPattern->GetStyleSheet() == pSearchStyle)
2563 {
2564 if (pMarkArray)
2565 {
2566 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2567 SCROW nStart = nIndex ? mvData[nIndex-1].nEndRow+1 : 0;
2568 if (nRow >= nStart && nRow <= mvData[nIndex].nEndRow)
2569 bFound = true;
2570 }
2571 else
2572 bFound = true;
2573 }
2574
2575 if (!bFound)
2576 {
2577 if (bUp)
2578 {
2579 if (nIndex==0)
2580 {
2581 nIndex = mvData.size();
2582 nRow = -1;
2583 }
2584 else
2585 {
2586 --nIndex;
2587 nRow = mvData[nIndex].nEndRow;
2588 pPattern = mvData[nIndex].pPattern;
2589 }
2590 }
2591 else
2592 {
2593 nRow = mvData[nIndex].nEndRow+1;
2594 ++nIndex;
2595 if (nIndex<mvData.size())
2596 pPattern = mvData[nIndex].pPattern;
2597 }
2598 }
2599 }
2600
2601 OSL_ENSURE( bFound || !rDocument.ValidRow(nRow), "Internal failure in ScAttrArray::SearchStyle" );
2602
2603 return nRow;
2604}
2605
2607 SCROW& rRow, SCROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
2608 const ScMarkArray* pMarkArray) const
2609{
2610 SCROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2611 if (rDocument.ValidRow(nStartRow))
2612 {
2613 if ( mvData.empty() )
2614 {
2615 rRow = nStartRow;
2616 if (bUp)
2617 {
2618 rEndRow = 0;
2619 if (pMarkArray)
2620 {
2621 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
2622 if (nMarkEnd>rEndRow)
2623 rEndRow = nMarkEnd;
2624 }
2625 }
2626 else
2627 {
2628 rEndRow = rDocument.MaxRow();
2629 if (pMarkArray)
2630 {
2631 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
2632 if (nMarkEnd<rEndRow)
2633 rEndRow = nMarkEnd;
2634 }
2635 }
2636
2637 return true;
2638 }
2639
2640 SCSIZE nIndex;
2641 Search(nStartRow,nIndex);
2642
2643 rRow = nStartRow;
2644 if (bUp)
2645 {
2646 if (nIndex>0)
2647 rEndRow = mvData[nIndex-1].nEndRow + 1;
2648 else
2649 rEndRow = 0;
2650 if (pMarkArray)
2651 {
2652 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
2653 if (nMarkEnd>rEndRow)
2654 rEndRow = nMarkEnd;
2655 }
2656 }
2657 else
2658 {
2659 rEndRow = mvData[nIndex].nEndRow;
2660 if (pMarkArray)
2661 {
2662 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
2663 if (nMarkEnd<rEndRow)
2664 rEndRow = nMarkEnd;
2665 }
2666 }
2667
2668 return true;
2669 }
2670 else
2671 return false;
2672}
2673
2674SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) const
2675{
2676 if ( mvData.empty() )
2677 return 1;
2678
2679 SCSIZE nIndex1, nIndex2;
2680
2681 if( !Search( nStartRow, nIndex1 ) )
2682 return 0;
2683
2684 if( !Search( nEndRow, nIndex2 ) )
2685 nIndex2 = mvData.size() - 1;
2686
2687 return nIndex2 - nIndex1 + 1;
2688}
2689
2690/* 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
static bool lcl_TestAttr(const SvxBorderLine *pOldLine, const SvxBorderLine *pNewLine, sal_uInt8 &rModified, const SvxBorderLine *&rpNew)
Definition: attarray.cxx:1029
static void SetLineColor(SvxBorderLine const *dest, Color c)
Definition: attarray.cxx:698
static void SetLine(const SvxBorderLine *dest, const SvxBorderLine *src)
Definition: attarray.cxx:706
static void lcl_MergeToFrame(SvxBoxItem *pLineOuter, SvxBoxInfoItem *pLineInner, ScLineFlags &rFlags, const ScPatternAttr *pPattern, bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom)
Definition: attarray.cxx:1060
static void lcl_MergeDeep(SfxItemSet &rMergeSet, const SfxItemSet &rSource)
Definition: attarray.cxx:937
const SCROW SC_VISATTR_STOP
Definition: attarray.cxx:1943
#define SC_LINE_EMPTY
Definition: attarray.hxx:46
#define SC_LINE_DONTCARE
Definition: attarray.hxx:48
#define SC_ATTRARRAY_DELTA
Definition: attarray.hxx:50
#define SC_LINE_SET
Definition: attarray.hxx:47
ScMF
Definition: attrib.hxx:34
@ Button
autofilter arrow
@ All
dp table output
double nx
virtual std::unique_ptr< EditTextObject > Clone() const=0
void SetRow(SCROW nRowP)
Definition: address.hxx:287
bool Concat(SCSIZE nPos)
Definition: attarray.cxx:154
bool RemoveFlags(SCROW nStartRow, SCROW nEndRow, ScMF nFlags)
Definition: attarray.cxx:1659
SCROW GetNextUnprotected(SCROW nRow, bool bUp) const
Including current, may return -1.
Definition: attarray.cxx:1790
void ClearItems(SCROW nStartRow, SCROW nEndRow, const sal_uInt16 *pWhich)
Definition: attarray.cxx:1696
ScAttrArray(const ScAttrArray &)=delete
void SetAttrEntries(std::vector< ScAttrEntry > &&vNewData)
Definition: attarray.cxx:919
void FindStyleSheet(const SfxStyleSheetBase *pStyleSheet, ScFlatBoolRowSegments &rUsedRows, bool bReset)
Definition: attarray.cxx:1827
void DeleteArea(SCROW nStartRow, SCROW nEndRow)
Definition: attarray.cxx:2333
bool Search(SCROW nRow, SCSIZE &nIndex) const
Definition: attarray.cxx:194
void DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
Definition: attarray.cxx:2345
bool ApplyFrame(const SvxBoxItem &rLineOuter, const SvxBoxInfoItem *pLineInner, SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom)
Definition: attarray.cxx:1165
ScDocument & rDocument
Definition: attarray.hxx:96
bool IsEmpty() const
Definition: attarray.cxx:1896
bool Reserve(SCSIZE nReserve)
Definition: attarray.cxx:423
bool HasVisibleAttrIn(SCROW nStartRow, SCROW nEndRow) const
Definition: attarray.cxx:2002
bool IsVisibleEqual(const ScAttrArray &rOther, SCROW nStartRow, SCROW nEndRow) const
Definition: attarray.cxx:2023
SCCOL nCol
Definition: attarray.hxx:94
void RemoveCellCharAttribs(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, ScEditDataArray *pDataArray)
Definition: attarray.cxx:393
bool IsMerged(SCROW nRow) const
Definition: attarray.cxx:1442
bool ApplyFlags(SCROW nStartRow, SCROW nEndRow, ScMF nFlags)
Definition: attarray.cxx:1622
void ApplyCacheArea(SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache *pCache, ScEditDataArray *pDataArray=nullptr, bool *const pIsChanged=nullptr)
Definition: attarray.cxx:836
void Reset(const ScPatternAttr *pPattern)
Definition: attarray.cxx:121
SCROW SearchStyle(SCROW nRow, const ScStyleSheet *pSearchStyle, bool bUp, const ScMarkArray *pMarkArray=nullptr) const
May return -1 if not found.
Definition: attarray.cxx:2534
void ChangeIndent(SCROW nStartRow, SCROW nEndRow, bool bIncrement)
Definition: attarray.cxx:1726
void SetDefaultIfNotInit(SCSIZE nNeeded=1)
Definition: attarray.cxx:109
void DeleteRow(SCROW nStartRow, SCSIZE nSize)
Definition: attarray.cxx:2275
SCSIZE Count() const
Definition: attarray.hxx:226
void MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray &rAttrArray)
Move within a document.
Definition: attarray.cxx:2389
void RemoveCondFormat(SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex)
if nIndex == 0, remove all conditional format data
Definition: attarray.cxx:336
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: attarray.cxx:239
void DeleteRange(SCSIZE nStartIndex, SCSIZE nEndIndex)
Definition: attarray.cxx:2323
void ApplyLineStyleArea(SCROW nStartRow, SCROW nEndRow, const ::editeng::SvxBorderLine *pLine, bool bColorOnly)
Definition: attarray.cxx:716
SCTAB nTab
Definition: attarray.hxx:95
void MergePatternArea(SCROW nStartRow, SCROW nEndRow, ScMergePatternState &rState, bool bDeep) const
Definition: attarray.cxx:973
bool GetFirstVisibleAttr(SCROW &rFirstRow) const
Definition: attarray.cxx:1909
void MergeBlockFrame(SvxBoxItem *pLineOuter, SvxBoxInfoItem *pLineInner, ScLineFlags &rFlags, SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight) const
Definition: attarray.cxx:1123
bool ExtendMerge(SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow, SCCOL &rPaintCol, SCROW &rPaintRow, bool bRefresh)
Area around any given summaries expand and adapt any MergeFlag (bRefresh)
Definition: attarray.cxx:1459
const ScPatternAttr * SetPatternAreaImpl(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, bool bPutToPool=false, ScEditDataArray *pDataArray=nullptr, bool bPassingPatternOwnership=false)
Definition: attarray.cxx:450
void SetPatternArea(SCROW nStartRow, SCROW nEndRow, std::unique_ptr< ScPatternAttr > pPattern, bool bPutToPool=false, ScEditDataArray *pDataArray=nullptr)
Definition: attarray.hxx:151
bool IsAllEqual(const ScAttrArray &rOther, SCROW nStartRow, SCROW nEndRow) const
Definition: attarray.cxx:2103
bool TestInsertRow(SCSIZE nSize) const
Definition: attarray.cxx:2208
bool IsStyleSheetUsed(const ScStyleSheet &rStyle) const
Definition: attarray.cxx:1862
bool HasAttrib_Impl(const ScPatternAttr *pPattern, HasAttrFlags nMask, SCROW nRow1, SCROW nRow2, SCSIZE i) const
Definition: attarray.cxx:1273
void CopyAreaSafe(SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray &rAttrArray)
Leave flags summarized with CopyArea.
Definition: attarray.cxx:2481
const ScPatternAttr * GetPatternRange(SCROW &rStartRow, SCROW &rEndRow, SCROW nRow) const
Returns if you search for attributes at nRow the range from rStartRow to rEndRow where that attribute...
Definition: attarray.cxx:254
void ApplyStyleArea(SCROW nStartRow, SCROW nEndRow, const ScStyleSheet &rStyle)
Definition: attarray.cxx:622
bool SearchStyleRange(SCROW &rRow, SCROW &rEndRow, const ScStyleSheet *pSearchStyle, bool bUp, const ScMarkArray *pMarkArray=nullptr) const
Definition: attarray.cxx:2606
void CopyArea(SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray &rAttrArray, ScMF nStripFlags=ScMF::NONE) const
Copy between documents (Clipboard)
Definition: attarray.cxx:2409
bool HasAttrib(SCROW nRow1, SCROW nRow2, HasAttrFlags nMask) const
Definition: attarray.cxx:1396
bool GetLastVisibleAttr(SCROW &rLastRow, SCROW nLastData) const
Definition: attarray.cxx:1945
void ApplyBlockFrame(const SvxBoxItem &rLineOuter, const SvxBoxInfoItem *pLineInner, SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight)
Definition: attarray.cxx:1234
bool TestInsertCol(SCROW nStartRow, SCROW nEndRow) const
Definition: attarray.cxx:2181
void InsertRow(SCROW nStartRow, SCSIZE nSize)
Definition: attarray.cxx:2226
void SetPatternAreaSafe(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pWantedPattern, bool bDefault)
Definition: attarray.cxx:1567
std::vector< ScAttrEntry > mvData
Definition: attarray.hxx:98
void AddCondFormat(SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex)
Definition: attarray.cxx:278
void RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
Definition: attarray.cxx:1512
void InvalidateTextWidth(std::u16string_view rStyleName)
Definition: documen8.cxx:295
SC_DLLPUBLIC sal_uInt16 GetColWidth(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4184
SC_DLLPUBLIC ScPatternAttr * GetDefPattern() const
Definition: document.cxx:6165
bool ValidRow(SCROW nRow) const
Definition: document.hxx:899
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:891
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6170
SC_DLLPUBLIC void ApplyPatternAreaTab(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr &rAttr)
Definition: document.cxx:4864
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:892
SC_DLLPUBLIC bool InitColumnBlockPosition(sc::ColumnBlockPosition &rBlockPos, SCTAB nTab, SCCOL nCol)
Definition: document.cxx:2663
SC_DLLPUBLIC bool ApplyFlagsTab(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, ScMF nFlags)
Definition: document.cxx:5083
void SetStreamValid(SCTAB nTab, bool bSet, bool bIgnoreLock=false)
Definition: document.cxx:937
SC_DLLPUBLIC void ApplyAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem &rAttr)
Definition: document.cxx:4835
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1081
SC_DLLPUBLIC ScStyleSheetPool * GetStyleSheetPool() const
Definition: document.cxx:6175
SC_DLLPUBLIC bool IsLayoutRTL(SCTAB nTab) const
Definition: document.cxx:998
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:798
void AddItem(SCTAB nTab, SCCOL nCol, SCROW nRow, std::unique_ptr< EditTextObject > pOldData, std::unique_ptr< EditTextObject > pNewData)
static void RemoveCharAttribs(EditTextObject &rEditText, const ScPatternAttr &rAttr)
Definition: editutil.cxx:155
bool setTrue(SCROW nRow1, SCROW nRow2)
static bool CheckWidthInvalidate(bool &bNumFormatChanged, const SfxItemSet &rNewAttrs, const SfxItemSet &rOldAttrs)
Definition: global.cxx:186
This is a rather odd datastructure.
Definition: markarr.hxx:44
SCROW GetNextMarked(SCROW nRow, bool bUp) const
Including current row, may return -1 if bUp and not found.
Definition: markarr.cxx:286
SCROW GetMarkEnd(SCROW nRow, bool bUp) const
Definition: markarr.cxx:309
SCCOL GetColMerge() const
Definition: attrib.hxx:68
bool IsMerged() const
Definition: attrib.hxx:71
SCROW GetRowMerge() const
Definition: attrib.hxx:69
bool HasAutoFilter() const
Definition: attrib.hxx:103
bool IsOverlapped() const
Definition: attrib.hxx:101
ScPatternAttr * PutInPool(ScDocument *pDestDoc, ScDocument *pSrcDoc) const
Definition: patattr.cxx:1083
bool IsVisible() const
Definition: patattr.cxx:1156
const ScStyleSheet * GetStyleSheet() const
Definition: patattr.hxx:128
bool IsVisibleEqual(const ScPatternAttr &rOther) const
Definition: patattr.cxx:1193
void SetStyleSheet(ScStyleSheet *pNewStyle, bool bClearDirectFormat=true)
Definition: patattr.cxx:1212
sal_uInt64 GetKey() const
Definition: patattr.cxx:1405
bool HasItemsSet(const sal_uInt16 *pWhich) const
Definition: patattr.cxx:1007
SfxItemSet & GetItemSet()
Definition: patattr.hxx:155
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:72
static SvxCellOrientation GetCellOrientation(const SfxItemSet &rItemSet, const SfxItemSet *pCondSet)
Definition: patattr.cxx:189
bool GetHideCell() const
Definition: attrib.hxx:147
bool GetProtection() const
Definition: attrib.hxx:143
void SetUsage(ScStyleSheet::Usage eUse) const
Definition: stlsheet.hxx:52
Degree100 GetValue() const
const SfxSetItem & ApplyTo(const SfxSetItem &rSetItem)
const SfxPoolItem & GetDefaultItem(sal_uInt16 nWhich) const
const T & Put(std::unique_ptr< T > xItem, sal_uInt16 nWhich=0)
void Remove(const SfxPoolItem &)
const WhichRangesContainer & GetRanges() const
SfxItemPool * GetPool() const
sal_uInt16 Count() const
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
void InvalidateItem(sal_uInt16 nWhich)
bool IsLoading() const
bool IsValid(SvxBoxInfoItemValidFlags nValid) const
const editeng::SvxBorderLine * GetHori() const
const editeng::SvxBorderLine * GetVert() const
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxInfoItemLine nLine)
const editeng::SvxBorderLine * GetTop() const
virtual SvxBoxItem * Clone(SfxItemPool *pPool=nullptr) const override
const editeng::SvxBorderLine * GetRight() const
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)
const editeng::SvxBorderLine * GetLeft() const
const editeng::SvxBorderLine * GetBottom() const
virtual SvxLineItem * Clone(SfxItemPool *pPool=nullptr) const override
SvxShadowLocation GetLocation() const
const_iterator begin() const
void reserve(size_type amount)
const_iterator find(const Value &x) const
void erase_at(size_t index)
const_iterator end() const
size_type size() const
std::pair< const_iterator, bool > insert(Value &&x)
int nCount
@ CELLTYPE_EDIT
Definition: global.hxx:276
#define SC_INDENT_STEP
Definition: global.hxx:223
HasAttrFlags
Definition: global.hxx:184
sal_Int32 nIndex
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
const SfxPoolItem * GetItem(const SwTextAttr &rAttr, sal_uInt16 nWhich)
ns
int i
TestDataElements TestData
long Long
sal_Int16 nId
SfxItemState
bool IsDefaultItem(const SfxPoolItem *pItem)
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
constexpr TypedWhichId< ScIndentItem > ATTR_INDENT(131)
constexpr TypedWhichId< ScMergeFlagAttr > ATTR_MERGE_FLAG(145)
constexpr TypedWhichId< ScPatternAttr > ATTR_PATTERN(156)
constexpr TypedWhichId< SvxLineItem > ATTR_BORDER_TLBR(141)
constexpr TypedWhichId< ScMergeAttr > ATTR_MERGE(144)
constexpr TypedWhichId< SvxShadowItem > ATTR_SHADOW(152)
constexpr TypedWhichId< ScRotateValueItem > ATTR_ROTATE_VALUE(135)
constexpr TypedWhichId< SvxHorJustifyItem > ATTR_HOR_JUSTIFY(129)
constexpr sal_uInt16 ATTR_PATTERN_START(100)
constexpr TypedWhichId< SvxBoxItem > ATTR_BORDER(150)
constexpr TypedWhichId< SvxLineItem > ATTR_BORDER_BLTR(142)
constexpr TypedWhichId< ScProtectionAttr > ATTR_PROTECTION(149)
constexpr sal_uInt16 ATTR_PATTERN_END(155)
constexpr TypedWhichId< ScLineBreakCell > ATTR_LINEBREAK(139)
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
static SfxItemSet & rSet
sal_uInt8 nHori
Definition: attarray.hxx:60
sal_uInt8 nVert
Definition: attarray.hxx:61
sal_uInt8 nLeft
Definition: attarray.hxx:56
sal_uInt8 nBottom
Definition: attarray.hxx:59
sal_uInt8 nRight
Definition: attarray.hxx:57
sal_uInt8 nTop
Definition: attarray.hxx:58
const ScPatternAttr * pOld2
Definition: attarray.hxx:71
std::optional< SfxItemSet > pItemSet
Definition: attarray.hxx:69
const ScPatternAttr * pOld1
existing objects, temporary
Definition: attarray.hxx:70
sal_uInt64 mnPatternId
Definition: attarray.hxx:74
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
const EditTextObject * getEditText() const
Definition: cellvalue.hxx:136
CellType getType() const
Definition: cellvalue.hxx:133
Store position data for column array storage.
SvxCellHorJustify
SvxShadowLocation
SvxBoxItem & rBoxItem
unsigned char sal_uInt8
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17