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