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>
30 #include <sheetdata.hxx>
31 #include <cellform.hxx>
32 #include <validat.hxx>
33 #include <patattr.hxx>
34 #include <scitems.hxx>
35 #include <docpool.hxx>
37 #include "XMLTableShapeImportHelper.hxx"
38 #include "XMLStylesImportHelper.hxx"
39 #include "celltextparacontext.hxx"
40 #include "XMLCellRangeSourceContext.hxx"
42 #include <arealink.hxx>
43 #include <sfx2/linkmgr.hxx>
44 #include <scerrors.hxx>
45 #include <editutil.hxx>
46 #include <formulacell.hxx>
47 #include "editattributemap.hxx"
48 #include <tokenarray.hxx>
49 #include <scmatrix.hxx>
50 #include <stringutil.hxx>
51 #include <documentimport.hxx>
52 #include <externalrefmgr.hxx>
54 #include <xmloff/maptype.hxx>
55 #include <xmloff/xmltoken.hxx>
56 #include <xmloff/xmlprmap.hxx>
57 #include <xmloff/xmluconv.hxx>
58 #include <xmloff/families.hxx>
59 #include <xmloff/xmlnamespace.hxx>
60 #include <xmloff/prstylei.hxx>
61 #include <xmloff/xmlimppr.hxx>
62 #include <svl/numformat.hxx>
63 #include <svl/zforlist.hxx>
64 #include <svx/svdocapt.hxx>
65 #include <editeng/eeitem.hxx>
66 #include <editeng/outlobj.hxx>
67 #include <editeng/wghtitem.hxx>
68 #include <editeng/colritem.hxx>
69 #include <editeng/fhgtitem.hxx>
70 #include <editeng/postitem.hxx>
71 #include <editeng/flditem.hxx>
72 #include <editeng/fontitem.hxx>
73 #include <editeng/udlnitem.hxx>
74 #include <editeng/wrlmitem.hxx>
75 #include <editeng/crossedoutitem.hxx>
76 #include <editeng/charreliefitem.hxx>
77 #include <editeng/charscaleitem.hxx>
78 #include <editeng/contouritem.hxx>
79 #include <editeng/shdditem.hxx>
80 #include <editeng/kernitem.hxx>
81 #include <editeng/autokernitem.hxx>
82 #include <editeng/escapementitem.hxx>
83 #include <editeng/emphasismarkitem.hxx>
84 #include <editeng/langitem.hxx>
85 #include <svl/sharedstringpool.hxx>
86 #include <sax/tools/converter.hxx>
87 #include <sax/fastattribs.hxx>
89 #include <com/sun/star/util/NumberFormat.hpp>
91 #include <com/sun/star/sheet/ValidationType.hpp>
92 #include <com/sun/star/sheet/ValidationAlertStyle.hpp>
94 #include <rtl/ustrbuf.hxx>
95 #include <osl/diagnose.h>
96 #include <sal/log.hxx>
97 #include <i18nlangtag/lang.h>
99 #include <comphelper/servicehelper.hxx>
100 #include <comphelper/lok.hxx>
102 using namespace com::sun::star
;
103 using namespace xmloff::token
;
105 ScXMLTableRowCellContext::ParaFormat::ParaFormat(const ScEditEngineDefaulter
& rEditEngine
) :
106 maItemSet(rEditEngine
.GetEmptyItemSet()) {}
108 ScXMLTableRowCellContext::Field::Field(std::unique_ptr
<SvxFieldData
> pData
) : mpData(std::move(pData
)) {}
110 ScXMLTableRowCellContext::Field::~Field()
114 ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport
& rImport
,
115 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
116 const bool bTempIsCovered
,
117 const sal_Int32 nTempRepeatedRows
) :
118 ScXMLImportContext( rImport
),
119 mpEditEngine(GetScImport().GetEditEngine()),
121 fValue(std::numeric_limits
<double>::quiet_NaN()),
124 nRepeatedRows(nTempRepeatedRows
),
129 eGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT
),
130 nCellType(util::NumberFormat::TEXT
),
133 bIsCovered(bTempIsCovered
),
135 mbNewValueType(false),
137 bSolarMutexLocked(false),
138 bFormulaTextResult(false),
139 mbPossibleErrorCell(false),
140 mbCheckWithCompilerForError(false),
141 mbEditEngineHasText(false),
142 mbHasFormatRuns(false),
144 mbPossibleEmptyDisplay(false)
146 rXMLImport
.GetTables().AddColumn(bTempIsCovered
);
148 std::optional
<OUString
> xStyleName
;
149 std::optional
<OUString
> xCurrencySymbol
;
150 if ( rAttrList
.is() )
152 for (auto &it
: *rAttrList
)
154 switch ( it
.getToken() )
156 case XML_ELEMENT( TABLE
, XML_STYLE_NAME
):
157 xStyleName
= it
.toString();
160 case XML_ELEMENT( TABLE
, XML_CONTENT_VALIDATION_NAME
):
161 OSL_ENSURE(!maContentValidationName
, "here should be only one Validation Name");
163 maContentValidationName
= it
.toString();
165 case XML_ELEMENT( TABLE
, XML_NUMBER_ROWS_SPANNED
):
167 nMergedRows
= static_cast<SCROW
>(it
.toInt32());
169 case XML_ELEMENT( TABLE
, XML_NUMBER_COLUMNS_SPANNED
):
171 nMergedCols
= static_cast<SCCOL
>(it
.toInt32());
173 case XML_ELEMENT( TABLE
, XML_NUMBER_MATRIX_COLUMNS_SPANNED
):
175 nMatrixCols
= static_cast<SCCOL
>(it
.toInt32());
177 case XML_ELEMENT( TABLE
, XML_NUMBER_MATRIX_ROWS_SPANNED
):
179 nMatrixRows
= static_cast<SCROW
>(it
.toInt32());
181 case XML_ELEMENT( TABLE
, XML_NUMBER_COLUMNS_REPEATED
):
182 nColsRepeated
= static_cast<SCCOL
>(
183 std::min
<sal_Int32
>( rImport
.GetDocument()->GetSheetLimits().GetMaxColCount(),
184 std::max( it
.toInt32(), static_cast<sal_Int32
>(1) ) ));
186 case XML_ELEMENT( OFFICE
, XML_VALUE_TYPE
):
187 nCellType
= ScXMLImport::GetCellType(it
.toCString(), it
.getLength());
190 case XML_ELEMENT( CALC_EXT
, XML_VALUE_TYPE
):
191 if(it
.isString( "error" ) )
194 nCellType
= ScXMLImport::GetCellType(it
.toCString(), it
.getLength());
196 mbNewValueType
= true;
198 case XML_ELEMENT( OFFICE
, XML_VALUE
):
202 fValue
= it
.toDouble();
205 //if office:value="0", let's get the text:p in case this is
206 //a special case in HasSpecialCaseFormulaText(). If it
207 //turns out not to be a special case, we'll use the 0 value.
209 bFormulaTextResult
= true;
213 case XML_ELEMENT( OFFICE
, XML_DATE_VALUE
):
215 if (!it
.isEmpty() && rXMLImport
.SetNullDateOnUnitConverter())
217 rXMLImport
.GetMM100UnitConverter().convertDateTime(fValue
, it
.toView());
222 case XML_ELEMENT( OFFICE
, XML_TIME_VALUE
):
226 ::sax::Converter::convertDuration(fValue
, it
.toView());
231 case XML_ELEMENT( OFFICE
, XML_STRING_VALUE
):
235 OSL_ENSURE(!maStringValue
, "here should be only one string value");
236 maStringValue
= it
.toString();
241 case XML_ELEMENT( OFFICE
, XML_BOOLEAN_VALUE
):
245 if ( IsXMLToken( it
, XML_TRUE
) )
247 else if ( IsXMLToken( it
, XML_FALSE
) )
250 fValue
= it
.toDouble();
255 case XML_ELEMENT( TABLE
, XML_FORMULA
):
259 OSL_ENSURE(!maFormula
, "here should be only one formula");
260 OUString aFormula
, aFormulaNmsp
;
261 rXMLImport
.ExtractFormulaNamespaceGrammar( aFormula
, aFormulaNmsp
, eGrammar
, it
.toString() );
262 maFormula
= FormulaWithNamespace(aFormula
, aFormulaNmsp
);
266 case XML_ELEMENT( OFFICE
, XML_CURRENCY
):
267 xCurrencySymbol
= it
.toString();
277 if (nCellType
== util::NumberFormat::TEXT
)
278 bFormulaTextResult
= true;
279 if(nCellType
== util::NumberFormat::DATETIME
)
280 nCellType
= util::NumberFormat::UNDEFINED
;
281 //if bIsEmpty is true at this point, then there is no office value.
282 //we must get the text:p (even if it is empty) in case this a special
283 //case in HasSpecialCaseFormulaText().
285 bFormulaTextResult
= true;
287 rXMLImport
.GetStylesImportHelper()->SetAttributes(std::move(xStyleName
), std::move(xCurrencySymbol
), nCellType
);
290 ScXMLTableRowCellContext::~ScXMLTableRowCellContext()
294 void ScXMLTableRowCellContext::LockSolarMutex()
296 if (!bSolarMutexLocked
)
298 GetScImport().LockSolarMutex();
299 bSolarMutexLocked
= true;
305 bool cellExists( const ScDocument
& rDoc
, const ScAddress
& rCellPos
)
307 return( rCellPos
.Col() >= 0 && rCellPos
.Row() >= 0 &&
308 rCellPos
.Col() <= rDoc
.MaxCol() && rCellPos
.Row() <= rDoc
.MaxRow() );
313 void ScXMLTableRowCellContext::PushParagraphSpan(std::u16string_view rSpan
, const OUString
& rStyleName
)
315 sal_Int32 nBegin
= maParagraph
.getLength();
316 sal_Int32 nEnd
= nBegin
+ rSpan
.size();
317 maParagraph
.append(rSpan
);
319 PushFormat(nBegin
, nEnd
, rStyleName
);
322 void ScXMLTableRowCellContext::PushParagraphField(std::unique_ptr
<SvxFieldData
> pData
, const OUString
& rStyleName
)
324 mbHasFormatRuns
= true;
325 maFields
.push_back(std::make_unique
<Field
>(std::move(pData
)));
326 Field
& rField
= *maFields
.back();
328 sal_Int32 nPos
= maParagraph
.getLength();
329 maParagraph
.append('\1'); // Placeholder text for inserted field item.
330 rField
.maSelection
.nStartPara
= mnCurParagraph
;
331 rField
.maSelection
.nEndPara
= mnCurParagraph
;
332 rField
.maSelection
.nStartPos
= nPos
;
333 rField
.maSelection
.nEndPos
= nPos
+1;
335 PushFormat(nPos
, nPos
+1, rStyleName
);
338 void ScXMLTableRowCellContext::PushFormat(sal_Int32 nBegin
, sal_Int32 nEnd
, const OUString
& rStyleName
)
340 if (rStyleName
.isEmpty())
343 // Get the style information from xmloff.
344 rtl::Reference
<XMLPropertySetMapper
> xMapper
= GetImport().GetTextImport()->GetTextImportPropertySetMapper()->getPropertySetMapper();
346 // We can't do anything without the mapper.
349 sal_Int32 nEntryCount
= xMapper
->GetEntryCount();
351 SvXMLStylesContext
* pAutoStyles
= GetImport().GetAutoStyles();
355 // Style name for text span corresponds with the name of an automatic style.
356 const XMLPropStyleContext
* pStyle
= dynamic_cast<const XMLPropStyleContext
*>(
357 pAutoStyles
->FindStyleChildContext(XmlStyleFamily::TEXT_TEXT
, rStyleName
));
360 // No style by that name found.
363 const std::vector
<XMLPropertyState
>& rProps
= pStyle
->GetProperties();
367 const ScXMLEditAttributeMap
& rEditAttrMap
= GetScImport().GetEditAttributeMap();
369 mbHasFormatRuns
= true;
370 maFormats
.push_back(std::make_unique
<ParaFormat
>(*mpEditEngine
));
371 ParaFormat
& rFmt
= *maFormats
.back();
372 rFmt
.maSelection
.nStartPara
= rFmt
.maSelection
.nEndPara
= mnCurParagraph
;
373 rFmt
.maSelection
.nStartPos
= nBegin
;
374 rFmt
.maSelection
.nEndPos
= nEnd
;
376 // Store the used text styles for export.
377 ScSheetSaveData
* pSheetData
= comphelper::getFromUnoTunnel
<ScModelObj
>(rXMLImport
.GetModel())->GetSheetSaveData();
378 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
379 pSheetData
->AddTextStyle(rStyleName
, aCellPos
, rFmt
.maSelection
);
381 std::unique_ptr
<SfxPoolItem
> pPoolItem
;
382 sal_uInt16 nLastItemID
= EE_CHAR_END
+ 1;
384 for (const auto& rProp
: rProps
)
386 if (rProp
.mnIndex
== -1 || rProp
.mnIndex
>= nEntryCount
)
389 const OUString
& rName
= xMapper
->GetEntryAPIName(rProp
.mnIndex
);
390 const ScXMLEditAttributeMap::Entry
* pEntry
= rEditAttrMap
.getEntryByAPIName(rName
);
394 if (nLastItemID
!= pEntry
->mnItemID
&& pPoolItem
)
396 // Flush the last item when the item ID changes.
397 rFmt
.maItemSet
.Put(std::move(pPoolItem
));
400 switch (pEntry
->mnItemID
)
402 case EE_CHAR_FONTINFO
:
403 case EE_CHAR_FONTINFO_CJK
:
404 case EE_CHAR_FONTINFO_CTL
:
406 // Font properties need to be consolidated into a single item.
408 pPoolItem
.reset(new SvxFontItem(pEntry
->mnItemID
));
410 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
414 case EE_CHAR_WEIGHT_CJK
:
415 case EE_CHAR_WEIGHT_CTL
:
418 pPoolItem
.reset(new SvxWeightItem(WEIGHT_NORMAL
, pEntry
->mnItemID
));
420 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
423 case EE_CHAR_FONTHEIGHT
:
424 case EE_CHAR_FONTHEIGHT_CJK
:
425 case EE_CHAR_FONTHEIGHT_CTL
:
428 pPoolItem
.reset(new SvxFontHeightItem(240, 100, pEntry
->mnItemID
));
430 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
434 case EE_CHAR_ITALIC_CJK
:
435 case EE_CHAR_ITALIC_CTL
:
438 pPoolItem
.reset(new SvxPostureItem(ITALIC_NONE
, pEntry
->mnItemID
));
440 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
443 case EE_CHAR_UNDERLINE
:
446 pPoolItem
.reset(new SvxUnderlineItem(LINESTYLE_NONE
, pEntry
->mnItemID
));
448 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
451 case EE_CHAR_OVERLINE
:
454 pPoolItem
.reset(new SvxOverlineItem(LINESTYLE_NONE
, pEntry
->mnItemID
));
456 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
462 pPoolItem
.reset(new SvxColorItem(pEntry
->mnItemID
));
464 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
470 pPoolItem
.reset(new SvxWordLineModeItem(false, pEntry
->mnItemID
));
472 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
475 case EE_CHAR_STRIKEOUT
:
478 pPoolItem
.reset(new SvxCrossedOutItem(STRIKEOUT_NONE
, pEntry
->mnItemID
));
480 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
486 pPoolItem
.reset(new SvxCharReliefItem(FontRelief::NONE
, pEntry
->mnItemID
));
488 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
491 case EE_CHAR_OUTLINE
:
494 pPoolItem
.reset(new SvxContourItem(false, pEntry
->mnItemID
));
496 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
502 pPoolItem
.reset(new SvxShadowedItem(false, pEntry
->mnItemID
));
504 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
507 case EE_CHAR_KERNING
:
510 pPoolItem
.reset(new SvxKerningItem(0, pEntry
->mnItemID
));
512 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
515 case EE_CHAR_PAIRKERNING
:
518 pPoolItem
.reset(new SvxAutoKernItem(false, pEntry
->mnItemID
));
520 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
523 case EE_CHAR_FONTWIDTH
:
526 pPoolItem
.reset(new SvxCharScaleWidthItem(100, pEntry
->mnItemID
));
528 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
531 case EE_CHAR_ESCAPEMENT
:
534 pPoolItem
.reset(new SvxEscapementItem(pEntry
->mnItemID
));
536 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
539 case EE_CHAR_EMPHASISMARK
:
542 pPoolItem
.reset(new SvxEmphasisMarkItem(FontEmphasisMark::NONE
, pEntry
->mnItemID
));
544 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
547 case EE_CHAR_LANGUAGE
:
548 case EE_CHAR_LANGUAGE_CJK
:
549 case EE_CHAR_LANGUAGE_CTL
:
552 pPoolItem
.reset(new SvxLanguageItem(LANGUAGE_DONTKNOW
, pEntry
->mnItemID
));
554 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
561 nLastItemID
= pEntry
->mnItemID
;
565 rFmt
.maItemSet
.Put(std::move(pPoolItem
));
568 OUString
ScXMLTableRowCellContext::GetFirstParagraph() const
570 if (!maFirstParagraph
)
571 return mpEditEngine
->GetText(0);
573 return *maFirstParagraph
;
576 void ScXMLTableRowCellContext::PushParagraphFieldDate(const OUString
& rStyleName
)
578 PushParagraphField(std::make_unique
<SvxDateField
>(), rStyleName
);
581 void ScXMLTableRowCellContext::PushParagraphFieldSheetName(const OUString
& rStyleName
)
583 SCTAB nTab
= GetScImport().GetTables().GetCurrentCellPos().Tab();
584 PushParagraphField(std::make_unique
<SvxTableField
>(nTab
), rStyleName
);
587 void ScXMLTableRowCellContext::PushParagraphFieldDocTitle(const OUString
& rStyleName
)
589 PushParagraphField(std::make_unique
<SvxFileField
>(), rStyleName
);
592 void ScXMLTableRowCellContext::PushParagraphFieldURL(
593 const OUString
& rURL
, const OUString
& rRep
, const OUString
& rStyleName
, const OUString
& rTargetFrame
)
595 OUString aAbsURL
= GetScImport().GetAbsoluteReference(rURL
);
596 std::unique_ptr
<SvxURLField
> pURLField(new SvxURLField(aAbsURL
, rRep
, SvxURLFormat::Repr
));
597 pURLField
->SetTargetFrame(rTargetFrame
);
598 PushParagraphField(std::move(pURLField
), rStyleName
);
601 void ScXMLTableRowCellContext::PushParagraphEnd()
603 // EditEngine always has at least one paragraph even when its content is empty.
605 if (mbEditEngineHasText
)
607 if (maFirstParagraph
)
609 // Flush the cached first paragraph first.
610 mpEditEngine
->Clear();
611 mpEditEngine
->SetTextCurrentDefaults(*maFirstParagraph
);
612 maFirstParagraph
.reset();
614 mpEditEngine
->InsertParagraph(mpEditEngine
->GetParagraphCount(), maParagraph
.makeStringAndClear());
616 else if (mbHasFormatRuns
|| ScStringUtil::isMultiline(maParagraph
))
618 mpEditEngine
->Clear();
619 mpEditEngine
->SetTextCurrentDefaults(maParagraph
.makeStringAndClear());
620 mbEditEngineHasText
= true;
622 else if (mnCurParagraph
== 0)
624 maFirstParagraph
= maParagraph
.makeStringAndClear();
625 mbEditEngineHasText
= true;
631 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
ScXMLTableRowCellContext::createFastChildContext(
632 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
634 SvXMLImportContext
*pContext
= nullptr;
635 sax_fastparser::FastAttributeList
*pAttribList
=
636 &sax_fastparser::castToFastAttributeList( xAttrList
);
641 case XML_ELEMENT( TEXT
, XML_P
):
646 pContext
= new ScXMLCellTextParaContext(rXMLImport
, *this);
649 case XML_ELEMENT( TABLE
, XML_SUB_TABLE
):
651 SAL_WARN("sc", "ScXMLTableRowCellContext::createFastChildContext: subtables are not supported");
654 case XML_ELEMENT( TABLE
, XML_DETECTIVE
):
657 if (!pDetectiveObjVec
)
658 pDetectiveObjVec
.reset( new ScMyImpDetectiveObjVec
);
659 pContext
= new ScXMLDetectiveContext(
660 rXMLImport
, pDetectiveObjVec
.get() );
663 case XML_ELEMENT( TABLE
, XML_CELL_RANGE_SOURCE
):
666 if (!pCellRangeSource
)
667 pCellRangeSource
.reset(new ScMyImpCellRangeSource());
668 pContext
= new ScXMLCellRangeSourceContext(
669 rXMLImport
, pAttribList
, pCellRangeSource
.get() );
672 case XML_ELEMENT(OFFICE
, XML_ANNOTATION
):
677 "ScXMLTableRowCellContext::CreateChildContext - multiple annotations in one cell");
678 mxAnnotationData
.reset( new ScXMLAnnotationData
);
679 pContext
= new ScXMLAnnotationContext( rXMLImport
, nElement
,
680 xAttrList
, *mxAnnotationData
);
685 if (!pContext
&& !bTextP
)
687 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
688 uno::Reference
<drawing::XShapes
> xShapes (rXMLImport
.GetTables().GetCurrentXShapes());
691 ScDocument
* pDoc
= rXMLImport
.GetDocument();
692 if (aCellPos
.Col() > pDoc
->MaxCol())
693 aCellPos
.SetCol(pDoc
->MaxCol());
694 if (aCellPos
.Row() > pDoc
->MaxRow())
695 aCellPos
.SetRow(pDoc
->MaxRow());
696 XMLTableShapeImportHelper
* pTableShapeImport
=
697 static_cast< XMLTableShapeImportHelper
* >( rXMLImport
.GetShapeImport().get() );
698 pTableShapeImport
->SetOnTable(false);
699 pTableShapeImport
->SetCell(aCellPos
);
700 pContext
= XMLShapeImportHelper::CreateGroupChildContext(
701 rXMLImport
, nElement
, xAttrList
, xShapes
);
705 rXMLImport
.ProgressBarIncrement();
713 void ScXMLTableRowCellContext::DoMerge( const ScAddress
& rScAddress
, const SCCOL nCols
, const SCROW nRows
)
715 SCCOL mergeToCol
= rScAddress
.Col() + nCols
;
716 SCROW mergeToRow
= rScAddress
.Row() + nRows
;
717 ScDocument
* pDoc
= rXMLImport
.GetDocument();
718 bool bInBounds
= rScAddress
.Col() <= pDoc
->MaxCol() && rScAddress
.Row() <= pDoc
->MaxRow() &&
719 mergeToCol
<= pDoc
->MaxCol() && mergeToRow
<= pDoc
->MaxRow();
722 pDoc
->DoMerge( rScAddress
.Col(), rScAddress
.Row(),
723 mergeToCol
, mergeToRow
, rScAddress
.Tab() );
729 ScValidationMode
validationTypeToMode( const sheet::ValidationType eVType
)
731 ScValidationMode eMode
;
734 case sheet::ValidationType_WHOLE
: eMode
= SC_VALID_WHOLE
; break;
735 case sheet::ValidationType_DECIMAL
: eMode
= SC_VALID_DECIMAL
; break;
736 case sheet::ValidationType_DATE
: eMode
= SC_VALID_DATE
; break;
737 case sheet::ValidationType_TIME
: eMode
= SC_VALID_TIME
; break;
738 case sheet::ValidationType_TEXT_LEN
: eMode
= SC_VALID_TEXTLEN
; break;
739 case sheet::ValidationType_LIST
: eMode
= SC_VALID_LIST
; break;
740 case sheet::ValidationType_CUSTOM
: eMode
= SC_VALID_CUSTOM
; break;
741 default: eMode
= SC_VALID_ANY
; break;
746 ScValidErrorStyle
validAlertToValidError( const sheet::ValidationAlertStyle eVAlertStyle
)
748 ScValidErrorStyle eVErrStyle
;
749 switch( eVAlertStyle
)
751 case sheet::ValidationAlertStyle_STOP
: eVErrStyle
= SC_VALERR_STOP
; break;
752 case sheet::ValidationAlertStyle_WARNING
: eVErrStyle
= SC_VALERR_WARNING
; break;
753 case sheet::ValidationAlertStyle_MACRO
: eVErrStyle
= SC_VALERR_MACRO
; break;
754 default: eVErrStyle
= SC_VALERR_INFO
; break;
755 //should INFO be the default? seems to be the most unobtrusive choice.
762 void ScXMLTableRowCellContext::SetContentValidation( const ScRange
& rScRange
)
764 if (!maContentValidationName
)
767 ScDocument
* pDoc
= rXMLImport
.GetDocument();
768 ScMyImportValidation aValidation
;
769 aValidation
.eGrammar1
= aValidation
.eGrammar2
= pDoc
->GetStorageGrammar();
770 if( !rXMLImport
.GetValidation(*maContentValidationName
, aValidation
) )
773 ScValidationData
aScValidationData(
774 validationTypeToMode(aValidation
.aValidationType
),
775 ScConditionEntry::GetModeFromApi(aValidation
.aOperator
),
776 aValidation
.sFormula1
, aValidation
.sFormula2
, *pDoc
, ScAddress(),
777 aValidation
.sFormulaNmsp1
, aValidation
.sFormulaNmsp2
,
778 aValidation
.eGrammar1
, aValidation
.eGrammar2
781 aScValidationData
.SetIgnoreBlank( aValidation
.bIgnoreBlanks
);
782 aScValidationData
.SetListType( aValidation
.nShowList
);
784 // set strings for error / input even if disabled (and disable afterwards)
785 aScValidationData
.SetInput( aValidation
.sInputTitle
, aValidation
.sInputMessage
);
786 if( !aValidation
.bShowInputMessage
)
787 aScValidationData
.ResetInput();
788 aScValidationData
.SetError( aValidation
.sErrorTitle
, aValidation
.sErrorMessage
, validAlertToValidError(aValidation
.aAlertStyle
) );
789 if( !aValidation
.bShowErrorMessage
)
790 aScValidationData
.ResetError();
792 if( !aValidation
.sBaseCellAddress
.isEmpty() )
793 aScValidationData
.SetSrcString( aValidation
.sBaseCellAddress
);
795 sal_uInt32 nIndex
= pDoc
->AddValidationEntry( aScValidationData
);
797 ScPatternAttr
aPattern( pDoc
->GetPool() );
798 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA
, nIndex
) );
799 if( rScRange
.aStart
== rScRange
.aEnd
) //for a single cell
801 pDoc
->ApplyPattern( rScRange
.aStart
.Col(), rScRange
.aStart
.Row(),
802 rScRange
.aStart
.Tab(), aPattern
);
804 else //for repeating cells
806 pDoc
->ApplyPatternAreaTab( rScRange
.aStart
.Col(), rScRange
.aStart
.Row(),
807 rScRange
.aEnd
.Col(), rScRange
.aEnd
.Row(),
808 rScRange
.aStart
.Tab(), aPattern
);
811 // is the below still needed?
812 // For now, any sheet with validity is blocked from stream-copying.
813 // Later, the validation names could be stored along with the style names.
814 ScSheetSaveData
* pSheetData
= comphelper::getFromUnoTunnel
<ScModelObj
>(GetImport().GetModel())->GetSheetSaveData();
815 pSheetData
->BlockSheet( GetScImport().GetTables().GetCurrentSheet() );
818 void ScXMLTableRowCellContext::SetContentValidation( const ScAddress
& rCellPos
)
820 SetContentValidation( ScRange(rCellPos
, rCellPos
) );
823 void ScXMLTableRowCellContext::SetAnnotation(const ScAddress
& rPos
)
825 ScDocument
* pDoc
= rXMLImport
.GetDocument();
826 if (!pDoc
|| !mxAnnotationData
)
831 ScPostIt
* pNote
= nullptr;
833 uno::Reference
< drawing::XShapes
> xShapes
= rXMLImport
.GetTables().GetCurrentXShapes();
834 sal_Int32 nOldShapeCount
= xShapes
.is() ? xShapes
->getCount() : 0;
836 OSL_ENSURE( !mxAnnotationData
->mxShape
.is() || mxAnnotationData
->mxShapes
.is(),
837 "ScXMLTableRowCellContext::SetAnnotation - shape without drawing page" );
838 if( mxAnnotationData
->mxShape
.is() && mxAnnotationData
->mxShapes
.is() )
840 OSL_ENSURE( mxAnnotationData
->mxShapes
.get() == xShapes
.get(), "ScXMLTableRowCellContext::SetAnnotation - different drawing pages" );
841 SdrObject
* pObject
= SdrObject::getSdrObjectFromXShape(mxAnnotationData
->mxShape
);
842 OSL_ENSURE( pObject
, "ScXMLTableRowCellContext::SetAnnotation - cannot get SdrObject from shape" );
844 /* Try to reuse the drawing object already created (but only if the
845 note is visible, and the object is a caption object). */
846 if( mxAnnotationData
->mbShown
&& mxAnnotationData
->mbUseShapePos
&& !comphelper::LibreOfficeKit::isActive())
848 if( SdrCaptionObj
* pCaption
= dynamic_cast< SdrCaptionObj
* >( pObject
) )
850 OSL_ENSURE( !pCaption
->GetLogicRect().IsEmpty(), "ScXMLTableRowCellContext::SetAnnotation - invalid caption rectangle" );
851 // create the cell note with the caption object
852 pNote
= ScNoteUtil::CreateNoteFromCaption( *pDoc
, rPos
, pCaption
);
853 // forget pointer to object (do not create note again below)
858 // drawing object has not been used to create a note -> use shape data
861 // rescue settings from drawing object before the shape is removed
862 SfxItemSet
aItemSet( pObject
->GetMergedItemSet() );
863 std::optional
<OutlinerParaObject
> pOutlinerObj
;
864 if (auto p
= pObject
->GetOutlinerParaObject())
866 tools::Rectangle aCaptionRect
;
867 if( mxAnnotationData
->mbUseShapePos
)
868 aCaptionRect
= pObject
->GetLogicRect();
869 // remove the shape from the drawing page, this invalidates pObject
870 mxAnnotationData
->mxShapes
->remove( mxAnnotationData
->mxShape
);
872 // update current number of existing objects
874 nOldShapeCount
= xShapes
->getCount();
876 // an outliner object is required (empty note captions not allowed)
879 // create cell note with all data from drawing object
880 if(!comphelper::LibreOfficeKit::isActive())
882 pNote
= ScNoteUtil::CreateNoteFromObjectData( *pDoc
, rPos
,
883 std::move(aItemSet
), *pOutlinerObj
,
884 aCaptionRect
, mxAnnotationData
->mbShown
);
888 pNote
= ScNoteUtil::CreateNoteFromObjectData( *pDoc
, rPos
,
889 std::move(aItemSet
), *pOutlinerObj
,
890 aCaptionRect
, false );
896 else if( !mxAnnotationData
->maSimpleText
.isEmpty() )
898 // create note from simple text
899 pNote
= ScNoteUtil::CreateNoteFromString( *pDoc
, rPos
,
900 mxAnnotationData
->maSimpleText
, mxAnnotationData
->mbShown
, false );
903 // set author and date
907 if (rXMLImport
.GetMM100UnitConverter().convertDateTime(fDate
, mxAnnotationData
->maCreateDate
))
909 SvNumberFormatter
* pNumForm
= pDoc
->GetFormatTable();
910 sal_uInt32 nfIndex
= pNumForm
->GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, LANGUAGE_SYSTEM
);
912 const Color
* pColor
= nullptr;
913 pNumForm
->GetOutputString( fDate
, nfIndex
, aDate
, &pColor
);
914 pNote
->SetDate( aDate
);
916 pNote
->SetAuthor( mxAnnotationData
->maAuthor
);
919 // register a shape that has been newly created in the ScNoteUtil functions
920 if( xShapes
.is() && (nOldShapeCount
< xShapes
->getCount()) )
922 uno::Reference
< drawing::XShape
> xShape
;
923 rXMLImport
.GetShapeImport()->shapeWithZIndexAdded( xShape
, xShapes
->getCount() );
926 // store the style names for stream copying
927 ScSheetSaveData
* pSheetData
= comphelper::getFromUnoTunnel
<ScModelObj
>(rXMLImport
.GetModel())->GetSheetSaveData();
928 pSheetData
->HandleNoteStyles( mxAnnotationData
->maStyleName
, mxAnnotationData
->maTextStyle
, rPos
);
930 for (const auto& rContentStyle
: mxAnnotationData
->maContentStyles
)
932 pSheetData
->AddNoteContentStyle( rContentStyle
.mnFamily
, rContentStyle
.maName
, rPos
, rContentStyle
.maSelection
);
936 // core implementation
937 void ScXMLTableRowCellContext::SetDetectiveObj( const ScAddress
& rPosition
)
939 ScDocument
* pDoc
= rXMLImport
.GetDocument();
940 if( !pDoc
|| !cellExists(*pDoc
, rPosition
) || !pDetectiveObjVec
|| pDetectiveObjVec
->empty() )
944 ScDetectiveFunc
aDetFunc( *pDoc
, rPosition
.Tab() );
945 uno::Reference
<container::XIndexAccess
> xShapesIndex
= rXMLImport
.GetTables().GetCurrentXShapes(); // make draw page
946 for(const auto& rDetectiveObj
: *pDetectiveObjVec
)
948 aDetFunc
.InsertObject( rDetectiveObj
.eObjType
, rPosition
, rDetectiveObj
.aSourceRange
, rDetectiveObj
.bHasError
);
949 if (xShapesIndex
.is())
951 sal_Int32 nShapes
= xShapesIndex
->getCount();
952 uno::Reference
< drawing::XShape
> xShape
;
953 rXMLImport
.GetShapeImport()->shapeWithZIndexAdded(xShape
, nShapes
);
958 // core implementation
959 void ScXMLTableRowCellContext::SetCellRangeSource( const ScAddress
& rPosition
)
961 ScDocument
* pDoc
= rXMLImport
.GetDocument();
962 if( !pDoc
|| !cellExists(*pDoc
, rPosition
) || !pCellRangeSource
|| pCellRangeSource
->sSourceStr
.isEmpty() ||
963 pCellRangeSource
->sFilterName
.isEmpty() || pCellRangeSource
->sURL
.isEmpty() )
967 ScRange
aDestRange( rPosition
.Col(), rPosition
.Row(), rPosition
.Tab(),
968 rPosition
.Col() + static_cast<SCCOL
>(pCellRangeSource
->nColumns
- 1),
969 rPosition
.Row() + static_cast<SCROW
>(pCellRangeSource
->nRows
- 1), rPosition
.Tab() );
970 OUString
sFilterName( pCellRangeSource
->sFilterName
);
971 OUString
sSourceStr( pCellRangeSource
->sSourceStr
);
972 ScAreaLink
* pLink
= new ScAreaLink( pDoc
->GetDocumentShell(), pCellRangeSource
->sURL
,
973 sFilterName
, pCellRangeSource
->sFilterOptions
, sSourceStr
, aDestRange
, pCellRangeSource
->nRefresh
);
974 sfx2::LinkManager
* pLinkManager
= pDoc
->GetLinkManager();
975 pLinkManager
->InsertFileLink( *pLink
, sfx2::SvBaseLinkObjectType::ClientFile
, pCellRangeSource
->sURL
, &sFilterName
, &sSourceStr
);
978 void ScXMLTableRowCellContext::SetFormulaCell(ScFormulaCell
* pFCell
) const
983 bool bMayForceNumberformat
= true;
987 // don't do anything here
988 // we need to recalc anyway
990 else if( bFormulaTextResult
&& maStringValue
)
992 if( !IsPossibleErrorString() )
994 ScDocument
* pDoc
= rXMLImport
.GetDocument();
995 pFCell
->SetHybridString(pDoc
->GetSharedStringPool().intern(*maStringValue
));
996 pFCell
->ResetDirty();
997 // A General format doesn't force any other format for a string
998 // result, don't attempt to recalculate this later.
999 bMayForceNumberformat
= false;
1002 else if (std::isfinite(fValue
))
1004 pFCell
->SetHybridDouble(fValue
);
1005 if (mbPossibleEmptyDisplay
&& fValue
== 0.0)
1007 // Needs to be recalculated to propagate, otherwise would be
1008 // propagated as empty string. So don't ResetDirty().
1009 pFCell
->SetHybridEmptyDisplayedAsString();
1012 pFCell
->ResetDirty();
1015 if (bMayForceNumberformat
)
1016 // Re-calculate to get number format only when style is not set.
1017 pFCell
->SetNeedNumberFormat(!mbHasStyle
);
1020 void ScXMLTableRowCellContext::PutTextCell( const ScAddress
& rCurrentPos
,
1021 const SCCOL nCurrentCol
, const ::std::optional
< OUString
>& pOUText
)
1023 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1024 bool bDoIncrement
= true;
1025 //matrix reference cells that contain text formula results;
1026 //cell was already put in document, just need to set text here.
1027 if( pDoc
&& rXMLImport
.GetTables().IsPartOfMatrix(rCurrentPos
) )
1029 ScRefCellValue
aCell(*pDoc
, rCurrentPos
);
1030 bDoIncrement
= aCell
.getType() == CELLTYPE_FORMULA
;
1033 ScFormulaCell
* pFCell
= aCell
.getFormula();
1034 OUString aCellString
;
1036 aCellString
= *maStringValue
;
1037 else if (mbEditEngineHasText
)
1038 aCellString
= GetFirstParagraph();
1039 else if ( nCurrentCol
> 0 && pOUText
&& !pOUText
->isEmpty() )
1040 aCellString
= *pOUText
;
1042 bDoIncrement
= false;
1045 bDoIncrement
= false;
1047 if(!aCellString
.isEmpty())
1049 if (bDoIncrement
&& !IsPossibleErrorString() && pFCell
)
1051 pFCell
->SetHybridString(pDoc
->GetSharedStringPool().intern(aCellString
));
1052 pFCell
->ResetDirty();
1056 ScAddress aTopLeftMatrixCell
;
1057 if (pFCell
&& pFCell
->GetMatrixOrigin(*pDoc
, aTopLeftMatrixCell
))
1059 ScFormulaCell
* pMatrixCell
= pDoc
->GetFormulaCell(aTopLeftMatrixCell
);
1061 pMatrixCell
->SetDirty();
1064 SAL_WARN("sc", "matrix cell without matrix");
1069 else //regular text cells
1071 ScDocumentImport
& rDoc
= rXMLImport
.GetDoc();
1074 rDoc
.setStringCell(rCurrentPos
, *maStringValue
);
1075 bDoIncrement
= true;
1077 else if (mbEditEngineHasText
)
1079 if (maFirstParagraph
)
1081 // This is a normal text without format runs.
1082 rDoc
.setStringCell(rCurrentPos
, *maFirstParagraph
);
1086 // This text either has format runs, has field(s), or consists of multiple lines.
1087 for (const auto& rxFormat
: maFormats
)
1088 mpEditEngine
->QuickSetAttribs(rxFormat
->maItemSet
, rxFormat
->maSelection
);
1090 for (const auto& rxField
: maFields
)
1091 mpEditEngine
->QuickInsertField(SvxFieldItem(*rxField
->mpData
, EE_FEATURE_FIELD
), rxField
->maSelection
);
1093 // This edit engine uses the SfxItemPool instance returned
1094 // from pDoc->GetEditPool() to create the text object, which
1095 // is a prerequisite for using this constructor of ScEditCell.
1096 rDoc
.setEditCell(rCurrentPos
, mpEditEngine
->CreateTextObject());
1098 bDoIncrement
= true;
1100 else if ( nCurrentCol
> 0 && pOUText
&& !pOUText
->isEmpty() )
1102 rDoc
.setStringCell(rCurrentPos
, *pOUText
);
1103 bDoIncrement
= true;
1106 bDoIncrement
= false;
1109 // #i56027# This is about setting simple text, not edit cells,
1110 // so ProgressBarIncrement must be called with bEditCell = FALSE.
1111 // Formatted text that is put into the cell by the child context
1112 // is handled in AddCellsToTable() (bIsEmpty is true then).
1114 rXMLImport
.ProgressBarIncrement();
1117 void ScXMLTableRowCellContext::PutValueCell( const ScAddress
& rCurrentPos
)
1119 //matrix reference cells that contain value formula results;
1120 //cell was already put in document, just need to set value here.
1121 if( rXMLImport
.GetTables().IsPartOfMatrix(rCurrentPos
) )
1123 ScRefCellValue
aCell(*rXMLImport
.GetDocument(), rCurrentPos
);
1124 if (aCell
.getType() == CELLTYPE_FORMULA
)
1126 ScFormulaCell
* pFCell
= aCell
.getFormula();
1127 SetFormulaCell(pFCell
);
1129 pFCell
->SetNeedNumberFormat( true );
1132 else //regular value cell
1134 // fdo#62250 absent values are not NaN, set to 0.0
1135 // PutValueCell() is called only for a known cell value type,
1136 // bIsEmpty==false in all these cases, no sense to check it here.
1137 if (!std::isfinite( fValue
))
1140 // #i62435# Initialize the value cell's script type if the default
1141 // style's number format is latin-only. If the cell uses a different
1142 // format, the script type will be reset when the style is applied.
1144 rXMLImport
.GetDoc().setNumericCell(rCurrentPos
, fValue
);
1146 rXMLImport
.ProgressBarIncrement();
1151 bool isEmptyOrNote( const ScDocument
* pDoc
, const ScAddress
& rCurrentPos
)
1153 CellType eType
= pDoc
->GetCellType(rCurrentPos
);
1154 return (eType
== CELLTYPE_NONE
);
1159 void ScXMLTableRowCellContext::AddTextAndValueCell( const ScAddress
& rCellPos
,
1160 const ::std::optional
< OUString
>& pOUText
, ScAddress
& rCurrentPos
)
1162 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1163 ScMyTables
& rTables
= rXMLImport
.GetTables();
1164 bool bWasEmpty
= bIsEmpty
;
1165 for (SCCOL i
= 0; i
< nColsRepeated
; ++i
)
1167 rCurrentPos
.SetCol( rCellPos
.Col() + i
);
1169 // it makes no sense to import data after the last supported column
1170 // fdo#58539 & gnome#627150
1171 if(rCurrentPos
.Col() > pDoc
->MaxCol())
1173 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW
);
1178 rTables
.AddColumn(false);
1181 for (SCROW j
= 0; j
< nRepeatedRows
; ++j
)
1183 rCurrentPos
.SetRow( rCellPos
.Row() + j
);
1185 // it makes no sense to import data after last supported row
1186 // fdo#58539 & gnome#627150
1187 if(rCurrentPos
.Row() > pDoc
->MaxRow())
1189 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW
);
1193 if( (rCurrentPos
.Col() == 0) && (j
> 0) )
1196 rTables
.AddColumn(false);
1198 if( cellExists(*pDoc
, rCurrentPos
) )
1200 if( !bIsCovered
|| isEmptyOrNote(pDoc
, rCurrentPos
) )
1204 case util::NumberFormat::TEXT
:
1206 PutTextCell( rCurrentPos
, i
, pOUText
);
1209 case util::NumberFormat::NUMBER
:
1210 case util::NumberFormat::PERCENT
:
1211 case util::NumberFormat::CURRENCY
:
1212 case util::NumberFormat::TIME
:
1213 case util::NumberFormat::DATETIME
:
1214 case util::NumberFormat::LOGICAL
:
1216 PutValueCell( rCurrentPos
);
1221 OSL_FAIL("no cell type given");
1227 SetAnnotation( rCurrentPos
);
1228 SetDetectiveObj( rCurrentPos
);
1229 SetCellRangeSource( rCurrentPos
);
1233 if (!bWasEmpty
|| mxAnnotationData
)
1235 if (rCurrentPos
.Row() > pDoc
->MaxRow())
1236 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW
);
1238 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW
);
1245 if ((i
== 0) && (rCellPos
.Col() == 0))
1247 for (sal_Int32 j
= 1; j
< nRepeatedRows
; ++j
)
1250 rTables
.AddColumn(false);
1257 bool ScXMLTableRowCellContext::CellsAreRepeated() const
1259 return ( (nColsRepeated
> 1) || (nRepeatedRows
> 1) );
1264 // from ScCellObj::GetOutputString_Imp(). all of it may not be necessary.
1265 OUString
getOutputString( ScDocument
* pDoc
, const ScAddress
& aCellPos
)
1270 ScRefCellValue
aCell(*pDoc
, aCellPos
);
1271 switch (aCell
.getType())
1277 // GetString on EditCell replaces linebreaks with spaces;
1278 // however here we need line breaks
1279 const EditTextObject
* pData
= aCell
.getEditText();
1280 EditEngine
& rEngine
= pDoc
->GetEditEngine();
1281 rEngine
.SetText(*pData
);
1282 return rEngine
.GetText();
1283 // also don't format EditCells per NumberFormatter
1288 // like in GetString for document (column)
1289 const Color
* pColor
;
1290 sal_uInt32 nNumFmt
= pDoc
->GetNumberFormat(aCellPos
);
1291 return ScCellFormat::GetString(aCell
, nNumFmt
, &pColor
, *pDoc
->GetFormatTable(), *pDoc
);
1298 void ScXMLTableRowCellContext::AddNonFormulaCell( const ScAddress
& rCellPos
)
1300 ::std::optional
< OUString
> pOUText
;
1302 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1303 if( nCellType
== util::NumberFormat::TEXT
)
1305 if( !bIsEmpty
&& !maStringValue
&& !mbEditEngineHasText
&& cellExists(*pDoc
, rCellPos
) && CellsAreRepeated() )
1306 pOUText
= getOutputString(pDoc
, rCellPos
);
1308 if (!mbEditEngineHasText
&& !pOUText
&& !maStringValue
)
1312 ScAddress
aCurrentPos( rCellPos
);
1313 if( mxAnnotationData
|| pDetectiveObjVec
|| pCellRangeSource
) // has special content
1316 AddTextAndValueCell( rCellPos
, pOUText
, aCurrentPos
);
1318 if( CellsAreRepeated() )
1320 SCCOL
nStartCol( std::min(rCellPos
.Col(), pDoc
->MaxCol()) );
1321 SCROW
nStartRow( std::min(rCellPos
.Row(), pDoc
->MaxRow()) );
1322 SCCOL
nEndCol( std::min
<SCCOL
>(rCellPos
.Col() + nColsRepeated
- 1, pDoc
->MaxCol()) );
1323 SCROW
nEndRow( std::min(rCellPos
.Row() + nRepeatedRows
- 1, pDoc
->MaxRow()) );
1324 ScRange
aScRange( nStartCol
, nStartRow
, rCellPos
.Tab(), nEndCol
, nEndRow
, rCellPos
.Tab() );
1325 SetContentValidation( aScRange
);
1326 rXMLImport
.GetStylesImportHelper()->AddRange( aScRange
);
1328 else if( cellExists(*pDoc
, rCellPos
) )
1330 rXMLImport
.GetStylesImportHelper()->AddCell(rCellPos
);
1331 SetContentValidation( rCellPos
);
1335 void ScXMLTableRowCellContext::PutFormulaCell( const ScAddress
& rCellPos
)
1337 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1338 ScDocumentImport
& rDocImport
= rXMLImport
.GetDoc();
1340 const OUString
& aText
= maFormula
->first
;
1342 ScExternalRefManager::ApiGuard
aExtRefGuard(*pDoc
);
1344 if ( aText
.isEmpty() )
1347 // temporary formula string as string tokens
1348 std::unique_ptr
<ScTokenArray
> pCode(new ScTokenArray(*pDoc
));
1350 // Check the special case of a single error constant without leading
1351 // '=' and create an error formula cell without tokens.
1352 FormulaError nError
= GetScImport().GetFormulaErrorConstant(aText
);
1353 if (nError
!= FormulaError::NONE
)
1355 pCode
->SetCodeError(nError
);
1359 // 5.2 and earlier wrote broken "Err:xxx" as formula to designate
1360 // an error formula cell.
1361 if (aText
.startsWithIgnoreAsciiCase("Err:") && aText
.getLength() <= 9 &&
1363 GetScImport().GetFormulaErrorConstant( OUString::Concat("#ERR") + aText
.subView(4) + "!")) != FormulaError::NONE
))
1365 pCode
->SetCodeError(nError
);
1369 OUString aFormulaNmsp
= maFormula
->second
;
1370 if( eGrammar
!= formula::FormulaGrammar::GRAM_EXTERNAL
)
1371 aFormulaNmsp
.clear();
1372 pCode
->AssignXMLString( aText
, aFormulaNmsp
);
1373 rDocImport
.getDoc().IncXMLImportedFormulaCount( aText
.getLength() );
1377 ScFormulaCell
* pNewCell
= new ScFormulaCell(*pDoc
, rCellPos
, std::move(pCode
), eGrammar
, ScMatrixMode::NONE
);
1378 SetFormulaCell(pNewCell
);
1379 rDocImport
.setFormulaCell(rCellPos
, pNewCell
);
1382 void ScXMLTableRowCellContext::AddFormulaCell( const ScAddress
& rCellPos
)
1384 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1385 if( cellExists(*pDoc
, rCellPos
) )
1387 SetContentValidation( rCellPos
);
1388 SAL_WARN_IF((nColsRepeated
!= 1) || (nRepeatedRows
!= 1), "sc", "repeated cells with formula not possible now");
1389 rXMLImport
.GetStylesImportHelper()->AddCell(rCellPos
);
1394 if (nMatrixCols
> 0 && nMatrixRows
> 0)
1396 //matrix cells are put in the document, but we must set the
1397 //value/text of each matrix cell later
1398 rXMLImport
.GetTables().AddMatrixRange(
1399 rCellPos
.Col(), rCellPos
.Row(),
1400 std::min
<SCCOL
>(rCellPos
.Col() + nMatrixCols
- 1, pDoc
->MaxCol()),
1401 std::min
<SCROW
>(rCellPos
.Row() + nMatrixRows
- 1, pDoc
->MaxRow()),
1402 maFormula
->first
, maFormula
->second
, eGrammar
);
1404 // Set the value/text of the top-left matrix position in its
1405 // cached result. For import, we only need to set the correct
1406 // matrix geometry and the value type of the top-left element.
1407 ScFormulaCell
* pFCell
= pDoc
->GetFormulaCell(rCellPos
);
1410 ScMatrixRef
pMat(new ScMatrix(nMatrixCols
, nMatrixRows
));
1411 if (bFormulaTextResult
&& maStringValue
)
1413 if (!IsPossibleErrorString())
1415 pFCell
->SetResultMatrix(
1416 nMatrixCols
, nMatrixRows
, pMat
, new formula::FormulaStringToken(
1417 pDoc
->GetSharedStringPool().intern( *maStringValue
)));
1418 pFCell
->ResetDirty();
1421 else if (std::isfinite(fValue
))
1423 pFCell
->SetResultMatrix(
1424 nMatrixCols
, nMatrixRows
, pMat
, new formula::FormulaDoubleToken(fValue
));
1425 pFCell
->ResetDirty();
1431 PutFormulaCell( rCellPos
);
1433 SetAnnotation( rCellPos
);
1434 SetDetectiveObj( rCellPos
);
1435 SetCellRangeSource( rCellPos
);
1436 rXMLImport
.ProgressBarIncrement();
1440 if (rCellPos
.Row() > pDoc
->MaxRow())
1441 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW
);
1443 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW
);
1447 //There are cases where a formula cell is exported with an office:value of 0 or
1448 //no office:value at all, but the formula cell will have a text:p value which
1449 //contains the intended formula result.
1450 //These cases include when a formula result:
1452 // - has a constant error value beginning with "#" (such as "#VALUE!" or "#N/A")
1453 // - has an "Err:[###]" (where "[###]" is an error number)
1454 // Libreoffice 4.1+ with ODF1.2 extended write however calcext:value-type="error" in that case
1455 void ScXMLTableRowCellContext::HasSpecialCaseFormulaText()
1457 if (!mbEditEngineHasText
)
1460 const OUString aStr
= GetFirstParagraph();
1465 mbPossibleEmptyDisplay
= true;
1471 mbPossibleErrorCell
= true;
1472 mbPossibleEmptyDisplay
= true;
1474 else if (aStr
.startsWith("Err:"))
1475 mbPossibleErrorCell
= true;
1476 else if (aStr
.startsWith("#"))
1477 mbCheckWithCompilerForError
= true;
1480 bool ScXMLTableRowCellContext::IsPossibleErrorString() const
1482 if(mbNewValueType
&& !mbErrorValue
)
1484 else if(mbNewValueType
&& mbErrorValue
)
1486 return mbPossibleErrorCell
|| (mbCheckWithCompilerForError
&&
1487 GetScImport().GetFormulaErrorConstant(*maStringValue
) != FormulaError::NONE
);
1490 void SAL_CALL
ScXMLTableRowCellContext::endFastElement(sal_Int32
/*nElement*/)
1492 HasSpecialCaseFormulaText();
1493 if( bFormulaTextResult
&& (mbPossibleErrorCell
|| mbCheckWithCompilerForError
) )
1495 maStringValue
= GetFirstParagraph();
1498 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
1499 if( aCellPos
.Col() > 0 && nRepeatedRows
> 1 )
1500 aCellPos
.SetRow( aCellPos
.Row() - (nRepeatedRows
- 1) );
1502 DoMerge( aCellPos
, nMergedCols
- 1, nMergedRows
- 1 );
1505 AddFormulaCell(aCellPos
);
1507 AddNonFormulaCell(aCellPos
);
1509 //if LockSolarMutex got used, we presumably need to ensure an UnlockSolarMutex
1510 if (bSolarMutexLocked
)
1512 GetScImport().UnlockSolarMutex();
1513 bSolarMutexLocked
= false;
1522 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */