xref: /aoo41x/main/sc/source/core/data/attarray.cxx (revision b3f79822)
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 
1924 sal_Bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1925 {
1926 	SCSIZE nIndex;
1927 	Search( nStartRow, nIndex );
1928 	SCROW nThisStart = nStartRow;
1929 	sal_Bool bFound = sal_False;
1930 	while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
1931 	{
1932 		if ( pData[nIndex].pPattern->IsVisible() )
1933 			bFound = sal_True;
1934 
1935 		nThisStart = pData[nIndex].nRow + 1;
1936 		++nIndex;
1937 	}
1938 
1939 	return bFound;
1940 }
1941 
1942 
1943 sal_Bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
1944 									SCROW nStartRow, SCROW nEndRow ) const
1945 {
1946 	sal_Bool bEqual = sal_True;
1947 	SCSIZE nThisPos = 0;
1948 	SCSIZE nOtherPos = 0;
1949 	if ( nStartRow > 0 )
1950 	{
1951 		Search( nStartRow, nThisPos );
1952 		rOther.Search( nStartRow, nOtherPos );
1953 	}
1954 
1955 	while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1956 	{
1957 		SCROW nThisRow = pData[nThisPos].nRow;
1958 		SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1959 		const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1960 		const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1961 		bEqual = ( pThisPattern == pOtherPattern ||
1962 					pThisPattern->IsVisibleEqual(*pOtherPattern) );
1963 
1964 		if ( nThisRow >= nOtherRow )
1965 		{
1966 			if ( nOtherRow >= nEndRow ) break;
1967 			++nOtherPos;
1968 		}
1969 		if ( nThisRow <= nOtherRow )
1970 		{
1971 			if ( nThisRow >= nEndRow ) break;
1972 			++nThisPos;
1973 		}
1974 	}
1975 
1976 	return bEqual;
1977 }
1978 
1979 
1980 sal_Bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
1981 {
1982 	//!	mit IsVisibleEqual zusammenfassen?
1983 
1984 	sal_Bool bEqual = sal_True;
1985 	SCSIZE nThisPos = 0;
1986 	SCSIZE nOtherPos = 0;
1987 	if ( nStartRow > 0 )
1988 	{
1989 		Search( nStartRow, nThisPos );
1990 		rOther.Search( nStartRow, nOtherPos );
1991 	}
1992 
1993 	while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1994 	{
1995 		SCROW nThisRow = pData[nThisPos].nRow;
1996 		SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1997 		const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1998 		const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1999 		bEqual = ( pThisPattern == pOtherPattern );
2000 
2001 		if ( nThisRow >= nOtherRow )
2002 		{
2003 			if ( nOtherRow >= nEndRow ) break;
2004 			++nOtherPos;
2005 		}
2006 		if ( nThisRow <= nOtherRow )
2007 		{
2008 			if ( nThisRow >= nEndRow ) break;
2009 			++nThisPos;
2010 		}
2011 	}
2012 
2013 	return bEqual;
2014 }
2015 
2016 
2017 sal_Bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2018 {
2019 	//	horizontal zusammengefasste duerfen nicht herausgeschoben werden
2020 	//	(ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen)
2021 
2022 	sal_Bool bTest = sal_True;
2023 	if (!IsEmpty())
2024 	{
2025 		SCSIZE nIndex = 0;
2026 		if ( nStartRow > 0 )
2027 			Search( nStartRow, nIndex );
2028 
2029 		for ( ; nIndex < nCount; nIndex++ )
2030 		{
2031 			if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
2032 						GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2033 			{
2034 				bTest = sal_False;						// darf nicht herausgeschoben werden
2035 				break;
2036 			}
2037 			if ( pData[nIndex].nRow >= nEndRow )	// Ende des Bereichs
2038 				break;
2039 		}
2040 	}
2041 	return bTest;
2042 }
2043 
2044 
2045 sal_Bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2046 {
2047 	//	wenn die erste herausgeschobene Zeile vertikal ueberlappt ist,
2048 	//	wuerde eine kaputte Zusammenfassung uebrigbleiben
2049 
2050 	if (pData)
2051 	{
2052 		//	MAXROW + 1 - nSize	= erste herausgeschobene Zeile
2053 
2054 		SCSIZE nFirstLost = nCount-1;
2055         while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2056 			--nFirstLost;
2057 
2058 		if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
2059 							GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2060 			return sal_False;
2061 	}
2062 
2063 	return sal_True;
2064 }
2065 
2066 
2067 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2068 {
2069 	if (!pData)
2070 		return;
2071 
2072 	SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0;		// Vorgaenger erweitern
2073 	SCSIZE nIndex;
2074 	Search( nSearch, nIndex );
2075 
2076 	//	ein gesetztes ScMergeAttr darf nicht ausgedehnt werden
2077 	//	(darum hinterher wieder loeschen)
2078 
2079 	sal_Bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
2080 
2081 	SCSIZE nRemove = 0;
2082 	SCSIZE i;
2083 	for (i = nIndex; i < nCount-1; i++)
2084 	{
2085 		SCROW nNew = pData[i].nRow + nSize;
2086 		if ( nNew >= MAXROW )					// Ende erreicht ?
2087 		{
2088 			nNew = MAXROW;
2089 			if (!nRemove)
2090 				nRemove = i+1;					// folgende loeschen
2091 		}
2092 		pData[i].nRow = nNew;
2093 	}
2094 
2095 	//	muessen Eintraege am Ende geloescht werden?
2096 
2097 	if (nRemove && nRemove < nCount)
2098 		DeleteRange( nRemove, nCount-1 );
2099 
2100 	if (bDoMerge)			// ausgedehntes ScMergeAttr wieder reparieren
2101 	{
2102 			//!	ApplyAttr fuer Bereiche !!!
2103 
2104 		const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
2105         for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2106             pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2107 
2108 		//	im eingefuegten Bereich ist nichts zusammengefasst
2109 	}
2110 
2111     // Don't duplicate the merge flags in the inserted row.
2112     // #i108488# SC_MF_SCENARIO has to be allowed.
2113     RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
2114 }
2115 
2116 
2117 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2118 {
2119 	if (pData)
2120 	{
2121 		sal_Bool bFirst=sal_True;
2122         SCSIZE nStartIndex = 0;
2123         SCSIZE nEndIndex = 0;
2124 		SCSIZE i;
2125 
2126 		for ( i = 0; i < nCount-1; i++)
2127             if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2128 			{
2129 				if (bFirst)
2130 				{
2131 					nStartIndex = i;
2132 					bFirst = sal_False;
2133 				}
2134 				nEndIndex = i;
2135 			}
2136 		if (!bFirst)
2137 		{
2138 			SCROW nStart;
2139 			if (nStartIndex==0)
2140 				nStart = 0;
2141 			else
2142 				nStart = pData[nStartIndex-1].nRow + 1;
2143 
2144 			if (nStart < nStartRow)
2145 			{
2146 				pData[nStartIndex].nRow = nStartRow - 1;
2147 				++nStartIndex;
2148 			}
2149 			if (nEndIndex >= nStartIndex)
2150 			{
2151 				DeleteRange( nStartIndex, nEndIndex );
2152 				if (nStartIndex > 0)
2153 					if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
2154 						DeleteRange( nStartIndex-1, nStartIndex-1 );
2155 			}
2156 		}
2157 		for (i = 0; i < nCount-1; i++)
2158 			if (pData[i].nRow >= nStartRow)
2159 				pData[i].nRow -= nSize;
2160 
2161 //		unten nicht Default-Pattern nachschieben, um Druckbereiche erkennen zu koennen
2162 //		stattdessen nur Merge-Flags loeschen
2163 
2164 		RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
2165 	}
2166 }
2167 
2168 
2169 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2170 {
2171 	ScDocumentPool* pDocPool = pDocument->GetPool();
2172 	for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2173 		pDocPool->Remove(*pData[i].pPattern);
2174 
2175 	memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
2176 	nCount -= nEndIndex-nStartIndex+1;
2177 }
2178 
2179 
2180 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2181 {
2182 	RemoveAreaMerge( nStartRow, nEndRow );			// von zusammengefassten auch die Flags loeschen
2183 
2184 	if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
2185 		SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
2186 	else
2187 		DeleteAreaSafe( nStartRow, nEndRow );		// Merge-Flags stehenlassen
2188 }
2189 
2190 
2191 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2192 {
2193 	const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2194 	const ScPatternAttr* pOldPattern;
2195 
2196 	SCSIZE	nIndex;
2197 	SCROW	nRow;
2198 	SCROW	nThisRow;
2199 
2200 	Search( nStartRow, nIndex );
2201 	nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
2202 	if (nThisRow < nStartRow) nThisRow = nStartRow;
2203 
2204 	while ( nThisRow <= nEndRow )
2205 	{
2206 		pOldPattern = pData[nIndex].pPattern;
2207 
2208 		if ( pOldPattern->GetItemSet().Count() )		// harte Attribute ?
2209 		{
2210 			nRow = pData[nIndex].nRow;
2211 			SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
2212 
2213 			ScPatternAttr aNewPattern(*pOldPattern);
2214 			SfxItemSet& rSet = aNewPattern.GetItemSet();
2215 			for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2216 				if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2217 					rSet.ClearItem(nId);
2218 
2219 			if ( aNewPattern == *pDefPattern )
2220 				SetPatternArea( nThisRow, nAttrRow, pDefPattern, sal_False );
2221 			else
2222 				SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
2223 
2224 			Search( nThisRow, nIndex );									// Daten wurden veraendert !!!
2225 		}
2226 
2227 		++nIndex;
2228 		nThisRow = pData[nIndex-1].nRow+1;
2229 	}
2230 }
2231 
2232 		// Verschieben innerhalb eines Dokuments
2233 
2234 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2235 {
2236 	SCROW nStart = nStartRow;
2237 	for (SCSIZE i = 0; i < nCount; i++)
2238 	{
2239 		if ((pData[i].nRow >= nStartRow) && ((i==0) ? sal_True : pData[i-1].nRow < nEndRow))
2240 		{
2241 			//	Kopieren (bPutToPool=sal_True)
2242 			rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
2243 										pData[i].pPattern, sal_True );
2244 		}
2245 		nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
2246 	}
2247 	DeleteArea(nStartRow, nEndRow);
2248 }
2249 
2250 
2251 		// Kopieren zwischen Dokumenten (Clipboard)
2252 
2253 void ScAttrArray::CopyArea( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray,
2254 								sal_Int16 nStripFlags )
2255 {
2256 	nStartRow -= nDy;		// Source
2257 	nEndRow -= nDy;
2258 
2259 	SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2260 	SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2261 
2262 	ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2263 	ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2264 	sal_Bool bSamePool = (pSourceDocPool==pDestDocPool);
2265 
2266 	for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2267 	{
2268 		if (pData[i].nRow >= nStartRow)
2269 		{
2270 			const ScPatternAttr* pOldPattern = pData[i].pPattern;
2271 			const ScPatternAttr* pNewPattern;
2272 
2273 			if (IsDefaultItem( pOldPattern ))
2274 			{
2275 				//	am Default muss nichts veraendert werden
2276 
2277 				pNewPattern = (const ScPatternAttr*)
2278 								&pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2279 			}
2280 			else if ( nStripFlags )
2281 			{
2282 				ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
2283 				sal_Int16 nNewFlags = 0;
2284 				if ( nStripFlags != SC_MF_ALL )
2285 					nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
2286 								GetValue() & ~nStripFlags;
2287 
2288 				if ( nNewFlags )
2289 					pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2290 				else
2291 					pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2292 
2293 				if (bSamePool)
2294 					pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
2295 				else
2296 					pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2297 				delete pTmpPattern;
2298 			}
2299 			else
2300 			{
2301 				if (bSamePool)
2302 					pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2303 				else
2304 					pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2305 			}
2306 
2307 			rAttrArray.SetPatternArea(nDestStart,
2308 							Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
2309 		}
2310 
2311 		// when pasting from clipboard and skipping filtered rows, the adjusted end position
2312 		// can be negative
2313 		nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2314 	}
2315 }
2316 
2317 		// Flags stehenlassen
2318 		//! mit CopyArea zusammenfassen !!!
2319 
2320 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2321 {
2322 	nStartRow -= nDy;		// Source
2323 	nEndRow -= nDy;
2324 
2325 	SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2326 	SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2327 
2328 	if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
2329 	{
2330 		CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2331 		return;
2332 	}
2333 
2334 	ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2335 	ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2336 	sal_Bool bSamePool = (pSourceDocPool==pDestDocPool);
2337 
2338 	for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2339 	{
2340 		if (pData[i].nRow >= nStartRow)
2341 		{
2342 			const ScPatternAttr* pOldPattern = pData[i].pPattern;
2343 			const ScPatternAttr* pNewPattern;
2344 
2345 			if (bSamePool)
2346 				pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2347 			else
2348 				pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2349 
2350 			rAttrArray.SetPatternAreaSafe(nDestStart,
2351 							Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, sal_False);
2352 		}
2353 
2354 		// when pasting from clipboard and skipping filtered rows, the adjusted end position
2355 		// can be negative
2356 		nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2357 	}
2358 }
2359 
2360 
2361 SCsROW ScAttrArray::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2362 									sal_Bool bUp, ScMarkArray* pMarkArray )
2363 {
2364 	sal_Bool bFound = sal_False;
2365 
2366 	if (pMarkArray)
2367 	{
2368 		nRow = pMarkArray->GetNextMarked( nRow, bUp );
2369 		if (!VALIDROW(nRow))
2370 			return nRow;
2371 	}
2372 
2373 	SCSIZE nIndex;
2374 	Search(nRow, nIndex);
2375 	const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2376 
2377 	while (nIndex < nCount && !bFound)
2378 	{
2379 		if (pPattern->GetStyleSheet() == pSearchStyle)
2380 		{
2381 			if (pMarkArray)
2382 			{
2383 				nRow = pMarkArray->GetNextMarked( nRow, bUp );
2384 				SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2385 				if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2386 					bFound = sal_True;
2387 			}
2388 			else
2389 				bFound = sal_True;
2390 		}
2391 
2392 		if (!bFound)
2393 		{
2394 			if (bUp)
2395 			{
2396 				if (nIndex==0)
2397                 {
2398                     nIndex = nCount;
2399 					nRow = -1;
2400                 }
2401                 else
2402 				{
2403                     --nIndex;
2404 					nRow = pData[nIndex].nRow;
2405 					pPattern = pData[nIndex].pPattern;
2406 				}
2407 			}
2408 			else
2409 			{
2410 				nRow = pData[nIndex].nRow+1;
2411 				++nIndex;
2412 				if (nIndex<nCount)
2413 					pPattern = pData[nIndex].pPattern;
2414 			}
2415 		}
2416 	}
2417 
2418 	DBG_ASSERT( bFound || !ValidRow(nRow), "interner Fehler in ScAttrArray::SearchStyle" );
2419 
2420 	return nRow;
2421 }
2422 
2423 
2424 sal_Bool ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow,
2425 						const ScStyleSheet* pSearchStyle, sal_Bool bUp, ScMarkArray* pMarkArray )
2426 {
2427 	SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2428 	if (VALIDROW(nStartRow))
2429 	{
2430 		SCSIZE nIndex;
2431 		Search(nStartRow,nIndex);
2432 
2433 		rRow = nStartRow;
2434 		if (bUp)
2435 		{
2436 			if (nIndex>0)
2437 				rEndRow = pData[nIndex-1].nRow + 1;
2438 			else
2439 				rEndRow = 0;
2440 			if (pMarkArray)
2441 			{
2442 				SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_True );
2443 				if (nMarkEnd>rEndRow)
2444 					rEndRow = nMarkEnd;
2445 			}
2446 		}
2447 		else
2448 		{
2449 			rEndRow = pData[nIndex].nRow;
2450 			if (pMarkArray)
2451 			{
2452 				SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_False );
2453 				if (nMarkEnd<rEndRow)
2454 					rEndRow = nMarkEnd;
2455 			}
2456 		}
2457 
2458 		return sal_True;
2459 	}
2460 	else
2461 		return sal_False;
2462 }
2463 
2464 //------------------------------------------------------------------------
2465 //
2466 //							Laden / Speichern
2467 //
2468 
2469 
2470 #if 0
2471 void ScAttrArray::Save( SvStream& /* rStream */ ) const
2472 {
2473 #if SC_ROWLIMIT_STREAM_ACCESS
2474 #error address types changed!
2475     ScWriteHeader aHdr( rStream, 8 );
2476 
2477     ScDocumentPool* pDocPool = pDocument->GetPool();
2478 
2479     sal_uInt16 nSaveCount = nCount;
2480     SCROW nSaveMaxRow = pDocument->GetSrcMaxRow();
2481     if ( nSaveMaxRow != MAXROW )
2482     {
2483         if ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow )
2484         {
2485             pDocument->SetLostData();           // Warnung ausgeben
2486             do
2487                 --nSaveCount;
2488             while ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow );
2489         }
2490     }
2491 
2492     rStream << nSaveCount;
2493 
2494     const SfxPoolItem* pItem;
2495     for (SCSIZE i=0; i<nSaveCount; i++)
2496     {
2497         rStream << Min( pData[i].nRow, nSaveMaxRow );
2498 
2499         const ScPatternAttr* pPattern = pData[i].pPattern;
2500         pDocPool->StoreSurrogate( rStream, pPattern );
2501 
2502         //	sal_False, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen:
2503         if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,sal_False,&pItem) == SFX_ITEM_SET)
2504             pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2505 
2506         if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,sal_False,&pItem) == SFX_ITEM_SET)
2507             pDocument->SetValidationUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2508     }
2509 #endif // SC_ROWLIMIT_STREAM_ACCESS
2510 }
2511 
2512 
2513 void ScAttrArray::Load( SvStream& /* rStream */ )
2514 {
2515 #if SC_ROWLIMIT_STREAM_ACCESS
2516 #error address types changed!
2517     ScDocumentPool* pDocPool = pDocument->GetPool();
2518 
2519     ScReadHeader aHdr( rStream );
2520 
2521     sal_uInt16 nNewCount;
2522     rStream >> nNewCount;
2523     if ( nNewCount > MAXROW+1 )                     // wuerde das Array zu gross?
2524     {
2525         pDocument->SetLostData();
2526         rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2527         return;
2528     }
2529 
2530     Reset( pDocument->GetDefPattern(), sal_False );     // loeschen
2531     pData = new ScAttrEntry[nNewCount];             // neu anlegen
2532     for (SCSIZE i=0; i<nNewCount; i++)
2533     {
2534         rStream >> pData[i].nRow;
2535 
2536         sal_uInt16 nWhich = ATTR_PATTERN;
2537         const ScPatternAttr* pNewPattern = (const ScPatternAttr*)
2538                                            pDocPool->LoadSurrogate( rStream, nWhich, ATTR_PATTERN );
2539         if (!pNewPattern)
2540         {
2541             // da is was schiefgelaufen
2542             DBG_ERROR("ScAttrArray::Load: Surrogat nicht im Pool");
2543             pNewPattern = pDocument->GetDefPattern();
2544         }
2545         ScDocumentPool::CheckRef( *pNewPattern );
2546         pData[i].pPattern = pNewPattern;
2547 
2548         // LoadSurrogate erhoeht auch die Ref
2549     }
2550     nCount = nLimit = nNewCount;
2551 
2552     if ( nCount > 1 && pData[nCount-2].nRow >= MAXROW ) // faengt ein Attribut hinter MAXROW an?
2553     {
2554         pDocument->SetLostData();
2555         rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2556         return;
2557     }
2558 
2559     if ( pDocument->GetSrcMaxRow() != MAXROW )          // Ende anpassen?
2560     {
2561         //	Ende immer auf MAXROW umsetzen (nur auf 32 Bit)
2562 
2563         DBG_ASSERT( pData[nCount-1].nRow == pDocument->GetSrcMaxRow(), "Attribut-Ende ?!?" );
2564         pData[nCount-1].nRow = MAXROW;
2565     }
2566 #endif // SC_ROWLIMIT_STREAM_ACCESS
2567 }
2568 #endif
2569 
2570 
2571 //UNUSED2008-05  void ScAttrArray::ConvertFontsAfterLoad()
2572 //UNUSED2008-05  {
2573 //UNUSED2008-05      ScFontToSubsFontConverter_AutoPtr xFontConverter;
2574 //UNUSED2008-05      const sal_uLong nFlags = FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
2575 //UNUSED2008-05      SCSIZE   nIndex = 0;
2576 //UNUSED2008-05      SCROW  nThisRow = 0;
2577 //UNUSED2008-05
2578 //UNUSED2008-05      while ( nThisRow <= MAXROW )
2579 //UNUSED2008-05      {
2580 //UNUSED2008-05          const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
2581 //UNUSED2008-05          const SfxPoolItem* pItem;
2582 //UNUSED2008-05          if( pOldPattern->GetItemSet().GetItemState( ATTR_FONT, sal_False, &pItem ) == SFX_ITEM_SET )
2583 //UNUSED2008-05          {
2584 //UNUSED2008-05              const SvxFontItem* pFontItem = (const SvxFontItem*) pItem;
2585 //UNUSED2008-05              const String& rOldName = pFontItem->GetFamilyName();
2586 //UNUSED2008-05              xFontConverter = CreateFontToSubsFontConverter( rOldName, nFlags );
2587 //UNUSED2008-05              if ( xFontConverter )
2588 //UNUSED2008-05              {
2589 //UNUSED2008-05                  String aNewName( GetFontToSubsFontName( xFontConverter ) );
2590 //UNUSED2008-05                  if ( aNewName != rOldName )
2591 //UNUSED2008-05                  {
2592 //UNUSED2008-05                      SCROW nAttrRow = pData[nIndex].nRow;
2593 //UNUSED2008-05                      SvxFontItem aNewItem( pFontItem->GetFamily(), aNewName,
2594 //UNUSED2008-05                          pFontItem->GetStyleName(), pFontItem->GetPitch(),
2595 //UNUSED2008-05                          RTL_TEXTENCODING_DONTKNOW, ATTR_FONT );
2596 //UNUSED2008-05                      ScPatternAttr aNewPattern( *pOldPattern );
2597 //UNUSED2008-05                      aNewPattern.GetItemSet().Put( aNewItem );
2598 //UNUSED2008-05                      SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True );
2599 //UNUSED2008-05                      Search( nThisRow, nIndex );     //! data changed
2600 //UNUSED2008-05                  }
2601 //UNUSED2008-05              }
2602 //UNUSED2008-05          }
2603 //UNUSED2008-05          ++nIndex;
2604 //UNUSED2008-05          nThisRow = pData[nIndex-1].nRow+1;
2605 //UNUSED2008-05      }
2606 //UNUSED2008-05  }
2607 
2608