1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
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
40 OUString sHelpMessage
;
42 OUString sErrorMessage
;
43 OUString sErrorMessageType
;
44 OUString sBaseCellAddress
;
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;
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
80 OUStringBuffer sMessage
;
81 sal_Int32 nParagraphCount
;
84 ScXMLContentValidationContext
* pValidationContext
;
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
102 OUStringBuffer sMessage
;
103 OUString sMessageType
;
104 sal_Int32 nParagraphCount
;
107 ScXMLContentValidationContext
* pValidationContext
;
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
125 ScXMLContentValidationContext
* pValidationContext
;
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
);
158 case XML_ELEMENT( TABLE
, XML_CONTENT_VALIDATION
):
159 pContext
= new ScXMLContentValidationContext( GetScImport(), pAttribList
);
164 pContext
= new SvXMLImportContext( GetImport() );
169 ScXMLContentValidationContext::ScXMLContentValidationContext( ScXMLImport
& rImport
,
170 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
) :
171 ScXMLImportContext( rImport
),
172 nShowList(sheet::TableValidationVisibility::UNSORTED
),
173 bAllowEmptyCell(true),
177 if ( rAttrList
.is() )
179 for (auto &aIter
: *rAttrList
)
181 switch (aIter
.getToken())
183 case XML_ELEMENT( TABLE
, XML_NAME
):
184 sName
= aIter
.toString();
186 case XML_ELEMENT( TABLE
, XML_CONDITION
):
187 sCondition
= aIter
.toString();
189 case XML_ELEMENT( TABLE
, XML_BASE_CELL_ADDRESS
):
190 sBaseCellAddress
= aIter
.toString();
192 case XML_ELEMENT( TABLE
, XML_ALLOW_EMPTY_CELL
):
193 if (IsXMLToken(aIter
, XML_FALSE
))
194 bAllowEmptyCell
= false;
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
;
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
;
236 pContext
= new SvXMLImportContext( GetImport(), nPrefix
, rLName
);
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
);
250 case XML_ELEMENT( TABLE
, XML_HELP_MESSAGE
):
251 pContext
= new ScXMLHelpMessageContext( GetScImport(), pAttribList
, this);
253 case XML_ELEMENT( TABLE
, XML_ERROR_MESSAGE
):
254 pContext
= new ScXMLErrorMessageContext( GetScImport(), pAttribList
, this);
256 case XML_ELEMENT( TABLE
, XML_ERROR_MACRO
):
257 pContext
= new ScXMLErrorMacroContext( GetScImport(), pAttribList
, this);
262 pContext
= new SvXMLImportContext( GetImport() );
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
;
287 // the entire attribute contains a namespace: internal namespace not allowed
288 rFormula
= rCondition
;
289 rFormulaNmsp
= rGlobNmsp
;
290 reGrammar
= eGlobGrammar
;
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
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
;
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;
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. */
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
;
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
)
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
),
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();
455 case XML_ELEMENT( TABLE
, XML_DISPLAY
):
456 bDisplay
= IsXMLToken(aIter
, XML_TRUE
);
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
) )
475 sMessage
.append('\n');
477 pContext
= new ScXMLContentContext( GetScImport(), nPrefix
, rLName
, sMessage
);
483 pContext
= new SvXMLImportContext( GetImport(), nPrefix
, rLName
);
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
),
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();
513 case XML_ELEMENT( TABLE
, XML_MESSAGE_TYPE
):
514 sMessageType
= aIter
.toString();
516 case XML_ELEMENT( TABLE
, XML_DISPLAY
):
517 bDisplay
= IsXMLToken(aIter
, XML_TRUE
);
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
) )
536 sMessage
.append('\n');
538 pContext
= new ScXMLContentContext( GetScImport(), nPrefix
, rLName
, sMessage
);
544 pContext
= new SvXMLImportContext( GetImport(), nPrefix
, rLName
);
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
),
560 pValidationContext
= pTempValidationContext
;
561 if ( rAttrList
.is() )
563 for (auto &aIter
: *rAttrList
)
565 switch (aIter
.getToken())
567 case XML_ELEMENT( TABLE
, XML_NAME
):
569 case XML_ELEMENT( TABLE
, XML_EXECUTE
):
570 bExecute
= IsXMLToken(aIter
, XML_TRUE
);
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
);
588 pContext
= new SvXMLImportContext( GetImport(), nPrefix
, rLName
);
593 void SAL_CALL
ScXMLErrorMacroContext::endFastElement( sal_Int32
/*nElement*/ )
595 pValidationContext
->SetErrorMacro( bExecute
);
598 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */