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>
22 #include <editeng/borderline.hxx>
23 #include <editeng/boxitem.hxx>
24 #include <editeng/lineitem.hxx>
25 #include <editeng/shaditem.hxx>
26 #include <editeng/editobj.hxx>
27 #include <editeng/justifyitem.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 
48 using ::editeng::SvxBorderLine;
49 
50 ScAttrArray::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
89 void ScAttrArray::TestData() const
90 {
91 
92  sal_uInt16 nErr = 0;
93  SCSIZE nPos;
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 
121 void 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 
146  rDocument.SetStreamValid(nTab, false);
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 
194 bool 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  }
265  SCSIZE nIndex;
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 
278 void 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  {
317  ScCondFormatItem aItem(nIndex);
318  pNewPattern->GetItemSet().Put( aItem );
319  }
320  }
321  else
322  {
323  pNewPattern.reset( new ScPatternAttr( rDocument.GetPool() ) );
324  ScCondFormatItem aItem(nIndex);
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 
336 void 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
398  sc::ColumnBlockPosition blockPos;
400  for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
401  {
402  ScAddress aPos(nCol, nRow, nTab);
403  ScRefCellValue aCell(rDocument, aPos, blockPos);
404  if (aCell.meType != CELLTYPE_EDIT || !aCell.mpEditText)
405  continue;
406 
407  std::unique_ptr<EditTextObject> pOldData;
408  if (pDataArray)
409  pOldData = aCell.mpEditText->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.mpEditText), *pPattern);
414 
415  if (pDataArray)
416  {
417  std::unique_ptr<EditTextObject> pNewData = aCell.mpEditText->Clone();
418  pDataArray->AddItem(nTab, nCol, nRow, std::move(pOldData), std::move(pNewData));
419  }
420  }
421 }
422 
423 bool ScAttrArray::Reserve( SCSIZE nReserve )
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 
450 const 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
478  SCSIZE nIndex;
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
491  bool bIsLoading = !rDocument.GetDocumentShell() || rDocument.GetDocumentShell()->IsLoading();
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 
612  rDocument.SetStreamValid(nTab, false);
613  }
614  }
615 
616 #if DEBUG_SC_TESTATTRARRAY
617  TestData();
618 #endif
619  return pPattern;
620 }
621 
622 void 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 
690  rDocument.SetStreamValid(nTab, false);
691 
692 #if DEBUG_SC_TESTATTRARRAY
693  TestData();
694 #endif
695 }
696 
697  // const cast, otherwise it will be too inefficient/complicated
698 static void SetLineColor(SvxBorderLine const * dest, Color c)
699 {
700  if (dest)
701  {
702  const_cast<SvxBorderLine*>(dest)->SetColor(c);
703  }
704 }
705 
706 static 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 
716 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
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( *pNewBoxItem );
802  if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem );
803  if( pNewBLTRItem ) rNewSet.Put( *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 
836 void 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 
912  rDocument.SetStreamValid(nTab, false);
913 
914 #if DEBUG_SC_TESTATTRARRAY
915  TestData();
916 #endif
917 }
918 
919 void 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 
937 static 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 
973 void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
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 
1029 static 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 
1060 static 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 
1165 bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
1166  const SvxBoxInfoItem* pBoxInfoItem,
1167  SCROW nStartRow, SCROW nEndRow,
1168  bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
1169 {
1170  OSL_ENSURE( pBoxItem && 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( pBoxItem->GetLeft(), SvxBoxItemLine::RIGHT );
1191  if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) )
1192  aNewFrame.SetLine( pBoxItem->GetRight(), SvxBoxItemLine::LEFT );
1193  }
1194  else
1195  {
1196  if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1197  aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1198  SvxBoxItemLine::RIGHT );
1199  if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1200  aNewFrame.SetLine( bLeft ? pBoxItem->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 ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1208  SvxBoxItemLine::LEFT );
1209  if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
1210  aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1211  SvxBoxItemLine::RIGHT );
1212  }
1213  if ( bTop ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
1214  aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
1215  SvxBoxItemLine::TOP );
1216  if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
1217  aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->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 
1234 void ScAttrArray::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
1235  SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight)
1236 {
1237  if (nStartRow == nEndRow)
1238  ApplyFrame(&rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0);
1239  else if ( !mvData.empty() )
1240  {
1241  ApplyFrame(&rLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1242  true, nEndRow-nStartRow);
1243 
1244  if ( nEndRow > nStartRow+1 ) // inner part available?
1245  {
1246  SCSIZE nStartIndex;
1247  SCSIZE nEndIndex;
1248  Search( nStartRow+1, nStartIndex );
1249  Search( nEndRow-1, nEndIndex );
1250  SCROW nTmpStart = nStartRow+1;
1251  SCROW nTmpEnd;
1252  for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1253  {
1254  nTmpEnd = std::min( static_cast<SCROW>(nEndRow-1), mvData[i].nEndRow );
1255  bool bChanged = ApplyFrame(&rLineOuter, pLineInner, nTmpStart, nTmpEnd,
1256  bLeft, nDistRight, false, nEndRow - nTmpEnd);
1257  nTmpStart = nTmpEnd+1;
1258  if (bChanged)
1259  {
1260  Search(nTmpStart, i);
1261  Search(nEndRow-1, nEndIndex);
1262  }
1263  else
1264  i++;
1265  }
1266  }
1267 
1268  ApplyFrame(&rLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0);
1269  }
1270  else
1271  {
1272  ApplyFrame(&rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0);
1273  }
1274 }
1275 
1276 bool ScAttrArray::HasAttrib_Impl(const ScPatternAttr* pPattern, HasAttrFlags nMask, SCROW nRow1, SCROW nRow2, SCSIZE i) const
1277 {
1278  bool bFound = false;
1279  if ( nMask & HasAttrFlags::Merged )
1280  {
1281  const ScMergeAttr* pMerge = &pPattern->GetItem( ATTR_MERGE );
1282  if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1283  bFound = true;
1284  }
1286  {
1287  const ScMergeFlagAttr* pMergeFlag = &pPattern->GetItem( ATTR_MERGE_FLAG );
1288  if ( (nMask & HasAttrFlags::Overlapped) && pMergeFlag->IsOverlapped() )
1289  bFound = true;
1290  if ( (nMask & HasAttrFlags::NotOverlapped) && !pMergeFlag->IsOverlapped() )
1291  bFound = true;
1292  if ( (nMask & HasAttrFlags::AutoFilter) && pMergeFlag->HasAutoFilter() )
1293  bFound = true;
1294  }
1295  if ( nMask & HasAttrFlags::Lines )
1296  {
1297  const SvxBoxItem* pBox = &pPattern->GetItem( ATTR_BORDER );
1298  if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1299  bFound = true;
1300  }
1301  if ( nMask & HasAttrFlags::Shadow )
1302  {
1303  const SvxShadowItem* pShadow = &pPattern->GetItem( ATTR_SHADOW );
1304  if ( pShadow->GetLocation() != SvxShadowLocation::NONE )
1305  bFound = true;
1306  }
1307  if ( nMask & HasAttrFlags::Conditional )
1308  {
1309  if ( !pPattern->GetItem( ATTR_CONDITIONAL ).GetCondFormatData().empty())
1310  bFound = true;
1311  }
1312  if ( nMask & HasAttrFlags::Protected )
1313  {
1314  const ScProtectionAttr* pProtect = &pPattern->GetItem( ATTR_PROTECTION );
1315  bool bFoundTemp = false;
1316  if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1317  bFoundTemp = true;
1318 
1319  bool bContainsCondFormat = !mvData.empty() &&
1320  !pPattern->GetItem( ATTR_CONDITIONAL ).GetCondFormatData().empty();
1321  if ( bContainsCondFormat && nCol != -1 ) // rDocument.GetCondResult() is valid only for real columns.
1322  {
1323  SCROW nRowStartCond = std::max<SCROW>( nRow1, i ? mvData[i-1].nEndRow + 1: 0 );
1324  SCROW nRowEndCond = std::min<SCROW>( nRow2, mvData[i].nEndRow );
1325  bool bFoundCond = false;
1326  for(SCROW nRowCond = nRowStartCond; nRowCond <= nRowEndCond && !bFoundCond; ++nRowCond)
1327  {
1328  const SfxItemSet* pSet = rDocument.GetCondResult( nCol, nRowCond, nTab );
1329 
1330  const ScProtectionAttr* pCondProtect;
1331  if( pSet && (pCondProtect = pSet->GetItemIfSet( ATTR_PROTECTION )) )
1332  {
1333  if( pCondProtect->GetProtection() || pCondProtect->GetHideCell() )
1334  bFoundCond = true;
1335  else
1336  break;
1337  }
1338  else
1339  {
1340  // well it is not true that we found one
1341  // but existing one + cell where conditional
1342  // formatting does not remove it
1343  // => we should use the existing protection setting
1344  bFoundCond = bFoundTemp;
1345  }
1346  }
1347  bFoundTemp = bFoundCond;
1348  }
1349 
1350  if(bFoundTemp)
1351  bFound = true;
1352  }
1353  if ( nMask & HasAttrFlags::Rotate )
1354  {
1355  const ScRotateValueItem* pRotate = &pPattern->GetItem( ATTR_ROTATE_VALUE );
1356  // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1357  // (see ScPatternAttr::GetCellOrientation)
1358  Degree100 nAngle = pRotate->GetValue();
1359  if ( nAngle && nAngle != 9000_deg100 && nAngle != 27000_deg100 )
1360  bFound = true;
1361  }
1362  if ( nMask & HasAttrFlags::NeedHeight )
1363  {
1364  if (pPattern->GetCellOrientation() != SvxCellOrientation::Standard)
1365  bFound = true;
1366  else if (pPattern->GetItem( ATTR_LINEBREAK ).GetValue())
1367  bFound = true;
1368  else if (pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Block)
1369  bFound = true;
1370 
1371  else if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
1372  bFound = true;
1373  else if (pPattern->GetItem( ATTR_ROTATE_VALUE ).GetValue())
1374  bFound = true;
1375  }
1377  {
1378  const SvxShadowItem* pShadow = &pPattern->GetItem( ATTR_SHADOW );
1379  SvxShadowLocation eLoc = pShadow->GetLocation();
1380  if ( nMask & HasAttrFlags::ShadowRight )
1381  if ( eLoc == SvxShadowLocation::TopRight || eLoc == SvxShadowLocation::BottomRight )
1382  bFound = true;
1383  if ( nMask & HasAttrFlags::ShadowDown )
1384  if ( eLoc == SvxShadowLocation::BottomLeft || eLoc == SvxShadowLocation::BottomRight )
1385  bFound = true;
1386  }
1387  if ( nMask & HasAttrFlags::RightOrCenter )
1388  {
1389  // called only if the sheet is LTR, so physical=logical alignment can be assumed
1390  SvxCellHorJustify eHorJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();
1391  if ( eHorJust == SvxCellHorJustify::Right || eHorJust == SvxCellHorJustify::Center )
1392  bFound = true;
1393  }
1394 
1395  return bFound;
1396 }
1397 
1398 // Test if field contains specific attribute
1399 bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const
1400 {
1401  if (mvData.empty())
1402  {
1403  return HasAttrib_Impl(rDocument.GetDefPattern(), nMask, 0, rDocument.MaxRow(), 0);
1404  }
1405 
1406  SCSIZE nStartIndex;
1407  SCSIZE nEndIndex;
1408  Search( nRow1, nStartIndex );
1409  if (nRow1 != nRow2)
1410  Search( nRow2, nEndIndex );
1411  else
1412  nEndIndex = nStartIndex;
1413  bool bFound = false;
1414 
1415  for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1416  {
1417  const ScPatternAttr* pPattern = mvData[i].pPattern;
1418  bFound = HasAttrib_Impl(pPattern, nMask, nRow1, nRow2, i);
1419  }
1420 
1421  return bFound;
1422 }
1423 
1424 bool ScAttrArray::HasAttrib( SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow, SCROW* nEndRow ) const
1425 {
1426  if (mvData.empty())
1427  {
1428  if( nStartRow )
1429  *nStartRow = 0;
1430  if( nEndRow )
1431  *nEndRow = rDocument.MaxRow();
1432  return HasAttrib_Impl(rDocument.GetDefPattern(), nMask, 0, rDocument.MaxRow(), 0);
1433  }
1434 
1435  SCSIZE nIndex;
1436  Search( nRow, nIndex );
1437  if( nStartRow )
1438  *nStartRow = nIndex > 0 ? mvData[nIndex-1].nEndRow+1 : 0;
1439  if( nEndRow )
1440  *nEndRow = mvData[nIndex].nEndRow;
1441  const ScPatternAttr* pPattern = mvData[nIndex].pPattern;
1442  return HasAttrib_Impl(pPattern, nMask, nRow, nRow, nIndex);
1443 }
1444 
1445 bool ScAttrArray::IsMerged( SCROW nRow ) const
1446 {
1447  if ( !mvData.empty() )
1448  {
1449  SCSIZE nIndex;
1450  Search(nRow, nIndex);
1451  const ScMergeAttr& rItem = mvData[nIndex].pPattern->GetItem(ATTR_MERGE);
1452 
1453  return rItem.IsMerged();
1454  }
1455 
1456  return rDocument.GetDefPattern()->GetItem(ATTR_MERGE).IsMerged();
1457 }
1458 
1462 bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
1463  SCCOL& rPaintCol, SCROW& rPaintRow,
1464  bool bRefresh )
1465 {
1466  assert( nCol != -1 );
1468  const ScPatternAttr* pPattern;
1469  const ScMergeAttr* pItem;
1470  SCSIZE nStartIndex;
1471  SCSIZE nEndIndex;
1472  Search( nStartRow, nStartIndex );
1473  Search( nEndRow, nEndIndex );
1474  bool bFound = false;
1475 
1476  for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1477  {
1478  pPattern = mvData[i].pPattern;
1479  pItem = &pPattern->GetItem( ATTR_MERGE );
1480  SCCOL nCountX = pItem->GetColMerge();
1481  SCROW nCountY = pItem->GetRowMerge();
1482  if (nCountX>1 || nCountY>1)
1483  {
1484  SCROW nThisRow = (i>0) ? mvData[i-1].nEndRow+1 : 0;
1485  SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1486  SCROW nMergeEndRow = nThisRow + nCountY - 1;
1487  if (nMergeEndCol > rPaintCol && nMergeEndCol <= rDocument.MaxCol())
1488  rPaintCol = nMergeEndCol;
1489  if (nMergeEndRow > rPaintRow && nMergeEndRow <= rDocument.MaxRow())
1490  rPaintRow = nMergeEndRow;
1491  bFound = true;
1492 
1493  if (bRefresh)
1494  {
1495  if ( nMergeEndCol > nThisCol )
1496  rDocument.ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, mvData[i].nEndRow,
1497  nTab, ScMF::Hor );
1498  if ( nMergeEndRow > nThisRow )
1499  rDocument.ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1500  nTab, ScMF::Ver );
1501  if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1502  rDocument.ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1503  nTab, ScMF::Hor | ScMF::Ver );
1504 
1505  Search( nThisRow, i ); // Data changed
1506  Search( nStartRow, nStartIndex );
1507  Search( nEndRow, nEndIndex );
1508  }
1509  }
1510  }
1511 
1512  return bFound;
1513 }
1514 
1515 void ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1516 {
1517  assert( nCol != -1 );
1519  const ScPatternAttr* pPattern;
1520  const ScMergeAttr* pItem;
1521  SCSIZE nIndex;
1522 
1523  Search( nStartRow, nIndex );
1524  SCROW nThisStart = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1525  if (nThisStart < nStartRow)
1526  nThisStart = nStartRow;
1527 
1528  while ( nThisStart <= nEndRow )
1529  {
1530  SCROW nThisEnd = mvData[nIndex].nEndRow;
1531  if (nThisEnd > nEndRow)
1532  nThisEnd = nEndRow;
1533 
1534  pPattern = mvData[nIndex].pPattern;
1535  pItem = &pPattern->GetItem( ATTR_MERGE );
1536  SCCOL nCountX = pItem->GetColMerge();
1537  SCROW nCountY = pItem->GetRowMerge();
1538  if (nCountX>1 || nCountY>1)
1539  {
1540  const ScMergeAttr* pAttr = &rDocument.GetPool()->GetDefaultItem( ATTR_MERGE );
1542 
1543  OSL_ENSURE( nCountY==1 || nThisStart==nThisEnd, "What's up?" );
1544 
1545  SCCOL nThisCol = nCol;
1546  SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1547  SCROW nMergeEndRow = nThisEnd + nCountY - 1;
1548 
1549  // ApplyAttr for areas
1550  for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
1551  rDocument.ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
1552 
1553  ScPatternAttr aNewPattern( rDocument.GetPool() );
1554  SfxItemSet* pSet = &aNewPattern.GetItemSet();
1555  pSet->Put( *pFlagAttr );
1556  rDocument.ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
1557  nTab, aNewPattern );
1558 
1559  Search( nThisEnd, nIndex ); // data changed
1560  }
1561 
1562  ++nIndex;
1563  if ( nIndex < mvData.size() )
1564  nThisStart = mvData[nIndex-1].nEndRow+1;
1565  else
1566  nThisStart = rDocument.MaxRow()+1; // End
1567  }
1568 }
1569 
1571  const ScPatternAttr* pWantedPattern, bool bDefault )
1572 {
1574  const ScPatternAttr* pOldPattern;
1575  const ScMergeFlagAttr* pItem;
1576 
1577  SCSIZE nIndex;
1578  SCROW nRow;
1579  SCROW nThisRow;
1580  bool bFirstUse = true;
1581 
1582  Search( nStartRow, nIndex );
1583  nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1584  while ( nThisRow <= nEndRow )
1585  {
1586  pOldPattern = mvData[nIndex].pPattern;
1587  if (pOldPattern != pWantedPattern) // FIXME: else-branch?
1588  {
1589  if (nThisRow < nStartRow) nThisRow = nStartRow;
1590  nRow = mvData[nIndex].nEndRow;
1591  SCROW nAttrRow = std::min( nRow, nEndRow );
1592  pItem = &pOldPattern->GetItem( ATTR_MERGE_FLAG );
1593 
1594  if (pItem->IsOverlapped() || pItem->HasAutoFilter())
1595  {
1596  // default-constructing a ScPatternAttr for DeleteArea doesn't work
1597  // because it would have no cell style information.
1598  // Instead, the document's GetDefPattern is copied. Since it is passed as
1599  // pWantedPattern, no special treatment of default is needed here anymore.
1600  std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pWantedPattern ));
1601  pNewPattern->GetItemSet().Put( *pItem );
1602  SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
1603  }
1604  else
1605  {
1606  if ( !bDefault )
1607  {
1608  if (bFirstUse)
1609  bFirstUse = false;
1610  else
1611  // it's in the pool
1612  rDocument.GetPool()->Put( *pWantedPattern );
1613  }
1614  SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
1615  }
1616 
1617  Search( nThisRow, nIndex ); // data changed
1618  }
1619 
1620  ++nIndex;
1621  nThisRow = mvData[nIndex-1].nEndRow+1;
1622  }
1623 }
1624 
1625 bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
1626 {
1628  const ScPatternAttr* pOldPattern;
1629 
1630  ScMF nOldValue;
1631  SCSIZE nIndex;
1632  SCROW nRow;
1633  SCROW nThisRow;
1634  bool bChanged = false;
1635 
1636  Search( nStartRow, nIndex );
1637  nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1638  if (nThisRow < nStartRow) nThisRow = nStartRow;
1639 
1640  while ( nThisRow <= nEndRow )
1641  {
1642  pOldPattern = mvData[nIndex].pPattern;
1643  nOldValue = pOldPattern->GetItem( ATTR_MERGE_FLAG ).GetValue();
1644  if ( (nOldValue | nFlags) != nOldValue )
1645  {
1646  nRow = mvData[nIndex].nEndRow;
1647  SCROW nAttrRow = std::min( nRow, nEndRow );
1648  auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
1649  pNewPattern->GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1650  SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
1651  Search( nThisRow, nIndex ); // data changed
1652  bChanged = true;
1653  }
1654 
1655  ++nIndex;
1656  nThisRow = mvData[nIndex-1].nEndRow+1;
1657  }
1658 
1659  return bChanged;
1660 }
1661 
1662 bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
1663 {
1665  const ScPatternAttr* pOldPattern;
1666 
1667  ScMF nOldValue;
1668  SCSIZE nIndex;
1669  SCROW nRow;
1670  SCROW nThisRow;
1671  bool bChanged = false;
1672 
1673  Search( nStartRow, nIndex );
1674  nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1675  if (nThisRow < nStartRow) nThisRow = nStartRow;
1676 
1677  while ( nThisRow <= nEndRow )
1678  {
1679  pOldPattern = mvData[nIndex].pPattern;
1680  nOldValue = pOldPattern->GetItem( ATTR_MERGE_FLAG ).GetValue();
1681  if ( (nOldValue & ~nFlags) != nOldValue )
1682  {
1683  nRow = mvData[nIndex].nEndRow;
1684  SCROW nAttrRow = std::min( nRow, nEndRow );
1685  auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
1686  pNewPattern->GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1687  SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
1688  Search( nThisRow, nIndex ); // data changed
1689  bChanged = true;
1690  }
1691 
1692  ++nIndex;
1693  nThisRow = mvData[nIndex-1].nEndRow+1;
1694  }
1695 
1696  return bChanged;
1697 }
1698 
1699 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
1700 {
1702  SCSIZE nIndex;
1703  SCROW nRow;
1704  SCROW nThisRow;
1705 
1706  Search( nStartRow, nIndex );
1707  nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1708  if (nThisRow < nStartRow) nThisRow = nStartRow;
1709 
1710  while ( nThisRow <= nEndRow )
1711  {
1712  const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
1713  if ( pOldPattern->HasItemsSet( pWhich ) )
1714  {
1715  auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
1716  pNewPattern->ClearItems( pWhich );
1717 
1718  nRow = mvData[nIndex].nEndRow;
1719  SCROW nAttrRow = std::min( nRow, nEndRow );
1720  SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
1721  Search( nThisRow, nIndex ); // data changed
1722  }
1723 
1724  ++nIndex;
1725  nThisRow = mvData[nIndex-1].nEndRow+1;
1726  }
1727 }
1728 
1729 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement )
1730 {
1732  SCSIZE nIndex;
1733  Search( nStartRow, nIndex );
1734  SCROW nThisStart = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
1735  if (nThisStart < nStartRow) nThisStart = nStartRow;
1736 
1737  while ( nThisStart <= nEndRow )
1738  {
1739  const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
1740  const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1741  const SvxHorJustifyItem* pItem;
1742 
1743  bool bNeedJust = !( pItem = rOldSet.GetItemIfSet( ATTR_HOR_JUSTIFY, false ) )
1744  || (pItem->GetValue() != SvxCellHorJustify::Left &&
1745  pItem->GetValue() != SvxCellHorJustify::Right );
1746  sal_uInt16 nOldValue = rOldSet.Get( ATTR_INDENT ).GetValue();
1747  sal_uInt16 nNewValue = nOldValue;
1748  // To keep Increment indent from running outside the cell1659
1749  tools::Long nColWidth = static_cast<tools::Long>(
1751  if ( bIncrement )
1752  {
1753  if ( nNewValue < nColWidth-SC_INDENT_STEP )
1754  {
1755  nNewValue += SC_INDENT_STEP;
1756  if ( nNewValue > nColWidth-SC_INDENT_STEP )
1757  nNewValue = nColWidth-SC_INDENT_STEP;
1758  }
1759  }
1760  else
1761  {
1762  if ( nNewValue > 0 )
1763  {
1764  if ( nNewValue > SC_INDENT_STEP )
1765  nNewValue -= SC_INDENT_STEP;
1766  else
1767  nNewValue = 0;
1768  }
1769  }
1770 
1771  if ( bNeedJust || nNewValue != nOldValue )
1772  {
1773  SCROW nThisEnd = mvData[nIndex].nEndRow;
1774  SCROW nAttrRow = std::min( nThisEnd, nEndRow );
1775  auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
1776  pNewPattern->GetItemSet().Put( ScIndentItem( nNewValue ) );
1777  if ( bNeedJust )
1778  pNewPattern->GetItemSet().Put(
1779  SvxHorJustifyItem( SvxCellHorJustify::Left, ATTR_HOR_JUSTIFY ) );
1780  SetPatternArea( nThisStart, nAttrRow, std::move(pNewPattern), true );
1781 
1782  nThisStart = nThisEnd + 1;
1783  Search( nThisStart, nIndex ); // data changed
1784  }
1785  else
1786  {
1787  nThisStart = mvData[nIndex].nEndRow + 1;
1788  ++nIndex;
1789  }
1790  }
1791 }
1792 
1794 {
1795  tools::Long nRet = nRow;
1796  if (rDocument.ValidRow(nRow))
1797  {
1798  if ( mvData.empty() )
1799  {
1800  if ( bUp )
1801  return -1;
1802  else
1803  return rDocument.MaxRow()+1;
1804  }
1805 
1806  SCSIZE nIndex;
1807  Search(nRow, nIndex);
1808  while (mvData[nIndex].pPattern->
1809  GetItem(ATTR_PROTECTION).GetProtection())
1810  {
1811  if (bUp)
1812  {
1813  if (nIndex==0)
1814  return -1; // not found
1815  --nIndex;
1816  nRet = mvData[nIndex].nEndRow;
1817  }
1818  else
1819  {
1820  nRet = mvData[nIndex].nEndRow+1;
1821  ++nIndex;
1822  if (nIndex >= mvData.size())
1823  return rDocument.MaxRow()+1; // not found
1824  }
1825  }
1826  }
1827  return nRet;
1828 }
1829 
1830 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1831 {
1833  SCROW nStart = 0;
1834  SCSIZE nPos = 0;
1835  while (nPos < mvData.size())
1836  {
1837  SCROW nEnd = mvData[nPos].nEndRow;
1838  if (mvData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1839  {
1840  rUsedRows.setTrue(nStart, nEnd);
1841 
1842  if (bReset)
1843  {
1844  ScPatternAttr aNewPattern(*mvData[nPos].pPattern);
1845  rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
1846  aNewPattern.SetStyleSheet( static_cast<ScStyleSheet*>(
1848  Find( ScResId(STR_STYLENAME_STANDARD),
1849  SfxStyleFamily::Para,
1850  SfxStyleSearchBits::Auto | SfxStyleSearchBits::ScStandard ) ) );
1851  mvData[nPos].pPattern = &rDocument.GetPool()->Put(aNewPattern);
1852 
1853  if (Concat(nPos))
1854  {
1855  Search(nStart, nPos);
1856  --nPos; // because ++ at end
1857  }
1858  }
1859  }
1860  nStart = nEnd + 1;
1861  ++nPos;
1862  }
1863 }
1864 
1865 bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
1866 {
1867  if ( mvData.empty() )
1868  {
1869  const ScStyleSheet* pStyle = rDocument.GetDefPattern()->GetStyleSheet();
1870  if ( pStyle )
1871  {
1873  if ( pStyle == &rStyle )
1874  return true;
1875  }
1876  return false;
1877  }
1878 
1879  bool bIsUsed = false;
1880  SCSIZE nPos = 0;
1881 
1882  while ( nPos < mvData.size() )
1883  {
1884  const ScStyleSheet* pStyle = mvData[nPos].pPattern->GetStyleSheet();
1885  if ( pStyle )
1886  {
1888  if ( pStyle == &rStyle )
1889  {
1890  bIsUsed = true;
1891  }
1892  }
1893  nPos++;
1894  }
1895 
1896  return bIsUsed;
1897 }
1898 
1900 {
1901  if ( mvData.empty() )
1902  return true;
1903 
1904  if (mvData.size() == 1)
1905  {
1906  return mvData[0].pPattern == rDocument.GetDefPattern();
1907  }
1908  else
1909  return false;
1910 }
1911 
1912 bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1913 {
1914  if ( mvData.empty() )
1915  return false;
1916 
1917  bool bFound = false;
1918  SCSIZE nStart = 0;
1919 
1920  // Skip first entry if more than 1 row.
1921  // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1922 
1923  SCSIZE nVisStart = 1;
1924  while ( nVisStart < mvData.size() && mvData[nVisStart].pPattern->IsVisibleEqual(*mvData[nVisStart-1].pPattern) )
1925  ++nVisStart;
1926  if ( nVisStart >= mvData.size() || mvData[nVisStart-1].nEndRow > 0 ) // more than 1 row?
1927  nStart = nVisStart;
1928 
1929  while ( nStart < mvData.size() && !bFound )
1930  {
1931  if ( mvData[nStart].pPattern->IsVisible() )
1932  {
1933  rFirstRow = nStart ? ( mvData[nStart-1].nEndRow + 1 ) : 0;
1934  bFound = true;
1935  }
1936  else
1937  ++nStart;
1938  }
1939 
1940  return bFound;
1941 }
1942 
1943 // size (rows) of a range of attributes after cell content where the search is stopped
1944 // (more than a default page size, 2*42 because it's as good as any number)
1945 
1947 
1948 bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
1949 {
1950  if ( mvData.empty() )
1951  {
1952  rLastRow = nLastData;
1953  return false;
1954  }
1955 
1956  // #i30830# changed behavior:
1957  // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1958  // below the last content cell
1959 
1960  if ( nLastData == rDocument.MaxRow() )
1961  {
1962  rLastRow = rDocument.MaxRow(); // can't look for attributes below rDocument.MaxRow()
1963  return true;
1964  }
1965 
1966  // Quick check: last data row in or immediately preceding a run that is the
1967  // last attribution down to the end, e.g. default style or column style.
1968  SCSIZE nPos = mvData.size() - 1;
1969  SCROW nStartRow = (nPos ? mvData[nPos-1].nEndRow + 1 : 0);
1970  if (nStartRow <= nLastData + 1)
1971  {
1972  // Ignore here a few rows if data happens to end within
1973  // SC_VISATTR_STOP rows before rDocument.MaxRow().
1974  rLastRow = nLastData;
1975  return false;
1976  }
1977 
1978  // Find a run below last data row.
1979  bool bFound = false;
1980  Search( nLastData, nPos );
1981  while ( nPos < mvData.size() )
1982  {
1983  // find range of visually equal formats
1984  SCSIZE nEndPos = nPos;
1985  while ( nEndPos < mvData.size()-1 &&
1986  mvData[nEndPos].pPattern->IsVisibleEqual( *mvData[nEndPos+1].pPattern))
1987  ++nEndPos;
1988  SCROW nAttrStartRow = ( nPos > 0 ) ? ( mvData[nPos-1].nEndRow + 1 ) : 0;
1989  if ( nAttrStartRow <= nLastData )
1990  nAttrStartRow = nLastData + 1;
1991  SCROW nAttrSize = mvData[nEndPos].nEndRow + 1 - nAttrStartRow;
1992  if ( nAttrSize >= SC_VISATTR_STOP )
1993  break; // while, ignore this range and below
1994  else if ( mvData[nEndPos].pPattern->IsVisible() )
1995  {
1996  rLastRow = mvData[nEndPos].nEndRow;
1997  bFound = true;
1998  }
1999  nPos = nEndPos + 1;
2000  }
2001 
2002  return bFound;
2003 }
2004 
2005 bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
2006 {
2007  if ( mvData.empty() )
2008  return rDocument.GetDefPattern()->IsVisible();
2009 
2010  SCSIZE nIndex;
2011  Search( nStartRow, nIndex );
2012  SCROW nThisStart = nStartRow;
2013  bool bFound = false;
2014  while ( nIndex < mvData.size() && nThisStart <= nEndRow && !bFound )
2015  {
2016  if ( mvData[nIndex].pPattern->IsVisible() )
2017  bFound = true;
2018 
2019  nThisStart = mvData[nIndex].nEndRow + 1;
2020  ++nIndex;
2021  }
2022 
2023  return bFound;
2024 }
2025 
2027  SCROW nStartRow, SCROW nEndRow ) const
2028 {
2029  if ( mvData.empty() && rOther.mvData.empty() )
2030  {
2031  const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern();
2032  const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern();
2033  return ( pDefPattern1 == pDefPattern2 || pDefPattern1->IsVisibleEqual( *pDefPattern2 ) );
2034  }
2035 
2036  {
2037  const ScAttrArray* pNonDefault = nullptr;
2038  const ScPatternAttr* pDefPattern = nullptr;
2039  bool bDefNonDefCase = false;
2040  if ( mvData.empty() && !rOther.mvData.empty() )
2041  {
2042  pNonDefault = &rOther;
2043  pDefPattern = rDocument.GetDefPattern();
2044  bDefNonDefCase = true;
2045  }
2046  else if ( !mvData.empty() && rOther.mvData.empty() )
2047  {
2048  pNonDefault = this;
2049  pDefPattern = rOther.rDocument.GetDefPattern();
2050  bDefNonDefCase = true;
2051  }
2052 
2053  if ( bDefNonDefCase )
2054  {
2055  bool bEqual = true;
2056  SCSIZE nPos = 0;
2057  if ( nStartRow > 0 )
2058  pNonDefault->Search( nStartRow, nPos );
2059 
2060  while ( nPos < pNonDefault->Count() && bEqual )
2061  {
2062  const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern;
2063  bEqual = ( pNonDefPattern == pDefPattern ||
2064  pNonDefPattern->IsVisibleEqual( *pDefPattern ) );
2065 
2066  if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break;
2067  ++nPos;
2068  }
2069  return bEqual;
2070  }
2071  }
2072 
2073  bool bEqual = true;
2074  SCSIZE nThisPos = 0;
2075  SCSIZE nOtherPos = 0;
2076  if ( nStartRow > 0 )
2077  {
2078  Search( nStartRow, nThisPos );
2079  rOther.Search( nStartRow, nOtherPos );
2080  }
2081 
2082  while ( nThisPos<mvData.size() && nOtherPos<rOther.Count() && bEqual )
2083  {
2084  SCROW nThisRow = mvData[nThisPos].nEndRow;
2085  SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow;
2086  const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern;
2087  const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern;
2088  bEqual = ( pThisPattern == pOtherPattern ||
2089  pThisPattern->IsVisibleEqual(*pOtherPattern) );
2090 
2091  if ( nThisRow >= nOtherRow )
2092  {
2093  if ( nOtherRow >= nEndRow ) break;
2094  ++nOtherPos;
2095  }
2096  if ( nThisRow <= nOtherRow )
2097  {
2098  if ( nThisRow >= nEndRow ) break;
2099  ++nThisPos;
2100  }
2101  }
2102 
2103  return bEqual;
2104 }
2105 
2106 bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
2107 {
2108  // summarised with IsVisibleEqual
2109  if ( mvData.empty() && rOther.mvData.empty() )
2110  {
2111  const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern();
2112  const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern();
2113  return ( pDefPattern1 == pDefPattern2 );
2114  }
2115 
2116  {
2117  const ScAttrArray* pNonDefault = nullptr;
2118  const ScPatternAttr* pDefPattern = nullptr;
2119  bool bDefNonDefCase = false;
2120  if ( mvData.empty() && !rOther.mvData.empty() )
2121  {
2122  pNonDefault = &rOther;
2123  pDefPattern = rDocument.GetDefPattern();
2124  bDefNonDefCase = true;
2125  }
2126  else if ( !mvData.empty() && rOther.mvData.empty() )
2127  {
2128  pNonDefault = this;
2129  pDefPattern = rOther.rDocument.GetDefPattern();
2130  bDefNonDefCase = true;
2131  }
2132 
2133  if ( bDefNonDefCase )
2134  {
2135  bool bEqual = true;
2136  SCSIZE nPos = 0;
2137  if ( nStartRow > 0 )
2138  pNonDefault->Search( nStartRow, nPos );
2139 
2140  while ( nPos < pNonDefault->Count() && bEqual )
2141  {
2142  const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern;
2143  bEqual = ( pNonDefPattern == pDefPattern );
2144 
2145  if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break;
2146  ++nPos;
2147  }
2148  return bEqual;
2149  }
2150  }
2151 
2152  bool bEqual = true;
2153  SCSIZE nThisPos = 0;
2154  SCSIZE nOtherPos = 0;
2155  if ( nStartRow > 0 )
2156  {
2157  Search( nStartRow, nThisPos );
2158  rOther.Search( nStartRow, nOtherPos );
2159  }
2160 
2161  while ( nThisPos<mvData.size() && nOtherPos<rOther.Count() && bEqual )
2162  {
2163  SCROW nThisRow = mvData[nThisPos].nEndRow;
2164  SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow;
2165  const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern;
2166  const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern;
2167  bEqual = ( pThisPattern == pOtherPattern );
2168 
2169  if ( nThisRow >= nOtherRow )
2170  {
2171  if ( nOtherRow >= nEndRow ) break;
2172  ++nOtherPos;
2173  }
2174  if ( nThisRow <= nOtherRow )
2175  {
2176  if ( nThisRow >= nEndRow ) break;
2177  ++nThisPos;
2178  }
2179  }
2180 
2181  return bEqual;
2182 }
2183 
2184 bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2185 {
2186  // Horizontal aggregate are not allowed to be moved out; if whole summary,
2187  // here is not recognized
2188 
2189  bool bTest = true;
2190  if (!IsEmpty())
2191  {
2192  SCSIZE nIndex = 0;
2193  if ( nStartRow > 0 )
2194  Search( nStartRow, nIndex );
2195 
2196  for ( ; nIndex < mvData.size(); nIndex++ )
2197  {
2198  if ( mvData[nIndex].pPattern->
2199  GetItem(ATTR_MERGE_FLAG).IsHorOverlapped() )
2200  {
2201  bTest = false; // may not be pushed out
2202  break;
2203  }
2204  if ( mvData[nIndex].nEndRow >= nEndRow ) // end of range
2205  break;
2206  }
2207  }
2208  return bTest;
2209 }
2210 
2212 {
2213  // if 1st row pushed out is vertically overlapped, summary would be broken
2214 
2215  // rDocument.MaxRow() + 1 - nSize = 1st row pushed out
2216 
2217  if ( mvData.empty() )
2218  return !rDocument.GetDefPattern()->
2219  GetItem(ATTR_MERGE_FLAG).IsVerOverlapped();
2220 
2221  SCSIZE nFirstLost = mvData.size()-1;
2222  while ( nFirstLost && mvData[nFirstLost-1].nEndRow >= sal::static_int_cast<SCROW>(rDocument.MaxRow() + 1 - nSize) )
2223  --nFirstLost;
2224 
2225  return !mvData[nFirstLost].pPattern->
2226  GetItem(ATTR_MERGE_FLAG).IsVerOverlapped();
2227 }
2228 
2229 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2230 {
2232 
2233  SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // expand predecessor
2234  SCSIZE nIndex;
2235  Search( nSearch, nIndex );
2236 
2237  // set ScMergeAttr may not be extended (so behind delete again)
2238 
2239  bool bDoMerge = mvData[nIndex].pPattern->GetItem(ATTR_MERGE).IsMerged();
2240 
2241  assert( !bDoMerge || nCol != -1 );
2242 
2243  SCSIZE nRemove = 0;
2244  SCSIZE i;
2245  for (i = nIndex; i < mvData.size()-1; i++)
2246  {
2247  SCROW nNew = mvData[i].nEndRow + nSize;
2248  if ( nNew >= rDocument.MaxRow() ) // at end?
2249  {
2250  nNew = rDocument.MaxRow();
2251  if (!nRemove)
2252  nRemove = i+1; // remove the following?
2253  }
2254  mvData[i].nEndRow = nNew;
2255  }
2256 
2257  // Remove entries at end ?
2258 
2259  if (nRemove && nRemove < mvData.size())
2260  DeleteRange( nRemove, mvData.size()-1 );
2261 
2262  if (bDoMerge) // extensively repair (again) ScMergeAttr
2263  {
2264  // ApplyAttr for areas
2265 
2267  for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2268  rDocument.ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2269 
2270  // reply inserts in this area not summarized
2271  }
2272 
2273  // Don't duplicate the merge flags in the inserted row.
2274  // #i108488# ScMF::Scenario has to be allowed.
2275  RemoveFlags( nStartRow, nStartRow+nSize-1, ScMF::Hor | ScMF::Ver | ScMF::Auto | ScMF::Button );
2276 }
2277 
2278 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2279 {
2281  bool bFirst=true;
2282  SCSIZE nStartIndex = 0;
2283  SCSIZE nEndIndex = 0;
2284  SCSIZE i;
2285 
2286  for ( i = 0; i < mvData.size()-1; i++)
2287  if (mvData[i].nEndRow >= nStartRow && mvData[i].nEndRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2288  {
2289  if (bFirst)
2290  {
2291  nStartIndex = i;
2292  bFirst = false;
2293  }
2294  nEndIndex = i;
2295  }
2296  if (!bFirst)
2297  {
2298  SCROW nStart;
2299  if (nStartIndex==0)
2300  nStart = 0;
2301  else
2302  nStart = mvData[nStartIndex-1].nEndRow + 1;
2303 
2304  if (nStart < nStartRow)
2305  {
2306  mvData[nStartIndex].nEndRow = nStartRow - 1;
2307  ++nStartIndex;
2308  }
2309  if (nEndIndex >= nStartIndex)
2310  {
2311  DeleteRange( nStartIndex, nEndIndex );
2312  if (nStartIndex > 0)
2313  if ( mvData[nStartIndex-1].pPattern == mvData[nStartIndex].pPattern )
2314  DeleteRange( nStartIndex-1, nStartIndex-1 );
2315  }
2316  }
2317  for (i = 0; i < mvData.size()-1; i++)
2318  if (mvData[i].nEndRow >= nStartRow)
2319  mvData[i].nEndRow -= nSize;
2320 
2321  // Below does not follow the pattern to detect pressure ranges;
2322  // instead, only remove merge flags.
2324 }
2325 
2326 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2327 {
2329  ScDocumentPool* pDocPool = rDocument.GetPool();
2330  for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2331  pDocPool->Remove(*mvData[i].pPattern);
2332 
2333  mvData.erase(mvData.begin() + nStartIndex, mvData.begin() + nEndIndex + 1);
2334 }
2335 
2336 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2337 {
2339  if ( nCol != -1 )
2340  RemoveAreaMerge( nStartRow, nEndRow ); // remove from combined flags
2341 
2342  if ( !HasAttrib( nStartRow, nEndRow, HasAttrFlags::Overlapped | HasAttrFlags::AutoFilter) )
2343  SetPatternArea( nStartRow, nEndRow, rDocument.GetDefPattern() );
2344  else
2345  SetPatternAreaSafe( nStartRow, nEndRow, rDocument.GetDefPattern(), true ); // leave merge flags
2346 }
2347 
2348 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2349 {
2351  const ScPatternAttr* pDefPattern = rDocument.GetDefPattern();
2352 
2353  SCSIZE nIndex;
2354  SCROW nRow;
2355  SCROW nThisRow;
2356 
2357  Search( nStartRow, nIndex );
2358  nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0;
2359  if (nThisRow < nStartRow) nThisRow = nStartRow;
2360 
2361  while ( nThisRow <= nEndRow )
2362  {
2363  const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern;
2364 
2365  if ( pOldPattern->GetItemSet().Count() ) // hard attributes ?
2366  {
2367  nRow = mvData[nIndex].nEndRow;
2368  SCROW nAttrRow = std::min( nRow, nEndRow );
2369 
2370  auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern);
2371  SfxItemSet& rSet = pNewPattern->GetItemSet();
2372  for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2373  if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2374  rSet.ClearItem(nId);
2375 
2376  if ( *pNewPattern == *pDefPattern )
2377  SetPatternArea( nThisRow, nAttrRow, pDefPattern );
2378  else
2379  SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true );
2380 
2381  Search( nThisRow, nIndex ); // data changed
2382  }
2383 
2384  ++nIndex;
2385  nThisRow = mvData[nIndex-1].nEndRow+1;
2386  }
2387 }
2388 
2392 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2393 {
2395  SCROW nStart = nStartRow;
2396  for (SCSIZE i = 0; i < mvData.size(); i++)
2397  {
2398  if ((mvData[i].nEndRow >= nStartRow) && (i == 0 || mvData[i-1].nEndRow < nEndRow))
2399  {
2400  // copy (bPutToPool=TRUE)
2401  rAttrArray.SetPatternArea( nStart, std::min( mvData[i].nEndRow, nEndRow ),
2402  mvData[i].pPattern, true );
2403  }
2404  nStart = std::max( nStart, mvData[i].nEndRow + 1 );
2405  }
2406  DeleteArea(nStartRow, nEndRow);
2407 }
2408 
2413  SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray& rAttrArray, ScMF nStripFlags) const
2414 {
2415  nStartRow -= nDy; // Source
2416  nEndRow -= nDy;
2417 
2418  SCROW nDestStart = std::max(static_cast<tools::Long>(static_cast<tools::Long>(nStartRow) + nDy), tools::Long(0));
2419  SCROW nDestEnd = std::min(static_cast<tools::Long>(static_cast<tools::Long>(nEndRow) + nDy), tools::Long(rDocument.MaxRow()));
2420 
2421  ScDocumentPool* pSourceDocPool = rDocument.GetPool();
2422  ScDocumentPool* pDestDocPool = rAttrArray.rDocument.GetPool();
2423  bool bSamePool = (pSourceDocPool==pDestDocPool);
2424 
2425  if ( mvData.empty() )
2426  {
2427  const ScPatternAttr* pNewPattern = &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2428  rAttrArray.SetPatternArea(nDestStart, nDestEnd, pNewPattern);
2429  return;
2430  }
2431 
2432  for (SCSIZE i = 0; (i < mvData.size()) && (nDestStart <= nDestEnd); i++)
2433  {
2434  if (mvData[i].nEndRow >= nStartRow)
2435  {
2436  const ScPatternAttr* pOldPattern = mvData[i].pPattern;
2437  const ScPatternAttr* pNewPattern;
2438 
2439  if (IsDefaultItem( pOldPattern ))
2440  {
2441  // default: nothing changed
2442 
2443  pNewPattern = &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2444  }
2445  else if ( nStripFlags != ScMF::NONE )
2446  {
2447  ScPatternAttr aTmpPattern( *pOldPattern );
2448  ScMF nNewFlags = ScMF::NONE;
2449  if ( nStripFlags != ScMF::All )
2450  nNewFlags = aTmpPattern.GetItem(ATTR_MERGE_FLAG).GetValue() & ~nStripFlags;
2451 
2452  if ( nNewFlags != ScMF::NONE )
2453  aTmpPattern.GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2454  else
2455  aTmpPattern.GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2456 
2457  if (bSamePool)
2458  pNewPattern = &pDestDocPool->Put(aTmpPattern);
2459  else
2460  pNewPattern = aTmpPattern.PutInPool( &rAttrArray.rDocument, &rDocument );
2461  }
2462  else
2463  {
2464  if (bSamePool)
2465  pNewPattern = &pDestDocPool->Put(*pOldPattern);
2466  else
2467  pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument );
2468  }
2469 
2470  rAttrArray.SetPatternArea(nDestStart,
2471  std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), pNewPattern);
2472  }
2473 
2474  // when pasting from clipboard and skipping filtered rows, the adjusted
2475  // end position can be negative
2476  nDestStart = std::max(static_cast<tools::Long>(nDestStart), static_cast<tools::Long>(mvData[i].nEndRow + nDy + 1));
2477  }
2478 }
2479 
2484 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray& rAttrArray )
2485 {
2486  nStartRow -= nDy; // Source
2487  nEndRow -= nDy;
2488 
2489  SCROW nDestStart = std::max(static_cast<tools::Long>(static_cast<tools::Long>(nStartRow) + nDy), tools::Long(0));
2490  SCROW nDestEnd = std::min(static_cast<tools::Long>(static_cast<tools::Long>(nEndRow) + nDy), tools::Long(rDocument.MaxRow()));
2491 
2492  if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HasAttrFlags::Overlapped ) )
2493  {
2494  CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2495  return;
2496  }
2497 
2498  ScDocumentPool* pSourceDocPool = rDocument.GetPool();
2499  ScDocumentPool* pDestDocPool = rAttrArray.rDocument.GetPool();
2500  bool bSamePool = (pSourceDocPool==pDestDocPool);
2501 
2502  if ( mvData.empty() )
2503  {
2504  const ScPatternAttr* pNewPattern;
2505  if (bSamePool)
2506  pNewPattern = &pDestDocPool->Put(*rDocument.GetDefPattern());
2507  else
2508  pNewPattern = rDocument.GetDefPattern()->PutInPool( &rAttrArray.rDocument, &rDocument );
2509 
2510  rAttrArray.SetPatternAreaSafe(nDestStart, nDestEnd, pNewPattern, false);
2511  return;
2512  }
2513 
2514 
2515  for (SCSIZE i = 0; (i < mvData.size()) && (nDestStart <= nDestEnd); i++)
2516  {
2517  if (mvData[i].nEndRow >= nStartRow)
2518  {
2519  const ScPatternAttr* pOldPattern = mvData[i].pPattern;
2520  const ScPatternAttr* pNewPattern;
2521 
2522  if (bSamePool)
2523  pNewPattern = &pDestDocPool->Put(*pOldPattern);
2524  else
2525  pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument );
2526 
2527  rAttrArray.SetPatternAreaSafe(nDestStart,
2528  std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), pNewPattern, false);
2529  }
2530 
2531  // when pasting from clipboard and skipping filtered rows, the adjusted
2532  // end position can be negative
2533  nDestStart = std::max(static_cast<tools::Long>(nDestStart), static_cast<tools::Long>(mvData[i].nEndRow + nDy + 1));
2534  }
2535 }
2536 
2538  SCROW nRow, const ScStyleSheet* pSearchStyle, bool bUp,
2539  const ScMarkArray* pMarkArray) const
2540 {
2541  bool bFound = false;
2542 
2543  if (pMarkArray)
2544  {
2545  nRow = pMarkArray->GetNextMarked( nRow, bUp );
2546  if (!rDocument.ValidRow(nRow))
2547  return nRow;
2548  }
2549 
2550  if ( mvData.empty() )
2551  {
2552  if (rDocument.GetDefPattern()->GetStyleSheet() == pSearchStyle)
2553  return nRow;
2554 
2555  nRow = bUp ? -1 : rDocument.MaxRow() + 1;
2556  return nRow;
2557  }
2558 
2559  SCSIZE nIndex;
2560  Search(nRow, nIndex);
2561  const ScPatternAttr* pPattern = mvData[nIndex].pPattern;
2562 
2563  while (nIndex < mvData.size() && !bFound)
2564  {
2565  if (pPattern->GetStyleSheet() == pSearchStyle)
2566  {
2567  if (pMarkArray)
2568  {
2569  nRow = pMarkArray->GetNextMarked( nRow, bUp );
2570  SCROW nStart = nIndex ? mvData[nIndex-1].nEndRow+1 : 0;
2571  if (nRow >= nStart && nRow <= mvData[nIndex].nEndRow)
2572  bFound = true;
2573  }
2574  else
2575  bFound = true;
2576  }
2577 
2578  if (!bFound)
2579  {
2580  if (bUp)
2581  {
2582  if (nIndex==0)
2583  {
2584  nIndex = mvData.size();
2585  nRow = -1;
2586  }
2587  else
2588  {
2589  --nIndex;
2590  nRow = mvData[nIndex].nEndRow;
2591  pPattern = mvData[nIndex].pPattern;
2592  }
2593  }
2594  else
2595  {
2596  nRow = mvData[nIndex].nEndRow+1;
2597  ++nIndex;
2598  if (nIndex<mvData.size())
2599  pPattern = mvData[nIndex].pPattern;
2600  }
2601  }
2602  }
2603 
2604  OSL_ENSURE( bFound || !rDocument.ValidRow(nRow), "Internal failure in ScAttrArray::SearchStyle" );
2605 
2606  return nRow;
2607 }
2608 
2610  SCROW& rRow, SCROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
2611  const ScMarkArray* pMarkArray) const
2612 {
2613  SCROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2614  if (rDocument.ValidRow(nStartRow))
2615  {
2616  if ( mvData.empty() )
2617  {
2618  rRow = nStartRow;
2619  if (bUp)
2620  {
2621  rEndRow = 0;
2622  if (pMarkArray)
2623  {
2624  SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
2625  if (nMarkEnd>rEndRow)
2626  rEndRow = nMarkEnd;
2627  }
2628  }
2629  else
2630  {
2631  rEndRow = rDocument.MaxRow();
2632  if (pMarkArray)
2633  {
2634  SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
2635  if (nMarkEnd<rEndRow)
2636  rEndRow = nMarkEnd;
2637  }
2638  }
2639 
2640  return true;
2641  }
2642 
2643  SCSIZE nIndex;
2644  Search(nStartRow,nIndex);
2645 
2646  rRow = nStartRow;
2647  if (bUp)
2648  {
2649  if (nIndex>0)
2650  rEndRow = mvData[nIndex-1].nEndRow + 1;
2651  else
2652  rEndRow = 0;
2653  if (pMarkArray)
2654  {
2655  SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
2656  if (nMarkEnd>rEndRow)
2657  rEndRow = nMarkEnd;
2658  }
2659  }
2660  else
2661  {
2662  rEndRow = mvData[nIndex].nEndRow;
2663  if (pMarkArray)
2664  {
2665  SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
2666  if (nMarkEnd<rEndRow)
2667  rEndRow = nMarkEnd;
2668  }
2669  }
2670 
2671  return true;
2672  }
2673  else
2674  return false;
2675 }
2676 
2677 SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) const
2678 {
2679  if ( mvData.empty() )
2680  return 1;
2681 
2682  SCSIZE nIndex1, nIndex2;
2683 
2684  if( !Search( nStartRow, nIndex1 ) )
2685  return 0;
2686 
2687  if( !Search( nEndRow, nIndex2 ) )
2688  nIndex2 = mvData.size() - 1;
2689 
2690  return nIndex2 - nIndex1 + 1;
2691 }
2692 
2693 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsVisibleEqual(const ScAttrArray &rOther, SCROW nStartRow, SCROW nEndRow) const
Definition: attarray.cxx:2026
void DeleteRange(SCSIZE nStartIndex, SCSIZE nEndIndex)
Definition: attarray.cxx:2326
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
SCCOL GetColMerge() const
Definition: attrib.hxx:68
SvxCellHorJustify
bool TestInsertRow(SCSIZE nSize) const
Definition: attarray.cxx:2211
sal_uInt64 GetKey() const
Definition: patattr.cxx:1405
sal_Int32 nIndex
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
constexpr TypedWhichId< ScPatternAttr > ATTR_PATTERN(156)
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
bool RemoveFlags(SCROW nStartRow, SCROW nEndRow, ScMF nFlags)
Definition: attarray.cxx:1662
HasAttrFlags
Definition: global.hxx:183
constexpr TypedWhichId< SvxBoxItem > ATTR_BORDER(150)
tuple ns
constexpr sal_uInt16 ATTR_PATTERN_START(100)
sal_uInt8 nRight
Definition: attarray.hxx:57
TestDataElements TestData
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:1462
void InsertRow(SCROW nStartRow, SCSIZE nSize)
Definition: attarray.cxx:2229
bool IsMerged(SCROW nRow) const
Definition: attarray.cxx:1445
sal_uInt8 nVert
Definition: attarray.hxx:61
const SfxPoolItem * GetItem(const SwTextAttr &rAttr, sal_uInt16 nWhich)
static void SetLine(const SvxBorderLine *dest, const SvxBorderLine *src)
Definition: attarray.cxx:706
long Long
bool Reserve(SCSIZE nReserve)
Definition: attarray.cxx:423
const editeng::SvxBorderLine * GetVert() const
bool IsOverlapped() const
Definition: attrib.hxx:101
SC_DLLPUBLIC bool ApplyFlagsTab(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, ScMF nFlags)
Definition: document.cxx:5069
SC_DLLPUBLIC bool InitColumnBlockPosition(sc::ColumnBlockPosition &rBlockPos, SCTAB nTab, SCCOL nCol)
Definition: document.cxx:2654
bool HasAttrib(SCROW nRow1, SCROW nRow2, HasAttrFlags nMask) const
Definition: attarray.cxx:1399
const WhichRangesContainer & GetRanges() const
bool Concat(SCSIZE nPos)
Definition: attarray.cxx:154
void InvalidateItem(sal_uInt16 nWhich)
sal_uInt8 nLeft
Definition: attarray.hxx:56
Store position data for column array storage.
sal_Int16 nId
bool HasItemsSet(const sal_uInt16 *pWhich) const
Definition: patattr.cxx:1007
void erase_at(size_t index)
const_iterator find(const Value &x) const
constexpr TypedWhichId< ScLineBreakCell > ATTR_LINEBREAK(139)
void SetUsage(ScStyleSheet::Usage eUse) const
Definition: stlsheet.hxx:52
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
constexpr TypedWhichId< ScProtectionAttr > ATTR_PROTECTION(149)
sal_uInt8 nBottom
Definition: attarray.hxx:59
ScAttrArray(const ScAttrArray &)=delete
void Remove(const SfxPoolItem &)
SC_DLLPUBLIC void ApplyAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem &rAttr)
Definition: document.cxx:4821
const editeng::SvxBorderLine * GetRight() const
void SetPatternAreaSafe(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pWantedPattern, bool bDefault)
Definition: attarray.cxx:1570
void SetDefaultIfNotInit(SCSIZE nNeeded=1)
Definition: attarray.cxx:109
constexpr TypedWhichId< ScMergeAttr > ATTR_MERGE(144)
SCTAB nTab
Definition: attarray.hxx:95
const SfxSetItem & ApplyTo(const SfxSetItem &rSetItem)
void ApplyBlockFrame(const SvxBoxItem &rLineOuter, const SvxBoxInfoItem *pLineInner, SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight)
Definition: attarray.cxx:1234
constexpr TypedWhichId< ScIndentItem > ATTR_INDENT(131)
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6156
void SetAttrEntries(std::vector< ScAttrEntry > &&vNewData)
Definition: attarray.cxx:919
void DeleteRow(SCROW nStartRow, SCSIZE nSize)
Definition: attarray.cxx:2278
constexpr TypedWhichId< ScRotateValueItem > ATTR_ROTATE_VALUE(135)
bool IsStyleSheetUsed(const ScStyleSheet &rStyle) const
Definition: attarray.cxx:1865
bool HasVisibleAttrIn(SCROW nStartRow, SCROW nEndRow) const
Definition: attarray.cxx:2005
SvxShadowLocation GetLocation() const
virtual SvxLineItem * Clone(SfxItemPool *pPool=nullptr) const override
const EditTextObject * mpEditText
Definition: cellvalue.hxx:109
void DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
Definition: attarray.cxx:2348
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:891
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
constexpr TypedWhichId< SvxShadowItem > ATTR_SHADOW(152)
This is a rather odd datastructure.
Definition: markarr.hxx:43
bool setTrue(SCROW nRow1, SCROW nRow2)
int nCount
void reserve(size_type amount)
bool SearchStyleRange(SCROW &rRow, SCROW &rEndRow, const ScStyleSheet *pSearchStyle, bool bUp, const ScMarkArray *pMarkArray=nullptr) const
Definition: attarray.cxx:2609
void CopyAreaSafe(SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray &rAttrArray)
Leave flags summarized with CopyArea.
Definition: attarray.cxx:2484
bool IsVisible() const
Definition: patattr.cxx:1156
void SetRow(SCROW nRowP)
Definition: address.hxx:287
bool TestInsertCol(SCROW nStartRow, SCROW nEndRow) const
Definition: attarray.cxx:2184
ScDocument & rDocument
Definition: attarray.hxx:96
bool Search(SCROW nRow, SCSIZE &nIndex) const
Definition: attarray.cxx:194
size_type size() const
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:72
constexpr TypedWhichId< SvxLineItem > ATTR_BORDER_TLBR(141)
std::vector< ScAttrEntry > mvData
Definition: attarray.hxx:98
bool GetHideCell() const
Definition: attrib.hxx:147
const editeng::SvxBorderLine * GetHori() const
void MergePatternArea(SCROW nStartRow, SCROW nEndRow, ScMergePatternState &rState, bool bDeep) const
Definition: attarray.cxx:973
const editeng::SvxBorderLine * GetTop() const
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:890
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
const editeng::SvxBorderLine * GetLeft() const
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
void ApplyCacheArea(SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache *pCache, ScEditDataArray *pDataArray=nullptr, bool *const pIsChanged=nullptr)
Definition: attarray.cxx:836
int i
sal_Int16 SCCOL
Definition: types.hxx:21
const SCROW SC_VISATTR_STOP
Definition: attarray.cxx:1946
static bool lcl_TestAttr(const SvxBorderLine *pOldLine, const SvxBorderLine *pNewLine, sal_uInt8 &rModified, const SvxBorderLine *&rpNew)
Definition: attarray.cxx:1029
void ClearItems(SCROW nStartRow, SCROW nEndRow, const sal_uInt16 *pWhich)
Definition: attarray.cxx:1699
#define SC_LINE_DONTCARE
Definition: attarray.hxx:48
void CopyArea(SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray &rAttrArray, ScMF nStripFlags=ScMF::NONE) const
Copy between documents (Clipboard)
Definition: attarray.cxx:2412
sal_uInt16 Count() const
autofilter arrow
void ApplyStyleArea(SCROW nStartRow, SCROW nEndRow, const ScStyleSheet &rStyle)
Definition: attarray.cxx:622
const ScStyleSheet * GetStyleSheet() const
Definition: patattr.hxx:128
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxInfoItemLine nLine)
SfxItemSet & GetItemSet()
Definition: patattr.hxx:155
sal_uInt64 mnPatternId
Definition: attarray.hxx:74
SCROW GetMarkEnd(SCROW nRow, bool bUp) const
Definition: markarr.cxx:309
SC_DLLPUBLIC void ApplyPatternAreaTab(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr &rAttr)
Definition: document.cxx:4850
bool HasAttrib_Impl(const ScPatternAttr *pPattern, HasAttrFlags nMask, SCROW nRow1, SCROW nRow2, SCSIZE i) const
Definition: attarray.cxx:1276
SCROW SearchStyle(SCROW nRow, const ScStyleSheet *pSearchStyle, bool bUp, const ScMarkArray *pMarkArray=nullptr) const
May return -1 if not found.
Definition: attarray.cxx:2537
virtual SvxBoxItem * Clone(SfxItemPool *pPool=nullptr) const override
void RemoveCellCharAttribs(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, ScEditDataArray *pDataArray)
Definition: attarray.cxx:393
const_iterator end() const
bool IsAllEqual(const ScAttrArray &rOther, SCROW nStartRow, SCROW nEndRow) const
Definition: attarray.cxx:2106
void SetPatternArea(SCROW nStartRow, SCROW nEndRow, std::unique_ptr< ScPatternAttr > pPattern, bool bPutToPool=false, ScEditDataArray *pDataArray=nullptr)
Definition: attarray.hxx:151
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:805
const SfxPoolItem & GetDefaultItem(sal_uInt16 nWhich) const
static SvxCellOrientation GetCellOrientation(const SfxItemSet &rItemSet, const SfxItemSet *pCondSet)
Definition: patattr.cxx:189
SCSIZE Count() const
Definition: attarray.hxx:226
SfxItemPool * GetPool() const
#define SC_INDENT_STEP
Definition: global.hxx:222
void SetStyleSheet(ScStyleSheet *pNewStyle, bool bClearDirectFormat=true)
Definition: patattr.cxx:1212
bool IsEmpty() const
Definition: attarray.cxx:1899
void MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray &rAttrArray)
Move within a document.
Definition: attarray.cxx:2392
bool IsValid(SvxBoxInfoItemValidFlags nValid) const
const_iterator begin() const
bool IsMerged() const
Definition: attrib.hxx:71
bool GetFirstVisibleAttr(SCROW &rFirstRow) const
Definition: attarray.cxx:1912
const ScPatternAttr * pOld2
Definition: attarray.hxx:71
#define SC_LINE_SET
Definition: attarray.hxx:47
void InvalidateTextWidth(std::u16string_view rStyleName)
Definition: documen8.cxx:295
CellType meType
Definition: cellvalue.hxx:105
void ChangeIndent(SCROW nStartRow, SCROW nEndRow, bool bIncrement)
Definition: attarray.cxx:1729
static void SetLineColor(SvxBorderLine const *dest, Color c)
Definition: attarray.cxx:698
constexpr TypedWhichId< ScMergeFlagAttr > ATTR_MERGE_FLAG(145)
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
sal_Int32 SCROW
Definition: types.hxx:17
const ScPatternAttr * SetPatternAreaImpl(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, bool bPutToPool=false, ScEditDataArray *pDataArray=nullptr, bool bPassingPatternOwnership=false)
Definition: attarray.cxx:450
bool ValidRow(SCROW nRow) const
Definition: document.hxx:898
ScMF
Definition: attrib.hxx:34
void SetStreamValid(SCTAB nTab, bool bSet, bool bIgnoreLock=false)
Definition: document.cxx:928
SfxItemState
#define SC_ATTRARRAY_DELTA
Definition: attarray.hxx:50
double nx
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
#define SAL_WARN_IF(condition, area, stream)
unsigned char sal_uInt8
void MergeBlockFrame(SvxBoxItem *pLineOuter, SvxBoxInfoItem *pLineInner, ScLineFlags &rFlags, SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight) const
Definition: attarray.cxx:1123
ScPatternAttr * PutInPool(ScDocument *pDestDoc, ScDocument *pSrcDoc) const
Definition: patattr.cxx:1083
bool GetProtection() const
Definition: attrib.hxx:143
sal_uInt8 nTop
Definition: attarray.hxx:58
void DeleteArea(SCROW nStartRow, SCROW nEndRow)
Definition: attarray.cxx:2336
virtual std::unique_ptr< EditTextObject > Clone() const =0
static bool CheckWidthInvalidate(bool &bNumFormatChanged, const SfxItemSet &rNewAttrs, const SfxItemSet &rOldAttrs)
Definition: global.cxx:182
const T & Put(std::unique_ptr< T > xItem, sal_uInt16 nWhich=0)
constexpr TypedWhichId< SvxHorJustifyItem > ATTR_HOR_JUSTIFY(129)
Degree100 GetValue() const
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
SC_DLLPUBLIC ScPatternAttr * GetDefPattern() const
Definition: document.cxx:6151
constexpr sal_uInt16 ATTR_PATTERN_END(155)
SCROW GetNextUnprotected(SCROW nRow, bool bUp) const
Including current, may return -1.
Definition: attarray.cxx:1793
static void RemoveCharAttribs(EditTextObject &rEditText, const ScPatternAttr &rAttr)
Definition: editutil.cxx:155
SC_DLLPUBLIC ScStyleSheetPool * GetStyleSheetPool() const
Definition: document.cxx:6161
SC_DLLPUBLIC bool IsLayoutRTL(SCTAB nTab) const
Definition: document.cxx:989
void ApplyLineStyleArea(SCROW nStartRow, SCROW nEndRow, const ::editeng::SvxBorderLine *pLine, bool bColorOnly)
Definition: attarray.cxx:716
bool GetLastVisibleAttr(SCROW &rLastRow, SCROW nLastData) const
Definition: attarray.cxx:1948
void Reset(const ScPatternAttr *pPattern)
Definition: attarray.cxx:121
void FindStyleSheet(const SfxStyleSheetBase *pStyleSheet, ScFlatBoolRowSegments &rUsedRows, bool bReset)
Definition: attarray.cxx:1830
bool IsVisibleEqual(const ScPatternAttr &rOther) const
Definition: patattr.cxx:1193
const ScPatternAttr * pOld1
existing objects, temporary
Definition: attarray.hxx:70
void RemoveCondFormat(SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex)
if nIndex == 0, remove all conditional format data
Definition: attarray.cxx:336
#define SC_LINE_EMPTY
Definition: attarray.hxx:46
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
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1080
void AddItem(SCTAB nTab, SCCOL nCol, SCROW nRow, std::unique_ptr< EditTextObject > pOldData, std::unique_ptr< EditTextObject > pNewData)
bool ApplyFrame(const SvxBoxItem *pLineOuter, const SvxBoxInfoItem *pLineInner, SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom)
Definition: attarray.cxx:1165
void AddCondFormat(SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex)
Definition: attarray.cxx:278
SCCOL nCol
Definition: attarray.hxx:94
SCROW GetRowMerge() const
Definition: attrib.hxx:69
void RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
Definition: attarray.cxx:1515
bool HasAutoFilter() const
Definition: attrib.hxx:103
std::pair< const_iterator, bool > insert(Value &&x)
SC_DLLPUBLIC sal_uInt16 GetColWidth(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4170
bool ApplyFlags(SCROW nStartRow, SCROW nEndRow, ScMF nFlags)
Definition: attarray.cxx:1625
std::optional< SfxItemSet > pItemSet
Definition: attarray.hxx:69
bool IsLoading() const
static void lcl_MergeDeep(SfxItemSet &rMergeSet, const SfxItemSet &rSource)
Definition: attarray.cxx:937
SCROW GetNextMarked(SCROW nRow, bool bUp) const
Including current row, may return -1 if bUp and not found.
Definition: markarr.cxx:286
const editeng::SvxBorderLine * GetBottom() const
constexpr TypedWhichId< SvxLineItem > ATTR_BORDER_BLTR(142)
sal_uInt8 nHori
Definition: attarray.hxx:60
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: attarray.cxx:239
sal_uInt16 nPos
sal_Int16 SCTAB
Definition: types.hxx:22
dp table output
bool IsDefaultItem(const SfxPoolItem *pItem)
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)
SvxShadowLocation