1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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"
32 #include "editutil.hxx"
33 #include "subtotal.hxx"
34 #include "markdata.hxx"
35 #include "compiler.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>
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>
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
);
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.
99 ScRefCellValue aCell
= GetCellValue(it
, aPos
.second
);
100 double nPPT
= bWidth
? nPPTX
: nPPTY
;
102 const ScPatternAttr
* pPattern
= rOptions
.pPattern
;
104 pPattern
= pAttrArray
->GetPattern( nRow
);
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
));
114 if ( pFlag
->IsHorOverlapped() )
116 if ( rOptions
.bSkipMerged
&& pMerge
->GetColMerge() > 1 )
121 if ( pFlag
->IsVerOverlapped() )
123 if ( rOptions
.bSkipMerged
&& pMerge
->GetRowMerge() > 1 )
127 // conditional formatting
128 const SfxItemSet
* pCondSet
= pDocument
->GetCondResult( nCol
, nRow
, nTab
);
132 const SfxPoolItem
* pCondItem
;
133 SvxCellHorJustify eHorJust
;
135 pCondSet
->GetItemState(ATTR_HOR_JUSTIFY
, true, &pCondItem
) == SfxItemState::SET
)
136 eHorJust
= (SvxCellHorJustify
)static_cast<const SvxHorJustifyItem
*>(pCondItem
)->GetValue();
138 eHorJust
= (SvxCellHorJustify
)static_cast<const SvxHorJustifyItem
&>(
139 pPattern
->GetItem( ATTR_HOR_JUSTIFY
)).GetValue();
141 if ( eHorJust
== SVX_HOR_JUSTIFY_BLOCK
)
143 else if ( pCondSet
&&
144 pCondSet
->GetItemState(ATTR_LINEBREAK
, true, &pCondItem
) == SfxItemState::SET
)
145 bBreak
= static_cast<const SfxBoolItem
*>(pCondItem
)->GetValue();
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
);
165 *ppPatternChange
= pPattern
; // XXX caller may have to check for change!
169 if (!bMayInvalidatePattern
|| pPattern
== pOldPattern
)
173 nFormat
= pPattern
->GetNumberFormat( pFormatter
, pCondSet
);
174 if ((nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0)
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
)
188 if ( bWidth
&& bBreak
) // after determining bAsianVertical (bBreak may be reset)
192 SvxRotateMode eRotMode
= SVX_ROTATE_MODE_STANDARD
;
193 if ( eOrient
== SVX_ORIENTATION_STANDARD
)
196 pCondSet
->GetItemState(ATTR_ROTATE_VALUE
, true, &pCondItem
) == SfxItemState::SET
)
197 nRotate
= static_cast<const SfxInt32Item
*>(pCondItem
)->GetValue();
199 nRotate
=static_cast<const SfxInt32Item
&>(pPattern
->GetItem(ATTR_ROTATE_VALUE
)).GetValue();
203 pCondSet
->GetItemState(ATTR_ROTATE_MODE
, true, &pCondItem
) == SfxItemState::SET
)
204 eRotMode
= (SvxRotateMode
)static_cast<const SvxRotateModeItem
*>(pCondItem
)->GetValue();
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
;
219 bAsianVertical
= false;
222 const SvxMarginItem
* pMargin
;
224 pCondSet
->GetItemState(ATTR_MARGIN
, true, &pCondItem
) == SfxItemState::SET
)
225 pMargin
= static_cast<const SvxMarginItem
*>(pCondItem
);
227 pMargin
= static_cast<const SvxMarginItem
*>(&pPattern
->GetItem(ATTR_MARGIN
));
228 sal_uInt16 nIndent
= 0;
229 if ( eHorJust
== SVX_HOR_JUSTIFY_LEFT
)
232 pCondSet
->GetItemState(ATTR_INDENT
, true, &pCondItem
) == SfxItemState::SET
)
233 nIndent
= static_cast<const SfxUInt16Item
*>(pCondItem
)->GetValue();
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
;
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
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
;
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
);
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
);
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
);
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
)
310 aSize
= Size( nWidth
, nHeight
);
312 nValue
= bWidth
? aSize
.Width() : aSize
.Height();
318 nValue
+= (long) ( pMargin
->GetLeftMargin() * nPPT
) +
319 (long) ( pMargin
->GetRightMargin() * nPPT
);
321 nValue
+= (long) ( nIndent
* nPPT
);
324 nValue
+= (long) ( pMargin
->GetTopMargin() * nPPT
) +
325 (long) ( pMargin
->GetBottomMargin() * nPPT
);
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() -
339 nDocPixel
= (nDocPixel
* 9) / 10; // for safety
340 if ( aSize
.Width() > nDocPixel
)
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();
360 nCtrl
|= EEControlBits::FORMAT100
;
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
);
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
)
394 double fWidthFactor
= nPPTX
;
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();
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)
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
;
423 aPaper
= pDev
->PixelToLogic( aPaper
, aHMMMode
);
425 pEngine
->SetPaperSize(aPaper
);
427 if (aCell
.meType
== CELLTYPE_EDIT
)
429 pEngine
->SetTextNewDefaults(*aCell
.mpEditText
, pSet
);
435 ScCellFormat::GetString(
436 aCell
, nFormat
, aString
, &pColor
, *pFormatter
, pDocument
, true,
437 rOptions
.bFormula
, ftCheck
);
439 if (!aString
.isEmpty())
440 pEngine
->SetTextNewDefaults(aString
, pSet
);
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
;
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
);
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
);
468 if ( pPattern
->GetRotateDir( pCondSet
) == SC_ROTDIR_RIGHT
)
469 nWidth
+= (long)( pDocument
->GetRowHeight( nRow
,nTab
) *
470 nPPT
* nCosAbs
/ nSinAbs
);
473 nWidth
= (long)( aSize
.Height() / nSinAbs
); //TODO: limit?
474 aSize
= Size( nWidth
, nHeight
);
476 Size aPixSize
= pDev
->LogicToPixel( aSize
, aHMMMode
);
478 nValue
= aPixSize
.Width();
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
;
497 nValue
= pDev
->LogicToPixel(Size( pEngine
->CalcTextWidth(), 0 ),
502 nValue
= pDev
->LogicToPixel(Size( 0, pEngine
->GetTextHeight() ),
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
)
521 nValue
+= (long) ( pMargin
->GetLeftMargin() * nPPT
) +
522 (long) ( pMargin
->GetRightMargin() * nPPT
);
524 nValue
+= (long) ( nIndent
* nPPT
);
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
);
550 // place for Autofilter Button
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();
563 class MaxStrLenFinder
567 OUString maMaxLenStr
;
570 void checkLength(ScRefCellValue
& rCell
)
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
;
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
);
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
);
609 void operator() (size_t /*nRow*/, const ScFormulaCell
* p
)
611 ScRefCellValue
aCell(const_cast<ScFormulaCell
*>(p
));
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.
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
);
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
);
642 if ( pParam
&& pParam
->mbSimpleText
)
643 { // all the same except for number format
644 const ScPatternAttr
* pPattern
= GetPattern( 0 );
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
);
658 if (pParam
->mnMaxTextRow
>= 0)
660 ScRefCellValue aCell
= GetCellValue(pParam
->mnMaxTextRow
);
661 ScCellFormat::GetString(
662 aCell
, nFormat
, aLongStr
, &pColor
, *pFormatter
, pDocument
, true, false, ftCheck
);
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
);
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
;
696 while (nRow
<= nRow2
)
698 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(itPos
, nRow
);
700 if (itPos
->type
== sc::element_type_empty
)
703 nRow
+= itPos
->size
- aPos
.second
;
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
);
721 if (nThis
> nWidth
|| !bFound
)
735 sal_uInt16 nTwips
= (sal_uInt16
) (nWidth
/ nPPTX
);
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();
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
;
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
);
787 // with conditional formatting, always consider the individual cells
789 const ScPatternAttr
* pPattern
= aIter
.Next(nStart
,nEnd
);
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
802 bool bStdAllowed
= (pPattern
->GetCellOrientation() == SVX_ORIENTATION_STANDARD
);
803 bool bStdOnly
= false;
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
);
812 // conditional formatting: loop all cells
814 !static_cast<const ScCondFormatItem
&>(pPattern
->GetItem(
815 ATTR_CONDITIONAL
)).GetCondFormatData().empty())
820 // rotated text: loop all cells
821 if ( bStdOnly
&& static_cast<const SfxInt32Item
&>(pPattern
->
822 GetItem(ATTR_ROTATE_VALUE
)).GetValue() )
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
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
)
845 nEnd
= nEditPos
; // calculate single
846 bStdAllowed
= false; // will be computed in any case per cell
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
);
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
);
873 nDefHeight
= nLatHeight
= lcl_GetAttribHeight( *pPattern
, ATTR_FONT_HEIGHT
);
875 // if everything below is already larger, the loop doesn't have to
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
;
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
)
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
;
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
);
966 pPattern
= aIter
.Next(nStart
,nEnd
);
970 bool ScColumn::GetNextSpellingCell(SCROW
& nRow
, bool bInSel
, const ScMarkData
& rData
) const
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
)) )
986 nRow
= rData
.GetNextMarked(nCol
, nRow
, false);
994 it
= maCells
.position(it
, nRow
).first
;
996 if ( (eType
== sc::element_type_string
|| eType
== sc::element_type_edittext
) &&
997 !(HasAttrib( nRow
, nRow
, HASATTR_PROTECTED
) &&
998 pDocument
->IsTabProtected(nTab
)) )
1004 else if (GetNextDataPos(nRow
))
1006 it
= maCells
.position(it
, nRow
).first
;
1008 if ( (eType
== sc::element_type_string
|| eType
== sc::element_type_edittext
) &&
1009 !(HasAttrib( nRow
, nRow
, HASATTR_PROTECTED
) &&
1010 pDocument
->IsTabProtected(nTab
)) )
1028 sc::CellStoreType
& mrCells
;
1036 StrEntry(SCROW nRow
, const OUString
& rStr
) : mnRow(nRow
), maStr(rStr
) {}
1039 std::vector
<StrEntry
> maStrEntries
;
1042 StrEntries(sc::CellStoreType
& rCells
, ScDocument
* pDoc
) : mrCells(rCells
), mpDoc(pDoc
) {}
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
;
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
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
);
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.
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
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
;
1159 CellCounter() : mnCount(0) {}
1162 const sc::CellStoreType::value_type
& node
, size_t /*nOffset*/, size_t nDataSize
)
1164 if (node
.type
== sc::element_type_empty
)
1167 mnCount
+= nDataSize
;
1170 size_t getCount() const { return mnCount
; }
1175 SCSIZE
ScColumn::VisibleCount( SCROW nStartRow
, SCROW nEndRow
) const
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.
1190 return it
->type
!= sc::element_type_empty
;
1193 bool ScColumn::IsEmptyAttr() const
1196 return pAttrArray
->IsEmpty();
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.
1214 if (it
->type
!= sc::element_type_empty
)
1215 // Non-empty cell at the start position.
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.
1231 if (it
->type
!= sc::element_type_empty
)
1232 // Non-empty cell at the start position.
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.
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.
1255 // length of this empty block minus the offset.
1256 size_t nThisLen
= it
->size
- aPos
.second
;
1257 return std::min(nThisLen
, nLength
);
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.
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
);
1282 SCROW
ScColumn::GetFirstDataPos() const
1287 sc::CellStoreType::const_iterator it
= maCells
.begin();
1288 if (it
->type
!= sc::element_type_empty
)
1294 SCROW
ScColumn::GetLastDataPos() const
1299 sc::CellStoreType::const_reverse_iterator it
= maCells
.rbegin();
1300 if (it
->type
!= sc::element_type_empty
)
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
)
1312 if (aPos
.first
== maCells
.begin())
1313 // This is the first block, and is empty.
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())
1326 if (it
->type
== sc::element_type_empty
)
1328 if (it
== maCells
.begin())
1329 // No more previous non-empty cell.
1332 rRow
-= aPos
.second
+ 1; // Last row position of the previous block.
1336 // This block is not empty.
1339 // There are preceding cells in this block. Simply move back one cell.
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.
1349 --rRow
; // Move to the last cell of the previous block.
1351 if (it
->type
== sc::element_type_empty
)
1353 // This block is empty.
1354 if (it
== maCells
.begin())
1355 // No more preceding blocks.
1358 // Skip the whole empty block segment.
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())
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
;
1377 if (it
== maCells
.end())
1378 // No more next block.
1381 // Next block exists, and is non-empty.
1385 if (aPos
.second
< it
->size
- 1)
1387 // There are still cells following the current position.
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.
1395 if (it
== maCells
.end())
1396 // No more next block.
1399 if (it
->type
== sc::element_type_empty
)
1401 // Next block is empty. Move to the next block.
1404 if (it
== maCells
.end())
1411 SCROW
ScColumn::FindNextVisibleRow(SCROW nRow
, bool bForward
) const
1417 bool bHidden
= pDocument
->RowHidden(nRow
, nTab
, NULL
, &nEndRow
);
1419 return std::min
<SCROW
>(MAXROW
, nEndRow
+ 1);
1426 SCROW nStartRow
= MAXROW
;
1427 bool bHidden
= pDocument
->RowHidden(nRow
, nTab
, &nStartRow
, NULL
);
1429 return std::max
<SCROW
>(0, nStartRow
- 1);
1435 SCROW
ScColumn::FindNextVisibleRowWithContent(
1436 sc::CellStoreType::const_iterator
& itPos
, SCROW nRow
, bool bForward
) const
1444 bool bHidden
= pDocument
->RowHidden(nRow
, nTab
, NULL
, &nEndRow
);
1452 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(itPos
, nRow
);
1454 if (itPos
== maCells
.end())
1458 if (itPos
->type
!= sc::element_type_empty
)
1461 // Move to the last cell of the current empty block.
1462 nRow
+= itPos
->size
- aPos
.second
- 1;
1464 while (nRow
< MAXROW
);
1472 SCROW nStartRow
= MAXROW
;
1473 bool bHidden
= pDocument
->RowHidden(nRow
, nTab
, &nStartRow
, NULL
);
1476 nRow
= nStartRow
- 1;
1481 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(itPos
, nRow
);
1483 if (itPos
== maCells
.end())
1487 if (itPos
->type
!= sc::element_type_empty
)
1490 // Move to the first cell of the current empty block.
1491 nRow
-= aPos
.second
;
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
;
1512 if (maCellTextAttrs
.size() != MAXROWCOUNT
)
1514 cout
<< "ScColumn::CellStorageModified: Size of the cell text attribute array is incorrect." << endl
;
1519 if (maBroadcasters
.size() != MAXROWCOUNT
)
1521 cout
<< "ScColumn::CellStorageModified: Size of the broadcaster array is incorrect." << endl
;
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
)
1534 while (itAttr
!= maCellTextAttrs
.end() && itAttr
->type
!= sc::element_type_empty
)
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
);
1550 // Move to the next empty blocks.
1552 while (itCell
!= maCells
.end() && itCell
->type
!= sc::element_type_empty
)
1556 while (itAttr
!= maCellTextAttrs
.end() && itAttr
->type
!= sc::element_type_empty
)
1562 #if DEBUG_COLUMN_STORAGE
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
)
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
;
1586 if (rCell
.GetSharedTopRow() != rCell
.aPos
.Row())
1588 cout
<< " + row " << rCell
.aPos
.Row() << " shared with top row " << rCell
.GetSharedTopRow() << " with length " << rCell
.GetSharedLength() << endl
;
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
;
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
)
1624 nOffsetInBlock
= nRowPos
- nBlockStart
;
1629 if (itBlk
== itBlkEnd
)
1630 // Specified range not found. Bail out.
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
;
1643 if (nBlockStart
<= nRowPos
&& nRowPos
< nBlockEnd
)
1644 // This block contains the end row.
1645 rDestCol
.maCellTextAttrs
.set_empty(nBlockStart
+ nOffsetInBlock
, nRowPos
);
1647 rDestCol
.maCellTextAttrs
.set_empty(nBlockStart
+ nOffsetInBlock
, nBlockEnd
-1);
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
);
1668 rDestCol
.maCellTextAttrs
.set(nBlockStart
+ nOffsetInBlock
, itData
, itDataEnd
);
1674 class CopyCellNotesHandler
1676 ScColumn
& mrDestCol
;
1677 sc::CellNoteStoreType
& mrDestNotes
;
1678 sc::CellNoteStoreType::iterator miPos
;
1683 SCROW mnDestOffset
; /// Add this to the source row position to get the destination row.
1684 bool mbCloneCaption
;
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.
1716 ScDrawLayer
*pDrawLayer
= rDestCol
.GetDoc().GetDrawLayer();
1717 bool bWasLocked
= bool();
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
);
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
)
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.
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
)
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
);
1820 class ForgetCellNoteCaptionsHandler
1824 ForgetCellNoteCaptionsHandler() {}
1826 void operator() ( size_t /*nRow*/, ScPostIt
* p
)
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.
1856 SCROW
ScColumn::GetCellNotesMaxRow() const
1858 // hypothesis : the column has cell notes (should be checked before)
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;
1868 SCROW
ScColumn::GetCellNotesMinRow() const
1870 // hypothesis : the column has cell notes (should be checked before)
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
)
1879 minRow
= it
->position
;
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
)
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
;
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
)
1933 sc::CellTextAttr
& rVal
= *it
;
1934 if (UpdateScriptType(rVal
, nRow
, itrCells
))
1936 nScriptType
|= rVal
.mnScriptType
;
1941 // Skip this whole block.
1942 nRow
+= itPos
->size
- aRet
.second
;
1945 while (nRow
<= nRow2
)
1948 if (itPos
== maCellTextAttrs
.end())
1951 if (itPos
->type
!= sc::element_type_celltextattr
)
1953 // Skip this whole block.
1954 nRow
+= itPos
->size
;
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
)
1965 sc::CellTextAttr
& rVal
= *it
;
1966 if (UpdateScriptType(rVal
, nRow
, itrCells
))
1969 nScriptType
|= rVal
.mnScriptType
;
1974 CellStorageModified();
1979 void ScColumn::SetScriptType( SCROW nRow
, SvtScriptType nType
)
1981 if (!ValidRow(nRow
))
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.
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();
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
);
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
:
2041 // Return a value of 0.0 in all the other cases.
2042 return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
2048 class ToMatrixHandler
2054 svl::SharedStringPool
& mrStrPool
;
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
);
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
)
2093 ToMatrixHandler
aFunc(rMat
, nMatCol
, nRow1
, pDocument
);
2094 sc::ParseAllNonEmpty(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
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
)
2115 rMat
.PutEmptyResultVector(mnEmpValCount
, nCol
, mnEmpValStart
);
2118 else if (!maNumVals
.empty())
2120 const double* p
= &maNumVals
[0];
2121 rMat
.PutDouble(p
, maNumVals
.size(), nCol
, mnNumValStart
);
2124 else if (!maStrVals
.empty())
2126 const svl::SharedString
* p
= &maStrVals
[0];
2127 rMat
.PutString(p
, maStrVals
.size(), nCol
, mnStrValStart
);
2134 mnEmpValStart
= mnNumValStart
= mnStrValStart
= 0;
2141 class FillMatrixHandler
2150 svl::SharedStringPool
& mrPool
;
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
;
2162 case sc::element_type_numeric
:
2164 const double* p
= &sc::numeric_block::at(*node
.data
, nOffset
);
2165 mrMat
.PutDouble(p
, nDataSize
, mnMatCol
, nMatRow
);
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
);
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
);
2192 case sc::element_type_formula
:
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
;
2214 // First empty result.
2215 aBucket
.flush(mrMat
, mnMatCol
);
2216 aBucket
.mnEmpValStart
= nThisRow
- mnTopRow
;
2217 ++aBucket
.mnEmpValCount
;
2224 if (rCell
.GetErrorOrValue(nErr
, fVal
))
2226 ScAddress
aAdr(mnCol
, nThisRow
, mnTab
);
2229 fVal
= CreateDoubleError(nErr
);
2231 if (!aBucket
.maNumVals
.empty() && nThisRow
== nPrevRow
+ 1)
2233 // Secondary numbers.
2234 aBucket
.maNumVals
.push_back(fVal
);
2239 aBucket
.flush(mrMat
, mnMatCol
);
2240 aBucket
.mnNumValStart
= nThisRow
- mnTopRow
;
2241 aBucket
.maNumVals
.push_back(fVal
);
2246 svl::SharedString aStr
= rCell
.GetString();
2247 if (!aBucket
.maStrVals
.empty() && nThisRow
== nPrevRow
+ 1)
2249 // Secondary strings.
2250 aBucket
.maStrVals
.push_back(aStr
);
2255 aBucket
.flush(mrMat
, mnMatCol
);
2256 aBucket
.mnStrValStart
= nThisRow
- mnTopRow
;
2257 aBucket
.maStrVals
.push_back(aStr
);
2261 aBucket
.flush(mrMat
, mnMatCol
);
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
);
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
;
2295 std::advance(rDataEnd
, rLenRemain
);
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
;
2307 rtl::math::setNan(&fNan
);
2309 for (sc::CellStoreType::iterator it
= _it
; it
!= itEnd
; ++it
)
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();
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();
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
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.
2369 if (aRes
.meType
== sc::FormulaResultValue::String
)
2371 rCxt
.ensureStrArray(rColArray
, nArrayLen
);
2372 (*rColArray
.mpStrArray
)[nPos
] = aRes
.maString
.getDataIgnoreCase();
2376 rCxt
.ensureNumArray(rColArray
, nArrayLen
);
2377 (*rColArray
.mpNumArray
)[nPos
] = aRes
.mfValue
;
2381 if (bTempDisableProgress
)
2382 pProgress
->Enable();
2385 case sc::element_type_empty
:
2387 if (nLenRemain
> it
->size
)
2390 nLenRemain
-= it
->size
;
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
;
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();
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();
2456 sc::FormulaGroupContext::ColArray
*
2457 copyFirstFormulaBlock(
2458 sc::FormulaGroupContext
& rCxt
, const sc::CellStoreType::iterator
& itBlk
, size_t nArrayLen
,
2459 SCTAB nTab
, SCCOL nCol
)
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
;
2473 std::advance(itEnd
, nLen
);
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.
2490 if (aRes
.meType
== sc::FormulaResultValue::Value
)
2494 rCxt
.maNumArrays
.push_back(
2495 new sc::FormulaGroupContext::NumArrayType(nArrayLen
, fNan
));
2496 pNumArray
= &rCxt
.maNumArrays
.back();
2499 (*pNumArray
)[nPos
] = aRes
.mfValue
;
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.
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
)
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);
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
);
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
);
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
;
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
]);
2596 return formula::VectorRefArray(&(*pColArray
->mpNumArray
)[nRow1
]);
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
);
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
;
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
]);
2627 return formula::VectorRefArray(&(*pColArray
->mpStrArray
)[nRow1
]);
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
2636 pColArray
= copyFirstFormulaBlock(rCxt
, itBlk
, nRow2
+1, nTab
, nCol
);
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
);
2653 // Failed to insert a new cached column array.
2654 return formula::VectorRefArray(formula::VectorRefArray::Invalid
);
2656 size_t nPos
= itBlk
->size
;
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
);
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
);
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
;
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
]);
2693 return formula::VectorRefArray(&(*pColArray
->mpNumArray
)[nRow1
]);
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.
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.
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
);
2725 rCell
.SetResultError(nErr
);
2727 rCell
.SetResultDouble(*pResults
);
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.
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.
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());
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
))
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())
2780 if (it
->type
!= sc::element_type_formula
)
2782 // Not a formula cell.
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())
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
);
2817 // Current cell is not empty.
2818 SCROW nNextRow
= FindNextVisibleRow(rRow
, bDown
);
2819 aPos
= maCells
.position(it
, nNextRow
);
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
);
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
)
2836 aPos
= maCells
.position(it
, nNextRow
);
2838 if (it
->type
!= sc::element_type_empty
)
2839 nLastRow
= nNextRow
;
2841 while (it
->type
!= sc::element_type_empty
);
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
);
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
);
2864 return !pAttrArray
&& !rCol
.pAttrArray
;
2867 bool ScColumn::GetFirstVisibleAttr( SCROW
& rFirstRow
) const
2870 return pAttrArray
->GetFirstVisibleAttr( rFirstRow
);
2875 bool ScColumn::GetLastVisibleAttr( SCROW
& rLastRow
, bool bFullFormattedArea
) const
2879 // row of last cell is needed
2880 SCROW nLastData
= GetLastDataPos(); // always including notes, 0 if none
2882 return pAttrArray
->GetLastVisibleAttr( rLastRow
, nLastData
, bFullFormattedArea
);
2888 bool ScColumn::HasVisibleAttrIn( SCROW nStartRow
, SCROW nEndRow
) const
2891 return pAttrArray
->HasVisibleAttrIn( nStartRow
, nEndRow
);
2898 class FindUsedRowsHandler
2900 typedef mdds::flat_segment_tree
<SCROW
,bool> UsedRowsType
;
2901 UsedRowsType
& mrUsed
;
2902 UsedRowsType::const_iterator miUsed
;
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
)
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
);
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
);
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.
2949 #if DEBUG_COLUMN_STORAGE
2950 cout
<< "ScColumn::StartListening: wrong block type encountered in the broadcaster storage." << endl
;
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
);
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
))
2984 sc::ColumnBlockPosition
* p
= rCxt
.getBlockPosition(nTab
, nCol
);
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
);
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
)
3006 SvtBroadcaster
* pBC
= sc::broadcaster_block::at(*it
->data
, aPos
.second
);
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
);
3017 class CompileDBFormulaHandler
3019 sc::CompileFormulaContext
& mrCxt
;
3022 CompileDBFormulaHandler( sc::CompileFormulaContext
& rCxt
) :
3025 void operator() (size_t, ScFormulaCell
* p
)
3027 p
->CompileDBFormula(mrCxt
);
3031 struct CompileColRowNameFormulaHandler
3033 sc::CompileFormulaContext
& mrCxt
;
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();
3061 class UpdateSubTotalHandler
3063 ScFunctionData
& mrData
;
3065 void update(double fVal
, bool bVal
)
3070 switch (mrData
.eFunc
)
3072 case SUBTOTAL_FUNC_SUM
:
3073 case SUBTOTAL_FUNC_AVE
:
3079 if (!SubTotal::SafePlus(mrData
.nVal
, fVal
))
3080 mrData
.bError
= true;
3083 case SUBTOTAL_FUNC_CNT
: // only the value
3091 case SUBTOTAL_FUNC_CNT2
: // everything
3094 case SUBTOTAL_FUNC_MAX
:
3099 if (++mrData
.nCount
== 1 || fVal
> mrData
.nVal
)
3103 case SUBTOTAL_FUNC_MIN
:
3108 if (++mrData
.nCount
== 1 || fVal
< mrData
.nVal
)
3114 // added to avoid warnings
3120 UpdateSubTotalHandler(ScFunctionData
& rData
) : mrData(rData
) {}
3122 void operator() (size_t /*nRow*/, double fVal
)
3127 void operator() (size_t /*nRow*/, const svl::SharedString
&)
3132 void operator() (size_t /*nRow*/, const EditTextObject
*)
3137 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
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();
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
;
3173 while (nRow
<= MAXROW
)
3175 if (!rHiddenRows
.getRangeData(nRow
, aRange
))
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;
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
);
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
);
3227 class WeightedCounter
3231 WeightedCounter() : mnCount(0) {}
3233 void operator() (const sc::CellStoreType::value_type
& node
)
3237 case sc::element_type_numeric
:
3238 case sc::element_type_string
:
3239 mnCount
+= node
.size
;
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();
3253 case sc::element_type_edittext
:
3254 // each edit-text cell is worth 50.
3255 mnCount
+= node
.size
* 50;
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();
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
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: */