xref: /aoo42x/main/sc/source/core/data/attarray.cxx (revision 6a261b58)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 
29 //------------------------------------------------------------------------
30 
31 #include "scitems.hxx"
32 #include <svx/algitem.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/bolnitem.hxx>
35 #include <editeng/frmdiritem.hxx>
36 #include <editeng/shaditem.hxx>
37 #include <svl/poolcach.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <unotools/fontcvt.hxx>
40 
41 #include "attarray.hxx"
42 #include "global.hxx"
43 #include "document.hxx"
44 #include "docpool.hxx"
45 #include "patattr.hxx"
46 #include "stlsheet.hxx"
47 #include "stlpool.hxx"
48 #include "markarr.hxx"
49 #include "rechead.hxx"
50 #include "globstr.hrc"
51 #include "segmenttree.hxx"
52 
53 #undef DBG_INVALIDATE
54 #define DBGOUTPUT(s) \
55 	DBG_ERROR( String("Invalidate ") + String(s) + String(": ") \
56 			   + String(nCol) + String('/') + String(aAdrStart.Row()) + String('/') + String(nTab) \
57 			   + String(" bis ") \
58 			   + String(nCol) + String('/') + String(aAdrEnd.Row())   + String('/') + String(nTab) \
59 			  );
60 
61 // STATIC DATA -----------------------------------------------------------
62 
63 
64 //------------------------------------------------------------------------
65 
66 ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
67 	nCol( nNewCol ),
68 	nTab( nNewTab ),
69 	pDocument( pDoc )
70 {
71     nCount = nLimit = 1;
72 	pData = new ScAttrEntry[1];
73 	if (pData)
74 	{
75 		pData[0].nRow = MAXROW;
76 		pData[0].pPattern = pDocument->GetDefPattern();		// ohne Put !!!
77 	}
78 }
79 
80 //------------------------------------------------------------------------
81 
82 ScAttrArray::~ScAttrArray()
83 {
84 #ifdef DBG_UTIL
85 	TestData();
86 #endif
87 
88 	if (pData)
89 	{
90 		ScDocumentPool* pDocPool = pDocument->GetPool();
91 		for (SCSIZE i=0; i<nCount; i++)
92 			pDocPool->Remove(*pData[i].pPattern);
93 
94 		delete[] pData;
95 	}
96 }
97 
98 //------------------------------------------------------------------------
99 #ifdef DBG_UTIL
100 void ScAttrArray::TestData() const
101 {
102 
103 	sal_uInt16 nErr = 0;
104 	if (pData)
105 	{
106         SCSIZE nPos;
107 		for (nPos=0; nPos<nCount; nPos++)
108 		{
109 			if (nPos > 0)
110 				if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow)
111 					++nErr;
112 			if (pData[nPos].pPattern->Which() != ATTR_PATTERN)
113 				++nErr;
114 		}
115         if ( nPos && pData[nPos-1].nRow != MAXROW )
116             ++nErr;
117 	}
118 	if (nErr)
119 	{
120 		ByteString aMsg = ByteString::CreateFromInt32(nErr);
121 		aMsg += " errors in attribute array, column ";
122 		aMsg += ByteString::CreateFromInt32(nCol);
123 		DBG_ERROR( aMsg.GetBuffer() );
124 	}
125 }
126 #endif
127 
128 //------------------------------------------------------------------------
129 
130 void ScAttrArray::Reset( const ScPatternAttr* pPattern, sal_Bool bAlloc )
131 {
132 	if (pData)
133 	{
134 		ScDocumentPool* 	 pDocPool = pDocument->GetPool();
135 		const ScPatternAttr* pOldPattern;
136 		ScAddress			 aAdrStart( nCol, 0, nTab );
137 		ScAddress			 aAdrEnd  ( nCol, 0, nTab );
138 
139 		for (SCSIZE i=0; i<nCount; i++)
140 		{
141 			// ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
142 			pOldPattern = pData[i].pPattern;
143 			sal_Bool bNumFormatChanged;
144 			if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
145 					pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
146 			{
147 				aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
148 				aAdrEnd  .SetRow( pData[i].nRow );
149 				pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
150 #ifdef DBG_INVALIDATE
151 				DBGOUTPUT("Reset");
152 #endif
153 			}
154 			// bedingtes Format gesetzt oder geloescht?
155 			if ( &pPattern->GetItem(ATTR_CONDITIONAL) != &pOldPattern->GetItem(ATTR_CONDITIONAL) )
156 			{
157 				pDocument->ConditionalChanged( ((const SfxUInt32Item&)
158 								pOldPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
159 				pDocument->ConditionalChanged( ((const SfxUInt32Item&)
160 								pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
161 			}
162 			pDocPool->Remove(*pOldPattern);
163 		}
164 		delete[] pData;
165 
166         if (pDocument->IsStreamValid(nTab))
167             pDocument->SetStreamValid(nTab, sal_False);
168 
169 		if (bAlloc)
170 		{
171             nCount = nLimit = 1;
172 			pData = new ScAttrEntry[1];
173 			if (pData)
174 			{
175 				ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
176 				pData[0].nRow = MAXROW;
177 				pData[0].pPattern = pNewPattern;
178 			}
179 		}
180 		else
181 		{
182             nCount = nLimit = 0;
183 			pData = NULL;				// muss sofort wieder belegt werden !
184 		}
185 	}
186 }
187 
188 
189 sal_Bool ScAttrArray::Concat(SCSIZE nPos)
190 {
191 	sal_Bool bRet = sal_False;
192 	if (pData && (nPos < nCount))
193 	{
194 		if (nPos > 0)
195 		{
196 			if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
197 			{
198 				pData[nPos - 1].nRow = pData[nPos].nRow;
199 				pDocument->GetPool()->Remove(*pData[nPos].pPattern);
200 				memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
201 				pData[nCount - 1].pPattern = NULL;
202 				pData[nCount - 1].nRow = 0;
203 				nCount--;
204 				nPos--;
205 				bRet = sal_True;
206 			}
207 		}
208 		if (nPos + 1 < nCount)
209 		{
210 			if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
211 			{
212 				pData[nPos].nRow = pData[nPos + 1].nRow;
213 				pDocument->GetPool()->Remove(*pData[nPos].pPattern);
214 				memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
215 				pData[nCount - 1].pPattern = NULL;
216 				pData[nCount - 1].nRow = 0;
217 				nCount--;
218 				bRet = sal_True;
219 			}
220 		}
221 	}
222 	return bRet;
223 }
224 
225 //------------------------------------------------------------------------
226 
227 sal_Bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
228 {
229 	long	nLo 		= 0;
230 	long	nHi 		= static_cast<long>(nCount) - 1;
231 	long	nStartRow	= 0;
232 	long	nEndRow		= 0;
233 	long	i			= 0;
234 	sal_Bool	bFound		= (nCount == 1);
235 	if (pData)
236 	{
237 		while ( !bFound && nLo <= nHi )
238 		{
239 			i = (nLo + nHi) / 2;
240 			if (i > 0)
241 				nStartRow = (long) pData[i - 1].nRow;
242 			else
243 				nStartRow = -1;
244 			nEndRow = (long) pData[i].nRow;
245 			if (nEndRow < (long) nRow)
246 				nLo = ++i;
247 			else
248 				if (nStartRow >= (long) nRow)
249 					nHi = --i;
250 				else
251 					bFound = sal_True;
252 		}
253 	}
254 	else
255 		bFound = sal_False;
256 
257 	if (bFound)
258 		nIndex=(SCSIZE)i;
259 	else
260 		nIndex=0;
261 	return bFound;
262 }
263 
264 
265 const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
266 {
267 	SCSIZE i;
268 	if (Search( nRow, i ))
269 		return pData[i].pPattern;
270 	else
271 		return NULL;
272 }
273 
274 
275 const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
276 		SCROW& rEndRow, SCROW nRow ) const
277 {
278 	SCSIZE nIndex;
279 	if ( Search( nRow, nIndex ) )
280 	{
281 		if ( nIndex > 0 )
282 			rStartRow = pData[nIndex-1].nRow + 1;
283 		else
284 			rStartRow = 0;
285 		rEndRow = pData[nIndex].nRow;
286 		return pData[nIndex].pPattern;
287 	}
288 	return NULL;
289 }
290 
291 //------------------------------------------------------------------------
292 
293 void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, sal_Bool bPutToPool )
294 {
295 	SetPatternArea( nRow, nRow, pPattern, bPutToPool );
296 }
297 
298 
299 void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, sal_Bool bPutToPool )
300 {
301 	if (ValidRow(nStartRow) && ValidRow(nEndRow))
302 	{
303 		if (bPutToPool)
304 			pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern);
305 
306 		if ((nStartRow == 0) && (nEndRow == MAXROW))
307 			Reset(pPattern);
308 		else
309 		{
310             SCSIZE nNeeded = nCount + 2;
311             if ( nLimit < nNeeded )
312             {
313                 nLimit += SC_ATTRARRAY_DELTA;
314                 if ( nLimit < nNeeded )
315                     nLimit = nNeeded;
316                 ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
317                 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
318 				delete[] pData;
319 				pData = pNewData;
320             }
321 
322             ScAddress       aAdrStart( nCol, 0, nTab );
323             ScAddress       aAdrEnd  ( nCol, 0, nTab );
324 
325             SCSIZE ni = 0;      // number of entries in beginning
326             SCSIZE nx = 0;      // track position
327             SCROW ns = 0;      // start row of track position
328             if ( nStartRow > 0 )
329             {
330                 // skip beginning
331                 SCSIZE nIndex;
332                 Search( nStartRow, nIndex );
333                 ni = nIndex;
334 
335                 if ( ni > 0 )
336                 {
337                     nx = ni;
338                     ns = pData[ni-1].nRow+1;
339                 }
340             }
341 
342             // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
343             // oder bedingte Formate neu gesetzt oder geloescht werden
344             while ( ns <= nEndRow )
345             {
346                 const SfxItemSet& rNewSet = pPattern->GetItemSet();
347                 const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
348 
349                 sal_Bool bNumFormatChanged;
350                 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
351                         rNewSet, rOldSet ) )
352                 {
353                     aAdrStart.SetRow( Max(nStartRow,ns) );
354                     aAdrEnd  .SetRow( Min(nEndRow,pData[nx].nRow) );
355                     pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
356 #ifdef DBG_INVALIDATE
357                     DBGOUTPUT("SetPatternArea");
358 #endif
359                 }
360                 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
361                 {
362                     pDocument->ConditionalChanged( ((const SfxUInt32Item&)
363                                     rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
364                     pDocument->ConditionalChanged( ((const SfxUInt32Item&)
365                                     rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
366                 }
367                 ns = pData[nx].nRow + 1;
368                 nx++;
369             }
370 
371             // continue modifying data array
372 
373             SCSIZE nInsert;     // insert position (MAXROWCOUNT := no insert)
374             sal_Bool bCombined = sal_False;
375             sal_Bool bSplit = sal_False;
376             if ( nStartRow > 0 )
377             {
378                 nInsert = MAXROWCOUNT;
379                 if ( pData[ni].pPattern != pPattern )
380                 {
381                     if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
382                     {   // may be a split or a simple insert or just a shrink,
383                         // row adjustment is done further down
384                         if ( pData[ni].nRow > nEndRow )
385                             bSplit = sal_True;
386                         ni++;
387                         nInsert = ni;
388                     }
389                     else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
390                         nInsert = ni;
391                 }
392                 if ( ni > 0 && pData[ni-1].pPattern == pPattern )
393                 {   // combine
394                     pData[ni-1].nRow = nEndRow;
395                     nInsert = MAXROWCOUNT;
396                     bCombined = sal_True;
397                 }
398             }
399             else
400                 nInsert = 0;
401 
402             SCSIZE nj = ni;     // stop position of range to replace
403             while ( nj < nCount && pData[nj].nRow <= nEndRow )
404                 nj++;
405             if ( !bSplit )
406             {
407                 if ( nj < nCount && pData[nj].pPattern == pPattern )
408                 {   // combine
409                     if ( ni > 0 )
410                     {
411                         if ( pData[ni-1].pPattern == pPattern )
412                         {   // adjacent entries
413                             pData[ni-1].nRow = pData[nj].nRow;
414                             nj++;
415                         }
416                         else if ( ni == nInsert )
417                             pData[ni-1].nRow = nStartRow - 1;   // shrink
418                     }
419                     nInsert = MAXROWCOUNT;
420                     bCombined = sal_True;
421                 }
422                 else if ( ni > 0 && ni == nInsert )
423                     pData[ni-1].nRow = nStartRow - 1;   // shrink
424             }
425             ScDocumentPool* pDocPool = pDocument->GetPool();
426             if ( bSplit )
427             {   // duplicate splitted entry in pool
428                 pDocPool->Put( *pData[ni-1].pPattern );
429             }
430             if ( ni < nj )
431             {   // remove middle entries
432                 for ( SCSIZE nk=ni; nk<nj; nk++)
433                 {   // remove entries from pool
434                     pDocPool->Remove( *pData[nk].pPattern );
435                 }
436                 if ( !bCombined )
437                 {   // replace one entry
438                     pData[ni].nRow = nEndRow;
439                     pData[ni].pPattern = pPattern;
440                     ni++;
441                     nInsert = MAXROWCOUNT;
442                 }
443                 if ( ni < nj )
444                 {   // remove entries
445                     memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
446                     nCount -= nj - ni;
447                 }
448             }
449 
450             if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
451             {   // insert or append new entry
452                 if ( nInsert <= nCount )
453                 {
454                     if ( !bSplit )
455                         memmove( pData + nInsert + 1, pData + nInsert,
456                             (nCount - nInsert) * sizeof(ScAttrEntry) );
457                     else
458                     {
459                         memmove( pData + nInsert + 2, pData + nInsert,
460                             (nCount - nInsert) * sizeof(ScAttrEntry) );
461                         pData[nInsert+1] = pData[nInsert-1];
462                         nCount++;
463                     }
464                 }
465                 if ( nInsert )
466                     pData[nInsert-1].nRow = nStartRow - 1;
467                 pData[nInsert].nRow = nEndRow;
468                 pData[nInsert].pPattern = pPattern;
469                 nCount++;
470             }
471 
472             if (pDocument->IsStreamValid(nTab))
473                 pDocument->SetStreamValid(nTab, sal_False);
474 		}
475 	}
476 //	InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
477 
478 #ifdef DBG_UTIL
479     TestData();
480 #endif
481 }
482 
483 
484 void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
485 {
486 	if (ValidRow(nStartRow) && ValidRow(nEndRow))
487 	{
488 		SCSIZE nPos;
489 		SCROW nStart=0;
490 		if (!Search( nStartRow, nPos ))
491 		{
492 			DBG_ERROR("Search-Fehler");
493 			return;
494 		}
495 
496 		ScAddress aAdrStart( nCol, 0, nTab );
497 		ScAddress aAdrEnd  ( nCol, 0, nTab );
498 
499 		do
500 		{
501 			const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
502 			ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
503 			pNewPattern->SetStyleSheet(pStyle);
504 			SCROW nY1 = nStart;
505 			SCROW nY2 = pData[nPos].nRow;
506 			nStart = pData[nPos].nRow + 1;
507 
508 			if ( *pNewPattern == *pOldPattern )
509 			{
510 				// keep the original pattern (might be default)
511 				// pNewPattern is deleted below
512 				nPos++;
513 			}
514 			else if ( nY1 < nStartRow || nY2 > nEndRow )
515 			{
516 				if (nY1 < nStartRow) nY1=nStartRow;
517 				if (nY2 > nEndRow) nY2=nEndRow;
518 				SetPatternArea( nY1, nY2, pNewPattern, sal_True );
519 				Search( nStart, nPos );
520 			}
521 			else
522 			{
523 				// ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
524 				// bedingte Formate in Vorlagen gibt es (noch) nicht
525 
526 				const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
527 				const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
528 
529 				sal_Bool bNumFormatChanged;
530 				if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
531 						rNewSet, rOldSet ) )
532 				{
533 					aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
534 					aAdrEnd  .SetRow( pData[nPos].nRow );
535 					pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
536 #ifdef DBG_INVALIDATE
537 					DBGOUTPUT("ApplyStyleArea");
538 #endif
539 				}
540 
541 				pDocument->GetPool()->Remove(*pData[nPos].pPattern);
542 				pData[nPos].pPattern = (const ScPatternAttr*)
543 											&pDocument->GetPool()->Put(*pNewPattern);
544 				if (Concat(nPos))
545 					Search(nStart, nPos);
546 				else
547 					nPos++;
548 			}
549 			delete pNewPattern;
550 		}
551 		while ((nStart <= nEndRow) && (nPos < nCount));
552 
553         if (pDocument->IsStreamValid(nTab))
554             pDocument->SetStreamValid(nTab, sal_False);
555 	}
556 
557 #ifdef DBG_UTIL
558 	TestData();
559 #endif
560 }
561 
562 
563 	// const wird weggecastet, weil es sonst
564 	// zu ineffizient/kompliziert wird!
565 #define SET_LINECOLOR(dest,c)						\
566 	if ((dest))										\
567 	{												\
568 		((SvxBorderLine*)(dest))->SetColor((c));	\
569 	}
570 
571 #define SET_LINE(dest,src) 								\
572 	if ((dest))											\
573 	{													\
574 		SvxBorderLine* pCast = (SvxBorderLine*)(dest);	\
575 		pCast->SetOutWidth((src)->GetOutWidth());		\
576 		pCast->SetInWidth ((src)->GetInWidth());		\
577 		pCast->SetDistance((src)->GetDistance());		\
578 	}
579 
580 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
581 									  const SvxBorderLine* pLine, sal_Bool bColorOnly )
582 {
583 	if ( bColorOnly && !pLine )
584 		return;
585 
586 	if (ValidRow(nStartRow) && ValidRow(nEndRow))
587 	{
588 		SCSIZE nPos;
589 		SCROW nStart=0;
590 		if (!Search( nStartRow, nPos ))
591 		{
592 			DBG_ERROR("Search-Fehler");
593 			return;
594 		}
595 
596 		do
597 		{
598 			const ScPatternAttr*	pOldPattern = pData[nPos].pPattern;
599             const SfxItemSet&       rOldSet = pOldPattern->GetItemSet();
600             const SfxPoolItem*      pBoxItem = 0;
601             SfxItemState            eState = rOldSet.GetItemState( ATTR_BORDER, sal_True, &pBoxItem );
602             const SfxPoolItem*      pTLBRItem = 0;
603             SfxItemState            eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, sal_True, &pTLBRItem );
604             const SfxPoolItem*      pBLTRItem = 0;
605             SfxItemState            eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, sal_True, &pBLTRItem );
606 
607             if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) )
608 			{
609 				ScPatternAttr*	pNewPattern = new ScPatternAttr(*pOldPattern);
610                 SfxItemSet&     rNewSet = pNewPattern->GetItemSet();
611 				SCROW			nY1 = nStart;
612 				SCROW			nY2 = pData[nPos].nRow;
613 
614                 SvxBoxItem*     pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0;
615                 SvxLineItem*    pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0;
616                 SvxLineItem*    pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0;
617 
618 				// Linienattribute holen und mit Parametern aktualisieren
619 
620 				if ( !pLine )
621 				{
622                     if( pNewBoxItem )
623                     {
624                         if ( pNewBoxItem->GetTop() )    pNewBoxItem->SetLine( NULL, BOX_LINE_TOP );
625                         if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM );
626                         if ( pNewBoxItem->GetLeft() )   pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT );
627                         if ( pNewBoxItem->GetRight() )  pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT );
628                     }
629                     if( pNewTLBRItem && pNewTLBRItem->GetLine() )
630                         pNewTLBRItem->SetLine( 0 );
631                     if( pNewBLTRItem && pNewBLTRItem->GetLine() )
632                         pNewBLTRItem->SetLine( 0 );
633 				}
634 				else
635 				{
636 					if ( bColorOnly )
637 					{
638                         Color aColor( pLine->GetColor() );
639                         if( pNewBoxItem )
640                         {
641                             SET_LINECOLOR( pNewBoxItem->GetTop(),    aColor );
642                             SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
643                             SET_LINECOLOR( pNewBoxItem->GetLeft(),   aColor );
644                             SET_LINECOLOR( pNewBoxItem->GetRight(),   aColor );
645                         }
646                         if( pNewTLBRItem )
647                             SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
648                         if( pNewBLTRItem )
649                             SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
650 					}
651 					else
652 					{
653                         if( pNewBoxItem )
654                         {
655                             SET_LINE( pNewBoxItem->GetTop(),    pLine );
656                             SET_LINE( pNewBoxItem->GetBottom(), pLine );
657                             SET_LINE( pNewBoxItem->GetLeft(),   pLine );
658                             SET_LINE( pNewBoxItem->GetRight(),   pLine );
659                         }
660                         if( pNewTLBRItem )
661                             SET_LINE( pNewTLBRItem->GetLine(), pLine );
662                         if( pNewBLTRItem )
663                             SET_LINE( pNewBLTRItem->GetLine(), pLine );
664 					}
665 				}
666                 if( pNewBoxItem )   rNewSet.Put( *pNewBoxItem );
667                 if( pNewTLBRItem )  rNewSet.Put( *pNewTLBRItem );
668                 if( pNewBLTRItem )  rNewSet.Put( *pNewBLTRItem );
669 
670 				nStart = pData[nPos].nRow + 1;
671 
672 				if ( nY1 < nStartRow || nY2 > nEndRow )
673 				{
674 					if (nY1 < nStartRow) nY1=nStartRow;
675 					if (nY2 > nEndRow) nY2=nEndRow;
676 					SetPatternArea( nY1, nY2, pNewPattern, sal_True );
677 					Search( nStart, nPos );
678 				}
679 				else
680 				{
681 						//! aus Pool loeschen?
682 					pDocument->GetPool()->Remove(*pData[nPos].pPattern);
683 					pData[nPos].pPattern = (const ScPatternAttr*)
684 								&pDocument->GetPool()->Put(*pNewPattern);
685 
686 					if (Concat(nPos))
687 						Search(nStart, nPos);
688 					else
689 						nPos++;
690 				}
691                 delete pNewBoxItem;
692                 delete pNewTLBRItem;
693                 delete pNewBLTRItem;
694 				delete pNewPattern;
695 			}
696 			else
697 			{
698 				nStart = pData[nPos].nRow + 1;
699 				nPos++;
700 			}
701 		}
702 		while ((nStart <= nEndRow) && (nPos < nCount));
703 	}
704 }
705 
706 #undef SET_LINECOLOR
707 #undef SET_LINE
708 
709 
710 void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache )
711 {
712 #ifdef DBG_UTIL
713 	TestData();
714 #endif
715 
716 	if (ValidRow(nStartRow) && ValidRow(nEndRow))
717 	{
718 		SCSIZE nPos;
719 		SCROW nStart=0;
720 		if (!Search( nStartRow, nPos ))
721 		{
722 			DBG_ERROR("Search-Fehler");
723 			return;
724 		}
725 
726 		ScAddress aAdrStart( nCol, 0, nTab );
727 		ScAddress aAdrEnd  ( nCol, 0, nTab );
728 
729 		do
730 		{
731 			const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
732 			const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, sal_True );
733 			ScDocumentPool::CheckRef( *pOldPattern );
734 			ScDocumentPool::CheckRef( *pNewPattern );
735 			if (pNewPattern != pOldPattern)
736 			{
737 				SCROW nY1 = nStart;
738 				SCROW nY2 = pData[nPos].nRow;
739 				nStart = pData[nPos].nRow + 1;
740 
741 				if ( nY1 < nStartRow || nY2 > nEndRow )
742 				{
743 					if (nY1 < nStartRow) nY1=nStartRow;
744 					if (nY2 > nEndRow) nY2=nEndRow;
745 					SetPatternArea( nY1, nY2, pNewPattern );
746 					Search( nStart, nPos );
747 				}
748 				else
749 				{
750 					// ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
751 
752 					const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
753 					const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
754 
755 					sal_Bool bNumFormatChanged;
756 					if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
757 							rNewSet, rOldSet ) )
758 					{
759 						aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
760 						aAdrEnd  .SetRow( pData[nPos].nRow );
761 						pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
762 #ifdef DBG_INVALIDATE
763 						DBGOUTPUT("ApplyCacheArea");
764 #endif
765 					}
766 
767 					// bedingte Formate neu gesetzt oder geloescht ?
768 
769 					if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
770 					{
771 						pDocument->ConditionalChanged( ((const SfxUInt32Item&)
772 										rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
773 						pDocument->ConditionalChanged( ((const SfxUInt32Item&)
774 										rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
775 					}
776 
777 					pDocument->GetPool()->Remove(*pData[nPos].pPattern);
778 					pData[nPos].pPattern = pNewPattern;
779 					if (Concat(nPos))
780 						Search(nStart, nPos);
781 					else
782 						++nPos;
783 				}
784 			}
785 			else
786 			{
787 //!!!!!!!!!!!!!!!!!! mit diesem Remove gibt es Abstuerze (Calc1 Import)
788 //!				pDocument->GetPool()->Remove(*pNewPattern);
789 				nStart = pData[nPos].nRow + 1;
790 				++nPos;
791 			}
792 		}
793 		while (nStart <= nEndRow);
794 
795         if (pDocument->IsStreamValid(nTab))
796             pDocument->SetStreamValid(nTab, sal_False);
797 	}
798 
799 #ifdef DBG_UTIL
800 	TestData();
801 #endif
802 }
803 
804 
805 void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
806 {
807 	const SfxPoolItem* pNewItem;
808 	const SfxPoolItem* pOldItem;
809 	for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
810 	{
811 		//	pMergeSet hat keinen Parent
812 		SfxItemState eOldState = rMergeSet.GetItemState( nId, sal_False, &pOldItem );
813 
814 		if ( eOldState == SFX_ITEM_DEFAULT )				// Default
815 		{
816 			SfxItemState eNewState = rSource.GetItemState( nId, sal_True, &pNewItem );
817 			if ( eNewState == SFX_ITEM_SET )
818 			{
819 				if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
820 					rMergeSet.InvalidateItem( nId );
821 			}
822 		}
823 		else if ( eOldState == SFX_ITEM_SET )				// Item gesetzt
824 		{
825 			SfxItemState eNewState = rSource.GetItemState( nId, sal_True, &pNewItem );
826 			if ( eNewState == SFX_ITEM_SET )
827 			{
828 				if ( pNewItem != pOldItem )					// beide gepuhlt
829 					rMergeSet.InvalidateItem( nId );
830 			}
831 			else			// Default
832 			{
833 				if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
834 					rMergeSet.InvalidateItem( nId );
835 			}
836 		}
837 		//	Dontcare bleibt Dontcare
838 	}
839 }
840 
841 
842 void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
843 									ScMergePatternState& rState, sal_Bool bDeep ) const
844 {
845 	if (ValidRow(nStartRow) && ValidRow(nEndRow))
846 	{
847 		SCSIZE nPos;
848 		SCROW nStart=0;
849 		if (!Search( nStartRow, nPos ))
850 		{
851 			DBG_ERROR("Search-Fehler");
852 			return;
853 		}
854 
855 		do
856 		{
857 			//	gleiche Patterns muessen nicht mehrfach angesehen werden
858 
859 			const ScPatternAttr* pPattern = pData[nPos].pPattern;
860 			if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
861 			{
862 				const SfxItemSet& rThisSet = pPattern->GetItemSet();
863 				if (rState.pItemSet)
864 				{
865 					//	(*ppSet)->MergeValues( rThisSet, sal_False );
866 					//	geht nicht, weil die Vorlagen nicht beruecksichtigt werden
867 
868 					if (bDeep)
869 						lcl_MergeDeep( *rState.pItemSet, rThisSet );
870 					else
871 						rState.pItemSet->MergeValues( rThisSet, sal_False );
872 				}
873 				else
874 				{
875 					//	erstes Pattern - in Set ohne Parent kopieren
876 					rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() );
877 					rState.pItemSet->Set( rThisSet, bDeep );
878 				}
879 
880 				rState.pOld2 = rState.pOld1;
881 				rState.pOld1 = pPattern;
882 			}
883 
884 			nStart = pData[nPos].nRow + 1;
885 			++nPos;
886 		}
887 		while (nStart <= nEndRow);
888 	}
889 }
890 
891 
892 
893 //			Umrandung zusammenbauen
894 
895 sal_Bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
896 							sal_uInt8& rModified, const SvxBorderLine*& rpNew )
897 {
898 	if (rModified == SC_LINE_DONTCARE)
899 		return sal_False;						// weiter geht's nicht
900 
901 	if (rModified == SC_LINE_EMPTY)
902 	{
903 		rModified = SC_LINE_SET;
904 		rpNew = pNewLine;
905 		return sal_True;						// zum ersten mal gesetzt
906 	}
907 
908 	if (pOldLine == pNewLine)
909 	{
910 		rpNew = pOldLine;
911 		return sal_False;
912 	}
913 
914 	if (pOldLine && pNewLine)
915 		if (*pOldLine == *pNewLine)
916 		{
917 			rpNew = pOldLine;
918 			return sal_False;
919 		}
920 
921 	rModified = SC_LINE_DONTCARE;
922 	rpNew = NULL;
923 	return sal_True;							// andere Linie -> dontcare
924 }
925 
926 
927 void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
928 								ScLineFlags& rFlags, const ScPatternAttr* pPattern,
929 								sal_Bool bLeft, SCCOL nDistRight, sal_Bool bTop, SCROW nDistBottom )
930 {
931 	//	rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
932 	const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
933 	if ( rMerge.GetColMerge() == nDistRight + 1 )
934 		nDistRight = 0;
935 	if ( rMerge.GetRowMerge() == nDistBottom + 1 )
936 		nDistBottom = 0;
937 
938 	const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER );
939 	const SvxBorderLine* pLeftAttr	 = pCellFrame->GetLeft();
940 	const SvxBorderLine* pRightAttr	 = pCellFrame->GetRight();
941 	const SvxBorderLine* pTopAttr	 = pCellFrame->GetTop();
942 	const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
943 	const SvxBorderLine* pNew;
944 
945 	if (bTop)
946 	{
947 		if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
948 			pLineOuter->SetLine( pNew, BOX_LINE_TOP );
949 	}
950 	else
951 	{
952 		if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
953 			pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
954 	}
955 
956 	if (nDistBottom == 0)
957 	{
958 		if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
959 			pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM );
960 	}
961 	else
962 	{
963 		if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
964 			pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
965 	}
966 
967 	if (bLeft)
968 	{
969 		if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
970 			pLineOuter->SetLine( pNew, BOX_LINE_LEFT );
971 	}
972 	else
973 	{
974 		if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
975 			pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
976 	}
977 
978 	if (nDistRight == 0)
979 	{
980 		if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
981 			pLineOuter->SetLine( pNew, BOX_LINE_RIGHT );
982 	}
983 	else
984 	{
985 		if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
986 			pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
987 	}
988 }
989 
990 
991 void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
992 					ScLineFlags& rFlags,
993 					SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) const
994 {
995 	const ScPatternAttr* pPattern;
996 
997 	if (nStartRow == nEndRow)
998 	{
999 		pPattern = GetPattern( nStartRow );
1000 		lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True, 0 );
1001 	}
1002 	else
1003 	{
1004 		pPattern = GetPattern( nStartRow );
1005 		lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True,
1006 							nEndRow-nStartRow );
1007 
1008 		SCSIZE nStartIndex;
1009 		SCSIZE nEndIndex;
1010 		Search( nStartRow+1, nStartIndex );
1011 		Search( nEndRow-1, nEndIndex );
1012 		for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1013 		{
1014 			pPattern = (ScPatternAttr*) pData[i].pPattern;
1015 			lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False,
1016 							nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
1017 			// nDistBottom hier immer > 0
1018 		}
1019 
1020 		pPattern = GetPattern( nEndRow );
1021 		lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False, 0 );
1022 	}
1023 }
1024 
1025 //
1026 //	Rahmen anwenden
1027 //
1028 
1029 //	ApplyFrame - auf einen Eintrag im Array
1030 
1031 
1032 sal_Bool ScAttrArray::ApplyFrame( const SvxBoxItem*		pBoxItem,
1033 							  const SvxBoxInfoItem* pBoxInfoItem,
1034 							  SCROW nStartRow, SCROW nEndRow,
1035 							  sal_Bool bLeft, SCCOL nDistRight, sal_Bool bTop, SCROW nDistBottom )
1036 {
1037 	DBG_ASSERT( pBoxItem && pBoxInfoItem, "Linienattribute fehlen!" );
1038 
1039 	const ScPatternAttr* pPattern = GetPattern( nStartRow );
1040 	const SvxBoxItem* pOldFrame = (const SvxBoxItem*)
1041 								  &pPattern->GetItemSet().Get( ATTR_BORDER );
1042 
1043 	//	rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
1044 	const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
1045 	if ( rMerge.GetColMerge() == nDistRight + 1 )
1046 		nDistRight = 0;
1047 	if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1048 		nDistBottom = 0;
1049 
1050 	SvxBoxItem aNewFrame( *pOldFrame );
1051 
1052 	if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1053 		aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1054 			BOX_LINE_LEFT );
1055 	if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1056 		aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1057 			BOX_LINE_RIGHT );
1058 	if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
1059 		aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
1060 			BOX_LINE_TOP );
1061 	if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
1062 		aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
1063 			BOX_LINE_BOTTOM );
1064 
1065 	if (aNewFrame == *pOldFrame)
1066 	{
1067 		// nothing to do
1068 		return sal_False;
1069 	}
1070 	else
1071 	{
1072 		SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
1073 		ApplyCacheArea( nStartRow, nEndRow, &aCache );
1074 
1075 /*		ScPatternAttr* pNewPattern = (ScPatternAttr*) pPattern->Clone();
1076 		pNewPattern->GetItemSet().Put( aNewFrame );
1077 		SetPatternArea( nStartRow, nEndRow, pNewPattern, sal_True );
1078 */
1079 		return sal_True;
1080 	}
1081 }
1082 
1083 
1084 void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
1085 							SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight )
1086 {
1087 	if (nStartRow == nEndRow)
1088 		ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, sal_True, 0 );
1089 	else
1090 	{
1091 		ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1092 						sal_True, nEndRow-nStartRow );
1093 
1094 		if ( nEndRow > nStartRow+1 )				// innerer Teil vorhanden?
1095 		{
1096 			SCSIZE nStartIndex;
1097 			SCSIZE nEndIndex;
1098 			Search( nStartRow+1, nStartIndex );
1099 			Search( nEndRow-1, nEndIndex );
1100 			SCROW nTmpStart = nStartRow+1;
1101 			SCROW nTmpEnd;
1102 			for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1103 			{
1104 				nTmpEnd = Min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
1105 				sal_Bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
1106 											bLeft, nDistRight, sal_False, nEndRow-nTmpEnd );
1107 				nTmpStart = nTmpEnd+1;
1108 				if (bChanged)
1109 				{
1110 					Search(nTmpStart, i);
1111 					Search(nEndRow-1, nEndIndex);
1112 				}
1113 				else
1114 					i++;
1115 			}
1116 		}
1117 
1118 		ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, sal_False, 0 );
1119 	}
1120 }
1121 
1122 
1123 long lcl_LineSize( const SvxBorderLine& rLine )
1124 {
1125 	//	nur eine Linie -> halbe Breite, min. 20
1126 	//	doppelte Linie -> halber Abstand + eine Linie (je min. 20)
1127 
1128 	long nTotal = 0;
1129 	sal_uInt16 nWidth = Max( rLine.GetOutWidth(), rLine.GetInWidth() );
1130 	sal_uInt16 nDist = rLine.GetDistance();
1131 	if (nDist)
1132 	{
1133 		DBG_ASSERT( rLine.GetOutWidth() && rLine.GetInWidth(),
1134 						"Linie hat Abstand, aber nur eine Breite ???" );
1135 
1136 //		nTotal += ( nDist > 40 ) ? ( nDist / 2 ) : 20;
1137 		nTotal += ( nDist > 20 ) ? nDist : 20;
1138 		nTotal += ( nWidth > 20 ) ? nWidth : 20;
1139 	}
1140 	else if (nWidth)
1141 //		nTotal += ( nWidth > 40 ) ? ( nWidth / 2 ) : 20;
1142 		nTotal += ( nWidth > 20 ) ? nWidth  : 20;
1143 
1144 		//!	auch halbieren ???
1145 
1146 	return nTotal;
1147 }
1148 
1149 
1150 sal_Bool ScAttrArray::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
1151 								sal_Bool bLeft, sal_Bool bRight ) const
1152 {
1153 	SCSIZE nStartIndex;
1154 	SCSIZE nEndIndex;
1155 	Search( nRow1, nStartIndex );
1156 	Search( nRow2, nEndIndex );
1157 	sal_Bool bFound = sal_False;
1158 
1159 	const SvxBoxItem* pItem = 0;
1160 	const SvxBorderLine* pLine = 0;
1161 	long nCmp;
1162 
1163 	//	oben
1164 
1165 	pItem = (const SvxBoxItem*) &pData[nStartIndex].pPattern->GetItem(ATTR_BORDER);
1166 	pLine = pItem->GetTop();
1167 	if (pLine)
1168 	{
1169 		nCmp = lcl_LineSize(*pLine);
1170 		if ( nCmp > rSizes.Top() )
1171 			rSizes.Top() = nCmp;
1172 		bFound = sal_True;
1173 	}
1174 
1175 	//	unten
1176 
1177 	if ( nEndIndex != nStartIndex )
1178 		pItem = (const SvxBoxItem*) &pData[nEndIndex].pPattern->GetItem(ATTR_BORDER);
1179 	pLine = pItem->GetBottom();
1180 	if (pLine)
1181 	{
1182 		nCmp = lcl_LineSize(*pLine);
1183 		if ( nCmp > rSizes.Bottom() )
1184 			rSizes.Bottom() = nCmp;
1185 		bFound = sal_True;
1186 	}
1187 
1188 	if ( bLeft || bRight )
1189 		for ( SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1190 		{
1191 			pItem = (const SvxBoxItem*) &pData[i].pPattern->GetItem(ATTR_BORDER);
1192 
1193 			//	links
1194 
1195 			if (bLeft)
1196 			{
1197 				pLine = pItem->GetLeft();
1198 				if (pLine)
1199 				{
1200 					nCmp = lcl_LineSize(*pLine);
1201 					if ( nCmp > rSizes.Left() )
1202 						rSizes.Left() = nCmp;
1203 					bFound = sal_True;
1204 				}
1205 			}
1206 
1207 			//	rechts
1208 
1209 			if (bRight)
1210 			{
1211 				pLine = pItem->GetRight();
1212 				if (pLine)
1213 				{
1214 					nCmp = lcl_LineSize(*pLine);
1215 					if ( nCmp > rSizes.Right() )
1216 						rSizes.Right() = nCmp;
1217 					bFound = sal_True;
1218 				}
1219 			}
1220 		}
1221 
1222 	return bFound;
1223 }
1224 
1225 //	Testen, ob Bereich bestimmtes Attribut enthaelt
1226 
1227 bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
1228 {
1229     SCSIZE nStartIndex;
1230     SCSIZE nEndIndex;
1231     Search( nRow1, nStartIndex );
1232     Search( nRow2, nEndIndex );
1233     bool bFound = false;
1234 
1235     for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1236     {
1237         const ScPatternAttr* pPattern = pData[i].pPattern;
1238         if ( nMask & HASATTR_MERGED )
1239         {
1240             const ScMergeAttr* pMerge =
1241                     (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1242             if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1243                 bFound = true;
1244         }
1245         if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
1246         {
1247             const ScMergeFlagAttr* pMergeFlag =
1248                     (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG );
1249             if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
1250                 bFound = true;
1251             if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
1252                 bFound = true;
1253             if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
1254                 bFound = true;
1255         }
1256         if ( nMask & HASATTR_LINES )
1257         {
1258             const SvxBoxItem* pBox =
1259                     (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER );
1260             if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1261                 bFound = true;
1262         }
1263         if ( nMask & HASATTR_SHADOW )
1264         {
1265             const SvxShadowItem* pShadow =
1266                     (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1267             if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
1268                 bFound = true;
1269         }
1270         if ( nMask & HASATTR_CONDITIONAL )
1271         {
1272             const SfxUInt32Item* pConditional =
1273                     (const SfxUInt32Item*) &pPattern->GetItem( ATTR_CONDITIONAL );
1274             if ( pConditional->GetValue() != 0 )
1275                 bFound = true;
1276         }
1277         if ( nMask & HASATTR_PROTECTED )
1278         {
1279             const ScProtectionAttr* pProtect =
1280                     (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION );
1281             if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1282                 bFound = true;
1283         }
1284         if ( nMask & HASATTR_ROTATE )
1285         {
1286             const SfxInt32Item* pRotate =
1287                     (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE );
1288             // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1289             // (see ScPatternAttr::GetCellOrientation)
1290             sal_Int32 nAngle = pRotate->GetValue();
1291             if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
1292                 bFound = true;
1293         }
1294         if ( nMask & HASATTR_NEEDHEIGHT )
1295         {
1296             if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
1297                 bFound = true;
1298             else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
1299                 bFound = true;
1300             else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
1301                         GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
1302                 bFound = true;
1303             else if (((const SfxUInt32Item&)pPattern->GetItem( ATTR_CONDITIONAL )).GetValue())
1304                 bFound = true;
1305             else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
1306                 bFound = true;
1307         }
1308         if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
1309         {
1310             const SvxShadowItem* pShadow =
1311                     (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1312             SvxShadowLocation eLoc = pShadow->GetLocation();
1313             if ( nMask & HASATTR_SHADOW_RIGHT )
1314                 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1315                     bFound = true;
1316             if ( nMask & HASATTR_SHADOW_DOWN )
1317                 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1318                     bFound = true;
1319         }
1320         if ( nMask & HASATTR_RTL )
1321         {
1322             const SvxFrameDirectionItem& rDirection =
1323                     (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR );
1324             if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP )
1325                 bFound = true;
1326         }
1327         if ( nMask & HASATTR_RIGHTORCENTER )
1328         {
1329             //  called only if the sheet is LTR, so physical=logical alignment can be assumed
1330             SvxCellHorJustify eHorJust = (SvxCellHorJustify)
1331                     ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
1332             if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
1333                 bFound = true;
1334         }
1335     }
1336 
1337     return bFound;
1338 }
1339 
1340 //	Bereich um evtl. enthaltene Zusammenfassungen erweitern
1341 //	und evtl. MergeFlag anpassen (bRefresh)
1342 
1343 sal_Bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
1344 								SCCOL& rPaintCol, SCROW& rPaintRow,
1345 								sal_Bool bRefresh, sal_Bool bAttrs )
1346 {
1347 	const ScPatternAttr* pPattern;
1348 	const ScMergeAttr* pItem;
1349 	SCSIZE nStartIndex;
1350 	SCSIZE nEndIndex;
1351 	Search( nStartRow, nStartIndex );
1352 	Search( nEndRow, nEndIndex );
1353 	sal_Bool bFound = sal_False;
1354 
1355 	for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1356 	{
1357 		pPattern = pData[i].pPattern;
1358 		pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1359 		SCsCOL	nCountX = pItem->GetColMerge();
1360 		SCsROW	nCountY = pItem->GetRowMerge();
1361 		if (nCountX>1 || nCountY>1)
1362 		{
1363 			SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
1364 			SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1365 			SCROW nMergeEndRow = nThisRow + nCountY - 1;
1366 			if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
1367 				rPaintCol = nMergeEndCol;
1368 			if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
1369 				rPaintRow = nMergeEndRow;
1370 			bFound = sal_True;
1371 
1372 			if (bAttrs)
1373 			{
1374 				const SvxShadowItem* pShadow =
1375 						(const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1376 				SvxShadowLocation eLoc = pShadow->GetLocation();
1377 				if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1378 					if ( nMergeEndCol+1 > rPaintCol && nMergeEndCol < MAXCOL )
1379 						rPaintCol = nMergeEndCol+1;
1380 				if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1381 					if ( nMergeEndRow+1 > rPaintRow && nMergeEndRow < MAXROW )
1382 						rPaintRow = nMergeEndRow+1;
1383 			}
1384 
1385 			if (bRefresh)
1386 			{
1387 				if ( nMergeEndCol > nThisCol )
1388 					pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
1389 								nTab, SC_MF_HOR );
1390 				if ( nMergeEndRow > nThisRow )
1391 					pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1392 								nTab, SC_MF_VER );
1393 				if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1394 					pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1395 								nTab, SC_MF_HOR | SC_MF_VER );
1396 
1397 				Search( nThisRow, i );					// Daten wurden veraendert
1398 				Search( nStartRow, nStartIndex );
1399 				Search( nEndRow, nEndIndex );
1400 			}
1401 		}
1402 	}
1403 
1404 	return bFound;
1405 }
1406 
1407 
1408 sal_Bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1409 {
1410 	sal_Bool bFound = sal_False;
1411 	const ScPatternAttr* pPattern;
1412 	const ScMergeAttr* pItem;
1413 	SCSIZE nIndex;
1414 
1415 	Search( nStartRow, nIndex );
1416 	SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1417 	if (nThisStart < nStartRow)
1418 		nThisStart = nStartRow;
1419 
1420 	while ( nThisStart <= nEndRow )
1421 	{
1422 		SCROW nThisEnd = pData[nIndex].nRow;
1423 		if (nThisEnd > nEndRow)
1424 			nThisEnd = nEndRow;
1425 
1426 		pPattern = pData[nIndex].pPattern;
1427 		pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1428 		SCsCOL	nCountX = pItem->GetColMerge();
1429 		SCsROW	nCountY = pItem->GetRowMerge();
1430 		if (nCountX>1 || nCountY>1)
1431 		{
1432 			const ScMergeAttr* pAttr = (const ScMergeAttr*)
1433 											&pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
1434 			const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*)
1435 											&pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
1436 
1437 			DBG_ASSERT( nCountY==1 || nThisStart==nThisEnd, "was'n hier los?" );
1438 
1439 			SCCOL nThisCol = nCol;
1440 			SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1441 			SCROW nMergeEndRow = nThisEnd + nCountY - 1;
1442 
1443 			//!	ApplyAttr fuer Bereiche !!!
1444 
1445 			for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
1446 				pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
1447 
1448 			ScPatternAttr* 	pNewPattern = new ScPatternAttr( pDocument->GetPool() );
1449 			SfxItemSet*		pSet = &pNewPattern->GetItemSet();
1450 			pSet->Put( *pFlagAttr );
1451 			pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
1452 												nTab, *pNewPattern );
1453 			delete pNewPattern;
1454 
1455 			Search( nThisEnd, nIndex );					// Daten wurden veraendert !!!
1456 		}
1457 
1458 		++nIndex;
1459 		if ( nIndex < nCount )
1460 			nThisStart = pData[nIndex-1].nRow+1;
1461 		else
1462 			nThisStart = MAXROW+1;		// Ende
1463 	}
1464 
1465 	return bFound;
1466 }
1467 
1468 			//		Bereich loeschen, aber Merge-Flags stehenlassen
1469 
1470 void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow)
1471 {
1472 	SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), sal_True );
1473 }
1474 
1475 
1476 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
1477 						const ScPatternAttr* pWantedPattern, sal_Bool bDefault )
1478 {
1479 	const ScPatternAttr*	pOldPattern;
1480 	const ScMergeFlagAttr*	pItem;
1481 
1482 	SCSIZE	nIndex;
1483 	SCROW	nRow;
1484 	SCROW	nThisRow;
1485 	sal_Bool	bFirstUse = sal_True;
1486 
1487 	Search( nStartRow, nIndex );
1488 	nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1489 	while ( nThisRow <= nEndRow )
1490 	{
1491 		pOldPattern = pData[nIndex].pPattern;
1492 		if (pOldPattern != pWantedPattern)							//! else-Zweig ?
1493 		{
1494 			if (nThisRow < nStartRow) nThisRow = nStartRow;
1495 			nRow = pData[nIndex].nRow;
1496 			SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1497 			pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG );
1498 
1499 			if (pItem->IsOverlapped() || pItem->HasAutoFilter())
1500 			{
1501 				//	#108045# default-constructing a ScPatternAttr for DeleteArea doesn't work
1502 				//	because it would have no cell style information.
1503 				//	Instead, the document's GetDefPattern is copied. Since it is passed as
1504 				//	pWantedPattern, no special treatment of default is needed here anymore.
1505 				ScPatternAttr*	pNewPattern = new ScPatternAttr( *pWantedPattern );
1506 				SfxItemSet*		pSet = &pNewPattern->GetItemSet();
1507 				pSet->Put( *pItem );
1508 				SetPatternArea( nThisRow, nAttrRow, pNewPattern, sal_True );
1509 				delete pNewPattern;
1510 			}
1511 			else
1512 			{
1513 				if ( !bDefault )
1514 				{
1515 					if (bFirstUse)
1516 						bFirstUse = sal_False;
1517 					else
1518 						pDocument->GetPool()->Put( *pWantedPattern );		// im Pool ist es schon!
1519 				}
1520 				SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
1521 			}
1522 
1523 			Search( nThisRow, nIndex );					// Daten wurden veraendert !!!
1524 		}
1525 
1526 		++nIndex;
1527 		nThisRow = pData[nIndex-1].nRow+1;
1528 	}
1529 }
1530 
1531 
1532 sal_Bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1533 {
1534 	const ScPatternAttr* pOldPattern;
1535 
1536 	sal_Int16	nOldValue;
1537 	SCSIZE	nIndex;
1538 	SCROW	nRow;
1539 	SCROW	nThisRow;
1540 	sal_Bool	bChanged = sal_False;
1541 
1542 	Search( nStartRow, nIndex );
1543 	nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1544 	if (nThisRow < nStartRow) nThisRow = nStartRow;
1545 
1546 	while ( nThisRow <= nEndRow )
1547 	{
1548 		pOldPattern = pData[nIndex].pPattern;
1549 		nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1550 		if ( (nOldValue | nFlags) != nOldValue )
1551 		{
1552 			nRow = pData[nIndex].nRow;
1553 			SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1554 			ScPatternAttr aNewPattern(*pOldPattern);
1555 			aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1556 			SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
1557 			Search( nThisRow, nIndex );									// Daten wurden veraendert !!!
1558 			bChanged = sal_True;
1559 		}
1560 
1561 		++nIndex;
1562 		nThisRow = pData[nIndex-1].nRow+1;
1563 	}
1564 
1565 	return bChanged;
1566 }
1567 
1568 
1569 sal_Bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
1570 {
1571 	const ScPatternAttr* pOldPattern;
1572 
1573 	sal_Int16	nOldValue;
1574 	SCSIZE	nIndex;
1575 	SCROW	nRow;
1576 	SCROW	nThisRow;
1577 	sal_Bool	bChanged = sal_False;
1578 
1579 	Search( nStartRow, nIndex );
1580 	nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1581 	if (nThisRow < nStartRow) nThisRow = nStartRow;
1582 
1583 	while ( nThisRow <= nEndRow )
1584 	{
1585 		pOldPattern = pData[nIndex].pPattern;
1586 		nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1587 		if ( (nOldValue & ~nFlags) != nOldValue )
1588 		{
1589 			nRow = pData[nIndex].nRow;
1590 			SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1591 			ScPatternAttr aNewPattern(*pOldPattern);
1592 			aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1593 			SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
1594 			Search( nThisRow, nIndex );									// Daten wurden veraendert !!!
1595 			bChanged = sal_True;
1596 		}
1597 
1598 		++nIndex;
1599 		nThisRow = pData[nIndex-1].nRow+1;
1600 	}
1601 
1602 	return bChanged;
1603 }
1604 
1605 
1606 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
1607 {
1608 	const ScPatternAttr* pOldPattern;
1609 
1610 	SCSIZE	nIndex;
1611 	SCROW	nRow;
1612 	SCROW	nThisRow;
1613 
1614 	Search( nStartRow, nIndex );
1615 	nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1616 	if (nThisRow < nStartRow) nThisRow = nStartRow;
1617 
1618 	while ( nThisRow <= nEndRow )
1619 	{
1620 		pOldPattern = pData[nIndex].pPattern;
1621 		if ( pOldPattern->HasItemsSet( pWhich ) )
1622 		{
1623 			ScPatternAttr aNewPattern(*pOldPattern);
1624 			aNewPattern.ClearItems( pWhich );
1625 
1626 			nRow = pData[nIndex].nRow;
1627 			SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1628 			SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
1629 			Search( nThisRow, nIndex );									// Daten wurden veraendert !!!
1630 		}
1631 
1632 		++nIndex;
1633 		nThisRow = pData[nIndex-1].nRow+1;
1634 	}
1635 }
1636 
1637 
1638 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, sal_Bool bIncrement )
1639 {
1640 	SCSIZE nIndex;
1641 	Search( nStartRow, nIndex );
1642 	SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1643 	if (nThisStart < nStartRow) nThisStart = nStartRow;
1644 
1645 	while ( nThisStart <= nEndRow )
1646 	{
1647 		const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
1648 		const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1649 		const SfxPoolItem* pItem;
1650 
1651 		sal_Bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, sal_False, &pItem ) != SFX_ITEM_SET
1652 						|| ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT );
1653 		sal_uInt16 nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
1654 		sal_uInt16 nNewValue = nOldValue;
1655 		if ( bIncrement )
1656 		{
1657 			if ( nNewValue < SC_MAX_INDENT )
1658 			{
1659 				nNewValue += SC_INDENT_STEP;
1660 				if ( nNewValue > SC_MAX_INDENT ) nNewValue = SC_MAX_INDENT;
1661 			}
1662 		}
1663 		else
1664 		{
1665 			if ( nNewValue > 0 )
1666 			{
1667 				if ( nNewValue > SC_INDENT_STEP )
1668 					nNewValue -= SC_INDENT_STEP;
1669 				else
1670 					nNewValue = 0;
1671 			}
1672 		}
1673 
1674 		if ( bNeedJust || nNewValue != nOldValue )
1675 		{
1676 			SCROW nThisEnd = pData[nIndex].nRow;
1677 			SCROW nAttrRow = Min( nThisEnd, nEndRow );
1678 			ScPatternAttr aNewPattern(*pOldPattern);
1679 			aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
1680 			if ( bNeedJust )
1681 				aNewPattern.GetItemSet().Put(
1682 								SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
1683 			SetPatternArea( nThisStart, nAttrRow, &aNewPattern, sal_True );
1684 
1685 			nThisStart = nThisEnd + 1;
1686 			Search( nThisStart, nIndex );				// Daten wurden veraendert !!!
1687 		}
1688 		else
1689 		{
1690 			nThisStart = pData[nIndex].nRow + 1;		// weiterzaehlen...
1691 			++nIndex;
1692 		}
1693 	}
1694 }
1695 
1696 
1697 SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, sal_Bool bUp ) const
1698 {
1699 	long nRet = nRow;
1700 	if (VALIDROW(nRow))
1701 	{
1702 		SCSIZE nIndex;
1703 		Search(nRow, nIndex);
1704 		while (((const ScProtectionAttr&)pData[nIndex].pPattern->
1705 				GetItem(ATTR_PROTECTION)).GetProtection())
1706 		{
1707 			if (bUp)
1708 			{
1709 				if (nIndex==0)
1710 					return -1;					// nichts gefunden
1711 				--nIndex;
1712 				nRet = pData[nIndex].nRow;
1713 			}
1714 			else
1715 			{
1716 				nRet = pData[nIndex].nRow+1;
1717 				++nIndex;
1718 				if (nIndex>=nCount)
1719 					return MAXROW+1;			// nichts gefunden
1720 			}
1721 		}
1722 	}
1723 	return nRet;
1724 }
1725 
1726 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1727 {
1728 	SCROW nStart = 0;
1729 	SCSIZE nPos = 0;
1730 	while (nPos < nCount)
1731 	{
1732 		SCROW nEnd = pData[nPos].nRow;
1733 		if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1734 		{
1735 //			for (SCROW nRow = nStart; nRow <= nEnd; nRow++)
1736 //				pUsed[nRow] = sal_True;
1737 
1738             rUsedRows.setTrue(nStart, nEnd);
1739 
1740 			if (bReset)
1741 			{
1742 				ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern);
1743 				pDocument->GetPool()->Remove(*pData[nPos].pPattern);
1744 				pNewPattern->SetStyleSheet( (ScStyleSheet*)
1745 					pDocument->GetStyleSheetPool()->
1746 						Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
1747 							  SFX_STYLE_FAMILY_PARA,
1748 							  SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) );
1749 				pData[nPos].pPattern = (const ScPatternAttr*)
1750 											&pDocument->GetPool()->Put(*pNewPattern);
1751 				delete pNewPattern;
1752 
1753 				if (Concat(nPos))
1754 				{
1755 					Search(nStart, nPos);
1756 					--nPos;							// wegen ++ am Ende
1757 				}
1758 			}
1759 		}
1760 		nStart = nEnd + 1;
1761 		++nPos;
1762 	}
1763 }
1764 
1765 
1766 sal_Bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
1767         sal_Bool bGatherAllStyles ) const
1768 {
1769 	sal_Bool	bIsUsed	= sal_False;
1770 	SCSIZE	nPos	= 0;
1771 
1772 	while ( nPos < nCount )
1773 	{
1774         const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
1775         if ( pStyle )
1776         {
1777             pStyle->SetUsage( ScStyleSheet::USED );
1778             if ( pStyle == &rStyle )
1779             {
1780                 if ( !bGatherAllStyles )
1781                     return sal_True;
1782                 bIsUsed = sal_True;
1783             }
1784         }
1785 		nPos++;
1786 	}
1787 
1788 	return bIsUsed;
1789 }
1790 
1791 
1792 sal_Bool ScAttrArray::IsEmpty() const
1793 {
1794 	if (nCount == 1)
1795 	{
1796 		if ( pData[0].pPattern != pDocument->GetDefPattern() )
1797 			return sal_False;
1798 		else
1799 			return sal_True;
1800 	}
1801 	else
1802 		return sal_False;
1803 }
1804 
1805 
1806 //UNUSED2008-05  SCROW ScAttrArray::GetFirstEntryPos() const
1807 //UNUSED2008-05  {
1808 //UNUSED2008-05      DBG_ASSERT( nCount, "nCount = 0" );
1809 //UNUSED2008-05
1810 //UNUSED2008-05      if ( pData[0].pPattern != pDocument->GetDefPattern() )
1811 //UNUSED2008-05          return 0;
1812 //UNUSED2008-05      else
1813 //UNUSED2008-05      {
1814 //UNUSED2008-05          if (nCount==1)
1815 //UNUSED2008-05              return 0;                               // leer
1816 //UNUSED2008-05          else
1817 //UNUSED2008-05              return pData[0].nRow + 1;
1818 //UNUSED2008-05      }
1819 //UNUSED2008-05  }
1820 //UNUSED2008-05
1821 //UNUSED2008-05
1822 //UNUSED2008-05  SCROW ScAttrArray::GetLastEntryPos( sal_Bool bIncludeBottom ) const
1823 //UNUSED2008-05  {
1824 //UNUSED2008-05      DBG_ASSERT( nCount, "nCount == 0" );
1825 //UNUSED2008-05
1826 //UNUSED2008-05      if (bIncludeBottom)
1827 //UNUSED2008-05          bIncludeBottom = ( pData[nCount-1].pPattern != pDocument->GetDefPattern() );
1828 //UNUSED2008-05
1829 //UNUSED2008-05      if (bIncludeBottom)
1830 //UNUSED2008-05          return MAXROW;
1831 //UNUSED2008-05      else
1832 //UNUSED2008-05      {
1833 //UNUSED2008-05          if (nCount<=1)
1834 //UNUSED2008-05              return 0;                               // leer
1835 //UNUSED2008-05          else
1836 //UNUSED2008-05              return pData[nCount-2].nRow;
1837 //UNUSED2008-05      }
1838 //UNUSED2008-05  }
1839 
1840 
1841 sal_Bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1842 {
1843     DBG_ASSERT( nCount, "nCount == 0" );
1844 
1845     sal_Bool bFound = sal_False;
1846     SCSIZE nStart = 0;
1847 
1848     // Skip first entry if more than 1 row.
1849     // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1850 
1851     SCSIZE nVisStart = 1;
1852     while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
1853         ++nVisStart;
1854     if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 )	// more than 1 row?
1855         nStart = nVisStart;
1856 
1857 	while ( nStart < nCount && !bFound )
1858 	{
1859 		if ( pData[nStart].pPattern->IsVisible() )
1860 		{
1861 			rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
1862 			bFound = sal_True;
1863 		}
1864 		else
1865 			++nStart;
1866 	}
1867 
1868     return bFound;
1869 }
1870 
1871 // size (rows) of a range of attributes after cell content where the search is stopped
1872 // (more than a default page size, 2*42 because it's as good as any number)
1873 
1874 const SCROW SC_VISATTR_STOP = 84;
1875 
1876 sal_Bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
1877 {
1878     //  #i30830# changed behavior:
1879     //  ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1880     //  below the last content cell
1881 
1882     if ( nLastData == MAXROW )
1883     {
1884         rLastRow = MAXROW;      // can't look for attributes below MAXROW
1885         return sal_True;
1886     }
1887 
1888     sal_Bool bFound = sal_False;
1889 
1890     //  loop backwards from the end instead of using Search, assuming that
1891     //  there usually aren't many attributes below the last cell
1892 
1893     SCSIZE nPos = nCount;
1894     while ( nPos > 0 && pData[nPos-1].nRow > nLastData )
1895     {
1896         SCSIZE nEndPos = nPos - 1;
1897         SCSIZE nStartPos = nEndPos;         // find range of visually equal formats
1898         while ( nStartPos > 0 &&
1899                 pData[nStartPos-1].nRow > nLastData &&
1900                 pData[nStartPos-1].pPattern->IsVisibleEqual(*pData[nStartPos].pPattern) )
1901             --nStartPos;
1902 
1903         SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos-1].nRow + 1 ) : 0;
1904         if ( nAttrStartRow <= nLastData )
1905             nAttrStartRow = nLastData + 1;
1906         SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1907         if ( nAttrSize >= SC_VISATTR_STOP )
1908         {
1909             bFound = sal_False;        // ignore this range and below
1910         }
1911         else if ( !bFound && pData[nEndPos].pPattern->IsVisible() )
1912         {
1913             rLastRow = pData[nEndPos].nRow;
1914             bFound = sal_True;
1915         }
1916 
1917         nPos = nStartPos;           // look further from the top of the range
1918     }
1919 
1920     return bFound;
1921 }
1922 
1923 sal_Bool ScAttrArray::GetLastAttr( SCROW& rLastRow, SCROW nLastData ) const
1924 {
1925     if ( nLastData == MAXROW )
1926     {
1927         rLastRow = MAXROW;
1928         return sal_True;
1929     }
1930 
1931     sal_Bool bFound = sal_False;
1932 
1933     // Loop backwards from the end instead of using Search, assuming that
1934     // there usually aren't many attributes below the last cell.
1935     SCSIZE nPos = nCount;
1936     while ( nPos > 0 && pData[nPos - 1].nRow > nLastData )
1937     {
1938         SCSIZE nEndPos = nPos - 1;
1939         SCSIZE nStartPos = nEndPos;
1940         while ( nStartPos > 0 && pData[nStartPos - 1].nRow > nLastData &&
1941                 pData[nStartPos - 1].pPattern->IsEqual( *pData[nStartPos].pPattern ) )
1942             --nStartPos;
1943 
1944         SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos - 1].nRow + 1 ) : 0;
1945         if ( nAttrStartRow <= nLastData )
1946             nAttrStartRow = nLastData + 1;
1947         SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1948         if ( nAttrSize >= SC_VISATTR_STOP )
1949         {
1950             bFound = sal_False;
1951         }
1952         else if ( !bFound )
1953         {
1954             rLastRow = pData[nEndPos].nRow;
1955             bFound = sal_True;
1956         }
1957 
1958         // look further from the top of the range.
1959         nPos = nStartPos;
1960     }
1961 
1962     return bFound;
1963 }
1964 
1965 
1966 sal_Bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1967 {
1968 	SCSIZE nIndex;
1969 	Search( nStartRow, nIndex );
1970 	SCROW nThisStart = nStartRow;
1971 	sal_Bool bFound = sal_False;
1972 	while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
1973 	{
1974 		if ( pData[nIndex].pPattern->IsVisible() )
1975 			bFound = sal_True;
1976 
1977 		nThisStart = pData[nIndex].nRow + 1;
1978 		++nIndex;
1979 	}
1980 
1981 	return bFound;
1982 }
1983 
1984 
1985 sal_Bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
1986 									SCROW nStartRow, SCROW nEndRow ) const
1987 {
1988 	sal_Bool bEqual = sal_True;
1989 	SCSIZE nThisPos = 0;
1990 	SCSIZE nOtherPos = 0;
1991 	if ( nStartRow > 0 )
1992 	{
1993 		Search( nStartRow, nThisPos );
1994 		rOther.Search( nStartRow, nOtherPos );
1995 	}
1996 
1997 	while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1998 	{
1999 		SCROW nThisRow = pData[nThisPos].nRow;
2000 		SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
2001 		const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
2002 		const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
2003 		bEqual = ( pThisPattern == pOtherPattern ||
2004 					pThisPattern->IsVisibleEqual(*pOtherPattern) );
2005 
2006 		if ( nThisRow >= nOtherRow )
2007 		{
2008 			if ( nOtherRow >= nEndRow ) break;
2009 			++nOtherPos;
2010 		}
2011 		if ( nThisRow <= nOtherRow )
2012 		{
2013 			if ( nThisRow >= nEndRow ) break;
2014 			++nThisPos;
2015 		}
2016 	}
2017 
2018 	return bEqual;
2019 }
2020 
2021 
2022 sal_Bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
2023 {
2024 	//!	mit IsVisibleEqual zusammenfassen?
2025 
2026 	sal_Bool bEqual = sal_True;
2027 	SCSIZE nThisPos = 0;
2028 	SCSIZE nOtherPos = 0;
2029 	if ( nStartRow > 0 )
2030 	{
2031 		Search( nStartRow, nThisPos );
2032 		rOther.Search( nStartRow, nOtherPos );
2033 	}
2034 
2035 	while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
2036 	{
2037 		SCROW nThisRow = pData[nThisPos].nRow;
2038 		SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
2039 		const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
2040 		const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
2041 		bEqual = ( pThisPattern == pOtherPattern );
2042 
2043 		if ( nThisRow >= nOtherRow )
2044 		{
2045 			if ( nOtherRow >= nEndRow ) break;
2046 			++nOtherPos;
2047 		}
2048 		if ( nThisRow <= nOtherRow )
2049 		{
2050 			if ( nThisRow >= nEndRow ) break;
2051 			++nThisPos;
2052 		}
2053 	}
2054 
2055 	return bEqual;
2056 }
2057 
2058 
2059 sal_Bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2060 {
2061 	//	horizontal zusammengefasste duerfen nicht herausgeschoben werden
2062 	//	(ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen)
2063 
2064 	sal_Bool bTest = sal_True;
2065 	if (!IsEmpty())
2066 	{
2067 		SCSIZE nIndex = 0;
2068 		if ( nStartRow > 0 )
2069 			Search( nStartRow, nIndex );
2070 
2071 		for ( ; nIndex < nCount; nIndex++ )
2072 		{
2073 			if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
2074 						GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2075 			{
2076 				bTest = sal_False;						// darf nicht herausgeschoben werden
2077 				break;
2078 			}
2079 			if ( pData[nIndex].nRow >= nEndRow )	// Ende des Bereichs
2080 				break;
2081 		}
2082 	}
2083 	return bTest;
2084 }
2085 
2086 
2087 sal_Bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2088 {
2089 	//	wenn die erste herausgeschobene Zeile vertikal ueberlappt ist,
2090 	//	wuerde eine kaputte Zusammenfassung uebrigbleiben
2091 
2092 	if (pData)
2093 	{
2094 		//	MAXROW + 1 - nSize	= erste herausgeschobene Zeile
2095 
2096 		SCSIZE nFirstLost = nCount-1;
2097         while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2098 			--nFirstLost;
2099 
2100 		if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
2101 							GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2102 			return sal_False;
2103 	}
2104 
2105 	return sal_True;
2106 }
2107 
2108 
2109 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2110 {
2111 	if (!pData)
2112 		return;
2113 
2114 	SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0;		// Vorgaenger erweitern
2115 	SCSIZE nIndex;
2116 	Search( nSearch, nIndex );
2117 
2118 	//	ein gesetztes ScMergeAttr darf nicht ausgedehnt werden
2119 	//	(darum hinterher wieder loeschen)
2120 
2121 	sal_Bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
2122 
2123 	SCSIZE nRemove = 0;
2124 	SCSIZE i;
2125 	for (i = nIndex; i < nCount-1; i++)
2126 	{
2127 		SCROW nNew = pData[i].nRow + nSize;
2128 		if ( nNew >= MAXROW )					// Ende erreicht ?
2129 		{
2130 			nNew = MAXROW;
2131 			if (!nRemove)
2132 				nRemove = i+1;					// folgende loeschen
2133 		}
2134 		pData[i].nRow = nNew;
2135 	}
2136 
2137 	//	muessen Eintraege am Ende geloescht werden?
2138 
2139 	if (nRemove && nRemove < nCount)
2140 		DeleteRange( nRemove, nCount-1 );
2141 
2142 	if (bDoMerge)			// ausgedehntes ScMergeAttr wieder reparieren
2143 	{
2144 			//!	ApplyAttr fuer Bereiche !!!
2145 
2146 		const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
2147         for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2148             pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2149 
2150 		//	im eingefuegten Bereich ist nichts zusammengefasst
2151 	}
2152 
2153     // Don't duplicate the merge flags in the inserted row.
2154     // #i108488# SC_MF_SCENARIO has to be allowed.
2155     RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
2156 }
2157 
2158 
2159 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2160 {
2161 	if (pData)
2162 	{
2163 		sal_Bool bFirst=sal_True;
2164         SCSIZE nStartIndex = 0;
2165         SCSIZE nEndIndex = 0;
2166 		SCSIZE i;
2167 
2168 		for ( i = 0; i < nCount-1; i++)
2169             if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2170 			{
2171 				if (bFirst)
2172 				{
2173 					nStartIndex = i;
2174 					bFirst = sal_False;
2175 				}
2176 				nEndIndex = i;
2177 			}
2178 		if (!bFirst)
2179 		{
2180 			SCROW nStart;
2181 			if (nStartIndex==0)
2182 				nStart = 0;
2183 			else
2184 				nStart = pData[nStartIndex-1].nRow + 1;
2185 
2186 			if (nStart < nStartRow)
2187 			{
2188 				pData[nStartIndex].nRow = nStartRow - 1;
2189 				++nStartIndex;
2190 			}
2191 			if (nEndIndex >= nStartIndex)
2192 			{
2193 				DeleteRange( nStartIndex, nEndIndex );
2194 				if (nStartIndex > 0)
2195 					if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
2196 						DeleteRange( nStartIndex-1, nStartIndex-1 );
2197 			}
2198 		}
2199 		for (i = 0; i < nCount-1; i++)
2200 			if (pData[i].nRow >= nStartRow)
2201 				pData[i].nRow -= nSize;
2202 
2203 //		unten nicht Default-Pattern nachschieben, um Druckbereiche erkennen zu koennen
2204 //		stattdessen nur Merge-Flags loeschen
2205 
2206 		RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
2207 	}
2208 }
2209 
2210 
2211 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2212 {
2213 	ScDocumentPool* pDocPool = pDocument->GetPool();
2214 	for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2215 		pDocPool->Remove(*pData[i].pPattern);
2216 
2217 	memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
2218 	nCount -= nEndIndex-nStartIndex+1;
2219 }
2220 
2221 
2222 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2223 {
2224 	RemoveAreaMerge( nStartRow, nEndRow );			// von zusammengefassten auch die Flags loeschen
2225 
2226 	if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
2227 		SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
2228 	else
2229 		DeleteAreaSafe( nStartRow, nEndRow );		// Merge-Flags stehenlassen
2230 }
2231 
2232 
2233 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2234 {
2235 	const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2236 	const ScPatternAttr* pOldPattern;
2237 
2238 	SCSIZE	nIndex;
2239 	SCROW	nRow;
2240 	SCROW	nThisRow;
2241 
2242 	Search( nStartRow, nIndex );
2243 	nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
2244 	if (nThisRow < nStartRow) nThisRow = nStartRow;
2245 
2246 	while ( nThisRow <= nEndRow )
2247 	{
2248 		pOldPattern = pData[nIndex].pPattern;
2249 
2250 		if ( pOldPattern->GetItemSet().Count() )		// harte Attribute ?
2251 		{
2252 			nRow = pData[nIndex].nRow;
2253 			SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
2254 
2255 			ScPatternAttr aNewPattern(*pOldPattern);
2256 			SfxItemSet& rSet = aNewPattern.GetItemSet();
2257 			for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2258 				if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2259 					rSet.ClearItem(nId);
2260 
2261 			if ( aNewPattern == *pDefPattern )
2262 				SetPatternArea( nThisRow, nAttrRow, pDefPattern, sal_False );
2263 			else
2264 				SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
2265 
2266 			Search( nThisRow, nIndex );									// Daten wurden veraendert !!!
2267 		}
2268 
2269 		++nIndex;
2270 		nThisRow = pData[nIndex-1].nRow+1;
2271 	}
2272 }
2273 
2274 		// Verschieben innerhalb eines Dokuments
2275 
2276 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2277 {
2278 	SCROW nStart = nStartRow;
2279 	for (SCSIZE i = 0; i < nCount; i++)
2280 	{
2281 		if ((pData[i].nRow >= nStartRow) && ((i==0) ? sal_True : pData[i-1].nRow < nEndRow))
2282 		{
2283 			//	Kopieren (bPutToPool=sal_True)
2284 			rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
2285 										pData[i].pPattern, sal_True );
2286 		}
2287 		nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
2288 	}
2289 	DeleteArea(nStartRow, nEndRow);
2290 }
2291 
2292 
2293 		// Kopieren zwischen Dokumenten (Clipboard)
2294 
2295 void ScAttrArray::CopyArea( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray,
2296 								sal_Int16 nStripFlags )
2297 {
2298 	nStartRow -= nDy;		// Source
2299 	nEndRow -= nDy;
2300 
2301 	SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2302 	SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2303 
2304 	ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2305 	ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2306 	sal_Bool bSamePool = (pSourceDocPool==pDestDocPool);
2307 
2308 	for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2309 	{
2310 		if (pData[i].nRow >= nStartRow)
2311 		{
2312 			const ScPatternAttr* pOldPattern = pData[i].pPattern;
2313 			const ScPatternAttr* pNewPattern;
2314 
2315 			if (IsDefaultItem( pOldPattern ))
2316 			{
2317 				//	am Default muss nichts veraendert werden
2318 
2319 				pNewPattern = (const ScPatternAttr*)
2320 								&pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2321 			}
2322 			else if ( nStripFlags )
2323 			{
2324 				ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
2325 				sal_Int16 nNewFlags = 0;
2326 				if ( nStripFlags != SC_MF_ALL )
2327 					nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
2328 								GetValue() & ~nStripFlags;
2329 
2330 				if ( nNewFlags )
2331 					pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2332 				else
2333 					pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2334 
2335 				if (bSamePool)
2336 					pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
2337 				else
2338 					pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2339 				delete pTmpPattern;
2340 			}
2341 			else
2342 			{
2343 				if (bSamePool)
2344 					pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2345 				else
2346 					pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2347 			}
2348 
2349 			rAttrArray.SetPatternArea(nDestStart,
2350 							Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
2351 		}
2352 
2353 		// when pasting from clipboard and skipping filtered rows, the adjusted end position
2354 		// can be negative
2355 		nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2356 	}
2357 }
2358 
2359 		// Flags stehenlassen
2360 		//! mit CopyArea zusammenfassen !!!
2361 
2362 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2363 {
2364 	nStartRow -= nDy;		// Source
2365 	nEndRow -= nDy;
2366 
2367 	SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2368 	SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2369 
2370 	if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
2371 	{
2372 		CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2373 		return;
2374 	}
2375 
2376 	ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2377 	ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2378 	sal_Bool bSamePool = (pSourceDocPool==pDestDocPool);
2379 
2380 	for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2381 	{
2382 		if (pData[i].nRow >= nStartRow)
2383 		{
2384 			const ScPatternAttr* pOldPattern = pData[i].pPattern;
2385 			const ScPatternAttr* pNewPattern;
2386 
2387 			if (bSamePool)
2388 				pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2389 			else
2390 				pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2391 
2392 			rAttrArray.SetPatternAreaSafe(nDestStart,
2393 							Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, sal_False);
2394 		}
2395 
2396 		// when pasting from clipboard and skipping filtered rows, the adjusted end position
2397 		// can be negative
2398 		nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2399 	}
2400 }
2401 
2402 
2403 SCsROW ScAttrArray::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2404 									sal_Bool bUp, ScMarkArray* pMarkArray )
2405 {
2406 	sal_Bool bFound = sal_False;
2407 
2408 	if (pMarkArray)
2409 	{
2410 		nRow = pMarkArray->GetNextMarked( nRow, bUp );
2411 		if (!VALIDROW(nRow))
2412 			return nRow;
2413 	}
2414 
2415 	SCSIZE nIndex;
2416 	Search(nRow, nIndex);
2417 	const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2418 
2419 	while (nIndex < nCount && !bFound)
2420 	{
2421 		if (pPattern->GetStyleSheet() == pSearchStyle)
2422 		{
2423 			if (pMarkArray)
2424 			{
2425 				nRow = pMarkArray->GetNextMarked( nRow, bUp );
2426 				SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2427 				if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2428 					bFound = sal_True;
2429 			}
2430 			else
2431 				bFound = sal_True;
2432 		}
2433 
2434 		if (!bFound)
2435 		{
2436 			if (bUp)
2437 			{
2438 				if (nIndex==0)
2439                 {
2440                     nIndex = nCount;
2441 					nRow = -1;
2442                 }
2443                 else
2444 				{
2445                     --nIndex;
2446 					nRow = pData[nIndex].nRow;
2447 					pPattern = pData[nIndex].pPattern;
2448 				}
2449 			}
2450 			else
2451 			{
2452 				nRow = pData[nIndex].nRow+1;
2453 				++nIndex;
2454 				if (nIndex<nCount)
2455 					pPattern = pData[nIndex].pPattern;
2456 			}
2457 		}
2458 	}
2459 
2460 	DBG_ASSERT( bFound || !ValidRow(nRow), "interner Fehler in ScAttrArray::SearchStyle" );
2461 
2462 	return nRow;
2463 }
2464 
2465 
2466 sal_Bool ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow,
2467 						const ScStyleSheet* pSearchStyle, sal_Bool bUp, ScMarkArray* pMarkArray )
2468 {
2469 	SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2470 	if (VALIDROW(nStartRow))
2471 	{
2472 		SCSIZE nIndex;
2473 		Search(nStartRow,nIndex);
2474 
2475 		rRow = nStartRow;
2476 		if (bUp)
2477 		{
2478 			if (nIndex>0)
2479 				rEndRow = pData[nIndex-1].nRow + 1;
2480 			else
2481 				rEndRow = 0;
2482 			if (pMarkArray)
2483 			{
2484 				SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_True );
2485 				if (nMarkEnd>rEndRow)
2486 					rEndRow = nMarkEnd;
2487 			}
2488 		}
2489 		else
2490 		{
2491 			rEndRow = pData[nIndex].nRow;
2492 			if (pMarkArray)
2493 			{
2494 				SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_False );
2495 				if (nMarkEnd<rEndRow)
2496 					rEndRow = nMarkEnd;
2497 			}
2498 		}
2499 
2500 		return sal_True;
2501 	}
2502 	else
2503 		return sal_False;
2504 }
2505 
2506 //------------------------------------------------------------------------
2507 //
2508 //							Laden / Speichern
2509 //
2510 
2511 
2512 #if 0
2513 void ScAttrArray::Save( SvStream& /* rStream */ ) const
2514 {
2515 #if SC_ROWLIMIT_STREAM_ACCESS
2516 #error address types changed!
2517     ScWriteHeader aHdr( rStream, 8 );
2518 
2519     ScDocumentPool* pDocPool = pDocument->GetPool();
2520 
2521     sal_uInt16 nSaveCount = nCount;
2522     SCROW nSaveMaxRow = pDocument->GetSrcMaxRow();
2523     if ( nSaveMaxRow != MAXROW )
2524     {
2525         if ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow )
2526         {
2527             pDocument->SetLostData();           // Warnung ausgeben
2528             do
2529                 --nSaveCount;
2530             while ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow );
2531         }
2532     }
2533 
2534     rStream << nSaveCount;
2535 
2536     const SfxPoolItem* pItem;
2537     for (SCSIZE i=0; i<nSaveCount; i++)
2538     {
2539         rStream << Min( pData[i].nRow, nSaveMaxRow );
2540 
2541         const ScPatternAttr* pPattern = pData[i].pPattern;
2542         pDocPool->StoreSurrogate( rStream, pPattern );
2543 
2544         //	sal_False, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen:
2545         if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,sal_False,&pItem) == SFX_ITEM_SET)
2546             pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2547 
2548         if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,sal_False,&pItem) == SFX_ITEM_SET)
2549             pDocument->SetValidationUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2550     }
2551 #endif // SC_ROWLIMIT_STREAM_ACCESS
2552 }
2553 
2554 
2555 void ScAttrArray::Load( SvStream& /* rStream */ )
2556 {
2557 #if SC_ROWLIMIT_STREAM_ACCESS
2558 #error address types changed!
2559     ScDocumentPool* pDocPool = pDocument->GetPool();
2560 
2561     ScReadHeader aHdr( rStream );
2562 
2563     sal_uInt16 nNewCount;
2564     rStream >> nNewCount;
2565     if ( nNewCount > MAXROW+1 )                     // wuerde das Array zu gross?
2566     {
2567         pDocument->SetLostData();
2568         rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2569         return;
2570     }
2571 
2572     Reset( pDocument->GetDefPattern(), sal_False );     // loeschen
2573     pData = new ScAttrEntry[nNewCount];             // neu anlegen
2574     for (SCSIZE i=0; i<nNewCount; i++)
2575     {
2576         rStream >> pData[i].nRow;
2577 
2578         sal_uInt16 nWhich = ATTR_PATTERN;
2579         const ScPatternAttr* pNewPattern = (const ScPatternAttr*)
2580                                            pDocPool->LoadSurrogate( rStream, nWhich, ATTR_PATTERN );
2581         if (!pNewPattern)
2582         {
2583             // da is was schiefgelaufen
2584             DBG_ERROR("ScAttrArray::Load: Surrogat nicht im Pool");
2585             pNewPattern = pDocument->GetDefPattern();
2586         }
2587         ScDocumentPool::CheckRef( *pNewPattern );
2588         pData[i].pPattern = pNewPattern;
2589 
2590         // LoadSurrogate erhoeht auch die Ref
2591     }
2592     nCount = nLimit = nNewCount;
2593 
2594     if ( nCount > 1 && pData[nCount-2].nRow >= MAXROW ) // faengt ein Attribut hinter MAXROW an?
2595     {
2596         pDocument->SetLostData();
2597         rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2598         return;
2599     }
2600 
2601     if ( pDocument->GetSrcMaxRow() != MAXROW )          // Ende anpassen?
2602     {
2603         //	Ende immer auf MAXROW umsetzen (nur auf 32 Bit)
2604 
2605         DBG_ASSERT( pData[nCount-1].nRow == pDocument->GetSrcMaxRow(), "Attribut-Ende ?!?" );
2606         pData[nCount-1].nRow = MAXROW;
2607     }
2608 #endif // SC_ROWLIMIT_STREAM_ACCESS
2609 }
2610 #endif
2611 
2612 
2613 //UNUSED2008-05  void ScAttrArray::ConvertFontsAfterLoad()
2614 //UNUSED2008-05  {
2615 //UNUSED2008-05      ScFontToSubsFontConverter_AutoPtr xFontConverter;
2616 //UNUSED2008-05      const sal_uLong nFlags = FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
2617 //UNUSED2008-05      SCSIZE   nIndex = 0;
2618 //UNUSED2008-05      SCROW  nThisRow = 0;
2619 //UNUSED2008-05
2620 //UNUSED2008-05      while ( nThisRow <= MAXROW )
2621 //UNUSED2008-05      {
2622 //UNUSED2008-05          const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
2623 //UNUSED2008-05          const SfxPoolItem* pItem;
2624 //UNUSED2008-05          if( pOldPattern->GetItemSet().GetItemState( ATTR_FONT, sal_False, &pItem ) == SFX_ITEM_SET )
2625 //UNUSED2008-05          {
2626 //UNUSED2008-05              const SvxFontItem* pFontItem = (const SvxFontItem*) pItem;
2627 //UNUSED2008-05              const String& rOldName = pFontItem->GetFamilyName();
2628 //UNUSED2008-05              xFontConverter = CreateFontToSubsFontConverter( rOldName, nFlags );
2629 //UNUSED2008-05              if ( xFontConverter )
2630 //UNUSED2008-05              {
2631 //UNUSED2008-05                  String aNewName( GetFontToSubsFontName( xFontConverter ) );
2632 //UNUSED2008-05                  if ( aNewName != rOldName )
2633 //UNUSED2008-05                  {
2634 //UNUSED2008-05                      SCROW nAttrRow = pData[nIndex].nRow;
2635 //UNUSED2008-05                      SvxFontItem aNewItem( pFontItem->GetFamily(), aNewName,
2636 //UNUSED2008-05                          pFontItem->GetStyleName(), pFontItem->GetPitch(),
2637 //UNUSED2008-05                          RTL_TEXTENCODING_DONTKNOW, ATTR_FONT );
2638 //UNUSED2008-05                      ScPatternAttr aNewPattern( *pOldPattern );
2639 //UNUSED2008-05                      aNewPattern.GetItemSet().Put( aNewItem );
2640 //UNUSED2008-05                      SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
2641 //UNUSED2008-05                      Search( nThisRow, nIndex );     //! data changed
2642 //UNUSED2008-05                  }
2643 //UNUSED2008-05              }
2644 //UNUSED2008-05          }
2645 //UNUSED2008-05          ++nIndex;
2646 //UNUSED2008-05          nThisRow = pData[nIndex-1].nRow+1;
2647 //UNUSED2008-05      }
2648 //UNUSED2008-05  }
2649 
2650