xref: /trunk/main/sc/source/core/data/column3.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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