From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- xmloff/source/chart/ColorPropertySet.cxx | 156 + xmloff/source/chart/ColorPropertySet.hxx | 85 + xmloff/source/chart/MultiPropertySetHandler.hxx | 245 ++ xmloff/source/chart/PropertyMap.hxx | 386 ++ xmloff/source/chart/PropertyMaps.cxx | 708 ++++ xmloff/source/chart/SchXMLAutoStylePoolP.cxx | 77 + xmloff/source/chart/SchXMLAxisContext.cxx | 1022 ++++++ xmloff/source/chart/SchXMLAxisContext.hxx | 80 + .../chart/SchXMLCalculationSettingsContext.cxx | 76 + .../chart/SchXMLCalculationSettingsContext.hxx | 44 + xmloff/source/chart/SchXMLChartContext.cxx | 1242 +++++++ xmloff/source/chart/SchXMLChartContext.hxx | 151 + xmloff/source/chart/SchXMLEnumConverter.cxx | 83 + xmloff/source/chart/SchXMLEnumConverter.hxx | 33 + xmloff/source/chart/SchXMLExport.cxx | 3852 ++++++++++++++++++++ xmloff/source/chart/SchXMLImport.cxx | 617 ++++ xmloff/source/chart/SchXMLLegendContext.cxx | 220 ++ xmloff/source/chart/SchXMLLegendContext.hxx | 41 + xmloff/source/chart/SchXMLParagraphContext.cxx | 110 + xmloff/source/chart/SchXMLParagraphContext.hxx | 56 + xmloff/source/chart/SchXMLPlotAreaContext.cxx | 1252 +++++++ xmloff/source/chart/SchXMLPlotAreaContext.hxx | 305 ++ .../source/chart/SchXMLPropertyMappingContext.cxx | 118 + .../source/chart/SchXMLPropertyMappingContext.hxx | 48 + .../chart/SchXMLRegressionCurveObjectContext.cxx | 199 + .../chart/SchXMLRegressionCurveObjectContext.hxx | 79 + xmloff/source/chart/SchXMLSeries2Context.cxx | 1188 ++++++ xmloff/source/chart/SchXMLSeries2Context.hxx | 133 + xmloff/source/chart/SchXMLSeriesHelper.cxx | 224 ++ xmloff/source/chart/SchXMLTableContext.cxx | 1075 ++++++ xmloff/source/chart/SchXMLTableContext.hxx | 188 + xmloff/source/chart/SchXMLTextListContext.cxx | 119 + xmloff/source/chart/SchXMLTextListContext.hxx | 52 + xmloff/source/chart/SchXMLTools.cxx | 856 +++++ xmloff/source/chart/SchXMLTools.hxx | 139 + xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx | 134 + xmloff/source/chart/XMLAxisPositionPropertyHdl.hxx | 39 + xmloff/source/chart/XMLChartPropertyContext.cxx | 75 + xmloff/source/chart/XMLChartPropertyContext.hxx | 49 + xmloff/source/chart/XMLChartStyleContext.cxx | 148 + .../source/chart/XMLErrorBarStylePropertyHdl.cxx | 59 + .../source/chart/XMLErrorBarStylePropertyHdl.hxx | 35 + .../source/chart/XMLErrorIndicatorPropertyHdl.cxx | 103 + .../source/chart/XMLErrorIndicatorPropertyHdl.hxx | 40 + xmloff/source/chart/XMLLabelSeparatorContext.cxx | 73 + xmloff/source/chart/XMLLabelSeparatorContext.hxx | 47 + xmloff/source/chart/XMLSymbolImageContext.cxx | 140 + xmloff/source/chart/XMLSymbolImageContext.hxx | 52 + xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx | 166 + xmloff/source/chart/XMLSymbolTypePropertyHdl.hxx | 39 + xmloff/source/chart/XMLTextOrientationHdl.cxx | 72 + xmloff/source/chart/XMLTextOrientationHdl.hxx | 40 + xmloff/source/chart/contexts.cxx | 197 + xmloff/source/chart/contexts.hxx | 107 + xmloff/source/chart/transporttypes.cxx | 30 + xmloff/source/chart/transporttypes.hxx | 202 + 56 files changed, 17106 insertions(+) create mode 100644 xmloff/source/chart/ColorPropertySet.cxx create mode 100644 xmloff/source/chart/ColorPropertySet.hxx create mode 100644 xmloff/source/chart/MultiPropertySetHandler.hxx create mode 100644 xmloff/source/chart/PropertyMap.hxx create mode 100644 xmloff/source/chart/PropertyMaps.cxx create mode 100644 xmloff/source/chart/SchXMLAutoStylePoolP.cxx create mode 100644 xmloff/source/chart/SchXMLAxisContext.cxx create mode 100644 xmloff/source/chart/SchXMLAxisContext.hxx create mode 100644 xmloff/source/chart/SchXMLCalculationSettingsContext.cxx create mode 100644 xmloff/source/chart/SchXMLCalculationSettingsContext.hxx create mode 100644 xmloff/source/chart/SchXMLChartContext.cxx create mode 100644 xmloff/source/chart/SchXMLChartContext.hxx create mode 100644 xmloff/source/chart/SchXMLEnumConverter.cxx create mode 100644 xmloff/source/chart/SchXMLEnumConverter.hxx create mode 100644 xmloff/source/chart/SchXMLExport.cxx create mode 100644 xmloff/source/chart/SchXMLImport.cxx create mode 100644 xmloff/source/chart/SchXMLLegendContext.cxx create mode 100644 xmloff/source/chart/SchXMLLegendContext.hxx create mode 100644 xmloff/source/chart/SchXMLParagraphContext.cxx create mode 100644 xmloff/source/chart/SchXMLParagraphContext.hxx create mode 100644 xmloff/source/chart/SchXMLPlotAreaContext.cxx create mode 100644 xmloff/source/chart/SchXMLPlotAreaContext.hxx create mode 100644 xmloff/source/chart/SchXMLPropertyMappingContext.cxx create mode 100644 xmloff/source/chart/SchXMLPropertyMappingContext.hxx create mode 100644 xmloff/source/chart/SchXMLRegressionCurveObjectContext.cxx create mode 100644 xmloff/source/chart/SchXMLRegressionCurveObjectContext.hxx create mode 100644 xmloff/source/chart/SchXMLSeries2Context.cxx create mode 100644 xmloff/source/chart/SchXMLSeries2Context.hxx create mode 100644 xmloff/source/chart/SchXMLSeriesHelper.cxx create mode 100644 xmloff/source/chart/SchXMLTableContext.cxx create mode 100644 xmloff/source/chart/SchXMLTableContext.hxx create mode 100644 xmloff/source/chart/SchXMLTextListContext.cxx create mode 100644 xmloff/source/chart/SchXMLTextListContext.hxx create mode 100644 xmloff/source/chart/SchXMLTools.cxx create mode 100644 xmloff/source/chart/SchXMLTools.hxx create mode 100644 xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx create mode 100644 xmloff/source/chart/XMLAxisPositionPropertyHdl.hxx create mode 100644 xmloff/source/chart/XMLChartPropertyContext.cxx create mode 100644 xmloff/source/chart/XMLChartPropertyContext.hxx create mode 100644 xmloff/source/chart/XMLChartStyleContext.cxx create mode 100644 xmloff/source/chart/XMLErrorBarStylePropertyHdl.cxx create mode 100644 xmloff/source/chart/XMLErrorBarStylePropertyHdl.hxx create mode 100644 xmloff/source/chart/XMLErrorIndicatorPropertyHdl.cxx create mode 100644 xmloff/source/chart/XMLErrorIndicatorPropertyHdl.hxx create mode 100644 xmloff/source/chart/XMLLabelSeparatorContext.cxx create mode 100644 xmloff/source/chart/XMLLabelSeparatorContext.hxx create mode 100644 xmloff/source/chart/XMLSymbolImageContext.cxx create mode 100644 xmloff/source/chart/XMLSymbolImageContext.hxx create mode 100644 xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx create mode 100644 xmloff/source/chart/XMLSymbolTypePropertyHdl.hxx create mode 100644 xmloff/source/chart/XMLTextOrientationHdl.cxx create mode 100644 xmloff/source/chart/XMLTextOrientationHdl.hxx create mode 100644 xmloff/source/chart/contexts.cxx create mode 100644 xmloff/source/chart/contexts.hxx create mode 100644 xmloff/source/chart/transporttypes.cxx create mode 100644 xmloff/source/chart/transporttypes.hxx (limited to 'xmloff/source/chart') diff --git a/xmloff/source/chart/ColorPropertySet.cxx b/xmloff/source/chart/ColorPropertySet.cxx new file mode 100644 index 000000000..59ebd9ae6 --- /dev/null +++ b/xmloff/source/chart/ColorPropertySet.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 "ColorPropertySet.hxx" + +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +class lcl_ColorPropertySetInfo : public ::cppu::WeakImplHelper< + XPropertySetInfo > +{ +public: + explicit lcl_ColorPropertySetInfo(); + +protected: + // ____ XPropertySetInfo ____ + virtual Sequence< Property > SAL_CALL getProperties() override; + virtual Property SAL_CALL getPropertyByName( const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override; + +private: + static constexpr OUStringLiteral g_aColorPropName = "FillColor"; + Property m_aColorProp; +}; + +lcl_ColorPropertySetInfo::lcl_ColorPropertySetInfo() : + m_aColorProp( g_aColorPropName, -1, + cppu::UnoType::get(), 0) +{} + +Sequence< Property > SAL_CALL lcl_ColorPropertySetInfo::getProperties() +{ + + return Sequence< Property >( & m_aColorProp, 1 ); +} + +Property SAL_CALL lcl_ColorPropertySetInfo::getPropertyByName( const OUString& aName ) +{ + if( aName == g_aColorPropName ) + return m_aColorProp; + throw UnknownPropertyException( g_aColorPropName, static_cast< uno::XWeak * >( this )); +} + +sal_Bool SAL_CALL lcl_ColorPropertySetInfo::hasPropertyByName( const OUString& Name ) +{ + return Name == g_aColorPropName; +} + +} // anonymous namespace + +namespace xmloff::chart +{ + +ColorPropertySet::ColorPropertySet( sal_Int32 nColor ) : + m_nColor( nColor ), + m_nDefaultColor( 0x0099ccff ) // blue 8 +{} + +ColorPropertySet::~ColorPropertySet() +{} + +// ____ XPropertySet ____ + +Reference< XPropertySetInfo > SAL_CALL ColorPropertySet::getPropertySetInfo() +{ + if( ! m_xInfo.is()) + m_xInfo.set( new lcl_ColorPropertySetInfo ); + + return m_xInfo; +} + +void SAL_CALL ColorPropertySet::setPropertyValue( const OUString& /* aPropertyName */, const uno::Any& aValue ) +{ + aValue >>= m_nColor; +} + +uno::Any SAL_CALL ColorPropertySet::getPropertyValue( const OUString& /* PropertyName */ ) +{ + return uno::makeAny( m_nColor ); +} + +void SAL_CALL ColorPropertySet::addPropertyChangeListener( const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* xListener */ ) +{ + OSL_FAIL( "Not Implemented" ); +} + +void SAL_CALL ColorPropertySet::removePropertyChangeListener( const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* aListener */ ) +{ + OSL_FAIL( "Not Implemented" ); +} + +void SAL_CALL ColorPropertySet::addVetoableChangeListener( const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL( "Not Implemented" ); +} + +void SAL_CALL ColorPropertySet::removeVetoableChangeListener( const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL( "Not Implemented" ); +} + +// ____ XPropertyState ____ + +PropertyState SAL_CALL ColorPropertySet::getPropertyState( const OUString& /* PropertyName */ ) +{ + return PropertyState_DIRECT_VALUE; +} + +Sequence< PropertyState > SAL_CALL ColorPropertySet::getPropertyStates( const Sequence< OUString >& /* aPropertyName */ ) +{ + PropertyState aState = PropertyState_DIRECT_VALUE; + // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence + return Sequence(&aState, 1); +} + +void SAL_CALL ColorPropertySet::setPropertyToDefault( const OUString& PropertyName ) +{ + if( PropertyName == g_aColorPropName ) + m_nColor = m_nDefaultColor; +} + +uno::Any SAL_CALL ColorPropertySet::getPropertyDefault( const OUString& aPropertyName ) +{ + if( aPropertyName == g_aColorPropName ) + return uno::makeAny( m_nDefaultColor ); + return uno::Any(); +} + +} // namespace xmloff::chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/ColorPropertySet.hxx b/xmloff/source/chart/ColorPropertySet.hxx new file mode 100644 index 000000000..f10d9e10e --- /dev/null +++ b/xmloff/source/chart/ColorPropertySet.hxx @@ -0,0 +1,85 @@ +/* -*- 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 . + */ +#ifndef XMLOFF_COLORPROPERTYSET_HXX +#define XMLOFF_COLORPROPERTYSET_HXX + +#include +#include + +#include +#include + +namespace xmloff +{ +namespace chart +{ + +class ColorPropertySet : public ::cppu::WeakImplHelper< + css::beans::XPropertySet, + css::beans::XPropertyState > +{ +public: + explicit ColorPropertySet( sal_Int32 nColor ); + virtual ~ColorPropertySet() override; + +protected: + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + virtual void SAL_CALL setPropertyValue( + const OUString& aPropertyName, + const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( + const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + // ____ XPropertyState ____ + virtual css::beans::PropertyState SAL_CALL getPropertyState( + const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( + const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( + const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( + const OUString& aPropertyName ) override; + +private: + css::uno::Reference< css::beans::XPropertySetInfo > m_xInfo; + static constexpr OUStringLiteral g_aColorPropName = "FillColor"; + Color m_nColor; + Color m_nDefaultColor; +}; + +} // namespace chart +} // namespace xmloff + +// XMLOFF_COLORPROPERTYSET_HXX +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/MultiPropertySetHandler.hxx b/xmloff/source/chart/MultiPropertySetHandler.hxx new file mode 100644 index 000000000..ddbd9881f --- /dev/null +++ b/xmloff/source/chart/MultiPropertySetHandler.hxx @@ -0,0 +1,245 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_MULTIPROPERTYSETHANDLER_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_MULTIPROPERTYSETHANDLER_HXX + +#include +#include + +#include +#include +#include + +/** @descr MultiPropertySetHandler handles the two slightly different + interfaces XPropertySet and XMultiPropertySet for accessing + properties of an object. + + It uses the classes PropertyWrapperBase and the template + PropertyWrapper for a type safe access to single properties. + + The function class OUStringComparison is used by a STL map to + sort the properties by names. +*/ + +/** @descr Base class for the templated property wrappers. + Having a common base class allows to set a variable to the + property's value without explicit knowledge of its type. +*/ +class PropertyWrapperBase +{ +public: + /** @descr Create a class instance and store the given name. + @param rName The name of the property. + */ + explicit PropertyWrapperBase (const OUString & rName) + : msName (rName) + {} + virtual ~PropertyWrapperBase() + {} + + /** @descr Abstract interface of a method for setting a variables + value to that of the property. + */ + virtual void SetValue (const css::uno::Any & rValue) = 0; + + const OUString msName; +}; + +/** @descr For every property type there will be one instantiation of this + template class with its own and type specific version of SetValue. +*/ +template class PropertyWrapper : public PropertyWrapperBase +{ +public: + /** @descr Create a wrapper for a property of type T. + */ + PropertyWrapper (const OUString & rName, T & rValue) + : PropertyWrapperBase (rName), + mrValue (rValue) + {} + + /** descr Set the given value inside an Any to the variable referenced + by the data member. + */ + virtual void SetValue (const css::uno::Any & rValue) override + { + rValue >>= mrValue; + } + +private: + /// Reference to a variable. Its value can be modified by a call to SetValue. + T & mrValue; +}; + +/** @descr Function object for comparing two OUStrings. +*/ +class OUStringComparison +{ +public: + /// Compare two strings. Returns true if the first is before the second. + bool operator() (const OUString & a, const OUString & b) const + { + return (a.compareTo (b) < 0); + } +}; + +/** @descr This class lets you get the values from an object that either + supports the interface XPropertySet or XMultiPropertySet. If it + supports both interfaces then XMultiPropertySet is preferred. + + Using it works in three steps. + 1. Create an instance and pass a reference to the object from which to + get the property values. + 2. Make all properties whose values you want to get known to the object + by using the Add method. This creates instances of a template class + that stores the properties name and a reference to the variable in + which to store its value. + 3. Finally call GetProperties to store the properties values into the + variables specified in step 2. This uses either the XPropertySet or + (preferred) the XMultiPropertySet interface. +*/ +class MultiPropertySetHandler +{ +public: + /** @descr Create a handler of the property set of the given + object. + @param xObject A reference to any of the object's interfaces. + not necessarily XPropertySet or XMultiPropertySet. It + is casted later to one of the two of them. + */ + explicit MultiPropertySetHandler (css::uno::Reference< + css::uno::XInterface> const & xObject); + /** @descr Add a property to handle. The type given implicitly by the + reference to a variable is used to create an instance of + the PropertyWrapper template class. + @param sName Name of the property. + @param rValue Reference to a variable whose value is set by the + call to GetProperties to the property's value. + */ + template void Add (const OUString & sName, T& rValue) + { + aPropertyList[sName] = std::make_unique>(sName, rValue); + } + + /** @descr Try to get the values for all properties added with the Add + method. If possible it uses the XMultiPropertySet. If that fails + (i.e. for an UnknownPropertyExcption) or if the interface is not + supported it uses the XPropertySet interface. + @return If none of the two interfaces is supported or using them both + fails then sal_False is returned. Else True is returned. + */ + inline bool GetProperties(); + +private: + /** @descr Try to use the XMultiPropertySet interface to get the property + values. + @param rNameList A precomputed and sorted sequence of OUStrings + containing the properties names. + @return True if values could be derived. + */ + inline bool MultiGet (const css::uno::Sequence< + OUString> & rNameList); + + /** @descr Try to use the XPropertySet interface to get the property + values. + @param rNameList A precomputed and sorted sequence of OUStrings + containing the properties names. + @return True if values could be derived. + */ + inline bool SingleGet (const css::uno::Sequence< + OUString> & rNameList); + + /** @descr STL map that maps from property names to polymorphic instances of + PropertyWrapper. It uses OUStringComparison for sorting + the property names. + */ + ::std::map< OUString, std::unique_ptr, OUStringComparison> aPropertyList; + + /// The object from which to get the property values. + css::uno::Reference< css::uno::XInterface> mxObject; +}; + +MultiPropertySetHandler::MultiPropertySetHandler (css::uno::Reference< + css::uno::XInterface> const & xObject) + : mxObject (xObject) +{ +} + +bool MultiPropertySetHandler::GetProperties() +{ + css::uno::Sequence< OUString> aNameList (aPropertyList.size()); + int i = 0; + for (const auto& rProperty : aPropertyList) + aNameList[i++] = rProperty.second->msName; + if ( ! MultiGet(aNameList)) + if ( ! SingleGet(aNameList)) + return false; + return true; +} + +bool MultiPropertySetHandler::MultiGet (const css::uno::Sequence< + OUString> & rNameList) +{ + css::uno::Reference< css::beans::XMultiPropertySet> xMultiSet ( + mxObject, css::uno::UNO_QUERY); + if (xMultiSet.is()) + try + { + int i = 0; + css::uno::Sequence< css::uno::Any> aValueList = + xMultiSet->getPropertyValues (rNameList); + for (auto& rProperty : aPropertyList) + rProperty.second->SetValue (aValueList[i++]); + } + catch (const css::beans::UnknownPropertyException&) + { + return false; + } + else + return false; + + return true; +} + +bool MultiPropertySetHandler::SingleGet (const css::uno::Sequence< + OUString> & rNameList) +{ + css::uno::Reference< css::beans::XPropertySet> xSingleSet ( + mxObject, css::uno::UNO_QUERY); + if (xSingleSet.is()) + try + { + int i = 0; + for (auto& rProperty : aPropertyList) + rProperty.second->SetValue (xSingleSet->getPropertyValue (rNameList[i++])); + } + catch (const css::beans::UnknownPropertyException&) + { + return false; + } + else + return false; + + return true; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/PropertyMap.hxx b/xmloff/source/chart/PropertyMap.hxx new file mode 100644 index 000000000..d11497847 --- /dev/null +++ b/xmloff/source/chart/PropertyMap.hxx @@ -0,0 +1,386 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_PROPERTYMAP_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_PROPERTYMAP_HXX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// custom types +#define XML_SCH_TYPE_AXIS_ARRANGEMENT ( XML_SCH_TYPES_START + 0 ) +#define XML_SCH_TYPE_ERROR_BAR_STYLE ( XML_SCH_TYPES_START + 1 ) +// free +#define XML_SCH_TYPE_SOLID_TYPE ( XML_SCH_TYPES_START + 3 ) +#define XML_SCH_TYPE_ERROR_INDICATOR_UPPER ( XML_SCH_TYPES_START + 4 ) +#define XML_SCH_TYPE_ERROR_INDICATOR_LOWER ( XML_SCH_TYPES_START + 5 ) +#define XML_SCH_TYPE_DATAROWSOURCE ( XML_SCH_TYPES_START + 6 ) +#define XML_SCH_TYPE_TEXT_ORIENTATION ( XML_SCH_TYPES_START + 7 ) +#define XML_SCH_TYPE_INTERPOLATION ( XML_SCH_TYPES_START + 8 ) +#define XML_SCH_TYPE_SYMBOL_TYPE ( XML_SCH_TYPES_START + 9 ) +#define XML_SCH_TYPE_NAMED_SYMBOL ( XML_SCH_TYPES_START + 10 ) +#define XML_SCH_TYPE_LABEL_PLACEMENT_TYPE ( XML_SCH_TYPES_START + 11 ) +#define XML_SCH_TYPE_MISSING_VALUE_TREATMENT ( XML_SCH_TYPES_START + 12 ) +#define XML_SCH_TYPE_AXIS_POSITION ( XML_SCH_TYPES_START + 13 ) +#define XML_SCH_TYPE_AXIS_POSITION_VALUE ( XML_SCH_TYPES_START + 14 ) +#define XML_SCH_TYPE_AXIS_LABEL_POSITION ( XML_SCH_TYPES_START + 15 ) +#define XML_SCH_TYPE_TICK_MARK_POSITION ( XML_SCH_TYPES_START + 16 ) +#define XML_SCH_TYPE_LABEL_BORDER_STYLE ( XML_SCH_TYPES_START + 17 ) +#define XML_SCH_TYPE_LABEL_BORDER_OPACITY ( XML_SCH_TYPES_START + 18 ) +#define XML_SCH_TYPE_LABEL_FILL_STYLE ( XML_SCH_TYPES_START + 19 ) + +// context ids +#define XML_SCH_CONTEXT_USER_SYMBOL ( XML_SCH_CTF_START + 0 ) +#define XML_SCH_CONTEXT_MIN ( XML_SCH_CTF_START + 1 ) +#define XML_SCH_CONTEXT_MAX ( XML_SCH_CTF_START + 2 ) +#define XML_SCH_CONTEXT_STEP_MAIN ( XML_SCH_CTF_START + 3 ) +#define XML_SCH_CONTEXT_STEP_HELP_COUNT ( XML_SCH_CTF_START + 4 ) +#define XML_SCH_CONTEXT_ORIGIN ( XML_SCH_CTF_START + 5 ) +#define XML_SCH_CONTEXT_LOGARITHMIC ( XML_SCH_CTF_START + 6 ) +#define XML_SCH_CONTEXT_STOCK_WITH_VOLUME ( XML_SCH_CTF_START + 7 ) +#define XML_SCH_CONTEXT_LINES_USED ( XML_SCH_CTF_START + 8 ) + +#define XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_INNER ( XML_SCH_CTF_START + 10 ) +#define XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_OUTER ( XML_SCH_CTF_START + 11 ) +#define XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_INNER ( XML_SCH_CTF_START + 12 ) +#define XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_OUTER ( XML_SCH_CTF_START + 13 ) +#define XML_SCH_CONTEXT_SPECIAL_TEXT_ROTATION ( XML_SCH_CTF_START + 14 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_NUMBER ( XML_SCH_CTF_START + 15 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_TEXT ( XML_SCH_CTF_START + 16 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SYMBOL ( XML_SCH_CTF_START + 17 ) +#define XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT ( XML_SCH_CTF_START + 18 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_ROW_SOURCE ( XML_SCH_CTF_START + 19 ) +#define XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH ( XML_SCH_CTF_START + 20 ) +#define XML_SCH_CONTEXT_SPECIAL_SYMBOL_HEIGHT ( XML_SCH_CTF_START + 21 ) +#define XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE_NAME ( XML_SCH_CTF_START + 22 ) +#define XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE ( XML_SCH_CTF_START + 23 ) +#define XML_SCH_CONTEXT_SPECIAL_LABEL_SEPARATOR ( XML_SCH_CTF_START + 24 ) +#define XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE ( XML_SCH_CTF_START + 25 ) +#define XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE ( XML_SCH_CTF_START + 26 ) + +#define MAP_FULL( ApiName, NameSpace, XMLTokenName, XMLType, ContextId, EarliestODFVersionForExport ) { ApiName, sizeof(ApiName)-1, XML_NAMESPACE_##NameSpace, xmloff::token::XMLTokenName, XMLType|XML_TYPE_PROP_CHART, ContextId, EarliestODFVersionForExport, false } +#define MAP_ENTRY( a, ns, nm, t ) { a, sizeof(a)-1, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_010, false } +#define MAP_ENTRY_ODF12( a, ns, nm, t ) { a, sizeof(a)-1, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_012, false } +#define MAP_ENTRY_ODF13( a, ns, nm, t ) { a, sizeof(a)-1, ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_013, false } +#define MAP_ENTRY_ODF_EXT( a, ns, nm, t ) { a, sizeof(a)-1, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false } +#define MAP_ENTRY_ODF_EXT_IMPORT( a, ns, nm, t ) { a, sizeof(a)-1, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, true } +#define MAP_CONTEXT( a, ns, nm, t, c ) { a, sizeof(a)-1, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, c, SvtSaveOptions::ODFSVER_010, false } +#define MAP_SPECIAL( a, ns, nm, t, c ) { a, sizeof(a)-1, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART | MID_FLAG_SPECIAL_ITEM, c, SvtSaveOptions::ODFSVER_010, false } +#define MAP_SPECIAL_ODF12( a, ns, nm, t, c ) { a, sizeof(a)-1, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART | MID_FLAG_SPECIAL_ITEM, c, SvtSaveOptions::ODFSVER_012, false } +#define MAP_ENTRY_END { nullptr,0,0,xmloff::token::XML_TOKEN_INVALID,0,0,SvtSaveOptions::ODFSVER_010, false } + +// PropertyMap for Chart properties drawing- and +// textproperties are added later using the chaining +// mechanism + +// only create maps once! +// this define is set in PropertyMaps.cxx + +#ifdef XML_SCH_CREATE_GLOBAL_MAPS + +const XMLPropertyMapEntry aXMLChartPropMap[] = +{ + // chart subtypes + MAP_ENTRY( "UpDown", CHART, XML_JAPANESE_CANDLE_STICK, XML_TYPE_BOOL ), // formerly XML_STOCK_UPDOWN_BARS + MAP_CONTEXT( "Volume", CHART, XML_STOCK_WITH_VOLUME, XML_TYPE_BOOL, XML_SCH_CONTEXT_STOCK_WITH_VOLUME ), + MAP_ENTRY( "Dim3D", CHART, XML_THREE_DIMENSIONAL, XML_TYPE_BOOL ), + MAP_ENTRY( "Deep", CHART, XML_DEEP, XML_TYPE_BOOL ), + MAP_ENTRY( "Lines", CHART, XML_LINES, XML_TYPE_BOOL ), + MAP_ENTRY( "Percent", CHART, XML_PERCENTAGE, XML_TYPE_BOOL ), + MAP_ENTRY( "SolidType", CHART, XML_SOLID_TYPE, XML_SCH_TYPE_SOLID_TYPE ), + // ODF 1.3 OFFICE-3662 added values + MAP_ENTRY( "SplineType", CHART, XML_INTERPOLATION, XML_SCH_TYPE_INTERPOLATION ), + MAP_ENTRY( "Stacked", CHART, XML_STACKED, XML_TYPE_BOOL ), + // type: "none", "automatic", "named-symbol" or "image" + MAP_ENTRY( "SymbolType", CHART, XML_SYMBOL_TYPE, XML_SCH_TYPE_SYMBOL_TYPE | MID_FLAG_MULTI_PROPERTY ), + // if type=="named-symbol" => name of symbol (square, diamond, ...) + MAP_ENTRY( "SymbolType", CHART, XML_SYMBOL_NAME, XML_SCH_TYPE_NAMED_SYMBOL | MID_FLAG_MULTI_PROPERTY ), + // if type=="image" => an xlink:href element with a linked (package) URI + MAP_SPECIAL( "SymbolBitmap", CHART, XML_SYMBOL_IMAGE, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE ), + MAP_SPECIAL( "SymbolSize", CHART, XML_SYMBOL_WIDTH, XML_TYPE_MEASURE | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH ), + MAP_SPECIAL( "SymbolSize", CHART, XML_SYMBOL_HEIGHT, XML_TYPE_MEASURE | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_SYMBOL_HEIGHT ), + MAP_ENTRY( "Vertical", CHART, XML_VERTICAL, XML_TYPE_BOOL ), + // #i32368# property should no longer be used as XML-property (in OASIS + // format), but is still ex-/imported for compatibility with the OOo file format + MAP_CONTEXT( "NumberOfLines", CHART, XML_LINES_USED, XML_TYPE_NUMBER, XML_SCH_CONTEXT_LINES_USED ), + MAP_ENTRY( "StackedBarsConnected", CHART, XML_CONNECT_BARS, XML_TYPE_BOOL ), + + MAP_ENTRY_ODF12( "GroupBarsPerAxis", CHART, XML_GROUP_BARS_PER_AXIS, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "IncludeHiddenCells", CHART, XML_INCLUDE_HIDDEN_CELLS, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "AutomaticPosition", CHART, XML_AUTOMATIC_POSITION, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "AutomaticSize", CHART, XML_AUTOMATIC_SIZE, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "StartingAngle", CHART, XML_ANGLE_OFFSET, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF12( "MissingValueTreatment", CHART, XML_TREAT_EMPTY_CELLS, XML_SCH_TYPE_MISSING_VALUE_TREATMENT ), + // #72304 Chart data table flags + MAP_ENTRY_ODF_EXT( "DataTableHBorder", LO_EXT, XML_DATA_TABLE_SHOW_HORZ_BORDER, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "DataTableVBorder", LO_EXT, XML_DATA_TABLE_SHOW_VERT_BORDER, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "DataTableOutline", LO_EXT, XML_DATA_TABLE_SHOW_OUTLINE, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT_IMPORT( "DataTableHBorder", CHART, XML_DATA_TABLE_SHOW_HORZ_BORDER, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT_IMPORT( "DataTableVBorder", CHART, XML_DATA_TABLE_SHOW_VERT_BORDER, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT_IMPORT( "DataTableOutline", CHART, XML_DATA_TABLE_SHOW_OUTLINE, XML_TYPE_BOOL ), + // Chart display units flags + MAP_ENTRY_ODF_EXT( "DisplayUnits", LO_EXT, XML_CHART_DUNITS_DISPLAYUNITS, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "BuiltInUnit", LO_EXT, XML_CHART_DUNITS_BUILTINUNIT, XML_TYPE_STRING ), + MAP_ENTRY_ODF_EXT( "ExternalData", LO_EXT, XML_EXTERNALDATA, XML_TYPE_STRING), + + MAP_ENTRY_ODF_EXT( "LabelBorderColor", LO_EXT, XML_LABEL_STROKE_COLOR, XML_TYPE_COLOR ), + MAP_ENTRY_ODF_EXT( "LabelBorderStyle", LO_EXT, XML_LABEL_STROKE, XML_SCH_TYPE_LABEL_BORDER_STYLE ), + MAP_ENTRY_ODF_EXT( "LabelBorderTransparency", LO_EXT, XML_LABEL_STROKE_OPACITY, XML_SCH_TYPE_LABEL_BORDER_OPACITY ), + MAP_ENTRY_ODF_EXT( "LabelBorderWidth", LO_EXT, XML_LABEL_STROKE_WIDTH, XML_TYPE_MEASURE ), + + MAP_ENTRY_ODF_EXT( "LabelFillColor", LO_EXT, XML_LABEL_FILL_COLOR, XML_TYPE_COLOR ), + MAP_ENTRY_ODF_EXT( "LabelFillStyle", LO_EXT, XML_LABEL_FILL, XML_SCH_TYPE_LABEL_FILL_STYLE ), + MAP_ENTRY_ODF_EXT( "LabelFillBackground", LO_EXT, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "LabelFillHatchName", LO_EXT, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME), + + MAP_ENTRY( "ScaleText", CHART, XML_SCALE_TEXT, XML_TYPE_BOOL ), + + // spline settings + MAP_ENTRY( "SplineOrder", CHART, XML_SPLINE_ORDER, XML_TYPE_NUMBER ), + MAP_ENTRY( "SplineResolution", CHART, XML_SPLINE_RESOLUTION, XML_TYPE_NUMBER ), + + // plot-area properties + MAP_ENTRY( "DataRowSource", CHART, XML_SERIES_SOURCE, XML_SCH_TYPE_DATAROWSOURCE ), + MAP_ENTRY_ODF12( "SortByXValues", CHART, XML_SORT_BY_X_VALUES, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "RightAngledAxes", CHART, XML_RIGHT_ANGLED_AXES, XML_TYPE_BOOL ), + + // axis properties + MAP_ENTRY( "DisplayLabels", CHART, XML_DISPLAY_LABEL, XML_TYPE_BOOL ), + MAP_SPECIAL( "Marks", CHART, XML_TICK_MARKS_MAJOR_INNER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_INNER ), // convert one constant + MAP_SPECIAL( "Marks", CHART, XML_TICK_MARKS_MAJOR_OUTER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_OUTER ), // to two bools + MAP_SPECIAL( "HelpMarks", CHART, XML_TICK_MARKS_MINOR_INNER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_INNER ), // see above + MAP_SPECIAL( "HelpMarks", CHART, XML_TICK_MARKS_MINOR_OUTER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_OUTER ), + MAP_CONTEXT( "Logarithmic", CHART, XML_LOGARITHMIC, XML_TYPE_BOOL, XML_SCH_CONTEXT_LOGARITHMIC ), + MAP_CONTEXT( "Min", CHART, XML_MINIMUM, XML_TYPE_DOUBLE, XML_SCH_CONTEXT_MIN ), + MAP_CONTEXT( "Max", CHART, XML_MAXIMUM, XML_TYPE_DOUBLE, XML_SCH_CONTEXT_MAX ), + MAP_CONTEXT( "Origin", CHART, XML_ORIGIN, XML_TYPE_DOUBLE, XML_SCH_CONTEXT_ORIGIN ), + MAP_CONTEXT( "StepMain", CHART, XML_INTERVAL_MAJOR, XML_TYPE_DOUBLE, XML_SCH_CONTEXT_STEP_MAIN ), + MAP_CONTEXT( "StepHelpCount", CHART, XML_INTERVAL_MINOR_DIVISOR, XML_TYPE_NUMBER, XML_SCH_CONTEXT_STEP_HELP_COUNT ), + MAP_ENTRY( "GapWidth", CHART, XML_GAP_WIDTH, XML_TYPE_NUMBER ), + MAP_ENTRY( "Overlap", CHART, XML_OVERLAP, XML_TYPE_NUMBER ), + MAP_ENTRY( "TextCanOverlap", CHART, XML_TEXT_OVERLAP, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "ReverseDirection", CHART, XML_REVERSE_DIRECTION, XML_TYPE_BOOL ), + MAP_ENTRY( "TextBreak", TEXT, XML_LINE_BREAK, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "TryStaggeringFirst", LO_EXT, XML_TRY_STAGGERING_FIRST, XML_TYPE_BOOL ), + MAP_ENTRY( "ArrangeOrder", CHART, XML_LABEL_ARRANGEMENT, XML_SCH_TYPE_AXIS_ARRANGEMENT ), + MAP_SPECIAL( "NumberFormat", STYLE, XML_DATA_STYLE_NAME, XML_TYPE_NUMBER, XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT ), + MAP_ENTRY( "LinkNumberFormatToSource", CHART, XML_LINK_DATA_STYLE_TO_SOURCE, XML_TYPE_BOOL ), + MAP_ENTRY( "Visible", CHART, XML_VISIBLE, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "MajorOrigin", LO_EXT, XML_MAJOR_ORIGIN, XML_TYPE_DOUBLE ), + + MAP_FULL( "CrossoverPosition", CHART, XML_AXIS_POSITION, XML_SCH_TYPE_AXIS_POSITION|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0, SvtSaveOptions::ODFSVER_012 ), + MAP_FULL( "CrossoverValue", CHART, XML_AXIS_POSITION, XML_SCH_TYPE_AXIS_POSITION_VALUE|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0, SvtSaveOptions::ODFSVER_012 ), + MAP_FULL( "LabelPosition", CHART, XML_AXIS_LABEL_POSITION, XML_SCH_TYPE_AXIS_LABEL_POSITION, 0, SvtSaveOptions::ODFSVER_012 ), + MAP_FULL( "MarkPosition", CHART, XML_TICK_MARK_POSITION, XML_SCH_TYPE_TICK_MARK_POSITION, 0, SvtSaveOptions::ODFSVER_012 ), + + // statistical properties + + MAP_ENTRY( "MeanValue", CHART, XML_MEAN_VALUE, XML_TYPE_BOOL ), + MAP_ENTRY( "ErrorMargin", CHART, XML_ERROR_MARGIN, XML_TYPE_DOUBLE ), + MAP_ENTRY( "PositiveError", CHART, XML_ERROR_LOWER_LIMIT, XML_TYPE_DOUBLE), + MAP_ENTRY( "NegativeError", CHART, XML_ERROR_UPPER_LIMIT, XML_TYPE_DOUBLE), + MAP_ENTRY( "ShowPositiveError", CHART, XML_ERROR_UPPER_INDICATOR, XML_TYPE_BOOL), + MAP_ENTRY( "ShowNegativeError", CHART, XML_ERROR_LOWER_INDICATOR, XML_TYPE_BOOL), + MAP_ENTRY( "ErrorBarStyle", CHART, XML_ERROR_CATEGORY, XML_SCH_TYPE_ERROR_BAR_STYLE ), + MAP_ENTRY( "PercentageError", CHART, XML_ERROR_PERCENTAGE, XML_TYPE_DOUBLE ), + + // regression curve properties + MAP_SPECIAL( "RegressionType", CHART, XML_REGRESSION_TYPE, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE ), + + // ODF 1.3 OFFICE-3958 + MAP_ENTRY_ODF13( "CurveName", XML_NAMESPACE_LO_EXT, XML_REGRESSION_CURVE_NAME, XML_TYPE_STRING ), + MAP_ENTRY_ODF13( "CurveName", XML_NAMESPACE_CHART, XML_REGRESSION_CURVE_NAME, XML_TYPE_STRING ), + MAP_ENTRY_ODF13( "PolynomialDegree", XML_NAMESPACE_LO_EXT, XML_REGRESSION_MAX_DEGREE, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF13( "PolynomialDegree", XML_NAMESPACE_CHART, XML_REGRESSION_MAX_DEGREE, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF13( "ForceIntercept", XML_NAMESPACE_LO_EXT, XML_REGRESSION_FORCE_INTERCEPT, XML_TYPE_BOOL ), + MAP_ENTRY_ODF13( "ForceIntercept", XML_NAMESPACE_CHART, XML_REGRESSION_FORCE_INTERCEPT, XML_TYPE_BOOL ), + MAP_ENTRY_ODF13( "InterceptValue", XML_NAMESPACE_LO_EXT, XML_REGRESSION_INTERCEPT_VALUE, XML_TYPE_DOUBLE ), + MAP_ENTRY_ODF13( "InterceptValue", XML_NAMESPACE_CHART, XML_REGRESSION_INTERCEPT_VALUE, XML_TYPE_DOUBLE ), + + // ODF 1.3 OFFICE-3959 + MAP_ENTRY_ODF13( "MovingAveragePeriod", XML_NAMESPACE_LO_EXT, XML_REGRESSION_PERIOD, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF13( "MovingAveragePeriod", XML_NAMESPACE_CHART, XML_REGRESSION_PERIOD, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF13( "MovingAverageType", XML_NAMESPACE_LO_EXT, XML_REGRESSION_MOVING_TYPE, XML_TYPE_STRING ), + MAP_ENTRY_ODF13( "MovingAverageType", XML_NAMESPACE_CHART, XML_REGRESSION_MOVING_TYPE, XML_TYPE_STRING ), + + MAP_ENTRY_ODF_EXT( "ExtrapolateForward", LO_EXT, XML_REGRESSION_EXTRAPOLATE_FORWARD, XML_TYPE_DOUBLE ), + MAP_ENTRY_ODF_EXT( "ExtrapolateBackward", LO_EXT, XML_REGRESSION_EXTRAPOLATE_BACKWARD, XML_TYPE_DOUBLE ), + MAP_ENTRY_ODF_EXT_IMPORT( "ExtrapolateForward", CHART, XML_REGRESSION_EXTRAPOLATE_FORWARD, XML_TYPE_DOUBLE ), + MAP_ENTRY_ODF_EXT_IMPORT( "ExtrapolateBackward", CHART, XML_REGRESSION_EXTRAPOLATE_BACKWARD, XML_TYPE_DOUBLE ), + + MAP_ENTRY_ODF_EXT( "XName", LO_EXT, XML_REGRESSION_X_NAME, XML_TYPE_STRING ), + MAP_ENTRY_ODF_EXT( "YName", LO_EXT, XML_REGRESSION_Y_NAME, XML_TYPE_STRING ), + + MAP_SPECIAL_ODF12( "ErrorBarRangePositive", CHART, XML_ERROR_UPPER_RANGE, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE ), // export only + MAP_SPECIAL_ODF12( "ErrorBarRangeNegative", CHART, XML_ERROR_LOWER_RANGE, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE ), // export only + + // errorbars properties (chart2) + MAP_ENTRY_ODF_EXT( "Weight", LO_EXT, XML_ERROR_STANDARD_WEIGHT, XML_TYPE_DOUBLE), + MAP_ENTRY_ODF_EXT_IMPORT( "Weight", CHART, XML_ERROR_STANDARD_WEIGHT, XML_TYPE_DOUBLE), + + // series/data-point properties + MAP_SPECIAL( "DataCaption", CHART, XML_DATA_LABEL_NUMBER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_NUMBER ), // convert one constant + MAP_SPECIAL( "DataCaption", CHART, XML_DATA_LABEL_TEXT, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_TEXT ), // to 'tristate' and two bools + MAP_SPECIAL( "DataCaption", CHART, XML_DATA_LABEL_SYMBOL, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SYMBOL ), + MAP_SPECIAL_ODF12( "LabelSeparator", CHART, XML_LABEL_SEPARATOR, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, XML_SCH_CONTEXT_SPECIAL_LABEL_SEPARATOR ), + MAP_ENTRY_ODF12( "LabelPlacement", CHART, XML_LABEL_POSITION, XML_SCH_TYPE_LABEL_PLACEMENT_TYPE ), + MAP_ENTRY( "SegmentOffset", CHART, XML_PIE_OFFSET, XML_TYPE_NUMBER ), + MAP_SPECIAL_ODF12( "PercentageNumberFormat", STYLE, XML_PERCENTAGE_DATA_STYLE_NAME, XML_TYPE_NUMBER, XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT ), + + // text properties for titles + MAP_SPECIAL( "TextRotation", STYLE, XML_ROTATION_ANGLE, XML_TYPE_NUMBER, XML_SCH_CONTEXT_SPECIAL_TEXT_ROTATION ), // convert 1/100th degrees to degrees + MAP_ENTRY( "StackedText", STYLE, XML_DIRECTION, XML_SCH_TYPE_TEXT_ORIENTATION ), + + // for compatibility to pre 6.0beta documents +// MAP_SPECIAL( "SymbolBitmap", CHART, XML_SYMBOL_IMAGE_NAME, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE_NAME ), + + MAP_ENTRY( "ChartUserDefinedAttributes", TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM ), + + MAP_ENTRY_END +}; + +// maps for enums to XML attributes + +const SvXMLEnumMapEntry aXMLChartAxisLabelPositionEnumMap[] = +{ + { ::xmloff::token::XML_NEAR_AXIS, css::chart::ChartAxisLabelPosition_NEAR_AXIS }, + { ::xmloff::token::XML_NEAR_AXIS_OTHER_SIDE, css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE }, + { ::xmloff::token::XML_OUTSIDE_START, css::chart::ChartAxisLabelPosition_OUTSIDE_START }, + { ::xmloff::token::XML_OUTSIDE_END, css::chart::ChartAxisLabelPosition_OUTSIDE_END }, + { ::xmloff::token::XML_OUTSIDE_MINIMUM, css::chart::ChartAxisLabelPosition_OUTSIDE_START },//#i114142# + { ::xmloff::token::XML_OUTSIDE_MAXIMUM, css::chart::ChartAxisLabelPosition_OUTSIDE_END },//#i114142# + { ::xmloff::token::XML_TOKEN_INVALID, css::chart::ChartAxisLabelPosition(0) } +}; + +const SvXMLEnumMapEntry aXMLChartAxisMarkPositionEnumMap[] = +{ + { ::xmloff::token::XML_AT_LABELS, css::chart::ChartAxisMarkPosition_AT_LABELS }, + { ::xmloff::token::XML_AT_AXIS, css::chart::ChartAxisMarkPosition_AT_AXIS }, + { ::xmloff::token::XML_AT_LABELS_AND_AXIS, css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS }, + { ::xmloff::token::XML_TOKEN_INVALID, css::chart::ChartAxisMarkPosition(0) } +}; + +const SvXMLEnumMapEntry aXMLChartAxisArrangementEnumMap[] = +{ + { ::xmloff::token::XML_SIDE_BY_SIDE, css::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE }, + { ::xmloff::token::XML_STAGGER_EVEN, css::chart::ChartAxisArrangeOrderType_STAGGER_EVEN }, + { ::xmloff::token::XML_STAGGER_ODD, css::chart::ChartAxisArrangeOrderType_STAGGER_ODD }, + { ::xmloff::token::XML_TOKEN_INVALID, css::chart::ChartAxisArrangeOrderType(0) } +}; + +const SvXMLEnumMapEntry aXMLChartErrorBarStyleEnumMap[] = +{ + { ::xmloff::token::XML_NONE, css::chart::ErrorBarStyle::NONE }, + { ::xmloff::token::XML_VARIANCE, css::chart::ErrorBarStyle::VARIANCE }, + { ::xmloff::token::XML_STANDARD_DEVIATION, css::chart::ErrorBarStyle::STANDARD_DEVIATION }, + { ::xmloff::token::XML_CONSTANT, css::chart::ErrorBarStyle::ABSOLUTE }, + { ::xmloff::token::XML_PERCENTAGE, css::chart::ErrorBarStyle::RELATIVE }, + { ::xmloff::token::XML_ERROR_MARGIN, css::chart::ErrorBarStyle::ERROR_MARGIN }, + { ::xmloff::token::XML_STANDARD_ERROR, css::chart::ErrorBarStyle::STANDARD_ERROR }, + { ::xmloff::token::XML_CELL_RANGE, css::chart::ErrorBarStyle::FROM_DATA }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry aXMLChartSolidTypeEnumMap[] = +{ + { ::xmloff::token::XML_CUBOID, css::chart::ChartSolidType::RECTANGULAR_SOLID }, + { ::xmloff::token::XML_CYLINDER, css::chart::ChartSolidType::CYLINDER }, + { ::xmloff::token::XML_CONE, css::chart::ChartSolidType::CONE }, + { ::xmloff::token::XML_PYRAMID, css::chart::ChartSolidType::PYRAMID }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry aXMLChartDataRowSourceTypeEnumMap[] = +{ + { ::xmloff::token::XML_COLUMNS, css::chart::ChartDataRowSource_COLUMNS }, + { ::xmloff::token::XML_ROWS, css::chart::ChartDataRowSource_ROWS }, + { ::xmloff::token::XML_TOKEN_INVALID, css::chart::ChartDataRowSource(0) } +}; + +const SvXMLEnumMapEntry g_XMLChartInterpolationTypeEnumMap_ODF12[] = +{ + // this is neither an enum nor a constants group, but just a + // documented long property + { ::xmloff::token::XML_NONE, 0 }, + { ::xmloff::token::XML_CUBIC_SPLINE, 1 }, + { ::xmloff::token::XML_B_SPLINE, 2 }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry g_XMLChartInterpolationTypeEnumMap[] = +{ + // this is neither an enum nor a constants group, but just a + // documented long property + { ::xmloff::token::XML_NONE, 0 }, + { ::xmloff::token::XML_CUBIC_SPLINE, 1 }, + { ::xmloff::token::XML_B_SPLINE, 2 }, + { ::xmloff::token::XML_STEP_START, 3 }, + { ::xmloff::token::XML_STEP_END, 4 }, + { ::xmloff::token::XML_STEP_CENTER_X, 5 }, + { ::xmloff::token::XML_STEP_CENTER_Y, 6 }, + // the GNM values should only be used for reading Gnumeric ods files + // they should never be used for writing ods file + { ::xmloff::token::XML_GNM_STEP_START, 3 }, + { ::xmloff::token::XML_GNM_STEP_END, 4 }, + { ::xmloff::token::XML_GNM_STEP_CENTER_X, 5 }, + { ::xmloff::token::XML_GNM_STEP_CENTER_Y, 6 }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry aXMLChartDataLabelPlacementEnumMap[] = +{ + { ::xmloff::token::XML_AVOID_OVERLAP, css::chart::DataLabelPlacement::AVOID_OVERLAP }, + { ::xmloff::token::XML_CENTER, css::chart::DataLabelPlacement::CENTER }, + { ::xmloff::token::XML_TOP, css::chart::DataLabelPlacement::TOP }, + { ::xmloff::token::XML_TOP_LEFT, css::chart::DataLabelPlacement::TOP_LEFT }, + { ::xmloff::token::XML_LEFT, css::chart::DataLabelPlacement::LEFT }, + { ::xmloff::token::XML_BOTTOM_LEFT, css::chart::DataLabelPlacement::BOTTOM_LEFT }, + { ::xmloff::token::XML_BOTTOM, css::chart::DataLabelPlacement::BOTTOM }, + { ::xmloff::token::XML_BOTTOM_RIGHT, css::chart::DataLabelPlacement::BOTTOM_RIGHT }, + { ::xmloff::token::XML_RIGHT, css::chart::DataLabelPlacement::RIGHT }, + { ::xmloff::token::XML_TOP_RIGHT, css::chart::DataLabelPlacement::TOP_RIGHT }, + { ::xmloff::token::XML_INSIDE, css::chart::DataLabelPlacement::INSIDE }, + { ::xmloff::token::XML_OUTSIDE, css::chart::DataLabelPlacement::OUTSIDE }, + { ::xmloff::token::XML_NEAR_ORIGIN, css::chart::DataLabelPlacement::NEAR_ORIGIN }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry aXMLChartMissingValueTreatmentEnumMap[] = +{ + { ::xmloff::token::XML_LEAVE_GAP, css::chart::MissingValueTreatment::LEAVE_GAP }, + { ::xmloff::token::XML_USE_ZERO, css::chart::MissingValueTreatment::USE_ZERO }, + { ::xmloff::token::XML_IGNORE, css::chart::MissingValueTreatment::CONTINUE }, + { ::xmloff::token::XML_TOKEN_INVALID,0 }, +}; + +#endif // XML_SCH_CREATE_GLOBAL_MAPS + +#endif // _PROPERTYMAP_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/PropertyMaps.cxx b/xmloff/source/chart/PropertyMaps.cxx new file mode 100644 index 000000000..ce3b458ec --- /dev/null +++ b/xmloff/source/chart/PropertyMaps.cxx @@ -0,0 +1,708 @@ +/* -*- 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 PropertyMap.hxx with this define +// to create the maps +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_PROPERTYMAP_HXX +#define XML_SCH_CREATE_GLOBAL_MAPS +#include "PropertyMap.hxx" +#undef XML_SCH_CREATE_GLOBAL_MAPS +#endif + +#include + +#include "SchXMLTools.hxx" +#include +#include "XMLErrorIndicatorPropertyHdl.hxx" +#include "XMLErrorBarStylePropertyHdl.hxx" +#include "XMLTextOrientationHdl.hxx" +#include "XMLSymbolTypePropertyHdl.hxx" +#include "XMLAxisPositionPropertyHdl.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SCH_XML_SETFLAG( status, flag ) (status)|= (flag) +#define SCH_XML_UNSETFLAG( status, flag ) (status) = ((status) | (flag)) - (flag) + +using namespace com::sun::star; +using namespace ::xmloff::token; + +namespace { + +SvXMLEnumMapEntry const aLineStyleMap[] = +{ + { XML_NONE, drawing::LineStyle_NONE }, + { XML_SOLID, drawing::LineStyle_SOLID }, + { XML_DASH, drawing::LineStyle_DASH }, + { XML_TOKEN_INVALID, drawing::LineStyle(0) } +}; + +SvXMLEnumMapEntry const aFillStyleMap[] = +{ + { XML_NONE, drawing::FillStyle_NONE }, + { XML_SOLID, drawing::FillStyle_SOLID }, + { XML_HATCH, drawing::FillStyle_HATCH } +}; + +} + +// the following class implementations are in this file: + +// * XMLChartPropHdlFactory +// * XMLChartPropertySetMapper +// * XMLChartExportPropertyMapper +// * XMLChartImportPropertyMapper +// * SchXMLStyleExport + +XMLChartPropHdlFactory::XMLChartPropHdlFactory(SvXMLExport const*const pExport) + : m_pExport(pExport) +{ +} + +XMLChartPropHdlFactory::~XMLChartPropHdlFactory() +{ +} + +const XMLPropertyHandler* XMLChartPropHdlFactory::GetPropertyHandler( sal_Int32 nType ) const +{ + const XMLPropertyHandler* pHdl = XMLPropertyHandlerFactory::GetPropertyHandler( nType ); + if( ! pHdl ) + { + switch( nType ) + { + case XML_SCH_TYPE_AXIS_POSITION: + pHdl = new XMLAxisPositionPropertyHdl( false ); + break; + case XML_SCH_TYPE_AXIS_POSITION_VALUE: + pHdl = new XMLAxisPositionPropertyHdl( true ); + break; + + case XML_SCH_TYPE_AXIS_LABEL_POSITION: + pHdl = new XMLEnumPropertyHdl( aXMLChartAxisLabelPositionEnumMap); + break; + + case XML_SCH_TYPE_TICK_MARK_POSITION: + pHdl = new XMLEnumPropertyHdl( aXMLChartAxisMarkPositionEnumMap); + break; + + case XML_SCH_TYPE_AXIS_ARRANGEMENT: + pHdl = new XMLEnumPropertyHdl( aXMLChartAxisArrangementEnumMap); + break; + + case XML_SCH_TYPE_ERROR_BAR_STYLE: + // here we have a constant rather than an enum + pHdl = new XMLErrorBarStylePropertyHdl( aXMLChartErrorBarStyleEnumMap ); + break; + + case XML_SCH_TYPE_ERROR_INDICATOR_LOWER: + pHdl = new XMLErrorIndicatorPropertyHdl( false ); + break; + case XML_SCH_TYPE_ERROR_INDICATOR_UPPER: + pHdl = new XMLErrorIndicatorPropertyHdl( true ); + break; + + case XML_SCH_TYPE_SOLID_TYPE: + // here we have a constant rather than an enum + pHdl = new XMLEnumPropertyHdl( aXMLChartSolidTypeEnumMap ); + break; + case XML_SCH_TYPE_LABEL_PLACEMENT_TYPE: + // here we have a constant rather than an enum + pHdl = new XMLEnumPropertyHdl( aXMLChartDataLabelPlacementEnumMap ); + break; + case XML_SCH_TYPE_DATAROWSOURCE: + pHdl = new XMLEnumPropertyHdl( aXMLChartDataRowSourceTypeEnumMap); + break; + case XML_SCH_TYPE_TEXT_ORIENTATION: + pHdl = new XMLTextOrientationHdl; + break; + + case XML_SCH_TYPE_INTERPOLATION: + if (m_pExport && m_pExport->getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_013) + { + pHdl = new XMLEnumPropertyHdl(g_XMLChartInterpolationTypeEnumMap_ODF12); + } + else // ODF 1.3 OFFICE-3662 + { + pHdl = new XMLEnumPropertyHdl(g_XMLChartInterpolationTypeEnumMap); + } + break; + case XML_SCH_TYPE_SYMBOL_TYPE: + pHdl = new XMLSymbolTypePropertyHdl( false ); + break; + + case XML_SCH_TYPE_NAMED_SYMBOL: + pHdl = new XMLSymbolTypePropertyHdl( true ); + break; + + case XML_SCH_TYPE_MISSING_VALUE_TREATMENT: + pHdl = new XMLEnumPropertyHdl( aXMLChartMissingValueTreatmentEnumMap ); + break; + case XML_SCH_TYPE_LABEL_BORDER_STYLE: + pHdl = new XMLEnumPropertyHdl( aLineStyleMap ); + break; + case XML_SCH_TYPE_LABEL_BORDER_OPACITY: + pHdl = new XMLOpacityPropertyHdl(nullptr); + break; + case XML_SCH_TYPE_LABEL_FILL_STYLE: + pHdl = new XMLEnumPropertyHdl( aFillStyleMap ); + break; + default: + ; + } + if( pHdl ) + PutHdlCache( nType, pHdl ); + } + + return pHdl; +} + +XMLChartPropertySetMapper::XMLChartPropertySetMapper(SvXMLExport const*const pExport) + : XMLPropertySetMapper(aXMLChartPropMap, new XMLChartPropHdlFactory(pExport), pExport != nullptr) +{ +} + +XMLChartPropertySetMapper::~XMLChartPropertySetMapper() +{ +} + +XMLChartExportPropertyMapper::XMLChartExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExport) : + SvXMLExportPropertyMapper( rMapper ), + mrExport( rExport ) +{ + // chain draw properties + ChainExportMapper( XMLShapeExport::CreateShapePropMapper( rExport )); + + // chain text properties + ChainExportMapper( XMLTextParagraphExport::CreateParaExtPropMapper( rExport )); +} + +XMLChartExportPropertyMapper::~XMLChartExportPropertyMapper() +{ +} + +void XMLChartExportPropertyMapper::ContextFilter( + bool bEnableFoFontFamily, + std::vector< XMLPropertyState >& rProperties, + const uno::Reference< beans::XPropertySet >& rPropSet ) const +{ + OUString aAutoPropName; + bool bCheckAuto = false; + + // filter properties + for( auto& rProperty : rProperties ) + { + // find properties with context + // to prevent writing this property set mnIndex member to -1 + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex )) + { + // if Auto... is set the corresponding properties mustn't be exported + case XML_SCH_CONTEXT_MIN: + bCheckAuto = true; + aAutoPropName = "AutoMin"; + break; + case XML_SCH_CONTEXT_MAX: + bCheckAuto = true; + aAutoPropName = "AutoMax"; + break; + case XML_SCH_CONTEXT_STEP_MAIN: + bCheckAuto = true; + aAutoPropName = "AutoStepMain"; + break; + case XML_SCH_CONTEXT_STEP_HELP_COUNT: + bCheckAuto = true; + aAutoPropName = "AutoStepHelp"; + break; + + case XML_SCH_CONTEXT_ORIGIN: + bCheckAuto = true; + aAutoPropName = "AutoOrigin"; + break; + + // the following property is deprecated + // element-item symbol-image is used now + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE_NAME: + rProperty.mnIndex = -1; + break; + + case XML_SCH_CONTEXT_STOCK_WITH_VOLUME: + case XML_SCH_CONTEXT_LINES_USED: + // note this avoids export of the properties in OASIS format, + // but also for the OOo XML Flat format (used by binfilter), + // because there, the transformation to OOo is done after the + // complete export of the chart in OASIS format. + if( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) + rProperty.mnIndex = -1; + break; + } + + if( bCheckAuto ) + { + if( rPropSet.is()) + { + try + { + bool bAuto = false; + uno::Any aAny = rPropSet->getPropertyValue( aAutoPropName ); + aAny >>= bAuto; + if( bAuto ) + rProperty.mnIndex = -1; + } + catch(const beans::UnknownPropertyException&) + { + } + } + bCheckAuto = false; + } + } + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +void XMLChartExportPropertyMapper::handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex )) + { + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE: + { + uno::Reference xGraphic; + rProperty.maValue >>= xGraphic; + + OUString sInternalURL; + // export as XLink reference into the package + // if embedding is off + if (xGraphic.is()) + { + OUString aOutMimeType; + sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, aOutMimeType); + } + if (!sInternalURL.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + } + + { + sal_uInt32 nPropIndex = rProperty.mnIndex; + // this is the element that has to live until the next statement + SvXMLElementExport aElem( mrExport, + getPropertySetMapper()->GetEntryNameSpace( nPropIndex ), + getPropertySetMapper()->GetEntryXMLName( nPropIndex ), + true, true ); + + // export as Base64 embedded graphic + // if embedding is on + if (xGraphic.is()) + mrExport.AddEmbeddedXGraphicAsBase64(xGraphic); + } + } + break; + + case XML_SCH_CONTEXT_SPECIAL_LABEL_SEPARATOR: + { + OUString aSeparator; + rProperty.maValue >>= aSeparator; + + if( !aSeparator.isEmpty() ) + { + sal_uInt32 nPropIndex = rProperty.mnIndex; + SvXMLElementExport aElem( mrExport, + getPropertySetMapper()->GetEntryNameSpace( nPropIndex ), + getPropertySetMapper()->GetEntryXMLName( nPropIndex ), + true, true ); + + SchXMLTools::exportText( mrExport, aSeparator, true ); + } + } + break; + + default: + // call parent + SvXMLExportPropertyMapper::handleElementItem( rExport, rProperty, + nFlags, pProperties, nIdx ); + break; + } +} + +namespace { + +OUString convertRange( const OUString & rRange, const uno::Reference< chart2::XChartDocument > & xDoc ) +{ + OUString aResult = rRange; + if( !xDoc.is() ) + return aResult; + uno::Reference< chart2::data::XRangeXMLConversion > xConversion( + xDoc->getDataProvider(), uno::UNO_QUERY ); + try + { + if( xConversion.is()) + aResult = xConversion->convertRangeToXML( rRange ); + } + catch (css::lang::IllegalArgumentException&) + { + } + + return aResult; +} + +} + +void XMLChartExportPropertyMapper::handleSpecialItem( + SvXMLAttributeList& rAttrList, const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + bool bHandled = false; + + sal_Int32 nContextId = getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ); + + if( nContextId ) + { + bHandled = true; + + OUString sAttrName = getPropertySetMapper()->GetEntryXMLName( rProperty.mnIndex ); + sal_uInt16 nNameSpace = getPropertySetMapper()->GetEntryNameSpace( rProperty.mnIndex ); + OUStringBuffer sValueBuffer; + OUString sValue; + + sal_Int32 nValue = 0; + bool bValue = false; + + switch( nContextId ) + { + case XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_INNER: + case XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_INNER: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartAxisMarks::INNER ) == chart::ChartAxisMarks::INNER ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_OUTER: + case XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_OUTER: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartAxisMarks::OUTER ) == chart::ChartAxisMarks::OUTER ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_TEXT_ROTATION: + { + // convert from 100th degrees to degrees (double) + rProperty.maValue >>= nValue; + double fVal = static_cast(nValue) / 100.0; + ::sax::Converter::convertDouble( sValueBuffer, fVal ); + } + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_NUMBER: + { + rProperty.maValue >>= nValue; + if( ( nValue & chart::ChartDataCaption::VALUE ) == chart::ChartDataCaption::VALUE ) + { + if( ( nValue & chart::ChartDataCaption::PERCENT ) == chart::ChartDataCaption::PERCENT ) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion( SvtSaveOptions().GetODFSaneDefaultVersion() ); + if (nCurrentVersion < SvtSaveOptions::ODFSVER_012) + sValueBuffer.append( GetXMLToken( XML_PERCENTAGE )); + else + sValueBuffer.append( GetXMLToken( XML_VALUE_AND_PERCENTAGE )); + } + else + sValueBuffer.append( GetXMLToken( XML_VALUE )); + } + else if(( nValue & chart::ChartDataCaption::PERCENT ) == chart::ChartDataCaption::PERCENT ) + sValueBuffer.append( GetXMLToken( XML_PERCENTAGE )); + else + sValueBuffer.append( GetXMLToken( XML_NONE )); + } + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_TEXT: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartDataCaption::TEXT ) == chart::ChartDataCaption::TEXT ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SYMBOL: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartDataCaption::SYMBOL ) == chart::ChartDataCaption::SYMBOL ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH: + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_HEIGHT: + { + awt::Size aSize; + rProperty.maValue >>= aSize; + rUnitConverter.convertMeasureToXML( sValueBuffer, + nContextId == XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH + ? aSize.Width + : aSize.Height ); + } + break; + + case XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT: + { + // just for import + break; + } + + case XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE: + { + OUString aRangeStr; + rProperty.maValue >>= aRangeStr; + sValueBuffer.append(convertRange(aRangeStr, mxChartDoc)); + } + break; + case XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE: + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion( SvtSaveOptions().GetODFSaneDefaultVersion() ); + + OUString aServiceName; + rProperty.maValue >>= aServiceName; + if (aServiceName == "com.sun.star.chart2.LinearRegressionCurve") + sValueBuffer.append( GetXMLToken( XML_LINEAR )); + else if (aServiceName == "com.sun.star.chart2.LogarithmicRegressionCurve") + sValueBuffer.append( GetXMLToken( XML_LOGARITHMIC )); + else if (aServiceName == "com.sun.star.chart2.ExponentialRegressionCurve") + sValueBuffer.append( GetXMLToken( XML_EXPONENTIAL )); + else if (aServiceName == "com.sun.star.chart2.PotentialRegressionCurve") + sValueBuffer.append( GetXMLToken( XML_POWER )); + else if (nCurrentVersion >= SvtSaveOptions::ODFSVER_013 && aServiceName == "com.sun.star.chart2.PolynomialRegressionCurve") + { // ODF 1.3 OFFICE-3958 + sValueBuffer.append( GetXMLToken( XML_POLYNOMIAL )); + } + else if (nCurrentVersion >= SvtSaveOptions::ODFSVER_013 && aServiceName == "com.sun.star.chart2.MovingAverageRegressionCurve") + { // ODF 1.3 OFFICE-3959 + sValueBuffer.append( GetXMLToken( XML_MOVING_AVERAGE )); + } + } + break; + + default: + bHandled = false; + break; + } + + if( !sValueBuffer.isEmpty()) + { + sValue = sValueBuffer.makeStringAndClear(); + sAttrName = rNamespaceMap.GetQNameByKey( nNameSpace, sAttrName ); + rAttrList.AddAttribute( sAttrName, sValue ); + } + } + + if( !bHandled ) + { + // call parent + SvXMLExportPropertyMapper::handleSpecialItem( rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx ); + } +} + +void XMLChartExportPropertyMapper::setChartDoc( const uno::Reference< chart2::XChartDocument >& xChartDoc ) +{ + mxChartDoc = xChartDoc; +} + +XMLChartImportPropertyMapper::XMLChartImportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, + const SvXMLImport& _rImport ) : + SvXMLImportPropertyMapper( rMapper, const_cast< SvXMLImport & >( _rImport )), + mrImport( const_cast< SvXMLImport & > ( _rImport )) +{ + // chain shape mapper for drawing properties + + // give an empty model. It is only used for numbering rules that don't exist in chart + uno::Reference< frame::XModel > xEmptyModel; + ChainImportMapper( XMLShapeImportHelper::CreateShapePropMapper( xEmptyModel, mrImport )); + + //#i14365# save and load writing-mode for chart elements + //The property TextWritingMode is mapped wrongly in the underlying draw mapper, but for draw it is necessary + //We remove that property here only for chart thus the chart can use the correct mapping from the writer paragraph settings (attribute 'writing-mode' <-> property 'WritingMode') + sal_Int32 nUnwantedWrongEntry = maPropMapper->FindEntryIndex( "TextWritingMode", XML_NAMESPACE_STYLE, GetXMLToken(XML_WRITING_MODE) ); + maPropMapper->RemoveEntry(nUnwantedWrongEntry); + + // do not chain text properties: on import this is done by shape mapper + // to import old documents +} + +XMLChartImportPropertyMapper::~XMLChartImportPropertyMapper() +{ +} + +bool XMLChartImportPropertyMapper::handleSpecialItem( + XMLPropertyState& rProperty, + ::std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const +{ + sal_Int32 nContextId = maPropMapper->GetEntryContextId( rProperty.mnIndex ); + bool bRet = (nContextId != 0); + + if( nContextId ) + { + sal_Int32 nValue = 0; + bool bValue = false; + + switch( nContextId ) + { + case XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_INNER: + case XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_INNER: + (void)::sax::Converter::convertBool( bValue, rValue ); + // modify old value + rProperty.maValue >>= nValue; + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartAxisMarks::INNER ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartAxisMarks::INNER ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_OUTER: + case XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_OUTER: + (void)::sax::Converter::convertBool( bValue, rValue ); + // modify old value + rProperty.maValue >>= nValue; + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartAxisMarks::OUTER ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartAxisMarks::OUTER ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_TEXT_ROTATION: + { + // convert from degrees (double) to 100th degrees (integer) + double fVal; + ::sax::Converter::convertDouble( fVal, rValue ); + nValue = static_cast( fVal * 100.0 ); + rProperty.maValue <<= nValue; + } + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_NUMBER: + { + // modify old value + rProperty.maValue >>= nValue; + if( IsXMLToken( rValue, XML_NONE )) + SCH_XML_UNSETFLAG( nValue, chart::ChartDataCaption::VALUE | chart::ChartDataCaption::PERCENT ); + else if( IsXMLToken( rValue, XML_VALUE_AND_PERCENTAGE ) ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::VALUE | chart::ChartDataCaption::PERCENT ); + else if( IsXMLToken( rValue, XML_VALUE ) ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::VALUE ); + else // must be XML_PERCENTAGE + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::PERCENT ); + rProperty.maValue <<= nValue; + } + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_TEXT: + rProperty.maValue >>= nValue; + (void)::sax::Converter::convertBool( bValue, rValue ); + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::TEXT ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartDataCaption::TEXT ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SYMBOL: + rProperty.maValue >>= nValue; + (void)::sax::Converter::convertBool( bValue, rValue ); + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::SYMBOL ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartDataCaption::SYMBOL ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH: + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_HEIGHT: + { + awt::Size aSize; + rProperty.maValue >>= aSize; + rUnitConverter.convertMeasureToCore( + (nContextId == XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH) + ? aSize.Width + : aSize.Height, + rValue ); + rProperty.maValue <<= aSize; + } + break; + + case XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE: + { + rProperty.maValue <<= rValue; + } + break; + + // deprecated from 6.0 beta on + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE_NAME: + rProperty.maValue <<= mrImport.loadGraphicByURL(rValue); + break; + + case XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE: + { + if (IsXMLToken( rValue, XML_LINEAR )) + rProperty.maValue <<= OUString("com.sun.star.chart2.LinearRegressionCurve"); + else if (IsXMLToken( rValue, XML_LOGARITHMIC)) + rProperty.maValue <<= OUString("com.sun.star.chart2.LogarithmicRegressionCurve"); + else if (IsXMLToken( rValue, XML_EXPONENTIAL)) + rProperty.maValue <<= OUString("com.sun.star.chart2.ExponentialRegressionCurve"); + else if (IsXMLToken( rValue, XML_POWER)) + rProperty.maValue <<= OUString("com.sun.star.chart2.PotentialRegressionCurve"); + else if (IsXMLToken( rValue, XML_POLYNOMIAL)) + rProperty.maValue <<= OUString("com.sun.star.chart2.PolynomialRegressionCurve"); + else if (IsXMLToken( rValue, XML_MOVING_AVERAGE)) + rProperty.maValue <<= OUString("com.sun.star.chart2.MovingAverageRegressionCurve"); + } + break; + + default: + bRet = false; + break; + } + } + + // if we didn't handle it, the parent should + if( !bRet ) + { + // call parent + bRet = SvXMLImportPropertyMapper::handleSpecialItem( rProperty, rProperties, rValue, rUnitConverter, rNamespaceMap ); + } + + return bRet; +} + +void XMLChartImportPropertyMapper::finished( ::std::vector< XMLPropertyState >& /*rProperties*/, sal_Int32 /*nStartIndex*/, sal_Int32 /*nEndIndex*/ ) const +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLAutoStylePoolP.cxx b/xmloff/source/chart/SchXMLAutoStylePoolP.cxx new file mode 100644 index 000000000..f4296bc48 --- /dev/null +++ b/xmloff/source/chart/SchXMLAutoStylePoolP.cxx @@ -0,0 +1,77 @@ +/* -*- 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 +#include "PropertyMap.hxx" +#include +#include +#include + + +SchXMLAutoStylePoolP::SchXMLAutoStylePoolP( SchXMLExport& rSchXMLExport ) : + SvXMLAutoStylePoolP( rSchXMLExport ), + mrSchXMLExport( rSchXMLExport ) +{} + +SchXMLAutoStylePoolP::~SchXMLAutoStylePoolP() +{} + +void SchXMLAutoStylePoolP::exportStyleAttributes( + SvXMLAttributeList& rAttrList, + XmlStyleFamily nFamily, + const ::std::vector< XMLPropertyState >& rProperties, + const SvXMLExportPropertyMapper& rPropExp + , const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap + ) const +{ + SvXMLAutoStylePoolP::exportStyleAttributes( rAttrList, nFamily, rProperties, + rPropExp, rUnitConverter, rNamespaceMap ); + + if( nFamily == XmlStyleFamily::SCH_CHART_ID ) + { + for( const auto& rProp : rProperties ) + { + if( rProp.mnIndex == -1 ) + continue; + + rtl::Reference< XMLPropertySetMapper > aPropMapper = + mrSchXMLExport.GetPropertySetMapper(); + sal_Int16 nContextID = aPropMapper->GetEntryContextId( rProp.mnIndex ); + if( nContextID == XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT ) + { + sal_Int32 nNumberFormat = -1; + if( ( rProp.maValue >>= nNumberFormat ) && + ( nNumberFormat != -1 )) + { + OUString sAttrValue = mrSchXMLExport.getDataStyleName( nNumberFormat ); + if( !sAttrValue.isEmpty() ) + { + mrSchXMLExport.AddAttribute( + aPropMapper->GetEntryNameSpace( rProp.mnIndex ), + aPropMapper->GetEntryXMLName( rProp.mnIndex ), + sAttrValue ); + } + } + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLAxisContext.cxx b/xmloff/source/chart/SchXMLAxisContext.cxx new file mode 100644 index 000000000..ac2c70103 --- /dev/null +++ b/xmloff/source/chart/SchXMLAxisContext.cxx @@ -0,0 +1,1022 @@ +/* -*- 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 + +#include "SchXMLAxisContext.hxx" +#include "SchXMLChartContext.hxx" +#include "SchXMLTools.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::xmloff::token; +using namespace com::sun::star; + +using com::sun::star::uno::Reference; + +static const SvXMLEnumMapEntry aXMLAxisDimensionMap[] = +{ + { XML_X, SCH_XML_AXIS_X }, + { XML_Y, SCH_XML_AXIS_Y }, + { XML_Z, SCH_XML_AXIS_Z }, + { XML_TOKEN_INVALID, SchXMLAxisDimension(0) } +}; + +static const SvXMLEnumMapEntry aXMLAxisTypeMap[] = +{ + { XML_AUTO, css::chart::ChartAxisType::AUTOMATIC }, + { XML_TEXT, css::chart::ChartAxisType::CATEGORY }, + { XML_DATE, css::chart::ChartAxisType::DATE }, + { XML_TOKEN_INVALID, 0 } +}; + +namespace { + +class SchXMLCategoriesContext : public SvXMLImportContext +{ +private: + OUString& mrAddress; + +public: + SchXMLCategoriesContext( SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + OUString& rAddress ); + virtual void StartElement( const Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +class DateScaleContext : public SvXMLImportContext +{ +public: + DateScaleContext( SvXMLImport& rImport, + sal_uInt16 nPrefix, const OUString& rLocalName, + const Reference< beans::XPropertySet >& rAxisProps ); + + virtual void StartElement( const Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + Reference< beans::XPropertySet > m_xAxisProps; +}; + +} + +SchXMLAxisContext::SchXMLAxisContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + Reference< chart::XDiagram > const & xDiagram, + std::vector< SchXMLAxis >& rAxes, + OUString & rCategoriesAddress, + bool bAddMissingXAxisForNetCharts, + bool bAdaptWrongPercentScaleValues, + bool bAdaptXAxisOrientationForOld2DBarCharts, + bool& rbAxisPositionAttributeImported ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + m_rImportHelper( rImpHelper ), + m_xDiagram( xDiagram ), + m_rAxes( rAxes ), + m_rCategoriesAddress( rCategoriesAddress ), + m_nAxisType(chart::ChartAxisType::AUTOMATIC), + m_bAxisTypeImported(false), + m_bDateScaleImported(false), + m_bAddMissingXAxisForNetCharts( bAddMissingXAxisForNetCharts ), + m_bAdaptWrongPercentScaleValues( bAdaptWrongPercentScaleValues ), + m_bAdaptXAxisOrientationForOld2DBarCharts( bAdaptXAxisOrientationForOld2DBarCharts ), + m_rbAxisPositionAttributeImported( rbAxisPositionAttributeImported ) +{ +} + +SchXMLAxisContext::~SchXMLAxisContext() +{} + +static Reference< chart::XAxis > lcl_getChartAxis(const SchXMLAxis& rCurrentAxis, const Reference< chart::XDiagram >& rDiagram ) +{ + Reference< chart::XAxis > xAxis; + Reference< chart::XAxisSupplier > xAxisSuppl( rDiagram, uno::UNO_QUERY ); + if( !xAxisSuppl.is() ) + return xAxis; + if( rCurrentAxis.nAxisIndex == 0 ) + xAxis = xAxisSuppl->getAxis(rCurrentAxis.eDimension); + else + xAxis = xAxisSuppl->getSecondaryAxis(rCurrentAxis.eDimension); + return xAxis; +} + +/* returns a shape for the current axis's title. The property + "Has...AxisTitle" is set to "True" to get the shape + */ +Reference< drawing::XShape > SchXMLAxisContext::getTitleShape() const +{ + Reference< drawing::XShape > xResult; + Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY ); + Reference< chart::XAxis > xAxis( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ) ); + if( !xDiaProp.is() || !xAxis.is() ) + return xResult; + + OUString aPropName; + switch( m_aCurrentAxis.eDimension ) + { + case SCH_XML_AXIS_X: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasXAxisTitle"; + else + aPropName = "HasSecondaryXAxisTitle"; + break; + case SCH_XML_AXIS_Y: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasYAxisTitle"; + else + aPropName = "HasSecondaryYAxisTitle"; + break; + case SCH_XML_AXIS_Z: + aPropName = "HasZAxisTitle"; + break; + case SCH_XML_AXIS_UNDEF: + SAL_INFO("xmloff.chart", "Invalid axis" ); + break; + } + xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) ); + xResult.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xResult; +} + +void SchXMLAxisContext::CreateGrid( const OUString& sAutoStyleName, bool bIsMajor ) +{ + Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY ); + Reference< chart::XAxis > xAxis( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ) ); + if( !xDiaProp.is() || !xAxis.is() ) + return; + + OUString aPropName; + switch( m_aCurrentAxis.eDimension ) + { + case SCH_XML_AXIS_X: + if( bIsMajor ) + aPropName = "HasXAxisGrid"; + else + aPropName = "HasXAxisHelpGrid"; + break; + case SCH_XML_AXIS_Y: + if( bIsMajor ) + aPropName = "HasYAxisGrid"; + else + aPropName = "HasYAxisHelpGrid"; + break; + case SCH_XML_AXIS_Z: + if( bIsMajor ) + aPropName = "HasZAxisGrid"; + else + aPropName = "HasZAxisHelpGrid"; + break; + case SCH_XML_AXIS_UNDEF: + SAL_INFO("xmloff.chart", "Invalid axis" ); + break; + } + xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) ); + + Reference< beans::XPropertySet > xGridProp; + if( bIsMajor ) + xGridProp = xAxis->getMajorGrid(); + else + xGridProp = xAxis->getMinorGrid(); + + // set properties + if( xGridProp.is()) + { + // the line color is black as default, in the model it is a light gray + xGridProp->setPropertyValue("LineColor", + uno::makeAny( COL_BLACK )); + if (!sAutoStyleName.isEmpty()) + m_rImportHelper.FillAutoStyle(sAutoStyleName, xGridProp); + } +} + +namespace +{ +enum AxisAttributeTokens +{ + XML_TOK_AXIS_DIMENSION, + XML_TOK_AXIS_NAME, + XML_TOK_AXIS_STYLE_NAME, + XML_TOK_AXIS_TYPE, + XML_TOK_AXIS_TYPE_EXT +}; + +const SvXMLTokenMapEntry aAxisAttributeTokenMap[] = +{ + { XML_NAMESPACE_CHART, XML_DIMENSION, XML_TOK_AXIS_DIMENSION }, + { XML_NAMESPACE_CHART, XML_NAME, XML_TOK_AXIS_NAME }, + { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_AXIS_STYLE_NAME }, + { XML_NAMESPACE_CHART, XML_AXIS_TYPE, XML_TOK_AXIS_TYPE }, + { XML_NAMESPACE_CHART_EXT, XML_AXIS_TYPE, XML_TOK_AXIS_TYPE_EXT }, + XML_TOKEN_MAP_END +}; + +class AxisAttributeTokenMap : public SvXMLTokenMap +{ +public: + AxisAttributeTokenMap(): SvXMLTokenMap( aAxisAttributeTokenMap ) {} + virtual ~AxisAttributeTokenMap() {} +}; + +//a AxisAttributeTokenMap Singleton +struct theAxisAttributeTokenMap : public rtl::Static< AxisAttributeTokenMap, theAxisAttributeTokenMap > {}; +} + +void SchXMLAxisContext::StartElement( const Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + const SvXMLTokenMap& rAttrTokenMap = theAxisAttributeTokenMap::get(); + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_AXIS_DIMENSION: + { + SchXMLAxisDimension nEnumVal; + if( SvXMLUnitConverter::convertEnum( nEnumVal, aValue, aXMLAxisDimensionMap )) + m_aCurrentAxis.eDimension = nEnumVal; + } + break; + case XML_TOK_AXIS_NAME: + m_aCurrentAxis.aName = aValue; + break; + case XML_TOK_AXIS_TYPE: + case XML_TOK_AXIS_TYPE_EXT: + sal_uInt16 nEnumVal; + if( SvXMLUnitConverter::convertEnum( nEnumVal, aValue, aXMLAxisTypeMap )) + { + m_nAxisType = nEnumVal; + m_bAxisTypeImported = true; + } + break; + case XML_TOK_AXIS_STYLE_NAME: + m_aAutoStyleName = aValue; + break; + } + } + + // check for number of axes with same dimension + m_aCurrentAxis.nAxisIndex = 0; + sal_Int32 nNumOfAxes = m_rAxes.size(); + for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ ) + { + if( m_rAxes[ nCurrent ].eDimension == m_aCurrentAxis.eDimension ) + m_aCurrentAxis.nAxisIndex++; + } + CreateAxis(); +} +namespace +{ + +Reference< chart2::XAxis > lcl_getAxis( const Reference< frame::XModel >& xChartModel, + sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + Reference< chart2::XAxis > xAxis; + + try + { + Reference< chart2::XChartDocument > xChart2Document( xChartModel, uno::UNO_QUERY ); + if( xChart2Document.is() ) + { + Reference< chart2::XDiagram > xDiagram( xChart2Document->getFirstDiagram()); + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); + uno::Sequence< Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + sal_Int32 nCooSysIndex = 0; + if( nCooSysIndex < aCooSysSeq.getLength() ) + { + Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] ); + if( xCooSys.is() && nDimensionIndex < xCooSys->getDimension() ) + { + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + if( nAxisIndex <= nMaxAxisIndex ) + xAxis = xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ); + } + } + } + } + catch( uno::Exception & ) + { + SAL_INFO("xmloff.chart", "Couldn't get axis" ); + } + + return xAxis; +} + +bool lcl_divideBy100( uno::Any& rDoubleAny ) +{ + bool bChanged = false; + double fValue=0.0; + if( (rDoubleAny>>=fValue) && (fValue!=0.0) ) + { + fValue/=100.0; + rDoubleAny <<= fValue; + bChanged = true; + } + return bChanged; +} + +bool lcl_AdaptWrongPercentScaleValues(chart2::ScaleData& rScaleData) +{ + bool bChanged = lcl_divideBy100( rScaleData.Minimum ); + bChanged = lcl_divideBy100( rScaleData.Maximum ) || bChanged; + bChanged = lcl_divideBy100( rScaleData.Origin ) || bChanged; + bChanged = lcl_divideBy100( rScaleData.IncrementData.Distance ) || bChanged; + return bChanged; +} + +}//end anonymous namespace + +void SchXMLAxisContext::CreateAxis() +{ + m_rAxes.push_back( m_aCurrentAxis ); + + Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY ); + if( !xDiaProp.is() ) + return; + OUString aPropName; + switch( m_aCurrentAxis.eDimension ) + { + case SCH_XML_AXIS_X: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasXAxis"; + else + aPropName = "HasSecondaryXAxis"; + break; + case SCH_XML_AXIS_Y: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasYAxis"; + else + aPropName = "HasSecondaryYAxis"; + break; + case SCH_XML_AXIS_Z: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasZAxis"; + break; + case SCH_XML_AXIS_UNDEF: + SAL_INFO("xmloff.chart", "Invalid axis" ); + break; + } + try + { + xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) ); + } + catch( beans::UnknownPropertyException & ) + { + SAL_INFO("xmloff.chart", "Couldn't turn on axis" ); + } + if( m_aCurrentAxis.eDimension==SCH_XML_AXIS_Z ) + { + bool bSettingZAxisSuccedded = false; + try + { + xDiaProp->getPropertyValue( aPropName ) >>= bSettingZAxisSuccedded; + } + catch( beans::UnknownPropertyException & ) + { + SAL_INFO("xmloff.chart", "Couldn't turn on z axis" ); + } + if( !bSettingZAxisSuccedded ) + return; + } + + m_xAxisProps.set( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ), uno::UNO_QUERY ); + + if( m_bAddMissingXAxisForNetCharts && m_aCurrentAxis.eDimension==SCH_XML_AXIS_Y && m_aCurrentAxis.nAxisIndex==0 ) + { + try + { + xDiaProp->setPropertyValue("HasXAxis", uno::makeAny(true) ); + } + catch( beans::UnknownPropertyException & ) + { + SAL_INFO("xmloff.chart", "Couldn't turn on x axis" ); + } + } + + // set properties + if( m_xAxisProps.is()) + { + uno::Any aTrueBool( uno::makeAny( true )); + uno::Any aFalseBool( uno::makeAny( false )); + + // #i109879# the line color is black as default, in the model it is a light gray + m_xAxisProps->setPropertyValue("LineColor", + uno::makeAny( COL_BLACK )); + + m_xAxisProps->setPropertyValue("DisplayLabels", aFalseBool ); + + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + // So the import default value for having compatibility with ODF + // documents created with earlier LibreOffice versions is `true`. + if( GetImport().getGeneratorVersion() != SvXMLImport::ProductVersionUnknown ) + m_xAxisProps->setPropertyValue("TryStaggeringFirst", aTrueBool ); + + // #88077# AutoOrigin 'on' is default + m_xAxisProps->setPropertyValue("AutoOrigin", aTrueBool ); + + if( m_bAxisTypeImported ) + m_xAxisProps->setPropertyValue("AxisType", uno::makeAny(m_nAxisType) ); + + if( !m_aAutoStyleName.isEmpty()) + { + const SvXMLStylesContext* pStylesCtxt = m_rImportHelper.GetAutoStylesContext(); + if (pStylesCtxt) + { + SvXMLStyleContext* pStyle = const_cast(pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(), m_aAutoStyleName)); + + if (XMLPropStyleContext * pPropStyleContext = dynamic_cast(pStyle)) + { + pPropStyleContext->FillPropertySet(m_xAxisProps); + + if( m_bAdaptWrongPercentScaleValues && m_aCurrentAxis.eDimension==SCH_XML_AXIS_Y ) + { + //set scale data of added x axis back to default + Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(), + m_aCurrentAxis.eDimension, m_aCurrentAxis.nAxisIndex ) ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData()); + if( lcl_AdaptWrongPercentScaleValues(aScaleData) ) + xAxis->setScaleData( aScaleData ); + } + } + + if( m_bAddMissingXAxisForNetCharts ) + { + //copy style from y axis to added x axis: + + Reference< chart::XAxisSupplier > xAxisSuppl( xDiaProp, uno::UNO_QUERY ); + if( xAxisSuppl.is() ) + { + Reference< beans::XPropertySet > xXAxisProp( xAxisSuppl->getAxis(0), uno::UNO_QUERY ); + pPropStyleContext->FillPropertySet(xXAxisProp); + } + + //set scale data of added x axis back to default + Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(), + 0 /*nDimensionIndex*/, 0 /*nAxisIndex*/ ) ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData; + aScaleData.AxisType = chart2::AxisType::CATEGORY; + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xAxis->setScaleData( aScaleData ); + } + + //set line style of added x axis to invisible + Reference< beans::XPropertySet > xNewAxisProp( xAxis, uno::UNO_QUERY ); + if( xNewAxisProp.is() ) + { + xNewAxisProp->setPropertyValue("LineStyle" + , uno::makeAny(drawing::LineStyle_NONE)); + } + } + + if( m_bAdaptXAxisOrientationForOld2DBarCharts && m_aCurrentAxis.eDimension == SCH_XML_AXIS_X ) + { + bool bIs3DChart = false; + if( xDiaProp.is() && ( xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart ) + && !bIs3DChart ) + { + Reference< chart2::XChartDocument > xChart2Document( GetImport().GetModel(), uno::UNO_QUERY ); + if( xChart2Document.is() ) + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChart2Document->getFirstDiagram(), uno::UNO_QUERY ); + if( xCooSysCnt.is() ) + { + uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() ); + if( aCooSysSeq.hasElements() ) + { + bool bSwapXandYAxis = false; + Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] ); + Reference< beans::XPropertySet > xCooSysProp( xCooSys, uno::UNO_QUERY ); + if( xCooSysProp.is() && ( xCooSysProp->getPropertyValue("SwapXAndYAxis") >>= bSwapXandYAxis ) + && bSwapXandYAxis ) + { + Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( 0, m_aCurrentAxis.nAxisIndex ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + aScaleData.Orientation = chart2::AxisOrientation_REVERSE; + xAxis->setScaleData( aScaleData ); + } + } + } + } + } + } + } + + m_rbAxisPositionAttributeImported = m_rbAxisPositionAttributeImported || SchXMLTools::getPropertyFromContext( + "CrossoverPosition", pPropStyleContext, pStylesCtxt ).hasValue(); + } + } + } + + if (m_aCurrentAxis.eDimension == SCH_XML_AXIS_X) + { + Reference xAxis(lcl_getAxis(GetImport().GetModel(), m_aCurrentAxis.eDimension, m_aCurrentAxis.nAxisIndex)); + if (xAxis.is()) + { + chart2::ScaleData aScaleData(xAxis->getScaleData()); + bool bIs3DChart = false; + double fMajorOrigin = -1; + OUString sChartType = m_xDiagram->getDiagramType(); + if ((xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart) && bIs3DChart + && (sChartType == "com.sun.star.chart.BarDiagram" || sChartType == "com.sun.star.chart.StockDiagram")) + { + aScaleData.ShiftedCategoryPosition = true; + xAxis->setScaleData(aScaleData); + } + else if ((m_xAxisProps->getPropertyValue("MajorOrigin") >>= fMajorOrigin) + && (rtl::math::approxEqual(fMajorOrigin, 0.0) || rtl::math::approxEqual(fMajorOrigin, 0.5))) + { + aScaleData.ShiftedCategoryPosition = rtl::math::approxEqual(fMajorOrigin, 0.5); + xAxis->setScaleData(aScaleData); + } + } + } + } +} + +void SchXMLAxisContext::SetAxisTitle() +{ + if( m_aCurrentAxis.aTitle.isEmpty() ) + return; + + Reference< chart::XAxis > xAxis( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ) ); + if( !xAxis.is() ) + return; + + Reference< beans::XPropertySet > xTitleProp( xAxis->getAxisTitle() ); + if( xTitleProp.is() ) + { + try + { + xTitleProp->setPropertyValue("String", uno::makeAny(m_aCurrentAxis.aTitle) ); + } + catch( beans::UnknownPropertyException & ) + { + SAL_INFO("xmloff.chart", "Property String for Title not available" ); + } + } +} + +namespace +{ +enum AxisChildTokens +{ + XML_TOK_AXIS_TITLE, + XML_TOK_AXIS_CATEGORIES, + XML_TOK_AXIS_GRID, + XML_TOK_AXIS_DATE_SCALE, + XML_TOK_AXIS_DATE_SCALE_EXT +}; + +const SvXMLTokenMapEntry aAxisChildTokenMap[] = +{ + { XML_NAMESPACE_CHART, XML_TITLE, XML_TOK_AXIS_TITLE }, + { XML_NAMESPACE_CHART, XML_CATEGORIES, XML_TOK_AXIS_CATEGORIES }, + { XML_NAMESPACE_CHART, XML_GRID, XML_TOK_AXIS_GRID }, + { XML_NAMESPACE_CHART, XML_DATE_SCALE, XML_TOK_AXIS_DATE_SCALE }, + { XML_NAMESPACE_CHART_EXT, XML_DATE_SCALE, XML_TOK_AXIS_DATE_SCALE_EXT }, + XML_TOKEN_MAP_END +}; + +class AxisChildTokenMap : public SvXMLTokenMap +{ +public: + AxisChildTokenMap(): SvXMLTokenMap( aAxisChildTokenMap ) {} + virtual ~AxisChildTokenMap() {} +}; + +//a AxisChildTokenMap Singleton +struct theAxisChildTokenMap : public rtl::Static< AxisChildTokenMap, theAxisChildTokenMap > {}; +} + +SvXMLImportContextRef SchXMLAxisContext::CreateChildContext( + sal_uInt16 p_nPrefix, + const OUString& rLocalName, + const Reference< xml::sax::XAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + const SvXMLTokenMap& rTokenMap = theAxisChildTokenMap::get(); + + switch( rTokenMap.Get( p_nPrefix, rLocalName )) + { + case XML_TOK_AXIS_TITLE: + { + Reference< drawing::XShape > xTitleShape = getTitleShape(); + pContext = new SchXMLTitleContext( m_rImportHelper, GetImport(), rLocalName, + m_aCurrentAxis.aTitle, + xTitleShape ); + } + break; + + case XML_TOK_AXIS_CATEGORIES: + pContext = new SchXMLCategoriesContext( GetImport(), + p_nPrefix, rLocalName, + m_rCategoriesAddress ); + m_aCurrentAxis.bHasCategories = true; + break; + + case XML_TOK_AXIS_DATE_SCALE: + case XML_TOK_AXIS_DATE_SCALE_EXT: + pContext = new DateScaleContext( GetImport(), + p_nPrefix, rLocalName, m_xAxisProps ); + m_bDateScaleImported = true; + break; + + case XML_TOK_AXIS_GRID: + { + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + bool bIsMajor = true; // default value for class is "major" + OUString sAutoStyleName; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_CHART ) + { + if( IsXMLToken( aLocalName, XML_CLASS ) ) + { + if( IsXMLToken( xAttrList->getValueByIndex( i ), XML_MINOR ) ) + bIsMajor = false; + } + else if( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + sAutoStyleName = xAttrList->getValueByIndex( i ); + } + } + + CreateGrid( sAutoStyleName, bIsMajor ); + + // don't create a context => use default context. grid elements are empty + } + break; + + default: + break; + } + + return pContext; +} + +void SchXMLAxisContext::EndElement() +{ + if( !m_bDateScaleImported && m_nAxisType==chart::ChartAxisType::AUTOMATIC ) + { + Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(), m_aCurrentAxis.eDimension, m_aCurrentAxis.nAxisIndex ) ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData()); + aScaleData.AutoDateAxis = false;//different default for older documents + xAxis->setScaleData( aScaleData ); + } + } + + SetAxisTitle(); +} + +namespace +{ + +Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& rCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + Reference< chart2::XAxis > xAxis; + try + { + xAxis = rCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ); + } + catch( uno::Exception & ) + { + } + return xAxis; +} + +} // anonymous namespace + +void SchXMLAxisContext::CorrectAxisPositions( const Reference< chart2::XChartDocument >& xNewDoc, + const OUString& rChartTypeServiceName, + const OUString& rODFVersionOfFile, + bool bAxisPositionAttributeImported ) +{ + if( rODFVersionOfFile.isEmpty() || rODFVersionOfFile == "1.0" || rODFVersionOfFile == "1.1" + || ( rODFVersionOfFile == "1.2" && !bAxisPositionAttributeImported ) ) + { + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); + uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + if( aCooSysSeq.hasElements() ) + { + Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] ); + if( xCooSys.is() ) + { + Reference< chart2::XAxis > xMainXAxis = lcl_getAxis( xCooSys, 0, 0 ); + Reference< chart2::XAxis > xMainYAxis = lcl_getAxis( xCooSys, 1, 0 ); + //Reference< chart2::XAxis > xMajorZAxis = lcl_getAxis( xCooSys, 2, 0 ); + Reference< chart2::XAxis > xSecondaryXAxis = lcl_getAxis( xCooSys, 0, 1 ); + Reference< chart2::XAxis > xSecondaryYAxis = lcl_getAxis( xCooSys, 1, 1 ); + + Reference< beans::XPropertySet > xMainXAxisProp( xMainXAxis, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xMainYAxisProp( xMainYAxis, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xSecondaryXAxisProp( xSecondaryXAxis, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xSecondaryYAxisProp( xSecondaryYAxis, uno::UNO_QUERY ); + + if( xMainXAxisProp.is() && xMainYAxisProp.is() ) + { + chart2::ScaleData aMainXScale = xMainXAxis->getScaleData(); + if( rChartTypeServiceName == "com.sun.star.chart2.ScatterChartType" ) + { + xMainYAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_VALUE) ); + double fCrossoverValue = 0.0; + aMainXScale.Origin >>= fCrossoverValue; + xMainYAxisProp->setPropertyValue("CrossoverValue" + , uno::makeAny( fCrossoverValue ) ); + + if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE ) + { + xMainYAxisProp->setPropertyValue("LabelPosition" + , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_END) ); + xMainYAxisProp->setPropertyValue("MarkPosition" + , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) ); + if( xSecondaryYAxisProp.is() ) + xSecondaryYAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_START) ); + } + else + { + xMainYAxisProp->setPropertyValue("LabelPosition" + , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_START) ); + xMainYAxisProp->setPropertyValue("MarkPosition" + , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) ); + if( xSecondaryYAxisProp.is() ) + xSecondaryYAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_END) ); + } + } + else + { + if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE ) + { + xMainYAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_END) ); + if( xSecondaryYAxisProp.is() ) + xSecondaryYAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_START) ); + } + else + { + xMainYAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_START) ); + if( xSecondaryYAxisProp.is() ) + xSecondaryYAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_END) ); + } + } + + chart2::ScaleData aMainYScale = xMainYAxis->getScaleData(); + xMainXAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_VALUE) ); + double fCrossoverValue = 0.0; + aMainYScale.Origin >>= fCrossoverValue; + xMainXAxisProp->setPropertyValue("CrossoverValue" + , uno::makeAny( fCrossoverValue ) ); + + if( aMainYScale.Orientation == chart2::AxisOrientation_REVERSE ) + { + xMainXAxisProp->setPropertyValue("LabelPosition" + , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_END) ); + xMainXAxisProp->setPropertyValue("MarkPosition" + , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) ); + if( xSecondaryXAxisProp.is() ) + xSecondaryXAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_START) ); + } + else + { + xMainXAxisProp->setPropertyValue("LabelPosition" + , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_START) ); + xMainXAxisProp->setPropertyValue("MarkPosition" + , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) ); + if( xSecondaryXAxisProp.is() ) + xSecondaryXAxisProp->setPropertyValue("CrossoverPosition" + , uno::makeAny( css::chart::ChartAxisPosition_END) ); + } + } + } + } + } + catch( uno::Exception & ) + { + } + } +} + +SchXMLCategoriesContext::SchXMLCategoriesContext( + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + OUString& rAddress ) : + SvXMLImportContext( rImport, nPrefix, rLocalName ), + mrAddress( rAddress ) +{ +} + +void SchXMLCategoriesContext::StartElement( const Reference< xml::sax::XAttributeList >& xAttrList ) +{ + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_TABLE && + IsXMLToken( aLocalName, XML_CELL_RANGE_ADDRESS ) ) + { + mrAddress = xAttrList->getValueByIndex( i ); + } + } +} + +DateScaleContext::DateScaleContext( + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const Reference< beans::XPropertySet >& rAxisProps ) : + SvXMLImportContext( rImport, nPrefix, rLocalName ), + m_xAxisProps( rAxisProps ) +{ +} + +namespace +{ +enum DateScaleAttributeTokens +{ + XML_TOK_DATESCALE_BASE_TIME_UNIT, + XML_TOK_DATESCALE_MAJOR_INTERVAL_VALUE, + XML_TOK_DATESCALE_MAJOR_INTERVAL_UNIT, + XML_TOK_DATESCALE_MINOR_INTERVAL_VALUE, + XML_TOK_DATESCALE_MINOR_INTERVAL_UNIT +}; + +const SvXMLTokenMapEntry aDateScaleAttributeTokenMap[] = +{ + { XML_NAMESPACE_CHART, XML_BASE_TIME_UNIT, XML_TOK_DATESCALE_BASE_TIME_UNIT }, + { XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_VALUE, XML_TOK_DATESCALE_MAJOR_INTERVAL_VALUE }, + { XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_UNIT, XML_TOK_DATESCALE_MAJOR_INTERVAL_UNIT }, + { XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_VALUE, XML_TOK_DATESCALE_MINOR_INTERVAL_VALUE }, + { XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_UNIT, XML_TOK_DATESCALE_MINOR_INTERVAL_UNIT }, + XML_TOKEN_MAP_END +}; + +class DateScaleAttributeTokenMap : public SvXMLTokenMap +{ +public: + DateScaleAttributeTokenMap(): SvXMLTokenMap( aDateScaleAttributeTokenMap ) {} + virtual ~DateScaleAttributeTokenMap() {} +}; + +struct theDateScaleAttributeTokenMap : public rtl::Static< DateScaleAttributeTokenMap, theDateScaleAttributeTokenMap > {}; + +sal_Int32 lcl_getTimeUnit( const OUString& rValue ) +{ + sal_Int32 nTimeUnit = css::chart::TimeUnit::DAY; + if( IsXMLToken( rValue, XML_DAYS ) ) + nTimeUnit = css::chart::TimeUnit::DAY; + else if( IsXMLToken( rValue, XML_MONTHS ) ) + nTimeUnit = css::chart::TimeUnit::MONTH; + else if( IsXMLToken( rValue, XML_YEARS ) ) + nTimeUnit = css::chart::TimeUnit::YEAR; + return nTimeUnit; +} + +} + +void DateScaleContext::StartElement( const Reference< xml::sax::XAttributeList >& xAttrList ) +{ + if( !m_xAxisProps.is() ) + return; + + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + const SvXMLTokenMap& rAttrTokenMap = theDateScaleAttributeTokenMap::get(); + + bool bSetNewIncrement=false; + chart::TimeIncrement aIncrement; + m_xAxisProps->getPropertyValue("TimeIncrement") >>= aIncrement; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_DATESCALE_BASE_TIME_UNIT: + { + aIncrement.TimeResolution <<= lcl_getTimeUnit(aValue); + bSetNewIncrement = true; + } + break; + case XML_TOK_DATESCALE_MAJOR_INTERVAL_VALUE: + { + chart::TimeInterval aInterval(1,0); + aIncrement.MajorTimeInterval >>= aInterval; + ::sax::Converter::convertNumber( aInterval.Number, aValue ); + aIncrement.MajorTimeInterval <<= aInterval; + bSetNewIncrement = true; + } + break; + case XML_TOK_DATESCALE_MAJOR_INTERVAL_UNIT: + { + chart::TimeInterval aInterval(1,0); + aIncrement.MajorTimeInterval >>= aInterval; + aInterval.TimeUnit = lcl_getTimeUnit(aValue); + aIncrement.MajorTimeInterval <<= aInterval; + bSetNewIncrement = true; + } + break; + case XML_TOK_DATESCALE_MINOR_INTERVAL_VALUE: + { + chart::TimeInterval aInterval(1,0); + aIncrement.MinorTimeInterval >>= aInterval; + ::sax::Converter::convertNumber( aInterval.Number, aValue ); + aIncrement.MinorTimeInterval <<= aInterval; + bSetNewIncrement = true; + } + break; + case XML_TOK_DATESCALE_MINOR_INTERVAL_UNIT: + { + chart::TimeInterval aInterval(1,0); + aIncrement.MinorTimeInterval >>= aInterval; + aInterval.TimeUnit = lcl_getTimeUnit(aValue); + aIncrement.MinorTimeInterval <<= aInterval; + bSetNewIncrement = true; + } + break; + } + } + + if( bSetNewIncrement ) + m_xAxisProps->setPropertyValue("TimeIncrement", uno::makeAny( aIncrement ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLAxisContext.hxx b/xmloff/source/chart/SchXMLAxisContext.hxx new file mode 100644 index 000000000..622c6282a --- /dev/null +++ b/xmloff/source/chart/SchXMLAxisContext.hxx @@ -0,0 +1,80 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLAXISCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLAXISCONTEXT_HXX + +#include +#include + +#include "transporttypes.hxx" + +#include +#include + +class SchXMLAxisContext : public SvXMLImportContext +{ +public: + SchXMLAxisContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + css::uno::Reference< css::chart::XDiagram > const & xDiagram, + std::vector< SchXMLAxis >& aAxes, + OUString& rCategoriesAddress, + bool bAddMissingXAxisForNetCharts, + bool bAdaptWrongPercentScaleValues, + bool bAdaptXAxisOrientationForOld2DBarCharts, + bool& rbAxisPositionAttributeImported ); + virtual ~SchXMLAxisContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + static void CorrectAxisPositions( const css::uno::Reference< css::chart2::XChartDocument >& xNewDoc, + const OUString& rChartTypeServiceName, + const OUString& rODFVersionOfFile, + bool bAxisPositionAttributeImported ); + +private: + SchXMLImportHelper& m_rImportHelper; + css::uno::Reference< css::chart::XDiagram > m_xDiagram; + SchXMLAxis m_aCurrentAxis; + std::vector< SchXMLAxis >& m_rAxes; + css::uno::Reference< css::beans::XPropertySet > m_xAxisProps; + OUString m_aAutoStyleName; + OUString& m_rCategoriesAddress; + sal_Int32 m_nAxisType;//css::chart::ChartAxisType + bool m_bAxisTypeImported; + bool m_bDateScaleImported; + bool m_bAddMissingXAxisForNetCharts; //to correct errors from older versions + bool m_bAdaptWrongPercentScaleValues; //to correct errors from older versions + bool m_bAdaptXAxisOrientationForOld2DBarCharts; //to correct different behaviour from older versions + bool& m_rbAxisPositionAttributeImported; + + css::uno::Reference< css::drawing::XShape > getTitleShape() const; + void CreateGrid( const OUString& sAutoStyleName, bool bIsMajor ); + void CreateAxis(); + void SetAxisTitle(); +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLAXISCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLCalculationSettingsContext.cxx b/xmloff/source/chart/SchXMLCalculationSettingsContext.cxx new file mode 100644 index 000000000..74780fe7e --- /dev/null +++ b/xmloff/source/chart/SchXMLCalculationSettingsContext.cxx @@ -0,0 +1,76 @@ +/* -*- 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 "SchXMLCalculationSettingsContext.hxx" +#include +#include +#include + +#include + +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SchXMLCalculationSettingsContext::SchXMLCalculationSettingsContext( SvXMLImport& rImport, + sal_uInt16 p_nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) +: SvXMLImportContext ( rImport, p_nPrefix, rLocalName ) +{ + const SvXMLNamespaceMap& rMap = GetImport().GetNamespaceMap(); + const sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + const sal_uInt16 nPrefix = rMap.GetKeyByAttrName(sAttrName, &aLocalName ); + if ( nPrefix == XML_NAMESPACE_TABLE && IsXMLToken( aLocalName, XML_DATE_VALUE ) ) + { + util::DateTime aNullDate; + const OUString sValue = xAttrList->getValueByIndex( i ); + ::sax::Converter::parseDateTime(aNullDate, sValue); + m_aNullDate <<= aNullDate; + } + } +} +SvXMLImportContextRef SchXMLCalculationSettingsContext::CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) +{ + return new SchXMLCalculationSettingsContext(GetImport(),nPrefix,rLocalName,xAttrList); +} + +void SchXMLCalculationSettingsContext::EndElement() +{ + if ( m_aNullDate.hasValue() ) + { + Reference < XPropertySet > xPropSet ( GetImport().GetModel(), UNO_QUERY ); + xPropSet->setPropertyValue ( "NullDate", m_aNullDate ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLCalculationSettingsContext.hxx b/xmloff/source/chart/SchXMLCalculationSettingsContext.hxx new file mode 100644 index 000000000..0fbe3056a --- /dev/null +++ b/xmloff/source/chart/SchXMLCalculationSettingsContext.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLCALCULATIONSETTINGSCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLCALCULATIONSETTINGSCONTEXT_HXX + +#include + +class SchXMLCalculationSettingsContext : public SvXMLImportContext +{ + css::uno::Any m_aNullDate; +public: + SchXMLCalculationSettingsContext( SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ); + + virtual SvXMLImportContextRef CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void EndElement() override; +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx new file mode 100644 index 000000000..b5f85d77d --- /dev/null +++ b/xmloff/source/chart/SchXMLChartContext.cxx @@ -0,0 +1,1242 @@ +/* -*- 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 "SchXMLChartContext.hxx" +#include +#include "SchXMLLegendContext.hxx" +#include "SchXMLPlotAreaContext.hxx" +#include "SchXMLParagraphContext.hxx" +#include "SchXMLTableContext.hxx" +#include "SchXMLSeries2Context.hxx" +#include "SchXMLTools.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; +using com::sun::star::uno::Reference; +using namespace ::SchXMLTools; + +namespace +{ + +void lcl_setRoleAtLabeledSequence( + const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq, + const OUString &rRole ) +{ + // set role of sequence + uno::Reference< chart2::data::XDataSequence > xValues( xLSeq->getValues()); + if( xValues.is()) + { + uno::Reference< beans::XPropertySet > xProp( xValues, uno::UNO_QUERY ); + if( xProp.is()) + xProp->setPropertyValue("Role", uno::makeAny( rRole )); + } +} + +void lcl_MoveDataToCandleStickSeries( + const uno::Reference< chart2::data::XDataSource > & xDataSource, + const uno::Reference< chart2::XDataSeries > & xDestination, + const OUString & rRole ) +{ + try + { + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq( + xDataSource->getDataSequences()); + if( aLabeledSeq.hasElements()) + { + lcl_setRoleAtLabeledSequence( aLabeledSeq[0], rRole ); + + // add to data series + uno::Reference< chart2::data::XDataSource > xSource( xDestination, uno::UNO_QUERY_THROW ); + // @todo: realloc only once outside this function + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xSource->getDataSequences()); + aData.realloc( aData.getLength() + 1); + aData[ aData.getLength() - 1 ] = aLabeledSeq[0]; + uno::Reference< chart2::data::XDataSink > xSink( xDestination, uno::UNO_QUERY_THROW ); + xSink->setData( aData ); + } + } + catch(const uno::Exception&) + { + SAL_WARN("xmloff.chart", "Exception caught while moving data to candlestick series" ); + } +} + +void lcl_setRoleAtFirstSequence( + const uno::Reference< chart2::XDataSeries > & xSeries, + const OUString & rRole ) +{ + uno::Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences()); + if( aSeq.hasElements()) + lcl_setRoleAtLabeledSequence( aSeq[0], rRole ); + } +} + +void lcl_removeEmptyChartTypeGroups( const uno::Reference< chart2::XChartDocument > & xDoc ) +{ + if( ! xDoc.is()) + return; + + uno::Reference< chart2::XDiagram > xDia( xDoc->getFirstDiagram()); + if( ! xDia.is()) + return; + + try + { + // count all charttype groups to be able to leave at least one + sal_Int32 nRemainingGroups = 0; + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW ); + const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + for( auto const & i : aCooSysSeq ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( i, uno::UNO_QUERY_THROW ); + nRemainingGroups += xCTCnt->getChartTypes().getLength(); + } + + // delete all empty groups, but leave at least group (empty or not) + for( sal_Int32 nI = aCooSysSeq.getLength(); nI-- && (nRemainingGroups > 1); ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes()); + for( sal_Int32 nJ=aCTSeq.getLength(); nJ-- && (nRemainingGroups > 1); ) + { + uno::Reference< chart2::XDataSeriesContainer > xDSCnt( aCTSeq[nJ], uno::UNO_QUERY_THROW ); + if( !xDSCnt->getDataSeries().hasElements() ) + { + // note: iterator stays valid as we have a local sequence + xCTCnt->removeChartType( aCTSeq[nJ] ); + --nRemainingGroups; + } + } + } + } + catch(const uno::Exception&) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught while removing empty chart types"); + } +} + +uno::Sequence< sal_Int32 > lcl_getNumberSequenceFromString( const OUString& rStr, bool bAddOneToEachOldIndex ) +{ + const sal_Unicode aSpace( ' ' ); + + // count number of entries + ::std::vector< sal_Int32 > aVec; + sal_Int32 nLastPos = 0; + sal_Int32 nPos = 0; + while( nPos != -1 ) + { + nPos = rStr.indexOf( aSpace, nLastPos ); + if( nPos > nLastPos ) + { + aVec.push_back( rStr.copy( nLastPos, (nPos - nLastPos) ).toInt32() ); + } + if( nPos != -1 ) + nLastPos = nPos + 1; + } + // last entry + if( nLastPos != 0 && + rStr.getLength() > nLastPos ) + { + aVec.push_back( rStr.copy( nLastPos ).toInt32() ); + } + + const sal_Int32 nVecSize = aVec.size(); + uno::Sequence< sal_Int32 > aSeq( nVecSize ); + + if(!bAddOneToEachOldIndex) + { + sal_Int32* pSeqArr = aSeq.getArray(); + for( nPos = 0; nPos < nVecSize; ++nPos ) + { + pSeqArr[ nPos ] = aVec[ nPos ]; + } + } + else if( bAddOneToEachOldIndex ) + { + aSeq.realloc( nVecSize+1 ); + aSeq[0]=0; + + sal_Int32* pSeqArr = aSeq.getArray(); + for( nPos = 0; nPos < nVecSize; ++nPos ) + { + pSeqArr[ nPos+1 ] = aVec[ nPos ]+1; + } + } + + return aSeq; +} + +} // anonymous namespace + +SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImpHelper ), + m_bHasRangeAtPlotArea( false ), + m_bHasTableElement( false ), + mbAllRangeAddressesAvailable( true ), + mbColHasLabels( false ), + mbRowHasLabels( false ), + meDataRowSource( chart::ChartDataRowSource_COLUMNS ), + mbIsStockChart( false ) +{ +} + +SchXMLChartContext::~SchXMLChartContext() +{} + +static bool lcl_hasServiceName(Reference const & xFactory, OUString const & rServiceName) +{ + const uno::Sequence aServiceNames(xFactory->getAvailableServiceNames()); + + return std::find(aServiceNames.begin(), aServiceNames.end(), rServiceName) != aServiceNames.end(); +} + +static void lcl_setDataProvider(uno::Reference const & xChartDoc, OUString const & sDataPilotSource) +{ + if (!xChartDoc.is()) + return; + + try + { + uno::Reference xChild(xChartDoc, uno::UNO_QUERY); + uno::Reference xDataReceiver(xChartDoc, uno::UNO_QUERY); + if (xChild.is() && xDataReceiver.is()) + { + bool bHasOwnData = true; + + Reference xFact(xChild->getParent(), uno::UNO_QUERY); + if (xFact.is()) + { + if (!xChartDoc->getDataProvider().is()) + { + bool bHasDataPilotSource = !sDataPilotSource.isEmpty(); + OUString aDataProviderServiceName("com.sun.star.chart2.data.DataProvider"); + if (bHasDataPilotSource) + aDataProviderServiceName = "com.sun.star.chart2.data.PivotTableDataProvider"; + + if (lcl_hasServiceName(xFact, aDataProviderServiceName)) + { + Reference xProvider(xFact->createInstance(aDataProviderServiceName), uno::UNO_QUERY); + + if (xProvider.is()) + { + if (bHasDataPilotSource) + { + Reference xPivotTableDataProvider(xProvider, uno::UNO_QUERY); + xPivotTableDataProvider->setPivotTableName(sDataPilotSource); + xDataReceiver->attachDataProvider(xProvider); + bHasOwnData = !xPivotTableDataProvider->hasPivotTable(); + } + else + { + xDataReceiver->attachDataProvider(xProvider); + bHasOwnData = false; + } + } + } + } + else + bHasOwnData = false; + } + // else we have no parent => we have our own data + + if (bHasOwnData && ! xChartDoc->hasInternalDataProvider()) + xChartDoc->createInternalDataProvider(false); + } + } + catch (const uno::Exception &) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "SchXMLChartContext::StartElement()"); + } +} + +void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // parse attributes + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetChartAttrTokenMap(); + + uno::Reference< embed::XVisualObject > xVisualObject( mrImportHelper.GetChartDocument(), uno::UNO_QUERY); + SAL_WARN_IF(!xVisualObject.is(), "xmloff.chart", "need xVisualObject for page size"); + if( xVisualObject.is() ) + maChartSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); //#i103460# take the size given from the parent frame as default + + OUString sAutoStyleName; + OUString aOldChartTypeName; + bool bHasAddin = false; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_CHART_DATA_PILOT_SOURCE: + msDataPilotSource = aValue; + break; + case XML_TOK_CHART_HREF: + m_aXLinkHRefAttributeToIndicateDataProvider = aValue; + break; + case XML_TOK_CHART_CLASS: + { + OUString sClassName; + sal_uInt16 nClassPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + aValue, &sClassName ); + if( XML_NAMESPACE_CHART == nClassPrefix ) + { + SchXMLChartTypeEnum eChartTypeEnum = SchXMLTools::GetChartTypeEnum( sClassName ); + if( eChartTypeEnum != XML_CHART_CLASS_UNKNOWN ) + { + aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( sClassName, true /* bUseOldNames */ ); + maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( sClassName, false /* bUseOldNames */ ); + switch( eChartTypeEnum ) + { + case XML_CHART_CLASS_STOCK: + mbIsStockChart = true; + break; + default: + break; + } + } + } + else if( XML_NAMESPACE_OOO == nClassPrefix ) + { + // service is taken from add-in-name attribute + bHasAddin = true; + + aOldChartTypeName = sClassName; + maChartTypeServiceName = sClassName; + } + } + break; + + case XML_TOK_CHART_WIDTH: + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maChartSize.Width, aValue ); + break; + + case XML_TOK_CHART_HEIGHT: + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maChartSize.Height, aValue ); + break; + + case XML_TOK_CHART_STYLE_NAME: + sAutoStyleName = aValue; + break; + + case XML_TOK_CHART_COL_MAPPING: + msColTrans = aValue; + break; + case XML_TOK_CHART_ROW_MAPPING: + msRowTrans = aValue; + break; + } + } + + uno::Reference xDoc = mrImportHelper.GetChartDocument(); + uno::Reference xNewDoc(xDoc, uno::UNO_QUERY); + + lcl_setDataProvider(xNewDoc, msDataPilotSource); + + if( aOldChartTypeName.isEmpty() ) + { + SAL_WARN("xmloff.chart", "need a charttype to create a diagram" ); + //set a fallback value: + const OUString& aChartClass_Bar( GetXMLToken(XML_BAR ) ); + aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, true /* bUseOldNames */ ); + maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, false /* bUseOldNames */ ); + } + + // Set the size of the draw page. + if( xVisualObject.is() ) + xVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, maChartSize ); + + InitChart( aOldChartTypeName); + + if( bHasAddin ) + { + //correct charttype service name when having an addin + //and don't refresh addin during load + uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); + if( xDocProp.is() ) + { + try + { + xDocProp->getPropertyValue("BaseDiagram") >>= aOldChartTypeName; + maChartTypeServiceName = SchXMLTools::GetNewChartTypeName( aOldChartTypeName ); + xDocProp->setPropertyValue("RefreshAddInAllowed", uno::makeAny( false) ); + } + catch(const uno::Exception&) + { + SAL_WARN("xmloff.chart", "Exception during import SchXMLChartContext::StartElement" ); + } + } + } + + // set auto-styles for Area + uno::Reference xProp = mrImportHelper.GetChartDocument()->getArea(); + mrImportHelper.FillAutoStyle(sAutoStyleName, xProp); +} + +namespace +{ + +struct NewDonutSeries +{ + css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + OUString msStyleName; + sal_Int32 mnAttachedAxis; + + ::std::vector< OUString > m_aSeriesStyles; + ::std::vector< OUString > m_aPointStyles; + + NewDonutSeries( const css::uno::Reference< css::chart2::XDataSeries >& xSeries, sal_Int32 nPointCount ) + : m_xSeries( xSeries ) + , mnAttachedAxis( 1 ) + { + m_aPointStyles.resize(nPointCount); + m_aSeriesStyles.resize(nPointCount); + } + + void setSeriesStyleNameToPoint( const OUString& rStyleName, sal_Int32 nPointIndex ) + { + SAL_WARN_IF(nPointIndex >= static_cast(m_aSeriesStyles.size()), "xmloff.chart", "donut point <-> series count mismatch"); + if( nPointIndex < static_cast(m_aSeriesStyles.size()) ) + m_aSeriesStyles[nPointIndex]=rStyleName; + } + + void setPointStyleNameToPoint( const OUString& rStyleName, sal_Int32 nPointIndex ) + { + SAL_WARN_IF(nPointIndex >= static_cast(m_aPointStyles.size()), "xmloff.chart", "donut point <-> series count mismatch"); + if( nPointIndex < static_cast(m_aPointStyles.size()) ) + m_aPointStyles[nPointIndex]=rStyleName; + } + + ::std::vector< DataRowPointStyle > creatStyleVector() + { + ::std::vector< DataRowPointStyle > aRet; + + DataRowPointStyle aSeriesStyle( DataRowPointStyle::DATA_SERIES + , m_xSeries, -1, 1, msStyleName, mnAttachedAxis ); + aRet.push_back( aSeriesStyle ); + + sal_Int32 nPointIndex=0; + for (auto const& pointStyle : m_aPointStyles) + { + DataRowPointStyle aPointStyle( DataRowPointStyle::DATA_POINT + , m_xSeries, nPointIndex, 1, pointStyle, mnAttachedAxis ); + if( nPointIndex < static_cast(m_aSeriesStyles.size()) ) + { + aPointStyle.msSeriesStyleNameForDonuts = m_aSeriesStyles[nPointIndex]; + } + if( !aPointStyle.msSeriesStyleNameForDonuts.isEmpty() + || !aPointStyle.msStyleName.isEmpty() ) + aRet.push_back( aPointStyle ); + ++nPointIndex; + } + + return aRet; + } +}; + +void lcl_swapPointAndSeriesStylesForDonutCharts( ::std::vector< DataRowPointStyle >& rStyleVector + , const ::std::map< css::uno::Reference< css::chart2::XDataSeries> , sal_Int32 >& rSeriesMap ) +{ + //detect old series count + //and add old series to aSeriesMap + ::std::map< css::uno::Reference< + css::chart2::XDataSeries >, sal_Int32 > aSeriesMap(rSeriesMap); + sal_Int32 nOldSeriesCount = 0; + { + sal_Int32 nMaxOldSeriesIndex = 0; + sal_Int32 nOldSeriesIndex = 0; + for (auto const& style : rStyleVector) + { + DataRowPointStyle aStyle(style); + if(aStyle.meType == DataRowPointStyle::DATA_SERIES && + aStyle.m_xSeries.is() ) + { + nMaxOldSeriesIndex = nOldSeriesIndex; + + if( aSeriesMap.end() == aSeriesMap.find(aStyle.m_xSeries) ) + aSeriesMap[aStyle.m_xSeries] = nOldSeriesIndex; + + nOldSeriesIndex++; + } + } + nOldSeriesCount = nMaxOldSeriesIndex+1; + } + + //initialize new series styles + ::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapEnd( aSeriesMap.end() ); + + //sort by index + ::std::vector< NewDonutSeries > aNewSeriesVector; + { + ::std::map< sal_Int32, Reference< chart2::XDataSeries > > aIndexSeriesMap; + for (auto const& series : aSeriesMap) + aIndexSeriesMap[series.second] = series.first; + + for (auto const& indexSeries : aIndexSeriesMap) + aNewSeriesVector.emplace_back(indexSeries.second,nOldSeriesCount ); + } + + //overwrite attached axis information according to old series styles + for (auto const& style : rStyleVector) + { + DataRowPointStyle aStyle(style); + if(aStyle.meType == DataRowPointStyle::DATA_SERIES ) + { + auto aSeriesMapIt = aSeriesMap.find( aStyle.m_xSeries ); + if( aSeriesMapIt != aSeriesMapEnd && aSeriesMapIt->second < static_cast(aNewSeriesVector.size()) ) + aNewSeriesVector[aSeriesMapIt->second].mnAttachedAxis = aStyle.mnAttachedAxis; + } + } + + //overwrite new series style names with old series style name information + for (auto const& style : rStyleVector) + { + DataRowPointStyle aStyle(style); + if( aStyle.meType == DataRowPointStyle::DATA_SERIES ) + { + auto aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries); + if( aSeriesMapEnd != aSeriesMapIt ) + { + sal_Int32 nNewPointIndex = aSeriesMapIt->second; + + for (auto & newSeries : aNewSeriesVector) + newSeries.setSeriesStyleNameToPoint( aStyle.msStyleName, nNewPointIndex ); + } + } + } + + //overwrite new series style names with point style name information + for (auto const& style : rStyleVector) + { + DataRowPointStyle aStyle(style); + if( aStyle.meType == DataRowPointStyle::DATA_POINT ) + { + auto aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries); + if( aSeriesMapEnd != aSeriesMapIt ) + { + sal_Int32 nNewPointIndex = aSeriesMapIt->second; + sal_Int32 nNewSeriesIndex = aStyle.m_nPointIndex; + sal_Int32 nRepeatCount = aStyle.m_nPointRepeat; + + while( nRepeatCount && (nNewSeriesIndex>=0) && (nNewSeriesIndex< static_cast(aNewSeriesVector.size()) ) ) + { + NewDonutSeries& rNewSeries( aNewSeriesVector[nNewSeriesIndex] ); + rNewSeries.setPointStyleNameToPoint( aStyle.msStyleName, nNewPointIndex ); + + nRepeatCount--; + nNewSeriesIndex++; + } + } + } + } + + //put information from aNewSeriesVector to output parameter rStyleVector + rStyleVector.clear(); + + for (auto & newSeries : aNewSeriesVector) + { + ::std::vector< DataRowPointStyle > aVector( newSeries.creatStyleVector() ); + rStyleVector.insert(rStyleVector.end(),aVector.begin(),aVector.end()); + } +} + +bool lcl_SpecialHandlingForDonutChartNeeded( + const OUString & rServiceName, + const SvXMLImport & rImport ) +{ + bool bResult = false; + if( rServiceName == "com.sun.star.chart2.DonutChartType" ) + { + bResult = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( rImport.GetModel() ); + } + return bResult; +} + +} // anonymous namespace + +static void lcl_ApplyDataFromRectangularRangeToDiagram( + const uno::Reference< chart2::XChartDocument >& xNewDoc + , const OUString& rRectangularRange + , css::chart::ChartDataRowSource eDataRowSource + , bool bRowHasLabels, bool bColHasLabels + , bool bSwitchOnLabelsAndCategoriesForOwnData + , const OUString& sColTrans + , const OUString& sRowTrans ) +{ + if( !xNewDoc.is() ) + return; + + uno::Reference< chart2::XDiagram > xNewDia( xNewDoc->getFirstDiagram()); + uno::Reference< chart2::data::XDataProvider > xDataProvider( xNewDoc->getDataProvider() ); + if( !xNewDia.is() || !xDataProvider.is() ) + return; + + bool bFirstCellAsLabel = + (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bRowHasLabels : bColHasLabels; + bool bHasCateories = + (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bColHasLabels : bRowHasLabels; + + if( bSwitchOnLabelsAndCategoriesForOwnData ) + { + bFirstCellAsLabel = true; + bHasCateories = true; + } + + uno::Sequence< beans::PropertyValue > aArgs( 3 ); + aArgs[0] = beans::PropertyValue( + "CellRangeRepresentation", + -1, uno::makeAny( rRectangularRange ), + beans::PropertyState_DIRECT_VALUE ); + aArgs[1] = beans::PropertyValue( + "DataRowSource", + -1, uno::makeAny( eDataRowSource ), + beans::PropertyState_DIRECT_VALUE ); + aArgs[2] = beans::PropertyValue( + "FirstCellAsLabel", + -1, uno::makeAny( bFirstCellAsLabel ), + beans::PropertyState_DIRECT_VALUE ); + + if( !sColTrans.isEmpty() || !sRowTrans.isEmpty() ) + { + aArgs.realloc( aArgs.getLength() + 1 ); + aArgs[ sal::static_int_cast(aArgs.getLength()) - 1 ] = beans::PropertyValue( + "SequenceMapping", + -1, uno::makeAny( !sColTrans.isEmpty() + ? lcl_getNumberSequenceFromString( sColTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) + : lcl_getNumberSequenceFromString( sRowTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) ), + beans::PropertyState_DIRECT_VALUE ); + } + + //work around wrong writer ranges ( see Issue 58464 ) + { + OUString aChartOleObjectName; + if( xNewDoc.is() ) + { + utl::MediaDescriptor aMediaDescriptor( xNewDoc->getArgs() ); + + utl::MediaDescriptor::const_iterator aIt( + aMediaDescriptor.find( OUString( "HierarchicalDocumentName" ))); + if( aIt != aMediaDescriptor.end() ) + { + aChartOleObjectName = (*aIt).second.get< OUString >(); + } + } + if( !aChartOleObjectName.isEmpty() ) + { + aArgs.realloc( aArgs.getLength() + 1 ); + aArgs[ sal::static_int_cast(aArgs.getLength()) - 1 ] = beans::PropertyValue( + "ChartOleObjectName", + -1, uno::makeAny( aChartOleObjectName ), + beans::PropertyState_DIRECT_VALUE ); + } + } + + uno::Reference< chart2::data::XDataSource > xDataSource( + xDataProvider->createDataSource( aArgs )); + + aArgs.realloc( aArgs.getLength() + 2 ); + aArgs[ sal::static_int_cast(aArgs.getLength()) - 2 ] = beans::PropertyValue( + "HasCategories", + -1, uno::makeAny( bHasCateories ), + beans::PropertyState_DIRECT_VALUE ); + aArgs[ sal::static_int_cast(aArgs.getLength()) - 1 ] = beans::PropertyValue( + "UseCategoriesAsX", + -1, uno::makeAny( false ),//categories in ODF files are not to be used as x values (independent from what is offered in our ui) + beans::PropertyState_DIRECT_VALUE ); + + xNewDia->setDiagramData( xDataSource, aArgs ); +} + +void SchXMLChartContext::EndElement() +{ + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY ); + uno::Reference< chart2::XChartDocument > xNewDoc( xDoc, uno::UNO_QUERY ); + + if( xProp.is()) + { + if( !maMainTitle.isEmpty()) + { + uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + try + { + xTitleProp->setPropertyValue("String", uno::Any(maMainTitle) ); + } + catch(const beans::UnknownPropertyException&) + { + SAL_WARN("xmloff.chart", "Property String for Title not available" ); + } + } + } + if( !maSubTitle.isEmpty()) + { + uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getSubTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + try + { + xTitleProp->setPropertyValue("String", uno::Any(maSubTitle) ); + } + catch(const beans::UnknownPropertyException&) + { + SAL_WARN("xmloff.chart", "Property String for Title not available" ); + } + } + } + } + + // cleanup: remove empty chart type groups + lcl_removeEmptyChartTypeGroups( xNewDoc ); + + // set stack mode before a potential chart type detection (in case we have a rectangular range) + uno::Reference< chart::XDiagram > xDiagram( xDoc->getDiagram() ); + uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY ); + if( xDiaProp.is()) + { + if( maSeriesDefaultsAndStyles.maStackedDefault.hasValue()) + xDiaProp->setPropertyValue("Stacked",maSeriesDefaultsAndStyles.maStackedDefault); + if( maSeriesDefaultsAndStyles.maPercentDefault.hasValue()) + xDiaProp->setPropertyValue("Percent",maSeriesDefaultsAndStyles.maPercentDefault); + if( maSeriesDefaultsAndStyles.maDeepDefault.hasValue()) + xDiaProp->setPropertyValue("Deep",maSeriesDefaultsAndStyles.maDeepDefault); + if( maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault.hasValue()) + xDiaProp->setPropertyValue("StackedBarsConnected",maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault); + } + + //the OOo 2.0 implementation and older has a bug with donuts + bool bSpecialHandlingForDonutChart = lcl_SpecialHandlingForDonutChartNeeded( + maChartTypeServiceName, GetImport()); + + // apply data + if(!xNewDoc.is()) + return; + + bool bHasOwnData = false; + if( m_aXLinkHRefAttributeToIndicateDataProvider == "." ) //data comes from the chart itself + bHasOwnData = true; + else if( m_aXLinkHRefAttributeToIndicateDataProvider == ".." ) //data comes from the parent application + bHasOwnData = false; + else if( !m_aXLinkHRefAttributeToIndicateDataProvider.isEmpty() ) //not supported so far to get the data by sibling objects -> fall back to chart itself if data are available + bHasOwnData = m_bHasTableElement; + else + bHasOwnData = !m_bHasRangeAtPlotArea; + + if( xNewDoc->hasInternalDataProvider()) + { + if( !m_bHasTableElement && m_aXLinkHRefAttributeToIndicateDataProvider != "." ) + { + //#i103147# ODF, workaround broken files with a missing table:cell-range-address at the plot-area + bool bSwitchSuccessful = SchXMLTools::switchBackToDataProviderFromParent( xNewDoc, maLSequencesPerIndex ); + bHasOwnData = !bSwitchSuccessful; + } + else + bHasOwnData = true;//e.g. in case of copy->paste from calc to impress + } + else if( bHasOwnData ) + { + xNewDoc->createInternalDataProvider( false /* bCloneExistingData */ ); + } + if( bHasOwnData ) + msChartAddress = "all"; + + bool bSwitchRangesFromOuterToInternalIfNecessary = false; + if( !bHasOwnData && mbAllRangeAddressesAvailable ) + { + // special handling for stock chart (merge series together) + if( mbIsStockChart ) + MergeSeriesForStockChart(); + } + else if( !msChartAddress.isEmpty() ) + { + //own data or only rectangular range available + + if( xNewDoc->hasInternalDataProvider() ) + SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc ); + + bool bOlderThan2_3 = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( xNewDoc ); + bool bOldFileWithOwnDataFromRows = (bOlderThan2_3 && bHasOwnData && (meDataRowSource==chart::ChartDataRowSource_ROWS)); // in this case there are range addresses that are simply wrong. + + if( mbAllRangeAddressesAvailable && !bSpecialHandlingForDonutChart && !mbIsStockChart && + !bOldFileWithOwnDataFromRows ) + { + //bHasOwnData is true in this case! + //e.g. for normal files with own data or also in case of copy paste scenario (e.g. calc to impress) + bSwitchRangesFromOuterToInternalIfNecessary = true; + } + else + { + //apply data from rectangular range + + // create datasource from data provider with rectangular range parameters and change the diagram setDiagramData + try + { + if( bOlderThan2_3 && xDiaProp.is() )//for older charts the hidden cells were removed by calc on the fly + xDiaProp->setPropertyValue("IncludeHiddenCells",uno::makeAny(false)); + + // note: mbRowHasLabels means the first row contains labels, that means we have "column-descriptions", + // (analogously mbColHasLabels means we have "row-descriptions") + lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans ); + } + catch(const uno::Exception&) + { + //try to fallback to internal data + SAL_WARN("xmloff.chart", "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram try to fallback to internal data" ); + if(!bHasOwnData) + { + bHasOwnData = true; + msChartAddress = "all"; + if( !xNewDoc->hasInternalDataProvider() ) + { + xNewDoc->createInternalDataProvider( false /* bCloneExistingData */ ); + SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc ); + try + { + lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans ); + } + catch(const uno::Exception&) + { + SAL_WARN("xmloff.chart", "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram fallback to internal data failed also" ); + } + } + } + } + } + } + else + { + SAL_WARN("xmloff.chart", "Must not get here" ); + } + + // now all series and data point properties are available and can be set + { + if( bSpecialHandlingForDonutChart ) + { + uno::Reference< chart2::XDiagram > xNewDiagram( xNewDoc->getFirstDiagram() ); + lcl_swapPointAndSeriesStylesForDonutCharts( maSeriesDefaultsAndStyles.maSeriesStyleVector + , SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram(xNewDiagram) ); + } + + SchXMLSeries2Context::initSeriesPropertySets( maSeriesDefaultsAndStyles, xDoc ); + + //set defaults from diagram to the new series: + //check whether we need to remove lines from symbol only charts + bool bSwitchOffLinesForScatter = false; + { + bool bLinesOn = true; + if( (maSeriesDefaultsAndStyles.maLinesOnProperty >>= bLinesOn) && !bLinesOn ) + { + if( maChartTypeServiceName == "com.sun.star.chart2.ScatterChartType" ) + { + bSwitchOffLinesForScatter = true; + SchXMLSeries2Context::switchSeriesLinesOff( maSeriesDefaultsAndStyles.maSeriesStyleVector ); + } + } + } + SchXMLSeries2Context::setDefaultsToSeries( maSeriesDefaultsAndStyles ); + + // set autostyles for series and data points + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + const SvXMLStyleContext* pStyle = nullptr; + OUString sCurrStyleName; + + if( pStylesCtxt ) + { + //iterate over data-series first + //don't set series styles for donut charts + if( !bSpecialHandlingForDonutChart ) + { + SchXMLSeries2Context::setStylesToSeries( + maSeriesDefaultsAndStyles, pStylesCtxt, pStyle, + sCurrStyleName, mrImportHelper, GetImport(), + mbIsStockChart, maLSequencesPerIndex ); + // ... then set attributes for statistics (after their existence was set in the series) + SchXMLSeries2Context::setStylesToStatisticsObjects( + maSeriesDefaultsAndStyles, pStylesCtxt, + pStyle, sCurrStyleName ); + + SchXMLSeries2Context::setStylesToRegressionCurves( + maSeriesDefaultsAndStyles, pStylesCtxt, + pStyle, sCurrStyleName ); + } + } + + //#i98319# call switchRangesFromOuterToInternalIfNecessary before the data point styles are applied, otherwise in copy->paste scenario the data point styles do get lost + if( bSwitchRangesFromOuterToInternalIfNecessary ) + { + if( xNewDoc->hasInternalDataProvider() ) + SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( maTable, maLSequencesPerIndex, xNewDoc, meDataRowSource ); + } + + if( pStylesCtxt ) + { + // ... then iterate over data-point attributes, so the latter are not overwritten + SchXMLSeries2Context::setStylesToDataPoints( maSeriesDefaultsAndStyles + , pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, bSpecialHandlingForDonutChart, bSwitchOffLinesForScatter ); + } + } + + if( xProp.is()) + xProp->setPropertyValue("RefreshAddInAllowed", uno::makeAny( true) ); +} + +void SchXMLChartContext::MergeSeriesForStockChart() +{ + OSL_ASSERT( mbIsStockChart ); + try + { + uno::Reference< chart::XChartDocument > xOldDoc( mrImportHelper.GetChartDocument()); + uno::Reference< chart2::XChartDocument > xDoc( xOldDoc, uno::UNO_QUERY_THROW ); + uno::Reference< chart2::XDiagram > xDiagram( xDoc->getFirstDiagram()); + if( ! xDiagram.is()) + return; + + bool bHasJapaneseCandlestick = true; + uno::Reference< chart2::XDataSeriesContainer > xDSContainer; + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); + const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + for( const auto& rCooSys : aCooSysSeq ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + auto pChartType = std::find_if(aChartTypes.begin(), aChartTypes.end(), + [](const auto& rChartType) { return rChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType"; }); + if (pChartType != aChartTypes.end()) + { + xDSContainer.set( *pChartType, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xCTProp( *pChartType, uno::UNO_QUERY_THROW ); + xCTProp->getPropertyValue("Japanese") >>= bHasJapaneseCandlestick; + } + } + + if( xDSContainer.is()) + { + // with japanese candlesticks: open, low, high, close + // otherwise: low, high, close + uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDSContainer->getDataSeries()); + const sal_Int32 nSeriesCount( aSeriesSeq.getLength()); + const sal_Int32 nSeriesPerCandleStick = bHasJapaneseCandlestick ? 4: 3; + sal_Int32 nCandleStickCount = nSeriesCount / nSeriesPerCandleStick; + OSL_ASSERT( nSeriesPerCandleStick * nCandleStickCount == nSeriesCount ); + uno::Sequence< uno::Reference< chart2::XDataSeries > > aNewSeries( nCandleStickCount ); + for( sal_Int32 i=0; i( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], "values-min"); + } + else + { + // low values + lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], "values-min"); + aNewSeries[i] = aSeriesSeq[ nSeriesIndex ]; + } + // high values + lcl_MoveDataToCandleStickSeries( + uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], "values-max"); + // close values + lcl_MoveDataToCandleStickSeries( + uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], "values-last"); + } + xDSContainer->setDataSeries( aNewSeries ); + } + } + catch(const uno::Exception&) + { + SAL_WARN("xmloff.chart", "Exception while merging series for stock chart" ); + } +} + +SvXMLImportContextRef SchXMLChartContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + const SvXMLTokenMap& rTokenMap = mrImportHelper.GetChartElemTokenMap(); + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY ); + + switch( rTokenMap.Get( nPrefix, rLocalName )) + { + case XML_TOK_CHART_PLOT_AREA: + pContext = new SchXMLPlotAreaContext( mrImportHelper, GetImport(), rLocalName, + m_aXLinkHRefAttributeToIndicateDataProvider, + msCategoriesAddress, + msChartAddress, m_bHasRangeAtPlotArea, mbAllRangeAddressesAvailable, + mbColHasLabels, mbRowHasLabels, + meDataRowSource, + maSeriesDefaultsAndStyles, + maChartTypeServiceName, + maLSequencesPerIndex, maChartSize ); + break; + + case XML_TOK_CHART_TITLE: + if( xDoc.is()) + { + if( xProp.is()) + { + xProp->setPropertyValue("HasMainTitle", uno::makeAny(true) ); + } + uno::Reference< drawing::XShape > xTitleShape = xDoc->getTitle(); + pContext = new SchXMLTitleContext( mrImportHelper, GetImport(), + rLocalName, maMainTitle, xTitleShape ); + } + break; + + case XML_TOK_CHART_SUBTITLE: + if( xDoc.is()) + { + if( xProp.is()) + { + xProp->setPropertyValue("HasSubTitle", uno::makeAny(true) ); + } + uno::Reference< drawing::XShape > xTitleShape = xDoc->getSubTitle(); + pContext = new SchXMLTitleContext( mrImportHelper, GetImport(), + rLocalName, maSubTitle, xTitleShape ); + } + break; + + case XML_TOK_CHART_LEGEND: + pContext = new SchXMLLegendContext( mrImportHelper, GetImport(), rLocalName ); + break; + + case XML_TOK_CHART_TABLE: + { + SchXMLTableContext * pTableContext = + new SchXMLTableContext( mrImportHelper, GetImport(), rLocalName, maTable ); + m_bHasTableElement = true; + // #i85913# take into account column- and row- mapping for + // charts with own data only for those which were not copied + // from a place where they got data from the container. Note, + // that this requires the plot-area been read before the table + // (which is required in the ODF spec) + // Note: For stock charts and donut charts with special handling + // the mapping must not be applied! + if( msChartAddress.isEmpty() && !mbIsStockChart && + !lcl_SpecialHandlingForDonutChartNeeded( + maChartTypeServiceName, GetImport())) + { + if( !msColTrans.isEmpty() ) + { + OSL_ASSERT( msRowTrans.isEmpty() ); + pTableContext->setColumnPermutation( lcl_getNumberSequenceFromString( msColTrans, true )); + msColTrans.clear(); + } + else if( !msRowTrans.isEmpty() ) + { + pTableContext->setRowPermutation( lcl_getNumberSequenceFromString( msRowTrans, true )); + msRowTrans.clear(); + } + } + pContext = pTableContext; + } + break; + + default: + // try importing as an additional shape + if( ! mxDrawPage.is()) + { + uno::Reference< drawing::XDrawPageSupplier > xSupp( xDoc, uno::UNO_QUERY ); + if( xSupp.is()) + mxDrawPage = xSupp->getDrawPage(); + + SAL_WARN_IF( !mxDrawPage.is(), "xmloff.chart", "Invalid Chart Page" ); + } + if( mxDrawPage.is()) + pContext = GetImport().GetShapeImport()->CreateGroupChildContext( + GetImport(), nPrefix, rLocalName, xAttrList, mxDrawPage ); + break; + } + + return pContext; +} + +/* + With a locked controller the following is done here: + 1. Hide title, subtitle, and legend. + 2. Set the size of the draw page. + 3. Set a (logically) empty data set. + 4. Set the chart type. +*/ +void SchXMLChartContext::InitChart( + const OUString & rChartTypeServiceName // currently the old service name + ) +{ + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + SAL_WARN_IF( !xDoc.is(), "xmloff.chart", "No valid document!" ); + + // Remove Title and Diagram ("De-InitNew") + uno::Reference< chart2::XChartDocument > xNewDoc( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); + if( xNewDoc.is()) + { + xNewDoc->setFirstDiagram( nullptr ); + uno::Reference< chart2::XTitled > xTitled( xNewDoc, uno::UNO_QUERY ); + if( xTitled.is()) + xTitled->setTitleObject( nullptr ); + } + + // Set the chart type via setting the diagram. + if( !rChartTypeServiceName.isEmpty() && xDoc.is()) + { + uno::Reference< lang::XMultiServiceFactory > xFact( xDoc, uno::UNO_QUERY ); + if( xFact.is()) + { + uno::Reference< chart::XDiagram > xDia( xFact->createInstance( rChartTypeServiceName ), uno::UNO_QUERY ); + if( xDia.is()) + xDoc->setDiagram( xDia ); + } + } +} + +SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, + const OUString& rLocalName, + OUString& rTitle, + uno::Reference< drawing::XShape > const & xTitleShape ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImpHelper ), + mrTitle( rTitle ), + mxTitleShape( xTitleShape ) +{ +} + +SchXMLTitleContext::~SchXMLTitleContext() +{} + +void SchXMLTitleContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + + css::awt::Point aPosition; + bool bHasXPosition=false; + bool bHasYPosition=false; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_SVG ) + { + if( IsXMLToken( aLocalName, XML_X ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aPosition.X, aValue ); + bHasXPosition = true; + } + else if( IsXMLToken( aLocalName, XML_Y ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aPosition.Y, aValue ); + bHasYPosition = true; + } + } + else if( nPrefix == XML_NAMESPACE_CHART ) + { + if( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + msAutoStyleName = aValue; + } + } + + if( mxTitleShape.is()) + { + if( bHasXPosition && bHasYPosition ) + mxTitleShape->setPosition( aPosition ); + + uno::Reference xProp(mxTitleShape, uno::UNO_QUERY); + mrImportHelper.FillAutoStyle(msAutoStyleName, xProp); + } +} + +SvXMLImportContextRef SchXMLTitleContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + if( (nPrefix == XML_NAMESPACE_TEXT || + nPrefix == XML_NAMESPACE_LO_EXT) && + IsXMLToken( rLocalName, XML_P ) ) + { + pContext = new SchXMLParagraphContext( GetImport(), rLocalName, mrTitle ); + } + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLChartContext.hxx b/xmloff/source/chart/SchXMLChartContext.hxx new file mode 100644 index 000000000..ae99d92fa --- /dev/null +++ b/xmloff/source/chart/SchXMLChartContext.hxx @@ -0,0 +1,151 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLCHARTCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLCHARTCONTEXT_HXX + +#include +#include +#include +#include + +#include "transporttypes.hxx" + +#include + +class SchXMLImportHelper; + +namespace com::sun::star { + namespace chart { + class XChartDocument; + struct ChartSeriesAddress; + } + namespace xml::sax { + class XAttributeList; + } + namespace drawing { + class XShapes; + } +} + +struct SeriesDefaultsAndStyles +{ + //default values for series: + css::uno::Any maSymbolTypeDefault; + css::uno::Any maDataCaptionDefault; + + css::uno::Any maErrorIndicatorDefault; + css::uno::Any maErrorCategoryDefault; + css::uno::Any maConstantErrorLowDefault; + css::uno::Any maConstantErrorHighDefault; + css::uno::Any maPercentageErrorDefault; + css::uno::Any maErrorMarginDefault; + + css::uno::Any maMeanValueDefault; + css::uno::Any maRegressionCurvesDefault; + + css::uno::Any maStackedDefault; + css::uno::Any maPercentDefault; + css::uno::Any maDeepDefault; + css::uno::Any maStackedBarsConnectedDefault; + + //additional information + css::uno::Any maLinesOnProperty; + + //styles for series and datapoints + ::std::vector< DataRowPointStyle > maSeriesStyleVector; + ::std::vector< RegressionStyle > maRegressionStyleVector; +}; + +class SchXMLChartContext : public SvXMLImportContext +{ +public: + SchXMLChartContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName ); + virtual ~SchXMLChartContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + SchXMLTable maTable; + SchXMLImportHelper& mrImportHelper; + + OUString maMainTitle, maSubTitle; + OUString m_aXLinkHRefAttributeToIndicateDataProvider; + bool m_bHasRangeAtPlotArea; + bool m_bHasTableElement; + bool mbAllRangeAddressesAvailable; + bool mbColHasLabels; + bool mbRowHasLabels; + css::chart::ChartDataRowSource meDataRowSource; + bool mbIsStockChart; + + OUString msCategoriesAddress; + OUString msChartAddress; + + OUString msDataPilotSource; + + SeriesDefaultsAndStyles maSeriesDefaultsAndStyles; + tSchXMLLSequencesPerIndex maLSequencesPerIndex; + + css::uno::Reference< css::drawing::XShapes > mxDrawPage; + OUString msColTrans; + OUString msRowTrans; + OUString maChartTypeServiceName; + + css::awt::Size maChartSize; + + /** @descr This method bundles some settings to the chart model and executes them with + a locked controller. This includes setting the chart type. + @param aServiceName The name of the service the diagram is initialized with. + */ + void InitChart (const OUString & rChartTypeServiceName); + + void MergeSeriesForStockChart(); +}; + +class SchXMLTitleContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + OUString& mrTitle; + css::uno::Reference< css::drawing::XShape > mxTitleShape; + OUString msAutoStyleName; + +public: + SchXMLTitleContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + OUString& rTitle, + css::uno::Reference< css::drawing::XShape > const & xTitleShape ); + virtual ~SchXMLTitleContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLCHARTCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLEnumConverter.cxx b/xmloff/source/chart/SchXMLEnumConverter.cxx new file mode 100644 index 000000000..6349b4577 --- /dev/null +++ b/xmloff/source/chart/SchXMLEnumConverter.cxx @@ -0,0 +1,83 @@ +/* -*- 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 +#include +#include "SchXMLEnumConverter.hxx" +#include +#include + +using namespace ::xmloff::token; +using namespace ::com::sun::star; + +namespace +{ + +const SvXMLEnumMapEntry aXMLLegendPositionEnumMap[] = +{ + { XML_START, chart::ChartLegendPosition_LEFT }, + { XML_TOP, chart::ChartLegendPosition_TOP }, + { XML_END, chart::ChartLegendPosition_RIGHT }, + { XML_BOTTOM, chart::ChartLegendPosition_BOTTOM }, + { XML_TOKEN_INVALID, chart::ChartLegendPosition(0) } +}; + +class XMLLegendPositionPropertyHdl : public XMLEnumPropertyHdl +{ +public: + XMLLegendPositionPropertyHdl() + : XMLEnumPropertyHdl( aXMLLegendPositionEnumMap) {} +}; + +struct TheLegendPositionPropertyHdl : public rtl::Static< XMLLegendPositionPropertyHdl, TheLegendPositionPropertyHdl > +{ +}; + +const SvXMLEnumMapEntry aXMLLegendExpansionEnumMap[] = +{ + { XML_WIDE, chart::ChartLegendExpansion_WIDE }, + { XML_HIGH, chart::ChartLegendExpansion_HIGH }, + { XML_BALANCED, chart::ChartLegendExpansion_BALANCED }, + { XML_CUSTOM, chart::ChartLegendExpansion_CUSTOM }, + { XML_TOKEN_INVALID, chart::ChartLegendExpansion(0) } +}; + +class XMLLegendExpansionPropertyHdl : public XMLEnumPropertyHdl +{ +public: + XMLLegendExpansionPropertyHdl() + : XMLEnumPropertyHdl( aXMLLegendExpansionEnumMap) {} +}; + +struct TheLegendExpansionPropertyHdl : public rtl::Static< XMLLegendExpansionPropertyHdl, TheLegendExpansionPropertyHdl > +{ +}; + +}//end anonymous namespace + +XMLEnumPropertyHdl& SchXMLEnumConverter::getLegendPositionConverter() +{ + return TheLegendPositionPropertyHdl::get(); +} +XMLEnumPropertyHdl& SchXMLEnumConverter::getLegendExpansionConverter() +{ + return TheLegendExpansionPropertyHdl::get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLEnumConverter.hxx b/xmloff/source/chart/SchXMLEnumConverter.hxx new file mode 100644 index 000000000..b3a5e79c6 --- /dev/null +++ b/xmloff/source/chart/SchXMLEnumConverter.hxx @@ -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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLENUMCONVERTER_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLENUMCONVERTER_HXX + +#include + +class SchXMLEnumConverter +{ +public: + static XMLEnumPropertyHdl& getLegendPositionConverter();//returns a singleton + static XMLEnumPropertyHdl& getLegendExpansionConverter();//returns a singleton +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLENUMCONVERTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx new file mode 100644 index 000000000..6ddc083b5 --- /dev/null +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -0,0 +1,3852 @@ +/* -*- 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 +#include +#include + +#include + +#include + +#include +#include +#include "ColorPropertySet.hxx" +#include "SchXMLTools.hxx" +#include "SchXMLEnumConverter.hxx" +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "MultiPropertySetHandler.hxx" +#include "PropertyMap.hxx" + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::std::vector; + + +namespace +{ + using CustomLabelSeq = Sequence>; + + struct SchXMLDataPointStruct + { + OUString maStyleName; + sal_Int32 mnRepeat; + CustomLabelSeq mCustomLabelText; + chart2::RelativePosition mCustomLabelPos; + + SchXMLDataPointStruct() : mnRepeat( 1 ) {} + }; +} + + +class SchXMLExportHelper_Impl +{ +public: + // first: data sequence for label, second: data sequence for values. + typedef ::std::pair< css::uno::Reference< css::chart2::data::XDataSequence >, + css::uno::Reference< css::chart2::data::XDataSequence > > tLabelValuesDataPair; + typedef ::std::vector< tLabelValuesDataPair > tDataSequenceCont; + +public: + SchXMLExportHelper_Impl( SvXMLExport& rExport, + SvXMLAutoStylePoolP& rASPool ); + + SchXMLExportHelper_Impl(const SchXMLExportHelper_Impl&) = delete; + SchXMLExportHelper_Impl& operator=(const SchXMLExportHelper_Impl&) = delete; + + // auto-styles + /// parse chart and collect all auto-styles used in current pool + void collectAutoStyles( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc ); + + /// write the styles collected into the current pool as elements + void exportAutoStyles(); + + /** export the element corresponding to rChartDoc + if bIncludeTable is true, the chart data is exported as + element (inside the chart element). + + Otherwise the external references stored in the chart document are used + for writing the corresponding attributes at series + + All attributes contained in xAttrList are written at the chart element, + which is the outer element of a chart. So these attributes can easily + be parsed again by the container + */ + void exportChart( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc, + bool bIncludeTable ); + + const rtl::Reference& GetPropertySetMapper() const; + + void SetChartRangeAddress( const OUString& rAddress ) + { msChartAddress = rAddress; } + + void InitRangeSegmentationProperties( + const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc ); + + static css::awt::Size getPageSize( + const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc ); + + /** first parseDocument: collect autostyles and store names in this queue + second parseDocument: export content and use names from this queue + */ + ::std::queue< OUString > maAutoStyleNameQueue; + void CollectAutoStyle( + const std::vector< XMLPropertyState >& aStates ); + void AddAutoStyleAttribute( + const std::vector< XMLPropertyState >& aStates ); + + /// if bExportContent is false the auto-styles are collected + void parseDocument( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc, + bool bExportContent, + bool bIncludeTable = false ); + void exportTable(); + void exportPlotArea( + const css::uno::Reference< css::chart::XDiagram >& xDiagram, + const css::uno::Reference< css::chart2::XDiagram >& xNewDiagram, + const css::awt::Size & rPageSize, + bool bExportContent, + bool bIncludeTable ); + void exportCoordinateRegion( const css::uno::Reference< css::chart::XDiagram >& xDiagram ); + void exportAxes( const css::uno::Reference< css::chart::XDiagram > & xDiagram, + const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram, + bool bExportContent ); + void exportAxis( enum XMLTokenEnum eDimension, enum XMLTokenEnum eAxisName, + const Reference< beans::XPropertySet >& rAxisProps, const Reference< chart2::XAxis >& rChart2Axis, + const OUString& rCategoriesRanges, + bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid, bool bExportContent, OUString sChartType ); + void exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent ); + void exportDateScale( const Reference< beans::XPropertySet >& rAxisProps ); + void exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent ); + + void exportSeries( + const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram, + const css::awt::Size & rPageSize, + bool bExportContent, + bool bHasTwoYAxes ); + + void exportPropertyMapping( + const css::uno::Reference< css::chart2::data::XDataSource > & xSource, + const Sequence< OUString >& rSupportedMappings ); + + void exportCandleStickSeries( + const css::uno::Sequence< + css::uno::Reference< css::chart2::XDataSeries > > & aSeriesSeq, + const css::uno::Reference< css::chart2::XDiagram > & xDiagram, + bool bJapaneseCandleSticks, + bool bExportContent ); + void exportDataPoints( + const css::uno::Reference< css::beans::XPropertySet > & xSeriesProperties, + sal_Int32 nSeriesLength, + const css::uno::Reference< css::chart2::XDiagram > & xDiagram, + bool bExportContent ); + + void exportCustomLabel(const CustomLabelSeq & xCustomLabel); + void exportCustomLabelPosition(const chart2::RelativePosition & xCustomLabelPosition); + + void exportRegressionCurve( + const css::uno::Reference& xSeries, + const css::awt::Size& rPageSize, + bool bExportContent ); + + void exportErrorBar ( + const css::uno::Reference &xSeriesProp, bool bYError, + bool bExportContent ); + + /// add svg position as attribute for current element + void addPosition( const css::awt::Point & rPosition ); + void addPosition( const css::uno::Reference< css::drawing::XShape >& xShape ); + /// add svg size as attribute for current element + void addSize( const css::awt::Size & rSize, bool bIsOOoNamespace = false ); + void addSize( const css::uno::Reference< css::drawing::XShape >& xShape ); + /// exports a string as a paragraph element + void exportText( const OUString& rText ); + +public: + SvXMLExport& mrExport; + SvXMLAutoStylePoolP& mrAutoStylePool; + rtl::Reference< XMLPropertySetMapper > mxPropertySetMapper; + rtl::Reference< XMLChartExportPropertyMapper > mxExpPropMapper; + + static constexpr OUStringLiteral gsTableName = "local-table"; + OUStringBuffer msStringBuffer; + OUString msString; + + // members filled by InitRangeSegmentationProperties (retrieved from DataProvider) + bool mbHasCategoryLabels; //if the categories are only automatically generated this will be false + bool mbRowSourceColumns; + OUString msChartAddress; + css::uno::Sequence< sal_Int32 > maSequenceMapping; + + OUString msCLSID; + + OUString maSrcShellID; + OUString maDestShellID; + + css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes; + + tDataSequenceCont m_aDataSequencesToExport; + OUString maCategoriesRange; +}; + +namespace +{ + +CustomLabelSeq lcl_getCustomLabelField(sal_Int32 nDataPointIndex, + const uno::Reference< chart2::XDataSeries >& rSeries) +{ + if( !rSeries.is() ) + return CustomLabelSeq(); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if ((nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) == 0) // do not export to ODF 1.3 or older + return CustomLabelSeq(); + + if(Reference xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is()) + { + if(Any aAny = xLabels->getPropertyValue("CustomLabelFields"); aAny.hasValue()) + { + Sequence> aCustomLabels; + aAny >>= aCustomLabels; + return aCustomLabels; + } + } + return CustomLabelSeq(); +} + +css::chart2::RelativePosition lcl_getCustomLabelPosition(sal_Int32 nDataPointIndex, + const uno::Reference< chart2::XDataSeries >& rSeries) +{ + if (!rSeries.is()) + return chart2::RelativePosition(); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if ((nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) == 0) // do not export to ODF 1.3 or older + return chart2::RelativePosition(); + + if (Reference xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is()) + { + if (Any aAny = xLabels->getPropertyValue("CustomLabelPosition"); aAny.hasValue()) + { + chart2::RelativePosition aCustomLabelPos; + aAny >>= aCustomLabelPos; + return aCustomLabelPos; + } + } + return chart2::RelativePosition(); +} + +class lcl_MatchesRole +{ +public: + explicit lcl_MatchesRole( const OUString & aRole ) : + m_aRole( aRole ) + {} + + bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const + { + if( !xSeq.is() ) + return false; + Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY ); + OUString aRole; + + return ( xProp.is() && + (xProp->getPropertyValue( "Role" ) >>= aRole ) && + m_aRole == aRole ); + } + +private: + OUString m_aRole; +}; + +template< typename T > + void lcl_SequenceToVectorAppend( const Sequence< T > & rSource, ::std::vector< T > & rDestination ) +{ + rDestination.reserve( rDestination.size() + rSource.getLength()); + ::std::copy( rSource.begin(), rSource.end(), + ::std::back_inserter( rDestination )); +} + +template< typename T > + void lcl_SequenceToVector( const Sequence< T > & rSource, ::std::vector< T > & rDestination ) +{ + rDestination.clear(); + lcl_SequenceToVectorAppend( rSource, rDestination ); +} + +Reference< chart2::data::XLabeledDataSequence > lcl_getCategories( const Reference< chart2::XDiagram > & xDiagram ) +{ + Reference< chart2::data::XLabeledDataSequence > xResult; + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDiagram, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XCoordinateSystem > xCooSys( rCooSys ); + SAL_WARN_IF( !xCooSys.is(), "xmloff.chart", "xCooSys is NULL" ); + for( sal_Int32 nN = xCooSys->getDimension(); nN--; ) + { + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN); + for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI) + { + Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI ); + SAL_WARN_IF( !xAxis.is(), "xmloff.chart", "xAxis is NULL"); + if( xAxis.is()) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + if( aScaleData.Categories.is()) + { + xResult.set( aScaleData.Categories ); + break; + } + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + + return xResult; +} + +Reference< chart2::data::XDataSource > lcl_createDataSource( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aData ) +{ + Reference< uno::XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + Reference< chart2::data::XDataSink > xSink( + xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.chart2.data.DataSource", xContext ), + uno::UNO_QUERY_THROW ); + xSink->setData( aData ); + + return Reference< chart2::data::XDataSource >( xSink, uno::UNO_QUERY ); +} + +Sequence< Reference< chart2::data::XLabeledDataSequence > > lcl_getAllSeriesSequences( const Reference< chart2::XChartDocument >& xChartDoc ) +{ + ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aContainer; + if( xChartDoc.is() ) + { + Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram()); + ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram )); + for( const auto& rSeries : aSeriesVector ) + { + Reference< chart2::data::XDataSource > xDataSource( rSeries, uno::UNO_QUERY ); + if( !xDataSource.is() ) + continue; + uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aDataSequences( xDataSource->getDataSequences() ); + lcl_SequenceToVectorAppend( aDataSequences, aContainer ); + } + } + + return comphelper::containerToSequence( aContainer ); +} + +Reference< chart2::data::XLabeledDataSequence > + lcl_getDataSequenceByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aLabeledSeq, + const OUString & rRole ) +{ + Reference< chart2::data::XLabeledDataSequence > aNoResult; + + const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray(); + const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength(); + const Reference< chart2::data::XLabeledDataSequence > * pMatch = + ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole )); + + if( pMatch != pEnd ) + return *pMatch; + + return aNoResult; +} + +Reference< chart2::data::XDataSource > lcl_pressUsedDataIntoRectangularFormat( const Reference< chart2::XChartDocument >& xChartDoc, bool& rOutSourceHasCategoryLabels ) +{ + ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeqVector; + + //categories are always the first sequence + Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram()); + Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xDiagram ) ); + if( xCategories.is() ) + aLabeledSeqVector.push_back( xCategories ); + rOutSourceHasCategoryLabels = xCategories.is(); + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeriesSeqVector( + lcl_getAllSeriesSequences( xChartDoc ) ); + + //the first x-values is always the next sequence //todo ... other x-values get lost for old format + Reference< chart2::data::XLabeledDataSequence > xXValues( + lcl_getDataSequenceByRole( aSeriesSeqVector, "values-x" ) ); + if( xXValues.is() ) + aLabeledSeqVector.push_back( xXValues ); + + //add all other sequences now without x-values + lcl_MatchesRole aHasXValues( "values-x" ); + std::copy_if(aSeriesSeqVector.begin(), aSeriesSeqVector.end(), std::back_inserter(aLabeledSeqVector), + [&aHasXValues](const auto& rSeriesSeq) { return !aHasXValues( rSeriesSeq ); }); + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( comphelper::containerToSequence(aLabeledSeqVector) ); + + return lcl_createDataSource( aSeq ); +} + +bool lcl_isSeriesAttachedToFirstAxis( + const Reference< chart2::XDataSeries > & xDataSeries ) +{ + bool bResult=true; + + try + { + sal_Int32 nAxisIndex = 0; + Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW ); + xProp->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex; + bResult = (0==nAxisIndex); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + + return bResult; +} + +OUString lcl_ConvertRange( const OUString & rRange, const Reference< chart2::XChartDocument > & xDoc ) +{ + OUString aResult = rRange; + if( !xDoc.is() ) + return aResult; + Reference< chart2::data::XRangeXMLConversion > xConversion( + xDoc->getDataProvider(), uno::UNO_QUERY ); + if( xConversion.is()) + aResult = xConversion->convertRangeToXML( rRange ); + return aResult; +} + +typedef ::std::pair< OUString, OUString > tLabelAndValueRange; + +tLabelAndValueRange lcl_getLabelAndValueRangeByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt, + const OUString & rRole, + const Reference< chart2::XChartDocument > & xDoc, + SchXMLExportHelper_Impl::tDataSequenceCont & rOutSequencesToExport ) +{ + tLabelAndValueRange aResult; + + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + lcl_getDataSequenceByRole( aSeqCnt, rRole )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel()); + if( xLabelSeq.is()) + aResult.first = lcl_ConvertRange( xLabelSeq->getSourceRangeRepresentation(), xDoc ); + + Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues()); + if( xValueSeq.is()) + aResult.second = lcl_ConvertRange( xValueSeq->getSourceRangeRepresentation(), xDoc ); + + if( xLabelSeq.is() || xValueSeq.is()) + rOutSequencesToExport.emplace_back( xLabelSeq, xValueSeq ); + } + + return aResult; +} + +sal_Int32 lcl_getSequenceLengthByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt, + const OUString & rRole ) +{ + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + lcl_getDataSequenceByRole( aSeqCnt, rRole )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getValues()); + return xSeq->getData().getLength(); + } + return 0; +} + +OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence ) +{ + OUStringBuffer aResult; + bool bPrecedeWithSpace = false; + for( const auto& rString : rSequence ) + { + if( !rString.isEmpty()) + { + if( bPrecedeWithSpace ) + aResult.append( ' ' ); + aResult.append( rString ); + bPrecedeWithSpace = true; + } + } + return aResult.makeStringAndClear(); +} + +void lcl_getLabelStringSequence( Sequence< OUString >& rOutLabels, const Reference< chart2::data::XDataSequence > & xLabelSeq ) +{ + uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY ); + if( xTextualDataSequence.is()) + { + rOutLabels = xTextualDataSequence->getTextualData(); + } + else if( xLabelSeq.is()) + { + Sequence< uno::Any > aAnies( xLabelSeq->getData()); + rOutLabels.realloc( aAnies.getLength()); + for( sal_Int32 i=0; i>= rOutLabels[i]; + } +} + +sal_Int32 lcl_getMaxSequenceLength( + const SchXMLExportHelper_Impl::tDataSequenceCont & rContainer ) +{ + sal_Int32 nResult = 0; + for( const auto& rDataSequence : rContainer ) + { + if( rDataSequence.second.is()) + { + sal_Int32 nSeqLength = rDataSequence.second->getData().getLength(); + if( nSeqLength > nResult ) + nResult = nSeqLength; + } + } + return nResult; +} + +uno::Sequence< OUString > lcl_DataSequenceToStringSequence( + const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) +{ + uno::Sequence< OUString > aResult; + if(!xDataSequence.is()) + return aResult; + + uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY ); + if( xTextualDataSequence.is() ) + { + aResult = xTextualDataSequence->getTextualData(); + } + else + { + uno::Sequence< uno::Any > aValues = xDataSequence->getData(); + aResult.realloc(aValues.getLength()); + + for(sal_Int32 nN=aValues.getLength();nN--;) + aValues[nN] >>= aResult[nN]; + } + + return aResult; +} +::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq ) +{ + double fNan = 0.0; + ::rtl::math::setNan( &fNan ); + ::std::vector< double > aResult; + if(!xSeq.is()) + return aResult; + + uno::Sequence< double > aValuesSequence; + Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY ); + if( xNumSeq.is() ) + { + aValuesSequence = xNumSeq->getNumericalData(); + } + else + { + Sequence< uno::Any > aAnies( xSeq->getData() ); + aValuesSequence.realloc( aAnies.getLength() ); + for( sal_Int32 i=0; i>= aValuesSequence[i]; + } + + //special handling for x-values (if x-values do point to categories, indices are used instead ) + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY ); + if( xProp.is() ) + { + OUString aRole; + xProp->getPropertyValue("Role") >>= aRole; + if( aRole.match("values-x") ) + { + //lcl_clearIfNoValuesButTextIsContained - replace by indices if the values are not appropriate + bool bHasValue = std::any_of(aValuesSequence.begin(), aValuesSequence.end(), + [](double fValue) { return !std::isnan( fValue ); }); + if(!bHasValue) + { + //no double value is contained + //is there any text? + uno::Sequence< OUString > aStrings( lcl_DataSequenceToStringSequence( xSeq ) ); + bool bHasText = std::any_of(aStrings.begin(), aStrings.end(), + [](const OUString& rString) { return !rString.isEmpty(); }); + if( bHasText ) + { + std::iota(aValuesSequence.begin(), aValuesSequence.end(), 1); + } + } + } + } + + ::std::copy( aValuesSequence.begin(), aValuesSequence.end(), + ::std::back_inserter( aResult )); + return aResult; +} + +bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) +{ + if( !xDataSequence.is() ) + return false; + uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY ); + if( xProp.is() ) + { + uno::Sequence< sal_Int32 > aHiddenValues; + try + { + xProp->getPropertyValue("HiddenValues") >>= aHiddenValues; + if( !aHiddenValues.hasElements() ) + return true; + } + catch( const uno::Exception& ) + { + return true; + } + } + return xDataSequence->getData().hasElements(); +} + +typedef vector< OUString > tStringVector; +typedef vector< vector< double > > t2DNumberContainer; + +struct lcl_TableData +{ + t2DNumberContainer aDataInRows; + tStringVector aDataRangeRepresentations; + + tStringVector aColumnDescriptions; + tStringVector aColumnDescriptions_Ranges; + + tStringVector aRowDescriptions; + tStringVector aRowDescriptions_Ranges; + + Sequence< Sequence< uno::Any > > aComplexColumnDescriptions;//outer index is columns - inner index is level + Sequence< Sequence< uno::Any > > aComplexRowDescriptions;//outer index is rows - inner index is level + + ::std::vector< sal_Int32 > aHiddenColumns; +}; + +typedef ::std::map< sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair > + lcl_DataSequenceMap; + +struct lcl_SequenceToMapElement +{ + std::pair + operator() (const SchXMLExportHelper_Impl::tLabelValuesDataPair& rContent) + { + sal_Int32 nIndex = -1; + if( rContent.second.is()) //has values + { + OUString aRangeRep( rContent.second->getSourceRangeRepresentation()); + nIndex = aRangeRep.toInt32(); + } + else if( rContent.first.is()) //has labels + nIndex = rContent.first->getSourceRangeRepresentation().copy( sizeof("label ")).toInt32(); + return std::make_pair(nIndex, rContent); + } +}; + +void lcl_ReorderInternalSequencesAccordingToTheirRangeName( + SchXMLExportHelper_Impl::tDataSequenceCont & rInOutSequences ) +{ + lcl_DataSequenceMap aIndexSequenceMap; + ::std::transform( rInOutSequences.begin(), rInOutSequences.end(), + ::std::inserter( aIndexSequenceMap, aIndexSequenceMap.begin()), + lcl_SequenceToMapElement()); + + rInOutSequences.clear(); + sal_Int32 nIndex = 0; + for( const auto& rEntry : aIndexSequenceMap ) + { + if( rEntry.first >= 0 ) + { + // fill empty columns + rInOutSequences.insert( + rInOutSequences.end(), + rEntry.first - nIndex, + SchXMLExportHelper_Impl::tDataSequenceCont::value_type( + uno::Reference< chart2::data::XDataSequence >(), + uno::Reference< chart2::data::XDataSequence >() )); + nIndex = rEntry.first; + rInOutSequences.push_back( rEntry.second ); + } + + ++nIndex; + } +} + +lcl_TableData lcl_getDataForLocalTable( + const SchXMLExportHelper_Impl::tDataSequenceCont & aSequencesToExport, + const Reference< chart2::XAnyDescriptionAccess >& xAnyDescriptionAccess, + const OUString& rCategoriesRange, + bool bSeriesFromColumns, + const Reference< chart2::data::XRangeXMLConversion > & xRangeConversion ) +{ + lcl_TableData aResult; + + try + { + Sequence< OUString > aSimpleCategories; + if( xAnyDescriptionAccess.is() ) + { + //categories + if( bSeriesFromColumns ) + { + aSimpleCategories = xAnyDescriptionAccess->getRowDescriptions(); + aResult.aComplexRowDescriptions = xAnyDescriptionAccess->getAnyRowDescriptions(); + } + else + { + aSimpleCategories = xAnyDescriptionAccess->getColumnDescriptions(); + aResult.aComplexColumnDescriptions = xAnyDescriptionAccess->getAnyColumnDescriptions(); + } + } + + //series values and series labels + SchXMLExportHelper_Impl::tDataSequenceCont::size_type nNumSequences = aSequencesToExport.size(); + + auto nMaxSequenceLength( lcl_getMaxSequenceLength( aSequencesToExport )); + if( aSimpleCategories.getLength() > nMaxSequenceLength ) + { + aSimpleCategories.realloc(nMaxSequenceLength);//#i110617# + } + size_t nNumColumns( bSeriesFromColumns ? nNumSequences : nMaxSequenceLength ); + size_t nNumRows( bSeriesFromColumns ? nMaxSequenceLength : nNumSequences ); + + // resize data + aResult.aDataInRows.resize( nNumRows ); + double fNan = 0.0; + ::rtl::math::setNan( &fNan ); + + for (auto& aData: aResult.aDataInRows) + aData.resize(nNumColumns, fNan); + aResult.aColumnDescriptions.resize( nNumColumns ); + aResult.aComplexColumnDescriptions.realloc( nNumColumns ); + aResult.aRowDescriptions.resize( nNumRows ); + aResult.aComplexRowDescriptions.realloc( nNumRows ); + + tStringVector& rCategories = bSeriesFromColumns ? aResult.aRowDescriptions : aResult.aColumnDescriptions; + tStringVector& rLabels = bSeriesFromColumns ? aResult.aColumnDescriptions : aResult.aRowDescriptions; + + //categories + lcl_SequenceToVector( aSimpleCategories, rCategories ); + if( !rCategoriesRange.isEmpty() ) + { + OUString aRange(rCategoriesRange); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + if( bSeriesFromColumns ) + aResult.aRowDescriptions_Ranges.push_back( aRange ); + else + aResult.aColumnDescriptions_Ranges.push_back( aRange ); + } + + // iterate over all sequences + size_t nSeqIdx = 0; + Sequence< Sequence< OUString > > aComplexLabels(nNumSequences); + for( const auto& rDataSequence : aSequencesToExport ) + { + OUString aRange; + Sequence< OUString >& rCurrentComplexLabel = aComplexLabels[nSeqIdx]; + if( rDataSequence.first.is()) + { + lcl_getLabelStringSequence( rCurrentComplexLabel, rDataSequence.first ); + rLabels[nSeqIdx] = lcl_flattenStringSequence( rCurrentComplexLabel ); + aRange = rDataSequence.first->getSourceRangeRepresentation(); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + } + else if( rDataSequence.second.is()) + { + rCurrentComplexLabel.realloc(1); + rLabels[nSeqIdx] = rCurrentComplexLabel[0] = lcl_flattenStringSequence( + rDataSequence.second->generateLabel( chart2::data::LabelOrigin_SHORT_SIDE )); + } + if( bSeriesFromColumns ) + aResult.aColumnDescriptions_Ranges.push_back( aRange ); + else + aResult.aRowDescriptions_Ranges.push_back( aRange ); + + ::std::vector< double > aNumbers( lcl_getAllValuesFromSequence( rDataSequence.second )); + if( bSeriesFromColumns ) + { + const sal_Int32 nSize( static_cast< sal_Int32 >( aNumbers.size())); + for( sal_Int32 nIdx=0; nIdxgetSourceRangeRepresentation(); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + } + aResult.aDataRangeRepresentations.push_back( aRange ); + + //is column hidden? + if( !lcl_SequenceHasUnhiddenData(rDataSequence.first) && !lcl_SequenceHasUnhiddenData(rDataSequence.second) ) + aResult.aHiddenColumns.push_back(nSeqIdx); + + ++nSeqIdx; + } + Sequence< Sequence< Any > >& rComplexAnyLabels = bSeriesFromColumns ? aResult.aComplexColumnDescriptions : aResult.aComplexRowDescriptions;//#i116544# + rComplexAnyLabels.realloc(aComplexLabels.getLength()); + for( sal_Int32 nN=0; nN& rSource = aComplexLabels[nN]; + Sequence< Any >& rTarget = rComplexAnyLabels[nN]; + rTarget.realloc( rSource.getLength() ); + for( sal_Int32 i=0; i& xPropSet, + SvXMLExport& rExport ) +{ + if( xPropSet.is()) + { + sal_Int32 nNumberFormat = 0; + Any aNumAny = xPropSet->getPropertyValue( rPropertyName ); + if( (aNumAny >>= nNumberFormat) && (nNumberFormat != -1) ) + rExport.addDataStyle( nNumberFormat ); + } +} + +::std::vector< Reference< chart2::data::XDataSequence > > + lcl_getErrorBarSequences( const Reference< beans::XPropertySet > & xErrorBarProp ) +{ + ::std::vector< Reference< chart2::data::XDataSequence > > aResult; + Reference< chart2::data::XDataSource > xErrorBarDataSource( xErrorBarProp, uno::UNO_QUERY ); + if( !xErrorBarDataSource.is()) + return aResult; + + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( + xErrorBarDataSource->getDataSequences()); + for( const auto& rSequence : aSequences ) + { + try + { + if( rSequence.is()) + { + Reference< chart2::data::XDataSequence > xSequence( rSequence->getValues()); + Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW ); + OUString aRole; + if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) && + aRole.match( "error-bars-" )) + { + aResult.push_back( xSequence ); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exporting error bar ranges" ); + } + } + + return aResult; +} + +bool lcl_exportDomainForThisSequence( const Reference< chart2::data::XDataSequence >& rValues, OUString& rFirstRangeForThisDomainIndex, SvXMLExport& rExport ) +{ + bool bDomainExported = false; + if( rValues.is()) + { + Reference< chart2::XChartDocument > xNewDoc( rExport.GetModel(), uno::UNO_QUERY ); + OUString aRange( lcl_ConvertRange( rValues->getSourceRangeRepresentation(), xNewDoc ) ); + + //work around error in OOo 2.0 (problems with multiple series having a domain element) + if( rFirstRangeForThisDomainIndex.isEmpty() || aRange != rFirstRangeForThisDomainIndex ) + { + rExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, aRange); + SvXMLElementExport aDomain( rExport, XML_NAMESPACE_CHART, XML_DOMAIN, true, true ); + bDomainExported = true; + } + + if( rFirstRangeForThisDomainIndex.isEmpty() ) + rFirstRangeForThisDomainIndex = aRange; + } + return bDomainExported; +} + +} // anonymous namespace + + +SchXMLExportHelper::SchXMLExportHelper( SvXMLExport& rExport, SvXMLAutoStylePoolP& rASPool ) + : m_pImpl( new SchXMLExportHelper_Impl( rExport, rASPool ) ) +{ +} + +SchXMLExportHelper::~SchXMLExportHelper() +{ +} + +const OUString& SchXMLExportHelper::getChartCLSID() const +{ + return m_pImpl->msCLSID; +} + +void SchXMLExportHelper::SetSourceShellID( const OUString& rShellID ) +{ + m_pImpl->maSrcShellID = rShellID; +} + +void SchXMLExportHelper::SetDestinationShellID( const OUString& rShellID ) +{ + m_pImpl->maDestShellID = rShellID; +} + +const rtl::Reference< XMLPropertySetMapper >& SchXMLExportHelper_Impl::GetPropertySetMapper() const +{ + return mxPropertySetMapper; +} + +void SchXMLExportHelper_Impl::exportAutoStyles() +{ + if( mxExpPropMapper.is()) + { + //ToDo: when embedded in calc/writer this is not necessary because the + // numberformatter is shared between both documents + mrExport.exportAutoDataStyles(); + + // export chart auto styles + mrAutoStylePool.exportXML( XmlStyleFamily::SCH_CHART_ID ); + + // export auto styles for additional shapes + mrExport.GetShapeExport()->exportAutoStyles(); + // and for text in additional shapes + mrExport.GetTextParagraphExport()->exportTextAutoStyles(); + } +} + +// private methods + +SchXMLExportHelper_Impl::SchXMLExportHelper_Impl( + SvXMLExport& rExport, + SvXMLAutoStylePoolP& rASPool ) : + mrExport( rExport ), + mrAutoStylePool( rASPool ), + mxPropertySetMapper( new XMLChartPropertySetMapper(&rExport) ), + mxExpPropMapper( new XMLChartExportPropertyMapper( mxPropertySetMapper, rExport ) ), + mbHasCategoryLabels( false ), + mbRowSourceColumns( true ), + msCLSID( SvGlobalName( SO3_SCH_CLASSID ).GetHexName() ) +{ + // register chart auto-style family + mrAutoStylePool.AddFamily( + XmlStyleFamily::SCH_CHART_ID, + OUString( XML_STYLE_FAMILY_SCH_CHART_NAME ), + mxExpPropMapper.get(), + OUString( XML_STYLE_FAMILY_SCH_CHART_PREFIX )); + + // register shape family + mrAutoStylePool.AddFamily( + XmlStyleFamily::SD_GRAPHICS_ID, + OUString( XML_STYLE_FAMILY_SD_GRAPHICS_NAME ), + mxExpPropMapper.get(), + OUString( XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX )); + // register paragraph family also for shapes + mrAutoStylePool.AddFamily( + XmlStyleFamily::TEXT_PARAGRAPH, + GetXMLToken( XML_PARAGRAPH ), + mxExpPropMapper.get(), + OUString( 'P' )); + // register text family also for shapes + mrAutoStylePool.AddFamily( + XmlStyleFamily::TEXT_TEXT, + GetXMLToken( XML_TEXT ), + mxExpPropMapper.get(), + OUString( 'T' )); +} + +void SchXMLExportHelper_Impl::collectAutoStyles( Reference< chart::XChartDocument > const & rChartDoc ) +{ + parseDocument( rChartDoc, false ); +} + +void SchXMLExportHelper_Impl::exportChart( Reference< chart::XChartDocument > const & rChartDoc, + bool bIncludeTable ) +{ + parseDocument( rChartDoc, true, bIncludeTable ); + SAL_WARN_IF( !maAutoStyleNameQueue.empty(), "xmloff.chart", "There are still remaining autostyle names in the queue" ); +} + +static OUString lcl_GetStringFromNumberSequence( const css::uno::Sequence< sal_Int32 >& rSequenceMapping, bool bRemoveOneFromEachIndex /*should be true if having categories*/ ) +{ + OUStringBuffer aBuf; + bool bHasPredecessor = false; + for( sal_Int32 nIndex : rSequenceMapping ) + { + if( bRemoveOneFromEachIndex ) + --nIndex; + if(nIndex>=0) + { + if(bHasPredecessor) + aBuf.append( ' ' ); + aBuf.append( nIndex ); + bHasPredecessor = true; + } + } + return aBuf.makeStringAndClear(); +} + +/// if bExportContent is false the auto-styles are collected +void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > const & rChartDoc, + bool bExportContent, + bool bIncludeTable ) +{ + Reference< chart2::XChartDocument > xNewDoc( rChartDoc, uno::UNO_QUERY ); + if( !rChartDoc.is() || !xNewDoc.is() ) + { + SAL_WARN("xmloff.chart", "No XChartDocument was given for export." ); + return; + } + + mxExpPropMapper->setChartDoc(xNewDoc); + + awt::Size aPageSize( getPageSize( xNewDoc )); + if( bExportContent ) + addSize( aPageSize ); + Reference< chart::XDiagram > xDiagram = rChartDoc->getDiagram(); + Reference< chart2::XDiagram > xNewDiagram; + if( xNewDoc.is()) + xNewDiagram.set( xNewDoc->getFirstDiagram()); + + //todo remove if model changes are notified and view is updated automatically + if( bExportContent ) + { + Reference< util::XRefreshable > xRefreshable( xNewDoc, uno::UNO_QUERY ); + if( xRefreshable.is() ) + xRefreshable->refresh(); + } + + // get Properties of ChartDocument + bool bHasMainTitle = false; + bool bHasSubTitle = false; + bool bHasLegend = false; + util::DateTime aNullDate(0,0,0,0,30,12,1899, false); + + std::vector< XMLPropertyState > aPropertyStates; + + Reference< beans::XPropertySet > xDocPropSet( rChartDoc, uno::UNO_QUERY ); + if( xDocPropSet.is()) + { + try + { + Any aAny = xDocPropSet->getPropertyValue("HasMainTitle"); + aAny >>= bHasMainTitle; + aAny = xDocPropSet->getPropertyValue("HasSubTitle"); + aAny >>= bHasSubTitle; + aAny = xDocPropSet->getPropertyValue("HasLegend"); + aAny >>= bHasLegend; + if ( bIncludeTable ) + { + aAny = xDocPropSet->getPropertyValue("NullDate"); + if ( !aAny.hasValue() ) + { + Reference xChild(rChartDoc, uno::UNO_QUERY ); + if ( xChild.is() ) + { + Reference< beans::XPropertySet > xParentDoc( xChild->getParent(),uno::UNO_QUERY); + if ( xParentDoc.is() && xParentDoc->getPropertySetInfo()->hasPropertyByName("NullDate") ) + aAny = xParentDoc->getPropertyValue("NullDate"); + } + } + + aAny >>= aNullDate; + } + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Required property not found in ChartDocument" ); + } + } + + if ( bIncludeTable && (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 ) ) + { + SvXMLElementExport aSet( mrExport, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, true, true ); + { + OUStringBuffer sBuffer; + ::sax::Converter::convertDateTime(sBuffer, aNullDate, nullptr); + mrExport.AddAttribute( XML_NAMESPACE_TABLE,XML_DATE_VALUE,sBuffer.makeStringAndClear()); + SvXMLElementExport aNull( mrExport, XML_NAMESPACE_TABLE, XML_NULL_DATE, true, true ); + } + } + + // chart element + std::unique_ptr xElChart; + + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet = rChartDoc->getArea(); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + + if( bExportContent ) + { + //export data provider in xlink:href attribute + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + OUString aDataProviderURL( ".." ); + if( xNewDoc->hasInternalDataProvider() ) + aDataProviderURL = "."; + else //special handling for data base data provider necessary + { + Reference< chart2::data::XDatabaseDataProvider > xDBDataProvider( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + if( xDBDataProvider.is() ) + aDataProviderURL = "."; + } + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aDataProviderURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + } + + Reference xPivotTableDataProvider(xNewDoc->getDataProvider(), uno::UNO_QUERY); + if (xPivotTableDataProvider.is() && nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName(); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, sPivotTableName); + } + + OUString sChartType( xDiagram->getDiagramType() ); + + // attributes + // determine class + if( !sChartType.isEmpty()) + { + enum XMLTokenEnum eXMLChartType = SchXMLTools::getTokenByChartType( sChartType, true /* bUseOldNames */ ); + + SAL_WARN_IF( eXMLChartType == XML_TOKEN_INVALID, "xmloff.chart", "invalid chart class" ); + if( eXMLChartType == XML_TOKEN_INVALID ) + eXMLChartType = XML_BAR; + + if( eXMLChartType == XML_ADD_IN ) + { + // sChartType is the service-name of the add-in + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, sChartType) ); + } + else if( eXMLChartType != XML_TOKEN_INVALID ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken(eXMLChartType )) ); + } + + //column-mapping or row-mapping + if( maSequenceMapping.hasElements() ) + { + enum XMLTokenEnum eTransToken = ::xmloff::token::XML_ROW_MAPPING; + if( mbRowSourceColumns ) + eTransToken = ::xmloff::token::XML_COLUMN_MAPPING; + OUString aSequenceMappingStr( lcl_GetStringFromNumberSequence( + maSequenceMapping, mbHasCategoryLabels && !xNewDoc->hasInternalDataProvider() ) ); + + mrExport.AddAttribute( XML_NAMESPACE_CHART, + ::xmloff::token::GetXMLToken( eTransToken ), + aSequenceMappingStr ); + } + } + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + //element + xElChart.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_CHART, true, true )); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + + // title element + if( bHasMainTitle ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getTitle(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + if( bExportContent ) + { + Reference< drawing::XShape > xShape = rChartDoc->getTitle(); + if( xShape.is()) // && "hasTitleBeenMoved" + addPosition( xShape ); + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element + SvXMLElementExport aElTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true ); + + // content (text:p) + Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + if( xPropSet.is()) + { + Any aAny( xPropSet->getPropertyValue( "String" )); + OUString aText; + aAny >>= aText; + exportText( aText ); + } + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // subtitle element + if( bHasSubTitle ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getSubTitle(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + + if( bExportContent ) + { + Reference< drawing::XShape > xShape = rChartDoc->getSubTitle(); + if( xShape.is()) + addPosition( xShape ); + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element (has no subelements) + SvXMLElementExport aElSubTitle( mrExport, XML_NAMESPACE_CHART, XML_SUBTITLE, true, true ); + + // content (text:p) + Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + if( xPropSet.is()) + { + Any aAny( xPropSet->getPropertyValue( "String" )); + OUString aText; + aAny >>= aText; + exportText( aText ); + } + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // legend element + if( bHasLegend ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getLegend(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + + if( bExportContent ) + { + Reference< beans::XPropertySet > xProp( rChartDoc->getLegend(), uno::UNO_QUERY ); + if( xProp.is()) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + + // export legend anchor position + try + { + Any aAny( xProp->getPropertyValue("Alignment")); + if( SchXMLEnumConverter::getLegendPositionConverter().exportXML( msString, aAny, mrExport.GetMM100UnitConverter() ) ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LEGEND_POSITION, msString ); + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property Align not found in ChartLegend" ); + } + + // export legend overlay + try + { + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + Any aAny( xProp->getPropertyValue("Overlay")); + if(aAny.get()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_OVERLAY, OUString::boolean(true)); + } + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property Overlay not found in ChartLegend" ); + } + + // export absolute legend position + Reference< drawing::XShape > xLegendShape( xProp, uno::UNO_QUERY ); + addPosition( xLegendShape ); + + // export legend size + if (xLegendShape.is() && nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + try + { + chart::ChartLegendExpansion nLegendExpansion = chart::ChartLegendExpansion_HIGH; + OUString aExpansionString; + Any aAny( xProp->getPropertyValue("Expansion")); + bool bHasExpansion = (aAny >>= nLegendExpansion); + if( bHasExpansion && SchXMLEnumConverter::getLegendExpansionConverter().exportXML( aExpansionString, aAny, mrExport.GetMM100UnitConverter() ) ) + { + mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION, aExpansionString ); + if( nLegendExpansion == chart::ChartLegendExpansion_CUSTOM) + { + awt::Size aSize( xLegendShape->getSize() ); + // tdf#131966: chart legend attributes width and height shouldn't be exported to ODF 1.2 (strict) + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_013) + { // ODF 1.3 OFFICE-3883 + addSize( aSize, false ); + } + else if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + addSize( aSize, true ); + } + OUStringBuffer aAspectRatioString; + ::sax::Converter::convertDouble( + aAspectRatioString, + (aSize.Height == 0 + ? 1.0 + : double(aSize.Width)/double(aSize.Height))); + mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION_ASPECT_RATIO, aAspectRatioString.makeStringAndClear() ); + } + } + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property Expansion not found in ChartLegend" ); + } + } + } + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element + SvXMLElementExport aLegend( mrExport, XML_NAMESPACE_CHART, XML_LEGEND, true, true ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // plot-area element + if( xDiagram.is()) + exportPlotArea( xDiagram, xNewDiagram, aPageSize, bExportContent, bIncludeTable ); + + // export additional shapes + if( xDocPropSet.is() ) + { + if( bExportContent ) + { + if( mxAdditionalShapes.is()) + { + // can't call exportShapes with all shapes because the + // initialisation happened with the complete draw page and not + // the XShapes object used here. Thus the shapes have to be + // exported one by one + rtl::Reference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport(); + Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount( mxAdditionalShapes->getCount()); + for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ ) + { + mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape; + SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" ); + if( ! xShape.is()) + continue; + + rShapeExport->exportShape( xShape ); + } + // this would be the easier way if it worked: + //mrExport.GetShapeExport()->exportShapes( mxAdditionalShapes ); + } + } + else + { + // get a sequence of non-chart shapes (inserted via clipboard) + try + { + Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes"); + aShapesAny >>= mxAdditionalShapes; + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found" ); + } + + if( mxAdditionalShapes.is()) + { + // seek shapes has to be called for the whole page because in + // the shape export the vector of shapes is accessed via the + // ZOrder which might be (actually is) larger than the number of + // shapes in mxAdditionalShapes + Reference< drawing::XDrawPageSupplier > xSupplier( rChartDoc, uno::UNO_QUERY ); + SAL_WARN_IF( !xSupplier.is(), "xmloff.chart", "Cannot retrieve draw page to initialize shape export" ); + if( xSupplier.is() ) + { + Reference< drawing::XShapes > xDrawPage = xSupplier->getDrawPage(); + SAL_WARN_IF( !xDrawPage.is(), "xmloff.chart", "Invalid draw page for initializing shape export" ); + if( xDrawPage.is()) + mrExport.GetShapeExport()->seekShapes( xDrawPage ); + } + + // can't call collectShapesAutoStyles with all shapes because + // the initialisation happened with the complete draw page and + // not the XShapes object used here. Thus the shapes have to be + // exported one by one + rtl::Reference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport(); + Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount( mxAdditionalShapes->getCount()); + for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ ) + { + mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape; + SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" ); + if( ! xShape.is()) + continue; + + rShapeExport->collectShapeAutoStyles( xShape ); + } + } + } + } + + // table element + // (is included as subelement of chart) + if( bExportContent ) + { + // #85929# always export table, otherwise clipboard may lose data + exportTable(); + } +} + +static void lcl_exportComplexLabel( const Sequence< uno::Any >& rComplexLabel, SvXMLExport& rExport ) +{ + sal_Int32 nLength = rComplexLabel.getLength(); + if( nLength<=1 ) + return; + SvXMLElementExport aTextList( rExport, XML_NAMESPACE_TEXT, XML_LIST, true, true ); + for(const auto& rElem : rComplexLabel) + { + SvXMLElementExport aListItem( rExport, XML_NAMESPACE_TEXT, XML_LIST_ITEM, true, true ); + OUString aString; + if( !(rElem >>= aString) ) + { + //todo? + } + SchXMLTools::exportText( rExport, aString, false /*bConvertTabsLFs*/ ); + } +} + +void SchXMLExportHelper_Impl::exportTable() +{ + // table element + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, gsTableName ); + + try + { + bool bProtected = false; + Reference< beans::XPropertySet > xProps( mrExport.GetModel(), uno::UNO_QUERY_THROW ); + if ( ( xProps->getPropertyValue("DisableDataTableDialog") >>= bProtected ) && + bProtected ) + { + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE ); + } + } + catch ( const uno::Exception& ) + { + } + + SvXMLElementExport aTable( mrExport, XML_NAMESPACE_TABLE, XML_TABLE, true, true ); + + bool bHasOwnData = false; + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + Reference< chart2::data::XRangeXMLConversion > xRangeConversion; + if( xNewDoc.is()) + { + bHasOwnData = xNewDoc->hasInternalDataProvider(); + xRangeConversion.set( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + } + + Reference< chart2::XAnyDescriptionAccess > xAnyDescriptionAccess; + { + Reference< chart::XChartDocument > xChartDoc( mrExport.GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is() ) + xAnyDescriptionAccess.set( xChartDoc->getData(), uno::UNO_QUERY ); + } + + if( bHasOwnData ) + lcl_ReorderInternalSequencesAccordingToTheirRangeName( m_aDataSequencesToExport ); + lcl_TableData aData( lcl_getDataForLocalTable( m_aDataSequencesToExport + , xAnyDescriptionAccess, maCategoriesRange + , mbRowSourceColumns, xRangeConversion )); + + tStringVector::const_iterator aDataRangeIter( aData.aDataRangeRepresentations.begin()); + const tStringVector::const_iterator aDataRangeEndIter( aData.aDataRangeRepresentations.end()); + + tStringVector::const_iterator aRowDescriptions_RangeIter( aData.aRowDescriptions_Ranges.begin()); + const tStringVector::const_iterator aRowDescriptions_RangeEnd( aData.aRowDescriptions_Ranges.end()); + + // declare columns + { + SvXMLElementExport aHeaderColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true, true ); + SvXMLElementExport aHeaderColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + } + { + SvXMLElementExport aColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, true, true ); + + sal_Int32 nNextIndex = 0; + for(sal_Int32 nHiddenIndex : aData.aHiddenColumns) + { + //i91578 display of hidden values (copy paste scenario; export hidden flag thus it can be used during migration to locale table upon paste ) + if( nHiddenIndex > nNextIndex ) + { + sal_Int64 nRepeat = static_cast< sal_Int64 >( nHiddenIndex - nNextIndex ); + if(nRepeat>1) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, + OUString::number( nRepeat )); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + } + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_VISIBILITY, GetXMLToken( XML_COLLAPSE ) ); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + nNextIndex = nHiddenIndex+1; + } + + sal_Int32 nEndIndex = aData.aColumnDescriptions.size()-1; + if( nEndIndex >= nNextIndex ) + { + sal_Int64 nRepeat = static_cast< sal_Int64 >( nEndIndex - nNextIndex + 1 ); + if(nRepeat>1) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, + OUString::number( nRepeat )); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + } + } + + // export rows with content + //export header row + { + SvXMLElementExport aHeaderRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true, true ); + SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true ); + + //first one empty cell for the row descriptions + { + SvXMLElementExport aEmptyCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true ); + SvXMLElementExport aEmptyParagraph( mrExport, XML_NAMESPACE_TEXT, XML_P, true, true ); + } + + //export column descriptions + tStringVector::const_iterator aColumnDescriptions_RangeIter( aData.aColumnDescriptions_Ranges.begin()); + const tStringVector::const_iterator aColumnDescriptions_RangeEnd( aData.aColumnDescriptions_Ranges.end()); + const Sequence< Sequence< uno::Any > >& rComplexColumnDescriptions = aData.aComplexColumnDescriptions; + sal_Int32 nComplexCount = rComplexColumnDescriptions.getLength(); + sal_Int32 nC = 0; + for( const auto& rDesc : aData.aColumnDescriptions ) + { + bool bExportString = true; + if( nC < nComplexCount ) + { + const Sequence< uno::Any >& rComplexLabel = rComplexColumnDescriptions[nC]; + if( rComplexLabel.hasElements() ) + { + double fValue=0.0; + if( rComplexLabel[0] >>=fValue ) + { + bExportString = false; + + ::sax::Converter::convertDouble( + msStringBuffer, fValue); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT ); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString ); + } + } + } + if( bExportString ) + { + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING ); + } + + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true ); + exportText( rDesc ); + if( nC < nComplexCount ) + lcl_exportComplexLabel( rComplexColumnDescriptions[nC], mrExport ); + if( !bHasOwnData && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd ) + { + // remind the original range to allow a correct re-association when copying via clipboard + if (!(*aColumnDescriptions_RangeIter).isEmpty()) + SchXMLTools::exportRangeToSomewhere( mrExport, *aColumnDescriptions_RangeIter ); + ++aColumnDescriptions_RangeIter; + } + + nC++; + } + SAL_WARN_IF( !bHasOwnData && (aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd" ); + } // closing row and header-rows elements + + // export value rows + { + SvXMLElementExport aRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROWS, true, true ); + tStringVector::const_iterator aRowDescriptionsIter( aData.aRowDescriptions.begin()); + const Sequence< Sequence< uno::Any > >& rComplexRowDescriptions = aData.aComplexRowDescriptions; + sal_Int32 nComplexCount = rComplexRowDescriptions.getLength(); + sal_Int32 nC = 0; + + for( const auto& rRow : aData.aDataInRows ) + { + SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true ); + + //export row descriptions + { + bool bExportString = true; + if( nC < nComplexCount ) + { + const Sequence< uno::Any >& rComplexLabel = rComplexRowDescriptions[nC]; + if( rComplexLabel.hasElements() ) + { + double fValue=0.0; + if( rComplexLabel[0] >>=fValue ) + { + bExportString = false; + + ::sax::Converter::convertDouble(msStringBuffer, fValue); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT ); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString ); + } + } + } + if( bExportString ) + { + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING ); + } + + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true ); + if( aRowDescriptionsIter != aData.aRowDescriptions.end()) + { + exportText( *aRowDescriptionsIter ); + if( nC < nComplexCount ) + lcl_exportComplexLabel( rComplexRowDescriptions[nC], mrExport ); + if( !bHasOwnData && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd ) + { + // remind the original range to allow a correct re-association when copying via clipboard + SchXMLTools::exportRangeToSomewhere( mrExport, *aRowDescriptions_RangeIter ); + ++aRowDescriptions_RangeIter; + } + ++aRowDescriptionsIter; + } + } + + //export row values + for( t2DNumberContainer::value_type::const_iterator aColIt( rRow.begin()); + aColIt != rRow.end(); ++aColIt ) + { + ::sax::Converter::convertDouble( msStringBuffer, *aColIt ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT ); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString ); + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true ); + exportText( msString ); // do not convert tabs and lfs + if( ( !bHasOwnData && aDataRangeIter != aDataRangeEndIter ) && + ( mbRowSourceColumns || (aColIt == rRow.begin()) ) ) + { + // remind the original range to allow a correct re-association when copying via clipboard + if (!(*aDataRangeIter).isEmpty()) + SchXMLTools::exportRangeToSomewhere( mrExport, *aDataRangeIter ); + ++aDataRangeIter; + } + } + + ++nC; + } + } + + // if range iterator was used it should have reached its end + SAL_WARN_IF( !bHasOwnData && (aDataRangeIter != aDataRangeEndIter), "xmloff.chart", "bHasOwnData == false && aDataRangeIter != aDataRangeEndIter" ); + SAL_WARN_IF( !bHasOwnData && (aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd" ); +} + +namespace +{ + +Reference< chart2::XCoordinateSystem > lcl_getCooSys( const Reference< chart2::XDiagram > & xNewDiagram ) +{ + Reference< chart2::XCoordinateSystem > xCooSys; + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDiagram, uno::UNO_QUERY ); + if(xCooSysCnt.is()) + { + Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() ); + if(aCooSysSeq.hasElements()) + xCooSys = aCooSysSeq[0]; + } + return xCooSys; +} + +Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& xCooSys, + enum XMLTokenEnum eDimension, bool bPrimary=true ) +{ + Reference< chart2::XAxis > xNewAxis; + try + { + if( xCooSys.is() ) + { + sal_Int32 nDimensionIndex=0; + switch( eDimension ) + { + case XML_X: + nDimensionIndex=0; + break; + case XML_Y: + nDimensionIndex=1; + break; + case XML_Z: + nDimensionIndex=2; + break; + default: + break; + } + + xNewAxis = xCooSys->getAxisByDimension( nDimensionIndex, bPrimary ? 0 : 1 ); + } + } + catch( const uno::Exception & ) + { + } + return xNewAxis; +} + +} + +void SchXMLExportHelper_Impl::exportPlotArea( + const Reference< chart::XDiagram >& xDiagram, + const Reference< chart2::XDiagram >& xNewDiagram, + const awt::Size & rPageSize, + bool bExportContent, + bool bIncludeTable ) +{ + SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" ); + if( ! xDiagram.is()) + return; + + // variables for autostyles + Reference< beans::XPropertySet > xPropSet; + std::vector< XMLPropertyState > aPropertyStates; + + msStringBuffer.setLength( 0 ); + + // plot-area element + + std::unique_ptr xElPlotArea; + // get property states for autostyles + xPropSet.set( xDiagram, uno::UNO_QUERY ); + if( xPropSet.is()) + { + if( mxExpPropMapper.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + if( bExportContent ) + { + rtl::Reference< XMLShapeExport > rShapeExport; + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + if( !msChartAddress.isEmpty() ) + { + if( !bIncludeTable ) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, msChartAddress ); + + Reference< chart::XChartDocument > xDoc( mrExport.GetModel(), uno::UNO_QUERY ); + if( xDoc.is() ) + { + Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY ); + if( xDocProp.is()) + { + Any aAny; + + try + { + bool bFirstCol = false, bFirstRow = false; + + aAny = xDocProp->getPropertyValue( "DataSourceLabelsInFirstColumn" ); + aAny >>= bFirstCol; + aAny = xDocProp->getPropertyValue( "DataSourceLabelsInFirstRow" ); + aAny >>= bFirstRow; + + if( bFirstCol || bFirstRow ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DATA_SOURCE_HAS_LABELS ), + ( bFirstCol + ? ( bFirstRow + ? ::xmloff::token::GetXMLToken( ::xmloff::token::XML_BOTH ) + : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_COLUMN )) + : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_ROW ))); + } + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Properties missing" ); + } + } + } + } + + // attributes + if( xDiagram.is()) + { + addPosition( xDiagram ); + addSize( xDiagram ); + } + + bool bIs3DChart = false; + + if( xPropSet.is()) + { + Any aAny; + + // 3d attributes + try + { + aAny = xPropSet->getPropertyValue("Dim3D"); + aAny >>= bIs3DChart; + + if( bIs3DChart ) + { + rShapeExport = mrExport.GetShapeExport(); + if( rShapeExport.is()) + rShapeExport->export3DSceneAttributes( xPropSet ); + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exportPlotAreaException caught"); + } + } + + // plot-area element + xElPlotArea.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_PLOT_AREA, true, true )); + + //inner position rectangle element + exportCoordinateRegion( xDiagram ); + + // light sources (inside plot area element) + if( bIs3DChart && + rShapeExport.is()) + rShapeExport->export3DLamps( xPropSet ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + + // axis elements + exportAxes( xDiagram, xNewDiagram, bExportContent ); + + // series elements + Reference< chart2::XAxis > xSecondYAxis = lcl_getAxis( lcl_getCooSys( xNewDiagram ), XML_Y, false ); + exportSeries( xNewDiagram, rPageSize, bExportContent, xSecondYAxis.is() ); + + // stock-chart elements + OUString sChartType ( xDiagram->getDiagramType()); + if( sChartType == "com.sun.star.chart.StockDiagram" ) + { + Reference< chart::XStatisticDisplay > xStockPropProvider( xDiagram, uno::UNO_QUERY ); + if( xStockPropProvider.is()) + { + // stock-gain-marker + Reference< beans::XPropertySet > xStockPropSet = xStockPropProvider->getUpBar(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter( xStockPropSet ); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_GAIN_MARKER, true, true ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + } + } + + // stock-loss-marker + xStockPropSet = xStockPropProvider->getDownBar(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter( xStockPropSet ); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_LOSS_MARKER, true, true ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + } + } + + // stock-range-line + xStockPropSet = xStockPropProvider->getMinMaxLine(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter( xStockPropSet ); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_RANGE_LINE, true, true ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } + } + + // wall and floor element + Reference< chart::X3DDisplay > xWallFloorSupplier( xDiagram, uno::UNO_QUERY ); + if( mxExpPropMapper.is() && + xWallFloorSupplier.is()) + { + // remove property states for autostyles + aPropertyStates.clear(); + + Reference< beans::XPropertySet > xWallPropSet = xWallFloorSupplier->getWall(); + if( xWallPropSet.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xWallPropSet ); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aWall( mrExport, XML_NAMESPACE_CHART, XML_WALL, true, true ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + } + } + + // floor element + // remove property states for autostyles + aPropertyStates.clear(); + + Reference< beans::XPropertySet > xFloorPropSet = xWallFloorSupplier->getFloor(); + if( xFloorPropSet.is()) + { + aPropertyStates = mxExpPropMapper->Filter( xFloorPropSet ); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aFloor( mrExport, XML_NAMESPACE_CHART, XML_FLOOR, true, true ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } +} + +void SchXMLExportHelper_Impl::exportCoordinateRegion( const uno::Reference< chart::XDiagram >& xDiagram ) +{ + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older + return; + + Reference< chart::XDiagramPositioning > xDiaPos( xDiagram, uno::UNO_QUERY ); + SAL_WARN_IF( !xDiaPos.is(), "xmloff.chart", "Invalid xDiaPos as parameter" ); + if( !xDiaPos.is() ) + return; + + awt::Rectangle aRect( xDiaPos->calculateDiagramPositionExcludingAxes() ); + addPosition( awt::Point(aRect.X,aRect.Y) ); + addSize( awt::Size(aRect.Width,aRect.Height) ); + + // ODF 1.3 OFFICE-3928 + SvXMLElementExport aCoordinateRegion( mrExport, + (SvtSaveOptions::ODFSVER_013 <= nCurrentODFVersion) ? XML_NAMESPACE_CHART : XML_NAMESPACE_CHART_EXT, + XML_COORDINATE_REGION, true, true ); +} + +namespace +{ + XMLTokenEnum lcl_getTimeUnitToken( sal_Int32 nTimeUnit ) + { + XMLTokenEnum eToken = XML_DAYS; + switch( nTimeUnit ) + { + case css::chart::TimeUnit::YEAR: + eToken = XML_YEARS; + break; + case css::chart::TimeUnit::MONTH: + eToken = XML_MONTHS; + break; + default://days + break; + } + return eToken; + } +} + +void SchXMLExportHelper_Impl::exportDateScale( const Reference< beans::XPropertySet >& rAxisProps ) +{ + if( !rAxisProps.is() ) + return; + + chart::TimeIncrement aIncrement; + if( rAxisProps->getPropertyValue("TimeIncrement") >>= aIncrement ) + { + sal_Int32 nTimeResolution = css::chart::TimeUnit::DAY; + if( aIncrement.TimeResolution >>= nTimeResolution ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_BASE_TIME_UNIT, lcl_getTimeUnitToken( nTimeResolution ) ); + + chart::TimeInterval aInterval; + if( aIncrement.MajorTimeInterval >>= aInterval ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_VALUE, OUString::number(aInterval.Number) ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) ); + } + if( aIncrement.MinorTimeInterval >>= aInterval ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_VALUE, OUString::number(aInterval.Number) ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) ); + } + + SvXMLElementExport aDateScale( mrExport, XML_NAMESPACE_CHART_EXT, XML_DATE_SCALE, true, true );//#i25706#todo: change namespace for next ODF version + } +} + +void SchXMLExportHelper_Impl::exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent ) +{ + if( !rTitleProps.is() ) + return; + std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( rTitleProps ); + if( bExportContent ) + { + OUString aText; + Any aAny( rTitleProps->getPropertyValue( "String" )); + aAny >>= aText; + + Reference< drawing::XShape > xShape( rTitleProps, uno::UNO_QUERY ); + if( xShape.is()) + addPosition( xShape ); + + AddAutoStyleAttribute( aPropertyStates ); + SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true ); + + // paragraph containing title + exportText( aText ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); +} + +void SchXMLExportHelper_Impl::exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent ) +{ + if( !rGridProperties.is() ) + return; + std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( rGridProperties ); + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, bMajor ? XML_MAJOR : XML_MINOR ); + SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, true, true ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); +} + +namespace +{ + +//returns true if a date scale needs to be exported +bool lcl_exportAxisType( const Reference< chart2::XAxis >& rChart2Axis, SvXMLExport& rExport) +{ + bool bExportDateScale = false; + if( !rChart2Axis.is() ) + return bExportDateScale; + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if ((nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) == 0) //do not export to ODF 1.3 or older + return bExportDateScale; + + chart2::ScaleData aScale( rChart2Axis->getScaleData() ); + //#i25706#todo: change namespace for next ODF version + sal_uInt16 nNameSpace = XML_NAMESPACE_CHART_EXT; + + switch(aScale.AxisType) + { + case chart2::AxisType::CATEGORY: + if( aScale.AutoDateAxis ) + { + rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO ); + bExportDateScale = true; + } + else + rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_TEXT ); + break; + case chart2::AxisType::DATE: + rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_DATE ); + bExportDateScale = true; + break; + default: //AUTOMATIC + rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO ); + break; + } + + return bExportDateScale; +} + +void disableLinkedNumberFormat( + std::vector& rPropStates, const rtl::Reference& rMapper ) +{ + for (XMLPropertyState & rState : rPropStates) + { + if (rState.mnIndex < 0 || rMapper->GetEntryCount() <= rState.mnIndex) + continue; + + OUString aXMLName = rMapper->GetEntryXMLName(rState.mnIndex); + + if (aXMLName != "link-data-style-to-source") + continue; + + // Entry found. Set the value to false and bail out. + rState.maValue <<= false; + return; + } + + // Entry not found. Insert a new entry for this. + sal_Int32 nIndex = rMapper->GetEntryIndex(XML_NAMESPACE_CHART, "link-data-style-to-source", 0); + XMLPropertyState aState(nIndex); + aState.maValue <<= false; + rPropStates.push_back(aState); +} + +} + +void SchXMLExportHelper_Impl::exportAxis( + enum XMLTokenEnum eDimension, + enum XMLTokenEnum eAxisName, + const Reference< beans::XPropertySet >& rAxisProps, + const Reference< chart2::XAxis >& rChart2Axis, + const OUString& rCategoriesRange, + bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid, + bool bExportContent, OUString sChartType ) +{ + std::vector< XMLPropertyState > aPropertyStates; + std::unique_ptr pAxis; + + // get property states for autostyles + if( rAxisProps.is() && mxExpPropMapper.is() ) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED + && eDimension == XML_X) + { + chart2::ScaleData aScaleData(rChart2Axis->getScaleData()); + bool bShiftedCatPos = aScaleData.ShiftedCategoryPosition; + if (sChartType == "com.sun.star.chart.BarDiagram" || sChartType == "com.sun.star.chart.StockDiagram") + { + if (!bShiftedCatPos) + rAxisProps->setPropertyValue("MajorOrigin", uno::makeAny(0.0)); + } + else if (bShiftedCatPos) + rAxisProps->setPropertyValue("MajorOrigin", uno::makeAny(0.5)); + } + + lcl_exportNumberFormat( "NumberFormat", rAxisProps, mrExport ); + aPropertyStates = mxExpPropMapper->Filter( rAxisProps ); + + if (!maSrcShellID.isEmpty() && !maDestShellID.isEmpty() && maSrcShellID != maDestShellID) + { + // Disable link to source number format property when pasting to + // a different doc shell. These shell ID's should be both empty + // during real ODF export. + disableLinkedNumberFormat(aPropertyStates, mxExpPropMapper->getPropertySetMapper()); + } + } + + bool bExportDateScale = false; + if( bExportContent ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, eDimension ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, eAxisName ); + AddAutoStyleAttribute( aPropertyStates ); // write style name + if( !rCategoriesRange.isEmpty() ) + bExportDateScale = lcl_exportAxisType( rChart2Axis, mrExport ); + + // open axis element + pAxis.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, true, true )); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + aPropertyStates.clear(); + + //date scale + if( bExportDateScale ) + exportDateScale( rAxisProps ); + + Reference< beans::XPropertySet > xTitleProps; + Reference< beans::XPropertySet > xMajorGridProps; + Reference< beans::XPropertySet > xMinorGridProps; + Reference< chart::XAxis > xAxis( rAxisProps, uno::UNO_QUERY ); + if( xAxis.is() ) + { + xTitleProps = bHasTitle ? xAxis->getAxisTitle() : nullptr; + xMajorGridProps = bHasMajorGrid ? xAxis->getMajorGrid() : nullptr; + xMinorGridProps = bHasMinorGrid ? xAxis->getMinorGrid() : nullptr; + } + + // axis-title + exportAxisTitle( xTitleProps , bExportContent ); + + // categories if we have a categories chart + if( bExportContent && !rCategoriesRange.isEmpty() ) + { + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, rCategoriesRange ); + SvXMLElementExport aCategories( mrExport, XML_NAMESPACE_CHART, XML_CATEGORIES, true, true ); + } + + // grid + exportGrid( xMajorGridProps, true, bExportContent ); + exportGrid( xMinorGridProps, false, bExportContent ); +} + +void SchXMLExportHelper_Impl::exportAxes( + const Reference< chart::XDiagram > & xDiagram, + const Reference< chart2::XDiagram > & xNewDiagram, + bool bExportContent ) +{ + SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" ); + if( ! xDiagram.is()) + return; + + // get some properties from document first + bool bHasXAxis = false, + bHasYAxis = false, + bHasZAxis = false, + bHasSecondaryXAxis = false, + bHasSecondaryYAxis = false; + bool bHasXAxisTitle = false, + bHasYAxisTitle = false, + bHasZAxisTitle = false, + bHasSecondaryXAxisTitle = false, + bHasSecondaryYAxisTitle = false; + bool bHasXAxisMajorGrid = false, + bHasXAxisMinorGrid = false, + bHasYAxisMajorGrid = false, + bHasYAxisMinorGrid = false, + bHasZAxisMajorGrid = false, + bHasZAxisMinorGrid = false; + + // get multiple properties using XMultiPropertySet + MultiPropertySetHandler aDiagramProperties (xDiagram); + + aDiagramProperties.Add ("HasXAxis", bHasXAxis); + aDiagramProperties.Add ("HasYAxis", bHasYAxis); + aDiagramProperties.Add ("HasZAxis", bHasZAxis); + aDiagramProperties.Add ("HasSecondaryXAxis", bHasSecondaryXAxis); + aDiagramProperties.Add ("HasSecondaryYAxis", bHasSecondaryYAxis); + + aDiagramProperties.Add ("HasXAxisTitle", bHasXAxisTitle); + aDiagramProperties.Add ("HasYAxisTitle", bHasYAxisTitle); + aDiagramProperties.Add ("HasZAxisTitle", bHasZAxisTitle); + aDiagramProperties.Add ("HasSecondaryXAxisTitle", bHasSecondaryXAxisTitle); + aDiagramProperties.Add ("HasSecondaryYAxisTitle", bHasSecondaryYAxisTitle); + + aDiagramProperties.Add ("HasXAxisGrid", bHasXAxisMajorGrid); + aDiagramProperties.Add ("HasYAxisGrid", bHasYAxisMajorGrid); + aDiagramProperties.Add ("HasZAxisGrid", bHasZAxisMajorGrid); + + aDiagramProperties.Add ("HasXAxisHelpGrid", bHasXAxisMinorGrid); + aDiagramProperties.Add ("HasYAxisHelpGrid", bHasYAxisMinorGrid); + aDiagramProperties.Add ("HasZAxisHelpGrid", bHasZAxisMinorGrid); + + if ( ! aDiagramProperties.GetProperties ()) + { + SAL_INFO("xmloff.chart", "Required properties not found in Chart diagram"); + } + + Reference< chart2::XCoordinateSystem > xCooSys( lcl_getCooSys(xNewDiagram) ); + + // write an axis element also if the axis itself is not visible, but a grid or a title + + OUString aCategoriesRange; + Reference< chart::XAxisSupplier > xAxisSupp( xDiagram, uno::UNO_QUERY ); + OUString sChartType = xDiagram->getDiagramType(); + + // x axis + + Reference< css::chart2::XAxis > xNewAxis = lcl_getAxis( xCooSys, XML_X ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(0) : nullptr, uno::UNO_QUERY ); + if( mbHasCategoryLabels && bExportContent ) + { + Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) ); + if( xCategories.is() ) + { + Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() ); + if( xValues.is() ) + { + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + maCategoriesRange = xValues->getSourceRangeRepresentation(); + aCategoriesRange = lcl_ConvertRange( maCategoriesRange, xNewDoc ); + } + } + } + exportAxis( XML_X, XML_PRIMARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasXAxisTitle, bHasXAxisMajorGrid, bHasXAxisMinorGrid, bExportContent, sChartType ); + aCategoriesRange.clear(); + } + + // secondary x axis + + xNewAxis = lcl_getAxis( xCooSys, XML_X, false ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(0) : nullptr, uno::UNO_QUERY ); + exportAxis( XML_X, XML_SECONDARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryXAxisTitle, false, false, bExportContent, sChartType ); + } + + // y axis + + xNewAxis = lcl_getAxis( xCooSys, XML_Y ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(1) : nullptr, uno::UNO_QUERY ); + exportAxis( XML_Y, XML_PRIMARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasYAxisTitle, bHasYAxisMajorGrid, bHasYAxisMinorGrid, bExportContent, sChartType ); + } + + // secondary y axis + + xNewAxis = lcl_getAxis( xCooSys, XML_Y, false ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(1) : nullptr, uno::UNO_QUERY ); + exportAxis( XML_Y, XML_SECONDARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryYAxisTitle, false, false, bExportContent, sChartType ); + } + + // z axis + + xNewAxis = lcl_getAxis( xCooSys, XML_Z ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(2) : nullptr, uno::UNO_QUERY ); + exportAxis( XML_Z, XML_PRIMARY_Z, xAxisProps, xNewAxis, aCategoriesRange, bHasZAxisTitle, bHasZAxisMajorGrid, bHasZAxisMinorGrid, bExportContent, sChartType ); + } +} + +namespace +{ + bool lcl_hasNoValuesButText( const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) + { + if( !xDataSequence.is() ) + return false;//have no data + + Sequence< uno::Any > aData; + Reference< chart2::data::XNumericalDataSequence > xNumericalDataSequence( xDataSequence, uno::UNO_QUERY ); + if( xNumericalDataSequence.is() ) + { + Sequence< double > aDoubles( xNumericalDataSequence->getNumericalData() ); + if (std::any_of(aDoubles.begin(), aDoubles.end(), [](double fDouble) { return !std::isnan( fDouble ); })) + return false;//have double value + } + else + { + aData = xDataSequence->getData(); + double fDouble = 0.0; + bool bHaveDouble = std::any_of(aData.begin(), aData.end(), + [&fDouble](const uno::Any& rData) { return (rData >>= fDouble) && !std::isnan( fDouble ); }); + if (bHaveDouble) + return false;//have double value + } + //no values found + + Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY ); + if( xTextualDataSequence.is() ) + { + uno::Sequence< OUString > aStrings( xTextualDataSequence->getTextualData() ); + if (std::any_of(aStrings.begin(), aStrings.end(), [](const OUString& rString) { return !rString.isEmpty(); })) + return true;//have text + } + else + { + if( !aData.hasElements() ) + aData = xDataSequence->getData(); + OUString aString; + bool bHaveText = std::any_of(aData.begin(), aData.end(), + [&aString](const uno::Any& rData) { return (rData >>= aString) && !aString.isEmpty(); }); + if (bHaveText) + return true;//have text + } + //no doubles and no texts + return false; + } +} + +void SchXMLExportHelper_Impl::exportSeries( + const Reference< chart2::XDiagram > & xNewDiagram, + const awt::Size & rPageSize, + bool bExportContent, + bool bHasTwoYAxes ) +{ + Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( xNewDiagram, uno::UNO_QUERY ); + if( ! xBCooSysCnt.is()) + return; + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + + OUString aFirstXDomainRange; + OUString aFirstYDomainRange; + + std::vector< XMLPropertyState > aPropertyStates; + + const Sequence< Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xBCooSysCnt->getCoordinateSystems()); + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY ); + if( ! xCTCnt.is()) + continue; + const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes()); + for( const auto& rChartType : aCTSeq ) + { + Reference< chart2::XDataSeriesContainer > xDSCnt( rChartType, uno::UNO_QUERY ); + if( ! xDSCnt.is()) + continue; + // note: if xDSCnt.is() then also aCTSeq[nCTIdx] + OUString aChartType( rChartType->getChartType()); + OUString aLabelRole = rChartType->getRoleOfSequenceForSeriesLabel(); + + // special export for stock charts + if ( aChartType == "com.sun.star.chart2.CandleStickChartType" ) + { + bool bJapaneseCandleSticks = false; + Reference< beans::XPropertySet > xCTProp( rChartType, uno::UNO_QUERY ); + if( xCTProp.is()) + xCTProp->getPropertyValue("Japanese") >>= bJapaneseCandleSticks; + exportCandleStickSeries( + xDSCnt->getDataSeries(), xNewDiagram, bJapaneseCandleSticks, bExportContent ); + continue; + } + + // export dataseries for current chart-type + Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries()); + for( sal_Int32 nSeriesIdx=0; nSeriesIdx xSource( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ); + if( xSource.is()) + { + std::unique_ptr pSeries; + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt( + xSource->getDataSequences()); + sal_Int32 nMainSequenceIndex = -1; + sal_Int32 nSeriesLength = 0; + sal_Int32 nAttachedAxis = chart::ChartAxisAssign::PRIMARY_Y; + bool bHasMeanValueLine = false; + Reference< beans::XPropertySet > xPropSet; + tLabelValuesDataPair aSeriesLabelValuesPair; + + // search for main sequence and create a series element + { + Reference< chart2::data::XDataSequence > xValuesSeq; + Reference< chart2::data::XDataSequence > xLabelSeq; + sal_Int32 nSeqIdx=0; + for( ; nSeqIdx xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() ); + if( nMainSequenceIndex==-1 ) + { + Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY ); + if( xSeqProp.is()) + xSeqProp->getPropertyValue("Role") >>= aRole; + // "main" sequence + if( aRole == aLabelRole ) + { + xValuesSeq.set( xTempValueSeq ); + xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel()); + nMainSequenceIndex = nSeqIdx; + } + } + sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0)); + if( nSeriesLength < nSequenceLength ) + nSeriesLength = nSequenceLength; + } + + // have found the main sequence, then xValuesSeq and + // xLabelSeq contain those. Otherwise both are empty + { + // get property states for autostyles + try + { + xPropSet = SchXMLSeriesHelper::createOldAPISeriesPropertySet( + aSeriesSeq[nSeriesIdx], mrExport.GetModel() ); + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Series not found or no XPropertySet" ); + continue; + } + if( xPropSet.is()) + { + // determine attached axis + try + { + Any aAny( xPropSet->getPropertyValue( "Axis" )); + aAny >>= nAttachedAxis; + + aAny = xPropSet->getPropertyValue( "MeanValue" ); + aAny >>= bHasMeanValueLine; + } + catch( const beans::UnknownPropertyException & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" ); + } + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport ); + lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport ); + } + + if( mxExpPropMapper.is()) + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + } + + if( bExportContent ) + { + if( bHasTwoYAxes ) + { + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + } + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + if( xValuesSeq.is()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, + lcl_ConvertRange( + xValuesSeq->getSourceRangeRepresentation(), + xNewDoc )); + else + // #i75297# allow empty series, export empty range to have all ranges on import + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, OUString()); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older + { + if (xPropSet.is()) + { + Any aAny = xPropSet->getPropertyValue("ShowLegendEntry"); + if (!aAny.get()) + { + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true)); + } + } + } + + if (xLabelSeq.is()) + { + // Check if the label is direct string value rather than a reference. + bool bHasString = false; + uno::Reference xLSProp(xLabelSeq, uno::UNO_QUERY); + if (xLSProp.is()) + { + try + { + xLSProp->getPropertyValue("HasStringLabel") >>= bHasString; + } + catch (const beans::UnknownPropertyException&) {} + } + + OUString aRange = xLabelSeq->getSourceRangeRepresentation(); + + if (bHasString) + { + mrExport.AddAttribute( + XML_NAMESPACE_LO_EXT, XML_LABEL_STRING, aRange); + } + else + { + mrExport.AddAttribute( + XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, + lcl_ConvertRange( + xLabelSeq->getSourceRangeRepresentation(), xNewDoc)); + } + } + + if( xLabelSeq.is() || xValuesSeq.is() ) + aSeriesLabelValuesPair = tLabelValuesDataPair( xLabelSeq, xValuesSeq ); + + // chart-type for mixed types + enum XMLTokenEnum eCTToken( + SchXMLTools::getTokenByChartType( aChartType, false /* bUseOldNames */ )); + //@todo: get token for current charttype + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( eCTToken ))); + + // open series element until end of for loop + pSeries.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true )); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + } + + // export domain elements if we have a series parent element + if( pSeries ) + { + // domain elements + if( bExportContent ) + { + bool bIsScatterChart = aChartType == "com.sun.star.chart2.ScatterChartType"; + bool bIsBubbleChart = aChartType == "com.sun.star.chart2.BubbleChartType"; + Reference< chart2::data::XDataSequence > xYValuesForBubbleChart; + if( bIsBubbleChart ) + { + Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-y" ) ); + if( xSequence.is() ) + { + xYValuesForBubbleChart = xSequence->getValues(); + if( !lcl_exportDomainForThisSequence( xYValuesForBubbleChart, aFirstYDomainRange, mrExport ) ) + xYValuesForBubbleChart = nullptr; + } + } + if( bIsScatterChart || bIsBubbleChart ) + { + Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-x" ) ); + if( xSequence.is() ) + { + Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() ); + if( lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport ) ) + m_aDataSequencesToExport.emplace_back( + uno::Reference< chart2::data::XDataSequence >(), xValues ); + } + else if( nSeriesIdx==0 ) + { + //might be that the categories are used as x-values (e.g. for date axis) -> export them accordingly + Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) ); + if( xCategories.is() ) + { + Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() ); + if( !lcl_hasNoValuesButText( xValues ) ) + lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport ); + } + } + } + if( xYValuesForBubbleChart.is() ) + m_aDataSequencesToExport.emplace_back( + uno::Reference< chart2::data::XDataSequence >(), xYValuesForBubbleChart ); + } + } + + // add sequences for main sequence after domain sequences, + // so that the export of the local table has the correct order + if( bExportContent && + (aSeriesLabelValuesPair.first.is() || aSeriesLabelValuesPair.second.is())) + m_aDataSequencesToExport.push_back( aSeriesLabelValuesPair ); + + // statistical objects: + // regression curves and mean value lines + if( bHasMeanValueLine && + xPropSet.is() && + mxExpPropMapper.is() ) + { + Reference< beans::XPropertySet > xStatProp; + try + { + Any aPropAny( xPropSet->getPropertyValue( "DataMeanValueProperties" )); + aPropAny >>= xStatProp; + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of series - optional DataMeanValueProperties not available" ); + } + + if( xStatProp.is() ) + { + aPropertyStates = mxExpPropMapper->Filter( xStatProp ); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_MEAN_VALUE, true, true ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } + + if( xPropSet.is() && + mxExpPropMapper.is() ) + { + exportRegressionCurve( aSeriesSeq[nSeriesIdx], rPageSize, bExportContent ); + } + + exportErrorBar( xPropSet,false, bExportContent ); // X ErrorBar + exportErrorBar( xPropSet,true, bExportContent ); // Y ErrorBar + + exportDataPoints( + uno::Reference< beans::XPropertySet >( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ), + nSeriesLength, xNewDiagram, bExportContent ); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (bExportContent && nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older + { + Sequence< OUString > aSupportedMappings = rChartType->getSupportedPropertyRoles(); + exportPropertyMapping( xSource, aSupportedMappings ); + } + + // close series element + pSeries.reset(); + } + } + aPropertyStates.clear(); + } + } +} + +void SchXMLExportHelper_Impl::exportPropertyMapping( + const Reference< chart2::data::XDataSource > & xSource, const Sequence< OUString >& rSupportedMappings ) +{ + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt( + xSource->getDataSequences()); + + for(const auto& rSupportedMapping : rSupportedMappings) + { + Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, rSupportedMapping ) ); + if(xSequence.is()) + { + Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() ); + if( xValues.is()) + { + mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_PROPERTY, rSupportedMapping); + mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_CELL_RANGE_ADDRESS, + lcl_ConvertRange( + xValues->getSourceRangeRepresentation(), + xNewDoc )); + SvXMLElementExport( mrExport, XML_NAMESPACE_LO_EXT, XML_PROPERTY_MAPPING, true, true ); + + // register range for data table export + m_aDataSequencesToExport.emplace_back( + uno::Reference< chart2::data::XDataSequence >(), xValues ); + } + } + } +} + +void SchXMLExportHelper_Impl::exportRegressionCurve( + const Reference< chart2::XDataSeries >& xSeries, + const awt::Size& rPageSize, + bool bExportContent ) +{ + OSL_ASSERT( mxExpPropMapper.is()); + + Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, uno::UNO_QUERY ); + if( xRegressionCurveContainer.is() ) + { + const Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves(); + + for( const auto& xRegCurve : aRegCurveSeq ) + { + std::vector< XMLPropertyState > aEquationPropertyStates; + if (!xRegCurve.is()) + continue; + + Reference< beans::XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY ); + if( !xProperties.is() ) + continue; + + Reference< lang::XServiceName > xServiceName( xProperties, uno::UNO_QUERY ); + if( !xServiceName.is() ) + continue; + + bool bShowEquation = false; + bool bShowRSquared = false; + bool bExportEquation = false; + + OUString aService = xServiceName->getServiceName(); + + std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( xProperties ); + + // Add service name (which is regression type) + sal_Int32 nIndex = GetPropertySetMapper()->FindEntryIndex(XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE); + XMLPropertyState property(nIndex, uno::makeAny(aService)); + aPropertyStates.push_back(property); + + Reference< beans::XPropertySet > xEquationProperties; + xEquationProperties.set( xRegCurve->getEquationProperties() ); + if( xEquationProperties.is()) + { + xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation; + xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowRSquared; + + bExportEquation = ( bShowEquation || bShowRSquared ); + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentVersion < SvtSaveOptions::ODFSVER_012) + { + bExportEquation=false; + } + if( bExportEquation ) + { + // number format + sal_Int32 nNumberFormat = 0; + if( (xEquationProperties->getPropertyValue("NumberFormat") >>= nNumberFormat ) && + nNumberFormat != -1 ) + { + mrExport.addDataStyle( nNumberFormat ); + } + aEquationPropertyStates = mxExpPropMapper->Filter( xEquationProperties ); + } + } + + if( !aPropertyStates.empty() || bExportEquation ) + { + // write element + if( bExportContent ) + { + // add style name attribute + if( !aPropertyStates.empty()) + { + AddAutoStyleAttribute( aPropertyStates ); + } + + SvXMLElementExport aRegressionExport( mrExport, XML_NAMESPACE_CHART, XML_REGRESSION_CURVE, true, true ); + if( bExportEquation ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_EQUATION, (bShowEquation ? XML_TRUE : XML_FALSE) ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_R_SQUARE, (bShowRSquared ? XML_TRUE : XML_FALSE) ); + + // export position + chart2::RelativePosition aRelativePosition; + if( xEquationProperties->getPropertyValue( "RelativePosition" ) >>= aRelativePosition ) + { + double fX = aRelativePosition.Primary * rPageSize.Width; + double fY = aRelativePosition.Secondary * rPageSize.Height; + awt::Point aPos; + aPos.X = static_cast< sal_Int32 >( ::rtl::math::round( fX )); + aPos.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY )); + addPosition( aPos ); + } + + if( !aEquationPropertyStates.empty()) + { + AddAutoStyleAttribute( aEquationPropertyStates ); + } + + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_EQUATION, true, true ); + } + } + else // autostyles + { + if( !aPropertyStates.empty()) + { + CollectAutoStyle( aPropertyStates ); + } + if( bExportEquation && !aEquationPropertyStates.empty()) + { + CollectAutoStyle( aEquationPropertyStates ); + } + } + } + } + } +} + +void SchXMLExportHelper_Impl::exportErrorBar( const Reference &xSeriesProp, + bool bYError, bool bExportContent ) +{ + assert(mxExpPropMapper.is()); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + + /// Don't export X ErrorBars for older ODF versions. + if (!bYError && nCurrentVersion < SvtSaveOptions::ODFSVER_012) + return; + + if (xSeriesProp.is()) + { + bool bNegative = false, bPositive = false; + sal_Int32 nErrorBarStyle = chart::ErrorBarStyle::NONE; + Reference< beans::XPropertySet > xErrorBarProp; + + try + { + Any aAny = xSeriesProp->getPropertyValue( bYError ? OUString("ErrorBarY") : OUString("ErrorBarX") ); + aAny >>= xErrorBarProp; + + if ( xErrorBarProp.is() ) + { + aAny = xErrorBarProp->getPropertyValue("ShowNegativeError" ); + aAny >>= bNegative; + + aAny = xErrorBarProp->getPropertyValue("ShowPositiveError" ); + aAny >>= bPositive; + + aAny = xErrorBarProp->getPropertyValue("ErrorBarStyle" ); + aAny >>= nErrorBarStyle; + } + } + catch( const beans::UnknownPropertyException & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" ); + } + + if( nErrorBarStyle != chart::ErrorBarStyle::NONE && (bNegative || bPositive)) + { + if( bExportContent && nErrorBarStyle == chart::ErrorBarStyle::FROM_DATA ) + { + // register data ranges for error bars for export in local table + ::std::vector< Reference< chart2::data::XDataSequence > > aErrorBarSequences( + lcl_getErrorBarSequences( xErrorBarProp )); + for( const auto& rErrorBarSequence : aErrorBarSequences ) + { + m_aDataSequencesToExport.emplace_back( + uno::Reference< chart2::data::XDataSequence >(), rErrorBarSequence ); + } + } + + std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( xErrorBarProp ); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + if (nCurrentVersion >= SvtSaveOptions::ODFSVER_012) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, bYError ? XML_Y : XML_X );//#i114149# + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_ERROR_INDICATOR, true, true ); + } + else // autostyles + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } +} + +void SchXMLExportHelper_Impl::exportCandleStickSeries( + const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq, + const Reference< chart2::XDiagram > & xDiagram, + bool bJapaneseCandleSticks, + bool bExportContent ) +{ + + for( const auto& xSeries : aSeriesSeq ) + { + sal_Int32 nAttachedAxis = lcl_isSeriesAttachedToFirstAxis( xSeries ) + ? chart::ChartAxisAssign::PRIMARY_Y + : chart::ChartAxisAssign::SECONDARY_Y; + + Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + // export series in correct order (as we don't store roles) + // with japanese candlesticks: open, low, high, close + // otherwise: low, high, close + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt( + xSource->getDataSequences()); + + sal_Int32 nSeriesLength = + lcl_getSequenceLengthByRole( aSeqCnt, "values-last"); + + if( bExportContent ) + { + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + //@todo: export data points + + //TODO: moggi: same code three times + // open + if( bJapaneseCandleSticks ) + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, "values-first", xNewDoc, m_aDataSequencesToExport )); + if( !aRanges.second.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( !aRanges.first.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aOpenSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ); + // export empty data points + exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent ); + } + + // low + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, "values-min", xNewDoc, m_aDataSequencesToExport )); + if( !aRanges.second.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( !aRanges.first.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aLowSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ); + // export empty data points + exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent ); + } + + // high + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, "values-max", xNewDoc, m_aDataSequencesToExport )); + if( !aRanges.second.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( !aRanges.first.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aHighSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ); + // export empty data points + exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent ); + } + + // close + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, "values-last", xNewDoc, m_aDataSequencesToExport )); + if( !aRanges.second.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( !aRanges.first.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aCloseSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ); + // export empty data points + exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent ); + } + } + else // autostyles + { + // for close series + } + // remove property states for autostyles + } + } +} + +void SchXMLExportHelper_Impl::exportDataPoints( + const uno::Reference< beans::XPropertySet > & xSeriesProperties, + sal_Int32 nSeriesLength, + const uno::Reference< chart2::XDiagram > & xDiagram, + bool bExportContent ) +{ + // data-points + + // write data-points only if they contain autostyles + // objects with equal autostyles are grouped using the attribute + // repeat="number" + + // Note: if only the nth data-point has autostyles there is an element + // without style and repeat="n-1" attribute written in advance. + + // the sequence aDataPointSeq contains indices of data-points that + // do have own attributes. This increases the performance substantially. + + // more performant version for #93600# + if (!mxExpPropMapper.is()) + return; + + uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY ); + + std::vector< XMLPropertyState > aPropertyStates; + + bool bVaryColorsByPoint = false; + Sequence< sal_Int32 > aDataPointSeq; + Sequence deletedLegendEntriesSeq; + if( xSeriesProperties.is()) + { + xSeriesProperties->getPropertyValue("AttributedDataPoints") >>= aDataPointSeq; + xSeriesProperties->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint; + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older + xSeriesProperties->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq; + } + + sal_Int32 nSize = aDataPointSeq.getLength(); + SAL_WARN_IF( nSize > nSeriesLength, "xmloff.chart", "Too many point attributes" ); + + const sal_Int32 * pPoints = aDataPointSeq.getConstArray(); + sal_Int32 nElement; + sal_Int32 nRepeat; + Reference< chart2::XColorScheme > xColorScheme; + if( xDiagram.is()) + xColorScheme.set( xDiagram->getDefaultColorScheme()); + + ::std::vector< SchXMLDataPointStruct > aDataPointVector; + + sal_Int32 nLastIndex = -1; + + // collect elements + if( bVaryColorsByPoint && xColorScheme.is() ) + { + ::std::set< sal_Int32 > aAttrPointSet; + ::std::copy( pPoints, pPoints + aDataPointSeq.getLength(), + ::std::inserter( aAttrPointSet, aAttrPointSet.begin())); + const ::std::set< sal_Int32 >::const_iterator aEndIt( aAttrPointSet.end()); + for( nElement = 0; nElement < nSeriesLength; ++nElement ) + { + aPropertyStates.clear(); + uno::Reference< beans::XPropertySet > xPropSet; + bool bExportNumFmt = false; + if( aAttrPointSet.find( nElement ) != aEndIt ) + { + try + { + xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet( + xSeries, nElement, mrExport.GetModel() ); + bExportNumFmt = true; + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" ); + } + } + else + { + // property set only containing the color + xPropSet.set( new ::xmloff::chart::ColorPropertySet( + xColorScheme->getColorByIndex( nElement ))); + } + SAL_WARN_IF( !xPropSet.is(), "xmloff.chart", "Pie Segments should have properties" ); + if( xPropSet.is()) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012 && bExportNumFmt) + { + lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport ); + lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport ); + } + + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + // write data-point with style + SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" ); + + SchXMLDataPointStruct aPoint; + aPoint.maStyleName = maAutoStyleNameQueue.front(); + if(bExportNumFmt) + aPoint.mCustomLabelText = lcl_getCustomLabelField(nElement, xSeries); + maAutoStyleNameQueue.pop(); + aDataPointVector.push_back( aPoint ); + } + else + { + CollectAutoStyle( aPropertyStates ); + } + } + } + } + SAL_WARN_IF( bExportContent && (static_cast(aDataPointVector.size()) != nSeriesLength), "xmloff.chart", "not enough data points on content export" ); + } + else + { + for( sal_Int32 nCurrIndex : aDataPointSeq ) + { + aPropertyStates.clear(); + //assuming sorted indices in pPoints + + if( nCurrIndex<0 || nCurrIndex>=nSeriesLength ) + break; + + // write leading empty data points + if( nCurrIndex - nLastIndex > 1 ) + { + SchXMLDataPointStruct aPoint; + aPoint.mnRepeat = nCurrIndex - nLastIndex - 1; + aDataPointVector.push_back( aPoint ); + } + + uno::Reference< beans::XPropertySet > xPropSet; + // get property states + try + { + xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet( + xSeries, nCurrIndex, mrExport.GetModel() ); + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" ); + } + if( xPropSet.is()) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport ); + lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport ); + } + + aPropertyStates = mxExpPropMapper->Filter( xPropSet ); + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + // write data-point with style + SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" ); + SchXMLDataPointStruct aPoint; + aPoint.maStyleName = maAutoStyleNameQueue.front(); + aPoint.mCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries); + aPoint.mCustomLabelPos = lcl_getCustomLabelPosition(nCurrIndex, xSeries); + maAutoStyleNameQueue.pop(); + + aDataPointVector.push_back( aPoint ); + nLastIndex = nCurrIndex; + } + else + { + CollectAutoStyle( aPropertyStates ); + } + continue; + } + } + + // if we get here the property states are empty + SchXMLDataPointStruct aPoint; + aDataPointVector.push_back( aPoint ); + + nLastIndex = nCurrIndex; + } + // final empty elements + nRepeat = nSeriesLength - nLastIndex - 1; + if( nRepeat > 0 ) + { + SchXMLDataPointStruct aPoint; + aPoint.mnRepeat = nRepeat; + aDataPointVector.push_back( aPoint ); + } + } + + if (!bExportContent) + return; + + // write elements (merge equal ones) + SchXMLDataPointStruct aPoint; + SchXMLDataPointStruct aLastPoint; + + // initialize so that it doesn't matter if + // the element is counted in the first iteration + aLastPoint.mnRepeat = 0; + sal_Int32 nIndex = 0; + for( const auto& rPoint : aDataPointVector ) + { + aPoint = rPoint; + + if( aPoint.maStyleName == aLastPoint.maStyleName && aLastPoint.mCustomLabelText.getLength() < 1 && + aLastPoint.mCustomLabelPos.Primary == 0.0 && aLastPoint.mCustomLabelPos.Secondary == 0.0 ) + aPoint.mnRepeat += aLastPoint.mnRepeat; + else if( aLastPoint.mnRepeat > 0 ) + { + // write last element + if( !aLastPoint.maStyleName.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName ); + + if( aLastPoint.mnRepeat > 1 ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED, + OUString::number( ( aLastPoint.mnRepeat ) )); + + for (auto& deletedLegendEntry : deletedLegendEntriesSeq) + { + if (nIndex == deletedLegendEntry) + { + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true)); + break; + } + } + nIndex++; + exportCustomLabelPosition(aLastPoint.mCustomLabelPos); + SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true ); + exportCustomLabel(aLastPoint.mCustomLabelText); + } + aLastPoint = aPoint; + } + // write last element if it hasn't been written in last iteration + if( aPoint.maStyleName == aLastPoint.maStyleName ) + { + if( !aLastPoint.maStyleName.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName ); + + if( aLastPoint.mnRepeat > 1 ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED, + OUString::number( ( aLastPoint.mnRepeat ) )); + + for (auto& deletedLegendEntry : deletedLegendEntriesSeq) + { + if (nIndex == deletedLegendEntry) + { + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true)); + break; + } + } + + exportCustomLabelPosition(aLastPoint.mCustomLabelPos); + SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true ); + exportCustomLabel(aLastPoint.mCustomLabelText); + } +} + +void SchXMLExportHelper_Impl::exportCustomLabel( const CustomLabelSeq & xCustomLabel ) +{ + if( xCustomLabel.getLength() < 1 ) + return; // nothing to export + + SvXMLElementExport aLabelElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_LABEL, true, true); + SvXMLElementExport aPara( mrExport, XML_NAMESPACE_TEXT, XML_P, true, false ); + for( const Reference& label : xCustomLabel ) + { + // TODO add style + SvXMLElementExport aSpan( mrExport, XML_NAMESPACE_TEXT, XML_SPAN, true, false); + mrExport.GetDocHandler()->characters(label->getString()); + } +} + +void SchXMLExportHelper_Impl::exportCustomLabelPosition( const chart2::RelativePosition & xCustomLabelPosition) +{ + if( xCustomLabelPosition.Primary == 0.0 && xCustomLabelPosition.Secondary == 0.0 ) + return; // nothing to export + + OUStringBuffer aCustomLabelPosString; + ::sax::Converter::convertDouble(aCustomLabelPosString, xCustomLabelPosition.Primary); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_POS_X, aCustomLabelPosString.makeStringAndClear()); + + ::sax::Converter::convertDouble(aCustomLabelPosString, xCustomLabelPosition.Secondary); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_POS_Y, aCustomLabelPosString.makeStringAndClear()); +} + +void SchXMLExportHelper_Impl::addPosition( const awt::Point & rPosition ) +{ + mrExport.GetMM100UnitConverter().convertMeasureToXML( + msStringBuffer, rPosition.X ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, msString ); + + mrExport.GetMM100UnitConverter().convertMeasureToXML( + msStringBuffer, rPosition.Y ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, msString ); +} + +void SchXMLExportHelper_Impl::addPosition( const Reference< drawing::XShape >& xShape ) +{ + if( xShape.is()) + addPosition( xShape->getPosition()); +} + +void SchXMLExportHelper_Impl::addSize( const awt::Size & rSize, bool bIsOOoNamespace) +{ + mrExport.GetMM100UnitConverter().convertMeasureToXML( + msStringBuffer, rSize.Width ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG , XML_WIDTH, msString ); + + mrExport.GetMM100UnitConverter().convertMeasureToXML( + msStringBuffer, rSize.Height); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG, XML_HEIGHT, msString ); +} + +void SchXMLExportHelper_Impl::addSize( const Reference< drawing::XShape >& xShape ) +{ + if( xShape.is()) + addSize( xShape->getSize() ); +} + +awt::Size SchXMLExportHelper_Impl::getPageSize( const Reference< chart2::XChartDocument > & xChartDoc ) +{ + awt::Size aSize( 8000, 7000 ); + uno::Reference< embed::XVisualObject > xVisualObject( xChartDoc, uno::UNO_QUERY ); + SAL_WARN_IF( !xVisualObject.is(), "xmloff.chart", "need XVisualObject for page size" ); + if( xVisualObject.is() ) + aSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); + + return aSize; +} + +void SchXMLExportHelper_Impl::CollectAutoStyle( const std::vector< XMLPropertyState >& aStates ) +{ + if( !aStates.empty() ) + maAutoStyleNameQueue.push( mrAutoStylePool.Add( XmlStyleFamily::SCH_CHART_ID, aStates )); +} + +void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector< XMLPropertyState >& aStates ) +{ + if( !aStates.empty() ) + { + SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" ); + + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, maAutoStyleNameQueue.front() ); + maAutoStyleNameQueue.pop(); + } +} + +void SchXMLExportHelper_Impl::exportText( const OUString& rText ) +{ + SchXMLTools::exportText( mrExport, rText, false/*bConvertTabsLFs*/ ); +} + + +SchXMLExport::SchXMLExport(const Reference& xContext, + OUString const& implementationName, SvXMLExportFlags nExportFlags) + : SvXMLExport(util::MeasureUnit::CM, xContext, implementationName, ::xmloff::token::XML_CHART, + nExportFlags) + , maAutoStylePool(new SchXMLAutoStylePoolP(*this)) + , maExportHelper(new SchXMLExportHelper(*this, *maAutoStylePool)) +{ + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + GetNamespaceMap_().Add( GetXMLToken(XML_NP_CHART_EXT), GetXMLToken(XML_N_CHART_EXT), XML_NAMESPACE_CHART_EXT); +} + +SchXMLExport::~SchXMLExport() +{ +} + +ErrCode SchXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ) +{ + maExportHelper->SetSourceShellID(GetSourceShellID()); + maExportHelper->SetDestinationShellID(GetDestinationShellID()); + + Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + maExportHelper->m_pImpl->InitRangeSegmentationProperties( xChartDoc ); + return SvXMLExport::exportDoc( eClass ); +} + +void SchXMLExport::ExportMasterStyles_() +{ + // not available in chart + SAL_INFO("xmloff.chart", "Master Style Export requested. Not available for Chart" ); +} + +void SchXMLExport::collectAutoStyles() +{ + SvXMLExport::collectAutoStyles(); + + if (mbAutoStylesCollected) + return; + + // there are no styles that require their own autostyles + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is()) + { + maExportHelper->m_pImpl->collectAutoStyles( xChartDoc ); + } + else + { + SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" ); + } + } + mbAutoStylesCollected = true; +} + +void SchXMLExport::ExportAutoStyles_() +{ + collectAutoStyles(); + + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is()) + { + maExportHelper->m_pImpl->exportAutoStyles(); + } + else + { + SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" ); + } + } +} + +void SchXMLExport::ExportContent_() +{ + Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is()) + { + // determine if data comes from the outside + bool bIncludeTable = true; + + Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY ); + if( xNewDoc.is()) + { + // check if we have own data. If so we must not export the complete + // range string, as this is our only indicator for having own or + // external data. @todo: fix this in the file format! + Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" )) + { + bIncludeTable = false; + } + } + else + { + Reference< lang::XServiceInfo > xServ( xChartDoc, uno::UNO_QUERY ); + if( xServ.is()) + { + if( xServ->supportsService( "com.sun.star.chart.ChartTableAddressSupplier" )) + { + Reference< beans::XPropertySet > xProp( xServ, uno::UNO_QUERY ); + if( xProp.is()) + { + Any aAny; + try + { + OUString sChartAddress; + aAny = xProp->getPropertyValue( "ChartRangeAddress" ); + aAny >>= sChartAddress; + maExportHelper->m_pImpl->SetChartRangeAddress( sChartAddress ); + + // do not include own table if there are external addresses + bIncludeTable = sChartAddress.isEmpty(); + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property ChartRangeAddress not supported by ChartDocument" ); + } + } + } + } + } + maExportHelper->m_pImpl->exportChart( xChartDoc, bIncludeTable ); + } + else + { + SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel" ); + } +} + +rtl::Reference< XMLPropertySetMapper > const & SchXMLExport::GetPropertySetMapper() const +{ + return maExportHelper->m_pImpl->GetPropertySetMapper(); +} + +void SchXMLExportHelper_Impl::InitRangeSegmentationProperties( const Reference< chart2::XChartDocument > & xChartDoc ) +{ + if( xChartDoc.is()) + try + { + Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + SAL_WARN_IF( !xDataProvider.is(), "xmloff.chart", "No DataProvider" ); + if( xDataProvider.is()) + { + Reference< chart2::data::XDataSource > xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc, mbHasCategoryLabels )); + const Sequence< beans::PropertyValue > aArgs( xDataProvider->detectArguments( xDataSource )); + OUString sCellRange, sBrokenRange; + bool bBrokenRangeAvailable = false; + for( const auto& rArg : aArgs ) + { + if ( rArg.Name == "CellRangeRepresentation" ) + rArg.Value >>= sCellRange; + else if ( rArg.Name == "BrokenCellRangeForExport" ) + { + if( rArg.Value >>= sBrokenRange ) + bBrokenRangeAvailable = true; + } + else if ( rArg.Name == "DataRowSource" ) + { + chart::ChartDataRowSource eRowSource; + rArg.Value >>= eRowSource; + mbRowSourceColumns = ( eRowSource == chart::ChartDataRowSource_COLUMNS ); + } + else if ( rArg.Name == "SequenceMapping" ) + rArg.Value >>= maSequenceMapping; + } + + // #i79009# For Writer we have to export a broken version of the + // range, where every row number is not too large, so that older + // version can correctly read those files. + msChartAddress = (bBrokenRangeAvailable ? sBrokenRange : sCellRange); + if( !msChartAddress.isEmpty() ) + { + // convert format to XML-conform one + Reference< chart2::data::XRangeXMLConversion > xConversion( xDataProvider, uno::UNO_QUERY ); + if( xConversion.is()) + msChartAddress = xConversion->convertRangeToXML( msChartAddress ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } +} + +// first version: everything goes in one storage + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SchXMLExport(pCtx, "SchXMLExport.Compact", + SvXMLExportFlags::ALL + ^ (SvXMLExportFlags::SETTINGS | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::SCRIPTS))); +} + +// Oasis format +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SchXMLExport(pCtx, "SchXMLExport.Oasis.Compact", + (SvXMLExportFlags::ALL + ^ (SvXMLExportFlags::SETTINGS | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::SCRIPTS)) + | SvXMLExportFlags::OASIS)); +} + +// multiple storage version: one for content / styles / meta + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLStylesExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Styles", SvXMLExportFlags::STYLES)); +} + +// Oasis format +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisStylesExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Styles", + SvXMLExportFlags::STYLES | SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLContentExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Content", + SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT + | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisContentExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Content", + SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT + | SvXMLExportFlags::FONTDECLS + | SvXMLExportFlags::OASIS)); +} + +// Oasis format + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisMetaExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Meta", + SvXMLExportFlags::META | SvXMLExportFlags::OASIS)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLImport.cxx b/xmloff/source/chart/SchXMLImport.cxx new file mode 100644 index 000000000..e03a2d3c2 --- /dev/null +++ b/xmloff/source/chart/SchXMLImport.cxx @@ -0,0 +1,617 @@ +/* -*- 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 +#include "SchXMLChartContext.hxx" +#include "contexts.hxx" +#include "SchXMLTools.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +class lcl_MatchesChartType +{ +public: + explicit lcl_MatchesChartType( const OUString & aChartTypeName ) : + m_aChartTypeName( aChartTypeName ) + {} + + bool operator () ( const Reference< chart2::XChartType > & xChartType ) const + { + return (xChartType.is() && + xChartType->getChartType() == m_aChartTypeName ); + } + +private: + OUString m_aChartTypeName; +}; +} // anonymous namespace + + // TokenMaps for distinguishing different + // tokens in different contexts + +// element maps + +// attribute maps + +SchXMLImportHelper::SchXMLImportHelper() : + mpAutoStyles( nullptr ) +{ +} + +SvXMLImportContext* SchXMLImportHelper::CreateChartContext( + SvXMLImport& rImport, + sal_uInt16 /*nPrefix*/, const OUString& rLocalName, + const Reference< frame::XModel >& rChartModel, + const Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + Reference< chart::XChartDocument > xDoc( rChartModel, uno::UNO_QUERY ); + if( xDoc.is()) + { + mxChartDoc = xDoc; + pContext = new SchXMLChartContext( *this, rImport, rLocalName ); + } + else + { + SAL_WARN("xmloff.chart", "No valid XChartDocument given as XModel" ); + } + + return pContext; +} + +void SchXMLImportHelper::FillAutoStyle(const OUString& rAutoStyleName, const uno::Reference& rProp) +{ + if (!rProp.is()) + return; + + const SvXMLStylesContext* pStylesCtxt = GetAutoStylesContext(); + if (pStylesCtxt) + { + SvXMLStyleContext* pStyle = const_cast(pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(), rAutoStyleName)); + + if (XMLPropStyleContext* pPropStyle = dynamic_cast(pStyle)) + pPropStyle->FillPropertySet(rProp); + } +} + +// get various token maps + +const SvXMLTokenMap& SchXMLImportHelper::GetDocElemTokenMap() +{ + if( ! mpChartDocElemTokenMap ) + { + static const SvXMLTokenMapEntry aDocElemTokenMap[] = + { + { XML_NAMESPACE_OFFICE, XML_AUTOMATIC_STYLES, XML_TOK_DOC_AUTOSTYLES }, + { XML_NAMESPACE_OFFICE, XML_STYLES, XML_TOK_DOC_STYLES }, + { XML_NAMESPACE_OFFICE, XML_META, XML_TOK_DOC_META }, + { XML_NAMESPACE_OFFICE, XML_BODY, XML_TOK_DOC_BODY }, + XML_TOKEN_MAP_END + }; + + mpChartDocElemTokenMap = std::make_unique( aDocElemTokenMap ); + } // if( ! mpChartDocElemTokenMap ) + + return *mpChartDocElemTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetTableElemTokenMap() +{ + if( ! mpTableElemTokenMap ) + { + static const SvXMLTokenMapEntry aTableElemTokenMap[] = + { + { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, XML_TOK_TABLE_HEADER_COLS }, + { XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, XML_TOK_TABLE_COLUMNS }, + { XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, XML_TOK_TABLE_COLUMN }, + { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, XML_TOK_TABLE_HEADER_ROWS }, + { XML_NAMESPACE_TABLE, XML_TABLE_ROWS, XML_TOK_TABLE_ROWS }, + { XML_NAMESPACE_TABLE, XML_TABLE_ROW, XML_TOK_TABLE_ROW }, + XML_TOKEN_MAP_END + }; + + mpTableElemTokenMap = std::make_unique( aTableElemTokenMap ); + } // if( ! mpTableElemTokenMap ) + + return *mpTableElemTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetChartElemTokenMap() +{ + if( ! mpChartElemTokenMap ) + { + static const SvXMLTokenMapEntry aChartElemTokenMap[] = + { + { XML_NAMESPACE_CHART, XML_PLOT_AREA, XML_TOK_CHART_PLOT_AREA }, + { XML_NAMESPACE_CHART, XML_TITLE, XML_TOK_CHART_TITLE }, + { XML_NAMESPACE_CHART, XML_SUBTITLE, XML_TOK_CHART_SUBTITLE }, + { XML_NAMESPACE_CHART, XML_LEGEND, XML_TOK_CHART_LEGEND }, + { XML_NAMESPACE_TABLE, XML_TABLE, XML_TOK_CHART_TABLE }, + XML_TOKEN_MAP_END + }; + + mpChartElemTokenMap = std::make_unique( aChartElemTokenMap ); + } // if( ! mpChartElemTokenMap ) + + return *mpChartElemTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetPlotAreaElemTokenMap() +{ + if( ! mpPlotAreaElemTokenMap ) + { + static const SvXMLTokenMapEntry aPlotAreaElemTokenMap[] = +{ + { XML_NAMESPACE_CHART_EXT, XML_COORDINATE_REGION, XML_TOK_PA_COORDINATE_REGION_EXT }, + { XML_NAMESPACE_CHART, XML_COORDINATE_REGION, XML_TOK_PA_COORDINATE_REGION }, + { XML_NAMESPACE_CHART, XML_AXIS, XML_TOK_PA_AXIS }, + { XML_NAMESPACE_CHART, XML_SERIES, XML_TOK_PA_SERIES }, + { XML_NAMESPACE_CHART, XML_WALL, XML_TOK_PA_WALL }, + { XML_NAMESPACE_CHART, XML_FLOOR, XML_TOK_PA_FLOOR }, + { XML_NAMESPACE_DR3D, XML_LIGHT, XML_TOK_PA_LIGHT_SOURCE }, + { XML_NAMESPACE_CHART, XML_STOCK_GAIN_MARKER, XML_TOK_PA_STOCK_GAIN }, + { XML_NAMESPACE_CHART, XML_STOCK_LOSS_MARKER, XML_TOK_PA_STOCK_LOSS }, + { XML_NAMESPACE_CHART, XML_STOCK_RANGE_LINE, XML_TOK_PA_STOCK_RANGE }, + XML_TOKEN_MAP_END +}; + + mpPlotAreaElemTokenMap = std::make_unique( aPlotAreaElemTokenMap ); + } // if( ! mpPlotAreaElemTokenMap ) + + return *mpPlotAreaElemTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetSeriesElemTokenMap() +{ + if( ! mpSeriesElemTokenMap ) + { + static const SvXMLTokenMapEntry aSeriesElemTokenMap[] = +{ + { XML_NAMESPACE_CHART, XML_DATA_POINT, XML_TOK_SERIES_DATA_POINT }, + { XML_NAMESPACE_CHART, XML_DOMAIN, XML_TOK_SERIES_DOMAIN }, + { XML_NAMESPACE_CHART, XML_MEAN_VALUE, XML_TOK_SERIES_MEAN_VALUE_LINE }, + { XML_NAMESPACE_CHART, XML_REGRESSION_CURVE, XML_TOK_SERIES_REGRESSION_CURVE }, + { XML_NAMESPACE_CHART, XML_ERROR_INDICATOR, XML_TOK_SERIES_ERROR_INDICATOR }, + { XML_NAMESPACE_LO_EXT, XML_PROPERTY_MAPPING, XML_TOK_SERIES_PROPERTY_MAPPING }, + { XML_NAMESPACE_CHART, XML_DATA_LABEL, XML_TOK_SERIES_DATA_LABEL }, + XML_TOKEN_MAP_END +}; + + mpSeriesElemTokenMap = std::make_unique( aSeriesElemTokenMap ); + } // if( ! mpSeriesElemTokenMap ) + + return *mpSeriesElemTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetChartAttrTokenMap() +{ + if( ! mpChartAttrTokenMap ) + { + static const SvXMLTokenMapEntry aChartAttrTokenMap[] = +{ + { XML_NAMESPACE_XLINK, XML_HREF, XML_TOK_CHART_HREF }, + { XML_NAMESPACE_CHART, XML_CLASS, XML_TOK_CHART_CLASS }, + { XML_NAMESPACE_SVG, XML_WIDTH, XML_TOK_CHART_WIDTH }, + { XML_NAMESPACE_SVG, XML_HEIGHT, XML_TOK_CHART_HEIGHT }, + { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_CHART_STYLE_NAME }, + { XML_NAMESPACE_CHART, XML_COLUMN_MAPPING, XML_TOK_CHART_COL_MAPPING }, + { XML_NAMESPACE_CHART, XML_ROW_MAPPING, XML_TOK_CHART_ROW_MAPPING }, + { XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, XML_TOK_CHART_DATA_PILOT_SOURCE }, + XML_TOKEN_MAP_END +}; + + mpChartAttrTokenMap = std::make_unique( aChartAttrTokenMap ); + } // if( ! mpChartAttrTokenMap ) + + return *mpChartAttrTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetPlotAreaAttrTokenMap() +{ + if( ! mpPlotAreaAttrTokenMap ) + { + static const SvXMLTokenMapEntry aPlotAreaAttrTokenMap[] = +{ + { XML_NAMESPACE_SVG, XML_X, XML_TOK_PA_X }, + { XML_NAMESPACE_SVG, XML_Y, XML_TOK_PA_Y }, + { XML_NAMESPACE_SVG, XML_WIDTH, XML_TOK_PA_WIDTH }, + { XML_NAMESPACE_SVG, XML_HEIGHT, XML_TOK_PA_HEIGHT }, + { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_PA_STYLE_NAME }, + { XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, XML_TOK_PA_CHART_ADDRESS }, + { XML_NAMESPACE_CHART, XML_DATA_SOURCE_HAS_LABELS, XML_TOK_PA_DS_HAS_LABELS }, + { XML_NAMESPACE_DR3D, XML_TRANSFORM, XML_TOK_PA_TRANSFORM }, + { XML_NAMESPACE_DR3D, XML_VRP, XML_TOK_PA_VRP }, + { XML_NAMESPACE_DR3D, XML_VPN, XML_TOK_PA_VPN }, + { XML_NAMESPACE_DR3D, XML_VUP, XML_TOK_PA_VUP }, + { XML_NAMESPACE_DR3D, XML_PROJECTION, XML_TOK_PA_PROJECTION }, + { XML_NAMESPACE_DR3D, XML_DISTANCE, XML_TOK_PA_DISTANCE }, + { XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, XML_TOK_PA_FOCAL_LENGTH }, + { XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, XML_TOK_PA_SHADOW_SLANT }, + { XML_NAMESPACE_DR3D, XML_SHADE_MODE, XML_TOK_PA_SHADE_MODE }, + { XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, XML_TOK_PA_AMBIENT_COLOR }, + { XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, XML_TOK_PA_LIGHTING_MODE }, + XML_TOKEN_MAP_END +}; + + mpPlotAreaAttrTokenMap = std::make_unique( aPlotAreaAttrTokenMap ); + } // if( ! mpPlotAreaAttrTokenMap ) + + return *mpPlotAreaAttrTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetCellAttrTokenMap() +{ + if( ! mpCellAttrTokenMap ) + { + static const SvXMLTokenMapEntry aCellAttrTokenMap[] = +{ + { XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_TOK_CELL_VAL_TYPE }, + { XML_NAMESPACE_OFFICE, XML_VALUE, XML_TOK_CELL_VALUE }, + XML_TOKEN_MAP_END +}; + + mpCellAttrTokenMap = std::make_unique( aCellAttrTokenMap ); + } // if( ! mpCellAttrTokenMap ) + + return *mpCellAttrTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetSeriesAttrTokenMap() +{ + if( ! mpSeriesAttrTokenMap ) + { + static const SvXMLTokenMapEntry aSeriesAttrTokenMap[] = +{ + { XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, XML_TOK_SERIES_CELL_RANGE }, + { XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, XML_TOK_SERIES_LABEL_ADDRESS }, + { XML_NAMESPACE_LO_EXT, XML_LABEL_STRING, XML_TOK_SERIES_LABEL_STRING }, + { XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_TOK_SERIES_ATTACHED_AXIS }, + { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_SERIES_STYLE_NAME }, + { XML_NAMESPACE_CHART, XML_CLASS, XML_TOK_SERIES_CHART_CLASS }, + { XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, XML_TOK_SERIES_HIDE_LEGEND }, + XML_TOKEN_MAP_END +}; + + mpSeriesAttrTokenMap = std::make_unique( aSeriesAttrTokenMap ); + } // if( ! mpSeriesAttrTokenMap ) + + return *mpSeriesAttrTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetPropMappingAttrTokenMap() +{ + if( !mpPropMappingAttrTokenMap ) + { + static const SvXMLTokenMapEntry aPropMappingAttrTokenMap[] = + { + { XML_NAMESPACE_LO_EXT, XML_PROPERTY, XML_TOK_PROPERTY_MAPPING_PROPERTY }, + { XML_NAMESPACE_LO_EXT, XML_CELL_RANGE_ADDRESS, XML_TOK_PROPERTY_MAPPING_RANGE }, + XML_TOKEN_MAP_END + }; + + mpPropMappingAttrTokenMap = std::make_unique( aPropMappingAttrTokenMap ); + } + + return *mpPropMappingAttrTokenMap; +} + +const SvXMLTokenMap& SchXMLImportHelper::GetRegEquationAttrTokenMap() +{ + if( ! mpRegEquationAttrTokenMap ) + { + static const SvXMLTokenMapEntry aRegressionEquationAttrTokenMap[] = +{ + { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_REGEQ_STYLE_NAME }, + { XML_NAMESPACE_CHART, XML_DISPLAY_EQUATION, XML_TOK_REGEQ_DISPLAY_EQUATION }, + { XML_NAMESPACE_CHART, XML_DISPLAY_R_SQUARE, XML_TOK_REGEQ_DISPLAY_R_SQUARE }, + { XML_NAMESPACE_SVG, XML_X, XML_TOK_REGEQ_POS_X }, + { XML_NAMESPACE_SVG, XML_Y, XML_TOK_REGEQ_POS_Y }, + XML_TOKEN_MAP_END +}; + + mpRegEquationAttrTokenMap = std::make_unique( aRegressionEquationAttrTokenMap ); + } // if( ! mpRegEquationAttrTokenMap ) + + return *mpRegEquationAttrTokenMap; +} + +//static +void SchXMLImportHelper::DeleteDataSeries( + const Reference< chart2::XDataSeries > & xSeries, + const Reference< chart2::XChartDocument > & xDoc ) +{ + if( !xDoc.is() ) + return; + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + + for( const auto& rChartType : aChartTypes ) + { + Reference< chart2::XDataSeriesContainer > xSeriesCnt( rChartType, uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xSeriesCnt->getDataSeries()); + + if (std::find(aSeriesSeq.begin(), aSeriesSeq.end(), xSeries) != aSeriesSeq.end()) + { + xSeriesCnt->removeDataSeries(xSeries); + return; + } + } + } + } + catch( const uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } +} + +// static +Reference< chart2::XDataSeries > SchXMLImportHelper::GetNewDataSeries( + const Reference< chart2::XChartDocument > & xDoc, + sal_Int32 nCoordinateSystemIndex, + const OUString & rChartTypeName, + bool bPushLastChartType /* = false */ ) +{ + Reference< chart2::XDataSeries > xResult; + if(!xDoc.is()) + return xResult; + + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + Reference< uno::XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + + if( nCoordinateSystemIndex < aCooSysSeq.getLength()) + { + Reference< chart2::XChartType > xCurrentType; + { + Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[ nCoordinateSystemIndex ], uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + // find matching chart type group + const Reference< chart2::XChartType > * pBegin = aChartTypes.getConstArray(); + const Reference< chart2::XChartType > * pEnd = pBegin + aChartTypes.getLength(); + const Reference< chart2::XChartType > * pIt = + ::std::find_if( pBegin, pEnd, lcl_MatchesChartType( rChartTypeName )); + if( pIt != pEnd ) + xCurrentType.set( *pIt ); + // if chart type is set at series and differs from current one, + // create a new chart type + if( !xCurrentType.is()) + { + xCurrentType.set( + xContext->getServiceManager()->createInstanceWithContext( rChartTypeName, xContext ), + uno::UNO_QUERY ); + if( xCurrentType.is()) + { + if( bPushLastChartType && aChartTypes.hasElements()) + { + sal_Int32 nIndex( aChartTypes.getLength() - 1 ); + aChartTypes.realloc( aChartTypes.getLength() + 1 ); + aChartTypes[ nIndex + 1 ] = aChartTypes[ nIndex ]; + aChartTypes[ nIndex ] = xCurrentType; + xCTCnt->setChartTypes( aChartTypes ); + } + else + xCTCnt->addChartType( xCurrentType ); + } + } + } + + if( xCurrentType.is()) + { + Reference< chart2::XDataSeriesContainer > xSeriesCnt( xCurrentType, uno::UNO_QUERY_THROW ); + + if( xContext.is() ) + { + xResult.set( + xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.chart2.DataSeries", + xContext ), uno::UNO_QUERY_THROW ); + } + if( xResult.is() ) + xSeriesCnt->addDataSeries( xResult ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + return xResult; +} + +SchXMLImport::SchXMLImport( + const Reference< uno::XComponentContext >& xContext, + OUString const & implementationName, SvXMLImportFlags nImportFlags ) : + SvXMLImport( xContext, implementationName, nImportFlags ), + maImportHelper(new SchXMLImportHelper) +{ + GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK ); + GetNamespaceMap().Add( GetXMLToken(XML_NP_CHART_EXT), GetXMLToken(XML_N_CHART_EXT), XML_NAMESPACE_CHART_EXT); +} + +SchXMLImport::~SchXMLImport() throw () +{ + uno::Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is() && xChartDoc->hasControllersLocked() ) + xChartDoc->unlockControllers(); +} + +// create the main context (subcontexts are created +// by the one created here) +SvXMLImportContext *SchXMLImport::CreateFastContext( sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContext* pContext = nullptr; + + switch (nElement) + { + case XML_ELEMENT( OFFICE, XML_DOCUMENT ): + case XML_ELEMENT( OFFICE, XML_DOCUMENT_META ): + { + uno::Reference xDPS( + GetModel(), uno::UNO_QUERY); + // mst@: right now, this seems to be not supported, so it is untested + if (xDPS.is()) { + pContext = (nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT_META)) + ? new SvXMLMetaDocumentContext(*this, xDPS->getDocumentProperties()) + // flat OpenDocument file format + : new SchXMLFlatDocContext_Impl(*maImportHelper, *this, nElement, + xDPS->getDocumentProperties()); + } + } + break; + // accept + case XML_ELEMENT(OFFICE, XML_DOCUMENT_STYLES): + case XML_ELEMENT(OFFICE, XML_DOCUMENT_CONTENT): + pContext = new SchXMLDocContext(*maImportHelper, *this, nElement); + break; + } + return pContext; +} + +SvXMLImportContext* SchXMLImport::CreateStylesContext() +{ + //#i103287# make sure that the version information is set before importing all the properties (especially stroke-opacity!) + SchXMLTools::setBuildIDAtImportInfo( GetModel(), getImportInfo() ); + + SvXMLStylesContext* pStylesCtxt = new SvXMLStylesContext( *this ); + + // set context at base class, so that all auto-style classes are imported + SetAutoStyles( pStylesCtxt ); + maImportHelper->SetAutoStylesContext( pStylesCtxt ); + + return pStylesCtxt; +} + +void SAL_CALL SchXMLImport::setTargetDocument(const uno::Reference& xDoc) +{ + uno::Reference xOldDoc(GetModel(), uno::UNO_QUERY); + if (xOldDoc.is() && xOldDoc->hasControllersLocked()) + xOldDoc->unlockControllers(); + + SvXMLImport::setTargetDocument(xDoc); + + uno::Reference xChartDoc(GetModel(), uno::UNO_QUERY); + + if (!xChartDoc.is()) + return; + try + { + // prevent rebuild of view during load (necessary especially if loaded not + // via load api, which is the case for example if binary files are loaded) + xChartDoc->lockControllers(); + + uno::Reference xChild(xChartDoc, uno::UNO_QUERY); + uno::Reference xDataReceiver(xChartDoc, uno::UNO_QUERY); + if (xChild.is() && xDataReceiver.is()) + { + Reference xFact(xChild->getParent(), uno::UNO_QUERY); + if (xFact.is()) + { + //if the parent has a number formatter we will use the numberformatter of the parent + Reference xNumberFormatsSupplier(xFact, uno::UNO_QUERY); + xDataReceiver->attachNumberFormatsSupplier(xNumberFormatsSupplier); + } + } + } + catch (const uno::Exception &) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "SchXMLChartContext::StartElement(): Exception caught"); + } +} + +// first version: everything comes from one storage + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisImporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLImport(pCtx, "SchXMLImport", SvXMLImportFlags::ALL)); +} + +// multiple storage version: one for content / styles / meta + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisMetaImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLImport(pCtx, "SchXMLImport.Meta", SvXMLImportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisStylesImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLImport(pCtx, "SchXMLImport.Styles", SvXMLImportFlags::STYLES)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisContentImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLImport(pCtx, "SchXMLImport.Content", + SvXMLImportFlags::CONTENT | SvXMLImportFlags::AUTOSTYLES + | SvXMLImportFlags::FONTDECLS)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLLegendContext.cxx b/xmloff/source/chart/SchXMLLegendContext.cxx new file mode 100644 index 000000000..3427fa368 --- /dev/null +++ b/xmloff/source/chart/SchXMLLegendContext.cxx @@ -0,0 +1,220 @@ +/* -*- 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 "SchXMLLegendContext.hxx" +#include "SchXMLEnumConverter.hxx" + +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace ::xmloff::token; +using namespace com::sun::star; + +namespace +{ + +enum LegendAttributeTokens +{ + XML_TOK_LEGEND_POSITION, + XML_TOK_LEGEND_OVERLAY, + XML_TOK_LEGEND_X, + XML_TOK_LEGEND_Y, + XML_TOK_LEGEND_STYLE_NAME, + XML_TOK_LEGEND_EXPANSION, + XML_TOK_LEGEND_EXPANSION_ASPECT_RATIO, + XML_TOK_LEGEND_WIDTH, + XML_TOK_LEGEND_WIDTH_EXT, + XML_TOK_LEGEND_HEIGHT, + XML_TOK_LEGEND_HEIGHT_EXT +}; + +const SvXMLTokenMapEntry aLegendAttributeTokenMap[] = +{ + { XML_NAMESPACE_CHART, XML_LEGEND_POSITION, XML_TOK_LEGEND_POSITION }, + { XML_NAMESPACE_LO_EXT, XML_OVERLAY, XML_TOK_LEGEND_OVERLAY }, + { XML_NAMESPACE_SVG, XML_X, XML_TOK_LEGEND_X }, + { XML_NAMESPACE_SVG, XML_Y, XML_TOK_LEGEND_Y }, + { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_LEGEND_STYLE_NAME }, + { XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION, XML_TOK_LEGEND_EXPANSION }, + { XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION_ASPECT_RATIO, XML_TOK_LEGEND_EXPANSION_ASPECT_RATIO }, + { XML_NAMESPACE_SVG, XML_WIDTH, XML_TOK_LEGEND_WIDTH }, + { XML_NAMESPACE_CHART_EXT, XML_WIDTH, XML_TOK_LEGEND_WIDTH_EXT }, + { XML_NAMESPACE_SVG, XML_HEIGHT, XML_TOK_LEGEND_HEIGHT }, + { XML_NAMESPACE_CHART_EXT, XML_HEIGHT, XML_TOK_LEGEND_HEIGHT_EXT }, + XML_TOKEN_MAP_END +}; + +class LegendAttributeTokenMap : public SvXMLTokenMap +{ +public: + LegendAttributeTokenMap(): SvXMLTokenMap( aLegendAttributeTokenMap ) {} + virtual ~LegendAttributeTokenMap() {} +}; + +//a LegendAttributeTokenMap Singleton +struct theLegendAttributeTokenMap : public rtl::Static< LegendAttributeTokenMap, theLegendAttributeTokenMap > {}; + +}//end anonymous namespace + +SchXMLLegendContext::SchXMLLegendContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, const OUString& rLocalName ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImpHelper ) +{ +} + +void SchXMLLegendContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + if( !xDoc.is() ) + return; + + // turn on legend + uno::Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY ); + if( xDocProp.is() ) + { + try + { + xDocProp->setPropertyValue("HasLegend", uno::makeAny( true ) ); + } + catch(const beans::UnknownPropertyException&) + { + SAL_INFO("xmloff.chart", "Property HasLegend not found" ); + } + } + + uno::Reference< drawing::XShape > xLegendShape = xDoc->getLegend(); + uno::Reference< beans::XPropertySet > xLegendProps( xLegendShape, uno::UNO_QUERY ); + if( !xLegendShape.is() || !xLegendProps.is() ) + { + SAL_INFO("xmloff.chart", "legend could not be created" ); + return; + } + + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + const SvXMLTokenMap& rAttrTokenMap = theLegendAttributeTokenMap::get(); + + awt::Point aLegendPos; + bool bOverlay = false; + bool bHasXPosition=false; + bool bHasYPosition=false; + awt::Size aLegendSize; + bool bHasWidth=false; + bool bHasHeight=false; + chart::ChartLegendExpansion nLegendExpansion = chart::ChartLegendExpansion_HIGH; + bool bHasExpansion=false; + + OUString sAutoStyleName; + uno::Any aAny; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_LEGEND_POSITION: + try + { + if( SchXMLEnumConverter::getLegendPositionConverter().importXML( aValue, aAny, GetImport().GetMM100UnitConverter() ) ) + xLegendProps->setPropertyValue("Alignment", aAny ); + } + catch(const beans::UnknownPropertyException&) + { + SAL_INFO("xmloff.chart", "Property Alignment (legend) not found" ); + } + break; + case XML_TOK_LEGEND_OVERLAY: + try + { + bOverlay = xAttrList->getValueByIndex(i).toBoolean(); + xLegendProps->setPropertyValue("Overlay", uno::makeAny(bOverlay)); + } + catch(const beans::UnknownPropertyException&) + { + SAL_INFO("xmloff.chart", "Property Overlay (legend) not found" ); + } + break; + case XML_TOK_LEGEND_X: + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aLegendPos.X, aValue ); + bHasXPosition = true; + break; + case XML_TOK_LEGEND_Y: + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aLegendPos.Y, aValue ); + bHasYPosition = true; + break; + case XML_TOK_LEGEND_STYLE_NAME: + sAutoStyleName = aValue; + break; + case XML_TOK_LEGEND_EXPANSION: + SchXMLEnumConverter::getLegendPositionConverter().importXML( aValue, aAny, GetImport().GetMM100UnitConverter() ); + bHasExpansion = (aAny>>=nLegendExpansion); + break; + case XML_TOK_LEGEND_EXPANSION_ASPECT_RATIO: + break; + case XML_TOK_LEGEND_WIDTH: + case XML_TOK_LEGEND_WIDTH_EXT: + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aLegendSize.Width, aValue ); + bHasWidth = true; + break; + case XML_TOK_LEGEND_HEIGHT: + case XML_TOK_LEGEND_HEIGHT_EXT: + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aLegendSize.Height, aValue ); + bHasHeight = true; + break; + default: + break; + } + } + + if( bHasExpansion && nLegendExpansion!= chart::ChartLegendExpansion_CUSTOM ) + xLegendProps->setPropertyValue("Expansion", uno::makeAny(nLegendExpansion) ); + else if( bHasHeight && bHasWidth ) + xLegendShape->setSize( aLegendSize ); + + if( bHasXPosition && bHasYPosition ) + xLegendShape->setPosition( aLegendPos ); + + // the fill style has the default "none" in XML, but "solid" in the model. + xLegendProps->setPropertyValue("FillStyle", uno::makeAny( drawing::FillStyle_NONE )); + + // set auto-styles for Legend + mrImportHelper.FillAutoStyle(sAutoStyleName, xLegendProps); +} + +SchXMLLegendContext::~SchXMLLegendContext() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLLegendContext.hxx b/xmloff/source/chart/SchXMLLegendContext.hxx new file mode 100644 index 000000000..2d0c46981 --- /dev/null +++ b/xmloff/source/chart/SchXMLLegendContext.hxx @@ -0,0 +1,41 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLLEGENDCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLLEGENDCONTEXT_HXX + +#include + +#include +#include + +class SchXMLLegendContext : public SvXMLImportContext +{ +public: + SchXMLLegendContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, const OUString& rLocalName ); + virtual ~SchXMLLegendContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + SchXMLImportHelper& mrImportHelper; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLLEGENDCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLParagraphContext.cxx b/xmloff/source/chart/SchXMLParagraphContext.cxx new file mode 100644 index 000000000..9161cfad0 --- /dev/null +++ b/xmloff/source/chart/SchXMLParagraphContext.cxx @@ -0,0 +1,110 @@ +/* -*- 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 "SchXMLParagraphContext.hxx" + +#include +#include +#include +#include + +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +SchXMLParagraphContext::SchXMLParagraphContext( SvXMLImport& rImport, + const OUString& rLocalName, + OUString& rText, + OUString * pOutId /* = 0 */ ) : + SvXMLImportContext( rImport, XML_NAMESPACE_TEXT, rLocalName ), + mrText( rText ), + mpId( pOutId ) +{ +} + +SchXMLParagraphContext::~SchXMLParagraphContext() +{} + +void SchXMLParagraphContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // remember the id. It is used for storing the original cell range string in + // a local table (cached data) + if( mpId ) + { + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + bool bHaveXmlId( false ); + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if (IsXMLToken(aLocalName, XML_ID)) + { + if (nPrefix == XML_NAMESPACE_XML) + { + (*mpId) = xAttrList->getValueByIndex( i ); + bHaveXmlId = true; + } + if (nPrefix == XML_NAMESPACE_TEXT) + { // text:id shall be ignored if xml:id exists + if (!bHaveXmlId) + { + (*mpId) = xAttrList->getValueByIndex( i ); + } + } + } + } + } +} + +void SchXMLParagraphContext::EndElement() +{ + mrText = maBuffer.makeStringAndClear(); +} + +SvXMLImportContextRef SchXMLParagraphContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + if( nPrefix == XML_NAMESPACE_TEXT ) + { + if( rLocalName == ::xmloff::token::GetXMLToken( ::xmloff::token::XML_TAB_STOP )) + { + maBuffer.append( u'\x0009'); // tabulator + } + else if( rLocalName == ::xmloff::token::GetXMLToken( ::xmloff::token::XML_LINE_BREAK )) + { + maBuffer.append( u'\x000A'); // linefeed + } + } + + return nullptr; +} + +void SchXMLParagraphContext::Characters( const OUString& rChars ) +{ + maBuffer.append( rChars ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLParagraphContext.hxx b/xmloff/source/chart/SchXMLParagraphContext.hxx new file mode 100644 index 000000000..655e7e33b --- /dev/null +++ b/xmloff/source/chart/SchXMLParagraphContext.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLPARAGRAPHCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLPARAGRAPHCONTEXT_HXX + +#include +#include +#include + +namespace com::sun::star::xml::sax { + class XAttributeList; +} + +class SchXMLParagraphContext : public SvXMLImportContext +{ +private: + OUString& mrText; + OUString* mpId; + OUStringBuffer maBuffer; + +public: + SchXMLParagraphContext( SvXMLImport& rImport, + const OUString& rLocalName, + OUString& rText, + OUString * pOutId = nullptr ); + virtual ~SchXMLParagraphContext() override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void Characters( const OUString& rChars ) override; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLPARAGRAPHCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLPlotAreaContext.cxx b/xmloff/source/chart/SchXMLPlotAreaContext.cxx new file mode 100644 index 000000000..01fdcf769 --- /dev/null +++ b/xmloff/source/chart/SchXMLPlotAreaContext.cxx @@ -0,0 +1,1252 @@ +/* -*- 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 "SchXMLPlotAreaContext.hxx" +#include +#include "SchXMLAxisContext.hxx" +#include "SchXMLSeries2Context.hxx" +#include "SchXMLTools.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using com::sun::star::uno::Reference; + +namespace +{ + +struct lcl_AxisHasCategories +{ + bool operator() ( const SchXMLAxis & rAxis ) + { + return rAxis.bHasCategories; + } +}; + +OUString lcl_ConvertRange( const OUString & rRange, const uno::Reference< chart2::XChartDocument > & xDoc ) +{ + OUString aResult = rRange; + if(!xDoc.is()) + return aResult; + uno::Reference< chart2::data::XRangeXMLConversion > xConversion( + xDoc->getDataProvider(), uno::UNO_QUERY ); + if( xConversion.is()) + aResult = xConversion->convertRangeFromXML( rRange ); + return aResult; +} + +} // anonymous namespace + +SchXML3DSceneAttributesHelper::SchXML3DSceneAttributesHelper( SvXMLImport& rImporter ) + : SdXML3DSceneAttributesHelper( rImporter ) +{ +} + +void SchXML3DSceneAttributesHelper::getCameraDefaultFromDiagram( const uno::Reference< chart::XDiagram >& xDiagram ) +{ + //different defaults for camera geometry necessary to workaround wrong behaviour in old chart + //in future make this version dependent if we have versioning (metastream) for ole objects + + try + { + uno::Reference< beans::XPropertySet > xProp( xDiagram, uno::UNO_QUERY ); + if( xProp.is() ) + { + drawing::CameraGeometry aCamGeo; + xProp->getPropertyValue("D3DCameraGeometry") >>= aCamGeo; + maVRP.setX( aCamGeo.vrp.PositionX ); + maVRP.setY( aCamGeo.vrp.PositionY ); + maVRP.setZ( aCamGeo.vrp.PositionZ ); + maVPN.setX( aCamGeo.vpn.DirectionX ); + maVPN.setY( aCamGeo.vpn.DirectionY ); + maVPN.setZ( aCamGeo.vpn.DirectionZ ); + maVUP.setX( aCamGeo.vup.DirectionX ); + maVUP.setY( aCamGeo.vup.DirectionY ); + maVUP.setZ( aCamGeo.vup.DirectionZ ); + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property NumberOfLines"); + } +} + +SchXML3DSceneAttributesHelper::~SchXML3DSceneAttributesHelper() +{ +} + +SchXMLPlotAreaContext::SchXMLPlotAreaContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + const OUString& rXLinkHRefAttributeToIndicateDataProvider, + OUString& rCategoriesAddress, + OUString& rChartAddress, + bool & rbHasRangeAtPlotArea, + bool & rAllRangeAddressesAvailable, + bool & rColHasLabels, + bool & rRowHasLabels, + chart::ChartDataRowSource & rDataRowSource, + SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles, + const OUString& aChartTypeServiceName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + const awt::Size & rChartSize ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImpHelper ), + mrCategoriesAddress( rCategoriesAddress ), + mrSeriesDefaultsAndStyles( rSeriesDefaultsAndStyles ), + mnNumOfLinesProp( 0 ), + mbStockHasVolume( false ), + mnSeries( 0 ), + m_aGlobalSeriesImportInfo( rAllRangeAddressesAvailable ), + maSceneImportHelper( rImport ), + m_aOuterPositioning( rImport ), + m_aInnerPositioning( rImport ), + mbPercentStacked(false), + m_bAxisPositionAttributeImported(false), + m_rXLinkHRefAttributeToIndicateDataProvider(rXLinkHRefAttributeToIndicateDataProvider), + mrChartAddress( rChartAddress ), + m_rbHasRangeAtPlotArea( rbHasRangeAtPlotArea ), + mrColHasLabels( rColHasLabels ), + mrRowHasLabels( rRowHasLabels ), + mrDataRowSource( rDataRowSource ), + maChartTypeServiceName( aChartTypeServiceName ), + mrLSequencesPerIndex( rLSequencesPerIndex ), + mbGlobalChartTypeUsedBySeries( false ), + maChartSize( rChartSize ) +{ + m_rbHasRangeAtPlotArea = false; + + // get Diagram + uno::Reference< chart::XChartDocument > xDoc = rImpHelper.GetChartDocument(); + if( xDoc.is()) + { + mxDiagram = xDoc->getDiagram(); + mxNewDoc.set( xDoc, uno::UNO_QUERY ); + + maSceneImportHelper.getCameraDefaultFromDiagram( mxDiagram ); + } + SAL_WARN_IF( !mxDiagram.is(),"xmloff.chart", "Couldn't get XDiagram" ); + + // turn off all axes initially + uno::Any aFalseBool; + aFalseBool <<= false; + + uno::Reference< lang::XServiceInfo > xInfo( mxDiagram, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xProp( mxDiagram, uno::UNO_QUERY ); + if( xInfo.is() && + xProp.is()) + { + try + { + xProp->setPropertyValue("HasXAxis", aFalseBool ); + xProp->setPropertyValue("HasXAxisGrid", aFalseBool ); + xProp->setPropertyValue("HasXAxisDescription", aFalseBool ); + xProp->setPropertyValue("HasSecondaryXAxis", aFalseBool ); + xProp->setPropertyValue("HasSecondaryXAxisDescription", aFalseBool ); + + xProp->setPropertyValue("HasYAxis", aFalseBool ); + xProp->setPropertyValue("HasYAxisGrid", aFalseBool ); + xProp->setPropertyValue("HasYAxisDescription", aFalseBool ); + xProp->setPropertyValue("HasSecondaryYAxis", aFalseBool ); + xProp->setPropertyValue("HasSecondaryYAxisDescription", aFalseBool ); + + xProp->setPropertyValue("HasZAxis", aFalseBool ); + xProp->setPropertyValue("HasZAxisDescription", aFalseBool ); + + xProp->setPropertyValue("DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) ); + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property required by service not supported" ); + } + } +} + +SchXMLPlotAreaContext::~SchXMLPlotAreaContext() +{} + +void SchXMLPlotAreaContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetPlotAreaAttrTokenMap(); + uno::Reference< chart2::XChartDocument > xNewDoc( GetImport().GetModel(), uno::UNO_QUERY ); + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_PA_X: + case XML_TOK_PA_Y: + case XML_TOK_PA_WIDTH: + case XML_TOK_PA_HEIGHT: + m_aOuterPositioning.readPositioningAttribute( nPrefix, aLocalName, aValue ); + break; + case XML_TOK_PA_STYLE_NAME: + msAutoStyleName = aValue; + break; + case XML_TOK_PA_CHART_ADDRESS: + mrChartAddress = lcl_ConvertRange( aValue, xNewDoc ); + // indicator for getting data from the outside + m_rbHasRangeAtPlotArea = true; + break; + case XML_TOK_PA_DS_HAS_LABELS: + { + if( aValue == ::xmloff::token::GetXMLToken( ::xmloff::token::XML_BOTH )) + mrColHasLabels = mrRowHasLabels = true; + else if( aValue == ::xmloff::token::GetXMLToken( ::xmloff::token::XML_ROW )) + mrRowHasLabels = true; + else if( aValue == ::xmloff::token::GetXMLToken( ::xmloff::token::XML_COLUMN )) + mrColHasLabels = true; + } + break; + case XML_TOK_PA_TRANSFORM: + case XML_TOK_PA_VRP: + case XML_TOK_PA_VPN: + case XML_TOK_PA_VUP: + case XML_TOK_PA_PROJECTION: + case XML_TOK_PA_DISTANCE: + case XML_TOK_PA_FOCAL_LENGTH: + case XML_TOK_PA_SHADOW_SLANT: + case XML_TOK_PA_SHADE_MODE: + case XML_TOK_PA_AMBIENT_COLOR: + case XML_TOK_PA_LIGHTING_MODE: + maSceneImportHelper.processSceneAttribute( nPrefix, aLocalName, aValue ); + break; + } + } + + if( ! mxNewDoc.is()) + { + uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); + if( xDocProp.is()) + { + try + { + xDocProp->setPropertyValue("DataSourceLabelsInFirstColumn", uno::Any(mrColHasLabels) ); + xDocProp->setPropertyValue("DataSourceLabelsInFirstRow", uno::Any(mrRowHasLabels) ); + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Properties missing" ); + } + } + } + + // set properties + uno::Reference< beans::XPropertySet > xProp( mxDiagram, uno::UNO_QUERY ); + if( !msAutoStyleName.isEmpty()) + { + if( xProp.is()) + { + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + if( pStylesCtxt ) + { + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName ); + + XMLPropStyleContext* pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( pStyle ) ); + if( pPropStyleContext ) + { + pPropStyleContext->FillPropertySet( xProp ); + + // get the data row source that was set without having data + xProp->getPropertyValue("DataRowSource") + >>= mrDataRowSource; + + //lines on/off + //this old property is not supported fully anymore with the new chart, so we need to get the information a little bit different from similar properties + mrSeriesDefaultsAndStyles.maLinesOnProperty = SchXMLTools::getPropertyFromContext( + "Lines", pPropStyleContext, pStylesCtxt ); + + //handle automatic position and size + m_aOuterPositioning.readAutomaticPositioningProperties( pPropStyleContext, pStylesCtxt ); + + //correct default starting angle for old 3D pies + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan3_0( GetImport().GetModel() ) ) + { + bool bIs3d = false; + if( xProp.is() && ( xProp->getPropertyValue("Dim3D") >>= bIs3d ) && + bIs3d ) + { + if( maChartTypeServiceName == "com.sun.star.chart2.PieChartType" || maChartTypeServiceName == "com.sun.star.chart2.DonutChartType" ) + { + OUString aPropName( "StartingAngle" ); + uno::Any aAStartingAngle( SchXMLTools::getPropertyFromContext( aPropName, pPropStyleContext, pStylesCtxt ) ); + if( !aAStartingAngle.hasValue() ) + xProp->setPropertyValue( aPropName, uno::makeAny(sal_Int32(0)) ) ; + } + } + } + } + } + } + } + + //remember default values for dataseries + if(xProp.is()) + { + try + { + mrSeriesDefaultsAndStyles.maSymbolTypeDefault = xProp->getPropertyValue("SymbolType"); + mrSeriesDefaultsAndStyles.maDataCaptionDefault = xProp->getPropertyValue("DataCaption"); + + mrSeriesDefaultsAndStyles.maMeanValueDefault = xProp->getPropertyValue("MeanValue"); + mrSeriesDefaultsAndStyles.maRegressionCurvesDefault = xProp->getPropertyValue("RegressionCurves"); + + bool bStacked = false; + mrSeriesDefaultsAndStyles.maStackedDefault = xProp->getPropertyValue("Stacked"); + mrSeriesDefaultsAndStyles.maStackedDefault >>= bStacked; + mrSeriesDefaultsAndStyles.maPercentDefault = xProp->getPropertyValue("Percent"); + mrSeriesDefaultsAndStyles.maPercentDefault >>= mbPercentStacked; + mrSeriesDefaultsAndStyles.maStackedBarsConnectedDefault = xProp->getPropertyValue("StackedBarsConnected"); + + // deep + uno::Any aDeepProperty( xProp->getPropertyValue("Deep")); + // #124488# old versions store a 3d area and 3D line deep chart with Deep==false => workaround for this + if( ! (bStacked || mbPercentStacked )) + { + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) + { + bool bIs3d = false; + if( ( xProp->getPropertyValue("Dim3D") >>= bIs3d ) && + bIs3d ) + { + if( maChartTypeServiceName == "com.sun.star.chart2.AreaChartType" || maChartTypeServiceName == "com.sun.star.chart2.LineChartType" ) + { + aDeepProperty <<= true; + } + } + } + } + mrSeriesDefaultsAndStyles.maDeepDefault = aDeepProperty; + + xProp->getPropertyValue("NumberOfLines") >>= mnNumOfLinesProp; + xProp->getPropertyValue("Volume") >>= mbStockHasVolume; + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "PlotAreaContext:EndElement(): Exception caught"); + } + } // if + + bool bCreateInternalDataProvider = false; + if( m_rXLinkHRefAttributeToIndicateDataProvider == "." ) //data comes from the chart itself + bCreateInternalDataProvider = true; + else if( m_rXLinkHRefAttributeToIndicateDataProvider == ".." ) //data comes from the parent application + bCreateInternalDataProvider = false; + else if( !m_rXLinkHRefAttributeToIndicateDataProvider.isEmpty() ) //not supported so far to get the data by sibling objects -> fall back to chart itself + bCreateInternalDataProvider = true; + else if( !m_rbHasRangeAtPlotArea ) + bCreateInternalDataProvider = true; + + if( bCreateInternalDataProvider && mxNewDoc.is() ) + { + // we have no complete range => we have own data, so switch the data + // provider to internal. Clone is not necessary, as we don't have any + // data yet. + mxNewDoc->createInternalDataProvider( false /* bCloneExistingData */ ); + if( xProp.is() && mrDataRowSource!=chart::ChartDataRowSource_COLUMNS ) + xProp->setPropertyValue("DataRowSource", uno::makeAny(mrDataRowSource) ); + } +} + +SvXMLImportContextRef SchXMLPlotAreaContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + const SvXMLTokenMap& rTokenMap = mrImportHelper.GetPlotAreaElemTokenMap(); + + switch( rTokenMap.Get( nPrefix, rLocalName )) + { + case XML_TOK_PA_COORDINATE_REGION_EXT: + case XML_TOK_PA_COORDINATE_REGION: + { + pContext = new SchXMLCoordinateRegionContext( GetImport(), nPrefix, rLocalName, m_aInnerPositioning ); + } + break; + + case XML_TOK_PA_AXIS: + { + bool bAddMissingXAxisForNetCharts = false; + bool bAdaptWrongPercentScaleValues = false; + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) + { + //correct errors from older versions + + // for NetCharts there were no xAxis exported to older files + // so we need to add the x axis here for those old NetChart files + if ( maChartTypeServiceName == "com.sun.star.chart2.NetChartType" ) + bAddMissingXAxisForNetCharts = true; + + //Issue 59288 + if( mbPercentStacked ) + bAdaptWrongPercentScaleValues = true; + } + + bool bAdaptXAxisOrientationForOld2DBarCharts = false; + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_4( GetImport().GetModel() ) ) + { + //issue74660 + if ( maChartTypeServiceName == "com.sun.star.chart2.ColumnChartType" ) + bAdaptXAxisOrientationForOld2DBarCharts = true; + } + + pContext = new SchXMLAxisContext( mrImportHelper, GetImport(), rLocalName, mxDiagram, maAxes, mrCategoriesAddress, + bAddMissingXAxisForNetCharts, bAdaptWrongPercentScaleValues, bAdaptXAxisOrientationForOld2DBarCharts, m_bAxisPositionAttributeImported ); + } + break; + + case XML_TOK_PA_SERIES: + { + if( mxNewDoc.is()) + { + pContext = new SchXMLSeries2Context( + mrImportHelper, GetImport(), rLocalName, + mxNewDoc, maAxes, + mrSeriesDefaultsAndStyles.maSeriesStyleVector, + mrSeriesDefaultsAndStyles.maRegressionStyleVector, + mnSeries, + mbStockHasVolume, + m_aGlobalSeriesImportInfo, + maChartTypeServiceName, + mrLSequencesPerIndex, + mbGlobalChartTypeUsedBySeries, maChartSize ); + } + mnSeries++; + } + break; + + case XML_TOK_PA_WALL: + pContext = new SchXMLWallFloorContext( mrImportHelper, GetImport(), nPrefix, rLocalName, mxDiagram, + SchXMLWallFloorContext::CONTEXT_TYPE_WALL ); + break; + case XML_TOK_PA_FLOOR: + pContext = new SchXMLWallFloorContext( mrImportHelper, GetImport(), nPrefix, rLocalName, mxDiagram, + SchXMLWallFloorContext::CONTEXT_TYPE_FLOOR ); + break; + + case XML_TOK_PA_LIGHT_SOURCE: + pContext = maSceneImportHelper.create3DLightContext( nPrefix, rLocalName, xAttrList ); + break; + + // elements for stock charts + case XML_TOK_PA_STOCK_GAIN: + pContext = new SchXMLStockContext( mrImportHelper, GetImport(), nPrefix, rLocalName, mxDiagram, + SchXMLStockContext::CONTEXT_TYPE_GAIN ); + break; + case XML_TOK_PA_STOCK_LOSS: + pContext = new SchXMLStockContext( mrImportHelper, GetImport(), nPrefix, rLocalName, mxDiagram, + SchXMLStockContext::CONTEXT_TYPE_LOSS ); + break; + case XML_TOK_PA_STOCK_RANGE: + pContext = new SchXMLStockContext( mrImportHelper, GetImport(), nPrefix, rLocalName, mxDiagram, + SchXMLStockContext::CONTEXT_TYPE_RANGE ); + break; + } + + return pContext; +} + +void SchXMLPlotAreaContext::EndElement() +{ + // set categories + if( !mrCategoriesAddress.isEmpty() && mxNewDoc.is()) + { + uno::Reference< chart2::data::XDataProvider > xDataProvider( + mxNewDoc->getDataProvider() ); + // @todo: correct coordinate system index + sal_Int32 nDimension( 0 ); + ::std::vector< SchXMLAxis >::const_iterator aIt( + ::std::find_if( maAxes.begin(), maAxes.end(), lcl_AxisHasCategories())); + if( aIt != maAxes.end()) + nDimension = static_cast< sal_Int32 >( (*aIt).eDimension ); + SchXMLTools::CreateCategories( + xDataProvider, mxNewDoc, mrCategoriesAddress, + 0 /* nCooSysIndex */, + nDimension, &mrLSequencesPerIndex ); + } + + uno::Reference< beans::XPropertySet > xDiaProp( mxDiagram, uno::UNO_QUERY ); + if( xDiaProp.is()) + { + bool bIsThreeDim = false; + uno::Any aAny = xDiaProp->getPropertyValue("Dim3D"); + aAny >>= bIsThreeDim; + + // set 3d scene attributes + if( bIsThreeDim ) + { + // set scene attributes at diagram + maSceneImportHelper.setSceneAttributes( xDiaProp ); + } + + // set correct number of lines at series + if( ! m_aGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && mnNumOfLinesProp > 0 && maChartTypeServiceName == "com.sun.star.chart2.ColumnChartType" ) + { + try + { + xDiaProp->setPropertyValue("NumberOfLines", + uno::makeAny( mnNumOfLinesProp )); + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property NumberOfLines"); + } + } + + // #i32366# stock has volume + if( mxDiagram->getDiagramType() == "com.sun.star.chart.StockDiagram" && + mbStockHasVolume ) + { + try + { + xDiaProp->setPropertyValue("Volume", + uno::makeAny( true )); + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property Volume"); + } + } + } + + // set changed size and position after properties (esp. 3d) + + uno::Reference< chart::XDiagramPositioning > xDiaPos( mxDiagram, uno::UNO_QUERY ); + if( xDiaPos.is()) + { + if( !m_aOuterPositioning.isAutomatic() ) + { + if( m_aInnerPositioning.hasPosSize() ) + xDiaPos->setDiagramPositionExcludingAxes( m_aInnerPositioning.getRectangle() ); + else if( m_aOuterPositioning.hasPosSize() ) + { + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan3_3( GetImport().GetModel() ) ) //old version of OOo did write a wrong rectangle for the diagram size + xDiaPos->setDiagramPositionIncludingAxesAndAxisTitles( m_aOuterPositioning.getRectangle() ); + else + xDiaPos->setDiagramPositionIncludingAxes( m_aOuterPositioning.getRectangle() ); + } + } + } + + SchXMLAxisContext::CorrectAxisPositions( uno::Reference< chart2::XChartDocument >( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ), maChartTypeServiceName, GetImport().GetODFVersion(), m_bAxisPositionAttributeImported ); +} + +SchXMLDataLabelSpanContext::SchXMLDataLabelSpanContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels): + SvXMLImportContext( rImport, XML_NAMESPACE_TEXT, rLocalName), + mrLabels(rLabels) +{ +} + +void SchXMLDataLabelSpanContext::Characters(const OUString& rChars) +{ + maCharBuffer.append(rChars); +} + +void SchXMLDataLabelSpanContext::EndElement() +{ + mrLabels.push_back(maCharBuffer.makeStringAndClear()); +} + +SchXMLDataLabelParaContext::SchXMLDataLabelParaContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels): + SvXMLImportContext( rImport, XML_NAMESPACE_TEXT, rLocalName), + mrLabels(rLabels) +{ +} + +SvXMLImportContextRef SchXMLDataLabelParaContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContextRef xContext; + if ( IsXMLToken( rLocalName, XML_SPAN ) && nPrefix == XML_NAMESPACE_TEXT ) + xContext = new SchXMLDataLabelSpanContext(GetImport(), rLocalName, mrLabels); + return xContext; +} + +SchXMLDataLabelContext::SchXMLDataLabelContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels): + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName), + mrLabels(rLabels) +{ +} + +SvXMLImportContextRef SchXMLDataLabelContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContextRef xContext; + if ( IsXMLToken( rLocalName, XML_P ) && nPrefix == XML_NAMESPACE_TEXT ) + xContext = new SchXMLDataLabelParaContext(GetImport(), rLocalName, mrLabels); + + return xContext; +} + + +SchXMLDataPointContext::SchXMLDataPointContext( SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, const OUString& rLocalName, + ::std::vector< DataRowPointStyle >& rStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + sal_Int32& rIndex, + bool bSymbolSizeForSeriesIsMissingInFile ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImportHelper ), + mrStyleVector( rStyleVector ), + mrIndex( rIndex ), + mDataPoint(DataRowPointStyle::DATA_POINT, xSeries, rIndex, 1, OUString{}) +{ + mDataPoint.mbSymbolSizeForSeriesIsMissingInFile = bSymbolSizeForSeriesIsMissingInFile; +} + +SvXMLImportContextRef SchXMLDataPointContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContext* pContext = nullptr; + const SvXMLTokenMap& rTokenMap = mrImportHelper.GetSeriesElemTokenMap(); + + switch( rTokenMap.Get( nPrefix, rLocalName )) + { + case XML_TOK_SERIES_DATA_LABEL: + mbHasLabelParagraph = true; + pContext = new SchXMLDataLabelContext( GetImport(), rLocalName, mDataPoint.mCustomLabels); + break; + } + return pContext; +} + +SchXMLDataPointContext::~SchXMLDataPointContext() +{ +} + +void SchXMLDataPointContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + OUString sAutoStyleName; + sal_Int32 nRepeat = 1; + OUString sCustomLabelField; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + bool bHideLegend = false; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_CHART ) + { + if( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + { + sAutoStyleName = xAttrList->getValueByIndex( i ); + mDataPoint.msStyleName = sAutoStyleName; + } + else if( IsXMLToken( aLocalName, XML_REPEATED ) ) + { + nRepeat = xAttrList->getValueByIndex( i ).toInt32(); + mDataPoint.m_nPointRepeat = nRepeat; + } + } + else if( nPrefix == XML_NAMESPACE_LO_EXT) + { + // Deprecated. New documents use the chart:data-label element + // instead in order to store custom label text. + if( IsXMLToken( aLocalName, XML_CUSTOM_LABEL_FIELD) && !mbHasLabelParagraph) + { + sCustomLabelField = xAttrList->getValueByIndex( i ); + mDataPoint.mCustomLabels.push_back(sCustomLabelField); + } + else if (IsXMLToken(aLocalName, XML_HIDE_LEGEND)) + { + bHideLegend = xAttrList->getValueByIndex(i).toBoolean(); + if (bHideLegend) + { + uno::Sequence deletedLegendEntriesSeq; + Reference xSeriesProp(mDataPoint.m_xSeries, uno::UNO_QUERY); + xSeriesProp->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq; + std::vector deletedLegendEntries; + for (auto& deletedLegendEntry : deletedLegendEntriesSeq) + { + deletedLegendEntries.push_back(deletedLegendEntry); + } + deletedLegendEntries.push_back(mDataPoint.m_nPointIndex); + xSeriesProp->setPropertyValue("DeletedLegendEntries", uno::makeAny(::oox::ContainerHelper::vectorToSequence(deletedLegendEntries))); + } + } + else if( IsXMLToken(aLocalName, XML_CUSTOM_LABEL_POS_X ) ) + { + mDataPoint.mCustomLabelPos[0] = xAttrList->getValueByIndex(i).toDouble(); + } + else if( IsXMLToken(aLocalName, XML_CUSTOM_LABEL_POS_Y) ) + { + mDataPoint.mCustomLabelPos[1] = xAttrList->getValueByIndex(i).toDouble(); + } + } + } + + mrIndex += nRepeat; +} + +void SchXMLDataPointContext::EndElement() +{ + if( !mDataPoint.msStyleName.isEmpty() || mDataPoint.mCustomLabels.size() > 0) + { + mrStyleVector.push_back( mDataPoint ); + } +} + +SchXMLPositionAttributesHelper::SchXMLPositionAttributesHelper( SvXMLImport& rImporter ) + : m_rImport( rImporter ) + , m_aPosition(0,0) + , m_aSize(0,0) + , m_bHasSizeWidth( false ) + , m_bHasSizeHeight( false ) + , m_bHasPositionX( false ) + , m_bHasPositionY( false ) + , m_bAutoSize( false ) + , m_bAutoPosition( false ) +{ +} + +SchXMLPositionAttributesHelper::~SchXMLPositionAttributesHelper() +{ +} + +bool SchXMLPositionAttributesHelper::hasPosSize() const +{ + return (m_bHasPositionX && m_bHasPositionY) && (m_bHasSizeWidth && m_bHasSizeHeight); +} + +bool SchXMLPositionAttributesHelper::isAutomatic() const +{ + return m_bAutoSize || m_bAutoPosition; +} + +void SchXMLPositionAttributesHelper::readPositioningAttribute( sal_uInt16 nPrefix, const OUString& rLocalName, const OUString& rValue ) +{ + if( XML_NAMESPACE_SVG == nPrefix ) + { + if( IsXMLToken( rLocalName, XML_X ) ) + { + m_rImport.GetMM100UnitConverter().convertMeasureToCore( + m_aPosition.X, rValue ); + m_bHasPositionX = true; + } + else if( IsXMLToken( rLocalName, XML_Y ) ) + { + m_rImport.GetMM100UnitConverter().convertMeasureToCore( + m_aPosition.Y, rValue ); + m_bHasPositionY = true; + } + else if( IsXMLToken( rLocalName, XML_WIDTH ) ) + { + m_rImport.GetMM100UnitConverter().convertMeasureToCore( + m_aSize.Width, rValue ); + m_bHasSizeWidth = true; + } + else if( IsXMLToken( rLocalName, XML_HEIGHT ) ) + { + m_rImport.GetMM100UnitConverter().convertMeasureToCore( + m_aSize.Height, rValue ); + m_bHasSizeHeight = true; + } + } +} + +void SchXMLPositionAttributesHelper::readAutomaticPositioningProperties( XMLPropStyleContext const * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) +{ + if( pPropStyleContext && pStylesCtxt ) + { + //handle automatic position and size + SchXMLTools::getPropertyFromContext( + "AutomaticSize", pPropStyleContext, pStylesCtxt ) >>= m_bAutoSize; + SchXMLTools::getPropertyFromContext( + "AutomaticPosition", pPropStyleContext, pStylesCtxt ) >>= m_bAutoPosition; + } +} + +SchXMLCoordinateRegionContext::SchXMLCoordinateRegionContext( + SvXMLImport& rImport + , sal_uInt16 nPrefix + , const OUString& rLocalName + , SchXMLPositionAttributesHelper& rPositioning ) + : SvXMLImportContext( rImport, nPrefix, rLocalName ) + , m_rPositioning( rPositioning ) +{ +} + +SchXMLCoordinateRegionContext::~SchXMLCoordinateRegionContext() +{ +} + +void SchXMLCoordinateRegionContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + m_rPositioning.readPositioningAttribute( nPrefix, aLocalName, aValue ); + } +} + +SchXMLWallFloorContext::SchXMLWallFloorContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + uno::Reference< chart::XDiagram > const & xDiagram, + ContextType eContextType ) : + SvXMLImportContext( rImport, nPrefix, rLocalName ), + mrImportHelper( rImpHelper ), + mxWallFloorSupplier( xDiagram, uno::UNO_QUERY ), + meContextType( eContextType ) +{ +} + +SchXMLWallFloorContext::~SchXMLWallFloorContext() +{ +} + +void SchXMLWallFloorContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + if( mxWallFloorSupplier.is()) + { + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + OUString sAutoStyleName; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_CHART && + IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + { + sAutoStyleName = xAttrList->getValueByIndex( i ); + } + } + + // set properties + uno::Reference< beans::XPropertySet > xProp = ( meContextType == CONTEXT_TYPE_WALL ) + ? mxWallFloorSupplier->getWall() + : mxWallFloorSupplier->getFloor(); + + if (!sAutoStyleName.isEmpty()) + mrImportHelper.FillAutoStyle(sAutoStyleName, xProp); + } +} + +SchXMLStockContext::SchXMLStockContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + uno::Reference< chart::XDiagram > const & xDiagram, + ContextType eContextType ) : + SvXMLImportContext( rImport, nPrefix, rLocalName ), + mrImportHelper( rImpHelper ), + mxStockPropProvider( xDiagram, uno::UNO_QUERY ), + meContextType( eContextType ) +{ +} + +SchXMLStockContext::~SchXMLStockContext() +{ +} + +void SchXMLStockContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + if( mxStockPropProvider.is()) + { + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + OUString sAutoStyleName; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_CHART && + IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + { + sAutoStyleName = xAttrList->getValueByIndex( i ); + } + } + + if( !sAutoStyleName.isEmpty()) + { + // set properties + uno::Reference< beans::XPropertySet > xProp; + switch( meContextType ) + { + case CONTEXT_TYPE_GAIN: + xProp = mxStockPropProvider->getUpBar(); + break; + case CONTEXT_TYPE_LOSS: + xProp = mxStockPropProvider->getDownBar(); + break; + case CONTEXT_TYPE_RANGE: + xProp = mxStockPropProvider->getMinMaxLine(); + break; + } + + mrImportHelper.FillAutoStyle(sAutoStyleName, xProp); + } + } +} + +static void lcl_setErrorBarSequence ( const uno::Reference< chart2::XChartDocument > &xDoc, + const uno::Reference< beans::XPropertySet > &xBarProp, + const OUString &aXMLRange, + bool bPositiveValue, bool bYError, + tSchXMLLSequencesPerIndex& rSequences) +{ + uno::Reference< css::chart2::data::XDataProvider > xDataProvider(xDoc->getDataProvider()); + uno::Reference< css::chart2::data::XDataSource > xDataSource( xBarProp, uno::UNO_QUERY ); + uno::Reference< css::chart2::data::XDataSink > xDataSink( xDataSource, uno::UNO_QUERY ); + + assert( xDataSink.is() && xDataSource.is() && xDataProvider.is() ); + + OUString aRange(lcl_ConvertRange(aXMLRange,xDoc)); + + uno::Reference< chart2::data::XDataSequence > xNewSequence( + xDataProvider->createDataSequenceByRangeRepresentation( aRange )); + + if( !xNewSequence.is()) + return; + + SchXMLTools::setXMLRangePropertyAtDataSequence(xNewSequence,aXMLRange); + + OUStringBuffer aRoleBuffer("error-bars-"); + if( bYError ) + aRoleBuffer.append( 'y' ); + else + aRoleBuffer.append( 'x'); + + aRoleBuffer.append( '-' ); + + if( bPositiveValue ) + aRoleBuffer = aRoleBuffer.append( "positive" ); + else + aRoleBuffer = aRoleBuffer.append( "negative" ); + + OUString aRole = aRoleBuffer.makeStringAndClear(); + + Reference< beans::XPropertySet > xSeqProp( xNewSequence, uno::UNO_QUERY ); + + xSeqProp->setPropertyValue("Role", uno::makeAny( aRole )); + + Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + + Reference< chart2::data::XLabeledDataSequence > xLabelSeq( chart2::data::LabeledDataSequence::create(xContext), + uno::UNO_QUERY_THROW ); + + rSequences.emplace( tSchXMLIndexWithPart( -2, SCH_XML_PART_ERROR_BARS ), xLabelSeq ); + + xLabelSeq->setValues( xNewSequence ); + + uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( + xDataSource->getDataSequences()); + + aSequences.realloc( aSequences.getLength() + 1 ); + aSequences[ aSequences.getLength() - 1 ] = xLabelSeq; + xDataSink->setData( aSequences ); + +} + +SchXMLStatisticsObjectContext::SchXMLStatisticsObjectContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString &rSeriesStyleName, + ::std::vector< DataRowPointStyle >& rStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + ContextType eContextType, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex) : + + SvXMLImportContext( rImport, nPrefix, rLocalName ), + mrImportHelper( rImpHelper ), + mrStyleVector( rStyleVector ), + m_xSeries( xSeries ), + meContextType( eContextType ), + maSeriesStyleName( rSeriesStyleName), + mrLSequencesPerIndex(rLSequencesPerIndex) +{} + +SchXMLStatisticsObjectContext::~SchXMLStatisticsObjectContext() +{ +} + +namespace { + +void SetErrorBarStyleProperties( const OUString& rStyleName, const uno::Reference< beans::XPropertySet >& xBarProp, + SchXMLImportHelper const & rImportHelper ) +{ + const SvXMLStylesContext* pStylesCtxt = rImportHelper.GetAutoStylesContext(); + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(), + rStyleName); + + XMLPropStyleContext &rSeriesStyleContext = + const_cast< XMLPropStyleContext& >( dynamic_cast< const XMLPropStyleContext& >( *pStyle )); + + rSeriesStyleContext.FillPropertySet( xBarProp ); +} + +void SetErrorBarPropertiesFromStyleName( const OUString& aStyleName, const uno::Reference< beans::XPropertySet>& xBarProp, + SchXMLImportHelper const & rImportHelper, OUString& aPosRange, OUString& aNegRange) +{ + const SvXMLStylesContext* pStylesCtxt = rImportHelper.GetAutoStylesContext(); + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(), + aStyleName); + + XMLPropStyleContext * pSeriesStyleContext = + const_cast< XMLPropStyleContext * >( dynamic_cast< const XMLPropStyleContext * >( pStyle )); + + uno::Any aAny = SchXMLTools::getPropertyFromContext("ErrorBarStyle", + pSeriesStyleContext,pStylesCtxt); + + if ( !aAny.hasValue() ) + return; + + sal_Int32 aBarStyle = css::chart::ErrorBarStyle::NONE; + aAny >>= aBarStyle; + xBarProp->setPropertyValue("ErrorBarStyle", aAny); + + aAny = SchXMLTools::getPropertyFromContext("ShowPositiveError", + pSeriesStyleContext,pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("ShowPositiveError",aAny); + + aAny = SchXMLTools::getPropertyFromContext("ShowNegativeError", + pSeriesStyleContext,pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("ShowNegativeError",aAny); + + aAny = SchXMLTools::getPropertyFromContext("PositiveError", + pSeriesStyleContext, pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("PositiveError", aAny); + else + { + aAny = SchXMLTools::getPropertyFromContext("ConstantErrorHigh", + pSeriesStyleContext, pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("PositiveError", aAny); + } + + aAny = SchXMLTools::getPropertyFromContext("NegativeError", + pSeriesStyleContext, pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("NegativeError", aAny); + else + { + aAny = SchXMLTools::getPropertyFromContext("ConstantErrorLow", + pSeriesStyleContext, pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("NegativeError", aAny); + } + + aAny = SchXMLTools::getPropertyFromContext("ErrorBarRangePositive", + pSeriesStyleContext, pStylesCtxt); + if( aAny.hasValue() ) + { + aAny >>= aPosRange; + } + + aAny = SchXMLTools::getPropertyFromContext("ErrorBarRangeNegative", + pSeriesStyleContext, pStylesCtxt); + if( aAny.hasValue() ) + { + aAny >>= aNegRange; + } + + aAny = SchXMLTools::getPropertyFromContext("Weight", + pSeriesStyleContext, pStylesCtxt); + if( aAny.hasValue() ) + { + xBarProp->setPropertyValue("Weight", aAny); + } + + aAny = SchXMLTools::getPropertyFromContext("PercentageError", + pSeriesStyleContext, pStylesCtxt); + if( aAny.hasValue() && aBarStyle == css::chart::ErrorBarStyle::RELATIVE ) + { + xBarProp->setPropertyValue("PositiveError", aAny); + xBarProp->setPropertyValue("NegativeError", aAny); + } + + switch(aBarStyle) + { + case css::chart::ErrorBarStyle::ERROR_MARGIN: + { + aAny = SchXMLTools::getPropertyFromContext("NegativeError", + pSeriesStyleContext,pStylesCtxt); + + xBarProp->setPropertyValue("NegativeError",aAny); + + aAny = SchXMLTools::getPropertyFromContext("PositiveError", + pSeriesStyleContext,pStylesCtxt); + + xBarProp->setPropertyValue("PositiveError",aAny); + } + break; + default: + break; + } + +} + +} + +void SchXMLStatisticsObjectContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + OUString sAutoStyleName; + OUString aPosRange; + OUString aNegRange; + bool bYError = true; /// Default errorbar, to be backward compatible with older files! + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_CHART ) + { + if( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + sAutoStyleName = xAttrList->getValueByIndex( i ); + else if( IsXMLToken( aLocalName, XML_DIMENSION ) ) + bYError = xAttrList->getValueByIndex(i) == "y"; + else if( IsXMLToken( aLocalName, XML_ERROR_UPPER_RANGE) ) + aPosRange = xAttrList->getValueByIndex(i); + else if( IsXMLToken( aLocalName, XML_ERROR_LOWER_RANGE) ) + aNegRange = xAttrList->getValueByIndex(i); + } + } + + if( !sAutoStyleName.isEmpty() ) + { + DataRowPointStyle aStyle( DataRowPointStyle::MEAN_VALUE, m_xSeries, -1, 1, sAutoStyleName ); + + switch( meContextType ) + { + case CONTEXT_TYPE_MEAN_VALUE_LINE: + aStyle.meType = DataRowPointStyle::MEAN_VALUE; + break; + case CONTEXT_TYPE_ERROR_INDICATOR: + { + aStyle.meType = DataRowPointStyle::ERROR_INDICATOR; + + uno::Reference< lang::XMultiServiceFactory > xFact = comphelper::getProcessServiceFactory(); + + uno::Reference< beans::XPropertySet > xBarProp( xFact->createInstance("com.sun.star.chart2.ErrorBar" ), + uno::UNO_QUERY ); + + xBarProp->setPropertyValue("ErrorBarStyle",uno::makeAny(css::chart::ErrorBarStyle::NONE)); + xBarProp->setPropertyValue("PositiveError",uno::makeAny(0.0)); + xBarProp->setPropertyValue("NegativeError",uno::makeAny(0.0)); + xBarProp->setPropertyValue("Weight",uno::makeAny(1.0)); + xBarProp->setPropertyValue("ShowPositiveError",uno::makeAny(true)); + xBarProp->setPropertyValue("ShowNegativeError",uno::makeAny(true)); + + // first import defaults from parent style + SetErrorBarStyleProperties( maSeriesStyleName, xBarProp, mrImportHelper ); + SetErrorBarStyleProperties( sAutoStyleName, xBarProp, mrImportHelper ); + SetErrorBarPropertiesFromStyleName( maSeriesStyleName, xBarProp, mrImportHelper, aPosRange, aNegRange ); + SetErrorBarPropertiesFromStyleName( sAutoStyleName, xBarProp, mrImportHelper, aPosRange, aNegRange ); + + uno::Reference< chart2::XChartDocument > xDoc(GetImport().GetModel(),uno::UNO_QUERY); + + if (!aPosRange.isEmpty()) + lcl_setErrorBarSequence(xDoc,xBarProp,aPosRange,true,bYError, mrLSequencesPerIndex); + + if (!aNegRange.isEmpty()) + lcl_setErrorBarSequence(xDoc,xBarProp,aNegRange,false,bYError, mrLSequencesPerIndex); + + if ( !bYError ) + { + aStyle.m_xErrorXProperties.set( xBarProp ); + } + else + { + aStyle.m_xErrorYProperties.set( xBarProp ); + } + } + break; + } + + mrStyleVector.push_back( aStyle ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLPlotAreaContext.hxx b/xmloff/source/chart/SchXMLPlotAreaContext.hxx new file mode 100644 index 000000000..1541c4ef6 --- /dev/null +++ b/xmloff/source/chart/SchXMLPlotAreaContext.hxx @@ -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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLPLOTAREACONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLPLOTAREACONTEXT_HXX + +#include "SchXMLChartContext.hxx" +#include +#include +#include +#include +#include +#include + +#include "transporttypes.hxx" + +class SvXMLImport; + +namespace com::sun::star { + namespace chart { + class XDiagram; + class X3DDisplay; + class XStatisticDisplay; + } + namespace chart2 { + class XChartDocument; + } + namespace xml::sax { + class XAttributeList; + } +} + +class SchXML3DSceneAttributesHelper : public SdXML3DSceneAttributesHelper +{ +public: + explicit SchXML3DSceneAttributesHelper( SvXMLImport& rImporter ); + virtual ~SchXML3DSceneAttributesHelper(); + + void getCameraDefaultFromDiagram( const css::uno::Reference< css::chart::XDiagram >& xDiagram ); +}; + +class SchXMLPositionAttributesHelper +{ +public: + explicit SchXMLPositionAttributesHelper( SvXMLImport& rImporter ); + ~SchXMLPositionAttributesHelper(); + + void readPositioningAttribute( sal_uInt16 nPrefix, const OUString& rLocalName, const OUString& rValue ); + void readAutomaticPositioningProperties( XMLPropStyleContext const * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ); + + bool hasPosSize() const; + bool isAutomatic() const; + css::awt::Rectangle getRectangle() const { return css::awt::Rectangle( m_aPosition.X, m_aPosition.Y, m_aSize.Width, m_aSize.Height );} + +private: + SvXMLImport& m_rImport; + + css::awt::Point m_aPosition; + css::awt::Size m_aSize; + + bool m_bHasSizeWidth; + bool m_bHasSizeHeight; + bool m_bHasPositionX; + bool m_bHasPositionY; + bool m_bAutoSize; + bool m_bAutoPosition; +}; + +class SchXMLPlotAreaContext : public SvXMLImportContext +{ +public: + SchXMLPlotAreaContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + const OUString& rXLinkHRefAttributeToIndicateDataProvider, + OUString& rCategoriesAddress, + OUString& rChartAddress, + bool& bHasRangeAtPlotArea, + bool & rAllRangeAddressesAvailable, + bool & rColHasLabels, + bool & rRowHasLabels, + css::chart::ChartDataRowSource & rDataRowSource, + SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles, + const OUString& aChartTypeServiceName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + const css::awt::Size & rChartSize ); + virtual ~SchXMLPlotAreaContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + +private: + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart::XDiagram > mxDiagram; + css::uno::Reference< css::chart2::XChartDocument > mxNewDoc; + ::std::vector< SchXMLAxis > maAxes; + OUString& mrCategoriesAddress; + SeriesDefaultsAndStyles& mrSeriesDefaultsAndStyles; + sal_Int32 mnNumOfLinesProp; + bool mbStockHasVolume; + sal_Int32 mnSeries; + GlobalSeriesImportInfo m_aGlobalSeriesImportInfo; + + SchXML3DSceneAttributesHelper maSceneImportHelper; + SchXMLPositionAttributesHelper m_aOuterPositioning;//including axes and axes titles + SchXMLPositionAttributesHelper m_aInnerPositioning;//excluding axes and axes titles + bool mbPercentStacked; + bool m_bAxisPositionAttributeImported; + OUString msAutoStyleName; + const OUString& m_rXLinkHRefAttributeToIndicateDataProvider; + OUString& mrChartAddress; + bool& m_rbHasRangeAtPlotArea; + bool & mrColHasLabels; + bool & mrRowHasLabels; + css::chart::ChartDataRowSource & mrDataRowSource; + OUString maChartTypeServiceName; + + tSchXMLLSequencesPerIndex & mrLSequencesPerIndex; + + bool mbGlobalChartTypeUsedBySeries; + css::awt::Size maChartSize; +}; + +class SchXMLDataLabelSpanContext: public SvXMLImportContext +{ +private: + ::std::vector& mrLabels; + OUStringBuffer maCharBuffer; +public: + SchXMLDataLabelSpanContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels); + virtual void Characters( const OUString& rChars ) override; + virtual void EndElement() override; +}; + +class SchXMLDataLabelParaContext: public SvXMLImportContext +{ +private: + ::std::vector& mrLabels; +public: + SchXMLDataLabelParaContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels); + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +class SchXMLDataLabelContext: public SvXMLImportContext +{ +private: + ::std::vector& mrLabels; +public: + SchXMLDataLabelContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels); + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +class SchXMLDataPointContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + ::std::vector< DataRowPointStyle >& mrStyleVector; + bool mbHasLabelParagraph = false; + sal_Int32& mrIndex; + DataRowPointStyle mDataPoint; + +public: + SchXMLDataPointContext( SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, const OUString& rLocalName, + ::std::vector< DataRowPointStyle >& rStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + sal_Int32& rIndex, + bool bSymbolSizeForSeriesIsMissingInFile ); + virtual ~SchXMLDataPointContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +class SchXMLCoordinateRegionContext : public SvXMLImportContext +{ +public: + SchXMLCoordinateRegionContext( + SvXMLImport& rImport + , sal_uInt16 nPrefix + , const OUString& rLocalName + , SchXMLPositionAttributesHelper& rPositioning ); + virtual ~SchXMLCoordinateRegionContext() override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + SchXMLPositionAttributesHelper& m_rPositioning; +}; + +class SchXMLWallFloorContext : public SvXMLImportContext +{ +public: + enum ContextType + { + CONTEXT_TYPE_WALL, + CONTEXT_TYPE_FLOOR + }; + +private: + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart::X3DDisplay > mxWallFloorSupplier; + ContextType meContextType; + +public: + SchXMLWallFloorContext( SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + css::uno::Reference< css::chart::XDiagram > const & xDiagram, + ContextType eContextType ); + virtual ~SchXMLWallFloorContext() override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +class SchXMLStockContext : public SvXMLImportContext +{ +public: + enum ContextType + { + CONTEXT_TYPE_GAIN, + CONTEXT_TYPE_LOSS, + CONTEXT_TYPE_RANGE + }; + +private: + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart::XStatisticDisplay > mxStockPropProvider; + ContextType meContextType; + +public: + SchXMLStockContext( SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + css::uno::Reference< css::chart::XDiagram > const & xDiagram, + ContextType eContextType ); + virtual ~SchXMLStockContext() override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +class SchXMLStatisticsObjectContext : public SvXMLImportContext +{ +public: + enum ContextType + { + CONTEXT_TYPE_MEAN_VALUE_LINE, + CONTEXT_TYPE_ERROR_INDICATOR + }; + + SchXMLStatisticsObjectContext( + SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString &rSeriesStyleName, + ::std::vector< DataRowPointStyle >& rStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + ContextType eContextType, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex ); + + virtual ~SchXMLStatisticsObjectContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + SchXMLImportHelper & mrImportHelper; + ::std::vector< DataRowPointStyle > & mrStyleVector; + css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + ContextType meContextType; + OUString maSeriesStyleName; + tSchXMLLSequencesPerIndex& mrLSequencesPerIndex; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLPLOTAREACONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLPropertyMappingContext.cxx b/xmloff/source/chart/SchXMLPropertyMappingContext.cxx new file mode 100644 index 000000000..688cfd752 --- /dev/null +++ b/xmloff/source/chart/SchXMLPropertyMappingContext.cxx @@ -0,0 +1,118 @@ +/* -*- 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 "SchXMLPropertyMappingContext.hxx" +#include "SchXMLTools.hxx" +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace com::sun::star::uno; + +namespace { + +Reference< chart2::data::XLabeledDataSequence2 > createAndAddSequenceToSeries( const OUString& rRole + , const OUString& rRange + , const Reference< chart2::XChartDocument >& xChartDoc + , const Reference< chart2::XDataSeries >& xSeries ) +{ + Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq; + + Reference< chart2::data::XDataSource > xSeriesSource( xSeries,uno::UNO_QUERY ); + + if( !(!rRange.isEmpty() && xChartDoc.is() && xSeriesSource.is()) ) + return xLabeledSeq; + + // create a new sequence + xLabeledSeq = SchXMLTools::GetNewLabeledDataSequence(); + + // set values at the new sequence + Reference< chart2::data::XDataSequence > xSeq = SchXMLTools::CreateDataSequence( rRange, xChartDoc ); + Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY ); + if( xSeqProp.is()) + xSeqProp->setPropertyValue("Role", uno::makeAny( rRole)); + xLabeledSeq->setValues( xSeq ); + + Reference< chart2::data::XDataSink > xSink( xSeriesSource, uno::UNO_QUERY ); + if( xSink.is()) + { + Sequence< Reference< chart2::data::XLabeledDataSequence > > aData( xSeriesSource->getDataSequences()); + aData.realloc( aData.getLength() + 1 ); + aData[ aData.getLength() - 1 ] = xLabeledSeq; + xSink->setData( aData ); + } + + return xLabeledSeq; +} + +} + +SchXMLPropertyMappingContext::SchXMLPropertyMappingContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + uno::Reference< + chart2::XDataSeries > const & xSeries ): + SvXMLImportContext( rImport, XML_NAMESPACE_LO_EXT, rLocalName ), + mrImportHelper( rImpHelper ), + mxDataSeries(xSeries), + mrLSequencesPerIndex(rLSequencesPerIndex) +{ + +} + +SchXMLPropertyMappingContext::~SchXMLPropertyMappingContext() +{ +} + +void SchXMLPropertyMappingContext::StartElement(const uno::Reference< xml::sax::XAttributeList>& xAttrList ) +{ + OUString aRange; + OUString aRole; + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetPropMappingAttrTokenMap(); + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_PROPERTY_MAPPING_PROPERTY: + aRole = aValue; + break; + case XML_TOK_PROPERTY_MAPPING_RANGE: + aRange = aValue; + break; + } + } + + if( !aRange.isEmpty() && !aRole.isEmpty() ) + { + Reference< chart2::XChartDocument > xChartDoc( GetImport().GetModel(), uno::UNO_QUERY ); + Reference< chart2::data::XLabeledDataSequence2 > xSeq = + createAndAddSequenceToSeries(aRole, aRange, xChartDoc, mxDataSeries); + mrLSequencesPerIndex.emplace( + tSchXMLIndexWithPart( 0, SCH_XML_PART_VALUES), + xSeq); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLPropertyMappingContext.hxx b/xmloff/source/chart/SchXMLPropertyMappingContext.hxx new file mode 100644 index 000000000..4206ed911 --- /dev/null +++ b/xmloff/source/chart/SchXMLPropertyMappingContext.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/. + */ + +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLPROPERTYMAPPINGCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLPROPERTYMAPPINGCONTEXT_HXX + +#include "transporttypes.hxx" +#include +#include + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + class XDataSeries; + } +} + +class SchXMLPropertyMappingContext : public SvXMLImportContext +{ +public: + + SchXMLPropertyMappingContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + tSchXMLLSequencesPerIndex& rLSequencesPerIndex, + css::uno::Reference< + css::chart2::XDataSeries > const & xSeries ); + + virtual ~SchXMLPropertyMappingContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +private: + + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart2::XDataSeries > mxDataSeries; + + tSchXMLLSequencesPerIndex& mrLSequencesPerIndex; + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLRegressionCurveObjectContext.cxx b/xmloff/source/chart/SchXMLRegressionCurveObjectContext.cxx new file mode 100644 index 000000000..13a316864 --- /dev/null +++ b/xmloff/source/chart/SchXMLRegressionCurveObjectContext.cxx @@ -0,0 +1,199 @@ +/* -*- 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 "SchXMLRegressionCurveObjectContext.hxx" + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace xmloff::token; + +SchXMLRegressionCurveObjectContext::SchXMLRegressionCurveObjectContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + std::vector< RegressionStyle >& rRegressionStyleVector, + const css::uno::Reference< + css::chart2::XDataSeries >& xSeries, + const awt::Size & rChartSize) : + SvXMLImportContext( rImport, nPrefix, rLocalName ), + mrImportHelper( rImpHelper ), + mxSeries( xSeries ), + maChartSize( rChartSize ), + mrRegressionStyleVector( rRegressionStyleVector ) +{ +} + +SchXMLRegressionCurveObjectContext::~SchXMLRegressionCurveObjectContext() +{ +} + +void SchXMLRegressionCurveObjectContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttributeList ) +{ + sal_Int16 nAttributeCount = xAttributeList.is()? xAttributeList->getLength(): 0; + OUString sAutoStyleName; + + for( sal_Int16 i = 0; i < nAttributeCount; i++ ) + { + OUString sAttributeName = xAttributeList->getNameByIndex( i ); + OUString aLocalName; + + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttributeName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_CHART ) + { + if( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + { + sAutoStyleName = xAttributeList->getValueByIndex( i ); + } + } + } + + RegressionStyle aStyle( mxSeries, sAutoStyleName ); + mrRegressionStyleVector.push_back( aStyle ); +} + +SvXMLImportContextRef SchXMLRegressionCurveObjectContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContextRef xContext; + + if( nPrefix == XML_NAMESPACE_CHART && IsXMLToken( rLocalName, XML_EQUATION ) ) + { + xContext = new SchXMLEquationContext( + mrImportHelper, GetImport(), nPrefix, rLocalName, maChartSize, mrRegressionStyleVector.back()); + } + + return xContext; +} + +SchXMLEquationContext::SchXMLEquationContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const awt::Size& rChartSize, + RegressionStyle& rRegressionStyle ) : + + SvXMLImportContext( rImport, nPrefix, rLocalName ), + mrImportHelper( rImpHelper ), + mrRegressionStyle( rRegressionStyle ), + maChartSize( rChartSize ) +{} + +SchXMLEquationContext::~SchXMLEquationContext() +{} + +void SchXMLEquationContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + SchXMLImport& rImport = static_cast< SchXMLImport& >(GetImport()); + const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetRegEquationAttrTokenMap(); + OUString sAutoStyleName; + + bool bShowEquation = true; + bool bShowRSquare = false; + awt::Point aPosition; + bool bHasXPos = false; + bool bHasYPos = false; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_REGEQ_POS_X: + rImport.GetMM100UnitConverter().convertMeasureToCore( + aPosition.X, aValue ); + bHasXPos = true; + break; + case XML_TOK_REGEQ_POS_Y: + rImport.GetMM100UnitConverter().convertMeasureToCore( + aPosition.Y, aValue ); + bHasYPos = true; + break; + case XML_TOK_REGEQ_DISPLAY_EQUATION: + (void)::sax::Converter::convertBool(bShowEquation, aValue); + break; + case XML_TOK_REGEQ_DISPLAY_R_SQUARE: + (void)::sax::Converter::convertBool(bShowRSquare, aValue); + break; + case XML_TOK_REGEQ_STYLE_NAME: + sAutoStyleName = aValue; + break; + } + } + + if( !sAutoStyleName.isEmpty() || bShowEquation || bShowRSquare ) + { + uno::Reference< beans::XPropertySet > xEquationProperties = chart2::RegressionEquation::create( comphelper::getProcessComponentContext() ); + + if( !sAutoStyleName.isEmpty() ) + { + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + if( pStylesCtxt ) + { + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), sAutoStyleName ); + + XMLPropStyleContext* pPropStyleContext = + const_cast< XMLPropStyleContext* >( dynamic_cast< const XMLPropStyleContext* >( pStyle )); + + if( pPropStyleContext ) + pPropStyleContext->FillPropertySet( xEquationProperties ); + } + } + xEquationProperties->setPropertyValue( "ShowEquation", uno::makeAny( bShowEquation )); + xEquationProperties->setPropertyValue( "ShowCorrelationCoefficient", uno::makeAny( bShowRSquare )); + + if( bHasXPos && bHasYPos ) + { + chart2::RelativePosition aRelPos; + aRelPos.Primary = static_cast< double >( aPosition.X ) / static_cast< double >( maChartSize.Width ); + aRelPos.Secondary = static_cast< double >( aPosition.Y ) / static_cast< double >( maChartSize.Height ); + xEquationProperties->setPropertyValue( "RelativePosition", uno::makeAny( aRelPos )); + } + mrRegressionStyle.m_xEquationProperties.set( xEquationProperties ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLRegressionCurveObjectContext.hxx b/xmloff/source/chart/SchXMLRegressionCurveObjectContext.hxx new file mode 100644 index 000000000..c9f13f4e5 --- /dev/null +++ b/xmloff/source/chart/SchXMLRegressionCurveObjectContext.hxx @@ -0,0 +1,79 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLREGRESSIONCURVEOBJECTCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLREGRESSIONCURVEOBJECTCONTEXT_HXX + +#include +#include +#include + +#include "transporttypes.hxx" + +class SchXMLRegressionCurveObjectContext : public SvXMLImportContext +{ +public: + SchXMLRegressionCurveObjectContext( + SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + std::vector< RegressionStyle >& rRegressionStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + const css::awt::Size & rChartSize ); + + virtual ~SchXMLRegressionCurveObjectContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + + SchXMLImportHelper& mrImportHelper; + css::uno::Reference mxSeries; + css::awt::Size maChartSize; + std::vector< RegressionStyle >& mrRegressionStyleVector; +}; + +class SchXMLEquationContext : public SvXMLImportContext +{ +public: + SchXMLEquationContext( + SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::awt::Size & rChartSize, + RegressionStyle & rRegressionStyle ); + + virtual ~SchXMLEquationContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + SchXMLImportHelper& mrImportHelper; + RegressionStyle& mrRegressionStyle; + css::awt::Size maChartSize; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLREGRESSIONCURVEOBJECTCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLSeries2Context.cxx b/xmloff/source/chart/SchXMLSeries2Context.cxx new file mode 100644 index 000000000..eb743022f --- /dev/null +++ b/xmloff/source/chart/SchXMLSeries2Context.cxx @@ -0,0 +1,1188 @@ +/* -*- 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 "SchXMLSeries2Context.hxx" +#include "SchXMLPlotAreaContext.hxx" +#include "SchXMLRegressionCurveObjectContext.hxx" +#include "SchXMLPropertyMappingContext.hxx" +#include "SchXMLTools.hxx" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +class SchXMLDomain2Context : public SvXMLImportContext +{ +private: + ::std::vector< OUString > & mrAddresses; + +public: + SchXMLDomain2Context( SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + ::std::vector< OUString > & rAddresses ); + virtual void StartElement( const Reference< xml::sax::XAttributeList >& xAttrList ) override; +}; + +SchXMLDomain2Context::SchXMLDomain2Context( + SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + ::std::vector< OUString > & rAddresses ) : + SvXMLImportContext( rImport, nPrefix, rLocalName ), + mrAddresses( rAddresses ) +{ +} + +void SchXMLDomain2Context::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_TABLE && + IsXMLToken( aLocalName, XML_CELL_RANGE_ADDRESS ) ) + { + mrAddresses.push_back( xAttrList->getValueByIndex( i )); + } + } +} + +void lcl_setAutomaticSymbolSize( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport ) +{ + awt::Size aSymbolSize(140,140);//old default for standard sized charts 7cm height + + uno::Reference< chart::XChartDocument > xChartDoc( rImport.GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is() ) + { + double fScale = 1; + uno::Reference< beans::XPropertySet > xLegendProp( xChartDoc->getLegend(), uno::UNO_QUERY ); + chart::ChartLegendPosition aLegendPosition = chart::ChartLegendPosition_NONE; + if( xLegendProp.is() && (xLegendProp->getPropertyValue("Alignment") >>= aLegendPosition) + && chart::ChartLegendPosition_NONE != aLegendPosition ) + { + + double fFontHeight = 6.0; + if( xLegendProp->getPropertyValue("CharHeight") >>= fFontHeight ) + fScale = 0.75*fFontHeight/6.0; + } + else + { + uno::Reference< embed::XVisualObject > xVisualObject( rImport.GetModel(), uno::UNO_QUERY ); + if( xVisualObject.is() ) + { + awt::Size aPageSize( xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) ); + fScale = aPageSize.Height/7000.0; + } + } + if( fScale>0 ) + { + aSymbolSize.Height = static_cast( fScale * aSymbolSize.Height ); + aSymbolSize.Width = aSymbolSize.Height; + } + } + xSeriesOrPointProp->setPropertyValue("SymbolSize",uno::makeAny( aSymbolSize )); +} + +void lcl_setSymbolSizeIfNeeded( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport ) +{ + if( !xSeriesOrPointProp.is() ) + return; + + sal_Int32 nSymbolType = chart::ChartSymbolType::NONE; + if( xSeriesOrPointProp.is() && ( xSeriesOrPointProp->getPropertyValue("SymbolType") >>= nSymbolType) ) + { + if(chart::ChartSymbolType::NONE!=nSymbolType) + { + if( chart::ChartSymbolType::BITMAPURL==nSymbolType ) + { + //set special size for graphics to indicate to use the bitmap size itself + xSeriesOrPointProp->setPropertyValue("SymbolSize",uno::makeAny( awt::Size(-1,-1) )); + } + else + { + lcl_setAutomaticSymbolSize( xSeriesOrPointProp, rImport ); + } + } + } +} + +void lcl_resetSymbolSizeForPointsIfNecessary( const uno::Reference< beans::XPropertySet >& xPointProp, const SvXMLImport& rImport + , const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) +{ + uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( "SymbolSize", pPropStyleContext, pStylesCtxt ) ); + if( !aASymbolSize.hasValue() ) + lcl_setSymbolSizeIfNeeded( xPointProp, rImport ); +} + +void lcl_setLinkNumberFormatToSourceIfNeeded( const uno::Reference< beans::XPropertySet >& xPointProp + , const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) +{ + uno::Any aAny( SchXMLTools::getPropertyFromContext("LinkNumberFormatToSource", pPropStyleContext, pStylesCtxt) ); + if( !aAny.hasValue() ) + { + if( !xPointProp.is() ) + return; + + bool bLinkToSource = false; + if( xPointProp.is() && (xPointProp->getPropertyValue("LinkNumberFormatToSource") >>= bLinkToSource) ) + { + if( bLinkToSource ) + { + xPointProp->setPropertyValue("LinkNumberFormatToSource", uno::makeAny(false)); + } + } + } +} + +void lcl_insertErrorBarLSequencesToMap( + tSchXMLLSequencesPerIndex & rInOutMap, + const uno::Reference< beans::XPropertySet > & xSeriesProp ) +{ + Reference< chart2::data::XDataSource > xErrorBarSource; + if( ( xSeriesProp->getPropertyValue( "ErrorBarY" ) >>= xErrorBarSource ) && + xErrorBarSource.is() ) + { + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSequences( + xErrorBarSource->getDataSequences()); + for( const auto& rLSequence : aLSequences ) + { + // use "0" as data index. This is ok, as it is not used for error bars + rInOutMap.emplace( + tSchXMLIndexWithPart( 0, SCH_XML_PART_ERROR_BARS ), rLSequence ); + } + } +} + +Reference< chart2::data::XLabeledDataSequence2 > lcl_createAndAddSequenceToSeries( const OUString& rRole + , const OUString& rRange + , const Reference< chart2::XChartDocument >& xChartDoc + , const Reference< chart2::XDataSeries >& xSeries ) +{ + Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq; + + Reference< chart2::data::XDataSource > xSeriesSource( xSeries,uno::UNO_QUERY ); + Reference< chart2::data::XDataSink > xSeriesSink( xSeries, uno::UNO_QUERY ); + + if( !(!rRange.isEmpty() && xChartDoc.is() && xSeriesSource.is() && xSeriesSink.is()) ) + return xLabeledSeq; + + // create a new sequence + xLabeledSeq = SchXMLTools::GetNewLabeledDataSequence(); + + // set values at the new sequence + Reference< chart2::data::XDataSequence > xSeq = SchXMLTools::CreateDataSequence( rRange, xChartDoc ); + Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY ); + if( xSeqProp.is()) + xSeqProp->setPropertyValue("Role", uno::makeAny( rRole)); + xLabeledSeq->setValues( xSeq ); + + // add new sequence to data series / push to front to have the correct sequence order if charttype is changed afterwards + Sequence< Reference< chart2::data::XLabeledDataSequence > > aOldSeq( xSeriesSource->getDataSequences()); + sal_Int32 nOldCount = aOldSeq.getLength(); + Sequence< Reference< chart2::data::XLabeledDataSequence > > aNewSeq( nOldCount + 1 ); + aNewSeq[0].set(xLabeledSeq, uno::UNO_QUERY_THROW); + std::copy(aOldSeq.begin(), aOldSeq.end(), std::next(aNewSeq.begin())); + xSeriesSink->setData( aNewSeq ); + + return xLabeledSeq; +} + +XMLPropStyleContext* lcl_GetStylePropContext( + const SvXMLStylesContext* pStylesCtxt, + const SvXMLStyleContext*& rpStyle, + OUString const & rStyleName ) +{ + rpStyle = pStylesCtxt->FindStyleChildContext( SchXMLImportHelper::GetChartFamilyID(), rStyleName ); + XMLPropStyleContext* pPropStyleContext = + const_cast< XMLPropStyleContext* >(dynamic_cast< const XMLPropStyleContext* >( rpStyle )); + return pPropStyleContext; +} + +} // anonymous namespace + +SchXMLSeries2Context::SchXMLSeries2Context( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + const Reference< chart2::XChartDocument > & xNewDoc, + std::vector< SchXMLAxis >& rAxes, + ::std::vector< DataRowPointStyle >& rStyleVector, + ::std::vector< RegressionStyle >& rRegressionStyleVector, + sal_Int32 nSeriesIndex, + bool bStockHasVolume, + GlobalSeriesImportInfo& rGlobalSeriesImportInfo, + const OUString & aGlobalChartTypeName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + bool& rGlobalChartTypeUsedBySeries, + const awt::Size & rChartSize ) : + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImpHelper ), + mxNewDoc( xNewDoc ), + mrAxes( rAxes ), + mrStyleVector( rStyleVector ), + mrRegressionStyleVector( rRegressionStyleVector ), + mnSeriesIndex( nSeriesIndex ), + mnDataPointIndex( 0 ), + m_bStockHasVolume( bStockHasVolume ), + m_rGlobalSeriesImportInfo(rGlobalSeriesImportInfo), + mpAttachedAxis( nullptr ), + mnAttachedAxis( 0 ), + maGlobalChartTypeName( aGlobalChartTypeName ), + maSeriesChartTypeName( aGlobalChartTypeName ), + m_bHasDomainContext(false), + mrLSequencesPerIndex( rLSequencesPerIndex ), + mrGlobalChartTypeUsedBySeries( rGlobalChartTypeUsedBySeries ), + mbSymbolSizeIsMissingInFile(false), + maChartSize( rChartSize ) +{ + if( aGlobalChartTypeName == "com.sun.star.chart2.DonutChartType" ) + { + maSeriesChartTypeName = "com.sun.star.chart2.PieChartType"; + maGlobalChartTypeName = maSeriesChartTypeName; + } +} + +SchXMLSeries2Context::~SchXMLSeries2Context() +{ + SAL_WARN_IF( !maPostponedSequences.empty(), "xmloff.chart", "maPostponedSequences is NULL"); +} + +void SchXMLSeries2Context::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // parse attributes + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetSeriesAttrTokenMap(); + mnAttachedAxis = 1; + + bool bHasRange = false; + OUString aSeriesLabelRange; + OUString aSeriesLabelString; + bool bHideLegend = false; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + OUString aValue = xAttrList->getValueByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_SERIES_CELL_RANGE: + m_aSeriesRange = aValue; + bHasRange = true; + break; + case XML_TOK_SERIES_LABEL_ADDRESS: + aSeriesLabelRange = aValue; + break; + case XML_TOK_SERIES_LABEL_STRING: + aSeriesLabelString = aValue; + break; + case XML_TOK_SERIES_ATTACHED_AXIS: + { + sal_Int32 nNumOfAxes = mrAxes.size(); + for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ ) + { + if( aValue == mrAxes[ nCurrent ].aName && + mrAxes[ nCurrent ].eDimension == SCH_XML_AXIS_Y ) + { + mpAttachedAxis = &( mrAxes[ nCurrent ] ); + } + } + } + break; + case XML_TOK_SERIES_STYLE_NAME: + msAutoStyleName = aValue; + break; + case XML_TOK_SERIES_CHART_CLASS: + { + OUString aClassName; + sal_uInt16 nClassPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + aValue, &aClassName ); + if( XML_NAMESPACE_CHART == nClassPrefix ) + maSeriesChartTypeName = SchXMLTools::GetChartTypeByClassName( aClassName, false /* bUseOldNames */ ); + + if( maSeriesChartTypeName.isEmpty()) + maSeriesChartTypeName = aClassName; + } + break; + case XML_TOK_SERIES_HIDE_LEGEND: + bHideLegend = aValue.toBoolean(); + break; + } + } + + if( mpAttachedAxis ) + { + if( mpAttachedAxis->nAxisIndex > 0 ) + { + // secondary axis => property has to be set (primary is default) + mnAttachedAxis = 2; + } + } + + try + { + SAL_WARN_IF( !mxNewDoc.is(), "xmloff.chart", "mxNewDoc is NULL"); + if( m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && ! bHasRange ) + m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable = false; + + bool bIsCandleStick = maGlobalChartTypeName == "com.sun.star.chart2.CandleStickChartType"; + if( !maSeriesChartTypeName.isEmpty() ) + { + bIsCandleStick = maSeriesChartTypeName == "com.sun.star.chart2.CandleStickChartType"; + } + else + { + if( bIsCandleStick + && m_bStockHasVolume + && mnSeriesIndex == 0 ) + { + maSeriesChartTypeName = "com.sun.star.chart2.ColumnChartType"; + bIsCandleStick = false; + } + else + { + maSeriesChartTypeName = maGlobalChartTypeName; + } + } + if( ! mrGlobalChartTypeUsedBySeries ) + mrGlobalChartTypeUsedBySeries = (maSeriesChartTypeName == maGlobalChartTypeName); + sal_Int32 const nCoordinateSystemIndex = 0;//so far we can only import one coordinate system + m_xSeries.set( + SchXMLImportHelper::GetNewDataSeries( mxNewDoc, nCoordinateSystemIndex, maSeriesChartTypeName, ! mrGlobalChartTypeUsedBySeries )); + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( SchXMLTools::GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW ); + + Reference< beans::XPropertySet > xSeriesProp( m_xSeries, uno::UNO_QUERY ); + if (xSeriesProp.is()) + { + if (bHideLegend) + xSeriesProp->setPropertyValue("ShowLegendEntry", uno::makeAny(false)); + + if( bIsCandleStick ) + { + // set default color for range-line to black (before applying styles) + xSeriesProp->setPropertyValue("Color", + uno::makeAny( sal_Int32( 0x000000 ))); // black + } + else if ( maSeriesChartTypeName == "com.sun.star.chart2.PieChartType" ) + { + //@todo: this property should be saved + xSeriesProp->setPropertyValue("VaryColorsByPoint", + uno::makeAny( true )); + } + + } + + Reference xDataProvider(mxNewDoc->getDataProvider()); + Reference xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); + + Reference xSequenceValues; + + // values + if (xPivotTableDataProvider.is()) // is pivot chart + { + xSequenceValues.set(xPivotTableDataProvider->createDataSequenceOfValuesByIndex(mnSeriesIndex)); + } + else + { + if (bHasRange && !m_aSeriesRange.isEmpty()) + xSequenceValues = SchXMLTools::CreateDataSequence(m_aSeriesRange, mxNewDoc); + } + + Reference xSeqProp(xSequenceValues, uno::UNO_QUERY); + if (xSeqProp.is()) + { + OUString aMainRole("values-y"); + if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType") + aMainRole = "values-size"; + xSeqProp->setPropertyValue("Role", uno::makeAny(aMainRole)); + } + xLabeledSeq->setValues(xSequenceValues); + + // register for setting local data if external data provider is not present + maPostponedSequences.emplace( + tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_VALUES ), xLabeledSeq ); + + // label + Reference xSequenceLabel; + + if (xPivotTableDataProvider.is()) + { + xSequenceLabel.set(xPivotTableDataProvider->createDataSequenceOfLabelsByIndex(mnSeriesIndex)); + } + else + { + if (!aSeriesLabelRange.isEmpty()) + { + xSequenceLabel.set(SchXMLTools::CreateDataSequence(aSeriesLabelRange, mxNewDoc)); + } + else if (!aSeriesLabelString.isEmpty()) + { + xSequenceLabel.set(SchXMLTools::CreateDataSequenceWithoutConvert(aSeriesLabelString, mxNewDoc)); + } + } + xLabeledSeq->setLabel(xSequenceLabel); + + // Note: Even if we have no label, we have to register the label + // for creation, because internal data always has labels. If + // they don't exist in the original, auto-generated labels are + // used for the internal data. + maPostponedSequences.emplace( + tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_LABEL ), xLabeledSeq ); + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( &xLabeledSeq, 1 ); + Reference< chart2::data::XDataSink > xSink( m_xSeries, uno::UNO_QUERY_THROW ); + xSink->setData( aSeq ); + } + catch( const uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + + //init mbSymbolSizeIsMissingInFile: + try + { + if( !msAutoStyleName.isEmpty() ) + { + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + if( pStylesCtxt ) + { + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName ); + + const XMLPropStyleContext* pPropStyleContext = dynamic_cast< const XMLPropStyleContext * >( pStyle ); + + uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( "SymbolSize" + , pPropStyleContext, pStylesCtxt ) ); + mbSymbolSizeIsMissingInFile = !aASymbolSize.hasValue(); + } + } + } + catch( const uno::Exception & ) + { + } +} + +namespace { + +struct DomainInfo +{ + DomainInfo( const OUString& rRole, const OUString& rRange, sal_Int32 nIndex ) + : aRole(rRole), aRange(rRange), nIndexForLocalData(nIndex) + {} + + OUString aRole; + OUString aRange; + sal_Int32 nIndexForLocalData; +}; + +} + +void SchXMLSeries2Context::EndElement() +{ + // special handling for different chart types. This is necessary as the + // roles are not yet saved in the file format + sal_Int32 nDomainCount = maDomainAddresses.size(); + bool bIsScatterChart = maSeriesChartTypeName == "com.sun.star.chart2.ScatterChartType"; + bool bIsBubbleChart = maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType"; + bool bDeleteSeries = false; + std::vector< DomainInfo > aDomainInfos; + + //different handling for different chart types necessary + if( bIsScatterChart || ( nDomainCount==1 && !bIsBubbleChart ) ) + { + DomainInfo aDomainInfo( "values-x", m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ; + bool bCreateXValues = true; + if( !maDomainAddresses.empty() ) + { + if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() ) + { + m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front(); + m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex; + } + aDomainInfo.aRange = maDomainAddresses.front(); + aDomainInfo.nIndexForLocalData = m_rGlobalSeriesImportInfo.nCurrentDataIndex; + m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + } + else if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() && !m_bHasDomainContext && mnSeriesIndex==0 ) + { + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) //wrong old chart files: + { + //for xy charts the first series needs to have a domain + //if this by error iss not the case the first series is taken s x values + //needed for wrong files created while having an addin (e.g. BoxPlot) + m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = m_aSeriesRange; + m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + bDeleteSeries = true; + bCreateXValues = false;//they will be created for the next series + } + } + if( bCreateXValues ) + aDomainInfos.push_back( aDomainInfo ); + } + else if( bIsBubbleChart ) + { + if( nDomainCount>1 ) + { + DomainInfo aDomainInfo( "values-x", maDomainAddresses[1], m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ; + if( m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() ) + { + //for bubble chart the second domain contains the x values which should become an index smaller than y values for own data table + //->so second first + m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress = maDomainAddresses[1]; + m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex; + } + aDomainInfos.push_back( aDomainInfo ); + m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + } + else if( !m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() ) + { + DomainInfo aDomainInfo( "values-x", m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress, m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex ) ; + aDomainInfos.push_back( aDomainInfo ); + } + if( nDomainCount>0) + { + DomainInfo aDomainInfo( "values-y", maDomainAddresses.front(), m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ; + if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() ) + { + m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front(); + m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex; + } + aDomainInfos.push_back( aDomainInfo ); + m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + } + else if( !m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() ) + { + DomainInfo aDomainInfo( "values-y", m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ; + aDomainInfos.push_back( aDomainInfo ); + } + } + + if( bDeleteSeries ) + { + //delete created series + SchXMLImportHelper::DeleteDataSeries( + m_xSeries, Reference< chart2::XChartDocument >( GetImport().GetModel(), uno::UNO_QUERY ) ); + } + else + { + //add style + if( !msAutoStyleName.isEmpty() || mnAttachedAxis != 1 ) + { + DataRowPointStyle aStyle( + DataRowPointStyle::DATA_SERIES, + m_xSeries, + -1, 1, + msAutoStyleName, mnAttachedAxis ); + aStyle.mbSymbolSizeForSeriesIsMissingInFile=mbSymbolSizeIsMissingInFile; + mrStyleVector.push_back( aStyle ); + } + } + + for( std::vector< DomainInfo >::reverse_iterator aIt( aDomainInfos.rbegin() ); aIt!= aDomainInfos.rend(); ++aIt ) + { + DomainInfo aDomainInfo( *aIt ); + Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq = + lcl_createAndAddSequenceToSeries( aDomainInfo.aRole, aDomainInfo.aRange, mxNewDoc, m_xSeries ); + if( xLabeledSeq.is() ) + { + // register for setting local data if external data provider is not present + mrLSequencesPerIndex.emplace( + tSchXMLIndexWithPart( aDomainInfo.nIndexForLocalData, SCH_XML_PART_VALUES ), + Reference< chart2::data::XLabeledDataSequence >(xLabeledSeq, uno::UNO_QUERY_THROW) ); + } + } + + if( !bDeleteSeries ) + { + for (auto const& postponedSequence : maPostponedSequences) + { + sal_Int32 nNewIndex = postponedSequence.first.first + nDomainCount; + mrLSequencesPerIndex.emplace( tSchXMLIndexWithPart( nNewIndex, postponedSequence.first.second ), postponedSequence.second ); + } + m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + } + maPostponedSequences.clear(); +} + +SvXMLImportContextRef SchXMLSeries2Context::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + const SvXMLTokenMap& rTokenMap = mrImportHelper.GetSeriesElemTokenMap(); + + switch( rTokenMap.Get( nPrefix, rLocalName )) + { + case XML_TOK_SERIES_DOMAIN: + if( m_xSeries.is()) + { + m_bHasDomainContext = true; + pContext = new SchXMLDomain2Context( + GetImport(), + nPrefix, rLocalName, + maDomainAddresses ); + } + break; + + case XML_TOK_SERIES_MEAN_VALUE_LINE: + pContext = new SchXMLStatisticsObjectContext( + mrImportHelper, GetImport(), + nPrefix, rLocalName, msAutoStyleName, + mrStyleVector, m_xSeries, + SchXMLStatisticsObjectContext::CONTEXT_TYPE_MEAN_VALUE_LINE, + mrLSequencesPerIndex ); + break; + case XML_TOK_SERIES_REGRESSION_CURVE: + pContext = new SchXMLRegressionCurveObjectContext( + mrImportHelper, GetImport(), + nPrefix, rLocalName, mrRegressionStyleVector, + m_xSeries, maChartSize ); + break; + case XML_TOK_SERIES_ERROR_INDICATOR: + pContext = new SchXMLStatisticsObjectContext( + mrImportHelper, GetImport(), + nPrefix, rLocalName, msAutoStyleName, + mrStyleVector, m_xSeries, + SchXMLStatisticsObjectContext::CONTEXT_TYPE_ERROR_INDICATOR, + mrLSequencesPerIndex ); + break; + + case XML_TOK_SERIES_DATA_POINT: + pContext = new SchXMLDataPointContext( mrImportHelper, GetImport(), rLocalName, + mrStyleVector, m_xSeries, mnDataPointIndex, mbSymbolSizeIsMissingInFile ); + break; + case XML_TOK_SERIES_PROPERTY_MAPPING: + pContext = new SchXMLPropertyMappingContext( mrImportHelper, + GetImport(), rLocalName, + mrLSequencesPerIndex, m_xSeries ); + break; + } + + return pContext; +} + +//static +void SchXMLSeries2Context::initSeriesPropertySets( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const uno::Reference< frame::XModel >& xChartModel ) +{ + // iterate over series first and remind propertysets in map + // new api <-> old api wrapper + ::std::map< Reference< chart2::XDataSeries >, Reference< beans::XPropertySet > > aSeriesMap; + for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES ) + continue; + + if( !seriesStyle.m_xOldAPISeries.is() ) + seriesStyle.m_xOldAPISeries = SchXMLSeriesHelper::createOldAPISeriesPropertySet( seriesStyle.m_xSeries, xChartModel ); + + aSeriesMap[seriesStyle.m_xSeries] = seriesStyle.m_xOldAPISeries; + + } + + //initialize m_xOldAPISeries for all other styles also + for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType == DataRowPointStyle::DATA_SERIES ) + continue; + seriesStyle.m_xOldAPISeries = aSeriesMap[seriesStyle.m_xSeries]; + } +} + +//static +void SchXMLSeries2Context::setDefaultsToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles ) +{ + // iterate over series + // call initSeriesPropertySets first + + for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES ) + continue; + + try + { + uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries ); + if( !xSeries.is() ) + continue; + + if( rSeriesDefaultsAndStyles.maSymbolTypeDefault.hasValue() ) + xSeries->setPropertyValue("SymbolType",rSeriesDefaultsAndStyles.maSymbolTypeDefault); + if( rSeriesDefaultsAndStyles.maDataCaptionDefault.hasValue() ) + xSeries->setPropertyValue("DataCaption",rSeriesDefaultsAndStyles.maDataCaptionDefault); + + if( rSeriesDefaultsAndStyles.maErrorIndicatorDefault.hasValue() ) + xSeries->setPropertyValue("ErrorIndicator",rSeriesDefaultsAndStyles.maErrorIndicatorDefault); + if( rSeriesDefaultsAndStyles.maErrorCategoryDefault.hasValue() ) + xSeries->setPropertyValue("ErrorCategory",rSeriesDefaultsAndStyles.maErrorCategoryDefault); + if( rSeriesDefaultsAndStyles.maConstantErrorLowDefault.hasValue() ) + xSeries->setPropertyValue("ConstantErrorLow",rSeriesDefaultsAndStyles.maConstantErrorLowDefault); + if( rSeriesDefaultsAndStyles.maConstantErrorHighDefault.hasValue() ) + xSeries->setPropertyValue("ConstantErrorHigh",rSeriesDefaultsAndStyles.maConstantErrorHighDefault); + if( rSeriesDefaultsAndStyles.maPercentageErrorDefault.hasValue() ) + xSeries->setPropertyValue("PercentageError",rSeriesDefaultsAndStyles.maPercentageErrorDefault); + if( rSeriesDefaultsAndStyles.maErrorMarginDefault.hasValue() ) + xSeries->setPropertyValue("ErrorMargin",rSeriesDefaultsAndStyles.maErrorMarginDefault); + + if( rSeriesDefaultsAndStyles.maMeanValueDefault.hasValue() ) + xSeries->setPropertyValue("MeanValue",rSeriesDefaultsAndStyles.maMeanValueDefault); + if( rSeriesDefaultsAndStyles.maRegressionCurvesDefault.hasValue() ) + xSeries->setPropertyValue("RegressionCurves",rSeriesDefaultsAndStyles.maRegressionCurvesDefault); + } + catch( uno::Exception & ) + { + //end of series reached + } + } +} + +//static +void SchXMLSeries2Context::setStylesToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName + , const SchXMLImportHelper& rImportHelper + , const SvXMLImport& rImport + , bool bIsStockChart + , tSchXMLLSequencesPerIndex & rInOutLSequencesPerIndex ) +{ + // iterate over series + for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType == DataRowPointStyle::DATA_SERIES ) + { + try + { + uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries ); + if( !xSeriesProp.is() ) + continue; + + if( seriesStyle.mnAttachedAxis != 1 ) + { + xSeriesProp->setPropertyValue("Axis" + , uno::makeAny(chart::ChartAxisAssign::SECONDARY_Y) ); + } + + if( !seriesStyle.msStyleName.isEmpty()) + { + if( rCurrStyleName != seriesStyle.msStyleName ) + { + rCurrStyleName = seriesStyle.msStyleName; + rpStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName ); + } + + //set style to series + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext * pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( rpStyle )); + if( pPropStyleContext ) + { + // error bar style must be set before the other error + // bar properties (which may be alphabetically before + // this property) + bool bHasErrorBarRangesFromData = false; + { + const OUString aErrorBarStylePropName( "ErrorBarStyle"); + uno::Any aErrorBarStyle( + SchXMLTools::getPropertyFromContext( aErrorBarStylePropName, pPropStyleContext, pStylesCtxt )); + if( aErrorBarStyle.hasValue()) + { + xSeriesProp->setPropertyValue( aErrorBarStylePropName, aErrorBarStyle ); + sal_Int32 eEBStyle = chart::ErrorBarStyle::NONE; + bHasErrorBarRangesFromData = + ( ( aErrorBarStyle >>= eEBStyle ) && + eEBStyle == chart::ErrorBarStyle::FROM_DATA ); + } + } + + //don't set the style to the min max line series of a stock chart + //otherwise the min max line properties gets overwritten and the series becomes invisible typically + bool bIsMinMaxSeries = false; + if( bIsStockChart ) + { + if( SchXMLSeriesHelper::isCandleStickSeries( seriesStyle.m_xSeries + , rImportHelper.GetChartDocument() ) ) + bIsMinMaxSeries = true; + } + if( !bIsMinMaxSeries ) + { + pPropStyleContext->FillPropertySet( xSeriesProp ); + if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile ) + lcl_setSymbolSizeIfNeeded( xSeriesProp, rImport ); + if( bHasErrorBarRangesFromData ) + lcl_insertErrorBarLSequencesToMap( rInOutLSequencesPerIndex, xSeriesProp ); + } + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" ); + } + } + } +} + +// static +void SchXMLSeries2Context::setStylesToRegressionCurves( + SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles, + const SvXMLStylesContext* pStylesCtxt, + const SvXMLStyleContext*& rpStyle, + OUString const & rCurrentStyleName ) +{ + // iterate over regression etc + for (auto const& regressionStyle : rSeriesDefaultsAndStyles.maRegressionStyleVector) + { + try + { + OUString aServiceName; + XMLPropStyleContext* pPropStyleContext = nullptr; + + if (!rCurrentStyleName.isEmpty()) + { + XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, rCurrentStyleName); + if( pCurrent ) + { + pPropStyleContext = pCurrent; + uno::Any aAny = SchXMLTools::getPropertyFromContext("RegressionType", pPropStyleContext, pStylesCtxt); + if ( aAny.hasValue() ) + { + aAny >>= aServiceName; + } + } + } + + if (!regressionStyle.msStyleName.isEmpty()) + { + XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, regressionStyle.msStyleName); + if( pCurrent ) + { + pPropStyleContext = pCurrent; + uno::Any aAny = SchXMLTools::getPropertyFromContext("RegressionType", pPropStyleContext, pStylesCtxt); + if ( aAny.hasValue() ) + { + aAny >>= aServiceName; + } + } + } + + if( !aServiceName.isEmpty() ) + { + Reference< lang::XMultiServiceFactory > xMSF = comphelper::getProcessServiceFactory(); + Reference< chart2::XRegressionCurve > xRegCurve( xMSF->createInstance( aServiceName ), uno::UNO_QUERY_THROW ); + Reference< chart2::XRegressionCurveContainer > xRegCurveCont( regressionStyle.m_xSeries, uno::UNO_QUERY_THROW ); + + Reference< beans::XPropertySet > xCurveProperties( xRegCurve, uno::UNO_QUERY ); + if( pPropStyleContext != nullptr) + pPropStyleContext->FillPropertySet( xCurveProperties ); + + xRegCurve->setEquationProperties( regressionStyle.m_xEquationProperties ); + + xRegCurveCont->addRegressionCurve( xRegCurve ); + } + } + catch( const uno::Exception& ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" ); + } + + } +} + +// static +void SchXMLSeries2Context::setStylesToStatisticsObjects( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName ) +{ + // iterate over regression etc + for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR || + seriesStyle.meType == DataRowPointStyle::MEAN_VALUE ) + { + if ( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR ) + { + uno::Reference< beans::XPropertySet > xNewSeriesProp(seriesStyle.m_xSeries,uno::UNO_QUERY); + + if (seriesStyle.m_xErrorXProperties.is()) + xNewSeriesProp->setPropertyValue("ErrorBarX",uno::makeAny(seriesStyle.m_xErrorXProperties)); + + if (seriesStyle.m_xErrorYProperties.is()) + xNewSeriesProp->setPropertyValue("ErrorBarY",uno::makeAny(seriesStyle.m_xErrorYProperties)); + } + + try + { + uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries ); + if( !xSeriesProp.is() ) + continue; + + if( !seriesStyle.msStyleName.isEmpty()) + { + if( rCurrStyleName != seriesStyle.msStyleName ) + { + rCurrStyleName = seriesStyle.msStyleName; + rpStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName ); + } + + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext * pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( rpStyle )); + if( pPropStyleContext ) + { + Reference< beans::XPropertySet > xStatPropSet; + switch( seriesStyle.meType ) + { + case DataRowPointStyle::MEAN_VALUE: + xSeriesProp->getPropertyValue("DataMeanValueProperties") >>= xStatPropSet; + break; + case DataRowPointStyle::ERROR_INDICATOR: + xSeriesProp->getPropertyValue("DataErrorProperties") >>= xStatPropSet; + break; + default: + break; + } + if( xStatPropSet.is()) + pPropStyleContext->FillPropertySet( xStatPropSet ); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" ); + } + } + } +} + +//static +void SchXMLSeries2Context::setStylesToDataPoints( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName + , const SchXMLImportHelper& rImportHelper + , const SvXMLImport& rImport + , bool bIsStockChart, bool bIsDonutChart, bool bSwitchOffLinesForScatter ) +{ + for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType != DataRowPointStyle::DATA_POINT ) + continue; + + if( seriesStyle.m_nPointIndex == -1 ) + continue; + + uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries ); + if(!xSeriesProp.is()) + continue; + + //ignore datapoint properties for stock charts + //... todo ... + if( bIsStockChart ) + { + if( SchXMLSeriesHelper::isCandleStickSeries( seriesStyle.m_xSeries, rImportHelper.GetChartDocument() ) ) + continue; + } + + // data point style + for( sal_Int32 i = 0; i < seriesStyle.m_nPointRepeat; i++ ) + { + try + { + uno::Reference< beans::XPropertySet > xPointProp( + SchXMLSeriesHelper::createOldAPIDataPointPropertySet( seriesStyle.m_xSeries, seriesStyle.m_nPointIndex + i + , rImportHelper.GetChartDocument() ) ); + + if( !xPointProp.is() ) + continue; + + if( bIsDonutChart ) + { + //set special series styles for donut charts first + if( rCurrStyleName != seriesStyle.msSeriesStyleNameForDonuts ) + { + rCurrStyleName = seriesStyle.msSeriesStyleNameForDonuts; + rpStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName ); + } + + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext * pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( rpStyle )); + if( pPropStyleContext ) + pPropStyleContext->FillPropertySet( xPointProp ); + } + + try + { + //need to set this explicitly here for old files as the new api does not support this property fully anymore + if( bSwitchOffLinesForScatter ) + xPointProp->setPropertyValue("Lines",uno::makeAny(false)); + } + catch( const uno::Exception & ) + { + } + + if( rCurrStyleName != seriesStyle.msStyleName ) + { + rCurrStyleName = seriesStyle.msStyleName; + rpStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName ); + } + + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext * pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( rpStyle )); + if( pPropStyleContext ) + { + pPropStyleContext->FillPropertySet( xPointProp ); + if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile ) + lcl_resetSymbolSizeForPointsIfNecessary( xPointProp, rImport, pPropStyleContext, pStylesCtxt ); + if( !pPropStyleContext->isEmptyDataStyleName() ) + lcl_setLinkNumberFormatToSourceIfNeeded( xPointProp, pPropStyleContext, pStylesCtxt ); + } + + // Custom labels might be passed as property + if(auto nLabelCount = seriesStyle.mCustomLabels.size(); nLabelCount > 0) + { + Sequence< Reference> xLabels(nLabelCount); + Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + for( auto j = 0; j< xLabels.getLength(); ++j ) + { + Reference< chart2::XDataPointCustomLabelField > xCustomLabel = chart2::DataPointCustomLabelField::create(xContext); + xLabels[j] = xCustomLabel; + xCustomLabel->setString(seriesStyle.mCustomLabels[j]); + xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT); + + // Restore character properties on the text span manually, till + // SchXMLExportHelper_Impl::exportCustomLabel() does not write the style. + uno::Reference xPointPropInfo + = xPointProp->getPropertySetInfo(); + if (xPointPropInfo.is()) + { + uno::Sequence aProperties = xPointPropInfo->getProperties(); + for (const auto& rProperty : std::as_const(aProperties)) + { + if (!rProperty.Name.startsWith("Char") + || rProperty.Name.startsWith("Chart")) + { + continue; + } + + xCustomLabel->setPropertyValue( + rProperty.Name, xPointProp->getPropertyValue(rProperty.Name)); + } + } + } + xPointProp->setPropertyValue("CustomLabelFields", uno::Any(xLabels)); + } + + if( seriesStyle.mCustomLabelPos[0] != 0.0 || seriesStyle.mCustomLabelPos[1] != 0.0 ) + { + chart2::RelativePosition aCustomlabelPosition; + aCustomlabelPosition.Primary = seriesStyle.mCustomLabelPos[0]; + aCustomlabelPosition.Secondary = seriesStyle.mCustomLabelPos[1]; + xPointProp->setPropertyValue("CustomLabelPosition", uno::Any(aCustomlabelPosition)); + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to data points" ); + } + } + } // styles iterator +} + +//static +void SchXMLSeries2Context::switchSeriesLinesOff( ::std::vector< DataRowPointStyle >& rSeriesStyleVector ) +{ + // iterate over series + for (auto const& seriesStyle : rSeriesStyleVector) + { + if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES ) + continue; + + try + { + uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries ); + if( !xSeries.is() ) + continue; + + xSeries->setPropertyValue("Lines",uno::makeAny(false)); + } + catch( uno::Exception & ) + { + //end of series reached + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLSeries2Context.hxx b/xmloff/source/chart/SchXMLSeries2Context.hxx new file mode 100644 index 000000000..7f825974e --- /dev/null +++ b/xmloff/source/chart/SchXMLSeries2Context.hxx @@ -0,0 +1,133 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLSERIES2CONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLSERIES2CONTEXT_HXX + +#include "transporttypes.hxx" +#include "SchXMLChartContext.hxx" +#include +#include +#include + +#include + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + class XDataSeries; + } + namespace awt { + struct Size; + } +} + +// class for child contexts: series, data point and statistics objects +class SchXMLSeries2Context : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart2::XChartDocument > mxNewDoc; + ::std::vector< SchXMLAxis >& mrAxes; + ::std::vector< DataRowPointStyle >& mrStyleVector; + ::std::vector< RegressionStyle >& mrRegressionStyleVector; + + css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + sal_Int32 mnSeriesIndex; + sal_Int32 mnDataPointIndex; + bool m_bStockHasVolume; + + GlobalSeriesImportInfo& m_rGlobalSeriesImportInfo; + + SchXMLAxis* mpAttachedAxis; + sal_Int32 mnAttachedAxis; + OUString msAutoStyleName; + ::std::vector< OUString > maDomainAddresses; + OUString maGlobalChartTypeName; + OUString maSeriesChartTypeName; + OUString m_aSeriesRange; + bool m_bHasDomainContext; + tSchXMLLSequencesPerIndex & mrLSequencesPerIndex; + tSchXMLLSequencesPerIndex maPostponedSequences; + bool& mrGlobalChartTypeUsedBySeries; + bool mbSymbolSizeIsMissingInFile; + css::awt::Size maChartSize; + +public: + SchXMLSeries2Context( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, const OUString& rLocalName, + const css::uno::Reference< css::chart2::XChartDocument > & xNewDoc, + std::vector< SchXMLAxis >& rAxes, + ::std::vector< DataRowPointStyle >& rStyleVector, + ::std::vector< RegressionStyle >& rRegressionStyleVector, + sal_Int32 nSeriesIndex, + bool bStockHasVolume, + GlobalSeriesImportInfo& rGlobalSeriesImportInfo, + const OUString & aGlobalChartTypeName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + bool& rGlobalChartTypeUsedBySeries, + const css::awt::Size & rChartSize ); + virtual ~SchXMLSeries2Context() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + + static void initSeriesPropertySets( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const css::uno::Reference< css::frame::XModel >& xChartModel ); + + static void setDefaultsToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles ); + + static void setStylesToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName + , const SchXMLImportHelper& rImportHelper + , const SvXMLImport& rImport + , bool bIsStockChart + , tSchXMLLSequencesPerIndex & rInOutLSequencesPerIndex ); + + static void setStylesToStatisticsObjects( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString &rCurrStyleName ); + + static void setStylesToRegressionCurves( + SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles, + const SvXMLStylesContext* pStylesCtxt, + const SvXMLStyleContext*& rpStyle, + OUString const &rCurrStyleName ); + + static void setStylesToDataPoints( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName + , const SchXMLImportHelper& rImportHelper + , const SvXMLImport& rImport + , bool bIsStockChart, bool bIsDonutChart, bool bSwitchOffLinesForScatter ); + + static void switchSeriesLinesOff( ::std::vector< DataRowPointStyle >& rSeriesStyleVector ); +}; + +// INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLSERIES2CONTEXT_HXX +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLSeriesHelper.cxx b/xmloff/source/chart/SchXMLSeriesHelper.cxx new file mode 100644 index 000000000..00adebc0d --- /dev/null +++ b/xmloff/source/chart/SchXMLSeriesHelper.cxx @@ -0,0 +1,224 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +::std::vector< Reference< chart2::XDataSeries > > + SchXMLSeriesHelper::getDataSeriesFromDiagram( + const Reference< chart2::XDiagram > & xDiagram ) +{ + ::std::vector< Reference< chart2::XDataSeries > > aResult; + + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDiagram, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XChartType > > aChartTypeSeq( xCTCnt->getChartTypes()); + for( const auto& rChartType : aChartTypeSeq ) + { + Reference< chart2::XDataSeriesContainer > xDSCnt( rChartType, uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() ); + ::std::copy( aSeriesSeq.begin(), aSeriesSeq.end(), + ::std::back_inserter( aResult )); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + + return aResult; +} + +::std::map< Reference< chart2::XDataSeries >, sal_Int32 > SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram( + const Reference< chart2::XDiagram > & xDiagram ) +{ + ::std::map< Reference< chart2::XDataSeries >, sal_Int32 > aRet; + + sal_Int32 nIndex=0; + + ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram )); + for( const Reference< chart2::XDataSeries >& xSeries : aSeriesVector ) + { + if( xSeries.is() ) + { + if( aRet.end() == aRet.find(xSeries) ) + aRet[xSeries]=nIndex; + } + nIndex++; + } + return aRet; +} + +namespace { +uno::Reference< chart2::XChartType > lcl_getChartTypeOfSeries( + const uno::Reference< chart2::XDiagram >& xDiagram + , const Reference< chart2::XDataSeries >& xSeries ) +{ + if(!xDiagram.is()) + return nullptr; + + //iterate through the model to find the given xSeries + //the found parent indicates the charttype + + //iterate through all coordinate systems + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); + if( !xCooSysContainer.is()) + return nullptr; + + const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); + for( const auto& xCooSys : aCooSysList ) + { + //iterate through all chart types in the current coordinate system + uno::Reference< chart2::XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY ); + SAL_WARN_IF( !xChartTypeContainer.is(), "xmloff.chart", "xChartTypeContainer is NULL"); + if( !xChartTypeContainer.is() ) + continue; + const uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() ); + for( const auto& xChartType : aChartTypeList ) + { + //iterate through all series in this chart type + uno::Reference< chart2::XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY ); + SAL_WARN_IF( !xDataSeriesContainer.is(), "xmloff.chart", "xDataSeriesContainer is NULL"); + if( !xDataSeriesContainer.is() ) + continue; + + uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() ); + if (std::find(aSeriesList.begin(), aSeriesList.end(), xSeries) != aSeriesList.end()) + return xChartType; + } + } + return nullptr; +} +} + +bool SchXMLSeriesHelper::isCandleStickSeries( + const Reference< chart2::XDataSeries >& xSeries + , const Reference< frame::XModel >& xChartModel ) +{ + bool bRet = false; + + uno::Reference< chart2::XChartDocument > xNewDoc( xChartModel, uno::UNO_QUERY ); + if( xNewDoc.is() ) + { + uno::Reference< chart2::XDiagram > xNewDiagram( xNewDoc->getFirstDiagram() ); + if( xNewDiagram.is() ) + { + uno::Reference< chart2::XChartType > xChartType( lcl_getChartTypeOfSeries( + xNewDiagram, xSeries ) ); + if( xChartType.is() ) + { + OUString aServiceName( xChartType->getChartType() ); + if( aServiceName == "com.sun.star.chart2.CandleStickChartType" ) + bRet = true; + } + } + } + return bRet; +} + +//static +uno::Reference< beans::XPropertySet > SchXMLSeriesHelper::createOldAPISeriesPropertySet( + const uno::Reference< chart2::XDataSeries >& xSeries + , const uno::Reference< frame::XModel >& xChartModel ) +{ + uno::Reference< beans::XPropertySet > xRet; + + if( xSeries.is() ) + { + try + { + uno::Reference< lang::XMultiServiceFactory > xFactory( xChartModel, uno::UNO_QUERY ); + if( xFactory.is() ) + { + xRet.set( xFactory->createInstance( "com.sun.star.comp.chart2.DataSeriesWrapper" ), uno::UNO_QUERY ); + Reference< lang::XInitialization > xInit( xRet, uno::UNO_QUERY ); + if(xInit.is()) + { + Sequence< uno::Any > aArguments(1); + aArguments[0] <<= xSeries; + xInit->initialize(aArguments); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught SchXMLSeriesHelper::createOldAPISeriesPropertySet" ); + } + } + + return xRet; +} + +//static +uno::Reference< beans::XPropertySet > SchXMLSeriesHelper::createOldAPIDataPointPropertySet( + const uno::Reference< chart2::XDataSeries >& xSeries + , sal_Int32 nPointIndex + , const uno::Reference< frame::XModel >& xChartModel ) +{ + uno::Reference< beans::XPropertySet > xRet; + + if( xSeries.is() ) + { + try + { + uno::Reference< lang::XMultiServiceFactory > xFactory( xChartModel, uno::UNO_QUERY ); + if( xFactory.is() ) + { + xRet.set( xFactory->createInstance( "com.sun.star.comp.chart2.DataSeriesWrapper" ), uno::UNO_QUERY ); + Reference< lang::XInitialization > xInit( xRet, uno::UNO_QUERY ); + if(xInit.is()) + { + Sequence< uno::Any > aArguments(2); + aArguments[0] <<= xSeries; + aArguments[1] <<= nPointIndex; + xInit->initialize(aArguments); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught SchXMLSeriesHelper::createOldAPIDataPointPropertySet" ); + } + } + + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTableContext.cxx b/xmloff/source/chart/SchXMLTableContext.cxx new file mode 100644 index 000000000..b561dcfb0 --- /dev/null +++ b/xmloff/source/chart/SchXMLTableContext.cxx @@ -0,0 +1,1075 @@ +/* -*- 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 + +#include "SchXMLTableContext.hxx" +#include "SchXMLParagraphContext.hxx" +#include "SchXMLTextListContext.hxx" +#include +#include "SchXMLTools.hxx" +#include "transporttypes.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +const char aCategoriesRange[] = "categories"; + +typedef ::std::multimap< OUString, OUString > + lcl_tOriginalRangeToInternalRangeMap; + +struct lcl_ApplyCellToData +{ + explicit lcl_ApplyCellToData( Sequence< double > & rOutData ) : + m_rData( rOutData ), + m_nIndex( 0 ), + m_nSize( rOutData.getLength()), + m_fNaN( 0.0 ) + { + ::rtl::math::setNan( &m_fNaN ); + } + + void operator() ( const SchXMLCell & rCell ) + { + if( m_nIndex < m_nSize ) + { + if( rCell.eType == SCH_CELL_TYPE_FLOAT ) + m_rData[m_nIndex] = rCell.fValue; + else + m_rData[m_nIndex] = m_fNaN; + } + ++m_nIndex; + } + + sal_Int32 getCurrentIndex() const + { + return m_nIndex; + } + +private: + Sequence< double > & m_rData; + sal_Int32 m_nIndex; + sal_Int32 m_nSize; + double m_fNaN; +}; + +void lcl_fillRangeMapping( + const SchXMLTable & rTable, + lcl_tOriginalRangeToInternalRangeMap & rOutRangeMap, + chart::ChartDataRowSource eDataRowSource ) +{ + sal_Int32 nRowOffset = ( rTable.bHasHeaderRow ? 1 : 0 ); + sal_Int32 nColOffset = ( rTable.bHasHeaderColumn ? 1 : 0 ); + + const OUString lcl_aCategoriesRange(aCategoriesRange); + const OUString lcl_aLabelPrefix("label "); + + // Fill range mapping + const size_t nTableRowCount( rTable.aData.size()); + for( size_t nRow = 0; nRow < nTableRowCount; ++nRow ) + { + const ::std::vector< SchXMLCell > & rRow( rTable.aData[nRow] ); + const size_t nTableColCount( rRow.size()); + for( size_t nCol = 0; nCol < nTableColCount; ++nCol ) + { + const OUString aRangeId( rRow[nCol].aRangeId ); + if( !aRangeId.isEmpty()) + { + if( eDataRowSource == chart::ChartDataRowSource_COLUMNS ) + { + if( nCol == 0 && rTable.bHasHeaderColumn ) + { + SAL_WARN_IF( static_cast< sal_Int32 >( nRow ) != nRowOffset, "xmloff.chart", "nRow != nRowOffset" ); + rOutRangeMap.emplace(aRangeId, lcl_aCategoriesRange); + } + else + { + OUString aColNumStr = OUString::number( nCol - nColOffset); + if( nRow == 0 && rTable.bHasHeaderRow ) + rOutRangeMap.emplace( aRangeId, lcl_aLabelPrefix + aColNumStr ); + else + rOutRangeMap.emplace( aRangeId, aColNumStr ); + } + } + else // eDataRowSource == chart::ChartDataRowSource_ROWS + { + if( nRow == 0 && rTable.bHasHeaderRow ) + { + SAL_WARN_IF( static_cast< sal_Int32 >( nCol ) != nColOffset, "xmloff.chart", "nCol != nColOffset" ); + rOutRangeMap.emplace( aRangeId, lcl_aCategoriesRange ); + } + else + { + OUString aRowNumStr = OUString::number( nRow - nRowOffset); + if( nCol == 0 && rTable.bHasHeaderColumn ) + rOutRangeMap.emplace( aRangeId, lcl_aLabelPrefix + aRowNumStr ); + else + rOutRangeMap.emplace( aRangeId, aRowNumStr ); + } + } + } + } + } +} + +Reference< chart2::data::XDataSequence > + lcl_reassignDataSequence( + const Reference< chart2::data::XDataSequence > & xSequence, + const Reference< chart2::data::XDataProvider > & xDataProvider, + lcl_tOriginalRangeToInternalRangeMap & rRangeMap, + const OUString & rRange ) +{ + Reference< chart2::data::XDataSequence > xResult( xSequence ); + lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange )); + if( aIt != rRangeMap.end()) + { + // set sequence with correct data + xResult.set( xDataProvider->createDataSequenceByRangeRepresentation( aIt->second )); + // remove translation, because it was used + rRangeMap.erase( aIt ); + } + + return xResult; +} + +bool lcl_mapContainsRange( + lcl_tOriginalRangeToInternalRangeMap & rRangeMap, + const OUString & rRange ) +{ + lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange )); + return ( aIt != rRangeMap.end()); +} + +bool lcl_tableOfRangeMatches( + const OUString & rRange, + const OUString & rTableName ) +{ + // both strings are non-empty and the table name is part of the range + return ( !rRange.isEmpty() && + !rTableName.isEmpty() && + (rRange.indexOf( rTableName ) != -1 )); +} + +} // anonymous namespace + +// class SchXMLTableContext +SchXMLTableContext::SchXMLTableContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rLName, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLName ), + mrImportHelper( rImpHelper ), + mrTable( aTable ), + mbHasRowPermutation( false ), + mbHasColumnPermutation( false ) +{ + mrTable.nColumnIndex = -1; + mrTable.nMaxColumnIndex = -1; + mrTable.nRowIndex = -1; + mrTable.aData.clear(); +} + +SchXMLTableContext::~SchXMLTableContext() +{ +} + +SvXMLImportContextRef SchXMLTableContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + const SvXMLTokenMap& rTokenMap = mrImportHelper.GetTableElemTokenMap(); + + switch( rTokenMap.Get( nPrefix, rLocalName )) + { + case XML_TOK_TABLE_HEADER_COLS: + mrTable.bHasHeaderColumn = true; + [[fallthrough]]; + case XML_TOK_TABLE_COLUMNS: + pContext = new SchXMLTableColumnsContext( GetImport(), rLocalName, mrTable ); + break; + + case XML_TOK_TABLE_COLUMN: + pContext = new SchXMLTableColumnContext( GetImport(), rLocalName, mrTable ); + break; + + case XML_TOK_TABLE_HEADER_ROWS: + mrTable.bHasHeaderRow = true; + [[fallthrough]]; + case XML_TOK_TABLE_ROWS: + pContext = new SchXMLTableRowsContext( mrImportHelper, GetImport(), rLocalName, mrTable ); + break; + + case XML_TOK_TABLE_ROW: + pContext = new SchXMLTableRowContext( mrImportHelper, GetImport(), rLocalName, mrTable ); + break; + } + + return pContext; +} + +void SchXMLTableContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // get table-name + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + if ( nPrefix == XML_NAMESPACE_TABLE ) + { + if ( IsXMLToken( aLocalName, XML_NAME ) ) + { + mrTable.aTableNameOfFile = xAttrList->getValueByIndex( i ); + } + else if ( IsXMLToken( aLocalName, XML_PROTECTED ) ) + { + if ( IsXMLToken( xAttrList->getValueByIndex( i ), XML_TRUE ) ) + { + mrTable.bProtected = true; + } + } + } + } +} + +void SchXMLTableContext::EndElement() +{ + if( mbHasColumnPermutation ) + { + SAL_WARN_IF( mbHasRowPermutation, "xmloff.chart", "mbHasColumnPermutation is true" ); + auto aPermutation( comphelper::sequenceToContainer>( maColumnPermutation )); + SAL_WARN_IF( aPermutation.empty(), "xmloff.chart", "aPermutation is NULL"); + if( aPermutation.empty()) + return; + + // permute the values of all rows according to aPermutation + for( auto& rRow : mrTable.aData ) + { + bool bModified = false; + ::std::vector< SchXMLCell > aModifiedRow; + const size_t nPermSize = aPermutation.size(); + SAL_WARN_IF( static_cast< sal_Int32 >( nPermSize ) - 1 != *(::std::max_element( aPermutation.begin(), aPermutation.end())), "xmloff.chart", "nPermSize - 1 != *(::std::max_element( aPermutation.begin(), aPermutation.end())"); + const size_t nRowSize = rRow.size(); + const size_t nDestSize = ::std::min( nPermSize, nRowSize ); + for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex ) + { + const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] ); + if( nSourceIndex != nDestinationIndex && + nSourceIndex < nRowSize ) + { + // copy original on first real permutation + if( !bModified ) + { + SAL_WARN_IF( !aModifiedRow.empty(), "xmloff.chart", "aModifiedRow is NOT NULL"); + aModifiedRow.reserve( rRow.size()); + ::std::copy( rRow.begin(), rRow.end(), ::std::back_inserter( aModifiedRow )); + SAL_WARN_IF( aModifiedRow.empty(), "xmloff.chart", "aModifiedRow is NULL"); + } + SAL_WARN_IF( nDestinationIndex >= aModifiedRow.size(), "xmloff.chart", "nDestinationIndex >= aModifiedRow.size()"); + aModifiedRow[ nDestinationIndex ] = rRow[ nSourceIndex ]; + bModified = true; + } + } + // copy back + if( bModified ) + ::std::copy( aModifiedRow.begin(), aModifiedRow.end(), rRow.begin()); + } + } + else if( mbHasRowPermutation ) + { + auto aPermutation( comphelper::sequenceToContainer>( maRowPermutation )); + SAL_WARN_IF( aPermutation.empty(), "xmloff.chart", "aPermutation is NULL"); + if( aPermutation.empty()) + return; + + bool bModified = false; + const size_t nPermSize = aPermutation.size(); + SAL_WARN_IF( static_cast< sal_Int32 >( nPermSize ) - 1 != *(::std::max_element( aPermutation.begin(), aPermutation.end())), "xmloff.chart", "nPermSize - 1 != *(::std::max_element( aPermutation.begin(), aPermutation.end())"); + const size_t nTableRowCount = mrTable.aData.size(); + const size_t nDestSize = ::std::min( nPermSize, nTableRowCount ); + ::std::vector< ::std::vector< SchXMLCell > > aDestination; + for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex ) + { + const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] ); + if( nSourceIndex != nDestinationIndex && + nSourceIndex < nTableRowCount ) + { + // copy original on first real permutation + if( !bModified ) + { + SAL_WARN_IF( !aDestination.empty(), "xmloff.chart", "aDestination is NOT NULL"); + aDestination.reserve( mrTable.aData.size()); + ::std::copy( mrTable.aData.begin(), mrTable.aData.end(), ::std::back_inserter( aDestination )); + SAL_WARN_IF( aDestination.empty(), "xmloff.chart", "aDestination is NULL"); + } + SAL_WARN_IF( nDestinationIndex >= aDestination.size(), "xmloff.chart", "nDestinationIndex >= aDestination.size()"); + aDestination[ nDestinationIndex ] = mrTable.aData[ nSourceIndex ]; + bModified = true; + } + } + if( bModified ) + { + // copy back + ::std::copy( aDestination.begin(), aDestination.end(), mrTable.aData.begin()); + } + } +} + +void SchXMLTableContext::setRowPermutation( const uno::Sequence< sal_Int32 > & rPermutation ) +{ + maRowPermutation = rPermutation; + mbHasRowPermutation = rPermutation.hasElements(); + + if( mbHasRowPermutation && mbHasColumnPermutation ) + { + mbHasColumnPermutation = false; + maColumnPermutation.realloc( 0 ); + } +} + +void SchXMLTableContext::setColumnPermutation( const uno::Sequence< sal_Int32 > & rPermutation ) +{ + maColumnPermutation = rPermutation; + mbHasColumnPermutation = rPermutation.hasElements(); + + if( mbHasColumnPermutation && mbHasRowPermutation ) + { + mbHasRowPermutation = false; + maRowPermutation.realloc( 0 ); + } +} + +// classes for columns +// class SchXMLTableColumnsContext +SchXMLTableColumnsContext::SchXMLTableColumnsContext( + SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), + mrTable( aTable ) +{ +} + +SchXMLTableColumnsContext::~SchXMLTableColumnsContext() +{ +} + +SvXMLImportContextRef SchXMLTableColumnsContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + if( nPrefix == XML_NAMESPACE_TABLE && + IsXMLToken( rLocalName, XML_TABLE_COLUMN ) ) + { + pContext = new SchXMLTableColumnContext( GetImport(), rLocalName, mrTable ); + } + + return pContext; +} + +// class SchXMLTableColumnContext +SchXMLTableColumnContext::SchXMLTableColumnContext( + SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), + mrTable( aTable ) +{ +} + +void SchXMLTableColumnContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + // get number-columns-repeated attribute + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + sal_Int32 nRepeated = 1; + bool bHidden = false; + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_TABLE && + IsXMLToken( aLocalName, XML_NUMBER_COLUMNS_REPEATED ) ) + { + OUString aValue = xAttrList->getValueByIndex( i ); + if( !aValue.isEmpty()) + nRepeated = aValue.toInt32(); + } + else if( nPrefix == XML_NAMESPACE_TABLE && + IsXMLToken( aLocalName, XML_VISIBILITY ) ) + { + OUString aVisibility = xAttrList->getValueByIndex( i ); + bHidden = aVisibility == GetXMLToken( XML_COLLAPSE ); + } + } + + sal_Int32 nOldCount = mrTable.nNumberOfColsEstimate; + sal_Int32 nNewCount = nOldCount + nRepeated; + mrTable.nNumberOfColsEstimate = nNewCount; + + if( bHidden ) + { + //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste ) + sal_Int32 nColOffset = ( mrTable.bHasHeaderColumn ? 1 : 0 ); + for( sal_Int32 nN = nOldCount; nN=0 ) + mrTable.aHiddenColumns.push_back(nHiddenColumnIndex); + } + } +} + +SchXMLTableColumnContext::~SchXMLTableColumnContext() +{ +} + +// classes for rows +// class SchXMLTableRowsContext +SchXMLTableRowsContext::SchXMLTableRowsContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), + mrImportHelper( rImpHelper ), + mrTable( aTable ) +{ +} + +SchXMLTableRowsContext::~SchXMLTableRowsContext() +{ +} + +SvXMLImportContextRef SchXMLTableRowsContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + if( nPrefix == XML_NAMESPACE_TABLE && + IsXMLToken( rLocalName, XML_TABLE_ROW ) ) + { + pContext = new SchXMLTableRowContext( mrImportHelper, GetImport(), rLocalName, mrTable ); + } + + return pContext; +} + +// class SchXMLTableRowContext +SchXMLTableRowContext::SchXMLTableRowContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), + mrImportHelper( rImpHelper ), + mrTable( aTable ) +{ + mrTable.nColumnIndex = -1; + mrTable.nRowIndex++; + + std::vector< SchXMLCell > aNewRow; + aNewRow.reserve( mrTable.nNumberOfColsEstimate ); + while( mrTable.aData.size() <= o3tl::make_unsigned(mrTable.nRowIndex) ) + mrTable.aData.push_back( aNewRow ); +} + +SchXMLTableRowContext::~SchXMLTableRowContext() +{ +} + +SvXMLImportContextRef SchXMLTableRowContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + // element + if( nPrefix == XML_NAMESPACE_TABLE && + IsXMLToken(rLocalName, XML_TABLE_CELL ) ) + { + pContext = new SchXMLTableCellContext( mrImportHelper, GetImport(), rLocalName, mrTable ); + } + else + { + assert(false); + } + + return pContext; +} + +namespace { + +class SchXMLRangeSomewhereContext : public SvXMLImportContext +{ +//#i113950# previously the range was exported to attribute text:id, +//but that attribute does not allow arbitrary strings anymore +//so we need to find an alternative to save that range info for copy/paste scenario ... +//-> use description at an empty group element for now + +private: + OUString& mrRangeString; + OUStringBuffer maRangeStringBuffer; + +public: + SchXMLRangeSomewhereContext( SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + OUString& rRangeString ); + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +} + +// classes for cells and their content +// class SchXMLTableCellContext +SchXMLTableCellContext::SchXMLTableCellContext( + SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, + const OUString& rLocalName, SchXMLTable& aTable) + : SvXMLImportContext(rImport, XML_NAMESPACE_TABLE, rLocalName) + , mrImportHelper(rImpHelper) + , mrTable(aTable) + , mbReadText(false) +{ +} + +SchXMLTableCellContext::~SchXMLTableCellContext() +{ +} + +void SchXMLTableCellContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; + OUString aValue; + OUString aLocalName; + OUString aCellContent; + SchXMLCellType eValueType = SCH_CELL_TYPE_UNKNOWN; + const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetCellAttrTokenMap(); + + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + OUString sAttrName = xAttrList->getNameByIndex( i ); + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); + + switch( rAttrTokenMap.Get( nPrefix, aLocalName )) + { + case XML_TOK_CELL_VAL_TYPE: + aValue = xAttrList->getValueByIndex( i ); + if( IsXMLToken( aValue, XML_FLOAT ) ) + eValueType = SCH_CELL_TYPE_FLOAT; + else if( IsXMLToken( aValue, XML_STRING ) ) + eValueType = SCH_CELL_TYPE_STRING; + break; + + case XML_TOK_CELL_VALUE: + aCellContent = xAttrList->getValueByIndex( i ); + break; + } + } + + mbReadText = true; + SchXMLCell aCell; + aCell.eType = eValueType; + + if( eValueType == SCH_CELL_TYPE_FLOAT ) + { + double fData; + // the result may be false if a NaN is read, but that's ok + ::sax::Converter::convertDouble( fData, aCellContent ); + + aCell.fValue = fData; + // don't read text from following or element + mbReadText = false; + } + + mrTable.aData[ mrTable.nRowIndex ].push_back( aCell ); + mrTable.nColumnIndex++; + if( mrTable.nMaxColumnIndex < mrTable.nColumnIndex ) + mrTable.nMaxColumnIndex = mrTable.nColumnIndex; +} + +SvXMLImportContextRef SchXMLTableCellContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + // element + if( nPrefix == XML_NAMESPACE_TEXT && IsXMLToken( rLocalName, XML_LIST ) && mbReadText ) + { + SchXMLCell& rCell = mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ]; + rCell.aComplexString = Sequence< OUString >(); + rCell.eType = SCH_CELL_TYPE_COMPLEX_STRING; + pContext = new SchXMLTextListContext( GetImport(), rLocalName, rCell.aComplexString ); + mbReadText = false;//don't apply text from + } + // element - read text (and range from text:id old version) + else if( (nPrefix == XML_NAMESPACE_TEXT || + nPrefix == XML_NAMESPACE_LO_EXT) && IsXMLToken( rLocalName, XML_P ) ) + { + pContext = new SchXMLParagraphContext( GetImport(), rLocalName, maCellContent, &maRangeId ); + } + // element - read range + else if( nPrefix == XML_NAMESPACE_DRAW && IsXMLToken( rLocalName, XML_G ) ) + { + //#i113950# previously the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore + //so we need to find an alternative to save that range info for copy/paste scenario ... -> use description at an empty group element for now + pContext = new SchXMLRangeSomewhereContext( GetImport(), nPrefix, rLocalName, maRangeId ); + } + + return pContext; +} + +void SchXMLTableCellContext::EndElement() +{ + if( mbReadText && !maCellContent.isEmpty() ) //apply text from element + mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aString = maCellContent; + if( !maRangeId.isEmpty()) + mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aRangeId = maRangeId; +} + +static void lcl_ApplyCellToComplexLabel( const SchXMLCell& rCell, Sequence< uno::Any >& rComplexLabel ) +{ + if( rCell.eType == SCH_CELL_TYPE_STRING ) + { + rComplexLabel.realloc(1); + rComplexLabel[0] <<= rCell.aString; + } + else if( rCell.aComplexString.hasElements() && rCell.eType == SCH_CELL_TYPE_COMPLEX_STRING ) + { + sal_Int32 nCount = rCell.aComplexString.getLength(); + rComplexLabel.realloc( nCount ); + for( sal_Int32 nN=0; nN& xChartDoc ) +{ + // apply all data read from the local table to the internal data provider + if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() ) + return; + Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider() ); + if( !xDataProv.is() ) + return; + + //prepare the read local table data + sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size())); + sal_Int32 nRowOffset = 0; + if( rTable.bHasHeaderRow ) + { + --nNumRows; + nRowOffset = 1; + } + sal_Int32 nNumColumns( rTable.nMaxColumnIndex + 1 ); + sal_Int32 nColOffset = 0; + if( rTable.bHasHeaderColumn ) + { + --nNumColumns; + nColOffset = 1; + } + + Sequence< Sequence< double > > aDataInRows( nNumRows ); + Sequence< Sequence< uno::Any > > aComplexRowDescriptions( nNumRows ); + Sequence< Sequence< uno::Any > > aComplexColumnDescriptions( nNumColumns ); + for( sal_Int32 i=0; i& rFirstRow = rTable.aData.front(); + const sal_Int32 nColumnLabelsSize = aComplexColumnDescriptions.getLength(); + const sal_Int32 nMax = ::std::min< sal_Int32 >( nColumnLabelsSize, static_cast< sal_Int32 >( rFirstRow.size()) - nColOffset ); + SAL_WARN_IF( nMax != nColumnLabelsSize, "xmloff.chart", "nMax != nColumnLabelsSize"); + for( sal_Int32 i=0; i >::const_iterator aRowIter( rTable.aData.begin() + nRowOffset ); + std::vector< ::std::vector< SchXMLCell > >::const_iterator aEnd( rTable.aData.end() ); + for( sal_Int32 nRow = 0; aRowIter != aEnd && nRow < nNumRows; ++aRowIter, ++nRow ) + { + const ::std::vector< SchXMLCell >& rRow = *aRowIter; + if( !rRow.empty() ) + { + // row label + if( rTable.bHasHeaderColumn ) + lcl_ApplyCellToComplexLabel( rRow.front(), aComplexRowDescriptions[nRow] ); + + // values + Sequence< double >& rTargetRow = aDataInRows[nRow]; + lcl_ApplyCellToData aApplyCellToData = ::std::for_each( rRow.begin() + nColOffset, rRow.end(), lcl_ApplyCellToData( rTargetRow ) ); + double fNaN = 0.0; + ::rtl::math::setNan( &fNaN ); + for( sal_Int32 nCurrentIndex = aApplyCellToData.getCurrentIndex(); nCurrentIndex xDataAccess( xDataProv, uno::UNO_QUERY ); + if( !xDataAccess.is() ) + return; + + xDataAccess->setData( aDataInRows ); + if( rTable.bHasHeaderColumn ) + xDataAccess->setAnyRowDescriptions( aComplexRowDescriptions ); + if( rTable.bHasHeaderRow ) + xDataAccess->setAnyColumnDescriptions( aComplexColumnDescriptions ); + + if ( rTable.bProtected ) + { + try + { + Reference< beans::XPropertySet > xProps( xChartDoc, uno::UNO_QUERY_THROW ); + xProps->setPropertyValue( "DisableDataTableDialog", uno::makeAny( true ) ); + xProps->setPropertyValue( "DisableComplexChartTypes", uno::makeAny( true ) ); + } + catch ( uno::Exception& ) + { + } + } +} + +void SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( + const SchXMLTable& rTable, + const tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + const uno::Reference< chart2::XChartDocument >& xChartDoc, + chart::ChartDataRowSource eDataRowSource ) +{ + if( ! (xChartDoc.is() && xChartDoc->hasInternalDataProvider())) + return; + + // If the range-strings are valid (starting with "local-table") they should + // be interpreted like given, otherwise (when the ranges refer to Calc- or + // Writer-ranges, but the container is not available like when pasting a + // chart from Calc to Impress) the range is ignored, and every object gets + // one table column in the order of appearance, which is: 1. categories, + // 2. data series: 2.a) domains, 2.b) values (main-role, usually y-values) + + Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider()); + + // create a mapping from original ranges to new ranges + lcl_tOriginalRangeToInternalRangeMap aRangeMap; + + lcl_fillRangeMapping( rTable, aRangeMap, eDataRowSource ); + + const OUString lcl_aCategoriesRange(aCategoriesRange); + + bool bCategoriesApplied = false; + // translate ranges (using the map created before) + for( const auto& rLSeq : rLSequencesPerIndex ) + { + if( rLSeq.second.is()) + { + // values/error bars/categories + if( rLSeq.first.second == SCH_XML_PART_VALUES || + rLSeq.first.second == SCH_XML_PART_ERROR_BARS ) + { + Reference< chart2::data::XDataSequence > xSeq( rLSeq.second->getValues()); + + OUString aRange; + if( xSeq.is() && + SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) && + lcl_mapContainsRange( aRangeMap, aRange )) + { + Reference< chart2::data::XDataSequence > xNewSeq( + lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange )); + if( xNewSeq != xSeq ) + { + SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); + rLSeq.second->setValues( xNewSeq ); + } + } + else + { + if( lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile )) + { + if( rLSeq.first.first == SCH_XML_CATEGORIES_INDEX ) + bCategoriesApplied = true; + } + else + { + if( rLSeq.first.first == SCH_XML_CATEGORIES_INDEX ) + { + Reference< beans::XPropertySet > xOldSequenceProp( rLSeq.second->getValues(), uno::UNO_QUERY ); + Reference< chart2::data::XDataSequence > xNewSequence( + xDataProv->createDataSequenceByRangeRepresentation("categories")); + SchXMLTools::copyProperties( + xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY )); + rLSeq.second->setValues( xNewSequence ); + bCategoriesApplied = true; + } + else + { + Reference< beans::XPropertySet > xOldSequenceProp( rLSeq.second->getValues(), uno::UNO_QUERY ); + OUString aRep( OUString::number( rLSeq.first.first )); + Reference< chart2::data::XDataSequence > xNewSequence( + xDataProv->createDataSequenceByRangeRepresentation( aRep )); + SchXMLTools::copyProperties( + xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY )); + rLSeq.second->setValues( xNewSequence ); + } + } + } + } + else // labels + { + SAL_WARN_IF( rLSeq.first.second != SCH_XML_PART_LABEL, "xmloff.chart", "rLSeq.first.second != SCH_XML_PART_LABEL" ); + // labels + Reference< chart2::data::XDataSequence > xSeq( rLSeq.second->getLabel()); + OUString aRange; + if( xSeq.is() && + SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) && + lcl_mapContainsRange( aRangeMap, aRange )) + { + Reference< chart2::data::XDataSequence > xNewSeq( + lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange )); + if( xNewSeq != xSeq ) + { + SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); + rLSeq.second->setLabel( xNewSeq ); + } + } + else if( ! lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile )) + { + OUString aRep = "label " + OUString::number( rLSeq.first.first ); + + Reference< chart2::data::XDataSequence > xNewSeq( + xDataProv->createDataSequenceByRangeRepresentation( aRep )); + SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); + rLSeq.second->setLabel( xNewSeq ); + } + } + } + } + + // there exist files with own data without a categories element but with row + // descriptions. The row descriptions were used as categories even without + // the categories element + if( ! bCategoriesApplied ) + { + SchXMLTools::CreateCategories( + xDataProv, xChartDoc, "categories", + 0 /* nCooSysIndex */, 0 /* nDimension */ ); + } + + //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste ) + //remove series that consist only of hidden columns + Reference< chart2::XInternalDataProvider > xInternalDataProvider( xDataProv, uno::UNO_QUERY ); + if( xInternalDataProvider.is() && !rTable.aHiddenColumns.empty() ) + { + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChartDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() ); + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XChartTypeContainer > xCooSysContainer( rCooSys, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XChartType > > aChartTypeSeq( xCooSysContainer->getChartTypes()); + for( const auto& rChartType : aChartTypeSeq ) + { + Reference< chart2::XDataSeriesContainer > xSeriesContainer( rChartType, uno::UNO_QUERY ); + if(!xSeriesContainer.is()) + continue; + const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xSeriesContainer->getDataSeries() ); + std::vector< Reference< chart2::XDataSeries > > aRemainingSeries; + + for( const auto& rSeries : aSeriesSeq ) + { + Reference< chart2::data::XDataSource > xDataSource( rSeries, uno::UNO_QUERY ); + if( xDataSource.is() ) + { + bool bHasUnhiddenColumns = false; + OUString aRange; + const uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences() ); + for( const auto& xLabeledSequence : aSequences ) + { + if(!xLabeledSequence.is()) + continue; + Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() ); + if( xValues.is() ) + { + aRange = xValues->getSourceRangeRepresentation(); + if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), aRange.toInt32() ) == rTable.aHiddenColumns.end() ) + bHasUnhiddenColumns = true; + } + if( !bHasUnhiddenColumns ) + { + Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() ); + if( xLabel.is() ) + { + aRange = xLabel->getSourceRangeRepresentation(); + const sal_Int32 nId {aRange.getToken(1, ' ').toInt32()}; + if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), nId ) == rTable.aHiddenColumns.end() ) + bHasUnhiddenColumns = true; + } + } + } + if( bHasUnhiddenColumns ) + aRemainingSeries.push_back( rSeries ); + } + } + + if( static_cast(aRemainingSeries.size()) != aSeriesSeq.getLength() ) + { + //remove the series that have only hidden data + xSeriesContainer->setDataSeries( comphelper::containerToSequence(aRemainingSeries) ); + + //remove unused sequences + Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY ); + if( xDataSource.is() ) + { + //first detect which columns are really used + std::map< sal_Int32, bool > aUsageMap; + OUString aRange; + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aUsedSequences( xDataSource->getDataSequences() ); + for( const auto& xLabeledSequence : aUsedSequences ) + { + if(!xLabeledSequence.is()) + continue; + Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() ); + if( xValues.is() ) + { + aRange = xValues->getSourceRangeRepresentation(); + sal_Int32 nIndex = aRange.toInt32(); + if( nIndex!=0 || aRange != lcl_aCategoriesRange ) + aUsageMap[nIndex] = true; + } + Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() ); + if( xLabel.is() ) + { + aRange = xLabel->getSourceRangeRepresentation(); + OUString aSecondToken = aRange.getToken(1, ' '); + if( !aSecondToken.isEmpty() ) + aUsageMap[aSecondToken.toInt32()] = true; + } + } + + ::std::vector< sal_Int32 > aSequenceIndexesToDelete; + std::copy_if(rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), + std::back_inserter(aSequenceIndexesToDelete), + [&aUsageMap](sal_Int32 nSequenceIndex) { return aUsageMap.find(nSequenceIndex) == aUsageMap.end(); }); + + // delete unnecessary sequences of the internal data + // iterate using greatest index first, so that deletion does not + // shift other sequences that will be deleted later + ::std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end()); + for( ::std::vector< sal_Int32 >::reverse_iterator aIt( + aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt ) + { + if( *aIt != -1 ) + xInternalDataProvider->deleteSequence( *aIt ); + } + } + } + } + } + } + catch( const uno::Exception & ) + { + } + } +} + +SchXMLRangeSomewhereContext::SchXMLRangeSomewhereContext( SvXMLImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + OUString& rRangeString ) : + SvXMLImportContext( rImport, nPrefix, rLocalName ), + mrRangeString( rRangeString ) +{ +} + +SvXMLImportContextRef SchXMLRangeSomewhereContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + if( XML_NAMESPACE_SVG == nPrefix && IsXMLToken( rLocalName, XML_DESC ) ) + { + return new XMLStringBufferImportContext( + GetImport(), nPrefix, rLocalName, maRangeStringBuffer ); + } + return nullptr; +} + +void SchXMLRangeSomewhereContext::EndElement() +{ + mrRangeString = maRangeStringBuffer.makeStringAndClear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTableContext.hxx b/xmloff/source/chart/SchXMLTableContext.hxx new file mode 100644 index 000000000..f0293195d --- /dev/null +++ b/xmloff/source/chart/SchXMLTableContext.hxx @@ -0,0 +1,188 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTABLECONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTABLECONTEXT_HXX + +#include +#include +#include + +#include + +#include "transporttypes.hxx" + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } + namespace chart { + class XChartDocument; + } +} + +class SchXMLTableContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + SchXMLTable& mrTable; + + bool mbHasRowPermutation; + bool mbHasColumnPermutation; + css::uno::Sequence< sal_Int32 > maRowPermutation; + css::uno::Sequence< sal_Int32 > maColumnPermutation; + +public: + SchXMLTableContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ); + virtual ~SchXMLTableContext() override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + + void setRowPermutation( const css::uno::Sequence< sal_Int32 > & rPermutation ); + void setColumnPermutation( const css::uno::Sequence< sal_Int32 > & rPermutation ); +}; + +class SchXMLTableHelper +{ +public: + static void applyTableToInternalDataProvider( const SchXMLTable& rTable, + const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc ); + + /** This function reorders local data to fit the correct data structure. + Call it after the data series got their styles set. + */ + static void switchRangesFromOuterToInternalIfNecessary( const SchXMLTable& rTable, + const tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc, + css::chart::ChartDataRowSource eDataRowSource ); +}; + +// classes for columns + +/** With this context all column elements are parsed to + determine the index of the column containing + the row descriptions and probably get an estimate + for the altogether number of columns + */ +class SchXMLTableColumnsContext : public SvXMLImportContext +{ +private: + SchXMLTable& mrTable; + +public: + SchXMLTableColumnsContext( SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ); + virtual ~SchXMLTableColumnsContext() override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +class SchXMLTableColumnContext : public SvXMLImportContext +{ +private: + SchXMLTable& mrTable; + +public: + SchXMLTableColumnContext( SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ); + virtual ~SchXMLTableColumnContext() override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +// classes for rows + +class SchXMLTableRowsContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + SchXMLTable& mrTable; + +public: + SchXMLTableRowsContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ); + virtual ~SchXMLTableRowsContext() override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +class SchXMLTableRowContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + SchXMLTable& mrTable; + +public: + SchXMLTableRowContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ); + virtual ~SchXMLTableRowContext() override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +// classes for cells and their content + +class SchXMLTableCellContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + SchXMLTable& mrTable; + OUString maCellContent; + OUString maRangeId; + bool mbReadText; + +public: + SchXMLTableCellContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rLocalName, + SchXMLTable& aTable ); + virtual ~SchXMLTableCellContext() override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTABLECONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTextListContext.cxx b/xmloff/source/chart/SchXMLTextListContext.cxx new file mode 100644 index 000000000..a494c79a0 --- /dev/null +++ b/xmloff/source/chart/SchXMLTextListContext.cxx @@ -0,0 +1,119 @@ +/* -*- 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 "SchXMLTextListContext.hxx" +#include "SchXMLParagraphContext.hxx" + +#include +#include + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using namespace com::sun::star; +using namespace ::xmloff::token; + +namespace { + +class SchXMLListItemContext : public SvXMLImportContext +{ +public: + SchXMLListItemContext( SvXMLImport& rImport, const OUString& rLocalName, OUString& rText ); + + virtual void StartElement( const Reference< xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + OUString& m_rText; +}; + +} + +SchXMLListItemContext::SchXMLListItemContext( + SvXMLImport& rImport + , const OUString& rLocalName + , OUString& rText ) + : SvXMLImportContext( rImport, XML_NAMESPACE_TEXT, rLocalName ) + , m_rText( rText ) +{ +} + +void SchXMLListItemContext::StartElement( const Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ +} + +void SchXMLListItemContext::EndElement() +{ +} + +SvXMLImportContextRef SchXMLListItemContext::CreateChildContext( + sal_uInt16 nPrefix, const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + if( (nPrefix == XML_NAMESPACE_TEXT || + nPrefix == XML_NAMESPACE_LO_EXT) && IsXMLToken( rLocalName, XML_P ) ) + pContext = new SchXMLParagraphContext( GetImport(), rLocalName, m_rText ); + return pContext; +} + +SchXMLTextListContext::SchXMLTextListContext( + SvXMLImport& rImport + , const OUString& rLocalName + , Sequence< OUString>& rTextList ) + : SvXMLImportContext( rImport, XML_NAMESPACE_TEXT, rLocalName ) + , m_rTextList( rTextList ) + , m_aTextVector() +{ +} + +SchXMLTextListContext::~SchXMLTextListContext() +{ +} + +void SchXMLTextListContext::StartElement( const Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ +} + +void SchXMLTextListContext::EndElement() +{ + sal_Int32 nCount = m_aTextVector.size(); + m_rTextList.realloc(nCount); + for( sal_Int32 nN=0; nN& ) +{ + SvXMLImportContext* pContext = nullptr; + if( nPrefix == XML_NAMESPACE_TEXT && IsXMLToken( rLocalName, XML_LIST_ITEM ) ) + { + m_aTextVector.emplace_back( ); + pContext = new SchXMLListItemContext( GetImport(), rLocalName, m_aTextVector.back() ); + } + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTextListContext.hxx b/xmloff/source/chart/SchXMLTextListContext.hxx new file mode 100644 index 000000000..2b15c17c6 --- /dev/null +++ b/xmloff/source/chart/SchXMLTextListContext.hxx @@ -0,0 +1,52 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTEXTLISTCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTEXTLISTCONTEXT_HXX + +#include +#include +#include + +namespace com::sun::star::xml::sax { + class XAttributeList; +} + +class SchXMLTextListContext : public SvXMLImportContext +{ +public: + SchXMLTextListContext( SvXMLImport& rImport, + const OUString& rLocalName, + css::uno::Sequence< OUString>& rTextList ); + virtual ~SchXMLTextListContext() override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + +private: + css::uno::Sequence< OUString>& m_rTextList; + std::vector< OUString> m_aTextVector; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTEXTLISTCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTools.cxx b/xmloff/source/chart/SchXMLTools.cxx new file mode 100644 index 000000000..f500ae820 --- /dev/null +++ b/xmloff/source/chart/SchXMLTools.cxx @@ -0,0 +1,856 @@ +/* -*- 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 "SchXMLTools.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +OUString lcl_getGeneratorFromModel( const uno::Reference< frame::XModel >& xChartModel ) +{ + OUString aGenerator; + uno::Reference< document::XDocumentPropertiesSupplier> xChartDocumentPropertiesSupplier( xChartModel, uno::UNO_QUERY ); + if( xChartDocumentPropertiesSupplier.is() ) + { + uno::Reference< document::XDocumentProperties > xChartDocumentProperties( + xChartDocumentPropertiesSupplier->getDocumentProperties()); + if( xChartDocumentProperties.is() ) + aGenerator = xChartDocumentProperties->getGenerator(); + } + return aGenerator; +} + +OUString lcl_getGeneratorFromModelOrItsParent( const uno::Reference< frame::XModel >& xChartModel ) +{ + OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( aGenerator.isEmpty() ) //try to get the missing info from the parent document + { + uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY ); + if( xChild.is() ) + aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) ); + } + return aGenerator; +} + +sal_Int32 lcl_getBuildIDFromGenerator( const OUString& rGenerator ) +{ + //returns -1 if nothing found + sal_Int32 nBuildId = -1; + const OUString sBuildCompare( "$Build-" ); + sal_Int32 nBegin = rGenerator.indexOf( sBuildCompare ); + if( nBegin >= 0 ) + { + OUString sBuildId( rGenerator.copy( nBegin + sBuildCompare.getLength() ) ); + nBuildId = sBuildId.toInt32(); + } + return nBuildId; +} + +OUString lcl_ConvertRange( const OUString & rRange, const Reference< chart2::data::XDataProvider >& xDataProvider ) +{ + OUString aResult = rRange; + Reference< chart2::data::XRangeXMLConversion > xRangeConversion( xDataProvider, uno::UNO_QUERY ); + if( xRangeConversion.is()) + aResult = xRangeConversion->convertRangeFromXML( rRange ); + return aResult; +} + +Reference< chart2::data::XDataSequence > lcl_createNewSequenceFromCachedXMLRange( const Reference< chart2::data::XDataSequence >& xSeq, const Reference< chart2::data::XDataProvider >& xDataProvider ) +{ + Reference< chart2::data::XDataSequence > xRet; + OUString aRange; + if( xSeq.is() && SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) ) + { + xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( + lcl_ConvertRange( aRange, xDataProvider )) ); + SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xRet, uno::UNO_QUERY )); + } + return xRet; +} + +} // anonymous namespace + +namespace SchXMLTools +{ + +static const SvXMLEnumMapEntry aXMLChartClassMap[] = +{ + { XML_LINE, XML_CHART_CLASS_LINE }, + { XML_AREA, XML_CHART_CLASS_AREA }, + { XML_CIRCLE, XML_CHART_CLASS_CIRCLE }, + { XML_RING, XML_CHART_CLASS_RING }, + { XML_SCATTER, XML_CHART_CLASS_SCATTER }, + { XML_RADAR, XML_CHART_CLASS_RADAR }, + { XML_FILLED_RADAR, XML_CHART_CLASS_FILLED_RADAR }, + { XML_BAR, XML_CHART_CLASS_BAR }, + { XML_STOCK, XML_CHART_CLASS_STOCK }, + { XML_BUBBLE, XML_CHART_CLASS_BUBBLE }, + { XML_SURFACE, XML_CHART_CLASS_BAR }, //@todo change this if a surface chart is available + { XML_ADD_IN, XML_CHART_CLASS_ADDIN }, + { XML_TOKEN_INVALID, XML_CHART_CLASS_UNKNOWN } +}; + +SchXMLChartTypeEnum GetChartTypeEnum( const OUString& rClassName ) +{ + SchXMLChartTypeEnum nEnumVal = XML_CHART_CLASS_UNKNOWN; + SvXMLUnitConverter::convertEnum( nEnumVal, rClassName, aXMLChartClassMap ); + return nEnumVal; +} + +typedef std::map< OUString, OUString > tMakeStringStringMap; +//static +static const tMakeStringStringMap& lcl_getChartTypeNameMap() +{ + //shape property -- chart model object property + static const tMakeStringStringMap g_aChartTypeNameMap{ + {"com.sun.star.chart.LineDiagram", + "com.sun.star.chart2.LineChartType"}, + {"com.sun.star.chart.AreaDiagram", + "com.sun.star.chart2.AreaChartType"}, + {"com.sun.star.chart.BarDiagram", + "com.sun.star.chart2.ColumnChartType"}, + {"com.sun.star.chart.PieDiagram", + "com.sun.star.chart2.PieChartType"}, + {"com.sun.star.chart.DonutDiagram", + "com.sun.star.chart2.DonutChartType"}, + {"com.sun.star.chart.XYDiagram", + "com.sun.star.chart2.ScatterChartType"}, + {"com.sun.star.chart.NetDiagram", + "com.sun.star.chart2.NetChartType"}, + {"com.sun.star.chart.FilledNetDiagram", + "com.sun.star.chart2.FilledNetChartType"}, + {"com.sun.star.chart.StockDiagram", + "com.sun.star.chart2.CandleStickChartType"}, + {"com.sun.star.chart.BubbleDiagram", + "com.sun.star.chart2.BubbleChartType"}}; + return g_aChartTypeNameMap; +} + +OUString GetNewChartTypeName( const OUString & rOldChartTypeName ) +{ + OUString aNew(rOldChartTypeName); + + const tMakeStringStringMap& rMap = lcl_getChartTypeNameMap(); + tMakeStringStringMap::const_iterator aIt( rMap.find( rOldChartTypeName )); + if( aIt != rMap.end()) + { + aNew = aIt->second; + } + return aNew; +} + +OUString GetChartTypeByClassName( + const OUString & rClassName, bool bUseOldNames ) +{ + OUStringBuffer aResultBuffer; + bool bInternalType = false; + + if( bUseOldNames ) + aResultBuffer.append( "com.sun.star.chart."); + else + aResultBuffer.append( "com.sun.star.chart2."); + + bInternalType = true; + + if( IsXMLToken( rClassName, XML_LINE )) + aResultBuffer.append("Line"); + else if( IsXMLToken( rClassName, XML_AREA )) + aResultBuffer.append("Area"); + else if( IsXMLToken( rClassName, XML_BAR )) + { + if( bUseOldNames ) + aResultBuffer.append("Bar"); + else + { + aResultBuffer.append("Column"); + // @todo: might be Bar + } + } + else if( IsXMLToken( rClassName, XML_CIRCLE )) + aResultBuffer.append("Pie"); + else if( IsXMLToken( rClassName, XML_RING )) + aResultBuffer.append("Donut"); + else if( IsXMLToken( rClassName, XML_SCATTER )) + { + if( bUseOldNames ) + aResultBuffer.append("XY"); + else + aResultBuffer.append("Scatter"); + } + + else if( IsXMLToken( rClassName, XML_BUBBLE )) + aResultBuffer.append("Bubble"); + else if( IsXMLToken( rClassName, XML_RADAR )) + aResultBuffer.append("Net"); + else if( IsXMLToken( rClassName, XML_FILLED_RADAR )) + aResultBuffer.append("FilledNet"); + else if( IsXMLToken( rClassName, XML_STOCK )) + { + if( bUseOldNames ) + aResultBuffer.append("Stock"); + else + aResultBuffer.append("CandleStick"); + } + else if( IsXMLToken( rClassName, XML_SURFACE )) + { + //@todo change this if a surface chart is available + if( bUseOldNames ) + aResultBuffer.append("Bar"); + else + aResultBuffer.append("Column"); + } + else + bInternalType = false; + + if( ! bInternalType ) + return OUString(); + + if( bUseOldNames ) + aResultBuffer.append("Diagram"); + else + aResultBuffer.append("ChartType"); + + return aResultBuffer.makeStringAndClear(); + +} + +XMLTokenEnum getTokenByChartType( + const OUString & rChartTypeService, bool bUseOldNames ) +{ + XMLTokenEnum eResult = XML_TOKEN_INVALID; + OUString aPrefix, aPostfix; + + if( bUseOldNames ) + { + aPrefix = "com.sun.star.chart."; + aPostfix = "Diagram"; + } + else + { + aPrefix = "com.sun.star.chart2."; + aPostfix = "ChartType"; + } + + if( rChartTypeService.match( aPrefix )) + { + sal_Int32 nSkip = aPrefix.getLength(); + SAL_WARN_IF( rChartTypeService.getLength() < nSkip, "xmloff.chart", "ChartTypeService.getLength() < nSkip" ); + sal_Int32 nTypeLength = rChartTypeService.getLength() - nSkip - aPostfix.getLength(); + // if postfix matches and leaves a non-empty type + if( nTypeLength > 0 && rChartTypeService.match( aPostfix, nSkip + nTypeLength )) + { + OUString aServiceName( rChartTypeService.copy( nSkip, nTypeLength )); + + if ( aServiceName == "Line" ) + eResult = XML_LINE; + else if ( aServiceName == "Area" ) + eResult = XML_AREA; + else if( aServiceName == "Bar" || + (!bUseOldNames && aServiceName == "Column")) + eResult = XML_BAR; + else if ( aServiceName == "Pie" ) + eResult = XML_CIRCLE; + else if ( aServiceName == "Donut" ) + eResult = XML_RING; + else if( (bUseOldNames && aServiceName == "XY") || + (!bUseOldNames && aServiceName == "Scatter")) + eResult = XML_SCATTER; + else if ( aServiceName == "Bubble" ) + eResult = XML_BUBBLE; + else if ( aServiceName == "Net" ) + eResult = XML_RADAR; + else if ( aServiceName == "FilledNet" ) + eResult = XML_FILLED_RADAR; + else if( (bUseOldNames && aServiceName == "Stock") || + (!bUseOldNames && aServiceName == "CandleStick")) + eResult = XML_STOCK; + } + } + + if( eResult == XML_TOKEN_INVALID && !rChartTypeService.isEmpty() ) + eResult = XML_ADD_IN; + + return eResult; +} + +Reference< chart2::data::XLabeledDataSequence2 > GetNewLabeledDataSequence() +{ + Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + Reference< chart2::data::XLabeledDataSequence2 > xResult = chart2::data::LabeledDataSequence::create(xContext); + return xResult; +} + +Reference< chart2::data::XDataSequence > CreateDataSequence( + const OUString & rRange, + const Reference< chart2::XChartDocument >& xChartDoc ) +{ + Reference< chart2::data::XDataSequence > xRet; + + if( !xChartDoc.is() ) + { + SAL_WARN("xmloff.chart", "need a chart document" ); + return xRet; + } + + Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + if( !xDataProvider.is() ) + { + SAL_WARN("xmloff.chart", "need a data provider" ); + return xRet; + } + + bool bUseInternal = false; + uno::Reference xPropSet(xDataProvider, uno::UNO_QUERY); + if (xPropSet.is()) + { + try + { + bool bVal = false; + uno::Any any = xPropSet->getPropertyValue("UseInternalDataProvider"); + if (any >>= bVal) + bUseInternal = bVal; + } + catch (const beans::UnknownPropertyException&) + { + // Do nothing + } + } + + if (!bUseInternal) + { + try + { + xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider ))); + SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange ); + } + catch( const lang::IllegalArgumentException & ) + { + SAL_WARN("xmloff.chart", "could not create data sequence" ); + } + } + + if( !xRet.is() && !xChartDoc->hasInternalDataProvider() && !rRange.isEmpty() ) + { + //#i103911# switch to internal data in case the parent cannot provide the requested data + xChartDoc->createInternalDataProvider( true /* bCloneExistingData */ ); + xDataProvider = xChartDoc->getDataProvider(); + try + { + xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider ))); + SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange ); + } + catch( const lang::IllegalArgumentException & ) + { + SAL_WARN("xmloff.chart", "could not create data sequence" ); + } + } + return xRet; +} + +Reference< chart2::data::XDataSequence > CreateDataSequenceWithoutConvert( + const OUString & rRange, + const Reference< chart2::XChartDocument >& xChartDoc ) +{ + Reference< chart2::data::XDataSequence > xRet; + + if( !xChartDoc.is() ) + { + SAL_WARN("xmloff.chart", "need a chart document" ); + return xRet; + } + + Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + if( !xDataProvider.is() ) + { + SAL_WARN("xmloff.chart", "need a data provider" ); + return xRet; + } + + try + { + xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( rRange ) ); + SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange ); + } + catch( const lang::IllegalArgumentException & ) + { + SAL_WARN("xmloff.chart", "could not create data sequence" ); + } + + return xRet; +} + +void CreateCategories( + const uno::Reference< chart2::data::XDataProvider > & xDataProvider, + const uno::Reference< chart2::XChartDocument > & xNewDoc, + const OUString & rRangeAddress, + sal_Int32 nCooSysIndex, + sal_Int32 nDimensionIndex, + tSchXMLLSequencesPerIndex * pLSequencesPerIndex ) +{ + try + { + if( xNewDoc.is() && !rRangeAddress.isEmpty()) + { + if( xDataProvider.is()) + { + uno::Reference< chart2::XDiagram > xDia( xNewDoc->getFirstDiagram()); + if( !xDia.is()) + return; + + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + if( nCooSysIndex < aCooSysSeq.getLength()) + { + uno::Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] ); + SAL_WARN_IF( !xCooSys.is(), "xmloff.chart", "xCooSys is NULL"); + if( nDimensionIndex < xCooSys->getDimension() ) + { + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI) + { + uno::Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nI )); + if( xAxis.is() ) + { + chart2::ScaleData aData( xAxis->getScaleData()); + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW); + try + { + OUString aConvertedRange( rRangeAddress ); + bool bRangeConverted = false; + if( ! (xNewDoc->hasInternalDataProvider() && aConvertedRange == "categories")) + { + Reference< chart2::data::XRangeXMLConversion > xXMLConv( xDataProvider, uno::UNO_QUERY ); + if( xXMLConv.is()) + { + aConvertedRange = xXMLConv->convertRangeFromXML( rRangeAddress ); + bRangeConverted = true; + } + } + + Reference xSequence; + Reference xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); + if (xPivotTableDataProvider.is()) + { + xSequence.set(xPivotTableDataProvider->createDataSequenceOfCategories()); + } + else + { + xSequence.set(xDataProvider->createDataSequenceByRangeRepresentation(aConvertedRange)); + if (bRangeConverted) + setXMLRangePropertyAtDataSequence(xSequence, rRangeAddress); + } + xLabeledSeq->setValues(xSequence); + + } + catch( const lang::IllegalArgumentException & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + aData.Categories.set( xLabeledSeq ); + if( pLSequencesPerIndex ) + { + // register for setting local data if external data provider is not present + pLSequencesPerIndex->emplace( + tSchXMLIndexWithPart( SCH_XML_CATEGORIES_INDEX, SCH_XML_PART_VALUES ), xLabeledSeq ); + } + xAxis->setScaleData( aData ); + } + } + } + } + } + } + } + catch( uno::Exception & ) + { + SAL_WARN("xmloff.chart", "Exception caught while creating Categories" ); + } +} + +uno::Any getPropertyFromContext( const OUString& rPropertyName, const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) +{ + uno::Any aRet; + if( !pPropStyleContext || !pStylesCtxt ) + return aRet; + const ::std::vector< XMLPropertyState >& rProperties = pPropStyleContext->GetProperties(); + const rtl::Reference< XMLPropertySetMapper >& rMapper = pStylesCtxt->GetImportPropertyMapper( pPropStyleContext->GetFamily()/*XML_STYLE_FAMILY_SCH_CHART_ID*/ )->getPropertySetMapper(); + for( const auto& rProp : rProperties ) + { + sal_Int32 nIdx = rProp.mnIndex; + if( nIdx == -1 ) + continue; + OUString aPropName = rMapper->GetEntryAPIName( nIdx ); + if(rPropertyName == aPropName) + return rProp.maValue; + } + return aRet; +} + +void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsLFs ) +{ + SvXMLElementExport aPara( rExport, XML_NAMESPACE_TEXT, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_P ), + true, false ); + + if( bConvertTabsLFs ) + { + sal_Int32 nStartPos = 0; + sal_Int32 nEndPos = rText.getLength(); + sal_Unicode cChar; + + for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ ) + { + cChar = rText[ nPos ]; + switch( cChar ) + { + case 0x0009: // tabulator + { + if( nPos > nStartPos ) + rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) ); + nStartPos = nPos + 1; + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_TAB_STOP ), + false, false ); + } + break; + + case 0x000A: // linefeed + { + if( nPos > nStartPos ) + rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) ); + nStartPos = nPos + 1; + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_LINE_BREAK ), + false, false ); + } + break; + } + } + if( nEndPos > nStartPos ) + { + if( nStartPos == 0 ) + rExport.GetDocHandler()->characters( rText ); + else + rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nEndPos - nStartPos)) ); + } + } + else // do not convert tabs and linefeeds (eg for numbers coming from unit converter) + { + rExport.GetDocHandler()->characters( rText ); + } +} + +void exportRangeToSomewhere( SvXMLExport& rExport, const OUString& rValue ) +{ + //with issue #i366# and CWS chart20 ranges for error bars were introduced + //to keep them during copy paste from calc to impress for example it + //was necessary to introduce a mapping between the used ranges within calc and the data written to the local table + //this is why we write this ranges here + + //#i113950# first the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore within ODF 1.2 + //as an alternative the range info is now saved into the description at an empty group element (not very nice, but ODF conform) + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentODFVersion == SvtSaveOptions::ODFSVER_010 || nCurrentODFVersion == SvtSaveOptions::ODFSVER_011) + return;//svg:desc is not allowed at draw:g in ODF1.0; but as the ranges for error bars are anyhow not allowed within ODF1.0 nor ODF1.1 we do not need the information + + SvXMLElementExport aEmptyShapeGroup( rExport, XML_NAMESPACE_DRAW, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_G ), + true, false ); + SvXMLElementExport aDescription( rExport, XML_NAMESPACE_SVG, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DESC ), + true, false ); + rExport.GetDocHandler()->characters( rValue ); +} + +void setXMLRangePropertyAtDataSequence( + const Reference< chart2::data::XDataSequence > & xDataSequence, + const OUString & rXMLRange ) +{ + if( !xDataSequence.is()) + return; + try + { + const OUString aXMLRangePropName( "CachedXMLRange" ); + Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW ); + Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo()); + if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName )) + xProp->setPropertyValue( aXMLRangePropName, uno::makeAny( rXMLRange )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } +} + +bool getXMLRangePropertyFromDataSequence( + const Reference< chart2::data::XDataSequence > & xDataSequence, + OUString & rOutXMLRange, + bool bClearProp /* = false */) +{ + bool bResult = false; + if( xDataSequence.is()) + { + try + { + const OUString aXMLRangePropName( "CachedXMLRange" ); + Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW ); + Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo()); + bResult = + ( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ) && + ( xProp->getPropertyValue( aXMLRangePropName ) >>= rOutXMLRange ) && + !rOutXMLRange.isEmpty()); + // clear the property after usage + if( bClearProp && bResult ) + xProp->setPropertyValue( aXMLRangePropName, uno::Any( OUString())); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + } + return bResult; +} + +void copyProperties( + const Reference< beans::XPropertySet > & xSource, + const Reference< beans::XPropertySet > & xDestination ) +{ + if( ! (xSource.is() && xDestination.is()) ) + return; + + try + { + Reference< beans::XPropertySetInfo > xSrcInfo( xSource->getPropertySetInfo(), uno::UNO_SET_THROW ); + Reference< beans::XPropertySetInfo > xDestInfo( xDestination->getPropertySetInfo(), uno::UNO_SET_THROW ); + const Sequence< beans::Property > aProperties( xSrcInfo->getProperties()); + for( const auto& rProperty : aProperties ) + { + OUString aName( rProperty.Name); + if( xDestInfo->hasPropertyByName( aName )) + { + beans::Property aProp( xDestInfo->getPropertyByName( aName )); + if( (aProp.Attributes & beans::PropertyAttribute::READONLY) == 0 ) + xDestination->setPropertyValue( + aName, xSource->getPropertyValue( aName )); + } + } + } + catch( const uno::Exception & ) + { + SAL_WARN("xmloff.chart", "Copying property sets failed!" ); + } +} + +bool switchBackToDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc, const tSchXMLLSequencesPerIndex & rLSequencesPerIndex ) +{ + //return whether the switch is successful + if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() ) + return false; + Reference< chart2::data::XDataProvider > xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc ) ); + if( !xDataProviderFromParent.is() ) + return false; + uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY ); + if( !xDataReceiver.is() ) + return false; + + xDataReceiver->attachDataProvider( xDataProviderFromParent ); + + for( const auto& rLSeq : rLSequencesPerIndex ) + { + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( rLSeq.second ); + if( !xLabeledSeq.is() ) + continue; + Reference< chart2::data::XDataSequence > xNewSeq; + xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getValues(), xDataProviderFromParent ); + if( xNewSeq.is() ) + xLabeledSeq->setValues( xNewSeq ); + xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getLabel(), xDataProviderFromParent ); + if( xNewSeq.is() ) + xLabeledSeq->setLabel( xNewSeq ); + } + return true; +} + +void setBuildIDAtImportInfo( const uno::Reference< frame::XModel >& xModel, const Reference< beans::XPropertySet >& xImportInfo ) +{ + OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xModel) ); + if( !aGenerator.isEmpty() ) + SvXMLMetaDocumentContext::setBuildId( aGenerator, xImportInfo ); +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const uno::Reference< frame::XModel >& xChartModel ) +{ + bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel ); + if( !bResult ) + { + OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( aGenerator.indexOf( "OpenOffice.org_project/3" ) != -1 ) + { + if( aGenerator.indexOf( "OpenOffice.org_project/300m" ) != -1 ) + { + sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( nBuilId>0 && nBuilId<9491 ) //9491 is build id of dev300m76 + bResult= true; + } + else if( aGenerator.indexOf( "OpenOffice.org_project/310m" ) != -1 ) + bResult= true; + else if( aGenerator.indexOf( "OpenOffice.org_project/320m" ) != -1 ) + bResult= true; + } + } + return bResult; +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const uno::Reference< frame::XModel >& xChartModel ) +{ + bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel ); + if( !bResult ) + { + OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( aGenerator.indexOf( "OpenOffice.org_project/680m" ) != -1 ) + bResult= true; + } + return bResult; +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const uno::Reference< frame::XModel >& xChartModel ) +{ + if( isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel ) ) + return true; + + if( isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel ) ) + { + sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( nBuilId>0 && nBuilId<=9238 ) //9238 is build id of OpenOffice.org 2.3.1 + return true; + } + return false; +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const uno::Reference< frame::XModel >& xChartModel ) +{ + bool bResult = false; + OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); + //if there is a meta stream at the chart object it was not written with an older OpenOffice version < 2.3 + if( aGenerator.isEmpty() ) + { + //if there is no meta stream at the chart object we need to check whether the parent document is OpenOffice at all + uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY ); + if( xChild.is() ) + { + aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) ); + if( aGenerator.indexOf( "OpenOffice.org_project" ) != -1 ) + { + //the chart application has not created files without a meta stream since OOo 2.3 (OOo 2.3 has written a metastream already) + //only the report builder extension has created some files with OOo 3.1 that do not have a meta stream + if( aGenerator.indexOf( "OpenOffice.org_project/31" ) != -1 ) + bResult = false;//#i100102# probably generated with OOo 3.1 by the report designer + else + bResult= true; //in this case the OLE chart was created by an older version, as OLE objects are sometimes stream copied the version can differ from the parents version, so the parents version is not a reliable indicator + } + else if( isDocumentGeneratedWithOpenOfficeOlderThan2_0(xChartModel) ) + bResult= true; + } + } + return bResult; +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const css::uno::Reference< css::frame::XModel >& xChartModel) +{ + bool bResult = false; + OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xChartModel) ); + if( aGenerator.startsWith( "OpenOffice.org 1" ) + || aGenerator.startsWith( "StarOffice 6" ) + || aGenerator.startsWith( "StarOffice 7" ) + || aGenerator.startsWith( "StarSuite 6" ) + || aGenerator.startsWith( "StarSuite 7" ) + ) + bResult= true; + return bResult; +} + +Reference< chart2::data::XDataProvider > getDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc ) +{ + Reference< chart2::data::XDataProvider > xRet; + uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY ); + if( xChild.is() ) + { + Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY ); + if( xFact.is() ) + { + const OUString aDataProviderServiceName( "com.sun.star.chart2.data.DataProvider"); + const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames()); + const OUString * pBegin = aServiceNames.getConstArray(); + const OUString * pEnd = pBegin + aServiceNames.getLength(); + if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd ) + { + xRet.set( xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY ); + } + } + } + return xRet; +} + +} // namespace SchXMLTools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTools.hxx b/xmloff/source/chart/SchXMLTools.hxx new file mode 100644 index 000000000..f57b41713 --- /dev/null +++ b/xmloff/source/chart/SchXMLTools.hxx @@ -0,0 +1,139 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTOOLS_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTOOLS_HXX + +#include +#include +#include "transporttypes.hxx" + +#include +#include + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + class XRegressionCurve; + namespace data { + class XDataProvider; + } + } +} + +class XMLPropStyleContext; +class SvXMLStylesContext; +class SvXMLExport; + +namespace SchXMLTools +{ + bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const css::uno::Reference< css::frame::XModel >& xChartModel); + bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const css::uno::Reference< css::frame::XModel >& xChartModel); + bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const css::uno::Reference< css::frame::XModel >& xChartModel); + bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const css::uno::Reference< css::frame::XModel >& xChartModel); + bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const css::uno::Reference< css::frame::XModel >& xChartModel); + + void setBuildIDAtImportInfo( const css::uno::Reference< css::frame::XModel >& xModel + , const css::uno::Reference< css::beans::XPropertySet >& xImportInfo ); + + enum SchXMLChartTypeEnum + { + XML_CHART_CLASS_LINE, + XML_CHART_CLASS_AREA, + XML_CHART_CLASS_CIRCLE, + XML_CHART_CLASS_RING, + XML_CHART_CLASS_SCATTER, + XML_CHART_CLASS_RADAR, + XML_CHART_CLASS_FILLED_RADAR, + XML_CHART_CLASS_BAR, + XML_CHART_CLASS_STOCK, + XML_CHART_CLASS_BUBBLE, + XML_CHART_CLASS_ADDIN, + XML_CHART_CLASS_UNKNOWN + }; + + SchXMLChartTypeEnum GetChartTypeEnum( const OUString& rClassName ); + + OUString GetChartTypeByClassName( + const OUString & rClassName, bool bUseOldNames ); + + ::xmloff::token::XMLTokenEnum getTokenByChartType( + const OUString & rChartTypeService, bool bUseOldNames ); + + OUString GetNewChartTypeName( const OUString & rOldChartTypeName ); + + css::uno::Reference< + css::chart2::data::XLabeledDataSequence2 > GetNewLabeledDataSequence(); + + css::uno::Reference< css::chart2::data::XDataSequence > CreateDataSequence( + const OUString& rRange, + const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc ); + + css::uno::Reference< css::chart2::data::XDataSequence > CreateDataSequenceWithoutConvert( + const OUString& rRange, + const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc ); + + void CreateCategories( + const css::uno::Reference< css::chart2::data::XDataProvider > & xDataProvider, + const css::uno::Reference< css::chart2::XChartDocument > & xNewDoc, + const OUString & rRangeAddress, + sal_Int32 nCooSysIndex, + sal_Int32 nDimensionIndex, + tSchXMLLSequencesPerIndex * pLSequencesPerIndex = nullptr ); + + css::uno::Any getPropertyFromContext( const OUString& rPropertyName, const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ); + + void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsLFs ); + + void exportRangeToSomewhere( SvXMLExport& rExport, const OUString& rValue ); + + /** checks if the data sequence has the property "CachedXMLRange" (true for + internal data sequences), and if so sets this property to the range + given in rXMLRange + */ + void setXMLRangePropertyAtDataSequence( + const css::uno::Reference< css::chart2::data::XDataSequence > & xDataSequence, + const OUString & rXMLRange ); + + /** checks if the data sequence has the property "CachedXMLRange" (true for + internal data sequences), and if so retrieves this property and applies + it to the range given in rOutXMLRange. + + @param bClearProp If true, the property is reset to its default after it + was assigned to rOutXMLRange + + @return true, if the property was found, assigned and is non-empty + */ + bool getXMLRangePropertyFromDataSequence( + const css::uno::Reference< css::chart2::data::XDataSequence > & xDataSequence, + OUString & rOutXMLRange, + bool bClearProp ); + + css::uno::Reference< css::chart2::data::XDataProvider > getDataProviderFromParent( const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc ); + + bool switchBackToDataProviderFromParent( const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc + , const tSchXMLLSequencesPerIndex & rLSequencesPerIndex ); + + void copyProperties( + const css::uno::Reference< css::beans::XPropertySet > & xSource, + const css::uno::Reference< css::beans::XPropertySet > & xDestination ); +} + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLTOOLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx b/xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx new file mode 100644 index 000000000..6508031ba --- /dev/null +++ b/xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx @@ -0,0 +1,134 @@ +/* -*- 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 "XMLAxisPositionPropertyHdl.hxx" + +#include + +#include +#include + +#include + +#include + + +using namespace ::xmloff::token; + +using namespace com::sun::star; + +XMLAxisPositionPropertyHdl::XMLAxisPositionPropertyHdl( bool bCrossingValue ) + : m_bCrossingValue( bCrossingValue ) +{} + +XMLAxisPositionPropertyHdl::~XMLAxisPositionPropertyHdl() +{} + +bool XMLAxisPositionPropertyHdl::importXML( const OUString& rStrImpValue, + uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bResult = false; + + if( rStrImpValue == GetXMLToken(XML_START) ) + { + if( !m_bCrossingValue ) + { + rValue <<= css::chart::ChartAxisPosition_START; + bResult = true; + } + } + else if( rStrImpValue == GetXMLToken(XML_END) ) + { + if( !m_bCrossingValue ) + { + rValue <<= css::chart::ChartAxisPosition_END; + bResult = true; + } + } + else if( rStrImpValue == GetXMLToken(XML_0) ) + { + if( !m_bCrossingValue ) + { + rValue <<= css::chart::ChartAxisPosition_ZERO; + bResult = true; + } + } + else + { + if( !m_bCrossingValue ) + { + rValue <<= css::chart::ChartAxisPosition_VALUE; + bResult = true; + } + else + { + double fDblValue=0.0; + bResult = ::sax::Converter::convertDouble(fDblValue, rStrImpValue); + rValue <<= fDblValue; + } + } + + return bResult; +} + +bool XMLAxisPositionPropertyHdl::exportXML( OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bResult = false; + + OUStringBuffer sValueBuffer; + if( m_bCrossingValue ) + { + if(rStrExpValue.isEmpty()) + { + double fValue = 0.0; + rValue >>= fValue; + ::sax::Converter::convertDouble( sValueBuffer, fValue ); + rStrExpValue = sValueBuffer.makeStringAndClear(); + bResult = true; + } + } + else + { + css::chart::ChartAxisPosition ePosition( css::chart::ChartAxisPosition_ZERO ); + rValue >>= ePosition; + switch(ePosition) + { + case css::chart::ChartAxisPosition_START: + rStrExpValue = GetXMLToken( XML_START ); + bResult = true; + break; + case css::chart::ChartAxisPosition_END: + rStrExpValue = GetXMLToken( XML_END ); + bResult = true; + break; + case css::chart::ChartAxisPosition_ZERO: + ::sax::Converter::convertDouble( sValueBuffer, 0.0 ); + rStrExpValue = sValueBuffer.makeStringAndClear(); + bResult = true; + break; + default: + break; + } + } + return bResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLAxisPositionPropertyHdl.hxx b/xmloff/source/chart/XMLAxisPositionPropertyHdl.hxx new file mode 100644 index 000000000..485b7a89c --- /dev/null +++ b/xmloff/source/chart/XMLAxisPositionPropertyHdl.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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_XMLAXISPOSITIONPROPERTYHDL_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_XMLAXISPOSITIONPROPERTYHDL_HXX + +#include + +class XMLAxisPositionPropertyHdl : public XMLPropertyHandler +{ +public: + explicit XMLAxisPositionPropertyHdl( bool bCrossingValue ); + virtual ~XMLAxisPositionPropertyHdl() 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; + +private: + bool m_bCrossingValue; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_XMLAXISPOSITIONPROPERTYHDL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLChartPropertyContext.cxx b/xmloff/source/chart/XMLChartPropertyContext.cxx new file mode 100644 index 000000000..ea3ead155 --- /dev/null +++ b/xmloff/source/chart/XMLChartPropertyContext.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 "XMLChartPropertyContext.hxx" +#include "PropertyMap.hxx" + +#include "XMLSymbolImageContext.hxx" +#include "XMLLabelSeparatorContext.hxx" +#include +#include + + +using namespace ::com::sun::star; + +XMLChartPropertyContext::XMLChartPropertyContext( + SvXMLImport& rImport, + sal_uInt16 nPrfx, + const OUString& rLName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState >& rProps, + const rtl::Reference< SvXMLImportPropertyMapper >& rMapper ) : + SvXMLPropertySetContext( rImport, nPrfx, rLName, xAttrList, nFamily, rProps, rMapper ) +{ +} + +XMLChartPropertyContext::~XMLChartPropertyContext() +{} + +SvXMLImportContextRef XMLChartPropertyContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + SvXMLImportContextRef xContext; + + switch( mxMapper->getPropertySetMapper()->GetEntryContextId( rProp.mnIndex ) ) + { + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE: + xContext = new XMLSymbolImageContext( GetImport(), nPrefix, rLocalName, rProp, rProperties ); + break; + case XML_SCH_CONTEXT_SPECIAL_LABEL_SEPARATOR: + xContext = new XMLLabelSeparatorContext( GetImport(), nPrefix, rLocalName, rProp, rProperties ); + break; + } + + // default / no context yet: create child context by base class + if (!xContext) + { + xContext = SvXMLPropertySetContext::CreateChildContext( + nPrefix, rLocalName, xAttrList, rProperties, rProp ); + } + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLChartPropertyContext.hxx b/xmloff/source/chart/XMLChartPropertyContext.hxx new file mode 100644 index 000000000..ba572e7e5 --- /dev/null +++ b/xmloff/source/chart/XMLChartPropertyContext.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_XMLCHARTPROPERTYCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_XMLCHARTPROPERTYCONTEXT_HXX + +#include + +class XMLChartPropertyContext : public SvXMLPropertySetContext +{ +public: + + XMLChartPropertyContext( SvXMLImport& rImport, sal_uInt16 nPrfx, + const OUString& rLName, + const css::uno::Reference< css::xml::sax::XAttributeList > & xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState >& rProps, + const rtl::Reference< SvXMLImportPropertyMapper >& rMapper ); + virtual ~XMLChartPropertyContext() override; + + using SvXMLPropertySetContext::CreateChildContext; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList > & xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; + +private: +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_XMLCHARTPROPERTYCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLChartStyleContext.cxx b/xmloff/source/chart/XMLChartStyleContext.cxx new file mode 100644 index 000000000..c0c33afc7 --- /dev/null +++ b/xmloff/source/chart/XMLChartStyleContext.cxx @@ -0,0 +1,148 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "XMLChartPropertyContext.hxx" + +using namespace com::sun::star; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_DATA_STYLE_NAME; +using ::xmloff::token::XML_PERCENTAGE_DATA_STYLE_NAME; +using ::xmloff::token::XML_TEXT_PROPERTIES; +using ::xmloff::token::XML_PARAGRAPH_PROPERTIES; +using ::xmloff::token::XML_GRAPHIC_PROPERTIES; +using ::xmloff::token::XML_CHART_PROPERTIES; + + +void XMLChartStyleContext::SetAttribute( + sal_uInt16 nPrefixKey, + const OUString& rLocalName, + const OUString& rValue ) +{ + if( IsXMLToken( rLocalName, XML_DATA_STYLE_NAME ) ) + { + msDataStyleName =rValue; + } + else if( IsXMLToken( rLocalName, XML_PERCENTAGE_DATA_STYLE_NAME ) ) + { + msPercentageDataStyleName =rValue; + } + else + { + XMLShapeStyleContext::SetAttribute( nPrefixKey, rLocalName, rValue ); + } +} + +XMLChartStyleContext::XMLChartStyleContext( + SvXMLImport& rImport, sal_uInt16 nPrfx, + const OUString& rLName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily ) : + + XMLShapeStyleContext( rImport, nPrfx, rLName, xAttrList, rStyles, nFamily ), + mrStyles( rStyles ) +{} + +XMLChartStyleContext::~XMLChartStyleContext() +{} + +namespace +{ + +void lcl_NumberFormatStyleToProperty( const OUString& rStyleName, const OUString& rPropertyName, + const SvXMLStylesContext& rStylesContext, + const uno::Reference< beans::XPropertySet >& rPropSet ) +{ + if( !rStyleName.isEmpty()) + { + const SvXMLNumFormatContext* pStyle = static_cast(rStylesContext.FindStyleChildContext( + XmlStyleFamily::DATA_STYLE, rStyleName, true )); + if( pStyle ) + { + sal_Int32 nNumberFormat = const_cast(pStyle)->GetKey(); + rPropSet->setPropertyValue( rPropertyName, uno::Any(nNumberFormat) ); + } + } +} + +} + +void XMLChartStyleContext::FillPropertySet( + const uno::Reference< beans::XPropertySet > & rPropSet ) +{ + try + { + XMLShapeStyleContext::FillPropertySet( rPropSet ); + } + catch( beans::UnknownPropertyException& ) + { + TOOLS_WARN_EXCEPTION( "xmloff", "unknown property exception -> shape style not completely imported for chart style" ); + } + + lcl_NumberFormatStyleToProperty( msDataStyleName, "NumberFormat", mrStyles, rPropSet ); + lcl_NumberFormatStyleToProperty( msPercentageDataStyleName, "PercentageNumberFormat", mrStyles, rPropSet ); +} + +SvXMLImportContextRef XMLChartStyleContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContextRef xContext; + + if( XML_NAMESPACE_STYLE == nPrefix || XML_NAMESPACE_LO_EXT == nPrefix ) + { + sal_uInt32 nFamily = 0; + if( IsXMLToken( rLocalName, XML_TEXT_PROPERTIES ) ) + nFamily = XML_TYPE_PROP_TEXT; + else if( IsXMLToken( rLocalName, XML_PARAGRAPH_PROPERTIES ) ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( IsXMLToken( rLocalName, XML_GRAPHIC_PROPERTIES ) ) + nFamily = XML_TYPE_PROP_GRAPHIC; + else if( IsXMLToken( rLocalName, XML_CHART_PROPERTIES ) ) + nFamily = XML_TYPE_PROP_CHART; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + xContext = new XMLChartPropertyContext( + GetImport(), nPrefix, rLocalName, xAttrList, nFamily, + GetProperties(), xImpPrMap ); + } + } + + if (!xContext) + xContext = XMLShapeStyleContext::CreateChildContext( nPrefix, rLocalName, + xAttrList ); + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLErrorBarStylePropertyHdl.cxx b/xmloff/source/chart/XMLErrorBarStylePropertyHdl.cxx new file mode 100644 index 000000000..0a14b5063 --- /dev/null +++ b/xmloff/source/chart/XMLErrorBarStylePropertyHdl.cxx @@ -0,0 +1,59 @@ +/* -*- 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 "XMLErrorBarStylePropertyHdl.hxx" +#include + +#include +#include + +using namespace com::sun::star; + +XMLErrorBarStylePropertyHdl::XMLErrorBarStylePropertyHdl( const SvXMLEnumMapEntry* pEnumMap ) + : XMLEnumPropertyHdl( pEnumMap ) +{ +} + +XMLErrorBarStylePropertyHdl::~XMLErrorBarStylePropertyHdl() +{ +} + +bool XMLErrorBarStylePropertyHdl::exportXML( OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + uno::Any aValue(rValue); + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(SvtSaveOptions().GetODFSaneDefaultVersion()); + if (nCurrentVersion < SvtSaveOptions::ODFSVER_012) + { + sal_Int32 nValue = 0; + if(rValue >>= nValue ) + { + if( nValue == css::chart::ErrorBarStyle::STANDARD_ERROR + || nValue == css::chart::ErrorBarStyle::FROM_DATA ) + { + nValue = css::chart::ErrorBarStyle::NONE; + aValue <<= nValue; + } + } + } + + return XMLEnumPropertyHdl::exportXML( rStrExpValue, aValue, rUnitConverter ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLErrorBarStylePropertyHdl.hxx b/xmloff/source/chart/XMLErrorBarStylePropertyHdl.hxx new file mode 100644 index 000000000..dfe6354c7 --- /dev/null +++ b/xmloff/source/chart/XMLErrorBarStylePropertyHdl.hxx @@ -0,0 +1,35 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_XMLERRORBARSTYLEPROPERTYHDL_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_XMLERRORBARSTYLEPROPERTYHDL_HXX + +#include + +class XMLErrorBarStylePropertyHdl : public XMLEnumPropertyHdl +{ +public: + XMLErrorBarStylePropertyHdl( const SvXMLEnumMapEntry* pEnumMap ); + virtual ~XMLErrorBarStylePropertyHdl() override; + + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_XMLERRORBARSTYLEPROPERTYHDL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.cxx b/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.cxx new file mode 100644 index 000000000..12ea12f51 --- /dev/null +++ b/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.cxx @@ -0,0 +1,103 @@ +/* -*- 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 "XMLErrorIndicatorPropertyHdl.hxx" + +#include + +#include +#include + +#include + + +using namespace com::sun::star; + +XMLErrorIndicatorPropertyHdl::~XMLErrorIndicatorPropertyHdl() +{} + +bool XMLErrorIndicatorPropertyHdl::importXML( const OUString& rStrImpValue, + uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bValue(false); + (void)::sax::Converter::convertBool( bValue, rStrImpValue ); + + // modify existing value + chart::ChartErrorIndicatorType eType = chart::ChartErrorIndicatorType_NONE; + if( rValue.hasValue()) + rValue >>= eType; + + if( bValue ) // enable flag + { + if( eType != chart::ChartErrorIndicatorType_TOP_AND_BOTTOM ) + { + if( mbUpperIndicator ) + eType = ( eType == chart::ChartErrorIndicatorType_LOWER ) + ? chart::ChartErrorIndicatorType_TOP_AND_BOTTOM + : chart::ChartErrorIndicatorType_UPPER; + else + eType = ( eType == chart::ChartErrorIndicatorType_UPPER ) + ? chart::ChartErrorIndicatorType_TOP_AND_BOTTOM + : chart::ChartErrorIndicatorType_LOWER; + } + } + else // disable flag + { + if( eType != chart::ChartErrorIndicatorType_NONE ) + { + if( mbUpperIndicator ) + eType = ( eType == chart::ChartErrorIndicatorType_UPPER ) + ? chart::ChartErrorIndicatorType_NONE + : chart::ChartErrorIndicatorType_LOWER; + else + eType = ( eType == chart::ChartErrorIndicatorType_LOWER ) + ? chart::ChartErrorIndicatorType_NONE + : chart::ChartErrorIndicatorType_UPPER; + } + } + + rValue <<= eType; + + return true; +} + +bool XMLErrorIndicatorPropertyHdl::exportXML( OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + OUStringBuffer aBuffer; + chart::ChartErrorIndicatorType eType; + + rValue >>= eType; + bool bValue = ( eType == chart::ChartErrorIndicatorType_TOP_AND_BOTTOM || + ( mbUpperIndicator + ? ( eType == chart::ChartErrorIndicatorType_UPPER ) + : ( eType == chart::ChartErrorIndicatorType_LOWER ))); + + if( bValue ) + { + ::sax::Converter::convertBool( aBuffer, bValue ); + rStrExpValue = aBuffer.makeStringAndClear(); + } + + // only export if set to true + return bValue; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.hxx b/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.hxx new file mode 100644 index 000000000..6e4de8706 --- /dev/null +++ b/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.hxx @@ -0,0 +1,40 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_XMLERRORINDICATORPROPERTYHDL_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_XMLERRORINDICATORPROPERTYHDL_HXX + +#include + +class XMLErrorIndicatorPropertyHdl : public XMLPropertyHandler +{ +private: + bool mbUpperIndicator; + +public: + explicit XMLErrorIndicatorPropertyHdl( bool bUpper ) : mbUpperIndicator( bUpper ) + {} + virtual ~XMLErrorIndicatorPropertyHdl() 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; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_XMLERRORINDICATORPROPERTYHDL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLLabelSeparatorContext.cxx b/xmloff/source/chart/XMLLabelSeparatorContext.cxx new file mode 100644 index 000000000..dec08c2ad --- /dev/null +++ b/xmloff/source/chart/XMLLabelSeparatorContext.cxx @@ -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 . + */ + +#include "XMLLabelSeparatorContext.hxx" + +#include "SchXMLParagraphContext.hxx" +#include +#include + + +using namespace ::com::sun::star; + +XMLLabelSeparatorContext::XMLLabelSeparatorContext( + SvXMLImport& rImport, sal_uInt16 nPrfx, + const OUString& rLocalName, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) : + XMLElementPropertyContext( + rImport, nPrfx, rLocalName, rProp, rProps ), + m_aSeparator() +{ +} + +XMLLabelSeparatorContext::~XMLLabelSeparatorContext() +{} + +void XMLLabelSeparatorContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ +} + +SvXMLImportContextRef XMLLabelSeparatorContext::CreateChildContext( + sal_uInt16 /*nPrefix*/, const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & /*xAttrList*/ ) +{ + SvXMLImportContext* pContext = nullptr; + if( xmloff::token::IsXMLToken( rLocalName, xmloff::token::XML_P ) ) + { + pContext = new SchXMLParagraphContext( GetImport(), + rLocalName, m_aSeparator ); + } + + return pContext; +} + +void XMLLabelSeparatorContext::EndElement() +{ + if( !m_aSeparator.isEmpty() ) + { + // aProp is a member of XMLElementPropertyContext + aProp.maValue <<= m_aSeparator; + SetInsert( true ); + } + + XMLElementPropertyContext::EndElement(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLLabelSeparatorContext.hxx b/xmloff/source/chart/XMLLabelSeparatorContext.hxx new file mode 100644 index 000000000..e2153ea65 --- /dev/null +++ b/xmloff/source/chart/XMLLabelSeparatorContext.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_XMLLABELSEPARATORCONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_XMLLABELSEPARATORCONTEXT_HXX + +#include + +class XMLLabelSeparatorContext : public XMLElementPropertyContext +{ +public: + + XMLLabelSeparatorContext( SvXMLImport& rImport, sal_uInt16 nPrfx, + const OUString& rLName, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ); + virtual ~XMLLabelSeparatorContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + +private: + OUString m_aSeparator; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_XMLLABELSEPARATORCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLSymbolImageContext.cxx b/xmloff/source/chart/XMLSymbolImageContext.cxx new file mode 100644 index 000000000..be661375c --- /dev/null +++ b/xmloff/source/chart/XMLSymbolImageContext.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 "XMLSymbolImageContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace css; + +namespace { + +enum SvXMLTokenMapAttrs +{ + XML_TOK_SYMBOL_IMAGE_HREF, + XML_TOK_SYMBOL_IMAGE_TYPE, + XML_TOK_SYMBOL_IMAGE_ACTUATE, + XML_TOK_SYMBOL_IMAGE_SHOW, +}; + +} + +static const SvXMLTokenMapEntry aSymbolImageAttrTokenMap[] = +{ + { XML_NAMESPACE_XLINK, ::xmloff::token::XML_HREF, XML_TOK_SYMBOL_IMAGE_HREF }, + { XML_NAMESPACE_XLINK, ::xmloff::token::XML_TYPE, XML_TOK_SYMBOL_IMAGE_TYPE }, + { XML_NAMESPACE_XLINK, ::xmloff::token::XML_ACTUATE, XML_TOK_SYMBOL_IMAGE_ACTUATE }, + { XML_NAMESPACE_XLINK, ::xmloff::token::XML_SHOW, XML_TOK_SYMBOL_IMAGE_SHOW }, + XML_TOKEN_MAP_END +}; + +XMLSymbolImageContext::XMLSymbolImageContext( + SvXMLImport& rImport, sal_uInt16 nPrfx, + const OUString& rLName, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) : + XMLElementPropertyContext( + rImport, nPrfx, rLName, rProp, rProps ) +{ +} + +XMLSymbolImageContext::~XMLSymbolImageContext() +{} + +void XMLSymbolImageContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + static const SvXMLTokenMap aTokenMap( aSymbolImageAttrTokenMap ); + OUString aLocalName; + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i = 0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + sal_uInt16 nPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + const OUString& rValue = xAttrList->getValueByIndex( i ); + + switch( aTokenMap.Get( nPrefix, aLocalName ) ) + { + case XML_TOK_SYMBOL_IMAGE_HREF: + msURL = rValue; + break; + case XML_TOK_SYMBOL_IMAGE_ACTUATE: + case XML_TOK_SYMBOL_IMAGE_TYPE: + case XML_TOK_SYMBOL_IMAGE_SHOW: + // these values are currently not interpreted + // it is always assumed 'actuate=onLoad', 'type=simple', 'show=embed' + break; + } + } +} + +SvXMLImportContextRef XMLSymbolImageContext::CreateChildContext( + sal_uInt16 nPrefix, const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + if( xmloff::token::IsXMLToken( rLocalName, + xmloff::token::XML_BINARY_DATA ) ) + { + if( msURL.isEmpty() && ! mxBase64Stream.is() ) + { + mxBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( mxBase64Stream.is() ) + pContext = new XMLBase64ImportContext( GetImport(), nPrefix, + rLocalName, xAttrList, + mxBase64Stream ); + } + } + + return pContext; +} + +void XMLSymbolImageContext::EndElement() +{ + uno::Reference xGraphic; + + if (!msURL.isEmpty()) + { + xGraphic = GetImport().loadGraphicByURL(msURL); + } + else if (mxBase64Stream.is()) + { + xGraphic = GetImport().loadGraphicFromBase64(mxBase64Stream); + mxBase64Stream = nullptr; + } + + if (xGraphic.is()) + { + // aProp is a member of XMLElementPropertyContext + aProp.maValue <<= xGraphic; + SetInsert( true ); + } + + XMLElementPropertyContext::EndElement(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLSymbolImageContext.hxx b/xmloff/source/chart/XMLSymbolImageContext.hxx new file mode 100644 index 000000000..14f87879e --- /dev/null +++ b/xmloff/source/chart/XMLSymbolImageContext.hxx @@ -0,0 +1,52 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_XMLSYMBOLIMAGECONTEXT_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_XMLSYMBOLIMAGECONTEXT_HXX + +#include + +namespace com::sun::star { + namespace io { class XOutputStream; } +} + +class XMLSymbolImageContext : public XMLElementPropertyContext +{ +public: + + XMLSymbolImageContext( SvXMLImport& rImport, sal_uInt16 nPrfx, + const OUString& rLName, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ); + virtual ~XMLSymbolImageContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + +private: + OUString msURL; + css::uno::Reference < css::io::XOutputStream > mxBase64Stream; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_XMLSYMBOLIMAGECONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx b/xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx new file mode 100644 index 000000000..1eb374a41 --- /dev/null +++ b/xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx @@ -0,0 +1,166 @@ +/* -*- 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 "XMLSymbolTypePropertyHdl.hxx" +#include +#include + +using namespace ::xmloff::token; + +namespace +{ +struct SvXMLSignedEnumMapEntry +{ + ::xmloff::token::XMLTokenEnum eToken; + sal_Int32 nValue; +}; + +const SvXMLSignedEnumMapEntry aXMLChartSymbolTypeEnumMap[] = +{ + { XML_NONE, -3 }, + { XML_AUTOMATIC, -2 }, + { XML_IMAGE, -1 }, + { XML_TOKEN_INVALID, 0 } +}; + +const SvXMLSignedEnumMapEntry aXMLChartSymbolNameMap[] = +{ + { XML_GRADIENTSTYLE_SQUARE, 0 }, // "square" + { XML_DIAMOND, 1 }, + { XML_ARROW_DOWN, 2 }, + { XML_ARROW_UP, 3 }, + { XML_ARROW_RIGHT, 4 }, + { XML_ARROW_LEFT, 5 }, + { XML_BOW_TIE, 6 }, + { XML_HOURGLASS, 7 }, + { XML_CIRCLE, 8 }, + { XML_STAR, 9 }, + { XML_X, 10 }, + { XML_PLUS, 11 }, + { XML_ASTERISK, 12 }, + { XML_HORIZONTAL_BAR, 13 }, + { XML_VERTICAL_BAR, 14 }, + { XML_TOKEN_INVALID, 0 } +}; + +bool lcl_convertEnum( + OUStringBuffer & rBuffer, + sal_Int32 nValue, + const SvXMLSignedEnumMapEntry *pMap ) +{ + enum XMLTokenEnum eTok = XML_TOKEN_INVALID; + + while( pMap->eToken != XML_TOKEN_INVALID ) + { + if( pMap->nValue == nValue ) + { + eTok = pMap->eToken; + break; + } + pMap++; + } + + if( eTok != XML_TOKEN_INVALID ) + rBuffer.append( GetXMLToken(eTok) ); + + return (eTok != XML_TOKEN_INVALID); +} + +bool lcl_convertEnum( + sal_Int32 & rEnum, + const OUString & rValue, + const SvXMLSignedEnumMapEntry *pMap ) +{ + while( pMap->eToken != XML_TOKEN_INVALID ) + { + if( IsXMLToken( rValue, pMap->eToken ) ) + { + rEnum = pMap->nValue; + return true; + } + pMap++; + } + return false; +} + +} // anonymous namespace + +using namespace com::sun::star; + +XMLSymbolTypePropertyHdl::XMLSymbolTypePropertyHdl( bool bIsNamedSymbol ) + : m_bIsNamedSymbol( bIsNamedSymbol ) +{} + +XMLSymbolTypePropertyHdl::~XMLSymbolTypePropertyHdl() +{} + +bool XMLSymbolTypePropertyHdl::importXML( const OUString& rStrImpValue, + uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bResult = false; + + if( m_bIsNamedSymbol ) + { + sal_Int32 nValue = -3; // NONE + bResult = lcl_convertEnum( nValue, rStrImpValue, aXMLChartSymbolNameMap ); + rValue <<= nValue; + } + else + { + sal_Int32 nValue = -3; // NONE + bResult = lcl_convertEnum( nValue, rStrImpValue, aXMLChartSymbolTypeEnumMap ); + rValue <<= nValue; + } + + return bResult; +} + +bool XMLSymbolTypePropertyHdl::exportXML( OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bResult = false; + + sal_Int32 nType = -3; // NONE + rValue >>= nType; + + if( m_bIsNamedSymbol ) + { + OUStringBuffer aBuf; + bResult = lcl_convertEnum( aBuf, nType, aXMLChartSymbolNameMap ); + rStrExpValue = aBuf.makeStringAndClear(); + } + else + { + if( nType < 0 ) + { + OUStringBuffer aBuf; + bResult = lcl_convertEnum( aBuf, nType, aXMLChartSymbolTypeEnumMap ); + rStrExpValue = aBuf.makeStringAndClear(); + } + else + { + bResult = true; + rStrExpValue = GetXMLToken( XML_NAMED_SYMBOL ); + } + } + + return bResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLSymbolTypePropertyHdl.hxx b/xmloff/source/chart/XMLSymbolTypePropertyHdl.hxx new file mode 100644 index 000000000..475463a59 --- /dev/null +++ b/xmloff/source/chart/XMLSymbolTypePropertyHdl.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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_XMLSYMBOLTYPEPROPERTYHDL_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_XMLSYMBOLTYPEPROPERTYHDL_HXX + +#include + +class XMLSymbolTypePropertyHdl : public XMLPropertyHandler +{ +public: + explicit XMLSymbolTypePropertyHdl( bool bIsNamedSymbol ); + virtual ~XMLSymbolTypePropertyHdl() 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; + +private: + bool m_bIsNamedSymbol; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_XMLSYMBOLTYPEPROPERTYHDL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLTextOrientationHdl.cxx b/xmloff/source/chart/XMLTextOrientationHdl.cxx new file mode 100644 index 000000000..7f23e58c1 --- /dev/null +++ b/xmloff/source/chart/XMLTextOrientationHdl.cxx @@ -0,0 +1,72 @@ +/* -*- 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 "XMLTextOrientationHdl.hxx" +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +XMLTextOrientationHdl::~XMLTextOrientationHdl() +{ +} + +bool XMLTextOrientationHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bRetval( false ); + + if( IsXMLToken( rStrImpValue, XML_LTR )) + { + rValue <<= false; + bRetval = true; + } + else if( IsXMLToken( rStrImpValue, XML_TTB )) + { + rValue <<= true; + bRetval = true; + } + + return bRetval; +} + +bool XMLTextOrientationHdl::exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bVal (false ); + bool bRetval( false ); + + if( rValue >>= bVal ) + { + if( bVal ) + rStrExpValue = GetXMLToken( XML_TTB ); + else + rStrExpValue = GetXMLToken( XML_LTR ); + bRetval = true; + } + + return bRetval; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLTextOrientationHdl.hxx b/xmloff/source/chart/XMLTextOrientationHdl.hxx new file mode 100644 index 000000000..2a2cd95f9 --- /dev/null +++ b/xmloff/source/chart/XMLTextOrientationHdl.hxx @@ -0,0 +1,40 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_XMLTEXTORIENTATIONHDL_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_XMLTEXTORIENTATIONHDL_HXX + +#include + +class XMLTextOrientationHdl : public XMLPropertyHandler +{ +private: +public: + virtual ~XMLTextOrientationHdl() 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; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_XMLTEXTORIENTATIONHDL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/contexts.cxx b/xmloff/source/chart/contexts.cxx new file mode 100644 index 000000000..218a91e19 --- /dev/null +++ b/xmloff/source/chart/contexts.cxx @@ -0,0 +1,197 @@ +/* -*- 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 +#include +#include +#include +#include +#include "SchXMLCalculationSettingsContext.hxx" + +#include "contexts.hxx" + +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +namespace { + +class SchXMLBodyContext_Impl : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + +public: + + SchXMLBodyContext_Impl( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport ); + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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; +}; + +} + +SchXMLBodyContext_Impl::SchXMLBodyContext_Impl( + SchXMLImportHelper& rImpHelper, SvXMLImport& rImport ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SchXMLBodyContext_Impl::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + return new SchXMLBodyContext( mrImportHelper, GetImport(), nElement ); +} + +SchXMLDocContext::SchXMLDocContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_Int32 nElement ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ) +{ + SAL_WARN_IF(( nElement != XML_ELEMENT( OFFICE, XML_DOCUMENT ) && + nElement != XML_ELEMENT( OFFICE, XML_DOCUMENT_META ) && + nElement != XML_ELEMENT( OFFICE, XML_DOCUMENT_STYLES ) && + nElement != XML_ELEMENT( OFFICE, XML_DOCUMENT_CONTENT ) ), "xmloff.chart", "SchXMLDocContext instantiated with no element" ); +} + +SchXMLDocContext::~SchXMLDocContext() +{} + + +SvXMLImportContextRef SchXMLDocContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContextRef xContext; + const SvXMLTokenMap& rTokenMap = mrImportHelper.GetDocElemTokenMap(); + + switch( rTokenMap.Get( nPrefix, rLocalName )) + { + case XML_TOK_DOC_META: + // we come here in the flat ODF file format, + // if XDocumentPropertiesSupplier is not supported at the model + break; + } + + return xContext; +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SchXMLDocContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportFlags nFlags = GetImport().getImportFlags(); + switch (nElement) + { + case XML_ELEMENT(OFFICE, XML_BODY): + if( nFlags & SvXMLImportFlags::CONTENT ) + return new SchXMLBodyContext_Impl( mrImportHelper, GetImport() ); + break; + case XML_ELEMENT(OFFICE, XML_STYLES): + // for draw styles containing gradients/hatches/markers and dashes + if( nFlags & SvXMLImportFlags::STYLES ) + return new SvXMLStylesContext( GetImport() ); + break; + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES): + if( nFlags & SvXMLImportFlags::AUTOSTYLES ) + // not nice, but this is safe, as the SchXMLDocContext class can only by + // instantiated by the chart import class SchXMLImport (header is not exported) + return + static_cast< SchXMLImport& >( GetImport() ).CreateStylesContext(); + break; + } + return nullptr; +} + +SchXMLFlatDocContext_Impl::SchXMLFlatDocContext_Impl( + SchXMLImportHelper& i_rImpHelper, + SchXMLImport& i_rImport, + sal_Int32 i_nElement, + const uno::Reference& i_xDocProps) : + SvXMLImportContext(i_rImport), + SchXMLDocContext(i_rImpHelper, i_rImport, i_nElement), + SvXMLMetaDocumentContext(i_rImport, i_xDocProps) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SchXMLFlatDocContext_Impl::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + // behave like meta base class iff we encounter office:meta + if ( nElement == XML_ELEMENT( OFFICE, XML_META ) ) { + return SvXMLMetaDocumentContext::createFastChildContext( + nElement, xAttrList ); + } else { + return SchXMLDocContext::createFastChildContext( + nElement, xAttrList ); + } +} + +SchXMLBodyContext::SchXMLBodyContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_Int32 nElement ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ) +{ + SAL_WARN_IF( nElement != XML_ELEMENT(OFFICE, XML_CHART), "xmloff.chart", "SchXMLBodyContext instantiated with no element" ); +} + +SchXMLBodyContext::~SchXMLBodyContext() +{} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLBodyContext::createFastChildContext( + sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + return nullptr; +} + +SvXMLImportContextRef SchXMLBodyContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + // element + if( nPrefix == XML_NAMESPACE_CHART && + IsXMLToken( rLocalName, XML_CHART ) ) + { + xContext = mrImportHelper.CreateChartContext( GetImport(), + nPrefix, rLocalName, + GetImport().GetModel(), + xAttrList ); + } + else if(nPrefix == XML_NAMESPACE_TABLE && + IsXMLToken( rLocalName, XML_CALCULATION_SETTINGS )) + { + // i99104 handle null date correctly + xContext = new SchXMLCalculationSettingsContext ( GetImport(), nPrefix, rLocalName, xAttrList); + } + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/contexts.hxx b/xmloff/source/chart/contexts.hxx new file mode 100644 index 000000000..7cfcf2d5f --- /dev/null +++ b/xmloff/source/chart/contexts.hxx @@ -0,0 +1,107 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_CONTEXTS_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_CONTEXTS_HXX + +#include +#include + +#include + +namespace com::sun::star::xml::sax { + class XAttributeList; +} + +/* + These contexts are only needed by + SchXMLImport not by the SchXMLImportHelper + that is also used by other applications +*/ + +class SchXMLDocContext : public virtual SvXMLImportContext +{ +protected: + SchXMLImportHelper& mrImportHelper; + +public: + SchXMLDocContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_Int32 nElement ); + + virtual ~SchXMLDocContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) 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; +}; + +// context for flat file xml format +class SchXMLFlatDocContext_Impl + : public SchXMLDocContext, public SvXMLMetaDocumentContext +{ +public: + SchXMLFlatDocContext_Impl( + SchXMLImportHelper& i_rImpHelper, + SchXMLImport& i_rImport, + sal_Int32 i_nElement, + const css::uno::Reference& i_xDocProps); + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override + { SvXMLMetaDocumentContext::startFastElement(nElement, 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; +}; + +class SchXMLBodyContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + +public: + SchXMLBodyContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_Int32 nElement ); + virtual ~SchXMLBodyContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_CONTEXTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/transporttypes.cxx b/xmloff/source/chart/transporttypes.cxx new file mode 100644 index 000000000..c648413be --- /dev/null +++ b/xmloff/source/chart/transporttypes.cxx @@ -0,0 +1,30 @@ +/* -*- 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 "transporttypes.hxx" + +bool operator < ( const tSchXMLIndexWithPart & rFirst, const tSchXMLIndexWithPart & rSecond ) +{ + if( rFirst.first == rSecond.first ) + return (static_cast< int >( rFirst.second ) < static_cast< int >( rSecond.second )); + return (rFirst.first < rSecond.first); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/transporttypes.hxx b/xmloff/source/chart/transporttypes.hxx new file mode 100644 index 000000000..673729f43 --- /dev/null +++ b/xmloff/source/chart/transporttypes.hxx @@ -0,0 +1,202 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_XMLOFF_SOURCE_CHART_TRANSPORTTYPES_HXX +#define INCLUDED_XMLOFF_SOURCE_CHART_TRANSPORTTYPES_HXX + +#include +#include + +#include +#include + +enum SchXMLCellType +{ + SCH_CELL_TYPE_UNKNOWN, + SCH_CELL_TYPE_FLOAT, + SCH_CELL_TYPE_STRING, + SCH_CELL_TYPE_COMPLEX_STRING +}; + +struct SchXMLCell +{ + OUString aString; + css::uno::Sequence< OUString > aComplexString; + double fValue; + SchXMLCellType eType; + OUString aRangeId; + + SchXMLCell(): fValue( 0.0 ), eType( SCH_CELL_TYPE_UNKNOWN ) + {} +}; + +struct SchXMLTable +{ + std::vector< std::vector< SchXMLCell > > aData; /// an array of rows containing the table contents + + sal_Int32 nRowIndex; /// reflects the index of the row currently parsed + sal_Int32 nColumnIndex; /// reflects the index of the column currently parsed + sal_Int32 nMaxColumnIndex; /// the greatest number of columns detected + + sal_Int32 nNumberOfColsEstimate; /// parsing column-elements may yield an estimate + + bool bHasHeaderRow; + bool bHasHeaderColumn; + + OUString aTableNameOfFile; /// the table name read at the table:table element + + ::std::vector< sal_Int32 > aHiddenColumns; + + bool bProtected; + + SchXMLTable() : nRowIndex( -1 ), + nColumnIndex( -1 ), + nMaxColumnIndex( -1 ), + nNumberOfColsEstimate( 0 ), + bHasHeaderRow( false ), + bHasHeaderColumn( false ), + bProtected( false ) + {} +}; + +typedef sal_Int32 tSchXMLIndex; +#define SCH_XML_CATEGORIES_INDEX (static_cast(-1)) +enum SchXMLLabeledSequencePart +{ + SCH_XML_PART_LABEL, + SCH_XML_PART_VALUES, + SCH_XML_PART_ERROR_BARS +}; +typedef ::std::pair< tSchXMLIndex, SchXMLLabeledSequencePart > tSchXMLIndexWithPart; +typedef ::std::multimap< tSchXMLIndexWithPart, + css::uno::Reference< css::chart2::data::XLabeledDataSequence > > + tSchXMLLSequencesPerIndex; + +bool operator < ( const tSchXMLIndexWithPart & rFirst, const tSchXMLIndexWithPart & rSecond ); + +enum SchXMLAxisDimension +{ + SCH_XML_AXIS_X = 0, + SCH_XML_AXIS_Y, + SCH_XML_AXIS_Z, + SCH_XML_AXIS_UNDEF +}; + +struct SchXMLAxis +{ + enum SchXMLAxisDimension eDimension; + sal_Int8 nAxisIndex;//0->primary axis; 1->secondary axis + OUString aName; + OUString aTitle; + bool bHasCategories; + + SchXMLAxis() : eDimension( SCH_XML_AXIS_UNDEF ), nAxisIndex( 0 ), bHasCategories( false ) {} +}; + +struct GlobalSeriesImportInfo +{ + explicit GlobalSeriesImportInfo( bool& rAllRangeAddressesAvailable ) + : rbAllRangeAddressesAvailable( rAllRangeAddressesAvailable ) + , nCurrentDataIndex( 0 ) + , nFirstFirstDomainIndex( -1 ) + , nFirstSecondDomainIndex( -1 ) + {} + + bool& rbAllRangeAddressesAvailable; + + sal_Int32 nCurrentDataIndex; + + OUString aFirstFirstDomainAddress; + sal_Int32 nFirstFirstDomainIndex; + + OUString aFirstSecondDomainAddress; + sal_Int32 nFirstSecondDomainIndex; +}; + +struct RegressionStyle +{ + css::uno::Reference< + css::chart2::XDataSeries > m_xSeries; + css::uno::Reference< + css::beans::XPropertySet > m_xEquationProperties; + + OUString msStyleName; + + RegressionStyle(const css::uno::Reference< + css::chart2::XDataSeries >& xSeries, + const OUString& sStyleName) : + m_xSeries ( xSeries ), + msStyleName ( sStyleName ) + {} +}; + +struct CustomLabelField { + std::vector sRuns; +}; + +struct DataRowPointStyle +{ + enum StyleType + { + DATA_POINT, + DATA_SERIES, + MEAN_VALUE, + ERROR_INDICATOR + }; + + StyleType meType; + css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + + css::uno::Reference< css::beans::XPropertySet > m_xOldAPISeries; + + css::uno::Reference< css::beans::XPropertySet > m_xErrorXProperties; + + css::uno::Reference< css::beans::XPropertySet > m_xErrorYProperties; + + sal_Int32 m_nPointIndex; + sal_Int32 m_nPointRepeat; + OUString msStyleName; + ::std::vector mCustomLabels; + double mCustomLabelPos[2] = { 0.0, 0.0 }; + OUString msSeriesStyleNameForDonuts; + + sal_Int32 mnAttachedAxis; + bool mbSymbolSizeForSeriesIsMissingInFile; + + DataRowPointStyle( StyleType eType + , const css::uno::Reference< css::chart2::XDataSeries >& xSeries + , sal_Int32 nPointIndex + , sal_Int32 nPointRepeat + , const OUString& sStyleName + , sal_Int32 nAttachedAxis = 0 ) : + meType( eType ), + m_xSeries( xSeries ), + m_nPointIndex( nPointIndex ), + m_nPointRepeat( nPointRepeat ), + msStyleName( sStyleName ), + mnAttachedAxis( nAttachedAxis ), + mbSymbolSizeForSeriesIsMissingInFile( false ) + {} +}; + +typedef ::std::multimap< OUString, css::uno::Reference< + css::chart2::data::XDataSequence > > tSchXMLRangeSequenceMap; + +#endif // INCLUDED_XMLOFF_SOURCE_CHART_TRANSPORTTYPES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3