Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / xml / xmlcelli.cxx
blob359f48b1e24ff760d77f690e2e38e70bd9c8338f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include "xmlcelli.hxx"
22 #include "xmlimprt.hxx"
23 #include "xmlannoi.hxx"
24 #include <global.hxx>
25 #include <cellvalue.hxx>
26 #include <document.hxx>
27 #include <docuno.hxx>
28 #include <postit.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()),
117 mnCurParagraph(0),
118 fValue(0.0),
119 nMergedRows(1),
120 nMatrixRows(0),
121 nRepeatedRows(nTempRepeatedRows),
122 nMergedCols(1),
123 nMatrixCols(0),
124 nColsRepeated(1),
125 rXMLImport(rImport),
126 eGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT),
127 nCellType(util::NumberFormat::TEXT),
128 bIsMerged(false),
129 bIsMatrix(false),
130 bIsCovered(bTempIsCovered),
131 bIsEmpty(true),
132 mbNewValueType(false),
133 mbErrorValue(false),
134 bSolarMutexLocked(false),
135 bFormulaTextResult(false),
136 mbPossibleErrorCell(false),
137 mbCheckWithCompilerForError(false),
138 mbEditEngineHasText(false),
139 mbHasFormatRuns(false),
140 mbHasStyle(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();
157 mbHasStyle = true;
158 break;
159 case XML_ELEMENT( TABLE, XML_CONTENT_VALIDATION_NAME ):
160 OSL_ENSURE(!maContentValidationName, "here should be only one Validation Name");
161 if (!it.isEmpty())
162 maContentValidationName = it.toString();
163 break;
164 case XML_ELEMENT( TABLE, XML_NUMBER_ROWS_SPANNED ):
165 bIsMerged = true;
166 nMergedRows = static_cast<SCROW>(it.toInt32());
167 break;
168 case XML_ELEMENT( TABLE, XML_NUMBER_COLUMNS_SPANNED ):
169 bIsMerged = true;
170 nMergedCols = static_cast<SCCOL>(it.toInt32());
171 break;
172 case XML_ELEMENT( TABLE, XML_NUMBER_MATRIX_COLUMNS_SPANNED ):
173 bIsMatrix = true;
174 nMatrixCols = static_cast<SCCOL>(it.toInt32());
175 break;
176 case XML_ELEMENT( TABLE, XML_NUMBER_MATRIX_ROWS_SPANNED ):
177 bIsMatrix = true;
178 nMatrixRows = static_cast<SCROW>(it.toInt32());
179 break;
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) ) ));
183 break;
184 case XML_ELEMENT( OFFICE, XML_VALUE_TYPE ):
185 nCellType = ScXMLImport::GetCellType(it.toCString(), it.getLength());
186 bIsEmpty = false;
187 break;
188 case XML_ELEMENT( CALC_EXT, XML_VALUE_TYPE ):
189 if(it.isString( "error" ) )
190 mbErrorValue = true;
191 else
192 nCellType = ScXMLImport::GetCellType(it.toCString(), it.getLength());
193 bIsEmpty = false;
194 mbNewValueType = true;
195 break;
196 case XML_ELEMENT( OFFICE, XML_VALUE ):
198 if (!it.isEmpty())
200 fValue = it.toDouble();
201 bIsEmpty = false;
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.
206 if(fValue == 0.0)
207 bFormulaTextResult = true;
210 break;
211 case XML_ELEMENT( OFFICE, XML_DATE_VALUE ):
213 if (!it.isEmpty() && rXMLImport.SetNullDateOnUnitConverter())
215 rXMLImport.GetMM100UnitConverter().convertDateTime(fValue, it.toString());
216 bIsEmpty = false;
219 break;
220 case XML_ELEMENT( OFFICE, XML_TIME_VALUE ):
222 if (!it.isEmpty())
224 ::sax::Converter::convertDuration(fValue, it.toString());
225 bIsEmpty = false;
228 break;
229 case XML_ELEMENT( OFFICE, XML_STRING_VALUE ):
231 if (!it.isEmpty())
233 OSL_ENSURE(!maStringValue, "here should be only one string value");
234 maStringValue = it.toString();
235 bIsEmpty = false;
238 break;
239 case XML_ELEMENT( OFFICE , XML_BOOLEAN_VALUE ):
241 if (!it.isEmpty())
243 if ( IsXMLToken( it, XML_TRUE ) )
244 fValue = 1.0;
245 else if ( IsXMLToken( it, XML_FALSE ) )
246 fValue = 0.0;
247 else
248 fValue = it.toDouble();
249 bIsEmpty = false;
252 break;
253 case XML_ELEMENT( TABLE, XML_FORMULA ):
255 if (!it.isEmpty())
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);
263 break;
264 case XML_ELEMENT( OFFICE, XML_CURRENCY ):
265 xCurrencySymbol = it.toString();
266 break;
267 default:
273 if (maFormula)
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().
282 if(bIsEmpty)
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;
301 namespace {
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())
339 return;
341 // Get the style information from xmloff.
342 rtl::Reference<XMLPropertySetMapper> xMapper = GetImport().GetTextImport()->GetTextImportPropertySetMapper()->getPropertySetMapper();
343 if (!xMapper.is())
344 // We can't do anything without the mapper.
345 return;
347 sal_Int32 nEntryCount = xMapper->GetEntryCount();
349 SvXMLStylesContext* pAutoStyles = GetImport().GetAutoStyles();
350 if (!pAutoStyles)
351 return;
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));
357 if (!pStyle)
358 // No style by that name found.
359 return;
361 const std::vector<XMLPropertyState>& rProps = pStyle->GetProperties();
362 if (rProps.empty())
363 return;
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)
385 continue;
387 const OUString& rName = xMapper->GetEntryAPIName(rProp.mnIndex);
388 const ScXMLEditAttributeMap::Entry* pEntry = rEditAttrMap.getEntryByAPIName(rName);
389 if (!pEntry)
390 continue;
392 if (nLastItemID != pEntry->mnItemID && pPoolItem)
394 // Flush the last item when the item ID changes.
395 rFmt.maItemSet.Put(*pPoolItem);
396 pPoolItem.reset();
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.
406 if (!pPoolItem)
407 pPoolItem.reset(new SvxFontItem(pEntry->mnItemID));
409 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
411 break;
412 case EE_CHAR_WEIGHT:
413 case EE_CHAR_WEIGHT_CJK:
414 case EE_CHAR_WEIGHT_CTL:
416 if (!pPoolItem)
417 pPoolItem.reset(new SvxWeightItem(WEIGHT_NORMAL, pEntry->mnItemID));
419 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
421 break;
422 case EE_CHAR_FONTHEIGHT:
423 case EE_CHAR_FONTHEIGHT_CJK:
424 case EE_CHAR_FONTHEIGHT_CTL:
426 if (!pPoolItem)
427 pPoolItem.reset(new SvxFontHeightItem(240, 100, pEntry->mnItemID));
429 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
431 break;
432 case EE_CHAR_ITALIC:
433 case EE_CHAR_ITALIC_CJK:
434 case EE_CHAR_ITALIC_CTL:
436 if (!pPoolItem)
437 pPoolItem.reset(new SvxPostureItem(ITALIC_NONE, pEntry->mnItemID));
439 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
441 break;
442 case EE_CHAR_UNDERLINE:
444 if (!pPoolItem)
445 pPoolItem.reset(new SvxUnderlineItem(LINESTYLE_NONE, pEntry->mnItemID));
447 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
449 break;
450 case EE_CHAR_OVERLINE:
452 if (!pPoolItem)
453 pPoolItem.reset(new SvxOverlineItem(LINESTYLE_NONE, pEntry->mnItemID));
455 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
457 break;
458 case EE_CHAR_COLOR:
460 if (!pPoolItem)
461 pPoolItem.reset(new SvxColorItem(pEntry->mnItemID));
463 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
465 break;
466 case EE_CHAR_WLM:
468 if (!pPoolItem)
469 pPoolItem.reset(new SvxWordLineModeItem(false, pEntry->mnItemID));
471 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
473 break;
474 case EE_CHAR_STRIKEOUT:
476 if (!pPoolItem)
477 pPoolItem.reset(new SvxCrossedOutItem(STRIKEOUT_NONE, pEntry->mnItemID));
479 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
481 break;
482 case EE_CHAR_RELIEF:
484 if (!pPoolItem)
485 pPoolItem.reset(new SvxCharReliefItem(FontRelief::NONE, pEntry->mnItemID));
487 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
489 break;
490 case EE_CHAR_OUTLINE:
492 if (!pPoolItem)
493 pPoolItem.reset(new SvxContourItem(false, pEntry->mnItemID));
495 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
497 break;
498 case EE_CHAR_SHADOW:
500 if (!pPoolItem)
501 pPoolItem.reset(new SvxShadowedItem(false, pEntry->mnItemID));
503 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
505 break;
506 case EE_CHAR_KERNING:
508 if (!pPoolItem)
509 pPoolItem.reset(new SvxKerningItem(0, pEntry->mnItemID));
511 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
513 break;
514 case EE_CHAR_PAIRKERNING:
516 if (!pPoolItem)
517 pPoolItem.reset(new SvxAutoKernItem(false, pEntry->mnItemID));
519 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
521 break;
522 case EE_CHAR_FONTWIDTH:
524 if (!pPoolItem)
525 pPoolItem.reset(new SvxCharScaleWidthItem(100, pEntry->mnItemID));
527 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
529 break;
530 case EE_CHAR_ESCAPEMENT:
532 if (!pPoolItem)
533 pPoolItem.reset(new SvxEscapementItem(pEntry->mnItemID));
535 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
537 break;
538 case EE_CHAR_EMPHASISMARK:
540 if (!pPoolItem)
541 pPoolItem.reset(new SvxEmphasisMarkItem(FontEmphasisMark::NONE, pEntry->mnItemID));
543 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
545 break;
546 case EE_CHAR_LANGUAGE:
547 case EE_CHAR_LANGUAGE_CJK:
548 case EE_CHAR_LANGUAGE_CTL:
550 if (!pPoolItem)
551 pPoolItem.reset(new SvxLanguageItem(LANGUAGE_DONTKNOW, pEntry->mnItemID));
553 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
555 break;
556 default:
560 nLastItemID = pEntry->mnItemID;
563 if (pPoolItem)
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;
627 ++mnCurParagraph;
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();
637 bool bTextP(false);
638 switch( rTokenMap.Get( nPrefix, rLName ) )
640 case XML_TOK_TABLE_ROW_CELL_P:
642 bTextP = true;
644 break;
645 case XML_TOK_TABLE_ROW_CELL_ANNOTATION:
647 bIsEmpty = false;
648 OSL_ENSURE(
649 !mxAnnotationData,
650 "ScXMLTableRowCellContext::CreateChildContext - multiple annotations in one cell");
651 mxAnnotationData.reset( new ScXMLAnnotationData );
652 pContext = new ScXMLAnnotationContext( rXMLImport, nPrefix, rLName,
653 xAttrList, *mxAnnotationData);
655 break;
658 if (!pContext && !bTextP)
660 ScAddress aCellPos = rXMLImport.GetTables().GetCurrentCellPos();
661 uno::Reference<drawing::XShapes> xShapes (rXMLImport.GetTables().GetCurrentXShapes());
662 if (xShapes.is())
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);
675 if (pContext)
677 bIsEmpty = false;
678 rXMLImport.ProgressBarIncrement();
683 if( !pContext )
684 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLName );
686 return pContext;
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);
697 switch (nElement)
699 case XML_ELEMENT( TEXT, XML_P ):
701 bIsEmpty = false;
702 // bTextP = true;
704 pContext = new ScXMLCellTextParaContext(rXMLImport, *this);
706 break;
707 case XML_ELEMENT( TABLE, XML_SUB_TABLE ):
709 SAL_WARN("sc", "ScXMLTableRowCellContext::createFastChildContext: subtables are not supported");
711 break;
712 case XML_ELEMENT( TABLE, XML_DETECTIVE ):
714 bIsEmpty = false;
715 if (!pDetectiveObjVec)
716 pDetectiveObjVec.reset( new ScMyImpDetectiveObjVec );
717 pContext = new ScXMLDetectiveContext(
718 rXMLImport, pDetectiveObjVec.get() );
720 break;
721 case XML_ELEMENT( TABLE, XML_CELL_RANGE_SOURCE ):
723 bIsEmpty = false;
724 if (!pCellRangeSource)
725 pCellRangeSource.reset(new ScMyImpCellRangeSource());
726 pContext = new ScXMLCellRangeSourceContext(
727 rXMLImport, pAttribList, pCellRangeSource.get() );
729 break;
732 if( !pContext )
733 pContext = new SvXMLImportContext( GetImport() );
735 return pContext;
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();
745 if( bInBounds )
747 pDoc->DoMerge( rScAddress.Tab(),
748 rScAddress.Col(), rScAddress.Row(), mergeToCol, mergeToRow );
752 namespace {
754 ScValidationMode validationTypeToMode( const sheet::ValidationType eVType )
756 ScValidationMode eMode;
757 switch( eVType )
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;
768 return eMode;
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.
782 return eVErrStyle;
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)
852 return;
854 LockSolarMutex();
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)
879 pObject = nullptr;
883 // drawing object has not been used to create a note -> use shape data
884 if( pObject )
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 );
896 pObject = nullptr;
897 // update current number of existing objects
898 if( xShapes.is() )
899 nOldShapeCount = xShapes->getCount();
901 // an outliner object is required (empty note captions not allowed)
902 if (xOutlinerObj)
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
919 if( pNote )
921 double fDate;
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 );
926 OUString aDate;
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() )
958 LockSolarMutex();
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() )
981 LockSolarMutex();
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
996 if(pFCell)
998 bool bMayForceNumberformat = true;
1000 if(mbErrorValue)
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();
1026 else
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;
1047 if ( bDoIncrement )
1049 ScFormulaCell* pFCell = aCell.mpFormula;
1050 OUString aCellString;
1051 if (maStringValue)
1052 aCellString = *maStringValue;
1053 else if (mbEditEngineHasText)
1054 aCellString = GetFirstParagraph();
1055 else if ( nCurrentCol > 0 && pOUText && !pOUText->isEmpty() )
1056 aCellString = *pOUText;
1057 else
1058 bDoIncrement = false;
1060 if(mbErrorValue)
1061 bDoIncrement = false;
1063 if(!aCellString.isEmpty())
1065 if (bDoIncrement && !IsPossibleErrorString() && pFCell)
1067 pFCell->SetHybridString(pDoc->GetSharedStringPool().intern(aCellString));
1068 pFCell->ResetDirty();
1070 else
1072 ScAddress aTopLeftMatrixCell;
1073 if (pFCell && pFCell->GetMatrixOrigin(aTopLeftMatrixCell))
1075 ScFormulaCell* pMatrixCell = pDoc->GetFormulaCell(aTopLeftMatrixCell);
1076 if (pMatrixCell)
1077 pMatrixCell->SetDirty();
1079 else
1080 SAL_WARN("sc", "matrix cell without matrix");
1085 else //regular text cells
1087 ScDocumentImport& rDoc = rXMLImport.GetDoc();
1088 if (maStringValue)
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);
1100 else
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;
1121 else
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).
1129 if (bDoIncrement)
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);
1144 if (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))
1154 fValue = 0.0;
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();
1165 namespace {
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())
1188 break;
1190 if (i > 0)
1191 rTables.AddColumn(false);
1192 if (!bIsEmpty)
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())
1201 break;
1203 if( (rCurrentPos.Col() == 0) && (j > 0) )
1205 rTables.AddRow();
1206 rTables.AddColumn(false);
1208 if( cellExists(*pDoc, rCurrentPos) )
1210 if( !bIsCovered || isEmptyOrNote(pDoc, rCurrentPos) )
1212 switch (nCellType)
1214 case util::NumberFormat::TEXT:
1216 PutTextCell( rCurrentPos, i, pOUText );
1218 break;
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 );
1228 break;
1229 default:
1231 OSL_FAIL("no cell type given");
1233 break;
1237 SetAnnotation( rCurrentPos );
1238 SetDetectiveObj( rCurrentPos );
1239 SetCellRangeSource( rCurrentPos );
1241 else
1243 if (!bWasEmpty || mxAnnotationData.get())
1245 if (rCurrentPos.Row() > pDoc->MaxRow())
1246 rXMLImport.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW);
1247 else
1248 rXMLImport.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW);
1253 else
1255 if ((i == 0) && (rCellPos.Col() == 0))
1257 for (sal_Int32 j = 1; j < nRepeatedRows; ++j)
1259 rTables.AddRow();
1260 rTables.AddColumn(false);
1267 bool ScXMLTableRowCellContext::CellsAreRepeated() const
1269 return ( (nColsRepeated > 1) || (nRepeatedRows > 1) );
1272 namespace {
1274 // from ScCellObj::GetOutputString_Imp(). all of it may not be necessary.
1275 OUString getOutputString( ScDocument* pDoc, const ScAddress& aCellPos )
1277 if (!pDoc)
1278 return OUString();
1280 ScRefCellValue aCell(*pDoc, aCellPos);
1281 switch (aCell.meType)
1283 case CELLTYPE_NONE:
1284 return OUString();
1285 case CELLTYPE_EDIT:
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
1295 break;
1296 default:
1298 // like in GetString for document (column)
1299 Color* pColor;
1300 sal_uInt32 nNumFmt = pDoc->GetNumberFormat(aCellPos);
1301 OUString aStr;
1302 ScCellFormat::GetString(aCell, nNumFmt, aStr, &pColor, *pDoc->GetFormatTable(), pDoc);
1303 return aStr;
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)
1321 bIsEmpty = true;
1324 ScAddress aCurrentPos( rCellPos );
1325 if( mxAnnotationData.get() || pDetectiveObjVec || pCellRangeSource ) // has special content
1326 bIsEmpty = false;
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);
1369 else
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 &&
1374 ((nError =
1375 GetScImport().GetFormulaErrorConstant( "#ERR" + aText.copy(4) + "!")) != FormulaError::NONE))
1377 pCode->SetCodeError(nError);
1379 else
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);
1404 //add matrix
1405 if(bIsMatrix)
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);
1421 if (pFCell)
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();
1443 else
1444 PutFormulaCell( rCellPos );
1446 SetAnnotation( rCellPos );
1447 SetDetectiveObj( rCellPos );
1448 SetCellRangeSource( rCellPos );
1449 rXMLImport.ProgressBarIncrement();
1451 else
1453 if (rCellPos.Row() > pDoc->MaxRow())
1454 rXMLImport.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW);
1455 else
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:
1464 // - is blank
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)
1471 return;
1473 const OUString aStr = GetFirstParagraph();
1475 if (mbNewValueType)
1477 if (aStr.isEmpty())
1478 mbPossibleEmptyDisplay = true;
1479 return;
1482 if (aStr.isEmpty())
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)
1496 return false;
1497 else if(mbNewValueType && mbErrorValue)
1498 return true;
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) );
1514 if( bIsMerged )
1515 DoMerge( aCellPos, nMergedCols - 1, nMergedRows - 1 );
1517 if (maFormula)
1518 AddFormulaCell(aCellPos);
1519 else
1520 AddNonFormulaCell(aCellPos);
1522 //if LockSolarMutex got used, we presumably need to ensure an UnlockSolarMutex
1523 if (bSolarMutexLocked)
1525 GetScImport().UnlockSolarMutex();
1526 bSolarMutexLocked = false;
1529 bIsMerged = false;
1530 nMergedCols = 1;
1531 nMergedRows = 1;
1532 nColsRepeated = 1;
1535 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */