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