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"
59 #include <com/sun/star/i18n/LocaleDataItem.hpp>
61 using ::com::sun::star::i18n::LocaleDataItem
;
62 using ::rtl::OUString
;
63 using ::rtl::OUStringBuffer
;
66 extern const ScFormulaCell
* pLastFormulaTreeTop
; // in cellform.cxx
67 using namespace formula
;
68 // STATIC DATA -----------------------------------------------------------
70 BOOL
ScColumn::bDoubleAlloc
= FALSE
; // fuer Import: Groesse beim Allozieren verdoppeln
73 void ScColumn::Insert( SCROW nRow
, ScBaseCell
* pNewCell
)
75 BOOL bIsAppended
= FALSE
;
76 if (pItems
&& nCount
>0)
78 if (pItems
[nCount
-1].nRow
< nRow
)
80 Append(nRow
, pNewCell
);
87 if (Search(nRow
, nIndex
))
89 ScBaseCell
* pOldCell
= pItems
[nIndex
].pCell
;
91 // move broadcaster and note to new cell, if not existing in new cell
92 if (pOldCell
->HasBroadcaster() && !pNewCell
->HasBroadcaster())
93 pNewCell
->TakeBroadcaster( pOldCell
->ReleaseBroadcaster() );
94 if (pOldCell
->HasNote() && !pNewCell
->HasNote())
95 pNewCell
->TakeNote( pOldCell
->ReleaseNote() );
97 if ( pOldCell
->GetCellType() == CELLTYPE_FORMULA
&& !pDocument
->IsClipOrUndo() )
99 pOldCell
->EndListeningTo( pDocument
);
100 // falls in EndListening NoteCell in gleicher Col zerstoert
101 if ( nIndex
>= nCount
|| pItems
[nIndex
].nRow
!= nRow
)
102 Search(nRow
, nIndex
);
105 pItems
[nIndex
].pCell
= pNewCell
;
109 if (nCount
+ 1 > nLimit
)
113 if (nLimit
< COLUMN_DELTA
)
114 nLimit
= COLUMN_DELTA
;
118 if ( nLimit
> sal::static_int_cast
<SCSIZE
>(MAXROWCOUNT
) )
119 nLimit
= MAXROWCOUNT
;
123 nLimit
+= COLUMN_DELTA
;
125 ColEntry
* pNewItems
= new ColEntry
[nLimit
];
128 memmove( pNewItems
, pItems
, nCount
* sizeof(ColEntry
) );
133 memmove( &pItems
[nIndex
+ 1], &pItems
[nIndex
], (nCount
- nIndex
) * sizeof(ColEntry
) );
134 pItems
[nIndex
].pCell
= pNewCell
;
135 pItems
[nIndex
].nRow
= nRow
;
139 // Bei aus Clipboard sind hier noch falsche (alte) Referenzen!
140 // Werden in CopyBlockFromClip per UpdateReference umgesetzt,
141 // danach StartListeningFromClip und BroadcastFromClip gerufen.
142 // Wird ins Clipboard/UndoDoc gestellt, wird kein Broadcast gebraucht.
143 // Nach Import wird CalcAfterLoad gerufen, dort Listening.
144 if ( !(pDocument
->IsClipOrUndo() || pDocument
->IsInsertingFromOtherDoc()) )
146 pNewCell
->StartListeningTo( pDocument
);
147 CellType eCellType
= pNewCell
->GetCellType();
148 // Notizzelle entsteht beim Laden nur durch StartListeningCell,
149 // ausloesende Formelzelle muss sowieso dirty sein.
150 if ( !(pDocument
->IsCalcingAfterLoad() && eCellType
== CELLTYPE_NOTE
) )
152 if ( eCellType
== CELLTYPE_FORMULA
)
153 ((ScFormulaCell
*)pNewCell
)->SetDirty();
155 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
,
156 ScAddress( nCol
, nRow
, nTab
), pNewCell
) );
162 void ScColumn::Insert( SCROW nRow
, ULONG nNumberFormat
, ScBaseCell
* pCell
)
165 short eOldType
= pDocument
->GetFormatTable()->
167 ((SfxUInt32Item
*)GetAttr( nRow
, ATTR_VALUE_FORMAT
))->
169 short eNewType
= pDocument
->GetFormatTable()->GetType(nNumberFormat
);
170 if (!pDocument
->GetFormatTable()->IsCompatible(eOldType
, eNewType
))
171 ApplyAttr( nRow
, SfxUInt32Item( ATTR_VALUE_FORMAT
, (UINT32
) nNumberFormat
) );
175 void ScColumn::Append( SCROW nRow
, ScBaseCell
* pCell
)
177 if (nCount
+ 1 > nLimit
)
181 if (nLimit
< COLUMN_DELTA
)
182 nLimit
= COLUMN_DELTA
;
186 if ( nLimit
> sal::static_int_cast
<SCSIZE
>(MAXROWCOUNT
) )
187 nLimit
= MAXROWCOUNT
;
191 nLimit
+= COLUMN_DELTA
;
193 ColEntry
* pNewItems
= new ColEntry
[nLimit
];
196 memmove( pNewItems
, pItems
, nCount
* sizeof(ColEntry
) );
201 pItems
[nCount
].pCell
= pCell
;
202 pItems
[nCount
].nRow
= nRow
;
207 void ScColumn::Delete( SCROW nRow
)
211 if (Search(nRow
, nIndex
))
213 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
214 ScNoteCell
* pNoteCell
= new ScNoteCell
;
215 pItems
[nIndex
].pCell
= pNoteCell
; // Dummy fuer Interpret
216 pDocument
->Broadcast( ScHint( SC_HINT_DYING
,
217 ScAddress( nCol
, nRow
, nTab
), pCell
) );
218 if ( SvtBroadcaster
* pBC
= pCell
->ReleaseBroadcaster() )
220 pNoteCell
->TakeBroadcaster( pBC
);
226 memmove( &pItems
[nIndex
], &pItems
[nIndex
+ 1], (nCount
- nIndex
) * sizeof(ColEntry
) );
227 pItems
[nCount
].nRow
= 0;
228 pItems
[nCount
].pCell
= NULL
;
229 // Soll man hier den Speicher freigeben (delta)? Wird dann langsamer!
231 pCell
->EndListeningTo( pDocument
);
237 void ScColumn::DeleteAtIndex( SCSIZE nIndex
)
239 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
240 ScNoteCell
* pNoteCell
= new ScNoteCell
;
241 pItems
[nIndex
].pCell
= pNoteCell
; // Dummy fuer Interpret
242 pDocument
->Broadcast( ScHint( SC_HINT_DYING
,
243 ScAddress( nCol
, pItems
[nIndex
].nRow
, nTab
), pCell
) );
246 memmove( &pItems
[nIndex
], &pItems
[nIndex
+ 1], (nCount
- nIndex
) * sizeof(ColEntry
) );
247 pItems
[nCount
].nRow
= 0;
248 pItems
[nCount
].pCell
= NULL
;
249 pCell
->EndListeningTo( pDocument
);
254 void ScColumn::FreeAll()
258 for (SCSIZE i
= 0; i
< nCount
; i
++)
259 pItems
[i
].pCell
->Delete();
268 void ScColumn::DeleteRow( SCROW nStartRow
, SCSIZE nSize
)
270 pAttrArray
->DeleteRow( nStartRow
, nSize
);
272 if ( !pItems
|| !nCount
)
276 Search( nStartRow
, nFirstIndex
);
277 if ( nFirstIndex
>= nCount
)
280 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
281 pDocument
->SetAutoCalc( FALSE
); // Mehrfachberechnungen vermeiden
284 SCROW nEndRow
= nStartRow
+ nSize
- 1;
285 SCSIZE nStartIndex
= 0;
286 SCSIZE nEndIndex
= 0;
289 for ( i
= nFirstIndex
; i
< nCount
&& pItems
[i
].nRow
<= nEndRow
; i
++ )
298 ScBaseCell
* pCell
= pItems
[i
].pCell
;
299 SvtBroadcaster
* pBC
= pCell
->GetBroadcaster();
302 // gibt jetzt invalid reference, kein Aufruecken der direkten Referenzen
303 // MoveListeners( *pBC, nRow+nSize );
304 pCell
->DeleteBroadcaster();
305 // in DeleteRange werden leere Broadcaster geloescht
310 DeleteRange( nStartIndex
, nEndIndex
, IDF_CONTENTS
);
311 Search( nStartRow
, i
);
314 pDocument
->SetAutoCalc( bOldAutoCalc
);
321 ScAddress
aAdr( nCol
, 0, nTab
);
322 ScHint
aHint( SC_HINT_DATACHANGED
, aAdr
, NULL
); // only areas (ScBaseCell* == NULL)
323 ScAddress
& rAddress
= aHint
.GetAddress();
324 // for sparse occupation use single broadcasts, not ranges
325 BOOL bSingleBroadcasts
= (((pItems
[nCount
-1].nRow
- pItems
[i
].nRow
) /
327 if ( bSingleBroadcasts
)
329 SCROW nLastBroadcast
= MAXROW
+1;
330 for ( ; i
< nCount
; i
++ )
332 SCROW nOldRow
= pItems
[i
].nRow
;
333 // #43940# Aenderung Quelle broadcasten
334 rAddress
.SetRow( nOldRow
);
335 pDocument
->AreaBroadcast( aHint
);
336 SCROW nNewRow
= (pItems
[i
].nRow
-= nSize
);
337 // #43940# Aenderung Ziel broadcasten
338 if ( nLastBroadcast
!= nNewRow
)
339 { // direkt aufeinanderfolgende nicht doppelt broadcasten
340 rAddress
.SetRow( nNewRow
);
341 pDocument
->AreaBroadcast( aHint
);
343 nLastBroadcast
= nOldRow
;
344 ScBaseCell
* pCell
= pItems
[i
].pCell
;
345 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
346 ((ScFormulaCell
*)pCell
)->aPos
.SetRow( nNewRow
);
351 rAddress
.SetRow( pItems
[i
].nRow
);
352 ScRange
aRange( rAddress
);
353 aRange
.aEnd
.SetRow( pItems
[nCount
-1].nRow
);
354 for ( ; i
< nCount
; i
++ )
356 SCROW nNewRow
= (pItems
[i
].nRow
-= nSize
);
357 ScBaseCell
* pCell
= pItems
[i
].pCell
;
358 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
359 ((ScFormulaCell
*)pCell
)->aPos
.SetRow( nNewRow
);
361 pDocument
->AreaBroadcastInRange( aRange
, aHint
);
364 pDocument
->SetAutoCalc( bOldAutoCalc
);
368 void ScColumn::DeleteRange( SCSIZE nStartIndex
, SCSIZE nEndIndex
, USHORT nDelFlag
)
370 /* If caller specifies to not remove the note caption objects, all cells
371 have to forget the pointers to them. This is used e.g. while undoing a
372 "paste cells" operation, which removes the caption objects later in
374 bool bDeleteNote
= (nDelFlag
& IDF_NOTE
) != 0;
375 bool bNoCaptions
= (nDelFlag
& IDF_NOCAPTIONS
) != 0;
376 if (bDeleteNote
&& bNoCaptions
)
377 for ( SCSIZE nIdx
= nStartIndex
; nIdx
<= nEndIndex
; ++nIdx
)
378 if ( ScPostIt
* pNote
= pItems
[ nIdx
].pCell
->GetNote() )
379 pNote
->ForgetCaption();
381 // special simple mode if all contents are deleted and cells do not contain broadcasters
382 bool bSimple
= ((nDelFlag
& IDF_CONTENTS
) == IDF_CONTENTS
);
384 for ( SCSIZE nIdx
= nStartIndex
; bSimple
&& (nIdx
<= nEndIndex
); ++nIdx
)
385 if (pItems
[ nIdx
].pCell
->GetBroadcaster())
388 ScHint
aHint( SC_HINT_DYING
, ScAddress( nCol
, 0, nTab
), 0 );
390 // cache all formula cells, they will be deleted at end of this function
391 typedef ::std::vector
< ScFormulaCell
* > FormulaCellVector
;
392 FormulaCellVector aDelCells
;
393 aDelCells
.reserve( nEndIndex
- nStartIndex
+ 1 );
395 // simple deletion of the cell objects
398 // pNoteCell: dummy replacement for old cells, to prevent that interpreter uses old cell
399 ScNoteCell
* pNoteCell
= new ScNoteCell
;
400 for ( SCSIZE nIdx
= nStartIndex
; nIdx
<= nEndIndex
; ++nIdx
)
402 ScBaseCell
* pOldCell
= pItems
[ nIdx
].pCell
;
403 if (pOldCell
->GetCellType() == CELLTYPE_FORMULA
)
405 // cache formula cell, will be deleted below
406 aDelCells
.push_back( static_cast< ScFormulaCell
* >( pOldCell
) );
410 // interpret in broadcast must not use the old cell
411 pItems
[ nIdx
].pCell
= pNoteCell
;
412 aHint
.GetAddress().SetRow( pItems
[ nIdx
].nRow
);
413 aHint
.SetCell( pOldCell
);
414 pDocument
->Broadcast( aHint
);
419 memmove( &pItems
[nStartIndex
], &pItems
[nEndIndex
+ 1], (nCount
- nEndIndex
- 1) * sizeof(ColEntry
) );
420 nCount
-= nEndIndex
-nStartIndex
+1;
423 // else: delete some contents of the cells
426 SCSIZE j
= nStartIndex
;
427 for ( SCSIZE nIdx
= nStartIndex
; nIdx
<= nEndIndex
; ++nIdx
)
429 // decide whether to delete the cell object according to passed flags
430 bool bDelete
= false;
431 ScBaseCell
* pOldCell
= pItems
[j
].pCell
;
432 CellType eCellType
= pOldCell
->GetCellType();
437 USHORT nValFlags
= nDelFlag
& (IDF_DATETIME
|IDF_VALUE
);
438 // delete values and dates?
439 bDelete
= nValFlags
== (IDF_DATETIME
|IDF_VALUE
);
440 // if not, decide according to cell number format
441 if( !bDelete
&& (nValFlags
!= 0) )
443 ULONG nIndex
= (ULONG
)((SfxUInt32Item
*)GetAttr( pItems
[j
].nRow
, ATTR_VALUE_FORMAT
))->GetValue();
444 short nType
= pDocument
->GetFormatTable()->GetType(nIndex
);
445 bool bIsDate
= (nType
== NUMBERFORMAT_DATE
) || (nType
== NUMBERFORMAT_TIME
) || (nType
== NUMBERFORMAT_DATETIME
);
446 bDelete
= nValFlags
== (bIsDate
? IDF_DATETIME
: IDF_VALUE
);
451 case CELLTYPE_STRING
:
453 bDelete
= (nDelFlag
& IDF_STRING
) != 0;
456 case CELLTYPE_FORMULA
:
457 bDelete
= (nDelFlag
& IDF_FORMULA
) != 0;
461 // do note delete note cell with broadcaster
462 bDelete
= bDeleteNote
&& !pOldCell
->GetBroadcaster();
465 default:; // added to avoid warnings
470 // try to create a replacement note cell, if note or broadcaster exists
471 ScNoteCell
* pNoteCell
= 0;
472 if (eCellType
!= CELLTYPE_NOTE
)
474 // do not rescue note if it has to be deleted according to passed flags
475 ScPostIt
* pNote
= bDeleteNote
? 0 : pOldCell
->ReleaseNote();
476 // #i99844# do not release broadcaster from old cell, it still has to notify deleted content
477 SvtBroadcaster
* pBC
= pOldCell
->GetBroadcaster();
479 pNoteCell
= new ScNoteCell( pNote
, pBC
);
482 // remove cell entry in cell item list
483 SCROW nOldRow
= pItems
[j
].nRow
;
486 // replace old cell with the replacement note cell
487 pItems
[j
].pCell
= pNoteCell
;
492 // remove the old cell from the cell item list
494 memmove( &pItems
[j
], &pItems
[j
+ 1], (nCount
- j
) * sizeof(ColEntry
) );
495 pItems
[nCount
].nRow
= 0;
496 pItems
[nCount
].pCell
= 0;
499 // cache formula cells (will be deleted later), delete cell of other type
500 if (eCellType
== CELLTYPE_FORMULA
)
502 aDelCells
.push_back( static_cast< ScFormulaCell
* >( pOldCell
) );
506 aHint
.GetAddress().SetRow( nOldRow
);
507 aHint
.SetCell( pOldCell
);
508 pDocument
->Broadcast( aHint
);
509 // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by pNoteCell)
510 pOldCell
->ReleaseBroadcaster();
518 pItems
[j
].pCell
->DeleteNote();
519 // cell not deleted, move index to next cell
525 // *** delete all formula cells ***
527 // first, all cells stop listening, may save unneeded recalcualtions
528 for ( FormulaCellVector::iterator aIt
= aDelCells
.begin(), aEnd
= aDelCells
.end(); aIt
!= aEnd
; ++aIt
)
529 (*aIt
)->EndListeningTo( pDocument
);
531 // #i101869# if the note cell with the broadcaster was deleted in EndListening,
532 // forget the pointer to the broadcaster
533 for ( FormulaCellVector::iterator aIt
= aDelCells
.begin(), aEnd
= aDelCells
.end(); aIt
!= aEnd
; ++aIt
)
536 if ( !Search( (*aIt
)->aPos
.Row(), nIndex
) )
537 (*aIt
)->ReleaseBroadcaster();
540 // broadcast SC_HINT_DYING for all cells and delete them
541 for ( FormulaCellVector::iterator aIt
= aDelCells
.begin(), aEnd
= aDelCells
.end(); aIt
!= aEnd
; ++aIt
)
543 aHint
.SetAddress( (*aIt
)->aPos
);
544 aHint
.SetCell( *aIt
);
545 pDocument
->Broadcast( aHint
);
546 // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by replacement note cell)
547 (*aIt
)->ReleaseBroadcaster();
553 void ScColumn::DeleteArea(SCROW nStartRow
, SCROW nEndRow
, USHORT nDelFlag
)
555 // FreeAll darf hier nicht gerufen werden wegen Broadcastern
557 // Attribute erst am Ende, damit vorher noch zwischen Zahlen und Datum
558 // unterschieden werden kann (#47901#)
560 USHORT nContMask
= IDF_CONTENTS
;
561 // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
562 if( nDelFlag
& IDF_NOTE
)
563 nContMask
|= IDF_NOCAPTIONS
;
564 USHORT nContFlag
= nDelFlag
& nContMask
;
566 if (pItems
&& nCount
>0 && nContFlag
)
568 if (nStartRow
==0 && nEndRow
==MAXROW
)
569 DeleteRange( 0, nCount
-1, nContFlag
);
573 SCSIZE nStartIndex
= 0;
574 SCSIZE nEndIndex
= 0;
575 for (SCSIZE i
= 0; i
< nCount
; i
++)
576 if ((pItems
[i
].nRow
>= nStartRow
) && (pItems
[i
].nRow
<= nEndRow
))
586 DeleteRange( nStartIndex
, nEndIndex
, nContFlag
);
590 if ( nDelFlag
& IDF_EDITATTR
)
592 DBG_ASSERT( nContFlag
== 0, "DeleteArea: falsche Flags" );
593 RemoveEditAttribs( nStartRow
, nEndRow
);
596 // Attribute erst hier
597 if ((nDelFlag
& IDF_ATTRIB
) == IDF_ATTRIB
) pAttrArray
->DeleteArea( nStartRow
, nEndRow
);
598 else if ((nDelFlag
& IDF_ATTRIB
) != 0) pAttrArray
->DeleteHardAttr( nStartRow
, nEndRow
);
602 ScFormulaCell
* ScColumn::CreateRefCell( ScDocument
* pDestDoc
, const ScAddress
& rDestPos
,
603 SCSIZE nIndex
, USHORT nFlags
) const
605 USHORT nContFlags
= nFlags
& IDF_CONTENTS
;
609 // Testen, ob Zelle kopiert werden soll
610 // auch bei IDF_CONTENTS komplett, wegen Notes / Broadcastern
613 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
614 CellType eCellType
= pCell
->GetCellType();
619 USHORT nValFlags
= nFlags
& (IDF_DATETIME
|IDF_VALUE
);
621 if ( nValFlags
== (IDF_DATETIME
|IDF_VALUE
) )
623 else if ( nValFlags
)
625 ULONG nNumIndex
= (ULONG
)((SfxUInt32Item
*)GetAttr(
626 pItems
[nIndex
].nRow
, ATTR_VALUE_FORMAT
))->GetValue();
627 short nTyp
= pDocument
->GetFormatTable()->GetType(nNumIndex
);
628 if ((nTyp
== NUMBERFORMAT_DATE
) || (nTyp
== NUMBERFORMAT_TIME
) || (nTyp
== NUMBERFORMAT_DATETIME
))
629 bMatch
= ((nFlags
& IDF_DATETIME
) != 0);
631 bMatch
= ((nFlags
& IDF_VALUE
) != 0);
635 case CELLTYPE_STRING
:
636 case CELLTYPE_EDIT
: bMatch
= ((nFlags
& IDF_STRING
) != 0); break;
637 case CELLTYPE_FORMULA
: bMatch
= ((nFlags
& IDF_FORMULA
) != 0); break;
640 // added to avoid warnings
647 // Referenz einsetzen
648 ScSingleRefData aRef
;
650 aRef
.nRow
= pItems
[nIndex
].nRow
;
652 aRef
.InitFlags(); // -> alles absolut
653 aRef
.SetFlag3D(TRUE
);
655 //! 3D(FALSE) und TabRel(TRUE), wenn die endgueltige Position auf der selben Tabelle ist?
656 //! (bei TransposeClip ist die Zielposition noch nicht bekannt)
658 aRef
.CalcRelFromAbs( rDestPos
);
661 aArr
.AddSingleReference( aRef
);
663 return new ScFormulaCell( pDestDoc
, rDestPos
, &aArr
);
668 // nRow1, nRow2 = Zielposition
670 void ScColumn::CopyFromClip(SCROW nRow1
, SCROW nRow2
, long nDy
,
671 USHORT nInsFlag
, BOOL bAsLink
, BOOL bSkipAttrForEmpty
,
674 if ((nInsFlag
& IDF_ATTRIB
) != 0)
676 if ( bSkipAttrForEmpty
)
678 // copy only attributes for non-empty cells
679 // (notes are not counted as non-empty here, to match the content behavior)
682 rColumn
.Search( nRow1
-nDy
, nStartIndex
);
683 while ( nStartIndex
< rColumn
.nCount
&& rColumn
.pItems
[nStartIndex
].nRow
<= nRow2
-nDy
)
685 SCSIZE nEndIndex
= nStartIndex
;
686 if ( rColumn
.pItems
[nStartIndex
].pCell
->GetCellType() != CELLTYPE_NOTE
)
688 SCROW nStartRow
= rColumn
.pItems
[nStartIndex
].nRow
;
689 SCROW nEndRow
= nStartRow
;
691 // find consecutive non-empty cells
693 while ( nEndRow
< nRow2
-nDy
&&
694 nEndIndex
+1 < rColumn
.nCount
&&
695 rColumn
.pItems
[nEndIndex
+1].nRow
== nEndRow
+1 &&
696 rColumn
.pItems
[nEndIndex
+1].pCell
->GetCellType() != CELLTYPE_NOTE
)
702 rColumn
.pAttrArray
->CopyAreaSafe( nStartRow
+nDy
, nEndRow
+nDy
, nDy
, *pAttrArray
);
704 nStartIndex
= nEndIndex
+ 1;
708 rColumn
.pAttrArray
->CopyAreaSafe( nRow1
, nRow2
, nDy
, *pAttrArray
);
710 if ((nInsFlag
& IDF_CONTENTS
) == 0)
713 if ( bAsLink
&& nInsFlag
== IDF_ALL
)
715 // bei "alles" werden auch leere Zellen referenziert
716 //! IDF_ALL muss immer mehr Flags enthalten, als bei "Inhalte Einfuegen"
717 //! einzeln ausgewaehlt werden koennen!
719 Resize( nCount
+ static_cast<SCSIZE
>(nRow2
-nRow1
+1) );
721 ScAddress
aDestPos( nCol
, 0, nTab
); // Row wird angepasst
723 // Referenz erzeugen (Quell-Position)
724 ScSingleRefData aRef
;
725 aRef
.nCol
= rColumn
.nCol
;
726 // nRow wird angepasst
727 aRef
.nTab
= rColumn
.nTab
;
728 aRef
.InitFlags(); // -> alles absolut
729 aRef
.SetFlag3D(TRUE
);
731 for (SCROW nDestRow
= nRow1
; nDestRow
<= nRow2
; nDestRow
++)
733 aRef
.nRow
= nDestRow
- nDy
; // Quell-Zeile
734 aDestPos
.SetRow( nDestRow
);
736 aRef
.CalcRelFromAbs( aDestPos
);
738 aArr
.AddSingleReference( aRef
);
739 Insert( nDestRow
, new ScFormulaCell( pDocument
, aDestPos
, &aArr
) );
745 SCSIZE nColCount
= rColumn
.nCount
;
747 // ignore IDF_FORMULA - "all contents but no formulas" results in the same number of cells
748 if ((nInsFlag
& ( IDF_CONTENTS
& ~IDF_FORMULA
)) == ( IDF_CONTENTS
& ~IDF_FORMULA
) && nRow2
-nRow1
>= 64)
750 //! Always do the Resize from the outside, where the number of repetitions is known
751 //! (then it can be removed here)
753 SCSIZE nNew
= nCount
+ nColCount
;
758 // IDF_ADDNOTES must be passed without other content flags than IDF_NOTE
759 bool bAddNotes
= (nInsFlag
& (IDF_CONTENTS
| IDF_ADDNOTES
)) == (IDF_NOTE
| IDF_ADDNOTES
);
762 for (SCSIZE i
= 0; i
< nColCount
&& !bAtEnd
; i
++)
764 SCsROW nDestRow
= rColumn
.pItems
[i
].nRow
+ nDy
;
765 if ( nDestRow
> (SCsROW
) nRow2
)
767 else if ( nDestRow
>= (SCsROW
) nRow1
)
769 // rows at the beginning may be skipped if filtered rows are left out,
770 // nDestRow may be negative then
772 ScAddress
aDestPos( nCol
, (SCROW
)nDestRow
, nTab
);
774 /* #i102056# Paste from clipboard needs to paste the cell notes in
775 a second pass. This must not overwrite the existing cells
776 already copied to the destination position in the first pass.
777 To indicate this special case, the modifier IDF_ADDNOTES is
778 passed together with IDF_NOTE in nInsFlag. Of course, there is
779 still the need to create a new cell, if there is no cell at the
780 destination position at all. */
781 ScBaseCell
* pAddNoteCell
= bAddNotes
? GetCell( aDestPos
.Row() ) : 0;
784 // do nothing if source cell does not contain a note
785 const ScBaseCell
* pSourceCell
= rColumn
.pItems
[i
].pCell
;
786 const ScPostIt
* pSourceNote
= pSourceCell
? pSourceCell
->GetNote() : 0;
789 DBG_ASSERT( !pAddNoteCell
->HasNote(), "ScColumn::CopyFromClip - unexpected note at destination cell" );
790 bool bCloneCaption
= (nInsFlag
& IDF_NOCAPTIONS
) == 0;
791 // #i52342# if caption is cloned, the note must be constructed with the destination document
792 ScAddress
aSourcePos( rColumn
.nCol
, rColumn
.pItems
[i
].nRow
, rColumn
.nTab
);
793 ScPostIt
* pNewNote
= pSourceNote
->Clone( aSourcePos
, *pDocument
, aDestPos
, bCloneCaption
);
794 pAddNoteCell
->TakeNote( pNewNote
);
799 ScBaseCell
* pNewCell
= bAsLink
?
800 rColumn
.CreateRefCell( pDocument
, aDestPos
, i
, nInsFlag
) :
801 rColumn
.CloneCell( i
, nInsFlag
, *pDocument
, aDestPos
);
803 Insert( aDestPos
.Row(), pNewCell
);
812 /** Helper for ScColumn::CloneCell - decides whether to clone a value cell depending on clone flags and number format. */
813 bool lclCanCloneValue( ScDocument
& rDoc
, const ScColumn
& rCol
, SCROW nRow
, bool bCloneValue
, bool bCloneDateTime
)
815 // values and dates, or nothing to be cloned -> not needed to check number format
816 if( bCloneValue
== bCloneDateTime
)
819 // check number format of value cell
820 ULONG nNumIndex
= (ULONG
)((SfxUInt32Item
*)rCol
.GetAttr( nRow
, ATTR_VALUE_FORMAT
))->GetValue();
821 short nTyp
= rDoc
.GetFormatTable()->GetType( nNumIndex
);
822 bool bIsDateTime
= (nTyp
== NUMBERFORMAT_DATE
) || (nTyp
== NUMBERFORMAT_TIME
) || (nTyp
== NUMBERFORMAT_DATETIME
);
823 return bIsDateTime
? bCloneDateTime
: bCloneValue
;
829 ScBaseCell
* ScColumn::CloneCell(SCSIZE nIndex
, USHORT nFlags
, ScDocument
& rDestDoc
, const ScAddress
& rDestPos
)
831 bool bCloneValue
= (nFlags
& IDF_VALUE
) != 0;
832 bool bCloneDateTime
= (nFlags
& IDF_DATETIME
) != 0;
833 bool bCloneString
= (nFlags
& IDF_STRING
) != 0;
834 bool bCloneSpecialBoolean
= (nFlags
& IDF_SPECIAL_BOOLEAN
) != 0;
835 bool bCloneFormula
= (nFlags
& IDF_FORMULA
) != 0;
836 bool bCloneNote
= (nFlags
& IDF_NOTE
) != 0;
837 bool bForceFormula
= false;
839 ScBaseCell
* pNew
= 0;
840 ScBaseCell
& rSource
= *pItems
[nIndex
].pCell
;
841 switch (rSource
.GetCellType())
844 // note will be cloned below
847 case CELLTYPE_STRING
:
849 // note will be cloned below
851 pNew
= rSource
.CloneWithoutNote( rDestDoc
, rDestPos
);
855 // note will be cloned below
856 if (lclCanCloneValue( *pDocument
, *this, pItems
[nIndex
].nRow
, bCloneValue
, bCloneDateTime
))
857 pNew
= rSource
.CloneWithoutNote( rDestDoc
, rDestPos
);
860 case CELLTYPE_FORMULA
:
861 if ( bCloneSpecialBoolean
)
863 ScFormulaCell
& rForm
= (ScFormulaCell
&)rSource
;
864 rtl::OUStringBuffer aBuf
;
865 // #TODO #FIXME do we have a localisation issue here?
866 rForm
.GetFormula( aBuf
);
867 rtl::OUString
aVal( aBuf
.makeStringAndClear() );
868 if ( aVal
.equalsAscii( "=TRUE()" )
869 || aVal
.equalsAscii( "=FALSE()" ) )
870 bForceFormula
= true;
872 if (bForceFormula
|| bCloneFormula
)
874 // note will be cloned below
875 pNew
= rSource
.CloneWithoutNote( rDestDoc
, rDestPos
);
877 else if ( (bCloneValue
|| bCloneDateTime
|| bCloneString
) && !rDestDoc
.IsUndo() )
879 // #48491# ins Undo-Dokument immer nur die Original-Zelle kopieren,
880 // aus Formeln keine Value/String-Zellen erzeugen
881 ScFormulaCell
& rForm
= (ScFormulaCell
&)rSource
;
882 USHORT nErr
= rForm
.GetErrCode();
885 // error codes are cloned with values
888 ScFormulaCell
* pErrCell
= new ScFormulaCell( &rDestDoc
, rDestPos
);
889 pErrCell
->SetErrCode( nErr
);
893 else if (rForm
.IsValue())
895 if (lclCanCloneValue( *pDocument
, *this, pItems
[nIndex
].nRow
, bCloneValue
, bCloneDateTime
))
897 double nVal
= rForm
.GetValue();
898 pNew
= new ScValueCell(nVal
);
901 else if (bCloneString
)
904 rForm
.GetString( aString
);
905 // #33224# do not clone empty string
906 if (aString
.Len() > 0)
908 if ( rForm
.IsMultilineResult() )
910 pNew
= new ScEditCell( aString
, &rDestDoc
);
914 pNew
= new ScStringCell( aString
);
921 default: DBG_ERRORFILE( "ScColumn::CloneCell - unknown cell type" );
924 // clone the cell note
927 if (ScPostIt
* pNote
= rSource
.GetNote())
929 bool bCloneCaption
= (nFlags
& IDF_NOCAPTIONS
) == 0;
930 // #i52342# if caption is cloned, the note must be constructed with the destination document
931 ScAddress
aOwnPos( nCol
, pItems
[nIndex
].nRow
, nTab
);
932 ScPostIt
* pNewNote
= pNote
->Clone( aOwnPos
, rDestDoc
, rDestPos
, bCloneCaption
);
934 pNew
= new ScNoteCell( pNewNote
);
936 pNew
->TakeNote( pNewNote
);
944 void ScColumn::MixMarked( const ScMarkData
& rMark
, USHORT nFunction
,
945 BOOL bSkipEmpty
, ScColumn
& rSrcCol
)
949 if (rMark
.IsMultiMarked())
951 ScMarkArrayIter
aIter( rMark
.GetArray()+nCol
);
952 while (aIter
.Next( nRow1
, nRow2
))
953 MixData( nRow1
, nRow2
, nFunction
, bSkipEmpty
, rSrcCol
);
960 BOOL
lcl_DoFunction( double& rVal1
, double nVal2
, USHORT nFunction
)
966 bOk
= SubTotal::SafePlus( rVal1
, nVal2
);
969 nVal2
= -nVal2
; //! geht das immer ohne Fehler?
970 bOk
= SubTotal::SafePlus( rVal1
, nVal2
);
973 bOk
= SubTotal::SafeMult( rVal1
, nVal2
);
976 bOk
= SubTotal::SafeDiv( rVal1
, nVal2
);
983 void lcl_AddCode( ScTokenArray
& rArr
, ScFormulaCell
* pCell
)
985 rArr
.AddOpCode(ocOpen
);
987 ScTokenArray
* pCode
= pCell
->GetCode();
990 const formula::FormulaToken
* pToken
= pCode
->First();
993 rArr
.AddToken( *pToken
);
994 pToken
= pCode
->Next();
998 rArr
.AddOpCode(ocClose
);
1002 void ScColumn::MixData( SCROW nRow1
, SCROW nRow2
,
1003 USHORT nFunction
, BOOL bSkipEmpty
,
1006 SCSIZE nSrcCount
= rSrcCol
.nCount
;
1009 Search( nRow1
, nIndex
);
1011 // SCSIZE nSrcIndex = 0;
1013 rSrcCol
.Search( nRow1
, nSrcIndex
); //! Testen, ob Daten ganz vorne
1015 SCROW nNextThis
= MAXROW
+1;
1016 if ( nIndex
< nCount
)
1017 nNextThis
= pItems
[nIndex
].nRow
;
1018 SCROW nNextSrc
= MAXROW
+1;
1019 if ( nSrcIndex
< nSrcCount
)
1020 nNextSrc
= rSrcCol
.pItems
[nSrcIndex
].nRow
;
1022 while ( nNextThis
<= nRow2
|| nNextSrc
<= nRow2
)
1024 SCROW nRow
= Min( nNextThis
, nNextSrc
);
1026 ScBaseCell
* pSrc
= NULL
;
1027 ScBaseCell
* pDest
= NULL
;
1028 ScBaseCell
* pNew
= NULL
;
1029 BOOL bDelete
= FALSE
;
1031 if ( nSrcIndex
< nSrcCount
&& nNextSrc
== nRow
)
1032 pSrc
= rSrcCol
.pItems
[nSrcIndex
].pCell
;
1034 if ( nIndex
< nCount
&& nNextThis
== nRow
)
1035 pDest
= pItems
[nIndex
].pCell
;
1037 DBG_ASSERT( pSrc
|| pDest
, "Nanu ?" );
1039 CellType eSrcType
= pSrc
? pSrc
->GetCellType() : CELLTYPE_NONE
;
1040 CellType eDestType
= pDest
? pDest
->GetCellType() : CELLTYPE_NONE
;
1042 BOOL bSrcEmpty
= ( eSrcType
== CELLTYPE_NONE
|| eSrcType
== CELLTYPE_NOTE
);
1043 BOOL bDestEmpty
= ( eDestType
== CELLTYPE_NONE
|| eDestType
== CELLTYPE_NOTE
);
1045 if ( bSkipEmpty
&& bDestEmpty
) // Originalzelle wiederherstellen
1047 if ( pSrc
) // war da eine Zelle?
1049 pNew
= pSrc
->CloneWithoutNote( *pDocument
);
1052 else if ( nFunction
) // wirklich Rechenfunktion angegeben
1056 if ( eSrcType
== CELLTYPE_VALUE
)
1057 nVal1
= ((ScValueCell
*)pSrc
)->GetValue();
1060 if ( eDestType
== CELLTYPE_VALUE
)
1061 nVal2
= ((ScValueCell
*)pDest
)->GetValue();
1065 // leere Zellen werden als Werte behandelt
1067 BOOL bSrcVal
= ( bSrcEmpty
|| eSrcType
== CELLTYPE_VALUE
);
1068 BOOL bDestVal
= ( bDestEmpty
|| eDestType
== CELLTYPE_VALUE
);
1070 BOOL bSrcText
= ( eSrcType
== CELLTYPE_STRING
||
1071 eSrcType
== CELLTYPE_EDIT
);
1072 BOOL bDestText
= ( eDestType
== CELLTYPE_STRING
||
1073 eDestType
== CELLTYPE_EDIT
);
1075 // sonst bleibt nur Formel...
1077 if ( bSrcEmpty
&& bDestEmpty
)
1079 // beide leer -> nix
1081 else if ( bSrcVal
&& bDestVal
)
1083 // neuen Wert eintragen, oder Fehler bei Ueberlauf
1085 BOOL bOk
= lcl_DoFunction( nVal1
, nVal2
, nFunction
);
1088 pNew
= new ScValueCell( nVal1
);
1091 ScFormulaCell
* pFC
= new ScFormulaCell( pDocument
,
1092 ScAddress( nCol
, nRow
, nTab
) );
1093 pFC
->SetErrCode( errNoValue
);
1094 //! oder NOVALUE, dann auch in consoli,
1095 //! sonst in Interpreter::GetCellValue die Abfrage auf errNoValue raus
1096 //! (dann geht Stringzelle+Wertzelle nicht mehr)
1100 else if ( bSrcText
|| bDestText
)
1102 // mit Texten wird nicht gerechnet - immer "alte" Zelle, also pSrc
1105 pNew
= pSrc
->CloneWithoutNote( *pDocument
);
1111 // Kombination aus Wert und mindestens einer Formel -> Formel erzeugen
1116 if ( eSrcType
== CELLTYPE_FORMULA
)
1117 lcl_AddCode( aArr
, (ScFormulaCell
*)pSrc
);
1119 aArr
.AddDouble( nVal1
);
1123 switch ( nFunction
)
1125 case PASTE_ADD
: eOp
= ocAdd
; break;
1126 case PASTE_SUB
: eOp
= ocSub
; break;
1127 case PASTE_MUL
: eOp
= ocMul
; break;
1128 case PASTE_DIV
: eOp
= ocDiv
; break;
1130 aArr
.AddOpCode(eOp
); // Funktion
1133 if ( eDestType
== CELLTYPE_FORMULA
)
1134 lcl_AddCode( aArr
, (ScFormulaCell
*)pDest
);
1136 aArr
.AddDouble( nVal2
);
1138 pNew
= new ScFormulaCell( pDocument
, ScAddress( nCol
, nRow
, nTab
), &aArr
);
1143 if ( pNew
|| bDelete
) // neues Ergebnis ?
1145 if (pDest
&& !pNew
) // alte Zelle da ?
1147 if ( pDest
->GetBroadcaster() )
1148 pNew
= new ScNoteCell
; // Broadcaster uebernehmen
1150 Delete(nRow
); // -> loeschen
1153 Insert(nRow
, pNew
); // neue einfuegen
1155 Search( nRow
, nIndex
); // alles kann sich verschoben haben
1157 nNextThis
= nRow
; // nIndex zeigt jetzt genau auf nRow
1159 nNextThis
= ( nIndex
< nCount
) ? pItems
[nIndex
].nRow
: MAXROW
+1;
1162 if ( nNextThis
== nRow
)
1165 nNextThis
= ( nIndex
< nCount
) ? pItems
[nIndex
].nRow
: MAXROW
+1;
1167 if ( nNextSrc
== nRow
)
1170 nNextSrc
= ( nSrcIndex
< nSrcCount
) ?
1171 rSrcCol
.pItems
[nSrcIndex
].nRow
:
1178 ScAttrIterator
* ScColumn::CreateAttrIterator( SCROW nStartRow
, SCROW nEndRow
) const
1180 return new ScAttrIterator( pAttrArray
, nStartRow
, nEndRow
);
1184 void ScColumn::StartAllListeners()
1187 for (SCSIZE i
= 0; i
< nCount
; i
++)
1189 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1190 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1192 SCROW nRow
= pItems
[i
].nRow
;
1193 ((ScFormulaCell
*)pCell
)->StartListeningTo( pDocument
);
1194 if ( nRow
!= pItems
[i
].nRow
)
1195 Search( nRow
, i
); // Listener eingefuegt?
1201 void ScColumn::StartNeededListeners()
1205 for (SCSIZE i
= 0; i
< nCount
; i
++)
1207 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1208 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1210 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1211 if (pFCell
->NeedsListening())
1213 SCROW nRow
= pItems
[i
].nRow
;
1214 pFCell
->StartListeningTo( pDocument
);
1215 if ( nRow
!= pItems
[i
].nRow
)
1216 Search( nRow
, i
); // Listener eingefuegt?
1224 void ScColumn::BroadcastInArea( SCROW nRow1
, SCROW nRow2
)
1230 Search( nRow1
, nIndex
);
1231 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRow2
)
1233 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1234 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1235 ((ScFormulaCell
*)pCell
)->SetDirty();
1237 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
,
1238 ScAddress( nCol
, nRow
, nTab
), pCell
) );
1245 void ScColumn::StartListeningInArea( SCROW nRow1
, SCROW nRow2
)
1251 Search( nRow1
, nIndex
);
1252 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRow2
)
1254 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1255 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1256 ((ScFormulaCell
*)pCell
)->StartListeningTo( pDocument
);
1257 if ( nRow
!= pItems
[nIndex
].nRow
)
1258 Search( nRow
, nIndex
); // durch Listening eingefuegt
1265 // TRUE = Zahlformat gesetzt
1266 BOOL
ScColumn::SetString( SCROW nRow
, SCTAB nTabP
, const String
& rString
,
1267 formula::FormulaGrammar::AddressConvention eConv
,
1268 SvNumberFormatter
* pFormatter
, bool bDetectNumberFormat
)
1270 BOOL bNumFmtSet
= FALSE
;
1273 ScBaseCell
* pNewCell
= NULL
;
1274 BOOL bIsLoading
= FALSE
;
1275 if (rString
.Len() > 0)
1278 sal_uInt32 nIndex
, nOldIndex
= 0;
1279 sal_Unicode cFirstChar
;
1281 pFormatter
= pDocument
->GetFormatTable();
1282 SfxObjectShell
* pDocSh
= pDocument
->GetDocumentShell();
1284 bIsLoading
= pDocSh
->IsLoading();
1285 // IsLoading bei ConvertFrom Import
1288 nIndex
= nOldIndex
= GetNumberFormat( nRow
);
1289 if ( rString
.Len() > 1
1290 && pFormatter
->GetType(nIndex
) != NUMBERFORMAT_TEXT
)
1291 cFirstChar
= rString
.GetChar(0);
1293 cFirstChar
= 0; // Text
1296 { // waehrend ConvertFrom Import gibt es keine gesetzten Formate
1297 cFirstChar
= rString
.GetChar(0);
1300 if ( cFirstChar
== '=' )
1302 if ( rString
.Len() == 1 ) // = Text
1303 pNewCell
= new ScStringCell( rString
);
1305 pNewCell
= new ScFormulaCell( pDocument
,
1306 ScAddress( nCol
, nRow
, nTabP
), rString
,
1307 formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_DEFAULT
,
1310 else if ( cFirstChar
== '\'') // 'Text
1311 pNewCell
= new ScStringCell( rString
.Copy(1) );
1314 BOOL bIsText
= FALSE
;
1317 if ( pItems
&& nCount
)
1321 SCSIZE nStop
= (i
>= 3 ? i
- 3 : 0);
1322 // die letzten Zellen vergleichen, ob gleicher String
1323 // und IsNumberFormat eingespart werden kann
1327 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1328 switch ( pCell
->GetCellType() )
1330 case CELLTYPE_STRING
:
1331 ((ScStringCell
*)pCell
)->GetString( aStr
);
1332 if ( rString
== aStr
)
1335 case CELLTYPE_NOTE
: // durch =Formel referenziert
1338 if ( i
== nCount
- 1 )
1340 // wahrscheinlich ganze Spalte kein String
1342 } while ( i
&& i
> nStop
&& !bIsText
);
1344 // nIndex fuer IsNumberFormat vorbelegen
1346 nIndex
= nOldIndex
= pFormatter
->GetStandardIndex();
1354 if (bDetectNumberFormat
)
1356 if (!pFormatter
->IsNumberFormat(rString
, nIndex
, nVal
))
1359 pNewCell
= new ScValueCell( nVal
);
1360 if ( nIndex
!= nOldIndex
)
1362 // #i22345# New behavior: Apply the detected number format only if
1363 // the old one was the default number, date, time or boolean format.
1364 // Exception: If the new format is boolean, always apply it.
1366 BOOL bOverwrite
= FALSE
;
1367 const SvNumberformat
* pOldFormat
= pFormatter
->GetEntry( nOldIndex
);
1370 short nOldType
= pOldFormat
->GetType() & ~NUMBERFORMAT_DEFINED
;
1371 if ( nOldType
== NUMBERFORMAT_NUMBER
|| nOldType
== NUMBERFORMAT_DATE
||
1372 nOldType
== NUMBERFORMAT_TIME
|| nOldType
== NUMBERFORMAT_LOGICAL
)
1374 if ( nOldIndex
== pFormatter
->GetStandardFormat(
1375 nOldType
, pOldFormat
->GetLanguage() ) )
1377 bOverwrite
= TRUE
; // default of these types can be overwritten
1381 if ( !bOverwrite
&& pFormatter
->GetType( nIndex
) == NUMBERFORMAT_LOGICAL
)
1383 bOverwrite
= TRUE
; // overwrite anything if boolean was detected
1388 ApplyAttr( nRow
, SfxUInt32Item( ATTR_VALUE_FORMAT
,
1396 // Only check if the string is a regular number.
1397 const LocaleDataWrapper
* pLocale
= pFormatter
->GetLocaleData();
1401 LocaleDataItem aLocaleItem
= pLocale
->getLocaleItem();
1402 const OUString
& rDecSep
= aLocaleItem
.decimalSeparator
;
1403 const OUString
& rGroupSep
= aLocaleItem
.thousandSeparator
;
1404 if (rDecSep
.getLength() != 1 || rGroupSep
.getLength() != 1)
1407 sal_Unicode dsep
= rDecSep
.getStr()[0];
1408 sal_Unicode gsep
= rGroupSep
.getStr()[0];
1410 if (!ScStringUtil::parseSimpleNumber(rString
, dsep
, gsep
, nVal
))
1413 pNewCell
= new ScValueCell(nVal
);
1419 pNewCell
= new ScStringCell(rString
);
1423 if ( bIsLoading
&& (!nCount
|| nRow
> pItems
[nCount
-1].nRow
) )
1424 { // Search einsparen und ohne Umweg ueber Insert, Listener aufbauen
1425 // und Broadcast kommt eh erst nach dem Laden
1427 Append( nRow
, pNewCell
);
1432 if (Search(nRow
, i
))
1434 ScBaseCell
* pOldCell
= pItems
[i
].pCell
;
1435 ScPostIt
* pNote
= pOldCell
->ReleaseNote();
1436 SvtBroadcaster
* pBC
= pOldCell
->ReleaseBroadcaster();
1437 if (pNewCell
|| pNote
|| pBC
)
1440 pNewCell
->TakeNote( pNote
);
1442 pNewCell
= new ScNoteCell( pNote
);
1445 pNewCell
->TakeBroadcaster(pBC
);
1446 pLastFormulaTreeTop
= 0; // Err527 Workaround
1449 if ( pOldCell
->GetCellType() == CELLTYPE_FORMULA
)
1451 pOldCell
->EndListeningTo( pDocument
);
1452 // falls in EndListening NoteCell in gleicher Col zerstoert
1453 if ( i
>= nCount
|| pItems
[i
].nRow
!= nRow
)
1457 pItems
[i
].pCell
= pNewCell
; // ersetzen
1458 if ( pNewCell
->GetCellType() == CELLTYPE_FORMULA
)
1460 pNewCell
->StartListeningTo( pDocument
);
1461 ((ScFormulaCell
*)pNewCell
)->SetDirty();
1464 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
,
1465 ScAddress( nCol
, nRow
, nTabP
), pNewCell
) );
1469 DeleteAtIndex(i
); // loeschen und Broadcast
1474 Insert(nRow
, pNewCell
); // neu eintragen und Broadcast
1478 // hier keine Formate mehr fuer Formeln setzen!
1479 // (werden bei der Ausgabe abgefragt)
1486 void ScColumn::GetFilterEntries(SCROW nStartRow
, SCROW nEndRow
, TypedScStrCollection
& rStrings
)
1488 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
1493 Search( nStartRow
, nIndex
);
1495 while ( (nIndex
< nCount
) ? ((nRow
=pItems
[nIndex
].nRow
) <= nEndRow
) : FALSE
)
1497 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1498 TypedStrData
* pData
;
1499 ULONG nFormat
= GetNumberFormat( nRow
);
1501 ScCellFormat::GetInputString( pCell
, nFormat
, aString
, *pFormatter
);
1503 if ( pDocument
->HasStringData( nCol
, nRow
, nTab
) )
1504 pData
= new TypedStrData( aString
);
1509 switch ( pCell
->GetCellType() )
1511 case CELLTYPE_VALUE
:
1512 nValue
= ((ScValueCell
*)pCell
)->GetValue();
1515 case CELLTYPE_FORMULA
:
1516 nValue
= ((ScFormulaCell
*)pCell
)->GetValue();
1523 pData
= new TypedStrData( aString
, nValue
, SC_STRTYPE_VALUE
);
1526 ScPostIt
aCellNote( ScPostIt::UNINITIALIZED
);
1527 // Hide visible notes during Filtering.
1528 if(pCell
->GetNote(aCellNote
) && aCellNote
.IsCaptionShown())
1530 ScDetectiveFunc( pDocument
, nTab
).HideComment( nCol
, nRow
);
1531 aCellNote
.SetShown( false );
1532 pCell
->SetNote(aCellNote
);
1536 if ( !rStrings
.Insert( pData
) )
1537 delete pData
; // doppelt
1544 // GetDataEntries - Strings aus zusammenhaengendem Bereich um nRow
1547 // DATENT_MAX - max. Anzahl Eintrage in Liste fuer Auto-Eingabe
1548 // DATENT_SEARCH - max. Anzahl Zellen, die durchsucht werden - neu: nur Strings zaehlen
1549 #define DATENT_MAX 200
1550 #define DATENT_SEARCH 2000
1553 BOOL
ScColumn::GetDataEntries(SCROW nStartRow
, TypedScStrCollection
& rStrings
, BOOL bLimit
)
1555 BOOL bFound
= FALSE
;
1557 BOOL bThisUsed
= Search( nStartRow
, nThisIndex
);
1561 // Die Beschraenkung auf angrenzende Zellen (ohne Luecken) ist nicht mehr gewollt
1562 // (Featurekommission zur 5.1), stattdessen abwechselnd nach oben und unten suchen,
1563 // damit naheliegende Zellen wenigstens zuerst gefunden werden.
1564 //! Abstaende der Zeilennummern vergleichen? (Performance??)
1566 SCSIZE nUpIndex
= nThisIndex
; // zeigt hinter die Zelle
1567 SCSIZE nDownIndex
= nThisIndex
; // zeigt auf die Zelle
1569 ++nDownIndex
; // Startzelle ueberspringen
1571 while ( nUpIndex
|| nDownIndex
< nCount
)
1573 if ( nUpIndex
) // nach oben
1575 ScBaseCell
* pCell
= pItems
[nUpIndex
-1].pCell
;
1576 CellType eType
= pCell
->GetCellType();
1577 if (eType
== CELLTYPE_STRING
|| eType
== CELLTYPE_EDIT
) // nur Strings interessieren
1579 if (eType
== CELLTYPE_STRING
)
1580 ((ScStringCell
*)pCell
)->GetString(aString
);
1582 ((ScEditCell
*)pCell
)->GetString(aString
);
1584 TypedStrData
* pData
= new TypedStrData(aString
);
1585 if ( !rStrings
.Insert( pData
) )
1586 delete pData
; // doppelt
1587 else if ( bLimit
&& rStrings
.GetCount() >= DATENT_MAX
)
1588 break; // Maximum erreicht
1592 if (++nCells
>= DATENT_SEARCH
)
1593 break; // genug gesucht
1598 if ( nDownIndex
< nCount
) // nach unten
1600 ScBaseCell
* pCell
= pItems
[nDownIndex
].pCell
;
1601 CellType eType
= pCell
->GetCellType();
1602 if (eType
== CELLTYPE_STRING
|| eType
== CELLTYPE_EDIT
) // nur Strings interessieren
1604 if (eType
== CELLTYPE_STRING
)
1605 ((ScStringCell
*)pCell
)->GetString(aString
);
1607 ((ScEditCell
*)pCell
)->GetString(aString
);
1609 TypedStrData
* pData
= new TypedStrData(aString
);
1610 if ( !rStrings
.Insert( pData
) )
1611 delete pData
; // doppelt
1612 else if ( bLimit
&& rStrings
.GetCount() >= DATENT_MAX
)
1613 break; // Maximum erreicht
1617 if (++nCells
>= DATENT_SEARCH
)
1618 break; // genug gesucht
1628 #undef DATENT_SEARCH
1631 void ScColumn::RemoveProtected( SCROW nStartRow
, SCROW nEndRow
)
1633 ScAttrIterator
aAttrIter( pAttrArray
, nStartRow
, nEndRow
);
1637 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nTop
, nBottom
);
1640 const ScProtectionAttr
* pAttr
= (const ScProtectionAttr
*)&pPattern
->GetItem(ATTR_PROTECTION
);
1641 if ( pAttr
->GetHideCell() )
1642 DeleteArea( nTop
, nBottom
, IDF_CONTENTS
);
1643 else if ( pAttr
->GetHideFormula() )
1645 Search( nTop
, nIndex
);
1646 while ( nIndex
<nCount
&& pItems
[nIndex
].nRow
<=nBottom
)
1648 if ( pItems
[nIndex
].pCell
->GetCellType() == CELLTYPE_FORMULA
)
1650 ScFormulaCell
* pFormula
= (ScFormulaCell
*)pItems
[nIndex
].pCell
;
1651 if (pFormula
->IsValue())
1653 double nVal
= pFormula
->GetValue();
1654 pItems
[nIndex
].pCell
= new ScValueCell( nVal
);
1659 pFormula
->GetString(aString
);
1660 pItems
[nIndex
].pCell
= new ScStringCell( aString
);
1668 pPattern
= aAttrIter
.Next( nTop
, nBottom
);
1673 void ScColumn::SetError( SCROW nRow
, const USHORT nError
)
1677 ScFormulaCell
* pCell
= new ScFormulaCell
1678 ( pDocument
, ScAddress( nCol
, nRow
, nTab
) );
1679 pCell
->SetErrCode( nError
);
1680 Insert( nRow
, pCell
);
1685 void ScColumn::SetValue( SCROW nRow
, const double& rVal
)
1689 ScBaseCell
* pCell
= new ScValueCell(rVal
);
1690 Insert( nRow
, pCell
);
1695 void ScColumn::GetString( SCROW nRow
, String
& rString
) const
1699 if (Search(nRow
, nIndex
))
1701 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1702 if (pCell
->GetCellType() != CELLTYPE_NOTE
)
1704 ULONG nFormat
= GetNumberFormat( nRow
);
1705 ScCellFormat::GetString( pCell
, nFormat
, rString
, &pColor
, *(pDocument
->GetFormatTable()) );
1715 void ScColumn::GetInputString( SCROW nRow
, String
& rString
) const
1718 if (Search(nRow
, nIndex
))
1720 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1721 if (pCell
->GetCellType() != CELLTYPE_NOTE
)
1723 ULONG nFormat
= GetNumberFormat( nRow
);
1724 ScCellFormat::GetInputString( pCell
, nFormat
, rString
, *(pDocument
->GetFormatTable()) );
1734 double ScColumn::GetValue( SCROW nRow
) const
1737 if (Search(nRow
, nIndex
))
1739 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1740 switch (pCell
->GetCellType())
1742 case CELLTYPE_VALUE
:
1743 return ((ScValueCell
*)pCell
)->GetValue();
1745 case CELLTYPE_FORMULA
:
1747 if (((ScFormulaCell
*)pCell
)->IsValue())
1748 return ((ScFormulaCell
*)pCell
)->GetValue();
1762 void ScColumn::GetFormula( SCROW nRow
, String
& rFormula
, BOOL
) const
1765 if (Search(nRow
, nIndex
))
1767 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1768 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1769 ((ScFormulaCell
*)pCell
)->GetFormula( rFormula
);
1778 CellType
ScColumn::GetCellType( SCROW nRow
) const
1781 if (Search(nRow
, nIndex
))
1782 return pItems
[nIndex
].pCell
->GetCellType();
1783 return CELLTYPE_NONE
;
1787 USHORT
ScColumn::GetErrCode( SCROW nRow
) const
1790 if (Search(nRow
, nIndex
))
1792 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1793 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1794 return ((ScFormulaCell
*)pCell
)->GetErrCode();
1800 BOOL
ScColumn::HasStringData( SCROW nRow
) const
1803 if (Search(nRow
, nIndex
))
1804 return (pItems
[nIndex
].pCell
)->HasStringData();
1809 BOOL
ScColumn::HasValueData( SCROW nRow
) const
1812 if (Search(nRow
, nIndex
))
1813 return (pItems
[nIndex
].pCell
)->HasValueData();
1817 BOOL
ScColumn::HasStringCells( SCROW nStartRow
, SCROW nEndRow
) const
1819 // TRUE, wenn String- oder Editzellen im Bereich
1824 Search( nStartRow
, nIndex
);
1825 while ( nIndex
< nCount
&& pItems
[nIndex
].nRow
<= nEndRow
)
1827 CellType eType
= pItems
[nIndex
].pCell
->GetCellType();
1828 if ( eType
== CELLTYPE_STRING
|| eType
== CELLTYPE_EDIT
)
1837 ScPostIt
* ScColumn::GetNote( SCROW nRow
)
1840 return Search( nRow
, nIndex
) ? pItems
[ nIndex
].pCell
->GetNote() : 0;
1844 void ScColumn::TakeNote( SCROW nRow
, ScPostIt
* pNote
)
1847 if( Search( nRow
, nIndex
) )
1848 pItems
[ nIndex
].pCell
->TakeNote( pNote
);
1850 Insert( nRow
, new ScNoteCell( pNote
) );
1854 ScPostIt
* ScColumn::ReleaseNote( SCROW nRow
)
1856 ScPostIt
* pNote
= 0;
1858 if( Search( nRow
, nIndex
) )
1860 ScBaseCell
* pCell
= pItems
[ nIndex
].pCell
;
1861 pNote
= pCell
->ReleaseNote();
1862 if( (pCell
->GetCellType() == CELLTYPE_NOTE
) && !pCell
->GetBroadcaster() )
1863 DeleteAtIndex( nIndex
);
1869 void ScColumn::DeleteNote( SCROW nRow
)
1871 delete ReleaseNote( nRow
);
1875 sal_Int32
ScColumn::GetMaxStringLen( SCROW nRowStart
, SCROW nRowEnd
, CharSet eCharSet
) const
1877 sal_Int32 nStringLen
= 0;
1881 rtl::OString aOString
;
1882 bool bIsOctetTextEncoding
= rtl_isOctetTextEncoding( eCharSet
);
1883 SvNumberFormatter
* pNumFmt
= pDocument
->GetFormatTable();
1886 Search( nRowStart
, nIndex
);
1887 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRowEnd
)
1889 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1890 if ( pCell
->GetCellType() != CELLTYPE_NOTE
)
1893 ULONG nFormat
= (ULONG
) ((SfxUInt32Item
*) GetAttr(
1894 nRow
, ATTR_VALUE_FORMAT
))->GetValue();
1895 ScCellFormat::GetString( pCell
, nFormat
, aString
, &pColor
,
1898 if (bIsOctetTextEncoding
)
1900 rtl::OUString
aOUString( aString
);
1901 if (!aOUString
.convertToString( &aOString
, eCharSet
,
1902 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
1903 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
))
1905 // TODO: anything? this is used by the dBase export filter
1906 // that throws an error anyway, but in case of another
1907 // context we might want to indicate a conversion error
1910 nLen
= aOString
.getLength();
1913 nLen
= aString
.Len() * sizeof(sal_Unicode
);
1914 if ( nStringLen
< nLen
)
1924 xub_StrLen
ScColumn::GetMaxNumberStringLen( USHORT
& nPrecision
,
1925 SCROW nRowStart
, SCROW nRowEnd
) const
1927 xub_StrLen nStringLen
= 0;
1928 nPrecision
= pDocument
->GetDocOptions().GetStdPrecision();
1932 SvNumberFormatter
* pNumFmt
= pDocument
->GetFormatTable();
1935 Search( nRowStart
, nIndex
);
1936 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRowEnd
)
1938 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1939 CellType eType
= pCell
->GetCellType();
1940 if ( eType
== CELLTYPE_VALUE
|| (eType
== CELLTYPE_FORMULA
1941 && ((ScFormulaCell
*)pCell
)->IsValue()) )
1943 ULONG nFormat
= (ULONG
) ((SfxUInt32Item
*) GetAttr(
1944 nRow
, ATTR_VALUE_FORMAT
))->GetValue();
1945 ScCellFormat::GetInputString( pCell
, nFormat
, aString
, *pNumFmt
);
1946 xub_StrLen nLen
= aString
.Len();
1951 const SvNumberformat
* pEntry
= pNumFmt
->GetEntry( nFormat
);
1954 BOOL bThousand
, bNegRed
;
1956 pEntry
->GetFormatSpecialInfo(bThousand
, bNegRed
, nPrecision
, nLeading
);
1959 nPrecision
= pNumFmt
->GetFormatPrecision( nFormat
);
1962 { // less than nPrecision in string => widen it
1963 // more => shorten it
1964 String aSep
= pNumFmt
->GetFormatDecimalSep( nFormat
);
1965 xub_StrLen nTmp
= aString
.Search( aSep
);
1966 if ( nTmp
== STRING_NOTFOUND
)
1967 nLen
+= nPrecision
+ aSep
.Len();
1970 nTmp
= aString
.Len() - (nTmp
+ aSep
.Len());
1971 if ( nTmp
!= nPrecision
)
1972 nLen
+= nPrecision
- nTmp
;
1973 // nPrecision > nTmp : nLen + Diff
1974 // nPrecision < nTmp : nLen - Diff
1977 if ( nStringLen
< nLen
)