1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: column3.cxx,v $
10 * $Revision: 1.27.128.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
33 // INCLUDE ---------------------------------------------------------------
37 #include <sfx2/objsh.hxx>
38 #include <svtools/zforlist.hxx>
39 #include <svtools/zformat.hxx>
41 #include "scitems.hxx"
44 #include "document.hxx"
45 #include "attarray.hxx"
46 #include "patattr.hxx"
47 #include "cellform.hxx"
48 #include "collect.hxx"
49 #include "formula/errorcodes.hxx"
50 #include "formula/token.hxx"
52 #include "docoptio.hxx" // GetStdPrecision fuer GetMaxNumberStringLen
53 #include "subtotal.hxx"
54 #include "markdata.hxx"
55 #include "detfunc.hxx" // fuer Notizen bei DeleteRange
57 #include "stringutil.hxx"
58 #include "docpool.hxx"
60 #include <com/sun/star/i18n/LocaleDataItem.hpp>
62 using ::com::sun::star::i18n::LocaleDataItem
;
63 using ::rtl::OUString
;
64 using ::rtl::OUStringBuffer
;
67 extern const ScFormulaCell
* pLastFormulaTreeTop
; // in cellform.cxx
68 using namespace formula
;
69 // STATIC DATA -----------------------------------------------------------
71 BOOL
ScColumn::bDoubleAlloc
= FALSE
; // fuer Import: Groesse beim Allozieren verdoppeln
74 void ScColumn::Insert( SCROW nRow
, ScBaseCell
* pNewCell
)
76 BOOL bIsAppended
= FALSE
;
77 if (pItems
&& nCount
>0)
79 if (pItems
[nCount
-1].nRow
< nRow
)
81 Append(nRow
, pNewCell
);
88 if (Search(nRow
, nIndex
))
90 ScBaseCell
* pOldCell
= pItems
[nIndex
].pCell
;
92 // move broadcaster and note to new cell, if not existing in new cell
93 if (pOldCell
->HasBroadcaster() && !pNewCell
->HasBroadcaster())
94 pNewCell
->TakeBroadcaster( pOldCell
->ReleaseBroadcaster() );
95 if (pOldCell
->HasNote() && !pNewCell
->HasNote())
96 pNewCell
->TakeNote( pOldCell
->ReleaseNote() );
98 if ( pOldCell
->GetCellType() == CELLTYPE_FORMULA
&& !pDocument
->IsClipOrUndo() )
100 pOldCell
->EndListeningTo( pDocument
);
101 // falls in EndListening NoteCell in gleicher Col zerstoert
102 if ( nIndex
>= nCount
|| pItems
[nIndex
].nRow
!= nRow
)
103 Search(nRow
, nIndex
);
106 pItems
[nIndex
].pCell
= pNewCell
;
110 if (nCount
+ 1 > nLimit
)
114 if (nLimit
< COLUMN_DELTA
)
115 nLimit
= COLUMN_DELTA
;
119 if ( nLimit
> sal::static_int_cast
<SCSIZE
>(MAXROWCOUNT
) )
120 nLimit
= MAXROWCOUNT
;
124 nLimit
+= COLUMN_DELTA
;
126 ColEntry
* pNewItems
= new ColEntry
[nLimit
];
129 memmove( pNewItems
, pItems
, nCount
* sizeof(ColEntry
) );
134 memmove( &pItems
[nIndex
+ 1], &pItems
[nIndex
], (nCount
- nIndex
) * sizeof(ColEntry
) );
135 pItems
[nIndex
].pCell
= pNewCell
;
136 pItems
[nIndex
].nRow
= nRow
;
140 // Bei aus Clipboard sind hier noch falsche (alte) Referenzen!
141 // Werden in CopyBlockFromClip per UpdateReference umgesetzt,
142 // danach StartListeningFromClip und BroadcastFromClip gerufen.
143 // Wird ins Clipboard/UndoDoc gestellt, wird kein Broadcast gebraucht.
144 // Nach Import wird CalcAfterLoad gerufen, dort Listening.
145 if ( !(pDocument
->IsClipOrUndo() || pDocument
->IsInsertingFromOtherDoc()) )
147 pNewCell
->StartListeningTo( pDocument
);
148 CellType eCellType
= pNewCell
->GetCellType();
149 // Notizzelle entsteht beim Laden nur durch StartListeningCell,
150 // ausloesende Formelzelle muss sowieso dirty sein.
151 if ( !(pDocument
->IsCalcingAfterLoad() && eCellType
== CELLTYPE_NOTE
) )
153 if ( eCellType
== CELLTYPE_FORMULA
)
154 ((ScFormulaCell
*)pNewCell
)->SetDirty();
156 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
,
157 ScAddress( nCol
, nRow
, nTab
), pNewCell
) );
163 void ScColumn::Insert( SCROW nRow
, ULONG nNumberFormat
, ScBaseCell
* pCell
)
166 short eOldType
= pDocument
->GetFormatTable()->
168 ((SfxUInt32Item
*)GetAttr( nRow
, ATTR_VALUE_FORMAT
))->
170 short eNewType
= pDocument
->GetFormatTable()->GetType(nNumberFormat
);
171 if (!pDocument
->GetFormatTable()->IsCompatible(eOldType
, eNewType
))
172 ApplyAttr( nRow
, SfxUInt32Item( ATTR_VALUE_FORMAT
, (UINT32
) nNumberFormat
) );
176 void ScColumn::Append( SCROW nRow
, ScBaseCell
* pCell
)
178 if (nCount
+ 1 > nLimit
)
182 if (nLimit
< COLUMN_DELTA
)
183 nLimit
= COLUMN_DELTA
;
187 if ( nLimit
> sal::static_int_cast
<SCSIZE
>(MAXROWCOUNT
) )
188 nLimit
= MAXROWCOUNT
;
192 nLimit
+= COLUMN_DELTA
;
194 ColEntry
* pNewItems
= new ColEntry
[nLimit
];
197 memmove( pNewItems
, pItems
, nCount
* sizeof(ColEntry
) );
202 pItems
[nCount
].pCell
= pCell
;
203 pItems
[nCount
].nRow
= nRow
;
208 void ScColumn::Delete( SCROW nRow
)
212 if (Search(nRow
, nIndex
))
214 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
215 ScNoteCell
* pNoteCell
= new ScNoteCell
;
216 pItems
[nIndex
].pCell
= pNoteCell
; // Dummy fuer Interpret
217 pDocument
->Broadcast( ScHint( SC_HINT_DYING
,
218 ScAddress( nCol
, nRow
, nTab
), pCell
) );
219 if ( SvtBroadcaster
* pBC
= pCell
->ReleaseBroadcaster() )
221 pNoteCell
->TakeBroadcaster( pBC
);
227 memmove( &pItems
[nIndex
], &pItems
[nIndex
+ 1], (nCount
- nIndex
) * sizeof(ColEntry
) );
228 pItems
[nCount
].nRow
= 0;
229 pItems
[nCount
].pCell
= NULL
;
230 // Soll man hier den Speicher freigeben (delta)? Wird dann langsamer!
232 pCell
->EndListeningTo( pDocument
);
238 void ScColumn::DeleteAtIndex( SCSIZE nIndex
)
240 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
241 ScNoteCell
* pNoteCell
= new ScNoteCell
;
242 pItems
[nIndex
].pCell
= pNoteCell
; // Dummy fuer Interpret
243 pDocument
->Broadcast( ScHint( SC_HINT_DYING
,
244 ScAddress( nCol
, pItems
[nIndex
].nRow
, nTab
), pCell
) );
247 memmove( &pItems
[nIndex
], &pItems
[nIndex
+ 1], (nCount
- nIndex
) * sizeof(ColEntry
) );
248 pItems
[nCount
].nRow
= 0;
249 pItems
[nCount
].pCell
= NULL
;
250 pCell
->EndListeningTo( pDocument
);
255 void ScColumn::FreeAll()
259 for (SCSIZE i
= 0; i
< nCount
; i
++)
260 pItems
[i
].pCell
->Delete();
269 void ScColumn::DeleteRow( SCROW nStartRow
, SCSIZE nSize
)
271 pAttrArray
->DeleteRow( nStartRow
, nSize
);
273 if ( !pItems
|| !nCount
)
277 Search( nStartRow
, nFirstIndex
);
278 if ( nFirstIndex
>= nCount
)
281 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
282 pDocument
->SetAutoCalc( FALSE
); // Mehrfachberechnungen vermeiden
285 SCROW nEndRow
= nStartRow
+ nSize
- 1;
286 SCSIZE nStartIndex
= 0;
287 SCSIZE nEndIndex
= 0;
290 for ( i
= nFirstIndex
; i
< nCount
&& pItems
[i
].nRow
<= nEndRow
; i
++ )
299 ScBaseCell
* pCell
= pItems
[i
].pCell
;
300 SvtBroadcaster
* pBC
= pCell
->GetBroadcaster();
303 // gibt jetzt invalid reference, kein Aufruecken der direkten Referenzen
304 // MoveListeners( *pBC, nRow+nSize );
305 pCell
->DeleteBroadcaster();
306 // in DeleteRange werden leere Broadcaster geloescht
311 DeleteRange( nStartIndex
, nEndIndex
, IDF_CONTENTS
);
312 Search( nStartRow
, i
);
315 pDocument
->SetAutoCalc( bOldAutoCalc
);
322 ScAddress
aAdr( nCol
, 0, nTab
);
323 ScHint
aHint( SC_HINT_DATACHANGED
, aAdr
, NULL
); // only areas (ScBaseCell* == NULL)
324 ScAddress
& rAddress
= aHint
.GetAddress();
325 // for sparse occupation use single broadcasts, not ranges
326 BOOL bSingleBroadcasts
= (((pItems
[nCount
-1].nRow
- pItems
[i
].nRow
) /
328 if ( bSingleBroadcasts
)
330 SCROW nLastBroadcast
= MAXROW
+1;
331 for ( ; i
< nCount
; i
++ )
333 SCROW nOldRow
= pItems
[i
].nRow
;
334 // #43940# Aenderung Quelle broadcasten
335 rAddress
.SetRow( nOldRow
);
336 pDocument
->AreaBroadcast( aHint
);
337 SCROW nNewRow
= (pItems
[i
].nRow
-= nSize
);
338 // #43940# Aenderung Ziel broadcasten
339 if ( nLastBroadcast
!= nNewRow
)
340 { // direkt aufeinanderfolgende nicht doppelt broadcasten
341 rAddress
.SetRow( nNewRow
);
342 pDocument
->AreaBroadcast( aHint
);
344 nLastBroadcast
= nOldRow
;
345 ScBaseCell
* pCell
= pItems
[i
].pCell
;
346 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
347 ((ScFormulaCell
*)pCell
)->aPos
.SetRow( nNewRow
);
352 rAddress
.SetRow( pItems
[i
].nRow
);
353 ScRange
aRange( rAddress
);
354 aRange
.aEnd
.SetRow( pItems
[nCount
-1].nRow
);
355 for ( ; i
< nCount
; i
++ )
357 SCROW nNewRow
= (pItems
[i
].nRow
-= nSize
);
358 ScBaseCell
* pCell
= pItems
[i
].pCell
;
359 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
360 ((ScFormulaCell
*)pCell
)->aPos
.SetRow( nNewRow
);
362 pDocument
->AreaBroadcastInRange( aRange
, aHint
);
365 pDocument
->SetAutoCalc( bOldAutoCalc
);
369 void ScColumn::DeleteRange( SCSIZE nStartIndex
, SCSIZE nEndIndex
, USHORT nDelFlag
)
371 /* If caller specifies to not remove the note caption objects, all cells
372 have to forget the pointers to them. This is used e.g. while undoing a
373 "paste cells" operation, which removes the caption objects later in
375 bool bDeleteNote
= (nDelFlag
& IDF_NOTE
) != 0;
376 bool bNoCaptions
= (nDelFlag
& IDF_NOCAPTIONS
) != 0;
377 if (bDeleteNote
&& bNoCaptions
)
378 for ( SCSIZE nIdx
= nStartIndex
; nIdx
<= nEndIndex
; ++nIdx
)
379 if ( ScPostIt
* pNote
= pItems
[ nIdx
].pCell
->GetNote() )
380 pNote
->ForgetCaption();
382 // special simple mode if all contents are deleted and cells do not contain broadcasters
383 bool bSimple
= ((nDelFlag
& IDF_CONTENTS
) == IDF_CONTENTS
);
385 for ( SCSIZE nIdx
= nStartIndex
; bSimple
&& (nIdx
<= nEndIndex
); ++nIdx
)
386 if (pItems
[ nIdx
].pCell
->GetBroadcaster())
389 ScHint
aHint( SC_HINT_DYING
, ScAddress( nCol
, 0, nTab
), 0 );
391 // cache all formula cells, they will be deleted at end of this function
392 typedef ::std::vector
< ScFormulaCell
* > FormulaCellVector
;
393 FormulaCellVector aDelCells
;
394 aDelCells
.reserve( nEndIndex
- nStartIndex
+ 1 );
396 // simple deletion of the cell objects
399 // pNoteCell: dummy replacement for old cells, to prevent that interpreter uses old cell
400 ScNoteCell
* pNoteCell
= new ScNoteCell
;
401 for ( SCSIZE nIdx
= nStartIndex
; nIdx
<= nEndIndex
; ++nIdx
)
403 ScBaseCell
* pOldCell
= pItems
[ nIdx
].pCell
;
404 if (pOldCell
->GetCellType() == CELLTYPE_FORMULA
)
406 // cache formula cell, will be deleted below
407 aDelCells
.push_back( static_cast< ScFormulaCell
* >( pOldCell
) );
411 // interpret in broadcast must not use the old cell
412 pItems
[ nIdx
].pCell
= pNoteCell
;
413 aHint
.GetAddress().SetRow( pItems
[ nIdx
].nRow
);
414 aHint
.SetCell( pOldCell
);
415 pDocument
->Broadcast( aHint
);
420 memmove( &pItems
[nStartIndex
], &pItems
[nEndIndex
+ 1], (nCount
- nEndIndex
- 1) * sizeof(ColEntry
) );
421 nCount
-= nEndIndex
-nStartIndex
+1;
424 // else: delete some contents of the cells
427 SCSIZE j
= nStartIndex
;
428 for ( SCSIZE nIdx
= nStartIndex
; nIdx
<= nEndIndex
; ++nIdx
)
430 // decide whether to delete the cell object according to passed flags
431 bool bDelete
= false;
432 ScBaseCell
* pOldCell
= pItems
[j
].pCell
;
433 CellType eCellType
= pOldCell
->GetCellType();
438 USHORT nValFlags
= nDelFlag
& (IDF_DATETIME
|IDF_VALUE
);
439 // delete values and dates?
440 bDelete
= nValFlags
== (IDF_DATETIME
|IDF_VALUE
);
441 // if not, decide according to cell number format
442 if( !bDelete
&& (nValFlags
!= 0) )
444 ULONG nIndex
= (ULONG
)((SfxUInt32Item
*)GetAttr( pItems
[j
].nRow
, ATTR_VALUE_FORMAT
))->GetValue();
445 short nType
= pDocument
->GetFormatTable()->GetType(nIndex
);
446 bool bIsDate
= (nType
== NUMBERFORMAT_DATE
) || (nType
== NUMBERFORMAT_TIME
) || (nType
== NUMBERFORMAT_DATETIME
);
447 bDelete
= nValFlags
== (bIsDate
? IDF_DATETIME
: IDF_VALUE
);
452 case CELLTYPE_STRING
:
454 bDelete
= (nDelFlag
& IDF_STRING
) != 0;
457 case CELLTYPE_FORMULA
:
458 bDelete
= (nDelFlag
& IDF_FORMULA
) != 0;
462 // do note delete note cell with broadcaster
463 bDelete
= bDeleteNote
&& !pOldCell
->GetBroadcaster();
466 default:; // added to avoid warnings
471 // try to create a replacement note cell, if note or broadcaster exists
472 ScNoteCell
* pNoteCell
= 0;
473 if (eCellType
!= CELLTYPE_NOTE
)
475 // do not rescue note if it has to be deleted according to passed flags
476 ScPostIt
* pNote
= bDeleteNote
? 0 : pOldCell
->ReleaseNote();
477 // #i99844# do not release broadcaster from old cell, it still has to notify deleted content
478 SvtBroadcaster
* pBC
= pOldCell
->GetBroadcaster();
480 pNoteCell
= new ScNoteCell( pNote
, pBC
);
483 // remove cell entry in cell item list
484 SCROW nOldRow
= pItems
[j
].nRow
;
487 // replace old cell with the replacement note cell
488 pItems
[j
].pCell
= pNoteCell
;
493 // remove the old cell from the cell item list
495 memmove( &pItems
[j
], &pItems
[j
+ 1], (nCount
- j
) * sizeof(ColEntry
) );
496 pItems
[nCount
].nRow
= 0;
497 pItems
[nCount
].pCell
= 0;
500 // cache formula cells (will be deleted later), delete cell of other type
501 if (eCellType
== CELLTYPE_FORMULA
)
503 aDelCells
.push_back( static_cast< ScFormulaCell
* >( pOldCell
) );
507 aHint
.GetAddress().SetRow( nOldRow
);
508 aHint
.SetCell( pOldCell
);
509 pDocument
->Broadcast( aHint
);
510 // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by pNoteCell)
511 pOldCell
->ReleaseBroadcaster();
519 pItems
[j
].pCell
->DeleteNote();
520 // cell not deleted, move index to next cell
526 // *** delete all formula cells ***
528 // first, all cells stop listening, may save unneeded recalcualtions
529 for ( FormulaCellVector::iterator aIt
= aDelCells
.begin(), aEnd
= aDelCells
.end(); aIt
!= aEnd
; ++aIt
)
530 (*aIt
)->EndListeningTo( pDocument
);
532 // #i101869# if the note cell with the broadcaster was deleted in EndListening,
533 // forget the pointer to the broadcaster
534 for ( FormulaCellVector::iterator aIt
= aDelCells
.begin(), aEnd
= aDelCells
.end(); aIt
!= aEnd
; ++aIt
)
537 if ( !Search( (*aIt
)->aPos
.Row(), nIndex
) )
538 (*aIt
)->ReleaseBroadcaster();
541 // broadcast SC_HINT_DYING for all cells and delete them
542 for ( FormulaCellVector::iterator aIt
= aDelCells
.begin(), aEnd
= aDelCells
.end(); aIt
!= aEnd
; ++aIt
)
544 aHint
.SetAddress( (*aIt
)->aPos
);
545 aHint
.SetCell( *aIt
);
546 pDocument
->Broadcast( aHint
);
547 // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by replacement note cell)
548 (*aIt
)->ReleaseBroadcaster();
554 void ScColumn::DeleteArea(SCROW nStartRow
, SCROW nEndRow
, USHORT nDelFlag
)
556 // FreeAll darf hier nicht gerufen werden wegen Broadcastern
558 // Attribute erst am Ende, damit vorher noch zwischen Zahlen und Datum
559 // unterschieden werden kann (#47901#)
561 USHORT nContMask
= IDF_CONTENTS
;
562 // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
563 if( nDelFlag
& IDF_NOTE
)
564 nContMask
|= IDF_NOCAPTIONS
;
565 USHORT nContFlag
= nDelFlag
& nContMask
;
567 if (pItems
&& nCount
>0 && nContFlag
)
569 if (nStartRow
==0 && nEndRow
==MAXROW
)
570 DeleteRange( 0, nCount
-1, nContFlag
);
574 SCSIZE nStartIndex
= 0;
575 SCSIZE nEndIndex
= 0;
576 for (SCSIZE i
= 0; i
< nCount
; i
++)
577 if ((pItems
[i
].nRow
>= nStartRow
) && (pItems
[i
].nRow
<= nEndRow
))
587 DeleteRange( nStartIndex
, nEndIndex
, nContFlag
);
591 if ( nDelFlag
& IDF_EDITATTR
)
593 DBG_ASSERT( nContFlag
== 0, "DeleteArea: falsche Flags" );
594 RemoveEditAttribs( nStartRow
, nEndRow
);
597 // Attribute erst hier
598 if ((nDelFlag
& IDF_ATTRIB
) == IDF_ATTRIB
) pAttrArray
->DeleteArea( nStartRow
, nEndRow
);
599 else if ((nDelFlag
& IDF_ATTRIB
) != 0) pAttrArray
->DeleteHardAttr( nStartRow
, nEndRow
);
603 ScFormulaCell
* ScColumn::CreateRefCell( ScDocument
* pDestDoc
, const ScAddress
& rDestPos
,
604 SCSIZE nIndex
, USHORT nFlags
) const
606 USHORT nContFlags
= nFlags
& IDF_CONTENTS
;
610 // Testen, ob Zelle kopiert werden soll
611 // auch bei IDF_CONTENTS komplett, wegen Notes / Broadcastern
614 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
615 CellType eCellType
= pCell
->GetCellType();
620 USHORT nValFlags
= nFlags
& (IDF_DATETIME
|IDF_VALUE
);
622 if ( nValFlags
== (IDF_DATETIME
|IDF_VALUE
) )
624 else if ( nValFlags
)
626 ULONG nNumIndex
= (ULONG
)((SfxUInt32Item
*)GetAttr(
627 pItems
[nIndex
].nRow
, ATTR_VALUE_FORMAT
))->GetValue();
628 short nTyp
= pDocument
->GetFormatTable()->GetType(nNumIndex
);
629 if ((nTyp
== NUMBERFORMAT_DATE
) || (nTyp
== NUMBERFORMAT_TIME
) || (nTyp
== NUMBERFORMAT_DATETIME
))
630 bMatch
= ((nFlags
& IDF_DATETIME
) != 0);
632 bMatch
= ((nFlags
& IDF_VALUE
) != 0);
636 case CELLTYPE_STRING
:
637 case CELLTYPE_EDIT
: bMatch
= ((nFlags
& IDF_STRING
) != 0); break;
638 case CELLTYPE_FORMULA
: bMatch
= ((nFlags
& IDF_FORMULA
) != 0); break;
641 // added to avoid warnings
648 // Referenz einsetzen
649 ScSingleRefData aRef
;
651 aRef
.nRow
= pItems
[nIndex
].nRow
;
653 aRef
.InitFlags(); // -> alles absolut
654 aRef
.SetFlag3D(TRUE
);
656 //! 3D(FALSE) und TabRel(TRUE), wenn die endgueltige Position auf der selben Tabelle ist?
657 //! (bei TransposeClip ist die Zielposition noch nicht bekannt)
659 aRef
.CalcRelFromAbs( rDestPos
);
662 aArr
.AddSingleReference( aRef
);
664 return new ScFormulaCell( pDestDoc
, rDestPos
, &aArr
);
669 // nRow1, nRow2 = Zielposition
671 void ScColumn::CopyFromClip(SCROW nRow1
, SCROW nRow2
, long nDy
,
672 USHORT nInsFlag
, BOOL bAsLink
, BOOL bSkipAttrForEmpty
,
675 if ((nInsFlag
& IDF_ATTRIB
) != 0)
677 if ( bSkipAttrForEmpty
)
679 // copy only attributes for non-empty cells
680 // (notes are not counted as non-empty here, to match the content behavior)
683 rColumn
.Search( nRow1
-nDy
, nStartIndex
);
684 while ( nStartIndex
< rColumn
.nCount
&& rColumn
.pItems
[nStartIndex
].nRow
<= nRow2
-nDy
)
686 SCSIZE nEndIndex
= nStartIndex
;
687 if ( rColumn
.pItems
[nStartIndex
].pCell
->GetCellType() != CELLTYPE_NOTE
)
689 SCROW nStartRow
= rColumn
.pItems
[nStartIndex
].nRow
;
690 SCROW nEndRow
= nStartRow
;
692 // find consecutive non-empty cells
694 while ( nEndRow
< nRow2
-nDy
&&
695 nEndIndex
+1 < rColumn
.nCount
&&
696 rColumn
.pItems
[nEndIndex
+1].nRow
== nEndRow
+1 &&
697 rColumn
.pItems
[nEndIndex
+1].pCell
->GetCellType() != CELLTYPE_NOTE
)
703 rColumn
.pAttrArray
->CopyAreaSafe( nStartRow
+nDy
, nEndRow
+nDy
, nDy
, *pAttrArray
);
705 nStartIndex
= nEndIndex
+ 1;
709 rColumn
.pAttrArray
->CopyAreaSafe( nRow1
, nRow2
, nDy
, *pAttrArray
);
711 if ((nInsFlag
& IDF_CONTENTS
) == 0)
714 if ( bAsLink
&& nInsFlag
== IDF_ALL
)
716 // bei "alles" werden auch leere Zellen referenziert
717 //! IDF_ALL muss immer mehr Flags enthalten, als bei "Inhalte Einfuegen"
718 //! einzeln ausgewaehlt werden koennen!
720 Resize( nCount
+ static_cast<SCSIZE
>(nRow2
-nRow1
+1) );
722 ScAddress
aDestPos( nCol
, 0, nTab
); // Row wird angepasst
724 // Referenz erzeugen (Quell-Position)
725 ScSingleRefData aRef
;
726 aRef
.nCol
= rColumn
.nCol
;
727 // nRow wird angepasst
728 aRef
.nTab
= rColumn
.nTab
;
729 aRef
.InitFlags(); // -> alles absolut
730 aRef
.SetFlag3D(TRUE
);
732 for (SCROW nDestRow
= nRow1
; nDestRow
<= nRow2
; nDestRow
++)
734 aRef
.nRow
= nDestRow
- nDy
; // Quell-Zeile
735 aDestPos
.SetRow( nDestRow
);
737 aRef
.CalcRelFromAbs( aDestPos
);
739 aArr
.AddSingleReference( aRef
);
740 Insert( nDestRow
, new ScFormulaCell( pDocument
, aDestPos
, &aArr
) );
746 SCSIZE nColCount
= rColumn
.nCount
;
748 // ignore IDF_FORMULA - "all contents but no formulas" results in the same number of cells
749 if ((nInsFlag
& ( IDF_CONTENTS
& ~IDF_FORMULA
)) == ( IDF_CONTENTS
& ~IDF_FORMULA
) && nRow2
-nRow1
>= 64)
751 //! Always do the Resize from the outside, where the number of repetitions is known
752 //! (then it can be removed here)
754 SCSIZE nNew
= nCount
+ nColCount
;
759 // IDF_ADDNOTES must be passed without other content flags than IDF_NOTE
760 bool bAddNotes
= (nInsFlag
& (IDF_CONTENTS
| IDF_ADDNOTES
)) == (IDF_NOTE
| IDF_ADDNOTES
);
763 for (SCSIZE i
= 0; i
< nColCount
&& !bAtEnd
; i
++)
765 SCsROW nDestRow
= rColumn
.pItems
[i
].nRow
+ nDy
;
766 if ( nDestRow
> (SCsROW
) nRow2
)
768 else if ( nDestRow
>= (SCsROW
) nRow1
)
770 // rows at the beginning may be skipped if filtered rows are left out,
771 // nDestRow may be negative then
773 ScAddress
aDestPos( nCol
, (SCROW
)nDestRow
, nTab
);
775 /* #i102056# Paste from clipboard needs to paste the cell notes in
776 a second pass. This must not overwrite the existing cells
777 already copied to the destination position in the first pass.
778 To indicate this special case, the modifier IDF_ADDNOTES is
779 passed together with IDF_NOTE in nInsFlag. Of course, there is
780 still the need to create a new cell, if there is no cell at the
781 destination position at all. */
782 ScBaseCell
* pAddNoteCell
= bAddNotes
? GetCell( aDestPos
.Row() ) : 0;
785 // do nothing if source cell does not contain a note
786 const ScBaseCell
* pSourceCell
= rColumn
.pItems
[i
].pCell
;
787 const ScPostIt
* pSourceNote
= pSourceCell
? pSourceCell
->GetNote() : 0;
790 DBG_ASSERT( !pAddNoteCell
->HasNote(), "ScColumn::CopyFromClip - unexpected note at destination cell" );
791 bool bCloneCaption
= (nInsFlag
& IDF_NOCAPTIONS
) == 0;
792 // #i52342# if caption is cloned, the note must be constructed with the destination document
793 ScAddress
aSourcePos( rColumn
.nCol
, rColumn
.pItems
[i
].nRow
, rColumn
.nTab
);
794 ScPostIt
* pNewNote
= pSourceNote
->Clone( aSourcePos
, *pDocument
, aDestPos
, bCloneCaption
);
795 pAddNoteCell
->TakeNote( pNewNote
);
800 ScBaseCell
* pNewCell
= bAsLink
?
801 rColumn
.CreateRefCell( pDocument
, aDestPos
, i
, nInsFlag
) :
802 rColumn
.CloneCell( i
, nInsFlag
, *pDocument
, aDestPos
);
804 Insert( aDestPos
.Row(), pNewCell
);
813 /** Helper for ScColumn::CloneCell - decides whether to clone a value cell depending on clone flags and number format. */
814 bool lclCanCloneValue( ScDocument
& rDoc
, const ScColumn
& rCol
, SCROW nRow
, bool bCloneValue
, bool bCloneDateTime
)
816 // values and dates, or nothing to be cloned -> not needed to check number format
817 if( bCloneValue
== bCloneDateTime
)
820 // check number format of value cell
821 ULONG nNumIndex
= (ULONG
)((SfxUInt32Item
*)rCol
.GetAttr( nRow
, ATTR_VALUE_FORMAT
))->GetValue();
822 short nTyp
= rDoc
.GetFormatTable()->GetType( nNumIndex
);
823 bool bIsDateTime
= (nTyp
== NUMBERFORMAT_DATE
) || (nTyp
== NUMBERFORMAT_TIME
) || (nTyp
== NUMBERFORMAT_DATETIME
);
824 return bIsDateTime
? bCloneDateTime
: bCloneValue
;
830 ScBaseCell
* ScColumn::CloneCell(SCSIZE nIndex
, USHORT nFlags
, ScDocument
& rDestDoc
, const ScAddress
& rDestPos
)
832 bool bCloneValue
= (nFlags
& IDF_VALUE
) != 0;
833 bool bCloneDateTime
= (nFlags
& IDF_DATETIME
) != 0;
834 bool bCloneString
= (nFlags
& IDF_STRING
) != 0;
835 bool bCloneSpecialBoolean
= (nFlags
& IDF_SPECIAL_BOOLEAN
) != 0;
836 bool bCloneFormula
= (nFlags
& IDF_FORMULA
) != 0;
837 bool bCloneNote
= (nFlags
& IDF_NOTE
) != 0;
838 bool bForceFormula
= false;
840 ScBaseCell
* pNew
= 0;
841 ScBaseCell
& rSource
= *pItems
[nIndex
].pCell
;
842 switch (rSource
.GetCellType())
845 // note will be cloned below
848 case CELLTYPE_STRING
:
850 // note will be cloned below
852 pNew
= rSource
.CloneWithoutNote( rDestDoc
, rDestPos
);
856 // note will be cloned below
857 if (lclCanCloneValue( *pDocument
, *this, pItems
[nIndex
].nRow
, bCloneValue
, bCloneDateTime
))
858 pNew
= rSource
.CloneWithoutNote( rDestDoc
, rDestPos
);
861 case CELLTYPE_FORMULA
:
862 if ( bCloneSpecialBoolean
)
864 ScFormulaCell
& rForm
= (ScFormulaCell
&)rSource
;
865 rtl::OUStringBuffer aBuf
;
866 // #TODO #FIXME do we have a localisation issue here?
867 rForm
.GetFormula( aBuf
);
868 rtl::OUString
aVal( aBuf
.makeStringAndClear() );
869 if ( aVal
.equalsAscii( "=TRUE()" )
870 || aVal
.equalsAscii( "=FALSE()" ) )
871 bForceFormula
= true;
873 if (bForceFormula
|| bCloneFormula
)
875 // note will be cloned below
876 pNew
= rSource
.CloneWithoutNote( rDestDoc
, rDestPos
);
878 else if ( (bCloneValue
|| bCloneDateTime
|| bCloneString
) && !rDestDoc
.IsUndo() )
880 // #48491# ins Undo-Dokument immer nur die Original-Zelle kopieren,
881 // aus Formeln keine Value/String-Zellen erzeugen
882 ScFormulaCell
& rForm
= (ScFormulaCell
&)rSource
;
883 USHORT nErr
= rForm
.GetErrCode();
886 // error codes are cloned with values
889 ScFormulaCell
* pErrCell
= new ScFormulaCell( &rDestDoc
, rDestPos
);
890 pErrCell
->SetErrCode( nErr
);
894 else if (rForm
.IsValue())
896 if (lclCanCloneValue( *pDocument
, *this, pItems
[nIndex
].nRow
, bCloneValue
, bCloneDateTime
))
898 double nVal
= rForm
.GetValue();
899 pNew
= new ScValueCell(nVal
);
902 else if (bCloneString
)
905 rForm
.GetString( aString
);
906 // #33224# do not clone empty string
907 if (aString
.Len() > 0)
909 if ( rForm
.IsMultilineResult() )
911 pNew
= new ScEditCell( aString
, &rDestDoc
);
915 pNew
= new ScStringCell( aString
);
922 default: DBG_ERRORFILE( "ScColumn::CloneCell - unknown cell type" );
925 // clone the cell note
928 if (ScPostIt
* pNote
= rSource
.GetNote())
930 bool bCloneCaption
= (nFlags
& IDF_NOCAPTIONS
) == 0;
931 // #i52342# if caption is cloned, the note must be constructed with the destination document
932 ScAddress
aOwnPos( nCol
, pItems
[nIndex
].nRow
, nTab
);
933 ScPostIt
* pNewNote
= pNote
->Clone( aOwnPos
, rDestDoc
, rDestPos
, bCloneCaption
);
935 pNew
= new ScNoteCell( pNewNote
);
937 pNew
->TakeNote( pNewNote
);
945 void ScColumn::MixMarked( const ScMarkData
& rMark
, USHORT nFunction
,
946 BOOL bSkipEmpty
, ScColumn
& rSrcCol
)
950 if (rMark
.IsMultiMarked())
952 ScMarkArrayIter
aIter( rMark
.GetArray()+nCol
);
953 while (aIter
.Next( nRow1
, nRow2
))
954 MixData( nRow1
, nRow2
, nFunction
, bSkipEmpty
, rSrcCol
);
961 BOOL
lcl_DoFunction( double& rVal1
, double nVal2
, USHORT nFunction
)
967 bOk
= SubTotal::SafePlus( rVal1
, nVal2
);
970 nVal2
= -nVal2
; //! geht das immer ohne Fehler?
971 bOk
= SubTotal::SafePlus( rVal1
, nVal2
);
974 bOk
= SubTotal::SafeMult( rVal1
, nVal2
);
977 bOk
= SubTotal::SafeDiv( rVal1
, nVal2
);
984 void lcl_AddCode( ScTokenArray
& rArr
, ScFormulaCell
* pCell
)
986 rArr
.AddOpCode(ocOpen
);
988 ScTokenArray
* pCode
= pCell
->GetCode();
991 const formula::FormulaToken
* pToken
= pCode
->First();
994 rArr
.AddToken( *pToken
);
995 pToken
= pCode
->Next();
999 rArr
.AddOpCode(ocClose
);
1003 void ScColumn::MixData( SCROW nRow1
, SCROW nRow2
,
1004 USHORT nFunction
, BOOL bSkipEmpty
,
1007 SCSIZE nSrcCount
= rSrcCol
.nCount
;
1010 Search( nRow1
, nIndex
);
1012 // SCSIZE nSrcIndex = 0;
1014 rSrcCol
.Search( nRow1
, nSrcIndex
); //! Testen, ob Daten ganz vorne
1016 SCROW nNextThis
= MAXROW
+1;
1017 if ( nIndex
< nCount
)
1018 nNextThis
= pItems
[nIndex
].nRow
;
1019 SCROW nNextSrc
= MAXROW
+1;
1020 if ( nSrcIndex
< nSrcCount
)
1021 nNextSrc
= rSrcCol
.pItems
[nSrcIndex
].nRow
;
1023 while ( nNextThis
<= nRow2
|| nNextSrc
<= nRow2
)
1025 SCROW nRow
= Min( nNextThis
, nNextSrc
);
1027 ScBaseCell
* pSrc
= NULL
;
1028 ScBaseCell
* pDest
= NULL
;
1029 ScBaseCell
* pNew
= NULL
;
1030 BOOL bDelete
= FALSE
;
1032 if ( nSrcIndex
< nSrcCount
&& nNextSrc
== nRow
)
1033 pSrc
= rSrcCol
.pItems
[nSrcIndex
].pCell
;
1035 if ( nIndex
< nCount
&& nNextThis
== nRow
)
1036 pDest
= pItems
[nIndex
].pCell
;
1038 DBG_ASSERT( pSrc
|| pDest
, "Nanu ?" );
1040 CellType eSrcType
= pSrc
? pSrc
->GetCellType() : CELLTYPE_NONE
;
1041 CellType eDestType
= pDest
? pDest
->GetCellType() : CELLTYPE_NONE
;
1043 BOOL bSrcEmpty
= ( eSrcType
== CELLTYPE_NONE
|| eSrcType
== CELLTYPE_NOTE
);
1044 BOOL bDestEmpty
= ( eDestType
== CELLTYPE_NONE
|| eDestType
== CELLTYPE_NOTE
);
1046 if ( bSkipEmpty
&& bDestEmpty
) // Originalzelle wiederherstellen
1048 if ( pSrc
) // war da eine Zelle?
1050 pNew
= pSrc
->CloneWithoutNote( *pDocument
);
1053 else if ( nFunction
) // wirklich Rechenfunktion angegeben
1057 if ( eSrcType
== CELLTYPE_VALUE
)
1058 nVal1
= ((ScValueCell
*)pSrc
)->GetValue();
1061 if ( eDestType
== CELLTYPE_VALUE
)
1062 nVal2
= ((ScValueCell
*)pDest
)->GetValue();
1066 // leere Zellen werden als Werte behandelt
1068 BOOL bSrcVal
= ( bSrcEmpty
|| eSrcType
== CELLTYPE_VALUE
);
1069 BOOL bDestVal
= ( bDestEmpty
|| eDestType
== CELLTYPE_VALUE
);
1071 BOOL bSrcText
= ( eSrcType
== CELLTYPE_STRING
||
1072 eSrcType
== CELLTYPE_EDIT
);
1073 BOOL bDestText
= ( eDestType
== CELLTYPE_STRING
||
1074 eDestType
== CELLTYPE_EDIT
);
1076 // sonst bleibt nur Formel...
1078 if ( bSrcEmpty
&& bDestEmpty
)
1080 // beide leer -> nix
1082 else if ( bSrcVal
&& bDestVal
)
1084 // neuen Wert eintragen, oder Fehler bei Ueberlauf
1086 BOOL bOk
= lcl_DoFunction( nVal1
, nVal2
, nFunction
);
1089 pNew
= new ScValueCell( nVal1
);
1092 ScFormulaCell
* pFC
= new ScFormulaCell( pDocument
,
1093 ScAddress( nCol
, nRow
, nTab
) );
1094 pFC
->SetErrCode( errNoValue
);
1095 //! oder NOVALUE, dann auch in consoli,
1096 //! sonst in Interpreter::GetCellValue die Abfrage auf errNoValue raus
1097 //! (dann geht Stringzelle+Wertzelle nicht mehr)
1101 else if ( bSrcText
|| bDestText
)
1103 // mit Texten wird nicht gerechnet - immer "alte" Zelle, also pSrc
1106 pNew
= pSrc
->CloneWithoutNote( *pDocument
);
1112 // Kombination aus Wert und mindestens einer Formel -> Formel erzeugen
1117 if ( eSrcType
== CELLTYPE_FORMULA
)
1118 lcl_AddCode( aArr
, (ScFormulaCell
*)pSrc
);
1120 aArr
.AddDouble( nVal1
);
1124 switch ( nFunction
)
1126 case PASTE_ADD
: eOp
= ocAdd
; break;
1127 case PASTE_SUB
: eOp
= ocSub
; break;
1128 case PASTE_MUL
: eOp
= ocMul
; break;
1129 case PASTE_DIV
: eOp
= ocDiv
; break;
1131 aArr
.AddOpCode(eOp
); // Funktion
1134 if ( eDestType
== CELLTYPE_FORMULA
)
1135 lcl_AddCode( aArr
, (ScFormulaCell
*)pDest
);
1137 aArr
.AddDouble( nVal2
);
1139 pNew
= new ScFormulaCell( pDocument
, ScAddress( nCol
, nRow
, nTab
), &aArr
);
1144 if ( pNew
|| bDelete
) // neues Ergebnis ?
1146 if (pDest
&& !pNew
) // alte Zelle da ?
1148 if ( pDest
->GetBroadcaster() )
1149 pNew
= new ScNoteCell
; // Broadcaster uebernehmen
1151 Delete(nRow
); // -> loeschen
1154 Insert(nRow
, pNew
); // neue einfuegen
1156 Search( nRow
, nIndex
); // alles kann sich verschoben haben
1158 nNextThis
= nRow
; // nIndex zeigt jetzt genau auf nRow
1160 nNextThis
= ( nIndex
< nCount
) ? pItems
[nIndex
].nRow
: MAXROW
+1;
1163 if ( nNextThis
== nRow
)
1166 nNextThis
= ( nIndex
< nCount
) ? pItems
[nIndex
].nRow
: MAXROW
+1;
1168 if ( nNextSrc
== nRow
)
1171 nNextSrc
= ( nSrcIndex
< nSrcCount
) ?
1172 rSrcCol
.pItems
[nSrcIndex
].nRow
:
1179 ScAttrIterator
* ScColumn::CreateAttrIterator( SCROW nStartRow
, SCROW nEndRow
) const
1181 return new ScAttrIterator( pAttrArray
, nStartRow
, nEndRow
);
1185 void ScColumn::StartAllListeners()
1188 for (SCSIZE i
= 0; i
< nCount
; i
++)
1190 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1191 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1193 SCROW nRow
= pItems
[i
].nRow
;
1194 ((ScFormulaCell
*)pCell
)->StartListeningTo( pDocument
);
1195 if ( nRow
!= pItems
[i
].nRow
)
1196 Search( nRow
, i
); // Listener eingefuegt?
1202 void ScColumn::StartNeededListeners()
1206 for (SCSIZE i
= 0; i
< nCount
; i
++)
1208 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1209 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1211 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1212 if (pFCell
->NeedsListening())
1214 SCROW nRow
= pItems
[i
].nRow
;
1215 pFCell
->StartListeningTo( pDocument
);
1216 if ( nRow
!= pItems
[i
].nRow
)
1217 Search( nRow
, i
); // Listener eingefuegt?
1225 void ScColumn::BroadcastInArea( SCROW nRow1
, SCROW nRow2
)
1231 Search( nRow1
, nIndex
);
1232 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRow2
)
1234 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1235 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1236 ((ScFormulaCell
*)pCell
)->SetDirty();
1238 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
,
1239 ScAddress( nCol
, nRow
, nTab
), pCell
) );
1246 void ScColumn::StartListeningInArea( SCROW nRow1
, SCROW nRow2
)
1252 Search( nRow1
, nIndex
);
1253 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRow2
)
1255 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1256 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1257 ((ScFormulaCell
*)pCell
)->StartListeningTo( pDocument
);
1258 if ( nRow
!= pItems
[nIndex
].nRow
)
1259 Search( nRow
, nIndex
); // durch Listening eingefuegt
1266 // TRUE = Zahlformat gesetzt
1267 BOOL
ScColumn::SetString( SCROW nRow
, SCTAB nTabP
, const String
& rString
,
1268 formula::FormulaGrammar::AddressConvention eConv
,
1269 ScSetStringParam
* pParam
)
1271 BOOL bNumFmtSet
= FALSE
;
1274 ScBaseCell
* pNewCell
= NULL
;
1275 BOOL bIsLoading
= FALSE
;
1276 if (rString
.Len() > 0)
1278 ScSetStringParam aParam
;
1283 sal_uInt32 nIndex
, nOldIndex
= 0;
1284 sal_Unicode cFirstChar
;
1285 if (!aParam
.mpNumFormatter
)
1286 aParam
.mpNumFormatter
= pDocument
->GetFormatTable();
1287 SfxObjectShell
* pDocSh
= pDocument
->GetDocumentShell();
1289 bIsLoading
= pDocSh
->IsLoading();
1290 // IsLoading bei ConvertFrom Import
1293 nIndex
= nOldIndex
= GetNumberFormat( nRow
);
1294 if ( rString
.Len() > 1
1295 && aParam
.mpNumFormatter
->GetType(nIndex
) != NUMBERFORMAT_TEXT
)
1296 cFirstChar
= rString
.GetChar(0);
1298 cFirstChar
= 0; // Text
1301 { // waehrend ConvertFrom Import gibt es keine gesetzten Formate
1302 cFirstChar
= rString
.GetChar(0);
1305 if ( cFirstChar
== '=' )
1307 if ( rString
.Len() == 1 ) // = Text
1308 pNewCell
= new ScStringCell( rString
);
1310 pNewCell
= new ScFormulaCell( pDocument
,
1311 ScAddress( nCol
, nRow
, nTabP
), rString
,
1312 formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_DEFAULT
,
1315 else if ( cFirstChar
== '\'') // 'Text
1316 pNewCell
= new ScStringCell( rString
.Copy(1) );
1319 BOOL bIsText
= FALSE
;
1322 if ( pItems
&& nCount
)
1326 SCSIZE nStop
= (i
>= 3 ? i
- 3 : 0);
1327 // die letzten Zellen vergleichen, ob gleicher String
1328 // und IsNumberFormat eingespart werden kann
1332 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1333 switch ( pCell
->GetCellType() )
1335 case CELLTYPE_STRING
:
1336 ((ScStringCell
*)pCell
)->GetString( aStr
);
1337 if ( rString
== aStr
)
1340 case CELLTYPE_NOTE
: // durch =Formel referenziert
1343 if ( i
== nCount
- 1 )
1345 // wahrscheinlich ganze Spalte kein String
1347 } while ( i
&& i
> nStop
&& !bIsText
);
1349 // nIndex fuer IsNumberFormat vorbelegen
1351 nIndex
= nOldIndex
= aParam
.mpNumFormatter
->GetStandardIndex();
1359 if (aParam
.mbDetectNumberFormat
)
1361 if (!aParam
.mpNumFormatter
->IsNumberFormat(rString
, nIndex
, nVal
))
1364 pNewCell
= new ScValueCell( nVal
);
1365 if ( nIndex
!= nOldIndex
)
1367 // #i22345# New behavior: Apply the detected number format only if
1368 // the old one was the default number, date, time or boolean format.
1369 // Exception: If the new format is boolean, always apply it.
1371 BOOL bOverwrite
= FALSE
;
1372 const SvNumberformat
* pOldFormat
= aParam
.mpNumFormatter
->GetEntry( nOldIndex
);
1375 short nOldType
= pOldFormat
->GetType() & ~NUMBERFORMAT_DEFINED
;
1376 if ( nOldType
== NUMBERFORMAT_NUMBER
|| nOldType
== NUMBERFORMAT_DATE
||
1377 nOldType
== NUMBERFORMAT_TIME
|| nOldType
== NUMBERFORMAT_LOGICAL
)
1379 if ( nOldIndex
== aParam
.mpNumFormatter
->GetStandardFormat(
1380 nOldType
, pOldFormat
->GetLanguage() ) )
1382 bOverwrite
= TRUE
; // default of these types can be overwritten
1386 if ( !bOverwrite
&& aParam
.mpNumFormatter
->GetType( nIndex
) == NUMBERFORMAT_LOGICAL
)
1388 bOverwrite
= TRUE
; // overwrite anything if boolean was detected
1393 ApplyAttr( nRow
, SfxUInt32Item( ATTR_VALUE_FORMAT
,
1401 // Only check if the string is a regular number.
1402 const LocaleDataWrapper
* pLocale
= aParam
.mpNumFormatter
->GetLocaleData();
1406 LocaleDataItem aLocaleItem
= pLocale
->getLocaleItem();
1407 const OUString
& rDecSep
= aLocaleItem
.decimalSeparator
;
1408 const OUString
& rGroupSep
= aLocaleItem
.thousandSeparator
;
1409 if (rDecSep
.getLength() != 1 || rGroupSep
.getLength() != 1)
1412 sal_Unicode dsep
= rDecSep
.getStr()[0];
1413 sal_Unicode gsep
= rGroupSep
.getStr()[0];
1415 if (!ScStringUtil::parseSimpleNumber(rString
, dsep
, gsep
, nVal
))
1418 pNewCell
= new ScValueCell(nVal
);
1425 if (aParam
.mbSetTextCellFormat
&& aParam
.mpNumFormatter
->IsNumberFormat(rString
, nIndex
, nVal
))
1427 // Set the cell format type to Text.
1428 sal_uInt32 nFormat
= aParam
.mpNumFormatter
->GetStandardFormat(NUMBERFORMAT_TEXT
);
1429 ScPatternAttr
aNewAttrs(pDocument
->GetPool());
1430 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
1431 rSet
.Put( SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
) );
1432 ApplyPattern(nRow
, aNewAttrs
);
1435 pNewCell
= new ScStringCell(rString
);
1440 if ( bIsLoading
&& (!nCount
|| nRow
> pItems
[nCount
-1].nRow
) )
1441 { // Search einsparen und ohne Umweg ueber Insert, Listener aufbauen
1442 // und Broadcast kommt eh erst nach dem Laden
1444 Append( nRow
, pNewCell
);
1449 if (Search(nRow
, i
))
1451 ScBaseCell
* pOldCell
= pItems
[i
].pCell
;
1452 ScPostIt
* pNote
= pOldCell
->ReleaseNote();
1453 SvtBroadcaster
* pBC
= pOldCell
->ReleaseBroadcaster();
1454 if (pNewCell
|| pNote
|| pBC
)
1457 pNewCell
->TakeNote( pNote
);
1459 pNewCell
= new ScNoteCell( pNote
);
1462 pNewCell
->TakeBroadcaster(pBC
);
1463 pLastFormulaTreeTop
= 0; // Err527 Workaround
1466 if ( pOldCell
->GetCellType() == CELLTYPE_FORMULA
)
1468 pOldCell
->EndListeningTo( pDocument
);
1469 // falls in EndListening NoteCell in gleicher Col zerstoert
1470 if ( i
>= nCount
|| pItems
[i
].nRow
!= nRow
)
1474 pItems
[i
].pCell
= pNewCell
; // ersetzen
1475 if ( pNewCell
->GetCellType() == CELLTYPE_FORMULA
)
1477 pNewCell
->StartListeningTo( pDocument
);
1478 ((ScFormulaCell
*)pNewCell
)->SetDirty();
1481 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
,
1482 ScAddress( nCol
, nRow
, nTabP
), pNewCell
) );
1486 DeleteAtIndex(i
); // loeschen und Broadcast
1491 Insert(nRow
, pNewCell
); // neu eintragen und Broadcast
1495 // hier keine Formate mehr fuer Formeln setzen!
1496 // (werden bei der Ausgabe abgefragt)
1503 void ScColumn::GetFilterEntries(SCROW nStartRow
, SCROW nEndRow
, TypedScStrCollection
& rStrings
, bool& rHasDates
)
1505 bool bHasDates
= false;
1506 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
1511 Search( nStartRow
, nIndex
);
1513 while ( (nIndex
< nCount
) ? ((nRow
=pItems
[nIndex
].nRow
) <= nEndRow
) : FALSE
)
1515 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1516 TypedStrData
* pData
;
1517 ULONG nFormat
= GetNumberFormat( nRow
);
1519 ScCellFormat::GetInputString( pCell
, nFormat
, aString
, *pFormatter
);
1521 if ( pDocument
->HasStringData( nCol
, nRow
, nTab
) )
1522 pData
= new TypedStrData( aString
);
1527 switch ( pCell
->GetCellType() )
1529 case CELLTYPE_VALUE
:
1530 nValue
= ((ScValueCell
*)pCell
)->GetValue();
1533 case CELLTYPE_FORMULA
:
1534 nValue
= ((ScFormulaCell
*)pCell
)->GetValue();
1543 short nType
= pFormatter
->GetType(nFormat
);
1544 if ((nType
& NUMBERFORMAT_DATE
) && !(nType
& NUMBERFORMAT_TIME
))
1546 // special case for date values. Disregard the time
1547 // element if the number format is of date type.
1548 nValue
= ::rtl::math::approxFloor(nValue
);
1553 pData
= new TypedStrData( aString
, nValue
, SC_STRTYPE_VALUE
);
1556 ScPostIt
aCellNote( ScPostIt::UNINITIALIZED
);
1557 // Hide visible notes during Filtering.
1558 if(pCell
->GetNote(aCellNote
) && aCellNote
.IsCaptionShown())
1560 ScDetectiveFunc( pDocument
, nTab
).HideComment( nCol
, nRow
);
1561 aCellNote
.SetShown( false );
1562 pCell
->SetNote(aCellNote
);
1566 if ( !rStrings
.Insert( pData
) )
1567 delete pData
; // doppelt
1572 rHasDates
= bHasDates
;
1576 // GetDataEntries - Strings aus zusammenhaengendem Bereich um nRow
1579 // DATENT_MAX - max. Anzahl Eintrage in Liste fuer Auto-Eingabe
1580 // DATENT_SEARCH - max. Anzahl Zellen, die durchsucht werden - neu: nur Strings zaehlen
1581 #define DATENT_MAX 200
1582 #define DATENT_SEARCH 2000
1585 BOOL
ScColumn::GetDataEntries(SCROW nStartRow
, TypedScStrCollection
& rStrings
, BOOL bLimit
)
1587 BOOL bFound
= FALSE
;
1589 BOOL bThisUsed
= Search( nStartRow
, nThisIndex
);
1593 // Die Beschraenkung auf angrenzende Zellen (ohne Luecken) ist nicht mehr gewollt
1594 // (Featurekommission zur 5.1), stattdessen abwechselnd nach oben und unten suchen,
1595 // damit naheliegende Zellen wenigstens zuerst gefunden werden.
1596 //! Abstaende der Zeilennummern vergleichen? (Performance??)
1598 SCSIZE nUpIndex
= nThisIndex
; // zeigt hinter die Zelle
1599 SCSIZE nDownIndex
= nThisIndex
; // zeigt auf die Zelle
1601 ++nDownIndex
; // Startzelle ueberspringen
1603 while ( nUpIndex
|| nDownIndex
< nCount
)
1605 if ( nUpIndex
) // nach oben
1607 ScBaseCell
* pCell
= pItems
[nUpIndex
-1].pCell
;
1608 CellType eType
= pCell
->GetCellType();
1609 if (eType
== CELLTYPE_STRING
|| eType
== CELLTYPE_EDIT
) // nur Strings interessieren
1611 if (eType
== CELLTYPE_STRING
)
1612 ((ScStringCell
*)pCell
)->GetString(aString
);
1614 ((ScEditCell
*)pCell
)->GetString(aString
);
1616 TypedStrData
* pData
= new TypedStrData(aString
);
1617 if ( !rStrings
.Insert( pData
) )
1618 delete pData
; // doppelt
1619 else if ( bLimit
&& rStrings
.GetCount() >= DATENT_MAX
)
1620 break; // Maximum erreicht
1624 if (++nCells
>= DATENT_SEARCH
)
1625 break; // genug gesucht
1630 if ( nDownIndex
< nCount
) // nach unten
1632 ScBaseCell
* pCell
= pItems
[nDownIndex
].pCell
;
1633 CellType eType
= pCell
->GetCellType();
1634 if (eType
== CELLTYPE_STRING
|| eType
== CELLTYPE_EDIT
) // nur Strings interessieren
1636 if (eType
== CELLTYPE_STRING
)
1637 ((ScStringCell
*)pCell
)->GetString(aString
);
1639 ((ScEditCell
*)pCell
)->GetString(aString
);
1641 TypedStrData
* pData
= new TypedStrData(aString
);
1642 if ( !rStrings
.Insert( pData
) )
1643 delete pData
; // doppelt
1644 else if ( bLimit
&& rStrings
.GetCount() >= DATENT_MAX
)
1645 break; // Maximum erreicht
1649 if (++nCells
>= DATENT_SEARCH
)
1650 break; // genug gesucht
1660 #undef DATENT_SEARCH
1663 void ScColumn::RemoveProtected( SCROW nStartRow
, SCROW nEndRow
)
1665 ScAttrIterator
aAttrIter( pAttrArray
, nStartRow
, nEndRow
);
1669 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nTop
, nBottom
);
1672 const ScProtectionAttr
* pAttr
= (const ScProtectionAttr
*)&pPattern
->GetItem(ATTR_PROTECTION
);
1673 if ( pAttr
->GetHideCell() )
1674 DeleteArea( nTop
, nBottom
, IDF_CONTENTS
);
1675 else if ( pAttr
->GetHideFormula() )
1677 Search( nTop
, nIndex
);
1678 while ( nIndex
<nCount
&& pItems
[nIndex
].nRow
<=nBottom
)
1680 if ( pItems
[nIndex
].pCell
->GetCellType() == CELLTYPE_FORMULA
)
1682 ScFormulaCell
* pFormula
= (ScFormulaCell
*)pItems
[nIndex
].pCell
;
1683 if (pFormula
->IsValue())
1685 double nVal
= pFormula
->GetValue();
1686 pItems
[nIndex
].pCell
= new ScValueCell( nVal
);
1691 pFormula
->GetString(aString
);
1692 pItems
[nIndex
].pCell
= new ScStringCell( aString
);
1700 pPattern
= aAttrIter
.Next( nTop
, nBottom
);
1705 void ScColumn::SetError( SCROW nRow
, const USHORT nError
)
1709 ScFormulaCell
* pCell
= new ScFormulaCell
1710 ( pDocument
, ScAddress( nCol
, nRow
, nTab
) );
1711 pCell
->SetErrCode( nError
);
1712 Insert( nRow
, pCell
);
1717 void ScColumn::SetValue( SCROW nRow
, const double& rVal
)
1721 ScBaseCell
* pCell
= new ScValueCell(rVal
);
1722 Insert( nRow
, pCell
);
1727 void ScColumn::GetString( SCROW nRow
, String
& rString
) const
1731 if (Search(nRow
, nIndex
))
1733 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1734 if (pCell
->GetCellType() != CELLTYPE_NOTE
)
1736 ULONG nFormat
= GetNumberFormat( nRow
);
1737 ScCellFormat::GetString( pCell
, nFormat
, rString
, &pColor
, *(pDocument
->GetFormatTable()) );
1747 void ScColumn::GetInputString( SCROW nRow
, String
& rString
) const
1750 if (Search(nRow
, nIndex
))
1752 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1753 if (pCell
->GetCellType() != CELLTYPE_NOTE
)
1755 ULONG nFormat
= GetNumberFormat( nRow
);
1756 ScCellFormat::GetInputString( pCell
, nFormat
, rString
, *(pDocument
->GetFormatTable()) );
1766 double ScColumn::GetValue( SCROW nRow
) const
1769 if (Search(nRow
, nIndex
))
1771 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1772 switch (pCell
->GetCellType())
1774 case CELLTYPE_VALUE
:
1775 return ((ScValueCell
*)pCell
)->GetValue();
1777 case CELLTYPE_FORMULA
:
1779 if (((ScFormulaCell
*)pCell
)->IsValue())
1780 return ((ScFormulaCell
*)pCell
)->GetValue();
1794 void ScColumn::GetFormula( SCROW nRow
, String
& rFormula
, BOOL
) const
1797 if (Search(nRow
, nIndex
))
1799 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1800 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1801 ((ScFormulaCell
*)pCell
)->GetFormula( rFormula
);
1810 CellType
ScColumn::GetCellType( SCROW nRow
) const
1813 if (Search(nRow
, nIndex
))
1814 return pItems
[nIndex
].pCell
->GetCellType();
1815 return CELLTYPE_NONE
;
1819 USHORT
ScColumn::GetErrCode( SCROW nRow
) const
1822 if (Search(nRow
, nIndex
))
1824 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1825 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1826 return ((ScFormulaCell
*)pCell
)->GetErrCode();
1832 BOOL
ScColumn::HasStringData( SCROW nRow
) const
1835 if (Search(nRow
, nIndex
))
1836 return (pItems
[nIndex
].pCell
)->HasStringData();
1841 BOOL
ScColumn::HasValueData( SCROW nRow
) const
1844 if (Search(nRow
, nIndex
))
1845 return (pItems
[nIndex
].pCell
)->HasValueData();
1849 BOOL
ScColumn::HasStringCells( SCROW nStartRow
, SCROW nEndRow
) const
1851 // TRUE, wenn String- oder Editzellen im Bereich
1856 Search( nStartRow
, nIndex
);
1857 while ( nIndex
< nCount
&& pItems
[nIndex
].nRow
<= nEndRow
)
1859 CellType eType
= pItems
[nIndex
].pCell
->GetCellType();
1860 if ( eType
== CELLTYPE_STRING
|| eType
== CELLTYPE_EDIT
)
1869 ScPostIt
* ScColumn::GetNote( SCROW nRow
)
1872 return Search( nRow
, nIndex
) ? pItems
[ nIndex
].pCell
->GetNote() : 0;
1876 void ScColumn::TakeNote( SCROW nRow
, ScPostIt
* pNote
)
1879 if( Search( nRow
, nIndex
) )
1880 pItems
[ nIndex
].pCell
->TakeNote( pNote
);
1882 Insert( nRow
, new ScNoteCell( pNote
) );
1886 ScPostIt
* ScColumn::ReleaseNote( SCROW nRow
)
1888 ScPostIt
* pNote
= 0;
1890 if( Search( nRow
, nIndex
) )
1892 ScBaseCell
* pCell
= pItems
[ nIndex
].pCell
;
1893 pNote
= pCell
->ReleaseNote();
1894 if( (pCell
->GetCellType() == CELLTYPE_NOTE
) && !pCell
->GetBroadcaster() )
1895 DeleteAtIndex( nIndex
);
1901 void ScColumn::DeleteNote( SCROW nRow
)
1903 delete ReleaseNote( nRow
);
1907 sal_Int32
ScColumn::GetMaxStringLen( SCROW nRowStart
, SCROW nRowEnd
, CharSet eCharSet
) const
1909 sal_Int32 nStringLen
= 0;
1913 rtl::OString aOString
;
1914 bool bIsOctetTextEncoding
= rtl_isOctetTextEncoding( eCharSet
);
1915 SvNumberFormatter
* pNumFmt
= pDocument
->GetFormatTable();
1918 Search( nRowStart
, nIndex
);
1919 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRowEnd
)
1921 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1922 if ( pCell
->GetCellType() != CELLTYPE_NOTE
)
1925 ULONG nFormat
= (ULONG
) ((SfxUInt32Item
*) GetAttr(
1926 nRow
, ATTR_VALUE_FORMAT
))->GetValue();
1927 ScCellFormat::GetString( pCell
, nFormat
, aString
, &pColor
,
1930 if (bIsOctetTextEncoding
)
1932 rtl::OUString
aOUString( aString
);
1933 if (!aOUString
.convertToString( &aOString
, eCharSet
,
1934 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
1935 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
))
1937 // TODO: anything? this is used by the dBase export filter
1938 // that throws an error anyway, but in case of another
1939 // context we might want to indicate a conversion error
1942 nLen
= aOString
.getLength();
1945 nLen
= aString
.Len() * sizeof(sal_Unicode
);
1946 if ( nStringLen
< nLen
)
1956 xub_StrLen
ScColumn::GetMaxNumberStringLen( USHORT
& nPrecision
,
1957 SCROW nRowStart
, SCROW nRowEnd
) const
1959 xub_StrLen nStringLen
= 0;
1960 nPrecision
= pDocument
->GetDocOptions().GetStdPrecision();
1964 SvNumberFormatter
* pNumFmt
= pDocument
->GetFormatTable();
1967 Search( nRowStart
, nIndex
);
1968 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRowEnd
)
1970 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1971 CellType eType
= pCell
->GetCellType();
1972 if ( eType
== CELLTYPE_VALUE
|| (eType
== CELLTYPE_FORMULA
1973 && ((ScFormulaCell
*)pCell
)->IsValue()) )
1975 ULONG nFormat
= (ULONG
) ((SfxUInt32Item
*) GetAttr(
1976 nRow
, ATTR_VALUE_FORMAT
))->GetValue();
1977 ScCellFormat::GetInputString( pCell
, nFormat
, aString
, *pNumFmt
);
1978 xub_StrLen nLen
= aString
.Len();
1983 const SvNumberformat
* pEntry
= pNumFmt
->GetEntry( nFormat
);
1986 BOOL bThousand
, bNegRed
;
1988 pEntry
->GetFormatSpecialInfo(bThousand
, bNegRed
, nPrecision
, nLeading
);
1991 nPrecision
= pNumFmt
->GetFormatPrecision( nFormat
);
1994 { // less than nPrecision in string => widen it
1995 // more => shorten it
1996 String aSep
= pNumFmt
->GetFormatDecimalSep( nFormat
);
1997 xub_StrLen nTmp
= aString
.Search( aSep
);
1998 if ( nTmp
== STRING_NOTFOUND
)
1999 nLen
+= nPrecision
+ aSep
.Len();
2002 nTmp
= aString
.Len() - (nTmp
+ aSep
.Len());
2003 if ( nTmp
!= nPrecision
)
2004 nLen
+= nPrecision
- nTmp
;
2005 // nPrecision > nTmp : nLen + Diff
2006 // nPrecision < nTmp : nLen - Diff
2009 if ( nStringLen
< nLen
)