diff options
Diffstat (limited to 'sc/source/filter/xml/xmlcvali.cxx')
-rw-r--r-- | sc/source/filter/xml/xmlcvali.cxx | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/sc/source/filter/xml/xmlcvali.cxx b/sc/source/filter/xml/xmlcvali.cxx new file mode 100644 index 000000000..6a5669b78 --- /dev/null +++ b/sc/source/filter/xml/xmlcvali.cxx @@ -0,0 +1,557 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xmlcvali.hxx" +#include "xmlimprt.hxx" +#include "xmlconti.hxx" +#include <document.hxx> +#include "XMLConverter.hxx" + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/XMLEventsImportContext.hxx> +#include <com/sun/star/sheet/TableValidationVisibility.hpp> + +using namespace com::sun::star; +using namespace xmloff::token; +using namespace ::formula; + +namespace { + +class ScXMLContentValidationContext : public ScXMLImportContext +{ + OUString sName; + OUString sHelpTitle; + OUString sHelpMessage; + OUString sErrorTitle; + OUString sErrorMessage; + OUString sErrorMessageType; + OUString sBaseCellAddress; + OUString sCondition; + sal_Int16 nShowList; + bool bAllowEmptyCell; + bool bDisplayHelp; + bool bDisplayError; + + SvXMLImportContextRef xEventContext; + + css::sheet::ValidationAlertStyle GetAlertStyle() const; + void SetFormula( OUString& rFormula, OUString& rFormulaNmsp, FormulaGrammar::Grammar& reGrammar, + const OUString& rCondition, const OUString& rGlobNmsp, FormulaGrammar::Grammar eGlobGrammar, bool bHasNmsp ) const; + void GetCondition( ScMyImportValidation& rValidation ) const; + +public: + + ScXMLContentValidationContext( ScXMLImport& rImport, + const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; + + void SetHelpMessage(const OUString& sTitle, const OUString& sMessage, const bool bDisplay); + void SetErrorMessage(const OUString& sTitle, const OUString& sMessage, const OUString& sMessageType, const bool bDisplay); + void SetErrorMacro(const bool bExecute); +}; + +class ScXMLHelpMessageContext : public ScXMLImportContext +{ + OUString sTitle; + OUStringBuffer sMessage; + sal_Int32 nParagraphCount; + bool bDisplay; + + ScXMLContentValidationContext* pValidationContext; + +public: + + ScXMLHelpMessageContext( ScXMLImport& rImport, + const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, + ScXMLContentValidationContext* pValidationContext); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; +}; + +class ScXMLErrorMessageContext : public ScXMLImportContext +{ + OUString sTitle; + OUStringBuffer sMessage; + OUString sMessageType; + sal_Int32 nParagraphCount; + bool bDisplay; + + ScXMLContentValidationContext* pValidationContext; + +public: + + ScXMLErrorMessageContext( ScXMLImport& rImport, + const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, + ScXMLContentValidationContext* pValidationContext); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; +}; + +class ScXMLErrorMacroContext : public ScXMLImportContext +{ + bool bExecute; + ScXMLContentValidationContext* pValidationContext; + +public: + + ScXMLErrorMacroContext( ScXMLImport& rImport, + const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, + ScXMLContentValidationContext* pValidationContext); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; +}; + +} + +ScXMLContentValidationsContext::ScXMLContentValidationsContext( ScXMLImport& rImport ) : + ScXMLImportContext( rImport ) +{ + // here are no attributes +} + +ScXMLContentValidationsContext::~ScXMLContentValidationsContext() +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLContentValidationsContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + sax_fastparser::FastAttributeList *pAttribList = + &sax_fastparser::castToFastAttributeList( xAttrList ); + + switch (nElement) + { + case XML_ELEMENT( TABLE, XML_CONTENT_VALIDATION ): + pContext = new ScXMLContentValidationContext( GetScImport(), pAttribList ); + break; + } + + return pContext; +} + +ScXMLContentValidationContext::ScXMLContentValidationContext( ScXMLImport& rImport, + const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList ) : + ScXMLImportContext( rImport ), + nShowList(sheet::TableValidationVisibility::UNSORTED), + bAllowEmptyCell(true), + bDisplayHelp(false), + bDisplayError(false) +{ + if ( !rAttrList.is() ) + return; + + for (auto &aIter : *rAttrList) + { + switch (aIter.getToken()) + { + case XML_ELEMENT( TABLE, XML_NAME ): + sName = aIter.toString(); + break; + case XML_ELEMENT( TABLE, XML_CONDITION ): + sCondition = aIter.toString(); + break; + case XML_ELEMENT( TABLE, XML_BASE_CELL_ADDRESS ): + sBaseCellAddress = aIter.toString(); + break; + case XML_ELEMENT( TABLE, XML_ALLOW_EMPTY_CELL ): + if (IsXMLToken(aIter, XML_FALSE)) + bAllowEmptyCell = false; + break; + case XML_ELEMENT( TABLE, XML_DISPLAY_LIST ): + if (IsXMLToken(aIter, XML_NO)) + { + nShowList = sheet::TableValidationVisibility::INVISIBLE; + } + else if (IsXMLToken(aIter, XML_UNSORTED)) + { + nShowList = sheet::TableValidationVisibility::UNSORTED; + } + else if (IsXMLToken(aIter, XML_SORT_ASCENDING)) + { + nShowList = sheet::TableValidationVisibility::SORTEDASCENDING; + } + else if (IsXMLToken(aIter, XML_SORTED_ASCENDING)) + { + // Read old wrong value, fdo#72548 + nShowList = sheet::TableValidationVisibility::SORTEDASCENDING; + } + break; + } + } +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLContentValidationContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + sax_fastparser::FastAttributeList *pAttribList = + &sax_fastparser::castToFastAttributeList( xAttrList ); + + switch (nElement) + { + case XML_ELEMENT( TABLE, XML_HELP_MESSAGE ): + pContext = new ScXMLHelpMessageContext( GetScImport(), pAttribList, this); + break; + case XML_ELEMENT( TABLE, XML_ERROR_MESSAGE ): + pContext = new ScXMLErrorMessageContext( GetScImport(), pAttribList, this); + break; + case XML_ELEMENT( TABLE, XML_ERROR_MACRO ): + pContext = new ScXMLErrorMacroContext( GetScImport(), pAttribList, this); + break; + case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS): + pContext = new XMLEventsImportContext( GetImport() ); + xEventContext = pContext; + } + + return pContext; +} + +sheet::ValidationAlertStyle ScXMLContentValidationContext::GetAlertStyle() const +{ + if (IsXMLToken(sErrorMessageType, XML_MACRO)) + return sheet::ValidationAlertStyle_MACRO; + if (IsXMLToken(sErrorMessageType, XML_STOP)) + return sheet::ValidationAlertStyle_STOP; + if (IsXMLToken(sErrorMessageType, XML_WARNING)) + return sheet::ValidationAlertStyle_WARNING; + if (IsXMLToken(sErrorMessageType, XML_INFORMATION)) + return sheet::ValidationAlertStyle_INFO; + // default for unknown + return sheet::ValidationAlertStyle_STOP; +} + +void ScXMLContentValidationContext::SetFormula( OUString& rFormula, OUString& rFormulaNmsp, FormulaGrammar::Grammar& reGrammar, + const OUString& rCondition, const OUString& rGlobNmsp, FormulaGrammar::Grammar eGlobGrammar, bool bHasNmsp ) const +{ + reGrammar = FormulaGrammar::GRAM_UNSPECIFIED; + if( bHasNmsp ) + { + // the entire attribute contains a namespace: internal namespace not allowed + rFormula = rCondition; + rFormulaNmsp = rGlobNmsp; + reGrammar = eGlobGrammar; + } + else + { + // the attribute does not contain a namespace: try to find a namespace of an external grammar + GetScImport().ExtractFormulaNamespaceGrammar( rFormula, rFormulaNmsp, reGrammar, rCondition, true ); + if( reGrammar != FormulaGrammar::GRAM_EXTERNAL ) + reGrammar = eGlobGrammar; + } +} + +void ScXMLContentValidationContext::GetCondition( ScMyImportValidation& rValidation ) const +{ + rValidation.aValidationType = sheet::ValidationType_ANY; // default if no condition is given + rValidation.aOperator = sheet::ConditionOperator_NONE; + + if( sCondition.isEmpty() ) + return; + + // extract leading namespace from condition string + OUString aCondition, aConditionNmsp; + FormulaGrammar::Grammar eGrammar = FormulaGrammar::GRAM_UNSPECIFIED; + GetScImport().ExtractFormulaNamespaceGrammar( aCondition, aConditionNmsp, eGrammar, sCondition ); + bool bHasNmsp = aCondition.getLength() < sCondition.getLength(); + + // parse a condition from the attribute string + ScXMLConditionParseResult aParseResult; + ScXMLConditionHelper::parseCondition( aParseResult, aCondition, 0 ); + + /* Check the result. A valid value in aParseResult.meToken implies + that the other members of aParseResult are filled with valid data + for that token. */ + bool bSecondaryPart = false; + switch( aParseResult.meToken ) + { + case XML_COND_TEXTLENGTH: // condition is 'cell-content-text-length()<operator><expression>' + case XML_COND_TEXTLENGTH_ISBETWEEN: // condition is 'cell-content-text-length-is-between(<expression1>,<expression2>)' + case XML_COND_TEXTLENGTH_ISNOTBETWEEN: // condition is 'cell-content-text-length-is-not-between(<expression1>,<expression2>)' + case XML_COND_ISINLIST: // condition is 'cell-content-is-in-list(<expression>)' + case XML_COND_ISTRUEFORMULA: // condition is 'is-true-formula(<expression>)' + rValidation.aValidationType = aParseResult.meValidation; + rValidation.aOperator = aParseResult.meOperator; + break; + + case XML_COND_ISWHOLENUMBER: // condition is 'cell-content-is-whole-number() and <condition>' + case XML_COND_ISDECIMALNUMBER: // condition is 'cell-content-is-decimal-number() and <condition>' + case XML_COND_ISDATE: // condition is 'cell-content-is-date() and <condition>' + case XML_COND_ISTIME: // condition is 'cell-content-is-time() and <condition>' + rValidation.aValidationType = aParseResult.meValidation; + bSecondaryPart = true; + break; + + default:; // unacceptable or unknown condition + } + + /* Parse the following 'and <condition>' part of some conditions. This + updates the members of aParseResult that will contain the operands + and comparison operator then. */ + if( bSecondaryPart ) + { + ScXMLConditionHelper::parseCondition( aParseResult, aCondition, aParseResult.mnEndIndex ); + if( aParseResult.meToken == XML_COND_AND ) + { + ScXMLConditionHelper::parseCondition( aParseResult, aCondition, aParseResult.mnEndIndex ); + switch( aParseResult.meToken ) + { + case XML_COND_CELLCONTENT: // condition is 'and cell-content()<operator><expression>' + case XML_COND_ISBETWEEN: // condition is 'and cell-content-is-between(<expression1>,<expression2>)' + case XML_COND_ISNOTBETWEEN: // condition is 'and cell-content-is-not-between(<expression1>,<expression2>)' + rValidation.aOperator = aParseResult.meOperator; + break; + default:; // unacceptable or unknown condition + } + } + } + + // a validation type (date, integer) without a condition isn't possible + if( rValidation.aOperator == sheet::ConditionOperator_NONE ) + rValidation.aValidationType = sheet::ValidationType_ANY; + + // parse the formulas + if( rValidation.aValidationType != sheet::ValidationType_ANY ) + { + SetFormula( rValidation.sFormula1, rValidation.sFormulaNmsp1, rValidation.eGrammar1, + aParseResult.maOperand1, aConditionNmsp, eGrammar, bHasNmsp ); + SetFormula( rValidation.sFormula2, rValidation.sFormulaNmsp2, rValidation.eGrammar2, + aParseResult.maOperand2, aConditionNmsp, eGrammar, bHasNmsp ); + } +} + +void SAL_CALL ScXMLContentValidationContext::endFastElement( sal_Int32 /*nElement*/ ) +{ + // #i36650# event-listeners element moved up one level + if (xEventContext.is()) + { + XMLEventsImportContext* pEvents = + static_cast<XMLEventsImportContext*>(xEventContext.get()); + uno::Sequence<beans::PropertyValue> aValues; + pEvents->GetEventSequence( "OnError", aValues ); + + auto pValue = std::find_if(std::cbegin(aValues), std::cend(aValues), + [](const beans::PropertyValue& rValue) { + return rValue.Name == "MacroName" || rValue.Name == "Script"; }); + if (pValue != std::cend(aValues)) + pValue->Value >>= sErrorTitle; + } + + ScMyImportValidation aValidation; + aValidation.eGrammar1 = aValidation.eGrammar2 = GetScImport().GetDocument()->GetStorageGrammar(); + aValidation.sName = sName; + aValidation.sBaseCellAddress = sBaseCellAddress; + aValidation.sInputTitle = sHelpTitle; + aValidation.sInputMessage = sHelpMessage; + aValidation.sErrorTitle = sErrorTitle; + aValidation.sErrorMessage = sErrorMessage; + GetCondition( aValidation ); + aValidation.aAlertStyle = GetAlertStyle(); + aValidation.bShowErrorMessage = bDisplayError; + aValidation.bShowInputMessage = bDisplayHelp; + aValidation.bIgnoreBlanks = bAllowEmptyCell; + aValidation.nShowList = nShowList; + GetScImport().AddValidation(aValidation); +} + +void ScXMLContentValidationContext::SetHelpMessage(const OUString& sTitle, const OUString& sMessage, const bool bDisplay) +{ + sHelpTitle = sTitle; + sHelpMessage = sMessage; + bDisplayHelp = bDisplay; +} + +void ScXMLContentValidationContext::SetErrorMessage(const OUString& sTitle, const OUString& sMessage, + const OUString& sMessageType, const bool bDisplay) +{ + sErrorTitle = sTitle; + sErrorMessage = sMessage; + sErrorMessageType = sMessageType; + bDisplayError = bDisplay; +} + +void ScXMLContentValidationContext::SetErrorMacro(const bool bExecute) +{ + sErrorMessageType = "macro"; + bDisplayError = bExecute; +} + +ScXMLHelpMessageContext::ScXMLHelpMessageContext( ScXMLImport& rImport, + const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, + ScXMLContentValidationContext* pTempValidationContext) : + ScXMLImportContext( rImport ), + nParagraphCount(0), + bDisplay(false) +{ + pValidationContext = pTempValidationContext; + if ( !rAttrList.is() ) + return; + + for (auto &aIter : *rAttrList) + { + switch (aIter.getToken()) + { + case XML_ELEMENT( TABLE, XML_TITLE ): + sTitle = aIter.toString(); + break; + case XML_ELEMENT( TABLE, XML_DISPLAY ): + bDisplay = IsXMLToken(aIter, XML_TRUE); + break; + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > ScXMLHelpMessageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContext *pContext = nullptr; + + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_P): + { + if(nParagraphCount) + sMessage.append('\n'); + ++nParagraphCount; + pContext = new ScXMLContentContext( GetScImport(), sMessage ); + } + break; + } + + return pContext; +} + +void SAL_CALL ScXMLHelpMessageContext::endFastElement( sal_Int32 /*nElement*/ ) +{ + pValidationContext->SetHelpMessage(sTitle, sMessage.makeStringAndClear(), bDisplay); +} + +ScXMLErrorMessageContext::ScXMLErrorMessageContext( ScXMLImport& rImport, + const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, + ScXMLContentValidationContext* pTempValidationContext) : + ScXMLImportContext( rImport ), + nParagraphCount(0), + bDisplay(false) +{ + pValidationContext = pTempValidationContext; + if ( !rAttrList.is() ) + return; + + for (auto &aIter : *rAttrList) + { + switch (aIter.getToken()) + { + case XML_ELEMENT( TABLE, XML_TITLE ): + sTitle = aIter.toString(); + break; + case XML_ELEMENT( TABLE, XML_MESSAGE_TYPE ): + sMessageType = aIter.toString(); + break; + case XML_ELEMENT( TABLE, XML_DISPLAY ): + bDisplay = IsXMLToken(aIter, XML_TRUE); + break; + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > ScXMLErrorMessageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContext *pContext = nullptr; + + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_P): + { + if(nParagraphCount) + sMessage.append('\n'); + ++nParagraphCount; + pContext = new ScXMLContentContext( GetScImport(), sMessage); + } + break; + } + + return pContext; +} + +void SAL_CALL ScXMLErrorMessageContext::endFastElement( sal_Int32 /*nElement*/ ) +{ + pValidationContext->SetErrorMessage(sTitle, sMessage.makeStringAndClear(), sMessageType, bDisplay); +} + +ScXMLErrorMacroContext::ScXMLErrorMacroContext( ScXMLImport& rImport, + const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, + ScXMLContentValidationContext* pTempValidationContext) : + ScXMLImportContext( rImport ), + bExecute(false) +{ + pValidationContext = pTempValidationContext; + if ( !rAttrList.is() ) + return; + + for (auto &aIter : *rAttrList) + { + switch (aIter.getToken()) + { + case XML_ELEMENT( TABLE, XML_NAME ): + break; + case XML_ELEMENT( TABLE, XML_EXECUTE ): + bExecute = IsXMLToken(aIter, XML_TRUE); + break; + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > ScXMLErrorMacroContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContext *pContext = nullptr; + + if (nElement == XML_ELEMENT(SCRIPT, XML_EVENTS)) + { + pContext = new XMLEventsImportContext(GetImport()); + } + + return pContext; +} + +void SAL_CALL ScXMLErrorMacroContext::endFastElement( sal_Int32 /*nElement*/ ) +{ + pValidationContext->SetErrorMacro( bExecute ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |