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/xmltoken.hxx>
27 #include <xmloff/xmlnamespace.hxx>
28 #include <xmloff/XMLEventsImportContext.hxx>
29 #include <com/sun/star/sheet/TableValidationVisibility.hpp>
31 using namespace com::sun::star
;
32 using namespace xmloff::token
;
33 using namespace ::formula
;
37 class ScXMLContentValidationContext
: public ScXMLImportContext
41 OUString sHelpMessage
;
43 OUString sErrorMessage
;
44 OUString sErrorMessageType
;
45 OUString sBaseCellAddress
;
49 bool bIsCaseSensitive
;
53 rtl::Reference
<XMLEventsImportContext
> xEventContext
;
55 css::sheet::ValidationAlertStyle
GetAlertStyle() const;
56 void SetFormula( OUString
& rFormula
, OUString
& rFormulaNmsp
, FormulaGrammar::Grammar
& reGrammar
,
57 const OUString
& rCondition
, const OUString
& rGlobNmsp
, FormulaGrammar::Grammar eGlobGrammar
, bool bHasNmsp
) const;
58 void GetCondition( ScMyImportValidation
& rValidation
) const;
62 ScXMLContentValidationContext( ScXMLImport
& rImport
,
63 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
);
65 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
66 sal_Int32 nElement
, const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
68 virtual void SAL_CALL
endFastElement( sal_Int32 nElement
) override
;
70 void SetHelpMessage(const OUString
& sTitle
, const OUString
& sMessage
, const bool bDisplay
);
71 void SetErrorMessage(const OUString
& sTitle
, const OUString
& sMessage
, const OUString
& sMessageType
, const bool bDisplay
);
72 void SetErrorMacro(const bool bExecute
);
75 class ScXMLHelpMessageContext
: public ScXMLImportContext
78 OUStringBuffer sMessage
;
79 sal_Int32 nParagraphCount
;
82 ScXMLContentValidationContext
* pValidationContext
;
86 ScXMLHelpMessageContext( ScXMLImport
& rImport
,
87 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
88 ScXMLContentValidationContext
* pValidationContext
);
90 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
92 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
94 virtual void SAL_CALL
endFastElement( sal_Int32 nElement
) override
;
97 class ScXMLErrorMessageContext
: public ScXMLImportContext
100 OUStringBuffer sMessage
;
101 OUString sMessageType
;
102 sal_Int32 nParagraphCount
;
105 ScXMLContentValidationContext
* pValidationContext
;
109 ScXMLErrorMessageContext( ScXMLImport
& rImport
,
110 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
111 ScXMLContentValidationContext
* pValidationContext
);
113 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
115 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
117 virtual void SAL_CALL
endFastElement( sal_Int32 nElement
) override
;
120 class ScXMLErrorMacroContext
: public ScXMLImportContext
123 ScXMLContentValidationContext
* pValidationContext
;
127 ScXMLErrorMacroContext( ScXMLImport
& rImport
,
128 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
129 ScXMLContentValidationContext
* pValidationContext
);
131 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
133 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
134 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::castToFastAttributeList( xAttrList
);
158 case XML_ELEMENT( TABLE
, XML_CONTENT_VALIDATION
):
159 pContext
= new ScXMLContentValidationContext( GetScImport(), pAttribList
);
166 ScXMLContentValidationContext::ScXMLContentValidationContext( ScXMLImport
& rImport
,
167 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
) :
168 ScXMLImportContext( rImport
),
169 nShowList(sheet::TableValidationVisibility::UNSORTED
),
170 bAllowEmptyCell(true),
171 bIsCaseSensitive(false),
175 if ( !rAttrList
.is() )
178 for (auto &aIter
: *rAttrList
)
180 switch (aIter
.getToken())
182 case XML_ELEMENT( TABLE
, XML_NAME
):
183 sName
= aIter
.toString();
185 case XML_ELEMENT( TABLE
, XML_CONDITION
):
186 sCondition
= aIter
.toString();
188 case XML_ELEMENT( TABLE
, XML_BASE_CELL_ADDRESS
):
189 sBaseCellAddress
= aIter
.toString();
191 case XML_ELEMENT( TABLE
, XML_ALLOW_EMPTY_CELL
):
192 if (IsXMLToken(aIter
, XML_FALSE
))
193 bAllowEmptyCell
= false;
195 case XML_ELEMENT( TABLE
, XML_CASE_SENSITIVE
):
196 if (IsXMLToken(aIter
, XML_TRUE
))
197 bIsCaseSensitive
= true;
199 case XML_ELEMENT( TABLE
, XML_DISPLAY_LIST
):
200 if (IsXMLToken(aIter
, XML_NO
))
202 nShowList
= sheet::TableValidationVisibility::INVISIBLE
;
204 else if (IsXMLToken(aIter
, XML_UNSORTED
))
206 nShowList
= sheet::TableValidationVisibility::UNSORTED
;
208 else if (IsXMLToken(aIter
, XML_SORT_ASCENDING
))
210 nShowList
= sheet::TableValidationVisibility::SORTEDASCENDING
;
212 else if (IsXMLToken(aIter
, XML_SORTED_ASCENDING
))
214 // Read old wrong value, fdo#72548
215 nShowList
= sheet::TableValidationVisibility::SORTEDASCENDING
;
222 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
ScXMLContentValidationContext::createFastChildContext(
223 sal_Int32 nElement
, const uno::Reference
< xml::sax::XFastAttributeList
>& xAttrList
)
225 SvXMLImportContext
*pContext
= nullptr;
226 sax_fastparser::FastAttributeList
*pAttribList
=
227 &sax_fastparser::castToFastAttributeList( xAttrList
);
231 case XML_ELEMENT( TABLE
, XML_HELP_MESSAGE
):
232 pContext
= new ScXMLHelpMessageContext( GetScImport(), pAttribList
, this);
234 case XML_ELEMENT( TABLE
, XML_ERROR_MESSAGE
):
235 pContext
= new ScXMLErrorMessageContext( GetScImport(), pAttribList
, this);
237 case XML_ELEMENT( TABLE
, XML_ERROR_MACRO
):
238 pContext
= new ScXMLErrorMacroContext( GetScImport(), pAttribList
, this);
240 case XML_ELEMENT(OFFICE
, XML_EVENT_LISTENERS
):
241 xEventContext
= new XMLEventsImportContext( GetImport() );
242 pContext
= xEventContext
.get();
248 sheet::ValidationAlertStyle
ScXMLContentValidationContext::GetAlertStyle() const
250 if (IsXMLToken(sErrorMessageType
, XML_MACRO
))
251 return sheet::ValidationAlertStyle_MACRO
;
252 if (IsXMLToken(sErrorMessageType
, XML_STOP
))
253 return sheet::ValidationAlertStyle_STOP
;
254 if (IsXMLToken(sErrorMessageType
, XML_WARNING
))
255 return sheet::ValidationAlertStyle_WARNING
;
256 if (IsXMLToken(sErrorMessageType
, XML_INFORMATION
))
257 return sheet::ValidationAlertStyle_INFO
;
258 // default for unknown
259 return sheet::ValidationAlertStyle_STOP
;
262 void ScXMLContentValidationContext::SetFormula( OUString
& rFormula
, OUString
& rFormulaNmsp
, FormulaGrammar::Grammar
& reGrammar
,
263 const OUString
& rCondition
, const OUString
& rGlobNmsp
, FormulaGrammar::Grammar eGlobGrammar
, bool bHasNmsp
) const
265 reGrammar
= FormulaGrammar::GRAM_UNSPECIFIED
;
268 // the entire attribute contains a namespace: internal namespace not allowed
269 rFormula
= rCondition
;
270 rFormulaNmsp
= rGlobNmsp
;
271 reGrammar
= eGlobGrammar
;
275 // the attribute does not contain a namespace: try to find a namespace of an external grammar
276 GetScImport().ExtractFormulaNamespaceGrammar( rFormula
, rFormulaNmsp
, reGrammar
, rCondition
, true );
277 if( reGrammar
!= FormulaGrammar::GRAM_EXTERNAL
)
278 reGrammar
= eGlobGrammar
;
282 void ScXMLContentValidationContext::GetCondition( ScMyImportValidation
& rValidation
) const
284 rValidation
.aValidationType
= sheet::ValidationType_ANY
; // default if no condition is given
285 rValidation
.aOperator
= sheet::ConditionOperator_NONE
;
287 if( sCondition
.isEmpty() )
290 // extract leading namespace from condition string
291 OUString aCondition
, aConditionNmsp
;
292 FormulaGrammar::Grammar eGrammar
= FormulaGrammar::GRAM_UNSPECIFIED
;
293 GetScImport().ExtractFormulaNamespaceGrammar( aCondition
, aConditionNmsp
, eGrammar
, sCondition
);
294 bool bHasNmsp
= aCondition
.getLength() < sCondition
.getLength();
296 // parse a condition from the attribute string
297 ScXMLConditionParseResult aParseResult
;
298 ScXMLConditionHelper::parseCondition( aParseResult
, aCondition
, 0 );
300 /* Check the result. A valid value in aParseResult.meToken implies
301 that the other members of aParseResult are filled with valid data
303 bool bSecondaryPart
= false;
304 switch( aParseResult
.meToken
)
306 case XML_COND_TEXTLENGTH
: // condition is 'cell-content-text-length()<operator><expression>'
307 case XML_COND_TEXTLENGTH_ISBETWEEN
: // condition is 'cell-content-text-length-is-between(<expression1>,<expression2>)'
308 case XML_COND_TEXTLENGTH_ISNOTBETWEEN
: // condition is 'cell-content-text-length-is-not-between(<expression1>,<expression2>)'
309 case XML_COND_ISINLIST
: // condition is 'cell-content-is-in-list(<expression>)'
310 case XML_COND_ISTRUEFORMULA
: // condition is 'is-true-formula(<expression>)'
311 rValidation
.aValidationType
= aParseResult
.meValidation
;
312 rValidation
.aOperator
= aParseResult
.meOperator
;
315 case XML_COND_ISWHOLENUMBER
: // condition is 'cell-content-is-whole-number() and <condition>'
316 case XML_COND_ISDECIMALNUMBER
: // condition is 'cell-content-is-decimal-number() and <condition>'
317 case XML_COND_ISDATE
: // condition is 'cell-content-is-date() and <condition>'
318 case XML_COND_ISTIME
: // condition is 'cell-content-is-time() and <condition>'
319 rValidation
.aValidationType
= aParseResult
.meValidation
;
320 bSecondaryPart
= true;
323 default:; // unacceptable or unknown condition
326 /* Parse the following 'and <condition>' part of some conditions. This
327 updates the members of aParseResult that will contain the operands
328 and comparison operator then. */
331 ScXMLConditionHelper::parseCondition( aParseResult
, aCondition
, aParseResult
.mnEndIndex
);
332 if( aParseResult
.meToken
== XML_COND_AND
)
334 ScXMLConditionHelper::parseCondition( aParseResult
, aCondition
, aParseResult
.mnEndIndex
);
335 switch( aParseResult
.meToken
)
337 case XML_COND_CELLCONTENT
: // condition is 'and cell-content()<operator><expression>'
338 case XML_COND_ISBETWEEN
: // condition is 'and cell-content-is-between(<expression1>,<expression2>)'
339 case XML_COND_ISNOTBETWEEN
: // condition is 'and cell-content-is-not-between(<expression1>,<expression2>)'
340 rValidation
.aOperator
= aParseResult
.meOperator
;
342 default:; // unacceptable or unknown condition
347 // a validation type (date, integer) without a condition isn't possible
348 if( rValidation
.aOperator
== sheet::ConditionOperator_NONE
)
349 rValidation
.aValidationType
= sheet::ValidationType_ANY
;
351 // parse the formulas
352 if( rValidation
.aValidationType
!= sheet::ValidationType_ANY
)
354 SetFormula( rValidation
.sFormula1
, rValidation
.sFormulaNmsp1
, rValidation
.eGrammar1
,
355 aParseResult
.maOperand1
, aConditionNmsp
, eGrammar
, bHasNmsp
);
356 SetFormula( rValidation
.sFormula2
, rValidation
.sFormulaNmsp2
, rValidation
.eGrammar2
,
357 aParseResult
.maOperand2
, aConditionNmsp
, eGrammar
, bHasNmsp
);
361 void SAL_CALL
ScXMLContentValidationContext::endFastElement( sal_Int32
/*nElement*/ )
363 // #i36650# event-listeners element moved up one level
364 if (xEventContext
.is())
366 uno::Sequence
<beans::PropertyValue
> aValues
;
367 xEventContext
->GetEventSequence( u
"OnError"_ustr
, aValues
);
369 auto pValue
= std::find_if(std::cbegin(aValues
), std::cend(aValues
),
370 [](const beans::PropertyValue
& rValue
) {
371 return rValue
.Name
== "MacroName" || rValue
.Name
== "Script"; });
372 if (pValue
!= std::cend(aValues
))
373 pValue
->Value
>>= sErrorTitle
;
376 ScMyImportValidation aValidation
;
377 if (ScDocument
* pDoc
= GetScImport().GetDocument())
378 aValidation
.eGrammar1
= aValidation
.eGrammar2
= pDoc
->GetStorageGrammar();
379 aValidation
.sName
= sName
;
380 aValidation
.sBaseCellAddress
= sBaseCellAddress
;
381 aValidation
.sInputTitle
= sHelpTitle
;
382 aValidation
.sInputMessage
= sHelpMessage
;
383 aValidation
.sErrorTitle
= sErrorTitle
;
384 aValidation
.sErrorMessage
= sErrorMessage
;
385 GetCondition( aValidation
);
386 aValidation
.aAlertStyle
= GetAlertStyle();
387 aValidation
.bShowErrorMessage
= bDisplayError
;
388 aValidation
.bShowInputMessage
= bDisplayHelp
;
389 aValidation
.bIgnoreBlanks
= bAllowEmptyCell
;
390 aValidation
.bCaseSensitive
= bIsCaseSensitive
;
391 aValidation
.nShowList
= nShowList
;
392 GetScImport().AddValidation(aValidation
);
395 void ScXMLContentValidationContext::SetHelpMessage(const OUString
& sTitle
, const OUString
& sMessage
, const bool bDisplay
)
398 sHelpMessage
= sMessage
;
399 bDisplayHelp
= bDisplay
;
402 void ScXMLContentValidationContext::SetErrorMessage(const OUString
& sTitle
, const OUString
& sMessage
,
403 const OUString
& sMessageType
, const bool bDisplay
)
405 sErrorTitle
= sTitle
;
406 sErrorMessage
= sMessage
;
407 sErrorMessageType
= sMessageType
;
408 bDisplayError
= bDisplay
;
411 void ScXMLContentValidationContext::SetErrorMacro(const bool bExecute
)
413 sErrorMessageType
= "macro";
414 bDisplayError
= bExecute
;
417 ScXMLHelpMessageContext::ScXMLHelpMessageContext( ScXMLImport
& rImport
,
418 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
419 ScXMLContentValidationContext
* pTempValidationContext
) :
420 ScXMLImportContext( rImport
),
424 pValidationContext
= pTempValidationContext
;
425 if ( !rAttrList
.is() )
428 for (auto &aIter
: *rAttrList
)
430 switch (aIter
.getToken())
432 case XML_ELEMENT( TABLE
, XML_TITLE
):
433 sTitle
= aIter
.toString();
435 case XML_ELEMENT( TABLE
, XML_DISPLAY
):
436 bDisplay
= IsXMLToken(aIter
, XML_TRUE
);
442 css::uno::Reference
< css::xml::sax::XFastContextHandler
> ScXMLHelpMessageContext::createFastChildContext(
444 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& /*xAttrList*/ )
446 SvXMLImportContext
*pContext
= nullptr;
450 case XML_ELEMENT(TEXT
, XML_P
):
453 sMessage
.append('\n');
455 pContext
= new ScXMLContentContext( GetScImport(), sMessage
);
463 void SAL_CALL
ScXMLHelpMessageContext::endFastElement( sal_Int32
/*nElement*/ )
465 pValidationContext
->SetHelpMessage(sTitle
, sMessage
.makeStringAndClear(), bDisplay
);
468 ScXMLErrorMessageContext::ScXMLErrorMessageContext( ScXMLImport
& rImport
,
469 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
470 ScXMLContentValidationContext
* pTempValidationContext
) :
471 ScXMLImportContext( rImport
),
475 pValidationContext
= pTempValidationContext
;
476 if ( !rAttrList
.is() )
479 for (auto &aIter
: *rAttrList
)
481 switch (aIter
.getToken())
483 case XML_ELEMENT( TABLE
, XML_TITLE
):
484 sTitle
= aIter
.toString();
486 case XML_ELEMENT( TABLE
, XML_MESSAGE_TYPE
):
487 sMessageType
= aIter
.toString();
489 case XML_ELEMENT( TABLE
, XML_DISPLAY
):
490 bDisplay
= IsXMLToken(aIter
, XML_TRUE
);
496 css::uno::Reference
< css::xml::sax::XFastContextHandler
> ScXMLErrorMessageContext::createFastChildContext(
498 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& /*xAttrList*/ )
500 SvXMLImportContext
*pContext
= nullptr;
504 case XML_ELEMENT(TEXT
, XML_P
):
507 sMessage
.append('\n');
509 pContext
= new ScXMLContentContext( GetScImport(), sMessage
);
517 void SAL_CALL
ScXMLErrorMessageContext::endFastElement( sal_Int32
/*nElement*/ )
519 pValidationContext
->SetErrorMessage(sTitle
, sMessage
.makeStringAndClear(), sMessageType
, bDisplay
);
522 ScXMLErrorMacroContext::ScXMLErrorMacroContext( ScXMLImport
& rImport
,
523 const rtl::Reference
<sax_fastparser::FastAttributeList
>& rAttrList
,
524 ScXMLContentValidationContext
* pTempValidationContext
) :
525 ScXMLImportContext( rImport
),
528 pValidationContext
= pTempValidationContext
;
529 if ( !rAttrList
.is() )
532 for (auto &aIter
: *rAttrList
)
534 switch (aIter
.getToken())
536 case XML_ELEMENT( TABLE
, XML_NAME
):
538 case XML_ELEMENT( TABLE
, XML_EXECUTE
):
539 bExecute
= IsXMLToken(aIter
, XML_TRUE
);
545 css::uno::Reference
< css::xml::sax::XFastContextHandler
> ScXMLErrorMacroContext::createFastChildContext(
546 sal_Int32 nElement
, const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& /*xAttrList*/ )
548 SvXMLImportContext
*pContext
= nullptr;
550 if (nElement
== XML_ELEMENT(SCRIPT
, XML_EVENTS
))
552 pContext
= new XMLEventsImportContext(GetImport());
558 void SAL_CALL
ScXMLErrorMacroContext::endFastElement( sal_Int32
/*nElement*/ )
560 pValidationContext
->SetErrorMacro( bExecute
);
563 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */