xref: /aoo42x/main/sc/source/core/data/column.cxx (revision 3a02adb1)
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 // INCLUDE ---------------------------------------------------------------
30 
31 #include <map>
32 
33 #include <svl/poolcach.hxx>
34 #include <svl/zforlist.hxx>
35 #include <editeng/scripttypeitem.hxx>
36 #include <string.h>
37 
38 #include "scitems.hxx"
39 #include "column.hxx"
40 #include "cell.hxx"
41 #include "document.hxx"
42 #include "docpool.hxx"
43 #include "attarray.hxx"
44 #include "patattr.hxx"
45 #include "compiler.hxx"
46 #include "brdcst.hxx"
47 #include "markdata.hxx"
48 #include "detfunc.hxx"			// for Notes in Sort/Swap
49 #include "postit.hxx"
50 
51 //#pragma optimize ( "", off )
52 //	nur Search ohne Optimierung!
53 
54 // STATIC DATA -----------------------------------------------------------
55 using namespace formula;
56 
57 inline sal_Bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
58 {
59 	//!	move to a header file
60 	return ( nScript != SCRIPTTYPE_LATIN &&
61 			 nScript != SCRIPTTYPE_ASIAN &&
62 			 nScript != SCRIPTTYPE_COMPLEX &&
63 			 nScript != 0 );
64 }
65 
66 // -----------------------------------------------------------------------------------------
67 
68 
69 ScColumn::ScColumn() :
70 	nCol( 0 ),
71 	nCount( 0 ),
72 	nLimit( 0 ),
73 	pItems( NULL ),
74     pAttrArray( NULL ),
75     pDocument( NULL )
76 {
77 }
78 
79 
80 ScColumn::~ScColumn()
81 {
82 	FreeAll();
83 	if (pAttrArray) delete pAttrArray;
84 }
85 
86 
87 void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
88 {
89 	nCol = nNewCol;
90 	nTab = nNewTab;
91 	pDocument = pDoc;
92 	pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
93 }
94 
95 
96 SCsROW ScColumn::GetNextUnprotected( SCROW nRow, sal_Bool bUp ) const
97 {
98 	return pAttrArray->GetNextUnprotected(nRow, bUp);
99 }
100 
101 
102 sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
103 {
104 	// nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32
105 	if ( !pItems )
106 		return 0;
107 	if ( nRow1 == nRow2 )
108 	{
109 		SCSIZE nIndex;
110 		if ( Search( nRow1, nIndex ) )
111 		{
112 			ScBaseCell* pCell = pItems[nIndex].pCell;
113 			if ( pCell->GetCellType() == CELLTYPE_FORMULA
114 				&& ((ScFormulaCell*)pCell)->GetMatrixFlag() )
115 			{
116 				ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
117 				return ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
118 			}
119 		}
120 		return 0;
121 	}
122 	else
123 	{
124 		ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
125 		sal_Bool bOpen = sal_False;
126 		sal_uInt16 nEdges = 0;
127 		SCSIZE nIndex;
128 		Search( nRow1, nIndex );
129 		while ( nIndex < nCount && pItems[nIndex].nRow <= nRow2 )
130 		{
131 			ScBaseCell* pCell = pItems[nIndex].pCell;
132 			if ( pCell->GetCellType() == CELLTYPE_FORMULA
133 				&& ((ScFormulaCell*)pCell)->GetMatrixFlag() )
134 			{
135 				nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
136 				if ( nEdges )
137 				{
138 					if ( nEdges & 8 )
139 						bOpen = sal_True;	// obere Kante oeffnet, weitersehen
140 					else if ( !bOpen )
141 						return nEdges | 32;	// es gibt was, was nicht geoeffnet wurde
142 					else if ( nEdges & 1 )
143 						return nEdges;	// mittendrin
144 					// (nMask & 16 und  (4 und nicht 16)) oder
145 					// (nMask & 4  und (16 und nicht 4))
146 					if ( ((nMask & 16) && (nEdges & 4)  && !(nEdges & 16))
147 						|| ((nMask & 4)  && (nEdges & 16) && !(nEdges & 4)) )
148 						return nEdges;	// nur linke/rechte Kante
149 					if ( nEdges & 2 )
150 						bOpen = sal_False;	// untere Kante schliesst
151 				}
152 			}
153 			nIndex++;
154 		}
155 		if ( bOpen )
156 			nEdges |= 32;			// es geht noch weiter
157 		return nEdges;
158 	}
159 }
160 
161 
162 sal_Bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
163 {
164 	if ( rMark.IsMultiMarked() )
165 	{
166 		sal_Bool bFound = sal_False;
167 
168 		ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
169 		ScAddress aCurOrg( ScAddress::INITIALIZE_INVALID );
170 		SCROW nTop, nBottom;
171 		ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
172 		while ( !bFound && aMarkIter.Next( nTop, nBottom ) )
173 		{
174 			sal_Bool bOpen = sal_False;
175 			sal_uInt16 nEdges;
176 			SCSIZE nIndex;
177 			Search( nTop, nIndex );
178 			while ( !bFound && nIndex < nCount && pItems[nIndex].nRow <= nBottom )
179 			{
180 				ScBaseCell* pCell = pItems[nIndex].pCell;
181 				if ( pCell->GetCellType() == CELLTYPE_FORMULA
182 					&& ((ScFormulaCell*)pCell)->GetMatrixFlag() )
183 				{
184 					nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
185 					if ( nEdges )
186 					{
187 						if ( nEdges & 8 )
188 							bOpen = sal_True;	// obere Kante oeffnet, weitersehen
189 						else if ( !bOpen )
190 							return sal_True;	// es gibt was, was nicht geoeffnet wurde
191 						else if ( nEdges & 1 )
192 							bFound = sal_True;	// mittendrin, alles selektiert?
193 						// (4 und nicht 16) oder (16 und nicht 4)
194 						if ( (((nEdges & 4) | 16) ^ ((nEdges & 16) | 4)) )
195 							bFound = sal_True;	// nur linke/rechte Kante, alles selektiert?
196 						if ( nEdges & 2 )
197 							bOpen = sal_False;	// untere Kante schliesst
198 
199 						if ( bFound )
200 						{	// alles selektiert?
201 							if ( aCurOrg != aOrg )
202 							{	// neue Matrix zu pruefen?
203 								aCurOrg = aOrg;
204 								ScFormulaCell* pFCell;
205 								if ( ((ScFormulaCell*)pCell)->GetMatrixFlag()
206 										== MM_REFERENCE )
207 									pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
208 								else
209 									pFCell = (ScFormulaCell*)pCell;
210                                 SCCOL nC;
211                                 SCROW nR;
212                                 pFCell->GetMatColsRows( nC, nR );
213 								ScRange aRange( aOrg, ScAddress(
214 									aOrg.Col() + nC - 1, aOrg.Row() + nR - 1,
215 									aOrg.Tab() ) );
216 								if ( rMark.IsAllMarked( aRange ) )
217 									bFound = sal_False;
218 							}
219 							else
220 								bFound = sal_False;		// war schon
221 						}
222 					}
223 				}
224 				nIndex++;
225 			}
226 			if ( bOpen )
227 				return sal_True;
228 		}
229 		return bFound;
230 	}
231 	else
232 		return sal_False;
233 }
234 
235 
236 //UNUSED2009-05 sal_Bool ScColumn::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
237 //UNUSED2009-05                             sal_Bool bLeft, sal_Bool bRight ) const
238 //UNUSED2009-05 {
239 //UNUSED2009-05     return pAttrArray->HasLines( nRow1, nRow2, rSizes, bLeft, bRight );
240 //UNUSED2009-05 }
241 
242 
243 bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
244 {
245 	return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
246 }
247 
248 
249 sal_Bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
250 {
251 	sal_Bool bFound = sal_False;
252 
253 	SCROW nTop;
254 	SCROW nBottom;
255 
256 	if (rMark.IsMultiMarked())
257 	{
258 		ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
259 		while (aMarkIter.Next( nTop, nBottom ) && !bFound)
260 		{
261 			if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
262 				bFound = sal_True;
263 		}
264 	}
265 
266 	return bFound;
267 }
268 
269 
270 sal_Bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
271 							SCCOL& rPaintCol, SCROW& rPaintRow,
272 							sal_Bool bRefresh, sal_Bool bAttrs )
273 {
274 	return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh, bAttrs );
275 }
276 
277 
278 void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, sal_Bool bDeep ) const
279 {
280 	SCROW nTop;
281 	SCROW nBottom;
282 
283 	if ( rMark.IsMultiMarked() )
284 	{
285         const ScMarkArray* pArray = rMark.GetArray() + nCol;
286         if ( pArray->HasMarks() )
287         {
288             ScMarkArrayIter aMarkIter( pArray );
289             while (aMarkIter.Next( nTop, nBottom ))
290                 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
291         }
292 	}
293 }
294 
295 
296 void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, sal_Bool bDeep ) const
297 {
298 	pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
299 }
300 
301 
302 void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
303 							ScLineFlags& rFlags,
304 							SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) const
305 {
306 	pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
307 }
308 
309 
310 void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
311 							SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight )
312 {
313 	pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
314 }
315 
316 
317 const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
318 {
319 	return pAttrArray->GetPattern( nRow );
320 }
321 
322 const ScPatternAttr* ScColumn::GetPatternRange( SCROW& rStartRow, SCROW& rEndRow, SCROW nRow ) const
323 {
324 	return pAttrArray->GetPatternRange( rStartRow, rEndRow, nRow );
325 }
326 
327 const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
328 {
329 	return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
330 }
331 
332 
333 const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
334 {
335     ::std::map< const ScPatternAttr*, size_t > aAttrMap;
336     const ScPatternAttr* pMaxPattern = 0;
337     size_t nMaxCount = 0;
338 
339     ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
340     const ScPatternAttr* pPattern;
341     SCROW nAttrRow1 = 0, nAttrRow2 = 0;
342 
343     while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
344     {
345         size_t& rnCount = aAttrMap[ pPattern ];
346         rnCount += (nAttrRow2 - nAttrRow1 + 1);
347         if( rnCount > nMaxCount )
348         {
349             pMaxPattern = pPattern;
350             nMaxCount = rnCount;
351         }
352     }
353 
354     return pMaxPattern;
355 }
356 
357 
358 sal_uLong ScColumn::GetNumberFormat( SCROW nRow ) const
359 {
360 	return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
361 }
362 
363 
364 SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark )
365 {
366     SCROW nTop = 0;
367     SCROW nBottom = 0;
368 	sal_Bool bFound = sal_False;
369 
370 	if ( rMark.IsMultiMarked() )
371 	{
372 		ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
373 		while (aMarkIter.Next( nTop, nBottom ))
374 		{
375 			pAttrArray->ApplyCacheArea( nTop, nBottom, pCache );
376 			bFound = sal_True;
377 		}
378 	}
379 
380 	if (!bFound)
381 		return -1;
382 	else if (nTop==0 && nBottom==MAXROW)
383 		return 0;
384 	else
385 		return nBottom;
386 }
387 
388 
389 void ScColumn::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark )
390 {
391 	SCROW nTop;
392 	SCROW nBottom;
393 
394 	if ( pAttrArray && rMark.IsMultiMarked() )
395 	{
396 		ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
397 		while (aMarkIter.Next( nTop, nBottom ))
398 			pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
399 	}
400 }
401 
402 
403 void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
404 {
405 	SCROW nTop;
406 	SCROW nBottom;
407 
408 	if ( pAttrArray && rMark.IsMultiMarked() )
409 	{
410 		ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
411 		while (aMarkIter.Next( nTop, nBottom ))
412 			pAttrArray->ClearItems(nTop, nBottom, pWhich);
413 	}
414 }
415 
416 
417 void ScColumn::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
418 {
419 	SCROW nTop;
420 	SCROW nBottom;
421 
422 	if ( rMark.IsMultiMarked() )
423 	{
424 		ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
425 		while (aMarkIter.Next( nTop, nBottom ))
426             DeleteArea(nTop, nBottom, nDelFlag);
427 	}
428 }
429 
430 
431 void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
432 {
433 	const SfxItemSet* pSet = &rPatAttr.GetItemSet();
434 	SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
435 
436 	const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
437 
438 	//	sal_True = alten Eintrag behalten
439 
440 	ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True );
441 	ScDocumentPool::CheckRef( *pPattern );
442 	ScDocumentPool::CheckRef( *pNewPattern );
443 
444 	if (pNewPattern != pPattern)
445 	  pAttrArray->SetPattern( nRow, pNewPattern );
446 }
447 
448 
449 void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr )
450 {
451 	const SfxItemSet* pSet = &rPatAttr.GetItemSet();
452 	SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
453 	pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache );
454 }
455 
456 
457 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
458 		const ScPatternAttr& rPattern, short nNewType )
459 {
460 	const SfxItemSet* pSet = &rPattern.GetItemSet();
461 	SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
462 	SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
463 	SCROW nEndRow = rRange.aEnd.Row();
464 	for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
465 	{
466 		SCROW nRow1, nRow2;
467 		const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
468 			nRow1, nRow2, nRow );
469 		sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter );
470 		short nOldType = pFormatter->GetType( nFormat );
471 		if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) )
472 			nRow = nRow2;
473 		else
474 		{
475 			SCROW nNewRow1 = Max( nRow1, nRow );
476 			SCROW nNewRow2 = Min( nRow2, nEndRow );
477 			pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
478 			nRow = nNewRow2;
479 		}
480 	}
481 }
482 
483 
484 void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
485 {
486 	const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
487 	ScPatternAttr* pNewPattern = new ScPatternAttr(*pPattern);
488 	if (pNewPattern)
489 	{
490 		pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
491 		pAttrArray->SetPattern(nRow, pNewPattern, sal_True);
492 		delete pNewPattern;
493 	}
494 }
495 
496 
497 void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
498 {
499 	pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle);
500 }
501 
502 
503 void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
504 {
505 	SCROW nTop;
506 	SCROW nBottom;
507 
508 	if ( rMark.IsMultiMarked() )
509 	{
510 		ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
511 		while (aMarkIter.Next( nTop, nBottom ))
512 			pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle);
513 	}
514 }
515 
516 
517 void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
518 									const SvxBorderLine* pLine, sal_Bool bColorOnly )
519 {
520 	if ( bColorOnly && !pLine )
521 		return;
522 
523 	SCROW nTop;
524 	SCROW nBottom;
525 
526 	if (rMark.IsMultiMarked())
527 	{
528 		ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
529 		while (aMarkIter.Next( nTop, nBottom ))
530 			pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
531 	}
532 }
533 
534 
535 const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
536 {
537 	return pAttrArray->GetPattern( nRow )->GetStyleSheet();
538 }
539 
540 
541 const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, sal_Bool& rFound ) const
542 {
543 	rFound = sal_False;
544 	if (!rMark.IsMultiMarked())
545 	{
546 		DBG_ERROR("ScColumn::GetSelectionStyle ohne Selektion");
547 		return NULL;
548 	}
549 
550 	sal_Bool bEqual = sal_True;
551 
552 	const ScStyleSheet* pStyle = NULL;
553 	const ScStyleSheet* pNewStyle;
554 
555 	ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
556 	SCROW nTop;
557 	SCROW nBottom;
558 	while (bEqual && aMarkIter.Next( nTop, nBottom ))
559 	{
560 		ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
561 		SCROW nRow;
562 		SCROW nDummy;
563 		const ScPatternAttr* pPattern;
564         while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
565 		{
566 			pNewStyle = pPattern->GetStyleSheet();
567 			rFound = sal_True;
568 			if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
569 				bEqual = sal_False;												// unterschiedliche
570 			pStyle = pNewStyle;
571 		}
572 	}
573 
574 	return bEqual ? pStyle : NULL;
575 }
576 
577 
578 const ScStyleSheet*	ScColumn::GetAreaStyle( sal_Bool& rFound, SCROW nRow1, SCROW nRow2 ) const
579 {
580 	rFound = sal_False;
581 
582 	sal_Bool bEqual = sal_True;
583 
584 	const ScStyleSheet* pStyle = NULL;
585 	const ScStyleSheet* pNewStyle;
586 
587 	ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
588 	SCROW nRow;
589 	SCROW nDummy;
590 	const ScPatternAttr* pPattern;
591     while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
592 	{
593 		pNewStyle = pPattern->GetStyleSheet();
594 		rFound = sal_True;
595 		if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
596 			bEqual = sal_False;												// unterschiedliche
597 		pStyle = pNewStyle;
598 	}
599 
600 	return bEqual ? pStyle : NULL;
601 }
602 
603 void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
604 {
605     pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
606 }
607 
608 sal_Bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
609 {
610 	return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
611 }
612 
613 
614 sal_Bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
615 {
616 	return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
617 }
618 
619 
620 sal_Bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
621 {
622 	return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
623 }
624 
625 
626 void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
627 {
628 	pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
629 }
630 
631 
632 void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, sal_Bool bPutToPool )
633 {
634 	pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
635 }
636 
637 
638 void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
639 								const ScPatternAttr& rPatAttr, sal_Bool bPutToPool )
640 {
641 	pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
642 }
643 
644 
645 void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
646 {
647 	//	um nur ein neues SetItem zu erzeugen, brauchen wir keinen SfxItemPoolCache.
648 	//!	Achtung: der SfxItemPoolCache scheint zuviele Refs fuer das neue SetItem zu erzeugen ??
649 
650 	ScDocumentPool* pDocPool = pDocument->GetPool();
651 
652 	const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
653 	ScPatternAttr* pTemp = new ScPatternAttr(*pOldPattern);
654 	pTemp->GetItemSet().Put(rAttr);
655 	const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pDocPool->Put( *pTemp );
656 
657 	if ( pNewPattern != pOldPattern )
658 		pAttrArray->SetPattern( nRow, pNewPattern );
659 	else
660 		pDocPool->Remove( *pNewPattern );		// ausser Spesen nichts gewesen
661 
662 	delete pTemp;
663 
664 		// alte Version mit SfxItemPoolCache:
665 #if 0
666 	SfxItemPoolCache aCache( pDocument->GetPool(), &rAttr );
667 
668 	const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
669 
670 	//	sal_True = alten Eintrag behalten
671 
672 	ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True );
673 	ScDocumentPool::CheckRef( *pPattern );
674 	ScDocumentPool::CheckRef( *pNewPattern );
675 
676 	if (pNewPattern != pPattern)
677 	  pAttrArray->SetPattern( nRow, pNewPattern );
678 #endif
679 }
680 
681 #ifdef _MSC_VER
682 #pragma optimize ( "", off )
683 #endif
684 
685 
686 sal_Bool ScColumn::Search( SCROW nRow, SCSIZE& nIndex ) const
687 {
688 	if ( !pItems || !nCount )
689 	{
690 		nIndex = 0;
691 		return sal_False;
692 	}
693 	SCROW nMinRow = pItems[0].nRow;
694 	if ( nRow <= nMinRow )
695 	{
696 		nIndex = 0;
697 		return nRow == nMinRow;
698 	}
699 	SCROW nMaxRow = pItems[nCount-1].nRow;
700 	if ( nRow >= nMaxRow )
701 	{
702 		if ( nRow == nMaxRow )
703 		{
704 			nIndex = nCount - 1;
705 			return sal_True;
706 		}
707 		else
708 		{
709 			nIndex = nCount;
710 			return sal_False;
711 		}
712 	}
713 
714 	long nOldLo, nOldHi;
715 	long	nLo 	= nOldLo = 0;
716     long	nHi 	= nOldHi = Min(static_cast<long>(nCount)-1, static_cast<long>(nRow) );
717 	long	i		= 0;
718 	sal_Bool	bFound	= sal_False;
719 	// quite continuous distribution? => interpolating search
720 	sal_Bool	bInterpol = (static_cast<SCSIZE>(nMaxRow - nMinRow) < nCount * 2);
721 	SCROW	nR;
722 
723 	while ( !bFound && nLo <= nHi )
724 	{
725 		if ( !bInterpol || nHi - nLo < 3 )
726 			i = (nLo+nHi) / 2;			// no effort, no division by zero
727 		else
728 		{	// interpolating search
729 			long nLoRow = pItems[nLo].nRow;		// no unsigned underflow upon substraction
730 			i = nLo + (long)((long)(nRow - nLoRow) * (nHi - nLo)
731 				/ (pItems[nHi].nRow - nLoRow));
732 			if ( i < 0 || static_cast<SCSIZE>(i) >= nCount )
733 			{	// oops ...
734 				i = (nLo+nHi) / 2;
735 				bInterpol = sal_False;
736 			}
737 		}
738 		nR = pItems[i].nRow;
739 		if ( nR < nRow )
740 		{
741 			nLo = i+1;
742 			if ( bInterpol )
743 			{
744 				if ( nLo <= nOldLo )
745 					bInterpol = sal_False;
746 				else
747 					nOldLo = nLo;
748 			}
749 		}
750 		else
751 		{
752 			if ( nR > nRow )
753 			{
754 				nHi = i-1;
755 				if ( bInterpol )
756 				{
757 					if ( nHi >= nOldHi )
758 						bInterpol = sal_False;
759 					else
760 						nOldHi = nHi;
761 				}
762 			}
763 			else
764 				bFound = sal_True;
765 		}
766 	}
767 	if (bFound)
768 		nIndex = static_cast<SCSIZE>(i);
769 	else
770 		nIndex = static_cast<SCSIZE>(nLo); // rear index
771 	return bFound;
772 }
773 
774 #ifdef _MSC_VER
775 #pragma optimize ( "", on )
776 #endif
777 
778 
779 ScBaseCell* ScColumn::GetCell( SCROW nRow ) const
780 {
781 	SCSIZE nIndex;
782 	if (Search(nRow, nIndex))
783 		return pItems[nIndex].pCell;
784 	return NULL;
785 }
786 
787 
788 void ScColumn::Resize( SCSIZE nSize )
789 {
790     if (nSize > sal::static_int_cast<SCSIZE>(MAXROWCOUNT))
791 		nSize = MAXROWCOUNT;
792 	if (nSize < nCount)
793 		nSize = nCount;
794 
795 	ColEntry* pNewItems;
796 	if (nSize)
797 	{
798 		SCSIZE nNewSize = nSize + COLUMN_DELTA - 1;
799 		nNewSize -= nNewSize % COLUMN_DELTA;
800 		nLimit = nNewSize;
801 		pNewItems = new ColEntry[nLimit];
802 	}
803 	else
804 	{
805 		nLimit = 0;
806 		pNewItems = NULL;
807 	}
808 	if (pItems)
809 	{
810 		if (pNewItems)
811 			memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
812 		delete[] pItems;
813 	}
814 	pItems = pNewItems;
815 }
816 
817 //	SwapRow zum Sortieren
818 
819 namespace {
820 
821 /** Moves broadcaster from old cell to new cell if exists, otherwise creates a new note cell. */
822 void lclTakeBroadcaster( ScBaseCell*& rpCell, SvtBroadcaster* pBC )
823 {
824     if( pBC )
825     {
826         if( rpCell )
827             rpCell->TakeBroadcaster( pBC );
828         else
829             rpCell = new ScNoteCell( pBC );
830     }
831 }
832 
833 } // namespace
834 
835 void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
836 {
837     /*  Simple swap of cell pointers does not work if broadcasters exist (crash
838         if cell broadcasts directly or indirectly to itself). While swapping
839         the cells, broadcasters have to remain at old positions! */
840 
841     /*  While cloning cells, do not clone notes, but move note pointers to new
842         cells. This prevents creation of new caption drawing objects for every
843         swap operation while sorting. */
844 
845 	ScBaseCell* pCell1 = 0;
846 	SCSIZE nIndex1;
847 	if ( Search( nRow1, nIndex1 ) )
848 		pCell1 = pItems[nIndex1].pCell;
849 
850     ScBaseCell* pCell2 = 0;
851 	SCSIZE nIndex2;
852 	if ( Search( nRow2, nIndex2 ) )
853 		pCell2 = pItems[nIndex2].pCell;
854 
855     // no cells found, nothing to do
856 	if ( !pCell1 && !pCell2 )
857 		return ;
858 
859     // swap variables if first cell is empty, to save some code below
860     if ( !pCell1 )
861     {
862         ::std::swap( nRow1, nRow2 );
863         ::std::swap( nIndex1, nIndex2 );
864         ::std::swap( pCell1, pCell2 );
865     }
866 
867     // from here: first cell (pCell1, nIndex1) exists always
868 
869     ScAddress aPos1( nCol, nRow1, nTab );
870     ScAddress aPos2( nCol, nRow2, nTab );
871 
872 	CellType eType1 = pCell1->GetCellType();
873 	CellType eType2 = pCell2 ? pCell2->GetCellType() : CELLTYPE_NONE;
874 
875     ScFormulaCell* pFmlaCell1 = (eType1 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
876     ScFormulaCell* pFmlaCell2 = (eType2 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
877 
878     // simple swap if no formula cells present
879 	if ( !pFmlaCell1 && !pFmlaCell2 )
880 	{
881         // remember cell broadcasters, must remain at old position
882         SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster();
883 
884 		if ( pCell2 )
885 		{
886             /*  Both cells exist, no formula cells involved, a simple swap can
887                 be performed (but keep broadcasters and notes at old position). */
888 			pItems[nIndex1].pCell = pCell2;
889 			pItems[nIndex2].pCell = pCell1;
890 
891             SvtBroadcaster* pBC2 = pCell2->ReleaseBroadcaster();
892             pCell1->TakeBroadcaster( pBC2 );
893             pCell2->TakeBroadcaster( pBC1 );
894 		}
895 		else
896 		{
897 			ScNoteCell* pDummyCell = pBC1 ? new ScNoteCell( pBC1 ) : 0;
898 			if ( pDummyCell )
899 			{
900                 // insert dummy note cell (without note) containing old broadcaster
901 				pItems[nIndex1].pCell = pDummyCell;
902 			}
903 			else
904 			{
905                 // remove ColEntry at old position
906 				--nCount;
907 				memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) );
908 				pItems[nCount].nRow = 0;
909 				pItems[nCount].pCell = 0;
910 			}
911 
912             // insert ColEntry at new position
913 			Insert( nRow2, pCell1 );
914 		}
915 
916 		return;
917 	}
918 
919 	// from here: at least one of the cells is a formula cell
920 
921     /*  Never move any array formulas. Disabling sort if parts of array
922         formulas are contained is done at UI. */
923     if ( (pFmlaCell1 && (pFmlaCell1->GetMatrixFlag() != 0)) || (pFmlaCell2 && (pFmlaCell2->GetMatrixFlag() != 0)) )
924         return;
925 
926     // do not swap, if formulas are equal
927 	if ( pFmlaCell1 && pFmlaCell2 )
928 	{
929 		ScTokenArray* pCode1 = pFmlaCell1->GetCode();
930 		ScTokenArray* pCode2 = pFmlaCell2->GetCode();
931 
932 		if (pCode1->GetLen() == pCode2->GetLen())		// nicht-UPN
933 		{
934 			sal_Bool bEqual = sal_True;
935 			sal_uInt16 nLen = pCode1->GetLen();
936 			FormulaToken** ppToken1 = pCode1->GetArray();
937 			FormulaToken** ppToken2 = pCode2->GetArray();
938 			for (sal_uInt16 i=0; i<nLen; i++)
939             {
940                 if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) ||
941                         ppToken1[i]->Is3DRef() || ppToken2[i]->Is3DRef() )
942 				{
943 					bEqual = sal_False;
944 					break;
945 				}
946             }
947 
948             // do not swap formula cells with equal formulas, but swap notes
949 			if (bEqual)
950             {
951                 ScPostIt* pNote1 = pCell1->ReleaseNote();
952                 pCell1->TakeNote( pCell2->ReleaseNote() );
953                 pCell2->TakeNote( pNote1 );
954 				return;
955             }
956 		}
957 	}
958 
959 	//	hier kein UpdateReference wegen #30529# - mitsortiert werden nur noch relative Referenzen
960 //	long dy = (long)nRow2 - (long)nRow1;
961 
962     /*  Create clone of pCell1 at position of pCell2 (pCell1 exists always, see
963         variable swapping above). Do not clone the note, but move pointer of
964         old note to new cell. */
965     ScBaseCell* pNew2 = pCell1->CloneWithoutNote( *pDocument, aPos2, SC_CLONECELL_ADJUST3DREL );
966     pNew2->TakeNote( pCell1->ReleaseNote() );
967 
968     /*  Create clone of pCell2 at position of pCell1. Do not clone the note,
969         but move pointer of old note to new cell. */
970 	ScBaseCell* pNew1 = 0;
971 	if ( pCell2 )
972 	{
973         pNew1 = pCell2->CloneWithoutNote( *pDocument, aPos1, SC_CLONECELL_ADJUST3DREL );
974         pNew1->TakeNote( pCell2->ReleaseNote() );
975 	}
976 
977     // move old broadcasters new cells at the same old position
978     SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster();
979     lclTakeBroadcaster( pNew1, pBC1 );
980     SvtBroadcaster* pBC2 = pCell2 ? pCell2->ReleaseBroadcaster() : 0;
981     lclTakeBroadcaster( pNew2, pBC2 );
982 
983 	/*  Insert the new cells. Old cell has to be deleted, if there is no new
984         cell (call to Insert deletes old cell by itself). */
985 	if ( !pNew1 )
986 		Delete( nRow1 );            // deletes pCell1
987 	else
988         Insert( nRow1, pNew1 );     // deletes pCell1, inserts pNew1
989 
990 	if ( pCell2 && !pNew2 )
991 		Delete( nRow2 );            // deletes pCell2
992 	else if ( pNew2 )
993 		Insert( nRow2, pNew2 );     // deletes pCell2 (if existing), inserts pNew2
994 }
995 
996 
997 void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
998 {
999 	ScBaseCell* pCell1 = 0;
1000 	SCSIZE nIndex1;
1001 	if ( Search( nRow, nIndex1 ) )
1002 		pCell1 = pItems[nIndex1].pCell;
1003 
1004     ScBaseCell* pCell2 = 0;
1005 	SCSIZE nIndex2;
1006 	if ( rCol.Search( nRow, nIndex2 ) )
1007 		pCell2 = rCol.pItems[nIndex2].pCell;
1008 
1009     // reverse call if own cell is missing (ensures own existing cell in following code)
1010     if( !pCell1 )
1011     {
1012         if( pCell2 )
1013             rCol.SwapCell( nRow, *this );
1014         return;
1015     }
1016 
1017     // from here: own cell (pCell1, nIndex1) exists always
1018 
1019     ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
1020 	ScFormulaCell* pFmlaCell2 = (pCell2 && (pCell2->GetCellType() == CELLTYPE_FORMULA)) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
1021 
1022 	if ( pCell2 )
1023 	{
1024 		// Tauschen
1025 		pItems[nIndex1].pCell = pCell2;
1026 		rCol.pItems[nIndex2].pCell = pCell1;
1027 		// Referenzen aktualisieren
1028 		SCsCOL dx = rCol.nCol - nCol;
1029 		if ( pFmlaCell1 )
1030 		{
1031 			ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
1032 							ScAddress( rCol.nCol, MAXROW, nTab ) );
1033 			pFmlaCell1->aPos.SetCol( rCol.nCol );
1034 			pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
1035 		}
1036 		if ( pFmlaCell2 )
1037 		{
1038 			ScRange aRange( ScAddress( nCol, 0, nTab ),
1039 							ScAddress( nCol, MAXROW, nTab ) );
1040 			pFmlaCell2->aPos.SetCol( nCol );
1041 			pFmlaCell2->UpdateReference(URM_MOVE, aRange, -dx, 0, 0);
1042 		}
1043 	}
1044 	else
1045     {
1046         // Loeschen
1047         --nCount;
1048         memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) );
1049         pItems[nCount].nRow = 0;
1050         pItems[nCount].pCell = 0;
1051         // Referenzen aktualisieren
1052         SCsCOL dx = rCol.nCol - nCol;
1053         if ( pFmlaCell1 )
1054         {
1055             ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
1056                             ScAddress( rCol.nCol, MAXROW, nTab ) );
1057             pFmlaCell1->aPos.SetCol( rCol.nCol );
1058             pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
1059         }
1060         // Einfuegen
1061         rCol.Insert(nRow, pCell1);
1062     }
1063 }
1064 
1065 
1066 sal_Bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1067 {
1068 	if (!IsEmpty())
1069 	{
1070 		sal_Bool bTest = sal_True;
1071 		if (pItems)
1072 			for (SCSIZE i=0; (i<nCount) && bTest; i++)
1073 				bTest = (pItems[i].nRow < nStartRow) || (pItems[i].nRow > nEndRow)
1074                         || pItems[i].pCell->IsBlank();
1075 
1076 		//	AttrArray testet nur zusammengefasste
1077 
1078 		if ((bTest) && (pAttrArray))
1079 			bTest = pAttrArray->TestInsertCol(nStartRow, nEndRow);
1080 
1081 		//!		rausgeschobene Attribute bei Undo beruecksichtigen
1082 
1083 		return bTest;
1084 	}
1085 	else
1086 		return sal_True;
1087 }
1088 
1089 
1090 sal_Bool ScColumn::TestInsertRow( SCSIZE nSize ) const
1091 {
1092     //  AttrArray only looks for merged cells
1093 
1094 	if ( pItems && nCount )
1095         return ( nSize <= sal::static_int_cast<SCSIZE>(MAXROW) &&
1096                  pItems[nCount-1].nRow <= MAXROW-(SCROW)nSize && pAttrArray->TestInsertRow( nSize ) );
1097 	else
1098 		return pAttrArray->TestInsertRow( nSize );
1099 
1100 #if 0
1101 	//!		rausgeschobene Attribute bei Undo beruecksichtigen
1102 
1103 	if ( nSize > static_cast<SCSIZE>(MAXROW) )
1104 		return sal_False;
1105 
1106 	SCSIZE nVis = nCount;
1107     while ( nVis && pItems[nVis-1].pCell->IsBlank() )
1108 		--nVis;
1109 
1110 	if ( nVis )
1111 		return ( pItems[nVis-1].nRow <= MAXROW-nSize );
1112 	else
1113 		return sal_True;
1114 #endif
1115 }
1116 
1117 
1118 void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
1119 {
1120 	pAttrArray->InsertRow( nStartRow, nSize );
1121 
1122 	//!	Search
1123 
1124 	if ( !pItems || !nCount )
1125 		return;
1126 
1127 	SCSIZE i;
1128 	Search( nStartRow, i );
1129 	if ( i >= nCount )
1130 		return ;
1131 
1132 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1133 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1134 
1135 	SCSIZE nNewCount = nCount;
1136 	sal_Bool bCountChanged = sal_False;
1137 	ScAddress aAdr( nCol, 0, nTab );
1138     ScHint aHint( SC_HINT_DATACHANGED, aAdr, NULL );    // only areas (ScBaseCell* == NULL)
1139     ScAddress& rAddress = aHint.GetAddress();
1140     // for sparse occupation use single broadcasts, not ranges
1141     sal_Bool bSingleBroadcasts = (((pItems[nCount-1].nRow - pItems[i].nRow) /
1142                 (nCount - i)) > 1);
1143     if ( bSingleBroadcasts )
1144     {
1145         SCROW nLastBroadcast = MAXROW+1;
1146         for ( ; i < nCount; i++)
1147         {
1148             SCROW nOldRow = pItems[i].nRow;
1149             // #43940# Aenderung Quelle broadcasten
1150             if ( nLastBroadcast != nOldRow )
1151             {   // direkt aufeinanderfolgende nicht doppelt broadcasten
1152                 rAddress.SetRow( nOldRow );
1153                 pDocument->AreaBroadcast( aHint );
1154             }
1155             SCROW nNewRow = (pItems[i].nRow += nSize);
1156             // #43940# Aenderung Ziel broadcasten
1157             rAddress.SetRow( nNewRow );
1158             pDocument->AreaBroadcast( aHint );
1159             nLastBroadcast = nNewRow;
1160             ScBaseCell* pCell = pItems[i].pCell;
1161             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1162                 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
1163             if ( nNewRow > MAXROW && !bCountChanged )
1164             {
1165                 nNewCount = i;
1166                 bCountChanged = sal_True;
1167             }
1168         }
1169     }
1170     else
1171     {
1172         rAddress.SetRow( pItems[i].nRow );
1173         ScRange aRange( rAddress );
1174         for ( ; i < nCount; i++)
1175         {
1176             SCROW nNewRow = (pItems[i].nRow += nSize);
1177             ScBaseCell* pCell = pItems[i].pCell;
1178             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1179                 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
1180             if ( nNewRow > MAXROW && !bCountChanged )
1181             {
1182                 nNewCount = i;
1183                 bCountChanged = sal_True;
1184                 aRange.aEnd.SetRow( MAXROW );
1185             }
1186         }
1187         if ( !bCountChanged )
1188             aRange.aEnd.SetRow( pItems[nCount-1].nRow );
1189         pDocument->AreaBroadcastInRange( aRange, aHint );
1190     }
1191 
1192 	if (bCountChanged)
1193 	{
1194 		SCSIZE nDelCount = nCount - nNewCount;
1195 		ScBaseCell** ppDelCells = new ScBaseCell*[nDelCount];
1196 		SCROW* pDelRows = new SCROW[nDelCount];
1197 		for (i = 0; i < nDelCount; i++)
1198 		{
1199 			ppDelCells[i] = pItems[nNewCount+i].pCell;
1200 			pDelRows[i] = pItems[nNewCount+i].nRow;
1201 		}
1202 		nCount = nNewCount;
1203 
1204 		for (i = 0; i < nDelCount; i++)
1205 		{
1206 			ScBaseCell* pCell = ppDelCells[i];
1207             DBG_ASSERT( pCell->IsBlank(), "sichtbare Zelle weggeschoben" );
1208 			SvtBroadcaster* pBC = pCell->GetBroadcaster();
1209 			if (pBC)
1210 			{
1211 				MoveListeners( *pBC, pDelRows[i] - nSize );
1212                 pCell->DeleteBroadcaster();
1213 				pCell->Delete();
1214 			}
1215 		}
1216 
1217 		delete [] pDelRows;
1218 		delete [] ppDelCells;
1219 	}
1220 
1221 	pDocument->SetAutoCalc( bOldAutoCalc );
1222 }
1223 
1224 
1225 void ScColumn::CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, sal_Bool bKeepScenarioFlags, sal_Bool bCloneNoteCaptions)
1226 {
1227 	pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
1228 							bKeepScenarioFlags ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
1229 
1230 	SCSIZE i;
1231 	SCSIZE nBlockCount = 0;
1232     SCSIZE nStartIndex = 0, nEndIndex = 0;
1233 	for (i = 0; i < nCount; i++)
1234 		if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2))
1235 		{
1236 			if (!nBlockCount)
1237 				nStartIndex = i;
1238 			nEndIndex = i;
1239 			++nBlockCount;
1240 
1241 			//	im Clipboard muessen interpretierte Zellen stehen, um andere Formate
1242 			//	(Text, Grafik...) erzueugen zu koennen
1243 
1244 			if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1245 			{
1246 				ScFormulaCell* pFCell = (ScFormulaCell*) pItems[i].pCell;
1247 				if (pFCell->GetDirty() && pDocument->GetAutoCalc())
1248 					pFCell->Interpret();
1249 			}
1250 		}
1251 
1252 	if (nBlockCount)
1253 	{
1254         int nCloneFlags = bCloneNoteCaptions ? SC_CLONECELL_DEFAULT : SC_CLONECELL_NOCAPTION;
1255 		rColumn.Resize( rColumn.GetCellCount() + nBlockCount );
1256         ScAddress aOwnPos( nCol, 0, nTab );
1257         ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
1258 		for (i = nStartIndex; i <= nEndIndex; i++)
1259         {
1260             aOwnPos.SetRow( pItems[i].nRow );
1261             aDestPos.SetRow( pItems[i].nRow );
1262             ScBaseCell* pNewCell = pItems[i].pCell->CloneWithNote( aOwnPos, *rColumn.pDocument, aDestPos, nCloneFlags );
1263             rColumn.Append( aDestPos.Row(), pNewCell );
1264         }
1265 	}
1266 }
1267 
1268 
1269 void ScColumn::CopyToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked,
1270 								ScColumn& rColumn, const ScMarkData* pMarkData, sal_Bool bAsLink )
1271 {
1272 	if (bMarked)
1273 	{
1274 		SCROW nStart, nEnd;
1275 		if (pMarkData && pMarkData->IsMultiMarked())
1276 		{
1277 			ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
1278 
1279 			while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
1280 			{
1281 				if ( nEnd >= nRow1 )
1282 					CopyToColumn( Max(nRow1,nStart), Min(nRow2,nEnd),
1283 									nFlags, sal_False, rColumn, pMarkData, bAsLink );
1284 			}
1285 		}
1286 		else
1287 		{
1288 			DBG_ERROR("CopyToColumn: bMarked, aber keine Markierung");
1289 		}
1290 		return;
1291 	}
1292 
1293 	if ( (nFlags & IDF_ATTRIB) != 0 )
1294 	{
1295 		if ( (nFlags & IDF_STYLES) != IDF_STYLES )
1296 		{	// StyleSheets im Zieldokument bleiben erhalten
1297 			// z.B. DIF und RTF Clipboard-Import
1298 			for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
1299 			{
1300 				const ScStyleSheet* pStyle =
1301 					rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
1302 				const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
1303 				ScPatternAttr* pNewPattern = new ScPatternAttr( *pPattern );
1304 				pNewPattern->SetStyleSheet( (ScStyleSheet*)pStyle );
1305 				rColumn.pAttrArray->SetPattern( nRow, pNewPattern, sal_True );
1306 				delete pNewPattern;
1307 			}
1308 		}
1309 		else
1310 			pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
1311 	}
1312 
1313 
1314 	if ((nFlags & IDF_CONTENTS) != 0)
1315 	{
1316 		SCSIZE i;
1317 		SCSIZE nBlockCount = 0;
1318         SCSIZE nStartIndex = 0, nEndIndex = 0;
1319 		for (i = 0; i < nCount; i++)
1320 			if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2))
1321 			{
1322 				if (!nBlockCount)
1323 					nStartIndex = i;
1324 				nEndIndex = i;
1325 				++nBlockCount;
1326 			}
1327 
1328 		if (nBlockCount)
1329 		{
1330 			rColumn.Resize( rColumn.GetCellCount() + nBlockCount );
1331 			ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
1332 			for (i = nStartIndex; i <= nEndIndex; i++)
1333 			{
1334 				aDestPos.SetRow( pItems[i].nRow );
1335 				ScBaseCell* pNew = bAsLink ?
1336                     CreateRefCell( rColumn.pDocument, aDestPos, i, nFlags ) :
1337                     CloneCell( i, nFlags, *rColumn.pDocument, aDestPos );
1338 
1339 				if (pNew)
1340 					rColumn.Insert(pItems[i].nRow, pNew);
1341 			}
1342 		}
1343 	}
1344 }
1345 
1346 
1347 void ScColumn::UndoToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked,
1348 								ScColumn& rColumn, const ScMarkData* pMarkData )
1349 {
1350 	if (nRow1 > 0)
1351 		CopyToColumn( 0, nRow1-1, IDF_FORMULA, sal_False, rColumn );
1352 
1353 	CopyToColumn( nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData );		//! bMarked ????
1354 
1355 	if (nRow2 < MAXROW)
1356 		CopyToColumn( nRow2+1, MAXROW, IDF_FORMULA, sal_False, rColumn );
1357 }
1358 
1359 
1360 void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
1361 {
1362 	ScDocument& rDestDoc = *rDestCol.pDocument;
1363     ScAddress aOwnPos( nCol, 0, nTab );
1364     ScAddress aDestPos( rDestCol.nCol, 0, rDestCol.nTab );
1365 
1366 	SCSIZE nPosCount = rPosCol.nCount;
1367 	for (SCSIZE nPosIndex = 0; nPosIndex < nPosCount; nPosIndex++)
1368 	{
1369         aOwnPos.SetRow( rPosCol.pItems[nPosIndex].nRow );
1370         aDestPos.SetRow( aOwnPos.Row() );
1371 		SCSIZE nThisIndex;
1372 		if ( Search( aDestPos.Row(), nThisIndex ) )
1373 		{
1374             ScBaseCell* pNew = pItems[nThisIndex].pCell->CloneWithNote( aOwnPos, rDestDoc, aDestPos );
1375 			rDestCol.Insert( aDestPos.Row(), pNew );
1376 		}
1377 	}
1378 
1379 	//	Dummy:
1380 	//	CopyToColumn( 0,MAXROW, IDF_FORMULA, sal_False, rDestCol, NULL, sal_False );
1381 }
1382 
1383 
1384 void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
1385 {
1386 	//	Dies ist die Szenario-Tabelle, die Daten werden hineinkopiert
1387 
1388 	ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1389 	SCROW nStart = -1, nEnd = -1;
1390 	const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1391 	while (pPattern)
1392 	{
1393 		if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1394 		{
1395 			DeleteArea( nStart, nEnd, IDF_CONTENTS );
1396 			((ScColumn&)rSrcCol).
1397 				CopyToColumn( nStart, nEnd, IDF_CONTENTS, sal_False, *this );
1398 
1399 			//	UpdateUsed nicht noetig, schon in TestCopyScenario passiert
1400 
1401 			SCsTAB nDz = nTab - rSrcCol.nTab;
1402 			UpdateReference(URM_COPY, nCol, nStart, nTab,
1403 									  nCol, nEnd,   nTab,
1404 									  0, 0, nDz, NULL);
1405 			UpdateCompile();
1406 		}
1407 
1408 		//!	CopyToColumn "const" machen !!!
1409 
1410 		pPattern = aAttrIter.Next( nStart, nEnd );
1411 	}
1412 }
1413 
1414 
1415 void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
1416 {
1417 	//	Dies ist die Szenario-Tabelle, die Daten werden in die andere kopiert
1418 
1419 	ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1420 	SCROW nStart = -1, nEnd = -1;
1421 	const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1422 	while (pPattern)
1423 	{
1424 		if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1425 		{
1426 			rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
1427 			((ScColumn*)this)->
1428 				CopyToColumn( nStart, nEnd, IDF_CONTENTS, sal_False, rDestCol );
1429 
1430 			//	UpdateUsed nicht noetig, schon in TestCopyScenario passiert
1431 
1432 			SCsTAB nDz = rDestCol.nTab - nTab;
1433 			rDestCol.UpdateReference(URM_COPY, rDestCol.nCol, nStart, rDestCol.nTab,
1434 											   rDestCol.nCol, nEnd,   rDestCol.nTab,
1435 											   0, 0, nDz, NULL);
1436 			rDestCol.UpdateCompile();
1437 		}
1438 
1439 		//!	CopyToColumn "const" machen !!!
1440 
1441 		pPattern = aAttrIter.Next( nStart, nEnd );
1442 	}
1443 }
1444 
1445 
1446 sal_Bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
1447 {
1448 	sal_Bool bOk = sal_True;
1449 	ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1450 	SCROW nStart = 0, nEnd = 0;
1451 	const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1452 	while (pPattern && bOk)
1453 	{
1454 		if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1455 			if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) )
1456 				bOk = sal_False;
1457 
1458 		pPattern = aAttrIter.Next( nStart, nEnd );
1459 	}
1460 	return bOk;
1461 }
1462 
1463 
1464 void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
1465 {
1466 	ScRange aRange( nCol, 0, nTab );
1467 
1468 	ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1469 	SCROW nStart = -1, nEnd = -1;
1470 	const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1471 	while (pPattern)
1472 	{
1473 		if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1474 		{
1475 			aRange.aStart.SetRow( nStart );
1476 			aRange.aEnd.SetRow( nEnd );
1477 			rDestMark.SetMultiMarkArea( aRange, sal_True );
1478 		}
1479 
1480 		pPattern = aAttrIter.Next( nStart, nEnd );
1481 	}
1482 }
1483 
1484 
1485 void ScColumn::SwapCol(ScColumn& rCol)
1486 {
1487 	SCSIZE nTemp;
1488 
1489 	nTemp = rCol.nCount;
1490 	rCol.nCount  = nCount;
1491 	nCount = nTemp;
1492 
1493 	nTemp = rCol.nLimit;
1494 	rCol.nLimit = nLimit;
1495 	nLimit = nTemp;
1496 
1497 	ColEntry* pTempItems = rCol.pItems;
1498 	rCol.pItems = pItems;
1499 	pItems = pTempItems;
1500 
1501 	ScAttrArray* pTempAttr = rCol.pAttrArray;
1502 	rCol.pAttrArray = pAttrArray;
1503 	pAttrArray = pTempAttr;
1504 
1505 	// #38415# AttrArray muss richtige Spaltennummer haben
1506 	pAttrArray->SetCol(nCol);
1507 	rCol.pAttrArray->SetCol(rCol.nCol);
1508 
1509 	SCSIZE i;
1510 	if (pItems)
1511 		for (i = 0; i < nCount; i++)
1512 		{
1513 			ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1514 			if( pCell->GetCellType() == CELLTYPE_FORMULA)
1515 				pCell->aPos.SetCol(nCol);
1516 		}
1517 	if (rCol.pItems)
1518 		for (i = 0; i < rCol.nCount; i++)
1519 		{
1520 			ScFormulaCell* pCell = (ScFormulaCell*) rCol.pItems[i].pCell;
1521 			if( pCell->GetCellType() == CELLTYPE_FORMULA)
1522 				pCell->aPos.SetCol(rCol.nCol);
1523 		}
1524 }
1525 
1526 
1527 void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
1528 {
1529 	pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
1530 
1531 	if (pItems)
1532 	{
1533         ::std::vector<SCROW> aRows;
1534         bool bConsecutive = true;
1535 		SCSIZE i;
1536         Search( nStartRow, i);  // i points to start row or position thereafter
1537 		SCSIZE nStartPos = i;
1538 		for ( ; i < nCount && pItems[i].nRow <= nEndRow; ++i)
1539 		{
1540             SCROW nRow = pItems[i].nRow;
1541             aRows.push_back( nRow);
1542             rCol.Insert( nRow, pItems[i].pCell);
1543             if (nRow != pItems[i].nRow)
1544             {   // Listener inserted
1545                 bConsecutive = false;
1546                 Search( nRow, i);
1547             }
1548 		}
1549         SCSIZE nStopPos = i;
1550 		if (nStartPos < nStopPos)
1551 		{
1552             // Create list of ranges of cell entry positions
1553             typedef ::std::pair<SCSIZE,SCSIZE> PosPair;
1554             typedef ::std::vector<PosPair> EntryPosPairs;
1555             EntryPosPairs aEntries;
1556             if (bConsecutive)
1557                 aEntries.push_back( PosPair(nStartPos, nStopPos));
1558             else
1559             {
1560                 bool bFirst = true;
1561                 nStopPos = 0;
1562                 for (::std::vector<SCROW>::const_iterator it( aRows.begin());
1563                         it != aRows.end() && nStopPos < nCount; ++it,
1564                         ++nStopPos)
1565                 {
1566                     if (!bFirst && *it != pItems[nStopPos].nRow)
1567                     {
1568                         aEntries.push_back( PosPair(nStartPos, nStopPos));
1569                         bFirst = true;
1570                     }
1571                     if (bFirst && Search( *it, nStartPos))
1572                     {
1573                         bFirst = false;
1574                         nStopPos = nStartPos;
1575                     }
1576                 }
1577                 if (!bFirst && nStartPos < nStopPos)
1578                     aEntries.push_back( PosPair(nStartPos, nStopPos));
1579             }
1580 			// Broadcast changes
1581             ScAddress aAdr( nCol, 0, nTab );
1582             ScHint aHint( SC_HINT_DYING, aAdr, NULL );  // areas only
1583             ScAddress& rAddress = aHint.GetAddress();
1584             ScNoteCell* pNoteCell = new ScNoteCell;		// Dummy like in DeleteRange
1585 
1586             // #121990# must iterate backwards, because indexes of following cells become invalid
1587             for (EntryPosPairs::reverse_iterator it( aEntries.rbegin());
1588                     it != aEntries.rend(); ++it)
1589             {
1590                 nStartPos = (*it).first;
1591                 nStopPos = (*it).second;
1592                 for (i=nStartPos; i<nStopPos; ++i)
1593                     pItems[i].pCell = pNoteCell;
1594                 for (i=nStartPos; i<nStopPos; ++i)
1595                 {
1596                     rAddress.SetRow( pItems[i].nRow );
1597                     pDocument->AreaBroadcast( aHint );
1598                 }
1599                 nCount -= nStopPos - nStartPos;
1600                 memmove( &pItems[nStartPos], &pItems[nStopPos],
1601                         (nCount - nStartPos) * sizeof(ColEntry) );
1602             }
1603             delete pNoteCell;
1604             pItems[nCount].nRow = 0;
1605             pItems[nCount].pCell = NULL;
1606 		}
1607 	}
1608 }
1609 
1610 
1611 void ScColumn::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1612 			 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
1613 			 ScDocument* pUndoDoc )
1614 {
1615 	if (pItems)
1616 	{
1617 		ScRange aRange( ScAddress( nCol1, nRow1, nTab1 ),
1618 						ScAddress( nCol2, nRow2, nTab2 ) );
1619 		if ( eUpdateRefMode == URM_COPY && nRow1 == nRow2 )
1620 		{	// z.B. eine einzelne Zelle aus dem Clipboard eingefuegt
1621 			SCSIZE nIndex;
1622 			if ( Search( nRow1, nIndex ) )
1623 			{
1624 				ScFormulaCell* pCell = (ScFormulaCell*) pItems[nIndex].pCell;
1625 				if( pCell->GetCellType() == CELLTYPE_FORMULA)
1626 					pCell->UpdateReference(	eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
1627 			}
1628 		}
1629 		else
1630 		{
1631             // #90279# For performance reasons two loop bodies instead of
1632             // testing for update mode in each iteration.
1633             // Anyways, this is still a bottleneck on large arrays with few
1634             // formulas cells.
1635             if ( eUpdateRefMode == URM_COPY )
1636             {
1637                 SCSIZE i;
1638                 Search( nRow1, i );
1639                 for ( ; i < nCount; i++ )
1640                 {
1641                     SCROW nRow = pItems[i].nRow;
1642                     if ( nRow > nRow2 )
1643                         break;
1644                     ScBaseCell* pCell = pItems[i].pCell;
1645                     if( pCell->GetCellType() == CELLTYPE_FORMULA)
1646                     {
1647                         ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
1648                         if ( nRow != pItems[i].nRow )
1649                             Search( nRow, i );  // Listener removed/inserted?
1650                     }
1651                 }
1652             }
1653             else
1654             {
1655                 SCSIZE i = 0;
1656                 for ( ; i < nCount; i++ )
1657                 {
1658                     ScBaseCell* pCell = pItems[i].pCell;
1659                     if( pCell->GetCellType() == CELLTYPE_FORMULA)
1660                     {
1661                         SCROW nRow = pItems[i].nRow;
1662                         // When deleting rows on several sheets, the formula's position may be updated with the first call,
1663                         // so the undo position must be passed from here.
1664                         ScAddress aUndoPos( nCol, nRow, nTab );
1665                         ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc, &aUndoPos );
1666                         if ( nRow != pItems[i].nRow )
1667                             Search( nRow, i );  // Listener removed/inserted?
1668                     }
1669                 }
1670             }
1671 		}
1672 	}
1673 }
1674 
1675 
1676 void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1677 									ScDocument* pUndoDoc )
1678 {
1679 	if (pItems)
1680 		for (SCSIZE i=0; i<nCount; i++)
1681 		{
1682 			ScBaseCell* pCell = pItems[i].pCell;
1683 			if (pCell->GetCellType() == CELLTYPE_FORMULA)
1684 			{
1685 				SCROW nRow = pItems[i].nRow;
1686 				((ScFormulaCell*)pCell)->UpdateTranspose( rSource, rDest, pUndoDoc );
1687 				if ( nRow != pItems[i].nRow )
1688 					Search( nRow, i );				// Listener geloescht/eingefuegt?
1689 			}
1690 		}
1691 }
1692 
1693 
1694 void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1695 {
1696 	if (pItems)
1697 		for (SCSIZE i=0; i<nCount; i++)
1698 		{
1699 			ScBaseCell* pCell = pItems[i].pCell;
1700 			if (pCell->GetCellType() == CELLTYPE_FORMULA)
1701 			{
1702 				SCROW nRow = pItems[i].nRow;
1703 				((ScFormulaCell*)pCell)->UpdateGrow( rArea, nGrowX, nGrowY );
1704 				if ( nRow != pItems[i].nRow )
1705 					Search( nRow, i );				// Listener geloescht/eingefuegt?
1706 			}
1707 		}
1708 }
1709 
1710 
1711 void ScColumn::UpdateInsertTab( SCTAB nTable)
1712 {
1713     if (nTab >= nTable)
1714         pAttrArray->SetTab(++nTab);
1715 	if( pItems )
1716 		UpdateInsertTabOnlyCells( nTable );
1717 }
1718 
1719 
1720 void ScColumn::UpdateInsertTabOnlyCells( SCTAB nTable)
1721 {
1722 	if (pItems)
1723 		for (SCSIZE i = 0; i < nCount; i++)
1724 		{
1725 			ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1726 			if( pCell->GetCellType() == CELLTYPE_FORMULA)
1727 			{
1728 				SCROW nRow = pItems[i].nRow;
1729 				pCell->UpdateInsertTab(nTable);
1730 				if ( nRow != pItems[i].nRow )
1731 					Search( nRow, i );		// Listener geloescht/eingefuegt?
1732 			}
1733 		}
1734 }
1735 
1736 
1737 void ScColumn::UpdateInsertTabAbs(SCTAB nTable)
1738 {
1739 	if (pItems)
1740 		for (SCSIZE i = 0; i < nCount; i++)
1741 		{
1742 			ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1743 			if( pCell->GetCellType() == CELLTYPE_FORMULA)
1744 			{
1745 				SCROW nRow = pItems[i].nRow;
1746 				pCell->UpdateInsertTabAbs(nTable);
1747 				if ( nRow != pItems[i].nRow )
1748 					Search( nRow, i );		// Listener geloescht/eingefuegt?
1749 			}
1750 		}
1751 }
1752 
1753 
1754 void ScColumn::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScColumn* pRefUndo )
1755 {
1756 	if (nTab > nTable)
1757 		pAttrArray->SetTab(--nTab);
1758 
1759 	if (pItems)
1760 		for (SCSIZE i = 0; i < nCount; i++)
1761 			if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1762 			{
1763 				SCROW nRow = pItems[i].nRow;
1764 				ScFormulaCell* pOld = (ScFormulaCell*)pItems[i].pCell;
1765 
1766                 /*  Do not copy cell note to the undo document. Undo will copy
1767                     back the formula cell while keeping the original note. */
1768                 ScBaseCell* pSave = pRefUndo ? pOld->CloneWithoutNote( *pDocument ) : 0;
1769 
1770 				sal_Bool bChanged = pOld->UpdateDeleteTab(nTable, bIsMove);
1771 				if ( nRow != pItems[i].nRow )
1772 					Search( nRow, i );		// Listener geloescht/eingefuegt?
1773 
1774 				if (pRefUndo)
1775 				{
1776 					if (bChanged)
1777 						pRefUndo->Insert( nRow, pSave );
1778 					else if(pSave)
1779 						pSave->Delete();
1780 				}
1781 			}
1782 }
1783 
1784 
1785 void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
1786 {
1787 	nTab = nTabNo;
1788 	pAttrArray->SetTab( nTabNo );
1789 	if (pItems)
1790 		for (SCSIZE i = 0; i < nCount; i++)
1791 		{
1792 			ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1793 			if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1794 			{
1795 				SCROW nRow = pItems[i].nRow;
1796 				pCell->UpdateMoveTab( nOldPos, nNewPos, nTabNo );
1797 				if ( nRow != pItems[i].nRow )
1798 					Search( nRow, i );		// Listener geloescht/eingefuegt?
1799 			}
1800 		}
1801 }
1802 
1803 
1804 void ScColumn::UpdateCompile( sal_Bool bForceIfNameInUse )
1805 {
1806 	if (pItems)
1807 		for (SCSIZE i = 0; i < nCount; i++)
1808 		{
1809 			ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1810 			if( p->GetCellType() == CELLTYPE_FORMULA )
1811 			{
1812 				SCROW nRow = pItems[i].nRow;
1813 				p->UpdateCompile( bForceIfNameInUse );
1814 				if ( nRow != pItems[i].nRow )
1815 					Search( nRow, i );		// Listener geloescht/eingefuegt?
1816 			}
1817 		}
1818 }
1819 
1820 
1821 void ScColumn::SetTabNo(SCTAB nNewTab)
1822 {
1823 	nTab = nNewTab;
1824 	pAttrArray->SetTab( nNewTab );
1825 	if (pItems)
1826 		for (SCSIZE i = 0; i < nCount; i++)
1827 		{
1828 			ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1829 			if( p->GetCellType() == CELLTYPE_FORMULA )
1830 				p->aPos.SetTab( nNewTab );
1831 		}
1832 }
1833 
1834 
1835 sal_Bool ScColumn::IsRangeNameInUse(SCROW nRow1, SCROW nRow2, sal_uInt16 nIndex) const
1836 {
1837 	sal_Bool bInUse = sal_False;
1838 	if (pItems)
1839 		for (SCSIZE i = 0; !bInUse && (i < nCount); i++)
1840 			if ((pItems[i].nRow >= nRow1) &&
1841 				(pItems[i].nRow <= nRow2) &&
1842 				(pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1843 					bInUse = ((ScFormulaCell*)pItems[i].pCell)->IsRangeNameInUse(nIndex);
1844 	return bInUse;
1845 }
1846 
1847 void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
1848 {
1849     if (pItems)
1850         for (SCSIZE i = 0; i < nCount; i++)
1851             if ((pItems[i].nRow >= nRow1) &&
1852                 (pItems[i].nRow <= nRow2) &&
1853                 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1854                     ((ScFormulaCell*)pItems[i].pCell)->FindRangeNamesInUse(rIndexes);
1855 }
1856 
1857 void ScColumn::ReplaceRangeNamesInUse(SCROW nRow1, SCROW nRow2,
1858                                      const ScRangeData::IndexMap& rMap )
1859 {
1860     if (pItems)
1861         for (SCSIZE i = 0; i < nCount; i++)
1862         {
1863             if ((pItems[i].nRow >= nRow1) &&
1864                 (pItems[i].nRow <= nRow2) &&
1865                 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1866             {
1867                 SCROW nRow = pItems[i].nRow;
1868                 ((ScFormulaCell*)pItems[i].pCell)->ReplaceRangeNamesInUse( rMap );
1869                 if ( nRow != pItems[i].nRow )
1870                     Search( nRow, i );      // Listener geloescht/eingefuegt?
1871             }
1872         }
1873 }
1874 
1875 void ScColumn::SetDirtyVar()
1876 {
1877 	for (SCSIZE i=0; i<nCount; i++)
1878 	{
1879 		ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1880 		if( p->GetCellType() == CELLTYPE_FORMULA )
1881 			p->SetDirtyVar();
1882 	}
1883 }
1884 
1885 
1886 void ScColumn::SetDirty()
1887 {
1888 	// wird nur dokumentweit verwendet, kein FormulaTrack
1889 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1890 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1891 	for (SCSIZE i=0; i<nCount; i++)
1892 	{
1893 		ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1894 		if( p->GetCellType() == CELLTYPE_FORMULA )
1895 		{
1896 			p->SetDirtyVar();
1897 			if ( !pDocument->IsInFormulaTree( p ) )
1898 				pDocument->PutInFormulaTree( p );
1899 		}
1900 	}
1901 	pDocument->SetAutoCalc( bOldAutoCalc );
1902 }
1903 
1904 
1905 void ScColumn::SetDirty( const ScRange& rRange )
1906 {	// broadcastet alles innerhalb eines Range, mit FormulaTrack
1907 	if ( !pItems || !nCount )
1908 		return ;
1909 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1910 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1911 	SCROW nRow2 = rRange.aEnd.Row();
1912 	ScAddress aPos( nCol, 0, nTab );
1913     ScHint aHint( SC_HINT_DATACHANGED, aPos, NULL );
1914 	SCROW nRow;
1915 	SCSIZE nIndex;
1916 	Search( rRange.aStart.Row(), nIndex );
1917 	while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
1918 	{
1919 		ScBaseCell* pCell = pItems[nIndex].pCell;
1920 		if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1921 			((ScFormulaCell*)pCell)->SetDirty();
1922 		else
1923 		{
1924 			aHint.GetAddress().SetRow( nRow );
1925             aHint.SetCell( pCell );
1926 			pDocument->Broadcast( aHint );
1927 		}
1928 		nIndex++;
1929 	}
1930 	pDocument->SetAutoCalc( bOldAutoCalc );
1931 }
1932 
1933 
1934 void ScColumn::SetTableOpDirty( const ScRange& rRange )
1935 {
1936 	if ( !pItems || !nCount )
1937 		return ;
1938 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1939 	pDocument->SetAutoCalc( sal_False );	// no multiple recalculation
1940 	SCROW nRow2 = rRange.aEnd.Row();
1941 	ScAddress aPos( nCol, 0, nTab );
1942     ScHint aHint( SC_HINT_TABLEOPDIRTY, aPos, NULL );
1943 	SCROW nRow;
1944 	SCSIZE nIndex;
1945 	Search( rRange.aStart.Row(), nIndex );
1946 	while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
1947 	{
1948 		ScBaseCell* pCell = pItems[nIndex].pCell;
1949 		if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1950 			((ScFormulaCell*)pCell)->SetTableOpDirty();
1951 		else
1952 		{
1953 			aHint.GetAddress().SetRow( nRow );
1954             aHint.SetCell( pCell );
1955 			pDocument->Broadcast( aHint );
1956 		}
1957 		nIndex++;
1958 	}
1959 	pDocument->SetAutoCalc( bOldAutoCalc );
1960 }
1961 
1962 
1963 void ScColumn::SetDirtyAfterLoad()
1964 {
1965 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1966 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1967 	for (SCSIZE i=0; i<nCount; i++)
1968 	{
1969 		ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1970 #if 1
1971         // Simply set dirty and append to FormulaTree, without broadcasting,
1972         // which is a magnitude faster. This is used to calculate the entire
1973         // document, e.g. when loading alien file formats.
1974         if ( p->GetCellType() == CELLTYPE_FORMULA )
1975             p->SetDirtyAfterLoad();
1976 #else
1977 /* This was used with the binary file format that stored results, where only
1978  * newly compiled and volatile functions and their dependents had to be
1979  * recalculated, which was faster then. Since that was moved to 'binfilter' to
1980  * convert to an XML file this isn't needed anymore, and not used for other
1981  * file formats. Kept for reference in case mechanism needs to be reactivated
1982  * for some file formats, we'd have to introduce a controlling parameter to
1983  * this method here then.
1984 */
1985 
1986         // If the cell was alsready dirty because of CalcAfterLoad,
1987         // FormulaTracking has to take place.
1988         if ( p->GetCellType() == CELLTYPE_FORMULA && p->GetDirty() )
1989             p->SetDirty();
1990 #endif
1991 	}
1992 	pDocument->SetAutoCalc( bOldAutoCalc );
1993 }
1994 
1995 
1996 void ScColumn::SetRelNameDirty()
1997 {
1998 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1999 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
2000 	for (SCSIZE i=0; i<nCount; i++)
2001 	{
2002 		ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
2003 		if( p->GetCellType() == CELLTYPE_FORMULA && p->HasRelNameReference() )
2004 			p->SetDirty();
2005 	}
2006 	pDocument->SetAutoCalc( bOldAutoCalc );
2007 }
2008 
2009 
2010 void ScColumn::CalcAll()
2011 {
2012 	if (pItems)
2013 		for (SCSIZE i=0; i<nCount; i++)
2014 		{
2015 			ScBaseCell* pCell = pItems[i].pCell;
2016 			if (pCell->GetCellType() == CELLTYPE_FORMULA)
2017 			{
2018 #if OSL_DEBUG_LEVEL > 1
2019 				// nach F9 ctrl-F9: ueberprueft die Berechnung per FormulaTree
2020 				ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
2021 				double nOldVal, nNewVal;
2022 				nOldVal = pFCell->GetValue();
2023 #endif
2024 				((ScFormulaCell*)pCell)->Interpret();
2025 #if OSL_DEBUG_LEVEL > 1
2026 				if ( pFCell->GetCode()->IsRecalcModeNormal() )
2027 					nNewVal = pFCell->GetValue();
2028 				else
2029 					nNewVal = nOldVal;	// random(), jetzt() etc.
2030 				DBG_ASSERT( nOldVal==nNewVal, "CalcAll: nOldVal != nNewVal" );
2031 #endif
2032 			}
2033 		}
2034 }
2035 
2036 
2037 void ScColumn::CompileAll()
2038 {
2039 	if (pItems)
2040 		for (SCSIZE i = 0; i < nCount; i++)
2041 		{
2042 			ScBaseCell* pCell = pItems[i].pCell;
2043 			if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2044 			{
2045 				SCROW nRow = pItems[i].nRow;
2046 				// fuer unbedingtes kompilieren
2047 				// bCompile=sal_True und pCode->nError=0
2048 				((ScFormulaCell*)pCell)->GetCode()->SetCodeError( 0 );
2049 				((ScFormulaCell*)pCell)->SetCompile( sal_True );
2050 				((ScFormulaCell*)pCell)->CompileTokenArray();
2051 				if ( nRow != pItems[i].nRow )
2052 					Search( nRow, i );		// Listener geloescht/eingefuegt?
2053 			}
2054 		}
2055 }
2056 
2057 
2058 void ScColumn::CompileXML( ScProgress& rProgress )
2059 {
2060 	if (pItems)
2061 		for (SCSIZE i = 0; i < nCount; i++)
2062 		{
2063 			ScBaseCell* pCell = pItems[i].pCell;
2064 			if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2065 			{
2066 				SCROW nRow = pItems[i].nRow;
2067 				((ScFormulaCell*)pCell)->CompileXML( rProgress );
2068 				if ( nRow != pItems[i].nRow )
2069 					Search( nRow, i );		// Listener geloescht/eingefuegt?
2070 			}
2071 		}
2072 }
2073 
2074 
2075 void ScColumn::CalcAfterLoad()
2076 {
2077 	if (pItems)
2078 		for (SCSIZE i = 0; i < nCount; i++)
2079 		{
2080 			ScBaseCell* pCell = pItems[i].pCell;
2081 			if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2082 				((ScFormulaCell*)pCell)->CalcAfterLoad();
2083 		}
2084 }
2085 
2086 
2087 void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
2088 {
2089 	if (pItems)
2090 	{
2091 		SCSIZE nIndex;
2092 		Search(nStartRow,nIndex);
2093 		while (nIndex<nCount && pItems[nIndex].nRow <= nEndRow)
2094 		{
2095 			ScBaseCell* pCell = pItems[nIndex].pCell;
2096 			if (pCell->GetCellType() == CELLTYPE_FORMULA)
2097 				((ScFormulaCell*)pCell)->ResetChanged();
2098 			++nIndex;
2099 		}
2100 	}
2101 }
2102 
2103 
2104 sal_Bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const
2105 {
2106 	//	used in GetOptimalHeight - ambiguous script type counts as edit cell
2107 
2108     SCROW nRow = 0;
2109 	SCSIZE nIndex;
2110 	Search(nStartRow,nIndex);
2111 	while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False )
2112 	{
2113 		ScBaseCell* pCell = pItems[nIndex].pCell;
2114         CellType eCellType = pCell->GetCellType();
2115 		if ( eCellType == CELLTYPE_EDIT ||
2116 			 IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) ||
2117              ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) )
2118 		{
2119 			rFirst = nRow;
2120 			return sal_True;
2121 		}
2122 		++nIndex;
2123 	}
2124 
2125 	return sal_False;
2126 }
2127 
2128 
2129 SCsROW ScColumn::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2130 								sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark )
2131 {
2132 	if (bInSelection)
2133 	{
2134 		if (rMark.IsMultiMarked())
2135 			return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp,
2136 									(ScMarkArray*) rMark.GetArray()+nCol );		//! const
2137 		else
2138 			return -1;
2139 	}
2140 	else
2141 		return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL );
2142 }
2143 
2144 
2145 sal_Bool ScColumn::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle,
2146 									sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark )
2147 {
2148 	if (bInSelection)
2149 	{
2150 		if (rMark.IsMultiMarked())
2151 			return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp,
2152 									(ScMarkArray*) rMark.GetArray()+nCol );		//! const
2153 		else
2154 			return sal_False;
2155 	}
2156 	else
2157 		return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );
2158 }
2159 
2160 
2161