Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / xml / xmlcvali.cxx
blob78dc7fd49597ca23dd6e3704b1e14a40a25d8a54
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "xmlcvali.hxx"
21 #include "xmlimprt.hxx"
22 #include "xmlconti.hxx"
23 #include <document.hxx>
24 #include "XMLConverter.hxx"
26 #include <xmloff/xmltkmap.hxx>
27 #include <xmloff/xmltoken.hxx>
28 #include <xmloff/xmlnmspe.hxx>
29 #include <xmloff/XMLEventsImportContext.hxx>
30 #include <com/sun/star/sheet/TableValidationVisibility.hpp>
32 using namespace com::sun::star;
33 using namespace xmloff::token;
34 using namespace ::formula;
36 class ScXMLContentValidationContext : public ScXMLImportContext
38 OUString sName;
39 OUString sHelpTitle;
40 OUString sHelpMessage;
41 OUString sErrorTitle;
42 OUString sErrorMessage;
43 OUString sErrorMessageType;
44 OUString sBaseCellAddress;
45 OUString sCondition;
46 sal_Int16 nShowList;
47 bool bAllowEmptyCell;
48 bool bDisplayHelp;
49 bool bDisplayError;
51 SvXMLImportContextRef xEventContext;
53 css::sheet::ValidationAlertStyle GetAlertStyle() const;
54 void SetFormula( OUString& rFormula, OUString& rFormulaNmsp, FormulaGrammar::Grammar& reGrammar,
55 const OUString& rCondition, const OUString& rGlobNmsp, FormulaGrammar::Grammar eGlobGrammar, bool bHasNmsp ) const;
56 void GetCondition( ScMyImportValidation& rValidation ) const;
58 public:
60 ScXMLContentValidationContext( ScXMLImport& rImport,
61 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList );
63 virtual SvXMLImportContextRef CreateChildContext( sal_uInt16 nPrefix,
64 const OUString& rLocalName,
65 const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList ) override;
67 virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
68 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
70 virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override;
72 void SetHelpMessage(const OUString& sTitle, const OUString& sMessage, const bool bDisplay);
73 void SetErrorMessage(const OUString& sTitle, const OUString& sMessage, const OUString& sMessageType, const bool bDisplay);
74 void SetErrorMacro(const bool bExecute);
77 class ScXMLHelpMessageContext : public ScXMLImportContext
79 OUString sTitle;
80 OUStringBuffer sMessage;
81 sal_Int32 nParagraphCount;
82 bool bDisplay;
84 ScXMLContentValidationContext* pValidationContext;
86 public:
88 ScXMLHelpMessageContext( ScXMLImport& rImport,
89 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
90 ScXMLContentValidationContext* pValidationContext);
92 virtual SvXMLImportContextRef CreateChildContext( sal_uInt16 nPrefix,
93 const OUString& rLocalName,
94 const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList ) override;
96 virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override;
99 class ScXMLErrorMessageContext : public ScXMLImportContext
101 OUString sTitle;
102 OUStringBuffer sMessage;
103 OUString sMessageType;
104 sal_Int32 nParagraphCount;
105 bool bDisplay;
107 ScXMLContentValidationContext* pValidationContext;
109 public:
111 ScXMLErrorMessageContext( ScXMLImport& rImport,
112 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
113 ScXMLContentValidationContext* pValidationContext);
115 virtual SvXMLImportContextRef CreateChildContext( sal_uInt16 nPrefix,
116 const OUString& rLocalName,
117 const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList ) override;
119 virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override;
122 class ScXMLErrorMacroContext : public ScXMLImportContext
124 bool bExecute;
125 ScXMLContentValidationContext* pValidationContext;
127 public:
129 ScXMLErrorMacroContext( ScXMLImport& rImport,
130 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
131 ScXMLContentValidationContext* pValidationContext);
133 virtual SvXMLImportContextRef CreateChildContext( sal_uInt16 nPrefix,
134 const OUString& rLocalName,
135 const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList ) override;
136 virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override;
139 ScXMLContentValidationsContext::ScXMLContentValidationsContext( ScXMLImport& rImport ) :
140 ScXMLImportContext( rImport )
142 // here are no attributes
145 ScXMLContentValidationsContext::~ScXMLContentValidationsContext()
149 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLContentValidationsContext::createFastChildContext(
150 sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
152 SvXMLImportContext *pContext = nullptr;
153 sax_fastparser::FastAttributeList *pAttribList =
154 sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
156 switch (nElement)
158 case XML_ELEMENT( TABLE, XML_CONTENT_VALIDATION ):
159 pContext = new ScXMLContentValidationContext( GetScImport(), pAttribList );
160 break;
163 if( !pContext )
164 pContext = new SvXMLImportContext( GetImport() );
166 return pContext;
169 ScXMLContentValidationContext::ScXMLContentValidationContext( ScXMLImport& rImport,
170 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList ) :
171 ScXMLImportContext( rImport ),
172 nShowList(sheet::TableValidationVisibility::UNSORTED),
173 bAllowEmptyCell(true),
174 bDisplayHelp(false),
175 bDisplayError(false)
177 if ( rAttrList.is() )
179 for (auto &aIter : *rAttrList)
181 switch (aIter.getToken())
183 case XML_ELEMENT( TABLE, XML_NAME ):
184 sName = aIter.toString();
185 break;
186 case XML_ELEMENT( TABLE, XML_CONDITION ):
187 sCondition = aIter.toString();
188 break;
189 case XML_ELEMENT( TABLE, XML_BASE_CELL_ADDRESS ):
190 sBaseCellAddress = aIter.toString();
191 break;
192 case XML_ELEMENT( TABLE, XML_ALLOW_EMPTY_CELL ):
193 if (IsXMLToken(aIter, XML_FALSE))
194 bAllowEmptyCell = false;
195 break;
196 case XML_ELEMENT( TABLE, XML_DISPLAY_LIST ):
197 if (IsXMLToken(aIter, XML_NO))
199 nShowList = sheet::TableValidationVisibility::INVISIBLE;
201 else if (IsXMLToken(aIter, XML_UNSORTED))
203 nShowList = sheet::TableValidationVisibility::UNSORTED;
205 else if (IsXMLToken(aIter, XML_SORT_ASCENDING))
207 nShowList = sheet::TableValidationVisibility::SORTEDASCENDING;
209 else if (IsXMLToken(aIter, XML_SORTED_ASCENDING))
211 // Read old wrong value, fdo#72548
212 nShowList = sheet::TableValidationVisibility::SORTEDASCENDING;
214 break;
220 SvXMLImportContextRef ScXMLContentValidationContext::CreateChildContext( sal_uInt16 nPrefix,
221 const OUString& rLName,
222 const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttrList*/ )
224 SvXMLImportContext *pContext = nullptr;
226 const SvXMLTokenMap& rTokenMap = GetScImport().GetContentValidationElemTokenMap();
227 switch( rTokenMap.Get( nPrefix, rLName ) )
229 case XML_TOK_CONTENT_VALIDATION_ELEM_EVENT_LISTENERS:
230 pContext = new XMLEventsImportContext( GetImport(), nPrefix, rLName );
231 xEventContext = pContext;
232 break;
235 if( !pContext )
236 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLName );
238 return pContext;
241 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLContentValidationContext::createFastChildContext(
242 sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
244 SvXMLImportContext *pContext = nullptr;
245 sax_fastparser::FastAttributeList *pAttribList =
246 sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
248 switch (nElement)
250 case XML_ELEMENT( TABLE, XML_HELP_MESSAGE ):
251 pContext = new ScXMLHelpMessageContext( GetScImport(), pAttribList, this);
252 break;
253 case XML_ELEMENT( TABLE, XML_ERROR_MESSAGE ):
254 pContext = new ScXMLErrorMessageContext( GetScImport(), pAttribList, this);
255 break;
256 case XML_ELEMENT( TABLE, XML_ERROR_MACRO ):
257 pContext = new ScXMLErrorMacroContext( GetScImport(), pAttribList, this);
258 break;
261 if( !pContext )
262 pContext = new SvXMLImportContext( GetImport() );
264 return pContext;
267 sheet::ValidationAlertStyle ScXMLContentValidationContext::GetAlertStyle() const
269 if (IsXMLToken(sErrorMessageType, XML_MACRO))
270 return sheet::ValidationAlertStyle_MACRO;
271 if (IsXMLToken(sErrorMessageType, XML_STOP))
272 return sheet::ValidationAlertStyle_STOP;
273 if (IsXMLToken(sErrorMessageType, XML_WARNING))
274 return sheet::ValidationAlertStyle_WARNING;
275 if (IsXMLToken(sErrorMessageType, XML_INFORMATION))
276 return sheet::ValidationAlertStyle_INFO;
277 // default for unknown
278 return sheet::ValidationAlertStyle_STOP;
281 void ScXMLContentValidationContext::SetFormula( OUString& rFormula, OUString& rFormulaNmsp, FormulaGrammar::Grammar& reGrammar,
282 const OUString& rCondition, const OUString& rGlobNmsp, FormulaGrammar::Grammar eGlobGrammar, bool bHasNmsp ) const
284 reGrammar = FormulaGrammar::GRAM_UNSPECIFIED;
285 if( bHasNmsp )
287 // the entire attribute contains a namespace: internal namespace not allowed
288 rFormula = rCondition;
289 rFormulaNmsp = rGlobNmsp;
290 reGrammar = eGlobGrammar;
292 else
294 // the attribute does not contain a namespace: try to find a namespace of an external grammar
295 GetScImport().ExtractFormulaNamespaceGrammar( rFormula, rFormulaNmsp, reGrammar, rCondition, true );
296 if( reGrammar != FormulaGrammar::GRAM_EXTERNAL )
297 reGrammar = eGlobGrammar;
301 void ScXMLContentValidationContext::GetCondition( ScMyImportValidation& rValidation ) const
303 rValidation.aValidationType = sheet::ValidationType_ANY; // default if no condition is given
304 rValidation.aOperator = sheet::ConditionOperator_NONE;
306 if( !sCondition.isEmpty() )
308 // extract leading namespace from condition string
309 OUString aCondition, aConditionNmsp;
310 FormulaGrammar::Grammar eGrammar = FormulaGrammar::GRAM_UNSPECIFIED;
311 GetScImport().ExtractFormulaNamespaceGrammar( aCondition, aConditionNmsp, eGrammar, sCondition );
312 bool bHasNmsp = aCondition.getLength() < sCondition.getLength();
314 // parse a condition from the attribute string
315 ScXMLConditionParseResult aParseResult;
316 ScXMLConditionHelper::parseCondition( aParseResult, aCondition, 0 );
318 /* Check the result. A valid value in aParseResult.meToken implies
319 that the other members of aParseResult are filled with valid data
320 for that token. */
321 bool bSecondaryPart = false;
322 switch( aParseResult.meToken )
324 case XML_COND_TEXTLENGTH: // condition is 'cell-content-text-length()<operator><expression>'
325 case XML_COND_TEXTLENGTH_ISBETWEEN: // condition is 'cell-content-text-length-is-between(<expression1>,<expression2>)'
326 case XML_COND_TEXTLENGTH_ISNOTBETWEEN: // condition is 'cell-content-text-length-is-not-between(<expression1>,<expression2>)'
327 case XML_COND_ISINLIST: // condition is 'cell-content-is-in-list(<expression>)'
328 case XML_COND_ISTRUEFORMULA: // condition is 'is-true-formula(<expression>)'
329 rValidation.aValidationType = aParseResult.meValidation;
330 rValidation.aOperator = aParseResult.meOperator;
331 break;
333 case XML_COND_ISWHOLENUMBER: // condition is 'cell-content-is-whole-number() and <condition>'
334 case XML_COND_ISDECIMALNUMBER: // condition is 'cell-content-is-decimal-number() and <condition>'
335 case XML_COND_ISDATE: // condition is 'cell-content-is-date() and <condition>'
336 case XML_COND_ISTIME: // condition is 'cell-content-is-time() and <condition>'
337 rValidation.aValidationType = aParseResult.meValidation;
338 bSecondaryPart = true;
339 break;
341 default:; // unacceptable or unknown condition
344 /* Parse the following 'and <condition>' part of some conditions. This
345 updates the members of aParseResult that will contain the operands
346 and comparison operator then. */
347 if( bSecondaryPart )
349 ScXMLConditionHelper::parseCondition( aParseResult, aCondition, aParseResult.mnEndIndex );
350 if( aParseResult.meToken == XML_COND_AND )
352 ScXMLConditionHelper::parseCondition( aParseResult, aCondition, aParseResult.mnEndIndex );
353 switch( aParseResult.meToken )
355 case XML_COND_CELLCONTENT: // condition is 'and cell-content()<operator><expression>'
356 case XML_COND_ISBETWEEN: // condition is 'and cell-content-is-between(<expression1>,<expression2>)'
357 case XML_COND_ISNOTBETWEEN: // condition is 'and cell-content-is-not-between(<expression1>,<expression2>)'
358 rValidation.aOperator = aParseResult.meOperator;
359 break;
360 default:; // unacceptable or unknown condition
365 // a validation type (date, integer) without a condition isn't possible
366 if( rValidation.aOperator == sheet::ConditionOperator_NONE )
367 rValidation.aValidationType = sheet::ValidationType_ANY;
369 // parse the formulas
370 if( rValidation.aValidationType != sheet::ValidationType_ANY )
372 SetFormula( rValidation.sFormula1, rValidation.sFormulaNmsp1, rValidation.eGrammar1,
373 aParseResult.maOperand1, aConditionNmsp, eGrammar, bHasNmsp );
374 SetFormula( rValidation.sFormula2, rValidation.sFormulaNmsp2, rValidation.eGrammar2,
375 aParseResult.maOperand2, aConditionNmsp, eGrammar, bHasNmsp );
380 void SAL_CALL ScXMLContentValidationContext::endFastElement( sal_Int32 /*nElement*/ )
382 // #i36650# event-listeners element moved up one level
383 if (xEventContext.is())
385 XMLEventsImportContext* pEvents =
386 static_cast<XMLEventsImportContext*>(xEventContext.get());
387 uno::Sequence<beans::PropertyValue> aValues;
388 pEvents->GetEventSequence( "OnError", aValues );
390 auto pValue = std::find_if(aValues.begin(), aValues.end(),
391 [](const beans::PropertyValue& rValue) {
392 return rValue.Name == "MacroName" || rValue.Name == "Script"; });
393 if (pValue != aValues.end())
394 pValue->Value >>= sErrorTitle;
397 ScMyImportValidation aValidation;
398 aValidation.eGrammar1 = aValidation.eGrammar2 = GetScImport().GetDocument()->GetStorageGrammar();
399 aValidation.sName = sName;
400 aValidation.sBaseCellAddress = sBaseCellAddress;
401 aValidation.sImputTitle = sHelpTitle;
402 aValidation.sImputMessage = sHelpMessage;
403 aValidation.sErrorTitle = sErrorTitle;
404 aValidation.sErrorMessage = sErrorMessage;
405 GetCondition( aValidation );
406 aValidation.aAlertStyle = GetAlertStyle();
407 aValidation.bShowErrorMessage = bDisplayError;
408 aValidation.bShowImputMessage = bDisplayHelp;
409 aValidation.bIgnoreBlanks = bAllowEmptyCell;
410 aValidation.nShowList = nShowList;
411 GetScImport().AddValidation(aValidation);
414 void ScXMLContentValidationContext::SetHelpMessage(const OUString& sTitle, const OUString& sMessage, const bool bDisplay)
416 sHelpTitle = sTitle;
417 sHelpMessage = sMessage;
418 bDisplayHelp = bDisplay;
421 void ScXMLContentValidationContext::SetErrorMessage(const OUString& sTitle, const OUString& sMessage,
422 const OUString& sMessageType, const bool bDisplay)
424 sErrorTitle = sTitle;
425 sErrorMessage = sMessage;
426 sErrorMessageType = sMessageType;
427 bDisplayError = bDisplay;
430 void ScXMLContentValidationContext::SetErrorMacro(const bool bExecute)
432 sErrorMessageType = "macro";
433 bDisplayError = bExecute;
436 ScXMLHelpMessageContext::ScXMLHelpMessageContext( ScXMLImport& rImport,
437 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
438 ScXMLContentValidationContext* pTempValidationContext) :
439 ScXMLImportContext( rImport ),
440 sTitle(),
441 sMessage(),
442 nParagraphCount(0),
443 bDisplay(false)
445 pValidationContext = pTempValidationContext;
446 if ( rAttrList.is() )
448 for (auto &aIter : *rAttrList)
450 switch (aIter.getToken())
452 case XML_ELEMENT( TABLE, XML_TITLE ):
453 sTitle = aIter.toString();
454 break;
455 case XML_ELEMENT( TABLE, XML_DISPLAY ):
456 bDisplay = IsXMLToken(aIter, XML_TRUE);
457 break;
463 SvXMLImportContextRef ScXMLHelpMessageContext::CreateChildContext( sal_uInt16 nPrefix,
464 const OUString& rLName,
465 const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttrList*/ )
467 SvXMLImportContext *pContext = nullptr;
469 const SvXMLTokenMap& rTokenMap = GetScImport().GetContentValidationMessageElemTokenMap();
470 switch( rTokenMap.Get( nPrefix, rLName ) )
472 case XML_TOK_P:
474 if(nParagraphCount)
475 sMessage.append('\n');
476 ++nParagraphCount;
477 pContext = new ScXMLContentContext( GetScImport(), nPrefix, rLName, sMessage);
479 break;
482 if( !pContext )
483 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLName );
485 return pContext;
488 void SAL_CALL ScXMLHelpMessageContext::endFastElement( sal_Int32 /*nElement*/ )
490 pValidationContext->SetHelpMessage(sTitle, sMessage.makeStringAndClear(), bDisplay);
493 ScXMLErrorMessageContext::ScXMLErrorMessageContext( ScXMLImport& rImport,
494 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
495 ScXMLContentValidationContext* pTempValidationContext) :
496 ScXMLImportContext( rImport ),
497 sTitle(),
498 sMessage(),
499 sMessageType(),
500 nParagraphCount(0),
501 bDisplay(false)
503 pValidationContext = pTempValidationContext;
504 if ( rAttrList.is() )
506 for (auto &aIter : *rAttrList)
508 switch (aIter.getToken())
510 case XML_ELEMENT( TABLE, XML_TITLE ):
511 sTitle = aIter.toString();
512 break;
513 case XML_ELEMENT( TABLE, XML_MESSAGE_TYPE ):
514 sMessageType = aIter.toString();
515 break;
516 case XML_ELEMENT( TABLE, XML_DISPLAY ):
517 bDisplay = IsXMLToken(aIter, XML_TRUE);
518 break;
524 SvXMLImportContextRef ScXMLErrorMessageContext::CreateChildContext( sal_uInt16 nPrefix,
525 const OUString& rLName,
526 const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttrList*/ )
528 SvXMLImportContext *pContext = nullptr;
530 const SvXMLTokenMap& rTokenMap = GetScImport().GetContentValidationMessageElemTokenMap();
531 switch( rTokenMap.Get( nPrefix, rLName ) )
533 case XML_TOK_P:
535 if(nParagraphCount)
536 sMessage.append('\n');
537 ++nParagraphCount;
538 pContext = new ScXMLContentContext( GetScImport(), nPrefix, rLName, sMessage);
540 break;
543 if( !pContext )
544 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLName );
546 return pContext;
549 void SAL_CALL ScXMLErrorMessageContext::endFastElement( sal_Int32 /*nElement*/ )
551 pValidationContext->SetErrorMessage(sTitle, sMessage.makeStringAndClear(), sMessageType, bDisplay);
554 ScXMLErrorMacroContext::ScXMLErrorMacroContext( ScXMLImport& rImport,
555 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
556 ScXMLContentValidationContext* pTempValidationContext) :
557 ScXMLImportContext( rImport ),
558 bExecute(false)
560 pValidationContext = pTempValidationContext;
561 if ( rAttrList.is() )
563 for (auto &aIter : *rAttrList)
565 switch (aIter.getToken())
567 case XML_ELEMENT( TABLE, XML_NAME ):
568 break;
569 case XML_ELEMENT( TABLE, XML_EXECUTE ):
570 bExecute = IsXMLToken(aIter, XML_TRUE);
571 break;
577 SvXMLImportContextRef ScXMLErrorMacroContext::CreateChildContext( sal_uInt16 nPrefix,
578 const OUString& rLName,
579 const css::uno::Reference<css::xml::sax::XAttributeList>& /* xAttrList */ )
581 SvXMLImportContext *pContext = nullptr;
583 if ((nPrefix == XML_NAMESPACE_SCRIPT) && IsXMLToken(rLName, XML_EVENTS))
585 pContext = new XMLEventsImportContext(GetImport(), nPrefix, rLName);
587 if (!pContext)
588 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLName );
590 return pContext;
593 void SAL_CALL ScXMLErrorMacroContext::endFastElement( sal_Int32 /*nElement*/ )
595 pValidationContext->SetErrorMacro( bExecute );
598 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */