Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / attarray.cxx
blobcee38bb8823db178186e9bb0e091bffbb49bccae
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>
49 // STATIC DATA -----------------------------------------------------------
51 //------------------------------------------------------------------------
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 //------------------------------------------------------------------------
68 ScAttrArray::~ScAttrArray()
70 #if OSL_DEBUG_LEVEL > 1
71 TestData();
72 #endif
74 ScDocumentPool* pDocPool = pDocument->GetPool();
75 for (SCSIZE i=0; i<nCount; i++)
76 pDocPool->Remove(*pData[i].pPattern);
78 delete[] pData;
81 //------------------------------------------------------------------------
82 #if OSL_DEBUG_LEVEL > 1
83 void ScAttrArray::TestData() const
86 sal_uInt16 nErr = 0;
87 SCSIZE nPos;
88 for (nPos=0; nPos<nCount; nPos++)
90 if (nPos > 0)
91 if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow)
92 ++nErr;
93 if (pData[nPos].pPattern->Which() != ATTR_PATTERN)
94 ++nErr;
96 if ( nPos && pData[nPos-1].nRow != MAXROW )
97 ++nErr;
99 if (nErr)
101 OStringBuffer aMsg;
102 aMsg.append(static_cast<sal_Int32>(nErr));
103 aMsg.append(" errors in attribute array, column ");
104 aMsg.append(static_cast<sal_Int32>(nCol));
105 OSL_FAIL(aMsg.getStr());
108 #endif
110 //------------------------------------------------------------------------
112 void ScAttrArray::Reset( const ScPatternAttr* pPattern )
114 ScDocumentPool* pDocPool = pDocument->GetPool();
115 const ScPatternAttr* pOldPattern;
116 ScAddress aAdrStart( nCol, 0, nTab );
117 ScAddress aAdrEnd ( nCol, 0, nTab );
119 for (SCSIZE i=0; i<nCount; i++)
121 // ensure that attributing changes text width of cell
122 pOldPattern = pData[i].pPattern;
123 bool bNumFormatChanged;
124 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
125 pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
127 aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
128 aAdrEnd .SetRow( pData[i].nRow );
129 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
131 pDocPool->Remove(*pOldPattern);
133 delete[] pData;
135 if (pDocument->IsStreamValid(nTab))
136 pDocument->SetStreamValid(nTab, false);
138 nCount = nLimit = 1;
139 pData = new ScAttrEntry[1];
140 ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
141 pData[0].nRow = MAXROW;
142 pData[0].pPattern = pNewPattern;
146 bool ScAttrArray::Concat(SCSIZE nPos)
148 bool bRet = false;
149 if (nPos < nCount)
151 if (nPos > 0)
153 if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
155 pData[nPos - 1].nRow = pData[nPos].nRow;
156 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
157 memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
158 pData[nCount - 1].pPattern = NULL;
159 pData[nCount - 1].nRow = 0;
160 nCount--;
161 nPos--;
162 bRet = true;
165 if (nPos + 1 < nCount)
167 if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
169 pData[nPos].nRow = pData[nPos + 1].nRow;
170 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
171 memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
172 pData[nCount - 1].pPattern = NULL;
173 pData[nCount - 1].nRow = 0;
174 nCount--;
175 bRet = true;
179 return bRet;
182 //------------------------------------------------------------------------
184 bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
186 long nHi = static_cast<long>(nCount) - 1;
187 long i = 0;
188 bool bFound = (nCount == 1);
189 long nLo = 0;
190 long nStartRow = 0;
191 long nEndRow = 0;
192 while ( !bFound && nLo <= nHi )
194 i = (nLo + nHi) / 2;
195 if (i > 0)
196 nStartRow = (long) pData[i - 1].nRow;
197 else
198 nStartRow = -1;
199 nEndRow = (long) pData[i].nRow;
200 if (nEndRow < (long) nRow)
201 nLo = ++i;
202 else
203 if (nStartRow >= (long) nRow)
204 nHi = --i;
205 else
206 bFound = true;
209 if (bFound)
210 nIndex=(SCSIZE)i;
211 else
212 nIndex=0;
213 return bFound;
217 const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
219 SCSIZE i;
220 if (Search( nRow, i ))
221 return pData[i].pPattern;
222 else
223 return NULL;
227 const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
228 SCROW& rEndRow, SCROW nRow ) const
230 SCSIZE nIndex;
231 if ( Search( nRow, nIndex ) )
233 if ( nIndex > 0 )
234 rStartRow = pData[nIndex-1].nRow + 1;
235 else
236 rStartRow = 0;
237 rEndRow = pData[nIndex].nRow;
238 return pData[nIndex].pPattern;
240 return NULL;
243 void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
245 if(!ValidRow(nStartRow) || !ValidRow(nEndRow))
246 return;
248 if(nEndRow < nStartRow)
249 return;
251 SCROW nTempStartRow = nStartRow;
252 SCROW nTempEndRow = nEndRow;
256 const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
258 boost::scoped_ptr<ScPatternAttr> pNewPattern;
259 if(pPattern)
261 pNewPattern.reset( new ScPatternAttr(*pPattern) );
262 SCROW nPatternStartRow;
263 SCROW nPatternEndRow;
264 GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
266 nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
267 const SfxPoolItem* pItem = NULL;
268 pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
269 std::vector< sal_uInt32 > aCondFormatData;
270 if(pItem)
271 aCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
272 aCondFormatData.push_back(nIndex);
274 ScCondFormatItem aItem;
275 aItem.SetCondFormatData( aCondFormatData );
276 pNewPattern->GetItemSet().Put( aItem );
278 else
280 pNewPattern.reset( new ScPatternAttr( pDocument->GetPool() ) );
281 ScCondFormatItem aItem;
282 aItem.AddCondFormatData(nIndex);
283 pNewPattern->GetItemSet().Put( aItem );
284 nTempEndRow = nEndRow;
287 SetPatternArea( nTempStartRow, nTempEndRow, pNewPattern.get(), true );
288 nTempStartRow = nTempEndRow + 1;
290 while(nTempEndRow < nEndRow);
294 void ScAttrArray::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
296 if(!ValidRow(nStartRow) || !ValidRow(nEndRow))
297 return;
299 if(nEndRow < nStartRow)
300 return;
302 SCROW nTempStartRow = nStartRow;
303 SCROW nTempEndRow = nEndRow;
307 const ScPatternAttr* pPattern = GetPattern(nTempStartRow);
309 if(pPattern)
311 ScPatternAttr aPattern( *pPattern );
312 SCROW nPatternStartRow;
313 SCROW nPatternEndRow;
314 GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow );
316 nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow );
317 const SfxPoolItem* pItem = NULL;
318 pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem );
319 if(pItem)
321 std::vector< sal_uInt32 > aCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData();
322 std::vector<sal_uInt32>::iterator itr = std::find(aCondFormatData.begin(), aCondFormatData.end(), nIndex);
323 if(itr != aCondFormatData.end())
325 ScCondFormatItem aItem;
326 aCondFormatData.erase(itr);
327 aItem.SetCondFormatData( aCondFormatData );
328 aPattern.GetItemSet().Put( aItem );
329 SetPatternArea( nTempStartRow, nTempEndRow, &aPattern, true );
334 else
336 return;
339 nTempStartRow = nTempEndRow + 1;
341 while(nTempEndRow < nEndRow);
345 //------------------------------------------------------------------------
347 void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, bool bPutToPool )
349 SetPatternArea( nRow, nRow, pPattern, bPutToPool );
352 void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
353 const ScPatternAttr* pPattern, ScEditDataArray* pDataArray )
355 for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
357 ScAddress aPos(nCol, nRow, nTab);
358 ScRefCellValue aCell;
359 aCell.assign(*pDocument, aPos);
360 if (aCell.meType != CELLTYPE_EDIT || !aCell.mpEditText)
361 continue;
363 EditTextObject* pOldData = NULL;
364 if (pDataArray)
365 pOldData = aCell.mpEditText->Clone();
367 // Direct modification of cell content - something to watch out for if
368 // we decide to share edit text instances in the future.
369 ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject&>(*aCell.mpEditText), *pPattern);
371 if (pDataArray)
373 EditTextObject* pNewData = aCell.mpEditText->Clone();
374 pDataArray->AddItem(nTab, nCol, nRow, pOldData, pNewData);
379 void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern,
380 bool bPutToPool, ScEditDataArray* pDataArray )
382 if (ValidRow(nStartRow) && ValidRow(nEndRow))
384 if (bPutToPool)
385 pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern);
387 if ((nStartRow == 0) && (nEndRow == MAXROW))
388 Reset(pPattern);
389 else
391 SCSIZE nNeeded = nCount + 2;
392 if ( nLimit < nNeeded )
394 nLimit += SC_ATTRARRAY_DELTA;
395 if ( nLimit < nNeeded )
396 nLimit = nNeeded;
397 ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
398 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
399 delete[] pData;
400 pData = pNewData;
403 ScAddress aAdrStart( nCol, 0, nTab );
404 ScAddress aAdrEnd ( nCol, 0, nTab );
406 SCSIZE ni = 0; // number of entries in beginning
407 SCSIZE nx = 0; // track position
408 SCROW ns = 0; // start row of track position
409 if ( nStartRow > 0 )
411 // skip beginning
412 SCSIZE nIndex;
413 Search( nStartRow, nIndex );
414 ni = nIndex;
416 if ( ni > 0 )
418 nx = ni;
419 ns = pData[ni-1].nRow+1;
423 // ensure that attributing changes text width of cell
424 // otherwise, conditional formats need to be reset or deleted
425 while ( ns <= nEndRow )
427 const SfxItemSet& rNewSet = pPattern->GetItemSet();
428 const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
430 bool bNumFormatChanged;
431 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
432 rNewSet, rOldSet ) )
434 aAdrStart.SetRow( std::max(nStartRow,ns) );
435 aAdrEnd .SetRow( std::min(nEndRow,pData[nx].nRow) );
436 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
438 ns = pData[nx].nRow + 1;
439 nx++;
442 // continue modifying data array
444 SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
445 bool bCombined = false;
446 bool bSplit = false;
447 if ( nStartRow > 0 )
449 nInsert = MAXROWCOUNT;
450 if ( pData[ni].pPattern != pPattern )
452 if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
453 { // may be a split or a simple insert or just a shrink,
454 // row adjustment is done further down
455 if ( pData[ni].nRow > nEndRow )
456 bSplit = true;
457 ni++;
458 nInsert = ni;
460 else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
461 nInsert = ni;
463 if ( ni > 0 && pData[ni-1].pPattern == pPattern )
464 { // combine
465 pData[ni-1].nRow = nEndRow;
466 nInsert = MAXROWCOUNT;
467 bCombined = true;
470 else
471 nInsert = 0;
473 SCSIZE nj = ni; // stop position of range to replace
474 while ( nj < nCount && pData[nj].nRow <= nEndRow )
475 nj++;
476 if ( !bSplit )
478 if ( nj < nCount && pData[nj].pPattern == pPattern )
479 { // combine
480 if ( ni > 0 )
482 if ( pData[ni-1].pPattern == pPattern )
483 { // adjacent entries
484 pData[ni-1].nRow = pData[nj].nRow;
485 nj++;
487 else if ( ni == nInsert )
488 pData[ni-1].nRow = nStartRow - 1; // shrink
490 nInsert = MAXROWCOUNT;
491 bCombined = true;
493 else if ( ni > 0 && ni == nInsert )
494 pData[ni-1].nRow = nStartRow - 1; // shrink
496 ScDocumentPool* pDocPool = pDocument->GetPool();
497 if ( bSplit )
498 { // duplicate splitted entry in pool
499 pDocPool->Put( *pData[ni-1].pPattern );
501 if ( ni < nj )
502 { // remove middle entries
503 for ( SCSIZE nk=ni; nk<nj; nk++)
504 { // remove entries from pool
505 pDocPool->Remove( *pData[nk].pPattern );
507 if ( !bCombined )
508 { // replace one entry
509 pData[ni].nRow = nEndRow;
510 pData[ni].pPattern = pPattern;
511 ni++;
512 nInsert = MAXROWCOUNT;
514 if ( ni < nj )
515 { // remove entries
516 memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
517 nCount -= nj - ni;
521 if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
522 { // insert or append new entry
523 if ( nInsert <= nCount )
525 if ( !bSplit )
526 memmove( pData + nInsert + 1, pData + nInsert,
527 (nCount - nInsert) * sizeof(ScAttrEntry) );
528 else
530 memmove( pData + nInsert + 2, pData + nInsert,
531 (nCount - nInsert) * sizeof(ScAttrEntry) );
532 pData[nInsert+1] = pData[nInsert-1];
533 nCount++;
536 if ( nInsert )
537 pData[nInsert-1].nRow = nStartRow - 1;
538 pData[nInsert].nRow = nEndRow;
539 pData[nInsert].pPattern = pPattern;
541 // Remove character attributes from these cells if the pattern
542 // is applied during normal session.
543 if (pDataArray)
544 RemoveCellCharAttribs(nStartRow, nEndRow, pPattern, pDataArray);
546 nCount++;
549 if (pDocument->IsStreamValid(nTab))
550 pDocument->SetStreamValid(nTab, false);
554 #if OSL_DEBUG_LEVEL > 1
555 TestData();
556 #endif
560 void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
562 if (ValidRow(nStartRow) && ValidRow(nEndRow))
564 SCSIZE nPos;
565 SCROW nStart=0;
566 if (!Search( nStartRow, nPos ))
568 OSL_FAIL("Search Failure");
569 return;
572 ScAddress aAdrStart( nCol, 0, nTab );
573 ScAddress aAdrEnd ( nCol, 0, nTab );
577 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
578 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
579 pNewPattern->SetStyleSheet(pStyle);
580 SCROW nY1 = nStart;
581 SCROW nY2 = pData[nPos].nRow;
582 nStart = pData[nPos].nRow + 1;
584 if ( *pNewPattern == *pOldPattern )
586 // keep the original pattern (might be default)
587 // pNewPattern is deleted below
588 nPos++;
590 else if ( nY1 < nStartRow || nY2 > nEndRow )
592 if (nY1 < nStartRow) nY1=nStartRow;
593 if (nY2 > nEndRow) nY2=nEndRow;
594 SetPatternArea( nY1, nY2, pNewPattern, true );
595 Search( nStart, nPos );
597 else
599 // ensure attributing changes text width of cell; otherwise
600 // there aren't (yet) template format changes
601 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
602 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
604 bool bNumFormatChanged;
605 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
606 rNewSet, rOldSet ) )
608 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
609 aAdrEnd .SetRow( pData[nPos].nRow );
610 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
613 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
614 pData[nPos].pPattern = (const ScPatternAttr*)
615 &pDocument->GetPool()->Put(*pNewPattern);
616 if (Concat(nPos))
617 Search(nStart, nPos);
618 else
619 nPos++;
621 delete pNewPattern;
623 while ((nStart <= nEndRow) && (nPos < nCount));
625 if (pDocument->IsStreamValid(nTab))
626 pDocument->SetStreamValid(nTab, false);
629 #if OSL_DEBUG_LEVEL > 1
630 TestData();
631 #endif
635 // const cast, otherwise it will be too inefficient/complicated
636 #define SET_LINECOLOR(dest,c) \
637 if ((dest)) \
639 ((SvxBorderLine*)(dest))->SetColor((c)); \
642 #define SET_LINE(dest,src) \
643 if ((dest)) \
645 SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
646 pCast->SetBorderLineStyle( (src)->GetBorderLineStyle() ); \
647 pCast->SetWidth( (src)->GetWidth( ) ); \
650 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
651 const SvxBorderLine* pLine, bool bColorOnly )
653 if ( bColorOnly && !pLine )
654 return;
656 if (ValidRow(nStartRow) && ValidRow(nEndRow))
658 SCSIZE nPos;
659 SCROW nStart=0;
660 if (!Search( nStartRow, nPos ))
662 OSL_FAIL("Search failure");
663 return;
668 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
669 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
670 const SfxPoolItem* pBoxItem = 0;
671 SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, true, &pBoxItem );
672 const SfxPoolItem* pTLBRItem = 0;
673 SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem );
674 const SfxPoolItem* pBLTRItem = 0;
675 SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem );
677 if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) )
679 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
680 SfxItemSet& rNewSet = pNewPattern->GetItemSet();
681 SCROW nY1 = nStart;
682 SCROW nY2 = pData[nPos].nRow;
684 SvxBoxItem* pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0;
685 SvxLineItem* pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0;
686 SvxLineItem* pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0;
688 // fetch line and update attributes with parameters
690 if ( !pLine )
692 if( pNewBoxItem )
694 if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( NULL, BOX_LINE_TOP );
695 if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM );
696 if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT );
697 if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT );
699 if( pNewTLBRItem && pNewTLBRItem->GetLine() )
700 pNewTLBRItem->SetLine( 0 );
701 if( pNewBLTRItem && pNewBLTRItem->GetLine() )
702 pNewBLTRItem->SetLine( 0 );
704 else
706 if ( bColorOnly )
708 Color aColor( pLine->GetColor() );
709 if( pNewBoxItem )
711 SET_LINECOLOR( pNewBoxItem->GetTop(), aColor );
712 SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
713 SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor );
714 SET_LINECOLOR( pNewBoxItem->GetRight(), aColor );
716 if( pNewTLBRItem )
717 SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
718 if( pNewBLTRItem )
719 SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
721 else
723 if( pNewBoxItem )
725 SET_LINE( pNewBoxItem->GetTop(), pLine );
726 SET_LINE( pNewBoxItem->GetBottom(), pLine );
727 SET_LINE( pNewBoxItem->GetLeft(), pLine );
728 SET_LINE( pNewBoxItem->GetRight(), pLine );
730 if( pNewTLBRItem )
731 SET_LINE( pNewTLBRItem->GetLine(), pLine );
732 if( pNewBLTRItem )
733 SET_LINE( pNewBLTRItem->GetLine(), pLine );
736 if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem );
737 if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem );
738 if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem );
740 nStart = pData[nPos].nRow + 1;
742 if ( nY1 < nStartRow || nY2 > nEndRow )
744 if (nY1 < nStartRow) nY1=nStartRow;
745 if (nY2 > nEndRow) nY2=nEndRow;
746 SetPatternArea( nY1, nY2, pNewPattern, true );
747 Search( nStart, nPos );
749 else
751 // remove from pool ?
752 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
753 pData[nPos].pPattern = (const ScPatternAttr*)
754 &pDocument->GetPool()->Put(*pNewPattern);
756 if (Concat(nPos))
757 Search(nStart, nPos);
758 else
759 nPos++;
761 delete pNewBoxItem;
762 delete pNewTLBRItem;
763 delete pNewBLTRItem;
764 delete pNewPattern;
766 else
768 nStart = pData[nPos].nRow + 1;
769 nPos++;
772 while ((nStart <= nEndRow) && (nPos < nCount));
776 #undef SET_LINECOLOR
777 #undef SET_LINE
780 void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray )
782 #if OSL_DEBUG_LEVEL > 1
783 TestData();
784 #endif
786 if (ValidRow(nStartRow) && ValidRow(nEndRow))
788 SCSIZE nPos;
789 SCROW nStart=0;
790 if (!Search( nStartRow, nPos ))
792 OSL_FAIL("Search Failure");
793 return;
796 ScAddress aAdrStart( nCol, 0, nTab );
797 ScAddress aAdrEnd ( nCol, 0, nTab );
801 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
802 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, true );
803 ScDocumentPool::CheckRef( *pOldPattern );
804 ScDocumentPool::CheckRef( *pNewPattern );
805 if (pNewPattern != pOldPattern)
807 SCROW nY1 = nStart;
808 SCROW nY2 = pData[nPos].nRow;
809 nStart = pData[nPos].nRow + 1;
811 if ( nY1 < nStartRow || nY2 > nEndRow )
813 if (nY1 < nStartRow) nY1=nStartRow;
814 if (nY2 > nEndRow) nY2=nEndRow;
815 SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray );
816 Search( nStart, nPos );
818 else
820 // ensure attributing changes text-width of cell
822 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
823 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
825 bool bNumFormatChanged;
826 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
827 rNewSet, rOldSet ) )
829 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
830 aAdrEnd .SetRow( pData[nPos].nRow );
831 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
834 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
835 pData[nPos].pPattern = pNewPattern;
836 if (Concat(nPos))
837 Search(nStart, nPos);
838 else
839 ++nPos;
842 else
844 nStart = pData[nPos].nRow + 1;
845 ++nPos;
848 while (nStart <= nEndRow);
850 if (pDocument->IsStreamValid(nTab))
851 pDocument->SetStreamValid(nTab, false);
854 #if OSL_DEBUG_LEVEL > 1
855 TestData();
856 #endif
859 bool ScAttrArray::SetAttrEntries(ScAttrEntry* pNewData, SCSIZE nSize)
861 ScDocumentPool* pDocPool = pDocument->GetPool();
862 for (SCSIZE i=0; i<nCount; i++)
863 pDocPool->Remove(*pData[i].pPattern);
865 delete[] pData;
867 pData = pNewData;
868 nCount = nLimit = nSize;
869 return true;
872 static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
874 const SfxPoolItem* pNewItem;
875 const SfxPoolItem* pOldItem;
876 for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
878 // pMergeSet has no parent
879 SfxItemState eOldState = rMergeSet.GetItemState( nId, false, &pOldItem );
881 if ( eOldState == SFX_ITEM_DEFAULT )
883 SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
884 if ( eNewState == SFX_ITEM_SET )
886 if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
887 rMergeSet.InvalidateItem( nId );
890 else if ( eOldState == SFX_ITEM_SET ) // Item gesetzt
892 SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
893 if ( eNewState == SFX_ITEM_SET )
895 if ( pNewItem != pOldItem ) // beide gepuhlt
896 rMergeSet.InvalidateItem( nId );
898 else // Default
900 if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
901 rMergeSet.InvalidateItem( nId );
904 // Dontcare remains Dontcare
909 void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
910 ScMergePatternState& rState, bool bDeep ) const
912 if (ValidRow(nStartRow) && ValidRow(nEndRow))
914 SCSIZE nPos;
915 SCROW nStart=0;
916 if (!Search( nStartRow, nPos ))
918 OSL_FAIL("Search failure");
919 return;
924 // similar patterns must not be repeated
926 const ScPatternAttr* pPattern = pData[nPos].pPattern;
927 if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
929 const SfxItemSet& rThisSet = pPattern->GetItemSet();
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);
957 // assemble border
959 static bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
960 sal_uInt8& rModified, const SvxBorderLine*& rpNew )
962 if (rModified == SC_LINE_DONTCARE)
963 return false; // don't go again
965 if (rModified == SC_LINE_EMPTY)
967 rModified = SC_LINE_SET;
968 rpNew = pNewLine;
969 return true; // initial value
972 if (pOldLine == pNewLine)
974 rpNew = pOldLine;
975 return false;
978 if (pOldLine && pNewLine)
979 if (*pOldLine == *pNewLine)
981 rpNew = pOldLine;
982 return false;
985 rModified = SC_LINE_DONTCARE;
986 rpNew = NULL;
987 return true; // another line -> don't care
991 static void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
992 ScLineFlags& rFlags, const ScPatternAttr* pPattern,
993 bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
995 // right/bottom border set when connected together
996 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
997 if ( rMerge.GetColMerge() == nDistRight + 1 )
998 nDistRight = 0;
999 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1000 nDistBottom = 0;
1002 const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER );
1003 const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
1004 const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
1005 const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
1006 const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
1007 const SvxBorderLine* pNew;
1009 if (bTop)
1011 if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
1012 pLineOuter->SetLine( pNew, BOX_LINE_TOP );
1014 else
1016 if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
1017 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
1020 if (nDistBottom == 0)
1022 if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
1023 pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM );
1025 else
1027 if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
1028 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
1031 if (bLeft)
1033 if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
1034 pLineOuter->SetLine( pNew, BOX_LINE_LEFT );
1036 else
1038 if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
1039 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1042 if (nDistRight == 0)
1044 if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
1045 pLineOuter->SetLine( pNew, BOX_LINE_RIGHT );
1047 else
1049 if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
1050 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1055 void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
1056 ScLineFlags& rFlags,
1057 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
1059 const ScPatternAttr* pPattern;
1061 if (nStartRow == nEndRow)
1063 pPattern = GetPattern( nStartRow );
1064 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true, 0 );
1066 else
1068 pPattern = GetPattern( nStartRow );
1069 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true,
1070 nEndRow-nStartRow );
1072 SCSIZE nStartIndex;
1073 SCSIZE nEndIndex;
1074 Search( nStartRow+1, nStartIndex );
1075 Search( nEndRow-1, nEndIndex );
1076 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1078 pPattern = (ScPatternAttr*) pData[i].pPattern;
1079 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false,
1080 nEndRow - std::min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
1081 // nDistBottom here always > 0
1084 pPattern = GetPattern( nEndRow );
1085 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false, 0 );
1090 // apply border
1093 // ApplyFrame - on an entry into the array
1095 bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
1096 const SvxBoxInfoItem* pBoxInfoItem,
1097 SCROW nStartRow, SCROW nEndRow,
1098 bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom )
1100 OSL_ENSURE( pBoxItem && pBoxInfoItem, "Missing line attributes!" );
1102 const ScPatternAttr* pPattern = GetPattern( nStartRow );
1103 const SvxBoxItem* pOldFrame = (const SvxBoxItem*)
1104 &pPattern->GetItemSet().Get( ATTR_BORDER );
1106 // right/bottom border set when connected together
1107 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
1108 if ( rMerge.GetColMerge() == nDistRight + 1 )
1109 nDistRight = 0;
1110 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1111 nDistBottom = 0;
1113 SvxBoxItem aNewFrame( *pOldFrame );
1114 bool bRTL=pDocument->IsLayoutRTL(nTab);
1115 // fdo#37464 check if the sheet are RTL then replace right <=> left
1116 if (bRTL)
1118 if( bLeft && nDistRight==0)
1120 if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1121 aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1122 BOX_LINE_RIGHT );
1123 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1124 aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1125 BOX_LINE_LEFT );
1127 else
1129 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1130 aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1131 BOX_LINE_RIGHT );
1132 if ( bLeft ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1133 aNewFrame.SetLine( bLeft ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1134 BOX_LINE_LEFT );
1137 else
1139 if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1140 aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1141 BOX_LINE_LEFT );
1142 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1143 aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1144 BOX_LINE_RIGHT );
1146 if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
1147 aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
1148 BOX_LINE_TOP );
1149 if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
1150 aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
1151 BOX_LINE_BOTTOM );
1153 if (aNewFrame == *pOldFrame)
1155 // nothing to do
1156 return false;
1158 else
1160 SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
1161 ApplyCacheArea( nStartRow, nEndRow, &aCache );
1163 return true;
1168 void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
1169 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
1171 if (nStartRow == nEndRow)
1172 ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0 );
1173 else
1175 ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1176 true, nEndRow-nStartRow );
1178 if ( nEndRow > nStartRow+1 ) // inner part available?
1180 SCSIZE nStartIndex;
1181 SCSIZE nEndIndex;
1182 Search( nStartRow+1, nStartIndex );
1183 Search( nEndRow-1, nEndIndex );
1184 SCROW nTmpStart = nStartRow+1;
1185 SCROW nTmpEnd;
1186 for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1188 nTmpEnd = std::min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
1189 bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
1190 bLeft, nDistRight, false, nEndRow-nTmpEnd );
1191 nTmpStart = nTmpEnd+1;
1192 if (bChanged)
1194 Search(nTmpStart, i);
1195 Search(nEndRow-1, nEndIndex);
1197 else
1198 i++;
1202 ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0 );
1206 // Test if field contains specific attribute
1208 bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
1210 SCSIZE nStartIndex;
1211 SCSIZE nEndIndex;
1212 Search( nRow1, nStartIndex );
1213 Search( nRow2, nEndIndex );
1214 bool bFound = false;
1216 for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1218 const ScPatternAttr* pPattern = pData[i].pPattern;
1219 if ( nMask & HASATTR_MERGED )
1221 const ScMergeAttr* pMerge =
1222 (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1223 if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1224 bFound = true;
1226 if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
1228 const ScMergeFlagAttr* pMergeFlag =
1229 (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG );
1230 if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
1231 bFound = true;
1232 if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
1233 bFound = true;
1234 if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
1235 bFound = true;
1237 if ( nMask & HASATTR_LINES )
1239 const SvxBoxItem* pBox =
1240 (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER );
1241 if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1242 bFound = true;
1244 if ( nMask & HASATTR_SHADOW )
1246 const SvxShadowItem* pShadow =
1247 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1248 if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
1249 bFound = true;
1251 if ( nMask & HASATTR_CONDITIONAL )
1253 bool bContainsCondFormat =
1254 !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
1255 if ( bContainsCondFormat )
1256 bFound = true;
1258 if ( nMask & HASATTR_PROTECTED )
1260 const ScProtectionAttr* pProtect =
1261 (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION );
1262 bool bFoundTemp = false;
1263 if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1264 bFoundTemp = true;
1266 bool bContainsCondFormat =
1267 !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
1268 if ( bContainsCondFormat )
1270 SCROW nRowStartCond = std::max<SCROW>( nRow1, i ? pData[i-1].nRow + 1: 0 );
1271 SCROW nRowEndCond = std::min<SCROW>( nRow2, pData[i].nRow );
1272 bool bFoundCond = false;
1273 for(SCROW nRowCond = nRowStartCond; nRowCond <= nRowEndCond && !bFoundCond; ++nRowCond)
1275 const SfxItemSet* pSet = pDocument->GetCondResult( nCol, nRowCond, nTab );
1277 const SfxPoolItem* pItem;
1278 if( pSet && pSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SFX_ITEM_SET )
1280 const ScProtectionAttr* pCondProtect = static_cast<const ScProtectionAttr*>(pItem);
1281 if( pCondProtect->GetProtection() || pCondProtect->GetHideCell() )
1282 bFoundCond = true;
1283 else
1284 break;
1286 else
1288 // well it is not true that we found one
1289 // but existing one + cell where conditional
1290 // formatting does not remove it
1291 // => we should use the existing protection settting
1292 bFoundCond = bFoundTemp;
1295 bFoundTemp = bFoundCond;
1298 if(bFoundTemp)
1299 bFound = true;
1301 if ( nMask & HASATTR_ROTATE )
1303 const SfxInt32Item* pRotate =
1304 (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE );
1305 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1306 // (see ScPatternAttr::GetCellOrientation)
1307 sal_Int32 nAngle = pRotate->GetValue();
1308 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
1309 bFound = true;
1311 if ( nMask & HASATTR_NEEDHEIGHT )
1313 if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
1314 bFound = true;
1315 else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
1316 bFound = true;
1317 else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
1318 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
1319 bFound = true;
1321 else if (!static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL)).GetCondFormatData().empty())
1322 bFound = true;
1323 else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
1324 bFound = true;
1326 if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
1328 const SvxShadowItem* pShadow =
1329 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1330 SvxShadowLocation eLoc = pShadow->GetLocation();
1331 if ( nMask & HASATTR_SHADOW_RIGHT )
1332 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1333 bFound = true;
1334 if ( nMask & HASATTR_SHADOW_DOWN )
1335 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1336 bFound = true;
1338 if ( nMask & HASATTR_RTL )
1340 const SvxFrameDirectionItem& rDirection =
1341 (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR );
1342 if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP )
1343 bFound = true;
1345 if ( nMask & HASATTR_RIGHTORCENTER )
1347 // called only if the sheet is LTR, so physical=logical alignment can be assumed
1348 SvxCellHorJustify eHorJust = (SvxCellHorJustify)
1349 ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
1350 if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
1351 bFound = true;
1355 return bFound;
1358 // Area around any given summaries expand and adapt any MergeFlag (bRefresh)
1359 bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
1360 SCCOL& rPaintCol, SCROW& rPaintRow,
1361 bool bRefresh )
1363 const ScPatternAttr* pPattern;
1364 const ScMergeAttr* pItem;
1365 SCSIZE nStartIndex;
1366 SCSIZE nEndIndex;
1367 Search( nStartRow, nStartIndex );
1368 Search( nEndRow, nEndIndex );
1369 bool bFound = false;
1371 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1373 pPattern = pData[i].pPattern;
1374 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1375 SCsCOL nCountX = pItem->GetColMerge();
1376 SCsROW nCountY = pItem->GetRowMerge();
1377 if (nCountX>1 || nCountY>1)
1379 SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
1380 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1381 SCROW nMergeEndRow = nThisRow + nCountY - 1;
1382 if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
1383 rPaintCol = nMergeEndCol;
1384 if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
1385 rPaintRow = nMergeEndRow;
1386 bFound = true;
1388 if (bRefresh)
1390 if ( nMergeEndCol > nThisCol )
1391 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
1392 nTab, SC_MF_HOR );
1393 if ( nMergeEndRow > nThisRow )
1394 pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1395 nTab, SC_MF_VER );
1396 if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1397 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1398 nTab, SC_MF_HOR | SC_MF_VER );
1400 Search( nThisRow, i ); // Data changed
1401 Search( nStartRow, nStartIndex );
1402 Search( nEndRow, nEndIndex );
1407 return bFound;
1411 bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1413 bool bFound = false;
1414 const ScPatternAttr* pPattern;
1415 const ScMergeAttr* pItem;
1416 SCSIZE nIndex;
1418 Search( nStartRow, nIndex );
1419 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1420 if (nThisStart < nStartRow)
1421 nThisStart = nStartRow;
1423 while ( nThisStart <= nEndRow )
1425 SCROW nThisEnd = pData[nIndex].nRow;
1426 if (nThisEnd > nEndRow)
1427 nThisEnd = nEndRow;
1429 pPattern = pData[nIndex].pPattern;
1430 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1431 SCsCOL nCountX = pItem->GetColMerge();
1432 SCsROW nCountY = pItem->GetRowMerge();
1433 if (nCountX>1 || nCountY>1)
1435 const ScMergeAttr* pAttr = (const ScMergeAttr*)
1436 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
1437 const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*)
1438 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
1440 OSL_ENSURE( nCountY==1 || nThisStart==nThisEnd, "What's up?" );
1442 SCCOL nThisCol = nCol;
1443 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1444 SCROW nMergeEndRow = nThisEnd + nCountY - 1;
1446 // ApplyAttr for areas
1448 for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
1449 pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
1451 ScPatternAttr* pNewPattern = new ScPatternAttr( pDocument->GetPool() );
1452 SfxItemSet* pSet = &pNewPattern->GetItemSet();
1453 pSet->Put( *pFlagAttr );
1454 pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
1455 nTab, *pNewPattern );
1456 delete pNewPattern;
1458 Search( nThisEnd, nIndex ); // data changed
1461 ++nIndex;
1462 if ( nIndex < nCount )
1463 nThisStart = pData[nIndex-1].nRow+1;
1464 else
1465 nThisStart = MAXROW+1; // End
1468 return bFound;
1471 // Remove field, but leave MergeFlags
1473 void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow)
1475 SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), true );
1479 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
1480 const ScPatternAttr* pWantedPattern, bool bDefault )
1482 const ScPatternAttr* pOldPattern;
1483 const ScMergeFlagAttr* pItem;
1485 SCSIZE nIndex;
1486 SCROW nRow;
1487 SCROW nThisRow;
1488 bool bFirstUse = true;
1490 Search( nStartRow, nIndex );
1491 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1492 while ( nThisRow <= nEndRow )
1494 pOldPattern = pData[nIndex].pPattern;
1495 if (pOldPattern != pWantedPattern) //! else-Zweig ?
1497 if (nThisRow < nStartRow) nThisRow = nStartRow;
1498 nRow = pData[nIndex].nRow;
1499 SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1500 pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG );
1502 if (pItem->IsOverlapped() || pItem->HasAutoFilter())
1504 // default-constructing a ScPatternAttr for DeleteArea doesn't work
1505 // because it would have no cell style information.
1506 // Instead, the document's GetDefPattern is copied. Since it is passed as
1507 // pWantedPattern, no special treatment of default is needed here anymore.
1508 ScPatternAttr* pNewPattern = new ScPatternAttr( *pWantedPattern );
1509 SfxItemSet* pSet = &pNewPattern->GetItemSet();
1510 pSet->Put( *pItem );
1511 SetPatternArea( nThisRow, nAttrRow, pNewPattern, true );
1512 delete pNewPattern;
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;
1536 bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1538 const ScPatternAttr* pOldPattern;
1540 sal_Int16 nOldValue;
1541 SCSIZE nIndex;
1542 SCROW nRow;
1543 SCROW nThisRow;
1544 bool bChanged = false;
1546 Search( nStartRow, nIndex );
1547 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1548 if (nThisRow < nStartRow) nThisRow = nStartRow;
1550 while ( nThisRow <= nEndRow )
1552 pOldPattern = pData[nIndex].pPattern;
1553 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1554 if ( (nOldValue | nFlags) != nOldValue )
1556 nRow = pData[nIndex].nRow;
1557 SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1558 ScPatternAttr aNewPattern(*pOldPattern);
1559 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1560 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1561 Search( nThisRow, nIndex ); // data changed
1562 bChanged = true;
1565 ++nIndex;
1566 nThisRow = pData[nIndex-1].nRow+1;
1569 return bChanged;
1573 bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1575 const ScPatternAttr* pOldPattern;
1577 sal_Int16 nOldValue;
1578 SCSIZE nIndex;
1579 SCROW nRow;
1580 SCROW nThisRow;
1581 bool bChanged = false;
1583 Search( nStartRow, nIndex );
1584 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1585 if (nThisRow < nStartRow) nThisRow = nStartRow;
1587 while ( nThisRow <= nEndRow )
1589 pOldPattern = pData[nIndex].pPattern;
1590 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1591 if ( (nOldValue & ~nFlags) != nOldValue )
1593 nRow = pData[nIndex].nRow;
1594 SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1595 ScPatternAttr aNewPattern(*pOldPattern);
1596 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1597 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1598 Search( nThisRow, nIndex ); // data changed
1599 bChanged = true;
1602 ++nIndex;
1603 nThisRow = pData[nIndex-1].nRow+1;
1606 return bChanged;
1610 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
1612 const ScPatternAttr* pOldPattern;
1614 SCSIZE nIndex;
1615 SCROW nRow;
1616 SCROW nThisRow;
1618 Search( nStartRow, nIndex );
1619 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1620 if (nThisRow < nStartRow) nThisRow = nStartRow;
1622 while ( nThisRow <= nEndRow )
1624 pOldPattern = pData[nIndex].pPattern;
1625 if ( pOldPattern->HasItemsSet( pWhich ) )
1627 ScPatternAttr aNewPattern(*pOldPattern);
1628 aNewPattern.ClearItems( pWhich );
1630 nRow = pData[nIndex].nRow;
1631 SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
1632 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
1633 Search( nThisRow, nIndex ); // data changed
1636 ++nIndex;
1637 nThisRow = pData[nIndex-1].nRow+1;
1642 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement )
1644 SCSIZE nIndex;
1645 Search( nStartRow, nIndex );
1646 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1647 if (nThisStart < nStartRow) nThisStart = nStartRow;
1649 while ( nThisStart <= nEndRow )
1651 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
1652 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1653 const SfxPoolItem* pItem;
1655 bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, false, &pItem ) != SFX_ITEM_SET
1656 || (((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT &&
1657 ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_RIGHT ));
1658 sal_uInt16 nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
1659 sal_uInt16 nNewValue = nOldValue;
1660 //to keep Increment indent from running outside the cell1659
1661 long nColWidth = (long)pDocument->GetColWidth(nCol,nTab);
1662 if ( bIncrement )
1664 if ( nNewValue < nColWidth-SC_INDENT_STEP )
1666 nNewValue += SC_INDENT_STEP;
1667 if ( nNewValue > nColWidth-SC_INDENT_STEP ) nNewValue = nColWidth-SC_INDENT_STEP;
1670 else
1672 if ( nNewValue > 0 )
1674 if ( nNewValue > SC_INDENT_STEP )
1675 nNewValue -= SC_INDENT_STEP;
1676 else
1677 nNewValue = 0;
1681 if ( bNeedJust || nNewValue != nOldValue )
1683 SCROW nThisEnd = pData[nIndex].nRow;
1684 SCROW nAttrRow = std::min( nThisEnd, nEndRow );
1685 ScPatternAttr aNewPattern(*pOldPattern);
1686 aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
1687 if ( bNeedJust )
1688 aNewPattern.GetItemSet().Put(
1689 SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
1690 SetPatternArea( nThisStart, nAttrRow, &aNewPattern, true );
1692 nThisStart = nThisEnd + 1;
1693 Search( nThisStart, nIndex ); // data changed
1695 else
1697 nThisStart = pData[nIndex].nRow + 1;
1698 ++nIndex;
1704 SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, bool bUp ) const
1706 long nRet = nRow;
1707 if (ValidRow(nRow))
1709 SCSIZE nIndex;
1710 Search(nRow, nIndex);
1711 while (((const ScProtectionAttr&)pData[nIndex].pPattern->
1712 GetItem(ATTR_PROTECTION)).GetProtection())
1714 if (bUp)
1716 if (nIndex==0)
1717 return -1; // not found
1718 --nIndex;
1719 nRet = pData[nIndex].nRow;
1721 else
1723 nRet = pData[nIndex].nRow+1;
1724 ++nIndex;
1725 if (nIndex>=nCount)
1726 return MAXROW+1; // not found
1730 return nRet;
1733 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1735 SCROW nStart = 0;
1736 SCSIZE nPos = 0;
1737 while (nPos < nCount)
1739 SCROW nEnd = pData[nPos].nRow;
1740 if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1742 rUsedRows.setTrue(nStart, nEnd);
1744 if (bReset)
1746 ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern);
1747 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
1748 pNewPattern->SetStyleSheet( (ScStyleSheet*)
1749 pDocument->GetStyleSheetPool()->
1750 Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
1751 SFX_STYLE_FAMILY_PARA,
1752 SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) );
1753 pData[nPos].pPattern = (const ScPatternAttr*)
1754 &pDocument->GetPool()->Put(*pNewPattern);
1755 delete pNewPattern;
1757 if (Concat(nPos))
1759 Search(nStart, nPos);
1760 --nPos; // because ++ at end
1764 nStart = nEnd + 1;
1765 ++nPos;
1770 bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
1771 bool bGatherAllStyles ) const
1773 bool bIsUsed = false;
1774 SCSIZE nPos = 0;
1776 while ( nPos < nCount )
1778 const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
1779 if ( pStyle )
1781 pStyle->SetUsage( ScStyleSheet::USED );
1782 if ( pStyle == &rStyle )
1784 if ( !bGatherAllStyles )
1785 return true;
1786 bIsUsed = true;
1789 nPos++;
1792 return bIsUsed;
1796 bool ScAttrArray::IsEmpty() const
1798 if (nCount == 1)
1800 if ( pData[0].pPattern != pDocument->GetDefPattern() )
1801 return false;
1802 else
1803 return true;
1805 else
1806 return false;
1810 bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1812 OSL_ENSURE( nCount, "nCount == 0" );
1814 bool bFound = false;
1815 SCSIZE nStart = 0;
1817 // Skip first entry if more than 1 row.
1818 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1820 SCSIZE nVisStart = 1;
1821 while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
1822 ++nVisStart;
1823 if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row?
1824 nStart = nVisStart;
1826 while ( nStart < nCount && !bFound )
1828 if ( pData[nStart].pPattern->IsVisible() )
1830 rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
1831 bFound = true;
1833 else
1834 ++nStart;
1837 return bFound;
1840 // size (rows) of a range of attributes after cell content where the search is stopped
1841 // (more than a default page size, 2*42 because it's as good as any number)
1843 const SCROW SC_VISATTR_STOP = 84;
1845 bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData, bool bFullFormattedArea ) const
1847 OSL_ENSURE( nCount, "nCount == 0" );
1849 // #i30830# changed behavior:
1850 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1851 // below the last content cell
1853 if ( nLastData == MAXROW )
1855 rLastRow = MAXROW; // can't look for attributes below MAXROW
1856 return true;
1859 // Quick check: last data row in or immediately preceding a run that is the
1860 // last attribution down to the end, e.g. default style or column style.
1861 SCSIZE nPos = nCount - 1;
1862 SCROW nStartRow = (nPos ? pData[nPos-1].nRow + 1 : 0);
1863 if (nStartRow <= nLastData + 1)
1865 if (bFullFormattedArea && pData[nPos].pPattern->IsVisible())
1867 rLastRow = pData[nPos].nRow;
1868 return true;
1870 else
1872 // Ignore here a few rows if data happens to end within
1873 // SC_VISATTR_STOP rows before MAXROW.
1874 rLastRow = nLastData;
1875 return false;
1879 // Find a run below last data row.
1880 bool bFound = false;
1881 Search( nLastData, nPos );
1882 while ( nPos < nCount )
1884 // find range of visually equal formats
1885 SCSIZE nEndPos = nPos;
1886 while ( nEndPos < nCount-1 &&
1887 pData[nEndPos].pPattern->IsVisibleEqual( *pData[nEndPos+1].pPattern))
1888 ++nEndPos;
1889 SCROW nAttrStartRow = ( nPos > 0 ) ? ( pData[nPos-1].nRow + 1 ) : 0;
1890 if ( nAttrStartRow <= nLastData )
1891 nAttrStartRow = nLastData + 1;
1892 SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1893 if ( nAttrSize >= SC_VISATTR_STOP && !bFullFormattedArea )
1894 break; // while, ignore this range and below
1895 else if ( pData[nEndPos].pPattern->IsVisible() )
1897 rLastRow = pData[nEndPos].nRow;
1898 bFound = true;
1900 nPos = nEndPos + 1;
1903 return bFound;
1907 bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1909 SCSIZE nIndex;
1910 Search( nStartRow, nIndex );
1911 SCROW nThisStart = nStartRow;
1912 bool bFound = false;
1913 while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
1915 if ( pData[nIndex].pPattern->IsVisible() )
1916 bFound = true;
1918 nThisStart = pData[nIndex].nRow + 1;
1919 ++nIndex;
1922 return bFound;
1926 bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
1927 SCROW nStartRow, SCROW nEndRow ) const
1929 bool bEqual = true;
1930 SCSIZE nThisPos = 0;
1931 SCSIZE nOtherPos = 0;
1932 if ( nStartRow > 0 )
1934 Search( nStartRow, nThisPos );
1935 rOther.Search( nStartRow, nOtherPos );
1938 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1940 SCROW nThisRow = pData[nThisPos].nRow;
1941 SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1942 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1943 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1944 bEqual = ( pThisPattern == pOtherPattern ||
1945 pThisPattern->IsVisibleEqual(*pOtherPattern) );
1947 if ( nThisRow >= nOtherRow )
1949 if ( nOtherRow >= nEndRow ) break;
1950 ++nOtherPos;
1952 if ( nThisRow <= nOtherRow )
1954 if ( nThisRow >= nEndRow ) break;
1955 ++nThisPos;
1959 return bEqual;
1963 bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
1965 // summarised with IsVisibleEqual
1967 bool bEqual = true;
1968 SCSIZE nThisPos = 0;
1969 SCSIZE nOtherPos = 0;
1970 if ( nStartRow > 0 )
1972 Search( nStartRow, nThisPos );
1973 rOther.Search( nStartRow, nOtherPos );
1976 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1978 SCROW nThisRow = pData[nThisPos].nRow;
1979 SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1980 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1981 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1982 bEqual = ( pThisPattern == pOtherPattern );
1984 if ( nThisRow >= nOtherRow )
1986 if ( nOtherRow >= nEndRow ) break;
1987 ++nOtherPos;
1989 if ( nThisRow <= nOtherRow )
1991 if ( nThisRow >= nEndRow ) break;
1992 ++nThisPos;
1996 return bEqual;
2000 bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2002 // Horizontal aggregate are not allowed to be moved out; if whole summary,
2003 // here is not recognized
2005 bool bTest = true;
2006 if (!IsEmpty())
2008 SCSIZE nIndex = 0;
2009 if ( nStartRow > 0 )
2010 Search( nStartRow, nIndex );
2012 for ( ; nIndex < nCount; nIndex++ )
2014 if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
2015 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2017 bTest = false; // may not be pushed out
2018 break;
2020 if ( pData[nIndex].nRow >= nEndRow ) // end of range
2021 break;
2024 return bTest;
2028 bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2030 // if 1st row pushed out is vertically overlapped, summary would be broken
2032 // MAXROW + 1 - nSize = 1st row pushed out
2034 SCSIZE nFirstLost = nCount-1;
2035 while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2036 --nFirstLost;
2038 if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
2039 GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2040 return false;
2042 return true;
2046 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2048 if (!pData)
2049 return;
2051 SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // expand predecessor
2052 SCSIZE nIndex;
2053 Search( nSearch, nIndex );
2055 // set ScMergeAttr may not be extended (so behind delete again)
2057 bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
2059 SCSIZE nRemove = 0;
2060 SCSIZE i;
2061 for (i = nIndex; i < nCount-1; i++)
2063 SCROW nNew = pData[i].nRow + nSize;
2064 if ( nNew >= MAXROW ) // at end?
2066 nNew = MAXROW;
2067 if (!nRemove)
2068 nRemove = i+1; // remove the following?
2070 pData[i].nRow = nNew;
2073 // Remove entries at end ?
2075 if (nRemove && nRemove < nCount)
2076 DeleteRange( nRemove, nCount-1 );
2078 if (bDoMerge) // extensively repair (again) ScMergeAttr
2080 // ApplyAttr for areas
2082 const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
2083 for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2084 pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2086 // reply inserts in this area not summarized
2089 // Don't duplicate the merge flags in the inserted row.
2090 // #i108488# SC_MF_SCENARIO has to be allowed.
2091 RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
2095 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2097 bool bFirst=true;
2098 SCSIZE nStartIndex = 0;
2099 SCSIZE nEndIndex = 0;
2100 SCSIZE i;
2102 for ( i = 0; i < nCount-1; i++)
2103 if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2105 if (bFirst)
2107 nStartIndex = i;
2108 bFirst = false;
2110 nEndIndex = i;
2112 if (!bFirst)
2114 SCROW nStart;
2115 if (nStartIndex==0)
2116 nStart = 0;
2117 else
2118 nStart = pData[nStartIndex-1].nRow + 1;
2120 if (nStart < nStartRow)
2122 pData[nStartIndex].nRow = nStartRow - 1;
2123 ++nStartIndex;
2125 if (nEndIndex >= nStartIndex)
2127 DeleteRange( nStartIndex, nEndIndex );
2128 if (nStartIndex > 0)
2129 if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
2130 DeleteRange( nStartIndex-1, nStartIndex-1 );
2133 for (i = 0; i < nCount-1; i++)
2134 if (pData[i].nRow >= nStartRow)
2135 pData[i].nRow -= nSize;
2137 // Below does not follow the pattern to detect pressure ranges;
2138 // instead, only remove merge flags.
2139 RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
2143 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2145 ScDocumentPool* pDocPool = pDocument->GetPool();
2146 for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2147 pDocPool->Remove(*pData[i].pPattern);
2149 memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
2150 nCount -= nEndIndex-nStartIndex+1;
2154 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2156 RemoveAreaMerge( nStartRow, nEndRow ); // remove from combined flags
2158 if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
2159 SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
2160 else
2161 DeleteAreaSafe( nStartRow, nEndRow ); // leave merge flags
2165 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2167 const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2168 const ScPatternAttr* pOldPattern;
2170 SCSIZE nIndex;
2171 SCROW nRow;
2172 SCROW nThisRow;
2174 Search( nStartRow, nIndex );
2175 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
2176 if (nThisRow < nStartRow) nThisRow = nStartRow;
2178 while ( nThisRow <= nEndRow )
2180 pOldPattern = pData[nIndex].pPattern;
2182 if ( pOldPattern->GetItemSet().Count() ) // hard attributes ?
2184 nRow = pData[nIndex].nRow;
2185 SCROW nAttrRow = std::min( (SCROW)nRow, (SCROW)nEndRow );
2187 ScPatternAttr aNewPattern(*pOldPattern);
2188 SfxItemSet& rSet = aNewPattern.GetItemSet();
2189 for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2190 if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2191 rSet.ClearItem(nId);
2193 if ( aNewPattern == *pDefPattern )
2194 SetPatternArea( nThisRow, nAttrRow, pDefPattern, false );
2195 else
2196 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, true );
2198 Search( nThisRow, nIndex ); // data changed
2201 ++nIndex;
2202 nThisRow = pData[nIndex-1].nRow+1;
2207 // move within a document
2209 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2211 SCROW nStart = nStartRow;
2212 for (SCSIZE i = 0; i < nCount; i++)
2214 if ((pData[i].nRow >= nStartRow) && ((i==0) ? true : pData[i-1].nRow < nEndRow))
2216 // copy (bPutToPool=TRUE)
2217 rAttrArray.SetPatternArea( nStart, std::min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
2218 pData[i].pPattern, true );
2220 nStart = std::max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
2222 DeleteArea(nStartRow, nEndRow);
2226 // copy between documents (Clipboard)
2228 void ScAttrArray::CopyArea(
2229 SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray, sal_Int16 nStripFlags) const
2231 nStartRow -= nDy; // Source
2232 nEndRow -= nDy;
2234 SCROW nDestStart = std::max((long)((long)nStartRow + nDy), (long) 0);
2235 SCROW nDestEnd = std::min((long)((long)nEndRow + nDy), (long) MAXROW);
2237 ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2238 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2239 bool bSamePool = (pSourceDocPool==pDestDocPool);
2241 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2243 if (pData[i].nRow >= nStartRow)
2245 const ScPatternAttr* pOldPattern = pData[i].pPattern;
2246 const ScPatternAttr* pNewPattern;
2248 if (IsDefaultItem( pOldPattern ))
2250 // default: nothing changed
2252 pNewPattern = (const ScPatternAttr*)
2253 &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2255 else if ( nStripFlags )
2257 ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
2258 sal_Int16 nNewFlags = 0;
2259 if ( nStripFlags != SC_MF_ALL )
2260 nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
2261 GetValue() & ~nStripFlags;
2263 if ( nNewFlags )
2264 pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2265 else
2266 pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2268 if (bSamePool)
2269 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
2270 else
2271 pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2272 delete pTmpPattern;
2274 else
2276 if (bSamePool)
2277 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2278 else
2279 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2282 rAttrArray.SetPatternArea(nDestStart,
2283 std::min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
2286 // when pasting from clipboard and skipping filtered rows, the adjusted
2287 // end position can be negative
2288 nDestStart = std::max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2293 // leave flags
2294 // summarized with CopyArea
2296 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2298 nStartRow -= nDy; // Source
2299 nEndRow -= nDy;
2301 SCROW nDestStart = std::max((long)((long)nStartRow + nDy), (long) 0);
2302 SCROW nDestEnd = std::min((long)((long)nEndRow + nDy), (long) MAXROW);
2304 if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
2306 CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2307 return;
2310 ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2311 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2312 bool bSamePool = (pSourceDocPool==pDestDocPool);
2314 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2316 if (pData[i].nRow >= nStartRow)
2318 const ScPatternAttr* pOldPattern = pData[i].pPattern;
2319 const ScPatternAttr* pNewPattern;
2321 if (bSamePool)
2322 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2323 else
2324 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2326 rAttrArray.SetPatternAreaSafe(nDestStart,
2327 std::min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, false);
2330 // when pasting from clipboard and skipping filtered rows, the adjusted
2331 // end position can be negative
2332 nDestStart = std::max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2337 SCsROW ScAttrArray::SearchStyle(
2338 SCsROW nRow, const ScStyleSheet* pSearchStyle, bool bUp,
2339 const ScMarkArray* pMarkArray) const
2341 bool bFound = false;
2343 if (pMarkArray)
2345 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2346 if (!ValidRow(nRow))
2347 return nRow;
2350 SCSIZE nIndex;
2351 Search(nRow, nIndex);
2352 const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2354 while (nIndex < nCount && !bFound)
2356 if (pPattern->GetStyleSheet() == pSearchStyle)
2358 if (pMarkArray)
2360 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2361 SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2362 if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2363 bFound = true;
2365 else
2366 bFound = true;
2369 if (!bFound)
2371 if (bUp)
2373 if (nIndex==0)
2375 nIndex = nCount;
2376 nRow = -1;
2378 else
2380 --nIndex;
2381 nRow = pData[nIndex].nRow;
2382 pPattern = pData[nIndex].pPattern;
2385 else
2387 nRow = pData[nIndex].nRow+1;
2388 ++nIndex;
2389 if (nIndex<nCount)
2390 pPattern = pData[nIndex].pPattern;
2395 OSL_ENSURE( bFound || !ValidRow(nRow), "Internal failure in in ScAttrArray::SearchStyle" );
2397 return nRow;
2401 bool ScAttrArray::SearchStyleRange(
2402 SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
2403 const ScMarkArray* pMarkArray) const
2405 SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2406 if (ValidRow(nStartRow))
2408 SCSIZE nIndex;
2409 Search(nStartRow,nIndex);
2411 rRow = nStartRow;
2412 if (bUp)
2414 if (nIndex>0)
2415 rEndRow = pData[nIndex-1].nRow + 1;
2416 else
2417 rEndRow = 0;
2418 if (pMarkArray)
2420 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
2421 if (nMarkEnd>rEndRow)
2422 rEndRow = nMarkEnd;
2425 else
2427 rEndRow = pData[nIndex].nRow;
2428 if (pMarkArray)
2430 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
2431 if (nMarkEnd<rEndRow)
2432 rEndRow = nMarkEnd;
2436 return true;
2438 else
2439 return false;
2442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */