fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / column.cxx
blob910981af7b394823958b22f588009d4c7ce2e6b4
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"
44 #include <listenercontext.hxx>
45 #include <refhint.hxx>
46 #include <stlalgorithm.hxx>
47 #include <formulagroup.hxx>
49 #include <svl/poolcach.hxx>
50 #include <svl/zforlist.hxx>
51 #include <svl/sharedstringpool.hxx>
52 #include <editeng/scripttypeitem.hxx>
53 #include <editeng/fieldupdater.hxx>
54 #include <osl/diagnose.h>
56 #include <cstring>
57 #include <map>
58 #include <cstdio>
59 #include <boost/checked_delete.hpp>
60 #include <boost/scoped_ptr.hpp>
62 using ::editeng::SvxBorderLine;
63 using namespace formula;
65 namespace {
67 inline bool IsAmbiguousScriptNonZero( SvtScriptType nScript )
69 //TODO: move to a header file
70 return ( nScript != SvtScriptType::LATIN &&
71 nScript != SvtScriptType::ASIAN &&
72 nScript != SvtScriptType::COMPLEX &&
73 nScript != SvtScriptType::NONE );
78 ScNeededSizeOptions::ScNeededSizeOptions() :
79 pPattern(NULL), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
83 ScColumn::ScColumn() :
84 maCellTextAttrs(MAXROWCOUNT),
85 maCellNotes(MAXROWCOUNT),
86 maBroadcasters(MAXROWCOUNT),
87 maCells(MAXROWCOUNT),
88 nCol( 0 ),
89 nTab( 0 ),
90 pAttrArray( NULL ),
91 pDocument( NULL ),
92 mbDirtyGroups(true)
96 ScColumn::~ScColumn()
98 FreeAll();
99 delete pAttrArray;
102 void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
104 nCol = nNewCol;
105 nTab = nNewTab;
106 pDocument = pDoc;
107 pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
110 SCsROW ScColumn::GetNextUnprotected( SCROW nRow, bool bUp ) const
112 return pAttrArray->GetNextUnprotected(nRow, bUp);
115 sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
117 using namespace sc;
119 if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
120 return 0;
122 ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
124 if (nRow1 == nRow2)
126 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
127 if (aPos.first->type != sc::element_type_formula)
128 return 0;
130 const ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
131 if (!pCell->GetMatrixFlag())
132 return 0;
134 return pCell->GetMatrixEdge(aOrigin);
137 bool bOpen = false;
138 sal_uInt16 nEdges = 0;
140 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
141 sc::CellStoreType::const_iterator it = aPos.first;
142 size_t nOffset = aPos.second;
143 SCROW nRow = nRow1;
144 for (;it != maCells.end() && nRow <= nRow2; ++it, nOffset = 0)
146 if (it->type != sc::element_type_formula)
148 // Skip this block.
149 nRow += it->size - nOffset;
150 continue;
153 size_t nRowsToRead = nRow2 - nRow + 1;
154 size_t nEnd = std::min(it->size, nOffset+nRowsToRead); // last row + 1
155 sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
156 std::advance(itCell, nOffset);
157 for (size_t i = nOffset; i < nEnd; ++itCell, ++i)
159 // Loop inside the formula block.
160 const ScFormulaCell* pCell = *itCell;
161 if (!pCell->GetMatrixFlag())
162 continue;
164 nEdges = pCell->GetMatrixEdge(aOrigin);
165 if (!nEdges)
166 continue;
168 if (nEdges & MatrixEdgeTop)
169 bOpen = true; // top edge opens, keep on looking
170 else if (!bOpen)
171 return nEdges | MatrixEdgeOpen; // there's something that wasn't opened
172 else if (nEdges & MatrixEdgeInside)
173 return nEdges; // inside
174 // (nMask & 16 and (4 and not 16)) or
175 // (nMask & 4 and (16 and not 4))
176 if (((nMask & MatrixEdgeRight) && (nEdges & MatrixEdgeLeft) && !(nEdges & MatrixEdgeRight)) ||
177 ((nMask & MatrixEdgeLeft) && (nEdges & MatrixEdgeRight) && !(nEdges & MatrixEdgeLeft)))
178 return nEdges; // only left/right edge
180 if (nEdges & MatrixEdgeBottom)
181 bOpen = false; // bottom edge closes
184 nRow += nEnd;
186 if (bOpen)
187 nEdges |= MatrixEdgeOpen; // not closed, matrix continues
189 return nEdges;
192 bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
194 using namespace sc;
196 if (!rMark.IsMultiMarked())
197 return false;
199 ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
200 ScAddress aCurOrigin = aOrigin;
202 bool bOpen = false;
203 ScRangeList aRanges = rMark.GetMarkedRanges();
204 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
206 const ScRange& r = *aRanges[i];
207 if (nTab < r.aStart.Tab() || r.aEnd.Tab() < nTab)
208 continue;
210 if (nCol < r.aStart.Col() || r.aEnd.Col() < nCol)
211 continue;
213 SCROW nTop = r.aStart.Row(), nBottom = r.aEnd.Row();
214 SCROW nRow = nTop;
215 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
216 sc::CellStoreType::const_iterator it = aPos.first;
217 size_t nOffset = aPos.second;
219 for (;it != maCells.end() && nRow <= nBottom; ++it, nOffset = 0)
221 if (it->type != sc::element_type_formula)
223 // Skip this block.
224 nRow += it->size - nOffset;
225 continue;
228 // This is a formula cell block.
229 size_t nRowsToRead = nBottom - nRow + 1;
230 size_t nEnd = std::min(it->size, nRowsToRead);
231 sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
232 std::advance(itCell, nOffset);
233 for (size_t j = nOffset; j < nEnd; ++itCell, ++j)
235 // Loop inside the formula block.
236 const ScFormulaCell* pCell = *itCell;
237 if (!pCell->GetMatrixFlag())
238 // cell is not a part of a matrix.
239 continue;
241 sal_uInt16 nEdges = pCell->GetMatrixEdge(aOrigin);
242 if (!nEdges)
243 continue;
245 bool bFound = false;
247 if (nEdges & MatrixEdgeTop)
248 bOpen = true; // top edge opens, keep on looking
249 else if (!bOpen)
250 return true; // there's something that wasn't opened
251 else if (nEdges & MatrixEdgeInside)
252 bFound = true; // inside, all selected?
254 if ((((nEdges & MatrixEdgeLeft) | MatrixEdgeRight) ^ ((nEdges & MatrixEdgeRight) | MatrixEdgeLeft)))
255 // either left or right, but not both.
256 bFound = true; // only left/right edge, all selected?
258 if (nEdges & MatrixEdgeBottom)
259 bOpen = false; // bottom edge closes
261 if (bFound)
263 // Check if the matrix is inside the selection in its entirety.
265 // TODO: It's more efficient to skip the matrix range if
266 // it's within selection, to avoid checking it again and
267 // again.
269 if (aCurOrigin != aOrigin)
270 { // new matrix to check?
271 aCurOrigin = aOrigin;
272 const ScFormulaCell* pFCell;
273 if (pCell->GetMatrixFlag() == MM_REFERENCE)
274 pFCell = pDocument->GetFormulaCell(aOrigin);
275 else
276 pFCell = pCell;
278 SCCOL nC;
279 SCROW nR;
280 pFCell->GetMatColsRows(nC, nR);
281 ScRange aRange(aOrigin, ScAddress(aOrigin.Col()+nC-1, aOrigin.Row()+nR-1, aOrigin.Tab()));
282 if (rMark.IsAllMarked(aRange))
283 bFound = false;
285 else
286 bFound = false; // done already
289 if (bFound)
290 return true;
293 nRow += nEnd;
297 if (bOpen)
298 return true;
300 return false;
303 bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
305 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;
328 bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
329 SCCOL& rPaintCol, SCROW& rPaintRow,
330 bool bRefresh )
332 return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh );
335 void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
337 SCROW nTop;
338 SCROW nBottom;
340 if ( rMark.IsMultiMarked() )
342 const ScMarkArray* pArray = rMark.GetArray() + nCol;
343 if ( pArray->HasMarks() )
345 ScMarkArrayIter aMarkIter( pArray );
346 while (aMarkIter.Next( nTop, nBottom ))
347 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
352 void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, bool bDeep ) const
354 pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
357 void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
358 ScLineFlags& rFlags,
359 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
361 pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
364 void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
365 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
367 pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
370 const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
372 return pAttrArray->GetPattern( nRow );
375 const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
377 return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
380 const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
382 ::std::map< const ScPatternAttr*, size_t > aAttrMap;
383 const ScPatternAttr* pMaxPattern = 0;
384 size_t nMaxCount = 0;
386 ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
387 const ScPatternAttr* pPattern;
388 SCROW nAttrRow1 = 0, nAttrRow2 = 0;
390 while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
392 size_t& rnCount = aAttrMap[ pPattern ];
393 rnCount += (nAttrRow2 - nAttrRow1 + 1);
394 if( rnCount > nMaxCount )
396 pMaxPattern = pPattern;
397 nMaxCount = rnCount;
401 return pMaxPattern;
404 sal_uInt32 ScColumn::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
406 SCROW nPatStartRow, nPatEndRow;
407 const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
408 sal_uInt32 nFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
409 while (nEndRow > nPatEndRow)
411 nStartRow = nPatEndRow + 1;
412 pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
413 sal_uInt32 nTmpFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
414 if (nFormat != nTmpFormat)
415 return 0;
417 return nFormat;
420 sal_uInt32 ScColumn::GetNumberFormat( SCROW nRow ) const
422 return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
425 SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray )
427 SCROW nTop = 0;
428 SCROW nBottom = 0;
429 bool bFound = false;
431 if ( rMark.IsMultiMarked() )
433 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
434 while (aMarkIter.Next( nTop, nBottom ))
436 pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray );
437 bFound = true;
441 if (!bFound)
442 return -1;
443 else if (nTop==0 && nBottom==MAXROW)
444 return 0;
445 else
446 return nBottom;
449 void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
451 SCROW nTop;
452 SCROW nBottom;
454 if ( pAttrArray && rMark.IsMultiMarked() )
456 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
457 while (aMarkIter.Next( nTop, nBottom ))
458 pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
462 void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
464 SCROW nTop;
465 SCROW nBottom;
467 if ( pAttrArray && rMark.IsMultiMarked() )
469 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
470 while (aMarkIter.Next( nTop, nBottom ))
471 pAttrArray->ClearItems(nTop, nBottom, pWhich);
475 void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
477 SCROW nTop;
478 SCROW nBottom;
480 if ( rMark.IsMultiMarked() )
482 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
483 while (aMarkIter.Next( nTop, nBottom ))
484 DeleteArea(nTop, nBottom, nDelFlag, bBroadcast);
488 void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
490 const SfxItemSet* pSet = &rPatAttr.GetItemSet();
491 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
493 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
495 // true = keep old content
497 const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &aCache.ApplyTo( *pPattern, true ) );
498 ScDocumentPool::CheckRef( *pPattern );
499 ScDocumentPool::CheckRef( *pNewPattern );
501 if (pNewPattern != pPattern)
502 pAttrArray->SetPattern( nRow, pNewPattern );
505 void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr,
506 ScEditDataArray* pDataArray )
508 const SfxItemSet* pSet = &rPatAttr.GetItemSet();
509 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
510 pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache, pDataArray );
513 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
514 const ScPatternAttr& rPattern, short nNewType )
516 const SfxItemSet* pSet = &rPattern.GetItemSet();
517 SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
518 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
519 SCROW nEndRow = rRange.aEnd.Row();
520 for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
522 SCROW nRow1, nRow2;
523 const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
524 nRow1, nRow2, nRow );
525 sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
526 short nOldType = pFormatter->GetType( nFormat );
527 if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) )
528 nRow = nRow2;
529 else
531 SCROW nNewRow1 = std::max( nRow1, nRow );
532 SCROW nNewRow2 = std::min( nRow2, nEndRow );
533 pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
534 nRow = nNewRow2;
539 void ScColumn::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
541 pAttrArray->AddCondFormat( nStartRow, nEndRow, nIndex );
544 void ScColumn::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
546 pAttrArray->RemoveCondFormat( nStartRow, nEndRow, nIndex );
549 void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
551 const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
552 boost::scoped_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pPattern));
553 if (pNewPattern)
555 pNewPattern->SetStyleSheet(const_cast<ScStyleSheet*>(&rStyle));
556 pAttrArray->SetPattern(nRow, pNewPattern.get(), true);
560 void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
562 pAttrArray->ApplyStyleArea(nStartRow, nEndRow, const_cast<ScStyleSheet*>(&rStyle));
565 void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
567 SCROW nTop;
568 SCROW nBottom;
570 if ( rMark.IsMultiMarked() )
572 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
573 while (aMarkIter.Next( nTop, nBottom ))
574 pAttrArray->ApplyStyleArea(nTop, nBottom, const_cast<ScStyleSheet*>(&rStyle));
578 void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
579 const SvxBorderLine* pLine, bool bColorOnly )
581 if ( bColorOnly && !pLine )
582 return;
584 SCROW nTop;
585 SCROW nBottom;
587 if (rMark.IsMultiMarked())
589 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
590 while (aMarkIter.Next( nTop, nBottom ))
591 pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
595 const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
597 return pAttrArray->GetPattern( nRow )->GetStyleSheet();
600 const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
602 rFound = false;
603 if (!rMark.IsMultiMarked())
605 OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
606 return NULL;
609 bool bEqual = true;
611 const ScStyleSheet* pStyle = NULL;
612 const ScStyleSheet* pNewStyle;
614 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
615 SCROW nTop;
616 SCROW nBottom;
617 while (bEqual && aMarkIter.Next( nTop, nBottom ))
619 ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
620 SCROW nRow;
621 SCROW nDummy;
622 const ScPatternAttr* pPattern;
623 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
625 pNewStyle = pPattern->GetStyleSheet();
626 rFound = true;
627 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
628 bEqual = false; // difference
629 pStyle = pNewStyle;
633 return bEqual ? pStyle : NULL;
636 const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRow2 ) const
638 rFound = false;
640 bool bEqual = true;
642 const ScStyleSheet* pStyle = NULL;
643 const ScStyleSheet* pNewStyle;
645 ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
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;
658 return bEqual ? pStyle : NULL;
661 void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
663 pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
666 bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const
668 return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
671 bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
673 return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
676 bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
678 return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
681 void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
683 pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
686 void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, bool bPutToPool )
688 pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
691 void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
692 const ScPatternAttr& rPatAttr, bool bPutToPool )
694 pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
697 void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
699 // in order to only create a new SetItem, we don't need SfxItemPoolCache.
700 //TODO: Warning: SfxItemPoolCache seems to create to many Refs for the new SetItem ??
702 ScDocumentPool* pDocPool = pDocument->GetPool();
704 const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
705 boost::scoped_ptr<ScPatternAttr> pTemp(new ScPatternAttr(*pOldPattern));
706 pTemp->GetItemSet().Put(rAttr);
707 const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pDocPool->Put( *pTemp ) );
709 if ( pNewPattern != pOldPattern )
710 pAttrArray->SetPattern( nRow, pNewPattern );
711 else
712 pDocPool->Remove( *pNewPattern ); // free up resources
715 ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
717 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
718 if (aPos.first == maCells.end())
719 return ScRefCellValue();
721 return GetCellValue(aPos.first, aPos.second);
724 ScRefCellValue ScColumn::GetCellValue( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
726 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
727 if (aPos.first == maCells.end())
728 return ScRefCellValue();
730 rBlockPos.miCellPos = aPos.first; // Store this for next call.
731 return GetCellValue(aPos.first, aPos.second);
734 ScRefCellValue ScColumn::GetCellValue( const sc::CellStoreType::const_iterator& itPos, size_t nOffset )
736 ScRefCellValue aVal; // Defaults to empty cell.
737 switch (itPos->type)
739 case sc::element_type_numeric:
740 // Numeric cell
741 aVal.mfValue = sc::numeric_block::at(*itPos->data, nOffset);
742 aVal.meType = CELLTYPE_VALUE;
743 break;
744 case sc::element_type_string:
745 // String cell
746 aVal.mpString = &sc::string_block::at(*itPos->data, nOffset);
747 aVal.meType = CELLTYPE_STRING;
748 break;
749 case sc::element_type_edittext:
750 // Edit cell
751 aVal.mpEditText = sc::edittext_block::at(*itPos->data, nOffset);
752 aVal.meType = CELLTYPE_EDIT;
753 break;
754 case sc::element_type_formula:
755 // Formula cell
756 aVal.mpFormula = sc::formula_block::at(*itPos->data, nOffset);
757 aVal.meType = CELLTYPE_FORMULA;
758 break;
759 default:
763 return aVal;
766 const sc::CellTextAttr* ScColumn::GetCellTextAttr( SCROW nRow ) const
768 sc::ColumnBlockConstPosition aBlockPos;
769 aBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
770 return GetCellTextAttr(aBlockPos, nRow);
773 const sc::CellTextAttr* ScColumn::GetCellTextAttr( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
775 sc::CellTextAttrStoreType::const_position_type aPos = maCellTextAttrs.position(rBlockPos.miCellTextAttrPos, nRow);
776 if (aPos.first == maCellTextAttrs.end())
777 return NULL;
779 rBlockPos.miCellTextAttrPos = aPos.first;
781 if (aPos.first->type != sc::element_type_celltextattr)
782 return NULL;
784 return &sc::celltextattr_block::at(*aPos.first->data, aPos.second);
787 bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
789 if (IsEmpty())
790 return true;
792 // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
793 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
794 sc::CellStoreType::const_iterator it = aPos.first;
795 if (it->type != sc::element_type_empty)
796 return false;
798 // Get the length of the remaining empty segment.
799 size_t nLen = it->size - aPos.second;
800 SCROW nNextNonEmptyRow = nStartRow + nLen;
801 if (nNextNonEmptyRow <= nEndRow)
802 return false;
804 // AttrArray only looks for merged cells
806 return pAttrArray == nullptr || pAttrArray->TestInsertCol(nStartRow, nEndRow);
809 bool ScColumn::TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const
811 // AttrArray only looks for merged cells
813 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
814 sc::CellStoreType::const_iterator it = aPos.first;
815 if (it->type == sc::element_type_empty && maCells.block_size() == 1)
816 // The entire cell array is empty.
817 return pAttrArray->TestInsertRow(nSize);
820 // See if there would be any non-empty cell that gets pushed out.
822 // Find the position of the last non-empty cell below nStartRow.
823 size_t nLastNonEmptyRow = MAXROW;
824 sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
825 if (it->type == sc::element_type_empty)
826 nLastNonEmptyRow -= it->size;
828 if (nLastNonEmptyRow < static_cast<size_t>(nStartRow))
829 // No cells would get pushed out.
830 return pAttrArray->TestInsertRow(nSize);
832 if (nLastNonEmptyRow + nSize > static_cast<size_t>(MAXROW))
833 // At least one cell would get pushed out. Not good.
834 return false;
836 return pAttrArray->TestInsertRow(nSize);
839 void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
841 pAttrArray->InsertRow( nStartRow, nSize );
843 maCellNotes.insert_empty(nStartRow, nSize);
844 maCellNotes.resize(MAXROWCOUNT);
846 maBroadcasters.insert_empty(nStartRow, nSize);
847 maBroadcasters.resize(MAXROWCOUNT);
849 maCellTextAttrs.insert_empty(nStartRow, nSize);
850 maCellTextAttrs.resize(MAXROWCOUNT);
852 maCells.insert_empty(nStartRow, nSize);
853 maCells.resize(MAXROWCOUNT);
855 CellStorageModified();
857 // We *probably* don't need to broadcast here since the parent call seems
858 // to take care of it.
861 namespace {
863 class CopyToClipHandler
865 const ScColumn& mrSrcCol;
866 ScColumn& mrDestCol;
867 sc::ColumnBlockPosition maDestPos;
868 sc::ColumnBlockPosition* mpDestPos;
869 bool mbCopyNotes;
871 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
873 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
874 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
875 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
878 void duplicateNotes(SCROW nStartRow, size_t nDataSize )
880 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, false);
883 public:
884 CopyToClipHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, bool bCopyNotes) :
885 mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mbCopyNotes(bCopyNotes)
887 if (mpDestPos)
888 maDestPos = *mpDestPos;
889 else
890 mrDestCol.InitBlockPosition(maDestPos);
893 ~CopyToClipHandler()
895 if (mpDestPos)
896 *mpDestPos = maDestPos;
899 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
901 size_t nTopRow = aNode.position + nOffset;
903 bool bSet = true;
905 switch (aNode.type)
907 case sc::element_type_numeric:
909 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
910 std::advance(it, nOffset);
911 sc::numeric_block::const_iterator itEnd = it;
912 std::advance(itEnd, nDataSize);
913 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
915 break;
916 case sc::element_type_string:
918 sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
919 std::advance(it, nOffset);
920 sc::string_block::const_iterator itEnd = it;
921 std::advance(itEnd, nDataSize);
922 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
925 break;
926 case sc::element_type_edittext:
928 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
929 std::advance(it, nOffset);
930 sc::edittext_block::const_iterator itEnd = it;
931 std::advance(itEnd, nDataSize);
933 std::vector<EditTextObject*> aCloned;
934 aCloned.reserve(nDataSize);
935 for (; it != itEnd; ++it)
936 aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
938 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
939 maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
941 break;
942 case sc::element_type_formula:
944 sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
945 std::advance(it, nOffset);
946 sc::formula_block::const_iterator itEnd = it;
947 std::advance(itEnd, nDataSize);
949 std::vector<ScFormulaCell*> aCloned;
950 aCloned.reserve(nDataSize);
951 ScAddress aDestPos(mrDestCol.GetCol(), nTopRow, mrDestCol.GetTab());
952 for (; it != itEnd; ++it, aDestPos.IncRow())
954 const ScFormulaCell& rOld = **it;
955 if (rOld.GetDirty() && mrSrcCol.GetDoc().GetAutoCalc())
956 const_cast<ScFormulaCell&>(rOld).Interpret();
958 aCloned.push_back(new ScFormulaCell(rOld, mrDestCol.GetDoc(), aDestPos));
961 // Group the cloned formula cells.
962 if (!aCloned.empty())
963 sc::SharedFormulaUtil::groupFormulaCells(aCloned.begin(), aCloned.end());
965 sc::CellStoreType& rDestCells = mrDestCol.GetCellStore();
966 maDestPos.miCellPos = rDestCells.set(
967 maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
969 // Merge adjacent formula cell groups (if applicable).
970 sc::CellStoreType::position_type aPos =
971 rDestCells.position(maDestPos.miCellPos, nTopRow);
972 maDestPos.miCellPos = aPos.first;
973 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
974 size_t nLastRow = nTopRow + nDataSize;
975 if (nLastRow < static_cast<size_t>(MAXROW))
977 aPos = rDestCells.position(maDestPos.miCellPos, nLastRow+1);
978 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
981 break;
982 default:
983 bSet = false;
986 if (bSet)
987 setDefaultAttrsToDest(nTopRow, nDataSize);
989 if (mbCopyNotes)
990 duplicateNotes(nTopRow, nDataSize);
994 class CopyTextAttrToClipHandler
996 sc::CellTextAttrStoreType& mrDestAttrs;
997 sc::CellTextAttrStoreType::iterator miPos;
999 public:
1000 CopyTextAttrToClipHandler( sc::CellTextAttrStoreType& rAttrs ) :
1001 mrDestAttrs(rAttrs), miPos(mrDestAttrs.begin()) {}
1003 void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
1005 if (aNode.type != sc::element_type_celltextattr)
1006 return;
1008 sc::celltextattr_block::const_iterator it = sc::celltextattr_block::begin(*aNode.data);
1009 std::advance(it, nOffset);
1010 sc::celltextattr_block::const_iterator itEnd = it;
1011 std::advance(itEnd, nDataSize);
1013 size_t nPos = aNode.position + nOffset;
1014 miPos = mrDestAttrs.set(miPos, nPos, it, itEnd);
1021 void ScColumn::CopyToClip(
1022 sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
1024 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
1025 rCxt.isKeepScenarioFlags() ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
1028 CopyToClipHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), rCxt.isCloneNotes());
1029 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1033 CopyTextAttrToClipHandler aFunc(rColumn.maCellTextAttrs);
1034 sc::ParseBlock(maCellTextAttrs.begin(), maCellTextAttrs, aFunc, nRow1, nRow2);
1037 rColumn.CellStorageModified();
1040 void ScColumn::CopyStaticToDocument(
1041 SCROW nRow1, SCROW nRow2, const SvNumberFormatterMergeMap& rMap, ScColumn& rDestCol )
1043 if (nRow1 > nRow2)
1044 return;
1046 sc::ColumnBlockPosition aDestPos;
1047 CopyCellTextAttrsToDocument(nRow1, nRow2, rDestCol);
1048 CopyCellNotesToDocument(nRow1, nRow2, rDestCol);
1050 // First, clear the destination column for the specified row range.
1051 rDestCol.maCells.set_empty(nRow1, nRow2);
1053 aDestPos.miCellPos = rDestCol.maCells.begin();
1055 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
1056 sc::CellStoreType::const_iterator it = aPos.first;
1057 size_t nOffset = aPos.second;
1058 size_t nDataSize = 0;
1059 size_t nCurRow = nRow1;
1061 for (; it != maCells.end() && nCurRow <= static_cast<size_t>(nRow2); ++it, nOffset = 0, nCurRow += nDataSize)
1063 bool bLastBlock = false;
1064 nDataSize = it->size - nOffset;
1065 if (nCurRow + nDataSize - 1 > static_cast<size_t>(nRow2))
1067 // Truncate the block to copy to clipboard.
1068 nDataSize = nRow2 - nCurRow + 1;
1069 bLastBlock = true;
1072 switch (it->type)
1074 case sc::element_type_numeric:
1076 sc::numeric_block::const_iterator itData = sc::numeric_block::begin(*it->data);
1077 std::advance(itData, nOffset);
1078 sc::numeric_block::const_iterator itDataEnd = itData;
1079 std::advance(itDataEnd, nDataSize);
1080 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1082 break;
1083 case sc::element_type_string:
1085 sc::string_block::const_iterator itData = sc::string_block::begin(*it->data);
1086 std::advance(itData, nOffset);
1087 sc::string_block::const_iterator itDataEnd = itData;
1088 std::advance(itDataEnd, nDataSize);
1089 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1091 break;
1092 case sc::element_type_edittext:
1094 sc::edittext_block::const_iterator itData = sc::edittext_block::begin(*it->data);
1095 std::advance(itData, nOffset);
1096 sc::edittext_block::const_iterator itDataEnd = itData;
1097 std::advance(itDataEnd, nDataSize);
1099 // Convert to simple strings.
1100 std::vector<svl::SharedString> aConverted;
1101 aConverted.reserve(nDataSize);
1102 for (; itData != itDataEnd; ++itData)
1104 const EditTextObject& rObj = **itData;
1105 svl::SharedString aSS = pDocument->GetSharedStringPool().intern(ScEditUtil::GetString(rObj, pDocument));
1106 aConverted.push_back(aSS);
1108 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, aConverted.begin(), aConverted.end());
1110 break;
1111 case sc::element_type_formula:
1113 sc::formula_block::const_iterator itData = sc::formula_block::begin(*it->data);
1114 std::advance(itData, nOffset);
1115 sc::formula_block::const_iterator itDataEnd = itData;
1116 std::advance(itDataEnd, nDataSize);
1118 // Interpret and convert to raw values.
1119 for (SCROW i = 0; itData != itDataEnd; ++itData, ++i)
1121 SCROW nRow = nCurRow + i;
1123 ScFormulaCell& rFC = const_cast<ScFormulaCell&>(**itData);
1124 if (rFC.GetDirty() && pDocument->GetAutoCalc())
1125 rFC.Interpret();
1127 if (rFC.GetErrCode())
1128 // Skip cells with error.
1129 break;
1131 if (rFC.IsValue())
1132 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, rFC.GetValue());
1133 else
1135 svl::SharedString aSS = rFC.GetString();
1136 if (aSS.isValid())
1137 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, aSS);
1141 break;
1142 default:
1146 if (bLastBlock)
1147 break;
1150 // Dont' forget to copy the number formats over. Charts may reference them.
1151 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
1153 sal_uInt32 nNumFmt = GetNumberFormat(nRow);
1154 SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt);
1155 if (itNum != rMap.end())
1156 nNumFmt = itNum->second;
1158 rDestCol.SetNumberFormat(nRow, nNumFmt);
1161 rDestCol.CellStorageModified();
1164 void ScColumn::CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol )
1166 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nSrcRow);
1167 sc::CellStoreType::const_iterator it = aPos.first;
1168 bool bSet = true;
1169 switch (it->type)
1171 case sc::element_type_numeric:
1172 rDestCol.maCells.set(nDestRow, sc::numeric_block::at(*it->data, aPos.second));
1173 break;
1174 case sc::element_type_string:
1175 rDestCol.maCells.set(nDestRow, sc::string_block::at(*it->data, aPos.second));
1176 break;
1177 case sc::element_type_edittext:
1179 EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
1180 if (pDocument == rDestCol.pDocument)
1181 rDestCol.maCells.set(nDestRow, p->Clone());
1182 else
1183 rDestCol.maCells.set(nDestRow, ScEditUtil::Clone(*p, *rDestCol.pDocument));
1185 break;
1186 case sc::element_type_formula:
1188 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
1189 if (p->GetDirty() && pDocument->GetAutoCalc())
1190 p->Interpret();
1192 ScAddress aDestPos = p->aPos;
1193 aDestPos.SetRow(nDestRow);
1194 ScFormulaCell* pNew = new ScFormulaCell(*p, *rDestCol.pDocument, aDestPos);
1195 rDestCol.SetFormulaCell(nDestRow, pNew);
1197 break;
1198 case sc::element_type_empty:
1199 default:
1200 // empty
1201 rDestCol.maCells.set_empty(nDestRow, nDestRow);
1202 bSet = false;
1205 if (bSet)
1207 rDestCol.maCellTextAttrs.set(nDestRow, maCellTextAttrs.get<sc::CellTextAttr>(nSrcRow));
1208 ScPostIt* pNote = maCellNotes.get<ScPostIt*>(nSrcRow);
1209 rDestCol.maCellNotes.set(nDestRow, pNote);
1210 if (pNote)
1211 pNote->UpdateCaptionPos(ScAddress(rDestCol.nCol, nDestRow, rDestCol.nTab));
1213 else
1215 rDestCol.maCellTextAttrs.set_empty(nDestRow, nDestRow);
1216 rDestCol.maCellNotes.set_empty(nDestRow, nDestRow);
1219 rDestCol.CellStorageModified();
1222 namespace {
1224 bool canCopyValue(const ScDocument& rDoc, const ScAddress& rPos, InsertDeleteFlags nFlags)
1226 sal_uInt32 nNumIndex = static_cast<const SfxUInt32Item*>(rDoc.GetAttr(rPos, ATTR_VALUE_FORMAT))->GetValue();
1227 short nType = rDoc.GetFormatTable()->GetType(nNumIndex);
1228 if ((nType == css::util::NumberFormat::DATE) || (nType == css::util::NumberFormat::TIME) || (nType == css::util::NumberFormat::DATETIME))
1229 return ((nFlags & IDF_DATETIME) != IDF_NONE);
1231 return (nFlags & IDF_VALUE) != IDF_NONE;
1234 class CopyAsLinkHandler
1236 const ScColumn& mrSrcCol;
1237 ScColumn& mrDestCol;
1238 sc::ColumnBlockPosition maDestPos;
1239 sc::ColumnBlockPosition* mpDestPos;
1240 InsertDeleteFlags mnCopyFlags;
1242 sc::StartListeningType meListenType;
1244 void setDefaultAttrToDest(size_t nRow)
1246 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1247 maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1250 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1252 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1253 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1254 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1257 ScFormulaCell* createRefCell(size_t nRow)
1259 ScSingleRefData aRef;
1260 aRef.InitAddress(ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab())); // Absolute reference.
1261 aRef.SetFlag3D(true);
1263 ScTokenArray aArr;
1264 aArr.AddSingleReference(aRef);
1265 return new ScFormulaCell(&mrDestCol.GetDoc(), ScAddress(mrDestCol.GetCol(), nRow, mrDestCol.GetTab()), aArr);
1268 void createRefBlock(const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1270 size_t nTopRow = aNode.position + nOffset;
1272 for (size_t i = 0; i < nDataSize; ++i)
1274 SCROW nRow = nTopRow + i;
1275 mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow), meListenType);
1278 setDefaultAttrsToDest(nTopRow, nDataSize);
1281 void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1283 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1286 public:
1287 CopyAsLinkHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, InsertDeleteFlags nCopyFlags) :
1288 mrSrcCol(rSrcCol),
1289 mrDestCol(rDestCol),
1290 mpDestPos(pDestPos),
1291 mnCopyFlags(nCopyFlags),
1292 meListenType(sc::SingleCellListening)
1294 if (mpDestPos)
1295 maDestPos = *mpDestPos;
1298 ~CopyAsLinkHandler()
1300 if (mpDestPos)
1301 *mpDestPos = maDestPos;
1304 void setStartListening( bool b )
1306 meListenType = b ? sc::SingleCellListening : sc::NoListening;
1309 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1311 size_t nRow = aNode.position + nOffset;
1313 if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
1315 bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == IDF_NONE;
1316 duplicateNotes(nRow, nDataSize, bCloneCaption );
1319 switch (aNode.type)
1321 case sc::element_type_numeric:
1323 if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == IDF_NONE)
1324 return;
1326 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1327 std::advance(it, nOffset);
1328 sc::numeric_block::const_iterator itEnd = it;
1329 std::advance(itEnd, nDataSize);
1331 ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1332 for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1334 if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1335 continue;
1337 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, createRefCell(nRow));
1338 setDefaultAttrToDest(nRow);
1341 break;
1342 case sc::element_type_string:
1343 case sc::element_type_edittext:
1345 if (!(mnCopyFlags & IDF_STRING))
1346 return;
1348 createRefBlock(aNode, nOffset, nDataSize);
1350 break;
1351 case sc::element_type_formula:
1353 if (!(mnCopyFlags & IDF_FORMULA))
1354 return;
1356 createRefBlock(aNode, nOffset, nDataSize);
1358 break;
1359 default:
1365 class CopyByCloneHandler
1367 const ScColumn& mrSrcCol;
1368 ScColumn& mrDestCol;
1369 sc::ColumnBlockPosition maDestPos;
1370 sc::ColumnBlockPosition* mpDestPos;
1371 svl::SharedStringPool* mpSharedStringPool;
1372 InsertDeleteFlags mnCopyFlags;
1374 sc::StartListeningType meListenType;
1376 void setDefaultAttrToDest(size_t nRow)
1378 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1379 maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1382 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1384 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1385 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1386 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1389 void cloneFormulaCell(size_t nRow, ScFormulaCell& rSrcCell)
1391 ScAddress aDestPos(mrDestCol.GetCol(), nRow, mrDestCol.GetTab());
1393 bool bCloneValue = (mnCopyFlags & IDF_VALUE) != IDF_NONE;
1394 bool bCloneDateTime = (mnCopyFlags & IDF_DATETIME) != IDF_NONE;
1395 bool bCloneString = (mnCopyFlags & IDF_STRING) != IDF_NONE;
1396 bool bCloneSpecialBoolean = (mnCopyFlags & IDF_SPECIAL_BOOLEAN) != IDF_NONE;
1397 bool bCloneFormula = (mnCopyFlags & IDF_FORMULA) != IDF_NONE;
1399 bool bForceFormula = false;
1401 if (bCloneSpecialBoolean)
1403 // See if the formula consists of =TRUE() or =FALSE().
1404 ScTokenArray* pCode = rSrcCell.GetCode();
1405 if (pCode && pCode->GetLen() == 1)
1407 const formula::FormulaToken* p = pCode->First();
1408 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
1409 // This is a boolean formula.
1410 bForceFormula = true;
1414 if (bForceFormula || bCloneFormula)
1416 // Clone as formula cell.
1417 ScFormulaCell* pCell = new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos);
1418 pCell->SetDirtyVar();
1419 mrDestCol.SetFormulaCell(maDestPos, nRow, pCell, meListenType);
1420 setDefaultAttrToDest(nRow);
1421 return;
1424 if (mrDestCol.GetDoc().IsUndo())
1425 return;
1427 if (bCloneValue)
1429 sal_uInt16 nErr = rSrcCell.GetErrCode();
1430 if (nErr)
1432 // error codes are cloned with values
1433 ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
1434 pErrCell->SetErrCode(nErr);
1435 mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell, meListenType);
1436 setDefaultAttrToDest(nRow);
1437 return;
1441 if (bCloneValue || bCloneDateTime)
1443 if (rSrcCell.IsValue())
1445 if (canCopyValue(mrSrcCol.GetDoc(), ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab()), mnCopyFlags))
1447 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1448 maDestPos.miCellPos, nRow, rSrcCell.GetValue());
1449 setDefaultAttrToDest(nRow);
1452 return;
1456 if (bCloneString)
1458 svl::SharedString aStr = rSrcCell.GetString();
1459 if (aStr.isEmpty())
1460 // Don't create empty string cells.
1461 return;
1463 if (rSrcCell.IsMultilineResult())
1465 // Clone as an edit text object.
1466 EditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
1467 rEngine.SetText(aStr.getString());
1468 maDestPos.miCellPos =
1469 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rEngine.CreateTextObject());
1471 else
1473 maDestPos.miCellPos =
1474 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aStr);
1477 setDefaultAttrToDest(nRow);
1481 void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1483 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1486 public:
1487 CopyByCloneHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos,
1488 InsertDeleteFlags nCopyFlags, svl::SharedStringPool* pSharedStringPool) :
1489 mrSrcCol(rSrcCol),
1490 mrDestCol(rDestCol),
1491 mpDestPos(pDestPos),
1492 mpSharedStringPool(pSharedStringPool),
1493 mnCopyFlags(nCopyFlags),
1494 meListenType(sc::SingleCellListening)
1496 if (mpDestPos)
1497 maDestPos = *mpDestPos;
1500 ~CopyByCloneHandler()
1502 if (mpDestPos)
1503 *mpDestPos = maDestPos;
1506 void setStartListening( bool b )
1508 meListenType = b ? sc::SingleCellListening : sc::NoListening;
1511 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1513 size_t nRow = aNode.position + nOffset;
1515 if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
1517 bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == IDF_NONE;
1518 duplicateNotes(nRow, nDataSize, bCloneCaption );
1521 switch (aNode.type)
1523 case sc::element_type_numeric:
1525 if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == IDF_NONE)
1526 return;
1528 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1529 std::advance(it, nOffset);
1530 sc::numeric_block::const_iterator itEnd = it;
1531 std::advance(itEnd, nDataSize);
1533 ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1534 for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1536 if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1537 continue;
1539 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, *it);
1540 setDefaultAttrToDest(nRow);
1543 break;
1544 case sc::element_type_string:
1546 if (!(mnCopyFlags & IDF_STRING))
1547 return;
1549 sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
1550 std::advance(it, nOffset);
1551 sc::string_block::const_iterator itEnd = it;
1552 std::advance(itEnd, nDataSize);
1554 for (; it != itEnd; ++it, ++nRow)
1556 const svl::SharedString& rStr = *it;
1557 if (rStr.isEmpty())
1559 // String cell with empty value is used to special-case cell value removal.
1560 maDestPos.miCellPos = mrDestCol.GetCellStore().set_empty(
1561 maDestPos.miCellPos, nRow, nRow);
1562 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set_empty(
1563 maDestPos.miCellTextAttrPos, nRow, nRow);
1565 else
1567 if (mpSharedStringPool)
1569 // Re-intern the string if source is a different document.
1570 svl::SharedString aInterned = mpSharedStringPool->intern( rStr.getString());
1571 maDestPos.miCellPos =
1572 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aInterned);
1574 else
1576 maDestPos.miCellPos =
1577 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rStr);
1579 setDefaultAttrToDest(nRow);
1583 break;
1584 case sc::element_type_edittext:
1586 if (!(mnCopyFlags & IDF_STRING))
1587 return;
1589 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
1590 std::advance(it, nOffset);
1591 sc::edittext_block::const_iterator itEnd = it;
1592 std::advance(itEnd, nDataSize);
1594 std::vector<EditTextObject*> aCloned;
1595 aCloned.reserve(nDataSize);
1596 for (; it != itEnd; ++it)
1597 aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
1599 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1600 maDestPos.miCellPos, nRow, aCloned.begin(), aCloned.end());
1602 setDefaultAttrsToDest(nRow, nDataSize);
1604 break;
1605 case sc::element_type_formula:
1607 sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
1608 std::advance(it, nOffset);
1609 sc::formula_block::const_iterator itEnd = it;
1610 std::advance(itEnd, nDataSize);
1612 for (; it != itEnd; ++it, ++nRow)
1613 cloneFormulaCell(nRow, const_cast<ScFormulaCell&>(**it));
1615 break;
1616 default:
1624 void ScColumn::CopyToColumn(
1625 sc::CopyToDocContext& rCxt,
1626 SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked, ScColumn& rColumn,
1627 const ScMarkData* pMarkData, bool bAsLink) const
1629 if (bMarked)
1631 SCROW nStart, nEnd;
1632 if (pMarkData && pMarkData->IsMultiMarked())
1634 ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
1636 while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
1638 if ( nEnd >= nRow1 )
1639 CopyToColumn(rCxt, std::max(nRow1,nStart), std::min(nRow2,nEnd),
1640 nFlags, false, rColumn, pMarkData, bAsLink );
1643 else
1645 OSL_FAIL("CopyToColumn: bMarked, but no mark");
1647 return;
1650 if ( (nFlags & IDF_ATTRIB) != IDF_NONE )
1652 if ( (nFlags & IDF_STYLES) != IDF_STYLES )
1653 { // keep the StyleSheets in the target document
1654 // e.g. DIF and RTF Clipboard-Import
1655 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
1657 const ScStyleSheet* pStyle =
1658 rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
1659 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
1660 boost::scoped_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pPattern ));
1661 pNewPattern->SetStyleSheet( const_cast<ScStyleSheet*>(pStyle) );
1662 rColumn.pAttrArray->SetPattern( nRow, pNewPattern.get(), true );
1665 else
1666 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
1669 if ((nFlags & IDF_CONTENTS) != IDF_NONE)
1671 if (bAsLink)
1673 CopyAsLinkHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags);
1674 aFunc.setStartListening(rCxt.isStartListening());
1675 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1677 else
1679 // Compare the ScDocumentPool* to determine if we are copying
1680 // within the same document. If not, re-intern shared strings.
1681 svl::SharedStringPool* pSharedStringPool =
1682 (pDocument->GetPool() != rColumn.pDocument->GetPool()) ?
1683 &rColumn.pDocument->GetSharedStringPool() : NULL;
1684 CopyByCloneHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags,
1685 pSharedStringPool);
1686 aFunc.setStartListening(rCxt.isStartListening());
1687 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1690 rColumn.CellStorageModified();
1694 void ScColumn::UndoToColumn(
1695 sc::CopyToDocContext& rCxt, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked,
1696 ScColumn& rColumn, const ScMarkData* pMarkData ) const
1698 if (nRow1 > 0)
1699 CopyToColumn(rCxt, 0, nRow1-1, IDF_FORMULA, false, rColumn);
1701 CopyToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData); //TODO: bMarked ????
1703 if (nRow2 < MAXROW)
1704 CopyToColumn(rCxt, nRow2+1, MAXROW, IDF_FORMULA, false, rColumn);
1707 void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
1709 // Copy cells from this column to the destination column only for those
1710 // rows that are present in the position column (rPosCol).
1712 // First, mark all the non-empty cell ranges from the position column.
1713 sc::SingleColumnSpanSet aRangeSet;
1714 aRangeSet.scan(rPosCol);
1716 // Now, copy cells from this column to the destination column for those
1717 // marked row ranges.
1718 sc::SingleColumnSpanSet::SpansType aRanges;
1719 aRangeSet.getSpans(aRanges);
1721 bool bCopyNotes = true;
1722 CopyToClipHandler aFunc(*this, rDestCol, NULL, bCopyNotes);
1723 sc::CellStoreType::const_iterator itPos = maCells.begin();
1724 sc::SingleColumnSpanSet::SpansType::const_iterator it = aRanges.begin(), itEnd = aRanges.end();
1725 for (; it != itEnd; ++it)
1726 itPos = sc::ParseBlock(itPos, maCells, aFunc, it->mnRow1, it->mnRow2);
1728 rDestCol.CellStorageModified();
1731 void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
1733 // This is the scenario table, the data is copied into it
1734 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1735 SCROW nStart = -1, nEnd = -1;
1736 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1737 while (pPattern)
1739 if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1741 DeleteArea( nStart, nEnd, IDF_CONTENTS );
1742 sc::CopyToDocContext aCxt(*pDocument);
1743 ((ScColumn&)rSrcCol).
1744 CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, *this);
1746 // UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
1748 sc::RefUpdateContext aRefCxt(*pDocument);
1749 aRefCxt.meMode = URM_COPY;
1750 aRefCxt.maRange = ScRange(nCol, nStart, nTab, nCol, nEnd, nTab);
1751 aRefCxt.mnTabDelta = nTab - rSrcCol.nTab;
1752 UpdateReferenceOnCopy(aRefCxt, NULL);
1753 UpdateCompile();
1756 //TODO: make CopyToColumn "const" !!! (obsolete comment ?)
1758 pPattern = aAttrIter.Next( nStart, nEnd );
1762 void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
1764 // This is the scenario table, the data is copied to the other
1765 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1766 SCROW nStart = -1, nEnd = -1;
1767 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1768 while (pPattern)
1770 if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1772 rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
1773 sc::CopyToDocContext aCxt(*rDestCol.pDocument);
1774 CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, rDestCol);
1776 // UpdateUsed not needed, is already done in TestCopyScenario (obsolete comment ?)
1778 sc::RefUpdateContext aRefCxt(*pDocument);
1779 aRefCxt.meMode = URM_COPY;
1780 aRefCxt.maRange = ScRange(rDestCol.nCol, nStart, rDestCol.nTab, rDestCol.nCol, nEnd, rDestCol.nTab);
1781 aRefCxt.mnTabDelta = rDestCol.nTab - nTab;
1782 rDestCol.UpdateReferenceOnCopy(aRefCxt, NULL);
1783 rDestCol.UpdateCompile();
1786 //TODO: make CopyToColumn "const" !!! (obsolete comment ?)
1788 pPattern = aAttrIter.Next( nStart, nEnd );
1792 bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
1794 bool bOk = true;
1795 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1796 SCROW nStart = 0, nEnd = 0;
1797 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1798 while (pPattern && bOk)
1800 if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1801 if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) )
1802 bOk = false;
1804 pPattern = aAttrIter.Next( nStart, nEnd );
1806 return bOk;
1809 void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
1811 ScRange aRange( nCol, 0, nTab );
1813 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1814 SCROW nStart = -1, nEnd = -1;
1815 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1816 while (pPattern)
1818 if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1820 aRange.aStart.SetRow( nStart );
1821 aRange.aEnd.SetRow( nEnd );
1822 rDestMark.SetMultiMarkArea( aRange, true );
1825 pPattern = aAttrIter.Next( nStart, nEnd );
1829 namespace {
1831 void resetColumnPosition(sc::CellStoreType& rCells, SCCOL nCol)
1833 sc::CellStoreType::iterator it = rCells.begin(), itEnd = rCells.end();
1834 for (; it != itEnd; ++it)
1836 if (it->type != sc::element_type_formula)
1837 continue;
1839 sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
1840 sc::formula_block::iterator itCellEnd = sc::formula_block::end(*it->data);
1841 for (; itCell != itCellEnd; ++itCell)
1843 ScFormulaCell& rCell = **itCell;
1844 rCell.aPos.SetCol(nCol);
1849 class NoteCaptionUpdater
1851 SCCOL mnCol;
1852 SCTAB mnTab;
1853 public:
1854 NoteCaptionUpdater( SCCOL nCol, SCTAB nTab ) : mnCol(nCol), mnTab(nTab) {}
1856 void operator() ( size_t nRow, ScPostIt* p )
1858 p->UpdateCaptionPos(ScAddress(mnCol,nRow,mnTab));
1864 void ScColumn::UpdateNoteCaptions( SCROW nRow1, SCROW nRow2 )
1866 NoteCaptionUpdater aFunc(nCol, nTab);
1867 sc::ProcessNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
1870 void ScColumn::SwapCol(ScColumn& rCol)
1872 maBroadcasters.swap(rCol.maBroadcasters);
1873 maCells.swap(rCol.maCells);
1874 maCellTextAttrs.swap(rCol.maCellTextAttrs);
1875 maCellNotes.swap(rCol.maCellNotes);
1877 // notes update caption
1878 UpdateNoteCaptions(0, MAXROW);
1879 rCol.UpdateNoteCaptions(0, MAXROW);
1881 ScAttrArray* pTempAttr = rCol.pAttrArray;
1882 rCol.pAttrArray = pAttrArray;
1883 pAttrArray = pTempAttr;
1885 // AttrArray needs to have the right column number
1886 pAttrArray->SetCol(nCol);
1887 rCol.pAttrArray->SetCol(rCol.nCol);
1889 std::swap(mbDirtyGroups, rCol.mbDirtyGroups);
1891 // Reset column positions in formula cells.
1892 resetColumnPosition(maCells, nCol);
1893 resetColumnPosition(rCol.maCells, rCol.nCol);
1895 CellStorageModified();
1896 rCol.CellStorageModified();
1899 void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
1901 pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
1903 // Mark the non-empty cells within the specified range, for later broadcasting.
1904 sc::SingleColumnSpanSet aNonEmpties;
1905 aNonEmpties.scan(*this, nStartRow, nEndRow);
1906 sc::SingleColumnSpanSet::SpansType aRanges;
1907 aNonEmpties.getSpans(aRanges);
1909 // Split the formula grouping at the top and bottom boundaries.
1910 sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
1911 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, nullptr);
1912 aPos = maCells.position(aPos.first, nEndRow+1);
1913 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, nullptr);
1915 // Do the same with the destination column.
1916 aPos = rCol.maCells.position(nStartRow);
1917 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, nullptr);
1918 aPos = rCol.maCells.position(aPos.first, nEndRow+1);
1919 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, nullptr);
1921 // Move the broadcasters to the destination column.
1922 maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow);
1923 maCells.transfer(nStartRow, nEndRow, rCol.maCells, nStartRow);
1924 maCellTextAttrs.transfer(nStartRow, nEndRow, rCol.maCellTextAttrs, nStartRow);
1926 // move the notes to the destination column
1927 maCellNotes.transfer(nStartRow, nEndRow, rCol.maCellNotes, nStartRow);
1928 UpdateNoteCaptions(0, MAXROW);
1930 // Re-group transferred formula cells.
1931 aPos = rCol.maCells.position(nStartRow);
1932 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1933 aPos = rCol.maCells.position(aPos.first, nEndRow+1);
1934 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1936 CellStorageModified();
1937 rCol.CellStorageModified();
1939 // Broadcast on moved ranges. Area-broadcast only.
1940 ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
1941 ScAddress& rPos = aHint.GetAddress();
1942 sc::SingleColumnSpanSet::SpansType::const_iterator itRange = aRanges.begin(), itRangeEnd = aRanges.end();
1943 for (; itRange != itRangeEnd; ++itRange)
1945 for (SCROW nRow = itRange->mnRow1; nRow <= itRange->mnRow2; ++nRow)
1947 rPos.SetRow(nRow);
1948 pDocument->AreaBroadcast(aHint);
1953 namespace {
1955 class SharedTopFormulaCellPicker : std::unary_function<sc::CellStoreType::value_type, void>
1957 public:
1958 virtual ~SharedTopFormulaCellPicker() {}
1960 void operator() ( sc::CellStoreType::value_type& node )
1962 if (node.type != sc::element_type_formula)
1963 return;
1965 size_t nTopRow = node.position;
1967 sc::formula_block::iterator itBeg = sc::formula_block::begin(*node.data);
1968 sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
1970 // Only pick shared formula cells that are the top cells of their
1971 // respective shared ranges.
1972 for (sc::formula_block::iterator it = itBeg; it != itEnd; ++it)
1974 ScFormulaCell* pCell = *it;
1975 size_t nRow = nTopRow + std::distance(itBeg, it);
1976 if (!pCell->IsShared())
1978 processNonShared(pCell, nRow);
1979 continue;
1982 if (pCell->IsSharedTop())
1984 ScFormulaCell** pp = &(*it);
1985 processSharedTop(pp, nRow, pCell->GetSharedLength());
1987 // Move to the last cell in the group, to get incremented to
1988 // the next cell in the next iteration.
1989 size_t nOffsetToLast = pCell->GetSharedLength() - 1;
1990 std::advance(it, nOffsetToLast);
1995 virtual void processNonShared( ScFormulaCell* /*pCell*/, size_t /*nRow*/ ) {}
1996 virtual void processSharedTop( ScFormulaCell** /*ppCells*/, size_t /*nRow*/, size_t /*nLength*/ ) {}
1999 class UpdateRefOnCopy
2001 const sc::RefUpdateContext& mrCxt;
2002 ScDocument* mpUndoDoc;
2003 bool mbUpdated;
2005 public:
2006 UpdateRefOnCopy(const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc) :
2007 mrCxt(rCxt), mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2009 bool isUpdated() const { return mbUpdated; }
2011 void operator() (sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2013 if (node.type != sc::element_type_formula)
2014 return;
2016 sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
2017 std::advance(it, nOffset);
2018 sc::formula_block::iterator itEnd = it;
2019 std::advance(itEnd, nDataSize);
2021 for (; it != itEnd; ++it)
2023 ScFormulaCell& rCell = **it;
2024 mbUpdated |= rCell.UpdateReference(mrCxt, mpUndoDoc);
2029 class UpdateRefOnNonCopy : std::unary_function<sc::FormulaGroupEntry, void>
2031 SCCOL mnCol;
2032 SCROW mnTab;
2033 const sc::RefUpdateContext* mpCxt;
2034 ScDocument* mpUndoDoc;
2035 bool mbUpdated;
2037 void recompileTokenArray( ScFormulaCell& rTopCell )
2039 // We need to re-compile the token array when a range name is
2040 // modified, to correctly reflect the new references in the
2041 // name.
2042 ScCompiler aComp(&mpCxt->mrDoc, rTopCell.aPos, *rTopCell.GetCode());
2043 aComp.SetGrammar(mpCxt->mrDoc.GetGrammar());
2044 aComp.CompileTokenArray();
2047 void updateRefOnShift( sc::FormulaGroupEntry& rGroup )
2049 if (!rGroup.mbShared)
2051 ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2052 mbUpdated |= rGroup.mpCell->UpdateReferenceOnShift(*mpCxt, mpUndoDoc, &aUndoPos);
2053 return;
2056 // Update references of a formula group.
2057 ScFormulaCell** pp = rGroup.mpCells;
2058 ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2059 ScFormulaCell* pTop = *pp;
2060 ScTokenArray* pCode = pTop->GetCode();
2061 boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
2062 ScAddress aOldPos = pTop->aPos;
2064 // Run this before the position gets updated.
2065 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnShift(*mpCxt, aOldPos);
2067 if (pTop->UpdatePosOnShift(*mpCxt))
2069 // Update the positions of all formula cells.
2070 for (++pp; pp != ppEnd; ++pp) // skip the top cell.
2072 ScFormulaCell* pFC = *pp;
2073 pFC->aPos.Move(mpCxt->mnColDelta, mpCxt->mnRowDelta, mpCxt->mnTabDelta);
2076 if (pCode->IsRecalcModeOnRefMove())
2077 aRes.mbValueChanged = true;
2079 else if (aRes.mbReferenceModified && pCode->IsRecalcModeOnRefMove())
2081 // The cell itself hasn't shifted. But it may have ROW or COLUMN
2082 // referencing another cell that has.
2083 aRes.mbValueChanged = true;
2086 if (aRes.mbNameModified)
2087 recompileTokenArray(*pTop);
2089 if (aRes.mbReferenceModified || aRes.mbNameModified)
2091 sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get());
2092 aEndCxt.setPositionDelta(
2093 ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
2095 for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
2097 ScFormulaCell* p = *pp;
2098 p->EndListeningTo(aEndCxt);
2099 p->SetNeedsListening(true);
2102 mbUpdated = true;
2104 fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
2107 if (aRes.mbValueChanged)
2109 for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
2111 ScFormulaCell* p = *pp;
2112 p->SetNeedsDirty(true);
2117 void updateRefOnMove( sc::FormulaGroupEntry& rGroup )
2119 if (!rGroup.mbShared)
2121 ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2122 mbUpdated |= rGroup.mpCell->UpdateReferenceOnMove(*mpCxt, mpUndoDoc, &aUndoPos);
2123 return;
2126 // Update references of a formula group.
2127 ScFormulaCell** pp = rGroup.mpCells;
2128 ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2129 ScFormulaCell* pTop = *pp;
2130 ScTokenArray* pCode = pTop->GetCode();
2131 boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
2133 ScAddress aPos = pTop->aPos;
2134 ScAddress aOldPos = aPos;
2136 if (mpCxt->maRange.In(aPos))
2138 // The cell is being moved or copied to a new position. The
2139 // position has already been updated prior to this call.
2140 // Determine its original position before the move which will be
2141 // used to adjust relative references later.
2143 aOldPos.Set(
2144 aPos.Col() - mpCxt->mnColDelta,
2145 aPos.Row() - mpCxt->mnRowDelta,
2146 aPos.Tab() - mpCxt->mnTabDelta);
2149 bool bRecalcOnMove = pCode->IsRecalcModeOnRefMove();
2150 if (bRecalcOnMove)
2151 bRecalcOnMove = aPos != aOldPos;
2153 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(*mpCxt, aOldPos, aPos);
2155 if (aRes.mbReferenceModified || aRes.mbNameModified || bRecalcOnMove)
2157 sc::AutoCalcSwitch(mpCxt->mrDoc, false);
2159 if (aRes.mbNameModified)
2160 recompileTokenArray(*pTop);
2162 // Perform end-listening, start-listening, and dirtying on all
2163 // formula cells in the group.
2165 // Make sure that the start and end listening contexts share the
2166 // same block position set, else an invalid iterator may ensue.
2167 boost::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(
2168 new sc::ColumnBlockPositionSet(mpCxt->mrDoc));
2170 sc::StartListeningContext aStartCxt(mpCxt->mrDoc, pPosSet);
2171 sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pPosSet, pOldCode.get());
2173 aEndCxt.setPositionDelta(
2174 ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
2176 for (; pp != ppEnd; ++pp)
2178 ScFormulaCell* p = *pp;
2179 p->EndListeningTo(aEndCxt);
2180 p->StartListeningTo(aStartCxt);
2181 p->SetDirty();
2184 fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
2188 void fillUndoDoc( const ScAddress& rOldPos, SCROW nLength, const ScTokenArray& rOldCode )
2190 if (!mpUndoDoc || nLength <= 0)
2191 return;
2193 // Insert the old formula group into the undo document.
2194 ScAddress aUndoPos = rOldPos;
2195 ScFormulaCell* pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, rOldCode.Clone());
2197 if (nLength == 1)
2199 mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
2200 return;
2203 std::vector<ScFormulaCell*> aCells;
2204 aCells.reserve(nLength);
2205 ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(nLength, false);
2206 aCells.push_back(pFC);
2207 aUndoPos.IncRow();
2208 for (SCROW i = 1; i < nLength; ++i, aUndoPos.IncRow())
2210 pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, xGroup);
2211 aCells.push_back(pFC);
2214 if (!mpUndoDoc->SetFormulaCells(rOldPos, aCells))
2215 // Insertion failed. Delete all formula cells.
2216 std::for_each(aCells.begin(), aCells.end(), boost::checked_deleter<ScFormulaCell>());
2219 public:
2220 UpdateRefOnNonCopy(
2221 SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext* pCxt,
2222 ScDocument* pUndoDoc) :
2223 mnCol(nCol), mnTab(nTab), mpCxt(pCxt),
2224 mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2226 void operator() ( sc::FormulaGroupEntry& rGroup )
2228 switch (mpCxt->meMode)
2230 case URM_INSDEL:
2231 updateRefOnShift(rGroup);
2232 return;
2233 case URM_MOVE:
2234 updateRefOnMove(rGroup);
2235 return;
2236 default:
2240 if (rGroup.mbShared)
2242 ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2243 ScFormulaCell** pp = rGroup.mpCells;
2244 ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2245 for (; pp != ppEnd; ++pp, aUndoPos.IncRow())
2247 ScFormulaCell* p = *pp;
2248 mbUpdated |= p->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
2251 else
2253 ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2254 mbUpdated |= rGroup.mpCell->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
2258 bool isUpdated() const { return mbUpdated; }
2261 class UpdateRefGroupBoundChecker : public SharedTopFormulaCellPicker
2263 const sc::RefUpdateContext& mrCxt;
2264 std::vector<SCROW>& mrBounds;
2266 public:
2267 UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
2268 mrCxt(rCxt), mrBounds(rBounds) {}
2270 virtual ~UpdateRefGroupBoundChecker() {}
2272 virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) SAL_OVERRIDE
2274 // Check its tokens and record its reference boundaries.
2275 ScFormulaCell& rCell = **ppCells;
2276 const ScTokenArray& rCode = *rCell.GetCode();
2277 rCode.CheckRelativeReferenceBounds(
2278 mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
2282 class UpdateRefExpandGroupBoundChecker : public SharedTopFormulaCellPicker
2284 const sc::RefUpdateContext& mrCxt;
2285 std::vector<SCROW>& mrBounds;
2287 public:
2288 UpdateRefExpandGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
2289 mrCxt(rCxt), mrBounds(rBounds) {}
2291 virtual ~UpdateRefExpandGroupBoundChecker() {}
2293 virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) SAL_OVERRIDE
2295 // Check its tokens and record its reference boundaries.
2296 ScFormulaCell& rCell = **ppCells;
2297 const ScTokenArray& rCode = *rCell.GetCode();
2298 rCode.CheckExpandReferenceBounds(
2299 mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
2303 class FormulaGroupPicker : public SharedTopFormulaCellPicker
2305 std::vector<sc::FormulaGroupEntry>& mrGroups;
2307 public:
2308 FormulaGroupPicker( std::vector<sc::FormulaGroupEntry>& rGroups ) : mrGroups(rGroups) {}
2310 virtual ~FormulaGroupPicker() {}
2312 virtual void processNonShared( ScFormulaCell* pCell, size_t nRow ) SAL_OVERRIDE
2314 mrGroups.push_back(sc::FormulaGroupEntry(pCell, nRow));
2317 virtual void processSharedTop( ScFormulaCell** ppCells, size_t nRow, size_t nLength ) SAL_OVERRIDE
2319 mrGroups.push_back(sc::FormulaGroupEntry(ppCells, nRow, nLength));
2325 bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
2327 // When copying, the range equals the destination range where cells
2328 // are pasted, and the dx, dy, dz refer to the distance from the
2329 // source range.
2331 UpdateRefOnCopy aHandler(rCxt, pUndoDoc);
2332 sc::CellStoreType::position_type aPos = maCells.position(rCxt.maRange.aStart.Row());
2333 sc::ProcessBlock(aPos.first, maCells, aHandler, rCxt.maRange.aStart.Row(), rCxt.maRange.aEnd.Row());
2335 // The formula groups at the top and bottom boundaries are expected to
2336 // have been split prior to this call. Here, we only do the joining.
2337 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2338 if (rCxt.maRange.aEnd.Row() < MAXROW)
2340 aPos = maCells.position(aPos.first, rCxt.maRange.aEnd.Row()+1);
2341 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2344 return aHandler.isUpdated();
2347 bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
2349 if (rCxt.meMode == URM_COPY)
2350 return UpdateReferenceOnCopy(rCxt, pUndoDoc);
2352 if (IsEmptyData() || pDocument->IsClipOrUndo())
2353 // Cells in this column are all empty, or clip or undo doc. No update needed.
2354 return false;
2356 std::vector<SCROW> aBounds;
2358 bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
2359 rCxt.maRange.aStart.Col() <= nCol && nCol <= rCxt.maRange.aEnd.Col());
2360 if (bThisColShifted)
2362 // Cells in this column is being shifted. Split formula grouping at
2363 // the top and bottom boundaries before they get shifted.
2364 // Also, for deleted rows split at the top of the deleted area to adapt
2365 // the affected group length.
2366 SCROW nSplitPos;
2367 if (rCxt.mnRowDelta < 0)
2369 nSplitPos = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
2370 if (ValidRow(nSplitPos))
2371 aBounds.push_back(nSplitPos);
2373 nSplitPos = rCxt.maRange.aStart.Row();
2374 if (ValidRow(nSplitPos))
2376 aBounds.push_back(nSplitPos);
2377 nSplitPos = rCxt.maRange.aEnd.Row() + 1;
2378 if (ValidRow(nSplitPos))
2379 aBounds.push_back(nSplitPos);
2383 // Check the row positions at which the group must be split per relative
2384 // references.
2385 UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
2386 std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
2388 // If expand reference edges is on, splitting groups may happen anywhere
2389 // where a reference points to an adjacent row of the insertion.
2390 if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs())
2392 UpdateRefExpandGroupBoundChecker aExpandChecker(rCxt, aBounds);
2393 std::for_each(maCells.begin(), maCells.end(), aExpandChecker);
2396 // Do the actual splitting.
2397 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
2399 // Collect all formula groups.
2400 std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
2402 // Process all collected formula groups.
2403 UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc);
2404 aHandler = std::for_each(aGroups.begin(), aGroups.end(), aHandler);
2405 if (aHandler.isUpdated())
2406 rCxt.maRegroupCols.set(nTab, nCol);
2408 return aHandler.isUpdated();
2411 std::vector<sc::FormulaGroupEntry> ScColumn::GetFormulaGroupEntries()
2413 std::vector<sc::FormulaGroupEntry> aGroups;
2414 std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups));
2415 return aGroups;
2418 namespace {
2420 class UpdateTransHandler
2422 ScColumn& mrColumn;
2423 sc::CellStoreType::iterator miPos;
2424 ScRange maSource;
2425 ScAddress maDest;
2426 ScDocument* mpUndoDoc;
2427 public:
2428 UpdateTransHandler(ScColumn& rColumn, const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc) :
2429 mrColumn(rColumn),
2430 miPos(rColumn.GetCellStore().begin()),
2431 maSource(rSource), maDest(rDest), mpUndoDoc(pUndoDoc) {}
2433 void operator() (size_t nRow, ScFormulaCell* pCell)
2435 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2436 miPos = aPos.first;
2437 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2438 pCell->UpdateTranspose(maSource, maDest, mpUndoDoc);
2439 ScColumn::JoinNewFormulaCell(aPos, *pCell);
2443 class UpdateGrowHandler
2445 ScColumn& mrColumn;
2446 sc::CellStoreType::iterator miPos;
2447 ScRange maArea;
2448 SCCOL mnGrowX;
2449 SCROW mnGrowY;
2450 public:
2451 UpdateGrowHandler(ScColumn& rColumn, const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) :
2452 mrColumn(rColumn),
2453 miPos(rColumn.GetCellStore().begin()),
2454 maArea(rArea), mnGrowX(nGrowX), mnGrowY(nGrowY) {}
2456 void operator() (size_t nRow, ScFormulaCell* pCell)
2458 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2459 miPos = aPos.first;
2460 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2461 pCell->UpdateGrow(maArea, mnGrowX, mnGrowY);
2462 ScColumn::JoinNewFormulaCell(aPos, *pCell);
2466 class InsertTabUpdater
2468 sc::RefUpdateInsertTabContext& mrCxt;
2469 sc::CellTextAttrStoreType& mrTextAttrs;
2470 sc::CellTextAttrStoreType::iterator miAttrPos;
2471 SCTAB mnTab;
2472 bool mbModified;
2474 public:
2475 InsertTabUpdater(sc::RefUpdateInsertTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2476 mrCxt(rCxt),
2477 mrTextAttrs(rTextAttrs),
2478 miAttrPos(rTextAttrs.begin()),
2479 mnTab(nTab),
2480 mbModified(false) {}
2482 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2484 pCell->UpdateInsertTab(mrCxt);
2485 mbModified = true;
2488 void operator() (size_t nRow, EditTextObject* pCell)
2490 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2491 aUpdater.updateTableFields(mnTab);
2492 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2493 mbModified = true;
2496 bool isModified() const { return mbModified; }
2499 class DeleteTabUpdater
2501 sc::RefUpdateDeleteTabContext& mrCxt;
2502 sc::CellTextAttrStoreType& mrTextAttrs;
2503 sc::CellTextAttrStoreType::iterator miAttrPos;
2504 SCTAB mnTab;
2505 bool mbModified;
2506 public:
2507 DeleteTabUpdater(sc::RefUpdateDeleteTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2508 mrCxt(rCxt),
2509 mrTextAttrs(rTextAttrs),
2510 miAttrPos(rTextAttrs.begin()),
2511 mnTab(nTab),
2512 mbModified(false) {}
2514 void operator() (size_t, ScFormulaCell* pCell)
2516 pCell->UpdateDeleteTab(mrCxt);
2517 mbModified = true;
2520 void operator() (size_t nRow, EditTextObject* pCell)
2522 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2523 aUpdater.updateTableFields(mnTab);
2524 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2525 mbModified = true;
2528 bool isModified() const { return mbModified; }
2531 class InsertAbsTabUpdater
2533 sc::CellTextAttrStoreType& mrTextAttrs;
2534 sc::CellTextAttrStoreType::iterator miAttrPos;
2535 SCTAB mnTab;
2536 SCTAB mnNewPos;
2537 bool mbModified;
2538 public:
2539 InsertAbsTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nNewPos) :
2540 mrTextAttrs(rTextAttrs),
2541 miAttrPos(rTextAttrs.begin()),
2542 mnTab(nTab),
2543 mnNewPos(nNewPos),
2544 mbModified(false) {}
2546 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2548 pCell->UpdateInsertTabAbs(mnNewPos);
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 MoveTabUpdater
2565 sc::RefUpdateMoveTabContext& mrCxt;
2566 sc::CellTextAttrStoreType& mrTextAttrs;
2567 sc::CellTextAttrStoreType::iterator miAttrPos;
2568 SCTAB mnTab;
2569 bool mbModified;
2570 public:
2571 MoveTabUpdater(sc::RefUpdateMoveTabContext& 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 /*nRow*/, ScFormulaCell* pCell)
2580 pCell->UpdateMoveTab(mrCxt, mnTab);
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 UpdateCompileHandler
2597 bool mbForceIfNameInUse:1;
2598 public:
2599 UpdateCompileHandler(bool bForceIfNameInUse) :
2600 mbForceIfNameInUse(bForceIfNameInUse) {}
2602 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2604 pCell->UpdateCompile(mbForceIfNameInUse);
2608 class TabNoSetter
2610 SCTAB mnTab;
2611 public:
2612 TabNoSetter(SCTAB nTab) : mnTab(nTab) {}
2614 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2616 pCell->aPos.SetTab(mnTab);
2620 class UsedRangeNameFinder
2622 std::set<sal_uInt16>& mrIndexes;
2623 public:
2624 UsedRangeNameFinder(std::set<sal_uInt16>& rIndexes) : mrIndexes(rIndexes) {}
2626 void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
2628 pCell->FindRangeNamesInUse(mrIndexes);
2632 struct SetDirtyVarHandler
2634 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2636 p->SetDirtyVar();
2640 class SetDirtyHandler
2642 ScDocument& mrDoc;
2643 const sc::SetFormulaDirtyContext& mrCxt;
2644 public:
2645 SetDirtyHandler( ScDocument& rDoc, const sc::SetFormulaDirtyContext& rCxt ) :
2646 mrDoc(rDoc), mrCxt(rCxt) {}
2648 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2650 if (mrCxt.mbClearTabDeletedFlag)
2652 if (!p->IsShared() || p->IsSharedTop())
2654 ScTokenArray* pCode = p->GetCode();
2655 pCode->ClearTabDeleted(
2656 p->aPos, mrCxt.mnTabDeletedStart, mrCxt.mnTabDeletedEnd);
2660 p->SetDirtyVar();
2661 if (!mrDoc.IsInFormulaTree(p))
2662 mrDoc.PutInFormulaTree(p);
2666 class SetDirtyOnRangeHandler
2668 sc::SingleColumnSpanSet maValueRanges;
2669 ScColumn& mrColumn;
2670 public:
2671 SetDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
2673 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2675 p->SetDirty();
2678 void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2680 if (type == sc::element_type_empty)
2681 // Ignore empty blocks.
2682 return;
2684 // Non-formula cells.
2685 SCROW nRow1 = nTopRow;
2686 SCROW nRow2 = nTopRow + nDataSize - 1;
2687 maValueRanges.set(nRow1, nRow2, true);
2690 void broadcast()
2692 std::vector<SCROW> aRows;
2693 maValueRanges.getRows(aRows);
2694 mrColumn.BroadcastCells(aRows, SC_HINT_DATACHANGED);
2697 void fillBroadcastSpans( sc::ColumnSpanSet& rBroadcastSpans ) const
2699 SCCOL nCol = mrColumn.GetCol();
2700 SCTAB nTab = mrColumn.GetTab();
2701 sc::SingleColumnSpanSet::SpansType aSpans;
2702 maValueRanges.getSpans(aSpans);
2704 sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
2705 for (; it != itEnd; ++it)
2706 rBroadcastSpans.set(nTab, nCol, it->mnRow1, it->mnRow2, true);
2710 class SetTableOpDirtyOnRangeHandler
2712 sc::SingleColumnSpanSet maValueRanges;
2713 ScColumn& mrColumn;
2714 public:
2715 SetTableOpDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
2717 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2719 p->SetTableOpDirty();
2722 void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2724 if (type == sc::element_type_empty)
2725 // Ignore empty blocks.
2726 return;
2728 // Non-formula cells.
2729 SCROW nRow1 = nTopRow;
2730 SCROW nRow2 = nTopRow + nDataSize - 1;
2731 maValueRanges.set(nRow1, nRow2, true);
2734 void broadcast()
2736 std::vector<SCROW> aRows;
2737 maValueRanges.getRows(aRows);
2738 mrColumn.BroadcastCells(aRows, SC_HINT_TABLEOPDIRTY);
2742 struct SetDirtyAfterLoadHandler
2744 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2746 #if 1
2747 // Simply set dirty and append to FormulaTree, without broadcasting,
2748 // which is a magnitude faster. This is used to calculate the entire
2749 // document, e.g. when loading alien file formats.
2750 pCell->SetDirtyAfterLoad();
2751 #else
2752 /* This was used with the binary file format that stored results, where only
2753 * newly compiled and volatile functions and their dependents had to be
2754 * recalculated, which was faster then. Since that was moved to 'binfilter' to
2755 * convert to an XML file this isn't needed anymore, and not used for other
2756 * file formats. Kept for reference in case mechanism needs to be reactivated
2757 * for some file formats, we'd have to introduce a controlling parameter to
2758 * this method here then.
2761 // If the cell was alsready dirty because of CalcAfterLoad,
2762 // FormulaTracking has to take place.
2763 if (pCell->GetDirty())
2764 pCell->SetDirty();
2765 #endif
2769 struct SetDirtyIfPostponedHandler
2771 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2773 if (pCell->IsPostponedDirty() || pCell->HasRelNameReference())
2774 pCell->SetDirty();
2778 struct CalcAllHandler
2780 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2782 #if OSL_DEBUG_LEVEL > 1
2783 // after F9 ctrl-F9: check the calculation for each FormulaTree
2784 double nOldVal, nNewVal;
2785 nOldVal = pCell->GetValue();
2786 #endif
2787 pCell->Interpret();
2788 #if OSL_DEBUG_LEVEL > 1
2789 if (pCell->GetCode()->IsRecalcModeNormal())
2790 nNewVal = pCell->GetValue();
2791 else
2792 nNewVal = nOldVal; // random(), jetzt() etc.
2794 OSL_ENSURE(nOldVal == nNewVal, "CalcAll: nOldVal != nNewVal");
2795 #endif
2799 class CompileAllHandler
2801 sc::CompileFormulaContext& mrCxt;
2802 public:
2803 CompileAllHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
2805 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2807 // for unconditional compilation
2808 // bCompile=true and pCode->nError=0
2809 pCell->GetCode()->SetCodeError(0);
2810 pCell->SetCompile(true);
2811 pCell->CompileTokenArray(mrCxt);
2815 class CompileXMLHandler
2817 sc::CompileFormulaContext& mrCxt;
2818 ScProgress& mrProgress;
2819 const ScColumn& mrCol;
2820 public:
2821 CompileXMLHandler( sc::CompileFormulaContext& rCxt, ScProgress& rProgress, const ScColumn& rCol) :
2822 mrCxt(rCxt),
2823 mrProgress(rProgress),
2824 mrCol(rCol) {}
2826 void operator() (size_t nRow, ScFormulaCell* pCell)
2828 sal_uInt32 nFormat = mrCol.GetNumberFormat(nRow);
2829 if( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
2830 // Non-default number format is set.
2831 pCell->SetNeedNumberFormat(false);
2832 else if (pCell->NeedsNumberFormat())
2833 pCell->SetDirtyVar();
2835 if (pCell->GetMatrixFlag())
2836 pCell->SetDirtyVar();
2838 pCell->CompileXML(mrCxt, mrProgress);
2842 class CompileErrorCellsHandler
2844 sc::CompileFormulaContext& mrCxt;
2845 ScColumn& mrColumn;
2846 sc::CellStoreType::iterator miPos;
2847 sal_uInt16 mnErrCode;
2848 bool mbCompiled;
2849 public:
2850 CompileErrorCellsHandler( sc::CompileFormulaContext& rCxt, ScColumn& rColumn, sal_uInt16 nErrCode ) :
2851 mrCxt(rCxt),
2852 mrColumn(rColumn),
2853 miPos(mrColumn.GetCellStore().begin()),
2854 mnErrCode(nErrCode),
2855 mbCompiled(false)
2859 void operator() (size_t nRow, ScFormulaCell* pCell)
2861 sal_uInt16 nCurError = pCell->GetRawError();
2862 if (!nCurError)
2863 // It's not an error cell. Skip it.
2864 return;
2866 if (mnErrCode && nCurError != mnErrCode)
2867 // Error code is specified, and it doesn't match. Skip it.
2868 return;
2870 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2871 miPos = aPos.first;
2872 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2873 pCell->GetCode()->SetCodeError(0);
2874 OUString aFormula = pCell->GetFormula(mrCxt);
2875 pCell->Compile(mrCxt, aFormula, false);
2876 ScColumn::JoinNewFormulaCell(aPos, *pCell);
2878 mbCompiled = true;
2881 bool isCompiled() const { return mbCompiled; }
2884 class CalcAfterLoadHandler
2886 sc::CompileFormulaContext& mrCxt;
2887 bool mbStartListening;
2889 public:
2890 CalcAfterLoadHandler( sc::CompileFormulaContext& rCxt, bool bStartListening ) :
2891 mrCxt(rCxt), mbStartListening(bStartListening) {}
2893 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2895 pCell->CalcAfterLoad(mrCxt, mbStartListening);
2899 struct ResetChangedHandler
2901 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2903 pCell->SetChanged(false);
2908 * Ambiguous script type counts as edit cell.
2910 class FindEditCellsHandler
2912 ScColumn& mrColumn;
2913 sc::CellTextAttrStoreType::iterator miAttrPos;
2914 sc::CellStoreType::iterator miCellPos;
2916 public:
2917 FindEditCellsHandler(ScColumn& rCol) :
2918 mrColumn(rCol),
2919 miAttrPos(rCol.GetCellAttrStore().begin()),
2920 miCellPos(rCol.GetCellStore().begin()) {}
2922 bool operator() (size_t, const EditTextObject*)
2924 // This is definitely an edit text cell.
2925 return true;
2928 bool operator() (size_t nRow, const ScFormulaCell* p)
2930 // With a formula cell, it's considered an edit text cell when either
2931 // the result is multi-line or it has more than one script types.
2932 SvtScriptType nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
2933 if (IsAmbiguousScriptNonZero(nScriptType))
2934 return true;
2936 return const_cast<ScFormulaCell*>(p)->IsMultilineResult();
2940 * Callback for a block of other types.
2942 std::pair<size_t,bool> operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2944 typedef std::pair<size_t,bool> RetType;
2946 if (node.type == sc::element_type_empty)
2947 // Ignore empty blocks.
2948 return RetType(0, false);
2950 // Check the script type of a non-empty element and see if it has
2951 // multiple script types.
2952 for (size_t i = 0; i < nDataSize; ++i)
2954 SCROW nRow = node.position + i + nOffset;
2955 SvtScriptType nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
2956 if (IsAmbiguousScriptNonZero(nScriptType))
2957 // Return the offset from the first row.
2958 return RetType(i+nOffset, true);
2961 // No edit text cell found.
2962 return RetType(0, false);
2968 void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
2969 ScDocument* pUndoDoc )
2971 UpdateTransHandler aFunc(*this, rSource, rDest, pUndoDoc);
2972 sc::ProcessFormula(maCells, aFunc);
2975 void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
2977 UpdateGrowHandler aFunc(*this, rArea, nGrowX, nGrowY);
2978 sc::ProcessFormula(maCells, aFunc);
2981 void ScColumn::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
2983 if (nTab >= rCxt.mnInsertPos)
2985 nTab += rCxt.mnSheets;
2986 pAttrArray->SetTab(nTab);
2989 UpdateInsertTabOnlyCells(rCxt);
2992 void ScColumn::UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext& rCxt )
2994 InsertTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
2995 sc::ProcessFormulaEditText(maCells, aFunc);
2996 if (aFunc.isModified())
2997 CellStorageModified();
3000 void ScColumn::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
3002 if (nTab > rCxt.mnDeletePos)
3004 nTab -= rCxt.mnSheets;
3005 pAttrArray->SetTab(nTab);
3008 DeleteTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3009 sc::ProcessFormulaEditText(maCells, aFunc);
3010 if (aFunc.isModified())
3011 CellStorageModified();
3014 void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos)
3016 InsertAbsTabUpdater aFunc(maCellTextAttrs, nTab, nNewPos);
3017 sc::ProcessFormulaEditText(maCells, aFunc);
3018 if (aFunc.isModified())
3019 CellStorageModified();
3022 void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo )
3024 nTab = nTabNo;
3025 pAttrArray->SetTab( nTabNo );
3027 MoveTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3028 sc::ProcessFormulaEditText(maCells, aFunc);
3029 if (aFunc.isModified())
3030 CellStorageModified();
3033 void ScColumn::UpdateCompile( bool bForceIfNameInUse )
3035 UpdateCompileHandler aFunc(bForceIfNameInUse);
3036 sc::ProcessFormula(maCells, aFunc);
3039 void ScColumn::SetTabNo(SCTAB nNewTab)
3041 nTab = nNewTab;
3042 pAttrArray->SetTab( nNewTab );
3044 TabNoSetter aFunc(nTab);
3045 sc::ProcessFormula(maCells, aFunc);
3048 void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
3050 UsedRangeNameFinder aFunc(rIndexes);
3051 sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
3054 void ScColumn::SetDirtyVar()
3056 SetDirtyVarHandler aFunc;
3057 sc::ProcessFormula(maCells, aFunc);
3060 bool ScColumn::IsFormulaDirty( SCROW nRow ) const
3062 if (!ValidRow(nRow))
3063 return false;
3065 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3066 sc::CellStoreType::const_iterator it = aPos.first;
3067 if (it->type != sc::element_type_formula)
3068 // This is not a formula cell block.
3069 return false;
3071 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3072 return p->GetDirty();
3075 void ScColumn::SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt )
3077 // is only done documentwide, no FormulaTracking
3078 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3079 SetDirtyHandler aFunc(*pDocument, rCxt);
3080 sc::ProcessFormula(maCells, aFunc);
3083 void ScColumn::SetDirtyFromClip( SCROW nRow1, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans )
3085 // Set all formula cells in the range dirty, and pick up all non-formula
3086 // cells for later broadcasting. We don't broadcast here.
3087 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3089 SetDirtyOnRangeHandler aHdl(*this);
3090 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3091 aHdl.fillBroadcastSpans(rBroadcastSpans);
3094 namespace {
3096 class BroadcastBroadcastersHandler
3098 ScHint& mrHint;
3099 ScAddress& mrAddress;
3100 bool mbBroadcasted;
3102 public:
3103 explicit BroadcastBroadcastersHandler( ScHint& rHint )
3104 : mrHint(rHint)
3105 , mrAddress(mrHint.GetAddress())
3106 , mbBroadcasted(false)
3110 void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
3112 mrAddress.SetRow(nRow);
3113 pBroadcaster->Broadcast(mrHint);
3114 mbBroadcasted = true;
3117 bool wasBroadcasted() { return mbBroadcasted; }
3122 bool ScColumn::BroadcastBroadcasters( SCROW nRow1, SCROW nRow2, ScHint& rHint )
3124 rHint.GetAddress().SetCol(nCol);
3125 BroadcastBroadcastersHandler aBroadcasterHdl( rHint);
3126 sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aBroadcasterHdl);
3127 return aBroadcasterHdl.wasBroadcasted();
3130 void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2, BroadcastMode eMode )
3132 // broadcasts everything within the range, with FormulaTracking
3133 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3135 switch (eMode)
3137 case BROADCAST_NONE:
3139 // Handler only used with formula cells.
3140 SetDirtyOnRangeHandler aHdl(*this);
3141 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl);
3143 break;
3144 case BROADCAST_DATA_POSITIONS:
3146 // Handler used with both, formula and non-formula cells.
3147 SetDirtyOnRangeHandler aHdl(*this);
3148 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3149 aHdl.broadcast();
3151 break;
3152 case BROADCAST_BROADCASTERS:
3154 // Handler only used with formula cells.
3155 SetDirtyOnRangeHandler aHdl(*this);
3156 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl);
3157 // Broadcast all broadcasters in range.
3158 ScHint aHint( SC_HINT_DATACHANGED, ScAddress( nCol, nRow1, nTab));
3159 BroadcastBroadcasters( nRow1, nRow2, aHint);
3161 break;
3165 void ScColumn::SetTableOpDirty( const ScRange& rRange )
3167 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3169 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3170 SetTableOpDirtyOnRangeHandler aHdl(*this);
3171 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3172 aHdl.broadcast();
3175 void ScColumn::SetDirtyAfterLoad()
3177 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3178 SetDirtyAfterLoadHandler aFunc;
3179 sc::ProcessFormula(maCells, aFunc);
3182 namespace {
3184 class RecalcOnRefMoveCollector
3186 std::vector<SCROW> maDirtyRows;
3187 public:
3188 void operator() (size_t nRow, ScFormulaCell* pCell)
3190 if (pCell->GetDirty() && pCell->GetCode()->IsRecalcModeOnRefMove())
3191 maDirtyRows.push_back(nRow);
3194 const std::vector<SCROW>& getDirtyRows() const
3196 return maDirtyRows;
3202 void ScColumn::SetDirtyIfPostponed()
3204 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3205 SetDirtyIfPostponedHandler aFunc;
3206 sc::ProcessFormula(maCells, aFunc);
3209 void ScColumn::BroadcastRecalcOnRefMove()
3211 sc::AutoCalcSwitch aSwitch(*pDocument, false);
3212 RecalcOnRefMoveCollector aFunc;
3213 sc::ProcessFormula(maCells, aFunc);
3214 BroadcastCells(aFunc.getDirtyRows(), SC_HINT_DATACHANGED);
3217 namespace {
3219 class TransferListenersHandler
3221 public:
3222 typedef std::vector<SvtListener*> ListenersType;
3223 struct Entry
3225 size_t mnRow;
3226 ListenersType maListeners;
3228 typedef std::vector<Entry> ListenerListType;
3230 void swapListeners( std::vector<Entry>& rListenerList )
3232 maListenerList.swap(rListenerList);
3235 void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
3237 assert(pBroadcaster);
3239 // It's important to make a copy here.
3240 SvtBroadcaster::ListenersType aLis = pBroadcaster->GetAllListeners();
3241 if (aLis.empty())
3242 // No listeners to transfer.
3243 return;
3245 Entry aEntry;
3246 aEntry.mnRow = nRow;
3248 SvtBroadcaster::ListenersType::iterator it = aLis.begin(), itEnd = aLis.end();
3249 for (; it != itEnd; ++it)
3251 SvtListener* pLis = *it;
3252 pLis->EndListening(*pBroadcaster);
3253 aEntry.maListeners.push_back(pLis);
3256 maListenerList.push_back(aEntry);
3258 // At this point, the source broadcaster should have no more listeners.
3259 assert(!pBroadcaster->HasListeners());
3262 private:
3263 ListenerListType maListenerList;
3266 class RemoveEmptyBroadcasterHandler
3268 sc::ColumnSpanSet maSet;
3269 ScDocument& mrDoc;
3270 SCCOL mnCol;
3271 SCTAB mnTab;
3273 public:
3274 RemoveEmptyBroadcasterHandler( ScDocument& rDoc, SCCOL nCol, SCTAB nTab ) :
3275 maSet(false), mrDoc(rDoc), mnCol(nCol), mnTab(nTab) {}
3277 void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
3279 if (!pBroadcaster->HasListeners())
3280 maSet.set(mnTab, mnCol, nRow, true);
3283 void purge()
3285 sc::PurgeListenerAction aAction(mrDoc);
3286 maSet.executeAction(aAction);
3292 void ScColumn::TransferListeners(
3293 ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta )
3295 if (nRow2 < nRow1)
3296 return;
3298 if (!ValidRow(nRow1) || !ValidRow(nRow2))
3299 return;
3301 if (nRowDelta <= 0 && !ValidRow(nRow1+nRowDelta))
3302 return;
3304 if (nRowDelta >= 0 && !ValidRow(nRow2+nRowDelta))
3305 return;
3307 // Collect all listeners from the source broadcasters. The listeners will
3308 // be removed from their broadcasters as they are collected.
3309 TransferListenersHandler aFunc;
3310 sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
3312 TransferListenersHandler::ListenerListType aListenerList;
3313 aFunc.swapListeners(aListenerList);
3315 // Re-register listeners with their destination broadcasters.
3316 sc::BroadcasterStoreType::iterator itDestPos = rDestCol.maBroadcasters.begin();
3317 TransferListenersHandler::ListenerListType::iterator it = aListenerList.begin(), itEnd = aListenerList.end();
3318 for (; it != itEnd; ++it)
3320 TransferListenersHandler::Entry& rEntry = *it;
3322 SCROW nDestRow = rEntry.mnRow + nRowDelta;
3324 sc::BroadcasterStoreType::position_type aPos =
3325 rDestCol.maBroadcasters.position(itDestPos, nDestRow);
3327 itDestPos = aPos.first;
3328 SvtBroadcaster* pDestBrd = NULL;
3329 if (aPos.first->type == sc::element_type_broadcaster)
3331 // Existing broadcaster.
3332 pDestBrd = sc::broadcaster_block::at(*aPos.first->data, aPos.second);
3334 else
3336 // No existing broadcaster. Create a new one.
3337 assert(aPos.first->type == sc::element_type_empty);
3338 pDestBrd = new SvtBroadcaster;
3339 itDestPos = rDestCol.maBroadcasters.set(itDestPos, nDestRow, pDestBrd);
3342 // Transfer all listeners from the source to the destination.
3343 SvtBroadcaster::ListenersType::iterator it2 = rEntry.maListeners.begin(), it2End = rEntry.maListeners.end();
3344 for (; it2 != it2End; ++it2)
3346 SvtListener* pLis = *it2;
3347 pLis->StartListening(*pDestBrd);
3351 // Remove any broadcasters that have no listeners.
3352 RemoveEmptyBroadcasterHandler aFuncRemoveEmpty(*pDocument, nCol, nTab);
3353 sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFuncRemoveEmpty);
3354 aFuncRemoveEmpty.purge();
3357 void ScColumn::CalcAll()
3359 CalcAllHandler aFunc;
3360 sc::ProcessFormula(maCells, aFunc);
3363 void ScColumn::CompileAll( sc::CompileFormulaContext& rCxt )
3365 CompileAllHandler aFunc(rCxt);
3366 sc::ProcessFormula(maCells, aFunc);
3369 void ScColumn::CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rProgress )
3371 CompileXMLHandler aFunc(rCxt, rProgress, *this);
3372 sc::ProcessFormula(maCells, aFunc);
3373 RegroupFormulaCells();
3376 bool ScColumn::CompileErrorCells( sc::CompileFormulaContext& rCxt, sal_uInt16 nErrCode )
3378 CompileErrorCellsHandler aHdl(rCxt, *this, nErrCode);
3379 sc::ProcessFormula(maCells, aHdl);
3380 return aHdl.isCompiled();
3383 void ScColumn::CalcAfterLoad( sc::CompileFormulaContext& rCxt, bool bStartListening )
3385 CalcAfterLoadHandler aFunc(rCxt, bStartListening);
3386 sc::ProcessFormula(maCells, aFunc);
3389 void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
3391 ResetChangedHandler aFunc;
3392 sc::ProcessFormula(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
3395 bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst)
3397 // used in GetOptimalHeight - ambiguous script type counts as edit cell
3399 FindEditCellsHandler aFunc(*this);
3400 std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
3401 sc::FindFormulaEditText(maCells, nStartRow, nEndRow, aFunc);
3403 if (aPos.first == maCells.end())
3404 return false;
3406 rFirst = aPos.first->position + aPos.second;
3407 return true;
3410 SCsROW ScColumn::SearchStyle(
3411 SCsROW nRow, const ScStyleSheet* pSearchStyle, bool bUp, bool bInSelection,
3412 const ScMarkData& rMark) const
3414 if (bInSelection)
3416 if (rMark.IsMultiMarked())
3417 return pAttrArray->SearchStyle(nRow, pSearchStyle, bUp, rMark.GetArray()+nCol);
3418 else
3419 return -1;
3421 else
3422 return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL );
3425 bool ScColumn::SearchStyleRange(
3426 SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
3427 bool bInSelection, const ScMarkData& rMark) const
3429 if (bInSelection)
3431 if (rMark.IsMultiMarked())
3432 return pAttrArray->SearchStyleRange(
3433 rRow, rEndRow, pSearchStyle, bUp, rMark.GetArray() + nCol);
3434 else
3435 return false;
3437 else
3438 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );
3441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */