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 "xmlcelli.hxx"
22 #include "xmlimprt.hxx"
23 #include "xmlannoi.hxx"
25 #include <cellvalue.hxx>
26 #include <document.hxx>
29 #include <sheetdata.hxx>
30 #include <cellform.hxx>
31 #include <validat.hxx>
32 #include <patattr.hxx>
33 #include <scitems.hxx>
34 #include <docpool.hxx>
36 #include "XMLTableShapeImportHelper.hxx"
37 #include "XMLStylesImportHelper.hxx"
38 #include "celltextparacontext.hxx"
39 #include "XMLCellRangeSourceContext.hxx"
41 #include <arealink.hxx>
42 #include <sfx2/linkmgr.hxx>
43 #include <scerrors.hxx>
44 #include <editutil.hxx>
45 #include <formulacell.hxx>
46 #include "editattributemap.hxx"
47 #include <tokenarray.hxx>
48 #include <scmatrix.hxx>
49 #include <documentimport.hxx>
50 #include <externalrefmgr.hxx>
52 #include <xmloff/maptype.hxx>
53 #include <xmloff/xmltkmap.hxx>
54 #include <xmloff/xmltoken.hxx>
55 #include <xmloff/xmlprmap.hxx>
56 #include <xmloff/xmluconv.hxx>
57 #include <xmloff/families.hxx>
58 #include <xmloff/xmlnmspe.hxx>
59 #include <xmloff/prstylei.hxx>
60 #include <xmloff/xmlimppr.hxx>
61 #include <svl/zforlist.hxx>
62 #include <svx/svdocapt.hxx>
63 #include <editeng/eeitem.hxx>
64 #include <editeng/outlobj.hxx>
65 #include <editeng/wghtitem.hxx>
66 #include <editeng/colritem.hxx>
67 #include <editeng/fhgtitem.hxx>
68 #include <editeng/postitem.hxx>
69 #include <editeng/flditem.hxx>
70 #include <editeng/fontitem.hxx>
71 #include <editeng/udlnitem.hxx>
72 #include <editeng/wrlmitem.hxx>
73 #include <editeng/crossedoutitem.hxx>
74 #include <editeng/charreliefitem.hxx>
75 #include <editeng/charscaleitem.hxx>
76 #include <editeng/contouritem.hxx>
77 #include <editeng/shdditem.hxx>
78 #include <editeng/kernitem.hxx>
79 #include <editeng/autokernitem.hxx>
80 #include <editeng/escapementitem.hxx>
81 #include <editeng/emphasismarkitem.hxx>
82 #include <editeng/langitem.hxx>
83 #include <svx/unoapi.hxx>
84 #include <svl/sharedstringpool.hxx>
85 #include <sax/tools/converter.hxx>
86 #include <sax/fastattribs.hxx>
88 #include <com/sun/star/util/NumberFormat.hpp>
90 #include <com/sun/star/sheet/ValidationType.hpp>
91 #include <com/sun/star/sheet/ValidationAlertStyle.hpp>
93 #include <rtl/ustrbuf.hxx>
94 #include <sal/log.hxx>
95 #include <i18nlangtag/lang.h>
97 #include <comphelper/servicehelper.hxx>
99 using namespace com::sun::star
;
100 using namespace xmloff::token
;
102 ScXMLTableRowCellContext::ParaFormat::ParaFormat(ScEditEngineDefaulter
& rEditEngine
) :
103 maItemSet(rEditEngine
.GetEmptyItemSet()) {}
105 ScXMLTableRowCellContext::Field::Field(std::unique_ptr
<SvxFieldData
> pData
) : mpData(std::move(pData
)) {}
107 ScXMLTableRowCellContext::Field::~Field()
111 ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport
& rImport
,
112 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
113 const bool bTempIsCovered
,
114 const sal_Int32 nTempRepeatedRows
) :
115 ScXMLImportContext( rImport
),
116 mpEditEngine(GetScImport().GetEditEngine()),
121 nRepeatedRows(nTempRepeatedRows
),
126 eGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT
),
127 nCellType(util::NumberFormat::TEXT
),
130 bIsCovered(bTempIsCovered
),
132 mbNewValueType(false),
134 bSolarMutexLocked(false),
135 bFormulaTextResult(false),
136 mbPossibleErrorCell(false),
137 mbCheckWithCompilerForError(false),
138 mbEditEngineHasText(false),
139 mbHasFormatRuns(false),
141 mbPossibleEmptyDisplay(false)
143 rtl::math::setNan(&fValue
); // NaN by default
145 rXMLImport
.GetTables().AddColumn(bTempIsCovered
);
147 boost::optional
<OUString
> xStyleName
;
148 boost::optional
<OUString
> xCurrencySymbol
;
149 if ( rAttrList
.is() )
151 for (auto &it
: *rAttrList
)
153 switch ( it
.getToken() )
155 case XML_ELEMENT( TABLE
, XML_STYLE_NAME
):
156 xStyleName
= it
.toString();
159 case XML_ELEMENT( TABLE
, XML_CONTENT_VALIDATION_NAME
):
160 OSL_ENSURE(!maContentValidationName
, "here should be only one Validation Name");
162 maContentValidationName
= it
.toString();
164 case XML_ELEMENT( TABLE
, XML_NUMBER_ROWS_SPANNED
):
166 nMergedRows
= static_cast<SCROW
>(it
.toInt32());
168 case XML_ELEMENT( TABLE
, XML_NUMBER_COLUMNS_SPANNED
):
170 nMergedCols
= static_cast<SCCOL
>(it
.toInt32());
172 case XML_ELEMENT( TABLE
, XML_NUMBER_MATRIX_COLUMNS_SPANNED
):
174 nMatrixCols
= static_cast<SCCOL
>(it
.toInt32());
176 case XML_ELEMENT( TABLE
, XML_NUMBER_MATRIX_ROWS_SPANNED
):
178 nMatrixRows
= static_cast<SCROW
>(it
.toInt32());
180 case XML_ELEMENT( TABLE
, XML_NUMBER_COLUMNS_REPEATED
):
181 nColsRepeated
= static_cast<SCCOL
>(std::min
<sal_Int32
>( MAXCOLCOUNT
,
182 std::max( it
.toInt32(), static_cast<sal_Int32
>(1) ) ));
184 case XML_ELEMENT( OFFICE
, XML_VALUE_TYPE
):
185 nCellType
= ScXMLImport::GetCellType(it
.toCString(), it
.getLength());
188 case XML_ELEMENT( CALC_EXT
, XML_VALUE_TYPE
):
189 if(it
.isString( "error" ) )
192 nCellType
= ScXMLImport::GetCellType(it
.toCString(), it
.getLength());
194 mbNewValueType
= true;
196 case XML_ELEMENT( OFFICE
, XML_VALUE
):
200 fValue
= it
.toDouble();
203 //if office:value="0", let's get the text:p in case this is
204 //a special case in HasSpecialCaseFormulaText(). If it
205 //turns out not to be a special case, we'll use the 0 value.
207 bFormulaTextResult
= true;
211 case XML_ELEMENT( OFFICE
, XML_DATE_VALUE
):
213 if (!it
.isEmpty() && rXMLImport
.SetNullDateOnUnitConverter())
215 rXMLImport
.GetMM100UnitConverter().convertDateTime(fValue
, it
.toString());
220 case XML_ELEMENT( OFFICE
, XML_TIME_VALUE
):
224 ::sax::Converter::convertDuration(fValue
, it
.toString());
229 case XML_ELEMENT( OFFICE
, XML_STRING_VALUE
):
233 OSL_ENSURE(!maStringValue
, "here should be only one string value");
234 maStringValue
= it
.toString();
239 case XML_ELEMENT( OFFICE
, XML_BOOLEAN_VALUE
):
243 if ( IsXMLToken( it
, XML_TRUE
) )
245 else if ( IsXMLToken( it
, XML_FALSE
) )
248 fValue
= it
.toDouble();
253 case XML_ELEMENT( TABLE
, XML_FORMULA
):
257 OSL_ENSURE(!maFormula
, "here should be only one formula");
258 OUString aFormula
, aFormulaNmsp
;
259 rXMLImport
.ExtractFormulaNamespaceGrammar( aFormula
, aFormulaNmsp
, eGrammar
, it
.toString() );
260 maFormula
= FormulaWithNamespace(aFormula
, aFormulaNmsp
);
264 case XML_ELEMENT( OFFICE
, XML_CURRENCY
):
265 xCurrencySymbol
= it
.toString();
275 if (nCellType
== util::NumberFormat::TEXT
)
276 bFormulaTextResult
= true;
277 if(nCellType
== util::NumberFormat::DATETIME
)
278 nCellType
= util::NumberFormat::UNDEFINED
;
279 //if bIsEmpty is true at this point, then there is no office value.
280 //we must get the text:p (even if it is empty) in case this a special
281 //case in HasSpecialCaseFormulaText().
283 bFormulaTextResult
= true;
285 rXMLImport
.GetStylesImportHelper()->SetAttributes(std::move(xStyleName
), std::move(xCurrencySymbol
), nCellType
);
288 ScXMLTableRowCellContext::~ScXMLTableRowCellContext()
292 void ScXMLTableRowCellContext::LockSolarMutex()
294 if (!bSolarMutexLocked
)
296 GetScImport().LockSolarMutex();
297 bSolarMutexLocked
= true;
303 bool cellExists( const ScDocument
& rDoc
, const ScAddress
& rCellPos
)
305 return( rCellPos
.Col() >= 0 && rCellPos
.Row() >= 0 &&
306 rCellPos
.Col() <= rDoc
.MaxCol() && rCellPos
.Row() <= rDoc
.MaxRow() );
311 void ScXMLTableRowCellContext::PushParagraphSpan(const OUString
& rSpan
, const OUString
& rStyleName
)
313 sal_Int32 nBegin
= maParagraph
.getLength();
314 sal_Int32 nEnd
= nBegin
+ rSpan
.getLength();
315 maParagraph
.append(rSpan
);
317 PushFormat(nBegin
, nEnd
, rStyleName
);
320 void ScXMLTableRowCellContext::PushParagraphField(std::unique_ptr
<SvxFieldData
> pData
, const OUString
& rStyleName
)
322 mbHasFormatRuns
= true;
323 maFields
.push_back(std::make_unique
<Field
>(std::move(pData
)));
324 Field
& rField
= *maFields
.back();
326 sal_Int32 nPos
= maParagraph
.getLength();
327 maParagraph
.append('\1'); // Placeholder text for inserted field item.
328 rField
.maSelection
.nStartPara
= mnCurParagraph
;
329 rField
.maSelection
.nEndPara
= mnCurParagraph
;
330 rField
.maSelection
.nStartPos
= nPos
;
331 rField
.maSelection
.nEndPos
= nPos
+1;
333 PushFormat(nPos
, nPos
+1, rStyleName
);
336 void ScXMLTableRowCellContext::PushFormat(sal_Int32 nBegin
, sal_Int32 nEnd
, const OUString
& rStyleName
)
338 if (rStyleName
.isEmpty())
341 // Get the style information from xmloff.
342 rtl::Reference
<XMLPropertySetMapper
> xMapper
= GetImport().GetTextImport()->GetTextImportPropertySetMapper()->getPropertySetMapper();
344 // We can't do anything without the mapper.
347 sal_Int32 nEntryCount
= xMapper
->GetEntryCount();
349 SvXMLStylesContext
* pAutoStyles
= GetImport().GetAutoStyles();
353 // Style name for text span corresponds with the name of an automatic style.
354 const XMLPropStyleContext
* pStyle
= dynamic_cast<const XMLPropStyleContext
*>(
355 pAutoStyles
->FindStyleChildContext(XML_STYLE_FAMILY_TEXT_TEXT
, rStyleName
));
358 // No style by that name found.
361 const std::vector
<XMLPropertyState
>& rProps
= pStyle
->GetProperties();
365 const ScXMLEditAttributeMap
& rEditAttrMap
= GetScImport().GetEditAttributeMap();
367 mbHasFormatRuns
= true;
368 maFormats
.push_back(std::make_unique
<ParaFormat
>(*mpEditEngine
));
369 ParaFormat
& rFmt
= *maFormats
.back();
370 rFmt
.maSelection
.nStartPara
= rFmt
.maSelection
.nEndPara
= mnCurParagraph
;
371 rFmt
.maSelection
.nStartPos
= nBegin
;
372 rFmt
.maSelection
.nEndPos
= nEnd
;
374 // Store the used text styles for export.
375 ScSheetSaveData
* pSheetData
= comphelper::getUnoTunnelImplementation
<ScModelObj
>(rXMLImport
.GetModel())->GetSheetSaveData();
376 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
377 pSheetData
->AddTextStyle(rStyleName
, aCellPos
, rFmt
.maSelection
);
379 std::unique_ptr
<SfxPoolItem
> pPoolItem
;
380 sal_uInt16 nLastItemID
= EE_CHAR_END
+ 1;
382 for (const auto& rProp
: rProps
)
384 if (rProp
.mnIndex
== -1 || rProp
.mnIndex
>= nEntryCount
)
387 const OUString
& rName
= xMapper
->GetEntryAPIName(rProp
.mnIndex
);
388 const ScXMLEditAttributeMap::Entry
* pEntry
= rEditAttrMap
.getEntryByAPIName(rName
);
392 if (nLastItemID
!= pEntry
->mnItemID
&& pPoolItem
)
394 // Flush the last item when the item ID changes.
395 rFmt
.maItemSet
.Put(*pPoolItem
);
399 switch (pEntry
->mnItemID
)
401 case EE_CHAR_FONTINFO
:
402 case EE_CHAR_FONTINFO_CJK
:
403 case EE_CHAR_FONTINFO_CTL
:
405 // Font properties need to be consolidated into a single item.
407 pPoolItem
.reset(new SvxFontItem(pEntry
->mnItemID
));
409 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
413 case EE_CHAR_WEIGHT_CJK
:
414 case EE_CHAR_WEIGHT_CTL
:
417 pPoolItem
.reset(new SvxWeightItem(WEIGHT_NORMAL
, pEntry
->mnItemID
));
419 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
422 case EE_CHAR_FONTHEIGHT
:
423 case EE_CHAR_FONTHEIGHT_CJK
:
424 case EE_CHAR_FONTHEIGHT_CTL
:
427 pPoolItem
.reset(new SvxFontHeightItem(240, 100, pEntry
->mnItemID
));
429 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
433 case EE_CHAR_ITALIC_CJK
:
434 case EE_CHAR_ITALIC_CTL
:
437 pPoolItem
.reset(new SvxPostureItem(ITALIC_NONE
, pEntry
->mnItemID
));
439 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
442 case EE_CHAR_UNDERLINE
:
445 pPoolItem
.reset(new SvxUnderlineItem(LINESTYLE_NONE
, pEntry
->mnItemID
));
447 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
450 case EE_CHAR_OVERLINE
:
453 pPoolItem
.reset(new SvxOverlineItem(LINESTYLE_NONE
, pEntry
->mnItemID
));
455 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
461 pPoolItem
.reset(new SvxColorItem(pEntry
->mnItemID
));
463 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
469 pPoolItem
.reset(new SvxWordLineModeItem(false, pEntry
->mnItemID
));
471 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
474 case EE_CHAR_STRIKEOUT
:
477 pPoolItem
.reset(new SvxCrossedOutItem(STRIKEOUT_NONE
, pEntry
->mnItemID
));
479 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
485 pPoolItem
.reset(new SvxCharReliefItem(FontRelief::NONE
, pEntry
->mnItemID
));
487 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
490 case EE_CHAR_OUTLINE
:
493 pPoolItem
.reset(new SvxContourItem(false, pEntry
->mnItemID
));
495 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
501 pPoolItem
.reset(new SvxShadowedItem(false, pEntry
->mnItemID
));
503 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
506 case EE_CHAR_KERNING
:
509 pPoolItem
.reset(new SvxKerningItem(0, pEntry
->mnItemID
));
511 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
514 case EE_CHAR_PAIRKERNING
:
517 pPoolItem
.reset(new SvxAutoKernItem(false, pEntry
->mnItemID
));
519 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
522 case EE_CHAR_FONTWIDTH
:
525 pPoolItem
.reset(new SvxCharScaleWidthItem(100, pEntry
->mnItemID
));
527 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
530 case EE_CHAR_ESCAPEMENT
:
533 pPoolItem
.reset(new SvxEscapementItem(pEntry
->mnItemID
));
535 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
538 case EE_CHAR_EMPHASISMARK
:
541 pPoolItem
.reset(new SvxEmphasisMarkItem(FontEmphasisMark::NONE
, pEntry
->mnItemID
));
543 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
546 case EE_CHAR_LANGUAGE
:
547 case EE_CHAR_LANGUAGE_CJK
:
548 case EE_CHAR_LANGUAGE_CTL
:
551 pPoolItem
.reset(new SvxLanguageItem(LANGUAGE_DONTKNOW
, pEntry
->mnItemID
));
553 pPoolItem
->PutValue(rProp
.maValue
, pEntry
->mnFlag
);
560 nLastItemID
= pEntry
->mnItemID
;
564 rFmt
.maItemSet
.Put(*pPoolItem
);
567 OUString
ScXMLTableRowCellContext::GetFirstParagraph() const
569 if (!maFirstParagraph
)
570 return mpEditEngine
->GetText(0);
572 return *maFirstParagraph
;
575 void ScXMLTableRowCellContext::PushParagraphFieldDate(const OUString
& rStyleName
)
577 PushParagraphField(std::make_unique
<SvxDateField
>(), rStyleName
);
580 void ScXMLTableRowCellContext::PushParagraphFieldSheetName(const OUString
& rStyleName
)
582 SCTAB nTab
= GetScImport().GetTables().GetCurrentCellPos().Tab();
583 PushParagraphField(std::make_unique
<SvxTableField
>(nTab
), rStyleName
);
586 void ScXMLTableRowCellContext::PushParagraphFieldDocTitle(const OUString
& rStyleName
)
588 PushParagraphField(std::make_unique
<SvxFileField
>(), rStyleName
);
591 void ScXMLTableRowCellContext::PushParagraphFieldURL(
592 const OUString
& rURL
, const OUString
& rRep
, const OUString
& rStyleName
, const OUString
& rTargetFrame
)
594 OUString aAbsURL
= GetScImport().GetAbsoluteReference(rURL
);
595 std::unique_ptr
<SvxURLField
> pURLField(new SvxURLField(aAbsURL
, rRep
, SvxURLFormat::Repr
));
596 pURLField
->SetTargetFrame(rTargetFrame
);
597 PushParagraphField(std::move(pURLField
), rStyleName
);
600 void ScXMLTableRowCellContext::PushParagraphEnd()
602 // EditEngine always has at least one paragraph even when its content is empty.
604 if (mbEditEngineHasText
)
606 if (maFirstParagraph
)
608 // Flush the cached first paragraph first.
609 mpEditEngine
->Clear();
610 mpEditEngine
->SetText(*maFirstParagraph
);
611 maFirstParagraph
.reset();
613 mpEditEngine
->InsertParagraph(mpEditEngine
->GetParagraphCount(), maParagraph
.makeStringAndClear());
615 else if (mbHasFormatRuns
)
617 mpEditEngine
->Clear();
618 mpEditEngine
->SetText(maParagraph
.makeStringAndClear());
619 mbEditEngineHasText
= true;
621 else if (mnCurParagraph
== 0)
623 maFirstParagraph
= maParagraph
.makeStringAndClear();
624 mbEditEngineHasText
= true;
630 SvXMLImportContextRef
ScXMLTableRowCellContext::CreateChildContext( sal_uInt16 nPrefix
,
631 const OUString
& rLName
,
632 const css::uno::Reference
<css::xml::sax::XAttributeList
>& xAttrList
)
634 SvXMLImportContext
*pContext
= nullptr;
636 const SvXMLTokenMap
& rTokenMap
= rXMLImport
.GetTableRowCellElemTokenMap();
638 switch( rTokenMap
.Get( nPrefix
, rLName
) )
640 case XML_TOK_TABLE_ROW_CELL_P
:
645 case XML_TOK_TABLE_ROW_CELL_ANNOTATION
:
650 "ScXMLTableRowCellContext::CreateChildContext - multiple annotations in one cell");
651 mxAnnotationData
.reset( new ScXMLAnnotationData
);
652 pContext
= new ScXMLAnnotationContext( rXMLImport
, nPrefix
, rLName
,
653 xAttrList
, *mxAnnotationData
);
658 if (!pContext
&& !bTextP
)
660 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
661 uno::Reference
<drawing::XShapes
> xShapes (rXMLImport
.GetTables().GetCurrentXShapes());
664 ScDocument
* pDoc
= rXMLImport
.GetDocument();
665 if (aCellPos
.Col() > pDoc
->MaxCol())
666 aCellPos
.SetCol(pDoc
->MaxCol());
667 if (aCellPos
.Row() > pDoc
->MaxRow())
668 aCellPos
.SetRow(pDoc
->MaxRow());
669 XMLTableShapeImportHelper
* pTableShapeImport
=
670 static_cast< XMLTableShapeImportHelper
* >( rXMLImport
.GetShapeImport().get() );
671 pTableShapeImport
->SetOnTable(false);
672 pTableShapeImport
->SetCell(aCellPos
);
673 pContext
= rXMLImport
.GetShapeImport()->CreateGroupChildContext(
674 rXMLImport
, nPrefix
, rLName
, xAttrList
, xShapes
);
678 rXMLImport
.ProgressBarIncrement();
684 pContext
= new SvXMLImportContext( GetImport(), nPrefix
, rLName
);
689 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
ScXMLTableRowCellContext::createFastChildContext(
690 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
692 SvXMLImportContext
*pContext
= nullptr;
693 sax_fastparser::FastAttributeList
*pAttribList
=
694 sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList
);
696 // bool bTextP(false);
699 case XML_ELEMENT( TEXT
, XML_P
):
704 pContext
= new ScXMLCellTextParaContext(rXMLImport
, *this);
707 case XML_ELEMENT( TABLE
, XML_SUB_TABLE
):
709 SAL_WARN("sc", "ScXMLTableRowCellContext::createFastChildContext: subtables are not supported");
712 case XML_ELEMENT( TABLE
, XML_DETECTIVE
):
715 if (!pDetectiveObjVec
)
716 pDetectiveObjVec
.reset( new ScMyImpDetectiveObjVec
);
717 pContext
= new ScXMLDetectiveContext(
718 rXMLImport
, pDetectiveObjVec
.get() );
721 case XML_ELEMENT( TABLE
, XML_CELL_RANGE_SOURCE
):
724 if (!pCellRangeSource
)
725 pCellRangeSource
.reset(new ScMyImpCellRangeSource());
726 pContext
= new ScXMLCellRangeSourceContext(
727 rXMLImport
, pAttribList
, pCellRangeSource
.get() );
733 pContext
= new SvXMLImportContext( GetImport() );
738 void ScXMLTableRowCellContext::DoMerge( const ScAddress
& rScAddress
, const SCCOL nCols
, const SCROW nRows
)
740 SCCOL mergeToCol
= rScAddress
.Col() + nCols
;
741 SCROW mergeToRow
= rScAddress
.Row() + nRows
;
742 ScDocument
* pDoc
= rXMLImport
.GetDocument();
743 bool bInBounds
= rScAddress
.Col() <= pDoc
->MaxCol() && rScAddress
.Row() <= pDoc
->MaxRow() &&
744 mergeToCol
<= pDoc
->MaxCol() && mergeToRow
<= pDoc
->MaxRow();
747 pDoc
->DoMerge( rScAddress
.Tab(),
748 rScAddress
.Col(), rScAddress
.Row(), mergeToCol
, mergeToRow
);
754 ScValidationMode
validationTypeToMode( const sheet::ValidationType eVType
)
756 ScValidationMode eMode
;
759 case sheet::ValidationType_WHOLE
: eMode
= SC_VALID_WHOLE
; break;
760 case sheet::ValidationType_DECIMAL
: eMode
= SC_VALID_DECIMAL
; break;
761 case sheet::ValidationType_DATE
: eMode
= SC_VALID_DATE
; break;
762 case sheet::ValidationType_TIME
: eMode
= SC_VALID_TIME
; break;
763 case sheet::ValidationType_TEXT_LEN
: eMode
= SC_VALID_TEXTLEN
; break;
764 case sheet::ValidationType_LIST
: eMode
= SC_VALID_LIST
; break;
765 case sheet::ValidationType_CUSTOM
: eMode
= SC_VALID_CUSTOM
; break;
766 default: eMode
= SC_VALID_ANY
; break;
771 ScValidErrorStyle
validAlertToValidError( const sheet::ValidationAlertStyle eVAlertStyle
)
773 ScValidErrorStyle eVErrStyle
;
774 switch( eVAlertStyle
)
776 case sheet::ValidationAlertStyle_STOP
: eVErrStyle
= SC_VALERR_STOP
; break;
777 case sheet::ValidationAlertStyle_WARNING
: eVErrStyle
= SC_VALERR_WARNING
; break;
778 case sheet::ValidationAlertStyle_MACRO
: eVErrStyle
= SC_VALERR_MACRO
; break;
779 default: eVErrStyle
= SC_VALERR_INFO
; break;
780 //should INFO be the default? seems to be the most unobtrusive choice.
787 void ScXMLTableRowCellContext::SetContentValidation( const ScRange
& rScRange
)
789 if (maContentValidationName
)
791 ScDocument
* pDoc
= rXMLImport
.GetDocument();
792 ScMyImportValidation aValidation
;
793 aValidation
.eGrammar1
= aValidation
.eGrammar2
= pDoc
->GetStorageGrammar();
794 if( rXMLImport
.GetValidation(*maContentValidationName
, aValidation
) )
796 ScValidationData
aScValidationData(
797 validationTypeToMode(aValidation
.aValidationType
),
798 ScConditionEntry::GetModeFromApi(aValidation
.aOperator
),
799 aValidation
.sFormula1
, aValidation
.sFormula2
, pDoc
, ScAddress(),
800 aValidation
.sFormulaNmsp1
, aValidation
.sFormulaNmsp2
,
801 aValidation
.eGrammar1
, aValidation
.eGrammar2
804 aScValidationData
.SetIgnoreBlank( aValidation
.bIgnoreBlanks
);
805 aScValidationData
.SetListType( aValidation
.nShowList
);
807 // set strings for error / input even if disabled (and disable afterwards)
808 aScValidationData
.SetInput( aValidation
.sImputTitle
, aValidation
.sImputMessage
);
809 if( !aValidation
.bShowImputMessage
)
810 aScValidationData
.ResetInput();
811 aScValidationData
.SetError( aValidation
.sErrorTitle
, aValidation
.sErrorMessage
, validAlertToValidError(aValidation
.aAlertStyle
) );
812 if( !aValidation
.bShowErrorMessage
)
813 aScValidationData
.ResetError();
815 if( !aValidation
.sBaseCellAddress
.isEmpty() )
816 aScValidationData
.SetSrcString( aValidation
.sBaseCellAddress
);
818 sal_uLong nIndex
= pDoc
->AddValidationEntry( aScValidationData
);
820 ScPatternAttr
aPattern( pDoc
->GetPool() );
821 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA
, nIndex
) );
822 if( rScRange
.aStart
== rScRange
.aEnd
) //for a single cell
824 pDoc
->ApplyPattern( rScRange
.aStart
.Col(), rScRange
.aStart
.Row(),
825 rScRange
.aStart
.Tab(), aPattern
);
827 else //for repeating cells
829 pDoc
->ApplyPatternAreaTab( rScRange
.aStart
.Col(), rScRange
.aStart
.Row(),
830 rScRange
.aEnd
.Col(), rScRange
.aEnd
.Row(),
831 rScRange
.aStart
.Tab(), aPattern
);
834 // is the below still needed?
835 // For now, any sheet with validity is blocked from stream-copying.
836 // Later, the validation names could be stored along with the style names.
837 ScSheetSaveData
* pSheetData
= comphelper::getUnoTunnelImplementation
<ScModelObj
>(GetImport().GetModel())->GetSheetSaveData();
838 pSheetData
->BlockSheet( GetScImport().GetTables().GetCurrentSheet() );
843 void ScXMLTableRowCellContext::SetContentValidation( const ScAddress
& rCellPos
)
845 SetContentValidation( ScRange(rCellPos
, rCellPos
) );
848 void ScXMLTableRowCellContext::SetAnnotation(const ScAddress
& rPos
)
850 ScDocument
* pDoc
= rXMLImport
.GetDocument();
851 if (!pDoc
|| !mxAnnotationData
)
856 ScPostIt
* pNote
= nullptr;
858 uno::Reference
< drawing::XShapes
> xShapes
= rXMLImport
.GetTables().GetCurrentXShapes();
859 sal_Int32 nOldShapeCount
= xShapes
.is() ? xShapes
->getCount() : 0;
861 OSL_ENSURE( !mxAnnotationData
->mxShape
.is() || mxAnnotationData
->mxShapes
.is(),
862 "ScXMLTableRowCellContext::SetAnnotation - shape without drawing page" );
863 if( mxAnnotationData
->mxShape
.is() && mxAnnotationData
->mxShapes
.is() )
865 OSL_ENSURE( mxAnnotationData
->mxShapes
.get() == xShapes
.get(), "ScXMLTableRowCellContext::SetAnnotation - different drawing pages" );
866 SdrObject
* pObject
= ::GetSdrObjectFromXShape( mxAnnotationData
->mxShape
);
867 OSL_ENSURE( pObject
, "ScXMLTableRowCellContext::SetAnnotation - cannot get SdrObject from shape" );
869 /* Try to reuse the drawing object already created (but only if the
870 note is visible, and the object is a caption object). */
871 if( mxAnnotationData
->mbShown
&& mxAnnotationData
->mbUseShapePos
)
873 if( SdrCaptionObj
* pCaption
= dynamic_cast< SdrCaptionObj
* >( pObject
) )
875 OSL_ENSURE( !pCaption
->GetLogicRect().IsEmpty(), "ScXMLTableRowCellContext::SetAnnotation - invalid caption rectangle" );
876 // create the cell note with the caption object
877 pNote
= ScNoteUtil::CreateNoteFromCaption( *pDoc
, rPos
, pCaption
);
878 // forget pointer to object (do not create note again below)
883 // drawing object has not been used to create a note -> use shape data
886 // rescue settings from drawing object before the shape is removed
887 ::std::unique_ptr
< SfxItemSet
> xItemSet( new SfxItemSet( pObject
->GetMergedItemSet() ) );
888 ::std::unique_ptr
< OutlinerParaObject
> xOutlinerObj
;
889 if( OutlinerParaObject
* pOutlinerObj
= pObject
->GetOutlinerParaObject() )
890 xOutlinerObj
.reset( new OutlinerParaObject( *pOutlinerObj
) );
891 tools::Rectangle aCaptionRect
;
892 if( mxAnnotationData
->mbUseShapePos
)
893 aCaptionRect
= pObject
->GetLogicRect();
894 // remove the shape from the drawing page, this invalidates pObject
895 mxAnnotationData
->mxShapes
->remove( mxAnnotationData
->mxShape
);
897 // update current number of existing objects
899 nOldShapeCount
= xShapes
->getCount();
901 // an outliner object is required (empty note captions not allowed)
904 // create cell note with all data from drawing object
905 pNote
= ScNoteUtil::CreateNoteFromObjectData( *pDoc
, rPos
,
906 std::move(xItemSet
), xOutlinerObj
.release(),
907 aCaptionRect
, mxAnnotationData
->mbShown
);
911 else if( !mxAnnotationData
->maSimpleText
.isEmpty() )
913 // create note from simple text
914 pNote
= ScNoteUtil::CreateNoteFromString( *pDoc
, rPos
,
915 mxAnnotationData
->maSimpleText
, mxAnnotationData
->mbShown
, false );
918 // set author and date
922 if (rXMLImport
.GetMM100UnitConverter().convertDateTime(fDate
, mxAnnotationData
->maCreateDate
))
924 SvNumberFormatter
* pNumForm
= pDoc
->GetFormatTable();
925 sal_uInt32 nfIndex
= pNumForm
->GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, LANGUAGE_SYSTEM
);
927 Color
* pColor
= nullptr;
928 Color
** ppColor
= &pColor
;
929 pNumForm
->GetOutputString( fDate
, nfIndex
, aDate
, ppColor
);
930 pNote
->SetDate( aDate
);
932 pNote
->SetAuthor( mxAnnotationData
->maAuthor
);
935 // register a shape that has been newly created in the ScNoteUtil functions
936 if( xShapes
.is() && (nOldShapeCount
< xShapes
->getCount()) )
938 uno::Reference
< drawing::XShape
> xShape
;
939 rXMLImport
.GetShapeImport()->shapeWithZIndexAdded( xShape
, xShapes
->getCount() );
942 // store the style names for stream copying
943 ScSheetSaveData
* pSheetData
= comphelper::getUnoTunnelImplementation
<ScModelObj
>(rXMLImport
.GetModel())->GetSheetSaveData();
944 pSheetData
->HandleNoteStyles( mxAnnotationData
->maStyleName
, mxAnnotationData
->maTextStyle
, rPos
);
946 for (const auto& rContentStyle
: mxAnnotationData
->maContentStyles
)
948 pSheetData
->AddNoteContentStyle( rContentStyle
.mnFamily
, rContentStyle
.maName
, rPos
, rContentStyle
.maSelection
);
952 // core implementation
953 void ScXMLTableRowCellContext::SetDetectiveObj( const ScAddress
& rPosition
)
955 ScDocument
* pDoc
= rXMLImport
.GetDocument();
956 if( pDoc
&& cellExists(*pDoc
, rPosition
) && pDetectiveObjVec
&& !pDetectiveObjVec
->empty() )
959 ScDetectiveFunc
aDetFunc( pDoc
, rPosition
.Tab() );
960 uno::Reference
<container::XIndexAccess
> xShapesIndex
= rXMLImport
.GetTables().GetCurrentXShapes(); // make draw page
961 for(const auto& rDetectiveObj
: *pDetectiveObjVec
)
963 aDetFunc
.InsertObject( rDetectiveObj
.eObjType
, rPosition
, rDetectiveObj
.aSourceRange
, rDetectiveObj
.bHasError
);
964 if (xShapesIndex
.is())
966 sal_Int32 nShapes
= xShapesIndex
->getCount();
967 uno::Reference
< drawing::XShape
> xShape
;
968 rXMLImport
.GetShapeImport()->shapeWithZIndexAdded(xShape
, nShapes
);
974 // core implementation
975 void ScXMLTableRowCellContext::SetCellRangeSource( const ScAddress
& rPosition
)
977 ScDocument
* pDoc
= rXMLImport
.GetDocument();
978 if( pDoc
&& cellExists(*pDoc
, rPosition
) && pCellRangeSource
&& !pCellRangeSource
->sSourceStr
.isEmpty() &&
979 !pCellRangeSource
->sFilterName
.isEmpty() && !pCellRangeSource
->sURL
.isEmpty() )
982 ScRange
aDestRange( rPosition
.Col(), rPosition
.Row(), rPosition
.Tab(),
983 rPosition
.Col() + static_cast<SCCOL
>(pCellRangeSource
->nColumns
- 1),
984 rPosition
.Row() + static_cast<SCROW
>(pCellRangeSource
->nRows
- 1), rPosition
.Tab() );
985 OUString
sFilterName( pCellRangeSource
->sFilterName
);
986 OUString
sSourceStr( pCellRangeSource
->sSourceStr
);
987 ScAreaLink
* pLink
= new ScAreaLink( pDoc
->GetDocumentShell(), pCellRangeSource
->sURL
,
988 sFilterName
, pCellRangeSource
->sFilterOptions
, sSourceStr
, aDestRange
, pCellRangeSource
->nRefresh
);
989 sfx2::LinkManager
* pLinkManager
= pDoc
->GetLinkManager();
990 pLinkManager
->InsertFileLink( *pLink
, OBJECT_CLIENT_FILE
, pCellRangeSource
->sURL
, &sFilterName
, &sSourceStr
);
994 void ScXMLTableRowCellContext::SetFormulaCell(ScFormulaCell
* pFCell
) const
998 bool bMayForceNumberformat
= true;
1002 // don't do anything here
1003 // we need to recalc anyway
1005 else if( bFormulaTextResult
&& maStringValue
)
1007 if( !IsPossibleErrorString() )
1009 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1010 pFCell
->SetHybridString(pDoc
->GetSharedStringPool().intern(*maStringValue
));
1011 pFCell
->ResetDirty();
1012 // A General format doesn't force any other format for a string
1013 // result, don't attempt to recalculate this later.
1014 bMayForceNumberformat
= false;
1017 else if (rtl::math::isFinite(fValue
))
1019 pFCell
->SetHybridDouble(fValue
);
1020 if (mbPossibleEmptyDisplay
&& fValue
== 0.0)
1022 // Needs to be recalculated to propagate, otherwise would be
1023 // propagated as empty string. So don't ResetDirty().
1024 pFCell
->SetHybridEmptyDisplayedAsString();
1027 pFCell
->ResetDirty();
1030 if (bMayForceNumberformat
)
1031 // Re-calculate to get number format only when style is not set.
1032 pFCell
->SetNeedNumberFormat(!mbHasStyle
);
1036 void ScXMLTableRowCellContext::PutTextCell( const ScAddress
& rCurrentPos
,
1037 const SCCOL nCurrentCol
, const ::boost::optional
< OUString
>& pOUText
)
1039 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1040 bool bDoIncrement
= true;
1041 //matrix reference cells that contain text formula results;
1042 //cell was already put in document, just need to set text here.
1043 if( pDoc
&& rXMLImport
.GetTables().IsPartOfMatrix(rCurrentPos
) )
1045 ScRefCellValue
aCell(*pDoc
, rCurrentPos
);
1046 bDoIncrement
= aCell
.meType
== CELLTYPE_FORMULA
;
1049 ScFormulaCell
* pFCell
= aCell
.mpFormula
;
1050 OUString aCellString
;
1052 aCellString
= *maStringValue
;
1053 else if (mbEditEngineHasText
)
1054 aCellString
= GetFirstParagraph();
1055 else if ( nCurrentCol
> 0 && pOUText
&& !pOUText
->isEmpty() )
1056 aCellString
= *pOUText
;
1058 bDoIncrement
= false;
1061 bDoIncrement
= false;
1063 if(!aCellString
.isEmpty())
1065 if (bDoIncrement
&& !IsPossibleErrorString() && pFCell
)
1067 pFCell
->SetHybridString(pDoc
->GetSharedStringPool().intern(aCellString
));
1068 pFCell
->ResetDirty();
1072 ScAddress aTopLeftMatrixCell
;
1073 if (pFCell
&& pFCell
->GetMatrixOrigin(aTopLeftMatrixCell
))
1075 ScFormulaCell
* pMatrixCell
= pDoc
->GetFormulaCell(aTopLeftMatrixCell
);
1077 pMatrixCell
->SetDirty();
1080 SAL_WARN("sc", "matrix cell without matrix");
1085 else //regular text cells
1087 ScDocumentImport
& rDoc
= rXMLImport
.GetDoc();
1090 rDoc
.setStringCell(rCurrentPos
, *maStringValue
);
1091 bDoIncrement
= true;
1093 else if (mbEditEngineHasText
)
1095 if (maFirstParagraph
)
1097 // This is a normal text without format runs.
1098 rDoc
.setStringCell(rCurrentPos
, *maFirstParagraph
);
1102 // This text either has format runs, has field(s), or consists of multiple lines.
1103 for (const auto& rxFormat
: maFormats
)
1104 mpEditEngine
->QuickSetAttribs(rxFormat
->maItemSet
, rxFormat
->maSelection
);
1106 for (const auto& rxField
: maFields
)
1107 mpEditEngine
->QuickInsertField(SvxFieldItem(*rxField
->mpData
, EE_FEATURE_FIELD
), rxField
->maSelection
);
1109 // This edit engine uses the SfxItemPool instance returned
1110 // from pDoc->GetEditPool() to create the text object, which
1111 // is a prerequisite for using this constructor of ScEditCell.
1112 rDoc
.setEditCell(rCurrentPos
, mpEditEngine
->CreateTextObject());
1114 bDoIncrement
= true;
1116 else if ( nCurrentCol
> 0 && pOUText
&& !pOUText
->isEmpty() )
1118 rDoc
.setStringCell(rCurrentPos
, *pOUText
);
1119 bDoIncrement
= true;
1122 bDoIncrement
= false;
1125 // #i56027# This is about setting simple text, not edit cells,
1126 // so ProgressBarIncrement must be called with bEditCell = FALSE.
1127 // Formatted text that is put into the cell by the child context
1128 // is handled in AddCellsToTable() (bIsEmpty is true then).
1130 rXMLImport
.ProgressBarIncrement();
1133 void ScXMLTableRowCellContext::PutValueCell( const ScAddress
& rCurrentPos
)
1135 //matrix reference cells that contain value formula results;
1136 //cell was already put in document, just need to set value here.
1137 if( rXMLImport
.GetTables().IsPartOfMatrix(rCurrentPos
) )
1139 ScRefCellValue
aCell(*rXMLImport
.GetDocument(), rCurrentPos
);
1140 if (aCell
.meType
== CELLTYPE_FORMULA
)
1142 ScFormulaCell
* pFCell
= aCell
.mpFormula
;
1143 SetFormulaCell(pFCell
);
1145 pFCell
->SetNeedNumberFormat( true );
1148 else //regular value cell
1150 // fdo#62250 absent values are not NaN, set to 0.0
1151 // PutValueCell() is called only for a known cell value type,
1152 // bIsEmpty==false in all these cases, no sense to check it here.
1153 if (!::rtl::math::isFinite( fValue
))
1156 // #i62435# Initialize the value cell's script type if the default
1157 // style's number format is latin-only. If the cell uses a different
1158 // format, the script type will be reset when the style is applied.
1160 rXMLImport
.GetDoc().setNumericCell(rCurrentPos
, fValue
);
1162 rXMLImport
.ProgressBarIncrement();
1167 bool isEmptyOrNote( const ScDocument
* pDoc
, const ScAddress
& rCurrentPos
)
1169 CellType eType
= pDoc
->GetCellType(rCurrentPos
);
1170 return (eType
== CELLTYPE_NONE
);
1175 void ScXMLTableRowCellContext::AddTextAndValueCell( const ScAddress
& rCellPos
,
1176 const ::boost::optional
< OUString
>& pOUText
, ScAddress
& rCurrentPos
)
1178 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1179 ScMyTables
& rTables
= rXMLImport
.GetTables();
1180 bool bWasEmpty
= bIsEmpty
;
1181 for (SCCOL i
= 0; i
< nColsRepeated
; ++i
)
1183 rCurrentPos
.SetCol( rCellPos
.Col() + i
);
1185 // it makes no sense to import data after the last supported column
1186 // fdo#58539 & gnome#627150
1187 if(rCurrentPos
.Col() > pDoc
->MaxCol())
1191 rTables
.AddColumn(false);
1194 for (SCROW j
= 0; j
< nRepeatedRows
; ++j
)
1196 rCurrentPos
.SetRow( rCellPos
.Row() + j
);
1198 // it makes no sense to import data after last supported row
1199 // fdo#58539 & gnome#627150
1200 if(rCurrentPos
.Row() > pDoc
->MaxRow())
1203 if( (rCurrentPos
.Col() == 0) && (j
> 0) )
1206 rTables
.AddColumn(false);
1208 if( cellExists(*pDoc
, rCurrentPos
) )
1210 if( !bIsCovered
|| isEmptyOrNote(pDoc
, rCurrentPos
) )
1214 case util::NumberFormat::TEXT
:
1216 PutTextCell( rCurrentPos
, i
, pOUText
);
1219 case util::NumberFormat::NUMBER
:
1220 case util::NumberFormat::PERCENT
:
1221 case util::NumberFormat::CURRENCY
:
1222 case util::NumberFormat::TIME
:
1223 case util::NumberFormat::DATETIME
:
1224 case util::NumberFormat::LOGICAL
:
1226 PutValueCell( rCurrentPos
);
1231 OSL_FAIL("no cell type given");
1237 SetAnnotation( rCurrentPos
);
1238 SetDetectiveObj( rCurrentPos
);
1239 SetCellRangeSource( rCurrentPos
);
1243 if (!bWasEmpty
|| mxAnnotationData
.get())
1245 if (rCurrentPos
.Row() > pDoc
->MaxRow())
1246 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW
);
1248 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW
);
1255 if ((i
== 0) && (rCellPos
.Col() == 0))
1257 for (sal_Int32 j
= 1; j
< nRepeatedRows
; ++j
)
1260 rTables
.AddColumn(false);
1267 bool ScXMLTableRowCellContext::CellsAreRepeated() const
1269 return ( (nColsRepeated
> 1) || (nRepeatedRows
> 1) );
1274 // from ScCellObj::GetOutputString_Imp(). all of it may not be necessary.
1275 OUString
getOutputString( ScDocument
* pDoc
, const ScAddress
& aCellPos
)
1280 ScRefCellValue
aCell(*pDoc
, aCellPos
);
1281 switch (aCell
.meType
)
1287 // GetString on EditCell replaces linebreaks with spaces;
1288 // however here we need line breaks
1289 const EditTextObject
* pData
= aCell
.mpEditText
;
1290 EditEngine
& rEngine
= pDoc
->GetEditEngine();
1291 rEngine
.SetText(*pData
);
1292 return rEngine
.GetText();
1293 // also don't format EditCells per NumberFormatter
1298 // like in GetString for document (column)
1300 sal_uInt32 nNumFmt
= pDoc
->GetNumberFormat(aCellPos
);
1302 ScCellFormat::GetString(aCell
, nNumFmt
, aStr
, &pColor
, *pDoc
->GetFormatTable(), pDoc
);
1310 void ScXMLTableRowCellContext::AddNonFormulaCell( const ScAddress
& rCellPos
)
1312 ::boost::optional
< OUString
> pOUText
;
1314 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1315 if( nCellType
== util::NumberFormat::TEXT
)
1317 if( !bIsEmpty
&& !maStringValue
&& !mbEditEngineHasText
&& cellExists(*pDoc
, rCellPos
) && CellsAreRepeated() )
1318 pOUText
= getOutputString(pDoc
, rCellPos
);
1320 if (!mbEditEngineHasText
&& !pOUText
&& !maStringValue
)
1324 ScAddress
aCurrentPos( rCellPos
);
1325 if( mxAnnotationData
.get() || pDetectiveObjVec
|| pCellRangeSource
) // has special content
1328 AddTextAndValueCell( rCellPos
, pOUText
, aCurrentPos
);
1330 if( CellsAreRepeated() )
1332 SCCOL
nStartCol( std::min(rCellPos
.Col(), pDoc
->MaxCol()) );
1333 SCROW
nStartRow( std::min(rCellPos
.Row(), pDoc
->MaxRow()) );
1334 SCCOL
nEndCol( std::min
<SCCOL
>(rCellPos
.Col() + nColsRepeated
- 1, pDoc
->MaxCol()) );
1335 SCROW
nEndRow( std::min(rCellPos
.Row() + nRepeatedRows
- 1, pDoc
->MaxRow()) );
1336 ScRange
aScRange( nStartCol
, nStartRow
, rCellPos
.Tab(), nEndCol
, nEndRow
, rCellPos
.Tab() );
1337 SetContentValidation( aScRange
);
1338 rXMLImport
.GetStylesImportHelper()->AddRange( aScRange
);
1340 else if( cellExists(*pDoc
, rCellPos
) )
1342 rXMLImport
.GetStylesImportHelper()->AddCell(rCellPos
);
1343 SetContentValidation( rCellPos
);
1347 void ScXMLTableRowCellContext::PutFormulaCell( const ScAddress
& rCellPos
)
1349 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1350 ScDocumentImport
& rDocImport
= rXMLImport
.GetDoc();
1352 OUString aText
= maFormula
->first
;
1354 std::unique_ptr
<ScExternalRefManager::ApiGuard
> pExtRefGuard (
1355 new ScExternalRefManager::ApiGuard(pDoc
));
1357 if ( !aText
.isEmpty() )
1359 // temporary formula string as string tokens
1360 std::unique_ptr
<ScTokenArray
> pCode(new ScTokenArray());
1362 // Check the special case of a single error constant without leading
1363 // '=' and create an error formula cell without tokens.
1364 FormulaError nError
= GetScImport().GetFormulaErrorConstant(aText
);
1365 if (nError
!= FormulaError::NONE
)
1367 pCode
->SetCodeError(nError
);
1371 // 5.2 and earlier wrote broken "Err:xxx" as formula to designate
1372 // an error formula cell.
1373 if (aText
.startsWithIgnoreAsciiCase("Err:") && aText
.getLength() <= 9 &&
1375 GetScImport().GetFormulaErrorConstant( "#ERR" + aText
.copy(4) + "!")) != FormulaError::NONE
))
1377 pCode
->SetCodeError(nError
);
1381 OUString aFormulaNmsp
= maFormula
->second
;
1382 if( eGrammar
!= formula::FormulaGrammar::GRAM_EXTERNAL
)
1383 aFormulaNmsp
.clear();
1384 pCode
->AssignXMLString( aText
, aFormulaNmsp
);
1385 rDocImport
.getDoc().IncXMLImportedFormulaCount( aText
.getLength() );
1389 ScFormulaCell
* pNewCell
= new ScFormulaCell(pDoc
, rCellPos
, std::move(pCode
), eGrammar
, ScMatrixMode::NONE
);
1390 SetFormulaCell(pNewCell
);
1391 rDocImport
.setFormulaCell(rCellPos
, pNewCell
);
1395 void ScXMLTableRowCellContext::AddFormulaCell( const ScAddress
& rCellPos
)
1397 ScDocument
* pDoc
= rXMLImport
.GetDocument();
1398 if( cellExists(*pDoc
, rCellPos
) )
1400 SetContentValidation( rCellPos
);
1401 SAL_WARN_IF((nColsRepeated
!= 1) || (nRepeatedRows
!= 1), "sc", "repeated cells with formula not possible now");
1402 rXMLImport
.GetStylesImportHelper()->AddCell(rCellPos
);
1407 if (nMatrixCols
> 0 && nMatrixRows
> 0)
1409 //matrix cells are put in the document, but we must set the
1410 //value/text of each matrix cell later
1411 rXMLImport
.GetTables().AddMatrixRange(
1412 rCellPos
.Col(), rCellPos
.Row(),
1413 std::min
<SCCOL
>(rCellPos
.Col() + nMatrixCols
- 1, pDoc
->MaxCol()),
1414 std::min
<SCROW
>(rCellPos
.Row() + nMatrixRows
- 1, pDoc
->MaxRow()),
1415 maFormula
->first
, maFormula
->second
, eGrammar
);
1417 // Set the value/text of the top-left matrix position in its
1418 // cached result. For import, we only need to set the correct
1419 // matrix geometry and the value type of the top-left element.
1420 ScFormulaCell
* pFCell
= pDoc
->GetFormulaCell(rCellPos
);
1423 ScMatrixRef
pMat(new ScMatrix(nMatrixCols
, nMatrixRows
));
1424 if (bFormulaTextResult
&& maStringValue
)
1426 if (!IsPossibleErrorString())
1428 pFCell
->SetResultMatrix(
1429 nMatrixCols
, nMatrixRows
, pMat
, new formula::FormulaStringToken(
1430 pDoc
->GetSharedStringPool().intern( *maStringValue
)));
1431 pFCell
->ResetDirty();
1434 else if (rtl::math::isFinite(fValue
))
1436 pFCell
->SetResultMatrix(
1437 nMatrixCols
, nMatrixRows
, pMat
, new formula::FormulaDoubleToken(fValue
));
1438 pFCell
->ResetDirty();
1444 PutFormulaCell( rCellPos
);
1446 SetAnnotation( rCellPos
);
1447 SetDetectiveObj( rCellPos
);
1448 SetCellRangeSource( rCellPos
);
1449 rXMLImport
.ProgressBarIncrement();
1453 if (rCellPos
.Row() > pDoc
->MaxRow())
1454 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW
);
1456 rXMLImport
.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW
);
1460 //There are cases where a formula cell is exported with an office:value of 0 or
1461 //no office:value at all, but the formula cell will have a text:p value which
1462 //contains the intended formula result.
1463 //These cases include when a formula result:
1465 // - has a constant error value beginning with "#" (such as "#VALUE!" or "#N/A")
1466 // - has an "Err:[###]" (where "[###]" is an error number)
1467 // Libreoffice 4.1+ with ODF1.2 extended write however calcext:value-type="error" in that case
1468 void ScXMLTableRowCellContext::HasSpecialCaseFormulaText()
1470 if (!mbEditEngineHasText
)
1473 const OUString aStr
= GetFirstParagraph();
1478 mbPossibleEmptyDisplay
= true;
1484 mbPossibleErrorCell
= true;
1485 mbPossibleEmptyDisplay
= true;
1487 else if (aStr
.startsWith("Err:"))
1488 mbPossibleErrorCell
= true;
1489 else if (aStr
.startsWith("#"))
1490 mbCheckWithCompilerForError
= true;
1493 bool ScXMLTableRowCellContext::IsPossibleErrorString() const
1495 if(mbNewValueType
&& !mbErrorValue
)
1497 else if(mbNewValueType
&& mbErrorValue
)
1499 return mbPossibleErrorCell
|| (mbCheckWithCompilerForError
&&
1500 GetScImport().GetFormulaErrorConstant(*maStringValue
) != FormulaError::NONE
);
1503 void SAL_CALL
ScXMLTableRowCellContext::endFastElement(sal_Int32
/*nElement*/)
1505 HasSpecialCaseFormulaText();
1506 if( bFormulaTextResult
&& (mbPossibleErrorCell
|| mbCheckWithCompilerForError
) )
1508 maStringValue
= GetFirstParagraph();
1511 ScAddress aCellPos
= rXMLImport
.GetTables().GetCurrentCellPos();
1512 if( aCellPos
.Col() > 0 && nRepeatedRows
> 1 )
1513 aCellPos
.SetRow( aCellPos
.Row() - (nRepeatedRows
- 1) );
1515 DoMerge( aCellPos
, nMergedCols
- 1, nMergedRows
- 1 );
1518 AddFormulaCell(aCellPos
);
1520 AddNonFormulaCell(aCellPos
);
1522 //if LockSolarMutex got used, we presumably need to ensure an UnlockSolarMutex
1523 if (bSolarMutexLocked
)
1525 GetScImport().UnlockSolarMutex();
1526 bSolarMutexLocked
= false;
1535 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */