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 0 : inline bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
66 : {
67 : //! move to a header file
68 0 : return ( nScript != SCRIPTTYPE_LATIN &&
69 0 : nScript != SCRIPTTYPE_ASIAN &&
70 0 : nScript != SCRIPTTYPE_COMPLEX &&
71 0 : nScript != 0 );
72 : }
73 :
74 : }
75 :
76 0 : ScNeededSizeOptions::ScNeededSizeOptions() :
77 0 : pPattern(NULL), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
78 : {
79 0 : }
80 :
81 0 : 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 0 : mbDirtyGroups(true)
91 : {
92 0 : }
93 :
94 :
95 0 : ScColumn::~ScColumn()
96 : {
97 0 : FreeAll();
98 0 : delete pAttrArray;
99 0 : }
100 :
101 :
102 0 : void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
103 : {
104 0 : nCol = nNewCol;
105 0 : nTab = nNewTab;
106 0 : pDocument = pDoc;
107 0 : pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
108 0 : }
109 :
110 :
111 0 : SCsROW ScColumn::GetNextUnprotected( SCROW nRow, bool bUp ) const
112 : {
113 0 : return pAttrArray->GetNextUnprotected(nRow, bUp);
114 : }
115 :
116 :
117 0 : sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
118 : {
119 : using namespace sc;
120 :
121 0 : if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
122 0 : return 0;
123 :
124 0 : ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
125 :
126 0 : if (nRow1 == nRow2)
127 : {
128 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
129 0 : if (aPos.first->type != sc::element_type_formula)
130 0 : return 0;
131 :
132 0 : const ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
133 0 : if (!pCell->GetMatrixFlag())
134 0 : return 0;
135 :
136 0 : return pCell->GetMatrixEdge(aOrigin);
137 : }
138 :
139 0 : bool bOpen = false;
140 0 : sal_uInt16 nEdges = 0;
141 :
142 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
143 0 : sc::CellStoreType::const_iterator it = aPos.first;
144 0 : size_t nOffset = aPos.second;
145 0 : SCROW nRow = nRow1;
146 0 : for (;it != maCells.end() && nRow <= nRow2; ++it, nOffset = 0)
147 : {
148 0 : if (it->type != sc::element_type_formula)
149 : {
150 : // Skip this block.
151 0 : nRow += it->size - nOffset;
152 0 : continue;
153 : }
154 :
155 0 : size_t nRowsToRead = nRow2 - nRow + 1;
156 0 : size_t nEnd = std::min(it->size, nRowsToRead);
157 0 : sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
158 0 : std::advance(itCell, nOffset);
159 0 : for (size_t i = nOffset; i < nEnd; ++itCell, ++i)
160 : {
161 : // Loop inside the formula block.
162 0 : const ScFormulaCell* pCell = *itCell;
163 0 : if (!pCell->GetMatrixFlag())
164 0 : 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 0 : nRow += nEnd;
187 : }
188 0 : if (bOpen)
189 0 : nEdges |= MatrixEdgeOpen; // not closed, matrix continues
190 :
191 0 : return nEdges;
192 : }
193 :
194 :
195 0 : bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
196 : {
197 : using namespace sc;
198 :
199 0 : if (!rMark.IsMultiMarked())
200 0 : return false;
201 :
202 0 : ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
203 0 : ScAddress aCurOrigin = aOrigin;
204 :
205 0 : bool bOpen = false;
206 0 : ScRangeList aRanges = rMark.GetMarkedRanges();
207 0 : for (size_t i = 0, n = aRanges.size(); i < n; ++i)
208 : {
209 0 : const ScRange& r = *aRanges[i];
210 0 : if (nTab < r.aStart.Tab() || r.aEnd.Tab() < nTab)
211 0 : continue;
212 :
213 0 : if (nCol < r.aStart.Col() || r.aEnd.Col() < nCol)
214 0 : continue;
215 :
216 0 : SCROW nTop = r.aStart.Row(), nBottom = r.aEnd.Row();
217 0 : SCROW nRow = nTop;
218 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
219 0 : sc::CellStoreType::const_iterator it = aPos.first;
220 0 : size_t nOffset = aPos.second;
221 :
222 0 : for (;it != maCells.end() && nRow <= nBottom; ++it, nOffset = 0)
223 : {
224 0 : if (it->type != sc::element_type_formula)
225 : {
226 : // Skip this block.
227 0 : nRow += it->size - nOffset;
228 0 : 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 0 : if (bOpen)
301 0 : return true;
302 :
303 0 : return false;
304 : }
305 :
306 :
307 0 : bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
308 : {
309 0 : 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 0 : bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
335 : SCCOL& rPaintCol, SCROW& rPaintRow,
336 : bool bRefresh )
337 : {
338 0 : return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh );
339 : }
340 :
341 :
342 0 : void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
343 : {
344 : SCROW nTop;
345 : SCROW nBottom;
346 :
347 0 : if ( rMark.IsMultiMarked() )
348 : {
349 0 : const ScMarkArray* pArray = rMark.GetArray() + nCol;
350 0 : if ( pArray->HasMarks() )
351 : {
352 0 : ScMarkArrayIter aMarkIter( pArray );
353 0 : while (aMarkIter.Next( nTop, nBottom ))
354 0 : pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
355 : }
356 : }
357 0 : }
358 :
359 :
360 0 : void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, bool bDeep ) const
361 : {
362 0 : pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
363 0 : }
364 :
365 :
366 0 : void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
367 : ScLineFlags& rFlags,
368 : SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
369 : {
370 0 : pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
371 0 : }
372 :
373 :
374 0 : void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
375 : SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
376 : {
377 0 : pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
378 0 : }
379 :
380 :
381 0 : const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
382 : {
383 0 : return pAttrArray->GetPattern( nRow );
384 : }
385 :
386 :
387 0 : const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
388 : {
389 0 : return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
390 : }
391 :
392 :
393 0 : const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
394 : {
395 0 : ::std::map< const ScPatternAttr*, size_t > aAttrMap;
396 0 : const ScPatternAttr* pMaxPattern = 0;
397 0 : size_t nMaxCount = 0;
398 :
399 0 : ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
400 : const ScPatternAttr* pPattern;
401 0 : SCROW nAttrRow1 = 0, nAttrRow2 = 0;
402 :
403 0 : while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
404 : {
405 0 : size_t& rnCount = aAttrMap[ pPattern ];
406 0 : rnCount += (nAttrRow2 - nAttrRow1 + 1);
407 0 : if( rnCount > nMaxCount )
408 : {
409 0 : pMaxPattern = pPattern;
410 0 : nMaxCount = rnCount;
411 : }
412 : }
413 :
414 0 : return pMaxPattern;
415 : }
416 :
417 0 : sal_uInt32 ScColumn::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
418 : {
419 : SCROW nPatStartRow, nPatEndRow;
420 0 : const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
421 0 : sal_uInt32 nFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
422 0 : while (nEndRow > nPatEndRow)
423 : {
424 0 : nStartRow = nPatEndRow + 1;
425 0 : pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
426 0 : sal_uInt32 nTmpFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
427 0 : if (nFormat != nTmpFormat)
428 0 : return 0;
429 : }
430 0 : return nFormat;
431 : }
432 :
433 :
434 0 : sal_uInt32 ScColumn::GetNumberFormat( SCROW nRow ) const
435 : {
436 0 : return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
437 : }
438 :
439 :
440 0 : SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray )
441 : {
442 0 : SCROW nTop = 0;
443 0 : SCROW nBottom = 0;
444 0 : bool bFound = false;
445 :
446 0 : if ( rMark.IsMultiMarked() )
447 : {
448 0 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
449 0 : while (aMarkIter.Next( nTop, nBottom ))
450 : {
451 0 : pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray );
452 0 : bFound = true;
453 0 : }
454 : }
455 :
456 0 : if (!bFound)
457 0 : return -1;
458 0 : else if (nTop==0 && nBottom==MAXROW)
459 0 : return 0;
460 : else
461 0 : return nBottom;
462 : }
463 :
464 :
465 0 : void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
466 : {
467 : SCROW nTop;
468 : SCROW nBottom;
469 :
470 0 : if ( pAttrArray && rMark.IsMultiMarked() )
471 : {
472 0 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
473 0 : while (aMarkIter.Next( nTop, nBottom ))
474 0 : pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
475 : }
476 0 : }
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 0 : void ScColumn::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark, bool bBroadcast )
493 : {
494 : SCROW nTop;
495 : SCROW nBottom;
496 :
497 0 : if ( rMark.IsMultiMarked() )
498 : {
499 0 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
500 0 : while (aMarkIter.Next( nTop, nBottom ))
501 0 : DeleteArea(nTop, nBottom, nDelFlag, bBroadcast);
502 : }
503 0 : }
504 :
505 :
506 0 : void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
507 : {
508 0 : const SfxItemSet* pSet = &rPatAttr.GetItemSet();
509 0 : SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
510 :
511 0 : const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
512 :
513 : // true = keep old content
514 :
515 0 : ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, true );
516 0 : ScDocumentPool::CheckRef( *pPattern );
517 0 : ScDocumentPool::CheckRef( *pNewPattern );
518 :
519 0 : if (pNewPattern != pPattern)
520 0 : pAttrArray->SetPattern( nRow, pNewPattern );
521 0 : }
522 :
523 :
524 0 : void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr,
525 : ScEditDataArray* pDataArray )
526 : {
527 0 : const SfxItemSet* pSet = &rPatAttr.GetItemSet();
528 0 : SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
529 0 : pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache, pDataArray );
530 0 : }
531 :
532 0 : bool ScColumn::SetAttrEntries(ScAttrEntry* pData, SCSIZE nSize)
533 : {
534 0 : 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 0 : void ScColumn::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
564 : {
565 0 : pAttrArray->AddCondFormat( nStartRow, nEndRow, nIndex );
566 0 : }
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 0 : void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
575 : {
576 0 : const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
577 0 : ScPatternAttr* pNewPattern = new ScPatternAttr(*pPattern);
578 0 : if (pNewPattern)
579 : {
580 0 : pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
581 0 : pAttrArray->SetPattern(nRow, pNewPattern, true);
582 0 : delete pNewPattern;
583 : }
584 0 : }
585 :
586 :
587 0 : void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
588 : {
589 0 : pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle);
590 0 : }
591 :
592 :
593 0 : void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
594 : {
595 : SCROW nTop;
596 : SCROW nBottom;
597 :
598 0 : if ( rMark.IsMultiMarked() )
599 : {
600 0 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
601 0 : while (aMarkIter.Next( nTop, nBottom ))
602 0 : pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle);
603 : }
604 0 : }
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 0 : const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
626 : {
627 0 : return pAttrArray->GetPattern( nRow )->GetStyleSheet();
628 : }
629 :
630 :
631 0 : const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
632 : {
633 0 : rFound = false;
634 0 : if (!rMark.IsMultiMarked())
635 : {
636 : OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
637 0 : return NULL;
638 : }
639 :
640 0 : bool bEqual = true;
641 :
642 0 : const ScStyleSheet* pStyle = NULL;
643 : const ScStyleSheet* pNewStyle;
644 :
645 0 : ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
646 : SCROW nTop;
647 : SCROW nBottom;
648 0 : while (bEqual && aMarkIter.Next( nTop, nBottom ))
649 : {
650 0 : ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
651 : SCROW nRow;
652 : SCROW nDummy;
653 : const ScPatternAttr* pPattern;
654 0 : while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
655 : {
656 0 : pNewStyle = pPattern->GetStyleSheet();
657 0 : rFound = true;
658 0 : if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
659 0 : bEqual = false; // difference
660 0 : pStyle = pNewStyle;
661 : }
662 : }
663 :
664 0 : return bEqual ? pStyle : NULL;
665 : }
666 :
667 :
668 0 : const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRow2 ) const
669 : {
670 0 : rFound = false;
671 :
672 0 : bool bEqual = true;
673 :
674 0 : const ScStyleSheet* pStyle = NULL;
675 : const ScStyleSheet* pNewStyle;
676 :
677 0 : ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
678 : SCROW nRow;
679 : SCROW nDummy;
680 : const ScPatternAttr* pPattern;
681 0 : while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
682 : {
683 0 : pNewStyle = pPattern->GetStyleSheet();
684 0 : rFound = true;
685 0 : if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
686 0 : bEqual = false; // difference
687 0 : pStyle = pNewStyle;
688 : }
689 :
690 0 : return bEqual ? pStyle : NULL;
691 : }
692 :
693 0 : void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
694 : {
695 0 : pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
696 0 : }
697 :
698 0 : bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const
699 : {
700 0 : return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
701 : }
702 :
703 :
704 0 : bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
705 : {
706 0 : return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
707 : }
708 :
709 :
710 0 : bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
711 : {
712 0 : return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
713 : }
714 :
715 :
716 0 : void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
717 : {
718 0 : pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
719 0 : }
720 :
721 :
722 0 : void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, bool bPutToPool )
723 : {
724 0 : pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
725 0 : }
726 :
727 :
728 0 : void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
729 : const ScPatternAttr& rPatAttr, bool bPutToPool )
730 : {
731 0 : pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
732 0 : }
733 :
734 :
735 0 : 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 0 : ScDocumentPool* pDocPool = pDocument->GetPool();
741 :
742 0 : const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
743 0 : ScPatternAttr* pTemp = new ScPatternAttr(*pOldPattern);
744 0 : pTemp->GetItemSet().Put(rAttr);
745 0 : const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pDocPool->Put( *pTemp );
746 :
747 0 : if ( pNewPattern != pOldPattern )
748 0 : pAttrArray->SetPattern( nRow, pNewPattern );
749 : else
750 0 : pDocPool->Remove( *pNewPattern ); // free up resources
751 :
752 0 : delete pTemp;
753 0 : }
754 :
755 0 : ScDocument& ScColumn::GetDoc()
756 : {
757 0 : return *pDocument;
758 : }
759 :
760 0 : const ScDocument& ScColumn::GetDoc() const
761 : {
762 0 : return *pDocument;
763 : }
764 :
765 0 : ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
766 : {
767 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
768 0 : if (aPos.first == maCells.end())
769 0 : return ScRefCellValue();
770 :
771 0 : return GetCellValue(aPos.first, aPos.second);
772 : }
773 :
774 0 : ScRefCellValue ScColumn::GetCellValue( const sc::CellStoreType::const_iterator& itPos, size_t nOffset ) const
775 : {
776 0 : ScRefCellValue aVal; // Defaults to empty cell.
777 0 : switch (itPos->type)
778 : {
779 : case sc::element_type_numeric:
780 : // Numeric cell
781 0 : aVal.mfValue = sc::numeric_block::at(*itPos->data, nOffset);
782 0 : aVal.meType = CELLTYPE_VALUE;
783 0 : break;
784 : case sc::element_type_string:
785 : // String cell
786 0 : aVal.mpString = &sc::string_block::at(*itPos->data, nOffset);
787 0 : aVal.meType = CELLTYPE_STRING;
788 0 : break;
789 : case sc::element_type_edittext:
790 : // Edit cell
791 0 : aVal.mpEditText = sc::edittext_block::at(*itPos->data, nOffset);
792 0 : aVal.meType = CELLTYPE_EDIT;
793 0 : break;
794 : case sc::element_type_formula:
795 : // Formula cell
796 0 : aVal.mpFormula = sc::formula_block::at(*itPos->data, nOffset);
797 0 : aVal.meType = CELLTYPE_FORMULA;
798 0 : break;
799 : default:
800 : ;
801 : }
802 :
803 0 : return aVal;
804 : }
805 :
806 : namespace {
807 :
808 0 : ScFormulaCell* cloneFormulaCell(ScDocument* pDoc, const ScAddress& rNewPos, ScFormulaCell& rOldCell)
809 : {
810 0 : ScFormulaCell* pNew = new ScFormulaCell(rOldCell, *pDoc, rNewPos, SC_CLONECELL_ADJUST3DREL);
811 0 : rOldCell.EndListeningTo(pDoc);
812 0 : pNew->StartListeningTo(pDoc);
813 0 : pNew->SetDirty();
814 0 : return pNew;
815 : }
816 :
817 : }
818 :
819 0 : void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
820 : {
821 0 : if (nRow1 == nRow2)
822 : // Nothing to swap.
823 0 : return;
824 :
825 : // Ensure that nRow1 < nRow2.
826 0 : if (nRow2 < nRow1)
827 0 : std::swap(nRow1, nRow2);
828 :
829 : // Broadcasters (if exist) should NOT be swapped.
830 :
831 0 : sc::CellStoreType::position_type aPos1 = maCells.position(nRow1);
832 0 : if (aPos1.first == maCells.end())
833 0 : return;
834 :
835 0 : sc::CellStoreType::position_type aPos2 = maCells.position(aPos1.first, nRow2);
836 0 : if (aPos2.first == maCells.end())
837 0 : return;
838 :
839 0 : std::vector<SCROW> aRows;
840 0 : aRows.reserve(2);
841 0 : aRows.push_back(nRow1);
842 0 : aRows.push_back(nRow2);
843 :
844 0 : sc::CellStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
845 :
846 0 : if (it1->type == it2->type)
847 : {
848 : // Both positions are of the same type. Do a simple value swap.
849 0 : switch (it1->type)
850 : {
851 : case sc::element_type_empty:
852 : // Both are empty. Nothing to swap.
853 0 : return;
854 : case sc::element_type_numeric:
855 : std::swap(
856 0 : sc::numeric_block::at(*it1->data, aPos1.second),
857 0 : sc::numeric_block::at(*it2->data, aPos2.second));
858 0 : break;
859 : case sc::element_type_string:
860 : std::swap(
861 0 : sc::string_block::at(*it1->data, aPos1.second),
862 0 : sc::string_block::at(*it2->data, aPos2.second));
863 0 : 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 0 : sc::formula_block::iterator itf1 = sc::formula_block::begin(*it1->data);
873 0 : sc::formula_block::iterator itf2 = sc::formula_block::begin(*it2->data);
874 0 : std::advance(itf1, aPos1.second);
875 0 : 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 0 : if(!(*itf1)->SwapWithinGroup(*itf2))
880 : {
881 : // otherwise we need to really move the formula &
882 : // re-write dependencies etc.
883 0 : boost::scoped_ptr<ScFormulaCell> pOld1(*itf1);
884 0 : boost::scoped_ptr<ScFormulaCell> pOld2(*itf2);
885 :
886 0 : DetachFormulaCell(aPos1, **itf1);
887 0 : DetachFormulaCell(aPos2, **itf2);
888 0 : ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *pOld2);
889 0 : ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *pOld1);
890 0 : *itf1 = pNew1;
891 0 : *itf2 = pNew2;
892 :
893 0 : ActivateNewFormulaCell(aPos1, *pNew1);
894 0 : ActivateNewFormulaCell(aPos2, *pNew2);
895 : }
896 : }
897 0 : break;
898 : default:
899 : ;
900 : }
901 :
902 0 : SwapCellTextAttrs(nRow1, nRow2);
903 0 : SwapCellNotes(nRow1, nRow2);
904 0 : CellStorageModified();
905 0 : BroadcastCells(aRows, SC_HINT_DATACHANGED);
906 0 : return;
907 : }
908 :
909 : // The two cells are of different types.
910 :
911 0 : ScRefCellValue aCell1 = GetCellValue(aPos1.first, aPos1.second);
912 0 : ScRefCellValue aCell2 = GetCellValue(aPos2.first, aPos2.second);
913 :
914 : // Make sure to put cells in row 1 first then row 2!
915 :
916 0 : if (aCell1.meType == CELLTYPE_NONE)
917 : {
918 : // cell 1 is empty and cell 2 is not.
919 0 : switch (aCell2.meType)
920 : {
921 : case CELLTYPE_VALUE:
922 0 : it1 = maCells.set(it1, nRow1, aCell2.mfValue); // it2 becomes invalid.
923 0 : maCells.set_empty(it1, nRow2, nRow2);
924 0 : break;
925 : case CELLTYPE_STRING:
926 0 : it1 = maCells.set(it1, nRow1, *aCell2.mpString);
927 0 : maCells.set_empty(it1, nRow2, nRow2);
928 0 : 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 0 : SwapCellTextAttrs(nRow1, nRow2);
952 0 : SwapCellNotes(nRow1, nRow2);
953 0 : CellStorageModified();
954 0 : BroadcastCells(aRows, SC_HINT_DATACHANGED);
955 0 : return;
956 : }
957 :
958 0 : 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 0 : switch (aCell1.meType)
1005 : {
1006 : case CELLTYPE_VALUE:
1007 : {
1008 0 : switch (aCell2.meType)
1009 : {
1010 : case CELLTYPE_STRING:
1011 0 : it1 = maCells.set(it1, nRow1, *aCell2.mpString);
1012 0 : 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 0 : maCells.set(it1, nRow2, aCell1.mfValue);
1035 :
1036 : }
1037 0 : break;
1038 : case CELLTYPE_STRING:
1039 : {
1040 0 : svl::SharedString aStr = *aCell1.mpString; // make a copy.
1041 0 : switch (aCell2.meType)
1042 : {
1043 : case CELLTYPE_VALUE:
1044 0 : it1 = maCells.set(it1, nRow1, aCell2.mfValue);
1045 0 : break;
1046 : case CELLTYPE_EDIT:
1047 : {
1048 0 : it1 = maCells.set(
1049 0 : it1, nRow1, const_cast<EditTextObject*>(aCell2.mpEditText));
1050 : EditTextObject* p;
1051 0 : it1 = maCells.release(it1, nRow2, p); // prevent it being overwritten.
1052 : }
1053 0 : 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 0 : maCells.set(it1, nRow2, aStr);
1069 : }
1070 0 : break;
1071 : case CELLTYPE_EDIT:
1072 : {
1073 : EditTextObject* p;
1074 0 : it1 = maCells.release(it1, nRow1, p);
1075 :
1076 0 : 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 0 : it1 = maCells.set(it1, nRow1, *aCell2.mpString);
1083 0 : 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 0 : maCells.set(it1, nRow2, const_cast<EditTextObject*>(aCell1.mpEditText));
1098 : }
1099 0 : 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 0 : SwapCellTextAttrs(nRow1, nRow2);
1133 0 : SwapCellNotes(nRow1, nRow2);
1134 0 : CellStorageModified();
1135 0 : 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 0 : bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1199 : {
1200 0 : if (IsEmpty())
1201 0 : 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 0 : bool ScColumn::TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const
1222 : {
1223 : // AttrArray only looks for merged cells
1224 : {
1225 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1226 0 : sc::CellStoreType::const_iterator it = aPos.first;
1227 0 : if (it->type == sc::element_type_empty && maCells.block_size() == 1)
1228 : // The entire cell array is empty.
1229 0 : 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 0 : size_t nLastNonEmptyRow = MAXROW;
1236 0 : sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
1237 0 : if (it->type == sc::element_type_empty)
1238 0 : nLastNonEmptyRow -= it->size;
1239 :
1240 0 : if (nLastNonEmptyRow < static_cast<size_t>(nStartRow))
1241 : // No cells would get pushed out.
1242 0 : return pAttrArray->TestInsertRow(nSize);
1243 :
1244 0 : 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 0 : return pAttrArray->TestInsertRow(nSize);
1249 : }
1250 :
1251 :
1252 0 : void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
1253 : {
1254 0 : pAttrArray->InsertRow( nStartRow, nSize );
1255 :
1256 0 : maCellNotes.insert_empty(nStartRow, nSize);
1257 0 : maCellNotes.resize(MAXROWCOUNT);
1258 :
1259 0 : maBroadcasters.insert_empty(nStartRow, nSize);
1260 0 : maBroadcasters.resize(MAXROWCOUNT);
1261 :
1262 0 : maCellTextAttrs.insert_empty(nStartRow, nSize);
1263 0 : maCellTextAttrs.resize(MAXROWCOUNT);
1264 :
1265 0 : maCells.insert_empty(nStartRow, nSize);
1266 0 : maCells.resize(MAXROWCOUNT);
1267 :
1268 0 : CellStorageModified();
1269 :
1270 : // We *probably* don't need to broadcast here since the parent call seems
1271 : // to take care of it.
1272 0 : }
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 0 : void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1285 : {
1286 0 : std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1287 0 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1288 0 : maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1289 0 : }
1290 :
1291 0 : void duplicateNotes(SCROW nStartRow, size_t nDataSize )
1292 : {
1293 0 : mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, false);
1294 0 : }
1295 :
1296 : public:
1297 0 : CopyToClipHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, bool bCopyNotes) :
1298 0 : mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mbCopyNotes(bCopyNotes)
1299 : {
1300 0 : if (mpDestPos)
1301 0 : maDestPos = *mpDestPos;
1302 : else
1303 0 : mrDestCol.InitBlockPosition(maDestPos);
1304 0 : }
1305 :
1306 0 : ~CopyToClipHandler()
1307 : {
1308 0 : if (mpDestPos)
1309 0 : *mpDestPos = maDestPos;
1310 0 : }
1311 :
1312 0 : void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1313 : {
1314 0 : size_t nTopRow = aNode.position + nOffset;
1315 :
1316 0 : bool bSet = true;
1317 :
1318 0 : switch (aNode.type)
1319 : {
1320 : case sc::element_type_numeric:
1321 : {
1322 0 : sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1323 0 : std::advance(it, nOffset);
1324 0 : sc::numeric_block::const_iterator itEnd = it;
1325 0 : std::advance(itEnd, nDataSize);
1326 0 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
1327 : }
1328 0 : break;
1329 : case sc::element_type_string:
1330 : {
1331 0 : sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
1332 0 : std::advance(it, nOffset);
1333 0 : sc::string_block::const_iterator itEnd = it;
1334 0 : std::advance(itEnd, nDataSize);
1335 0 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
1336 :
1337 : }
1338 0 : 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 0 : sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
1358 0 : std::advance(it, nOffset);
1359 0 : sc::formula_block::const_iterator itEnd = it;
1360 0 : std::advance(itEnd, nDataSize);
1361 :
1362 0 : std::vector<ScFormulaCell*> aCloned;
1363 0 : aCloned.reserve(nDataSize);
1364 0 : ScAddress aDestPos(mrDestCol.GetCol(), nTopRow, mrDestCol.GetTab());
1365 0 : for (; it != itEnd; ++it, aDestPos.IncRow())
1366 : {
1367 0 : const ScFormulaCell& rOld = **it;
1368 0 : if (rOld.GetDirty() && mrSrcCol.GetDoc().GetAutoCalc())
1369 0 : const_cast<ScFormulaCell&>(rOld).Interpret();
1370 :
1371 0 : aCloned.push_back(new ScFormulaCell(rOld, mrDestCol.GetDoc(), aDestPos));
1372 : }
1373 :
1374 : // Group the cloned formula cells.
1375 0 : if (!aCloned.empty())
1376 0 : sc::SharedFormulaUtil::groupFormulaCells(aCloned.begin(), aCloned.end());
1377 :
1378 0 : sc::CellStoreType& rDestCells = mrDestCol.GetCellStore();
1379 0 : maDestPos.miCellPos = rDestCells.set(
1380 0 : maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
1381 :
1382 : // Merge adjacent formula cell groups (if applicable).
1383 : sc::CellStoreType::position_type aPos =
1384 0 : rDestCells.position(maDestPos.miCellPos, nTopRow);
1385 0 : maDestPos.miCellPos = aPos.first;
1386 0 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1387 0 : size_t nLastRow = nTopRow + nDataSize;
1388 0 : if (nLastRow < static_cast<size_t>(MAXROW))
1389 : {
1390 0 : aPos = rDestCells.position(maDestPos.miCellPos, nLastRow+1);
1391 0 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1392 0 : }
1393 : }
1394 0 : break;
1395 : default:
1396 0 : bSet = false;
1397 : }
1398 :
1399 0 : if (bSet)
1400 0 : setDefaultAttrsToDest(nTopRow, nDataSize);
1401 :
1402 0 : if (mbCopyNotes)
1403 0 : duplicateNotes(nTopRow, nDataSize);
1404 0 : }
1405 : };
1406 :
1407 : }
1408 :
1409 0 : void ScColumn::CopyToClip(
1410 : sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
1411 : {
1412 : pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
1413 0 : rCxt.isKeepScenarioFlags() ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
1414 :
1415 0 : CopyToClipHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), rCxt.isCloneNotes());
1416 0 : sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1417 :
1418 0 : rColumn.CellStorageModified();
1419 0 : }
1420 :
1421 0 : void ScColumn::CopyStaticToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol)
1422 : {
1423 0 : if (nRow1 > nRow2)
1424 0 : return;
1425 :
1426 0 : sc::ColumnBlockPosition aDestPos;
1427 0 : CopyCellTextAttrsToDocument(nRow1, nRow2, rDestCol);
1428 0 : CopyCellNotesToDocument(nRow1, nRow2, rDestCol);
1429 :
1430 : // First, clear the destination column for the specified row range.
1431 0 : rDestCol.maCells.set_empty(nRow1, nRow2);
1432 :
1433 0 : aDestPos.miCellPos = rDestCol.maCells.begin();
1434 :
1435 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
1436 0 : sc::CellStoreType::const_iterator it = aPos.first;
1437 0 : size_t nOffset = aPos.second;
1438 0 : size_t nDataSize = 0;
1439 0 : size_t nCurRow = nRow1;
1440 :
1441 0 : for (; it != maCells.end() && nCurRow <= static_cast<size_t>(nRow2); ++it, nOffset = 0, nCurRow += nDataSize)
1442 : {
1443 0 : bool bLastBlock = false;
1444 0 : nDataSize = it->size - nOffset;
1445 0 : if (nCurRow + nDataSize - 1 > static_cast<size_t>(nRow2))
1446 : {
1447 : // Truncate the block to copy to clipboard.
1448 0 : nDataSize = nRow2 - nCurRow + 1;
1449 0 : bLastBlock = true;
1450 : }
1451 :
1452 0 : switch (it->type)
1453 : {
1454 : case sc::element_type_numeric:
1455 : {
1456 0 : sc::numeric_block::const_iterator itData = sc::numeric_block::begin(*it->data);
1457 0 : std::advance(itData, nOffset);
1458 0 : sc::numeric_block::const_iterator itDataEnd = itData;
1459 0 : std::advance(itDataEnd, nDataSize);
1460 0 : aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1461 : }
1462 0 : break;
1463 : case sc::element_type_string:
1464 : {
1465 0 : sc::string_block::const_iterator itData = sc::string_block::begin(*it->data);
1466 0 : std::advance(itData, nOffset);
1467 0 : sc::string_block::const_iterator itDataEnd = itData;
1468 0 : std::advance(itDataEnd, nDataSize);
1469 0 : aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1470 : }
1471 0 : 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 0 : sc::formula_block::const_iterator itData = sc::formula_block::begin(*it->data);
1494 0 : std::advance(itData, nOffset);
1495 0 : sc::formula_block::const_iterator itDataEnd = itData;
1496 0 : std::advance(itDataEnd, nDataSize);
1497 :
1498 : // Interpret and convert to raw values.
1499 0 : for (SCROW i = 0; itData != itDataEnd; ++itData, ++i)
1500 : {
1501 0 : SCROW nRow = nCurRow + i;
1502 :
1503 0 : ScFormulaCell& rFC = const_cast<ScFormulaCell&>(**itData);
1504 0 : if (rFC.GetDirty() && pDocument->GetAutoCalc())
1505 0 : rFC.Interpret();
1506 :
1507 0 : if (rFC.GetErrCode())
1508 : // Skip cells with error.
1509 0 : break;
1510 :
1511 0 : if (rFC.IsValue())
1512 0 : 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 0 : break;
1522 : default:
1523 : ;
1524 : }
1525 :
1526 0 : if (bLastBlock)
1527 0 : break;
1528 : }
1529 :
1530 0 : rDestCol.CellStorageModified();
1531 : }
1532 :
1533 0 : void ScColumn::CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol )
1534 : {
1535 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nSrcRow);
1536 0 : sc::CellStoreType::const_iterator it = aPos.first;
1537 0 : bool bSet = true;
1538 0 : 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 0 : rDestCol.maCells.set(nDestRow, sc::string_block::at(*it->data, aPos.second));
1545 0 : 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 0 : if (bSet)
1575 : {
1576 0 : rDestCol.maCellTextAttrs.set(nDestRow, maCellTextAttrs.get<sc::CellTextAttr>(nSrcRow));
1577 0 : ScPostIt* pNote = maCellNotes.get<ScPostIt*>(nSrcRow);
1578 0 : rDestCol.maCellNotes.set(nDestRow, pNote);
1579 0 : 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 0 : rDestCol.CellStorageModified();
1589 0 : }
1590 :
1591 : namespace {
1592 :
1593 0 : bool canCopyValue(const ScDocument& rDoc, const ScAddress& rPos, sal_uInt16 nFlags)
1594 : {
1595 0 : sal_uInt32 nNumIndex = static_cast<const SfxUInt32Item*>(rDoc.GetAttr(rPos, ATTR_VALUE_FORMAT))->GetValue();
1596 0 : short nType = rDoc.GetFormatTable()->GetType(nNumIndex);
1597 0 : if ((nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME))
1598 0 : return ((nFlags & IDF_DATETIME) != 0);
1599 :
1600 0 : 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 0 : void setDefaultAttrToDest(size_t nRow)
1733 : {
1734 0 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1735 0 : maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1736 0 : }
1737 :
1738 0 : void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1739 : {
1740 0 : std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1741 0 : maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1742 0 : maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1743 0 : }
1744 :
1745 0 : void cloneFormulaCell(size_t nRow, ScFormulaCell& rSrcCell)
1746 : {
1747 0 : ScAddress aDestPos(mrDestCol.GetCol(), nRow, mrDestCol.GetTab());
1748 :
1749 0 : bool bCloneValue = (mnCopyFlags & IDF_VALUE) != 0;
1750 0 : bool bCloneDateTime = (mnCopyFlags & IDF_DATETIME) != 0;
1751 0 : bool bCloneString = (mnCopyFlags & IDF_STRING) != 0;
1752 0 : bool bCloneSpecialBoolean = (mnCopyFlags & IDF_SPECIAL_BOOLEAN) != 0;
1753 0 : bool bCloneFormula = (mnCopyFlags & IDF_FORMULA) != 0;
1754 :
1755 0 : bool bForceFormula = false;
1756 :
1757 0 : 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 0 : if (bForceFormula || bCloneFormula)
1771 : {
1772 : // Clone as formula cell.
1773 0 : ScFormulaCell* pCell = new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos);
1774 0 : pCell->SetDirtyVar();
1775 0 : mrDestCol.SetFormulaCell(maDestPos, nRow, pCell);
1776 0 : setDefaultAttrToDest(nRow);
1777 0 : 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 0 : void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1838 : {
1839 0 : mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1840 0 : }
1841 :
1842 : public:
1843 0 : 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 0 : mnCopyFlags(nCopyFlags)
1847 : {
1848 0 : if (mpDestPos)
1849 0 : maDestPos = *mpDestPos;
1850 0 : }
1851 :
1852 0 : ~CopyByCloneHandler()
1853 : {
1854 0 : if (mpDestPos)
1855 0 : *mpDestPos = maDestPos;
1856 0 : }
1857 :
1858 0 : void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1859 : {
1860 0 : size_t nRow = aNode.position + nOffset;
1861 :
1862 0 : if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
1863 : {
1864 0 : bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == 0;
1865 0 : duplicateNotes(nRow, nDataSize, bCloneCaption );
1866 : }
1867 :
1868 0 : switch (aNode.type)
1869 : {
1870 : case sc::element_type_numeric:
1871 : {
1872 0 : if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == 0)
1873 0 : return;
1874 :
1875 0 : sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1876 0 : std::advance(it, nOffset);
1877 0 : sc::numeric_block::const_iterator itEnd = it;
1878 0 : std::advance(itEnd, nDataSize);
1879 :
1880 0 : ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1881 0 : for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1882 : {
1883 0 : if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1884 0 : continue;
1885 :
1886 0 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, *it);
1887 0 : setDefaultAttrToDest(nRow);
1888 : }
1889 : }
1890 0 : break;
1891 : case sc::element_type_string:
1892 : {
1893 0 : if (!(mnCopyFlags & IDF_STRING))
1894 0 : return;
1895 :
1896 0 : sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
1897 0 : std::advance(it, nOffset);
1898 0 : sc::string_block::const_iterator itEnd = it;
1899 0 : std::advance(itEnd, nDataSize);
1900 :
1901 0 : for (; it != itEnd; ++it, ++nRow)
1902 : {
1903 0 : const svl::SharedString& rStr = *it;
1904 0 : 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 0 : if (mpSharedStringPool)
1915 : {
1916 : // Re-intern the string if source is a different document.
1917 0 : svl::SharedString aInterned = mpSharedStringPool->intern( rStr.getString());
1918 0 : maDestPos.miCellPos =
1919 0 : mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aInterned);
1920 : }
1921 : else
1922 : {
1923 0 : maDestPos.miCellPos =
1924 0 : mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rStr);
1925 : }
1926 0 : setDefaultAttrToDest(nRow);
1927 : }
1928 : }
1929 : }
1930 0 : break;
1931 : case sc::element_type_edittext:
1932 : {
1933 0 : if (!(mnCopyFlags & IDF_STRING))
1934 0 : return;
1935 :
1936 0 : sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
1937 0 : std::advance(it, nOffset);
1938 0 : sc::edittext_block::const_iterator itEnd = it;
1939 0 : std::advance(itEnd, nDataSize);
1940 :
1941 0 : std::vector<EditTextObject*> aCloned;
1942 0 : aCloned.reserve(nDataSize);
1943 0 : for (; it != itEnd; ++it)
1944 0 : aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
1945 :
1946 0 : maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1947 0 : maDestPos.miCellPos, nRow, aCloned.begin(), aCloned.end());
1948 :
1949 0 : setDefaultAttrsToDest(nRow, nDataSize);
1950 : }
1951 0 : break;
1952 : case sc::element_type_formula:
1953 : {
1954 0 : sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
1955 0 : std::advance(it, nOffset);
1956 0 : sc::formula_block::const_iterator itEnd = it;
1957 0 : std::advance(itEnd, nDataSize);
1958 :
1959 0 : for (; it != itEnd; ++it, ++nRow)
1960 0 : cloneFormulaCell(nRow, const_cast<ScFormulaCell&>(**it));
1961 : }
1962 0 : break;
1963 : default:
1964 : ;
1965 : }
1966 : }
1967 : };
1968 :
1969 : }
1970 :
1971 0 : 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 0 : if (bMarked)
1977 : {
1978 : SCROW nStart, nEnd;
1979 0 : if (pMarkData && pMarkData->IsMultiMarked())
1980 : {
1981 0 : ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
1982 :
1983 0 : while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
1984 : {
1985 0 : if ( nEnd >= nRow1 )
1986 0 : CopyToColumn(rCxt, std::max(nRow1,nStart), std::min(nRow2,nEnd),
1987 0 : nFlags, false, rColumn, pMarkData, bAsLink );
1988 0 : }
1989 : }
1990 : else
1991 : {
1992 : OSL_FAIL("CopyToColumn: bMarked, but no mark");
1993 : }
1994 0 : return;
1995 : }
1996 :
1997 0 : if ( (nFlags & IDF_ATTRIB) != 0 )
1998 : {
1999 0 : 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 0 : pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
2015 : }
2016 :
2017 0 : if ((nFlags & IDF_CONTENTS) != 0)
2018 : {
2019 0 : 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 0 : (pDocument->GetPool() != rColumn.pDocument->GetPool()) ?
2030 0 : &rColumn.pDocument->GetSharedStringPool() : NULL;
2031 : CopyByCloneHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags,
2032 0 : pSharedStringPool);
2033 0 : sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
2034 : }
2035 :
2036 0 : rColumn.CellStorageModified();
2037 : }
2038 : }
2039 :
2040 :
2041 0 : 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 0 : if (nRow1 > 0)
2046 0 : CopyToColumn(rCxt, 0, nRow1-1, IDF_FORMULA, false, rColumn);
2047 :
2048 0 : CopyToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData); //! bMarked ????
2049 :
2050 0 : if (nRow2 < MAXROW)
2051 0 : CopyToColumn(rCxt, nRow2+1, MAXROW, IDF_FORMULA, false, rColumn);
2052 0 : }
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 0 : void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
2162 : {
2163 0 : ScRange aRange( nCol, 0, nTab );
2164 :
2165 0 : ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
2166 0 : SCROW nStart = -1, nEnd = -1;
2167 0 : const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
2168 0 : while (pPattern)
2169 : {
2170 0 : if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
2171 : {
2172 0 : aRange.aStart.SetRow( nStart );
2173 0 : aRange.aEnd.SetRow( nEnd );
2174 0 : rDestMark.SetMultiMarkArea( aRange, true );
2175 : }
2176 :
2177 0 : pPattern = aAttrIter.Next( nStart, nEnd );
2178 : }
2179 0 : }
2180 :
2181 : namespace {
2182 :
2183 0 : void resetColumnPosition(sc::CellStoreType& rCells, SCCOL nCol)
2184 : {
2185 0 : sc::CellStoreType::iterator it = rCells.begin(), itEnd = rCells.end();
2186 0 : for (; it != itEnd; ++it)
2187 : {
2188 0 : if (it->type != sc::element_type_formula)
2189 0 : continue;
2190 :
2191 0 : sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
2192 0 : sc::formula_block::iterator itCellEnd = sc::formula_block::end(*it->data);
2193 0 : for (; itCell != itCellEnd; ++itCell)
2194 : {
2195 0 : ScFormulaCell& rCell = **itCell;
2196 0 : rCell.aPos.SetCol(nCol);
2197 : }
2198 : }
2199 0 : }
2200 :
2201 : }
2202 :
2203 0 : void ScColumn::UpdateNoteCaptions()
2204 : {
2205 0 : sc::CellNoteStoreType::const_iterator itBlk = maCellNotes.begin(), itBlkEnd = maCellNotes.end();
2206 0 : sc::cellnote_block::const_iterator itData, itDataEnd;
2207 :
2208 0 : SCROW curRow = 0;
2209 0 : for (;itBlk!=itBlkEnd;++itBlk)
2210 : {
2211 0 : if (itBlk->data)
2212 : {
2213 : // non empty block
2214 0 : itData = sc::cellnote_block::begin(*itBlk->data);
2215 0 : itDataEnd = sc::cellnote_block::end(*itBlk->data);
2216 0 : for(;itData!=itDataEnd; ++itData)
2217 : {
2218 0 : ScPostIt* pNote = *itData;
2219 0 : pNote->UpdateCaptionPos(ScAddress(nCol, curRow, nTab));
2220 0 : curRow +=1;
2221 : }
2222 : }
2223 : else
2224 : {
2225 : // empty block
2226 0 : curRow += itBlk->size;
2227 : }
2228 : }
2229 0 : }
2230 :
2231 0 : void ScColumn::SwapCol(ScColumn& rCol)
2232 : {
2233 0 : maBroadcasters.swap(rCol.maBroadcasters);
2234 0 : maCells.swap(rCol.maCells);
2235 0 : maCellTextAttrs.swap(rCol.maCellTextAttrs);
2236 0 : maCellNotes.swap(rCol.maCellNotes);
2237 :
2238 : // notes update caption
2239 0 : UpdateNoteCaptions();
2240 0 : rCol.UpdateNoteCaptions();
2241 :
2242 0 : ScAttrArray* pTempAttr = rCol.pAttrArray;
2243 0 : rCol.pAttrArray = pAttrArray;
2244 0 : pAttrArray = pTempAttr;
2245 :
2246 : // AttrArray needs to have the right column number
2247 0 : pAttrArray->SetCol(nCol);
2248 0 : rCol.pAttrArray->SetCol(rCol.nCol);
2249 :
2250 0 : std::swap(mbDirtyGroups, rCol.mbDirtyGroups);
2251 :
2252 : // Reset column positions in formula cells.
2253 0 : resetColumnPosition(maCells, nCol);
2254 0 : resetColumnPosition(rCol.maCells, rCol.nCol);
2255 :
2256 0 : CellStorageModified();
2257 0 : rCol.CellStorageModified();
2258 0 : }
2259 :
2260 0 : void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
2261 : {
2262 0 : pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
2263 :
2264 : // Mark the non-empty cells within the specified range, for later broadcasting.
2265 0 : sc::SingleColumnSpanSet aNonEmpties;
2266 0 : aNonEmpties.scan(*this, nStartRow, nEndRow);
2267 0 : sc::SingleColumnSpanSet::SpansType aRanges;
2268 0 : aNonEmpties.getSpans(aRanges);
2269 :
2270 : // Split the formula grouping at the top and bottom boundaries.
2271 0 : sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
2272 0 : sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
2273 0 : aPos = maCells.position(aPos.first, nEndRow+1);
2274 0 : sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
2275 :
2276 : // Do the same with the destination column.
2277 0 : aPos = rCol.maCells.position(nStartRow);
2278 0 : sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
2279 0 : aPos = rCol.maCells.position(aPos.first, nEndRow+1);
2280 0 : sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
2281 :
2282 : // Move the broadcasters to the destination column.
2283 0 : maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow);
2284 0 : maCells.transfer(nStartRow, nEndRow, rCol.maCells, nStartRow);
2285 0 : maCellTextAttrs.transfer(nStartRow, nEndRow, rCol.maCellTextAttrs, nStartRow);
2286 :
2287 : // move the notes to the destination column
2288 0 : maCellNotes.transfer(nStartRow, nEndRow, rCol.maCellNotes, nStartRow);
2289 0 : UpdateNoteCaptions();
2290 :
2291 : // Re-group transferred formula cells.
2292 0 : aPos = rCol.maCells.position(nStartRow);
2293 0 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2294 0 : aPos = rCol.maCells.position(aPos.first, nEndRow+1);
2295 0 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2296 :
2297 0 : CellStorageModified();
2298 0 : rCol.CellStorageModified();
2299 :
2300 : // Broadcast on moved ranges. Area-broadcast only.
2301 0 : ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
2302 0 : ScAddress& rPos = aHint.GetAddress();
2303 0 : sc::SingleColumnSpanSet::SpansType::const_iterator itRange = aRanges.begin(), itRangeEnd = aRanges.end();
2304 0 : for (; itRange != itRangeEnd; ++itRange)
2305 : {
2306 0 : for (SCROW nRow = itRange->mnRow1; nRow <= itRange->mnRow2; ++nRow)
2307 : {
2308 0 : rPos.SetRow(nRow);
2309 0 : pDocument->AreaBroadcast(aHint);
2310 : }
2311 0 : }
2312 0 : }
2313 :
2314 : namespace {
2315 :
2316 : class SubTotalCellPicker
2317 : {
2318 : sc::ColumnSpanSet& mrSet;
2319 : SCTAB mnTab;
2320 : SCCOL mnCol;
2321 : bool mbVal;
2322 : public:
2323 0 : SubTotalCellPicker(sc::ColumnSpanSet& rSet, SCTAB nTab, SCCOL nCol, bool bVal) :
2324 0 : mrSet(rSet), mnTab(nTab), mnCol(nCol), mbVal(bVal) {}
2325 :
2326 0 : void operator() (size_t nRow, const ScFormulaCell* pCell)
2327 : {
2328 0 : if (pCell->IsSubTotal())
2329 0 : mrSet.set(mnTab, mnCol, nRow, mbVal);
2330 0 : }
2331 : };
2332 :
2333 : }
2334 :
2335 0 : void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nRow2, bool bVal ) const
2336 : {
2337 0 : SubTotalCellPicker aFunc(rSet, nTab, nCol, bVal);
2338 0 : sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
2339 0 : }
2340 :
2341 : namespace {
2342 :
2343 0 : class SharedTopFormulaCellPicker : std::unary_function<sc::CellStoreType::value_type, void>
2344 : {
2345 : public:
2346 0 : virtual ~SharedTopFormulaCellPicker() {}
2347 :
2348 0 : void operator() ( sc::CellStoreType::value_type& node )
2349 : {
2350 0 : if (node.type != sc::element_type_formula)
2351 0 : return;
2352 :
2353 0 : size_t nTopRow = node.position;
2354 :
2355 0 : sc::formula_block::iterator itBeg = sc::formula_block::begin(*node.data);
2356 0 : 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 0 : for (sc::formula_block::iterator it = itBeg; it != itEnd; ++it)
2361 : {
2362 0 : ScFormulaCell* pCell = *it;
2363 0 : size_t nRow = nTopRow + std::distance(itBeg, it);
2364 0 : if (!pCell->IsShared())
2365 : {
2366 0 : processNonShared(pCell, nRow);
2367 0 : continue;
2368 : }
2369 :
2370 0 : if (pCell->IsSharedTop())
2371 : {
2372 0 : ScFormulaCell** pp = &(*it);
2373 0 : 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 0 : size_t nOffsetToLast = pCell->GetSharedLength() - 1;
2378 0 : std::advance(it, nOffsetToLast);
2379 : }
2380 : }
2381 : }
2382 :
2383 0 : 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 0 : UpdateRefOnCopy(const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc) :
2395 0 : mrCxt(rCxt), mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2396 :
2397 0 : bool isUpdated() const { return mbUpdated; }
2398 :
2399 0 : void operator() (sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2400 : {
2401 0 : if (node.type != sc::element_type_formula)
2402 0 : return;
2403 :
2404 0 : sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
2405 0 : std::advance(it, nOffset);
2406 0 : sc::formula_block::iterator itEnd = it;
2407 0 : std::advance(itEnd, nDataSize);
2408 :
2409 0 : for (; it != itEnd; ++it)
2410 : {
2411 0 : ScFormulaCell& rCell = **it;
2412 0 : 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 0 : void updateRefOnShift( sc::FormulaGroupEntry& rGroup )
2426 : {
2427 0 : if (!rGroup.mbShared)
2428 : {
2429 0 : ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2430 0 : mbUpdated |= rGroup.mpCell->UpdateReferenceOnShift(*mpCxt, mpUndoDoc, &aUndoPos);
2431 0 : return;
2432 : }
2433 :
2434 : // Update references of a formula group.
2435 0 : ScFormulaCell** pp = rGroup.mpCells;
2436 0 : ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2437 0 : ScFormulaCell* pTop = *pp;
2438 0 : ScTokenArray* pCode = pTop->GetCode();
2439 0 : boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
2440 0 : ScAddress aOldPos = pTop->aPos;
2441 :
2442 : // Run this before the position gets updated.
2443 0 : sc::RefUpdateResult aRes = pCode->AdjustReferenceOnShift(*mpCxt, aOldPos);
2444 :
2445 0 : if (pTop->UpdatePosOnShift(*mpCxt))
2446 : {
2447 : // Update the positions of all formula cells.
2448 0 : for (++pp; pp != ppEnd; ++pp) // skip the top cell.
2449 : {
2450 0 : ScFormulaCell* pFC = *pp;
2451 0 : pFC->aPos.Move(mpCxt->mnColDelta, mpCxt->mnRowDelta, mpCxt->mnTabDelta);
2452 : }
2453 :
2454 0 : if (pCode->IsRecalcModeOnRefMove())
2455 0 : aRes.mbValueChanged = true;
2456 : }
2457 :
2458 0 : if (aRes.mbReferenceModified)
2459 : {
2460 0 : sc::StartListeningContext aStartCxt(mpCxt->mrDoc);
2461 0 : sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get());
2462 : aEndCxt.setPositionDelta(
2463 0 : ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
2464 :
2465 0 : for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
2466 : {
2467 0 : ScFormulaCell* p = *pp;
2468 0 : p->EndListeningTo(aEndCxt);
2469 0 : p->SetNeedsListening(true);
2470 : }
2471 :
2472 0 : mbUpdated = true;
2473 :
2474 0 : fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
2475 : }
2476 :
2477 0 : if (aRes.mbValueChanged)
2478 : {
2479 0 : for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
2480 : {
2481 0 : ScFormulaCell* p = *pp;
2482 0 : p->SetNeedsDirty(true);
2483 : }
2484 0 : }
2485 : }
2486 :
2487 0 : void updateRefOnMove( sc::FormulaGroupEntry& rGroup )
2488 : {
2489 0 : if (!rGroup.mbShared)
2490 : {
2491 0 : ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2492 0 : mbUpdated |= rGroup.mpCell->UpdateReferenceOnMove(*mpCxt, mpUndoDoc, &aUndoPos);
2493 0 : return;
2494 : }
2495 :
2496 : // Update references of a formula group.
2497 0 : ScFormulaCell** pp = rGroup.mpCells;
2498 0 : ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2499 0 : ScFormulaCell* pTop = *pp;
2500 0 : ScTokenArray* pCode = pTop->GetCode();
2501 0 : boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
2502 :
2503 0 : ScAddress aPos = pTop->aPos;
2504 0 : ScAddress aOldPos = aPos;
2505 :
2506 0 : 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 0 : bool bRecalcOnMove = pCode->IsRecalcModeOnRefMove();
2520 0 : if (bRecalcOnMove)
2521 0 : bRecalcOnMove = aPos != aOldPos;
2522 :
2523 0 : sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(*mpCxt, aOldPos, aPos);
2524 :
2525 0 : if (aRes.mbReferenceModified || aRes.mbNameModified || bRecalcOnMove)
2526 : {
2527 0 : sc::AutoCalcSwitch(mpCxt->mrDoc, false);
2528 :
2529 0 : 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 0 : ScCompiler aComp(&mpCxt->mrDoc, aPos, *pCode);
2535 0 : aComp.SetGrammar(mpCxt->mrDoc.GetGrammar());
2536 0 : aComp.CompileTokenArray();
2537 : }
2538 :
2539 : // Perform end-listening, start-listening, and dirtying on all
2540 : // formula cells in the group.
2541 :
2542 0 : sc::StartListeningContext aStartCxt(mpCxt->mrDoc);
2543 :
2544 0 : sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get());
2545 : aEndCxt.setPositionDelta(
2546 0 : ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
2547 :
2548 0 : for (; pp != ppEnd; ++pp)
2549 : {
2550 0 : ScFormulaCell* p = *pp;
2551 0 : p->EndListeningTo(aEndCxt);
2552 0 : p->StartListeningTo(aStartCxt);
2553 0 : p->SetDirty();
2554 : }
2555 :
2556 0 : fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
2557 0 : }
2558 : }
2559 :
2560 0 : void fillUndoDoc( const ScAddress& rOldPos, SCROW nLength, const ScTokenArray& rOldCode )
2561 : {
2562 0 : if (!mpUndoDoc || nLength <= 0)
2563 0 : return;
2564 :
2565 : // Insert the old formula group into the undo document.
2566 0 : ScAddress aUndoPos = rOldPos;
2567 0 : ScFormulaCell* pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, rOldCode.Clone());
2568 :
2569 0 : if (nLength == 1)
2570 : {
2571 0 : mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
2572 0 : return;
2573 : }
2574 :
2575 0 : std::vector<ScFormulaCell*> aCells;
2576 0 : aCells.reserve(nLength);
2577 0 : ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(nLength, false);
2578 0 : aCells.push_back(pFC);
2579 0 : aUndoPos.IncRow();
2580 0 : for (SCROW i = 1; i < nLength; ++i, aUndoPos.IncRow())
2581 : {
2582 0 : pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, xGroup);
2583 0 : aCells.push_back(pFC);
2584 : }
2585 :
2586 0 : if (!mpUndoDoc->SetFormulaCells(rOldPos, aCells))
2587 : // Insertion failed. Delete all formula cells.
2588 0 : std::for_each(aCells.begin(), aCells.end(), ScDeleteObjectByPtr<ScFormulaCell>());
2589 : }
2590 :
2591 : public:
2592 0 : UpdateRefOnNonCopy(
2593 : SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext* pCxt,
2594 : ScDocument* pUndoDoc) :
2595 : mnCol(nCol), mnTab(nTab), mpCxt(pCxt),
2596 0 : mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2597 :
2598 0 : void operator() ( sc::FormulaGroupEntry& rGroup )
2599 : {
2600 0 : switch (mpCxt->meMode)
2601 : {
2602 : case URM_INSDEL:
2603 0 : updateRefOnShift(rGroup);
2604 0 : return;
2605 : case URM_MOVE:
2606 0 : updateRefOnMove(rGroup);
2607 0 : 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 0 : bool isUpdated() const { return mbUpdated; }
2631 : };
2632 :
2633 0 : class UpdateRefGroupBoundChecker : public SharedTopFormulaCellPicker
2634 : {
2635 : const sc::RefUpdateContext& mrCxt;
2636 : std::vector<SCROW>& mrBounds;
2637 :
2638 : public:
2639 0 : UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
2640 0 : mrCxt(rCxt), mrBounds(rBounds) {}
2641 :
2642 0 : virtual ~UpdateRefGroupBoundChecker() {}
2643 :
2644 0 : virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) SAL_OVERRIDE
2645 : {
2646 : // Check its tokens and record its reference boundaries.
2647 0 : ScFormulaCell& rCell = **ppCells;
2648 0 : const ScTokenArray& rCode = *rCell.GetCode();
2649 : rCode.CheckRelativeReferenceBounds(
2650 0 : mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
2651 0 : }
2652 : };
2653 :
2654 0 : class FormulaGroupPicker : public SharedTopFormulaCellPicker
2655 : {
2656 : std::vector<sc::FormulaGroupEntry>& mrGroups;
2657 :
2658 : public:
2659 0 : FormulaGroupPicker( std::vector<sc::FormulaGroupEntry>& rGroups ) : mrGroups(rGroups) {}
2660 :
2661 0 : virtual ~FormulaGroupPicker() {}
2662 :
2663 0 : virtual void processNonShared( ScFormulaCell* pCell, size_t nRow ) SAL_OVERRIDE
2664 : {
2665 0 : mrGroups.push_back(sc::FormulaGroupEntry(pCell, nRow));
2666 0 : }
2667 :
2668 0 : virtual void processSharedTop( ScFormulaCell** ppCells, size_t nRow, size_t nLength ) SAL_OVERRIDE
2669 : {
2670 0 : mrGroups.push_back(sc::FormulaGroupEntry(ppCells, nRow, nLength));
2671 0 : }
2672 : };
2673 :
2674 : }
2675 :
2676 0 : 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 0 : UpdateRefOnCopy aHandler(rCxt, pUndoDoc);
2683 0 : sc::CellStoreType::position_type aPos = maCells.position(rCxt.maRange.aStart.Row());
2684 0 : 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 0 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2689 0 : if (rCxt.maRange.aEnd.Row() < MAXROW)
2690 : {
2691 0 : aPos = maCells.position(aPos.first, rCxt.maRange.aEnd.Row()+1);
2692 0 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
2693 : }
2694 :
2695 0 : return aHandler.isUpdated();
2696 : }
2697 :
2698 0 : bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
2699 : {
2700 0 : if (rCxt.meMode == URM_COPY)
2701 0 : return UpdateReferenceOnCopy(rCxt, pUndoDoc);
2702 :
2703 0 : if (IsEmptyData() || pDocument->IsClipOrUndo())
2704 : // Cells in this column are all empty, or clip or undo doc. No update needed.
2705 0 : return false;
2706 :
2707 0 : std::vector<SCROW> aBounds;
2708 :
2709 0 : bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
2710 0 : rCxt.maRange.aStart.Col() <= nCol && nCol <= rCxt.maRange.aEnd.Col());
2711 0 : 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 0 : if (rCxt.mnRowDelta < 0)
2719 : {
2720 0 : nSplitPos = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
2721 0 : if (ValidRow(nSplitPos))
2722 0 : aBounds.push_back(nSplitPos);
2723 : }
2724 0 : nSplitPos = rCxt.maRange.aStart.Row();
2725 0 : if (ValidRow(nSplitPos))
2726 : {
2727 0 : aBounds.push_back(nSplitPos);
2728 0 : nSplitPos = rCxt.maRange.aEnd.Row() + 1;
2729 0 : if (ValidRow(nSplitPos))
2730 0 : aBounds.push_back(nSplitPos);
2731 : }
2732 : }
2733 :
2734 : // Check the row positions at which the group must be split per relative
2735 : // references.
2736 0 : UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
2737 0 : std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
2738 :
2739 : // Do the actual splitting.
2740 0 : sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
2741 :
2742 : // Collect all formula groups.
2743 0 : std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
2744 :
2745 : // Process all collected formula groups.
2746 0 : UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc);
2747 0 : aHandler = std::for_each(aGroups.begin(), aGroups.end(), aHandler);
2748 0 : if (aHandler.isUpdated())
2749 0 : rCxt.maRegroupCols.set(nTab, nCol);
2750 :
2751 0 : return aHandler.isUpdated();
2752 : }
2753 :
2754 0 : std::vector<sc::FormulaGroupEntry> ScColumn::GetFormulaGroupEntries()
2755 : {
2756 0 : std::vector<sc::FormulaGroupEntry> aGroups;
2757 0 : std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups));
2758 0 : 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 0 : InsertTabUpdater(sc::RefUpdateInsertTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2819 : mrCxt(rCxt),
2820 : mrTextAttrs(rTextAttrs),
2821 : miAttrPos(rTextAttrs.begin()),
2822 : mnTab(nTab),
2823 0 : mbModified(false) {}
2824 :
2825 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2826 : {
2827 0 : pCell->UpdateInsertTab(mrCxt);
2828 0 : mbModified = true;
2829 0 : }
2830 :
2831 0 : void operator() (size_t nRow, EditTextObject* pCell)
2832 : {
2833 0 : editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2834 0 : aUpdater.updateTableFields(mnTab);
2835 0 : miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2836 0 : mbModified = true;
2837 0 : }
2838 :
2839 0 : 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 0 : DeleteTabUpdater(sc::RefUpdateDeleteTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2851 : mrCxt(rCxt),
2852 : mrTextAttrs(rTextAttrs),
2853 : miAttrPos(rTextAttrs.begin()),
2854 : mnTab(nTab),
2855 0 : mbModified(false) {}
2856 :
2857 0 : void operator() (size_t, ScFormulaCell* pCell)
2858 : {
2859 0 : pCell->UpdateDeleteTab(mrCxt);
2860 0 : mbModified = true;
2861 0 : }
2862 :
2863 0 : void operator() (size_t nRow, EditTextObject* pCell)
2864 : {
2865 0 : editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2866 0 : aUpdater.updateTableFields(mnTab);
2867 0 : miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2868 0 : mbModified = true;
2869 0 : }
2870 :
2871 0 : 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 0 : InsertAbsTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nNewPos) :
2883 : mrTextAttrs(rTextAttrs),
2884 : miAttrPos(rTextAttrs.begin()),
2885 : mnTab(nTab),
2886 : mnNewPos(nNewPos),
2887 0 : mbModified(false) {}
2888 :
2889 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2890 : {
2891 0 : pCell->UpdateInsertTabAbs(mnNewPos);
2892 0 : mbModified = true;
2893 0 : }
2894 :
2895 0 : void operator() (size_t nRow, EditTextObject* pCell)
2896 : {
2897 0 : editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2898 0 : aUpdater.updateTableFields(mnTab);
2899 0 : miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2900 0 : mbModified = true;
2901 0 : }
2902 :
2903 0 : 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 0 : MoveTabUpdater(sc::RefUpdateMoveTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2915 : mrCxt(rCxt),
2916 : mrTextAttrs(rTextAttrs),
2917 : miAttrPos(rTextAttrs.begin()),
2918 : mnTab(nTab),
2919 0 : mbModified(false) {}
2920 :
2921 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2922 : {
2923 0 : pCell->UpdateMoveTab(mrCxt, mnTab);
2924 0 : mbModified = true;
2925 0 : }
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 0 : bool isModified() const { return mbModified; }
2936 : };
2937 :
2938 : class UpdateCompileHandler
2939 : {
2940 : bool mbForceIfNameInUse:1;
2941 : public:
2942 0 : UpdateCompileHandler(bool bForceIfNameInUse) :
2943 0 : mbForceIfNameInUse(bForceIfNameInUse) {}
2944 :
2945 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2946 : {
2947 0 : pCell->UpdateCompile(mbForceIfNameInUse);
2948 0 : }
2949 : };
2950 :
2951 : class TabNoSetter
2952 : {
2953 : SCTAB mnTab;
2954 : public:
2955 0 : TabNoSetter(SCTAB nTab) : mnTab(nTab) {}
2956 :
2957 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2958 : {
2959 0 : pCell->aPos.SetTab(mnTab);
2960 0 : }
2961 : };
2962 :
2963 : class UsedRangeNameFinder
2964 : {
2965 : std::set<sal_uInt16>& mrIndexes;
2966 : public:
2967 0 : UsedRangeNameFinder(std::set<sal_uInt16>& rIndexes) : mrIndexes(rIndexes) {}
2968 :
2969 0 : void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
2970 : {
2971 0 : pCell->FindRangeNamesInUse(mrIndexes);
2972 0 : }
2973 : };
2974 :
2975 : struct SetDirtyVarHandler
2976 : {
2977 0 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
2978 : {
2979 0 : p->SetDirtyVar();
2980 0 : }
2981 : };
2982 :
2983 : class SetDirtyHandler
2984 : {
2985 : ScDocument& mrDoc;
2986 : const sc::SetFormulaDirtyContext& mrCxt;
2987 : public:
2988 0 : SetDirtyHandler( ScDocument& rDoc, const sc::SetFormulaDirtyContext& rCxt ) :
2989 0 : mrDoc(rDoc), mrCxt(rCxt) {}
2990 :
2991 0 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
2992 : {
2993 0 : if (mrCxt.mbClearTabDeletedFlag)
2994 : {
2995 0 : if (!p->IsShared() || p->IsSharedTop())
2996 : {
2997 0 : ScTokenArray* pCode = p->GetCode();
2998 : pCode->ClearTabDeleted(
2999 0 : p->aPos, mrCxt.mnTabDeletedStart, mrCxt.mnTabDeletedEnd);
3000 : }
3001 : }
3002 :
3003 0 : p->SetDirtyVar();
3004 0 : if (!mrDoc.IsInFormulaTree(p))
3005 0 : mrDoc.PutInFormulaTree(p);
3006 0 : }
3007 : };
3008 :
3009 0 : class SetDirtyOnRangeHandler
3010 : {
3011 : sc::SingleColumnSpanSet maValueRanges;
3012 : ScColumn& mrColumn;
3013 : public:
3014 0 : SetDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
3015 :
3016 0 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
3017 : {
3018 0 : p->SetDirty();
3019 0 : }
3020 :
3021 0 : void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
3022 : {
3023 0 : if (type == sc::element_type_empty)
3024 : // Ignore empty blocks.
3025 0 : return;
3026 :
3027 : // Non-formula cells.
3028 0 : SCROW nRow1 = nTopRow;
3029 0 : SCROW nRow2 = nTopRow + nDataSize - 1;
3030 0 : maValueRanges.set(nRow1, nRow2, true);
3031 : }
3032 :
3033 0 : void broadcast()
3034 : {
3035 0 : std::vector<SCROW> aRows;
3036 0 : maValueRanges.getRows(aRows);
3037 0 : mrColumn.BroadcastCells(aRows, SC_HINT_DATACHANGED);
3038 0 : }
3039 : };
3040 :
3041 0 : class SetTableOpDirtyOnRangeHandler
3042 : {
3043 : sc::SingleColumnSpanSet maValueRanges;
3044 : ScColumn& mrColumn;
3045 : public:
3046 0 : SetTableOpDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
3047 :
3048 0 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
3049 : {
3050 0 : p->SetTableOpDirty();
3051 0 : }
3052 :
3053 0 : void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
3054 : {
3055 0 : if (type == sc::element_type_empty)
3056 : // Ignore empty blocks.
3057 0 : return;
3058 :
3059 : // Non-formula cells.
3060 0 : SCROW nRow1 = nTopRow;
3061 0 : SCROW nRow2 = nTopRow + nDataSize - 1;
3062 0 : maValueRanges.set(nRow1, nRow2, true);
3063 : }
3064 :
3065 0 : void broadcast()
3066 : {
3067 0 : std::vector<SCROW> aRows;
3068 0 : maValueRanges.getRows(aRows);
3069 0 : mrColumn.BroadcastCells(aRows, SC_HINT_TABLEOPDIRTY);
3070 0 : }
3071 : };
3072 :
3073 : struct SetDirtyAfterLoadHandler
3074 : {
3075 0 : 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 0 : 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 0 : }
3098 : };
3099 :
3100 : struct SetDirtyIfPostponedHandler
3101 : {
3102 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
3103 : {
3104 0 : if (pCell->IsPostponedDirty() || pCell->HasRelNameReference())
3105 0 : pCell->SetDirty();
3106 0 : }
3107 : };
3108 :
3109 : struct CalcAllHandler
3110 : {
3111 0 : 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 0 : 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 0 : }
3128 : };
3129 :
3130 : class CompileAllHandler
3131 : {
3132 : sc::CompileFormulaContext& mrCxt;
3133 : public:
3134 0 : CompileAllHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
3135 :
3136 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
3137 : {
3138 : // for unconditional compilation
3139 : // bCompile=true and pCode->nError=0
3140 0 : pCell->GetCode()->SetCodeError(0);
3141 0 : pCell->SetCompile(true);
3142 0 : pCell->CompileTokenArray(mrCxt);
3143 0 : }
3144 : };
3145 :
3146 : class CompileXMLHandler
3147 : {
3148 : sc::CompileFormulaContext& mrCxt;
3149 : ScProgress& mrProgress;
3150 : const ScColumn& mrCol;
3151 : public:
3152 0 : CompileXMLHandler( sc::CompileFormulaContext& rCxt, ScProgress& rProgress, const ScColumn& rCol) :
3153 : mrCxt(rCxt),
3154 : mrProgress(rProgress),
3155 0 : mrCol(rCol) {}
3156 :
3157 0 : void operator() (size_t nRow, ScFormulaCell* pCell)
3158 : {
3159 0 : sal_uInt32 nFormat = mrCol.GetNumberFormat(nRow);
3160 0 : if( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
3161 : // Non-default number format is set.
3162 0 : pCell->SetNeedNumberFormat(false);
3163 0 : else if (pCell->NeedsNumberFormat())
3164 0 : pCell->SetDirtyVar();
3165 :
3166 0 : if (pCell->GetMatrixFlag())
3167 0 : pCell->SetDirtyVar();
3168 :
3169 0 : pCell->CompileXML(mrCxt, mrProgress);
3170 0 : }
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 0 : CalcAfterLoadHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
3220 :
3221 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
3222 : {
3223 0 : pCell->CalcAfterLoad(mrCxt);
3224 0 : }
3225 : };
3226 :
3227 : struct ResetChangedHandler
3228 : {
3229 0 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
3230 : {
3231 0 : pCell->SetChanged(false);
3232 0 : }
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 0 : FindEditCellsHandler(ScColumn& rColumn, sc::CellTextAttrStoreType& rAttrs,
3246 : sc::CellStoreType::iterator rCellItr) :
3247 0 : mrColumn(rColumn), miAttrPos(rAttrs.begin()), miCellPos(rCellItr) {}
3248 :
3249 0 : bool operator() (size_t, const EditTextObject*)
3250 : {
3251 0 : return true;
3252 : }
3253 :
3254 0 : bool operator() (size_t nRow, const ScFormulaCell* p)
3255 : {
3256 0 : sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
3257 0 : if (IsAmbiguousScriptNonZero(nScriptType))
3258 0 : return true;
3259 :
3260 0 : return const_cast<ScFormulaCell*>(p)->IsMultilineResult();
3261 : }
3262 :
3263 0 : 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 0 : if (node.type == sc::element_type_empty)
3268 0 : return RetType(0, false);
3269 :
3270 0 : for (size_t i = 0; i < nDataSize; ++i)
3271 : {
3272 0 : SCROW nRow = node.position + i + nOffset;
3273 0 : sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
3274 0 : if (IsAmbiguousScriptNonZero(nScriptType))
3275 : // Return the offset from the first row.
3276 0 : return RetType(i+nOffset, true);
3277 : }
3278 :
3279 0 : 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 0 : void ScColumn::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
3301 : {
3302 0 : if (nTab >= rCxt.mnInsertPos)
3303 : {
3304 0 : nTab += rCxt.mnSheets;
3305 0 : pAttrArray->SetTab(nTab);
3306 : }
3307 :
3308 0 : UpdateInsertTabOnlyCells(rCxt);
3309 0 : }
3310 :
3311 0 : void ScColumn::UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext& rCxt )
3312 : {
3313 0 : InsertTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3314 0 : sc::ProcessFormulaEditText(maCells, aFunc);
3315 0 : if (aFunc.isModified())
3316 0 : CellStorageModified();
3317 0 : }
3318 :
3319 0 : void ScColumn::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
3320 : {
3321 0 : if (nTab > rCxt.mnDeletePos)
3322 : {
3323 0 : nTab -= rCxt.mnSheets;
3324 0 : pAttrArray->SetTab(nTab);
3325 : }
3326 :
3327 0 : DeleteTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3328 0 : sc::ProcessFormulaEditText(maCells, aFunc);
3329 0 : if (aFunc.isModified())
3330 0 : CellStorageModified();
3331 0 : }
3332 :
3333 0 : void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos)
3334 : {
3335 0 : InsertAbsTabUpdater aFunc(maCellTextAttrs, nTab, nNewPos);
3336 0 : sc::ProcessFormulaEditText(maCells, aFunc);
3337 0 : if (aFunc.isModified())
3338 0 : CellStorageModified();
3339 0 : }
3340 :
3341 0 : void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo )
3342 : {
3343 0 : nTab = nTabNo;
3344 0 : pAttrArray->SetTab( nTabNo );
3345 :
3346 0 : MoveTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3347 0 : sc::ProcessFormulaEditText(maCells, aFunc);
3348 0 : if (aFunc.isModified())
3349 0 : CellStorageModified();
3350 0 : }
3351 :
3352 :
3353 0 : void ScColumn::UpdateCompile( bool bForceIfNameInUse )
3354 : {
3355 0 : UpdateCompileHandler aFunc(bForceIfNameInUse);
3356 0 : sc::ProcessFormula(maCells, aFunc);
3357 0 : }
3358 :
3359 :
3360 0 : void ScColumn::SetTabNo(SCTAB nNewTab)
3361 : {
3362 0 : nTab = nNewTab;
3363 0 : pAttrArray->SetTab( nNewTab );
3364 :
3365 0 : TabNoSetter aFunc(nTab);
3366 0 : sc::ProcessFormula(maCells, aFunc);
3367 0 : }
3368 :
3369 0 : void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
3370 : {
3371 0 : UsedRangeNameFinder aFunc(rIndexes);
3372 0 : sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
3373 0 : }
3374 :
3375 0 : void ScColumn::SetDirtyVar()
3376 : {
3377 : SetDirtyVarHandler aFunc;
3378 0 : sc::ProcessFormula(maCells, aFunc);
3379 0 : }
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 0 : void ScColumn::SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt )
3397 : {
3398 : // is only done documentwide, no FormulaTracking
3399 0 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3400 0 : SetDirtyHandler aFunc(*pDocument, rCxt);
3401 0 : sc::ProcessFormula(maCells, aFunc);
3402 0 : }
3403 :
3404 0 : void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2 )
3405 : {
3406 : // broadcasts everything within the range, with FormulaTracking
3407 0 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3408 :
3409 0 : SetDirtyOnRangeHandler aHdl(*this);
3410 0 : sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3411 0 : aHdl.broadcast();
3412 0 : }
3413 :
3414 0 : void ScColumn::SetTableOpDirty( const ScRange& rRange )
3415 : {
3416 0 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3417 :
3418 0 : SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3419 0 : SetTableOpDirtyOnRangeHandler aHdl(*this);
3420 0 : sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3421 0 : aHdl.broadcast();
3422 0 : }
3423 :
3424 0 : void ScColumn::SetDirtyAfterLoad()
3425 : {
3426 0 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3427 : SetDirtyAfterLoadHandler aFunc;
3428 0 : sc::ProcessFormula(maCells, aFunc);
3429 0 : }
3430 :
3431 : namespace {
3432 :
3433 0 : class RecalcOnRefMoveCollector
3434 : {
3435 : std::vector<SCROW> maDirtyRows;
3436 : public:
3437 0 : void operator() (size_t nRow, ScFormulaCell* pCell)
3438 : {
3439 0 : if (pCell->GetDirty() && pCell->GetCode()->IsRecalcModeOnRefMove())
3440 0 : maDirtyRows.push_back(nRow);
3441 0 : }
3442 :
3443 0 : const std::vector<SCROW>& getDirtyRows() const
3444 : {
3445 0 : return maDirtyRows;
3446 : }
3447 : };
3448 :
3449 : }
3450 :
3451 0 : void ScColumn::SetDirtyIfPostponed()
3452 : {
3453 0 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3454 : SetDirtyIfPostponedHandler aFunc;
3455 0 : sc::ProcessFormula(maCells, aFunc);
3456 0 : }
3457 :
3458 0 : void ScColumn::BroadcastRecalcOnRefMove()
3459 : {
3460 0 : sc::AutoCalcSwitch aSwitch(*pDocument, false);
3461 0 : RecalcOnRefMoveCollector aFunc;
3462 0 : sc::ProcessFormula(maCells, aFunc);
3463 0 : BroadcastCells(aFunc.getDirtyRows(), SC_HINT_DATACHANGED);
3464 0 : }
3465 :
3466 : namespace {
3467 :
3468 : class BroadcastRefMovedHandler
3469 : {
3470 : const sc::RefMovedHint& mrHint;
3471 : public:
3472 0 : BroadcastRefMovedHandler( const sc::RefMovedHint& rHint ) : mrHint(rHint) {}
3473 :
3474 0 : void operator() ( size_t, SvtBroadcaster* p )
3475 : {
3476 0 : p->Broadcast(mrHint);
3477 0 : }
3478 : };
3479 :
3480 : }
3481 :
3482 0 : void ScColumn::BroadcastRefMoved( const sc::RefMovedHint& rHint )
3483 : {
3484 0 : const ScRange& rRange = rHint.getRange();
3485 0 : SCROW nRow1 = rRange.aStart.Row();
3486 0 : SCROW nRow2 = rRange.aEnd.Row();
3487 :
3488 : // Notify all listeners within specified rows.
3489 0 : BroadcastRefMovedHandler aFunc(rHint);
3490 0 : sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
3491 0 : }
3492 :
3493 : namespace {
3494 :
3495 0 : class TransferListenersHandler
3496 : {
3497 : public:
3498 : typedef std::vector<SvtListener*> ListenersType;
3499 0 : struct Entry
3500 : {
3501 : size_t mnRow;
3502 : ListenersType maListeners;
3503 : };
3504 : typedef std::vector<Entry> ListenerListType;
3505 :
3506 0 : void swapListeners( std::vector<Entry>& rListenerList )
3507 : {
3508 0 : maListenerList.swap(rListenerList);
3509 0 : }
3510 :
3511 0 : void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
3512 : {
3513 : assert(pBroadcaster);
3514 :
3515 : // It's important to make a copy here.
3516 0 : SvtBroadcaster::ListenersType aLis = pBroadcaster->GetAllListeners();
3517 0 : if (aLis.empty())
3518 : // No listeners to transfer.
3519 0 : return;
3520 :
3521 0 : Entry aEntry;
3522 0 : aEntry.mnRow = nRow;
3523 :
3524 0 : SvtBroadcaster::ListenersType::iterator it = aLis.begin(), itEnd = aLis.end();
3525 0 : for (; it != itEnd; ++it)
3526 : {
3527 0 : SvtListener* pLis = *it;
3528 0 : pLis->EndListening(*pBroadcaster);
3529 0 : aEntry.maListeners.push_back(pLis);
3530 : }
3531 :
3532 0 : maListenerList.push_back(aEntry);
3533 :
3534 : // At this point, the source broadcaster should have no more listeners.
3535 0 : assert(!pBroadcaster->HasListeners());
3536 : }
3537 :
3538 : private:
3539 : ListenerListType maListenerList;
3540 : };
3541 :
3542 0 : class RemoveEmptyBroadcasterHandler
3543 : {
3544 : sc::ColumnSpanSet maSet;
3545 : ScDocument& mrDoc;
3546 : SCCOL mnCol;
3547 : SCTAB mnTab;
3548 :
3549 : public:
3550 0 : RemoveEmptyBroadcasterHandler( ScDocument& rDoc, SCCOL nCol, SCTAB nTab ) :
3551 0 : maSet(false), mrDoc(rDoc), mnCol(nCol), mnTab(nTab) {}
3552 :
3553 0 : void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
3554 : {
3555 0 : if (!pBroadcaster->HasListeners())
3556 0 : maSet.set(mnTab, mnCol, nRow, true);
3557 0 : }
3558 :
3559 0 : void purge()
3560 : {
3561 0 : sc::PurgeListenerAction aAction(mrDoc);
3562 0 : maSet.executeAction(aAction);
3563 0 : }
3564 : };
3565 :
3566 : }
3567 :
3568 0 : void ScColumn::TransferListeners(
3569 : ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta )
3570 : {
3571 0 : if (nRow2 < nRow1)
3572 0 : return;
3573 :
3574 0 : if (!ValidRow(nRow1) || !ValidRow(nRow2))
3575 0 : return;
3576 :
3577 0 : if (nRowDelta <= 0 && !ValidRow(nRow1+nRowDelta))
3578 0 : return;
3579 :
3580 0 : 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 0 : TransferListenersHandler aFunc;
3586 0 : sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
3587 :
3588 0 : TransferListenersHandler::ListenerListType aListenerList;
3589 0 : aFunc.swapListeners(aListenerList);
3590 :
3591 : // Re-register listeners with their destination broadcasters.
3592 0 : sc::BroadcasterStoreType::iterator itDestPos = rDestCol.maBroadcasters.begin();
3593 0 : TransferListenersHandler::ListenerListType::iterator it = aListenerList.begin(), itEnd = aListenerList.end();
3594 0 : for (; it != itEnd; ++it)
3595 : {
3596 0 : TransferListenersHandler::Entry& rEntry = *it;
3597 :
3598 0 : SCROW nDestRow = rEntry.mnRow + nRowDelta;
3599 :
3600 : sc::BroadcasterStoreType::position_type aPos =
3601 0 : rDestCol.maBroadcasters.position(itDestPos, nDestRow);
3602 :
3603 0 : itDestPos = aPos.first;
3604 0 : SvtBroadcaster* pDestBrd = NULL;
3605 0 : 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 0 : pDestBrd = new SvtBroadcaster;
3615 0 : itDestPos = rDestCol.maBroadcasters.set(itDestPos, nDestRow, pDestBrd);
3616 : }
3617 :
3618 : // Transfer all listeners from the source to the destination.
3619 0 : SvtBroadcaster::ListenersType::iterator it2 = rEntry.maListeners.begin(), it2End = rEntry.maListeners.end();
3620 0 : for (; it2 != it2End; ++it2)
3621 : {
3622 0 : SvtListener* pLis = *it2;
3623 0 : pLis->StartListening(*pDestBrd);
3624 : }
3625 : }
3626 :
3627 : // Remove any broadcasters that have no listeners.
3628 0 : RemoveEmptyBroadcasterHandler aFuncRemoveEmpty(*pDocument, nCol, nTab);
3629 0 : sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFuncRemoveEmpty);
3630 0 : aFuncRemoveEmpty.purge();
3631 : }
3632 :
3633 0 : void ScColumn::CalcAll()
3634 : {
3635 : CalcAllHandler aFunc;
3636 0 : sc::ProcessFormula(maCells, aFunc);
3637 0 : }
3638 :
3639 0 : void ScColumn::CompileAll( sc::CompileFormulaContext& rCxt )
3640 : {
3641 0 : CompileAllHandler aFunc(rCxt);
3642 0 : sc::ProcessFormula(maCells, aFunc);
3643 0 : }
3644 :
3645 0 : void ScColumn::CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rProgress )
3646 : {
3647 0 : CompileXMLHandler aFunc(rCxt, rProgress, *this);
3648 0 : sc::ProcessFormula(maCells, aFunc);
3649 0 : RegroupFormulaCells();
3650 0 : }
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 0 : void ScColumn::CalcAfterLoad( sc::CompileFormulaContext& rCxt )
3660 : {
3661 0 : CalcAfterLoadHandler aFunc(rCxt);
3662 0 : sc::ProcessFormula(maCells, aFunc);
3663 0 : }
3664 :
3665 0 : void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
3666 : {
3667 : ResetChangedHandler aFunc;
3668 0 : sc::ProcessFormula(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
3669 0 : }
3670 :
3671 0 : bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst)
3672 : {
3673 : // used in GetOptimalHeight - ambiguous script type counts as edit cell
3674 :
3675 0 : FindEditCellsHandler aFunc(*this, maCellTextAttrs, maCells.begin());
3676 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
3677 0 : sc::FindFormulaEditText(maCells, nStartRow, nEndRow, aFunc);
3678 :
3679 0 : if (aPos.first == maCells.end())
3680 0 : return false;
3681 :
3682 0 : rFirst = aPos.first->position + aPos.second;
3683 0 : 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 0 : }
3718 :
3719 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|