fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / attarray.cxx
blob216ede66939b946f687a352db10c08ae25758a3d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
33 #include "global.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 ) :
55 nCol( nNewCol ),
56 nTab( nNewTab ),
57 pDocument( pDoc ),
58 nCount(1),
59 nLimit(1),
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
69 TestData();
70 #endif
72 ScDocumentPool* pDocPool = pDocument->GetPool();
73 for (SCSIZE i=0; i<nCount; i++)
74 pDocPool->Remove(*pData[i].pPattern);
76 delete[] pData;
79 #if OSL_DEBUG_LEVEL > 1
80 void ScAttrArray::TestData() const
83 sal_uInt16 nErr = 0;
84 SCSIZE nPos;
85 for (nPos=0; nPos<nCount; nPos++)
87 if (nPos > 0)
88 if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow)
89 ++nErr;
90 if (pData[nPos].pPattern->Which() != ATTR_PATTERN)
91 ++nErr;
93 if ( nPos && pData[nPos-1].nRow != MAXROW )
94 ++nErr;
96 if (nErr)
98 OStringBuffer aMsg;
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());
105 #endif
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);
127 delete[] pData;
129 if (pDocument->IsStreamValid(nTab))
130 pDocument->SetStreamValid(nTab, false);
132 nCount = nLimit = 1;
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)
141 bool bRet = false;
142 if (nPos < nCount)
144 if (nPos > 0)
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;
153 nCount--;
154 nPos--;
155 bRet = true;
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;
167 nCount--;
168 bRet = true;
172 return bRet;
175 bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
177 long nHi = static_cast<long>(nCount) - 1;
178 long i = 0;
179 bool bFound = (nCount == 1);
180 long nLo = 0;
181 long nStartRow = 0;
182 while ( !bFound && nLo <= nHi )
184 i = (nLo + nHi) / 2;
185 if (i > 0)
186 nStartRow = (long) pData[i - 1].nRow;
187 else
188 nStartRow = -1;
189 const long nEndRow = (long) pData[i].nRow;
190 if (nEndRow < (long) nRow)
191 nLo = ++i;
192 else
193 if (nStartRow >= (long) nRow)
194 nHi = --i;
195 else
196 bFound = true;
199 if (bFound)
200 nIndex=(SCSIZE)i;
201 else
202 nIndex=0;
203 return bFound;
206 const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
208 SCSIZE i;
209 if (Search( nRow, i ))
210 return pData[i].pPattern;
211 else
212 return NULL;
215 const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
216 SCROW& rEndRow, SCROW nRow ) const
218 SCSIZE nIndex;
219 if ( Search( nRow, nIndex ) )
221 if ( nIndex > 0 )
222 rStartRow = pData[nIndex-1].nRow + 1;
223 else
224 rStartRow = 0;
225 rEndRow = pData[nIndex].nRow;
226 return pData[nIndex].pPattern;
228 return NULL;
231 void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
233 if(!ValidRow(nStartRow) || !ValidRow(nEndRow))
234 return;
236 if(nEndRow < nStartRow)
237 return;
239 SCROW nTempStartRow = nStartRow;
240 SCROW nTempEndRow = nEndRow;
244 const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
246 boost::scoped_ptr<ScPatternAttr> pNewPattern;
247 if(pPattern)
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;
258 if(pItem)
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 );
266 else
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))
285 return;
287 if(nEndRow < nStartRow)
288 return;
290 SCROW nTempStartRow = nStartRow;
291 SCROW nTempEndRow = nEndRow;
295 const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
297 if(pPattern)
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 );
307 if(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;
314 if (nIndex == 0)
315 aCondFormatData.clear();
316 else
317 aCondFormatData.erase(itr);
318 aItem.SetCondFormatData( aCondFormatData );
319 aPattern.GetItemSet().Put( aItem );
320 SetPatternArea( nTempStartRow, nTempEndRow, &aPattern, true );
324 else
326 return;
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)
349 continue;
351 EditTextObject* pOldData = NULL;
352 if (pDataArray)
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);
359 if (pDataArray)
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] )
373 nLimit = nReserve;
374 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
375 delete[] pData;
376 pData = pNewData;
377 return true;
379 else
380 return false;
382 else
383 return false;
386 void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern,
387 bool bPutToPool, ScEditDataArray* pDataArray )
389 if (ValidRow(nStartRow) && ValidRow(nEndRow))
391 if (bPutToPool)
392 pPattern = static_cast<const ScPatternAttr*>(&pDocument->GetPool()->Put(*pPattern));
394 if ((nStartRow == 0) && (nEndRow == MAXROW))
395 Reset(pPattern);
396 else
398 SCSIZE nNeeded = nCount + 2;
399 if ( nLimit < nNeeded )
401 nLimit += SC_ATTRARRAY_DELTA;
402 if ( nLimit < nNeeded )
403 nLimit = nNeeded;
404 ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
405 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
406 delete[] pData;
407 pData = pNewData;
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
416 if ( nStartRow > 0 )
418 // skip beginning
419 SCSIZE nIndex;
420 Search( nStartRow, nIndex );
421 ni = nIndex;
423 if ( ni > 0 )
425 nx = ni;
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,
439 rNewSet, rOldSet ) )
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;
446 nx++;
449 // continue modifying data array
451 SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
452 bool bCombined = false;
453 bool bSplit = false;
454 if ( nStartRow > 0 )
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 )
463 bSplit = true;
464 ni++;
465 nInsert = ni;
467 else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
468 nInsert = ni;
470 if ( ni > 0 && pData[ni-1].pPattern == pPattern )
471 { // combine
472 pData[ni-1].nRow = nEndRow;
473 nInsert = MAXROWCOUNT;
474 bCombined = true;
477 else
478 nInsert = 0;
480 SCSIZE nj = ni; // stop position of range to replace
481 while ( nj < nCount && pData[nj].nRow <= nEndRow )
482 nj++;
483 if ( !bSplit )
485 if ( nj < nCount && pData[nj].pPattern == pPattern )
486 { // combine
487 if ( ni > 0 )
489 if ( pData[ni-1].pPattern == pPattern )
490 { // adjacent entries
491 pData[ni-1].nRow = pData[nj].nRow;
492 nj++;
494 else if ( ni == nInsert )
495 pData[ni-1].nRow = nStartRow - 1; // shrink
497 nInsert = MAXROWCOUNT;
498 bCombined = true;
500 else if ( ni > 0 && ni == nInsert )
501 pData[ni-1].nRow = nStartRow - 1; // shrink
503 ScDocumentPool* pDocPool = pDocument->GetPool();
504 if ( bSplit )
505 { // duplicate splitted entry in pool
506 pDocPool->Put( *pData[ni-1].pPattern );
508 if ( ni < nj )
509 { // remove middle entries
510 for ( SCSIZE nk=ni; nk<nj; nk++)
511 { // remove entries from pool
512 pDocPool->Remove( *pData[nk].pPattern );
514 if ( !bCombined )
515 { // replace one entry
516 pData[ni].nRow = nEndRow;
517 pData[ni].pPattern = pPattern;
518 ni++;
519 nInsert = MAXROWCOUNT;
521 if ( ni < nj )
522 { // remove entries
523 memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
524 nCount -= nj - ni;
528 if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
529 { // insert or append new entry
530 if ( nInsert <= nCount )
532 if ( !bSplit )
533 memmove( pData + nInsert + 1, pData + nInsert,
534 (nCount - nInsert) * sizeof(ScAttrEntry) );
535 else
537 memmove( pData + nInsert + 2, pData + nInsert,
538 (nCount - nInsert) * sizeof(ScAttrEntry) );
539 pData[nInsert+1] = pData[nInsert-1];
540 nCount++;
543 if ( nInsert )
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.
550 if (pDataArray)
551 RemoveCellCharAttribs(nStartRow, nEndRow, pPattern, pDataArray);
553 nCount++;
556 if (pDocument->IsStreamValid(nTab))
557 pDocument->SetStreamValid(nTab, false);
561 #if OSL_DEBUG_LEVEL > 1
562 TestData();
563 #endif
566 void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
568 if (ValidRow(nStartRow) && ValidRow(nEndRow))
570 SCSIZE nPos;
571 SCROW nStart=0;
572 if (!Search( nStartRow, nPos ))
574 OSL_FAIL("Search Failure");
575 return;
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);
586 SCROW nY1 = nStart;
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
594 nPos++;
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 );
603 else
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,
612 rNewSet, rOldSet ) )
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));
622 if (Concat(nPos))
623 Search(nStart, nPos);
624 else
625 nPos++;
628 while ((nStart <= nEndRow) && (nPos < nCount));
630 if (pDocument->IsStreamValid(nTab))
631 pDocument->SetStreamValid(nTab, false);
634 #if OSL_DEBUG_LEVEL > 1
635 TestData();
636 #endif
639 // const cast, otherwise it will be too inefficient/complicated
640 #define SET_LINECOLOR(dest,c) \
641 if ((dest)) \
643 const_cast<SvxBorderLine*>(dest)->SetColor((c)); \
646 #define SET_LINE(dest,src) \
647 if ((dest)) \
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 )
658 return;
660 if (ValidRow(nStartRow) && ValidRow(nEndRow))
662 SCSIZE nPos;
663 SCROW nStart=0;
664 if (!Search( nStartRow, nPos ))
666 OSL_FAIL("Search failure");
667 return;
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();
685 SCROW nY1 = nStart;
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
694 if ( !pLine )
696 if( pNewBoxItem )
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 );
708 else
710 if ( bColorOnly )
712 Color aColor( pLine->GetColor() );
713 if( pNewBoxItem )
715 SET_LINECOLOR( pNewBoxItem->GetTop(), aColor );
716 SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
717 SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor );
718 SET_LINECOLOR( pNewBoxItem->GetRight(), aColor );
720 if( pNewTLBRItem )
721 SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
722 if( pNewBLTRItem )
723 SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
725 else
727 if( pNewBoxItem )
729 SET_LINE( pNewBoxItem->GetTop(), pLine );
730 SET_LINE( pNewBoxItem->GetBottom(), pLine );
731 SET_LINE( pNewBoxItem->GetLeft(), pLine );
732 SET_LINE( pNewBoxItem->GetRight(), pLine );
734 if( pNewTLBRItem )
735 SET_LINE( pNewTLBRItem->GetLine(), pLine );
736 if( pNewBLTRItem )
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 );
753 else
755 // remove from pool ?
756 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
757 pData[nPos].pPattern = static_cast<const ScPatternAttr*>(
758 &pDocument->GetPool()->Put(*pNewPattern) );
760 if (Concat(nPos))
761 Search(nStart, nPos);
762 else
763 nPos++;
765 delete pNewBoxItem;
766 delete pNewTLBRItem;
767 delete pNewBLTRItem;
769 else
771 nStart = pData[nPos].nRow + 1;
772 nPos++;
775 while ((nStart <= nEndRow) && (nPos < nCount));
779 #undef SET_LINECOLOR
780 #undef SET_LINE
782 void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray )
784 #if OSL_DEBUG_LEVEL > 1
785 TestData();
786 #endif
788 if (ValidRow(nStartRow) && ValidRow(nEndRow))
790 SCSIZE nPos;
791 SCROW nStart=0;
792 if (!Search( nStartRow, nPos ))
794 OSL_FAIL("Search Failure");
795 return;
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)
809 SCROW nY1 = nStart;
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 );
820 else
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,
829 rNewSet, rOldSet ) )
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;
838 if (Concat(nPos))
839 Search(nStart, nPos);
840 else
841 ++nPos;
844 else
846 nStart = pData[nPos].nRow + 1;
847 ++nPos;
850 while (nStart <= nEndRow);
852 if (pDocument->IsStreamValid(nTab))
853 pDocument->SetStreamValid(nTab, false);
856 #if OSL_DEBUG_LEVEL > 1
857 TestData();
858 #endif
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);
867 delete[] pData;
869 pData = pNewData;
870 nCount = nLimit = nSize;
871 return true;
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 );
900 else // Default
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))
915 SCSIZE nPos;
916 SCROW nStart=0;
917 if (!Search( nStartRow, nPos ))
919 OSL_FAIL("Search failure");
920 return;
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();
930 if (rState.pItemSet)
932 if (bDeep)
933 lcl_MergeDeep( *rState.pItemSet, rThisSet );
934 else
935 rState.pItemSet->MergeValues( rThisSet, false );
937 else
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;
949 ++nPos;
951 while (nStart <= nEndRow);
955 // assemble border
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;
966 rpNew = pNewLine;
967 return true; // initial value
970 if (pOldLine == pNewLine)
972 rpNew = pOldLine;
973 return false;
976 if (pOldLine && pNewLine)
977 if (*pOldLine == *pNewLine)
979 rpNew = pOldLine;
980 return false;
983 rModified = SC_LINE_DONTCARE;
984 rpNew = NULL;
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 )
995 nDistRight = 0;
996 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
997 nDistBottom = 0;
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;
1006 if (bTop)
1008 if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
1009 pLineOuter->SetLine( pNew, SvxBoxItemLine::TOP );
1011 else
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 );
1022 else
1024 if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
1025 pLineInner->SetLine( pNew, SvxBoxInfoItemLine::HORI );
1028 if (bLeft)
1030 if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
1031 pLineOuter->SetLine( pNew, SvxBoxItemLine::LEFT );
1033 else
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 );
1044 else
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 );
1062 else
1064 pPattern = GetPattern( nStartRow );
1065 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true,
1066 nEndRow-nStartRow );
1068 SCSIZE nStartIndex;
1069 SCSIZE nEndIndex;
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 );
1085 // apply border
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 )
1103 nDistRight = 0;
1104 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1105 nDistBottom = 0;
1107 SvxBoxItem aNewFrame( *pOldFrame );
1108 bool bRTL=pDocument->IsLayoutRTL(nTab);
1109 // fdo#37464 check if the sheet are RTL then replace right <=> left
1110 if (bRTL)
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 );
1119 else
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 );
1129 else
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)
1147 // nothing to do
1148 return false;
1150 else
1152 SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
1153 ApplyCacheArea( nStartRow, nEndRow, &aCache );
1155 return true;
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 );
1164 else
1166 ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1167 true, nEndRow-nStartRow );
1169 if ( nEndRow > nStartRow+1 ) // inner part available?
1171 SCSIZE nStartIndex;
1172 SCSIZE nEndIndex;
1173 Search( nStartRow+1, nStartIndex );
1174 Search( nEndRow-1, nEndIndex );
1175 SCROW nTmpStart = nStartRow+1;
1176 SCROW nTmpEnd;
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;
1183 if (bChanged)
1185 Search(nTmpStart, i);
1186 Search(nEndRow-1, nEndIndex);
1188 else
1189 i++;
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
1201 SCSIZE nStartIndex;
1202 SCSIZE nEndIndex;
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 )
1215 bFound = true;
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() )
1222 bFound = true;
1223 if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
1224 bFound = true;
1225 if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
1226 bFound = true;
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() )
1233 bFound = true;
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 )
1240 bFound = true;
1242 if ( nMask & HASATTR_CONDITIONAL )
1244 bool bContainsCondFormat =
1245 !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
1246 if ( bContainsCondFormat )
1247 bFound = true;
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() )
1255 bFoundTemp = true;
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() )
1273 bFoundCond = true;
1274 else
1275 break;
1277 else
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;
1289 if(bFoundTemp)
1290 bFound = true;
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 )
1300 bFound = true;
1302 if ( nMask & HASATTR_NEEDHEIGHT )
1304 if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
1305 bFound = true;
1306 else if (static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
1307 bFound = true;
1308 else if ((SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
1309 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
1310 bFound = true;
1312 else if (!static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL)).GetCondFormatData().empty())
1313 bFound = true;
1314 else if (static_cast<const SfxInt32Item&>(pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
1315 bFound = true;
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 )
1324 bFound = true;
1325 if ( nMask & HASATTR_SHADOW_DOWN )
1326 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1327 bFound = true;
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 )
1334 bFound = true;
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 )
1342 bFound = true;
1346 return bFound;
1349 bool ScAttrArray::IsMerged( SCROW nRow ) const
1351 SCSIZE nIndex;
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,
1364 bool bRefresh )
1366 const ScPatternAttr* pPattern;
1367 const ScMergeAttr* pItem;
1368 SCSIZE nStartIndex;
1369 SCSIZE nEndIndex;
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;
1389 bFound = true;
1391 if (bRefresh)
1393 if ( nMergeEndCol > nThisCol )
1394 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
1395 nTab, SC_MF_HOR );
1396 if ( nMergeEndRow > nThisRow )
1397 pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1398 nTab, SC_MF_VER );
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 );
1410 return bFound;
1413 bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1415 bool bFound = false;
1416 const ScPatternAttr* pPattern;
1417 const ScMergeAttr* pItem;
1418 SCSIZE nIndex;
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)
1429 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
1462 ++nIndex;
1463 if ( nIndex < nCount )
1464 nThisStart = pData[nIndex-1].nRow+1;
1465 else
1466 nThisStart = MAXROW+1; // End
1469 return bFound;
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;
1486 SCSIZE nIndex;
1487 SCROW nRow;
1488 SCROW nThisRow;
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 );
1514 else
1516 if ( !bDefault )
1518 if (bFirstUse)
1519 bFirstUse = false;
1520 else
1521 // it's in the pool
1522 pDocument->GetPool()->Put( *pWantedPattern );
1524 SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
1527 Search( nThisRow, nIndex ); // data changed
1530 ++nIndex;
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;
1540 SCSIZE nIndex;
1541 SCROW nRow;
1542 SCROW nThisRow;
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
1561 bChanged = true;
1564 ++nIndex;
1565 nThisRow = pData[nIndex-1].nRow+1;
1568 return bChanged;
1571 bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1573 const ScPatternAttr* pOldPattern;
1575 sal_Int16 nOldValue;
1576 SCSIZE nIndex;
1577 SCROW nRow;
1578 SCROW nThisRow;
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
1597 bChanged = true;
1600 ++nIndex;
1601 nThisRow = pData[nIndex-1].nRow+1;
1604 return bChanged;
1607 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
1609 SCSIZE nIndex;
1610 SCROW nRow;
1611 SCROW nThisRow;
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
1631 ++nIndex;
1632 nThisRow = pData[nIndex-1].nRow+1;
1636 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement )
1638 SCSIZE nIndex;
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);
1656 if ( bIncrement )
1658 if ( nNewValue < nColWidth-SC_INDENT_STEP )
1660 nNewValue += SC_INDENT_STEP;
1661 if ( nNewValue > nColWidth-SC_INDENT_STEP ) nNewValue = nColWidth-SC_INDENT_STEP;
1664 else
1666 if ( nNewValue > 0 )
1668 if ( nNewValue > SC_INDENT_STEP )
1669 nNewValue -= SC_INDENT_STEP;
1670 else
1671 nNewValue = 0;
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 ) );
1681 if ( bNeedJust )
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
1689 else
1691 nThisStart = pData[nIndex].nRow + 1;
1692 ++nIndex;
1697 SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, bool bUp ) const
1699 long nRet = nRow;
1700 if (ValidRow(nRow))
1702 SCSIZE nIndex;
1703 Search(nRow, nIndex);
1704 while (static_cast<const ScProtectionAttr&>(pData[nIndex].pPattern->
1705 GetItem(ATTR_PROTECTION)).GetProtection())
1707 if (bUp)
1709 if (nIndex==0)
1710 return -1; // not found
1711 --nIndex;
1712 nRet = pData[nIndex].nRow;
1714 else
1716 nRet = pData[nIndex].nRow+1;
1717 ++nIndex;
1718 if (nIndex>=nCount)
1719 return MAXROW+1; // not found
1723 return nRet;
1726 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1728 SCROW nStart = 0;
1729 SCSIZE nPos = 0;
1730 while (nPos < nCount)
1732 SCROW nEnd = pData[nPos].nRow;
1733 if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1735 rUsedRows.setTrue(nStart, nEnd);
1737 if (bReset)
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();
1750 if (Concat(nPos))
1752 Search(nStart, nPos);
1753 --nPos; // because ++ at end
1757 nStart = nEnd + 1;
1758 ++nPos;
1762 bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
1763 bool bGatherAllStyles ) const
1765 bool bIsUsed = false;
1766 SCSIZE nPos = 0;
1768 while ( nPos < nCount )
1770 const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
1771 if ( pStyle )
1773 pStyle->SetUsage( ScStyleSheet::USED );
1774 if ( pStyle == &rStyle )
1776 if ( !bGatherAllStyles )
1777 return true;
1778 bIsUsed = true;
1781 nPos++;
1784 return bIsUsed;
1787 bool ScAttrArray::IsEmpty() const
1789 if (nCount == 1)
1791 if ( pData[0].pPattern != pDocument->GetDefPattern() )
1792 return false;
1793 else
1794 return true;
1796 else
1797 return false;
1800 bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1802 OSL_ENSURE( nCount, "nCount == 0" );
1804 bool bFound = false;
1805 SCSIZE nStart = 0;
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) )
1812 ++nVisStart;
1813 if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row?
1814 nStart = nVisStart;
1816 while ( nStart < nCount && !bFound )
1818 if ( pData[nStart].pPattern->IsVisible() )
1820 rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
1821 bFound = true;
1823 else
1824 ++nStart;
1827 return bFound;
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
1846 return true;
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;
1858 return true;
1860 else
1862 // Ignore here a few rows if data happens to end within
1863 // SC_VISATTR_STOP rows before MAXROW.
1864 rLastRow = nLastData;
1865 return false;
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))
1878 ++nEndPos;
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;
1888 bFound = true;
1890 nPos = nEndPos + 1;
1893 return bFound;
1896 bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1898 SCSIZE nIndex;
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() )
1905 bFound = true;
1907 nThisStart = pData[nIndex].nRow + 1;
1908 ++nIndex;
1911 return bFound;
1914 bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
1915 SCROW nStartRow, SCROW nEndRow ) const
1917 bool bEqual = true;
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;
1938 ++nOtherPos;
1940 if ( nThisRow <= nOtherRow )
1942 if ( nThisRow >= nEndRow ) break;
1943 ++nThisPos;
1947 return bEqual;
1950 bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
1952 // summarised with IsVisibleEqual
1954 bool bEqual = true;
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;
1974 ++nOtherPos;
1976 if ( nThisRow <= nOtherRow )
1978 if ( nThisRow >= nEndRow ) break;
1979 ++nThisPos;
1983 return bEqual;
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
1991 bool bTest = true;
1992 if (!IsEmpty())
1994 SCSIZE nIndex = 0;
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
2004 break;
2006 if ( pData[nIndex].nRow >= nEndRow ) // end of range
2007 break;
2010 return bTest;
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) )
2021 --nFirstLost;
2023 if ( static_cast<const ScMergeFlagAttr&>(pData[nFirstLost].pPattern->
2024 GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2025 return false;
2027 return true;
2030 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2032 if (!pData)
2033 return;
2035 SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // expand predecessor
2036 SCSIZE nIndex;
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();
2043 SCSIZE nRemove = 0;
2044 SCSIZE i;
2045 for (i = nIndex; i < nCount-1; i++)
2047 SCROW nNew = pData[i].nRow + nSize;
2048 if ( nNew >= MAXROW ) // at end?
2050 nNew = MAXROW;
2051 if (!nRemove)
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 )
2080 bool bFirst=true;
2081 SCSIZE nStartIndex = 0;
2082 SCSIZE nEndIndex = 0;
2083 SCSIZE i;
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))
2088 if (bFirst)
2090 nStartIndex = i;
2091 bFirst = false;
2093 nEndIndex = i;
2095 if (!bFirst)
2097 SCROW nStart;
2098 if (nStartIndex==0)
2099 nStart = 0;
2100 else
2101 nStart = pData[nStartIndex-1].nRow + 1;
2103 if (nStart < nStartRow)
2105 pData[nStartIndex].nRow = nStartRow - 1;
2106 ++nStartIndex;
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() );
2141 else
2142 DeleteAreaSafe( nStartRow, nEndRow ); // leave merge flags
2145 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2147 const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2149 SCSIZE nIndex;
2150 SCROW nRow;
2151 SCROW nThisRow;
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 );
2174 else
2175 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
2177 Search( nThisRow, nIndex ); // data changed
2180 ++nIndex;
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
2211 nEndRow -= nDy;
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;
2242 if ( nNewFlags )
2243 pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2244 else
2245 pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2247 if (bSamePool)
2248 pNewPattern = static_cast<const ScPatternAttr*>( &pDestDocPool->Put(*pTmpPattern) );
2249 else
2250 pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2252 else
2254 if (bSamePool)
2255 pNewPattern = static_cast<const ScPatternAttr*>( &pDestDocPool->Put(*pOldPattern) );
2256 else
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));
2271 * Leave flags
2272 * summarized with CopyArea
2274 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2276 nStartRow -= nDy; // Source
2277 nEndRow -= nDy;
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 );
2285 return;
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;
2299 if (bSamePool)
2300 pNewPattern = static_cast<const ScPatternAttr*>( &pDestDocPool->Put(*pOldPattern) );
2301 else
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;
2320 if (pMarkArray)
2322 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2323 if (!ValidRow(nRow))
2324 return nRow;
2327 SCSIZE nIndex;
2328 Search(nRow, nIndex);
2329 const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2331 while (nIndex < nCount && !bFound)
2333 if (pPattern->GetStyleSheet() == pSearchStyle)
2335 if (pMarkArray)
2337 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2338 SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2339 if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2340 bFound = true;
2342 else
2343 bFound = true;
2346 if (!bFound)
2348 if (bUp)
2350 if (nIndex==0)
2352 nIndex = nCount;
2353 nRow = -1;
2355 else
2357 --nIndex;
2358 nRow = pData[nIndex].nRow;
2359 pPattern = pData[nIndex].pPattern;
2362 else
2364 nRow = pData[nIndex].nRow+1;
2365 ++nIndex;
2366 if (nIndex<nCount)
2367 pPattern = pData[nIndex].pPattern;
2372 OSL_ENSURE( bFound || !ValidRow(nRow), "Internal failure in ScAttrArray::SearchStyle" );
2374 return nRow;
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))
2384 SCSIZE nIndex;
2385 Search(nStartRow,nIndex);
2387 rRow = nStartRow;
2388 if (bUp)
2390 if (nIndex>0)
2391 rEndRow = pData[nIndex-1].nRow + 1;
2392 else
2393 rEndRow = 0;
2394 if (pMarkArray)
2396 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
2397 if (nMarkEnd>rEndRow)
2398 rEndRow = nMarkEnd;
2401 else
2403 rEndRow = pData[nIndex].nRow;
2404 if (pMarkArray)
2406 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
2407 if (nMarkEnd<rEndRow)
2408 rEndRow = nMarkEnd;
2412 return true;
2414 else
2415 return false;
2418 SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) const
2420 SCSIZE nIndex1, nIndex2;
2422 if( !Search( nStartRow, nIndex1 ) )
2423 return 0;
2425 if( !Search( nEndRow, nIndex2 ) )
2426 nIndex2 = nCount - 1;
2428 return nIndex2 - nIndex1 + 1;
2431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */