1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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 <poolcach.hxx>
32 #include <document.hxx>
33 #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>
48 using ::editeng::SvxBorderLine
;
50 ScAttrArray::ScAttrArray( SCCOL nNewCol
, SCTAB nNewTab
, ScDocument
& rDoc
, ScAttrArray
* pDefaultColAttrArray
) :
55 if ( nCol
== -1 || !pDefaultColAttrArray
|| pDefaultColAttrArray
->mvData
.empty() )
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
)
63 mvData
[nIdx
].nEndRow
= pDefaultColAttrArray
->mvData
[nIdx
].nEndRow
;
64 mvData
[nIdx
].setScPatternAttr(pDefaultColAttrArray
->mvData
[nIdx
].getScPatternAttr());
65 bool bNumFormatChanged
= false;
66 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
67 mvData
[nIdx
].getScPatternAttr()->GetItemSet(),
68 rDocument
.getCellAttributeHelper().getDefaultCellAttribute().GetItemSet() ) )
70 aAdrStart
.SetRow( nIdx
? mvData
[nIdx
-1].nEndRow
+1 : 0 );
71 aAdrEnd
.SetRow( mvData
[nIdx
].nEndRow
);
72 rDocument
.InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
77 ScAttrArray::~ScAttrArray()
79 #if DEBUG_SC_TESTATTRARRAY
84 #if DEBUG_SC_TESTATTRARRAY
85 void ScAttrArray::TestData() const
90 for (nPos
=0; nPos
<nCount
; nPos
++)
93 if (mvData
[nPos
].pPattern
== mvData
[nPos
-1].pPattern
|| mvData
[nPos
].nRow
<= mvData
[nPos
-1].nRow
)
96 if ( nPos
&& mvData
[nPos
-1].nRow
!= rDocument
.MaxRow() )
99 SAL_WARN_IF( nErr
, "sc", nErr
<< " errors in attribute array, column " << nCol
);
103 void ScAttrArray::SetDefaultIfNotInit( SCSIZE nNeeded
)
105 if ( !mvData
.empty() )
108 SCSIZE nNewLimit
= std::max
<SCSIZE
>( SC_ATTRARRAY_DELTA
, nNeeded
);
109 mvData
.reserve( nNewLimit
);
110 mvData
.emplace_back();
111 mvData
[0].nEndRow
= rDocument
.MaxRow();
112 mvData
[0].setScPatternAttr(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute()); // no put
115 void ScAttrArray::Reset(const CellAttributeHolder
& rPattern
)
117 const ScPatternAttr
* pPattern(rPattern
.getScPatternAttr());
118 if (nullptr == pPattern
)
121 ScAddress
aAdrStart( nCol
, 0, nTab
);
122 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
124 for (SCSIZE i
=0; i
<mvData
.size(); i
++)
126 // ensure that attributing changes text width of cell
127 const ScPatternAttr
* pOldPattern(mvData
[i
].getScPatternAttr());
130 bool bNumFormatChanged
;
131 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
132 pPattern
->GetItemSet(), pOldPattern
->GetItemSet() ) )
134 aAdrStart
.SetRow( i
? mvData
[i
-1].nEndRow
+1 : 0 );
135 aAdrEnd
.SetRow( mvData
[i
].nEndRow
);
136 rDocument
.InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
142 rDocument
.SetStreamValid(nTab
, false);
145 mvData
[0].nEndRow
= rDocument
.MaxRow();
146 mvData
[0].setScPatternAttr(pPattern
);
149 bool ScAttrArray::Concat(SCSIZE nPos
)
152 if (nPos
< mvData
.size())
156 if (ScPatternAttr::areSame(mvData
[nPos
- 1].getScPatternAttr(), mvData
[nPos
].getScPatternAttr()))
158 mvData
[nPos
- 1].nEndRow
= mvData
[nPos
].nEndRow
;
159 mvData
.erase(mvData
.begin() + nPos
);
164 if (nPos
+ 1 < mvData
.size())
166 if (ScPatternAttr::areSame(mvData
[nPos
+ 1].getScPatternAttr(), mvData
[nPos
].getScPatternAttr()))
168 mvData
[nPos
].nEndRow
= mvData
[nPos
+ 1].nEndRow
;
169 mvData
.erase(mvData
.begin() + nPos
+ 1);
178 * nCount is the number of runs of different attribute combinations;
179 * no attribute in a column => nCount==1, one attribute somewhere => nCount == 3
180 * (ie. one run with no attribute + one attribute + another run with no attribute)
181 * so a range of identical attributes is only one entry in ScAttrArray.
183 * Iterative implementation of Binary Search
184 * The same implementation was used inside ScMarkArray::Search().
186 * @param oIndexHint, hint for the start of the search, useful when searching twice for successive values
189 bool ScAttrArray::Search( SCROW nRow
, SCSIZE
& nIndex
, std::optional
<SCROW
> oIndexHint
) const
191 /* auto it = std::lower_bound(mvData.begin(), mvData.end(), nRow,
192 [] (const ScAttrEntry &r1, SCROW nRow)
193 { return r1.nEndRow < nRow; } );
194 if (it != mvData.end())
195 nIndex = it - mvData.begin();
196 return it != mvData.end(); */
198 if (mvData
.size() == 1)
204 tools::Long nHi
= static_cast<tools::Long
>(mvData
.size()) - 1;
206 assert((!oIndexHint
|| *oIndexHint
<= nHi
) && "bad index hint");
207 tools::Long nLo
= oIndexHint
? *oIndexHint
: 0;
213 if (mvData
[i
].nEndRow
< nRow
)
215 // If [nRow] greater, ignore left half
218 else if ((i
> 0) && (mvData
[i
- 1].nEndRow
>= nRow
))
220 // If [nRow] is smaller, ignore right half
226 nIndex
=static_cast<SCSIZE
>(i
);
235 const ScPatternAttr
* ScAttrArray::GetPattern( SCROW nRow
) const
237 if ( mvData
.empty() )
239 if ( !rDocument
.ValidRow(nRow
) )
241 return &rDocument
.getCellAttributeHelper().getDefaultCellAttribute();
244 if (Search( nRow
, i
))
245 return mvData
[i
].getScPatternAttr();
250 const ScPatternAttr
* ScAttrArray::GetPatternRange( SCROW
& rStartRow
,
251 SCROW
& rEndRow
, SCROW nRow
) const
253 if ( mvData
.empty() )
255 if ( !rDocument
.ValidRow( nRow
) )
258 rEndRow
= rDocument
.MaxRow();
259 return &rDocument
.getCellAttributeHelper().getDefaultCellAttribute();
262 if ( Search( nRow
, nIndex
) )
265 rStartRow
= mvData
[nIndex
-1].nEndRow
+ 1;
268 rEndRow
= mvData
[nIndex
].nEndRow
;
269 return mvData
[nIndex
].getScPatternAttr();
274 void ScAttrArray::AddCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
276 if(!rDocument
.ValidRow(nStartRow
) || !rDocument
.ValidRow(nEndRow
))
279 if(nEndRow
< nStartRow
)
282 SCROW nTempStartRow
= nStartRow
;
283 SCROW nTempEndRow
= nEndRow
;
287 const ScPatternAttr
* pPattern
= GetPattern(nTempStartRow
);
289 // changed to create pNewPattern only if needed, else use already
290 // existing pPattern. This shows by example how to avoid that special
291 // handling of ScPatternAttr in SC and massive
292 // incarnations/destructions of that Item (which contains an ItemSet)
293 std::unique_ptr
<ScPatternAttr
> pNewPattern
;
296 SCROW nPatternStartRow
;
297 SCROW nPatternEndRow
;
298 GetPatternRange( nPatternStartRow
, nPatternEndRow
, nTempStartRow
);
300 nTempEndRow
= std::min
<SCROW
>( nPatternEndRow
, nEndRow
);
301 if (const ScCondFormatItem
* pItem
= pPattern
->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL
))
303 ScCondFormatIndexes
const & rCondFormatData
= pItem
->GetCondFormatData();
304 if (rCondFormatData
.find(nIndex
) == rCondFormatData
.end())
306 ScCondFormatIndexes aNewCondFormatData
;
307 aNewCondFormatData
.reserve(rCondFormatData
.size()+1);
308 aNewCondFormatData
= rCondFormatData
;
309 aNewCondFormatData
.insert(nIndex
);
310 ScCondFormatItem
aItem( std::move(aNewCondFormatData
) );
311 pNewPattern
.reset( new ScPatternAttr(*pPattern
) );
312 pNewPattern
->GetItemSet().Put( aItem
);
317 ScCondFormatItem
aItem(nIndex
);
318 pNewPattern
.reset( new ScPatternAttr(*pPattern
) );
319 pNewPattern
->GetItemSet().Put( aItem
);
324 pNewPattern
.reset( new ScPatternAttr( rDocument
.getCellAttributeHelper() ) );
325 ScCondFormatItem
aItem(nIndex
);
326 pNewPattern
->GetItemSet().Put( aItem
);
327 nTempEndRow
= nEndRow
;
331 SetPatternArea( nTempStartRow
, nTempEndRow
, CellAttributeHolder(pNewPattern
.release(), true) );
333 SetPatternArea( nTempStartRow
, nTempEndRow
, CellAttributeHolder(pPattern
) );
335 nTempStartRow
= nTempEndRow
+ 1;
337 while(nTempEndRow
< nEndRow
);
341 void ScAttrArray::RemoveCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
343 if(!rDocument
.ValidRow(nStartRow
) || !rDocument
.ValidRow(nEndRow
))
346 if(nEndRow
< nStartRow
)
349 SCROW nTempStartRow
= nStartRow
;
350 SCROW nTempEndRow
= nEndRow
;
354 const ScPatternAttr
* pPattern
= GetPattern(nTempStartRow
);
358 SCROW nPatternStartRow
;
359 SCROW nPatternEndRow
;
360 GetPatternRange( nPatternStartRow
, nPatternEndRow
, nTempStartRow
);
362 nTempEndRow
= std::min
<SCROW
>( nPatternEndRow
, nEndRow
);
363 if (const ScCondFormatItem
* pItem
= pPattern
->GetItemSet().GetItemIfSet( ATTR_CONDITIONAL
))
367 ScCondFormatItem aItem
;
368 ScPatternAttr
* pTemp(new ScPatternAttr(*pPattern
));
369 pTemp
->GetItemSet().Put( aItem
);
370 SetPatternArea( nTempStartRow
, nTempEndRow
, CellAttributeHolder(pTemp
, true) );
374 ScCondFormatIndexes
const & rCondFormatData
= pItem
->GetCondFormatData();
375 auto itr
= rCondFormatData
.find(nIndex
);
376 if(itr
!= rCondFormatData
.end())
378 ScCondFormatIndexes
aNewCondFormatData(rCondFormatData
);
379 aNewCondFormatData
.erase_at(std::distance(rCondFormatData
.begin(), itr
));
380 ScCondFormatItem
aItem( std::move(aNewCondFormatData
) );
381 ScPatternAttr
* pTemp(new ScPatternAttr(*pPattern
));
382 pTemp
->GetItemSet().Put( aItem
);
383 SetPatternArea( nTempStartRow
, nTempEndRow
, CellAttributeHolder(pTemp
, true) );
393 nTempStartRow
= nTempEndRow
+ 1;
395 while(nTempEndRow
< nEndRow
);
399 void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow
, SCROW nEndRow
,
400 const ScPatternAttr
* pPattern
, ScEditDataArray
* pDataArray
)
402 assert( nCol
!= -1 );
403 // cache mdds position, this doesn't modify the mdds container, just EditTextObject's
404 sc::ColumnBlockPosition blockPos
;
405 rDocument
.InitColumnBlockPosition( blockPos
, nTab
, nCol
);
406 nEndRow
= rDocument
.GetLastDataRow(nTab
, nCol
, nCol
, nEndRow
);
407 for (SCROW nRow
= nStartRow
; nRow
<= nEndRow
; ++nRow
)
409 ScAddress
aPos(nCol
, nRow
, nTab
);
410 ScRefCellValue
aCell(rDocument
, aPos
, blockPos
);
411 if (aCell
.getType() != CELLTYPE_EDIT
|| !aCell
.getEditText())
414 std::unique_ptr
<EditTextObject
> pOldData
;
416 pOldData
= aCell
.getEditText()->Clone();
418 // Direct modification of cell content - something to watch out for if
419 // we decide to share edit text instances in the future.
420 ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject
&>(*aCell
.getEditText()), *pPattern
);
424 std::unique_ptr
<EditTextObject
> pNewData
= aCell
.getEditText()->Clone();
425 pDataArray
->AddItem(nTab
, nCol
, nRow
, std::move(pOldData
), std::move(pNewData
));
430 bool ScAttrArray::Reserve( SCSIZE nReserve
)
432 if ( mvData
.empty() && nReserve
)
435 mvData
.reserve(nReserve
);
436 mvData
.emplace_back();
437 mvData
[0].nEndRow
= rDocument
.MaxRow();
438 mvData
[0].setScPatternAttr(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute()); // no put
440 } catch (std::bad_alloc
const &) {
444 else if ( mvData
.capacity() < nReserve
)
447 mvData
.reserve(nReserve
);
449 } catch (std::bad_alloc
const &) {
457 const ScPatternAttr
* ScAttrArray::SetPatternAreaImpl(
458 SCROW nStartRow
, SCROW nEndRow
, const CellAttributeHolder
& rPattern
, ScEditDataArray
* pDataArray
)
460 const ScPatternAttr
* pPattern(rPattern
.getScPatternAttr());
461 if (nullptr == pPattern
)
464 if (rDocument
.ValidRow(nStartRow
) && rDocument
.ValidRow(nEndRow
))
466 if ((nStartRow
== 0) && (nEndRow
== rDocument
.MaxRow()))
470 SCSIZE nNeeded
= mvData
.size() + 2;
471 SetDefaultIfNotInit( nNeeded
);
473 ScAddress
aAdrStart( nCol
, 0, nTab
);
474 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
476 SCSIZE ni
= 0; // number of entries in beginning
477 SCSIZE nx
= 0; // track position
478 SCROW ns
= 0; // start row of track position
483 Search( nStartRow
, nIndex
);
489 ns
= mvData
[ni
-1].nEndRow
+1;
493 // ensure that attributing changes text width of cell
494 // otherwise, conditional formats need to be reset or deleted
495 bool bIsLoading
= !rDocument
.GetDocumentShell() || rDocument
.GetDocumentShell()->IsLoading();
496 while ( ns
<= nEndRow
)
498 if ( nCol
!= -1 && !bIsLoading
)
500 const SfxItemSet
& rNewSet
= pPattern
->GetItemSet();
501 const SfxItemSet
& rOldSet
= mvData
[nx
].getScPatternAttr()->GetItemSet();
502 bool bNumFormatChanged
;
503 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
506 aAdrStart
.SetRow( std::max(nStartRow
,ns
) );
507 aAdrEnd
.SetRow( std::min(nEndRow
,mvData
[nx
].nEndRow
) );
508 rDocument
.InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
511 ns
= mvData
[nx
].nEndRow
+ 1;
515 // continue modifying data array
517 SCSIZE nInsert
; // insert position (MAXROWCOUNT := no insert)
518 bool bCombined
= false;
522 nInsert
= rDocument
.MaxRow() + 1;
523 if ( !ScPatternAttr::areSame(mvData
[ni
].getScPatternAttr(), pPattern
) )
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
)
533 else if (mvData
[ni
- 1].nEndRow
== nStartRow
- 1)
536 if ( ni
> 0 && ScPatternAttr::areSame(mvData
[ni
-1].getScPatternAttr(), pPattern
) )
538 mvData
[ni
-1].nEndRow
= nEndRow
;
539 nInsert
= rDocument
.MaxRow() + 1;
546 SCSIZE nj
= ni
; // stop position of range to replace
547 while ( nj
< mvData
.size() && mvData
[nj
].nEndRow
<= nEndRow
)
551 if ( nj
< mvData
.size() && ScPatternAttr::areSame(mvData
[nj
].getScPatternAttr(), pPattern
) )
555 if ( ScPatternAttr::areSame(mvData
[ni
-1].getScPatternAttr(), pPattern
) )
556 { // adjacent entries
557 mvData
[ni
-1].nEndRow
= mvData
[nj
].nEndRow
;
560 else if ( ni
== nInsert
)
561 mvData
[ni
-1].nEndRow
= nStartRow
- 1; // shrink
563 nInsert
= rDocument
.MaxRow() + 1;
566 else if ( ni
> 0 && ni
== nInsert
)
567 mvData
[ni
-1].nEndRow
= nStartRow
- 1; // shrink
570 { // remove middle entries
572 { // replace one entry
573 mvData
[ni
].nEndRow
= nEndRow
;
574 mvData
[ni
].setScPatternAttr(pPattern
);
576 nInsert
= rDocument
.MaxRow() + 1;
580 mvData
.erase( mvData
.begin() + ni
, mvData
.begin() + nj
);
584 if ( nInsert
< sal::static_int_cast
<SCSIZE
>(rDocument
.MaxRow() + 1) )
585 { // insert or append new entry
586 if ( nInsert
<= mvData
.size() )
589 mvData
.emplace(mvData
.begin() + nInsert
);
592 mvData
.insert(mvData
.begin() + nInsert
, 2, ScAttrEntry());
593 mvData
[nInsert
+1] = mvData
[nInsert
-1];
597 mvData
[nInsert
-1].nEndRow
= nStartRow
- 1;
598 mvData
[nInsert
].nEndRow
= nEndRow
;
599 mvData
[nInsert
].setScPatternAttr(pPattern
);
601 // Remove character attributes from these cells if the pattern
602 // is applied during normal session.
603 if (pDataArray
&& nCol
!= -1)
604 RemoveCellCharAttribs(nStartRow
, nEndRow
, pPattern
, pDataArray
);
607 rDocument
.SetStreamValid(nTab
, false);
611 #if DEBUG_SC_TESTATTRARRAY
617 void ScAttrArray::ApplyStyleArea( SCROW nStartRow
, SCROW nEndRow
, const ScStyleSheet
& rStyle
)
619 if (!(rDocument
.ValidRow(nStartRow
) && rDocument
.ValidRow(nEndRow
)))
622 SetDefaultIfNotInit();
625 if (!Search( nStartRow
, nPos
))
627 OSL_FAIL("Search Failure");
631 ScAddress
aAdrStart( nCol
, 0, nTab
);
632 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
636 const ScPatternAttr
* pOldPattern
= mvData
[nPos
].getScPatternAttr();
637 std::unique_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr(*pOldPattern
));
638 pNewPattern
->SetStyleSheet(const_cast<ScStyleSheet
*>(&rStyle
));
640 SCROW nY2
= mvData
[nPos
].nEndRow
;
641 nStart
= mvData
[nPos
].nEndRow
+ 1;
643 if ( *pNewPattern
== *pOldPattern
)
645 // keep the original pattern (might be default)
646 // pNewPattern is deleted below
649 else if ( nY1
< nStartRow
|| nY2
> nEndRow
)
651 if (nY1
< nStartRow
) nY1
=nStartRow
;
652 if (nY2
> nEndRow
) nY2
=nEndRow
;
653 SetPatternArea( nY1
, nY2
, CellAttributeHolder(pNewPattern
.release(), true) );
654 Search( nStart
, nPos
);
660 // ensure attributing changes text width of cell; otherwise
661 // there aren't (yet) template format changes
662 const SfxItemSet
& rNewSet
= pNewPattern
->GetItemSet();
663 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
665 bool bNumFormatChanged
;
666 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
669 aAdrStart
.SetRow( nPos
? mvData
[nPos
-1].nEndRow
+1 : 0 );
670 aAdrEnd
.SetRow( mvData
[nPos
].nEndRow
);
671 rDocument
.InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
675 mvData
[nPos
].setScPatternAttr(pNewPattern
.release(), true);
677 Search(nStart
, nPos
);
682 while ((nStart
<= nEndRow
) && (nPos
< mvData
.size()));
684 rDocument
.SetStreamValid(nTab
, false);
686 #if DEBUG_SC_TESTATTRARRAY
691 // const cast, otherwise it will be too inefficient/complicated
692 static void SetLineColor(SvxBorderLine
const * dest
, Color c
)
696 const_cast<SvxBorderLine
*>(dest
)->SetColor(c
);
700 static void SetLine(const SvxBorderLine
* dest
, const SvxBorderLine
* src
)
704 SvxBorderLine
* pCast
= const_cast<SvxBorderLine
*>(dest
);
705 pCast
->SetBorderLineStyle( src
->GetBorderLineStyle() );
706 pCast
->SetWidth( src
->GetWidth() );
710 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow
, SCROW nEndRow
,
711 const SvxBorderLine
* pLine
, bool bColorOnly
)
713 if ( bColorOnly
&& !pLine
)
716 if (!(rDocument
.ValidRow(nStartRow
) && rDocument
.ValidRow(nEndRow
)))
721 SetDefaultIfNotInit();
722 if (!Search( nStartRow
, nPos
))
724 OSL_FAIL("Search failure");
730 const ScPatternAttr
* pOldPattern
= mvData
[nPos
].getScPatternAttr();
731 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
732 const SvxBoxItem
* pBoxItem
= rOldSet
.GetItemIfSet( ATTR_BORDER
);
733 const SvxLineItem
* pTLBRItem
= rOldSet
.GetItemIfSet( ATTR_BORDER_TLBR
);
734 const SvxLineItem
* pBLTRItem
= rOldSet
.GetItemIfSet( ATTR_BORDER_BLTR
);
736 if ( pBoxItem
|| pTLBRItem
|| pBLTRItem
)
738 std::unique_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr(*pOldPattern
));
739 SfxItemSet
& rNewSet
= pNewPattern
->GetItemSet();
741 SCROW nY2
= mvData
[nPos
].nEndRow
;
743 std::unique_ptr
<SvxBoxItem
> pNewBoxItem( pBoxItem
? pBoxItem
->Clone() : nullptr);
744 std::unique_ptr
<SvxLineItem
> pNewTLBRItem( pTLBRItem
? pTLBRItem
->Clone() : nullptr);
745 std::unique_ptr
<SvxLineItem
> pNewBLTRItem(pBLTRItem
? pBLTRItem
->Clone() : nullptr);
747 // fetch line and update attributes with parameters
753 if ( pNewBoxItem
->GetTop() ) pNewBoxItem
->SetLine( nullptr, SvxBoxItemLine::TOP
);
754 if ( pNewBoxItem
->GetBottom() ) pNewBoxItem
->SetLine( nullptr, SvxBoxItemLine::BOTTOM
);
755 if ( pNewBoxItem
->GetLeft() ) pNewBoxItem
->SetLine( nullptr, SvxBoxItemLine::LEFT
);
756 if ( pNewBoxItem
->GetRight() ) pNewBoxItem
->SetLine( nullptr, SvxBoxItemLine::RIGHT
);
758 if( pNewTLBRItem
&& pNewTLBRItem
->GetLine() )
759 pNewTLBRItem
->SetLine( nullptr );
760 if( pNewBLTRItem
&& pNewBLTRItem
->GetLine() )
761 pNewBLTRItem
->SetLine( nullptr );
767 Color
aColor( pLine
->GetColor() );
770 SetLineColor( pNewBoxItem
->GetTop(), aColor
);
771 SetLineColor( pNewBoxItem
->GetBottom(), aColor
);
772 SetLineColor( pNewBoxItem
->GetLeft(), aColor
);
773 SetLineColor( pNewBoxItem
->GetRight(), aColor
);
776 SetLineColor( pNewTLBRItem
->GetLine(), aColor
);
778 SetLineColor( pNewBLTRItem
->GetLine(), aColor
);
784 SetLine( pNewBoxItem
->GetTop(), pLine
);
785 SetLine( pNewBoxItem
->GetBottom(), pLine
);
786 SetLine( pNewBoxItem
->GetLeft(), pLine
);
787 SetLine( pNewBoxItem
->GetRight(), pLine
);
790 SetLine( pNewTLBRItem
->GetLine(), pLine
);
792 SetLine( pNewBLTRItem
->GetLine(), pLine
);
795 if( pNewBoxItem
) rNewSet
.Put( std::move(pNewBoxItem
) );
796 if( pNewTLBRItem
) rNewSet
.Put( std::move(pNewTLBRItem
) );
797 if( pNewBLTRItem
) rNewSet
.Put( std::move(pNewBLTRItem
) );
799 nStart
= mvData
[nPos
].nEndRow
+ 1;
801 if ( nY1
< nStartRow
|| nY2
> nEndRow
)
803 if (nY1
< nStartRow
) nY1
=nStartRow
;
804 if (nY2
> nEndRow
) nY2
=nEndRow
;
805 SetPatternArea( nY1
, nY2
, CellAttributeHolder(pNewPattern
.release(), true) );
806 Search( nStart
, nPos
);
810 // remove from pool ?
811 mvData
[nPos
].setScPatternAttr(pNewPattern
.release(), true);
814 Search(nStart
, nPos
);
821 nStart
= mvData
[nPos
].nEndRow
+ 1;
825 while ((nStart
<= nEndRow
) && (nPos
< mvData
.size()));
828 void ScAttrArray::ApplyCacheArea( SCROW nStartRow
, SCROW nEndRow
, ScItemPoolCache
& rCache
, ScEditDataArray
* pDataArray
, bool* const pIsChanged
)
830 #if DEBUG_SC_TESTATTRARRAY
834 if (!(rDocument
.ValidRow(nStartRow
) && rDocument
.ValidRow(nEndRow
)))
839 SetDefaultIfNotInit();
840 if (!Search( nStartRow
, nPos
))
842 OSL_FAIL("Search Failure");
846 ScAddress
aAdrStart( nCol
, 0, nTab
);
847 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
851 const CellAttributeHolder
& rOldPattern(mvData
[nPos
].getCellAttributeHolder());
852 const CellAttributeHolder
& rNewPattern(rCache
.ApplyTo( rOldPattern
));
854 if (!CellAttributeHolder::areSame(&rNewPattern
, &rOldPattern
))
857 SCROW nY2
= mvData
[nPos
].nEndRow
;
858 nStart
= mvData
[nPos
].nEndRow
+ 1;
863 if ( nY1
< nStartRow
|| nY2
> nEndRow
)
865 if (nY1
< nStartRow
) nY1
=nStartRow
;
866 if (nY2
> nEndRow
) nY2
=nEndRow
;
867 SetPatternArea( nY1
, nY2
, rNewPattern
, pDataArray
);
868 Search( nStart
, nPos
);
874 // ensure attributing changes text-width of cell
876 const SfxItemSet
& rNewSet
= rNewPattern
.getScPatternAttr()->GetItemSet();
877 const SfxItemSet
& rOldSet
= rOldPattern
.getScPatternAttr()->GetItemSet();
879 bool bNumFormatChanged
;
880 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
883 aAdrStart
.SetRow( nPos
? mvData
[nPos
-1].nEndRow
+1 : 0 );
884 aAdrEnd
.SetRow( mvData
[nPos
].nEndRow
);
885 rDocument
.InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
889 mvData
[nPos
].setCellAttributeHolder(rNewPattern
);
891 Search(nStart
, nPos
);
898 nStart
= mvData
[nPos
].nEndRow
+ 1;
902 while (nStart
<= nEndRow
);
904 rDocument
.SetStreamValid(nTab
, false);
906 #if DEBUG_SC_TESTATTRARRAY
911 void ScAttrArray::SetAttrEntries(std::vector
<ScAttrEntry
> && vNewData
)
913 mvData
= std::move(vNewData
);
916 SCROW lastEndRow
= -1;
917 for(const auto& entry
: mvData
)
918 { // Verify that the data is not corrupted.
919 assert(entry
.nEndRow
> lastEndRow
);
920 lastEndRow
= entry
.nEndRow
;
925 static void lcl_MergeDeep( SfxItemSet
& rMergeSet
, const SfxItemSet
& rSource
)
927 const SfxPoolItem
* pNewItem
;
928 const SfxPoolItem
* pOldItem
;
929 for (sal_uInt16 nId
=ATTR_PATTERN_START
; nId
<=ATTR_PATTERN_END
; nId
++)
931 // pMergeSet has no parent
932 SfxItemState eOldState
= rMergeSet
.GetItemState( nId
, false, &pOldItem
);
934 if ( eOldState
== SfxItemState::DEFAULT
)
936 SfxItemState eNewState
= rSource
.GetItemState( nId
, true, &pNewItem
);
937 if ( eNewState
== SfxItemState::SET
)
939 if ( *pNewItem
!= rMergeSet
.GetPool()->GetUserOrPoolDefaultItem(nId
) )
940 rMergeSet
.InvalidateItem( nId
);
943 else if ( eOldState
== SfxItemState::SET
) // Item set
945 SfxItemState eNewState
= rSource
.GetItemState( nId
, true, &pNewItem
);
946 if ( eNewState
== SfxItemState::SET
)
948 if ( !SfxPoolItem::areSame(pNewItem
, pOldItem
) ) // Both pulled
949 rMergeSet
.InvalidateItem( nId
);
953 if ( *pOldItem
!= rSource
.GetPool()->GetUserOrPoolDefaultItem(nId
) )
954 rMergeSet
.InvalidateItem( nId
);
957 // Dontcare remains Dontcare
961 void ScAttrArray::MergePatternArea( SCROW nStartRow
, SCROW nEndRow
,
962 ScMergePatternState
& rState
, bool bDeep
) const
964 if (!(rDocument
.ValidRow(nStartRow
) && rDocument
.ValidRow(nEndRow
)))
969 if ( !mvData
.empty() && !Search( nStartRow
, nPos
) )
971 OSL_FAIL("Search failure");
977 // similar patterns must not be repeated
978 const ScPatternAttr
* pPattern(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute());
979 if ( !mvData
.empty() )
980 pPattern
= mvData
[nPos
].getScPatternAttr();
982 if ( !ScPatternAttr::areSame(pPattern
, rState
.aOld1
.getScPatternAttr())
983 && !ScPatternAttr::areSame(pPattern
, rState
.aOld2
.getScPatternAttr()) )
985 const SfxItemSet
& rThisSet
= pPattern
->GetItemSet();
988 rState
.mbValidPatternId
= false;
990 lcl_MergeDeep( *rState
.pItemSet
, rThisSet
);
992 rState
.pItemSet
->MergeValues( rThisSet
);
996 // first pattern - copied from parent
997 rState
.pItemSet
.emplace( *rThisSet
.GetPool(), rThisSet
.GetRanges() );
998 rState
.pItemSet
->Set( rThisSet
, bDeep
);
999 rState
.mnPatternId
= pPattern
->GetPAKey();
1002 rState
.aOld2
= rState
.aOld1
;
1003 rState
.aOld1
= pPattern
;
1006 if ( !mvData
.empty() )
1007 nStart
= mvData
[nPos
].nEndRow
+ 1;
1009 nStart
= rDocument
.MaxRow() + 1;
1012 while (nStart
<= nEndRow
);
1017 static bool lcl_TestAttr( const SvxBorderLine
* pOldLine
, const SvxBorderLine
* pNewLine
,
1018 sal_uInt8
& rModified
, const SvxBorderLine
*& rpNew
)
1020 if (rModified
== SC_LINE_DONTCARE
)
1021 return false; // don't go again
1023 if (rModified
== SC_LINE_EMPTY
)
1025 rModified
= SC_LINE_SET
;
1027 return true; // initial value
1030 if (pOldLine
== pNewLine
)
1036 if (pOldLine
&& pNewLine
)
1037 if (*pOldLine
== *pNewLine
)
1043 rModified
= SC_LINE_DONTCARE
;
1045 return true; // another line -> don't care
1048 static void lcl_MergeToFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
1049 ScLineFlags
& rFlags
, const ScPatternAttr
* pPattern
,
1050 bool bLeft
, SCCOL nDistRight
, bool bTop
, SCROW nDistBottom
)
1052 // right/bottom border set when connected together
1053 const ScMergeAttr
& rMerge
= pPattern
->GetItem(ATTR_MERGE
);
1054 if ( rMerge
.GetColMerge() == nDistRight
+ 1 )
1056 if ( rMerge
.GetRowMerge() == nDistBottom
+ 1 )
1059 const SvxBoxItem
* pCellFrame
= &pPattern
->GetItem( ATTR_BORDER
);
1060 const SvxBorderLine
* pLeftAttr
= pCellFrame
->GetLeft();
1061 const SvxBorderLine
* pRightAttr
= pCellFrame
->GetRight();
1062 const SvxBorderLine
* pTopAttr
= pCellFrame
->GetTop();
1063 const SvxBorderLine
* pBottomAttr
= pCellFrame
->GetBottom();
1064 const SvxBorderLine
* pNew
;
1068 if (lcl_TestAttr( pLineOuter
->GetTop(), pTopAttr
, rFlags
.nTop
, pNew
))
1069 pLineOuter
->SetLine( pNew
, SvxBoxItemLine::TOP
);
1073 if (lcl_TestAttr( pLineInner
->GetHori(), pTopAttr
, rFlags
.nHori
, pNew
))
1074 pLineInner
->SetLine( pNew
, SvxBoxInfoItemLine::HORI
);
1077 if (nDistBottom
== 0)
1079 if (lcl_TestAttr( pLineOuter
->GetBottom(), pBottomAttr
, rFlags
.nBottom
, pNew
))
1080 pLineOuter
->SetLine( pNew
, SvxBoxItemLine::BOTTOM
);
1084 if (lcl_TestAttr( pLineInner
->GetHori(), pBottomAttr
, rFlags
.nHori
, pNew
))
1085 pLineInner
->SetLine( pNew
, SvxBoxInfoItemLine::HORI
);
1090 if (lcl_TestAttr( pLineOuter
->GetLeft(), pLeftAttr
, rFlags
.nLeft
, pNew
))
1091 pLineOuter
->SetLine( pNew
, SvxBoxItemLine::LEFT
);
1095 if (lcl_TestAttr( pLineInner
->GetVert(), pLeftAttr
, rFlags
.nVert
, pNew
))
1096 pLineInner
->SetLine( pNew
, SvxBoxInfoItemLine::VERT
);
1099 if (nDistRight
== 0)
1101 if (lcl_TestAttr( pLineOuter
->GetRight(), pRightAttr
, rFlags
.nRight
, pNew
))
1102 pLineOuter
->SetLine( pNew
, SvxBoxItemLine::RIGHT
);
1106 if (lcl_TestAttr( pLineInner
->GetVert(), pRightAttr
, rFlags
.nVert
, pNew
))
1107 pLineInner
->SetLine( pNew
, SvxBoxInfoItemLine::VERT
);
1111 void ScAttrArray::MergeBlockFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
1112 ScLineFlags
& rFlags
,
1113 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
) const
1115 const ScPatternAttr
* pPattern
;
1117 if (nStartRow
== nEndRow
)
1119 pPattern
= GetPattern( nStartRow
);
1120 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, true, 0 );
1122 else if ( !mvData
.empty() ) // non-default pattern
1124 pPattern
= GetPattern( nStartRow
);
1125 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, true,
1126 nEndRow
-nStartRow
);
1130 Search( nStartRow
+1, nStartIndex
);
1131 Search( nEndRow
-1, nEndIndex
);
1132 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
; i
++)
1134 pPattern
= mvData
[i
].getScPatternAttr();
1135 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, false,
1136 nEndRow
- std::min( mvData
[i
].nEndRow
, static_cast<SCROW
>(nEndRow
-1) ) );
1137 // nDistBottom here always > 0
1140 pPattern
= GetPattern( nEndRow
);
1141 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, false, 0 );
1145 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, &rDocument
.getCellAttributeHelper().getDefaultCellAttribute(), bLeft
, nDistRight
, true, 0 );
1151 // ApplyFrame - on an entry into the array
1153 bool ScAttrArray::ApplyFrame( const SvxBoxItem
& rBoxItem
,
1154 const SvxBoxInfoItem
* pBoxInfoItem
,
1155 SCROW nStartRow
, SCROW nEndRow
,
1156 bool bLeft
, SCCOL nDistRight
, bool bTop
, SCROW nDistBottom
)
1158 OSL_ENSURE( pBoxInfoItem
, "Missing line attributes!" );
1160 const ScPatternAttr
* pPattern
= GetPattern( nStartRow
);
1161 const SvxBoxItem
* pOldFrame
= &pPattern
->GetItem( ATTR_BORDER
);
1163 // right/bottom border set when connected together
1164 const ScMergeAttr
& rMerge
= pPattern
->GetItem(ATTR_MERGE
);
1165 if ( rMerge
.GetColMerge() == nDistRight
+ 1 )
1167 if ( rMerge
.GetRowMerge() == nDistBottom
+ 1 )
1170 SvxBoxItem
aNewFrame( *pOldFrame
);
1171 bool bRTL
=rDocument
.IsLayoutRTL(nTab
);
1172 // fdo#37464 check if the sheet are RTL then replace right <=> left
1175 if( bLeft
&& nDistRight
==0)
1177 if ( pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::LEFT
) )
1178 aNewFrame
.SetLine( rBoxItem
.GetLeft(), SvxBoxItemLine::RIGHT
);
1179 if ( pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::RIGHT
) )
1180 aNewFrame
.SetLine( rBoxItem
.GetRight(), SvxBoxItemLine::LEFT
);
1184 if ( (nDistRight
==0) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::LEFT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
1185 aNewFrame
.SetLine( (nDistRight
==0) ? rBoxItem
.GetLeft() : pBoxInfoItem
->GetVert(),
1186 SvxBoxItemLine::RIGHT
);
1187 if ( bLeft
? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::RIGHT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
1188 aNewFrame
.SetLine( bLeft
? rBoxItem
.GetRight() : pBoxInfoItem
->GetVert(),
1189 SvxBoxItemLine::LEFT
);
1194 if ( bLeft
? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::LEFT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
1195 aNewFrame
.SetLine( bLeft
? rBoxItem
.GetLeft() : pBoxInfoItem
->GetVert(),
1196 SvxBoxItemLine::LEFT
);
1197 if ( (nDistRight
==0) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::RIGHT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
1198 aNewFrame
.SetLine( (nDistRight
==0) ? rBoxItem
.GetRight() : pBoxInfoItem
->GetVert(),
1199 SvxBoxItemLine::RIGHT
);
1201 if ( bTop
? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::TOP
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::HORI
) )
1202 aNewFrame
.SetLine( bTop
? rBoxItem
.GetTop() : pBoxInfoItem
->GetHori(),
1203 SvxBoxItemLine::TOP
);
1204 if ( (nDistBottom
==0) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::BOTTOM
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::HORI
) )
1205 aNewFrame
.SetLine( (nDistBottom
==0) ? rBoxItem
.GetBottom() : pBoxInfoItem
->GetHori(),
1206 SvxBoxItemLine::BOTTOM
);
1208 if (aNewFrame
== *pOldFrame
)
1215 ScItemPoolCache
aCache( rDocument
.getCellAttributeHelper(), aNewFrame
);
1216 ApplyCacheArea( nStartRow
, nEndRow
, aCache
);
1222 void ScAttrArray::ApplyBlockFrame(const SvxBoxItem
& rLineOuter
, const SvxBoxInfoItem
* pLineInner
,
1223 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
)
1225 SetDefaultIfNotInit();
1226 if (nStartRow
== nEndRow
)
1227 ApplyFrame(rLineOuter
, pLineInner
, nStartRow
, nEndRow
, bLeft
, nDistRight
, true, 0);
1230 ApplyFrame(rLineOuter
, pLineInner
, nStartRow
, nStartRow
, bLeft
, nDistRight
,
1231 true, nEndRow
-nStartRow
);
1233 if ( nEndRow
> nStartRow
+1 ) // inner part available?
1237 Search( nStartRow
+1, nStartIndex
);
1238 Search( nEndRow
-1, nEndIndex
);
1239 SCROW nTmpStart
= nStartRow
+1;
1241 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
;)
1243 nTmpEnd
= std::min( static_cast<SCROW
>(nEndRow
-1), mvData
[i
].nEndRow
);
1244 bool bChanged
= ApplyFrame(rLineOuter
, pLineInner
, nTmpStart
, nTmpEnd
,
1245 bLeft
, nDistRight
, false, nEndRow
- nTmpEnd
);
1246 nTmpStart
= nTmpEnd
+1;
1249 Search(nTmpStart
, i
);
1250 Search(nEndRow
-1, nEndIndex
);
1257 ApplyFrame(rLineOuter
, pLineInner
, nEndRow
, nEndRow
, bLeft
, nDistRight
, false, 0);
1261 bool ScAttrArray::HasAttrib_Impl(const ScPatternAttr
* pPattern
, HasAttrFlags nMask
, SCROW nRow1
, SCROW nRow2
, SCSIZE i
) const
1263 bool bFound
= false;
1264 if ( nMask
& HasAttrFlags::Merged
)
1266 const ScMergeAttr
* pMerge
= &pPattern
->GetItem( ATTR_MERGE
);
1267 if ( pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1 )
1270 if ( nMask
& ( HasAttrFlags::Overlapped
| HasAttrFlags::NotOverlapped
| HasAttrFlags::AutoFilter
) )
1272 const ScMergeFlagAttr
* pMergeFlag
= &pPattern
->GetItem( ATTR_MERGE_FLAG
);
1273 if ( (nMask
& HasAttrFlags::Overlapped
) && pMergeFlag
->IsOverlapped() )
1275 if ( (nMask
& HasAttrFlags::NotOverlapped
) && !pMergeFlag
->IsOverlapped() )
1277 if ( (nMask
& HasAttrFlags::AutoFilter
) && pMergeFlag
->HasAutoFilter() )
1280 if ( nMask
& HasAttrFlags::Lines
)
1282 const SvxBoxItem
* pBox
= &pPattern
->GetItem( ATTR_BORDER
);
1283 if ( pBox
->GetLeft() || pBox
->GetRight() || pBox
->GetTop() || pBox
->GetBottom() )
1286 if ( nMask
& HasAttrFlags::Shadow
)
1288 const SvxShadowItem
* pShadow
= &pPattern
->GetItem( ATTR_SHADOW
);
1289 if ( pShadow
->GetLocation() != SvxShadowLocation::NONE
)
1292 if ( nMask
& HasAttrFlags::Conditional
)
1294 if ( !pPattern
->GetItem( ATTR_CONDITIONAL
).GetCondFormatData().empty())
1297 if ( nMask
& HasAttrFlags::Protected
)
1299 const ScProtectionAttr
* pProtect
= &pPattern
->GetItem( ATTR_PROTECTION
);
1300 bool bFoundTemp
= false;
1301 if ( pProtect
->GetProtection() || pProtect
->GetHideCell() )
1304 bool bContainsCondFormat
= !mvData
.empty() &&
1305 !pPattern
->GetItem( ATTR_CONDITIONAL
).GetCondFormatData().empty();
1306 if ( bContainsCondFormat
&& nCol
!= -1 ) // rDocument.GetCondResult() is valid only for real columns.
1308 SCROW nRowStartCond
= std::max
<SCROW
>( nRow1
, i
? mvData
[i
-1].nEndRow
+ 1: 0 );
1309 SCROW nRowEndCond
= std::min
<SCROW
>( nRow2
, mvData
[i
].nEndRow
);
1310 bool bFoundCond
= false;
1311 for(SCROW nRowCond
= nRowStartCond
; nRowCond
<= nRowEndCond
&& !bFoundCond
; ++nRowCond
)
1313 const SfxItemSet
* pSet
= rDocument
.GetCondResult( nCol
, nRowCond
, nTab
);
1315 const ScProtectionAttr
* pCondProtect
;
1316 if( pSet
&& (pCondProtect
= pSet
->GetItemIfSet( ATTR_PROTECTION
)) )
1318 if( pCondProtect
->GetProtection() || pCondProtect
->GetHideCell() )
1325 // well it is not true that we found one
1326 // but existing one + cell where conditional
1327 // formatting does not remove it
1328 // => we should use the existing protection setting
1329 bFoundCond
= bFoundTemp
;
1332 bFoundTemp
= bFoundCond
;
1338 if ( nMask
& HasAttrFlags::Rotate
)
1340 const ScRotateValueItem
* pRotate
= &pPattern
->GetItem( ATTR_ROTATE_VALUE
);
1341 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1342 // (see ScPatternAttr::GetCellOrientation)
1343 Degree100 nAngle
= pRotate
->GetValue();
1344 if ( nAngle
&& nAngle
!= 9000_deg100
&& nAngle
!= 27000_deg100
)
1347 if ( nMask
& HasAttrFlags::NeedHeight
)
1349 if (pPattern
->GetCellOrientation() != SvxCellOrientation::Standard
)
1351 else if (pPattern
->GetItem( ATTR_LINEBREAK
).GetValue())
1353 else if (pPattern
->GetItem( ATTR_HOR_JUSTIFY
).GetValue() == SvxCellHorJustify::Block
)
1356 else if (!pPattern
->GetItem(ATTR_CONDITIONAL
).GetCondFormatData().empty())
1358 else if (pPattern
->GetItem( ATTR_ROTATE_VALUE
).GetValue())
1361 if ( nMask
& ( HasAttrFlags::ShadowRight
| HasAttrFlags::ShadowDown
) )
1363 const SvxShadowItem
* pShadow
= &pPattern
->GetItem( ATTR_SHADOW
);
1364 SvxShadowLocation eLoc
= pShadow
->GetLocation();
1365 if ( nMask
& HasAttrFlags::ShadowRight
)
1366 if ( eLoc
== SvxShadowLocation::TopRight
|| eLoc
== SvxShadowLocation::BottomRight
)
1368 if ( nMask
& HasAttrFlags::ShadowDown
)
1369 if ( eLoc
== SvxShadowLocation::BottomLeft
|| eLoc
== SvxShadowLocation::BottomRight
)
1372 if ( nMask
& HasAttrFlags::RightOrCenter
)
1374 // called only if the sheet is LTR, so physical=logical alignment can be assumed
1375 SvxCellHorJustify eHorJust
= pPattern
->GetItem( ATTR_HOR_JUSTIFY
).GetValue();
1376 if ( eHorJust
== SvxCellHorJustify::Right
|| eHorJust
== SvxCellHorJustify::Center
)
1383 // Test if field contains specific attribute
1384 bool ScAttrArray::HasAttrib( SCROW nRow1
, SCROW nRow2
, HasAttrFlags nMask
) const
1388 return HasAttrib_Impl(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute(), nMask
, 0, rDocument
.MaxRow(), 0);
1393 Search( nRow1
, nStartIndex
);
1395 Search( nRow2
, nEndIndex
, /*hint*/nStartIndex
);
1397 nEndIndex
= nStartIndex
;
1398 bool bFound
= false;
1400 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
&& !bFound
; i
++)
1402 const ScPatternAttr
* pPattern
= mvData
[i
].getScPatternAttr();
1403 bFound
= HasAttrib_Impl(pPattern
, nMask
, nRow1
, nRow2
, i
);
1409 bool ScAttrArray::HasAttrib( SCROW nRow
, HasAttrFlags nMask
, SCROW
* nStartRow
, SCROW
* nEndRow
) const
1416 *nEndRow
= rDocument
.MaxRow();
1417 return HasAttrib_Impl(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute(), nMask
, 0, rDocument
.MaxRow(), 0);
1421 Search( nRow
, nIndex
);
1423 *nStartRow
= nIndex
> 0 ? mvData
[nIndex
-1].nEndRow
+1 : 0;
1425 *nEndRow
= mvData
[nIndex
].nEndRow
;
1426 const ScPatternAttr
* pPattern
= mvData
[nIndex
].getScPatternAttr();
1427 return HasAttrib_Impl(pPattern
, nMask
, nRow
, nRow
, nIndex
);
1430 bool ScAttrArray::IsMerged( SCROW nRow
) const
1432 if ( !mvData
.empty() )
1435 Search(nRow
, nIndex
);
1436 const ScMergeAttr
& rItem
= mvData
[nIndex
].getScPatternAttr()->GetItem(ATTR_MERGE
);
1438 return rItem
.IsMerged();
1441 return rDocument
.getCellAttributeHelper().getDefaultCellAttribute().GetItem(ATTR_MERGE
).IsMerged();
1445 * Area around any given summaries expand and adapt any MergeFlag (bRefresh)
1447 bool ScAttrArray::ExtendMerge( SCCOL nThisCol
, SCROW nStartRow
, SCROW nEndRow
,
1448 SCCOL
& rPaintCol
, SCROW
& rPaintRow
,
1451 assert( nCol
!= -1 );
1452 SetDefaultIfNotInit();
1453 const ScPatternAttr
* pPattern
;
1454 const ScMergeAttr
* pItem
;
1457 Search( nStartRow
, nStartIndex
);
1458 Search( nEndRow
, nEndIndex
);
1459 bool bFound
= false;
1461 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
; i
++)
1463 pPattern
= mvData
[i
].getScPatternAttr();
1464 pItem
= &pPattern
->GetItem( ATTR_MERGE
);
1465 SCCOL nCountX
= pItem
->GetColMerge();
1466 SCROW nCountY
= pItem
->GetRowMerge();
1467 if (nCountX
>1 || nCountY
>1)
1469 SCROW nThisRow
= (i
>0) ? mvData
[i
-1].nEndRow
+1 : 0;
1470 SCCOL nMergeEndCol
= nThisCol
+ nCountX
- 1;
1471 SCROW nMergeEndRow
= nThisRow
+ nCountY
- 1;
1472 if (nMergeEndCol
> rPaintCol
&& nMergeEndCol
<= rDocument
.MaxCol())
1473 rPaintCol
= nMergeEndCol
;
1474 if (nMergeEndRow
> rPaintRow
&& nMergeEndRow
<= rDocument
.MaxRow())
1475 rPaintRow
= nMergeEndRow
;
1480 if ( nMergeEndCol
> nThisCol
)
1481 rDocument
.ApplyFlagsTab( nThisCol
+1, nThisRow
, nMergeEndCol
, mvData
[i
].nEndRow
,
1483 if ( nMergeEndRow
> nThisRow
)
1484 rDocument
.ApplyFlagsTab( nThisCol
, nThisRow
+1, nThisCol
, nMergeEndRow
,
1486 if ( nMergeEndCol
> nThisCol
&& nMergeEndRow
> nThisRow
)
1487 rDocument
.ApplyFlagsTab( nThisCol
+1, nThisRow
+1, nMergeEndCol
, nMergeEndRow
,
1488 nTab
, ScMF::Hor
| ScMF::Ver
);
1490 Search( nThisRow
, i
); // Data changed
1491 Search( nStartRow
, nStartIndex
);
1492 Search( nEndRow
, nEndIndex
);
1500 void ScAttrArray::RemoveAreaMerge(SCROW nStartRow
, SCROW nEndRow
)
1502 assert( nCol
!= -1 );
1503 SetDefaultIfNotInit();
1504 const ScPatternAttr
* pPattern
;
1505 const ScMergeAttr
* pItem
;
1508 Search( nStartRow
, nIndex
);
1509 SCROW nThisStart
= (nIndex
>0) ? mvData
[nIndex
-1].nEndRow
+1 : 0;
1510 if (nThisStart
< nStartRow
)
1511 nThisStart
= nStartRow
;
1513 while ( nThisStart
<= nEndRow
)
1515 SCROW nThisEnd
= mvData
[nIndex
].nEndRow
;
1516 if (nThisEnd
> nEndRow
)
1519 pPattern
= mvData
[nIndex
].getScPatternAttr();
1520 pItem
= &pPattern
->GetItem( ATTR_MERGE
);
1521 SCCOL nCountX
= pItem
->GetColMerge();
1522 SCROW nCountY
= pItem
->GetRowMerge();
1523 if (nCountX
>1 || nCountY
>1)
1525 const ScMergeAttr
* pAttr
= &rDocument
.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE
);
1526 const ScMergeFlagAttr
* pFlagAttr
= &rDocument
.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE_FLAG
);
1528 OSL_ENSURE( nCountY
==1 || nThisStart
==nThisEnd
, "What's up?" );
1530 SCCOL nThisCol
= nCol
;
1531 SCCOL nMergeEndCol
= nThisCol
+ nCountX
- 1;
1532 SCROW nMergeEndRow
= nThisEnd
+ nCountY
- 1;
1534 // ApplyAttr for areas
1535 for (SCROW nThisRow
= nThisStart
; nThisRow
<= nThisEnd
; nThisRow
++)
1536 rDocument
.ApplyAttr( nThisCol
, nThisRow
, nTab
, *pAttr
);
1538 ScPatternAttr
aNewPattern( rDocument
.getCellAttributeHelper() );
1539 SfxItemSet
* pSet
= &aNewPattern
.GetItemSet();
1540 pSet
->Put( *pFlagAttr
);
1541 rDocument
.ApplyPatternAreaTab( nThisCol
, nThisStart
, nMergeEndCol
, nMergeEndRow
,
1542 nTab
, aNewPattern
);
1544 Search( nThisEnd
, nIndex
); // data changed
1548 if ( nIndex
< mvData
.size() )
1549 nThisStart
= mvData
[nIndex
-1].nEndRow
+1;
1551 nThisStart
= rDocument
.MaxRow()+1; // End
1555 void ScAttrArray::SetPatternAreaSafe(SCROW nStartRow
, SCROW nEndRow
, const CellAttributeHolder
& rWantedPattern
)
1557 SetDefaultIfNotInit();
1558 const ScMergeFlagAttr
* pItem
;
1564 Search( nStartRow
, nIndex
);
1565 nThisRow
= (nIndex
>0) ? mvData
[nIndex
-1].nEndRow
+1 : 0;
1566 while ( nThisRow
<= nEndRow
)
1568 const CellAttributeHolder
& rOldPattern(mvData
[nIndex
].getCellAttributeHolder());
1569 if (!CellAttributeHolder::areSame(&rOldPattern
, &rWantedPattern
)) // FIXME: else-branch?
1571 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1572 nRow
= mvData
[nIndex
].nEndRow
;
1573 SCROW nAttrRow
= std::min( nRow
, nEndRow
);
1574 pItem
= &rOldPattern
.getScPatternAttr()->GetItem( ATTR_MERGE_FLAG
);
1576 if (pItem
->IsOverlapped() || pItem
->HasAutoFilter())
1578 // default-constructing a ScPatternAttr for DeleteArea doesn't work
1579 // because it would have no cell style information.
1580 // Instead, the document's getCellAttributeHelper().getDefaultCellAttribute() is copied. Since it is passed as
1581 // pWantedPattern, no special treatment of default is needed here anymore.
1582 ScPatternAttr
* pNewPattern(new ScPatternAttr(*rWantedPattern
.getScPatternAttr()));
1583 pNewPattern
->GetItemSet().Put( *pItem
);
1584 SetPatternArea( nThisRow
, nAttrRow
, CellAttributeHolder(pNewPattern
, true) );
1588 SetPatternArea(nThisRow
, nAttrRow
, rWantedPattern
);
1591 Search( nThisRow
, nIndex
); // data changed
1595 nThisRow
= mvData
[nIndex
-1].nEndRow
+1;
1599 bool ScAttrArray::ApplyFlags( SCROW nStartRow
, SCROW nEndRow
, ScMF nFlags
)
1601 SetDefaultIfNotInit();
1602 const ScPatternAttr
* pOldPattern
;
1608 bool bChanged
= false;
1610 Search( nStartRow
, nIndex
);
1611 nThisRow
= (nIndex
>0) ? mvData
[nIndex
-1].nEndRow
+1 : 0;
1612 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1614 while ( nThisRow
<= nEndRow
)
1616 pOldPattern
= mvData
[nIndex
].getScPatternAttr();
1617 nOldValue
= pOldPattern
->GetItem( ATTR_MERGE_FLAG
).GetValue();
1618 if ( (nOldValue
| nFlags
) != nOldValue
)
1620 nRow
= mvData
[nIndex
].nEndRow
;
1621 SCROW nAttrRow
= std::min( nRow
, nEndRow
);
1622 ScPatternAttr
* pNewPattern(new ScPatternAttr(*pOldPattern
));
1623 pNewPattern
->GetItemSet().Put( ScMergeFlagAttr( nOldValue
| nFlags
) );
1624 SetPatternArea( nThisRow
, nAttrRow
, CellAttributeHolder(pNewPattern
, true) );
1625 Search( nThisRow
, nIndex
); // data changed
1630 nThisRow
= mvData
[nIndex
-1].nEndRow
+1;
1636 bool ScAttrArray::RemoveFlags( SCROW nStartRow
, SCROW nEndRow
, ScMF nFlags
)
1638 SetDefaultIfNotInit();
1639 const ScPatternAttr
* pOldPattern
;
1645 bool bChanged
= false;
1647 Search( nStartRow
, nIndex
);
1648 nThisRow
= (nIndex
>0) ? mvData
[nIndex
-1].nEndRow
+1 : 0;
1649 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1651 while ( nThisRow
<= nEndRow
)
1653 pOldPattern
= mvData
[nIndex
].getScPatternAttr();
1654 nOldValue
= pOldPattern
->GetItem( ATTR_MERGE_FLAG
).GetValue();
1655 if ( (nOldValue
& ~nFlags
) != nOldValue
)
1657 nRow
= mvData
[nIndex
].nEndRow
;
1658 SCROW nAttrRow
= std::min( nRow
, nEndRow
);
1659 ScPatternAttr
* pNewPattern(new ScPatternAttr(*pOldPattern
));
1660 pNewPattern
->GetItemSet().Put( ScMergeFlagAttr( nOldValue
& ~nFlags
) );
1661 SetPatternArea( nThisRow
, nAttrRow
, CellAttributeHolder(pNewPattern
, true) );
1662 Search( nThisRow
, nIndex
); // data changed
1667 nThisRow
= mvData
[nIndex
-1].nEndRow
+1;
1673 void ScAttrArray::ClearItems( SCROW nStartRow
, SCROW nEndRow
, const sal_uInt16
* pWhich
)
1675 SetDefaultIfNotInit();
1680 Search( nStartRow
, nIndex
);
1681 nThisRow
= (nIndex
>0) ? mvData
[nIndex
-1].nEndRow
+1 : 0;
1682 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1684 while ( nThisRow
<= nEndRow
)
1686 const ScPatternAttr
* pOldPattern
= mvData
[nIndex
].getScPatternAttr();
1687 if ( pOldPattern
->HasItemsSet( pWhich
) )
1689 ScPatternAttr
* pNewPattern(new ScPatternAttr(*pOldPattern
));
1690 pNewPattern
->ClearItems( pWhich
);
1692 nRow
= mvData
[nIndex
].nEndRow
;
1693 SCROW nAttrRow
= std::min( nRow
, nEndRow
);
1694 SetPatternArea( nThisRow
, nAttrRow
, CellAttributeHolder(pNewPattern
, true) );
1695 Search( nThisRow
, nIndex
); // data changed
1699 nThisRow
= mvData
[nIndex
-1].nEndRow
+1;
1703 void ScAttrArray::ChangeIndent( SCROW nStartRow
, SCROW nEndRow
, bool bIncrement
)
1705 SetDefaultIfNotInit();
1707 Search( nStartRow
, nIndex
);
1708 SCROW nThisStart
= (nIndex
>0) ? mvData
[nIndex
-1].nEndRow
+1 : 0;
1709 if (nThisStart
< nStartRow
) nThisStart
= nStartRow
;
1711 while ( nThisStart
<= nEndRow
)
1713 const ScPatternAttr
* pOldPattern
= mvData
[nIndex
].getScPatternAttr();
1714 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
1715 const SvxHorJustifyItem
* pItem
;
1717 bool bNeedJust
= !( pItem
= rOldSet
.GetItemIfSet( ATTR_HOR_JUSTIFY
, false ) )
1718 || (pItem
->GetValue() != SvxCellHorJustify::Left
&&
1719 pItem
->GetValue() != SvxCellHorJustify::Right
);
1720 sal_uInt16 nOldValue
= rOldSet
.Get( ATTR_INDENT
).GetValue();
1721 sal_uInt16 nNewValue
= nOldValue
;
1722 // To keep Increment indent from running outside the cell1659
1723 tools::Long nColWidth
= static_cast<tools::Long
>(
1724 rDocument
.GetColWidth(nCol
== -1 ? rDocument
.MaxCol() : nCol
,nTab
));
1727 if ( nNewValue
< nColWidth
-SC_INDENT_STEP
)
1729 nNewValue
+= SC_INDENT_STEP
;
1730 if ( nNewValue
> nColWidth
-SC_INDENT_STEP
)
1731 nNewValue
= nColWidth
-SC_INDENT_STEP
;
1736 if ( nNewValue
> 0 )
1738 if ( nNewValue
> SC_INDENT_STEP
)
1739 nNewValue
-= SC_INDENT_STEP
;
1745 if ( bNeedJust
|| nNewValue
!= nOldValue
)
1747 SCROW nThisEnd
= mvData
[nIndex
].nEndRow
;
1748 SCROW nAttrRow
= std::min( nThisEnd
, nEndRow
);
1749 ScPatternAttr
* pNewPattern(new ScPatternAttr(*pOldPattern
));
1750 pNewPattern
->GetItemSet().Put( ScIndentItem( nNewValue
) );
1752 pNewPattern
->GetItemSet().Put(
1753 SvxHorJustifyItem( SvxCellHorJustify::Left
, ATTR_HOR_JUSTIFY
) );
1754 SetPatternArea( nThisStart
, nAttrRow
, CellAttributeHolder(pNewPattern
, true) );
1756 nThisStart
= nThisEnd
+ 1;
1757 Search( nThisStart
, nIndex
); // data changed
1761 nThisStart
= mvData
[nIndex
].nEndRow
+ 1;
1767 SCROW
ScAttrArray::GetNextUnprotected( SCROW nRow
, bool bUp
) const
1769 tools::Long nRet
= nRow
;
1770 if (rDocument
.ValidRow(nRow
))
1772 if ( mvData
.empty() )
1777 return rDocument
.MaxRow()+1;
1781 Search(nRow
, nIndex
);
1782 while (mvData
[nIndex
].getScPatternAttr()->GetItem(ATTR_PROTECTION
).GetProtection())
1787 return -1; // not found
1789 nRet
= mvData
[nIndex
].nEndRow
;
1793 nRet
= mvData
[nIndex
].nEndRow
+1;
1795 if (nIndex
>= mvData
.size())
1796 return rDocument
.MaxRow()+1; // not found
1803 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase
* pStyleSheet
, ScFlatBoolRowSegments
& rUsedRows
, bool bReset
)
1805 SetDefaultIfNotInit();
1808 while (nPos
< mvData
.size())
1810 bool bIterateNext
= true;
1812 SCROW nEnd
= mvData
[nPos
].nEndRow
;
1813 if (mvData
[nPos
].getScPatternAttr()->GetStyleSheet() == pStyleSheet
)
1815 rUsedRows
.setTrue(nStart
, nEnd
);
1819 ScPatternAttr
* pNewPattern(new ScPatternAttr(*mvData
[nPos
].getScPatternAttr()));
1820 pNewPattern
->SetStyleSheet( static_cast<ScStyleSheet
*>(
1821 rDocument
.GetStyleSheetPool()->
1822 Find( ScResId(STR_STYLENAME_STANDARD
),
1823 SfxStyleFamily::Para
,
1824 SfxStyleSearchBits::Auto
| SfxStyleSearchBits::ScStandard
) ) );
1825 mvData
[nPos
].setScPatternAttr(pNewPattern
, true);
1829 Search(nStart
, nPos
);
1830 bIterateNext
= false; // because ++ at end otherwise
1841 bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet
& rStyle
) const
1843 if ( mvData
.empty() )
1845 const ScStyleSheet
* pStyle
= rDocument
.getCellAttributeHelper().getDefaultCellAttribute().GetStyleSheet();
1848 pStyle
->SetUsage( ScStyleSheet::Usage::USED
);
1849 if ( pStyle
== &rStyle
)
1855 bool bIsUsed
= false;
1858 while ( nPos
< mvData
.size() )
1860 const ScStyleSheet
* pStyle
= mvData
[nPos
].getScPatternAttr()->GetStyleSheet();
1863 pStyle
->SetUsage( ScStyleSheet::Usage::USED
);
1864 if ( pStyle
== &rStyle
)
1875 bool ScAttrArray::IsEmpty() const
1877 if ( mvData
.empty() )
1880 if (mvData
.size() == 1)
1882 return mvData
[0].getScPatternAttr()->isDefault();
1888 bool ScAttrArray::GetFirstVisibleAttr( SCROW
& rFirstRow
) const
1890 if ( mvData
.empty() )
1893 bool bFound
= false;
1896 // Skip first entry if more than 1 row.
1897 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1899 SCSIZE nVisStart
= 1;
1900 while ( nVisStart
< mvData
.size() && mvData
[nVisStart
].getScPatternAttr()->IsVisibleEqual(*mvData
[nVisStart
-1].getScPatternAttr()) )
1902 if ( nVisStart
>= mvData
.size() || mvData
[nVisStart
-1].nEndRow
> 0 ) // more than 1 row?
1905 while ( nStart
< mvData
.size() && !bFound
)
1907 if ( mvData
[nStart
].getScPatternAttr()->IsVisible() )
1909 rFirstRow
= nStart
? ( mvData
[nStart
-1].nEndRow
+ 1 ) : 0;
1919 // size (rows) of a range of attributes after cell content where the search is stopped
1920 // (more than a default page size, 2*42 because it's as good as any number)
1922 const SCROW SC_VISATTR_STOP
= 84;
1924 bool ScAttrArray::GetLastVisibleAttr( SCROW
& rLastRow
, SCROW nLastData
, bool bSkipEmpty
) const
1926 if ( mvData
.empty() )
1928 rLastRow
= nLastData
;
1932 // #i30830# changed behavior:
1933 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1934 // below the last content cell
1936 if ( nLastData
== rDocument
.MaxRow() )
1938 rLastRow
= rDocument
.MaxRow(); // can't look for attributes below rDocument.MaxRow()
1942 // Quick check: last data row in or immediately preceding a run that is the
1943 // last attribution down to the end, e.g. default style or column style.
1944 SCSIZE nPos
= mvData
.size() - 1;
1945 SCROW nStartRow
= (nPos
? mvData
[nPos
-1].nEndRow
+ 1 : 0);
1946 if (nStartRow
<= nLastData
+ 1)
1948 // Ignore here a few rows if data happens to end within
1949 // SC_VISATTR_STOP rows before rDocument.MaxRow().
1950 rLastRow
= nLastData
;
1953 // tdf#93315: If "Suppress output of empty pages" in Calc Options is not checked, show empty
1954 // (containing only empty data cells) page in the document
1955 bool bFound
= false;
1958 Search( nLastData
, nPos
);
1959 while ( nPos
< mvData
.size() )
1961 // find range of visually equal formats
1962 SCSIZE nEndPos
= nPos
;
1963 while ( nEndPos
< mvData
.size()-1 &&
1964 mvData
[nEndPos
].getScPatternAttr()->IsVisibleEqual(*mvData
[nEndPos
+1].getScPatternAttr()))
1966 SCROW nAttrStartRow
= ( nPos
> 0 ) ? ( mvData
[nPos
-1].nEndRow
+ 1) : 0;
1967 if ( nAttrStartRow
<= nLastData
)
1968 nAttrStartRow
= nLastData
+ 1;
1969 SCROW nAttrSize
= mvData
[nEndPos
].nEndRow
+ 1 - nAttrStartRow
;
1970 if ( nAttrSize
>= SC_VISATTR_STOP
)
1971 break; // while, ignore this range and below
1972 else if ( mvData
[nEndPos
].getScPatternAttr()->IsVisible() )
1974 rLastRow
= mvData
[nEndPos
].nEndRow
;
1982 if ((nPos
> 0 && mvData
[nPos
-1].getScPatternAttr()->IsVisible())
1983 || (nPos
> 1 && !mvData
[nPos
-1].getScPatternAttr()->IsVisibleEqual(*mvData
[nPos
-2].getScPatternAttr())))
1985 rLastRow
= mvData
[nPos
-1].nEndRow
;
1988 rLastRow
= nLastData
;
1993 bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow
, SCROW nEndRow
) const
1995 if ( mvData
.empty() )
1996 return rDocument
.getCellAttributeHelper().getDefaultCellAttribute().IsVisible();
1999 Search( nStartRow
, nIndex
);
2000 SCROW nThisStart
= nStartRow
;
2001 bool bFound
= false;
2002 while ( nIndex
< mvData
.size() && nThisStart
<= nEndRow
&& !bFound
)
2004 if ( mvData
[nIndex
].getScPatternAttr()->IsVisible() )
2007 nThisStart
= mvData
[nIndex
].nEndRow
+ 1;
2014 bool ScAttrArray::IsVisibleEqual( const ScAttrArray
& rOther
,
2015 SCROW nStartRow
, SCROW nEndRow
) const
2017 if ( mvData
.empty() && rOther
.mvData
.empty() )
2019 const ScPatternAttr
* pDefPattern1(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute());
2020 const ScPatternAttr
* pDefPattern2(&rOther
.rDocument
.getCellAttributeHelper().getDefaultCellAttribute());
2021 return ( ScPatternAttr::areSame(pDefPattern1
, pDefPattern2
) || pDefPattern1
->IsVisibleEqual( *pDefPattern2
) );
2025 const ScAttrArray
* pNonDefault
= nullptr;
2026 const ScPatternAttr
* pDefPattern
= nullptr;
2027 bool bDefNonDefCase
= false;
2028 if ( mvData
.empty() && !rOther
.mvData
.empty() )
2030 pNonDefault
= &rOther
;
2031 pDefPattern
= &rDocument
.getCellAttributeHelper().getDefaultCellAttribute();
2032 bDefNonDefCase
= true;
2034 else if ( !mvData
.empty() && rOther
.mvData
.empty() )
2037 pDefPattern
= &rOther
.rDocument
.getCellAttributeHelper().getDefaultCellAttribute();
2038 bDefNonDefCase
= true;
2041 if ( bDefNonDefCase
)
2045 if ( nStartRow
> 0 )
2046 pNonDefault
->Search( nStartRow
, nPos
);
2048 while ( nPos
< pNonDefault
->Count() && bEqual
)
2050 const ScPatternAttr
* pNonDefPattern
= pNonDefault
->mvData
[nPos
].getScPatternAttr();
2051 bEqual
= ScPatternAttr::areSame(pNonDefPattern
, pDefPattern
) || pNonDefPattern
->IsVisibleEqual( *pDefPattern
);
2053 if ( pNonDefault
->mvData
[nPos
].nEndRow
>= nEndRow
) break;
2061 SCSIZE nThisPos
= 0;
2062 SCSIZE nOtherPos
= 0;
2063 if ( nStartRow
> 0 )
2065 Search( nStartRow
, nThisPos
);
2066 rOther
.Search( nStartRow
, nOtherPos
);
2069 while ( nThisPos
<mvData
.size() && nOtherPos
<rOther
.Count() && bEqual
)
2071 SCROW nThisRow
= mvData
[nThisPos
].nEndRow
;
2072 SCROW nOtherRow
= rOther
.mvData
[nOtherPos
].nEndRow
;
2073 const ScPatternAttr
* pThisPattern
= mvData
[nThisPos
].getScPatternAttr();
2074 const ScPatternAttr
* pOtherPattern
= rOther
.mvData
[nOtherPos
].getScPatternAttr();
2075 bEqual
= ( ScPatternAttr::areSame(pThisPattern
, pOtherPattern
) || pThisPattern
->IsVisibleEqual(*pOtherPattern
) );
2077 if ( nThisRow
>= nOtherRow
)
2079 if ( nOtherRow
>= nEndRow
) break;
2082 if ( nThisRow
<= nOtherRow
)
2084 if ( nThisRow
>= nEndRow
) break;
2092 bool ScAttrArray::IsAllEqual( const ScAttrArray
& rOther
, SCROW nStartRow
, SCROW nEndRow
) const
2094 // summarised with IsVisibleEqual
2095 if ( mvData
.empty() && rOther
.mvData
.empty() )
2097 const ScPatternAttr
* pDefPattern1(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute());
2098 const ScPatternAttr
* pDefPattern2(&rOther
.rDocument
.getCellAttributeHelper().getDefaultCellAttribute());
2099 return ScPatternAttr::areSame(pDefPattern1
, pDefPattern2
);
2103 const ScAttrArray
* pNonDefault
= nullptr;
2104 const ScPatternAttr
* pDefPattern
= nullptr;
2105 bool bDefNonDefCase
= false;
2106 if ( mvData
.empty() && !rOther
.mvData
.empty() )
2108 pNonDefault
= &rOther
;
2109 pDefPattern
= &rDocument
.getCellAttributeHelper().getDefaultCellAttribute();
2110 bDefNonDefCase
= true;
2112 else if ( !mvData
.empty() && rOther
.mvData
.empty() )
2115 pDefPattern
= &rOther
.rDocument
.getCellAttributeHelper().getDefaultCellAttribute();
2116 bDefNonDefCase
= true;
2119 if ( bDefNonDefCase
)
2123 if ( nStartRow
> 0 )
2124 pNonDefault
->Search( nStartRow
, nPos
);
2126 while ( nPos
< pNonDefault
->Count() && bEqual
)
2128 const ScPatternAttr
* pNonDefPattern
= pNonDefault
->mvData
[nPos
].getScPatternAttr();
2129 bEqual
= ScPatternAttr::areSame( pNonDefPattern
, pDefPattern
);
2131 if ( pNonDefault
->mvData
[nPos
].nEndRow
>= nEndRow
) break;
2139 SCSIZE nThisPos
= 0;
2140 SCSIZE nOtherPos
= 0;
2141 if ( nStartRow
> 0 )
2143 Search( nStartRow
, nThisPos
);
2144 rOther
.Search( nStartRow
, nOtherPos
);
2147 while ( nThisPos
<mvData
.size() && nOtherPos
<rOther
.Count() && bEqual
)
2149 SCROW nThisRow
= mvData
[nThisPos
].nEndRow
;
2150 SCROW nOtherRow
= rOther
.mvData
[nOtherPos
].nEndRow
;
2151 const ScPatternAttr
* pThisPattern
= mvData
[nThisPos
].getScPatternAttr();
2152 const ScPatternAttr
* pOtherPattern
= rOther
.mvData
[nOtherPos
].getScPatternAttr();
2153 bEqual
= ScPatternAttr::areSame( pThisPattern
, pOtherPattern
);
2155 if ( nThisRow
>= nOtherRow
)
2157 if ( nOtherRow
>= nEndRow
) break;
2160 if ( nThisRow
<= nOtherRow
)
2162 if ( nThisRow
>= nEndRow
) break;
2170 bool ScAttrArray::TestInsertCol( SCROW nStartRow
, SCROW nEndRow
) const
2172 // Horizontal aggregate are not allowed to be moved out; if whole summary,
2173 // here is not recognized
2179 if ( nStartRow
> 0 )
2180 Search( nStartRow
, nIndex
);
2182 for ( ; nIndex
< mvData
.size(); nIndex
++ )
2184 if ( mvData
[nIndex
].getScPatternAttr()->GetItem(ATTR_MERGE_FLAG
).IsHorOverlapped() )
2186 bTest
= false; // may not be pushed out
2189 if ( mvData
[nIndex
].nEndRow
>= nEndRow
) // end of range
2196 bool ScAttrArray::TestInsertRow( SCSIZE nSize
) const
2198 // if 1st row pushed out is vertically overlapped, summary would be broken
2200 // rDocument.MaxRow() + 1 - nSize = 1st row pushed out
2202 if ( mvData
.empty() )
2203 return !rDocument
.getCellAttributeHelper().getDefaultCellAttribute().GetItem(ATTR_MERGE_FLAG
).IsVerOverlapped();
2205 SCSIZE nFirstLost
= mvData
.size()-1;
2206 while ( nFirstLost
&& mvData
[nFirstLost
-1].nEndRow
>= sal::static_int_cast
<SCROW
>(rDocument
.MaxRow() + 1 - nSize
) )
2209 return !mvData
[nFirstLost
].getScPatternAttr()->GetItem(ATTR_MERGE_FLAG
).IsVerOverlapped();
2212 void ScAttrArray::InsertRow( SCROW nStartRow
, SCSIZE nSize
)
2214 SetDefaultIfNotInit();
2216 SCROW nSearch
= nStartRow
> 0 ? nStartRow
- 1 : 0; // expand predecessor
2218 Search( nSearch
, nIndex
);
2220 // set ScMergeAttr may not be extended (so behind delete again)
2222 bool bDoMerge
= mvData
[nIndex
].getScPatternAttr()->GetItem(ATTR_MERGE
).IsMerged();
2224 assert( !bDoMerge
|| nCol
!= -1 );
2228 for (i
= nIndex
; i
< mvData
.size()-1; i
++)
2230 SCROW nNew
= mvData
[i
].nEndRow
+ nSize
;
2231 if ( nNew
>= rDocument
.MaxRow() ) // at end?
2233 nNew
= rDocument
.MaxRow();
2235 nRemove
= i
+1; // remove the following?
2237 mvData
[i
].nEndRow
= nNew
;
2240 // Remove entries at end ?
2242 if (nRemove
&& nRemove
< mvData
.size())
2243 DeleteRange( nRemove
, mvData
.size()-1 );
2245 if (bDoMerge
) // extensively repair (again) ScMergeAttr
2247 // ApplyAttr for areas
2249 const SfxPoolItem
& rDef
= rDocument
.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE
);
2250 for (SCSIZE nAdd
=0; nAdd
<nSize
; nAdd
++)
2251 rDocument
.ApplyAttr( nCol
, nStartRow
+nAdd
, nTab
, rDef
);
2253 // reply inserts in this area not summarized
2256 // Don't duplicate the merge flags in the inserted row.
2257 // #i108488# ScMF::Scenario has to be allowed.
2258 RemoveFlags( nStartRow
, nStartRow
+nSize
-1, ScMF::Hor
| ScMF::Ver
| ScMF::Auto
| ScMF::Button
);
2261 void ScAttrArray::DeleteRow( SCROW nStartRow
, SCSIZE nSize
)
2263 SetDefaultIfNotInit();
2265 SCSIZE nStartIndex
= 0;
2266 SCSIZE nEndIndex
= 0;
2269 for ( i
= 0; i
< mvData
.size()-1; i
++)
2270 if (mvData
[i
].nEndRow
>= nStartRow
&& mvData
[i
].nEndRow
<= sal::static_int_cast
<SCROW
>(nStartRow
+nSize
-1))
2285 nStart
= mvData
[nStartIndex
-1].nEndRow
+ 1;
2287 if (nStart
< nStartRow
)
2289 mvData
[nStartIndex
].nEndRow
= nStartRow
- 1;
2292 if (nEndIndex
>= nStartIndex
)
2294 DeleteRange( nStartIndex
, nEndIndex
);
2295 if (nStartIndex
> 0)
2296 if ( ScPatternAttr::areSame( mvData
[nStartIndex
-1].getScPatternAttr(), mvData
[nStartIndex
].getScPatternAttr() ) )
2297 DeleteRange( nStartIndex
-1, nStartIndex
-1 );
2300 for (i
= 0; i
< mvData
.size()-1; i
++)
2301 if (mvData
[i
].nEndRow
>= nStartRow
)
2302 mvData
[i
].nEndRow
-= nSize
;
2304 // Below does not follow the pattern to detect pressure ranges;
2305 // instead, only remove merge flags.
2306 RemoveFlags( rDocument
.MaxRow()-nSize
+1, rDocument
.MaxRow(), ScMF::Hor
| ScMF::Ver
| ScMF::Auto
);
2309 void ScAttrArray::DeleteRange( SCSIZE nStartIndex
, SCSIZE nEndIndex
)
2311 SetDefaultIfNotInit();
2312 mvData
.erase(mvData
.begin() + nStartIndex
, mvData
.begin() + nEndIndex
+ 1);
2315 void ScAttrArray::DeleteArea(SCROW nStartRow
, SCROW nEndRow
)
2317 SetDefaultIfNotInit();
2319 RemoveAreaMerge( nStartRow
, nEndRow
); // remove from combined flags
2321 const CellAttributeHolder
aDefHolder(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute());
2323 if ( !HasAttrib( nStartRow
, nEndRow
, HasAttrFlags::Overlapped
| HasAttrFlags::AutoFilter
) )
2324 SetPatternArea( nStartRow
, nEndRow
, aDefHolder
);
2326 SetPatternAreaSafe( nStartRow
, nEndRow
, aDefHolder
); // leave merge flags
2329 void ScAttrArray::DeleteHardAttr(SCROW nStartRow
, SCROW nEndRow
)
2331 SetDefaultIfNotInit();
2332 const CellAttributeHolder
aDefHolder(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute());
2338 Search( nStartRow
, nIndex
);
2339 nThisRow
= (nIndex
>0) ? mvData
[nIndex
-1].nEndRow
+1 : 0;
2340 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
2342 while ( nThisRow
<= nEndRow
)
2344 const ScPatternAttr
* pOldPattern
= mvData
[nIndex
].getScPatternAttr();
2346 if ( pOldPattern
->GetItemSet().Count() ) // hard attributes ?
2348 nRow
= mvData
[nIndex
].nEndRow
;
2349 SCROW nAttrRow
= std::min( nRow
, nEndRow
);
2351 ScPatternAttr
* pNewPattern(new ScPatternAttr(*pOldPattern
));
2352 SfxItemSet
& rSet
= pNewPattern
->GetItemSet();
2353 for (sal_uInt16 nId
= ATTR_PATTERN_START
; nId
<= ATTR_PATTERN_END
; nId
++)
2354 if (nId
!= ATTR_MERGE
&& nId
!= ATTR_MERGE_FLAG
)
2355 rSet
.ClearItem(nId
);
2357 if ( *pNewPattern
== *aDefHolder
.getScPatternAttr() )
2360 SetPatternArea( nThisRow
, nAttrRow
, aDefHolder
);
2364 SetPatternArea( nThisRow
, nAttrRow
, CellAttributeHolder(pNewPattern
, true) );
2367 Search( nThisRow
, nIndex
); // data changed
2371 nThisRow
= mvData
[nIndex
-1].nEndRow
+1;
2376 * Move within a document
2378 void ScAttrArray::MoveTo(SCROW nStartRow
, SCROW nEndRow
, ScAttrArray
& rAttrArray
)
2380 SetDefaultIfNotInit();
2381 SCROW nStart
= nStartRow
;
2382 for (SCSIZE i
= 0; i
< mvData
.size(); i
++)
2384 if ((mvData
[i
].nEndRow
>= nStartRow
) && (i
== 0 || mvData
[i
-1].nEndRow
< nEndRow
))
2386 // copy (bPutToPool=TRUE)
2387 rAttrArray
.SetPatternArea( nStart
, std::min( mvData
[i
].nEndRow
, nEndRow
), mvData
[i
].getCellAttributeHolder() );
2389 nStart
= std::max( nStart
, mvData
[i
].nEndRow
+ 1 );
2391 DeleteArea(nStartRow
, nEndRow
);
2395 * Copy between documents (Clipboard)
2397 void ScAttrArray::CopyArea(
2398 SCROW nStartRow
, SCROW nEndRow
, tools::Long nDy
, ScAttrArray
& rAttrArray
, ScMF nStripFlags
) const
2400 nStartRow
-= nDy
; // Source
2403 SCROW nDestStart
= std::max(static_cast<tools::Long
>(static_cast<tools::Long
>(nStartRow
) + nDy
), tools::Long(0));
2404 SCROW nDestEnd
= std::min(static_cast<tools::Long
>(static_cast<tools::Long
>(nEndRow
) + nDy
), tools::Long(rDocument
.MaxRow()));
2405 const bool bSameCellAttributeHelper(&rDocument
.getCellAttributeHelper() == &rAttrArray
.rDocument
.getCellAttributeHelper());
2407 const ScPatternAttr
* pSourceDefaultPattern
= &rDocument
.getCellAttributeHelper().getDefaultCellAttribute();
2408 const ScPatternAttr
* pDestDefaultPattern
= &rAttrArray
.rDocument
.getCellAttributeHelper().getDefaultCellAttribute();
2409 if ( mvData
.empty() )
2411 rAttrArray
.SetPatternArea(nDestStart
, nDestEnd
, pDestDefaultPattern
);
2415 for (SCSIZE i
= 0; (i
< mvData
.size()) && (nDestStart
<= nDestEnd
); i
++)
2417 if (mvData
[i
].nEndRow
>= nStartRow
)
2419 const ScPatternAttr
* pOldPattern
= mvData
[i
].getScPatternAttr();
2420 CellAttributeHolder aNewPattern
;
2422 if (ScPatternAttr::areSame(pSourceDefaultPattern
, pOldPattern
))
2424 // default: nothing changed
2425 aNewPattern
.setScPatternAttr(pDestDefaultPattern
);
2427 else if ( nStripFlags
!= ScMF::NONE
)
2429 ScPatternAttr
* pTmpPattern(new ScPatternAttr(*pOldPattern
));
2430 ScMF nNewFlags
= ScMF::NONE
;
2431 if ( nStripFlags
!= ScMF::All
)
2432 nNewFlags
= pTmpPattern
->GetItem(ATTR_MERGE_FLAG
).GetValue() & ~nStripFlags
;
2434 if ( nNewFlags
!= ScMF::NONE
)
2435 pTmpPattern
->GetItemSet().Put( ScMergeFlagAttr( nNewFlags
) );
2437 pTmpPattern
->GetItemSet().ClearItem( ATTR_MERGE_FLAG
);
2439 if (bSameCellAttributeHelper
)
2440 aNewPattern
.setScPatternAttr(pTmpPattern
, true);
2443 aNewPattern
= pTmpPattern
->MigrateToDocument( &rAttrArray
.rDocument
, &rDocument
);
2449 if (bSameCellAttributeHelper
)
2450 aNewPattern
.setScPatternAttr(pOldPattern
);
2452 aNewPattern
= pOldPattern
->MigrateToDocument( &rAttrArray
.rDocument
, &rDocument
);
2455 rAttrArray
.SetPatternArea(nDestStart
,
2456 std::min(static_cast<SCROW
>(mvData
[i
].nEndRow
+ nDy
), nDestEnd
), aNewPattern
.getScPatternAttr());
2459 // when pasting from clipboard and skipping filtered rows, the adjusted
2460 // end position can be negative
2461 nDestStart
= std::max(static_cast<tools::Long
>(nDestStart
), static_cast<tools::Long
>(mvData
[i
].nEndRow
+ nDy
+ 1));
2467 * summarized with CopyArea
2469 void ScAttrArray::CopyAreaSafe( SCROW nStartRow
, SCROW nEndRow
, tools::Long nDy
, ScAttrArray
& rAttrArray
)
2471 nStartRow
-= nDy
; // Source
2474 SCROW nDestStart
= std::max(static_cast<tools::Long
>(static_cast<tools::Long
>(nStartRow
) + nDy
), tools::Long(0));
2475 SCROW nDestEnd
= std::min(static_cast<tools::Long
>(static_cast<tools::Long
>(nEndRow
) + nDy
), tools::Long(rDocument
.MaxRow()));
2477 if ( !rAttrArray
.HasAttrib( nDestStart
, nDestEnd
, HasAttrFlags::Overlapped
) )
2479 CopyArea( nStartRow
+nDy
, nEndRow
+nDy
, nDy
, rAttrArray
);
2483 const bool bSameCellAttributeHelper(&rDocument
.getCellAttributeHelper() == &rAttrArray
.rDocument
.getCellAttributeHelper());
2485 if ( mvData
.empty() )
2487 CellAttributeHolder aNewPattern
;
2488 if (bSameCellAttributeHelper
)
2489 aNewPattern
.setScPatternAttr(&rDocument
.getCellAttributeHelper().getDefaultCellAttribute());
2491 aNewPattern
= rDocument
.getCellAttributeHelper().getDefaultCellAttribute().MigrateToDocument( &rAttrArray
.rDocument
, &rDocument
);
2493 rAttrArray
.SetPatternAreaSafe(nDestStart
, nDestEnd
, aNewPattern
);
2498 for (SCSIZE i
= 0; (i
< mvData
.size()) && (nDestStart
<= nDestEnd
); i
++)
2500 if (mvData
[i
].nEndRow
>= nStartRow
)
2502 const ScPatternAttr
* pOldPattern
= mvData
[i
].getScPatternAttr();
2503 CellAttributeHolder aNewPattern
;
2505 if (bSameCellAttributeHelper
)
2506 aNewPattern
.setScPatternAttr(pOldPattern
);
2508 aNewPattern
= pOldPattern
->MigrateToDocument( &rAttrArray
.rDocument
, &rDocument
);
2510 rAttrArray
.SetPatternAreaSafe(nDestStart
,
2511 std::min(static_cast<SCROW
>(mvData
[i
].nEndRow
+ nDy
), nDestEnd
), aNewPattern
);
2514 // when pasting from clipboard and skipping filtered rows, the adjusted
2515 // end position can be negative
2516 nDestStart
= std::max(static_cast<tools::Long
>(nDestStart
), static_cast<tools::Long
>(mvData
[i
].nEndRow
+ nDy
+ 1));
2520 SCROW
ScAttrArray::SearchStyle(
2521 SCROW nRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
2522 const ScMarkArray
* pMarkArray
) const
2524 bool bFound
= false;
2528 nRow
= pMarkArray
->GetNextMarked( nRow
, bUp
);
2529 if (!rDocument
.ValidRow(nRow
))
2533 if ( mvData
.empty() )
2535 if (rDocument
.getCellAttributeHelper().getDefaultCellAttribute().GetStyleSheet() == pSearchStyle
)
2538 nRow
= bUp
? -1 : rDocument
.MaxRow() + 1;
2543 Search(nRow
, nIndex
);
2544 const ScPatternAttr
* pPattern
= mvData
[nIndex
].getScPatternAttr();
2546 while (nIndex
< mvData
.size() && !bFound
)
2548 if (pPattern
->GetStyleSheet() == pSearchStyle
)
2552 nRow
= pMarkArray
->GetNextMarked( nRow
, bUp
);
2553 SCROW nStart
= nIndex
? mvData
[nIndex
-1].nEndRow
+1 : 0;
2554 if (nRow
>= nStart
&& nRow
<= mvData
[nIndex
].nEndRow
)
2567 nIndex
= mvData
.size();
2573 nRow
= mvData
[nIndex
].nEndRow
;
2574 pPattern
= mvData
[nIndex
].getScPatternAttr();
2579 nRow
= mvData
[nIndex
].nEndRow
+1;
2581 if (nIndex
<mvData
.size())
2582 pPattern
= mvData
[nIndex
].getScPatternAttr();
2587 OSL_ENSURE( bFound
|| !rDocument
.ValidRow(nRow
), "Internal failure in ScAttrArray::SearchStyle" );
2592 bool ScAttrArray::SearchStyleRange(
2593 SCROW
& rRow
, SCROW
& rEndRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
2594 const ScMarkArray
* pMarkArray
) const
2596 SCROW nStartRow
= SearchStyle( rRow
, pSearchStyle
, bUp
, pMarkArray
);
2597 if (rDocument
.ValidRow(nStartRow
))
2599 if ( mvData
.empty() )
2607 SCROW nMarkEnd
= pMarkArray
->GetMarkEnd( nStartRow
, true );
2608 if (nMarkEnd
>rEndRow
)
2614 rEndRow
= rDocument
.MaxRow();
2617 SCROW nMarkEnd
= pMarkArray
->GetMarkEnd( nStartRow
, false );
2618 if (nMarkEnd
<rEndRow
)
2627 Search(nStartRow
,nIndex
);
2633 rEndRow
= mvData
[nIndex
-1].nEndRow
+ 1;
2638 SCROW nMarkEnd
= pMarkArray
->GetMarkEnd( nStartRow
, true );
2639 if (nMarkEnd
>rEndRow
)
2645 rEndRow
= mvData
[nIndex
].nEndRow
;
2648 SCROW nMarkEnd
= pMarkArray
->GetMarkEnd( nStartRow
, false );
2649 if (nMarkEnd
<rEndRow
)
2660 SCSIZE
ScAttrArray::Count( SCROW nStartRow
, SCROW nEndRow
) const
2662 if ( mvData
.empty() )
2665 SCSIZE nIndex1
, nIndex2
;
2667 if( !Search( nStartRow
, nIndex1
) )
2670 if( !Search( nEndRow
, nIndex2
) )
2671 nIndex2
= mvData
.size() - 1;
2673 return nIndex2
- nIndex1
+ 1;
2676 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */