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