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