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