This is an automated email from the ASF dual-hosted git repository. jimjag pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit dadd651f52f1b9ef2dfee0bdde61aa44a31cd418 Author: Jim Jagielski <[email protected]> AuthorDate: Tue Nov 3 06:13:26 2026 -0500 Write the ODF 1.4 draw:handle attributes, form:input-required and chart plot-area as ODF 1.4 requires --- main/xmloff/inc/EnhancedCustomShapeToken.hxx | 6 ++ main/xmloff/inc/xmloff/xmltoken.hxx | 8 +++ main/xmloff/source/chart/SchXMLExport.cxx | 3 +- main/xmloff/source/core/xmltoken.cxx | 8 +++ .../source/draw/EnhancedCustomShapeToken.cxx | 6 ++ main/xmloff/source/draw/shapeexport4.cxx | 27 ++++++++ main/xmloff/source/draw/ximpcustomshape.cxx | 76 ++++++++++++++++++++++ main/xmloff/source/forms/elementexport.cxx | 7 +- main/xmloff/source/forms/elementimport.cxx | 6 ++ 9 files changed, 144 insertions(+), 3 deletions(-) diff --git a/main/xmloff/inc/EnhancedCustomShapeToken.hxx b/main/xmloff/inc/EnhancedCustomShapeToken.hxx index 18cc2f83c3..706b37d2a4 100644 --- a/main/xmloff/inc/EnhancedCustomShapeToken.hxx +++ b/main/xmloff/inc/EnhancedCustomShapeToken.hxx @@ -88,6 +88,12 @@ namespace xmloff { namespace EnhancedCustomShapeToken { EAS_handle_polar, EAS_handle_radius_range_minimum, EAS_handle_radius_range_maximum, + EAS_handle_position_x, + EAS_handle_position_y, + EAS_handle_polar_pole_x, + EAS_handle_polar_pole_y, + EAS_handle_polar_radius, + EAS_handle_polar_angle, EAS_CustomShapeEngine, EAS_CustomShapeData, diff --git a/main/xmloff/inc/xmloff/xmltoken.hxx b/main/xmloff/inc/xmloff/xmltoken.hxx index c5f8e0ec73..46f3a003a6 100644 --- a/main/xmloff/inc/xmloff/xmltoken.hxx +++ b/main/xmloff/inc/xmloff/xmltoken.hxx @@ -3152,6 +3152,14 @@ namespace xmloff { namespace token { // ODF 1.3 XML_CREATOR_INITIALS, + // ODF 1.4 + XML_HANDLE_POSITION_X, + XML_HANDLE_POSITION_Y, + XML_HANDLE_POLAR_POLE_X, + XML_HANDLE_POLAR_POLE_Y, + XML_HANDLE_POLAR_RADIUS, + XML_HANDLE_POLAR_ANGLE, + XML_TOKEN_END }; diff --git a/main/xmloff/source/chart/SchXMLExport.cxx b/main/xmloff/source/chart/SchXMLExport.cxx index 32e0598d58..488db2fa33 100644 --- a/main/xmloff/source/chart/SchXMLExport.cxx +++ b/main/xmloff/source/chart/SchXMLExport.cxx @@ -2000,7 +2000,8 @@ void SchXMLExportHelper_Impl::exportPlotArea( if( msChartAddress.getLength() ) { - if( !bIncludeTable ) + // ODF 1.4 removed table:cell-range-address from chart:plot-area; the importer takes the data from the series ranges + if( !bIncludeTable && mrExport.getDefaultVersion() < SvtSaveOptions::ODFVER_014 ) mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, msChartAddress ); Reference< chart::XChartDocument > xDoc( mrExport.GetModel(), uno::UNO_QUERY ); diff --git a/main/xmloff/source/core/xmltoken.cxx b/main/xmloff/source/core/xmltoken.cxx index eeab76506a..b2f2b93607 100644 --- a/main/xmloff/source/core/xmltoken.cxx +++ b/main/xmloff/source/core/xmltoken.cxx @@ -3152,6 +3152,14 @@ namespace xmloff { namespace token { // ODF 1.3 TOKEN( "creator-initials", XML_CREATOR_INITIALS ), + // ODF 1.4 + TOKEN( "handle-position-x", XML_HANDLE_POSITION_X ), + TOKEN( "handle-position-y", XML_HANDLE_POSITION_Y ), + TOKEN( "handle-polar-pole-x", XML_HANDLE_POLAR_POLE_X ), + TOKEN( "handle-polar-pole-y", XML_HANDLE_POLAR_POLE_Y ), + TOKEN( "handle-polar-radius", XML_HANDLE_POLAR_RADIUS ), + TOKEN( "handle-polar-angle", XML_HANDLE_POLAR_ANGLE ), + #if OSL_DEBUG_LEVEL > 0 { 0, NULL, NULL, XML_TOKEN_END } #else diff --git a/main/xmloff/source/draw/EnhancedCustomShapeToken.cxx b/main/xmloff/source/draw/EnhancedCustomShapeToken.cxx index a7d223a54b..64ceed8043 100644 --- a/main/xmloff/source/draw/EnhancedCustomShapeToken.cxx +++ b/main/xmloff/source/draw/EnhancedCustomShapeToken.cxx @@ -104,6 +104,12 @@ static const TokenTable pTokenTableArray[] = { "handle-polar", EAS_handle_polar }, { "handle-radius-range-minimum", EAS_handle_radius_range_minimum }, { "handle-radius-range-maximum", EAS_handle_radius_range_maximum }, + { "handle-position-x", EAS_handle_position_x }, + { "handle-position-y", EAS_handle_position_y }, + { "handle-polar-pole-x", EAS_handle_polar_pole_x }, + { "handle-polar-pole-y", EAS_handle_polar_pole_y }, + { "handle-polar-radius", EAS_handle_polar_radius }, + { "handle-polar-angle", EAS_handle_polar_angle }, { "CustomShapeEngine", EAS_CustomShapeEngine }, { "CustomShapeData", EAS_CustomShapeData }, diff --git a/main/xmloff/source/draw/shapeexport4.cxx b/main/xmloff/source/draw/shapeexport4.cxx index d91a50230c..6fee08701d 100644 --- a/main/xmloff/source/draw/shapeexport4.cxx +++ b/main/xmloff/source/draw/shapeexport4.cxx @@ -184,10 +184,16 @@ void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::Propert { rtl::OUString aStr; rtl::OUStringBuffer aStrBuffer; + // ODF 1.4 requires draw:handle-position-x/-y or draw:handle-polar-pole-x/-y with draw:handle-polar-radius/-angle; + // the deprecated draw:handle-position and draw:handle-polar stay, older AOO versions drop the handles without them + const sal_Bool bODF14 = rExport.getDefaultVersion() >= SvtSaveOptions::ODFVER_014; for ( i = 0; i < nElements; i++ ) { sal_Bool bPosition = sal_False; + sal_Bool bPolar = sal_False; + com::sun::star::drawing::EnhancedCustomShapeParameterPair aPosition14; + com::sun::star::drawing::EnhancedCustomShapeParameterPair aPolar14; const uno::Sequence< beans::PropertyValue >& rPropSeq = rHandles[ i ]; for ( j = 0; j < (sal_uInt32)rPropSeq.getLength(); j++ ) { @@ -199,6 +205,7 @@ void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::Propert com::sun::star::drawing::EnhancedCustomShapeParameterPair aPosition; if ( rPropVal.Value >>= aPosition ) { + aPosition14 = aPosition; ExportParameter( aStrBuffer, aPosition.First ); ExportParameter( aStrBuffer, aPosition.Second ); aStr = aStrBuffer.makeStringAndClear(); @@ -236,6 +243,8 @@ void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::Propert com::sun::star::drawing::EnhancedCustomShapeParameterPair aPolar; if ( rPropVal.Value >>= aPolar ) { + aPolar14 = aPolar; + bPolar = sal_True; ExportParameter( aStrBuffer, aPolar.First ); ExportParameter( aStrBuffer, aPolar.Second ); aStr = aStrBuffer.makeStringAndClear(); @@ -313,6 +322,24 @@ void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::Propert break; } } + if ( bPosition && bODF14 ) + { + // a polar handle has its pole in the polar pair and its radius and angle in the position pair + const XMLTokenEnum eFirst = bPolar ? XML_HANDLE_POLAR_POLE_X : XML_HANDLE_POSITION_X; + const XMLTokenEnum eSecond = bPolar ? XML_HANDLE_POLAR_POLE_Y : XML_HANDLE_POSITION_Y; + const com::sun::star::drawing::EnhancedCustomShapeParameterPair& rFirst = bPolar ? aPolar14 : aPosition14; + ExportParameter( aStrBuffer, rFirst.First ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, eFirst, aStrBuffer.makeStringAndClear() ); + ExportParameter( aStrBuffer, rFirst.Second ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, eSecond, aStrBuffer.makeStringAndClear() ); + if ( bPolar ) + { + ExportParameter( aStrBuffer, aPosition14.First ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_RADIUS, aStrBuffer.makeStringAndClear() ); + ExportParameter( aStrBuffer, aPosition14.Second ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_ANGLE, aStrBuffer.makeStringAndClear() ); + } + } if ( bPosition ) SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_HANDLE, sal_True, sal_True ); else diff --git a/main/xmloff/source/draw/ximpcustomshape.cxx b/main/xmloff/source/draw/ximpcustomshape.cxx index af08fbb94a..364a2dd8eb 100644 --- a/main/xmloff/source/draw/ximpcustomshape.cxx +++ b/main/xmloff/source/draw/ximpcustomshape.cxx @@ -1379,6 +1379,11 @@ SvXMLImportContext* XMLEnhancedCustomShapeContext::CreateChildContext( sal_uInt1 else if ( aTokenEnum == EAS_handle ) { std::vector< com::sun::star::beans::PropertyValue > aHandle; + // ODF 1.4: draw:handle-position-x/-y, or draw:handle-polar-pole-x/-y with -radius and -angle; + // the old draw:handle-position and draw:handle-polar win when both forms are present + bool bHasPosition = false, bHasPolar = false; + com::sun::star::drawing::EnhancedCustomShapeParameter aPosX, aPosY, aPoleX, aPoleY, aRadius, aAngle; + bool bPosX = false, bPosY = false, bPoleX = false, bPoleY = false, bRadius = false, bAngle = false; const sal_Int16 nLength = xAttrList->getLength(); for( sal_Int16 nAttr = 0; nAttr < nLength; nAttr++ ) { @@ -1398,6 +1403,43 @@ SvXMLImportContext* XMLEnhancedCustomShapeContext::CreateChildContext( sal_uInt1 break; case EAS_handle_position : GetEnhancedParameterPair( aHandle, rValue, EAS_Position ); + bHasPosition = true; + break; + case EAS_handle_position_x : + { + sal_Int32 nIndex = 0; + bPosX = GetNextParameter( aPosX, nIndex, rValue ); + } + break; + case EAS_handle_position_y : + { + sal_Int32 nIndex = 0; + bPosY = GetNextParameter( aPosY, nIndex, rValue ); + } + break; + case EAS_handle_polar_pole_x : + { + sal_Int32 nIndex = 0; + bPoleX = GetNextParameter( aPoleX, nIndex, rValue ); + } + break; + case EAS_handle_polar_pole_y : + { + sal_Int32 nIndex = 0; + bPoleY = GetNextParameter( aPoleY, nIndex, rValue ); + } + break; + case EAS_handle_polar_radius : + { + sal_Int32 nIndex = 0; + bRadius = GetNextParameter( aRadius, nIndex, rValue ); + } + break; + case EAS_handle_polar_angle : + { + sal_Int32 nIndex = 0; + bAngle = GetNextParameter( aAngle, nIndex, rValue ); + } break; case EAS_handle_range_x_minimum : GetEnhancedParameter( aHandle, rValue, EAS_RangeXMinimum ); @@ -1413,6 +1455,7 @@ SvXMLImportContext* XMLEnhancedCustomShapeContext::CreateChildContext( sal_uInt1 break; case EAS_handle_polar : GetEnhancedParameterPair( aHandle, rValue, EAS_Polar ); + bHasPolar = true; break; case EAS_handle_radius_range_minimum : GetEnhancedParameter( aHandle, rValue, EAS_RadiusRangeMinimum ); @@ -1424,6 +1467,39 @@ SvXMLImportContext* XMLEnhancedCustomShapeContext::CreateChildContext( sal_uInt1 break; } } + if ( !bHasPosition && !bHasPolar ) + { + beans::PropertyValue aProp; + com::sun::star::drawing::EnhancedCustomShapeParameterPair aPair; + if ( bPosX && bPosY ) + { + aPair.First = aPosX; + aPair.Second = aPosY; + aProp.Name = EASGet( EAS_Position ); + aProp.Value <<= aPair; + aHandle.push_back( aProp ); + } + else if ( bPoleX && bPoleY ) + { + aPair.First = aPoleX; + aPair.Second = aPoleY; + aProp.Name = EASGet( EAS_Polar ); + aProp.Value <<= aPair; + aHandle.push_back( aProp ); + // the handle position of a polar handle is its radius and angle, both 0 when absent + sal_Int32 nIndex = 0; + if ( !bRadius ) + GetNextParameter( aRadius, nIndex, rtl::OUString::createFromAscii( "0" ) ); + nIndex = 0; + if ( !bAngle ) + GetNextParameter( aAngle, nIndex, rtl::OUString::createFromAscii( "0" ) ); + aPair.First = aRadius; + aPair.Second = aAngle; + aProp.Name = EASGet( EAS_Position ); + aProp.Value <<= aPair; + aHandle.push_back( aProp ); + } + } beans::PropertyValues aPropSeq( aHandle.size() ); std::vector< beans::PropertyValue >::const_iterator aIter = aHandle.begin(); std::vector< beans::PropertyValue >::const_iterator aEnd = aHandle.end(); diff --git a/main/xmloff/source/forms/elementexport.cxx b/main/xmloff/source/forms/elementexport.cxx index 56038c9b8c..e7ff814888 100644 --- a/main/xmloff/source/forms/elementexport.cxx +++ b/main/xmloff/source/forms/elementexport.cxx @@ -918,14 +918,17 @@ namespace xmloff if ( DA_INPUT_REQUIRED & m_nIncludeDatabase ) { // form:input-required is an ODF 1.4 attribute - if ( SvtSaveOptions::IsODFStrict( m_rContext.getGlobalContext().getDefaultVersion() ) ) + const SvtSaveOptions::ODFDefaultVersion eVersion = m_rContext.getGlobalContext().getDefaultVersion(); + if ( SvtSaveOptions::IsODFStrict( eVersion ) && eVersion < SvtSaveOptions::ODFVER_014 ) exportedProperty( PROPERTY_INPUT_REQUIRED ); else exportBooleanPropertyAttribute( OAttributeMetaData::getDatabaseAttributeNamespace( DA_INPUT_REQUIRED ), OAttributeMetaData::getDatabaseAttributeName( DA_INPUT_REQUIRED ), PROPERTY_INPUT_REQUIRED, - BOOLATTR_DEFAULT_TRUE + // the property is true by default and an absent attribute means true to older readers, but ODF 1.4 + // defines the attribute as false by default: write it explicitly in the 1.4 modes + ( eVersion >= SvtSaveOptions::ODFVER_014 ) ? BOOLATTR_DEFAULT_VOID : BOOLATTR_DEFAULT_TRUE ); RESET_BIT( nIncludeDatabase, DA_INPUT_REQUIRED ); } diff --git a/main/xmloff/source/forms/elementimport.cxx b/main/xmloff/source/forms/elementimport.cxx index 76cd8e4e71..9310c4eb3f 100644 --- a/main/xmloff/source/forms/elementimport.cxx +++ b/main/xmloff/source/forms/elementimport.cxx @@ -54,6 +54,7 @@ #include <tools/diagnose_ex.h> #include <tools/time.hxx> #include <rtl/logfile.hxx> +#include <comphelper/documentconstants.hxx> #include <comphelper/extract.hxx> #include <comphelper/types.hxx> @@ -852,6 +853,11 @@ namespace xmloff // let the base class handle all the attributes OElementImport::StartElement(xAttributes); + // ODF 1.4 defines form:input-required as false by default, the property is true by default + if ( m_xElement.is() && m_xInfo.is() && m_xInfo->hasPropertyByName( PROPERTY_INPUT_REQUIRED ) + && GetImport().GetODFVersion().compareTo( ODFVER_014_TEXT ) >= 0 ) + simulateDefaultedAttribute( OAttributeMetaData::getDatabaseAttributeName( DA_INPUT_REQUIRED ), PROPERTY_INPUT_REQUIRED, "false" ); + if ( !m_aValueProperties.empty() && m_xElement.is()) { // get the property set info
