diff options
Diffstat (limited to 'xmloff/source/core/SettingsExportHelper.cxx')
-rw-r--r-- | xmloff/source/core/SettingsExportHelper.cxx | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/xmloff/source/core/SettingsExportHelper.cxx b/xmloff/source/core/SettingsExportHelper.cxx new file mode 100644 index 000000000..09a615b51 --- /dev/null +++ b/xmloff/source/core/SettingsExportHelper.cxx @@ -0,0 +1,517 @@ +/* -*- 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 <sax/tools/converter.hxx> + +#include <xmloff/SettingsExportHelper.hxx> +#include <xmloff/xmltoken.hxx> +#include <sal/log.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/base64.hxx> +#include <comphelper/extract.hxx> + +#include <com/sun/star/linguistic2/XSupportedLocales.hpp> +#include <com/sun/star/i18n/XForbiddenCharacters.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/util/PathSubstitution.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/formula/SymbolDescriptor.hpp> +#include <com/sun/star/document/PrinterIndependentLayout.hpp> +#include <com/sun/star/document/IndexedPropertyValues.hpp> +#include <xmloff/XMLSettingsExportContext.hxx> +#include "xmlenums.hxx" + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +static const OUStringLiteral gsPrinterIndependentLayout( "PrinterIndependentLayout" ); +static const OUStringLiteral gsColorTableURL( "ColorTableURL" ); +static const OUStringLiteral gsLineEndTableURL( "LineEndTableURL" ); +static const OUStringLiteral gsHatchTableURL( "HatchTableURL" ); +static const OUStringLiteral gsDashTableURL( "DashTableURL" ); +static const OUStringLiteral gsGradientTableURL( "GradientTableURL" ); +static const OUStringLiteral gsBitmapTableURL( "BitmapTableURL" ); + +XMLSettingsExportHelper::XMLSettingsExportHelper( ::xmloff::XMLSettingsExportContext& i_rContext ) +: m_rContext( i_rContext ) +{ +} + +XMLSettingsExportHelper::~XMLSettingsExportHelper() +{ +} + +void XMLSettingsExportHelper::CallTypeFunction(const uno::Any& rAny, + const OUString& rName) const +{ + uno::Any aAny( rAny ); + ManipulateSetting( aAny, rName ); + + uno::TypeClass eClass = aAny.getValueTypeClass(); + switch (eClass) + { + case uno::TypeClass_VOID: + { + /* + * This assertion pops up when exporting values which are set to: + * PropertyAttribute::MAYBEVOID, and thus are _supposed_ to have + * a VOID value...so I'm removing it ...mtg + * OSL_FAIL("no type"); + */ + } + break; + case uno::TypeClass_BOOLEAN: + { + exportBool(::cppu::any2bool(aAny), rName); + } + break; + case uno::TypeClass_BYTE: + { + exportByte(); + } + break; + case uno::TypeClass_SHORT: + { + sal_Int16 nInt16 = 0; + aAny >>= nInt16; + exportShort(nInt16, rName); + } + break; + case uno::TypeClass_LONG: + { + sal_Int32 nInt32 = 0; + aAny >>= nInt32; + exportInt(nInt32, rName); + } + break; + case uno::TypeClass_HYPER: + { + sal_Int64 nInt64 = 0; + aAny >>= nInt64; + exportLong(nInt64, rName); + } + break; + case uno::TypeClass_DOUBLE: + { + double fDouble = 0.0; + aAny >>= fDouble; + exportDouble(fDouble, rName); + } + break; + case uno::TypeClass_STRING: + { + OUString sString; + aAny >>= sString; + exportString(sString, rName); + } + break; + default: + { + const uno::Type& aType = aAny.getValueType(); + if (aType.equals(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get() ) ) + { + uno::Sequence< beans::PropertyValue> aProps; + aAny >>= aProps; + exportSequencePropertyValue(aProps, rName); + } + else if( aType.equals(cppu::UnoType<uno::Sequence<sal_Int8>>::get() ) ) + { + uno::Sequence< sal_Int8 > aProps; + aAny >>= aProps; + exportbase64Binary(aProps, rName); + } + else if (aType.equals(cppu::UnoType<container::XNameContainer>::get()) || + aType.equals(cppu::UnoType<container::XNameAccess>::get())) + { + uno::Reference< container::XNameAccess> aNamed; + aAny >>= aNamed; + exportNameAccess(aNamed, rName); + } + else if (aType.equals(cppu::UnoType<container::XIndexAccess>::get()) || + aType.equals(cppu::UnoType<container::XIndexContainer>::get()) ) + { + uno::Reference<container::XIndexAccess> aIndexed; + aAny >>= aIndexed; + exportIndexAccess(aIndexed, rName); + } + else if (aType.equals(cppu::UnoType<util::DateTime>::get()) ) + { + util::DateTime aDateTime; + aAny >>= aDateTime; + exportDateTime(aDateTime, rName); + } + else if( aType.equals(cppu::UnoType<i18n::XForbiddenCharacters>::get()) ) + { + exportForbiddenCharacters( aAny, rName ); + } + else if( aType.equals(cppu::UnoType<uno::Sequence<formula::SymbolDescriptor>>::get() ) ) + { + uno::Sequence< formula::SymbolDescriptor > aProps; + aAny >>= aProps; + exportSymbolDescriptors(aProps, rName); + } + else { + OSL_FAIL("this type is not implemented now"); + } + } + break; + } +} + +void XMLSettingsExportHelper::exportBool(const bool bValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_BOOLEAN ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + OUString sValue; + if (bValue) + sValue = GetXMLToken(XML_TRUE); + else + sValue = GetXMLToken(XML_FALSE); + m_rContext.Characters( sValue ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportByte() +{ + OSL_ENSURE(false, "XMLSettingsExportHelper::exportByte(): #i114162#:\n" + "config-items of type \"byte\" are not valid ODF, " + "so storing them is disabled!\n" + "Use a different type instead (e.g. \"short\")."); +} +void XMLSettingsExportHelper::exportShort(const sal_Int16 nValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_SHORT ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + m_rContext.Characters( OUString::number(nValue) ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportInt(const sal_Int32 nValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_INT ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + m_rContext.Characters( OUString::number(nValue) ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportLong(const sal_Int64 nValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_LONG ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + m_rContext.Characters( OUString::number(nValue) ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportDouble(const double fValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_DOUBLE ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + OUStringBuffer sBuffer; + ::sax::Converter::convertDouble(sBuffer, fValue); + m_rContext.Characters( sBuffer.makeStringAndClear() ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportString(const OUString& sValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_STRING ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + if (!sValue.isEmpty()) + m_rContext.Characters( sValue ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportDateTime(const util::DateTime& aValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_DATETIME ); + OUStringBuffer sBuffer; + ::sax::Converter::convertDateTime(sBuffer, aValue, nullptr); + m_rContext.StartElement( XML_CONFIG_ITEM ); + m_rContext.Characters( sBuffer.makeStringAndClear() ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportSequencePropertyValue( + const uno::Sequence<beans::PropertyValue>& aProps, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + if(aProps.hasElements()) + { + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.StartElement( XML_CONFIG_ITEM_SET ); + for (const auto& rProp : aProps) + CallTypeFunction(rProp.Value, rProp.Name); + m_rContext.EndElement( true ); + } +} +void XMLSettingsExportHelper::exportSymbolDescriptors( + const uno::Sequence < formula::SymbolDescriptor > &rProps, + const OUString& rName) const +{ + uno::Reference< container::XIndexContainer > xBox = document::IndexedPropertyValues::create(m_rContext.GetComponentContext()); + + const OUString sName ( "Name" ); + const OUString sExportName ( "ExportName" ); + const OUString sSymbolSet ( "SymbolSet" ); + const OUString sCharacter ( "Character" ); + const OUString sFontName ( "FontName" ); + const OUString sCharSet ( "CharSet" ); + const OUString sFamily ( "Family" ); + const OUString sPitch ( "Pitch" ); + const OUString sWeight ( "Weight" ); + const OUString sItalic ( "Italic" ); + + sal_Int32 nCount = rProps.getLength(); + const formula::SymbolDescriptor *pDescriptor = rProps.getConstArray(); + + for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++, pDescriptor++ ) + { + uno::Sequence < beans::PropertyValue > aSequence ( XML_SYMBOL_DESCRIPTOR_MAX ); + beans::PropertyValue *pSymbol = aSequence.getArray(); + + pSymbol[XML_SYMBOL_DESCRIPTOR_NAME].Name = sName; + pSymbol[XML_SYMBOL_DESCRIPTOR_NAME].Value <<= pDescriptor->sName; + pSymbol[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME].Name = sExportName; + pSymbol[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME].Value<<= pDescriptor->sExportName; + pSymbol[XML_SYMBOL_DESCRIPTOR_FONT_NAME].Name = sFontName; + pSymbol[XML_SYMBOL_DESCRIPTOR_FONT_NAME].Value <<= pDescriptor->sFontName; + pSymbol[XML_SYMBOL_DESCRIPTOR_CHAR_SET].Name = sCharSet; + pSymbol[XML_SYMBOL_DESCRIPTOR_CHAR_SET].Value <<= pDescriptor->nCharSet; + pSymbol[XML_SYMBOL_DESCRIPTOR_FAMILY].Name = sFamily; + pSymbol[XML_SYMBOL_DESCRIPTOR_FAMILY].Value <<= pDescriptor->nFamily; + pSymbol[XML_SYMBOL_DESCRIPTOR_PITCH].Name = sPitch; + pSymbol[XML_SYMBOL_DESCRIPTOR_PITCH].Value <<= pDescriptor->nPitch; + pSymbol[XML_SYMBOL_DESCRIPTOR_WEIGHT].Name = sWeight; + pSymbol[XML_SYMBOL_DESCRIPTOR_WEIGHT].Value <<= pDescriptor->nWeight; + pSymbol[XML_SYMBOL_DESCRIPTOR_ITALIC].Name = sItalic; + pSymbol[XML_SYMBOL_DESCRIPTOR_ITALIC].Value <<= pDescriptor->nItalic; + pSymbol[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET].Name = sSymbolSet; + pSymbol[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET].Value <<= pDescriptor->sSymbolSet; + pSymbol[XML_SYMBOL_DESCRIPTOR_CHARACTER].Name = sCharacter; + pSymbol[XML_SYMBOL_DESCRIPTOR_CHARACTER].Value <<= pDescriptor->nCharacter; + + xBox->insertByIndex(nIndex, uno::makeAny( aSequence )); + } + + exportIndexAccess( xBox, rName ); +} +void XMLSettingsExportHelper::exportbase64Binary( + const uno::Sequence<sal_Int8>& aProps, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_BASE64BINARY ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + if(aProps.hasElements()) + { + OUStringBuffer sBuffer; + ::comphelper::Base64::encode(sBuffer, aProps); + m_rContext.Characters( sBuffer.makeStringAndClear() ); + } + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportMapEntry(const uno::Any& rAny, + const OUString& rName, + const bool bNameAccess) const +{ + DBG_ASSERT((bNameAccess && !rName.isEmpty()) || !bNameAccess, "no name"); + uno::Sequence<beans::PropertyValue> aProps; + rAny >>= aProps; + if (aProps.hasElements()) + { + if (bNameAccess) + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.StartElement( XML_CONFIG_ITEM_MAP_ENTRY ); + for (const auto& rProp : std::as_const(aProps)) + CallTypeFunction(rProp.Value, rProp.Name); + m_rContext.EndElement( true ); + } +} + +void XMLSettingsExportHelper::exportNameAccess( + const uno::Reference<container::XNameAccess>& aNamed, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + DBG_ASSERT(aNamed->getElementType().equals(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get() ), + "wrong NameAccess" ); + if(aNamed->hasElements()) + { + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.StartElement( XML_CONFIG_ITEM_MAP_NAMED ); + const uno::Sequence< OUString > aNames(aNamed->getElementNames()); + for (const auto& rElementName : aNames) + exportMapEntry(aNamed->getByName(rElementName), rElementName, true); + m_rContext.EndElement( true ); + } +} + +void XMLSettingsExportHelper::exportIndexAccess( + const uno::Reference<container::XIndexAccess>& rIndexed, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + DBG_ASSERT(rIndexed->getElementType().equals(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get() ), + "wrong IndexAccess" ); + if (rIndexed->hasElements()) + { + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.StartElement( XML_CONFIG_ITEM_MAP_INDEXED ); + sal_Int32 nCount = rIndexed->getCount(); + for (sal_Int32 i = 0; i < nCount; i++) + { + exportMapEntry(rIndexed->getByIndex(i), "", false); + } + m_rContext.EndElement( true ); + } +} + +void XMLSettingsExportHelper::exportForbiddenCharacters( + const uno::Any &rAny, + const OUString& rName) const +{ + uno::Reference<i18n::XForbiddenCharacters> xForbChars; + uno::Reference<linguistic2::XSupportedLocales> xLocales; + + rAny >>= xForbChars; + rAny >>= xLocales; + + SAL_WARN_IF( !(xForbChars.is() && xLocales.is()), "xmloff","XMLSettingsExportHelper::exportForbiddenCharacters: got illegal forbidden characters!" ); + + if( !xForbChars.is() || !xLocales.is() ) + return; + + uno::Reference< container::XIndexContainer > xBox = document::IndexedPropertyValues::create(m_rContext.GetComponentContext()); + const uno::Sequence< lang::Locale > aLocales( xLocales->getLocales() ); + + /* FIXME-BCP47: this stupid and counterpart in + * xmloff/source/core/DocumentSettingsContext.cxx + * XMLConfigItemMapIndexedContext::EndElement() */ + + const OUString sLanguage ( "Language" ); + const OUString sCountry ( "Country" ); + const OUString sVariant ( "Variant" ); + const OUString sBeginLine ( "BeginLine" ); + const OUString sEndLine ( "EndLine" ); + + sal_Int32 nPos = 0; + for( const auto& rLocale : aLocales ) + { + if( xForbChars->hasForbiddenCharacters( rLocale ) ) + { + const i18n::ForbiddenCharacters aChars( xForbChars->getForbiddenCharacters( rLocale ) ); + + + uno::Sequence < beans::PropertyValue > aSequence ( XML_FORBIDDEN_CHARACTER_MAX ); + beans::PropertyValue *pForChar = aSequence.getArray(); + + pForChar[XML_FORBIDDEN_CHARACTER_LANGUAGE].Name = sLanguage; + pForChar[XML_FORBIDDEN_CHARACTER_LANGUAGE].Value <<= rLocale.Language; + pForChar[XML_FORBIDDEN_CHARACTER_COUNTRY].Name = sCountry; + pForChar[XML_FORBIDDEN_CHARACTER_COUNTRY].Value <<= rLocale.Country; + pForChar[XML_FORBIDDEN_CHARACTER_VARIANT].Name = sVariant; + pForChar[XML_FORBIDDEN_CHARACTER_VARIANT].Value <<= rLocale.Variant; + pForChar[XML_FORBIDDEN_CHARACTER_BEGIN_LINE].Name = sBeginLine; + pForChar[XML_FORBIDDEN_CHARACTER_BEGIN_LINE].Value <<= aChars.beginLine; + pForChar[XML_FORBIDDEN_CHARACTER_END_LINE].Name = sEndLine; + pForChar[XML_FORBIDDEN_CHARACTER_END_LINE].Value <<= aChars.endLine; + xBox->insertByIndex(nPos++, uno::makeAny( aSequence )); + } + } + + exportIndexAccess( xBox, rName ); +} + +void XMLSettingsExportHelper::exportAllSettings( + const uno::Sequence<beans::PropertyValue>& aProps, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + exportSequencePropertyValue(aProps, rName); +} + + +/** For some settings we may want to change their API representation + * from their XML settings representation. This is your chance to do + * so! + */ +void XMLSettingsExportHelper::ManipulateSetting( uno::Any& rAny, const OUString& rName ) const +{ + if( rName == gsPrinterIndependentLayout ) + { + sal_Int16 nTmp = sal_Int16(); + if( rAny >>= nTmp ) + { + if( nTmp == document::PrinterIndependentLayout::LOW_RESOLUTION ) + rAny <<= OUString("low-resolution"); + else if( nTmp == document::PrinterIndependentLayout::DISABLED ) + rAny <<= OUString("disabled"); + else if( nTmp == document::PrinterIndependentLayout::HIGH_RESOLUTION ) + rAny <<= OUString("high-resolution"); + } + } + else if( (rName == gsColorTableURL) || (rName == gsLineEndTableURL) || (rName == gsHatchTableURL) || + (rName == gsDashTableURL) || (rName == gsGradientTableURL) || (rName == gsBitmapTableURL ) ) + { + if( !mxStringSubsitution.is() ) + { + try + { + const_cast< XMLSettingsExportHelper* >(this)->mxStringSubsitution = + util::PathSubstitution::create( m_rContext.GetComponentContext() ); + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.core"); + } + } + + if( mxStringSubsitution.is() ) + { + OUString aURL; + rAny >>= aURL; + aURL = mxStringSubsitution->reSubstituteVariables( aURL ); + rAny <<= aURL; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |