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 "drwlayer.hxx"
26 : #include "attarray.hxx"
27 : #include "patattr.hxx"
28 : #include "cellform.hxx"
29 : #include "stlsheet.hxx"
30 : #include "rechead.hxx"
31 : #include "brdcst.hxx"
32 : #include "editutil.hxx"
33 : #include "subtotal.hxx"
34 : #include "markdata.hxx"
35 : #include "compiler.hxx"
36 : #include "dbdata.hxx"
37 : #include "fillinfo.hxx"
38 : #include "segmenttree.hxx"
39 : #include "docparam.hxx"
40 : #include "cellvalue.hxx"
41 : #include "tokenarray.hxx"
42 : #include "globalnames.hxx"
43 : #include "formulagroup.hxx"
44 : #include "listenercontext.hxx"
45 : #include "mtvcellfunc.hxx"
46 : #include "progress.hxx"
47 : #include "scmatrix.hxx"
48 : #include <rowheightcontext.hxx>
49 :
50 : #include <math.h>
51 :
52 : #include <editeng/eeitem.hxx>
53 :
54 : #include <svx/algitem.hxx>
55 : #include <editeng/editobj.hxx>
56 : #include <editeng/editstat.hxx>
57 : #include <editeng/emphasismarkitem.hxx>
58 : #include <editeng/fhgtitem.hxx>
59 : #include <editeng/forbiddencharacterstable.hxx>
60 : #include <svx/rotmodit.hxx>
61 : #include <editeng/scripttypeitem.hxx>
62 : #include <editeng/unolingu.hxx>
63 : #include <editeng/justifyitem.hxx>
64 : #include <svl/zforlist.hxx>
65 : #include <svl/broadcast.hxx>
66 : #include <vcl/outdev.hxx>
67 : #include <formula/errorcodes.hxx>
68 : #include <formula/vectortoken.hxx>
69 :
70 : #include <boost/scoped_ptr.hpp>
71 : #include <algorithm>
72 :
73 : // factor from font size to optimal cell height (text width)
74 : #define SC_ROT_BREAK_FACTOR 6
75 :
76 27751 : inline bool IsAmbiguousScript( SvtScriptType nScript )
77 : {
78 : //TODO: move to a header file
79 2 : return ( nScript != SvtScriptType::LATIN &&
80 27751 : nScript != SvtScriptType::ASIAN &&
81 27751 : nScript != SvtScriptType::COMPLEX );
82 : }
83 :
84 : // Data operations
85 :
86 1548 : long ScColumn::GetNeededSize(
87 : SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY,
88 : const Fraction& rZoomX, const Fraction& rZoomY,
89 : bool bWidth, const ScNeededSizeOptions& rOptions,
90 : const ScPatternAttr** ppPatternChange ) const
91 : {
92 1548 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
93 1548 : sc::CellStoreType::const_iterator it = aPos.first;
94 1548 : if (it == maCells.end() || it->type == sc::element_type_empty)
95 : // Empty cell, or invalid row.
96 0 : return 0;
97 :
98 1548 : long nValue = 0;
99 1548 : ScRefCellValue aCell = GetCellValue(it, aPos.second);
100 1548 : double nPPT = bWidth ? nPPTX : nPPTY;
101 :
102 1548 : const ScPatternAttr* pPattern = rOptions.pPattern;
103 1548 : if (!pPattern)
104 30 : pPattern = pAttrArray->GetPattern( nRow );
105 :
106 : // merged?
107 : // Do not merge in conditional formatting
108 :
109 1548 : const ScMergeAttr* pMerge = static_cast<const ScMergeAttr*>(&pPattern->GetItem(ATTR_MERGE));
110 1548 : const ScMergeFlagAttr* pFlag = static_cast<const ScMergeFlagAttr*>(&pPattern->GetItem(ATTR_MERGE_FLAG));
111 :
112 1548 : if ( bWidth )
113 : {
114 325 : if ( pFlag->IsHorOverlapped() )
115 0 : return 0;
116 325 : if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
117 0 : return 0;
118 : }
119 : else
120 : {
121 1223 : if ( pFlag->IsVerOverlapped() )
122 0 : return 0;
123 1223 : if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
124 0 : return 0;
125 : }
126 :
127 : // conditional formatting
128 1548 : const SfxItemSet* pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
129 :
130 : // line break?
131 :
132 : const SfxPoolItem* pCondItem;
133 : SvxCellHorJustify eHorJust;
134 1548 : if (pCondSet &&
135 0 : pCondSet->GetItemState(ATTR_HOR_JUSTIFY, true, &pCondItem) == SfxItemState::SET)
136 0 : eHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem*>(pCondItem)->GetValue();
137 : else
138 : eHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(
139 1548 : pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
140 : bool bBreak;
141 1548 : if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
142 385 : bBreak = true;
143 1163 : else if ( pCondSet &&
144 0 : pCondSet->GetItemState(ATTR_LINEBREAK, true, &pCondItem) == SfxItemState::SET)
145 0 : bBreak = static_cast<const SfxBoolItem*>(pCondItem)->GetValue();
146 : else
147 1163 : bBreak = static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
148 :
149 1548 : SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
150 1548 : sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
151 : // #i111387# disable automatic line breaks only for "General" number format
152 1548 : if (bBreak && ( nFormat % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
153 : {
154 : // If a formula cell needs to be interpreted during aCell.hasNumeric()
155 : // to determine the type, the pattern may get invalidated because the
156 : // result may set a number format. In which case there's also the
157 : // General format not set anymore..
158 66 : bool bMayInvalidatePattern = (aCell.meType == CELLTYPE_FORMULA);
159 66 : const ScPatternAttr* pOldPattern = pPattern;
160 66 : bool bNumeric = aCell.hasNumeric();
161 66 : if (bMayInvalidatePattern)
162 : {
163 0 : pPattern = pAttrArray->GetPattern( nRow );
164 0 : if (ppPatternChange)
165 0 : *ppPatternChange = pPattern; // XXX caller may have to check for change!
166 : }
167 66 : if (bNumeric)
168 : {
169 5 : if (!bMayInvalidatePattern || pPattern == pOldPattern)
170 5 : bBreak = false;
171 : else
172 : {
173 0 : nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
174 0 : if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
175 0 : bBreak = false;
176 : }
177 : }
178 : }
179 :
180 : // get other attributes from pattern and conditional formatting
181 :
182 1548 : SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
183 1550 : bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
184 1550 : static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
185 1548 : if ( bAsianVertical )
186 0 : bBreak = false;
187 :
188 1548 : if ( bWidth && bBreak ) // after determining bAsianVertical (bBreak may be reset)
189 8 : return 0;
190 :
191 1540 : long nRotate = 0;
192 1540 : SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
193 1540 : if ( eOrient == SVX_ORIENTATION_STANDARD )
194 : {
195 1440 : if (pCondSet &&
196 0 : pCondSet->GetItemState(ATTR_ROTATE_VALUE, true, &pCondItem) == SfxItemState::SET)
197 0 : nRotate = static_cast<const SfxInt32Item*>(pCondItem)->GetValue();
198 : else
199 1440 : nRotate =static_cast<const SfxInt32Item&>(pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
200 1440 : if ( nRotate )
201 : {
202 956 : if (pCondSet &&
203 0 : pCondSet->GetItemState(ATTR_ROTATE_MODE, true, &pCondItem) == SfxItemState::SET)
204 0 : eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem*>(pCondItem)->GetValue();
205 : else
206 : eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
207 956 : pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
208 :
209 956 : if ( nRotate == 18000 )
210 0 : eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
211 : }
212 : }
213 :
214 1540 : if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
215 : {
216 : // ignore orientation/rotation if "repeat" is active
217 0 : eOrient = SVX_ORIENTATION_STANDARD;
218 0 : nRotate = 0;
219 0 : bAsianVertical = false;
220 : }
221 :
222 : const SvxMarginItem* pMargin;
223 1540 : if (pCondSet &&
224 0 : pCondSet->GetItemState(ATTR_MARGIN, true, &pCondItem) == SfxItemState::SET)
225 0 : pMargin = static_cast<const SvxMarginItem*>(pCondItem);
226 : else
227 1540 : pMargin = static_cast<const SvxMarginItem*>(&pPattern->GetItem(ATTR_MARGIN));
228 1540 : sal_uInt16 nIndent = 0;
229 1540 : if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
230 : {
231 189 : if (pCondSet &&
232 0 : pCondSet->GetItemState(ATTR_INDENT, true, &pCondItem) == SfxItemState::SET)
233 0 : nIndent = static_cast<const SfxUInt16Item*>(pCondItem)->GetValue();
234 : else
235 189 : nIndent = static_cast<const SfxUInt16Item&>(pPattern->GetItem(ATTR_INDENT)).GetValue();
236 : }
237 :
238 1540 : SvtScriptType nScript = pDocument->GetScriptType(nCol, nRow, nTab);
239 1540 : if (nScript == SvtScriptType::NONE) nScript = ScGlobal::GetDefaultScriptType();
240 :
241 : // also call SetFont for edit cells, because bGetFont may be set only once
242 : // bGetFont is set also if script type changes
243 1540 : if (rOptions.bGetFont)
244 : {
245 1540 : Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
246 3080 : vcl::Font aFont;
247 : // font color doesn't matter here
248 1540 : pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
249 3080 : pDev->SetFont(aFont);
250 : }
251 :
252 1540 : bool bAddMargin = true;
253 1540 : CellType eCellType = aCell.meType;
254 :
255 1434 : bool bEditEngine = (eCellType == CELLTYPE_EDIT ||
256 1432 : eOrient == SVX_ORIENTATION_STACKED ||
257 4512 : IsAmbiguousScript(nScript) ||
258 1706 : ((eCellType == CELLTYPE_FORMULA) && aCell.mpFormula->IsMultilineResult()));
259 :
260 1540 : if (!bEditEngine) // direct output
261 : {
262 : Color* pColor;
263 1432 : OUString aValStr;
264 : ScCellFormat::GetString(
265 1432 : aCell, nFormat, aValStr, &pColor, *pFormatter, pDocument, true, rOptions.bFormula, ftCheck);
266 :
267 1432 : if (!aValStr.isEmpty())
268 : {
269 : // SetFont is moved up
270 :
271 1432 : Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
272 1432 : if ( eOrient != SVX_ORIENTATION_STANDARD )
273 : {
274 98 : long nTemp = aSize.Width();
275 98 : aSize.Width() = aSize.Height();
276 98 : aSize.Height() = nTemp;
277 : }
278 1334 : else if ( nRotate )
279 : {
280 : //TODO: take different X/Y scaling into consideration
281 :
282 955 : double nRealOrient = nRotate * F_PI18000; // nRotate is in 1/100 Grad
283 955 : double nCosAbs = fabs( cos( nRealOrient ) );
284 955 : double nSinAbs = fabs( sin( nRealOrient ) );
285 955 : long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
286 : long nWidth;
287 955 : if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
288 955 : nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
289 0 : else if ( rOptions.bTotalSize )
290 : {
291 0 : nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
292 0 : bAddMargin = false;
293 : // only to the right:
294 : //TODO: differ on direction up/down (only Text/whole height)
295 0 : if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
296 0 : nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
297 0 : nPPT * nCosAbs / nSinAbs );
298 : }
299 : else
300 0 : nWidth = (long)( aSize.Height() / nSinAbs ); //TODO: limit?
301 :
302 955 : if ( bBreak && !rOptions.bTotalSize )
303 : {
304 : // limit size for line break
305 643 : long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
306 643 : if ( nHeight > nCmp )
307 0 : nHeight = nCmp;
308 : }
309 :
310 955 : aSize = Size( nWidth, nHeight );
311 : }
312 1432 : nValue = bWidth ? aSize.Width() : aSize.Height();
313 :
314 1432 : if ( bAddMargin )
315 : {
316 1432 : if (bWidth)
317 : {
318 634 : nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
319 634 : (long) ( pMargin->GetRightMargin() * nPPT );
320 317 : if ( nIndent )
321 0 : nValue += (long) ( nIndent * nPPT );
322 : }
323 : else
324 2230 : nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
325 2230 : (long) ( pMargin->GetBottomMargin() * nPPT );
326 : }
327 :
328 : // linebreak done ?
329 :
330 1432 : if ( bBreak && !bWidth )
331 : {
332 : // test with EditEngine the safety at 90%
333 : // (due to rounding errors and because EditEngine formats partially differently)
334 :
335 1496 : long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
336 1496 : pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
337 : nIndent )
338 748 : * nPPT );
339 748 : nDocPixel = (nDocPixel * 9) / 10; // for safety
340 748 : if ( aSize.Width() > nDocPixel )
341 703 : bEditEngine = true;
342 : }
343 1432 : }
344 : }
345 :
346 1540 : if (bEditEngine)
347 : {
348 : // the font is not reset each time with !bEditEngine
349 811 : vcl::Font aOldFont = pDev->GetFont();
350 :
351 1622 : MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
352 :
353 : // save in document ?
354 811 : ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
355 :
356 811 : pEngine->SetUpdateMode( false );
357 811 : bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
358 811 : EEControlBits nCtrl = pEngine->GetControlWord();
359 811 : if ( bTextWysiwyg )
360 0 : nCtrl |= EEControlBits::FORMAT100;
361 : else
362 811 : nCtrl &= ~EEControlBits::FORMAT100;
363 811 : pEngine->SetControlWord( nCtrl );
364 1622 : MapMode aOld = pDev->GetMapMode();
365 811 : pDev->SetMapMode( aHMMMode );
366 811 : pEngine->SetRefDevice( pDev );
367 811 : pDocument->ApplyAsianEditSettings( *pEngine );
368 811 : SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
369 811 : if ( ScStyleSheet* pPreviewStyle = pDocument->GetPreviewCellStyle( nCol, nRow, nTab ) )
370 : {
371 0 : boost::scoped_ptr<ScPatternAttr> pPreviewPattern(new ScPatternAttr( *pPattern ));
372 0 : pPreviewPattern->SetStyleSheet(pPreviewStyle);
373 0 : pPreviewPattern->FillEditItemSet( pSet, pCondSet );
374 : }
375 : else
376 : {
377 811 : SfxItemSet* pFontSet = pDocument->GetPreviewFont( nCol, nRow, nTab );
378 811 : pPattern->FillEditItemSet( pSet, pFontSet ? pFontSet : pCondSet );
379 : }
380 : // no longer needed, are setted with the text (is faster)
381 : // pEngine->SetDefaults( pSet );
382 :
383 811 : if ( static_cast<const SfxBoolItem&>(pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
384 :
385 542 : com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
386 542 : pEngine->SetHyphenator( xXHyphenator );
387 : }
388 :
389 811 : Size aPaper = Size( 1000000, 1000000 );
390 811 : if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
391 2 : aPaper.Width() = 1;
392 809 : else if (bBreak)
393 : {
394 704 : double fWidthFactor = nPPTX;
395 704 : if ( bTextWysiwyg )
396 : {
397 : // if text is formatted for printer, don't use PixelToLogic,
398 : // to ensure the exact same paper width (and same line breaks) as in
399 : // ScEditUtil::GetEditArea, used for output.
400 :
401 0 : fWidthFactor = HMM_PER_TWIPS;
402 : }
403 :
404 : // use original width for hidden columns:
405 704 : long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
406 704 : SCCOL nColMerge = pMerge->GetColMerge();
407 704 : if (nColMerge > 1)
408 0 : for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
409 0 : nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
410 704 : nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
411 704 : + (long) ( pMargin->GetRightMargin() * fWidthFactor )
412 704 : + 1; // output size is width-1 pixel (due to gridline)
413 704 : if ( nIndent )
414 84 : nDocWidth -= (long) ( nIndent * fWidthFactor );
415 :
416 : // space for AutoFilter button: 20 * nZoom/100
417 704 : if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
418 0 : nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
419 :
420 704 : aPaper.Width() = nDocWidth;
421 :
422 704 : if ( !bTextWysiwyg )
423 704 : aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
424 : }
425 811 : pEngine->SetPaperSize(aPaper);
426 :
427 811 : if (aCell.meType == CELLTYPE_EDIT)
428 : {
429 106 : pEngine->SetTextNewDefaults(*aCell.mpEditText, pSet);
430 : }
431 : else
432 : {
433 : Color* pColor;
434 705 : OUString aString;
435 : ScCellFormat::GetString(
436 : aCell, nFormat, aString, &pColor, *pFormatter, pDocument, true,
437 705 : rOptions.bFormula, ftCheck);
438 :
439 705 : if (!aString.isEmpty())
440 705 : pEngine->SetTextNewDefaults(aString, pSet);
441 : else
442 0 : pEngine->SetDefaults(pSet);
443 : }
444 :
445 811 : bool bEngineVertical = pEngine->IsVertical();
446 811 : pEngine->SetVertical( bAsianVertical );
447 811 : pEngine->SetUpdateMode( true );
448 :
449 811 : bool bEdWidth = bWidth;
450 811 : if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
451 48 : bEdWidth = !bEdWidth;
452 811 : if ( nRotate )
453 : {
454 : //TODO: take different X/Y scaling into consideration
455 :
456 626 : Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
457 626 : double nRealOrient = nRotate * F_PI18000; // nRotate is in 1/100 Grad
458 626 : double nCosAbs = fabs( cos( nRealOrient ) );
459 626 : double nSinAbs = fabs( sin( nRealOrient ) );
460 626 : long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
461 : long nWidth;
462 626 : if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
463 626 : nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
464 0 : else if ( rOptions.bTotalSize )
465 : {
466 0 : nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
467 0 : bAddMargin = false;
468 0 : if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
469 0 : nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
470 0 : nPPT * nCosAbs / nSinAbs );
471 : }
472 : else
473 0 : nWidth = (long)( aSize.Height() / nSinAbs ); //TODO: limit?
474 626 : aSize = Size( nWidth, nHeight );
475 :
476 626 : Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
477 626 : if ( bEdWidth )
478 0 : nValue = aPixSize.Width();
479 : else
480 : {
481 626 : nValue = aPixSize.Height();
482 :
483 626 : if ( bBreak && !rOptions.bTotalSize )
484 : {
485 : // limit size for line break
486 626 : long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
487 626 : if ( nValue > nCmp )
488 1 : nValue = nCmp;
489 : }
490 : }
491 : }
492 185 : else if ( bEdWidth )
493 : {
494 48 : if (bBreak)
495 48 : nValue = 0;
496 : else
497 0 : nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
498 0 : aHMMMode).Width();
499 : }
500 : else // height
501 : {
502 137 : nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
503 137 : aHMMMode).Height();
504 :
505 : // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
506 137 : if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
507 0 : ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
508 : {
509 0 : pEngine->SetControlWord( nCtrl | EEControlBits::FORMAT100 );
510 0 : pEngine->QuickFormatDoc( true );
511 0 : long nSecondValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ), aHMMMode).Height();
512 0 : if ( nSecondValue > nValue )
513 0 : nValue = nSecondValue;
514 : }
515 : }
516 :
517 811 : if ( nValue && bAddMargin )
518 : {
519 763 : if (bWidth)
520 : {
521 0 : nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
522 0 : (long) ( pMargin->GetRightMargin() * nPPT );
523 0 : if (nIndent)
524 0 : nValue += (long) ( nIndent * nPPT );
525 : }
526 : else
527 : {
528 1526 : nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
529 1526 : (long) ( pMargin->GetBottomMargin() * nPPT );
530 :
531 763 : if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
532 : {
533 : // add 1pt extra (default margin value) for line breaks with SetVertical
534 0 : nValue += (long) ( 20 * nPPT );
535 : }
536 : }
537 : }
538 :
539 : // EditEngine is cached and re-used, so the old vertical flag must be restored
540 811 : pEngine->SetVertical( bEngineVertical );
541 :
542 811 : pDocument->DisposeFieldEditEngine(pEngine);
543 :
544 811 : pDev->SetMapMode( aOld );
545 1622 : pDev->SetFont( aOldFont );
546 : }
547 :
548 1540 : if (bWidth)
549 : {
550 : // place for Autofilter Button
551 : // 20 * nZoom/100
552 : // Conditional formatting is not interesting here
553 :
554 317 : sal_Int16 nFlags = static_cast<const ScMergeFlagAttr&>(pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
555 317 : if (nFlags & SC_MF_AUTO)
556 0 : nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
557 : }
558 1540 : return nValue;
559 : }
560 :
561 : namespace {
562 :
563 67 : class MaxStrLenFinder
564 : {
565 : ScDocument& mrDoc;
566 : sal_uInt32 mnFormat;
567 : OUString maMaxLenStr;
568 : sal_Int32 mnMaxLen;
569 :
570 1489 : void checkLength(ScRefCellValue& rCell)
571 : {
572 : Color* pColor;
573 1489 : OUString aValStr;
574 : ScCellFormat::GetString(
575 1489 : rCell, mnFormat, aValStr, &pColor, *mrDoc.GetFormatTable(), &mrDoc, true, false, ftCheck);
576 :
577 1489 : if (aValStr.getLength() > mnMaxLen)
578 : {
579 59 : mnMaxLen = aValStr.getLength();
580 59 : maMaxLenStr = aValStr;
581 1489 : }
582 1489 : }
583 :
584 : public:
585 67 : MaxStrLenFinder(ScDocument& rDoc, sal_uInt32 nFormat) :
586 67 : mrDoc(rDoc), mnFormat(nFormat), mnMaxLen(0) {}
587 :
588 1473 : void operator() (size_t /*nRow*/, double f)
589 : {
590 1473 : ScRefCellValue aCell(f);
591 1473 : checkLength(aCell);
592 1473 : }
593 :
594 1116 : void operator() (size_t /*nRow*/, const svl::SharedString& rSS)
595 : {
596 1116 : if (rSS.getLength() > mnMaxLen)
597 : {
598 64 : mnMaxLen = rSS.getLength();
599 64 : maMaxLenStr = rSS.getString();
600 : }
601 1116 : }
602 :
603 16 : void operator() (size_t /*nRow*/, const EditTextObject* p)
604 : {
605 16 : ScRefCellValue aCell(p);
606 16 : checkLength(aCell);
607 16 : }
608 :
609 0 : void operator() (size_t /*nRow*/, const ScFormulaCell* p)
610 : {
611 0 : ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
612 0 : checkLength(aCell);
613 0 : }
614 :
615 67 : const OUString& getMaxLenStr() const { return maMaxLenStr; }
616 : };
617 :
618 : }
619 :
620 98 : sal_uInt16 ScColumn::GetOptimalColWidth(
621 : OutputDevice* pDev, double nPPTX, double nPPTY, const Fraction& rZoomX, const Fraction& rZoomY,
622 : bool bFormula, sal_uInt16 nOldWidth, const ScMarkData* pMarkData, const ScColWidthParam* pParam) const
623 : {
624 98 : if (maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty)
625 : // All cells are empty.
626 13 : return nOldWidth;
627 :
628 85 : sc::SingleColumnSpanSet aSpanSet;
629 170 : sc::SingleColumnSpanSet::SpansType aMarkedSpans;
630 85 : if (pMarkData && (pMarkData->IsMarked() || pMarkData->IsMultiMarked()))
631 : {
632 77 : aSpanSet.scan(*pMarkData, nTab, nCol);
633 77 : aSpanSet.getSpans(aMarkedSpans);
634 : }
635 : else
636 : // "Select" the entire column if no selection exists.
637 8 : aMarkedSpans.push_back(sc::RowSpan(0, MAXROW));
638 :
639 85 : sal_uInt16 nWidth = static_cast<sal_uInt16>(nOldWidth*nPPTX);
640 85 : bool bFound = false;
641 :
642 85 : if ( pParam && pParam->mbSimpleText )
643 : { // all the same except for number format
644 67 : const ScPatternAttr* pPattern = GetPattern( 0 );
645 67 : vcl::Font aFont;
646 : // font color doesn't matter here
647 67 : pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX, NULL );
648 67 : pDev->SetFont( aFont );
649 67 : const SvxMarginItem* pMargin = static_cast<const SvxMarginItem*>(&pPattern->GetItem(ATTR_MARGIN));
650 134 : long nMargin = (long) ( pMargin->GetLeftMargin() * nPPTX ) +
651 134 : (long) ( pMargin->GetRightMargin() * nPPTX );
652 :
653 : // Try to find the row that has the longest string, and measure the width of that string.
654 67 : SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
655 67 : sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
656 134 : OUString aLongStr;
657 : Color* pColor;
658 67 : if (pParam->mnMaxTextRow >= 0)
659 : {
660 0 : ScRefCellValue aCell = GetCellValue(pParam->mnMaxTextRow);
661 : ScCellFormat::GetString(
662 0 : aCell, nFormat, aLongStr, &pColor, *pFormatter, pDocument, true, false, ftCheck);
663 : }
664 : else
665 : {
666 : // Go though all non-empty cells within selection.
667 67 : MaxStrLenFinder aFunc(*pDocument, nFormat);
668 67 : sc::CellStoreType::const_iterator itPos = maCells.begin();
669 67 : sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
670 134 : for (; it != itEnd; ++it)
671 67 : itPos = sc::ParseAllNonEmpty(itPos, maCells, it->mnRow1, it->mnRow2, aFunc);
672 :
673 67 : aLongStr = aFunc.getMaxLenStr();
674 : }
675 :
676 67 : if (!aLongStr.isEmpty())
677 : {
678 67 : nWidth = pDev->GetTextWidth(aLongStr) + static_cast<sal_uInt16>(nMargin);
679 67 : bFound = true;
680 67 : }
681 : }
682 : else
683 : {
684 18 : ScNeededSizeOptions aOptions;
685 18 : aOptions.bFormula = bFormula;
686 18 : const ScPatternAttr* pOldPattern = NULL;
687 18 : SvtScriptType nOldScript = SvtScriptType::NONE;
688 :
689 : // Go though all non-empty cells within selection.
690 18 : sc::CellStoreType::const_iterator itPos = maCells.begin();
691 18 : sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
692 36 : for (; it != itEnd; ++it)
693 : {
694 18 : SCROW nRow1 = it->mnRow1, nRow2 = it->mnRow2;
695 18 : SCROW nRow = nRow1;
696 101 : while (nRow <= nRow2)
697 : {
698 65 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
699 65 : itPos = aPos.first;
700 65 : if (itPos->type == sc::element_type_empty)
701 : {
702 : // Skip empty cells.
703 32 : nRow += itPos->size - aPos.second;
704 32 : continue;
705 : }
706 :
707 328 : for (size_t nOffset = aPos.second; nOffset < itPos->size; ++nOffset, ++nRow)
708 : {
709 295 : SvtScriptType nScript = pDocument->GetScriptType(nCol, nRow, nTab);
710 295 : if (nScript == SvtScriptType::NONE)
711 0 : nScript = ScGlobal::GetDefaultScriptType();
712 :
713 295 : const ScPatternAttr* pPattern = GetPattern(nRow);
714 295 : aOptions.pPattern = pPattern;
715 295 : aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
716 295 : pOldPattern = pPattern;
717 : sal_uInt16 nThis = (sal_uInt16) GetNeededSize(
718 295 : nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, true, aOptions, &pOldPattern);
719 295 : if (nThis)
720 : {
721 287 : if (nThis > nWidth || !bFound)
722 : {
723 26 : nWidth = nThis;
724 26 : bFound = true;
725 : }
726 : }
727 : }
728 : }
729 : }
730 : }
731 :
732 85 : if (bFound)
733 : {
734 85 : nWidth += 2;
735 85 : sal_uInt16 nTwips = (sal_uInt16) (nWidth / nPPTX);
736 85 : return nTwips;
737 : }
738 : else
739 85 : return nOldWidth;
740 : }
741 :
742 751336 : static sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId )
743 : {
744 : const SvxFontHeightItem& rFontHeight =
745 751336 : static_cast<const SvxFontHeightItem&>(rPattern.GetItem(nFontHeightId));
746 :
747 751336 : sal_uInt16 nHeight = rFontHeight.GetHeight();
748 751336 : nHeight *= 1.18;
749 :
750 751336 : if ( static_cast<const SvxEmphasisMarkItem&>(rPattern.
751 751336 : GetItem(ATTR_FONT_EMPHASISMARK)).GetEmphasisMark() != EMPHASISMARK_NONE )
752 : {
753 : // add height for emphasis marks
754 : //TODO: font metrics should be used instead
755 670 : nHeight += nHeight / 4;
756 : }
757 :
758 : const SvxMarginItem& rMargin =
759 751336 : static_cast<const SvxMarginItem&>(rPattern.GetItem(ATTR_MARGIN));
760 :
761 751336 : nHeight += rMargin.GetTopMargin() + rMargin.GetBottomMargin();
762 :
763 751336 : if (nHeight > STD_ROWHEIGHT_DIFF)
764 751336 : nHeight -= STD_ROWHEIGHT_DIFF;
765 :
766 751336 : if (nHeight < ScGlobal::nStdRowHeight)
767 599177 : nHeight = ScGlobal::nStdRowHeight;
768 :
769 751336 : return nHeight;
770 : }
771 :
772 : // pHeight in Twips
773 : // optimize nMinHeight, nMinStart : with nRow >= nMinStart is at least nMinHeight
774 : // (is only evaluated with bStdAllowed)
775 :
776 844800 : void ScColumn::GetOptimalHeight(
777 : sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, sal_uInt16 nMinHeight, SCROW nMinStart )
778 : {
779 844800 : std::vector<sal_uInt16>& rHeights = rCxt.getHeightArray();
780 844800 : ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
781 :
782 844800 : SCROW nStart = -1;
783 844800 : SCROW nEnd = -1;
784 844800 : SCROW nEditPos = 0;
785 844800 : SCROW nNextEnd = 0;
786 :
787 : // with conditional formatting, always consider the individual cells
788 :
789 844800 : const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
790 2537446 : while ( pPattern )
791 : {
792 847846 : const ScMergeAttr* pMerge = static_cast<const ScMergeAttr*>(&pPattern->GetItem(ATTR_MERGE));
793 847846 : const ScMergeFlagAttr* pFlag = static_cast<const ScMergeFlagAttr*>(&pPattern->GetItem(ATTR_MERGE_FLAG));
794 847846 : if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
795 : {
796 : // do nothing - vertically with merged and overlapping,
797 : // horizontally only with overlapped (invisible) -
798 : // only one horizontal merged is always considered
799 : }
800 : else
801 : {
802 847817 : bool bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
803 847817 : bool bStdOnly = false;
804 847817 : if (bStdAllowed)
805 : {
806 1470361 : bool bBreak = static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
807 : ((SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
808 718920 : GetItem( ATTR_HOR_JUSTIFY )).GetValue() ==
809 751441 : SVX_HOR_JUSTIFY_BLOCK);
810 751441 : bStdOnly = !bBreak;
811 :
812 : // conditional formatting: loop all cells
813 1470292 : if (bStdOnly &&
814 : !static_cast<const ScCondFormatItem&>(pPattern->GetItem(
815 718851 : ATTR_CONDITIONAL)).GetCondFormatData().empty())
816 : {
817 1 : bStdOnly = false;
818 : }
819 :
820 : // rotated text: loop all cells
821 1470291 : if ( bStdOnly && static_cast<const SfxInt32Item&>(pPattern->
822 718850 : GetItem(ATTR_ROTATE_VALUE)).GetValue() )
823 208 : bStdOnly = false;
824 : }
825 :
826 847817 : if (bStdOnly)
827 718642 : if (HasEditCells(nStart,nEnd,nEditPos)) // includes mixed script types
828 : {
829 105 : if (nEditPos == nStart)
830 : {
831 105 : bStdOnly = false;
832 105 : if (nEnd > nEditPos)
833 0 : nNextEnd = nEnd;
834 105 : nEnd = nEditPos; // calculate single
835 105 : bStdAllowed = false; // will be computed in any case per cell
836 : }
837 : else
838 : {
839 0 : nNextEnd = nEnd;
840 0 : nEnd = nEditPos - 1; // standard - part
841 : }
842 : }
843 :
844 847817 : sc::SingleColumnSpanSet aSpanSet;
845 847817 : aSpanSet.scan(*this, nStart, nEnd);
846 1695634 : sc::SingleColumnSpanSet::SpansType aSpans;
847 847817 : aSpanSet.getSpans(aSpans);
848 :
849 847817 : if (bStdAllowed)
850 : {
851 751336 : sal_uInt16 nLatHeight = 0;
852 751336 : sal_uInt16 nCjkHeight = 0;
853 751336 : sal_uInt16 nCtlHeight = 0;
854 : sal_uInt16 nDefHeight;
855 751336 : SvtScriptType nDefScript = ScGlobal::GetDefaultScriptType();
856 751336 : if ( nDefScript == SvtScriptType::ASIAN )
857 0 : nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
858 751336 : else if ( nDefScript == SvtScriptType::COMPLEX )
859 0 : nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
860 : else
861 751336 : nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
862 :
863 : // if everything below is already larger, the loop doesn't have to
864 : // be run again
865 751336 : SCROW nStdEnd = nEnd;
866 751336 : if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
867 716346 : nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
868 :
869 356744753 : for (SCROW nRow = nStart; nRow <= nStdEnd; ++nRow)
870 355993417 : if (nDefHeight > rHeights[nRow-nStartRow])
871 83890070 : rHeights[nRow-nStartRow] = nDefHeight;
872 :
873 751336 : if ( bStdOnly )
874 : {
875 : // if cells are not handled individually below,
876 : // check for cells with different script type
877 718537 : sc::CellTextAttrStoreType::iterator itAttr = maCellTextAttrs.begin();
878 718537 : sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
879 718537 : sc::CellStoreType::iterator itCells = maCells.begin();
880 721127 : for (; it != itEnd; ++it)
881 : {
882 34483 : for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
883 : {
884 31893 : SvtScriptType nScript = GetRangeScriptType(itAttr, nRow, nRow, itCells);
885 31893 : if (nScript == nDefScript)
886 31722 : continue;
887 :
888 171 : if ( nScript == SvtScriptType::ASIAN )
889 : {
890 0 : if ( nCjkHeight == 0 )
891 0 : nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
892 0 : if (nCjkHeight > rHeights[nRow-nStartRow])
893 0 : rHeights[nRow-nStartRow] = nCjkHeight;
894 : }
895 171 : else if ( nScript == SvtScriptType::COMPLEX )
896 : {
897 0 : if ( nCtlHeight == 0 )
898 0 : nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
899 0 : if (nCtlHeight > rHeights[nRow-nStartRow])
900 0 : rHeights[nRow-nStartRow] = nCtlHeight;
901 : }
902 : else
903 : {
904 171 : if ( nLatHeight == 0 )
905 0 : nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
906 171 : if (nLatHeight > rHeights[nRow-nStartRow])
907 0 : rHeights[nRow-nStartRow] = nLatHeight;
908 : }
909 : }
910 : }
911 : }
912 : }
913 :
914 847817 : if (!bStdOnly) // search covered cells
915 : {
916 129280 : ScNeededSizeOptions aOptions;
917 :
918 129280 : sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
919 130072 : for (; it != itEnd; ++it)
920 : {
921 2354 : for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
922 : {
923 : // only calculate the cell height when it's used later (#37928#)
924 :
925 1562 : if (rCxt.isForceAutoSize() || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
926 : {
927 1223 : aOptions.pPattern = pPattern;
928 1223 : const ScPatternAttr* pOldPattern = pPattern;
929 : sal_uInt16 nHeight = (sal_uInt16)
930 : ( GetNeededSize( nRow, rCxt.getOutputDevice(), rCxt.getPPTX(), rCxt.getPPTY(),
931 1223 : rCxt.getZoomX(), rCxt.getZoomY(), false, aOptions,
932 1223 : &pPattern) / rCxt.getPPTY() );
933 1223 : if (nHeight > rHeights[nRow-nStartRow])
934 818 : rHeights[nRow-nStartRow] = nHeight;
935 : // Pattern changed due to calculation? => sync.
936 1223 : if (pPattern != pOldPattern)
937 : {
938 0 : pPattern = aIter.Resync( nRow, nStart, nEnd);
939 0 : nNextEnd = 0;
940 : }
941 : }
942 : }
943 : }
944 847817 : }
945 : }
946 :
947 847846 : if (nNextEnd > 0)
948 : {
949 0 : nStart = nEnd + 1;
950 0 : nEnd = nNextEnd;
951 0 : nNextEnd = 0;
952 : }
953 : else
954 847846 : pPattern = aIter.Next(nStart,nEnd);
955 : }
956 844800 : }
957 :
958 0 : bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const
959 : {
960 0 : bool bStop = false;
961 0 : sc::CellStoreType::const_iterator it = maCells.position(nRow).first;
962 0 : mdds::mtv::element_t eType = it->type;
963 0 : if (!bInSel && it != maCells.end() && eType != sc::element_type_empty)
964 : {
965 0 : if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
966 0 : !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
967 0 : pDocument->IsTabProtected(nTab)) )
968 0 : return true;
969 : }
970 0 : while (!bStop)
971 : {
972 0 : if (bInSel)
973 : {
974 0 : nRow = rData.GetNextMarked(nCol, nRow, false);
975 0 : if (!ValidRow(nRow))
976 : {
977 0 : nRow = MAXROW+1;
978 0 : bStop = true;
979 : }
980 : else
981 : {
982 0 : it = maCells.position(it, nRow).first;
983 0 : eType = it->type;
984 0 : if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
985 0 : !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
986 0 : pDocument->IsTabProtected(nTab)) )
987 0 : return true;
988 : else
989 0 : nRow++;
990 : }
991 : }
992 0 : else if (GetNextDataPos(nRow))
993 : {
994 0 : it = maCells.position(it, nRow).first;
995 0 : eType = it->type;
996 0 : if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
997 0 : !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
998 0 : pDocument->IsTabProtected(nTab)) )
999 0 : return true;
1000 : else
1001 0 : nRow++;
1002 : }
1003 : else
1004 : {
1005 0 : nRow = MAXROW+1;
1006 0 : bStop = true;
1007 : }
1008 : }
1009 0 : return false;
1010 : }
1011 :
1012 : namespace {
1013 :
1014 0 : class StrEntries
1015 : {
1016 : sc::CellStoreType& mrCells;
1017 :
1018 : protected:
1019 0 : struct StrEntry
1020 : {
1021 : SCROW mnRow;
1022 : OUString maStr;
1023 :
1024 0 : StrEntry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maStr(rStr) {}
1025 : };
1026 :
1027 : std::vector<StrEntry> maStrEntries;
1028 : ScDocument* mpDoc;
1029 :
1030 0 : StrEntries(sc::CellStoreType& rCells, ScDocument* pDoc) : mrCells(rCells), mpDoc(pDoc) {}
1031 :
1032 : public:
1033 0 : void commitStrings()
1034 : {
1035 0 : svl::SharedStringPool& rPool = mpDoc->GetSharedStringPool();
1036 0 : sc::CellStoreType::iterator it = mrCells.begin();
1037 0 : std::vector<StrEntry>::iterator itStr = maStrEntries.begin(), itStrEnd = maStrEntries.end();
1038 0 : for (; itStr != itStrEnd; ++itStr)
1039 0 : it = mrCells.set(it, itStr->mnRow, rPool.intern(itStr->maStr));
1040 0 : }
1041 : };
1042 :
1043 0 : class RemoveEditAttribsHandler : public StrEntries
1044 : {
1045 : boost::scoped_ptr<ScFieldEditEngine> mpEngine;
1046 :
1047 : public:
1048 0 : RemoveEditAttribsHandler(sc::CellStoreType& rCells, ScDocument* pDoc) : StrEntries(rCells, pDoc) {}
1049 :
1050 0 : void operator() (size_t nRow, EditTextObject*& pObj)
1051 : {
1052 : // For the test on hard formatting (ScEditAttrTester), are the defaults in the
1053 : // EditEngine of no importance. When the tester would later recognise the same
1054 : // attributes in default and hard formatting and has to remove them, the correct
1055 : // defaults must be set in the EditEngine for each cell.
1056 :
1057 : // test for attributes
1058 0 : if (!mpEngine)
1059 : {
1060 0 : mpEngine.reset(new ScFieldEditEngine(mpDoc, mpDoc->GetEditPool()));
1061 : // EEControlBits::ONLINESPELLING if there are errors already
1062 0 : mpEngine->SetControlWord(mpEngine->GetControlWord() | EEControlBits::ONLINESPELLING);
1063 0 : mpDoc->ApplyAsianEditSettings(*mpEngine);
1064 : }
1065 0 : mpEngine->SetText(*pObj);
1066 0 : sal_Int32 nParCount = mpEngine->GetParagraphCount();
1067 0 : for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
1068 : {
1069 0 : mpEngine->RemoveCharAttribs(nPar);
1070 0 : const SfxItemSet& rOld = mpEngine->GetParaAttribs(nPar);
1071 0 : if ( rOld.Count() )
1072 : {
1073 0 : SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // empty
1074 0 : mpEngine->SetParaAttribs( nPar, aNew );
1075 : }
1076 : }
1077 : // change URL field to text (not possible otherwise, thus pType=0)
1078 0 : mpEngine->RemoveFields(true);
1079 :
1080 0 : bool bSpellErrors = mpEngine->HasOnlineSpellErrors();
1081 0 : bool bNeedObject = bSpellErrors || nParCount>1; // keep errors/paragraphs
1082 : // ScEditAttrTester is not needed anymore, arrays are gone
1083 :
1084 0 : if (bNeedObject) // remains edit cell
1085 : {
1086 0 : EEControlBits nCtrl = mpEngine->GetControlWord();
1087 0 : EEControlBits nWantBig = bSpellErrors ? EEControlBits::ALLOWBIGOBJS : EEControlBits::NONE;
1088 0 : if ( ( nCtrl & EEControlBits::ALLOWBIGOBJS ) != nWantBig )
1089 0 : mpEngine->SetControlWord( (nCtrl & ~EEControlBits::ALLOWBIGOBJS) | nWantBig );
1090 :
1091 : // Overwrite the existing object.
1092 0 : delete pObj;
1093 0 : pObj = mpEngine->CreateTextObject();
1094 : }
1095 : else // create String
1096 : {
1097 : // Store the string replacement for later commits.
1098 0 : OUString aText = ScEditUtil::GetSpaceDelimitedString(*mpEngine);
1099 0 : maStrEntries.push_back(StrEntry(nRow, aText));
1100 : }
1101 0 : }
1102 : };
1103 :
1104 : class TestTabRefAbsHandler
1105 : {
1106 : SCTAB mnTab;
1107 : bool mbTestResult;
1108 : public:
1109 1065 : TestTabRefAbsHandler(SCTAB nTab) : mnTab(nTab), mbTestResult(false) {}
1110 :
1111 21 : void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
1112 : {
1113 21 : if (const_cast<ScFormulaCell*>(pCell)->TestTabRefAbs(mnTab))
1114 10 : mbTestResult = true;
1115 21 : }
1116 :
1117 1065 : bool getTestResult() const { return mbTestResult; }
1118 : };
1119 :
1120 : }
1121 :
1122 0 : void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
1123 : {
1124 0 : RemoveEditAttribsHandler aFunc(maCells, pDocument);
1125 0 : sc::ProcessEditText(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
1126 0 : aFunc.commitStrings();
1127 0 : }
1128 :
1129 1065 : bool ScColumn::TestTabRefAbs(SCTAB nTable) const
1130 : {
1131 1065 : TestTabRefAbsHandler aFunc(nTable);
1132 1065 : sc::ParseFormula(maCells, aFunc);
1133 1065 : return aFunc.getTestResult();
1134 : }
1135 :
1136 9170500 : bool ScColumn::IsEmptyData() const
1137 : {
1138 9170500 : return maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty;
1139 : }
1140 :
1141 : namespace {
1142 :
1143 : class CellCounter
1144 : {
1145 : size_t mnCount;
1146 : public:
1147 4 : CellCounter() : mnCount(0) {}
1148 :
1149 4 : void operator() (
1150 : const sc::CellStoreType::value_type& node, size_t /*nOffset*/, size_t nDataSize)
1151 : {
1152 4 : if (node.type == sc::element_type_empty)
1153 8 : return;
1154 :
1155 0 : mnCount += nDataSize;
1156 : }
1157 :
1158 4 : size_t getCount() const { return mnCount; }
1159 : };
1160 :
1161 : }
1162 :
1163 4 : SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
1164 : {
1165 4 : CellCounter aFunc;
1166 4 : sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
1167 4 : return aFunc.getCount();
1168 : }
1169 :
1170 7822 : bool ScColumn::HasVisibleDataAt(SCROW nRow) const
1171 : {
1172 7822 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
1173 7822 : sc::CellStoreType::const_iterator it = aPos.first;
1174 7822 : if (it == maCells.end())
1175 : // Likely invalid row number.
1176 0 : return false;
1177 :
1178 7822 : return it->type != sc::element_type_empty;
1179 : }
1180 :
1181 60 : bool ScColumn::IsEmptyAttr() const
1182 : {
1183 60 : if (pAttrArray)
1184 60 : return pAttrArray->IsEmpty();
1185 : else
1186 0 : return true;
1187 : }
1188 :
1189 60 : bool ScColumn::IsEmpty() const
1190 : {
1191 60 : return (IsEmptyData() && IsEmptyAttr());
1192 : }
1193 :
1194 6032237 : bool ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
1195 : {
1196 6032237 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1197 6032237 : sc::CellStoreType::const_iterator it = aPos.first;
1198 6032237 : if (it == maCells.end())
1199 : // Invalid row number.
1200 0 : return false;
1201 :
1202 6032237 : if (it->type != sc::element_type_empty)
1203 : // Non-empty cell at the start position.
1204 1357 : return false;
1205 :
1206 : // start position of next block which is not empty.
1207 6030880 : SCROW nNextRow = nStartRow + it->size - aPos.second;
1208 6030880 : return nEndRow < nNextRow;
1209 : }
1210 :
1211 92087 : bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
1212 : {
1213 92087 : std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
1214 92087 : sc::CellNoteStoreType::const_iterator it = aPos.first;
1215 92087 : if (it == maCellNotes.end())
1216 : // Invalid row number.
1217 0 : return false;
1218 :
1219 92087 : if (it->type != sc::element_type_empty)
1220 : // Non-empty cell at the start position.
1221 35 : return false;
1222 :
1223 : // start position of next block which is not empty.
1224 92052 : SCROW nNextRow = nStartRow + it->size - aPos.second;
1225 92052 : return nEndRow < nNextRow;
1226 : }
1227 :
1228 33 : SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
1229 : {
1230 : // Given a range of rows, find a top or bottom empty segment. Skip the start row.
1231 33 : switch (eDir)
1232 : {
1233 : case DIR_TOP:
1234 : {
1235 : // Determine the length of empty head segment.
1236 12 : size_t nLength = nEndRow - nStartRow;
1237 12 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1238 12 : sc::CellStoreType::const_iterator it = aPos.first;
1239 12 : if (it->type != sc::element_type_empty)
1240 : // First row is already not empty.
1241 8 : return 0;
1242 :
1243 : // length of this empty block minus the offset.
1244 4 : size_t nThisLen = it->size - aPos.second;
1245 4 : return std::min(nThisLen, nLength);
1246 : }
1247 : break;
1248 : case DIR_BOTTOM:
1249 : {
1250 : // Determine the length of empty tail segment.
1251 21 : size_t nLength = nEndRow - nStartRow;
1252 21 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow);
1253 21 : sc::CellStoreType::const_iterator it = aPos.first;
1254 21 : if (it->type != sc::element_type_empty)
1255 : // end row is already not empty.
1256 11 : return 0;
1257 :
1258 : // length of this empty block from the tip to the end row position.
1259 10 : size_t nThisLen = aPos.second + 1;
1260 10 : return std::min(nThisLen, nLength);
1261 : }
1262 : break;
1263 : default:
1264 : ;
1265 : }
1266 :
1267 0 : return 0;
1268 : }
1269 :
1270 12642 : SCROW ScColumn::GetFirstDataPos() const
1271 : {
1272 12642 : if (IsEmptyData())
1273 0 : return 0;
1274 :
1275 12642 : sc::CellStoreType::const_iterator it = maCells.begin();
1276 12642 : if (it->type != sc::element_type_empty)
1277 10194 : return 0;
1278 :
1279 2448 : return it->size;
1280 : }
1281 :
1282 3275702 : SCROW ScColumn::GetLastDataPos() const
1283 : {
1284 3275702 : if (IsEmptyData())
1285 3223803 : return 0;
1286 :
1287 51899 : sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
1288 51899 : if (it->type != sc::element_type_empty)
1289 0 : return MAXROW;
1290 :
1291 51899 : return MAXROW - static_cast<SCROW>(it->size);
1292 : }
1293 :
1294 89 : SCROW ScColumn::GetLastDataPos( SCROW nLastRow ) const
1295 : {
1296 89 : sc::CellStoreType::const_position_type aPos = maCells.position(nLastRow);
1297 89 : if (aPos.first->type != sc::element_type_empty)
1298 77 : return nLastRow;
1299 :
1300 12 : if (aPos.first == maCells.begin())
1301 : // This is the first block, and is empty.
1302 0 : return 0;
1303 :
1304 12 : return static_cast<SCROW>(aPos.first->position - 1);
1305 : }
1306 :
1307 0 : bool ScColumn::GetPrevDataPos(SCROW& rRow) const
1308 : {
1309 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
1310 0 : sc::CellStoreType::const_iterator it = aPos.first;
1311 0 : if (it == maCells.end())
1312 0 : return false;
1313 :
1314 0 : if (it->type == sc::element_type_empty)
1315 : {
1316 0 : if (it == maCells.begin())
1317 : // No more previous non-empty cell.
1318 0 : return false;
1319 :
1320 0 : rRow -= aPos.second + 1; // Last row position of the previous block.
1321 0 : return true;
1322 : }
1323 :
1324 : // This block is not empty.
1325 0 : if (aPos.second)
1326 : {
1327 : // There are preceding cells in this block. Simply move back one cell.
1328 0 : --rRow;
1329 0 : return true;
1330 : }
1331 :
1332 : // This is the first cell in an non-empty block. Move back to the previous block.
1333 0 : if (it == maCells.begin())
1334 : // No more preceding block.
1335 0 : return false;
1336 :
1337 0 : --rRow; // Move to the last cell of the previous block.
1338 0 : --it;
1339 0 : if (it->type == sc::element_type_empty)
1340 : {
1341 : // This block is empty.
1342 0 : if (it == maCells.begin())
1343 : // No more preceding blocks.
1344 0 : return false;
1345 :
1346 : // Skip the whole empty block segment.
1347 0 : rRow -= it->size;
1348 : }
1349 :
1350 0 : return true;
1351 : }
1352 :
1353 4070 : bool ScColumn::GetNextDataPos(SCROW& rRow) const // greater than rRow
1354 : {
1355 4070 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
1356 4070 : sc::CellStoreType::const_iterator it = aPos.first;
1357 4070 : if (it == maCells.end())
1358 0 : return false;
1359 :
1360 4070 : if (it->type == sc::element_type_empty)
1361 : {
1362 : // This block is empty. Skip ahead to the next block (if exists).
1363 527 : rRow += it->size - aPos.second;
1364 527 : ++it;
1365 527 : if (it == maCells.end())
1366 : // No more next block.
1367 65 : return false;
1368 :
1369 : // Next block exists, and is non-empty.
1370 462 : return true;
1371 : }
1372 :
1373 3543 : if (aPos.second < it->size - 1)
1374 : {
1375 : // There are still cells following the current position.
1376 2347 : ++rRow;
1377 2347 : return true;
1378 : }
1379 :
1380 : // This is the last cell in the block. Move ahead to the next block.
1381 1196 : rRow += it->size - aPos.second; // First cell in the next block.
1382 1196 : ++it;
1383 1196 : if (it == maCells.end())
1384 : // No more next block.
1385 0 : return false;
1386 :
1387 1196 : if (it->type == sc::element_type_empty)
1388 : {
1389 : // Next block is empty. Move to the next block.
1390 1051 : rRow += it->size;
1391 1051 : ++it;
1392 1051 : if (it == maCells.end())
1393 551 : return false;
1394 : }
1395 :
1396 645 : return true;
1397 : }
1398 :
1399 393382 : SCROW ScColumn::FindNextVisibleRow(SCROW nRow, bool bForward) const
1400 : {
1401 393382 : if(bForward)
1402 : {
1403 393343 : nRow++;
1404 393343 : SCROW nEndRow = 0;
1405 393343 : bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
1406 393343 : if(bHidden)
1407 2 : return std::min<SCROW>(MAXROW, nEndRow + 1);
1408 : else
1409 393341 : return nRow;
1410 : }
1411 : else
1412 : {
1413 39 : nRow--;
1414 39 : SCROW nStartRow = MAXROW;
1415 39 : bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
1416 39 : if(bHidden)
1417 24 : return std::max<SCROW>(0, nStartRow - 1);
1418 : else
1419 15 : return nRow;
1420 : }
1421 : }
1422 :
1423 17 : SCROW ScColumn::FindNextVisibleRowWithContent(
1424 : sc::CellStoreType::const_iterator& itPos, SCROW nRow, bool bForward) const
1425 : {
1426 17 : if (bForward)
1427 : {
1428 6 : do
1429 : {
1430 12 : nRow++;
1431 12 : SCROW nEndRow = 0;
1432 12 : bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
1433 12 : if (bHidden)
1434 : {
1435 1 : nRow = nEndRow + 1;
1436 1 : if(nRow >= MAXROW)
1437 6 : return MAXROW;
1438 : }
1439 :
1440 12 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
1441 12 : itPos = aPos.first;
1442 12 : if (itPos == maCells.end())
1443 : // Invalid row.
1444 0 : return MAXROW;
1445 :
1446 12 : if (itPos->type != sc::element_type_empty)
1447 6 : return nRow;
1448 :
1449 : // Move to the last cell of the current empty block.
1450 6 : nRow += itPos->size - aPos.second - 1;
1451 : }
1452 : while (nRow < MAXROW);
1453 :
1454 5 : return MAXROW;
1455 : }
1456 :
1457 2 : do
1458 : {
1459 7 : nRow--;
1460 7 : SCROW nStartRow = MAXROW;
1461 7 : bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
1462 7 : if (bHidden)
1463 : {
1464 0 : nRow = nStartRow - 1;
1465 0 : if(nRow <= 0)
1466 5 : return 0;
1467 : }
1468 :
1469 7 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
1470 7 : itPos = aPos.first;
1471 7 : if (itPos == maCells.end())
1472 : // Invalid row.
1473 0 : return 0;
1474 :
1475 7 : if (itPos->type != sc::element_type_empty)
1476 5 : return nRow;
1477 :
1478 : // Move to the first cell of the current empty block.
1479 2 : nRow -= aPos.second;
1480 : }
1481 : while (nRow > 0);
1482 :
1483 1 : return 0;
1484 : }
1485 :
1486 3801852 : void ScColumn::CellStorageModified()
1487 : {
1488 : // TODO: Update column's "last updated" timestamp here.
1489 :
1490 3801852 : mbDirtyGroups = true;
1491 :
1492 : #if DEBUG_COLUMN_STORAGE
1493 : if (maCells.size() != MAXROWCOUNT)
1494 : {
1495 : cout << "ScColumn::CellStorageModified: Size of the cell array is incorrect." << endl;
1496 : cout.flush();
1497 : abort();
1498 : }
1499 :
1500 : if (maCellTextAttrs.size() != MAXROWCOUNT)
1501 : {
1502 : cout << "ScColumn::CellStorageModified: Size of the cell text attribute array is incorrect." << endl;
1503 : cout.flush();
1504 : abort();
1505 : }
1506 :
1507 : if (maBroadcasters.size() != MAXROWCOUNT)
1508 : {
1509 : cout << "ScColumn::CellStorageModified: Size of the broadcaster array is incorrect." << endl;
1510 : cout.flush();
1511 : abort();
1512 : }
1513 :
1514 : // Make sure that these two containers are synchronized wrt empty segments.
1515 : sc::CellStoreType::const_iterator itCell = maCells.begin();
1516 : sc::CellTextAttrStoreType::const_iterator itAttr = maCellTextAttrs.begin();
1517 :
1518 : // Move to the first empty blocks.
1519 : while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
1520 : ++itCell;
1521 :
1522 : while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
1523 : ++itAttr;
1524 :
1525 : while (itCell != maCells.end())
1526 : {
1527 : if (itCell->position != itAttr->position || itCell->size != itAttr->size)
1528 : {
1529 : cout << "ScColumn::CellStorageModified: Cell array and cell text attribute array are out of sync." << endl;
1530 : cout << "-- cell array" << endl;
1531 : maCells.dump_blocks(cout);
1532 : cout << "-- attribute array" << endl;
1533 : maCellTextAttrs.dump_blocks(cout);
1534 : cout.flush();
1535 : abort();
1536 : }
1537 :
1538 : // Move to the next empty blocks.
1539 : ++itCell;
1540 : while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
1541 : ++itCell;
1542 :
1543 : ++itAttr;
1544 : while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
1545 : ++itAttr;
1546 : }
1547 : #endif
1548 3801852 : }
1549 :
1550 : #if DEBUG_COLUMN_STORAGE
1551 :
1552 : namespace {
1553 :
1554 : struct FormulaGroupDumper : std::unary_function<sc::CellStoreType::value_type, void>
1555 : {
1556 : void operator() (const sc::CellStoreType::value_type& rNode) const
1557 : {
1558 : if (rNode.type != sc::element_type_formula)
1559 : return;
1560 :
1561 : cout << " -- formula block" << endl;
1562 : sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
1563 : sc::formula_block::const_iterator itEnd = sc::formula_block::end(*rNode.data);
1564 :
1565 : for (; it != itEnd; ++it)
1566 : {
1567 : const ScFormulaCell& rCell = **it;
1568 : if (!rCell.IsShared())
1569 : {
1570 : cout << " + row " << rCell.aPos.Row() << " not shared" << endl;
1571 : continue;
1572 : }
1573 :
1574 : if (rCell.GetSharedTopRow() != rCell.aPos.Row())
1575 : {
1576 : cout << " + row " << rCell.aPos.Row() << " shared with top row " << rCell.GetSharedTopRow() << " with length " << rCell.GetSharedLength() << endl;
1577 : continue;
1578 : }
1579 :
1580 : SCROW nLen = rCell.GetSharedLength();
1581 : cout << " * group: start=" << rCell.aPos.Row() << ", length=" << nLen << endl;
1582 : std::advance(it, nLen-1);
1583 : }
1584 : }
1585 : };
1586 :
1587 : }
1588 :
1589 : void ScColumn::DumpFormulaGroups() const
1590 : {
1591 : cout << "-- formua groups" << endl;
1592 : std::for_each(maCells.begin(), maCells.end(), FormulaGroupDumper());
1593 : cout << "--" << endl;
1594 : }
1595 : #endif
1596 :
1597 6 : void ScColumn::CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const
1598 : {
1599 6 : rDestCol.maCellTextAttrs.set_empty(nRow1, nRow2); // Empty the destination range first.
1600 :
1601 6 : sc::CellTextAttrStoreType::const_iterator itBlk = maCellTextAttrs.begin(), itBlkEnd = maCellTextAttrs.end();
1602 :
1603 : // Locate the top row position.
1604 6 : size_t nOffsetInBlock = 0;
1605 6 : size_t nBlockStart = 0, nBlockEnd = 0, nRowPos = static_cast<size_t>(nRow1);
1606 6 : for (; itBlk != itBlkEnd; ++itBlk)
1607 : {
1608 6 : nBlockEnd = nBlockStart + itBlk->size;
1609 6 : if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1610 : {
1611 : // Found.
1612 6 : nOffsetInBlock = nRowPos - nBlockStart;
1613 6 : break;
1614 : }
1615 : }
1616 :
1617 6 : if (itBlk == itBlkEnd)
1618 : // Specified range not found. Bail out.
1619 6 : return;
1620 :
1621 6 : nRowPos = static_cast<size_t>(nRow2); // End row position.
1622 :
1623 : // Keep copying until we hit the end row position.
1624 6 : sc::celltextattr_block::const_iterator itData, itDataEnd;
1625 8 : for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd, nOffsetInBlock = 0)
1626 : {
1627 7 : nBlockEnd = nBlockStart + itBlk->size;
1628 7 : if (!itBlk->data)
1629 : {
1630 : // Empty block.
1631 1 : if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1632 : // This block contains the end row.
1633 1 : rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nRowPos);
1634 : else
1635 0 : rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nBlockEnd-1);
1636 :
1637 1 : continue;
1638 : }
1639 :
1640 : // Non-empty block.
1641 6 : itData = sc::celltextattr_block::begin(*itBlk->data);
1642 6 : itDataEnd = sc::celltextattr_block::end(*itBlk->data);
1643 6 : std::advance(itData, nOffsetInBlock);
1644 :
1645 6 : if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1646 : {
1647 : // This block contains the end row. Only copy partially.
1648 5 : size_t nOffset = nRowPos - nBlockStart + 1;
1649 5 : itDataEnd = sc::celltextattr_block::begin(*itBlk->data);
1650 5 : std::advance(itDataEnd, nOffset);
1651 :
1652 5 : rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
1653 5 : break;
1654 : }
1655 :
1656 1 : rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
1657 : }
1658 : }
1659 :
1660 : namespace {
1661 :
1662 : class CopyCellNotesHandler
1663 : {
1664 : ScColumn& mrDestCol;
1665 : sc::CellNoteStoreType& mrDestNotes;
1666 : sc::CellNoteStoreType::iterator miPos;
1667 : SCTAB mnSrcTab;
1668 : SCCOL mnSrcCol;
1669 : SCTAB mnDestTab;
1670 : SCCOL mnDestCol;
1671 : SCROW mnDestOffset; /// Add this to the source row position to get the destination row.
1672 : bool mbCloneCaption;
1673 :
1674 : public:
1675 39 : CopyCellNotesHandler( const ScColumn& rSrcCol, ScColumn& rDestCol, SCROW nDestOffset, bool bCloneCaption ) :
1676 : mrDestCol(rDestCol),
1677 39 : mrDestNotes(rDestCol.GetCellNoteStore()),
1678 : miPos(mrDestNotes.begin()),
1679 39 : mnSrcTab(rSrcCol.GetTab()),
1680 39 : mnSrcCol(rSrcCol.GetCol()),
1681 39 : mnDestTab(rDestCol.GetTab()),
1682 39 : mnDestCol(rDestCol.GetCol()),
1683 : mnDestOffset(nDestOffset),
1684 234 : mbCloneCaption(bCloneCaption) {}
1685 :
1686 49 : void operator() ( size_t nRow, const ScPostIt* p )
1687 : {
1688 49 : SCROW nDestRow = nRow + mnDestOffset;
1689 49 : ScAddress aSrcPos(mnSrcCol, nRow, mnSrcTab);
1690 49 : ScAddress aDestPos(mnDestCol, nDestRow, mnDestTab);
1691 49 : miPos = mrDestNotes.set(miPos, nDestRow, p->Clone(aSrcPos, mrDestCol.GetDoc(), aDestPos, mbCloneCaption));
1692 49 : }
1693 : };
1694 :
1695 : }
1696 :
1697 91670 : void ScColumn::CopyCellNotesToDocument(
1698 : SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, bool bCloneCaption, SCROW nRowOffsetDest ) const
1699 : {
1700 91670 : if (IsNotesEmptyBlock(nRow1, nRow2))
1701 : // The column has no cell notes to copy between specified rows.
1702 183301 : return;
1703 :
1704 39 : ScDrawLayer *pDrawLayer = rDestCol.GetDoc().GetDrawLayer();
1705 39 : bool bWasLocked = bool();
1706 39 : if (pDrawLayer)
1707 : {
1708 : // Avoid O(n^2) by temporary locking SdrModel which disables broadcasting.
1709 : // Each cell note adds undo listener, and all of them would be woken up in ScPostIt::CreateCaption.
1710 7 : bWasLocked = pDrawLayer->isLocked();
1711 7 : pDrawLayer->setLock(true);
1712 : }
1713 39 : CopyCellNotesHandler aFunc(*this, rDestCol, nRowOffsetDest, bCloneCaption);
1714 39 : sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
1715 39 : if (pDrawLayer)
1716 7 : pDrawLayer->setLock(bWasLocked);
1717 : }
1718 :
1719 91664 : void ScColumn::DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol, sc::ColumnBlockPosition& maDestBlockPos,
1720 : bool bCloneCaption, SCROW nRowOffsetDest ) const
1721 : {
1722 91664 : CopyCellNotesToDocument(nStartRow, nStartRow + nDataSize -1, rDestCol, bCloneCaption, nRowOffsetDest);
1723 91664 : maDestBlockPos.miCellNotePos = rDestCol.maCellNotes.begin();
1724 91664 : }
1725 :
1726 58164 : SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow)
1727 : {
1728 58164 : return maBroadcasters.get<SvtBroadcaster*>(nRow);
1729 : }
1730 :
1731 14 : const SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow) const
1732 : {
1733 14 : return maBroadcasters.get<SvtBroadcaster*>(nRow);
1734 : }
1735 :
1736 599 : const SvtBroadcaster* ScColumn::GetBroadcaster( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
1737 : {
1738 599 : sc::BroadcasterStoreType::const_position_type aPos = maBroadcasters.position(rBlockPos.miBroadcasterPos, nRow);
1739 599 : rBlockPos.miBroadcasterPos = aPos.first;
1740 :
1741 599 : if (aPos.first->type != sc::element_type_broadcaster)
1742 476 : return NULL;
1743 :
1744 123 : return sc::broadcaster_block::at(*aPos.first->data, aPos.second);
1745 : }
1746 :
1747 125 : void ScColumn::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
1748 : {
1749 250 : rBlockPos.miBroadcasterPos =
1750 125 : maBroadcasters.set_empty(rBlockPos.miBroadcasterPos, nRow1, nRow2);
1751 125 : }
1752 :
1753 2437120 : void ScColumn::PrepareBroadcastersForDestruction()
1754 : {
1755 2437120 : sc::BroadcasterStoreType::iterator itPos = maBroadcasters.begin(), itPosEnd = maBroadcasters.end();
1756 4878122 : for (; itPos != itPosEnd; ++itPos)
1757 : {
1758 2441002 : if (itPos->type == sc::element_type_broadcaster)
1759 : {
1760 2055 : sc::broadcaster_block::iterator it = sc::broadcaster_block::begin(*itPos->data);
1761 2055 : sc::broadcaster_block::iterator itEnd = sc::broadcaster_block::end(*itPos->data);
1762 9905 : for (; it != itEnd; ++it)
1763 7850 : (*it)->PrepareForDestruction();
1764 : }
1765 : }
1766 2437120 : }
1767 :
1768 0 : bool ScColumn::HasBroadcaster() const
1769 : {
1770 0 : sc::BroadcasterStoreType::const_iterator it = maBroadcasters.begin(), itEnd = maBroadcasters.end();
1771 0 : for (; it != itEnd; ++it)
1772 : {
1773 0 : if (it->type == sc::element_type_broadcaster)
1774 : // Having a broadcaster block automatically means there is at least one broadcaster.
1775 0 : return true;
1776 : }
1777 0 : return false;
1778 : }
1779 :
1780 207031 : ScPostIt* ScColumn::GetCellNote(SCROW nRow)
1781 : {
1782 207031 : return maCellNotes.get<ScPostIt*>(nRow);
1783 : }
1784 :
1785 131 : const ScPostIt* ScColumn::GetCellNote(SCROW nRow) const
1786 : {
1787 131 : return maCellNotes.get<ScPostIt*>(nRow);
1788 : }
1789 :
1790 599 : const ScPostIt* ScColumn::GetCellNote( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
1791 : {
1792 599 : sc::CellNoteStoreType::const_position_type aPos = maCellNotes.position(rBlockPos.miCellNotePos, nRow);
1793 599 : rBlockPos.miCellNotePos = aPos.first;
1794 :
1795 599 : if (aPos.first->type != sc::element_type_cellnote)
1796 598 : return NULL;
1797 :
1798 1 : return sc::cellnote_block::at(*aPos.first->data, aPos.second);
1799 : }
1800 :
1801 72 : void ScColumn::SetCellNote(SCROW nRow, ScPostIt* pNote)
1802 : {
1803 : //pNote->UpdateCaptionPos(ScAddress(nCol, nRow, nTab)); // TODO notes useful ? slow import with many notes
1804 72 : maCellNotes.set(nRow, pNote);
1805 72 : }
1806 :
1807 48521 : void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
1808 : {
1809 97042 : rBlockPos.miCellNotePos =
1810 48521 : maCellNotes.set_empty(rBlockPos.miCellNotePos, nRow1, nRow2);
1811 48521 : }
1812 :
1813 4995083 : bool ScColumn::HasCellNotes() const
1814 : {
1815 4995083 : sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
1816 9990155 : for (; it != itEnd; ++it)
1817 : {
1818 4995159 : if (it->type == sc::element_type_cellnote)
1819 : // Having a cellnote block automatically means there is at least one cell note.
1820 87 : return true;
1821 : }
1822 4994996 : return false;
1823 : }
1824 :
1825 50 : SCROW ScColumn::GetCellNotesMaxRow() const
1826 : {
1827 : // hypothesis : the column has cell notes (should be checked before)
1828 50 : SCROW maxRow = 0;
1829 50 : sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
1830 195 : for (; it != itEnd; ++it)
1831 : {
1832 145 : if (it->type == sc::element_type_cellnote)
1833 50 : maxRow = it->position + it->size -1;
1834 : }
1835 50 : return maxRow;
1836 : }
1837 34 : SCROW ScColumn::GetCellNotesMinRow() const
1838 : {
1839 : // hypothesis : the column has cell notes (should be checked before)
1840 34 : SCROW minRow = 0;
1841 34 : bool bFound = false;
1842 34 : sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
1843 99 : for (; it != itEnd && !bFound; ++it)
1844 : {
1845 65 : if (it->type == sc::element_type_cellnote)
1846 : {
1847 34 : bFound = true;
1848 34 : minRow = it->position;
1849 : }
1850 : }
1851 34 : return minRow;
1852 : }
1853 :
1854 49 : sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
1855 : {
1856 49 : return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnTextWidth;
1857 : }
1858 :
1859 30 : void ScColumn::SetTextWidth(SCROW nRow, sal_uInt16 nWidth)
1860 : {
1861 30 : sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
1862 30 : if (aPos.first->type != sc::element_type_celltextattr)
1863 30 : return;
1864 :
1865 : // Set new value only when the slot is not empty.
1866 30 : sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnTextWidth = nWidth;
1867 30 : CellStorageModified();
1868 : }
1869 :
1870 31225 : SvtScriptType ScColumn::GetScriptType( SCROW nRow ) const
1871 : {
1872 31225 : if (!ValidRow(nRow) || maCellTextAttrs.is_empty(nRow))
1873 1657 : return SvtScriptType::NONE;
1874 :
1875 29568 : return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnScriptType;
1876 : }
1877 :
1878 63889 : SvtScriptType ScColumn::GetRangeScriptType(
1879 : sc::CellTextAttrStoreType::iterator& itPos, SCROW nRow1, SCROW nRow2, const sc::CellStoreType::iterator& itrCells )
1880 : {
1881 63889 : if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
1882 0 : return SvtScriptType::NONE;
1883 :
1884 63889 : SCROW nRow = nRow1;
1885 : std::pair<sc::CellTextAttrStoreType::iterator,size_t> aRet =
1886 63889 : maCellTextAttrs.position(itPos, nRow1);
1887 :
1888 63889 : itPos = aRet.first; // Track the position of cell text attribute array.
1889 :
1890 63889 : SvtScriptType nScriptType = SvtScriptType::NONE;
1891 63889 : bool bUpdated = false;
1892 63889 : if (itPos->type == sc::element_type_celltextattr)
1893 : {
1894 63745 : sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
1895 63745 : sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
1896 63745 : std::advance(it, aRet.second);
1897 127630 : for (; it != itEnd; ++it, ++nRow)
1898 : {
1899 125276 : if (nRow > nRow2)
1900 61391 : return nScriptType;
1901 :
1902 63885 : sc::CellTextAttr& rVal = *it;
1903 63885 : if (UpdateScriptType(rVal, nRow, itrCells))
1904 24849 : bUpdated = true;
1905 63885 : nScriptType |= rVal.mnScriptType;
1906 : }
1907 : }
1908 : else
1909 : {
1910 : // Skip this whole block.
1911 144 : nRow += itPos->size - aRet.second;
1912 : }
1913 :
1914 4996 : while (nRow <= nRow2)
1915 : {
1916 0 : ++itPos;
1917 0 : if (itPos == maCellTextAttrs.end())
1918 0 : return nScriptType;
1919 :
1920 0 : if (itPos->type != sc::element_type_celltextattr)
1921 : {
1922 : // Skip this whole block.
1923 0 : nRow += itPos->size;
1924 0 : continue;
1925 : }
1926 :
1927 0 : sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
1928 0 : sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
1929 0 : for (; it != itEnd; ++it, ++nRow)
1930 : {
1931 0 : if (nRow > nRow2)
1932 0 : return nScriptType;
1933 :
1934 0 : sc::CellTextAttr& rVal = *it;
1935 0 : if (UpdateScriptType(rVal, nRow, itrCells))
1936 0 : bUpdated = true;
1937 :
1938 0 : nScriptType |= rVal.mnScriptType;
1939 : }
1940 : }
1941 :
1942 2498 : if (bUpdated)
1943 550 : CellStorageModified();
1944 :
1945 2498 : return nScriptType;
1946 : }
1947 :
1948 3642 : void ScColumn::SetScriptType( SCROW nRow, SvtScriptType nType )
1949 : {
1950 3642 : if (!ValidRow(nRow))
1951 0 : return;
1952 :
1953 3642 : sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
1954 3642 : if (aPos.first->type != sc::element_type_celltextattr)
1955 : // Set new value only when the slot is already set.
1956 0 : return;
1957 :
1958 3642 : sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnScriptType = nType;
1959 3642 : CellStorageModified();
1960 : }
1961 :
1962 38 : size_t ScColumn::GetFormulaHash( SCROW nRow ) const
1963 : {
1964 38 : const ScFormulaCell* pCell = FetchFormulaCell(nRow);
1965 38 : return pCell ? pCell->GetHash() : 0;
1966 : }
1967 :
1968 6 : ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
1969 : {
1970 6 : const ScFormulaCell* pCell = FetchFormulaCell(nRow);
1971 6 : return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
1972 : }
1973 :
1974 0 : formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
1975 : {
1976 0 : std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
1977 0 : sc::CellStoreType::iterator it = aPos.first;
1978 0 : if (it == maCells.end())
1979 : // Invalid row. Return a null token.
1980 0 : return formula::FormulaTokenRef();
1981 :
1982 0 : switch (it->type)
1983 : {
1984 : case sc::element_type_numeric:
1985 : {
1986 0 : double fVal = sc::numeric_block::at(*it->data, aPos.second);
1987 0 : return formula::FormulaTokenRef(new formula::FormulaDoubleToken(fVal));
1988 : }
1989 : case sc::element_type_formula:
1990 : {
1991 0 : ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
1992 0 : if (p->IsValue())
1993 0 : return formula::FormulaTokenRef(new formula::FormulaDoubleToken(p->GetValue()));
1994 :
1995 0 : return formula::FormulaTokenRef(new formula::FormulaStringToken(p->GetString()));
1996 : }
1997 : case sc::element_type_string:
1998 : {
1999 0 : const svl::SharedString& rSS = sc::string_block::at(*it->data, aPos.second);
2000 0 : return formula::FormulaTokenRef(new formula::FormulaStringToken(rSS.getString()));
2001 : }
2002 : case sc::element_type_edittext:
2003 : {
2004 0 : const EditTextObject* pText = sc::edittext_block::at(*it->data, aPos.second);
2005 0 : OUString aStr = ScEditUtil::GetString(*pText, pDocument);
2006 0 : return formula::FormulaTokenRef(new formula::FormulaStringToken(aStr));
2007 : }
2008 : case sc::element_type_empty:
2009 : default:
2010 : // Return a value of 0.0 in all the other cases.
2011 0 : return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
2012 : }
2013 : }
2014 :
2015 : namespace {
2016 :
2017 : class ToMatrixHandler
2018 : {
2019 : ScMatrix& mrMat;
2020 : SCCOL mnMatCol;
2021 : SCROW mnTopRow;
2022 : ScDocument* mpDoc;
2023 : svl::SharedStringPool& mrStrPool;
2024 : public:
2025 0 : ToMatrixHandler(ScMatrix& rMat, SCCOL nMatCol, SCROW nTopRow, ScDocument* pDoc) :
2026 : mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow),
2027 0 : mpDoc(pDoc), mrStrPool(pDoc->GetSharedStringPool()) {}
2028 :
2029 0 : void operator() (size_t nRow, double fVal)
2030 : {
2031 0 : mrMat.PutDouble(fVal, mnMatCol, nRow - mnTopRow);
2032 0 : }
2033 :
2034 0 : void operator() (size_t nRow, const ScFormulaCell* p)
2035 : {
2036 : // Formula cell may need to re-calculate.
2037 0 : ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*p);
2038 0 : if (rCell.IsValue())
2039 0 : mrMat.PutDouble(rCell.GetValue(), mnMatCol, nRow - mnTopRow);
2040 : else
2041 0 : mrMat.PutString(rCell.GetString(), mnMatCol, nRow - mnTopRow);
2042 0 : }
2043 :
2044 0 : void operator() (size_t nRow, const svl::SharedString& rSS)
2045 : {
2046 0 : mrMat.PutString(rSS, mnMatCol, nRow - mnTopRow);
2047 0 : }
2048 :
2049 0 : void operator() (size_t nRow, const EditTextObject* pStr)
2050 : {
2051 0 : mrMat.PutString(mrStrPool.intern(ScEditUtil::GetString(*pStr, mpDoc)), mnMatCol, nRow - mnTopRow);
2052 0 : }
2053 : };
2054 :
2055 : }
2056 :
2057 0 : bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
2058 : {
2059 0 : if (nRow1 > nRow2)
2060 0 : return false;
2061 :
2062 0 : ToMatrixHandler aFunc(rMat, nMatCol, nRow1, pDocument);
2063 0 : sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
2064 0 : return true;
2065 : }
2066 :
2067 : namespace {
2068 :
2069 50 : struct CellBucket
2070 : {
2071 : SCSIZE mnEmpValStart;
2072 : SCSIZE mnNumValStart;
2073 : SCSIZE mnStrValStart;
2074 : SCSIZE mnEmpValCount;
2075 : std::vector<double> maNumVals;
2076 : std::vector<svl::SharedString> maStrVals;
2077 :
2078 50 : CellBucket() : mnEmpValStart(0), mnNumValStart(0), mnStrValStart(0), mnEmpValCount(0) {}
2079 :
2080 100 : void flush(ScMatrix& rMat, SCSIZE nCol)
2081 : {
2082 100 : if (mnEmpValCount)
2083 : {
2084 0 : rMat.PutEmptyResultVector(mnEmpValCount, nCol, mnEmpValStart);
2085 0 : reset();
2086 : }
2087 100 : else if (!maNumVals.empty())
2088 : {
2089 50 : const double* p = &maNumVals[0];
2090 50 : rMat.PutDouble(p, maNumVals.size(), nCol, mnNumValStart);
2091 50 : reset();
2092 : }
2093 50 : else if (!maStrVals.empty())
2094 : {
2095 0 : const svl::SharedString* p = &maStrVals[0];
2096 0 : rMat.PutString(p, maStrVals.size(), nCol, mnStrValStart);
2097 0 : reset();
2098 : }
2099 100 : }
2100 :
2101 50 : void reset()
2102 : {
2103 50 : mnEmpValStart = mnNumValStart = mnStrValStart = 0;
2104 50 : mnEmpValCount = 0;
2105 50 : maNumVals.clear();
2106 50 : maStrVals.clear();
2107 50 : }
2108 : };
2109 :
2110 : class FillMatrixHandler
2111 : {
2112 : ScMatrix& mrMat;
2113 : size_t mnMatCol;
2114 : size_t mnTopRow;
2115 :
2116 : SCCOL mnCol;
2117 : SCTAB mnTab;
2118 : ScDocument* mpDoc;
2119 : svl::SharedStringPool& mrPool;
2120 :
2121 : public:
2122 247 : FillMatrixHandler(ScMatrix& rMat, size_t nMatCol, size_t nTopRow, SCCOL nCol, SCTAB nTab, ScDocument* pDoc) :
2123 247 : mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow), mnCol(nCol), mnTab(nTab), mpDoc(pDoc), mrPool(pDoc->GetSharedStringPool()) {}
2124 :
2125 356 : void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2126 : {
2127 356 : size_t nMatRow = node.position + nOffset - mnTopRow;
2128 :
2129 356 : switch (node.type)
2130 : {
2131 : case sc::element_type_numeric:
2132 : {
2133 250 : const double* p = &sc::numeric_block::at(*node.data, nOffset);
2134 250 : mrMat.PutDouble(p, nDataSize, mnMatCol, nMatRow);
2135 : }
2136 250 : break;
2137 : case sc::element_type_string:
2138 : {
2139 13 : const svl::SharedString* p = &sc::string_block::at(*node.data, nOffset);
2140 13 : mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
2141 : }
2142 13 : break;
2143 : case sc::element_type_edittext:
2144 : {
2145 0 : std::vector<svl::SharedString> aSSs;
2146 0 : aSSs.reserve(nDataSize);
2147 0 : sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
2148 0 : std::advance(it, nOffset);
2149 0 : sc::edittext_block::const_iterator itEnd = it;
2150 0 : std::advance(itEnd, nDataSize);
2151 0 : for (; it != itEnd; ++it)
2152 : {
2153 0 : OUString aStr = ScEditUtil::GetString(**it, mpDoc);
2154 0 : aSSs.push_back(mrPool.intern(aStr));
2155 0 : }
2156 :
2157 0 : const svl::SharedString* p = &aSSs[0];
2158 0 : mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
2159 : }
2160 0 : break;
2161 : case sc::element_type_formula:
2162 : {
2163 50 : CellBucket aBucket;
2164 50 : sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
2165 50 : std::advance(it, nOffset);
2166 50 : sc::formula_block::const_iterator itEnd = it;
2167 50 : std::advance(itEnd, nDataSize);
2168 :
2169 50 : size_t nPrevRow = 0, nThisRow = node.position + nOffset;
2170 150 : for (; it != itEnd; ++it, nPrevRow = nThisRow, ++nThisRow)
2171 : {
2172 100 : ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
2173 :
2174 100 : if (rCell.IsEmpty())
2175 : {
2176 0 : if (aBucket.mnEmpValCount && nThisRow == nPrevRow + 1)
2177 : {
2178 : // Secondary empty results.
2179 0 : ++aBucket.mnEmpValCount;
2180 : }
2181 : else
2182 : {
2183 : // First empty result.
2184 0 : aBucket.flush(mrMat, mnMatCol);
2185 0 : aBucket.mnEmpValStart = nThisRow - mnTopRow;
2186 0 : ++aBucket.mnEmpValCount;
2187 : }
2188 100 : continue;
2189 : }
2190 :
2191 : sal_uInt16 nErr;
2192 : double fVal;
2193 100 : if (rCell.GetErrorOrValue(nErr, fVal))
2194 : {
2195 100 : ScAddress aAdr(mnCol, nThisRow, mnTab);
2196 :
2197 100 : if (nErr)
2198 5 : fVal = CreateDoubleError(nErr);
2199 :
2200 100 : if (!aBucket.maNumVals.empty() && nThisRow == nPrevRow + 1)
2201 : {
2202 : // Secondary numbers.
2203 50 : aBucket.maNumVals.push_back(fVal);
2204 : }
2205 : else
2206 : {
2207 : // First number.
2208 50 : aBucket.flush(mrMat, mnMatCol);
2209 50 : aBucket.mnNumValStart = nThisRow - mnTopRow;
2210 50 : aBucket.maNumVals.push_back(fVal);
2211 : }
2212 100 : continue;
2213 : }
2214 :
2215 0 : svl::SharedString aStr = rCell.GetString();
2216 0 : if (!aBucket.maStrVals.empty() && nThisRow == nPrevRow + 1)
2217 : {
2218 : // Secondary strings.
2219 0 : aBucket.maStrVals.push_back(aStr);
2220 : }
2221 : else
2222 : {
2223 : // First string.
2224 0 : aBucket.flush(mrMat, mnMatCol);
2225 0 : aBucket.mnStrValStart = nThisRow - mnTopRow;
2226 0 : aBucket.maStrVals.push_back(aStr);
2227 : }
2228 0 : }
2229 :
2230 50 : aBucket.flush(mrMat, mnMatCol);
2231 : }
2232 50 : break;
2233 : default:
2234 : ;
2235 : }
2236 356 : }
2237 : };
2238 :
2239 : }
2240 :
2241 247 : void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2 ) const
2242 : {
2243 247 : FillMatrixHandler aFunc(rMat, nMatCol, nRow1, nCol, nTab, pDocument);
2244 247 : sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
2245 247 : }
2246 :
2247 : namespace {
2248 :
2249 : template<typename _Blk>
2250 18 : void getBlockIterators(
2251 : const sc::CellStoreType::iterator& it, size_t& rLenRemain,
2252 : typename _Blk::iterator& rData, typename _Blk::iterator& rDataEnd )
2253 : {
2254 18 : rData = _Blk::begin(*it->data);
2255 18 : if (rLenRemain >= it->size)
2256 : {
2257 : // Block is shorter than the remaining requested length.
2258 18 : rDataEnd = _Blk::end(*it->data);
2259 18 : rLenRemain -= it->size;
2260 : }
2261 : else
2262 : {
2263 0 : rDataEnd = rData;
2264 0 : std::advance(rDataEnd, rLenRemain);
2265 0 : rLenRemain = 0;
2266 : }
2267 18 : }
2268 :
2269 11 : bool appendToBlock(
2270 : ScDocument* pDoc, sc::FormulaGroupContext& rCxt, sc::FormulaGroupContext::ColArray& rColArray,
2271 : size_t nPos, size_t nArrayLen, const sc::CellStoreType::iterator& _it, const sc::CellStoreType::iterator& itEnd )
2272 : {
2273 11 : svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
2274 11 : size_t nLenRemain = nArrayLen - nPos;
2275 : double fNan;
2276 11 : rtl::math::setNan(&fNan);
2277 :
2278 29 : for (sc::CellStoreType::iterator it = _it; it != itEnd; ++it)
2279 : {
2280 29 : switch (it->type)
2281 : {
2282 : case sc::element_type_string:
2283 : {
2284 5 : sc::string_block::iterator itData, itDataEnd;
2285 5 : getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
2286 5 : rCxt.ensureStrArray(rColArray, nArrayLen);
2287 :
2288 10 : for (; itData != itDataEnd; ++itData, ++nPos)
2289 5 : (*rColArray.mpStrArray)[nPos] = itData->getDataIgnoreCase();
2290 : }
2291 5 : break;
2292 : case sc::element_type_edittext:
2293 : {
2294 0 : sc::edittext_block::iterator itData, itDataEnd;
2295 0 : getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
2296 0 : rCxt.ensureStrArray(rColArray, nArrayLen);
2297 :
2298 0 : for (; itData != itDataEnd; ++itData, ++nPos)
2299 : {
2300 0 : OUString aStr = ScEditUtil::GetString(**itData, pDoc);
2301 0 : (*rColArray.mpStrArray)[nPos] = rPool.intern(aStr).getDataIgnoreCase();
2302 0 : }
2303 : }
2304 0 : break;
2305 : case sc::element_type_formula:
2306 : {
2307 6 : sc::formula_block::iterator itData, itDataEnd;
2308 6 : getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
2309 :
2310 : /* tdf#91416 setting progress in triggers a resize of the window
2311 : and so ScTabView::DoResize and an InterpretVisible and
2312 : InterpretDirtyCells which resets the mpFormulaGroupCxt that
2313 : the current rCxt points to, which is bad, so disable progress
2314 : during GetResult
2315 : */
2316 6 : ScProgress *pProgress = ScProgress::GetInterpretProgress();
2317 6 : bool bTempDisableProgress = pProgress && pProgress->Enabled();
2318 6 : if (bTempDisableProgress)
2319 6 : pProgress->Disable();
2320 :
2321 14 : for (; itData != itDataEnd; ++itData, ++nPos)
2322 : {
2323 8 : ScFormulaCell& rFC = **itData;
2324 :
2325 8 : sc::FormulaResultValue aRes = rFC.GetResult();
2326 :
2327 8 : if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
2328 : {
2329 0 : if (aRes.mnError == ScErrorCodes::errCircularReference)
2330 : {
2331 : // This cell needs to be recalculated on next visit.
2332 0 : rFC.SetErrCode(0);
2333 0 : rFC.SetDirtyVar();
2334 : }
2335 0 : return false;
2336 : }
2337 :
2338 8 : if (aRes.meType == sc::FormulaResultValue::String)
2339 : {
2340 1 : rCxt.ensureStrArray(rColArray, nArrayLen);
2341 1 : (*rColArray.mpStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
2342 : }
2343 : else
2344 : {
2345 7 : rCxt.ensureNumArray(rColArray, nArrayLen);
2346 7 : (*rColArray.mpNumArray)[nPos] = aRes.mfValue;
2347 : }
2348 8 : }
2349 :
2350 6 : if (bTempDisableProgress)
2351 6 : pProgress->Enable();
2352 : }
2353 6 : break;
2354 : case sc::element_type_empty:
2355 : {
2356 11 : if (nLenRemain > it->size)
2357 : {
2358 3 : nPos += it->size;
2359 3 : nLenRemain -= it->size;
2360 : }
2361 : else
2362 : {
2363 8 : nPos = nArrayLen;
2364 8 : nLenRemain = 0;
2365 : }
2366 : }
2367 11 : break;
2368 : case sc::element_type_numeric:
2369 : {
2370 7 : sc::numeric_block::iterator itData, itDataEnd;
2371 7 : getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
2372 7 : rCxt.ensureNumArray(rColArray, nArrayLen);
2373 :
2374 756 : for (; itData != itDataEnd; ++itData, ++nPos)
2375 749 : (*rColArray.mpNumArray)[nPos] = *itData;
2376 : }
2377 7 : break;
2378 : default:
2379 0 : return false;
2380 : }
2381 :
2382 29 : if (!nLenRemain)
2383 11 : return true;
2384 : }
2385 :
2386 0 : return false;
2387 : }
2388 :
2389 4 : void copyFirstStringBlock(
2390 : ScDocument& rDoc, sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, const sc::CellStoreType::iterator& itBlk )
2391 : {
2392 4 : sc::FormulaGroupContext::StrArrayType::iterator itArray = rArray.begin();
2393 :
2394 4 : switch (itBlk->type)
2395 : {
2396 : case sc::element_type_string:
2397 : {
2398 4 : sc::string_block::iterator it = sc::string_block::begin(*itBlk->data);
2399 4 : sc::string_block::iterator itEnd = it;
2400 4 : std::advance(itEnd, nLen);
2401 20 : for (; it != itEnd; ++it, ++itArray)
2402 16 : *itArray = it->getDataIgnoreCase();
2403 : }
2404 4 : break;
2405 : case sc::element_type_edittext:
2406 : {
2407 0 : sc::edittext_block::iterator it = sc::edittext_block::begin(*itBlk->data);
2408 0 : sc::edittext_block::iterator itEnd = it;
2409 0 : std::advance(itEnd, nLen);
2410 :
2411 0 : svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
2412 0 : for (; it != itEnd; ++it, ++itArray)
2413 : {
2414 0 : EditTextObject* pText = *it;
2415 0 : OUString aStr = ScEditUtil::GetString(*pText, &rDoc);
2416 0 : *itArray = rPool.intern(aStr).getDataIgnoreCase();
2417 0 : }
2418 : }
2419 0 : break;
2420 : default:
2421 : ;
2422 : }
2423 4 : }
2424 :
2425 : sc::FormulaGroupContext::ColArray*
2426 4 : copyFirstFormulaBlock(
2427 : sc::FormulaGroupContext& rCxt, const sc::CellStoreType::iterator& itBlk, size_t nArrayLen,
2428 : SCTAB nTab, SCCOL nCol )
2429 : {
2430 : double fNan;
2431 4 : rtl::math::setNan(&fNan);
2432 :
2433 4 : size_t nLen = std::min(itBlk->size, nArrayLen);
2434 :
2435 4 : sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data);
2436 4 : sc::formula_block::iterator itEnd;
2437 :
2438 4 : sc::FormulaGroupContext::NumArrayType* pNumArray = NULL;
2439 4 : sc::FormulaGroupContext::StrArrayType* pStrArray = NULL;
2440 :
2441 4 : itEnd = it;
2442 4 : std::advance(itEnd, nLen);
2443 4 : size_t nPos = 0;
2444 32 : for (; it != itEnd; ++it, ++nPos)
2445 : {
2446 28 : ScFormulaCell& rFC = **it;
2447 28 : sc::FormulaResultValue aRes = rFC.GetResult();
2448 28 : if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
2449 : {
2450 0 : if (aRes.mnError == ScErrorCodes::errCircularReference)
2451 : {
2452 : // This cell needs to be recalculated on next visit.
2453 0 : rFC.SetErrCode(0);
2454 0 : rFC.SetDirtyVar();
2455 : }
2456 0 : return NULL;
2457 : }
2458 :
2459 28 : if (aRes.meType == sc::FormulaResultValue::Value)
2460 : {
2461 28 : if (!pNumArray)
2462 : {
2463 : rCxt.maNumArrays.push_back(
2464 4 : new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
2465 4 : pNumArray = &rCxt.maNumArrays.back();
2466 : }
2467 :
2468 28 : (*pNumArray)[nPos] = aRes.mfValue;
2469 : }
2470 : else
2471 : {
2472 0 : if (!pStrArray)
2473 : {
2474 : rCxt.maStrArrays.push_back(
2475 0 : new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
2476 0 : pStrArray = &rCxt.maStrArrays.back();
2477 : }
2478 :
2479 0 : (*pStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
2480 : }
2481 28 : }
2482 :
2483 4 : if (!pNumArray && !pStrArray)
2484 : // At least one of these arrays should be allocated.
2485 0 : return NULL;
2486 :
2487 4 : return rCxt.setCachedColArray(nTab, nCol, pNumArray, pStrArray);
2488 : }
2489 :
2490 : struct NonNullStringFinder : std::unary_function<const rtl_uString*, bool>
2491 : {
2492 751 : bool operator() (const rtl_uString* p) const { return p != NULL; }
2493 : };
2494 :
2495 5 : bool hasNonEmpty( const sc::FormulaGroupContext::StrArrayType& rArray, SCROW nRow1, SCROW nRow2 )
2496 : {
2497 : // The caller has to make sure the array is at least nRow2+1 long.
2498 5 : sc::FormulaGroupContext::StrArrayType::const_iterator it = rArray.begin();
2499 5 : std::advance(it, nRow1);
2500 5 : sc::FormulaGroupContext::StrArrayType::const_iterator itEnd = it;
2501 5 : std::advance(itEnd, nRow2-nRow1+1);
2502 5 : return std::any_of(it, itEnd, NonNullStringFinder());
2503 : }
2504 :
2505 : }
2506 :
2507 22 : formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2 )
2508 : {
2509 22 : if (nRow1 > nRow2)
2510 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2511 :
2512 : // See if the requested range is already cached.
2513 22 : sc::FormulaGroupContext& rCxt = pDocument->GetFormulaGroupContext();
2514 22 : sc::FormulaGroupContext::ColArray* pColArray = rCxt.getCachedColArray(nTab, nCol, nRow2+1);
2515 22 : if (pColArray)
2516 : {
2517 4 : const double* pNum = NULL;
2518 4 : if (pColArray->mpNumArray)
2519 4 : pNum = &(*pColArray->mpNumArray)[nRow1];
2520 :
2521 4 : rtl_uString** pStr = NULL;
2522 4 : if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
2523 0 : pStr = &(*pColArray->mpStrArray)[nRow1];
2524 :
2525 4 : return formula::VectorRefArray(pNum, pStr);
2526 : }
2527 :
2528 : double fNan;
2529 18 : rtl::math::setNan(&fNan);
2530 :
2531 : // We need to fetch all cell values from row 0 to nRow2 for caching purposes.
2532 18 : sc::CellStoreType::iterator itBlk = maCells.begin();
2533 18 : switch (itBlk->type)
2534 : {
2535 : case sc::element_type_numeric:
2536 : {
2537 3 : if (static_cast<size_t>(nRow2) < itBlk->size)
2538 : {
2539 : // Requested range falls within the first block. No need to cache.
2540 1 : const double* p = &sc::numeric_block::at(*itBlk->data, nRow1);
2541 1 : return formula::VectorRefArray(p);
2542 : }
2543 :
2544 : // Allocate a new array and copy the values to it.
2545 2 : sc::numeric_block::const_iterator it = sc::numeric_block::begin(*itBlk->data);
2546 2 : sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*itBlk->data);
2547 2 : rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(it, itEnd));
2548 2 : sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
2549 2 : rArray.resize(nRow2+1, fNan); // allocate to the requested length.
2550 :
2551 2 : pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
2552 2 : if (!pColArray)
2553 : // Failed to insert a new cached column array.
2554 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2555 :
2556 : // Fill the remaining array with values from the following blocks.
2557 2 : size_t nPos = itBlk->size;
2558 2 : ++itBlk;
2559 2 : if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2560 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2561 :
2562 2 : if (pColArray->mpStrArray)
2563 1 : return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
2564 : else
2565 1 : return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
2566 : }
2567 : break;
2568 : case sc::element_type_string:
2569 : case sc::element_type_edittext:
2570 : {
2571 4 : rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType(nRow2+1, NULL));
2572 4 : sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
2573 4 : pColArray = rCxt.setCachedColArray(nTab, nCol, NULL, &rArray);
2574 4 : if (!pColArray)
2575 : // Failed to insert a new cached column array.
2576 0 : return formula::VectorRefArray();
2577 :
2578 4 : if (static_cast<size_t>(nRow2) < itBlk->size)
2579 : {
2580 : // Requested range falls within the first block.
2581 2 : copyFirstStringBlock(*pDocument, rArray, nRow2+1, itBlk);
2582 2 : return formula::VectorRefArray(&rArray[nRow1]);
2583 : }
2584 :
2585 2 : copyFirstStringBlock(*pDocument, rArray, itBlk->size, itBlk);
2586 :
2587 : // Fill the remaining array with values from the following blocks.
2588 2 : size_t nPos = itBlk->size;
2589 2 : ++itBlk;
2590 2 : if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2591 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2592 :
2593 2 : if (pColArray->mpNumArray)
2594 1 : return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
2595 : else
2596 1 : return formula::VectorRefArray(&(*pColArray->mpStrArray)[nRow1]);
2597 : }
2598 : break;
2599 : case sc::element_type_formula:
2600 : {
2601 4 : if (static_cast<size_t>(nRow2) < itBlk->size)
2602 : {
2603 : // Requested length is within a single block, and the data is
2604 : // not cached.
2605 2 : pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
2606 2 : if (!pColArray)
2607 : // Failed to insert a new cached column array.
2608 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2609 :
2610 2 : const double* pNum = NULL;
2611 2 : rtl_uString** pStr = NULL;
2612 2 : if (pColArray->mpNumArray)
2613 2 : pNum = &(*pColArray->mpNumArray)[nRow1];
2614 2 : if (pColArray->mpStrArray)
2615 0 : pStr = &(*pColArray->mpStrArray)[nRow1];
2616 :
2617 2 : return formula::VectorRefArray(pNum, pStr);
2618 : }
2619 :
2620 2 : pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
2621 2 : if (!pColArray)
2622 : // Failed to insert a new cached column array.
2623 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2624 :
2625 2 : size_t nPos = itBlk->size;
2626 2 : ++itBlk;
2627 2 : if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2628 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2629 :
2630 2 : const double* pNum = NULL;
2631 2 : rtl_uString** pStr = NULL;
2632 2 : if (pColArray->mpNumArray)
2633 2 : pNum = &(*pColArray->mpNumArray)[nRow1];
2634 2 : if (pColArray->mpStrArray)
2635 1 : pStr = &(*pColArray->mpStrArray)[nRow1];
2636 :
2637 2 : return formula::VectorRefArray(pNum, pStr);
2638 : }
2639 : break;
2640 : case sc::element_type_empty:
2641 : {
2642 : // Fill the whole length with NaN's.
2643 7 : rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nRow2+1, fNan));
2644 7 : sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
2645 7 : pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
2646 7 : if (!pColArray)
2647 : // Failed to insert a new cached column array.
2648 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2649 :
2650 7 : if (static_cast<size_t>(nRow2) < itBlk->size)
2651 2 : return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
2652 :
2653 : // Fill the remaining array with values from the following blocks.
2654 5 : size_t nPos = itBlk->size;
2655 5 : ++itBlk;
2656 5 : if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2657 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2658 :
2659 5 : if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
2660 0 : return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
2661 : else
2662 5 : return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
2663 : }
2664 : break;
2665 : default:
2666 : ;
2667 : }
2668 :
2669 0 : return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2670 : }
2671 :
2672 0 : void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen )
2673 : {
2674 0 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
2675 0 : sc::CellStoreType::iterator it = aPos.first;
2676 0 : if (it->type != sc::element_type_formula)
2677 : // This is not a formula block.
2678 0 : return;
2679 :
2680 0 : size_t nBlockLen = it->size - aPos.second;
2681 0 : if (nBlockLen < nLen)
2682 : // Result array is longer than the length of formula cells. Not good.
2683 0 : return;
2684 :
2685 0 : sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
2686 0 : std::advance(itCell, aPos.second);
2687 :
2688 0 : const double* pResEnd = pResults + nLen;
2689 0 : for (; pResults != pResEnd; ++pResults, ++itCell)
2690 : {
2691 0 : ScFormulaCell& rCell = **itCell;
2692 0 : sal_uInt16 nErr = GetDoubleErrorValue(*pResults);
2693 0 : if (nErr != 0)
2694 0 : rCell.SetResultError(nErr);
2695 : else
2696 0 : rCell.SetResultDouble(*pResults);
2697 0 : rCell.ResetDirty();
2698 0 : rCell.SetChanged(true);
2699 : }
2700 : }
2701 :
2702 0 : void ScColumn::SetFormulaResults( SCROW nRow, const formula::FormulaTokenRef* pResults, size_t nLen )
2703 : {
2704 0 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
2705 0 : sc::CellStoreType::iterator it = aPos.first;
2706 0 : if (it->type != sc::element_type_formula)
2707 : // This is not a formula block.
2708 0 : return;
2709 :
2710 0 : size_t nBlockLen = it->size - aPos.second;
2711 0 : if (nBlockLen < nLen)
2712 : // Result array is longer than the length of formula cells. Not good.
2713 0 : return;
2714 :
2715 0 : sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
2716 0 : std::advance(itCell, aPos.second);
2717 :
2718 0 : const formula::FormulaTokenRef* pResEnd = pResults + nLen;
2719 0 : for (; pResults != pResEnd; ++pResults, ++itCell)
2720 : {
2721 0 : ScFormulaCell& rCell = **itCell;
2722 0 : rCell.SetResultToken(pResults->get());
2723 0 : rCell.ResetDirty();
2724 0 : rCell.SetChanged(true);
2725 : }
2726 : }
2727 :
2728 78 : void ScColumn::SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat )
2729 : {
2730 78 : ApplyAttr(nRow, SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat));
2731 78 : }
2732 :
2733 37577 : ScFormulaCell * const * ScColumn::GetFormulaCellBlockAddress( SCROW nRow, size_t& rBlockSize ) const
2734 : {
2735 37577 : if (!ValidRow(nRow))
2736 : {
2737 0 : rBlockSize = 0;
2738 0 : return NULL;
2739 : }
2740 :
2741 37577 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2742 37577 : sc::CellStoreType::const_iterator it = aPos.first;
2743 37577 : if (it == maCells.end())
2744 : {
2745 0 : rBlockSize = 0;
2746 0 : return NULL;
2747 : }
2748 :
2749 37577 : if (it->type != sc::element_type_formula)
2750 : {
2751 : // Not a formula cell.
2752 33112 : rBlockSize = 0;
2753 33112 : return NULL;
2754 : }
2755 :
2756 4465 : rBlockSize = it->size;
2757 4465 : return &sc::formula_block::at(*it->data, aPos.second);
2758 : }
2759 :
2760 37556 : const ScFormulaCell* ScColumn::FetchFormulaCell( SCROW nRow ) const
2761 : {
2762 37556 : size_t nBlockSize = 0;
2763 37556 : ScFormulaCell const * const * pp = GetFormulaCellBlockAddress( nRow, nBlockSize );
2764 37556 : return pp ? *pp : NULL;
2765 : }
2766 :
2767 49 : void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
2768 : {
2769 : // If the cell is empty, find the next non-empty cell position. If the
2770 : // cell is not empty, find the last non-empty cell position in the current
2771 : // contiguous cell block.
2772 :
2773 49 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
2774 49 : sc::CellStoreType::const_iterator it = aPos.first;
2775 49 : if (it == maCells.end())
2776 : // Invalid row.
2777 17 : return;
2778 :
2779 49 : if (it->type == sc::element_type_empty)
2780 : {
2781 : // Current cell is empty. Find the next non-empty cell.
2782 12 : rRow = FindNextVisibleRowWithContent(it, rRow, bDown);
2783 12 : return;
2784 : }
2785 :
2786 : // Current cell is not empty.
2787 37 : SCROW nNextRow = FindNextVisibleRow(rRow, bDown);
2788 37 : aPos = maCells.position(it, nNextRow);
2789 37 : it = aPos.first;
2790 37 : if (it->type == sc::element_type_empty)
2791 : {
2792 : // Next visible cell is empty. Find the next non-empty cell.
2793 5 : rRow = FindNextVisibleRowWithContent(it, nNextRow, bDown);
2794 5 : return;
2795 : }
2796 :
2797 : // Next visible cell is non-empty. Find the edge that's still visible.
2798 32 : SCROW nLastRow = nNextRow;
2799 393330 : do
2800 : {
2801 393345 : nNextRow = FindNextVisibleRow(nLastRow, bDown);
2802 393345 : if (nNextRow == nLastRow)
2803 15 : break;
2804 :
2805 393330 : aPos = maCells.position(it, nNextRow);
2806 393330 : it = aPos.first;
2807 393330 : if (it->type != sc::element_type_empty)
2808 393313 : nLastRow = nNextRow;
2809 : }
2810 393330 : while (it->type != sc::element_type_empty);
2811 :
2812 32 : rRow = nLastRow;
2813 : }
2814 :
2815 5019 : bool ScColumn::HasDataAt(SCROW nRow) const
2816 : {
2817 5019 : return maCells.get_type(nRow) != sc::element_type_empty;
2818 : }
2819 :
2820 43998 : bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
2821 : {
2822 43998 : if (pAttrArray && rCol.pAttrArray)
2823 43998 : return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
2824 : else
2825 0 : return !pAttrArray && !rCol.pAttrArray;
2826 : }
2827 :
2828 12035 : bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
2829 : {
2830 12035 : if (pAttrArray && rCol.pAttrArray)
2831 12035 : return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
2832 : else
2833 0 : return !pAttrArray && !rCol.pAttrArray;
2834 : }
2835 :
2836 2085888 : bool ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
2837 : {
2838 2085888 : if (pAttrArray)
2839 2085888 : return pAttrArray->GetFirstVisibleAttr( rFirstRow );
2840 : else
2841 0 : return false;
2842 : }
2843 :
2844 3248305 : bool ScColumn::GetLastVisibleAttr( SCROW& rLastRow, bool bFullFormattedArea ) const
2845 : {
2846 3248305 : if (pAttrArray)
2847 : {
2848 : // row of last cell is needed
2849 3248305 : SCROW nLastData = GetLastDataPos(); // always including notes, 0 if none
2850 :
2851 3248305 : return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData, bFullFormattedArea );
2852 : }
2853 : else
2854 0 : return false;
2855 : }
2856 :
2857 0 : bool ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
2858 : {
2859 0 : if (pAttrArray)
2860 0 : return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
2861 : else
2862 0 : return false;
2863 : }
2864 :
2865 : namespace {
2866 :
2867 : class FindUsedRowsHandler
2868 : {
2869 : typedef mdds::flat_segment_tree<SCROW,bool> UsedRowsType;
2870 : UsedRowsType& mrUsed;
2871 : UsedRowsType::const_iterator miUsed;
2872 : public:
2873 10 : FindUsedRowsHandler(UsedRowsType& rUsed) : mrUsed(rUsed), miUsed(rUsed.begin()) {}
2874 :
2875 39 : void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2876 : {
2877 39 : if (node.type == sc::element_type_empty)
2878 51 : return;
2879 :
2880 27 : SCROW nRow1 = node.position + nOffset;
2881 27 : SCROW nRow2 = nRow1 + nDataSize - 1;
2882 27 : miUsed = mrUsed.insert(miUsed, nRow1, nRow2+1, true).first;
2883 : }
2884 : };
2885 :
2886 : }
2887 :
2888 10 : void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree<SCROW,bool>& rUsed ) const
2889 : {
2890 10 : FindUsedRowsHandler aFunc(rUsed);
2891 10 : sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
2892 10 : }
2893 :
2894 : namespace {
2895 :
2896 14703 : void startListening(
2897 : sc::BroadcasterStoreType& rStore, sc::BroadcasterStoreType::iterator& itBlockPos, size_t nElemPos,
2898 : SCROW nRow, SvtListener& rLst)
2899 : {
2900 14703 : switch (itBlockPos->type)
2901 : {
2902 : case sc::element_type_broadcaster:
2903 : {
2904 : // Broadcaster already exists here.
2905 6136 : SvtBroadcaster* pBC = sc::broadcaster_block::at(*itBlockPos->data, nElemPos);
2906 6136 : rLst.StartListening(*pBC);
2907 : }
2908 6136 : break;
2909 : case mdds::mtv::element_type_empty:
2910 : {
2911 : // No broadcaster exists at this position yet.
2912 8567 : SvtBroadcaster* pBC = new SvtBroadcaster;
2913 8567 : rLst.StartListening(*pBC);
2914 8567 : itBlockPos = rStore.set(itBlockPos, nRow, pBC); // Store the block position for next iteration.
2915 : }
2916 8567 : break;
2917 : default:
2918 : #if DEBUG_COLUMN_STORAGE
2919 : cout << "ScColumn::StartListening: wrong block type encountered in the broadcaster storage." << endl;
2920 : cout.flush();
2921 : abort();
2922 : #else
2923 : ;
2924 : #endif
2925 : }
2926 14703 : }
2927 :
2928 : }
2929 :
2930 1059 : void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
2931 : {
2932 1059 : std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(nRow);
2933 1059 : startListening(maBroadcasters, aPos.first, aPos.second, nRow, rLst);
2934 1059 : }
2935 :
2936 775 : void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
2937 : {
2938 775 : SvtBroadcaster* pBC = GetBroadcaster(nRow);
2939 775 : if (!pBC)
2940 861 : return;
2941 :
2942 689 : rLst.EndListening(*pBC);
2943 689 : if (!pBC->HasListeners())
2944 : // There is no more listeners for this cell. Remove the broadcaster.
2945 423 : maBroadcasters.set_empty(nRow, nRow);
2946 : }
2947 :
2948 13644 : void ScColumn::StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rLst )
2949 : {
2950 13644 : if (!ValidRow(nRow))
2951 0 : return;
2952 :
2953 13644 : sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
2954 13644 : if (!p)
2955 0 : return;
2956 :
2957 13644 : sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
2958 13644 : std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
2959 13644 : it = aPos.first; // store the block position for next iteration.
2960 13644 : startListening(maBroadcasters, it, aPos.second, nRow, rLst);
2961 : }
2962 :
2963 595 : void ScColumn::EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener )
2964 : {
2965 595 : sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
2966 595 : if (!p)
2967 6 : return;
2968 :
2969 595 : sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
2970 595 : std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
2971 595 : it = aPos.first; // store the block position for next iteration.
2972 595 : if (it->type != sc::element_type_broadcaster)
2973 6 : return;
2974 :
2975 589 : SvtBroadcaster* pBC = sc::broadcaster_block::at(*it->data, aPos.second);
2976 : OSL_ASSERT(pBC);
2977 :
2978 589 : rListener.EndListening(*pBC);
2979 589 : if (!pBC->HasListeners())
2980 : // There is no more listeners for this cell. Add it to the purge list for later purging.
2981 348 : rCxt.addEmptyBroadcasterPosition(nTab, nCol, nRow);
2982 : }
2983 :
2984 : namespace {
2985 :
2986 : class CompileDBFormulaHandler
2987 : {
2988 : sc::CompileFormulaContext& mrCxt;
2989 :
2990 : public:
2991 9216 : CompileDBFormulaHandler( sc::CompileFormulaContext& rCxt ) :
2992 9216 : mrCxt(rCxt) {}
2993 :
2994 2 : void operator() (size_t, ScFormulaCell* p)
2995 : {
2996 2 : p->CompileDBFormula(mrCxt);
2997 2 : }
2998 : };
2999 :
3000 : struct CompileColRowNameFormulaHandler
3001 : {
3002 : sc::CompileFormulaContext& mrCxt;
3003 : public:
3004 7168 : CompileColRowNameFormulaHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
3005 :
3006 0 : void operator() (size_t, ScFormulaCell* p)
3007 : {
3008 0 : p->CompileColRowNameFormula(mrCxt);
3009 0 : }
3010 : };
3011 :
3012 : }
3013 :
3014 9216 : void ScColumn::CompileDBFormula( sc::CompileFormulaContext& rCxt )
3015 : {
3016 9216 : CompileDBFormulaHandler aFunc(rCxt);
3017 9216 : sc::ProcessFormula(maCells, aFunc);
3018 9216 : RegroupFormulaCells();
3019 9216 : }
3020 :
3021 7168 : void ScColumn::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
3022 : {
3023 7168 : CompileColRowNameFormulaHandler aFunc(rCxt);
3024 7168 : sc::ProcessFormula(maCells, aFunc);
3025 7168 : RegroupFormulaCells();
3026 7168 : }
3027 :
3028 : namespace {
3029 :
3030 : class UpdateSubTotalHandler
3031 : {
3032 : ScFunctionData& mrData;
3033 :
3034 117 : void update(double fVal, bool bVal)
3035 : {
3036 117 : if (mrData.bError)
3037 0 : return;
3038 :
3039 117 : switch (mrData.eFunc)
3040 : {
3041 : case SUBTOTAL_FUNC_SUM:
3042 : case SUBTOTAL_FUNC_AVE:
3043 : {
3044 30 : if (!bVal)
3045 4 : return;
3046 :
3047 26 : ++mrData.nCount;
3048 26 : if (!SubTotal::SafePlus(mrData.nVal, fVal))
3049 0 : mrData.bError = true;
3050 : }
3051 26 : break;
3052 : case SUBTOTAL_FUNC_CNT: // only the value
3053 : {
3054 13 : if (!bVal)
3055 2 : return;
3056 :
3057 11 : ++mrData.nCount;
3058 : }
3059 11 : break;
3060 : case SUBTOTAL_FUNC_CNT2: // everything
3061 48 : ++mrData.nCount;
3062 48 : break;
3063 : case SUBTOTAL_FUNC_MAX:
3064 : {
3065 13 : if (!bVal)
3066 2 : return;
3067 :
3068 11 : if (++mrData.nCount == 1 || fVal > mrData.nVal)
3069 11 : mrData.nVal = fVal;
3070 : }
3071 11 : break;
3072 : case SUBTOTAL_FUNC_MIN:
3073 : {
3074 13 : if (!bVal)
3075 2 : return;
3076 :
3077 11 : if (++mrData.nCount == 1 || fVal < mrData.nVal)
3078 3 : mrData.nVal = fVal;
3079 : }
3080 11 : break;
3081 : default:
3082 : {
3083 : // added to avoid warnings
3084 : }
3085 : }
3086 : }
3087 :
3088 : public:
3089 207872 : UpdateSubTotalHandler(ScFunctionData& rData) : mrData(rData) {}
3090 :
3091 63 : void operator() (size_t /*nRow*/, double fVal)
3092 : {
3093 63 : update(fVal, true);
3094 63 : }
3095 :
3096 27 : void operator() (size_t /*nRow*/, const svl::SharedString&)
3097 : {
3098 27 : update(0.0, false);
3099 27 : }
3100 :
3101 2 : void operator() (size_t /*nRow*/, const EditTextObject*)
3102 : {
3103 2 : update(0.0, false);
3104 2 : }
3105 :
3106 25 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
3107 : {
3108 25 : double fVal = 0.0;
3109 25 : bool bVal = false;
3110 25 : if (mrData.eFunc != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
3111 : {
3112 :
3113 20 : if (pCell->GetErrCode())
3114 : {
3115 0 : if (mrData.eFunc != SUBTOTAL_FUNC_CNT) // simply remove from count
3116 0 : mrData.bError = true;
3117 : }
3118 20 : else if (pCell->IsValue())
3119 : {
3120 10 : fVal = pCell->GetValue();
3121 10 : bVal = true;
3122 : }
3123 : // otherwise text
3124 : }
3125 :
3126 25 : update(fVal, bVal);
3127 25 : }
3128 : };
3129 :
3130 : }
3131 :
3132 : // multiple selections:
3133 217088 : void ScColumn::UpdateSelectionFunction(
3134 : const ScRangeList& rRanges, ScFunctionData& rData, ScFlatBoolRowSegments& rHiddenRows )
3135 : {
3136 217088 : sc::SingleColumnSpanSet aSpanSet;
3137 217088 : aSpanSet.scan(rRanges, nTab, nCol); // mark all selected rows.
3138 :
3139 : // Exclude all hidden rows.
3140 : ScFlatBoolRowSegments::RangeData aRange;
3141 217088 : SCROW nRow = 0;
3142 726016 : while (nRow <= MAXROW)
3143 : {
3144 291840 : if (!rHiddenRows.getRangeData(nRow, aRange))
3145 0 : break;
3146 :
3147 291840 : if (aRange.mbValue)
3148 : // Hidden range detected.
3149 38912 : aSpanSet.set(nRow, aRange.mnRow2, false);
3150 :
3151 291840 : nRow = aRange.mnRow2 + 1;
3152 : }
3153 :
3154 434176 : sc::SingleColumnSpanSet::SpansType aSpans;
3155 217088 : aSpanSet.getSpans(aSpans);
3156 :
3157 217088 : sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
3158 :
3159 217088 : switch (rData.eFunc)
3160 : {
3161 : case SUBTOTAL_FUNC_SELECTION_COUNT:
3162 : {
3163 : // Simply count selected rows regardless of cell contents.
3164 9231 : for (; it != itEnd; ++it)
3165 15 : rData.nCount += it->mnRow2 - it->mnRow1 + 1;
3166 : }
3167 9216 : break;
3168 : case SUBTOTAL_FUNC_CNT2:
3169 : {
3170 : // We need to parse all non-empty cells.
3171 6144 : sc::CellStoreType::const_iterator itCellPos = maCells.begin();
3172 6144 : UpdateSubTotalHandler aFunc(rData);
3173 6166 : for (; it != itEnd; ++it)
3174 : {
3175 66 : itCellPos = sc::ParseAllNonEmpty(
3176 66 : itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
3177 : }
3178 : }
3179 6144 : break;
3180 : default:
3181 : {
3182 : // We need to parse only numeric values.
3183 201728 : sc::CellStoreType::const_iterator itCellPos = maCells.begin();
3184 201728 : UpdateSubTotalHandler aFunc(rData);
3185 201964 : for (; it != itEnd; ++it)
3186 : {
3187 708 : itCellPos = sc::ParseFormulaNumeric(
3188 708 : itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
3189 : }
3190 : }
3191 217088 : }
3192 217088 : }
3193 :
3194 : namespace {
3195 :
3196 : class WeightedCounter
3197 : {
3198 : size_t mnCount;
3199 : public:
3200 4478 : WeightedCounter() : mnCount(0) {}
3201 :
3202 20095 : void operator() (const sc::CellStoreType::value_type& node)
3203 : {
3204 20095 : switch (node.type)
3205 : {
3206 : case sc::element_type_numeric:
3207 : case sc::element_type_string:
3208 8685 : mnCount += node.size;
3209 8685 : break;
3210 : case sc::element_type_formula:
3211 : {
3212 : // Each formula cell is worth its code length plus 5.
3213 778 : sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
3214 778 : sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
3215 3270 : for (; it != itEnd; ++it)
3216 : {
3217 2492 : const ScFormulaCell* p = *it;
3218 2492 : mnCount += 5 + p->GetCode()->GetCodeLen();
3219 : }
3220 : }
3221 778 : break;
3222 : case sc::element_type_edittext:
3223 : // each edit-text cell is worth 50.
3224 183 : mnCount += node.size * 50;
3225 183 : break;
3226 : default:
3227 : ;
3228 : }
3229 20095 : }
3230 :
3231 4478 : size_t getCount() const { return mnCount; }
3232 : };
3233 :
3234 : }
3235 :
3236 4478 : sal_uInt32 ScColumn::GetWeightedCount() const
3237 : {
3238 4478 : WeightedCounter aFunc;
3239 4478 : std::for_each(maCells.begin(), maCells.end(), aFunc);
3240 4478 : return aFunc.getCount();
3241 : }
3242 :
3243 : namespace {
3244 :
3245 : class CodeCounter
3246 : {
3247 : size_t mnCount;
3248 : public:
3249 0 : CodeCounter() : mnCount(0) {}
3250 :
3251 0 : void operator() (size_t, const ScFormulaCell* p)
3252 : {
3253 0 : mnCount += p->GetCode()->GetCodeLen();
3254 0 : }
3255 :
3256 0 : size_t getCount() const { return mnCount; }
3257 : };
3258 :
3259 : }
3260 :
3261 0 : sal_uInt32 ScColumn::GetCodeCount() const
3262 : {
3263 0 : CodeCounter aFunc;
3264 0 : sc::ParseFormula(maCells, aFunc);
3265 0 : return aFunc.getCount();
3266 : }
3267 :
3268 0 : SCSIZE ScColumn::GetPatternCount() const
3269 : {
3270 0 : return pAttrArray ? pAttrArray->Count() : 0;
3271 : }
3272 :
3273 113 : SCSIZE ScColumn::GetPatternCount( SCROW nRow1, SCROW nRow2 ) const
3274 : {
3275 113 : return pAttrArray ? pAttrArray->Count( nRow1, nRow2 ) : 0;
3276 : }
3277 :
3278 0 : bool ScColumn::ReservePatternCount( SCSIZE nReserve )
3279 : {
3280 0 : return pAttrArray && pAttrArray->Reserve( nReserve );
3281 156 : }
3282 :
3283 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|