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