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