Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
48 :
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 :
55 : #include <cstring>
56 : #include <map>
57 : #include <cstdio>
58 : #include <boost/checked_delete.hpp>
59 : #include <boost/scoped_ptr.hpp>
60 :
61 : using ::editeng::SvxBorderLine;
62 : using namespace formula;
63 :
64 : namespace {
65 :
66 65731 : inline bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
67 : {
68 : //! move to a header file
69 346 : return ( nScript != SCRIPTTYPE_LATIN &&
70 346 : nScript != SCRIPTTYPE_ASIAN &&
71 66077 : nScript != SCRIPTTYPE_COMPLEX &&
72 65731 : nScript != 0 );
73 : }
74 :
75 : }
76 :
77 270992 : ScNeededSizeOptions::ScNeededSizeOptions() :
78 270992 : pPattern(NULL), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
79 : {
80 270992 : }
81 :
82 4425728 : ScColumn::ScColumn() :
83 : maCellTextAttrs(MAXROWCOUNT),
84 : maCellNotes(MAXROWCOUNT),
85 : maBroadcasters(MAXROWCOUNT),
86 : maCells(MAXROWCOUNT),
87 : nCol( 0 ),
88 : nTab( 0 ),
89 : pAttrArray( NULL ),
90 : pDocument( NULL ),
91 4425728 : mbDirtyGroups(true)
92 : {
93 4425728 : }
94 :
95 8843264 : ScColumn::~ScColumn()
96 : {
97 4421632 : FreeAll();
98 4421632 : delete pAttrArray;
99 4421632 : }
100 :
101 4425728 : void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
102 : {
103 4425728 : nCol = nNewCol;
104 4425728 : nTab = nNewTab;
105 4425728 : pDocument = pDoc;
106 4425728 : pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
107 4425728 : }
108 :
109 0 : SCsROW ScColumn::GetNextUnprotected( SCROW nRow, bool bUp ) const
110 : {
111 0 : return pAttrArray->GetNextUnprotected(nRow, bUp);
112 : }
113 :
114 212466 : sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
115 : {
116 : using namespace sc;
117 :
118 212466 : if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
119 0 : return 0;
120 :
121 212466 : ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
122 :
123 212466 : if (nRow1 == nRow2)
124 : {
125 210540 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
126 210540 : if (aPos.first->type != sc::element_type_formula)
127 210310 : return 0;
128 :
129 230 : const ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
130 230 : if (!pCell->GetMatrixFlag())
131 220 : return 0;
132 :
133 10 : return pCell->GetMatrixEdge(aOrigin);
134 : }
135 :
136 1926 : bool bOpen = false;
137 1926 : sal_uInt16 nEdges = 0;
138 :
139 1926 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
140 1926 : sc::CellStoreType::const_iterator it = aPos.first;
141 1926 : size_t nOffset = aPos.second;
142 1926 : SCROW nRow = nRow1;
143 5526 : for (;it != maCells.end() && nRow <= nRow2; ++it, nOffset = 0)
144 : {
145 3600 : if (it->type != sc::element_type_formula)
146 : {
147 : // Skip this block.
148 3490 : nRow += it->size - nOffset;
149 3490 : continue;
150 : }
151 :
152 110 : size_t nRowsToRead = nRow2 - nRow + 1;
153 110 : size_t nEnd = std::min(it->size, nOffset+nRowsToRead); // last row + 1
154 110 : sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
155 110 : std::advance(itCell, nOffset);
156 390 : for (size_t i = nOffset; i < nEnd; ++itCell, ++i)
157 : {
158 : // Loop inside the formula block.
159 280 : const ScFormulaCell* pCell = *itCell;
160 280 : if (!pCell->GetMatrixFlag())
161 276 : continue;
162 :
163 4 : nEdges = pCell->GetMatrixEdge(aOrigin);
164 4 : if (!nEdges)
165 0 : continue;
166 :
167 4 : if (nEdges & MatrixEdgeTop)
168 2 : bOpen = true; // top edge opens, keep on looking
169 2 : else if (!bOpen)
170 0 : return nEdges | MatrixEdgeOpen; // there's something that wasn't opened
171 2 : else if (nEdges & MatrixEdgeInside)
172 0 : return nEdges; // inside
173 : // (nMask & 16 and (4 and not 16)) or
174 : // (nMask & 4 and (16 and not 4))
175 8 : if (((nMask & MatrixEdgeRight) && (nEdges & MatrixEdgeLeft) && !(nEdges & MatrixEdgeRight)) ||
176 8 : ((nMask & MatrixEdgeLeft) && (nEdges & MatrixEdgeRight) && !(nEdges & MatrixEdgeLeft)))
177 0 : return nEdges; // only left/right edge
178 :
179 4 : if (nEdges & MatrixEdgeBottom)
180 2 : bOpen = false; // bottom edge closes
181 : }
182 :
183 110 : nRow += nEnd;
184 : }
185 1926 : if (bOpen)
186 0 : nEdges |= MatrixEdgeOpen; // not closed, matrix continues
187 :
188 1926 : return nEdges;
189 : }
190 :
191 748 : bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
192 : {
193 : using namespace sc;
194 :
195 748 : if (!rMark.IsMultiMarked())
196 0 : return false;
197 :
198 748 : ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
199 748 : ScAddress aCurOrigin = aOrigin;
200 :
201 748 : bool bOpen = false;
202 748 : ScRangeList aRanges = rMark.GetMarkedRanges();
203 3584 : for (size_t i = 0, n = aRanges.size(); i < n; ++i)
204 : {
205 2836 : const ScRange& r = *aRanges[i];
206 2836 : if (nTab < r.aStart.Tab() || r.aEnd.Tab() < nTab)
207 2088 : continue;
208 :
209 2836 : if (nCol < r.aStart.Col() || r.aEnd.Col() < nCol)
210 2088 : continue;
211 :
212 748 : SCROW nTop = r.aStart.Row(), nBottom = r.aEnd.Row();
213 748 : SCROW nRow = nTop;
214 748 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
215 748 : sc::CellStoreType::const_iterator it = aPos.first;
216 748 : size_t nOffset = aPos.second;
217 :
218 1496 : for (;it != maCells.end() && nRow <= nBottom; ++it, nOffset = 0)
219 : {
220 748 : if (it->type != sc::element_type_formula)
221 : {
222 : // Skip this block.
223 748 : nRow += it->size - nOffset;
224 748 : continue;
225 : }
226 :
227 : // This is a formula cell block.
228 0 : size_t nRowsToRead = nBottom - nRow + 1;
229 0 : size_t nEnd = std::min(it->size, nRowsToRead);
230 0 : sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
231 0 : std::advance(itCell, nOffset);
232 0 : for (size_t j = nOffset; j < nEnd; ++itCell, ++j)
233 : {
234 : // Loop inside the formula block.
235 0 : const ScFormulaCell* pCell = *itCell;
236 0 : if (!pCell->GetMatrixFlag())
237 : // cell is not a part of a matrix.
238 0 : continue;
239 :
240 0 : sal_uInt16 nEdges = pCell->GetMatrixEdge(aOrigin);
241 0 : if (!nEdges)
242 0 : continue;
243 :
244 0 : bool bFound = false;
245 :
246 0 : if (nEdges & MatrixEdgeTop)
247 0 : bOpen = true; // top edge opens, keep on looking
248 0 : else if (!bOpen)
249 0 : return true; // there's something that wasn't opened
250 0 : else if (nEdges & MatrixEdgeInside)
251 0 : bFound = true; // inside, all selected?
252 :
253 0 : if ((((nEdges & MatrixEdgeLeft) | MatrixEdgeRight) ^ ((nEdges & MatrixEdgeRight) | MatrixEdgeLeft)))
254 : // either left or right, but not both.
255 0 : bFound = true; // only left/right edge, all selected?
256 :
257 0 : if (nEdges & MatrixEdgeBottom)
258 0 : bOpen = false; // bottom edge closes
259 :
260 0 : if (bFound)
261 : {
262 : // Check if the matrix is inside the selection in its entirety.
263 : //
264 : // TODO: It's more efficient to skip the matrix range if
265 : // it's within selection, to avoid checking it again and
266 : // again.
267 :
268 0 : if (aCurOrigin != aOrigin)
269 : { // new matrix to check?
270 0 : aCurOrigin = aOrigin;
271 : const ScFormulaCell* pFCell;
272 0 : if (pCell->GetMatrixFlag() == MM_REFERENCE)
273 0 : pFCell = pDocument->GetFormulaCell(aOrigin);
274 : else
275 0 : pFCell = pCell;
276 :
277 : SCCOL nC;
278 : SCROW nR;
279 0 : pFCell->GetMatColsRows(nC, nR);
280 0 : ScRange aRange(aOrigin, ScAddress(aOrigin.Col()+nC-1, aOrigin.Row()+nR-1, aOrigin.Tab()));
281 0 : if (rMark.IsAllMarked(aRange))
282 0 : bFound = false;
283 : }
284 : else
285 0 : bFound = false; // done already
286 : }
287 :
288 0 : if (bFound)
289 0 : return true;
290 : }
291 :
292 0 : nRow += nEnd;
293 : }
294 : }
295 :
296 748 : if (bOpen)
297 0 : return true;
298 :
299 748 : return false;
300 : }
301 :
302 28191952 : bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
303 : {
304 28191952 : return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
305 : }
306 :
307 0 : bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
308 : {
309 0 : bool bFound = false;
310 :
311 : SCROW nTop;
312 : SCROW nBottom;
313 :
314 0 : if (rMark.IsMultiMarked())
315 : {
316 0 : ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
317 0 : while (aMarkIter.Next( nTop, nBottom ) && !bFound)
318 : {
319 0 : if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
320 0 : bFound = true;
321 0 : }
322 : }
323 :
324 0 : return bFound;
325 : }
326 :
327 20536 : bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
328 : SCCOL& rPaintCol, SCROW& rPaintRow,
329 : bool bRefresh )
330 : {
331 20536 : return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh );
332 : }
333 :
334 512000 : void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
335 : {
336 : SCROW nTop;
337 : SCROW nBottom;
338 :
339 512000 : if ( rMark.IsMultiMarked() )
340 : {
341 512000 : const ScMarkArray* pArray = rMark.GetArray() + nCol;
342 512000 : if ( pArray->HasMarks() )
343 : {
344 60160 : ScMarkArrayIter aMarkIter( pArray );
345 181936 : while (aMarkIter.Next( nTop, nBottom ))
346 121776 : pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
347 : }
348 : }
349 512000 : }
350 :
351 112654 : void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, bool bDeep ) const
352 : {
353 112654 : pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
354 112654 : }
355 :
356 256 : void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
357 : ScLineFlags& rFlags,
358 : SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
359 : {
360 256 : pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
361 256 : }
362 :
363 3692 : void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
364 : SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
365 : {
366 3692 : pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
367 3692 : }
368 :
369 37831569 : const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
370 : {
371 37831569 : return pAttrArray->GetPattern( nRow );
372 : }
373 :
374 22610 : const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
375 : {
376 22610 : return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
377 : }
378 :
379 88576 : const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
380 : {
381 88576 : ::std::map< const ScPatternAttr*, size_t > aAttrMap;
382 88576 : const ScPatternAttr* pMaxPattern = 0;
383 88576 : size_t nMaxCount = 0;
384 :
385 88576 : ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
386 : const ScPatternAttr* pPattern;
387 88576 : SCROW nAttrRow1 = 0, nAttrRow2 = 0;
388 :
389 269552 : while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
390 : {
391 92400 : size_t& rnCount = aAttrMap[ pPattern ];
392 92400 : rnCount += (nAttrRow2 - nAttrRow1 + 1);
393 92400 : if( rnCount > nMaxCount )
394 : {
395 90576 : pMaxPattern = pPattern;
396 90576 : nMaxCount = rnCount;
397 : }
398 : }
399 :
400 88576 : return pMaxPattern;
401 : }
402 :
403 48 : sal_uInt32 ScColumn::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
404 : {
405 : SCROW nPatStartRow, nPatEndRow;
406 48 : const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
407 48 : sal_uInt32 nFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
408 96 : while (nEndRow > nPatEndRow)
409 : {
410 0 : nStartRow = nPatEndRow + 1;
411 0 : pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
412 0 : sal_uInt32 nTmpFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
413 0 : if (nFormat != nTmpFormat)
414 0 : return 0;
415 : }
416 48 : return nFormat;
417 : }
418 :
419 102775 : sal_uInt32 ScColumn::GetNumberFormat( SCROW nRow ) const
420 : {
421 102775 : return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
422 : }
423 :
424 352256 : SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray )
425 : {
426 352256 : SCROW nTop = 0;
427 352256 : SCROW nBottom = 0;
428 352256 : bool bFound = false;
429 :
430 352256 : if ( rMark.IsMultiMarked() )
431 : {
432 352256 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
433 720330 : while (aMarkIter.Next( nTop, nBottom ))
434 : {
435 15818 : pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray );
436 15818 : bFound = true;
437 352256 : }
438 : }
439 :
440 352256 : if (!bFound)
441 337666 : return -1;
442 14590 : else if (nTop==0 && nBottom==MAXROW)
443 8144 : return 0;
444 : else
445 6446 : return nBottom;
446 : }
447 :
448 12288 : void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
449 : {
450 : SCROW nTop;
451 : SCROW nBottom;
452 :
453 12288 : if ( pAttrArray && rMark.IsMultiMarked() )
454 : {
455 12288 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
456 24628 : while (aMarkIter.Next( nTop, nBottom ))
457 12340 : pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
458 : }
459 12288 : }
460 :
461 0 : void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
462 : {
463 : SCROW nTop;
464 : SCROW nBottom;
465 :
466 0 : if ( pAttrArray && rMark.IsMultiMarked() )
467 : {
468 0 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
469 0 : while (aMarkIter.Next( nTop, nBottom ))
470 0 : pAttrArray->ClearItems(nTop, nBottom, pWhich);
471 : }
472 0 : }
473 :
474 190464 : void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
475 : {
476 : SCROW nTop;
477 : SCROW nBottom;
478 :
479 190464 : if ( rMark.IsMultiMarked() )
480 : {
481 188416 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
482 377212 : while (aMarkIter.Next( nTop, nBottom ))
483 188796 : DeleteArea(nTop, nBottom, nDelFlag, bBroadcast);
484 : }
485 190464 : }
486 :
487 274 : void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
488 : {
489 274 : const SfxItemSet* pSet = &rPatAttr.GetItemSet();
490 274 : SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
491 :
492 274 : const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
493 :
494 : // true = keep old content
495 :
496 274 : const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &aCache.ApplyTo( *pPattern, true ) );
497 274 : ScDocumentPool::CheckRef( *pPattern );
498 274 : ScDocumentPool::CheckRef( *pNewPattern );
499 :
500 274 : if (pNewPattern != pPattern)
501 274 : pAttrArray->SetPattern( nRow, pNewPattern );
502 274 : }
503 :
504 134398 : void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr,
505 : ScEditDataArray* pDataArray )
506 : {
507 134398 : const SfxItemSet* pSet = &rPatAttr.GetItemSet();
508 134398 : SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
509 134398 : pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache, pDataArray );
510 134398 : }
511 :
512 0 : void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
513 : const ScPatternAttr& rPattern, short nNewType )
514 : {
515 0 : const SfxItemSet* pSet = &rPattern.GetItemSet();
516 0 : SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
517 0 : SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
518 0 : SCROW nEndRow = rRange.aEnd.Row();
519 0 : for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
520 : {
521 : SCROW nRow1, nRow2;
522 : const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
523 0 : nRow1, nRow2, nRow );
524 0 : sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
525 0 : short nOldType = pFormatter->GetType( nFormat );
526 0 : if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) )
527 0 : nRow = nRow2;
528 : else
529 : {
530 0 : SCROW nNewRow1 = std::max( nRow1, nRow );
531 0 : SCROW nNewRow2 = std::min( nRow2, nEndRow );
532 0 : pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
533 0 : nRow = nNewRow2;
534 : }
535 0 : }
536 0 : }
537 :
538 13036 : void ScColumn::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
539 : {
540 13036 : pAttrArray->AddCondFormat( nStartRow, nEndRow, nIndex );
541 13036 : }
542 :
543 0 : void ScColumn::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
544 : {
545 0 : pAttrArray->RemoveCondFormat( nStartRow, nEndRow, nIndex );
546 0 : }
547 :
548 4 : void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
549 : {
550 4 : const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
551 4 : boost::scoped_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pPattern));
552 4 : if (pNewPattern)
553 : {
554 4 : pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
555 4 : pAttrArray->SetPattern(nRow, pNewPattern.get(), true);
556 4 : }
557 4 : }
558 :
559 406092 : void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
560 : {
561 406092 : pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle);
562 406092 : }
563 :
564 481280 : void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
565 : {
566 : SCROW nTop;
567 : SCROW nBottom;
568 :
569 481280 : if ( rMark.IsMultiMarked() )
570 : {
571 481280 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
572 983772 : while (aMarkIter.Next( nTop, nBottom ))
573 502492 : pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle);
574 : }
575 481280 : }
576 :
577 0 : void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
578 : const SvxBorderLine* pLine, bool bColorOnly )
579 : {
580 0 : if ( bColorOnly && !pLine )
581 0 : return;
582 :
583 : SCROW nTop;
584 : SCROW nBottom;
585 :
586 0 : if (rMark.IsMultiMarked())
587 : {
588 0 : ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
589 0 : while (aMarkIter.Next( nTop, nBottom ))
590 0 : pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
591 : }
592 : }
593 :
594 16 : const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
595 : {
596 16 : return pAttrArray->GetPattern( nRow )->GetStyleSheet();
597 : }
598 :
599 45056 : const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
600 : {
601 45056 : rFound = false;
602 45056 : if (!rMark.IsMultiMarked())
603 : {
604 : OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
605 0 : return NULL;
606 : }
607 :
608 45056 : bool bEqual = true;
609 :
610 45056 : const ScStyleSheet* pStyle = NULL;
611 : const ScStyleSheet* pNewStyle;
612 :
613 45056 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
614 : SCROW nTop;
615 : SCROW nBottom;
616 135252 : while (bEqual && aMarkIter.Next( nTop, nBottom ))
617 : {
618 45140 : ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
619 : SCROW nRow;
620 : SCROW nDummy;
621 : const ScPatternAttr* pPattern;
622 135420 : while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
623 : {
624 45140 : pNewStyle = pPattern->GetStyleSheet();
625 45140 : rFound = true;
626 45140 : if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
627 0 : bEqual = false; // difference
628 45140 : pStyle = pNewStyle;
629 : }
630 : }
631 :
632 45056 : return bEqual ? pStyle : NULL;
633 : }
634 :
635 70060 : const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRow2 ) const
636 : {
637 70060 : rFound = false;
638 :
639 70060 : bool bEqual = true;
640 :
641 70060 : const ScStyleSheet* pStyle = NULL;
642 : const ScStyleSheet* pNewStyle;
643 :
644 70060 : ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
645 : SCROW nRow;
646 : SCROW nDummy;
647 : const ScPatternAttr* pPattern;
648 210200 : while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
649 : {
650 70080 : pNewStyle = pPattern->GetStyleSheet();
651 70080 : rFound = true;
652 70080 : if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
653 0 : bEqual = false; // difference
654 70080 : pStyle = pNewStyle;
655 : }
656 :
657 70060 : return bEqual ? pStyle : NULL;
658 : }
659 :
660 10694656 : void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
661 : {
662 10694656 : pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
663 10694656 : }
664 :
665 0 : bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const
666 : {
667 0 : return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
668 : }
669 :
670 10872 : bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
671 : {
672 10872 : return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
673 : }
674 :
675 32328 : bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
676 : {
677 32328 : return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
678 : }
679 :
680 330 : void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
681 : {
682 330 : pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
683 330 : }
684 :
685 326 : void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, bool bPutToPool )
686 : {
687 326 : pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
688 326 : }
689 :
690 68 : void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
691 : const ScPatternAttr& rPatAttr, bool bPutToPool )
692 : {
693 68 : pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
694 68 : }
695 :
696 6016 : void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
697 : {
698 : // in order to only create a new SetItem, we don't need SfxItemPoolCache.
699 : //! Warning: SfxItemPoolCache seems to create to many Refs for the new SetItem ??
700 :
701 6016 : ScDocumentPool* pDocPool = pDocument->GetPool();
702 :
703 6016 : const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
704 6016 : boost::scoped_ptr<ScPatternAttr> pTemp(new ScPatternAttr(*pOldPattern));
705 6016 : pTemp->GetItemSet().Put(rAttr);
706 6016 : const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pDocPool->Put( *pTemp ) );
707 :
708 6016 : if ( pNewPattern != pOldPattern )
709 5392 : pAttrArray->SetPattern( nRow, pNewPattern );
710 : else
711 624 : pDocPool->Remove( *pNewPattern ); // free up resources
712 6016 : }
713 :
714 192220 : ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
715 : {
716 192220 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
717 192220 : if (aPos.first == maCells.end())
718 0 : return ScRefCellValue();
719 :
720 192220 : return GetCellValue(aPos.first, aPos.second);
721 : }
722 :
723 11370 : ScRefCellValue ScColumn::GetCellValue( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
724 : {
725 11370 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
726 11370 : if (aPos.first == maCells.end())
727 0 : return ScRefCellValue();
728 :
729 11370 : rBlockPos.miCellPos = aPos.first; // Store this for next call.
730 11370 : return GetCellValue(aPos.first, aPos.second);
731 : }
732 :
733 256381 : ScRefCellValue ScColumn::GetCellValue( const sc::CellStoreType::const_iterator& itPos, size_t nOffset ) const
734 : {
735 256381 : ScRefCellValue aVal; // Defaults to empty cell.
736 256381 : switch (itPos->type)
737 : {
738 : case sc::element_type_numeric:
739 : // Numeric cell
740 100952 : aVal.mfValue = sc::numeric_block::at(*itPos->data, nOffset);
741 100952 : aVal.meType = CELLTYPE_VALUE;
742 100952 : break;
743 : case sc::element_type_string:
744 : // String cell
745 35549 : aVal.mpString = &sc::string_block::at(*itPos->data, nOffset);
746 35549 : aVal.meType = CELLTYPE_STRING;
747 35549 : break;
748 : case sc::element_type_edittext:
749 : // Edit cell
750 1576 : aVal.mpEditText = sc::edittext_block::at(*itPos->data, nOffset);
751 1576 : aVal.meType = CELLTYPE_EDIT;
752 1576 : break;
753 : case sc::element_type_formula:
754 : // Formula cell
755 55785 : aVal.mpFormula = sc::formula_block::at(*itPos->data, nOffset);
756 55785 : aVal.meType = CELLTYPE_FORMULA;
757 55785 : break;
758 : default:
759 : ;
760 : }
761 :
762 256381 : return aVal;
763 : }
764 :
765 11120 : const sc::CellTextAttr* ScColumn::GetCellTextAttr( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
766 : {
767 11120 : sc::CellTextAttrStoreType::const_position_type aPos = maCellTextAttrs.position(rBlockPos.miCellTextAttrPos, nRow);
768 11120 : if (aPos.first == maCellTextAttrs.end())
769 0 : return NULL;
770 :
771 11120 : rBlockPos.miCellTextAttrPos = aPos.first;
772 :
773 11120 : if (aPos.first->type != sc::element_type_celltextattr)
774 10300 : return NULL;
775 :
776 820 : return &sc::celltextattr_block::at(*aPos.first->data, aPos.second);
777 : }
778 :
779 118 : bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
780 : {
781 118 : if (IsEmpty())
782 118 : return true;
783 :
784 : // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
785 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
786 0 : sc::CellStoreType::const_iterator it = aPos.first;
787 0 : if (it->type != sc::element_type_empty)
788 0 : return false;
789 :
790 : // Get the length of the remaining empty segment.
791 0 : size_t nLen = it->size - aPos.second;
792 0 : SCROW nNextNonEmptyRow = nStartRow + nLen;
793 0 : if (nNextNonEmptyRow <= nEndRow)
794 0 : return false;
795 :
796 : // AttrArray only looks for merged cells
797 :
798 0 : return pAttrArray ? pAttrArray->TestInsertCol(nStartRow, nEndRow) : true;
799 : }
800 :
801 81938 : bool ScColumn::TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const
802 : {
803 : // AttrArray only looks for merged cells
804 : {
805 81938 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
806 81938 : sc::CellStoreType::const_iterator it = aPos.first;
807 81938 : if (it->type == sc::element_type_empty && maCells.block_size() == 1)
808 : // The entire cell array is empty.
809 81810 : return pAttrArray->TestInsertRow(nSize);
810 : }
811 :
812 : // See if there would be any non-empty cell that gets pushed out.
813 :
814 : // Find the position of the last non-empty cell below nStartRow.
815 128 : size_t nLastNonEmptyRow = MAXROW;
816 128 : sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
817 128 : if (it->type == sc::element_type_empty)
818 128 : nLastNonEmptyRow -= it->size;
819 :
820 128 : if (nLastNonEmptyRow < static_cast<size_t>(nStartRow))
821 : // No cells would get pushed out.
822 42 : return pAttrArray->TestInsertRow(nSize);
823 :
824 86 : if (nLastNonEmptyRow + nSize > static_cast<size_t>(MAXROW))
825 : // At least one cell would get pushed out. Not good.
826 0 : return false;
827 :
828 86 : return pAttrArray->TestInsertRow(nSize);
829 : }
830 :
831 81938 : void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
832 : {
833 81938 : pAttrArray->InsertRow( nStartRow, nSize );
834 :
835 81938 : maCellNotes.insert_empty(nStartRow, nSize);
836 81938 : maCellNotes.resize(MAXROWCOUNT);
837 :
838 81938 : maBroadcasters.insert_empty(nStartRow, nSize);
839 81938 : maBroadcasters.resize(MAXROWCOUNT);
840 :
841 81938 : maCellTextAttrs.insert_empty(nStartRow, nSize);
842 81938 : maCellTextAttrs.resize(MAXROWCOUNT);
843 :
844 81938 : maCells.insert_empty(nStartRow, nSize);
845 81938 : maCells.resize(MAXROWCOUNT);
846 :
847 81938 : CellStorageModified();
848 :
849 : // We *probably* don't need to broadcast here since the parent call seems
850 : // to take care of it.
851 81938 : }
852 :
853 : namespace {
854 :
855 : class CopyToClipHandler
856 : {
857 : const ScColumn& mrSrcCol;
858 : ScColumn& mrDestCol;
859 : sc::ColumnBlockPosition maDestPos;
860 : sc::ColumnBlockPosition* mpDestPos;
861 : bool mbCopyNotes;
862 :
863 154 : void setDefaultAttrsToDest(size_t nRow, size_t nSize)
864 : {
865 154 : std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
866 308 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
867 308 : maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
868 154 : }
869 :
870 200 : void duplicateNotes(SCROW nStartRow, size_t nDataSize )
871 : {
872 200 : mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, false);
873 200 : }
874 :
875 : public:
876 150 : CopyToClipHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, bool bCopyNotes) :
877 150 : mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mbCopyNotes(bCopyNotes)
878 : {
879 150 : if (mpDestPos)
880 150 : maDestPos = *mpDestPos;
881 : else
882 0 : mrDestCol.InitBlockPosition(maDestPos);
883 150 : }
884 :
885 150 : ~CopyToClipHandler()
886 : {
887 150 : if (mpDestPos)
888 150 : *mpDestPos = maDestPos;
889 150 : }
890 :
891 200 : void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
892 : {
893 200 : size_t nTopRow = aNode.position + nOffset;
894 :
895 200 : bool bSet = true;
896 :
897 200 : switch (aNode.type)
898 : {
899 : case sc::element_type_numeric:
900 : {
901 70 : sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
902 70 : std::advance(it, nOffset);
903 70 : sc::numeric_block::const_iterator itEnd = it;
904 70 : std::advance(itEnd, nDataSize);
905 70 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
906 : }
907 70 : break;
908 : case sc::element_type_string:
909 : {
910 42 : sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
911 42 : std::advance(it, nOffset);
912 42 : sc::string_block::const_iterator itEnd = it;
913 42 : std::advance(itEnd, nDataSize);
914 42 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
915 :
916 : }
917 42 : break;
918 : case sc::element_type_edittext:
919 : {
920 0 : sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
921 0 : std::advance(it, nOffset);
922 0 : sc::edittext_block::const_iterator itEnd = it;
923 0 : std::advance(itEnd, nDataSize);
924 :
925 0 : std::vector<EditTextObject*> aCloned;
926 0 : aCloned.reserve(nDataSize);
927 0 : for (; it != itEnd; ++it)
928 0 : aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
929 :
930 0 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(
931 0 : maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
932 : }
933 0 : break;
934 : case sc::element_type_formula:
935 : {
936 42 : sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
937 42 : std::advance(it, nOffset);
938 42 : sc::formula_block::const_iterator itEnd = it;
939 42 : std::advance(itEnd, nDataSize);
940 :
941 42 : std::vector<ScFormulaCell*> aCloned;
942 42 : aCloned.reserve(nDataSize);
943 42 : ScAddress aDestPos(mrDestCol.GetCol(), nTopRow, mrDestCol.GetTab());
944 118 : for (; it != itEnd; ++it, aDestPos.IncRow())
945 : {
946 76 : const ScFormulaCell& rOld = **it;
947 76 : if (rOld.GetDirty() && mrSrcCol.GetDoc().GetAutoCalc())
948 32 : const_cast<ScFormulaCell&>(rOld).Interpret();
949 :
950 76 : aCloned.push_back(new ScFormulaCell(rOld, mrDestCol.GetDoc(), aDestPos));
951 : }
952 :
953 : // Group the cloned formula cells.
954 42 : if (!aCloned.empty())
955 42 : sc::SharedFormulaUtil::groupFormulaCells(aCloned.begin(), aCloned.end());
956 :
957 42 : sc::CellStoreType& rDestCells = mrDestCol.GetCellStore();
958 84 : maDestPos.miCellPos = rDestCells.set(
959 42 : maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
960 :
961 : // Merge adjacent formula cell groups (if applicable).
962 : sc::CellStoreType::position_type aPos =
963 42 : rDestCells.position(maDestPos.miCellPos, nTopRow);
964 42 : maDestPos.miCellPos = aPos.first;
965 42 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
966 42 : size_t nLastRow = nTopRow + nDataSize;
967 42 : if (nLastRow < static_cast<size_t>(MAXROW))
968 : {
969 42 : aPos = rDestCells.position(maDestPos.miCellPos, nLastRow+1);
970 42 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
971 42 : }
972 : }
973 42 : break;
974 : default:
975 46 : bSet = false;
976 : }
977 :
978 200 : if (bSet)
979 154 : setDefaultAttrsToDest(nTopRow, nDataSize);
980 :
981 200 : if (mbCopyNotes)
982 200 : duplicateNotes(nTopRow, nDataSize);
983 200 : }
984 : };
985 :
986 : class CopyTextAttrToClipHandler
987 : {
988 : sc::CellTextAttrStoreType& mrDestAttrs;
989 : sc::CellTextAttrStoreType::iterator miPos;
990 :
991 : public:
992 150 : CopyTextAttrToClipHandler( sc::CellTextAttrStoreType& rAttrs ) :
993 150 : mrDestAttrs(rAttrs), miPos(mrDestAttrs.begin()) {}
994 :
995 178 : void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
996 : {
997 178 : if (aNode.type != sc::element_type_celltextattr)
998 224 : return;
999 :
1000 132 : sc::celltextattr_block::const_iterator it = sc::celltextattr_block::begin(*aNode.data);
1001 132 : std::advance(it, nOffset);
1002 132 : sc::celltextattr_block::const_iterator itEnd = it;
1003 132 : std::advance(itEnd, nDataSize);
1004 :
1005 132 : size_t nPos = aNode.position + nOffset;
1006 132 : miPos = mrDestAttrs.set(miPos, nPos, it, itEnd);
1007 : }
1008 : };
1009 :
1010 :
1011 : }
1012 :
1013 150 : void ScColumn::CopyToClip(
1014 : sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
1015 : {
1016 : pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
1017 150 : rCxt.isKeepScenarioFlags() ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
1018 :
1019 : {
1020 150 : CopyToClipHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), rCxt.isCloneNotes());
1021 150 : sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1022 : }
1023 :
1024 : {
1025 150 : CopyTextAttrToClipHandler aFunc(rColumn.maCellTextAttrs);
1026 150 : sc::ParseBlock(maCellTextAttrs.begin(), maCellTextAttrs, aFunc, nRow1, nRow2);
1027 : }
1028 :
1029 150 : rColumn.CellStorageModified();
1030 150 : }
1031 :
1032 12 : void ScColumn::CopyStaticToDocument(
1033 : SCROW nRow1, SCROW nRow2, const SvNumberFormatterMergeMap& rMap, ScColumn& rDestCol )
1034 : {
1035 12 : if (nRow1 > nRow2)
1036 12 : return;
1037 :
1038 12 : sc::ColumnBlockPosition aDestPos;
1039 12 : CopyCellTextAttrsToDocument(nRow1, nRow2, rDestCol);
1040 12 : CopyCellNotesToDocument(nRow1, nRow2, rDestCol);
1041 :
1042 : // First, clear the destination column for the specified row range.
1043 12 : rDestCol.maCells.set_empty(nRow1, nRow2);
1044 :
1045 12 : aDestPos.miCellPos = rDestCol.maCells.begin();
1046 :
1047 12 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
1048 12 : sc::CellStoreType::const_iterator it = aPos.first;
1049 12 : size_t nOffset = aPos.second;
1050 12 : size_t nDataSize = 0;
1051 12 : size_t nCurRow = nRow1;
1052 :
1053 18 : for (; it != maCells.end() && nCurRow <= static_cast<size_t>(nRow2); ++it, nOffset = 0, nCurRow += nDataSize)
1054 : {
1055 14 : bool bLastBlock = false;
1056 14 : nDataSize = it->size - nOffset;
1057 14 : if (nCurRow + nDataSize - 1 > static_cast<size_t>(nRow2))
1058 : {
1059 : // Truncate the block to copy to clipboard.
1060 8 : nDataSize = nRow2 - nCurRow + 1;
1061 8 : bLastBlock = true;
1062 : }
1063 :
1064 14 : switch (it->type)
1065 : {
1066 : case sc::element_type_numeric:
1067 : {
1068 8 : sc::numeric_block::const_iterator itData = sc::numeric_block::begin(*it->data);
1069 8 : std::advance(itData, nOffset);
1070 8 : sc::numeric_block::const_iterator itDataEnd = itData;
1071 8 : std::advance(itDataEnd, nDataSize);
1072 8 : aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1073 : }
1074 8 : break;
1075 : case sc::element_type_string:
1076 : {
1077 2 : sc::string_block::const_iterator itData = sc::string_block::begin(*it->data);
1078 2 : std::advance(itData, nOffset);
1079 2 : sc::string_block::const_iterator itDataEnd = itData;
1080 2 : std::advance(itDataEnd, nDataSize);
1081 2 : aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1082 : }
1083 2 : break;
1084 : case sc::element_type_edittext:
1085 : {
1086 0 : sc::edittext_block::const_iterator itData = sc::edittext_block::begin(*it->data);
1087 0 : std::advance(itData, nOffset);
1088 0 : sc::edittext_block::const_iterator itDataEnd = itData;
1089 0 : std::advance(itDataEnd, nDataSize);
1090 :
1091 : // Convert to simple strings.
1092 0 : std::vector<svl::SharedString> aConverted;
1093 0 : aConverted.reserve(nDataSize);
1094 0 : for (; itData != itDataEnd; ++itData)
1095 : {
1096 0 : const EditTextObject& rObj = **itData;
1097 0 : svl::SharedString aSS = pDocument->GetSharedStringPool().intern(ScEditUtil::GetString(rObj, pDocument));
1098 0 : aConverted.push_back(aSS);
1099 0 : }
1100 0 : aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, aConverted.begin(), aConverted.end());
1101 : }
1102 0 : break;
1103 : case sc::element_type_formula:
1104 : {
1105 2 : sc::formula_block::const_iterator itData = sc::formula_block::begin(*it->data);
1106 2 : std::advance(itData, nOffset);
1107 2 : sc::formula_block::const_iterator itDataEnd = itData;
1108 2 : std::advance(itDataEnd, nDataSize);
1109 :
1110 : // Interpret and convert to raw values.
1111 4 : for (SCROW i = 0; itData != itDataEnd; ++itData, ++i)
1112 : {
1113 2 : SCROW nRow = nCurRow + i;
1114 :
1115 2 : ScFormulaCell& rFC = const_cast<ScFormulaCell&>(**itData);
1116 2 : if (rFC.GetDirty() && pDocument->GetAutoCalc())
1117 0 : rFC.Interpret();
1118 :
1119 2 : if (rFC.GetErrCode())
1120 : // Skip cells with error.
1121 0 : break;
1122 :
1123 2 : if (rFC.IsValue())
1124 2 : aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, rFC.GetValue());
1125 : else
1126 : {
1127 0 : svl::SharedString aSS = rFC.GetString();
1128 0 : if (aSS.isValid())
1129 0 : aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, aSS);
1130 : }
1131 : }
1132 : }
1133 2 : break;
1134 : default:
1135 : ;
1136 : }
1137 :
1138 14 : if (bLastBlock)
1139 8 : break;
1140 : }
1141 :
1142 : // Dont' forget to copy the number formats over. Charts may reference them.
1143 34 : for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
1144 : {
1145 22 : sal_uInt32 nNumFmt = GetNumberFormat(nRow);
1146 22 : SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt);
1147 22 : if (itNum != rMap.end())
1148 6 : nNumFmt = itNum->second;
1149 :
1150 22 : rDestCol.SetNumberFormat(nRow, nNumFmt);
1151 : }
1152 :
1153 12 : rDestCol.CellStorageModified();
1154 : }
1155 :
1156 2 : void ScColumn::CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol )
1157 : {
1158 2 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nSrcRow);
1159 2 : sc::CellStoreType::const_iterator it = aPos.first;
1160 2 : bool bSet = true;
1161 2 : switch (it->type)
1162 : {
1163 : case sc::element_type_numeric:
1164 0 : rDestCol.maCells.set(nDestRow, sc::numeric_block::at(*it->data, aPos.second));
1165 0 : break;
1166 : case sc::element_type_string:
1167 2 : rDestCol.maCells.set(nDestRow, sc::string_block::at(*it->data, aPos.second));
1168 2 : break;
1169 : case sc::element_type_edittext:
1170 : {
1171 0 : EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
1172 0 : if (pDocument == rDestCol.pDocument)
1173 0 : rDestCol.maCells.set(nDestRow, p->Clone());
1174 : else
1175 0 : rDestCol.maCells.set(nDestRow, ScEditUtil::Clone(*p, *rDestCol.pDocument));
1176 : }
1177 0 : break;
1178 : case sc::element_type_formula:
1179 : {
1180 0 : ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
1181 0 : if (p->GetDirty() && pDocument->GetAutoCalc())
1182 0 : p->Interpret();
1183 :
1184 0 : ScAddress aDestPos = p->aPos;
1185 0 : aDestPos.SetRow(nDestRow);
1186 0 : ScFormulaCell* pNew = new ScFormulaCell(*p, *rDestCol.pDocument, aDestPos);
1187 0 : rDestCol.SetFormulaCell(nDestRow, pNew);
1188 : }
1189 0 : break;
1190 : case sc::element_type_empty:
1191 : default:
1192 : // empty
1193 0 : rDestCol.maCells.set_empty(nDestRow, nDestRow);
1194 0 : bSet = false;
1195 : }
1196 :
1197 2 : if (bSet)
1198 : {
1199 2 : rDestCol.maCellTextAttrs.set(nDestRow, maCellTextAttrs.get<sc::CellTextAttr>(nSrcRow));
1200 2 : ScPostIt* pNote = maCellNotes.get<ScPostIt*>(nSrcRow);
1201 2 : rDestCol.maCellNotes.set(nDestRow, pNote);
1202 2 : if (pNote)
1203 0 : pNote->UpdateCaptionPos(ScAddress(rDestCol.nCol, nDestRow, rDestCol.nTab));
1204 : }
1205 : else
1206 : {
1207 0 : rDestCol.maCellTextAttrs.set_empty(nDestRow, nDestRow);
1208 0 : rDestCol.maCellNotes.set_empty(nDestRow, nDestRow);
1209 : }
1210 :
1211 2 : rDestCol.CellStorageModified();
1212 2 : }
1213 :
1214 : namespace {
1215 :
1216 2656 : bool canCopyValue(const ScDocument& rDoc, const ScAddress& rPos, InsertDeleteFlags nFlags)
1217 : {
1218 2656 : sal_uInt32 nNumIndex = static_cast<const SfxUInt32Item*>(rDoc.GetAttr(rPos, ATTR_VALUE_FORMAT))->GetValue();
1219 2656 : short nType = rDoc.GetFormatTable()->GetType(nNumIndex);
1220 2656 : if ((nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME))
1221 0 : return ((nFlags & IDF_DATETIME) != IDF_NONE);
1222 :
1223 2656 : return (nFlags & IDF_VALUE) != IDF_NONE;
1224 : }
1225 :
1226 : class CopyAsLinkHandler
1227 : {
1228 : const ScColumn& mrSrcCol;
1229 : ScColumn& mrDestCol;
1230 : sc::ColumnBlockPosition maDestPos;
1231 : sc::ColumnBlockPosition* mpDestPos;
1232 : InsertDeleteFlags mnCopyFlags;
1233 :
1234 0 : void setDefaultAttrToDest(size_t nRow)
1235 : {
1236 0 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1237 0 : maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1238 0 : }
1239 :
1240 0 : void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1241 : {
1242 0 : std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1243 0 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1244 0 : maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1245 0 : }
1246 :
1247 0 : ScFormulaCell* createRefCell(size_t nRow)
1248 : {
1249 : ScSingleRefData aRef;
1250 0 : aRef.InitAddress(ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab())); // Absolute reference.
1251 0 : aRef.SetFlag3D(true);
1252 :
1253 0 : ScTokenArray aArr;
1254 0 : aArr.AddSingleReference(aRef);
1255 0 : return new ScFormulaCell(&mrDestCol.GetDoc(), ScAddress(mrDestCol.GetCol(), nRow, mrDestCol.GetTab()), aArr);
1256 : }
1257 :
1258 0 : void createRefBlock(const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1259 : {
1260 0 : size_t nTopRow = aNode.position + nOffset;
1261 :
1262 0 : for (size_t i = 0; i < nDataSize; ++i)
1263 : {
1264 0 : SCROW nRow = nTopRow + i;
1265 0 : mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow));
1266 : }
1267 :
1268 0 : setDefaultAttrsToDest(nTopRow, nDataSize);
1269 0 : }
1270 :
1271 0 : void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1272 : {
1273 0 : mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1274 0 : }
1275 :
1276 : public:
1277 0 : CopyAsLinkHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, InsertDeleteFlags nCopyFlags) :
1278 0 : mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mnCopyFlags(nCopyFlags)
1279 : {
1280 0 : if (mpDestPos)
1281 0 : maDestPos = *mpDestPos;
1282 0 : }
1283 :
1284 0 : ~CopyAsLinkHandler()
1285 : {
1286 0 : if (mpDestPos)
1287 0 : *mpDestPos = maDestPos;
1288 0 : }
1289 :
1290 0 : void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1291 : {
1292 0 : size_t nRow = aNode.position + nOffset;
1293 :
1294 0 : if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
1295 : {
1296 0 : bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == IDF_NONE;
1297 0 : duplicateNotes(nRow, nDataSize, bCloneCaption );
1298 : }
1299 :
1300 0 : switch (aNode.type)
1301 : {
1302 : case sc::element_type_numeric:
1303 : {
1304 0 : if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == IDF_NONE)
1305 0 : return;
1306 :
1307 0 : sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1308 0 : std::advance(it, nOffset);
1309 0 : sc::numeric_block::const_iterator itEnd = it;
1310 0 : std::advance(itEnd, nDataSize);
1311 :
1312 0 : ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1313 0 : for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1314 : {
1315 0 : if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1316 0 : continue;
1317 :
1318 0 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, createRefCell(nRow));
1319 0 : setDefaultAttrToDest(nRow);
1320 : }
1321 : }
1322 0 : break;
1323 : case sc::element_type_string:
1324 : case sc::element_type_edittext:
1325 : {
1326 0 : if (!(mnCopyFlags & IDF_STRING))
1327 0 : return;
1328 :
1329 0 : createRefBlock(aNode, nOffset, nDataSize);
1330 : }
1331 0 : break;
1332 : case sc::element_type_formula:
1333 : {
1334 0 : if (!(mnCopyFlags & IDF_FORMULA))
1335 0 : return;
1336 :
1337 0 : createRefBlock(aNode, nOffset, nDataSize);
1338 : }
1339 0 : break;
1340 : default:
1341 : ;
1342 : }
1343 : }
1344 : };
1345 :
1346 : class CopyByCloneHandler
1347 : {
1348 : const ScColumn& mrSrcCol;
1349 : ScColumn& mrDestCol;
1350 : sc::ColumnBlockPosition maDestPos;
1351 : sc::ColumnBlockPosition* mpDestPos;
1352 : svl::SharedStringPool* mpSharedStringPool;
1353 : InsertDeleteFlags mnCopyFlags;
1354 :
1355 5272 : void setDefaultAttrToDest(size_t nRow)
1356 : {
1357 10544 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1358 5272 : maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1359 5272 : }
1360 :
1361 8 : void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1362 : {
1363 8 : std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1364 16 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1365 16 : maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1366 8 : }
1367 :
1368 500 : void cloneFormulaCell(size_t nRow, ScFormulaCell& rSrcCell)
1369 : {
1370 500 : ScAddress aDestPos(mrDestCol.GetCol(), nRow, mrDestCol.GetTab());
1371 :
1372 500 : bool bCloneValue = (mnCopyFlags & IDF_VALUE) != IDF_NONE;
1373 500 : bool bCloneDateTime = (mnCopyFlags & IDF_DATETIME) != IDF_NONE;
1374 500 : bool bCloneString = (mnCopyFlags & IDF_STRING) != IDF_NONE;
1375 500 : bool bCloneSpecialBoolean = (mnCopyFlags & IDF_SPECIAL_BOOLEAN) != IDF_NONE;
1376 500 : bool bCloneFormula = (mnCopyFlags & IDF_FORMULA) != IDF_NONE;
1377 :
1378 500 : bool bForceFormula = false;
1379 :
1380 500 : if (bCloneSpecialBoolean)
1381 : {
1382 : // See if the formula consists of =TRUE() or =FALSE().
1383 0 : ScTokenArray* pCode = rSrcCell.GetCode();
1384 0 : if (pCode && pCode->GetLen() == 1)
1385 : {
1386 0 : const formula::FormulaToken* p = pCode->First();
1387 0 : if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
1388 : // This is a boolean formula.
1389 0 : bForceFormula = true;
1390 : }
1391 : }
1392 :
1393 500 : if (bForceFormula || bCloneFormula)
1394 : {
1395 : // Clone as formula cell.
1396 500 : ScFormulaCell* pCell = new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos);
1397 500 : pCell->SetDirtyVar();
1398 500 : mrDestCol.SetFormulaCell(maDestPos, nRow, pCell);
1399 500 : setDefaultAttrToDest(nRow);
1400 1000 : return;
1401 : }
1402 :
1403 0 : if (mrDestCol.GetDoc().IsUndo())
1404 0 : return;
1405 :
1406 0 : if (bCloneValue)
1407 : {
1408 0 : sal_uInt16 nErr = rSrcCell.GetErrCode();
1409 0 : if (nErr)
1410 : {
1411 : // error codes are cloned with values
1412 0 : ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
1413 0 : pErrCell->SetErrCode(nErr);
1414 0 : mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell);
1415 0 : setDefaultAttrToDest(nRow);
1416 0 : return;
1417 : }
1418 : }
1419 :
1420 0 : if (bCloneValue || bCloneDateTime)
1421 : {
1422 0 : if (rSrcCell.IsValue())
1423 : {
1424 0 : if (canCopyValue(mrSrcCol.GetDoc(), ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab()), mnCopyFlags))
1425 : {
1426 0 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1427 0 : maDestPos.miCellPos, nRow, rSrcCell.GetValue());
1428 0 : setDefaultAttrToDest(nRow);
1429 : }
1430 :
1431 0 : return;
1432 : }
1433 : }
1434 :
1435 0 : if (bCloneString)
1436 : {
1437 0 : svl::SharedString aStr = rSrcCell.GetString();
1438 0 : if (aStr.isEmpty())
1439 : // Don't create empty string cells.
1440 0 : return;
1441 :
1442 0 : if (rSrcCell.IsMultilineResult())
1443 : {
1444 : // Clone as an edit text object.
1445 0 : EditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
1446 0 : rEngine.SetText(aStr.getString());
1447 0 : maDestPos.miCellPos =
1448 0 : mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rEngine.CreateTextObject());
1449 : }
1450 : else
1451 : {
1452 0 : maDestPos.miCellPos =
1453 0 : mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aStr);
1454 : }
1455 :
1456 0 : setDefaultAttrToDest(nRow);
1457 : }
1458 : }
1459 :
1460 172544 : void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1461 : {
1462 172544 : mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1463 172544 : }
1464 :
1465 : public:
1466 362890 : CopyByCloneHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos,
1467 : InsertDeleteFlags nCopyFlags, svl::SharedStringPool* pSharedStringPool) :
1468 : mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mpSharedStringPool(pSharedStringPool),
1469 362890 : mnCopyFlags(nCopyFlags)
1470 : {
1471 362890 : if (mpDestPos)
1472 362890 : maDestPos = *mpDestPos;
1473 362890 : }
1474 :
1475 362890 : ~CopyByCloneHandler()
1476 : {
1477 362890 : if (mpDestPos)
1478 362890 : *mpDestPos = maDestPos;
1479 362890 : }
1480 :
1481 366696 : void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1482 : {
1483 366696 : size_t nRow = aNode.position + nOffset;
1484 :
1485 366696 : if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
1486 : {
1487 172544 : bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == IDF_NONE;
1488 172544 : duplicateNotes(nRow, nDataSize, bCloneCaption );
1489 : }
1490 :
1491 366696 : switch (aNode.type)
1492 : {
1493 : case sc::element_type_numeric:
1494 : {
1495 1728 : if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == IDF_NONE)
1496 296 : return;
1497 :
1498 1432 : sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1499 1432 : std::advance(it, nOffset);
1500 1432 : sc::numeric_block::const_iterator itEnd = it;
1501 1432 : std::advance(itEnd, nDataSize);
1502 :
1503 1432 : ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1504 4088 : for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1505 : {
1506 2656 : if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1507 0 : continue;
1508 :
1509 2656 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, *it);
1510 2656 : setDefaultAttrToDest(nRow);
1511 : }
1512 : }
1513 1432 : break;
1514 : case sc::element_type_string:
1515 : {
1516 1152 : if (!(mnCopyFlags & IDF_STRING))
1517 204 : return;
1518 :
1519 948 : sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
1520 948 : std::advance(it, nOffset);
1521 948 : sc::string_block::const_iterator itEnd = it;
1522 948 : std::advance(itEnd, nDataSize);
1523 :
1524 3064 : for (; it != itEnd; ++it, ++nRow)
1525 : {
1526 2116 : const svl::SharedString& rStr = *it;
1527 2116 : if (rStr.isEmpty())
1528 : {
1529 : // String cell with empty value is used to special-case cell value removal.
1530 0 : maDestPos.miCellPos = mrDestCol.GetCellStore().set_empty(
1531 0 : maDestPos.miCellPos, nRow, nRow);
1532 0 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set_empty(
1533 0 : maDestPos.miCellTextAttrPos, nRow, nRow);
1534 : }
1535 : else
1536 : {
1537 2116 : if (mpSharedStringPool)
1538 : {
1539 : // Re-intern the string if source is a different document.
1540 104 : svl::SharedString aInterned = mpSharedStringPool->intern( rStr.getString());
1541 312 : maDestPos.miCellPos =
1542 312 : mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aInterned);
1543 : }
1544 : else
1545 : {
1546 6036 : maDestPos.miCellPos =
1547 4024 : mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rStr);
1548 : }
1549 2116 : setDefaultAttrToDest(nRow);
1550 : }
1551 : }
1552 : }
1553 948 : break;
1554 : case sc::element_type_edittext:
1555 : {
1556 8 : if (!(mnCopyFlags & IDF_STRING))
1557 0 : return;
1558 :
1559 8 : sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
1560 8 : std::advance(it, nOffset);
1561 8 : sc::edittext_block::const_iterator itEnd = it;
1562 8 : std::advance(itEnd, nDataSize);
1563 :
1564 8 : std::vector<EditTextObject*> aCloned;
1565 8 : aCloned.reserve(nDataSize);
1566 24 : for (; it != itEnd; ++it)
1567 16 : aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
1568 :
1569 16 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1570 8 : maDestPos.miCellPos, nRow, aCloned.begin(), aCloned.end());
1571 :
1572 8 : setDefaultAttrsToDest(nRow, nDataSize);
1573 : }
1574 8 : break;
1575 : case sc::element_type_formula:
1576 : {
1577 304 : sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
1578 304 : std::advance(it, nOffset);
1579 304 : sc::formula_block::const_iterator itEnd = it;
1580 304 : std::advance(itEnd, nDataSize);
1581 :
1582 804 : for (; it != itEnd; ++it, ++nRow)
1583 500 : cloneFormulaCell(nRow, const_cast<ScFormulaCell&>(**it));
1584 : }
1585 304 : break;
1586 : default:
1587 : ;
1588 : }
1589 : }
1590 : };
1591 :
1592 : }
1593 :
1594 368958 : void ScColumn::CopyToColumn(
1595 : sc::CopyToDocContext& rCxt,
1596 : SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked, ScColumn& rColumn,
1597 : const ScMarkData* pMarkData, bool bAsLink) const
1598 : {
1599 368958 : if (bMarked)
1600 : {
1601 : SCROW nStart, nEnd;
1602 2924 : if (pMarkData && pMarkData->IsMultiMarked())
1603 : {
1604 2924 : ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
1605 :
1606 6752 : while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
1607 : {
1608 904 : if ( nEnd >= nRow1 )
1609 1808 : CopyToColumn(rCxt, std::max(nRow1,nStart), std::min(nRow2,nEnd),
1610 2712 : nFlags, false, rColumn, pMarkData, bAsLink );
1611 2924 : }
1612 : }
1613 : else
1614 : {
1615 : OSL_FAIL("CopyToColumn: bMarked, but no mark");
1616 : }
1617 371882 : return;
1618 : }
1619 :
1620 366034 : if ( (nFlags & IDF_ATTRIB) != IDF_NONE )
1621 : {
1622 180930 : if ( (nFlags & IDF_STYLES) != IDF_STYLES )
1623 : { // keep the StyleSheets in the target document
1624 : // e.g. DIF and RTF Clipboard-Import
1625 0 : for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
1626 : {
1627 : const ScStyleSheet* pStyle =
1628 0 : rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
1629 0 : const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
1630 0 : boost::scoped_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pPattern ));
1631 0 : pNewPattern->SetStyleSheet( (ScStyleSheet*)pStyle );
1632 0 : rColumn.pAttrArray->SetPattern( nRow, pNewPattern.get(), true );
1633 0 : }
1634 : }
1635 : else
1636 180930 : pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
1637 : }
1638 :
1639 366034 : if ((nFlags & IDF_CONTENTS) != IDF_NONE)
1640 : {
1641 362890 : if (bAsLink)
1642 : {
1643 0 : CopyAsLinkHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags);
1644 0 : sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1645 : }
1646 : else
1647 : {
1648 : // Compare the ScDocumentPool* to determine if we are copying
1649 : // within the same document. If not, re-intern shared strings.
1650 : svl::SharedStringPool* pSharedStringPool =
1651 362890 : (pDocument->GetPool() != rColumn.pDocument->GetPool()) ?
1652 362890 : &rColumn.pDocument->GetSharedStringPool() : NULL;
1653 : CopyByCloneHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags,
1654 362890 : pSharedStringPool);
1655 362890 : sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1656 : }
1657 :
1658 362890 : rColumn.CellStorageModified();
1659 : }
1660 : }
1661 :
1662 32 : void ScColumn::UndoToColumn(
1663 : sc::CopyToDocContext& rCxt, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked,
1664 : ScColumn& rColumn, const ScMarkData* pMarkData ) const
1665 : {
1666 32 : if (nRow1 > 0)
1667 14 : CopyToColumn(rCxt, 0, nRow1-1, IDF_FORMULA, false, rColumn);
1668 :
1669 32 : CopyToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData); //! bMarked ????
1670 :
1671 32 : if (nRow2 < MAXROW)
1672 32 : CopyToColumn(rCxt, nRow2+1, MAXROW, IDF_FORMULA, false, rColumn);
1673 32 : }
1674 :
1675 0 : void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
1676 : {
1677 : // Copy cells from this column to the destination column only for those
1678 : // rows that are present in the position column (rPosCol).
1679 :
1680 : // First, mark all the non-empty cell ranges from the position column.
1681 0 : sc::SingleColumnSpanSet aRangeSet;
1682 0 : aRangeSet.scan(rPosCol);
1683 :
1684 : // Now, copy cells from this column to the destination column for those
1685 : // marked row ranges.
1686 0 : sc::SingleColumnSpanSet::SpansType aRanges;
1687 0 : aRangeSet.getSpans(aRanges);
1688 :
1689 0 : bool bCopyNotes = true;
1690 0 : CopyToClipHandler aFunc(*this, rDestCol, NULL, bCopyNotes);
1691 0 : sc::CellStoreType::const_iterator itPos = maCells.begin();
1692 0 : sc::SingleColumnSpanSet::SpansType::const_iterator it = aRanges.begin(), itEnd = aRanges.end();
1693 0 : for (; it != itEnd; ++it)
1694 0 : itPos = sc::ParseBlock(itPos, maCells, aFunc, it->mnRow1, it->mnRow2);
1695 :
1696 0 : rDestCol.CellStorageModified();
1697 0 : }
1698 :
1699 0 : void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
1700 : {
1701 : // This is the scenario table, the data is copied into it
1702 0 : ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1703 0 : SCROW nStart = -1, nEnd = -1;
1704 0 : const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1705 0 : while (pPattern)
1706 : {
1707 0 : if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1708 : {
1709 0 : DeleteArea( nStart, nEnd, IDF_CONTENTS );
1710 0 : sc::CopyToDocContext aCxt(*pDocument);
1711 : ((ScColumn&)rSrcCol).
1712 0 : CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, *this);
1713 :
1714 : // UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
1715 :
1716 0 : sc::RefUpdateContext aRefCxt(*pDocument);
1717 0 : aRefCxt.meMode = URM_COPY;
1718 0 : aRefCxt.maRange = ScRange(nCol, nStart, nTab, nCol, nEnd, nTab);
1719 0 : aRefCxt.mnTabDelta = nTab - rSrcCol.nTab;
1720 0 : UpdateReferenceOnCopy(aRefCxt, NULL);
1721 0 : UpdateCompile();
1722 : }
1723 :
1724 : //! make CopyToColumn "const" !!! (obsolete comment ?)
1725 :
1726 0 : pPattern = aAttrIter.Next( nStart, nEnd );
1727 : }
1728 0 : }
1729 :
1730 0 : void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
1731 : {
1732 : // This is the scenario table, the data is copied to the other
1733 0 : ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1734 0 : SCROW nStart = -1, nEnd = -1;
1735 0 : const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1736 0 : while (pPattern)
1737 : {
1738 0 : if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1739 : {
1740 0 : rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
1741 0 : sc::CopyToDocContext aCxt(*rDestCol.pDocument);
1742 0 : CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, rDestCol);
1743 :
1744 : // UpdateUsed not needed, is already done in TestCopyScenario (obsolete comment ?)
1745 :
1746 0 : sc::RefUpdateContext aRefCxt(*pDocument);
1747 0 : aRefCxt.meMode = URM_COPY;
1748 0 : aRefCxt.maRange = ScRange(rDestCol.nCol, nStart, rDestCol.nTab, rDestCol.nCol, nEnd, rDestCol.nTab);
1749 0 : aRefCxt.mnTabDelta = rDestCol.nTab - nTab;
1750 0 : rDestCol.UpdateReferenceOnCopy(aRefCxt, NULL);
1751 0 : rDestCol.UpdateCompile();
1752 : }
1753 :
1754 : //! make CopyToColumn "const" !!! (obsolete comment ?)
1755 :
1756 0 : pPattern = aAttrIter.Next( nStart, nEnd );
1757 : }
1758 0 : }
1759 :
1760 0 : bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
1761 : {
1762 0 : bool bOk = true;
1763 0 : ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1764 0 : SCROW nStart = 0, nEnd = 0;
1765 0 : const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1766 0 : while (pPattern && bOk)
1767 : {
1768 0 : if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1769 0 : if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) )
1770 0 : bOk = false;
1771 :
1772 0 : pPattern = aAttrIter.Next( nStart, nEnd );
1773 : }
1774 0 : return bOk;
1775 : }
1776 :
1777 2048 : void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
1778 : {
1779 2048 : ScRange aRange( nCol, 0, nTab );
1780 :
1781 2048 : ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1782 2048 : SCROW nStart = -1, nEnd = -1;
1783 2048 : const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1784 6172 : while (pPattern)
1785 : {
1786 2076 : if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1787 : {
1788 28 : aRange.aStart.SetRow( nStart );
1789 28 : aRange.aEnd.SetRow( nEnd );
1790 28 : rDestMark.SetMultiMarkArea( aRange, true );
1791 : }
1792 :
1793 2076 : pPattern = aAttrIter.Next( nStart, nEnd );
1794 : }
1795 2048 : }
1796 :
1797 : namespace {
1798 :
1799 318508 : void resetColumnPosition(sc::CellStoreType& rCells, SCCOL nCol)
1800 : {
1801 318508 : sc::CellStoreType::iterator it = rCells.begin(), itEnd = rCells.end();
1802 637348 : for (; it != itEnd; ++it)
1803 : {
1804 318840 : if (it->type != sc::element_type_formula)
1805 318742 : continue;
1806 :
1807 98 : sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
1808 98 : sc::formula_block::iterator itCellEnd = sc::formula_block::end(*it->data);
1809 230 : for (; itCell != itCellEnd; ++itCell)
1810 : {
1811 132 : ScFormulaCell& rCell = **itCell;
1812 132 : rCell.aPos.SetCol(nCol);
1813 : }
1814 : }
1815 318508 : }
1816 :
1817 : class NoteCaptionUpdater
1818 : {
1819 : SCCOL mnCol;
1820 : SCTAB mnTab;
1821 : public:
1822 347210 : NoteCaptionUpdater( SCCOL nCol, SCTAB nTab ) : mnCol(nCol), mnTab(nTab) {}
1823 :
1824 6 : void operator() ( size_t nRow, ScPostIt* p )
1825 : {
1826 6 : p->UpdateCaptionPos(ScAddress(mnCol,nRow,mnTab));
1827 6 : }
1828 : };
1829 :
1830 : }
1831 :
1832 347210 : void ScColumn::UpdateNoteCaptions( SCROW nRow1, SCROW nRow2 )
1833 : {
1834 347210 : NoteCaptionUpdater aFunc(nCol, nTab);
1835 347210 : sc::ProcessNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
1836 347210 : }
1837 :
1838 159254 : void ScColumn::SwapCol(ScColumn& rCol)
1839 : {
1840 159254 : maBroadcasters.swap(rCol.maBroadcasters);
1841 159254 : maCells.swap(rCol.maCells);
1842 159254 : maCellTextAttrs.swap(rCol.maCellTextAttrs);
1843 159254 : maCellNotes.swap(rCol.maCellNotes);
1844 :
1845 : // notes update caption
1846 159254 : UpdateNoteCaptions(0, MAXROW);
1847 159254 : rCol.UpdateNoteCaptions(0, MAXROW);
1848 :
1849 159254 : ScAttrArray* pTempAttr = rCol.pAttrArray;
1850 159254 : rCol.pAttrArray = pAttrArray;
1851 159254 : pAttrArray = pTempAttr;
1852 :
1853 : // AttrArray needs to have the right column number
1854 159254 : pAttrArray->SetCol(nCol);
1855 159254 : rCol.pAttrArray->SetCol(rCol.nCol);
1856 :
1857 159254 : std::swap(mbDirtyGroups, rCol.mbDirtyGroups);
1858 :
1859 : // Reset column positions in formula cells.
1860 159254 : resetColumnPosition(maCells, nCol);
1861 159254 : resetColumnPosition(rCol.maCells, rCol.nCol);
1862 :
1863 159254 : CellStorageModified();
1864 159254 : rCol.CellStorageModified();
1865 159254 : }
1866 :
1867 26488 : void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
1868 : {
1869 26488 : pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
1870 :
1871 : // Mark the non-empty cells within the specified range, for later broadcasting.
1872 26488 : sc::SingleColumnSpanSet aNonEmpties;
1873 26488 : aNonEmpties.scan(*this, nStartRow, nEndRow);
1874 52976 : sc::SingleColumnSpanSet::SpansType aRanges;
1875 26488 : aNonEmpties.getSpans(aRanges);
1876 :
1877 : // Split the formula grouping at the top and bottom boundaries.
1878 26488 : sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
1879 26488 : sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
1880 26488 : aPos = maCells.position(aPos.first, nEndRow+1);
1881 26488 : sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
1882 :
1883 : // Do the same with the destination column.
1884 26488 : aPos = rCol.maCells.position(nStartRow);
1885 26488 : sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
1886 26488 : aPos = rCol.maCells.position(aPos.first, nEndRow+1);
1887 26488 : sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
1888 :
1889 : // Move the broadcasters to the destination column.
1890 26488 : maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow);
1891 26488 : maCells.transfer(nStartRow, nEndRow, rCol.maCells, nStartRow);
1892 26488 : maCellTextAttrs.transfer(nStartRow, nEndRow, rCol.maCellTextAttrs, nStartRow);
1893 :
1894 : // move the notes to the destination column
1895 26488 : maCellNotes.transfer(nStartRow, nEndRow, rCol.maCellNotes, nStartRow);
1896 26488 : UpdateNoteCaptions(0, MAXROW);
1897 :
1898 : // Re-group transferred formula cells.
1899 26488 : aPos = rCol.maCells.position(nStartRow);
1900 26488 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1901 26488 : aPos = rCol.maCells.position(aPos.first, nEndRow+1);
1902 26488 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1903 :
1904 26488 : CellStorageModified();
1905 26488 : rCol.CellStorageModified();
1906 :
1907 : // Broadcast on moved ranges. Area-broadcast only.
1908 52976 : ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
1909 26488 : ScAddress& rPos = aHint.GetAddress();
1910 26488 : sc::SingleColumnSpanSet::SpansType::const_iterator itRange = aRanges.begin(), itRangeEnd = aRanges.end();
1911 26510 : for (; itRange != itRangeEnd; ++itRange)
1912 : {
1913 48 : for (SCROW nRow = itRange->mnRow1; nRow <= itRange->mnRow2; ++nRow)
1914 : {
1915 26 : rPos.SetRow(nRow);
1916 26 : pDocument->AreaBroadcast(aHint);
1917 : }
1918 26488 : }
1919 26488 : }
1920 :
1921 : namespace {
1922 :
1923 : class SubTotalCellPicker
1924 : {
1925 : sc::ColumnSpanSet& mrSet;
1926 : SCTAB mnTab;
1927 : SCCOL mnCol;
1928 : bool mbVal;
1929 : public:
1930 0 : SubTotalCellPicker(sc::ColumnSpanSet& rSet, SCTAB nTab, SCCOL nCol, bool bVal) :
1931 0 : mrSet(rSet), mnTab(nTab), mnCol(nCol), mbVal(bVal) {}
1932 :
1933 0 : void operator() (size_t nRow, const ScFormulaCell* pCell)
1934 : {
1935 0 : if (pCell->IsSubTotal())
1936 0 : mrSet.set(mnTab, mnCol, nRow, mbVal);
1937 0 : }
1938 : };
1939 :
1940 : }
1941 :
1942 0 : void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nRow2, bool bVal ) const
1943 : {
1944 0 : SubTotalCellPicker aFunc(rSet, nTab, nCol, bVal);
1945 0 : sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1946 0 : }
1947 :
1948 : namespace {
1949 :
1950 667502 : class SharedTopFormulaCellPicker : std::unary_function<sc::CellStoreType::value_type, void>
1951 : {
1952 : public:
1953 667502 : virtual ~SharedTopFormulaCellPicker() {}
1954 :
1955 337992 : void operator() ( sc::CellStoreType::value_type& node )
1956 : {
1957 337992 : if (node.type != sc::element_type_formula)
1958 675280 : return;
1959 :
1960 704 : size_t nTopRow = node.position;
1961 :
1962 704 : sc::formula_block::iterator itBeg = sc::formula_block::begin(*node.data);
1963 704 : sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
1964 :
1965 : // Only pick shared formula cells that are the top cells of their
1966 : // respective shared ranges.
1967 1724 : for (sc::formula_block::iterator it = itBeg; it != itEnd; ++it)
1968 : {
1969 1020 : ScFormulaCell* pCell = *it;
1970 1020 : size_t nRow = nTopRow + std::distance(itBeg, it);
1971 1020 : if (!pCell->IsShared())
1972 : {
1973 816 : processNonShared(pCell, nRow);
1974 816 : continue;
1975 : }
1976 :
1977 204 : if (pCell->IsSharedTop())
1978 : {
1979 204 : ScFormulaCell** pp = &(*it);
1980 204 : processSharedTop(pp, nRow, pCell->GetSharedLength());
1981 :
1982 : // Move to the last cell in the group, to get incremented to
1983 : // the next cell in the next iteration.
1984 204 : size_t nOffsetToLast = pCell->GetSharedLength() - 1;
1985 204 : std::advance(it, nOffsetToLast);
1986 : }
1987 : }
1988 : }
1989 :
1990 374 : virtual void processNonShared( ScFormulaCell* /*pCell*/, size_t /*nRow*/ ) {}
1991 0 : virtual void processSharedTop( ScFormulaCell** /*ppCells*/, size_t /*nRow*/, size_t /*nLength*/ ) {}
1992 : };
1993 :
1994 : class UpdateRefOnCopy
1995 : {
1996 : const sc::RefUpdateContext& mrCxt;
1997 : ScDocument* mpUndoDoc;
1998 : bool mbUpdated;
1999 :
2000 : public:
2001 35038 : UpdateRefOnCopy(const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc) :
2002 35038 : mrCxt(rCxt), mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2003 :
2004 35038 : bool isUpdated() const { return mbUpdated; }
2005 :
2006 35478 : void operator() (sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2007 : {
2008 35478 : if (node.type != sc::element_type_formula)
2009 70836 : return;
2010 :
2011 120 : sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
2012 120 : std::advance(it, nOffset);
2013 120 : sc::formula_block::iterator itEnd = it;
2014 120 : std::advance(itEnd, nDataSize);
2015 :
2016 276 : for (; it != itEnd; ++it)
2017 : {
2018 156 : ScFormulaCell& rCell = **it;
2019 156 : mbUpdated |= rCell.UpdateReference(mrCxt, mpUndoDoc);
2020 : }
2021 : }
2022 : };
2023 :
2024 : class UpdateRefOnNonCopy : std::unary_function<sc::FormulaGroupEntry, void>
2025 : {
2026 : SCCOL mnCol;
2027 : SCROW mnTab;
2028 : const sc::RefUpdateContext* mpCxt;
2029 : ScDocument* mpUndoDoc;
2030 : bool mbUpdated;
2031 :
2032 4 : void recompileTokenArray( ScFormulaCell& rTopCell )
2033 : {
2034 : // We need to re-compile the token array when a range name is
2035 : // modified, to correctly reflect the new references in the
2036 : // name.
2037 4 : ScCompiler aComp(&mpCxt->mrDoc, rTopCell.aPos, *rTopCell.GetCode());
2038 4 : aComp.SetGrammar(mpCxt->mrDoc.GetGrammar());
2039 4 : aComp.CompileTokenArray();
2040 4 : }
2041 :
2042 432 : void updateRefOnShift( sc::FormulaGroupEntry& rGroup )
2043 : {
2044 432 : if (!rGroup.mbShared)
2045 : {
2046 348 : ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2047 348 : mbUpdated |= rGroup.mpCell->UpdateReferenceOnShift(*mpCxt, mpUndoDoc, &aUndoPos);
2048 780 : return;
2049 : }
2050 :
2051 : // Update references of a formula group.
2052 84 : ScFormulaCell** pp = rGroup.mpCells;
2053 84 : ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2054 84 : ScFormulaCell* pTop = *pp;
2055 84 : ScTokenArray* pCode = pTop->GetCode();
2056 84 : boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
2057 84 : ScAddress aOldPos = pTop->aPos;
2058 :
2059 : // Run this before the position gets updated.
2060 84 : sc::RefUpdateResult aRes = pCode->AdjustReferenceOnShift(*mpCxt, aOldPos);
2061 :
2062 84 : if (pTop->UpdatePosOnShift(*mpCxt))
2063 : {
2064 : // Update the positions of all formula cells.
2065 132 : for (++pp; pp != ppEnd; ++pp) // skip the top cell.
2066 : {
2067 88 : ScFormulaCell* pFC = *pp;
2068 88 : pFC->aPos.Move(mpCxt->mnColDelta, mpCxt->mnRowDelta, mpCxt->mnTabDelta);
2069 : }
2070 :
2071 44 : if (pCode->IsRecalcModeOnRefMove())
2072 0 : aRes.mbValueChanged = true;
2073 : }
2074 40 : else if (aRes.mbReferenceModified && pCode->IsRecalcModeOnRefMove())
2075 : {
2076 : // The cell itself hasn't shifted. But it may have ROW or COLUMN
2077 : // referencing another cell that has.
2078 2 : aRes.mbValueChanged = true;
2079 : }
2080 :
2081 84 : if (aRes.mbNameModified)
2082 2 : recompileTokenArray(*pTop);
2083 :
2084 84 : if (aRes.mbReferenceModified || aRes.mbNameModified)
2085 : {
2086 48 : sc::StartListeningContext aStartCxt(mpCxt->mrDoc);
2087 96 : sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get());
2088 : aEndCxt.setPositionDelta(
2089 48 : ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
2090 :
2091 188 : for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
2092 : {
2093 140 : ScFormulaCell* p = *pp;
2094 140 : p->EndListeningTo(aEndCxt);
2095 140 : p->SetNeedsListening(true);
2096 : }
2097 :
2098 48 : mbUpdated = true;
2099 :
2100 96 : fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
2101 : }
2102 :
2103 84 : if (aRes.mbValueChanged)
2104 : {
2105 60 : for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
2106 : {
2107 40 : ScFormulaCell* p = *pp;
2108 40 : p->SetNeedsDirty(true);
2109 : }
2110 84 : }
2111 : }
2112 :
2113 68 : void updateRefOnMove( sc::FormulaGroupEntry& rGroup )
2114 : {
2115 68 : if (!rGroup.mbShared)
2116 : {
2117 58 : ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2118 58 : mbUpdated |= rGroup.mpCell->UpdateReferenceOnMove(*mpCxt, mpUndoDoc, &aUndoPos);
2119 126 : return;
2120 : }
2121 :
2122 : // Update references of a formula group.
2123 10 : ScFormulaCell** pp = rGroup.mpCells;
2124 10 : ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2125 10 : ScFormulaCell* pTop = *pp;
2126 10 : ScTokenArray* pCode = pTop->GetCode();
2127 10 : boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
2128 :
2129 10 : ScAddress aPos = pTop->aPos;
2130 10 : ScAddress aOldPos = aPos;
2131 :
2132 10 : if (mpCxt->maRange.In(aPos))
2133 : {
2134 : // The cell is being moved or copied to a new position. The
2135 : // position has already been updated prior to this call.
2136 : // Determine its original position before the move which will be
2137 : // used to adjust relative references later.
2138 :
2139 : aOldPos.Set(
2140 0 : aPos.Col() - mpCxt->mnColDelta,
2141 0 : aPos.Row() - mpCxt->mnRowDelta,
2142 0 : aPos.Tab() - mpCxt->mnTabDelta);
2143 : }
2144 :
2145 10 : bool bRecalcOnMove = pCode->IsRecalcModeOnRefMove();
2146 10 : if (bRecalcOnMove)
2147 0 : bRecalcOnMove = aPos != aOldPos;
2148 :
2149 10 : sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(*mpCxt, aOldPos, aPos);
2150 :
2151 10 : if (aRes.mbReferenceModified || aRes.mbNameModified || bRecalcOnMove)
2152 : {
2153 8 : sc::AutoCalcSwitch(mpCxt->mrDoc, false);
2154 :
2155 8 : if (aRes.mbNameModified)
2156 2 : recompileTokenArray(*pTop);
2157 :
2158 : // Perform end-listening, start-listening, and dirtying on all
2159 : // formula cells in the group.
2160 :
2161 : // Make sure that the start and end listening contexts share the
2162 : // same block position set, else an invalid iterator may ensue.
2163 : boost::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(
2164 8 : new sc::ColumnBlockPositionSet(mpCxt->mrDoc));
2165 :
2166 16 : sc::StartListeningContext aStartCxt(mpCxt->mrDoc, pPosSet);
2167 16 : sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pPosSet, pOldCode.get());
2168 :
2169 : aEndCxt.setPositionDelta(
2170 8 : ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
2171 :
2172 26 : for (; pp != ppEnd; ++pp)
2173 : {
2174 18 : ScFormulaCell* p = *pp;
2175 18 : p->EndListeningTo(aEndCxt);
2176 18 : p->StartListeningTo(aStartCxt);
2177 18 : p->SetDirty();
2178 : }
2179 :
2180 16 : fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
2181 10 : }
2182 : }
2183 :
2184 56 : void fillUndoDoc( const ScAddress& rOldPos, SCROW nLength, const ScTokenArray& rOldCode )
2185 : {
2186 56 : if (!mpUndoDoc || nLength <= 0)
2187 100 : return;
2188 :
2189 : // Insert the old formula group into the undo document.
2190 6 : ScAddress aUndoPos = rOldPos;
2191 6 : ScFormulaCell* pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, rOldCode.Clone());
2192 :
2193 6 : if (nLength == 1)
2194 : {
2195 0 : mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
2196 0 : return;
2197 : }
2198 :
2199 6 : std::vector<ScFormulaCell*> aCells;
2200 6 : aCells.reserve(nLength);
2201 12 : ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(nLength, false);
2202 6 : aCells.push_back(pFC);
2203 6 : aUndoPos.IncRow();
2204 12 : for (SCROW i = 1; i < nLength; ++i, aUndoPos.IncRow())
2205 : {
2206 6 : pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, xGroup);
2207 6 : aCells.push_back(pFC);
2208 : }
2209 :
2210 6 : if (!mpUndoDoc->SetFormulaCells(rOldPos, aCells))
2211 : // Insertion failed. Delete all formula cells.
2212 6 : std::for_each(aCells.begin(), aCells.end(), boost::checked_deleter<ScFormulaCell>());
2213 : }
2214 :
2215 : public:
2216 790 : UpdateRefOnNonCopy(
2217 : SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext* pCxt,
2218 : ScDocument* pUndoDoc) :
2219 : mnCol(nCol), mnTab(nTab), mpCxt(pCxt),
2220 790 : mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2221 :
2222 500 : void operator() ( sc::FormulaGroupEntry& rGroup )
2223 : {
2224 500 : switch (mpCxt->meMode)
2225 : {
2226 : case URM_INSDEL:
2227 432 : updateRefOnShift(rGroup);
2228 432 : return;
2229 : case URM_MOVE:
2230 68 : updateRefOnMove(rGroup);
2231 68 : return;
2232 : default:
2233 : ;
2234 : }
2235 :
2236 0 : if (rGroup.mbShared)
2237 : {
2238 0 : ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2239 0 : ScFormulaCell** pp = rGroup.mpCells;
2240 0 : ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2241 0 : for (; pp != ppEnd; ++pp, aUndoPos.IncRow())
2242 : {
2243 0 : ScFormulaCell* p = *pp;
2244 0 : mbUpdated |= p->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
2245 : }
2246 : }
2247 : else
2248 : {
2249 0 : ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2250 0 : mbUpdated |= rGroup.mpCell->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
2251 : }
2252 : }
2253 :
2254 1580 : bool isUpdated() const { return mbUpdated; }
2255 : };
2256 :
2257 1580 : class UpdateRefGroupBoundChecker : public SharedTopFormulaCellPicker
2258 : {
2259 : const sc::RefUpdateContext& mrCxt;
2260 : std::vector<SCROW>& mrBounds;
2261 :
2262 : public:
2263 790 : UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
2264 790 : mrCxt(rCxt), mrBounds(rBounds) {}
2265 :
2266 2370 : virtual ~UpdateRefGroupBoundChecker() {}
2267 :
2268 90 : virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) SAL_OVERRIDE
2269 : {
2270 : // Check its tokens and record its reference boundaries.
2271 90 : ScFormulaCell& rCell = **ppCells;
2272 90 : const ScTokenArray& rCode = *rCell.GetCode();
2273 : rCode.CheckRelativeReferenceBounds(
2274 90 : mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
2275 90 : }
2276 : };
2277 :
2278 332566 : class FormulaGroupPicker : public SharedTopFormulaCellPicker
2279 : {
2280 : std::vector<sc::FormulaGroupEntry>& mrGroups;
2281 :
2282 : public:
2283 332566 : FormulaGroupPicker( std::vector<sc::FormulaGroupEntry>& rGroups ) : mrGroups(rGroups) {}
2284 :
2285 665132 : virtual ~FormulaGroupPicker() {}
2286 :
2287 442 : virtual void processNonShared( ScFormulaCell* pCell, size_t nRow ) SAL_OVERRIDE
2288 : {
2289 442 : mrGroups.push_back(sc::FormulaGroupEntry(pCell, nRow));
2290 442 : }
2291 :
2292 114 : virtual void processSharedTop( ScFormulaCell** ppCells, size_t nRow, size_t nLength ) SAL_OVERRIDE
2293 : {
2294 114 : mrGroups.push_back(sc::FormulaGroupEntry(ppCells, nRow, nLength));
2295 114 : }
2296 : };
2297 :
2298 : }
2299 :
2300 35038 : bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
2301 : {
2302 : // When copying, the range equals the destination range where cells
2303 : // are pasted, and the dx, dy, dz refer to the distance from the
2304 : // source range.
2305 :
2306 35038 : UpdateRefOnCopy aHandler(rCxt, pUndoDoc);
2307 35038 : sc::CellStoreType::position_type aPos = maCells.position(rCxt.maRange.aStart.Row());
2308 35038 : sc::ProcessBlock(aPos.first, maCells, aHandler, rCxt.maRange.aStart.Row(), rCxt.maRange.aEnd.Row());
2309 :
2310 : // The formula groups at the top and bottom boundaries are expected to
2311 : // have been split prior to this call. Here, we only do the joining.
2312 35038 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2313 35038 : if (rCxt.maRange.aEnd.Row() < MAXROW)
2314 : {
2315 222 : aPos = maCells.position(aPos.first, rCxt.maRange.aEnd.Row()+1);
2316 222 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2317 : }
2318 :
2319 35038 : return aHandler.isUpdated();
2320 : }
2321 :
2322 432350 : bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
2323 : {
2324 432350 : if (rCxt.meMode == URM_COPY)
2325 35038 : return UpdateReferenceOnCopy(rCxt, pUndoDoc);
2326 :
2327 397312 : if (IsEmptyData() || pDocument->IsClipOrUndo())
2328 : // Cells in this column are all empty, or clip or undo doc. No update needed.
2329 396522 : return false;
2330 :
2331 790 : std::vector<SCROW> aBounds;
2332 :
2333 2334 : bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
2334 2078 : rCxt.maRange.aStart.Col() <= nCol && nCol <= rCxt.maRange.aEnd.Col());
2335 790 : if (bThisColShifted)
2336 : {
2337 : // Cells in this column is being shifted. Split formula grouping at
2338 : // the top and bottom boundaries before they get shifted.
2339 : // Also, for deleted rows split at the top of the deleted area to adapt
2340 : // the affected group length.
2341 : SCROW nSplitPos;
2342 480 : if (rCxt.mnRowDelta < 0)
2343 : {
2344 116 : nSplitPos = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
2345 116 : if (ValidRow(nSplitPos))
2346 114 : aBounds.push_back(nSplitPos);
2347 : }
2348 480 : nSplitPos = rCxt.maRange.aStart.Row();
2349 480 : if (ValidRow(nSplitPos))
2350 : {
2351 480 : aBounds.push_back(nSplitPos);
2352 480 : nSplitPos = rCxt.maRange.aEnd.Row() + 1;
2353 480 : if (ValidRow(nSplitPos))
2354 94 : aBounds.push_back(nSplitPos);
2355 : }
2356 : }
2357 :
2358 : // Check the row positions at which the group must be split per relative
2359 : // references.
2360 1580 : UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
2361 790 : std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
2362 :
2363 : // Do the actual splitting.
2364 790 : sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
2365 :
2366 : // Collect all formula groups.
2367 1580 : std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
2368 :
2369 : // Process all collected formula groups.
2370 790 : UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc);
2371 790 : aHandler = std::for_each(aGroups.begin(), aGroups.end(), aHandler);
2372 790 : if (aHandler.isUpdated())
2373 232 : rCxt.maRegroupCols.set(nTab, nCol);
2374 :
2375 1580 : return aHandler.isUpdated();
2376 : }
2377 :
2378 332566 : std::vector<sc::FormulaGroupEntry> ScColumn::GetFormulaGroupEntries()
2379 : {
2380 332566 : std::vector<sc::FormulaGroupEntry> aGroups;
2381 332566 : std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups));
2382 332566 : return aGroups;
2383 : }
2384 :
2385 : namespace {
2386 :
2387 : class UpdateTransHandler
2388 : {
2389 : ScColumn& mrColumn;
2390 : sc::CellStoreType::iterator miPos;
2391 : ScRange maSource;
2392 : ScAddress maDest;
2393 : ScDocument* mpUndoDoc;
2394 : public:
2395 0 : UpdateTransHandler(ScColumn& rColumn, const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc) :
2396 : mrColumn(rColumn),
2397 0 : miPos(rColumn.GetCellStore().begin()),
2398 0 : maSource(rSource), maDest(rDest), mpUndoDoc(pUndoDoc) {}
2399 :
2400 0 : void operator() (size_t nRow, ScFormulaCell* pCell)
2401 : {
2402 0 : sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2403 0 : miPos = aPos.first;
2404 0 : sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2405 0 : pCell->UpdateTranspose(maSource, maDest, mpUndoDoc);
2406 0 : mrColumn.JoinNewFormulaCell(aPos, *pCell);
2407 0 : }
2408 : };
2409 :
2410 : class UpdateGrowHandler
2411 : {
2412 : ScColumn& mrColumn;
2413 : sc::CellStoreType::iterator miPos;
2414 : ScRange maArea;
2415 : SCCOL mnGrowX;
2416 : SCROW mnGrowY;
2417 : public:
2418 0 : UpdateGrowHandler(ScColumn& rColumn, const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) :
2419 : mrColumn(rColumn),
2420 0 : miPos(rColumn.GetCellStore().begin()),
2421 0 : maArea(rArea), mnGrowX(nGrowX), mnGrowY(nGrowY) {}
2422 :
2423 0 : void operator() (size_t nRow, ScFormulaCell* pCell)
2424 : {
2425 0 : sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2426 0 : miPos = aPos.first;
2427 0 : sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2428 0 : pCell->UpdateGrow(maArea, mnGrowX, mnGrowY);
2429 0 : mrColumn.JoinNewFormulaCell(aPos, *pCell);
2430 0 : }
2431 : };
2432 :
2433 : class InsertTabUpdater
2434 : {
2435 : sc::RefUpdateInsertTabContext& mrCxt;
2436 : sc::CellTextAttrStoreType& mrTextAttrs;
2437 : sc::CellTextAttrStoreType::iterator miAttrPos;
2438 : SCTAB mnTab;
2439 : bool mbModified;
2440 :
2441 : public:
2442 274432 : InsertTabUpdater(sc::RefUpdateInsertTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2443 : mrCxt(rCxt),
2444 : mrTextAttrs(rTextAttrs),
2445 : miAttrPos(rTextAttrs.begin()),
2446 : mnTab(nTab),
2447 274432 : mbModified(false) {}
2448 :
2449 500 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2450 : {
2451 500 : pCell->UpdateInsertTab(mrCxt);
2452 500 : mbModified = true;
2453 500 : }
2454 :
2455 12 : void operator() (size_t nRow, EditTextObject* pCell)
2456 : {
2457 12 : editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2458 12 : aUpdater.updateTableFields(mnTab);
2459 12 : miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2460 12 : mbModified = true;
2461 12 : }
2462 :
2463 274432 : bool isModified() const { return mbModified; }
2464 : };
2465 :
2466 : class DeleteTabUpdater
2467 : {
2468 : sc::RefUpdateDeleteTabContext& mrCxt;
2469 : sc::CellTextAttrStoreType& mrTextAttrs;
2470 : sc::CellTextAttrStoreType::iterator miAttrPos;
2471 : SCTAB mnTab;
2472 : bool mbModified;
2473 : public:
2474 438272 : DeleteTabUpdater(sc::RefUpdateDeleteTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2475 : mrCxt(rCxt),
2476 : mrTextAttrs(rTextAttrs),
2477 : miAttrPos(rTextAttrs.begin()),
2478 : mnTab(nTab),
2479 438272 : mbModified(false) {}
2480 :
2481 358 : void operator() (size_t, ScFormulaCell* pCell)
2482 : {
2483 358 : pCell->UpdateDeleteTab(mrCxt);
2484 358 : mbModified = true;
2485 358 : }
2486 :
2487 24 : void operator() (size_t nRow, EditTextObject* pCell)
2488 : {
2489 24 : editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2490 24 : aUpdater.updateTableFields(mnTab);
2491 24 : miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2492 24 : mbModified = true;
2493 24 : }
2494 :
2495 438272 : bool isModified() const { return mbModified; }
2496 : };
2497 :
2498 : class InsertAbsTabUpdater
2499 : {
2500 : sc::CellTextAttrStoreType& mrTextAttrs;
2501 : sc::CellTextAttrStoreType::iterator miAttrPos;
2502 : SCTAB mnTab;
2503 : SCTAB mnNewPos;
2504 : bool mbModified;
2505 : public:
2506 12288 : InsertAbsTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nNewPos) :
2507 : mrTextAttrs(rTextAttrs),
2508 : miAttrPos(rTextAttrs.begin()),
2509 : mnTab(nTab),
2510 : mnNewPos(nNewPos),
2511 12288 : mbModified(false) {}
2512 :
2513 4 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2514 : {
2515 4 : pCell->UpdateInsertTabAbs(mnNewPos);
2516 4 : mbModified = true;
2517 4 : }
2518 :
2519 12 : void operator() (size_t nRow, EditTextObject* pCell)
2520 : {
2521 12 : editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2522 12 : aUpdater.updateTableFields(mnTab);
2523 12 : miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2524 12 : mbModified = true;
2525 12 : }
2526 :
2527 12288 : bool isModified() const { return mbModified; }
2528 : };
2529 :
2530 : class MoveTabUpdater
2531 : {
2532 : sc::RefUpdateMoveTabContext& mrCxt;
2533 : sc::CellTextAttrStoreType& mrTextAttrs;
2534 : sc::CellTextAttrStoreType::iterator miAttrPos;
2535 : SCTAB mnTab;
2536 : bool mbModified;
2537 : public:
2538 79872 : MoveTabUpdater(sc::RefUpdateMoveTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2539 : mrCxt(rCxt),
2540 : mrTextAttrs(rTextAttrs),
2541 : miAttrPos(rTextAttrs.begin()),
2542 : mnTab(nTab),
2543 79872 : mbModified(false) {}
2544 :
2545 48 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2546 : {
2547 48 : pCell->UpdateMoveTab(mrCxt, mnTab);
2548 48 : mbModified = true;
2549 48 : }
2550 :
2551 0 : void operator() (size_t nRow, EditTextObject* pCell)
2552 : {
2553 0 : editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2554 0 : aUpdater.updateTableFields(mnTab);
2555 0 : miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2556 0 : mbModified = true;
2557 0 : }
2558 :
2559 79872 : bool isModified() const { return mbModified; }
2560 : };
2561 :
2562 : class UpdateCompileHandler
2563 : {
2564 : bool mbForceIfNameInUse:1;
2565 : public:
2566 741376 : UpdateCompileHandler(bool bForceIfNameInUse) :
2567 741376 : mbForceIfNameInUse(bForceIfNameInUse) {}
2568 :
2569 828 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2570 : {
2571 828 : pCell->UpdateCompile(mbForceIfNameInUse);
2572 828 : }
2573 : };
2574 :
2575 : class TabNoSetter
2576 : {
2577 : SCTAB mnTab;
2578 : public:
2579 26624 : TabNoSetter(SCTAB nTab) : mnTab(nTab) {}
2580 :
2581 100 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2582 : {
2583 100 : pCell->aPos.SetTab(mnTab);
2584 100 : }
2585 : };
2586 :
2587 : class UsedRangeNameFinder
2588 : {
2589 : std::set<sal_uInt16>& mrIndexes;
2590 : public:
2591 22 : UsedRangeNameFinder(std::set<sal_uInt16>& rIndexes) : mrIndexes(rIndexes) {}
2592 :
2593 2 : void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
2594 : {
2595 2 : pCell->FindRangeNamesInUse(mrIndexes);
2596 2 : }
2597 : };
2598 :
2599 : struct SetDirtyVarHandler
2600 : {
2601 7202 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
2602 : {
2603 7202 : p->SetDirtyVar();
2604 7202 : }
2605 : };
2606 :
2607 : class SetDirtyHandler
2608 : {
2609 : ScDocument& mrDoc;
2610 : const sc::SetFormulaDirtyContext& mrCxt;
2611 : public:
2612 1861632 : SetDirtyHandler( ScDocument& rDoc, const sc::SetFormulaDirtyContext& rCxt ) :
2613 1861632 : mrDoc(rDoc), mrCxt(rCxt) {}
2614 :
2615 996 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
2616 : {
2617 996 : if (mrCxt.mbClearTabDeletedFlag)
2618 : {
2619 6 : if (!p->IsShared() || p->IsSharedTop())
2620 : {
2621 2 : ScTokenArray* pCode = p->GetCode();
2622 : pCode->ClearTabDeleted(
2623 2 : p->aPos, mrCxt.mnTabDeletedStart, mrCxt.mnTabDeletedEnd);
2624 : }
2625 : }
2626 :
2627 996 : p->SetDirtyVar();
2628 996 : if (!mrDoc.IsInFormulaTree(p))
2629 250 : mrDoc.PutInFormulaTree(p);
2630 996 : }
2631 : };
2632 :
2633 29472 : class SetDirtyOnRangeHandler
2634 : {
2635 : sc::SingleColumnSpanSet maValueRanges;
2636 : ScColumn& mrColumn;
2637 : public:
2638 29472 : SetDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
2639 :
2640 554 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
2641 : {
2642 554 : p->SetDirty();
2643 554 : }
2644 :
2645 29812 : void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2646 : {
2647 29812 : if (type == sc::element_type_empty)
2648 : // Ignore empty blocks.
2649 58664 : return;
2650 :
2651 : // Non-formula cells.
2652 960 : SCROW nRow1 = nTopRow;
2653 960 : SCROW nRow2 = nTopRow + nDataSize - 1;
2654 960 : maValueRanges.set(nRow1, nRow2, true);
2655 : }
2656 :
2657 29472 : void broadcast()
2658 : {
2659 29472 : std::vector<SCROW> aRows;
2660 29472 : maValueRanges.getRows(aRows);
2661 29472 : mrColumn.BroadcastCells(aRows, SC_HINT_DATACHANGED);
2662 29472 : }
2663 : };
2664 :
2665 88 : class SetTableOpDirtyOnRangeHandler
2666 : {
2667 : sc::SingleColumnSpanSet maValueRanges;
2668 : ScColumn& mrColumn;
2669 : public:
2670 88 : SetTableOpDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
2671 :
2672 0 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
2673 : {
2674 0 : p->SetTableOpDirty();
2675 0 : }
2676 :
2677 88 : void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2678 : {
2679 88 : if (type == sc::element_type_empty)
2680 : // Ignore empty blocks.
2681 152 : return;
2682 :
2683 : // Non-formula cells.
2684 24 : SCROW nRow1 = nTopRow;
2685 24 : SCROW nRow2 = nTopRow + nDataSize - 1;
2686 24 : maValueRanges.set(nRow1, nRow2, true);
2687 : }
2688 :
2689 88 : void broadcast()
2690 : {
2691 88 : std::vector<SCROW> aRows;
2692 88 : maValueRanges.getRows(aRows);
2693 88 : mrColumn.BroadcastCells(aRows, SC_HINT_TABLEOPDIRTY);
2694 88 : }
2695 : };
2696 :
2697 : struct SetDirtyAfterLoadHandler
2698 : {
2699 7428 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2700 : {
2701 : #if 1
2702 : // Simply set dirty and append to FormulaTree, without broadcasting,
2703 : // which is a magnitude faster. This is used to calculate the entire
2704 : // document, e.g. when loading alien file formats.
2705 7428 : pCell->SetDirtyAfterLoad();
2706 : #else
2707 : /* This was used with the binary file format that stored results, where only
2708 : * newly compiled and volatile functions and their dependents had to be
2709 : * recalculated, which was faster then. Since that was moved to 'binfilter' to
2710 : * convert to an XML file this isn't needed anymore, and not used for other
2711 : * file formats. Kept for reference in case mechanism needs to be reactivated
2712 : * for some file formats, we'd have to introduce a controlling parameter to
2713 : * this method here then.
2714 : */
2715 :
2716 : // If the cell was alsready dirty because of CalcAfterLoad,
2717 : // FormulaTracking has to take place.
2718 : if (pCell->GetDirty())
2719 : pCell->SetDirty();
2720 : #endif
2721 7428 : }
2722 : };
2723 :
2724 : struct SetDirtyIfPostponedHandler
2725 : {
2726 572 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2727 : {
2728 572 : if (pCell->IsPostponedDirty() || pCell->HasRelNameReference())
2729 184 : pCell->SetDirty();
2730 572 : }
2731 : };
2732 :
2733 : struct CalcAllHandler
2734 : {
2735 7202 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2736 : {
2737 : #if OSL_DEBUG_LEVEL > 1
2738 : // after F9 ctrl-F9: check the calculation for each FormulaTree
2739 : double nOldVal, nNewVal;
2740 : nOldVal = pCell->GetValue();
2741 : #endif
2742 7202 : pCell->Interpret();
2743 : #if OSL_DEBUG_LEVEL > 1
2744 : if (pCell->GetCode()->IsRecalcModeNormal())
2745 : nNewVal = pCell->GetValue();
2746 : else
2747 : nNewVal = nOldVal; // random(), jetzt() etc.
2748 :
2749 : OSL_ENSURE(nOldVal == nNewVal, "CalcAll: nOldVal != nNewVal");
2750 : #endif
2751 7202 : }
2752 : };
2753 :
2754 : class CompileAllHandler
2755 : {
2756 : sc::CompileFormulaContext& mrCxt;
2757 : public:
2758 63488 : CompileAllHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
2759 :
2760 172 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2761 : {
2762 : // for unconditional compilation
2763 : // bCompile=true and pCode->nError=0
2764 172 : pCell->GetCode()->SetCodeError(0);
2765 172 : pCell->SetCompile(true);
2766 172 : pCell->CompileTokenArray(mrCxt);
2767 172 : }
2768 : };
2769 :
2770 : class CompileXMLHandler
2771 : {
2772 : sc::CompileFormulaContext& mrCxt;
2773 : ScProgress& mrProgress;
2774 : const ScColumn& mrCol;
2775 : public:
2776 591872 : CompileXMLHandler( sc::CompileFormulaContext& rCxt, ScProgress& rProgress, const ScColumn& rCol) :
2777 : mrCxt(rCxt),
2778 : mrProgress(rProgress),
2779 591872 : mrCol(rCol) {}
2780 :
2781 1816 : void operator() (size_t nRow, ScFormulaCell* pCell)
2782 : {
2783 1816 : sal_uInt32 nFormat = mrCol.GetNumberFormat(nRow);
2784 1816 : if( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
2785 : // Non-default number format is set.
2786 596 : pCell->SetNeedNumberFormat(false);
2787 1220 : else if (pCell->NeedsNumberFormat())
2788 484 : pCell->SetDirtyVar();
2789 :
2790 1816 : if (pCell->GetMatrixFlag())
2791 168 : pCell->SetDirtyVar();
2792 :
2793 1816 : pCell->CompileXML(mrCxt, mrProgress);
2794 1816 : }
2795 : };
2796 :
2797 : class CompileErrorCellsHandler
2798 : {
2799 : sc::CompileFormulaContext& mrCxt;
2800 : ScColumn& mrColumn;
2801 : sc::CellStoreType::iterator miPos;
2802 : sal_uInt16 mnErrCode;
2803 : bool mbCompiled;
2804 : public:
2805 0 : CompileErrorCellsHandler( sc::CompileFormulaContext& rCxt, ScColumn& rColumn, sal_uInt16 nErrCode ) :
2806 : mrCxt(rCxt),
2807 : mrColumn(rColumn),
2808 0 : miPos(mrColumn.GetCellStore().begin()),
2809 : mnErrCode(nErrCode),
2810 0 : mbCompiled(false)
2811 : {
2812 0 : }
2813 :
2814 0 : void operator() (size_t nRow, ScFormulaCell* pCell)
2815 : {
2816 0 : sal_uInt16 nCurError = pCell->GetRawError();
2817 0 : if (!nCurError)
2818 : // It's not an error cell. Skip it.
2819 0 : return;
2820 :
2821 0 : if (mnErrCode && nCurError != mnErrCode)
2822 : // Error code is specified, and it doesn't match. Skip it.
2823 0 : return;
2824 :
2825 0 : sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2826 0 : miPos = aPos.first;
2827 0 : sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
2828 0 : pCell->GetCode()->SetCodeError(0);
2829 0 : OUString aFormula = pCell->GetFormula(mrCxt);
2830 0 : pCell->Compile(mrCxt, aFormula, false);
2831 0 : mrColumn.JoinNewFormulaCell(aPos, *pCell);
2832 :
2833 0 : mbCompiled = true;
2834 : }
2835 :
2836 0 : bool isCompiled() const { return mbCompiled; }
2837 : };
2838 :
2839 : class CalcAfterLoadHandler
2840 : {
2841 : sc::CompileFormulaContext& mrCxt;
2842 : public:
2843 444416 : CalcAfterLoadHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
2844 :
2845 7428 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2846 : {
2847 7428 : pCell->CalcAfterLoad(mrCxt);
2848 7428 : }
2849 : };
2850 :
2851 : struct ResetChangedHandler
2852 : {
2853 375 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2854 : {
2855 375 : pCell->SetChanged(false);
2856 375 : }
2857 : };
2858 :
2859 : /**
2860 : * Ambiguous script type counts as edit cell.
2861 : */
2862 : class FindEditCellsHandler
2863 : {
2864 : ScColumn& mrColumn;
2865 : sc::CellTextAttrStoreType::iterator miAttrPos;
2866 : sc::CellStoreType::iterator miCellPos;
2867 :
2868 : public:
2869 2510394 : FindEditCellsHandler(ScColumn& rCol) :
2870 : mrColumn(rCol),
2871 2510394 : miAttrPos(rCol.GetCellAttrStore().begin()),
2872 5020788 : miCellPos(rCol.GetCellStore().begin()) {}
2873 :
2874 214 : bool operator() (size_t, const EditTextObject*)
2875 : {
2876 : // This is definitely an edit text cell.
2877 214 : return true;
2878 : }
2879 :
2880 1616 : bool operator() (size_t nRow, const ScFormulaCell* p)
2881 : {
2882 : // With a formula cell, it's considered an edit text cell when either
2883 : // the result is multi-line or it has more than one script types.
2884 1616 : sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
2885 1616 : if (IsAmbiguousScriptNonZero(nScriptType))
2886 0 : return true;
2887 :
2888 1616 : return const_cast<ScFormulaCell*>(p)->IsMultilineResult();
2889 : }
2890 :
2891 : /**
2892 : * Callback for a block of other types.
2893 : */
2894 2511358 : std::pair<size_t,bool> operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2895 : {
2896 : typedef std::pair<size_t,bool> RetType;
2897 :
2898 2511358 : if (node.type == sc::element_type_empty)
2899 : // Ignore empty blocks.
2900 2503897 : return RetType(0, false);
2901 :
2902 : // Check the script type of a non-empty element and see if it has
2903 : // multiple script types.
2904 71572 : for (size_t i = 0; i < nDataSize; ++i)
2905 : {
2906 64115 : SCROW nRow = node.position + i + nOffset;
2907 64115 : sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
2908 64115 : if (IsAmbiguousScriptNonZero(nScriptType))
2909 : // Return the offset from the first row.
2910 4 : return RetType(i+nOffset, true);
2911 : }
2912 :
2913 : // No edit text cell found.
2914 7457 : return RetType(0, false);
2915 : }
2916 : };
2917 :
2918 : }
2919 :
2920 0 : void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
2921 : ScDocument* pUndoDoc )
2922 : {
2923 0 : UpdateTransHandler aFunc(*this, rSource, rDest, pUndoDoc);
2924 0 : sc::ProcessFormula(maCells, aFunc);
2925 0 : }
2926 :
2927 0 : void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
2928 : {
2929 0 : UpdateGrowHandler aFunc(*this, rArea, nGrowX, nGrowY);
2930 0 : sc::ProcessFormula(maCells, aFunc);
2931 0 : }
2932 :
2933 274432 : void ScColumn::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
2934 : {
2935 274432 : if (nTab >= rCxt.mnInsertPos)
2936 : {
2937 253952 : nTab += rCxt.mnSheets;
2938 253952 : pAttrArray->SetTab(nTab);
2939 : }
2940 :
2941 274432 : UpdateInsertTabOnlyCells(rCxt);
2942 274432 : }
2943 :
2944 274432 : void ScColumn::UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext& rCxt )
2945 : {
2946 274432 : InsertTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
2947 274432 : sc::ProcessFormulaEditText(maCells, aFunc);
2948 274432 : if (aFunc.isModified())
2949 472 : CellStorageModified();
2950 274432 : }
2951 :
2952 438272 : void ScColumn::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
2953 : {
2954 438272 : if (nTab > rCxt.mnDeletePos)
2955 : {
2956 86016 : nTab -= rCxt.mnSheets;
2957 86016 : pAttrArray->SetTab(nTab);
2958 : }
2959 :
2960 438272 : DeleteTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
2961 438272 : sc::ProcessFormulaEditText(maCells, aFunc);
2962 438272 : if (aFunc.isModified())
2963 130 : CellStorageModified();
2964 438272 : }
2965 :
2966 12288 : void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos)
2967 : {
2968 12288 : InsertAbsTabUpdater aFunc(maCellTextAttrs, nTab, nNewPos);
2969 12288 : sc::ProcessFormulaEditText(maCells, aFunc);
2970 12288 : if (aFunc.isModified())
2971 6 : CellStorageModified();
2972 12288 : }
2973 :
2974 79872 : void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo )
2975 : {
2976 79872 : nTab = nTabNo;
2977 79872 : pAttrArray->SetTab( nTabNo );
2978 :
2979 79872 : MoveTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
2980 79872 : sc::ProcessFormulaEditText(maCells, aFunc);
2981 79872 : if (aFunc.isModified())
2982 18 : CellStorageModified();
2983 79872 : }
2984 :
2985 741376 : void ScColumn::UpdateCompile( bool bForceIfNameInUse )
2986 : {
2987 741376 : UpdateCompileHandler aFunc(bForceIfNameInUse);
2988 741376 : sc::ProcessFormula(maCells, aFunc);
2989 741376 : }
2990 :
2991 26624 : void ScColumn::SetTabNo(SCTAB nNewTab)
2992 : {
2993 26624 : nTab = nNewTab;
2994 26624 : pAttrArray->SetTab( nNewTab );
2995 :
2996 26624 : TabNoSetter aFunc(nTab);
2997 26624 : sc::ProcessFormula(maCells, aFunc);
2998 26624 : }
2999 :
3000 22 : void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
3001 : {
3002 22 : UsedRangeNameFinder aFunc(rIndexes);
3003 22 : sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
3004 22 : }
3005 :
3006 909312 : void ScColumn::SetDirtyVar()
3007 : {
3008 : SetDirtyVarHandler aFunc;
3009 909312 : sc::ProcessFormula(maCells, aFunc);
3010 909312 : }
3011 :
3012 0 : bool ScColumn::IsFormulaDirty( SCROW nRow ) const
3013 : {
3014 0 : if (!ValidRow(nRow))
3015 0 : return false;
3016 :
3017 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3018 0 : sc::CellStoreType::const_iterator it = aPos.first;
3019 0 : if (it->type != sc::element_type_formula)
3020 : // This is not a formula cell block.
3021 0 : return false;
3022 :
3023 0 : const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3024 0 : return p->GetDirty();
3025 : }
3026 :
3027 1861632 : void ScColumn::SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt )
3028 : {
3029 : // is only done documentwide, no FormulaTracking
3030 1861632 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3031 1861632 : SetDirtyHandler aFunc(*pDocument, rCxt);
3032 1861632 : sc::ProcessFormula(maCells, aFunc);
3033 1861632 : }
3034 :
3035 29472 : void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2 )
3036 : {
3037 : // broadcasts everything within the range, with FormulaTracking
3038 29472 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3039 :
3040 58944 : SetDirtyOnRangeHandler aHdl(*this);
3041 29472 : sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3042 58944 : aHdl.broadcast();
3043 29472 : }
3044 :
3045 88 : void ScColumn::SetTableOpDirty( const ScRange& rRange )
3046 : {
3047 88 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3048 :
3049 88 : SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3050 176 : SetTableOpDirtyOnRangeHandler aHdl(*this);
3051 88 : sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3052 176 : aHdl.broadcast();
3053 88 : }
3054 :
3055 444416 : void ScColumn::SetDirtyAfterLoad()
3056 : {
3057 444416 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3058 : SetDirtyAfterLoadHandler aFunc;
3059 444416 : sc::ProcessFormula(maCells, aFunc);
3060 444416 : }
3061 :
3062 : namespace {
3063 :
3064 704512 : class RecalcOnRefMoveCollector
3065 : {
3066 : std::vector<SCROW> maDirtyRows;
3067 : public:
3068 572 : void operator() (size_t nRow, ScFormulaCell* pCell)
3069 : {
3070 572 : if (pCell->GetDirty() && pCell->GetCode()->IsRecalcModeOnRefMove())
3071 20 : maDirtyRows.push_back(nRow);
3072 572 : }
3073 :
3074 352256 : const std::vector<SCROW>& getDirtyRows() const
3075 : {
3076 352256 : return maDirtyRows;
3077 : }
3078 : };
3079 :
3080 : }
3081 :
3082 352256 : void ScColumn::SetDirtyIfPostponed()
3083 : {
3084 352256 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3085 : SetDirtyIfPostponedHandler aFunc;
3086 352256 : sc::ProcessFormula(maCells, aFunc);
3087 352256 : }
3088 :
3089 352256 : void ScColumn::BroadcastRecalcOnRefMove()
3090 : {
3091 352256 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3092 704512 : RecalcOnRefMoveCollector aFunc;
3093 352256 : sc::ProcessFormula(maCells, aFunc);
3094 704512 : BroadcastCells(aFunc.getDirtyRows(), SC_HINT_DATACHANGED);
3095 352256 : }
3096 :
3097 : namespace {
3098 :
3099 28 : class TransferListenersHandler
3100 : {
3101 : public:
3102 : typedef std::vector<SvtListener*> ListenersType;
3103 112 : struct Entry
3104 : {
3105 : size_t mnRow;
3106 : ListenersType maListeners;
3107 : };
3108 : typedef std::vector<Entry> ListenerListType;
3109 :
3110 14 : void swapListeners( std::vector<Entry>& rListenerList )
3111 : {
3112 14 : maListenerList.swap(rListenerList);
3113 14 : }
3114 :
3115 20 : void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
3116 : {
3117 : assert(pBroadcaster);
3118 :
3119 : // It's important to make a copy here.
3120 20 : SvtBroadcaster::ListenersType aLis = pBroadcaster->GetAllListeners();
3121 20 : if (aLis.empty())
3122 : // No listeners to transfer.
3123 20 : return;
3124 :
3125 40 : Entry aEntry;
3126 20 : aEntry.mnRow = nRow;
3127 :
3128 20 : SvtBroadcaster::ListenersType::iterator it = aLis.begin(), itEnd = aLis.end();
3129 50 : for (; it != itEnd; ++it)
3130 : {
3131 30 : SvtListener* pLis = *it;
3132 30 : pLis->EndListening(*pBroadcaster);
3133 30 : aEntry.maListeners.push_back(pLis);
3134 : }
3135 :
3136 20 : maListenerList.push_back(aEntry);
3137 :
3138 : // At this point, the source broadcaster should have no more listeners.
3139 20 : assert(!pBroadcaster->HasListeners());
3140 : }
3141 :
3142 : private:
3143 : ListenerListType maListenerList;
3144 : };
3145 :
3146 14 : class RemoveEmptyBroadcasterHandler
3147 : {
3148 : sc::ColumnSpanSet maSet;
3149 : ScDocument& mrDoc;
3150 : SCCOL mnCol;
3151 : SCTAB mnTab;
3152 :
3153 : public:
3154 14 : RemoveEmptyBroadcasterHandler( ScDocument& rDoc, SCCOL nCol, SCTAB nTab ) :
3155 14 : maSet(false), mrDoc(rDoc), mnCol(nCol), mnTab(nTab) {}
3156 :
3157 20 : void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
3158 : {
3159 20 : if (!pBroadcaster->HasListeners())
3160 16 : maSet.set(mnTab, mnCol, nRow, true);
3161 20 : }
3162 :
3163 14 : void purge()
3164 : {
3165 14 : sc::PurgeListenerAction aAction(mrDoc);
3166 14 : maSet.executeAction(aAction);
3167 14 : }
3168 : };
3169 :
3170 : }
3171 :
3172 14 : void ScColumn::TransferListeners(
3173 : ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta )
3174 : {
3175 14 : if (nRow2 < nRow1)
3176 0 : return;
3177 :
3178 14 : if (!ValidRow(nRow1) || !ValidRow(nRow2))
3179 0 : return;
3180 :
3181 14 : if (nRowDelta <= 0 && !ValidRow(nRow1+nRowDelta))
3182 0 : return;
3183 :
3184 14 : if (nRowDelta >= 0 && !ValidRow(nRow2+nRowDelta))
3185 0 : return;
3186 :
3187 : // Collect all listeners from the source broadcasters. The listeners will
3188 : // be removed from their broadcasters as they are collected.
3189 14 : TransferListenersHandler aFunc;
3190 14 : sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
3191 :
3192 28 : TransferListenersHandler::ListenerListType aListenerList;
3193 14 : aFunc.swapListeners(aListenerList);
3194 :
3195 : // Re-register listeners with their destination broadcasters.
3196 14 : sc::BroadcasterStoreType::iterator itDestPos = rDestCol.maBroadcasters.begin();
3197 14 : TransferListenersHandler::ListenerListType::iterator it = aListenerList.begin(), itEnd = aListenerList.end();
3198 34 : for (; it != itEnd; ++it)
3199 : {
3200 20 : TransferListenersHandler::Entry& rEntry = *it;
3201 :
3202 20 : SCROW nDestRow = rEntry.mnRow + nRowDelta;
3203 :
3204 : sc::BroadcasterStoreType::position_type aPos =
3205 20 : rDestCol.maBroadcasters.position(itDestPos, nDestRow);
3206 :
3207 20 : itDestPos = aPos.first;
3208 20 : SvtBroadcaster* pDestBrd = NULL;
3209 20 : if (aPos.first->type == sc::element_type_broadcaster)
3210 : {
3211 : // Existing broadcaster.
3212 20 : pDestBrd = sc::broadcaster_block::at(*aPos.first->data, aPos.second);
3213 : }
3214 : else
3215 : {
3216 : // No existing broadcaster. Create a new one.
3217 : assert(aPos.first->type == sc::element_type_empty);
3218 0 : pDestBrd = new SvtBroadcaster;
3219 0 : itDestPos = rDestCol.maBroadcasters.set(itDestPos, nDestRow, pDestBrd);
3220 : }
3221 :
3222 : // Transfer all listeners from the source to the destination.
3223 20 : SvtBroadcaster::ListenersType::iterator it2 = rEntry.maListeners.begin(), it2End = rEntry.maListeners.end();
3224 50 : for (; it2 != it2End; ++it2)
3225 : {
3226 30 : SvtListener* pLis = *it2;
3227 30 : pLis->StartListening(*pDestBrd);
3228 : }
3229 : }
3230 :
3231 : // Remove any broadcasters that have no listeners.
3232 28 : RemoveEmptyBroadcasterHandler aFuncRemoveEmpty(*pDocument, nCol, nTab);
3233 14 : sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFuncRemoveEmpty);
3234 28 : aFuncRemoveEmpty.purge();
3235 : }
3236 :
3237 909312 : void ScColumn::CalcAll()
3238 : {
3239 : CalcAllHandler aFunc;
3240 909312 : sc::ProcessFormula(maCells, aFunc);
3241 909312 : }
3242 :
3243 63488 : void ScColumn::CompileAll( sc::CompileFormulaContext& rCxt )
3244 : {
3245 63488 : CompileAllHandler aFunc(rCxt);
3246 63488 : sc::ProcessFormula(maCells, aFunc);
3247 63488 : }
3248 :
3249 591872 : void ScColumn::CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rProgress )
3250 : {
3251 591872 : CompileXMLHandler aFunc(rCxt, rProgress, *this);
3252 591872 : sc::ProcessFormula(maCells, aFunc);
3253 591872 : RegroupFormulaCells();
3254 591872 : }
3255 :
3256 0 : bool ScColumn::CompileErrorCells( sc::CompileFormulaContext& rCxt, sal_uInt16 nErrCode )
3257 : {
3258 0 : CompileErrorCellsHandler aHdl(rCxt, *this, nErrCode);
3259 0 : sc::ProcessFormula(maCells, aHdl);
3260 0 : return aHdl.isCompiled();
3261 : }
3262 :
3263 444416 : void ScColumn::CalcAfterLoad( sc::CompileFormulaContext& rCxt )
3264 : {
3265 444416 : CalcAfterLoadHandler aFunc(rCxt);
3266 444416 : sc::ProcessFormula(maCells, aFunc);
3267 444416 : }
3268 :
3269 25204 : void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
3270 : {
3271 : ResetChangedHandler aFunc;
3272 25204 : sc::ProcessFormula(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
3273 25204 : }
3274 :
3275 2510394 : bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst)
3276 : {
3277 : // used in GetOptimalHeight - ambiguous script type counts as edit cell
3278 :
3279 2510394 : FindEditCellsHandler aFunc(*this);
3280 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
3281 2510394 : sc::FindFormulaEditText(maCells, nStartRow, nEndRow, aFunc);
3282 :
3283 2510394 : if (aPos.first == maCells.end())
3284 2510176 : return false;
3285 :
3286 218 : rFirst = aPos.first->position + aPos.second;
3287 218 : return true;
3288 : }
3289 :
3290 0 : SCsROW ScColumn::SearchStyle(
3291 : SCsROW nRow, const ScStyleSheet* pSearchStyle, bool bUp, bool bInSelection,
3292 : const ScMarkData& rMark) const
3293 : {
3294 0 : if (bInSelection)
3295 : {
3296 0 : if (rMark.IsMultiMarked())
3297 0 : return pAttrArray->SearchStyle(nRow, pSearchStyle, bUp, rMark.GetArray()+nCol);
3298 : else
3299 0 : return -1;
3300 : }
3301 : else
3302 0 : return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL );
3303 : }
3304 :
3305 0 : bool ScColumn::SearchStyleRange(
3306 : SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
3307 : bool bInSelection, const ScMarkData& rMark) const
3308 : {
3309 0 : if (bInSelection)
3310 : {
3311 0 : if (rMark.IsMultiMarked())
3312 : return pAttrArray->SearchStyleRange(
3313 0 : rRow, rEndRow, pSearchStyle, bUp, rMark.GetArray() + nCol);
3314 : else
3315 0 : return false;
3316 : }
3317 : else
3318 0 : return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );
3319 228 : }
3320 :
3321 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|