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