1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
35 
36 #include "XMLTableShapeImportHelper.hxx"
37 #include "XMLStylesImportHelper.hxx"
38 #include "celltextparacontext.hxx"
39 #include "XMLCellRangeSourceContext.hxx"
40 
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>
51 
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/xmlnamespace.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>
87 
88 #include <com/sun/star/util/NumberFormat.hpp>
89 
90 #include <com/sun/star/sheet/ValidationType.hpp>
91 #include <com/sun/star/sheet/ValidationAlertStyle.hpp>
92 
93 #include <rtl/ustrbuf.hxx>
94 #include <osl/diagnose.h>
95 #include <sal/log.hxx>
96 #include <i18nlangtag/lang.h>
97 
98 #include <comphelper/servicehelper.hxx>
99 #include <comphelper/lok.hxx>
100 
101 using namespace com::sun::star;
102 using namespace xmloff::token;
103 
ParaFormat(const ScEditEngineDefaulter & rEditEngine)104 ScXMLTableRowCellContext::ParaFormat::ParaFormat(const ScEditEngineDefaulter& rEditEngine) :
105     maItemSet(rEditEngine.GetEmptyItemSet()) {}
106 
Field(std::unique_ptr<SvxFieldData> pData)107 ScXMLTableRowCellContext::Field::Field(std::unique_ptr<SvxFieldData> pData) : mpData(std::move(pData)) {}
108 
~Field()109 ScXMLTableRowCellContext::Field::~Field()
110 {
111 }
112 
ScXMLTableRowCellContext(ScXMLImport & rImport,const rtl::Reference<sax_fastparser::FastAttributeList> & rAttrList,const bool bTempIsCovered,const sal_Int32 nTempRepeatedRows)113 ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport& rImport,
114                                       const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
115                                       const bool bTempIsCovered,
116                                       const sal_Int32 nTempRepeatedRows ) :
117     ScXMLImportContext( rImport ),
118     mpEditEngine(GetScImport().GetEditEngine()),
119     mnCurParagraph(0),
120     fValue(0.0),
121     nMergedRows(1),
122     nMatrixRows(0),
123     nRepeatedRows(nTempRepeatedRows),
124     nMergedCols(1),
125     nMatrixCols(0),
126     nColsRepeated(1),
127     rXMLImport(rImport),
128     eGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT),
129     nCellType(util::NumberFormat::TEXT),
130     bIsMerged(false),
131     bIsMatrix(false),
132     bIsCovered(bTempIsCovered),
133     bIsEmpty(true),
134     mbNewValueType(false),
135     mbErrorValue(false),
136     bSolarMutexLocked(false),
137     bFormulaTextResult(false),
138     mbPossibleErrorCell(false),
139     mbCheckWithCompilerForError(false),
140     mbEditEngineHasText(false),
141     mbHasFormatRuns(false),
142     mbHasStyle(false),
143     mbPossibleEmptyDisplay(false)
144 {
145     rtl::math::setNan(&fValue); // NaN by default
146 
147     rXMLImport.GetTables().AddColumn(bTempIsCovered);
148 
149     std::optional<OUString> xStyleName;
150     std::optional<OUString> xCurrencySymbol;
151     if ( rAttrList.is() )
152     {
153         for (auto &it : *rAttrList)
154         {
155             switch ( it.getToken() )
156             {
157                 case XML_ELEMENT( TABLE, XML_STYLE_NAME ):
158                     xStyleName = it.toString();
159                     mbHasStyle = true;
160                 break;
161                 case XML_ELEMENT( TABLE, XML_CONTENT_VALIDATION_NAME ):
162                     OSL_ENSURE(!maContentValidationName, "here should be only one Validation Name");
163                     if (!it.isEmpty())
164                         maContentValidationName = it.toString();
165                 break;
166                 case XML_ELEMENT( TABLE, XML_NUMBER_ROWS_SPANNED ):
167                     bIsMerged = true;
168                     nMergedRows = static_cast<SCROW>(it.toInt32());
169                 break;
170                 case XML_ELEMENT( TABLE, XML_NUMBER_COLUMNS_SPANNED ):
171                     bIsMerged = true;
172                     nMergedCols = static_cast<SCCOL>(it.toInt32());
173                 break;
174                 case XML_ELEMENT( TABLE, XML_NUMBER_MATRIX_COLUMNS_SPANNED ):
175                     bIsMatrix = true;
176                     nMatrixCols = static_cast<SCCOL>(it.toInt32());
177                 break;
178                 case XML_ELEMENT( TABLE, XML_NUMBER_MATRIX_ROWS_SPANNED ):
179                     bIsMatrix = true;
180                     nMatrixRows = static_cast<SCROW>(it.toInt32());
181                 break;
182                 case XML_ELEMENT( TABLE, XML_NUMBER_COLUMNS_REPEATED ):
183                     nColsRepeated = static_cast<SCCOL>(std::min<sal_Int32>( MAXCOLCOUNT,
184                                 std::max( it.toInt32(), static_cast<sal_Int32>(1) ) ));
185                 break;
186                 case XML_ELEMENT( OFFICE, XML_VALUE_TYPE ):
187                     nCellType = ScXMLImport::GetCellType(it.toCString(), it.getLength());
188                     bIsEmpty = false;
189                 break;
190                 case XML_ELEMENT( CALC_EXT, XML_VALUE_TYPE ):
191                     if(it.isString( "error" ) )
192                         mbErrorValue = true;
193                     else
194                         nCellType = ScXMLImport::GetCellType(it.toCString(), it.getLength());
195                     bIsEmpty = false;
196                     mbNewValueType = true;
197                 break;
198                 case XML_ELEMENT( OFFICE, XML_VALUE ):
199                 {
200                     if (!it.isEmpty())
201                     {
202                         fValue = it.toDouble();
203                         bIsEmpty = false;
204 
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.
208                         if(fValue == 0.0)
209                             bFormulaTextResult = true;
210                     }
211                 }
212                 break;
213                 case XML_ELEMENT( OFFICE, XML_DATE_VALUE ):
214                 {
215                     if (!it.isEmpty() && rXMLImport.SetNullDateOnUnitConverter())
216                     {
217                         rXMLImport.GetMM100UnitConverter().convertDateTime(fValue, it.toString());
218                         bIsEmpty = false;
219                     }
220                 }
221                 break;
222                 case XML_ELEMENT( OFFICE, XML_TIME_VALUE ):
223                 {
224                     if (!it.isEmpty())
225                     {
226                         ::sax::Converter::convertDuration(fValue, it.toString());
227                         bIsEmpty = false;
228                     }
229                 }
230                 break;
231                 case XML_ELEMENT( OFFICE, XML_STRING_VALUE ):
232                 {
233                     if (!it.isEmpty())
234                     {
235                         OSL_ENSURE(!maStringValue, "here should be only one string value");
236                         maStringValue = it.toString();
237                         bIsEmpty = false;
238                     }
239                 }
240                 break;
241                 case XML_ELEMENT( OFFICE , XML_BOOLEAN_VALUE ):
242                 {
243                     if (!it.isEmpty())
244                     {
245                         if ( IsXMLToken( it, XML_TRUE ) )
246                             fValue = 1.0;
247                         else if ( IsXMLToken( it, XML_FALSE ) )
248                             fValue = 0.0;
249                         else
250                             fValue = it.toDouble();
251                         bIsEmpty = false;
252                     }
253                 }
254                 break;
255                 case XML_ELEMENT( TABLE, XML_FORMULA ):
256                 {
257                     if (!it.isEmpty())
258                     {
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);
263                     }
264                 }
265                 break;
266                 case XML_ELEMENT( OFFICE, XML_CURRENCY ):
267                     xCurrencySymbol = it.toString();
268                 break;
269                 default:
270                     ;
271             }
272         }
273     }
274 
275     if (maFormula)
276     {
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().
284         if(bIsEmpty)
285             bFormulaTextResult = true;
286     }
287     rXMLImport.GetStylesImportHelper()->SetAttributes(std::move(xStyleName), std::move(xCurrencySymbol), nCellType);
288 }
289 
~ScXMLTableRowCellContext()290 ScXMLTableRowCellContext::~ScXMLTableRowCellContext()
291 {
292 }
293 
LockSolarMutex()294 void ScXMLTableRowCellContext::LockSolarMutex()
295 {
296     if (!bSolarMutexLocked)
297     {
298         GetScImport().LockSolarMutex();
299         bSolarMutexLocked = true;
300     }
301 }
302 
303 namespace {
304 
cellExists(const ScDocument & rDoc,const ScAddress & rCellPos)305 bool cellExists( const ScDocument& rDoc, const ScAddress& rCellPos )
306 {
307     return( rCellPos.Col() >= 0 && rCellPos.Row() >= 0 &&
308             rCellPos.Col() <= rDoc.MaxCol() && rCellPos.Row() <= rDoc.MaxRow() );
309 }
310 
311 }
312 
PushParagraphSpan(const OUString & rSpan,const OUString & rStyleName)313 void ScXMLTableRowCellContext::PushParagraphSpan(const OUString& rSpan, const OUString& rStyleName)
314 {
315     sal_Int32 nBegin = maParagraph.getLength();
316     sal_Int32 nEnd = nBegin + rSpan.getLength();
317     maParagraph.append(rSpan);
318 
319     PushFormat(nBegin, nEnd, rStyleName);
320 }
321 
PushParagraphField(std::unique_ptr<SvxFieldData> pData,const OUString & rStyleName)322 void ScXMLTableRowCellContext::PushParagraphField(std::unique_ptr<SvxFieldData> pData, const OUString& rStyleName)
323 {
324     mbHasFormatRuns = true;
325     maFields.push_back(std::make_unique<Field>(std::move(pData)));
326     Field& rField = *maFields.back();
327 
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;
334 
335     PushFormat(nPos, nPos+1, rStyleName);
336 }
337 
PushFormat(sal_Int32 nBegin,sal_Int32 nEnd,const OUString & rStyleName)338 void ScXMLTableRowCellContext::PushFormat(sal_Int32 nBegin, sal_Int32 nEnd, const OUString& rStyleName)
339 {
340     if (rStyleName.isEmpty())
341         return;
342 
343     // Get the style information from xmloff.
344     rtl::Reference<XMLPropertySetMapper> xMapper = GetImport().GetTextImport()->GetTextImportPropertySetMapper()->getPropertySetMapper();
345     if (!xMapper.is())
346         // We can't do anything without the mapper.
347         return;
348 
349     sal_Int32 nEntryCount = xMapper->GetEntryCount();
350 
351     SvXMLStylesContext* pAutoStyles = GetImport().GetAutoStyles();
352     if (!pAutoStyles)
353         return;
354 
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));
358 
359     if (!pStyle)
360         // No style by that name found.
361         return;
362 
363     const std::vector<XMLPropertyState>& rProps = pStyle->GetProperties();
364     if (rProps.empty())
365         return;
366 
367     const ScXMLEditAttributeMap& rEditAttrMap = GetScImport().GetEditAttributeMap();
368 
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;
375 
376     // Store the used text styles for export.
377     ScSheetSaveData* pSheetData = comphelper::getUnoTunnelImplementation<ScModelObj>(rXMLImport.GetModel())->GetSheetSaveData();
378     ScAddress aCellPos = rXMLImport.GetTables().GetCurrentCellPos();
379     pSheetData->AddTextStyle(rStyleName, aCellPos, rFmt.maSelection);
380 
381     std::unique_ptr<SfxPoolItem> pPoolItem;
382     sal_uInt16 nLastItemID = EE_CHAR_END + 1;
383 
384     for (const auto& rProp : rProps)
385     {
386         if (rProp.mnIndex == -1 || rProp.mnIndex >= nEntryCount)
387             continue;
388 
389         const OUString& rName = xMapper->GetEntryAPIName(rProp.mnIndex);
390         const ScXMLEditAttributeMap::Entry* pEntry = rEditAttrMap.getEntryByAPIName(rName);
391         if (!pEntry)
392             continue;
393 
394         if (nLastItemID != pEntry->mnItemID && pPoolItem)
395         {
396             // Flush the last item when the item ID changes.
397             rFmt.maItemSet.Put(*pPoolItem);
398             pPoolItem.reset();
399         }
400 
401         switch (pEntry->mnItemID)
402         {
403             case EE_CHAR_FONTINFO:
404             case EE_CHAR_FONTINFO_CJK:
405             case EE_CHAR_FONTINFO_CTL:
406             {
407                 // Font properties need to be consolidated into a single item.
408                 if (!pPoolItem)
409                     pPoolItem.reset(new SvxFontItem(pEntry->mnItemID));
410 
411                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
412             }
413             break;
414             case EE_CHAR_WEIGHT:
415             case EE_CHAR_WEIGHT_CJK:
416             case EE_CHAR_WEIGHT_CTL:
417             {
418                 if (!pPoolItem)
419                     pPoolItem.reset(new SvxWeightItem(WEIGHT_NORMAL, pEntry->mnItemID));
420 
421                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
422             }
423             break;
424             case EE_CHAR_FONTHEIGHT:
425             case EE_CHAR_FONTHEIGHT_CJK:
426             case EE_CHAR_FONTHEIGHT_CTL:
427             {
428                 if (!pPoolItem)
429                     pPoolItem.reset(new SvxFontHeightItem(240, 100, pEntry->mnItemID));
430 
431                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
432             }
433             break;
434             case EE_CHAR_ITALIC:
435             case EE_CHAR_ITALIC_CJK:
436             case EE_CHAR_ITALIC_CTL:
437             {
438                 if (!pPoolItem)
439                     pPoolItem.reset(new SvxPostureItem(ITALIC_NONE, pEntry->mnItemID));
440 
441                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
442             }
443             break;
444             case EE_CHAR_UNDERLINE:
445             {
446                 if (!pPoolItem)
447                     pPoolItem.reset(new SvxUnderlineItem(LINESTYLE_NONE, pEntry->mnItemID));
448 
449                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
450             }
451             break;
452             case EE_CHAR_OVERLINE:
453             {
454                 if (!pPoolItem)
455                     pPoolItem.reset(new SvxOverlineItem(LINESTYLE_NONE, pEntry->mnItemID));
456 
457                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
458             }
459             break;
460             case EE_CHAR_COLOR:
461             {
462                 if (!pPoolItem)
463                     pPoolItem.reset(new SvxColorItem(pEntry->mnItemID));
464 
465                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
466             }
467             break;
468             case EE_CHAR_WLM:
469             {
470                 if (!pPoolItem)
471                     pPoolItem.reset(new SvxWordLineModeItem(false, pEntry->mnItemID));
472 
473                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
474             }
475             break;
476             case EE_CHAR_STRIKEOUT:
477             {
478                 if (!pPoolItem)
479                     pPoolItem.reset(new SvxCrossedOutItem(STRIKEOUT_NONE, pEntry->mnItemID));
480 
481                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
482             }
483             break;
484             case EE_CHAR_RELIEF:
485             {
486                 if (!pPoolItem)
487                     pPoolItem.reset(new SvxCharReliefItem(FontRelief::NONE, pEntry->mnItemID));
488 
489                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
490             }
491             break;
492             case EE_CHAR_OUTLINE:
493             {
494                 if (!pPoolItem)
495                     pPoolItem.reset(new SvxContourItem(false, pEntry->mnItemID));
496 
497                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
498             }
499             break;
500             case EE_CHAR_SHADOW:
501             {
502                 if (!pPoolItem)
503                     pPoolItem.reset(new SvxShadowedItem(false, pEntry->mnItemID));
504 
505                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
506             }
507             break;
508             case EE_CHAR_KERNING:
509             {
510                 if (!pPoolItem)
511                     pPoolItem.reset(new SvxKerningItem(0, pEntry->mnItemID));
512 
513                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
514             }
515             break;
516             case EE_CHAR_PAIRKERNING:
517             {
518                 if (!pPoolItem)
519                     pPoolItem.reset(new SvxAutoKernItem(false, pEntry->mnItemID));
520 
521                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
522             }
523             break;
524             case EE_CHAR_FONTWIDTH:
525             {
526                 if (!pPoolItem)
527                     pPoolItem.reset(new SvxCharScaleWidthItem(100, pEntry->mnItemID));
528 
529                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
530             }
531             break;
532             case EE_CHAR_ESCAPEMENT:
533             {
534                 if (!pPoolItem)
535                     pPoolItem.reset(new SvxEscapementItem(pEntry->mnItemID));
536 
537                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
538             }
539             break;
540             case EE_CHAR_EMPHASISMARK:
541             {
542                 if (!pPoolItem)
543                     pPoolItem.reset(new SvxEmphasisMarkItem(FontEmphasisMark::NONE, pEntry->mnItemID));
544 
545                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
546             }
547             break;
548             case EE_CHAR_LANGUAGE:
549             case EE_CHAR_LANGUAGE_CJK:
550             case EE_CHAR_LANGUAGE_CTL:
551             {
552                 if (!pPoolItem)
553                     pPoolItem.reset(new SvxLanguageItem(LANGUAGE_DONTKNOW, pEntry->mnItemID));
554 
555                 pPoolItem->PutValue(rProp.maValue, pEntry->mnFlag);
556             }
557             break;
558             default:
559                 ;
560         }
561 
562         nLastItemID = pEntry->mnItemID;
563     }
564 
565     if (pPoolItem)
566         rFmt.maItemSet.Put(*pPoolItem);
567 }
568 
GetFirstParagraph() const569 OUString ScXMLTableRowCellContext::GetFirstParagraph() const
570 {
571     if (!maFirstParagraph)
572         return mpEditEngine->GetText(0);
573 
574     return *maFirstParagraph;
575 }
576 
PushParagraphFieldDate(const OUString & rStyleName)577 void ScXMLTableRowCellContext::PushParagraphFieldDate(const OUString& rStyleName)
578 {
579     PushParagraphField(std::make_unique<SvxDateField>(), rStyleName);
580 }
581 
PushParagraphFieldSheetName(const OUString & rStyleName)582 void ScXMLTableRowCellContext::PushParagraphFieldSheetName(const OUString& rStyleName)
583 {
584     SCTAB nTab = GetScImport().GetTables().GetCurrentCellPos().Tab();
585     PushParagraphField(std::make_unique<SvxTableField>(nTab), rStyleName);
586 }
587 
PushParagraphFieldDocTitle(const OUString & rStyleName)588 void ScXMLTableRowCellContext::PushParagraphFieldDocTitle(const OUString& rStyleName)
589 {
590     PushParagraphField(std::make_unique<SvxFileField>(), rStyleName);
591 }
592 
PushParagraphFieldURL(const OUString & rURL,const OUString & rRep,const OUString & rStyleName,const OUString & rTargetFrame)593 void ScXMLTableRowCellContext::PushParagraphFieldURL(
594     const OUString& rURL, const OUString& rRep, const OUString& rStyleName, const OUString& rTargetFrame)
595 {
596     OUString aAbsURL = GetScImport().GetAbsoluteReference(rURL);
597     std::unique_ptr<SvxURLField> pURLField(new SvxURLField(aAbsURL, rRep, SvxURLFormat::Repr));
598     pURLField->SetTargetFrame(rTargetFrame);
599     PushParagraphField(std::move(pURLField), rStyleName);
600 }
601 
PushParagraphEnd()602 void ScXMLTableRowCellContext::PushParagraphEnd()
603 {
604     // EditEngine always has at least one paragraph even when its content is empty.
605 
606     if (mbEditEngineHasText)
607     {
608         if (maFirstParagraph)
609         {
610             // Flush the cached first paragraph first.
611             mpEditEngine->Clear();
612             mpEditEngine->SetTextCurrentDefaults(*maFirstParagraph);
613             maFirstParagraph.reset();
614         }
615         mpEditEngine->InsertParagraph(mpEditEngine->GetParagraphCount(), maParagraph.makeStringAndClear());
616     }
617     else if (mbHasFormatRuns)
618     {
619         mpEditEngine->Clear();
620         mpEditEngine->SetTextCurrentDefaults(maParagraph.makeStringAndClear());
621         mbEditEngineHasText = true;
622     }
623     else if (mnCurParagraph == 0)
624     {
625         maFirstParagraph = maParagraph.makeStringAndClear();
626         mbEditEngineHasText = true;
627     }
628 
629     ++mnCurParagraph;
630 }
631 
createFastChildContext(sal_Int32 nElement,const uno::Reference<xml::sax::XFastAttributeList> & xAttrList)632 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLTableRowCellContext::createFastChildContext(
633     sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
634 {
635     SvXMLImportContext *pContext = nullptr;
636     sax_fastparser::FastAttributeList *pAttribList =
637         &sax_fastparser::castToFastAttributeList( xAttrList );
638 
639     bool bTextP(false);
640     switch (nElement)
641     {
642         case XML_ELEMENT( TEXT, XML_P ):
643         {
644             bIsEmpty = false;
645             bTextP = true;
646 
647             pContext = new ScXMLCellTextParaContext(rXMLImport, *this);
648         }
649         break;
650         case XML_ELEMENT( TABLE, XML_SUB_TABLE ):
651         {
652             SAL_WARN("sc", "ScXMLTableRowCellContext::createFastChildContext: subtables are not supported");
653         }
654         break;
655         case XML_ELEMENT( TABLE, XML_DETECTIVE ):
656         {
657             bIsEmpty = false;
658             if (!pDetectiveObjVec)
659                 pDetectiveObjVec.reset( new ScMyImpDetectiveObjVec );
660             pContext = new ScXMLDetectiveContext(
661                 rXMLImport, pDetectiveObjVec.get() );
662         }
663         break;
664         case XML_ELEMENT( TABLE, XML_CELL_RANGE_SOURCE ):
665         {
666             bIsEmpty = false;
667             if (!pCellRangeSource)
668                 pCellRangeSource.reset(new ScMyImpCellRangeSource());
669             pContext = new ScXMLCellRangeSourceContext(
670                 rXMLImport, pAttribList, pCellRangeSource.get() );
671         }
672         break;
673         case XML_ELEMENT(OFFICE, XML_ANNOTATION):
674         {
675             bIsEmpty = false;
676             OSL_ENSURE(
677                 !mxAnnotationData,
678                 "ScXMLTableRowCellContext::CreateChildContext - multiple annotations in one cell");
679             mxAnnotationData.reset( new ScXMLAnnotationData );
680             pContext = new ScXMLAnnotationContext( rXMLImport, nElement,
681                                                     xAttrList, *mxAnnotationData);
682         }
683         break;
684     }
685 
686     if (!pContext && !bTextP)
687     {
688         ScAddress aCellPos = rXMLImport.GetTables().GetCurrentCellPos();
689         uno::Reference<drawing::XShapes> xShapes (rXMLImport.GetTables().GetCurrentXShapes());
690         if (xShapes.is())
691         {
692             ScDocument* pDoc = rXMLImport.GetDocument();
693             if (aCellPos.Col() > pDoc->MaxCol())
694                 aCellPos.SetCol(pDoc->MaxCol());
695             if (aCellPos.Row() > pDoc->MaxRow())
696                 aCellPos.SetRow(pDoc->MaxRow());
697             XMLTableShapeImportHelper* pTableShapeImport =
698                     static_cast< XMLTableShapeImportHelper* >( rXMLImport.GetShapeImport().get() );
699             pTableShapeImport->SetOnTable(false);
700             pTableShapeImport->SetCell(aCellPos);
701             pContext = XMLShapeImportHelper::CreateGroupChildContext(
702                 rXMLImport, nElement, xAttrList, xShapes);
703             if (pContext)
704             {
705                 bIsEmpty = false;
706                 rXMLImport.ProgressBarIncrement();
707             }
708         }
709     }
710 
711     return pContext;
712 }
713 
DoMerge(const ScAddress & rScAddress,const SCCOL nCols,const SCROW nRows)714 void ScXMLTableRowCellContext::DoMerge( const ScAddress& rScAddress, const SCCOL nCols, const SCROW nRows )
715 {
716     SCCOL mergeToCol = rScAddress.Col() + nCols;
717     SCROW mergeToRow = rScAddress.Row() + nRows;
718     ScDocument* pDoc = rXMLImport.GetDocument();
719     bool bInBounds = rScAddress.Col() <= pDoc->MaxCol() && rScAddress.Row() <= pDoc->MaxRow() &&
720                        mergeToCol <= pDoc->MaxCol() && mergeToRow <= pDoc->MaxRow();
721     if( bInBounds )
722     {
723         pDoc->DoMerge( rScAddress.Tab(),
724             rScAddress.Col(), rScAddress.Row(), mergeToCol, mergeToRow );
725     }
726 }
727 
728 namespace {
729 
validationTypeToMode(const sheet::ValidationType eVType)730 ScValidationMode validationTypeToMode( const sheet::ValidationType eVType )
731 {
732     ScValidationMode eMode;
733     switch( eVType )
734     {
735         case sheet::ValidationType_WHOLE:               eMode = SC_VALID_WHOLE;     break;
736         case sheet::ValidationType_DECIMAL:             eMode = SC_VALID_DECIMAL;   break;
737         case sheet::ValidationType_DATE:                eMode = SC_VALID_DATE;      break;
738         case sheet::ValidationType_TIME:                eMode = SC_VALID_TIME;      break;
739         case sheet::ValidationType_TEXT_LEN:            eMode = SC_VALID_TEXTLEN;   break;
740         case sheet::ValidationType_LIST:                eMode = SC_VALID_LIST;      break;
741         case sheet::ValidationType_CUSTOM:              eMode = SC_VALID_CUSTOM;    break;
742         default:                                        eMode = SC_VALID_ANY;       break;
743     }
744     return eMode;
745 }
746 
validAlertToValidError(const sheet::ValidationAlertStyle eVAlertStyle)747 ScValidErrorStyle validAlertToValidError( const sheet::ValidationAlertStyle eVAlertStyle )
748 {
749     ScValidErrorStyle eVErrStyle;
750     switch( eVAlertStyle )
751     {
752         case sheet::ValidationAlertStyle_STOP:          eVErrStyle = SC_VALERR_STOP;      break;
753         case sheet::ValidationAlertStyle_WARNING:       eVErrStyle = SC_VALERR_WARNING;   break;
754         case sheet::ValidationAlertStyle_MACRO:         eVErrStyle = SC_VALERR_MACRO;     break;
755         default:                                        eVErrStyle = SC_VALERR_INFO;      break;
756         //should INFO be the default?  seems to be the most unobtrusive choice.
757     }
758     return eVErrStyle;
759 }
760 
761 }
762 
SetContentValidation(const ScRange & rScRange)763 void ScXMLTableRowCellContext::SetContentValidation( const ScRange& rScRange )
764 {
765     if (!maContentValidationName)
766         return;
767 
768     ScDocument* pDoc = rXMLImport.GetDocument();
769     ScMyImportValidation aValidation;
770     aValidation.eGrammar1 = aValidation.eGrammar2 = pDoc->GetStorageGrammar();
771     if( !rXMLImport.GetValidation(*maContentValidationName, aValidation) )
772         return;
773 
774     ScValidationData aScValidationData(
775         validationTypeToMode(aValidation.aValidationType),
776         ScConditionEntry::GetModeFromApi(aValidation.aOperator),
777         aValidation.sFormula1, aValidation.sFormula2, *pDoc, ScAddress(),
778         aValidation.sFormulaNmsp1, aValidation.sFormulaNmsp2,
779         aValidation.eGrammar1, aValidation.eGrammar2
780     );
781 
782     aScValidationData.SetIgnoreBlank( aValidation.bIgnoreBlanks );
783     aScValidationData.SetListType( aValidation.nShowList );
784 
785     // set strings for error / input even if disabled (and disable afterwards)
786     aScValidationData.SetInput( aValidation.sInputTitle, aValidation.sInputMessage );
787     if( !aValidation.bShowInputMessage )
788         aScValidationData.ResetInput();
789     aScValidationData.SetError( aValidation.sErrorTitle, aValidation.sErrorMessage, validAlertToValidError(aValidation.aAlertStyle) );
790     if( !aValidation.bShowErrorMessage )
791         aScValidationData.ResetError();
792 
793     if( !aValidation.sBaseCellAddress.isEmpty() )
794         aScValidationData.SetSrcString( aValidation.sBaseCellAddress );
795 
796     sal_uLong nIndex = pDoc->AddValidationEntry( aScValidationData );
797 
798     ScPatternAttr aPattern( pDoc->GetPool() );
799     aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nIndex ) );
800     if( rScRange.aStart == rScRange.aEnd )  //for a single cell
801     {
802         pDoc->ApplyPattern( rScRange.aStart.Col(), rScRange.aStart.Row(),
803                             rScRange.aStart.Tab(), aPattern );
804     }
805     else  //for repeating cells
806     {
807         pDoc->ApplyPatternAreaTab( rScRange.aStart.Col(), rScRange.aStart.Row(),
808                                rScRange.aEnd.Col(), rScRange.aEnd.Row(),
809                                rScRange.aStart.Tab(), aPattern );
810     }
811 
812     // is the below still needed?
813     // For now, any sheet with validity is blocked from stream-copying.
814     // Later, the validation names could be stored along with the style names.
815     ScSheetSaveData* pSheetData = comphelper::getUnoTunnelImplementation<ScModelObj>(GetImport().GetModel())->GetSheetSaveData();
816     pSheetData->BlockSheet( GetScImport().GetTables().GetCurrentSheet() );
817 }
818 
SetContentValidation(const ScAddress & rCellPos)819 void ScXMLTableRowCellContext::SetContentValidation( const ScAddress& rCellPos )
820 {
821     SetContentValidation( ScRange(rCellPos, rCellPos) );
822 }
823 
SetAnnotation(const ScAddress & rPos)824 void ScXMLTableRowCellContext::SetAnnotation(const ScAddress& rPos)
825 {
826     ScDocument* pDoc = rXMLImport.GetDocument();
827     if (!pDoc || !mxAnnotationData)
828         return;
829 
830     LockSolarMutex();
831 
832     ScPostIt* pNote = nullptr;
833 
834     uno::Reference< drawing::XShapes > xShapes = rXMLImport.GetTables().GetCurrentXShapes();
835     sal_Int32 nOldShapeCount = xShapes.is() ? xShapes->getCount() : 0;
836 
837     OSL_ENSURE( !mxAnnotationData->mxShape.is() || mxAnnotationData->mxShapes.is(),
838         "ScXMLTableRowCellContext::SetAnnotation - shape without drawing page" );
839     if( mxAnnotationData->mxShape.is() && mxAnnotationData->mxShapes.is() )
840     {
841         OSL_ENSURE( mxAnnotationData->mxShapes.get() == xShapes.get(), "ScXMLTableRowCellContext::SetAnnotation - different drawing pages" );
842         SdrObject* pObject = ::GetSdrObjectFromXShape( mxAnnotationData->mxShape );
843         OSL_ENSURE( pObject, "ScXMLTableRowCellContext::SetAnnotation - cannot get SdrObject from shape" );
844 
845         /*  Try to reuse the drawing object already created (but only if the
846             note is visible, and the object is a caption object). */
847         if( mxAnnotationData->mbShown && mxAnnotationData->mbUseShapePos && !comphelper::LibreOfficeKit::isActive())
848         {
849             if( SdrCaptionObj* pCaption = dynamic_cast< SdrCaptionObj* >( pObject ) )
850             {
851                 OSL_ENSURE( !pCaption->GetLogicRect().IsEmpty(), "ScXMLTableRowCellContext::SetAnnotation - invalid caption rectangle" );
852                 // create the cell note with the caption object
853                 pNote = ScNoteUtil::CreateNoteFromCaption( *pDoc, rPos, pCaption );
854                 // forget pointer to object (do not create note again below)
855                 pObject = nullptr;
856             }
857         }
858 
859         // drawing object has not been used to create a note -> use shape data
860         if( pObject )
861         {
862             // rescue settings from drawing object before the shape is removed
863             ::std::unique_ptr< SfxItemSet > xItemSet( new SfxItemSet( pObject->GetMergedItemSet() ) );
864             ::std::unique_ptr< OutlinerParaObject > xOutlinerObj;
865             if( OutlinerParaObject* pOutlinerObj = pObject->GetOutlinerParaObject() )
866                 xOutlinerObj.reset( new OutlinerParaObject( *pOutlinerObj ) );
867             tools::Rectangle aCaptionRect;
868             if( mxAnnotationData->mbUseShapePos )
869                 aCaptionRect = pObject->GetLogicRect();
870             // remove the shape from the drawing page, this invalidates pObject
871             mxAnnotationData->mxShapes->remove( mxAnnotationData->mxShape );
872             pObject = nullptr;
873             // update current number of existing objects
874             if( xShapes.is() )
875                 nOldShapeCount = xShapes->getCount();
876 
877             // an outliner object is required (empty note captions not allowed)
878             if (xOutlinerObj)
879             {
880                 // create cell note with all data from drawing object
881                 if(!comphelper::LibreOfficeKit::isActive())
882                 {
883                     pNote = ScNoteUtil::CreateNoteFromObjectData( *pDoc, rPos,
884                     std::move(xItemSet), xOutlinerObj.release(),
885                     aCaptionRect, mxAnnotationData->mbShown );
886                 }
887                 else
888                 {
889                     pNote = ScNoteUtil::CreateNoteFromObjectData( *pDoc, rPos,
890                     std::move(xItemSet), xOutlinerObj.release(),
891                     aCaptionRect, false );
892                 }
893 
894             }
895         }
896     }
897     else if( !mxAnnotationData->maSimpleText.isEmpty() )
898     {
899         // create note from simple text
900         pNote = ScNoteUtil::CreateNoteFromString( *pDoc, rPos,
901             mxAnnotationData->maSimpleText, mxAnnotationData->mbShown, false );
902     }
903 
904     // set author and date
905     if( pNote )
906     {
907         double fDate;
908         if (rXMLImport.GetMM100UnitConverter().convertDateTime(fDate, mxAnnotationData->maCreateDate))
909         {
910             SvNumberFormatter* pNumForm = pDoc->GetFormatTable();
911             sal_uInt32 nfIndex = pNumForm->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, LANGUAGE_SYSTEM );
912             OUString aDate;
913             const Color* pColor = nullptr;
914             pNumForm->GetOutputString( fDate, nfIndex, aDate, &pColor );
915             pNote->SetDate( aDate );
916         }
917         pNote->SetAuthor( mxAnnotationData->maAuthor );
918     }
919 
920     // register a shape that has been newly created in the ScNoteUtil functions
921     if( xShapes.is() && (nOldShapeCount < xShapes->getCount()) )
922     {
923         uno::Reference< drawing::XShape > xShape;
924         rXMLImport.GetShapeImport()->shapeWithZIndexAdded( xShape, xShapes->getCount() );
925     }
926 
927     // store the style names for stream copying
928     ScSheetSaveData* pSheetData = comphelper::getUnoTunnelImplementation<ScModelObj>(rXMLImport.GetModel())->GetSheetSaveData();
929     pSheetData->HandleNoteStyles( mxAnnotationData->maStyleName, mxAnnotationData->maTextStyle, rPos );
930 
931     for (const auto& rContentStyle : mxAnnotationData->maContentStyles)
932     {
933         pSheetData->AddNoteContentStyle( rContentStyle.mnFamily, rContentStyle.maName, rPos, rContentStyle.maSelection );
934     }
935 }
936 
937 // core implementation
SetDetectiveObj(const ScAddress & rPosition)938 void ScXMLTableRowCellContext::SetDetectiveObj( const ScAddress& rPosition )
939 {
940     ScDocument* pDoc = rXMLImport.GetDocument();
941     if( !pDoc || !cellExists(*pDoc, rPosition) || !pDetectiveObjVec || pDetectiveObjVec->empty() )
942         return;
943 
944     LockSolarMutex();
945     ScDetectiveFunc aDetFunc( *pDoc, rPosition.Tab() );
946     uno::Reference<container::XIndexAccess> xShapesIndex = rXMLImport.GetTables().GetCurrentXShapes(); // make draw page
947     for(const auto& rDetectiveObj : *pDetectiveObjVec)
948     {
949         aDetFunc.InsertObject( rDetectiveObj.eObjType, rPosition, rDetectiveObj.aSourceRange, rDetectiveObj.bHasError );
950         if (xShapesIndex.is())
951         {
952             sal_Int32 nShapes = xShapesIndex->getCount();
953             uno::Reference < drawing::XShape > xShape;
954             rXMLImport.GetShapeImport()->shapeWithZIndexAdded(xShape, nShapes);
955         }
956     }
957 }
958 
959 // core implementation
SetCellRangeSource(const ScAddress & rPosition)960 void ScXMLTableRowCellContext::SetCellRangeSource( const ScAddress& rPosition )
961 {
962     ScDocument* pDoc = rXMLImport.GetDocument();
963     if( !pDoc || !cellExists(*pDoc, rPosition) || !pCellRangeSource || pCellRangeSource->sSourceStr.isEmpty() ||
964         pCellRangeSource->sFilterName.isEmpty() || pCellRangeSource->sURL.isEmpty() )
965         return;
966 
967     LockSolarMutex();
968     ScRange aDestRange( rPosition.Col(), rPosition.Row(), rPosition.Tab(),
969         rPosition.Col() + static_cast<SCCOL>(pCellRangeSource->nColumns - 1),
970         rPosition.Row() + static_cast<SCROW>(pCellRangeSource->nRows - 1), rPosition.Tab() );
971     OUString sFilterName( pCellRangeSource->sFilterName );
972     OUString sSourceStr( pCellRangeSource->sSourceStr );
973     ScAreaLink* pLink = new ScAreaLink( pDoc->GetDocumentShell(), pCellRangeSource->sURL,
974         sFilterName, pCellRangeSource->sFilterOptions, sSourceStr, aDestRange, pCellRangeSource->nRefresh );
975     sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
976     pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, pCellRangeSource->sURL, &sFilterName, &sSourceStr );
977 }
978 
SetFormulaCell(ScFormulaCell * pFCell) const979 void ScXMLTableRowCellContext::SetFormulaCell(ScFormulaCell* pFCell) const
980 {
981     if(!pFCell)
982         return;
983 
984     bool bMayForceNumberformat = true;
985 
986     if(mbErrorValue)
987     {
988         // don't do anything here
989         // we need to recalc anyway
990     }
991     else if( bFormulaTextResult && maStringValue )
992     {
993         if( !IsPossibleErrorString() )
994         {
995             ScDocument* pDoc = rXMLImport.GetDocument();
996             pFCell->SetHybridString(pDoc->GetSharedStringPool().intern(*maStringValue));
997             pFCell->ResetDirty();
998             // A General format doesn't force any other format for a string
999             // result, don't attempt to recalculate this later.
1000             bMayForceNumberformat = false;
1001         }
1002     }
1003     else if (std::isfinite(fValue))
1004     {
1005         pFCell->SetHybridDouble(fValue);
1006         if (mbPossibleEmptyDisplay && fValue == 0.0)
1007         {
1008             // Needs to be recalculated to propagate, otherwise would be
1009             // propagated as empty string. So don't ResetDirty().
1010             pFCell->SetHybridEmptyDisplayedAsString();
1011         }
1012         else
1013             pFCell->ResetDirty();
1014     }
1015 
1016     if (bMayForceNumberformat)
1017         // Re-calculate to get number format only when style is not set.
1018         pFCell->SetNeedNumberFormat(!mbHasStyle);
1019 }
1020 
PutTextCell(const ScAddress & rCurrentPos,const SCCOL nCurrentCol,const::std::optional<OUString> & pOUText)1021 void ScXMLTableRowCellContext::PutTextCell( const ScAddress& rCurrentPos,
1022         const SCCOL nCurrentCol, const ::std::optional< OUString >& pOUText )
1023 {
1024     ScDocument* pDoc = rXMLImport.GetDocument();
1025     bool bDoIncrement = true;
1026     //matrix reference cells that contain text formula results;
1027     //cell was already put in document, just need to set text here.
1028     if( pDoc && rXMLImport.GetTables().IsPartOfMatrix(rCurrentPos) )
1029     {
1030         ScRefCellValue aCell(*pDoc, rCurrentPos);
1031         bDoIncrement = aCell.meType == CELLTYPE_FORMULA;
1032         if ( bDoIncrement )
1033         {
1034             ScFormulaCell* pFCell = aCell.mpFormula;
1035             OUString aCellString;
1036             if (maStringValue)
1037                 aCellString = *maStringValue;
1038             else if (mbEditEngineHasText)
1039                 aCellString = GetFirstParagraph();
1040             else if ( nCurrentCol > 0 && pOUText && !pOUText->isEmpty() )
1041                 aCellString = *pOUText;
1042             else
1043                 bDoIncrement = false;
1044 
1045             if(mbErrorValue)
1046                 bDoIncrement = false;
1047 
1048             if(!aCellString.isEmpty())
1049             {
1050                 if (bDoIncrement && !IsPossibleErrorString() && pFCell)
1051                 {
1052                     pFCell->SetHybridString(pDoc->GetSharedStringPool().intern(aCellString));
1053                     pFCell->ResetDirty();
1054                 }
1055                 else
1056                 {
1057                     ScAddress aTopLeftMatrixCell;
1058                     if (pFCell && pFCell->GetMatrixOrigin(*pDoc, aTopLeftMatrixCell))
1059                     {
1060                         ScFormulaCell* pMatrixCell = pDoc->GetFormulaCell(aTopLeftMatrixCell);
1061                         if (pMatrixCell)
1062                             pMatrixCell->SetDirty();
1063                     }
1064                     else
1065                         SAL_WARN("sc", "matrix cell without matrix");
1066                 }
1067             }
1068         }
1069     }
1070     else //regular text cells
1071     {
1072         ScDocumentImport& rDoc = rXMLImport.GetDoc();
1073         if (maStringValue)
1074         {
1075             rDoc.setStringCell(rCurrentPos, *maStringValue);
1076             bDoIncrement = true;
1077         }
1078         else if (mbEditEngineHasText)
1079         {
1080             if (maFirstParagraph)
1081             {
1082                 // This is a normal text without format runs.
1083                 rDoc.setStringCell(rCurrentPos, *maFirstParagraph);
1084             }
1085             else
1086             {
1087                 // This text either has format runs, has field(s), or consists of multiple lines.
1088                 for (const auto& rxFormat : maFormats)
1089                     mpEditEngine->QuickSetAttribs(rxFormat->maItemSet, rxFormat->maSelection);
1090 
1091                 for (const auto& rxField : maFields)
1092                     mpEditEngine->QuickInsertField(SvxFieldItem(*rxField->mpData, EE_FEATURE_FIELD), rxField->maSelection);
1093 
1094                 // This edit engine uses the SfxItemPool instance returned
1095                 // from pDoc->GetEditPool() to create the text object, which
1096                 // is a prerequisite for using this constructor of ScEditCell.
1097                 rDoc.setEditCell(rCurrentPos, mpEditEngine->CreateTextObject());
1098             }
1099             bDoIncrement = true;
1100         }
1101         else if ( nCurrentCol > 0 && pOUText && !pOUText->isEmpty() )
1102         {
1103             rDoc.setStringCell(rCurrentPos, *pOUText);
1104             bDoIncrement = true;
1105         }
1106         else
1107             bDoIncrement = false;
1108     }
1109 
1110     // #i56027# This is about setting simple text, not edit cells,
1111     // so ProgressBarIncrement must be called with bEditCell = FALSE.
1112     // Formatted text that is put into the cell by the child context
1113     // is handled in AddCellsToTable() (bIsEmpty is true then).
1114     if (bDoIncrement)
1115         rXMLImport.ProgressBarIncrement();
1116 }
1117 
PutValueCell(const ScAddress & rCurrentPos)1118 void ScXMLTableRowCellContext::PutValueCell( const ScAddress& rCurrentPos )
1119 {
1120     //matrix reference cells that contain value formula results;
1121     //cell was already put in document, just need to set value here.
1122     if( rXMLImport.GetTables().IsPartOfMatrix(rCurrentPos) )
1123     {
1124         ScRefCellValue aCell(*rXMLImport.GetDocument(), rCurrentPos);
1125         if (aCell.meType == CELLTYPE_FORMULA)
1126         {
1127             ScFormulaCell* pFCell = aCell.mpFormula;
1128             SetFormulaCell(pFCell);
1129             if (pFCell)
1130                 pFCell->SetNeedNumberFormat( true );
1131         }
1132     }
1133     else  //regular value cell
1134     {
1135         // fdo#62250 absent values are not NaN, set to 0.0
1136         // PutValueCell() is called only for a known cell value type,
1137         // bIsEmpty==false in all these cases, no sense to check it here.
1138         if (!std::isfinite( fValue))
1139             fValue = 0.0;
1140 
1141         // #i62435# Initialize the value cell's script type if the default
1142         // style's number format is latin-only. If the cell uses a different
1143         // format, the script type will be reset when the style is applied.
1144 
1145         rXMLImport.GetDoc().setNumericCell(rCurrentPos, fValue);
1146     }
1147     rXMLImport.ProgressBarIncrement();
1148 }
1149 
1150 namespace {
1151 
isEmptyOrNote(const ScDocument * pDoc,const ScAddress & rCurrentPos)1152 bool isEmptyOrNote( const ScDocument* pDoc, const ScAddress& rCurrentPos )
1153 {
1154     CellType eType = pDoc->GetCellType(rCurrentPos);
1155     return (eType == CELLTYPE_NONE);
1156 }
1157 
1158 }
1159 
AddTextAndValueCell(const ScAddress & rCellPos,const::std::optional<OUString> & pOUText,ScAddress & rCurrentPos)1160 void ScXMLTableRowCellContext::AddTextAndValueCell( const ScAddress& rCellPos,
1161         const ::std::optional< OUString >& pOUText, ScAddress& rCurrentPos )
1162 {
1163     ScDocument* pDoc = rXMLImport.GetDocument();
1164     ScMyTables& rTables = rXMLImport.GetTables();
1165     bool bWasEmpty = bIsEmpty;
1166     for (SCCOL i = 0; i < nColsRepeated; ++i)
1167     {
1168         rCurrentPos.SetCol( rCellPos.Col() + i );
1169 
1170         // it makes no sense to import data after the last supported column
1171         // fdo#58539 & gnome#627150
1172         if(rCurrentPos.Col() > pDoc->MaxCol())
1173             break;
1174 
1175         if (i > 0)
1176             rTables.AddColumn(false);
1177         if (!bIsEmpty)
1178         {
1179             for (SCROW j = 0; j < nRepeatedRows; ++j)
1180             {
1181                 rCurrentPos.SetRow( rCellPos.Row() + j );
1182 
1183                 // it makes no sense to import data after last supported row
1184                 // fdo#58539 & gnome#627150
1185                 if(rCurrentPos.Row() > pDoc->MaxRow())
1186                     break;
1187 
1188                 if( (rCurrentPos.Col() == 0) && (j > 0) )
1189                 {
1190                     rTables.AddRow();
1191                     rTables.AddColumn(false);
1192                 }
1193                 if( cellExists(*pDoc, rCurrentPos) )
1194                 {
1195                     if(  !bIsCovered || isEmptyOrNote(pDoc, rCurrentPos)  )
1196                     {
1197                         switch (nCellType)
1198                         {
1199                             case util::NumberFormat::TEXT:
1200                             {
1201                                 PutTextCell( rCurrentPos, i, pOUText );
1202                             }
1203                             break;
1204                             case util::NumberFormat::NUMBER:
1205                             case util::NumberFormat::PERCENT:
1206                             case util::NumberFormat::CURRENCY:
1207                             case util::NumberFormat::TIME:
1208                             case util::NumberFormat::DATETIME:
1209                             case util::NumberFormat::LOGICAL:
1210                             {
1211                                 PutValueCell( rCurrentPos );
1212                             }
1213                             break;
1214                             default:
1215                             {
1216                                 OSL_FAIL("no cell type given");
1217                             }
1218                             break;
1219                         }
1220                     }
1221 
1222                     SetAnnotation( rCurrentPos );
1223                     SetDetectiveObj( rCurrentPos );
1224                     SetCellRangeSource( rCurrentPos );
1225                 }
1226                 else
1227                 {
1228                     if (!bWasEmpty || mxAnnotationData)
1229                     {
1230                         if (rCurrentPos.Row() > pDoc->MaxRow())
1231                             rXMLImport.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW);
1232                         else
1233                             rXMLImport.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW);
1234                     }
1235                 }
1236             }
1237         }
1238         else
1239         {
1240             if ((i == 0) && (rCellPos.Col() == 0))
1241             {
1242                 for (sal_Int32 j = 1; j < nRepeatedRows; ++j)
1243                 {
1244                     rTables.AddRow();
1245                     rTables.AddColumn(false);
1246                 }
1247             }
1248         }
1249     }
1250 }
1251 
CellsAreRepeated() const1252 bool ScXMLTableRowCellContext::CellsAreRepeated() const
1253 {
1254     return ( (nColsRepeated > 1) || (nRepeatedRows > 1) );
1255 }
1256 
1257 namespace {
1258 
1259 // from ScCellObj::GetOutputString_Imp().  all of it may not be necessary.
getOutputString(ScDocument * pDoc,const ScAddress & aCellPos)1260 OUString getOutputString( ScDocument* pDoc, const ScAddress& aCellPos )
1261 {
1262     if (!pDoc)
1263         return OUString();
1264 
1265     ScRefCellValue aCell(*pDoc, aCellPos);
1266     switch (aCell.meType)
1267     {
1268         case CELLTYPE_NONE:
1269             return OUString();
1270         case CELLTYPE_EDIT:
1271         {
1272             //  GetString on EditCell replaces linebreaks with spaces;
1273             //  however here we need line breaks
1274             const EditTextObject* pData = aCell.mpEditText;
1275             EditEngine& rEngine = pDoc->GetEditEngine();
1276             rEngine.SetText(*pData);
1277             return rEngine.GetText();
1278             //  also don't format EditCells per NumberFormatter
1279         }
1280         break;
1281         default:
1282         {
1283             //  like in GetString for document (column)
1284             const Color* pColor;
1285             sal_uInt32 nNumFmt = pDoc->GetNumberFormat(aCellPos);
1286             OUString aStr;
1287             ScCellFormat::GetString(aCell, nNumFmt, aStr, &pColor, *pDoc->GetFormatTable(), *pDoc);
1288             return aStr;
1289         }
1290     }
1291 }
1292 
1293 }
1294 
AddNonFormulaCell(const ScAddress & rCellPos)1295 void ScXMLTableRowCellContext::AddNonFormulaCell( const ScAddress& rCellPos )
1296 {
1297     ::std::optional< OUString > pOUText;
1298 
1299     ScDocument* pDoc = rXMLImport.GetDocument();
1300     if( nCellType == util::NumberFormat::TEXT )
1301     {
1302         if( !bIsEmpty && !maStringValue && !mbEditEngineHasText && cellExists(*pDoc, rCellPos) && CellsAreRepeated() )
1303             pOUText = getOutputString(pDoc, rCellPos);
1304 
1305         if (!mbEditEngineHasText && !pOUText && !maStringValue)
1306             bIsEmpty = true;
1307     }
1308 
1309     ScAddress aCurrentPos( rCellPos );
1310     if( mxAnnotationData || pDetectiveObjVec || pCellRangeSource ) // has special content
1311         bIsEmpty = false;
1312 
1313     AddTextAndValueCell( rCellPos, pOUText, aCurrentPos );
1314 
1315     if( CellsAreRepeated() )
1316     {
1317         SCCOL nStartCol( std::min(rCellPos.Col(), pDoc->MaxCol()) );
1318         SCROW nStartRow( std::min(rCellPos.Row(), pDoc->MaxRow()) );
1319         SCCOL nEndCol( std::min<SCCOL>(rCellPos.Col() + nColsRepeated - 1, pDoc->MaxCol()) );
1320         SCROW nEndRow( std::min(rCellPos.Row() + nRepeatedRows - 1, pDoc->MaxRow()) );
1321         ScRange aScRange( nStartCol, nStartRow, rCellPos.Tab(), nEndCol, nEndRow, rCellPos.Tab() );
1322         SetContentValidation( aScRange );
1323         rXMLImport.GetStylesImportHelper()->AddRange( aScRange );
1324     }
1325     else if( cellExists(*pDoc, rCellPos) )
1326     {
1327         rXMLImport.GetStylesImportHelper()->AddCell(rCellPos);
1328         SetContentValidation( rCellPos );
1329     }
1330 }
1331 
PutFormulaCell(const ScAddress & rCellPos)1332 void ScXMLTableRowCellContext::PutFormulaCell( const ScAddress& rCellPos )
1333 {
1334     ScDocument* pDoc = rXMLImport.GetDocument();
1335     ScDocumentImport& rDocImport = rXMLImport.GetDoc();
1336 
1337     OUString aText = maFormula->first;
1338 
1339     ScExternalRefManager::ApiGuard aExtRefGuard(*pDoc);
1340 
1341     if ( aText.isEmpty() )
1342         return;
1343 
1344     // temporary formula string as string tokens
1345     std::unique_ptr<ScTokenArray> pCode(new ScTokenArray(*pDoc));
1346 
1347     // Check the special case of a single error constant without leading
1348     // '=' and create an error formula cell without tokens.
1349     FormulaError nError = GetScImport().GetFormulaErrorConstant(aText);
1350     if (nError != FormulaError::NONE)
1351     {
1352         pCode->SetCodeError(nError);
1353     }
1354     else
1355     {
1356         // 5.2 and earlier wrote broken "Err:xxx" as formula to designate
1357         // an error formula cell.
1358         if (aText.startsWithIgnoreAsciiCase("Err:") && aText.getLength() <= 9 &&
1359                 ((nError =
1360                   GetScImport().GetFormulaErrorConstant( OUString::Concat("#ERR") + aText.subView(4) + "!")) != FormulaError::NONE))
1361         {
1362             pCode->SetCodeError(nError);
1363         }
1364         else
1365         {
1366             OUString aFormulaNmsp = maFormula->second;
1367             if( eGrammar != formula::FormulaGrammar::GRAM_EXTERNAL )
1368                 aFormulaNmsp.clear();
1369             pCode->AssignXMLString( aText, aFormulaNmsp );
1370             rDocImport.getDoc().IncXMLImportedFormulaCount( aText.getLength() );
1371         }
1372     }
1373 
1374     ScFormulaCell* pNewCell = new ScFormulaCell(*pDoc, rCellPos, std::move(pCode), eGrammar, ScMatrixMode::NONE);
1375     SetFormulaCell(pNewCell);
1376     rDocImport.setFormulaCell(rCellPos, pNewCell);
1377 }
1378 
AddFormulaCell(const ScAddress & rCellPos)1379 void ScXMLTableRowCellContext::AddFormulaCell( const ScAddress& rCellPos )
1380 {
1381     ScDocument* pDoc = rXMLImport.GetDocument();
1382     if( cellExists(*pDoc, rCellPos) )
1383     {
1384         SetContentValidation( rCellPos );
1385         SAL_WARN_IF((nColsRepeated != 1) || (nRepeatedRows != 1), "sc", "repeated cells with formula not possible now");
1386         rXMLImport.GetStylesImportHelper()->AddCell(rCellPos);
1387 
1388         //add matrix
1389         if(bIsMatrix)
1390         {
1391             if (nMatrixCols > 0 && nMatrixRows > 0)
1392             {
1393                 //matrix cells are put in the document, but we must set the
1394                 //value/text of each matrix cell later
1395                 rXMLImport.GetTables().AddMatrixRange(
1396                         rCellPos.Col(), rCellPos.Row(),
1397                         std::min<SCCOL>(rCellPos.Col() + nMatrixCols - 1, pDoc->MaxCol()),
1398                         std::min<SCROW>(rCellPos.Row() + nMatrixRows - 1, pDoc->MaxRow()),
1399                         maFormula->first, maFormula->second, eGrammar);
1400 
1401                 // Set the value/text of the top-left matrix position in its
1402                 // cached result.  For import, we only need to set the correct
1403                 // matrix geometry and the value type of the top-left element.
1404                 ScFormulaCell* pFCell = pDoc->GetFormulaCell(rCellPos);
1405                 if (pFCell)
1406                 {
1407                     ScMatrixRef pMat(new ScMatrix(nMatrixCols, nMatrixRows));
1408                     if (bFormulaTextResult && maStringValue)
1409                     {
1410                         if (!IsPossibleErrorString())
1411                         {
1412                             pFCell->SetResultMatrix(
1413                                     nMatrixCols, nMatrixRows, pMat, new formula::FormulaStringToken(
1414                                         pDoc->GetSharedStringPool().intern( *maStringValue)));
1415                             pFCell->ResetDirty();
1416                         }
1417                     }
1418                     else if (std::isfinite(fValue))
1419                     {
1420                         pFCell->SetResultMatrix(
1421                             nMatrixCols, nMatrixRows, pMat, new formula::FormulaDoubleToken(fValue));
1422                         pFCell->ResetDirty();
1423                     }
1424                 }
1425             }
1426         }
1427         else
1428             PutFormulaCell( rCellPos );
1429 
1430         SetAnnotation( rCellPos );
1431         SetDetectiveObj( rCellPos );
1432         SetCellRangeSource( rCellPos );
1433         rXMLImport.ProgressBarIncrement();
1434     }
1435     else
1436     {
1437         if (rCellPos.Row() > pDoc->MaxRow())
1438             rXMLImport.SetRangeOverflowType(SCWARN_IMPORT_ROW_OVERFLOW);
1439         else
1440             rXMLImport.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW);
1441     }
1442 }
1443 
1444 //There are cases where a formula cell is exported with an office:value of 0 or
1445 //no office:value at all, but the formula cell will have a text:p value which
1446 //contains the intended formula result.
1447 //These cases include when a formula result:
1448 // - is blank
1449 // - has a constant error value beginning with "#" (such as "#VALUE!" or "#N/A")
1450 // - has an "Err:[###]" (where "[###]" is an error number)
1451 // Libreoffice 4.1+ with ODF1.2 extended write however calcext:value-type="error" in that case
HasSpecialCaseFormulaText()1452 void ScXMLTableRowCellContext::HasSpecialCaseFormulaText()
1453 {
1454     if (!mbEditEngineHasText)
1455         return;
1456 
1457     const OUString aStr = GetFirstParagraph();
1458 
1459     if (mbNewValueType)
1460     {
1461         if (aStr.isEmpty())
1462             mbPossibleEmptyDisplay = true;
1463         return;
1464     }
1465 
1466     if (aStr.isEmpty())
1467     {
1468         mbPossibleErrorCell = true;
1469         mbPossibleEmptyDisplay = true;
1470     }
1471     else if (aStr.startsWith("Err:"))
1472         mbPossibleErrorCell = true;
1473     else if (aStr.startsWith("#"))
1474         mbCheckWithCompilerForError = true;
1475 }
1476 
IsPossibleErrorString() const1477 bool ScXMLTableRowCellContext::IsPossibleErrorString() const
1478 {
1479     if(mbNewValueType && !mbErrorValue)
1480         return false;
1481     else if(mbNewValueType && mbErrorValue)
1482         return true;
1483     return mbPossibleErrorCell || (mbCheckWithCompilerForError &&
1484             GetScImport().GetFormulaErrorConstant(*maStringValue) != FormulaError::NONE);
1485 }
1486 
endFastElement(sal_Int32)1487 void SAL_CALL ScXMLTableRowCellContext::endFastElement(sal_Int32 /*nElement*/)
1488 {
1489     HasSpecialCaseFormulaText();
1490     if( bFormulaTextResult && (mbPossibleErrorCell || mbCheckWithCompilerForError) )
1491     {
1492         maStringValue = GetFirstParagraph();
1493     }
1494 
1495     ScAddress aCellPos = rXMLImport.GetTables().GetCurrentCellPos();
1496     if( aCellPos.Col() > 0 && nRepeatedRows > 1 )
1497         aCellPos.SetRow( aCellPos.Row() - (nRepeatedRows - 1) );
1498     if( bIsMerged )
1499         DoMerge( aCellPos, nMergedCols - 1, nMergedRows - 1 );
1500 
1501     if (maFormula)
1502         AddFormulaCell(aCellPos);
1503     else
1504         AddNonFormulaCell(aCellPos);
1505 
1506     //if LockSolarMutex got used, we presumably need to ensure an UnlockSolarMutex
1507     if (bSolarMutexLocked)
1508     {
1509         GetScImport().UnlockSolarMutex();
1510         bSolarMutexLocked = false;
1511     }
1512 
1513     bIsMerged = false;
1514     nMergedCols = 1;
1515     nMergedRows = 1;
1516     nColsRepeated = 1;
1517 }
1518 
1519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1520