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 <svx/algitem.hxx>
23 #include <editeng/boxitem.hxx>
24 #include <editeng/lineitem.hxx>
25 #include <editeng/frmdiritem.hxx>
26 #include <editeng/shaditem.hxx>
27 #include <editeng/editobj.hxx>
28 #include <editeng/justifyitem.hxx>
29 #include <svl/poolcach.hxx>
30 #include <editeng/fontitem.hxx>
31 #include <unotools/fontcvt.hxx>
34 #include "document.hxx"
35 #include "docpool.hxx"
36 #include "patattr.hxx"
37 #include "stlsheet.hxx"
38 #include "stlpool.hxx"
39 #include "markarr.hxx"
40 #include "rechead.hxx"
41 #include "globstr.hrc"
42 #include "segmenttree.hxx"
43 #include "editdataarray.hxx"
44 #include "formulacell.hxx"
45 #include "cellvalue.hxx"
46 #include "editutil.hxx"
47 #include <rtl/strbuf.hxx>
49 // STATIC DATA -----------------------------------------------------------
51 //------------------------------------------------------------------------
52 using ::editeng::SvxBorderLine
;
54 ScAttrArray::ScAttrArray( SCCOL nNewCol
, SCTAB nNewTab
, ScDocument
* pDoc
) :
60 pData(new ScAttrEntry
[1])
62 pData
[0].nRow
= MAXROW
;
63 pData
[0].pPattern
= pDocument
->GetDefPattern(); // no put
66 //------------------------------------------------------------------------
68 ScAttrArray::~ScAttrArray()
70 #if OSL_DEBUG_LEVEL > 1
74 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
75 for (SCSIZE i
=0; i
<nCount
; i
++)
76 pDocPool
->Remove(*pData
[i
].pPattern
);
81 //------------------------------------------------------------------------
82 #if OSL_DEBUG_LEVEL > 1
83 void ScAttrArray::TestData() const
88 for (nPos
=0; nPos
<nCount
; nPos
++)
91 if (pData
[nPos
].pPattern
== pData
[nPos
-1].pPattern
|| pData
[nPos
].nRow
<= pData
[nPos
-1].nRow
)
93 if (pData
[nPos
].pPattern
->Which() != ATTR_PATTERN
)
96 if ( nPos
&& pData
[nPos
-1].nRow
!= MAXROW
)
102 aMsg
.append(static_cast<sal_Int32
>(nErr
));
103 aMsg
.append(" errors in attribute array, column ");
104 aMsg
.append(static_cast<sal_Int32
>(nCol
));
105 OSL_FAIL(aMsg
.getStr());
110 //------------------------------------------------------------------------
112 void ScAttrArray::Reset( const ScPatternAttr
* pPattern
)
114 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
115 const ScPatternAttr
* pOldPattern
;
116 ScAddress
aAdrStart( nCol
, 0, nTab
);
117 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
119 for (SCSIZE i
=0; i
<nCount
; i
++)
121 // ensure that attributing changes text width of cell
122 pOldPattern
= pData
[i
].pPattern
;
123 bool bNumFormatChanged
;
124 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
125 pPattern
->GetItemSet(), pOldPattern
->GetItemSet() ) )
127 aAdrStart
.SetRow( i
? pData
[i
-1].nRow
+1 : 0 );
128 aAdrEnd
.SetRow( pData
[i
].nRow
);
129 pDocument
->InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
131 pDocPool
->Remove(*pOldPattern
);
135 if (pDocument
->IsStreamValid(nTab
))
136 pDocument
->SetStreamValid(nTab
, false);
139 pData
= new ScAttrEntry
[1];
140 ScPatternAttr
* pNewPattern
= (ScPatternAttr
*) &pDocPool
->Put(*pPattern
);
141 pData
[0].nRow
= MAXROW
;
142 pData
[0].pPattern
= pNewPattern
;
146 bool ScAttrArray::Concat(SCSIZE nPos
)
153 if (pData
[nPos
- 1].pPattern
== pData
[nPos
].pPattern
)
155 pData
[nPos
- 1].nRow
= pData
[nPos
].nRow
;
156 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
157 memmove(&pData
[nPos
], &pData
[nPos
+ 1], (nCount
- nPos
- 1) * sizeof(ScAttrEntry
));
158 pData
[nCount
- 1].pPattern
= NULL
;
159 pData
[nCount
- 1].nRow
= 0;
165 if (nPos
+ 1 < nCount
)
167 if (pData
[nPos
+ 1].pPattern
== pData
[nPos
].pPattern
)
169 pData
[nPos
].nRow
= pData
[nPos
+ 1].nRow
;
170 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
171 memmove(&pData
[nPos
+ 1], &pData
[nPos
+ 2], (nCount
- nPos
- 2) * sizeof(ScAttrEntry
));
172 pData
[nCount
- 1].pPattern
= NULL
;
173 pData
[nCount
- 1].nRow
= 0;
182 //------------------------------------------------------------------------
184 bool ScAttrArray::Search( SCROW nRow
, SCSIZE
& nIndex
) const
186 long nHi
= static_cast<long>(nCount
) - 1;
188 bool bFound
= (nCount
== 1);
192 while ( !bFound
&& nLo
<= nHi
)
196 nStartRow
= (long) pData
[i
- 1].nRow
;
199 nEndRow
= (long) pData
[i
].nRow
;
200 if (nEndRow
< (long) nRow
)
203 if (nStartRow
>= (long) nRow
)
217 const ScPatternAttr
* ScAttrArray::GetPattern( SCROW nRow
) const
220 if (Search( nRow
, i
))
221 return pData
[i
].pPattern
;
227 const ScPatternAttr
* ScAttrArray::GetPatternRange( SCROW
& rStartRow
,
228 SCROW
& rEndRow
, SCROW nRow
) const
231 if ( Search( nRow
, nIndex
) )
234 rStartRow
= pData
[nIndex
-1].nRow
+ 1;
237 rEndRow
= pData
[nIndex
].nRow
;
238 return pData
[nIndex
].pPattern
;
243 void ScAttrArray::AddCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
245 if(!ValidRow(nStartRow
) || !ValidRow(nEndRow
))
248 if(nEndRow
< nStartRow
)
251 SCROW nTempStartRow
= nStartRow
;
252 SCROW nTempEndRow
= nEndRow
;
256 const ScPatternAttr
* pPattern
= GetPattern(nTempStartRow
);
258 boost::scoped_ptr
<ScPatternAttr
> pNewPattern
;
261 pNewPattern
.reset( new ScPatternAttr(*pPattern
) );
262 SCROW nPatternStartRow
;
263 SCROW nPatternEndRow
;
264 GetPatternRange( nPatternStartRow
, nPatternEndRow
, nTempStartRow
);
266 nTempEndRow
= std::min
<SCROW
>( nPatternEndRow
, nEndRow
);
267 const SfxPoolItem
* pItem
= NULL
;
268 pPattern
->GetItemSet().GetItemState( ATTR_CONDITIONAL
, true, &pItem
);
269 std::vector
< sal_uInt32
> aCondFormatData
;
271 aCondFormatData
= static_cast<const ScCondFormatItem
*>(pItem
)->GetCondFormatData();
272 aCondFormatData
.push_back(nIndex
);
274 ScCondFormatItem aItem
;
275 aItem
.SetCondFormatData( aCondFormatData
);
276 pNewPattern
->GetItemSet().Put( aItem
);
280 pNewPattern
.reset( new ScPatternAttr( pDocument
->GetPool() ) );
281 ScCondFormatItem aItem
;
282 aItem
.AddCondFormatData(nIndex
);
283 pNewPattern
->GetItemSet().Put( aItem
);
284 nTempEndRow
= nEndRow
;
287 SetPatternArea( nTempStartRow
, nTempEndRow
, pNewPattern
.get(), true );
288 nTempStartRow
= nTempEndRow
+ 1;
290 while(nTempEndRow
< nEndRow
);
294 void ScAttrArray::RemoveCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
296 if(!ValidRow(nStartRow
) || !ValidRow(nEndRow
))
299 if(nEndRow
< nStartRow
)
302 SCROW nTempStartRow
= nStartRow
;
303 SCROW nTempEndRow
= nEndRow
;
307 const ScPatternAttr
* pPattern
= GetPattern(nTempStartRow
);
311 ScPatternAttr
aPattern( *pPattern
);
312 SCROW nPatternStartRow
;
313 SCROW nPatternEndRow
;
314 GetPatternRange( nPatternStartRow
, nPatternEndRow
, nTempStartRow
);
316 nTempEndRow
= std::min
<SCROW
>( nPatternEndRow
, nEndRow
);
317 const SfxPoolItem
* pItem
= NULL
;
318 pPattern
->GetItemSet().GetItemState( ATTR_CONDITIONAL
, true, &pItem
);
321 std::vector
< sal_uInt32
> aCondFormatData
= static_cast<const ScCondFormatItem
*>(pItem
)->GetCondFormatData();
322 std::vector
<sal_uInt32
>::iterator itr
= std::find(aCondFormatData
.begin(), aCondFormatData
.end(), nIndex
);
323 if(itr
!= aCondFormatData
.end())
325 ScCondFormatItem aItem
;
326 aCondFormatData
.erase(itr
);
327 aItem
.SetCondFormatData( aCondFormatData
);
328 aPattern
.GetItemSet().Put( aItem
);
329 SetPatternArea( nTempStartRow
, nTempEndRow
, &aPattern
, true );
339 nTempStartRow
= nTempEndRow
+ 1;
341 while(nTempEndRow
< nEndRow
);
345 //------------------------------------------------------------------------
347 void ScAttrArray::SetPattern( SCROW nRow
, const ScPatternAttr
* pPattern
, bool bPutToPool
)
349 SetPatternArea( nRow
, nRow
, pPattern
, bPutToPool
);
352 void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow
, SCROW nEndRow
,
353 const ScPatternAttr
* pPattern
, ScEditDataArray
* pDataArray
)
355 for (SCROW nRow
= nStartRow
; nRow
<= nEndRow
; ++nRow
)
357 ScAddress
aPos(nCol
, nRow
, nTab
);
358 ScRefCellValue aCell
;
359 aCell
.assign(*pDocument
, aPos
);
360 if (aCell
.meType
!= CELLTYPE_EDIT
|| !aCell
.mpEditText
)
363 EditTextObject
* pOldData
= NULL
;
365 pOldData
= aCell
.mpEditText
->Clone();
367 // Direct modification of cell content - something to watch out for if
368 // we decide to share edit text instances in the future.
369 ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject
&>(*aCell
.mpEditText
), *pPattern
);
373 EditTextObject
* pNewData
= aCell
.mpEditText
->Clone();
374 pDataArray
->AddItem(nTab
, nCol
, nRow
, pOldData
, pNewData
);
379 void ScAttrArray::SetPatternArea(SCROW nStartRow
, SCROW nEndRow
, const ScPatternAttr
*pPattern
,
380 bool bPutToPool
, ScEditDataArray
* pDataArray
)
382 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
385 pPattern
= (const ScPatternAttr
*) &pDocument
->GetPool()->Put(*pPattern
);
387 if ((nStartRow
== 0) && (nEndRow
== MAXROW
))
391 SCSIZE nNeeded
= nCount
+ 2;
392 if ( nLimit
< nNeeded
)
394 nLimit
+= SC_ATTRARRAY_DELTA
;
395 if ( nLimit
< nNeeded
)
397 ScAttrEntry
* pNewData
= new ScAttrEntry
[nLimit
];
398 memcpy( pNewData
, pData
, nCount
*sizeof(ScAttrEntry
) );
403 ScAddress
aAdrStart( nCol
, 0, nTab
);
404 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
406 SCSIZE ni
= 0; // number of entries in beginning
407 SCSIZE nx
= 0; // track position
408 SCROW ns
= 0; // start row of track position
413 Search( nStartRow
, nIndex
);
419 ns
= pData
[ni
-1].nRow
+1;
423 // ensure that attributing changes text width of cell
424 // otherwise, conditional formats need to be reset or deleted
425 while ( ns
<= nEndRow
)
427 const SfxItemSet
& rNewSet
= pPattern
->GetItemSet();
428 const SfxItemSet
& rOldSet
= pData
[nx
].pPattern
->GetItemSet();
430 bool bNumFormatChanged
;
431 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
434 aAdrStart
.SetRow( std::max(nStartRow
,ns
) );
435 aAdrEnd
.SetRow( std::min(nEndRow
,pData
[nx
].nRow
) );
436 pDocument
->InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
438 ns
= pData
[nx
].nRow
+ 1;
442 // continue modifying data array
444 SCSIZE nInsert
; // insert position (MAXROWCOUNT := no insert)
445 bool bCombined
= false;
449 nInsert
= MAXROWCOUNT
;
450 if ( pData
[ni
].pPattern
!= pPattern
)
452 if ( ni
== 0 || (pData
[ni
-1].nRow
< nStartRow
- 1) )
453 { // may be a split or a simple insert or just a shrink,
454 // row adjustment is done further down
455 if ( pData
[ni
].nRow
> nEndRow
)
460 else if ( ni
> 0 && pData
[ni
-1].nRow
== nStartRow
- 1 )
463 if ( ni
> 0 && pData
[ni
-1].pPattern
== pPattern
)
465 pData
[ni
-1].nRow
= nEndRow
;
466 nInsert
= MAXROWCOUNT
;
473 SCSIZE nj
= ni
; // stop position of range to replace
474 while ( nj
< nCount
&& pData
[nj
].nRow
<= nEndRow
)
478 if ( nj
< nCount
&& pData
[nj
].pPattern
== pPattern
)
482 if ( pData
[ni
-1].pPattern
== pPattern
)
483 { // adjacent entries
484 pData
[ni
-1].nRow
= pData
[nj
].nRow
;
487 else if ( ni
== nInsert
)
488 pData
[ni
-1].nRow
= nStartRow
- 1; // shrink
490 nInsert
= MAXROWCOUNT
;
493 else if ( ni
> 0 && ni
== nInsert
)
494 pData
[ni
-1].nRow
= nStartRow
- 1; // shrink
496 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
498 { // duplicate splitted entry in pool
499 pDocPool
->Put( *pData
[ni
-1].pPattern
);
502 { // remove middle entries
503 for ( SCSIZE nk
=ni
; nk
<nj
; nk
++)
504 { // remove entries from pool
505 pDocPool
->Remove( *pData
[nk
].pPattern
);
508 { // replace one entry
509 pData
[ni
].nRow
= nEndRow
;
510 pData
[ni
].pPattern
= pPattern
;
512 nInsert
= MAXROWCOUNT
;
516 memmove( pData
+ ni
, pData
+ nj
, (nCount
- nj
) * sizeof(ScAttrEntry
) );
521 if ( nInsert
< sal::static_int_cast
<SCSIZE
>(MAXROWCOUNT
) )
522 { // insert or append new entry
523 if ( nInsert
<= nCount
)
526 memmove( pData
+ nInsert
+ 1, pData
+ nInsert
,
527 (nCount
- nInsert
) * sizeof(ScAttrEntry
) );
530 memmove( pData
+ nInsert
+ 2, pData
+ nInsert
,
531 (nCount
- nInsert
) * sizeof(ScAttrEntry
) );
532 pData
[nInsert
+1] = pData
[nInsert
-1];
537 pData
[nInsert
-1].nRow
= nStartRow
- 1;
538 pData
[nInsert
].nRow
= nEndRow
;
539 pData
[nInsert
].pPattern
= pPattern
;
541 // Remove character attributes from these cells if the pattern
542 // is applied during normal session.
544 RemoveCellCharAttribs(nStartRow
, nEndRow
, pPattern
, pDataArray
);
549 if (pDocument
->IsStreamValid(nTab
))
550 pDocument
->SetStreamValid(nTab
, false);
554 #if OSL_DEBUG_LEVEL > 1
560 void ScAttrArray::ApplyStyleArea( SCROW nStartRow
, SCROW nEndRow
, ScStyleSheet
* pStyle
)
562 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
566 if (!Search( nStartRow
, nPos
))
568 OSL_FAIL("Search Failure");
572 ScAddress
aAdrStart( nCol
, 0, nTab
);
573 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
577 const ScPatternAttr
* pOldPattern
= pData
[nPos
].pPattern
;
578 ScPatternAttr
* pNewPattern
= new ScPatternAttr(*pOldPattern
);
579 pNewPattern
->SetStyleSheet(pStyle
);
581 SCROW nY2
= pData
[nPos
].nRow
;
582 nStart
= pData
[nPos
].nRow
+ 1;
584 if ( *pNewPattern
== *pOldPattern
)
586 // keep the original pattern (might be default)
587 // pNewPattern is deleted below
590 else if ( nY1
< nStartRow
|| nY2
> nEndRow
)
592 if (nY1
< nStartRow
) nY1
=nStartRow
;
593 if (nY2
> nEndRow
) nY2
=nEndRow
;
594 SetPatternArea( nY1
, nY2
, pNewPattern
, true );
595 Search( nStart
, nPos
);
599 // ensure attributing changes text width of cell; otherwise
600 // there aren't (yet) template format changes
601 const SfxItemSet
& rNewSet
= pNewPattern
->GetItemSet();
602 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
604 bool bNumFormatChanged
;
605 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
608 aAdrStart
.SetRow( nPos
? pData
[nPos
-1].nRow
+1 : 0 );
609 aAdrEnd
.SetRow( pData
[nPos
].nRow
);
610 pDocument
->InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
613 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
614 pData
[nPos
].pPattern
= (const ScPatternAttr
*)
615 &pDocument
->GetPool()->Put(*pNewPattern
);
617 Search(nStart
, nPos
);
623 while ((nStart
<= nEndRow
) && (nPos
< nCount
));
625 if (pDocument
->IsStreamValid(nTab
))
626 pDocument
->SetStreamValid(nTab
, false);
629 #if OSL_DEBUG_LEVEL > 1
635 // const cast, otherwise it will be too inefficient/complicated
636 #define SET_LINECOLOR(dest,c) \
639 ((SvxBorderLine*)(dest))->SetColor((c)); \
642 #define SET_LINE(dest,src) \
645 SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
646 pCast->SetBorderLineStyle( (src)->GetBorderLineStyle() ); \
647 pCast->SetWidth( (src)->GetWidth( ) ); \
650 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow
, SCROW nEndRow
,
651 const SvxBorderLine
* pLine
, bool bColorOnly
)
653 if ( bColorOnly
&& !pLine
)
656 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
660 if (!Search( nStartRow
, nPos
))
662 OSL_FAIL("Search failure");
668 const ScPatternAttr
* pOldPattern
= pData
[nPos
].pPattern
;
669 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
670 const SfxPoolItem
* pBoxItem
= 0;
671 SfxItemState eState
= rOldSet
.GetItemState( ATTR_BORDER
, true, &pBoxItem
);
672 const SfxPoolItem
* pTLBRItem
= 0;
673 SfxItemState eTLBRState
= rOldSet
.GetItemState( ATTR_BORDER_TLBR
, true, &pTLBRItem
);
674 const SfxPoolItem
* pBLTRItem
= 0;
675 SfxItemState eBLTRState
= rOldSet
.GetItemState( ATTR_BORDER_BLTR
, true, &pBLTRItem
);
677 if ( (SFX_ITEM_SET
== eState
) || (SFX_ITEM_SET
== eTLBRState
) || (SFX_ITEM_SET
== eBLTRState
) )
679 ScPatternAttr
* pNewPattern
= new ScPatternAttr(*pOldPattern
);
680 SfxItemSet
& rNewSet
= pNewPattern
->GetItemSet();
682 SCROW nY2
= pData
[nPos
].nRow
;
684 SvxBoxItem
* pNewBoxItem
= pBoxItem
? (SvxBoxItem
*)pBoxItem
->Clone() : 0;
685 SvxLineItem
* pNewTLBRItem
= pTLBRItem
? (SvxLineItem
*)pTLBRItem
->Clone() : 0;
686 SvxLineItem
* pNewBLTRItem
= pBLTRItem
? (SvxLineItem
*)pBLTRItem
->Clone() : 0;
688 // fetch line and update attributes with parameters
694 if ( pNewBoxItem
->GetTop() ) pNewBoxItem
->SetLine( NULL
, BOX_LINE_TOP
);
695 if ( pNewBoxItem
->GetBottom() ) pNewBoxItem
->SetLine( NULL
, BOX_LINE_BOTTOM
);
696 if ( pNewBoxItem
->GetLeft() ) pNewBoxItem
->SetLine( NULL
, BOX_LINE_LEFT
);
697 if ( pNewBoxItem
->GetRight() ) pNewBoxItem
->SetLine( NULL
, BOX_LINE_RIGHT
);
699 if( pNewTLBRItem
&& pNewTLBRItem
->GetLine() )
700 pNewTLBRItem
->SetLine( 0 );
701 if( pNewBLTRItem
&& pNewBLTRItem
->GetLine() )
702 pNewBLTRItem
->SetLine( 0 );
708 Color
aColor( pLine
->GetColor() );
711 SET_LINECOLOR( pNewBoxItem
->GetTop(), aColor
);
712 SET_LINECOLOR( pNewBoxItem
->GetBottom(), aColor
);
713 SET_LINECOLOR( pNewBoxItem
->GetLeft(), aColor
);
714 SET_LINECOLOR( pNewBoxItem
->GetRight(), aColor
);
717 SET_LINECOLOR( pNewTLBRItem
->GetLine(), aColor
);
719 SET_LINECOLOR( pNewBLTRItem
->GetLine(), aColor
);
725 SET_LINE( pNewBoxItem
->GetTop(), pLine
);
726 SET_LINE( pNewBoxItem
->GetBottom(), pLine
);
727 SET_LINE( pNewBoxItem
->GetLeft(), pLine
);
728 SET_LINE( pNewBoxItem
->GetRight(), pLine
);
731 SET_LINE( pNewTLBRItem
->GetLine(), pLine
);
733 SET_LINE( pNewBLTRItem
->GetLine(), pLine
);
736 if( pNewBoxItem
) rNewSet
.Put( *pNewBoxItem
);
737 if( pNewTLBRItem
) rNewSet
.Put( *pNewTLBRItem
);
738 if( pNewBLTRItem
) rNewSet
.Put( *pNewBLTRItem
);
740 nStart
= pData
[nPos
].nRow
+ 1;
742 if ( nY1
< nStartRow
|| nY2
> nEndRow
)
744 if (nY1
< nStartRow
) nY1
=nStartRow
;
745 if (nY2
> nEndRow
) nY2
=nEndRow
;
746 SetPatternArea( nY1
, nY2
, pNewPattern
, true );
747 Search( nStart
, nPos
);
751 // remove from pool ?
752 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
753 pData
[nPos
].pPattern
= (const ScPatternAttr
*)
754 &pDocument
->GetPool()->Put(*pNewPattern
);
757 Search(nStart
, nPos
);
768 nStart
= pData
[nPos
].nRow
+ 1;
772 while ((nStart
<= nEndRow
) && (nPos
< nCount
));
780 void ScAttrArray::ApplyCacheArea( SCROW nStartRow
, SCROW nEndRow
, SfxItemPoolCache
* pCache
, ScEditDataArray
* pDataArray
)
782 #if OSL_DEBUG_LEVEL > 1
786 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
790 if (!Search( nStartRow
, nPos
))
792 OSL_FAIL("Search Failure");
796 ScAddress
aAdrStart( nCol
, 0, nTab
);
797 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
801 const ScPatternAttr
* pOldPattern
= pData
[nPos
].pPattern
;
802 const ScPatternAttr
* pNewPattern
= (const ScPatternAttr
*) &pCache
->ApplyTo( *pOldPattern
, true );
803 ScDocumentPool::CheckRef( *pOldPattern
);
804 ScDocumentPool::CheckRef( *pNewPattern
);
805 if (pNewPattern
!= pOldPattern
)
808 SCROW nY2
= pData
[nPos
].nRow
;
809 nStart
= pData
[nPos
].nRow
+ 1;
811 if ( nY1
< nStartRow
|| nY2
> nEndRow
)
813 if (nY1
< nStartRow
) nY1
=nStartRow
;
814 if (nY2
> nEndRow
) nY2
=nEndRow
;
815 SetPatternArea( nY1
, nY2
, pNewPattern
, false, pDataArray
);
816 Search( nStart
, nPos
);
820 // ensure attributing changes text-width of cell
822 const SfxItemSet
& rNewSet
= pNewPattern
->GetItemSet();
823 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
825 bool bNumFormatChanged
;
826 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
829 aAdrStart
.SetRow( nPos
? pData
[nPos
-1].nRow
+1 : 0 );
830 aAdrEnd
.SetRow( pData
[nPos
].nRow
);
831 pDocument
->InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
834 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
835 pData
[nPos
].pPattern
= pNewPattern
;
837 Search(nStart
, nPos
);
844 nStart
= pData
[nPos
].nRow
+ 1;
848 while (nStart
<= nEndRow
);
850 if (pDocument
->IsStreamValid(nTab
))
851 pDocument
->SetStreamValid(nTab
, false);
854 #if OSL_DEBUG_LEVEL > 1
859 bool ScAttrArray::SetAttrEntries(ScAttrEntry
* pNewData
, SCSIZE nSize
)
861 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
862 for (SCSIZE i
=0; i
<nCount
; i
++)
863 pDocPool
->Remove(*pData
[i
].pPattern
);
868 nCount
= nLimit
= nSize
;
872 static void lcl_MergeDeep( SfxItemSet
& rMergeSet
, const SfxItemSet
& rSource
)
874 const SfxPoolItem
* pNewItem
;
875 const SfxPoolItem
* pOldItem
;
876 for (sal_uInt16 nId
=ATTR_PATTERN_START
; nId
<=ATTR_PATTERN_END
; nId
++)
878 // pMergeSet has no parent
879 SfxItemState eOldState
= rMergeSet
.GetItemState( nId
, false, &pOldItem
);
881 if ( eOldState
== SFX_ITEM_DEFAULT
)
883 SfxItemState eNewState
= rSource
.GetItemState( nId
, true, &pNewItem
);
884 if ( eNewState
== SFX_ITEM_SET
)
886 if ( *pNewItem
!= rMergeSet
.GetPool()->GetDefaultItem(nId
) )
887 rMergeSet
.InvalidateItem( nId
);
890 else if ( eOldState
== SFX_ITEM_SET
) // Item gesetzt
892 SfxItemState eNewState
= rSource
.GetItemState( nId
, true, &pNewItem
);
893 if ( eNewState
== SFX_ITEM_SET
)
895 if ( pNewItem
!= pOldItem
) // beide gepuhlt
896 rMergeSet
.InvalidateItem( nId
);
900 if ( *pOldItem
!= rSource
.GetPool()->GetDefaultItem(nId
) )
901 rMergeSet
.InvalidateItem( nId
);
904 // Dontcare remains Dontcare
909 void ScAttrArray::MergePatternArea( SCROW nStartRow
, SCROW nEndRow
,
910 ScMergePatternState
& rState
, bool bDeep
) const
912 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
916 if (!Search( nStartRow
, nPos
))
918 OSL_FAIL("Search failure");
924 // similar patterns must not be repeated
926 const ScPatternAttr
* pPattern
= pData
[nPos
].pPattern
;
927 if ( pPattern
!= rState
.pOld1
&& pPattern
!= rState
.pOld2
)
929 const SfxItemSet
& rThisSet
= pPattern
->GetItemSet();
933 lcl_MergeDeep( *rState
.pItemSet
, rThisSet
);
935 rState
.pItemSet
->MergeValues( rThisSet
, false );
939 // first pattern - copied from parent
940 rState
.pItemSet
= new SfxItemSet( *rThisSet
.GetPool(), rThisSet
.GetRanges() );
941 rState
.pItemSet
->Set( rThisSet
, bDeep
);
944 rState
.pOld2
= rState
.pOld1
;
945 rState
.pOld1
= pPattern
;
948 nStart
= pData
[nPos
].nRow
+ 1;
951 while (nStart
<= nEndRow
);
959 static bool lcl_TestAttr( const SvxBorderLine
* pOldLine
, const SvxBorderLine
* pNewLine
,
960 sal_uInt8
& rModified
, const SvxBorderLine
*& rpNew
)
962 if (rModified
== SC_LINE_DONTCARE
)
963 return false; // don't go again
965 if (rModified
== SC_LINE_EMPTY
)
967 rModified
= SC_LINE_SET
;
969 return true; // initial value
972 if (pOldLine
== pNewLine
)
978 if (pOldLine
&& pNewLine
)
979 if (*pOldLine
== *pNewLine
)
985 rModified
= SC_LINE_DONTCARE
;
987 return true; // another line -> don't care
991 static void lcl_MergeToFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
992 ScLineFlags
& rFlags
, const ScPatternAttr
* pPattern
,
993 bool bLeft
, SCCOL nDistRight
, bool bTop
, SCROW nDistBottom
)
995 // right/bottom border set when connected together
996 const ScMergeAttr
& rMerge
= (const ScMergeAttr
&)pPattern
->GetItem(ATTR_MERGE
);
997 if ( rMerge
.GetColMerge() == nDistRight
+ 1 )
999 if ( rMerge
.GetRowMerge() == nDistBottom
+ 1 )
1002 const SvxBoxItem
* pCellFrame
= (SvxBoxItem
*) &pPattern
->GetItemSet().Get( ATTR_BORDER
);
1003 const SvxBorderLine
* pLeftAttr
= pCellFrame
->GetLeft();
1004 const SvxBorderLine
* pRightAttr
= pCellFrame
->GetRight();
1005 const SvxBorderLine
* pTopAttr
= pCellFrame
->GetTop();
1006 const SvxBorderLine
* pBottomAttr
= pCellFrame
->GetBottom();
1007 const SvxBorderLine
* pNew
;
1011 if (lcl_TestAttr( pLineOuter
->GetTop(), pTopAttr
, rFlags
.nTop
, pNew
))
1012 pLineOuter
->SetLine( pNew
, BOX_LINE_TOP
);
1016 if (lcl_TestAttr( pLineInner
->GetHori(), pTopAttr
, rFlags
.nHori
, pNew
))
1017 pLineInner
->SetLine( pNew
, BOXINFO_LINE_HORI
);
1020 if (nDistBottom
== 0)
1022 if (lcl_TestAttr( pLineOuter
->GetBottom(), pBottomAttr
, rFlags
.nBottom
, pNew
))
1023 pLineOuter
->SetLine( pNew
, BOX_LINE_BOTTOM
);
1027 if (lcl_TestAttr( pLineInner
->GetHori(), pBottomAttr
, rFlags
.nHori
, pNew
))
1028 pLineInner
->SetLine( pNew
, BOXINFO_LINE_HORI
);
1033 if (lcl_TestAttr( pLineOuter
->GetLeft(), pLeftAttr
, rFlags
.nLeft
, pNew
))
1034 pLineOuter
->SetLine( pNew
, BOX_LINE_LEFT
);
1038 if (lcl_TestAttr( pLineInner
->GetVert(), pLeftAttr
, rFlags
.nVert
, pNew
))
1039 pLineInner
->SetLine( pNew
, BOXINFO_LINE_VERT
);
1042 if (nDistRight
== 0)
1044 if (lcl_TestAttr( pLineOuter
->GetRight(), pRightAttr
, rFlags
.nRight
, pNew
))
1045 pLineOuter
->SetLine( pNew
, BOX_LINE_RIGHT
);
1049 if (lcl_TestAttr( pLineInner
->GetVert(), pRightAttr
, rFlags
.nVert
, pNew
))
1050 pLineInner
->SetLine( pNew
, BOXINFO_LINE_VERT
);
1055 void ScAttrArray::MergeBlockFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
1056 ScLineFlags
& rFlags
,
1057 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
) const
1059 const ScPatternAttr
* pPattern
;
1061 if (nStartRow
== nEndRow
)
1063 pPattern
= GetPattern( nStartRow
);
1064 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, true, 0 );
1068 pPattern
= GetPattern( nStartRow
);
1069 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, true,
1070 nEndRow
-nStartRow
);
1074 Search( nStartRow
+1, nStartIndex
);
1075 Search( nEndRow
-1, nEndIndex
);
1076 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
; i
++)
1078 pPattern
= (ScPatternAttr
*) pData
[i
].pPattern
;
1079 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, false,
1080 nEndRow
- std::min( pData
[i
].nRow
, (SCROW
)(nEndRow
-1) ) );
1081 // nDistBottom here always > 0
1084 pPattern
= GetPattern( nEndRow
);
1085 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, false, 0 );
1093 // ApplyFrame - on an entry into the array
1095 bool ScAttrArray::ApplyFrame( const SvxBoxItem
* pBoxItem
,
1096 const SvxBoxInfoItem
* pBoxInfoItem
,
1097 SCROW nStartRow
, SCROW nEndRow
,
1098 bool bLeft
, SCCOL nDistRight
, bool bTop
, SCROW nDistBottom
)
1100 OSL_ENSURE( pBoxItem
&& pBoxInfoItem
, "Missing line attributes!" );
1102 const ScPatternAttr
* pPattern
= GetPattern( nStartRow
);
1103 const SvxBoxItem
* pOldFrame
= (const SvxBoxItem
*)
1104 &pPattern
->GetItemSet().Get( ATTR_BORDER
);
1106 // right/bottom border set when connected together
1107 const ScMergeAttr
& rMerge
= (const ScMergeAttr
&)pPattern
->GetItem(ATTR_MERGE
);
1108 if ( rMerge
.GetColMerge() == nDistRight
+ 1 )
1110 if ( rMerge
.GetRowMerge() == nDistBottom
+ 1 )
1113 SvxBoxItem
aNewFrame( *pOldFrame
);
1114 bool bRTL
=pDocument
->IsLayoutRTL(nTab
);
1115 // fdo#37464 check if the sheet are RTL then replace right <=> left
1118 if( bLeft
&& nDistRight
==0)
1120 if ( bLeft
? pBoxInfoItem
->IsValid(VALID_LEFT
) : pBoxInfoItem
->IsValid(VALID_VERT
) )
1121 aNewFrame
.SetLine( bLeft
? pBoxItem
->GetLeft() : pBoxInfoItem
->GetVert(),
1123 if ( (nDistRight
==0) ? pBoxInfoItem
->IsValid(VALID_RIGHT
) : pBoxInfoItem
->IsValid(VALID_VERT
) )
1124 aNewFrame
.SetLine( (nDistRight
==0) ? pBoxItem
->GetRight() : pBoxInfoItem
->GetVert(),
1129 if ( (nDistRight
==0) ? pBoxInfoItem
->IsValid(VALID_LEFT
) : pBoxInfoItem
->IsValid(VALID_VERT
) )
1130 aNewFrame
.SetLine( (nDistRight
==0) ? pBoxItem
->GetLeft() : pBoxInfoItem
->GetVert(),
1132 if ( bLeft
? pBoxInfoItem
->IsValid(VALID_RIGHT
) : pBoxInfoItem
->IsValid(VALID_VERT
) )
1133 aNewFrame
.SetLine( bLeft
? pBoxItem
->GetRight() : pBoxInfoItem
->GetVert(),
1139 if ( bLeft
? pBoxInfoItem
->IsValid(VALID_LEFT
) : pBoxInfoItem
->IsValid(VALID_VERT
) )
1140 aNewFrame
.SetLine( bLeft
? pBoxItem
->GetLeft() : pBoxInfoItem
->GetVert(),
1142 if ( (nDistRight
==0) ? pBoxInfoItem
->IsValid(VALID_RIGHT
) : pBoxInfoItem
->IsValid(VALID_VERT
) )
1143 aNewFrame
.SetLine( (nDistRight
==0) ? pBoxItem
->GetRight() : pBoxInfoItem
->GetVert(),
1146 if ( bTop
? pBoxInfoItem
->IsValid(VALID_TOP
) : pBoxInfoItem
->IsValid(VALID_HORI
) )
1147 aNewFrame
.SetLine( bTop
? pBoxItem
->GetTop() : pBoxInfoItem
->GetHori(),
1149 if ( (nDistBottom
==0) ? pBoxInfoItem
->IsValid(VALID_BOTTOM
) : pBoxInfoItem
->IsValid(VALID_HORI
) )
1150 aNewFrame
.SetLine( (nDistBottom
==0) ? pBoxItem
->GetBottom() : pBoxInfoItem
->GetHori(),
1153 if (aNewFrame
== *pOldFrame
)
1160 SfxItemPoolCache
aCache( pDocument
->GetPool(), &aNewFrame
);
1161 ApplyCacheArea( nStartRow
, nEndRow
, &aCache
);
1168 void ScAttrArray::ApplyBlockFrame( const SvxBoxItem
* pLineOuter
, const SvxBoxInfoItem
* pLineInner
,
1169 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
)
1171 if (nStartRow
== nEndRow
)
1172 ApplyFrame( pLineOuter
, pLineInner
, nStartRow
, nEndRow
, bLeft
, nDistRight
, true, 0 );
1175 ApplyFrame( pLineOuter
, pLineInner
, nStartRow
, nStartRow
, bLeft
, nDistRight
,
1176 true, nEndRow
-nStartRow
);
1178 if ( nEndRow
> nStartRow
+1 ) // inner part available?
1182 Search( nStartRow
+1, nStartIndex
);
1183 Search( nEndRow
-1, nEndIndex
);
1184 SCROW nTmpStart
= nStartRow
+1;
1186 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
;)
1188 nTmpEnd
= std::min( (SCROW
)(nEndRow
-1), (SCROW
)(pData
[i
].nRow
) );
1189 bool bChanged
= ApplyFrame( pLineOuter
, pLineInner
, nTmpStart
, nTmpEnd
,
1190 bLeft
, nDistRight
, false, nEndRow
-nTmpEnd
);
1191 nTmpStart
= nTmpEnd
+1;
1194 Search(nTmpStart
, i
);
1195 Search(nEndRow
-1, nEndIndex
);
1202 ApplyFrame( pLineOuter
, pLineInner
, nEndRow
, nEndRow
, bLeft
, nDistRight
, false, 0 );
1206 // Test if field contains specific attribute
1208 bool ScAttrArray::HasAttrib( SCROW nRow1
, SCROW nRow2
, sal_uInt16 nMask
) const
1212 Search( nRow1
, nStartIndex
);
1213 Search( nRow2
, nEndIndex
);
1214 bool bFound
= false;
1216 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
&& !bFound
; i
++)
1218 const ScPatternAttr
* pPattern
= pData
[i
].pPattern
;
1219 if ( nMask
& HASATTR_MERGED
)
1221 const ScMergeAttr
* pMerge
=
1222 (const ScMergeAttr
*) &pPattern
->GetItem( ATTR_MERGE
);
1223 if ( pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1 )
1226 if ( nMask
& ( HASATTR_OVERLAPPED
| HASATTR_NOTOVERLAPPED
| HASATTR_AUTOFILTER
) )
1228 const ScMergeFlagAttr
* pMergeFlag
=
1229 (const ScMergeFlagAttr
*) &pPattern
->GetItem( ATTR_MERGE_FLAG
);
1230 if ( (nMask
& HASATTR_OVERLAPPED
) && pMergeFlag
->IsOverlapped() )
1232 if ( (nMask
& HASATTR_NOTOVERLAPPED
) && !pMergeFlag
->IsOverlapped() )
1234 if ( (nMask
& HASATTR_AUTOFILTER
) && pMergeFlag
->HasAutoFilter() )
1237 if ( nMask
& HASATTR_LINES
)
1239 const SvxBoxItem
* pBox
=
1240 (const SvxBoxItem
*) &pPattern
->GetItem( ATTR_BORDER
);
1241 if ( pBox
->GetLeft() || pBox
->GetRight() || pBox
->GetTop() || pBox
->GetBottom() )
1244 if ( nMask
& HASATTR_SHADOW
)
1246 const SvxShadowItem
* pShadow
=
1247 (const SvxShadowItem
*) &pPattern
->GetItem( ATTR_SHADOW
);
1248 if ( pShadow
->GetLocation() != SVX_SHADOW_NONE
)
1251 if ( nMask
& HASATTR_CONDITIONAL
)
1253 bool bContainsCondFormat
=
1254 !static_cast<const ScCondFormatItem
&>(pPattern
->GetItem( ATTR_CONDITIONAL
)).GetCondFormatData().empty();
1255 if ( bContainsCondFormat
)
1258 if ( nMask
& HASATTR_PROTECTED
)
1260 const ScProtectionAttr
* pProtect
=
1261 (const ScProtectionAttr
*) &pPattern
->GetItem( ATTR_PROTECTION
);
1262 bool bFoundTemp
= false;
1263 if ( pProtect
->GetProtection() || pProtect
->GetHideCell() )
1266 bool bContainsCondFormat
=
1267 !static_cast<const ScCondFormatItem
&>(pPattern
->GetItem( ATTR_CONDITIONAL
)).GetCondFormatData().empty();
1268 if ( bContainsCondFormat
)
1270 SCROW nRowStartCond
= std::max
<SCROW
>( nRow1
, i
? pData
[i
-1].nRow
+ 1: 0 );
1271 SCROW nRowEndCond
= std::min
<SCROW
>( nRow2
, pData
[i
].nRow
);
1272 bool bFoundCond
= false;
1273 for(SCROW nRowCond
= nRowStartCond
; nRowCond
<= nRowEndCond
&& !bFoundCond
; ++nRowCond
)
1275 const SfxItemSet
* pSet
= pDocument
->GetCondResult( nCol
, nRowCond
, nTab
);
1277 const SfxPoolItem
* pItem
;
1278 if( pSet
&& pSet
->GetItemState( ATTR_PROTECTION
, true, &pItem
) == SFX_ITEM_SET
)
1280 const ScProtectionAttr
* pCondProtect
= static_cast<const ScProtectionAttr
*>(pItem
);
1281 if( pCondProtect
->GetProtection() || pCondProtect
->GetHideCell() )
1288 // well it is not true that we found one
1289 // but existing one + cell where conditional
1290 // formatting does not remove it
1291 // => we should use the existing protection settting
1292 bFoundCond
= bFoundTemp
;
1295 bFoundTemp
= bFoundCond
;
1301 if ( nMask
& HASATTR_ROTATE
)
1303 const SfxInt32Item
* pRotate
=
1304 (const SfxInt32Item
*) &pPattern
->GetItem( ATTR_ROTATE_VALUE
);
1305 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1306 // (see ScPatternAttr::GetCellOrientation)
1307 sal_Int32 nAngle
= pRotate
->GetValue();
1308 if ( nAngle
!= 0 && nAngle
!= 9000 && nAngle
!= 27000 )
1311 if ( nMask
& HASATTR_NEEDHEIGHT
)
1313 if (pPattern
->GetCellOrientation() != SVX_ORIENTATION_STANDARD
)
1315 else if (((const SfxBoolItem
&)pPattern
->GetItem( ATTR_LINEBREAK
)).GetValue())
1317 else if ((SvxCellHorJustify
)((const SvxHorJustifyItem
&)pPattern
->
1318 GetItem( ATTR_HOR_JUSTIFY
)).GetValue() == SVX_HOR_JUSTIFY_BLOCK
)
1321 else if (!static_cast<const ScCondFormatItem
&>(pPattern
->GetItem(ATTR_CONDITIONAL
)).GetCondFormatData().empty())
1323 else if (((const SfxInt32Item
&)pPattern
->GetItem( ATTR_ROTATE_VALUE
)).GetValue())
1326 if ( nMask
& ( HASATTR_SHADOW_RIGHT
| HASATTR_SHADOW_DOWN
) )
1328 const SvxShadowItem
* pShadow
=
1329 (const SvxShadowItem
*) &pPattern
->GetItem( ATTR_SHADOW
);
1330 SvxShadowLocation eLoc
= pShadow
->GetLocation();
1331 if ( nMask
& HASATTR_SHADOW_RIGHT
)
1332 if ( eLoc
== SVX_SHADOW_TOPRIGHT
|| eLoc
== SVX_SHADOW_BOTTOMRIGHT
)
1334 if ( nMask
& HASATTR_SHADOW_DOWN
)
1335 if ( eLoc
== SVX_SHADOW_BOTTOMLEFT
|| eLoc
== SVX_SHADOW_BOTTOMRIGHT
)
1338 if ( nMask
& HASATTR_RTL
)
1340 const SvxFrameDirectionItem
& rDirection
=
1341 (const SvxFrameDirectionItem
&) pPattern
->GetItem( ATTR_WRITINGDIR
);
1342 if ( rDirection
.GetValue() == FRMDIR_HORI_RIGHT_TOP
)
1345 if ( nMask
& HASATTR_RIGHTORCENTER
)
1347 // called only if the sheet is LTR, so physical=logical alignment can be assumed
1348 SvxCellHorJustify eHorJust
= (SvxCellHorJustify
)
1349 ((const SvxHorJustifyItem
&) pPattern
->GetItem( ATTR_HOR_JUSTIFY
)).GetValue();
1350 if ( eHorJust
== SVX_HOR_JUSTIFY_RIGHT
|| eHorJust
== SVX_HOR_JUSTIFY_CENTER
)
1358 // Area around any given summaries expand and adapt any MergeFlag (bRefresh)
1359 bool ScAttrArray::ExtendMerge( SCCOL nThisCol
, SCROW nStartRow
, SCROW nEndRow
,
1360 SCCOL
& rPaintCol
, SCROW
& rPaintRow
,
1363 const ScPatternAttr
* pPattern
;
1364 const ScMergeAttr
* pItem
;
1367 Search( nStartRow
, nStartIndex
);
1368 Search( nEndRow
, nEndIndex
);
1369 bool bFound
= false;
1371 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
; i
++)
1373 pPattern
= pData
[i
].pPattern
;
1374 pItem
= (const ScMergeAttr
*) &pPattern
->GetItem( ATTR_MERGE
);
1375 SCsCOL nCountX
= pItem
->GetColMerge();
1376 SCsROW nCountY
= pItem
->GetRowMerge();
1377 if (nCountX
>1 || nCountY
>1)
1379 SCROW nThisRow
= (i
>0) ? pData
[i
-1].nRow
+1 : 0;
1380 SCCOL nMergeEndCol
= nThisCol
+ nCountX
- 1;
1381 SCROW nMergeEndRow
= nThisRow
+ nCountY
- 1;
1382 if (nMergeEndCol
> rPaintCol
&& nMergeEndCol
<= MAXCOL
)
1383 rPaintCol
= nMergeEndCol
;
1384 if (nMergeEndRow
> rPaintRow
&& nMergeEndRow
<= MAXROW
)
1385 rPaintRow
= nMergeEndRow
;
1390 if ( nMergeEndCol
> nThisCol
)
1391 pDocument
->ApplyFlagsTab( nThisCol
+1, nThisRow
, nMergeEndCol
, pData
[i
].nRow
,
1393 if ( nMergeEndRow
> nThisRow
)
1394 pDocument
->ApplyFlagsTab( nThisCol
, nThisRow
+1, nThisCol
, nMergeEndRow
,
1396 if ( nMergeEndCol
> nThisCol
&& nMergeEndRow
> nThisRow
)
1397 pDocument
->ApplyFlagsTab( nThisCol
+1, nThisRow
+1, nMergeEndCol
, nMergeEndRow
,
1398 nTab
, SC_MF_HOR
| SC_MF_VER
);
1400 Search( nThisRow
, i
); // Data changed
1401 Search( nStartRow
, nStartIndex
);
1402 Search( nEndRow
, nEndIndex
);
1411 bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow
, SCROW nEndRow
)
1413 bool bFound
= false;
1414 const ScPatternAttr
* pPattern
;
1415 const ScMergeAttr
* pItem
;
1418 Search( nStartRow
, nIndex
);
1419 SCROW nThisStart
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1420 if (nThisStart
< nStartRow
)
1421 nThisStart
= nStartRow
;
1423 while ( nThisStart
<= nEndRow
)
1425 SCROW nThisEnd
= pData
[nIndex
].nRow
;
1426 if (nThisEnd
> nEndRow
)
1429 pPattern
= pData
[nIndex
].pPattern
;
1430 pItem
= (const ScMergeAttr
*) &pPattern
->GetItem( ATTR_MERGE
);
1431 SCsCOL nCountX
= pItem
->GetColMerge();
1432 SCsROW nCountY
= pItem
->GetRowMerge();
1433 if (nCountX
>1 || nCountY
>1)
1435 const ScMergeAttr
* pAttr
= (const ScMergeAttr
*)
1436 &pDocument
->GetPool()->GetDefaultItem( ATTR_MERGE
);
1437 const ScMergeFlagAttr
* pFlagAttr
= (const ScMergeFlagAttr
*)
1438 &pDocument
->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG
);
1440 OSL_ENSURE( nCountY
==1 || nThisStart
==nThisEnd
, "What's up?" );
1442 SCCOL nThisCol
= nCol
;
1443 SCCOL nMergeEndCol
= nThisCol
+ nCountX
- 1;
1444 SCROW nMergeEndRow
= nThisEnd
+ nCountY
- 1;
1446 // ApplyAttr for areas
1448 for (SCROW nThisRow
= nThisStart
; nThisRow
<= nThisEnd
; nThisRow
++)
1449 pDocument
->ApplyAttr( nThisCol
, nThisRow
, nTab
, *pAttr
);
1451 ScPatternAttr
* pNewPattern
= new ScPatternAttr( pDocument
->GetPool() );
1452 SfxItemSet
* pSet
= &pNewPattern
->GetItemSet();
1453 pSet
->Put( *pFlagAttr
);
1454 pDocument
->ApplyPatternAreaTab( nThisCol
, nThisStart
, nMergeEndCol
, nMergeEndRow
,
1455 nTab
, *pNewPattern
);
1458 Search( nThisEnd
, nIndex
); // data changed
1462 if ( nIndex
< nCount
)
1463 nThisStart
= pData
[nIndex
-1].nRow
+1;
1465 nThisStart
= MAXROW
+1; // End
1471 // Remove field, but leave MergeFlags
1473 void ScAttrArray::DeleteAreaSafe(SCROW nStartRow
, SCROW nEndRow
)
1475 SetPatternAreaSafe( nStartRow
, nEndRow
, pDocument
->GetDefPattern(), true );
1479 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow
, SCROW nEndRow
,
1480 const ScPatternAttr
* pWantedPattern
, bool bDefault
)
1482 const ScPatternAttr
* pOldPattern
;
1483 const ScMergeFlagAttr
* pItem
;
1488 bool bFirstUse
= true;
1490 Search( nStartRow
, nIndex
);
1491 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1492 while ( nThisRow
<= nEndRow
)
1494 pOldPattern
= pData
[nIndex
].pPattern
;
1495 if (pOldPattern
!= pWantedPattern
) //! else-Zweig ?
1497 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1498 nRow
= pData
[nIndex
].nRow
;
1499 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
1500 pItem
= (const ScMergeFlagAttr
*) &pOldPattern
->GetItem( ATTR_MERGE_FLAG
);
1502 if (pItem
->IsOverlapped() || pItem
->HasAutoFilter())
1504 // default-constructing a ScPatternAttr for DeleteArea doesn't work
1505 // because it would have no cell style information.
1506 // Instead, the document's GetDefPattern is copied. Since it is passed as
1507 // pWantedPattern, no special treatment of default is needed here anymore.
1508 ScPatternAttr
* pNewPattern
= new ScPatternAttr( *pWantedPattern
);
1509 SfxItemSet
* pSet
= &pNewPattern
->GetItemSet();
1510 pSet
->Put( *pItem
);
1511 SetPatternArea( nThisRow
, nAttrRow
, pNewPattern
, true );
1522 pDocument
->GetPool()->Put( *pWantedPattern
);
1524 SetPatternArea( nThisRow
, nAttrRow
, pWantedPattern
);
1527 Search( nThisRow
, nIndex
); // data changed
1531 nThisRow
= pData
[nIndex
-1].nRow
+1;
1536 bool ScAttrArray::ApplyFlags( SCROW nStartRow
, SCROW nEndRow
, sal_Int16 nFlags
)
1538 const ScPatternAttr
* pOldPattern
;
1540 sal_Int16 nOldValue
;
1544 bool bChanged
= false;
1546 Search( nStartRow
, nIndex
);
1547 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1548 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1550 while ( nThisRow
<= nEndRow
)
1552 pOldPattern
= pData
[nIndex
].pPattern
;
1553 nOldValue
= ((const ScMergeFlagAttr
*) &pOldPattern
->GetItem( ATTR_MERGE_FLAG
))->GetValue();
1554 if ( (nOldValue
| nFlags
) != nOldValue
)
1556 nRow
= pData
[nIndex
].nRow
;
1557 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
1558 ScPatternAttr
aNewPattern(*pOldPattern
);
1559 aNewPattern
.GetItemSet().Put( ScMergeFlagAttr( nOldValue
| nFlags
) );
1560 SetPatternArea( nThisRow
, nAttrRow
, &aNewPattern
, true );
1561 Search( nThisRow
, nIndex
); // data changed
1566 nThisRow
= pData
[nIndex
-1].nRow
+1;
1573 bool ScAttrArray::RemoveFlags( SCROW nStartRow
, SCROW nEndRow
, sal_Int16 nFlags
)
1575 const ScPatternAttr
* pOldPattern
;
1577 sal_Int16 nOldValue
;
1581 bool bChanged
= false;
1583 Search( nStartRow
, nIndex
);
1584 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1585 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1587 while ( nThisRow
<= nEndRow
)
1589 pOldPattern
= pData
[nIndex
].pPattern
;
1590 nOldValue
= ((const ScMergeFlagAttr
*) &pOldPattern
->GetItem( ATTR_MERGE_FLAG
))->GetValue();
1591 if ( (nOldValue
& ~nFlags
) != nOldValue
)
1593 nRow
= pData
[nIndex
].nRow
;
1594 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
1595 ScPatternAttr
aNewPattern(*pOldPattern
);
1596 aNewPattern
.GetItemSet().Put( ScMergeFlagAttr( nOldValue
& ~nFlags
) );
1597 SetPatternArea( nThisRow
, nAttrRow
, &aNewPattern
, true );
1598 Search( nThisRow
, nIndex
); // data changed
1603 nThisRow
= pData
[nIndex
-1].nRow
+1;
1610 void ScAttrArray::ClearItems( SCROW nStartRow
, SCROW nEndRow
, const sal_uInt16
* pWhich
)
1612 const ScPatternAttr
* pOldPattern
;
1618 Search( nStartRow
, nIndex
);
1619 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1620 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1622 while ( nThisRow
<= nEndRow
)
1624 pOldPattern
= pData
[nIndex
].pPattern
;
1625 if ( pOldPattern
->HasItemsSet( pWhich
) )
1627 ScPatternAttr
aNewPattern(*pOldPattern
);
1628 aNewPattern
.ClearItems( pWhich
);
1630 nRow
= pData
[nIndex
].nRow
;
1631 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
1632 SetPatternArea( nThisRow
, nAttrRow
, &aNewPattern
, true );
1633 Search( nThisRow
, nIndex
); // data changed
1637 nThisRow
= pData
[nIndex
-1].nRow
+1;
1642 void ScAttrArray::ChangeIndent( SCROW nStartRow
, SCROW nEndRow
, bool bIncrement
)
1645 Search( nStartRow
, nIndex
);
1646 SCROW nThisStart
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1647 if (nThisStart
< nStartRow
) nThisStart
= nStartRow
;
1649 while ( nThisStart
<= nEndRow
)
1651 const ScPatternAttr
* pOldPattern
= pData
[nIndex
].pPattern
;
1652 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
1653 const SfxPoolItem
* pItem
;
1655 bool bNeedJust
= ( rOldSet
.GetItemState( ATTR_HOR_JUSTIFY
, false, &pItem
) != SFX_ITEM_SET
1656 || (((const SvxHorJustifyItem
*)pItem
)->GetValue() != SVX_HOR_JUSTIFY_LEFT
&&
1657 ((const SvxHorJustifyItem
*)pItem
)->GetValue() != SVX_HOR_JUSTIFY_RIGHT
));
1658 sal_uInt16 nOldValue
= ((const SfxUInt16Item
&)rOldSet
.Get( ATTR_INDENT
)).GetValue();
1659 sal_uInt16 nNewValue
= nOldValue
;
1660 //to keep Increment indent from running outside the cell1659
1661 long nColWidth
= (long)pDocument
->GetColWidth(nCol
,nTab
);
1664 if ( nNewValue
< nColWidth
-SC_INDENT_STEP
)
1666 nNewValue
+= SC_INDENT_STEP
;
1667 if ( nNewValue
> nColWidth
-SC_INDENT_STEP
) nNewValue
= nColWidth
-SC_INDENT_STEP
;
1672 if ( nNewValue
> 0 )
1674 if ( nNewValue
> SC_INDENT_STEP
)
1675 nNewValue
-= SC_INDENT_STEP
;
1681 if ( bNeedJust
|| nNewValue
!= nOldValue
)
1683 SCROW nThisEnd
= pData
[nIndex
].nRow
;
1684 SCROW nAttrRow
= std::min( nThisEnd
, nEndRow
);
1685 ScPatternAttr
aNewPattern(*pOldPattern
);
1686 aNewPattern
.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT
, nNewValue
) );
1688 aNewPattern
.GetItemSet().Put(
1689 SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT
, ATTR_HOR_JUSTIFY
) );
1690 SetPatternArea( nThisStart
, nAttrRow
, &aNewPattern
, true );
1692 nThisStart
= nThisEnd
+ 1;
1693 Search( nThisStart
, nIndex
); // data changed
1697 nThisStart
= pData
[nIndex
].nRow
+ 1;
1704 SCsROW
ScAttrArray::GetNextUnprotected( SCsROW nRow
, bool bUp
) const
1710 Search(nRow
, nIndex
);
1711 while (((const ScProtectionAttr
&)pData
[nIndex
].pPattern
->
1712 GetItem(ATTR_PROTECTION
)).GetProtection())
1717 return -1; // not found
1719 nRet
= pData
[nIndex
].nRow
;
1723 nRet
= pData
[nIndex
].nRow
+1;
1726 return MAXROW
+1; // not found
1733 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase
* pStyleSheet
, ScFlatBoolRowSegments
& rUsedRows
, bool bReset
)
1737 while (nPos
< nCount
)
1739 SCROW nEnd
= pData
[nPos
].nRow
;
1740 if (pData
[nPos
].pPattern
->GetStyleSheet() == pStyleSheet
)
1742 rUsedRows
.setTrue(nStart
, nEnd
);
1746 ScPatternAttr
* pNewPattern
= new ScPatternAttr(*pData
[nPos
].pPattern
);
1747 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
1748 pNewPattern
->SetStyleSheet( (ScStyleSheet
*)
1749 pDocument
->GetStyleSheetPool()->
1750 Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD
),
1751 SFX_STYLE_FAMILY_PARA
,
1752 SFXSTYLEBIT_AUTO
| SCSTYLEBIT_STANDARD
) );
1753 pData
[nPos
].pPattern
= (const ScPatternAttr
*)
1754 &pDocument
->GetPool()->Put(*pNewPattern
);
1759 Search(nStart
, nPos
);
1760 --nPos
; // because ++ at end
1770 bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet
& rStyle
,
1771 bool bGatherAllStyles
) const
1773 bool bIsUsed
= false;
1776 while ( nPos
< nCount
)
1778 const ScStyleSheet
* pStyle
= pData
[nPos
].pPattern
->GetStyleSheet();
1781 pStyle
->SetUsage( ScStyleSheet::USED
);
1782 if ( pStyle
== &rStyle
)
1784 if ( !bGatherAllStyles
)
1796 bool ScAttrArray::IsEmpty() const
1800 if ( pData
[0].pPattern
!= pDocument
->GetDefPattern() )
1810 bool ScAttrArray::GetFirstVisibleAttr( SCROW
& rFirstRow
) const
1812 OSL_ENSURE( nCount
, "nCount == 0" );
1814 bool bFound
= false;
1817 // Skip first entry if more than 1 row.
1818 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1820 SCSIZE nVisStart
= 1;
1821 while ( nVisStart
< nCount
&& pData
[nVisStart
].pPattern
->IsVisibleEqual(*pData
[nVisStart
-1].pPattern
) )
1823 if ( nVisStart
>= nCount
|| pData
[nVisStart
-1].nRow
> 0 ) // more than 1 row?
1826 while ( nStart
< nCount
&& !bFound
)
1828 if ( pData
[nStart
].pPattern
->IsVisible() )
1830 rFirstRow
= nStart
? ( pData
[nStart
-1].nRow
+ 1 ) : 0;
1840 // size (rows) of a range of attributes after cell content where the search is stopped
1841 // (more than a default page size, 2*42 because it's as good as any number)
1843 const SCROW SC_VISATTR_STOP
= 84;
1845 bool ScAttrArray::GetLastVisibleAttr( SCROW
& rLastRow
, SCROW nLastData
, bool bFullFormattedArea
) const
1847 OSL_ENSURE( nCount
, "nCount == 0" );
1849 // #i30830# changed behavior:
1850 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1851 // below the last content cell
1853 if ( nLastData
== MAXROW
)
1855 rLastRow
= MAXROW
; // can't look for attributes below MAXROW
1859 // Quick check: last data row in or immediately preceding a run that is the
1860 // last attribution down to the end, e.g. default style or column style.
1861 SCSIZE nPos
= nCount
- 1;
1862 SCROW nStartRow
= (nPos
? pData
[nPos
-1].nRow
+ 1 : 0);
1863 if (nStartRow
<= nLastData
+ 1)
1865 if (bFullFormattedArea
&& pData
[nPos
].pPattern
->IsVisible())
1867 rLastRow
= pData
[nPos
].nRow
;
1872 // Ignore here a few rows if data happens to end within
1873 // SC_VISATTR_STOP rows before MAXROW.
1874 rLastRow
= nLastData
;
1879 // Find a run below last data row.
1880 bool bFound
= false;
1881 Search( nLastData
, nPos
);
1882 while ( nPos
< nCount
)
1884 // find range of visually equal formats
1885 SCSIZE nEndPos
= nPos
;
1886 while ( nEndPos
< nCount
-1 &&
1887 pData
[nEndPos
].pPattern
->IsVisibleEqual( *pData
[nEndPos
+1].pPattern
))
1889 SCROW nAttrStartRow
= ( nPos
> 0 ) ? ( pData
[nPos
-1].nRow
+ 1 ) : 0;
1890 if ( nAttrStartRow
<= nLastData
)
1891 nAttrStartRow
= nLastData
+ 1;
1892 SCROW nAttrSize
= pData
[nEndPos
].nRow
+ 1 - nAttrStartRow
;
1893 if ( nAttrSize
>= SC_VISATTR_STOP
&& !bFullFormattedArea
)
1894 break; // while, ignore this range and below
1895 else if ( pData
[nEndPos
].pPattern
->IsVisible() )
1897 rLastRow
= pData
[nEndPos
].nRow
;
1907 bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow
, SCROW nEndRow
) const
1910 Search( nStartRow
, nIndex
);
1911 SCROW nThisStart
= nStartRow
;
1912 bool bFound
= false;
1913 while ( nIndex
< nCount
&& nThisStart
<= nEndRow
&& !bFound
)
1915 if ( pData
[nIndex
].pPattern
->IsVisible() )
1918 nThisStart
= pData
[nIndex
].nRow
+ 1;
1926 bool ScAttrArray::IsVisibleEqual( const ScAttrArray
& rOther
,
1927 SCROW nStartRow
, SCROW nEndRow
) const
1930 SCSIZE nThisPos
= 0;
1931 SCSIZE nOtherPos
= 0;
1932 if ( nStartRow
> 0 )
1934 Search( nStartRow
, nThisPos
);
1935 rOther
.Search( nStartRow
, nOtherPos
);
1938 while ( nThisPos
<nCount
&& nOtherPos
<rOther
.nCount
&& bEqual
)
1940 SCROW nThisRow
= pData
[nThisPos
].nRow
;
1941 SCROW nOtherRow
= rOther
.pData
[nOtherPos
].nRow
;
1942 const ScPatternAttr
* pThisPattern
= pData
[nThisPos
].pPattern
;
1943 const ScPatternAttr
* pOtherPattern
= rOther
.pData
[nOtherPos
].pPattern
;
1944 bEqual
= ( pThisPattern
== pOtherPattern
||
1945 pThisPattern
->IsVisibleEqual(*pOtherPattern
) );
1947 if ( nThisRow
>= nOtherRow
)
1949 if ( nOtherRow
>= nEndRow
) break;
1952 if ( nThisRow
<= nOtherRow
)
1954 if ( nThisRow
>= nEndRow
) break;
1963 bool ScAttrArray::IsAllEqual( const ScAttrArray
& rOther
, SCROW nStartRow
, SCROW nEndRow
) const
1965 // summarised with IsVisibleEqual
1968 SCSIZE nThisPos
= 0;
1969 SCSIZE nOtherPos
= 0;
1970 if ( nStartRow
> 0 )
1972 Search( nStartRow
, nThisPos
);
1973 rOther
.Search( nStartRow
, nOtherPos
);
1976 while ( nThisPos
<nCount
&& nOtherPos
<rOther
.nCount
&& bEqual
)
1978 SCROW nThisRow
= pData
[nThisPos
].nRow
;
1979 SCROW nOtherRow
= rOther
.pData
[nOtherPos
].nRow
;
1980 const ScPatternAttr
* pThisPattern
= pData
[nThisPos
].pPattern
;
1981 const ScPatternAttr
* pOtherPattern
= rOther
.pData
[nOtherPos
].pPattern
;
1982 bEqual
= ( pThisPattern
== pOtherPattern
);
1984 if ( nThisRow
>= nOtherRow
)
1986 if ( nOtherRow
>= nEndRow
) break;
1989 if ( nThisRow
<= nOtherRow
)
1991 if ( nThisRow
>= nEndRow
) break;
2000 bool ScAttrArray::TestInsertCol( SCROW nStartRow
, SCROW nEndRow
) const
2002 // Horizontal aggregate are not allowed to be moved out; if whole summary,
2003 // here is not recognized
2009 if ( nStartRow
> 0 )
2010 Search( nStartRow
, nIndex
);
2012 for ( ; nIndex
< nCount
; nIndex
++ )
2014 if ( ((const ScMergeFlagAttr
&)pData
[nIndex
].pPattern
->
2015 GetItem(ATTR_MERGE_FLAG
)).IsHorOverlapped() )
2017 bTest
= false; // may not be pushed out
2020 if ( pData
[nIndex
].nRow
>= nEndRow
) // end of range
2028 bool ScAttrArray::TestInsertRow( SCSIZE nSize
) const
2030 // if 1st row pushed out is vertically overlapped, summary would be broken
2032 // MAXROW + 1 - nSize = 1st row pushed out
2034 SCSIZE nFirstLost
= nCount
-1;
2035 while ( nFirstLost
&& pData
[nFirstLost
-1].nRow
>= sal::static_int_cast
<SCROW
>(MAXROW
+ 1 - nSize
) )
2038 if ( ((const ScMergeFlagAttr
&)pData
[nFirstLost
].pPattern
->
2039 GetItem(ATTR_MERGE_FLAG
)).IsVerOverlapped() )
2046 void ScAttrArray::InsertRow( SCROW nStartRow
, SCSIZE nSize
)
2051 SCROW nSearch
= nStartRow
> 0 ? nStartRow
- 1 : 0; // expand predecessor
2053 Search( nSearch
, nIndex
);
2055 // set ScMergeAttr may not be extended (so behind delete again)
2057 bool bDoMerge
= ((const ScMergeAttr
&) pData
[nIndex
].pPattern
->GetItem(ATTR_MERGE
)).IsMerged();
2061 for (i
= nIndex
; i
< nCount
-1; i
++)
2063 SCROW nNew
= pData
[i
].nRow
+ nSize
;
2064 if ( nNew
>= MAXROW
) // at end?
2068 nRemove
= i
+1; // remove the following?
2070 pData
[i
].nRow
= nNew
;
2073 // Remove entries at end ?
2075 if (nRemove
&& nRemove
< nCount
)
2076 DeleteRange( nRemove
, nCount
-1 );
2078 if (bDoMerge
) // extensively repair (again) ScMergeAttr
2080 // ApplyAttr for areas
2082 const SfxPoolItem
& rDef
= pDocument
->GetPool()->GetDefaultItem( ATTR_MERGE
);
2083 for (SCSIZE nAdd
=0; nAdd
<nSize
; nAdd
++)
2084 pDocument
->ApplyAttr( nCol
, nStartRow
+nAdd
, nTab
, rDef
);
2086 // reply inserts in this area not summarized
2089 // Don't duplicate the merge flags in the inserted row.
2090 // #i108488# SC_MF_SCENARIO has to be allowed.
2091 RemoveFlags( nStartRow
, nStartRow
+nSize
-1, SC_MF_HOR
| SC_MF_VER
| SC_MF_AUTO
| SC_MF_BUTTON
);
2095 void ScAttrArray::DeleteRow( SCROW nStartRow
, SCSIZE nSize
)
2098 SCSIZE nStartIndex
= 0;
2099 SCSIZE nEndIndex
= 0;
2102 for ( i
= 0; i
< nCount
-1; i
++)
2103 if (pData
[i
].nRow
>= nStartRow
&& pData
[i
].nRow
<= sal::static_int_cast
<SCROW
>(nStartRow
+nSize
-1))
2118 nStart
= pData
[nStartIndex
-1].nRow
+ 1;
2120 if (nStart
< nStartRow
)
2122 pData
[nStartIndex
].nRow
= nStartRow
- 1;
2125 if (nEndIndex
>= nStartIndex
)
2127 DeleteRange( nStartIndex
, nEndIndex
);
2128 if (nStartIndex
> 0)
2129 if ( pData
[nStartIndex
-1].pPattern
== pData
[nStartIndex
].pPattern
)
2130 DeleteRange( nStartIndex
-1, nStartIndex
-1 );
2133 for (i
= 0; i
< nCount
-1; i
++)
2134 if (pData
[i
].nRow
>= nStartRow
)
2135 pData
[i
].nRow
-= nSize
;
2137 // Below does not follow the pattern to detect pressure ranges;
2138 // instead, only remove merge flags.
2139 RemoveFlags( MAXROW
-nSize
+1, MAXROW
, SC_MF_HOR
| SC_MF_VER
| SC_MF_AUTO
);
2143 void ScAttrArray::DeleteRange( SCSIZE nStartIndex
, SCSIZE nEndIndex
)
2145 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
2146 for (SCSIZE i
= nStartIndex
; i
<= nEndIndex
; i
++)
2147 pDocPool
->Remove(*pData
[i
].pPattern
);
2149 memmove( &pData
[nStartIndex
], &pData
[nEndIndex
+ 1], (nCount
- nEndIndex
- 1) * sizeof(ScAttrEntry
) );
2150 nCount
-= nEndIndex
-nStartIndex
+1;
2154 void ScAttrArray::DeleteArea(SCROW nStartRow
, SCROW nEndRow
)
2156 RemoveAreaMerge( nStartRow
, nEndRow
); // remove from combined flags
2158 if ( !HasAttrib( nStartRow
, nEndRow
, HASATTR_OVERLAPPED
| HASATTR_AUTOFILTER
) )
2159 SetPatternArea( nStartRow
, nEndRow
, pDocument
->GetDefPattern() );
2161 DeleteAreaSafe( nStartRow
, nEndRow
); // leave merge flags
2165 void ScAttrArray::DeleteHardAttr(SCROW nStartRow
, SCROW nEndRow
)
2167 const ScPatternAttr
* pDefPattern
= pDocument
->GetDefPattern();
2168 const ScPatternAttr
* pOldPattern
;
2174 Search( nStartRow
, nIndex
);
2175 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
2176 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
2178 while ( nThisRow
<= nEndRow
)
2180 pOldPattern
= pData
[nIndex
].pPattern
;
2182 if ( pOldPattern
->GetItemSet().Count() ) // hard attributes ?
2184 nRow
= pData
[nIndex
].nRow
;
2185 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
2187 ScPatternAttr
aNewPattern(*pOldPattern
);
2188 SfxItemSet
& rSet
= aNewPattern
.GetItemSet();
2189 for (sal_uInt16 nId
= ATTR_PATTERN_START
; nId
<= ATTR_PATTERN_END
; nId
++)
2190 if (nId
!= ATTR_MERGE
&& nId
!= ATTR_MERGE_FLAG
)
2191 rSet
.ClearItem(nId
);
2193 if ( aNewPattern
== *pDefPattern
)
2194 SetPatternArea( nThisRow
, nAttrRow
, pDefPattern
, false );
2196 SetPatternArea( nThisRow
, nAttrRow
, &aNewPattern
, true );
2198 Search( nThisRow
, nIndex
); // data changed
2202 nThisRow
= pData
[nIndex
-1].nRow
+1;
2207 // move within a document
2209 void ScAttrArray::MoveTo(SCROW nStartRow
, SCROW nEndRow
, ScAttrArray
& rAttrArray
)
2211 SCROW nStart
= nStartRow
;
2212 for (SCSIZE i
= 0; i
< nCount
; i
++)
2214 if ((pData
[i
].nRow
>= nStartRow
) && ((i
==0) ? true : pData
[i
-1].nRow
< nEndRow
))
2216 // copy (bPutToPool=TRUE)
2217 rAttrArray
.SetPatternArea( nStart
, std::min( (SCROW
)pData
[i
].nRow
, (SCROW
)nEndRow
),
2218 pData
[i
].pPattern
, true );
2220 nStart
= std::max( (SCROW
)nStart
, (SCROW
)(pData
[i
].nRow
+ 1) );
2222 DeleteArea(nStartRow
, nEndRow
);
2226 // copy between documents (Clipboard)
2228 void ScAttrArray::CopyArea(
2229 SCROW nStartRow
, SCROW nEndRow
, long nDy
, ScAttrArray
& rAttrArray
, sal_Int16 nStripFlags
) const
2231 nStartRow
-= nDy
; // Source
2234 SCROW nDestStart
= std::max((long)((long)nStartRow
+ nDy
), (long) 0);
2235 SCROW nDestEnd
= std::min((long)((long)nEndRow
+ nDy
), (long) MAXROW
);
2237 ScDocumentPool
* pSourceDocPool
= pDocument
->GetPool();
2238 ScDocumentPool
* pDestDocPool
= rAttrArray
.pDocument
->GetPool();
2239 bool bSamePool
= (pSourceDocPool
==pDestDocPool
);
2241 for (SCSIZE i
= 0; (i
< nCount
) && (nDestStart
<= nDestEnd
); i
++)
2243 if (pData
[i
].nRow
>= nStartRow
)
2245 const ScPatternAttr
* pOldPattern
= pData
[i
].pPattern
;
2246 const ScPatternAttr
* pNewPattern
;
2248 if (IsDefaultItem( pOldPattern
))
2250 // default: nothing changed
2252 pNewPattern
= (const ScPatternAttr
*)
2253 &pDestDocPool
->GetDefaultItem( ATTR_PATTERN
);
2255 else if ( nStripFlags
)
2257 ScPatternAttr
* pTmpPattern
= new ScPatternAttr( *pOldPattern
);
2258 sal_Int16 nNewFlags
= 0;
2259 if ( nStripFlags
!= SC_MF_ALL
)
2260 nNewFlags
= ((const ScMergeFlagAttr
&)pTmpPattern
->GetItem(ATTR_MERGE_FLAG
)).
2261 GetValue() & ~nStripFlags
;
2264 pTmpPattern
->GetItemSet().Put( ScMergeFlagAttr( nNewFlags
) );
2266 pTmpPattern
->GetItemSet().ClearItem( ATTR_MERGE_FLAG
);
2269 pNewPattern
= (ScPatternAttr
*) &pDestDocPool
->Put(*pTmpPattern
);
2271 pNewPattern
= pTmpPattern
->PutInPool( rAttrArray
.pDocument
, pDocument
);
2277 pNewPattern
= (ScPatternAttr
*) &pDestDocPool
->Put(*pOldPattern
);
2279 pNewPattern
= pOldPattern
->PutInPool( rAttrArray
.pDocument
, pDocument
);
2282 rAttrArray
.SetPatternArea(nDestStart
,
2283 std::min((SCROW
)(pData
[i
].nRow
+ nDy
), nDestEnd
), pNewPattern
);
2286 // when pasting from clipboard and skipping filtered rows, the adjusted
2287 // end position can be negative
2288 nDestStart
= std::max((long)nDestStart
, (long)(pData
[i
].nRow
+ nDy
+ 1));
2294 // summarized with CopyArea
2296 void ScAttrArray::CopyAreaSafe( SCROW nStartRow
, SCROW nEndRow
, long nDy
, ScAttrArray
& rAttrArray
)
2298 nStartRow
-= nDy
; // Source
2301 SCROW nDestStart
= std::max((long)((long)nStartRow
+ nDy
), (long) 0);
2302 SCROW nDestEnd
= std::min((long)((long)nEndRow
+ nDy
), (long) MAXROW
);
2304 if ( !rAttrArray
.HasAttrib( nDestStart
, nDestEnd
, HASATTR_OVERLAPPED
) )
2306 CopyArea( nStartRow
+nDy
, nEndRow
+nDy
, nDy
, rAttrArray
);
2310 ScDocumentPool
* pSourceDocPool
= pDocument
->GetPool();
2311 ScDocumentPool
* pDestDocPool
= rAttrArray
.pDocument
->GetPool();
2312 bool bSamePool
= (pSourceDocPool
==pDestDocPool
);
2314 for (SCSIZE i
= 0; (i
< nCount
) && (nDestStart
<= nDestEnd
); i
++)
2316 if (pData
[i
].nRow
>= nStartRow
)
2318 const ScPatternAttr
* pOldPattern
= pData
[i
].pPattern
;
2319 const ScPatternAttr
* pNewPattern
;
2322 pNewPattern
= (ScPatternAttr
*) &pDestDocPool
->Put(*pOldPattern
);
2324 pNewPattern
= pOldPattern
->PutInPool( rAttrArray
.pDocument
, pDocument
);
2326 rAttrArray
.SetPatternAreaSafe(nDestStart
,
2327 std::min((SCROW
)(pData
[i
].nRow
+ nDy
), nDestEnd
), pNewPattern
, false);
2330 // when pasting from clipboard and skipping filtered rows, the adjusted
2331 // end position can be negative
2332 nDestStart
= std::max((long)nDestStart
, (long)(pData
[i
].nRow
+ nDy
+ 1));
2337 SCsROW
ScAttrArray::SearchStyle(
2338 SCsROW nRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
2339 const ScMarkArray
* pMarkArray
) const
2341 bool bFound
= false;
2345 nRow
= pMarkArray
->GetNextMarked( nRow
, bUp
);
2346 if (!ValidRow(nRow
))
2351 Search(nRow
, nIndex
);
2352 const ScPatternAttr
* pPattern
= pData
[nIndex
].pPattern
;
2354 while (nIndex
< nCount
&& !bFound
)
2356 if (pPattern
->GetStyleSheet() == pSearchStyle
)
2360 nRow
= pMarkArray
->GetNextMarked( nRow
, bUp
);
2361 SCROW nStart
= nIndex
? pData
[nIndex
-1].nRow
+1 : 0;
2362 if (nRow
>= nStart
&& nRow
<= pData
[nIndex
].nRow
)
2381 nRow
= pData
[nIndex
].nRow
;
2382 pPattern
= pData
[nIndex
].pPattern
;
2387 nRow
= pData
[nIndex
].nRow
+1;
2390 pPattern
= pData
[nIndex
].pPattern
;
2395 OSL_ENSURE( bFound
|| !ValidRow(nRow
), "Internal failure in in ScAttrArray::SearchStyle" );
2401 bool ScAttrArray::SearchStyleRange(
2402 SCsROW
& rRow
, SCsROW
& rEndRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
2403 const ScMarkArray
* pMarkArray
) const
2405 SCsROW nStartRow
= SearchStyle( rRow
, pSearchStyle
, bUp
, pMarkArray
);
2406 if (ValidRow(nStartRow
))
2409 Search(nStartRow
,nIndex
);
2415 rEndRow
= pData
[nIndex
-1].nRow
+ 1;
2420 SCROW nMarkEnd
= pMarkArray
->GetMarkEnd( nStartRow
, true );
2421 if (nMarkEnd
>rEndRow
)
2427 rEndRow
= pData
[nIndex
].nRow
;
2430 SCROW nMarkEnd
= pMarkArray
->GetMarkEnd( nStartRow
, false );
2431 if (nMarkEnd
<rEndRow
)
2442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */