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 .
22 #include "xmlcelli.hxx"
23 #include "xmlimprt.hxx"
24 #include "xmlannoi.hxx"
26 #include <cellvalue.hxx>
27 #include <document.hxx>
31 #include <sheetdata.hxx>
32 #include <cellform.hxx>
33 #include <validat.hxx>
34 #include <patattr.hxx>
35 #include <scitems.hxx>
36 #include <docpool.hxx>
38 #include "XMLTableShapeImportHelper.hxx"
39 #include "XMLStylesImportHelper.hxx"
40 #include "celltextparacontext.hxx"
41 #include "XMLCellRangeSourceContext.hxx"
43 #include <arealink.hxx>
44 #include <sfx2/linkmgr.hxx>
45 #include <scerrors.hxx>
46 #include <editutil.hxx>
47 #include <formulacell.hxx>
48 #include "editattributemap.hxx"
49 #include <tokenarray.hxx>
50 #include <scmatrix.hxx>
51 #include <stringutil.hxx>
52 #include <documentimport.hxx>
53 #include <externalrefmgr.hxx>
55 #include <xmloff/maptype.hxx>
56 #include <xmloff/xmltoken.hxx>
57 #include <xmloff/xmlprmap.hxx>
58 #include <xmloff/xmluconv.hxx>
59 #include <xmloff/families.hxx>
60 #include <xmloff/xmlnamespace.hxx>
61 #include <xmloff/prstylei.hxx>
62 #include <xmloff/xmlimppr.hxx>
63 #include <svl/numformat.hxx>
64 #include <svl/zforlist.hxx>
65 #include <svx/svdocapt.hxx>
66 #include <editeng/eeitem.hxx>
67 #include <editeng/outlobj.hxx>
68 #include <editeng/wghtitem.hxx>
69 #include <editeng/colritem.hxx>
70 #include <editeng/fhgtitem.hxx>
71 #include <editeng/postitem.hxx>
72 #include <editeng/flditem.hxx>
73 #include <editeng/fontitem.hxx>
74 #include <editeng/udlnitem.hxx>
75 #include <editeng/wrlmitem.hxx>
76 #include <editeng/crossedoutitem.hxx>
77 #include <editeng/charreliefitem.hxx>
78 #include <editeng/charscaleitem.hxx>
79 #include <editeng/contouritem.hxx>
80 #include <editeng/shdditem.hxx>
81 #include <editeng/kernitem.hxx>
82 #include <editeng/autokernitem.hxx>
83 #include <editeng/escapementitem.hxx>
84 #include <editeng/emphasismarkitem.hxx>
85 #include <editeng/langitem.hxx>
86 #include <svl/sharedstringpool.hxx>
87 #include <sax/tools/converter.hxx>
88 #include <sax/fastattribs.hxx>
90 #include <com/sun/star/util/NumberFormat.hpp>
92 #include <com/sun/star/sheet/ValidationType.hpp>
93 #include <com/sun/star/sheet/ValidationAlertStyle.hpp>
95 #include <rtl/ustrbuf.hxx>
96 #include <osl/diagnose.h>
97 #include <sal/log.hxx>
98 #include <i18nlangtag/lang.h>
100 #include <comphelper/servicehelper.hxx>
101 #include <comphelper/lok.hxx>
103 using namespace com::sun::star
;
104 using namespace xmloff::token
;
106 ScXMLTableRowCellContext::ParaFormat::ParaFormat(const ScEditEngineDefaulter
& rEditEngine
) :
107 maItemSet(rEditEngine
.GetEmptyItemSet()) {}
109 ScXMLTableRowCellContext::Field::Field(std::unique_ptr
<SvxFieldData
> pData
) : mpData(std::move(pData
)) {}
111 ScXMLTableRowCellContext::Field::~Field()
115 ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport
& rImport
,
116 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
117 const bool bTempIsCovered
,
118 const sal_Int32 nTempRepeatedRows
) :
119 ScXMLImportContext( rImport
),
120 mpEditEngine(GetScImport().GetEditEngine()),
122 fValue(std::numeric_limits
<double>::quiet_NaN()),
125 nRepeatedRows(nTempRepeatedRows
),
130 eGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT
),
131 nCellType(util::NumberFormat::TEXT
),
134 bIsCovered(bTempIsCovered
),
136 mbNewValueType(false),
138 bSolarMutexLocked(false),
139 bFormulaTextResult(false),
140 mbPossibleErrorCell(false),
141 mbCheckWithCompilerForError(false),
142 mbEditEngineHasText(false),
143 mbHasFormatRuns(false),
145 mbPossibleEmptyDisplay(false)
147 rXMLImport
.GetTables().AddColumn(bTempIsCovered
);
149 std::optional
<OUString
> xStyleName
;
150 std::optional
<OUString
> xCurrencySymbol
;
151 if ( rAttrList
.is() )
153 for (auto &it
: *rAttrList
)
155 switch ( it
.getToken() )
157 case XML_ELEMENT( TABLE
, XML_STYLE_NAME
):
158 xStyleName
= it
.toString();
161 case XML_ELEMENT( TABLE
, XML_CONTENT_VALIDATION_NAME
):
162 OSL_ENSURE(!maContentValidationName
, "here should be only one Validation Name");
164 maContentValidationName
= it
.toString();
166 case XML_ELEMENT( TABLE
, XML_NUMBER_ROWS_SPANNED
):
168 nMergedRows
= static_cast<SCROW
>(it
.toInt32());
170 case XML_ELEMENT( TABLE
, XML_NUMBER_COLUMNS_SPANNED
):
172 nMergedCols
= static_cast<SCCOL
>(it
.toInt32());
174 case XML_ELEMENT( TABLE
, XML_NUMBER_MATRIX_COLUMNS_SPANNED
):
176 nMatrixCols
= static_cast<SCCOL
>(it
.toInt32());
178 case XML_ELEMENT( TABLE
, XML_NUMBER_MATRIX_ROWS_SPANNED
):
180 nMatrixRows
= static_cast<SCROW
>(it
.toInt32());
182 case XML_ELEMENT( TABLE
, XML_NUMBER_COLUMNS_REPEATED
):
184 if (ScDocument
* pDoc
= rImport
.GetDocument())
186 nColsRepeated
= static_cast<SCCOL
>(
187 std::min
<sal_Int32
>( pDoc
->GetSheetLimits().GetMaxColCount(),
188 std::max( it
.toInt32(), static_cast<sal_Int32
>(1) ) ));
192 case XML_ELEMENT( OFFICE
, XML_VALUE_TYPE
):
193 nCellType
= ScXMLImport::GetCellType(it
.toCString(), it
.getLength());
196 case XML_ELEMENT( CALC_EXT
, XML_VALUE_TYPE
):
197 if(it
.isString( "error" ) )
200 nCellType
= ScXMLImport::GetCellType(it
.toCString(), it
.getLength());
202 mbNewValueType
= true;
204 case XML_ELEMENT( OFFICE
, XML_VALUE
):
208 fValue
= it
.toDouble();
211 //if office:value="0", let's get the text:p in case this is
212 //a special case in HasSpecialCaseFormulaText(). If it
213 //turns out not to be a special case, we'll use the 0 value.
215 bFormulaTextResult
= true;
219 case XML_ELEMENT( OFFICE
, XML_DATE_VALUE
):
221 if (!it
.isEmpty() && rXMLImport
.SetNullDateOnUnitConverter())
223 rXMLImport
.GetMM100UnitConverter().convertDateTime(fValue
, it
.toView());
228 case XML_ELEMENT( OFFICE
, XML_TIME_VALUE
):
232 ::sax::Converter::convertDuration(fValue
, it
.toView());
237 case XML_ELEMENT( OFFICE
, XML_STRING_VALUE
):
241 OSL_ENSURE(!maStringValue
, "here should be only one string value");
242 maStringValue
= it
.toString();
247 case XML_ELEMENT( OFFICE
, XML_BOOLEAN_VALUE
):
251 if ( IsXMLToken( it
, XML_TRUE
) )
253 else if ( IsXMLToken( it
, XML_FALSE
) )
256 fValue
= it
.toDouble();
261 case XML_ELEMENT( TABLE
, XML_FORMULA
):
265 OSL_ENSURE(!maFormula
, "here should be only one formula");
266 OUString aFormula
, aFormulaNmsp
;
267 rXMLImport
.ExtractFormulaNamespaceGrammar( aFormula
, aFormulaNmsp
, eGrammar
, it
.toString() );
268 maFormula
= FormulaWithNamespace(aFormula
, aFormulaNmsp
);
272 case XML_ELEMENT( OFFICE
, XML_CURRENCY
):
273 xCurrencySymbol
= it
.toString();
283 if (nCellType
== util::NumberFormat::TEXT
)
284 bFormulaTextResult
= true;
285 if(nCellType
== util::NumberFormat::DATETIME
)
286 nCellType
= util::NumberFormat::UNDEFINED
;
287 //if bIsEmpty is true at this point, then there is no office value.
288 //we must get the text:p (even if it is empty) in case this a special
289 //case in HasSpecialCaseFormulaText().
291 bFormulaTextResult
= true;
293 rXMLImport
.GetStylesImportHelper()->SetAttributes(std::move(xStyleName
), std::move(xCurrencySymbol
), nCellType
);
296 ScXMLTableRowCellContext::~ScXMLTableRowCellContext()
300 void ScXMLTableRowCellContext::LockSolarMutex()
302 if (!bSolarMutexLocked
)
304 GetScImport().LockSolarMutex();
305 bSolarMutexLocked
= true;
311 bool cellExists( const ScDocument
& rDoc
, const ScAddress
& rCellPos
)
313 return( rCellPos
.Col() >= 0 && rCellPos
.Row() >= 0 &&
314 rCellPos
.Col() <= rDoc
.MaxCol() && rCellPos
.Row() <= rDoc
.MaxRow() );
319 void ScXMLTableRowCellContext::PushParagraphSpan(std::u16string_view rSpan
, const OUString
& rStyleName
)
321 sal_Int32 nBegin
= maParagraph
.getLength();
322 sal_Int32 nEnd
= nBegin
+ rSpan
.size();
323 maParagraph
.append(rSpan
);
325 PushFormat(nBegin
, nEnd
, rStyleName
);
328 void ScXMLTableRowCellContext::PushParagraphField(std::unique_ptr
<SvxFieldData
> pData
, const OUString
& rStyleName
)
330 mbHasFormatRuns
= true;
331 maFields
.push_back(std::make_unique
<Field
>(std::move(pData
)));
332 Field
& rField
= *maFields
.back();
334 sal_Int32 nPos
= maParagraph
.getLength();
335 maParagraph
.append('\1'); // Placeholder text for inserted field item.
336 rField
.maSelection
.start
.nPara
= rField
.maSelection
.end
.nPara
= mnCurParagraph
;
337 rField
.maSelection
.start
.nIndex
= nPos
;
338 rField
.maSelection
.end
.nIndex
= nPos
+1;
340 PushFormat(nPos
, nPos
+1, rStyleName
);
343 void ScXMLTableRowCellContext::PushFormat(sal_Int32 nBegin
, sal_Int32 nEnd
, const OUString
& rStyleName
)
345 if (rStyleName
.isEmpty())
348 // Get the style information from xmloff.
349 rtl::Reference
<XMLPropertySetMapper
> xMapper
= GetImport().GetTextImport()->GetTextImportPropertySetMapper()->getPropertySetMapper();
351 // We can't do anything without the mapper.
354 sal_Int32 nEntryCount
= xMapper
->GetEntryCount();
356 SvXMLStylesContext
* pAutoStyles
= GetImport().GetAutoStyles();
360 // Style name for text span corresponds with the name of an automatic style.
361 const XMLPropStyleContext
* pStyle
= dynamic_cast<const XMLPropStyleContext
*>(
362 pAutoStyles
->FindStyleChildContext(XmlStyleFamily::TEXT_TEXT
, rStyleName
));
365 // No style by that name found.
368 const std::vector
<XMLPropertyState
>& rProps
= pStyle
->GetProperties();
372 const ScXMLEditAttributeMap
& rEditAttrMap
= GetScImport().GetEditAttributeMap();
374 mbHasFormatRuns
= true;
375 maFormats
.push_back(std::make_unique
<ParaFormat
>(*mpEditEngine
));
376 ParaFormat
& rFmt
= *maFormats
.back();
377 rFmt
.maSelection
.start
.nPara
= rFmt
.maSelection
.end
.nPara
= mnCurParagraph
;
378 rFmt
.maSelection
.start
.nIndex
= nBegin
;
379 rFmt
.maSelection
.end
.nIndex
= nEnd
;
381 // Store the used text styles for export.
382 ScSheetSaveData
* pSheetData
= rXMLImport
.GetScModel()->GetSheetSaveData();
383 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
384 pSheetData
->AddTextStyle(rStyleName
, aCellPos
, rFmt
.maSelection
);
386 std::unique_ptr
<SfxPoolItem
> pPoolItem
;
387 sal_uInt16 nLastItemID
= EE_CHAR_END
+ 1;
389 for (const auto& rProp
: rProps
)
391 if (rProp
.mnIndex
== -1 || rProp
.mnIndex
>= nEntryCount
)
394 const OUString
& rName
= xMapper
->GetEntryAPIName(rProp
.mnIndex
);
395 const ScXMLEditAttributeMap::Entry
* pEntry
= rEditAttrMap
.getEntryByAPIName(rName
);
399 if (nLastItemID
!= pEntry
->mnItemID
&& pPoolItem
)
401 // Flush the last item when the item ID changes.
402 rFmt
.maItemSet
.Put(std::move(pPoolItem
));
405 switch (pEntry
->mnItemID
)
407 case EE_CHAR_FONTINFO
:
408 case EE_CHAR_FONTINFO_CJK
:
409 case EE_CHAR_FONTINFO_CTL
:
411 // Font properties need to be consolidated into a single item.
413 pPoolItem
.reset(new SvxFontItem(pEntry
->mnItemID
));
415 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
419 case EE_CHAR_WEIGHT_CJK
:
420 case EE_CHAR_WEIGHT_CTL
:
423 pPoolItem
.reset(new SvxWeightItem(WEIGHT_NORMAL
, pEntry
->mnItemID
));
425 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
428 case EE_CHAR_FONTHEIGHT
:
429 case EE_CHAR_FONTHEIGHT_CJK
:
430 case EE_CHAR_FONTHEIGHT_CTL
:
433 pPoolItem
.reset(new SvxFontHeightItem(240, 100, pEntry
->mnItemID
));
435 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
439 case EE_CHAR_ITALIC_CJK
:
440 case EE_CHAR_ITALIC_CTL
:
443 pPoolItem
.reset(new SvxPostureItem(ITALIC_NONE
, pEntry
->mnItemID
));
445 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
448 case EE_CHAR_UNDERLINE
:
451 pPoolItem
.reset(new SvxUnderlineItem(LINESTYLE_NONE
, pEntry
->mnItemID
));
453 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
456 case EE_CHAR_OVERLINE
:
459 pPoolItem
.reset(new SvxOverlineItem(LINESTYLE_NONE
, pEntry
->mnItemID
));
461 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
467 pPoolItem
.reset(new SvxColorItem(pEntry
->mnItemID
));
469 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
475 pPoolItem
.reset(new SvxWordLineModeItem(false, pEntry
->mnItemID
));
477 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
480 case EE_CHAR_STRIKEOUT
:
483 pPoolItem
.reset(new SvxCrossedOutItem(STRIKEOUT_NONE
, pEntry
->mnItemID
));
485 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
491 pPoolItem
.reset(new SvxCharReliefItem(FontRelief::NONE
, pEntry
->mnItemID
));
493 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
496 case EE_CHAR_OUTLINE
:
499 pPoolItem
.reset(new SvxContourItem(false, pEntry
->mnItemID
));
501 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
507 pPoolItem
.reset(new SvxShadowedItem(false, pEntry
->mnItemID
));
509 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
512 case EE_CHAR_KERNING
:
515 pPoolItem
.reset(new SvxKerningItem(0, pEntry
->mnItemID
));
517 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
520 case EE_CHAR_PAIRKERNING
:
523 pPoolItem
.reset(new SvxAutoKernItem(false, pEntry
->mnItemID
));
525 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
528 case EE_CHAR_FONTWIDTH
:
531 pPoolItem
.reset(new SvxCharScaleWidthItem(100, TypedWhichId
<SvxCharScaleWidthItem
>(pEntry
->mnItemID
)));
533 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
536 case EE_CHAR_ESCAPEMENT
:
539 pPoolItem
.reset(new SvxEscapementItem(pEntry
->mnItemID
));
541 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
544 case EE_CHAR_EMPHASISMARK
:
547 pPoolItem
.reset(new SvxEmphasisMarkItem(FontEmphasisMark::NONE
, TypedWhichId
<SvxEmphasisMarkItem
>(pEntry
->mnItemID
)));
549 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
552 case EE_CHAR_LANGUAGE
:
553 case EE_CHAR_LANGUAGE_CJK
:
554 case EE_CHAR_LANGUAGE_CTL
:
557 pPoolItem
.reset(new SvxLanguageItem(LANGUAGE_DONTKNOW
, pEntry
->mnItemID
));
559 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
566 nLastItemID
= pEntry
->mnItemID
;
570 rFmt
.maItemSet
.Put(std::move(pPoolItem
));
573 OUString
ScXMLTableRowCellContext::GetFirstParagraph() const
575 if (!maFirstParagraph
)
576 return mpEditEngine
->GetText(0);
578 return *maFirstParagraph
;
581 void ScXMLTableRowCellContext::PushParagraphFieldDate(const OUString
& rStyleName
)
583 PushParagraphField(std::make_unique
<SvxDateField
>(), rStyleName
);
586 void ScXMLTableRowCellContext::PushParagraphFieldSheetName(const OUString
& rStyleName
)
588 SCTAB nTab
= GetScImport().GetTables().GetCurrentCellPos().Tab();
589 PushParagraphField(std::make_unique
<SvxTableField
>(nTab
), rStyleName
);
592 void ScXMLTableRowCellContext::PushParagraphFieldDocTitle(const OUString
& rStyleName
)
594 PushParagraphField(std::make_unique
<SvxFileField
>(), rStyleName
);
597 void ScXMLTableRowCellContext::PushParagraphFieldURL(
598 const OUString
& rURL
, const OUString
& rRep
, const OUString
& rStyleName
, const OUString
& rTargetFrame
)
600 OUString aAbsURL
= GetScImport().GetAbsoluteReference(rURL
);
601 std::unique_ptr
<SvxURLField
> pURLField(new SvxURLField(aAbsURL
, rRep
, SvxURLFormat::Repr
));
602 pURLField
->SetTargetFrame(rTargetFrame
);
603 PushParagraphField(std::move(pURLField
), rStyleName
);
606 void ScXMLTableRowCellContext::PushParagraphEnd()
608 // EditEngine always has at least one paragraph even when its content is empty.
610 if (mbEditEngineHasText
)
612 if (maFirstParagraph
)
614 // Flush the cached first paragraph first.
615 mpEditEngine
->Clear();
616 mpEditEngine
->SetTextCurrentDefaults(*maFirstParagraph
);
617 maFirstParagraph
.reset();
619 mpEditEngine
->InsertParagraph(mpEditEngine
->GetParagraphCount(), maParagraph
.makeStringAndClear());
621 else if (mbHasFormatRuns
|| ScStringUtil::isMultiline(maParagraph
))
623 mpEditEngine
->Clear();
624 mpEditEngine
->SetTextCurrentDefaults(maParagraph
.makeStringAndClear());
625 mbEditEngineHasText
= true;
627 else if (mnCurParagraph
== 0)
629 maFirstParagraph
= maParagraph
.makeStringAndClear();
630 mbEditEngineHasText
= true;
636 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
ScXMLTableRowCellContext::createFastChildContext(
637 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
639 SvXMLImportContext
*pContext
= nullptr;
640 sax_fastparser::FastAttributeList
*pAttribList
=
641 &sax_fastparser::castToFastAttributeList( xAttrList
);
646 case XML_ELEMENT( TEXT
, XML_P
):
651 pContext
= new ScXMLCellTextParaContext(rXMLImport
, *this);
654 case XML_ELEMENT( TABLE
, XML_SUB_TABLE
):
656 SAL_WARN("sc", "ScXMLTableRowCellContext::createFastChildContext: subtables are not supported");
659 case XML_ELEMENT( TABLE
, XML_DETECTIVE
):
662 if (!pDetectiveObjVec
)
663 pDetectiveObjVec
.reset( new ScMyImpDetectiveObjVec
);
664 pContext
= new ScXMLDetectiveContext(
665 rXMLImport
, pDetectiveObjVec
.get() );
668 case XML_ELEMENT( TABLE
, XML_CELL_RANGE_SOURCE
):
671 if (!pCellRangeSource
)
672 pCellRangeSource
.reset(new ScMyImpCellRangeSource());
673 pContext
= new ScXMLCellRangeSourceContext(
674 rXMLImport
, pAttribList
, pCellRangeSource
.get() );
677 case XML_ELEMENT(OFFICE
, XML_ANNOTATION
):
682 "ScXMLTableRowCellContext::CreateChildContext - multiple annotations in one cell");
683 mxAnnotationData
.reset( new ScXMLAnnotationData
);
684 pContext
= new ScXMLAnnotationContext( rXMLImport
, nElement
,
685 xAttrList
, *mxAnnotationData
);
690 if (!pContext
&& !bTextP
)
692 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
693 uno::Reference
<drawing::XShapes
> xShapes (rXMLImport
.GetTables().GetCurrentXShapes());
696 if (ScDocument
* pDoc
= rXMLImport
.GetDocument())
698 if (aCellPos
.Col() > pDoc
->MaxCol())
699 aCellPos
.SetCol(pDoc
->MaxCol());
700 if (aCellPos
.Row() > pDoc
->MaxRow())
701 aCellPos
.SetRow(pDoc
->MaxRow());
702 XMLTableShapeImportHelper
* pTableShapeImport
=
703 static_cast< XMLTableShapeImportHelper
* >( rXMLImport
.GetShapeImport().get() );
704 pTableShapeImport
->SetOnTable(false);
705 pTableShapeImport
->SetCell(aCellPos
);
706 pContext
= XMLShapeImportHelper::CreateGroupChildContext(
707 rXMLImport
, nElement
, xAttrList
, xShapes
);
711 rXMLImport
.ProgressBarIncrement();
720 void ScXMLTableRowCellContext::DoMerge( const ScAddress
& rScAddress
, const SCCOL nCols
, const SCROW nRows
)
722 SCCOL mergeToCol
= rScAddress
.Col() + nCols
;
723 SCROW mergeToRow
= rScAddress
.Row() + nRows
;
724 if (ScDocument
* pDoc
= rXMLImport
.GetDocument())
726 bool bInBounds
= rScAddress
.Col() <= pDoc
->MaxCol() && rScAddress
.Row() <= pDoc
->MaxRow() &&
727 mergeToCol
<= pDoc
->MaxCol() && mergeToRow
<= pDoc
->MaxRow();
730 pDoc
->DoMerge( rScAddress
.Col(), rScAddress
.Row(),
731 mergeToCol
, mergeToRow
, rScAddress
.Tab() );
738 ScValidationMode
validationTypeToMode( const sheet::ValidationType eVType
)
740 ScValidationMode eMode
;
743 case sheet::ValidationType_WHOLE
: eMode
= SC_VALID_WHOLE
; break;
744 case sheet::ValidationType_DECIMAL
: eMode
= SC_VALID_DECIMAL
; break;
745 case sheet::ValidationType_DATE
: eMode
= SC_VALID_DATE
; break;
746 case sheet::ValidationType_TIME
: eMode
= SC_VALID_TIME
; break;
747 case sheet::ValidationType_TEXT_LEN
: eMode
= SC_VALID_TEXTLEN
; break;
748 case sheet::ValidationType_LIST
: eMode
= SC_VALID_LIST
; break;
749 case sheet::ValidationType_CUSTOM
: eMode
= SC_VALID_CUSTOM
; break;
750 default: eMode
= SC_VALID_ANY
; break;
755 ScValidErrorStyle
validAlertToValidError( const sheet::ValidationAlertStyle eVAlertStyle
)
757 ScValidErrorStyle eVErrStyle
;
758 switch( eVAlertStyle
)
760 case sheet::ValidationAlertStyle_STOP
: eVErrStyle
= SC_VALERR_STOP
; break;
761 case sheet::ValidationAlertStyle_WARNING
: eVErrStyle
= SC_VALERR_WARNING
; break;
762 case sheet::ValidationAlertStyle_MACRO
: eVErrStyle
= SC_VALERR_MACRO
; break;
763 default: eVErrStyle
= SC_VALERR_INFO
; break;
764 //should INFO be the default? seems to be the most unobtrusive choice.
771 void ScXMLTableRowCellContext::SetContentValidation( const ScRange
& rScRange
)
773 if (!maContentValidationName
)
776 ScDocument
* pDoc
= rXMLImport
.GetDocument();
780 ScMyImportValidation aValidation
;
781 aValidation
.eGrammar1
= aValidation
.eGrammar2
= pDoc
->GetStorageGrammar();
782 if( !rXMLImport
.GetValidation(*maContentValidationName
, aValidation
) )
785 ScValidationData
aScValidationData(
786 validationTypeToMode(aValidation
.aValidationType
),
787 ScConditionEntry::GetModeFromApi(aValidation
.aOperator
),
788 aValidation
.sFormula1
, aValidation
.sFormula2
, *pDoc
, ScAddress(),
789 aValidation
.sFormulaNmsp1
, aValidation
.sFormulaNmsp2
,
790 aValidation
.eGrammar1
, aValidation
.eGrammar2
793 aScValidationData
.SetIgnoreBlank( aValidation
.bIgnoreBlanks
);
794 aScValidationData
.SetCaseSensitive( aValidation
.bCaseSensitive
);
795 aScValidationData
.SetListType( aValidation
.nShowList
);
797 // set strings for error / input even if disabled (and disable afterwards)
798 aScValidationData
.SetInput( aValidation
.sInputTitle
, aValidation
.sInputMessage
);
799 if( !aValidation
.bShowInputMessage
)
800 aScValidationData
.ResetInput();
801 aScValidationData
.SetError( aValidation
.sErrorTitle
, aValidation
.sErrorMessage
, validAlertToValidError(aValidation
.aAlertStyle
) );
802 if( !aValidation
.bShowErrorMessage
)
803 aScValidationData
.ResetError();
805 if( !aValidation
.sBaseCellAddress
.isEmpty() )
806 aScValidationData
.SetSrcString( aValidation
.sBaseCellAddress
);
808 sal_uInt32 nIndex
= pDoc
->AddValidationEntry( aScValidationData
);
810 ScPatternAttr
aPattern(pDoc
->getCellAttributeHelper());
811 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA
, nIndex
) );
812 if( rScRange
.aStart
== rScRange
.aEnd
) //for a single cell
814 pDoc
->ApplyPattern( rScRange
.aStart
.Col(), rScRange
.aStart
.Row(),
815 rScRange
.aStart
.Tab(), aPattern
);
817 else //for repeating cells
819 pDoc
->ApplyPatternAreaTab( rScRange
.aStart
.Col(), rScRange
.aStart
.Row(),
820 rScRange
.aEnd
.Col(), rScRange
.aEnd
.Row(),
821 rScRange
.aStart
.Tab(), aPattern
);
824 // is the below still needed?
825 // For now, any sheet with validity is blocked from stream-copying.
826 // Later, the validation names could be stored along with the style names.
827 ScSheetSaveData
* pSheetData
= GetScImport().GetScModel()->GetSheetSaveData();
828 pSheetData
->BlockSheet( GetScImport().GetTables().GetCurrentSheet() );
831 void ScXMLTableRowCellContext::SetContentValidation( const ScAddress
& rCellPos
)
833 SetContentValidation( ScRange(rCellPos
, rCellPos
) );
836 void ScXMLTableRowCellContext::SetAnnotation(const ScAddress
& rPos
)
838 ScDocument
* pDoc
= rXMLImport
.GetDocument();
839 if (!pDoc
|| !mxAnnotationData
)
844 ScPostIt
* pNote
= nullptr;
846 uno::Reference
< drawing::XShapes
> xShapes
= rXMLImport
.GetTables().GetCurrentXShapes();
847 sal_Int32 nOldShapeCount
= xShapes
.is() ? xShapes
->getCount() : 0;
849 OSL_ENSURE( !mxAnnotationData
->mxShape
.is() || mxAnnotationData
->mxShapes
.is(),
850 "ScXMLTableRowCellContext::SetAnnotation - shape without drawing page" );
851 if( mxAnnotationData
->mxShape
.is() && mxAnnotationData
->mxShapes
.is() )
853 OSL_ENSURE( mxAnnotationData
->mxShapes
.get() == xShapes
.get(), "ScXMLTableRowCellContext::SetAnnotation - different drawing pages" );
855 /* Don't attempt to get the style from the SdrObject,
856 as it might be a default assigned one. */
857 const SvXMLStylesContext
* pStylesCtxt
= rXMLImport
.GetShapeImport()->GetAutoStylesContext();
858 const SvXMLStyleContext
* pStyle
= pStylesCtxt
? pStylesCtxt
->FindStyleChildContext(
859 XmlStyleFamily::SD_GRAPHICS_ID
, mxAnnotationData
->maStyleName
) : nullptr;
860 OUString aStyleName
= pStyle
? pStyle
->GetParentName() : mxAnnotationData
->maStyleName
;
861 assert(!pStylesCtxt
|| !pStylesCtxt
->FindStyleChildContext(
862 XmlStyleFamily::SD_GRAPHICS_ID
, aStyleName
));
863 aStyleName
= rXMLImport
.GetStyleDisplayName(XmlStyleFamily::SD_GRAPHICS_ID
, aStyleName
);
865 SdrObject
* pObject
= SdrObject::getSdrObjectFromXShape(mxAnnotationData
->mxShape
);
866 OSL_ENSURE( pObject
, "ScXMLTableRowCellContext::SetAnnotation - cannot get SdrObject from shape" );
868 /* Try to reuse the drawing object already created (but only if the
869 note is visible, and the object is a caption object). */
870 if( mxAnnotationData
->mbShown
&& mxAnnotationData
->mbUseShapePos
&& !comphelper::LibreOfficeKit::isActive())
872 if( SdrCaptionObj
* pCaption
= dynamic_cast< SdrCaptionObj
* >( pObject
) )
874 OSL_ENSURE( !pCaption
->GetLogicRect().IsEmpty(), "ScXMLTableRowCellContext::SetAnnotation - invalid caption rectangle" );
875 // create the cell note with the caption object
876 pNote
= ScNoteUtil::CreateNoteFromCaption( *pDoc
, rPos
, pCaption
, !aStyleName
.isEmpty() );
877 // forget pointer to object (do not create note again below)
882 // drawing object has not been used to create a note -> use shape data
885 // rescue settings from drawing object before the shape is removed
886 SfxItemSet
aItemSet( pObject
->GetMergedItemSet() );
887 std::optional
<OutlinerParaObject
> pOutlinerObj
;
888 if (auto p
= pObject
->GetOutlinerParaObject())
890 tools::Rectangle aCaptionRect
;
891 if( mxAnnotationData
->mbUseShapePos
)
892 aCaptionRect
= pObject
->GetLogicRect();
893 // remove the shape from the drawing page, this invalidates pObject
894 mxAnnotationData
->mxShapes
->remove( mxAnnotationData
->mxShape
);
896 // update current number of existing objects
898 nOldShapeCount
= xShapes
->getCount();
900 // an outliner object is required (empty note captions not allowed)
903 // create cell note with all data from drawing object
904 if(!comphelper::LibreOfficeKit::isActive())
906 pNote
= ScNoteUtil::CreateNoteFromObjectData( *pDoc
, rPos
,
907 std::move(aItemSet
), aStyleName
, *pOutlinerObj
,
908 aCaptionRect
, mxAnnotationData
->mbShown
);
912 pNote
= ScNoteUtil::CreateNoteFromObjectData( *pDoc
, rPos
,
913 std::move(aItemSet
), aStyleName
, *pOutlinerObj
,
914 aCaptionRect
, false );
920 else if( !mxAnnotationData
->maSimpleText
.isEmpty() )
922 // create note from simple text
923 pNote
= ScNoteUtil::CreateNoteFromString( *pDoc
, rPos
,
924 mxAnnotationData
->maSimpleText
, mxAnnotationData
->mbShown
, false );
927 // set author and date
931 if (rXMLImport
.GetMM100UnitConverter().convertDateTime(fDate
, mxAnnotationData
->maCreateDate
))
933 SvNumberFormatter
* pNumForm
= pDoc
->GetFormatTable();
935 // Date string is in format ISO 8601 inside <dc:date>
936 // i.e: 2024-08-14 or 2024-08-14T23:55:06 or 20240814T235506
937 // Time always has prefix 'T'
938 sal_uInt32 nfIndex
= pNumForm
->GetFormatIndex(
939 mxAnnotationData
->maCreateDate
.indexOf('T') > -1 ? NF_DATETIME_SYS_DDMMYYYY_HHMMSS
940 : NF_DATE_SYS_DDMMYYYY
,
943 const Color
* pColor
= nullptr;
944 pNumForm
->GetOutputString( fDate
, nfIndex
, aDate
, &pColor
);
945 pNote
->SetDate( aDate
);
947 pNote
->SetAuthor( mxAnnotationData
->maAuthor
);
950 // register a shape that has been newly created in the ScNoteUtil functions
951 if( xShapes
.is() && (nOldShapeCount
< xShapes
->getCount()) )
953 uno::Reference
< drawing::XShape
> xShape
;
954 rXMLImport
.GetShapeImport()->shapeWithZIndexAdded( xShape
, xShapes
->getCount() );
957 // store the style names for stream copying
958 ScSheetSaveData
* pSheetData
= rXMLImport
.GetScModel()->GetSheetSaveData();
959 pSheetData
->HandleNoteStyles( mxAnnotationData
->maStyleName
, mxAnnotationData
->maTextStyle
, rPos
);
961 for (const auto& rContentStyle
: mxAnnotationData
->maContentStyles
)
963 pSheetData
->AddNoteContentStyle( rContentStyle
.mnFamily
, rContentStyle
.maName
, rPos
, rContentStyle
.maSelection
);
967 // core implementation
968 void ScXMLTableRowCellContext::SetDetectiveObj( const ScAddress
& rPosition
)
970 ScDocument
* pDoc
= rXMLImport
.GetDocument();
971 if( !pDoc
|| !cellExists(*pDoc
, rPosition
) || !pDetectiveObjVec
|| pDetectiveObjVec
->empty() )
975 ScDetectiveFunc
aDetFunc( *pDoc
, rPosition
.Tab() );
976 uno::Reference
<container::XIndexAccess
> xShapesIndex
= rXMLImport
.GetTables().GetCurrentXShapes(); // make draw page
977 for(const auto& rDetectiveObj
: *pDetectiveObjVec
)
979 aDetFunc
.InsertObject( rDetectiveObj
.eObjType
, rPosition
, rDetectiveObj
.aSourceRange
, rDetectiveObj
.bHasError
);
980 if (xShapesIndex
.is())
982 sal_Int32 nShapes
= xShapesIndex
->getCount();
983 uno::Reference
< drawing::XShape
> xShape
;
984 rXMLImport
.GetShapeImport()->shapeWithZIndexAdded(xShape
, nShapes
);
989 // core implementation
990 void ScXMLTableRowCellContext::SetCellRangeSource( const ScAddress
& rPosition
)
992 ScDocument
* pDoc
= rXMLImport
.GetDocument();
993 if( !pDoc
|| !cellExists(*pDoc
, rPosition
) || !pCellRangeSource
|| pCellRangeSource
->sSourceStr
.isEmpty() ||
994 pCellRangeSource
->sFilterName
.isEmpty() || pCellRangeSource
->sURL
.isEmpty() )
998 ScRange
aDestRange( rPosition
.Col(), rPosition
.Row(), rPosition
.Tab(),
999 rPosition
.Col() + static_cast<SCCOL
>(pCellRangeSource
->nColumns
- 1),
1000 rPosition
.Row() + static_cast<SCROW
>(pCellRangeSource
->nRows
- 1), rPosition
.Tab() );
1001 OUString
sFilterName( pCellRangeSource
->sFilterName
);
1002 OUString
sSourceStr( pCellRangeSource
->sSourceStr
);
1003 ScAreaLink
* pLink
= new ScAreaLink( pDoc
->GetDocumentShell(), pCellRangeSource
->sURL
,
1004 sFilterName
, pCellRangeSource
->sFilterOptions
, sSourceStr
, aDestRange
, pCellRangeSource
->nRefresh
);
1005 sfx2::LinkManager
* pLinkManager
= pDoc
->GetLinkManager();
1006 pLinkManager
->InsertFileLink( *pLink
, sfx2::SvBaseLinkObjectType::ClientFile
, pCellRangeSource
->sURL
, &sFilterName
, &sSourceStr
);
1009 void ScXMLTableRowCellContext::SetFormulaCell(ScFormulaCell
* pFCell
) const
1014 bool bMayForceNumberformat
= true;
1018 // don't do anything here
1019 // we need to recalc anyway
1021 else if( bFormulaTextResult
&& maStringValue
)
1023 if( !IsPossibleErrorString() )
1025 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1026 pFCell
->SetHybridString(pDoc
->GetSharedStringPool().intern(*maStringValue
));
1027 pFCell
->ResetDirty();
1028 // A General format doesn't force any other format for a string
1029 // result, don't attempt to recalculate this later.
1030 bMayForceNumberformat
= false;
1033 else if (std::isfinite(fValue
))
1035 pFCell
->SetHybridDouble(fValue
);
1036 if (mbPossibleEmptyDisplay
&& fValue
== 0.0)
1038 // Needs to be recalculated to propagate, otherwise would be
1039 // propagated as empty string. So don't ResetDirty().
1040 pFCell
->SetHybridEmptyDisplayedAsString();
1043 pFCell
->ResetDirty();
1046 if (bMayForceNumberformat
)
1047 // Re-calculate to get number format only when style is not set.
1048 pFCell
->SetNeedNumberFormat(!mbHasStyle
);
1051 void ScXMLTableRowCellContext::PutTextCell( const ScAddress
& rCurrentPos
,
1052 const SCCOL nCurrentCol
, const ::std::optional
< OUString
>& pOUText
)
1054 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1055 bool bDoIncrement
= true;
1056 //matrix reference cells that contain text formula results;
1057 //cell was already put in document, just need to set text here.
1058 if( pDoc
&& rXMLImport
.GetTables().IsPartOfMatrix(rCurrentPos
) )
1060 ScRefCellValue
aCell(*pDoc
, rCurrentPos
);
1061 bDoIncrement
= aCell
.getType() == CELLTYPE_FORMULA
;
1064 ScFormulaCell
* pFCell
= aCell
.getFormula();
1065 OUString aCellString
;
1067 aCellString
= *maStringValue
;
1068 else if (mbEditEngineHasText
)
1069 aCellString
= GetFirstParagraph();
1070 else if ( nCurrentCol
> 0 && pOUText
&& !pOUText
->isEmpty() )
1071 aCellString
= *pOUText
;
1073 bDoIncrement
= false;
1076 bDoIncrement
= false;
1078 if(!aCellString
.isEmpty())
1080 if (bDoIncrement
&& !IsPossibleErrorString() && pFCell
)
1082 pFCell
->SetHybridString(pDoc
->GetSharedStringPool().intern(aCellString
));
1083 pFCell
->ResetDirty();
1087 ScAddress aTopLeftMatrixCell
;
1088 if (pFCell
&& pFCell
->GetMatrixOrigin(*pDoc
, aTopLeftMatrixCell
))
1090 ScFormulaCell
* pMatrixCell
= pDoc
->GetFormulaCell(aTopLeftMatrixCell
);
1092 pMatrixCell
->SetDirty();
1095 SAL_WARN("sc", "matrix cell without matrix");
1100 else //regular text cells
1102 ScDocumentImport
& rDoc
= rXMLImport
.GetDoc();
1105 rDoc
.setStringCell(rCurrentPos
, *maStringValue
);
1107 else if (mbEditEngineHasText
)
1109 if (maFirstParagraph
)
1111 // This is a normal text without format runs.
1112 rDoc
.setStringCell(rCurrentPos
, *maFirstParagraph
);
1116 // This text either has format runs, has field(s), or consists of multiple lines.
1117 for (const auto& rxFormat
: maFormats
)
1118 mpEditEngine
->QuickSetAttribs(rxFormat
->maItemSet
, rxFormat
->maSelection
);
1120 for (const auto& rxField
: maFields
)
1121 mpEditEngine
->QuickInsertField(SvxFieldItem(*rxField
->mpData
, EE_FEATURE_FIELD
), rxField
->maSelection
);
1123 // This edit engine uses the SfxItemPool instance returned
1124 // from pDoc->GetEditPool() to create the text object, which
1125 // is a prerequisite for using this constructor of ScEditCell.
1126 rDoc
.setEditCell(rCurrentPos
, mpEditEngine
->CreateTextObject());
1129 else if ( nCurrentCol
> 0 && pOUText
&& !pOUText
->isEmpty() )
1131 rDoc
.setStringCell(rCurrentPos
, *pOUText
);
1134 bDoIncrement
= false;
1137 // #i56027# This is about setting simple text, not edit cells,
1138 // so ProgressBarIncrement must be called with bEditCell = FALSE.
1139 // Formatted text that is put into the cell by the child context
1140 // is handled in AddCellsToTable() (bIsEmpty is true then).
1142 rXMLImport
.ProgressBarIncrement();
1145 void ScXMLTableRowCellContext::PutValueCell( const ScAddress
& rCurrentPos
)
1147 //matrix reference cells that contain value formula results;
1148 //cell was already put in document, just need to set value here.
1149 if( rXMLImport
.GetTables().IsPartOfMatrix(rCurrentPos
) )
1151 ScRefCellValue
aCell(*rXMLImport
.GetDocument(), rCurrentPos
);
1152 if (aCell
.getType() == CELLTYPE_FORMULA
)
1154 ScFormulaCell
* pFCell
= aCell
.getFormula();
1155 SetFormulaCell(pFCell
);
1157 pFCell
->SetNeedNumberFormat( true );
1160 else //regular value cell
1162 // fdo#62250 absent values are not NaN, set to 0.0
1163 // PutValueCell() is called only for a known cell value type,
1164 // bIsEmpty==false in all these cases, no sense to check it here.
1165 if (!std::isfinite( fValue
))
1168 // #i62435# Initialize the value cell's script type if the default
1169 // style's number format is latin-only. If the cell uses a different
1170 // format, the script type will be reset when the style is applied.
1172 rXMLImport
.GetDoc().setNumericCell(rCurrentPos
, fValue
);
1174 rXMLImport
.ProgressBarIncrement();
1179 bool isEmptyOrNote( const ScDocument
* pDoc
, const ScAddress
& rCurrentPos
)
1181 CellType eType
= pDoc
->GetCellType(rCurrentPos
);
1182 return (eType
== CELLTYPE_NONE
);
1187 void ScXMLTableRowCellContext::AddTextAndValueCell( const ScAddress
& rCellPos
,
1188 const ::std::optional
< OUString
>& pOUText
, ScAddress
& rCurrentPos
)
1190 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1191 ScMyTables
& rTables
= rXMLImport
.GetTables();
1192 bool bWasEmpty
= bIsEmpty
;
1193 for (SCCOL i
= 0; i
< nColsRepeated
; ++i
)
1195 rCurrentPos
.SetCol( rCellPos
.Col() + i
);
1197 // it makes no sense to import data after the last supported column
1198 // fdo#58539 & gnome#627150
1199 if(rCurrentPos
.Col() > pDoc
->MaxCol())
1201 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW
);
1206 rTables
.AddColumn(false);
1209 for (SCROW j
= 0; j
< nRepeatedRows
; ++j
)
1211 rCurrentPos
.SetRow( rCellPos
.Row() + j
);
1213 // it makes no sense to import data after last supported row
1214 // fdo#58539 & gnome#627150
1215 if(rCurrentPos
.Row() > pDoc
->MaxRow())
1217 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW
);
1221 if( (rCurrentPos
.Col() == 0) && (j
> 0) )
1224 rTables
.AddColumn(false);
1226 if( cellExists(*pDoc
, rCurrentPos
) )
1228 if( !bIsCovered
|| isEmptyOrNote(pDoc
, rCurrentPos
) )
1232 case util::NumberFormat::TEXT
:
1234 PutTextCell( rCurrentPos
, i
, pOUText
);
1237 case util::NumberFormat::NUMBER
:
1238 case util::NumberFormat::PERCENT
:
1239 case util::NumberFormat::CURRENCY
:
1240 case util::NumberFormat::TIME
:
1241 case util::NumberFormat::DATETIME
:
1242 case util::NumberFormat::LOGICAL
:
1244 PutValueCell( rCurrentPos
);
1249 OSL_FAIL("no cell type given");
1255 SetAnnotation( rCurrentPos
);
1256 SetDetectiveObj( rCurrentPos
);
1257 SetCellRangeSource( rCurrentPos
);
1261 if (!bWasEmpty
|| mxAnnotationData
)
1263 if (rCurrentPos
.Row() > pDoc
->MaxRow())
1264 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW
);
1266 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW
);
1273 if ((i
== 0) && (rCellPos
.Col() == 0))
1275 for (sal_Int32 j
= 1; j
< nRepeatedRows
; ++j
)
1278 rTables
.AddColumn(false);
1281 // if nothing else useful can happen in the loop, just exit early
1282 if (i
!= 0 && bIsEmpty
&& rCurrentPos
.Row() != 0)
1284 rCurrentPos
.SetCol( rCellPos
.Col() + nColsRepeated
- 1 );
1285 rTables
.AddColumns(nColsRepeated
- i
- 1);
1292 bool ScXMLTableRowCellContext::CellsAreRepeated() const
1294 return ( (nColsRepeated
> 1) || (nRepeatedRows
> 1) );
1299 // from ScCellObj::GetOutputString_Imp(). all of it may not be necessary.
1300 OUString
getOutputString( ScDocument
* pDoc
, const ScAddress
& aCellPos
)
1305 ScRefCellValue
aCell(*pDoc
, aCellPos
);
1306 switch (aCell
.getType())
1312 // GetString on EditCell replaces linebreaks with spaces;
1313 // however here we need line breaks
1314 const EditTextObject
* pData
= aCell
.getEditText();
1315 EditEngine
& rEngine
= pDoc
->GetEditEngine();
1316 rEngine
.SetText(*pData
);
1317 return rEngine
.GetText();
1318 // also don't format EditCells per NumberFormatter
1323 // like in GetString for document (column)
1324 const Color
* pColor
;
1325 sal_uInt32 nNumFmt
= pDoc
->GetNumberFormat(ScRange(aCellPos
));
1326 return ScCellFormat::GetString(aCell
, nNumFmt
, &pColor
, nullptr, *pDoc
);
1333 void ScXMLTableRowCellContext::AddNonFormulaCell( const ScAddress
& rCellPos
)
1335 ::std::optional
< OUString
> pOUText
;
1337 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1338 if( nCellType
== util::NumberFormat::TEXT
)
1340 if( !bIsEmpty
&& !maStringValue
&& !mbEditEngineHasText
&& cellExists(*pDoc
, rCellPos
) && CellsAreRepeated() )
1341 pOUText
= getOutputString(pDoc
, rCellPos
);
1343 if (!mbEditEngineHasText
&& !pOUText
&& !maStringValue
)
1347 ScAddress
aCurrentPos( rCellPos
);
1348 if( mxAnnotationData
|| pDetectiveObjVec
|| pCellRangeSource
) // has special content
1351 AddTextAndValueCell( rCellPos
, pOUText
, aCurrentPos
);
1353 if( CellsAreRepeated() )
1355 SCCOL
nStartCol( std::min(rCellPos
.Col(), pDoc
->MaxCol()) );
1356 SCROW
nStartRow( std::min(rCellPos
.Row(), pDoc
->MaxRow()) );
1357 SCCOL
nEndCol( std::min
<SCCOL
>(rCellPos
.Col() + nColsRepeated
- 1, pDoc
->MaxCol()) );
1358 SCROW
nEndRow( std::min(rCellPos
.Row() + nRepeatedRows
- 1, pDoc
->MaxRow()) );
1359 ScRange
aScRange( nStartCol
, nStartRow
, rCellPos
.Tab(), nEndCol
, nEndRow
, rCellPos
.Tab() );
1360 SetContentValidation( aScRange
);
1361 rXMLImport
.GetStylesImportHelper()->AddRange( aScRange
);
1363 else if( cellExists(*pDoc
, rCellPos
) )
1365 rXMLImport
.GetStylesImportHelper()->AddCell(rCellPos
);
1366 SetContentValidation( rCellPos
);
1370 void ScXMLTableRowCellContext::PutFormulaCell( const ScAddress
& rCellPos
)
1372 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1376 ScDocumentImport
& rDocImport
= rXMLImport
.GetDoc();
1378 const OUString
& aText
= maFormula
->first
;
1380 ScExternalRefManager::ApiGuard
aExtRefGuard(*pDoc
);
1382 if ( aText
.isEmpty() )
1385 // temporary formula string as string tokens
1386 std::unique_ptr
<ScTokenArray
> pCode(new ScTokenArray(*pDoc
));
1388 // Check the special case of a single error constant without leading
1389 // '=' and create an error formula cell without tokens.
1390 FormulaError nError
= GetScImport().GetFormulaErrorConstant(aText
);
1391 if (nError
!= FormulaError::NONE
)
1393 pCode
->SetCodeError(nError
);
1397 // 5.2 and earlier wrote broken "Err:xxx" as formula to designate
1398 // an error formula cell.
1399 if (aText
.startsWithIgnoreAsciiCase("Err:") && aText
.getLength() <= 9 &&
1401 GetScImport().GetFormulaErrorConstant( OUString::Concat("#ERR") + aText
.subView(4) + "!")) != FormulaError::NONE
))
1403 pCode
->SetCodeError(nError
);
1407 OUString aFormulaNmsp
= maFormula
->second
;
1408 if( eGrammar
!= formula::FormulaGrammar::GRAM_EXTERNAL
)
1409 aFormulaNmsp
.clear();
1410 pCode
->AssignXMLString( aText
, aFormulaNmsp
);
1411 rDocImport
.getDoc().IncXMLImportedFormulaCount( aText
.getLength() );
1415 ScFormulaCell
* pNewCell
= new ScFormulaCell(*pDoc
, rCellPos
, std::move(pCode
), eGrammar
, ScMatrixMode::NONE
);
1416 SetFormulaCell(pNewCell
);
1417 rDocImport
.setFormulaCell(rCellPos
, pNewCell
);
1420 void ScXMLTableRowCellContext::AddFormulaCell( const ScAddress
& rCellPos
)
1422 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1423 if( cellExists(*pDoc
, rCellPos
) )
1425 SetContentValidation( rCellPos
);
1426 SAL_WARN_IF((nColsRepeated
!= 1) || (nRepeatedRows
!= 1), "sc", "repeated cells with formula not possible now");
1427 rXMLImport
.GetStylesImportHelper()->AddCell(rCellPos
);
1432 if (nMatrixCols
> 0 && nMatrixRows
> 0)
1434 //matrix cells are put in the document, but we must set the
1435 //value/text of each matrix cell later
1436 rXMLImport
.GetTables().AddMatrixRange(
1437 rCellPos
.Col(), rCellPos
.Row(),
1438 std::min
<SCCOL
>(rCellPos
.Col() + nMatrixCols
- 1, pDoc
->MaxCol()),
1439 std::min
<SCROW
>(rCellPos
.Row() + nMatrixRows
- 1, pDoc
->MaxRow()),
1440 maFormula
->first
, maFormula
->second
, eGrammar
);
1442 // Set the value/text of the top-left matrix position in its
1443 // cached result. For import, we only need to set the correct
1444 // matrix geometry and the value type of the top-left element.
1445 ScFormulaCell
* pFCell
= pDoc
->GetFormulaCell(rCellPos
);
1448 ScMatrixRef
pMat(new ScMatrix(nMatrixCols
, nMatrixRows
));
1449 if (bFormulaTextResult
&& maStringValue
)
1451 if (!IsPossibleErrorString())
1453 pFCell
->SetResultMatrix(
1454 nMatrixCols
, nMatrixRows
, pMat
, new formula::FormulaStringToken(
1455 pDoc
->GetSharedStringPool().intern( *maStringValue
)));
1456 pFCell
->ResetDirty();
1459 else if (std::isfinite(fValue
))
1461 pFCell
->SetResultMatrix(
1462 nMatrixCols
, nMatrixRows
, pMat
, new formula::FormulaDoubleToken(fValue
));
1463 pFCell
->ResetDirty();
1469 PutFormulaCell( rCellPos
);
1471 SetAnnotation( rCellPos
);
1472 SetDetectiveObj( rCellPos
);
1473 SetCellRangeSource( rCellPos
);
1474 rXMLImport
.ProgressBarIncrement();
1478 if (rCellPos
.Row() > pDoc
->MaxRow())
1479 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW
);
1481 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW
);
1485 //There are cases where a formula cell is exported with an office:value of 0 or
1486 //no office:value at all, but the formula cell will have a text:p value which
1487 //contains the intended formula result.
1488 //These cases include when a formula result:
1490 // - has a constant error value beginning with "#" (such as "#VALUE!" or "#N/A")
1491 // - has an "Err:[###]" (where "[###]" is an error number)
1492 // Libreoffice 4.1+ with ODF1.2 extended write however calcext:value-type="error" in that case
1493 void ScXMLTableRowCellContext::HasSpecialCaseFormulaText()
1495 if (!mbEditEngineHasText
)
1498 const OUString aStr
= GetFirstParagraph();
1503 mbPossibleEmptyDisplay
= true;
1509 mbPossibleErrorCell
= true;
1510 mbPossibleEmptyDisplay
= true;
1512 else if (aStr
.startsWith("Err:"))
1513 mbPossibleErrorCell
= true;
1514 else if (aStr
.startsWith("#"))
1515 mbCheckWithCompilerForError
= true;
1518 bool ScXMLTableRowCellContext::IsPossibleErrorString() const
1521 return mbErrorValue
;
1523 return mbPossibleErrorCell
|| (mbCheckWithCompilerForError
&& maStringValue
&&
1524 GetScImport().GetFormulaErrorConstant(*maStringValue
) != FormulaError::NONE
);
1527 void SAL_CALL
ScXMLTableRowCellContext::endFastElement(sal_Int32
/*nElement*/)
1529 HasSpecialCaseFormulaText();
1530 if( bFormulaTextResult
&& (mbPossibleErrorCell
|| mbCheckWithCompilerForError
) )
1532 maStringValue
= GetFirstParagraph();
1535 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
1536 if( aCellPos
.Col() > 0 && nRepeatedRows
> 1 )
1537 aCellPos
.SetRow( aCellPos
.Row() - (nRepeatedRows
- 1) );
1539 DoMerge( aCellPos
, nMergedCols
- 1, nMergedRows
- 1 );
1542 AddFormulaCell(aCellPos
);
1544 AddNonFormulaCell(aCellPos
);
1546 //if LockSolarMutex got used, we presumably need to ensure an UnlockSolarMutex
1547 if (bSolarMutexLocked
)
1549 GetScImport().UnlockSolarMutex();
1550 bSolarMutexLocked
= false;
1559 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */