xref: /aoo41x/main/sc/source/core/data/column3.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 // INCLUDE ---------------------------------------------------------------
31 
32 
33 
34 #include <sfx2/objsh.hxx>
35 #include <svl/zforlist.hxx>
36 #include <svl/zformat.hxx>
37 
38 #include "scitems.hxx"
39 #include "column.hxx"
40 #include "cell.hxx"
41 #include "document.hxx"
42 #include "attarray.hxx"
43 #include "patattr.hxx"
44 #include "cellform.hxx"
45 #include "collect.hxx"
46 #include "formula/errorcodes.hxx"
47 #include "formula/token.hxx"
48 #include "brdcst.hxx"
49 #include "docoptio.hxx"			// GetStdPrecision fuer GetMaxNumberStringLen
50 #include "subtotal.hxx"
51 #include "markdata.hxx"
52 #include "detfunc.hxx"			// fuer Notizen bei DeleteRange
53 #include "postit.hxx"
54 #include "stringutil.hxx"
55 
56 #include <com/sun/star/i18n/LocaleDataItem.hpp>
57 
58 using ::com::sun::star::i18n::LocaleDataItem;
59 using ::rtl::OUString;
60 using ::rtl::OUStringBuffer;
61 
62 // Err527 Workaround
63 extern const ScFormulaCell* pLastFormulaTreeTop;	// in cellform.cxx
64 using namespace formula;
65 // STATIC DATA -----------------------------------------------------------
66 
67 sal_Bool ScColumn::bDoubleAlloc = sal_False;	// fuer Import: Groesse beim Allozieren verdoppeln
68 
69 
70 void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
71 {
72 	sal_Bool bIsAppended = sal_False;
73 	if (pItems && nCount>0)
74 	{
75 		if (pItems[nCount-1].nRow < nRow)
76 		{
77 			Append(nRow, pNewCell );
78 			bIsAppended = sal_True;
79 		}
80 	}
81 	if ( !bIsAppended )
82 	{
83 		SCSIZE	nIndex;
84 		if (Search(nRow, nIndex))
85 		{
86 			ScBaseCell* pOldCell = pItems[nIndex].pCell;
87 
88             // move broadcaster and note to new cell, if not existing in new cell
89             if (pOldCell->HasBroadcaster() && !pNewCell->HasBroadcaster())
90                 pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
91             if (pOldCell->HasNote() && !pNewCell->HasNote())
92 				pNewCell->TakeNote( pOldCell->ReleaseNote() );
93 
94             if ( pOldCell->GetCellType() == CELLTYPE_FORMULA && !pDocument->IsClipOrUndo() )
95 			{
96 				pOldCell->EndListeningTo( pDocument );
97 				// falls in EndListening NoteCell in gleicher Col zerstoert
98 				if ( nIndex >= nCount || pItems[nIndex].nRow != nRow )
99 					Search(nRow, nIndex);
100 			}
101 			pOldCell->Delete();
102 			pItems[nIndex].pCell = pNewCell;
103 		}
104 		else
105 		{
106 			if (nCount + 1 > nLimit)
107 			{
108 				if (bDoubleAlloc)
109 				{
110 					if (nLimit < COLUMN_DELTA)
111 						nLimit = COLUMN_DELTA;
112 					else
113 					{
114 						nLimit *= 2;
115                         if ( nLimit > sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
116 							nLimit = MAXROWCOUNT;
117 					}
118 				}
119 				else
120 					nLimit += COLUMN_DELTA;
121 
122 				ColEntry* pNewItems = new ColEntry[nLimit];
123 				if (pItems)
124 				{
125 					memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
126 					delete[] pItems;
127 				}
128 				pItems = pNewItems;
129 			}
130 			memmove( &pItems[nIndex + 1], &pItems[nIndex], (nCount - nIndex) * sizeof(ColEntry) );
131 			pItems[nIndex].pCell = pNewCell;
132 			pItems[nIndex].nRow  = nRow;
133 			++nCount;
134 		}
135 	}
136 	// Bei aus Clipboard sind hier noch falsche (alte) Referenzen!
137 	// Werden in CopyBlockFromClip per UpdateReference umgesetzt,
138 	// danach StartListeningFromClip und BroadcastFromClip gerufen.
139 	// Wird ins Clipboard/UndoDoc gestellt, wird kein Broadcast gebraucht.
140 	// Nach Import wird CalcAfterLoad gerufen, dort Listening.
141 	if ( !(pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc()) )
142 	{
143 		pNewCell->StartListeningTo( pDocument );
144 		CellType eCellType = pNewCell->GetCellType();
145 		// Notizzelle entsteht beim Laden nur durch StartListeningCell,
146 		// ausloesende Formelzelle muss sowieso dirty sein.
147 		if ( !(pDocument->IsCalcingAfterLoad() && eCellType == CELLTYPE_NOTE) )
148 		{
149 			if ( eCellType == CELLTYPE_FORMULA )
150 				((ScFormulaCell*)pNewCell)->SetDirty();
151 			else
152 				pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED,
153 					ScAddress( nCol, nRow, nTab ), pNewCell ) );
154 		}
155 	}
156 }
157 
158 
159 void ScColumn::Insert( SCROW nRow, sal_uLong nNumberFormat, ScBaseCell* pCell )
160 {
161 	Insert(nRow, pCell);
162 	short eOldType = pDocument->GetFormatTable()->
163 						GetType( (sal_uLong)
164 							((SfxUInt32Item*)GetAttr( nRow, ATTR_VALUE_FORMAT ))->
165 								GetValue() );
166 	short eNewType = pDocument->GetFormatTable()->GetType(nNumberFormat);
167 	if (!pDocument->GetFormatTable()->IsCompatible(eOldType, eNewType))
168 		ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, (sal_uInt32) nNumberFormat) );
169 }
170 
171 
172 void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
173 {
174 	if (nCount + 1 > nLimit)
175 	{
176 		if (bDoubleAlloc)
177 		{
178 			if (nLimit < COLUMN_DELTA)
179 				nLimit = COLUMN_DELTA;
180 			else
181 			{
182 				nLimit *= 2;
183                 if ( nLimit > sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
184 					nLimit = MAXROWCOUNT;
185 			}
186 		}
187 		else
188 			nLimit += COLUMN_DELTA;
189 
190 		ColEntry* pNewItems = new ColEntry[nLimit];
191 		if (pItems)
192 		{
193 			memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
194 			delete[] pItems;
195 		}
196 		pItems = pNewItems;
197 	}
198 	pItems[nCount].pCell = pCell;
199 	pItems[nCount].nRow  = nRow;
200 	++nCount;
201 }
202 
203 
204 void ScColumn::Delete( SCROW nRow )
205 {
206 	SCSIZE	nIndex;
207 
208 	if (Search(nRow, nIndex))
209 	{
210 		ScBaseCell* pCell = pItems[nIndex].pCell;
211 		ScNoteCell* pNoteCell = new ScNoteCell;
212 		pItems[nIndex].pCell = pNoteCell;		// Dummy fuer Interpret
213 		pDocument->Broadcast( ScHint( SC_HINT_DYING,
214 			ScAddress( nCol, nRow, nTab ), pCell ) );
215         if ( SvtBroadcaster* pBC = pCell->ReleaseBroadcaster() )
216 		{
217             pNoteCell->TakeBroadcaster( pBC );
218 		}
219 		else
220 		{
221 			delete pNoteCell;
222 			--nCount;
223 			memmove( &pItems[nIndex], &pItems[nIndex + 1], (nCount - nIndex) * sizeof(ColEntry) );
224 			pItems[nCount].nRow = 0;
225 			pItems[nCount].pCell = NULL;
226 			//	Soll man hier den Speicher freigeben (delta)? Wird dann langsamer!
227 		}
228 		pCell->EndListeningTo( pDocument );
229 		pCell->Delete();
230 	}
231 }
232 
233 
234 void ScColumn::DeleteAtIndex( SCSIZE nIndex )
235 {
236 	ScBaseCell* pCell = pItems[nIndex].pCell;
237 	ScNoteCell* pNoteCell = new ScNoteCell;
238 	pItems[nIndex].pCell = pNoteCell;		// Dummy fuer Interpret
239 	pDocument->Broadcast( ScHint( SC_HINT_DYING,
240 		ScAddress( nCol, pItems[nIndex].nRow, nTab ), pCell ) );
241 	delete pNoteCell;
242 	--nCount;
243 	memmove( &pItems[nIndex], &pItems[nIndex + 1], (nCount - nIndex) * sizeof(ColEntry) );
244 	pItems[nCount].nRow = 0;
245 	pItems[nCount].pCell = NULL;
246 	pCell->EndListeningTo( pDocument );
247 	pCell->Delete();
248 }
249 
250 
251 void ScColumn::FreeAll()
252 {
253 	if (pItems)
254 	{
255 		for (SCSIZE i = 0; i < nCount; i++)
256 			pItems[i].pCell->Delete();
257 		delete[] pItems;
258 		pItems = NULL;
259 	}
260 	nCount = 0;
261 	nLimit = 0;
262 }
263 
264 
265 void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
266 {
267 	pAttrArray->DeleteRow( nStartRow, nSize );
268 
269 	if ( !pItems || !nCount )
270 		return ;
271 
272 	SCSIZE nFirstIndex;
273 	Search( nStartRow, nFirstIndex );
274 	if ( nFirstIndex >= nCount )
275 		return ;
276 
277 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
278 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
279 
280 	sal_Bool bFound=sal_False;
281 	SCROW nEndRow = nStartRow + nSize - 1;
282     SCSIZE nStartIndex = 0;
283     SCSIZE nEndIndex = 0;
284 	SCSIZE i;
285 
286 	for ( i = nFirstIndex; i < nCount && pItems[i].nRow <= nEndRow; i++ )
287 	{
288 		if (!bFound)
289 		{
290 			nStartIndex = i;
291 			bFound = sal_True;
292 		}
293 		nEndIndex = i;
294 
295 		ScBaseCell* pCell = pItems[i].pCell;
296 		SvtBroadcaster* pBC = pCell->GetBroadcaster();
297 		if (pBC)
298 		{
299 // gibt jetzt invalid reference, kein Aufruecken der direkten Referenzen
300 //			MoveListeners( *pBC, nRow+nSize );
301             pCell->DeleteBroadcaster();
302 			//	in DeleteRange werden leere Broadcaster geloescht
303 		}
304 	}
305 	if (bFound)
306 	{
307 		DeleteRange( nStartIndex, nEndIndex, IDF_CONTENTS );
308 		Search( nStartRow, i );
309 		if ( i >= nCount )
310 		{
311 			pDocument->SetAutoCalc( bOldAutoCalc );
312 			return ;
313 		}
314 	}
315 	else
316 		i = nFirstIndex;
317 
318 	ScAddress aAdr( nCol, 0, nTab );
319     ScHint aHint( SC_HINT_DATACHANGED, aAdr, NULL );    // only areas (ScBaseCell* == NULL)
320     ScAddress& rAddress = aHint.GetAddress();
321     // for sparse occupation use single broadcasts, not ranges
322     sal_Bool bSingleBroadcasts = (((pItems[nCount-1].nRow - pItems[i].nRow) /
323                 (nCount - i)) > 1);
324     if ( bSingleBroadcasts )
325     {
326         SCROW nLastBroadcast = MAXROW+1;
327         for ( ; i < nCount; i++ )
328         {
329             SCROW nOldRow = pItems[i].nRow;
330             // #43940# Aenderung Quelle broadcasten
331             rAddress.SetRow( nOldRow );
332             pDocument->AreaBroadcast( aHint );
333             SCROW nNewRow = (pItems[i].nRow -= nSize);
334             // #43940# Aenderung Ziel broadcasten
335             if ( nLastBroadcast != nNewRow )
336             {   // direkt aufeinanderfolgende nicht doppelt broadcasten
337                 rAddress.SetRow( nNewRow );
338                 pDocument->AreaBroadcast( aHint );
339             }
340             nLastBroadcast = nOldRow;
341             ScBaseCell* pCell = pItems[i].pCell;
342             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
343                 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
344         }
345     }
346     else
347     {
348         rAddress.SetRow( pItems[i].nRow );
349         ScRange aRange( rAddress );
350         aRange.aEnd.SetRow( pItems[nCount-1].nRow );
351         for ( ; i < nCount; i++ )
352         {
353             SCROW nNewRow = (pItems[i].nRow -= nSize);
354             ScBaseCell* pCell = pItems[i].pCell;
355             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
356                 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
357         }
358         pDocument->AreaBroadcastInRange( aRange, aHint );
359     }
360 
361 	pDocument->SetAutoCalc( bOldAutoCalc );
362 }
363 
364 
365 void ScColumn::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDelFlag )
366 {
367     /*  If caller specifies to not remove the note caption objects, all cells
368         have to forget the pointers to them. This is used e.g. while undoing a
369         "paste cells" operation, which removes the caption objects later in
370         drawing undo. */
371     bool bDeleteNote = (nDelFlag & IDF_NOTE) != 0;
372     bool bNoCaptions = (nDelFlag & IDF_NOCAPTIONS) != 0;
373     if (bDeleteNote && bNoCaptions)
374 		for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx )
375 			if ( ScPostIt* pNote = pItems[ nIdx ].pCell->GetNote() )
376 				pNote->ForgetCaption();
377 
378     // special simple mode if all contents are deleted and cells do not contain broadcasters
379 	bool bSimple = ((nDelFlag & IDF_CONTENTS) == IDF_CONTENTS);
380 	if (bSimple)
381 		for ( SCSIZE nIdx = nStartIndex; bSimple && (nIdx <= nEndIndex); ++nIdx )
382 			if (pItems[ nIdx ].pCell->GetBroadcaster())
383 				bSimple = false;
384 
385     ScHint aHint( SC_HINT_DYING, ScAddress( nCol, 0, nTab ), 0 );
386 
387     // cache all formula cells, they will be deleted at end of this function
388 	typedef ::std::vector< ScFormulaCell* > FormulaCellVector;
389 	FormulaCellVector aDelCells;
390     aDelCells.reserve( nEndIndex - nStartIndex + 1 );
391 
392     // simple deletion of the cell objects
393 	if (bSimple)
394 	{
395         // pNoteCell: dummy replacement for old cells, to prevent that interpreter uses old cell
396 		ScNoteCell* pNoteCell = new ScNoteCell;
397 		for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx )
398 		{
399 			ScBaseCell* pOldCell = pItems[ nIdx ].pCell;
400 			if (pOldCell->GetCellType() == CELLTYPE_FORMULA)
401             {
402                 // cache formula cell, will be deleted below
403 				aDelCells.push_back( static_cast< ScFormulaCell* >( pOldCell ) );
404             }
405 			else
406 			{
407 				// interpret in broadcast must not use the old cell
408 				pItems[ nIdx ].pCell = pNoteCell;
409                 aHint.GetAddress().SetRow( pItems[ nIdx ].nRow );
410                 aHint.SetCell( pOldCell );
411 				pDocument->Broadcast( aHint );
412 				pOldCell->Delete();
413 			}
414 		}
415 		delete pNoteCell;
416 		memmove( &pItems[nStartIndex], &pItems[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ColEntry) );
417 		nCount -= nEndIndex-nStartIndex+1;
418 	}
419 
420     // else: delete some contents of the cells
421 	else
422 	{
423 		SCSIZE j = nStartIndex;
424         for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx )
425 		{
426             // decide whether to delete the cell object according to passed flags
427 			bool bDelete = false;
428 			ScBaseCell* pOldCell = pItems[j].pCell;
429 			CellType eCellType = pOldCell->GetCellType();
430 			switch ( eCellType )
431 			{
432 				case CELLTYPE_VALUE:
433                 {
434                     sal_uInt16 nValFlags = nDelFlag & (IDF_DATETIME|IDF_VALUE);
435                     // delete values and dates?
436 					bDelete = nValFlags == (IDF_DATETIME|IDF_VALUE);
437                     // if not, decide according to cell number format
438 					if( !bDelete && (nValFlags != 0) )
439 					{
440 						sal_uLong nIndex = (sal_uLong)((SfxUInt32Item*)GetAttr( pItems[j].nRow, ATTR_VALUE_FORMAT ))->GetValue();
441 						short nType = pDocument->GetFormatTable()->GetType(nIndex);
442 						bool bIsDate = (nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME);
443                         bDelete = nValFlags == (bIsDate ? IDF_DATETIME : IDF_VALUE);
444 					}
445                 }
446                 break;
447 
448 				case CELLTYPE_STRING:
449 				case CELLTYPE_EDIT:
450                     bDelete = (nDelFlag & IDF_STRING) != 0;
451                 break;
452 
453 				case CELLTYPE_FORMULA:
454                     bDelete = (nDelFlag & IDF_FORMULA) != 0;
455                 break;
456 
457 				case CELLTYPE_NOTE:
458                     // do note delete note cell with broadcaster
459 					bDelete = bDeleteNote && !pOldCell->GetBroadcaster();
460                 break;
461 
462                 default:;   // added to avoid warnings
463 			}
464 
465 			if (bDelete)
466 			{
467                 // try to create a replacement note cell, if note or broadcaster exists
468 				ScNoteCell* pNoteCell = 0;
469 				if (eCellType != CELLTYPE_NOTE)
470 				{
471                     // do not rescue note if it has to be deleted according to passed flags
472 					ScPostIt* pNote = bDeleteNote ? 0 : pOldCell->ReleaseNote();
473                     // #i99844# do not release broadcaster from old cell, it still has to notify deleted content
474                     SvtBroadcaster* pBC = pOldCell->GetBroadcaster();
475                     if( pNote || pBC )
476                         pNoteCell = new ScNoteCell( pNote, pBC );
477 				}
478 
479                 // remove cell entry in cell item list
480 				SCROW nOldRow = pItems[j].nRow;
481 				if (pNoteCell)
482 				{
483                     // replace old cell with the replacement note cell
484 					pItems[j].pCell = pNoteCell;
485 					++j;
486 				}
487 				else
488 				{
489                     // remove the old cell from the cell item list
490 					--nCount;
491 					memmove( &pItems[j], &pItems[j + 1], (nCount - j) * sizeof(ColEntry) );
492 					pItems[nCount].nRow = 0;
493 					pItems[nCount].pCell = 0;
494 				}
495 
496                 // cache formula cells (will be deleted later), delete cell of other type
497 				if (eCellType == CELLTYPE_FORMULA)
498 				{
499 					aDelCells.push_back( static_cast< ScFormulaCell* >( pOldCell ) );
500 				}
501 				else
502 				{
503                     aHint.GetAddress().SetRow( nOldRow );
504                     aHint.SetCell( pOldCell );
505 					pDocument->Broadcast( aHint );
506                     // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by pNoteCell)
507                     pOldCell->ReleaseBroadcaster();
508 					pOldCell->Delete();
509 				}
510 			}
511 			else
512 			{
513                 // delete cell note
514 				if (bDeleteNote)
515 					pItems[j].pCell->DeleteNote();
516                 // cell not deleted, move index to next cell
517 				++j;
518 			}
519 		}
520 	}
521 
522     // *** delete all formula cells ***
523 
524 	// first, all cells stop listening, may save unneeded recalcualtions
525 	for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt )
526 		(*aIt)->EndListeningTo( pDocument );
527 
528     // #i101869# if the note cell with the broadcaster was deleted in EndListening,
529     // forget the pointer to the broadcaster
530     for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt )
531     {
532         SCSIZE nIndex;
533         if ( !Search( (*aIt)->aPos.Row(), nIndex ) )
534             (*aIt)->ReleaseBroadcaster();
535     }
536 
537     // broadcast SC_HINT_DYING for all cells and delete them
538 	for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt )
539 	{
540         aHint.SetAddress( (*aIt)->aPos );
541         aHint.SetCell( *aIt );
542 		pDocument->Broadcast( aHint );
543         // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by replacement note cell)
544         (*aIt)->ReleaseBroadcaster();
545 		(*aIt)->Delete();
546 	}
547 }
548 
549 
550 void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
551 {
552 	//	FreeAll darf hier nicht gerufen werden wegen Broadcastern
553 
554 	//	Attribute erst am Ende, damit vorher noch zwischen Zahlen und Datum
555 	//	unterschieden werden kann (#47901#)
556 
557     sal_uInt16 nContMask = IDF_CONTENTS;
558     //  IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
559     if( nDelFlag & IDF_NOTE )
560         nContMask |= IDF_NOCAPTIONS;
561     sal_uInt16 nContFlag = nDelFlag & nContMask;
562 
563 	if (pItems && nCount>0 && nContFlag)
564 	{
565 		if (nStartRow==0 && nEndRow==MAXROW)
566             DeleteRange( 0, nCount-1, nContFlag );
567 		else
568 		{
569 			sal_Bool bFound=sal_False;
570             SCSIZE nStartIndex = 0;
571             SCSIZE nEndIndex = 0;
572 			for (SCSIZE i = 0; i < nCount; i++)
573 				if ((pItems[i].nRow >= nStartRow) && (pItems[i].nRow <= nEndRow))
574 				{
575 					if (!bFound)
576 					{
577 						nStartIndex = i;
578 						bFound = sal_True;
579 					}
580 					nEndIndex = i;
581 				}
582 			if (bFound)
583                 DeleteRange( nStartIndex, nEndIndex, nContFlag );
584 		}
585 	}
586 
587 	if ( nDelFlag & IDF_EDITATTR )
588 	{
589 		DBG_ASSERT( nContFlag == 0, "DeleteArea: falsche Flags" );
590 		RemoveEditAttribs( nStartRow, nEndRow );
591 	}
592 
593 	//	Attribute erst hier
594 	if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB) pAttrArray->DeleteArea( nStartRow, nEndRow );
595 	else if ((nDelFlag & IDF_ATTRIB) != 0) pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
596 }
597 
598 
599 ScFormulaCell* ScColumn::CreateRefCell( ScDocument* pDestDoc, const ScAddress& rDestPos,
600 											SCSIZE nIndex, sal_uInt16 nFlags ) const
601 {
602 	sal_uInt16 nContFlags = nFlags & IDF_CONTENTS;
603 	if (!nContFlags)
604 		return NULL;
605 
606 	//	Testen, ob Zelle kopiert werden soll
607 	//	auch bei IDF_CONTENTS komplett, wegen Notes / Broadcastern
608 
609 	sal_Bool bMatch = sal_False;
610 	ScBaseCell* pCell = pItems[nIndex].pCell;
611 	CellType eCellType = pCell->GetCellType();
612 	switch ( eCellType )
613 	{
614 		case CELLTYPE_VALUE:
615 			{
616 				sal_uInt16 nValFlags = nFlags & (IDF_DATETIME|IDF_VALUE);
617 
618 				if ( nValFlags == (IDF_DATETIME|IDF_VALUE) )
619 					bMatch = sal_True;
620 				else if ( nValFlags )
621 				{
622 					sal_uLong nNumIndex = (sal_uLong)((SfxUInt32Item*)GetAttr(
623 									pItems[nIndex].nRow, ATTR_VALUE_FORMAT ))->GetValue();
624 					short nTyp = pDocument->GetFormatTable()->GetType(nNumIndex);
625 					if ((nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME))
626 						bMatch = ((nFlags & IDF_DATETIME) != 0);
627 					else
628 						bMatch = ((nFlags & IDF_VALUE) != 0);
629 				}
630 			}
631 			break;
632 		case CELLTYPE_STRING:
633 		case CELLTYPE_EDIT:		bMatch = ((nFlags & IDF_STRING) != 0); break;
634 		case CELLTYPE_FORMULA:	bMatch = ((nFlags & IDF_FORMULA) != 0); break;
635         default:
636         {
637             // added to avoid warnings
638         }
639 	}
640 	if (!bMatch)
641 		return NULL;
642 
643 
644 	//	Referenz einsetzen
645 	ScSingleRefData aRef;
646 	aRef.nCol = nCol;
647 	aRef.nRow = pItems[nIndex].nRow;
648 	aRef.nTab = nTab;
649 	aRef.InitFlags();							// -> alles absolut
650 	aRef.SetFlag3D(sal_True);
651 
652 	//!	3D(sal_False) und TabRel(sal_True), wenn die endgueltige Position auf der selben Tabelle ist?
653 	//!	(bei TransposeClip ist die Zielposition noch nicht bekannt)
654 
655 	aRef.CalcRelFromAbs( rDestPos );
656 
657 	ScTokenArray aArr;
658 	aArr.AddSingleReference( aRef );
659 
660 	return new ScFormulaCell( pDestDoc, rDestPos, &aArr );
661 }
662 
663 
664 //	rColumn = Quelle
665 //	nRow1, nRow2 = Zielposition
666 
667 void ScColumn::CopyFromClip(SCROW nRow1, SCROW nRow2, long nDy,
668 								sal_uInt16 nInsFlag, sal_Bool bAsLink, sal_Bool bSkipAttrForEmpty,
669 								ScColumn& rColumn)
670 {
671 	if ((nInsFlag & IDF_ATTRIB) != 0)
672 	{
673 		if ( bSkipAttrForEmpty )
674 		{
675 			//	copy only attributes for non-empty cells
676 			//	(notes are not counted as non-empty here, to match the content behavior)
677 
678 			SCSIZE nStartIndex;
679 			rColumn.Search( nRow1-nDy, nStartIndex );
680 			while ( nStartIndex < rColumn.nCount && rColumn.pItems[nStartIndex].nRow <= nRow2-nDy )
681 			{
682 				SCSIZE nEndIndex = nStartIndex;
683 				if ( rColumn.pItems[nStartIndex].pCell->GetCellType() != CELLTYPE_NOTE )
684 				{
685 					SCROW nStartRow = rColumn.pItems[nStartIndex].nRow;
686 					SCROW nEndRow = nStartRow;
687 
688 					//	find consecutive non-empty cells
689 
690 					while ( nEndRow < nRow2-nDy &&
691 							nEndIndex+1 < rColumn.nCount &&
692 							rColumn.pItems[nEndIndex+1].nRow == nEndRow+1 &&
693 							rColumn.pItems[nEndIndex+1].pCell->GetCellType() != CELLTYPE_NOTE )
694 					{
695 						++nEndIndex;
696 						++nEndRow;
697 					}
698 
699 					rColumn.pAttrArray->CopyAreaSafe( nStartRow+nDy, nEndRow+nDy, nDy, *pAttrArray );
700 				}
701 				nStartIndex = nEndIndex + 1;
702 			}
703 		}
704 		else
705 			rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
706 	}
707     if ((nInsFlag & IDF_CONTENTS) == 0)
708 		return;
709 
710 	if ( bAsLink && nInsFlag == IDF_ALL )
711 	{
712 		//	bei "alles" werden auch leere Zellen referenziert
713 		//!	IDF_ALL muss immer mehr Flags enthalten, als bei "Inhalte Einfuegen"
714 		//!	einzeln ausgewaehlt werden koennen!
715 
716 		Resize( nCount + static_cast<SCSIZE>(nRow2-nRow1+1) );
717 
718 		ScAddress aDestPos( nCol, 0, nTab );		// Row wird angepasst
719 
720 		//	Referenz erzeugen (Quell-Position)
721 		ScSingleRefData aRef;
722 		aRef.nCol = rColumn.nCol;
723 		//	nRow wird angepasst
724 		aRef.nTab = rColumn.nTab;
725 		aRef.InitFlags();							// -> alles absolut
726 		aRef.SetFlag3D(sal_True);
727 
728 		for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++)
729 		{
730 			aRef.nRow = nDestRow - nDy;				// Quell-Zeile
731 			aDestPos.SetRow( nDestRow );
732 
733 			aRef.CalcRelFromAbs( aDestPos );
734 			ScTokenArray aArr;
735 			aArr.AddSingleReference( aRef );
736 			Insert( nDestRow, new ScFormulaCell( pDocument, aDestPos, &aArr ) );
737 		}
738 
739 		return;
740 	}
741 
742 	SCSIZE nColCount = rColumn.nCount;
743 
744     // ignore IDF_FORMULA - "all contents but no formulas" results in the same number of cells
745 	if ((nInsFlag & ( IDF_CONTENTS & ~IDF_FORMULA )) == ( IDF_CONTENTS & ~IDF_FORMULA ) && nRow2-nRow1 >= 64)
746 	{
747         //! Always do the Resize from the outside, where the number of repetitions is known
748         //! (then it can be removed here)
749 
750 		SCSIZE nNew = nCount + nColCount;
751 		if ( nLimit < nNew )
752 			Resize( nNew );
753 	}
754 
755     // IDF_ADDNOTES must be passed without other content flags than IDF_NOTE
756     bool bAddNotes = (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES);
757 
758 	sal_Bool bAtEnd = sal_False;
759 	for (SCSIZE i = 0; i < nColCount && !bAtEnd; i++)
760 	{
761 		SCsROW nDestRow = rColumn.pItems[i].nRow + nDy;
762 		if ( nDestRow > (SCsROW) nRow2 )
763 			bAtEnd = sal_True;
764 		else if ( nDestRow >= (SCsROW) nRow1 )
765 		{
766 			//	rows at the beginning may be skipped if filtered rows are left out,
767 			//	nDestRow may be negative then
768 
769             ScAddress aDestPos( nCol, (SCROW)nDestRow, nTab );
770 
771             /*  #i102056# Paste from clipboard needs to paste the cell notes in
772                 a second pass. This must not overwrite the existing cells
773                 already copied to the destination position in the first pass.
774                 To indicate this special case, the modifier IDF_ADDNOTES is
775                 passed together with IDF_NOTE in nInsFlag. Of course, there is
776                 still the need to create a new cell, if there is no cell at the
777                 destination position at all. */
778             ScBaseCell* pAddNoteCell = bAddNotes ? GetCell( aDestPos.Row() ) : 0;
779             if (pAddNoteCell)
780             {
781                 // do nothing if source cell does not contain a note
782                 const ScBaseCell* pSourceCell = rColumn.pItems[i].pCell;
783                 const ScPostIt* pSourceNote = pSourceCell ? pSourceCell->GetNote() : 0;
784                 if (pSourceNote)
785                 {
786                     DBG_ASSERT( !pAddNoteCell->HasNote(), "ScColumn::CopyFromClip - unexpected note at destination cell" );
787                     bool bCloneCaption = (nInsFlag & IDF_NOCAPTIONS) == 0;
788                     // #i52342# if caption is cloned, the note must be constructed with the destination document
789                     ScAddress aSourcePos( rColumn.nCol, rColumn.pItems[i].nRow, rColumn.nTab );
790                     ScPostIt* pNewNote = pSourceNote->Clone( aSourcePos, *pDocument, aDestPos, bCloneCaption );
791                     pAddNoteCell->TakeNote( pNewNote );
792                 }
793             }
794             else
795             {
796                 ScBaseCell* pNewCell = bAsLink ?
797                     rColumn.CreateRefCell( pDocument, aDestPos, i, nInsFlag ) :
798                     rColumn.CloneCell( i, nInsFlag, *pDocument, aDestPos );
799                 if (pNewCell)
800                     Insert( aDestPos.Row(), pNewCell );
801             }
802 		}
803 	}
804 }
805 
806 
807 namespace {
808 
809 /** Helper for ScColumn::CloneCell - decides whether to clone a value cell depending on clone flags and number format. */
810 bool lclCanCloneValue( ScDocument& rDoc, const ScColumn& rCol, SCROW nRow, bool bCloneValue, bool bCloneDateTime )
811 {
812     // values and dates, or nothing to be cloned -> not needed to check number format
813     if( bCloneValue == bCloneDateTime )
814         return bCloneValue;
815 
816     // check number format of value cell
817     sal_uLong nNumIndex = (sal_uLong)((SfxUInt32Item*)rCol.GetAttr( nRow, ATTR_VALUE_FORMAT ))->GetValue();
818     short nTyp = rDoc.GetFormatTable()->GetType( nNumIndex );
819     bool bIsDateTime = (nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME);
820     return bIsDateTime ? bCloneDateTime : bCloneValue;
821 }
822 
823 } // namespace
824 
825 
826 ScBaseCell* ScColumn::CloneCell(SCSIZE nIndex, sal_uInt16 nFlags, ScDocument& rDestDoc, const ScAddress& rDestPos)
827 {
828     bool bCloneValue    = (nFlags & IDF_VALUE) != 0;
829     bool bCloneDateTime = (nFlags & IDF_DATETIME) != 0;
830     bool bCloneString   = (nFlags & IDF_STRING) != 0;
831     bool bCloneFormula  = (nFlags & IDF_FORMULA) != 0;
832     bool bCloneNote     = (nFlags & IDF_NOTE) != 0;
833 
834     ScBaseCell* pNew = 0;
835     ScBaseCell& rSource = *pItems[nIndex].pCell;
836     switch (rSource.GetCellType())
837 	{
838 		case CELLTYPE_NOTE:
839             // note will be cloned below
840         break;
841 
842         case CELLTYPE_STRING:
843 		case CELLTYPE_EDIT:
844             // note will be cloned below
845             if (bCloneString)
846                 pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos );
847         break;
848 
849 		case CELLTYPE_VALUE:
850             // note will be cloned below
851             if (lclCanCloneValue( *pDocument, *this, pItems[nIndex].nRow, bCloneValue, bCloneDateTime ))
852                 pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos );
853         break;
854 
855 		case CELLTYPE_FORMULA:
856             if (bCloneFormula)
857             {
858                 // note will be cloned below
859                 pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos );
860             }
861             else if ( (bCloneValue || bCloneDateTime || bCloneString) && !rDestDoc.IsUndo() )
862             {
863                 //  #48491# ins Undo-Dokument immer nur die Original-Zelle kopieren,
864                 //  aus Formeln keine Value/String-Zellen erzeugen
865                 ScFormulaCell& rForm = (ScFormulaCell&)rSource;
866                 sal_uInt16 nErr = rForm.GetErrCode();
867                 if ( nErr )
868                 {
869                     // error codes are cloned with values
870                     if (bCloneValue)
871                     {
872                         ScFormulaCell* pErrCell = new ScFormulaCell( &rDestDoc, rDestPos );
873                         pErrCell->SetErrCode( nErr );
874                         pNew = pErrCell;
875                     }
876                 }
877                 else if (rForm.IsValue())
878                 {
879                     if (lclCanCloneValue( *pDocument, *this, pItems[nIndex].nRow, bCloneValue, bCloneDateTime ))
880                     {
881                         double nVal = rForm.GetValue();
882                         pNew = new ScValueCell(nVal);
883                     }
884                 }
885                 else if (bCloneString)
886                 {
887                     String aString;
888                     rForm.GetString( aString );
889                     // #33224# do not clone empty string
890                     if (aString.Len() > 0)
891                     {
892                         if ( rForm.IsMultilineResult() )
893                         {
894                             pNew = new ScEditCell( aString, &rDestDoc );
895                         }
896                         else
897                         {
898                             pNew = new ScStringCell( aString );
899                         }
900                     }
901                 }
902             }
903         break;
904 
905         default: DBG_ERRORFILE( "ScColumn::CloneCell - unknown cell type" );
906 	}
907 
908     // clone the cell note
909     if (bCloneNote)
910     {
911         if (ScPostIt* pNote = rSource.GetNote())
912         {
913             bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == 0;
914             // #i52342# if caption is cloned, the note must be constructed with the destination document
915             ScAddress aOwnPos( nCol, pItems[nIndex].nRow, nTab );
916             ScPostIt* pNewNote = pNote->Clone( aOwnPos, rDestDoc, rDestPos, bCloneCaption );
917             if (!pNew)
918                 pNew = new ScNoteCell( pNewNote );
919             else
920                 pNew->TakeNote( pNewNote );
921         }
922     }
923 
924 	return pNew;
925 }
926 
927 
928 void ScColumn::MixMarked( const ScMarkData& rMark, sal_uInt16 nFunction,
929 							sal_Bool bSkipEmpty, ScColumn& rSrcCol )
930 {
931 	SCROW nRow1, nRow2;
932 
933 	if (rMark.IsMultiMarked())
934 	{
935 		ScMarkArrayIter aIter( rMark.GetArray()+nCol );
936 		while (aIter.Next( nRow1, nRow2 ))
937 			MixData( nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol );
938 	}
939 }
940 
941 
942 //	Ergebnis in rVal1
943 
944 sal_Bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
945 {
946 	sal_Bool bOk = sal_False;
947 	switch (nFunction)
948 	{
949 		case PASTE_ADD:
950 			bOk = SubTotal::SafePlus( rVal1, nVal2 );
951 			break;
952 		case PASTE_SUB:
953 			nVal2 = -nVal2;		//! geht das immer ohne Fehler?
954 			bOk = SubTotal::SafePlus( rVal1, nVal2 );
955 			break;
956 		case PASTE_MUL:
957 			bOk = SubTotal::SafeMult( rVal1, nVal2 );
958 			break;
959 		case PASTE_DIV:
960 			bOk = SubTotal::SafeDiv( rVal1, nVal2 );
961 			break;
962 	}
963 	return bOk;
964 }
965 
966 
967 void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
968 {
969 	rArr.AddOpCode(ocOpen);
970 
971 	ScTokenArray* pCode = pCell->GetCode();
972 	if (pCode)
973 	{
974         const formula::FormulaToken* pToken = pCode->First();
975 		while (pToken)
976 		{
977 			rArr.AddToken( *pToken );
978 			pToken = pCode->Next();
979 		}
980 	}
981 
982 	rArr.AddOpCode(ocClose);
983 }
984 
985 
986 void ScColumn::MixData( SCROW nRow1, SCROW nRow2,
987 							sal_uInt16 nFunction, sal_Bool bSkipEmpty,
988 							ScColumn& rSrcCol )
989 {
990 	SCSIZE nSrcCount = rSrcCol.nCount;
991 
992 	SCSIZE nIndex;
993 	Search( nRow1, nIndex );
994 
995 //	SCSIZE nSrcIndex = 0;
996 	SCSIZE nSrcIndex;
997 	rSrcCol.Search( nRow1, nSrcIndex );			//! Testen, ob Daten ganz vorne
998 
999 	SCROW nNextThis = MAXROW+1;
1000 	if ( nIndex < nCount )
1001 		nNextThis = pItems[nIndex].nRow;
1002 	SCROW nNextSrc = MAXROW+1;
1003 	if ( nSrcIndex < nSrcCount )
1004 		nNextSrc = rSrcCol.pItems[nSrcIndex].nRow;
1005 
1006 	while ( nNextThis <= nRow2 || nNextSrc <= nRow2 )
1007 	{
1008 		SCROW nRow = Min( nNextThis, nNextSrc );
1009 
1010 		ScBaseCell* pSrc = NULL;
1011 		ScBaseCell* pDest = NULL;
1012 		ScBaseCell* pNew = NULL;
1013 		sal_Bool bDelete = sal_False;
1014 
1015 		if ( nSrcIndex < nSrcCount && nNextSrc == nRow )
1016 			pSrc = rSrcCol.pItems[nSrcIndex].pCell;
1017 
1018 		if ( nIndex < nCount && nNextThis == nRow )
1019 			pDest = pItems[nIndex].pCell;
1020 
1021         DBG_ASSERT( pSrc || pDest, "Nanu ?" );
1022 
1023 		CellType eSrcType  = pSrc  ? pSrc->GetCellType()  : CELLTYPE_NONE;
1024 		CellType eDestType = pDest ? pDest->GetCellType() : CELLTYPE_NONE;
1025 
1026 		sal_Bool bSrcEmpty = ( eSrcType == CELLTYPE_NONE || eSrcType == CELLTYPE_NOTE );
1027 		sal_Bool bDestEmpty = ( eDestType == CELLTYPE_NONE || eDestType == CELLTYPE_NOTE );
1028 
1029 		if ( bSkipEmpty && bDestEmpty )		// Originalzelle wiederherstellen
1030 		{
1031 			if ( pSrc )						// war da eine Zelle?
1032 			{
1033                 pNew = pSrc->CloneWithoutNote( *pDocument );
1034 			}
1035 		}
1036 		else if ( nFunction )				// wirklich Rechenfunktion angegeben
1037 		{
1038 			double nVal1;
1039 			double nVal2;
1040 			if ( eSrcType == CELLTYPE_VALUE )
1041 				nVal1 = ((ScValueCell*)pSrc)->GetValue();
1042 			else
1043 				nVal1 = 0.0;
1044 			if ( eDestType == CELLTYPE_VALUE )
1045 				nVal2 = ((ScValueCell*)pDest)->GetValue();
1046 			else
1047 				nVal2 = 0.0;
1048 
1049 			//	leere Zellen werden als Werte behandelt
1050 
1051 			sal_Bool bSrcVal  = ( bSrcEmpty || eSrcType == CELLTYPE_VALUE );
1052 			sal_Bool bDestVal  = ( bDestEmpty || eDestType == CELLTYPE_VALUE );
1053 
1054 			sal_Bool bSrcText = ( eSrcType == CELLTYPE_STRING ||
1055 								eSrcType == CELLTYPE_EDIT );
1056 			sal_Bool bDestText = ( eDestType == CELLTYPE_STRING ||
1057 								eDestType == CELLTYPE_EDIT );
1058 
1059 			//	sonst bleibt nur Formel...
1060 
1061 			if ( bSrcEmpty && bDestEmpty )
1062 			{
1063 				//	beide leer -> nix
1064 			}
1065 			else if ( bSrcVal && bDestVal )
1066 			{
1067 				//	neuen Wert eintragen, oder Fehler bei Ueberlauf
1068 
1069 				sal_Bool bOk = lcl_DoFunction( nVal1, nVal2, nFunction );
1070 
1071 				if (bOk)
1072 					pNew = new ScValueCell( nVal1 );
1073 				else
1074 				{
1075 					ScFormulaCell* pFC = new ScFormulaCell( pDocument,
1076 												ScAddress( nCol, nRow, nTab ) );
1077 					pFC->SetErrCode( errNoValue );
1078 					//!	oder NOVALUE, dann auch in consoli,
1079 					//!	sonst in Interpreter::GetCellValue die Abfrage auf errNoValue raus
1080 					//!	(dann geht Stringzelle+Wertzelle nicht mehr)
1081 					pNew = pFC;
1082 				}
1083 			}
1084 			else if ( bSrcText || bDestText )
1085 			{
1086 				//	mit Texten wird nicht gerechnet - immer "alte" Zelle, also pSrc
1087 
1088 				if (pSrc)
1089                     pNew = pSrc->CloneWithoutNote( *pDocument );
1090 				else if (pDest)
1091 					bDelete = sal_True;
1092 			}
1093 			else
1094 			{
1095 				//	Kombination aus Wert und mindestens einer Formel -> Formel erzeugen
1096 
1097 				ScTokenArray aArr;
1098 
1099 				//	erste Zelle
1100 				if ( eSrcType == CELLTYPE_FORMULA )
1101 					lcl_AddCode( aArr, (ScFormulaCell*)pSrc );
1102 				else
1103 					aArr.AddDouble( nVal1 );
1104 
1105 				//	Operator
1106 				OpCode eOp = ocAdd;
1107 				switch ( nFunction )
1108 				{
1109 					case PASTE_ADD:	eOp = ocAdd; break;
1110 					case PASTE_SUB:	eOp = ocSub; break;
1111 					case PASTE_MUL:	eOp = ocMul; break;
1112 					case PASTE_DIV:	eOp = ocDiv; break;
1113 				}
1114 				aArr.AddOpCode(eOp);				// Funktion
1115 
1116 				//	zweite Zelle
1117 				if ( eDestType == CELLTYPE_FORMULA )
1118 					lcl_AddCode( aArr, (ScFormulaCell*)pDest );
1119 				else
1120 					aArr.AddDouble( nVal2 );
1121 
1122 				pNew = new ScFormulaCell( pDocument, ScAddress( nCol, nRow, nTab ), &aArr );
1123 			}
1124 		}
1125 
1126 
1127 		if ( pNew || bDelete )			// neues Ergebnis ?
1128 		{
1129 			if (pDest && !pNew)						// alte Zelle da ?
1130 			{
1131 				if ( pDest->GetBroadcaster() )
1132 					pNew = new ScNoteCell;			// Broadcaster uebernehmen
1133 				else
1134 					Delete(nRow);					// -> loeschen
1135 			}
1136 			if (pNew)
1137 				Insert(nRow, pNew);		// neue einfuegen
1138 
1139 			Search( nRow, nIndex );		// alles kann sich verschoben haben
1140 			if (pNew)
1141 				nNextThis = nRow;		// nIndex zeigt jetzt genau auf nRow
1142 			else
1143 				nNextThis = ( nIndex < nCount ) ? pItems[nIndex].nRow : MAXROW+1;
1144 		}
1145 
1146 		if ( nNextThis == nRow )
1147 		{
1148 			++nIndex;
1149 			nNextThis = ( nIndex < nCount ) ? pItems[nIndex].nRow : MAXROW+1;
1150 		}
1151 		if ( nNextSrc == nRow )
1152 		{
1153 			++nSrcIndex;
1154 			nNextSrc = ( nSrcIndex < nSrcCount ) ?
1155 							rSrcCol.pItems[nSrcIndex].nRow :
1156 							MAXROW+1;
1157 		}
1158 	}
1159 }
1160 
1161 
1162 ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
1163 {
1164 	return new ScAttrIterator( pAttrArray, nStartRow, nEndRow );
1165 }
1166 
1167 
1168 void ScColumn::StartAllListeners()
1169 {
1170 	if (pItems)
1171 		for (SCSIZE i = 0; i < nCount; i++)
1172 		{
1173 			ScBaseCell* pCell = pItems[i].pCell;
1174 			if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1175 			{
1176 				SCROW nRow = pItems[i].nRow;
1177 				((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
1178 				if ( nRow != pItems[i].nRow )
1179 					Search( nRow, i );		// Listener eingefuegt?
1180 			}
1181 		}
1182 }
1183 
1184 
1185 void ScColumn::StartNeededListeners()
1186 {
1187 	if (pItems)
1188     {
1189 		for (SCSIZE i = 0; i < nCount; i++)
1190 		{
1191 			ScBaseCell* pCell = pItems[i].pCell;
1192 			if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1193 			{
1194                 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
1195                 if (pFCell->NeedsListening())
1196                 {
1197                     SCROW nRow = pItems[i].nRow;
1198                     pFCell->StartListeningTo( pDocument );
1199                     if ( nRow != pItems[i].nRow )
1200                         Search( nRow, i );		// Listener eingefuegt?
1201                 }
1202 			}
1203 		}
1204     }
1205 }
1206 
1207 
1208 void ScColumn::BroadcastInArea( SCROW nRow1, SCROW nRow2 )
1209 {
1210 	if ( pItems )
1211 	{
1212         SCROW nRow;
1213         SCSIZE nIndex;
1214 		Search( nRow1, nIndex );
1215 		while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
1216 		{
1217 			ScBaseCell* pCell = pItems[nIndex].pCell;
1218 			if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1219 				((ScFormulaCell*)pCell)->SetDirty();
1220 			else
1221 				pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED,
1222 					ScAddress( nCol, nRow, nTab ), pCell ) );
1223 			nIndex++;
1224 		}
1225 	}
1226 }
1227 
1228 
1229 void ScColumn::StartListeningInArea( SCROW nRow1, SCROW nRow2 )
1230 {
1231 	if ( pItems )
1232 	{
1233         SCROW nRow;
1234         SCSIZE nIndex;
1235 		Search( nRow1, nIndex );
1236 		while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
1237 		{
1238 			ScBaseCell* pCell = pItems[nIndex].pCell;
1239 			if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1240 				((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
1241 			if ( nRow != pItems[nIndex].nRow )
1242 				Search( nRow, nIndex );		// durch Listening eingefuegt
1243 			nIndex++;
1244 		}
1245 	}
1246 }
1247 
1248 
1249 //	sal_True = Zahlformat gesetzt
1250 sal_Bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
1251                           formula::FormulaGrammar::AddressConvention eConv,
1252                           SvNumberFormatter* pLangFormatter, bool bDetectNumberFormat )
1253 {
1254 	sal_Bool bNumFmtSet = sal_False;
1255 	if (VALIDROW(nRow))
1256 	{
1257 		ScBaseCell* pNewCell = NULL;
1258 		sal_Bool bIsLoading = sal_False;
1259 		if (rString.Len() > 0)
1260 		{
1261 			double nVal;
1262             sal_uInt32 nIndex, nOldIndex = 0;
1263 			sal_Unicode cFirstChar;
1264             // #i110979# If a different NumberFormatter is passed in (pLangFormatter),
1265             // its formats aren't valid in the document.
1266             // Only use the language / LocaleDataWrapper from pLangFormatter,
1267             // always the document's number formatter for IsNumberFormat.
1268             SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
1269 			SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
1270 			if ( pDocSh )
1271 				bIsLoading = pDocSh->IsLoading();
1272 			// IsLoading bei ConvertFrom Import
1273 			if ( !bIsLoading )
1274 			{
1275 				nIndex = nOldIndex = GetNumberFormat( nRow );
1276 				if ( rString.Len() > 1
1277 						&& pFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT )
1278 					cFirstChar = rString.GetChar(0);
1279 				else
1280 					cFirstChar = 0;								// Text
1281 			}
1282 			else
1283 			{	// waehrend ConvertFrom Import gibt es keine gesetzten Formate
1284 				cFirstChar = rString.GetChar(0);
1285 			}
1286 
1287 			if ( cFirstChar == '=' )
1288 			{
1289 				if ( rString.Len() == 1 )						// = Text
1290 					pNewCell = new ScStringCell( rString );
1291 				else											// =Formel
1292 					pNewCell = new ScFormulaCell( pDocument,
1293                         ScAddress( nCol, nRow, nTabP ), rString,
1294                         formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_DEFAULT,
1295                             eConv), MM_NONE );
1296 			}
1297 			else if ( cFirstChar == '\'')						// 'Text
1298 				pNewCell = new ScStringCell( rString.Copy(1) );
1299 			else
1300 			{
1301 				sal_Bool bIsText = sal_False;
1302 				if ( bIsLoading )
1303 				{
1304 					if ( pItems && nCount )
1305 					{
1306 						String aStr;
1307 						SCSIZE i = nCount;
1308 						SCSIZE nStop = (i >= 3 ? i - 3 : 0);
1309 						// die letzten Zellen vergleichen, ob gleicher String
1310 						// und IsNumberFormat eingespart werden kann
1311 						do
1312 						{
1313 							i--;
1314 							ScBaseCell* pCell = pItems[i].pCell;
1315 							switch ( pCell->GetCellType() )
1316 							{
1317 								case CELLTYPE_STRING :
1318 									((ScStringCell*)pCell)->GetString( aStr );
1319 									if ( rString == aStr )
1320 										bIsText = sal_True;
1321 								break;
1322 								case CELLTYPE_NOTE :	// durch =Formel referenziert
1323 								break;
1324 								default:
1325 									if ( i == nCount - 1 )
1326 										i = 0;
1327 										// wahrscheinlich ganze Spalte kein String
1328 							}
1329 						} while ( i && i > nStop && !bIsText );
1330 					}
1331 					// nIndex fuer IsNumberFormat vorbelegen
1332 					if ( !bIsText )
1333 						nIndex = nOldIndex = pFormatter->GetStandardIndex();
1334 				}
1335 
1336                 do
1337                 {
1338                     if (bIsText)
1339                         break;
1340 
1341                     if (bDetectNumberFormat)
1342                     {
1343                         if ( pLangFormatter )
1344                         {
1345                             // for number detection: valid format index for selected language
1346                             nIndex = pFormatter->GetStandardIndex( pLangFormatter->GetLanguage() );
1347                         }
1348 
1349                         if (!pFormatter->IsNumberFormat(rString, nIndex, nVal))
1350                             break;
1351 
1352                         if ( pLangFormatter )
1353                         {
1354                             // convert back to the original language if a built-in format was detected
1355                             const SvNumberformat* pOldFormat = pFormatter->GetEntry( nOldIndex );
1356                             if ( pOldFormat )
1357                                 nIndex = pFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() );
1358                         }
1359 
1360                         pNewCell = new ScValueCell( nVal );
1361                         if ( nIndex != nOldIndex)
1362                         {
1363                             // #i22345# New behavior: Apply the detected number format only if
1364                             // the old one was the default number, date, time or boolean format.
1365                             // Exception: If the new format is boolean, always apply it.
1366 
1367                             sal_Bool bOverwrite = sal_False;
1368                             const SvNumberformat* pOldFormat = pFormatter->GetEntry( nOldIndex );
1369                             if ( pOldFormat )
1370                             {
1371                                 short nOldType = pOldFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1372                                 if ( nOldType == NUMBERFORMAT_NUMBER || nOldType == NUMBERFORMAT_DATE ||
1373                                      nOldType == NUMBERFORMAT_TIME || nOldType == NUMBERFORMAT_LOGICAL )
1374                                 {
1375                                     if ( nOldIndex == pFormatter->GetStandardFormat(
1376                                                         nOldType, pOldFormat->GetLanguage() ) )
1377                                     {
1378                                         bOverwrite = sal_True;      // default of these types can be overwritten
1379                                     }
1380                                 }
1381                             }
1382                             if ( !bOverwrite && pFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL )
1383                             {
1384                                 bOverwrite = sal_True;              // overwrite anything if boolean was detected
1385                             }
1386 
1387                             if ( bOverwrite )
1388                             {
1389                                 ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
1390                                     (sal_uInt32) nIndex) );
1391                                 bNumFmtSet = sal_True;
1392                             }
1393                         }
1394                     }
1395                     else
1396                     {
1397                         // Only check if the string is a regular number.
1398                         SvNumberFormatter* pLocaleSource = pLangFormatter ? pLangFormatter : pFormatter;
1399                         const LocaleDataWrapper* pLocale = pLocaleSource->GetLocaleData();
1400                         if (!pLocale)
1401                             break;
1402 
1403                         LocaleDataItem aLocaleItem = pLocale->getLocaleItem();
1404                         const OUString& rDecSep = aLocaleItem.decimalSeparator;
1405                         const OUString& rGroupSep = aLocaleItem.thousandSeparator;
1406                         if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1)
1407                             break;
1408 
1409                         sal_Unicode dsep = rDecSep.getStr()[0];
1410                         sal_Unicode gsep = rGroupSep.getStr()[0];
1411 
1412                         if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal))
1413                             break;
1414 
1415                         pNewCell = new ScValueCell(nVal);
1416                     }
1417                 }
1418                 while (false);
1419 
1420                 if (!pNewCell)
1421                     pNewCell = new ScStringCell(rString);
1422             }
1423         }
1424 
1425 		if ( bIsLoading && (!nCount || nRow > pItems[nCount-1].nRow) )
1426 		{	// Search einsparen und ohne Umweg ueber Insert, Listener aufbauen
1427 			// und Broadcast kommt eh erst nach dem Laden
1428 			if ( pNewCell )
1429 				Append( nRow, pNewCell );
1430 		}
1431 		else
1432 		{
1433 			SCSIZE i;
1434 			if (Search(nRow, i))
1435 			{
1436 				ScBaseCell* pOldCell = pItems[i].pCell;
1437 				ScPostIt* pNote = pOldCell->ReleaseNote();
1438                 SvtBroadcaster* pBC = pOldCell->ReleaseBroadcaster();
1439 				if (pNewCell || pNote || pBC)
1440 				{
1441 					if (pNewCell)
1442                         pNewCell->TakeNote( pNote );
1443                     else
1444 						pNewCell = new ScNoteCell( pNote );
1445 					if (pBC)
1446 					{
1447                         pNewCell->TakeBroadcaster(pBC);
1448 						pLastFormulaTreeTop = 0;	// Err527 Workaround
1449 					}
1450 
1451 					if ( pOldCell->GetCellType() == CELLTYPE_FORMULA )
1452 					{
1453 						pOldCell->EndListeningTo( pDocument );
1454 						// falls in EndListening NoteCell in gleicher Col zerstoert
1455 						if ( i >= nCount || pItems[i].nRow != nRow )
1456 							Search(nRow, i);
1457 					}
1458 					pOldCell->Delete();
1459 					pItems[i].pCell = pNewCell;			// ersetzen
1460 					if ( pNewCell->GetCellType() == CELLTYPE_FORMULA )
1461 					{
1462 						pNewCell->StartListeningTo( pDocument );
1463 						((ScFormulaCell*)pNewCell)->SetDirty();
1464 					}
1465 					else
1466 						pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED,
1467                             ScAddress( nCol, nRow, nTabP ), pNewCell ) );
1468 				}
1469 				else
1470 				{
1471 					DeleteAtIndex(i);					// loeschen und Broadcast
1472 				}
1473 			}
1474 			else if (pNewCell)
1475 			{
1476 				Insert(nRow, pNewCell);					// neu eintragen und Broadcast
1477 			}
1478 		}
1479 
1480 		//	hier keine Formate mehr fuer Formeln setzen!
1481 		//	(werden bei der Ausgabe abgefragt)
1482 
1483 	}
1484 	return bNumFmtSet;
1485 }
1486 
1487 
1488 void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, TypedScStrCollection& rStrings, bool& rHasDates)
1489 {
1490     bool bHasDates = false;
1491 	SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
1492 	String aString;
1493     SCROW nRow = 0;
1494 	SCSIZE nIndex;
1495 
1496 	Search( nStartRow, nIndex );
1497 
1498 	while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False )
1499 	{
1500 		ScBaseCell*			 pCell	  = pItems[nIndex].pCell;
1501 		TypedStrData*		 pData;
1502 		sal_uLong				 nFormat  = GetNumberFormat( nRow );
1503 
1504 		ScCellFormat::GetInputString( pCell, nFormat, aString, *pFormatter );
1505 
1506 		if ( pDocument->HasStringData( nCol, nRow, nTab ) )
1507 			pData = new TypedStrData( aString );
1508 		else
1509 		{
1510 			double nValue;
1511 
1512 			switch ( pCell->GetCellType() )
1513 			{
1514 				case CELLTYPE_VALUE:
1515 					nValue = ((ScValueCell*)pCell)->GetValue();
1516 					break;
1517 
1518 				case CELLTYPE_FORMULA:
1519 					nValue = ((ScFormulaCell*)pCell)->GetValue();
1520 					break;
1521 
1522 				default:
1523 					nValue = 0.0;
1524 			}
1525 
1526             if (pFormatter)
1527             {
1528                 short nType = pFormatter->GetType(nFormat);
1529                 if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME))
1530                 {
1531                     // special case for date values.  Disregard the time
1532                     // element if the number format is of date type.
1533                     nValue = ::rtl::math::approxFloor(nValue);
1534                     bHasDates = true;
1535                 }
1536             }
1537 
1538 			pData = new TypedStrData( aString, nValue, SC_STRTYPE_VALUE );
1539 		}
1540 #if 0 // DR
1541 		ScPostIt aCellNote( ScPostIt::UNINITIALIZED );
1542 		// Hide visible notes during Filtering.
1543 		if(pCell->GetNote(aCellNote) && aCellNote.IsCaptionShown())
1544 		{
1545 		    ScDetectiveFunc( pDocument, nTab ).HideComment( nCol, nRow );
1546 		    aCellNote.SetShown( false );
1547 		    pCell->SetNote(aCellNote);
1548 		}
1549 #endif
1550 
1551 		if ( !rStrings.Insert( pData ) )
1552 			delete pData;								// doppelt
1553 
1554 		++nIndex;
1555 	}
1556 
1557     rHasDates = bHasDates;
1558 }
1559 
1560 //
1561 //	GetDataEntries - Strings aus zusammenhaengendem Bereich um nRow
1562 //
1563 
1564 //	DATENT_MAX		- max. Anzahl Eintrage in Liste fuer Auto-Eingabe
1565 //	DATENT_SEARCH	- max. Anzahl Zellen, die durchsucht werden - neu: nur Strings zaehlen
1566 #define DATENT_MAX		200
1567 #define DATENT_SEARCH	2000
1568 
1569 
1570 sal_Bool ScColumn::GetDataEntries(SCROW nStartRow, TypedScStrCollection& rStrings, sal_Bool bLimit)
1571 {
1572 	sal_Bool bFound = sal_False;
1573 	SCSIZE nThisIndex;
1574 	sal_Bool bThisUsed = Search( nStartRow, nThisIndex );
1575 	String aString;
1576 	sal_uInt16 nCells = 0;
1577 
1578 	//	Die Beschraenkung auf angrenzende Zellen (ohne Luecken) ist nicht mehr gewollt
1579 	//	(Featurekommission zur 5.1), stattdessen abwechselnd nach oben und unten suchen,
1580 	//	damit naheliegende Zellen wenigstens zuerst gefunden werden.
1581 	//!	Abstaende der Zeilennummern vergleichen? (Performance??)
1582 
1583 	SCSIZE nUpIndex = nThisIndex;		// zeigt hinter die Zelle
1584 	SCSIZE nDownIndex = nThisIndex;		// zeigt auf die Zelle
1585 	if (bThisUsed)
1586 		++nDownIndex;					// Startzelle ueberspringen
1587 
1588 	while ( nUpIndex || nDownIndex < nCount )
1589 	{
1590 		if ( nUpIndex )					// nach oben
1591 		{
1592 			ScBaseCell* pCell = pItems[nUpIndex-1].pCell;
1593 			CellType eType = pCell->GetCellType();
1594 			if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)		// nur Strings interessieren
1595 			{
1596 				if (eType == CELLTYPE_STRING)
1597 					((ScStringCell*)pCell)->GetString(aString);
1598 				else
1599 					((ScEditCell*)pCell)->GetString(aString);
1600 
1601 				TypedStrData* pData = new TypedStrData(aString);
1602 				if ( !rStrings.Insert( pData ) )
1603 					delete pData;											// doppelt
1604 				else if ( bLimit && rStrings.GetCount() >= DATENT_MAX )
1605 					break;													// Maximum erreicht
1606 				bFound = sal_True;
1607 
1608 				if ( bLimit )
1609 					if (++nCells >= DATENT_SEARCH)
1610 						break;									// genug gesucht
1611 			}
1612 			--nUpIndex;
1613 		}
1614 
1615 		if ( nDownIndex < nCount )		// nach unten
1616 		{
1617 			ScBaseCell* pCell = pItems[nDownIndex].pCell;
1618 			CellType eType = pCell->GetCellType();
1619 			if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)		// nur Strings interessieren
1620 			{
1621 				if (eType == CELLTYPE_STRING)
1622 					((ScStringCell*)pCell)->GetString(aString);
1623 				else
1624 					((ScEditCell*)pCell)->GetString(aString);
1625 
1626 				TypedStrData* pData = new TypedStrData(aString);
1627 				if ( !rStrings.Insert( pData ) )
1628 					delete pData;											// doppelt
1629 				else if ( bLimit && rStrings.GetCount() >= DATENT_MAX )
1630 					break;													// Maximum erreicht
1631 				bFound = sal_True;
1632 
1633 				if ( bLimit )
1634 					if (++nCells >= DATENT_SEARCH)
1635 						break;									// genug gesucht
1636 			}
1637 			++nDownIndex;
1638 		}
1639 	}
1640 
1641 	return bFound;
1642 }
1643 
1644 #undef DATENT_MAX
1645 #undef DATENT_SEARCH
1646 
1647 
1648 void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
1649 {
1650 	ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
1651 	SCROW nTop = -1;
1652 	SCROW nBottom = -1;
1653 	SCSIZE nIndex;
1654 	const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
1655 	while (pPattern)
1656 	{
1657 		const ScProtectionAttr* pAttr = (const ScProtectionAttr*)&pPattern->GetItem(ATTR_PROTECTION);
1658 		if ( pAttr->GetHideCell() )
1659 			DeleteArea( nTop, nBottom, IDF_CONTENTS );
1660 		else if ( pAttr->GetHideFormula() )
1661 		{
1662 			Search( nTop, nIndex );
1663 			while ( nIndex<nCount && pItems[nIndex].nRow<=nBottom )
1664 			{
1665 				if ( pItems[nIndex].pCell->GetCellType() == CELLTYPE_FORMULA )
1666 				{
1667 					ScFormulaCell* pFormula = (ScFormulaCell*)pItems[nIndex].pCell;
1668 					if (pFormula->IsValue())
1669 					{
1670 						double nVal = pFormula->GetValue();
1671 						pItems[nIndex].pCell = new ScValueCell( nVal );
1672 					}
1673 					else
1674 					{
1675 						String aString;
1676 						pFormula->GetString(aString);
1677 						pItems[nIndex].pCell = new ScStringCell( aString );
1678 					}
1679 					delete pFormula;
1680 				}
1681 				++nIndex;
1682 			}
1683 		}
1684 
1685 		pPattern = aAttrIter.Next( nTop, nBottom );
1686 	}
1687 }
1688 
1689 
1690 void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError)
1691 {
1692 	if (VALIDROW(nRow))
1693 	{
1694 		ScFormulaCell* pCell = new ScFormulaCell
1695 			( pDocument, ScAddress( nCol, nRow, nTab ) );
1696 		pCell->SetErrCode( nError );
1697 		Insert( nRow, pCell );
1698 	}
1699 }
1700 
1701 
1702 void ScColumn::SetValue( SCROW nRow, const double& rVal)
1703 {
1704 	if (VALIDROW(nRow))
1705 	{
1706 		ScBaseCell* pCell = new ScValueCell(rVal);
1707 		Insert( nRow, pCell );
1708 	}
1709 }
1710 
1711 
1712 void ScColumn::GetString( SCROW nRow, String& rString ) const
1713 {
1714 	SCSIZE	nIndex;
1715 	Color* pColor;
1716 	if (Search(nRow, nIndex))
1717 	{
1718 		ScBaseCell* pCell = pItems[nIndex].pCell;
1719 		if (pCell->GetCellType() != CELLTYPE_NOTE)
1720 		{
1721 			sal_uLong nFormat = GetNumberFormat( nRow );
1722 			ScCellFormat::GetString( pCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()) );
1723 		}
1724 		else
1725 			rString.Erase();
1726 	}
1727 	else
1728 		rString.Erase();
1729 }
1730 
1731 
1732 void ScColumn::GetInputString( SCROW nRow, String& rString ) const
1733 {
1734 	SCSIZE	nIndex;
1735 	if (Search(nRow, nIndex))
1736 	{
1737 		ScBaseCell* pCell = pItems[nIndex].pCell;
1738 		if (pCell->GetCellType() != CELLTYPE_NOTE)
1739 		{
1740 			sal_uLong nFormat = GetNumberFormat( nRow );
1741 			ScCellFormat::GetInputString( pCell, nFormat, rString, *(pDocument->GetFormatTable()) );
1742 		}
1743 		else
1744 			rString.Erase();
1745 	}
1746 	else
1747 		rString.Erase();
1748 }
1749 
1750 
1751 double ScColumn::GetValue( SCROW nRow ) const
1752 {
1753 	SCSIZE	nIndex;
1754 	if (Search(nRow, nIndex))
1755 	{
1756 		ScBaseCell* pCell = pItems[nIndex].pCell;
1757 		switch (pCell->GetCellType())
1758 		{
1759 			case CELLTYPE_VALUE:
1760 				return ((ScValueCell*)pCell)->GetValue();
1761 //                break;
1762 			case CELLTYPE_FORMULA:
1763 				{
1764 					if (((ScFormulaCell*)pCell)->IsValue())
1765 						return ((ScFormulaCell*)pCell)->GetValue();
1766 					else
1767 						return 0.0;
1768 				}
1769 //                break;
1770 			default:
1771 				return 0.0;
1772 //                break;
1773 		}
1774 	}
1775 	return 0.0;
1776 }
1777 
1778 
1779 void ScColumn::GetFormula( SCROW nRow, String& rFormula, sal_Bool ) const
1780 {
1781 	SCSIZE	nIndex;
1782 	if (Search(nRow, nIndex))
1783 	{
1784 		ScBaseCell* pCell = pItems[nIndex].pCell;
1785 		if (pCell->GetCellType() == CELLTYPE_FORMULA)
1786 			((ScFormulaCell*)pCell)->GetFormula( rFormula );
1787 		else
1788 			rFormula.Erase();
1789 	}
1790 	else
1791 		rFormula.Erase();
1792 }
1793 
1794 
1795 CellType ScColumn::GetCellType( SCROW nRow ) const
1796 {
1797 	SCSIZE	nIndex;
1798 	if (Search(nRow, nIndex))
1799 		return pItems[nIndex].pCell->GetCellType();
1800 	return CELLTYPE_NONE;
1801 }
1802 
1803 
1804 sal_uInt16 ScColumn::GetErrCode( SCROW nRow ) const
1805 {
1806 	SCSIZE	nIndex;
1807 	if (Search(nRow, nIndex))
1808 	{
1809 		ScBaseCell* pCell = pItems[nIndex].pCell;
1810 		if (pCell->GetCellType() == CELLTYPE_FORMULA)
1811 			return ((ScFormulaCell*)pCell)->GetErrCode();
1812 	}
1813 	return 0;
1814 }
1815 
1816 
1817 sal_Bool ScColumn::HasStringData( SCROW nRow ) const
1818 {
1819 	SCSIZE	nIndex;
1820 	if (Search(nRow, nIndex))
1821 		return (pItems[nIndex].pCell)->HasStringData();
1822 	return sal_False;
1823 }
1824 
1825 
1826 sal_Bool ScColumn::HasValueData( SCROW nRow ) const
1827 {
1828 	SCSIZE	nIndex;
1829 	if (Search(nRow, nIndex))
1830 		return (pItems[nIndex].pCell)->HasValueData();
1831 	return sal_False;
1832 }
1833 
1834 sal_Bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
1835 {
1836 	//	sal_True, wenn String- oder Editzellen im Bereich
1837 
1838 	if ( pItems )
1839 	{
1840 		SCSIZE nIndex;
1841 		Search( nStartRow, nIndex );
1842 		while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
1843 		{
1844 			CellType eType = pItems[nIndex].pCell->GetCellType();
1845 			if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
1846 				return sal_True;
1847 			++nIndex;
1848 		}
1849 	}
1850 	return sal_False;
1851 }
1852 
1853 
1854 ScPostIt* ScColumn::GetNote( SCROW nRow )
1855 {
1856 	SCSIZE nIndex;
1857 	return Search( nRow, nIndex ) ? pItems[ nIndex ].pCell->GetNote() : 0;
1858 }
1859 
1860 
1861 void ScColumn::TakeNote( SCROW nRow, ScPostIt* pNote )
1862 {
1863 	SCSIZE nIndex;
1864 	if( Search( nRow, nIndex ) )
1865 		pItems[ nIndex ].pCell->TakeNote( pNote );
1866     else
1867         Insert( nRow, new ScNoteCell( pNote ) );
1868 }
1869 
1870 
1871 ScPostIt* ScColumn::ReleaseNote( SCROW nRow )
1872 {
1873     ScPostIt* pNote = 0;
1874 	SCSIZE nIndex;
1875 	if( Search( nRow, nIndex ) )
1876 	{
1877 		ScBaseCell* pCell = pItems[ nIndex ].pCell;
1878         pNote = pCell->ReleaseNote();
1879 		if( (pCell->GetCellType() == CELLTYPE_NOTE) && !pCell->GetBroadcaster() )
1880 			DeleteAtIndex( nIndex );
1881 	}
1882     return pNote;
1883 }
1884 
1885 
1886 void ScColumn::DeleteNote( SCROW nRow )
1887 {
1888     delete ReleaseNote( nRow );
1889 }
1890 
1891 
1892 sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const
1893 {
1894 	sal_Int32 nStringLen = 0;
1895 	if ( pItems )
1896 	{
1897 		String aString;
1898         rtl::OString aOString;
1899         bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet);
1900 		SvNumberFormatter* pNumFmt = pDocument->GetFormatTable();
1901         SCSIZE nIndex;
1902         SCROW nRow;
1903 		Search( nRowStart, nIndex );
1904 		while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRowEnd )
1905 		{
1906 			ScBaseCell* pCell = pItems[nIndex].pCell;
1907 			if ( pCell->GetCellType() != CELLTYPE_NOTE )
1908 			{
1909 				Color* pColor;
1910 				sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr(
1911 					nRow, ATTR_VALUE_FORMAT ))->GetValue();
1912 				ScCellFormat::GetString( pCell, nFormat, aString, &pColor,
1913 					*pNumFmt );
1914                 sal_Int32 nLen;
1915                 if (bIsOctetTextEncoding)
1916                 {
1917                     rtl::OUString aOUString( aString);
1918                     if (!aOUString.convertToString( &aOString, eCharSet,
1919                                 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1920                                 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
1921                     {
1922                         // TODO: anything? this is used by the dBase export filter
1923                         // that throws an error anyway, but in case of another
1924                         // context we might want to indicate a conversion error
1925                         // early.
1926                     }
1927                     nLen = aOString.getLength();
1928                 }
1929                 else
1930                     nLen = aString.Len() * sizeof(sal_Unicode);
1931 				if ( nStringLen < nLen)
1932 					nStringLen = nLen;
1933 			}
1934 			nIndex++;
1935 		}
1936 	}
1937 	return nStringLen;
1938 }
1939 
1940 
1941 xub_StrLen ScColumn::GetMaxNumberStringLen(
1942     sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
1943 {
1944     xub_StrLen nStringLen = 0;
1945     nPrecision = pDocument->GetDocOptions().GetStdPrecision();
1946     if ( nPrecision == SvNumberFormatter::UNLIMITED_PRECISION )
1947         // In case of unlimited precision, use 2 instead.
1948         nPrecision = 2;
1949 
1950     if ( pItems )
1951     {
1952         String aString;
1953         SvNumberFormatter* pNumFmt = pDocument->GetFormatTable();
1954         SCSIZE nIndex;
1955         SCROW nRow;
1956         Search( nRowStart, nIndex );
1957         while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRowEnd )
1958         {
1959             ScBaseCell* pCell = pItems[nIndex].pCell;
1960             CellType eType = pCell->GetCellType();
1961             if ( eType == CELLTYPE_VALUE || (eType == CELLTYPE_FORMULA
1962                     && ((ScFormulaCell*)pCell)->IsValue()) )
1963             {
1964                 sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr(
1965                     nRow, ATTR_VALUE_FORMAT ))->GetValue();
1966                 ScCellFormat::GetInputString( pCell, nFormat, aString, *pNumFmt );
1967                 xub_StrLen nLen = aString.Len();
1968                 if ( nLen )
1969                 {
1970                     if ( nFormat )
1971                     {   // more decimals than standard?
1972                         sal_uInt16 nPrec = pNumFmt->GetFormatPrecision( nFormat );
1973                         if ( nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > nPrecision )
1974                             nPrecision = nPrec;
1975                     }
1976                     if ( nPrecision )
1977                     {   // less than nPrecision in string => widen it
1978                         // more => shorten it
1979                         String aSep = pNumFmt->GetFormatDecimalSep( nFormat );
1980                         xub_StrLen nTmp = aString.Search( aSep );
1981                         if ( nTmp == STRING_NOTFOUND )
1982                             nLen += nPrecision + aSep.Len();
1983                         else
1984                         {
1985                             nTmp = aString.Len() - (nTmp + aSep.Len());
1986                             if ( nTmp != nPrecision )
1987                                 nLen += nPrecision - nTmp;
1988                                 // nPrecision > nTmp : nLen + Diff
1989                                 // nPrecision < nTmp : nLen - Diff
1990                         }
1991                     }
1992                     if ( nStringLen < nLen )
1993                         nStringLen = nLen;
1994                 }
1995             }
1996             nIndex++;
1997         }
1998     }
1999     return nStringLen;
2000 }
2001 
2002