Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / column.cxx
blob007e9e317cf278f10310c676a9ab316b59acda26
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 "column.hxx"
21 #include "scitems.hxx"
22 #include "formulacell.hxx"
23 #include "document.hxx"
24 #include "docpool.hxx"
25 #include "attarray.hxx"
26 #include "patattr.hxx"
27 #include "compiler.hxx"
28 #include "brdcst.hxx"
29 #include "markdata.hxx"
30 #include "detfunc.hxx"
31 #include "postit.hxx"
32 #include "globalnames.hxx"
33 #include "cellvalue.hxx"
34 #include "tokenarray.hxx"
35 #include "cellform.hxx"
36 #include "clipcontext.hxx"
37 #include "types.hxx"
38 #include "editutil.hxx"
39 #include "mtvcellfunc.hxx"
40 #include "columnspanset.hxx"
41 #include "scopetools.hxx"
42 #include "sharedformula.hxx"
43 #include "refupdatecontext.hxx"
45 #include <svl/poolcach.hxx>
46 #include <svl/zforlist.hxx>
47 #include "svl/sharedstringpool.hxx"
48 #include <editeng/scripttypeitem.hxx>
49 #include "editeng/fieldupdater.hxx"
51 #include <cstring>
52 #include <map>
53 #include <cstdio>
54 #include <boost/scoped_ptr.hpp>
56 using ::editeng::SvxBorderLine;
57 using namespace formula;
59 namespace {
61 inline bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
63 //! move to a header file
64 return ( nScript != SCRIPTTYPE_LATIN &&
65 nScript != SCRIPTTYPE_ASIAN &&
66 nScript != SCRIPTTYPE_COMPLEX &&
67 nScript != 0 );
72 ScNeededSizeOptions::ScNeededSizeOptions() :
73 pPattern(NULL), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
77 ScColumn::ScColumn() :
78 maCellTextAttrs(MAXROWCOUNT),
79 maCellNotes(MAXROWCOUNT),
80 maBroadcasters(MAXROWCOUNT),
81 maCells(MAXROWCOUNT),
82 nCol( 0 ),
83 pAttrArray( NULL ),
84 pDocument( NULL ),
85 mbDirtyGroups(true)
90 ScColumn::~ScColumn()
92 FreeAll();
93 delete pAttrArray;
97 void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
99 nCol = nNewCol;
100 nTab = nNewTab;
101 pDocument = pDoc;
102 pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
106 SCsROW ScColumn::GetNextUnprotected( SCROW nRow, bool bUp ) const
108 return pAttrArray->GetNextUnprotected(nRow, bUp);
112 sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
114 using namespace sc;
116 if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
117 return 0;
119 ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
121 if (nRow1 == nRow2)
123 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
124 if (aPos.first->type != sc::element_type_formula)
125 return 0;
127 const ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
128 if (!pCell->GetMatrixFlag())
129 return 0;
131 return pCell->GetMatrixEdge(aOrigin);
134 bool bOpen = false;
135 sal_uInt16 nEdges = 0;
137 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
138 sc::CellStoreType::const_iterator it = aPos.first;
139 size_t nOffset = aPos.second;
140 SCROW nRow = nRow1;
141 for (;it != maCells.end() && nRow <= nRow2; ++it, nOffset = 0)
143 if (it->type != sc::element_type_formula)
145 // Skip this block.
146 nRow += it->size - nOffset;
147 continue;
150 size_t nRowsToRead = nRow2 - nRow + 1;
151 size_t nEnd = std::min(it->size, nRowsToRead);
152 sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
153 std::advance(itCell, nOffset);
154 for (size_t i = nOffset; i < nEnd; ++itCell, ++i)
156 // Loop inside the formula block.
157 const ScFormulaCell* pCell = *itCell;
158 if (!pCell->GetMatrixFlag())
159 continue;
161 nEdges = pCell->GetMatrixEdge(aOrigin);
162 if (!nEdges)
163 continue;
165 if (nEdges & MatrixEdgeTop)
166 bOpen = true; // top edge opens, keep on looking
167 else if (!bOpen)
168 return nEdges | MatrixEdgeOpen; // there's something that wasn't opened
169 else if (nEdges & MatrixEdgeInside)
170 return nEdges; // inside
171 // (nMask & 16 and (4 and not 16)) or
172 // (nMask & 4 and (16 and not 4))
173 if (((nMask & MatrixEdgeRight) && (nEdges & MatrixEdgeLeft) && !(nEdges & MatrixEdgeRight)) ||
174 ((nMask & MatrixEdgeLeft) && (nEdges & MatrixEdgeRight) && !(nEdges & MatrixEdgeLeft)))
175 return nEdges; // only left/right edge
177 if (nEdges & MatrixEdgeBottom)
178 bOpen = false; // bottom edge closes
181 nRow += nEnd;
183 if (bOpen)
184 nEdges |= MatrixEdgeOpen; // not closed, matrix continues
186 return nEdges;
190 bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
192 using namespace sc;
194 if (!rMark.IsMultiMarked())
195 return false;
197 ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
198 ScAddress aCurOrigin = aOrigin;
200 bool bOpen = false;
201 ScRangeList aRanges = rMark.GetMarkedRanges();
202 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
204 const ScRange& r = *aRanges[i];
205 if (nTab < r.aStart.Tab() || r.aEnd.Tab() < nTab)
206 continue;
208 if (nCol < r.aStart.Col() || r.aEnd.Col() < nCol)
209 continue;
211 SCROW nTop = r.aStart.Row(), nBottom = r.aEnd.Row();
212 SCROW nRow = nTop;
213 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
214 sc::CellStoreType::const_iterator it = aPos.first;
215 size_t nOffset = aPos.second;
217 for (;it != maCells.end() && nRow <= nBottom; ++it, nOffset = 0)
219 if (it->type != sc::element_type_formula)
221 // Skip this block.
222 nRow += it->size - nOffset;
223 continue;
226 // This is a formula cell block.
227 size_t nRowsToRead = nBottom - nRow + 1;
228 size_t nEnd = std::min(it->size, nRowsToRead);
229 sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
230 std::advance(itCell, nOffset);
231 for (size_t j = nOffset; j < nEnd; ++itCell, ++j)
233 // Loop inside the formula block.
234 const ScFormulaCell* pCell = *itCell;
235 if (!pCell->GetMatrixFlag())
236 // cell is not a part of a matrix.
237 continue;
239 sal_uInt16 nEdges = pCell->GetMatrixEdge(aOrigin);
240 if (!nEdges)
241 continue;
243 bool bFound = false;
245 if (nEdges & MatrixEdgeTop)
246 bOpen = true; // top edge opens, keep on looking
247 else if (!bOpen)
248 return true; // there's something that wasn't opened
249 else if (nEdges & MatrixEdgeInside)
250 bFound = true; // inside, all selected?
252 if ((((nEdges & MatrixEdgeLeft) | MatrixEdgeRight) ^ ((nEdges & MatrixEdgeRight) | MatrixEdgeLeft)))
253 // either left or right, but not both.
254 bFound = true; // only left/right edge, all selected?
256 if (nEdges & MatrixEdgeBottom)
257 bOpen = false; // bottom edge closes
259 if (bFound)
261 // Check if the matrix is inside the selection in its entirety.
263 // TODO: It's more efficient to skip the matrix range if
264 // it's within selection, to avoid checking it again and
265 // again.
267 if (aCurOrigin != aOrigin)
268 { // new matrix to check?
269 aCurOrigin = aOrigin;
270 const ScFormulaCell* pFCell;
271 if (pCell->GetMatrixFlag() == MM_REFERENCE)
272 pFCell = pDocument->GetFormulaCell(aOrigin);
273 else
274 pFCell = pCell;
276 SCCOL nC;
277 SCROW nR;
278 pFCell->GetMatColsRows(nC, nR);
279 ScRange aRange(aOrigin, ScAddress(aOrigin.Col()+nC-1, aOrigin.Row()+nR-1, aOrigin.Tab()));
280 if (rMark.IsAllMarked(aRange))
281 bFound = false;
283 else
284 bFound = false; // done already
287 if (bFound)
288 return true;
291 nRow += nEnd;
295 if (bOpen)
296 return true;
298 return false;
302 bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
304 return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
308 bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
310 bool bFound = false;
312 SCROW nTop;
313 SCROW nBottom;
315 if (rMark.IsMultiMarked())
317 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
318 while (aMarkIter.Next( nTop, nBottom ) && !bFound)
320 if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
321 bFound = true;
325 return bFound;
329 bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
330 SCCOL& rPaintCol, SCROW& rPaintRow,
331 bool bRefresh )
333 return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh );
337 void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
339 SCROW nTop;
340 SCROW nBottom;
342 if ( rMark.IsMultiMarked() )
344 const ScMarkArray* pArray = rMark.GetArray() + nCol;
345 if ( pArray->HasMarks() )
347 ScMarkArrayIter aMarkIter( pArray );
348 while (aMarkIter.Next( nTop, nBottom ))
349 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
355 void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, bool bDeep ) const
357 pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
361 void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
362 ScLineFlags& rFlags,
363 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
365 pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
369 void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
370 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
372 pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
376 const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
378 return pAttrArray->GetPattern( nRow );
382 const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
384 return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
388 const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
390 ::std::map< const ScPatternAttr*, size_t > aAttrMap;
391 const ScPatternAttr* pMaxPattern = 0;
392 size_t nMaxCount = 0;
394 ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
395 const ScPatternAttr* pPattern;
396 SCROW nAttrRow1 = 0, nAttrRow2 = 0;
398 while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
400 size_t& rnCount = aAttrMap[ pPattern ];
401 rnCount += (nAttrRow2 - nAttrRow1 + 1);
402 if( rnCount > nMaxCount )
404 pMaxPattern = pPattern;
405 nMaxCount = rnCount;
409 return pMaxPattern;
412 sal_uInt32 ScColumn::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
414 SCROW nPatStartRow, nPatEndRow;
415 const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
416 sal_uInt32 nFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
417 while (nEndRow > nPatEndRow)
419 nStartRow = nPatEndRow + 1;
420 pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
421 sal_uInt32 nTmpFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
422 if (nFormat != nTmpFormat)
423 return 0;
425 return nFormat;
429 sal_uInt32 ScColumn::GetNumberFormat( SCROW nRow ) const
431 return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
435 SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray )
437 SCROW nTop = 0;
438 SCROW nBottom = 0;
439 bool bFound = false;
441 if ( rMark.IsMultiMarked() )
443 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
444 while (aMarkIter.Next( nTop, nBottom ))
446 pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray );
447 bFound = true;
451 if (!bFound)
452 return -1;
453 else if (nTop==0 && nBottom==MAXROW)
454 return 0;
455 else
456 return nBottom;
460 void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
462 SCROW nTop;
463 SCROW nBottom;
465 if ( pAttrArray && rMark.IsMultiMarked() )
467 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
468 while (aMarkIter.Next( nTop, nBottom ))
469 pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
473 void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
475 SCROW nTop;
476 SCROW nBottom;
478 if ( pAttrArray && rMark.IsMultiMarked() )
480 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
481 while (aMarkIter.Next( nTop, nBottom ))
482 pAttrArray->ClearItems(nTop, nBottom, pWhich);
487 void ScColumn::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
489 SCROW nTop;
490 SCROW nBottom;
492 if ( rMark.IsMultiMarked() )
494 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
495 while (aMarkIter.Next( nTop, nBottom ))
496 DeleteArea(nTop, nBottom, nDelFlag);
501 void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
503 const SfxItemSet* pSet = &rPatAttr.GetItemSet();
504 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
506 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
508 // true = keep old content
510 ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, true );
511 ScDocumentPool::CheckRef( *pPattern );
512 ScDocumentPool::CheckRef( *pNewPattern );
514 if (pNewPattern != pPattern)
515 pAttrArray->SetPattern( nRow, pNewPattern );
519 void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr,
520 ScEditDataArray* pDataArray )
522 const SfxItemSet* pSet = &rPatAttr.GetItemSet();
523 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
524 pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache, pDataArray );
527 bool ScColumn::SetAttrEntries(ScAttrEntry* pData, SCSIZE nSize)
529 return pAttrArray->SetAttrEntries(pData, nSize);
532 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
533 const ScPatternAttr& rPattern, short nNewType )
535 const SfxItemSet* pSet = &rPattern.GetItemSet();
536 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
537 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
538 SCROW nEndRow = rRange.aEnd.Row();
539 for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
541 SCROW nRow1, nRow2;
542 const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
543 nRow1, nRow2, nRow );
544 sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
545 short nOldType = pFormatter->GetType( nFormat );
546 if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) )
547 nRow = nRow2;
548 else
550 SCROW nNewRow1 = std::max( nRow1, nRow );
551 SCROW nNewRow2 = std::min( nRow2, nEndRow );
552 pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
553 nRow = nNewRow2;
558 void ScColumn::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
560 pAttrArray->AddCondFormat( nStartRow, nEndRow, nIndex );
563 void ScColumn::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
565 pAttrArray->RemoveCondFormat( nStartRow, nEndRow, nIndex );
569 void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
571 const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
572 ScPatternAttr* pNewPattern = new ScPatternAttr(*pPattern);
573 if (pNewPattern)
575 pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
576 pAttrArray->SetPattern(nRow, pNewPattern, true);
577 delete pNewPattern;
582 void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
584 pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle);
588 void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
590 SCROW nTop;
591 SCROW nBottom;
593 if ( rMark.IsMultiMarked() )
595 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
596 while (aMarkIter.Next( nTop, nBottom ))
597 pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle);
602 void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
603 const SvxBorderLine* pLine, bool bColorOnly )
605 if ( bColorOnly && !pLine )
606 return;
608 SCROW nTop;
609 SCROW nBottom;
611 if (rMark.IsMultiMarked())
613 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
614 while (aMarkIter.Next( nTop, nBottom ))
615 pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
620 const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
622 return pAttrArray->GetPattern( nRow )->GetStyleSheet();
626 const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
628 rFound = false;
629 if (!rMark.IsMultiMarked())
631 OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
632 return NULL;
635 bool bEqual = true;
637 const ScStyleSheet* pStyle = NULL;
638 const ScStyleSheet* pNewStyle;
640 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
641 SCROW nTop;
642 SCROW nBottom;
643 while (bEqual && aMarkIter.Next( nTop, nBottom ))
645 ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
646 SCROW nRow;
647 SCROW nDummy;
648 const ScPatternAttr* pPattern;
649 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
651 pNewStyle = pPattern->GetStyleSheet();
652 rFound = true;
653 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
654 bEqual = false; // difference
655 pStyle = pNewStyle;
659 return bEqual ? pStyle : NULL;
663 const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRow2 ) const
665 rFound = false;
667 bool bEqual = true;
669 const ScStyleSheet* pStyle = NULL;
670 const ScStyleSheet* pNewStyle;
672 ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
673 SCROW nRow;
674 SCROW nDummy;
675 const ScPatternAttr* pPattern;
676 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
678 pNewStyle = pPattern->GetStyleSheet();
679 rFound = true;
680 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
681 bEqual = false; // difference
682 pStyle = pNewStyle;
685 return bEqual ? pStyle : NULL;
688 void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
690 pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
693 bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const
695 return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
699 bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
701 return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
705 bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
707 return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
711 void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
713 pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
717 void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, bool bPutToPool )
719 pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
723 void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
724 const ScPatternAttr& rPatAttr, bool bPutToPool )
726 pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
730 void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
732 // in order to only create a new SetItem, we don't need SfxItemPoolCache.
733 //! Warning: SfxItemPoolCache seems to create to many Refs for the new SetItem ??
735 ScDocumentPool* pDocPool = pDocument->GetPool();
737 const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
738 ScPatternAttr* pTemp = new ScPatternAttr(*pOldPattern);
739 pTemp->GetItemSet().Put(rAttr);
740 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pDocPool->Put( *pTemp );
742 if ( pNewPattern != pOldPattern )
743 pAttrArray->SetPattern( nRow, pNewPattern );
744 else
745 pDocPool->Remove( *pNewPattern ); // free up resources
747 delete pTemp;
750 ScDocument& ScColumn::GetDoc()
752 return *pDocument;
755 const ScDocument& ScColumn::GetDoc() const
757 return *pDocument;
760 ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
762 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
763 if (aPos.first == maCells.end())
764 return ScRefCellValue();
766 return GetCellValue(aPos.first, aPos.second);
769 ScRefCellValue ScColumn::GetCellValue( const sc::CellStoreType::const_iterator& itPos, size_t nOffset ) const
771 ScRefCellValue aVal; // Defaults to empty cell.
772 switch (itPos->type)
774 case sc::element_type_numeric:
775 // Numeric cell
776 aVal.mfValue = sc::numeric_block::at(*itPos->data, nOffset);
777 aVal.meType = CELLTYPE_VALUE;
778 break;
779 case sc::element_type_string:
780 // String cell
781 aVal.mpString = &sc::string_block::at(*itPos->data, nOffset);
782 aVal.meType = CELLTYPE_STRING;
783 break;
784 case sc::element_type_edittext:
785 // Edit cell
786 aVal.mpEditText = sc::edittext_block::at(*itPos->data, nOffset);
787 aVal.meType = CELLTYPE_EDIT;
788 break;
789 case sc::element_type_formula:
790 // Formula cell
791 aVal.mpFormula = sc::formula_block::at(*itPos->data, nOffset);
792 aVal.meType = CELLTYPE_FORMULA;
793 break;
794 default:
798 return aVal;
801 namespace {
803 ScFormulaCell* cloneFormulaCell(ScDocument* pDoc, const ScAddress& rNewPos, ScFormulaCell& rOldCell)
805 ScFormulaCell* pNew = new ScFormulaCell(rOldCell, *pDoc, rNewPos, SC_CLONECELL_ADJUST3DREL);
806 rOldCell.EndListeningTo(pDoc);
807 pNew->StartListeningTo(pDoc);
808 pNew->SetDirty();
809 return pNew;
814 void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
816 if (nRow1 == nRow2)
817 // Nothing to swap.
818 return;
820 // Ensure that nRow1 < nRow2.
821 if (nRow2 < nRow1)
822 std::swap(nRow1, nRow2);
824 // Broadcasters (if exist) should NOT be swapped.
826 sc::CellStoreType::position_type aPos1 = maCells.position(nRow1);
827 if (aPos1.first == maCells.end())
828 return;
830 sc::CellStoreType::position_type aPos2 = maCells.position(aPos1.first, nRow2);
831 if (aPos2.first == maCells.end())
832 return;
834 std::vector<SCROW> aRows;
835 aRows.reserve(2);
836 aRows.push_back(nRow1);
837 aRows.push_back(nRow2);
839 sc::CellStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
841 if (it1->type == it2->type)
843 // Both positions are of the same type. Do a simple value swap.
844 switch (it1->type)
846 case sc::element_type_empty:
847 // Both are empty. Nothing to swap.
848 return;
849 case sc::element_type_numeric:
850 std::swap(
851 sc::numeric_block::at(*it1->data, aPos1.second),
852 sc::numeric_block::at(*it2->data, aPos2.second));
853 break;
854 case sc::element_type_string:
855 std::swap(
856 sc::string_block::at(*it1->data, aPos1.second),
857 sc::string_block::at(*it2->data, aPos2.second));
858 break;
859 case sc::element_type_edittext:
860 std::swap(
861 sc::edittext_block::at(*it1->data, aPos1.second),
862 sc::edittext_block::at(*it2->data, aPos2.second));
863 break;
864 case sc::element_type_formula:
866 // Swapping of formula cells involve adjustment of references wrt their positions.
867 sc::formula_block::iterator itf1 = sc::formula_block::begin(*it1->data);
868 sc::formula_block::iterator itf2 = sc::formula_block::begin(*it2->data);
869 std::advance(itf1, aPos1.second);
870 std::advance(itf2, aPos2.second);
872 // TODO: Find out a way to adjust references without cloning new instances.
873 boost::scoped_ptr<ScFormulaCell> pOld1(*itf1);
874 boost::scoped_ptr<ScFormulaCell> pOld2(*itf2);
875 DetachFormulaCell(aPos1, **itf1);
876 DetachFormulaCell(aPos2, **itf2);
877 ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *pOld2);
878 ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *pOld1);
879 *itf1 = pNew1;
880 *itf2 = pNew2;
882 ActivateNewFormulaCell(aPos1, *pNew1);
883 ActivateNewFormulaCell(aPos2, *pNew2);
885 break;
886 default:
890 SwapCellTextAttrs(nRow1, nRow2);
891 SwapCellNotes(nRow1, nRow2);
892 CellStorageModified();
893 BroadcastCells(aRows, SC_HINT_DATACHANGED);
894 return;
897 // The two cells are of different types.
899 ScRefCellValue aCell1 = GetCellValue(aPos1.first, aPos1.second);
900 ScRefCellValue aCell2 = GetCellValue(aPos2.first, aPos2.second);
902 // Make sure to put cells in row 1 first then row 2!
904 if (aCell1.meType == CELLTYPE_NONE)
906 // cell 1 is empty and cell 2 is not.
907 switch (aCell2.meType)
909 case CELLTYPE_VALUE:
910 it1 = maCells.set(it1, nRow1, aCell2.mfValue); // it2 becomes invalid.
911 maCells.set_empty(it1, nRow2, nRow2);
912 break;
913 case CELLTYPE_STRING:
914 it1 = maCells.set(it1, nRow1, *aCell2.mpString);
915 maCells.set_empty(it1, nRow2, nRow2);
916 break;
917 case CELLTYPE_EDIT:
919 it1 = maCells.set(
920 it1, nRow1, const_cast<EditTextObject*>(aCell2.mpEditText));
921 EditTextObject* p;
922 maCells.release(it1, nRow2, p);
924 break;
925 case CELLTYPE_FORMULA:
927 // cell 1 is empty and cell 2 is a formula cell.
928 ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
929 DetachFormulaCell(aPos2, *aCell2.mpFormula);
930 it1 = maCells.set(it1, nRow1, pNew);
931 maCells.set_empty(it1, nRow2, nRow2); // original formula cell gets deleted.
932 ActivateNewFormulaCell(it1, nRow1, *pNew);
934 break;
935 default:
939 SwapCellTextAttrs(nRow1, nRow2);
940 SwapCellNotes(nRow1, nRow2);
941 CellStorageModified();
942 BroadcastCells(aRows, SC_HINT_DATACHANGED);
943 return;
946 if (aCell2.meType == CELLTYPE_NONE)
948 // cell 1 is not empty and cell 2 is empty.
949 switch (aCell1.meType)
951 case CELLTYPE_VALUE:
952 // Value is copied in Cell1.
953 it1 = maCells.set_empty(it1, nRow1, nRow1);
954 maCells.set(it1, nRow2, aCell1.mfValue);
955 break;
956 case CELLTYPE_STRING:
958 svl::SharedString aStr = *aCell1.mpString; // make a copy.
959 it1 = maCells.set_empty(it1, nRow1, nRow1); // original string is gone.
960 maCells.set(it1, nRow2, aStr);
962 break;
963 case CELLTYPE_EDIT:
965 EditTextObject* p;
966 it1 = maCells.release(it1, nRow1, p);
967 maCells.set(it1, nRow2, p);
969 break;
970 case CELLTYPE_FORMULA:
972 // cell 1 is a formula cell and cell 2 is empty.
973 ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *aCell1.mpFormula);
974 DetachFormulaCell(aPos1, *aCell1.mpFormula);
975 it1 = maCells.set_empty(it1, nRow1, nRow1); // original formula cell is gone.
976 it1 = maCells.set(it1, nRow2, pNew);
977 ActivateNewFormulaCell(it1, nRow2, *pNew);
979 break;
980 default:
984 SwapCellTextAttrs(nRow1, nRow2);
985 SwapCellNotes(nRow1, nRow2);
986 CellStorageModified();
987 BroadcastCells(aRows, SC_HINT_DATACHANGED);
988 return;
991 // Neither cells are empty, and they are of different types.
992 switch (aCell1.meType)
994 case CELLTYPE_VALUE:
996 switch (aCell2.meType)
998 case CELLTYPE_STRING:
999 it1 = maCells.set(it1, nRow1, *aCell2.mpString);
1000 break;
1001 case CELLTYPE_EDIT:
1003 it1 = maCells.set(
1004 it1, nRow1, const_cast<EditTextObject*>(aCell2.mpEditText));
1005 EditTextObject* p;
1006 it1 = maCells.release(it1, nRow2, p);
1008 break;
1009 case CELLTYPE_FORMULA:
1011 DetachFormulaCell(aPos2, *aCell2.mpFormula);
1012 ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
1013 it1 = maCells.set(it1, nRow1, pNew);
1014 ActivateNewFormulaCell(it1, nRow1, *pNew);
1015 // The old formula cell will get overwritten below.
1017 break;
1018 default:
1022 maCells.set(it1, nRow2, aCell1.mfValue);
1025 break;
1026 case CELLTYPE_STRING:
1028 svl::SharedString aStr = *aCell1.mpString; // make a copy.
1029 switch (aCell2.meType)
1031 case CELLTYPE_VALUE:
1032 it1 = maCells.set(it1, nRow1, aCell2.mfValue);
1033 break;
1034 case CELLTYPE_EDIT:
1036 it1 = maCells.set(
1037 it1, nRow1, const_cast<EditTextObject*>(aCell2.mpEditText));
1038 EditTextObject* p;
1039 it1 = maCells.release(it1, nRow2, p); // prevent it being overwritten.
1041 break;
1042 case CELLTYPE_FORMULA:
1044 // cell 1 - string, cell 2 - formula
1045 DetachFormulaCell(aPos2, *aCell2.mpFormula);
1046 ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
1047 it1 = maCells.set(it1, nRow1, pNew);
1048 ActivateNewFormulaCell(it1, nRow1, *pNew);
1049 // Old formula cell will get overwritten below.
1051 break;
1052 default:
1056 maCells.set(it1, nRow2, aStr);
1058 break;
1059 case CELLTYPE_EDIT:
1061 EditTextObject* p;
1062 it1 = maCells.release(it1, nRow1, p);
1064 switch (aCell2.meType)
1066 case CELLTYPE_VALUE:
1067 it1 = maCells.set(it1, nRow1, aCell2.mfValue);
1068 break;
1069 case CELLTYPE_STRING:
1070 it1 = maCells.set(it1, nRow1, *aCell2.mpString);
1071 break;
1072 case CELLTYPE_FORMULA:
1074 DetachFormulaCell(aPos2, *aCell2.mpFormula);
1075 ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
1076 it1 = maCells.set(it1, nRow1, pNew);
1077 ActivateNewFormulaCell(it1, nRow1, *pNew);
1078 // Old formula cell will get overwritten below.
1080 break;
1081 default:
1085 maCells.set(it1, nRow2, const_cast<EditTextObject*>(aCell1.mpEditText));
1087 break;
1088 case CELLTYPE_FORMULA:
1090 // cell 1 is a formula cell and cell 2 is not.
1091 DetachFormulaCell(aPos1, *aCell1.mpFormula);
1092 ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *aCell1.mpFormula);
1093 switch (aCell2.meType)
1095 case CELLTYPE_VALUE:
1096 it1 = maCells.set(it1, nRow1, aCell2.mfValue);
1097 break;
1098 case CELLTYPE_STRING:
1099 it1 = maCells.set(it1, nRow1, *aCell2.mpString);
1100 break;
1101 case CELLTYPE_EDIT:
1103 it1 = maCells.set(it1, nRow1, aCell2.mpEditText);
1104 EditTextObject* p;
1105 it1 = maCells.release(it1, nRow2, p);
1107 break;
1108 default:
1112 it1 = maCells.set(it1, nRow2, pNew);
1113 ActivateNewFormulaCell(it1, nRow2, *pNew);
1115 break;
1116 default:
1120 SwapCellTextAttrs(nRow1, nRow2);
1121 SwapCellNotes(nRow1, nRow2);
1122 CellStorageModified();
1123 BroadcastCells(aRows, SC_HINT_DATACHANGED);
1126 namespace {
1129 * Adjust references in formula cell with respect to column-wise relocation.
1131 void updateRefInFormulaCell( ScDocument* pDoc, ScFormulaCell& rCell, SCCOL nCol, SCTAB nTab, SCCOL nColDiff )
1133 rCell.aPos.SetCol(nCol);
1134 sc::RefUpdateContext aCxt(*pDoc);
1135 aCxt.meMode = URM_MOVE;
1136 aCxt.maRange = ScRange(ScAddress(nCol, 0, nTab), ScAddress(nCol, MAXROW, nTab));
1137 aCxt.mnColDelta = nColDiff;
1138 rCell.UpdateReference(aCxt);
1143 void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
1145 sc::CellStoreType::position_type aPos1 = maCells.position(nRow);
1146 sc::CellStoreType::position_type aPos2 = rCol.maCells.position(nRow);
1148 if (aPos1.first->type == sc::element_type_formula)
1150 ScFormulaCell& rCell = *sc::formula_block::at(*aPos1.first->data, aPos1.second);
1151 updateRefInFormulaCell(pDocument, rCell, rCol.nCol, nTab, rCol.nCol - nCol);
1152 sc::SharedFormulaUtil::unshareFormulaCell(aPos1, rCell);
1155 if (aPos2.first->type == sc::element_type_formula)
1157 ScFormulaCell& rCell = *sc::formula_block::at(*aPos2.first->data, aPos2.second);
1158 updateRefInFormulaCell(pDocument, rCell, nCol, nTab, nCol - rCol.nCol);
1159 sc::SharedFormulaUtil::unshareFormulaCell(aPos2, rCell);
1162 maCells.swap(nRow, nRow, rCol.maCells, nRow);
1163 maCellTextAttrs.swap(nRow, nRow, rCol.maCellTextAttrs, nRow);
1164 maCellNotes.swap(nRow, nRow, rCol.maCellNotes, nRow);
1166 aPos1 = maCells.position(nRow);
1167 aPos2 = rCol.maCells.position(nRow);
1169 if (aPos1.first->type == sc::element_type_formula)
1171 ScFormulaCell& rCell = *sc::formula_block::at(*aPos1.first->data, aPos1.second);
1172 JoinNewFormulaCell(aPos1, rCell);
1175 if (aPos2.first->type == sc::element_type_formula)
1177 ScFormulaCell& rCell = *sc::formula_block::at(*aPos2.first->data, aPos2.second);
1178 rCol.JoinNewFormulaCell(aPos2, rCell);
1181 CellStorageModified();
1182 rCol.CellStorageModified();
1186 bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1188 if (IsEmpty())
1189 return true;
1191 // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
1192 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1193 sc::CellStoreType::const_iterator it = aPos.first;
1194 if (it->type != sc::element_type_empty)
1195 return false;
1197 // Get the length of the remaining empty segment.
1198 size_t nLen = it->size - aPos.second;
1199 SCROW nNextNonEmptyRow = nStartRow + nLen;
1200 if (nNextNonEmptyRow <= nEndRow)
1201 return false;
1203 // AttrArray only looks for merged cells
1205 return pAttrArray ? pAttrArray->TestInsertCol(nStartRow, nEndRow) : true;
1209 bool ScColumn::TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const
1211 // AttrArray only looks for merged cells
1213 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1214 sc::CellStoreType::const_iterator it = aPos.first;
1215 if (it->type == sc::element_type_empty && maCells.block_size() == 1)
1216 // The entire cell array is empty.
1217 return pAttrArray->TestInsertRow(nSize);
1220 // See if there would be any non-empty cell that gets pushed out.
1222 // Find the position of the last non-empty cell below nStartRow.
1223 size_t nLastNonEmptyRow = MAXROW;
1224 sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
1225 if (it->type == sc::element_type_empty)
1226 nLastNonEmptyRow -= it->size;
1228 if (nLastNonEmptyRow < static_cast<size_t>(nStartRow))
1229 // No cells would get pushed out.
1230 return pAttrArray->TestInsertRow(nSize);
1232 if (nLastNonEmptyRow + nSize > static_cast<size_t>(MAXROW))
1233 // At least one cell would get pushed out. Not good.
1234 return false;
1236 return pAttrArray->TestInsertRow(nSize);
1240 void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
1242 pAttrArray->InsertRow( nStartRow, nSize );
1244 maCellNotes.insert_empty(nStartRow, nSize);
1245 maCellNotes.resize(MAXROWCOUNT);
1247 maBroadcasters.insert_empty(nStartRow, nSize);
1248 maBroadcasters.resize(MAXROWCOUNT);
1250 maCellTextAttrs.insert_empty(nStartRow, nSize);
1251 maCellTextAttrs.resize(MAXROWCOUNT);
1253 maCells.insert_empty(nStartRow, nSize);
1254 maCells.resize(MAXROWCOUNT);
1256 CellStorageModified();
1258 // We *probably* don't need to broadcast here since the parent call seems
1259 // to take care of it.
1262 namespace {
1264 class CopyToClipHandler
1266 const ScColumn& mrSrcCol;
1267 ScColumn& mrDestCol;
1268 sc::ColumnBlockPosition maDestPos;
1269 sc::ColumnBlockPosition* mpDestPos;
1270 bool mbCopyNotes;
1272 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1274 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1275 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1276 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1279 void duplicateNotes(SCROW nStartRow, size_t nDataSize )
1281 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos);
1284 public:
1285 CopyToClipHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, bool bCopyNotes) :
1286 mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mbCopyNotes(bCopyNotes)
1288 if (mpDestPos)
1289 maDestPos = *mpDestPos;
1290 else
1291 mrDestCol.InitBlockPosition(maDestPos);
1294 ~CopyToClipHandler()
1296 if (mpDestPos)
1297 *mpDestPos = maDestPos;
1300 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1302 size_t nTopRow = aNode.position + nOffset;
1304 bool bSet = true;
1306 switch (aNode.type)
1308 case sc::element_type_numeric:
1310 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1311 std::advance(it, nOffset);
1312 sc::numeric_block::const_iterator itEnd = it;
1313 std::advance(itEnd, nDataSize);
1314 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
1316 break;
1317 case sc::element_type_string:
1319 sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
1320 std::advance(it, nOffset);
1321 sc::string_block::const_iterator itEnd = it;
1322 std::advance(itEnd, nDataSize);
1323 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
1326 break;
1327 case sc::element_type_edittext:
1329 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
1330 std::advance(it, nOffset);
1331 sc::edittext_block::const_iterator itEnd = it;
1332 std::advance(itEnd, nDataSize);
1334 std::vector<EditTextObject*> aCloned;
1335 aCloned.reserve(nDataSize);
1336 for (; it != itEnd; ++it)
1337 aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
1339 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1340 maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
1342 break;
1343 case sc::element_type_formula:
1345 sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
1346 std::advance(it, nOffset);
1347 sc::formula_block::const_iterator itEnd = it;
1348 std::advance(itEnd, nDataSize);
1350 std::vector<ScFormulaCell*> aCloned;
1351 aCloned.reserve(nDataSize);
1352 ScAddress aDestPos(mrDestCol.GetCol(), nTopRow, mrDestCol.GetTab());
1353 for (; it != itEnd; ++it, aDestPos.IncRow())
1355 const ScFormulaCell& rOld = **it;
1356 if (rOld.GetDirty() && mrSrcCol.GetDoc().GetAutoCalc())
1357 const_cast<ScFormulaCell&>(rOld).Interpret();
1359 aCloned.push_back(new ScFormulaCell(rOld, mrDestCol.GetDoc(), aDestPos));
1362 // Group the cloned formula cells.
1363 if (!aCloned.empty())
1364 sc::SharedFormulaUtil::groupFormulaCells(aCloned.begin(), aCloned.end());
1366 sc::CellStoreType& rDestCells = mrDestCol.GetCellStore();
1367 maDestPos.miCellPos = rDestCells.set(
1368 maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
1370 // Merge adjacent formula cell groups (if applicable).
1371 sc::CellStoreType::position_type aPos =
1372 rDestCells.position(maDestPos.miCellPos, nTopRow);
1373 maDestPos.miCellPos = aPos.first;
1374 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1375 size_t nLastRow = nTopRow + nDataSize;
1376 if (nLastRow < static_cast<size_t>(MAXROW))
1378 aPos = rDestCells.position(maDestPos.miCellPos, nLastRow+1);
1379 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1382 break;
1383 default:
1384 bSet = false;
1387 if (bSet)
1388 setDefaultAttrsToDest(nTopRow, nDataSize);
1390 if (mbCopyNotes)
1391 duplicateNotes(nTopRow, nDataSize);
1397 void ScColumn::CopyToClip(
1398 sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
1400 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
1401 rCxt.isKeepScenarioFlags() ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
1403 CopyToClipHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), rCxt.isCloneNotes());
1404 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1406 rColumn.CellStorageModified();
1409 void ScColumn::CopyStaticToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol)
1411 if (nRow1 > nRow2)
1412 return;
1414 sc::ColumnBlockPosition aDestPos;
1415 CopyCellTextAttrsToDocument(nRow1, nRow2, rDestCol);
1416 CopyCellNotesToDocument(nRow1, nRow2, rDestCol);
1418 // First, clear the destination column for the specified row range.
1419 rDestCol.maCells.set_empty(nRow1, nRow2);
1421 aDestPos.miCellPos = rDestCol.maCells.begin();
1423 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
1424 sc::CellStoreType::const_iterator it = aPos.first;
1425 size_t nOffset = aPos.second;
1426 size_t nDataSize = 0;
1427 size_t nCurRow = nRow1;
1429 for (; it != maCells.end() && nCurRow <= static_cast<size_t>(nRow2); ++it, nOffset = 0, nCurRow += nDataSize)
1431 bool bLastBlock = false;
1432 nDataSize = it->size - nOffset;
1433 if (nCurRow + nDataSize - 1 > static_cast<size_t>(nRow2))
1435 // Truncate the block to copy to clipboard.
1436 nDataSize = nRow2 - nCurRow + 1;
1437 bLastBlock = true;
1440 switch (it->type)
1442 case sc::element_type_numeric:
1444 sc::numeric_block::const_iterator itData = sc::numeric_block::begin(*it->data);
1445 std::advance(itData, nOffset);
1446 sc::numeric_block::const_iterator itDataEnd = itData;
1447 std::advance(itDataEnd, nDataSize);
1448 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1450 break;
1451 case sc::element_type_string:
1453 sc::string_block::const_iterator itData = sc::string_block::begin(*it->data);
1454 std::advance(itData, nOffset);
1455 sc::string_block::const_iterator itDataEnd = itData;
1456 std::advance(itDataEnd, nDataSize);
1457 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1459 break;
1460 case sc::element_type_edittext:
1462 sc::edittext_block::const_iterator itData = sc::edittext_block::begin(*it->data);
1463 std::advance(itData, nOffset);
1464 sc::edittext_block::const_iterator itDataEnd = itData;
1465 std::advance(itDataEnd, nDataSize);
1467 // Convert to simple strings.
1468 std::vector<svl::SharedString> aConverted;
1469 aConverted.reserve(nDataSize);
1470 for (; itData != itDataEnd; ++itData)
1472 const EditTextObject& rObj = **itData;
1473 svl::SharedString aSS = pDocument->GetSharedStringPool().intern(ScEditUtil::GetString(rObj, pDocument));
1474 aConverted.push_back(aSS);
1476 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, aConverted.begin(), aConverted.end());
1478 break;
1479 case sc::element_type_formula:
1481 sc::formula_block::const_iterator itData = sc::formula_block::begin(*it->data);
1482 std::advance(itData, nOffset);
1483 sc::formula_block::const_iterator itDataEnd = itData;
1484 std::advance(itDataEnd, nDataSize);
1486 // Interpret and convert to raw values.
1487 for (SCROW i = 0; itData != itDataEnd; ++itData, ++i)
1489 SCROW nRow = nCurRow + i;
1491 ScFormulaCell& rFC = const_cast<ScFormulaCell&>(**itData);
1492 if (rFC.GetDirty() && pDocument->GetAutoCalc())
1493 rFC.Interpret();
1495 if (rFC.GetErrCode())
1496 // Skip cells with error.
1497 break;
1499 if (rFC.IsValue())
1500 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, rFC.GetValue());
1501 else
1503 svl::SharedString aSS = rFC.GetString();
1504 if (aSS.isValid())
1505 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, aSS);
1509 break;
1510 default:
1514 if (bLastBlock)
1515 break;
1518 rDestCol.CellStorageModified();
1521 void ScColumn::CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol )
1523 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nSrcRow);
1524 sc::CellStoreType::const_iterator it = aPos.first;
1525 bool bSet = true;
1526 switch (it->type)
1528 case sc::element_type_numeric:
1529 rDestCol.maCells.set(nDestRow, sc::numeric_block::at(*it->data, aPos.second));
1530 break;
1531 case sc::element_type_string:
1532 rDestCol.maCells.set(nDestRow, sc::string_block::at(*it->data, aPos.second));
1533 break;
1534 case sc::element_type_edittext:
1536 EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
1537 if (pDocument == rDestCol.pDocument)
1538 rDestCol.maCells.set(nDestRow, p->Clone());
1539 else
1540 rDestCol.maCells.set(nDestRow, ScEditUtil::Clone(*p, *rDestCol.pDocument));
1542 break;
1543 case sc::element_type_formula:
1545 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
1546 if (p->GetDirty() && pDocument->GetAutoCalc())
1547 p->Interpret();
1549 ScAddress aDestPos = p->aPos;
1550 aDestPos.SetRow(nDestRow);
1551 ScFormulaCell* pNew = new ScFormulaCell(*p, *rDestCol.pDocument, aDestPos);
1552 rDestCol.SetFormulaCell(nDestRow, pNew);
1554 break;
1555 case sc::element_type_empty:
1556 default:
1557 // empty
1558 rDestCol.maCells.set_empty(nDestRow, nDestRow);
1559 bSet = false;
1562 if (bSet)
1564 rDestCol.maCellTextAttrs.set(nDestRow, maCellTextAttrs.get<sc::CellTextAttr>(nSrcRow));
1565 ScPostIt* pNote = maCellNotes.get<ScPostIt*>(nSrcRow);
1566 rDestCol.maCellNotes.set(nDestRow, pNote);
1567 if (pNote)
1568 pNote->UpdateCaptionPos(ScAddress(rDestCol.nCol, nDestRow, rDestCol.nTab));
1570 else
1572 rDestCol.maCellTextAttrs.set_empty(nDestRow, nDestRow);
1573 rDestCol.maCellNotes.set_empty(nDestRow, nDestRow);
1576 rDestCol.CellStorageModified();
1579 namespace {
1581 bool canCopyValue(const ScDocument& rDoc, const ScAddress& rPos, sal_uInt16 nFlags)
1583 sal_uInt32 nNumIndex = static_cast<const SfxUInt32Item*>(rDoc.GetAttr(rPos, ATTR_VALUE_FORMAT))->GetValue();
1584 short nType = rDoc.GetFormatTable()->GetType(nNumIndex);
1585 if ((nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME))
1586 return ((nFlags & IDF_DATETIME) != 0);
1588 return ((nFlags & IDF_VALUE) != 0);
1591 class CopyAsLinkHandler
1593 const ScColumn& mrSrcCol;
1594 ScColumn& mrDestCol;
1595 sc::ColumnBlockPosition maDestPos;
1596 sc::ColumnBlockPosition* mpDestPos;
1597 sal_uInt16 mnCopyFlags;
1599 void setDefaultAttrToDest(size_t nRow)
1601 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1602 maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1605 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1607 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1608 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1609 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1612 ScFormulaCell* createRefCell(size_t nRow)
1614 ScSingleRefData aRef;
1615 aRef.InitAddress(ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab())); // Absolute reference.
1616 aRef.SetFlag3D(true);
1618 ScTokenArray aArr;
1619 aArr.AddSingleReference(aRef);
1620 return new ScFormulaCell(&mrDestCol.GetDoc(), ScAddress(mrDestCol.GetCol(), nRow, mrDestCol.GetTab()), aArr);
1623 void createRefBlock(const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1625 size_t nTopRow = aNode.position + nOffset;
1627 for (size_t i = 0; i < nDataSize; ++i)
1629 SCROW nRow = nTopRow + i;
1630 mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow));
1633 setDefaultAttrsToDest(nTopRow, nDataSize);
1636 void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1638 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1641 public:
1642 CopyAsLinkHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, sal_uInt16 nCopyFlags) :
1643 mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mnCopyFlags(nCopyFlags)
1645 if (mpDestPos)
1646 maDestPos = *mpDestPos;
1649 ~CopyAsLinkHandler()
1651 if (mpDestPos)
1652 *mpDestPos = maDestPos;
1655 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1657 size_t nRow = aNode.position + nOffset;
1659 if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
1661 bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == 0;
1662 duplicateNotes(nRow, nDataSize, bCloneCaption );
1665 switch (aNode.type)
1667 case sc::element_type_numeric:
1669 if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == 0)
1670 return;
1672 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1673 std::advance(it, nOffset);
1674 sc::numeric_block::const_iterator itEnd = it;
1675 std::advance(itEnd, nDataSize);
1677 ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1678 for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1680 if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1681 continue;
1683 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, createRefCell(nRow));
1684 setDefaultAttrToDest(nRow);
1687 break;
1688 case sc::element_type_string:
1689 case sc::element_type_edittext:
1691 if (!(mnCopyFlags & IDF_STRING))
1692 return;
1694 createRefBlock(aNode, nOffset, nDataSize);
1696 break;
1697 case sc::element_type_formula:
1699 if (!(mnCopyFlags & IDF_FORMULA))
1700 return;
1702 createRefBlock(aNode, nOffset, nDataSize);
1704 break;
1705 default:
1711 class CopyByCloneHandler
1713 const ScColumn& mrSrcCol;
1714 ScColumn& mrDestCol;
1715 sc::ColumnBlockPosition maDestPos;
1716 sc::ColumnBlockPosition* mpDestPos;
1717 sal_uInt16 mnCopyFlags;
1719 void setDefaultAttrToDest(size_t nRow)
1721 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1722 maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1725 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1727 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1728 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1729 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1732 void cloneFormulaCell(size_t nRow, ScFormulaCell& rSrcCell)
1734 ScAddress aDestPos(mrDestCol.GetCol(), nRow, mrDestCol.GetTab());
1736 bool bCloneValue = (mnCopyFlags & IDF_VALUE) != 0;
1737 bool bCloneDateTime = (mnCopyFlags & IDF_DATETIME) != 0;
1738 bool bCloneString = (mnCopyFlags & IDF_STRING) != 0;
1739 bool bCloneSpecialBoolean = (mnCopyFlags & IDF_SPECIAL_BOOLEAN) != 0;
1740 bool bCloneFormula = (mnCopyFlags & IDF_FORMULA) != 0;
1742 bool bForceFormula = false;
1744 if (bCloneSpecialBoolean)
1746 // See if the formula consists of =TRUE() or =FALSE().
1747 ScTokenArray* pCode = rSrcCell.GetCode();
1748 if (pCode && pCode->GetLen() == 1)
1750 const formula::FormulaToken* p = pCode->First();
1751 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
1752 // This is a boolean formula.
1753 bForceFormula = true;
1757 if (bForceFormula || bCloneFormula)
1759 // Clone as formula cell.
1760 ScFormulaCell* pCell = new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos);
1761 pCell->SetDirtyVar();
1762 mrDestCol.SetFormulaCell(maDestPos, nRow, pCell);
1763 setDefaultAttrToDest(nRow);
1764 return;
1767 if (mrDestCol.GetDoc().IsUndo())
1768 return;
1770 if (bCloneValue)
1772 sal_uInt16 nErr = rSrcCell.GetErrCode();
1773 if (nErr)
1775 // error codes are cloned with values
1776 ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
1777 pErrCell->SetErrCode(nErr);
1778 mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell);
1779 setDefaultAttrToDest(nRow);
1780 return;
1784 if (bCloneValue || bCloneDateTime)
1786 if (rSrcCell.IsValue())
1788 if (canCopyValue(mrSrcCol.GetDoc(), ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab()), mnCopyFlags))
1790 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1791 maDestPos.miCellPos, nRow, rSrcCell.GetValue());
1792 setDefaultAttrToDest(nRow);
1795 return;
1799 if (bCloneString)
1801 svl::SharedString aStr = rSrcCell.GetString();
1802 if (aStr.isEmpty())
1803 // Don't create empty string cells.
1804 return;
1806 if (rSrcCell.IsMultilineResult())
1808 // Clone as an edit text object.
1809 EditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
1810 rEngine.SetText(aStr.getString());
1811 maDestPos.miCellPos =
1812 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rEngine.CreateTextObject());
1814 else
1816 maDestPos.miCellPos =
1817 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aStr);
1820 setDefaultAttrToDest(nRow);
1824 void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1826 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1829 public:
1830 CopyByCloneHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, sal_uInt16 nCopyFlags) :
1831 mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mnCopyFlags(nCopyFlags)
1833 if (mpDestPos)
1834 maDestPos = *mpDestPos;
1837 ~CopyByCloneHandler()
1839 if (mpDestPos)
1840 *mpDestPos = maDestPos;
1843 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1845 size_t nRow = aNode.position + nOffset;
1847 if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
1849 bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == 0;
1850 duplicateNotes(nRow, nDataSize, bCloneCaption );
1853 switch (aNode.type)
1855 case sc::element_type_numeric:
1857 if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == 0)
1858 return;
1860 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1861 std::advance(it, nOffset);
1862 sc::numeric_block::const_iterator itEnd = it;
1863 std::advance(itEnd, nDataSize);
1865 ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1866 for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1868 if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1869 continue;
1871 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, *it);
1872 setDefaultAttrToDest(nRow);
1875 break;
1876 case sc::element_type_string:
1878 if (!(mnCopyFlags & IDF_STRING))
1879 return;
1881 sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
1882 std::advance(it, nOffset);
1883 sc::string_block::const_iterator itEnd = it;
1884 std::advance(itEnd, nDataSize);
1886 for (; it != itEnd; ++it, ++nRow)
1888 const svl::SharedString& rStr = *it;
1889 if (rStr.isEmpty())
1891 // String cell with empty value is used to special-case cell value removal.
1892 maDestPos.miCellPos = mrDestCol.GetCellStore().set_empty(
1893 maDestPos.miCellPos, nRow, nRow);
1894 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set_empty(
1895 maDestPos.miCellTextAttrPos, nRow, nRow);
1897 else
1899 maDestPos.miCellPos =
1900 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rStr);
1901 setDefaultAttrToDest(nRow);
1905 break;
1906 case sc::element_type_edittext:
1908 if (!(mnCopyFlags & IDF_STRING))
1909 return;
1911 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
1912 std::advance(it, nOffset);
1913 sc::edittext_block::const_iterator itEnd = it;
1914 std::advance(itEnd, nDataSize);
1916 std::vector<EditTextObject*> aCloned;
1917 aCloned.reserve(nDataSize);
1918 for (; it != itEnd; ++it, ++nRow)
1919 aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
1921 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1922 maDestPos.miCellPos, nRow, aCloned.begin(), aCloned.end());
1924 setDefaultAttrsToDest(nRow, nDataSize);
1926 break;
1927 case sc::element_type_formula:
1929 sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
1930 std::advance(it, nOffset);
1931 sc::formula_block::const_iterator itEnd = it;
1932 std::advance(itEnd, nDataSize);
1934 for (; it != itEnd; ++it, ++nRow)
1935 cloneFormulaCell(nRow, const_cast<ScFormulaCell&>(**it));
1937 break;
1938 default:
1946 void ScColumn::CopyToColumn(
1947 sc::CopyToDocContext& rCxt,
1948 SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, bool bMarked, ScColumn& rColumn,
1949 const ScMarkData* pMarkData, bool bAsLink) const
1951 if (bMarked)
1953 SCROW nStart, nEnd;
1954 if (pMarkData && pMarkData->IsMultiMarked())
1956 ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
1958 while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
1960 if ( nEnd >= nRow1 )
1961 CopyToColumn(rCxt, std::max(nRow1,nStart), std::min(nRow2,nEnd),
1962 nFlags, false, rColumn, pMarkData, bAsLink );
1965 else
1967 OSL_FAIL("CopyToColumn: bMarked, but no mark");
1969 return;
1972 if ( (nFlags & IDF_ATTRIB) != 0 )
1974 if ( (nFlags & IDF_STYLES) != IDF_STYLES )
1975 { // keep the StyleSheets in the target document
1976 // e.g. DIF and RTF Clipboard-Import
1977 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
1979 const ScStyleSheet* pStyle =
1980 rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
1981 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
1982 ScPatternAttr* pNewPattern = new ScPatternAttr( *pPattern );
1983 pNewPattern->SetStyleSheet( (ScStyleSheet*)pStyle );
1984 rColumn.pAttrArray->SetPattern( nRow, pNewPattern, true );
1985 delete pNewPattern;
1988 else
1989 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
1992 if ((nFlags & IDF_CONTENTS) != 0)
1994 if (bAsLink)
1996 CopyAsLinkHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags);
1997 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1999 else
2001 CopyByCloneHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags);
2002 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
2005 rColumn.CellStorageModified();
2010 void ScColumn::UndoToColumn(
2011 sc::CopyToDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, bool bMarked,
2012 ScColumn& rColumn, const ScMarkData* pMarkData ) const
2014 if (nRow1 > 0)
2015 CopyToColumn(rCxt, 0, nRow1-1, IDF_FORMULA, false, rColumn);
2017 CopyToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData); //! bMarked ????
2019 if (nRow2 < MAXROW)
2020 CopyToColumn(rCxt, nRow2+1, MAXROW, IDF_FORMULA, false, rColumn);
2024 void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
2026 // Copy cells from this column to the destination column only for those
2027 // rows that are present in the position column (rPosCol).
2029 // First, mark all the non-empty cell ranges from the position column.
2030 sc::SingleColumnSpanSet aRangeSet;
2031 aRangeSet.scan(rPosCol);
2033 // Now, copy cells from this column to the destination column for those
2034 // marked row ranges.
2035 sc::SingleColumnSpanSet::SpansType aRanges;
2036 aRangeSet.getSpans(aRanges);
2038 bool bCopyNotes = true;
2039 CopyToClipHandler aFunc(*this, rDestCol, NULL, bCopyNotes);
2040 sc::CellStoreType::const_iterator itPos = maCells.begin();
2041 sc::SingleColumnSpanSet::SpansType::const_iterator it = aRanges.begin(), itEnd = aRanges.end();
2042 for (; it != itEnd; ++it)
2043 itPos = sc::ParseBlock(itPos, maCells, aFunc, it->mnRow1, it->mnRow2);
2045 rDestCol.CellStorageModified();
2049 void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
2051 // This is the scenario table, the data is copied into it
2052 sc::CopyToDocContext aCxt(*pDocument);
2053 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
2054 SCROW nStart = -1, nEnd = -1;
2055 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
2056 while (pPattern)
2058 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
2060 DeleteArea( nStart, nEnd, IDF_CONTENTS );
2061 ((ScColumn&)rSrcCol).
2062 CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, *this);
2064 // UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
2066 sc::RefUpdateContext aRefCxt(*pDocument);
2067 aRefCxt.meMode = URM_COPY;
2068 aRefCxt.maRange = ScRange(nCol, nStart, nTab, nCol, nEnd, nTab);
2069 aRefCxt.mnTabDelta = nTab - rSrcCol.nTab;
2070 UpdateReferenceOnCopy(aRefCxt, NULL);
2071 UpdateCompile();
2074 //! make CopyToColumn "const" !!! (obsolete comment ?)
2076 pPattern = aAttrIter.Next( nStart, nEnd );
2081 void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
2083 // This is the scenario table, the data is copied to the other
2084 sc::CopyToDocContext aCxt(*rDestCol.pDocument);
2085 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
2086 SCROW nStart = -1, nEnd = -1;
2087 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
2088 while (pPattern)
2090 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
2092 rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
2093 CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, rDestCol);
2095 // UpdateUsed not needed, is already done in TestCopyScenario (obsolete comment ?)
2097 sc::RefUpdateContext aRefCxt(*pDocument);
2098 aRefCxt.meMode = URM_COPY;
2099 aRefCxt.maRange = ScRange(rDestCol.nCol, nStart, rDestCol.nTab, rDestCol.nCol, nEnd, rDestCol.nTab);
2100 aRefCxt.mnTabDelta = rDestCol.nTab - nTab;
2101 rDestCol.UpdateReferenceOnCopy(aRefCxt, NULL);
2102 rDestCol.UpdateCompile();
2105 //! make CopyToColumn "const" !!! (obsolete comment ?)
2107 pPattern = aAttrIter.Next( nStart, nEnd );
2112 bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
2114 bool bOk = true;
2115 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
2116 SCROW nStart = 0, nEnd = 0;
2117 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
2118 while (pPattern && bOk)
2120 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
2121 if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) )
2122 bOk = false;
2124 pPattern = aAttrIter.Next( nStart, nEnd );
2126 return bOk;
2130 void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
2132 ScRange aRange( nCol, 0, nTab );
2134 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
2135 SCROW nStart = -1, nEnd = -1;
2136 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
2137 while (pPattern)
2139 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
2141 aRange.aStart.SetRow( nStart );
2142 aRange.aEnd.SetRow( nEnd );
2143 rDestMark.SetMultiMarkArea( aRange, true );
2146 pPattern = aAttrIter.Next( nStart, nEnd );
2150 namespace {
2152 void resetColumnPosition(sc::CellStoreType& rCells, SCCOL nCol)
2154 sc::CellStoreType::iterator it = rCells.begin(), itEnd = rCells.end();
2155 for (; it != itEnd; ++it)
2157 if (it->type != sc::element_type_formula)
2158 continue;
2160 sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
2161 sc::formula_block::iterator itCellEnd = sc::formula_block::end(*it->data);
2162 for (; itCell != itCellEnd; ++itCell)
2164 ScFormulaCell& rCell = **itCell;
2165 rCell.aPos.SetCol(nCol);
2172 void ScColumn::UpdateNoteCaptions()
2174 sc::CellNoteStoreType::const_iterator itBlk = maCellNotes.begin(), itBlkEnd = maCellNotes.end();
2175 sc::cellnote_block::const_iterator itData, itDataEnd;
2177 SCROW curRow = 0;
2178 for (;itBlk!=itBlkEnd;++itBlk)
2180 if (itBlk->data)
2182 // non empty block
2183 itData = sc::cellnote_block::begin(*itBlk->data);
2184 itDataEnd = sc::cellnote_block::end(*itBlk->data);
2185 for(;itData!=itDataEnd; ++itData)
2187 ScPostIt* pNote = *itData;
2188 pNote->UpdateCaptionPos(ScAddress(nCol, curRow, nTab));
2189 curRow +=1;
2192 else
2194 // empty block
2195 curRow += itBlk->size;
2200 void ScColumn::SwapCol(ScColumn& rCol)
2202 maBroadcasters.swap(rCol.maBroadcasters);
2203 maCells.swap(rCol.maCells);
2204 maCellTextAttrs.swap(rCol.maCellTextAttrs);
2205 maCellNotes.swap(rCol.maCellNotes);
2207 // notes update caption
2208 UpdateNoteCaptions();
2209 rCol.UpdateNoteCaptions();
2211 ScAttrArray* pTempAttr = rCol.pAttrArray;
2212 rCol.pAttrArray = pAttrArray;
2213 pAttrArray = pTempAttr;
2215 // AttrArray needs to have the right column number
2216 pAttrArray->SetCol(nCol);
2217 rCol.pAttrArray->SetCol(rCol.nCol);
2219 std::swap(mbDirtyGroups, rCol.mbDirtyGroups);
2221 // Reset column positions in formula cells.
2222 resetColumnPosition(maCells, nCol);
2223 resetColumnPosition(rCol.maCells, rCol.nCol);
2225 CellStorageModified();
2226 rCol.CellStorageModified();
2229 void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
2231 pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
2233 // Mark the non-empty cells within the specified range, for later broadcasting.
2234 sc::SingleColumnSpanSet aNonEmpties;
2235 aNonEmpties.scan(*this, nStartRow, nEndRow);
2236 sc::SingleColumnSpanSet::SpansType aRanges;
2237 aNonEmpties.getSpans(aRanges);
2239 // Split the formula grouping at the top and bottom boundaries.
2240 sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
2241 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
2242 aPos = maCells.position(aPos.first, nEndRow+1);
2243 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
2245 // Do the same with the destination column.
2246 aPos = rCol.maCells.position(nStartRow);
2247 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
2248 aPos = rCol.maCells.position(aPos.first, nEndRow+1);
2249 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
2251 // Move the broadcasters to the destination column.
2252 maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow);
2253 maCells.transfer(nStartRow, nEndRow, rCol.maCells, nStartRow);
2254 maCellTextAttrs.transfer(nStartRow, nEndRow, rCol.maCellTextAttrs, nStartRow);
2256 // move the notes to the destination column
2257 maCellNotes.transfer(nStartRow, nEndRow, rCol.maCellNotes, nStartRow);
2258 UpdateNoteCaptions();
2260 // Re-group transferred formula cells.
2261 aPos = rCol.maCells.position(nStartRow);
2262 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2263 aPos = rCol.maCells.position(aPos.first, nEndRow+1);
2264 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2266 CellStorageModified();
2267 rCol.CellStorageModified();
2269 // Broadcast on moved ranges. Area-broadcast only.
2270 ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
2271 ScAddress& rPos = aHint.GetAddress();
2272 sc::SingleColumnSpanSet::SpansType::const_iterator itRange = aRanges.begin(), itRangeEnd = aRanges.end();
2273 for (; itRange != itRangeEnd; ++itRange)
2275 for (SCROW nRow = itRange->mnRow1; nRow <= itRange->mnRow2; ++nRow)
2277 rPos.SetRow(nRow);
2278 pDocument->AreaBroadcast(aHint);
2283 namespace {
2285 class SubTotalCellPicker
2287 sc::ColumnSpanSet& mrSet;
2288 SCTAB mnTab;
2289 SCCOL mnCol;
2290 bool mbVal;
2291 public:
2292 SubTotalCellPicker(sc::ColumnSpanSet& rSet, SCTAB nTab, SCCOL nCol, bool bVal) :
2293 mrSet(rSet), mnTab(nTab), mnCol(nCol), mbVal(bVal) {}
2295 void operator() (size_t nRow, const ScFormulaCell* pCell)
2297 if (pCell->IsSubTotal())
2298 mrSet.set(mnTab, mnCol, nRow, mbVal);
2304 void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nRow2, bool bVal ) const
2306 SubTotalCellPicker aFunc(rSet, nTab, nCol, bVal);
2307 sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
2310 namespace {
2312 class UpdateRefOnCopy
2314 const sc::RefUpdateContext& mrCxt;
2315 ScDocument* mpUndoDoc;
2316 bool mbUpdated;
2318 public:
2319 UpdateRefOnCopy(const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc) :
2320 mrCxt(rCxt), mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2322 bool isUpdated() const { return mbUpdated; }
2324 void operator() (sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2326 if (node.type != sc::element_type_formula)
2327 return;
2329 sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
2330 std::advance(it, nOffset);
2331 sc::formula_block::iterator itEnd = it;
2332 std::advance(itEnd, nDataSize);
2334 for (; it != itEnd; ++it)
2336 ScFormulaCell& rCell = **it;
2337 mbUpdated |= rCell.UpdateReference(mrCxt, mpUndoDoc);
2342 class UpdateRefOnNonCopy
2344 SCCOL mnCol;
2345 SCROW mnTab;
2346 const sc::RefUpdateContext& mrCxt;
2347 ScDocument* mpUndoDoc;
2348 bool mbUpdated;
2350 public:
2351 UpdateRefOnNonCopy(
2352 SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext& rCxt,
2353 ScDocument* pUndoDoc) :
2354 mnCol(nCol), mnTab(nTab), mrCxt(rCxt),
2355 mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2357 void operator() (size_t nRow, ScFormulaCell* pCell)
2359 ScAddress aUndoPos(mnCol, nRow, mnTab);
2360 mbUpdated |= pCell->UpdateReference(mrCxt, mpUndoDoc, &aUndoPos);
2363 bool isUpdated() const { return mbUpdated; }
2366 class UpdateRefGroupBoundChecker : std::unary_function<sc::CellStoreType::value_type, void>
2368 const sc::RefUpdateContext& mrCxt;
2369 std::vector<SCROW>& mrBounds;
2370 public:
2371 UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
2372 mrCxt(rCxt), mrBounds(rBounds) {}
2374 void operator() (const sc::CellStoreType::value_type& node)
2376 if (node.type != sc::element_type_formula)
2377 return;
2379 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
2380 sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
2382 // Only pick shared formula cells that are the top cells of their
2383 // respective shared ranges.
2384 for (; it != itEnd; ++it)
2386 const ScFormulaCell& rCell = **it;
2387 if (!rCell.IsShared())
2388 continue;
2390 if (rCell.IsSharedTop())
2392 // Check its tokens and record its reference boundaries.
2393 const ScTokenArray& rCode = *rCell.GetCode();
2394 rCode.CheckRelativeReferenceBounds(
2395 mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
2397 // Move to the last cell in the group, to get incremented to
2398 // the next cell in the next iteration.
2399 size_t nOffsetToLast = rCell.GetSharedLength() - 1;
2400 std::advance(it, nOffsetToLast);
2408 bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
2410 // When copying, the range equals the destination range where cells
2411 // are pasted, and the dx, dy, dz refer to the distance from the
2412 // source range.
2414 UpdateRefOnCopy aHandler(rCxt, pUndoDoc);
2415 sc::CellStoreType::position_type aPos = maCells.position(rCxt.maRange.aStart.Row());
2416 sc::ProcessBlock(aPos.first, maCells, aHandler, rCxt.maRange.aStart.Row(), rCxt.maRange.aEnd.Row());
2418 // The formula groups at the top and bottom boundaries are expected to
2419 // have been split prior to this call. Here, we only do the joining.
2420 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2421 if (rCxt.maRange.aEnd.Row() < MAXROW)
2423 aPos = maCells.position(aPos.first, rCxt.maRange.aEnd.Row()+1);
2424 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2427 return aHandler.isUpdated();
2430 bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
2432 if (rCxt.meMode == URM_COPY)
2433 return UpdateReferenceOnCopy(rCxt, pUndoDoc);
2435 if (IsEmptyData())
2436 // Cells in this column are all empty.
2437 return false;
2439 std::vector<SCROW> aBounds;
2441 bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
2442 rCxt.maRange.aStart.Col() <= nCol && nCol <= rCxt.maRange.aEnd.Col());
2443 if (bThisColShifted)
2445 // Cells in this column is being shifted. Split formula grouping at
2446 // the top and bottom boundaries before they get shifted.
2447 // Also, for deleted rows split at the top of the deleted area to adapt
2448 // the affected group length.
2449 SCROW nSplitPos;
2450 if (rCxt.mnRowDelta < 0)
2452 nSplitPos = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
2453 if (ValidRow(nSplitPos))
2454 aBounds.push_back(nSplitPos);
2456 nSplitPos = rCxt.maRange.aStart.Row();
2457 if (ValidRow(nSplitPos))
2459 aBounds.push_back(nSplitPos);
2460 nSplitPos = rCxt.maRange.aEnd.Row() + 1;
2461 if (ValidRow(nSplitPos))
2462 aBounds.push_back(nSplitPos);
2466 // Check the row positions at which the group must be split per relative
2467 // references.
2468 UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
2469 std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
2471 // Do the actual splitting.
2472 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
2474 UpdateRefOnNonCopy aHandler(nCol, nTab, rCxt, pUndoDoc);
2475 sc::ProcessFormula(maCells, aHandler);
2476 if (aHandler.isUpdated())
2477 rCxt.maRegroupCols.set(nTab, nCol);
2479 return aHandler.isUpdated();
2482 namespace {
2484 class UpdateTransHandler
2486 ScColumn& mrColumn;
2487 sc::CellStoreType::iterator miPos;
2488 ScRange maSource;
2489 ScAddress maDest;
2490 ScDocument* mpUndoDoc;
2491 public:
2492 UpdateTransHandler(ScColumn& rColumn, const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc) :
2493 mrColumn(rColumn),
2494 miPos(rColumn.GetCellStore().begin()),
2495 maSource(rSource), maDest(rDest), mpUndoDoc(pUndoDoc) {}
2497 void operator() (size_t nRow, ScFormulaCell* pCell)
2499 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2500 miPos = aPos.first;
2501 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2502 pCell->UpdateTranspose(maSource, maDest, mpUndoDoc);
2503 mrColumn.JoinNewFormulaCell(aPos, *pCell);
2507 class UpdateGrowHandler
2509 ScColumn& mrColumn;
2510 sc::CellStoreType::iterator miPos;
2511 ScRange maArea;
2512 SCCOL mnGrowX;
2513 SCROW mnGrowY;
2514 public:
2515 UpdateGrowHandler(ScColumn& rColumn, const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) :
2516 mrColumn(rColumn),
2517 miPos(rColumn.GetCellStore().begin()),
2518 maArea(rArea), mnGrowX(nGrowX), mnGrowY(nGrowY) {}
2520 void operator() (size_t nRow, ScFormulaCell* pCell)
2522 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2523 miPos = aPos.first;
2524 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2525 pCell->UpdateGrow(maArea, mnGrowX, mnGrowY);
2526 mrColumn.JoinNewFormulaCell(aPos, *pCell);
2530 class InsertTabUpdater
2532 sc::RefUpdateInsertTabContext& mrCxt;
2533 sc::CellTextAttrStoreType& mrTextAttrs;
2534 sc::CellTextAttrStoreType::iterator miAttrPos;
2535 SCTAB mnTab;
2536 bool mbModified;
2538 public:
2539 InsertTabUpdater(sc::RefUpdateInsertTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2540 mrCxt(rCxt),
2541 mrTextAttrs(rTextAttrs),
2542 miAttrPos(rTextAttrs.begin()),
2543 mnTab(nTab),
2544 mbModified(false) {}
2546 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2548 pCell->UpdateInsertTab(mrCxt);
2549 mbModified = true;
2552 void operator() (size_t nRow, EditTextObject* pCell)
2554 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2555 aUpdater.updateTableFields(mnTab);
2556 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2557 mbModified = true;
2560 bool isModified() const { return mbModified; }
2563 class DeleteTabUpdater
2565 sc::RefUpdateDeleteTabContext& mrCxt;
2566 sc::CellTextAttrStoreType& mrTextAttrs;
2567 sc::CellTextAttrStoreType::iterator miAttrPos;
2568 SCTAB mnTab;
2569 bool mbModified;
2570 public:
2571 DeleteTabUpdater(sc::RefUpdateDeleteTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2572 mrCxt(rCxt),
2573 mrTextAttrs(rTextAttrs),
2574 miAttrPos(rTextAttrs.begin()),
2575 mnTab(nTab),
2576 mbModified(false) {}
2578 void operator() (size_t, ScFormulaCell* pCell)
2580 pCell->UpdateDeleteTab(mrCxt);
2581 mbModified = true;
2584 void operator() (size_t nRow, EditTextObject* pCell)
2586 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2587 aUpdater.updateTableFields(mnTab);
2588 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2589 mbModified = true;
2592 bool isModified() const { return mbModified; }
2595 class InsertAbsTabUpdater
2597 sc::CellTextAttrStoreType& mrTextAttrs;
2598 sc::CellTextAttrStoreType::iterator miAttrPos;
2599 SCTAB mnTab;
2600 SCTAB mnNewPos;
2601 bool mbModified;
2602 public:
2603 InsertAbsTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nNewPos) :
2604 mrTextAttrs(rTextAttrs),
2605 miAttrPos(rTextAttrs.begin()),
2606 mnTab(nTab),
2607 mnNewPos(nNewPos),
2608 mbModified(false) {}
2610 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2612 pCell->UpdateInsertTabAbs(mnNewPos);
2613 mbModified = true;
2616 void operator() (size_t nRow, EditTextObject* pCell)
2618 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2619 aUpdater.updateTableFields(mnTab);
2620 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2621 mbModified = true;
2624 bool isModified() const { return mbModified; }
2627 class MoveTabUpdater
2629 sc::RefUpdateMoveTabContext& mrCxt;
2630 sc::CellTextAttrStoreType& mrTextAttrs;
2631 sc::CellTextAttrStoreType::iterator miAttrPos;
2632 SCTAB mnTab;
2633 bool mbModified;
2634 public:
2635 MoveTabUpdater(sc::RefUpdateMoveTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2636 mrCxt(rCxt),
2637 mrTextAttrs(rTextAttrs),
2638 miAttrPos(rTextAttrs.begin()),
2639 mnTab(nTab),
2640 mbModified(false) {}
2642 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2644 pCell->UpdateMoveTab(mrCxt, mnTab);
2645 mbModified = true;
2648 void operator() (size_t nRow, EditTextObject* pCell)
2650 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2651 aUpdater.updateTableFields(mnTab);
2652 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2653 mbModified = true;
2656 bool isModified() const { return mbModified; }
2659 class UpdateCompileHandler
2661 bool mbForceIfNameInUse:1;
2662 public:
2663 UpdateCompileHandler(bool bForceIfNameInUse) :
2664 mbForceIfNameInUse(bForceIfNameInUse) {}
2666 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2668 pCell->UpdateCompile(mbForceIfNameInUse);
2672 class TabNoSetter
2674 SCTAB mnTab;
2675 public:
2676 TabNoSetter(SCTAB nTab) : mnTab(nTab) {}
2678 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2680 pCell->aPos.SetTab(mnTab);
2684 class UsedRangeNameFinder
2686 std::set<sal_uInt16>& mrIndexes;
2687 public:
2688 UsedRangeNameFinder(std::set<sal_uInt16>& rIndexes) : mrIndexes(rIndexes) {}
2690 void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
2692 pCell->FindRangeNamesInUse(mrIndexes);
2696 struct SetDirtyVarHandler
2698 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2700 p->SetDirtyVar();
2704 class SetDirtyHandler
2706 ScDocument& mrDoc;
2707 public:
2708 SetDirtyHandler(ScDocument& rDoc) : mrDoc(rDoc) {}
2710 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2712 p->SetDirtyVar();
2713 if (!mrDoc.IsInFormulaTree(p))
2714 mrDoc.PutInFormulaTree(p);
2718 class SetDirtyOnRangeHandler
2720 sc::SingleColumnSpanSet maValueRanges;
2721 ScColumn& mrColumn;
2722 public:
2723 SetDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
2725 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2727 p->SetDirty();
2730 void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2732 if (type == sc::element_type_empty)
2733 // Ignore empty blocks.
2734 return;
2736 // Non-formula cells.
2737 SCROW nRow1 = nTopRow;
2738 SCROW nRow2 = nTopRow + nDataSize - 1;
2739 maValueRanges.set(nRow1, nRow2, true);
2742 void broadcast()
2744 std::vector<SCROW> aRows;
2745 maValueRanges.getRows(aRows);
2746 mrColumn.BroadcastCells(aRows, SC_HINT_DATACHANGED);
2750 class SetTableOpDirtyOnRangeHandler
2752 sc::SingleColumnSpanSet maValueRanges;
2753 ScColumn& mrColumn;
2754 public:
2755 SetTableOpDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
2757 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2759 p->SetTableOpDirty();
2762 void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2764 if (type == sc::element_type_empty)
2765 // Ignore empty blocks.
2766 return;
2768 // Non-formula cells.
2769 SCROW nRow1 = nTopRow;
2770 SCROW nRow2 = nTopRow + nDataSize - 1;
2771 maValueRanges.set(nRow1, nRow2, true);
2774 void broadcast()
2776 std::vector<SCROW> aRows;
2777 maValueRanges.getRows(aRows);
2778 mrColumn.BroadcastCells(aRows, SC_HINT_TABLEOPDIRTY);
2782 struct SetDirtyAfterLoadHandler
2784 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2786 #if 1
2787 // Simply set dirty and append to FormulaTree, without broadcasting,
2788 // which is a magnitude faster. This is used to calculate the entire
2789 // document, e.g. when loading alien file formats.
2790 pCell->SetDirtyAfterLoad();
2791 #else
2792 /* This was used with the binary file format that stored results, where only
2793 * newly compiled and volatile functions and their dependents had to be
2794 * recalculated, which was faster then. Since that was moved to 'binfilter' to
2795 * convert to an XML file this isn't needed anymore, and not used for other
2796 * file formats. Kept for reference in case mechanism needs to be reactivated
2797 * for some file formats, we'd have to introduce a controlling parameter to
2798 * this method here then.
2801 // If the cell was alsready dirty because of CalcAfterLoad,
2802 // FormulaTracking has to take place.
2803 if (pCell->GetDirty())
2804 pCell->SetDirty();
2805 #endif
2809 struct SetDirtyIfPostponedHandler
2811 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2813 if (pCell->IsPostponedDirty() || pCell->HasRelNameReference())
2814 pCell->SetDirty();
2818 struct CalcAllHandler
2820 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2822 #if OSL_DEBUG_LEVEL > 1
2823 // after F9 ctrl-F9: check the calculation for each FormulaTree
2824 double nOldVal, nNewVal;
2825 nOldVal = pCell->GetValue();
2826 #endif
2827 pCell->Interpret();
2828 #if OSL_DEBUG_LEVEL > 1
2829 if (pCell->GetCode()->IsRecalcModeNormal())
2830 nNewVal = pCell->GetValue();
2831 else
2832 nNewVal = nOldVal; // random(), jetzt() etc.
2834 OSL_ENSURE(nOldVal == nNewVal, "CalcAll: nOldVal != nNewVal");
2835 #endif
2839 struct CompileAllHandler
2841 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2843 // for unconditional compilation
2844 // bCompile=true and pCode->nError=0
2845 pCell->GetCode()->SetCodeError(0);
2846 pCell->SetCompile(true);
2847 pCell->CompileTokenArray();
2851 class CompileXMLHandler
2853 ScProgress& mrProgress;
2854 const ScColumn& mrCol;
2855 public:
2856 CompileXMLHandler(ScProgress& rProgress, const ScColumn& rCol) :
2857 mrProgress(rProgress),
2858 mrCol(rCol) {}
2860 void operator() (size_t nRow, ScFormulaCell* pCell)
2862 sal_uInt32 nFormat = mrCol.GetNumberFormat(nRow);
2863 if( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
2864 pCell->SetNeedNumberFormat(false);
2865 else
2866 pCell->SetDirty(true);
2868 pCell->CompileXML(mrProgress);
2872 class CompileErrorCellsHandler
2874 ScColumn& mrColumn;
2875 sc::CellStoreType::iterator miPos;
2876 sal_uInt16 mnErrCode;
2877 FormulaGrammar::Grammar meGram;
2878 bool mbCompiled;
2879 public:
2880 CompileErrorCellsHandler(ScColumn& rColumn, sal_uInt16 nErrCode, FormulaGrammar::Grammar eGram) :
2881 mrColumn(rColumn),
2882 miPos(mrColumn.GetCellStore().begin()),
2883 mnErrCode(nErrCode),
2884 meGram(eGram),
2885 mbCompiled(false)
2889 void operator() (size_t nRow, ScFormulaCell* pCell)
2891 sal_uInt16 nCurError = pCell->GetRawError();
2892 if (!nCurError)
2893 // It's not an error cell. Skip it.
2894 return;
2896 if (mnErrCode && nCurError != mnErrCode)
2897 // Error code is specified, and it doesn't match. Skip it.
2898 return;
2900 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2901 miPos = aPos.first;
2902 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2903 pCell->GetCode()->SetCodeError(0);
2904 OUStringBuffer aBuf;
2905 pCell->GetFormula(aBuf, meGram);
2906 pCell->Compile(aBuf.makeStringAndClear(), false, meGram);
2907 mrColumn.JoinNewFormulaCell(aPos, *pCell);
2909 mbCompiled = true;
2912 bool isCompiled() const { return mbCompiled; }
2915 struct CalcAfterLoadHandler
2917 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2919 pCell->CalcAfterLoad();
2923 struct ResetChangedHandler
2925 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2927 pCell->SetChanged(false);
2932 * Ambiguous script type counts as edit cell.
2934 class FindEditCellsHandler
2936 ScColumn& mrColumn;
2937 sc::CellTextAttrStoreType::iterator miAttrPos;
2938 sc::CellStoreType::iterator miCellPos;
2940 public:
2941 FindEditCellsHandler(ScColumn& rColumn, sc::CellTextAttrStoreType& rAttrs,
2942 sc::CellStoreType::iterator rCellItr) :
2943 mrColumn(rColumn), miAttrPos(rAttrs.begin()), miCellPos(rCellItr) {}
2945 bool operator() (size_t, const EditTextObject*)
2947 return true;
2950 bool operator() (size_t nRow, const ScFormulaCell* p)
2952 sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
2953 if (IsAmbiguousScriptNonZero(nScriptType))
2954 return true;
2956 return const_cast<ScFormulaCell*>(p)->IsMultilineResult();
2959 std::pair<size_t,bool> operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2961 typedef std::pair<size_t,bool> RetType;
2963 if (type == sc::element_type_empty)
2964 return RetType(0, false);
2966 for (size_t i = 0; i < nDataSize; ++i)
2968 SCROW nRow = nTopRow + i;
2969 sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
2970 if (IsAmbiguousScriptNonZero(nScriptType))
2971 // Return the offset from the first row.
2972 return RetType(i, true);
2975 return RetType(0, false);
2981 void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
2982 ScDocument* pUndoDoc )
2984 UpdateTransHandler aFunc(*this, rSource, rDest, pUndoDoc);
2985 sc::ProcessFormula(maCells, aFunc);
2989 void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
2991 UpdateGrowHandler aFunc(*this, rArea, nGrowX, nGrowY);
2992 sc::ProcessFormula(maCells, aFunc);
2996 void ScColumn::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
2998 if (nTab >= rCxt.mnInsertPos)
3000 nTab += rCxt.mnSheets;
3001 pAttrArray->SetTab(nTab);
3004 UpdateInsertTabOnlyCells(rCxt);
3007 void ScColumn::UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext& rCxt )
3009 InsertTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3010 sc::ProcessFormulaEditText(maCells, aFunc);
3011 if (aFunc.isModified())
3012 CellStorageModified();
3015 void ScColumn::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
3017 if (nTab > rCxt.mnDeletePos)
3019 nTab -= rCxt.mnSheets;
3020 pAttrArray->SetTab(nTab);
3023 DeleteTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3024 sc::ProcessFormulaEditText(maCells, aFunc);
3025 if (aFunc.isModified())
3026 CellStorageModified();
3029 void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos)
3031 InsertAbsTabUpdater aFunc(maCellTextAttrs, nTab, nNewPos);
3032 sc::ProcessFormulaEditText(maCells, aFunc);
3033 if (aFunc.isModified())
3034 CellStorageModified();
3037 void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo )
3039 nTab = nTabNo;
3040 pAttrArray->SetTab( nTabNo );
3042 MoveTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3043 sc::ProcessFormulaEditText(maCells, aFunc);
3044 if (aFunc.isModified())
3045 CellStorageModified();
3049 void ScColumn::UpdateCompile( bool bForceIfNameInUse )
3051 UpdateCompileHandler aFunc(bForceIfNameInUse);
3052 sc::ProcessFormula(maCells, aFunc);
3056 void ScColumn::SetTabNo(SCTAB nNewTab)
3058 nTab = nNewTab;
3059 pAttrArray->SetTab( nNewTab );
3061 TabNoSetter aFunc(nTab);
3062 sc::ProcessFormula(maCells, aFunc);
3065 void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
3067 UsedRangeNameFinder aFunc(rIndexes);
3068 sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
3071 void ScColumn::SetDirtyVar()
3073 SetDirtyVarHandler aFunc;
3074 sc::ProcessFormula(maCells, aFunc);
3077 bool ScColumn::IsFormulaDirty( SCROW nRow ) const
3079 if (!ValidRow(nRow))
3080 return false;
3082 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3083 sc::CellStoreType::const_iterator it = aPos.first;
3084 if (it->type != sc::element_type_formula)
3085 // This is not a formula cell block.
3086 return false;
3088 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3089 return p->GetDirty();
3092 void ScColumn::SetDirty()
3094 // is only done documentwide, no FormulaTracking
3095 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3096 SetDirtyHandler aFunc(*pDocument);
3097 sc::ProcessFormula(maCells, aFunc);
3100 void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2 )
3102 // broadcasts everything within the range, with FormulaTracking
3103 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3105 SetDirtyOnRangeHandler aHdl(*this);
3106 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3107 aHdl.broadcast();
3110 void ScColumn::SetTableOpDirty( const ScRange& rRange )
3112 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3114 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3115 SetTableOpDirtyOnRangeHandler aHdl(*this);
3116 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3117 aHdl.broadcast();
3120 void ScColumn::SetDirtyAfterLoad()
3122 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3123 SetDirtyAfterLoadHandler aFunc;
3124 sc::ProcessFormula(maCells, aFunc);
3127 namespace {
3129 class RecalcOnRefMoveCollector
3131 std::vector<SCROW> maDirtyRows;
3132 public:
3133 void operator() (size_t nRow, ScFormulaCell* pCell)
3135 if (pCell->GetDirty() && pCell->GetCode()->IsRecalcModeOnRefMove())
3136 maDirtyRows.push_back(nRow);
3139 const std::vector<SCROW>& getDirtyRows() const
3141 return maDirtyRows;
3147 void ScColumn::SetDirtyIfPostponed()
3149 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3150 SetDirtyIfPostponedHandler aFunc;
3151 sc::ProcessFormula(maCells, aFunc);
3154 void ScColumn::BroadcastRecalcOnRefMove()
3156 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3157 RecalcOnRefMoveCollector aFunc;
3158 sc::ProcessFormula(maCells, aFunc);
3159 BroadcastCells(aFunc.getDirtyRows(), SC_HINT_DATACHANGED);
3162 void ScColumn::CalcAll()
3164 CalcAllHandler aFunc;
3165 sc::ProcessFormula(maCells, aFunc);
3168 void ScColumn::CompileAll()
3170 CompileAllHandler aFunc;
3171 sc::ProcessFormula(maCells, aFunc);
3174 void ScColumn::CompileXML( ScProgress& rProgress )
3176 CompileXMLHandler aFunc(rProgress, *this);
3177 sc::ProcessFormula(maCells, aFunc);
3178 RegroupFormulaCells();
3181 bool ScColumn::CompileErrorCells(sal_uInt16 nErrCode)
3183 CompileErrorCellsHandler aHdl(*this, nErrCode, pDocument->GetGrammar());
3184 sc::ProcessFormula(maCells, aHdl);
3185 return aHdl.isCompiled();
3188 void ScColumn::CalcAfterLoad()
3190 CalcAfterLoadHandler aFunc;
3191 sc::ProcessFormula(maCells, aFunc);
3194 void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
3196 ResetChangedHandler aFunc;
3197 sc::ProcessFormula(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
3200 bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst)
3202 // used in GetOptimalHeight - ambiguous script type counts as edit cell
3204 FindEditCellsHandler aFunc(*this, maCellTextAttrs, maCells.begin());
3205 std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
3206 sc::FindFormulaEditText(maCells, nStartRow, nEndRow, aFunc);
3208 if (aPos.first == maCells.end())
3209 return false;
3211 rFirst = aPos.first->position + aPos.second;
3212 return true;
3216 SCsROW ScColumn::SearchStyle(
3217 SCsROW nRow, const ScStyleSheet* pSearchStyle, bool bUp, bool bInSelection,
3218 const ScMarkData& rMark) const
3220 if (bInSelection)
3222 if (rMark.IsMultiMarked())
3223 return pAttrArray->SearchStyle(nRow, pSearchStyle, bUp, rMark.GetArray()+nCol);
3224 else
3225 return -1;
3227 else
3228 return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL );
3232 bool ScColumn::SearchStyleRange(
3233 SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
3234 bool bInSelection, const ScMarkData& rMark) const
3236 if (bInSelection)
3238 if (rMark.IsMultiMarked())
3239 return pAttrArray->SearchStyleRange(
3240 rRow, rEndRow, pSearchStyle, bUp, rMark.GetArray() + nCol);
3241 else
3242 return false;
3244 else
3245 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );
3248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */