re-enabled user-defined numeric fields for dBase export
[LibreOffice.git] / sc / source / core / data / column3.cxx
blob3630be3e223943c0508671c1c036bee9f2c61f56
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <boost/scoped_ptr.hpp>
22 #include <mdds/flat_segment_tree.hpp>
24 #include <sfx2/objsh.hxx>
25 #include <svl/zforlist.hxx>
26 #include <svl/zformat.hxx>
27 #include <svl/broadcast.hxx>
29 #include "scitems.hxx"
30 #include "column.hxx"
31 #include "cell.hxx"
32 #include "formulacell.hxx"
33 #include "document.hxx"
34 #include "attarray.hxx"
35 #include "patattr.hxx"
36 #include "cellform.hxx"
37 #include "typedstrdata.hxx"
38 #include "formula/errorcodes.hxx"
39 #include "formula/token.hxx"
40 #include "brdcst.hxx"
41 #include "docoptio.hxx" // GetStdPrecision for GetMaxNumberStringLen
42 #include "subtotal.hxx"
43 #include "markdata.hxx"
44 #include "detfunc.hxx" // For Notes for DeleteRange
45 #include "postit.hxx"
46 #include "stringutil.hxx"
47 #include "docpool.hxx"
48 #include "globalnames.hxx"
49 #include "cellvalue.hxx"
50 #include "tokenarray.hxx"
51 #include "stlalgorithm.hxx"
52 #include "clipcontext.hxx"
54 #include <com/sun/star/i18n/LocaleDataItem.hpp>
56 #include <cstdio>
58 using ::com::sun::star::i18n::LocaleDataItem;
60 // Err527 Workaroand
61 extern const ScFormulaCell* pLastFormulaTreeTop; // in cellform.cxx
62 using namespace formula;
63 // STATIC DATA -----------------------------------------------------------
65 namespace {
67 void broadcastCells(ScDocument& rDoc, SCCOL nCol, SCROW nTab, const std::vector<SCROW>& rRows)
69 // Broadcast the changes.
70 ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
71 std::vector<SCROW>::const_iterator itRow = rRows.begin(), itRowEnd = rRows.end();
72 for (; itRow != itRowEnd; ++itRow)
74 aHint.GetAddress().SetRow(*itRow);
75 rDoc.Broadcast(aHint);
81 void ScColumn::Insert( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pNewCell )
83 SetCell(rBlockPos, nRow, pNewCell);
84 PostSetCell(nRow, pNewCell);
87 void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
89 SetCell(nRow, pNewCell);
90 PostSetCell(nRow, pNewCell);
94 void ScColumn::Insert( SCROW nRow, sal_uInt32 nNumberFormat, ScBaseCell* pCell )
96 Insert(nRow, pCell);
97 SetNumberFormat(nRow, nNumberFormat);
100 void ScColumn::Append( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pCell )
102 maItems.push_back(ColEntry());
103 maItems.back().pCell = pCell;
104 maItems.back().nRow = nRow;
106 rBlockPos.miCellTextAttrPos =
107 maCellTextAttrs.set(rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
109 CellStorageModified();
112 void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
114 maItems.push_back(ColEntry());
115 maItems.back().pCell = pCell;
116 maItems.back().nRow = nRow;
118 maCellTextAttrs.set<sc::CellTextAttr>(nRow, sc::CellTextAttr());
119 CellStorageModified();
122 void ScColumn::Delete( SCROW nRow )
124 SCSIZE nIndex;
125 if (!Search(nRow, nIndex))
126 return;
128 ScBaseCell* pCell = maItems[nIndex].pCell;
129 maItems.erase(maItems.begin() + nIndex);
130 maCellTextAttrs.set_empty(nRow, nRow);
131 // Should we free memory here (delta)? It'll be slower!
132 if (pCell->GetCellType() == CELLTYPE_FORMULA)
133 static_cast<ScFormulaCell*>(pCell)->EndListeningTo(pDocument);
134 pCell->Delete();
136 pDocument->Broadcast(
137 ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
139 CellStorageModified();
143 void ScColumn::DeleteAtIndex( SCSIZE nIndex )
145 ScBaseCell* pCell = maItems[nIndex].pCell;
146 SCROW nRow = maItems[nIndex].nRow;
147 maItems.erase(maItems.begin() + nIndex);
148 if (pCell->GetCellType() == CELLTYPE_FORMULA)
149 static_cast<ScFormulaCell*>(pCell)->EndListeningTo(pDocument);
150 pCell->Delete();
152 pDocument->Broadcast(
153 ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
155 maCellTextAttrs.set_empty(nRow, nRow);
156 CellStorageModified();
160 void ScColumn::FreeAll()
162 for (SCSIZE i = 0; i < maItems.size(); i++)
163 maItems[i].pCell->Delete();
164 maItems.clear();
166 // Text width should keep a logical empty range of 0-MAXROW when the cell array is empty.
167 maCellTextAttrs.clear();
168 maCellTextAttrs.resize(MAXROWCOUNT);
169 CellStorageModified();
173 void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
175 SCROW nEndRow = nStartRow + nSize - 1;
177 pAttrArray->DeleteRow( nStartRow, nSize );
179 maBroadcasters.erase(nStartRow, nEndRow);
180 maBroadcasters.resize(MAXROWCOUNT);
182 if ( maItems.empty() )
183 return ;
185 SCSIZE nFirstIndex;
186 Search( nStartRow, nFirstIndex );
187 if ( nFirstIndex >= maItems.size() )
188 return ;
190 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
191 pDocument->SetAutoCalc( false ); // Avoid calculating it multiple times
193 bool bFound = false;
194 SCSIZE nStartIndex = 0;
195 SCSIZE nEndIndex = 0;
196 SCSIZE i;
199 for ( i = nFirstIndex; i < maItems.size() && maItems[i].nRow <= nEndRow; i++ )
201 if (!bFound)
203 nStartIndex = i;
204 bFound = true;
206 nEndIndex = i;
209 if (bFound)
211 std::vector<SCROW> aDeletedRows;
212 DeleteRange(nStartIndex, nEndIndex, IDF_CONTENTS, aDeletedRows);
213 broadcastCells(*pDocument, nCol, nTab, aDeletedRows);
215 Search( nStartRow, i );
216 if ( i >= maItems.size() )
218 pDocument->SetAutoCalc( bOldAutoCalc );
219 return ;
222 else
223 i = nFirstIndex;
225 // There are cells below the deletion point. Shift their row positions.
227 // Shift the text width array too (before the broadcast).
228 maCellTextAttrs.erase(nStartRow, nEndRow);
229 maCellTextAttrs.resize(MAXROWCOUNT);
231 ScAddress aAdr( nCol, 0, nTab );
232 ScHint aHint(SC_HINT_DATACHANGED, aAdr); // only areas (ScBaseCell* == NULL)
233 ScAddress& rAddress = aHint.GetAddress();
234 // for sparse occupation use single broadcasts, not ranges
235 bool bSingleBroadcasts = (((maItems.back().nRow - maItems[i].nRow) /
236 (maItems.size() - i)) > 1);
237 if ( bSingleBroadcasts )
239 SCROW nLastBroadcast = MAXROW+1;
240 for ( ; i < maItems.size(); i++ )
242 SCROW nOldRow = maItems[i].nRow;
243 // Broadcast change in source
244 rAddress.SetRow( nOldRow );
245 pDocument->AreaBroadcast( aHint );
246 SCROW nNewRow = (maItems[i].nRow -= nSize);
247 // Broadcast change in target
248 if ( nLastBroadcast != nNewRow )
249 { // Do not broadcast successive ones
250 rAddress.SetRow( nNewRow );
251 pDocument->AreaBroadcast( aHint );
253 nLastBroadcast = nOldRow;
254 ScBaseCell* pCell = maItems[i].pCell;
255 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
256 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
259 else
261 rAddress.SetRow( maItems[i].nRow );
262 ScRange aRange( rAddress );
263 aRange.aEnd.SetRow( maItems.back().nRow );
264 for ( ; i < maItems.size(); i++ )
266 SCROW nNewRow = (maItems[i].nRow -= nSize);
267 ScBaseCell* pCell = maItems[i].pCell;
268 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
269 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
271 pDocument->AreaBroadcastInRange( aRange, aHint );
274 CellStorageModified();
275 pDocument->SetAutoCalc( bOldAutoCalc );
278 void ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow )
280 if (rAttr.mnScriptType != SC_SCRIPTTYPE_UNKNOWN)
281 // Already updated. Nothing to do.
282 return;
284 // Script type not yet determined. Determine the real script
285 // type, and store it.
286 const ScPatternAttr* pPattern = GetPattern(nRow);
287 if (!pPattern)
288 return;
290 ScRefCellValue aCell;
291 ScAddress aPos(nCol, nRow, nTab);
292 aCell.assign(*pDocument, aPos);
294 const SfxItemSet* pCondSet = NULL;
295 ScConditionalFormatList* pCFList = pDocument->GetCondFormList(nTab);
296 if (pCFList)
298 const ScCondFormatItem& rItem =
299 static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL));
300 const std::vector<sal_uInt32>& rData = rItem.GetCondFormatData();
301 pCondSet = pDocument->GetCondResult(aCell, aPos, *pCFList, rData);
304 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
306 OUString aStr;
307 Color* pColor;
308 sal_uLong nFormat = pPattern->GetNumberFormat(pFormatter, pCondSet);
309 ScCellFormat::GetString(aCell, nFormat, aStr, &pColor, *pFormatter, pDocument);
311 // Store the real script type to the array.
312 rAttr.mnScriptType = pDocument->GetStringScriptType(aStr);
315 namespace {
317 bool isDate(const ScDocument& rDoc, const ScColumn& rCol, SCROW nRow)
319 sal_uLong nIndex = (sal_uLong)((SfxUInt32Item*)rCol.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
320 short nType = rDoc.GetFormatTable()->GetType(nIndex);
321 return (nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME);
324 bool checkDeleteCellByFlag(
325 CellType eCellType, sal_uInt16 nDelFlag, const ScDocument& rDoc, const ScColumn& rCol, const ColEntry& rEntry)
327 bool bDelete = false;
329 switch (eCellType)
331 case CELLTYPE_VALUE:
333 sal_uInt16 nValFlags = nDelFlag & (IDF_DATETIME|IDF_VALUE);
334 // delete values and dates?
335 bDelete = nValFlags == (IDF_DATETIME|IDF_VALUE);
336 // if not, decide according to cell number format
337 if (!bDelete && (nValFlags != 0))
339 bool bIsDate = isDate(rDoc, rCol, rEntry.nRow);
340 bDelete = nValFlags == (bIsDate ? IDF_DATETIME : IDF_VALUE);
343 break;
344 case CELLTYPE_STRING:
345 case CELLTYPE_EDIT:
346 bDelete = (nDelFlag & IDF_STRING) != 0;
347 break;
348 case CELLTYPE_FORMULA:
349 bDelete = (nDelFlag & IDF_FORMULA) != 0;
350 break;
351 default:; // added to avoid warnings
354 return bDelete;
359 void ScColumn::DeleteRange(
360 SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDelFlag, std::vector<SCROW>& rDeletedRows )
362 /* If caller specifies to not remove the note caption objects, all cells
363 have to forget the pointers to them. This is used e.g. while undoing a
364 "paste cells" operation, which removes the caption objects later in
365 drawing undo. */
367 // cache all formula cells, they will be deleted at end of this function
368 std::vector<ScFormulaCell*> aDelCells;
369 aDelCells.reserve( nEndIndex - nStartIndex + 1 );
371 typedef mdds::flat_segment_tree<SCSIZE, bool> RemovedSegments_t;
372 RemovedSegments_t aRemovedSegments(nStartIndex, maItems.size(), false);
373 SCSIZE nFirst = nStartIndex;
375 for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx )
377 if (((nDelFlag & IDF_CONTENTS) == IDF_CONTENTS))
379 // all content is to be deleted.
381 ScBaseCell* pOldCell = maItems[ nIdx ].pCell;
382 rDeletedRows.push_back(maItems[nIdx].nRow);
384 if (pOldCell->GetCellType() == CELLTYPE_FORMULA)
386 // cache formula cell, will be deleted below
387 aDelCells.push_back( static_cast< ScFormulaCell* >( pOldCell ) );
389 else
390 pOldCell->Delete();
392 continue;
395 // delete some contents of the cells, or cells with broadcaster
396 bool bDelete = false;
397 ScBaseCell* pOldCell = maItems[nIdx].pCell;
398 CellType eCellType = pOldCell->GetCellType();
399 if ((nDelFlag & IDF_CONTENTS) == IDF_CONTENTS)
400 // All cell types to be deleted.
401 bDelete = true;
402 else
404 // Decide whether to delete the cell object according to passed
405 // flags.
406 bDelete = checkDeleteCellByFlag(eCellType, nDelFlag, *pDocument, *this, maItems[nIdx]);
409 if (bDelete)
411 // remove cell entry in cell item list
412 if (eCellType == CELLTYPE_FORMULA)
414 // Cache formula cells (will be deleted later), delete cell of other type.
415 aDelCells.push_back(static_cast<ScFormulaCell*>(pOldCell));
417 else
418 pOldCell->Delete();
420 rDeletedRows.push_back(maItems[nIdx].nRow);
423 if (!bDelete)
425 // We just came to a non-deleted cell after a segment of
426 // deleted ones. So we need to remember the segment
427 // before moving on.
428 if (nFirst < nIdx)
429 aRemovedSegments.insert_back(nFirst, nIdx, true);
430 nFirst = nIdx + 1;
433 // there is a segment of deleted cells at the end
434 if (nFirst <= nEndIndex)
435 aRemovedSegments.insert_back(nFirst, nEndIndex + 1, true);
438 // Remove segments from the column array, containing pDummyCell and
439 // formula cell pointers to be deleted.
441 RemovedSegments_t::const_reverse_iterator it = aRemovedSegments.rbegin();
442 RemovedSegments_t::const_reverse_iterator itEnd = aRemovedSegments.rend();
444 std::vector<ColEntry>::iterator itErase, itEraseEnd;
445 SCSIZE nEndSegment = it->first; // should equal maItems.size(). Non-inclusive.
446 // Skip the first node.
447 for (++it; it != itEnd; ++it)
449 if (!it->second)
451 // Don't remove this segment.
452 nEndSegment = it->first;
453 continue;
456 // Remove this segment.
457 SCSIZE nStartSegment = it->first;
458 SCROW nStartRow = maItems[nStartSegment].nRow;
459 SCROW nEndRow = maItems[nEndSegment-1].nRow;
461 itErase = maItems.begin();
462 std::advance(itErase, nStartSegment);
463 itEraseEnd = maItems.begin();
464 std::advance(itEraseEnd, nEndSegment);
465 maItems.erase(itErase, itEraseEnd);
467 maCellTextAttrs.set_empty(nStartRow, nEndRow);
469 nEndSegment = nStartSegment;
473 pDocument->EndListeningFormulaCells(aDelCells);
474 std::for_each(aDelCells.begin(), aDelCells.end(), ScDeleteObjectByPtr<ScFormulaCell>());
477 void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
479 // FreeAll must not be called here due to Broadcasters
480 // Delete attribute at the end so that we can distinguish between numbers and dates
482 sal_uInt16 nContMask = IDF_CONTENTS;
483 // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
484 if( nDelFlag & IDF_NOTE )
485 nContMask |= IDF_NOCAPTIONS;
486 sal_uInt16 nContFlag = nDelFlag & nContMask;
488 std::vector<SCROW> aDeletedRows;
490 if ( !maItems.empty() && nContFlag)
492 if (nStartRow==0 && nEndRow==MAXROW)
494 DeleteRange(0, maItems.size()-1, nContFlag, aDeletedRows);
496 else
498 sal_Bool bFound=false;
499 SCSIZE nStartIndex = 0;
500 SCSIZE nEndIndex = 0;
501 for (SCSIZE i = 0; i < maItems.size(); i++)
502 if ((maItems[i].nRow >= nStartRow) && (maItems[i].nRow <= nEndRow))
504 if (!bFound)
506 nStartIndex = i;
507 bFound = sal_True;
509 nEndIndex = i;
511 if (bFound)
512 DeleteRange(nStartIndex, nEndIndex, nContFlag, aDeletedRows);
516 if ( nDelFlag & IDF_EDITATTR )
518 OSL_ENSURE( nContFlag == 0, "DeleteArea: Wrong Flags" );
519 RemoveEditAttribs( nStartRow, nEndRow );
522 // Delete attributes just now
523 if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB)
524 pAttrArray->DeleteArea( nStartRow, nEndRow );
525 else if ((nDelFlag & IDF_HARDATTR) == IDF_HARDATTR)
526 pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
528 // Broadcast on only cells that were deleted; no point broadcasting on
529 // cells that were already empty before the deletion.
530 broadcastCells(*pDocument, nCol, nTab, aDeletedRows);
534 ScFormulaCell* ScColumn::CreateRefCell( ScDocument* pDestDoc, const ScAddress& rDestPos,
535 SCSIZE nIndex, sal_uInt16 nFlags ) const
537 sal_uInt16 nContFlags = nFlags & IDF_CONTENTS;
538 if (!nContFlags)
539 return NULL;
541 // Test whether the Cell should be copied
542 // Also do this for IDF_CONTENTS, due to Notes/Broadcasters
543 sal_Bool bMatch = false;
544 ScBaseCell* pCell = maItems[nIndex].pCell;
545 CellType eCellType = pCell->GetCellType();
546 switch ( eCellType )
548 case CELLTYPE_VALUE:
550 sal_uInt16 nValFlags = nFlags & (IDF_DATETIME|IDF_VALUE);
552 if ( nValFlags == (IDF_DATETIME|IDF_VALUE) )
553 bMatch = sal_True;
554 else if ( nValFlags )
556 sal_uLong nNumIndex = (sal_uLong)((SfxUInt32Item*)GetAttr(
557 maItems[nIndex].nRow, ATTR_VALUE_FORMAT ))->GetValue();
558 short nTyp = pDocument->GetFormatTable()->GetType(nNumIndex);
559 if ((nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME))
560 bMatch = ((nFlags & IDF_DATETIME) != 0);
561 else
562 bMatch = ((nFlags & IDF_VALUE) != 0);
565 break;
566 case CELLTYPE_STRING:
567 case CELLTYPE_EDIT: bMatch = ((nFlags & IDF_STRING) != 0); break;
568 case CELLTYPE_FORMULA: bMatch = ((nFlags & IDF_FORMULA) != 0); break;
569 default:
571 // added to avoid warnings
574 if (!bMatch)
575 return NULL;
578 // Insert Reference
579 ScSingleRefData aRef;
580 aRef.nCol = nCol;
581 aRef.nRow = maItems[nIndex].nRow;
582 aRef.nTab = nTab;
583 aRef.InitFlags(); // -> Everything absolute
584 aRef.SetFlag3D(true);
586 // 3D (false) and TabRel (true), if the final Position is at the same Table?
587 // The target position is not yet known for TransposeClip!
589 aRef.CalcRelFromAbs( rDestPos );
591 ScTokenArray aArr;
592 aArr.AddSingleReference( aRef );
594 return new ScFormulaCell( pDestDoc, rDestPos, &aArr );
597 bool ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos )
599 rBlockPos.miBroadcasterPos = maBroadcasters.begin();
600 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
601 return true;
604 // rColumn = source
605 // nRow1, nRow2 = target position
607 void ScColumn::CopyFromClip(
608 sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn )
610 if ((rCxt.getInsertFlag() & IDF_ATTRIB) != 0)
612 if (rCxt.isSkipAttrForEmptyCells())
614 // copy only attributes for non-empty cells
615 // (notes are not counted as non-empty here, to match the content behavior)
617 SCSIZE nStartIndex;
618 rColumn.Search( nRow1-nDy, nStartIndex );
619 while ( nStartIndex < rColumn.maItems.size() && rColumn.maItems[nStartIndex].nRow <= nRow2-nDy )
621 SCSIZE nEndIndex = nStartIndex;
622 SCROW nStartRow = rColumn.maItems[nStartIndex].nRow;
623 SCROW nEndRow = nStartRow;
625 // find consecutive non-empty cells
626 while ( nEndRow < nRow2-nDy &&
627 nEndIndex+1 < rColumn.maItems.size() &&
628 rColumn.maItems[nEndIndex+1].nRow == nEndRow+1 )
630 ++nEndIndex;
631 ++nEndRow;
634 rColumn.pAttrArray->CopyAreaSafe( nStartRow+nDy, nEndRow+nDy, nDy, *pAttrArray );
635 nStartIndex = nEndIndex + 1;
638 else
639 rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
641 if ((rCxt.getInsertFlag() & IDF_CONTENTS) == 0)
642 return;
644 if (rCxt.isAsLink() && rCxt.getInsertFlag() == IDF_ALL)
646 // We also reference empty cells for "ALL"
647 // IDF_ALL must always contain more flags when compared to "Insert contents" as
648 // contents can be selected one by one!
650 ReserveSize(maItems.size() + static_cast<SCSIZE>(nRow2-nRow1+1));
652 ScAddress aDestPos( nCol, 0, nTab ); // Adapt Row
654 // Create reference (Source Position)
655 ScSingleRefData aRef;
656 aRef.nCol = rColumn.nCol;
657 // Adapt nRow
658 aRef.nTab = rColumn.nTab;
659 aRef.InitFlags(); // -> All absolute
660 aRef.SetFlag3D(true);
662 for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++)
664 aRef.nRow = nDestRow - nDy; // Source row
665 aDestPos.SetRow( nDestRow );
667 aRef.CalcRelFromAbs( aDestPos );
668 ScTokenArray aArr;
669 aArr.AddSingleReference( aRef );
670 Insert( nDestRow, new ScFormulaCell( pDocument, aDestPos, &aArr ) );
673 return;
676 SCSIZE nColCount = rColumn.maItems.size();
678 // ignore IDF_FORMULA - "all contents but no formulas" results in the same number of cells
679 if ((rCxt.getInsertFlag() & ( IDF_CONTENTS & ~IDF_FORMULA )) == ( IDF_CONTENTS & ~IDF_FORMULA ) && nRow2-nRow1 >= 64)
681 //! Always do the Resize from the outside, where the number of repetitions is known
682 //! (then it can be removed here)
684 ReserveSize(maItems.size() + nColCount);
687 sal_Bool bAtEnd = false;
688 for (SCSIZE i = 0; i < nColCount && !bAtEnd; i++)
690 SCsROW nDestRow = rColumn.maItems[i].nRow + nDy;
691 if ( nDestRow > (SCsROW) nRow2 )
692 bAtEnd = sal_True;
693 else if ( nDestRow >= (SCsROW) nRow1 )
695 // rows at the beginning may be skipped if filtered rows are left out,
696 // nDestRow may be negative then
698 ScAddress aDestPos( nCol, (SCROW)nDestRow, nTab );
700 ScBaseCell* pNewCell = rCxt.isAsLink() ?
701 rColumn.CreateRefCell(pDocument, aDestPos, i, rCxt.getInsertFlag()) :
702 rColumn.CloneCell(i, rCxt.getInsertFlag(), *pDocument, aDestPos);
703 if (pNewCell)
705 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
706 if (p)
707 Insert(*p, aDestPos.Row(), pNewCell);
708 else
709 Insert(aDestPos.Row(), pNewCell);
716 namespace {
719 * Helper for ScColumn::CloneCell
720 * Decide whether to clone a value cell depending on clone flags and number format.
722 bool lclCanCloneValue( ScDocument& rDoc, const ScColumn& rCol, SCROW nRow, bool bCloneValue, bool bCloneDateTime )
724 // values and dates, or nothing to be cloned -> not needed to check number format
725 if( bCloneValue == bCloneDateTime )
726 return bCloneValue;
728 // check number format of value cell
729 sal_uLong nNumIndex = (sal_uLong)((SfxUInt32Item*)rCol.GetAttr( nRow, ATTR_VALUE_FORMAT ))->GetValue();
730 short nTyp = rDoc.GetFormatTable()->GetType( nNumIndex );
731 bool bIsDateTime = (nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME);
732 return bIsDateTime ? bCloneDateTime : bCloneValue;
735 } // namespace
738 ScBaseCell* ScColumn::CloneCell(
739 SCSIZE nIndex, sal_uInt16 nFlags, ScDocument& rDestDoc, const ScAddress& rDestPos) const
741 bool bCloneValue = (nFlags & IDF_VALUE) != 0;
742 bool bCloneDateTime = (nFlags & IDF_DATETIME) != 0;
743 bool bCloneString = (nFlags & IDF_STRING) != 0;
744 bool bCloneSpecialBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != 0;
745 bool bCloneFormula = (nFlags & IDF_FORMULA) != 0;
746 bool bForceFormula = false;
748 ScBaseCell* pNew = 0;
749 ScBaseCell& rSource = *maItems[nIndex].pCell;
750 switch (rSource.GetCellType())
752 case CELLTYPE_STRING:
753 case CELLTYPE_EDIT:
754 // note will be cloned below
755 if (bCloneString)
756 pNew = rSource.Clone( rDestDoc, rDestPos );
757 break;
759 case CELLTYPE_VALUE:
760 // note will be cloned below
761 if (lclCanCloneValue( *pDocument, *this, maItems[nIndex].nRow, bCloneValue, bCloneDateTime ))
762 pNew = rSource.Clone( rDestDoc, rDestPos );
763 break;
765 case CELLTYPE_FORMULA:
766 if ( bCloneSpecialBoolean )
768 ScFormulaCell& rForm = (ScFormulaCell&)rSource;
769 OUStringBuffer aBuf;
770 // FIXME: do we have a localisation issue here?
771 rForm.GetFormula( aBuf );
772 OUString aVal( aBuf.makeStringAndClear() );
773 if ( aVal == "=TRUE()" || aVal == "=FALSE()" )
774 bForceFormula = true;
776 if (bForceFormula || bCloneFormula)
778 // note will be cloned below
779 pNew = rSource.Clone( rDestDoc, rDestPos );
781 else if ( (bCloneValue || bCloneDateTime || bCloneString) && !rDestDoc.IsUndo() )
783 // Always just copy the original row to the Undo Documen;
784 // do not create Value/string cells from formulas
785 ScFormulaCell& rForm = (ScFormulaCell&)rSource;
786 sal_uInt16 nErr = rForm.GetErrCode();
787 if ( nErr )
789 // error codes are cloned with values
790 if (bCloneValue)
792 ScFormulaCell* pErrCell = new ScFormulaCell( &rDestDoc, rDestPos );
793 pErrCell->SetErrCode( nErr );
794 pNew = pErrCell;
797 else if (rForm.IsValue())
799 if (lclCanCloneValue( *pDocument, *this, maItems[nIndex].nRow, bCloneValue, bCloneDateTime ))
801 double nVal = rForm.GetValue();
802 pNew = new ScValueCell(nVal);
805 else if (bCloneString)
807 String aString = rForm.GetString();
808 // do not clone empty string
809 if (aString.Len() > 0)
811 if ( rForm.IsMultilineResult() )
813 pNew = new ScEditCell( aString, &rDestDoc );
815 else
817 pNew = new ScStringCell( aString );
822 break;
824 default: OSL_FAIL( "ScColumn::CloneCell - unknown cell type" );
827 return pNew;
831 void ScColumn::MixMarked(
832 sc::MixDocContext& rCxt, const ScMarkData& rMark, sal_uInt16 nFunction,
833 bool bSkipEmpty, const ScColumn& rSrcCol )
835 SCROW nRow1, nRow2;
837 if (rMark.IsMultiMarked())
839 ScMarkArrayIter aIter( rMark.GetArray()+nCol );
840 while (aIter.Next( nRow1, nRow2 ))
841 MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol);
845 namespace {
847 // Result in rVal1
848 bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
850 bool bOk = false;
851 switch (nFunction)
853 case PASTE_ADD:
854 bOk = SubTotal::SafePlus( rVal1, nVal2 );
855 break;
856 case PASTE_SUB:
857 nVal2 = -nVal2; // FIXME: Can we do this alwyas without error?
858 bOk = SubTotal::SafePlus( rVal1, nVal2 );
859 break;
860 case PASTE_MUL:
861 bOk = SubTotal::SafeMult( rVal1, nVal2 );
862 break;
863 case PASTE_DIV:
864 bOk = SubTotal::SafeDiv( rVal1, nVal2 );
865 break;
867 return bOk;
870 void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
872 rArr.AddOpCode(ocOpen);
874 ScTokenArray* pCode = pCell->GetCode();
875 if (pCode)
877 const formula::FormulaToken* pToken = pCode->First();
878 while (pToken)
880 rArr.AddToken( *pToken );
881 pToken = pCode->Next();
885 rArr.AddOpCode(ocClose);
888 struct FindRemovedCell : std::unary_function<ColEntry, bool>
890 bool operator() (const ColEntry& rEntry) const
892 return rEntry.pCell == NULL;
898 void ScColumn::MixData(
899 sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction,
900 bool bSkipEmpty, const ScColumn& rSrcCol )
902 SCSIZE nSrcCount = rSrcCol.maItems.size();
904 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
906 SCSIZE nIndex;
907 Search( nRow1, nIndex );
909 SCSIZE nSrcIndex = 0, nDestIndex = 0;
910 rSrcCol.Search( nRow1, nSrcIndex ); // See if data is at the beginning
912 SCROW nNextThis = MAXROW+1;
913 if ( nIndex < maItems.size() )
914 nNextThis = maItems[nIndex].nRow;
915 SCROW nNextSrc = MAXROW+1;
916 if ( nSrcIndex < nSrcCount )
917 nNextSrc = rSrcCol.maItems[nSrcIndex].nRow;
919 bool bDeferredDelete = false;
920 while ( nNextThis <= nRow2 || nNextSrc <= nRow2 )
922 SCROW nRow = std::min( nNextThis, nNextSrc );
924 ScBaseCell* pSrc = NULL;
925 ScBaseCell* pDest = NULL;
926 ScBaseCell* pNew = NULL;
927 bool bDelete = false;
929 if ( nSrcIndex < nSrcCount && nNextSrc == nRow )
930 pSrc = rSrcCol.maItems[nSrcIndex].pCell;
932 if ( nIndex < maItems.size() && nNextThis == nRow )
934 pDest = maItems[nIndex].pCell;
935 nDestIndex = nIndex;
938 OSL_ENSURE( pSrc || pDest, "What happened?" );
940 CellType eSrcType = pSrc ? pSrc->GetCellType() : CELLTYPE_NONE;
941 CellType eDestType = pDest ? pDest->GetCellType() : CELLTYPE_NONE;
943 bool bSrcEmpty = (eSrcType == CELLTYPE_NONE);
944 bool bDestEmpty = (eDestType == CELLTYPE_NONE);
946 if ( bSkipEmpty && bDestEmpty ) // Restore original row
948 if ( pSrc ) // Did we have a row here?
950 pNew = pSrc->Clone( *pDocument );
953 else if ( nFunction ) // Really provide calculation function
955 double nVal1;
956 double nVal2;
957 if ( eSrcType == CELLTYPE_VALUE )
958 nVal1 = ((ScValueCell*)pSrc)->GetValue();
959 else
960 nVal1 = 0.0;
961 if ( eDestType == CELLTYPE_VALUE )
962 nVal2 = ((ScValueCell*)pDest)->GetValue();
963 else
964 nVal2 = 0.0;
966 // Empty row is treated as a value
967 sal_Bool bSrcVal = ( bSrcEmpty || eSrcType == CELLTYPE_VALUE );
968 sal_Bool bDestVal = ( bDestEmpty || eDestType == CELLTYPE_VALUE );
970 sal_Bool bSrcText = ( eSrcType == CELLTYPE_STRING ||
971 eSrcType == CELLTYPE_EDIT );
972 sal_Bool bDestText = ( eDestType == CELLTYPE_STRING ||
973 eDestType == CELLTYPE_EDIT );
975 // Else we only have formulas ...
976 if ( bSrcEmpty && bDestEmpty )
978 // Both empty -> do nothing
980 else if ( bSrcVal && bDestVal )
982 // Insterted new value or both have overflown
983 sal_Bool bOk = lcl_DoFunction( nVal1, nVal2, nFunction );
985 if (bOk)
986 pNew = new ScValueCell( nVal1 );
987 else
989 ScFormulaCell* pFC = new ScFormulaCell( pDocument,
990 ScAddress( nCol, nRow, nTab ) );
991 pFC->SetErrCode( errNoValue );
992 //! oder NOVALUE, dann auch in consoli,
993 //! sonst in Interpreter::GetCellValue die Abfrage auf errNoValue raus
994 //! (dann geht Stringzelle+Wertzelle nicht mehr)
995 pNew = pFC;
998 else if ( bSrcText || bDestText )
1000 // We do no not calculate with texts - alwyas "old" cell, thus pSrc
1001 if (pSrc)
1002 pNew = pSrc->Clone( *pDocument );
1003 else if (pDest)
1004 bDelete = sal_True;
1006 else
1008 // Combination of value and at least one formula -> Create formula
1009 ScTokenArray aArr;
1011 // First row
1012 if ( eSrcType == CELLTYPE_FORMULA )
1013 lcl_AddCode( aArr, (ScFormulaCell*)pSrc );
1014 else
1015 aArr.AddDouble( nVal1 );
1017 // Operator
1018 OpCode eOp = ocAdd;
1019 switch ( nFunction )
1021 case PASTE_ADD: eOp = ocAdd; break;
1022 case PASTE_SUB: eOp = ocSub; break;
1023 case PASTE_MUL: eOp = ocMul; break;
1024 case PASTE_DIV: eOp = ocDiv; break;
1026 aArr.AddOpCode(eOp); // Function
1028 // Second row
1029 if ( eDestType == CELLTYPE_FORMULA )
1030 lcl_AddCode( aArr, (ScFormulaCell*)pDest );
1031 else
1032 aArr.AddDouble( nVal2 );
1034 pNew = new ScFormulaCell( pDocument, ScAddress( nCol, nRow, nTab ), &aArr );
1039 if ( pNew || bDelete ) // New result?
1041 if (pDest && !pNew) // Old cell present?
1043 // Delete the destination cell because the cell was originally
1044 // empty. Don't erase its slot in the cell array yet.
1045 OSL_ASSERT(pDest == maItems[nDestIndex].pCell);
1046 maItems[nDestIndex].pCell = NULL;
1048 if (pDest->GetCellType() == CELLTYPE_FORMULA)
1049 static_cast<ScFormulaCell*>(pDest)->EndListeningTo(pDocument);
1050 pDest->Delete();
1052 bDeferredDelete = true;
1054 if (pNew)
1056 if (p)
1057 Insert(*p, nRow, pNew);
1058 else
1059 Insert(nRow, pNew); // Insert new one
1062 Search( nRow, nIndex ); // Everything could have moved
1063 if (pNew)
1064 nNextThis = nRow; // nIndex points right at nRow now
1065 else
1066 nNextThis = ( nIndex < maItems.size() ) ? maItems[nIndex].nRow : MAXROW+1;
1069 if ( nNextThis == nRow )
1071 ++nIndex;
1072 nNextThis = ( nIndex < maItems.size() ) ? maItems[nIndex].nRow : MAXROW+1;
1074 if ( nNextSrc == nRow )
1076 ++nSrcIndex;
1077 nNextSrc = ( nSrcIndex < nSrcCount ) ?
1078 rSrcCol.maItems[nSrcIndex].nRow :
1079 MAXROW+1;
1083 if (bDeferredDelete)
1085 // Erase all the slots in the cell array where the deleted cells
1086 // previously occupied.
1087 std::vector<ColEntry>::iterator it =
1088 std::remove_if(maItems.begin(), maItems.end(), FindRemovedCell());
1090 maItems.erase(it, maItems.end());
1092 // Reset the cell text attriute array to keep it in sync again.
1093 ResetCellTextAttrs();
1098 ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
1100 return new ScAttrIterator( pAttrArray, nStartRow, nEndRow );
1104 void ScColumn::StartAllListeners()
1106 if (maItems.empty())
1107 return;
1109 for (SCSIZE i = 0; i < maItems.size(); i++)
1111 ScBaseCell* pCell = maItems[i].pCell;
1112 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1114 SCROW nRow = maItems[i].nRow;
1115 ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
1116 if ( nRow != maItems[i].nRow )
1117 Search( nRow, i ); // Insert Listener?
1123 void ScColumn::StartNeededListeners()
1125 if (maItems.empty())
1126 return;
1128 for (SCSIZE i = 0; i < maItems.size(); i++)
1130 ScBaseCell* pCell = maItems[i].pCell;
1131 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1133 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
1134 if (pFCell->NeedsListening())
1136 SCROW nRow = maItems[i].nRow;
1137 pFCell->StartListeningTo( pDocument );
1138 if ( nRow != maItems[i].nRow )
1139 Search( nRow, i ); // Insert Listener?
1146 void ScColumn::BroadcastInArea( SCROW nRow1, SCROW nRow2 )
1148 if (maItems.empty())
1149 return;
1151 SCROW nRow;
1152 SCSIZE nIndex;
1153 Search(nRow1, nIndex);
1155 while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRow2 )
1157 ScBaseCell* pCell = maItems[nIndex].pCell;
1158 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1159 ((ScFormulaCell*)pCell)->SetDirty();
1160 else
1161 pDocument->Broadcast( ScHint(SC_HINT_DATACHANGED,
1162 ScAddress(nCol, nRow, nTab)));
1163 nIndex++;
1168 void ScColumn::StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
1170 if (maItems.empty())
1171 return;
1173 SCROW nRow;
1174 SCSIZE nIndex;
1175 Search( nRow1, nIndex );
1176 while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRow2 )
1178 ScBaseCell* pCell = maItems[nIndex].pCell;
1179 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1180 ((ScFormulaCell*)pCell)->StartListeningTo(rCxt);
1181 if ( nRow != maItems[nIndex].nRow )
1182 Search( nRow, nIndex ); // Inserted via Listening
1184 ++nIndex;
1188 namespace {
1190 void applyTextNumFormat( ScColumn& rCol, ScDocument& rDoc, SCROW nRow, SvNumberFormatter* pFormatter )
1192 sal_uInt32 nFormat = pFormatter->GetStandardFormat(NUMBERFORMAT_TEXT);
1193 ScPatternAttr aNewAttrs(rDoc.GetPool());
1194 SfxItemSet& rSet = aNewAttrs.GetItemSet();
1195 rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
1196 rCol.ApplyPattern(nRow, aNewAttrs);
1201 bool ScColumn::ParseString(
1202 ScCellValue& rCell, SCROW nRow, SCTAB nTabP, const String& rString,
1203 formula::FormulaGrammar::AddressConvention eConv,
1204 ScSetStringParam* pParam )
1206 if (!rString.Len())
1207 return false;
1209 bool bNumFmtSet = false;
1211 ScSetStringParam aParam;
1213 if (pParam)
1214 aParam = *pParam;
1216 sal_uInt32 nIndex = 0;
1217 sal_uInt32 nOldIndex = 0;
1218 sal_Unicode cFirstChar;
1219 if (!aParam.mpNumFormatter)
1220 aParam.mpNumFormatter = pDocument->GetFormatTable();
1222 nIndex = nOldIndex = GetNumberFormat( nRow );
1223 if ( rString.Len() > 1
1224 && aParam.mpNumFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT )
1225 cFirstChar = rString.GetChar(0);
1226 else
1227 cFirstChar = 0; // Text
1229 if ( cFirstChar == '=' )
1231 if ( rString.Len() == 1 ) // = Text
1232 rCell.set(rString);
1233 else if (aParam.meSetTextNumFormat == ScSetStringParam::Always)
1235 // Set the cell format type to Text.
1236 applyTextNumFormat(*this, *pDocument, nRow, aParam.mpNumFormatter);
1237 rCell.set(rString);
1239 else // = Formula
1240 rCell.set(
1241 new ScFormulaCell(
1242 pDocument, ScAddress(nCol, nRow, nTabP), rString,
1243 formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_DEFAULT, eConv),
1244 MM_NONE));
1246 else if ( cFirstChar == '\'') // 'Text
1248 bool bNumeric = false;
1249 if (aParam.mbHandleApostrophe)
1251 // Cell format is not 'Text', and the first char
1252 // is an apostrophe. Check if the input is considered a number.
1253 String aTest = rString.Copy(1);
1254 double fTest;
1255 bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest);
1256 if (bNumeric)
1257 // This is a number. Strip out the first char.
1258 rCell.set(aTest);
1260 if (!bNumeric)
1261 // This is normal text. Take it as-is.
1262 rCell.set(rString);
1264 else
1266 double nVal;
1270 if (aParam.mbDetectNumberFormat)
1272 if (!aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
1273 break;
1275 if ( aParam.mpNumFormatter )
1277 // convert back to the original language if a built-in format was detected
1278 const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
1279 if ( pOldFormat )
1280 nIndex = aParam.mpNumFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() );
1283 rCell.set(nVal);
1284 if ( nIndex != nOldIndex)
1286 // #i22345# New behavior: Apply the detected number format only if
1287 // the old one was the default number, date, time or boolean format.
1288 // Exception: If the new format is boolean, always apply it.
1290 bool bOverwrite = false;
1291 const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
1292 if ( pOldFormat )
1294 short nOldType = pOldFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1295 if ( nOldType == NUMBERFORMAT_NUMBER || nOldType == NUMBERFORMAT_DATE ||
1296 nOldType == NUMBERFORMAT_TIME || nOldType == NUMBERFORMAT_LOGICAL )
1298 if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat(
1299 nOldType, pOldFormat->GetLanguage() ) )
1301 bOverwrite = true; // default of these types can be overwritten
1305 if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL )
1307 bOverwrite = true; // overwrite anything if boolean was detected
1310 if ( bOverwrite )
1312 ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
1313 (sal_uInt32) nIndex) );
1314 bNumFmtSet = true;
1318 else if (aParam.meSetTextNumFormat != ScSetStringParam::Always)
1320 // Only check if the string is a regular number.
1321 const LocaleDataWrapper* pLocale = aParam.mpNumFormatter->GetLocaleData();
1322 if (!pLocale)
1323 break;
1325 LocaleDataItem aLocaleItem = pLocale->getLocaleItem();
1326 const OUString& rDecSep = aLocaleItem.decimalSeparator;
1327 const OUString& rGroupSep = aLocaleItem.thousandSeparator;
1328 if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1)
1329 break;
1331 sal_Unicode dsep = rDecSep.getStr()[0];
1332 sal_Unicode gsep = rGroupSep.getStr()[0];
1334 if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal))
1335 break;
1337 rCell.set(nVal);
1340 while (false);
1342 if (rCell.meType == CELLTYPE_NONE)
1344 if (aParam.meSetTextNumFormat != ScSetStringParam::Never && aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
1346 // Set the cell format type to Text.
1347 applyTextNumFormat(*this, *pDocument, nRow, aParam.mpNumFormatter);
1350 rCell.set(rString);
1354 return bNumFmtSet;
1358 * Returns true if the cell format was set as well
1360 bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
1361 formula::FormulaGrammar::AddressConvention eConv,
1362 ScSetStringParam* pParam )
1364 if (!ValidRow(nRow))
1365 return false;
1367 ScCellValue aNewCell;
1368 bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam);
1369 aNewCell.release(*this, nRow);
1371 // Do not set Formats and Formulas here anymore!
1372 // These are queried during output
1374 return bNumFmtSet;
1377 void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
1379 Insert(nRow, new ScEditCell(pEditText, pDocument));
1382 void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
1384 Insert(nRow, new ScEditCell(rEditText, pDocument, pEditPool));
1387 void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
1389 ScAddress aPos(nCol, nRow, nTab);
1390 ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, &rArray, eGram);
1391 sal_uInt32 nCellFormat = GetNumberFormat( nRow );
1392 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
1393 pCell->SetNeedNumberFormat(true);
1394 Insert(nRow, pCell);
1397 void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
1399 ScAddress aPos(nCol, nRow, nTab);
1400 ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rFormula, eGram);
1402 sal_uInt32 nCellFormat = GetNumberFormat( nRow );
1403 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
1404 pCell->SetNeedNumberFormat(true);
1405 Insert(nRow, pCell);
1408 void ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell )
1410 Insert(nRow, pCell);
1413 void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
1415 bool bHasDates = false;
1416 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
1417 OUString aString;
1418 SCSIZE nIndex;
1420 Search( nStartRow, nIndex );
1422 for (; nIndex < maItems.size(); ++nIndex)
1424 SCROW nRow = maItems[nIndex].nRow;
1425 if (nRow > nEndRow)
1426 break;
1428 ScBaseCell* pCell = maItems[nIndex].pCell;
1429 ScRefCellValue aCell;
1430 aCell.assign(*maItems[nIndex].pCell);
1431 sal_uLong nFormat = GetNumberFormat( nRow );
1433 ScCellFormat::GetInputString(aCell, nFormat, aString, *pFormatter, pDocument);
1435 if ( pDocument->HasStringData( nCol, nRow, nTab ) )
1437 rStrings.push_back(ScTypedStrData(aString));
1438 continue;
1441 double nValue = 0.0;
1443 switch ( pCell->GetCellType() )
1445 case CELLTYPE_VALUE:
1446 nValue = ((ScValueCell*)pCell)->GetValue();
1447 break;
1449 case CELLTYPE_FORMULA:
1451 ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
1452 sal_uInt16 nErr = pFC->GetErrCode();
1453 if (nErr)
1455 // Error cell is evaluated as string (for now).
1456 String aErr = ScGlobal::GetErrorString(nErr);
1457 if (aErr.Len())
1459 rStrings.push_back(ScTypedStrData(aErr));
1460 continue;
1463 else
1464 nValue = pFC->GetValue();
1466 break;
1467 default:
1471 if (pFormatter)
1473 short nType = pFormatter->GetType(nFormat);
1474 if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME))
1476 // special case for date values. Disregard the time
1477 // element if the number format is of date type.
1478 nValue = ::rtl::math::approxFloor(nValue);
1479 bHasDates = true;
1483 rStrings.push_back(ScTypedStrData(aString, nValue, ScTypedStrData::Value));
1486 rHasDates = bHasDates;
1490 // GetDataEntries - Strings from continuous Section around nRow
1493 // DATENT_MAX - max. number of entries in list for auto entry
1494 // DATENT_SEARCH - max. number of cells that get transparent - new: only count Strings
1495 #define DATENT_MAX 200
1496 #define DATENT_SEARCH 2000
1499 bool ScColumn::GetDataEntries(SCROW nStartRow, std::set<ScTypedStrData>& rStrings, bool bLimit)
1501 sal_Bool bFound = false;
1502 SCSIZE nThisIndex;
1503 sal_Bool bThisUsed = Search( nStartRow, nThisIndex );
1504 String aString;
1505 sal_uInt16 nCells = 0;
1507 // The limitation to neighbouring cells (without gaps) is not wanted anymore
1508 // (Featurecommission for 5.1), search upwards/downwards instead so that
1509 // nearby cell are cought at least first.
1510 // TODO: Compare distances of cell numbers? Performance??
1512 SCSIZE nUpIndex = nThisIndex; // Points after the row
1513 SCSIZE nDownIndex = nThisIndex; // Points to the row
1514 if (bThisUsed)
1515 ++nDownIndex; // Skip starting row
1517 while ( nUpIndex || nDownIndex < maItems.size() )
1519 if ( nUpIndex ) // Up
1521 ScBaseCell* pCell = maItems[nUpIndex-1].pCell;
1522 CellType eType = pCell->GetCellType();
1523 if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT) // Only Strings are of interest
1525 if (eType == CELLTYPE_STRING)
1526 aString = ((ScStringCell*)pCell)->GetString();
1527 else
1528 aString = ((ScEditCell*)pCell)->GetString();
1530 bool bInserted = rStrings.insert(ScTypedStrData(aString)).second;
1531 if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
1532 break; // Maximum reached
1533 bFound = true;
1535 if ( bLimit )
1536 if (++nCells >= DATENT_SEARCH)
1537 break; // Searched enough
1539 --nUpIndex;
1542 if ( nDownIndex < maItems.size() ) // Down
1544 ScBaseCell* pCell = maItems[nDownIndex].pCell;
1545 CellType eType = pCell->GetCellType();
1546 if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT) // Only Strings are of interest
1548 if (eType == CELLTYPE_STRING)
1549 aString = ((ScStringCell*)pCell)->GetString();
1550 else
1551 aString = ((ScEditCell*)pCell)->GetString();
1553 bool bInserted = rStrings.insert(ScTypedStrData(aString)).second;
1554 if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
1555 break; // Maximum reached
1556 bFound = true;
1558 if ( bLimit )
1559 if (++nCells >= DATENT_SEARCH)
1560 break; // Searched enough
1562 ++nDownIndex;
1566 return bFound;
1569 #undef DATENT_MAX
1570 #undef DATENT_SEARCH
1573 void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
1575 ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
1576 SCROW nTop = -1;
1577 SCROW nBottom = -1;
1578 SCSIZE nIndex;
1579 const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
1580 while (pPattern)
1582 const ScProtectionAttr* pAttr = (const ScProtectionAttr*)&pPattern->GetItem(ATTR_PROTECTION);
1583 if ( pAttr->GetHideCell() )
1584 DeleteArea( nTop, nBottom, IDF_CONTENTS );
1585 else if ( pAttr->GetHideFormula() )
1587 Search( nTop, nIndex );
1588 while ( nIndex<maItems.size() && maItems[nIndex].nRow<=nBottom )
1590 if ( maItems[nIndex].pCell->GetCellType() == CELLTYPE_FORMULA )
1592 ScFormulaCell* pFormula = (ScFormulaCell*)maItems[nIndex].pCell;
1593 if (pFormula->IsValue())
1595 double nVal = pFormula->GetValue();
1596 maItems[nIndex].pCell = new ScValueCell( nVal );
1598 else
1600 String aString = pFormula->GetString();
1601 maItems[nIndex].pCell = new ScStringCell( aString );
1603 delete pFormula;
1605 SetTextWidth(maItems[nIndex].nRow, TEXTWIDTH_DIRTY);
1606 CellStorageModified();
1608 ++nIndex;
1612 pPattern = aAttrIter.Next( nTop, nBottom );
1617 void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError)
1619 if (ValidRow(nRow))
1621 ScFormulaCell* pCell = new ScFormulaCell
1622 ( pDocument, ScAddress( nCol, nRow, nTab ) );
1623 pCell->SetErrCode( nError );
1624 Insert( nRow, pCell );
1628 void ScColumn::SetRawString( SCROW nRow, const OUString& rStr )
1630 if (!ValidRow(nRow))
1631 return;
1633 ScBaseCell* pCell = new ScStringCell(rStr);
1634 Insert(nRow, pCell);
1637 void ScColumn::SetValue( SCROW nRow, const double& rVal)
1639 if (ValidRow(nRow))
1641 ScBaseCell* pCell = new ScValueCell(rVal);
1642 Insert( nRow, pCell );
1647 void ScColumn::GetString( SCROW nRow, OUString& rString ) const
1649 SCSIZE nIndex;
1650 Color* pColor;
1651 if (Search(nRow, nIndex))
1653 ScRefCellValue aCell;
1654 aCell.assign(*maItems[nIndex].pCell);
1656 // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
1657 if(aCell.meType == CELLTYPE_FORMULA)
1658 aCell.mpFormula->MaybeInterpret();
1660 sal_uLong nFormat = GetNumberFormat( nRow );
1661 ScCellFormat::GetString(aCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()), pDocument);
1663 else
1664 rString = EMPTY_OUSTRING;
1667 const OUString* ScColumn::GetStringCell( SCROW nRow ) const
1669 SCSIZE nIndex;
1670 if (!Search(nRow, nIndex))
1671 return NULL;
1673 const ScBaseCell* pCell = maItems[nIndex].pCell;
1674 if (pCell->GetCellType() != CELLTYPE_STRING)
1675 return NULL;
1677 return static_cast<const ScStringCell*>(pCell)->GetStringPtr();
1680 double* ScColumn::GetValueCell( SCROW nRow )
1682 SCSIZE nIndex;
1683 if (!Search(nRow, nIndex))
1684 return NULL;
1686 ScBaseCell* pCell = maItems[nIndex].pCell;
1687 if (pCell->GetCellType() != CELLTYPE_VALUE)
1688 return NULL;
1690 return static_cast<ScValueCell*>(pCell)->GetValuePtr();
1693 void ScColumn::GetInputString( SCROW nRow, OUString& rString ) const
1695 SCSIZE nIndex;
1696 if (Search(nRow, nIndex))
1698 ScRefCellValue aCell;
1699 aCell.assign(*maItems[nIndex].pCell);
1700 sal_uLong nFormat = GetNumberFormat( nRow );
1701 ScCellFormat::GetInputString(aCell, nFormat, rString, *(pDocument->GetFormatTable()), pDocument);
1703 else
1704 rString = OUString();
1708 double ScColumn::GetValue( SCROW nRow ) const
1710 SCSIZE nIndex;
1711 if (Search(nRow, nIndex))
1713 ScBaseCell* pCell = maItems[nIndex].pCell;
1714 switch (pCell->GetCellType())
1716 case CELLTYPE_VALUE:
1717 return ((ScValueCell*)pCell)->GetValue();
1719 case CELLTYPE_FORMULA:
1721 if (((ScFormulaCell*)pCell)->IsValue())
1722 return ((ScFormulaCell*)pCell)->GetValue();
1723 else
1724 return 0.0;
1727 default:
1728 return 0.0;
1731 return 0.0;
1734 const EditTextObject* ScColumn::GetEditText( SCROW nRow ) const
1736 SCSIZE nIndex;
1737 if (!Search(nRow, nIndex))
1738 return NULL;
1740 const ScBaseCell* pCell = maItems[nIndex].pCell;
1741 if (pCell->GetCellType() != CELLTYPE_EDIT)
1742 return NULL;
1744 const ScEditCell* pEditCell = static_cast<const ScEditCell*>(pCell);
1745 return pEditCell->GetData();
1748 void ScColumn::RemoveEditTextCharAttribs( SCROW nRow, const ScPatternAttr& rAttr )
1750 SCSIZE nIndex;
1751 if (!Search(nRow, nIndex))
1752 return;
1754 ScBaseCell* pCell = maItems[nIndex].pCell;
1755 if (pCell->GetCellType() != CELLTYPE_EDIT)
1756 return;
1758 ScEditCell* pEditCell = static_cast<ScEditCell*>(pCell);
1759 pEditCell->RemoveCharAttribs(rAttr);
1762 void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const
1764 SCSIZE nIndex;
1765 if (Search(nRow, nIndex))
1767 ScBaseCell* pCell = maItems[nIndex].pCell;
1768 if (pCell->GetCellType() == CELLTYPE_FORMULA)
1769 ((ScFormulaCell*)pCell)->GetFormula( rFormula );
1770 else
1771 rFormula = OUString();
1773 else
1774 rFormula = OUString();
1777 const ScTokenArray* ScColumn::GetFormulaTokens( SCROW nRow ) const
1779 const ScFormulaCell* pCell = FetchFormulaCell(nRow);
1780 if (!pCell)
1781 return NULL;
1783 return pCell->GetCode();
1786 const ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow ) const
1788 return FetchFormulaCell(nRow);
1791 ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow )
1793 return const_cast<ScFormulaCell*>(FetchFormulaCell(nRow));
1796 CellType ScColumn::GetCellType( SCROW nRow ) const
1798 SCSIZE nIndex;
1799 if (Search(nRow, nIndex))
1800 return maItems[nIndex].pCell->GetCellType();
1801 return CELLTYPE_NONE;
1804 SCSIZE ScColumn::GetCellCount() const
1806 return maItems.size();
1809 sal_uInt16 ScColumn::GetErrCode( SCROW nRow ) const
1811 SCSIZE nIndex;
1812 if (Search(nRow, nIndex))
1814 ScBaseCell* pCell = maItems[nIndex].pCell;
1815 if (pCell->GetCellType() == CELLTYPE_FORMULA)
1816 return ((ScFormulaCell*)pCell)->GetErrCode();
1818 return 0;
1822 bool ScColumn::HasStringData( SCROW nRow ) const
1824 SCSIZE nIndex;
1825 if (Search(nRow, nIndex))
1826 return (maItems[nIndex].pCell)->HasStringData();
1827 return false;
1831 bool ScColumn::HasValueData( SCROW nRow ) const
1833 SCSIZE nIndex;
1834 if (Search(nRow, nIndex))
1835 return (maItems[nIndex].pCell)->HasValueData();
1836 return false;
1840 * Return true if there is a string or editcell in the range
1842 bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
1844 if ( !maItems.empty() )
1846 SCSIZE nIndex;
1847 Search( nStartRow, nIndex );
1848 while ( nIndex < maItems.size() && maItems[nIndex].nRow <= nEndRow )
1850 CellType eType = maItems[nIndex].pCell->GetCellType();
1851 if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
1852 return sal_True;
1853 ++nIndex;
1856 return false;
1860 sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const
1862 sal_Int32 nStringLen = 0;
1863 if ( !maItems.empty() )
1865 OUString aString;
1866 OString aOString;
1867 bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet);
1868 SvNumberFormatter* pNumFmt = pDocument->GetFormatTable();
1869 SCSIZE nIndex;
1870 SCROW nRow;
1871 Search( nRowStart, nIndex );
1872 while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRowEnd )
1874 ScRefCellValue aCell;
1875 aCell.assign(*maItems[nIndex].pCell);
1876 Color* pColor;
1877 sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr(
1878 nRow, ATTR_VALUE_FORMAT ))->GetValue();
1879 ScCellFormat::GetString(aCell, nFormat, aString, &pColor, *pNumFmt, pDocument);
1880 sal_Int32 nLen;
1881 if (bIsOctetTextEncoding)
1883 if (!aString.convertToString( &aOString, eCharSet,
1884 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1885 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
1887 // TODO: anything? this is used by the dBase export filter
1888 // that throws an error anyway, but in case of another
1889 // context we might want to indicate a conversion error
1890 // early.
1892 nLen = aOString.getLength();
1894 else
1895 nLen = aString.getLength() * sizeof(sal_Unicode);
1896 if ( nStringLen < nLen)
1897 nStringLen = nLen;
1898 nIndex++;
1901 return nStringLen;
1905 xub_StrLen ScColumn::GetMaxNumberStringLen(
1906 sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
1908 xub_StrLen nStringLen = 0;
1909 nPrecision = 0;
1911 if ( !maItems.empty() )
1913 OUString aString;
1914 String aSep;
1915 SvNumberFormatter* pNumFmt = pDocument->GetFormatTable();
1916 sal_uInt16 nMaxGeneralPrecision = pDocument->GetDocOptions().GetStdPrecision();
1917 // Limit the decimals passed to doubleToUString().
1918 // Also, the dBaseIII maximum precision is 15.
1919 if (nMaxGeneralPrecision > 15)
1920 nMaxGeneralPrecision = 15;
1921 bool bHaveSigned = false;
1922 SCSIZE nIndex;
1923 SCROW nRow;
1924 Search( nRowStart, nIndex );
1925 while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRowEnd )
1927 ScRefCellValue aCell;
1928 aCell.assign(*maItems[nIndex].pCell);
1929 CellType eType = aCell.meType;
1930 if ( eType == CELLTYPE_VALUE || (eType == CELLTYPE_FORMULA
1931 && aCell.mpFormula->IsValue()) )
1935 sal_uInt16 nCellPrecision = nMaxGeneralPrecision;
1936 if (eType == CELLTYPE_FORMULA)
1938 // Limit unformatted formula cell precision to precision
1939 // encountered so far, if any, otherwise we'd end up with 15 just
1940 // because of =1/3 ... If no precision yet then arbitrarily limit
1941 // to a maximum of 4 unless a maximum general precision is set.
1942 if (nPrecision)
1943 nCellPrecision = nPrecision;
1944 else
1945 nCellPrecision = (nMaxGeneralPrecision >= 15) ? 4 : nMaxGeneralPrecision;
1948 double fVal = aCell.getValue();
1949 if (!bHaveSigned && fVal < 0.0)
1950 bHaveSigned = true;
1952 sal_uInt16 nPrec;
1953 sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr(
1954 nRow, ATTR_VALUE_FORMAT ))->GetValue();
1955 if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
1957 aSep = pNumFmt->GetFormatDecimalSep(nFormat);
1958 ScCellFormat::GetInputString(aCell, nFormat, aString, *pNumFmt, pDocument);
1959 const SvNumberformat* pEntry = pNumFmt->GetEntry( nFormat );
1960 if (pEntry)
1962 bool bThousand, bNegRed;
1963 sal_uInt16 nLeading;
1964 pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
1966 else
1967 nPrec = pNumFmt->GetFormatPrecision( nFormat );
1969 else
1971 if (nPrecision >= nMaxGeneralPrecision)
1972 break; // early bail out for nothing changes here
1974 if (!fVal)
1976 // 0 doesn't change precision, but set a maximum length if none yet.
1977 if (!nStringLen)
1978 nStringLen = 1;
1979 break;
1982 // Simple number string with at most 15 decimals and trailing
1983 // decimal zeros eliminated.
1984 aSep = ".";
1985 aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
1986 nPrec = SvNumberFormatter::UNLIMITED_PRECISION;
1989 sal_Int32 nLen = aString.getLength();
1990 if (nLen <= 0)
1991 // Ignore empty string.
1992 break;
1994 if (nPrec == SvNumberFormatter::UNLIMITED_PRECISION && nPrecision < nMaxGeneralPrecision)
1996 if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
1998 // For some reason we couldn't obtain a precision from the
1999 // format, retry with simple number string.
2000 aSep = ".";
2001 aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
2002 nLen = aString.getLength();
2004 sal_Int32 nSep = aString.indexOf( aSep);
2005 if (nSep != -1)
2006 nPrec = aString.getLength() - nSep - 1;
2010 if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > nPrecision)
2011 nPrecision = nPrec;
2013 if ( nPrecision )
2014 { // less than nPrecision in string => widen it
2015 // more => shorten it
2016 sal_Int32 nTmp = aString.indexOf( aSep );
2017 if ( nTmp == -1 )
2018 nLen += nPrecision + aSep.Len();
2019 else
2021 nTmp = aString.getLength() - (nTmp + aSep.Len());
2022 if ( nTmp != nPrecision )
2023 nLen += nPrecision - nTmp;
2024 // nPrecision > nTmp : nLen + Diff
2025 // nPrecision < nTmp : nLen - Diff
2029 // Enlarge for sign if necessary. Bear in mind that
2030 // GetMaxNumberStringLen() is for determining dBase decimal field width
2031 // and precision where the overall field width must include the sign.
2032 // Fitting -1 into "#.##" (width 4, 2 decimals) does not work.
2033 if (bHaveSigned && fVal >= 0.0)
2034 ++nLen;
2036 if ( nStringLen < nLen )
2037 nStringLen = nLen;
2039 } while (0);
2041 nIndex++;
2044 return nStringLen;
2047 namespace {
2049 struct CellGroupSetter : std::unary_function<ColEntry, void>
2051 ScFormulaCellGroupRef mxGroup;
2052 public:
2053 CellGroupSetter(const ScFormulaCellGroupRef& xGroup) : mxGroup(xGroup) {}
2055 void operator() (ColEntry& rEntry)
2057 if (rEntry.pCell && rEntry.pCell->GetCellType() == CELLTYPE_FORMULA)
2058 static_cast<ScFormulaCell*>(rEntry.pCell)->SetCellGroup(mxGroup);
2064 // Very[!] slow way to look for and merge contiguous runs
2065 // of similar formulae into a formulagroup
2066 void ScColumn::RebuildFormulaGroups()
2068 if ( maItems.empty() || !mbDirtyGroups )
2069 return;
2071 // clear double groups
2072 std::for_each(maDoubles.begin(), maDoubles.end(), ScDeleteObjectByPtr<ColDoubleEntry>());
2073 maDoubles.clear();
2075 // clear previous groups
2076 ScFormulaCellGroupRef xNone;
2077 std::for_each(maItems.begin(), maItems.end(), CellGroupSetter(xNone));
2078 maFnGroups.clear();
2080 // re-build groups
2081 ColDoubleEntry *pLastDouble = NULL;
2082 for (size_t i = 1; i < maItems.size(); i++)
2084 ColEntry &rCur = maItems[ i ];
2085 ColEntry &rPrev = maItems[ i - 1 ];
2086 if ( ( rPrev.nRow != rCur.nRow - 1 ) || // not contiguous
2087 !rCur.pCell || !rPrev.pCell || // paranoia
2088 rCur.pCell->GetCellType() != rPrev.pCell->GetCellType() ) // same type
2090 // Non-contiguous cell detected. Break the series.
2091 pLastDouble = NULL;
2092 continue;
2095 // collate doubles
2096 if ( rCur.pCell->GetCellType() == CELLTYPE_VALUE )
2098 if ( !pLastDouble )
2100 pLastDouble = new ColDoubleEntry();
2101 pLastDouble->mnStart = rPrev.nRow;
2102 pLastDouble->maData.push_back(
2103 static_cast< ScValueCell * >( rPrev.pCell )->GetValue() );
2104 maDoubles.push_back( pLastDouble );
2106 pLastDouble->maData.push_back(
2107 static_cast< ScValueCell * >( rCur.pCell )->GetValue() );
2108 continue;
2111 if ( rCur.pCell->GetCellType() != CELLTYPE_FORMULA )
2112 continue;
2114 // see if these formula tokens are identical.
2115 ScFormulaCell *pCur = static_cast< ScFormulaCell *>( rCur.pCell );
2116 ScFormulaCell *pPrev = static_cast< ScFormulaCell *>( rPrev.pCell );
2118 ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(pCur);
2119 if (eCompState == ScFormulaCell::NotEqual)
2121 // different formula tokens.
2122 pCur->SetCellGroup( xNone );
2123 continue;
2126 ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup();
2127 if (!xGroup)
2129 // create a new group ...
2130 xGroup.reset(new ScFormulaCellGroup);
2131 xGroup->mnStart = rPrev.nRow;
2132 xGroup->mbInvariant = eCompState == ScFormulaCell::EqualInvariant;
2133 xGroup->mnLength = 2;
2135 maFnGroups.push_back( xGroup );
2137 pCur->SetCellGroup( xGroup );
2138 pPrev->SetCellGroup( xGroup );
2140 else
2142 // existing group. extend its length.
2143 pCur->SetCellGroup( xGroup );
2144 xGroup->mnLength++;
2148 #if OSL_DEBUG_LEVEL > 0
2149 if ( maDoubles.size() + maFnGroups.size() > 0 )
2151 OUString aStr;
2152 fprintf( stderr, "column %2d has %2d double span(s): ", (int)nCol, (int)maDoubles.size() );
2153 for (std::vector< ColDoubleEntry *>::iterator it = maDoubles.begin();
2154 it != maDoubles.end(); ++it )
2156 ScRange aDoubleRange( nCol, (*it)->mnStart, nTab,
2157 nCol, (*it)->mnStart + (*it)->maData.size() - 1, nTab );
2158 aDoubleRange.Format( aStr, SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW, pDocument );
2159 fprintf( stderr, "%s, ", OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 ).getStr() );
2161 fprintf( stderr, "\n" );
2163 fprintf( stderr, "column %2d has %2d formula span(s): ", (int)nCol, (int)maFnGroups.size() );
2164 for (std::vector< ScFormulaCellGroupRef>::iterator it = maFnGroups.begin();
2165 it != maFnGroups.end(); ++it )
2167 ScRange aDoubleRange( nCol, (*it)->mnStart, nTab,
2168 nCol, (*it)->mnStart + (*it)->mnLength - 1, nTab );
2169 aDoubleRange.Format( aStr, SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW, pDocument );
2170 fprintf( stderr, "%s, ", OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 ).getStr() );
2172 fprintf( stderr, "\n" );
2174 #endif
2176 mbDirtyGroups = false;
2179 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */