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>
48 #include <boost/scoped_ptr.hpp>
50 // STATIC DATA -----------------------------------------------------------
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 ScAttrArray::~ScAttrArray()
68 #if OSL_DEBUG_LEVEL > 1
72 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
73 for (SCSIZE i
=0; i
<nCount
; i
++)
74 pDocPool
->Remove(*pData
[i
].pPattern
);
79 #if OSL_DEBUG_LEVEL > 1
80 void ScAttrArray::TestData() const
85 for (nPos
=0; nPos
<nCount
; nPos
++)
88 if (pData
[nPos
].pPattern
== pData
[nPos
-1].pPattern
|| pData
[nPos
].nRow
<= pData
[nPos
-1].nRow
)
90 if (pData
[nPos
].pPattern
->Which() != ATTR_PATTERN
)
93 if ( nPos
&& pData
[nPos
-1].nRow
!= MAXROW
)
99 aMsg
.append(static_cast<sal_Int32
>(nErr
));
100 aMsg
.append(" errors in attribute array, column ");
101 aMsg
.append(static_cast<sal_Int32
>(nCol
));
102 OSL_FAIL(aMsg
.getStr());
107 void ScAttrArray::Reset( const ScPatternAttr
* pPattern
)
109 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
110 ScAddress
aAdrStart( nCol
, 0, nTab
);
111 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
113 for (SCSIZE i
=0; i
<nCount
; i
++)
115 // ensure that attributing changes text width of cell
116 const ScPatternAttr
* pOldPattern
= pData
[i
].pPattern
;
117 bool bNumFormatChanged
;
118 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
119 pPattern
->GetItemSet(), pOldPattern
->GetItemSet() ) )
121 aAdrStart
.SetRow( i
? pData
[i
-1].nRow
+1 : 0 );
122 aAdrEnd
.SetRow( pData
[i
].nRow
);
123 pDocument
->InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
125 pDocPool
->Remove(*pOldPattern
);
129 if (pDocument
->IsStreamValid(nTab
))
130 pDocument
->SetStreamValid(nTab
, false);
133 pData
= new ScAttrEntry
[1];
134 const ScPatternAttr
* pNewPattern
= static_cast<const ScPatternAttr
*>( &pDocPool
->Put(*pPattern
) );
135 pData
[0].nRow
= MAXROW
;
136 pData
[0].pPattern
= pNewPattern
;
139 bool ScAttrArray::Concat(SCSIZE nPos
)
146 if (pData
[nPos
- 1].pPattern
== pData
[nPos
].pPattern
)
148 pData
[nPos
- 1].nRow
= pData
[nPos
].nRow
;
149 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
150 memmove(&pData
[nPos
], &pData
[nPos
+ 1], (nCount
- nPos
- 1) * sizeof(ScAttrEntry
));
151 pData
[nCount
- 1].pPattern
= NULL
;
152 pData
[nCount
- 1].nRow
= 0;
158 if (nPos
+ 1 < nCount
)
160 if (pData
[nPos
+ 1].pPattern
== pData
[nPos
].pPattern
)
162 pData
[nPos
].nRow
= pData
[nPos
+ 1].nRow
;
163 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
164 memmove(&pData
[nPos
+ 1], &pData
[nPos
+ 2], (nCount
- nPos
- 2) * sizeof(ScAttrEntry
));
165 pData
[nCount
- 1].pPattern
= NULL
;
166 pData
[nCount
- 1].nRow
= 0;
175 bool ScAttrArray::Search( SCROW nRow
, SCSIZE
& nIndex
) const
177 long nHi
= static_cast<long>(nCount
) - 1;
179 bool bFound
= (nCount
== 1);
182 while ( !bFound
&& nLo
<= nHi
)
186 nStartRow
= (long) pData
[i
- 1].nRow
;
189 const long nEndRow
= (long) pData
[i
].nRow
;
190 if (nEndRow
< (long) nRow
)
193 if (nStartRow
>= (long) nRow
)
206 const ScPatternAttr
* ScAttrArray::GetPattern( SCROW nRow
) const
209 if (Search( nRow
, i
))
210 return pData
[i
].pPattern
;
215 const ScPatternAttr
* ScAttrArray::GetPatternRange( SCROW
& rStartRow
,
216 SCROW
& rEndRow
, SCROW nRow
) const
219 if ( Search( nRow
, nIndex
) )
222 rStartRow
= pData
[nIndex
-1].nRow
+ 1;
225 rEndRow
= pData
[nIndex
].nRow
;
226 return pData
[nIndex
].pPattern
;
231 void ScAttrArray::AddCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
233 if(!ValidRow(nStartRow
) || !ValidRow(nEndRow
))
236 if(nEndRow
< nStartRow
)
239 SCROW nTempStartRow
= nStartRow
;
240 SCROW nTempEndRow
= nEndRow
;
244 const ScPatternAttr
* pPattern
= GetPattern(nTempStartRow
);
246 boost::scoped_ptr
<ScPatternAttr
> pNewPattern
;
249 pNewPattern
.reset( new ScPatternAttr(*pPattern
) );
250 SCROW nPatternStartRow
;
251 SCROW nPatternEndRow
;
252 GetPatternRange( nPatternStartRow
, nPatternEndRow
, nTempStartRow
);
254 nTempEndRow
= std::min
<SCROW
>( nPatternEndRow
, nEndRow
);
255 const SfxPoolItem
* pItem
= NULL
;
256 pPattern
->GetItemSet().GetItemState( ATTR_CONDITIONAL
, true, &pItem
);
257 std::vector
< sal_uInt32
> aCondFormatData
;
259 aCondFormatData
= static_cast<const ScCondFormatItem
*>(pItem
)->GetCondFormatData();
260 aCondFormatData
.push_back(nIndex
);
262 ScCondFormatItem aItem
;
263 aItem
.SetCondFormatData( aCondFormatData
);
264 pNewPattern
->GetItemSet().Put( aItem
);
268 pNewPattern
.reset( new ScPatternAttr( pDocument
->GetPool() ) );
269 ScCondFormatItem aItem
;
270 aItem
.AddCondFormatData(nIndex
);
271 pNewPattern
->GetItemSet().Put( aItem
);
272 nTempEndRow
= nEndRow
;
275 SetPatternArea( nTempStartRow
, nTempEndRow
, pNewPattern
.get(), true );
276 nTempStartRow
= nTempEndRow
+ 1;
278 while(nTempEndRow
< nEndRow
);
282 void ScAttrArray::RemoveCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
284 if(!ValidRow(nStartRow
) || !ValidRow(nEndRow
))
287 if(nEndRow
< nStartRow
)
290 SCROW nTempStartRow
= nStartRow
;
291 SCROW nTempEndRow
= nEndRow
;
295 const ScPatternAttr
* pPattern
= GetPattern(nTempStartRow
);
299 ScPatternAttr
aPattern( *pPattern
);
300 SCROW nPatternStartRow
;
301 SCROW nPatternEndRow
;
302 GetPatternRange( nPatternStartRow
, nPatternEndRow
, nTempStartRow
);
304 nTempEndRow
= std::min
<SCROW
>( nPatternEndRow
, nEndRow
);
305 const SfxPoolItem
* pItem
= NULL
;
306 pPattern
->GetItemSet().GetItemState( ATTR_CONDITIONAL
, true, &pItem
);
309 std::vector
< sal_uInt32
> aCondFormatData
= static_cast<const ScCondFormatItem
*>(pItem
)->GetCondFormatData();
310 std::vector
<sal_uInt32
>::iterator itr
= std::find(aCondFormatData
.begin(), aCondFormatData
.end(), nIndex
);
311 if(itr
!= aCondFormatData
.end() || nIndex
== 0)
313 ScCondFormatItem aItem
;
315 aCondFormatData
.clear();
317 aCondFormatData
.erase(itr
);
318 aItem
.SetCondFormatData( aCondFormatData
);
319 aPattern
.GetItemSet().Put( aItem
);
320 SetPatternArea( nTempStartRow
, nTempEndRow
, &aPattern
, true );
329 nTempStartRow
= nTempEndRow
+ 1;
331 while(nTempEndRow
< nEndRow
);
335 void ScAttrArray::SetPattern( SCROW nRow
, const ScPatternAttr
* pPattern
, bool bPutToPool
)
337 SetPatternArea( nRow
, nRow
, pPattern
, bPutToPool
);
340 void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow
, SCROW nEndRow
,
341 const ScPatternAttr
* pPattern
, ScEditDataArray
* pDataArray
)
343 for (SCROW nRow
= nStartRow
; nRow
<= nEndRow
; ++nRow
)
345 ScAddress
aPos(nCol
, nRow
, nTab
);
346 ScRefCellValue aCell
;
347 aCell
.assign(*pDocument
, aPos
);
348 if (aCell
.meType
!= CELLTYPE_EDIT
|| !aCell
.mpEditText
)
351 EditTextObject
* pOldData
= NULL
;
353 pOldData
= aCell
.mpEditText
->Clone();
355 // Direct modification of cell content - something to watch out for if
356 // we decide to share edit text instances in the future.
357 ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject
&>(*aCell
.mpEditText
), *pPattern
);
361 EditTextObject
* pNewData
= aCell
.mpEditText
->Clone();
362 pDataArray
->AddItem(nTab
, nCol
, nRow
, pOldData
, pNewData
);
367 bool ScAttrArray::Reserve( SCSIZE nReserve
)
369 if ( nLimit
< nReserve
)
371 if( ScAttrEntry
* pNewData
= new (std::nothrow
) ScAttrEntry
[nReserve
] )
374 memcpy( pNewData
, pData
, nCount
*sizeof(ScAttrEntry
) );
386 void ScAttrArray::SetPatternArea(SCROW nStartRow
, SCROW nEndRow
, const ScPatternAttr
*pPattern
,
387 bool bPutToPool
, ScEditDataArray
* pDataArray
)
389 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
392 pPattern
= static_cast<const ScPatternAttr
*>(&pDocument
->GetPool()->Put(*pPattern
));
394 if ((nStartRow
== 0) && (nEndRow
== MAXROW
))
398 SCSIZE nNeeded
= nCount
+ 2;
399 if ( nLimit
< nNeeded
)
401 nLimit
+= SC_ATTRARRAY_DELTA
;
402 if ( nLimit
< nNeeded
)
404 ScAttrEntry
* pNewData
= new ScAttrEntry
[nLimit
];
405 memcpy( pNewData
, pData
, nCount
*sizeof(ScAttrEntry
) );
410 ScAddress
aAdrStart( nCol
, 0, nTab
);
411 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
413 SCSIZE ni
= 0; // number of entries in beginning
414 SCSIZE nx
= 0; // track position
415 SCROW ns
= 0; // start row of track position
420 Search( nStartRow
, nIndex
);
426 ns
= pData
[ni
-1].nRow
+1;
430 // ensure that attributing changes text width of cell
431 // otherwise, conditional formats need to be reset or deleted
432 while ( ns
<= nEndRow
)
434 const SfxItemSet
& rNewSet
= pPattern
->GetItemSet();
435 const SfxItemSet
& rOldSet
= pData
[nx
].pPattern
->GetItemSet();
437 bool bNumFormatChanged
;
438 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
441 aAdrStart
.SetRow( std::max(nStartRow
,ns
) );
442 aAdrEnd
.SetRow( std::min(nEndRow
,pData
[nx
].nRow
) );
443 pDocument
->InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
445 ns
= pData
[nx
].nRow
+ 1;
449 // continue modifying data array
451 SCSIZE nInsert
; // insert position (MAXROWCOUNT := no insert)
452 bool bCombined
= false;
456 nInsert
= MAXROWCOUNT
;
457 if ( pData
[ni
].pPattern
!= pPattern
)
459 if ( ni
== 0 || (pData
[ni
-1].nRow
< nStartRow
- 1) )
460 { // may be a split or a simple insert or just a shrink,
461 // row adjustment is done further down
462 if ( pData
[ni
].nRow
> nEndRow
)
467 else if ( ni
> 0 && pData
[ni
-1].nRow
== nStartRow
- 1 )
470 if ( ni
> 0 && pData
[ni
-1].pPattern
== pPattern
)
472 pData
[ni
-1].nRow
= nEndRow
;
473 nInsert
= MAXROWCOUNT
;
480 SCSIZE nj
= ni
; // stop position of range to replace
481 while ( nj
< nCount
&& pData
[nj
].nRow
<= nEndRow
)
485 if ( nj
< nCount
&& pData
[nj
].pPattern
== pPattern
)
489 if ( pData
[ni
-1].pPattern
== pPattern
)
490 { // adjacent entries
491 pData
[ni
-1].nRow
= pData
[nj
].nRow
;
494 else if ( ni
== nInsert
)
495 pData
[ni
-1].nRow
= nStartRow
- 1; // shrink
497 nInsert
= MAXROWCOUNT
;
500 else if ( ni
> 0 && ni
== nInsert
)
501 pData
[ni
-1].nRow
= nStartRow
- 1; // shrink
503 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
505 { // duplicate splitted entry in pool
506 pDocPool
->Put( *pData
[ni
-1].pPattern
);
509 { // remove middle entries
510 for ( SCSIZE nk
=ni
; nk
<nj
; nk
++)
511 { // remove entries from pool
512 pDocPool
->Remove( *pData
[nk
].pPattern
);
515 { // replace one entry
516 pData
[ni
].nRow
= nEndRow
;
517 pData
[ni
].pPattern
= pPattern
;
519 nInsert
= MAXROWCOUNT
;
523 memmove( pData
+ ni
, pData
+ nj
, (nCount
- nj
) * sizeof(ScAttrEntry
) );
528 if ( nInsert
< sal::static_int_cast
<SCSIZE
>(MAXROWCOUNT
) )
529 { // insert or append new entry
530 if ( nInsert
<= nCount
)
533 memmove( pData
+ nInsert
+ 1, pData
+ nInsert
,
534 (nCount
- nInsert
) * sizeof(ScAttrEntry
) );
537 memmove( pData
+ nInsert
+ 2, pData
+ nInsert
,
538 (nCount
- nInsert
) * sizeof(ScAttrEntry
) );
539 pData
[nInsert
+1] = pData
[nInsert
-1];
544 pData
[nInsert
-1].nRow
= nStartRow
- 1;
545 pData
[nInsert
].nRow
= nEndRow
;
546 pData
[nInsert
].pPattern
= pPattern
;
548 // Remove character attributes from these cells if the pattern
549 // is applied during normal session.
551 RemoveCellCharAttribs(nStartRow
, nEndRow
, pPattern
, pDataArray
);
556 if (pDocument
->IsStreamValid(nTab
))
557 pDocument
->SetStreamValid(nTab
, false);
561 #if OSL_DEBUG_LEVEL > 1
566 void ScAttrArray::ApplyStyleArea( SCROW nStartRow
, SCROW nEndRow
, ScStyleSheet
* pStyle
)
568 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
572 if (!Search( nStartRow
, nPos
))
574 OSL_FAIL("Search Failure");
578 ScAddress
aAdrStart( nCol
, 0, nTab
);
579 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
583 const ScPatternAttr
* pOldPattern
= pData
[nPos
].pPattern
;
584 boost::scoped_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr(*pOldPattern
));
585 pNewPattern
->SetStyleSheet(pStyle
);
587 SCROW nY2
= pData
[nPos
].nRow
;
588 nStart
= pData
[nPos
].nRow
+ 1;
590 if ( *pNewPattern
== *pOldPattern
)
592 // keep the original pattern (might be default)
593 // pNewPattern is deleted below
596 else if ( nY1
< nStartRow
|| nY2
> nEndRow
)
598 if (nY1
< nStartRow
) nY1
=nStartRow
;
599 if (nY2
> nEndRow
) nY2
=nEndRow
;
600 SetPatternArea( nY1
, nY2
, pNewPattern
.get(), true );
601 Search( nStart
, nPos
);
605 // ensure attributing changes text width of cell; otherwise
606 // there aren't (yet) template format changes
607 const SfxItemSet
& rNewSet
= pNewPattern
->GetItemSet();
608 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
610 bool bNumFormatChanged
;
611 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
614 aAdrStart
.SetRow( nPos
? pData
[nPos
-1].nRow
+1 : 0 );
615 aAdrEnd
.SetRow( pData
[nPos
].nRow
);
616 pDocument
->InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
619 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
620 pData
[nPos
].pPattern
= static_cast<const ScPatternAttr
*>(
621 &pDocument
->GetPool()->Put(*pNewPattern
));
623 Search(nStart
, nPos
);
628 while ((nStart
<= nEndRow
) && (nPos
< nCount
));
630 if (pDocument
->IsStreamValid(nTab
))
631 pDocument
->SetStreamValid(nTab
, false);
634 #if OSL_DEBUG_LEVEL > 1
639 // const cast, otherwise it will be too inefficient/complicated
640 #define SET_LINECOLOR(dest,c) \
643 const_cast<SvxBorderLine*>(dest)->SetColor((c)); \
646 #define SET_LINE(dest,src) \
649 SvxBorderLine* pCast = const_cast<SvxBorderLine*>(dest); \
650 pCast->SetBorderLineStyle( (src)->GetBorderLineStyle() ); \
651 pCast->SetWidth( (src)->GetWidth( ) ); \
654 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow
, SCROW nEndRow
,
655 const SvxBorderLine
* pLine
, bool bColorOnly
)
657 if ( bColorOnly
&& !pLine
)
660 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
664 if (!Search( nStartRow
, nPos
))
666 OSL_FAIL("Search failure");
672 const ScPatternAttr
* pOldPattern
= pData
[nPos
].pPattern
;
673 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
674 const SfxPoolItem
* pBoxItem
= 0;
675 SfxItemState eState
= rOldSet
.GetItemState( ATTR_BORDER
, true, &pBoxItem
);
676 const SfxPoolItem
* pTLBRItem
= 0;
677 SfxItemState eTLBRState
= rOldSet
.GetItemState( ATTR_BORDER_TLBR
, true, &pTLBRItem
);
678 const SfxPoolItem
* pBLTRItem
= 0;
679 SfxItemState eBLTRState
= rOldSet
.GetItemState( ATTR_BORDER_BLTR
, true, &pBLTRItem
);
681 if ( (SfxItemState::SET
== eState
) || (SfxItemState::SET
== eTLBRState
) || (SfxItemState::SET
== eBLTRState
) )
683 boost::scoped_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr(*pOldPattern
));
684 SfxItemSet
& rNewSet
= pNewPattern
->GetItemSet();
686 SCROW nY2
= pData
[nPos
].nRow
;
688 SvxBoxItem
* pNewBoxItem
= pBoxItem
? static_cast<SvxBoxItem
*>(pBoxItem
->Clone()) : 0;
689 SvxLineItem
* pNewTLBRItem
= pTLBRItem
? static_cast<SvxLineItem
*>(pTLBRItem
->Clone()) : 0;
690 SvxLineItem
* pNewBLTRItem
= pBLTRItem
? static_cast<SvxLineItem
*>(pBLTRItem
->Clone()) : 0;
692 // fetch line and update attributes with parameters
698 if ( pNewBoxItem
->GetTop() ) pNewBoxItem
->SetLine( NULL
, SvxBoxItemLine::TOP
);
699 if ( pNewBoxItem
->GetBottom() ) pNewBoxItem
->SetLine( NULL
, SvxBoxItemLine::BOTTOM
);
700 if ( pNewBoxItem
->GetLeft() ) pNewBoxItem
->SetLine( NULL
, SvxBoxItemLine::LEFT
);
701 if ( pNewBoxItem
->GetRight() ) pNewBoxItem
->SetLine( NULL
, SvxBoxItemLine::RIGHT
);
703 if( pNewTLBRItem
&& pNewTLBRItem
->GetLine() )
704 pNewTLBRItem
->SetLine( 0 );
705 if( pNewBLTRItem
&& pNewBLTRItem
->GetLine() )
706 pNewBLTRItem
->SetLine( 0 );
712 Color
aColor( pLine
->GetColor() );
715 SET_LINECOLOR( pNewBoxItem
->GetTop(), aColor
);
716 SET_LINECOLOR( pNewBoxItem
->GetBottom(), aColor
);
717 SET_LINECOLOR( pNewBoxItem
->GetLeft(), aColor
);
718 SET_LINECOLOR( pNewBoxItem
->GetRight(), aColor
);
721 SET_LINECOLOR( pNewTLBRItem
->GetLine(), aColor
);
723 SET_LINECOLOR( pNewBLTRItem
->GetLine(), aColor
);
729 SET_LINE( pNewBoxItem
->GetTop(), pLine
);
730 SET_LINE( pNewBoxItem
->GetBottom(), pLine
);
731 SET_LINE( pNewBoxItem
->GetLeft(), pLine
);
732 SET_LINE( pNewBoxItem
->GetRight(), pLine
);
735 SET_LINE( pNewTLBRItem
->GetLine(), pLine
);
737 SET_LINE( pNewBLTRItem
->GetLine(), pLine
);
740 if( pNewBoxItem
) rNewSet
.Put( *pNewBoxItem
);
741 if( pNewTLBRItem
) rNewSet
.Put( *pNewTLBRItem
);
742 if( pNewBLTRItem
) rNewSet
.Put( *pNewBLTRItem
);
744 nStart
= pData
[nPos
].nRow
+ 1;
746 if ( nY1
< nStartRow
|| nY2
> nEndRow
)
748 if (nY1
< nStartRow
) nY1
=nStartRow
;
749 if (nY2
> nEndRow
) nY2
=nEndRow
;
750 SetPatternArea( nY1
, nY2
, pNewPattern
.get(), true );
751 Search( nStart
, nPos
);
755 // remove from pool ?
756 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
757 pData
[nPos
].pPattern
= static_cast<const ScPatternAttr
*>(
758 &pDocument
->GetPool()->Put(*pNewPattern
) );
761 Search(nStart
, nPos
);
771 nStart
= pData
[nPos
].nRow
+ 1;
775 while ((nStart
<= nEndRow
) && (nPos
< nCount
));
782 void ScAttrArray::ApplyCacheArea( SCROW nStartRow
, SCROW nEndRow
, SfxItemPoolCache
* pCache
, ScEditDataArray
* pDataArray
)
784 #if OSL_DEBUG_LEVEL > 1
788 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
792 if (!Search( nStartRow
, nPos
))
794 OSL_FAIL("Search Failure");
798 ScAddress
aAdrStart( nCol
, 0, nTab
);
799 ScAddress
aAdrEnd ( nCol
, 0, nTab
);
803 const ScPatternAttr
* pOldPattern
= pData
[nPos
].pPattern
;
804 const ScPatternAttr
* pNewPattern
= static_cast<const ScPatternAttr
*>( &pCache
->ApplyTo( *pOldPattern
, true ) );
805 ScDocumentPool::CheckRef( *pOldPattern
);
806 ScDocumentPool::CheckRef( *pNewPattern
);
807 if (pNewPattern
!= pOldPattern
)
810 SCROW nY2
= pData
[nPos
].nRow
;
811 nStart
= pData
[nPos
].nRow
+ 1;
813 if ( nY1
< nStartRow
|| nY2
> nEndRow
)
815 if (nY1
< nStartRow
) nY1
=nStartRow
;
816 if (nY2
> nEndRow
) nY2
=nEndRow
;
817 SetPatternArea( nY1
, nY2
, pNewPattern
, false, pDataArray
);
818 Search( nStart
, nPos
);
822 // ensure attributing changes text-width of cell
824 const SfxItemSet
& rNewSet
= pNewPattern
->GetItemSet();
825 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
827 bool bNumFormatChanged
;
828 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged
,
831 aAdrStart
.SetRow( nPos
? pData
[nPos
-1].nRow
+1 : 0 );
832 aAdrEnd
.SetRow( pData
[nPos
].nRow
);
833 pDocument
->InvalidateTextWidth( &aAdrStart
, &aAdrEnd
, bNumFormatChanged
);
836 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
837 pData
[nPos
].pPattern
= pNewPattern
;
839 Search(nStart
, nPos
);
846 nStart
= pData
[nPos
].nRow
+ 1;
850 while (nStart
<= nEndRow
);
852 if (pDocument
->IsStreamValid(nTab
))
853 pDocument
->SetStreamValid(nTab
, false);
856 #if OSL_DEBUG_LEVEL > 1
861 bool ScAttrArray::SetAttrEntries(ScAttrEntry
* pNewData
, SCSIZE nSize
)
863 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
864 for (SCSIZE i
=0; i
<nCount
; i
++)
865 pDocPool
->Remove(*pData
[i
].pPattern
);
870 nCount
= nLimit
= nSize
;
874 static void lcl_MergeDeep( SfxItemSet
& rMergeSet
, const SfxItemSet
& rSource
)
876 const SfxPoolItem
* pNewItem
;
877 const SfxPoolItem
* pOldItem
;
878 for (sal_uInt16 nId
=ATTR_PATTERN_START
; nId
<=ATTR_PATTERN_END
; nId
++)
880 // pMergeSet has no parent
881 SfxItemState eOldState
= rMergeSet
.GetItemState( nId
, false, &pOldItem
);
883 if ( eOldState
== SfxItemState::DEFAULT
)
885 SfxItemState eNewState
= rSource
.GetItemState( nId
, true, &pNewItem
);
886 if ( eNewState
== SfxItemState::SET
)
888 if ( *pNewItem
!= rMergeSet
.GetPool()->GetDefaultItem(nId
) )
889 rMergeSet
.InvalidateItem( nId
);
892 else if ( eOldState
== SfxItemState::SET
) // Item set
894 SfxItemState eNewState
= rSource
.GetItemState( nId
, true, &pNewItem
);
895 if ( eNewState
== SfxItemState::SET
)
897 if ( pNewItem
!= pOldItem
) // Both pulled
898 rMergeSet
.InvalidateItem( nId
);
902 if ( *pOldItem
!= rSource
.GetPool()->GetDefaultItem(nId
) )
903 rMergeSet
.InvalidateItem( nId
);
906 // Dontcare remains Dontcare
910 void ScAttrArray::MergePatternArea( SCROW nStartRow
, SCROW nEndRow
,
911 ScMergePatternState
& rState
, bool bDeep
) const
913 if (ValidRow(nStartRow
) && ValidRow(nEndRow
))
917 if (!Search( nStartRow
, nPos
))
919 OSL_FAIL("Search failure");
925 // 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
);
957 static bool lcl_TestAttr( const SvxBorderLine
* pOldLine
, const SvxBorderLine
* pNewLine
,
958 sal_uInt8
& rModified
, const SvxBorderLine
*& rpNew
)
960 if (rModified
== SC_LINE_DONTCARE
)
961 return false; // don't go again
963 if (rModified
== SC_LINE_EMPTY
)
965 rModified
= SC_LINE_SET
;
967 return true; // initial value
970 if (pOldLine
== pNewLine
)
976 if (pOldLine
&& pNewLine
)
977 if (*pOldLine
== *pNewLine
)
983 rModified
= SC_LINE_DONTCARE
;
985 return true; // another line -> don't care
988 static void lcl_MergeToFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
989 ScLineFlags
& rFlags
, const ScPatternAttr
* pPattern
,
990 bool bLeft
, SCCOL nDistRight
, bool bTop
, SCROW nDistBottom
)
992 // right/bottom border set when connected together
993 const ScMergeAttr
& rMerge
= static_cast<const ScMergeAttr
&>(pPattern
->GetItem(ATTR_MERGE
));
994 if ( rMerge
.GetColMerge() == nDistRight
+ 1 )
996 if ( rMerge
.GetRowMerge() == nDistBottom
+ 1 )
999 const SvxBoxItem
* pCellFrame
= static_cast<const SvxBoxItem
*>( &pPattern
->GetItemSet().Get( ATTR_BORDER
) );
1000 const SvxBorderLine
* pLeftAttr
= pCellFrame
->GetLeft();
1001 const SvxBorderLine
* pRightAttr
= pCellFrame
->GetRight();
1002 const SvxBorderLine
* pTopAttr
= pCellFrame
->GetTop();
1003 const SvxBorderLine
* pBottomAttr
= pCellFrame
->GetBottom();
1004 const SvxBorderLine
* pNew
;
1008 if (lcl_TestAttr( pLineOuter
->GetTop(), pTopAttr
, rFlags
.nTop
, pNew
))
1009 pLineOuter
->SetLine( pNew
, SvxBoxItemLine::TOP
);
1013 if (lcl_TestAttr( pLineInner
->GetHori(), pTopAttr
, rFlags
.nHori
, pNew
))
1014 pLineInner
->SetLine( pNew
, SvxBoxInfoItemLine::HORI
);
1017 if (nDistBottom
== 0)
1019 if (lcl_TestAttr( pLineOuter
->GetBottom(), pBottomAttr
, rFlags
.nBottom
, pNew
))
1020 pLineOuter
->SetLine( pNew
, SvxBoxItemLine::BOTTOM
);
1024 if (lcl_TestAttr( pLineInner
->GetHori(), pBottomAttr
, rFlags
.nHori
, pNew
))
1025 pLineInner
->SetLine( pNew
, SvxBoxInfoItemLine::HORI
);
1030 if (lcl_TestAttr( pLineOuter
->GetLeft(), pLeftAttr
, rFlags
.nLeft
, pNew
))
1031 pLineOuter
->SetLine( pNew
, SvxBoxItemLine::LEFT
);
1035 if (lcl_TestAttr( pLineInner
->GetVert(), pLeftAttr
, rFlags
.nVert
, pNew
))
1036 pLineInner
->SetLine( pNew
, SvxBoxInfoItemLine::VERT
);
1039 if (nDistRight
== 0)
1041 if (lcl_TestAttr( pLineOuter
->GetRight(), pRightAttr
, rFlags
.nRight
, pNew
))
1042 pLineOuter
->SetLine( pNew
, SvxBoxItemLine::RIGHT
);
1046 if (lcl_TestAttr( pLineInner
->GetVert(), pRightAttr
, rFlags
.nVert
, pNew
))
1047 pLineInner
->SetLine( pNew
, SvxBoxInfoItemLine::VERT
);
1051 void ScAttrArray::MergeBlockFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
1052 ScLineFlags
& rFlags
,
1053 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
) const
1055 const ScPatternAttr
* pPattern
;
1057 if (nStartRow
== nEndRow
)
1059 pPattern
= GetPattern( nStartRow
);
1060 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, true, 0 );
1064 pPattern
= GetPattern( nStartRow
);
1065 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, true,
1066 nEndRow
-nStartRow
);
1070 Search( nStartRow
+1, nStartIndex
);
1071 Search( nEndRow
-1, nEndIndex
);
1072 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
; i
++)
1074 pPattern
= pData
[i
].pPattern
;
1075 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, false,
1076 nEndRow
- std::min( pData
[i
].nRow
, (SCROW
)(nEndRow
-1) ) );
1077 // nDistBottom here always > 0
1080 pPattern
= GetPattern( nEndRow
);
1081 lcl_MergeToFrame( pLineOuter
, pLineInner
, rFlags
, pPattern
, bLeft
, nDistRight
, false, 0 );
1087 // ApplyFrame - on an entry into the array
1089 bool ScAttrArray::ApplyFrame( const SvxBoxItem
* pBoxItem
,
1090 const SvxBoxInfoItem
* pBoxInfoItem
,
1091 SCROW nStartRow
, SCROW nEndRow
,
1092 bool bLeft
, SCCOL nDistRight
, bool bTop
, SCROW nDistBottom
)
1094 OSL_ENSURE( pBoxItem
&& pBoxInfoItem
, "Missing line attributes!" );
1096 const ScPatternAttr
* pPattern
= GetPattern( nStartRow
);
1097 const SvxBoxItem
* pOldFrame
= static_cast<const SvxBoxItem
*>(
1098 &pPattern
->GetItemSet().Get( ATTR_BORDER
));
1100 // right/bottom border set when connected together
1101 const ScMergeAttr
& rMerge
= static_cast<const ScMergeAttr
&>(pPattern
->GetItem(ATTR_MERGE
));
1102 if ( rMerge
.GetColMerge() == nDistRight
+ 1 )
1104 if ( rMerge
.GetRowMerge() == nDistBottom
+ 1 )
1107 SvxBoxItem
aNewFrame( *pOldFrame
);
1108 bool bRTL
=pDocument
->IsLayoutRTL(nTab
);
1109 // fdo#37464 check if the sheet are RTL then replace right <=> left
1112 if( bLeft
&& nDistRight
==0)
1114 if ( pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::LEFT
) )
1115 aNewFrame
.SetLine( pBoxItem
->GetLeft(), SvxBoxItemLine::RIGHT
);
1116 if ( pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::RIGHT
) )
1117 aNewFrame
.SetLine( pBoxItem
->GetRight(), SvxBoxItemLine::LEFT
);
1121 if ( (nDistRight
==0) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::LEFT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
1122 aNewFrame
.SetLine( (nDistRight
==0) ? pBoxItem
->GetLeft() : pBoxInfoItem
->GetVert(),
1123 SvxBoxItemLine::RIGHT
);
1124 if ( bLeft
? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::RIGHT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
1125 aNewFrame
.SetLine( bLeft
? pBoxItem
->GetRight() : pBoxInfoItem
->GetVert(),
1126 SvxBoxItemLine::LEFT
);
1131 if ( bLeft
? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::LEFT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
1132 aNewFrame
.SetLine( bLeft
? pBoxItem
->GetLeft() : pBoxInfoItem
->GetVert(),
1133 SvxBoxItemLine::LEFT
);
1134 if ( (nDistRight
==0) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::RIGHT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
1135 aNewFrame
.SetLine( (nDistRight
==0) ? pBoxItem
->GetRight() : pBoxInfoItem
->GetVert(),
1136 SvxBoxItemLine::RIGHT
);
1138 if ( bTop
? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::TOP
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::HORI
) )
1139 aNewFrame
.SetLine( bTop
? pBoxItem
->GetTop() : pBoxInfoItem
->GetHori(),
1140 SvxBoxItemLine::TOP
);
1141 if ( (nDistBottom
==0) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::BOTTOM
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::HORI
) )
1142 aNewFrame
.SetLine( (nDistBottom
==0) ? pBoxItem
->GetBottom() : pBoxInfoItem
->GetHori(),
1143 SvxBoxItemLine::BOTTOM
);
1145 if (aNewFrame
== *pOldFrame
)
1152 SfxItemPoolCache
aCache( pDocument
->GetPool(), &aNewFrame
);
1153 ApplyCacheArea( nStartRow
, nEndRow
, &aCache
);
1159 void ScAttrArray::ApplyBlockFrame( const SvxBoxItem
* pLineOuter
, const SvxBoxInfoItem
* pLineInner
,
1160 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
)
1162 if (nStartRow
== nEndRow
)
1163 ApplyFrame( pLineOuter
, pLineInner
, nStartRow
, nEndRow
, bLeft
, nDistRight
, true, 0 );
1166 ApplyFrame( pLineOuter
, pLineInner
, nStartRow
, nStartRow
, bLeft
, nDistRight
,
1167 true, nEndRow
-nStartRow
);
1169 if ( nEndRow
> nStartRow
+1 ) // inner part available?
1173 Search( nStartRow
+1, nStartIndex
);
1174 Search( nEndRow
-1, nEndIndex
);
1175 SCROW nTmpStart
= nStartRow
+1;
1177 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
;)
1179 nTmpEnd
= std::min( (SCROW
)(nEndRow
-1), (SCROW
)(pData
[i
].nRow
) );
1180 bool bChanged
= ApplyFrame( pLineOuter
, pLineInner
, nTmpStart
, nTmpEnd
,
1181 bLeft
, nDistRight
, false, nEndRow
-nTmpEnd
);
1182 nTmpStart
= nTmpEnd
+1;
1185 Search(nTmpStart
, i
);
1186 Search(nEndRow
-1, nEndIndex
);
1193 ApplyFrame( pLineOuter
, pLineInner
, nEndRow
, nEndRow
, bLeft
, nDistRight
, false, 0 );
1197 // Test if field contains specific attribute
1199 bool ScAttrArray::HasAttrib( SCROW nRow1
, SCROW nRow2
, sal_uInt16 nMask
) const
1203 Search( nRow1
, nStartIndex
);
1204 Search( nRow2
, nEndIndex
);
1205 bool bFound
= false;
1207 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
&& !bFound
; i
++)
1209 const ScPatternAttr
* pPattern
= pData
[i
].pPattern
;
1210 if ( nMask
& HASATTR_MERGED
)
1212 const ScMergeAttr
* pMerge
=
1213 static_cast<const ScMergeAttr
*>( &pPattern
->GetItem( ATTR_MERGE
) );
1214 if ( pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1 )
1217 if ( nMask
& ( HASATTR_OVERLAPPED
| HASATTR_NOTOVERLAPPED
| HASATTR_AUTOFILTER
) )
1219 const ScMergeFlagAttr
* pMergeFlag
=
1220 static_cast<const ScMergeFlagAttr
*>( &pPattern
->GetItem( ATTR_MERGE_FLAG
) );
1221 if ( (nMask
& HASATTR_OVERLAPPED
) && pMergeFlag
->IsOverlapped() )
1223 if ( (nMask
& HASATTR_NOTOVERLAPPED
) && !pMergeFlag
->IsOverlapped() )
1225 if ( (nMask
& HASATTR_AUTOFILTER
) && pMergeFlag
->HasAutoFilter() )
1228 if ( nMask
& HASATTR_LINES
)
1230 const SvxBoxItem
* pBox
=
1231 static_cast<const SvxBoxItem
*>( &pPattern
->GetItem( ATTR_BORDER
) );
1232 if ( pBox
->GetLeft() || pBox
->GetRight() || pBox
->GetTop() || pBox
->GetBottom() )
1235 if ( nMask
& HASATTR_SHADOW
)
1237 const SvxShadowItem
* pShadow
=
1238 static_cast<const SvxShadowItem
*>( &pPattern
->GetItem( ATTR_SHADOW
) );
1239 if ( pShadow
->GetLocation() != SVX_SHADOW_NONE
)
1242 if ( nMask
& HASATTR_CONDITIONAL
)
1244 bool bContainsCondFormat
=
1245 !static_cast<const ScCondFormatItem
&>(pPattern
->GetItem( ATTR_CONDITIONAL
)).GetCondFormatData().empty();
1246 if ( bContainsCondFormat
)
1249 if ( nMask
& HASATTR_PROTECTED
)
1251 const ScProtectionAttr
* pProtect
=
1252 static_cast<const ScProtectionAttr
*>( &pPattern
->GetItem( ATTR_PROTECTION
) );
1253 bool bFoundTemp
= false;
1254 if ( pProtect
->GetProtection() || pProtect
->GetHideCell() )
1257 bool bContainsCondFormat
=
1258 !static_cast<const ScCondFormatItem
&>(pPattern
->GetItem( ATTR_CONDITIONAL
)).GetCondFormatData().empty();
1259 if ( bContainsCondFormat
)
1261 SCROW nRowStartCond
= std::max
<SCROW
>( nRow1
, i
? pData
[i
-1].nRow
+ 1: 0 );
1262 SCROW nRowEndCond
= std::min
<SCROW
>( nRow2
, pData
[i
].nRow
);
1263 bool bFoundCond
= false;
1264 for(SCROW nRowCond
= nRowStartCond
; nRowCond
<= nRowEndCond
&& !bFoundCond
; ++nRowCond
)
1266 const SfxItemSet
* pSet
= pDocument
->GetCondResult( nCol
, nRowCond
, nTab
);
1268 const SfxPoolItem
* pItem
;
1269 if( pSet
&& pSet
->GetItemState( ATTR_PROTECTION
, true, &pItem
) == SfxItemState::SET
)
1271 const ScProtectionAttr
* pCondProtect
= static_cast<const ScProtectionAttr
*>(pItem
);
1272 if( pCondProtect
->GetProtection() || pCondProtect
->GetHideCell() )
1279 // well it is not true that we found one
1280 // but existing one + cell where conditional
1281 // formatting does not remove it
1282 // => we should use the existing protection settting
1283 bFoundCond
= bFoundTemp
;
1286 bFoundTemp
= bFoundCond
;
1292 if ( nMask
& HASATTR_ROTATE
)
1294 const SfxInt32Item
* pRotate
=
1295 static_cast<const SfxInt32Item
*>( &pPattern
->GetItem( ATTR_ROTATE_VALUE
) );
1296 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1297 // (see ScPatternAttr::GetCellOrientation)
1298 sal_Int32 nAngle
= pRotate
->GetValue();
1299 if ( nAngle
!= 0 && nAngle
!= 9000 && nAngle
!= 27000 )
1302 if ( nMask
& HASATTR_NEEDHEIGHT
)
1304 if (pPattern
->GetCellOrientation() != SVX_ORIENTATION_STANDARD
)
1306 else if (static_cast<const SfxBoolItem
&>(pPattern
->GetItem( ATTR_LINEBREAK
)).GetValue())
1308 else if ((SvxCellHorJustify
)static_cast<const SvxHorJustifyItem
&>(pPattern
->
1309 GetItem( ATTR_HOR_JUSTIFY
)).GetValue() == SVX_HOR_JUSTIFY_BLOCK
)
1312 else if (!static_cast<const ScCondFormatItem
&>(pPattern
->GetItem(ATTR_CONDITIONAL
)).GetCondFormatData().empty())
1314 else if (static_cast<const SfxInt32Item
&>(pPattern
->GetItem( ATTR_ROTATE_VALUE
)).GetValue())
1317 if ( nMask
& ( HASATTR_SHADOW_RIGHT
| HASATTR_SHADOW_DOWN
) )
1319 const SvxShadowItem
* pShadow
=
1320 static_cast<const SvxShadowItem
*>( &pPattern
->GetItem( ATTR_SHADOW
));
1321 SvxShadowLocation eLoc
= pShadow
->GetLocation();
1322 if ( nMask
& HASATTR_SHADOW_RIGHT
)
1323 if ( eLoc
== SVX_SHADOW_TOPRIGHT
|| eLoc
== SVX_SHADOW_BOTTOMRIGHT
)
1325 if ( nMask
& HASATTR_SHADOW_DOWN
)
1326 if ( eLoc
== SVX_SHADOW_BOTTOMLEFT
|| eLoc
== SVX_SHADOW_BOTTOMRIGHT
)
1329 if ( nMask
& HASATTR_RTL
)
1331 const SvxFrameDirectionItem
& rDirection
=
1332 static_cast<const SvxFrameDirectionItem
&>( pPattern
->GetItem( ATTR_WRITINGDIR
) );
1333 if ( rDirection
.GetValue() == FRMDIR_HORI_RIGHT_TOP
)
1336 if ( nMask
& HASATTR_RIGHTORCENTER
)
1338 // called only if the sheet is LTR, so physical=logical alignment can be assumed
1339 SvxCellHorJustify eHorJust
= (SvxCellHorJustify
)
1340 static_cast<const SvxHorJustifyItem
&>( pPattern
->GetItem( ATTR_HOR_JUSTIFY
)).GetValue();
1341 if ( eHorJust
== SVX_HOR_JUSTIFY_RIGHT
|| eHorJust
== SVX_HOR_JUSTIFY_CENTER
)
1349 bool ScAttrArray::IsMerged( SCROW nRow
) const
1352 Search(nRow
, nIndex
);
1353 const ScMergeAttr
& rItem
=
1354 static_cast<const ScMergeAttr
&>(pData
[nIndex
].pPattern
->GetItem(ATTR_MERGE
));
1356 return rItem
.IsMerged();
1360 * Area around any given summaries expand and adapt any MergeFlag (bRefresh)
1362 bool ScAttrArray::ExtendMerge( SCCOL nThisCol
, SCROW nStartRow
, SCROW nEndRow
,
1363 SCCOL
& rPaintCol
, SCROW
& rPaintRow
,
1366 const ScPatternAttr
* pPattern
;
1367 const ScMergeAttr
* pItem
;
1370 Search( nStartRow
, nStartIndex
);
1371 Search( nEndRow
, nEndIndex
);
1372 bool bFound
= false;
1374 for (SCSIZE i
=nStartIndex
; i
<=nEndIndex
; i
++)
1376 pPattern
= pData
[i
].pPattern
;
1377 pItem
= static_cast<const ScMergeAttr
*>( &pPattern
->GetItem( ATTR_MERGE
) );
1378 SCsCOL nCountX
= pItem
->GetColMerge();
1379 SCsROW nCountY
= pItem
->GetRowMerge();
1380 if (nCountX
>1 || nCountY
>1)
1382 SCROW nThisRow
= (i
>0) ? pData
[i
-1].nRow
+1 : 0;
1383 SCCOL nMergeEndCol
= nThisCol
+ nCountX
- 1;
1384 SCROW nMergeEndRow
= nThisRow
+ nCountY
- 1;
1385 if (nMergeEndCol
> rPaintCol
&& nMergeEndCol
<= MAXCOL
)
1386 rPaintCol
= nMergeEndCol
;
1387 if (nMergeEndRow
> rPaintRow
&& nMergeEndRow
<= MAXROW
)
1388 rPaintRow
= nMergeEndRow
;
1393 if ( nMergeEndCol
> nThisCol
)
1394 pDocument
->ApplyFlagsTab( nThisCol
+1, nThisRow
, nMergeEndCol
, pData
[i
].nRow
,
1396 if ( nMergeEndRow
> nThisRow
)
1397 pDocument
->ApplyFlagsTab( nThisCol
, nThisRow
+1, nThisCol
, nMergeEndRow
,
1399 if ( nMergeEndCol
> nThisCol
&& nMergeEndRow
> nThisRow
)
1400 pDocument
->ApplyFlagsTab( nThisCol
+1, nThisRow
+1, nMergeEndCol
, nMergeEndRow
,
1401 nTab
, SC_MF_HOR
| SC_MF_VER
);
1403 Search( nThisRow
, i
); // Data changed
1404 Search( nStartRow
, nStartIndex
);
1405 Search( nEndRow
, nEndIndex
);
1413 bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow
, SCROW nEndRow
)
1415 bool bFound
= false;
1416 const ScPatternAttr
* pPattern
;
1417 const ScMergeAttr
* pItem
;
1420 Search( nStartRow
, nIndex
);
1421 SCROW nThisStart
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1422 if (nThisStart
< nStartRow
)
1423 nThisStart
= nStartRow
;
1425 while ( nThisStart
<= nEndRow
)
1427 SCROW nThisEnd
= pData
[nIndex
].nRow
;
1428 if (nThisEnd
> nEndRow
)
1431 pPattern
= pData
[nIndex
].pPattern
;
1432 pItem
= static_cast<const ScMergeAttr
*>( &pPattern
->GetItem( ATTR_MERGE
) );
1433 SCsCOL nCountX
= pItem
->GetColMerge();
1434 SCsROW nCountY
= pItem
->GetRowMerge();
1435 if (nCountX
>1 || nCountY
>1)
1437 const ScMergeAttr
* pAttr
= static_cast<const ScMergeAttr
*>(
1438 &pDocument
->GetPool()->GetDefaultItem( ATTR_MERGE
) );
1439 const ScMergeFlagAttr
* pFlagAttr
= static_cast<const ScMergeFlagAttr
*>(
1440 &pDocument
->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG
));
1442 OSL_ENSURE( nCountY
==1 || nThisStart
==nThisEnd
, "What's up?" );
1444 SCCOL nThisCol
= nCol
;
1445 SCCOL nMergeEndCol
= nThisCol
+ nCountX
- 1;
1446 SCROW nMergeEndRow
= nThisEnd
+ nCountY
- 1;
1448 // ApplyAttr for areas
1449 for (SCROW nThisRow
= nThisStart
; nThisRow
<= nThisEnd
; nThisRow
++)
1450 pDocument
->ApplyAttr( nThisCol
, nThisRow
, nTab
, *pAttr
);
1452 boost::scoped_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr( pDocument
->GetPool() ));
1453 SfxItemSet
* pSet
= &pNewPattern
->GetItemSet();
1454 pSet
->Put( *pFlagAttr
);
1455 pDocument
->ApplyPatternAreaTab( nThisCol
, nThisStart
, nMergeEndCol
, nMergeEndRow
,
1456 nTab
, *pNewPattern
);
1457 pNewPattern
.reset();
1459 Search( nThisEnd
, nIndex
); // data changed
1463 if ( nIndex
< nCount
)
1464 nThisStart
= pData
[nIndex
-1].nRow
+1;
1466 nThisStart
= MAXROW
+1; // End
1473 * Remove field, but leave MergeFlags
1475 void ScAttrArray::DeleteAreaSafe(SCROW nStartRow
, SCROW nEndRow
)
1477 SetPatternAreaSafe( nStartRow
, nEndRow
, pDocument
->GetDefPattern(), true );
1480 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow
, SCROW nEndRow
,
1481 const ScPatternAttr
* pWantedPattern
, bool bDefault
)
1483 const ScPatternAttr
* pOldPattern
;
1484 const ScMergeFlagAttr
* pItem
;
1489 bool bFirstUse
= true;
1491 Search( nStartRow
, nIndex
);
1492 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1493 while ( nThisRow
<= nEndRow
)
1495 pOldPattern
= pData
[nIndex
].pPattern
;
1496 if (pOldPattern
!= pWantedPattern
) // FIXME: else-branch?
1498 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1499 nRow
= pData
[nIndex
].nRow
;
1500 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
1501 pItem
= static_cast<const ScMergeFlagAttr
*>( &pOldPattern
->GetItem( ATTR_MERGE_FLAG
) );
1503 if (pItem
->IsOverlapped() || pItem
->HasAutoFilter())
1505 // default-constructing a ScPatternAttr for DeleteArea doesn't work
1506 // because it would have no cell style information.
1507 // Instead, the document's GetDefPattern is copied. Since it is passed as
1508 // pWantedPattern, no special treatment of default is needed here anymore.
1509 boost::scoped_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr( *pWantedPattern
));
1510 SfxItemSet
* pSet
= &pNewPattern
->GetItemSet();
1511 pSet
->Put( *pItem
);
1512 SetPatternArea( nThisRow
, nAttrRow
, pNewPattern
.get(), true );
1522 pDocument
->GetPool()->Put( *pWantedPattern
);
1524 SetPatternArea( nThisRow
, nAttrRow
, pWantedPattern
);
1527 Search( nThisRow
, nIndex
); // data changed
1531 nThisRow
= pData
[nIndex
-1].nRow
+1;
1535 bool ScAttrArray::ApplyFlags( SCROW nStartRow
, SCROW nEndRow
, sal_Int16 nFlags
)
1537 const ScPatternAttr
* pOldPattern
;
1539 sal_Int16 nOldValue
;
1543 bool bChanged
= false;
1545 Search( nStartRow
, nIndex
);
1546 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1547 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1549 while ( nThisRow
<= nEndRow
)
1551 pOldPattern
= pData
[nIndex
].pPattern
;
1552 nOldValue
= static_cast<const ScMergeFlagAttr
*>( &pOldPattern
->GetItem( ATTR_MERGE_FLAG
))->GetValue();
1553 if ( (nOldValue
| nFlags
) != nOldValue
)
1555 nRow
= pData
[nIndex
].nRow
;
1556 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
1557 ScPatternAttr
aNewPattern(*pOldPattern
);
1558 aNewPattern
.GetItemSet().Put( ScMergeFlagAttr( nOldValue
| nFlags
) );
1559 SetPatternArea( nThisRow
, nAttrRow
, &aNewPattern
, true );
1560 Search( nThisRow
, nIndex
); // data changed
1565 nThisRow
= pData
[nIndex
-1].nRow
+1;
1571 bool ScAttrArray::RemoveFlags( SCROW nStartRow
, SCROW nEndRow
, sal_Int16 nFlags
)
1573 const ScPatternAttr
* pOldPattern
;
1575 sal_Int16 nOldValue
;
1579 bool bChanged
= false;
1581 Search( nStartRow
, nIndex
);
1582 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1583 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1585 while ( nThisRow
<= nEndRow
)
1587 pOldPattern
= pData
[nIndex
].pPattern
;
1588 nOldValue
= static_cast<const ScMergeFlagAttr
*>(&pOldPattern
->GetItem( ATTR_MERGE_FLAG
))->GetValue();
1589 if ( (nOldValue
& ~nFlags
) != nOldValue
)
1591 nRow
= pData
[nIndex
].nRow
;
1592 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
1593 ScPatternAttr
aNewPattern(*pOldPattern
);
1594 aNewPattern
.GetItemSet().Put( ScMergeFlagAttr( nOldValue
& ~nFlags
) );
1595 SetPatternArea( nThisRow
, nAttrRow
, &aNewPattern
, true );
1596 Search( nThisRow
, nIndex
); // data changed
1601 nThisRow
= pData
[nIndex
-1].nRow
+1;
1607 void ScAttrArray::ClearItems( SCROW nStartRow
, SCROW nEndRow
, const sal_uInt16
* pWhich
)
1613 Search( nStartRow
, nIndex
);
1614 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1615 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
1617 while ( nThisRow
<= nEndRow
)
1619 const ScPatternAttr
* pOldPattern
= pData
[nIndex
].pPattern
;
1620 if ( pOldPattern
->HasItemsSet( pWhich
) )
1622 ScPatternAttr
aNewPattern(*pOldPattern
);
1623 aNewPattern
.ClearItems( pWhich
);
1625 nRow
= pData
[nIndex
].nRow
;
1626 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
1627 SetPatternArea( nThisRow
, nAttrRow
, &aNewPattern
, true );
1628 Search( nThisRow
, nIndex
); // data changed
1632 nThisRow
= pData
[nIndex
-1].nRow
+1;
1636 void ScAttrArray::ChangeIndent( SCROW nStartRow
, SCROW nEndRow
, bool bIncrement
)
1639 Search( nStartRow
, nIndex
);
1640 SCROW nThisStart
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
1641 if (nThisStart
< nStartRow
) nThisStart
= nStartRow
;
1643 while ( nThisStart
<= nEndRow
)
1645 const ScPatternAttr
* pOldPattern
= pData
[nIndex
].pPattern
;
1646 const SfxItemSet
& rOldSet
= pOldPattern
->GetItemSet();
1647 const SfxPoolItem
* pItem
;
1649 bool bNeedJust
= ( rOldSet
.GetItemState( ATTR_HOR_JUSTIFY
, false, &pItem
) != SfxItemState::SET
1650 || (static_cast<const SvxHorJustifyItem
*>(pItem
)->GetValue() != SVX_HOR_JUSTIFY_LEFT
&&
1651 static_cast<const SvxHorJustifyItem
*>(pItem
)->GetValue() != SVX_HOR_JUSTIFY_RIGHT
));
1652 sal_uInt16 nOldValue
= static_cast<const SfxUInt16Item
&>(rOldSet
.Get( ATTR_INDENT
)).GetValue();
1653 sal_uInt16 nNewValue
= nOldValue
;
1654 // To keep Increment indent from running outside the cell1659
1655 long nColWidth
= (long)pDocument
->GetColWidth(nCol
,nTab
);
1658 if ( nNewValue
< nColWidth
-SC_INDENT_STEP
)
1660 nNewValue
+= SC_INDENT_STEP
;
1661 if ( nNewValue
> nColWidth
-SC_INDENT_STEP
) nNewValue
= nColWidth
-SC_INDENT_STEP
;
1666 if ( nNewValue
> 0 )
1668 if ( nNewValue
> SC_INDENT_STEP
)
1669 nNewValue
-= SC_INDENT_STEP
;
1675 if ( bNeedJust
|| nNewValue
!= nOldValue
)
1677 SCROW nThisEnd
= pData
[nIndex
].nRow
;
1678 SCROW nAttrRow
= std::min( nThisEnd
, nEndRow
);
1679 ScPatternAttr
aNewPattern(*pOldPattern
);
1680 aNewPattern
.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT
, nNewValue
) );
1682 aNewPattern
.GetItemSet().Put(
1683 SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT
, ATTR_HOR_JUSTIFY
) );
1684 SetPatternArea( nThisStart
, nAttrRow
, &aNewPattern
, true );
1686 nThisStart
= nThisEnd
+ 1;
1687 Search( nThisStart
, nIndex
); // data changed
1691 nThisStart
= pData
[nIndex
].nRow
+ 1;
1697 SCsROW
ScAttrArray::GetNextUnprotected( SCsROW nRow
, bool bUp
) const
1703 Search(nRow
, nIndex
);
1704 while (static_cast<const ScProtectionAttr
&>(pData
[nIndex
].pPattern
->
1705 GetItem(ATTR_PROTECTION
)).GetProtection())
1710 return -1; // not found
1712 nRet
= pData
[nIndex
].nRow
;
1716 nRet
= pData
[nIndex
].nRow
+1;
1719 return MAXROW
+1; // not found
1726 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase
* pStyleSheet
, ScFlatBoolRowSegments
& rUsedRows
, bool bReset
)
1730 while (nPos
< nCount
)
1732 SCROW nEnd
= pData
[nPos
].nRow
;
1733 if (pData
[nPos
].pPattern
->GetStyleSheet() == pStyleSheet
)
1735 rUsedRows
.setTrue(nStart
, nEnd
);
1739 boost::scoped_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr(*pData
[nPos
].pPattern
));
1740 pDocument
->GetPool()->Remove(*pData
[nPos
].pPattern
);
1741 pNewPattern
->SetStyleSheet( static_cast<ScStyleSheet
*>(
1742 pDocument
->GetStyleSheetPool()->
1743 Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD
),
1744 SFX_STYLE_FAMILY_PARA
,
1745 SFXSTYLEBIT_AUTO
| SCSTYLEBIT_STANDARD
) ) );
1746 pData
[nPos
].pPattern
= static_cast<const ScPatternAttr
*>(
1747 &pDocument
->GetPool()->Put(*pNewPattern
));
1748 pNewPattern
.reset();
1752 Search(nStart
, nPos
);
1753 --nPos
; // because ++ at end
1762 bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet
& rStyle
,
1763 bool bGatherAllStyles
) const
1765 bool bIsUsed
= false;
1768 while ( nPos
< nCount
)
1770 const ScStyleSheet
* pStyle
= pData
[nPos
].pPattern
->GetStyleSheet();
1773 pStyle
->SetUsage( ScStyleSheet::USED
);
1774 if ( pStyle
== &rStyle
)
1776 if ( !bGatherAllStyles
)
1787 bool ScAttrArray::IsEmpty() const
1791 if ( pData
[0].pPattern
!= pDocument
->GetDefPattern() )
1800 bool ScAttrArray::GetFirstVisibleAttr( SCROW
& rFirstRow
) const
1802 OSL_ENSURE( nCount
, "nCount == 0" );
1804 bool bFound
= false;
1807 // Skip first entry if more than 1 row.
1808 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1810 SCSIZE nVisStart
= 1;
1811 while ( nVisStart
< nCount
&& pData
[nVisStart
].pPattern
->IsVisibleEqual(*pData
[nVisStart
-1].pPattern
) )
1813 if ( nVisStart
>= nCount
|| pData
[nVisStart
-1].nRow
> 0 ) // more than 1 row?
1816 while ( nStart
< nCount
&& !bFound
)
1818 if ( pData
[nStart
].pPattern
->IsVisible() )
1820 rFirstRow
= nStart
? ( pData
[nStart
-1].nRow
+ 1 ) : 0;
1830 // size (rows) of a range of attributes after cell content where the search is stopped
1831 // (more than a default page size, 2*42 because it's as good as any number)
1833 const SCROW SC_VISATTR_STOP
= 84;
1835 bool ScAttrArray::GetLastVisibleAttr( SCROW
& rLastRow
, SCROW nLastData
, bool bFullFormattedArea
) const
1837 OSL_ENSURE( nCount
, "nCount == 0" );
1839 // #i30830# changed behavior:
1840 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1841 // below the last content cell
1843 if ( nLastData
== MAXROW
)
1845 rLastRow
= MAXROW
; // can't look for attributes below MAXROW
1849 // Quick check: last data row in or immediately preceding a run that is the
1850 // last attribution down to the end, e.g. default style or column style.
1851 SCSIZE nPos
= nCount
- 1;
1852 SCROW nStartRow
= (nPos
? pData
[nPos
-1].nRow
+ 1 : 0);
1853 if (nStartRow
<= nLastData
+ 1)
1855 if (bFullFormattedArea
&& pData
[nPos
].pPattern
->IsVisible())
1857 rLastRow
= pData
[nPos
].nRow
;
1862 // Ignore here a few rows if data happens to end within
1863 // SC_VISATTR_STOP rows before MAXROW.
1864 rLastRow
= nLastData
;
1869 // Find a run below last data row.
1870 bool bFound
= false;
1871 Search( nLastData
, nPos
);
1872 while ( nPos
< nCount
)
1874 // find range of visually equal formats
1875 SCSIZE nEndPos
= nPos
;
1876 while ( nEndPos
< nCount
-1 &&
1877 pData
[nEndPos
].pPattern
->IsVisibleEqual( *pData
[nEndPos
+1].pPattern
))
1879 SCROW nAttrStartRow
= ( nPos
> 0 ) ? ( pData
[nPos
-1].nRow
+ 1 ) : 0;
1880 if ( nAttrStartRow
<= nLastData
)
1881 nAttrStartRow
= nLastData
+ 1;
1882 SCROW nAttrSize
= pData
[nEndPos
].nRow
+ 1 - nAttrStartRow
;
1883 if ( nAttrSize
>= SC_VISATTR_STOP
&& !bFullFormattedArea
)
1884 break; // while, ignore this range and below
1885 else if ( pData
[nEndPos
].pPattern
->IsVisible() )
1887 rLastRow
= pData
[nEndPos
].nRow
;
1896 bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow
, SCROW nEndRow
) const
1899 Search( nStartRow
, nIndex
);
1900 SCROW nThisStart
= nStartRow
;
1901 bool bFound
= false;
1902 while ( nIndex
< nCount
&& nThisStart
<= nEndRow
&& !bFound
)
1904 if ( pData
[nIndex
].pPattern
->IsVisible() )
1907 nThisStart
= pData
[nIndex
].nRow
+ 1;
1914 bool ScAttrArray::IsVisibleEqual( const ScAttrArray
& rOther
,
1915 SCROW nStartRow
, SCROW nEndRow
) const
1918 SCSIZE nThisPos
= 0;
1919 SCSIZE nOtherPos
= 0;
1920 if ( nStartRow
> 0 )
1922 Search( nStartRow
, nThisPos
);
1923 rOther
.Search( nStartRow
, nOtherPos
);
1926 while ( nThisPos
<nCount
&& nOtherPos
<rOther
.nCount
&& bEqual
)
1928 SCROW nThisRow
= pData
[nThisPos
].nRow
;
1929 SCROW nOtherRow
= rOther
.pData
[nOtherPos
].nRow
;
1930 const ScPatternAttr
* pThisPattern
= pData
[nThisPos
].pPattern
;
1931 const ScPatternAttr
* pOtherPattern
= rOther
.pData
[nOtherPos
].pPattern
;
1932 bEqual
= ( pThisPattern
== pOtherPattern
||
1933 pThisPattern
->IsVisibleEqual(*pOtherPattern
) );
1935 if ( nThisRow
>= nOtherRow
)
1937 if ( nOtherRow
>= nEndRow
) break;
1940 if ( nThisRow
<= nOtherRow
)
1942 if ( nThisRow
>= nEndRow
) break;
1950 bool ScAttrArray::IsAllEqual( const ScAttrArray
& rOther
, SCROW nStartRow
, SCROW nEndRow
) const
1952 // summarised with IsVisibleEqual
1955 SCSIZE nThisPos
= 0;
1956 SCSIZE nOtherPos
= 0;
1957 if ( nStartRow
> 0 )
1959 Search( nStartRow
, nThisPos
);
1960 rOther
.Search( nStartRow
, nOtherPos
);
1963 while ( nThisPos
<nCount
&& nOtherPos
<rOther
.nCount
&& bEqual
)
1965 SCROW nThisRow
= pData
[nThisPos
].nRow
;
1966 SCROW nOtherRow
= rOther
.pData
[nOtherPos
].nRow
;
1967 const ScPatternAttr
* pThisPattern
= pData
[nThisPos
].pPattern
;
1968 const ScPatternAttr
* pOtherPattern
= rOther
.pData
[nOtherPos
].pPattern
;
1969 bEqual
= ( pThisPattern
== pOtherPattern
);
1971 if ( nThisRow
>= nOtherRow
)
1973 if ( nOtherRow
>= nEndRow
) break;
1976 if ( nThisRow
<= nOtherRow
)
1978 if ( nThisRow
>= nEndRow
) break;
1986 bool ScAttrArray::TestInsertCol( SCROW nStartRow
, SCROW nEndRow
) const
1988 // Horizontal aggregate are not allowed to be moved out; if whole summary,
1989 // here is not recognized
1995 if ( nStartRow
> 0 )
1996 Search( nStartRow
, nIndex
);
1998 for ( ; nIndex
< nCount
; nIndex
++ )
2000 if ( static_cast<const ScMergeFlagAttr
&>(pData
[nIndex
].pPattern
->
2001 GetItem(ATTR_MERGE_FLAG
)).IsHorOverlapped() )
2003 bTest
= false; // may not be pushed out
2006 if ( pData
[nIndex
].nRow
>= nEndRow
) // end of range
2013 bool ScAttrArray::TestInsertRow( SCSIZE nSize
) const
2015 // if 1st row pushed out is vertically overlapped, summary would be broken
2017 // MAXROW + 1 - nSize = 1st row pushed out
2019 SCSIZE nFirstLost
= nCount
-1;
2020 while ( nFirstLost
&& pData
[nFirstLost
-1].nRow
>= sal::static_int_cast
<SCROW
>(MAXROW
+ 1 - nSize
) )
2023 if ( static_cast<const ScMergeFlagAttr
&>(pData
[nFirstLost
].pPattern
->
2024 GetItem(ATTR_MERGE_FLAG
)).IsVerOverlapped() )
2030 void ScAttrArray::InsertRow( SCROW nStartRow
, SCSIZE nSize
)
2035 SCROW nSearch
= nStartRow
> 0 ? nStartRow
- 1 : 0; // expand predecessor
2037 Search( nSearch
, nIndex
);
2039 // set ScMergeAttr may not be extended (so behind delete again)
2041 bool bDoMerge
= static_cast<const ScMergeAttr
&>( pData
[nIndex
].pPattern
->GetItem(ATTR_MERGE
)).IsMerged();
2045 for (i
= nIndex
; i
< nCount
-1; i
++)
2047 SCROW nNew
= pData
[i
].nRow
+ nSize
;
2048 if ( nNew
>= MAXROW
) // at end?
2052 nRemove
= i
+1; // remove the following?
2054 pData
[i
].nRow
= nNew
;
2057 // Remove entries at end ?
2059 if (nRemove
&& nRemove
< nCount
)
2060 DeleteRange( nRemove
, nCount
-1 );
2062 if (bDoMerge
) // extensively repair (again) ScMergeAttr
2064 // ApplyAttr for areas
2066 const SfxPoolItem
& rDef
= pDocument
->GetPool()->GetDefaultItem( ATTR_MERGE
);
2067 for (SCSIZE nAdd
=0; nAdd
<nSize
; nAdd
++)
2068 pDocument
->ApplyAttr( nCol
, nStartRow
+nAdd
, nTab
, rDef
);
2070 // reply inserts in this area not summarized
2073 // Don't duplicate the merge flags in the inserted row.
2074 // #i108488# SC_MF_SCENARIO has to be allowed.
2075 RemoveFlags( nStartRow
, nStartRow
+nSize
-1, SC_MF_HOR
| SC_MF_VER
| SC_MF_AUTO
| SC_MF_BUTTON
);
2078 void ScAttrArray::DeleteRow( SCROW nStartRow
, SCSIZE nSize
)
2081 SCSIZE nStartIndex
= 0;
2082 SCSIZE nEndIndex
= 0;
2085 for ( i
= 0; i
< nCount
-1; i
++)
2086 if (pData
[i
].nRow
>= nStartRow
&& pData
[i
].nRow
<= sal::static_int_cast
<SCROW
>(nStartRow
+nSize
-1))
2101 nStart
= pData
[nStartIndex
-1].nRow
+ 1;
2103 if (nStart
< nStartRow
)
2105 pData
[nStartIndex
].nRow
= nStartRow
- 1;
2108 if (nEndIndex
>= nStartIndex
)
2110 DeleteRange( nStartIndex
, nEndIndex
);
2111 if (nStartIndex
> 0)
2112 if ( pData
[nStartIndex
-1].pPattern
== pData
[nStartIndex
].pPattern
)
2113 DeleteRange( nStartIndex
-1, nStartIndex
-1 );
2116 for (i
= 0; i
< nCount
-1; i
++)
2117 if (pData
[i
].nRow
>= nStartRow
)
2118 pData
[i
].nRow
-= nSize
;
2120 // Below does not follow the pattern to detect pressure ranges;
2121 // instead, only remove merge flags.
2122 RemoveFlags( MAXROW
-nSize
+1, MAXROW
, SC_MF_HOR
| SC_MF_VER
| SC_MF_AUTO
);
2125 void ScAttrArray::DeleteRange( SCSIZE nStartIndex
, SCSIZE nEndIndex
)
2127 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
2128 for (SCSIZE i
= nStartIndex
; i
<= nEndIndex
; i
++)
2129 pDocPool
->Remove(*pData
[i
].pPattern
);
2131 memmove( &pData
[nStartIndex
], &pData
[nEndIndex
+ 1], (nCount
- nEndIndex
- 1) * sizeof(ScAttrEntry
) );
2132 nCount
-= nEndIndex
-nStartIndex
+1;
2135 void ScAttrArray::DeleteArea(SCROW nStartRow
, SCROW nEndRow
)
2137 RemoveAreaMerge( nStartRow
, nEndRow
); // remove from combined flags
2139 if ( !HasAttrib( nStartRow
, nEndRow
, HASATTR_OVERLAPPED
| HASATTR_AUTOFILTER
) )
2140 SetPatternArea( nStartRow
, nEndRow
, pDocument
->GetDefPattern() );
2142 DeleteAreaSafe( nStartRow
, nEndRow
); // leave merge flags
2145 void ScAttrArray::DeleteHardAttr(SCROW nStartRow
, SCROW nEndRow
)
2147 const ScPatternAttr
* pDefPattern
= pDocument
->GetDefPattern();
2153 Search( nStartRow
, nIndex
);
2154 nThisRow
= (nIndex
>0) ? pData
[nIndex
-1].nRow
+1 : 0;
2155 if (nThisRow
< nStartRow
) nThisRow
= nStartRow
;
2157 while ( nThisRow
<= nEndRow
)
2159 const ScPatternAttr
* pOldPattern
= pData
[nIndex
].pPattern
;
2161 if ( pOldPattern
->GetItemSet().Count() ) // hard attributes ?
2163 nRow
= pData
[nIndex
].nRow
;
2164 SCROW nAttrRow
= std::min( (SCROW
)nRow
, (SCROW
)nEndRow
);
2166 ScPatternAttr
aNewPattern(*pOldPattern
);
2167 SfxItemSet
& rSet
= aNewPattern
.GetItemSet();
2168 for (sal_uInt16 nId
= ATTR_PATTERN_START
; nId
<= ATTR_PATTERN_END
; nId
++)
2169 if (nId
!= ATTR_MERGE
&& nId
!= ATTR_MERGE_FLAG
)
2170 rSet
.ClearItem(nId
);
2172 if ( aNewPattern
== *pDefPattern
)
2173 SetPatternArea( nThisRow
, nAttrRow
, pDefPattern
, false );
2175 SetPatternArea( nThisRow
, nAttrRow
, &aNewPattern
, true );
2177 Search( nThisRow
, nIndex
); // data changed
2181 nThisRow
= pData
[nIndex
-1].nRow
+1;
2186 * Move within a document
2188 void ScAttrArray::MoveTo(SCROW nStartRow
, SCROW nEndRow
, ScAttrArray
& rAttrArray
)
2190 SCROW nStart
= nStartRow
;
2191 for (SCSIZE i
= 0; i
< nCount
; i
++)
2193 if ((pData
[i
].nRow
>= nStartRow
) && (i
== 0 || pData
[i
-1].nRow
< nEndRow
))
2195 // copy (bPutToPool=TRUE)
2196 rAttrArray
.SetPatternArea( nStart
, std::min( (SCROW
)pData
[i
].nRow
, (SCROW
)nEndRow
),
2197 pData
[i
].pPattern
, true );
2199 nStart
= std::max( (SCROW
)nStart
, (SCROW
)(pData
[i
].nRow
+ 1) );
2201 DeleteArea(nStartRow
, nEndRow
);
2205 * Copy between documents (Clipboard)
2207 void ScAttrArray::CopyArea(
2208 SCROW nStartRow
, SCROW nEndRow
, long nDy
, ScAttrArray
& rAttrArray
, sal_Int16 nStripFlags
) const
2210 nStartRow
-= nDy
; // Source
2213 SCROW nDestStart
= std::max((long)((long)nStartRow
+ nDy
), (long) 0);
2214 SCROW nDestEnd
= std::min((long)((long)nEndRow
+ nDy
), (long) MAXROW
);
2216 ScDocumentPool
* pSourceDocPool
= pDocument
->GetPool();
2217 ScDocumentPool
* pDestDocPool
= rAttrArray
.pDocument
->GetPool();
2218 bool bSamePool
= (pSourceDocPool
==pDestDocPool
);
2220 for (SCSIZE i
= 0; (i
< nCount
) && (nDestStart
<= nDestEnd
); i
++)
2222 if (pData
[i
].nRow
>= nStartRow
)
2224 const ScPatternAttr
* pOldPattern
= pData
[i
].pPattern
;
2225 const ScPatternAttr
* pNewPattern
;
2227 if (IsDefaultItem( pOldPattern
))
2229 // default: nothing changed
2231 pNewPattern
= static_cast<const ScPatternAttr
*>(
2232 &pDestDocPool
->GetDefaultItem( ATTR_PATTERN
));
2234 else if ( nStripFlags
)
2236 boost::scoped_ptr
<ScPatternAttr
> pTmpPattern(new ScPatternAttr( *pOldPattern
));
2237 sal_Int16 nNewFlags
= 0;
2238 if ( nStripFlags
!= SC_MF_ALL
)
2239 nNewFlags
= static_cast<const ScMergeFlagAttr
&>(pTmpPattern
->GetItem(ATTR_MERGE_FLAG
)).
2240 GetValue() & ~nStripFlags
;
2243 pTmpPattern
->GetItemSet().Put( ScMergeFlagAttr( nNewFlags
) );
2245 pTmpPattern
->GetItemSet().ClearItem( ATTR_MERGE_FLAG
);
2248 pNewPattern
= static_cast<const ScPatternAttr
*>( &pDestDocPool
->Put(*pTmpPattern
) );
2250 pNewPattern
= pTmpPattern
->PutInPool( rAttrArray
.pDocument
, pDocument
);
2255 pNewPattern
= static_cast<const ScPatternAttr
*>( &pDestDocPool
->Put(*pOldPattern
) );
2257 pNewPattern
= pOldPattern
->PutInPool( rAttrArray
.pDocument
, pDocument
);
2260 rAttrArray
.SetPatternArea(nDestStart
,
2261 std::min((SCROW
)(pData
[i
].nRow
+ nDy
), nDestEnd
), pNewPattern
);
2264 // when pasting from clipboard and skipping filtered rows, the adjusted
2265 // end position can be negative
2266 nDestStart
= std::max((long)nDestStart
, (long)(pData
[i
].nRow
+ nDy
+ 1));
2272 * summarized with CopyArea
2274 void ScAttrArray::CopyAreaSafe( SCROW nStartRow
, SCROW nEndRow
, long nDy
, ScAttrArray
& rAttrArray
)
2276 nStartRow
-= nDy
; // Source
2279 SCROW nDestStart
= std::max((long)((long)nStartRow
+ nDy
), (long) 0);
2280 SCROW nDestEnd
= std::min((long)((long)nEndRow
+ nDy
), (long) MAXROW
);
2282 if ( !rAttrArray
.HasAttrib( nDestStart
, nDestEnd
, HASATTR_OVERLAPPED
) )
2284 CopyArea( nStartRow
+nDy
, nEndRow
+nDy
, nDy
, rAttrArray
);
2288 ScDocumentPool
* pSourceDocPool
= pDocument
->GetPool();
2289 ScDocumentPool
* pDestDocPool
= rAttrArray
.pDocument
->GetPool();
2290 bool bSamePool
= (pSourceDocPool
==pDestDocPool
);
2292 for (SCSIZE i
= 0; (i
< nCount
) && (nDestStart
<= nDestEnd
); i
++)
2294 if (pData
[i
].nRow
>= nStartRow
)
2296 const ScPatternAttr
* pOldPattern
= pData
[i
].pPattern
;
2297 const ScPatternAttr
* pNewPattern
;
2300 pNewPattern
= static_cast<const ScPatternAttr
*>( &pDestDocPool
->Put(*pOldPattern
) );
2302 pNewPattern
= pOldPattern
->PutInPool( rAttrArray
.pDocument
, pDocument
);
2304 rAttrArray
.SetPatternAreaSafe(nDestStart
,
2305 std::min((SCROW
)(pData
[i
].nRow
+ nDy
), nDestEnd
), pNewPattern
, false);
2308 // when pasting from clipboard and skipping filtered rows, the adjusted
2309 // end position can be negative
2310 nDestStart
= std::max((long)nDestStart
, (long)(pData
[i
].nRow
+ nDy
+ 1));
2314 SCsROW
ScAttrArray::SearchStyle(
2315 SCsROW nRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
2316 const ScMarkArray
* pMarkArray
) const
2318 bool bFound
= false;
2322 nRow
= pMarkArray
->GetNextMarked( nRow
, bUp
);
2323 if (!ValidRow(nRow
))
2328 Search(nRow
, nIndex
);
2329 const ScPatternAttr
* pPattern
= pData
[nIndex
].pPattern
;
2331 while (nIndex
< nCount
&& !bFound
)
2333 if (pPattern
->GetStyleSheet() == pSearchStyle
)
2337 nRow
= pMarkArray
->GetNextMarked( nRow
, bUp
);
2338 SCROW nStart
= nIndex
? pData
[nIndex
-1].nRow
+1 : 0;
2339 if (nRow
>= nStart
&& nRow
<= pData
[nIndex
].nRow
)
2358 nRow
= pData
[nIndex
].nRow
;
2359 pPattern
= pData
[nIndex
].pPattern
;
2364 nRow
= pData
[nIndex
].nRow
+1;
2367 pPattern
= pData
[nIndex
].pPattern
;
2372 OSL_ENSURE( bFound
|| !ValidRow(nRow
), "Internal failure in ScAttrArray::SearchStyle" );
2377 bool ScAttrArray::SearchStyleRange(
2378 SCsROW
& rRow
, SCsROW
& rEndRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
2379 const ScMarkArray
* pMarkArray
) const
2381 SCsROW nStartRow
= SearchStyle( rRow
, pSearchStyle
, bUp
, pMarkArray
);
2382 if (ValidRow(nStartRow
))
2385 Search(nStartRow
,nIndex
);
2391 rEndRow
= pData
[nIndex
-1].nRow
+ 1;
2396 SCROW nMarkEnd
= pMarkArray
->GetMarkEnd( nStartRow
, true );
2397 if (nMarkEnd
>rEndRow
)
2403 rEndRow
= pData
[nIndex
].nRow
;
2406 SCROW nMarkEnd
= pMarkArray
->GetMarkEnd( nStartRow
, false );
2407 if (nMarkEnd
<rEndRow
)
2418 SCSIZE
ScAttrArray::Count( SCROW nStartRow
, SCROW nEndRow
) const
2420 SCSIZE nIndex1
, nIndex2
;
2422 if( !Search( nStartRow
, nIndex1
) )
2425 if( !Search( nEndRow
, nIndex2
) )
2426 nIndex2
= nCount
- 1;
2428 return nIndex2
- nIndex1
+ 1;
2431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */