fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / column2.cxx
blob8929ecd9f46e52a4534866846bab49ee2ac29130
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "column.hxx"
21 #include "scitems.hxx"
22 #include "formulacell.hxx"
23 #include "document.hxx"
24 #include "docpool.hxx"
25 #include "drwlayer.hxx"
26 #include "attarray.hxx"
27 #include "patattr.hxx"
28 #include "cellform.hxx"
29 #include "stlsheet.hxx"
30 #include "rechead.hxx"
31 #include "brdcst.hxx"
32 #include "editutil.hxx"
33 #include "subtotal.hxx"
34 #include "markdata.hxx"
35 #include "compiler.hxx"
36 #include "dbdata.hxx"
37 #include "fillinfo.hxx"
38 #include "segmenttree.hxx"
39 #include "docparam.hxx"
40 #include "cellvalue.hxx"
41 #include "tokenarray.hxx"
42 #include "globalnames.hxx"
43 #include "formulagroup.hxx"
44 #include "listenercontext.hxx"
45 #include "mtvcellfunc.hxx"
46 #include "progress.hxx"
47 #include "scmatrix.hxx"
48 #include <rowheightcontext.hxx>
50 #include <math.h>
52 #include <editeng/eeitem.hxx>
54 #include <svx/algitem.hxx>
55 #include <editeng/editobj.hxx>
56 #include <editeng/editstat.hxx>
57 #include <editeng/emphasismarkitem.hxx>
58 #include <editeng/fhgtitem.hxx>
59 #include <editeng/forbiddencharacterstable.hxx>
60 #include <svx/rotmodit.hxx>
61 #include <editeng/scripttypeitem.hxx>
62 #include <editeng/unolingu.hxx>
63 #include <editeng/justifyitem.hxx>
64 #include <svl/zforlist.hxx>
65 #include <svl/broadcast.hxx>
66 #include <vcl/outdev.hxx>
67 #include <formula/errorcodes.hxx>
68 #include <formula/vectortoken.hxx>
70 #include <boost/scoped_ptr.hpp>
71 #include <algorithm>
73 // factor from font size to optimal cell height (text width)
74 #define SC_ROT_BREAK_FACTOR 6
76 inline bool IsAmbiguousScript( SvtScriptType nScript )
78 //TODO: move to a header file
79 return ( nScript != SvtScriptType::LATIN &&
80 nScript != SvtScriptType::ASIAN &&
81 nScript != SvtScriptType::COMPLEX );
84 // Data operations
86 long ScColumn::GetNeededSize(
87 SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY,
88 const Fraction& rZoomX, const Fraction& rZoomY,
89 bool bWidth, const ScNeededSizeOptions& rOptions,
90 const ScPatternAttr** ppPatternChange ) const
92 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
93 sc::CellStoreType::const_iterator it = aPos.first;
94 if (it == maCells.end() || it->type == sc::element_type_empty)
95 // Empty cell, or invalid row.
96 return 0;
98 long nValue = 0;
99 ScRefCellValue aCell = GetCellValue(it, aPos.second);
100 double nPPT = bWidth ? nPPTX : nPPTY;
102 const ScPatternAttr* pPattern = rOptions.pPattern;
103 if (!pPattern)
104 pPattern = pAttrArray->GetPattern( nRow );
106 // merged?
107 // Do not merge in conditional formatting
109 const ScMergeAttr* pMerge = static_cast<const ScMergeAttr*>(&pPattern->GetItem(ATTR_MERGE));
110 const ScMergeFlagAttr* pFlag = static_cast<const ScMergeFlagAttr*>(&pPattern->GetItem(ATTR_MERGE_FLAG));
112 if ( bWidth )
114 if ( pFlag->IsHorOverlapped() )
115 return 0;
116 if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
117 return 0;
119 else
121 if ( pFlag->IsVerOverlapped() )
122 return 0;
123 if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
124 return 0;
127 // conditional formatting
128 const SfxItemSet* pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
130 // line break?
132 const SfxPoolItem* pCondItem;
133 SvxCellHorJustify eHorJust;
134 if (pCondSet &&
135 pCondSet->GetItemState(ATTR_HOR_JUSTIFY, true, &pCondItem) == SfxItemState::SET)
136 eHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem*>(pCondItem)->GetValue();
137 else
138 eHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(
139 pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
140 bool bBreak;
141 if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
142 bBreak = true;
143 else if ( pCondSet &&
144 pCondSet->GetItemState(ATTR_LINEBREAK, true, &pCondItem) == SfxItemState::SET)
145 bBreak = static_cast<const SfxBoolItem*>(pCondItem)->GetValue();
146 else
147 bBreak = static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
149 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
150 sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
151 // #i111387# disable automatic line breaks only for "General" number format
152 if (bBreak && ( nFormat % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
154 // If a formula cell needs to be interpreted during aCell.hasNumeric()
155 // to determine the type, the pattern may get invalidated because the
156 // result may set a number format. In which case there's also the
157 // General format not set anymore..
158 bool bMayInvalidatePattern = (aCell.meType == CELLTYPE_FORMULA);
159 const ScPatternAttr* pOldPattern = pPattern;
160 bool bNumeric = aCell.hasNumeric();
161 if (bMayInvalidatePattern)
163 pPattern = pAttrArray->GetPattern( nRow );
164 if (ppPatternChange)
165 *ppPatternChange = pPattern; // XXX caller may have to check for change!
167 if (bNumeric)
169 if (!bMayInvalidatePattern || pPattern == pOldPattern)
170 bBreak = false;
171 else
173 nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
174 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
175 bBreak = false;
180 // get other attributes from pattern and conditional formatting
182 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
183 bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
184 static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
185 if ( bAsianVertical )
186 bBreak = false;
188 if ( bWidth && bBreak ) // after determining bAsianVertical (bBreak may be reset)
189 return 0;
191 long nRotate = 0;
192 SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
193 if ( eOrient == SVX_ORIENTATION_STANDARD )
195 if (pCondSet &&
196 pCondSet->GetItemState(ATTR_ROTATE_VALUE, true, &pCondItem) == SfxItemState::SET)
197 nRotate = static_cast<const SfxInt32Item*>(pCondItem)->GetValue();
198 else
199 nRotate =static_cast<const SfxInt32Item&>(pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
200 if ( nRotate )
202 if (pCondSet &&
203 pCondSet->GetItemState(ATTR_ROTATE_MODE, true, &pCondItem) == SfxItemState::SET)
204 eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem*>(pCondItem)->GetValue();
205 else
206 eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
207 pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
209 if ( nRotate == 18000 )
210 eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
214 if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
216 // ignore orientation/rotation if "repeat" is active
217 eOrient = SVX_ORIENTATION_STANDARD;
218 nRotate = 0;
219 bAsianVertical = false;
222 const SvxMarginItem* pMargin;
223 if (pCondSet &&
224 pCondSet->GetItemState(ATTR_MARGIN, true, &pCondItem) == SfxItemState::SET)
225 pMargin = static_cast<const SvxMarginItem*>(pCondItem);
226 else
227 pMargin = static_cast<const SvxMarginItem*>(&pPattern->GetItem(ATTR_MARGIN));
228 sal_uInt16 nIndent = 0;
229 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
231 if (pCondSet &&
232 pCondSet->GetItemState(ATTR_INDENT, true, &pCondItem) == SfxItemState::SET)
233 nIndent = static_cast<const SfxUInt16Item*>(pCondItem)->GetValue();
234 else
235 nIndent = static_cast<const SfxUInt16Item&>(pPattern->GetItem(ATTR_INDENT)).GetValue();
238 SvtScriptType nScript = pDocument->GetScriptType(nCol, nRow, nTab);
239 if (nScript == SvtScriptType::NONE) nScript = ScGlobal::GetDefaultScriptType();
241 // also call SetFont for edit cells, because bGetFont may be set only once
242 // bGetFont is set also if script type changes
243 if (rOptions.bGetFont)
245 Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
246 vcl::Font aFont;
247 // font color doesn't matter here
248 pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
249 pDev->SetFont(aFont);
252 bool bAddMargin = true;
253 CellType eCellType = aCell.meType;
255 bool bEditEngine = (eCellType == CELLTYPE_EDIT ||
256 eOrient == SVX_ORIENTATION_STACKED ||
257 IsAmbiguousScript(nScript) ||
258 ((eCellType == CELLTYPE_FORMULA) && aCell.mpFormula->IsMultilineResult()));
260 if (!bEditEngine) // direct output
262 Color* pColor;
263 OUString aValStr;
264 ScCellFormat::GetString(
265 aCell, nFormat, aValStr, &pColor, *pFormatter, pDocument, true, rOptions.bFormula, ftCheck);
267 if (!aValStr.isEmpty())
269 // SetFont is moved up
271 Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
272 if ( eOrient != SVX_ORIENTATION_STANDARD )
274 long nTemp = aSize.Width();
275 aSize.Width() = aSize.Height();
276 aSize.Height() = nTemp;
278 else if ( nRotate )
280 //TODO: take different X/Y scaling into consideration
282 double nRealOrient = nRotate * F_PI18000; // nRotate is in 1/100 Grad
283 double nCosAbs = fabs( cos( nRealOrient ) );
284 double nSinAbs = fabs( sin( nRealOrient ) );
285 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
286 long nWidth;
287 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
288 nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
289 else if ( rOptions.bTotalSize )
291 nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
292 bAddMargin = false;
293 // only to the right:
294 //TODO: differ on direction up/down (only Text/whole height)
295 if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
296 nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
297 nPPT * nCosAbs / nSinAbs );
299 else
300 nWidth = (long)( aSize.Height() / nSinAbs ); //TODO: limit?
302 if ( bBreak && !rOptions.bTotalSize )
304 // limit size for line break
305 long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
306 if ( nHeight > nCmp )
307 nHeight = nCmp;
310 aSize = Size( nWidth, nHeight );
312 nValue = bWidth ? aSize.Width() : aSize.Height();
314 if ( bAddMargin )
316 if (bWidth)
318 nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
319 (long) ( pMargin->GetRightMargin() * nPPT );
320 if ( nIndent )
321 nValue += (long) ( nIndent * nPPT );
323 else
324 nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
325 (long) ( pMargin->GetBottomMargin() * nPPT );
328 // linebreak done ?
330 if ( bBreak && !bWidth )
332 // test with EditEngine the safety at 90%
333 // (due to rounding errors and because EditEngine formats partially differently)
335 long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
336 pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
337 nIndent )
338 * nPPT );
339 nDocPixel = (nDocPixel * 9) / 10; // for safety
340 if ( aSize.Width() > nDocPixel )
341 bEditEngine = true;
346 if (bEditEngine)
348 // the font is not reset each time with !bEditEngine
349 vcl::Font aOldFont = pDev->GetFont();
351 MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
353 // save in document ?
354 ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
356 pEngine->SetUpdateMode( false );
357 bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
358 EEControlBits nCtrl = pEngine->GetControlWord();
359 if ( bTextWysiwyg )
360 nCtrl |= EEControlBits::FORMAT100;
361 else
362 nCtrl &= ~EEControlBits::FORMAT100;
363 pEngine->SetControlWord( nCtrl );
364 MapMode aOld = pDev->GetMapMode();
365 pDev->SetMapMode( aHMMMode );
366 pEngine->SetRefDevice( pDev );
367 pDocument->ApplyAsianEditSettings( *pEngine );
368 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
369 if ( ScStyleSheet* pPreviewStyle = pDocument->GetPreviewCellStyle( nCol, nRow, nTab ) )
371 boost::scoped_ptr<ScPatternAttr> pPreviewPattern(new ScPatternAttr( *pPattern ));
372 pPreviewPattern->SetStyleSheet(pPreviewStyle);
373 pPreviewPattern->FillEditItemSet( pSet, pCondSet );
375 else
377 SfxItemSet* pFontSet = pDocument->GetPreviewFont( nCol, nRow, nTab );
378 pPattern->FillEditItemSet( pSet, pFontSet ? pFontSet : pCondSet );
380 // no longer needed, are setted with the text (is faster)
381 // pEngine->SetDefaults( pSet );
383 if ( static_cast<const SfxBoolItem&>(pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
385 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
386 pEngine->SetHyphenator( xXHyphenator );
389 Size aPaper = Size( 1000000, 1000000 );
390 if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
391 aPaper.Width() = 1;
392 else if (bBreak)
394 double fWidthFactor = nPPTX;
395 if ( bTextWysiwyg )
397 // if text is formatted for printer, don't use PixelToLogic,
398 // to ensure the exact same paper width (and same line breaks) as in
399 // ScEditUtil::GetEditArea, used for output.
401 fWidthFactor = HMM_PER_TWIPS;
404 // use original width for hidden columns:
405 long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
406 SCCOL nColMerge = pMerge->GetColMerge();
407 if (nColMerge > 1)
408 for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
409 nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
410 nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
411 + (long) ( pMargin->GetRightMargin() * fWidthFactor )
412 + 1; // output size is width-1 pixel (due to gridline)
413 if ( nIndent )
414 nDocWidth -= (long) ( nIndent * fWidthFactor );
416 // space for AutoFilter button: 20 * nZoom/100
417 if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
418 nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
420 aPaper.Width() = nDocWidth;
422 if ( !bTextWysiwyg )
423 aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
425 pEngine->SetPaperSize(aPaper);
427 if (aCell.meType == CELLTYPE_EDIT)
429 pEngine->SetTextNewDefaults(*aCell.mpEditText, pSet);
431 else
433 Color* pColor;
434 OUString aString;
435 ScCellFormat::GetString(
436 aCell, nFormat, aString, &pColor, *pFormatter, pDocument, true,
437 rOptions.bFormula, ftCheck);
439 if (!aString.isEmpty())
440 pEngine->SetTextNewDefaults(aString, pSet);
441 else
442 pEngine->SetDefaults(pSet);
445 bool bEngineVertical = pEngine->IsVertical();
446 pEngine->SetVertical( bAsianVertical );
447 pEngine->SetUpdateMode( true );
449 bool bEdWidth = bWidth;
450 if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
451 bEdWidth = !bEdWidth;
452 if ( nRotate )
454 //TODO: take different X/Y scaling into consideration
456 Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
457 double nRealOrient = nRotate * F_PI18000; // nRotate is in 1/100 Grad
458 double nCosAbs = fabs( cos( nRealOrient ) );
459 double nSinAbs = fabs( sin( nRealOrient ) );
460 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
461 long nWidth;
462 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
463 nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
464 else if ( rOptions.bTotalSize )
466 nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
467 bAddMargin = false;
468 if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
469 nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
470 nPPT * nCosAbs / nSinAbs );
472 else
473 nWidth = (long)( aSize.Height() / nSinAbs ); //TODO: limit?
474 aSize = Size( nWidth, nHeight );
476 Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
477 if ( bEdWidth )
478 nValue = aPixSize.Width();
479 else
481 nValue = aPixSize.Height();
483 if ( bBreak && !rOptions.bTotalSize )
485 // limit size for line break
486 long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
487 if ( nValue > nCmp )
488 nValue = nCmp;
492 else if ( bEdWidth )
494 if (bBreak)
495 nValue = 0;
496 else
497 nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
498 aHMMMode).Width();
500 else // height
502 nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
503 aHMMMode).Height();
505 // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
506 if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
507 ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
509 pEngine->SetControlWord( nCtrl | EEControlBits::FORMAT100 );
510 pEngine->QuickFormatDoc( true );
511 long nSecondValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ), aHMMMode).Height();
512 if ( nSecondValue > nValue )
513 nValue = nSecondValue;
517 if ( nValue && bAddMargin )
519 if (bWidth)
521 nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
522 (long) ( pMargin->GetRightMargin() * nPPT );
523 if (nIndent)
524 nValue += (long) ( nIndent * nPPT );
526 else
528 nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
529 (long) ( pMargin->GetBottomMargin() * nPPT );
531 if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
533 // add 1pt extra (default margin value) for line breaks with SetVertical
534 nValue += (long) ( 20 * nPPT );
539 // EditEngine is cached and re-used, so the old vertical flag must be restored
540 pEngine->SetVertical( bEngineVertical );
542 pDocument->DisposeFieldEditEngine(pEngine);
544 pDev->SetMapMode( aOld );
545 pDev->SetFont( aOldFont );
548 if (bWidth)
550 // place for Autofilter Button
551 // 20 * nZoom/100
552 // Conditional formatting is not interesting here
554 sal_Int16 nFlags = static_cast<const ScMergeFlagAttr&>(pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
555 if (nFlags & SC_MF_AUTO)
556 nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
558 return nValue;
561 namespace {
563 class MaxStrLenFinder
565 ScDocument& mrDoc;
566 sal_uInt32 mnFormat;
567 OUString maMaxLenStr;
568 sal_Int32 mnMaxLen;
570 void checkLength(ScRefCellValue& rCell)
572 Color* pColor;
573 OUString aValStr;
574 ScCellFormat::GetString(
575 rCell, mnFormat, aValStr, &pColor, *mrDoc.GetFormatTable(), &mrDoc, true, false, ftCheck);
577 if (aValStr.getLength() > mnMaxLen)
579 mnMaxLen = aValStr.getLength();
580 maMaxLenStr = aValStr;
584 public:
585 MaxStrLenFinder(ScDocument& rDoc, sal_uInt32 nFormat) :
586 mrDoc(rDoc), mnFormat(nFormat), mnMaxLen(0) {}
588 void operator() (size_t /*nRow*/, double f)
590 ScRefCellValue aCell(f);
591 checkLength(aCell);
594 void operator() (size_t /*nRow*/, const svl::SharedString& rSS)
596 if (rSS.getLength() > mnMaxLen)
598 mnMaxLen = rSS.getLength();
599 maMaxLenStr = rSS.getString();
603 void operator() (size_t /*nRow*/, const EditTextObject* p)
605 ScRefCellValue aCell(p);
606 checkLength(aCell);
609 void operator() (size_t /*nRow*/, const ScFormulaCell* p)
611 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
612 checkLength(aCell);
615 const OUString& getMaxLenStr() const { return maMaxLenStr; }
620 sal_uInt16 ScColumn::GetOptimalColWidth(
621 OutputDevice* pDev, double nPPTX, double nPPTY, const Fraction& rZoomX, const Fraction& rZoomY,
622 bool bFormula, sal_uInt16 nOldWidth, const ScMarkData* pMarkData, const ScColWidthParam* pParam) const
624 if (maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty)
625 // All cells are empty.
626 return nOldWidth;
628 sc::SingleColumnSpanSet aSpanSet;
629 sc::SingleColumnSpanSet::SpansType aMarkedSpans;
630 if (pMarkData && (pMarkData->IsMarked() || pMarkData->IsMultiMarked()))
632 aSpanSet.scan(*pMarkData, nTab, nCol);
633 aSpanSet.getSpans(aMarkedSpans);
635 else
636 // "Select" the entire column if no selection exists.
637 aMarkedSpans.push_back(sc::RowSpan(0, MAXROW));
639 sal_uInt16 nWidth = static_cast<sal_uInt16>(nOldWidth*nPPTX);
640 bool bFound = false;
642 if ( pParam && pParam->mbSimpleText )
643 { // all the same except for number format
644 const ScPatternAttr* pPattern = GetPattern( 0 );
645 vcl::Font aFont;
646 // font color doesn't matter here
647 pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX, NULL );
648 pDev->SetFont( aFont );
649 const SvxMarginItem* pMargin = static_cast<const SvxMarginItem*>(&pPattern->GetItem(ATTR_MARGIN));
650 long nMargin = (long) ( pMargin->GetLeftMargin() * nPPTX ) +
651 (long) ( pMargin->GetRightMargin() * nPPTX );
653 // Try to find the row that has the longest string, and measure the width of that string.
654 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
655 sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
656 OUString aLongStr;
657 Color* pColor;
658 if (pParam->mnMaxTextRow >= 0)
660 ScRefCellValue aCell = GetCellValue(pParam->mnMaxTextRow);
661 ScCellFormat::GetString(
662 aCell, nFormat, aLongStr, &pColor, *pFormatter, pDocument, true, false, ftCheck);
664 else
666 // Go though all non-empty cells within selection.
667 MaxStrLenFinder aFunc(*pDocument, nFormat);
668 sc::CellStoreType::const_iterator itPos = maCells.begin();
669 sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
670 for (; it != itEnd; ++it)
671 itPos = sc::ParseAllNonEmpty(itPos, maCells, it->mnRow1, it->mnRow2, aFunc);
673 aLongStr = aFunc.getMaxLenStr();
676 if (!aLongStr.isEmpty())
678 nWidth = pDev->GetTextWidth(aLongStr) + static_cast<sal_uInt16>(nMargin);
679 bFound = true;
682 else
684 ScNeededSizeOptions aOptions;
685 aOptions.bFormula = bFormula;
686 const ScPatternAttr* pOldPattern = NULL;
687 SvtScriptType nOldScript = SvtScriptType::NONE;
689 // Go though all non-empty cells within selection.
690 sc::CellStoreType::const_iterator itPos = maCells.begin();
691 sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
692 for (; it != itEnd; ++it)
694 SCROW nRow1 = it->mnRow1, nRow2 = it->mnRow2;
695 SCROW nRow = nRow1;
696 while (nRow <= nRow2)
698 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
699 itPos = aPos.first;
700 if (itPos->type == sc::element_type_empty)
702 // Skip empty cells.
703 nRow += itPos->size - aPos.second;
704 continue;
707 for (size_t nOffset = aPos.second; nOffset < itPos->size; ++nOffset, ++nRow)
709 SvtScriptType nScript = pDocument->GetScriptType(nCol, nRow, nTab);
710 if (nScript == SvtScriptType::NONE)
711 nScript = ScGlobal::GetDefaultScriptType();
713 const ScPatternAttr* pPattern = GetPattern(nRow);
714 aOptions.pPattern = pPattern;
715 aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
716 pOldPattern = pPattern;
717 sal_uInt16 nThis = (sal_uInt16) GetNeededSize(
718 nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, true, aOptions, &pOldPattern);
719 if (nThis)
721 if (nThis > nWidth || !bFound)
723 nWidth = nThis;
724 bFound = true;
732 if (bFound)
734 nWidth += 2;
735 sal_uInt16 nTwips = (sal_uInt16) (nWidth / nPPTX);
736 return nTwips;
738 else
739 return nOldWidth;
742 static sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId )
744 const SvxFontHeightItem& rFontHeight =
745 static_cast<const SvxFontHeightItem&>(rPattern.GetItem(nFontHeightId));
747 sal_uInt16 nHeight = rFontHeight.GetHeight();
748 nHeight *= 1.18;
750 if ( static_cast<const SvxEmphasisMarkItem&>(rPattern.
751 GetItem(ATTR_FONT_EMPHASISMARK)).GetEmphasisMark() != EMPHASISMARK_NONE )
753 // add height for emphasis marks
754 //TODO: font metrics should be used instead
755 nHeight += nHeight / 4;
758 const SvxMarginItem& rMargin =
759 static_cast<const SvxMarginItem&>(rPattern.GetItem(ATTR_MARGIN));
761 nHeight += rMargin.GetTopMargin() + rMargin.GetBottomMargin();
763 if (nHeight > STD_ROWHEIGHT_DIFF)
764 nHeight -= STD_ROWHEIGHT_DIFF;
766 if (nHeight < ScGlobal::nStdRowHeight)
767 nHeight = ScGlobal::nStdRowHeight;
769 return nHeight;
772 // pHeight in Twips
773 // optimize nMinHeight, nMinStart : with nRow >= nMinStart is at least nMinHeight
774 // (is only evaluated with bStdAllowed)
776 void ScColumn::GetOptimalHeight(
777 sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, sal_uInt16 nMinHeight, SCROW nMinStart )
779 std::vector<sal_uInt16>& rHeights = rCxt.getHeightArray();
780 ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
782 SCROW nStart = -1;
783 SCROW nEnd = -1;
784 SCROW nEditPos = 0;
785 SCROW nNextEnd = 0;
787 // with conditional formatting, always consider the individual cells
789 const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
790 while ( pPattern )
792 const ScMergeAttr* pMerge = static_cast<const ScMergeAttr*>(&pPattern->GetItem(ATTR_MERGE));
793 const ScMergeFlagAttr* pFlag = static_cast<const ScMergeFlagAttr*>(&pPattern->GetItem(ATTR_MERGE_FLAG));
794 if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
796 // do nothing - vertically with merged and overlapping,
797 // horizontally only with overlapped (invisible) -
798 // only one horizontal merged is always considered
800 else
802 bool bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
803 bool bStdOnly = false;
804 if (bStdAllowed)
806 bool bBreak = static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
807 ((SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
808 GetItem( ATTR_HOR_JUSTIFY )).GetValue() ==
809 SVX_HOR_JUSTIFY_BLOCK);
810 bStdOnly = !bBreak;
812 // conditional formatting: loop all cells
813 if (bStdOnly &&
814 !static_cast<const ScCondFormatItem&>(pPattern->GetItem(
815 ATTR_CONDITIONAL)).GetCondFormatData().empty())
817 bStdOnly = false;
820 // rotated text: loop all cells
821 if ( bStdOnly && static_cast<const SfxInt32Item&>(pPattern->
822 GetItem(ATTR_ROTATE_VALUE)).GetValue() )
823 bStdOnly = false;
826 if (bStdOnly)
828 bool bHasEditCells = HasEditCells(nStart,nEnd,nEditPos);
829 // Call to HasEditCells() may change pattern due to
830 // calculation, => sync always.
831 // We don't know which row changed first, but as pPattern
832 // covered nStart to nEnd we can pick nStart. Worst case we
833 // have to repeat that for every row in range if every row
834 // changed.
835 pPattern = aIter.Resync( nStart, nStart, nEnd);
836 if (bHasEditCells && nEnd < nEditPos)
837 bHasEditCells = false; // run into that again
838 if (bHasEditCells) // includes mixed script types
840 if (nEditPos == nStart)
842 bStdOnly = false;
843 if (nEnd > nEditPos)
844 nNextEnd = nEnd;
845 nEnd = nEditPos; // calculate single
846 bStdAllowed = false; // will be computed in any case per cell
848 else
850 nNextEnd = nEnd;
851 nEnd = nEditPos - 1; // standard - part
856 sc::SingleColumnSpanSet aSpanSet;
857 aSpanSet.scan(*this, nStart, nEnd);
858 sc::SingleColumnSpanSet::SpansType aSpans;
859 aSpanSet.getSpans(aSpans);
861 if (bStdAllowed)
863 sal_uInt16 nLatHeight = 0;
864 sal_uInt16 nCjkHeight = 0;
865 sal_uInt16 nCtlHeight = 0;
866 sal_uInt16 nDefHeight;
867 SvtScriptType nDefScript = ScGlobal::GetDefaultScriptType();
868 if ( nDefScript == SvtScriptType::ASIAN )
869 nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
870 else if ( nDefScript == SvtScriptType::COMPLEX )
871 nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
872 else
873 nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
875 // if everything below is already larger, the loop doesn't have to
876 // be run again
877 SCROW nStdEnd = nEnd;
878 if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
879 nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
881 for (SCROW nRow = nStart; nRow <= nStdEnd; ++nRow)
882 if (nDefHeight > rHeights[nRow-nStartRow])
883 rHeights[nRow-nStartRow] = nDefHeight;
885 if ( bStdOnly )
887 // if cells are not handled individually below,
888 // check for cells with different script type
889 sc::CellTextAttrStoreType::iterator itAttr = maCellTextAttrs.begin();
890 sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
891 sc::CellStoreType::iterator itCells = maCells.begin();
892 for (; it != itEnd; ++it)
894 for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
896 SvtScriptType nScript = GetRangeScriptType(itAttr, nRow, nRow, itCells);
897 if (nScript == nDefScript)
898 continue;
900 if ( nScript == SvtScriptType::ASIAN )
902 if ( nCjkHeight == 0 )
903 nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
904 if (nCjkHeight > rHeights[nRow-nStartRow])
905 rHeights[nRow-nStartRow] = nCjkHeight;
907 else if ( nScript == SvtScriptType::COMPLEX )
909 if ( nCtlHeight == 0 )
910 nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
911 if (nCtlHeight > rHeights[nRow-nStartRow])
912 rHeights[nRow-nStartRow] = nCtlHeight;
914 else
916 if ( nLatHeight == 0 )
917 nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
918 if (nLatHeight > rHeights[nRow-nStartRow])
919 rHeights[nRow-nStartRow] = nLatHeight;
926 if (!bStdOnly) // search covered cells
928 ScNeededSizeOptions aOptions;
930 sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
931 for (; it != itEnd; ++it)
933 for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
935 // only calculate the cell height when it's used later (#37928#)
937 if (rCxt.isForceAutoSize() || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
939 aOptions.pPattern = pPattern;
940 const ScPatternAttr* pOldPattern = pPattern;
941 sal_uInt16 nHeight = (sal_uInt16)
942 ( GetNeededSize( nRow, rCxt.getOutputDevice(), rCxt.getPPTX(), rCxt.getPPTY(),
943 rCxt.getZoomX(), rCxt.getZoomY(), false, aOptions,
944 &pPattern) / rCxt.getPPTY() );
945 if (nHeight > rHeights[nRow-nStartRow])
946 rHeights[nRow-nStartRow] = nHeight;
947 // Pattern changed due to calculation? => sync.
948 if (pPattern != pOldPattern)
950 pPattern = aIter.Resync( nRow, nStart, nEnd);
951 nNextEnd = 0;
959 if (nNextEnd > 0)
961 nStart = nEnd + 1;
962 nEnd = nNextEnd;
963 nNextEnd = 0;
965 else
966 pPattern = aIter.Next(nStart,nEnd);
970 bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const
972 bool bStop = false;
973 sc::CellStoreType::const_iterator it = maCells.position(nRow).first;
974 mdds::mtv::element_t eType = it->type;
975 if (!bInSel && it != maCells.end() && eType != sc::element_type_empty)
977 if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
978 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
979 pDocument->IsTabProtected(nTab)) )
980 return true;
982 while (!bStop)
984 if (bInSel)
986 nRow = rData.GetNextMarked(nCol, nRow, false);
987 if (!ValidRow(nRow))
989 nRow = MAXROW+1;
990 bStop = true;
992 else
994 it = maCells.position(it, nRow).first;
995 eType = it->type;
996 if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
997 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
998 pDocument->IsTabProtected(nTab)) )
999 return true;
1000 else
1001 nRow++;
1004 else if (GetNextDataPos(nRow))
1006 it = maCells.position(it, nRow).first;
1007 eType = it->type;
1008 if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
1009 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
1010 pDocument->IsTabProtected(nTab)) )
1011 return true;
1012 else
1013 nRow++;
1015 else
1017 nRow = MAXROW+1;
1018 bStop = true;
1021 return false;
1024 namespace {
1026 class StrEntries
1028 sc::CellStoreType& mrCells;
1030 protected:
1031 struct StrEntry
1033 SCROW mnRow;
1034 OUString maStr;
1036 StrEntry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maStr(rStr) {}
1039 std::vector<StrEntry> maStrEntries;
1040 ScDocument* mpDoc;
1042 StrEntries(sc::CellStoreType& rCells, ScDocument* pDoc) : mrCells(rCells), mpDoc(pDoc) {}
1044 public:
1045 void commitStrings()
1047 svl::SharedStringPool& rPool = mpDoc->GetSharedStringPool();
1048 sc::CellStoreType::iterator it = mrCells.begin();
1049 std::vector<StrEntry>::iterator itStr = maStrEntries.begin(), itStrEnd = maStrEntries.end();
1050 for (; itStr != itStrEnd; ++itStr)
1051 it = mrCells.set(it, itStr->mnRow, rPool.intern(itStr->maStr));
1055 class RemoveEditAttribsHandler : public StrEntries
1057 boost::scoped_ptr<ScFieldEditEngine> mpEngine;
1059 public:
1060 RemoveEditAttribsHandler(sc::CellStoreType& rCells, ScDocument* pDoc) : StrEntries(rCells, pDoc) {}
1062 void operator() (size_t nRow, EditTextObject*& pObj)
1064 // For the test on hard formatting (ScEditAttrTester), are the defaults in the
1065 // EditEngine of no importance. When the tester would later recognise the same
1066 // attributes in default and hard formatting and has to remove them, the correct
1067 // defaults must be set in the EditEngine for each cell.
1069 // test for attributes
1070 if (!mpEngine)
1072 mpEngine.reset(new ScFieldEditEngine(mpDoc, mpDoc->GetEditPool()));
1073 // EEControlBits::ONLINESPELLING if there are errors already
1074 mpEngine->SetControlWord(mpEngine->GetControlWord() | EEControlBits::ONLINESPELLING);
1075 mpDoc->ApplyAsianEditSettings(*mpEngine);
1077 mpEngine->SetText(*pObj);
1078 sal_Int32 nParCount = mpEngine->GetParagraphCount();
1079 for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
1081 mpEngine->RemoveCharAttribs(nPar);
1082 const SfxItemSet& rOld = mpEngine->GetParaAttribs(nPar);
1083 if ( rOld.Count() )
1085 SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // empty
1086 mpEngine->SetParaAttribs( nPar, aNew );
1089 // change URL field to text (not possible otherwise, thus pType=0)
1090 mpEngine->RemoveFields(true);
1092 bool bSpellErrors = mpEngine->HasOnlineSpellErrors();
1093 bool bNeedObject = bSpellErrors || nParCount>1; // keep errors/paragraphs
1094 // ScEditAttrTester is not needed anymore, arrays are gone
1096 if (bNeedObject) // remains edit cell
1098 EEControlBits nCtrl = mpEngine->GetControlWord();
1099 EEControlBits nWantBig = bSpellErrors ? EEControlBits::ALLOWBIGOBJS : EEControlBits::NONE;
1100 if ( ( nCtrl & EEControlBits::ALLOWBIGOBJS ) != nWantBig )
1101 mpEngine->SetControlWord( (nCtrl & ~EEControlBits::ALLOWBIGOBJS) | nWantBig );
1103 // Overwrite the existing object.
1104 delete pObj;
1105 pObj = mpEngine->CreateTextObject();
1107 else // create String
1109 // Store the string replacement for later commits.
1110 OUString aText = ScEditUtil::GetSpaceDelimitedString(*mpEngine);
1111 maStrEntries.push_back(StrEntry(nRow, aText));
1116 class TestTabRefAbsHandler
1118 SCTAB mnTab;
1119 bool mbTestResult;
1120 public:
1121 TestTabRefAbsHandler(SCTAB nTab) : mnTab(nTab), mbTestResult(false) {}
1123 void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
1125 if (const_cast<ScFormulaCell*>(pCell)->TestTabRefAbs(mnTab))
1126 mbTestResult = true;
1129 bool getTestResult() const { return mbTestResult; }
1134 void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
1136 RemoveEditAttribsHandler aFunc(maCells, pDocument);
1137 sc::ProcessEditText(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
1138 aFunc.commitStrings();
1141 bool ScColumn::TestTabRefAbs(SCTAB nTable) const
1143 TestTabRefAbsHandler aFunc(nTable);
1144 sc::ParseFormula(maCells, aFunc);
1145 return aFunc.getTestResult();
1148 bool ScColumn::IsEmptyData() const
1150 return maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty;
1153 namespace {
1155 class CellCounter
1157 size_t mnCount;
1158 public:
1159 CellCounter() : mnCount(0) {}
1161 void operator() (
1162 const sc::CellStoreType::value_type& node, size_t /*nOffset*/, size_t nDataSize)
1164 if (node.type == sc::element_type_empty)
1165 return;
1167 mnCount += nDataSize;
1170 size_t getCount() const { return mnCount; }
1175 SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
1177 CellCounter aFunc;
1178 sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
1179 return aFunc.getCount();
1182 bool ScColumn::HasVisibleDataAt(SCROW nRow) const
1184 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
1185 sc::CellStoreType::const_iterator it = aPos.first;
1186 if (it == maCells.end())
1187 // Likely invalid row number.
1188 return false;
1190 return it->type != sc::element_type_empty;
1193 bool ScColumn::IsEmptyAttr() const
1195 if (pAttrArray)
1196 return pAttrArray->IsEmpty();
1197 else
1198 return true;
1201 bool ScColumn::IsEmpty() const
1203 return (IsEmptyData() && IsEmptyAttr());
1206 bool ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
1208 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1209 sc::CellStoreType::const_iterator it = aPos.first;
1210 if (it == maCells.end())
1211 // Invalid row number.
1212 return false;
1214 if (it->type != sc::element_type_empty)
1215 // Non-empty cell at the start position.
1216 return false;
1218 // start position of next block which is not empty.
1219 SCROW nNextRow = nStartRow + it->size - aPos.second;
1220 return nEndRow < nNextRow;
1223 bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
1225 std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
1226 sc::CellNoteStoreType::const_iterator it = aPos.first;
1227 if (it == maCellNotes.end())
1228 // Invalid row number.
1229 return false;
1231 if (it->type != sc::element_type_empty)
1232 // Non-empty cell at the start position.
1233 return false;
1235 // start position of next block which is not empty.
1236 SCROW nNextRow = nStartRow + it->size - aPos.second;
1237 return nEndRow < nNextRow;
1240 SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
1242 // Given a range of rows, find a top or bottom empty segment. Skip the start row.
1243 switch (eDir)
1245 case DIR_TOP:
1247 // Determine the length of empty head segment.
1248 size_t nLength = nEndRow - nStartRow;
1249 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1250 sc::CellStoreType::const_iterator it = aPos.first;
1251 if (it->type != sc::element_type_empty)
1252 // First row is already not empty.
1253 return 0;
1255 // length of this empty block minus the offset.
1256 size_t nThisLen = it->size - aPos.second;
1257 return std::min(nThisLen, nLength);
1259 break;
1260 case DIR_BOTTOM:
1262 // Determine the length of empty tail segment.
1263 size_t nLength = nEndRow - nStartRow;
1264 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow);
1265 sc::CellStoreType::const_iterator it = aPos.first;
1266 if (it->type != sc::element_type_empty)
1267 // end row is already not empty.
1268 return 0;
1270 // length of this empty block from the tip to the end row position.
1271 size_t nThisLen = aPos.second + 1;
1272 return std::min(nThisLen, nLength);
1274 break;
1275 default:
1279 return 0;
1282 SCROW ScColumn::GetFirstDataPos() const
1284 if (IsEmptyData())
1285 return 0;
1287 sc::CellStoreType::const_iterator it = maCells.begin();
1288 if (it->type != sc::element_type_empty)
1289 return 0;
1291 return it->size;
1294 SCROW ScColumn::GetLastDataPos() const
1296 if (IsEmptyData())
1297 return 0;
1299 sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
1300 if (it->type != sc::element_type_empty)
1301 return MAXROW;
1303 return MAXROW - static_cast<SCROW>(it->size);
1306 SCROW ScColumn::GetLastDataPos( SCROW nLastRow ) const
1308 sc::CellStoreType::const_position_type aPos = maCells.position(nLastRow);
1309 if (aPos.first->type != sc::element_type_empty)
1310 return nLastRow;
1312 if (aPos.first == maCells.begin())
1313 // This is the first block, and is empty.
1314 return 0;
1316 return static_cast<SCROW>(aPos.first->position - 1);
1319 bool ScColumn::GetPrevDataPos(SCROW& rRow) const
1321 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
1322 sc::CellStoreType::const_iterator it = aPos.first;
1323 if (it == maCells.end())
1324 return false;
1326 if (it->type == sc::element_type_empty)
1328 if (it == maCells.begin())
1329 // No more previous non-empty cell.
1330 return false;
1332 rRow -= aPos.second + 1; // Last row position of the previous block.
1333 return true;
1336 // This block is not empty.
1337 if (aPos.second)
1339 // There are preceding cells in this block. Simply move back one cell.
1340 --rRow;
1341 return true;
1344 // This is the first cell in an non-empty block. Move back to the previous block.
1345 if (it == maCells.begin())
1346 // No more preceding block.
1347 return false;
1349 --rRow; // Move to the last cell of the previous block.
1350 --it;
1351 if (it->type == sc::element_type_empty)
1353 // This block is empty.
1354 if (it == maCells.begin())
1355 // No more preceding blocks.
1356 return false;
1358 // Skip the whole empty block segment.
1359 rRow -= it->size;
1362 return true;
1365 bool ScColumn::GetNextDataPos(SCROW& rRow) const // greater than rRow
1367 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
1368 sc::CellStoreType::const_iterator it = aPos.first;
1369 if (it == maCells.end())
1370 return false;
1372 if (it->type == sc::element_type_empty)
1374 // This block is empty. Skip ahead to the next block (if exists).
1375 rRow += it->size - aPos.second;
1376 ++it;
1377 if (it == maCells.end())
1378 // No more next block.
1379 return false;
1381 // Next block exists, and is non-empty.
1382 return true;
1385 if (aPos.second < it->size - 1)
1387 // There are still cells following the current position.
1388 ++rRow;
1389 return true;
1392 // This is the last cell in the block. Move ahead to the next block.
1393 rRow += it->size - aPos.second; // First cell in the next block.
1394 ++it;
1395 if (it == maCells.end())
1396 // No more next block.
1397 return false;
1399 if (it->type == sc::element_type_empty)
1401 // Next block is empty. Move to the next block.
1402 rRow += it->size;
1403 ++it;
1404 if (it == maCells.end())
1405 return false;
1408 return true;
1411 SCROW ScColumn::FindNextVisibleRow(SCROW nRow, bool bForward) const
1413 if(bForward)
1415 nRow++;
1416 SCROW nEndRow = 0;
1417 bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
1418 if(bHidden)
1419 return std::min<SCROW>(MAXROW, nEndRow + 1);
1420 else
1421 return nRow;
1423 else
1425 nRow--;
1426 SCROW nStartRow = MAXROW;
1427 bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
1428 if(bHidden)
1429 return std::max<SCROW>(0, nStartRow - 1);
1430 else
1431 return nRow;
1435 SCROW ScColumn::FindNextVisibleRowWithContent(
1436 sc::CellStoreType::const_iterator& itPos, SCROW nRow, bool bForward) const
1438 if (bForward)
1442 nRow++;
1443 SCROW nEndRow = 0;
1444 bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
1445 if (bHidden)
1447 nRow = nEndRow + 1;
1448 if(nRow >= MAXROW)
1449 return MAXROW;
1452 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
1453 itPos = aPos.first;
1454 if (itPos == maCells.end())
1455 // Invalid row.
1456 return MAXROW;
1458 if (itPos->type != sc::element_type_empty)
1459 return nRow;
1461 // Move to the last cell of the current empty block.
1462 nRow += itPos->size - aPos.second - 1;
1464 while (nRow < MAXROW);
1466 return MAXROW;
1471 nRow--;
1472 SCROW nStartRow = MAXROW;
1473 bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
1474 if (bHidden)
1476 nRow = nStartRow - 1;
1477 if(nRow <= 0)
1478 return 0;
1481 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
1482 itPos = aPos.first;
1483 if (itPos == maCells.end())
1484 // Invalid row.
1485 return 0;
1487 if (itPos->type != sc::element_type_empty)
1488 return nRow;
1490 // Move to the first cell of the current empty block.
1491 nRow -= aPos.second;
1493 while (nRow > 0);
1495 return 0;
1498 void ScColumn::CellStorageModified()
1500 // TODO: Update column's "last updated" timestamp here.
1502 mbDirtyGroups = true;
1504 #if DEBUG_COLUMN_STORAGE
1505 if (maCells.size() != MAXROWCOUNT)
1507 cout << "ScColumn::CellStorageModified: Size of the cell array is incorrect." << endl;
1508 cout.flush();
1509 abort();
1512 if (maCellTextAttrs.size() != MAXROWCOUNT)
1514 cout << "ScColumn::CellStorageModified: Size of the cell text attribute array is incorrect." << endl;
1515 cout.flush();
1516 abort();
1519 if (maBroadcasters.size() != MAXROWCOUNT)
1521 cout << "ScColumn::CellStorageModified: Size of the broadcaster array is incorrect." << endl;
1522 cout.flush();
1523 abort();
1526 // Make sure that these two containers are synchronized wrt empty segments.
1527 sc::CellStoreType::const_iterator itCell = maCells.begin();
1528 sc::CellTextAttrStoreType::const_iterator itAttr = maCellTextAttrs.begin();
1530 // Move to the first empty blocks.
1531 while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
1532 ++itCell;
1534 while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
1535 ++itAttr;
1537 while (itCell != maCells.end())
1539 if (itCell->position != itAttr->position || itCell->size != itAttr->size)
1541 cout << "ScColumn::CellStorageModified: Cell array and cell text attribute array are out of sync." << endl;
1542 cout << "-- cell array" << endl;
1543 maCells.dump_blocks(cout);
1544 cout << "-- attribute array" << endl;
1545 maCellTextAttrs.dump_blocks(cout);
1546 cout.flush();
1547 abort();
1550 // Move to the next empty blocks.
1551 ++itCell;
1552 while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
1553 ++itCell;
1555 ++itAttr;
1556 while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
1557 ++itAttr;
1559 #endif
1562 #if DEBUG_COLUMN_STORAGE
1564 namespace {
1566 struct FormulaGroupDumper : std::unary_function<sc::CellStoreType::value_type, void>
1568 void operator() (const sc::CellStoreType::value_type& rNode) const
1570 if (rNode.type != sc::element_type_formula)
1571 return;
1573 cout << " -- formula block" << endl;
1574 sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
1575 sc::formula_block::const_iterator itEnd = sc::formula_block::end(*rNode.data);
1577 for (; it != itEnd; ++it)
1579 const ScFormulaCell& rCell = **it;
1580 if (!rCell.IsShared())
1582 cout << " + row " << rCell.aPos.Row() << " not shared" << endl;
1583 continue;
1586 if (rCell.GetSharedTopRow() != rCell.aPos.Row())
1588 cout << " + row " << rCell.aPos.Row() << " shared with top row " << rCell.GetSharedTopRow() << " with length " << rCell.GetSharedLength() << endl;
1589 continue;
1592 SCROW nLen = rCell.GetSharedLength();
1593 cout << " * group: start=" << rCell.aPos.Row() << ", length=" << nLen << endl;
1594 std::advance(it, nLen-1);
1601 void ScColumn::DumpFormulaGroups() const
1603 cout << "-- formua groups" << endl;
1604 std::for_each(maCells.begin(), maCells.end(), FormulaGroupDumper());
1605 cout << "--" << endl;
1607 #endif
1609 void ScColumn::CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const
1611 rDestCol.maCellTextAttrs.set_empty(nRow1, nRow2); // Empty the destination range first.
1613 sc::CellTextAttrStoreType::const_iterator itBlk = maCellTextAttrs.begin(), itBlkEnd = maCellTextAttrs.end();
1615 // Locate the top row position.
1616 size_t nOffsetInBlock = 0;
1617 size_t nBlockStart = 0, nBlockEnd = 0, nRowPos = static_cast<size_t>(nRow1);
1618 for (; itBlk != itBlkEnd; ++itBlk)
1620 nBlockEnd = nBlockStart + itBlk->size;
1621 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1623 // Found.
1624 nOffsetInBlock = nRowPos - nBlockStart;
1625 break;
1629 if (itBlk == itBlkEnd)
1630 // Specified range not found. Bail out.
1631 return;
1633 nRowPos = static_cast<size_t>(nRow2); // End row position.
1635 // Keep copying until we hit the end row position.
1636 sc::celltextattr_block::const_iterator itData, itDataEnd;
1637 for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd, nOffsetInBlock = 0)
1639 nBlockEnd = nBlockStart + itBlk->size;
1640 if (!itBlk->data)
1642 // Empty block.
1643 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1644 // This block contains the end row.
1645 rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nRowPos);
1646 else
1647 rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nBlockEnd-1);
1649 continue;
1652 // Non-empty block.
1653 itData = sc::celltextattr_block::begin(*itBlk->data);
1654 itDataEnd = sc::celltextattr_block::end(*itBlk->data);
1655 std::advance(itData, nOffsetInBlock);
1657 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1659 // This block contains the end row. Only copy partially.
1660 size_t nOffset = nRowPos - nBlockStart + 1;
1661 itDataEnd = sc::celltextattr_block::begin(*itBlk->data);
1662 std::advance(itDataEnd, nOffset);
1664 rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
1665 break;
1668 rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
1672 namespace {
1674 class CopyCellNotesHandler
1676 ScColumn& mrDestCol;
1677 sc::CellNoteStoreType& mrDestNotes;
1678 sc::CellNoteStoreType::iterator miPos;
1679 SCTAB mnSrcTab;
1680 SCCOL mnSrcCol;
1681 SCTAB mnDestTab;
1682 SCCOL mnDestCol;
1683 SCROW mnDestOffset; /// Add this to the source row position to get the destination row.
1684 bool mbCloneCaption;
1686 public:
1687 CopyCellNotesHandler( const ScColumn& rSrcCol, ScColumn& rDestCol, SCROW nDestOffset, bool bCloneCaption ) :
1688 mrDestCol(rDestCol),
1689 mrDestNotes(rDestCol.GetCellNoteStore()),
1690 miPos(mrDestNotes.begin()),
1691 mnSrcTab(rSrcCol.GetTab()),
1692 mnSrcCol(rSrcCol.GetCol()),
1693 mnDestTab(rDestCol.GetTab()),
1694 mnDestCol(rDestCol.GetCol()),
1695 mnDestOffset(nDestOffset),
1696 mbCloneCaption(bCloneCaption) {}
1698 void operator() ( size_t nRow, const ScPostIt* p )
1700 SCROW nDestRow = nRow + mnDestOffset;
1701 ScAddress aSrcPos(mnSrcCol, nRow, mnSrcTab);
1702 ScAddress aDestPos(mnDestCol, nDestRow, mnDestTab);
1703 miPos = mrDestNotes.set(miPos, nDestRow, p->Clone(aSrcPos, mrDestCol.GetDoc(), aDestPos, mbCloneCaption));
1709 void ScColumn::CopyCellNotesToDocument(
1710 SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, bool bCloneCaption, SCROW nRowOffsetDest ) const
1712 if (IsNotesEmptyBlock(nRow1, nRow2))
1713 // The column has no cell notes to copy between specified rows.
1714 return;
1716 ScDrawLayer *pDrawLayer = rDestCol.GetDoc().GetDrawLayer();
1717 bool bWasLocked = bool();
1718 if (pDrawLayer)
1720 // Avoid O(n^2) by temporary locking SdrModel which disables broadcasting.
1721 // Each cell note adds undo listener, and all of them would be woken up in ScPostIt::CreateCaption.
1722 bWasLocked = pDrawLayer->isLocked();
1723 pDrawLayer->setLock(true);
1725 CopyCellNotesHandler aFunc(*this, rDestCol, nRowOffsetDest, bCloneCaption);
1726 sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
1727 if (pDrawLayer)
1728 pDrawLayer->setLock(bWasLocked);
1731 void ScColumn::DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol, sc::ColumnBlockPosition& maDestBlockPos,
1732 bool bCloneCaption, SCROW nRowOffsetDest ) const
1734 CopyCellNotesToDocument(nStartRow, nStartRow + nDataSize -1, rDestCol, bCloneCaption, nRowOffsetDest);
1735 maDestBlockPos.miCellNotePos = rDestCol.maCellNotes.begin();
1738 SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow)
1740 return maBroadcasters.get<SvtBroadcaster*>(nRow);
1743 const SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow) const
1745 return maBroadcasters.get<SvtBroadcaster*>(nRow);
1748 const SvtBroadcaster* ScColumn::GetBroadcaster( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
1750 sc::BroadcasterStoreType::const_position_type aPos = maBroadcasters.position(rBlockPos.miBroadcasterPos, nRow);
1751 rBlockPos.miBroadcasterPos = aPos.first;
1753 if (aPos.first->type != sc::element_type_broadcaster)
1754 return NULL;
1756 return sc::broadcaster_block::at(*aPos.first->data, aPos.second);
1759 void ScColumn::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
1761 rBlockPos.miBroadcasterPos =
1762 maBroadcasters.set_empty(rBlockPos.miBroadcasterPos, nRow1, nRow2);
1765 void ScColumn::PrepareBroadcastersForDestruction()
1767 sc::BroadcasterStoreType::iterator itPos = maBroadcasters.begin(), itPosEnd = maBroadcasters.end();
1768 for (; itPos != itPosEnd; ++itPos)
1770 if (itPos->type == sc::element_type_broadcaster)
1772 sc::broadcaster_block::iterator it = sc::broadcaster_block::begin(*itPos->data);
1773 sc::broadcaster_block::iterator itEnd = sc::broadcaster_block::end(*itPos->data);
1774 for (; it != itEnd; ++it)
1775 (*it)->PrepareForDestruction();
1780 bool ScColumn::HasBroadcaster() const
1782 sc::BroadcasterStoreType::const_iterator it = maBroadcasters.begin(), itEnd = maBroadcasters.end();
1783 for (; it != itEnd; ++it)
1785 if (it->type == sc::element_type_broadcaster)
1786 // Having a broadcaster block automatically means there is at least one broadcaster.
1787 return true;
1789 return false;
1792 ScPostIt* ScColumn::GetCellNote(SCROW nRow)
1794 return maCellNotes.get<ScPostIt*>(nRow);
1797 const ScPostIt* ScColumn::GetCellNote(SCROW nRow) const
1799 return maCellNotes.get<ScPostIt*>(nRow);
1802 const ScPostIt* ScColumn::GetCellNote( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
1804 sc::CellNoteStoreType::const_position_type aPos = maCellNotes.position(rBlockPos.miCellNotePos, nRow);
1805 rBlockPos.miCellNotePos = aPos.first;
1807 if (aPos.first->type != sc::element_type_cellnote)
1808 return NULL;
1810 return sc::cellnote_block::at(*aPos.first->data, aPos.second);
1813 void ScColumn::SetCellNote(SCROW nRow, ScPostIt* pNote)
1815 //pNote->UpdateCaptionPos(ScAddress(nCol, nRow, nTab)); // TODO notes useful ? slow import with many notes
1816 maCellNotes.set(nRow, pNote);
1819 namespace {
1820 class ForgetCellNoteCaptionsHandler
1823 public:
1824 ForgetCellNoteCaptionsHandler() {}
1826 void operator() ( size_t /*nRow*/, ScPostIt* p )
1828 p->ForgetCaption();
1833 void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership )
1835 if (bForgetCaptionOwnership)
1837 ForgetCellNoteCaptionsHandler aFunc;
1838 sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
1840 rBlockPos.miCellNotePos =
1841 maCellNotes.set_empty(rBlockPos.miCellNotePos, nRow1, nRow2);
1844 bool ScColumn::HasCellNotes() const
1846 sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
1847 for (; it != itEnd; ++it)
1849 if (it->type == sc::element_type_cellnote)
1850 // Having a cellnote block automatically means there is at least one cell note.
1851 return true;
1853 return false;
1856 SCROW ScColumn::GetCellNotesMaxRow() const
1858 // hypothesis : the column has cell notes (should be checked before)
1859 SCROW maxRow = 0;
1860 sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
1861 for (; it != itEnd; ++it)
1863 if (it->type == sc::element_type_cellnote)
1864 maxRow = it->position + it->size -1;
1866 return maxRow;
1868 SCROW ScColumn::GetCellNotesMinRow() const
1870 // hypothesis : the column has cell notes (should be checked before)
1871 SCROW minRow = 0;
1872 bool bFound = false;
1873 sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
1874 for (; it != itEnd && !bFound; ++it)
1876 if (it->type == sc::element_type_cellnote)
1878 bFound = true;
1879 minRow = it->position;
1882 return minRow;
1885 sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
1887 return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnTextWidth;
1890 void ScColumn::SetTextWidth(SCROW nRow, sal_uInt16 nWidth)
1892 sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
1893 if (aPos.first->type != sc::element_type_celltextattr)
1894 return;
1896 // Set new value only when the slot is not empty.
1897 sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnTextWidth = nWidth;
1898 CellStorageModified();
1901 SvtScriptType ScColumn::GetScriptType( SCROW nRow ) const
1903 if (!ValidRow(nRow) || maCellTextAttrs.is_empty(nRow))
1904 return SvtScriptType::NONE;
1906 return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnScriptType;
1909 SvtScriptType ScColumn::GetRangeScriptType(
1910 sc::CellTextAttrStoreType::iterator& itPos, SCROW nRow1, SCROW nRow2, const sc::CellStoreType::iterator& itrCells )
1912 if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
1913 return SvtScriptType::NONE;
1915 SCROW nRow = nRow1;
1916 std::pair<sc::CellTextAttrStoreType::iterator,size_t> aRet =
1917 maCellTextAttrs.position(itPos, nRow1);
1919 itPos = aRet.first; // Track the position of cell text attribute array.
1921 SvtScriptType nScriptType = SvtScriptType::NONE;
1922 bool bUpdated = false;
1923 if (itPos->type == sc::element_type_celltextattr)
1925 sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
1926 sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
1927 std::advance(it, aRet.second);
1928 for (; it != itEnd; ++it, ++nRow)
1930 if (nRow > nRow2)
1931 return nScriptType;
1933 sc::CellTextAttr& rVal = *it;
1934 if (UpdateScriptType(rVal, nRow, itrCells))
1935 bUpdated = true;
1936 nScriptType |= rVal.mnScriptType;
1939 else
1941 // Skip this whole block.
1942 nRow += itPos->size - aRet.second;
1945 while (nRow <= nRow2)
1947 ++itPos;
1948 if (itPos == maCellTextAttrs.end())
1949 return nScriptType;
1951 if (itPos->type != sc::element_type_celltextattr)
1953 // Skip this whole block.
1954 nRow += itPos->size;
1955 continue;
1958 sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
1959 sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
1960 for (; it != itEnd; ++it, ++nRow)
1962 if (nRow > nRow2)
1963 return nScriptType;
1965 sc::CellTextAttr& rVal = *it;
1966 if (UpdateScriptType(rVal, nRow, itrCells))
1967 bUpdated = true;
1969 nScriptType |= rVal.mnScriptType;
1973 if (bUpdated)
1974 CellStorageModified();
1976 return nScriptType;
1979 void ScColumn::SetScriptType( SCROW nRow, SvtScriptType nType )
1981 if (!ValidRow(nRow))
1982 return;
1984 sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
1985 if (aPos.first->type != sc::element_type_celltextattr)
1986 // Set new value only when the slot is already set.
1987 return;
1989 sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnScriptType = nType;
1990 CellStorageModified();
1993 size_t ScColumn::GetFormulaHash( SCROW nRow ) const
1995 const ScFormulaCell* pCell = FetchFormulaCell(nRow);
1996 return pCell ? pCell->GetHash() : 0;
1999 ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
2001 const ScFormulaCell* pCell = FetchFormulaCell(nRow);
2002 return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
2005 formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
2007 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2008 sc::CellStoreType::iterator it = aPos.first;
2009 if (it == maCells.end())
2010 // Invalid row. Return a null token.
2011 return formula::FormulaTokenRef();
2013 switch (it->type)
2015 case sc::element_type_numeric:
2017 double fVal = sc::numeric_block::at(*it->data, aPos.second);
2018 return formula::FormulaTokenRef(new formula::FormulaDoubleToken(fVal));
2020 case sc::element_type_formula:
2022 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2023 if (p->IsValue())
2024 return formula::FormulaTokenRef(new formula::FormulaDoubleToken(p->GetValue()));
2026 return formula::FormulaTokenRef(new formula::FormulaStringToken(p->GetString()));
2028 case sc::element_type_string:
2030 const svl::SharedString& rSS = sc::string_block::at(*it->data, aPos.second);
2031 return formula::FormulaTokenRef(new formula::FormulaStringToken(rSS.getString()));
2033 case sc::element_type_edittext:
2035 const EditTextObject* pText = sc::edittext_block::at(*it->data, aPos.second);
2036 OUString aStr = ScEditUtil::GetString(*pText, pDocument);
2037 return formula::FormulaTokenRef(new formula::FormulaStringToken(aStr));
2039 case sc::element_type_empty:
2040 default:
2041 // Return a value of 0.0 in all the other cases.
2042 return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
2046 namespace {
2048 class ToMatrixHandler
2050 ScMatrix& mrMat;
2051 SCCOL mnMatCol;
2052 SCROW mnTopRow;
2053 ScDocument* mpDoc;
2054 svl::SharedStringPool& mrStrPool;
2055 public:
2056 ToMatrixHandler(ScMatrix& rMat, SCCOL nMatCol, SCROW nTopRow, ScDocument* pDoc) :
2057 mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow),
2058 mpDoc(pDoc), mrStrPool(pDoc->GetSharedStringPool()) {}
2060 void operator() (size_t nRow, double fVal)
2062 mrMat.PutDouble(fVal, mnMatCol, nRow - mnTopRow);
2065 void operator() (size_t nRow, const ScFormulaCell* p)
2067 // Formula cell may need to re-calculate.
2068 ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*p);
2069 if (rCell.IsValue())
2070 mrMat.PutDouble(rCell.GetValue(), mnMatCol, nRow - mnTopRow);
2071 else
2072 mrMat.PutString(rCell.GetString(), mnMatCol, nRow - mnTopRow);
2075 void operator() (size_t nRow, const svl::SharedString& rSS)
2077 mrMat.PutString(rSS, mnMatCol, nRow - mnTopRow);
2080 void operator() (size_t nRow, const EditTextObject* pStr)
2082 mrMat.PutString(mrStrPool.intern(ScEditUtil::GetString(*pStr, mpDoc)), mnMatCol, nRow - mnTopRow);
2088 bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
2090 if (nRow1 > nRow2)
2091 return false;
2093 ToMatrixHandler aFunc(rMat, nMatCol, nRow1, pDocument);
2094 sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
2095 return true;
2098 namespace {
2100 struct CellBucket
2102 SCSIZE mnEmpValStart;
2103 SCSIZE mnNumValStart;
2104 SCSIZE mnStrValStart;
2105 SCSIZE mnEmpValCount;
2106 std::vector<double> maNumVals;
2107 std::vector<svl::SharedString> maStrVals;
2109 CellBucket() : mnEmpValStart(0), mnNumValStart(0), mnStrValStart(0), mnEmpValCount(0) {}
2111 void flush(ScMatrix& rMat, SCSIZE nCol)
2113 if (mnEmpValCount)
2115 rMat.PutEmptyResultVector(mnEmpValCount, nCol, mnEmpValStart);
2116 reset();
2118 else if (!maNumVals.empty())
2120 const double* p = &maNumVals[0];
2121 rMat.PutDouble(p, maNumVals.size(), nCol, mnNumValStart);
2122 reset();
2124 else if (!maStrVals.empty())
2126 const svl::SharedString* p = &maStrVals[0];
2127 rMat.PutString(p, maStrVals.size(), nCol, mnStrValStart);
2128 reset();
2132 void reset()
2134 mnEmpValStart = mnNumValStart = mnStrValStart = 0;
2135 mnEmpValCount = 0;
2136 maNumVals.clear();
2137 maStrVals.clear();
2141 class FillMatrixHandler
2143 ScMatrix& mrMat;
2144 size_t mnMatCol;
2145 size_t mnTopRow;
2147 SCCOL mnCol;
2148 SCTAB mnTab;
2149 ScDocument* mpDoc;
2150 svl::SharedStringPool& mrPool;
2152 public:
2153 FillMatrixHandler(ScMatrix& rMat, size_t nMatCol, size_t nTopRow, SCCOL nCol, SCTAB nTab, ScDocument* pDoc) :
2154 mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow), mnCol(nCol), mnTab(nTab), mpDoc(pDoc), mrPool(pDoc->GetSharedStringPool()) {}
2156 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2158 size_t nMatRow = node.position + nOffset - mnTopRow;
2160 switch (node.type)
2162 case sc::element_type_numeric:
2164 const double* p = &sc::numeric_block::at(*node.data, nOffset);
2165 mrMat.PutDouble(p, nDataSize, mnMatCol, nMatRow);
2167 break;
2168 case sc::element_type_string:
2170 const svl::SharedString* p = &sc::string_block::at(*node.data, nOffset);
2171 mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
2173 break;
2174 case sc::element_type_edittext:
2176 std::vector<svl::SharedString> aSSs;
2177 aSSs.reserve(nDataSize);
2178 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
2179 std::advance(it, nOffset);
2180 sc::edittext_block::const_iterator itEnd = it;
2181 std::advance(itEnd, nDataSize);
2182 for (; it != itEnd; ++it)
2184 OUString aStr = ScEditUtil::GetString(**it, mpDoc);
2185 aSSs.push_back(mrPool.intern(aStr));
2188 const svl::SharedString* p = &aSSs[0];
2189 mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
2191 break;
2192 case sc::element_type_formula:
2194 CellBucket aBucket;
2195 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
2196 std::advance(it, nOffset);
2197 sc::formula_block::const_iterator itEnd = it;
2198 std::advance(itEnd, nDataSize);
2200 size_t nPrevRow = 0, nThisRow = node.position + nOffset;
2201 for (; it != itEnd; ++it, nPrevRow = nThisRow, ++nThisRow)
2203 ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
2205 if (rCell.IsEmpty())
2207 if (aBucket.mnEmpValCount && nThisRow == nPrevRow + 1)
2209 // Secondary empty results.
2210 ++aBucket.mnEmpValCount;
2212 else
2214 // First empty result.
2215 aBucket.flush(mrMat, mnMatCol);
2216 aBucket.mnEmpValStart = nThisRow - mnTopRow;
2217 ++aBucket.mnEmpValCount;
2219 continue;
2222 sal_uInt16 nErr;
2223 double fVal;
2224 if (rCell.GetErrorOrValue(nErr, fVal))
2226 ScAddress aAdr(mnCol, nThisRow, mnTab);
2228 if (nErr)
2229 fVal = CreateDoubleError(nErr);
2231 if (!aBucket.maNumVals.empty() && nThisRow == nPrevRow + 1)
2233 // Secondary numbers.
2234 aBucket.maNumVals.push_back(fVal);
2236 else
2238 // First number.
2239 aBucket.flush(mrMat, mnMatCol);
2240 aBucket.mnNumValStart = nThisRow - mnTopRow;
2241 aBucket.maNumVals.push_back(fVal);
2243 continue;
2246 svl::SharedString aStr = rCell.GetString();
2247 if (!aBucket.maStrVals.empty() && nThisRow == nPrevRow + 1)
2249 // Secondary strings.
2250 aBucket.maStrVals.push_back(aStr);
2252 else
2254 // First string.
2255 aBucket.flush(mrMat, mnMatCol);
2256 aBucket.mnStrValStart = nThisRow - mnTopRow;
2257 aBucket.maStrVals.push_back(aStr);
2261 aBucket.flush(mrMat, mnMatCol);
2263 break;
2264 default:
2272 void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2 ) const
2274 FillMatrixHandler aFunc(rMat, nMatCol, nRow1, nCol, nTab, pDocument);
2275 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
2278 namespace {
2280 template<typename _Blk>
2281 void getBlockIterators(
2282 const sc::CellStoreType::iterator& it, size_t& rLenRemain,
2283 typename _Blk::iterator& rData, typename _Blk::iterator& rDataEnd )
2285 rData = _Blk::begin(*it->data);
2286 if (rLenRemain >= it->size)
2288 // Block is shorter than the remaining requested length.
2289 rDataEnd = _Blk::end(*it->data);
2290 rLenRemain -= it->size;
2292 else
2294 rDataEnd = rData;
2295 std::advance(rDataEnd, rLenRemain);
2296 rLenRemain = 0;
2300 bool appendToBlock(
2301 ScDocument* pDoc, sc::FormulaGroupContext& rCxt, sc::FormulaGroupContext::ColArray& rColArray,
2302 size_t nPos, size_t nArrayLen, const sc::CellStoreType::iterator& _it, const sc::CellStoreType::iterator& itEnd )
2304 svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
2305 size_t nLenRemain = nArrayLen - nPos;
2306 double fNan;
2307 rtl::math::setNan(&fNan);
2309 for (sc::CellStoreType::iterator it = _it; it != itEnd; ++it)
2311 switch (it->type)
2313 case sc::element_type_string:
2315 sc::string_block::iterator itData, itDataEnd;
2316 getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
2317 rCxt.ensureStrArray(rColArray, nArrayLen);
2319 for (; itData != itDataEnd; ++itData, ++nPos)
2320 (*rColArray.mpStrArray)[nPos] = itData->getDataIgnoreCase();
2322 break;
2323 case sc::element_type_edittext:
2325 sc::edittext_block::iterator itData, itDataEnd;
2326 getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
2327 rCxt.ensureStrArray(rColArray, nArrayLen);
2329 for (; itData != itDataEnd; ++itData, ++nPos)
2331 OUString aStr = ScEditUtil::GetString(**itData, pDoc);
2332 (*rColArray.mpStrArray)[nPos] = rPool.intern(aStr).getDataIgnoreCase();
2335 break;
2336 case sc::element_type_formula:
2338 sc::formula_block::iterator itData, itDataEnd;
2339 getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
2341 /* tdf#91416 setting progress in triggers a resize of the window
2342 and so ScTabView::DoResize and an InterpretVisible and
2343 InterpretDirtyCells which resets the mpFormulaGroupCxt that
2344 the current rCxt points to, which is bad, so disable progress
2345 during GetResult
2347 ScProgress *pProgress = ScProgress::GetInterpretProgress();
2348 bool bTempDisableProgress = pProgress && pProgress->Enabled();
2349 if (bTempDisableProgress)
2350 pProgress->Disable();
2352 for (; itData != itDataEnd; ++itData, ++nPos)
2354 ScFormulaCell& rFC = **itData;
2356 sc::FormulaResultValue aRes = rFC.GetResult();
2358 if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
2360 if (aRes.mnError == ScErrorCodes::errCircularReference)
2362 // This cell needs to be recalculated on next visit.
2363 rFC.SetErrCode(0);
2364 rFC.SetDirtyVar();
2366 return false;
2369 if (aRes.meType == sc::FormulaResultValue::String)
2371 rCxt.ensureStrArray(rColArray, nArrayLen);
2372 (*rColArray.mpStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
2374 else
2376 rCxt.ensureNumArray(rColArray, nArrayLen);
2377 (*rColArray.mpNumArray)[nPos] = aRes.mfValue;
2381 if (bTempDisableProgress)
2382 pProgress->Enable();
2384 break;
2385 case sc::element_type_empty:
2387 if (nLenRemain > it->size)
2389 nPos += it->size;
2390 nLenRemain -= it->size;
2392 else
2394 nPos = nArrayLen;
2395 nLenRemain = 0;
2398 break;
2399 case sc::element_type_numeric:
2401 sc::numeric_block::iterator itData, itDataEnd;
2402 getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
2403 rCxt.ensureNumArray(rColArray, nArrayLen);
2405 for (; itData != itDataEnd; ++itData, ++nPos)
2406 (*rColArray.mpNumArray)[nPos] = *itData;
2408 break;
2409 default:
2410 return false;
2413 if (!nLenRemain)
2414 return true;
2417 return false;
2420 void copyFirstStringBlock(
2421 ScDocument& rDoc, sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, const sc::CellStoreType::iterator& itBlk )
2423 sc::FormulaGroupContext::StrArrayType::iterator itArray = rArray.begin();
2425 switch (itBlk->type)
2427 case sc::element_type_string:
2429 sc::string_block::iterator it = sc::string_block::begin(*itBlk->data);
2430 sc::string_block::iterator itEnd = it;
2431 std::advance(itEnd, nLen);
2432 for (; it != itEnd; ++it, ++itArray)
2433 *itArray = it->getDataIgnoreCase();
2435 break;
2436 case sc::element_type_edittext:
2438 sc::edittext_block::iterator it = sc::edittext_block::begin(*itBlk->data);
2439 sc::edittext_block::iterator itEnd = it;
2440 std::advance(itEnd, nLen);
2442 svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
2443 for (; it != itEnd; ++it, ++itArray)
2445 EditTextObject* pText = *it;
2446 OUString aStr = ScEditUtil::GetString(*pText, &rDoc);
2447 *itArray = rPool.intern(aStr).getDataIgnoreCase();
2450 break;
2451 default:
2456 sc::FormulaGroupContext::ColArray*
2457 copyFirstFormulaBlock(
2458 sc::FormulaGroupContext& rCxt, const sc::CellStoreType::iterator& itBlk, size_t nArrayLen,
2459 SCTAB nTab, SCCOL nCol )
2461 double fNan;
2462 rtl::math::setNan(&fNan);
2464 size_t nLen = std::min(itBlk->size, nArrayLen);
2466 sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data);
2467 sc::formula_block::iterator itEnd;
2469 sc::FormulaGroupContext::NumArrayType* pNumArray = NULL;
2470 sc::FormulaGroupContext::StrArrayType* pStrArray = NULL;
2472 itEnd = it;
2473 std::advance(itEnd, nLen);
2474 size_t nPos = 0;
2475 for (; it != itEnd; ++it, ++nPos)
2477 ScFormulaCell& rFC = **it;
2478 sc::FormulaResultValue aRes = rFC.GetResult();
2479 if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
2481 if (aRes.mnError == ScErrorCodes::errCircularReference)
2483 // This cell needs to be recalculated on next visit.
2484 rFC.SetErrCode(0);
2485 rFC.SetDirtyVar();
2487 return NULL;
2490 if (aRes.meType == sc::FormulaResultValue::Value)
2492 if (!pNumArray)
2494 rCxt.maNumArrays.push_back(
2495 new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
2496 pNumArray = &rCxt.maNumArrays.back();
2499 (*pNumArray)[nPos] = aRes.mfValue;
2501 else
2503 if (!pStrArray)
2505 rCxt.maStrArrays.push_back(
2506 new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
2507 pStrArray = &rCxt.maStrArrays.back();
2510 (*pStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
2514 if (!pNumArray && !pStrArray)
2515 // At least one of these arrays should be allocated.
2516 return NULL;
2518 return rCxt.setCachedColArray(nTab, nCol, pNumArray, pStrArray);
2521 struct NonNullStringFinder : std::unary_function<const rtl_uString*, bool>
2523 bool operator() (const rtl_uString* p) const { return p != NULL; }
2526 bool hasNonEmpty( const sc::FormulaGroupContext::StrArrayType& rArray, SCROW nRow1, SCROW nRow2 )
2528 // The caller has to make sure the array is at least nRow2+1 long.
2529 sc::FormulaGroupContext::StrArrayType::const_iterator it = rArray.begin();
2530 std::advance(it, nRow1);
2531 sc::FormulaGroupContext::StrArrayType::const_iterator itEnd = it;
2532 std::advance(itEnd, nRow2-nRow1+1);
2533 return std::any_of(it, itEnd, NonNullStringFinder());
2538 formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2 )
2540 if (nRow1 > nRow2)
2541 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2543 // See if the requested range is already cached.
2544 sc::FormulaGroupContext& rCxt = pDocument->GetFormulaGroupContext();
2545 sc::FormulaGroupContext::ColArray* pColArray = rCxt.getCachedColArray(nTab, nCol, nRow2+1);
2546 if (pColArray)
2548 const double* pNum = NULL;
2549 if (pColArray->mpNumArray)
2550 pNum = &(*pColArray->mpNumArray)[nRow1];
2552 rtl_uString** pStr = NULL;
2553 if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
2554 pStr = &(*pColArray->mpStrArray)[nRow1];
2556 return formula::VectorRefArray(pNum, pStr);
2559 double fNan;
2560 rtl::math::setNan(&fNan);
2562 // We need to fetch all cell values from row 0 to nRow2 for caching purposes.
2563 sc::CellStoreType::iterator itBlk = maCells.begin();
2564 switch (itBlk->type)
2566 case sc::element_type_numeric:
2568 if (static_cast<size_t>(nRow2) < itBlk->size)
2570 // Requested range falls within the first block. No need to cache.
2571 const double* p = &sc::numeric_block::at(*itBlk->data, nRow1);
2572 return formula::VectorRefArray(p);
2575 // Allocate a new array and copy the values to it.
2576 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*itBlk->data);
2577 sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*itBlk->data);
2578 rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(it, itEnd));
2579 sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
2580 rArray.resize(nRow2+1, fNan); // allocate to the requested length.
2582 pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
2583 if (!pColArray)
2584 // Failed to insert a new cached column array.
2585 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2587 // Fill the remaining array with values from the following blocks.
2588 size_t nPos = itBlk->size;
2589 ++itBlk;
2590 if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2591 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2593 if (pColArray->mpStrArray)
2594 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
2595 else
2596 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
2598 break;
2599 case sc::element_type_string:
2600 case sc::element_type_edittext:
2602 rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType(nRow2+1, NULL));
2603 sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
2604 pColArray = rCxt.setCachedColArray(nTab, nCol, NULL, &rArray);
2605 if (!pColArray)
2606 // Failed to insert a new cached column array.
2607 return formula::VectorRefArray();
2609 if (static_cast<size_t>(nRow2) < itBlk->size)
2611 // Requested range falls within the first block.
2612 copyFirstStringBlock(*pDocument, rArray, nRow2+1, itBlk);
2613 return formula::VectorRefArray(&rArray[nRow1]);
2616 copyFirstStringBlock(*pDocument, rArray, itBlk->size, itBlk);
2618 // Fill the remaining array with values from the following blocks.
2619 size_t nPos = itBlk->size;
2620 ++itBlk;
2621 if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2622 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2624 if (pColArray->mpNumArray)
2625 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
2626 else
2627 return formula::VectorRefArray(&(*pColArray->mpStrArray)[nRow1]);
2629 break;
2630 case sc::element_type_formula:
2632 if (static_cast<size_t>(nRow2) < itBlk->size)
2634 // Requested length is within a single block, and the data is
2635 // not cached.
2636 pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
2637 if (!pColArray)
2638 // Failed to insert a new cached column array.
2639 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2641 const double* pNum = NULL;
2642 rtl_uString** pStr = NULL;
2643 if (pColArray->mpNumArray)
2644 pNum = &(*pColArray->mpNumArray)[nRow1];
2645 if (pColArray->mpStrArray)
2646 pStr = &(*pColArray->mpStrArray)[nRow1];
2648 return formula::VectorRefArray(pNum, pStr);
2651 pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
2652 if (!pColArray)
2653 // Failed to insert a new cached column array.
2654 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2656 size_t nPos = itBlk->size;
2657 ++itBlk;
2658 if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2659 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2661 const double* pNum = NULL;
2662 rtl_uString** pStr = NULL;
2663 if (pColArray->mpNumArray)
2664 pNum = &(*pColArray->mpNumArray)[nRow1];
2665 if (pColArray->mpStrArray)
2666 pStr = &(*pColArray->mpStrArray)[nRow1];
2668 return formula::VectorRefArray(pNum, pStr);
2670 break;
2671 case sc::element_type_empty:
2673 // Fill the whole length with NaN's.
2674 rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nRow2+1, fNan));
2675 sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
2676 pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
2677 if (!pColArray)
2678 // Failed to insert a new cached column array.
2679 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2681 if (static_cast<size_t>(nRow2) < itBlk->size)
2682 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
2684 // Fill the remaining array with values from the following blocks.
2685 size_t nPos = itBlk->size;
2686 ++itBlk;
2687 if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2688 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2690 if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
2691 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
2692 else
2693 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
2695 break;
2696 default:
2700 return formula::VectorRefArray(formula::VectorRefArray::Invalid);
2703 void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen )
2705 sc::CellStoreType::position_type aPos = maCells.position(nRow);
2706 sc::CellStoreType::iterator it = aPos.first;
2707 if (it->type != sc::element_type_formula)
2708 // This is not a formula block.
2709 return;
2711 size_t nBlockLen = it->size - aPos.second;
2712 if (nBlockLen < nLen)
2713 // Result array is longer than the length of formula cells. Not good.
2714 return;
2716 sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
2717 std::advance(itCell, aPos.second);
2719 const double* pResEnd = pResults + nLen;
2720 for (; pResults != pResEnd; ++pResults, ++itCell)
2722 ScFormulaCell& rCell = **itCell;
2723 sal_uInt16 nErr = GetDoubleErrorValue(*pResults);
2724 if (nErr != 0)
2725 rCell.SetResultError(nErr);
2726 else
2727 rCell.SetResultDouble(*pResults);
2728 rCell.ResetDirty();
2729 rCell.SetChanged(true);
2733 void ScColumn::SetFormulaResults( SCROW nRow, const formula::FormulaTokenRef* pResults, size_t nLen )
2735 sc::CellStoreType::position_type aPos = maCells.position(nRow);
2736 sc::CellStoreType::iterator it = aPos.first;
2737 if (it->type != sc::element_type_formula)
2738 // This is not a formula block.
2739 return;
2741 size_t nBlockLen = it->size - aPos.second;
2742 if (nBlockLen < nLen)
2743 // Result array is longer than the length of formula cells. Not good.
2744 return;
2746 sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
2747 std::advance(itCell, aPos.second);
2749 const formula::FormulaTokenRef* pResEnd = pResults + nLen;
2750 for (; pResults != pResEnd; ++pResults, ++itCell)
2752 ScFormulaCell& rCell = **itCell;
2753 rCell.SetResultToken(pResults->get());
2754 rCell.ResetDirty();
2755 rCell.SetChanged(true);
2759 void ScColumn::SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat )
2761 ApplyAttr(nRow, SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat));
2764 ScFormulaCell * const * ScColumn::GetFormulaCellBlockAddress( SCROW nRow, size_t& rBlockSize ) const
2766 if (!ValidRow(nRow))
2768 rBlockSize = 0;
2769 return NULL;
2772 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2773 sc::CellStoreType::const_iterator it = aPos.first;
2774 if (it == maCells.end())
2776 rBlockSize = 0;
2777 return NULL;
2780 if (it->type != sc::element_type_formula)
2782 // Not a formula cell.
2783 rBlockSize = 0;
2784 return NULL;
2787 rBlockSize = it->size;
2788 return &sc::formula_block::at(*it->data, aPos.second);
2791 const ScFormulaCell* ScColumn::FetchFormulaCell( SCROW nRow ) const
2793 size_t nBlockSize = 0;
2794 ScFormulaCell const * const * pp = GetFormulaCellBlockAddress( nRow, nBlockSize );
2795 return pp ? *pp : NULL;
2798 void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
2800 // If the cell is empty, find the next non-empty cell position. If the
2801 // cell is not empty, find the last non-empty cell position in the current
2802 // contiguous cell block.
2804 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
2805 sc::CellStoreType::const_iterator it = aPos.first;
2806 if (it == maCells.end())
2807 // Invalid row.
2808 return;
2810 if (it->type == sc::element_type_empty)
2812 // Current cell is empty. Find the next non-empty cell.
2813 rRow = FindNextVisibleRowWithContent(it, rRow, bDown);
2814 return;
2817 // Current cell is not empty.
2818 SCROW nNextRow = FindNextVisibleRow(rRow, bDown);
2819 aPos = maCells.position(it, nNextRow);
2820 it = aPos.first;
2821 if (it->type == sc::element_type_empty)
2823 // Next visible cell is empty. Find the next non-empty cell.
2824 rRow = FindNextVisibleRowWithContent(it, nNextRow, bDown);
2825 return;
2828 // Next visible cell is non-empty. Find the edge that's still visible.
2829 SCROW nLastRow = nNextRow;
2832 nNextRow = FindNextVisibleRow(nLastRow, bDown);
2833 if (nNextRow == nLastRow)
2834 break;
2836 aPos = maCells.position(it, nNextRow);
2837 it = aPos.first;
2838 if (it->type != sc::element_type_empty)
2839 nLastRow = nNextRow;
2841 while (it->type != sc::element_type_empty);
2843 rRow = nLastRow;
2846 bool ScColumn::HasDataAt(SCROW nRow) const
2848 return maCells.get_type(nRow) != sc::element_type_empty;
2851 bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
2853 if (pAttrArray && rCol.pAttrArray)
2854 return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
2855 else
2856 return !pAttrArray && !rCol.pAttrArray;
2859 bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
2861 if (pAttrArray && rCol.pAttrArray)
2862 return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
2863 else
2864 return !pAttrArray && !rCol.pAttrArray;
2867 bool ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
2869 if (pAttrArray)
2870 return pAttrArray->GetFirstVisibleAttr( rFirstRow );
2871 else
2872 return false;
2875 bool ScColumn::GetLastVisibleAttr( SCROW& rLastRow, bool bFullFormattedArea ) const
2877 if (pAttrArray)
2879 // row of last cell is needed
2880 SCROW nLastData = GetLastDataPos(); // always including notes, 0 if none
2882 return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData, bFullFormattedArea );
2884 else
2885 return false;
2888 bool ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
2890 if (pAttrArray)
2891 return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
2892 else
2893 return false;
2896 namespace {
2898 class FindUsedRowsHandler
2900 typedef mdds::flat_segment_tree<SCROW,bool> UsedRowsType;
2901 UsedRowsType& mrUsed;
2902 UsedRowsType::const_iterator miUsed;
2903 public:
2904 FindUsedRowsHandler(UsedRowsType& rUsed) : mrUsed(rUsed), miUsed(rUsed.begin()) {}
2906 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2908 if (node.type == sc::element_type_empty)
2909 return;
2911 SCROW nRow1 = node.position + nOffset;
2912 SCROW nRow2 = nRow1 + nDataSize - 1;
2913 miUsed = mrUsed.insert(miUsed, nRow1, nRow2+1, true).first;
2919 void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree<SCROW,bool>& rUsed ) const
2921 FindUsedRowsHandler aFunc(rUsed);
2922 sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
2925 namespace {
2927 void startListening(
2928 sc::BroadcasterStoreType& rStore, sc::BroadcasterStoreType::iterator& itBlockPos, size_t nElemPos,
2929 SCROW nRow, SvtListener& rLst)
2931 switch (itBlockPos->type)
2933 case sc::element_type_broadcaster:
2935 // Broadcaster already exists here.
2936 SvtBroadcaster* pBC = sc::broadcaster_block::at(*itBlockPos->data, nElemPos);
2937 rLst.StartListening(*pBC);
2939 break;
2940 case mdds::mtv::element_type_empty:
2942 // No broadcaster exists at this position yet.
2943 SvtBroadcaster* pBC = new SvtBroadcaster;
2944 rLst.StartListening(*pBC);
2945 itBlockPos = rStore.set(itBlockPos, nRow, pBC); // Store the block position for next iteration.
2947 break;
2948 default:
2949 #if DEBUG_COLUMN_STORAGE
2950 cout << "ScColumn::StartListening: wrong block type encountered in the broadcaster storage." << endl;
2951 cout.flush();
2952 abort();
2953 #else
2955 #endif
2961 void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
2963 std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(nRow);
2964 startListening(maBroadcasters, aPos.first, aPos.second, nRow, rLst);
2967 void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
2969 SvtBroadcaster* pBC = GetBroadcaster(nRow);
2970 if (!pBC)
2971 return;
2973 rLst.EndListening(*pBC);
2974 if (!pBC->HasListeners())
2975 // There is no more listeners for this cell. Remove the broadcaster.
2976 maBroadcasters.set_empty(nRow, nRow);
2979 void ScColumn::StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rLst )
2981 if (!ValidRow(nRow))
2982 return;
2984 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
2985 if (!p)
2986 return;
2988 sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
2989 std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
2990 it = aPos.first; // store the block position for next iteration.
2991 startListening(maBroadcasters, it, aPos.second, nRow, rLst);
2994 void ScColumn::EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener )
2996 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
2997 if (!p)
2998 return;
3000 sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
3001 std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
3002 it = aPos.first; // store the block position for next iteration.
3003 if (it->type != sc::element_type_broadcaster)
3004 return;
3006 SvtBroadcaster* pBC = sc::broadcaster_block::at(*it->data, aPos.second);
3007 OSL_ASSERT(pBC);
3009 rListener.EndListening(*pBC);
3010 if (!pBC->HasListeners())
3011 // There is no more listeners for this cell. Add it to the purge list for later purging.
3012 rCxt.addEmptyBroadcasterPosition(nTab, nCol, nRow);
3015 namespace {
3017 class CompileDBFormulaHandler
3019 sc::CompileFormulaContext& mrCxt;
3021 public:
3022 CompileDBFormulaHandler( sc::CompileFormulaContext& rCxt ) :
3023 mrCxt(rCxt) {}
3025 void operator() (size_t, ScFormulaCell* p)
3027 p->CompileDBFormula(mrCxt);
3031 struct CompileColRowNameFormulaHandler
3033 sc::CompileFormulaContext& mrCxt;
3034 public:
3035 CompileColRowNameFormulaHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
3037 void operator() (size_t, ScFormulaCell* p)
3039 p->CompileColRowNameFormula(mrCxt);
3045 void ScColumn::CompileDBFormula( sc::CompileFormulaContext& rCxt )
3047 CompileDBFormulaHandler aFunc(rCxt);
3048 sc::ProcessFormula(maCells, aFunc);
3049 RegroupFormulaCells();
3052 void ScColumn::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
3054 CompileColRowNameFormulaHandler aFunc(rCxt);
3055 sc::ProcessFormula(maCells, aFunc);
3056 RegroupFormulaCells();
3059 namespace {
3061 class UpdateSubTotalHandler
3063 ScFunctionData& mrData;
3065 void update(double fVal, bool bVal)
3067 if (mrData.bError)
3068 return;
3070 switch (mrData.eFunc)
3072 case SUBTOTAL_FUNC_SUM:
3073 case SUBTOTAL_FUNC_AVE:
3075 if (!bVal)
3076 return;
3078 ++mrData.nCount;
3079 if (!SubTotal::SafePlus(mrData.nVal, fVal))
3080 mrData.bError = true;
3082 break;
3083 case SUBTOTAL_FUNC_CNT: // only the value
3085 if (!bVal)
3086 return;
3088 ++mrData.nCount;
3090 break;
3091 case SUBTOTAL_FUNC_CNT2: // everything
3092 ++mrData.nCount;
3093 break;
3094 case SUBTOTAL_FUNC_MAX:
3096 if (!bVal)
3097 return;
3099 if (++mrData.nCount == 1 || fVal > mrData.nVal)
3100 mrData.nVal = fVal;
3102 break;
3103 case SUBTOTAL_FUNC_MIN:
3105 if (!bVal)
3106 return;
3108 if (++mrData.nCount == 1 || fVal < mrData.nVal)
3109 mrData.nVal = fVal;
3111 break;
3112 default:
3114 // added to avoid warnings
3119 public:
3120 UpdateSubTotalHandler(ScFunctionData& rData) : mrData(rData) {}
3122 void operator() (size_t /*nRow*/, double fVal)
3124 update(fVal, true);
3127 void operator() (size_t /*nRow*/, const svl::SharedString&)
3129 update(0.0, false);
3132 void operator() (size_t /*nRow*/, const EditTextObject*)
3134 update(0.0, false);
3137 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
3139 double fVal = 0.0;
3140 bool bVal = false;
3141 if (mrData.eFunc != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
3144 if (pCell->GetErrCode())
3146 if (mrData.eFunc != SUBTOTAL_FUNC_CNT) // simply remove from count
3147 mrData.bError = true;
3149 else if (pCell->IsValue())
3151 fVal = pCell->GetValue();
3152 bVal = true;
3154 // otherwise text
3157 update(fVal, bVal);
3163 // multiple selections:
3164 void ScColumn::UpdateSelectionFunction(
3165 const ScRangeList& rRanges, ScFunctionData& rData, ScFlatBoolRowSegments& rHiddenRows )
3167 sc::SingleColumnSpanSet aSpanSet;
3168 aSpanSet.scan(rRanges, nTab, nCol); // mark all selected rows.
3170 // Exclude all hidden rows.
3171 ScFlatBoolRowSegments::RangeData aRange;
3172 SCROW nRow = 0;
3173 while (nRow <= MAXROW)
3175 if (!rHiddenRows.getRangeData(nRow, aRange))
3176 break;
3178 if (aRange.mbValue)
3179 // Hidden range detected.
3180 aSpanSet.set(nRow, aRange.mnRow2, false);
3182 nRow = aRange.mnRow2 + 1;
3185 sc::SingleColumnSpanSet::SpansType aSpans;
3186 aSpanSet.getSpans(aSpans);
3188 sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
3190 switch (rData.eFunc)
3192 case SUBTOTAL_FUNC_SELECTION_COUNT:
3194 // Simply count selected rows regardless of cell contents.
3195 for (; it != itEnd; ++it)
3196 rData.nCount += it->mnRow2 - it->mnRow1 + 1;
3198 break;
3199 case SUBTOTAL_FUNC_CNT2:
3201 // We need to parse all non-empty cells.
3202 sc::CellStoreType::const_iterator itCellPos = maCells.begin();
3203 UpdateSubTotalHandler aFunc(rData);
3204 for (; it != itEnd; ++it)
3206 itCellPos = sc::ParseAllNonEmpty(
3207 itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
3210 break;
3211 default:
3213 // We need to parse only numeric values.
3214 sc::CellStoreType::const_iterator itCellPos = maCells.begin();
3215 UpdateSubTotalHandler aFunc(rData);
3216 for (; it != itEnd; ++it)
3218 itCellPos = sc::ParseFormulaNumeric(
3219 itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
3225 namespace {
3227 class WeightedCounter
3229 size_t mnCount;
3230 public:
3231 WeightedCounter() : mnCount(0) {}
3233 void operator() (const sc::CellStoreType::value_type& node)
3235 switch (node.type)
3237 case sc::element_type_numeric:
3238 case sc::element_type_string:
3239 mnCount += node.size;
3240 break;
3241 case sc::element_type_formula:
3243 // Each formula cell is worth its code length plus 5.
3244 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
3245 sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
3246 for (; it != itEnd; ++it)
3248 const ScFormulaCell* p = *it;
3249 mnCount += 5 + p->GetCode()->GetCodeLen();
3252 break;
3253 case sc::element_type_edittext:
3254 // each edit-text cell is worth 50.
3255 mnCount += node.size * 50;
3256 break;
3257 default:
3262 size_t getCount() const { return mnCount; }
3267 sal_uInt32 ScColumn::GetWeightedCount() const
3269 WeightedCounter aFunc;
3270 std::for_each(maCells.begin(), maCells.end(), aFunc);
3271 return aFunc.getCount();
3274 namespace {
3276 class CodeCounter
3278 size_t mnCount;
3279 public:
3280 CodeCounter() : mnCount(0) {}
3282 void operator() (size_t, const ScFormulaCell* p)
3284 mnCount += p->GetCode()->GetCodeLen();
3287 size_t getCount() const { return mnCount; }
3292 sal_uInt32 ScColumn::GetCodeCount() const
3294 CodeCounter aFunc;
3295 sc::ParseFormula(maCells, aFunc);
3296 return aFunc.getCount();
3299 SCSIZE ScColumn::GetPatternCount() const
3301 return pAttrArray ? pAttrArray->Count() : 0;
3304 SCSIZE ScColumn::GetPatternCount( SCROW nRow1, SCROW nRow2 ) const
3306 return pAttrArray ? pAttrArray->Count( nRow1, nRow2 ) : 0;
3309 bool ScColumn::ReservePatternCount( SCSIZE nReserve )
3311 return pAttrArray && pAttrArray->Reserve( nReserve );
3314 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */