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