diff options
Diffstat (limited to 'xmloff/source/style')
116 files changed, 28644 insertions, 0 deletions
diff --git a/xmloff/source/style/AttributeContainerHandler.cxx b/xmloff/source/style/AttributeContainerHandler.cxx new file mode 100644 index 0000000000..17dc4391ec --- /dev/null +++ b/xmloff/source/style/AttributeContainerHandler.cxx @@ -0,0 +1,86 @@ +/* -*- 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 <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/xml/AttributeData.hpp> +#include <com/sun/star/uno/Any.hxx> + +#include <AttributeContainerHandler.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + + + + +XMLAttributeContainerHandler::~XMLAttributeContainerHandler() +{ + // nothing to do +} + +bool XMLAttributeContainerHandler::equals( + const Any& r1, + const Any& r2 ) const +{ + Reference< XNameContainer > xContainer1; + Reference< XNameContainer > xContainer2; + + if( ( r1 >>= xContainer1 ) && ( r2 >>= xContainer2 ) ) + { + const uno::Sequence< OUString > aAttribNames1( xContainer1->getElementNames() ); + uno::Sequence< OUString > aAttribNames2( xContainer2->getElementNames() ); + + if( aAttribNames1.getLength() == aAttribNames2.getLength() ) + { + xml::AttributeData aData1; + xml::AttributeData aData2; + + for( const OUString& rAttribName : aAttribNames1 ) + { + if( !xContainer2->hasByName( rAttribName ) ) + return false; + + xContainer1->getByName( rAttribName ) >>= aData1; + xContainer2->getByName( rAttribName ) >>= aData2; + + if( ( aData1.Namespace != aData2.Namespace ) || + ( aData1.Type != aData2.Type ) || + ( aData1.Value != aData2.Value ) ) + return false; + } + + return true; + } + } + + return false; +} + +bool XMLAttributeContainerHandler::importXML( const OUString& /*rStrImpValue*/, Any& /*rValue*/, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + return true; +} + +bool XMLAttributeContainerHandler::exportXML( OUString& /*rStrExpValue*/, const Any& /*rValue*/, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/DashStyle.cxx b/xmloff/source/style/DashStyle.cxx new file mode 100644 index 0000000000..009b7f1297 --- /dev/null +++ b/xmloff/source/style/DashStyle.cxx @@ -0,0 +1,275 @@ +/* -*- 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 <com/sun/star/drawing/DashStyle.hpp> +#include <com/sun/star/drawing/LineDash.hpp> + +#include <sax/tools/converter.hxx> + +#include <xmloff/DashStyle.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <xmloff/xmltkmap.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<drawing::DashStyle> const pXML_DashStyle_Enum[] = +{ + { XML_RECT, drawing::DashStyle_RECT }, + { XML_ROUND, drawing::DashStyle_ROUND }, + { XML_RECT, drawing::DashStyle_RECTRELATIVE }, + { XML_ROUND, drawing::DashStyle_ROUNDRELATIVE }, + { XML_TOKEN_INVALID, drawing::DashStyle(0) } +}; + +// Import + +XMLDashStyleImport::XMLDashStyleImport( SvXMLImport& rImp ) + : m_rImport(rImp) +{ +} + +void XMLDashStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + drawing::LineDash aLineDash; + aLineDash.Style = drawing::DashStyle_RECT; + aLineDash.Dots = 0; + aLineDash.DotLen = 0; + aLineDash.Dashes = 0; + aLineDash.DashLen = 0; + aLineDash.Distance = 20; + OUString aDisplayName; + + bool bIsRel = false; + + SvXMLUnitConverter& rUnitConverter = m_rImport.GetMM100UnitConverter(); + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + case XML_ELEMENT(DRAW_OOO, XML_NAME): + { + rStrName = aIter.toString(); + } + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + case XML_ELEMENT(DRAW_OOO, XML_DISPLAY_NAME): + { + aDisplayName = aIter.toString(); + } + break; + case XML_ELEMENT(DRAW, XML_STYLE): + case XML_ELEMENT(DRAW_OOO, XML_STYLE): + { + SvXMLUnitConverter::convertEnum( aLineDash.Style, aIter.toView(), pXML_DashStyle_Enum ); + } + break; + case XML_ELEMENT(DRAW, XML_DOTS1): + case XML_ELEMENT(DRAW_OOO, XML_DOTS1): + aLineDash.Dots = static_cast<sal_Int16>(aIter.toInt32()); + break; + + case XML_ELEMENT(DRAW, XML_DOTS1_LENGTH): + case XML_ELEMENT(DRAW_OOO, XML_DOTS1_LENGTH): + { + if( aIter.toView().find( '%' ) != std::string_view::npos ) // it's a percentage + { + bIsRel = true; + ::sax::Converter::convertPercent(aLineDash.DotLen, aIter.toView()); + } + else + { + rUnitConverter.convertMeasureToCore( aLineDash.DotLen, + aIter.toView() ); + } + } + break; + + case XML_ELEMENT(DRAW, XML_DOTS2): + case XML_ELEMENT(DRAW_OOO, XML_DOTS2): + aLineDash.Dashes = static_cast<sal_Int16>(aIter.toInt32()); + break; + + case XML_ELEMENT(DRAW, XML_DOTS2_LENGTH): + case XML_ELEMENT(DRAW_OOO, XML_DOTS2_LENGTH): + { + if( aIter.toView().find( '%' ) != std::string_view::npos ) // it's a percentage + { + bIsRel = true; + ::sax::Converter::convertPercent(aLineDash.DashLen, aIter.toView()); + } + else + { + rUnitConverter.convertMeasureToCore( aLineDash.DashLen, + aIter.toView() ); + } + } + break; + + case XML_ELEMENT(DRAW, XML_DISTANCE): + case XML_ELEMENT(DRAW_OOO, XML_DISTANCE): + { + if( aIter.toView().find( '%' ) != std::string_view::npos ) // it's a percentage + { + bIsRel = true; + ::sax::Converter::convertPercent(aLineDash.Distance, aIter.toView()); + } + else + { + rUnitConverter.convertMeasureToCore( aLineDash.Distance, + aIter.toView() ); + } + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + if( bIsRel ) + aLineDash.Style = aLineDash.Style == drawing::DashStyle_RECT ? drawing::DashStyle_RECTRELATIVE : drawing::DashStyle_ROUNDRELATIVE; + + rValue <<= aLineDash; + + if( !aDisplayName.isEmpty() ) + { + m_rImport.AddStyleDisplayName( XmlStyleFamily::SD_STROKE_DASH_ID, + rStrName, aDisplayName ); + rStrName = aDisplayName; + } +} + +// Export + +XMLDashStyleExport::XMLDashStyleExport( SvXMLExport& rExp ) + : m_rExport(rExp) +{ +} + +void XMLDashStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + SvXMLUnitConverter & rUnitConverter = m_rExport.GetMM100UnitConverter(); + + drawing::LineDash aLineDash; + + if( rStrName.isEmpty() ) + return; + + if( !(rValue >>= aLineDash) ) + return; + + bool bIsRel = aLineDash.Style == drawing::DashStyle_RECTRELATIVE || aLineDash.Style == drawing::DashStyle_ROUNDRELATIVE; + + OUString aStrValue; + OUStringBuffer aOut; + + // Name + bool bEncoded = false; + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + m_rExport.EncodeStyleName( rStrName, + &bEncoded ) ); + if( bEncoded ) + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + rStrName ); + + // Style + SvXMLUnitConverter::convertEnum( aOut, aLineDash.Style, pXML_DashStyle_Enum ); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + + // dots + if( aLineDash.Dots ) + { + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DOTS1, OUString::number( aLineDash.Dots ) ); + + if( aLineDash.DotLen ) + { + // dashes length + if( bIsRel ) + { + ::sax::Converter::convertPercent(aOut, aLineDash.DotLen); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, + aLineDash.DotLen ); + } + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DOTS1_LENGTH, aStrValue ); + } + } + + // dashes + if( aLineDash.Dashes ) + { + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DOTS2, OUString::number( aLineDash.Dashes ) ); + + if( aLineDash.DashLen ) + { + // dashes length + if( bIsRel ) + { + ::sax::Converter::convertPercent(aOut, aLineDash.DashLen); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, + aLineDash.DashLen ); + } + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DOTS2_LENGTH, aStrValue ); + } + } + + // distance + if( bIsRel ) + { + ::sax::Converter::convertPercent( aOut, aLineDash.Distance ); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, + aLineDash.Distance ); + } + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISTANCE, aStrValue ); + + // do Write + SvXMLElementExport rElem( m_rExport, + XML_NAMESPACE_DRAW, XML_STROKE_DASH, + true, false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/DrawAspectHdl.cxx b/xmloff/source/style/DrawAspectHdl.cxx new file mode 100644 index 0000000000..7eeb374ca5 --- /dev/null +++ b/xmloff/source/style/DrawAspectHdl.cxx @@ -0,0 +1,61 @@ +/* -*- 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 "DrawAspectHdl.hxx" + +#include <com/sun/star/uno/Any.hxx> +#include <rtl/ustrbuf.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +DrawAspectHdl::~DrawAspectHdl() +{ + // nothing to do +} + +bool DrawAspectHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int64 nAspect = 0; + + ::sax::Converter::convertNumber64( nAspect, rStrImpValue ); + rValue <<= nAspect; + + return nAspect > 0; +} + +bool DrawAspectHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + sal_Int64 nAspect = 0; + if( ( rValue >>= nAspect ) && nAspect > 0 ) + { + // store the aspect as an integer value + rStrExpValue = OUString::number(nAspect); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/DrawAspectHdl.hxx b/xmloff/source/style/DrawAspectHdl.hxx new file mode 100644 index 0000000000..0eb1fae15d --- /dev/null +++ b/xmloff/source/style/DrawAspectHdl.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class DrawAspectHdl : public XMLPropertyHandler +{ +public: + virtual ~DrawAspectHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/EnumPropertyHdl.cxx b/xmloff/source/style/EnumPropertyHdl.cxx new file mode 100644 index 0000000000..903ac3914d --- /dev/null +++ b/xmloff/source/style/EnumPropertyHdl.cxx @@ -0,0 +1,82 @@ +/* -*- 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 <xmloff/EnumPropertyHdl.hxx> +#include <xmloff/xmluconv.hxx> +#include <comphelper/extract.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> + +using namespace ::com::sun::star::uno; + + + +XMLEnumPropertyHdl::~XMLEnumPropertyHdl() +{ + // Nothing to do +} + +bool XMLEnumPropertyHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nValue = 0; + + if( SvXMLUnitConverter::convertEnum( nValue, rStrImpValue, mpEnumMap ) ) + { + switch( mrType.getTypeClass() ) + { + case TypeClass_ENUM: + rValue = ::cppu::int2enum( nValue, mrType ); + break; + case TypeClass_LONG: + rValue <<= static_cast<sal_Int32>(nValue); + break; + case TypeClass_SHORT: + rValue <<= static_cast<sal_Int16>(nValue); + break; + case TypeClass_BYTE: + rValue <<= static_cast<sal_Int8>(nValue); + break; + default: + assert(!"Wrong type for enum property handler!"); + return false; + } + return true; + } + + return false; +} + +bool XMLEnumPropertyHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + if(!(rValue >>= nValue )) + if(!::cppu::enum2int(nValue, rValue) ) + return false; + + OUStringBuffer aOut; + + if(!SvXMLUnitConverter::convertEnum( aOut, static_cast<sal_uInt16>(nValue), mpEnumMap )) + return false; + + rStrExpValue = aOut.makeStringAndClear(); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/FillStyleContext.cxx b/xmloff/source/style/FillStyleContext.cxx new file mode 100644 index 0000000000..3b0ff9ca2f --- /dev/null +++ b/xmloff/source/style/FillStyleContext.cxx @@ -0,0 +1,412 @@ +/* -*- 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 "FillStyleContext.hxx" + +#include <TransGradientStyle.hxx> + +#include <com/sun/star/awt/ColorStop.hpp> +#include <com/sun/star/awt/Gradient2.hpp> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/rendering/RGBColor.hpp> + +#include <comphelper/sequence.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/GradientStyle.hxx> +#include <xmloff/HatchStyle.hxx> +#include <xmloff/ImageStyle.hxx> +#include <xmloff/MarkerStyle.hxx> +#include <xmloff/DashStyle.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/XMLBase64ImportContext.hxx> + +#include <vector> + +using namespace ::com::sun::star; + + +XMLGradientStyleContext::XMLGradientStyleContext( SvXMLImport& rImport, sal_Int32 , + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLGradientStyleImport aGradientStyle( GetImport() ); + aGradientStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLGradientStyleContext::~XMLGradientStyleContext() +{ +} + +css::uno::Reference<css::xml::sax::XFastContextHandler> XMLGradientStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if (nElement == XML_ELEMENT(LO_EXT, xmloff::token::XML_GRADIENT_STOP)) + return new XMLGradientStopContext(GetImport(), nElement, xAttrList, maColorStopVec); + + return nullptr; +} + +void XMLGradientStyleContext::endFastElement(sal_Int32 ) +{ + // correcting invalid StopOffset values is done at the model. Therefore we import them here + // without any change. + if (!maColorStopVec.empty()) + { + awt::Gradient2 aGradient; + maAny >>= aGradient; + aGradient.ColorStops = comphelper::containerToSequence(maColorStopVec); + maAny <<= aGradient; + } + + uno::Reference< container::XNameContainer > xGradient( GetImport().GetGradientHelper() ); + try + { + if(xGradient.is()) + { + if( xGradient->hasByName( maStrName ) ) + { + xGradient->replaceByName( maStrName, maAny ); + } + else + { + xGradient->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLGradientStyleContext::IsTransient() const +{ + return true; +} + +XMLHatchStyleContext::XMLHatchStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLHatchStyleImport aHatchStyle( GetImport() ); + aHatchStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLHatchStyleContext::~XMLHatchStyleContext() +{ +} + +void XMLHatchStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xHatch( GetImport().GetHatchHelper() ); + + try + { + if(xHatch.is()) + { + if( xHatch->hasByName( maStrName ) ) + { + xHatch->replaceByName( maStrName, maAny ); + } + else + { + xHatch->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLHatchStyleContext::IsTransient() const +{ + return true; +} + + +XMLBitmapStyleContext::XMLBitmapStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLImageStyle::importXML( xAttrList, maAny, maStrName, rImport ); +} + +XMLBitmapStyleContext::~XMLBitmapStyleContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLBitmapStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(OFFICE, xmloff::token::XML_BINARY_DATA) ) + { + OUString sURL; + maAny >>= sURL; + if( sURL.isEmpty() && !mxBase64Stream.is() ) + { + mxBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( mxBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), mxBase64Stream ); + } + } + + return nullptr; +} + +void XMLBitmapStyleContext::endFastElement(sal_Int32 ) +{ + if (!maAny.has<uno::Reference<graphic::XGraphic>>() && mxBase64Stream.is()) + { + // No graphic so far? Then see if it's inline. + uno::Reference<graphic::XGraphic> xGraphic = GetImport().loadGraphicFromBase64(mxBase64Stream); + if (xGraphic.is()) + { + maAny <<= xGraphic; + } + } + + if (!maAny.has<uno::Reference<graphic::XGraphic>>()) + return; + + uno::Reference<container::XNameContainer> xBitmapContainer(GetImport().GetBitmapHelper()); + + uno::Reference<graphic::XGraphic> xGraphic = maAny.get<uno::Reference<graphic::XGraphic>>(); + uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY); + + try + { + if (xBitmapContainer.is()) + { + if (xBitmapContainer->hasByName(maStrName)) + { + xBitmapContainer->replaceByName(maStrName, uno::Any(xBitmap)); + } + else + { + xBitmapContainer->insertByName(maStrName, uno::Any(xBitmap)); + } + } + } + catch (container::ElementExistException&) + {} +} + +bool XMLBitmapStyleContext::IsTransient() const +{ + return true; +} + + +XMLTransGradientStyleContext::XMLTransGradientStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLTransGradientStyleImport aTransGradientStyle( GetImport() ); + aTransGradientStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLTransGradientStyleContext::~XMLTransGradientStyleContext() +{ +} + +css::uno::Reference<css::xml::sax::XFastContextHandler> XMLTransGradientStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if (nElement == XML_ELEMENT(LO_EXT, xmloff::token::XML_OPACITY_STOP)) + return new XMLTransparencyStopContext(GetImport(), nElement, xAttrList, maColorStopVec); + + return nullptr; +} + +void XMLTransGradientStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xTransGradient( GetImport().GetTransGradientHelper() ); + + // correcting invalid StopOffset values is done at the model. Therefore we import them here + // without any change. + if (!maColorStopVec.empty()) + { + awt::Gradient2 aGradient; + maAny >>= aGradient; + aGradient.ColorStops = comphelper::containerToSequence(maColorStopVec); + maAny <<= aGradient; + } + + try + { + if(xTransGradient.is()) + { + if( xTransGradient->hasByName( maStrName ) ) + { + xTransGradient->replaceByName( maStrName, maAny ); + } + else + { + xTransGradient->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLTransGradientStyleContext::IsTransient() const +{ + return true; +} + +XMLTransparencyStopContext::XMLTransparencyStopContext( + SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + std::vector<awt::ColorStop>& rColorStopVec) +: SvXMLStyleContext(rImport) +{ + if(nElement != XML_ELEMENT(LO_EXT, xmloff::token::XML_OPACITY_STOP)) + return; + + double fOffset = -1.0; + css::rendering::RGBColor aRGBColor; // transparency is handled as gray color + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, xmloff::token::XML_OFFSET): // needed?? + case XML_ELEMENT(SVG_COMPAT, xmloff::token::XML_OFFSET): + if (!::sax::Converter::convertDouble(fOffset, aIter.toView())) + return; + break; + case XML_ELEMENT(SVG, xmloff::token::XML_STOP_OPACITY): + case XML_ELEMENT(SVG_COMPAT, xmloff::token::XML_STOP_OPACITY): + { + double fOpacity = 1.0; + if (!::sax::Converter::convertDouble(fOpacity, aIter.toView())) + return; + // Transparency is gray, full transparent is (1|1|1). + double fGrayComponent = std::clamp<double>(1.0 - fOpacity, 0.0, 1.0); + aRGBColor.Red = fGrayComponent; + aRGBColor.Green = fGrayComponent; + aRGBColor.Blue = fGrayComponent; + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + awt::ColorStop aColorStop; + aColorStop.StopOffset = fOffset; + aColorStop.StopColor = aRGBColor; + rColorStopVec.push_back(aColorStop); +} + +XMLTransparencyStopContext::~XMLTransparencyStopContext() +{ +} + +XMLMarkerStyleContext::XMLMarkerStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLMarkerStyleImport aMarkerStyle( GetImport() ); + aMarkerStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLMarkerStyleContext::~XMLMarkerStyleContext() +{ +} + +void XMLMarkerStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xMarker( GetImport().GetMarkerHelper() ); + + try + { + if(xMarker.is()) + { + if( xMarker->hasByName( maStrName ) ) + { + xMarker->replaceByName( maStrName, maAny ); + } + else + { + xMarker->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLMarkerStyleContext::IsTransient() const +{ + return true; +} + + +XMLDashStyleContext::XMLDashStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLDashStyleImport aDashStyle( GetImport() ); + aDashStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLDashStyleContext::~XMLDashStyleContext() +{ +} + +void XMLDashStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xDashes( GetImport().GetDashHelper() ); + + try + { + if(xDashes.is()) + { + if( xDashes->hasByName( maStrName ) ) + { + xDashes->replaceByName( maStrName, maAny ); + } + else + { + xDashes->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLDashStyleContext::IsTransient() const +{ + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/FillStyleContext.hxx b/xmloff/source/style/FillStyleContext.hxx new file mode 100644 index 0000000000..e3d00ad824 --- /dev/null +++ b/xmloff/source/style/FillStyleContext.hxx @@ -0,0 +1,170 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/awt/ColorStop.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <xmloff/xmlstyle.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +#include <vector> + +// draw:gradient context + +class XMLGradientStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + std::vector<css::awt::ColorStop> maColorStopVec; + +public: + + XMLGradientStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLGradientStyleContext() override; + + virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& AttrList) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:hatch context + +class XMLHatchStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + +public: + + XMLHatchStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLHatchStyleContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:fill-image context + +class XMLBitmapStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + css::uno::Reference < css::io::XOutputStream > mxBase64Stream; + +public: + + XMLBitmapStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLBitmapStyleContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:transparency context + +class XMLTransGradientStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + std::vector<css::awt::ColorStop> maColorStopVec; // Transparency is handled as color gray. + +public: + + XMLTransGradientStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLTransGradientStyleContext() override; + + virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& AttrList) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +class XMLTransparencyStopContext: public SvXMLStyleContext +{ +private: + +public: + + XMLTransparencyStopContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + std::vector<css::awt::ColorStop>& rColorStopVec); + virtual ~XMLTransparencyStopContext() override; +}; + +// draw:marker context + +class XMLMarkerStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + +public: + + XMLMarkerStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLMarkerStyleContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:marker context + +class XMLDashStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + +public: + + XMLDashStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLDashStyleContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/GradientStyle.cxx b/xmloff/source/style/GradientStyle.cxx new file mode 100644 index 0000000000..67b749f79f --- /dev/null +++ b/xmloff/source/style/GradientStyle.cxx @@ -0,0 +1,360 @@ +/* -*- 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 <xmloff/GradientStyle.hxx> + +#include <com/sun/star/awt/Gradient2.hpp> + +#include <comphelper/documentconstants.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <basegfx/utils/bgradient.hxx> +#include <docmodel/uno/UnoGradientTools.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<awt::GradientStyle> const pXML_GradientStyle_Enum[] = +{ + { XML_LINEAR, awt::GradientStyle_LINEAR }, + { XML_GRADIENTSTYLE_AXIAL, awt::GradientStyle_AXIAL }, + { XML_GRADIENTSTYLE_RADIAL, awt::GradientStyle_RADIAL }, + { XML_GRADIENTSTYLE_ELLIPSOID, awt::GradientStyle_ELLIPTICAL }, + { XML_GRADIENTSTYLE_SQUARE, awt::GradientStyle_SQUARE }, + { XML_GRADIENTSTYLE_RECTANGULAR, awt::GradientStyle_RECT }, + { XML_TOKEN_INVALID, awt::GradientStyle(0) } +}; + +// Import +XMLGradientStyleImport::XMLGradientStyleImport( + SvXMLImport& rImp ) + : m_rImport(rImp) +{ +} + +void XMLGradientStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + OUString aDisplayName; + + awt::Gradient2 aGradient; + aGradient.Style = css::awt::GradientStyle_LINEAR; + aGradient.StartColor = 0; + aGradient.EndColor = 0; + aGradient.Angle = 0; + aGradient.Border = 0; + aGradient.XOffset = 0; + aGradient.YOffset = 0; + aGradient.StartIntensity = 100; + aGradient.EndIntensity = 100; + aGradient.StepCount = 0; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + sal_Int32 nTmpValue(0); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + rStrName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + aDisplayName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_STYLE): + SvXMLUnitConverter::convertEnum( aGradient.Style, aIter.toView(), pXML_GradientStyle_Enum ); + break; + case XML_ELEMENT(DRAW, XML_CX): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.XOffset = static_cast< sal_Int16 >( nTmpValue ); + break; + case XML_ELEMENT(DRAW, XML_CY): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.YOffset = static_cast< sal_Int16 >( nTmpValue ); + break; + case XML_ELEMENT(DRAW, XML_START_COLOR): + ::sax::Converter::convertColor(aGradient.StartColor, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_END_COLOR): + ::sax::Converter::convertColor(aGradient.EndColor, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_START_INTENSITY): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.StartIntensity = static_cast< sal_Int16 >( nTmpValue ); + break; + case XML_ELEMENT(DRAW, XML_END_INTENSITY): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.EndIntensity = static_cast< sal_Int16 >( nTmpValue ); + break; + case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE): + { + auto const cmp12(m_rImport.GetODFVersion().compareTo(ODFVER_012_TEXT)); + bool const bSuccess = + ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(), + // tdf#89475 try to detect borked OOo angles + (cmp12 < 0) || (cmp12 == 0 + && (m_rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || m_rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle"); + } + break; + case XML_ELEMENT(DRAW, XML_BORDER): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.Border = static_cast< sal_Int16 >( nTmpValue ); + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + rValue <<= aGradient; + + if( !aDisplayName.isEmpty() ) + { + m_rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName, + aDisplayName ); + rStrName = aDisplayName; + } +} + +XMLGradientStopContext::XMLGradientStopContext( + SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + std::vector<awt::ColorStop>& rColorStopVec) +: SvXMLImportContext(rImport) +{ + if(nElement != XML_ELEMENT(LO_EXT, xmloff::token::XML_GRADIENT_STOP)) + return; + + double fOffset = -1.0; + OUString sColorType; + OUString sColorValue; + // First collect all attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, xmloff::token::XML_OFFSET): // needed?? + case XML_ELEMENT(SVG_COMPAT, xmloff::token::XML_OFFSET): + if (!::sax::Converter::convertDouble(fOffset, aIter.toView())) + return; + break; + case XML_ELEMENT(LO_EXT, xmloff::token::XML_COLOR_VALUE): + sColorValue = aIter.toString(); + if (sColorValue.isEmpty()) + return; + break; + case XML_ELEMENT(LO_EXT, xmloff::token::XML_COLOR_TYPE): + sColorType = aIter.toString(); + if (sColorType.isEmpty()) + return; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + // As of LO 7.6.0 only "rgb" is implemented. + if (sColorType != u"rgb") + return; + + // Type "rgb" requires kind color-value="#rrggbb". + ::Color aColor; + if (!::sax::Converter::convertColor(aColor, sColorValue)) + return; + + // All attribute values OK. Generate ColorStop. + css::rendering::RGBColor aRGBColor; + aRGBColor.Red = aColor.GetRed() / 255.0; + aRGBColor.Green = aColor.GetGreen() / 255.0; + aRGBColor.Blue = aColor.GetBlue() / 255.0; + + awt::ColorStop aColorStop; + aColorStop.StopOffset = fOffset; + aColorStop.StopColor = aRGBColor; + rColorStopVec.push_back(aColorStop); +} + +XMLGradientStopContext::~XMLGradientStopContext() +{ +} + +// Export + +XMLGradientStyleExport::XMLGradientStyleExport( + SvXMLExport& rExp ) + : m_rExport(rExp) +{ +} + +void XMLGradientStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + if( rStrName.isEmpty() ) + return; + + if (!rValue.has<css::awt::Gradient2>() && !rValue.has<css::awt::Gradient>()) + return; + + basegfx::BGradient aGradient = model::gradient::getFromAny(rValue); + + // Export of axial gradient to OOXML produces a symmetrical linear multi-color gradient. Import + // does not regenerate it as 'axial' because that is not needed for MCGR. For export to ODF we + // try to regenerate 'axial' for to get a better compatibility with LO versions before MCGR. + aGradient.tryToConvertToAxial(); + + // MCGR: For better compatibility with LO versions before MCGR, try + // to re-create a 'border' value based on the existing gradient stops. + // With MCGR we do not need 'border' anymore in quite some cases since + // no Start/EndColor at 0.0 resp. 1.0 is explicitly needed. Since we + // (unfortunately need to) internally continue to support border + // anyways it does no harm to fallback to use the border value - if + // there is an equivalent representation as this helper checks for. + // For exports that do not support 'border' this will be adapted as + // needed (see tryToApplyBorder()). + aGradient.tryToRecreateBorder(nullptr); + + OUString aStrValue; + OUStringBuffer aOut; + + // Style + if( !SvXMLUnitConverter::convertEnum( aOut, aGradient.GetGradientStyle(), pXML_GradientStyle_Enum ) ) + return; + + // Name + bool bEncoded = false; + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + m_rExport.EncodeStyleName( rStrName, + &bEncoded ) ); + if( bEncoded ) + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + rStrName ); + + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + + // Center x/y + if( aGradient.GetGradientStyle() != awt::GradientStyle_LINEAR && + aGradient.GetGradientStyle() != awt::GradientStyle_AXIAL ) + { + ::sax::Converter::convertPercent(aOut, aGradient.GetXOffset()); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue ); + ::sax::Converter::convertPercent(aOut, aGradient.GetYOffset()); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue ); + } + + // prep Start/EndColor, default black + basegfx::BColor aStartColor; + basegfx::BColor aEndColor; + + if (!aGradient.GetColorStops().empty()) + { + aStartColor = aGradient.GetColorStops().front().getStopColor(); + aEndColor = aGradient.GetColorStops().back().getStopColor(); + } + + // Color start + ::sax::Converter::convertColor(aOut, Color(aStartColor)); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_COLOR, aStrValue ); + + // Color end + ::sax::Converter::convertColor(aOut, Color(aEndColor)); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_COLOR, aStrValue ); + + // Intensity start + ::sax::Converter::convertPercent(aOut, aGradient.GetStartIntens()); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_INTENSITY, aStrValue ); + + // Intensity end + ::sax::Converter::convertPercent(aOut, aGradient.GetEndIntens()); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_INTENSITY, aStrValue ); + + // Angle + if( aGradient.GetGradientStyle() != awt::GradientStyle_RADIAL ) + { + ::sax::Converter::convertAngle(aOut, static_cast<sal_Int16>(aGradient.GetAngle()), m_rExport.getSaneDefaultVersion()); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); + } + + // Border + ::sax::Converter::convertPercent( aOut, aGradient.GetBorder() ); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); + + // ctor writes start tag. End-tag is written by destructor at block end. + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_DRAW, XML_GRADIENT, + true, false ); + + // Write child elements <loext:gradient-stop> + // Do not export in standard ODF 1.3 or older. + if ((m_rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + return; + + if (aGradient.GetColorStops().empty()) + return; + + double fPreviousOffset = 0.0; + for (const auto& aCandidate : aGradient.GetColorStops()) + { + // Attribute svg:offset. Make sure offsets are increasing. + double fOffset = std::clamp<double>(aCandidate.getStopOffset(), 0.0, 1.0); + if (fOffset < fPreviousOffset) + fOffset = fPreviousOffset; + m_rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset)); + fPreviousOffset = fOffset; + + // As of LO 7.6.0 only color-type="rgb" is implemented. + m_rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_COLOR_TYPE, u"rgb"_ustr); + + // Attribute loext:color-value, data type color, that is #rrggbb. + const basegfx::BColor aDecimalColor(aCandidate.getStopColor()); + ::Color aToolsColor(std::clamp<sal_uInt8>(std::round(aDecimalColor.getRed() * 255.0), 0, 255), + std::clamp<sal_uInt8>(std::round(aDecimalColor.getGreen() * 255.0), 0, 255), + std::clamp<sal_uInt8>(std::round(aDecimalColor.getBlue() * 255.0), 0, 255)); + m_rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_COLOR_VALUE, + rtl::OUStringChar('#') + aToolsColor.AsRGBHexString()); + + // write gradient stop element + SvXMLElementExport aStopElement(m_rExport, XML_NAMESPACE_LO_EXT, XML_GRADIENT_STOP, true, true); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/HatchStyle.cxx b/xmloff/source/style/HatchStyle.cxx new file mode 100644 index 0000000000..2a0bc22597 --- /dev/null +++ b/xmloff/source/style/HatchStyle.cxx @@ -0,0 +1,178 @@ +/* -*- 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 <xmloff/HatchStyle.hxx> + +#include <com/sun/star/drawing/Hatch.hpp> + +#include <sax/tools/converter.hxx> + +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlimp.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlement.hxx> + +using namespace ::com::sun::star; + +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<drawing::HatchStyle> const pXML_HatchStyle_Enum[] = +{ + { XML_SINGLE, drawing::HatchStyle_SINGLE }, + { XML_DOUBLE, drawing::HatchStyle_DOUBLE }, + { XML_HATCHSTYLE_TRIPLE, drawing::HatchStyle_TRIPLE }, + { XML_TOKEN_INVALID, drawing::HatchStyle(0) } +}; + +// Import + +XMLHatchStyleImport::XMLHatchStyleImport( SvXMLImport& rImp ) + : m_rImport(rImp) +{ +} + +void XMLHatchStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + OUString aDisplayName; + + drawing::Hatch aHatch; + aHatch.Style = drawing::HatchStyle_SINGLE; + aHatch.Color = 0; + aHatch.Distance = 0; + aHatch.Angle = 0; + + SvXMLUnitConverter& rUnitConverter = m_rImport.GetMM100UnitConverter(); + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + case XML_ELEMENT(DRAW_OOO, XML_NAME): + rStrName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + case XML_ELEMENT(DRAW_OOO, XML_DISPLAY_NAME): + aDisplayName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_STYLE): + case XML_ELEMENT(DRAW_OOO, XML_STYLE): + SvXMLUnitConverter::convertEnum( aHatch.Style, aIter.toView(), pXML_HatchStyle_Enum ); + break; + case XML_ELEMENT(DRAW, XML_COLOR): + case XML_ELEMENT(DRAW_OOO, XML_COLOR): + ::sax::Converter::convertColor(aHatch.Color, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_DISTANCE): + case XML_ELEMENT(DRAW_OOO, XML_DISTANCE): + rUnitConverter.convertMeasureToCore(aHatch.Distance, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_ROTATION): + case XML_ELEMENT(DRAW_OOO, XML_ROTATION): + { + sal_Int32 nValue; + if (::sax::Converter::convertNumber(nValue, aIter.toView(), 0, 3600)) + aHatch.Angle = sal_Int16(nValue); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + rValue <<= aHatch; + + if( !aDisplayName.isEmpty() ) + { + m_rImport.AddStyleDisplayName( XmlStyleFamily::SD_HATCH_ID, rStrName, + aDisplayName ); + rStrName = aDisplayName; + } +} + +// Export + +XMLHatchStyleExport::XMLHatchStyleExport( SvXMLExport& rExp ) + : m_rExport(rExp) +{ +} + +void XMLHatchStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + drawing::Hatch aHatch; + + if( rStrName.isEmpty() ) + return; + + if( !(rValue >>= aHatch) ) + return; + + OUString aStrValue; + OUStringBuffer aOut; + + SvXMLUnitConverter& rUnitConverter = + m_rExport.GetMM100UnitConverter(); + + // Style + if( !SvXMLUnitConverter::convertEnum( aOut, aHatch.Style, pXML_HatchStyle_Enum ) ) + return; + + // Name + bool bEncoded = false; + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + m_rExport.EncodeStyleName( rStrName, + &bEncoded ) ); + if( bEncoded ) + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + rStrName ); + + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + + // Color + ::sax::Converter::convertColor(aOut, aHatch.Color); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_COLOR, aStrValue ); + + // Distance + rUnitConverter.convertMeasureToXML( aOut, aHatch.Distance ); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISTANCE, aStrValue ); + + // Angle + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ROTATION, OUString::number(aHatch.Angle) ); + + // Do Write + SvXMLElementExport rElem( m_rExport, XML_NAMESPACE_DRAW, XML_HATCH, + true, false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/ImageStyle.cxx b/xmloff/source/style/ImageStyle.cxx new file mode 100644 index 0000000000..13443d4adf --- /dev/null +++ b/xmloff/source/style/ImageStyle.cxx @@ -0,0 +1,135 @@ +/* -*- 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 <xmloff/ImageStyle.hxx> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlimp.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <xmloff/xmltkmap.hxx> + +using namespace css; +using namespace xmloff::token; + +void XMLImageStyle::exportXML(OUString const & rStrName, uno::Any const & rValue, SvXMLExport& rExport) +{ + if (rStrName.isEmpty()) + return; + + if (!rValue.has<uno::Reference<awt::XBitmap>>()) + return; + + // Name + bool bEncoded = false; + rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, + rExport.EncodeStyleName(rStrName, &bEncoded)); + if (bEncoded) + { + rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, rStrName); + } + + auto xBitmap = rValue.get<uno::Reference<awt::XBitmap>>(); + uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY); + + OUString aMimeType; + const OUString aStr = rExport.AddEmbeddedXGraphic(xGraphic, aMimeType); + + // uri + if (!aStr.isEmpty()) + { + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStr ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + + // Do Write + SvXMLElementExport aElem(rExport, XML_NAMESPACE_DRAW, XML_FILL_IMAGE, true, true); + + if (xBitmap.is() && xGraphic.is()) + { + // optional office:binary-data + rExport.AddEmbeddedXGraphicAsBase64(xGraphic); + } +} + +bool XMLImageStyle::importXML(uno::Reference<xml::sax::XFastAttributeList> const & xAttrList, + uno::Any& rValue, OUString& rStrName, SvXMLImport& rImport) +{ + bool bHasHRef = false; + bool bHasName = false; + OUString aDisplayName; + uno::Reference<graphic::XGraphic> xGraphic; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + const OUString aStrValue = aIter.toString(); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + { + rStrName = aStrValue; + bHasName = true; + } + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + { + aDisplayName = aStrValue; + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + xGraphic = rImport.loadGraphicByURL(aStrValue); + bHasHRef = true; + } + break; + case XML_ELEMENT(XLINK, XML_TYPE): + // ignore + break; + case XML_ELEMENT(XLINK, XML_SHOW): + // ignore + break; + case XML_ELEMENT(XLINK, XML_ACTUATE): + // ignore + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + if (xGraphic.is()) + rValue <<= xGraphic; + + if( !aDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::SD_FILL_IMAGE_ID, + rStrName, aDisplayName ); + rStrName = aDisplayName; + } + + return bHasName && bHasHRef; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/MarkerStyle.cxx b/xmloff/source/style/MarkerStyle.cxx new file mode 100644 index 0000000000..9cf9ecc942 --- /dev/null +++ b/xmloff/source/style/MarkerStyle.cxx @@ -0,0 +1,193 @@ +/* -*- 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 <memory> +#include <xmloff/MarkerStyle.hxx> +#include <xexptran.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlimp.hxx> +#include <sal/log.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +using namespace ::com::sun::star; + +using namespace ::xmloff::token; + +// Import + +XMLMarkerStyleImport::XMLMarkerStyleImport( SvXMLImport& rImp ) + : m_rImport( rImp ) +{ +} + +void XMLMarkerStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + bool bHasViewBox = false; + bool bHasPathData = false; + OUString aDisplayName; + + std::unique_ptr<SdXMLImExViewBox> xViewBox; + + SvXMLUnitConverter& rUnitConverter = m_rImport.GetMM100UnitConverter(); + + OUString strPathData; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + OUString aStrValue = aIter.toString(); + + switch (aIter.getToken() & TOKEN_MASK) + { + case XML_NAME: + rStrName = aStrValue; + break; + case XML_DISPLAY_NAME: + aDisplayName = aStrValue; + break; + case XML_VIEWBOX: + xViewBox.reset(new SdXMLImExViewBox(aStrValue, rUnitConverter)); + bHasViewBox = true; + break; + case XML_D: + strPathData = aStrValue; + bHasPathData = true; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + if( bHasViewBox && bHasPathData ) + { + basegfx::B2DPolyPolygon aPolyPolygon; + + if(basegfx::utils::importFromSvgD(aPolyPolygon, strPathData, m_rImport.needFixPositionAfterZ(), nullptr)) + { + if(aPolyPolygon.count()) + { + // ViewBox probably not used, but stay with former processing inside of + // SdXMLImExSvgDElement + const basegfx::B2DRange aSourceRange( + xViewBox->GetX(), xViewBox->GetY(), + xViewBox->GetX() + xViewBox->GetWidth(), + xViewBox->GetY() + xViewBox->GetHeight()); + const basegfx::B2DRange aTargetRange( + 0.0, 0.0, + xViewBox->GetWidth(), xViewBox->GetHeight()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + // always use PolyPolygonBezierCoords here + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + rValue <<= aSourcePolyPolygon; + } + } + + if( !aDisplayName.isEmpty() ) + { + m_rImport.AddStyleDisplayName( XmlStyleFamily::SD_MARKER_ID, rStrName, + aDisplayName ); + rStrName = aDisplayName; + } + } + + xViewBox.reset(); +} + +// Export + +XMLMarkerStyleExport::XMLMarkerStyleExport( SvXMLExport& rExp ) + : m_rExport( rExp ) +{ +} + +void XMLMarkerStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + if(rStrName.isEmpty()) + return; + + drawing::PolyPolygonBezierCoords aBezier; + + if(!(rValue >>= aBezier)) + return; + + // Name + bool bEncoded(false); + + m_rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, m_rExport.EncodeStyleName( rStrName, &bEncoded ) ); + + if( bEncoded ) + { + m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, rStrName ); + } + + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + aBezier)); + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); + + + // Viewbox (viewBox="0 0 1500 1000") + + SdXMLImExViewBox aViewBox( + aPolyPolygonRange.getMinX(), + aPolyPolygonRange.getMinY(), + aPolyPolygonRange.getWidth(), + aPolyPolygonRange.getHeight()); + m_rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() ); + + // Pathdata + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + m_rExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + + // Do Write + SvXMLElementExport rElem( m_rExport, XML_NAMESPACE_DRAW, XML_MARKER, true, false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/MultiPropertySetHelper.cxx b/xmloff/source/style/MultiPropertySetHelper.cxx new file mode 100644 index 0000000000..7636278ebe --- /dev/null +++ b/xmloff/source/style/MultiPropertySetHelper.cxx @@ -0,0 +1,169 @@ +/* -*- 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 <MultiPropertySetHelper.hxx> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> + +#include <sal/log.hxx> + +using ::com::sun::star::beans::XMultiPropertySet; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XPropertySetInfo; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; + + +MultiPropertySetHelper::MultiPropertySetHelper( + const char** pNames ) : + nLength( 0 ), + pValues( nullptr ) +{ + // first count the elements + for( const char** pPtr = pNames; *pPtr != nullptr; pPtr++ ) + nLength++; + + // allocate array and create strings + pPropertyNames.reset( new OUString[nLength] ); + for( sal_Int16 i = 0; i < nLength; i++ ) + pPropertyNames[i] = OUString::createFromAscii( pNames[i] ); +} + + +MultiPropertySetHelper::~MultiPropertySetHelper() +{ + pValues = nullptr; // memory 'owned' by aValues +} + + +void MultiPropertySetHelper::hasProperties( + const Reference<XPropertySetInfo> & rInfo ) +{ + SAL_WARN_IF( !rInfo.is(), "xmloff", "I'd really like an XPropertySetInfo here." ); + + // allocate sequence index + if ( !pSequenceIndex ) + pSequenceIndex.reset( new sal_Int16[nLength] ); + + // construct pSequenceIndex + sal_Int16 nNumberOfProperties = 0; + sal_Int16 i; + + for( i = 0; i < nLength; i++ ) + { + // ask for property + bool bHasProperty = + rInfo->hasPropertyByName( pPropertyNames[i] ); + + // set index and increment (if appropriate) + pSequenceIndex[i]= bHasProperty ? nNumberOfProperties : -1; + if ( bHasProperty ) + nNumberOfProperties++; + } + + // construct property sequence from index array + if ( aPropertySequence.getLength() != nNumberOfProperties ) + aPropertySequence.realloc( nNumberOfProperties ); + OUString* pPropertySequence = aPropertySequence.getArray(); + for( i = 0; i < nLength; i ++ ) + { + sal_Int16 nIndex = pSequenceIndex[i]; + if ( nIndex != -1 ) + pPropertySequence[nIndex] = pPropertyNames[i]; + } +} + +bool MultiPropertySetHelper::checkedProperties() +{ + return (nullptr != pSequenceIndex); +} + + +void MultiPropertySetHelper::getValues( + const Reference<XMultiPropertySet> & rMultiPropertySet ) +{ + SAL_WARN_IF( !rMultiPropertySet.is(), "xmloff", "We need an XMultiPropertySet." ); + + aValues = rMultiPropertySet->getPropertyValues( aPropertySequence ); + pValues = aValues.getConstArray(); +} + +void MultiPropertySetHelper::getValues( + const Reference<XPropertySet> & rPropertySet ) +{ + SAL_WARN_IF( !rPropertySet.is(), "xmloff", "We need an XPropertySet." ); + + // re-alloc aValues (if necessary) and fill with values from XPropertySet + sal_Int16 nSupportedPropertiesCount = + static_cast<sal_Int16>(aPropertySequence.getLength()); + if ( aValues.getLength() != nSupportedPropertiesCount ) + aValues.realloc( nSupportedPropertiesCount ); + Any* pMutableArray = aValues.getArray(); + for( sal_Int16 i = 0; i < nSupportedPropertiesCount; i++ ) + { + pMutableArray[i] = rPropertySet->getPropertyValue( + pPropertyNames[ pSequenceIndex[ i ] ] ); + } + + // re-establish pValues pointer + pValues = aValues.getConstArray(); +} + + +const Any& MultiPropertySetHelper::getValue( sal_Int16 nIndex, + const Reference< XPropertySet> & rPropSet, + bool bTryMulti ) +{ + if( !pValues ) + { + if( bTryMulti ) + { + Reference < XMultiPropertySet > xMultiPropSet( rPropSet, + UNO_QUERY ); + if( xMultiPropSet.is() ) + getValues( xMultiPropSet ); + else + getValues( rPropSet ); + } + else + { + getValues( rPropSet ); + } + } + + return getValue( nIndex ); +} + +const Any& MultiPropertySetHelper::getValue( sal_Int16 nIndex, + const Reference< XMultiPropertySet> & rMultiPropSet ) +{ + if( !pValues ) + getValues( rMultiPropSet ); + + return getValue( nIndex ); +} + +// inline methods defined in header: +// inline Any& MultiPropertySetHelper::getValue( sal_Int16 nIndex ) +// inline sal_Bool MultiPropertySetHelper::hasProperty( sal_Int16 nValueNo ) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/NamedBoolPropertyHdl.cxx b/xmloff/source/style/NamedBoolPropertyHdl.cxx new file mode 100644 index 0000000000..be74fa4b7c --- /dev/null +++ b/xmloff/source/style/NamedBoolPropertyHdl.cxx @@ -0,0 +1,67 @@ +/* -*- 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 <xmloff/NamedBoolPropertyHdl.hxx> +#include <xmloff/xmluconv.hxx> +#include <comphelper/extract.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Any.hxx> + +using namespace ::com::sun::star::uno; + + + + +XMLNamedBoolPropertyHdl::~XMLNamedBoolPropertyHdl() +{ + // Nothing to do +} + +bool XMLNamedBoolPropertyHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + if( rStrImpValue == maTrueStr ) + { + rValue <<= true; + return true; + } + + if( rStrImpValue == maFalseStr ) + { + rValue <<= false; + return true; + } + + return false; +} + +bool XMLNamedBoolPropertyHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + if( ::cppu::any2bool( rValue ) ) + { + rStrExpValue = maTrueStr; + } + else + { + rStrExpValue = maFalseStr; + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageHeaderFooterContext.cxx b/xmloff/source/style/PageHeaderFooterContext.cxx new file mode 100644 index 0000000000..b36473361f --- /dev/null +++ b/xmloff/source/style/PageHeaderFooterContext.cxx @@ -0,0 +1,71 @@ +/* -*- 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 "PageHeaderFooterContext.hxx" +#include <utility> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/xmlimppr.hxx> +#include "PagePropertySetContext.hxx" +#include <sal/log.hxx> + +using namespace com::sun::star; +using ::xmloff::token::XML_HEADER_FOOTER_PROPERTIES; + +PageHeaderFooterContext::PageHeaderFooterContext( SvXMLImport& rImport, + ::std::vector< XMLPropertyState > & rTempProperties, + rtl::Reference < SvXMLImportPropertyMapper > xTempMap, + sal_Int32 nStart, sal_Int32 nEnd, + const bool bTempHeader ) : + SvXMLImportContext( rImport ), + rProperties(rTempProperties), + nStartIndex(nStart), + nEndIndex(nEnd), + rMap(std::move(xTempMap)) +{ + bHeader = bTempHeader; +} + +PageHeaderFooterContext::~PageHeaderFooterContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > PageHeaderFooterContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_HEADER_FOOTER_PROPERTIES) ) + { + PageContextType aType = Header; + if (!bHeader) + aType = Footer; + return new PagePropertySetContext( GetImport(), nElement, + xAttrList, + XML_TYPE_PROP_HEADER_FOOTER, + rProperties, + rMap, nStartIndex, nEndIndex, aType); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageHeaderFooterContext.hxx b/xmloff/source/style/PageHeaderFooterContext.hxx new file mode 100644 index 0000000000..30c2f430a8 --- /dev/null +++ b/xmloff/source/style/PageHeaderFooterContext.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ +#pragma once + +#include <xmloff/xmlimp.hxx> +#include <xmloff/maptype.hxx> + +class PageHeaderFooterContext : public SvXMLImportContext +{ + ::std::vector< XMLPropertyState > & rProperties; + sal_Int32 nStartIndex; + sal_Int32 nEndIndex; + bool bHeader; + const rtl::Reference < SvXMLImportPropertyMapper > rMap; + +public: + + PageHeaderFooterContext( SvXMLImport& rImport, + ::std::vector< XMLPropertyState > & rProperties, + rtl::Reference < SvXMLImportPropertyMapper > xMap, + sal_Int32 nStartIndex, sal_Int32 nEndIndex, + const bool bHeader); + + virtual ~PageHeaderFooterContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterExportPropMapper.cxx b/xmloff/source/style/PageMasterExportPropMapper.cxx new file mode 100644 index 0000000000..1da95f35cd --- /dev/null +++ b/xmloff/source/style/PageMasterExportPropMapper.cxx @@ -0,0 +1,650 @@ +/* -*- 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 "PageMasterExportPropMapper.hxx" +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/BorderLine2.hpp> +#include <PageMasterStyleMap.hxx> +#include <rtl/ref.hxx> +#include <comphelper/extract.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::comphelper; +using namespace ::xmloff::token; + +static bool lcl_HasSameLineWidth( const table::BorderLine2& rLine1, const table::BorderLine2& rLine2 ) +{ + return (rLine1.InnerLineWidth == rLine2.InnerLineWidth) && + (rLine1.OuterLineWidth == rLine2.OuterLineWidth) && + (rLine1.LineDistance == rLine2.LineDistance) && + (rLine1.LineWidth == rLine2.LineWidth); +} + +static void lcl_RemoveState( XMLPropertyState* pState ) +{ + pState->mnIndex = -1; + pState->maValue.clear(); +} + +static void lcl_RemoveStateIfZero16( XMLPropertyState* pState ) +{ + sal_Int16 nValue = sal_Int16(); + if( (pState->maValue >>= nValue) && !nValue ) + lcl_RemoveState( pState ); +} + +static void lcl_AddState(::std::vector< XMLPropertyState >& rPropState, sal_Int32 nIndex, const OUString& rProperty, const uno::Reference< beans::XPropertySet >& xProps) +{ + if(::cppu::any2bool(xProps->getPropertyValue(rProperty))) + rPropState.emplace_back(nIndex, css::uno::Any(true)); +} + +// helper struct to handle equal XMLPropertyState's for page, header and footer + +namespace { + +struct XMLPropertyStateBuffer +{ + XMLPropertyState* pPMMarginAll; + + XMLPropertyState* pPMBorderAll; + XMLPropertyState* pPMBorderTop; + XMLPropertyState* pPMBorderBottom; + XMLPropertyState* pPMBorderLeft; + XMLPropertyState* pPMBorderRight; + + XMLPropertyState* pPMBorderWidthAll; + XMLPropertyState* pPMBorderWidthTop; + XMLPropertyState* pPMBorderWidthBottom; + XMLPropertyState* pPMBorderWidthLeft; + XMLPropertyState* pPMBorderWidthRight; + + XMLPropertyState* pPMPaddingAll; + XMLPropertyState* pPMPaddingTop; + XMLPropertyState* pPMPaddingBottom; + XMLPropertyState* pPMPaddingLeft; + XMLPropertyState* pPMPaddingRight; + + XMLPropertyState* pPMMarginGutter; + XMLPropertyState* pPMMarginLeft; + XMLPropertyState* pPMRtlGutter; + XMLPropertyState* pPMMarginRight; + bool m_bGutterAtTop; + XMLPropertyState* pPMMarginTop; + + XMLPropertyStateBuffer(); + void ContextFilter( ::std::vector< XMLPropertyState >& rPropState ); +}; + +} + +XMLPropertyStateBuffer::XMLPropertyStateBuffer() + : pPMMarginAll( nullptr ) + , + pPMBorderAll( nullptr ), + pPMBorderTop( nullptr ), + pPMBorderBottom( nullptr ), + pPMBorderLeft( nullptr ), + pPMBorderRight( nullptr ), + + pPMBorderWidthAll( nullptr ), + pPMBorderWidthTop( nullptr ), + pPMBorderWidthBottom( nullptr ), + pPMBorderWidthLeft( nullptr ), + pPMBorderWidthRight( nullptr ), + + pPMPaddingAll( nullptr ), + pPMPaddingTop( nullptr ), + pPMPaddingBottom( nullptr ), + pPMPaddingLeft( nullptr ), + pPMPaddingRight( nullptr ), + + pPMMarginGutter( nullptr ), + pPMMarginLeft( nullptr ), + pPMRtlGutter( nullptr ), + pPMMarginRight( nullptr ), + m_bGutterAtTop( false ), + pPMMarginTop( nullptr ) +{ +} + +void XMLPropertyStateBuffer::ContextFilter( ::std::vector< XMLPropertyState >& ) +{ + if (pPMMarginGutter) + { + sal_Int32 nGutterMargin{}; + pPMMarginGutter->maValue >>= nGutterMargin; + if (m_bGutterAtTop) + { + if (nGutterMargin && pPMMarginTop) + { + // Increase top margin to include gutter. + sal_Int32 nTopMargin{}; + pPMMarginTop->maValue >>= nTopMargin; + nTopMargin += nGutterMargin; + pPMMarginTop->maValue <<= nTopMargin; + } + } + else + { + bool bRtlGutter{}; + if (nGutterMargin && pPMRtlGutter) + { + pPMRtlGutter->maValue >>= bRtlGutter; + } + if (bRtlGutter) + { + if (nGutterMargin && pPMMarginRight) + { + // Increase right margin to include gutter. + sal_Int32 nRightMargin{}; + pPMMarginRight->maValue >>= nRightMargin; + nRightMargin += nGutterMargin; + pPMMarginRight->maValue <<= nRightMargin; + } + } + else + { + if (nGutterMargin && pPMMarginLeft) + { + // Increase left margin to include gutter. + sal_Int32 nLeftMargin{}; + pPMMarginLeft->maValue >>= nLeftMargin; + nLeftMargin += nGutterMargin; + pPMMarginLeft->maValue <<= nLeftMargin; + } + } + } + } + + if (pPMMarginAll) + { + lcl_RemoveState(pPMMarginAll); // #i117696# do not write fo:margin + } + + if( pPMBorderAll ) + { + if( pPMBorderTop && pPMBorderBottom && pPMBorderLeft && pPMBorderRight ) + { + table::BorderLine2 aLineTop, aLineBottom, aLineLeft, aLineRight; + + pPMBorderTop->maValue >>= aLineTop; + pPMBorderBottom->maValue >>= aLineBottom; + pPMBorderLeft->maValue >>= aLineLeft; + pPMBorderRight->maValue >>= aLineRight; + + if( (aLineTop == aLineBottom) && (aLineBottom == aLineLeft) && (aLineLeft == aLineRight) ) + { + lcl_RemoveState( pPMBorderTop ); + lcl_RemoveState( pPMBorderBottom ); + lcl_RemoveState( pPMBorderLeft ); + lcl_RemoveState( pPMBorderRight ); + } + else + lcl_RemoveState( pPMBorderAll ); + } + else + lcl_RemoveState( pPMBorderAll ); + } + + if( pPMBorderWidthAll ) + { + if( pPMBorderWidthTop && pPMBorderWidthBottom && pPMBorderWidthLeft && pPMBorderWidthRight ) + { + table::BorderLine2 aLineTop, aLineBottom, aLineLeft, aLineRight; + + pPMBorderWidthTop->maValue >>= aLineTop; + pPMBorderWidthBottom->maValue >>= aLineBottom; + pPMBorderWidthLeft->maValue >>= aLineLeft; + pPMBorderWidthRight->maValue >>= aLineRight; + + if( lcl_HasSameLineWidth( aLineTop, aLineBottom ) && + lcl_HasSameLineWidth( aLineBottom, aLineLeft ) && + lcl_HasSameLineWidth( aLineLeft, aLineRight ) ) + { + lcl_RemoveState( pPMBorderWidthTop ); + lcl_RemoveState( pPMBorderWidthBottom ); + lcl_RemoveState( pPMBorderWidthLeft ); + lcl_RemoveState( pPMBorderWidthRight ); + } + else + lcl_RemoveState( pPMBorderWidthAll ); + } + else + lcl_RemoveState( pPMBorderWidthAll ); + } + + if( !pPMPaddingAll ) + return; + + if( pPMPaddingTop && pPMPaddingBottom && pPMPaddingLeft && pPMPaddingRight ) + { + sal_Int32 nTop = 0, nBottom = 0, nLeft = 0, nRight = 0; + + pPMPaddingTop->maValue >>= nTop; + pPMPaddingBottom->maValue >>= nBottom; + pPMPaddingLeft->maValue >>= nLeft; + pPMPaddingRight->maValue >>= nRight; + + if( (nTop == nBottom) && (nBottom == nLeft) && (nLeft == nRight) ) + { + lcl_RemoveState( pPMPaddingTop ); + lcl_RemoveState( pPMPaddingBottom ); + lcl_RemoveState( pPMPaddingLeft ); + lcl_RemoveState( pPMPaddingRight ); + } + else + lcl_RemoveState( pPMPaddingAll ); + } + else + lcl_RemoveState( pPMPaddingAll ); +} + +XMLPageMasterExportPropMapper::XMLPageMasterExportPropMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExport ) : + SvXMLExportPropertyMapper( rMapper ), + aBackgroundImageExport( rExport ), + aTextColumnsExport( rExport ), + aFootnoteSeparatorExport( rExport ) +{ +} + +XMLPageMasterExportPropMapper::~XMLPageMasterExportPropMapper() +{ +} + +void XMLPageMasterExportPropMapper::handleElementItem( + SvXMLExport&, + const XMLPropertyState& rProperty, + SvXmlExportFlags /*nFlags*/, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx ) const +{ + XMLPageMasterExportPropMapper* pThis = const_cast<XMLPageMasterExportPropMapper*>(this); + + sal_uInt32 nContextId = getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ); + switch( nContextId ) + { + case CTF_PM_GRAPHICURL: + case CTF_PM_HEADERGRAPHICURL: + case CTF_PM_FOOTERGRAPHICURL: + { + assert(pProperties); + assert(nIdx >= 2 && "horrible array ordering borked again"); + sal_Int32 nPos(-1); + sal_Int32 nFilter(-1); + switch( nContextId ) + { + case CTF_PM_GRAPHICURL: + nPos = CTF_PM_GRAPHICPOSITION; + nFilter = CTF_PM_GRAPHICFILTER; + break; + case CTF_PM_HEADERGRAPHICURL: + nPos = CTF_PM_HEADERGRAPHICPOSITION; + nFilter = CTF_PM_HEADERGRAPHICFILTER; + break; + case CTF_PM_FOOTERGRAPHICURL: + nPos = CTF_PM_FOOTERGRAPHICPOSITION; + nFilter = CTF_PM_FOOTERGRAPHICFILTER; + break; + default: + assert(false); + } + const Any* pPos = nullptr; + const Any* pFilter = nullptr; + sal_uInt32 nIndex(nIdx - 1); + const XMLPropertyState& rFilter = (*pProperties)[nIndex]; + if (getPropertySetMapper()->GetEntryContextId(rFilter.mnIndex) == nFilter) + { + pFilter = &rFilter.maValue; + --nIndex; + } + const XMLPropertyState& rPos = (*pProperties)[nIndex]; + if (getPropertySetMapper()->GetEntryContextId(rPos.mnIndex) == nPos) + { + pPos = &rPos.maValue; + --nIndex; + } + sal_uInt32 nPropIndex = rProperty.mnIndex; + pThis->aBackgroundImageExport.exportXML( rProperty.maValue, pPos, pFilter, nullptr, + getPropertySetMapper()->GetEntryNameSpace( nPropIndex ), + getPropertySetMapper()->GetEntryXMLName( nPropIndex ) ); + } + break; + case CTF_PM_TEXTCOLUMNS: + pThis->aTextColumnsExport.exportXML( rProperty.maValue ); + break; + case CTF_PM_FTN_LINE_WEIGHT: + pThis->aFootnoteSeparatorExport.exportXML( pProperties, nIdx, + getPropertySetMapper()); + break; + } +} + +void XMLPageMasterExportPropMapper::handleSpecialItem( + comphelper::AttributeList&, + const XMLPropertyState&, + const SvXMLUnitConverter&, + const SvXMLNamespaceMap&, + const ::std::vector< XMLPropertyState >*, + sal_uInt32 /*nIdx*/) const +{ +} + +void XMLPageMasterExportPropMapper::ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rPropState, + const Reference< XPropertySet >& rPropSet ) const +{ + XMLPropertyStateBuffer aPageBuffer; + if (m_bGutterAtTop) + { + aPageBuffer.m_bGutterAtTop = true; + } + + XMLPropertyStateBuffer aHeaderBuffer; + XMLPropertyStateBuffer aFooterBuffer; + + XMLPropertyState* pPMHeaderHeight = nullptr; + XMLPropertyState* pPMHeaderMinHeight = nullptr; + XMLPropertyState* pPMHeaderDynamic = nullptr; + + XMLPropertyState* pPMFooterHeight = nullptr; + XMLPropertyState* pPMFooterMinHeight = nullptr; + XMLPropertyState* pPMFooterDynamic = nullptr; + + XMLPropertyState* pPMScaleTo = nullptr; + XMLPropertyState* pPMScaleToPages = nullptr; + XMLPropertyState* pPMScaleToX = nullptr; + XMLPropertyState* pPMScaleToY = nullptr; + XMLPropertyState* pPMStandardMode = nullptr; + XMLPropertyState* pPMGridBaseWidth = nullptr; + // same as pPMGridSnapTo but for backward compatibility only + XMLPropertyState* pPMGridSnapToChars = nullptr; + XMLPropertyState* pPMGridSnapTo = nullptr; + + XMLPropertyState* pPrint = nullptr; + + XMLPropertyState* pRepeatOffsetX = nullptr; + XMLPropertyState* pRepeatOffsetY = nullptr; + XMLPropertyState* pHeaderRepeatOffsetX = nullptr; + XMLPropertyState* pHeaderRepeatOffsetY = nullptr; + XMLPropertyState* pFooterRepeatOffsetX = nullptr; + XMLPropertyState* pFooterRepeatOffsetY = nullptr; + + rtl::Reference < XMLPropertySetMapper > aPropMapper(getPropertySetMapper()); + + // distinguish 2 cases: drawing-page export has CTF_PM_FILL, page-layout-properties export does not + bool const isDrawingPageExport(aPropMapper->FindEntryIndex(CTF_PM_FILL) != -1); + + for( auto& rProp : rPropState ) + { + XMLPropertyState *pProp = &rProp; + sal_Int16 nContextId = aPropMapper->GetEntryContextId( pProp->mnIndex ); + sal_Int16 nFlag = nContextId & CTF_PM_FLAGMASK; + sal_Int16 nSimpleId = nContextId & (~CTF_PM_FLAGMASK | XML_PM_CTF_START); + sal_Int16 nPrintId = nContextId & CTF_PM_PRINTMASK; + + + // tdf#103602 don't export draw:fill attributes on page-layout-properties in strict ODF + if (!isDrawingPageExport + && [](OUString const& rName) -> bool { + return rName.startsWith("Fill") + || rName.startsWith("HeaderFill") + || rName.startsWith("FooterFill"); + } (aPropMapper->GetEntryAPIName(rProp.mnIndex)) + && ((aBackgroundImageExport.GetExport().getSaneDefaultVersion() + & SvtSaveOptions::ODFSVER_EXTENDED) == 0)) + { + lcl_RemoveState(&rProp); + continue; + } + + XMLPropertyStateBuffer* pBuffer; + switch( nFlag ) + { + case CTF_PM_HEADERFLAG: pBuffer = &aHeaderBuffer; break; + case CTF_PM_FOOTERFLAG: pBuffer = &aFooterBuffer; break; + default: pBuffer = &aPageBuffer; break; + } + + switch( nSimpleId ) + { + case CTF_PM_MARGINALL: pBuffer->pPMMarginAll = pProp; break; + case CTF_PM_BORDERALL: pBuffer->pPMBorderAll = pProp; break; + case CTF_PM_BORDERTOP: pBuffer->pPMBorderTop = pProp; break; + case CTF_PM_BORDERBOTTOM: pBuffer->pPMBorderBottom = pProp; break; + case CTF_PM_BORDERLEFT: pBuffer->pPMBorderLeft = pProp; break; + case CTF_PM_BORDERRIGHT: pBuffer->pPMBorderRight = pProp; break; + case CTF_PM_BORDERWIDTHALL: pBuffer->pPMBorderWidthAll = pProp; break; + case CTF_PM_BORDERWIDTHTOP: pBuffer->pPMBorderWidthTop = pProp; break; + case CTF_PM_BORDERWIDTHBOTTOM: pBuffer->pPMBorderWidthBottom = pProp; break; + case CTF_PM_BORDERWIDTHLEFT: pBuffer->pPMBorderWidthLeft = pProp; break; + case CTF_PM_BORDERWIDTHRIGHT: pBuffer->pPMBorderWidthRight = pProp; break; + case CTF_PM_PADDINGALL: pBuffer->pPMPaddingAll = pProp; break; + case CTF_PM_PADDINGTOP: pBuffer->pPMPaddingTop = pProp; break; + case CTF_PM_PADDINGBOTTOM: pBuffer->pPMPaddingBottom = pProp; break; + case CTF_PM_PADDINGLEFT: pBuffer->pPMPaddingLeft = pProp; break; + case CTF_PM_PADDINGRIGHT: pBuffer->pPMPaddingRight = pProp; break; + case CTF_PM_MARGINGUTTER: + pBuffer->pPMMarginGutter = pProp; + break; + case CTF_PM_MARGINLEFT: + pBuffer->pPMMarginLeft = pProp; + break; + case CTF_PM_RTLGUTTER: + pBuffer->pPMRtlGutter = pProp; + break; + case CTF_PM_MARGINRIGHT: + pBuffer->pPMMarginRight = pProp; + break; + case CTF_PM_MARGINTOP: + pBuffer->pPMMarginTop = pProp; + break; + } + + switch( nContextId ) + { + case CTF_PM_HEADERHEIGHT: pPMHeaderHeight = pProp; break; + case CTF_PM_HEADERMINHEIGHT: pPMHeaderMinHeight = pProp; break; + case CTF_PM_HEADERDYNAMIC: pPMHeaderDynamic = pProp; break; + case CTF_PM_FOOTERHEIGHT: pPMFooterHeight = pProp; break; + case CTF_PM_FOOTERMINHEIGHT: pPMFooterMinHeight = pProp; break; + case CTF_PM_FOOTERDYNAMIC: pPMFooterDynamic = pProp; break; + case CTF_PM_SCALETO: pPMScaleTo = pProp; break; + case CTF_PM_SCALETOPAGES: pPMScaleToPages = pProp; break; + case CTF_PM_SCALETOX: pPMScaleToX = pProp; break; + case CTF_PM_SCALETOY: pPMScaleToY = pProp; break; + case CTF_PM_STANDARD_MODE: pPMStandardMode = pProp; break; + case CTP_PM_GRID_BASE_WIDTH: pPMGridBaseWidth = pProp; break; + case CTP_PM_GRID_SNAP_TO_CHARS: pPMGridSnapToChars = pProp; break; + case CTP_PM_GRID_SNAP_TO: pPMGridSnapTo = pProp; break; + + case CTF_PM_REPEAT_OFFSET_X: + pRepeatOffsetX = pProp; + break; + + case CTF_PM_REPEAT_OFFSET_Y: + pRepeatOffsetY = pProp; + break; + + case CTF_PM_HEADERREPEAT_OFFSET_X: + pHeaderRepeatOffsetX = pProp; + break; + + case CTF_PM_HEADERREPEAT_OFFSET_Y: + pHeaderRepeatOffsetY = pProp; + break; + + case CTF_PM_FOOTERREPEAT_OFFSET_X: + pFooterRepeatOffsetX = pProp; + break; + + case CTF_PM_FOOTERREPEAT_OFFSET_Y: + pFooterRepeatOffsetY = pProp; + break; + + // Sort out empty entries + case CTF_PM_FILLGRADIENTNAME: + case CTF_PM_FILLHATCHNAME: + case CTF_PM_FILLBITMAPNAME: + case CTF_PM_FILLTRANSNAME: + + case CTF_PM_HEADERFILLGRADIENTNAME: + case CTF_PM_HEADERFILLHATCHNAME: + case CTF_PM_HEADERFILLBITMAPNAME: + case CTF_PM_HEADERFILLTRANSNAME: + + case CTF_PM_FOOTERFILLGRADIENTNAME: + case CTF_PM_FOOTERFILLHATCHNAME: + case CTF_PM_FOOTERFILLBITMAPNAME: + case CTF_PM_FOOTERFILLTRANSNAME: + { + OUString aStr; + + if( (pProp->maValue >>= aStr) && 0 == aStr.getLength() ) + { + pProp->mnIndex = -1; + } + + break; + } + } + + if (nPrintId == CTF_PM_PRINTMASK) + { + pPrint = pProp; + lcl_RemoveState(pPrint); + } + } + + // These entries need to be reduced to a single one for XML export. + // Both would be exported as 'draw:tile-repeat-offset' following a percent + // value and a 'vertical' or 'horizontal' tag as mark. If both would be active + // and both would be exported this would create an XML error (same property twice) + if(pRepeatOffsetX && pRepeatOffsetY) + { + sal_Int32 nOffset(0); + + if((pRepeatOffsetX->maValue >>= nOffset) && (!nOffset)) + { + pRepeatOffsetX->mnIndex = -1; + } + else + { + pRepeatOffsetY->mnIndex = -1; + } + } + + // Same as above for Header + if(pHeaderRepeatOffsetX && pHeaderRepeatOffsetY) + { + sal_Int32 nOffset(0); + + if((pHeaderRepeatOffsetX->maValue >>= nOffset) && (!nOffset)) + { + pHeaderRepeatOffsetX->mnIndex = -1; + } + else + { + pHeaderRepeatOffsetY->mnIndex = -1; + } + } + + // Same as above for Footer + if(pFooterRepeatOffsetX && pFooterRepeatOffsetY) + { + sal_Int32 nOffset(0); + + if((pFooterRepeatOffsetX->maValue >>= nOffset) && (!nOffset)) + { + pFooterRepeatOffsetX->mnIndex = -1; + } + else + { + pFooterRepeatOffsetY->mnIndex = -1; + } + } + + if( pPMStandardMode && !getBOOL(pPMStandardMode->maValue) ) + { + lcl_RemoveState(pPMStandardMode); + if( pPMGridBaseWidth ) + lcl_RemoveState(pPMGridBaseWidth); + if( pPMGridSnapToChars ) + lcl_RemoveState(pPMGridSnapToChars); + if (pPMGridSnapTo) + { + lcl_RemoveState(pPMGridSnapTo); + } + } + + if( pPMGridBaseWidth && pPMStandardMode ) + lcl_RemoveState(pPMStandardMode); + + aPageBuffer.ContextFilter( rPropState ); + aHeaderBuffer.ContextFilter( rPropState ); + aFooterBuffer.ContextFilter( rPropState ); + + if( pPMHeaderHeight && (!pPMHeaderDynamic || getBOOL( pPMHeaderDynamic->maValue )) ) + lcl_RemoveState( pPMHeaderHeight ); + if( pPMHeaderMinHeight && pPMHeaderDynamic && !getBOOL( pPMHeaderDynamic->maValue ) ) + lcl_RemoveState( pPMHeaderMinHeight ); + if( pPMHeaderDynamic ) + lcl_RemoveState( pPMHeaderDynamic ); + + if( pPMFooterHeight && (!pPMFooterDynamic || getBOOL( pPMFooterDynamic->maValue )) ) + lcl_RemoveState( pPMFooterHeight ); + if( pPMFooterMinHeight && pPMFooterDynamic && !getBOOL( pPMFooterDynamic->maValue ) ) + lcl_RemoveState( pPMFooterMinHeight ); + if( pPMFooterDynamic ) + lcl_RemoveState( pPMFooterDynamic ); + + if( pPMScaleTo ) + lcl_RemoveStateIfZero16( pPMScaleTo ); + if( pPMScaleToPages ) + lcl_RemoveStateIfZero16( pPMScaleToPages ); + if( pPMScaleToX ) + lcl_RemoveStateIfZero16( pPMScaleToX ); + if( pPMScaleToY ) + lcl_RemoveStateIfZero16( pPMScaleToY ); + + if (pPrint) + { + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_ANNOTATIONS), "PrintAnnotations", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_CHARTS), "PrintCharts", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_DRAWING), "PrintDrawing", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_FORMULAS), "PrintFormulas", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_GRID), "PrintGrid", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_HEADERS), "PrintHeaders", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_OBJECTS), "PrintObjects", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_ZEROVALUES), "PrintZeroValues", rPropSet); + } + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rPropState, rPropSet); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterExportPropMapper.hxx b/xmloff/source/style/PageMasterExportPropMapper.hxx new file mode 100644 index 0000000000..71550443fa --- /dev/null +++ b/xmloff/source/style/PageMasterExportPropMapper.hxx @@ -0,0 +1,66 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlexppr.hxx> +#include <XMLBackgroundImageExport.hxx> +#include <XMLTextColumnsExport.hxx> +#include "XMLFootnoteSeparatorExport.hxx" + +class XMLPageMasterExportPropMapper : public SvXMLExportPropertyMapper +{ + XMLBackgroundImageExport aBackgroundImageExport; + XMLTextColumnsExport aTextColumnsExport; + XMLFootnoteSeparatorExport aFootnoteSeparatorExport; + bool m_bGutterAtTop = false; + + virtual void ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet + ) const override; + +public: + XMLPageMasterExportPropMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExport + ); + virtual ~XMLPageMasterExportPropMapper() override; + + virtual void handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx + ) const override; + virtual void handleSpecialItem( + comphelper::AttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx + ) const override; + + void SetGutterAtTop(bool bGutterAtTop) { m_bGutterAtTop = bGutterAtTop; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterImportContext.cxx b/xmloff/source/style/PageMasterImportContext.cxx new file mode 100644 index 0000000000..4e4a291291 --- /dev/null +++ b/xmloff/source/style/PageMasterImportContext.cxx @@ -0,0 +1,434 @@ +/* -*- 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 <PageMasterImportContext.hxx> +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmltoken.hxx> +#include "PageMasterPropHdl.hxx" +#include "PagePropertySetContext.hxx" +#include "PageHeaderFooterContext.hxx" +#include <PageMasterStyleMap.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <osl/diagnose.h> + +// +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <xmloff/xmlerror.hxx> +#include <xmloff/XMLTextMasterPageContext.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +// +using namespace ::com::sun::star::beans; + +void PageStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_PAGE_USAGE) ) + { + sPageUsage = rValue; + } + else + { + XMLPropStyleContext::SetAttribute( nElement, rValue ); + } +} + + +PageStyleContext::PageStyleContext( SvXMLImport& rImport, + SvXMLStylesContext& rStyles, + bool bDefaultStyle) : + XMLPropStyleContext( rImport, rStyles, XmlStyleFamily::PAGE_MASTER, bDefaultStyle), + m_bIsFillStyleAlreadyConverted(false) // +{ +} + +PageStyleContext::~PageStyleContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > PageStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_HEADER_STYLE) || + nElement == XML_ELEMENT(STYLE, XML_FOOTER_STYLE) ) + { + bool bHeader = nElement == XML_ELEMENT(STYLE, XML_HEADER_STYLE); + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + { + const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper(); + sal_Int32 nFlag; + if (bHeader) + nFlag = CTF_PM_HEADERFLAG; + else + nFlag = CTF_PM_FOOTERFLAG; + sal_Int32 nStartIndex (-1); + sal_Int32 nEndIndex (-1); + bool bFirst(false); + bool bEnd(false); + sal_Int32 nIndex = 0; + while ( nIndex < rMapper->GetEntryCount() && !bEnd) + { + if ((rMapper->GetEntryContextId( nIndex ) & CTF_PM_FLAGMASK) == nFlag) + { + if (!bFirst) + { + bFirst = true; + nStartIndex = nIndex; + } + } + else if (bFirst) + { + bEnd = true; + nEndIndex = nIndex; + } + nIndex++; + } + if (!bEnd) + nEndIndex = nIndex; + return new PageHeaderFooterContext(GetImport(), + GetProperties(), xImpPrMap, nStartIndex, nEndIndex, bHeader); + } + } + + if( nElement == XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_PROPERTIES) ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + { + const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper(); + sal_Int32 nEndIndex (-1); + bool bEnd(false); + sal_Int32 nIndex = 0; + sal_Int16 nContextID; + while ( nIndex < rMapper->GetEntryCount() && !bEnd) + { + nContextID = rMapper->GetEntryContextId( nIndex ); + if (nContextID && ((nContextID & CTF_PM_FLAGMASK) != XML_PM_CTF_START)) + { + nEndIndex = nIndex; + bEnd = true; + } + nIndex++; + } + if (!bEnd) + nEndIndex = nIndex; + return new PagePropertySetContext( GetImport(), nElement, + xAttrList, + XML_TYPE_PROP_PAGE_LAYOUT, + GetProperties(), + xImpPrMap, 0, nEndIndex, Page); + } + } + + return XMLPropStyleContext::createFastChildContext(nElement, xAttrList); +} + +void PageStyleContext::FillPropertySet(const uno::Reference<beans::XPropertySet > &) +{ + assert(false); // don't call this virtual, call function below +} + +void PageStyleContext::FillPropertySet_PageStyle( + const uno::Reference<beans::XPropertySet> & xPropSet, + XMLPropStyleContext *const pDrawingPageStyle) +{ + // need to filter out old fill definitions when the new ones are used. The new + // ones are used when a FillStyle is defined + if(!m_bIsFillStyleAlreadyConverted && !GetProperties().empty()) + { + static constexpr OUString s_FillStyle(u"FillStyle"_ustr); + static constexpr OUStringLiteral s_HeaderFillStyle(u"HeaderFillStyle"); + static constexpr OUStringLiteral s_FooterFillStyle(u"FooterFillStyle"); + + // note: the function must only check by property name, not any id/flag! + if (doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle) + || (pDrawingPageStyle && pDrawingPageStyle->doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle))) + { + deactivateOldFillStyleDefinitions(getStandardSet()); + } + + if(doNewDrawingLayerFillStyleDefinitionsExist(s_HeaderFillStyle)) + { + deactivateOldFillStyleDefinitions(getHeaderSet()); + } + + if(doNewDrawingLayerFillStyleDefinitionsExist(s_FooterFillStyle)) + { + deactivateOldFillStyleDefinitions(getFooterSet()); + } + + m_bIsFillStyleAlreadyConverted = true; + } + + // do not use XMLPropStyleContext::FillPropertySet, we need to handle this ourselves since + // we have properties which use the MID_FLAG_NO_PROPERTY_IMPORT flag since they need some special + // handling + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = GetStyles()->GetImportPropertyMapper(GetFamily()); + + if(xImpPrMap.is()) + { + // properties that need special handling because they need the used name to be translated first + struct ContextID_Index_Pair aContextIDs[] = + { + { CTF_PM_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_PM_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_PM_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_PM_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + // also need to special handling for header entries + { CTF_PM_HEADERFILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_PM_HEADERFILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_PM_HEADERFILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_PM_HEADERFILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + // also need to special handling for footer entries + { CTF_PM_FOOTERFILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_PM_FOOTERFILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_PM_FOOTERFILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_PM_FOOTERFILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + {-1, -1, drawing::FillStyle::FillStyle_GRADIENT} + }; + + // the style families associated with the same index modulo 4 + static const XmlStyleFamily aFamilies[] = + { + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID + }; + + // Fill PropertySet, but let it handle special properties not itself + xImpPrMap->FillPropertySet(GetProperties(), xPropSet, aContextIDs); + + // get property set mapper + const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper(); + Reference<XPropertySetInfo> const xInfo(xPropSet->getPropertySetInfo()); + + // don't look at the attributes, look at the property, could + // theoretically be inherited and we don't want to delete erroneously + drawing::FillStyle fillStyle{drawing::FillStyle_NONE}; + drawing::FillStyle fillStyleHeader{drawing::FillStyle_NONE}; + drawing::FillStyle fillStyleFooter{drawing::FillStyle_NONE}; + if (xInfo->hasPropertyByName("FillStyle")) // SwXTextDefaults lacks it? + { + xPropSet->getPropertyValue("FillStyle") >>= fillStyle; + xPropSet->getPropertyValue("HeaderFillStyle") >>= fillStyleHeader; + xPropSet->getPropertyValue("FooterFillStyle") >>= fillStyleFooter; + } + + // handle special attributes which have MID_FLAG_NO_PROPERTY_IMPORT set + for(sal_uInt16 i = 0; aContextIDs[i].nContextID != -1; i++) + { + sal_Int32 nIndex = aContextIDs[i].nIndex; + + if(nIndex != -1) + { + drawing::FillStyle const* pFillStyle(nullptr); + switch(aContextIDs[i].nContextID) + { + case CTF_PM_FILLGRADIENTNAME: + case CTF_PM_FILLTRANSNAME: + case CTF_PM_FILLHATCHNAME: + case CTF_PM_FILLBITMAPNAME: + pFillStyle = &fillStyle; + [[fallthrough]]; + case CTF_PM_HEADERFILLGRADIENTNAME: + case CTF_PM_HEADERFILLTRANSNAME: + case CTF_PM_HEADERFILLHATCHNAME: + case CTF_PM_HEADERFILLBITMAPNAME: + if (!pFillStyle) { pFillStyle = &fillStyleHeader; } + [[fallthrough]]; + case CTF_PM_FOOTERFILLGRADIENTNAME: + case CTF_PM_FOOTERFILLTRANSNAME: + case CTF_PM_FOOTERFILLHATCHNAME: + case CTF_PM_FOOTERFILLBITMAPNAME: + { + if (!pFillStyle) { pFillStyle = &fillStyleFooter; } + struct XMLPropertyState& rState = GetProperties()[nIndex]; + OUString sStyleName; + rState.maValue >>= sStyleName; + + if (aContextIDs[i].nExpectedFillStyle != drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE + && aContextIDs[i].nExpectedFillStyle != *pFillStyle) + { + SAL_INFO("xmloff.style", "PageStyleContext: dropping fill named item: " << sStyleName); + break; // ignore it, it's not used + } + // translate the used name from ODF intern to the name used in the Model + sStyleName = GetImport().GetStyleDisplayName(aFamilies[i%4], sStyleName); + + try + { + // set property + const OUString& rPropertyName = rMapper->GetEntryAPIName(rState.mnIndex); + + if(xInfo->hasPropertyByName(rPropertyName)) + { + xPropSet->setPropertyValue(rPropertyName,Any(sStyleName)); + } + } + catch(css::lang::IllegalArgumentException& e) + { + Sequence<OUString> aSeq { sStyleName }; + GetImport().SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, + aSeq,e.Message,nullptr); + } + break; + } + } + } + } + } + else + { + OSL_ENSURE(xImpPrMap.is(), "Got no SvXMLImportPropertyMapper (!)"); + } + + // pDrawingPageStyle overrides this + if (pDrawingPageStyle) + { + pDrawingPageStyle->FillPropertySet(xPropSet); + } + // horrible heuristic to guess BackgroundFullSize for Writer < 7.0 + else if (!IsDefaultStyle() // ignore pool default, only fix existing styles + && (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x)) + { + bool isFullSize(true); // default is current LO default + drawing::FillStyle fillStyle{drawing::FillStyle_NONE}; + xPropSet->getPropertyValue("FillStyle") >>= fillStyle; + if (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_63x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x) + { + // before LO 6.3, always inside the margins (but ignore it if NONE) + if (fillStyle != drawing::FillStyle_NONE) + { + isFullSize = false; + } + } + else + { + // LO 6.3/6.4: guess depending on fill style/bitmap mode + // this should work even if the document doesn't contain fill style + // but only old background attributes + // (can't use the aContextIDs stuff above because that requires + // re-routing through handleSpecialItem()) + switch (fillStyle) + { + case drawing::FillStyle_NONE: + break; + case drawing::FillStyle_SOLID: + case drawing::FillStyle_GRADIENT: + case drawing::FillStyle_HATCH: + isFullSize = true; + break; + case drawing::FillStyle_BITMAP: + { + drawing::BitmapMode bitmapMode{}; + xPropSet->getPropertyValue("FillBitmapMode") >>= bitmapMode; + switch (bitmapMode) + { + case drawing::BitmapMode_REPEAT: + isFullSize = true; + break; + case drawing::BitmapMode_STRETCH: + case drawing::BitmapMode_NO_REPEAT: + isFullSize = false; + break; + default: + assert(false); + } + } + break; + default: + assert(false); + } + } + // set it explicitly if it's not the default + if (!isFullSize) + { + SAL_INFO("xmloff.style", "FillPropertySet_PageStyle: Heuristically resetting BackgroundFullSize"); + xPropSet->setPropertyValue("BackgroundFullSize", uno::Any(isFullSize)); + } + } + + // old code, replaced by above stuff + // XMLPropStyleContext::FillPropertySet(rPropSet); + + if (!sPageUsage.isEmpty()) + { + uno::Any aPageUsage; + XMLPMPropHdl_PageStyleLayout aPageUsageHdl; + if (aPageUsageHdl.importXML(sPageUsage, aPageUsage, GetImport().GetMM100UnitConverter())) + xPropSet->setPropertyValue("PageStyleLayout", aPageUsage); + } +} + +extern ContextID_Index_Pair const g_MasterPageContextIDs[] = +{ + { CTF_PM_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_PM_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_PM_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_PM_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + {-1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE} +}; + +extern XmlStyleFamily const g_MasterPageFamilies[] = +{ + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID +}; + +// text grid enhancement for better CJK support +//set default page layout style +void PageStyleContext::SetDefaults( ) +{ + Reference < XMultiServiceFactory > xFactory ( GetImport().GetModel(), UNO_QUERY); + if (xFactory.is()) + { + Reference < XInterface > xInt = xFactory->createInstance( "com.sun.star.text.Defaults" ); + Reference < beans::XPropertySet > xProperties ( xInt, UNO_QUERY ); + if ( xProperties.is() ) + FillPropertySet_PageStyle(xProperties, nullptr); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterImportPropMapper.cxx b/xmloff/source/style/PageMasterImportPropMapper.cxx new file mode 100644 index 0000000000..d4eba76017 --- /dev/null +++ b/xmloff/source/style/PageMasterImportPropMapper.cxx @@ -0,0 +1,521 @@ +/* -*- 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 "PageMasterImportPropMapper.hxx" +#include <PageMasterStyleMap.hxx> +#include <xmloff/maptype.hxx> +#include <com/sun/star/table/BorderLine2.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlprmap.hxx> +#include <memory> + +#define XML_LINE_LEFT 0 +#define XML_LINE_RIGHT 1 +#define XML_LINE_TOP 2 +#define XML_LINE_BOTTOM 3 + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + +PageMasterImportPropertyMapper::PageMasterImportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLImport& rImp ) : + SvXMLImportPropertyMapper( rMapper, rImp ), + rImport( rImp ) +{ +} + +PageMasterImportPropertyMapper::~PageMasterImportPropertyMapper() +{ +} + +bool PageMasterImportPropertyMapper::handleSpecialItem( + XMLPropertyState& rProperty, + std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const +{ + bool bRet = false; + sal_Int16 nContextID = + getPropertySetMapper()->GetEntryContextId(rProperty.mnIndex); + + if( CTF_PM_REGISTER_STYLE==nContextID ) + { + OUString sDisplayName( rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, rValue ) ); + Reference < XNameContainer > xParaStyles = + rImport.GetTextImport()->GetParaStyles(); + if( xParaStyles.is() && xParaStyles->hasByName( sDisplayName ) ) + { + rProperty.maValue <<= sDisplayName; + bRet = true; + } + } + else + { + bRet = SvXMLImportPropertyMapper::handleSpecialItem( + rProperty, rProperties, rValue, + rUnitConverter, rNamespaceMap ); + } + + return bRet; +} + + +void PageMasterImportPropertyMapper::finished(std::vector< XMLPropertyState >& rProperties, sal_Int32 nStartIndex, sal_Int32 nEndIndex ) const +{ + SvXMLImportPropertyMapper::finished(rProperties, nStartIndex, nEndIndex); + XMLPropertyState* pAllPaddingProperty = nullptr; + XMLPropertyState* pPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pNewPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllBorderProperty = nullptr; + XMLPropertyState* pBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllBorderWidthProperty = nullptr; + XMLPropertyState* pBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllHeaderPaddingProperty = nullptr; + XMLPropertyState* pHeaderPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pHeaderNewPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllHeaderBorderProperty = nullptr; + XMLPropertyState* pHeaderBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pHeaderNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllHeaderBorderWidthProperty = nullptr; + XMLPropertyState* pHeaderBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllFooterPaddingProperty = nullptr; + XMLPropertyState* pFooterPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pFooterNewPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllFooterBorderProperty = nullptr; + XMLPropertyState* pFooterBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pFooterNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllFooterBorderWidthProperty = nullptr; + XMLPropertyState* pFooterBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pHeaderHeight = nullptr; + XMLPropertyState* pHeaderMinHeight = nullptr; + std::optional<XMLPropertyState> xHeaderDynamic; + XMLPropertyState* pFooterHeight = nullptr; + XMLPropertyState* pFooterMinHeight = nullptr; + std::optional<XMLPropertyState> xFooterDynamic; + XMLPropertyState* pAllMarginProperty = nullptr; + XMLPropertyState* pMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + std::optional<XMLPropertyState> pNewMargins[4]; + XMLPropertyState* pAllHeaderMarginProperty = nullptr; + XMLPropertyState* pHeaderMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + std::optional<XMLPropertyState> pNewHeaderMargins[4]; + XMLPropertyState* pAllFooterMarginProperty = nullptr; + XMLPropertyState* pFooterMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + std::optional<XMLPropertyState> pNewFooterMargins[4]; + XMLPropertyState* pMarginGutter = nullptr; + XMLPropertyState* pRtlGutter = nullptr; + + for (auto& rProp : rProperties) + { + XMLPropertyState *property = &rProp; + sal_Int16 nContextID = getPropertySetMapper()->GetEntryContextId(property->mnIndex); + if (property->mnIndex >= nStartIndex && property->mnIndex < nEndIndex) + { + switch (nContextID) + { + case CTF_PM_PADDINGALL : pAllPaddingProperty = property; break; + case CTF_PM_PADDINGLEFT : pPadding[XML_LINE_LEFT] = property; break; + case CTF_PM_PADDINGRIGHT : pPadding[XML_LINE_RIGHT] = property; break; + case CTF_PM_PADDINGTOP : pPadding[XML_LINE_TOP] = property; break; + case CTF_PM_PADDINGBOTTOM : pPadding[XML_LINE_BOTTOM] = property; break; + case CTF_PM_BORDERALL : pAllBorderProperty = property; break; + case CTF_PM_BORDERLEFT : pBorders[XML_LINE_LEFT] = property; break; + case CTF_PM_BORDERRIGHT : pBorders[XML_LINE_RIGHT] = property; break; + case CTF_PM_BORDERTOP : pBorders[XML_LINE_TOP] = property; break; + case CTF_PM_BORDERBOTTOM : pBorders[XML_LINE_BOTTOM] = property; break; + case CTF_PM_BORDERWIDTHALL : pAllBorderWidthProperty = property; break; + case CTF_PM_BORDERWIDTHLEFT : pBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_PM_BORDERWIDTHRIGHT : pBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_PM_BORDERWIDTHTOP : pBorderWidths[XML_LINE_TOP] = property; break; + case CTF_PM_BORDERWIDTHBOTTOM : pBorderWidths[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERPADDINGALL : pAllHeaderPaddingProperty = property; break; + case CTF_PM_HEADERPADDINGLEFT : pHeaderPadding[XML_LINE_LEFT] = property; break; + case CTF_PM_HEADERPADDINGRIGHT : pHeaderPadding[XML_LINE_RIGHT] = property; break; + case CTF_PM_HEADERPADDINGTOP : pHeaderPadding[XML_LINE_TOP] = property; break; + case CTF_PM_HEADERPADDINGBOTTOM : pHeaderPadding[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERBORDERALL : pAllHeaderBorderProperty = property; break; + case CTF_PM_HEADERBORDERLEFT : pHeaderBorders[XML_LINE_LEFT] = property; break; + case CTF_PM_HEADERBORDERRIGHT : pHeaderBorders[XML_LINE_RIGHT] = property; break; + case CTF_PM_HEADERBORDERTOP : pHeaderBorders[XML_LINE_TOP] = property; break; + case CTF_PM_HEADERBORDERBOTTOM : pHeaderBorders[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERBORDERWIDTHALL : pAllHeaderBorderWidthProperty = property; break; + case CTF_PM_HEADERBORDERWIDTHLEFT : pHeaderBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_PM_HEADERBORDERWIDTHRIGHT : pHeaderBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_PM_HEADERBORDERWIDTHTOP : pHeaderBorderWidths[XML_LINE_TOP] = property; break; + case CTF_PM_HEADERBORDERWIDTHBOTTOM : pHeaderBorderWidths[XML_LINE_BOTTOM] = property; break; + case CTF_PM_FOOTERPADDINGALL : pAllFooterPaddingProperty = property; break; + case CTF_PM_FOOTERPADDINGLEFT : pFooterPadding[XML_LINE_LEFT] = property; break; + case CTF_PM_FOOTERPADDINGRIGHT : pFooterPadding[XML_LINE_RIGHT] = property; break; + case CTF_PM_FOOTERPADDINGTOP : pFooterPadding[XML_LINE_TOP] = property; break; + case CTF_PM_FOOTERPADDINGBOTTOM : pFooterPadding[XML_LINE_BOTTOM] = property; break; + case CTF_PM_FOOTERBORDERALL : pAllFooterBorderProperty = property; break; + case CTF_PM_FOOTERBORDERLEFT : pFooterBorders[XML_LINE_LEFT] = property; break; + case CTF_PM_FOOTERBORDERRIGHT : pFooterBorders[XML_LINE_RIGHT] = property; break; + case CTF_PM_FOOTERBORDERTOP : pFooterBorders[XML_LINE_TOP] = property; break; + case CTF_PM_FOOTERBORDERBOTTOM : pFooterBorders[XML_LINE_BOTTOM] = property; break; + case CTF_PM_FOOTERBORDERWIDTHALL : pAllFooterBorderWidthProperty = property; break; + case CTF_PM_FOOTERBORDERWIDTHLEFT : pFooterBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_PM_FOOTERBORDERWIDTHRIGHT : pFooterBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_PM_FOOTERBORDERWIDTHTOP : pFooterBorderWidths[XML_LINE_TOP] = property; break; + case CTF_PM_FOOTERBORDERWIDTHBOTTOM : pFooterBorderWidths[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERHEIGHT : pHeaderHeight = property; break; + case CTF_PM_HEADERMINHEIGHT : pHeaderMinHeight = property; break; + case CTF_PM_FOOTERHEIGHT : pFooterHeight = property; break; + case CTF_PM_FOOTERMINHEIGHT : pFooterMinHeight = property; break; + case CTF_PM_MARGINALL : + pAllMarginProperty = property; break; + case CTF_PM_MARGINTOP : + pMargins[XML_LINE_TOP] = property; break; + case CTF_PM_MARGINBOTTOM: + pMargins[XML_LINE_BOTTOM] = property; break; + case CTF_PM_MARGINLEFT : + pMargins[XML_LINE_LEFT] = property; break; + case CTF_PM_MARGINRIGHT : + pMargins[XML_LINE_RIGHT] = property; break; + case CTF_PM_MARGINGUTTER: + pMarginGutter = property; + break; + case CTF_PM_RTLGUTTER: + pRtlGutter = property; + break; + case CTF_PM_HEADERMARGINALL : + pAllHeaderMarginProperty = property; break; + case CTF_PM_HEADERMARGINTOP : + pHeaderMargins[XML_LINE_TOP] = property; break; + case CTF_PM_HEADERMARGINBOTTOM: + pHeaderMargins[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERMARGINLEFT : + pHeaderMargins[XML_LINE_LEFT] = property; break; + case CTF_PM_HEADERMARGINRIGHT : + pHeaderMargins[XML_LINE_RIGHT] = property; break; + case CTF_PM_FOOTERMARGINALL : + pAllFooterMarginProperty = property; break; + case CTF_PM_FOOTERMARGINTOP : + pFooterMargins[XML_LINE_TOP] = property; break; + case CTF_PM_FOOTERMARGINBOTTOM: + pFooterMargins[XML_LINE_BOTTOM] = property; break; + case CTF_PM_FOOTERMARGINLEFT : + pFooterMargins[XML_LINE_LEFT] = property; break; + case CTF_PM_FOOTERMARGINRIGHT : + pFooterMargins[XML_LINE_RIGHT] = property; break; + } + } + } + + for (sal_uInt16 i = 0; i < 4; i++) + { + if (pAllMarginProperty && !pMargins[i]) + { + pNewMargins[i].emplace( + pAllMarginProperty->mnIndex + 1 + i, + pAllMarginProperty->maValue); + } + if (pAllHeaderMarginProperty && !pHeaderMargins[i]) + { + pNewHeaderMargins[i].emplace( + pAllHeaderMarginProperty->mnIndex + 1 + i, + pAllHeaderMarginProperty->maValue); + } + if (pAllFooterMarginProperty && !pFooterMargins[i]) + { + pNewFooterMargins[i].emplace( + pAllFooterMarginProperty->mnIndex + 1 + i, + pAllFooterMarginProperty->maValue); + } + if (pAllPaddingProperty && !pPadding[i]) + pNewPadding[i] = new XMLPropertyState(pAllPaddingProperty->mnIndex + 1 + i, pAllPaddingProperty->maValue); + if (pAllBorderProperty && !pBorders[i]) + { + pNewBorders[i] = new XMLPropertyState(pAllBorderProperty->mnIndex + 1 + i, pAllBorderProperty->maValue); + pBorders[i] = pNewBorders[i]; + } + if( !pBorderWidths[i] ) + pBorderWidths[i] = pAllBorderWidthProperty; + else + pBorderWidths[i]->mnIndex = -1; + if( pBorders[i] ) + { + table::BorderLine2 aBorderLine; + pBorders[i]->maValue >>= aBorderLine; + if( pBorderWidths[i] ) + { + table::BorderLine2 aBorderLineWidth; + pBorderWidths[i]->maValue >>= aBorderLineWidth; + aBorderLine.OuterLineWidth = aBorderLineWidth.OuterLineWidth; + aBorderLine.InnerLineWidth = aBorderLineWidth.InnerLineWidth; + aBorderLine.LineDistance = aBorderLineWidth.LineDistance; + aBorderLine.LineWidth = aBorderLineWidth.LineWidth; + pBorders[i]->maValue <<= aBorderLine; + } + } + if (pAllHeaderPaddingProperty && !pHeaderPadding[i]) + pHeaderNewPadding[i] = new XMLPropertyState(pAllHeaderPaddingProperty->mnIndex + 1 + i, pAllHeaderPaddingProperty->maValue); + if (pAllHeaderBorderProperty && !pHeaderBorders[i]) + pHeaderNewBorders[i] = new XMLPropertyState(pAllHeaderBorderProperty->mnIndex + 1 + i, pAllHeaderBorderProperty->maValue); + if( !pHeaderBorderWidths[i] ) + pHeaderBorderWidths[i] = pAllHeaderBorderWidthProperty; + else + pHeaderBorderWidths[i]->mnIndex = -1; + if( pHeaderBorders[i] ) + { + table::BorderLine2 aBorderLine; + pHeaderBorders[i]->maValue >>= aBorderLine; + if( pHeaderBorderWidths[i] ) + { + table::BorderLine2 aBorderLineWidth; + pHeaderBorderWidths[i]->maValue >>= aBorderLineWidth; + aBorderLine.OuterLineWidth = aBorderLineWidth.OuterLineWidth; + aBorderLine.InnerLineWidth = aBorderLineWidth.InnerLineWidth; + aBorderLine.LineDistance = aBorderLineWidth.LineDistance; + aBorderLine.LineWidth = aBorderLineWidth.LineWidth; + pHeaderBorders[i]->maValue <<= aBorderLine; + } + } + if (pAllFooterPaddingProperty && !pFooterPadding[i]) + pFooterNewPadding[i] = new XMLPropertyState(pAllFooterPaddingProperty->mnIndex + 1 + i, pAllFooterPaddingProperty->maValue); + if (pAllFooterBorderProperty && !pFooterBorders[i]) + pFooterNewBorders[i] = new XMLPropertyState(pAllFooterBorderProperty->mnIndex + 1 + i, pAllFooterBorderProperty->maValue); + if( !pFooterBorderWidths[i] ) + pFooterBorderWidths[i] = pAllFooterBorderWidthProperty; + else + pFooterBorderWidths[i]->mnIndex = -1; + if( pFooterBorders[i] ) + { + table::BorderLine2 aBorderLine; + pFooterBorders[i]->maValue >>= aBorderLine; + if( pFooterBorderWidths[i] ) + { + table::BorderLine2 aBorderLineWidth; + pFooterBorderWidths[i]->maValue >>= aBorderLineWidth; + aBorderLine.OuterLineWidth = aBorderLineWidth.OuterLineWidth; + aBorderLine.InnerLineWidth = aBorderLineWidth.InnerLineWidth; + aBorderLine.LineDistance = aBorderLineWidth.LineDistance; + aBorderLine.LineWidth = aBorderLineWidth.LineWidth; + pFooterBorders[i]->maValue <<= aBorderLine; + } + } + } + + if (pHeaderHeight) + { + xHeaderDynamic.emplace(pHeaderHeight->mnIndex + 2, Any(false)); + } + if (pHeaderMinHeight) + { + xHeaderDynamic.emplace(pHeaderMinHeight->mnIndex + 1, Any(true)); + } + if (pFooterHeight) + { + xFooterDynamic.emplace(pFooterHeight->mnIndex + 2, Any(false)); + } + if (pFooterMinHeight) + { + xFooterDynamic.emplace(pFooterMinHeight->mnIndex + 1, Any(true)); + } + + // fdo#38056: nerf the various AllFoo properties so they do not override + // the individual Foo properties later on + if (pAllPaddingProperty) + { + pAllPaddingProperty->mnIndex = -1; + } + if (pAllBorderProperty) + { + pAllBorderProperty->mnIndex = -1; + } + if (pAllBorderWidthProperty) + { + pAllBorderWidthProperty->mnIndex = -1; + } + if (pAllHeaderPaddingProperty) + { + pAllHeaderPaddingProperty->mnIndex = -1; + } + if (pAllHeaderBorderProperty) + { + pAllHeaderBorderProperty->mnIndex = -1; + } + if (pAllHeaderBorderWidthProperty) + { + pAllHeaderBorderWidthProperty->mnIndex = -1; + } + if (pAllFooterPaddingProperty) + { + pAllFooterPaddingProperty->mnIndex = -1; + } + if (pAllFooterBorderProperty) + { + pAllFooterBorderProperty->mnIndex = -1; + } + if (pAllFooterBorderWidthProperty) + { + pAllFooterBorderWidthProperty->mnIndex = -1; + } + if (pAllMarginProperty) + { + pAllMarginProperty->mnIndex = -1; + } + if (pAllHeaderMarginProperty) + { + pAllHeaderMarginProperty->mnIndex = -1; + } + if (pAllFooterMarginProperty) + { + pAllFooterMarginProperty->mnIndex = -1; + } + + if (pMarginGutter) + { + sal_Int32 nGutterMargin{}; + pMarginGutter->maValue >>= nGutterMargin; + + bool bGutterAtTop{}; + uno::Reference<lang::XServiceInfo> xSI(GetImport().GetModel(), uno::UNO_QUERY); + if (xSI.is() && xSI->supportsService("com.sun.star.text.TextDocument")) + { + uno::Reference<lang::XMultiServiceFactory> xFac(GetImport().GetModel(), uno::UNO_QUERY); + if (xFac.is()) + { + uno::Reference<beans::XPropertySet> xProps( + xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY); + if (xProps.is()) + { + xProps->getPropertyValue("GutterAtTop") >>= bGutterAtTop; + } + } + } + if (bGutterAtTop) + { + if (nGutterMargin && pMargins[XML_LINE_TOP]) + { + // Decrease top margin to not include gutter. + sal_Int32 nTopMargin{}; + pMargins[XML_LINE_TOP]->maValue >>= nTopMargin; + nTopMargin -= nGutterMargin; + pMargins[XML_LINE_TOP]->maValue <<= nTopMargin; + } + } + else + { + bool bRtlGutter{}; + if (nGutterMargin && pRtlGutter) + { + pRtlGutter->maValue >>= bRtlGutter; + } + if (bRtlGutter) + { + if (nGutterMargin && pMargins[XML_LINE_RIGHT]) + { + // Decrease right margin to not include gutter. + sal_Int32 nRightMargin{}; + pMargins[XML_LINE_RIGHT]->maValue >>= nRightMargin; + nRightMargin -= nGutterMargin; + pMargins[XML_LINE_RIGHT]->maValue <<= nRightMargin; + } + } + else + { + if (nGutterMargin && pMargins[XML_LINE_LEFT]) + { + // Decrease left margin to not include gutter. + sal_Int32 nLeftMargin{}; + pMargins[XML_LINE_LEFT]->maValue >>= nLeftMargin; + nLeftMargin -= nGutterMargin; + pMargins[XML_LINE_LEFT]->maValue <<= nLeftMargin; + } + } + } + } + + // CAUTION! + // The following code adds into the rProperties vector, so all the + // XMLPropertyState* pointers that are pointing to the rProperties + // elements could potentially be deallocated, so don't use them after + // this! + for (sal_uInt16 i = 0; i < 4; i++) + { + if (pNewMargins[i]) + { + rProperties.push_back(*pNewMargins[i]); + } + if (pNewHeaderMargins[i]) + { + rProperties.push_back(*pNewHeaderMargins[i]); + } + if (pNewFooterMargins[i]) + { + rProperties.push_back(*pNewFooterMargins[i]); + } + if (pNewPadding[i]) + { + rProperties.push_back(*pNewPadding[i]); + delete pNewPadding[i]; + } + if (pNewBorders[i]) + { + rProperties.push_back(*pNewBorders[i]); + delete pNewBorders[i]; + } + if (pHeaderNewPadding[i]) + { + rProperties.push_back(*pHeaderNewPadding[i]); + delete pHeaderNewPadding[i]; + } + if (pHeaderNewBorders[i]) + { + rProperties.push_back(*pHeaderNewBorders[i]); + delete pHeaderNewBorders[i]; + } + if (pFooterNewPadding[i]) + { + rProperties.push_back(*pFooterNewPadding[i]); + delete pFooterNewPadding[i]; + } + if (pFooterNewBorders[i]) + { + rProperties.push_back(*pFooterNewBorders[i]); + delete pFooterNewBorders[i]; + } + } + // CAUTION - do not use XMLPropertyState* pointers (like pMargins, + // pMarginGutter) after this. + + if(xHeaderDynamic) + { + rProperties.push_back(*xHeaderDynamic); + xHeaderDynamic.reset(); + } + if(xFooterDynamic) + { + rProperties.push_back(*xFooterDynamic); + xFooterDynamic.reset(); + } + +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterImportPropMapper.hxx b/xmloff/source/style/PageMasterImportPropMapper.hxx new file mode 100644 index 0000000000..1493ffd6b9 --- /dev/null +++ b/xmloff/source/style/PageMasterImportPropMapper.hxx @@ -0,0 +1,53 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlimppr.hxx> + +class SvXMLImport; + +class PageMasterImportPropertyMapper : public SvXMLImportPropertyMapper +{ + SvXMLImport& rImport; + +protected: + +public: + + PageMasterImportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLImport& rImp); + virtual ~PageMasterImportPropertyMapper() override; + + /** this method is called for every item that has the MID_FLAG_SPECIAL_ITEM_IMPORT flag set */ + virtual bool handleSpecialItem( + XMLPropertyState& rProperty, + ::std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const override; + + /** This method is called when all attributes have been processed. It may be used to remove items that are incomplete */ + virtual void finished( + ::std::vector< XMLPropertyState >& rProperties, + sal_Int32 nStartIndex, sal_Int32 nEndIndex ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterPropHdl.cxx b/xmloff/source/style/PageMasterPropHdl.cxx new file mode 100644 index 0000000000..c1fb9010b7 --- /dev/null +++ b/xmloff/source/style/PageMasterPropHdl.cxx @@ -0,0 +1,398 @@ +/* -*- 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 "PageMasterPropHdl.hxx" + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/style/PageStyleLayout.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <comphelper/types.hxx> +#include <comphelper/extract.hxx> +#include <o3tl/string_view.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::comphelper; +using namespace ::xmloff::token; + +#define DEFAULT_PAPERTRAY (sal_Int32(-1)) + +// property handler for style:page-usage (style::PageStyleLayout) + +XMLPMPropHdl_PageStyleLayout::~XMLPMPropHdl_PageStyleLayout() +{ +} + +bool XMLPMPropHdl_PageStyleLayout::equals( const Any& rAny1, const Any& rAny2 ) const +{ + style::PageStyleLayout eLayout1, eLayout2; + return (rAny1 >>= eLayout1) && (rAny2 >>= eLayout2) && (eLayout1 == eLayout2); +} + +bool XMLPMPropHdl_PageStyleLayout::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + + if( IsXMLToken( rStrImpValue, XML_ALL ) ) + rValue <<= PageStyleLayout_ALL; + else if( IsXMLToken( rStrImpValue, XML_LEFT ) ) + rValue <<= PageStyleLayout_LEFT; + else if( IsXMLToken( rStrImpValue, XML_RIGHT ) ) + rValue <<= PageStyleLayout_RIGHT; + else if( IsXMLToken( rStrImpValue, XML_MIRRORED ) ) + rValue <<= PageStyleLayout_MIRRORED; + else + bRet = false; + + return bRet; +} + +bool XMLPMPropHdl_PageStyleLayout::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + PageStyleLayout eLayout; + + if( rValue >>= eLayout ) + { + bRet = true; + switch( eLayout ) + { + case PageStyleLayout_ALL: + rStrExpValue = GetXMLToken( XML_ALL ); + break; + case PageStyleLayout_LEFT: + rStrExpValue = GetXMLToken( XML_LEFT ); + break; + case PageStyleLayout_RIGHT: + rStrExpValue = GetXMLToken( XML_RIGHT ); + break; + case PageStyleLayout_MIRRORED: + rStrExpValue = GetXMLToken( XML_MIRRORED ); + break; + default: + bRet = false; + } + } + + return bRet; +} + +// property handler for style:num-format (style::NumberingType) + +XMLPMPropHdl_NumFormat::~XMLPMPropHdl_NumFormat() +{ +} + +bool XMLPMPropHdl_NumFormat::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int16 nSync = sal_Int16(); + sal_Int16 nNumType = NumberingType::NUMBER_NONE; + rUnitConverter.convertNumFormat( nNumType, rStrImpValue, u"", true ); + + if( !(rValue >>= nSync) ) + nSync = NumberingType::NUMBER_NONE; + + // if num-letter-sync appears before num-format, the function + // XMLPMPropHdl_NumLetterSync::importXML() sets the value + // NumberingType::CHARS_LOWER_LETTER_N + if( nSync == NumberingType::CHARS_LOWER_LETTER_N ) + { + switch( nNumType ) + { + case NumberingType::CHARS_LOWER_LETTER: + nNumType = NumberingType::CHARS_LOWER_LETTER_N; + break; + case NumberingType::CHARS_UPPER_LETTER: + nNumType = NumberingType::CHARS_UPPER_LETTER_N; + break; + } + } + rValue <<= nNumType; + + return true; +} + +bool XMLPMPropHdl_NumFormat::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int16 nNumType = sal_Int16(); + + if( rValue >>= nNumType ) + { + OUStringBuffer aBuffer( 10 ); + rUnitConverter.convertNumFormat( aBuffer, nNumType ); + rStrExpValue = aBuffer.makeStringAndClear(); + bRet = true; + } + return bRet; +} + +// property handler for style:num-letter-sync (style::NumberingType) + +XMLPMPropHdl_NumLetterSync::~XMLPMPropHdl_NumLetterSync() +{ +} + +bool XMLPMPropHdl_NumLetterSync::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int16 nNumType; + sal_Int16 nSync = NumberingType::NUMBER_NONE; + rUnitConverter.convertNumFormat( nSync, rStrImpValue, + GetXMLToken( XML_A ), true ); + + if( !(rValue >>= nNumType) ) + nNumType = NumberingType::NUMBER_NONE; + + if( nSync == NumberingType::CHARS_LOWER_LETTER_N ) + { + switch( nNumType ) + { + case NumberingType::CHARS_LOWER_LETTER: + nNumType = NumberingType::CHARS_LOWER_LETTER_N; + break; + case NumberingType::CHARS_UPPER_LETTER: + nNumType = NumberingType::CHARS_UPPER_LETTER_N; + break; + } + } + rValue <<= nNumType; + + return true; +} + +bool XMLPMPropHdl_NumLetterSync::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bRet = false; + sal_Int16 nNumType = sal_Int16(); + + if( rValue >>= nNumType ) + { + OUStringBuffer aBuffer( 5 ); + SvXMLUnitConverter::convertNumLetterSync( aBuffer, nNumType ); + rStrExpValue = aBuffer.makeStringAndClear(); + bRet = !rStrExpValue.isEmpty(); + } + return bRet; +} + +// property handler for style:paper-tray-number + +XMLPMPropHdl_PaperTrayNumber::~XMLPMPropHdl_PaperTrayNumber() +{ +} + +bool XMLPMPropHdl_PaperTrayNumber::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( IsXMLToken( rStrImpValue, XML_DEFAULT ) ) + { + rValue <<= DEFAULT_PAPERTRAY; + bRet = true; + } + else + { + sal_Int32 nPaperTray; + if (::sax::Converter::convertNumber( nPaperTray, rStrImpValue, 0 )) + { + rValue <<= nPaperTray; + bRet = true; + } + } + + return bRet; +} + +bool XMLPMPropHdl_PaperTrayNumber::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nPaperTray = 0; + + if( rValue >>= nPaperTray ) + { + if( nPaperTray == DEFAULT_PAPERTRAY ) + rStrExpValue = GetXMLToken( XML_DEFAULT ); + else + { + rStrExpValue = OUString::number( nPaperTray ); + } + bRet = true; + } + return bRet; +} + +// property handler for style:print + +XMLPMPropHdl_Print::XMLPMPropHdl_Print( enum XMLTokenEnum eValue ) : + sAttrValue( GetXMLToken( eValue ) ) +{ +} + +XMLPMPropHdl_Print::~XMLPMPropHdl_Print() +{ +} + +bool XMLPMPropHdl_Print::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nTokenIndex = 0; + bool bFound = false; + + do + { + bFound = (sAttrValue == o3tl::getToken(rStrImpValue, 0, ' ', nTokenIndex )); + } + while ( (nTokenIndex >= 0) && !bFound ); + + rValue <<= bFound; + return true; +} + +bool XMLPMPropHdl_Print::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( getBOOL( rValue ) ) + { + if( !rStrExpValue.isEmpty() ) + rStrExpValue += " "; + rStrExpValue += sAttrValue; + } + + return true; +} + +// property handler for style:table-centering + +XMLPMPropHdl_CenterHorizontal::~XMLPMPropHdl_CenterHorizontal() +{ +} + +bool XMLPMPropHdl_CenterHorizontal::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if (!rStrImpValue.isEmpty()) + if (IsXMLToken( rStrImpValue, XML_BOTH) || + IsXMLToken( rStrImpValue, XML_HORIZONTAL)) + { + rValue <<= true; + bRet = true; + } + + return bRet; +} + +bool XMLPMPropHdl_CenterHorizontal::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if ( ::cppu::any2bool( rValue ) ) + { + bRet = true; + if (!rStrExpValue.isEmpty()) + rStrExpValue = GetXMLToken(XML_BOTH); + else + rStrExpValue = GetXMLToken(XML_HORIZONTAL); + } + + return bRet; +} + +XMLPMPropHdl_CenterVertical::~XMLPMPropHdl_CenterVertical() +{ +} + +bool XMLPMPropHdl_CenterVertical::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if (!rStrImpValue.isEmpty()) + if (IsXMLToken(rStrImpValue, XML_BOTH) || + IsXMLToken(rStrImpValue, XML_VERTICAL) ) + { + rValue <<= true; + bRet = true; + } + + return bRet; +} + +bool XMLPMPropHdl_CenterVertical::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if ( ::cppu::any2bool( rValue ) ) + { + bRet = true; + if (!rStrExpValue.isEmpty()) + rStrExpValue = GetXMLToken(XML_BOTH); + else + rStrExpValue = GetXMLToken(XML_VERTICAL); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterPropHdl.hxx b/xmloff/source/style/PageMasterPropHdl.hxx new file mode 100644 index 0000000000..2cfd39aff2 --- /dev/null +++ b/xmloff/source/style/PageMasterPropHdl.hxx @@ -0,0 +1,158 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> +#include <rtl/ustring.hxx> +#include <xmloff/xmltoken.hxx> + +// property handler for style:page-usage (style::PageStyleLayout) + +class XMLPMPropHdl_PageStyleLayout : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_PageStyleLayout() override; + virtual bool equals( + const css::uno::Any& rAny1, + const css::uno::Any& rAny2 + ) const override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:num-format (style::NumberingType) + +class XMLPMPropHdl_NumFormat : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_NumFormat() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:num-letter-sync (style::NumberingType) + +class XMLPMPropHdl_NumLetterSync : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_NumLetterSync() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:paper-tray-number + +class XMLPMPropHdl_PaperTrayNumber : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_PaperTrayNumber() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:print + +class XMLPMPropHdl_Print : public XMLPropertyHandler +{ + OUString sAttrValue; + +public: + explicit XMLPMPropHdl_Print( enum ::xmloff::token::XMLTokenEnum eValue ); + virtual ~XMLPMPropHdl_Print() override; + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:table-centering + +class XMLPMPropHdl_CenterHorizontal : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_CenterHorizontal() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +class XMLPMPropHdl_CenterVertical : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_CenterVertical() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterPropHdlFactory.cxx b/xmloff/source/style/PageMasterPropHdlFactory.cxx new file mode 100644 index 0000000000..88a14fb809 --- /dev/null +++ b/xmloff/source/style/PageMasterPropHdlFactory.cxx @@ -0,0 +1,170 @@ +/* -*- 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 <PageMasterPropHdlFactory.hxx> +#include <enummaps.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/xmltoken.hxx> +#include "xmlbahdl.hxx" +#include <xmloff/NamedBoolPropertyHdl.hxx> +#include <XMLTextColumnsPropertyHandler.hxx> +#include <xmloff/XMLConstantsPropertyHandler.hxx> +#include "PageMasterPropHdl.hxx" +#include <PageMasterStyleMap.hxx> +#include <com/sun/star/text/TextGridMode.hpp> +#include <xmloff/EnumPropertyHdl.hxx> +#include <osl/diagnose.h> +#include <XMLFillBitmapSizePropertyHandler.hxx> +#include <XMLBitmapLogicalSizePropertyHandler.hxx> +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <XMLBitmapRepeatOffsetPropertyHandler.hxx> +#include <XMLRtlGutterPropertyHandler.hxx> + +using namespace ::xmloff::token; +using namespace ::com::sun::star; +using namespace ::com::sun::star::drawing; + +SvXMLEnumMapEntry<sal_uInt16> const aXML_TextGridMode_ConstantMap[] = +{ + { XML_NONE, text::TextGridMode::NONE }, + { XML_LINE, text::TextGridMode::LINES }, + { XML_BOTH, text::TextGridMode::LINES_AND_CHARS }, + { XML_TOKEN_INVALID, 0 } +}; + +XMLPageMasterPropHdlFactory::XMLPageMasterPropHdlFactory() +{ +} + +XMLPageMasterPropHdlFactory::~XMLPageMasterPropHdlFactory() +{ +} + +const XMLPropertyHandler* XMLPageMasterPropHdlFactory::GetPropertyHandler( sal_Int32 nType ) const +{ + nType &= MID_FLAG_MASK; + + XMLPropertyHandler* pHdl = const_cast<XMLPropertyHandler*>(XMLPropertyHandlerFactory::GetPropertyHandler( nType )); + if( !pHdl ) + { + switch( nType ) + { + case XML_PM_TYPE_PAGESTYLELAYOUT: + pHdl = new XMLPMPropHdl_PageStyleLayout; + break; + case XML_PM_TYPE_NUMFORMAT: + pHdl = new XMLPMPropHdl_NumFormat; + break; + case XML_PM_TYPE_NUMLETTERSYNC: + pHdl = new XMLPMPropHdl_NumLetterSync; + break; + case XML_PM_TYPE_PAPERTRAYNUMBER: + pHdl = new XMLPMPropHdl_PaperTrayNumber; + break; + case XML_PM_TYPE_PRINTORIENTATION: + pHdl = new XMLNamedBoolPropertyHdl( + GetXMLToken( XML_LANDSCAPE ), + GetXMLToken( XML_PORTRAIT ) ); + break; + case XML_PM_TYPE_PRINTANNOTATIONS: + pHdl = new XMLPMPropHdl_Print( XML_ANNOTATIONS ); + break; + case XML_PM_TYPE_PRINTCHARTS: + pHdl = new XMLPMPropHdl_Print( XML_CHARTS ); + break; + case XML_PM_TYPE_PRINTDRAWING: + pHdl = new XMLPMPropHdl_Print( XML_DRAWINGS ); + break; + case XML_PM_TYPE_PRINTFORMULAS: + pHdl = new XMLPMPropHdl_Print( XML_FORMULAS ); + break; + case XML_PM_TYPE_PRINTGRID: + pHdl = new XMLPMPropHdl_Print( XML_GRID ); + break; + case XML_PM_TYPE_PRINTHEADERS: + pHdl = new XMLPMPropHdl_Print( XML_HEADERS ); + break; + case XML_PM_TYPE_PRINTOBJECTS: + pHdl = new XMLPMPropHdl_Print( XML_OBJECTS ); + break; + case XML_PM_TYPE_PRINTZEROVALUES: + pHdl = new XMLPMPropHdl_Print( XML_ZERO_VALUES ); + break; + case XML_PM_TYPE_PRINTPAGEORDER: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_TTB ), + GetXMLToken( XML_LTR ) ); + break; + case XML_PM_TYPE_FIRSTPAGENUMBER: + pHdl = new XMLNumberNonePropHdl( XML_CONTINUE, 2 ); + break; + case XML_PM_TYPE_CENTER_HORIZONTAL: + pHdl = new XMLPMPropHdl_CenterHorizontal; + break; + case XML_PM_TYPE_CENTER_VERTICAL: + pHdl = new XMLPMPropHdl_CenterVertical; + break; + case XML_TYPE_TEXT_COLUMNS: + pHdl = new XMLTextColumnsPropertyHandler; + break; + case XML_TYPE_LAYOUT_GRID_MODE: + pHdl = new XMLConstantsPropertyHandler( + aXML_TextGridMode_ConstantMap, XML_NONE ); + break; + + case XML_SW_TYPE_FILLSTYLE: + pHdl = new XMLEnumPropertyHdl( aXML_FillStyle_EnumMap ); + break; + case XML_SW_TYPE_PRESPAGE_BACKSIZE: + pHdl = new XMLNamedBoolPropertyHdl(GetXMLToken(XML_FULL), GetXMLToken(XML_BORDER)); + break; + case XML_SW_TYPE_FILLBITMAPSIZE: + pHdl = new XMLFillBitmapSizePropertyHandler(); + break; + case XML_SW_TYPE_LOGICAL_SIZE: + pHdl = new XMLBitmapLogicalSizePropertyHandler(); + break; + case XML_SW_TYPE_BITMAP_REFPOINT: + pHdl = new XMLEnumPropertyHdl( aXML_RefPoint_EnumMap ); + break; + case XML_SW_TYPE_BITMAP_MODE: + pHdl = new XMLEnumPropertyHdl( aXML_BitmapMode_EnumMap ); + break; + case XML_SW_TYPE_BITMAPREPOFFSETX: + case XML_SW_TYPE_BITMAPREPOFFSETY: + pHdl = new XMLBitmapRepeatOffsetPropertyHandler(XML_SW_TYPE_BITMAPREPOFFSETX == nType); + break; + case XML_SW_TYPE_RTLGUTTER: + pHdl = new XMLRtlGutterPropertyHandler(); + break; + + default: + { + OSL_ENSURE(false, "XMLPropertyHandler missing (!)"); + break; + } + } + + if( pHdl ) + PutHdlCache( nType, pHdl ); + } + return pHdl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterPropMapper.cxx b/xmloff/source/style/PageMasterPropMapper.cxx new file mode 100644 index 0000000000..c792ff0a0e --- /dev/null +++ b/xmloff/source/style/PageMasterPropMapper.cxx @@ -0,0 +1,48 @@ +/* -*- 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 <PageMasterPropMapper.hxx> + +#include <rtl/ref.hxx> +#include <PageMasterStyleMap.hxx> +#include <PageMasterPropHdlFactory.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +XMLPageMasterPropSetMapper::XMLPageMasterPropSetMapper(): + XMLPropertySetMapper( aXMLPageMasterStyleMap, new XMLPageMasterPropHdlFactory(), false/*bForExport*/) +{ +} + +XMLPageMasterPropSetMapper::XMLPageMasterPropSetMapper( + const XMLPropertyMapEntry* pEntries, + const rtl::Reference< XMLPropertyHandlerFactory >& rFactory ) : + XMLPropertySetMapper( pEntries, rFactory, true/*bForExport*/ ) +{ +} + +XMLPageMasterPropSetMapper::~XMLPageMasterPropSetMapper() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterStyleMap.cxx b/xmloff/source/style/PageMasterStyleMap.cxx new file mode 100644 index 0000000000..6f63128967 --- /dev/null +++ b/xmloff/source/style/PageMasterStyleMap.cxx @@ -0,0 +1,307 @@ +/* -*- 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 <PageMasterStyleMap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmlprop.hxx> + +using namespace ::xmloff::token; + +#define MAP(name,prefix,token,type,context,version) { name, prefix, token, type, context, version, false } +#define DPMAP(name,prefix,token,type,context) MAP(name, prefix, token, type|XML_TYPE_PROP_DRAWING_PAGE, context, SvtSaveOptions::ODFSVER_013) +#define PLMAP(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_PAGE_LAYOUT, context, SvtSaveOptions::ODFSVER_010) +#define PLMAP_12(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_PAGE_LAYOUT, context, SvtSaveOptions::ODFSVER_012) +#define PLMAP_ODF13(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_PAGE_LAYOUT, context, SvtSaveOptions::ODFSVER_013) +#define PLMAP_EXT(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_PAGE_LAYOUT, context, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED) +#define HFMAP(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_HEADER_FOOTER, context, SvtSaveOptions::ODFSVER_010) + + +const XMLPropertyMapEntry aXMLPageMasterStyleMap[] = +{ + ////////////////////////////////////////////////////////////////////////// + // Section for 'page-layout-properties' + + // page master + PLMAP( PROP_PageStyleLayout, XML_NAMESPACE_STYLE, XML_PAGE_USAGE, XML_PM_TYPE_PAGESTYLELAYOUT | MID_FLAG_SPECIAL_ITEM, CTF_PM_PAGEUSAGE ), + PLMAP( PROP_Width, XML_NAMESPACE_FO, XML_PAGE_WIDTH, XML_TYPE_MEASURE, 0 ), + PLMAP( PROP_Height, XML_NAMESPACE_FO, XML_PAGE_HEIGHT, XML_TYPE_MEASURE, 0 ), + PLMAP( PROP_NumberingType, XML_NAMESPACE_STYLE, XML_NUM_FORMAT, XML_PM_TYPE_NUMFORMAT | MID_FLAG_MERGE_PROPERTY, 0 ), + PLMAP( PROP_NumberingType, XML_NAMESPACE_STYLE, XML_NUM_LETTER_SYNC, XML_PM_TYPE_NUMLETTERSYNC, 0 ), + PLMAP( PROP_PrinterPaperTray, XML_NAMESPACE_STYLE, XML_PAPER_TRAY_NAME, XML_TYPE_STRING | MID_FLAG_PROPERTY_MAY_THROW, 0 ), + PLMAP( PROP_IsLandscape, XML_NAMESPACE_STYLE, XML_PRINT_ORIENTATION, XML_PM_TYPE_PRINTORIENTATION, 0 ), + PLMAP( PROP_TopMargin, XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_MEASURE, CTF_PM_MARGINALL ), + PLMAP( PROP_TopMargin, XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_TYPE_MEASURE, CTF_PM_MARGINTOP ), + PLMAP( PROP_BottomMargin, XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_TYPE_MEASURE, CTF_PM_MARGINBOTTOM ), + PLMAP( PROP_LeftMargin, XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, CTF_PM_MARGINLEFT ), + PLMAP( PROP_RightMargin, XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, CTF_PM_MARGINRIGHT ), + PLMAP( PROP_TopBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER, CTF_PM_BORDERALL ), + PLMAP( PROP_TopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, CTF_PM_BORDERTOP ), + PLMAP( PROP_BottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, CTF_PM_BORDERBOTTOM ), + PLMAP( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, CTF_PM_BORDERLEFT ), + PLMAP( PROP_RightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, CTF_PM_BORDERRIGHT ), + PLMAP( PROP_TopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHALL ), + PLMAP( PROP_TopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHTOP ), + PLMAP( PROP_BottomBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHBOTTOM ), + PLMAP( PROP_LeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHLEFT ), + PLMAP( PROP_RightBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHRIGHT ), + PLMAP( PROP_TopBorderDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE, CTF_PM_PADDINGALL ), + PLMAP( PROP_TopBorderDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE, CTF_PM_PADDINGTOP ), + PLMAP( PROP_BottomBorderDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE, CTF_PM_PADDINGBOTTOM ), + PLMAP( PROP_LeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE, CTF_PM_PADDINGLEFT ), + PLMAP( PROP_RightBorderDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE, CTF_PM_PADDINGRIGHT ), + PLMAP( PROP_ShadowFormat, XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW, 0 ), + PLMAP( PROP_BackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT | MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( PROP_BackTransparent, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT | MID_FLAG_MERGE_ATTRIBUTE, 0 ), + PLMAP( PROP_BackGraphicLocation, XML_NAMESPACE_STYLE, XML_POSITION, XML_TYPE_BUILDIN_CMP_ONLY | MID_FLAG_SPECIAL_ITEM, CTF_PM_GRAPHICPOSITION ), + PLMAP( PROP_BackGraphicFilter, XML_NAMESPACE_STYLE, XML_FILTER_NAME, XML_TYPE_STRING | MID_FLAG_SPECIAL_ITEM, CTF_PM_GRAPHICFILTER ), + PLMAP( PROP_BackGraphic, XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, CTF_PM_GRAPHICURL ), + PLMAP( PROP_PrintAnnotations, XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTANNOTATIONS | MID_FLAG_MULTI_PROPERTY, CTF_PM_PRINT_ANNOTATIONS ), + PLMAP( PROP_PrintCharts, XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTCHARTS | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_CHARTS ), + PLMAP( PROP_PrintDrawing, XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTDRAWING | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_DRAWING ), + PLMAP( PROP_PrintFormulas, XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTFORMULAS | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_FORMULAS ), + PLMAP( PROP_PrintGrid, XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTGRID | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_GRID ), + PLMAP( PROP_PrintHeaders, XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTHEADERS | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_HEADERS ), + PLMAP( PROP_PrintObjects, XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTOBJECTS | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_OBJECTS ), + PLMAP( PROP_PrintZeroValues, XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTZEROVALUES | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_ZEROVALUES ), + PLMAP( PROP_PrintDownFirst, XML_NAMESPACE_STYLE, XML_PRINT_PAGE_ORDER, XML_PM_TYPE_PRINTPAGEORDER, 0 ), + PLMAP( PROP_FirstPageNumber, XML_NAMESPACE_STYLE, XML_FIRST_PAGE_NUMBER, XML_PM_TYPE_FIRSTPAGENUMBER, 0 ), + PLMAP( PROP_PageScale, XML_NAMESPACE_STYLE, XML_SCALE_TO, XML_TYPE_PERCENT16, CTF_PM_SCALETO ), + PLMAP( PROP_ScaleToPages, XML_NAMESPACE_STYLE, XML_SCALE_TO_PAGES, XML_TYPE_NUMBER16, CTF_PM_SCALETOPAGES ), + // ODF 1.3 OFFICE-3857 + PLMAP_ODF13( PROP_ScaleToPagesX, XML_NAMESPACE_STYLE, XML_SCALE_TO_X, XML_TYPE_NUMBER16, CTF_PM_SCALETOX ), + PLMAP_ODF13( PROP_ScaleToPagesY, XML_NAMESPACE_STYLE, XML_SCALE_TO_Y, XML_TYPE_NUMBER16, CTF_PM_SCALETOY ), + PLMAP_ODF13( PROP_ScaleToPagesX, XML_NAMESPACE_LO_EXT, XML_SCALE_TO_X, XML_TYPE_NUMBER16, CTF_PM_SCALETOX ), + PLMAP_ODF13( PROP_ScaleToPagesY, XML_NAMESPACE_LO_EXT, XML_SCALE_TO_Y, XML_TYPE_NUMBER16, CTF_PM_SCALETOY ), + PLMAP( PROP_CenterHorizontally, XML_NAMESPACE_STYLE, XML_TABLE_CENTERING, XML_PM_TYPE_CENTER_HORIZONTAL | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, 0 ), + PLMAP( PROP_CenterVertically, XML_NAMESPACE_STYLE, XML_TABLE_CENTERING, XML_PM_TYPE_CENTER_VERTICAL | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, 0 ), + PLMAP( PROP_TextColumns, XML_NAMESPACE_STYLE, XML_COLUMNS, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_COLUMNS, CTF_PM_TEXTCOLUMNS ), + PLMAP( PROP_RegisterModeActive, XML_NAMESPACE_STYLE, XML_REGISTER_TRUE, XML_TYPE_BOOL, 0 ), + PLMAP( PROP_RegisterParagraphStyle, XML_NAMESPACE_STYLE, XML_REGISTER_TRUTH_REF_STYLE_NAME, XML_TYPE_STYLENAME| MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_PM_REGISTER_STYLE ), + PLMAP( PROP_WritingMode, XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE | MID_FLAG_MULTI_PROPERTY, CTF_PM_WRITINGMODE ), + PLMAP( PROP_RtlGutter, XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_SW_TYPE_RTLGUTTER | MID_FLAG_MULTI_PROPERTY, CTF_PM_RTLGUTTER ), + + // Index 53: Grid definitions + PLMAP( PROP_GridColor, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_COLOR, XML_TYPE_COLOR, 0 ), + PLMAP( PROP_GridLines, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_LINES, XML_TYPE_NUMBER16, 0 ), + PLMAP( PROP_GridBaseHeight, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_BASE_HEIGHT, XML_TYPE_MEASURE, 0 ), + PLMAP( PROP_GridRubyHeight, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_RUBY_HEIGHT, XML_TYPE_MEASURE, 0 ), + PLMAP( PROP_GridMode, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_MODE, XML_TYPE_LAYOUT_GRID_MODE, 0 ), + PLMAP( PROP_RubyBelow, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_RUBY_BELOW, XML_TYPE_BOOL, 0 ), + PLMAP( PROP_GridPrint, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_PRINT, XML_TYPE_BOOL, 0 ), + PLMAP( PROP_GridDisplay, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_DISPLAY, XML_TYPE_BOOL, 0 ), + + //text grid enhancement for better CJK support + PLMAP_12( PROP_GridBaseWidth, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_BASE_WIDTH, XML_TYPE_MEASURE, CTP_PM_GRID_BASE_WIDTH ), + PLMAP_12( PROP_GridSnapToChars, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_SNAP_TO, XML_TYPE_BOOL, CTP_PM_GRID_SNAP_TO ), + //export as a default attribute + PLMAP_12( PROP_StandardPageMode, XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_STANDARD_MODE, XML_TYPE_BOOL|MID_FLAG_DEFAULT_ITEM_EXPORT, CTF_PM_STANDARD_MODE ), + + PLMAP( PROP_UserDefinedAttributes, XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + + //Index 65: fill attributes; use PLMAP macro here instead of GMAP, this list is ordered and its order is used + // to decide in which section in ODF to export the contained stuff (the PageMasterStyle creates several XML + // sections, for Page, Header and Footer). The needed order seems to rely not on filtering, but using sections + // based on the order used in this list. + // Also need own defines for the used context flags (e.g. CTF_PM_FILLGRADIENTNAME instead of + // CTF_FILLGRADIENTNAME) since these are used to *filter* up to which entry the attributes belong to the + // 'page-layout-properties' section (!), see SvXMLAutoStylePoolP_Impl::exportXML, look for XmlStyleFamily::PAGE_MASTER + // note: these are duplicated below, in g_XMLPageMasterDrawingPageStyleMap + PLMAP( PROP_FillStyle, XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, 0 ), + PLMAP( PROP_FillColor, XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0 ), + PLMAP( PROP_FillColor2, XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0 ), + PLMAP( PROP_FillGradientName, XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLGRADIENTNAME ), + PLMAP( PROP_FillGradientStepCount, XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0 ), + PLMAP( PROP_FillHatchName, XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLHATCHNAME ), + PLMAP( PROP_FillBackground, XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + PLMAP( PROP_FillBitmapName, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLBITMAPNAME ), + PLMAP( PROP_FillTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + PLMAP( PROP_FillTransparenceGradientName, XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLTRANSNAME ), + PLMAP( PROP_FillBitmapSizeX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( PROP_FillBitmapSizeY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( PROP_FillBitmapMode, XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FILLBITMAPMODE ), + PLMAP( PROP_FillBitmapPositionOffsetX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + PLMAP( PROP_FillBitmapPositionOffsetY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + PLMAP( PROP_FillBitmapRectanglePoint, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, 0 ), + PLMAP( PROP_FillBitmapOffsetX, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_PM_REPEAT_OFFSET_X ), + PLMAP( PROP_FillBitmapOffsetY, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_PM_REPEAT_OFFSET_Y ), + + // Index 85: footnote + PLMAP( PROP_FootnoteHeight, XML_NAMESPACE_STYLE, XML_FOOTNOTE_MAX_HEIGHT, XML_TYPE_MEASURE, CTF_PM_FTN_HEIGHT ), + PLMAP( PROP_FootnoteLineAdjust, XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_TEXT_HORIZONTAL_ADJUST|MID_FLAG_SPECIAL_ITEM, CTF_PM_FTN_LINE_ADJUST ), + PLMAP( PROP_FootnoteLineColor, XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_COLOR|MID_FLAG_SPECIAL_ITEM, CTF_PM_FTN_LINE_COLOR ), + PLMAP( PROP_FootnoteLineDistance, XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM,CTF_PM_FTN_DISTANCE ), + PLMAP( PROP_FootnoteLineRelativeWidth, XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_PERCENT8|MID_FLAG_SPECIAL_ITEM, CTF_PM_FTN_LINE_WIDTH ), + PLMAP( PROP_FootnoteLineTextDistance, XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM, CTF_PM_FTN_LINE_DISTANCE ), + PLMAP( PROP_FootnoteLineWeight, XML_NAMESPACE_STYLE, XML_FOOTNOTE_SEP, XML_TYPE_MEASURE16|MID_FLAG_ELEMENT_ITEM, CTF_PM_FTN_LINE_WEIGHT ), + PLMAP( PROP_FootnoteLineStyle, XML_NAMESPACE_STYLE, XML_TOKEN_EMPTY, XML_TYPE_STRING|MID_FLAG_ELEMENT_ITEM, CTF_PM_FTN_LINE_STYLE ), + PLMAP_EXT(PROP_GutterMargin, XML_NAMESPACE_LO_EXT, XML_MARGIN_GUTTER, XML_TYPE_MEASURE, CTF_PM_MARGINGUTTER), + + ////////////////////////////////////////////////////////////////////////// + //Index 92: Section for 'header-style' own section, all members *have* to use CTF_PM_HEADERFLAG in the context entry (the 5th one) + HFMAP( PROP_HeaderHeight, XML_NAMESPACE_SVG, XML_HEIGHT, XML_TYPE_MEASURE, CTF_PM_HEADERHEIGHT ), + HFMAP( PROP_HeaderHeight, XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_TYPE_MEASURE, CTF_PM_HEADERMINHEIGHT ), + HFMAP( PROP_HeaderIsDynamicHeight, XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_BOOL, CTF_PM_HEADERDYNAMIC ), + HFMAP( PROP_HeaderLeftMargin, XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_MEASURE, CTF_PM_HEADERMARGINALL ), + HFMAP( PROP_HeaderLeftMargin, XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, CTF_PM_HEADERMARGINLEFT ), + HFMAP( PROP_HeaderRightMargin, XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, CTF_PM_HEADERMARGINRIGHT ), + HFMAP( PROP_HeaderBodyDistance, XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_TYPE_MEASURE, CTF_PM_HEADERMARGINBOTTOM ), + HFMAP( PROP_HeaderTopBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER, CTF_PM_HEADERBORDERALL ), + HFMAP( PROP_HeaderTopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, CTF_PM_HEADERBORDERTOP ), + HFMAP( PROP_HeaderBottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, CTF_PM_HEADERBORDERBOTTOM ), + HFMAP( PROP_HeaderLeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, CTF_PM_HEADERBORDERLEFT ), + HFMAP( PROP_HeaderRightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, CTF_PM_HEADERBORDERRIGHT ), + HFMAP( PROP_HeaderTopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHALL ), + HFMAP( PROP_HeaderTopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHTOP ), + HFMAP( PROP_HeaderBottomBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHBOTTOM ), + HFMAP( PROP_HeaderLeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHLEFT ), + HFMAP( PROP_HeaderRightBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHRIGHT ), + HFMAP( PROP_HeaderTopBorderDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGALL ), + HFMAP( PROP_HeaderTopBorderDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGTOP ), + HFMAP( PROP_HeaderBottomBorderDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGBOTTOM ), + HFMAP( PROP_HeaderLeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGLEFT ), + HFMAP( PROP_HeaderRightBorderDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGRIGHT ), + HFMAP( PROP_HeaderShadowFormat, XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderBackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT | MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderBackTransparent, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderBackGraphicLocation, XML_NAMESPACE_STYLE, XML_POSITION, XML_TYPE_BUILDIN_CMP_ONLY | MID_FLAG_SPECIAL_ITEM, CTF_PM_HEADERGRAPHICPOSITION ), + HFMAP( PROP_HeaderBackGraphicFilter, XML_NAMESPACE_STYLE, XML_FILTER_NAME, XML_TYPE_STRING | MID_FLAG_SPECIAL_ITEM, CTF_PM_HEADERGRAPHICFILTER ), + HFMAP( PROP_HeaderBackGraphic, XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, CTF_PM_HEADERGRAPHICURL ), + HFMAP( PROP_HeaderDynamicSpacing, XML_NAMESPACE_STYLE, XML_DYNAMIC_SPACING, XML_TYPE_BOOL, CTF_PM_HEADERFLAG ), + + //Index 121: Header DrawingLayer FillAttributes + // Use HFMAP to get XML_TYPE_PROP_HEADER_FOOTER ORed to the 4th entry + // Names have to begin with 'Header', all 5th entries need to be ORed with the CTF_PM_HEADERFLAG + HFMAP( PROP_HeaderFillStyle, XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillColor, XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillColor2, XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillGradientName, XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_HEADERFILLGRADIENTNAME ), + HFMAP( PROP_HeaderFillGradientStepCount, XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillHatchName, XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_HEADERFILLHATCHNAME ), + HFMAP( PROP_HeaderFillBackground, XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapName, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_HEADERFILLBITMAPNAME ), + HFMAP( PROP_HeaderFillTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), // exists in SW, too + HFMAP( PROP_HeaderFillTransparenceGradientName, XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_HEADERFILLTRANSNAME ), + HFMAP( PROP_HeaderFillBitmapSizeX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapSizeY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapMode, XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapPositionOffsetX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapPositionOffsetY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapRectanglePoint, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, CTF_PM_HEADERFLAG ), + HFMAP( PROP_HeaderFillBitmapOffsetX, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERREPEAT_OFFSET_X ), + HFMAP( PROP_HeaderFillBitmapOffsetY, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERREPEAT_OFFSET_Y ), + + ////////////////////////////////////////////////////////////////////////// + //Index 141: Section for 'footer-style' own section, all members *have* to use CTF_PM_FOOTERFLAG in the context entry (the 5th one) + HFMAP( PROP_FooterHeight, XML_NAMESPACE_SVG, XML_HEIGHT, XML_TYPE_MEASURE, CTF_PM_FOOTERHEIGHT ), + HFMAP( PROP_FooterHeight, XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_TYPE_MEASURE, CTF_PM_FOOTERMINHEIGHT ), + HFMAP( PROP_FooterIsDynamicHeight, XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_BOOL, CTF_PM_FOOTERDYNAMIC ), + HFMAP( PROP_FooterLeftMargin, XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_MEASURE, CTF_PM_FOOTERMARGINALL ), + HFMAP( PROP_FooterLeftMargin, XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, CTF_PM_FOOTERMARGINLEFT ), + HFMAP( PROP_FooterRightMargin, XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, CTF_PM_FOOTERMARGINRIGHT ), + HFMAP( PROP_FooterBodyDistance, XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_TYPE_MEASURE, CTF_PM_FOOTERMARGINTOP ), + HFMAP( PROP_FooterTopBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERALL ), + HFMAP( PROP_FooterTopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERTOP ), + HFMAP( PROP_FooterBottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERBOTTOM ), + HFMAP( PROP_FooterLeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERLEFT ), + HFMAP( PROP_FooterRightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERRIGHT ), + HFMAP( PROP_FooterTopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHALL ), + HFMAP( PROP_FooterTopBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHTOP ), + HFMAP( PROP_FooterBottomBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHBOTTOM ), + HFMAP( PROP_FooterLeftBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHLEFT ), + HFMAP( PROP_FooterRightBorder, XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHRIGHT ), + HFMAP( PROP_FooterTopBorderDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGALL ), + HFMAP( PROP_FooterTopBorderDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGTOP ), + HFMAP( PROP_FooterBottomBorderDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGBOTTOM ), + HFMAP( PROP_FooterLeftBorderDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGLEFT ), + HFMAP( PROP_FooterRightBorderDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGRIGHT ), + HFMAP( PROP_FooterShadowFormat, XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterBackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT | MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterBackTransparent, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterBackGraphicLocation, XML_NAMESPACE_STYLE, XML_POSITION, XML_TYPE_BUILDIN_CMP_ONLY | MID_FLAG_SPECIAL_ITEM, CTF_PM_FOOTERGRAPHICPOSITION ), + HFMAP( PROP_FooterBackGraphicFilter, XML_NAMESPACE_STYLE, XML_FILTER_NAME, XML_TYPE_STRING | MID_FLAG_SPECIAL_ITEM, CTF_PM_FOOTERGRAPHICFILTER ), + HFMAP( PROP_FooterBackGraphic, XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, CTF_PM_FOOTERGRAPHICURL ), + HFMAP( PROP_FooterDynamicSpacing, XML_NAMESPACE_STYLE, XML_DYNAMIC_SPACING, XML_TYPE_BOOL, CTF_PM_FOOTERFLAG ), + + //Index 170: Footer DrawingLayer FillAttributes + // Use HFMAP to get XML_TYPE_PROP_HEADER_FOOTER ORed to the 4th entry + // Names have to begin with 'Footer', all 5th entries need to be ORed with the CTF_PM_FOOTERFLAG + HFMAP( PROP_FooterFillStyle, XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillColor, XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillColor2, XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillGradientName, XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FOOTERFILLGRADIENTNAME ), + HFMAP( PROP_FooterFillGradientStepCount, XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillHatchName, XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FOOTERFILLHATCHNAME ), + HFMAP( PROP_FooterFillBackground, XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapName, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FOOTERFILLBITMAPNAME ), + HFMAP( PROP_FooterFillTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), // exists in SW, too + HFMAP( PROP_FooterFillTransparenceGradientName, XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FOOTERFILLTRANSNAME ), + HFMAP( PROP_FooterFillBitmapSizeX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapSizeY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapMode, XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapPositionOffsetX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapPositionOffsetY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapRectanglePoint, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, CTF_PM_FOOTERFLAG ), + HFMAP( PROP_FooterFillBitmapOffsetX, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERREPEAT_OFFSET_X ), + HFMAP( PROP_FooterFillBitmapOffsetY, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERREPEAT_OFFSET_Y ), + + { nullptr } // index 190 +}; + +XMLPropertyMapEntry const g_XMLPageMasterDrawingPageStyleMap[] = +{ + // ODF 1.3 OFFICE-3937 style of family "drawing-page" referenced from style:master-page + // duplication of relevant part of aXMLPageMasterStyleMap but as DP type + DPMAP( PROP_FillStyle, XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, CTF_PM_FILL), + DPMAP( PROP_BackgroundFullSize, XML_NAMESPACE_DRAW, XML_BACKGROUND_SIZE, XML_SW_TYPE_PRESPAGE_BACKSIZE, CTF_PM_BACKGROUNDSIZE), + DPMAP( PROP_FillColor, XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0), + DPMAP( PROP_FillColor2, XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0), + DPMAP( PROP_FillGradientName, XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLGRADIENTNAME), + DPMAP( PROP_FillGradientStepCount, XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0), + DPMAP( PROP_FillHatchName, XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLHATCHNAME), + DPMAP( PROP_FillBackground, XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0), + DPMAP( PROP_FillBitmapName, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLBITMAPNAME), + DPMAP( PROP_FillTransparence, XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0), /* exists in SW, too */ + DPMAP( PROP_FillTransparenceGradientName, XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLTRANSNAME), + DPMAP( PROP_FillBitmapSizeX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0), + DPMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0), + DPMAP( PROP_FillBitmapSizeY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0), + DPMAP( PROP_FillBitmapLogicalSize, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0), + DPMAP( PROP_FillBitmapMode, XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FILLBITMAPMODE), + DPMAP( PROP_FillBitmapPositionOffsetX, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0), + DPMAP( PROP_FillBitmapPositionOffsetY, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0), + DPMAP( PROP_FillBitmapRectanglePoint, XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, 0), + DPMAP( PROP_FillBitmapOffsetX, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_PM_REPEAT_OFFSET_X), + DPMAP( PROP_FillBitmapOffsetY, XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_PM_REPEAT_OFFSET_Y), + + { nullptr } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PagePropertySetContext.cxx b/xmloff/source/style/PagePropertySetContext.cxx new file mode 100644 index 0000000000..583a5d14c3 --- /dev/null +++ b/xmloff/source/style/PagePropertySetContext.cxx @@ -0,0 +1,117 @@ +/* -*- 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 <tools/debug.hxx> +#include "PagePropertySetContext.hxx" +#include <XMLBackgroundImageContext.hxx> +#include <XMLTextColumnsContext.hxx> +#include <PageMasterStyleMap.hxx> +#include "XMLFootnoteSeparatorImport.hxx" +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlprmap.hxx> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +PagePropertySetContext::PagePropertySetContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_uInt32 nFam, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + sal_Int32 nStartIndex, sal_Int32 nEndIndex, + const PageContextType aTempType ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, nFam, + rProps, rMap, nStartIndex, nEndIndex ) +{ + aType = aTempType; +} + +PagePropertySetContext::~PagePropertySetContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > PagePropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + sal_Int32 nPos = CTF_PM_GRAPHICPOSITION; + sal_Int32 nFil = CTF_PM_GRAPHICFILTER; + switch ( aType ) + { + case Header: + { + nPos = CTF_PM_HEADERGRAPHICPOSITION; + nFil = CTF_PM_HEADERGRAPHICFILTER; + } + break; + case Footer: + { + nPos = CTF_PM_FOOTERGRAPHICPOSITION; + nFil = CTF_PM_FOOTERGRAPHICFILTER; + } + break; + default: + break; + } + + switch( mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_PM_GRAPHICURL: + case CTF_PM_HEADERGRAPHICURL: + case CTF_PM_FOOTERGRAPHICURL: + DBG_ASSERT( rProp.mnIndex >= 2 && + nPos == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-2 ) && + nFil == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-1 ), + "invalid property map!"); + return + new XMLBackgroundImageContext( GetImport(), nElement, + xAttrList, + rProp, + rProp.mnIndex-2, + rProp.mnIndex-1, + -1, + mxMapper->getPropertySetMapper()->FindEntryIndex(CTF_PM_FILLBITMAPMODE), + rProperties ); + break; + + case CTF_PM_TEXTCOLUMNS: + return new XMLTextColumnsContext(GetImport(), nElement, xAttrList, rProp, rProperties); + break; + + case CTF_PM_FTN_LINE_WEIGHT: + return new XMLFootnoteSeparatorImport( + GetImport(), nElement, rProperties, + mxMapper->getPropertySetMapper(), rProp.mnIndex); + break; + } + + return SvXMLPropertySetContext::createFastChildContext( nElement, + xAttrList, + rProperties, rProp ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PagePropertySetContext.hxx b/xmloff/source/style/PagePropertySetContext.hxx new file mode 100644 index 0000000000..2429dc1947 --- /dev/null +++ b/xmloff/source/style/PagePropertySetContext.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprcon.hxx> + +enum PageContextType +{ + Page, + Header, + Footer +}; + +class PagePropertySetContext : public SvXMLPropertySetContext +{ + PageContextType aType; + +public: + PagePropertySetContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + sal_uInt32 nFam, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + sal_Int32 nStartIndex, sal_Int32 nEndIndex, + const PageContextType aType ); + + virtual ~PagePropertySetContext() override; + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/SinglePropertySetInfoCache.cxx b/xmloff/source/style/SinglePropertySetInfoCache.cxx new file mode 100644 index 0000000000..be81c02c8e --- /dev/null +++ b/xmloff/source/style/SinglePropertySetInfoCache.cxx @@ -0,0 +1,54 @@ +/* -*- 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 <cppuhelper/weakref.hxx> +#include <xmloff/SinglePropertySetInfoCache.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::com::sun::star::uno; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XPropertySetInfo; + +bool SinglePropertySetInfoCache::hasProperty( + const Reference< XPropertySet >& rPropSet, + Reference< XPropertySetInfo >& rPropSetInfo ) +{ + if( !rPropSetInfo.is() ) + rPropSetInfo = rPropSet->getPropertySetInfo(); + Map::iterator aIter = m_Map.find( rPropSetInfo ); + if( aIter != m_Map.end() ) + { + return (*aIter).second; + } + bool bRet = rPropSetInfo->hasPropertyByName( m_sName ); + // Check whether the property set info is destroyed if it is assigned to a + // weak reference only; if it is destroyed, then every instance of + // getPropertySetInfo returns a new object; Such property set infos must not + // be cached: + WeakReference < XPropertySetInfo > xWeakInfo( rPropSetInfo ); + rPropSetInfo = nullptr; + rPropSetInfo = xWeakInfo; + if( rPropSetInfo.is() ) + { + m_Map.emplace(rPropSetInfo, bRet); + } + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/StyleMap.cxx b/xmloff/source/style/StyleMap.cxx new file mode 100644 index 0000000000..cb7acfb33d --- /dev/null +++ b/xmloff/source/style/StyleMap.cxx @@ -0,0 +1,29 @@ +/* -*- 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 <StyleMap.hxx> + +using namespace css::uno; +using namespace css::lang; + +StyleMap::StyleMap() {} + +StyleMap::~StyleMap() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/StylePropertiesContext.cxx b/xmloff/source/style/StylePropertiesContext.cxx new file mode 100644 index 0000000000..910b7873d5 --- /dev/null +++ b/xmloff/source/style/StylePropertiesContext.cxx @@ -0,0 +1,45 @@ +/* -*- 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/. + */ + +#include "StylePropertiesContext.hxx" + +#include <tools/debug.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/xmlimp.hxx> + +#include <xmloff/XMLComplexColorContext.hxx> + +using namespace xmloff::token; + +StylePropertiesContext::StylePropertiesContext( + SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, sal_uInt32 nFamily, + std::vector<XMLPropertyState>& rProps, const rtl::Reference<SvXMLImportPropertyMapper>& rMap) + : SvXMLPropertySetContext(rImport, nElement, xAttrList, nFamily, rProps, rMap) +{ +} + +StylePropertiesContext::~StylePropertiesContext() {} + +css::uno::Reference<css::xml::sax::XFastContextHandler> +StylePropertiesContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, + std::vector<XMLPropertyState>& rProperties, const XMLPropertyState& rProperty) +{ + if (nElement == XML_ELEMENT(LO_EXT, XML_CHAR_COMPLEX_COLOR)) + { + return new XMLPropertyComplexColorContext(GetImport(), nElement, xAttrList, rProperty, + rProperties); + } + return SvXMLPropertySetContext::createFastChildContext(nElement, xAttrList, rProperties, + rProperty); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/StylePropertiesContext.hxx b/xmloff/source/style/StylePropertiesContext.hxx new file mode 100644 index 0000000000..6fa3ef8703 --- /dev/null +++ b/xmloff/source/style/StylePropertiesContext.hxx @@ -0,0 +1,31 @@ +/* -*- 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/. + */ + +#pragma once + +#include <xmloff/xmlprcon.hxx> + +class StylePropertiesContext : public SvXMLPropertySetContext +{ +public: + StylePropertiesContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, + sal_uInt32 nFamily, std::vector<XMLPropertyState>& rProps, + const rtl::Reference<SvXMLImportPropertyMapper>& rMap); + + virtual ~StylePropertiesContext() override; + + using SvXMLPropertySetContext::createFastChildContext; + + virtual css::uno::Reference<css::xml::sax::XFastContextHandler> createFastChildContext( + sal_Int32 nElement, const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, + std::vector<XMLPropertyState>& rProperties, const XMLPropertyState& rProperty) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/TransGradientStyle.cxx b/xmloff/source/style/TransGradientStyle.cxx new file mode 100644 index 0000000000..74b7670c02 --- /dev/null +++ b/xmloff/source/style/TransGradientStyle.cxx @@ -0,0 +1,285 @@ +/* -*- 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 <TransGradientStyle.hxx> + +#include <com/sun/star/awt/Gradient2.hpp> + +#include <basegfx/utils/bgradient.hxx> +#include <comphelper/documentconstants.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> +#include <tools/color.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmluconv.hxx> +#include <docmodel/uno/UnoGradientTools.hxx> + +using namespace ::com::sun::star; + +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<awt::GradientStyle> const pXML_GradientStyle_Enum[] = +{ + { XML_LINEAR, awt::GradientStyle_LINEAR }, + { XML_GRADIENTSTYLE_AXIAL, awt::GradientStyle_AXIAL }, + { XML_GRADIENTSTYLE_RADIAL, awt::GradientStyle_RADIAL }, + { XML_GRADIENTSTYLE_ELLIPSOID, awt::GradientStyle_ELLIPTICAL }, + { XML_GRADIENTSTYLE_SQUARE, awt::GradientStyle_SQUARE }, + { XML_GRADIENTSTYLE_RECTANGULAR, awt::GradientStyle_RECT }, + { XML_TOKEN_INVALID, awt::GradientStyle(0) } +}; + +// Import + +XMLTransGradientStyleImport::XMLTransGradientStyleImport( SvXMLImport& rImp ) + : rImport(rImp) +{ +} + +void XMLTransGradientStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + OUString aDisplayName; + + awt::Gradient2 aGradient; + aGradient.XOffset = 0; + aGradient.YOffset = 0; + aGradient.StartIntensity = 100; + aGradient.EndIntensity = 100; + aGradient.Angle = 0; + aGradient.Border = 0; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + sal_Int32 nTmpValue; + + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + { + rStrName = aIter.toString(); + } + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + { + aDisplayName = aIter.toString(); + } + break; + case XML_ELEMENT(DRAW, XML_STYLE): + { + SvXMLUnitConverter::convertEnum( aGradient.Style, aIter.toView(), pXML_GradientStyle_Enum ); + } + break; + case XML_ELEMENT(DRAW, XML_CX): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.XOffset = sal::static_int_cast< sal_Int16 >(nTmpValue); + break; + case XML_ELEMENT(DRAW, XML_CY): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.YOffset = sal::static_int_cast< sal_Int16 >(nTmpValue); + break; + case XML_ELEMENT(DRAW, XML_START): + { + sal_Int32 aStartTransparency; + ::sax::Converter::convertPercent( aStartTransparency, aIter.toView() ); + + sal_uInt8 n = sal::static_int_cast< sal_uInt8 >( + ( (100 - aStartTransparency) * 255 ) / 100 ); + + Color aColor( n, n, n ); + aGradient.StartColor = static_cast<sal_Int32>( aColor ); + } + break; + case XML_ELEMENT(DRAW, XML_END): + { + sal_Int32 aEndTransparency; + ::sax::Converter::convertPercent( aEndTransparency, aIter.toView() ); + + sal_uInt8 n = sal::static_int_cast< sal_uInt8 >( + ( (100 - aEndTransparency) * 255 ) / 100 ); + + Color aColor( n, n, n ); + aGradient.EndColor = static_cast<sal_Int32>( aColor ); + } + break; + case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE): + { + auto const cmp12(rImport.GetODFVersion().compareTo(ODFVER_012_TEXT)); + bool const bSuccess = + ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(), + // tdf#89475 try to detect borked OOo angles + (cmp12 < 0) || (cmp12 == 0 + && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle"); + } + break; + case XML_ELEMENT(DRAW, XML_BORDER): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.Border = sal::static_int_cast< sal_Int16 >(nTmpValue); + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + rValue <<= aGradient; + + if( !aDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName, + aDisplayName ); + rStrName = aDisplayName; + } +} + +// Export + +XMLTransGradientStyleExport::XMLTransGradientStyleExport( SvXMLExport& rExp ) + : rExport(rExp) +{ +} + +void XMLTransGradientStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + // MCGR: We try to write the gradient so, that applications without multi-color gradient support + // can render it as best as possible. + // This is similar to XMLGradientStyleExport::exportXML(). For details see there. + if( rStrName.isEmpty() ) + return; + if (!rValue.has<css::awt::Gradient2>() && !rValue.has<css::awt::Gradient>()) + return; + + basegfx::BGradient aGradient = model::gradient::getFromAny(rValue); + + aGradient.tryToConvertToAxial(); + + aGradient.tryToRecreateBorder(nullptr); + + OUString aStrValue; + OUStringBuffer aOut; + + // Style + if (!SvXMLUnitConverter::convertEnum(aOut, aGradient.GetGradientStyle(), + pXML_GradientStyle_Enum)) + return; + + // Name + bool bEncoded = false; + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + rExport.EncodeStyleName( rStrName, + &bEncoded ) ); + if( bEncoded ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + rStrName ); + + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + + // Center x/y + if (awt::GradientStyle_LINEAR != aGradient.GetGradientStyle() + && awt::GradientStyle_AXIAL != aGradient.GetGradientStyle()) + { + ::sax::Converter::convertPercent(aOut, aGradient.GetXOffset()); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue ); + + ::sax::Converter::convertPercent(aOut, aGradient.GetYOffset()); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue ); + } + + // LO uses a gray color as transparency. ODF uses opacity in range [0%,100%]. + // Default 100% opacity. + double fOpacityStartPerc = 100.0; + double fOpacityEndPerc = 100.0; + if (!aGradient.GetColorStops().empty()) + { + fOpacityStartPerc + = (1.0 - aGradient.GetColorStops().front().getStopColor().getRed()) * 100.0; + fOpacityEndPerc = (1.0 - aGradient.GetColorStops().back().getStopColor().getRed()) * 100.0; + } + + // Opacity start + ::sax::Converter::convertPercent(aOut, static_cast<sal_Int32>(std::lround(fOpacityStartPerc))); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START, aStrValue ); + + // Opacity end + ::sax::Converter::convertPercent( aOut, static_cast<sal_Int32>(std::lround(fOpacityEndPerc))); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END, aStrValue ); + + // Angle + if (awt::GradientStyle_RADIAL != aGradient.GetGradientStyle()) + { + ::sax::Converter::convertAngle(aOut, aGradient.GetAngle().get(), + rExport.getSaneDefaultVersion()); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); + } + + // Border + ::sax::Converter::convertPercent(aOut, aGradient.GetBorder()); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); + + // ctor writes start tag. End-tag is written by destructor at block end. + SvXMLElementExport rElem(rExport, XML_NAMESPACE_DRAW, XML_OPACITY, true, false); + + // Write child elements <loext:opacity-stop> + // Do not export in standard ODF 1.3 or older. + if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + return; + if (aGradient.GetColorStops().empty()) + return; + + double fPreviousOffset = 0.0; + for (auto& aCandidate : aGradient.GetColorStops()) + { + // Attribute svg:offset. Make sure offsets are increasing. + double fOffset = std::clamp<double>(aCandidate.getStopOffset(), 0.0, 1.0); + if (fOffset < fPreviousOffset) + fOffset = fPreviousOffset; + rExport.AddAttribute(XML_NAMESPACE_SVG, XML_OFFSET, OUString::number(fOffset)); + fPreviousOffset = fOffset; + + // Attribute svg:stop-opacity, data type zeroToOneDecimal + double fOpacity = std::clamp<double>(1.0 - aCandidate.getStopColor().getRed(), 0.0, 1.0); + rExport.AddAttribute(XML_NAMESPACE_SVG, XML_STOP_OPACITY, OUString::number(fOpacity)); + + // write opacity stop element + SvXMLElementExport aStopElement(rExport, XML_NAMESPACE_LO_EXT, XML_OPACITY_STOP, true, true); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/WordWrapPropertyHdl.cxx b/xmloff/source/style/WordWrapPropertyHdl.cxx new file mode 100644 index 0000000000..0a01bd11dd --- /dev/null +++ b/xmloff/source/style/WordWrapPropertyHdl.cxx @@ -0,0 +1,88 @@ +/* -*- 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 <xmloff/xmlimp.hxx> +#include <WordWrapPropertyHdl.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <comphelper/extract.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Any.hxx> + +using namespace ::com::sun::star::uno; + + + + +XMLWordWrapPropertyHdl::XMLWordWrapPropertyHdl( SvXMLImport* pImport ) +: mpImport( pImport ) +{ +} + +XMLWordWrapPropertyHdl::~XMLWordWrapPropertyHdl() +{ + // Nothing to do +} + +bool XMLWordWrapPropertyHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRetValue = false; + bool bValue = false; + if( rStrImpValue == GetXMLToken( xmloff::token::XML_WRAP ) ) + { + bValue = true; + bRetValue = true; + } + if( rStrImpValue == GetXMLToken( xmloff::token::XML_NO_WRAP ) ) + { + bValue = false; + bRetValue = true; + } + if ( bRetValue && mpImport ) + { + sal_Int32 nUPD, nBuildId; + if( mpImport->getBuildIds( nUPD, nBuildId ) ) + { + if( nUPD == 300 ) + { + if( ( nBuildId > 0 ) && (nBuildId < 9316 ) ) + bValue = !bValue; // treat OOo 3.0 beta1 as OOo 2.x + } + else if( ( nUPD == 680 ) || ( nUPD >= 640 && nUPD <= 645 ) ) + bValue = !bValue; + } + rValue <<= bValue; + } + return bRetValue; +} + +bool XMLWordWrapPropertyHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + if( ::cppu::any2bool( rValue ) ) + { + rStrExpValue = GetXMLToken( xmloff::token::XML_WRAP ); + } + else + { + rStrExpValue = GetXMLToken( xmloff::token::XML_NO_WRAP ); + } + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLBackgroundImageContext.cxx b/xmloff/source/style/XMLBackgroundImageContext.cxx new file mode 100644 index 0000000000..cd500672c6 --- /dev/null +++ b/xmloff/source/style/XMLBackgroundImageContext.cxx @@ -0,0 +1,397 @@ +/* -*- 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 <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> + +#include <tools/debug.hxx> +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> + +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/XMLBase64ImportContext.hxx> +#include <XMLBackgroundImageContext.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::io; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry<GraphicLocation> psXML_BrushHoriPos[] = +{ + { XML_LEFT, GraphicLocation_LEFT_MIDDLE }, + { XML_RIGHT, GraphicLocation_RIGHT_MIDDLE }, + { XML_TOKEN_INVALID, GraphicLocation(0) } +}; + +const SvXMLEnumMapEntry<GraphicLocation> psXML_BrushVertPos[] = +{ + { XML_TOP, GraphicLocation_MIDDLE_TOP }, + { XML_BOTTOM, GraphicLocation_MIDDLE_BOTTOM }, + { XML_TOKEN_INVALID, GraphicLocation(0) } +}; + +static void lcl_xmlbic_MergeHoriPos( GraphicLocation& ePos, + GraphicLocation eHori ) +{ + DBG_ASSERT( GraphicLocation_LEFT_MIDDLE==eHori || + GraphicLocation_MIDDLE_MIDDLE==eHori || + GraphicLocation_RIGHT_MIDDLE==eHori, + "lcl_xmlbic_MergeHoriPos: vertical pos must be middle" ); + + switch( ePos ) + { + case GraphicLocation_LEFT_TOP: + case GraphicLocation_MIDDLE_TOP: + case GraphicLocation_RIGHT_TOP: + ePos = GraphicLocation_LEFT_MIDDLE==eHori + ? GraphicLocation_LEFT_TOP + : (GraphicLocation_MIDDLE_MIDDLE==eHori + ? GraphicLocation_MIDDLE_TOP + : GraphicLocation_RIGHT_TOP); + break; + + case GraphicLocation_LEFT_MIDDLE: + case GraphicLocation_MIDDLE_MIDDLE: + case GraphicLocation_RIGHT_MIDDLE: + ePos = eHori; + break; + + case GraphicLocation_LEFT_BOTTOM: + case GraphicLocation_MIDDLE_BOTTOM: + case GraphicLocation_RIGHT_BOTTOM: + ePos = GraphicLocation_LEFT_MIDDLE==eHori + ? GraphicLocation_LEFT_BOTTOM + : (GraphicLocation_MIDDLE_MIDDLE==eHori + ? GraphicLocation_MIDDLE_BOTTOM + : GraphicLocation_RIGHT_BOTTOM); + break; + default: + break; + } +} + +static void lcl_xmlbic_MergeVertPos( GraphicLocation& ePos, + GraphicLocation eVert ) +{ + DBG_ASSERT( GraphicLocation_MIDDLE_TOP==eVert || + GraphicLocation_MIDDLE_MIDDLE==eVert || + GraphicLocation_MIDDLE_BOTTOM==eVert, + "lcl_xmlbic_MergeVertPos: horizontal pos must be middle" ); + + switch( ePos ) + { + case GraphicLocation_LEFT_TOP: + case GraphicLocation_LEFT_MIDDLE: + case GraphicLocation_LEFT_BOTTOM: + ePos = GraphicLocation_MIDDLE_TOP==eVert + ? GraphicLocation_LEFT_TOP + : (GraphicLocation_MIDDLE_MIDDLE==eVert + ? GraphicLocation_LEFT_MIDDLE + : GraphicLocation_LEFT_BOTTOM); + break; + + case GraphicLocation_MIDDLE_TOP: + case GraphicLocation_MIDDLE_MIDDLE: + case GraphicLocation_MIDDLE_BOTTOM: + ePos = eVert; + break; + + case GraphicLocation_RIGHT_TOP: + case GraphicLocation_RIGHT_MIDDLE: + case GraphicLocation_RIGHT_BOTTOM: + ePos = GraphicLocation_MIDDLE_TOP==eVert + ? GraphicLocation_RIGHT_TOP + : (GraphicLocation_MIDDLE_MIDDLE==eVert + ? GraphicLocation_RIGHT_MIDDLE + : GraphicLocation_RIGHT_BOTTOM); + break; + default: + break; + } +} + + +void XMLBackgroundImageContext::ProcessAttrs( + const Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + ePos = GraphicLocation_NONE; + + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + m_sURL = aIter.toString(); + if( GraphicLocation_NONE == ePos ) + ePos = GraphicLocation_TILED; + break; + case XML_ELEMENT(XLINK, XML_TYPE): + case XML_ELEMENT(XLINK, XML_ACTUATE): + case XML_ELEMENT(XLINK, XML_SHOW): + break; + case XML_ELEMENT(STYLE, XML_POSITION): + { + GraphicLocation eNewPos = GraphicLocation_NONE, eTmp; + OUString sValue = aIter.toString(); + SvXMLTokenEnumerator aTokenEnum( sValue ); + std::u16string_view aToken; + bool bHori = false, bVert = false; + bool bOK = true; + while( bOK && aTokenEnum.getNextToken( aToken ) ) + { + GraphicLocation nTmpGraphicLocation; + if( bHori && bVert ) + { + bOK = false; + } + else if( std::u16string_view::npos != aToken.find( '%' ) ) + { + sal_Int32 nPrc = 50; + if (::sax::Converter::convertPercent( nPrc, aToken )) + { + if( !bHori ) + { + eNewPos = nPrc < 25 + ? GraphicLocation_LEFT_TOP + : (nPrc < 75 ? GraphicLocation_MIDDLE_MIDDLE + : GraphicLocation_RIGHT_BOTTOM); + bHori = true; + } + else + { + eTmp = nPrc < 25 + ? GraphicLocation_LEFT_TOP + : (nPrc < 75 ? GraphicLocation_LEFT_MIDDLE + : GraphicLocation_LEFT_BOTTOM); + lcl_xmlbic_MergeVertPos( eNewPos, eTmp ); + bVert = true; + } + } + else + { + // wrong percentage + bOK = false; + } + } + else if( IsXMLToken( aToken, XML_CENTER ) ) + { + if( bHori ) + lcl_xmlbic_MergeVertPos( eNewPos, + GraphicLocation_MIDDLE_MIDDLE ); + else if ( bVert ) + lcl_xmlbic_MergeHoriPos( eNewPos, + GraphicLocation_MIDDLE_MIDDLE ); + else + eNewPos = GraphicLocation_MIDDLE_MIDDLE; + } + else if( SvXMLUnitConverter::convertEnum( nTmpGraphicLocation, aToken, + psXML_BrushHoriPos ) ) + { + if( bVert ) + lcl_xmlbic_MergeHoriPos( eNewPos, nTmpGraphicLocation ); + else if( !bHori ) + eNewPos = nTmpGraphicLocation; + else + bOK = false; + bHori = true; + } + else if( SvXMLUnitConverter::convertEnum( nTmpGraphicLocation, aToken, + psXML_BrushVertPos ) ) + { + if( bHori ) + lcl_xmlbic_MergeVertPos( eNewPos, nTmpGraphicLocation ); + else if( !bVert ) + eNewPos = nTmpGraphicLocation; + else + bOK = false; + bVert = true; + } + else + { + bOK = false; + } + } + + bOK &= GraphicLocation_NONE != eNewPos; + if( bOK ) + ePos = eNewPos; + } + break; + case XML_ELEMENT(STYLE, XML_REPEAT): + { + GraphicLocation nPos = GraphicLocation_NONE; + static const SvXMLEnumMapEntry<GraphicLocation> psXML_BrushRepeat[] = + { + { XML_REPEAT, GraphicLocation_TILED }, + { XML_BACKGROUND_NO_REPEAT, GraphicLocation_MIDDLE_MIDDLE }, + { XML_STRETCH, GraphicLocation_AREA }, + { XML_TOKEN_INVALID, GraphicLocation(0) } + }; + if( SvXMLUnitConverter::convertEnum( nPos, aIter.toView(), + psXML_BrushRepeat ) ) + { + if( GraphicLocation_MIDDLE_MIDDLE != nPos || + GraphicLocation_NONE == ePos || + GraphicLocation_AREA == ePos || + GraphicLocation_TILED == ePos ) + ePos = nPos; + } + } + break; + case XML_ELEMENT(STYLE, XML_FILTER_NAME): + sFilter = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_OPACITY): + { + sal_Int32 nTmp; + // convert from percent and clip + if (::sax::Converter::convertPercent( nTmp, aIter.toView() )) + { + if( (nTmp >= 0) && (nTmp <= 100) ) + nTransparency = static_cast<sal_Int8>( 100-nTmp ); + } + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + +} + +XMLBackgroundImageContext::XMLBackgroundImageContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + const XMLPropertyState& rProp, + sal_Int32 nPosIdx, + sal_Int32 nFilterIdx, + sal_Int32 nTransparencyIdx, + sal_Int32 nBitmapModeIdx, + ::std::vector< XMLPropertyState > &rProps ) : + XMLElementPropertyContext( rImport, nElement, rProp, rProps ), + aPosProp( nPosIdx ), + m_nBitmapModeIdx(nBitmapModeIdx), + aFilterProp( nFilterIdx ), + aTransparencyProp( nTransparencyIdx ), + nTransparency( 0 ) +{ + ProcessAttrs( xAttrList ); +} + +XMLBackgroundImageContext::~XMLBackgroundImageContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLBackgroundImageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + if( nElement == XML_ELEMENT(OFFICE, xmloff::token::XML_BINARY_DATA) ) + { + if( m_sURL.isEmpty() && !m_xBase64Stream.is() ) + { + m_xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( m_xBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), m_xBase64Stream ); + } + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLBackgroundImageContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference<graphic::XGraphic> xGraphic; + if (!m_sURL.isEmpty()) + { + xGraphic = GetImport().loadGraphicByURL(m_sURL); + } + else if (m_xBase64Stream.is()) + { + xGraphic = GetImport().loadGraphicFromBase64(m_xBase64Stream); + m_xBase64Stream = nullptr; + } + + if (!xGraphic.is()) + ePos = GraphicLocation_NONE; + else if (GraphicLocation_NONE == ePos) + ePos = GraphicLocation_TILED; + + if (xGraphic.is()) + aProp.maValue <<= xGraphic; + aPosProp.maValue <<= ePos; + aFilterProp.maValue <<= sFilter; + aTransparencyProp.maValue <<= nTransparency; + + SetInsert( true ); + XMLElementPropertyContext::endFastElement(nElement); + + if( -1 != aPosProp.mnIndex ) + { + // See if a FillBitmapMode property is already set, in that case + // BackGraphicLocation will be ignored. + bool bFound = false; + if (m_nBitmapModeIdx != -1) + { + for (XMLPropertyState& rProperty : rProperties) + { + if (rProperty.mnIndex == m_nBitmapModeIdx) + { + bFound = true; + + // Found, so map the old property to the new one. + switch (ePos) + { + case GraphicLocation_TILED: + rProperty.maValue <<= drawing::BitmapMode_REPEAT; + break; + case GraphicLocation_AREA: + rProperty.maValue <<= drawing::BitmapMode_STRETCH; + break; + case GraphicLocation_MIDDLE_MIDDLE: + rProperty.maValue <<= drawing::BitmapMode_NO_REPEAT; + break; + default: + break; + } + break; + } + } + } + if (!bFound) + rProperties.push_back( aPosProp ); + } + if( -1 != aFilterProp.mnIndex ) + rProperties.push_back( aFilterProp ); + if( -1 != aTransparencyProp.mnIndex ) + rProperties.push_back( aTransparencyProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLBackgroundImageExport.cxx b/xmloff/source/style/XMLBackgroundImageExport.cxx new file mode 100644 index 0000000000..c3ae8748a5 --- /dev/null +++ b/xmloff/source/style/XMLBackgroundImageExport.cxx @@ -0,0 +1,165 @@ +/* -*- 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 <com/sun/star/style/GraphicLocation.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <rtl/ustrbuf.hxx> +#include <xmloff/xmlexp.hxx> +#include <XMLBackgroundImageExport.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + +XMLBackgroundImageExport::XMLBackgroundImageExport( SvXMLExport& rExp ) : + rExport( rExp ) +{ +} + +void XMLBackgroundImageExport::exportXML( const Any& rGraphicAny, + const Any *pPos, + const Any *pFilter, + const Any *pTransparency, + sal_uInt16 nPrefix, + const OUString& rLocalName ) +{ + GraphicLocation ePos; + if( !(pPos && ((*pPos) >>= ePos)) ) + ePos = GraphicLocation_AREA; + + uno::Reference<graphic::XGraphic> xGraphic; + if (rGraphicAny.has<uno::Reference<graphic::XGraphic>>()) + xGraphic = rGraphicAny.get<uno::Reference<graphic::XGraphic>>(); + + if (xGraphic.is() && GraphicLocation_NONE != ePos) + { + OUString sUsedMimeType; + OUString sInternalURL(GetExport().AddEmbeddedXGraphic(xGraphic, sUsedMimeType)); + + if (!sInternalURL.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + + OUStringBuffer aOut; + switch( ePos ) + { + case GraphicLocation_LEFT_TOP: + case GraphicLocation_MIDDLE_TOP: + case GraphicLocation_RIGHT_TOP: + aOut.append( GetXMLToken(XML_TOP) ); + break; + case GraphicLocation_LEFT_MIDDLE: + case GraphicLocation_MIDDLE_MIDDLE: + case GraphicLocation_RIGHT_MIDDLE: + aOut.append( GetXMLToken(XML_CENTER) ); + break; + case GraphicLocation_LEFT_BOTTOM: + case GraphicLocation_MIDDLE_BOTTOM: + case GraphicLocation_RIGHT_BOTTOM: + aOut.append( GetXMLToken(XML_BOTTOM) ); + break; + default: + break; + } + + if( !aOut.isEmpty() ) + { + aOut.append( ' ' ); + + switch( ePos ) + { + case GraphicLocation_LEFT_TOP: + case GraphicLocation_LEFT_BOTTOM: + case GraphicLocation_LEFT_MIDDLE: + aOut.append( GetXMLToken(XML_LEFT) ); + break; + case GraphicLocation_MIDDLE_TOP: + case GraphicLocation_MIDDLE_MIDDLE: + case GraphicLocation_MIDDLE_BOTTOM: + aOut.append( GetXMLToken(XML_CENTER) ); + break; + case GraphicLocation_RIGHT_MIDDLE: + case GraphicLocation_RIGHT_TOP: + case GraphicLocation_RIGHT_BOTTOM: + aOut.append( GetXMLToken(XML_RIGHT) ); + break; + default: + break; + } + } + if( !aOut.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_POSITION, aOut.makeStringAndClear() ); + + if( GraphicLocation_AREA == ePos ) + { + aOut.append( GetXMLToken(XML_STRETCH) ); + } + else if( GraphicLocation_NONE != ePos && GraphicLocation_TILED != ePos ) + { + aOut.append( GetXMLToken(XML_BACKGROUND_NO_REPEAT) ); + } + if( !aOut.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REPEAT, + aOut.makeStringAndClear() ); + + if( pFilter ) + { + OUString sFilter; + (*pFilter) >>= sFilter; + if( !sFilter.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FILTER_NAME, + sFilter ); + } + + if( pTransparency ) + { + sal_Int8 nTransparency = sal_Int8(); + if( (*pTransparency) >>= nTransparency ) + { + OUStringBuffer aTransOut; + ::sax::Converter::convertPercent(aTransOut, 100-nTransparency); + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_OPACITY, + aTransOut.makeStringAndClear() ); + } + } + } + + { + SvXMLElementExport aElem(GetExport(), nPrefix, rLocalName, true, true); + if (xGraphic.is() && GraphicLocation_NONE != ePos) + { + // optional office:binary-data + GetExport().AddEmbeddedXGraphicAsBase64(xGraphic); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLBitmapLogicalSizePropertyHandler.cxx b/xmloff/source/style/XMLBitmapLogicalSizePropertyHandler.cxx new file mode 100644 index 0000000000..92d409e8a8 --- /dev/null +++ b/xmloff/source/style/XMLBitmapLogicalSizePropertyHandler.cxx @@ -0,0 +1,53 @@ +/* -*- 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 <xmloff/xmluconv.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <XMLBitmapLogicalSizePropertyHandler.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLBitmapLogicalSizePropertyHandler::XMLBitmapLogicalSizePropertyHandler() +{ +} + +XMLBitmapLogicalSizePropertyHandler::~XMLBitmapLogicalSizePropertyHandler() +{ +} + +bool XMLBitmapLogicalSizePropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + rValue <<= ( rStrImpValue.indexOf( '%' ) == -1 ); + return true; +} + +bool XMLBitmapLogicalSizePropertyHandler::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLBitmapRepeatOffsetPropertyHandler.cxx b/xmloff/source/style/XMLBitmapRepeatOffsetPropertyHandler.cxx new file mode 100644 index 0000000000..c4a9384bfd --- /dev/null +++ b/xmloff/source/style/XMLBitmapRepeatOffsetPropertyHandler.cxx @@ -0,0 +1,93 @@ +/* -*- 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 <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <sax/tools/converter.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <XMLBitmapRepeatOffsetPropertyHandler.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +using ::xmloff::token::GetXMLToken; +using ::xmloff::token::XML_VERTICAL; +using ::xmloff::token::XML_HORIZONTAL; + + +XMLBitmapRepeatOffsetPropertyHandler::XMLBitmapRepeatOffsetPropertyHandler( bool bX ) +: mbX( bX ), + msVertical( GetXMLToken(XML_VERTICAL) ), + msHorizontal( GetXMLToken(XML_HORIZONTAL) ) +{ +} + +XMLBitmapRepeatOffsetPropertyHandler::~XMLBitmapRepeatOffsetPropertyHandler() +{ +} + +bool XMLBitmapRepeatOffsetPropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + std::u16string_view aToken; + if( aTokenEnum.getNextToken( aToken ) ) + { + sal_Int32 nValue; + if (::sax::Converter::convertPercent( nValue, aToken )) + { + if( aTokenEnum.getNextToken( aToken ) ) + { + if( ( mbX && ( aToken == msHorizontal ) ) || ( !mbX && ( aToken == msVertical ) ) ) + { + rValue <<= nValue; + return true; + } + } + } + } + + return false; + +} + +bool XMLBitmapRepeatOffsetPropertyHandler::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + aOut.append( " " + ( mbX ? msHorizontal : msVertical ) ); + rStrExpValue = aOut.makeStringAndClear(); + + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLClipPropertyHandler.cxx b/xmloff/source/style/XMLClipPropertyHandler.cxx new file mode 100644 index 0000000000..7a4d01cd99 --- /dev/null +++ b/xmloff/source/style/XMLClipPropertyHandler.cxx @@ -0,0 +1,140 @@ +/* -*- 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 <XMLClipPropertyHandler.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <com/sun/star/text/GraphicCrop.hpp> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + + + + +XMLClipPropertyHandler::XMLClipPropertyHandler( bool bODF11 ) : + m_bODF11( bODF11 ) +{ +} + +XMLClipPropertyHandler::~XMLClipPropertyHandler() +{ + // nothing to do +} + +bool XMLClipPropertyHandler::equals( + const Any& r1, + const Any& r2 ) const +{ + GraphicCrop aCrop1, aCrop2; + r1 >>= aCrop1; + r2 >>= aCrop2; + + return aCrop1.Top == aCrop2.Top && + aCrop1.Bottom == aCrop2.Bottom && + aCrop1.Left == aCrop2.Left && + aCrop1.Right == aCrop2.Right; +} + +bool XMLClipPropertyHandler::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int32 nLen = rStrImpValue.getLength(); + if( nLen > 6 && + rStrImpValue.startsWith( GetXMLToken(XML_RECT)) && + rStrImpValue[4] == '(' && + rStrImpValue[nLen-1] == ')' ) + { + GraphicCrop aCrop; + OUString sTmp( rStrImpValue.copy( 5, nLen-6 ) ); + + bool bHasComma = sTmp.indexOf( ',' ) != -1; + SvXMLTokenEnumerator aTokenEnum( sTmp, bHasComma ? ',' : ' ' ); + + sal_uInt16 nPos = 0; + std::u16string_view aToken; + while( aTokenEnum.getNextToken( aToken ) ) + { + sal_Int32 nVal = 0; + if( !IsXMLToken(aToken, XML_AUTO) && + !rUnitConverter.convertMeasureToCore( nVal, aToken ) ) + break; + + // fdo#80009 such nonsense could be written via WW8 import fdo#77454 + if (abs(nVal) > 400000) + { + SAL_INFO("xmloff.style", "ignoring excessive clip " << OUString(aToken)); + nVal = 0; + } + + switch( nPos ) + { + case 0: aCrop.Top = nVal; break; + case 1: aCrop.Right = nVal; break; + case 2: aCrop.Bottom = nVal; break; + case 3: aCrop.Left = nVal; break; + } + nPos++; + } + + bRet = (4 == nPos ); + if( bRet ) + rValue <<= aCrop; + } + + return bRet; +} + +bool XMLClipPropertyHandler::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + OUStringBuffer aOut(30); + GraphicCrop aCrop; + + if( rValue >>= aCrop ) + { + aOut.append( GetXMLToken(XML_RECT) + "(" ); + rUnitConverter.convertMeasureToXML( aOut, aCrop.Top ); + if( !m_bODF11 ) + aOut.append( ',' ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aCrop.Right ); + if( !m_bODF11 ) + aOut.append( ',' ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aCrop.Bottom ); + if( !m_bODF11 ) + aOut.append( ',' ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aCrop.Left ); + aOut.append( ')' ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLConstantsPropertyHandler.cxx b/xmloff/source/style/XMLConstantsPropertyHandler.cxx new file mode 100644 index 0000000000..54145a46f8 --- /dev/null +++ b/xmloff/source/style/XMLConstantsPropertyHandler.cxx @@ -0,0 +1,91 @@ +/* -*- 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 <xmloff/xmluconv.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/uno/Any.hxx> +#include <xmloff/XMLConstantsPropertyHandler.hxx> + +using namespace ::com::sun::star::uno; + +XMLConstantsPropertyHandler::~XMLConstantsPropertyHandler() +{ +} + +bool XMLConstantsPropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_uInt16 nEnum; + bool bRet = SvXMLUnitConverter::convertEnum( + nEnum, rStrImpValue, m_pMap ); + + if( bRet ) + rValue <<= static_cast<sal_Int16>(nEnum); + + return bRet; +} + +bool XMLConstantsPropertyHandler::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + sal_Int32 nEnum = 0; + + if( rValue.hasValue() && (rValue.getValueTypeClass() == TypeClass_ENUM)) + { + nEnum = *static_cast<sal_Int32 const *>(rValue.getValue()); + bRet = true; + } + else + { + bRet = (rValue >>= nEnum ); + } + + if( bRet ) + { + if( (nEnum >= 0) && (nEnum <= 0xffff) ) + { + sal_uInt16 nConst = static_cast<sal_uInt16>( nEnum ); + OUStringBuffer aOut; + + bRet = SvXMLUnitConverter::convertEnum( + aOut, nConst, m_pMap, m_eDefault ); + + rStrExpValue = aOut.makeStringAndClear(); + } + else + { + OSL_FAIL("XMLConstantsPropertyHandler::exportXML() constant is out of range for implementation using sal_uInt16"); + } + } + else + { + OSL_FAIL("XMLConstantsPropertyHandler::exportXML() could not convert any to sal_Int32"); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLElementPropertyContext.cxx b/xmloff/source/style/XMLElementPropertyContext.cxx new file mode 100644 index 0000000000..1722375be7 --- /dev/null +++ b/xmloff/source/style/XMLElementPropertyContext.cxx @@ -0,0 +1,45 @@ +/* -*- 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 <xmloff/XMLElementPropertyContext.hxx> +#include <utility> + + +XMLElementPropertyContext::XMLElementPropertyContext ( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + XMLPropertyState _aProp, + ::std::vector< XMLPropertyState > &rProps ) : + SvXMLImportContext( rImport ), + bInsert( false ), + rProperties( rProps ), + aProp(std::move( _aProp )) +{ +} + +XMLElementPropertyContext::~XMLElementPropertyContext() +{ +} + +void XMLElementPropertyContext::endFastElement(sal_Int32 ) +{ + if( bInsert ) + rProperties.push_back( aProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFillBitmapSizePropertyHandler.cxx b/xmloff/source/style/XMLFillBitmapSizePropertyHandler.cxx new file mode 100644 index 0000000000..4dded1859c --- /dev/null +++ b/xmloff/source/style/XMLFillBitmapSizePropertyHandler.cxx @@ -0,0 +1,88 @@ +/* -*- 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 <XMLFillBitmapSizePropertyHandler.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmluconv.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLFillBitmapSizePropertyHandler::XMLFillBitmapSizePropertyHandler() +{ +} + +XMLFillBitmapSizePropertyHandler::~XMLFillBitmapSizePropertyHandler() +{ +} + +bool XMLFillBitmapSizePropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int32 nValue; + bool bRet; + + if( rStrImpValue.indexOf( '%' ) != -1 ) + { + bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + nValue *= -1; + } + else + { + bRet = rUnitConverter.convertMeasureToCore( nValue, rStrImpValue ); + } + + if( bRet ) + rValue <<= nValue; + + return bRet; +} + +bool XMLFillBitmapSizePropertyHandler::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + if( nValue < 0 ) + { + ::sax::Converter::convertPercent( aOut, -nValue ); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, nValue ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFontAutoStylePool.cxx b/xmloff/source/style/XMLFontAutoStylePool.cxx new file mode 100644 index 0000000000..d7b880208b --- /dev/null +++ b/xmloff/source/style/XMLFontAutoStylePool.cxx @@ -0,0 +1,681 @@ +/* -*- 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 <o3tl/sorted_vector.hxx> +#include <tools/fontenum.hxx> +#include <utility> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include "fonthdl.hxx" +#include <xmloff/xmlexp.hxx> +#include <xmloff/XMLFontAutoStylePool.hxx> +#include <vcl/embeddedfontshelper.hxx> +#include <osl/file.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/ucb/SimpleFileAccess.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/container/XNameAccess.hpp> + +#include <XMLBase64Export.hxx> +#include <AutoStyleEntry.hxx> +#include <comphelper/hash.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +namespace { + +class XMLFontAutoStylePoolEntry_Impl +{ + OUString sName; + OUString sFamilyName; + OUString sStyleName; + FontFamily nFamily; + FontPitch nPitch; + rtl_TextEncoding eEnc; + +public: + + inline XMLFontAutoStylePoolEntry_Impl( + OUString aName, + OUString aFamilyName, + OUString aStyleName, + FontFamily nFamily, + FontPitch nPitch, + rtl_TextEncoding eEnc ); + + inline XMLFontAutoStylePoolEntry_Impl( + OUString aFamilyName, + OUString aStyleName, + FontFamily nFamily, + FontPitch nPitch, + rtl_TextEncoding eEnc ); + + const OUString& GetName() const { return sName; } + const OUString& GetFamilyName() const { return sFamilyName; } + const OUString& GetStyleName() const { return sStyleName; } + FontFamily GetFamily() const { return nFamily; } + FontPitch GetPitch() const { return nPitch; } + rtl_TextEncoding GetEncoding() const { return eEnc; } +}; + +} + +inline XMLFontAutoStylePoolEntry_Impl::XMLFontAutoStylePoolEntry_Impl( + OUString aName, + OUString aFamilyName, + OUString aStyleName, + FontFamily nFam, + FontPitch nP, + rtl_TextEncoding eE ) : + sName(std::move( aName )), + sFamilyName(std::move( aFamilyName )), + sStyleName(std::move( aStyleName )), + nFamily( nFam ), + nPitch( nP ), + eEnc( eE ) +{ +} + +inline XMLFontAutoStylePoolEntry_Impl::XMLFontAutoStylePoolEntry_Impl( + OUString rFamilyName, + OUString rStyleName, + FontFamily nFam, + FontPitch nP, + rtl_TextEncoding eE ) : + sFamilyName(std::move( rFamilyName )), + sStyleName(std::move( rStyleName )), + nFamily( nFam ), + nPitch( nP ), + eEnc( eE ) +{ +} + +namespace { + +struct XMLFontAutoStylePoolEntryCmp_Impl { + bool operator()( + std::unique_ptr<XMLFontAutoStylePoolEntry_Impl> const& r1, + std::unique_ptr<XMLFontAutoStylePoolEntry_Impl> const& r2 ) const + { + bool bEnc1(r1->GetEncoding() != RTL_TEXTENCODING_SYMBOL); + bool bEnc2(r2->GetEncoding() != RTL_TEXTENCODING_SYMBOL); + if( bEnc1 != bEnc2 ) + return bEnc1 < bEnc2; + else if( r1->GetPitch() != r2->GetPitch() ) + return r1->GetPitch() < r2->GetPitch(); + else if( r1->GetFamily() != r2->GetFamily() ) + return r1->GetFamily() < r2->GetFamily(); + else + { + sal_Int32 nCmp = r1->GetFamilyName().compareTo( r2->GetFamilyName() ); + if( 0 == nCmp ) + return r1->GetStyleName().compareTo( r2->GetStyleName() ) < 0; + else + return nCmp < 0; + } + } +}; + +} + +class XMLFontAutoStylePool_Impl : public o3tl::sorted_vector<std::unique_ptr<XMLFontAutoStylePoolEntry_Impl>, XMLFontAutoStylePoolEntryCmp_Impl> +{ +}; + +XMLFontAutoStylePool::XMLFontAutoStylePool(SvXMLExport& rExp, bool bTryToEmbedFonts) : + m_rExport( rExp ), + m_pFontAutoStylePool( new XMLFontAutoStylePool_Impl ), + m_bTryToEmbedFonts( bTryToEmbedFonts ), + m_bEmbedUsedOnly(false), + m_bEmbedLatinScript(true), + m_bEmbedAsianScript(true), + m_bEmbedComplexScript(true) +{ +} + +XMLFontAutoStylePool::~XMLFontAutoStylePool() +{ +} + +OUString XMLFontAutoStylePool::Add( + const OUString& rFamilyName, + const OUString& rStyleName, + FontFamily nFamily, + FontPitch nPitch, + rtl_TextEncoding eEnc ) +{ + OUString sPoolName; + XMLFontAutoStylePoolEntry_Impl aTmp( rFamilyName, rStyleName, nFamily, + nPitch, eEnc ); + XMLFontAutoStylePool_Impl::const_iterator it = m_pFontAutoStylePool->find( &aTmp ); + if( it != m_pFontAutoStylePool->end() ) + { + sPoolName = (*it)->GetName(); + } + else + { + OUString sName; + sal_Int32 nLen = rFamilyName.indexOf( ';' ); + if( -1 == nLen ) + { + sName = rFamilyName; + } + else if( nLen > 0 ) + { + sName = rFamilyName.copy( 0, nLen ); + sName = sName.trim(); + } + + if( sName.isEmpty() ) + sName = "F"; + + if( m_aNames.find(sName) != m_aNames.end() ) + { + sal_Int32 nCount = 1; + OUString sPrefix( sName ); + sName = sPrefix + OUString::number( nCount ); + while( m_aNames.find(sName) != m_aNames.end() ) + { + sName = sPrefix + OUString::number( ++nCount ); + } + } + + std::unique_ptr<XMLFontAutoStylePoolEntry_Impl> pEntry( + new XMLFontAutoStylePoolEntry_Impl( sName, rFamilyName, rStyleName, + nFamily, nPitch, eEnc )); + m_pFontAutoStylePool->insert( std::move(pEntry) ); + m_aNames.insert(sName); + } + + return sPoolName; +} + +OUString XMLFontAutoStylePool::Find( + const OUString& rFamilyName, + const OUString& rStyleName, + FontFamily nFamily, + FontPitch nPitch, + rtl_TextEncoding eEnc ) const +{ + OUString sName; + XMLFontAutoStylePoolEntry_Impl aTmp( rFamilyName, rStyleName, nFamily, + nPitch, eEnc ); + XMLFontAutoStylePool_Impl::const_iterator it = m_pFontAutoStylePool->find( &aTmp ); + if( it != m_pFontAutoStylePool->end() ) + { + sName = (*it)->GetName(); + } + + return sName; +} + +namespace +{ + +OUString lcl_checkFontFile( const OUString &fileUrl ) +{ + osl::DirectoryItem aDirItem; + if( osl::DirectoryItem::get( fileUrl, aDirItem ) == osl::File::E_None ) + { + osl::FileStatus aStatus( osl_FileStatus_Mask_Type ); + if( aDirItem.getFileStatus( aStatus ) == osl::File::E_None ) + { + if( !aStatus.isDirectory() ) + return fileUrl; + } + } + return OUString(); +} + +/// Contains information about a single variant of an embedded font. +struct EmbeddedFontInfo +{ + OUString aURL; + FontWeight eWeight = WEIGHT_NORMAL; + FontItalic eItalic = ITALIC_NONE; +}; + +/// Converts FontWeight to CSS-compatible string representation. +OUString FontWeightToString(FontWeight eWeight) +{ + OUString aRet; + + switch (eWeight) + { + case WEIGHT_BOLD: + aRet = "bold"; + break; + default: + aRet = "normal"; + break; + } + + return aRet; +} + +/// Converts FontItalic to CSS-compatible string representation. +OUString FontItalicToString(FontItalic eWeight) +{ + OUString aRet; + + switch (eWeight) + { + case ITALIC_NORMAL: + aRet = "italic"; + break; + default: + aRet = "normal"; + break; + } + + return aRet; +} + +} + +std::unordered_set<OUString> XMLFontAutoStylePool::getUsedFontList() +{ + std::unordered_set<OUString> aReturnSet; + + uno::Reference<style::XStyleFamiliesSupplier> xFamiliesSupp(GetExport().GetModel(), UNO_QUERY); + if (!xFamiliesSupp.is()) + return aReturnSet; + + // Check styles first + uno::Reference<container::XNameAccess> xFamilies(xFamiliesSupp->getStyleFamilies()); + if (xFamilies.is()) + { + const uno::Sequence<OUString> aFamilyNames = xFamilies->getElementNames(); + for (OUString const & sFamilyName : aFamilyNames) + { + uno::Reference<container::XNameAccess> xStyleContainer; + xFamilies->getByName(sFamilyName) >>= xStyleContainer; + + if (xStyleContainer.is()) + { + const uno::Sequence<OUString> aStyleNames = xStyleContainer->getElementNames(); + for (OUString const & rName : aStyleNames) + { + uno::Reference<style::XStyle> xStyle; + xStyleContainer->getByName(rName) >>= xStyle; + if (xStyle->isInUse()) + { + uno::Reference<beans::XPropertySet> xPropertySet(xStyle, UNO_QUERY); + uno::Reference<beans::XPropertySetInfo> xInfo(xPropertySet ? xPropertySet->getPropertySetInfo() : nullptr); + if (xInfo) + { + if (m_bEmbedLatinScript && xInfo->hasPropertyByName("CharFontName")) + { + OUString sCharFontName; + Any aFontAny = xPropertySet->getPropertyValue("CharFontName"); + aFontAny >>= sCharFontName; + if (!sCharFontName.isEmpty()) + aReturnSet.insert(sCharFontName); + } + if (m_bEmbedAsianScript && xInfo->hasPropertyByName("CharFontNameAsian")) + { + OUString sCharFontNameAsian; + Any aFontAny = xPropertySet->getPropertyValue("CharFontNameAsian"); + aFontAny >>= sCharFontNameAsian; + if (!sCharFontNameAsian.isEmpty()) + aReturnSet.insert(sCharFontNameAsian); + } + if (m_bEmbedComplexScript && xInfo->hasPropertyByName("CharFontNameComplex")) + { + OUString sCharFontNameComplex; + Any aFontAny = xPropertySet->getPropertyValue("CharFontNameComplex"); + aFontAny >>= sCharFontNameComplex; + if (!sCharFontNameComplex.isEmpty()) + aReturnSet.insert(sCharFontNameComplex); + } + } + } + } + } + } + } + + // make sure auto-styles are collected + GetExport().collectAutoStyles(); + + // Check auto-styles for fonts + std::vector<xmloff::AutoStyleEntry> aAutoStyleEntries = GetExport().GetAutoStylePool()->GetAutoStyleEntries(); + for (auto const & rAutoStyleEntry : aAutoStyleEntries) + { + for (auto const & rPair : rAutoStyleEntry.m_aXmlProperties) + { + if (rPair.first == "font-name" || + rPair.first == "font-weight-asian" || + rPair.first == "font-weight-complex") + { + if (rPair.second.has<OUString>()) + { + OUString sFontName = rPair.second.get<OUString>(); + if (!sFontName.isEmpty()) + aReturnSet.insert(sFontName); + } + } + } + } + + return aReturnSet; +} + +void XMLFontAutoStylePool::exportXML() +{ + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_OFFICE, + XML_FONT_FACE_DECLS, + true, true); + Any aAny; + OUString sTmp; + XMLFontFamilyNamePropHdl aFamilyNameHdl; + XMLFontFamilyPropHdl aFamilyHdl; + XMLFontPitchPropHdl aPitchHdl; + XMLFontEncodingPropHdl aEncHdl; + const SvXMLUnitConverter& rUnitConv = GetExport().GetMM100UnitConverter(); + + std::map<OUString, OUString> fontFilesMap; // our url to document url + + std::unordered_set<OUString> aUsedFontNames; + if (m_bEmbedUsedOnly) + aUsedFontNames = getUsedFontList(); + + // Sort <style:font-face> elements based on their style:name attribute. + std::vector<XMLFontAutoStylePoolEntry_Impl*> aFontAutoStyles; + for (const auto& pEntry : *m_pFontAutoStylePool) + { + aFontAutoStyles.push_back(pEntry.get()); + } + std::sort( + aFontAutoStyles.begin(), aFontAutoStyles.end(), + [](const XMLFontAutoStylePoolEntry_Impl* pA, XMLFontAutoStylePoolEntry_Impl* pB) -> bool { + return pA->GetName() < pB->GetName(); + }); + + for (const auto& pEntry : aFontAutoStyles) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, pEntry->GetName()); + + aAny <<= pEntry->GetFamilyName(); + if (aFamilyNameHdl.exportXML(sTmp, aAny, rUnitConv)) + GetExport().AddAttribute(XML_NAMESPACE_SVG, + XML_FONT_FAMILY, sTmp); + + const OUString& rStyleName = pEntry->GetStyleName(); + if (!rStyleName.isEmpty()) + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_FONT_ADORNMENTS, + rStyleName); + + aAny <<= static_cast<sal_Int16>(pEntry->GetFamily()); + if (aFamilyHdl.exportXML(sTmp, aAny, rUnitConv)) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_FONT_FAMILY_GENERIC, sTmp); + } + aAny <<= static_cast<sal_Int16>(pEntry->GetPitch()); + if (aPitchHdl.exportXML(sTmp, aAny, rUnitConv)) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_FONT_PITCH, sTmp); + } + + aAny <<= static_cast<sal_Int16>(pEntry->GetEncoding()); + if (aEncHdl.exportXML( sTmp, aAny, rUnitConv)) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_FONT_CHARSET, sTmp); + } + + SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_STYLE, + XML_FONT_FACE, true, true); + + if (m_bTryToEmbedFonts) + { + const bool bExportFlat(GetExport().getExportFlags() & SvXMLExportFlags::EMBEDDED); + std::vector<EmbeddedFontInfo> aEmbeddedFonts; + static const std::vector<std::pair<FontWeight, FontItalic>> aCombinations = + { + { WEIGHT_NORMAL, ITALIC_NONE }, + { WEIGHT_BOLD, ITALIC_NONE }, + { WEIGHT_NORMAL, ITALIC_NORMAL }, + { WEIGHT_BOLD, ITALIC_NORMAL }, + }; + + for (auto const & aCombinationPair : aCombinations) + { + // Embed font if at least viewing is allowed (in which case the opening app must check + // the font license rights too and open either read-only or not use the font for editing). + OUString sFileUrl = EmbeddedFontsHelper::fontFileUrl( + pEntry->GetFamilyName(), pEntry->GetFamily(), + aCombinationPair.second, aCombinationPair.first, pEntry->GetPitch(), + EmbeddedFontsHelper::FontRights::ViewingAllowed); + if (sFileUrl.isEmpty()) + continue; + + // When embedded only is not set or font is used + if (!m_bEmbedUsedOnly || + aUsedFontNames.find(pEntry->GetFamilyName()) != aUsedFontNames.end()) + { + if (!fontFilesMap.count(sFileUrl)) + { + const OUString docUrl = bExportFlat ? + lcl_checkFontFile(sFileUrl) : embedFontFile(sFileUrl, pEntry->GetFamilyName()); + if (!docUrl.isEmpty()) + fontFilesMap[sFileUrl] = docUrl; + else + continue; // --> failed to embed + } + EmbeddedFontInfo aEmbeddedFont; + aEmbeddedFont.aURL = sFileUrl; + aEmbeddedFont.eWeight = aCombinationPair.first; + aEmbeddedFont.eItalic = aCombinationPair.second; + aEmbeddedFonts.push_back(aEmbeddedFont); + } + } + if (!aEmbeddedFonts.empty()) + { + SvXMLElementExport fontFaceSrc(GetExport(), XML_NAMESPACE_SVG, XML_FONT_FACE_SRC, true, true); + for (EmbeddedFontInfo const & rEmbeddedFont : aEmbeddedFonts) + { + if (fontFilesMap.count(rEmbeddedFont.aURL)) + { + if (!bExportFlat) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, + fontFilesMap[rEmbeddedFont.aURL]); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, "simple"); + } + + // Help consumers of our output by telling them which + // font file is which one. + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_FONT_STYLE, + FontItalicToString(rEmbeddedFont.eItalic)); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_FONT_WEIGHT, + FontWeightToString(rEmbeddedFont.eWeight)); + + SvXMLElementExport fontFaceUri(GetExport(), XML_NAMESPACE_SVG, + XML_FONT_FACE_URI, true, true); + + if (bExportFlat) + { + const uno::Reference<ucb::XSimpleFileAccess> xFileAccess( + ucb::SimpleFileAccess::create(GetExport().getComponentContext())); + try + { + const uno::Reference<io::XInputStream> xInput(xFileAccess->openFileRead(fontFilesMap[rEmbeddedFont.aURL])); + XMLBase64Export aBase64Exp(GetExport()); + aBase64Exp.exportOfficeBinaryDataElement(xInput); + } + catch (const uno::Exception &) + { + // opening the file failed, ignore + } + } + + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_STRING, "truetype"); + SvXMLElementExport fontFaceFormat(GetExport(), XML_NAMESPACE_SVG, + XML_FONT_FACE_FORMAT, true, true); + } + } + } + } + } +} + +static OUString getFreeFontName(uno::Reference<embed::XStorage> const & rxStorage, OUString const & rFamilyName) +{ + OUString sName; + int nIndex = 1; + do + { + sName = "Font_" + + rFamilyName.replaceAll(" ", "_") + "_" + + OUString::number(nIndex) + ".ttf"; + nIndex++; + } while (rxStorage->hasByName(sName)); + + return sName; +} + +static OString convertToHashString(std::vector<unsigned char> const & rHash) +{ + std::stringstream aStringStream; + for (auto const & rByte : rHash) + { + aStringStream << std::setw(2) << std::setfill('0') << std::hex << int(rByte); + } + + return OString(aStringStream.str()); +} + +static OString getFileHash(OUString const & rFileUrl) +{ + OString aHash; + osl::File aFile(rFileUrl); + if (aFile.open(osl_File_OpenFlag_Read) != osl::File::E_None) + return aHash; + + comphelper::Hash aHashEngine(comphelper::HashType::SHA512); + for (;;) + { + sal_Int8 aBuffer[4096]; + sal_uInt64 nReadSize; + sal_Bool bEof; + if (aFile.isEndOfFile(&bEof) != osl::File::E_None) + { + SAL_WARN("xmloff", "Error reading font file " << rFileUrl); + return aHash; + } + if (bEof) + break; + if (aFile.read(aBuffer, 4096, nReadSize) != osl::File::E_None) + { + SAL_WARN("xmloff", "Error reading font file " << rFileUrl); + return aHash; + } + if (nReadSize == 0) + break; + aHashEngine.update(reinterpret_cast<unsigned char*>(aBuffer), nReadSize); + } + return convertToHashString(aHashEngine.finalize()); +} + +OUString XMLFontAutoStylePool::embedFontFile(OUString const & fileUrl, OUString const & rFamilyName) +{ + try + { + OString sHashString = getFileHash(fileUrl); + if (m_aEmbeddedFontFiles.find(sHashString) != m_aEmbeddedFontFiles.end()) + return m_aEmbeddedFontFiles.at(sHashString); + + osl::File file( fileUrl ); + if( file.open( osl_File_OpenFlag_Read ) != osl::File::E_None ) + return OUString(); + + if ( !GetExport().GetTargetStorage().is() ) + return OUString(); + + uno::Reference< embed::XStorage > storage; + storage.set( GetExport().GetTargetStorage()->openStorageElement( "Fonts", + ::embed::ElementModes::WRITE ), uno::UNO_SET_THROW ); + + OUString name = getFreeFontName(storage, rFamilyName); + + uno::Reference< io::XOutputStream > outputStream; + outputStream.set( storage->openStreamElement( name, ::embed::ElementModes::WRITE ), UNO_QUERY_THROW ); + uno::Reference < beans::XPropertySet > propertySet( outputStream, uno::UNO_QUERY ); + assert( propertySet.is()); + propertySet->setPropertyValue( "MediaType", uno::Any( OUString( "application/x-font-ttf" ))); // TODO + for(;;) + { + sal_Int8 buffer[ 4096 ]; + sal_uInt64 readSize; + sal_Bool eof; + if( file.isEndOfFile( &eof ) != osl::File::E_None ) + { + SAL_WARN( "xmloff", "Error reading font file " << fileUrl ); + outputStream->closeOutput(); + return OUString(); + } + if( eof ) + break; + if( file.read( buffer, 4096, readSize ) != osl::File::E_None ) + { + SAL_WARN( "xmloff", "Error reading font file " << fileUrl ); + outputStream->closeOutput(); + return OUString(); + } + if( readSize == 0 ) + break; + // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence + outputStream->writeBytes(uno::Sequence<sal_Int8>(buffer, readSize)); + } + outputStream->closeOutput(); + if( storage.is() ) + { + Reference< embed::XTransactedObject > transaction( storage, UNO_QUERY ); + if( transaction.is()) + { + transaction->commit(); + OUString sInternalName = "Fonts/" + name; + m_aEmbeddedFontFiles.emplace(sHashString, sInternalName); + return sInternalName; + } + } + } catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff", "Exception when embedding a font file" ); + } + return OUString(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFontStylesContext.cxx b/xmloff/source/style/XMLFontStylesContext.cxx new file mode 100644 index 0000000000..71fe2ad514 --- /dev/null +++ b/xmloff/source/style/XMLFontStylesContext.cxx @@ -0,0 +1,352 @@ +/* -*- 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 <xmloff/XMLFontStylesContext.hxx> +#include "XMLFontStylesContext_impl.hxx" + +#include <com/sun/star/awt/FontFamily.hpp> +#include <com/sun/star/awt/FontPitch.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XStorage.hpp> + +#include <comphelper/seqstream.hxx> + +#include <sal/log.hxx> + +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include "fonthdl.hxx" +#include <xmloff/xmlimp.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/XMLBase64ImportContext.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::awt; +using namespace ::xmloff::token; + + +#define XML_STYLE_FAMILY_FONT XmlStyleFamily::PAGE_MASTER + +XMLFontStyleContextFontFace::XMLFontStyleContextFontFace( SvXMLImport& rImport, + XMLFontStylesContext& rStyles ) : + SvXMLStyleContext( rImport, XML_STYLE_FAMILY_FONT ), + xStyles( &rStyles ) +{ + aFamilyName <<= OUString(); + aStyleName <<= OUString(); + aFamily <<= sal_Int16(awt::FontFamily::DONTKNOW); + aPitch <<= sal_Int16(awt::FontPitch::DONTKNOW); + aEnc <<= static_cast<sal_Int16>(rStyles.GetDfltCharset()); +} + +void XMLFontStyleContextFontFace::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter(); + Any aAny; + + switch(nElement) + { + case XML_ELEMENT(SVG, XML_FONT_FAMILY): + case XML_ELEMENT(SVG_COMPAT, XML_FONT_FAMILY): + if( GetStyles()->GetFamilyNameHdl().importXML( rValue, aAny, + rUnitConv ) ) + aFamilyName = aAny; + break; + case XML_ELEMENT(STYLE, XML_FONT_ADORNMENTS): + aStyleName <<= rValue; + break; + case XML_ELEMENT(STYLE, XML_FONT_FAMILY_GENERIC): + if( GetStyles()->GetFamilyHdl().importXML( rValue, aAny, + rUnitConv ) ) + aFamily = aAny; + break; + case XML_ELEMENT(STYLE, XML_FONT_PITCH): + if( GetStyles()->GetPitchHdl().importXML( rValue, aAny, + rUnitConv ) ) + aPitch = aAny; + break; + case XML_ELEMENT(STYLE, XML_FONT_CHARSET): + if( GetStyles()->GetEncodingHdl().importXML( rValue, aAny, + rUnitConv ) ) + aEnc = aAny; + break; + default: + SvXMLStyleContext::SetAttribute( nElement, rValue ); + break; + } +} + +XMLFontStyleContextFontFace::~XMLFontStyleContextFontFace() +{ +} + +void XMLFontStyleContextFontFace::FillProperties( + ::std::vector< XMLPropertyState > &rProps, + sal_Int32 nFamilyNameIdx, + sal_Int32 nStyleNameIdx, + sal_Int32 nFamilyIdx, + sal_Int32 nPitchIdx, + sal_Int32 nCharsetIdx ) const +{ + if( nFamilyNameIdx != -1 ) + { + XMLPropertyState aPropState( nFamilyNameIdx, aFamilyName ); + rProps.push_back( aPropState ); + } + if( nStyleNameIdx != -1 ) + { + XMLPropertyState aPropState( nStyleNameIdx, aStyleName ); + rProps.push_back( aPropState ); + } + if( nFamilyIdx != -1 ) + { + XMLPropertyState aPropState( nFamilyIdx, aFamily ); + rProps.push_back( aPropState ); + } + if( nPitchIdx != -1 ) + { + XMLPropertyState aPropState( nPitchIdx, aPitch ); + rProps.push_back( aPropState ); + } + if( nCharsetIdx != -1 ) + { + XMLPropertyState aPropState( nCharsetIdx, aEnc ); + rProps.push_back( aPropState ); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFontStyleContextFontFace::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & ) +{ + if( nElement == XML_ELEMENT(SVG, XML_FONT_FACE_SRC) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_FONT_FACE_SRC) ) + return new XMLFontStyleContextFontFaceSrc( GetImport(), *this ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +OUString XMLFontStyleContextFontFace::familyName() const +{ + OUString ret; + aFamilyName >>= ret; + return ret; +} + + +XMLFontStyleContextFontFaceFormat::XMLFontStyleContextFontFaceFormat( SvXMLImport& rImport, + XMLFontStyleContextFontFaceUri& _uri ) + : SvXMLStyleContext( rImport ) + , uri(_uri) +{ +} + +void XMLFontStyleContextFontFaceFormat::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(SVG, XML_STRING) || nElement == XML_ELEMENT(SVG_COMPAT, XML_STRING)) + uri.SetFormat(rValue); + else + SvXMLStyleContext::SetAttribute( nElement, rValue ); +} + + +XMLFontStyleContextFontFaceSrc::XMLFontStyleContextFontFaceSrc( SvXMLImport& rImport, + const XMLFontStyleContextFontFace& _font ) + : SvXMLImportContext( rImport ) + , font( _font ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFontStyleContextFontFaceSrc::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) +{ + if( nElement == XML_ELEMENT(SVG, XML_FONT_FACE_URI) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_FONT_FACE_URI) ) + return new XMLFontStyleContextFontFaceUri( GetImport(), font ); + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +XMLFontStyleContextFontFaceUri::XMLFontStyleContextFontFaceUri( SvXMLImport& rImport, + const XMLFontStyleContextFontFace& _font ) + : SvXMLStyleContext( rImport ) + , font( _font ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFontStyleContextFontFaceUri::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) +{ + if( nElement == XML_ELEMENT(SVG, XML_FONT_FACE_FORMAT) ) + return new XMLFontStyleContextFontFaceFormat( GetImport(), *this ); + else if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + assert(linkPath.isEmpty()); + if( linkPath.isEmpty() ) + { + mxBase64Stream.set( new comphelper::OSequenceOutputStream( maFontData ) ); + if( mxBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), mxBase64Stream ); + } + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLFontStyleContextFontFaceUri::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(XLINK, XML_HREF) ) + linkPath = rValue; + else + SvXMLStyleContext::SetAttribute( nElement, rValue ); +} + +void XMLFontStyleContextFontFaceUri::SetFormat( const OUString& rFormat ) +{ + format = rFormat; +} + +// the CSS2 standard ( http://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#referencing ) +// defines these format strings. +const char OPENTYPE_FORMAT[] = "opentype"; +const char TRUETYPE_FORMAT[] = "truetype"; +const char EOT_FORMAT[] = "embedded-opentype"; + +void XMLFontStyleContextFontFaceUri::endFastElement(sal_Int32 ) +{ + if( ( linkPath.getLength() == 0 ) && ( !maFontData.hasElements() ) ) + { + SAL_WARN( "xmloff", "svg:font-face-uri tag with no link or base64 data; ignoring." ); + return; + } + bool eot; + // Assume by default that the font is not compressed. + if( format.getLength() == 0 + || format == OPENTYPE_FORMAT + || format == TRUETYPE_FORMAT ) + { + eot = false; + } + else if( format == EOT_FORMAT ) + { + eot = true; + } + else + { + SAL_WARN( "xmloff", "Unknown format of embedded font; assuming TTF." ); + eot = false; + } + if ( !maFontData.hasElements() ) + handleEmbeddedFont( linkPath, eot ); + else + handleEmbeddedFont( maFontData, eot ); +} + +void XMLFontStyleContextFontFaceUri::handleEmbeddedFont( const OUString& url, bool eot ) +{ + if( GetImport().embeddedFontAlreadyProcessed( url )) + { + GetImport().NotifyContainsEmbeddedFont(); + return; + } + OUString fontName = font.familyName(); + // If there's any giveMeStreamForThisURL(), then it's well-hidden for me to find it. + if( GetImport().IsPackageURL( url )) + { + uno::Reference< embed::XStorage > storage; + storage.set( GetImport().GetSourceStorage(), UNO_SET_THROW ); + if( url.indexOf( '/' ) > -1 ) // TODO what if more levels? + storage.set( storage->openStorageElement( url.copy( 0, url.indexOf( '/' )), + ::embed::ElementModes::READ ), uno::UNO_SET_THROW ); + uno::Reference< io::XInputStream > inputStream; + inputStream.set( storage->openStreamElement( url.copy( url.indexOf( '/' ) + 1 ), ::embed::ElementModes::READ ), + UNO_QUERY_THROW ); + if (GetImport().addEmbeddedFont(inputStream, fontName, u"?", std::vector< unsigned char >(), eot)) + GetImport().NotifyContainsEmbeddedFont(); + inputStream->closeInput(); + } + else + SAL_WARN( "xmloff", "External URL for font file not handled." ); +} + +void XMLFontStyleContextFontFaceUri::handleEmbeddedFont( const ::css::uno::Sequence< sal_Int8 >& rData, const bool eot ) +{ + const uno::Reference< io::XInputStream > xInput( new comphelper::SequenceInputStream( rData ) ); + const OUString fontName = font.familyName(); + if (GetImport().addEmbeddedFont(xInput, fontName, u"?", std::vector< unsigned char >(), eot)) + GetImport().NotifyContainsEmbeddedFont(); + xInput->closeInput(); +} + +SvXMLStyleContext *XMLFontStylesContext::CreateStyleChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_FONT_FACE) ) + { + return new XMLFontStyleContextFontFace( GetImport(), *this ); + } + return SvXMLStylesContext::CreateStyleChildContext( nElement, xAttrList ); +} + + +XMLFontStylesContext::XMLFontStylesContext( SvXMLImport& rImport, + rtl_TextEncoding eDfltEnc ) : + SvXMLStylesContext( rImport ), + m_pFamilyNameHdl( new XMLFontFamilyNamePropHdl ), + m_pFamilyHdl( new XMLFontFamilyPropHdl ), + m_pPitchHdl( new XMLFontPitchPropHdl ), + m_pEncHdl( new XMLFontEncodingPropHdl ), + m_eDefaultEncoding( eDfltEnc ) +{ +} + +XMLFontStylesContext::~XMLFontStylesContext() {} + +bool XMLFontStylesContext::FillProperties( const OUString& rName, + ::std::vector< XMLPropertyState > &rProps, + sal_Int32 nFamilyNameIdx, + sal_Int32 nStyleNameIdx, + sal_Int32 nFamilyIdx, + sal_Int32 nPitchIdx, + sal_Int32 nCharsetIdx ) const +{ + const SvXMLStyleContext* pStyle = FindStyleChildContext( XML_STYLE_FAMILY_FONT, rName, true ); + const XMLFontStyleContextFontFace *pFontStyle = dynamic_cast<const XMLFontStyleContextFontFace*>(pStyle);// use temp var, PTR_CAST is a bad macro, FindStyleChildContext will be called twice + if( pFontStyle ) + pFontStyle->FillProperties( rProps, nFamilyNameIdx, nStyleNameIdx, + nFamilyIdx, nPitchIdx, nCharsetIdx ); + return nullptr != pFontStyle; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFontStylesContext_impl.hxx b/xmloff/source/style/XMLFontStylesContext_impl.hxx new file mode 100644 index 0000000000..b86bedbd12 --- /dev/null +++ b/xmloff/source/style/XMLFontStylesContext_impl.hxx @@ -0,0 +1,122 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlstyle.hxx> + +namespace com::sun::star::io { + class XOutputStream; +} + +/// Handles <style:font-face> +class XMLFontStyleContextFontFace : public SvXMLStyleContext +{ + css::uno::Any aFamilyName; + css::uno::Any aStyleName; + css::uno::Any aFamily; + css::uno::Any aPitch; + css::uno::Any aEnc; + + rtl::Reference<XMLFontStylesContext> xStyles; + + XMLFontStylesContext *GetStyles() + { + return xStyles.get(); + } + +public: + + + XMLFontStyleContextFontFace( SvXMLImport& rImport, + XMLFontStylesContext& rStyles ); + virtual ~XMLFontStyleContextFontFace() override; + + void SetAttribute( sal_Int32 nElement, + const OUString& rValue ) override; + + void FillProperties( ::std::vector< XMLPropertyState > &rProps, + sal_Int32 nFamilyNameIdx, + sal_Int32 nStyleNameIdx, + sal_Int32 nFamilyIdx, + sal_Int32 nPitchIdx, + sal_Int32 nCharsetIdx ) const; + + OUString familyName() const; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; +}; + +/// Handles <style:font-face-src> +class XMLFontStyleContextFontFaceSrc : public SvXMLImportContext +{ + const XMLFontStyleContextFontFace& font; +public: + + + XMLFontStyleContextFontFaceSrc( SvXMLImport& rImport, + const XMLFontStyleContextFontFace& font ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; +}; + +/// Handles <style:font-face-uri> +class XMLFontStyleContextFontFaceUri : public SvXMLStyleContext +{ + const XMLFontStyleContextFontFace& font; + OUString format; + OUString linkPath; + ::css::uno::Sequence< sal_Int8 > maFontData; + ::css::uno::Reference< ::css::io::XOutputStream > mxBase64Stream; + + void handleEmbeddedFont( const OUString& url, bool eot ); + void handleEmbeddedFont( const ::css::uno::Sequence< sal_Int8 >& rData, bool eot ); +public: + + + XMLFontStyleContextFontFaceUri( SvXMLImport& rImport, + const XMLFontStyleContextFontFace& font ); + + virtual void SetAttribute( sal_Int32 nElement, + const OUString& rValue ) override; + void SetFormat( const OUString& rFormat ); + void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; +}; + +/// Handles <svg:font-face-format> +class XMLFontStyleContextFontFaceFormat : public SvXMLStyleContext +{ + XMLFontStyleContextFontFaceUri& uri; +public: + + XMLFontStyleContextFontFaceFormat( SvXMLImport& rImport, + XMLFontStyleContextFontFaceUri& uri ); + + void SetAttribute( sal_Int32 nElement, + const OUString& rValue ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFootnoteSeparatorExport.cxx b/xmloff/source/style/XMLFootnoteSeparatorExport.cxx new file mode 100644 index 0000000000..c5e160dffd --- /dev/null +++ b/xmloff/source/style/XMLFootnoteSeparatorExport.cxx @@ -0,0 +1,179 @@ +/* -*- 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 "XMLFootnoteSeparatorExport.hxx" + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmlement.hxx> + +#include <PageMasterStyleMap.hxx> +#include <com/sun/star/text/HorizontalAdjust.hpp> +#include <rtl/ustrbuf.hxx> + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using ::std::vector; + +XMLFootnoteSeparatorExport::XMLFootnoteSeparatorExport(SvXMLExport& rExp) : + rExport(rExp) +{ +} + +void XMLFootnoteSeparatorExport::exportXML( + const vector<XMLPropertyState> * pProperties, + sal_uInt32 const nIdx, + const rtl::Reference<XMLPropertySetMapper> & rMapper) +{ + assert(pProperties); + + // initialize values + text::HorizontalAdjust eLineAdjust = text::HorizontalAdjust_LEFT; + sal_Int32 nLineColor = 0; + sal_Int32 nLineDistance = 0; + sal_Int8 nLineRelWidth = 0; + sal_Int32 nLineTextDistance = 0; + sal_Int16 nLineWeight = 0; + sal_Int8 nLineStyle = 0; + + // find indices into property map and get values + sal_uInt32 nCount = pProperties->size(); + for(sal_uInt32 i = 0; i < nCount; i++) + { + const XMLPropertyState& rState = (*pProperties)[i]; + + if( rState.mnIndex == -1 ) + continue; + + switch (rMapper->GetEntryContextId(rState.mnIndex)) + { + case CTF_PM_FTN_LINE_ADJUST: + { + sal_Int16 nTmp; + if (rState.maValue >>= nTmp) + eLineAdjust = static_cast<text::HorizontalAdjust>(nTmp); + break; + } + case CTF_PM_FTN_LINE_COLOR: + rState.maValue >>= nLineColor; + break; + case CTF_PM_FTN_DISTANCE: + rState.maValue >>= nLineDistance; + break; + case CTF_PM_FTN_LINE_WIDTH: + rState.maValue >>= nLineRelWidth; + break; + case CTF_PM_FTN_LINE_DISTANCE: + rState.maValue >>= nLineTextDistance; + break; + case CTF_PM_FTN_LINE_WEIGHT: + (void) nIdx; + assert(i == nIdx && "received wrong property state index"); + rState.maValue >>= nLineWeight; + break; + case CTF_PM_FTN_LINE_STYLE: + rState.maValue >>= nLineStyle; + break; + } + } + + OUStringBuffer sBuf; + + // weight/width + if (nLineWeight > 0) + { + rExport.GetMM100UnitConverter().convertMeasureToXML(sBuf, nLineWeight); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_WIDTH, + sBuf.makeStringAndClear()); + } + + // line text distance + if (nLineTextDistance > 0) + { + rExport.GetMM100UnitConverter().convertMeasureToXML(sBuf, + nLineTextDistance); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DISTANCE_BEFORE_SEP, + sBuf.makeStringAndClear()); + } + + // line distance + if (nLineDistance > 0) + { + rExport.GetMM100UnitConverter().convertMeasureToXML(sBuf, + nLineDistance); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DISTANCE_AFTER_SEP, + sBuf.makeStringAndClear()); + } + + // line style + static const SvXMLEnumMapEntry<sal_Int8> aXML_LineStyle_Enum[] = + { + { XML_NONE, 0 }, + { XML_SOLID, 1 }, + { XML_DOTTED, 2 }, + { XML_DASH, 3 }, + { XML_TOKEN_INVALID, 0 } + }; + if (SvXMLUnitConverter::convertEnum( + sBuf, nLineStyle, aXML_LineStyle_Enum ) ) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_LINE_STYLE, + sBuf.makeStringAndClear()); + } + + // adjustment + static const SvXMLEnumMapEntry<text::HorizontalAdjust> aXML_HorizontalAdjust_Enum[] = + { + { XML_LEFT, text::HorizontalAdjust_LEFT }, + { XML_CENTER, text::HorizontalAdjust_CENTER }, + { XML_RIGHT, text::HorizontalAdjust_RIGHT }, + { XML_TOKEN_INVALID, text::HorizontalAdjust(0) } + }; + + if (SvXMLUnitConverter::convertEnum( + sBuf, eLineAdjust, aXML_HorizontalAdjust_Enum)) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_ADJUSTMENT, + sBuf.makeStringAndClear()); + } + + // relative line width + ::sax::Converter::convertPercent(sBuf, nLineRelWidth); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_REL_WIDTH, + sBuf.makeStringAndClear()); + + // color + ::sax::Converter::convertColor(sBuf, nLineColor); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_COLOR, + sBuf.makeStringAndClear()); + + // line-style + + SvXMLElementExport aElem(rExport, XML_NAMESPACE_STYLE, + XML_FOOTNOTE_SEP, true, true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFootnoteSeparatorExport.hxx b/xmloff/source/style/XMLFootnoteSeparatorExport.hxx new file mode 100644 index 0000000000..2784e291b6 --- /dev/null +++ b/xmloff/source/style/XMLFootnoteSeparatorExport.hxx @@ -0,0 +1,50 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sal/types.h> +#include <vector> + +class SvXMLExport; +class XMLPropertySetMapper; +struct XMLPropertyState; +namespace rtl { + template<class X> class Reference; +} + +/** + * export footnote separator element in page styles + */ +class XMLFootnoteSeparatorExport +{ + SvXMLExport& rExport; + +public: + + explicit XMLFootnoteSeparatorExport(SvXMLExport& rExp); + + void exportXML( + const ::std::vector<XMLPropertyState> * pProperties, + sal_uInt32 nIdx, + /// used only for debugging + const rtl::Reference<XMLPropertySetMapper> & rMapper); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFootnoteSeparatorImport.cxx b/xmloff/source/style/XMLFootnoteSeparatorImport.cxx new file mode 100644 index 0000000000..6b3be1892c --- /dev/null +++ b/xmloff/source/style/XMLFootnoteSeparatorImport.cxx @@ -0,0 +1,198 @@ +/* -*- 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 "XMLFootnoteSeparatorImport.hxx" + +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/text/HorizontalAdjust.hpp> + + +#include <sax/tools/converter.hxx> + +#include <utility> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmlement.hxx> + +#include <PageMasterStyleMap.hxx> + +#include <vector> + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::std::vector; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + + +XMLFootnoteSeparatorImport::XMLFootnoteSeparatorImport( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + vector<XMLPropertyState> & rProps, + rtl::Reference<XMLPropertySetMapper> xMapperRef, + sal_Int32 nIndex) : + SvXMLImportContext(rImport), + rProperties(rProps), + rMapper(std::move(xMapperRef)), + nPropIndex(nIndex) +{ +} + +XMLFootnoteSeparatorImport::~XMLFootnoteSeparatorImport() +{ +} + +void XMLFootnoteSeparatorImport::startFastElement( + sal_Int32 /*nElement*/, + const Reference<css::xml::sax::XFastAttributeList> & xAttrList) +{ + // get the values from the properties + sal_Int16 nLineWeight = 0; + sal_Int32 nLineColor = 0; + sal_Int8 nLineRelWidth = 0; + text::HorizontalAdjust eLineAdjust = text::HorizontalAdjust_LEFT; + sal_Int32 nLineTextDistance = 0; + sal_Int32 nLineDistance = 0; + + // Default separator line style should be SOLID (used to be default before + // the choice selector was available) + sal_Int8 nLineStyle = 1; + + // iterate over xattribute list and fill values + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_WIDTH): + { + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nTmp, aIter.toView())) + { + nLineWeight = static_cast<sal_Int16>(nTmp); + } + break; + } + case XML_ELEMENT(STYLE, XML_DISTANCE_BEFORE_SEP): + { + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nTmp, aIter.toView())) + nLineTextDistance = nTmp; + break; + } + case XML_ELEMENT(STYLE, XML_DISTANCE_AFTER_SEP): + { + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nTmp, aIter.toView())) + nLineDistance = nTmp; + break; + } + case XML_ELEMENT(STYLE, XML_ADJUSTMENT ): + { + static const SvXMLEnumMapEntry<text::HorizontalAdjust> aXML_HorizontalAdjust_Enum[] = + { + { XML_LEFT, text::HorizontalAdjust_LEFT }, + { XML_CENTER, text::HorizontalAdjust_CENTER }, + { XML_RIGHT, text::HorizontalAdjust_RIGHT }, + { XML_TOKEN_INVALID, text::HorizontalAdjust(0) } + }; + + SvXMLUnitConverter::convertEnum( + eLineAdjust, aIter.toView(), aXML_HorizontalAdjust_Enum); + break; + } + case XML_ELEMENT(STYLE, XML_REL_WIDTH ): + { + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nLineRelWidth = static_cast<sal_uInt8>(nTmp); + break; + } + case XML_ELEMENT(STYLE, XML_COLOR): + { + if (::sax::Converter::convertColor(nTmp, aIter.toView())) + { + nLineColor = nTmp; + } + break; + } + case XML_ELEMENT(STYLE, XML_LINE_STYLE ): + { + static const SvXMLEnumMapEntry<sal_Int8> aXML_LineStyle_Enum[] = + { + { XML_NONE, 0 }, + { XML_SOLID, 1 }, + { XML_DOTTED, 2 }, + { XML_DASH, 3 }, + { XML_TOKEN_INVALID, 0 } + }; + + SvXMLUnitConverter::convertEnum(nLineStyle, aIter.toView(), aXML_LineStyle_Enum); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // OK, now we have all values and can fill the XMLPropertyState vector + sal_Int32 nIndex; + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_ADJUST); + XMLPropertyState aLineAdjust( nIndex, uno::Any(sal_Int16(eLineAdjust)) ); + rProperties.push_back(aLineAdjust); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_COLOR); + XMLPropertyState aLineColor( nIndex, uno::Any(nLineColor) ); + rProperties.push_back(aLineColor); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_STYLE); + XMLPropertyState aLineStyle( nIndex, uno::Any(nLineStyle) ); + rProperties.push_back(aLineStyle); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_DISTANCE); + XMLPropertyState aLineDistance( nIndex, uno::Any(nLineDistance) ); + rProperties.push_back(aLineDistance); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_WIDTH); + XMLPropertyState aLineRelWidth( nIndex, uno::Any(nLineRelWidth)); + rProperties.push_back(aLineRelWidth); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_DISTANCE); + XMLPropertyState aLineTextDistance( nIndex, uno::Any(nLineTextDistance)); + rProperties.push_back(aLineTextDistance); + + SAL_WARN_IF( rMapper->FindEntryIndex(CTF_PM_FTN_LINE_WEIGHT) != nPropIndex, "xmloff", + "Received wrong property map index!" ); + XMLPropertyState aLineWeight( nPropIndex, uno::Any(nLineWeight) ); + rProperties.push_back(aLineWeight); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFootnoteSeparatorImport.hxx b/xmloff/source/style/XMLFootnoteSeparatorImport.hxx new file mode 100644 index 0000000000..da14495563 --- /dev/null +++ b/xmloff/source/style/XMLFootnoteSeparatorImport.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlictxt.hxx> +#include <rtl/ref.hxx> +#include <vector> + + +class SvXMLImport; +struct XMLPropertyState; +class XMLPropertySetMapper; +namespace com::sun::star { + namespace uno { template<class X> class Reference; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import the footnote-separator element in page styles. + */ +class XMLFootnoteSeparatorImport : public SvXMLImportContext +{ + ::std::vector<XMLPropertyState> & rProperties; + rtl::Reference<XMLPropertySetMapper> rMapper; + sal_Int32 nPropIndex; + +public: + + + XMLFootnoteSeparatorImport( + SvXMLImport& rImport, + sal_Int32 nElement, + ::std::vector<XMLPropertyState> & rProperties, + rtl::Reference<XMLPropertySetMapper> xMapperRef, + sal_Int32 nIndex); + + virtual ~XMLFootnoteSeparatorImport() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLIsPercentagePropertyHandler.cxx b/xmloff/source/style/XMLIsPercentagePropertyHandler.cxx new file mode 100644 index 0000000000..3d32e8479a --- /dev/null +++ b/xmloff/source/style/XMLIsPercentagePropertyHandler.cxx @@ -0,0 +1,50 @@ +/* -*- 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 <com/sun/star/uno/Any.hxx> +#include <osl/diagnose.h> +#include <XMLIsPercentagePropertyHandler.hxx> + +using namespace ::com::sun::star; +using namespace css::uno; + + +XMLIsPercentagePropertyHandler::~XMLIsPercentagePropertyHandler() +{ +} + +bool XMLIsPercentagePropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + rValue <<= rStrImpValue.indexOf( '%' ) != -1; + return true; +} + +bool XMLIsPercentagePropertyHandler::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + OSL_FAIL( "XMLIsPercentagePropertyHandler is not for export!" ); + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLPageExport.cxx b/xmloff/source/style/XMLPageExport.cxx new file mode 100644 index 0000000000..c827eb14bd --- /dev/null +++ b/xmloff/source/style/XMLPageExport.cxx @@ -0,0 +1,318 @@ +/* -*- 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 <xmloff/XMLPageExport.hxx> +#include <o3tl/any.hxx> +#include <sal/log.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <xmloff/families.hxx> +#include <xmloff/xmlexp.hxx> +#include <PageMasterPropHdlFactory.hxx> +#include <PageMasterStyleMap.hxx> +#include <PageMasterPropMapper.hxx> +#include "PageMasterExportPropMapper.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +constexpr OUString gsIsPhysical( u"IsPhysical"_ustr ); +constexpr OUString gsFollowStyle( u"FollowStyle"_ustr ); + +namespace { + +bool findPageMasterNameEntry( + ::std::vector<XMLPageExportNameEntry> const& aNameVector, + const OUString& rStyleName, XMLPageExportNameEntry & o_rEntry) +{ + auto pEntry = std::find_if(aNameVector.cbegin(), aNameVector.cend(), + [&rStyleName](const XMLPageExportNameEntry& rEntry) { return rEntry.sStyleName == rStyleName; }); + + if( pEntry != aNameVector.cend() ) + { + o_rEntry = *pEntry; + return true; + } + + return false; +} + +} // namespace + +void XMLPageExport::collectPageMasterAutoStyle( + const Reference < XPropertySet > & rPropSet, + XMLPageExportNameEntry & rEntry) +{ + SAL_WARN_IF( !m_xPageMasterPropSetMapper.is(), "xmloff", "page master family/XMLPageMasterPropSetMapper not found" ); + if( m_xPageMasterPropSetMapper.is() ) + { + ::std::vector<XMLPropertyState> aPropStates = m_xPageMasterExportPropMapper->Filter(m_rExport, rPropSet); + if( !aPropStates.empty()) + { + OUString sParent; + rEntry.sPageMasterName = m_rExport.GetAutoStylePool()->Find( XmlStyleFamily::PAGE_MASTER, sParent, aPropStates ); + if (rEntry.sPageMasterName.isEmpty()) + { + rEntry.sPageMasterName = m_rExport.GetAutoStylePool()->Add(XmlStyleFamily::PAGE_MASTER, sParent, std::move(aPropStates)); + } + } + } + assert(m_xPageMasterDrawingPageExportPropMapper.is()); + ::std::vector<XMLPropertyState> aPropStates( + m_xPageMasterDrawingPageExportPropMapper->Filter(m_rExport, rPropSet)); + if (!aPropStates.empty()) + { + OUString sParent; + rEntry.sDrawingPageStyleName = m_rExport.GetAutoStylePool()->Find(XmlStyleFamily::SD_DRAWINGPAGE_ID, sParent, aPropStates); + if (rEntry.sDrawingPageStyleName.isEmpty()) + { + rEntry.sDrawingPageStyleName = m_rExport.GetAutoStylePool()->Add(XmlStyleFamily::SD_DRAWINGPAGE_ID, sParent, std::move(aPropStates)); + } + } +} + +void XMLPageExport::exportMasterPageContent( + const Reference < XPropertySet > &, + bool /*bAutoStyles*/ ) +{ + +} + +bool XMLPageExport::exportStyle( + const Reference< XStyle >& rStyle, + bool bAutoStyles ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + // Don't export styles that aren't existing really. This may be the + // case for StarOffice Writer's pool styles. + if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) ) + { + Any aAny = xPropSet->getPropertyValue( gsIsPhysical ); + if( !*o3tl::doAccess<bool>(aAny) ) + return false; + } + + if( bAutoStyles ) + { + XMLPageExportNameEntry aEntry; + collectPageMasterAutoStyle(xPropSet, aEntry); + aEntry.sStyleName = rStyle->getName(); + m_aNameVector.push_back( aEntry ); + + exportMasterPageContent( xPropSet, true ); + } + else + { + OUString sName( rStyle->getName() ); + bool bEncoded = false; + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, + GetExport().EncodeStyleName( sName, &bEncoded ) ); + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + uno::Any aValue = xPropSet->getPropertyValue( "Hidden" ); + bool bHidden = false; + if ((aValue >>= bHidden) && bHidden + && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDDEN, "true"); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility + } + } + + if( bEncoded ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, + sName); + + XMLPageExportNameEntry entry; + if (findPageMasterNameEntry(m_aNameVector, sName, entry)) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME, GetExport().EncodeStyleName(entry.sPageMasterName)); + if (!entry.sDrawingPageStyleName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, GetExport().EncodeStyleName(entry.sDrawingPageStyleName)); + } + } + + Reference<XPropertySetInfo> xInfo = xPropSet->getPropertySetInfo(); + if ( xInfo.is() && xInfo->hasPropertyByName(gsFollowStyle) ) + { + OUString sNextName; + xPropSet->getPropertyValue( gsFollowStyle ) >>= sNextName; + + if( sName != sNextName && !sNextName.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NEXT_STYLE_NAME, + GetExport().EncodeStyleName( sNextName ) ); + } + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_MASTER_PAGE, true, true ); + + exportMasterPageContent( xPropSet, false ); + } + + return true; +} + +XMLPageExport::XMLPageExport(SvXMLExport & rExp) + : m_rExport(rExp) + , m_xPageMasterPropHdlFactory(new XMLPageMasterPropHdlFactory) + , m_xPageMasterPropSetMapper(new XMLPageMasterPropSetMapper( + aXMLPageMasterStyleMap, + m_xPageMasterPropHdlFactory)) + , m_xPageMasterExportPropMapper(new XMLPageMasterExportPropMapper( + m_xPageMasterPropSetMapper, rExp)) + , m_xPageMasterDrawingPagePropSetMapper(new XMLPageMasterPropSetMapper( + g_XMLPageMasterDrawingPageStyleMap, + m_xPageMasterPropHdlFactory)) + // use same class but with different map, need its ContextFilter() + , m_xPageMasterDrawingPageExportPropMapper(new XMLPageMasterExportPropMapper( + m_xPageMasterDrawingPagePropSetMapper, rExp)) +{ + m_rExport.GetAutoStylePool()->AddFamily( XmlStyleFamily::PAGE_MASTER, XML_STYLE_FAMILY_PAGE_MASTER_NAME, + m_xPageMasterExportPropMapper, XML_STYLE_FAMILY_PAGE_MASTER_PREFIX, false ); + m_rExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::SD_DRAWINGPAGE_ID, XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME, + m_xPageMasterDrawingPageExportPropMapper, XML_STYLE_FAMILY_SD_DRAWINGPAGE_PREFIX); + + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), + UNO_QUERY ); + SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", + "No XStyleFamiliesSupplier from XModel for export!" ); + if( !xFamiliesSupp.is() ) + return; + + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", + "getStyleFamilies() from XModel failed for export!" ); + if( xFamilies.is() ) + { + static constexpr OUString aPageStyleName(u"PageStyles"_ustr); + + if( xFamilies->hasByName( aPageStyleName ) ) + { + m_xPageStyles.set(xFamilies->getByName( aPageStyleName ),uno::UNO_QUERY); + + SAL_WARN_IF( !m_xPageStyles.is(), "xmloff", + "Page Styles not found for export!" ); + } + } + + if (GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITER) + return; + + uno::Reference<lang::XMultiServiceFactory> xFac(GetExport().GetModel(), uno::UNO_QUERY); + if (!xFac.is()) + return; + + uno::Reference<beans::XPropertySet> xProps( + xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY); + if (!xProps.is()) + return; + + bool bGutterAtTop{}; + xProps->getPropertyValue("GutterAtTop") >>= bGutterAtTop; + if (bGutterAtTop) + { + m_xPageMasterExportPropMapper->SetGutterAtTop(true); + } +} + +XMLPageExport::~XMLPageExport() +{ +} + +void XMLPageExport::exportStyles( bool bUsed, bool bAutoStyles ) +{ + if( m_xPageStyles.is() ) + { + const uno::Sequence< OUString> aSeq = m_xPageStyles->getElementNames(); + for(const auto& rName : aSeq) + { + Reference< XStyle > xStyle(m_xPageStyles->getByName( rName ),uno::UNO_QUERY); + if( !bUsed || xStyle->isInUse() ) + exportStyle( xStyle, bAutoStyles ); + } + } +} + +void XMLPageExport::exportAutoStyles() +{ + m_rExport.GetAutoStylePool()->exportXML(XmlStyleFamily::PAGE_MASTER); + // tdf#103602 this is called by both Writer and Calc but Calc doesn't + // have fill properties yet + m_rExport.GetAutoStylePool()->exportXML(XmlStyleFamily::SD_DRAWINGPAGE_ID); +} + +void XMLPageExport::exportDefaultStyle() +{ + Reference < lang::XMultiServiceFactory > xFactory (GetExport().GetModel(), UNO_QUERY); + if (!xFactory.is()) + return; + + Reference < XPropertySet > xPropSet (xFactory->createInstance ( "com.sun.star.text.Defaults" ), UNO_QUERY); + if (!xPropSet.is()) + return; + + // <style:default-style ...> + GetExport().CheckAttrList(); + + ::std::vector< XMLPropertyState > aPropStates = + m_xPageMasterExportPropMapper->FilterDefaults(m_rExport, xPropSet); + + bool bExport = false; + rtl::Reference < XMLPropertySetMapper > aPropMapper(m_xPageMasterExportPropMapper->getPropertySetMapper()); + for( const auto& rProp : aPropStates ) + { + sal_Int16 nContextId = aPropMapper->GetEntryContextId( rProp.mnIndex ); + if( nContextId == CTF_PM_STANDARD_MODE ) + { + bExport = true; + break; + } + } + + if( !bExport ) + return; + + assert(GetExport().getSaneDefaultVersion() + >= SvtSaveOptions::ODFSVER_012); + + //<style:default-page-layout> + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_DEFAULT_PAGE_LAYOUT, + true, true ); + + m_xPageMasterExportPropMapper->exportXML( GetExport(), aPropStates, + SvXmlExportFlags::IGN_WS ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLPercentOrMeasurePropertyHandler.cxx b/xmloff/source/style/XMLPercentOrMeasurePropertyHandler.cxx new file mode 100644 index 0000000000..d49174c359 --- /dev/null +++ b/xmloff/source/style/XMLPercentOrMeasurePropertyHandler.cxx @@ -0,0 +1,75 @@ +/* -*- 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 <XMLPercentOrMeasurePropertyHandler.hxx> + +#include <rtl/ustrbuf.hxx> + +#include <com/sun/star/uno/Any.hxx> + +#include <xmloff/xmluconv.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLPercentOrMeasurePropertyHandler::XMLPercentOrMeasurePropertyHandler() +{ +} + +XMLPercentOrMeasurePropertyHandler::~XMLPercentOrMeasurePropertyHandler() +{ +} + +bool XMLPercentOrMeasurePropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + if( rStrImpValue.indexOf( '%' ) != -1 ) + return false; + + sal_Int32 nValue; + + if (!rUnitConverter.convertMeasureToCore( nValue, rStrImpValue )) + return false; + + rValue <<= nValue; + return true; +} + +bool XMLPercentOrMeasurePropertyHandler::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + sal_Int32 nValue = 0; + if( !(rValue >>= nValue ) ) + return false; + + rUnitConverter.convertMeasureToXML( aOut, nValue ); + + rStrExpValue = aOut.makeStringAndClear(); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLRectangleMembersHandler.cxx b/xmloff/source/style/XMLRectangleMembersHandler.cxx new file mode 100644 index 0000000000..5a80cd0c14 --- /dev/null +++ b/xmloff/source/style/XMLRectangleMembersHandler.cxx @@ -0,0 +1,112 @@ +/* -*- 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 <xmloff/xmluconv.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> + +#include <com/sun/star/awt/Rectangle.hpp> +#include <XMLRectangleMembersHandler.hxx> +#include <xmloff/xmltypes.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLRectangleMembersHdl::XMLRectangleMembersHdl( sal_Int32 nType ) +: mnType( nType ) +{ +} + +XMLRectangleMembersHdl::~XMLRectangleMembersHdl() +{ +} + +bool XMLRectangleMembersHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + awt::Rectangle aRect( 0, 0, 0, 0 ); + if( rValue.hasValue() ) + rValue >>= aRect; + + sal_Int32 nValue; + + if (rUnitConverter.convertMeasureToCore( nValue, rStrImpValue )) + { + switch( mnType ) + { + case XML_TYPE_RECTANGLE_LEFT : + aRect.X = nValue; + break; + case XML_TYPE_RECTANGLE_TOP : + aRect.Y = nValue; + break; + case XML_TYPE_RECTANGLE_WIDTH : + aRect.Width = nValue; + break; + case XML_TYPE_RECTANGLE_HEIGHT : + aRect.Height = nValue; + break; + } + + rValue <<= aRect; + return true; + } + + return false; +} + +bool XMLRectangleMembersHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + awt::Rectangle aRect( 0, 0, 0, 0 ); + rValue >>= aRect; + + sal_Int32 nValue; + + switch( mnType ) + { + case XML_TYPE_RECTANGLE_LEFT : + nValue = aRect.X; + break; + case XML_TYPE_RECTANGLE_TOP : + nValue = aRect.Y; + break; + case XML_TYPE_RECTANGLE_WIDTH : + nValue = aRect.Width; + break; + case XML_TYPE_RECTANGLE_HEIGHT : + nValue = aRect.Height; + break; + default: + nValue = 0; // TODO What value should this be? + break; + } + + OUStringBuffer sBuffer; + rUnitConverter.convertMeasureToXML( sBuffer, nValue ); + rStrExpValue = sBuffer.makeStringAndClear(); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLRtlGutterPropertyHandler.cxx b/xmloff/source/style/XMLRtlGutterPropertyHandler.cxx new file mode 100644 index 0000000000..d5d94bdb44 --- /dev/null +++ b/xmloff/source/style/XMLRtlGutterPropertyHandler.cxx @@ -0,0 +1,55 @@ +/* -*- 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 <XMLRtlGutterPropertyHandler.hxx> +#include <frozen/bits/defines.h> +#include <frozen/bits/elsa_std.h> +#include <frozen/unordered_set.h> +#include <com/sun/star/uno/Any.hxx> +#include <xmloff/xmluconv.hxx> + +using namespace com::sun::star; + +XMLRtlGutterPropertyHandler::XMLRtlGutterPropertyHandler() = default; + +XMLRtlGutterPropertyHandler::~XMLRtlGutterPropertyHandler() = default; + +namespace +{ +constexpr frozen::unordered_set<std::u16string_view, 4> constRtlModes{ u"rl-tb", u"tb-rl", u"rl", + u"tb" }; +} // end anonymous ns + +bool XMLRtlGutterPropertyHandler::importXML(const OUString& rStrImpValue, uno::Any& rValue, + const SvXMLUnitConverter&) const +{ + // Infer RtlGutter from WritingMode. + auto it = constRtlModes.find(rStrImpValue); + rValue <<= (it != constRtlModes.end()); + return true; +} + +bool XMLRtlGutterPropertyHandler::exportXML(OUString&, const uno::Any&, + const SvXMLUnitConverter&) const +{ + // No need to export RtlGutter. + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLThemeContext.cxx b/xmloff/source/style/XMLThemeContext.cxx new file mode 100644 index 0000000000..564d934ff8 --- /dev/null +++ b/xmloff/source/style/XMLThemeContext.cxx @@ -0,0 +1,176 @@ +/* -*- 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/. + */ + +#include <XMLThemeContext.hxx> + +#include <xmloff/maptype.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlprcon.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlprhdl.hxx> + +#include <sal/log.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <sax/tools/converter.hxx> +#include <comphelper/sequence.hxx> + +#include <docmodel/uno/UnoTheme.hxx> +#include <docmodel/theme/Theme.hxx> + +using namespace css; +using namespace xmloff::token; + +XMLThemeContext::XMLThemeContext( + SvXMLImport& rImport, const uno::Reference<xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference<css::uno::XInterface> const& xObjectWithThemeProperty) + : SvXMLImportContext(rImport) + , m_xObjectWithThemeProperty(xObjectWithThemeProperty) + , mpTheme(new model::Theme) +{ + for (const auto& rAttribute : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rAttribute.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_NAME): + { + OUString aName = rAttribute.toString(); + mpTheme->SetName(aName); + break; + } + } + } +} + +XMLThemeContext::~XMLThemeContext() +{ + if (mpTheme && mpTheme->getColorSet()) + { + uno::Reference<beans::XPropertySet> xPropertySet(m_xObjectWithThemeProperty, + uno::UNO_QUERY); + auto xTheme = model::theme::createXTheme(mpTheme); + xPropertySet->setPropertyValue("Theme", uno::Any(xTheme)); + } +} + +uno::Reference<xml::sax::XFastContextHandler> SAL_CALL XMLThemeContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference<xml::sax::XFastAttributeList>& xAttribs) +{ + if (nElement == XML_ELEMENT(LO_EXT, XML_THEME_COLORS)) + { + return new XMLThemeColorsContext(GetImport(), xAttribs, *mpTheme); + } + + return nullptr; +} + +XMLThemeColorsContext::XMLThemeColorsContext( + SvXMLImport& rImport, const uno::Reference<xml::sax::XFastAttributeList>& xAttrList, + model::Theme& rTheme) + : SvXMLImportContext(rImport) + , mrTheme(rTheme) +{ + for (const auto& rAttribute : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rAttribute.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_NAME): + { + OUString aName = rAttribute.toString(); + m_pColorSet.reset(new model::ColorSet(aName)); + break; + } + } + } +} + +XMLThemeColorsContext::~XMLThemeColorsContext() +{ + if (m_pColorSet) + mrTheme.setColorSet(m_pColorSet); +} + +uno::Reference<xml::sax::XFastContextHandler> + SAL_CALL XMLThemeColorsContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference<xml::sax::XFastAttributeList>& xAttribs) +{ + if (nElement == XML_ELEMENT(LO_EXT, XML_COLOR)) + { + if (m_pColorSet) + return new XMLColorContext(GetImport(), xAttribs, m_pColorSet); + } + + return nullptr; +} + +XMLColorContext::XMLColorContext(SvXMLImport& rImport, + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList, + std::shared_ptr<model::ColorSet>& rpColorSet) + : SvXMLImportContext(rImport) +{ + OUString aName; + ::Color aColor; + + for (const auto& rAttribute : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rAttribute.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_NAME): + { + aName = rAttribute.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_COLOR): + { + sax::Converter::convertColor(aColor, rAttribute.toView()); + break; + } + } + } + + if (!aName.isEmpty()) + { + auto eType = model::ThemeColorType::Unknown; + if (aName == u"dark1") + eType = model::ThemeColorType::Dark1; + else if (aName == u"light1") + eType = model::ThemeColorType::Light1; + else if (aName == u"dark2") + eType = model::ThemeColorType::Dark2; + else if (aName == u"light2") + eType = model::ThemeColorType::Light2; + else if (aName == u"accent1") + eType = model::ThemeColorType::Accent1; + else if (aName == u"accent2") + eType = model::ThemeColorType::Accent2; + else if (aName == u"accent3") + eType = model::ThemeColorType::Accent3; + else if (aName == u"accent4") + eType = model::ThemeColorType::Accent4; + else if (aName == u"accent5") + eType = model::ThemeColorType::Accent5; + else if (aName == u"accent6") + eType = model::ThemeColorType::Accent6; + else if (aName == u"hyperlink") + eType = model::ThemeColorType::Hyperlink; + else if (aName == u"followed-hyperlink") + eType = model::ThemeColorType::FollowedHyperlink; + + if (eType != model::ThemeColorType::Unknown) + { + rpColorSet->add(eType, aColor); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/adjushdl.cxx b/xmloff/source/style/adjushdl.cxx new file mode 100644 index 0000000000..41a93d57f6 --- /dev/null +++ b/xmloff/source/style/adjushdl.cxx @@ -0,0 +1,121 @@ +/* -*- 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 "adjushdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/style/ParagraphAdjust.hpp> +#include <com/sun/star/uno/Any.hxx> + +using namespace ::com::sun::star; + +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<style::ParagraphAdjust> const pXML_Para_Adjust_Enum[] = +{ + { XML_START, style::ParagraphAdjust_LEFT }, + { XML_END, style::ParagraphAdjust_RIGHT }, + { XML_CENTER, style::ParagraphAdjust_CENTER }, + { XML_JUSTIFY, style::ParagraphAdjust_BLOCK }, + { XML_JUSTIFIED, style::ParagraphAdjust_BLOCK }, // obsolete + { XML_LEFT, style::ParagraphAdjust_LEFT }, + { XML_RIGHT, style::ParagraphAdjust_RIGHT }, + { XML_TOKEN_INVALID, style::ParagraphAdjust(0) } +}; + +SvXMLEnumMapEntry<style::ParagraphAdjust> const pXML_Para_Align_Last_Enum[] = +{ + { XML_START, style::ParagraphAdjust_LEFT }, + { XML_CENTER, style::ParagraphAdjust_CENTER }, + { XML_JUSTIFY, style::ParagraphAdjust_BLOCK }, + { XML_JUSTIFIED, style::ParagraphAdjust_BLOCK }, // obsolete + { XML_TOKEN_INVALID, style::ParagraphAdjust(0) } +}; + + + + +XMLParaAdjustPropHdl::~XMLParaAdjustPropHdl() +{ + // nothing to do +} + +bool XMLParaAdjustPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + style::ParagraphAdjust eAdjust; + bool bRet = SvXMLUnitConverter::convertEnum( eAdjust, rStrImpValue, pXML_Para_Adjust_Enum ); + if( bRet ) + rValue <<= static_cast<sal_Int16>(eAdjust); + + return bRet; +} + +bool XMLParaAdjustPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if(!rValue.hasValue()) + return false; + OUStringBuffer aOut; + sal_Int16 nVal = 0; + + rValue >>= nVal; + + bool bRet = SvXMLUnitConverter::convertEnum( aOut, static_cast<style::ParagraphAdjust>(nVal), pXML_Para_Adjust_Enum, XML_START ); + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + + + + +XMLLastLineAdjustPropHdl::~XMLLastLineAdjustPropHdl() +{ + // nothing to do +} + +bool XMLLastLineAdjustPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + style::ParagraphAdjust eAdjust; + bool bRet = SvXMLUnitConverter::convertEnum( eAdjust, rStrImpValue, pXML_Para_Align_Last_Enum ); + if( bRet ) + rValue <<= static_cast<sal_Int16>(eAdjust); + + return bRet; +} + +bool XMLLastLineAdjustPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut; + sal_Int16 nVal = 0; + bool bRet = false; + + rValue >>= nVal; + + if( static_cast<style::ParagraphAdjust>(nVal) != style::ParagraphAdjust_LEFT ) + bRet = SvXMLUnitConverter::convertEnum( aOut, static_cast<style::ParagraphAdjust>(nVal), pXML_Para_Align_Last_Enum, XML_START ); + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/adjushdl.hxx b/xmloff/source/style/adjushdl.hxx new file mode 100644 index 0000000000..5de0551639 --- /dev/null +++ b/xmloff/source/style/adjushdl.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLParaAdjustPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLParaAdjustPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLLastLineAdjustPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLLastLineAdjustPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/backhdl.cxx b/xmloff/source/style/backhdl.cxx new file mode 100644 index 0000000000..4df7a2f6e5 --- /dev/null +++ b/xmloff/source/style/backhdl.cxx @@ -0,0 +1,285 @@ +/* -*- 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 "backhdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <sax/tools/converter.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<style::GraphicLocation> const pXML_BrushHorizontalPos[] = +{ + { XML_LEFT, style::GraphicLocation_LEFT_MIDDLE }, + { XML_RIGHT, style::GraphicLocation_RIGHT_MIDDLE }, + { XML_TOKEN_INVALID, style::GraphicLocation(0) } +}; + +SvXMLEnumMapEntry<style::GraphicLocation> const pXML_BrushVerticalPos[] = +{ + { XML_TOP, style::GraphicLocation_MIDDLE_TOP }, + { XML_BOTTOM, style::GraphicLocation_MIDDLE_BOTTOM }, + { XML_TOKEN_INVALID, style::GraphicLocation(0) } +}; + + + + +XMLBackGraphicPositionPropHdl::~XMLBackGraphicPositionPropHdl() +{ + // Nothing to do +} + +bool XMLBackGraphicPositionPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = true; + style::GraphicLocation ePos = style::GraphicLocation_NONE, eTmp; + style::GraphicLocation nTmpGraphicLocation; + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + std::u16string_view aToken; + bool bHori = false, bVert = false; + + while( bRet && aTokenEnum.getNextToken( aToken ) ) + { + if( bHori && bVert ) + { + bRet = false; + } + else if( std::u16string_view::npos != aToken.find( '%' ) ) + { + sal_Int32 nPrc = 50; + if (::sax::Converter::convertPercent( nPrc, aToken )) + { + if( !bHori ) + { + ePos = nPrc < 25 ? style::GraphicLocation_LEFT_TOP : + (nPrc < 75 ? style::GraphicLocation_MIDDLE_MIDDLE : + style::GraphicLocation_RIGHT_BOTTOM); + bHori = true; + } + else + { + eTmp = nPrc < 25 ? style::GraphicLocation_LEFT_TOP: + (nPrc < 75 ? style::GraphicLocation_LEFT_MIDDLE : + style::GraphicLocation_LEFT_BOTTOM); + MergeXMLVertPos( ePos, eTmp ); + bVert = true; + } + } + else + { + // wrong percentage + bRet = false; + } + } + else if( IsXMLToken( aToken, XML_CENTER ) ) + { + if( bHori ) + MergeXMLVertPos( ePos, style::GraphicLocation_MIDDLE_MIDDLE ); + else if ( bVert ) + MergeXMLHoriPos( ePos, style::GraphicLocation_MIDDLE_MIDDLE ); + else + ePos = style::GraphicLocation_MIDDLE_MIDDLE; + } + else if( SvXMLUnitConverter::convertEnum( nTmpGraphicLocation, aToken, pXML_BrushHorizontalPos ) ) + { + if( bVert ) + MergeXMLHoriPos( ePos, nTmpGraphicLocation ); + else if( !bHori ) + ePos = nTmpGraphicLocation; + else + bRet = false; + + bHori = true; + } + else if( SvXMLUnitConverter::convertEnum( nTmpGraphicLocation, aToken, pXML_BrushVerticalPos ) ) + { + if( bHori ) + MergeXMLVertPos( ePos, nTmpGraphicLocation ); + else if( !bVert ) + ePos = nTmpGraphicLocation; + else + bRet = false; + bVert = true; + } + else + { + bRet = false; + } + } + + bRet &= style::GraphicLocation_NONE != ePos; + if( bRet ) + rValue <<= static_cast<style::GraphicLocation>(static_cast<sal_uInt16>(ePos)); + + return bRet; +} + +bool XMLBackGraphicPositionPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = true; + OUStringBuffer aOut; + + style::GraphicLocation eLocation; + if( !( rValue >>= eLocation ) ) + { + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + eLocation = static_cast<style::GraphicLocation>(nValue); + else + bRet = false; + } + + if( bRet ) + { + bRet = false; + + switch( eLocation ) + { + case style::GraphicLocation_LEFT_TOP: + case style::GraphicLocation_MIDDLE_TOP: + case style::GraphicLocation_RIGHT_TOP: + aOut.append( GetXMLToken(XML_TOP) ); + bRet = true; + break; + case style::GraphicLocation_LEFT_MIDDLE: + case style::GraphicLocation_MIDDLE_MIDDLE: + case style::GraphicLocation_RIGHT_MIDDLE: + aOut.append( GetXMLToken(XML_CENTER) ); + bRet = true; + break; + case style::GraphicLocation_LEFT_BOTTOM: + case style::GraphicLocation_MIDDLE_BOTTOM: + case style::GraphicLocation_RIGHT_BOTTOM: + aOut.append( GetXMLToken(XML_BOTTOM) ); + bRet = true; + break; + default: + break; + } + + if( bRet ) + { + aOut.append( ' ' ); + + switch( eLocation ) + { + case style::GraphicLocation_LEFT_TOP: + case style::GraphicLocation_LEFT_BOTTOM: + case style::GraphicLocation_LEFT_MIDDLE: + aOut.append( GetXMLToken(XML_LEFT) ); + break; + case style::GraphicLocation_MIDDLE_TOP: + case style::GraphicLocation_MIDDLE_MIDDLE: + case style::GraphicLocation_MIDDLE_BOTTOM: + aOut.append( GetXMLToken(XML_CENTER) ); + break; + case style::GraphicLocation_RIGHT_MIDDLE: + case style::GraphicLocation_RIGHT_TOP: + case style::GraphicLocation_RIGHT_BOTTOM: + aOut.append( GetXMLToken(XML_RIGHT) ); + break; + default: + break; + } + } + } + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +void XMLBackGraphicPositionPropHdl::MergeXMLVertPos( style::GraphicLocation& ePos, style::GraphicLocation eVert ) +{ + switch( ePos ) + { + case style::GraphicLocation_LEFT_TOP: + case style::GraphicLocation_LEFT_MIDDLE: + case style::GraphicLocation_LEFT_BOTTOM: + ePos = style::GraphicLocation_MIDDLE_TOP==eVert ? + style::GraphicLocation_LEFT_TOP : + (style::GraphicLocation_MIDDLE_MIDDLE==eVert ? + style::GraphicLocation_LEFT_MIDDLE : + style::GraphicLocation_LEFT_BOTTOM); + break; + + case style::GraphicLocation_MIDDLE_TOP: + case style::GraphicLocation_MIDDLE_MIDDLE: + case style::GraphicLocation_MIDDLE_BOTTOM: + ePos = eVert; + break; + + case style::GraphicLocation_RIGHT_TOP: + case style::GraphicLocation_RIGHT_MIDDLE: + case style::GraphicLocation_RIGHT_BOTTOM: + ePos = style::GraphicLocation_MIDDLE_TOP==eVert ? + style::GraphicLocation_RIGHT_TOP : + (style::GraphicLocation_MIDDLE_MIDDLE==eVert ? + style::GraphicLocation_RIGHT_MIDDLE : + style::GraphicLocation_RIGHT_BOTTOM); + break; + default: + break; + } +} + +void XMLBackGraphicPositionPropHdl::MergeXMLHoriPos( style::GraphicLocation& ePos, style::GraphicLocation eHori ) +{ + SAL_WARN_IF( !(style::GraphicLocation_LEFT_MIDDLE==eHori || style::GraphicLocation_MIDDLE_MIDDLE==eHori || style::GraphicLocation_RIGHT_MIDDLE==eHori), "xmloff", + "lcl_frmitems_MergeXMLHoriPos: vertical pos must be middle" ); + + switch( ePos ) + { + case style::GraphicLocation_LEFT_TOP: + case style::GraphicLocation_MIDDLE_TOP: + case style::GraphicLocation_RIGHT_TOP: + ePos = style::GraphicLocation_LEFT_MIDDLE==eHori ? + style::GraphicLocation_LEFT_TOP : + (style::GraphicLocation_MIDDLE_MIDDLE==eHori ? + style::GraphicLocation_MIDDLE_TOP : + style::GraphicLocation_RIGHT_TOP); + break; + + case style::GraphicLocation_LEFT_MIDDLE: + case style::GraphicLocation_MIDDLE_MIDDLE: + case style::GraphicLocation_RIGHT_MIDDLE: + ePos = eHori; + break; + + case style::GraphicLocation_LEFT_BOTTOM: + case style::GraphicLocation_MIDDLE_BOTTOM: + case style::GraphicLocation_RIGHT_BOTTOM: + ePos = style::GraphicLocation_LEFT_MIDDLE==eHori ? + style::GraphicLocation_LEFT_BOTTOM : + (style::GraphicLocation_MIDDLE_MIDDLE==eHori ? + style::GraphicLocation_MIDDLE_BOTTOM : + style::GraphicLocation_RIGHT_BOTTOM); + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/backhdl.hxx b/xmloff/source/style/backhdl.hxx new file mode 100644 index 0000000000..0392909df9 --- /dev/null +++ b/xmloff/source/style/backhdl.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> +#include <com/sun/star/style/GraphicLocation.hpp> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLBackGraphicPositionPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLBackGraphicPositionPropHdl() override; + + /// TabStops will be imported/exported as XML-Elements. So the Import/Export-work must be done at another place. + using XMLPropertyHandler::importXML; + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + +private: + static void MergeXMLHoriPos( css::style::GraphicLocation& ePos, css::style::GraphicLocation eHori ); + static void MergeXMLVertPos( css::style::GraphicLocation& ePos, css::style::GraphicLocation eVert ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/bordrhdl.cxx b/xmloff/source/style/bordrhdl.cxx new file mode 100644 index 0000000000..d04d3f2f85 --- /dev/null +++ b/xmloff/source/style/bordrhdl.cxx @@ -0,0 +1,349 @@ +/* -*- 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 "bordrhdl.hxx" +#include <sax/tools/converter.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/table/BorderLine2.hpp> +#include <com/sun/star/table/BorderLineStyle.hpp> + +#include <limits.h> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +#define DEF_LINE_WIDTH_0 1 +#define DEF_LINE_WIDTH_1 35 +#define DEF_LINE_WIDTH_2 88 + +#define SVX_XML_BORDER_WIDTH_THIN 0 +#define SVX_XML_BORDER_WIDTH_MIDDLE 1 +#define SVX_XML_BORDER_WIDTH_THICK 2 + +SvXMLEnumMapEntry<sal_uInt16> const pXML_BorderStyles[] = +{ + { XML_NONE, table::BorderLineStyle::NONE }, + { XML_HIDDEN, table::BorderLineStyle::NONE }, + { XML_SOLID, table::BorderLineStyle::SOLID }, + { XML_DOUBLE, table::BorderLineStyle::DOUBLE }, + { XML_DOUBLE_THIN, table::BorderLineStyle::DOUBLE_THIN }, + { XML_DOTTED, table::BorderLineStyle::DOTTED }, + { XML_DASHED, table::BorderLineStyle::DASHED }, + { XML_GROOVE, table::BorderLineStyle::ENGRAVED }, + { XML_RIDGE, table::BorderLineStyle::EMBOSSED }, + { XML_INSET, table::BorderLineStyle::INSET }, + { XML_OUTSET, table::BorderLineStyle::OUTSET }, + { XML_FINE_DASHED, table::BorderLineStyle::FINE_DASHED }, + { XML_DASH_DOT, table::BorderLineStyle::DASH_DOT }, + { XML_DASH_DOT_DOT, table::BorderLineStyle::DASH_DOT_DOT }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_NamedBorderWidths[] = +{ + { XML_THIN, SVX_XML_BORDER_WIDTH_THIN }, + { XML_MIDDLE, SVX_XML_BORDER_WIDTH_MIDDLE }, + { XML_THICK, SVX_XML_BORDER_WIDTH_THICK }, + { XML_TOKEN_INVALID, 0 } +}; +// mapping tables to map external xml input to internal box line widths + +sal_uInt16 const aBorderWidths[] = +{ + DEF_LINE_WIDTH_0, + DEF_LINE_WIDTH_1, + DEF_LINE_WIDTH_2 +}; + +static void lcl_frmitems_setXMLBorderStyle( table::BorderLine2 & rBorderLine, sal_uInt16 nStyle ) +{ + sal_Int16 eStyle = -1; // None + if (nStyle != table::BorderLineStyle::NONE) + eStyle = sal_Int16( nStyle ); + + rBorderLine.LineStyle = eStyle; +} + + + + +XMLBorderWidthHdl::~XMLBorderWidthHdl() +{ + // nothing to do +} + +bool XMLBorderWidthHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + + sal_Int32 nInWidth, nDistance, nOutWidth; + + std::u16string_view aToken; + if( !aTokenEnum.getNextToken( aToken ) ) + return false; + + if (!rUnitConverter.convertMeasureToCore( nInWidth, aToken, 0, 500 )) + return false; + + if( !aTokenEnum.getNextToken( aToken ) ) + return false; + + if (!rUnitConverter.convertMeasureToCore( nDistance, aToken, 0, 500 )) + return false; + + if( !aTokenEnum.getNextToken( aToken ) ) + return false; + + if (!rUnitConverter.convertMeasureToCore( nOutWidth, aToken, 0, 500 )) + return false; + + table::BorderLine2 aBorderLine; + if(!(rValue >>= aBorderLine)) + aBorderLine.Color = 0; + + aBorderLine.InnerLineWidth = sal::static_int_cast< sal_Int16 >(nInWidth); + aBorderLine.OuterLineWidth = sal::static_int_cast< sal_Int16 >(nOutWidth); + aBorderLine.LineDistance = sal::static_int_cast< sal_Int16 >(nDistance); + + rValue <<= aBorderLine; + return true; +} + +bool XMLBorderWidthHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + table::BorderLine2 aBorderLine; + if(!(rValue >>= aBorderLine)) + return false; + + bool bDouble = false; + switch ( aBorderLine.LineStyle ) + { + case table::BorderLineStyle::DOUBLE: + case table::BorderLineStyle::DOUBLE_THIN: + case table::BorderLineStyle::THINTHICK_SMALLGAP: + case table::BorderLineStyle::THINTHICK_MEDIUMGAP: + case table::BorderLineStyle::THINTHICK_LARGEGAP: + case table::BorderLineStyle::THICKTHIN_SMALLGAP: + case table::BorderLineStyle::THICKTHIN_MEDIUMGAP: + case table::BorderLineStyle::THICKTHIN_LARGEGAP: + bDouble = true; + break; + default: + break; + } + + if( ( aBorderLine.LineDistance == 0 && aBorderLine.InnerLineWidth == 0 ) || !bDouble ) + return false; + + rUnitConverter.convertMeasureToXML( aOut, aBorderLine.InnerLineWidth ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aBorderLine.LineDistance ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aBorderLine.OuterLineWidth ); + + rStrExpValue = aOut.makeStringAndClear(); + return true; +} + + + + +XMLBorderHdl::~XMLBorderHdl() +{ + // nothing to do +} + +bool XMLBorderHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + std::u16string_view aToken; + SvXMLTokenEnumerator aTokens( rStrImpValue ); + + bool bHasStyle = false; + bool bHasWidth = false; + bool bHasColor = false; + + sal_uInt16 nStyle = USHRT_MAX; + sal_uInt16 nWidth = 0; + sal_uInt16 nNamedWidth = USHRT_MAX; + sal_Int32 nColor = 0; + + sal_Int32 nTemp; + while( aTokens.getNextToken( aToken ) && !aToken.empty() ) + { + if( !bHasWidth && + SvXMLUnitConverter::convertEnum( nNamedWidth, aToken, + pXML_NamedBorderWidths ) ) + { + bHasWidth = true; + } + else if( !bHasStyle && + SvXMLUnitConverter::convertEnum( nStyle, aToken, + pXML_BorderStyles ) ) + { + bHasStyle = true; + } + else if (!bHasColor && ::sax::Converter::convertColor(nColor, aToken)) + { + bHasColor = true; + } + else if( !bHasWidth && + rUnitConverter.convertMeasureToCore( nTemp, aToken, 0, + USHRT_MAX ) ) + { + nWidth = static_cast<sal_uInt16>(nTemp); + bHasWidth = true; + } + else + { + // misformed + return false; + } + } + + // if there is no style or a different style than none but no width, + // then the declaration is not valid. + if (!bHasStyle || (table::BorderLineStyle::NONE != nStyle && !bHasWidth)) + return false; + + table::BorderLine2 aBorderLine; + if(!(rValue >>= aBorderLine)) + { + aBorderLine.Color = 0; + aBorderLine.InnerLineWidth = 0; + aBorderLine.OuterLineWidth = 0; + aBorderLine.LineDistance = 0; + aBorderLine.LineWidth = 0; + } + + // first of all, delete an empty line + if (table::BorderLineStyle::NONE == nStyle || + (bHasWidth && USHRT_MAX == nNamedWidth && 0 == nWidth) ) + { + aBorderLine.InnerLineWidth = 0; + aBorderLine.OuterLineWidth = 0; + aBorderLine.LineDistance = 0; + aBorderLine.LineWidth = 0; + } + else + { + if( USHRT_MAX != nNamedWidth ) + { + aBorderLine.LineWidth = aBorderWidths[nNamedWidth]; + } + else + { + aBorderLine.LineWidth = nWidth; + lcl_frmitems_setXMLBorderStyle( aBorderLine, nStyle ); + } + } + + // set color + if( bHasColor ) + { + aBorderLine.Color = nColor; + } + + rValue <<= aBorderLine; + return true; +} + +bool XMLBorderHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& /* rUnitConverter */ ) const +{ + OUStringBuffer aOut; + + table::BorderLine2 aBorderLine; + if(!(rValue >>= aBorderLine)) + return false; + + sal_Int32 nWidth = aBorderLine.LineWidth; + + if( nWidth == 0 ) + { + aOut.append( GetXMLToken( XML_NONE ) ); + } + else + { + ::sax::Converter::convertMeasure( aOut, nWidth, + util::MeasureUnit::MM_100TH, util::MeasureUnit::POINT); + + aOut.append( ' ' ); + + XMLTokenEnum eStyleToken = XML_SOLID; + switch ( aBorderLine.LineStyle ) + { + case table::BorderLineStyle::DASHED: + eStyleToken = XML_DASHED; + break; + case table::BorderLineStyle::DOTTED: + eStyleToken = XML_DOTTED; + break; + case table::BorderLineStyle::DOUBLE: + case table::BorderLineStyle::THINTHICK_SMALLGAP: + case table::BorderLineStyle::THINTHICK_MEDIUMGAP: + case table::BorderLineStyle::THINTHICK_LARGEGAP: + case table::BorderLineStyle::THICKTHIN_SMALLGAP: + case table::BorderLineStyle::THICKTHIN_MEDIUMGAP: + case table::BorderLineStyle::THICKTHIN_LARGEGAP: + eStyleToken = XML_DOUBLE; + break; + case table::BorderLineStyle::EMBOSSED: + eStyleToken = XML_RIDGE; + break; + case table::BorderLineStyle::ENGRAVED: + eStyleToken = XML_GROOVE; + break; + case table::BorderLineStyle::OUTSET: + eStyleToken = XML_OUTSET; + break; + case table::BorderLineStyle::INSET: + eStyleToken = XML_INSET; + break; + case table::BorderLineStyle::FINE_DASHED: + eStyleToken = XML_FINE_DASHED; + break; + case table::BorderLineStyle::DASH_DOT: + eStyleToken = XML_DASH_DOT; + break; + case table::BorderLineStyle::DASH_DOT_DOT: + eStyleToken = XML_DASH_DOT_DOT; + break; + case table::BorderLineStyle::DOUBLE_THIN: + eStyleToken = XML_DOUBLE_THIN; + break; + case table::BorderLineStyle::SOLID: + default: + break; + } + aOut.append( GetXMLToken( eStyleToken ) + " " ); + + ::sax::Converter::convertColor( aOut, aBorderLine.Color ); + } + + rStrExpValue = aOut.makeStringAndClear(); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/bordrhdl.hxx b/xmloff/source/style/bordrhdl.hxx new file mode 100644 index 0000000000..3741fc3a78 --- /dev/null +++ b/xmloff/source/style/bordrhdl.hxx @@ -0,0 +1,45 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLBorderWidthHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLBorderWidthHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLBorderHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLBorderHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/breakhdl.cxx b/xmloff/source/style/breakhdl.cxx new file mode 100644 index 0000000000..d1490881f3 --- /dev/null +++ b/xmloff/source/style/breakhdl.cxx @@ -0,0 +1,179 @@ +/* -*- 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 "breakhdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/style/BreakType.hpp> +#include <com/sun/star/uno/Any.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_BreakTypes[] = +{ + { XML_AUTO, 0 }, + { XML_COLUMN, 1 }, + { XML_PAGE, 2 }, + { XML_EVEN_PAGE, 2 }, + { XML_ODD_PAGE, 2 }, + { XML_TOKEN_INVALID, 0} +}; + + + + +XMLFmtBreakBeforePropHdl::~XMLFmtBreakBeforePropHdl() +{ + // Nothing to do +} + +bool XMLFmtBreakBeforePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nEnum; + bool bRet = SvXMLUnitConverter::convertEnum( nEnum, rStrImpValue, pXML_BreakTypes ); + if( bRet ) + { + style::BreakType eBreak; + switch ( nEnum ) + { + case 0: + eBreak = style::BreakType_NONE; + break; + case 1: + eBreak = style::BreakType_COLUMN_BEFORE; + break; + default: + eBreak = style::BreakType_PAGE_BEFORE; + break; + } + rValue <<= eBreak; + } + + return bRet; +} + +bool XMLFmtBreakBeforePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + style::BreakType eBreak; + + if( !( rValue >>= eBreak ) ) + { + sal_Int32 nValue = 0; + if( !( rValue >>= nValue ) ) + return false; + + eBreak = static_cast<style::BreakType>(nValue); + } + + sal_uInt16 nEnum = 0; + switch( eBreak ) + { + case style::BreakType_COLUMN_BEFORE: + nEnum = 1; + break; + case style::BreakType_PAGE_BEFORE: + nEnum = 2; + break; + case style::BreakType_NONE: + nEnum = 0; + break; + default: + return false; + } + + OUStringBuffer aOut; + /* bool bOk = */ SvXMLUnitConverter::convertEnum( aOut, nEnum, pXML_BreakTypes ); + rStrExpValue = aOut.makeStringAndClear(); + + return true; +} + + + + +XMLFmtBreakAfterPropHdl::~XMLFmtBreakAfterPropHdl() +{ + // Nothing to do +} + +bool XMLFmtBreakAfterPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nEnum; + bool bRet = SvXMLUnitConverter::convertEnum( nEnum, rStrImpValue, pXML_BreakTypes ); + if( bRet ) + { + style::BreakType eBreak; + switch ( nEnum ) + { + case 0: + eBreak = style::BreakType_NONE; + break; + case 1: + eBreak = style::BreakType_COLUMN_AFTER; + break; + default: + eBreak = style::BreakType_PAGE_AFTER; + break; + } + rValue <<= eBreak; + } + + return bRet; +} + +bool XMLFmtBreakAfterPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + style::BreakType eBreak; + + if( !( rValue >>= eBreak ) ) + { + sal_Int32 nValue = 0; + if( !( rValue >>= nValue ) ) + return false; + + eBreak = static_cast<style::BreakType>(nValue); + } + + sal_uInt16 nEnum = 0; + switch( eBreak ) + { + case style::BreakType_COLUMN_AFTER: + nEnum = 1; + break; + case style::BreakType_PAGE_AFTER: + nEnum = 2; + break; + case style::BreakType_NONE: + nEnum = 0; + break; + default: + return false; + } + + OUStringBuffer aOut; + /* bool bOk = */ SvXMLUnitConverter::convertEnum( aOut, nEnum, pXML_BreakTypes ); + rStrExpValue = aOut.makeStringAndClear(); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/breakhdl.hxx b/xmloff/source/style/breakhdl.hxx new file mode 100644 index 0000000000..c38e33ba6b --- /dev/null +++ b/xmloff/source/style/breakhdl.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFmtBreakBeforePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFmtBreakBeforePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFmtBreakAfterPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFmtBreakAfterPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/cdouthdl.cxx b/xmloff/source/style/cdouthdl.cxx new file mode 100644 index 0000000000..0b484dcf04 --- /dev/null +++ b/xmloff/source/style/cdouthdl.cxx @@ -0,0 +1,305 @@ +/* -*- 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 "cdouthdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> + +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/uno/Any.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::awt; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_CrossedoutType_Enum[] = +{ + { XML_NONE, awt::FontStrikeout::NONE }, + { XML_SINGLE, awt::FontStrikeout::SINGLE }, + { XML_DOUBLE, awt::FontStrikeout::DOUBLE }, + { XML_SINGLE, awt::FontStrikeout::BOLD }, + { XML_SINGLE, awt::FontStrikeout::SLASH }, + { XML_SINGLE, awt::FontStrikeout::X }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_CrossedoutStyle_Enum[] = +{ + { XML_NONE, awt::FontStrikeout::NONE }, + { XML_SOLID, awt::FontStrikeout::SINGLE }, + { XML_SOLID, awt::FontStrikeout::DOUBLE }, + { XML_SOLID, awt::FontStrikeout::BOLD }, + { XML_SOLID, awt::FontStrikeout::SLASH }, + { XML_SOLID, awt::FontStrikeout::X }, + { XML_DOTTED, awt::FontStrikeout::SINGLE }, + { XML_DASH, awt::FontStrikeout::SINGLE }, + { XML_LONG_DASH, awt::FontStrikeout::SINGLE }, + { XML_DOT_DASH, awt::FontStrikeout::SINGLE }, + { XML_DOT_DOT_DASH, awt::FontStrikeout::SINGLE }, + { XML_WAVE, awt::FontStrikeout::SINGLE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_CrossedoutWidth_Enum[] = +{ + { XML_AUTO, awt::FontStrikeout::NONE }, + { XML_AUTO, awt::FontStrikeout::SINGLE }, + { XML_AUTO, awt::FontStrikeout::DOUBLE }, + { XML_BOLD, awt::FontStrikeout::BOLD }, + { XML_AUTO, awt::FontStrikeout::SLASH }, + { XML_AUTO, awt::FontStrikeout::X }, + { XML_THIN, awt::FontStrikeout::NONE }, + { XML_MEDIUM, awt::FontStrikeout::NONE }, + { XML_THICK, awt::FontStrikeout::NONE }, + { XML_TOKEN_INVALID, 0 } +}; + + +XMLCrossedOutTypePropHdl::~XMLCrossedOutTypePropHdl() +{ + // nothing to do +} + +bool XMLCrossedOutTypePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewStrikeout = 0; + bool bRet = SvXMLUnitConverter::convertEnum( + eNewStrikeout, rStrImpValue, pXML_CrossedoutType_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eStrikeout = sal_Int16(); + if( (rValue >>= eStrikeout) && awt::FontStrikeout::NONE!=eStrikeout ) + { + switch( eNewStrikeout ) + { + case awt::FontStrikeout::NONE: + case awt::FontStrikeout::SINGLE: + // keep existing line style + eNewStrikeout = eStrikeout; + break; + case awt::FontStrikeout::DOUBLE: + // A double line style has priority over a solid or a bold + // line style, + // but not about any other line style + switch( eStrikeout ) + { + case awt::FontStrikeout::SINGLE: + case awt::FontStrikeout::BOLD: + break; + default: + // If a double line style is not supported for the existing + // value, keep the new one + eNewStrikeout = eStrikeout; + break; + } + break; + default: + OSL_ENSURE( bRet, "unexpected line type value" ); + break; + } + if( eNewStrikeout != eStrikeout ) + rValue <<= static_cast<sal_Int16>(eNewStrikeout); + } + else + { + rValue <<= static_cast<sal_Int16>(eNewStrikeout); + } + } + + return bRet; +} + +bool XMLCrossedOutTypePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if (rValue >>= nValue) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_CrossedoutType_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + +XMLCrossedOutStylePropHdl::~XMLCrossedOutStylePropHdl() +{ + // nothing to do +} + +bool XMLCrossedOutStylePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewStrikeout(0); + bool bRet = SvXMLUnitConverter::convertEnum( + eNewStrikeout, rStrImpValue, pXML_CrossedoutStyle_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eStrikeout = sal_Int16(); + if( (rValue >>= eStrikeout) && awt::FontStrikeout::NONE!=eStrikeout ) + { + // one NONE a SINGLE are possible new values. For both, the + // existing value is kept. + } + else + { + rValue <<= static_cast<sal_Int16>(eNewStrikeout); + } + } + + return bRet; +} + +bool XMLCrossedOutStylePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_CrossedoutStyle_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + +XMLCrossedOutWidthPropHdl::~XMLCrossedOutWidthPropHdl() +{ + // nothing to do +} + +bool XMLCrossedOutWidthPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewStrikeout = 0; + bool bRet = SvXMLUnitConverter::convertEnum( + eNewStrikeout, rStrImpValue, pXML_CrossedoutWidth_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eStrikeout = sal_Int16(); + if( (rValue >>= eStrikeout) && awt::FontStrikeout::NONE!=eStrikeout ) + { + switch( eNewStrikeout ) + { + case awt::FontStrikeout::NONE: + // keep existing line style + eNewStrikeout = eStrikeout; + break; + case awt::FontStrikeout::BOLD: + switch( eStrikeout ) + { + case awt::FontStrikeout::SINGLE: + break; + default: + // If a double line style is not supported for the existing + // value, keep the new one + eNewStrikeout = eStrikeout; + break; + } + break; + default: + OSL_ENSURE( bRet, "unexpected line type value" ); + break; + } + if( eNewStrikeout != eStrikeout ) + rValue <<= static_cast<sal_Int16>(eNewStrikeout); + } + else + { + rValue <<= static_cast<sal_Int16>(eNewStrikeout); + } + } + + return bRet; +} + +bool XMLCrossedOutWidthPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( (rValue >>= nValue) && (awt::FontStrikeout::BOLD == nValue) ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_CrossedoutWidth_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + +XMLCrossedOutTextPropHdl::~XMLCrossedOutTextPropHdl() +{ + // nothing to do +} + +bool XMLCrossedOutTextPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( !rStrImpValue.isEmpty() ) + { + sal_Int16 eStrikeout = ('/' == rStrImpValue[0] + ? awt::FontStrikeout::SLASH + : awt::FontStrikeout::X); + rValue <<= eStrikeout; + bRet = true; + } + + return bRet; +} + +bool XMLCrossedOutTextPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int16 nValue = sal_Int16(); + + if( (rValue >>= nValue) && + (awt::FontStrikeout::SLASH == nValue || awt::FontStrikeout::X == nValue) ) + { + rStrExpValue = OUString( + static_cast< sal_Unicode>( awt::FontStrikeout::SLASH == nValue ? '/' + : 'X' ) ); + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/cdouthdl.hxx b/xmloff/source/style/cdouthdl.hxx new file mode 100644 index 0000000000..70f9ddbbad --- /dev/null +++ b/xmloff/source/style/cdouthdl.hxx @@ -0,0 +1,63 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLCrossedOutTypePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCrossedOutTypePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCrossedOutStylePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCrossedOutStylePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCrossedOutWidthPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCrossedOutWidthPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCrossedOutTextPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCrossedOutTextPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/chrhghdl.cxx b/xmloff/source/style/chrhghdl.cxx new file mode 100644 index 0000000000..5304881272 --- /dev/null +++ b/xmloff/source/style/chrhghdl.cxx @@ -0,0 +1,149 @@ +/* -*- 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 "chrhghdl.hxx" + +#include <rtl/ustrbuf.hxx> + +#include <com/sun/star/uno/Any.hxx> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmluconv.hxx> + +using namespace ::com::sun::star; + + + + +XMLCharHeightHdl::~XMLCharHeightHdl() +{ + // nothing to do +} + +bool XMLCharHeightHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if( rStrImpValue.indexOf( '%' ) == -1 ) + { + double fSize; + sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString( + rStrImpValue, util::MeasureUnit::POINT ); + if (::sax::Converter::convertDouble(fSize, rStrImpValue, + eSrcUnit, util::MeasureUnit::POINT)) + { + fSize = ::std::max<double>(fSize, 1.0); // fdo#49876: 0pt is invalid + rValue <<= static_cast<float>(fSize); + return true; + } + } + + return false; +} + +bool XMLCharHeightHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut; + + float fSize = 0; + if( rValue >>= fSize ) + { + fSize = ::std::max<float>(fSize, 1.0f); // fdo#49876: 0pt is invalid + ::sax::Converter::convertDouble(aOut, static_cast<double>(fSize), true, + util::MeasureUnit::POINT, util::MeasureUnit::POINT); + aOut.append( "pt" ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLCharHeightPropHdl::~XMLCharHeightPropHdl() +{ + // nothing to do +} + +bool XMLCharHeightPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if( rStrImpValue.indexOf( '%' ) != -1 ) + { + sal_Int32 nPrc = 100; + if (::sax::Converter::convertPercent( nPrc, rStrImpValue )) + { + rValue <<= static_cast<sal_Int16>(nPrc); + return true; + } + } + + return false; +} + +bool XMLCharHeightPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut( rStrExpValue ); + + sal_Int16 nValue = sal_Int16(); + if( rValue >>= nValue ) + { + ::sax::Converter::convertPercent( aOut, nValue ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLCharHeightDiffHdl::~XMLCharHeightDiffHdl() +{ + // nothing to do +} + +bool XMLCharHeightDiffHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nRel = 0; + + if (::sax::Converter::convertMeasure( nRel, rStrImpValue, + util::MeasureUnit::POINT )) + { + rValue <<= static_cast<float>(nRel); + return true; + } + + return false; +} + +bool XMLCharHeightDiffHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + float nRel = 0; + if( (rValue >>= nRel) && (nRel != 0) ) + { + OUStringBuffer aOut; + ::sax::Converter::convertMeasure( aOut, static_cast<sal_Int32>(nRel), + util::MeasureUnit::POINT, util::MeasureUnit::POINT ); + rStrExpValue = aOut.makeStringAndClear(); + } + + return !rStrExpValue.isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/chrhghdl.hxx b/xmloff/source/style/chrhghdl.hxx new file mode 100644 index 0000000000..392ffab6f3 --- /dev/null +++ b/xmloff/source/style/chrhghdl.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLCharHeightHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharHeightHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharHeightPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharHeightPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharHeightDiffHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharHeightDiffHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/chrlohdl.cxx b/xmloff/source/style/chrlohdl.cxx new file mode 100644 index 0000000000..05dd6d770e --- /dev/null +++ b/xmloff/source/style/chrlohdl.cxx @@ -0,0 +1,423 @@ +/* -*- 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 "chrlohdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <unotools/saveopt.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <sal/log.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/lang/Locale.hpp> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +/* TODO-BCP47: this fiddling with Locale is quite ugly and fragile, especially + * for the fo:script temporarily stored in Variant, it would be better to use + * LanguageTagODF but we have that nasty UNO API requirement here. + * => make LanguageTagODF (unpublished) API? */ + +// For runtime performance, instead of converting back and forth between +// css::Locale and LanguageTag to decide if script or tag are +// needed, this code takes advantage of knowledge about the internal +// representation of BCP 47 language tags in a Locale if present as done in a +// LanguageTag. + +XMLCharLanguageHdl::~XMLCharLanguageHdl() +{ + // nothing to do +} + +bool XMLCharLanguageHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const +{ + bool bRet = false; + lang::Locale aLocale1, aLocale2; + + if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) ) + { + bool bEmptyOrScriptVariant1 = (aLocale1.Variant.isEmpty() || aLocale1.Variant[0] == '-'); + bool bEmptyOrScriptVariant2 = (aLocale2.Variant.isEmpty() || aLocale2.Variant[0] == '-'); + if (bEmptyOrScriptVariant1 && bEmptyOrScriptVariant2) + bRet = ( aLocale1.Language == aLocale2.Language ); + else + { + OUString aLanguage1, aLanguage2; + if (bEmptyOrScriptVariant1) + aLanguage1 = aLocale1.Language; + else + aLanguage1 = LanguageTag( aLocale1).getLanguage(); + if (bEmptyOrScriptVariant2) + aLanguage2 = aLocale2.Language; + else + aLanguage2 = LanguageTag( aLocale2).getLanguage(); + bRet = ( aLanguage1 == aLanguage2 ); + } + } + + return bRet; +} + +bool XMLCharLanguageHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + rValue >>= aLocale; + + if( !IsXMLToken(rStrImpValue, XML_NONE) ) + { + if (aLocale.Variant.isEmpty()) + aLocale.Language = rStrImpValue; + else + { + if (!aLocale.Language.isEmpty() || aLocale.Variant[0] != '-') + { + SAL_WARN_IF( aLocale.Language != I18NLANGTAG_QLT, "xmloff.style", + "XMLCharLanguageHdl::importXML - attempt to import language twice"); + } + else + { + aLocale.Variant = rStrImpValue + aLocale.Variant; + if (!aLocale.Country.isEmpty()) + aLocale.Variant += "-" + aLocale.Country; + aLocale.Language = I18NLANGTAG_QLT; + } + } + } + + rValue <<= aLocale; + return true; +} + +bool XMLCharLanguageHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + if(!(rValue >>= aLocale)) + return false; + + if (aLocale.Variant.isEmpty()) + rStrExpValue = aLocale.Language; + else + { + LanguageTag aLanguageTag( aLocale); + OUString aScript, aCountry; + aLanguageTag.getIsoLanguageScriptCountry( rStrExpValue, aScript, aCountry); + // Do not write *:language='none' for a non-ISO language with + // *:rfc-language-tag that is written if Variant is not empty. If there + // is no match do not write this attribute at all. + if (rStrExpValue.isEmpty()) + return false; + } + + if( rStrExpValue.isEmpty() ) + rStrExpValue = GetXMLToken( XML_NONE ); + + return true; +} + +XMLCharScriptHdl::~XMLCharScriptHdl() +{ + // nothing to do +} + +bool XMLCharScriptHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const +{ + bool bRet = false; + lang::Locale aLocale1, aLocale2; + + if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) ) + { + bool bEmptyVariant1 = aLocale1.Variant.isEmpty(); + bool bEmptyVariant2 = aLocale2.Variant.isEmpty(); + if (bEmptyVariant1 && bEmptyVariant2) + bRet = true; + else if (bEmptyVariant1 != bEmptyVariant2) + ; // stays false + else + { + OUString aScript1, aScript2; + if (aLocale1.Variant[0] == '-') + aScript1 = aLocale1.Variant.copy(1); + else + aScript1 = LanguageTag( aLocale1).getScript(); + if (aLocale2.Variant[0] == '-') + aScript2 = aLocale2.Variant.copy(1); + else + aScript2 = LanguageTag( aLocale2).getScript(); + bRet = ( aScript1 == aScript2 ); + } + } + + return bRet; +} + +bool XMLCharScriptHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + rValue >>= aLocale; + + if( !IsXMLToken( rStrImpValue, XML_NONE ) ) + { + // Import the script only if we don't have a full BCP 47 language tag + // in Variant yet. + if (aLocale.Variant.isEmpty()) + { + if (aLocale.Language.isEmpty()) + { + SAL_INFO( "xmloff.style", "XMLCharScriptHdl::importXML - script but no language yet"); + // Temporarily store in Variant and hope the best (we will get + // a language later, yes?) + aLocale.Variant = "-" + rStrImpValue; + } + else + { + aLocale.Variant = aLocale.Language + "-" + rStrImpValue; + if (!aLocale.Country.isEmpty()) + aLocale.Variant += "-" + aLocale.Country; + aLocale.Language = I18NLANGTAG_QLT; + } + } + else if (aLocale.Variant[0] == '-') + { + SAL_WARN( "xmloff.style", "XMLCharScriptHdl::importXML - attempt to insert script twice: " + << rStrImpValue << " -> " << aLocale.Variant); + } + else + { + // Assume that if there already is a script or anything else BCP 47 + // it was read by XMLCharRfcLanguageTagHdl() and takes precedence. + // On the other hand, an *:rfc-language-tag without script and a + // *:script ?!? +#if OSL_DEBUG_LEVEL > 0 || defined(DBG_UTIL) + LanguageTag aLanguageTag( aLocale); + if (!aLanguageTag.hasScript()) + { + SAL_WARN( "xmloff.style", "XMLCharScriptHdl::importXML - attempt to insert script over bcp47: " + << rStrImpValue << " -> " << aLanguageTag.getBcp47()); + } +#endif + } + } + + rValue <<= aLocale; + return true; +} + +bool XMLCharScriptHdl::exportXML(OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& rUnitConv) const +{ + lang::Locale aLocale; + if(!(rValue >>= aLocale)) + return false; + + // Do not write script='none' for default script. + + if (aLocale.Variant.isEmpty()) + return false; + + LanguageTag aLanguageTag( aLocale); + if (!aLanguageTag.hasScript()) + return false; + + if (rUnitConv.getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012) + return false; + + OUString aLanguage, aCountry; + aLanguageTag.getIsoLanguageScriptCountry( aLanguage, rStrExpValue, aCountry); + // For non-ISO language it does not make sense to write *:script if + // *:language is not written either, does it? It's all in + // *:rfc-language-tag + return !aLanguage.isEmpty() && !rStrExpValue.isEmpty(); +} + +XMLCharCountryHdl::~XMLCharCountryHdl() +{ + // nothing to do +} + +bool XMLCharCountryHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const +{ + bool bRet = false; + lang::Locale aLocale1, aLocale2; + + if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) ) + bRet = ( aLocale1.Country == aLocale2.Country ); + + return bRet; +} + +bool XMLCharCountryHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + rValue >>= aLocale; + + if( !IsXMLToken( rStrImpValue, XML_NONE ) ) + { + if (aLocale.Country.isEmpty()) + { + aLocale.Country = rStrImpValue; + if (aLocale.Variant.getLength() >= 7 && aLocale.Language == I18NLANGTAG_QLT) + { + // already assembled language tag, at least ll-Ssss and not + // ll-CC or lll-CC + sal_Int32 i = aLocale.Variant.indexOf('-'); // separator to script + if (2 <= i && i < aLocale.Variant.getLength()) + { + i = aLocale.Variant.indexOf( '-', i+1); + if (i < 0) // no other separator + aLocale.Variant += "-" + rStrImpValue; // append country + } + } + } + } + + rValue <<= aLocale; + return true; +} + +bool XMLCharCountryHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + if(!(rValue >>= aLocale)) + return false; + + if (aLocale.Variant.isEmpty()) + rStrExpValue = aLocale.Country; + else + { + LanguageTag aLanguageTag( aLocale); + OUString aLanguage, aScript; + aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, rStrExpValue); + // Do not write *:country='none' for a non-ISO country with + // *:rfc-language-tag that is written if Variant is not empty. If there + // is no match do not write this attribute at all. + if (rStrExpValue.isEmpty()) + return false; + } + + if( rStrExpValue.isEmpty() ) + rStrExpValue = GetXMLToken( XML_NONE ); + + return true; +} + +XMLCharRfcLanguageTagHdl::~XMLCharRfcLanguageTagHdl() +{ + // nothing to do +} + +bool XMLCharRfcLanguageTagHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const +{ + bool bRet = false; + lang::Locale aLocale1, aLocale2; + + if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) ) + bRet = ( aLocale1.Variant == aLocale2.Variant ); + + return bRet; +} + +bool XMLCharRfcLanguageTagHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + rValue >>= aLocale; + + if( !IsXMLToken( rStrImpValue, XML_NONE ) ) + { + // Stored may be a *:rfc-language-tag in violation of ODF v1.3 + // 19.516 style:rfc-language-tag "It shall only be used if its value + // cannot be expressed as a valid combination of the fo:language + // 19.871, fo:script 19.242 and fo:country 19.234 attributes". + // That could override a more detailed fo:* and we also don't want an + // unjustified I18NLANGTAG_QLT extended locale tag, but fetch the + // values in case fo:* doesn't follow. + // Rule out the obvious. + if (rStrImpValue.getLength() < 7) + { + SAL_WARN("xmloff.style","rfc-language-tag too short: {" << rStrImpValue << "} Set: " + << aLocale.Language <<","<< aLocale.Country <<","<< aLocale.Variant); + // Ignore empty and keep Ssss or any earlier qlt already set. + if (!rStrImpValue.isEmpty() && aLocale.Language != I18NLANGTAG_QLT) + { + // Shorter than ll-Ssss, so try ll-CC or lll-CC or ll or lll + sal_Int32 h = rStrImpValue.indexOf('-'); + OUString aLang; + if (2 <= h && h <= 3) + aLang = rStrImpValue.copy(0, h); + else if (h < 0 && 2 <= rStrImpValue.getLength() && rStrImpValue.getLength() <= 3) + aLang = rStrImpValue; + OUString aCoun; + if (!aLang.isEmpty() && aLang.getLength() + 3 == rStrImpValue.getLength()) + aCoun = rStrImpValue.copy( aLang.getLength() + 1); + // Ignore identical value or less information. + if ((!aLang.isEmpty() && aLang != aLocale.Language) || + (!aCoun.isEmpty() && aCoun != aLocale.Country)) + { + // Do not override existing values. + if (aLocale.Language.isEmpty()) + aLocale.Language = aLang; + if (aLocale.Country.isEmpty()) + aLocale.Country = aCoun; + if (aLang != aLocale.Language || aCoun != aLocale.Country) + { + // No match, so we still need the qlt anyway. Whatever.. + aLocale.Variant = rStrImpValue; + aLocale.Language = I18NLANGTAG_QLT; + } + } + else if (aLang.isEmpty() && aCoun.isEmpty()) + { + // Both empty, some other tag. + aLocale.Variant = rStrImpValue; + aLocale.Language = I18NLANGTAG_QLT; + } + } + SAL_WARN("xmloff.style","rfc-language-tag too short: now set: " + << aLocale.Language <<","<< aLocale.Country <<","<< aLocale.Variant); + } + else + { + aLocale.Variant = rStrImpValue; + aLocale.Language = I18NLANGTAG_QLT; + } + } + + rValue <<= aLocale; + return true; +} + +bool XMLCharRfcLanguageTagHdl::exportXML(OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& rUnitConv) const +{ + lang::Locale aLocale; + if(!(rValue >>= aLocale)) + return false; + + // Do not write rfc-language-tag='none' if BCP 47 is not needed. + if (aLocale.Variant.isEmpty()) + return false; + + if (rUnitConv.getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012) + return false; + + rStrExpValue = aLocale.Variant; + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/chrlohdl.hxx b/xmloff/source/style/chrlohdl.hxx new file mode 100644 index 0000000000..a6e710b26f --- /dev/null +++ b/xmloff/source/style/chrlohdl.hxx @@ -0,0 +1,71 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLCharLanguageHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharLanguageHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharScriptHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharScriptHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharCountryHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharCountryHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharRfcLanguageTagHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharRfcLanguageTagHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/csmaphdl.cxx b/xmloff/source/style/csmaphdl.cxx new file mode 100644 index 0000000000..4e760a6c9e --- /dev/null +++ b/xmloff/source/style/csmaphdl.cxx @@ -0,0 +1,120 @@ +/* -*- 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 "csmaphdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/style/CaseMap.hpp> +#include <com/sun/star/uno/Any.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry<sal_uInt16> pXML_Casemap_Enum[] = +{ + { XML_NONE, style::CaseMap::NONE }, + { XML_CASEMAP_LOWERCASE, style::CaseMap::LOWERCASE }, + { XML_CASEMAP_UPPERCASE, style::CaseMap::UPPERCASE }, + { XML_CASEMAP_CAPITALIZE, style::CaseMap::TITLE }, + { XML_TOKEN_INVALID, 0 } +}; + + +XMLCaseMapPropHdl::~XMLCaseMapPropHdl() +{ + // nothing to do +} + +bool XMLCaseMapPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nVal; + bool bRet = SvXMLUnitConverter::convertEnum( + nVal, rStrImpValue, pXML_Casemap_Enum ); + if( bRet ) + rValue <<= nVal; + + return bRet; +} + +bool XMLCaseMapPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_Casemap_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + +XMLCaseMapVariantHdl::~XMLCaseMapVariantHdl() +{ + // nothing to do +} + +bool XMLCaseMapVariantHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( IsXMLToken( rStrImpValue, XML_CASEMAP_SMALL_CAPS ) ) + { + rValue <<= sal_Int16(style::CaseMap::SMALLCAPS); + bRet = true; + } + else if( IsXMLToken( rStrImpValue, XML_NORMAL ) ) + { + rValue <<= sal_Int16(style::CaseMap::NONE); + bRet = true; + } + + return bRet; +} + +bool XMLCaseMapVariantHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nValue = sal_uInt16(); + OUStringBuffer aOut; + + if( rValue >>= nValue ) + { + switch( nValue ) + { + case style::CaseMap::NONE: + aOut.append( GetXMLToken(XML_NORMAL) ); + break; + case style::CaseMap::SMALLCAPS: + aOut.append( GetXMLToken(XML_CASEMAP_SMALL_CAPS) ); + break; + } + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/csmaphdl.hxx b/xmloff/source/style/csmaphdl.hxx new file mode 100644 index 0000000000..1d80d676ae --- /dev/null +++ b/xmloff/source/style/csmaphdl.hxx @@ -0,0 +1,45 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLCaseMapPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCaseMapPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCaseMapVariantHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCaseMapVariantHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/durationhdl.cxx b/xmloff/source/style/durationhdl.cxx new file mode 100644 index 0000000000..a58181027e --- /dev/null +++ b/xmloff/source/style/durationhdl.cxx @@ -0,0 +1,71 @@ +/* -*- 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 "durationhdl.hxx" +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/util/Duration.hpp> +#include <rtl/ustrbuf.hxx> +#include <sax/tools/converter.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; + +bool XMLDurationMS16PropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + Duration aDuration; + if (!::sax::Converter::convertDuration( aDuration, rStrImpValue )) + return false; + + // TODO FIXME why is this in centiseconds? Should it be nanoseconds? + // This overflows... 24h == 8640000cs >> 0x7FFF cs == 32767 + // 32767cs = approx 5 minutes and 27.67s + const sal_Int16 nMS = ((aDuration.Hours * 60 + aDuration.Minutes) * 60 + + aDuration.Seconds) * 100 + (aDuration.NanoSeconds / (10*1000*1000)); + rValue <<= nMS; + + return true; +} + +bool XMLDurationMS16PropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int16 nMS = sal_Int16(); + + if(rValue >>= nMS) + { + OUStringBuffer aOut; + Duration aDuration(false, 0, 0, 0, 0, 0, 0, nMS * 10); + ::sax::Converter::convertDuration(aOut, aDuration); + rStrExpValue = aOut.makeStringAndClear(); + return true; + } + + return false; +} + +XMLDurationMS16PropHdl_Impl::~XMLDurationMS16PropHdl_Impl() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/durationhdl.hxx b/xmloff/source/style/durationhdl.hxx new file mode 100644 index 0000000000..de5193f601 --- /dev/null +++ b/xmloff/source/style/durationhdl.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for a sal_int16 duration in ms: +*/ +class XMLDurationMS16PropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual ~XMLDurationMS16PropHdl_Impl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/escphdl.cxx b/xmloff/source/style/escphdl.cxx new file mode 100644 index 0000000000..8148fb69a0 --- /dev/null +++ b/xmloff/source/style/escphdl.cxx @@ -0,0 +1,156 @@ +/* -*- 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 "escphdl.hxx" + +#include <editeng/escapementitem.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + + + +XMLEscapementPropHdl::~XMLEscapementPropHdl() +{ + // nothing to do +} + +bool XMLEscapementPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int16 nVal; + + SvXMLTokenEnumerator aTokens( rStrImpValue ); + + std::u16string_view aToken; + if( ! aTokens.getNextToken( aToken ) ) + return false; + + if( IsXMLToken( aToken, XML_ESCAPEMENT_SUB ) ) + { + nVal = DFLT_ESC_AUTO_SUB; + } + else if( IsXMLToken( aToken, XML_ESCAPEMENT_SUPER ) ) + { + nVal = DFLT_ESC_AUTO_SUPER; + } + else + { + sal_Int32 nNewEsc; + if (!::sax::Converter::convertPercent( nNewEsc, aToken )) + return false; + + nVal = static_cast<sal_Int16>(nNewEsc); + } + + rValue <<= nVal; + return true; +} + +bool XMLEscapementPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + OUStringBuffer aOut; + + if( rValue >>= nValue ) + { + if( nValue == DFLT_ESC_AUTO_SUPER ) + { + aOut.append( GetXMLToken(XML_ESCAPEMENT_SUPER) ); + } + else if( nValue == DFLT_ESC_AUTO_SUB ) + { + aOut.append( GetXMLToken(XML_ESCAPEMENT_SUB) ); + } + else + { + ::sax::Converter::convertPercent( aOut, nValue ); + } + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLEscapementHeightPropHdl::~XMLEscapementHeightPropHdl() +{ + // nothing to do +} + +bool XMLEscapementHeightPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if( IsXMLToken( rStrImpValue, XML_CASEMAP_SMALL_CAPS ) ) + return false; + + SvXMLTokenEnumerator aTokens( rStrImpValue ); + + std::u16string_view aToken; + if( ! aTokens.getNextToken( aToken ) ) + return false; + + sal_Int8 nProp; + if( aTokens.getNextToken( aToken ) ) + { + sal_Int32 nNewProp; + if (!::sax::Converter::convertPercent( nNewProp, aToken )) + return false; + nProp = static_cast<sal_Int8>(nNewProp); + } + else + { + sal_Int32 nEscapementPosition=0; + if (::sax::Converter::convertPercent( nEscapementPosition, aToken ) + && (nEscapementPosition == 0)) + { + nProp = 100; //if escapement position is zero and no escapement height is given the default height should be 100percent and not something smaller (#i91800#) + } + else + nProp = sal_Int8(DFLT_ESC_PROP); + } + + rValue <<= nProp; + return true; +} + +bool XMLEscapementHeightPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut( rStrExpValue ); + + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + { + if( !rStrExpValue.isEmpty() ) + aOut.append( ' '); + + ::sax::Converter::convertPercent( aOut, nValue ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/escphdl.hxx b/xmloff/source/style/escphdl.hxx new file mode 100644 index 0000000000..d52e20f71a --- /dev/null +++ b/xmloff/source/style/escphdl.hxx @@ -0,0 +1,45 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLEscapementPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLEscapementPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLEscapementHeightPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLEscapementHeightPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/fonthdl.cxx b/xmloff/source/style/fonthdl.cxx new file mode 100644 index 0000000000..d85f425ae6 --- /dev/null +++ b/xmloff/source/style/fonthdl.cxx @@ -0,0 +1,288 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include "fonthdl.hxx" + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <tools/fontenum.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +static const SvXMLEnumMapEntry<FontFamily>* lcl_getFontFamilyGenericMapping() +{ + static SvXMLEnumMapEntry<FontFamily> const aFontFamilyGenericMapping[] = + { + { XML_DECORATIVE, FAMILY_DECORATIVE }, + + { XML_MODERN, FAMILY_MODERN }, + { XML_ROMAN, FAMILY_ROMAN }, + { XML_SCRIPT, FAMILY_SCRIPT }, + { XML_SWISS, FAMILY_SWISS }, + { XML_SYSTEM, FAMILY_SYSTEM }, + { XML_TOKEN_INVALID, FontFamily(0) } + }; + return aFontFamilyGenericMapping; +} + +SvXMLEnumMapEntry<FontPitch> const aFontPitchMapping[] = +{ + { XML_FIXED, PITCH_FIXED }, + { XML_VARIABLE, PITCH_VARIABLE }, + { XML_TOKEN_INVALID, FontPitch(0) } +}; + + +XMLFontFamilyNamePropHdl::~XMLFontFamilyNamePropHdl() +{ + // Nothing to do +} + +bool XMLFontFamilyNamePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + OUStringBuffer sValue; + sal_Int32 nPos = 0; + + do + { + sal_Int32 nFirst = nPos; + nPos = ::sax::Converter::indexOfComma( rStrImpValue, nPos ); + sal_Int32 nLast = (-1 == nPos ? rStrImpValue.getLength() - 1 : nPos - 1); + + // skip trailing blanks + while( nLast > nFirst && ' ' == rStrImpValue[nLast] ) + nLast--; + + // skip leading blanks + while(nFirst <= nLast && ' ' == rStrImpValue[nFirst]) + nFirst++; + + // remove quotes + sal_Unicode c = nFirst > nLast ? 0 : rStrImpValue[nFirst]; + if( nFirst < nLast && ('\'' == c || '\"' == c) && rStrImpValue[nLast] == c ) + { + nFirst++; + nLast--; + } + + if( nFirst <= nLast ) + { + if( !sValue.isEmpty() ) + sValue.append(';'); + + sValue.append(rStrImpValue.subView(nFirst, nLast-nFirst+1)); + } + + if( -1 != nPos ) + nPos++; + } + while( -1 != nPos ); + + if (!sValue.isEmpty()) + { + rValue <<= sValue.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + +bool XMLFontFamilyNamePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + OUString aStrFamilyName; + + if( rValue >>= aStrFamilyName ) + { + OUStringBuffer sValue( aStrFamilyName.getLength() + 2 ); + sal_Int32 nPos = 0; + do + { + sal_Int32 nFirst = nPos; + nPos = aStrFamilyName.indexOf( ';', nPos ); + sal_Int32 nLast = (-1 == nPos ? aStrFamilyName.getLength() : nPos); + + // Set position to the character behind the ';', so we won't + // forget this. + if( -1 != nPos ) + nPos++; + + // If the property value was empty, we stop now. + // If there is a ';' at the first position, the empty name + // at the start will be removed. + if( 0 == nLast ) + continue; + + // nFirst and nLast now denote the first and last character of + // one font name. + nLast--; + + // skip trailing blanks + while( nLast > nFirst && ' ' == aStrFamilyName[nLast] ) + nLast--; + + // skip leading blanks + while( nFirst <= nLast && ' ' == aStrFamilyName[nFirst] ) + nFirst++; + + if( nFirst <= nLast ) + { + if( !sValue.isEmpty() ) + sValue.append( ", " ); + sal_Int32 nLen = nLast-nFirst+1; + std::u16string_view sFamily( aStrFamilyName.subView( nFirst, nLen ) ); + bool bQuote = false; + for( sal_Int32 i=0; i < nLen; i++ ) + { + sal_Unicode c = sFamily[i]; + if( ' ' == c || ',' == c ) + { + bQuote = true; + break; + } + } + if( bQuote ) + sValue.append( '\'' ); + sValue.append( sFamily ); + if( bQuote ) + sValue.append( '\'' ); + } + } + while( -1 != nPos ); + + rStrExpValue = sValue.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLFontFamilyPropHdl::~XMLFontFamilyPropHdl() +{ + // Nothing to do +} + +bool XMLFontFamilyPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + FontFamily eNewFamily; + bool bRet = SvXMLUnitConverter::convertEnum( eNewFamily, rStrImpValue, lcl_getFontFamilyGenericMapping() ); + if( bRet ) + rValue <<= static_cast<sal_Int16>(eNewFamily); + + return bRet; +} + +bool XMLFontFamilyPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + OUStringBuffer aOut; + + sal_Int16 nFamily = sal_Int16(); + if( rValue >>= nFamily ) + { + FontFamily eFamily = static_cast<FontFamily>(nFamily); + if( eFamily != FAMILY_DONTKNOW ) + bRet = SvXMLUnitConverter::convertEnum( aOut, eFamily, lcl_getFontFamilyGenericMapping() ); + } + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + + +XMLFontEncodingPropHdl::~XMLFontEncodingPropHdl() +{ + // Nothing to do +} + +bool XMLFontEncodingPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if( IsXMLToken( rStrImpValue, XML_X_SYMBOL ) ) + rValue <<= sal_Int16(RTL_TEXTENCODING_SYMBOL); + + return true; +} + +bool XMLFontEncodingPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int16 nSet = sal_Int16(); + + if( rValue >>= nSet ) + { + if( static_cast<rtl_TextEncoding>(nSet) == RTL_TEXTENCODING_SYMBOL ) + { + rStrExpValue = GetXMLToken(XML_X_SYMBOL); + bRet = true; + } + } + + return bRet; +} + + +XMLFontPitchPropHdl::~XMLFontPitchPropHdl() +{ + // Nothing to do +} + +bool XMLFontPitchPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + FontPitch eNewPitch; + bool bRet = SvXMLUnitConverter::convertEnum( eNewPitch, rStrImpValue, aFontPitchMapping ); + if( bRet ) + rValue <<= static_cast<sal_Int16>(eNewPitch); + + return bRet; +} + +bool XMLFontPitchPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int16 nPitch = sal_Int16(); + + FontPitch ePitch = PITCH_DONTKNOW; + if( rValue >>= nPitch ) + ePitch = static_cast<FontPitch>(nPitch); + + if( PITCH_DONTKNOW != ePitch ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( aOut, ePitch, aFontPitchMapping, XML_FIXED ); + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/fonthdl.hxx b/xmloff/source/style/fonthdl.hxx new file mode 100644 index 0000000000..970cbc273f --- /dev/null +++ b/xmloff/source/style/fonthdl.hxx @@ -0,0 +1,73 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontFamilyNamePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontFamilyNamePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontFamilyPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontFamilyPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontEncodingPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontEncodingPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontPitchPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontPitchPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/impastpl.cxx b/xmloff/source/style/impastpl.cxx new file mode 100644 index 0000000000..1d84aa8b33 --- /dev/null +++ b/xmloff/source/style/impastpl.cxx @@ -0,0 +1,699 @@ +/* -*- 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 <memory> +#include <algorithm> + +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <tools/solar.h> +#include <PageMasterStyleMap.hxx> +#include <utility> +#include <xmloff/families.hxx> +#include <xmloff/xmlaustp.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlexppr.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmltoken.hxx> + +#include "impastpl.hxx" + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +// Class XMLAutoStyleFamily +// ctor/dtor class XMLAutoStyleFamily + +XMLAutoStyleFamily::XMLAutoStyleFamily( + XmlStyleFamily nFamily, + OUString aStrName, + rtl::Reference < SvXMLExportPropertyMapper > xMapper, + OUString aStrPrefix, + bool bAsFamily ) : + mnFamily( nFamily ), maStrFamilyName(std::move( aStrName)), mxMapper(std::move( xMapper )), + mnCount( 0 ), mnName( 0 ), maStrPrefix(std::move( aStrPrefix )), mbAsFamily( bAsFamily ) +{} + +XMLAutoStyleFamily::XMLAutoStyleFamily( XmlStyleFamily nFamily ) : + mnFamily(nFamily), mnCount(0), mnName(0), mbAsFamily(false) {} + +void XMLAutoStyleFamily::ClearEntries() +{ + m_ParentSet.clear(); +} + +static OUString +data2string(void *data, + const typelib_TypeDescriptionReference *type); + +static OUString +struct2string(void *data, + const typelib_TypeDescription *type) +{ + assert(type->eTypeClass == typelib_TypeClass_STRUCT); + + OUStringBuffer result("{"); + + const typelib_CompoundTypeDescription *compoundType = + &reinterpret_cast<const typelib_StructTypeDescription*>(type)->aBase; + + for (int i = 0; i < compoundType->nMembers; i++) + { + if (i > 0) + result.append(":"); + result.append( + OUString::unacquired(&compoundType->ppMemberNames[i]) + + "=" + + data2string(static_cast<char *>(data)+compoundType->pMemberOffsets[i], + compoundType->ppTypeRefs[i])); + } + + result.append("}"); + + return result.makeStringAndClear(); +} + +static OUString +data2string(void *data, + const typelib_TypeDescriptionReference *type) +{ + switch (type->eTypeClass) + { + case typelib_TypeClass_VOID: + return ""; + case typelib_TypeClass_BOOLEAN: + return *static_cast<const sal_Bool*>(data) ? OUString("true") : OUString("false"); + case typelib_TypeClass_BYTE: + return OUString::number(*static_cast<const sal_Int8*>(data)); + case typelib_TypeClass_SHORT: + return OUString::number(*static_cast<const sal_Int16*>(data)); + case typelib_TypeClass_LONG: + return OUString::number(*static_cast<const sal_Int32*>(data)); + case typelib_TypeClass_HYPER: + return OUString::number(*static_cast<const sal_Int64*>(data)); + case typelib_TypeClass_UNSIGNED_SHORT: + return OUString::number(*static_cast<const sal_uInt16*>(data)); + case typelib_TypeClass_UNSIGNED_LONG: + return OUString::number((*static_cast<const sal_uInt32*>(data)), 16); + case typelib_TypeClass_UNSIGNED_HYPER: + return OUString::number((*static_cast<const sal_uInt64*>(data)), 16); + case typelib_TypeClass_FLOAT: + return OUString::number(*static_cast<const float*>(data)); + case typelib_TypeClass_DOUBLE: + return OUString::number(*static_cast<const double*>(data)); + case typelib_TypeClass_CHAR: + return ("U+" + OUString::number(*static_cast<const sal_uInt16*>(data))); + case typelib_TypeClass_STRING: + return *static_cast<OUString*>(data); + case typelib_TypeClass_TYPE: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_INTERFACE: + return "wtf"; + case typelib_TypeClass_STRUCT: + return struct2string(data, type->pType); + case typelib_TypeClass_ENUM: + return OUString::number(*static_cast<const sal_Int32*>(data)); + default: + assert(false); // this cannot happen I hope + break; + } + return ""; +} + +static OUString any2string(const uno::Any& any) +{ + return data2string(const_cast<void*>(any.getValue()), any.pType); +} + +// Class SvXMLAutoStylePoolProperties_Impl +// ctor class SvXMLAutoStylePoolProperties_Impl + +XMLAutoStylePoolProperties::XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, OUString const & rParentName ) +: maProperties( std::move(rProperties) ), + mnPos ( rFamilyData.mnCount ) +{ + static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr); + + if (bHack) + { + OUStringBuffer aStemBuffer(32); + aStemBuffer.append( rFamilyData.maStrPrefix ); + + if (!rParentName.isEmpty()) + { + aStemBuffer.append("-" + rParentName); + } + + // Create a name based on the properties used + for(XMLPropertyState const & rState : maProperties) + { + if (rState.mnIndex == -1) + continue; + OUString sXMLName(rFamilyData.mxMapper->getPropertySetMapper()->GetEntryXMLName(rState.mnIndex)); + if (sXMLName.isEmpty()) + continue; + aStemBuffer.append( + "-" + + OUString::number(static_cast<sal_Int32>(rFamilyData.mxMapper->getPropertySetMapper()->GetEntryNameSpace(rState.mnIndex))) + + ":" + + sXMLName + + "=" + + any2string(rState.maValue)); + } + +#if 0 + // Finally append an incremental counter in an attempt to make identical + // styles always come out in the same order. Will see if this works. + aStemBuffer.append("-z"); + static sal_Int32 nCounter = 0; + aStemBuffer.append(nCounter++)); +#endif + + // create a name that hasn't been used before. The created name has not + // to be added to the array, because it will never tried again + + msName = aStemBuffer; + bool bWarned = false; + while (rFamilyData.maNameSet.find(msName) != + rFamilyData.maNameSet.end()) + { + if (!bWarned) + SAL_WARN("xmloff", "Overlapping style name for " << msName); + bWarned = true; + rFamilyData.mnName++; + msName = aStemBuffer + "-" + OUString::number( static_cast<sal_Int64>(rFamilyData.mnName) ); + } + rFamilyData.maNameSet.insert(msName); + } + else + { + // create a name that hasn't been used before. The created name has not + // to be added to the array, because it will never tried again + do + { + rFamilyData.mnName++; + msName = rFamilyData.maStrPrefix + OUString::number( static_cast<sal_Int64>(rFamilyData.mnName) ); + } + while (rFamilyData.maNameSet.find(msName) != rFamilyData.maNameSet.end() || rFamilyData.maReservedNameSet.find(msName) != rFamilyData.maReservedNameSet.end()); + } + +#if OSL_DEBUG_LEVEL > 0 + std::set<sal_Int32> DebugProperties; + for (XMLPropertyState const & rPropState : maProperties) + { + sal_Int32 const property(rPropState.mnIndex); + // serious bug: will cause duplicate attributes to be exported + assert(DebugProperties.find(property) == DebugProperties.end()); + if (-1 != property) + { + DebugProperties.insert(property); + } + } +#endif +} + +bool operator<( const XMLAutoStyleFamily& r1, const XMLAutoStyleFamily& r2) +{ + return r1.mnFamily < r2.mnFamily; +} + + +XMLAutoStylePoolParent::~XMLAutoStylePoolParent() +{ +} + +namespace { + +struct ComparePartial +{ + const XMLAutoStyleFamily& rFamilyData; + + bool operator()(const std::vector< XMLPropertyState >& lhs, + const XMLAutoStylePoolProperties& rhs) const + { + return rFamilyData.mxMapper->LessPartial(lhs, rhs.GetProperties()); + } + bool operator()(const XMLAutoStylePoolProperties& lhs, + const std::vector< XMLPropertyState >& rhs ) const + { + return rFamilyData.mxMapper->LessPartial(lhs.GetProperties(), rhs); + } +}; + +} + +// Adds an array of XMLPropertyState ( std::vector< XMLPropertyState > ) to list +// if not added, yet. + +bool XMLAutoStylePoolParent::Add( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, OUString& rName, bool bDontSeek ) +{ + PropertiesListType::iterator pProperties = m_PropertiesList.end();; + auto [itBegin, itEnd] = std::equal_range(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData}); + if (!bDontSeek) + for (auto it = itBegin; it != itEnd; ++it) + if (rFamilyData.mxMapper->Equals(it->GetProperties(), rProperties)) + pProperties = it; + + bool bAdded = false; + if( bDontSeek || pProperties == m_PropertiesList.end() ) + { + pProperties = m_PropertiesList.emplace(itBegin, rFamilyData, std::move(rProperties), msParent); + bAdded = true; + } + + rName = pProperties->GetName(); + + return bAdded; +} + + +// Adds an array of XMLPropertyState ( std::vector< XMLPropertyState > ) with a given name. +// If the name exists already, nothing is done. If a style with a different name and +// the same properties exists, a new one is added (like with bDontSeek). + + +bool XMLAutoStylePoolParent::AddNamed( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, const OUString& rName ) +{ + if (rFamilyData.maNameSet.find(rName) != rFamilyData.maNameSet.end()) + return false; + + auto it = std::lower_bound(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData}); + + it = m_PropertiesList.emplace(it, rFamilyData, std::move(rProperties), msParent); + // ignore the generated name + it->SetName( rName ); + return true; +} + + +// Search for an array of XMLPropertyState ( std::vector< XMLPropertyState > ) in list + + +OUString XMLAutoStylePoolParent::Find( const XMLAutoStyleFamily& rFamilyData, const std::vector< XMLPropertyState >& rProperties ) const +{ + OUString sName; + auto [itBegin,itEnd] = std::equal_range(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData}); + for (auto it = itBegin; it != itEnd; ++it) + if (rFamilyData.mxMapper->Equals(it->GetProperties(), rProperties)) + sName = it->GetName(); + + return sName; +} + +bool XMLAutoStylePoolParent::operator< (const XMLAutoStylePoolParent& rOther) const +{ + return msParent < rOther.msParent; +} + +// Class SvXMLAutoStylePool_Impl +// ctor/dtor class SvXMLAutoStylePool_Impl + +SvXMLAutoStylePoolP_Impl::SvXMLAutoStylePoolP_Impl( SvXMLExport& rExp) + : rExport( rExp ) +{ +} + +SvXMLAutoStylePoolP_Impl::~SvXMLAutoStylePoolP_Impl() +{ +} + +// Adds stylefamily-information to sorted list + +void SvXMLAutoStylePoolP_Impl::AddFamily( + XmlStyleFamily nFamily, + const OUString& rStrName, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper, + const OUString& rStrPrefix, + bool bAsFamily ) +{ + // store family in a list if not already stored + SvXMLExportFlags nExportFlags = GetExport().getExportFlags(); + bool bStylesOnly = (nExportFlags & SvXMLExportFlags::STYLES) && !(nExportFlags & SvXMLExportFlags::CONTENT); + + OUString aPrefix( rStrPrefix ); + if( bStylesOnly ) + { + aPrefix = "M" + rStrPrefix; + } + +#if OSL_DEBUG_LEVEL > 0 + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + if (iter != m_FamilySet.end()) + { + // FIXME: do we really intend to replace the previous nFamily + // entry in this case ? + SAL_WARN_IF( iter->mxMapper != rMapper, "xmloff", + "Adding duplicate family " << rStrName << + " with mismatching mapper ! " << + typeid(iter->mxMapper.get()).name() << " " << + typeid(*rMapper).name() ); + } +#endif + + m_FamilySet.emplace(nFamily, rStrName, rMapper, aPrefix, bAsFamily); +} + +void SvXMLAutoStylePoolP_Impl::SetFamilyPropSetMapper( + XmlStyleFamily nFamily, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper ) +{ + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + if (iter != m_FamilySet.end()) + const_cast<XMLAutoStyleFamily&>(*iter).mxMapper = rMapper; +} + +// Adds a name to list +void SvXMLAutoStylePoolP_Impl::RegisterName( XmlStyleFamily nFamily, const OUString& rName ) +{ + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + const_cast<XMLAutoStyleFamily&>(*iter).maNameSet.insert(rName); +} + +// Adds a name to list +void SvXMLAutoStylePoolP_Impl::RegisterDefinedName( XmlStyleFamily nFamily, const OUString& rName ) +{ + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + const_cast<XMLAutoStyleFamily&>(*iter).maReservedNameSet.insert(rName); +} + + +// Retrieve the list of registered names + + +void SvXMLAutoStylePoolP_Impl::GetRegisteredNames( + uno::Sequence<sal_Int32>& rFamilies, + uno::Sequence<OUString>& rNames ) +{ + // collect registered names + families + std::vector<sal_Int32> aFamilies; + std::vector<OUString> aNames; + + // iterate over families + for (XMLAutoStyleFamily const & rFamily : m_FamilySet) + { + // iterate over names + for (const auto& rName : rFamily.maNameSet) + { + aFamilies.push_back( static_cast<sal_Int32>(rFamily.mnFamily) ); + aNames.push_back( rName ); + } + } + + // copy the families + names into the sequence types + assert(aFamilies.size() == aNames.size()); + + rFamilies.realloc( aFamilies.size() ); + std::copy( aFamilies.begin(), aFamilies.end(), rFamilies.getArray() ); + + rNames.realloc( aNames.size() ); + std::copy( aNames.begin(), aNames.end(), rNames.getArray() ); +} + +// Adds an array of XMLPropertyState ( vector< XMLPropertyState > ) to list +// if not added, yet. + +bool SvXMLAutoStylePoolP_Impl::Add( + OUString& rName, XmlStyleFamily nFamily, const OUString& rParentName, + ::std::vector< XMLPropertyState >&& rProperties, bool bDontSeek ) +{ + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + + XMLAutoStyleFamily &rFamily = const_cast<XMLAutoStyleFamily&>(*iter); + + auto itPair = rFamily.m_ParentSet.emplace(rParentName); + XMLAutoStylePoolParent& rParent = const_cast<XMLAutoStylePoolParent&>(*itPair.first); + + bool bRet = false; + if (rParent.Add(rFamily, std::move(rProperties), rName, bDontSeek)) + { + rFamily.mnCount++; + bRet = true; + } + + return bRet; +} + +bool SvXMLAutoStylePoolP_Impl::AddNamed( + const OUString& rName, XmlStyleFamily nFamily, const OUString& rParentName, + std::vector< XMLPropertyState >&& rProperties ) +{ + // get family and parent the same way as in Add() + + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + + XMLAutoStyleFamily &rFamily = const_cast<XMLAutoStyleFamily&>(*iter); + + auto itPair = rFamily.m_ParentSet.emplace(rParentName); + XMLAutoStylePoolParent& rParent = const_cast<XMLAutoStylePoolParent&>(*itPair.first); + + bool bRet = false; + if (rParent.AddNamed(rFamily, std::move(rProperties), rName)) + { + rFamily.mnCount++; + bRet = true; + } + + return bRet; +} + + +// Search for an array of XMLPropertyState ( std::vector< XMLPropertyState > ) in list + + +OUString SvXMLAutoStylePoolP_Impl::Find( XmlStyleFamily nFamily, + const OUString& rParent, + const std::vector< XMLPropertyState >& rProperties ) const +{ + OUString sName; + + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + + XMLAutoStyleFamily const& rFamily = *iter; + XMLAutoStylePoolParent aTmp(rParent); + auto const it2 = rFamily.m_ParentSet.find(aTmp); + if (it2 != rFamily.m_ParentSet.end()) + { + sName = it2->Find(rFamily, rProperties); + } + + return sName; +} + +std::vector<xmloff::AutoStyleEntry> SvXMLAutoStylePoolP_Impl::GetAutoStyleEntries() const +{ + std::vector<xmloff::AutoStyleEntry> rReturnVector; + + for (XMLAutoStyleFamily const & rFamily : m_FamilySet) + { + rtl::Reference<XMLPropertySetMapper> aPropertyMapper = rFamily.mxMapper->getPropertySetMapper(); + for (XMLAutoStylePoolParent const & rParent : rFamily.m_ParentSet) + { + for (XMLAutoStylePoolProperties const & rProperty : rParent.GetPropertiesList()) + { + rReturnVector.emplace_back(); + xmloff::AutoStyleEntry & rEntry = rReturnVector.back(); + for (XMLPropertyState const & rPropertyState : rProperty.GetProperties()) + { + if (rPropertyState.mnIndex >= 0) + { + OUString sXmlName = aPropertyMapper->GetEntryXMLName(rPropertyState.mnIndex); + rEntry.m_aXmlProperties.emplace_back(sXmlName, rPropertyState.maValue); + } + } + } + } + } + return rReturnVector; +} + +namespace { + +struct AutoStylePoolExport +{ + const OUString* mpParent; + XMLAutoStylePoolProperties* mpProperties; + + AutoStylePoolExport() : mpParent(nullptr), mpProperties(nullptr) {} +}; + +struct StyleComparator +{ + bool operator() (const AutoStylePoolExport& a, const AutoStylePoolExport& b) + { + return (a.mpProperties->GetName() < b.mpProperties->GetName() || + (a.mpProperties->GetName() == b.mpProperties->GetName() && *a.mpParent < *b.mpParent)); + } +}; + +} + +void SvXMLAutoStylePoolP_Impl::exportXML( + XmlStyleFamily nFamily, + const SvXMLAutoStylePoolP *pAntiImpl) const +{ + // Get list of parents for current family (nFamily) + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + + const XMLAutoStyleFamily &rFamily = *iter; + sal_uInt32 nCount = rFamily.mnCount; + + if (!nCount) + return; + + // create, initialize and fill helper-structure (SvXMLAutoStylePoolProperties_Impl) + // which contains a parent-name and a SvXMLAutoStylePoolProperties_Impl + std::vector<AutoStylePoolExport> aExpStyles(nCount); + + for (XMLAutoStylePoolParent const& rParent : rFamily.m_ParentSet) + { + size_t nProperties = rParent.GetPropertiesList().size(); + for( size_t j = 0; j < nProperties; j++ ) + { + const XMLAutoStylePoolProperties & rProperties = + rParent.GetPropertiesList()[j]; + sal_uInt32 nPos = rProperties.GetPos(); + assert(nPos < nCount); + assert(!aExpStyles[nPos].mpProperties); + aExpStyles[nPos].mpProperties = &const_cast<XMLAutoStylePoolProperties&>(rProperties); + aExpStyles[nPos].mpParent = &rParent.GetParent(); + } + } + + static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr); + + if (bHack) + { + + std::sort(aExpStyles.begin(), aExpStyles.end(), StyleComparator()); + + for (size_t i = 0; i < nCount; i++) + { + OUString oldName = aExpStyles[i].mpProperties->GetName(); + sal_Int32 dashIx = oldName.indexOf('-'); + OUString newName = (dashIx > 0 ? oldName.copy(0, dashIx) : oldName) + OUString::number(i); + aExpStyles[i].mpProperties->SetName(newName); + } + } + + + // create string to export for each XML-style. That means for each property-list + + OUString aStrFamilyName = rFamily.maStrFamilyName; + + for( size_t i = 0; i < nCount; i++ ) + { + assert(aExpStyles[i].mpProperties); + + if( aExpStyles[i].mpProperties ) + { + GetExport().AddAttribute( + XML_NAMESPACE_STYLE, XML_NAME, + aExpStyles[i].mpProperties->GetName() ); + + bool bExtensionNamespace = false; + if( rFamily.mbAsFamily ) + { + GetExport().AddAttribute( + XML_NAMESPACE_STYLE, XML_FAMILY, aStrFamilyName ); + if(aStrFamilyName != "graphic" && + aStrFamilyName != "drawing-page" && + aStrFamilyName != "presentation" && + aStrFamilyName != "chart" ) + bExtensionNamespace = true; + } + + if( !aExpStyles[i].mpParent->isEmpty() ) + { + GetExport().AddAttribute( + XML_NAMESPACE_STYLE, XML_PARENT_STYLE_NAME, + GetExport().EncodeStyleName( + *aExpStyles[i].mpParent ) ); + } + + OUString sName; + if( rFamily.mbAsFamily ) + sName = GetXMLToken(XML_STYLE); + else + sName = rFamily.maStrFamilyName; + + pAntiImpl->exportStyleAttributes(GetExport().GetAttrList(), nFamily, + aExpStyles[i].mpProperties->GetProperties(), + *rFamily.mxMapper, GetExport().GetMM100UnitConverter(), + GetExport().GetNamespaceMap()); + + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_STYLE, sName, + true, true ); + + sal_Int32 nStart(-1); + sal_Int32 nEnd(-1); + if (nFamily == XmlStyleFamily::PAGE_MASTER) + { + nStart = 0; + sal_Int32 nIndex = 0; + rtl::Reference< XMLPropertySetMapper > aPropMapper = + rFamily.mxMapper->getPropertySetMapper(); + sal_Int16 nContextID; + while(nIndex < aPropMapper->GetEntryCount() && nEnd == -1) + { + nContextID = aPropMapper->GetEntryContextId( nIndex ); + if (nContextID && ((nContextID & CTF_PM_FLAGMASK) != XML_PM_CTF_START)) + nEnd = nIndex; + nIndex++; + } + if (nEnd == -1) + nEnd = nIndex; + } + + rFamily.mxMapper->exportXML( + GetExport(), + aExpStyles[i].mpProperties->GetProperties(), + nStart, nEnd, SvXmlExportFlags::IGN_WS, bExtensionNamespace ); + + pAntiImpl->exportStyleContent(GetExport().GetDocHandler(), nFamily, + aExpStyles[i].mpProperties->GetProperties(), + *rFamily.mxMapper, GetExport().GetMM100UnitConverter(), + GetExport().GetNamespaceMap()); + } + } +} + +void SvXMLAutoStylePoolP_Impl::ClearEntries() +{ + for (auto & aI : m_FamilySet) + const_cast<XMLAutoStyleFamily&>(aI).ClearEntries(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/impastpl.hxx b/xmloff/source/style/impastpl.hxx new file mode 100644 index 0000000000..7cbb898171 --- /dev/null +++ b/xmloff/source/style/impastpl.hxx @@ -0,0 +1,176 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <rtl/ref.hxx> +#include <set> +#include <memory> +#include <utility> +#include <vector> + +#include <comphelper/stl_types.hxx> + +#include <xmloff/maptype.hxx> +#include <xmloff/xmlexppr.hxx> +#include <AutoStyleEntry.hxx> + +class SvXMLAutoStylePoolP; +class XMLAutoStylePoolParent; +struct XMLAutoStyleFamily; +class SvXMLExportPropertyMapper; +class SvXMLExport; +enum class XmlStyleFamily; + +// Properties of a pool + +class XMLAutoStylePoolProperties +{ + OUString msName; + ::std::vector< XMLPropertyState > maProperties; + sal_uInt32 mnPos; + +public: + + XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, OUString const & rParentname ); + + const OUString& GetName() const { return msName; } + const ::std::vector< XMLPropertyState >& GetProperties() const { return maProperties; } + sal_uInt32 GetPos() const { return mnPos; } + + void SetName( const OUString& rNew ) { msName = rNew; } +}; + +// Parents of AutoStylePool's +class XMLAutoStylePoolParent +{ +public: + typedef std::vector<XMLAutoStylePoolProperties> PropertiesListType; + +private: + OUString msParent; + PropertiesListType m_PropertiesList; + +public: + + explicit XMLAutoStylePoolParent( OUString aParent ) : + msParent(std::move( aParent )) + { + } + + ~XMLAutoStylePoolParent(); + + bool Add( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, OUString& rName, bool bDontSeek ); + + bool AddNamed( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, const OUString& rName ); + + OUString Find( const XMLAutoStyleFamily& rFamilyData, const ::std::vector< XMLPropertyState >& rProperties ) const; + + const OUString& GetParent() const { return msParent; } + + const PropertiesListType& GetPropertiesList() const { return m_PropertiesList; } + + bool operator< (const XMLAutoStylePoolParent& rOther) const; +}; + +// Implementationclass for stylefamily-information + +struct XMLAutoStyleFamily +{ + typedef std::set<XMLAutoStylePoolParent> ParentSetType; + + XmlStyleFamily mnFamily; + OUString maStrFamilyName; + rtl::Reference<SvXMLExportPropertyMapper> mxMapper; + + ParentSetType m_ParentSet; + std::set<OUString> maNameSet; + std::set<OUString> maReservedNameSet; + sal_uInt32 mnCount; + sal_uInt32 mnName; + OUString maStrPrefix; + bool mbAsFamily; + + XMLAutoStyleFamily( XmlStyleFamily nFamily, OUString aStrName, + rtl::Reference<SvXMLExportPropertyMapper> xMapper, + OUString aStrPrefix, bool bAsFamily ); + + explicit XMLAutoStyleFamily( XmlStyleFamily nFamily ); + + XMLAutoStyleFamily(const XMLAutoStyleFamily&) = delete; + XMLAutoStyleFamily& operator=(const XMLAutoStyleFamily&) = delete; + + friend bool operator<(const XMLAutoStyleFamily& r1, const XMLAutoStyleFamily& r2); + + void ClearEntries(); +}; + +// Implementationclass of SvXMLAutoStylePool + +class SvXMLAutoStylePoolP_Impl +{ + // A set that finds and sorts based only on mnFamily + typedef std::set<XMLAutoStyleFamily> FamilySetType; + + SvXMLExport& rExport; + FamilySetType m_FamilySet; + +public: + + explicit SvXMLAutoStylePoolP_Impl( SvXMLExport& rExport ); + ~SvXMLAutoStylePoolP_Impl(); + + SvXMLExport& GetExport() const { return rExport; } + + void AddFamily( XmlStyleFamily nFamily, const OUString& rStrName, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper, + const OUString& rStrPrefix, bool bAsFamily ); + void SetFamilyPropSetMapper( XmlStyleFamily nFamily, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper ); + void RegisterName( XmlStyleFamily nFamily, const OUString& rName ); + void RegisterDefinedName( XmlStyleFamily nFamily, const OUString& rName ); + void GetRegisteredNames( + css::uno::Sequence<sal_Int32>& aFamilies, + css::uno::Sequence<OUString>& aNames ); + + bool Add( + OUString& rName, XmlStyleFamily nFamily, + const OUString& rParentName, + std::vector< XMLPropertyState >&& rProperties, + bool bDontSeek = false ); + + bool AddNamed( + const OUString& rName, XmlStyleFamily nFamily, + const OUString& rParentName, + std::vector< XMLPropertyState >&& rProperties ); + + OUString Find( XmlStyleFamily nFamily, const OUString& rParent, + const ::std::vector< XMLPropertyState >& rProperties ) const; + + void exportXML( XmlStyleFamily nFamily, + const SvXMLAutoStylePoolP *pAntiImpl) const; + + void ClearEntries(); + + std::vector<xmloff::AutoStyleEntry> GetAutoStyleEntries() const; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/kernihdl.cxx b/xmloff/source/style/kernihdl.cxx new file mode 100644 index 0000000000..cee24fe20e --- /dev/null +++ b/xmloff/source/style/kernihdl.cxx @@ -0,0 +1,78 @@ +/* -*- 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 "kernihdl.hxx" +#include <com/sun/star/uno/Any.hxx> +#include <rtl/ustrbuf.hxx> + + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + + + + +XMLKerningPropHdl::~XMLKerningPropHdl() +{ + // nothing to do +} + +bool XMLKerningPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = true; + sal_Int32 nKerning = 0; + + if( ! IsXMLToken( rStrImpValue, XML_NORMAL ) ) + { + bRet = rUnitConverter.convertMeasureToCore( nKerning, rStrImpValue ); + } + + rValue <<= static_cast<sal_Int16>(nKerning); + + return bRet; +} + +bool XMLKerningPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int16 nValue = sal_Int16(); + + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + + if( nValue == 0 ) + aOut.append( GetXMLToken(XML_NORMAL) ); + else + { + rUnitConverter.convertMeasureToXML( aOut, nValue ); + } + + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/kernihdl.hxx b/xmloff/source/style/kernihdl.hxx new file mode 100644 index 0000000000..3f4a7b4f8f --- /dev/null +++ b/xmloff/source/style/kernihdl.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLKerningPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLKerningPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/lspachdl.cxx b/xmloff/source/style/lspachdl.cxx new file mode 100644 index 0000000000..21a3e7dac8 --- /dev/null +++ b/xmloff/source/style/lspachdl.cxx @@ -0,0 +1,173 @@ +/* -*- 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 "lspachdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <sax/tools/converter.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/style/LineSpacingMode.hpp> + +using namespace ::com::sun::star; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_NORMAL; + + + + +XMLLineHeightHdl::~XMLLineHeightHdl() +{ + // nothing to do +} + +bool XMLLineHeightHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + style::LineSpacing aLSp; + sal_Int32 nTemp = 0; + + if( -1 != rStrImpValue.indexOf( '%' ) ) + { + aLSp.Mode = style::LineSpacingMode::PROP; + if (!::sax::Converter::convertPercent( nTemp, rStrImpValue )) + return false; + aLSp.Height = sal::static_int_cast< sal_Int16 >(nTemp); + } + else if( IsXMLToken( rStrImpValue, XML_NORMAL) ) + { + aLSp.Mode = style::LineSpacingMode::PROP; + aLSp.Height = 100; + } + else + { + aLSp.Mode = style::LineSpacingMode::FIX; + if (!rUnitConverter.convertMeasureToCore( + nTemp, rStrImpValue, 0x0000, 0xffff)) + return false; + aLSp.Height = sal::static_int_cast< sal_Int16 >(nTemp); + } + + rValue <<= aLSp; + return true; +} + +bool XMLLineHeightHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + style::LineSpacing aLSp; + if(!(rValue >>= aLSp)) + return false; + + if( style::LineSpacingMode::PROP != aLSp.Mode && style::LineSpacingMode::FIX != aLSp.Mode ) + return false; + + if( style::LineSpacingMode::PROP == aLSp.Mode ) + { + ::sax::Converter::convertPercent( aOut, aLSp.Height ); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, aLSp.Height ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLLineHeightAtLeastHdl::~XMLLineHeightAtLeastHdl() +{ + // nothing to do +} + +bool XMLLineHeightAtLeastHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + style::LineSpacing aLSp; + + sal_Int32 nTemp; + aLSp.Mode = style::LineSpacingMode::MINIMUM; + if (!rUnitConverter.convertMeasureToCore( nTemp, rStrImpValue, 0, 0xffff)) + return false; + aLSp.Height = sal::static_int_cast< sal_Int16 >(nTemp); + + rValue <<= aLSp; + return true; +} + +bool XMLLineHeightAtLeastHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + style::LineSpacing aLSp; + if(!(rValue >>= aLSp)) + return false; + + if( style::LineSpacingMode::MINIMUM != aLSp.Mode ) + return false; + + rUnitConverter.convertMeasureToXML( aOut, aLSp.Height ); + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLLineSpacingHdl::~XMLLineSpacingHdl() +{ + // nothing to do +} + +bool XMLLineSpacingHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + style::LineSpacing aLSp; + sal_Int32 nTemp; + + aLSp.Mode = style::LineSpacingMode::LEADING; + if (!rUnitConverter.convertMeasureToCore( nTemp, rStrImpValue, 0, 0xffff)) + return false; + aLSp.Height = sal::static_int_cast< sal_Int16 >(nTemp); + + rValue <<= aLSp; + return true; +} + +bool XMLLineSpacingHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + style::LineSpacing aLSp; + if(!(rValue >>= aLSp)) + return false; + + if( style::LineSpacingMode::LEADING != aLSp.Mode ) + return false; + + rUnitConverter.convertMeasureToXML( aOut, aLSp.Height ); + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/lspachdl.hxx b/xmloff/source/style/lspachdl.hxx new file mode 100644 index 0000000000..b0b4d41d7e --- /dev/null +++ b/xmloff/source/style/lspachdl.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLLineHeightHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLLineHeightHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLLineHeightAtLeastHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLLineHeightAtLeastHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLLineSpacingHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLLineSpacingHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/numehelp.cxx b/xmloff/source/style/numehelp.cxx new file mode 100644 index 0000000000..f2c3a3b2ca --- /dev/null +++ b/xmloff/source/style/numehelp.cxx @@ -0,0 +1,510 @@ +/* -*- 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 <xmloff/numehelp.hxx> + +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <com/sun/star/uno/Reference.h> +#include <rtl/ustring.hxx> +#include <svl/zforlist.hxx> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <sax/tools/converter.hxx> +#include <rtl/math.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> + +using namespace com::sun::star; +using namespace xmloff::token; + +constexpr OUString gsStandardFormat(u"StandardFormat"_ustr); +constexpr OUString gsType(u"Type"_ustr); +constexpr OUString gsCurrencySymbol(u"CurrencySymbol"_ustr); +constexpr OUString gsCurrencyAbbreviation(u"CurrencyAbbreviation"_ustr); + +XMLNumberFormatAttributesExportHelper::XMLNumberFormatAttributesExportHelper( + css::uno::Reference< css::util::XNumberFormatsSupplier > const & xTempNumberFormatsSupplier) + : m_xNumberFormats(xTempNumberFormatsSupplier.is() ? xTempNumberFormatsSupplier->getNumberFormats() : css::uno::Reference< css::util::XNumberFormats > ()), + m_pExport(nullptr) +{ +} + +XMLNumberFormatAttributesExportHelper::XMLNumberFormatAttributesExportHelper( + css::uno::Reference< css::util::XNumberFormatsSupplier > const & xTempNumberFormatsSupplier, + SvXMLExport& rTempExport ) +: m_xNumberFormats(xTempNumberFormatsSupplier.is() ? xTempNumberFormatsSupplier->getNumberFormats() : css::uno::Reference< css::util::XNumberFormats > ()), + m_pExport(&rTempExport), + m_sAttrValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_VALUE))), + m_sAttrDateValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_DATE_VALUE))), + m_sAttrTimeValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_TIME_VALUE))), + m_sAttrBooleanValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_BOOLEAN_VALUE))), + m_sAttrStringValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_STRING_VALUE))), + m_sAttrCurrency(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_CURRENCY))) +{ +} + +XMLNumberFormatAttributesExportHelper::~XMLNumberFormatAttributesExportHelper() +{ +} + +sal_Int16 XMLNumberFormatAttributesExportHelper::GetCellType(const sal_Int32 nNumberFormat, OUString& sCurrency, bool& bIsStandard) +{ + XMLNumberFormat aFormat(nNumberFormat); + XMLNumberFormatSet::iterator aItr(m_aNumberFormats.find(aFormat)); + XMLNumberFormatSet::iterator aEndItr(m_aNumberFormats.end()); + if (aItr != aEndItr) + { + bIsStandard = aItr->bIsStandard; + sCurrency = aItr->sCurrency; + return aItr->nType; + } + else + { + aFormat.nType = GetCellType(nNumberFormat, bIsStandard); + aFormat.bIsStandard = bIsStandard; + if ((aFormat.nType & ~util::NumberFormat::DEFINED) == util::NumberFormat::CURRENCY) + if (GetCurrencySymbol(nNumberFormat, aFormat.sCurrency)) + sCurrency = aFormat.sCurrency; + m_aNumberFormats.insert(aFormat); + return aFormat.nType; + } +} + +void XMLNumberFormatAttributesExportHelper::WriteAttributes(SvXMLExport& rXMLExport, + const sal_Int16 nTypeKey, + const double& rValue, + const OUString& rCurrency, + bool bExportValue) +{ + bool bWasSetTypeAttribute = false; + switch(nTypeKey & ~util::NumberFormat::DEFINED) + { + case 0: + case util::NumberFormat::NUMBER: + case util::NumberFormat::SCIENTIFIC: + case util::NumberFormat::FRACTION: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT); + bWasSetTypeAttribute = true; + [[fallthrough]]; + } + case util::NumberFormat::PERCENT: + { + if (!bWasSetTypeAttribute) + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_PERCENTAGE); + bWasSetTypeAttribute = true; + } + [[fallthrough]]; + } + case util::NumberFormat::CURRENCY: + { + if (!bWasSetTypeAttribute) + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_CURRENCY); + if (!rCurrency.isEmpty()) + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CURRENCY, rCurrency); + } + + if (bExportValue) + { + OUString sValue( ::rtl::math::doubleToUString( rValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', true)); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, sValue); + } + } + break; + case util::NumberFormat::DATE: + case util::NumberFormat::DATETIME: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_DATE); + if (bExportValue) + { + if ( rXMLExport.SetNullDateOnUnitConverter() ) + { + OUStringBuffer sBuffer; + rXMLExport.GetMM100UnitConverter().convertDateTime(sBuffer, rValue); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_DATE_VALUE, sBuffer.makeStringAndClear()); + } + } + } + break; + case util::NumberFormat::TIME: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_TIME); + if (bExportValue) + { + OUStringBuffer sBuffer; + ::sax::Converter::convertDuration(sBuffer, rValue); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TIME_VALUE, sBuffer.makeStringAndClear()); + } + } + break; + case util::NumberFormat::LOGICAL: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_BOOLEAN); + if (bExportValue) + { + double fTempValue = rValue; + if (::rtl::math::approxEqual( fTempValue, 1.0 )) + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_TRUE); + } + else + { + if (rValue == 0.0) + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_FALSE); + } + else + { + OUString sValue( ::rtl::math::doubleToUString( + fTempValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', + true)); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, sValue); + } + } + } + } + break; + case util::NumberFormat::TEXT: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT); + if (bExportValue) + { + OUString sValue( ::rtl::math::doubleToUString( rValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', true)); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, sValue); + } + } + break; + } +} + +bool XMLNumberFormatAttributesExportHelper::GetCurrencySymbol(const sal_Int32 nNumberFormat, OUString& sCurrencySymbol, + uno::Reference <util::XNumberFormatsSupplier> const & xNumberFormatsSupplier) +{ + if (xNumberFormatsSupplier.is()) + { + uno::Reference <util::XNumberFormats> xNumberFormats(xNumberFormatsSupplier->getNumberFormats()); + if (xNumberFormats.is()) + { + try + { + uno::Reference <beans::XPropertySet> xNumberPropertySet(xNumberFormats->getByKey(nNumberFormat)); + if ( xNumberPropertySet->getPropertyValue(gsCurrencySymbol) >>= sCurrencySymbol) + { + OUString sCurrencyAbbreviation; + if ( xNumberPropertySet->getPropertyValue(gsCurrencyAbbreviation) >>= sCurrencyAbbreviation) + { + if ( !sCurrencyAbbreviation.isEmpty()) + sCurrencySymbol = sCurrencyAbbreviation; + else + { + if ( sCurrencySymbol.getLength() == 1 && sCurrencySymbol.toChar() == NfCurrencyEntry::GetEuroSymbol() ) + sCurrencySymbol = "EUR"; + } + } + return true; + } + } + catch ( uno::Exception& ) + { + OSL_FAIL("Numberformat not found"); + } + } + } + return false; +} + + +sal_Int16 XMLNumberFormatAttributesExportHelper::GetCellType(const sal_Int32 nNumberFormat, bool& bIsStandard, + uno::Reference <util::XNumberFormatsSupplier> const & xNumberFormatsSupplier) +{ + if (xNumberFormatsSupplier.is()) + { + uno::Reference <util::XNumberFormats> xNumberFormats(xNumberFormatsSupplier->getNumberFormats()); + if (xNumberFormats.is()) + { + try + { + uno::Reference <beans::XPropertySet> xNumberPropertySet(xNumberFormats->getByKey(nNumberFormat)); + xNumberPropertySet->getPropertyValue(gsStandardFormat) >>= bIsStandard; + sal_Int16 nNumberType = sal_Int16(); + if ( xNumberPropertySet->getPropertyValue(gsType) >>= nNumberType ) + { + return nNumberType; + } + } + catch ( uno::Exception& ) + { + OSL_FAIL("Numberformat not found"); + } + } + } + return 0; +} + +void XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes(SvXMLExport& rXMLExport, + const sal_Int32 nNumberFormat, const double& rValue, bool bExportValue) +{ + bool bIsStandard; + sal_Int16 nTypeKey = GetCellType(nNumberFormat, bIsStandard, rXMLExport.GetNumberFormatsSupplier()); + OUString sCurrency; + if ((nTypeKey & ~util::NumberFormat::DEFINED) == util::NumberFormat::CURRENCY) + GetCurrencySymbol(nNumberFormat, sCurrency, rXMLExport.GetNumberFormatsSupplier()); + WriteAttributes(rXMLExport, nTypeKey, rValue, sCurrency, bExportValue); +} + +void XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes(SvXMLExport& rXMLExport, + const OUString& rValue, std::u16string_view rCharacters, + bool bExportValue, bool bExportTypeAttribute) +{ + if (bExportTypeAttribute) + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING); + if (bExportValue && !rValue.isEmpty() && (rValue != rCharacters)) + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, rValue); +} + +bool XMLNumberFormatAttributesExportHelper::GetCurrencySymbol(const sal_Int32 nNumberFormat, OUString& rCurrencySymbol) +{ + if (!m_xNumberFormats.is() && m_pExport && m_pExport->GetNumberFormatsSupplier().is()) + m_xNumberFormats.set(m_pExport->GetNumberFormatsSupplier()->getNumberFormats()); + + if (m_xNumberFormats.is()) + { + try + { + uno::Reference <beans::XPropertySet> xNumberPropertySet(m_xNumberFormats->getByKey(nNumberFormat)); + if ( xNumberPropertySet->getPropertyValue(gsCurrencySymbol) >>= rCurrencySymbol) + { + OUString sCurrencyAbbreviation; + if ( xNumberPropertySet->getPropertyValue(gsCurrencyAbbreviation) >>= sCurrencyAbbreviation) + { + if ( !sCurrencyAbbreviation.isEmpty()) + rCurrencySymbol = sCurrencyAbbreviation; + else + { + if ( rCurrencySymbol.getLength() == 1 && rCurrencySymbol.toChar() == NfCurrencyEntry::GetEuroSymbol() ) + rCurrencySymbol = "EUR"; + } + } + return true; + } + } + catch ( uno::Exception& ) + { + OSL_FAIL("Numberformat not found"); + } + } + return false; +} + +sal_Int16 XMLNumberFormatAttributesExportHelper::GetCellType(const sal_Int32 nNumberFormat, bool& bIsStandard) +{ + if (!m_xNumberFormats.is() && m_pExport && m_pExport->GetNumberFormatsSupplier().is()) + m_xNumberFormats.set(m_pExport->GetNumberFormatsSupplier()->getNumberFormats()); + + if (m_xNumberFormats.is()) + { + try + { + uno::Reference <beans::XPropertySet> xNumberPropertySet(m_xNumberFormats->getByKey(nNumberFormat)); + if (xNumberPropertySet.is()) + { + xNumberPropertySet->getPropertyValue(gsStandardFormat) >>= bIsStandard; + sal_Int16 nNumberType = sal_Int16(); + if ( xNumberPropertySet->getPropertyValue(gsType) >>= nNumberType ) + { + return nNumberType; + } + } + } + catch ( uno::Exception& ) + { + OSL_FAIL("Numberformat not found"); + } + } + return 0; +} + +void XMLNumberFormatAttributesExportHelper::WriteAttributes( + const sal_Int16 nTypeKey, + const double& rValue, + const OUString& rCurrency, + bool bExportValue, sal_uInt16 nNamespace) +{ + if (!m_pExport) + return; + + bool bWasSetTypeAttribute = false; + OUString sAttrValType = m_pExport->GetNamespaceMap().GetQNameByKey( nNamespace, GetXMLToken(XML_VALUE_TYPE)); + switch(nTypeKey & ~util::NumberFormat::DEFINED) + { + case 0: + case util::NumberFormat::NUMBER: + case util::NumberFormat::SCIENTIFIC: + case util::NumberFormat::FRACTION: + { + m_pExport->AddAttribute(sAttrValType, XML_FLOAT); + bWasSetTypeAttribute = true; + [[fallthrough]]; + } + case util::NumberFormat::PERCENT: + { + if (!bWasSetTypeAttribute) + { + m_pExport->AddAttribute(sAttrValType, XML_PERCENTAGE); + bWasSetTypeAttribute = true; + } + [[fallthrough]]; + } + case util::NumberFormat::CURRENCY: + { + if (!bWasSetTypeAttribute) + { + m_pExport->AddAttribute(sAttrValType, XML_CURRENCY); + if (!rCurrency.isEmpty()) + m_pExport->AddAttribute(m_sAttrCurrency, rCurrency); + } + + if (bExportValue) + { + OUString sValue( ::rtl::math::doubleToUString( rValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', true)); + m_pExport->AddAttribute(m_sAttrValue, sValue); + } + } + break; + case util::NumberFormat::DATE: + case util::NumberFormat::DATETIME: + { + m_pExport->AddAttribute(sAttrValType, XML_DATE); + if (bExportValue) + { + if ( m_pExport->SetNullDateOnUnitConverter() ) + { + OUStringBuffer sBuffer; + m_pExport->GetMM100UnitConverter().convertDateTime(sBuffer, rValue); + m_pExport->AddAttribute(m_sAttrDateValue, sBuffer.makeStringAndClear()); + } + } + } + break; + case util::NumberFormat::TIME: + { + m_pExport->AddAttribute(sAttrValType, XML_TIME); + if (bExportValue) + { + OUStringBuffer sBuffer; + ::sax::Converter::convertDuration(sBuffer, rValue); + m_pExport->AddAttribute(m_sAttrTimeValue, sBuffer.makeStringAndClear()); + } + } + break; + case util::NumberFormat::LOGICAL: + { + m_pExport->AddAttribute(sAttrValType, XML_BOOLEAN); + if (bExportValue) + { + double fTempValue = rValue; + if (::rtl::math::approxEqual( fTempValue, 1.0 )) + { + m_pExport->AddAttribute(m_sAttrBooleanValue, XML_TRUE); + } + else + { + if (rValue == 0.0) + { + m_pExport->AddAttribute(m_sAttrBooleanValue, XML_FALSE); + } + else + { + OUString sValue( ::rtl::math::doubleToUString( + fTempValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', + true)); + m_pExport->AddAttribute(m_sAttrBooleanValue, sValue); + } + } + } + } + break; + case util::NumberFormat::TEXT: + { + m_pExport->AddAttribute(sAttrValType, XML_FLOAT); + if (bExportValue) + { + OUString sValue( ::rtl::math::doubleToUString( rValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', true)); + m_pExport->AddAttribute(m_sAttrValue, sValue); + } + } + break; + } +} + +void XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes( + const sal_Int32 nNumberFormat, const double& rValue, bool bExportValue, + sal_uInt16 nNamespace, bool bExportCurrencySymbol) +{ + if (m_pExport) + { + bool bIsStandard; + OUString sCurrency; + sal_Int16 nTypeKey = GetCellType(nNumberFormat, sCurrency, bIsStandard); + if(!bExportCurrencySymbol) + sCurrency.clear(); + + WriteAttributes(nTypeKey, rValue, sCurrency, bExportValue, nNamespace); + } + else { + OSL_FAIL("no SvXMLExport given"); + } +} + +void XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes( + const OUString& rValue, std::u16string_view rCharacters, + bool bExportValue, + sal_uInt16 nNamespace) +{ + if (m_pExport) + { + m_pExport->AddAttribute(nNamespace, XML_VALUE_TYPE, XML_STRING); + if (bExportValue && !rValue.isEmpty() && (rValue != rCharacters)) + m_pExport->AddAttribute(m_sAttrStringValue, rValue); + } + else { + OSL_FAIL("no SvXMLExport given"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/opaquhdl.cxx b/xmloff/source/style/opaquhdl.cxx new file mode 100644 index 0000000000..c710d67c67 --- /dev/null +++ b/xmloff/source/style/opaquhdl.cxx @@ -0,0 +1,61 @@ +/* -*- 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 "opaquhdl.hxx" +#include <com/sun/star/uno/Any.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + + +XMLOpaquePropHdl::~XMLOpaquePropHdl() +{ + // nothing to do +} + +bool XMLOpaquePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue = IsXMLToken( rStrImpValue, XML_FOREGROUND ); + rValue <<= bValue; + + return true; +} + +bool XMLOpaquePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + if( bValue ) + rStrExpValue = GetXMLToken( XML_FOREGROUND ); + else + rStrExpValue = GetXMLToken( XML_BACKGROUND ); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/opaquhdl.hxx b/xmloff/source/style/opaquhdl.hxx new file mode 100644 index 0000000000..1d4c193a96 --- /dev/null +++ b/xmloff/source/style/opaquhdl.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLOpaquePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLOpaquePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/postuhdl.cxx b/xmloff/source/style/postuhdl.cxx new file mode 100644 index 0000000000..5e0d5bfbc6 --- /dev/null +++ b/xmloff/source/style/postuhdl.cxx @@ -0,0 +1,81 @@ +/* -*- 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 "postuhdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/awt/FontSlant.hpp> +#include <tools/fontenum.hxx> +#include <vcl/unohelp.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<FontItalic> const aPostureGenericMapping[] = +{ + { XML_NORMAL, ITALIC_NONE }, + { XML_ITALIC, ITALIC_NORMAL }, + { XML_POSTURE_OBLIQUE, ITALIC_OBLIQUE }, + { XML_TOKEN_INVALID, FontItalic(0) } +}; + + + + +XMLPosturePropHdl::~XMLPosturePropHdl() +{ + // nothing to do +} + +bool XMLPosturePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + FontItalic ePosture; + bool bRet = SvXMLUnitConverter::convertEnum( ePosture, rStrImpValue, aPostureGenericMapping ); + if( bRet ) + rValue <<= vcl::unohelper::ConvertFontSlant(ePosture); + + return bRet; +} + +bool XMLPosturePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + awt::FontSlant eSlant; + + if( !( rValue >>= eSlant ) ) + { + sal_Int32 nValue = 0; + + if( !( rValue >>= nValue ) ) + return false; + + eSlant = static_cast<awt::FontSlant>(nValue); + } + + OUStringBuffer aOut; + bool bRet = SvXMLUnitConverter::convertEnum(aOut, vcl::unohelper::ConvertFontSlant(eSlant), aPostureGenericMapping); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/postuhdl.hxx b/xmloff/source/style/postuhdl.hxx new file mode 100644 index 0000000000..b63abd607a --- /dev/null +++ b/xmloff/source/style/postuhdl.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLPosturePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLPosturePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/prhdlfac.cxx b/xmloff/source/style/prhdlfac.cxx new file mode 100644 index 0000000000..a3ab3290be --- /dev/null +++ b/xmloff/source/style/prhdlfac.cxx @@ -0,0 +1,486 @@ +/* -*- 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 <xmloff/prhdlfac.hxx> + +#include <com/sun/star/drawing/ColorMode.hpp> +#include <com/sun/star/text/HorizontalAdjust.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/text/VertOrientation.hpp> + + +#include <sal/log.hxx> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlprhdl.hxx> +#include "xmlbahdl.hxx" +#include <xmloff/NamedBoolPropertyHdl.hxx> +#include <xmloff/XMLConstantsPropertyHandler.hxx> +#include "cdouthdl.hxx" +#include "csmaphdl.hxx" +#include "fonthdl.hxx" +#include "kernihdl.hxx" +#include "postuhdl.hxx" +#include "shadwhdl.hxx" +#include "shdwdhdl.hxx" +#include "undlihdl.hxx" +#include "weighhdl.hxx" +#include "breakhdl.hxx" +#include "adjushdl.hxx" +#include "escphdl.hxx" +#include "chrhghdl.hxx" +#include "chrlohdl.hxx" +#include "lspachdl.hxx" +#include "bordrhdl.hxx" +#include "tabsthdl.hxx" +#include <xmloff/EnumPropertyHdl.hxx> +#include <AttributeContainerHandler.hxx> +#include "durationhdl.hxx" +#include <XMLRectangleMembersHandler.hxx> +#include <XMLNumberWithAutoForVoidPropHdl.hxx> +#include "DrawAspectHdl.hxx" +#include <xmloff/XMLComplexColorHandler.hxx> + +#include <map> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<drawing::ColorMode> const aXML_ColorMode_EnumMap[] = +{ + { XML_GREYSCALE, drawing::ColorMode_GREYS }, + { XML_MONO, drawing::ColorMode_MONO }, + { XML_WATERMARK, drawing::ColorMode_WATERMARK }, + { XML_STANDARD, drawing::ColorMode_STANDARD }, + { XML_TOKEN_INVALID, drawing::ColorMode(0) } +}; + +SvXMLEnumMapEntry<text::HorizontalAdjust> const aXML_HorizontalAdjust_Enum[] = +{ + { XML_LEFT, text::HorizontalAdjust_LEFT }, + { XML_CENTER, text::HorizontalAdjust_CENTER }, + { XML_RIGHT, text::HorizontalAdjust_RIGHT }, + { XML_TOKEN_INVALID, text::HorizontalAdjust(0) } +}; + +// aXML_WritingDirection_Enum is used with and without 'page' +// attribute, so you'll find uses of aXML_WritingDirection_Enum +// directly, as well as &(aXML_WritingDirection_Enum[1]) +SvXMLEnumMapEntry<sal_uInt16> const aXML_WritingDirection_Enum[] = +{ + // aXML_WritingDirection_Enum + { XML_PAGE, text::WritingMode2::PAGE }, + + // &(aXML_WritingDirection_Enum[1]) + { XML_LR_TB, text::WritingMode2::LR_TB }, + { XML_RL_TB, text::WritingMode2::RL_TB }, + { XML_TB_RL, text::WritingMode2::TB_RL }, + { XML_TB_LR, text::WritingMode2::TB_LR }, + { XML_BT_LR, text::WritingMode2::BT_LR }, + + // alternative names of the above, as accepted by XSL + { XML_LR, text::WritingMode2::LR_TB }, + { XML_RL, text::WritingMode2::RL_TB }, + { XML_TB, text::WritingMode2::TB_RL }, + + // vertical as clockwise 90deg rotation, for OOXML vert="vert" + { XML_TB_RL90, text::WritingMode2::TB_RL90 }, + + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_VertPos_Enum[] = +{ + { XML_FROM_TOP, text::VertOrientation::NONE }, + { XML_TOP, text::VertOrientation::TOP }, + { XML_TOP, text::VertOrientation::CHAR_TOP }, // export only + { XML_TOP, text::VertOrientation::LINE_TOP }, // export only + { XML_MIDDLE, text::VertOrientation::CENTER }, + { XML_MIDDLE, text::VertOrientation::CHAR_CENTER }, // export only + { XML_MIDDLE, text::VertOrientation::LINE_CENTER }, // export only + { XML_BOTTOM, text::VertOrientation::BOTTOM }, + { XML_BOTTOM, text::VertOrientation::CHAR_BOTTOM }, // export only + { XML_BOTTOM, text::VertOrientation::LINE_BOTTOM }, // export only + { XML_BELOW, text::VertOrientation::CHAR_BOTTOM }, // import only + { XML_TOKEN_INVALID, 0 } +}; + +typedef std::map<sal_Int32, const XMLPropertyHandler*> CacheMap; + +struct XMLPropertyHandlerFactory::Impl +{ + mutable CacheMap maHandlerCache; +}; + +XMLPropertyHandlerFactory::XMLPropertyHandlerFactory() : + mpImpl(new Impl) {} + +XMLPropertyHandlerFactory::~XMLPropertyHandlerFactory() +{ + for( const auto& rCacheEntry : mpImpl->maHandlerCache ) + delete rCacheEntry.second; +} + +// Interface +const XMLPropertyHandler* XMLPropertyHandlerFactory::GetPropertyHandler( sal_Int32 nType ) const +{ + SAL_WARN_IF( (nType & ~(sal_uInt32(MID_FLAG_MASK))) != 0, "xmloff", + "GetPropertyHandler called with flags in type" ); + return GetBasicHandler( nType ); +} + +// Helper-methods to create and cache PropertyHandler +const XMLPropertyHandler* XMLPropertyHandlerFactory::GetHdlCache( sal_Int32 nType ) const +{ + const XMLPropertyHandler* pRet = nullptr; + + if( mpImpl->maHandlerCache.find( nType ) != mpImpl->maHandlerCache.end() ) + pRet = mpImpl->maHandlerCache.find( nType )->second; + + return pRet; +} + +void XMLPropertyHandlerFactory::PutHdlCache( sal_Int32 nType, const XMLPropertyHandler* pHdl ) const +{ + mpImpl->maHandlerCache[nType] = pHdl; +} + +const XMLPropertyHandler* XMLPropertyHandlerFactory::GetBasicHandler( sal_Int32 nType ) const +{ + const XMLPropertyHandler* pPropHdl = GetHdlCache( nType ); + if( pPropHdl ) + return pPropHdl; + + std::unique_ptr<XMLPropertyHandler> pNewPropHdl = CreatePropertyHandler( nType ); + if( pNewPropHdl ) + PutHdlCache( nType, pNewPropHdl.get() ); + return pNewPropHdl.release(); +} + +std::unique_ptr<XMLPropertyHandler> XMLPropertyHandlerFactory::CreatePropertyHandler( sal_Int32 nType ) +{ + std::unique_ptr<XMLPropertyHandler> pPropHdl; + + switch( nType ) + { + case XML_TYPE_BOOL : + pPropHdl.reset(new XMLBoolPropHdl); + break; + case XML_TYPE_BOOL_FALSE : + pPropHdl.reset(new XMLBoolFalsePropHdl); + break; + case XML_TYPE_MEASURE : + pPropHdl.reset(new XMLMeasurePropHdl( 4 )); + break; + case XML_TYPE_MEASURE8 : + pPropHdl.reset(new XMLMeasurePropHdl( 1 )); + break; + case XML_TYPE_MEASURE16: + pPropHdl.reset(new XMLMeasurePropHdl( 2 )); + break; + case XML_TYPE_PERCENT : + pPropHdl.reset(new XMLPercentPropHdl( 4 )); + break; + case XML_TYPE_PERCENT8 : + pPropHdl.reset(new XMLPercentPropHdl( 1 )); + break; + case XML_TYPE_PERCENT16 : + pPropHdl.reset(new XMLPercentPropHdl( 2 )); + break; + case XML_TYPE_PERCENT100: + pPropHdl.reset(new XML100thPercentPropHdl); + break; + case XML_TYPE_DOUBLE_PERCENT : + pPropHdl.reset(new XMLDoublePercentPropHdl); + break; + case XML_TYPE_NEG_PERCENT : + pPropHdl.reset(new XMLNegPercentPropHdl( 4 )); + break; + case XML_TYPE_NEG_PERCENT8 : + pPropHdl.reset(new XMLNegPercentPropHdl( 1 )); + break; + case XML_TYPE_NEG_PERCENT16 : + pPropHdl.reset(new XMLNegPercentPropHdl( 2 )); + break; + case XML_TYPE_MEASURE_PX : + pPropHdl.reset(new XMLMeasurePxPropHdl( 4 )); + break; + case XML_TYPE_STRING : + pPropHdl.reset(new XMLStringPropHdl); + break; + case XML_TYPE_COLOR : + pPropHdl.reset(new XMLColorPropHdl); + break; + case XML_TYPE_HEX : + pPropHdl.reset(new XMLHexPropHdl); + break; + case XML_TYPE_NUMBER : + pPropHdl.reset(new XMLNumberPropHdl( 4 )); + break; + case XML_TYPE_NUMBER8 : + pPropHdl.reset(new XMLNumberPropHdl( 1 )); + break; + case XML_TYPE_NUMBER16: + pPropHdl.reset(new XMLNumberPropHdl( 2 )); + break; + case XML_TYPE_NUMBER_NONE : + pPropHdl.reset(new XMLNumberNonePropHdl); + break; + case XML_TYPE_NUMBER8_NONE : + pPropHdl.reset(new XMLNumberNonePropHdl( 1 )); + break; + case XML_TYPE_NUMBER16_NONE : + pPropHdl.reset(new XMLNumberNonePropHdl( 2 )); + break; + case XML_TYPE_DOUBLE : + pPropHdl.reset(new XMLDoublePropHdl); + break; + case XML_TYPE_NBOOL : + pPropHdl.reset(new XMLNBoolPropHdl); + break; + case XML_TYPE_COLORTRANSPARENT : + pPropHdl.reset(new XMLColorTransparentPropHdl); + break; + case XML_TYPE_ISTRANSPARENT : + pPropHdl.reset(new XMLIsTransparentPropHdl); + break; + case XML_TYPE_COLORAUTO : + pPropHdl.reset(new XMLColorAutoPropHdl); + break; + case XML_TYPE_ISAUTOCOLOR : + pPropHdl.reset(new XMLIsAutoColorPropHdl); + break; + case XML_TYPE_BUILDIN_CMP_ONLY : + pPropHdl.reset(new XMLCompareOnlyPropHdl); + break; + + case XML_TYPE_RECTANGLE_LEFT : + case XML_TYPE_RECTANGLE_TOP : + case XML_TYPE_RECTANGLE_WIDTH : + case XML_TYPE_RECTANGLE_HEIGHT : + pPropHdl.reset(new XMLRectangleMembersHdl( nType )); + break; + + case XML_TYPE_TEXT_CROSSEDOUT_TYPE: + pPropHdl.reset(new XMLCrossedOutTypePropHdl) ; + break; + case XML_TYPE_TEXT_CROSSEDOUT_STYLE: + pPropHdl.reset(new XMLCrossedOutStylePropHdl) ; + break; + case XML_TYPE_TEXT_CROSSEDOUT_WIDTH: + pPropHdl.reset(new XMLCrossedOutWidthPropHdl) ; + break; + case XML_TYPE_TEXT_CROSSEDOUT_TEXT: + pPropHdl.reset(new XMLCrossedOutTextPropHdl) ; + break; + case XML_TYPE_TEXT_BOOLCROSSEDOUT: + pPropHdl.reset(new XMLNamedBoolPropertyHdl( + GetXMLToken(XML_SOLID), + GetXMLToken(XML_NONE) )); + break; + case XML_TYPE_TEXT_ESCAPEMENT: + pPropHdl.reset(new XMLEscapementPropHdl); + break; + case XML_TYPE_TEXT_ESCAPEMENT_HEIGHT: + pPropHdl.reset(new XMLEscapementHeightPropHdl); + break; + case XML_TYPE_TEXT_CASEMAP: + pPropHdl.reset(new XMLCaseMapPropHdl); + break; + case XML_TYPE_TEXT_CASEMAP_VAR: + pPropHdl.reset(new XMLCaseMapVariantHdl); + break; + case XML_TYPE_TEXT_FONTFAMILYNAME: + pPropHdl.reset(new XMLFontFamilyNamePropHdl); + break; + case XML_TYPE_TEXT_FONTFAMILY: + pPropHdl.reset(new XMLFontFamilyPropHdl); + break; + case XML_TYPE_TEXT_FONTENCODING: + pPropHdl.reset(new XMLFontEncodingPropHdl); + break; + case XML_TYPE_TEXT_FONTPITCH: + pPropHdl.reset(new XMLFontPitchPropHdl); + break; + case XML_TYPE_TEXT_KERNING: + pPropHdl.reset(new XMLKerningPropHdl); + break; + case XML_TYPE_TEXT_POSTURE: + pPropHdl.reset(new XMLPosturePropHdl); + break; + case XML_TYPE_TEXT_SHADOWED: + pPropHdl.reset(new XMLShadowedPropHdl); + break; + case XML_TYPE_TEXT_UNDERLINE_TYPE: + pPropHdl.reset(new XMLUnderlineTypePropHdl); + break; + case XML_TYPE_TEXT_UNDERLINE_STYLE: + pPropHdl.reset(new XMLUnderlineStylePropHdl); + break; + case XML_TYPE_TEXT_UNDERLINE_WIDTH: + pPropHdl.reset(new XMLUnderlineWidthPropHdl); + break; + case XML_TYPE_TEXT_UNDERLINE_COLOR: + pPropHdl.reset(new XMLColorTransparentPropHdl( XML_FONT_COLOR )); + break; + case XML_TYPE_TEXT_UNDERLINE_HASCOLOR: + pPropHdl.reset(new XMLIsTransparentPropHdl( XML_FONT_COLOR, + false )); + break; + case XML_TYPE_TEXT_OVERLINE_TYPE: + pPropHdl.reset(new XMLUnderlineTypePropHdl); + break; + case XML_TYPE_TEXT_OVERLINE_STYLE: + pPropHdl.reset(new XMLUnderlineStylePropHdl); + break; + case XML_TYPE_TEXT_OVERLINE_WIDTH: + pPropHdl.reset(new XMLUnderlineWidthPropHdl); + break; + case XML_TYPE_TEXT_OVERLINE_COLOR: + pPropHdl.reset(new XMLColorTransparentPropHdl( XML_FONT_COLOR )); + break; + case XML_TYPE_TEXT_OVERLINE_HASCOLOR: + pPropHdl.reset(new XMLIsTransparentPropHdl( XML_FONT_COLOR, + false )); + break; + case XML_TYPE_TEXT_WEIGHT: + pPropHdl.reset(new XMLFontWeightPropHdl); + break; + case XML_TYPE_TEXT_SPLIT: + pPropHdl.reset(new XMLNamedBoolPropertyHdl( + GetXMLToken(XML_AUTO), + GetXMLToken(XML_ALWAYS) )); + break; + case XML_TYPE_TEXT_BREAKBEFORE: + pPropHdl.reset(new XMLFmtBreakBeforePropHdl); + break; + case XML_TYPE_TEXT_BREAKAFTER: + pPropHdl.reset(new XMLFmtBreakAfterPropHdl); + break; + case XML_TYPE_TEXT_SHADOW: + pPropHdl.reset(new XMLShadowPropHdl); + break; + case XML_TYPE_TEXT_ADJUST: + pPropHdl.reset(new XMLParaAdjustPropHdl); + break; + case XML_TYPE_TEXT_ADJUSTLAST: + pPropHdl.reset(new XMLLastLineAdjustPropHdl); + break; + case XML_TYPE_CHAR_HEIGHT: + pPropHdl.reset(new XMLCharHeightHdl); + break; + case XML_TYPE_CHAR_HEIGHT_PROP: + pPropHdl.reset(new XMLCharHeightPropHdl); + break; + case XML_TYPE_CHAR_HEIGHT_DIFF: + pPropHdl.reset(new XMLCharHeightDiffHdl); + break; + case XML_TYPE_CHAR_RFC_LANGUAGE_TAG: + pPropHdl.reset(new XMLCharRfcLanguageTagHdl); + break; + case XML_TYPE_CHAR_LANGUAGE: + pPropHdl.reset(new XMLCharLanguageHdl); + break; + case XML_TYPE_CHAR_SCRIPT: + pPropHdl.reset(new XMLCharScriptHdl); + break; + case XML_TYPE_CHAR_COUNTRY: + pPropHdl.reset(new XMLCharCountryHdl); + break; + case XML_TYPE_LINE_SPACE_FIXED: + pPropHdl.reset(new XMLLineHeightHdl); + break; + case XML_TYPE_LINE_SPACE_MINIMUM: + pPropHdl.reset(new XMLLineHeightAtLeastHdl); + break; + case XML_TYPE_LINE_SPACE_DISTANCE: + pPropHdl.reset(new XMLLineSpacingHdl); + break; + case XML_TYPE_BORDER_WIDTH: + pPropHdl.reset(new XMLBorderWidthHdl); + break; + case XML_TYPE_BORDER: + pPropHdl.reset(new XMLBorderHdl); + break; + case XML_TYPE_TEXT_TABSTOP: + pPropHdl.reset(new XMLTabStopPropHdl); + break; + case XML_TYPE_ATTRIBUTE_CONTAINER: + pPropHdl.reset(new XMLAttributeContainerHandler); + break; + case XML_TYPE_COLOR_MODE: + pPropHdl.reset(new XMLEnumPropertyHdl(aXML_ColorMode_EnumMap)); + break; + case XML_TYPE_DURATION16_MS: + pPropHdl.reset(new XMLDurationMS16PropHdl_Impl); + break; + case XML_TYPE_TEXT_HORIZONTAL_ADJUST: + pPropHdl.reset(new XMLEnumPropertyHdl(aXML_HorizontalAdjust_Enum)); + break; + case XML_TYPE_TEXT_DRAW_ASPECT: + pPropHdl.reset(new DrawAspectHdl); + break; + case XML_TYPE_TEXT_WRITING_MODE: + pPropHdl.reset(new XMLConstantsPropertyHandler( + &(aXML_WritingDirection_Enum[1]), + XML_LR_TB)); + break; + case XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT: + pPropHdl.reset(new XMLConstantsPropertyHandler( + aXML_WritingDirection_Enum, + XML_PAGE)); + break; + case XML_TYPE_TEXT_HIDDEN_AS_DISPLAY: + pPropHdl.reset(new XMLNamedBoolPropertyHdl( + GetXMLToken(XML_NONE), + GetXMLToken(XML_TRUE) )); + break; + case XML_TYPE_STYLENAME : + pPropHdl.reset(new XMLStyleNamePropHdl); + break; + case XML_TYPE_NUMBER_NO_ZERO: + pPropHdl.reset(new XMLNumberWithoutZeroPropHdl( 4 )); + break; + case XML_TYPE_NUMBER8_NO_ZERO: + pPropHdl.reset(new XMLNumberWithoutZeroPropHdl( 1 )); + break; + case XML_TYPE_NUMBER16_NO_ZERO: + pPropHdl.reset(new XMLNumberWithoutZeroPropHdl( 2 )); + break; + case XML_TYPE_NUMBER16_AUTO: + pPropHdl.reset(new XMLNumberWithAutoForVoidPropHdl); + break; + case XML_TYPE_TEXT_VERTICAL_POS: + pPropHdl.reset(new XMLConstantsPropertyHandler( pXML_VertPos_Enum, XML_TOKEN_INVALID )); + break; + case XML_TYPE_TEXT_OVERFLOW_BEHAVIOR: + // auto-create-new-frame isn't properly implemented yet. It just means don't clip. + pPropHdl.reset(new XMLNamedBoolPropertyHdl(GetXMLToken(XML_CLIP), + GetXMLToken(XML_AUTO_CREATE_NEW_FRAME))); + break; + case XML_TYPE_COMPLEX_COLOR: + pPropHdl.reset(new XMLComplexColorHandler); + break; + } + + return pPropHdl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/prstylecond.cxx b/xmloff/source/style/prstylecond.cxx new file mode 100644 index 0000000000..a7ab66f835 --- /dev/null +++ b/xmloff/source/style/prstylecond.cxx @@ -0,0 +1,91 @@ +/* -*- 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 <rtl/ustring.hxx> +#include <prstylecond.hxx> +#include <xmloff/xmltoken.hxx> + +using namespace ::xmloff::token; + +// note: keep this in sync with the list of conditions in sw/source/uibase/chrdlg/ccoll.cxx + +namespace { + +struct ConditionMap +{ + char const* aInternal; + XMLTokenEnum nExternal; + int aValue; +}; + +} + +const ConditionMap g_ConditionMap[] = +{ + { "TableHeader", XML_TABLE_HEADER, -1 }, + { "Table", XML_TABLE, -1 }, + { "Frame", XML_TEXT_BOX, -1 }, // FIXME - Not in ODF spec + { "Section", XML_SECTION, -1 }, + { "Footnote", XML_FOOTNOTE, -1 }, + { "Endnote", XML_ENDNOTE, -1 }, + { "Header", XML_HEADER, -1 }, + { "Footer", XML_FOOTER, -1 }, + { "OutlineLevel1", XML_OUTLINE_LEVEL, 1 }, + { "OutlineLevel2", XML_OUTLINE_LEVEL, 2 }, + { "OutlineLevel3", XML_OUTLINE_LEVEL, 3 }, + { "OutlineLevel4", XML_OUTLINE_LEVEL, 4 }, + { "OutlineLevel5", XML_OUTLINE_LEVEL, 5 }, + { "OutlineLevel6", XML_OUTLINE_LEVEL, 6 }, + { "OutlineLevel7", XML_OUTLINE_LEVEL, 7 }, + { "OutlineLevel8", XML_OUTLINE_LEVEL, 8 }, + { "OutlineLevel9", XML_OUTLINE_LEVEL, 9 }, + { "OutlineLevel10", XML_OUTLINE_LEVEL, 10 }, + { "NumberingLevel1", XML_LIST_LEVEL, 1 }, + { "NumberingLevel2", XML_LIST_LEVEL, 2 }, + { "NumberingLevel3", XML_LIST_LEVEL, 3 }, + { "NumberingLevel4", XML_LIST_LEVEL, 4 }, + { "NumberingLevel5", XML_LIST_LEVEL, 5 }, + { "NumberingLevel6", XML_LIST_LEVEL, 6 }, + { "NumberingLevel7", XML_LIST_LEVEL, 7 }, + { "NumberingLevel8", XML_LIST_LEVEL, 8 }, + { "NumberingLevel9", XML_LIST_LEVEL, 9 }, + { "NumberingLevel10", XML_LIST_LEVEL, 10 } +}; + +OUString GetParaStyleCondExternal( std::u16string_view internal) +{ + for (size_t i = 0; i < SAL_N_ELEMENTS(g_ConditionMap); ++i) + { + if (o3tl::equalsAscii(internal, g_ConditionMap[i].aInternal )) + { + OUString aResult = GetXMLToken( g_ConditionMap[i].nExternal ) + + "()"; + if (g_ConditionMap[i].aValue != -1) + { + aResult += "=" + + OUString::number( g_ConditionMap[i].aValue ); + } + return aResult; + } + } + assert(!"GetParaStyleCondExternal: model has unknown style condition"); + return OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/prstylei.cxx b/xmloff/source/style/prstylei.cxx new file mode 100644 index 0000000000..7aef1ec4c0 --- /dev/null +++ b/xmloff/source/style/prstylei.cxx @@ -0,0 +1,661 @@ +/* -*- 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 <sal/config.h> + +#include <o3tl/any.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <set> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlprcon.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/style/XAutoStyleFamily.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XMultiPropertyStates.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <xmloff/xmlimp.hxx> +#include <xmloff/prstylei.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlprmap.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/drawing/FillStyle.hpp> +#include "StylePropertiesContext.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::xmloff::token; +using namespace com::sun::star::drawing; + +void XMLPropStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_FAMILY) ) + { + SAL_WARN_IF( GetFamily() != SvXMLStylesContext::GetFamily( rValue ), "xmloff", "unexpected style family" ); + } + else + { + SvXMLStyleContext::SetAttribute( nElement, rValue ); + } +} + + +namespace +{ + const OldFillStyleDefinitionSet & theStandardSet() + { + static const OldFillStyleDefinitionSet theSet = []() + { + OldFillStyleDefinitionSet aSet; + aSet.insert("BackColorRGB"); + aSet.insert("BackTransparent"); + aSet.insert("BackColorTransparency"); + aSet.insert("BackGraphic"); + aSet.insert("BackGraphicFilter"); + aSet.insert("BackGraphicLocation"); + aSet.insert("BackGraphicTransparency"); + return aSet; + }(); + return theSet; + }; + const OldFillStyleDefinitionSet & theHeaderSet() + { + static const OldFillStyleDefinitionSet theSet = []() + { + OldFillStyleDefinitionSet aSet; + aSet.insert("HeaderBackColorRGB"); + aSet.insert("HeaderBackTransparent"); + aSet.insert("HeaderBackColorTransparency"); + aSet.insert("HeaderBackGraphic"); + aSet.insert("HeaderBackGraphicFilter"); + aSet.insert("HeaderBackGraphicLocation"); + aSet.insert("HeaderBackGraphicTransparency"); + return aSet; + }(); + return theSet; + }; + const OldFillStyleDefinitionSet & theFooterSet() + { + static const OldFillStyleDefinitionSet theSet = []() + { + OldFillStyleDefinitionSet aSet; + aSet.insert("FooterBackColorRGB"); + aSet.insert("FooterBackTransparent"); + aSet.insert("FooterBackColorTransparency"); + aSet.insert("FooterBackGraphic"); + aSet.insert("FooterBackGraphicFilter"); + aSet.insert("FooterBackGraphicLocation"); + aSet.insert("FooterBackGraphicTransparency"); + return aSet; + }(); + return theSet; + }; + const OldFillStyleDefinitionSet & theParaSet() + { + static const OldFillStyleDefinitionSet theSet = []() + { + OldFillStyleDefinitionSet aSet; + // Caution: here it is *not* 'ParaBackColorRGB' as it should be, but indeed + // 'ParaBackColor' is used, see aXMLParaPropMap definition (line 313) + aSet.insert("ParaBackColor"); + aSet.insert("ParaBackTransparent"); + aSet.insert("ParaBackGraphicLocation"); + aSet.insert("ParaBackGraphicFilter"); + aSet.insert("ParaBackGraphic"); + + // These are not used in aXMLParaPropMap definition, thus not needed here + // aSet.insert("ParaBackColorTransparency"); + // aSet.insert("ParaBackGraphicTransparency"); + return aSet; + }(); + return theSet; + }; +} + + + +constexpr OUString gsIsPhysical( u"IsPhysical"_ustr ); +constexpr OUString gsFollowStyle( u"FollowStyle"_ustr ); + +XMLPropStyleContext::XMLPropStyleContext( SvXMLImport& rImport, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily, + bool bDefault ) +: SvXMLStyleContext( rImport, nFamily, bDefault ) +, mxStyles( &rStyles ) +{ +} + +XMLPropStyleContext::~XMLPropStyleContext() +{ +} + +const OldFillStyleDefinitionSet& XMLPropStyleContext::getStandardSet() +{ + return theStandardSet(); +} + +const OldFillStyleDefinitionSet& XMLPropStyleContext::getHeaderSet() +{ + return theHeaderSet(); +} + +const OldFillStyleDefinitionSet& XMLPropStyleContext::getFooterSet() +{ + return theFooterSet(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLPropStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + sal_uInt32 nFamily = 0; + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + else if( nLocalName == XML_DRAWING_PAGE_PROPERTIES ) + nFamily = XML_TYPE_PROP_DRAWING_PAGE; + else if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_RUBY_PROPERTIES ) + nFamily = XML_TYPE_PROP_RUBY; + else if( nLocalName == XML_SECTION_PROPERTIES ) + nFamily = XML_TYPE_PROP_SECTION; + else if( nLocalName == XML_TABLE_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE; + else if( nLocalName == XML_TABLE_COLUMN_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE_COLUMN; + else if( nLocalName ==XML_TABLE_ROW_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE_ROW; + else if( nLocalName == XML_TABLE_CELL_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE_CELL; + else if( nLocalName == XML_CHART_PROPERTIES ) + nFamily = XML_TYPE_PROP_CHART; + } + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + mxStyles->GetImportPropertyMapper( GetFamily() ); + if (xImpPrMap.is()) + { + return new StylePropertiesContext(GetImport(), nElement, xAttrList, nFamily, maProperties, xImpPrMap); + } + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLPropStyleContext::FillPropertySet( + const Reference< XPropertySet > & rPropSet ) +{ + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + mxStyles->GetImportPropertyMapper( GetFamily() ); + SAL_WARN_IF( !xImpPrMap.is(), "xmloff", "There is the import prop mapper" ); + if( xImpPrMap.is() ) + xImpPrMap->FillPropertySet( maProperties, rPropSet ); +} + +void XMLPropStyleContext::SetDefaults() +{ +} + +Reference < XStyle > XMLPropStyleContext::Create() +{ + Reference < XStyle > xNewStyle; + + OUString sServiceName = mxStyles->GetServiceName( GetFamily() ); + if( !sServiceName.isEmpty() ) + { + Reference< XMultiServiceFactory > xFactory( GetImport().GetModel(), + UNO_QUERY ); + if( xFactory.is() ) + { + Reference < XInterface > xIfc = + xFactory->createInstance( sServiceName ); + if( xIfc.is() ) + xNewStyle.set( xIfc, UNO_QUERY ); + } + } + + return xNewStyle; +} + +void XMLPropStyleContext::CreateAndInsert( bool bOverwrite ) +{ + SvXMLStylesContext* pSvXMLStylesContext = mxStyles.get(); + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = pSvXMLStylesContext->GetImportPropertyMapper(GetFamily()); + OSL_ENSURE(xImpPrMap.is(), "There is no import prop mapper"); + + // need to filter out old fill definitions when the new ones are used. The new + // ones are used when a FillStyle is defined + const bool bTakeCareOfDrawingLayerFillStyle(xImpPrMap.is() && GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH); + bool bDrawingLayerFillStylesUsed(false); + + if(bTakeCareOfDrawingLayerFillStyle) + { + // check if new FillStyles are used and if so mark old ones with -1 + static OUString s_FillStyle("FillStyle"); + + if(doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle)) + { + deactivateOldFillStyleDefinitions(theParaSet()); + bDrawingLayerFillStylesUsed = true; + } + } + + if( pSvXMLStylesContext->IsAutomaticStyle() + && ( GetFamily() == XmlStyleFamily::TEXT_TEXT || GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH ) ) + { + // Need to translate StyleName from temp MapNames to names + // used in already imported items (already exist in the pool). This + // is required for AutomaticStyles since these do *not* use FillPropertySet + // and thus just trigger CheckSpecialContext in XMLTextStyleContext::FillPropertySet + // (which may be double action anyways). The mechanism there to use _ContextID_Index_Pair + // is not working for AutomaticStyles and is already too late, too (this + // method is already called before XMLTextStyleContext::FillPropertySet gets called) + if(bDrawingLayerFillStylesUsed) + { + translateNameBasedDrawingLayerFillStyleDefinitionsToStyleDisplayNames(); + } + + Reference < XAutoStyleFamily > xAutoFamily = pSvXMLStylesContext->GetAutoStyles( GetFamily() ); + if( !xAutoFamily.is() ) + return; + if( xImpPrMap.is() ) + { + Sequence< PropertyValue > aValues; + xImpPrMap->FillPropertySequence( maProperties, aValues ); + + sal_Int32 nLen = aValues.getLength(); + if( nLen ) + { + if( GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH ) + { + aValues.realloc( nLen + 2 ); + PropertyValue *pProps = aValues.getArray() + nLen; + pProps->Name = "ParaStyleName"; + OUString sParent( GetParentName() ); + if( !sParent.isEmpty() ) + { + sParent = GetImport().GetStyleDisplayName( GetFamily(), sParent ); + Reference < XNameContainer > xFamilies = pSvXMLStylesContext->GetStylesContainer( GetFamily() ); + if(xFamilies.is() && xFamilies->hasByName( sParent ) ) + { + css::uno::Reference< css::style::XStyle > xStyle; + Any aAny = xFamilies->getByName( sParent ); + aAny >>= xStyle; + sParent = xStyle->getName() ; + } + } + else + sParent = "Standard"; + pProps->Value <<= sParent; + ++pProps; + pProps->Name = "ParaConditionalStyleName"; + pProps->Value <<= sParent; + } + + Reference < XAutoStyle > xAutoStyle = xAutoFamily->insertStyle( aValues ); + if( xAutoStyle.is() ) + { + Sequence< OUString > aPropNames + { + (GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH)? + OUString("ParaAutoStyleName"): + OUString("CharAutoStyleName") + }; + Sequence< Any > aAny = xAutoStyle->getPropertyValues( aPropNames ); + if( aAny.hasElements() ) + { + SetAutoName(aAny[0]); + } + } + } + } + } + else + { + const OUString& rName = GetDisplayName(); + if( rName.isEmpty() || IsDefaultStyle() ) + return; + + Reference < XNameContainer > xFamilies = pSvXMLStylesContext->GetStylesContainer( GetFamily() ); + if( !xFamilies.is() ) + { + SAL_WARN("xmloff", "no styles container for family " << static_cast<int>(GetFamily())); + return; + } + + bool bNew = false; + if( xFamilies->hasByName( rName ) ) + { + Any aAny = xFamilies->getByName( rName ); + aAny >>= mxStyle; + } + else + { + mxStyle = Create(); + if( !mxStyle.is() ) + return; + + xFamilies->insertByName( rName, Any(mxStyle) ); + bNew = true; + } + + Reference < XPropertySet > xPropSet( mxStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( !bNew && xPropSetInfo->hasPropertyByName( gsIsPhysical ) ) + { + Any aAny = xPropSet->getPropertyValue( gsIsPhysical ); + bNew = !*o3tl::doAccess<bool>(aAny); + } + SetNew( bNew ); + if( rName != GetName() ) + GetImport().AddStyleDisplayName( GetFamily(), GetName(), rName ); + + + if( bOverwrite || bNew ) + { + rtl::Reference < XMLPropertySetMapper > xPrMap; + if( xImpPrMap.is() ) + xPrMap = xImpPrMap->getPropertySetMapper(); + if( xPrMap.is() ) + { + Reference < XMultiPropertyStates > xMultiStates( xPropSet, + UNO_QUERY ); + if( xMultiStates.is() ) + { + xMultiStates->setAllPropertiesToDefault(); + } + else + { + std::set < OUString > aNameSet; + sal_Int32 nCount = xPrMap->GetEntryCount(); + sal_Int32 i; + for( i = 0; i < nCount; i++ ) + { + const OUString& rPrName = xPrMap->GetEntryAPIName( i ); + if( xPropSetInfo->hasPropertyByName( rPrName ) ) + aNameSet.insert( rPrName ); + } + Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if (xPropState.is()) + { + nCount = aNameSet.size(); + Sequence<OUString> aNames( comphelper::containerToSequence(aNameSet) ); + Sequence < PropertyState > aStates( xPropState->getPropertyStates(aNames) ); + const PropertyState *pStates = aStates.getConstArray(); + OUString* pNames = aNames.getArray(); + + for( i = 0; i < nCount; i++ ) + { + if( PropertyState_DIRECT_VALUE == *pStates++ ) + xPropState->setPropertyToDefault( pNames[i] ); + } + } + } + } + + if (mxStyle.is()) + mxStyle->setParentStyle(OUString()); + + FillPropertySet( xPropSet ); + } + else + { + SetValid( false ); + } + } +} + +void XMLPropStyleContext::Finish( bool bOverwrite ) +{ + if( !mxStyle.is() || !(IsNew() || bOverwrite) ) + return; + + // The families container must exist + Reference < XNameContainer > xFamilies = mxStyles->GetStylesContainer( GetFamily() ); + SAL_WARN_IF( !xFamilies.is(), "xmloff", "Families lost" ); + if( !xFamilies.is() ) + return; + + // connect parent + OUString sParent( GetParentName() ); + if( !sParent.isEmpty() ) + sParent = GetImport().GetStyleDisplayName( GetFamily(), sParent ); + if( !sParent.isEmpty() && !xFamilies->hasByName( sParent ) ) + sParent.clear(); + + if( sParent != mxStyle->getParentStyle() ) + { + // this may except if setting the parent style forms a + // circle in the style dependencies; especially if the parent + // style is the same as the current style + try + { + mxStyle->setParentStyle( sParent ); + } + catch(const uno::Exception& e) + { + // according to the API definition, I would expect a + // container::NoSuchElementException. But it throws an + // uno::RuntimeException instead. I catch + // uno::Exception in order to process both of them. + + // We can't set the parent style. For a proper + // Error-Message, we should pass in the name of the + // style, as well as the desired parent style. + + // getName() throws no non-Runtime exception: + GetImport().SetError( + XMLERROR_FLAG_ERROR | XMLERROR_PARENT_STYLE_NOT_ALLOWED, + { mxStyle->getName(), sParent }, e.Message, nullptr ); + } + } + + // connect follow + OUString sFollow( GetFollow() ); + if( !sFollow.isEmpty() ) + sFollow = GetImport().GetStyleDisplayName( GetFamily(), sFollow ); + if( sFollow.isEmpty() || !xFamilies->hasByName( sFollow ) ) + sFollow = mxStyle->getName(); + + Reference < XPropertySet > xPropSet( mxStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) ) + { + Any aAny = xPropSet->getPropertyValue( gsFollowStyle ); + OUString sCurrFollow; + aAny >>= sCurrFollow; + if( sCurrFollow != sFollow ) + { + xPropSet->setPropertyValue( gsFollowStyle, Any(sFollow) ); + } + } + + // Connect linked style. + OUString aLinked(GetLinked()); + if (!aLinked.isEmpty()) + { + if (GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH) + { + aLinked = GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_TEXT, aLinked); + } + else if (GetFamily() == XmlStyleFamily::TEXT_TEXT) + { + aLinked = GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_PARAGRAPH, aLinked); + } + } + if (!aLinked.isEmpty() && xPropSetInfo->hasPropertyByName("LinkStyle")) + { + uno::Any aAny = xPropSet->getPropertyValue("LinkStyle"); + OUString aCurrentLinked; + aAny >>= aCurrentLinked; + if (aCurrentLinked != aLinked) + { + xPropSet->setPropertyValue("LinkStyle", uno::Any(aLinked)); + } + } + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + xPropSet->setPropertyValue( "Hidden", uno::Any( IsHidden( ) ) ); + } + +} + +bool XMLPropStyleContext::doNewDrawingLayerFillStyleDefinitionsExist( + std::u16string_view rFillStyleTag) const +{ + if(!maProperties.empty() && !rFillStyleTag.empty()) + { + // no & to avoid non-obvious UAF due to the 2nd temp Reference + const rtl::Reference<XMLPropertySetMapper> rMapper = GetStyles()->GetImportPropertyMapper(GetFamily())->getPropertySetMapper(); + + if(rMapper.is()) + { + for(const auto& a : maProperties) + { + if(a.mnIndex != -1) + { + const OUString& rPropName = rMapper->GetEntryAPIName(a.mnIndex); + + if(rPropName == rFillStyleTag) + { + FillStyle eFillStyle(FillStyle_NONE); + + if(a.maValue >>= eFillStyle) + { + // okay, type was good, FillStyle is set + } + else + { + // also try an int (see XFillStyleItem::PutValue) + sal_Int32 nFillStyle(0); + + if(a.maValue >>= nFillStyle) + { + eFillStyle = static_cast< FillStyle >(nFillStyle); + } + } + + // we found the entry, check it + return FillStyle_NONE != eFillStyle; + } + } + } + } + } + + return false; +} + +void XMLPropStyleContext::deactivateOldFillStyleDefinitions( + const OldFillStyleDefinitionSet& rHashSetOfTags) +{ + if(rHashSetOfTags.empty() || maProperties.empty()) + return; + + const rtl::Reference< XMLPropertySetMapper >& rMapper = GetStyles()->GetImportPropertyMapper(GetFamily())->getPropertySetMapper(); + + if(!rMapper.is()) + return; + + for(auto& a : maProperties) + { + if(a.mnIndex != -1) + { + const OUString& rPropName = rMapper->GetEntryAPIName(a.mnIndex); + + if(rHashSetOfTags.find(rPropName) != rHashSetOfTags.end()) + { + // mark entry as inactive + a.mnIndex = -1; + } + } + } +} + +void XMLPropStyleContext::translateNameBasedDrawingLayerFillStyleDefinitionsToStyleDisplayNames() +{ + if(maProperties.empty()) + return; + + const rtl::Reference< XMLPropertySetMapper >& rMapper = GetStyles()->GetImportPropertyMapper(GetFamily())->getPropertySetMapper(); + + if(!rMapper.is()) + return; + + static constexpr OUStringLiteral s_FillGradientName(u"FillGradientName"); + static constexpr OUStringLiteral s_FillHatchName(u"FillHatchName"); + static constexpr OUStringLiteral s_FillBitmapName(u"FillBitmapName"); + static constexpr OUStringLiteral s_FillTransparenceGradientName(u"FillTransparenceGradientName"); + + for(auto& a : maProperties) + { + if(a.mnIndex != -1) + { + const OUString& rPropName = rMapper->GetEntryAPIName(a.mnIndex); + XmlStyleFamily aStyleFamily(XmlStyleFamily::DATA_STYLE); + + if(rPropName == s_FillGradientName || rPropName == s_FillTransparenceGradientName) + { + aStyleFamily = XmlStyleFamily::SD_GRADIENT_ID; + } + else if(rPropName == s_FillHatchName) + { + aStyleFamily = XmlStyleFamily::SD_HATCH_ID; + } + else if(rPropName == s_FillBitmapName) + { + aStyleFamily = XmlStyleFamily::SD_FILL_IMAGE_ID; + } + + if(aStyleFamily != XmlStyleFamily::DATA_STYLE) + { + OUString sStyleName; + + a.maValue >>= sStyleName; + sStyleName = GetImport().GetStyleDisplayName( aStyleFamily, sStyleName ); + a.maValue <<= sStyleName; + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/shadwhdl.cxx b/xmloff/source/style/shadwhdl.cxx new file mode 100644 index 0000000000..b80db3a8d0 --- /dev/null +++ b/xmloff/source/style/shadwhdl.cxx @@ -0,0 +1,167 @@ +/* -*- 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 "shadwhdl.hxx" +#include <com/sun/star/uno/Any.hxx> +#include <rtl/ustrbuf.hxx> + + +#include <com/sun/star/table/ShadowFormat.hpp> +#include <o3tl/safeint.hxx> +#include <tools/color.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + + + +XMLShadowPropHdl::~XMLShadowPropHdl() +{ + // nothing to do +} + +bool XMLShadowPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + table::ShadowFormat aShadow; + aShadow.Location = table::ShadowLocation_BOTTOM_RIGHT; + + bool bColorFound = false; + bool bOffsetFound = false; + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + Color aColor( 128,128, 128 ); + std::u16string_view aToken; + + while( aTokenEnum.getNextToken( aToken ) ) + { + if( IsXMLToken( aToken, XML_NONE ) ) + { + aShadow.Location = table::ShadowLocation_NONE; + bRet = true; + break; + } + else if( !bColorFound && aToken.substr(0,1) == u"#" ) + { + bRet = ::sax::Converter::convertColor( aColor, aToken ); + if( !bRet ) + return false; + bColorFound = true; + } + else if( !bOffsetFound ) + { + sal_Int32 nX = 0, nY = 0; + + bRet = rUnitConverter.convertMeasureToCore( nX, aToken ); + if( bRet && aTokenEnum.getNextToken( aToken ) ) + bRet = rUnitConverter.convertMeasureToCore( nY, aToken ); + + if( bRet ) + { + if( nX < 0 ) + { + if( nY < 0 ) + aShadow.Location = table::ShadowLocation_TOP_LEFT; + else + aShadow.Location = table::ShadowLocation_BOTTOM_LEFT; + } + else + { + if( nY < 0 ) + aShadow.Location = table::ShadowLocation_TOP_RIGHT; + else + aShadow.Location = table::ShadowLocation_BOTTOM_RIGHT; + } + + if (nX < 0) + nX = o3tl::saturating_toggle_sign(nX); + if (nY < 0) + nY = o3tl::saturating_toggle_sign(nY); + + sal_Int32 nWidth; + bRet = !o3tl::checked_add(nX, nY, nWidth); + if (bRet) + aShadow.ShadowWidth = sal::static_int_cast<sal_Int16>(nWidth >> 1); + } + } + } + + if( bRet && ( bColorFound || bOffsetFound ) ) + { + aShadow.IsTransparent = aColor.IsTransparent(); + aShadow.Color = sal_Int32(aColor); + bRet = true; + } + + rValue <<= aShadow; + + return bRet; +} + +bool XMLShadowPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + table::ShadowFormat aShadow; + + if( rValue >>= aShadow ) + { + sal_Int32 nX = 1, nY = 1; + + switch( aShadow.Location ) + { + case table::ShadowLocation_TOP_LEFT: + nX = -1; + nY = -1; + break; + case table::ShadowLocation_TOP_RIGHT: + nY = -1; + break; + case table::ShadowLocation_BOTTOM_LEFT: + nX = -1; + break; + case table::ShadowLocation_BOTTOM_RIGHT: + break; + case table::ShadowLocation_NONE: + default: + rStrExpValue = GetXMLToken(XML_NONE); + return true; + } + + nX *= aShadow.ShadowWidth; + nY *= aShadow.ShadowWidth; + + OUStringBuffer aOut; + ::sax::Converter::convertColor( aOut, aShadow.Color ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, nX ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, nY ); + + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/shadwhdl.hxx b/xmloff/source/style/shadwhdl.hxx new file mode 100644 index 0000000000..8b0a7762f1 --- /dev/null +++ b/xmloff/source/style/shadwhdl.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLShadowPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLShadowPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/shdwdhdl.cxx b/xmloff/source/style/shdwdhdl.cxx new file mode 100644 index 0000000000..41b1b4574c --- /dev/null +++ b/xmloff/source/style/shdwdhdl.cxx @@ -0,0 +1,67 @@ +/* -*- 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 "shdwdhdl.hxx" +#include <com/sun/star/uno/Any.hxx> + + +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + + + + +XMLShadowedPropHdl::~XMLShadowedPropHdl() +{ + // nothing to do +} + +bool XMLShadowedPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue = ! IsXMLToken( rStrImpValue, XML_NONE ); + rValue <<= bValue; + + return true; +} + +bool XMLShadowedPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + if( bValue ) + { + rStrExpValue = "1pt 1pt"; + } + else + { + rStrExpValue = GetXMLToken( XML_NONE ); + } + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/shdwdhdl.hxx b/xmloff/source/style/shdwdhdl.hxx new file mode 100644 index 0000000000..e7397f80c7 --- /dev/null +++ b/xmloff/source/style/shdwdhdl.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLShadowedPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLShadowedPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/styleexp.cxx b/xmloff/source/style/styleexp.cxx new file mode 100644 index 0000000000..15e2d714d3 --- /dev/null +++ b/xmloff/source/style/styleexp.cxx @@ -0,0 +1,581 @@ +/* -*- 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 <sal/config.h> + +#include <o3tl/any.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlexppr.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/text/XChapterNumberingSupplier.hpp> +#include <xmloff/xmlaustp.hxx> +#include <xmloff/styleexp.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/XMLEventExport.hxx> +#include <xmloff/maptype.hxx> +#include <memory> +#include <set> +#include <prstylecond.hxx> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::document::XEventsSupplier; + +constexpr OUString gsIsPhysical( u"IsPhysical"_ustr ); +constexpr OUString gsIsAutoUpdate( u"IsAutoUpdate"_ustr ); +constexpr OUString gsFollowStyle( u"FollowStyle"_ustr ); +constexpr OUString gsNumberingStyleName( u"NumberingStyleName"_ustr ); +constexpr OUString gsOutlineLevel( u"OutlineLevel"_ustr ); + +XMLStyleExport::XMLStyleExport( + SvXMLExport& rExp, + SvXMLAutoStylePoolP *pAutoStyleP ) : + m_rExport( rExp ), + m_pAutoStylePool( pAutoStyleP ) +{ +} + +XMLStyleExport::~XMLStyleExport() +{ +} + +void XMLStyleExport::exportStyleAttributes( const Reference< XStyle >& ) +{ +} + +void XMLStyleExport::exportStyleContent( const Reference< XStyle >& rStyle ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + assert(xPropSet.is()); + + try + { + uno::Any aProperty = xPropSet->getPropertyValue( "ParaStyleConditions" ); + uno::Sequence< beans::NamedValue > aSeq; + + aProperty >>= aSeq; + + for (beans::NamedValue const& rNamedCond : std::as_const(aSeq)) + { + OUString aStyleName; + + if (rNamedCond.Value >>= aStyleName) + { + if (!aStyleName.isEmpty()) + { + OUString aExternal = GetParaStyleCondExternal(rNamedCond.Name); + + if (!aExternal.isEmpty()) + { + bool bEncoded; + + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_CONDITION, + aExternal); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_APPLY_STYLE_NAME, + GetExport().EncodeStyleName( aStyleName, + &bEncoded ) ); + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_STYLE, + XML_MAP, + true, + true ); + } + } + } + } + } + catch( const beans::UnknownPropertyException& ) + { + } +} + +namespace +{ +/// Writes <style:style style:list-level="..."> for Writer paragraph styles. +void ExportStyleListlevel(const uno::Reference<beans::XPropertySetInfo>& xPropSetInfo, + const uno::Reference<beans::XPropertyState>& xPropState, + const uno::Reference<beans::XPropertySet>& xPropSet, SvXMLExport& rExport) +{ + if (!xPropSetInfo->hasPropertyByName("NumberingLevel")) + { + SAL_WARN("xmloff", "ExportStyleListlevel: no NumberingLevel for a Writer paragraph style"); + return; + } + + if (xPropState->getPropertyState("NumberingLevel") != beans::PropertyState_DIRECT_VALUE) + { + return; + } + + sal_Int16 nNumberingLevel{}; + if (!(xPropSet->getPropertyValue("NumberingLevel") >>= nNumberingLevel)) + { + return; + } + + // The spec is positiveInteger (1-based), but the implementation is 0-based. + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_LIST_LEVEL, OUString::number(++nNumberingLevel)); +} +} + +bool XMLStyleExport::exportStyle( + const Reference< XStyle >& rStyle, + const OUString& rXMLFamily, + const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper, + const Reference< XNameAccess >& xStyles, + const OUString* pPrefix ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + if (!xPropSet) + return false; + + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + Any aAny; + + // Don't export styles that aren't existing really. This may be the + // case for StarOffice Writer's pool styles. + if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) ) + { + aAny = xPropSet->getPropertyValue( gsIsPhysical ); + if( !*o3tl::doAccess<bool>(aAny) ) + return false; + } + + // <style:style ...> + GetExport().CheckAttrList(); + + // style:name="..." + OUString sName; + + if(pPrefix) + sName = *pPrefix; + sName += rStyle->getName(); + + bool bEncoded = false; + const OUString sEncodedStyleName(GetExport().EncodeStyleName( sName, &bEncoded )); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, sEncodedStyleName ); + + if( bEncoded ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, + sName); + + // style:family="..." + if( !rXMLFamily.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, rXMLFamily); + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + aAny = xPropSet->getPropertyValue( "Hidden" ); + bool bHidden = false; + if ((aAny >>= bHidden) && bHidden + && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDDEN, "true"); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility + } + } + + // style:parent-style-name="..." + OUString sParentString(rStyle->getParentStyle()); + OUString sParent; + + if(!sParentString.isEmpty()) + { + if(pPrefix) + sParent = *pPrefix; + sParent += sParentString; + } + + if( !sParent.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_PARENT_STYLE_NAME, + GetExport().EncodeStyleName( sParent ) ); + + // style:next-style-name="..." (paragraph styles only) + if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) ) + { + aAny = xPropSet->getPropertyValue( gsFollowStyle ); + OUString sNextName; + aAny >>= sNextName; + if( sName != sNextName ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NEXT_STYLE_NAME, + GetExport().EncodeStyleName( sNextName ) ); + } + } + + // style:linked-style-name="..." (SW paragraph and character styles only) + if (xPropSetInfo->hasPropertyByName("LinkStyle")) + { + aAny = xPropSet->getPropertyValue("LinkStyle"); + OUString sLinkName; + aAny >>= sLinkName; + if (!sLinkName.isEmpty() + && (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_LINKED_STYLE_NAME, + GetExport().EncodeStyleName(sLinkName)); + } + } + + // style:auto-update="..." (SW only) + if( xPropSetInfo->hasPropertyByName( gsIsAutoUpdate ) ) + { + aAny = xPropSet->getPropertyValue( gsIsAutoUpdate ); + if( *o3tl::doAccess<bool>(aAny) ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_AUTO_UPDATE, + XML_TRUE ); + } + + // style:default-outline-level"..." + sal_Int32 nOutlineLevel = 0; + if( xPropSetInfo->hasPropertyByName( gsOutlineLevel ) ) + { + Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if( PropertyState_DIRECT_VALUE == xPropState->getPropertyState( gsOutlineLevel ) ) + { + aAny = xPropSet->getPropertyValue( gsOutlineLevel ); + aAny >>= nOutlineLevel; + if( nOutlineLevel > 0 ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DEFAULT_OUTLINE_LEVEL, + OUString::number(nOutlineLevel) ); + } + else + { + /* Empty value for style:default-outline-level does exist + since ODF 1.2. Thus, suppress its export for former versions. (#i104889#) + */ + if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DEFAULT_OUTLINE_LEVEL, + OUString( "" )); + } + } + } + } + + // style:list-style-name="..." (SW paragraph styles only) + if( xPropSetInfo->hasPropertyByName( gsNumberingStyleName ) ) + { + Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if( PropertyState_DIRECT_VALUE == + xPropState->getPropertyState( gsNumberingStyleName ) ) + { + aAny = xPropSet->getPropertyValue( gsNumberingStyleName ); + if( aAny.hasValue() ) + { + OUString sListName; + aAny >>= sListName; + + /* A direct set empty list style has to be written. Otherwise, + this information is lost and causes an error, if the parent + style has a list style set. (#i69523#) + */ + if ( sListName.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_LIST_STYLE_NAME, + sListName /* empty string */); + } + else + { + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + bool bSuppressListStyle( false ); + { + if ( !GetExport().writeOutlineStyleAsNormalListStyle() ) + { + Reference< XChapterNumberingSupplier > xCNSupplier + (GetExport().GetModel(), UNO_QUERY); + + if (xCNSupplier.is()) + { + Reference< XIndexReplace > xNumRule + ( xCNSupplier->getChapterNumberingRules() ); + assert(xNumRule.is()); + + Reference< XPropertySet > xNumRulePropSet + (xNumRule, UNO_QUERY); + OUString sOutlineName; + xNumRulePropSet->getPropertyValue("Name") + >>= sOutlineName; + bSuppressListStyle = sListName == sOutlineName; + } + } + } + + if ( !sListName.isEmpty() && !bSuppressListStyle ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_LIST_STYLE_NAME, + GetExport().EncodeStyleName( sListName ) ); + + ExportStyleListlevel(xPropSetInfo, xPropState, xPropSet, GetExport()); + } + } + } + } + else if( nOutlineLevel > 0 ) + { + + bool bNoInheritedListStyle( true ); + + Reference<XStyle> xStyle( xPropState, UNO_QUERY ); + while ( xStyle.is() ) + { + OUString aParentStyle( xStyle->getParentStyle() ); + if ( aParentStyle.isEmpty() || !xStyles->hasByName( aParentStyle ) ) + { + break; + } + else + { + xPropState.set( xStyles->getByName( aParentStyle ), UNO_QUERY ); + if ( !xPropState.is() ) + { + break; + } + if ( xPropState->getPropertyState( gsNumberingStyleName ) == PropertyState_DIRECT_VALUE ) + { + bNoInheritedListStyle = false; + break; + } + else + { + xStyle.set( xPropState, UNO_QUERY ); + } + } + } + if ( bNoInheritedListStyle ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_LIST_STYLE_NAME, + OUString( "" )); + } + } + + // style:pool-id="..." is not required any longer since we use + // english style names only + exportStyleAttributes( rStyle ); + + // TODO: style:help-file-name="..." and style:help-id="..." can neither + // be modified by UI nor by API and that for, have not to be exported + // currently. + + { + // <style:style> + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, XML_STYLE, + true, true ); + + rPropMapper->SetStyleName( sName ); + + // <style:properties> + ::std::vector< XMLPropertyState > aPropStates = + rPropMapper->Filter(GetExport(), xPropSet, true); + bool const bUseExtensionNamespaceForGraphicProperties( + rXMLFamily != "drawing-page" && + rXMLFamily != "graphic" && + rXMLFamily != "presentation" && + rXMLFamily != "chart"); + rPropMapper->exportXML( GetExport(), aPropStates, + SvXmlExportFlags::IGN_WS, + bUseExtensionNamespaceForGraphicProperties ); + + rPropMapper->SetStyleName( OUString() ); + + exportStyleContent( rStyle ); + + // <script:events>, if they are supported by this style + Reference<XEventsSupplier> xEventsSupp(rStyle, UNO_QUERY); + GetExport().GetEventExport().Export(xEventsSupp); + } + return true; +} + +void XMLStyleExport::exportDefaultStyle( + const Reference< XPropertySet >& xPropSet, + const OUString& rXMLFamily, + const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper ) +{ + // <style:default-style ...> + GetExport().CheckAttrList(); + + { + // style:family="..." + if( !rXMLFamily.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, + rXMLFamily ); + // <style:style> + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_DEFAULT_STYLE, + true, true ); + // <style:properties> + ::std::vector< XMLPropertyState > aPropStates = + rPropMapper->FilterDefaults(GetExport(), xPropSet); + rPropMapper->exportXML( GetExport(), aPropStates, + SvXmlExportFlags::IGN_WS ); + } +} + +void XMLStyleExport::exportStyleFamily( + const OUString& rFamily, const OUString& rXMLFamily, + const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper, + bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix) +{ + assert(GetExport().GetModel().is()); + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), UNO_QUERY ); + if( !xFamiliesSupp.is() ) + return; // family not available in current model + + Reference< XNameAccess > xStyleCont; + + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + if( xFamilies->hasByName( rFamily ) ) + xFamilies->getByName( rFamily ) >>= xStyleCont; + + if( !xStyleCont.is() ) + return; + + // If next styles are supported and used styles should be exported only, + // the next style may be unused but has to be exported, too. In this case + // the names of all exported styles are remembered. + std::optional<std::set<OUString> > xExportedStyles; + bool bFirstStyle = true; + + const uno::Sequence< OUString> aSeq = xStyleCont->getElementNames(); + for(const auto& rName : aSeq) + { + Reference< XStyle > xStyle; + try + { + xStyleCont->getByName( rName ) >>= xStyle; + } + catch(const lang::IndexOutOfBoundsException&) + { + // due to bugs in prior versions it is possible that + // a binary file is missing some critical styles. + // The only possible way to deal with this is to + // not export them here and remain silent. + continue; + } + catch(css::container::NoSuchElementException&) + { + continue; + } + + assert(xStyle.is()); + if (!bUsed || xStyle->isInUse()) + { + bool bExported = exportStyle( xStyle, rXMLFamily, rPropMapper, + xStyleCont,pPrefix ); + if (bUsed && bFirstStyle && bExported) + { + // If this is the first style, find out whether next styles + // are supported. + Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + + if (xPropSetInfo->hasPropertyByName( gsFollowStyle )) + xExportedStyles.emplace(); + bFirstStyle = false; + } + + if (xExportedStyles && bExported) + { + // If next styles are supported, remember this style's name. + xExportedStyles->insert( xStyle->getName() ); + } + } + + // if an auto style pool is given, remember this style's name as a + // style name that must not be used by automatic styles. + if (m_pAutoStylePool) + m_pAutoStylePool->RegisterName( nFamily, xStyle->getName() ); + } + + if( !xExportedStyles ) + return; + + // if next styles are supported, export all next styles that are + // unused and that for, haven't been exported in the first loop. + for(const auto& rName : aSeq) + { + Reference< XStyle > xStyle; + xStyleCont->getByName( rName ) >>= xStyle; + + assert(xStyle.is()); + + Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + // styles that aren't existing really are ignored. + if (xPropSetInfo->hasPropertyByName( gsIsPhysical )) + { + Any aAny( xPropSet->getPropertyValue( gsIsPhysical ) ); + if (!*o3tl::doAccess<bool>(aAny)) + continue; + } + + if (!xStyle->isInUse()) + continue; + + if (!xPropSetInfo->hasPropertyByName( gsFollowStyle )) + { + continue; + } + + OUString sNextName; + xPropSet->getPropertyValue( gsFollowStyle ) >>= sNextName; + OUString sTmp( sNextName ); + // if the next style hasn't been exported by now, export it now + // and remember its name. + if (xStyle->getName() != sNextName && + 0 == xExportedStyles->count( sTmp )) + { + xStyleCont->getByName( sNextName ) >>= xStyle; + assert(xStyle.is()); + + if (exportStyle(xStyle, rXMLFamily, rPropMapper, xStyleCont, pPrefix)) + xExportedStyles->insert( sTmp ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/tabsthdl.cxx b/xmloff/source/style/tabsthdl.cxx new file mode 100644 index 0000000000..2e497f3eab --- /dev/null +++ b/xmloff/source/style/tabsthdl.cxx @@ -0,0 +1,65 @@ +/* -*- 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 "tabsthdl.hxx" +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/style/TabStop.hpp> + +using namespace ::com::sun::star; + + + + +XMLTabStopPropHdl::~XMLTabStopPropHdl() +{ + // Nothing to do +} + +bool XMLTabStopPropHdl::equals( const uno::Any& r1, const uno::Any& r2 ) const +{ + uno::Sequence< style::TabStop> aSeq1; + if( r1 >>= aSeq1 ) + { + uno::Sequence< style::TabStop> aSeq2; + if( r2 >>= aSeq2 ) + { + return std::equal(std::cbegin(aSeq1), std::cend(aSeq1), std::cbegin(aSeq2), std::cend(aSeq2), + [](const style::TabStop& a, const style::TabStop& b) { + return a.Position == b.Position + && a.Alignment == b.Alignment + && a.DecimalChar == b.DecimalChar + && a.FillChar == b.FillChar; + }); + } + } + + return false; +} + +bool XMLTabStopPropHdl::importXML( const OUString&, css::uno::Any&, const SvXMLUnitConverter& ) const +{ + return false; +} + +bool XMLTabStopPropHdl::exportXML( OUString&, const css::uno::Any&, const SvXMLUnitConverter& ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/tabsthdl.hxx b/xmloff/source/style/tabsthdl.hxx new file mode 100644 index 0000000000..755790e8f3 --- /dev/null +++ b/xmloff/source/style/tabsthdl.hxx @@ -0,0 +1,39 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLTabStopPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLTabStopPropHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + /// TabStops will be imported/exported as XML-Elements. So the Import/Export-work must be done at another place. + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/undlihdl.cxx b/xmloff/source/style/undlihdl.cxx new file mode 100644 index 0000000000..4d6482c4f4 --- /dev/null +++ b/xmloff/source/style/undlihdl.cxx @@ -0,0 +1,365 @@ +/* -*- 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 "undlihdl.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlement.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/awt/FontUnderline.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::awt; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_UnderlineType_Enum[] = +{ + { XML_NONE, awt::FontUnderline::NONE }, + { XML_SINGLE, awt::FontUnderline::SINGLE }, + { XML_DOUBLE, awt::FontUnderline::DOUBLE }, + { XML_SINGLE, awt::FontUnderline::DOTTED }, + { XML_SINGLE, awt::FontUnderline::DASH }, + { XML_SINGLE, awt::FontUnderline::LONGDASH }, + { XML_SINGLE, awt::FontUnderline::DASHDOT }, + { XML_SINGLE, awt::FontUnderline::DASHDOTDOT }, + { XML_SINGLE, awt::FontUnderline::WAVE }, + { XML_SINGLE, awt::FontUnderline::BOLD }, + { XML_SINGLE, awt::FontUnderline::BOLDDOTTED }, + { XML_SINGLE, awt::FontUnderline::BOLDDASH }, + { XML_SINGLE, awt::FontUnderline::BOLDLONGDASH }, + { XML_SINGLE, awt::FontUnderline::BOLDDASHDOT }, + { XML_SINGLE, awt::FontUnderline::BOLDDASHDOTDOT }, + { XML_SINGLE, awt::FontUnderline::BOLDWAVE }, + { XML_DOUBLE, awt::FontUnderline::DOUBLEWAVE }, + { XML_SINGLE, awt::FontUnderline::SMALLWAVE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_UnderlineStyle_Enum[] = +{ + { XML_NONE, awt::FontUnderline::NONE }, + { XML_SOLID, awt::FontUnderline::SINGLE }, + { XML_SOLID, awt::FontUnderline::DOUBLE }, + { XML_DOTTED, awt::FontUnderline::DOTTED }, + { XML_DASH, awt::FontUnderline::DASH }, + { XML_LONG_DASH, awt::FontUnderline::LONGDASH }, + { XML_DOT_DASH, awt::FontUnderline::DASHDOT }, + { XML_DOT_DOT_DASH, awt::FontUnderline::DASHDOTDOT }, + { XML_WAVE, awt::FontUnderline::WAVE }, + { XML_SOLID, awt::FontUnderline::BOLD }, + { XML_DOTTED, awt::FontUnderline::BOLDDOTTED }, + { XML_DASH, awt::FontUnderline::BOLDDASH }, + { XML_LONG_DASH, awt::FontUnderline::BOLDLONGDASH }, + { XML_DOT_DASH, awt::FontUnderline::BOLDDASHDOT }, + { XML_DOT_DOT_DASH, awt::FontUnderline::BOLDDASHDOTDOT }, + { XML_WAVE, awt::FontUnderline::BOLDWAVE }, + { XML_WAVE, awt::FontUnderline::DOUBLEWAVE }, + { XML_SMALL_WAVE, awt::FontUnderline::SMALLWAVE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry<sal_uInt16> const pXML_UnderlineWidth_Enum[] = +{ + { XML_AUTO, awt::FontUnderline::NONE }, + { XML_AUTO, awt::FontUnderline::SINGLE }, + { XML_AUTO, awt::FontUnderline::DOUBLE }, + { XML_AUTO, awt::FontUnderline::DOTTED }, + { XML_AUTO, awt::FontUnderline::DASH }, + { XML_AUTO, awt::FontUnderline::LONGDASH }, + { XML_AUTO, awt::FontUnderline::DASHDOT }, + { XML_AUTO, awt::FontUnderline::DASHDOTDOT }, + { XML_AUTO, awt::FontUnderline::WAVE }, + { XML_BOLD, awt::FontUnderline::BOLD }, + { XML_BOLD, awt::FontUnderline::BOLDDOTTED }, + { XML_BOLD, awt::FontUnderline::BOLDDASH }, + { XML_BOLD, awt::FontUnderline::BOLDLONGDASH }, + { XML_BOLD, awt::FontUnderline::BOLDDASHDOT }, + { XML_BOLD, awt::FontUnderline::BOLDDASHDOTDOT }, + { XML_BOLD, awt::FontUnderline::BOLDWAVE }, + { XML_AUTO, awt::FontUnderline::DOUBLEWAVE }, + { XML_THIN, awt::FontUnderline::NONE }, + { XML_MEDIUM, awt::FontUnderline::NONE }, + { XML_THICK, awt::FontUnderline::BOLD}, + { XML_TOKEN_INVALID, 0 } +}; + + + + +XMLUnderlineTypePropHdl::~XMLUnderlineTypePropHdl() +{ + // nothing to do +} + +bool XMLUnderlineTypePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewUnderline(0); + bool bRet = SvXMLUnitConverter::convertEnum( + eNewUnderline, rStrImpValue, pXML_UnderlineType_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eUnderline = sal_Int16(); + if( (rValue >>= eUnderline) && awt::FontUnderline::NONE!=eUnderline ) + { + switch( eNewUnderline ) + { + case awt::FontUnderline::NONE: + case awt::FontUnderline::SINGLE: + // keep existing line style + eNewUnderline = eUnderline; + break; + case awt::FontUnderline::DOUBLE: + // A double line style has priority over a bold line style, + // but not over the line style itself. + switch( eUnderline ) + { + case awt::FontUnderline::SINGLE: + case awt::FontUnderline::BOLD: + break; + case awt::FontUnderline::WAVE: + case awt::FontUnderline::BOLDWAVE: + eNewUnderline = awt::FontUnderline::DOUBLEWAVE; + break; + default: + // If a double line style is not supported for the existing + // value, keep the new one + eNewUnderline = eUnderline; + break; + } + break; + default: + OSL_ENSURE( bRet, "unexpected line type value" ); + break; + } + if( eNewUnderline != eUnderline ) + rValue <<= static_cast<sal_Int16>(eNewUnderline); + } + else + { + rValue <<= static_cast<sal_Int16>(eNewUnderline); + } + } + + return bRet; +} + +bool XMLUnderlineTypePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( (rValue >>= nValue) && + (awt::FontUnderline::DOUBLE == nValue || + awt::FontUnderline::DOUBLEWAVE == nValue) ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_UnderlineType_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + + + +XMLUnderlineStylePropHdl::~XMLUnderlineStylePropHdl() +{ + // nothing to do +} + +bool XMLUnderlineStylePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewUnderline(0); + bool bRet = SvXMLUnitConverter::convertEnum( + eNewUnderline, rStrImpValue, pXML_UnderlineStyle_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eUnderline = sal_Int16(); + if( (rValue >>= eUnderline) && awt::FontUnderline::NONE!=eUnderline ) + { + switch( eNewUnderline ) + { + case awt::FontUnderline::NONE: + case awt::FontUnderline::SINGLE: + // keep double or bold line style + eNewUnderline = eUnderline; + break; + case awt::FontUnderline::DOTTED: + // The line style has priority over a double type. + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDDOTTED; + break; + case awt::FontUnderline::DASH: + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDDASH; + break; + case awt::FontUnderline::LONGDASH: + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDLONGDASH; + break; + case awt::FontUnderline::DASHDOT: + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDDASHDOT; + break; + case awt::FontUnderline::DASHDOTDOT: + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDDASHDOTDOT; + break; + case awt::FontUnderline::WAVE: + if( awt::FontUnderline::DOUBLE == eUnderline ) + eNewUnderline = awt::FontUnderline::DOUBLEWAVE; + else if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDWAVE; + break; + case awt::FontUnderline::SMALLWAVE: + // SMALLWAVE is not used + default: + OSL_ENSURE( bRet, "unexpected line style value" ); + break; + } + if( eNewUnderline != eUnderline ) + rValue <<= static_cast<sal_Int16>(eNewUnderline); + } + else + { + rValue <<= static_cast<sal_Int16>(eNewUnderline); + } + } + + return bRet; +} + +bool XMLUnderlineStylePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_UnderlineStyle_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + + + +XMLUnderlineWidthPropHdl::~XMLUnderlineWidthPropHdl() +{ + // nothing to do +} + +bool XMLUnderlineWidthPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewUnderline(0); + bool bRet = SvXMLUnitConverter::convertEnum( + eNewUnderline, rStrImpValue, pXML_UnderlineWidth_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eUnderline = sal_Int16(); + if( (rValue >>= eUnderline) && awt::FontUnderline::NONE!=eUnderline ) + { + switch( eNewUnderline ) + { + case awt::FontUnderline::NONE: + // keep existing line style + eNewUnderline = eUnderline; + break; + case awt::FontUnderline::BOLD: + // A double line style has priority over a bold line style, + // but not over the line style itself. + switch( eUnderline ) + { + case awt::FontUnderline::SINGLE: + break; + case awt::FontUnderline::DOTTED: + eNewUnderline = awt::FontUnderline::BOLDDOTTED; + break; + case awt::FontUnderline::DASH: + eNewUnderline = awt::FontUnderline::BOLDDASH; + break; + case awt::FontUnderline::LONGDASH: + eNewUnderline = awt::FontUnderline::BOLDLONGDASH; + break; + case awt::FontUnderline::DASHDOT: + eNewUnderline = awt::FontUnderline::BOLDDASHDOT; + break; + case awt::FontUnderline::DASHDOTDOT: + eNewUnderline = awt::FontUnderline::BOLDDASHDOTDOT; + break; + case awt::FontUnderline::WAVE: + eNewUnderline = awt::FontUnderline::BOLDWAVE; + break; + default: + // a double line style overwrites a bold one + eNewUnderline = eUnderline; + break; + } + break; + default: + OSL_ENSURE( bRet, "unexpected line width value" ); + break; + } + if( eNewUnderline != eUnderline ) + rValue <<= static_cast<sal_Int16>(eNewUnderline); + } + else + { + rValue <<= static_cast<sal_Int16>(eNewUnderline); + } + } + + return bRet; +} + +bool XMLUnderlineWidthPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( (rValue >>= nValue) && (awt::FontUnderline::NONE != nValue) ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_UnderlineWidth_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/undlihdl.hxx b/xmloff/source/style/undlihdl.hxx new file mode 100644 index 0000000000..4b9ad1b50b --- /dev/null +++ b/xmloff/source/style/undlihdl.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLUnderlineTypePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLUnderlineTypePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLUnderlineStylePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLUnderlineStylePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLUnderlineWidthPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLUnderlineWidthPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/weighhdl.cxx b/xmloff/source/style/weighhdl.cxx new file mode 100644 index 0000000000..a069dbd30f --- /dev/null +++ b/xmloff/source/style/weighhdl.cxx @@ -0,0 +1,154 @@ +/* -*- 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 "weighhdl.hxx" + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmltoken.hxx> + +#include <rtl/ustring.hxx> + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/awt/FontWeight.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +namespace { + +struct FontWeightMapper +{ + float fWeight; + sal_uInt16 nValue; +}; + +} + +FontWeightMapper const aFontWeightMap[] = +{ + { css::awt::FontWeight::DONTKNOW, 0 }, + { css::awt::FontWeight::THIN, 100 }, + { css::awt::FontWeight::ULTRALIGHT, 150 }, + { css::awt::FontWeight::LIGHT, 250 }, + { css::awt::FontWeight::SEMILIGHT, 350 }, + { css::awt::FontWeight::NORMAL, 400 }, + { css::awt::FontWeight::NORMAL, 450 }, + { css::awt::FontWeight::SEMIBOLD, 600 }, + { css::awt::FontWeight::BOLD, 700 }, + { css::awt::FontWeight::ULTRABOLD, 800 }, + { css::awt::FontWeight::BLACK, 900 }, + { css::awt::FontWeight::DONTKNOW, 1000 } +}; + + +XMLFontWeightPropHdl::~XMLFontWeightPropHdl() +{ + // Nothing to do +} + +bool XMLFontWeightPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nWeight = 0; + + if( IsXMLToken( rStrImpValue, XML_NORMAL ) ) + { + nWeight = 400; + bRet = true; + } + else if( IsXMLToken( rStrImpValue, XML_BOLD ) ) + { + nWeight = 700; + bRet = true; + } + else + { + sal_Int32 nTemp; + bRet = ::sax::Converter::convertNumber(nTemp, rStrImpValue, 100, 900); + if( bRet ) + nWeight = sal::static_int_cast< sal_uInt16 >(nTemp); + } + + if( bRet ) + { + bRet = false; + int const nCount = SAL_N_ELEMENTS(aFontWeightMap); + for (int i = 0; i < (nCount-1); ++i) + { + if( (nWeight >= aFontWeightMap[i].nValue) && (nWeight <= aFontWeightMap[i+1].nValue) ) + { + sal_uInt16 nDiff1 = nWeight - aFontWeightMap[i].nValue; + sal_uInt16 nDiff2 = aFontWeightMap[i+1].nValue - nWeight; + + if( nDiff1 < nDiff2 ) + rValue <<= aFontWeightMap[i].fWeight; + else + rValue <<= aFontWeightMap[i+1].fWeight; + + bRet = true; + break; + } + } + } + + return bRet; +} + +bool XMLFontWeightPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + float fValue = float(); + if( !( rValue >>= fValue ) ) + { + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + { + fValue = static_cast<float>(nValue); + bRet = true; + } + } + else + bRet = true; + + if( bRet ) + { + sal_uInt16 nWeight = 0; + for( auto const & pair : aFontWeightMap ) + { + if( fValue <= pair.fWeight ) + { + nWeight = pair.nValue; + break; + } + } + + if( 400 == nWeight ) + rStrExpValue = GetXMLToken(XML_NORMAL); + else if( 700 == nWeight ) + rStrExpValue = GetXMLToken(XML_BOLD); + else + rStrExpValue = OUString::number( nWeight ); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/weighhdl.hxx b/xmloff/source/style/weighhdl.hxx new file mode 100644 index 0000000000..e9df030011 --- /dev/null +++ b/xmloff/source/style/weighhdl.hxx @@ -0,0 +1,37 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontWeightPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontWeightPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlaustp.cxx b/xmloff/source/style/xmlaustp.cxx new file mode 100644 index 0000000000..583c4a7019 --- /dev/null +++ b/xmloff/source/style/xmlaustp.cxx @@ -0,0 +1,382 @@ +/* -*- 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 <com/sun/star/container/XIndexReplace.hpp> +#include "impastpl.hxx" +#include <xmloff/xmlaustp.hxx> +#include <xmloff/families.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlprhdl.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/XMLTextListAutoStylePool.hxx> + +#include <PageMasterStyleMap.hxx> +#include <osl/diagnose.h> + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + +namespace +{ + void lcl_exportDataStyle( SvXMLExport& _rExport, const rtl::Reference< XMLPropertySetMapper >& _rxMapper, + const XMLPropertyState& _rProperty ) + { + assert(_rxMapper.is()); + // obtain the data style name + OUString sDataStyleName; + _rProperty.maValue >>= sDataStyleName; + assert(!sDataStyleName.isEmpty() && "xmloff::lcl_exportDataStyle: invalid property value for the data style name!"); + + // add the attribute + _rExport.AddAttribute( + _rxMapper->GetEntryNameSpace( _rProperty.mnIndex ), + _rxMapper->GetEntryXMLName( _rProperty.mnIndex ), + sDataStyleName ); + } +} + +void SvXMLAutoStylePoolP::exportStyleAttributes( + comphelper::AttributeList&, + XmlStyleFamily nFamily, + const std::vector< XMLPropertyState >& rProperties, + const SvXMLExportPropertyMapper& rPropExp, + const SvXMLUnitConverter&, + const SvXMLNamespaceMap& + ) const +{ + if ( XmlStyleFamily::CONTROL_ID == nFamily ) + { // it's a control-related style + const rtl::Reference< XMLPropertySetMapper >& aPropertyMapper = rPropExp.getPropertySetMapper(); + + for (const auto& rProp : rProperties) + { + if ( ( rProp.mnIndex > -1 ) + && ( CTF_FORMS_DATA_STYLE == aPropertyMapper->GetEntryContextId( rProp.mnIndex ) ) + ) + { // it's the data-style for a grid column + lcl_exportDataStyle( GetExport(), aPropertyMapper, rProp ); + } + } + } + + if( (XmlStyleFamily::SD_GRAPHICS_ID == nFamily) || (XmlStyleFamily::SD_PRESENTATION_ID == nFamily) ) + { // it's a graphics style + const rtl::Reference< XMLPropertySetMapper >& aPropertyMapper = rPropExp.getPropertySetMapper(); + assert(aPropertyMapper.is()); + + bool bFoundControlShapeDataStyle = false; + bool bFoundNumberingRulesName = false; + + for (const auto& rProp : rProperties) + { + if (rProp.mnIndex > -1) + { // it's a valid property + switch( aPropertyMapper->GetEntryContextId(rProp.mnIndex) ) + { + case CTF_SD_CONTROL_SHAPE_DATA_STYLE: + { // it's the control shape data style property + + if (bFoundControlShapeDataStyle) + { + OSL_FAIL("SvXMLAutoStylePoolP::exportStyleAttributes: found two properties with the ControlShapeDataStyle context id!"); + // already added the attribute for the first occurrence + break; + } + + lcl_exportDataStyle( GetExport(), aPropertyMapper, rProp ); + + // check if there is another property with the special context id we're handling here + bFoundControlShapeDataStyle = true; + break; + } + case CTF_SD_NUMBERINGRULES_NAME: + { + if (bFoundNumberingRulesName) + { + OSL_FAIL("SvXMLAutoStylePoolP::exportStyleAttributes: found two properties with the numbering rules name context id!"); + // already added the attribute for the first occurrence + break; + } + + uno::Reference< container::XIndexReplace > xNumRule; + rProp.maValue >>= xNumRule; + if( xNumRule.is() && (xNumRule->getCount() > 0 ) ) + { + const OUString sName(const_cast<XMLTextListAutoStylePool*>(&GetExport().GetTextParagraphExport()->GetListAutoStylePool())->Add( xNumRule )); + + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_LIST_STYLE_NAME, GetExport().EncodeStyleName( sName ) ); + } + + bFoundNumberingRulesName = true; + break; + } + } + } + } + } + + if( nFamily != XmlStyleFamily::PAGE_MASTER ) + return; + + for( const auto& rProp : rProperties ) + { + if (rProp.mnIndex > -1) + { + const rtl::Reference< XMLPropertySetMapper >& aPropMapper = rPropExp.getPropertySetMapper(); + sal_Int32 nIndex = rProp.mnIndex; + sal_Int16 nContextID = aPropMapper->GetEntryContextId( nIndex ); + switch( nContextID ) + { + case CTF_PM_PAGEUSAGE: + { + OUString sValue; + const XMLPropertyHandler* pPropHdl = aPropMapper->GetPropertyHandler( nIndex ); + if( pPropHdl && + pPropHdl->exportXML( sValue, rProp.maValue, + GetExport().GetMM100UnitConverter() ) && + ( ! IsXMLToken( sValue, XML_ALL ) ) ) + { + GetExport().AddAttribute( aPropMapper->GetEntryNameSpace( nIndex ), aPropMapper->GetEntryXMLName( nIndex ), sValue ); + } + } + break; + } + } + } +} + +void SvXMLAutoStylePoolP::exportStyleContent( + const css::uno::Reference< css::xml::sax::XDocumentHandler > &, + XmlStyleFamily nFamily, + const std::vector< XMLPropertyState >& rProperties, + const SvXMLExportPropertyMapper& rPropExp, + const SvXMLUnitConverter&, + const SvXMLNamespaceMap& + ) const +{ + if( nFamily != XmlStyleFamily::PAGE_MASTER ) + return; + + sal_Int32 nHeaderStartIndex(-1); + sal_Int32 nHeaderEndIndex(-1); + sal_Int32 nFooterStartIndex(-1); + sal_Int32 nFooterEndIndex(-1); + bool bHeaderStartIndex(false); + bool bHeaderEndIndex(false); + bool bFooterStartIndex(false); + bool bFooterEndIndex(false); + + const rtl::Reference< XMLPropertySetMapper >& aPropMapper = rPropExp.getPropertySetMapper(); + + sal_Int32 nIndex(0); + while(nIndex < aPropMapper->GetEntryCount()) + { + switch( aPropMapper->GetEntryContextId( nIndex ) & CTF_PM_FLAGMASK ) + { + case CTF_PM_HEADERFLAG: + { + if (!bHeaderStartIndex) + { + nHeaderStartIndex = nIndex; + bHeaderStartIndex = true; + } + if (bFooterStartIndex && !bFooterEndIndex) + { + nFooterEndIndex = nIndex; + bFooterEndIndex = true; + } + } + break; + case CTF_PM_FOOTERFLAG: + { + if (!bFooterStartIndex) + { + nFooterStartIndex = nIndex; + bFooterStartIndex = true; + } + if (bHeaderStartIndex && !bHeaderEndIndex) + { + nHeaderEndIndex = nIndex; + bHeaderEndIndex = true; + } + } + break; + } + nIndex++; + } + if (!bHeaderEndIndex) + nHeaderEndIndex = nIndex; + if (!bFooterEndIndex) + nFooterEndIndex = nIndex; + + // export header style element + { + SvXMLElementExport aElem( + GetExport(), XML_NAMESPACE_STYLE, XML_HEADER_STYLE, + true, true ); + + rPropExp.exportXML( + GetExport(), rProperties, + nHeaderStartIndex, nHeaderEndIndex, SvXmlExportFlags::IGN_WS); + } + + // export footer style + { + SvXMLElementExport aElem( + GetExport(), XML_NAMESPACE_STYLE, XML_FOOTER_STYLE, + true, true ); + + rPropExp.exportXML( + GetExport(), rProperties, + nFooterStartIndex, nFooterEndIndex, SvXmlExportFlags::IGN_WS); + } + +} + +SvXMLAutoStylePoolP::SvXMLAutoStylePoolP( SvXMLExport& rExport ) + : m_pImpl( new SvXMLAutoStylePoolP_Impl( rExport ) ) +{ +} + +SvXMLAutoStylePoolP::~SvXMLAutoStylePoolP() +{ +} + +SvXMLExport& SvXMLAutoStylePoolP::GetExport() const +{ + return m_pImpl->GetExport(); +} + +// TODO: remove this +void SvXMLAutoStylePoolP::AddFamily( + XmlStyleFamily nFamily, + const OUString& rStrName, + SvXMLExportPropertyMapper* pMapper, + const OUString& aStrPrefix ) +{ + rtl::Reference <SvXMLExportPropertyMapper> xTmp = pMapper; + AddFamily( nFamily, rStrName, xTmp, aStrPrefix ); +} + +void SvXMLAutoStylePoolP::AddFamily( + XmlStyleFamily nFamily, + const OUString& rStrName, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper, + const OUString& rStrPrefix, + bool bAsFamily ) +{ + m_pImpl->AddFamily( nFamily, rStrName, rMapper, rStrPrefix, bAsFamily ); +} + +void SvXMLAutoStylePoolP::SetFamilyPropSetMapper( + XmlStyleFamily nFamily, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper ) +{ + m_pImpl->SetFamilyPropSetMapper( nFamily, rMapper ); +} + +void SvXMLAutoStylePoolP::RegisterName( XmlStyleFamily nFamily, + const OUString& rName ) +{ + m_pImpl->RegisterName( nFamily, rName ); +} + +void SvXMLAutoStylePoolP::RegisterDefinedName( XmlStyleFamily nFamily, + const OUString& rName ) +{ + m_pImpl->RegisterDefinedName( nFamily, rName ); +} + +void SvXMLAutoStylePoolP::GetRegisteredNames( + uno::Sequence<sal_Int32>& rFamilies, + uno::Sequence<OUString>& rNames ) +{ + m_pImpl->GetRegisteredNames( rFamilies, rNames ); +} + +void SvXMLAutoStylePoolP::RegisterNames( + uno::Sequence<sal_Int32> const & aFamilies, + uno::Sequence<OUString> const & aNames ) +{ + assert(aFamilies.getLength() == aNames.getLength()); + + // iterate over sequence(s) and call RegisterName(..) for each pair + const sal_Int32* pFamilies = aFamilies.getConstArray(); + const OUString* pNames = aNames.getConstArray(); + sal_Int32 nCount = std::min( aFamilies.getLength(), aNames.getLength() ); + for( sal_Int32 n = 0; n < nCount; n++ ) + RegisterName( static_cast<XmlStyleFamily>(pFamilies[n]), pNames[n] ); +} + +OUString SvXMLAutoStylePoolP::Add( XmlStyleFamily nFamily, + std::vector< XMLPropertyState >&& rProperties ) +{ + OUString sName; + m_pImpl->Add(sName, nFamily, "", std::move(rProperties) ); + return sName; +} + +OUString SvXMLAutoStylePoolP::Add( XmlStyleFamily nFamily, + const OUString& rParent, + std::vector< XMLPropertyState >&& rProperties, bool bDontSeek ) +{ + OUString sName; + m_pImpl->Add(sName, nFamily, rParent, std::move(rProperties), bDontSeek); + return sName; +} + +bool SvXMLAutoStylePoolP::Add(OUString& rName, XmlStyleFamily nFamily, const OUString& rParent, ::std::vector< XMLPropertyState >&& rProperties ) +{ + return m_pImpl->Add(rName, nFamily, rParent, std::move(rProperties)); +} + +bool SvXMLAutoStylePoolP::AddNamed( const OUString& rName, XmlStyleFamily nFamily, const OUString& rParent, + std::vector< XMLPropertyState > rProperties ) + +{ + return m_pImpl->AddNamed(rName, nFamily, rParent, std::move(rProperties)); +} + +OUString SvXMLAutoStylePoolP::Find( XmlStyleFamily nFamily, + const OUString& rParent, + const std::vector< XMLPropertyState >& rProperties ) const +{ + return m_pImpl->Find( nFamily, rParent, rProperties ); +} + +void SvXMLAutoStylePoolP::exportXML( XmlStyleFamily nFamily ) const +{ + m_pImpl->exportXML( nFamily, this ); +} + +void SvXMLAutoStylePoolP::ClearEntries() +{ + m_pImpl->ClearEntries(); +} + +std::vector<xmloff::AutoStyleEntry> SvXMLAutoStylePoolP::GetAutoStyleEntries() const +{ + return m_pImpl->GetAutoStyleEntries(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlbahdl.cxx b/xmloff/source/style/xmlbahdl.cxx new file mode 100644 index 0000000000..36bc1037cb --- /dev/null +++ b/xmloff/source/style/xmlbahdl.cxx @@ -0,0 +1,904 @@ +/* -*- 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 "xmlbahdl.hxx" + +#include <XMLNumberWithAutoForVoidPropHdl.hxx> +#include <sal/log.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include <sax/tools/converter.hxx> +#include <xmloff/xmluconv.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <xmloff/xmltoken.hxx> + +#include <limits.h> + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +static void lcl_xmloff_setAny( Any& rValue, sal_Int32 nValue, sal_Int8 nBytes ) +{ + switch( nBytes ) + { + case 1: + if( nValue < SCHAR_MIN ) + nValue = SCHAR_MIN; + else if( nValue > SCHAR_MAX ) + nValue = SCHAR_MAX; + rValue <<= static_cast<sal_Int8>(nValue); + break; + case 2: + if( nValue < SHRT_MIN ) + nValue = SHRT_MIN; + else if( nValue > SHRT_MAX ) + nValue = SHRT_MAX; + rValue <<= static_cast<sal_Int16>(nValue); + break; + case 4: + rValue <<= nValue; + break; + } +} + +static bool lcl_xmloff_getAny( const Any& rValue, sal_Int32& nValue, + sal_Int8 nBytes ) +{ + bool bRet = false; + + switch( nBytes ) + { + case 1: + { + sal_Int8 nValue8 = 0; + bRet = rValue >>= nValue8; + nValue = nValue8; + } + break; + case 2: + { + sal_Int16 nValue16 = 0; + bRet = rValue >>= nValue16; + nValue = nValue16; + } + break; + case 4: + bRet = rValue >>= nValue; + break; + } + + return bRet; +} + + +XMLNumberPropHdl::~XMLNumberPropHdl() +{ + // nothing to do +} + +bool XMLNumberPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + lcl_xmloff_setAny( rValue, nValue, nBytes ); + + return bRet; +} + +bool XMLNumberPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + rStrExpValue = OUString::number( nValue ); + + bRet = true; + } + + return bRet; +} + + +XMLNumberNonePropHdl::XMLNumberNonePropHdl( sal_Int8 nB ) : + sZeroStr( GetXMLToken(XML_NO_LIMIT) ), + nBytes( nB ) +{ +} + +XMLNumberNonePropHdl::XMLNumberNonePropHdl( enum XMLTokenEnum eZeroString, sal_Int8 nB ) : + sZeroStr( GetXMLToken( eZeroString ) ), + nBytes( nB ) +{ +} + +XMLNumberNonePropHdl::~XMLNumberNonePropHdl() +{ + // nothing to do +} + +bool XMLNumberNonePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + sal_Int32 nValue = 0; + if( rStrImpValue == sZeroStr ) + { + bRet = true; + } + else + { + bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + } + lcl_xmloff_setAny( rValue, nValue, nBytes ); + + return bRet; +} + +bool XMLNumberNonePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + if( nValue == 0 ) + { + rStrExpValue = sZeroStr; + } + else + { + rStrExpValue = OUString::number( nValue ); + } + + bRet = true; + } + + return bRet; +} + + +XMLMeasurePropHdl::~XMLMeasurePropHdl() +{ + // nothing to do +} + +bool XMLMeasurePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int32 nValue = 0; + bool bRet = rUnitConverter.convertMeasureToCore( nValue, rStrImpValue ); + lcl_xmloff_setAny( rValue, nValue, nBytes ); + return bRet; +} + +bool XMLMeasurePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + OUStringBuffer aOut; + rUnitConverter.convertMeasureToXML( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLBoolFalsePropHdl::~XMLBoolFalsePropHdl() +{ + // nothing to do +} + +bool XMLBoolFalsePropHdl::importXML( const OUString&, Any&, const SvXMLUnitConverter& ) const +{ + return false; +} + +bool XMLBoolFalsePropHdl::exportXML( OUString& rStrExpValue, const Any& /*rValue*/, const SvXMLUnitConverter& rCnv) const +{ + return XMLBoolPropHdl::exportXML( rStrExpValue, Any( false ), rCnv ); +} + + +XMLBoolPropHdl::~XMLBoolPropHdl() +{ + // nothing to do +} + +bool XMLBoolPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue(false); + bool const bRet = ::sax::Converter::convertBool( bValue, rStrImpValue ); + rValue <<= bValue; + + return bRet; +} + +bool XMLBoolPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + OUStringBuffer aOut; + ::sax::Converter::convertBool( aOut, bValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLNBoolPropHdl::~XMLNBoolPropHdl() +{ + // nothing to do +} + +bool XMLNBoolPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue(false); + bool const bRet = ::sax::Converter::convertBool( bValue, rStrImpValue ); + rValue <<= !bValue; + + return bRet; +} + +bool XMLNBoolPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + OUStringBuffer aOut; + ::sax::Converter::convertBool( aOut, !bValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLPercentPropHdl::~XMLPercentPropHdl() +{ + // nothing to do +} + +bool XMLPercentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool const bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + lcl_xmloff_setAny( rValue, nValue, nBytes ); + + return bRet; +} + +bool XMLPercentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +bool XMLDoublePercentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + double fValue = 1.0; + + if( rStrImpValue.indexOf( '%' ) == -1 ) + { + fValue = rStrImpValue.toDouble(); + } + else + { + sal_Int32 nValue = 0; + bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + fValue = static_cast<double>(nValue) / 100.0; + } + rValue <<= fValue; + + return bRet; +} + +bool XMLDoublePercentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + double fValue = 0; + + if( rValue >>= fValue ) + { + fValue *= 100.0; + if( fValue > 0 ) fValue += 0.5; else fValue -= 0.5; + + sal_Int32 nValue = static_cast<sal_Int32>(fValue); + + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +bool XML100thPercentPropHdl::importXML(const OUString& rStrImpValue, Any& rValue, + const SvXMLUnitConverter&) const +{ + bool bRet = false; + + sal_Int32 nValue = 0; + bRet = sax::Converter::convertPercent(nValue, rStrImpValue); + rValue <<= static_cast<sal_Int16>(nValue * 100); + + return bRet; +} + +bool XML100thPercentPropHdl::exportXML(OUString& rStrExpValue, const Any& rValue, + const SvXMLUnitConverter&) const +{ + bool bRet = false; + sal_Int16 nValue = 0; + + if (rValue >>= nValue) + { + nValue = std::round(static_cast<double>(nValue) / 100); + OUStringBuffer aOut; + sax::Converter::convertPercent(aOut, nValue); + rStrExpValue = aOut.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + + +XMLNegPercentPropHdl::~XMLNegPercentPropHdl() +{ + // nothing to do +} + +bool XMLNegPercentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + if (bRet) + bRet = !o3tl::checked_sub<sal_Int32>(100, nValue, nValue); + if (bRet) + lcl_xmloff_setAny( rValue, nValue, nBytes ); + return bRet; +} + +bool XMLNegPercentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, 100-nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +XMLMeasurePxPropHdl::~XMLMeasurePxPropHdl() +{ + // nothing to do +} + +bool XMLMeasurePxPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool bRet = ::sax::Converter::convertMeasurePx( nValue, rStrImpValue ); + lcl_xmloff_setAny( rValue, nValue, nBytes ); + return bRet; +} + +bool XMLMeasurePxPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + OUStringBuffer aOut; + ::sax::Converter::convertMeasurePx( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLColorPropHdl::~XMLColorPropHdl() +{ + // Nothing to do +} + +bool XMLColorPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( rStrImpValue.matchIgnoreAsciiCase( "hsl" ) ) + { + sal_Int32 nOpen = rStrImpValue.indexOf( '(' ); + sal_Int32 nClose = rStrImpValue.lastIndexOf( ')' ); + + if( (nOpen != -1) && (nClose > nOpen) ) + { + const std::u16string_view aTmp( rStrImpValue.subView( nOpen+1, nClose - nOpen-1) ); + + sal_Int32 nIndex = 0; + + Sequence< double > aHSL + { + o3tl::toDouble(o3tl::getToken(aTmp, 0, ',', nIndex )), + o3tl::toDouble(o3tl::getToken(aTmp, 0, ',', nIndex )) / 100.0, + o3tl::toDouble(o3tl::getToken(aTmp, 0, ',', nIndex )) / 100.0 + }; + rValue <<= aHSL; + bRet = true; + } + } + else + { + sal_Int32 nColor(0); + bRet = ::sax::Converter::convertColor( nColor, rStrImpValue ); + rValue <<= nColor; + } + + return bRet; +} + +bool XMLColorPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nColor = 0; + + OUStringBuffer aOut; + if( rValue >>= nColor ) + { + ::sax::Converter::convertColor( aOut, nColor ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + else + { + Sequence< double > aHSL; + if( (rValue >>= aHSL) && (aHSL.getLength() == 3) ) + { + rStrExpValue = "hsl(" + OUString::number(aHSL[0]) + "," + + OUString::number(aHSL[1] * 100.0) + "%," + + OUString::number(aHSL[2] * 100.0) + "%)"; + + bRet = true; + } + } + + return bRet; +} + + +XMLHexPropHdl::~XMLHexPropHdl() +{ + // Nothing to do +} + +bool XMLHexPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt32 nRsid; + bool bRet = SvXMLUnitConverter::convertHex( nRsid, rStrImpValue ); + rValue <<= nRsid; + + return bRet; +} + +bool XMLHexPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt32 nRsid = 0; + + if( rValue >>= nRsid ) + { + OUStringBuffer aOut; + SvXMLUnitConverter::convertHex( aOut, nRsid ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + else + { + bRet = false; + } + + return bRet; +} + + +XMLStringPropHdl::~XMLStringPropHdl() +{ + // Nothing to do +} + +bool XMLStringPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + rValue <<= rStrImpValue; + return true; +} + +bool XMLStringPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( rValue >>= rStrExpValue ) + bRet = true; + + return bRet; +} + + +XMLStyleNamePropHdl::~XMLStyleNamePropHdl() +{ + // Nothing to do +} + +bool XMLStyleNamePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + + if( rValue >>= rStrExpValue ) + { + rStrExpValue = rUnitConverter.encodeStyleName( rStrExpValue ); + bRet = true; + } + + return bRet; +} + + +XMLDoublePropHdl::~XMLDoublePropHdl() +{ + // Nothing to do +} + +bool XMLDoublePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + double fDblValue(0.0); + bool const bRet = ::sax::Converter::convertDouble(fDblValue, rStrImpValue); + rValue <<= fDblValue; + return bRet; +} + +bool XMLDoublePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + double fValue = 0; + + if( rValue >>= fValue ) + { + OUStringBuffer aOut; + ::sax::Converter::convertDouble( aOut, fValue ); + rStrExpValue = aOut.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + + +XMLColorTransparentPropHdl::XMLColorTransparentPropHdl( + enum XMLTokenEnum eTransparent ) : + sTransparent( GetXMLToken( + eTransparent != XML_TOKEN_INVALID ? eTransparent : XML_TRANSPARENT ) ) +{ + // Nothing to do +} + +XMLColorTransparentPropHdl::~XMLColorTransparentPropHdl() +{ + // Nothing to do +} + +bool XMLColorTransparentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( rStrImpValue != sTransparent ) + { + sal_Int32 nColor(0); + bRet = ::sax::Converter::convertColor( nColor, rStrImpValue ); + rValue <<= nColor; + } + + return bRet; +} + +bool XMLColorTransparentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nColor = 0; + + if( rStrExpValue == sTransparent ) + bRet = false; + else if( rValue >>= nColor ) + { + OUStringBuffer aOut; + ::sax::Converter::convertColor( aOut, nColor ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLIsTransparentPropHdl::XMLIsTransparentPropHdl( + enum XMLTokenEnum eTransparent, bool bTransPropVal ) : + sTransparent( GetXMLToken( + eTransparent != XML_TOKEN_INVALID ? eTransparent : XML_TRANSPARENT ) ), + bTransPropValue( bTransPropVal ) +{ +} + +XMLIsTransparentPropHdl::~XMLIsTransparentPropHdl() +{ + // Nothing to do +} + +bool XMLIsTransparentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue = ( (rStrImpValue == sTransparent) == bTransPropValue); + rValue <<= bValue; + + return true; +} + +bool XMLIsTransparentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + // MIB: This looks a bit strange, because bTransPropValue == bValue should + // do the same, but this only applies if 'true' is represented by the same + // 8 bit value in bValue and bTransPropValue. Who will ensure this? + bool bValue = *o3tl::doAccess<bool>(rValue); + bool bIsTrans = bTransPropValue ? bValue : !bValue; + + if( bIsTrans ) + { + rStrExpValue = sTransparent; + bRet = true; + } + + return bRet; +} + + +XMLColorAutoPropHdl::XMLColorAutoPropHdl() +{ + // Nothing to do +} + +XMLColorAutoPropHdl::~XMLColorAutoPropHdl() +{ + // Nothing to do +} + +bool XMLColorAutoPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + // This is a multi property: the value might be set to AUTO_COLOR + // already by the XMLIsAutoColorPropHdl! + sal_Int32 nColor = 0; + if( !(rValue >>= nColor) || -1 != nColor ) + { + bRet = ::sax::Converter::convertColor( nColor, rStrImpValue ); + if( bRet ) + rValue <<= nColor; + } + + return bRet; +} + +bool XMLColorAutoPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + sal_Int32 nColor = 0; + if( (rValue >>= nColor) && -1 != nColor ) + { + OUStringBuffer aOut; + ::sax::Converter::convertColor( aOut, nColor ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLIsAutoColorPropHdl::XMLIsAutoColorPropHdl() +{ +} + +XMLIsAutoColorPropHdl::~XMLIsAutoColorPropHdl() +{ + // Nothing to do +} + +bool XMLIsAutoColorPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + // An auto color overrides any other color set! + bool bValue; + bool const bRet = ::sax::Converter::convertBool( bValue, rStrImpValue ); + if( bRet && bValue ) + rValue <<= sal_Int32(-1); + + return true; +} + +bool XMLIsAutoColorPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nColor = 0; + + if( (rValue >>= nColor) && -1 == nColor ) + { + OUStringBuffer aOut; + ::sax::Converter::convertBool( aOut, true ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLCompareOnlyPropHdl::~XMLCompareOnlyPropHdl() +{ + // Nothing to do +} + +bool XMLCompareOnlyPropHdl::importXML( const OUString&, Any&, const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "importXML called for compare-only-property" ); + return false; +} + +bool XMLCompareOnlyPropHdl::exportXML( OUString&, const Any&, const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "exportXML called for compare-only-property" ); + return false; +} + + +XMLNumberWithoutZeroPropHdl::XMLNumberWithoutZeroPropHdl( sal_Int8 nB ) : + nBytes( nB ) +{ +} + +XMLNumberWithoutZeroPropHdl::~XMLNumberWithoutZeroPropHdl() +{ +} + +bool XMLNumberWithoutZeroPropHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool const bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + if( bRet ) + lcl_xmloff_setAny( rValue, nValue, nBytes ); + return bRet; +} + +bool XMLNumberWithoutZeroPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + + sal_Int32 nValue = 0; + bool bRet = lcl_xmloff_getAny( rValue, nValue, nBytes ); + bRet &= nValue != 0; + + if( bRet ) + { + rStrExpValue = OUString::number(nValue); + } + + return bRet; +} + + +XMLNumberWithAutoForVoidPropHdl::~XMLNumberWithAutoForVoidPropHdl() +{ +} + +bool XMLNumberWithAutoForVoidPropHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + if( bRet ) + lcl_xmloff_setAny( rValue, nValue, 2 ); + else if( rStrImpValue == GetXMLToken( XML_AUTO ) ) + { + rValue.clear(); // void + bRet = true; + } + return bRet; +} + +bool XMLNumberWithAutoForVoidPropHdl::exportXML( + OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter&) const +{ + + sal_Int32 nValue = 0; + bool bRet = lcl_xmloff_getAny( rValue, nValue, 2 ); + + // note: 0 is a valid value here, see CTF_PAGENUMBEROFFSET for when it isn't + + if (!bRet) + rStrExpValue = GetXMLToken( XML_AUTO ); + else + { + rStrExpValue = OUString::number(nValue); + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlbahdl.hxx b/xmloff/source/style/xmlbahdl.hxx new file mode 100644 index 0000000000..09e392d6cc --- /dev/null +++ b/xmloff/source/style/xmlbahdl.hxx @@ -0,0 +1,314 @@ +/* -*- 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 . + */ + +#pragma once + +#include <xmloff/xmlprhdl.hxx> +#include <xmloff/xmltoken.hxx> + + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NUMBER +*/ +class XMLNumberPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; + +public: + explicit XMLNumberPropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLNumberPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NUMBER_NONE +*/ +class XMLNumberNonePropHdl : public XMLPropertyHandler +{ + OUString sZeroStr; + sal_Int8 nBytes; +public: + explicit XMLNumberNonePropHdl( sal_Int8 nB = 4 ); + XMLNumberNonePropHdl( enum ::xmloff::token::XMLTokenEnum eZeroString, sal_Int8 nB ); + virtual ~XMLNumberNonePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_MEASURE +*/ +class XMLMeasurePropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLMeasurePropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLMeasurePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_PERCENT +*/ +class XMLPercentPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLPercentPropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLPercentPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_PERCENT + that is mapped on a double from 0.0 to 1.0 +*/ +class XMLDoublePercentPropHdl : public XMLPropertyHandler +{ + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/// Maps between XML percentage and our 100th percent ints. +class XML100thPercentPropHdl : public XMLPropertyHandler +{ + virtual bool importXML(const OUString& rStrImpValue, css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter) const override; + virtual bool exportXML(OUString& rStrExpValue, const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NEG_PERCENT +*/ +class XMLNegPercentPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLNegPercentPropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLNegPercentPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_PERCENT +*/ +class XMLMeasurePxPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLMeasurePxPropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLMeasurePxPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_BOOL +*/ +class XMLBoolPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLBoolPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLBoolFalsePropHdl : public XMLBoolPropHdl +{ +public: + virtual ~XMLBoolFalsePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_COLOR +*/ +class XMLColorPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLColorPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_HEX +*/ +class XMLHexPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLHexPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_STRING +*/ +class XMLStringPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLStringPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_STYLENAME +*/ +class XMLStyleNamePropHdl : public XMLStringPropHdl +{ +public: + virtual ~XMLStyleNamePropHdl() override; + + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + + +/** + PropertyHandler for the XML-data-type: XML_TYPE_DOUBLE +*/ +class XMLDoublePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLDoublePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NBOOL +*/ +class XMLNBoolPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLNBoolPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_COLORTRANSPARENT +*/ +class XMLColorTransparentPropHdl : public XMLPropertyHandler +{ + const OUString sTransparent; + +public: + explicit XMLColorTransparentPropHdl( enum ::xmloff::token::XMLTokenEnum eTransparent = xmloff::token::XML_TOKEN_INVALID ); + virtual ~XMLColorTransparentPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_ISTRANSPARENT +*/ +class XMLIsTransparentPropHdl : public XMLPropertyHandler +{ + const OUString sTransparent; + bool bTransPropValue; + +public: + XMLIsTransparentPropHdl( enum ::xmloff::token::XMLTokenEnum eTransparent = xmloff::token::XML_TOKEN_INVALID, + bool bTransPropValue = true ); + virtual ~XMLIsTransparentPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_COLORAUTO +*/ +class XMLColorAutoPropHdl : public XMLPropertyHandler +{ +public: + XMLColorAutoPropHdl(); + virtual ~XMLColorAutoPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_COLORISAUTO +*/ +class XMLIsAutoColorPropHdl : public XMLPropertyHandler +{ +public: + XMLIsAutoColorPropHdl(); + virtual ~XMLIsAutoColorPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + + +/** + PropertyHandler for properties that cannot make use of importXML + and exportXML methods, but can make use of the default comparison +*/ +class XMLCompareOnlyPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCompareOnlyPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NUMBER_NO_ZERO + Reads/writes numeric properties, but fails for the value zero + (i.e., a value 0 property will not be written) +*/ +class XMLNumberWithoutZeroPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLNumberWithoutZeroPropHdl( sal_Int8 nB ); + virtual ~XMLNumberWithoutZeroPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlexppr.cxx b/xmloff/source/style/xmlexppr.cxx new file mode 100644 index 0000000000..b296ee8e9d --- /dev/null +++ b/xmloff/source/style/xmlexppr.cxx @@ -0,0 +1,1125 @@ +/* -*- 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 <memory> +#include <optional> +#include <string_view> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/xml/AttributeData.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XTolerantMultiPropertySet.hpp> +#include <com/sun/star/beans/TolerantPropertySetResultType.hpp> +#include <rtl/ustrbuf.hxx> +#include <comphelper/anycompare.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <cppuhelper/weakref.hxx> +#include <osl/diagnose.h> +#include <list> +#include <map> +#include <o3tl/sorted_vector.hxx> + +#include <utility> +#include <xmloff/xmlexppr.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/xmlprhdl.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::xmloff::token; + +#define GET_PROP_TYPE( f ) static_cast<sal_uInt16>((f & XML_TYPE_PROP_MASK) >> XML_TYPE_PROP_SHIFT) + +namespace { + +struct XMLPropTokens_Impl +{ + sal_uInt16 nType; + XMLTokenEnum eToken; +}; + +const sal_uInt16 MAX_PROP_TYPES = + (XML_TYPE_PROP_END >> XML_TYPE_PROP_SHIFT) - + (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT); + +XMLPropTokens_Impl const aPropTokens[MAX_PROP_TYPES] = +{ + { GET_PROP_TYPE(XML_TYPE_PROP_CHART), XML_CHART_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_GRAPHIC), XML_GRAPHIC_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_TABLE), XML_TABLE_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_COLUMN), XML_TABLE_COLUMN_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_ROW), XML_TABLE_ROW_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_CELL), XML_TABLE_CELL_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_LIST_LEVEL), XML_LIST_LEVEL_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_PARAGRAPH), XML_PARAGRAPH_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_TEXT), XML_TEXT_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_DRAWING_PAGE), XML_DRAWING_PAGE_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_PAGE_LAYOUT), XML_PAGE_LAYOUT_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_HEADER_FOOTER), XML_HEADER_FOOTER_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_RUBY), XML_RUBY_PROPERTIES }, + { GET_PROP_TYPE(XML_TYPE_PROP_SECTION), XML_SECTION_PROPERTIES } +}; + +// public methods + +// Take all properties of the XPropertySet which are also found in the +// XMLPropertyMapEntry-array and which are not set to their default-value, +// if a state is available. +// After that I call the method 'ContextFilter'. + +struct ComparePropertyState +{ + bool operator()(XMLPropertyState const& lhs, XMLPropertyState const& rhs) + { + return lhs.mnIndex < rhs.mnIndex; + } +}; +class XMLPropertyStates_Impl +{ + o3tl::sorted_vector<XMLPropertyState, ComparePropertyState> aPropStates; +public: + XMLPropertyStates_Impl(); + void AddPropertyState(const XMLPropertyState& rPropState); + void FillPropertyStateVector(std::vector<XMLPropertyState>& rVector); +}; + +XMLPropertyStates_Impl::XMLPropertyStates_Impl() +{ +} + +void XMLPropertyStates_Impl::AddPropertyState( + const XMLPropertyState& rPropState) +{ + aPropStates.insert(rPropState); +} + +void XMLPropertyStates_Impl::FillPropertyStateVector( + std::vector<XMLPropertyState>& rVector) +{ + rVector.insert( rVector.begin(), aPropStates.begin(), aPropStates.end() ); +} + +class FilterPropertyInfo_Impl +{ + OUString msApiName; + std::vector<sal_uInt32> maIndexes; + +public: + + FilterPropertyInfo_Impl( OUString aApiName, + const sal_uInt32 nIndex); + + const OUString& GetApiName() const { return msApiName; } + std::vector<sal_uInt32>& GetIndexes() { return maIndexes; } + + // for sort + bool operator< ( const FilterPropertyInfo_Impl& rArg ) const + { + return (GetApiName() < rArg.GetApiName()); + } +}; + +FilterPropertyInfo_Impl::FilterPropertyInfo_Impl( + OUString aApiName, + const sal_uInt32 nIndex ) : + msApiName(std::move( aApiName )) +{ + maIndexes.push_back(nIndex); +} + +typedef std::list<FilterPropertyInfo_Impl> FilterPropertyInfoList_Impl; + +class FilterPropertiesInfo_Impl +{ + FilterPropertyInfoList_Impl aPropInfos; + + std::optional<Sequence<OUString>> mxApiNames; + +public: + FilterPropertiesInfo_Impl(); + + void AddProperty(const OUString& rApiName, const sal_uInt32 nIndex); + const uno::Sequence<OUString>& GetApiNames(); + void FillPropertyStateArray( + std::vector< XMLPropertyState >& rPropStates, + const Reference< XPropertySet >& xPropSet, + const rtl::Reference< XMLPropertySetMapper >& maPropMapper, + const bool bDefault); + sal_uInt32 GetPropertyCount() const { return aPropInfos.size(); } +}; + +FilterPropertiesInfo_Impl::FilterPropertiesInfo_Impl() +{ +} + +void FilterPropertiesInfo_Impl::AddProperty( + const OUString& rApiName, const sal_uInt32 nIndex) +{ + aPropInfos.emplace_back(rApiName, nIndex); + + OSL_ENSURE( !mxApiNames, "performance warning: API names already retrieved" ); + mxApiNames.reset(); +} + +const uno::Sequence<OUString>& FilterPropertiesInfo_Impl::GetApiNames() +{ + if( !mxApiNames ) + { + // we have to do three things: + // 1) sort API names, + // 2) merge duplicates, + // 3) construct sequence + + // sort names + aPropInfos.sort(); + + // merge duplicates + if ( aPropInfos.size() > 1 ) + { + FilterPropertyInfoList_Impl::iterator aOld = aPropInfos.begin(); + FilterPropertyInfoList_Impl::iterator aEnd = aPropInfos.end(); + FilterPropertyInfoList_Impl::iterator aCurrent = aOld; + ++aCurrent; + + while ( aCurrent != aEnd ) + { + // equal to next element? + if ( aOld->GetApiName() == aCurrent->GetApiName() ) + { + // if equal: merge index lists + std::vector<sal_uInt32> aMerged; + std::merge(aOld->GetIndexes().begin(), aOld->GetIndexes().end(), + aCurrent->GetIndexes().begin(), aCurrent->GetIndexes().end(), + std::back_inserter(aMerged)); + aOld->GetIndexes() = std::move(aMerged); + aCurrent->GetIndexes().clear(); + // erase element, and continue with next + aCurrent = aPropInfos.erase( aCurrent ); + } + else + { + // remember old element and continue with next + aOld = aCurrent; + ++aCurrent; + } + } + } + + // construct sequence + mxApiNames.emplace( aPropInfos.size() ); + OUString *pNames = mxApiNames->getArray(); + + for (auto const& propInfo : aPropInfos) + { + *pNames = propInfo.GetApiName(); + ++pNames; + } + } + + return *mxApiNames; +} + +void FilterPropertiesInfo_Impl::FillPropertyStateArray( + std::vector< XMLPropertyState >& rPropStates, + const Reference< XPropertySet >& rPropSet, + const rtl::Reference< XMLPropertySetMapper >& rPropMapper, + const bool bDefault ) +{ + XMLPropertyStates_Impl aPropStates; + + const uno::Sequence<OUString>& rApiNames = GetApiNames(); + + Reference < XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY ); + if (xTolPropSet.is()) + { + if (!bDefault) + { + Sequence < beans::GetDirectPropertyTolerantResult > aResults(xTolPropSet->getDirectPropertyValuesTolerant(rApiNames)); + sal_Int32 nResultCount(aResults.getLength()); + if (nResultCount > 0) + { + const beans::GetDirectPropertyTolerantResult *pResults = aResults.getConstArray(); + FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin()); + XMLPropertyState aNewProperty( -1 ); + while (nResultCount > 0 && aPropIter != aPropInfos.end()) + { + if (pResults->Name == aPropIter->GetApiName()) + { + aNewProperty.mnIndex = -1; + aNewProperty.maValue = pResults->Value; + + for (auto const& index : aPropIter->GetIndexes()) + { + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + ++pResults; + --nResultCount; + } + ++aPropIter; + } + } + } + else + { + const Sequence < beans::GetPropertyTolerantResult > aResults(xTolPropSet->getPropertyValuesTolerant(rApiNames)); + OSL_ENSURE( rApiNames.getLength() == aResults.getLength(), "wrong implemented XTolerantMultiPropertySet" ); + FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin()); + XMLPropertyState aNewProperty( -1 ); + OSL_ENSURE( aPropInfos.size() == static_cast<sal_uInt32>(aResults.getLength()), "wrong implemented XTolerantMultiPropertySet??" ); + for( const auto& rResult : aResults ) + { + if ((rResult.Result == beans::TolerantPropertySetResultType::SUCCESS) && + ((rResult.State == PropertyState_DIRECT_VALUE) || (rResult.State == PropertyState_DEFAULT_VALUE))) + { + aNewProperty.mnIndex = -1; + aNewProperty.maValue = rResult.Value; + + for (auto const& index : aPropIter->GetIndexes()) + { + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + } + ++aPropIter; + } + } + } + else + { + Sequence < PropertyState > aStates; + const PropertyState *pStates = nullptr; + Reference< XPropertyState > xPropState( rPropSet, UNO_QUERY ); + if( xPropState.is() ) + { + aStates = xPropState->getPropertyStates( rApiNames ); + pStates = aStates.getConstArray(); + } + + Reference < XMultiPropertySet > xMultiPropSet( rPropSet, UNO_QUERY ); + if( xMultiPropSet.is() && !bDefault ) + { + Sequence < Any > aValues; + if( pStates ) + { + // step 1: get value count + sal_uInt32 nValueCount = 0; + + for (size_t i = 0; i < aPropInfos.size(); ++i, ++pStates) + { + if( *pStates == PropertyState_DIRECT_VALUE ) + nValueCount++; + } + + if( nValueCount ) + { + // step 2: collect property names + Sequence < OUString > aAPINames( nValueCount ); + OUString *pAPINames = aAPINames.getArray(); + + ::std::vector< FilterPropertyInfoList_Impl::iterator > aPropIters; + aPropIters.reserve( nValueCount ); + + FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); + OSL_ENSURE(aItr != aPropInfos.end(),"Invalid iterator!"); + + pStates = aStates.getConstArray(); + sal_uInt32 i = 0; + while( i < nValueCount ) + { + if( *pStates == PropertyState_DIRECT_VALUE ) + { + *pAPINames++ = aItr->GetApiName(); + aPropIters.push_back( aItr ); + ++i; + } + ++aItr; + ++pStates; + } + + aValues = xMultiPropSet->getPropertyValues( aAPINames ); + const Any *pValues = aValues.getConstArray(); + + ::std::vector< FilterPropertyInfoList_Impl::iterator >::const_iterator + pPropIter = aPropIters.begin(); + + XMLPropertyState aNewProperty( -1 ); + for( i = 0; i < nValueCount; ++i ) + { + aNewProperty.mnIndex = -1; + aNewProperty.maValue = *pValues; + + for (auto const& index : (*pPropIter)->GetIndexes()) + { + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + + ++pPropIter; + ++pValues; + } + } + } + else + { + aValues = xMultiPropSet->getPropertyValues( rApiNames ); + const Any *pValues = aValues.getConstArray(); + + FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); + for (size_t i = 0; i < aPropInfos.size(); ++i) + { + // The value is stored in the PropertySet itself, add to list. + XMLPropertyState aNewProperty( -1 ); + aNewProperty.maValue = *pValues; + ++pValues; + for (auto const& index : aItr->GetIndexes()) + { + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + ++aItr; + } + } + } + else + { + FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); + for (size_t i = 0; i < aPropInfos.size(); ++i) + { + bool bDirectValue = + !pStates || *pStates == PropertyState_DIRECT_VALUE; + if( bDirectValue || bDefault ) + { + // The value is stored in the PropertySet itself, add to list. + bool bGotValue = false; + XMLPropertyState aNewProperty( -1 ); + for (auto const& index : aItr->GetIndexes()) + { + if( bDirectValue || + (rPropMapper->GetEntryFlags(index) & + MID_FLAG_DEFAULT_ITEM_EXPORT) != 0 ) + { + try + { + if( !bGotValue ) + { + aNewProperty.maValue = + rPropSet->getPropertyValue( aItr->GetApiName() ); + bGotValue = true; + } + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + catch( UnknownPropertyException& ) + { + // might be a problem of getImplementationId + TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyValue" ); + } + + } + } + } + + ++aItr; + if( pStates ) + ++pStates; + } + } + } + aPropStates.FillPropertyStateVector(rPropStates); +} + +} + +struct SvXMLExportPropertyMapper::Impl +{ + typedef std::map<css::uno::Reference<css::beans::XPropertySetInfo>, std::unique_ptr<FilterPropertiesInfo_Impl>> CacheType; + CacheType maCache; + + rtl::Reference<SvXMLExportPropertyMapper> mxNextMapper; + rtl::Reference<XMLPropertySetMapper> mxPropMapper; + + OUString maStyleName; +}; + +// ctor/dtor , class SvXMLExportPropertyMapper + +SvXMLExportPropertyMapper::SvXMLExportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper ) : + mpImpl(new Impl) +{ + mpImpl->mxPropMapper = rMapper; +} + +SvXMLExportPropertyMapper::~SvXMLExportPropertyMapper() +{ +} + +void SvXMLExportPropertyMapper::ChainExportMapper( + const rtl::Reference< SvXMLExportPropertyMapper>& rMapper ) +{ + // add map entries from rMapper to current map + mpImpl->mxPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() ); + // rMapper uses the same map as 'this' + rMapper->mpImpl->mxPropMapper = mpImpl->mxPropMapper; + + // set rMapper as last mapper in current chain + rtl::Reference< SvXMLExportPropertyMapper > xNext = mpImpl->mxNextMapper; + if( xNext.is()) + { + while (xNext->mpImpl->mxNextMapper.is()) + xNext = xNext->mpImpl->mxNextMapper; + xNext->mpImpl->mxNextMapper = rMapper; + } + else + mpImpl->mxNextMapper = rMapper; + + // if rMapper was already chained, correct + // map pointer of successors + xNext = rMapper; + + while (xNext->mpImpl->mxNextMapper.is()) + { + xNext = xNext->mpImpl->mxNextMapper; + xNext->mpImpl->mxPropMapper = mpImpl->mxPropMapper; + } +} + +std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter( + SvXMLExport const& rExport, + const uno::Reference<beans::XPropertySet>& rPropSet, bool bEnableFoFontFamily ) const +{ + return Filter_(rExport, rPropSet, false, bEnableFoFontFamily); +} + +std::vector<XMLPropertyState> SvXMLExportPropertyMapper::FilterDefaults( + SvXMLExport const& rExport, + const uno::Reference<beans::XPropertySet>& rPropSet ) const +{ + return Filter_(rExport, rPropSet, true, false/*bEnableFoFontFamily*/); +} + +std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter_( + SvXMLExport const& rExport, + const Reference<XPropertySet>& xPropSet, bool bDefault, bool bEnableFoFontFamily ) const +{ + std::vector< XMLPropertyState > aPropStateArray; + + // Retrieve XPropertySetInfo and XPropertyState + Reference< XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() ); + if( !xInfo.is() ) + return aPropStateArray; + + sal_Int32 nProps = mpImpl->mxPropMapper->GetEntryCount(); + + FilterPropertiesInfo_Impl *pFilterInfo = nullptr; + + Impl::CacheType::iterator aIter = mpImpl->maCache.find(xInfo); + if (aIter != mpImpl->maCache.end()) + pFilterInfo = (*aIter).second.get(); + + bool bDelInfo = false; + if( !pFilterInfo ) + { + assert(GetODFDefaultVersion() != SvtSaveOptions::ODFVER_UNKNOWN); + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(rExport.getSaneDefaultVersion()); + pFilterInfo = new FilterPropertiesInfo_Impl; + for( sal_Int32 i=0; i < nProps; i++ ) + { + // Are we allowed to ask for the property? (MID_FLAG_NO_PROP..) + // Does the PropertySet contain name of mpEntries-array ? + const OUString& rAPIName = mpImpl->mxPropMapper->GetEntryAPIName( i ); + const sal_Int32 nFlags = mpImpl->mxPropMapper->GetEntryFlags( i ); + if( (0 == (nFlags & MID_FLAG_NO_PROPERTY_EXPORT)) && + ( (0 != (nFlags & MID_FLAG_MUST_EXIST)) || + xInfo->hasPropertyByName( rAPIName ) ) ) + { + const SvtSaveOptions::ODFSaneDefaultVersion nEarliestODFVersionForExport( + mpImpl->mxPropMapper->GetEarliestODFVersionForExport(i)); + // note: only standard ODF versions are allowed here, + // only exception is the unknown future + assert((nEarliestODFVersionForExport & SvtSaveOptions::ODFSVER_EXTENDED) == 0 + || nEarliestODFVersionForExport == SvtSaveOptions::ODFSVER_FUTURE_EXTENDED); + static_assert(SvtSaveOptions::ODFSVER_LATEST_EXTENDED < SvtSaveOptions::ODFSVER_FUTURE_EXTENDED); + /// standard ODF namespaces for elements and attributes + static sal_uInt16 s_OdfNs[] = { + XML_NAMESPACE_OFFICE, + XML_NAMESPACE_STYLE, + XML_NAMESPACE_TEXT, + XML_NAMESPACE_TABLE, + XML_NAMESPACE_DRAW, + XML_NAMESPACE_FO, + XML_NAMESPACE_XLINK, + XML_NAMESPACE_DC, + XML_NAMESPACE_META, + XML_NAMESPACE_NUMBER, + XML_NAMESPACE_PRESENTATION, + XML_NAMESPACE_SVG, + XML_NAMESPACE_CHART, + XML_NAMESPACE_DR3D, + XML_NAMESPACE_MATH, + XML_NAMESPACE_FORM, + XML_NAMESPACE_SCRIPT, + XML_NAMESPACE_CONFIG, + XML_NAMESPACE_DB, + XML_NAMESPACE_XFORMS, + XML_NAMESPACE_SMIL, + XML_NAMESPACE_ANIMATION, + XML_NAMESPACE_XML, + XML_NAMESPACE_XHTML, + XML_NAMESPACE_GRDDL, + }; + static bool s_Assert(false); + if (!s_Assert) + { + assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs))); + s_Assert = true; + } + //static_assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs))); + auto const ns(mpImpl->mxPropMapper->GetEntryNameSpace(i)); + auto const iter(std::lower_bound(std::begin(s_OdfNs), std::end(s_OdfNs), + ns)); + bool const isExtension(iter == std::end(s_OdfNs) || *iter != ns + // FIXME: very special hack to suppress style:hyperlink + || (ns == XML_NAMESPACE_STYLE + && mpImpl->mxPropMapper->GetEntryXMLName(i) == GetXMLToken(XML_HYPERLINK))); + if (isExtension + ? ((nCurrentVersion & SvtSaveOptions::ODFSVER_EXTENDED) + // if it's in standard ODF, don't export extension + && (nCurrentVersion < nEarliestODFVersionForExport)) + : (nEarliestODFVersionForExport <= nCurrentVersion)) + { + pFilterInfo->AddProperty(rAPIName, i); + } + } + } + + // Check whether the property set info is destroyed if it is assigned to + // a weak reference only; If it is destroyed, then every instance of + // getPropertySetInfo returns a new object; such property set infos must + // not be cached: + WeakReference < XPropertySetInfo > xWeakInfo( xInfo ); + xInfo.clear(); + xInfo = xWeakInfo; + if( xInfo.is() ) + { + mpImpl->maCache.emplace(xInfo, std::unique_ptr<FilterPropertiesInfo_Impl>(pFilterInfo)); + } + else + bDelInfo = true; + } + + if( pFilterInfo->GetPropertyCount() ) + { + try + { + pFilterInfo->FillPropertyStateArray( + aPropStateArray, xPropSet, mpImpl->mxPropMapper, bDefault); + } + catch( UnknownPropertyException& ) + { + // might be a problem of getImplementationId + TOOLS_WARN_EXCEPTION("xmloff.style", "unknown property in getPropertyStates" ); + } + } + + // Call context-filter + if( !aPropStateArray.empty() ) + ContextFilter(bEnableFoFontFamily, aPropStateArray, xPropSet); + + // Have to do if we change from a vector to a list or something like that + + if( bDelInfo ) + delete pFilterInfo; + + return aPropStateArray; +} + +void SvXMLExportPropertyMapper::ContextFilter( + bool bEnableFoFontFamily, + std::vector< XMLPropertyState >& rProperties, + const Reference< XPropertySet >& rPropSet ) const +{ + // Derived class could implement this. + if (mpImpl->mxNextMapper.is()) + mpImpl->mxNextMapper->ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +// Compares two Sequences of XMLPropertyState: +// 1.Number of elements equal ? +// 2.Index of each element equal ? (So I know whether the propertynames are the same) +// 3.Value of each element equal ? +bool SvXMLExportPropertyMapper::Equals( + const std::vector< XMLPropertyState >& aProperties1, + const std::vector< XMLPropertyState >& aProperties2 ) const +{ + if (aProperties1.size() < aProperties2.size()) + return true; + if (aProperties1.size() > aProperties2.size()) + return false; + + sal_uInt32 nCount = aProperties1.size(); + + for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex) + { + const XMLPropertyState& rProp1 = aProperties1[ nIndex ]; + const XMLPropertyState& rProp2 = aProperties2[ nIndex ]; + + // Compare index. If equal, compare value + if( rProp1.mnIndex < rProp2.mnIndex ) + return true; + if( rProp1.mnIndex > rProp2.mnIndex ) + return false; + + if( rProp1.mnIndex != -1 ) + { + // Now compare values + if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) & + XML_TYPE_BUILDIN_CMP ) != 0 ) + { + // simple type ( binary compare ) + if ( rProp1.maValue != rProp2.maValue) + return false; + } + else + { + // complex type ( ask for compare-function ) + if (!mpImpl->mxPropMapper->GetPropertyHandler( + rProp1.mnIndex )->equals( rProp1.maValue, + rProp2.maValue )) + return false; + } + } + } + + return true; +} + +// Compares two Sequences of XMLPropertyState: +// 1.Number of elements equal ? +// 2.Index of each element equal ? (So I know whether the propertynames are the same) +// 3.Value of each element equal ? +bool SvXMLExportPropertyMapper::LessPartial( + const std::vector< XMLPropertyState >& aProperties1, + const std::vector< XMLPropertyState >& aProperties2 ) const +{ + if (aProperties1.size() < aProperties2.size()) + return true; + if (aProperties1.size() > aProperties2.size()) + return false; + + sal_uInt32 nCount = aProperties1.size(); + + for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex) + { + const XMLPropertyState& rProp1 = aProperties1[ nIndex ]; + const XMLPropertyState& rProp2 = aProperties2[ nIndex ]; + + // Compare index. If equal, compare value + if( rProp1.mnIndex < rProp2.mnIndex ) + return true; + if( rProp1.mnIndex > rProp2.mnIndex ) + return false; + + if( rProp1.mnIndex != -1 ) + { + // Now compare values + if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) & + XML_TYPE_BUILDIN_CMP ) != 0 ) + { + // simple type ( binary compare ) + if ( comphelper::anyLess(rProp1.maValue, rProp2.maValue) ) + return true; + if ( comphelper::anyLess(rProp2.maValue, rProp1.maValue ) ) + return false; + } + } + } + + return false; +} + +/** fills the given attribute list with the items in the given set +void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList, + const ::std::vector< XMLPropertyState >& rProperties, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + sal_uInt16 nFlags ) const +{ + _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap, + nFlags, 0, -1, -1 ); +} + +void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList, + const ::std::vector< XMLPropertyState >& rProperties, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx, + sal_uInt16 nFlags ) const +{ + _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap, + nFlags, 0, nPropMapStartIdx, nPropMapEndIdx ); +} +*/ + +void SvXMLExportPropertyMapper::exportXML( + SvXMLExport& rExport, + const ::std::vector< XMLPropertyState >& rProperties, + SvXmlExportFlags nFlags, + bool bUseExtensionNamespaceForGraphicProperties) const +{ + exportXML(rExport, rProperties, -1, -1, nFlags, bUseExtensionNamespaceForGraphicProperties); +} + + +void SvXMLExportPropertyMapper::exportXML( + SvXMLExport& rExport, + const ::std::vector< XMLPropertyState >& rProperties, + sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx, + SvXmlExportFlags nFlags, bool bUseExtensionNamespaceForGraphicProperties) const +{ + sal_uInt16 nPropTypeFlags = 0; + for( sal_uInt16 i=0; i<MAX_PROP_TYPES; ++i ) + { + sal_uInt16 nPropType = aPropTokens[i].nType; + if( 0==i || (nPropTypeFlags & (1 << nPropType)) != 0 ) + { + sal_uInt16 nNamespace = XML_NAMESPACE_STYLE; + if (bUseExtensionNamespaceForGraphicProperties && + aPropTokens[i].eToken == xmloff::token::XML_GRAPHIC_PROPERTIES) + { + nNamespace = XML_NAMESPACE_LO_EXT; + if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + continue; // don't write for ODF <= 1.2 + } + } + + std::vector<sal_uInt16> aIndexArray; + + _exportXML( nPropType, nPropTypeFlags, + rExport.GetAttrList(), rProperties, + rExport.GetMM100UnitConverter(), + rExport.GetNamespaceMap(), + &aIndexArray, + nPropMapStartIdx, nPropMapEndIdx ); + + if( rExport.GetAttrList().getLength() > 0 || + !aIndexArray.empty() ) + { + SvXMLElementExport aElem( rExport, nNamespace, + aPropTokens[i].eToken, + bool(nFlags & SvXmlExportFlags::IGN_WS), + false ); + + exportElementItems( rExport, rProperties, nFlags, aIndexArray ); + } + } + } +} + +/** this method is called for every item that has the + MID_FLAG_SPECIAL_ITEM_EXPORT flag set */ +void SvXMLExportPropertyMapper::handleSpecialItem( + comphelper::AttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + OSL_ENSURE(mpImpl->mxNextMapper.is(), "special item not handled in xml export"); + if (mpImpl->mxNextMapper.is()) + mpImpl->mxNextMapper->handleSpecialItem( + rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx); +} + +/** this method is called for every item that has the + MID_FLAG_ELEMENT_EXPORT flag set */ +void SvXMLExportPropertyMapper::handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + OSL_ENSURE(mpImpl->mxNextMapper.is(), "element item not handled in xml export"); + if (mpImpl->mxNextMapper.is()) + mpImpl->mxNextMapper->handleElementItem(rExport, rProperty, nFlags, pProperties, nIdx); +} + +// protected methods + +/** fills the given attribute list with the items in the given set */ +void SvXMLExportPropertyMapper::_exportXML( + sal_uInt16 nPropType, sal_uInt16& rPropTypeFlags, + comphelper::AttributeList& rAttrList, + const ::std::vector< XMLPropertyState >& rProperties, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + std::vector<sal_uInt16>* pIndexArray, + sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx ) const +{ + const sal_uInt32 nCount = rProperties.size(); + sal_uInt32 nIndex = 0; + + if( -1 == nPropMapStartIdx ) + nPropMapStartIdx = 0; + if( -1 == nPropMapEndIdx ) + nPropMapEndIdx = mpImpl->mxPropMapper->GetEntryCount(); + + while( nIndex < nCount ) + { + sal_Int32 nPropMapIdx = rProperties[nIndex].mnIndex; + if( nPropMapIdx >= nPropMapStartIdx && + nPropMapIdx < nPropMapEndIdx )// valid entry? + { + sal_uInt32 nEFlags = mpImpl->mxPropMapper->GetEntryFlags(nPropMapIdx); + sal_uInt16 nEPType = GET_PROP_TYPE(nEFlags); + OSL_ENSURE(nEPType >= (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT), + "no prop type specified"); + rPropTypeFlags |= (1 << nEPType); + if( nEPType == nPropType ) + { + // we have a valid map entry here, so lets use it... + if( ( nEFlags & MID_FLAG_ELEMENT_ITEM_EXPORT ) != 0 ) + { + // element items do not add any properties, + // we export it later + if( pIndexArray ) + { + pIndexArray->push_back( static_cast<sal_uInt16>(nIndex) ); + } + } + else + { + _exportXML( rAttrList, rProperties[nIndex], rUnitConverter, + rNamespaceMap, &rProperties, nIndex ); + } + } + } + + nIndex++; + } +} + +namespace +{ +// -1 = Attribute needs extended namespace, but current ODF version is strict. +// 1 = Attribute needs extended namespace and current ODF version allows it. +// 0 = Attribute does not need extended namespace +sal_Int8 CheckExtendedNamespace(std::u16string_view sXMLAttributeName, std::u16string_view sValue, + const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion) +{ + if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE) + && (IsXMLToken(sValue, XML_BT_LR) || IsXMLToken(sValue, XML_TB_RL90))) + return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1; + else if (IsXMLToken(sXMLAttributeName, XML_VERTICAL_REL) + && (IsXMLToken(sValue, XML_PAGE_CONTENT_BOTTOM) + || IsXMLToken(sValue, XML_PAGE_CONTENT_TOP))) + return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1; + return 0; +} +} + +void SvXMLExportPropertyMapper::_exportXML( + comphelper::AttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_SPECIAL_ITEM_EXPORT) != 0) + { + uno::Reference< container::XNameContainer > xAttrContainer; + if( (rProperty.maValue >>= xAttrContainer) && xAttrContainer.is() ) + { + std::unique_ptr<SvXMLNamespaceMap> pNewNamespaceMap; + const SvXMLNamespaceMap *pNamespaceMap = &rNamespaceMap; + + const uno::Sequence< OUString > aAttribNames( xAttrContainer->getElementNames() ); + + xml::AttributeData aData; + for( const auto& rAttribName : aAttribNames ) + { + xAttrContainer->getByName( rAttribName ) >>= aData; + OUString sAttribName( rAttribName ); + + // extract namespace prefix from attribute name if it exists + OUString sPrefix; + const sal_Int32 nColonPos = + rAttribName.indexOf( ':' ); + if( nColonPos != -1 ) + sPrefix = rAttribName.copy( 0, nColonPos ); + + if( !sPrefix.isEmpty() ) + { + OUString sNamespace( aData.Namespace ); + + // if the prefix isn't defined yet or has another meaning, + // we have to redefine it now. + sal_uInt16 nKey = pNamespaceMap->GetKeyByPrefix( sPrefix ); + if( USHRT_MAX == nKey || pNamespaceMap->GetNameByKey( nKey ) != sNamespace ) + { + bool bAddNamespace = false; + if( USHRT_MAX == nKey ) + { + // The prefix is unused, so it is sufficient + // to add it to the namespace map. + bAddNamespace = true; + } + else + { + // check if there is a prefix registered for the + // namespace URI + nKey = pNamespaceMap->GetKeyByName( sNamespace ); + if( XML_NAMESPACE_UNKNOWN == nKey ) + { + // There is no prefix for the namespace, so + // we have to generate one and have to add it. + sal_Int32 n=0; + OUString sOrigPrefix( sPrefix ); + do + { + sPrefix = sOrigPrefix + OUString::number( ++n ); + nKey = pNamespaceMap->GetKeyByPrefix( sPrefix ); + } + while( nKey != USHRT_MAX ); + + bAddNamespace = true; + } + else + { + // If there is a prefix for the namespace, + // we reuse that. + sPrefix = pNamespaceMap->GetPrefixByKey( nKey ); + } + // In any case, the attribute name has to be adapted. + sAttribName = sPrefix + ":" + rAttribName.subView(nColonPos+1); + } + + if( bAddNamespace ) + { + if( !pNewNamespaceMap ) + { + pNewNamespaceMap.reset(new SvXMLNamespaceMap( rNamespaceMap )); + pNamespaceMap = pNewNamespaceMap.get(); + } + pNewNamespaceMap->Add( sPrefix, sNamespace ); + OUString sAttr = GetXMLToken(XML_XMLNS) + ":" + sPrefix; + rAttrList.AddAttribute( sAttr, sNamespace ); + } + } + } + OUString sOldValue( rAttrList.getValueByName( sAttribName ) ); + OSL_ENSURE( sOldValue.isEmpty(), "alien attribute exists already" ); + OSL_ENSURE(aData.Type == GetXMLToken(XML_CDATA), "different type to our default type which should be written out"); + if( sOldValue.isEmpty() ) + rAttrList.AddAttribute( sAttribName, aData.Value ); + } + } + else + { + handleSpecialItem( rAttrList, rProperty, rUnitConverter, + rNamespaceMap, pProperties, nIdx ); + } + } + else if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_ELEMENT_ITEM_EXPORT ) == 0) + { + OUString aValue; + OUString sName = rNamespaceMap.GetQNameByKey( + mpImpl->mxPropMapper->GetEntryNameSpace(rProperty.mnIndex), + mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); + + bool bRemove = false; + if ((mpImpl->mxPropMapper->GetEntryFlags( rProperty.mnIndex ) & MID_FLAG_MERGE_ATTRIBUTE) != 0) + { + aValue = rAttrList.getValueByName( sName ); + bRemove = true; + } + + if (mpImpl->mxPropMapper->exportXML(aValue, rProperty, rUnitConverter)) + { + if( bRemove ) + rAttrList.RemoveAttribute( sName ); + + // We don't seem to have a generic mechanism to write an attribute in the extension + // namespace in case of certain attribute values only, so do this manually. + sal_Int8 nExtendedStatus + = CheckExtendedNamespace(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex), + aValue, rUnitConverter.getSaneDefaultVersion()); + if (nExtendedStatus == -1) + return; + if (nExtendedStatus == 1) + sName = rNamespaceMap.GetQNameByKey( + XML_NAMESPACE_LO_EXT, mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); + rAttrList.AddAttribute( sName, aValue ); + } + } +} + +void SvXMLExportPropertyMapper::exportElementItems( + SvXMLExport& rExport, + const ::std::vector< XMLPropertyState >& rProperties, + SvXmlExportFlags nFlags, + const std::vector<sal_uInt16>& rIndexArray ) const +{ + bool bItemsExported = false; + for (const sal_uInt16 nElement : rIndexArray) + { + OSL_ENSURE( 0 != (mpImpl->mxPropMapper->GetEntryFlags( + rProperties[nElement].mnIndex ) & MID_FLAG_ELEMENT_ITEM_EXPORT), + "wrong mid flag!" ); + + rExport.IgnorableWhitespace(); + handleElementItem( rExport, rProperties[nElement], + nFlags, &rProperties, nElement ); + bItemsExported = true; + } + + if( bItemsExported ) + rExport.IgnorableWhitespace(); +} + +const rtl::Reference<XMLPropertySetMapper>& SvXMLExportPropertyMapper::getPropertySetMapper() const +{ + return mpImpl->mxPropMapper; +} + +void SvXMLExportPropertyMapper::SetStyleName( const OUString& rStyleName ) +{ + mpImpl->maStyleName = rStyleName; +} + +const OUString& SvXMLExportPropertyMapper::GetStyleName() const +{ + return mpImpl->maStyleName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlimppr.cxx b/xmloff/source/style/xmlimppr.cxx new file mode 100644 index 0000000000..f72d6906e1 --- /dev/null +++ b/xmloff/source/style/xmlimppr.cxx @@ -0,0 +1,761 @@ +/* -*- 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 <com/sun/star/xml/AttributeData.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/beans/PropertyVetoException.hpp> +#include <com/sun/star/beans/TolerantPropertySetResultType.hpp> +#include <com/sun/star/beans/XTolerantMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <utility> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlimp.hxx> + +#include <xmloff/unoatrcn.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/contextid.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/maptype.hxx> + +#include <algorithm> +#include <vector> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; + +using namespace ::xmloff::token; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::lang::WrappedTargetException; +using ::com::sun::star::beans::UnknownPropertyException; +using ::com::sun::star::beans::PropertyVetoException; + + +SvXMLImportPropertyMapper::SvXMLImportPropertyMapper( + rtl::Reference< XMLPropertySetMapper > xMapper, + SvXMLImport& rImp ): + m_rImport(rImp), + maPropMapper (std::move( xMapper )) +{ +} + +SvXMLImportPropertyMapper::~SvXMLImportPropertyMapper() +{ + mxNextMapper = nullptr; +} + +void SvXMLImportPropertyMapper::ChainImportMapper( + const rtl::Reference< SvXMLImportPropertyMapper>& rMapper ) +{ + // add map entries from rMapper to current map + maPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() ); + // rMapper uses the same map as 'this' + rMapper->maPropMapper = maPropMapper; + + // set rMapper as last mapper in current chain + rtl::Reference< SvXMLImportPropertyMapper > xNext = mxNextMapper; + if( xNext.is()) + { + while( xNext->mxNextMapper.is()) + xNext = xNext->mxNextMapper; + xNext->mxNextMapper = rMapper; + } + else + mxNextMapper = rMapper; + + // if rMapper was already chained, correct + // map pointer of successors + xNext = rMapper; + + while( xNext->mxNextMapper.is()) + { + xNext = xNext->mxNextMapper; + xNext->maPropMapper = maPropMapper; + } +} + +/** fills the given itemset with the attributes in the given list */ +void SvXMLImportPropertyMapper::importXML( + std::vector< XMLPropertyState >& rProperties, + const Reference< XFastAttributeList >& xAttrList, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + sal_uInt32 nPropType, + sal_Int32 nStartIdx, + sal_Int32 nEndIdx ) const +{ + Reference< XNameContainer > xAttrContainer; + + if( -1 == nStartIdx ) + nStartIdx = 0; + if( -1 == nEndIdx ) + nEndIdx = maPropMapper->GetEntryCount(); + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + sal_Int32 nToken = aIter.getToken(); + if( IsTokenInNamespace(nToken, XML_NAMESPACE_XMLNS) ) + continue; + + const OUString aPrefix = SvXMLImport::getNamespacePrefixFromToken(nToken, &rNamespaceMap); + const OUString aNamespaceURI = SvXMLImport::getNamespaceURIFromToken(nToken); + OUString sAttrName = SvXMLImport::getNameFromToken( nToken ); + if ( !aPrefix.isEmpty() ) + sAttrName = aPrefix + SvXMLImport::aNamespaceSeparator + sAttrName; + + const OUString sValue = aIter.toString(); + + importXMLAttribute(rProperties, rUnitConverter, rNamespaceMap, + nPropType, nStartIdx, nEndIdx, xAttrContainer, + sAttrName, aNamespaceURI, sValue); + } + + const css::uno::Sequence< css::xml::Attribute > unknownAttribs = xAttrList->getUnknownAttributes(); + for (const css::xml::Attribute& rAttribute : unknownAttribs) + { + int nSepIndex = rAttribute.Name.indexOf(SvXMLImport::aNamespaceSeparator); + if (nSepIndex != -1) + { + // If it's an unknown attribute in a known namespace, ignore it. + OUString aPrefix = rAttribute.Name.copy(0, nSepIndex); + auto nKey = rNamespaceMap.GetKeyByPrefix(aPrefix); + if (nKey != USHRT_MAX && !(nKey & XML_NAMESPACE_UNKNOWN_FLAG)) + continue; + } + + importXMLAttribute(rProperties, rUnitConverter, rNamespaceMap, + nPropType, nStartIdx, nEndIdx, xAttrContainer, + rAttribute.Name, rAttribute.NamespaceURL, rAttribute.Value); + } + + finished( rProperties, nStartIdx, nEndIdx ); +} + +void SvXMLImportPropertyMapper::importXMLAttribute( + std::vector< XMLPropertyState >& rProperties, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const sal_uInt32 nPropType, + const sal_Int32 nStartIdx, + const sal_Int32 nEndIdx, + Reference< XNameContainer >& xAttrContainer, + const OUString& rAttrName, + const OUString& aNamespaceURI, + const OUString& sValue) const +{ + OUString aLocalName, aPrefix, aNamespace; + sal_uInt16 nPrefix = rNamespaceMap.GetKeyByAttrName( rAttrName, &aPrefix, + &aLocalName, &aNamespace ); + + // index of actual property map entry + // This looks very strange, but it works well: + // If the start index is 0, the new value will become -1, and + // GetEntryIndex will start searching with position 0. + // Otherwise GetEntryIndex will start with the next position specified. + sal_Int32 nIndex = nStartIdx - 1; + sal_uInt32 nFlags = 0; // flags of actual property map entry + bool bFound = false; + + // for better error reporting: this should be set true if no + // warning is needed + bool bNoWarning = false; + + do + { + // find an entry for this attribute + nIndex = maPropMapper->GetEntryIndex( nPrefix, aLocalName, + nPropType, nIndex ); + + if( nIndex > -1 && nIndex < nEndIdx ) + { + // create a XMLPropertyState with an empty value + + nFlags = maPropMapper->GetEntryFlags( nIndex ); + if( ( nFlags & MID_FLAG_ELEMENT_ITEM_IMPORT ) == 0 ) + { + XMLPropertyState aNewProperty( nIndex ); + sal_Int32 nReference = -1; + + // if this is a multi attribute check if another attribute already set + // this any. If so use this as an initial value + if( ( nFlags & MID_FLAG_MERGE_PROPERTY ) != 0 ) + { + const OUString aAPIName( maPropMapper->GetEntryAPIName( nIndex ) ); + const sal_Int32 nSize = rProperties.size(); + for( nReference = 0; nReference < nSize; nReference++ ) + { + sal_Int32 nRefIdx = rProperties[nReference].mnIndex; + if( (nRefIdx != -1) && (nIndex != nRefIdx) && + (maPropMapper->GetEntryAPIName( nRefIdx ) == aAPIName )) + { + aNewProperty = rProperties[nReference]; + aNewProperty.mnIndex = nIndex; + break; + } + } + + if( nReference == nSize ) + nReference = -1; + } + + bool bSet = false; + if( ( nFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) == 0 ) + { + // let the XMLPropertySetMapper decide how to import the value + bSet = maPropMapper->importXML( sValue, aNewProperty, + rUnitConverter ); + } + else + { + sal_uInt32 nOldSize = rProperties.size(); + + bSet = handleSpecialItem( aNewProperty, rProperties, + sValue, rUnitConverter, + rNamespaceMap ); + + // no warning if handleSpecialItem added properties + bNoWarning |= ( nOldSize != rProperties.size() ); + } + + // no warning if we found could set the item. This + // 'remembers' bSet across multi properties. + bNoWarning |= bSet; + + // store the property in the given vector + if( bSet ) + { + if( nReference == -1 ) + rProperties.push_back( aNewProperty ); + else + rProperties[nReference] = aNewProperty; + } + else + { + // warn about unknown value. Unless it's a + // multi property: Then we get another chance + // to set the value. + if( !bNoWarning && + ((nFlags & MID_FLAG_MULTI_PROPERTY) == 0) ) + { + m_rImport.SetError( XMLERROR_FLAG_WARNING | + XMLERROR_STYLE_ATTR_VALUE, + { rAttrName, sValue } ); + } + } + } + bFound = true; + continue; + } + + if( !bFound ) + { + SAL_INFO_IF((XML_NAMESPACE_NONE != nPrefix) && + !(XML_NAMESPACE_UNKNOWN_FLAG & nPrefix), + "xmloff.style", + "unknown attribute: \"" << rAttrName << "\""); + if( (XML_NAMESPACE_UNKNOWN_FLAG & nPrefix) || (XML_NAMESPACE_NONE == nPrefix) ) + { + if( !xAttrContainer.is() ) + { + // add an unknown attribute container to the properties + Reference< XNameContainer > xNew( SvUnoAttributeContainer_CreateInstance(), UNO_QUERY ); + xAttrContainer = xNew; + + // find map entry and create new property state + if( -1 == nIndex ) + { + switch( nPropType ) + { + case XML_TYPE_PROP_CHART: + nIndex = maPropMapper->FindEntryIndex( "ChartUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) ); + break; + case XML_TYPE_PROP_PARAGRAPH: + nIndex = maPropMapper->FindEntryIndex( "ParaUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) ); + break; + case XML_TYPE_PROP_TEXT: + nIndex = maPropMapper->FindEntryIndex( "TextUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) ); + break; + default: + break; + } + // other property type or property not found + if( -1 == nIndex ) + nIndex = maPropMapper->FindEntryIndex( "UserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) ); + } + + // #106963#; use userdefined attribute only if it is in the specified property range + if( nIndex != -1 && nIndex >= nStartIdx && nIndex < nEndIdx) + { + XMLPropertyState aNewProperty( nIndex, Any(xAttrContainer) ); + + // push it on our stack so we export it later + rProperties.push_back( aNewProperty ); + } + } + + if( xAttrContainer.is() ) + { + AttributeData aData; + aData.Type = GetXMLToken( XML_CDATA ); + aData.Value = sValue; + OUString sName; + if( XML_NAMESPACE_NONE != nPrefix ) + { + sName = rAttrName; + aData.Namespace = aNamespaceURI; + } + else + sName = aLocalName; + xAttrContainer->insertByName( sName, Any(aData) ); + } + } + } + } + while( ( nIndex >= 0 && nIndex + 1 < nEndIdx ) && (( nFlags & MID_FLAG_MULTI_PROPERTY ) != 0 ) ); +} + +/** this method is called for every item that has the MID_FLAG_SPECIAL_ITEM_IMPORT flag set */ +bool SvXMLImportPropertyMapper::handleSpecialItem( + XMLPropertyState& rProperty, + std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const +{ + OSL_ENSURE( mxNextMapper.is(), "unsupported special item in xml import" ); + if( mxNextMapper.is() ) + return mxNextMapper->handleSpecialItem( rProperty, rProperties, rValue, + rUnitConverter, rNamespaceMap ); + else + return false; +} + +void SvXMLImportPropertyMapper::FillPropertySequence( + const ::std::vector< XMLPropertyState >& rProperties, + css::uno::Sequence< css::beans::PropertyValue >& rValues ) + const +{ + sal_Int32 nCount = rProperties.size(); + sal_Int32 nValueCount = 0; + rValues.realloc( nCount ); + PropertyValue *pProps = rValues.getArray(); + for( sal_Int32 i=0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = rProperties[i]; + sal_Int32 nIdx = rProp.mnIndex; + if( nIdx == -1 ) + continue; + pProps->Name = maPropMapper->GetEntryAPIName( nIdx ); + if( !pProps->Name.isEmpty() ) + { + pProps->Value = rProp.maValue; + ++pProps; + ++nValueCount; + } + } + if( nValueCount < nCount ) + rValues.realloc( nValueCount ); +} + +void SvXMLImportPropertyMapper::CheckSpecialContext( + const ::std::vector< XMLPropertyState >& aProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet, + ContextID_Index_Pair* pSpecialContextIds ) const +{ + OSL_ENSURE( rPropSet.is(), "need an XPropertySet" ); + sal_Int32 nCount = aProperties.size(); + + for( sal_Int32 i=0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = aProperties[i]; + sal_Int32 nIdx = rProp.mnIndex; + + // disregard property state if it has an invalid index + if( -1 == nIdx ) + continue; + + const sal_Int32 nPropFlags = maPropMapper->GetEntryFlags( nIdx ); + + // handle no-property and special items + if( ( pSpecialContextIds != nullptr ) && + ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) || + ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) ) ) ) + { + // maybe it's one of our special context ids? + sal_Int16 nContextId = maPropMapper->GetEntryContextId(nIdx); + + for ( sal_Int32 n = 0; + pSpecialContextIds[n].nContextID != -1; + n++ ) + { + // found: set index in pSpecialContextIds array + if ( pSpecialContextIds[n].nContextID == nContextId ) + { + pSpecialContextIds[n].nIndex = i; + break; // early out + } + } + } + } + +} + +bool SvXMLImportPropertyMapper::FillPropertySet( + const std::vector< XMLPropertyState >& aProperties, + const Reference< XPropertySet >& rPropSet, + ContextID_Index_Pair* pSpecialContextIds ) const +{ + bool bSet = false; + + Reference< XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY ); + if (xTolPropSet.is()) + bSet = FillTolerantMultiPropertySet_( aProperties, xTolPropSet, maPropMapper, m_rImport, + pSpecialContextIds ); + + if (!bSet) + { + // get property set info + Reference< XPropertySetInfo > xInfo(rPropSet->getPropertySetInfo()); + + // check for multi-property set + Reference<XMultiPropertySet> xMultiPropSet( rPropSet, UNO_QUERY ); + if ( xMultiPropSet.is() ) + { + // Try XMultiPropertySet. If that fails, try the regular route. + bSet = FillMultiPropertySet_( aProperties, xMultiPropSet, + xInfo, maPropMapper, + pSpecialContextIds ); + if ( !bSet ) + bSet = FillPropertySet_( aProperties, rPropSet, + xInfo, maPropMapper, m_rImport, + pSpecialContextIds); + } + else + bSet = FillPropertySet_( aProperties, rPropSet, xInfo, + maPropMapper, m_rImport, + pSpecialContextIds ); + } + + return bSet; +} + +bool SvXMLImportPropertyMapper::FillPropertySet_( + const std::vector<XMLPropertyState> & rProperties, + const Reference<XPropertySet> & rPropSet, + const Reference<XPropertySetInfo> & rPropSetInfo, + const rtl::Reference<XMLPropertySetMapper> & rPropMapper, + SvXMLImport& rImport, + ContextID_Index_Pair* pSpecialContextIds ) +{ + OSL_ENSURE( rPropSet.is(), "need an XPropertySet" ); + OSL_ENSURE( rPropSetInfo.is(), "need an XPropertySetInfo" ); + + // preliminaries + bool bSet = false; + sal_Int32 nCount = rProperties.size(); + + // iterate over property states that we want to set + for( sal_Int32 i=0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = rProperties[i]; + sal_Int32 nIdx = rProp.mnIndex; + + // disregard property state if it has an invalid index + if( -1 == nIdx ) + continue; + + const OUString& rPropName = rPropMapper->GetEntryAPIName( nIdx ); + const sal_Int32 nPropFlags = rPropMapper->GetEntryFlags( nIdx ); + + if ( ( 0 == ( nPropFlags & MID_FLAG_NO_PROPERTY ) ) && + ( ( 0 != ( nPropFlags & MID_FLAG_MUST_EXIST ) ) || + rPropSetInfo->hasPropertyByName( rPropName ) ) ) + { + // try setting the property + try + { + rPropSet->setPropertyValue( rPropName, rProp.maValue ); + bSet = true; + } + catch ( const IllegalArgumentException& e ) + { + // illegal value: check whether this property is + // allowed to throw this exception + if ( 0 == ( nPropFlags & MID_FLAG_PROPERTY_MAY_THROW ) ) + { + Sequence<OUString> aSeq { rPropName }; + rImport.SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_ERROR, + aSeq, e.Message, nullptr ); + } + } + catch ( const UnknownPropertyException& e ) + { + // unknown property: This is always an error! + Sequence<OUString> aSeq { rPropName }; + rImport.SetError( + XMLERROR_STYLE_PROP_UNKNOWN | XMLERROR_FLAG_ERROR, + aSeq, e.Message, nullptr ); + } + catch ( const PropertyVetoException& e ) + { + // property veto: this shouldn't happen + Sequence<OUString> aSeq { rPropName }; + rImport.SetError( + XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR, + aSeq, e.Message, nullptr ); + } + catch ( const WrappedTargetException& e ) + { + // wrapped target: this shouldn't happen either + Sequence<OUString> aSeq { rPropName }; + rImport.SetError( + XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR, + aSeq, e.Message, nullptr ); + } + } + + // handle no-property and special items + if( ( pSpecialContextIds != nullptr ) && + ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) || + ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) ) ) ) + { + // maybe it's one of our special context ids? + sal_Int16 nContextId = rPropMapper->GetEntryContextId(nIdx); + + for ( sal_Int32 n = 0; + pSpecialContextIds[n].nContextID != -1; + n++ ) + { + // found: set index in pSpecialContextIds array + if ( pSpecialContextIds[n].nContextID == nContextId ) + { + pSpecialContextIds[n].nIndex = i; + break; // early out + } + } + } + } + + return bSet; +} + + +typedef std::pair<const OUString*, const Any* > PropertyPair; + +namespace { + +struct PropertyPairLessFunctor +{ + bool operator()( const PropertyPair& a, const PropertyPair& b ) const + { + return (*a.first < *b.first); + } +}; + +} + +void SvXMLImportPropertyMapper::PrepareForMultiPropertySet_( + const std::vector<XMLPropertyState> & rProperties, + const Reference<XPropertySetInfo> & rPropSetInfo, + const rtl::Reference<XMLPropertySetMapper> & rPropMapper, + ContextID_Index_Pair* pSpecialContextIds, + Sequence<OUString>& rNames, + Sequence<Any>& rValues) +{ + sal_Int32 nCount = rProperties.size(); + + // property pairs structure stores names + values of properties to be set. + std::vector<PropertyPair> aPropertyPairs; + aPropertyPairs.reserve( nCount ); + + // iterate over property states that we want to set + sal_Int32 i; + for( i = 0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = rProperties[i]; + sal_Int32 nIdx = rProp.mnIndex; + + // disregard property state if it has an invalid index + if( -1 == nIdx ) + continue; + + const OUString& rPropName = rPropMapper->GetEntryAPIName( nIdx ); + const sal_Int32 nPropFlags = rPropMapper->GetEntryFlags( nIdx ); + + if ( ( 0 == ( nPropFlags & MID_FLAG_NO_PROPERTY ) ) && + ( ( 0 != ( nPropFlags & MID_FLAG_MUST_EXIST ) ) || + !rPropSetInfo.is() || + rPropSetInfo->hasPropertyByName(rPropName) ) ) + { + // save property into property pair structure + aPropertyPairs.emplace_back( &rPropName, &rProp.maValue ); + } + + // handle no-property and special items + if( ( pSpecialContextIds != nullptr ) && + ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) || + ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) ) ) ) + { + // maybe it's one of our special context ids? + sal_Int16 nContextId = rPropMapper->GetEntryContextId(nIdx); + for ( sal_Int32 n = 0; + pSpecialContextIds[n].nContextID != -1; + n++ ) + { + // found: set index in pSpecialContextIds array + if ( pSpecialContextIds[n].nContextID == nContextId ) + { + pSpecialContextIds[n].nIndex = i; + break; // early out + } + } + } + } + + // We now need to construct the sequences and actually the set + // values. + + // sort the property pairs + sort( aPropertyPairs.begin(), aPropertyPairs.end(), + PropertyPairLessFunctor()); + + // create sequences + rNames.realloc( aPropertyPairs.size() ); + OUString* pNamesArray = rNames.getArray(); + rValues.realloc( aPropertyPairs.size() ); + Any* pValuesArray = rValues.getArray(); + + // copy values into sequences + i = 0; + for( const auto& rPropertyPair : aPropertyPairs ) + { + pNamesArray[i] = *(rPropertyPair.first); + pValuesArray[i++] = *(rPropertyPair.second); + } +} + +bool SvXMLImportPropertyMapper::FillMultiPropertySet_( + const std::vector<XMLPropertyState> & rProperties, + const Reference<XMultiPropertySet> & rMultiPropSet, + const Reference<XPropertySetInfo> & rPropSetInfo, + const rtl::Reference<XMLPropertySetMapper> & rPropMapper, + ContextID_Index_Pair* pSpecialContextIds ) +{ + OSL_ENSURE( rMultiPropSet.is(), "Need multi property set. "); + OSL_ENSURE( rPropSetInfo.is(), "Need property set info." ); + + bool bSuccessful = false; + + Sequence<OUString> aNames; + Sequence<Any> aValues; + + PrepareForMultiPropertySet_(rProperties, rPropSetInfo, rPropMapper, pSpecialContextIds, + aNames, aValues); + + // and, finally, try to set the values + try + { + rMultiPropSet->setPropertyValues( aNames, aValues ); + bSuccessful = true; + } + catch ( ... ) + { + OSL_ENSURE(bSuccessful, "Exception caught; style may not be imported correctly."); + } + + return bSuccessful; +} + +bool SvXMLImportPropertyMapper::FillTolerantMultiPropertySet_( + const std::vector<XMLPropertyState> & rProperties, + const Reference<XTolerantMultiPropertySet> & rTolMultiPropSet, + const rtl::Reference<XMLPropertySetMapper> & rPropMapper, + SvXMLImport& rImport, + ContextID_Index_Pair* pSpecialContextIds ) +{ + OSL_ENSURE( rTolMultiPropSet.is(), "Need tolerant multi property set. "); + + bool bSuccessful = false; + + Sequence<OUString> aNames; + Sequence<Any> aValues; + + PrepareForMultiPropertySet_(rProperties, Reference<XPropertySetInfo>(nullptr), rPropMapper, pSpecialContextIds, + aNames, aValues); + + // and, finally, try to set the values + try + { + const Sequence< SetPropertyTolerantFailed > aResults(rTolMultiPropSet->setPropertyValuesTolerant( aNames, aValues )); + bSuccessful = !aResults.hasElements(); + for( const auto& rResult : aResults) + { + Sequence<OUString> aSeq { rResult.Name }; + OUString sMessage; + switch (rResult.Result) + { + case TolerantPropertySetResultType::UNKNOWN_PROPERTY : + sMessage = "UNKNOWN_PROPERTY"; + break; + case TolerantPropertySetResultType::ILLEGAL_ARGUMENT : + sMessage = "ILLEGAL_ARGUMENT"; + break; + case TolerantPropertySetResultType::PROPERTY_VETO : + sMessage = "PROPERTY_VETO"; + break; + case TolerantPropertySetResultType::WRAPPED_TARGET : + sMessage = "WRAPPED_TARGET"; + break; + } + rImport.SetError( + XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR, + aSeq, sMessage, nullptr ); + } + } + catch ( ... ) + { + OSL_ENSURE(bSuccessful, "Exception caught; style may not be imported correctly."); + } + + return bSuccessful; +} + +void SvXMLImportPropertyMapper::finished( + std::vector< XMLPropertyState >& rProperties, + sal_Int32 nStartIndex, sal_Int32 nEndIndex ) const +{ + // nothing to do here + if( mxNextMapper.is() ) + mxNextMapper->finished( rProperties, nStartIndex, nEndIndex ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlnume.cxx b/xmloff/source/style/xmlnume.cxx new file mode 100644 index 0000000000..d6ab014266 --- /dev/null +++ b/xmloff/source/style/xmlnume.cxx @@ -0,0 +1,837 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/XChapterNumberingSupplier.hpp> +#include <com/sun/star/text/PositionAndSpaceMode.hpp> +#include <com/sun/star/text/LabelFollow.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <o3tl/any.hxx> +#include <o3tl/temporary.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +#include <sax/tools/converter.hxx> + +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include "fonthdl.hxx" +#include <xmloff/XMLTextListAutoStylePool.hxx> +#include <xmloff/xmlnume.hxx> +#include <xmloff/xmlexp.hxx> +#include <tools/fontenum.hxx> +#include <vcl/vclenum.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +void SvxXMLNumRuleExport::exportLevelStyles( const uno::Reference< css::container::XIndexReplace > & xNumRule, + bool bOutline ) +{ + sal_Int32 nCount = xNumRule ->getCount(); + for( sal_Int32 i=0; i<nCount; i++ ) + { + uno::Any aEntry( xNumRule->getByIndex( i ) ); + uno::Sequence<beans::PropertyValue> aSeq; + if( aEntry >>= aSeq ) + { + exportLevelStyle( i, aSeq, bOutline ); + } + } +} + +void SvxXMLNumRuleExport::exportLevelStyle( sal_Int32 nLevel, + const uno::Sequence<beans::PropertyValue>& rProps, + bool bOutline ) +{ + sal_Int16 eType = NumberingType::CHAR_SPECIAL; + + sal_Int16 eAdjust = HoriOrientation::LEFT; + OUString sPrefix, sSuffix, sListFormat; + OUString sTextStyleName; + bool bIsLegal = false; + bool bHasColor = false; + sal_Int32 nColor = 0; + sal_Int32 nSpaceBefore = 0, nMinLabelWidth = 0, nMinLabelDist = 0; + + sal_Int16 nStartValue = 1, nDisplayLevels = 1, nBullRelSize = 0; + + sal_UCS4 cBullet = 0xf095; + OUString sBulletFontName, sBulletFontStyleName ; + FontFamily eBulletFontFamily = FAMILY_DONTKNOW; + FontPitch eBulletFontPitch = PITCH_DONTKNOW; + rtl_TextEncoding eBulletFontEncoding = RTL_TEXTENCODING_DONTKNOW; + + uno::Reference<graphic::XGraphic> xGraphic; + + sal_Int32 nImageWidth = 0, nImageHeight = 0; + sal_Int16 eImageVertOrient = VertOrientation::LINE_CENTER; + + sal_Int16 ePosAndSpaceMode = PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION; + sal_Int16 eLabelFollowedBy = LabelFollow::LISTTAB; + sal_Int32 nListtabStopPosition( 0 ); + sal_Int32 nFirstLineIndent( 0 ); + sal_Int32 nIndentAt( 0 ); + + for( const beans::PropertyValue& rProp : rProps ) + { + if( rProp.Name == "NumberingType" ) + { + rProp.Value >>= eType; + } + else if( rProp.Name == "Prefix" ) + { + rProp.Value >>= sPrefix; + } + else if( rProp.Name == "Suffix" ) + { + rProp.Value >>= sSuffix; + } + else if (rProp.Name == "ListFormat") + { + rProp.Value >>= sListFormat; + } + else if (rProp.Name == "IsLegal") + { + rProp.Value >>= bIsLegal; + } + else if (rProp.Name == "BulletChar") + { + OUString sValue; + rProp.Value >>= sValue; + if( !sValue.isEmpty() ) + { + cBullet = sValue.iterateCodePoints(&o3tl::temporary(sal_Int32(0))); + } + } + else if( rProp.Name == "BulletRelSize" ) + { + rProp.Value >>= nBullRelSize; + } + else if( rProp.Name == "Adjust" ) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + eAdjust = nValue; + } + else if( rProp.Name == "BulletFont" ) + { + awt::FontDescriptor rFDesc; + if( rProp.Value >>= rFDesc ) + { + sBulletFontName = rFDesc.Name; + sBulletFontStyleName = rFDesc.StyleName; + eBulletFontFamily = static_cast< FontFamily >( rFDesc.Family ); + eBulletFontPitch = static_cast< FontPitch >( rFDesc.Pitch ); + eBulletFontEncoding = static_cast<rtl_TextEncoding>(rFDesc.CharSet); + } + } + else if( rProp.Name == "GraphicBitmap" ) + { + uno::Reference<awt::XBitmap> xBitmap; + rProp.Value >>= xBitmap; + xGraphic.set(xBitmap, uno::UNO_QUERY); + } + else if( rProp.Name == "BulletColor" ) + { + rProp.Value >>= nColor; + bHasColor = true; + } + else if( rProp.Name == "StartWith" ) + { + rProp.Value >>= nStartValue; + } + else if( rProp.Name == "LeftMargin" ) + { + rProp.Value >>= nSpaceBefore; + } + else if( rProp.Name == "FirstLineOffset" ) + { + rProp.Value >>= nMinLabelWidth; + } + else if( rProp.Name == "SymbolTextDistance" ) + { + rProp.Value >>= nMinLabelDist; + } + else if( rProp.Name == "ParentNumbering" ) + { + rProp.Value >>= nDisplayLevels; + if( nDisplayLevels > nLevel+1 ) + nDisplayLevels = static_cast<sal_Int16>( nLevel )+1; + } + else if( rProp.Name == "CharStyleName" ) + { + rProp.Value >>= sTextStyleName; + } + else if( rProp.Name == "GraphicSize" ) + { + awt::Size aSize; + if( rProp.Value >>= aSize ) + { + nImageWidth = aSize.Width; + nImageHeight = aSize.Height; + } + } + else if( rProp.Name == "VertOrient" ) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + eImageVertOrient = nValue; + } + else if( rProp.Name == "PositionAndSpaceMode" ) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + ePosAndSpaceMode = nValue; + } + else if( rProp.Name == "LabelFollowedBy" ) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + eLabelFollowedBy = nValue; + } + else if( rProp.Name == "ListtabStopPosition" ) + { + rProp.Value >>= nListtabStopPosition; + } + else if( rProp.Name == "FirstLineIndent" ) + { + rProp.Value >>= nFirstLineIndent; + } + else if( rProp.Name == "IndentAt" ) + { + rProp.Value >>= nIndentAt; + } + } + + if( bOutline && (NumberingType::CHAR_SPECIAL == eType || + NumberingType::BITMAP == eType) ) + { + SAL_WARN_IF( bOutline, "xmloff", + "SvxXMLNumRuleExport::exportLevelStyle: invalid style for outline" ); + return; + } + + GetExport().CheckAttrList(); + + // text:level + OUStringBuffer sTmp; + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_LEVEL, OUString::number( nLevel + 1 ) ); + // #i110694#: no style-name on list-level-style-image + // #i116149#: neither prefix/suffix + if (NumberingType::BITMAP != eType) + { + if (!sTextStyleName.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sTextStyleName ) ); + } + if (bIsLegal) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_IS_LEGAL, "true"); + } + if (!sListFormat.isEmpty()) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // Write only in extended mode: in ODF 1.3 we write only prefix/suffix, + // no list format yet available. Praying we did not lost some formatting. + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_NUM_LIST_FORMAT, sListFormat); + } + } + if (!sPrefix.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NUM_PREFIX, + sPrefix ); + } + if (!sSuffix.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NUM_SUFFIX, + sSuffix ); + } + } + + enum XMLTokenEnum eElem = XML_LIST_LEVEL_STYLE_NUMBER; + if( NumberingType::CHAR_SPECIAL == eType ) + { + // <text:list-level-style-bullet> + eElem = XML_LIST_LEVEL_STYLE_BULLET; + + if( cBullet ) + { + if( cBullet < ' ' ) + { + cBullet = 0xF000 + 149; + } + // text:bullet-char="..." + sTmp.append(OUString(&cBullet, 1)); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_BULLET_CHAR, + sTmp.makeStringAndClear() ); + } + else + { + // If 'cBullet' is zero, XML_BULLET_CHAR must exist with blank. + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_BULLET_CHAR, ""); + } + } + else if( NumberingType::BITMAP == eType ) + { + // <text:list-level-style-image> + + eElem = XML_LIST_LEVEL_STYLE_IMAGE; + + if (xGraphic.is()) + { + OUString sUsedMimeType; + OUString sInternalURL = GetExport().AddEmbeddedXGraphic(xGraphic, sUsedMimeType); + if (!sInternalURL.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + } + else + { + SAL_WARN_IF(xGraphic.is(), "xmloff", "embedded images are not supported by now"); + } + } + else + { + // <text:list-level-style-number> or <text:outline-level-style> + if( bOutline ) + eElem = XML_OUTLINE_LEVEL_STYLE; + else + eElem = XML_LIST_LEVEL_STYLE_NUMBER; + + GetExport().GetMM100UnitConverter().convertNumFormat( sTmp, eType ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sTmp.makeStringAndClear() ); + SvXMLUnitConverter::convertNumLetterSync( sTmp, eType ); + if( !sTmp.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_NUM_LETTER_SYNC, + sTmp.makeStringAndClear() ); + + if( nStartValue != 1 ) + { + sTmp.append( static_cast<sal_Int32>(nStartValue) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, + sTmp.makeStringAndClear() ); + } + if( nDisplayLevels > 1 && NumberingType::NUMBER_NONE != eType ) + { + sTmp.append( static_cast<sal_Int32>(nDisplayLevels) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_DISPLAY_LEVELS, + sTmp.makeStringAndClear() ); + } + } + + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, eElem, + true, true ); + + if ( ePosAndSpaceMode == PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION ) + { + nSpaceBefore += nMinLabelWidth; + nMinLabelWidth = -nMinLabelWidth; + if( nSpaceBefore != 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nSpaceBefore ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_SPACE_BEFORE, sAttr ); + } + if( nMinLabelWidth != 0 ) + { + OUString s = GetExport().GetMM100UnitConverter().convertMeasureToXML( nMinLabelWidth ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_MIN_LABEL_WIDTH, s); + } + if( nMinLabelDist > 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nMinLabelDist ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_MIN_LABEL_DISTANCE, sAttr); + } + } + /* Check, if properties for position-and-space-mode LABEL_ALIGNMENT + are allowed to be exported. (#i89178#) + */ + else if ( ePosAndSpaceMode == PositionAndSpaceMode::LABEL_ALIGNMENT && + mbExportPositionAndSpaceModeLabelAlignment ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_LIST_LEVEL_POSITION_AND_SPACE_MODE, + XML_LABEL_ALIGNMENT ); + } + if( HoriOrientation::LEFT != eAdjust ) + { + enum XMLTokenEnum eValue = XML_TOKEN_INVALID; + switch( eAdjust ) + { + case HoriOrientation::RIGHT: eValue = XML_END; break; + case HoriOrientation::CENTER: eValue = XML_CENTER; break; + } + if( eValue != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_TEXT_ALIGN, eValue ); + } + + if( NumberingType::BITMAP == eType ) + { + enum XMLTokenEnum eValue = XML_TOKEN_INVALID; + switch( eImageVertOrient ) + { + case VertOrientation::BOTTOM: // yes, it's OK: BOTTOM means that the baseline + // hits the frame at its topmost position + case VertOrientation::LINE_TOP: + case VertOrientation::CHAR_TOP: + eValue = XML_TOP; + break; + case VertOrientation::CENTER: + case VertOrientation::LINE_CENTER: + case VertOrientation::CHAR_CENTER: + eValue = XML_MIDDLE; + break; + case VertOrientation::TOP: // yes, it's OK: TOP means that the baseline + // hits the frame at its bottommost position + case VertOrientation::LINE_BOTTOM: + case VertOrientation::CHAR_BOTTOM: + eValue = XML_BOTTOM; + break; + } + if( eValue != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_VERTICAL_POS, eValue ); + + eValue = XML_TOKEN_INVALID; + switch( eImageVertOrient ) + { + case VertOrientation::TOP: + case VertOrientation::CENTER: + case VertOrientation::BOTTOM: + eValue = XML_BASELINE; + break; + case VertOrientation::LINE_TOP: + case VertOrientation::LINE_CENTER: + case VertOrientation::LINE_BOTTOM: + eValue = XML_LINE; + break; + case VertOrientation::CHAR_TOP: + case VertOrientation::CHAR_CENTER: + case VertOrientation::CHAR_BOTTOM: + eValue = XML_CHAR; + break; + } + if( eValue != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_VERTICAL_REL, eValue ); + + if( nImageWidth > 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nImageWidth ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_WIDTH, sAttr ); + } + + if( nImageHeight > 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nImageHeight ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_HEIGHT, sAttr ); + } + } + + { + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, + XML_LIST_LEVEL_PROPERTIES, true, true ); + + /* Check, if properties for position-and-space-mode LABEL_ALIGNMENT + are allowed to be exported. (#i89178#) + */ + if ( ePosAndSpaceMode == PositionAndSpaceMode::LABEL_ALIGNMENT && + mbExportPositionAndSpaceModeLabelAlignment ) + { + enum XMLTokenEnum eValue = XML_LISTTAB; + if ( eLabelFollowedBy == LabelFollow::SPACE ) + { + eValue = XML_SPACE; + } + else if ( eLabelFollowedBy == LabelFollow::NOTHING ) + { + eValue = XML_NOTHING; + } + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_LABEL_FOLLOWED_BY, eValue ); + + if (eLabelFollowedBy == LabelFollow::NEWLINE) + { + eValue = XML_NEWLINE; + GetExport().AddAttribute( XML_NAMESPACE_LO_EXT, + XML_LABEL_FOLLOWED_BY, eValue ); + } + + if ( eLabelFollowedBy == LabelFollow::LISTTAB && + nListtabStopPosition > 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nListtabStopPosition ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_LIST_TAB_STOP_POSITION, + sAttr ); + } + + if ( nFirstLineIndent != 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nFirstLineIndent ); + GetExport().AddAttribute( XML_NAMESPACE_FO, + XML_TEXT_INDENT, + sAttr ); + } + + if ( nIndentAt != 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nIndentAt ); + GetExport().AddAttribute( XML_NAMESPACE_FO, + XML_MARGIN_LEFT, + sAttr ); + } + + SvXMLElementExport aLabelAlignmentElement( GetExport(), XML_NAMESPACE_STYLE, + XML_LIST_LEVEL_LABEL_ALIGNMENT, + true, true ); + } + } + + if( NumberingType::CHAR_SPECIAL == eType ) + { + if( !sBulletFontName.isEmpty() ) + { + OUString sStyleName = + GetExport().GetFontAutoStylePool()->Find( + sBulletFontName, sBulletFontStyleName, + eBulletFontFamily, eBulletFontPitch, + eBulletFontEncoding ); + + if( !sStyleName.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_NAME, + sStyleName ); + } + else + { + OUString sTemp; + + const SvXMLUnitConverter& rUnitConv = + GetExport().GetMM100UnitConverter(); + XMLFontFamilyNamePropHdl aFamilyNameHdl; + if( aFamilyNameHdl.exportXML( sTemp, Any(sBulletFontName), rUnitConv ) ) + GetExport().AddAttribute( XML_NAMESPACE_FO, + XML_FONT_FAMILY, sTemp ); + + if( !sBulletFontStyleName.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_STYLE_NAME, + sBulletFontStyleName ); + + XMLFontFamilyPropHdl aFamilyHdl; + if( aFamilyHdl.exportXML( sTemp, Any(static_cast<sal_Int16>(eBulletFontFamily)), rUnitConv ) ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_FAMILY_GENERIC, + sTemp ); + + XMLFontPitchPropHdl aPitchHdl; + if( aPitchHdl.exportXML( sTemp, Any(static_cast<sal_Int16>(eBulletFontPitch)), rUnitConv ) ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_PITCH, sTemp ); + + XMLFontEncodingPropHdl aEncHdl; + if( aEncHdl.exportXML( sTemp, Any(static_cast<sal_Int16>(eBulletFontEncoding)), rUnitConv ) ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_CHARSET, sTemp ); + } + } + } + if( NumberingType::BITMAP != eType ) + { + // fo:color = "#..." + if( bHasColor ) + { + if (0xffffffff == static_cast<sal_uInt32>(nColor)) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_USE_WINDOW_FONT_COLOR, XML_TRUE ); + } + else + { + OUStringBuffer sBuffer; + ::sax::Converter::convertColor( sBuffer, nColor ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_COLOR, + sBuffer.makeStringAndClear() ); + } + } + // fo:height="...%" + if( nBullRelSize ) + { + ::sax::Converter::convertPercent( sTmp, nBullRelSize ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_FONT_SIZE, + sTmp.makeStringAndClear() ); + } + } + if( GetExport().GetAttrList().getLength() > 0 ) + { + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, + XML_TEXT_PROPERTIES, true, true ); + } + if (xGraphic.is() && NumberingType::BITMAP == eType) + { + // optional office:binary-data + GetExport().AddEmbeddedXGraphicAsBase64(xGraphic); + } + } +} + + +constexpr OUStringLiteral gsNumberingRules( u"NumberingRules" ); +constexpr OUString gsIsPhysical( u"IsPhysical"_ustr ); +constexpr OUString gsIsContinuousNumbering( u"IsContinuousNumbering"_ustr ); + +SvxXMLNumRuleExport::SvxXMLNumRuleExport( SvXMLExport& rExp ) : + m_rExport( rExp ), + // Let list style creation depend on Load/Save option "ODF format version" (#i89178#) + mbExportPositionAndSpaceModeLabelAlignment( true ) +{ + switch (GetExport().getSaneDefaultVersion()) + { + case SvtSaveOptions::ODFSVER_010: + case SvtSaveOptions::ODFSVER_011: + { + mbExportPositionAndSpaceModeLabelAlignment = false; + } + break; + default: // >= ODFSVER_012 + { + mbExportPositionAndSpaceModeLabelAlignment = true; + } + } +} + +void SvxXMLNumRuleExport::exportNumberingRule( + const OUString& rName, bool bIsHidden, + const Reference< XIndexReplace >& rNumRule ) +{ + Reference< XPropertySet > xPropSet( rNumRule, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo; + if( xPropSet.is() ) + xPropSetInfo = xPropSet->getPropertySetInfo(); + + GetExport().CheckAttrList(); + + // style:name="..." + if( !rName.isEmpty() ) + { + bool bEncoded = false; + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, + GetExport().EncodeStyleName( rName, &bEncoded ) ); + if( bEncoded ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, + rName); + } + + // style:hidden="..." + if (bIsHidden + && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDDEN, "true"); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility + } + + // text:consecutive-numbering="..." + bool bContNumbering = false; + if( xPropSetInfo.is() && + xPropSetInfo->hasPropertyByName( gsIsContinuousNumbering ) ) + { + Any aAny( xPropSet->getPropertyValue( gsIsContinuousNumbering ) ); + bContNumbering = *o3tl::doAccess<bool>(aAny); + } + if( bContNumbering ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_CONSECUTIVE_NUMBERING, XML_TRUE ); + + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, XML_LIST_STYLE , + true, true ); + exportLevelStyles( rNumRule ); + } +} + +void SvxXMLNumRuleExport::exportStyle( const Reference< XStyle >& rStyle ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + Any aAny; + + // Don't export styles that aren't existing really. This may be the + // case for StarOffice Writer's pool styles. + if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) ) + { + aAny = xPropSet->getPropertyValue( gsIsPhysical ); + if( !*o3tl::doAccess<bool>(aAny) ) + return; + } + + aAny = xPropSet->getPropertyValue( gsNumberingRules ); + Reference<XIndexReplace> xNumRule; + aAny >>= xNumRule; + + OUString sName = rStyle->getName(); + + bool bHidden = false; + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + aAny = xPropSet->getPropertyValue( "Hidden" ); + aAny >>= bHidden; + } + + exportNumberingRule( sName, bHidden, xNumRule ); +} + +void SvxXMLNumRuleExport::exportOutline() +{ + Reference< XChapterNumberingSupplier > xCNSupplier( GetExport().GetModel(), + UNO_QUERY ); + SAL_WARN_IF( !xCNSupplier.is(), "xmloff", "no chapter numbering supplier" ); + + if( !xCNSupplier.is() ) + return; + + Reference< XIndexReplace > xNumRule( xCNSupplier->getChapterNumberingRules() ); + SAL_WARN_IF( !xNumRule.is(), "xmloff", "no chapter numbering rules" ); + + if( !xNumRule.is() ) + return; + + /* Outline style has property style:name since ODF 1.2 + Thus, export this property and adjust fix for issue #i69627# (#i90780#) + */ + OUString sOutlineStyleName; + { + Reference<XPropertySet> xNumRulePropSet( + xCNSupplier->getChapterNumberingRules(), UNO_QUERY ); + if (xNumRulePropSet.is()) + { + xNumRulePropSet->getPropertyValue( "Name" ) >>= sOutlineStyleName; + } + } + const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion = + GetExport().getSaneDefaultVersion(); + if ((nODFVersion == SvtSaveOptions::ODFSVER_010 || + nODFVersion == SvtSaveOptions::ODFSVER_011) + && GetExport().writeOutlineStyleAsNormalListStyle()) + { + exportNumberingRule( sOutlineStyleName, false, xNumRule ); + } + else + { + if (nODFVersion != SvtSaveOptions::ODFSVER_010 && + nODFVersion != SvtSaveOptions::ODFSVER_011) + { + // style:name="..." + GetExport().CheckAttrList(); + if ( !sOutlineStyleName.isEmpty() ) + { + bool bEncoded = false; + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, + GetExport().EncodeStyleName( sOutlineStyleName, + &bEncoded ) ); + if( bEncoded ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY_NAME, + sOutlineStyleName ); + } + } + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_OUTLINE_STYLE, true, true ); + exportLevelStyles( xNumRule, true ); + } +} + +void SvxXMLNumRuleExport::exportStyles( bool bUsed, bool bExportChapterNumbering ) +{ + if( bExportChapterNumbering ) + exportOutline(); + + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), UNO_QUERY ); + SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", "No XStyleFamiliesSupplier from XModel for export!" ); + if( !xFamiliesSupp.is() ) + return; + + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", "getStyleFamilies() from XModel failed for export!" ); + + if( !xFamilies.is() ) + return; + + static constexpr OUString aNumberStyleName( u"NumberingStyles"_ustr ); + + Reference< XIndexAccess > xStyles; + if( !xFamilies->hasByName( aNumberStyleName ) ) + return; + + xFamilies->getByName( aNumberStyleName ) >>= xStyles; + + SAL_WARN_IF( !xStyles.is(), "xmloff", "Style not found for export!" ); + + if( !xStyles.is() ) + return; + + const sal_Int32 nStyles = xStyles->getCount(); + + for( sal_Int32 i=0; i < nStyles; i++ ) + { + Reference< XStyle > xStyle; + xStyles->getByIndex( i ) >>= xStyle; + + if( !bUsed || xStyle->isInUse() ) + exportStyle( xStyle ); + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx new file mode 100644 index 0000000000..406c22236a --- /dev/null +++ b/xmloff/source/style/xmlnumfe.cxx @@ -0,0 +1,2138 @@ +/* -*- 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 <comphelper/sequence.hxx> +#include <comphelper/string.hxx> +#include <svl/numformat.hxx> +#include <svl/zforlist.hxx> +#include <svl/zformat.hxx> +#include <svl/numuno.hxx> +#include <i18nlangtag/mslangid.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <tools/debug.hxx> +#include <rtl/math.hxx> +#include <unotools/calendarwrapper.hxx> +#include <unotools/charclass.hxx> +#include <com/sun/star/lang/Locale.hpp> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <tools/color.hxx> +#include <sax/tools/converter.hxx> + +#include <com/sun/star/i18n/NativeNumberXmlAttributes2.hpp> + +#include <utility> +#include <xmloff/xmlnumfe.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlnumfi.hxx> + +#include <svl/nfsymbol.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlexp.hxx> +#include <o3tl/string_view.hxx> + +#include <float.h> +#include <set> +#include <string_view> +#include <vector> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::svt; + +typedef std::set< sal_uInt32 > SvXMLuInt32Set; + +namespace { + +struct SvXMLEmbeddedTextEntry +{ + sal_uInt16 nSourcePos; // position in NumberFormat (to skip later) + sal_Int32 nFormatPos; // resulting position in embedded-text element + OUString aText; + bool isBlankWidth; // "_x" + + SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, OUString aT, bool bBW = false ) : + nSourcePos(nSP), nFormatPos(nFP), aText(std::move(aT)), isBlankWidth( bBW ) {} +}; + +} + +class SvXMLEmbeddedTextEntryArr +{ + typedef std::vector<SvXMLEmbeddedTextEntry> DataType; + DataType maData; + +public: + + void push_back( SvXMLEmbeddedTextEntry const& r ) + { + maData.push_back(r); + } + + const SvXMLEmbeddedTextEntry& operator[] ( size_t i ) const + { + return maData[i]; + } + + size_t size() const + { + return maData.size(); + } +}; + +class SvXMLNumUsedList_Impl +{ + SvXMLuInt32Set aUsed; + SvXMLuInt32Set aWasUsed; + SvXMLuInt32Set::iterator aCurrentUsedPos; + sal_uInt32 nUsedCount; + sal_uInt32 nWasUsedCount; + +public: + SvXMLNumUsedList_Impl(); + + void SetUsed( sal_uInt32 nKey ); + bool IsUsed( sal_uInt32 nKey ) const; + bool IsWasUsed( sal_uInt32 nKey ) const; + void Export(); + + bool GetFirstUsed(sal_uInt32& nKey); + bool GetNextUsed(sal_uInt32& nKey); + + uno::Sequence<sal_Int32> GetWasUsed() const; + void SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed); +}; + +//! SvXMLNumUsedList_Impl should be optimized! + +SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() : + nUsedCount(0), + nWasUsedCount(0) +{ +} + +void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey ) +{ + if ( !IsWasUsed(nKey) ) + { + std::pair<SvXMLuInt32Set::iterator, bool> aPair = aUsed.insert( nKey ); + if (aPair.second) + nUsedCount++; + } +} + +bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const +{ + SvXMLuInt32Set::const_iterator aItr = aUsed.find(nKey); + return (aItr != aUsed.end()); +} + +bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const +{ + SvXMLuInt32Set::const_iterator aItr = aWasUsed.find(nKey); + return (aItr != aWasUsed.end()); +} + +void SvXMLNumUsedList_Impl::Export() +{ + SvXMLuInt32Set::const_iterator aItr = aUsed.begin(); + while (aItr != aUsed.end()) + { + std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( *aItr ); + if (aPair.second) + nWasUsedCount++; + ++aItr; + } + aUsed.clear(); + nUsedCount = 0; +} + +bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32& nKey) +{ + bool bRet(false); + aCurrentUsedPos = aUsed.begin(); + if(nUsedCount) + { + DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong"); + nKey = *aCurrentUsedPos; + bRet = true; + } + return bRet; +} + +bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32& nKey) +{ + bool bRet(false); + if (aCurrentUsedPos != aUsed.end()) + { + ++aCurrentUsedPos; + if (aCurrentUsedPos != aUsed.end()) + { + nKey = *aCurrentUsedPos; + bRet = true; + } + } + return bRet; +} + +uno::Sequence<sal_Int32> SvXMLNumUsedList_Impl::GetWasUsed() const +{ + return comphelper::containerToSequence<sal_Int32>(aWasUsed); +} + +void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed) +{ + DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty"); + for (const auto nWasUsed : rWasUsed) + { + std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( nWasUsed ); + if (aPair.second) + nWasUsedCount++; + } +} + +SvXMLNumFmtExport::SvXMLNumFmtExport( + SvXMLExport& rExp, + const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) : + m_rExport( rExp ), + m_sPrefix( OUString("N") ), + m_pFormatter( nullptr ), + m_bHasText( false ) +{ + // supplier must be SvNumberFormatsSupplierObj + SvNumberFormatsSupplierObj* pObj = + comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp ); + if (pObj) + m_pFormatter = pObj->GetNumberFormatter(); + + if ( m_pFormatter ) + { + m_pLocaleData.reset( new LocaleDataWrapper( m_pFormatter->GetComponentContext(), + m_pFormatter->GetLanguageTag() ) ); + } + else + { + LanguageTag aLanguageTag( MsLangId::getConfiguredSystemLanguage() ); + + m_pLocaleData.reset( new LocaleDataWrapper( m_rExport.getComponentContext(), std::move(aLanguageTag) ) ); + } + + m_pUsedList.reset(new SvXMLNumUsedList_Impl); +} + +SvXMLNumFmtExport::SvXMLNumFmtExport( + SvXMLExport& rExp, + const css::uno::Reference< css::util::XNumberFormatsSupplier >& rSupp, + OUString aPrefix ) : + m_rExport( rExp ), + m_sPrefix(std::move( aPrefix )), + m_pFormatter( nullptr ), + m_bHasText( false ) +{ + // supplier must be SvNumberFormatsSupplierObj + SvNumberFormatsSupplierObj* pObj = + comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp ); + if (pObj) + m_pFormatter = pObj->GetNumberFormatter(); + + if ( m_pFormatter ) + { + m_pLocaleData.reset( new LocaleDataWrapper( m_pFormatter->GetComponentContext(), + m_pFormatter->GetLanguageTag() ) ); + } + else + { + LanguageTag aLanguageTag( MsLangId::getConfiguredSystemLanguage() ); + + m_pLocaleData.reset( new LocaleDataWrapper( m_rExport.getComponentContext(), std::move(aLanguageTag) ) ); + } + + m_pUsedList.reset(new SvXMLNumUsedList_Impl); +} + +SvXMLNumFmtExport::~SvXMLNumFmtExport() +{ +} + +// helper methods + +static OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, bool bDefPart, std::u16string_view rPrefix ) +{ + if (bDefPart) + return rPrefix + OUString::number(nKey); + else + return rPrefix + OUString::number(nKey) + "P" + OUString::number( nPart ); +} + +void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar ) +{ + if ( !rCalendar.isEmpty() ) + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_CALENDAR, rCalendar ); + } +} + +void SvXMLNumFmtExport::AddStyleAttr_Impl( bool bLong ) +{ + if ( bLong ) // short is default + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG ); + } +} + +void SvXMLNumFmtExport::AddLanguageAttr_Impl( LanguageType nLang ) +{ + if ( nLang != LANGUAGE_SYSTEM ) + { + m_rExport.AddLanguageTagAttributes( XML_NAMESPACE_NUMBER, XML_NAMESPACE_NUMBER, + LanguageTag( nLang), false); + } +} + +// methods to write individual elements within a format + +void SvXMLNumFmtExport::AddToTextElement_Impl( std::u16string_view rString ) +{ + // append to sTextContent, write element in FinishTextElement_Impl + // to avoid several text elements following each other + + m_sTextContent.append( rString ); + // Also empty string leads to a number:text element as it may separate + // keywords of the same letter (e.g. MM""MMM) that otherwise would be + // concatenated when reading back in. + m_bHasText = true; +} + +void SvXMLNumFmtExport::FinishTextElement_Impl(bool bUseExtensionNS) +{ + if ( m_bHasText ) + { + if ( !m_sBlankWidthString.isEmpty() ) + { + // Export only for 1.3 with extensions and later. + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + if (eVersion > SvtSaveOptions::ODFSVER_013 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 )) + { + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_BLANK_WIDTH_CHAR, + m_sBlankWidthString.makeStringAndClear() ); + } + } + sal_uInt16 nNS = bUseExtensionNS ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER; + SvXMLElementExport aElem( m_rExport, nNS, XML_TEXT, + true, false ); + m_rExport.Characters( m_sTextContent.makeStringAndClear() ); + m_bHasText = false; + } +} + +void SvXMLNumFmtExport::WriteColorElement_Impl( const Color& rColor ) +{ + FinishTextElement_Impl(); + + OUStringBuffer aColStr( 7 ); + ::sax::Converter::convertColor( aColStr, rColor ); + m_rExport.AddAttribute( XML_NAMESPACE_FO, XML_COLOR, + aColStr.makeStringAndClear() ); + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES, + true, false ); +} + +void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString& rString, + std::u16string_view rExt ) +{ + FinishTextElement_Impl(); + + if ( !rExt.empty() ) + { + // rExt should be a 16-bit hex value max FFFF which may contain a + // leading "-" separator (that is not a minus sign, but toInt32 can be + // used to parse it, with post-processing as necessary): + sal_Int32 nLang = o3tl::toInt32(rExt, 16); + if ( nLang < 0 ) + nLang = -nLang; + SAL_WARN_IF(nLang > 0xFFFF, "xmloff.style", "Out of range Lang Id: " << nLang << " from input string: " << OUString(rExt)); + AddLanguageAttr_Impl( LanguageType(nLang & 0xFFFF) ); // adds to pAttrList + } + + SvXMLElementExport aElem( m_rExport, + XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL, + true, false ); + m_rExport.Characters( rString ); +} + +void SvXMLNumFmtExport::WriteBooleanElement_Impl() +{ + FinishTextElement_Impl(); + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_BOOLEAN, + true, false ); +} + +void SvXMLNumFmtExport::WriteTextContentElement_Impl() +{ + FinishTextElement_Impl(); + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT, + true, false ); +} + +// date elements + +void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_DAY, + true, false ); +} + +void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, bool bLong, bool bText ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + if ( bText ) + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE ); + } + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_MONTH, + true, false ); +} + +void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_YEAR, + true, false ); +} + +void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_ERA, + true, false ); +} + +void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK, + true, false ); +} + +void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR, + true, false ); +} + +void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_QUARTER, + true, false ); +} + +// time elements + +void SvXMLNumFmtExport::WriteHoursElement_Impl( bool bLong ) +{ + FinishTextElement_Impl(); + + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_HOURS, + true, false ); +} + +void SvXMLNumFmtExport::WriteMinutesElement_Impl( bool bLong ) +{ + FinishTextElement_Impl(); + + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_MINUTES, + true, false ); +} + +void SvXMLNumFmtExport::WriteRepeatedElement_Impl( sal_Unicode nChar ) +{ + // Export only for 1.2 with extensions or 1.3 and later. + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + FinishTextElement_Impl(eVersion < SvtSaveOptions::ODFSVER_013); + // OFFICE-3765 For 1.2+ use loext namespace, for 1.3 use number namespace. + SvXMLElementExport aElem( m_rExport, + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_FILL_CHARACTER, true, false ); + m_rExport.Characters( OUString( nChar ) ); + } +} + +namespace { +void lcl_WriteBlankWidthString( std::u16string_view rBlankWidthChar, OUStringBuffer& rBlankWidthString, OUStringBuffer& rTextContent ) +{ + // export "_x" + if ( rBlankWidthString.isEmpty() ) + { + rBlankWidthString.append( rBlankWidthChar ); + if ( !rTextContent.isEmpty() ) + { + // add position in rTextContent + rBlankWidthString.append( rTextContent.getLength() ); + } + } + else + { + // add "_" as separator if there are several blank width char + rBlankWidthString.append( "_" ); + rBlankWidthString.append( rBlankWidthChar ); + rBlankWidthString.append( rTextContent.getLength() ); + } + // for previous versions, turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat + if ( !rBlankWidthChar.empty() ) + { + OUString aBlanks; + SvNumberformat::InsertBlanks( aBlanks, 0, rBlankWidthChar[0] ); + rTextContent.append( aBlanks ); + } +} +} + +void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong, sal_uInt16 nDecimals ) +{ + FinishTextElement_Impl(); + + AddStyleAttr_Impl( bLong ); // adds to pAttrList + if ( nDecimals > 0 ) + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, + OUString::number( nDecimals ) ); + } + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_SECONDS, + true, false ); +} + +void SvXMLNumFmtExport::WriteAMPMElement_Impl() +{ + FinishTextElement_Impl(); + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_AM_PM, + true, false ); +} + +// numbers + +void SvXMLNumFmtExport::WriteIntegerElement_Impl( + sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping ) +{ + // integer digits: '0' and '?' + if ( nInteger >= 0 ) // negative = automatic + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, + OUString::number( nInteger ) ); + } + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + // blank integer digits: '?' + if ( nBlankInteger > 0 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 ) ) + { + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_MAX_BLANK_INTEGER_DIGITS, + OUString::number( nBlankInteger ) ); + } + // (automatic) grouping separator + if ( bGrouping ) + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); + } +} + +void SvXMLNumFmtExport::WriteEmbeddedEntries_Impl( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ) +{ + auto nEntryCount = rEmbeddedEntries.size(); + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + for (decltype(nEntryCount) nEntry=0; nEntry < nEntryCount; ++nEntry) + { + const SvXMLEmbeddedTextEntry* pObj = &rEmbeddedEntries[nEntry]; + + // position attribute + // position == 0 is between first integer digit and decimal separator + // position < 0 is inside decimal part + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION, + OUString::number( pObj->nFormatPos ) ); + + // text as element content + OUStringBuffer aContent; + OUStringBuffer aBlankWidthString; + do + { + pObj = &rEmbeddedEntries[nEntry]; + if ( pObj->isBlankWidth ) + { + // (#i20396# the spaces may also be in embedded-text elements) + lcl_WriteBlankWidthString( pObj->aText, aBlankWidthString, aContent ); + } + else + { + // The array can contain several elements for the same position in the number. + // Literal texts are merged into a single embedded-text element. + aContent.append( pObj->aText ); + } + ++nEntry; + } + while ( nEntry < nEntryCount + && rEmbeddedEntries[nEntry].nFormatPos == pObj->nFormatPos ); + --nEntry; + + // Export only for 1.3 with extensions and later. + if ( !aBlankWidthString.isEmpty() && eVersion > SvtSaveOptions::ODFSVER_013 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 ) ) + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_BLANK_WIDTH_CHAR, aBlankWidthString.makeStringAndClear() ); + SvXMLElementExport aChildElem( m_rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT, + true, false ); + m_rExport.Characters( aContent.makeStringAndClear() ); + } +} + +void SvXMLNumFmtExport::WriteNumberElement_Impl( + sal_Int32 nDecimals, sal_Int32 nMinDecimals, + sal_Int32 nInteger, sal_Int32 nBlankInteger, const OUString& rDashStr, + bool bGrouping, sal_Int32 nTrailingThousands, + const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ) +{ + FinishTextElement_Impl(); + + // decimals + if ( nDecimals >= 0 ) // negative = automatic + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, + OUString::number( nDecimals ) ); + } + + if ( nMinDecimals >= 0 ) // negative = automatic + { + // Export only for 1.2 with extensions or 1.3 and later. + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace. + m_rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_MIN_DECIMAL_PLACES, + OUString::number( nMinDecimals ) ); + } + } + // decimal replacement (dashes) or variable decimals (#) + if ( !rDashStr.isEmpty() || nMinDecimals < nDecimals ) + { + // full variable decimals means an empty replacement string + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT, + rDashStr ); + } + + WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping ); + + // display-factor if there are trailing thousands separators + if ( nTrailingThousands ) + { + // each separator character removes three digits + double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands ); + + OUStringBuffer aFactStr; + ::sax::Converter::convertDouble( aFactStr, fFactor ); + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() ); + } + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_NUMBER, + true, true ); + + // number:embedded-text as child elements + WriteEmbeddedEntries_Impl( rEmbeddedEntries ); +} + +void SvXMLNumFmtExport::WriteScientificElement_Impl( + sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, sal_Int32 nBlankInteger, + bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign, bool bExponentLowercase, sal_Int32 nBlankExp, + const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ) +{ + FinishTextElement_Impl(); + + // decimals + if ( nDecimals >= 0 ) // negative = automatic + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, + OUString::number( nDecimals ) ); + } + + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + if ( nMinDecimals >= 0 ) // negative = automatic + { + // Export only for 1.2 with extensions or 1.3 and later. + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace. + m_rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_MIN_DECIMAL_PLACES, + OUString::number( nMinDecimals ) ); + } + } + + WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping ); + + // exponent digits + if ( nExp >= 0 ) + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS, + OUString::number( nExp ) ); + } + + // exponent interval for engineering notation + if ( nExpInterval >= 0 ) + { + // Export only for 1.2 with extensions or 1.3 and later. + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-1828 For 1.2+ use loext namespace, for 1.3 use number namespace. + m_rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_EXPONENT_INTERVAL, OUString::number( nExpInterval ) ); + } + } + + // exponent sign + // Export only for 1.2 with extensions or 1.3 and later. + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace. + m_rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_FORCED_EXPONENT_SIGN, + bExpSign? XML_TRUE : XML_FALSE ); + } + // exponent string + // Export only for 1.x with extensions + if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + if (bExponentLowercase) + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_EXPONENT_LOWERCASE, XML_TRUE ); + if (nBlankExp > 0) + { + if (nBlankExp >= nExp) + nBlankExp = nExp - 1; // preserve at least one '0' in exponent + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_BLANK_EXPONENT_DIGITS, OUString::number( nBlankExp ) ); + } + } + + SvXMLElementExport aElem( m_rExport, + XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER, + true, false ); + + // number:embedded-text as child elements + // Export only for 1.x with extensions + if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) + WriteEmbeddedEntries_Impl( rEmbeddedEntries ); +} + +void SvXMLNumFmtExport::WriteFractionElement_Impl( + sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping, + const SvNumberformat& rFormat, sal_uInt16 nPart ) +{ + FinishTextElement_Impl(); + WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping ); + + const OUString aNumeratorString = rFormat.GetNumeratorString( nPart ); + const OUString aDenominatorString = rFormat.GetDenominatorString( nPart ); + const OUString aIntegerFractionDelimiterString = rFormat.GetIntegerFractionDelimiterString( nPart ); + sal_Int32 nMaxNumeratorDigits = aNumeratorString.getLength(); + // Count '0' as '?' + sal_Int32 nMinNumeratorDigits = aNumeratorString.replaceAll("0","?").indexOf('?'); + sal_Int32 nZerosNumeratorDigits = aNumeratorString.indexOf('0'); + if ( nMinNumeratorDigits >= 0 ) + nMinNumeratorDigits = nMaxNumeratorDigits - nMinNumeratorDigits; + else + nMinNumeratorDigits = 0; + if ( nZerosNumeratorDigits >= 0 ) + nZerosNumeratorDigits = nMaxNumeratorDigits - nZerosNumeratorDigits; + else + nZerosNumeratorDigits = 0; + sal_Int32 nMaxDenominatorDigits = aDenominatorString.getLength(); + sal_Int32 nMinDenominatorDigits = aDenominatorString.replaceAll("0","?").indexOf('?'); + sal_Int32 nZerosDenominatorDigits = aDenominatorString.indexOf('0'); + if ( nMinDenominatorDigits >= 0 ) + nMinDenominatorDigits = nMaxDenominatorDigits - nMinDenominatorDigits; + else + nMinDenominatorDigits = 0; + if ( nZerosDenominatorDigits >= 0 ) + nZerosDenominatorDigits = nMaxDenominatorDigits - nZerosDenominatorDigits; + else + nZerosDenominatorDigits = 0; + sal_Int32 nDenominator = aDenominatorString.toInt32(); + + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + + // integer/fraction delimiter + if ( !aIntegerFractionDelimiterString.isEmpty() && aIntegerFractionDelimiterString != " " + && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) ) + { // Export only for 1.2/1.3 with extensions. + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_INTEGER_FRACTION_DELIMITER, + aIntegerFractionDelimiterString ); + } + + // numerator digits + if ( nMinNumeratorDigits == 0 ) // at least one digit to keep compatibility with previous versions + nMinNumeratorDigits++; + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, + OUString::number( nMinNumeratorDigits ) ); + // Export only for 1.2/1.3 with extensions. + if ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) + { + // For extended ODF use loext namespace + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_MAX_NUMERATOR_DIGITS, + OUString::number( nMaxNumeratorDigits ) ); + } + if ( nZerosNumeratorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) ) + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_ZEROS_NUMERATOR_DIGITS, + OUString::number( nZerosNumeratorDigits ) ); + + if ( nDenominator ) + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DENOMINATOR_VALUE, + OUString::number( nDenominator) ); + } + // it's not necessary to export nDenominatorDigits + // if we have a forced denominator + else + { + if ( nMinDenominatorDigits == 0 ) // at least one digit to keep compatibility with previous versions + nMinDenominatorDigits++; + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, + OUString::number( nMinDenominatorDigits ) ); + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-3695 For 1.2+ use loext namespace, for 1.3 use number namespace. + m_rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_MAX_DENOMINATOR_VALUE, + OUString::number( pow ( 10.0, nMaxDenominatorDigits ) - 1 ) ); // 9, 99 or 999 + } + if ( nZerosDenominatorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) ) + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_ZEROS_DENOMINATOR_DIGITS, + OUString::number( nZerosDenominatorDigits ) ); + } + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, XML_FRACTION, + true, false ); +} + +// mapping (condition) + +void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit, + sal_Int32 nKey, sal_Int32 nPart ) +{ + FinishTextElement_Impl(); + + if ( nOp == NUMBERFORMAT_OP_NO ) + return; + + // style namespace + + OUStringBuffer aCondStr(20); + aCondStr.append( "value()" ); //! define constant + switch ( nOp ) + { + case NUMBERFORMAT_OP_EQ: aCondStr.append( '=' ); break; + case NUMBERFORMAT_OP_NE: aCondStr.append( "!=" ); break; + case NUMBERFORMAT_OP_LT: aCondStr.append( '<' ); break; + case NUMBERFORMAT_OP_LE: aCondStr.append( "<=" ); break; + case NUMBERFORMAT_OP_GT: aCondStr.append( '>' ); break; + case NUMBERFORMAT_OP_GE: aCondStr.append( ">=" ); break; + default: + OSL_FAIL("unknown operator"); + } + ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit, + rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, + '.', true ); + + m_rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CONDITION, + aCondStr.makeStringAndClear() ); + + m_rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME, + m_rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, false, + m_sPrefix ) ) ); + + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_STYLE, XML_MAP, + true, false ); +} + +// for old (automatic) currency formats: parse currency symbol from text + +static sal_Int32 lcl_FindSymbol( const OUString& sUpperStr, std::u16string_view sCurString ) +{ + // search for currency symbol + // Quoting as in ImpSvNumberformatScan::Symbol_Division + + sal_Int32 nCPos = 0; + while (nCPos >= 0) + { + nCPos = sUpperStr.indexOf( sCurString, nCPos ); + if (nCPos >= 0) + { + // in Quotes? + sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos ); + if ( nQ < 0 ) + { + // dm can be escaped as "dm or \d + sal_Unicode c; + if ( nCPos == 0 ) + return nCPos; // found + c = sUpperStr[nCPos-1]; + if ( c != '"' && c != '\\') + { + return nCPos; // found + } + else + { + nCPos++; // continue + } + } + else + { + nCPos = nQ + 1; // continue after quote end + } + } + } + return -1; +} + +bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString, + const css::lang::Locale& rLocale ) +{ + // returns true if currency element was written + + bool bRet = false; + + LanguageTag aLanguageTag( rLocale ); + m_pFormatter->ChangeIntl( aLanguageTag.getLanguageType( false) ); + OUString sCurString, sDummy; + m_pFormatter->GetCompatibilityCurrency( sCurString, sDummy ); + + OUString sUpperStr = m_pFormatter->GetCharClass()->uppercase(rString); + sal_Int32 nPos = lcl_FindSymbol( sUpperStr, sCurString ); + if ( nPos >= 0 ) + { + sal_Int32 nLength = rString.getLength(); + sal_Int32 nCurLen = sCurString.getLength(); + sal_Int32 nCont = nPos + nCurLen; + + // text before currency symbol + if ( nPos > 0 ) + { + AddToTextElement_Impl( rString.subView( 0, nPos ) ); + } + // currency symbol (empty string -> default) + WriteCurrencyElement_Impl( "", u"" ); + bRet = true; + + // text after currency symbol + if ( nCont < nLength ) + { + AddToTextElement_Impl( rString.subView( nCont, nLength-nCont ) ); + } + } + else + { + AddToTextElement_Impl( rString ); // simple text + } + + return bRet; // true: currency element written +} + +static OUString lcl_GetDefaultCalendar( SvNumberFormatter const * pFormatter, LanguageType nLang ) +{ + // get name of first non-gregorian calendar for the language + + OUString aCalendar; + CalendarWrapper* pCalendar = pFormatter->GetCalendar(); + if (pCalendar) + { + lang::Locale aLocale( LanguageTag::convertToLocale( nLang ) ); + + const uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale ); + auto pCal = std::find_if(aCals.begin(), aCals.end(), + [](const OUString& rCal) { return rCal != "gregorian"; }); + if (pCal != aCals.end()) + aCalendar = *pCal; + } + return aCalendar; +} + +static bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos ) +{ + auto nCount = rEmbeddedEntries.size(); + for (decltype(nCount) i=0; i<nCount; i++) + if ( rEmbeddedEntries[i].nSourcePos == nPos ) + return true; + + return false; // not found +} + +static bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, bool bSystemDate, NfIndexTableOffset eBuiltIn ) +{ + // make an extra loop to collect date elements, to check if it is a default format + // before adding the automatic-order attribute + + SvXMLDateElementAttributes eDateDOW = XML_DEA_NONE; + SvXMLDateElementAttributes eDateDay = XML_DEA_NONE; + SvXMLDateElementAttributes eDateMonth = XML_DEA_NONE; + SvXMLDateElementAttributes eDateYear = XML_DEA_NONE; + SvXMLDateElementAttributes eDateHours = XML_DEA_NONE; + SvXMLDateElementAttributes eDateMins = XML_DEA_NONE; + SvXMLDateElementAttributes eDateSecs = XML_DEA_NONE; + bool bDateNoDefault = false; + + sal_uInt16 nPos = 0; + bool bEnd = false; + short nLastType = 0; + while (!bEnd) + { + short nElemType = rFormat.GetNumForType( 0, nPos ); + switch ( nElemType ) + { + case 0: + if ( nLastType == NF_SYMBOLTYPE_STRING ) + bDateNoDefault = true; // text at the end -> no default date format + bEnd = true; // end of format reached + break; + case NF_SYMBOLTYPE_STRING: + case NF_SYMBOLTYPE_DATESEP: + case NF_SYMBOLTYPE_TIMESEP: + case NF_SYMBOLTYPE_TIME100SECSEP: + // text is ignored, except at the end + break; + // same mapping as in SvXMLNumFormatContext::AddNfKeyword: + case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break; + case NF_KEY_NNN: + case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break; + case NF_KEY_D: eDateDay = XML_DEA_SHORT; break; + case NF_KEY_DD: eDateDay = XML_DEA_LONG; break; + case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break; + case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break; + case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break; + case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break; + case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break; + case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break; + case NF_KEY_H: eDateHours = XML_DEA_SHORT; break; + case NF_KEY_HH: eDateHours = XML_DEA_LONG; break; + case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break; + case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break; + case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break; + case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break; + case NF_KEY_AP: + case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself + default: + bDateNoDefault = true; // any other element -> no default format + } + nLastType = nElemType; + ++nPos; + } + + if ( bDateNoDefault ) + return false; // additional elements + else + { + NfIndexTableOffset eFound = static_cast<NfIndexTableOffset>(SvXMLNumFmtDefaults::GetDefaultDateFormat( + eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate )); + + return ( eFound == eBuiltIn ); + } +} + +// export one part (condition) + +void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey, + sal_uInt16 nPart, bool bDefPart ) +{ + //! for the default part, pass the conditions from the other parts! + + // element name + + NfIndexTableOffset eBuiltIn = m_pFormatter->GetIndexTableOffset( nRealKey ); + + SvNumFormatType nFmtType = SvNumFormatType::ALL; + bool bThousand = false; + sal_uInt16 nPrecision = 0; + sal_uInt16 nLeading = 0; + rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading); + nFmtType &= ~SvNumFormatType::DEFINED; + + // special treatment of builtin formats that aren't detected by normal parsing + // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats) + if ( eBuiltIn == NF_NUMBER_STANDARD ) + nFmtType = SvNumFormatType::NUMBER; + else if ( eBuiltIn == NF_BOOLEAN ) + nFmtType = SvNumFormatType::LOGICAL; + else if ( eBuiltIn == NF_TEXT ) + nFmtType = SvNumFormatType::TEXT; + + // #101606# An empty subformat is a valid number-style resulting in an + // empty display string for the condition of the subformat. + + XMLTokenEnum eType = XML_TOKEN_INVALID; + switch ( nFmtType ) + { + // Type UNDEFINED likely is a crappy format string for that we could + // not decide on any format type (and maybe could try harder?), but the + // resulting XMLTokenEnum should be something valid, so make that + // number-style. + case SvNumFormatType::UNDEFINED: + SAL_WARN("xmloff.style","UNDEFINED number format: '" << rFormat.GetFormatstring() << "'"); + [[fallthrough]]; + // Type is 0 if a format contains no recognized elements + // (like text only) - this is handled as a number-style. + case SvNumFormatType::ALL: + case SvNumFormatType::EMPTY: + case SvNumFormatType::NUMBER: + case SvNumFormatType::SCIENTIFIC: + case SvNumFormatType::FRACTION: + eType = XML_NUMBER_STYLE; + break; + case SvNumFormatType::PERCENT: + eType = XML_PERCENTAGE_STYLE; + break; + case SvNumFormatType::CURRENCY: + eType = XML_CURRENCY_STYLE; + break; + case SvNumFormatType::DATE: + case SvNumFormatType::DATETIME: + eType = XML_DATE_STYLE; + break; + case SvNumFormatType::TIME: + eType = XML_TIME_STYLE; + break; + case SvNumFormatType::TEXT: + eType = XML_TEXT_STYLE; + break; + case SvNumFormatType::LOGICAL: + eType = XML_BOOLEAN_STYLE; + break; + default: break; + } + SAL_WARN_IF( eType == XML_TOKEN_INVALID, "xmloff.style", "unknown format type" ); + + OUString sAttrValue; + bool bUserDef( rFormat.GetType() & SvNumFormatType::DEFINED ); + + // common attributes for format + + // format name (generated from key) - style namespace + m_rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, + lcl_CreateStyleName( nKey, nPart, bDefPart, m_sPrefix ) ); + + // "volatile" attribute for styles used only in maps + if ( !bDefPart ) + m_rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TRUE ); + + // language / country + LanguageType nLang = rFormat.GetLanguage(); + AddLanguageAttr_Impl( nLang ); // adds to pAttrList + + // title (comment) + // titles for builtin formats are not written + sAttrValue = rFormat.GetComment(); + if ( !sAttrValue.isEmpty() && bUserDef && bDefPart ) + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TITLE, sAttrValue ); + } + + // automatic ordering for currency and date formats + // only used for some built-in formats + bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 || + eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED || + eBuiltIn == NF_CURRENCY_1000DEC2_DASHED || + eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG || + eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM || + eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY || + eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY || + eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY || + eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY || + eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMM || + eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS ); + + // format source (for date and time formats) + // only used for some built-in formats + bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT || + eBuiltIn == NF_DATE_SYSTEM_LONG || + eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM ); + bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG ); + + // check if the format definition matches the key + if ( bAutoOrder && ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) && + !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) ) + { + bAutoOrder = bSystemDate = bLongSysDate = false; // don't write automatic-order attribute then + } + + if ( bAutoOrder && + ( nFmtType == SvNumFormatType::CURRENCY || nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) ) + { + // #85109# format type must be checked to avoid dtd errors if + // locale data contains other format types at the built-in positions + + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, + XML_TRUE ); + } + + if ( bSystemDate && bAutoOrder && + ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) ) + { + // #85109# format type must be checked to avoid dtd errors if + // locale data contains other format types at the built-in positions + + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE, + XML_LANGUAGE ); + } + + // overflow for time formats as in [hh]:mm + // controlled by bThousand from number format info + // default for truncate-on-overflow is true + if ( nFmtType == SvNumFormatType::TIME && bThousand ) + { + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW, + XML_FALSE ); + } + + // Native number transliteration + css::i18n::NativeNumberXmlAttributes2 aAttr; + rFormat.GetNatNumXml( aAttr, nPart ); + if ( !aAttr.Format.isEmpty() ) + { + assert(aAttr.Spellout.isEmpty()); // mutually exclusive + + /* FIXME-BCP47: ODF defines no transliteration-script or + * transliteration-rfc-language-tag */ + LanguageTag aLanguageTag( aAttr.Locale); + OUString aLanguage, aScript, aCountry; + aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry); + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT, + aAttr.Format ); + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, + aLanguage ); + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, + aCountry ); + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE, + aAttr.Style ); + } + + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + if ( !aAttr.Spellout.isEmpty() ) + { + const bool bWriteSpellout = aAttr.Format.isEmpty(); + assert(bWriteSpellout); // mutually exclusive + + // Export only for 1.2 and later with extensions + // Also ensure that duplicated transliteration-language and + // transliteration-country attributes never escape into the wild with + // releases. + if ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) && bWriteSpellout ) + { + /* FIXME-BCP47: ODF defines no transliteration-script or + * transliteration-rfc-language-tag */ + LanguageTag aLanguageTag( aAttr.Locale); + OUString aLanguage, aScript, aCountry; + aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry); + // For 1.2/1.3+ use loext namespace. + m_rExport.AddAttribute( /*((eVersion < SvtSaveOptions::ODFSVER_) + ? */ XML_NAMESPACE_LO_EXT /*: XML_NAMESPACE_NUMBER)*/, + XML_TRANSLITERATION_SPELLOUT, aAttr.Spellout ); + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, + aLanguage ); + m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, + aCountry ); + } + } + + // The element + SvXMLElementExport aElem( m_rExport, XML_NAMESPACE_NUMBER, eType, + true, true ); + + // color (properties element) + + const Color* pCol = rFormat.GetColor( nPart ); + if (pCol) + WriteColorElement_Impl(*pCol); + + // detect if there is "real" content, excluding color and maps + //! move to implementation of Write... methods? + bool bAnyContent = false; + + // format elements + + SvXMLEmbeddedTextEntryArr aEmbeddedEntries; + if ( eBuiltIn == NF_NUMBER_STANDARD ) + { + // default number format contains just one number element + WriteNumberElement_Impl( -1, -1, 1, -1, OUString(), false, 0, aEmbeddedEntries ); + bAnyContent = true; + } + else if ( eBuiltIn == NF_BOOLEAN ) + { + // boolean format contains just one boolean element + WriteBooleanElement_Impl(); + bAnyContent = true; + } + else if (eType == XML_BOOLEAN_STYLE) + { + // <number:boolean-style> may contain only <number:boolean> and + // <number:text> elements. + sal_uInt16 nPos = 0; + bool bEnd = false; + while (!bEnd) + { + const short nElemType = rFormat.GetNumForType( nPart, nPos ); + switch (nElemType) + { + case 0: + bEnd = true; // end of format reached + if (m_bHasText && m_sTextContent.isEmpty()) + m_bHasText = false; // don't write trailing empty text + break; + case NF_SYMBOLTYPE_STRING: + { + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + if (pElemStr) + AddToTextElement_Impl( *pElemStr ); + } + break; + case NF_KEY_BOOLEAN: + WriteBooleanElement_Impl(); + bAnyContent = true; + break; + } + ++nPos; + } + } + else + { + // first loop to collect attributes + + bool bDecDashes = false; + bool bExpFound = false; + bool bCurrFound = false; + bool bInInteger = true; + bool bExpSign = true; + bool bExponentLowercase = false; // 'e' or 'E' for scientific notation + bool bDecAlign = false; // decimal alignment with "?" + sal_Int32 nExpDigits = 0; // '0' and '?' in exponent + sal_Int32 nBlankExp = 0; // only '?' in exponent + sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#" + sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits + sal_Int32 nMinDecimals = nPrecision; + sal_Int32 nBlankInteger = 0; + OUString sCurrExt; + OUString aCalendar; + bool bImplicitOtherCalendar = false; + bool bExplicitCalendar = false; + sal_uInt16 nPos = 0; + bool bEnd = false; + while (!bEnd) + { + short nElemType = rFormat.GetNumForType( nPart, nPos ); + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + + switch ( nElemType ) + { + case 0: + bEnd = true; // end of format reached + break; + case NF_SYMBOLTYPE_DIGIT: + if ( bExpFound && pElemStr ) + { + nExpDigits += pElemStr->getLength(); + for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- ) + { + if ( (*pElemStr)[i] == '?' ) + nBlankExp ++; + } + } + else if ( !bDecDashes && pElemStr && (*pElemStr)[0] == '-' ) + { + bDecDashes = true; + nMinDecimals = 0; + } + else if ( nFmtType != SvNumFormatType::FRACTION && !bInInteger && pElemStr ) + { + for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- ) + { + sal_Unicode aChar = (*pElemStr)[i]; + if ( aChar == '#' || aChar == '?' ) + { + nMinDecimals --; + if ( aChar == '?' ) + bDecAlign = true; + } + else + break; + } + } + if ( bInInteger && pElemStr ) + { + nIntegerSymbols += pElemStr->getLength(); + for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- ) + { + if ( (*pElemStr)[i] == '?' ) + nBlankInteger ++; + } + } + nTrailingThousands = 0; + break; + case NF_SYMBOLTYPE_FRACBLANK: + case NF_SYMBOLTYPE_DECSEP: + bInInteger = false; + break; + case NF_SYMBOLTYPE_THSEP: + if (pElemStr) + nTrailingThousands += pElemStr->getLength(); // is reset to 0 if digits follow + break; + case NF_SYMBOLTYPE_EXP: + bExpFound = true; // following digits are exponent digits + bInInteger = false; + if ( pElemStr && ( pElemStr->getLength() == 1 + || ( pElemStr->getLength() == 2 && (*pElemStr)[1] == '-' ) ) ) + bExpSign = false; // for 0.00E0 or 0.00E-00 + if ( pElemStr && (*pElemStr)[0] == 'e' ) + bExponentLowercase = true; // for 0.00e+00 + break; + case NF_SYMBOLTYPE_CURRENCY: + bCurrFound = true; + break; + case NF_SYMBOLTYPE_CURREXT: + if (pElemStr) + sCurrExt = *pElemStr; + break; + + // E, EE, R, RR: select non-gregorian calendar + // AAA, AAAA: calendar is switched at the position of the element + case NF_KEY_EC: + case NF_KEY_EEC: + case NF_KEY_R: + case NF_KEY_RR: + if (aCalendar.isEmpty()) + { + aCalendar = lcl_GetDefaultCalendar( m_pFormatter, nLang ); + bImplicitOtherCalendar = true; + } + break; + } + ++nPos; + } + + // collect strings for embedded-text (must be known before number element is written) + bool bAllowEmbedded = ( nFmtType == SvNumFormatType::ALL || nFmtType == SvNumFormatType::NUMBER || + nFmtType == SvNumFormatType::CURRENCY || + // Export only for 1.x with extensions + ( nFmtType == SvNumFormatType::SCIENTIFIC && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) )|| + nFmtType == SvNumFormatType::PERCENT ); + if ( bAllowEmbedded ) + { + sal_Int32 nDigitsPassed = 0; + sal_Int32 nEmbeddedPositionsMax = nIntegerSymbols; + // Enable embedded text in decimal part only if there's a decimal part + if ( nPrecision ) + nEmbeddedPositionsMax += nPrecision + 1; + // Enable embedded text in exponent in scientific number + if ( nFmtType == SvNumFormatType::SCIENTIFIC ) + nEmbeddedPositionsMax += 1 + nExpDigits; + nPos = 0; + bEnd = false; + bExpFound = false; + while (!bEnd) + { + short nElemType = rFormat.GetNumForType( nPart, nPos ); + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + + switch ( nElemType ) + { + case 0: + bEnd = true; // end of format reached + break; + case NF_SYMBOLTYPE_DIGIT: + if ( pElemStr ) + nDigitsPassed += pElemStr->getLength(); + break; + case NF_SYMBOLTYPE_EXP: + bExpFound = true; + [[fallthrough]]; + case NF_SYMBOLTYPE_DECSEP: + nDigitsPassed++; + break; + case NF_SYMBOLTYPE_STRING: + case NF_SYMBOLTYPE_BLANK: + case NF_SYMBOLTYPE_PERCENT: + if ( 0 < nDigitsPassed && nDigitsPassed < nEmbeddedPositionsMax && pElemStr ) + { + // text (literal or underscore) within the integer (>=0) or decimal (<0) part of a number:number element + + OUString aEmbeddedStr; + bool bSaveBlankWidthSymbol = false; + if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT ) + { + aEmbeddedStr = *pElemStr; + } + else if (pElemStr->getLength() >= 2) + { + if ( eVersion > SvtSaveOptions::ODFSVER_013 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 ) ) + { + aEmbeddedStr = pElemStr->copy( 1, 1 ); + bSaveBlankWidthSymbol = true; + } + else // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat + SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] ); + } + sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed; + + aEmbeddedEntries.push_back( + SvXMLEmbeddedTextEntry( nPos, nEmbedPos, aEmbeddedStr, bSaveBlankWidthSymbol )); + // exponent sign is required with embedded text in exponent + if ( bExpFound && !bExpSign ) + bExpSign = true; + } + break; + } + ++nPos; + } + } + + // final loop to write elements + + bool bNumWritten = false; + bool bCurrencyWritten = false; + short nPrevType = 0; + nPos = 0; + bEnd = false; + while (!bEnd) + { + short nElemType = rFormat.GetNumForType( nPart, nPos ); + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + + switch ( nElemType ) + { + case 0: + bEnd = true; // end of format reached + if (m_bHasText && m_sTextContent.isEmpty()) + m_bHasText = false; // don't write trailing empty text + break; + case NF_SYMBOLTYPE_STRING: + case NF_SYMBOLTYPE_DATESEP: + case NF_SYMBOLTYPE_TIMESEP: + case NF_SYMBOLTYPE_TIME100SECSEP: + case NF_SYMBOLTYPE_PERCENT: + if (pElemStr) + { + if ( ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) && + ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS || + ( nPos > 0 && (*rFormat.GetNumForString( nPart, nPos-1 ))[0] == ']' && + ( nFmtType == SvNumFormatType::TIME || nFmtType == SvNumFormatType::DATETIME ) ) ) && + nPrecision > 0 ) + { + // decimal separator after seconds or [SS] is implied by + // "decimal-places" attribute and must not be written + // as text element + //! difference between '.' and ',' is lost here + } + else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) ) + { + // text is written as embedded-text child of the number, + // don't create a text element + } + else if ( nFmtType == SvNumFormatType::CURRENCY && !bCurrFound && !bCurrencyWritten ) + { + // automatic currency symbol is implemented as part of + // normal text -> search for the symbol + bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr, + LanguageTag::convertToLocale( nLang ) ); + bAnyContent = true; + } + else + AddToTextElement_Impl( *pElemStr ); + } + break; + case NF_SYMBOLTYPE_BLANK: + if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) ) + { + if ( pElemStr->getLength() == 2 ) + { + OUString aBlankWidthChar = pElemStr->copy( 1 ); + lcl_WriteBlankWidthString( aBlankWidthChar, m_sBlankWidthString, m_sTextContent ); + m_bHasText = true; + } + } + break; + case NF_KEY_GENERAL : + WriteNumberElement_Impl( -1, -1, 1, -1, OUString(), false, 0, aEmbeddedEntries ); + bAnyContent = true; + break; + case NF_KEY_CCC: + if (pElemStr) + { + if ( bCurrencyWritten ) + AddToTextElement_Impl( *pElemStr ); // never more than one currency element + else + { + //! must be different from short automatic format + //! but should still be empty (meaning automatic) + // pElemStr is "CCC" + + WriteCurrencyElement_Impl( *pElemStr, u"" ); + bAnyContent = true; + bCurrencyWritten = true; + } + } + break; + case NF_SYMBOLTYPE_CURRENCY: + if (pElemStr) + { + if ( bCurrencyWritten ) + AddToTextElement_Impl( *pElemStr ); // never more than one currency element + else + { + WriteCurrencyElement_Impl( *pElemStr, sCurrExt ); + bAnyContent = true; + bCurrencyWritten = true; + } + } + break; + case NF_SYMBOLTYPE_DIGIT: + if (!bNumWritten) // write number part + { + switch ( nFmtType ) + { + // for type 0 (not recognized as a special type), + // write a "normal" number + case SvNumFormatType::ALL: + case SvNumFormatType::NUMBER: + case SvNumFormatType::CURRENCY: + case SvNumFormatType::PERCENT: + { + // decimals + // only some built-in formats have automatic decimals + sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo + if ( eBuiltIn == NF_NUMBER_STANDARD || + eBuiltIn == NF_CURRENCY_1000DEC2 || + eBuiltIn == NF_CURRENCY_1000DEC2_RED || + eBuiltIn == NF_CURRENCY_1000DEC2_CCC || + eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ) + nDecimals = -1; + + // integer digits + // only one built-in format has automatic integer digits + sal_Int32 nInteger = nLeading; + if ( eBuiltIn == NF_NUMBER_SYSTEM ) + { + nInteger = -1; + nBlankInteger = -1; + } + + // string for decimal replacement + // has to be taken from nPrecision + // (positive number even for automatic decimals) + OUStringBuffer sDashStr; + if (bDecDashes && nPrecision > 0) + comphelper::string::padToLength(sDashStr, nPrecision, '-'); + // "?" in decimal part are replaced by space character + if (bDecAlign && nPrecision > 0) + sDashStr = " "; + + WriteNumberElement_Impl(nDecimals, nMinDecimals, nInteger, nBlankInteger, sDashStr.makeStringAndClear(), + bThousand, nTrailingThousands, aEmbeddedEntries); + bAnyContent = true; + } + break; + case SvNumFormatType::SCIENTIFIC: + // #i43959# for scientific numbers, count all integer symbols ("0", "?" and "#") + // as integer digits: use nIntegerSymbols instead of nLeading + // nIntegerSymbols represents exponent interval (for engineering notation) + WriteScientificElement_Impl( nPrecision, nMinDecimals, nLeading, nBlankInteger, bThousand, nExpDigits, nIntegerSymbols, bExpSign, + bExponentLowercase, nBlankExp, aEmbeddedEntries ); + bAnyContent = true; + break; + case SvNumFormatType::FRACTION: + { + sal_Int32 nInteger = nLeading; + if ( rFormat.GetNumForNumberElementCount( nPart ) == 3 ) + { + // If there is only two numbers + fraction in format string + // the fraction doesn't have an integer part, and no + // min-integer-digits attribute must be written. + nInteger = -1; + nBlankInteger = -1; + } + WriteFractionElement_Impl( nInteger, nBlankInteger, bThousand, rFormat, nPart ); + bAnyContent = true; + } + break; + default: break; + } + + bNumWritten = true; + } + break; + case NF_SYMBOLTYPE_DECSEP: + if ( pElemStr && nPrecision == 0 ) + { + // A decimal separator after the number, without following decimal digits, + // isn't modelled as part of the number element, so it's written as text + // (the distinction between a quoted and non-quoted, locale-dependent + // character is lost here). + + AddToTextElement_Impl( *pElemStr ); + } + break; + case NF_SYMBOLTYPE_DEL: + if ( pElemStr && *pElemStr == "@" ) + { + WriteTextContentElement_Impl(); + bAnyContent = true; + } + break; + + case NF_SYMBOLTYPE_CALENDAR: + if ( pElemStr ) + { + aCalendar = *pElemStr; + bExplicitCalendar = true; + } + break; + + // date elements: + + case NF_KEY_D: + case NF_KEY_DD: + { + bool bLong = ( nElemType == NF_KEY_DD ); + WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); + bAnyContent = true; + } + break; + case NF_KEY_DDD: + case NF_KEY_DDDD: + case NF_KEY_NN: + case NF_KEY_NNN: + case NF_KEY_NNNN: + case NF_KEY_AAA: + case NF_KEY_AAAA: + { + OUString aCalAttr = aCalendar; + if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA ) + { + // calendar attribute for AAA and AAAA is switched only for this element + if (aCalAttr.isEmpty()) + aCalAttr = lcl_GetDefaultCalendar( m_pFormatter, nLang ); + } + + bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN || + nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA ); + WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) ); + bAnyContent = true; + if ( nElemType == NF_KEY_NNNN ) + { + // write additional text element for separator + m_pLocaleData.reset( new LocaleDataWrapper( m_pFormatter->GetComponentContext(), + LanguageTag( nLang ) ) ); + AddToTextElement_Impl( m_pLocaleData->getLongDateDayOfWeekSep() ); + } + } + break; + case NF_KEY_M: + case NF_KEY_MM: + case NF_KEY_MMM: + case NF_KEY_MMMM: + case NF_KEY_MMMMM: //! first letter of month name, no attribute available + { + bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM ); + bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM || + nElemType == NF_KEY_MMMMM ); + WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText ); + bAnyContent = true; + } + break; + case NF_KEY_YY: + case NF_KEY_YYYY: + case NF_KEY_EC: + case NF_KEY_EEC: + case NF_KEY_R: //! R acts as EE, no attribute available + { + //! distinguish EE and R + // Calendar attribute for E and EE and R is set in + // first loop. If set and not an explicit calendar and + // YY or YYYY is encountered, switch temporarily to + // Gregorian. + bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC || + nElemType == NF_KEY_R ); + WriteYearElement_Impl( + ((bImplicitOtherCalendar && !bExplicitCalendar + && (nElemType == NF_KEY_YY || nElemType == NF_KEY_YYYY)) ? "gregorian" : aCalendar), + (bSystemDate ? bLongSysDate : bLong)); + bAnyContent = true; + } + break; + case NF_KEY_G: + case NF_KEY_GG: + case NF_KEY_GGG: + case NF_KEY_RR: //! RR acts as GGGEE, no attribute available + { + //! distinguish GG and GGG and RR + bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR ); + WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); + bAnyContent = true; + if ( nElemType == NF_KEY_RR ) + { + // calendar attribute for RR is set in first loop + WriteYearElement_Impl( aCalendar, ( bSystemDate || bLongSysDate ) ); + } + } + break; + case NF_KEY_Q: + case NF_KEY_QQ: + { + bool bLong = ( nElemType == NF_KEY_QQ ); + WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); + bAnyContent = true; + } + break; + case NF_KEY_WW: + WriteWeekElement_Impl( aCalendar ); + bAnyContent = true; + break; + + // time elements (bSystemDate is not used): + + case NF_KEY_H: + case NF_KEY_HH: + WriteHoursElement_Impl( nElemType == NF_KEY_HH ); + bAnyContent = true; + break; + case NF_KEY_MI: + case NF_KEY_MMI: + WriteMinutesElement_Impl( nElemType == NF_KEY_MMI ); + bAnyContent = true; + break; + case NF_KEY_S: + case NF_KEY_SS: + WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision ); + bAnyContent = true; + break; + case NF_KEY_AMPM: + case NF_KEY_AP: + WriteAMPMElement_Impl(); // short/long? + bAnyContent = true; + break; + case NF_SYMBOLTYPE_STAR : + // export only if ODF 1.2 extensions are enabled + if (m_rExport.getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + if ( pElemStr && pElemStr->getLength() > 1 ) + WriteRepeatedElement_Impl( (*pElemStr)[1] ); + } + break; + } + nPrevType = nElemType; + ++nPos; + } + } + + if ( !m_sTextContent.isEmpty() ) + bAnyContent = true; // element written in FinishTextElement_Impl + + FinishTextElement_Impl(); // final text element - before maps + + if ( !bAnyContent ) + { + // for an empty format, write an empty text element + SvXMLElementExport aTElem( m_rExport, XML_NAMESPACE_NUMBER, XML_TEXT, + true, false ); + } + + // mapping (conditions) must be last elements + + if (!bDefPart) + return; + + SvNumberformatLimitOps eOp1, eOp2; + double fLimit1, fLimit2; + rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 ); + + WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 ); + WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 ); + + if ( !rFormat.HasTextFormat() ) + return; + + // 4th part is for text -> make an "all other numbers" condition for the 3rd part + // by reversing the 2nd condition. + // For a trailing text format like 0;@ that has no conditions + // use a "less or equal than biggest" condition for the number + // part, ODF can't store subformats (style maps) without + // conditions. + + SvNumberformatLimitOps eOp3 = NUMBERFORMAT_OP_NO; + double fLimit3 = fLimit2; + sal_uInt16 nLastPart = 2; + SvNumberformatLimitOps eOpLast = eOp2; + if (eOp2 == NUMBERFORMAT_OP_NO) + { + eOpLast = eOp1; + fLimit3 = fLimit1; + nLastPart = (eOp1 == NUMBERFORMAT_OP_NO) ? 0 : 1; + } + switch ( eOpLast ) + { + case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break; + case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break; + case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break; + case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break; + case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break; + case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break; + case NUMBERFORMAT_OP_NO: eOp3 = NUMBERFORMAT_OP_LE; fLimit3 = DBL_MAX; break; + } + + if ( fLimit1 == fLimit2 && + ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) || + ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) ) + { + // For <x and >x, add =x as last condition + // (just for readability, <=x would be valid, too) + + eOp3 = NUMBERFORMAT_OP_EQ; + } + + WriteMapElement_Impl( eOp3, fLimit3, nKey, nLastPart ); +} + +// export one format + +void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey ) +{ + const sal_uInt16 XMLNUM_MAX_PARTS = 4; + bool bParts[XMLNUM_MAX_PARTS] = { false, false, false, false }; + sal_uInt16 nUsedParts = 0; + for (sal_uInt16 nPart=0; nPart<XMLNUM_MAX_PARTS; ++nPart) + { + if (rFormat.GetNumForInfoScannedType( nPart) != SvNumFormatType::UNDEFINED) + { + bParts[nPart] = true; + nUsedParts = nPart + 1; + } + } + + SvNumberformatLimitOps eOp1, eOp2; + double fLimit1, fLimit2; + rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 ); + + // if conditions are set, even empty formats must be written + + if ( eOp1 != NUMBERFORMAT_OP_NO ) + { + bParts[1] = true; + if (nUsedParts < 2) + nUsedParts = 2; + } + if ( eOp2 != NUMBERFORMAT_OP_NO ) + { + bParts[2] = true; + if (nUsedParts < 3) + nUsedParts = 3; + } + if ( rFormat.HasTextFormat() ) + { + bParts[3] = true; + if (nUsedParts < 4) + nUsedParts = 4; + } + + for (sal_uInt16 nPart=0; nPart<XMLNUM_MAX_PARTS; ++nPart) + { + if (bParts[nPart]) + { + bool bDefault = ( nPart+1 == nUsedParts ); // last = default + ExportPart_Impl( rFormat, nKey, nRealKey, nPart, bDefault ); + } + } +} + +// export method called by application + +void SvXMLNumFmtExport::Export( bool bIsAutoStyle ) +{ + if ( !m_pFormatter ) + return; // no formatter -> no entries + + sal_uInt32 nKey; + const SvNumberformat* pFormat = nullptr; + bool bNext(m_pUsedList->GetFirstUsed(nKey)); + while(bNext) + { + // ODF has its notation of system formats, so obtain the "real" already + // substituted format but use the original key for style name. + sal_uInt32 nRealKey = nKey; + pFormat = m_pFormatter->GetSubstitutedEntry( nKey, nRealKey); + if(pFormat) + ExportFormat_Impl( *pFormat, nKey, nRealKey ); + bNext = m_pUsedList->GetNextUsed(nKey); + } + if (!bIsAutoStyle) + { + std::vector<LanguageType> aLanguages; + m_pFormatter->GetUsedLanguages( aLanguages ); + for (const auto& nLang : aLanguages) + { + sal_uInt32 nDefaultIndex = 0; + SvNumberFormatTable& rTable = m_pFormatter->GetEntryTable( + SvNumFormatType::DEFINED, nDefaultIndex, nLang ); + for (const auto& rTableEntry : rTable) + { + nKey = rTableEntry.first; + pFormat = rTableEntry.second; + if (!m_pUsedList->IsUsed(nKey)) + { + DBG_ASSERT((pFormat->GetType() & SvNumFormatType::DEFINED), "a not user defined numberformat found"); + sal_uInt32 nRealKey = nKey; + if (pFormat->IsSubstituted()) + { + pFormat = m_pFormatter->GetSubstitutedEntry( nKey, nRealKey); // export the "real" format + assert(pFormat); + } + // user-defined and used formats are exported + ExportFormat_Impl( *pFormat, nKey, nRealKey ); + // if it is a user-defined Format it will be added else nothing will happen + m_pUsedList->SetUsed(nKey); + } + } + } + } + m_pUsedList->Export(); +} + +OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey ) +{ + if(m_pUsedList->IsUsed(nKey) || m_pUsedList->IsWasUsed(nKey)) + return lcl_CreateStyleName( nKey, 0, true, m_sPrefix ); + else + { + OSL_FAIL("There is no written Data-Style"); + return OUString(); + } +} + +void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey ) +{ + SAL_WARN_IF( m_pFormatter == nullptr, "xmloff.style", "missing formatter" ); + if( !m_pFormatter ) + return; + + if (m_pFormatter->GetEntry(nKey)) + m_pUsedList->SetUsed( nKey ); + else { + OSL_FAIL("no existing Numberformat found with this key"); + } +} + +uno::Sequence<sal_Int32> SvXMLNumFmtExport::GetWasUsed() const +{ + if (m_pUsedList) + return m_pUsedList->GetWasUsed(); + return uno::Sequence<sal_Int32>(); +} + +void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed) +{ + if (m_pUsedList) + m_pUsedList->SetWasUsed(rWasUsed); +} + +static const SvNumberformat* lcl_GetFormat( SvNumberFormatter const * pFormatter, + sal_uInt32 nKey ) +{ + return ( pFormatter != nullptr ) ? pFormatter->GetEntry( nKey ) : nullptr; +} + +sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey ) +{ + sal_uInt32 nRet = nKey; + + const SvNumberformat* pFormat = lcl_GetFormat( m_pFormatter, nKey ); + if( pFormat != nullptr ) + { + SAL_WARN_IF( m_pFormatter == nullptr, "xmloff.style", "format without formatter?" ); + + SvNumFormatType nType = pFormat->GetType(); + + sal_uInt32 nNewKey = m_pFormatter->GetFormatForLanguageIfBuiltIn( + nKey, LANGUAGE_SYSTEM ); + + if( nNewKey != nKey ) + { + nRet = nNewKey; + } + else + { + OUString aFormatString( pFormat->GetFormatstring() ); + sal_Int32 nErrorPos; + m_pFormatter->PutandConvertEntry( + aFormatString, + nErrorPos, nType, nNewKey, + pFormat->GetLanguage(), LANGUAGE_SYSTEM, true); + + // success? Then use new key. + if( nErrorPos == 0 ) + nRet = nNewKey; + } + } + + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx new file mode 100644 index 0000000000..f6d05e94c1 --- /dev/null +++ b/xmloff/source/style/xmlnumfi.cxx @@ -0,0 +1,2368 @@ +/* -*- 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 <svl/zforlist.hxx> +#include <svl/numformat.hxx> +#include <svl/zformat.hxx> +#include <svl/numuno.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <tools/color.hxx> +#include <osl/diagnose.h> +#include <rtl/math.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +#include <sax/tools/converter.hxx> + +#include <utility> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlnumfi.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/families.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/languagetagodf.hxx> + +#include <memory> +#include <string_view> +#include <vector> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +namespace { + +struct SvXMLNumFmtEntry +{ + OUString aName; + sal_uInt32 nKey; + bool bRemoveAfterUse; + + SvXMLNumFmtEntry( OUString aN, sal_uInt32 nK, bool bR ) : + aName(std::move(aN)), nKey(nK), bRemoveAfterUse(bR) {} +}; + +} + +class SvXMLNumImpData +{ + SvNumberFormatter* pFormatter; + std::unique_ptr<LocaleDataWrapper> pLocaleData; + std::vector<SvXMLNumFmtEntry> m_NameEntries; + + uno::Reference< uno::XComponentContext > m_xContext; + +public: + SvXMLNumImpData( + SvNumberFormatter* pFmt, + const uno::Reference<uno::XComponentContext>& rxContext ); + + SvNumberFormatter* GetNumberFormatter() const { return pFormatter; } + const LocaleDataWrapper& GetLocaleData( LanguageType nLang ); + sal_uInt32 GetKeyForName( std::u16string_view rName ); + void AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse ); + void SetUsed( sal_uInt32 nKey ); + void RemoveVolatileFormats(); +}; + +struct SvXMLNumberInfo +{ + sal_Int32 nDecimals = -1; + sal_Int32 nInteger = -1; /// Total min number of digits in integer part ('0' + '?') + sal_Int32 nBlankInteger = -1; /// Number of '?' in integer part + sal_Int32 nExpDigits = -1; /// Number of '0' and '?' in exponent + sal_Int32 nBlankExp = -1; /// Number of '?' in exponent + sal_Int32 nExpInterval = -1; + sal_Int32 nMinNumerDigits = -1; + sal_Int32 nMinDenomDigits = -1; + sal_Int32 nMaxNumerDigits = -1; + sal_Int32 nMaxDenomDigits = -1; + sal_Int32 nFracDenominator = -1; + sal_Int32 nMinDecimalDigits = -1; + sal_Int32 nZerosNumerDigits = -1; + sal_Int32 nZerosDenomDigits = -1; + bool bGrouping = false; + bool bDecReplace = false; + bool bExpSign = true; + bool bExponentLowercase = false; /// Exponent is 'e' instead of 'E' + bool bDecAlign = false; + double fDisplayFactor = 1.0; + OUString aIntegerFractionDelimiter; + std::map<sal_Int32, OUString> m_EmbeddedElements; +}; + +namespace { + +enum class SvXMLStyleTokens; + +class SvXMLNumFmtElementContext : public SvXMLImportContext +{ + SvXMLNumFormatContext& rParent; + SvXMLStyleTokens nType; + OUStringBuffer aContent; + SvXMLNumberInfo aNumInfo; + LanguageType nElementLang; + bool bLong; + bool bTextual; + OUString sCalendar; + OUString sBlankWidthString; + +public: + SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_Int32 nElement, + SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + void AddEmbeddedElement( sal_Int32 nFormatPos, std::u16string_view rContent, std::u16string_view rBlankWidthString ); +}; + +class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext +{ + SvXMLNumFmtElementContext& rParent; + OUStringBuffer aContent; + sal_Int32 nTextPosition; + OUString aBlankWidthString; + +public: + SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_Int32 nElement, + SvXMLNumFmtElementContext& rParentContext, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + virtual void SAL_CALL characters( const OUString& rChars ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class SvXMLNumFmtMapContext : public SvXMLImportContext +{ + SvXMLNumFormatContext& rParent; + OUString sCondition; + OUString sName; + +public: + SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_Int32 nElement, + SvXMLNumFormatContext& rParentContext, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class SvXMLNumFmtPropContext : public SvXMLImportContext +{ + SvXMLNumFormatContext& rParent; + Color m_nColor; + bool bColSet; + +public: + SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_Int32 nElement, + SvXMLNumFormatContext& rParentContext, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +enum class SvXMLStyleTokens +{ + Text, + FillCharacter, + Number, + ScientificNumber, + Fraction, + CurrencySymbol, + Day, + Month, + Year, + Era, + DayOfWeek, + WeekOfYear, + Quarter, + Hours, + AmPm, + Minutes, + Seconds, + Boolean, + TextContent +}; + +} + +// standard colors + + +#define XML_NUMF_COLORCOUNT 10 + +const Color aNumFmtStdColors[XML_NUMF_COLORCOUNT] = +{ + COL_BLACK, + COL_LIGHTBLUE, + COL_LIGHTGREEN, + COL_LIGHTCYAN, + COL_LIGHTRED, + COL_LIGHTMAGENTA, + COL_BROWN, + COL_GRAY, + COL_YELLOW, + COL_WHITE +}; + + +// token maps + + +// maps for SvXMLUnitConverter::convertEnum + +const SvXMLEnumMapEntry<bool> aStyleValueMap[] = +{ + { XML_SHORT, false }, + { XML_LONG, true }, + { XML_TOKEN_INVALID, false } +}; + +const SvXMLEnumMapEntry<bool> aFormatSourceMap[] = +{ + { XML_FIXED, false }, + { XML_LANGUAGE, true }, + { XML_TOKEN_INVALID, false } +}; + +namespace { + +struct SvXMLDefaultDateFormat +{ + NfIndexTableOffset eFormat; + SvXMLDateElementAttributes eDOW; + SvXMLDateElementAttributes eDay; + SvXMLDateElementAttributes eMonth; + SvXMLDateElementAttributes eYear; + SvXMLDateElementAttributes eHours; + SvXMLDateElementAttributes eMins; + SvXMLDateElementAttributes eSecs; + bool bSystem; +}; + +} + +const SvXMLDefaultDateFormat aDefaultDateFormats[] = +{ + // format day-of-week day month year hours minutes seconds format-source + + { NF_DATE_SYSTEM_SHORT, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, true }, + { NF_DATE_SYSTEM_LONG, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, true }, + { NF_DATE_SYS_MMYY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DDMMM, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_TEXTSHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DDMMYYYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DDMMYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DMMMYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DMMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_NNDMMMYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_NNDMMMMYYYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_NNNNDMMMMYYYY, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATETIME_SYS_DDMMYYYY_HHMM, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_LONG, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, false }, + { NF_DATETIME_SYSTEM_SHORT_HHMM, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, true }, + { NF_DATETIME_SYS_DDMMYYYY_HHMMSS, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, false } +}; + + +// SvXMLNumImpData + + +SvXMLNumImpData::SvXMLNumImpData( + SvNumberFormatter* pFmt, + const uno::Reference<uno::XComponentContext>& rxContext ) +: pFormatter(pFmt), + m_xContext(rxContext) +{ + SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); +} + +sal_uInt32 SvXMLNumImpData::GetKeyForName( std::u16string_view rName ) +{ + for (const auto& rObj : m_NameEntries) + { + if (rObj.aName == rName) + return rObj.nKey; // found + } + return NUMBERFORMAT_ENTRY_NOT_FOUND; +} + +void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse ) +{ + if ( bRemoveAfterUse ) + { + // if there is already an entry for this key without the bRemoveAfterUse flag, + // clear the flag for this entry, too + + for (const auto& rObj : m_NameEntries) + { + if (rObj.nKey == nKey && !rObj.bRemoveAfterUse) + { + bRemoveAfterUse = false; // clear flag for new entry + break; + } + } + } + else + { + // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key + SetUsed( nKey ); + } + + m_NameEntries.emplace_back(rName, nKey, bRemoveAfterUse); +} + +void SvXMLNumImpData::SetUsed( sal_uInt32 nKey ) +{ + for (auto& rObj : m_NameEntries) + { + if (rObj.nKey == nKey) + { + rObj.bRemoveAfterUse = false; // used -> don't remove + + // continue searching - there may be several entries for the same key + // (with different names), the format must not be deleted if any one of + // them is used + } + } +} + +void SvXMLNumImpData::RemoveVolatileFormats() +{ + // remove temporary (volatile) formats from NumberFormatter + // called at the end of each import (styles and content), so volatile formats + // from styles can't be used in content + + if ( !pFormatter ) + return; + + for (const auto& rObj : m_NameEntries) + { + if (rObj.bRemoveAfterUse ) + { + const SvNumberformat* pFormat = pFormatter->GetEntry(rObj.nKey); + if (pFormat && (pFormat->GetType() & SvNumFormatType::DEFINED)) + pFormatter->DeleteEntry(rObj.nKey); + } + } +} + +const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang ) +{ + if ( !pLocaleData || pLocaleData->getLanguageTag() != LanguageTag(nLang) ) + pLocaleData = std::make_unique<LocaleDataWrapper>( + pFormatter ? pFormatter->GetComponentContext() : m_xContext, + LanguageTag( nLang ) ); + return *pLocaleData; +} + + +// SvXMLNumFmtMapContext + + +SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumFormatContext& rParentContext, + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) : + SvXMLImportContext( rImport ), + rParent( rParentContext ) +{ + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_CONDITION): + sCondition = sValue; + break; + case XML_ELEMENT(STYLE, XML_APPLY_STYLE_NAME): + sName = sValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +void SvXMLNumFmtMapContext::endFastElement(sal_Int32 ) +{ + rParent.AddCondition( sCondition, sName ); +} + + +// SvXMLNumFmtPropContext + + +SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumFormatContext& rParentContext, + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) : + SvXMLImportContext( rImport ), + rParent( rParentContext ), + m_nColor( 0 ), + bColSet( false ) +{ + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + switch ( aIter.getToken()) + { + case XML_ELEMENT(FO, XML_COLOR): + case XML_ELEMENT(FO_COMPAT, XML_COLOR): + bColSet = ::sax::Converter::convertColor( m_nColor, aIter.toView() ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +void SvXMLNumFmtPropContext::endFastElement(sal_Int32 ) +{ + if (bColSet) + rParent.AddColor( m_nColor ); +} + + +// SvXMLNumFmtEmbeddedTextContext + + +SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumFmtElementContext& rParentContext, + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) : + SvXMLImportContext( rImport ), + rParent( rParentContext ), + nTextPosition( 0 ) +{ + sal_Int32 nAttrVal; + + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + if ( aIter.getToken() == XML_ELEMENT(NUMBER, XML_POSITION) ) + { + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView() )) + nTextPosition = nAttrVal; + } + else if ( aIter.getToken() == XML_ELEMENT(LO_EXT, XML_BLANK_WIDTH_CHAR) + || aIter.getToken() == XML_ELEMENT(NUMBER, XML_BLANK_WIDTH_CHAR) ) + { + aBlankWidthString = aIter.toString(); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +void SvXMLNumFmtEmbeddedTextContext::characters( const OUString& rChars ) +{ + aContent.append( rChars ); +} + +void SvXMLNumFmtEmbeddedTextContext::endFastElement(sal_Int32 ) +{ + rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear(), aBlankWidthString ); +} + +static bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent ) +{ + SvXMLStylesTokens nFormatType = rParent.GetType(); + + // Treat space equal to non-breaking space separator. + const sal_Unicode cNBSP = 0x00A0; + sal_Unicode cTS; + if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE || + nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || + nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) && + (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep()[0]) || + (cChar == ' ' && cTS == cNBSP)) ) + { + // #i22394# Extra occurrences of thousands separator must be quoted, so they + // aren't mis-interpreted as display-factor. + // This must be limited to the format types that can contain a number element, + // because the same character can be a date separator that should not be quoted + // in date formats. + + return false; // force quotes + } + + // see ImpSvNumberformatScan::Next_Symbol + + // All format types except BOOLEAN may contain minus sign or delimiter. + if ( cChar == '-' ) + return nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE; + + if ( ( cChar == ' ' || + cChar == '/' || + cChar == '.' || + cChar == ',' || + cChar == ':' || + cChar == '\'' ) && + ( nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || + nFormatType == SvXMLStylesTokens::DATE_STYLE || + nFormatType == SvXMLStylesTokens::TIME_STYLE ) ) // other formats do not require delimiter tdf#97837 + return true; + + // percent sign must be used without quotes for percentage styles only + if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && cChar == '%' ) + return true; + + // don't put quotes around single parentheses (often used for negative numbers) + if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE || + nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || + nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) && + ( cChar == '(' || cChar == ')' ) ) + return true; + + return false; +} + +static void lcl_EnquoteIfNecessary( OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent ) +{ + bool bQuote = true; + sal_Int32 nLength = rContent.getLength(); + const SvXMLStylesTokens nFormatType = rParent.GetType(); + + if (nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE && + ((nLength == 1 && lcl_ValidChar( rContent[0], rParent)) || + (nLength == 2 && + ((rContent[0] == ' ' && rContent[1] == '-') || + (rContent[1] == ' ' && lcl_ValidChar( rContent[0], rParent)))))) + { + // Don't quote single separator characters like space or percent, + // or separator characters followed by space (used in date formats). + // Or space followed by minus (used in currency formats) that would + // lead to almost duplicated formats with built-in formats just with + // the difference of quotes. + bQuote = false; + } + else if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && nLength > 1 ) + { + // the percent character in percentage styles must be left out of quoting + // (one occurrence is enough even if there are several percent characters in the string) + + sal_Int32 nPos = rContent.indexOf( '%' ); + if ( nPos >= 0 ) + { + if ( nPos + 1 < nLength ) + { + if ( nPos + 2 == nLength && lcl_ValidChar( rContent[nPos + 1], rParent ) ) + { + // single character that doesn't need quoting + } + else + { + // quote text behind percent character + rContent.insert( nPos + 1, '"' ); + rContent.append( '"' ); + } + } + if ( nPos > 0 ) + { + if ( nPos == 1 && lcl_ValidChar( rContent[0], rParent ) ) + { + // single character that doesn't need quoting + } + else + { + // quote text before percent character + rContent.insert( nPos, '"' ); + rContent.insert( 0, '"' ); + } + } + bQuote = false; + } + // else: normal quoting (below) + } + + if ( !bQuote ) + return; + + // #i55469# quotes in the string itself have to be escaped + bool bEscape = ( rContent.indexOf( '"' ) >= 0 ); + if ( bEscape ) + { + // A quote is turned into "\"" - a quote to end quoted text, an escaped quote, + // and a quote to resume quoting. + OUString aInsert( "\"\\\"" ); + + sal_Int32 nPos = 0; + while ( nPos < rContent.getLength() ) + { + if ( rContent[nPos] == '"' ) + { + rContent.insert( nPos, aInsert ); + nPos += aInsert.getLength(); + } + ++nPos; + } + } + + // quote string literals + rContent.insert( 0, '"' ); + rContent.append( '"' ); + + // remove redundant double quotes at start or end + if ( !bEscape ) + return; + + if ( rContent.getLength() > 2 && + rContent[0] == '"' && + rContent[1] == '"' ) + { + rContent.remove(0, 2); + } + + sal_Int32 nLen = rContent.getLength(); + if ( nLen > 2 && + rContent[nLen - 1] == '"' && + rContent[nLen - 2] == '"' ) + { + rContent.truncate(nLen - 2); + } +} + + +// SvXMLNumFmtElementContext + + +SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType, + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) : + SvXMLImportContext( rImport ), + rParent( rParentContext ), + nType( nNewType ), + nElementLang( LANGUAGE_SYSTEM ), + bLong( false ), + bTextual( false ) +{ + LanguageTagODF aLanguageTagODF; + sal_Int32 nAttrVal; + bool bAttrBool(false); + bool bVarDecimals = false; + bool bIsMaxDenominator = false; + double fAttrDouble; + + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(NUMBER, XML_DECIMAL_PLACES): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + { + // fdo#58539 & gnome#627420: limit number of digits during import + aNumInfo.nDecimals = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS); + } + break; + case XML_ELEMENT(LO_EXT, XML_MIN_DECIMAL_PLACES): + case XML_ELEMENT(NUMBER, XML_MIN_DECIMAL_PLACES): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nMinDecimalDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_MIN_INTEGER_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nInteger = nAttrVal; + break; + case XML_ELEMENT(LO_EXT, XML_MAX_BLANK_INTEGER_DIGITS): + case XML_ELEMENT(NUMBER, XML_MAX_BLANK_INTEGER_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nBlankInteger = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_GROUPING): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + aNumInfo.bGrouping = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_DISPLAY_FACTOR): + if (::sax::Converter::convertDouble( fAttrDouble, aIter.toView() )) + aNumInfo.fDisplayFactor = fAttrDouble; + break; + case XML_ELEMENT(NUMBER, XML_DECIMAL_REPLACEMENT): + if ( aIter.toView() == " " ) + { + aNumInfo.bDecAlign = true; // space replacement for "?" + bVarDecimals = true; + } + else + if ( aIter.isEmpty() ) + bVarDecimals = true; // empty replacement string: variable decimals + else // all other strings + aNumInfo.bDecReplace = true; // decimal replacement with dashes + break; + case XML_ELEMENT(NUMBER, XML_MIN_EXPONENT_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nExpDigits = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS); + break; + case XML_ELEMENT(NUMBER, XML_BLANK_EXPONENT_DIGITS): + case XML_ELEMENT(LO_EXT, XML_BLANK_EXPONENT_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nBlankExp = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS); + break; + case XML_ELEMENT(NUMBER, XML_EXPONENT_INTERVAL): + case XML_ELEMENT(LO_EXT, XML_EXPONENT_INTERVAL): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nExpInterval = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_FORCED_EXPONENT_SIGN): + case XML_ELEMENT(LO_EXT, XML_FORCED_EXPONENT_SIGN): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + aNumInfo.bExpSign = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_EXPONENT_LOWERCASE): + case XML_ELEMENT(LO_EXT, XML_EXPONENT_LOWERCASE): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + aNumInfo.bExponentLowercase = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_MIN_NUMERATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nMinNumerDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_MIN_DENOMINATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nMinDenomDigits = nAttrVal; + break; + case XML_ELEMENT(LO_EXT, XML_MAX_NUMERATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 )) // at least one '#' + aNumInfo.nMaxNumerDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_DENOMINATOR_VALUE): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 )) // 0 is not valid + { + aNumInfo.nFracDenominator = nAttrVal; + bIsMaxDenominator = false; + } + break; + case XML_ELEMENT(NUMBER, XML_MAX_DENOMINATOR_VALUE): // part of ODF 1.3 + case XML_ELEMENT(LO_EXT, XML_MAX_DENOMINATOR_VALUE): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 ) && aNumInfo.nFracDenominator <= 0) + { // if denominator value not yet defined + aNumInfo.nFracDenominator = nAttrVal; + bIsMaxDenominator = true; + } + break; + case XML_ELEMENT(LO_EXT, XML_ZEROS_NUMERATOR_DIGITS): + case XML_ELEMENT(NUMBER, XML_ZEROS_NUMERATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nZerosNumerDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_ZEROS_DENOMINATOR_DIGITS): + case XML_ELEMENT(LO_EXT, XML_ZEROS_DENOMINATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nZerosDenomDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_INTEGER_FRACTION_DELIMITER): + case XML_ELEMENT(LO_EXT, XML_INTEGER_FRACTION_DELIMITER): + aNumInfo.aIntegerFractionDelimiter = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG): + aLanguageTagODF.maRfcLanguageTag = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_LANGUAGE): + aLanguageTagODF.maLanguage = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_SCRIPT): + aLanguageTagODF.maScript = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_COUNTRY): + aLanguageTagODF.maCountry = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_STYLE): + SvXMLUnitConverter::convertEnum( bLong, aIter.toView(), aStyleValueMap ); + break; + case XML_ELEMENT(NUMBER, XML_TEXTUAL): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + bTextual = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_CALENDAR): + sCalendar = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_BLANK_WIDTH_CHAR): + case XML_ELEMENT(LO_EXT, XML_BLANK_WIDTH_CHAR): + sBlankWidthString = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + if ( aNumInfo.nBlankInteger > aNumInfo.nInteger ) + aNumInfo.nInteger = aNumInfo.nBlankInteger; + if ( aNumInfo.nMinDecimalDigits == -1) + { + if ( bVarDecimals || aNumInfo.bDecReplace ) + aNumInfo.nMinDecimalDigits = 0; + else + aNumInfo.nMinDecimalDigits = aNumInfo.nDecimals; + } + if ( aNumInfo.nExpDigits > 0 && aNumInfo.nBlankExp >= aNumInfo.nExpDigits ) + aNumInfo.nBlankExp = aNumInfo.nExpDigits - 1; // at least one '0' in exponent + + if ( aNumInfo.nZerosDenomDigits > 0 ) + { // nMin = count of '0' and '?' + if ( aNumInfo.nMinDenomDigits < aNumInfo.nZerosDenomDigits ) + aNumInfo.nMinDenomDigits = aNumInfo.nZerosDenomDigits; + } + else + aNumInfo.nZerosDenomDigits = 0; + if ( aNumInfo.nMinDenomDigits >= 0 ) + if ( aNumInfo.nMaxDenomDigits < aNumInfo.nMinDenomDigits ) + aNumInfo.nMaxDenomDigits = ( aNumInfo.nMinDenomDigits ? aNumInfo.nMinDenomDigits : 1 ); + if ( aNumInfo.nZerosNumerDigits > 0 ) + { + if ( aNumInfo.nMinNumerDigits < aNumInfo.nZerosNumerDigits ) + aNumInfo.nMinNumerDigits = aNumInfo.nZerosNumerDigits; + } + else + aNumInfo.nZerosNumerDigits = 0; + if ( aNumInfo.nMinNumerDigits >= 0 ) + if ( aNumInfo.nMaxNumerDigits < aNumInfo.nMinNumerDigits ) + aNumInfo.nMaxNumerDigits = ( aNumInfo.nMinNumerDigits ? aNumInfo.nMinNumerDigits : 1 ); + if ( bIsMaxDenominator && aNumInfo.nFracDenominator > 0 ) + { + aNumInfo.nMaxDenomDigits = floor( log10( aNumInfo.nFracDenominator ) ) + 1; + aNumInfo.nFracDenominator = -1; // Max denominator value only gives number of digits at denominator + } + if ( aNumInfo.nMaxDenomDigits > 0 ) + { + if ( aNumInfo.nMinDenomDigits < 0 ) + aNumInfo.nMinDenomDigits = 0; + else if ( aNumInfo.nMinDenomDigits > aNumInfo.nMaxDenomDigits ) + aNumInfo.nMinDenomDigits = aNumInfo.nMaxDenomDigits; + } + + if ( !aLanguageTagODF.isEmpty() ) + { + nElementLang = aLanguageTagODF.getLanguageTag().getLanguageType( false); + if ( nElementLang == LANGUAGE_DONTKNOW ) + nElementLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? + } + + if ( aNumInfo.aIntegerFractionDelimiter.isEmpty() ) + aNumInfo.aIntegerFractionDelimiter = " "; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFmtElementContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // only number:number and number:scientific-number supports number:embedded-text child element + + if ( ( nType == SvXMLStyleTokens::Number || nType == SvXMLStyleTokens::ScientificNumber ) && + nElement == XML_ELEMENT(NUMBER, XML_EMBEDDED_TEXT) ) + { + return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nElement, *this, xAttrList ); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SvXMLNumFmtElementContext::characters( const OUString& rChars ) +{ + aContent.append( rChars ); +} + +namespace { +void lcl_InsertBlankWidthChars( std::u16string_view rBlankWidthString, OUStringBuffer& rContent ) +{ + sal_Int32 nShiftPosition = 1; // rContent starts with a quote + const size_t nLenBlank = rBlankWidthString.size(); + for ( size_t i = 0 ; i < nLenBlank ; i++ ) + { + sal_Unicode nChar = rBlankWidthString[ i ]; + OUString aBlanks; + SvNumberformat::InsertBlanks( aBlanks, 0, nChar ); + sal_Int32 nPositionContent = 0; + if ( ++i < nLenBlank ) + { + sal_Int32 nNext = rBlankWidthString.find( '_', i ); + if ( static_cast<sal_Int32>( i ) < nNext ) + { + nPositionContent = o3tl::toInt32( rBlankWidthString.substr( i, nNext - i ) ); + i = nNext; + } + else + nPositionContent = o3tl::toInt32( rBlankWidthString.substr( i ) ); + } + nPositionContent += nShiftPosition; + if ( nPositionContent >= 0 ) + { + rContent.remove( nPositionContent, aBlanks.getLength() ); + if ( nPositionContent >= 1 && rContent[ nPositionContent-1 ] == '\"' ) + { + nPositionContent--; + rContent.insert( nPositionContent, nChar ); + rContent.insert( nPositionContent, '_' ); + } + else + { + rContent.insert( nPositionContent, '\"' ); + rContent.insert( nPositionContent, nChar ); + rContent.insert( nPositionContent, "\"_" ); + nShiftPosition += 2; + } + // rContent length was modified: remove blanks, add "_x" + nShiftPosition += 2 - aBlanks.getLength(); + } + } + // remove empty string at the end of rContent + if ( std::u16string_view( rContent ).substr( rContent.getLength() - 2 ) == u"\"\"" ) + { + sal_Int32 nLen = rContent.getLength(); + if ( nLen >= 3 && rContent[ nLen-3 ] != '\\' ) + rContent.truncate( nLen - 2 ); + } +} +} + +void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, std::u16string_view rContentEmbedded, std::u16string_view rBlankWidthString ) +{ + if ( rContentEmbedded.empty() ) + return; + OUStringBuffer aContentEmbedded( rContentEmbedded ); + // #107805# always quote embedded strings - even space would otherwise + // be recognized as thousands separator in French. + aContentEmbedded.insert( 0, '"' ); + aContentEmbedded.append( '"' ); + if ( !rBlankWidthString.empty() ) + lcl_InsertBlankWidthChars( rBlankWidthString, aContentEmbedded ); + + auto iterPair = aNumInfo.m_EmbeddedElements.emplace( nFormatPos, aContentEmbedded.toString() ); + if (!iterPair.second) + { + // there's already an element at this position - append text to existing element + if ( iterPair.first->second.endsWith( "\"" ) && aContentEmbedded[ 0 ] == '"' ) + { // remove double quote + iterPair.first->second = OUString::Concat( iterPair.first->second.subView( 0, iterPair.first->second.getLength() - 1 ) ) + + aContentEmbedded.subView( 1, aContentEmbedded.getLength() - 1 ); + } + else + iterPair.first->second += aContentEmbedded; + } +} + +void SvXMLNumFmtElementContext::endFastElement(sal_Int32 ) +{ + bool bEffLong = bLong; + switch (nType) + { + case SvXMLStyleTokens::Text: + if ( rParent.HasLongDoW() && + std::u16string_view(aContent) == rParent.GetLocaleData().getLongDateDayOfWeekSep() ) + { + // skip separator constant after long day of week + // (NF_KEY_NNNN contains the separator) + + if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) ) + { + aContent.truncate(); + } + + rParent.SetHasLongDoW( false ); // only once + } + if ( !aContent.isEmpty() ) + { + lcl_EnquoteIfNecessary( aContent, rParent ); + if ( !sBlankWidthString.isEmpty() ) + { + lcl_InsertBlankWidthChars( sBlankWidthString, aContent ); + sBlankWidthString = ""; + } + rParent.AddToCode( aContent ); + aContent.setLength(0); + } + else + { + // Quoted empty text may be significant to separate. + aContent.append("\"\""); + rParent.AddToCode( aContent ); + aContent.setLength(0); + rParent.SetHasTrailingEmptyText(true); // *after* AddToCode() + } + break; + + case SvXMLStyleTokens::Number: + rParent.AddNumber( aNumInfo ); + break; + + case SvXMLStyleTokens::CurrencySymbol: + rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang ); + break; + + case SvXMLStyleTokens::TextContent: + rParent.AddToCode( '@'); + break; + case SvXMLStyleTokens::FillCharacter: + if ( !aContent.isEmpty() ) + { + rParent.AddToCode( '*' ); + rParent.AddToCode( aContent[0] ); + } + break; + case SvXMLStyleTokens::Boolean: + rParent.AddNfKeyword( NF_KEY_BOOLEAN ); + break; + + case SvXMLStyleTokens::Day: + rParent.UpdateCalendar( sCalendar ); +//! I18N doesn't provide SYSTEM or extended date information yet + + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_DD : NF_KEY_D ) ); + break; + case SvXMLStyleTokens::Month: + rParent.UpdateCalendar( sCalendar ); +//! I18N doesn't provide SYSTEM or extended date information yet + + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bTextual + ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM ) + : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) ); + break; + case SvXMLStyleTokens::Year: +//! I18N doesn't provide SYSTEM or extended date information yet + { + // Y after G (era) is replaced by E for a secondary calendar. + // Do not replace for default calendar. + // Also replace Y by E if we're switching to the secondary + // calendar of a locale if it is known to implicitly use E. + rParent.UpdateCalendar( sCalendar); + const SvXMLNumFormatContext::ImplicitCalendar eCal = rParent.GetImplicitCalendarState(); + if (eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY + || eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER) + { + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_EEC : NF_KEY_EC ) ); + } + else + { + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) ); + } + } + break; + case SvXMLStyleTokens::Era: + rParent.UpdateCalendar( sCalendar ); +//! I18N doesn't provide SYSTEM or extended date information yet + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_GGG : NF_KEY_G ) ); + // HasEra flag is set + break; + case SvXMLStyleTokens::DayOfWeek: +//! I18N doesn't provide SYSTEM or extended date information yet + { + // Implicit secondary calendar uses A keyword, default and + // explicit calendar N keyword. + rParent.UpdateCalendar( sCalendar); + const SvXMLNumFormatContext::ImplicitCalendar eCal = rParent.GetImplicitCalendarState(); + if (eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY + || eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER) + { + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_AAAA : NF_KEY_AAA ) ); + } + else + { + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) ); + } + } + break; + case SvXMLStyleTokens::WeekOfYear: + rParent.UpdateCalendar( sCalendar ); + rParent.AddNfKeyword( NF_KEY_WW ); + break; + case SvXMLStyleTokens::Quarter: + rParent.UpdateCalendar( sCalendar ); + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_QQ : NF_KEY_Q ) ); + break; + case SvXMLStyleTokens::Hours: + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_HH : NF_KEY_H ) ); + break; + case SvXMLStyleTokens::AmPm: + //! short/long? + rParent.AddNfKeyword( NF_KEY_AMPM ); + break; + case SvXMLStyleTokens::Minutes: + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_MMI : NF_KEY_MI ) ); + break; + case SvXMLStyleTokens::Seconds: + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_SS : NF_KEY_S ) ); + if ( aNumInfo.nDecimals > 0 ) + { + // manually add the decimal places + rParent.AddToCode(rParent.GetLocaleData().getNumDecimalSep()); + for (sal_Int32 i=0; i<aNumInfo.nDecimals; i++) + { + rParent.AddToCode( '0'); + } + } + break; + + case SvXMLStyleTokens::Fraction: + { + if ( aNumInfo.nInteger >= 0 ) + { + // add integer part only if min-integer-digits attribute is there + aNumInfo.nDecimals = 0; + rParent.AddNumber( aNumInfo ); // number without decimals + OUStringBuffer sIntegerFractionDelimiter(aNumInfo.aIntegerFractionDelimiter); + lcl_EnquoteIfNecessary( sIntegerFractionDelimiter, rParent ); + rParent.AddToCode( sIntegerFractionDelimiter ); // default is ' ' + } + + //! build string and add at once + + sal_Int32 i; + for (i=aNumInfo.nMaxNumerDigits; i > 0; i--) + { + if ( i > aNumInfo.nMinNumerDigits ) + rParent.AddToCode( '#' ); + else if ( i > aNumInfo.nZerosNumerDigits ) + rParent.AddToCode( '?' ); + else + rParent.AddToCode( '0' ); + } + rParent.AddToCode( '/' ); + if ( aNumInfo.nFracDenominator > 0 ) + { + rParent.AddToCode( OUString::number( aNumInfo.nFracDenominator ) ); + } + else + { + for (i=aNumInfo.nMaxDenomDigits; i > 0 ; i--) + { + if ( i > aNumInfo.nMinDenomDigits ) + rParent.AddToCode( '#' ); + else if ( i > aNumInfo.nZerosDenomDigits ) + rParent.AddToCode( '?' ); + else + rParent.AddToCode( '0' ); + } + } + } + break; + + case SvXMLStyleTokens::ScientificNumber: + { + // exponential interval for engineering notation + if( !aNumInfo.bGrouping && aNumInfo.nExpInterval > aNumInfo.nInteger ) + { + for (sal_Int32 i=aNumInfo.nInteger; i<aNumInfo.nExpInterval; i++) + { + rParent.AddToCode( '#' ); + } + } + rParent.AddNumber( aNumInfo ); // number and exponent + } + break; + + default: + assert(false && "invalid element ID"); + } +} + +sal_uInt16 SvXMLNumFmtDefaults::GetDefaultDateFormat( SvXMLDateElementAttributes eDOW, + SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth, + SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours, + SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs, + bool bSystem ) +{ + for (const auto & rEntry : aDefaultDateFormats) + { + if ( bSystem == rEntry.bSystem && + ( eDOW == rEntry.eDOW || ( rEntry.eDOW == XML_DEA_ANY && eDOW != XML_DEA_NONE ) ) && + ( eDay == rEntry.eDay || ( rEntry.eDay == XML_DEA_ANY && eDay != XML_DEA_NONE ) ) && + ( eMonth == rEntry.eMonth || ( rEntry.eMonth == XML_DEA_ANY && eMonth != XML_DEA_NONE ) ) && + ( eYear == rEntry.eYear || ( rEntry.eYear == XML_DEA_ANY && eYear != XML_DEA_NONE ) ) && + ( eHours == rEntry.eHours || ( rEntry.eHours == XML_DEA_ANY && eHours != XML_DEA_NONE ) ) && + ( eMins == rEntry.eMins || ( rEntry.eMins == XML_DEA_ANY && eMins != XML_DEA_NONE ) ) && + ( eSecs == rEntry.eSecs || ( rEntry.eSecs == XML_DEA_ANY && eSecs != XML_DEA_NONE ) ) ) + { + return sal::static_int_cast< sal_uInt16 >(rEntry.eFormat); + } + } + + return NF_INDEX_TABLE_ENTRIES; // invalid +} + + +// SvXMLNumFormatContext + +SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumImpData* pNewData, SvXMLStylesTokens nNewType, + const uno::Reference<xml::sax::XFastAttributeList>& xAttrList, + SvXMLStylesContext& rStyles ) : + SvXMLStyleContext( rImport ), + m_pData( pNewData ), + m_pStyles( &rStyles ), + m_nType( nNewType ), + m_nKey(-1), + m_eImplicitCalendar(ImplicitCalendar::DEFAULT), + m_nFormatLang( LANGUAGE_SYSTEM ), + m_bAutoOrder( false ), + m_bFromSystem( false ), + m_bTruncate( true ), + m_bAutoDec( false ), + m_bAutoInt( false ), + m_bHasExtraText( false ), + m_bHasTrailingEmptyText( false ), + m_bHasLongDoW( false ), + m_bHasDateTime( false ), + m_bRemoveAfterUse( false ), + m_eDateDOW( XML_DEA_NONE ), + m_eDateDay( XML_DEA_NONE ), + m_eDateMonth( XML_DEA_NONE ), + m_eDateYear( XML_DEA_NONE ), + m_eDateHours( XML_DEA_NONE ), + m_eDateMins( XML_DEA_NONE ), + m_eDateSecs( XML_DEA_NONE ), + m_bDateNoDefault( false ) +{ + LanguageTagODF aLanguageTagODF; + css::i18n::NativeNumberXmlAttributes aNatNumAttr; + OUString aSpellout; + bool bAttrBool(false); + + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + switch (aIter.getToken()) + { + // attributes for a style + case XML_ELEMENT(STYLE, XML_NAME): + break; + case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG): + aLanguageTagODF.maRfcLanguageTag = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_LANGUAGE): + aLanguageTagODF.maLanguage = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_SCRIPT): + aLanguageTagODF.maScript = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_COUNTRY): + aLanguageTagODF.maCountry = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_TITLE): + m_sFormatTitle = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_AUTOMATIC_ORDER): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + m_bAutoOrder = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_FORMAT_SOURCE): + SvXMLUnitConverter::convertEnum( m_bFromSystem, aIter.toView(), aFormatSourceMap ); + break; + case XML_ELEMENT(NUMBER, XML_TRUNCATE_ON_OVERFLOW): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + m_bTruncate = bAttrBool; + break; + case XML_ELEMENT(STYLE, XML_VOLATILE): + // volatile formats can be removed after importing + // if not used in other styles + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + m_bRemoveAfterUse = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_FORMAT): + aNatNumAttr.Format = aIter.toString(); + break; + case XML_ELEMENT(LO_EXT, XML_TRANSLITERATION_SPELLOUT): + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_SPELLOUT): + aSpellout = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_LANGUAGE): + aNatNumAttr.Locale.Language = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_COUNTRY): + aNatNumAttr.Locale.Country = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_STYLE): + aNatNumAttr.Style = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if (!aLanguageTagODF.isEmpty()) + { + m_nFormatLang = aLanguageTagODF.getLanguageTag().getLanguageType( false); + if ( m_nFormatLang == LANGUAGE_DONTKNOW ) + m_nFormatLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? + } + + if (aNatNumAttr.Format.isEmpty() && aSpellout.isEmpty()) + return; + + LanguageTag aLanguageTag( OUString(), aNatNumAttr.Locale.Language, + std::u16string_view(), aNatNumAttr.Locale.Country); + aNatNumAttr.Locale = aLanguageTag.getLocale( false); + + // NatNum12 spell out formula (cardinal, ordinal, ordinal-feminine etc.) + if ( !aSpellout.isEmpty() ) + { + m_aFormatCode.append( "[NatNum12 " ); + m_aFormatCode.append( aSpellout ); + } else { + SvNumberFormatter* pFormatter = m_pData->GetNumberFormatter(); + if ( !pFormatter ) return; + + sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr ); + m_aFormatCode.append( "[NatNum" ); + m_aFormatCode.append( nNatNum ); + } + + LanguageType eLang = aLanguageTag.getLanguageType( false ); + if ( eLang == LANGUAGE_DONTKNOW ) + eLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? + if ( eLang != m_nFormatLang && eLang != LANGUAGE_SYSTEM ) + { + m_aFormatCode.append( "][$-" ); + // language code in upper hex: + m_aFormatCode.append(OUString::number(static_cast<sal_uInt16>(eLang), 16).toAsciiUpperCase()); + } + m_aFormatCode.append( ']' ); +} + +SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, + const OUString& rName, + const uno::Reference<xml::sax::XFastAttributeList>& /*xAttrList*/, + const sal_Int32 nTempKey, LanguageType nLang, + SvXMLStylesContext& rStyles ) : + SvXMLStyleContext( rImport, XmlStyleFamily::DATA_STYLE ), + m_pData( nullptr ), + m_pStyles( &rStyles ), + m_nType( SvXMLStylesTokens::NUMBER_STYLE ), + m_nKey(nTempKey), + m_eImplicitCalendar(ImplicitCalendar::DEFAULT), + m_nFormatLang( nLang ), + m_bAutoOrder( false ), + m_bFromSystem( false ), + m_bTruncate( true ), + m_bAutoDec( false ), + m_bAutoInt( false ), + m_bHasExtraText( false ), + m_bHasTrailingEmptyText( false ), + m_bHasLongDoW( false ), + m_bHasDateTime( false ), + m_bRemoveAfterUse( false ), + m_eDateDOW( XML_DEA_NONE ), + m_eDateDay( XML_DEA_NONE ), + m_eDateMonth( XML_DEA_NONE ), + m_eDateYear( XML_DEA_NONE ), + m_eDateHours( XML_DEA_NONE ), + m_eDateMins( XML_DEA_NONE ), + m_eDateSecs( XML_DEA_NONE ), + m_bDateNoDefault( false ) +{ + SetAttribute(XML_ELEMENT(STYLE, XML_NAME), rName); +} + +SvXMLNumFormatContext::~SvXMLNumFormatContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFormatContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + + switch (nElement) + { + case XML_ELEMENT(LO_EXT, XML_TEXT): + case XML_ELEMENT(NUMBER, XML_TEXT): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Text, xAttrList ); + break; + case XML_ELEMENT(LO_EXT, XML_FILL_CHARACTER): + case XML_ELEMENT(NUMBER, XML_FILL_CHARACTER): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::FillCharacter, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_NUMBER): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Number, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_SCIENTIFIC_NUMBER): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::ScientificNumber, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_FRACTION): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Fraction, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_CURRENCY_SYMBOL): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::CurrencySymbol, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_DAY): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Day, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_MONTH): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Month, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_YEAR): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Year, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_ERA): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Era, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_DAY_OF_WEEK): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::DayOfWeek, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_WEEK_OF_YEAR): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::WeekOfYear, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_QUARTER): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Quarter, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_HOURS): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Hours, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_AM_PM): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::AmPm, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_MINUTES): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Minutes, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_SECONDS): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Seconds, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_BOOLEAN): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Boolean, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_TEXT_CONTENT): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::TextContent, xAttrList ); + break; + + case XML_ELEMENT(STYLE, XML_TEXT_PROPERTIES): + pContext = new SvXMLNumFmtPropContext( GetImport(), nElement, + *this, xAttrList ); + break; + case XML_ELEMENT(STYLE, XML_MAP): + { + // SvXMLNumFmtMapContext::EndElement adds to aMyConditions, + // so there's no need for an extra flag + pContext = new SvXMLNumFmtMapContext( GetImport(), nElement, + *this, xAttrList ); + } + break; + } + + if( !pContext ) + { + SAL_WARN("xmloff.core", "No context for unknown-element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); + pContext = new SvXMLImportContext(GetImport()); + } + + return pContext; +} + +sal_Int32 SvXMLNumFormatContext::GetKey() +{ + if (m_nKey > -1) + { + if (m_bRemoveAfterUse) + { + // format is used -> don't remove + m_bRemoveAfterUse = false; + if (m_pData) + m_pData->SetUsed(m_nKey); + + // Add to import's list of keys now - CreateAndInsert didn't add + // the style if bRemoveAfterUse was set. + GetImport().AddNumberStyle( m_nKey, GetName() ); + } + return m_nKey; + } + else + { + // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set + m_bRemoveAfterUse = false; + CreateAndInsert(true); + return m_nKey; + } +} + +sal_Int32 SvXMLNumFormatContext::PrivateGetKey() +{ + // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag + + if (m_nKey > -1) + return m_nKey; + else + { + CreateAndInsert(true); + return m_nKey; + } +} + +sal_Int32 SvXMLNumFormatContext::CreateAndInsert( css::uno::Reference< css::util::XNumberFormatsSupplier > const & xFormatsSupplier ) +{ + if (m_nKey <= -1) + { + SvNumberFormatter* pFormatter = nullptr; + SvNumberFormatsSupplierObj* pObj = + comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xFormatsSupplier ); + if (pObj) + pFormatter = pObj->GetNumberFormatter(); + + if ( pFormatter ) + return CreateAndInsert( pFormatter ); + else + return -1; + } + else + return m_nKey; +} + +void SvXMLNumFormatContext::CreateAndInsert(bool /*bOverwrite*/) +{ + if (m_nKey <= -1) + CreateAndInsert(m_pData->GetNumberFormatter()); +} + +sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter) +{ + if (!pFormatter) + { + OSL_FAIL("no number formatter"); + return -1; + } + + sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND; + + for (size_t i = 0; i < m_aMyConditions.size(); i++) + { + SvXMLNumFormatContext* pStyle = const_cast<SvXMLNumFormatContext*>( static_cast<const SvXMLNumFormatContext *>(m_pStyles->FindStyleChildContext( + XmlStyleFamily::DATA_STYLE, m_aMyConditions[i].sMapName))); + if (this == pStyle) + { + SAL_INFO("xmloff.style", "invalid style:map references containing style"); + pStyle = nullptr; + } + if (pStyle) + { + if (pStyle->PrivateGetKey() > -1) // don't reset pStyle's bRemoveAfterUse flag + AddCondition(i); + } + } + + sal_Int32 nBufLen; + if ( m_aFormatCode.isEmpty() ) + { + // insert empty format as empty string (with quotes) + // #93901# this check has to be done before inserting the conditions + m_aFormatCode.append("\"\""); // "" + } + else if (m_bHasTrailingEmptyText && (nBufLen = m_aFormatCode.getLength()) >= 3) + { + // Remove a trailing empty text. Earlier this may had been written to + // file, like in "General;General" written with elements for + // 'General"";General""' (whyever); when reading, empty text was + // ignored, which it isn't anymore, so get rid of those. + if (m_aFormatCode[nBufLen-1] == '"' && m_aFormatCode[nBufLen-2] == '"') + m_aFormatCode.truncate( nBufLen - 2); + } + + m_aFormatCode.insert( 0, m_aConditions ); + m_aConditions.setLength(0); + OUString sFormat = m_aFormatCode.makeStringAndClear(); + + // test special cases + + if ( m_bAutoDec ) // automatic decimal places + { + // #99391# adjust only if the format contains no text elements, no conditions + // and no color definition (detected by the '[' at the start) + + if ( m_nType == SvXMLStylesTokens::NUMBER_STYLE && !m_bHasExtraText && + m_aMyConditions.empty() && sFormat.toChar() != '[' ) + nIndex = pFormatter->GetStandardIndex( m_nFormatLang ); + } + if ( m_bAutoInt ) // automatic integer digits + { + //! only if two decimal places was set? + + if ( m_nType == SvXMLStylesTokens::NUMBER_STYLE && !m_bHasExtraText && + m_aMyConditions.empty() && sFormat.toChar() != '[' ) + nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, m_nFormatLang ); + } + + if ( m_nType == SvXMLStylesTokens::BOOLEAN_STYLE && !m_bHasExtraText && + m_aMyConditions.empty() && sFormat.toChar() != '[' ) + nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, m_nFormatLang ); + + // check for default date formats + if ( m_nType == SvXMLStylesTokens::DATE_STYLE && m_bAutoOrder && !m_bDateNoDefault ) + { + NfIndexTableOffset eFormat = static_cast<NfIndexTableOffset>(SvXMLNumFmtDefaults::GetDefaultDateFormat( + m_eDateDOW, m_eDateDay, m_eDateMonth, m_eDateYear, + m_eDateHours, m_eDateMins, m_eDateSecs, m_bFromSystem )); + if ( eFormat < NF_INDEX_TABLE_RESERVED_START ) + { + // #109651# if a date format has the automatic-order attribute and + // contains exactly the elements of one of the default date formats, + // use that default format, with the element order and separators + // from the current locale settings + + nIndex = pFormatter->GetFormatIndex( eFormat, m_nFormatLang ); + } + } + + if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && !sFormat.isEmpty() ) + { + // insert by format string + + OUString aFormatStr( sFormat ); + nIndex = pFormatter->GetEntryKey( aFormatStr, m_nFormatLang ); + if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { + sal_Int32 nErrPos = 0; + SvNumFormatType l_nType = SvNumFormatType::ALL; + bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, m_nFormatLang ); + if ( !bOk && nErrPos == 0 && aFormatStr != sFormat ) + { + // if the string was modified by PutEntry, look for an existing format + // with the modified string + nIndex = pFormatter->GetEntryKey( aFormatStr, m_nFormatLang ); + if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND ) + bOk = true; + } + if (!bOk) + nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND; + } + } + +//! I18N doesn't provide SYSTEM or extended date information yet + if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !m_bAutoOrder ) + { + // use fixed-order formats instead of SYS... if bAutoOrder is false + // (only if the format strings are equal for the locale) + + NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex ); + if ( eOffset == NF_DATE_SYS_DMMMYYYY ) + { + sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, m_nFormatLang ); + const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex ); + const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex ); + if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() ) + nIndex = nNewIndex; + } + else if ( eOffset == NF_DATE_SYS_DMMMMYYYY ) + { + sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, m_nFormatLang ); + const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex ); + const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex ); + if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() ) + nIndex = nNewIndex; + } + } + + if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && !m_sFormatTitle.isEmpty()) + { + SvNumberformat* pFormat = const_cast<SvNumberformat*>(pFormatter->GetEntry( nIndex )); + if (pFormat) + { + pFormat->SetComment(m_sFormatTitle); + } + } + + if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { + OSL_FAIL("invalid number format"); + nIndex = pFormatter->GetStandardIndex( m_nFormatLang ); + } + + m_pData->AddKey( nIndex, GetName(), m_bRemoveAfterUse ); + m_nKey = nIndex; + + // Add to import's list of keys (shared between styles and content import) + // only if not volatile - formats are removed from NumberFormatter at the + // end of each import (in SvXMLNumFmtHelper dtor). + // If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there. + + if (!m_bRemoveAfterUse) + GetImport().AddNumberStyle( m_nKey, GetName() ); + + return m_nKey; +} + +const LocaleDataWrapper& SvXMLNumFormatContext::GetLocaleData() const +{ + return m_pData->GetLocaleData( m_nFormatLang ); +} + +void SvXMLNumFormatContext::AddToCode( sal_Unicode c ) +{ + m_aFormatCode.append( c ); + m_bHasExtraText = true; +} + +void SvXMLNumFormatContext::AddToCode( std::u16string_view rString ) +{ + m_aFormatCode.append( rString ); + m_bHasExtraText = true; + m_bHasTrailingEmptyText = false; // is set by caller again if so +} + +void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) +{ + SvNumberFormatter* pFormatter = m_pData->GetNumberFormatter(); + if (!pFormatter) + return; + + // store special conditions + m_bAutoDec = ( rInfo.nDecimals < 0 ); + m_bAutoInt = ( rInfo.nInteger < 0 ); + + sal_uInt16 nPrec = 0; + sal_uInt16 nLeading = 0; + if ( rInfo.nDecimals >= 0 ) // < 0 : Default + nPrec = static_cast<sal_uInt16>(rInfo.nDecimals); + if ( rInfo.nInteger >= 0 ) // < 0 : Default + nLeading = static_cast<sal_uInt16>(rInfo.nInteger); + + if ( m_bAutoDec ) + { + if ( m_nType == SvXMLStylesTokens::CURRENCY_STYLE ) + { + // for currency formats, "automatic decimals" is used for the automatic + // currency format with (fixed) decimals from the locale settings + + const LocaleDataWrapper& rLoc = m_pData->GetLocaleData( m_nFormatLang ); + nPrec = rLoc.getCurrDigits(); + } + else + { + // for other types, "automatic decimals" means dynamic determination of + // decimals, as achieved with the "general" keyword + + m_aFormatCode.append( pFormatter->GetStandardName( m_nFormatLang ) ); + return; + } + } + if ( m_bAutoInt ) + { + //!... + } + + sal_uInt16 nGenPrec = nPrec; + if ( rInfo.nMinDecimalDigits >= 0 ) + nGenPrec = rInfo.nMinDecimalDigits; + if ( rInfo.bDecReplace ) + nGenPrec = 0; // generate format without decimals... + + bool bGrouping = rInfo.bGrouping; + size_t const nEmbeddedCount = rInfo.m_EmbeddedElements.size(); + if ( nEmbeddedCount && rInfo.m_EmbeddedElements.rbegin()->first > 0 ) + bGrouping = false; // grouping and embedded characters in integer part can't be used together + + sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( m_nFormatLang ); + OUStringBuffer aNumStr(pFormatter->GenerateFormat( nStdIndex, m_nFormatLang, + bGrouping, false, nGenPrec, nLeading )); + + if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 ) + { + // #i43959# For scientific numbers, "#" in the integer part forces a digit, + // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0"). + + aNumStr.stripStart('#'); + } + + if ( rInfo.nBlankInteger > 0 ) + { + // Replace nBlankInteger '0' by '?' + sal_Int32 nIndex = 0; + sal_Int32 nBlanks = rInfo.nBlankInteger; + sal_Int32 nIntegerEnd = aNumStr.indexOf( pFormatter->GetNumDecimalSep() ); + if ( nIntegerEnd < 0 ) + nIntegerEnd = aNumStr.getLength(); + while ( nIndex < nIntegerEnd && nBlanks > 0 ) + { + if ( aNumStr[nIndex] == '0' ) + { + aNumStr[nIndex] = '?'; + nBlanks--; + } + nIndex++; + } + } + + if ( bGrouping && rInfo.nExpInterval > rInfo.nInteger ) + { + sal_Int32 nIndex = 0; + sal_Int32 nDigits = rInfo.nInteger; + sal_Int32 nIntegerEnd = aNumStr.indexOf( pFormatter->GetNumDecimalSep() ); + if ( nIntegerEnd < 0 ) + nIntegerEnd = aNumStr.getLength(); + while ( nIndex >= 0 && nIndex < nIntegerEnd ) + { + if ( ( nIndex = aNumStr.indexOf( '#', nIndex ) ) >= 0 ) + { + nDigits ++; + nIndex ++; + } + else + nIndex = -1; + } + while ( rInfo.nExpInterval > nDigits ) + { + nDigits++; + aNumStr.insert( 0, '#' ); + } + } + + if ( ( rInfo.bDecReplace || rInfo.nMinDecimalDigits < rInfo.nDecimals ) && nPrec ) // add decimal replacement (dashes) + { + // add dashes for explicit decimal replacement, # or ? for variable decimals + sal_Unicode cAdd = rInfo.bDecReplace ? '-' : ( rInfo.bDecAlign ? '?': '#' ); + + if ( rInfo.nMinDecimalDigits == 0 ) + aNumStr.append( m_pData->GetLocaleData( m_nFormatLang ).getNumDecimalSep() ); + for ( sal_uInt16 i=rInfo.nMinDecimalDigits; i<nPrec; i++) + aNumStr.append( cAdd ); + } + + // Scientific number + sal_Int32 nExpPos = -1; + if ( rInfo.nExpDigits > 0 ) + { + nExpPos = aNumStr.getLength(); + aNumStr.append( rInfo.bExponentLowercase ? u"e" : u"E" ); + // exponent sign is required with embedded text in exponent + if ( rInfo.bExpSign || ( nEmbeddedCount && ( rInfo.nDecimals + 1 < -rInfo.m_EmbeddedElements.begin()->first ) ) ) + { + aNumStr.append( u"+" ); + } + for (sal_Int32 i=0; i<rInfo.nExpDigits; i++) + { + if ( i < rInfo.nBlankExp ) + aNumStr.append( '?' ); + else + aNumStr.append( '0' ); + } + } + + if ( nEmbeddedCount ) + { + // insert embedded strings into number string + // support integer (position >=0) and decimal (position <0) part + // nZeroPos is the string position where format position 0 is inserted + + sal_Int32 nZeroPos = aNumStr.indexOf( m_pData->GetLocaleData( m_nFormatLang ).getNumDecimalSep() ); + if ( nZeroPos < 0 ) + { + nZeroPos = aNumStr.getLength(); + } + + // m_EmbeddedElements is sorted - last entry has the largest position (leftmost) + sal_Int32 const nLastFormatPos = rInfo.m_EmbeddedElements.rbegin()->first; + if ( nLastFormatPos >= nZeroPos ) + { + // add '#' characters so all embedded texts are really embedded in digits + // (there always has to be a digit before the leftmost embedded text) + + sal_Int32 nAddCount = nLastFormatPos + 1 - nZeroPos; + for(sal_Int32 index = 0; index < nAddCount; ++index) + { + aNumStr.insert(0, '#'); + } + nZeroPos = nZeroPos + nAddCount; + if ( nExpPos > 0 ) + nExpPos = nExpPos + nAddCount; + } + + // m_EmbeddedElements is sorted with ascending positions - loop is from right to left + for (auto const& it : rInfo.m_EmbeddedElements) + { + sal_Int32 const nFormatPos = it.first; + sal_Int32 nInsertPos = nZeroPos - nFormatPos; + if ( nExpPos > 0 && nInsertPos > nExpPos ) + nInsertPos ++; + if ( 0 <= nInsertPos && nInsertPos <= aNumStr.getLength() ) + { + aNumStr.insert( nInsertPos, it.second ); + } + } + } + + m_aFormatCode.append( aNumStr ); + + // add extra thousands separators for display factor + + if (rInfo.fDisplayFactor == 1.0 || rInfo.fDisplayFactor <= 0.0) + return; + + // test for 1.0 is just for optimization - nSepCount would be 0 + + // one separator for each factor of 1000 + sal_Int32 nSepCount = static_cast<sal_Int32>(::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 )); + if ( nSepCount > 0 ) + { + OUString aSep = m_pData->GetLocaleData( m_nFormatLang ).getNumThousandSep(); + for ( sal_Int32 i=0; i<nSepCount; i++ ) + m_aFormatCode.append( aSep ); + } +} + +void SvXMLNumFormatContext::AddCurrency( const OUString& rContent, LanguageType nLang ) +{ + bool bAutomatic = false; + OUString aSymbol = rContent; + if ( aSymbol.isEmpty()) + { + SvNumberFormatter* pFormatter = m_pData->GetNumberFormatter(); + if ( pFormatter ) + { + pFormatter->ChangeIntl( m_nFormatLang ); + OUString sCurString, sDummy; + pFormatter->GetCompatibilityCurrency( sCurString, sDummy ); + aSymbol = sCurString; + + bAutomatic = true; + } + } + else if ( nLang == LANGUAGE_SYSTEM && aSymbol == "CCC" ) + { + // "CCC" is used for automatic long symbol + bAutomatic = true; + } + + if ( bAutomatic ) + { + // remove unnecessary quotes before automatic symbol (formats like "-(0DM)") + // otherwise the currency symbol isn't recognized (#94048#) + + sal_Int32 nLength = m_aFormatCode.getLength(); + if ( nLength > 1 && m_aFormatCode[nLength - 1] == '"' ) + { + // find start of quoted string + // When SvXMLNumFmtElementContext::EndElement creates escaped quotes, + // they must be handled here, too. + + sal_Int32 nFirst = nLength - 2; + while ( nFirst >= 0 && m_aFormatCode[nFirst] != '"' ) + --nFirst; + if ( nFirst >= 0 ) + { + // remove both quotes from aFormatCode + OUString aOld = m_aFormatCode.makeStringAndClear(); + if ( nFirst > 0 ) + m_aFormatCode.append( aOld.subView( 0, nFirst ) ); + if ( nLength > nFirst + 2 ) + m_aFormatCode.append( aOld.subView( nFirst + 1, nLength - nFirst - 2 ) ); + } + } + } + + if (!bAutomatic) + m_aFormatCode.append( "[$" ); // intro for "new" currency symbols + + m_aFormatCode.append( aSymbol ); + + if (!bAutomatic) + { + if ( nLang != LANGUAGE_SYSTEM ) + { + // '-' sign and language code in hex: + m_aFormatCode.append("-" + OUString(OUString::number(sal_uInt16(nLang), 16)).toAsciiUpperCase()); + } + + m_aFormatCode.append( ']' ); // end of "new" currency symbol + } +} + +void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex ) +{ + SvNumberFormatter* pFormatter = m_pData->GetNumberFormatter(); + if (!pFormatter) + return; + + if ( nIndex == NF_KEY_NNNN ) + { + nIndex = NF_KEY_NNN; + m_bHasLongDoW = true; // to remove string constant with separator + } + + OUString sKeyword = pFormatter->GetKeyword( m_nFormatLang, nIndex ); + + if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH || + nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI || + nIndex == NF_KEY_S || nIndex == NF_KEY_SS ) + { + if ( !m_bTruncate && !m_bHasDateTime ) + { + // with truncate-on-overflow = false, add "[]" to first time part + m_aFormatCode.append("[" + sKeyword + "]"); + } + else + { + m_aFormatCode.append( sKeyword ); + } + m_bHasDateTime = true; + } + else + { + m_aFormatCode.append( sKeyword ); + } + // collect the date elements that the format contains, to recognize default date formats + switch ( nIndex ) + { + case NF_KEY_NN: m_eDateDOW = XML_DEA_SHORT; break; + case NF_KEY_NNN: + case NF_KEY_NNNN: m_eDateDOW = XML_DEA_LONG; break; + case NF_KEY_D: m_eDateDay = XML_DEA_SHORT; break; + case NF_KEY_DD: m_eDateDay = XML_DEA_LONG; break; + case NF_KEY_M: m_eDateMonth = XML_DEA_SHORT; break; + case NF_KEY_MM: m_eDateMonth = XML_DEA_LONG; break; + case NF_KEY_MMM: m_eDateMonth = XML_DEA_TEXTSHORT; break; + case NF_KEY_MMMM: m_eDateMonth = XML_DEA_TEXTLONG; break; + case NF_KEY_YY: m_eDateYear = XML_DEA_SHORT; break; + case NF_KEY_YYYY: m_eDateYear = XML_DEA_LONG; break; + case NF_KEY_H: m_eDateHours = XML_DEA_SHORT; break; + case NF_KEY_HH: m_eDateHours = XML_DEA_LONG; break; + case NF_KEY_MI: m_eDateMins = XML_DEA_SHORT; break; + case NF_KEY_MMI: m_eDateMins = XML_DEA_LONG; break; + case NF_KEY_S: m_eDateSecs = XML_DEA_SHORT; break; + case NF_KEY_SS: m_eDateSecs = XML_DEA_LONG; break; + case NF_KEY_AP: + case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself + default: + m_bDateNoDefault = true; // any other element -> no default format + } +} + +static bool lcl_IsAtEnd( OUStringBuffer& rBuffer, std::u16string_view rToken ) +{ + sal_Int32 nBufLen = rBuffer.getLength(); + sal_Int32 nTokLen = rToken.size(); + + if ( nTokLen > nBufLen ) + return false; + + sal_Int32 nStartPos = nBufLen - nTokLen; + for ( sal_Int32 nTokPos = 0; nTokPos < nTokLen; nTokPos++ ) + if ( rToken[ nTokPos ] != rBuffer[nStartPos + nTokPos] ) + return false; + + return true; +} + +bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew ) +{ + // replaces one keyword with another if it is found at the end of the code + + SvNumberFormatter* pFormatter = m_pData->GetNumberFormatter(); + if (!pFormatter) + return false; + + OUString sOldStr = pFormatter->GetKeyword( m_nFormatLang, nOld ); + if ( lcl_IsAtEnd( m_aFormatCode, sOldStr ) ) + { + // remove old keyword + m_aFormatCode.setLength( m_aFormatCode.getLength() - sOldStr.getLength() ); + + // add new keyword + OUString sNewStr = pFormatter->GetKeyword( m_nFormatLang, nNew ); + m_aFormatCode.append( sNewStr ); + + return true; // changed + } + return false; // not found +} + +void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex ) +{ + OUString rApplyName = m_aMyConditions[nIndex].sMapName; + OUString rCondition = m_aMyConditions[nIndex].sCondition; + SvNumberFormatter* pFormatter = m_pData->GetNumberFormatter(); + sal_uInt32 l_nKey = m_pData->GetKeyForName( rApplyName ); + + OUString sRealCond; + if ( !(pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND && + rCondition.startsWith("value()", &sRealCond)) ) + return; + + //! test for valid conditions + //! test for default conditions + + bool bDefaultCond = false; + + //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count + //! allow blanks in conditions + if ( m_aConditions.isEmpty() && m_aMyConditions.size() == 1 && sRealCond == ">=0" ) + bDefaultCond = true; + + if ( m_nType == SvXMLStylesTokens::TEXT_STYLE && static_cast<size_t>(nIndex) == m_aMyConditions.size() - 1 ) + { + // The last condition in a number format with a text part can only + // be "all other numbers", the condition string must be empty. + bDefaultCond = true; + } + + if (!bDefaultCond) + { + // Convert != to <> + sal_Int32 nPos = sRealCond.indexOf( "!=" ); + if ( nPos >= 0 ) + { + sRealCond = sRealCond.replaceAt( nPos, 2, u"<>" ); + } + + nPos = sRealCond.indexOf( '.' ); + if ( nPos >= 0 ) + { + // #i8026# #103991# localize decimal separator + const OUString& rDecSep = GetLocaleData().getNumDecimalSep(); + if ( rDecSep.getLength() > 1 || rDecSep[0] != '.' ) + { + sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep ); + } + } + m_aConditions.append("[" + sRealCond + "]"); + } + + const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey); + if ( pFormat ) + m_aConditions.append( pFormat->GetFormatstring() ); + + m_aConditions.append( ';' ); +} + +void SvXMLNumFormatContext::AddCondition( const OUString& rCondition, const OUString& rApplyName ) +{ + MyCondition aCondition; + aCondition.sCondition = rCondition; + aCondition.sMapName = rApplyName; + m_aMyConditions.push_back(aCondition); +} + +void SvXMLNumFormatContext::AddColor( Color const nColor ) +{ + SvNumberFormatter* pFormatter = m_pData->GetNumberFormatter(); + if (!pFormatter) + return; + + OUStringBuffer aColName; + for ( sal_uInt16 i=0; i<XML_NUMF_COLORCOUNT; i++ ) + if (nColor == aNumFmtStdColors[i]) + { + aColName = pFormatter->GetKeyword( m_nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) ); + break; + } + + if ( !aColName.isEmpty() ) + { + aColName.insert( 0, '[' ); + aColName.append( ']' ); + m_aFormatCode.insert( 0, aColName ); + } +} + +void SvXMLNumFormatContext::UpdateCalendar( const OUString& rNewCalendar ) +{ + if ( rNewCalendar == m_sCalendar ) + return; + + if (rNewCalendar.isEmpty() || rNewCalendar == m_aImplicitCalendar[0]) + { + m_eImplicitCalendar = (m_eImplicitCalendar == ImplicitCalendar::OTHER ? + ImplicitCalendar::DEFAULT_FROM_OTHER : ImplicitCalendar::DEFAULT); + } + else if (m_aImplicitCalendar[0].isEmpty() && rNewCalendar == GetLocaleData().getDefaultCalendar()->Name) + { + m_eImplicitCalendar = (m_eImplicitCalendar == ImplicitCalendar::OTHER ? + ImplicitCalendar::DEFAULT_FROM_OTHER : ImplicitCalendar::DEFAULT); + m_aImplicitCalendar[0] = rNewCalendar; + } + else if (rNewCalendar == m_aImplicitCalendar[1]) + { + m_eImplicitCalendar = (m_eImplicitCalendar == ImplicitCalendar::OTHER ? + ImplicitCalendar::SECONDARY_FROM_OTHER : ImplicitCalendar::SECONDARY); + } + else if (m_aImplicitCalendar[1].isEmpty() && GetLocaleData().doesSecondaryCalendarUseEC( rNewCalendar)) + { + m_eImplicitCalendar = (m_eImplicitCalendar == ImplicitCalendar::OTHER ? + ImplicitCalendar::SECONDARY_FROM_OTHER : ImplicitCalendar::SECONDARY); + m_aImplicitCalendar[1] = rNewCalendar; + } + else + { + m_eImplicitCalendar = ImplicitCalendar::OTHER; + } + + if (m_eImplicitCalendar != ImplicitCalendar::DEFAULT && m_eImplicitCalendar != ImplicitCalendar::SECONDARY) + { + // A switch from empty default calendar to named default calendar or + // vice versa is not a switch. + bool bSameDefault = false; + if (m_sCalendar.isEmpty() || rNewCalendar.isEmpty()) + { + // As both are not equal, only one can be empty here, the other + // can not. + const OUString& rDefaultCalendar = GetLocaleData().getDefaultCalendar()->Name; + // So if one is the named default calendar the other is the + // empty default calendar. + bSameDefault = (rNewCalendar == rDefaultCalendar || m_sCalendar == rDefaultCalendar); + } + if (!bSameDefault) + { + m_aFormatCode.append( "[~" ); // intro for calendar code + if (rNewCalendar.isEmpty()) + { + // Empty calendar name here means switching to default calendar + // from a different calendar. Needs to be explicitly stated in + // format code. + m_aFormatCode.append( GetLocaleData().getDefaultCalendar()->Name ); + } + else + { + m_aFormatCode.append( rNewCalendar ); + } + m_aFormatCode.append( ']' ); // end of calendar code + } + } + m_sCalendar = rNewCalendar; +} + +bool SvXMLNumFormatContext::IsSystemLanguage() const +{ + return m_nFormatLang == LANGUAGE_SYSTEM; +} + + +// SvXMLNumFmtHelper + + +SvXMLNumFmtHelper::SvXMLNumFmtHelper( + const uno::Reference<util::XNumberFormatsSupplier>& rSupp, + const uno::Reference<uno::XComponentContext>& rxContext ) +{ + SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); + + SvNumberFormatter* pFormatter = nullptr; + SvNumberFormatsSupplierObj* pObj = + comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp ); + if (pObj) + pFormatter = pObj->GetNumberFormatter(); + + m_pData = std::make_unique<SvXMLNumImpData>( pFormatter, rxContext ); +} + +SvXMLNumFmtHelper::SvXMLNumFmtHelper( + SvNumberFormatter* pNumberFormatter, + const uno::Reference<uno::XComponentContext>& rxContext ) +{ + SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); + + m_pData = std::make_unique<SvXMLNumImpData>( pNumberFormatter, rxContext ); +} + +SvXMLNumFmtHelper::~SvXMLNumFmtHelper() +{ + // remove temporary (volatile) formats from NumberFormatter + m_pData->RemoveVolatileFormats(); +} + + +SvXMLStyleContext* SvXMLNumFmtHelper::CreateChildContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + SvXMLStylesContext& rStyles ) +{ + SvXMLStylesTokens nStyleToken; + switch (nElement) + { + case XML_ELEMENT(NUMBER, XML_NUMBER_STYLE): + nStyleToken = SvXMLStylesTokens::NUMBER_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_CURRENCY_STYLE): + nStyleToken = SvXMLStylesTokens::CURRENCY_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_PERCENTAGE_STYLE): + nStyleToken = SvXMLStylesTokens::PERCENTAGE_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_DATE_STYLE): + nStyleToken = SvXMLStylesTokens::DATE_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_TIME_STYLE): + nStyleToken = SvXMLStylesTokens::TIME_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_BOOLEAN_STYLE): + nStyleToken = SvXMLStylesTokens::BOOLEAN_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_TEXT_STYLE): + nStyleToken = SvXMLStylesTokens::TEXT_STYLE; + break; + default: + // return NULL if not a data style, caller must handle other elements + return nullptr; + } + return new SvXMLNumFormatContext( rImport, nElement, + m_pData.get(), nStyleToken, xAttrList, rStyles ); +} + +LanguageType SvXMLNumFmtHelper::GetLanguageForKey(sal_Int32 nKey) const +{ + if (m_pData->GetNumberFormatter()) + { + const SvNumberformat* pEntry = m_pData->GetNumberFormatter()->GetEntry(nKey); + if (pEntry) + return pEntry->GetLanguage(); + } + + return LANGUAGE_SYSTEM; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlnumi.cxx b/xmloff/source/style/xmlnumi.cxx new file mode 100644 index 0000000000..0ddab1466d --- /dev/null +++ b/xmloff/source/style/xmlnumi.cxx @@ -0,0 +1,1089 @@ +/* -*- 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 <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/PositionAndSpaceMode.hpp> +#include <com/sun/star/text/LabelFollow.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> + +#include <o3tl/any.hxx> +#include <o3tl/temporary.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/propertyvalue.hxx> + +#include <tools/fontenum.hxx> +#include <tools/color.hxx> + +#include <sax/tools/converter.hxx> + +#include <vcl/vclenum.hxx> + +#include <xmloff/xmltkmap.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/XMLBase64ImportContext.hxx> +#include <xmloff/xmltoken.hxx> + +#include <xmloff/xmluconv.hxx> +#include "fonthdl.hxx" +#include <xmloff/XMLFontStylesContext.hxx> +#include <xmloff/families.hxx> +#include <xmloff/maptype.hxx> + +#include <xmloff/xmlnumi.hxx> +#include <optional> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +using namespace ::xmloff::token; +using namespace ::com::sun::star::io; + +class SvxXMLListLevelStyleContext_Impl; + +namespace { + +class SvxXMLListLevelStyleAttrContext_Impl : public SvXMLImportContext +{ + SvxXMLListLevelStyleContext_Impl& rListLevel; + +public: + + SvxXMLListLevelStyleAttrContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList >& xAttrList, + SvxXMLListLevelStyleContext_Impl& rLLevel ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +class SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl : public SvXMLImportContext +{ +public: + + SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList >& xAttrList, + SvxXMLListLevelStyleContext_Impl& rLLevel ); +}; + +} + +class SvxXMLListLevelStyleContext_Impl : public SvXMLImportContext +{ + friend SvxXMLListLevelStyleAttrContext_Impl; + + OUString sPrefix; + OUString sSuffix; + std::optional<OUString> sListFormat; // It is optional to distinguish empty format string + // from not existing format string in old docs + OUString sTextStyleName; + OUString sNumFormat; + OUString sNumLetterSync; + OUString sBulletFontName; + OUString sBulletFontStyleName; + OUString sImageURL; + + Reference < XOutputStream > xBase64Stream; + + sal_Int32 nLevel; + sal_Int32 nSpaceBefore; + sal_Int32 nMinLabelWidth; + sal_Int32 nMinLabelDist; + sal_Int32 nImageWidth; + sal_Int32 nImageHeight; + sal_Int16 nNumStartValue; + sal_Int16 nNumDisplayLevels; + + sal_Int16 eAdjust; + sal_Int16 eBulletFontFamily; + sal_Int16 eBulletFontPitch; + rtl_TextEncoding eBulletFontEncoding; + sal_Int16 eImageVertOrient; + + sal_UCS4 cBullet; + + sal_Int16 nRelSize; + Color m_nColor; + + sal_Int16 ePosAndSpaceMode; + sal_Int16 eLabelFollowedBy; + sal_Int32 nListtabStopPosition; + sal_Int32 nFirstLineIndent; + sal_Int32 nIndentAt; + + bool bBullet : 1; + bool bImage : 1; + bool bNum : 1; + bool bHasColor : 1; + + bool m_bIsLegal = false; + + void SetRelSize( sal_Int16 nRel ) { nRelSize = nRel; } + void SetColor( Color nColor ) + { m_nColor = nColor; bHasColor = true; } + void SetSpaceBefore( sal_Int32 nSet ) { nSpaceBefore = nSet; } + void SetMinLabelWidth( sal_Int32 nSet ) { nMinLabelWidth = nSet; } + void SetMinLabelDist( sal_Int32 nSet ) { nMinLabelDist = nSet; } + void SetAdjust( sal_Int16 eSet ) { eAdjust = eSet; } + + void SetBulletFontName( const OUString& rSet ) { sBulletFontName = rSet; } + void SetBulletFontStyleName( const OUString& rSet ) + { sBulletFontStyleName = rSet; } + void SetBulletFontFamily( sal_Int16 eSet ) { eBulletFontFamily = eSet; } + void SetBulletFontPitch( sal_Int16 eSet ) { eBulletFontPitch = eSet; } + void SetBulletFontEncoding( rtl_TextEncoding eSet ) + { eBulletFontEncoding = eSet; } + + void SetImageWidth( sal_Int32 nSet ) { nImageWidth = nSet; } + void SetImageHeight( sal_Int32 nSet ) { nImageHeight = nSet; } + void SetImageVertOrient( sal_Int16 eSet ) + { eImageVertOrient = eSet; } + +public: + + SvxXMLListLevelStyleContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + sal_Int32 GetLevel() const { return nLevel; } + Sequence<beans::PropertyValue> GetProperties(); + + void SetPosAndSpaceMode( sal_Int16 eValue ) + { + ePosAndSpaceMode = eValue; + } + void SetLabelFollowedBy( sal_Int16 eValue ) + { + eLabelFollowedBy = eValue; + } + void SetListtabStopPosition( sal_Int32 nValue ) + { + nListtabStopPosition = nValue; + } + void SetFirstLineIndent( sal_Int32 nValue ) + { + nFirstLineIndent = nValue; + } + void SetIndentAt( sal_Int32 nValue ) + { + nIndentAt = nValue; + } +}; + +constexpr OUStringLiteral gsStarBats( u"StarBats" ); +constexpr OUStringLiteral gsStarMath( u"StarMath" ); + +SvxXMLListLevelStyleContext_Impl::SvxXMLListLevelStyleContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList ) + +: SvXMLImportContext( rImport ) +, sNumFormat( "1" ) +, nLevel( -1 ) +, nSpaceBefore( 0 ) +, nMinLabelWidth( 0 ) +, nMinLabelDist( 0 ) +, nImageWidth( 0 ) +, nImageHeight( 0 ) +, nNumStartValue( 1 ) +, nNumDisplayLevels( 1 ) +, eAdjust( HoriOrientation::LEFT ) +, eBulletFontFamily( FAMILY_DONTKNOW ) +, eBulletFontPitch( PITCH_DONTKNOW ) +, eBulletFontEncoding( RTL_TEXTENCODING_DONTKNOW ) +, eImageVertOrient(0) +, cBullet( 0 ) +, nRelSize(0) +, m_nColor(0) +, ePosAndSpaceMode( PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION ) +, eLabelFollowedBy( LabelFollow::LISTTAB ) +, nListtabStopPosition( 0 ) +, nFirstLineIndent( 0 ) +, nIndentAt( 0 ) +, bBullet( false ) +, bImage( false ) +, bNum( false ) +, bHasColor( false ) +{ + switch (nElement & TOKEN_MASK) + { + case XML_LIST_LEVEL_STYLE_NUMBER: + case XML_OUTLINE_LEVEL_STYLE: + bNum = true; + break; + case XML_LIST_LEVEL_STYLE_BULLET: + bBullet = true; + break; + case XML_LIST_LEVEL_STYLE_IMAGE: + bImage = true; + break; + } + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(TEXT, XML_LEVEL): + nLevel = aIter.toInt32(); + if( nLevel >= 1 ) + nLevel--; + else + nLevel = 0; + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + sTextStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_BULLET_CHAR): + if (!aIter.isEmpty()) + { + cBullet = aIter.toString().iterateCodePoints(&o3tl::temporary(sal_Int32(0))); + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + if( bImage ) + sImageURL = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_TYPE): + case XML_ELEMENT(XLINK, XML_SHOW): + case XML_ELEMENT(XLINK, XML_ACTUATE): + // This properties will be ignored + break; + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + if( bNum ) + sNumFormat = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_NUM_PREFIX): + sPrefix = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_NUM_SUFFIX): + sSuffix = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_NUM_LIST_FORMAT): + case XML_ELEMENT(LO_EXT, XML_NUM_LIST_FORMAT): + sListFormat = std::make_optional(aIter.toString()); + break; + case XML_ELEMENT(LO_EXT, XML_IS_LEGAL): + m_bIsLegal = aIter.toBoolean(); + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + if( bNum ) + sNumLetterSync = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_START_VALUE): + if( bNum ) + { + sal_Int32 nTmp = aIter.toInt32(); + nNumStartValue = + (nTmp < 0) ? 1 : ( (nTmp>SHRT_MAX) ? SHRT_MAX + : static_cast<sal_Int16>(nTmp) ); + } + break; + case XML_ELEMENT(TEXT, XML_DISPLAY_LEVELS): + if( bNum ) + { + sal_Int32 nTmp = aIter.toInt32(); + nNumDisplayLevels = + (nTmp < 1) ? 1 : ( (nTmp>SHRT_MAX) ? SHRT_MAX + : static_cast<sal_Int16>(nTmp) ); + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListLevelStyleContext_Impl::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_LIST_LEVEL_PROPERTIES) || + nElement == XML_ELEMENT(STYLE, XML_TEXT_PROPERTIES) ) + { + return new SvxXMLListLevelStyleAttrContext_Impl( GetImport(), + nElement, + xAttrList, + *this ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + if( bImage && sImageURL.isEmpty() && !xBase64Stream.is() ) + { + xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( xBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), xBase64Stream ); + } + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +Sequence<beans::PropertyValue> SvxXMLListLevelStyleContext_Impl::GetProperties() +{ + if (!bBullet && !bImage && !bNum) + { + return Sequence<beans::PropertyValue>(); + } + + sal_Int16 eType = NumberingType::NUMBER_NONE; + std::vector<beans::PropertyValue> aProperties; + + if( bBullet ) + { + eType = NumberingType::CHAR_SPECIAL; + } + if( bImage ) + { + eType = NumberingType::BITMAP; + } + if( bNum ) + { + eType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( + eType, sNumFormat, sNumLetterSync, true ); + } + + if (bBullet && !sSuffix.isEmpty()) + { + sal_uInt16 const nVersion(GetImport().getGeneratorVersion()); + sal_Int32 nUPD; + sal_Int32 nBuildId; + if (GetImport().getBuildIds(nUPD, nBuildId) + && ( (SvXMLImport::OOo_1x == nVersion) + || (SvXMLImport::OOo_2x == nVersion) + || (310 == nUPD) || (320 == nUPD) || (330 == nUPD) + || ((300 == nUPD) && (nBuildId <= 9573)))) + { + // #i93908# OOo < 3.4 wrote a bogus suffix for bullet chars + sSuffix.clear(); // clear it + } + } + + if (!sListFormat.has_value()) + { + // This is older document: it has no list format, but can probably contain prefix and/or suffix + // Generate list format string, based on this + sListFormat = std::make_optional(sPrefix); + + for (int i = 1; i <= nNumDisplayLevels; i++) + { + *sListFormat += "%"; + *sListFormat += OUString::number(nLevel - nNumDisplayLevels + i + 1); + *sListFormat += "%"; + if (i != nNumDisplayLevels) + *sListFormat += "."; // Default separator for older ODT + } + + *sListFormat += sSuffix; + } + + aProperties.push_back(comphelper::makePropertyValue("NumberingType", eType)); + + aProperties.push_back(comphelper::makePropertyValue("Prefix", sPrefix)); + + aProperties.push_back(comphelper::makePropertyValue("Suffix", sSuffix)); + + aProperties.push_back(comphelper::makePropertyValue("Adjust", eAdjust)); + + sal_Int32 nLeftMargin = nSpaceBefore + nMinLabelWidth; + aProperties.push_back(comphelper::makePropertyValue("LeftMargin", nLeftMargin)); + + sal_Int32 nFirstLineOffset = -nMinLabelWidth; + aProperties.push_back(comphelper::makePropertyValue("FirstLineOffset", nFirstLineOffset)); + + aProperties.push_back(comphelper::makePropertyValue("SymbolTextDistance", static_cast<sal_Int16>(nMinLabelDist))); + + aProperties.push_back(comphelper::makePropertyValue("PositionAndSpaceMode", ePosAndSpaceMode)); + + aProperties.push_back(comphelper::makePropertyValue("LabelFollowedBy", eLabelFollowedBy)); + + aProperties.push_back(comphelper::makePropertyValue("ListtabStopPosition", nListtabStopPosition)); + + aProperties.push_back(comphelper::makePropertyValue("FirstLineIndent", nFirstLineIndent)); + + aProperties.push_back(comphelper::makePropertyValue("IndentAt", nIndentAt)); + + OUString sDisplayTextStyleName = GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_TEXT, sTextStyleName); + aProperties.push_back(comphelper::makePropertyValue("CharStyleName", sDisplayTextStyleName)); + + if( bBullet ) + { + awt::FontDescriptor aFDesc; + aFDesc.Name = sBulletFontName; + if( !sBulletFontName.isEmpty() ) + { + aFDesc.StyleName = sBulletFontStyleName; + aFDesc.Family = eBulletFontFamily; + aFDesc.Pitch = eBulletFontPitch; + aFDesc.CharSet = eBulletFontEncoding; + aFDesc.Weight = WEIGHT_DONTKNOW; + bool bStarSymbol = false; + if( aFDesc.Name.equalsIgnoreAsciiCase( gsStarBats ) ) + { + cBullet = GetImport().ConvStarBatsCharToStarSymbol( cBullet ); + bStarSymbol = true; + } + else if( aFDesc.Name.equalsIgnoreAsciiCase( gsStarMath ) ) + { + cBullet = GetImport().ConvStarMathCharToStarSymbol( cBullet ); + bStarSymbol = true; + } + if( bStarSymbol ) + aFDesc.Name = "StarSymbol" ; + } + + // Must append 'cBullet' even if it is zero + // if 'bBullet' is true and 'cBullet' is zero - BulletChar property must be 0. + aProperties.push_back(comphelper::makePropertyValue("BulletChar", OUString(&cBullet, 1))); + aProperties.push_back(comphelper::makePropertyValue("BulletFont", aFDesc)); + } + + if( bImage ) + { + uno::Reference<graphic::XGraphic> xGraphic; + if (!sImageURL.isEmpty()) + { + xGraphic = GetImport().loadGraphicByURL(sImageURL); + } + else if( xBase64Stream.is() ) + { + xGraphic = GetImport().loadGraphicFromBase64(xBase64Stream); + } + + uno::Reference<awt::XBitmap> xBitmap; + if (xGraphic.is()) + xBitmap.set(xGraphic, uno::UNO_QUERY); + + if (xBitmap.is()) + { + aProperties.push_back(comphelper::makePropertyValue("GraphicBitmap", xBitmap)); + } + + awt::Size aSize(nImageWidth, nImageHeight); + aProperties.push_back(comphelper::makePropertyValue("GraphicSize", aSize)); + aProperties.push_back(comphelper::makePropertyValue("VertOrient", eImageVertOrient)); + } + + if( bNum ) + { + aProperties.push_back(comphelper::makePropertyValue("StartWith", nNumStartValue)); + aProperties.push_back(comphelper::makePropertyValue("ParentNumbering", nNumDisplayLevels)); + } + + if( ( bNum || bBullet ) && nRelSize ) + { + aProperties.push_back(comphelper::makePropertyValue("BulletRelSize", nRelSize)); + } + + if( !bImage && bHasColor ) + { + aProperties.push_back(comphelper::makePropertyValue("BulletColor", m_nColor)); + } + + aProperties.push_back(comphelper::makePropertyValue("ListFormat", *sListFormat)); + + if (m_bIsLegal) + aProperties.push_back(comphelper::makePropertyValue("IsLegal", true)); + + return comphelper::containerToSequence(aProperties); +} + +SvxXMLListLevelStyleAttrContext_Impl::SvxXMLListLevelStyleAttrContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + SvxXMLListLevelStyleContext_Impl& rLLevel ) : + SvXMLImportContext( rImport ), + rListLevel( rLLevel ) +{ + SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter(); + + OUString sFontName, sFontFamily, sFontStyleName, sFontFamilyGeneric, + sFontPitch, sFontCharset; + OUString sVerticalPos, sVerticalRel; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(TEXT, XML_SPACE_BEFORE): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX)) + rListLevel.SetSpaceBefore( nVal ); + break; + case XML_ELEMENT(TEXT, XML_MIN_LABEL_WIDTH): + if (rUnitConv.convertMeasureToCore( nVal, aIter.toView(), 0, SHRT_MAX )) + rListLevel.SetMinLabelWidth( nVal ); + break; + case XML_ELEMENT(TEXT, XML_MIN_LABEL_DISTANCE): + if (rUnitConv.convertMeasureToCore( nVal, aIter.toView(), 0, USHRT_MAX )) + rListLevel.SetMinLabelDist( nVal ); + break; + case XML_ELEMENT(FO, XML_TEXT_ALIGN): + case XML_ELEMENT(FO_COMPAT, XML_TEXT_ALIGN): + if( !aIter.isEmpty() ) + { + sal_Int16 eAdjust = HoriOrientation::LEFT; + if( IsXMLToken( aIter, XML_CENTER ) ) + eAdjust = HoriOrientation::CENTER; + else if( IsXMLToken( aIter, XML_END ) ) + eAdjust = HoriOrientation::RIGHT; + rListLevel.SetAdjust( eAdjust ); + } + break; + case XML_ELEMENT(STYLE, XML_FONT_NAME): + sFontName = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_FONT_FAMILY): + case XML_ELEMENT(FO_COMPAT, XML_FONT_FAMILY): + sFontFamily = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_FONT_FAMILY_GENERIC): + sFontFamilyGeneric = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_FONT_STYLE_NAME): + sFontStyleName = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_FONT_PITCH): + sFontPitch = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_FONT_CHARSET): + sFontCharset = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_VERTICAL_POS): + sVerticalPos = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_VERTICAL_REL): + sVerticalRel = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_WIDTH): + case XML_ELEMENT(FO_COMPAT, XML_WIDTH): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView())) + rListLevel.SetImageWidth( nVal ); + break; + case XML_ELEMENT(FO, XML_HEIGHT): + case XML_ELEMENT(FO_COMPAT, XML_HEIGHT): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView())) + rListLevel.SetImageHeight( nVal ); + break; + case XML_ELEMENT(FO, XML_COLOR): + case XML_ELEMENT(FO_COMPAT, XML_COLOR): + { + Color nColor; + if (::sax::Converter::convertColor( nColor, aIter.toView() )) + rListLevel.SetColor( nColor ); + } + break; + case XML_ELEMENT(STYLE, XML_USE_WINDOW_FONT_COLOR): + { + if( IsXMLToken( aIter, XML_TRUE ) ) + rListLevel.SetColor(COL_AUTO); + } + break; + case XML_ELEMENT(FO, XML_FONT_SIZE): + case XML_ELEMENT(FO_COMPAT, XML_FONT_SIZE): + if (::sax::Converter::convertPercent( nVal, aIter.toView() )) + rListLevel.SetRelSize( static_cast<sal_Int16>(nVal) ); + break; + case XML_ELEMENT(TEXT, XML_LIST_LEVEL_POSITION_AND_SPACE_MODE): + { + sal_Int16 ePosAndSpaceMode = PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION; + if( IsXMLToken( aIter, XML_LABEL_ALIGNMENT ) ) + ePosAndSpaceMode = PositionAndSpaceMode::LABEL_ALIGNMENT; + rListLevel.SetPosAndSpaceMode( ePosAndSpaceMode ); + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !sFontName.isEmpty() ) + { + const XMLFontStylesContext *pFontDecls = + GetImport().GetFontDecls(); + if( pFontDecls ) + { + ::std::vector < XMLPropertyState > aProps; + if( pFontDecls->FillProperties( sFontName, aProps, 0, 1, 2, 3, 4 ) ) + { + OUString sTmp; + sal_Int16 nTmp = 0; + for( const auto& rProp : aProps ) + { + switch( rProp.mnIndex ) + { + case 0: + rProp.maValue >>= sTmp; + rListLevel.SetBulletFontName( sTmp); + break; + case 1: + rProp.maValue >>= sTmp; + rListLevel.SetBulletFontStyleName( sTmp ); + break; + case 2: + rProp.maValue >>= nTmp; + rListLevel.SetBulletFontFamily( nTmp ); + break; + case 3: + rProp.maValue >>= nTmp; + rListLevel.SetBulletFontPitch( nTmp ); + break; + case 4: + rProp.maValue >>= nTmp; + rListLevel.SetBulletFontEncoding( nTmp ); + break; + } + } + } + } + } + if( !sFontFamily.isEmpty() ) + { + Any aAny; + + XMLFontFamilyNamePropHdl aFamilyNameHdl; + if( aFamilyNameHdl.importXML( sFontFamily, aAny, rUnitConv ) ) + { + OUString sTmp; + aAny >>= sTmp; + rListLevel.SetBulletFontName( sTmp); + } + + XMLFontFamilyPropHdl aFamilyHdl; + if( !sFontFamilyGeneric.isEmpty() && + aFamilyHdl.importXML( sFontFamilyGeneric, aAny, rUnitConv ) ) + { + sal_Int16 nTmp = 0; + aAny >>= nTmp; + rListLevel.SetBulletFontFamily( nTmp ); + } + + if( !sFontStyleName.isEmpty() ) + rListLevel.SetBulletFontStyleName( sFontStyleName ); + + XMLFontPitchPropHdl aPitchHdl; + if( !sFontPitch.isEmpty() && + aPitchHdl.importXML( sFontPitch, aAny, rUnitConv ) ) + { + sal_Int16 nTmp = 0; + aAny >>= nTmp; + rListLevel.SetBulletFontPitch( nTmp ); + } + + XMLFontEncodingPropHdl aEncHdl; + if( !sFontCharset.isEmpty() && + aEncHdl.importXML( sFontCharset, aAny, rUnitConv ) ) + { + sal_Int16 nTmp = 0; + aAny >>= nTmp; + rListLevel.SetBulletFontEncoding( nTmp ); + } + } + + sal_Int16 eVertOrient = VertOrientation::LINE_CENTER; + if( !sVerticalPos.isEmpty() ) + { + if( IsXMLToken( sVerticalPos, XML_TOP ) ) + eVertOrient = VertOrientation::LINE_TOP; + else if( IsXMLToken( sVerticalPos, XML_BOTTOM ) ) + eVertOrient = VertOrientation::LINE_BOTTOM; + } + if( !sVerticalRel.isEmpty() ) + { + if( IsXMLToken( sVerticalRel, XML_BASELINE ) ) + { + // TOP and BOTTOM are exchanged for a baseline relation + switch( eVertOrient ) + { + case VertOrientation::LINE_TOP: + eVertOrient = VertOrientation::BOTTOM; + break; + case VertOrientation::LINE_CENTER: + eVertOrient = VertOrientation::CENTER; + break; + case VertOrientation::LINE_BOTTOM: + eVertOrient = VertOrientation::TOP; + break; + } + } + else if( IsXMLToken( sVerticalRel, XML_CHAR ) ) + { + switch( eVertOrient ) + { + case VertOrientation::LINE_TOP: + eVertOrient = VertOrientation::CHAR_TOP; + break; + case VertOrientation::LINE_CENTER: + eVertOrient = VertOrientation::CHAR_CENTER; + break; + case VertOrientation::LINE_BOTTOM: + eVertOrient = VertOrientation::CHAR_BOTTOM; + break; + } + } + } + rListLevel.SetImageVertOrient( eVertOrient ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListLevelStyleAttrContext_Impl::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(STYLE, XML_LIST_LEVEL_LABEL_ALIGNMENT) ) + { + return new SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl( GetImport(), + nElement, + xAttrList, + rListLevel ); + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl::SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + SvxXMLListLevelStyleContext_Impl& rLLevel ) : + SvXMLImportContext( rImport ) +{ + SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter(); + + sal_Int16 eLabelFollowedBy = LabelFollow::LISTTAB; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(TEXT, XML_LABEL_FOLLOWED_BY): + case XML_ELEMENT(LO_EXT, XML_LABEL_FOLLOWED_BY): + { + if( eLabelFollowedBy == LabelFollow::NEWLINE) + //NewLine from LO_EXT has precedence over other values of the Non LO_EXT namespace + break; + if( IsXMLToken( aIter, XML_SPACE ) ) + eLabelFollowedBy = LabelFollow::SPACE; + else if( IsXMLToken( aIter, XML_NOTHING ) ) + eLabelFollowedBy = LabelFollow::NOTHING; + else if( IsXMLToken( aIter, XML_NEWLINE ) ) + eLabelFollowedBy = LabelFollow::NEWLINE; + } + break; + case XML_ELEMENT(TEXT, XML_LIST_TAB_STOP_POSITION): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), 0, SHRT_MAX)) + rLLevel.SetListtabStopPosition( nVal ); + break; + case XML_ELEMENT(FO, XML_TEXT_INDENT): + case XML_ELEMENT(FO_COMPAT, XML_TEXT_INDENT): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX)) + rLLevel.SetFirstLineIndent( nVal ); + break; + case XML_ELEMENT(FO, XML_MARGIN_LEFT): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_LEFT): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX)) + rLLevel.SetIndentAt( nVal ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + rLLevel.SetLabelFollowedBy( eLabelFollowedBy ); +} + +void SvxXMLListStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(TEXT, XML_CONSECUTIVE_NUMBERING) ) + { + m_bConsecutive = IsXMLToken( rValue, XML_TRUE ); + } + else + { + SvXMLStyleContext::SetAttribute( nElement, rValue ); + } +} + +constexpr OUString sIsPhysical( u"IsPhysical"_ustr ); +constexpr OUString sNumberingRules( u"NumberingRules"_ustr ); +constexpr OUString sIsContinuousNumbering( u"IsContinuousNumbering"_ustr ); + +SvxXMLListStyleContext::SvxXMLListStyleContext( SvXMLImport& rImport, + bool bOutl ) +: SvXMLStyleContext( rImport, bOutl ? XmlStyleFamily::TEXT_OUTLINE : XmlStyleFamily::TEXT_LIST ) +, m_bConsecutive( false ) +, m_bOutline( bOutl ) +{ +} + +SvxXMLListStyleContext::~SvxXMLListStyleContext() {} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( m_bOutline + ? nElement == XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL_STYLE) + : ( nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_NUMBER) || + nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_BULLET) || + nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_IMAGE ) ) ) + { + rtl::Reference<SvxXMLListLevelStyleContext_Impl> xLevelStyle{ + new SvxXMLListLevelStyleContext_Impl( GetImport(), nElement, xAttrList )}; + if( !m_pLevelStyles ) + m_pLevelStyles = std::make_unique<SvxXMLListStyle_Impl>(); + m_pLevelStyles->push_back( xLevelStyle ); + + return xLevelStyle; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SvxXMLListStyleContext::FillUnoNumRule( + const Reference<container::XIndexReplace> & rNumRule) const +{ + try + { + if( m_pLevelStyles && rNumRule.is() ) + { + sal_Int32 l_nLevels = rNumRule->getCount(); + for (const auto& pLevelStyle : *m_pLevelStyles) + { + sal_Int32 nLevel = pLevelStyle->GetLevel(); + if( nLevel >= 0 && nLevel < l_nLevels ) + { + Sequence<beans::PropertyValue> aProps = + pLevelStyle->GetProperties(); + rNumRule->replaceByIndex( nLevel, Any(aProps) ); + } + } + } + + Reference < XPropertySet > xPropSet( rNumRule, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo; + if (xPropSet.is()) + xPropSetInfo = xPropSet->getPropertySetInfo(); + if( xPropSetInfo.is() && + xPropSetInfo->hasPropertyByName( sIsContinuousNumbering ) ) + { + xPropSet->setPropertyValue( sIsContinuousNumbering, Any(m_bConsecutive) ); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.style", "" ); + } +} + +void SvxXMLListStyleContext::CreateAndInsertLate( bool bOverwrite ) +{ + if( m_bOutline ) + { + if( bOverwrite ) + { + const Reference< XIndexReplace >& rNumRule = + GetImport().GetTextImport()->GetChapterNumbering(); + // We don't set xNumberingRules here, to avoid using them + // as numbering rules. + if( rNumRule.is() ) + FillUnoNumRule(rNumRule); + } + } + else + { + Reference < XStyle > xStyle; + const OUString& rName = GetDisplayName(); + if( rName.isEmpty() ) + { + SetValid( false ); + return; + } + + const Reference < XNameContainer >& rNumStyles = + GetImport().GetTextImport()->GetNumberingStyles(); + if( !rNumStyles.is() ) + { + SetValid( false ); + return; + } + + bool bNew = false; + if( rNumStyles->hasByName( rName ) ) + { + Any aAny = rNumStyles->getByName( rName ); + aAny >>= xStyle; + } + else + { + Reference< XMultiServiceFactory > xFactory( GetImport().GetModel(), + UNO_QUERY ); + SAL_WARN_IF( !xFactory.is(), "xmloff", "no factory" ); + if( !xFactory.is() ) + return; + + Reference < XInterface > xIfc = xFactory->createInstance("com.sun.star.style.NumberingStyle"); + if( !xIfc.is() ) + return; + Reference < XStyle > xTmp( xIfc, UNO_QUERY ); + xStyle = xTmp; + if( !xStyle.is() ) + return; + + rNumStyles->insertByName( rName, Any(xStyle) ); + bNew = true; + } + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( !bNew && xPropSetInfo->hasPropertyByName( sIsPhysical ) ) + { + Any aAny = xPropSet->getPropertyValue( sIsPhysical ); + bNew = !*o3tl::doAccess<bool>(aAny); + } + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + xPropSet->setPropertyValue( "Hidden", uno::Any( IsHidden( ) ) ); + + if( rName != GetName() ) + GetImport().AddStyleDisplayName( XmlStyleFamily::TEXT_LIST, + GetName(), rName ); + + Any aAny = xPropSet->getPropertyValue( sNumberingRules ); + aAny >>= m_xNumRules; + if( bOverwrite || bNew ) + { + FillUnoNumRule(m_xNumRules); + xPropSet->setPropertyValue( sNumberingRules, Any(m_xNumRules) ); + } + else + { + SetValid( false ); + } + + SetNew( bNew ); + } +} + +void SvxXMLListStyleContext::CreateAndInsertAuto() const +{ + SAL_WARN_IF( m_bOutline, "xmloff", "Outlines cannot be inserted here" ); + SAL_WARN_IF( m_xNumRules.is(), "xmloff", "Numbering Rule is existing already" ); + + const OUString& rName = GetName(); + if( m_bOutline || m_xNumRules.is() || rName.isEmpty() ) + { + const_cast<SvxXMLListStyleContext *>(this)->SetValid( false ); + return; + } + + const_cast<SvxXMLListStyleContext *>(this)->m_xNumRules = CreateNumRule( + GetImport().GetModel() ); + + FillUnoNumRule(m_xNumRules); +} + +Reference < XIndexReplace > SvxXMLListStyleContext::CreateNumRule( + const Reference < XModel > & rModel ) +{ + Reference<XIndexReplace> xNumRule; + + Reference< XMultiServiceFactory > xFactory( rModel, UNO_QUERY ); + SAL_WARN_IF( !xFactory.is(), "xmloff", "no factory" ); + if( !xFactory.is() ) + return xNumRule; + + Reference < XInterface > xIfc = xFactory->createInstance("com.sun.star.text.NumberingRules"); + if( !xIfc.is() ) + return xNumRule; + + xNumRule.set( xIfc, UNO_QUERY ); + SAL_WARN_IF( !xNumRule.is(), "xmloff", "go no numbering rule" ); + + return xNumRule; +} + +void SvxXMLListStyleContext::SetDefaultStyle( + const Reference < XIndexReplace > & rNumRule, + sal_Int16 nLevel, + bool bOrdered ) +{ + Sequence<beans::PropertyValue> aPropSeq( bOrdered ? 1 : 4 ); + beans::PropertyValue *pProps = aPropSeq.getArray(); + + pProps->Name = "NumberingType"; + (pProps++)->Value <<= static_cast<sal_Int16>(bOrdered ? NumberingType::ARABIC + : NumberingType::CHAR_SPECIAL ); + if( !bOrdered ) + { + // TODO: Bullet-Font + awt::FontDescriptor aFDesc; + aFDesc.Name = +#ifdef _WIN32 + "StarBats" +#else + "starbats" +#endif + ; + aFDesc.Family = FAMILY_DONTKNOW ; + aFDesc.Pitch = PITCH_DONTKNOW ; + aFDesc.CharSet = RTL_TEXTENCODING_SYMBOL ; + aFDesc.Weight = WEIGHT_DONTKNOW; + pProps->Name = "BulletFont"; + (pProps++)->Value <<= aFDesc; + + pProps->Name = "BulletChar"; + (pProps++)->Value <<= OUString(sal_Unicode(0xF000 + 149)); + pProps->Name = "CharStyleName"; + (pProps++)->Value <<= OUString( "Numbering Symbols" ); + } + + rNumRule->replaceByIndex( nLevel, Any(aPropSeq) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlprcon.cxx b/xmloff/source/style/xmlprcon.cxx new file mode 100644 index 0000000000..023a7f5b6b --- /dev/null +++ b/xmloff/source/style/xmlprcon.cxx @@ -0,0 +1,89 @@ +/* -*- 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 <sal/log.hxx> +#include <utility> +#include <xmloff/xmlprcon.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlprmap.hxx> + +using namespace ::com::sun::star; + +SvXMLPropertySetContext::SvXMLPropertySetContext( + SvXMLImport& rImp, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + sal_uInt32 nFam, + std::vector< XMLPropertyState > &rProps, + rtl::Reference < SvXMLImportPropertyMapper > xMap, + sal_Int32 nSIdx, sal_Int32 nEIdx ) +: SvXMLImportContext( rImp ) +, mnStartIdx( nSIdx ) +, mnEndIdx( nEIdx ) +, mnFamily( nFam ) +, mrProperties( rProps ) +, mxMapper(std::move( xMap )) +{ + mxMapper->importXML( mrProperties, xAttrList, + GetImport().GetMM100UnitConverter(), + GetImport().GetNamespaceMap(), mnFamily, + mnStartIdx, mnEndIdx ); +} + +SvXMLPropertySetContext::~SvXMLPropertySetContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLPropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + rtl::Reference< XMLPropertySetMapper > aSetMapper( + mxMapper->getPropertySetMapper() ); + sal_Int32 nEntryIndex = aSetMapper->GetEntryIndex( nElement, mnFamily, mnStartIdx ); + + if( ( nEntryIndex != -1 ) && (-1 == mnEndIdx || nEntryIndex < mnEndIdx ) && + ( 0 != ( aSetMapper->GetEntryFlags( nEntryIndex ) + & MID_FLAG_ELEMENT_ITEM_IMPORT ) ) ) + { + XMLPropertyState aProp( nEntryIndex ); + return createFastChildContext( nElement, xAttrList, mrProperties, aProp ); + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +/** This method is called from this instance implementation of + CreateChildContext if the element matches an entry in the + SvXMLImportItemMapper with the mid flag MID_FLAG_ELEMENT +*/ +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLPropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/, + ::std::vector< XMLPropertyState > &/*rProperties*/, + const XMLPropertyState& /*rProp*/ ) +{ + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlprhdl.cxx b/xmloff/source/style/xmlprhdl.cxx new file mode 100644 index 0000000000..530bcd4793 --- /dev/null +++ b/xmloff/source/style/xmlprhdl.cxx @@ -0,0 +1,33 @@ +/* -*- 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 <xmloff/xmlprhdl.hxx> +#include <com/sun/star/uno/Any.hxx> + +XMLPropertyHandler::~XMLPropertyHandler() +{ + // does nothing +} + +bool XMLPropertyHandler::equals(const css::uno::Any& r1, const css::uno::Any& r2) const +{ + return (r1 == r2); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlprmap.cxx b/xmloff/source/style/xmlprmap.cxx new file mode 100644 index 0000000000..d8503eebb3 --- /dev/null +++ b/xmloff/source/style/xmlprmap.cxx @@ -0,0 +1,358 @@ +/* -*- 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 <o3tl/safeint.hxx> +#include <rtl/ref.hxx> + +#include <xmloff/xmlprmap.hxx> +#include <xmloff/xmlprhdl.hxx> +#include <xmloff/xmltypes.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/maptype.hxx> +#include <xmloff/prhdlfac.hxx> +#include <xmloff/xmlimp.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <vector> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using ::xmloff::token::GetXMLToken; + +namespace { + +/** Helper-class for XML-im/export: + - Holds a pointer to a given array of XMLPropertyMapEntry + - Provides several methods to access data from this array + - Holds a Sequence of XML-names (for properties) + - The filter takes all properties of the XPropertySet which are also + in the XMLPropertyMapEntry and which are have not a default value + and put them into a vector of XMLPropertyStae + - this class knows how to compare, im/export properties + + Attention: At all methods, which get an index as parameter, there is no + range validation to save runtime !! +*/ +struct XMLPropertySetMapperEntry_Impl +{ + OUString sXMLAttributeName; + OUString sAPIPropertyName; + sal_Int32 nType; + sal_uInt16 nXMLNameSpace; + sal_Int16 nContextId; + SvtSaveOptions::ODFSaneDefaultVersion nEarliestODFVersionForExport; + bool bImportOnly; + const XMLPropertyHandler *pHdl; + + XMLPropertySetMapperEntry_Impl( + const XMLPropertyMapEntry& rMapEntry, + const rtl::Reference< XMLPropertyHandlerFactory >& rFactory ); + + sal_uInt32 GetPropType() const { return nType & XML_TYPE_PROP_MASK; } +}; + +} + +XMLPropertySetMapperEntry_Impl::XMLPropertySetMapperEntry_Impl( + const XMLPropertyMapEntry& rMapEntry, + const rtl::Reference< XMLPropertyHandlerFactory >& rFactory ) : + sXMLAttributeName( GetXMLToken(rMapEntry.meXMLName) ), + sAPIPropertyName( rMapEntry.getApiName() ), + nType( rMapEntry.mnType ), + nXMLNameSpace( rMapEntry.mnNameSpace ), + nContextId( rMapEntry.mnContextId ), + nEarliestODFVersionForExport( rMapEntry.mnEarliestODFVersionForExport ), + bImportOnly( rMapEntry.mbImportOnly), + pHdl( rFactory->GetPropertyHandler( rMapEntry.mnType & MID_FLAG_MASK ) ) +{ + assert(pHdl); +} + +struct XMLPropertySetMapper::Impl +{ + std::vector<XMLPropertySetMapperEntry_Impl> maMapEntries; + std::vector<rtl::Reference <XMLPropertyHandlerFactory> > maHdlFactories; + + bool mbOnlyExportMappings; + + explicit Impl( bool bForExport ) : mbOnlyExportMappings(bForExport) {} +}; + +// Ctor +XMLPropertySetMapper::XMLPropertySetMapper( + const XMLPropertyMapEntry* pEntries, const rtl::Reference<XMLPropertyHandlerFactory>& rFactory, + bool bForExport ) : + mpImpl(new Impl(bForExport)) +{ + mpImpl->maHdlFactories.push_back(rFactory); + if( !pEntries ) + return; + + const XMLPropertyMapEntry* pIter = pEntries; + + if (mpImpl->mbOnlyExportMappings) + { + while( !pIter->IsEnd() ) + { + if (!pIter->mbImportOnly) + { + XMLPropertySetMapperEntry_Impl aEntry( *pIter, rFactory ); + mpImpl->maMapEntries.push_back( aEntry ); + } + ++pIter; + } + } + else + { + while( !pIter->IsEnd() ) + { + XMLPropertySetMapperEntry_Impl aEntry( *pIter, rFactory ); + mpImpl->maMapEntries.push_back( aEntry ); + ++pIter; + } + } +} + +XMLPropertySetMapper::~XMLPropertySetMapper() +{ +} + +void XMLPropertySetMapper::AddMapperEntry( + const rtl::Reference < XMLPropertySetMapper >& rMapper ) +{ + for( const auto& rHdlFactory : rMapper->mpImpl->maHdlFactories ) + { + mpImpl->maHdlFactories.push_back(rHdlFactory); + } + + for( const auto& rMapEntry : rMapper->mpImpl->maMapEntries ) + { + if (!mpImpl->mbOnlyExportMappings || !rMapEntry.bImportOnly) + mpImpl->maMapEntries.push_back( rMapEntry ); + } +} + +sal_Int32 XMLPropertySetMapper::GetEntryCount() const +{ + return mpImpl->maMapEntries.size(); +} + +sal_uInt32 XMLPropertySetMapper::GetEntryFlags( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].nType & ~MID_FLAG_MASK; +} + +sal_uInt32 XMLPropertySetMapper::GetEntryType( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + sal_uInt32 nType = mpImpl->maMapEntries[nIndex].nType; + return nType; +} + +sal_uInt16 XMLPropertySetMapper::GetEntryNameSpace( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].nXMLNameSpace; +} + +const OUString& XMLPropertySetMapper::GetEntryXMLName( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].sXMLAttributeName; +} + +const OUString& XMLPropertySetMapper::GetEntryAPIName( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].sAPIPropertyName; +} + +sal_Int16 XMLPropertySetMapper::GetEntryContextId( sal_Int32 nIndex ) const +{ + assert((-1 <= nIndex) && (nIndex < static_cast<sal_Int32>(mpImpl->maMapEntries.size()))); + return nIndex == -1 ? 0 : mpImpl->maMapEntries[nIndex].nContextId; +} + +SvtSaveOptions::ODFSaneDefaultVersion +XMLPropertySetMapper::GetEarliestODFVersionForExport(sal_Int32 const nIndex) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].nEarliestODFVersionForExport; +} + +const XMLPropertyHandler* XMLPropertySetMapper::GetPropertyHandler( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].pHdl; +} + +// Export a Property +bool XMLPropertySetMapper::exportXML( + OUString& rStrExpValue, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + + const XMLPropertyHandler* pHdl = GetPropertyHandler( rProperty.mnIndex ); + + assert(pHdl); + if( pHdl ) + bRet = pHdl->exportXML( rStrExpValue, rProperty.maValue, + rUnitConverter ); + + return bRet; +} + +// Import a Property +bool XMLPropertySetMapper::importXML( + const OUString& rStrImpValue, + XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + + const XMLPropertyHandler* pHdl = GetPropertyHandler( rProperty.mnIndex ); + + if( pHdl ) + bRet = pHdl->importXML( rStrImpValue, rProperty.maValue, + rUnitConverter ); + + return bRet; +} + +// Search for the given name and the namespace in the list and return +// the index of the entry +// If there is no matching entry the method returns -1 +sal_Int32 XMLPropertySetMapper::GetEntryIndex( + sal_uInt16 nNamespace, + std::u16string_view rStrName, + sal_uInt32 nPropType, + sal_Int32 nStartAt /* = -1 */ ) const +{ + sal_Int32 nEntries = GetEntryCount(); + sal_Int32 nIndex= nStartAt == - 1? 0 : nStartAt+1; + + if ( nEntries && nIndex < nEntries ) + { + do + { + const XMLPropertySetMapperEntry_Impl& rEntry = mpImpl->maMapEntries[nIndex]; + if( (!nPropType || nPropType == rEntry.GetPropType()) && + rEntry.nXMLNameSpace == nNamespace && + rStrName == rEntry.sXMLAttributeName ) + return nIndex; + else + nIndex++; + + } while( nIndex<nEntries ); + } + + return -1; +} + +// Search for the given name and the namespace in the list and return +// the index of the entry +// If there is no matching entry the method returns -1 +sal_Int32 XMLPropertySetMapper::GetEntryIndex( + sal_Int32 nElement, + sal_uInt32 nPropType, + sal_Int32 nStartAt /* = -1 */ ) const +{ + sal_Int32 nEntries = GetEntryCount(); + sal_Int32 nIndex= nStartAt == - 1? 0 : nStartAt+1; + + if ( nEntries && nIndex < nEntries ) + { + sal_uInt16 nNamespace = (nElement >> NMSP_SHIFT) - 1; + const OUString& rStrName = SvXMLImport::getNameFromToken(nElement); + do + { + const XMLPropertySetMapperEntry_Impl& rEntry = mpImpl->maMapEntries[nIndex]; + if( (!nPropType || nPropType == rEntry.GetPropType()) && + rEntry.nXMLNameSpace == nNamespace && + rStrName == rEntry.sXMLAttributeName ) + return nIndex; + else + nIndex++; + + } while( nIndex<nEntries ); + } + + return -1; +} + +/** searches for an entry that matches the given api name, namespace and local name or -1 if nothing found */ +sal_Int32 XMLPropertySetMapper::FindEntryIndex( + const char* sApiName, + sal_uInt16 nNameSpace, + std::u16string_view sXMLName ) const +{ + sal_Int32 nIndex = 0; + sal_Int32 nEntries = GetEntryCount(); + + do + { + const XMLPropertySetMapperEntry_Impl& rEntry = mpImpl->maMapEntries[nIndex]; + if( rEntry.nXMLNameSpace == nNameSpace && + rEntry.sXMLAttributeName == sXMLName && + rEntry.sAPIPropertyName.equalsAscii( sApiName ) ) + return nIndex; + else + nIndex++; + + } while( nIndex < nEntries ); + + return -1; +} + +sal_Int32 XMLPropertySetMapper::FindEntryIndex( const sal_Int16 nContextId ) const +{ + const sal_Int32 nEntries = GetEntryCount(); + + if ( nEntries ) + { + sal_Int32 nIndex = 0; + do + { + const XMLPropertySetMapperEntry_Impl& rEntry = mpImpl->maMapEntries[nIndex]; + if( rEntry.nContextId == nContextId ) + return nIndex; + else + nIndex++; + + } while( nIndex < nEntries ); + } + + return -1; +} + +void XMLPropertySetMapper::RemoveEntry( sal_Int32 nIndex ) +{ + const sal_Int32 nEntries = GetEntryCount(); + if( nIndex>=nEntries || nIndex<0 ) + return; + std::vector < XMLPropertySetMapperEntry_Impl >::iterator aEIter = mpImpl->maMapEntries.begin(); + std::advance(aEIter, nIndex); + mpImpl->maMapEntries.erase( aEIter ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlstyle.cxx b/xmloff/source/style/xmlstyle.cxx new file mode 100644 index 0000000000..168483af1d --- /dev/null +++ b/xmloff/source/style/xmlstyle.cxx @@ -0,0 +1,795 @@ +/* -*- 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 <config_wasm_strip.h> + +#include <sal/config.h> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/style/XAutoStylesSupplier.hpp> +#include <com/sun/star/style/XAutoStyleFamily.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <PageMasterPropMapper.hxx> +#include <sal/log.hxx> +#include <svl/style.hxx> +#include <utility> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> + +#include <xmloff/families.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnumi.hxx> +#include <xmloff/xmlimppr.hxx> +#include <xmloff/xmlstyle.hxx> +#include <xmloff/txtstyli.hxx> +#include <xmloff/xmlnumfi.hxx> +#include <XMLChartStyleContext.hxx> +#include <XMLChartPropertySetMapper.hxx> +#include <XMLThemeContext.hxx> +#include <xmloff/XMLShapeStyleContext.hxx> +#include "FillStyleContext.hxx" +#include <XMLFootnoteConfigurationImportContext.hxx> +#include <XMLIndexBibliographyConfigurationContext.hxx> +#include <XMLLineNumberingImportContext.hxx> +#include <PageMasterImportContext.hxx> +#include "PageMasterImportPropMapper.hxx" + +#include <memory> +#include <set> +#include <string_view> +#include <vector> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + +constexpr OUStringLiteral gsParaStyleServiceName( u"com.sun.star.style.ParagraphStyle" ); +constexpr OUStringLiteral gsTextStyleServiceName( u"com.sun.star.style.CharacterStyle" ); +constexpr OUString gsParagraphStyles(u"ParagraphStyles"_ustr); +constexpr OUString gsCharacterStyles(u"CharacterStyles"_ustr); + +void SvXMLStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + switch (nElement) + { + case XML_ELEMENT(STYLE, XML_FAMILY): + { + if( IsXMLToken( rValue, XML_PARAGRAPH ) ) + mnFamily = XmlStyleFamily(SfxStyleFamily::Para); + else if( IsXMLToken( rValue, XML_TEXT ) ) + mnFamily = XmlStyleFamily(SfxStyleFamily::Char); + break; + } + case XML_ELEMENT(STYLE, XML_NAME): + maName = rValue; + break; + case XML_ELEMENT(STYLE, XML_DISPLAY_NAME): + maDisplayName = rValue; + break; + case XML_ELEMENT(STYLE, XML_PARENT_STYLE_NAME): + maParentName = rValue; + break; + case XML_ELEMENT(STYLE, XML_NEXT_STYLE_NAME): + maFollow = rValue; + break; + case XML_ELEMENT(LO_EXT, XML_LINKED_STYLE_NAME): + maLinked = rValue; + break; + case XML_ELEMENT(STYLE, XML_HIDDEN): + mbHidden = rValue.toBoolean(); + break; + case XML_ELEMENT(LO_EXT, XML_HIDDEN): + mbHidden = rValue.toBoolean(); + break; + } +} + + +SvXMLStyleContext::SvXMLStyleContext( + SvXMLImport& rImp, + XmlStyleFamily nFam, bool bDefault ) : + SvXMLImportContext( rImp ), + mbHidden( false ), + mnFamily( nFam ), + mbValid( true ), + mbNew( true ), + mbDefaultStyle( bDefault ) +{ +} + +SvXMLStyleContext::~SvXMLStyleContext() +{ +} + +void SvXMLStyleContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto &it : sax_fastparser::castToFastAttributeList( xAttrList ) ) + SetAttribute( it.getToken(), it.toString() ); +} + +void SvXMLStyleContext::SetDefaults() +{ +} + +void SvXMLStyleContext::CreateAndInsert( bool /*bOverwrite*/ ) +{ +} + +void SvXMLStyleContext::CreateAndInsertLate( bool /*bOverwrite*/ ) +{ +} + +void SvXMLStyleContext::Finish( bool /*bOverwrite*/ ) +{ +} + +bool SvXMLStyleContext::IsTransient() const +{ + return false; +} + +namespace { + +class SvXMLStyleIndex_Impl +{ + OUString sName; + XmlStyleFamily nFamily; + // we deliberately don't use a reference here, to avoid creating a ref-count-cycle + SvXMLStyleContext* mpStyle; + +public: + + SvXMLStyleIndex_Impl( XmlStyleFamily nFam, OUString aName ) : + sName(std::move( aName )), + nFamily( nFam ), + mpStyle(nullptr) + { + } + + SvXMLStyleIndex_Impl( const rtl::Reference<SvXMLStyleContext> &rStl ) : + sName( rStl->GetName() ), + nFamily( rStl->GetFamily() ), + mpStyle ( rStl.get() ) + { + } + + const OUString& GetName() const { return sName; } + XmlStyleFamily GetFamily() const { return nFamily; } + const SvXMLStyleContext *GetStyle() const { return mpStyle; } +}; + +struct SvXMLStyleIndexCmp_Impl +{ + bool operator()(const SvXMLStyleIndex_Impl& r1, const SvXMLStyleIndex_Impl& r2) const + { + sal_Int32 nRet; + + if( r1.GetFamily() < r2.GetFamily() ) + nRet = -1; + else if( r1.GetFamily() > r2.GetFamily() ) + nRet = 1; + else + nRet = r1.GetName().compareTo( r2.GetName() ); + + return nRet < 0; + } +}; + +} + +class SvXMLStylesContext_Impl +{ + typedef std::set<SvXMLStyleIndex_Impl, SvXMLStyleIndexCmp_Impl> IndicesType; + + std::vector<rtl::Reference<SvXMLStyleContext>> aStyles; + mutable std::unique_ptr<IndicesType> pIndices; + bool bAutomaticStyle; + +#if OSL_DEBUG_LEVEL > 0 + mutable sal_uInt32 m_nIndexCreated; +#endif + + void FlushIndex() { pIndices.reset(); } + +public: + explicit SvXMLStylesContext_Impl( bool bAuto ); + + size_t GetStyleCount() const { return aStyles.size(); } + + SvXMLStyleContext *GetStyle( size_t i ) + { + return i < aStyles.size() ? aStyles[ i ].get() : nullptr; + } + + inline void AddStyle( SvXMLStyleContext *pStyle ); + void dispose(); + + const SvXMLStyleContext *FindStyleChildContext( XmlStyleFamily nFamily, + const OUString& rName, + bool bCreateIndex ) const; + bool IsAutomaticStyle() const { return bAutomaticStyle; } +}; + +SvXMLStylesContext_Impl::SvXMLStylesContext_Impl( bool bAuto ) : + bAutomaticStyle( bAuto ) +#if OSL_DEBUG_LEVEL > 0 + , m_nIndexCreated( 0 ) +#endif +{} + +inline void SvXMLStylesContext_Impl::AddStyle( SvXMLStyleContext *pStyle ) +{ +#if OSL_DEBUG_LEVEL > 0 +// for (auto const & xStyle : aStyles) +// if (xStyle->GetFamily() == pStyle->GetFamily() && xStyle->GetName() == pStyle->GetName()) +// assert(false && "duplicate style"); +#endif + aStyles.emplace_back(pStyle ); + + FlushIndex(); +} + +void SvXMLStylesContext_Impl::dispose() +{ + FlushIndex(); + aStyles.clear(); +} + +const SvXMLStyleContext *SvXMLStylesContext_Impl::FindStyleChildContext( XmlStyleFamily nFamily, + const OUString& rName, + bool bCreateIndex ) const +{ + const SvXMLStyleContext *pStyle = nullptr; + + if( !pIndices && bCreateIndex && !aStyles.empty() ) + { + pIndices = std::make_unique<IndicesType>(aStyles.begin(), aStyles.end()); + SAL_WARN_IF(pIndices->size() != aStyles.size(), "xmloff.style", "Here is a duplicate Style"); +#if OSL_DEBUG_LEVEL > 0 + SAL_WARN_IF(0 != m_nIndexCreated, "xmloff.style", + "Performance warning: sdbcx::Index created multiple times"); + ++m_nIndexCreated; +#endif + } + + if( pIndices ) + { + SvXMLStyleIndex_Impl aIndex( nFamily, rName ); + IndicesType::iterator aFind = pIndices->find(aIndex); + if( aFind != pIndices->end() ) + pStyle = aFind->GetStyle(); + } + else + { + for( size_t i = 0; !pStyle && i < aStyles.size(); i++ ) + { + const SvXMLStyleContext *pS = aStyles[ i ].get(); + if( pS->GetFamily() == nFamily && + pS->GetName() == rName ) + pStyle = pS; + } + } + return pStyle; +} + + +sal_uInt32 SvXMLStylesContext::GetStyleCount() const +{ + return mpImpl->GetStyleCount(); +} + +SvXMLStyleContext *SvXMLStylesContext::GetStyle( sal_uInt32 i ) +{ + return mpImpl->GetStyle( i ); +} + +const SvXMLStyleContext *SvXMLStylesContext::GetStyle( sal_uInt32 i ) const +{ + return mpImpl->GetStyle( i ); +} + +bool SvXMLStylesContext::IsAutomaticStyle() const +{ + return mpImpl->IsAutomaticStyle(); +} + +SvXMLStyleContext *SvXMLStylesContext::CreateStyleChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + SvXMLStyleContext *pStyle = nullptr; + + if(GetImport().GetDataStylesImport()) + { + pStyle = GetImport().GetDataStylesImport()->CreateChildContext(GetImport(), nElement, + xAttrList, *this); + if (pStyle) + return pStyle; + } + + switch (nElement) + { + case XML_ELEMENT(STYLE, XML_STYLE): + case XML_ELEMENT(STYLE, XML_DEFAULT_STYLE): + { + XmlStyleFamily nFamily = XmlStyleFamily::DATA_STYLE; + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + if( aIter.getToken() == XML_ELEMENT(STYLE, XML_FAMILY) ) + { + nFamily = GetFamily( aIter.toString() ); + break; + } + } + pStyle = XML_ELEMENT(STYLE, XML_STYLE)==nElement + ? CreateStyleStyleChildContext( nFamily, nElement, xAttrList ) + : CreateDefaultStyleStyleChildContext( nFamily, nElement, xAttrList ); + break; + } + case XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY_CONFIGURATION): + pStyle = new XMLIndexBibliographyConfigurationContext(GetImport()); + break; + case XML_ELEMENT(TEXT, XML_NOTES_CONFIGURATION): + pStyle = new XMLFootnoteConfigurationImportContext( + GetImport(), nElement, xAttrList); + break; + case XML_ELEMENT(TEXT, XML_LINENUMBERING_CONFIGURATION): + pStyle = new XMLLineNumberingImportContext(GetImport()); + break; + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT): + case XML_ELEMENT(STYLE, XML_DEFAULT_PAGE_LAYOUT): + { + //there is not page family in ODF now, so I specify one for it + bool bDefaultStyle = XML_ELEMENT(STYLE, XML_DEFAULT_PAGE_LAYOUT) == nElement; + pStyle = new PageStyleContext( GetImport(), *this, bDefaultStyle ); + } + break; + case XML_ELEMENT(TEXT, XML_LIST_STYLE): + pStyle = new SvxXMLListStyleContext( GetImport() ); + break; + case XML_ELEMENT(TEXT, XML_OUTLINE_STYLE): + pStyle = new SvxXMLListStyleContext( GetImport(), true ); + break; + + // FillStyles + + case XML_ELEMENT(DRAW, XML_GRADIENT): + { + pStyle = new XMLGradientStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_HATCH): + { + pStyle = new XMLHatchStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_FILL_IMAGE): + { + pStyle = new XMLBitmapStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_OPACITY): + { + pStyle = new XMLTransGradientStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_MARKER): + { + pStyle = new XMLMarkerStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_STROKE_DASH): + { + pStyle = new XMLDashStyleContext( GetImport(), nElement, xAttrList ); + break; + } + } + + if (!pStyle) + SAL_WARN("xmloff", "Unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); + + return pStyle; +} + +SvXMLStyleContext *SvXMLStylesContext::CreateStyleStyleChildContext( + XmlStyleFamily nFamily, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList > & /*xAttrList*/ ) +{ + SvXMLStyleContext *pStyle = nullptr; + + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + case XmlStyleFamily::TEXT_TEXT: + case XmlStyleFamily::TEXT_SECTION: + pStyle = new XMLTextStyleContext( GetImport(), *this, nFamily ); + break; + + case XmlStyleFamily::TEXT_RUBY: + pStyle = new XMLPropStyleContext( GetImport(), *this, nFamily ); + break; +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + case XmlStyleFamily::SCH_CHART_ID: + pStyle = new XMLChartStyleContext( GetImport(), *this, nFamily ); + break; +#endif + case XmlStyleFamily::SD_GRAPHICS_ID: + case XmlStyleFamily::SD_PRESENTATION_ID: + case XmlStyleFamily::SD_POOL_ID: + pStyle = new XMLShapeStyleContext( GetImport(), *this, nFamily ); + break; + default: break; + } + + return pStyle; +} + +SvXMLStyleContext *SvXMLStylesContext::CreateDefaultStyleStyleChildContext( + XmlStyleFamily /*nFamily*/, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList > & ) +{ + return nullptr; +} + +bool SvXMLStylesContext::InsertStyleFamily( XmlStyleFamily ) const +{ + return true; +} + +XmlStyleFamily SvXMLStylesContext::GetFamily( std::u16string_view rValue ) +{ + XmlStyleFamily nFamily = XmlStyleFamily::DATA_STYLE; + if( IsXMLToken( rValue, XML_PARAGRAPH ) ) + { + nFamily = XmlStyleFamily::TEXT_PARAGRAPH; + } + else if( IsXMLToken( rValue, XML_TEXT ) ) + { + nFamily = XmlStyleFamily::TEXT_TEXT; + } + else if( IsXMLToken( rValue, XML_DATA_STYLE ) ) + { + nFamily = XmlStyleFamily::DATA_STYLE; + } + else if ( IsXMLToken( rValue, XML_SECTION ) ) + { + nFamily = XmlStyleFamily::TEXT_SECTION; + } + else if( IsXMLToken( rValue, XML_TABLE ) ) + { + nFamily = XmlStyleFamily::TABLE_TABLE; + } + else if( IsXMLToken( rValue, XML_TABLE_COLUMN ) ) + nFamily = XmlStyleFamily::TABLE_COLUMN; + else if( IsXMLToken( rValue, XML_TABLE_ROW ) ) + nFamily = XmlStyleFamily::TABLE_ROW; + else if( IsXMLToken( rValue, XML_TABLE_CELL ) ) + nFamily = XmlStyleFamily::TABLE_CELL; + else if ( rValue == XML_STYLE_FAMILY_SD_GRAPHICS_NAME ) + { + nFamily = XmlStyleFamily::SD_GRAPHICS_ID; + } + else if ( rValue == XML_STYLE_FAMILY_SD_PRESENTATION_NAME ) + { + nFamily = XmlStyleFamily::SD_PRESENTATION_ID; + } + else if ( rValue == XML_STYLE_FAMILY_SD_POOL_NAME ) + { + nFamily = XmlStyleFamily::SD_POOL_ID; + } + else if ( rValue == XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME ) + { + nFamily = XmlStyleFamily::SD_DRAWINGPAGE_ID; + } + else if ( rValue == XML_STYLE_FAMILY_SCH_CHART_NAME ) + { + nFamily = XmlStyleFamily::SCH_CHART_ID; + } + else if ( IsXMLToken( rValue, XML_RUBY ) ) + { + nFamily = XmlStyleFamily::TEXT_RUBY; + } + + return nFamily; +} + +rtl::Reference < SvXMLImportPropertyMapper > SvXMLStylesContext::GetImportPropertyMapper( + XmlStyleFamily nFamily ) const +{ + rtl::Reference < SvXMLImportPropertyMapper > xMapper; + + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + if( !mxParaImpPropMapper.is() ) + { + SvXMLStylesContext * pThis = const_cast<SvXMLStylesContext *>(this); + pThis->mxParaImpPropMapper = + pThis->GetImport().GetTextImport() + ->GetParaImportPropertySetMapper(); + } + xMapper = mxParaImpPropMapper; + break; + case XmlStyleFamily::TEXT_TEXT: + if( !mxTextImpPropMapper.is() ) + { + SvXMLStylesContext * pThis = const_cast<SvXMLStylesContext *>(this); + pThis->mxTextImpPropMapper = + pThis->GetImport().GetTextImport() + ->GetTextImportPropertySetMapper(); + } + xMapper = mxTextImpPropMapper; + break; + + case XmlStyleFamily::TEXT_SECTION: + // don't cache section mapper, as it's rarely used + // *sigh*, cast to non-const, because this is a const method, + // but SvXMLImport::GetTextImport() isn't. + xMapper = const_cast<SvXMLStylesContext*>(this)->GetImport().GetTextImport()-> + GetSectionImportPropertySetMapper(); + break; + + case XmlStyleFamily::TEXT_RUBY: + // don't cache section mapper, as it's rarely used + // *sigh*, cast to non-const, because this is a const method, + // but SvXMLImport::GetTextImport() isn't. + xMapper = const_cast<SvXMLStylesContext*>(this)->GetImport().GetTextImport()-> + GetRubyImportPropertySetMapper(); + break; + + case XmlStyleFamily::SD_GRAPHICS_ID: + case XmlStyleFamily::SD_PRESENTATION_ID: + case XmlStyleFamily::SD_POOL_ID: + if(!mxShapeImpPropMapper.is()) + { + rtl::Reference< XMLShapeImportHelper > aImpHelper = const_cast<SvXMLImport&>(GetImport()).GetShapeImport(); + const_cast<SvXMLStylesContext*>(this)->mxShapeImpPropMapper = + aImpHelper->GetPropertySetMapper(); + } + xMapper = mxShapeImpPropMapper; + break; +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + case XmlStyleFamily::SCH_CHART_ID: + if( ! mxChartImpPropMapper.is() ) + { + XMLPropertySetMapper *const pPropMapper = new XMLChartPropertySetMapper(nullptr); + mxChartImpPropMapper = new XMLChartImportPropertyMapper( pPropMapper, GetImport() ); + } + xMapper = mxChartImpPropMapper; + break; +#endif + case XmlStyleFamily::PAGE_MASTER: + if( ! mxPageImpPropMapper.is() ) + { + XMLPropertySetMapper *pPropMapper = + new XMLPageMasterPropSetMapper(); + mxPageImpPropMapper = + new PageMasterImportPropertyMapper( pPropMapper, + const_cast<SvXMLStylesContext*>(this)->GetImport() ); + } + xMapper = mxPageImpPropMapper; + break; + default: break; + } + + return xMapper; +} + +Reference < XAutoStyleFamily > SvXMLStylesContext::GetAutoStyles( XmlStyleFamily nFamily ) const +{ + Reference < XAutoStyleFamily > xAutoStyles; + if( XmlStyleFamily::TEXT_TEXT == nFamily || XmlStyleFamily::TEXT_PARAGRAPH == nFamily) + { + bool bPara = XmlStyleFamily::TEXT_PARAGRAPH == nFamily; + const Reference<XAutoStyleFamily>& rxAutoStyles = bPara ? mxParaAutoStyles : mxTextAutoStyles; + if (!rxAutoStyles) + { + OUString sName(bPara ? gsParagraphStyles : gsCharacterStyles); + Reference< XAutoStylesSupplier > xAutoStylesSupp( GetImport().GetModel(), UNO_QUERY ); + Reference< XAutoStyles > xAutoStyleFamilies = xAutoStylesSupp->getAutoStyles(); + if (xAutoStyleFamilies->hasByName(sName)) + { + Any aAny = xAutoStyleFamilies->getByName( sName ); + aAny >>= const_cast<Reference<XAutoStyleFamily>&>(rxAutoStyles); + } + } + xAutoStyles = rxAutoStyles; + } + return xAutoStyles; +} + +Reference < XNameContainer > SvXMLStylesContext::GetStylesContainer( + XmlStyleFamily nFamily ) const +{ + Reference < XNameContainer > xStyles; + if (XmlStyleFamily::TEXT_TEXT == nFamily || XmlStyleFamily::TEXT_PARAGRAPH == nFamily) + { + bool bPara = XmlStyleFamily::TEXT_PARAGRAPH == nFamily; + const Reference<XNameContainer>& rxStyles = bPara ? mxParaStyles : mxTextStyles; + if (!rxStyles) + { + OUString sName(bPara ? gsParagraphStyles : gsCharacterStyles); + Reference<XStyleFamiliesSupplier> xFamiliesSupp(GetImport().GetModel(), UNO_QUERY); + if (xFamiliesSupp.is()) + { + Reference<XNameAccess> xFamilies = xFamiliesSupp->getStyleFamilies(); + if (xFamilies->hasByName(sName)) + { + Any aAny = xFamilies->getByName(sName); + aAny >>= const_cast<Reference<XNameContainer>&>(rxStyles); + } + } + } + xStyles = rxStyles; + } + + return xStyles; +} + +OUString SvXMLStylesContext::GetServiceName( XmlStyleFamily nFamily ) const +{ + OUString sServiceName; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + sServiceName = gsParaStyleServiceName; + break; + case XmlStyleFamily::TEXT_TEXT: + sServiceName = gsTextStyleServiceName; + break; + default: break; + } + + return sServiceName; +} + +SvXMLStylesContext::SvXMLStylesContext( SvXMLImport& rImport, bool bAuto ) : + SvXMLImportContext( rImport ), + mpImpl( new SvXMLStylesContext_Impl( bAuto ) ) +{ +} + +SvXMLStylesContext::~SvXMLStylesContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLStylesContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (nElement == XML_ELEMENT(LO_EXT, XML_THEME)) + { + uno::Reference<uno::XInterface> xObject(GetImport().GetModel(), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPageSupplier> const xDrawPageSupplier(GetImport().GetModel(), uno::UNO_QUERY); + if (xDrawPageSupplier.is()) + { + uno::Reference<drawing::XDrawPage> xPage = xDrawPageSupplier->getDrawPage(); + if (xPage.is()) + xObject = xPage; + } + + return new XMLThemeContext(GetImport(), xAttrList, xObject); + } + + SvXMLStyleContext* pStyle = CreateStyleChildContext( nElement, xAttrList ); + if (pStyle) + { + if (!pStyle->IsTransient()) + mpImpl->AddStyle(pStyle); + return pStyle; + } + + return nullptr; +} + +void SvXMLStylesContext::AddStyle(SvXMLStyleContext& rNew) +{ + mpImpl->AddStyle( &rNew ); +} + +void SvXMLStylesContext::dispose() +{ + mpImpl->dispose(); +} + +void SvXMLStylesContext::CopyAutoStylesToDoc() +{ + sal_uInt32 nCount = GetStyleCount(); + sal_uInt32 i; + for( i = 0; i < nCount; i++ ) + { + SvXMLStyleContext *pStyle = GetStyle( i ); + if( !pStyle || ( pStyle->GetFamily() != XmlStyleFamily::TEXT_TEXT && + pStyle->GetFamily() != XmlStyleFamily::TEXT_PARAGRAPH && + pStyle->GetFamily() != XmlStyleFamily::TABLE_CELL ) ) + continue; + pStyle->CreateAndInsert( false ); + } +} + +void SvXMLStylesContext::CopyStylesToDoc( bool bOverwrite, + bool bFinish ) +{ + // pass 1: create text, paragraph and frame styles + sal_uInt32 nCount = GetStyleCount(); + sal_uInt32 i; + + for( i = 0; i < nCount; i++ ) + { + SvXMLStyleContext *pStyle = GetStyle( i ); + if( !pStyle ) + continue; + + if (pStyle->IsDefaultStyle()) + { + if (bOverwrite) pStyle->SetDefaults(); + } + else if( InsertStyleFamily( pStyle->GetFamily() ) ) + pStyle->CreateAndInsert( bOverwrite ); + } + + // pass 2: create list styles (they require char styles) + for( i=0; i<nCount; i++ ) + { + SvXMLStyleContext *pStyle = GetStyle( i ); + if( !pStyle || pStyle->IsDefaultStyle()) + continue; + + if( InsertStyleFamily( pStyle->GetFamily() ) ) + pStyle->CreateAndInsertLate( bOverwrite ); + } + + // pass3: finish creation of styles + if( bFinish ) + FinishStyles( bOverwrite ); +} + +void SvXMLStylesContext::FinishStyles( bool bOverwrite ) +{ + sal_uInt32 nCount = GetStyleCount(); + for( sal_uInt32 i=0; i<nCount; i++ ) + { + SvXMLStyleContext *pStyle = GetStyle( i ); + if( !pStyle || !pStyle->IsValid() || pStyle->IsDefaultStyle() ) + continue; + + if( InsertStyleFamily( pStyle->GetFamily() ) ) + pStyle->Finish( bOverwrite ); + } +} + +const SvXMLStyleContext *SvXMLStylesContext::FindStyleChildContext( + XmlStyleFamily nFamily, + const OUString& rName, + bool bCreateIndex ) const +{ + return mpImpl->FindStyleChildContext( nFamily, rName, bCreateIndex ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmltabe.cxx b/xmloff/source/style/xmltabe.cxx new file mode 100644 index 0000000000..661caedf6f --- /dev/null +++ b/xmloff/source/style/xmltabe.cxx @@ -0,0 +1,120 @@ +/* -*- 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 <com/sun/star/style/TabStop.hpp> +#include <com/sun/star/style/TabAlign.hpp> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> +#include <xmloff/xmlement.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmltabe.hxx> + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry<style::TabAlign> const pXML_tabstop_style[] = +{ + { XML_LEFT, style::TabAlign_LEFT }, + { XML_CENTER, style::TabAlign_CENTER }, + { XML_RIGHT, style::TabAlign_RIGHT }, + { XML_CHAR, style::TabAlign_DECIMAL }, + { XML_DEFAULT, style::TabAlign_DEFAULT }, // ????????????????????????????????????? + { XML_TOKEN_INVALID, style::TabAlign(0) } +}; + +void SvxXMLTabStopExport::exportTabStop( const css::style::TabStop* pTabStop ) +{ + SvXMLUnitConverter& rUnitConv = rExport.GetMM100UnitConverter(); + + // text:level + OUStringBuffer sBuffer; + + // position attribute + rUnitConv.convertMeasureToXML( sBuffer, pTabStop->Position ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_POSITION, + sBuffer.makeStringAndClear() ); + + // type attribute + if( style::TabAlign_LEFT != pTabStop->Alignment ) + { + SvXMLUnitConverter::convertEnum( sBuffer, pTabStop->Alignment, + pXML_tabstop_style ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_TYPE, + sBuffer.makeStringAndClear() ); + } + + // char + if( style::TabAlign_DECIMAL == pTabStop->Alignment && + pTabStop->DecimalChar != 0 ) + { + sBuffer.append( pTabStop->DecimalChar ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CHAR, + sBuffer.makeStringAndClear() ); + } + + // leader-char + if( ' ' != pTabStop->FillChar && 0 != pTabStop->FillChar ) + { + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEADER_STYLE, + GetXMLToken('.' == pTabStop->FillChar ? XML_DOTTED + : XML_SOLID) ); + + sBuffer.append( pTabStop->FillChar ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEADER_TEXT, + sBuffer.makeStringAndClear() ); + } + + SvXMLElementExport rElem( rExport, XML_NAMESPACE_STYLE, XML_TAB_STOP, + true, true ); +} + + +SvxXMLTabStopExport::SvxXMLTabStopExport( + SvXMLExport& rExp) + : rExport( rExp ) +{ +} + +void SvxXMLTabStopExport::Export( const uno::Any& rAny ) +{ + uno::Sequence< css::style::TabStop> aSeq; + if(!(rAny >>= aSeq)) + { + OSL_FAIL( "SvxXMLTabStopExport needs a Sequence css::style::TabStop>" ); + } + else + { + SvXMLElementExport rElem( rExport, XML_NAMESPACE_STYLE, XML_TAB_STOPS, + true, true ); + + for( const auto& rTab : std::as_const(aSeq) ) + { + if( style::TabAlign_DEFAULT != rTab.Alignment ) + exportTabStop( &rTab ); + } + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmltabi.cxx b/xmloff/source/style/xmltabi.cxx new file mode 100644 index 0000000000..e6d33b1149 --- /dev/null +++ b/xmloff/source/style/xmltabi.cxx @@ -0,0 +1,183 @@ +/* -*- 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 <com/sun/star/style/TabAlign.hpp> +#include <sal/log.hxx> +#include <xmloff/xmltkmap.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmlimp.hxx> +#include <com/sun/star/style/TabStop.hpp> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmltabi.hxx> + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +class SvxXMLTabStopContext_Impl : public SvXMLImportContext +{ +private: + style::TabStop aTabStop; + +public: + + SvxXMLTabStopContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList > & xAttrList ); + + const style::TabStop& getTabStop() const { return aTabStop; } +}; + + +SvxXMLTabStopContext_Impl::SvxXMLTabStopContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList > & xAttrList ) +: SvXMLImportContext( rImport ) +{ + aTabStop.Position = 0; + aTabStop.Alignment = style::TabAlign_LEFT; + aTabStop.DecimalChar = ','; + aTabStop.FillChar = ' '; + sal_Unicode cTextFillChar = 0; + + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(STYLE, XML_POSITION): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nVal, aIter.toView())) + { + aTabStop.Position = nVal; + } + break; + case XML_ELEMENT(STYLE, XML_TYPE): + if( IsXMLToken( aIter, XML_LEFT ) ) + { + aTabStop.Alignment = style::TabAlign_LEFT; + } + else if( IsXMLToken( aIter, XML_RIGHT ) ) + { + aTabStop.Alignment = style::TabAlign_RIGHT; + } + else if( IsXMLToken( aIter, XML_CENTER ) ) + { + aTabStop.Alignment = style::TabAlign_CENTER; + } + else if( IsXMLToken( aIter, XML_CHAR ) ) + { + aTabStop.Alignment = style::TabAlign_DECIMAL; + } + else if( IsXMLToken( aIter, XML_DEFAULT ) ) + { + aTabStop.Alignment = style::TabAlign_DEFAULT; + } + break; + case XML_ELEMENT(STYLE, XML_CHAR): + if( !aIter.isEmpty() ) + aTabStop.DecimalChar = aIter.toString()[0]; + break; + case XML_ELEMENT(STYLE, XML_LEADER_STYLE): + if( IsXMLToken( aIter, XML_NONE ) ) + aTabStop.FillChar = ' '; + else if( IsXMLToken( aIter, XML_DOTTED ) ) + aTabStop.FillChar = '.'; + else + aTabStop.FillChar = '_'; + break; + case XML_ELEMENT(STYLE, XML_LEADER_TEXT): + if( !aIter.isEmpty() ) + cTextFillChar = aIter.toString()[0]; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( cTextFillChar != 0 && aTabStop.FillChar != ' ' ) + aTabStop.FillChar = cTextFillChar; +} + + +SvxXMLTabStopImportContext::SvxXMLTabStopImportContext( + SvXMLImport& rImport, sal_Int32 nElement, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) +: XMLElementPropertyContext( rImport, nElement, rProp, rProps ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLTabStopImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + if( nElement == XML_ELEMENT(STYLE, XML_TAB_STOP) ) + { + // create new tabstop import context + const rtl::Reference<SvxXMLTabStopContext_Impl> xTabStopContext{ + new SvxXMLTabStopContext_Impl( GetImport(), nElement, xAttrList )}; + + // add new tabstop to array of tabstops + maTabStops.push_back( xTabStopContext ); + + return xTabStopContext; + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +void SvxXMLTabStopImportContext::endFastElement(sal_Int32 nElement) +{ + sal_uInt16 nCount = maTabStops.size(); + uno::Sequence< style::TabStop> aSeq( nCount ); + + if( nCount ) + { + sal_uInt16 nNewCount = 0; + + style::TabStop* pTabStops = aSeq.getArray(); + for( sal_uInt16 i=0; i < nCount; i++ ) + { + SvxXMLTabStopContext_Impl *pTabStopContext = maTabStops[i].get(); + const style::TabStop& rTabStop = pTabStopContext->getTabStop(); + bool bDflt = style::TabAlign_DEFAULT == rTabStop.Alignment; + if( !bDflt || 0==i ) + { + *pTabStops++ = pTabStopContext->getTabStop(); + nNewCount++; + } + if( bDflt && 0==i ) + break; + } + + if( nCount != nNewCount ) + aSeq.realloc( nNewCount ); + } + aProp.maValue <<= aSeq; + + SetInsert( true ); + XMLElementPropertyContext::endFastElement(nElement); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |