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