3e6ad944ac
Change-Id: I49477c20849dd99118d5935c0f1576429648bfca Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177734 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
5247 lines
223 KiB
C++
5247 lines
223 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <config_wasm_strip.h>
|
|
|
|
#include <basegfx/matrix/b2dhommatrix.hxx>
|
|
#include <basegfx/matrix/b3dhommatrix.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <basegfx/polygon/b3dpolypolygon.hxx>
|
|
#include <basegfx/polygon/b3dpolypolygontools.hxx>
|
|
#include <basegfx/tuple/b2dtuple.hxx>
|
|
#include <basegfx/vector/b3dvector.hxx>
|
|
|
|
#include <com/sun/star/beans/XPropertyState.hpp>
|
|
#include <com/sun/star/beans/PropertyValues.hpp>
|
|
#include <com/sun/star/container/XChild.hpp>
|
|
#include <com/sun/star/container/XEnumerationAccess.hpp>
|
|
#include <com/sun/star/container/XIdentifierAccess.hpp>
|
|
#include <com/sun/star/container/XNamed.hpp>
|
|
#include <com/sun/star/document/XEventsSupplier.hpp>
|
|
#include <com/sun/star/drawing/CameraGeometry.hpp>
|
|
#include <com/sun/star/drawing/CircleKind.hpp>
|
|
#include <com/sun/star/drawing/ConnectorType.hpp>
|
|
#include <com/sun/star/drawing/Direction3D.hpp>
|
|
#include <com/sun/star/drawing/EscapeDirection.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
|
|
#include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
|
|
#include <com/sun/star/drawing/GluePoint2.hpp>
|
|
#include <com/sun/star/drawing/HomogenMatrix.hpp>
|
|
#include <com/sun/star/drawing/HomogenMatrix3.hpp>
|
|
#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
|
|
#include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
|
|
#include <com/sun/star/drawing/Position3D.hpp>
|
|
#include <com/sun/star/drawing/ProjectionMode.hpp>
|
|
#include <com/sun/star/drawing/ShadeMode.hpp>
|
|
#include <com/sun/star/drawing/XControlShape.hpp>
|
|
#include <com/sun/star/drawing/XCustomShapeEngine.hpp>
|
|
#include <com/sun/star/drawing/XGluePointsSupplier.hpp>
|
|
#include <com/sun/star/drawing/BarCode.hpp>
|
|
#include <com/sun/star/drawing/BarCodeErrorCorrection.hpp>
|
|
#include <com/sun/star/drawing/XShapes3.hpp>
|
|
#include <com/sun/star/embed/ElementModes.hpp>
|
|
#include <com/sun/star/embed/XStorage.hpp>
|
|
#include <com/sun/star/embed/XTransactedObject.hpp>
|
|
#include <com/sun/star/graphic/XGraphic.hpp>
|
|
#include <com/sun/star/graphic/GraphicProvider.hpp>
|
|
#include <com/sun/star/graphic/XGraphicProvider.hpp>
|
|
#include <com/sun/star/io/XSeekableInputStream.hpp>
|
|
#include <com/sun/star/io/XStream.hpp>
|
|
#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
|
|
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
|
#include <com/sun/star/media/ZoomLevel.hpp>
|
|
#include <com/sun/star/presentation/AnimationSpeed.hpp>
|
|
#include <com/sun/star/presentation/ClickAction.hpp>
|
|
#include <com/sun/star/style/XStyle.hpp>
|
|
#include <com/sun/star/table/XColumnRowRange.hpp>
|
|
#include <com/sun/star/text/WritingMode2.hpp>
|
|
#include <com/sun/star/text/XText.hpp>
|
|
|
|
#include <comphelper/classids.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <comphelper/propertyvalue.hxx>
|
|
#include <comphelper/sequenceashashmap.hxx>
|
|
#include <comphelper/storagehelper.hxx>
|
|
#include <officecfg/Office/Common.hxx>
|
|
|
|
#include <o3tl/any.hxx>
|
|
#include <o3tl/typed_flags_set.hxx>
|
|
#include <o3tl/string_view.hxx>
|
|
|
|
#include <rtl/math.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
#include <rtl/ustring.hxx>
|
|
#include <sal/log.hxx>
|
|
|
|
#include <sax/tools/converter.hxx>
|
|
|
|
#include <tools/debug.hxx>
|
|
#include <tools/globname.hxx>
|
|
#include <tools/helpers.hxx>
|
|
#include <comphelper/diagnose_ex.hxx>
|
|
#include <vcl/graph.hxx>
|
|
|
|
#include <xmloff/contextid.hxx>
|
|
#include <xmloff/families.hxx>
|
|
#include <xmloff/namespacemap.hxx>
|
|
#include <xmloff/shapeexport.hxx>
|
|
#include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
|
|
#include <xmloff/xmlexp.hxx>
|
|
#include <xmloff/xmlnamespace.hxx>
|
|
#include <xmloff/xmltoken.hxx>
|
|
#include <xmloff/xmluconv.hxx>
|
|
#include <xmloff/table/XMLTableExport.hxx>
|
|
#include <xmloff/ProgressBarHelper.hxx>
|
|
|
|
#include <anim.hxx>
|
|
#include <EnhancedCustomShapeToken.hxx>
|
|
#include "sdpropls.hxx"
|
|
#include <xexptran.hxx>
|
|
#include "ximpshap.hxx"
|
|
#include <XMLBase64Export.hxx>
|
|
#include <XMLImageMapExport.hxx>
|
|
#include <memory>
|
|
#include <algorithm>
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace ::xmloff::EnhancedCustomShapeToken;
|
|
using namespace ::xmloff::token;
|
|
|
|
constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:";
|
|
|
|
namespace {
|
|
|
|
bool supportsText(XmlShapeType eShapeType)
|
|
{
|
|
return eShapeType != XmlShapeType::PresChartShape &&
|
|
eShapeType != XmlShapeType::PresOLE2Shape &&
|
|
eShapeType != XmlShapeType::DrawSheetShape &&
|
|
eShapeType != XmlShapeType::PresSheetShape &&
|
|
eShapeType != XmlShapeType::Draw3DSceneObject &&
|
|
eShapeType != XmlShapeType::Draw3DCubeObject &&
|
|
eShapeType != XmlShapeType::Draw3DSphereObject &&
|
|
eShapeType != XmlShapeType::Draw3DLatheObject &&
|
|
eShapeType != XmlShapeType::Draw3DExtrudeObject &&
|
|
eShapeType != XmlShapeType::DrawPageShape &&
|
|
eShapeType != XmlShapeType::PresPageShape &&
|
|
eShapeType != XmlShapeType::DrawGroupShape;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
constexpr OUString gsZIndex( u"ZOrder"_ustr );
|
|
constexpr OUStringLiteral gsPrintable( u"Printable" );
|
|
constexpr OUStringLiteral gsVisible( u"Visible" );
|
|
constexpr OUString gsModel( u"Model"_ustr );
|
|
constexpr OUStringLiteral gsStartShape( u"StartShape" );
|
|
constexpr OUStringLiteral gsEndShape( u"EndShape" );
|
|
constexpr OUString gsOnClick( u"OnClick"_ustr );
|
|
constexpr OUStringLiteral gsEventType( u"EventType" );
|
|
constexpr OUStringLiteral gsPresentation( u"Presentation" );
|
|
constexpr OUStringLiteral gsMacroName( u"MacroName" );
|
|
constexpr OUString gsScript( u"Script"_ustr );
|
|
constexpr OUStringLiteral gsLibrary( u"Library" );
|
|
constexpr OUStringLiteral gsClickAction( u"ClickAction" );
|
|
constexpr OUString gsBookmark( u"Bookmark"_ustr );
|
|
constexpr OUStringLiteral gsEffect( u"Effect" );
|
|
constexpr OUStringLiteral gsPlayFull( u"PlayFull" );
|
|
constexpr OUStringLiteral gsVerb( u"Verb" );
|
|
constexpr OUStringLiteral gsSoundURL( u"SoundURL" );
|
|
constexpr OUStringLiteral gsSpeed( u"Speed" );
|
|
constexpr OUStringLiteral gsStarBasic( u"StarBasic" );
|
|
constexpr OUStringLiteral gsHyperlink( u"Hyperlink" );
|
|
|
|
XMLShapeExport::XMLShapeExport(SvXMLExport& rExp,
|
|
SvXMLExportPropertyMapper *pExtMapper )
|
|
: mrExport( rExp ),
|
|
maCurrentShapesIter(maShapesInfos.end()),
|
|
mbExportLayer( false ),
|
|
// #88546# init to sal_False
|
|
mbHandleProgressBar( false )
|
|
{
|
|
// construct PropertySetMapper
|
|
mxPropertySetMapper = CreateShapePropMapper( mrExport );
|
|
if( pExtMapper )
|
|
{
|
|
rtl::Reference < SvXMLExportPropertyMapper > xExtMapper( pExtMapper );
|
|
mxPropertySetMapper->ChainExportMapper( xExtMapper );
|
|
}
|
|
|
|
/*
|
|
// chain text attributes
|
|
xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp));
|
|
*/
|
|
|
|
mrExport.GetAutoStylePool()->AddFamily(
|
|
XmlStyleFamily::SD_GRAPHICS_ID,
|
|
XML_STYLE_FAMILY_SD_GRAPHICS_NAME,
|
|
GetPropertySetMapper(),
|
|
XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX);
|
|
mrExport.GetAutoStylePool()->AddFamily(
|
|
XmlStyleFamily::SD_PRESENTATION_ID,
|
|
XML_STYLE_FAMILY_SD_PRESENTATION_NAME,
|
|
GetPropertySetMapper(),
|
|
XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX);
|
|
|
|
// create table export helper and let him add his families in time
|
|
GetShapeTableExport();
|
|
}
|
|
|
|
XMLShapeExport::~XMLShapeExport()
|
|
{
|
|
}
|
|
|
|
// sj: replacing CustomShapes with standard objects that are also supported in OpenOffice.org format
|
|
uno::Reference< drawing::XShape > XMLShapeExport::checkForCustomShapeReplacement( const uno::Reference< drawing::XShape >& xShape )
|
|
{
|
|
uno::Reference< drawing::XShape > xCustomShapeReplacement;
|
|
|
|
if( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) )
|
|
{
|
|
OUString aType( xShape->getShapeType() );
|
|
if( aType == "com.sun.star.drawing.CustomShape" )
|
|
{
|
|
uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
|
|
if( xSet.is() )
|
|
{
|
|
OUString aEngine;
|
|
xSet->getPropertyValue(u"CustomShapeEngine"_ustr) >>= aEngine;
|
|
if ( aEngine.isEmpty() )
|
|
{
|
|
aEngine = "com.sun.star.drawing.EnhancedCustomShapeEngine";
|
|
}
|
|
const uno::Reference< uno::XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
|
|
|
|
if ( !aEngine.isEmpty() )
|
|
{
|
|
uno::Sequence< beans::PropertyValue > aPropValues{
|
|
comphelper::makePropertyValue(u"CustomShape"_ustr, xShape),
|
|
comphelper::makePropertyValue(u"ForceGroupWithText"_ustr, true)
|
|
};
|
|
uno::Sequence< uno::Any > aArgument = { uno::Any(aPropValues) };
|
|
uno::Reference< uno::XInterface > xInterface(
|
|
xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine, aArgument, xContext) );
|
|
if ( xInterface.is() )
|
|
{
|
|
uno::Reference< drawing::XCustomShapeEngine > xCustomShapeEngine(
|
|
uno::Reference< drawing::XCustomShapeEngine >( xInterface, uno::UNO_QUERY ) );
|
|
if ( xCustomShapeEngine.is() )
|
|
xCustomShapeReplacement = xCustomShapeEngine->render();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return xCustomShapeReplacement;
|
|
}
|
|
|
|
// This method collects all automatic styles for the given XShape
|
|
void XMLShapeExport::collectShapeAutoStyles(const uno::Reference< drawing::XShape >& xShape )
|
|
{
|
|
if( maCurrentShapesIter == maShapesInfos.end() )
|
|
{
|
|
OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no call to seekShapes()!" );
|
|
return;
|
|
}
|
|
sal_Int32 nZIndex = 0;
|
|
uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if( xPropSet.is() )
|
|
xPropSet->getPropertyValue(gsZIndex) >>= nZIndex;
|
|
|
|
ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
|
|
|
|
if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
|
|
{
|
|
OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no shape info allocated for a given shape" );
|
|
return;
|
|
}
|
|
|
|
ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
|
|
|
|
uno::Reference< drawing::XShape > xCustomShapeReplacement = checkForCustomShapeReplacement( xShape );
|
|
if ( xCustomShapeReplacement.is() )
|
|
aShapeInfo.xCustomShapeReplacement = std::move(xCustomShapeReplacement);
|
|
|
|
// first compute the shapes type
|
|
ImpCalcShapeType(xShape, aShapeInfo.meShapeType);
|
|
|
|
// #i118485# enabled XmlShapeType::DrawChartShape and XmlShapeType::DrawOLE2Shape
|
|
// to have text
|
|
const bool bObjSupportsText =
|
|
supportsText(aShapeInfo.meShapeType);
|
|
|
|
const bool bObjSupportsStyle =
|
|
aShapeInfo.meShapeType != XmlShapeType::DrawGroupShape;
|
|
|
|
bool bIsEmptyPresObj = false;
|
|
|
|
if ( aShapeInfo.xCustomShapeReplacement.is() )
|
|
xPropSet.clear();
|
|
|
|
// prep text styles
|
|
if( xPropSet.is() && bObjSupportsText )
|
|
{
|
|
uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY);
|
|
if (xText.is())
|
|
{
|
|
try
|
|
{
|
|
// tdf#153161: it seems that the call to XTextRange::getString flushes the changes
|
|
// for some objects, that otherwise fail to get exported correctly. Maybe at some
|
|
// point it would make sense to find a better place for more targeted flush.
|
|
xText->getString();
|
|
}
|
|
catch (uno::RuntimeException const&)
|
|
{
|
|
// E.g., SwXTextFrame that contains only a table will throw; this is not an error
|
|
}
|
|
|
|
uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
|
|
|
|
if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(u"IsEmptyPresentationObject"_ustr) )
|
|
{
|
|
uno::Any aAny = xPropSet->getPropertyValue(u"IsEmptyPresentationObject"_ustr);
|
|
aAny >>= bIsEmptyPresObj;
|
|
}
|
|
|
|
if(!bIsEmptyPresObj)
|
|
{
|
|
GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText );
|
|
}
|
|
}
|
|
}
|
|
|
|
// compute the shape parent style
|
|
if( xPropSet.is() )
|
|
{
|
|
uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( xPropSet->getPropertySetInfo() );
|
|
|
|
OUString aParentName;
|
|
uno::Reference< style::XStyle > xStyle;
|
|
|
|
if( bObjSupportsStyle )
|
|
{
|
|
if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName(u"Style"_ustr) )
|
|
xPropSet->getPropertyValue(u"Style"_ustr) >>= xStyle;
|
|
|
|
if(xStyle.is())
|
|
{
|
|
// get family ID
|
|
uno::Reference< beans::XPropertySet > xStylePropSet(xStyle, uno::UNO_QUERY);
|
|
SAL_WARN_IF( !xStylePropSet.is(), "xmloff", "style without a XPropertySet?" );
|
|
try
|
|
{
|
|
if(xStylePropSet.is())
|
|
{
|
|
OUString aFamilyName;
|
|
xStylePropSet->getPropertyValue(u"Family"_ustr) >>= aFamilyName;
|
|
if( !aFamilyName.isEmpty() && aFamilyName != "graphics" )
|
|
aShapeInfo.mnFamily = XmlStyleFamily::SD_PRESENTATION_ID;
|
|
}
|
|
}
|
|
catch(const beans::UnknownPropertyException&)
|
|
{
|
|
// Ignored.
|
|
SAL_WARN( "xmloff",
|
|
"XMLShapeExport::collectShapeAutoStyles: style has no 'Family' property");
|
|
}
|
|
|
|
// get parent-style name
|
|
if(XmlStyleFamily::SD_PRESENTATION_ID == aShapeInfo.mnFamily)
|
|
{
|
|
aParentName = msPresentationStylePrefix;
|
|
}
|
|
|
|
aParentName += xStyle->getName();
|
|
}
|
|
}
|
|
|
|
if (aParentName.isEmpty() && xPropertySetInfo->hasPropertyByName(u"TextBox"_ustr) && xPropSet->getPropertyValue(u"TextBox"_ustr).hasValue() && xPropSet->getPropertyValue(u"TextBox"_ustr).get<bool>())
|
|
{
|
|
// Shapes with a Writer TextBox always have a parent style.
|
|
// If there would be none, then assign the default one.
|
|
aParentName = "Frame";
|
|
}
|
|
|
|
// filter propset
|
|
std::vector< XMLPropertyState > aPropStates;
|
|
|
|
sal_Int32 nCount = 0;
|
|
if( !bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape) )
|
|
{
|
|
aPropStates = GetPropertySetMapper()->Filter(mrExport, xPropSet);
|
|
|
|
if (XmlShapeType::DrawControlShape == aShapeInfo.meShapeType)
|
|
{
|
|
// for control shapes, we additionally need the number format style (if any)
|
|
uno::Reference< drawing::XControlShape > xControl(xShape, uno::UNO_QUERY);
|
|
DBG_ASSERT(xControl.is(), "XMLShapeExport::collectShapeAutoStyles: ShapeType control, but no XControlShape!");
|
|
if (xControl.is())
|
|
{
|
|
uno::Reference< beans::XPropertySet > xControlModel(xControl->getControl(), uno::UNO_QUERY);
|
|
DBG_ASSERT(xControlModel.is(), "XMLShapeExport::collectShapeAutoStyles: no control model on the control shape!");
|
|
|
|
OUString sNumberStyle = mrExport.GetFormExport()->getControlNumberStyle(xControlModel);
|
|
if (!sNumberStyle.isEmpty())
|
|
{
|
|
sal_Int32 nIndex = GetPropertySetMapper()->getPropertySetMapper()->FindEntryIndex(CTF_SD_CONTROL_SHAPE_DATA_STYLE);
|
|
// TODO : this retrieval of the index could be moved into the ctor, holding the index
|
|
// as member, thus saving time.
|
|
DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for our context id!");
|
|
|
|
XMLPropertyState aNewState(nIndex, uno::Any(sNumberStyle));
|
|
aPropStates.push_back(aNewState);
|
|
}
|
|
}
|
|
}
|
|
|
|
nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
|
|
[](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
|
|
}
|
|
|
|
if(nCount == 0)
|
|
{
|
|
// no hard attributes, use parent style name for export
|
|
aShapeInfo.msStyleName = aParentName;
|
|
}
|
|
else
|
|
{
|
|
// there are filtered properties -> hard attributes
|
|
// try to find this style in AutoStylePool
|
|
aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Find(aShapeInfo.mnFamily, aParentName, aPropStates);
|
|
|
|
if(aShapeInfo.msStyleName.isEmpty())
|
|
{
|
|
// Style did not exist, add it to AutoStalePool
|
|
aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Add(aShapeInfo.mnFamily, aParentName, std::move(aPropStates));
|
|
}
|
|
}
|
|
|
|
// optionally generate auto style for text attributes
|
|
if( (!bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape)) && bObjSupportsText )
|
|
{
|
|
aPropStates = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(mrExport, xPropSet);
|
|
|
|
// yet more additionally, we need to care for the ParaAdjust property
|
|
if ( XmlShapeType::DrawControlShape == aShapeInfo.meShapeType )
|
|
{
|
|
uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
|
|
uno::Reference< beans::XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
|
|
if ( xPropSetInfo.is() && xPropState.is() )
|
|
{
|
|
// this is because:
|
|
// * if controls shapes have a ParaAdjust property, then this is the Align property of the control model
|
|
// * control models are allowed to have an Align of "void"
|
|
// * the Default for control model's Align is TextAlign_LEFT
|
|
// * defaults for style properties are not written, but we need to write the "left",
|
|
// because we need to distinguish this "left" from the case where not align attribute
|
|
// is present which means "void"
|
|
if ( xPropSetInfo->hasPropertyByName( u"ParaAdjust"_ustr )
|
|
&& ( beans::PropertyState_DEFAULT_VALUE == xPropState->getPropertyState( u"ParaAdjust"_ustr ) )
|
|
)
|
|
{
|
|
sal_Int32 nIndex = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->getPropertySetMapper()->FindEntryIndex( CTF_SD_SHAPE_PARA_ADJUST );
|
|
// TODO : this retrieval of the index should be moved into the ctor, holding the index
|
|
// as member, thus saving time.
|
|
DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for the ParaAdjust context id!");
|
|
|
|
XMLPropertyState aAlignDefaultState(nIndex, xPropSet->getPropertyValue(u"ParaAdjust"_ustr));
|
|
|
|
aPropStates.push_back( aAlignDefaultState );
|
|
}
|
|
}
|
|
}
|
|
|
|
nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
|
|
[](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
|
|
|
|
if( nCount )
|
|
{
|
|
aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Find( XmlStyleFamily::TEXT_PARAGRAPH, u""_ustr, aPropStates );
|
|
if(aShapeInfo.msTextStyleName.isEmpty())
|
|
{
|
|
// Style did not exist, add it to AutoStalePool
|
|
aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TEXT_PARAGRAPH, u""_ustr, std::move(aPropStates));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// prepare animation information if needed
|
|
if( mxAnimationsExporter.is() )
|
|
XMLAnimationsExporter::prepare( xShape );
|
|
|
|
// check for special shapes
|
|
|
|
switch( aShapeInfo.meShapeType )
|
|
{
|
|
case XmlShapeType::DrawConnectorShape:
|
|
{
|
|
uno::Reference< uno::XInterface > xConnection;
|
|
|
|
// create shape ids for export later
|
|
xPropSet->getPropertyValue( gsStartShape ) >>= xConnection;
|
|
if( xConnection.is() )
|
|
mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection );
|
|
|
|
xPropSet->getPropertyValue( gsEndShape ) >>= xConnection;
|
|
if( xConnection.is() )
|
|
mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection );
|
|
break;
|
|
}
|
|
case XmlShapeType::PresTableShape:
|
|
case XmlShapeType::DrawTableShape:
|
|
{
|
|
try
|
|
{
|
|
uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
|
|
GetShapeTableExport()->collectTableAutoStyles( xRange );
|
|
}
|
|
catch(const uno::Exception&)
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION( "xmloff", "collecting auto styles for a table" );
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// check for shape collections (group shape or 3d scene)
|
|
// and collect contained shapes style infos
|
|
const uno::Reference< drawing::XShape >& xCollection = aShapeInfo.xCustomShapeReplacement.is()
|
|
? aShapeInfo.xCustomShapeReplacement : xShape;
|
|
{
|
|
uno::Reference< drawing::XShapes > xShapes( xCollection, uno::UNO_QUERY );
|
|
if( xShapes.is() )
|
|
{
|
|
collectShapesAutoStyles( xShapes );
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace
|
|
{
|
|
class NewTextListsHelper
|
|
{
|
|
public:
|
|
explicit NewTextListsHelper( SvXMLExport& rExp )
|
|
: mrExport( rExp )
|
|
{
|
|
mrExport.GetTextParagraphExport()->PushNewTextListsHelper();
|
|
}
|
|
|
|
~NewTextListsHelper()
|
|
{
|
|
mrExport.GetTextParagraphExport()->PopTextListsHelper();
|
|
}
|
|
|
|
private:
|
|
SvXMLExport& mrExport;
|
|
};
|
|
}
|
|
// This method exports the given XShape
|
|
void XMLShapeExport::exportShape(const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */,
|
|
css::awt::Point* pRefPoint /* = NULL */,
|
|
comphelper::AttributeList* pAttrList /* = NULL */ )
|
|
{
|
|
SAL_INFO("xmloff", xShape->getShapeType());
|
|
if( maCurrentShapesIter == maShapesInfos.end() )
|
|
{
|
|
SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no auto styles where collected before export" );
|
|
return;
|
|
}
|
|
sal_Int32 nZIndex = 0;
|
|
uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
|
|
OUString sHyperlink;
|
|
try
|
|
{
|
|
xSet->getPropertyValue(gsHyperlink) >>= sHyperlink;
|
|
}
|
|
catch (beans::UnknownPropertyException)
|
|
{
|
|
}
|
|
|
|
std::unique_ptr< SvXMLElementExport > pHyperlinkElement;
|
|
|
|
// Need to stash the attributes that are pre-loaded for the shape export
|
|
// (otherwise they will become attributes of the draw:a element)
|
|
uno::Reference<xml::sax::XAttributeList> xSaveAttribs(
|
|
new comphelper::AttributeList(GetExport().GetAttrList()));
|
|
GetExport().ClearAttrList();
|
|
if( xSet.is() && (GetExport().GetModelType() == SvtModuleOptions::EFactory::DRAW) )
|
|
{
|
|
// export hyperlinks with <a><shape/></a>. Currently only in draw since draw
|
|
// does not support document events
|
|
try
|
|
{
|
|
presentation::ClickAction eAction = presentation::ClickAction_NONE;
|
|
xSet->getPropertyValue(gsOnClick) >>= eAction;
|
|
|
|
if( (eAction == presentation::ClickAction_DOCUMENT) ||
|
|
(eAction == presentation::ClickAction_BOOKMARK) )
|
|
{
|
|
OUString sURL;
|
|
xSet->getPropertyValue(gsBookmark) >>= sURL;
|
|
|
|
if( !sURL.isEmpty() )
|
|
{
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) );
|
|
}
|
|
}
|
|
}
|
|
catch(const uno::Exception&)
|
|
{
|
|
TOOLS_WARN_EXCEPTION("xmloff", "XMLShapeExport::exportShape(): exception during hyperlink export");
|
|
}
|
|
}
|
|
else if (xSet.is() && !sHyperlink.isEmpty())
|
|
{
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sHyperlink );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) );
|
|
}
|
|
// re-add stashed attributes
|
|
GetExport().AddAttributeList(xSaveAttribs);
|
|
|
|
if( xSet.is() )
|
|
xSet->getPropertyValue(gsZIndex) >>= nZIndex;
|
|
|
|
ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
|
|
|
|
if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
|
|
{
|
|
SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no shape info collected for a given shape" );
|
|
return;
|
|
}
|
|
|
|
NewTextListsHelper aNewTextListsHelper( mrExport );
|
|
|
|
const ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
|
|
|
|
#ifdef DBG_UTIL
|
|
// check if this is the correct ShapesInfo
|
|
uno::Reference< container::XChild > xChild( xShape, uno::UNO_QUERY );
|
|
if( xChild.is() )
|
|
{
|
|
uno::Reference< drawing::XShapes > xParent( xChild->getParent(), uno::UNO_QUERY );
|
|
SAL_WARN_IF( !xParent.is() && xParent.get() == (*maCurrentShapesIter).first.get(), "xmloff", "XMLShapeExport::exportShape(): Wrong call to XMLShapeExport::seekShapes()" );
|
|
}
|
|
|
|
// first compute the shapes type
|
|
{
|
|
XmlShapeType eShapeType(XmlShapeType::NotYetSet);
|
|
ImpCalcShapeType(xShape, eShapeType);
|
|
|
|
SAL_WARN_IF( eShapeType != aShapeInfo.meShapeType, "xmloff", "exportShape callings do not correspond to collectShapeAutoStyles calls!: " << xShape->getShapeType() );
|
|
}
|
|
#endif
|
|
|
|
// collect animation information if needed
|
|
if( mxAnimationsExporter.is() )
|
|
mxAnimationsExporter->collect( xShape, mrExport );
|
|
|
|
/* Export shapes name if he has one (#i51726#)
|
|
Export of the shape name for text documents only if the OpenDocument
|
|
file format is written - exceptions are group shapes.
|
|
Note: Writer documents in OpenOffice.org file format doesn't contain
|
|
any names for shapes, except for group shapes.
|
|
*/
|
|
{
|
|
if ( ( GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITER &&
|
|
GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERWEB &&
|
|
GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERGLOBAL ) ||
|
|
( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) ||
|
|
aShapeInfo.meShapeType == XmlShapeType::DrawGroupShape ||
|
|
( aShapeInfo.meShapeType == XmlShapeType::DrawCustomShape &&
|
|
aShapeInfo.xCustomShapeReplacement.is() ) )
|
|
{
|
|
uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY );
|
|
if( xNamed.is() )
|
|
{
|
|
const OUString aName( xNamed->getName() );
|
|
if( !aName.isEmpty() )
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, aName );
|
|
}
|
|
}
|
|
}
|
|
|
|
// export style name
|
|
if( !aShapeInfo.msStyleName.isEmpty() )
|
|
{
|
|
if(XmlStyleFamily::SD_GRAPHICS_ID == aShapeInfo.mnFamily)
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) );
|
|
else
|
|
mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) );
|
|
}
|
|
|
|
// export text style name
|
|
if( !aShapeInfo.msTextStyleName.isEmpty() )
|
|
{
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TEXT_STYLE_NAME, aShapeInfo.msTextStyleName );
|
|
}
|
|
|
|
// export shapes id if needed
|
|
{
|
|
uno::Reference< uno::XInterface > xRef( xShape, uno::UNO_QUERY );
|
|
const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRef );
|
|
if( !rShapeId.isEmpty() )
|
|
{
|
|
mrExport.AddAttributeIdLegacy(XML_NAMESPACE_DRAW, rShapeId);
|
|
}
|
|
}
|
|
|
|
// export layer information
|
|
if( mbExportLayer )
|
|
{
|
|
// check for group or scene shape and not export layer if this is one
|
|
uno::Reference< drawing::XShapes > xShapes( xShape, uno::UNO_QUERY );
|
|
if( !xShapes.is() )
|
|
{
|
|
try
|
|
{
|
|
uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
|
|
OUString aLayerName;
|
|
xProps->getPropertyValue(u"LayerName"_ustr) >>= aLayerName;
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LAYER, aLayerName );
|
|
|
|
}
|
|
catch(const uno::Exception&)
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting layer name for shape" );
|
|
}
|
|
}
|
|
}
|
|
|
|
// export draw:display (do not export in ODF 1.3 or older)
|
|
if (xSet.is() && (mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
|
|
{
|
|
if( aShapeInfo.meShapeType != XmlShapeType::DrawPageShape && aShapeInfo.meShapeType != XmlShapeType::PresPageShape &&
|
|
aShapeInfo.meShapeType != XmlShapeType::HandoutShape && aShapeInfo.meShapeType != XmlShapeType::DrawChartShape )
|
|
try
|
|
{
|
|
bool bVisible = true;
|
|
bool bPrintable = true;
|
|
|
|
xSet->getPropertyValue(gsVisible) >>= bVisible;
|
|
xSet->getPropertyValue(gsPrintable) >>= bPrintable;
|
|
|
|
XMLTokenEnum eDisplayToken = XML_TOKEN_INVALID;
|
|
const unsigned short nDisplay = (bVisible ? 2 : 0) | (bPrintable ? 1 : 0);
|
|
switch( nDisplay )
|
|
{
|
|
case 0: eDisplayToken = XML_NONE; break;
|
|
case 1: eDisplayToken = XML_PRINTER; break;
|
|
case 2: eDisplayToken = XML_SCREEN; break;
|
|
// case 3: eDisplayToken = XML_ALWAYS break; this is the default
|
|
}
|
|
|
|
if( eDisplayToken != XML_TOKEN_INVALID )
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW_EXT, XML_DISPLAY, eDisplayToken );
|
|
}
|
|
catch(const uno::Exception&)
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("xmloff.draw");
|
|
}
|
|
}
|
|
|
|
// #82003# test export count
|
|
// #91587# ALWAYS increment since now ALL to be exported shapes are counted.
|
|
if(mrExport.GetShapeExport()->IsHandleProgressBarEnabled())
|
|
{
|
|
mrExport.GetProgressBarHelper()->Increment();
|
|
}
|
|
|
|
onExport( xShape );
|
|
|
|
// export shape element
|
|
switch(aShapeInfo.meShapeType)
|
|
{
|
|
case XmlShapeType::DrawRectangleShape:
|
|
{
|
|
ImpExportRectangleShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
case XmlShapeType::DrawEllipseShape:
|
|
{
|
|
ImpExportEllipseShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
case XmlShapeType::DrawLineShape:
|
|
{
|
|
ImpExportLineShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
case XmlShapeType::DrawPolyPolygonShape: // closed PolyPolygon
|
|
case XmlShapeType::DrawPolyLineShape: // open PolyPolygon
|
|
case XmlShapeType::DrawClosedBezierShape: // closed tools::PolyPolygon containing curves
|
|
case XmlShapeType::DrawOpenBezierShape: // open tools::PolyPolygon containing curves
|
|
{
|
|
ImpExportPolygonShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawTextShape:
|
|
case XmlShapeType::PresTitleTextShape:
|
|
case XmlShapeType::PresOutlinerShape:
|
|
case XmlShapeType::PresSubtitleShape:
|
|
case XmlShapeType::PresNotesShape:
|
|
case XmlShapeType::PresHeaderShape:
|
|
case XmlShapeType::PresFooterShape:
|
|
case XmlShapeType::PresSlideNumberShape:
|
|
case XmlShapeType::PresDateTimeShape:
|
|
{
|
|
ImpExportTextBoxShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawGraphicObjectShape:
|
|
case XmlShapeType::PresGraphicObjectShape:
|
|
{
|
|
ImpExportGraphicObjectShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawChartShape:
|
|
case XmlShapeType::PresChartShape:
|
|
{
|
|
ImpExportChartShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint, pAttrList );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawControlShape:
|
|
{
|
|
ImpExportControlShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawConnectorShape:
|
|
{
|
|
ImpExportConnectorShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawMeasureShape:
|
|
{
|
|
ImpExportMeasureShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawOLE2Shape:
|
|
case XmlShapeType::PresOLE2Shape:
|
|
case XmlShapeType::DrawSheetShape:
|
|
case XmlShapeType::PresSheetShape:
|
|
{
|
|
ImpExportOLE2Shape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::PresTableShape:
|
|
case XmlShapeType::DrawTableShape:
|
|
{
|
|
ImpExportTableShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawPageShape:
|
|
case XmlShapeType::PresPageShape:
|
|
case XmlShapeType::HandoutShape:
|
|
{
|
|
ImpExportPageShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawCaptionShape:
|
|
{
|
|
ImpExportCaptionShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::Draw3DCubeObject:
|
|
case XmlShapeType::Draw3DSphereObject:
|
|
case XmlShapeType::Draw3DLatheObject:
|
|
case XmlShapeType::Draw3DExtrudeObject:
|
|
{
|
|
ImpExport3DShape(xShape, aShapeInfo.meShapeType);
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::Draw3DSceneObject:
|
|
{
|
|
ImpExport3DSceneShape( xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawGroupShape:
|
|
{
|
|
// empty group
|
|
ImpExportGroupShape( xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawFrameShape:
|
|
{
|
|
ImpExportFrameShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawAppletShape:
|
|
{
|
|
ImpExportAppletShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawPluginShape:
|
|
{
|
|
ImpExportPluginShape(xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::DrawCustomShape:
|
|
{
|
|
if ( aShapeInfo.xCustomShapeReplacement.is() )
|
|
ImpExportGroupShape( aShapeInfo.xCustomShapeReplacement, nFeatures, pRefPoint );
|
|
else
|
|
ImpExportCustomShape( xShape, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::PresMediaShape:
|
|
case XmlShapeType::DrawMediaShape:
|
|
{
|
|
ImpExportMediaShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
|
|
break;
|
|
}
|
|
|
|
case XmlShapeType::PresOrgChartShape:
|
|
case XmlShapeType::Unknown:
|
|
case XmlShapeType::NotYetSet:
|
|
default:
|
|
{
|
|
// this should never happen and is an error
|
|
OSL_FAIL("XMLEXP: WriteShape: unknown or unexpected type of shape in export!");
|
|
break;
|
|
}
|
|
}
|
|
|
|
pHyperlinkElement.reset();
|
|
|
|
// #97489# #97111#
|
|
// if there was an error and no element for the shape was exported
|
|
// we need to clear the attribute list or the attributes will be
|
|
// set on the next exported element, which can result in corrupt
|
|
// xml files due to duplicate attributes
|
|
|
|
mrExport.CheckAttrList(); // asserts in non pro if we have attributes left
|
|
mrExport.ClearAttrList(); // clears the attributes
|
|
}
|
|
|
|
// This method collects all automatic styles for the shapes inside the given XShapes collection
|
|
void XMLShapeExport::collectShapesAutoStyles( const uno::Reference < drawing::XShapes >& xShapes )
|
|
{
|
|
ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter;
|
|
seekShapes( xShapes );
|
|
|
|
uno::Reference< drawing::XShape > xShape;
|
|
const sal_Int32 nShapeCount(xShapes->getCount());
|
|
for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
|
|
{
|
|
xShapes->getByIndex(nShapeId) >>= xShape;
|
|
SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" );
|
|
if(!xShape.is())
|
|
continue;
|
|
|
|
collectShapeAutoStyles( xShape );
|
|
}
|
|
|
|
maCurrentShapesIter = aOldCurrentShapesIter;
|
|
}
|
|
|
|
// This method exports all XShape inside the given XShapes collection
|
|
void XMLShapeExport::exportShapes( const uno::Reference < drawing::XShapes >& xShapes, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */ )
|
|
{
|
|
ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter;
|
|
seekShapes( xShapes );
|
|
|
|
uno::Reference< drawing::XShape > xShape;
|
|
const sal_Int32 nShapeCount(xShapes->getCount());
|
|
for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
|
|
{
|
|
xShapes->getByIndex(nShapeId) >>= xShape;
|
|
SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" );
|
|
if(!xShape.is())
|
|
continue;
|
|
|
|
exportShape( xShape, nFeatures, pRefPoint );
|
|
}
|
|
|
|
maCurrentShapesIter = aOldCurrentShapesIter;
|
|
}
|
|
|
|
namespace xmloff {
|
|
|
|
void FixZOrder(uno::Reference<drawing::XShapes> const& xShapes,
|
|
std::function<unsigned int (uno::Reference<beans::XPropertySet> const&)> const& rGetLayer)
|
|
{
|
|
uno::Reference<drawing::XShapes3> const xShapes3(xShapes, uno::UNO_QUERY);
|
|
assert(xShapes3.is());
|
|
if (!xShapes3.is())
|
|
{
|
|
return; // only SvxDrawPage implements this
|
|
}
|
|
struct Layer { std::vector<sal_Int32> shapes; sal_Int32 nMin = SAL_MAX_INT32; sal_Int32 nMax = 0; };
|
|
std::vector<Layer> layers;
|
|
// shapes are sorted by ZOrder
|
|
sal_Int32 const nCount(xShapes->getCount());
|
|
for (sal_Int32 i = 0; i < nCount; ++i)
|
|
{
|
|
uno::Reference<beans::XPropertySet> const xShape(xShapes->getByIndex(i), uno::UNO_QUERY);
|
|
if (!xShape.is())
|
|
{
|
|
SAL_WARN("xmloff", "FixZOrder: null shape, cannot sort");
|
|
return;
|
|
}
|
|
unsigned int const nLayer(rGetLayer(xShape));
|
|
if (layers.size() <= nLayer)
|
|
{
|
|
layers.resize(nLayer + 1);
|
|
}
|
|
layers[nLayer].shapes.emplace_back(i);
|
|
if (i < layers[nLayer].nMin)
|
|
{
|
|
layers[nLayer].nMin = i;
|
|
}
|
|
if (layers[nLayer].nMax < i)
|
|
{
|
|
layers[nLayer].nMax = i;
|
|
}
|
|
}
|
|
std::erase_if(layers, [](Layer const& rLayer) { return rLayer.shapes.empty(); });
|
|
bool isSorted(true);
|
|
for (size_t i = 1; i < layers.size(); ++i)
|
|
{
|
|
assert(layers[i].nMin != layers[i-1].nMax); // unique!
|
|
if (layers[i].nMin < layers[i-1].nMax)
|
|
{
|
|
isSorted = false;
|
|
break;
|
|
}
|
|
}
|
|
if (isSorted)
|
|
{
|
|
return; // nothing to do
|
|
}
|
|
uno::Sequence<sal_Int32> aNewOrder(nCount);
|
|
auto iterInsert(aNewOrder.getArray());
|
|
for (auto const& rLayer : layers)
|
|
{
|
|
assert(rLayer.nMin <= rLayer.nMax); // empty layers have been removed
|
|
iterInsert = std::copy(rLayer.shapes.begin(), rLayer.shapes.end(), iterInsert);
|
|
}
|
|
try
|
|
{
|
|
xShapes3->sort(aNewOrder);
|
|
}
|
|
catch (uno::Exception const&)
|
|
{
|
|
SAL_WARN("xmloff", "FixZOrder: exception");
|
|
}
|
|
}
|
|
|
|
} // namespace xmloff
|
|
|
|
void XMLShapeExport::seekShapes( const uno::Reference< drawing::XShapes >& xShapes ) noexcept
|
|
{
|
|
if( xShapes.is() )
|
|
{
|
|
maCurrentShapesIter = maShapesInfos.find( xShapes );
|
|
if( maCurrentShapesIter == maShapesInfos.end() )
|
|
{
|
|
auto itPair = maShapesInfos.emplace( xShapes, ImplXMLShapeExportInfoVector( static_cast<ShapesInfos::size_type>(xShapes->getCount()) ) );
|
|
|
|
maCurrentShapesIter = itPair.first;
|
|
|
|
SAL_WARN_IF( maCurrentShapesIter == maShapesInfos.end(), "xmloff", "XMLShapeExport::seekShapes(): insert into stl::map failed" );
|
|
}
|
|
|
|
SAL_WARN_IF( (*maCurrentShapesIter).second.size() != static_cast<ShapesInfos::size_type>(xShapes->getCount()), "xmloff", "XMLShapeExport::seekShapes(): XShapes size varied between calls" );
|
|
|
|
}
|
|
else
|
|
{
|
|
maCurrentShapesIter = maShapesInfos.end();
|
|
}
|
|
}
|
|
|
|
void XMLShapeExport::exportAutoStyles()
|
|
{
|
|
// export all autostyle infos
|
|
|
|
// ...for graphic
|
|
{
|
|
GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_GRAPHICS_ID );
|
|
}
|
|
|
|
// ...for presentation
|
|
{
|
|
GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_PRESENTATION_ID );
|
|
}
|
|
|
|
if( mxShapeTableExport.is() )
|
|
mxShapeTableExport->exportAutoStyles();
|
|
}
|
|
|
|
/// returns the export property mapper for external chaining
|
|
SvXMLExportPropertyMapper* XMLShapeExport::CreateShapePropMapper(
|
|
SvXMLExport& rExport )
|
|
{
|
|
rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rExport.GetModel(), rExport );
|
|
rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, true );
|
|
rExport.GetTextParagraphExport(); // get or create text paragraph export
|
|
SvXMLExportPropertyMapper* pResult =
|
|
new XMLShapeExportPropertyMapper( xMapper, rExport );
|
|
// chain text attributes
|
|
return pResult;
|
|
}
|
|
|
|
void XMLShapeExport::ImpCalcShapeType(const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType& eShapeType)
|
|
{
|
|
// set in every case, so init here
|
|
eShapeType = XmlShapeType::Unknown;
|
|
|
|
if(!xShape.is())
|
|
return;
|
|
|
|
OUString aType(xShape->getShapeType());
|
|
|
|
if(!aType.match("com.sun.star."))
|
|
return;
|
|
|
|
if(aType.match("drawing.", 13))
|
|
{
|
|
// drawing shapes
|
|
if (aType.match("Rectangle", 21)) { eShapeType = XmlShapeType::DrawRectangleShape; }
|
|
|
|
// #i72177# Note: Correcting CustomShape, CustomShape->Custom, len from 9 (was wrong anyways) to 6.
|
|
// As can be seen at the other compares, the appendix "Shape" is left out of the comparison.
|
|
else if(aType.match("Custom", 21)) { eShapeType = XmlShapeType::DrawCustomShape; }
|
|
|
|
else if(aType.match("Ellipse", 21)) { eShapeType = XmlShapeType::DrawEllipseShape; }
|
|
else if(aType.match("Control", 21)) { eShapeType = XmlShapeType::DrawControlShape; }
|
|
else if(aType.match("Connector", 21)) { eShapeType = XmlShapeType::DrawConnectorShape; }
|
|
else if(aType.match("Measure", 21)) { eShapeType = XmlShapeType::DrawMeasureShape; }
|
|
else if(aType.match("Line", 21)) { eShapeType = XmlShapeType::DrawLineShape; }
|
|
|
|
// #i72177# Note: This covers two types by purpose, PolyPolygonShape and PolyPolygonPathShape
|
|
else if(aType.match("PolyPolygon", 21)) { eShapeType = XmlShapeType::DrawPolyPolygonShape; }
|
|
|
|
// #i72177# Note: This covers two types by purpose, PolyLineShape and PolyLinePathShape
|
|
else if(aType.match("PolyLine", 21)) { eShapeType = XmlShapeType::DrawPolyLineShape; }
|
|
|
|
else if(aType.match("OpenBezier", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
|
|
else if(aType.match("ClosedBezier", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
|
|
|
|
// #i72177# FreeHand (opened and closed) now supports the types OpenFreeHandShape and
|
|
// ClosedFreeHandShape respectively. Represent them as bezier shapes
|
|
else if(aType.match("OpenFreeHand", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
|
|
else if(aType.match("ClosedFreeHand", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
|
|
|
|
else if(aType.match("GraphicObject", 21)) { eShapeType = XmlShapeType::DrawGraphicObjectShape; }
|
|
else if(aType.match("Group", 21)) { eShapeType = XmlShapeType::DrawGroupShape; }
|
|
else if(aType.match("Text", 21)) { eShapeType = XmlShapeType::DrawTextShape; }
|
|
else if(aType.match("OLE2", 21))
|
|
{
|
|
eShapeType = XmlShapeType::DrawOLE2Shape;
|
|
|
|
// get info about presentation shape
|
|
uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
|
|
|
|
if(xPropSet.is())
|
|
{
|
|
OUString sCLSID;
|
|
if(xPropSet->getPropertyValue(u"CLSID"_ustr) >>= sCLSID)
|
|
{
|
|
#if !ENABLE_WASM_STRIP_CHART
|
|
// WASM_CHART change
|
|
// TODO: With Chart extracted this cannot really happen since
|
|
// no Chart could've been added at all
|
|
if (sCLSID == mrExport.GetChartExport()->getChartCLSID() ||
|
|
#else
|
|
if(
|
|
#endif
|
|
sCLSID == SvGlobalName( SO3_RPTCH_CLASSID ).GetHexName() )
|
|
{
|
|
eShapeType = XmlShapeType::DrawChartShape;
|
|
}
|
|
else if (sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
|
|
{
|
|
eShapeType = XmlShapeType::DrawSheetShape;
|
|
}
|
|
else
|
|
{
|
|
// general OLE2 Object
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(aType.match("Page", 21)) { eShapeType = XmlShapeType::DrawPageShape; }
|
|
else if(aType.match("Frame", 21)) { eShapeType = XmlShapeType::DrawFrameShape; }
|
|
else if(aType.match("Caption", 21)) { eShapeType = XmlShapeType::DrawCaptionShape; }
|
|
else if(aType.match("Plugin", 21)) { eShapeType = XmlShapeType::DrawPluginShape; }
|
|
else if(aType.match("Applet", 21)) { eShapeType = XmlShapeType::DrawAppletShape; }
|
|
else if(aType.match("MediaShape", 21)) { eShapeType = XmlShapeType::DrawMediaShape; }
|
|
else if(aType.match("TableShape", 21)) { eShapeType = XmlShapeType::DrawTableShape; }
|
|
|
|
// 3D shapes
|
|
else if(aType.match("Scene", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSceneObject; }
|
|
else if(aType.match("Cube", 21 + 7)) { eShapeType = XmlShapeType::Draw3DCubeObject; }
|
|
else if(aType.match("Sphere", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSphereObject; }
|
|
else if(aType.match("Lathe", 21 + 7)) { eShapeType = XmlShapeType::Draw3DLatheObject; }
|
|
else if(aType.match("Extrude", 21 + 7)) { eShapeType = XmlShapeType::Draw3DExtrudeObject; }
|
|
}
|
|
else if(aType.match("presentation.", 13))
|
|
{
|
|
// presentation shapes
|
|
if (aType.match("TitleText", 26)) { eShapeType = XmlShapeType::PresTitleTextShape; }
|
|
else if(aType.match("Outliner", 26)) { eShapeType = XmlShapeType::PresOutlinerShape; }
|
|
else if(aType.match("Subtitle", 26)) { eShapeType = XmlShapeType::PresSubtitleShape; }
|
|
else if(aType.match("GraphicObject", 26)) { eShapeType = XmlShapeType::PresGraphicObjectShape; }
|
|
else if(aType.match("Page", 26)) { eShapeType = XmlShapeType::PresPageShape; }
|
|
else if(aType.match("OLE2", 26))
|
|
{
|
|
eShapeType = XmlShapeType::PresOLE2Shape;
|
|
|
|
// get info about presentation shape
|
|
uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
|
|
|
|
if(xPropSet.is()) try
|
|
{
|
|
OUString sCLSID;
|
|
if(xPropSet->getPropertyValue(u"CLSID"_ustr) >>= sCLSID)
|
|
{
|
|
if( sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
|
|
{
|
|
eShapeType = XmlShapeType::PresSheetShape;
|
|
}
|
|
}
|
|
}
|
|
catch(const uno::Exception&)
|
|
{
|
|
SAL_WARN( "xmloff", "XMLShapeExport::ImpCalcShapeType(), expected ole shape to have the CLSID property?" );
|
|
}
|
|
}
|
|
else if(aType.match("Chart", 26)) { eShapeType = XmlShapeType::PresChartShape; }
|
|
else if(aType.match("OrgChart", 26)) { eShapeType = XmlShapeType::PresOrgChartShape; }
|
|
else if(aType.match("CalcShape", 26)) { eShapeType = XmlShapeType::PresSheetShape; }
|
|
else if(aType.match("TableShape", 26)) { eShapeType = XmlShapeType::PresTableShape; }
|
|
else if(aType.match("Notes", 26)) { eShapeType = XmlShapeType::PresNotesShape; }
|
|
else if(aType.match("HandoutShape", 26)) { eShapeType = XmlShapeType::HandoutShape; }
|
|
else if(aType.match("HeaderShape", 26)) { eShapeType = XmlShapeType::PresHeaderShape; }
|
|
else if(aType.match("FooterShape", 26)) { eShapeType = XmlShapeType::PresFooterShape; }
|
|
else if(aType.match("SlideNumberShape", 26)) { eShapeType = XmlShapeType::PresSlideNumberShape; }
|
|
else if(aType.match("DateTimeShape", 26)) { eShapeType = XmlShapeType::PresDateTimeShape; }
|
|
else if(aType.match("MediaShape", 26)) { eShapeType = XmlShapeType::PresMediaShape; }
|
|
}
|
|
}
|
|
|
|
/** exports all user defined gluepoints */
|
|
void XMLShapeExport::ImpExportGluePoints( const uno::Reference< drawing::XShape >& xShape )
|
|
{
|
|
uno::Reference< drawing::XGluePointsSupplier > xSupplier( xShape, uno::UNO_QUERY );
|
|
if( !xSupplier.is() )
|
|
return;
|
|
|
|
uno::Reference< container::XIdentifierAccess > xGluePoints( xSupplier->getGluePoints(), uno::UNO_QUERY );
|
|
if( !xGluePoints.is() )
|
|
return;
|
|
|
|
drawing::GluePoint2 aGluePoint;
|
|
|
|
const uno::Sequence< sal_Int32 > aIdSequence( xGluePoints->getIdentifiers() );
|
|
|
|
for( const sal_Int32 nIdentifier : aIdSequence )
|
|
{
|
|
if( (xGluePoints->getByIdentifier( nIdentifier ) >>= aGluePoint) && aGluePoint.IsUserDefined )
|
|
{
|
|
// export only user defined gluepoints
|
|
|
|
const OUString sId( OUString::number( nIdentifier ) );
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ID, sId );
|
|
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
|
|
aGluePoint.Position.X);
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, msBuffer.makeStringAndClear());
|
|
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
|
|
aGluePoint.Position.Y);
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, msBuffer.makeStringAndClear());
|
|
|
|
if( !aGluePoint.IsRelative )
|
|
{
|
|
SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.PositionAlignment, aXML_GlueAlignment_EnumMap );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ALIGN, msBuffer.makeStringAndClear() );
|
|
}
|
|
|
|
if( aGluePoint.Escape != drawing::EscapeDirection_SMART )
|
|
{
|
|
SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.Escape, aXML_GlueEscapeDirection_EnumMap );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ESCAPE_DIRECTION, msBuffer.makeStringAndClear() );
|
|
}
|
|
|
|
SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_DRAW, XML_GLUE_POINT, true, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportSignatureLine(const uno::Reference<drawing::XShape>& xShape)
|
|
{
|
|
uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
|
|
|
|
bool bIsSignatureLine = false;
|
|
xPropSet->getPropertyValue(u"IsSignatureLine"_ustr) >>= bIsSignatureLine;
|
|
if (!bIsSignatureLine)
|
|
return;
|
|
|
|
OUString aSignatureLineId;
|
|
xPropSet->getPropertyValue(u"SignatureLineId"_ustr) >>= aSignatureLineId;
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, aSignatureLineId);
|
|
|
|
OUString aSuggestedSignerName;
|
|
xPropSet->getPropertyValue(u"SignatureLineSuggestedSignerName"_ustr) >>= aSuggestedSignerName;
|
|
if (!aSuggestedSignerName.isEmpty())
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_NAME, aSuggestedSignerName);
|
|
|
|
OUString aSuggestedSignerTitle;
|
|
xPropSet->getPropertyValue(u"SignatureLineSuggestedSignerTitle"_ustr) >>= aSuggestedSignerTitle;
|
|
if (!aSuggestedSignerTitle.isEmpty())
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_TITLE, aSuggestedSignerTitle);
|
|
|
|
OUString aSuggestedSignerEmail;
|
|
xPropSet->getPropertyValue(u"SignatureLineSuggestedSignerEmail"_ustr) >>= aSuggestedSignerEmail;
|
|
if (!aSuggestedSignerEmail.isEmpty())
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_EMAIL, aSuggestedSignerEmail);
|
|
|
|
OUString aSigningInstructions;
|
|
xPropSet->getPropertyValue(u"SignatureLineSigningInstructions"_ustr) >>= aSigningInstructions;
|
|
if (!aSigningInstructions.isEmpty())
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SIGNING_INSTRUCTIONS, aSigningInstructions);
|
|
|
|
bool bShowSignDate = false;
|
|
xPropSet->getPropertyValue(u"SignatureLineShowSignDate"_ustr) >>= bShowSignDate;
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOW_SIGN_DATE,
|
|
bShowSignDate ? XML_TRUE : XML_FALSE);
|
|
|
|
bool bCanAddComment = false;
|
|
xPropSet->getPropertyValue(u"SignatureLineCanAddComment"_ustr) >>= bCanAddComment;
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CAN_ADD_COMMENT,
|
|
bCanAddComment ? XML_TRUE : XML_FALSE);
|
|
|
|
SvXMLElementExport aSignatureLineElement(mrExport, XML_NAMESPACE_LO_EXT, XML_SIGNATURELINE, true,
|
|
true);
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportQRCode(const uno::Reference<drawing::XShape>& xShape)
|
|
{
|
|
uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
|
|
|
|
uno::Any aAny = xPropSet->getPropertyValue(u"BarCodeProperties"_ustr);
|
|
|
|
css::drawing::BarCode aBarCode;
|
|
if(!(aAny >>= aBarCode))
|
|
return;
|
|
|
|
mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, aBarCode.Payload);
|
|
/* Export QR Code as per customised schema, @see OpenDocument-schema-v1.3+libreoffice */
|
|
OUString temp;
|
|
switch(aBarCode.ErrorCorrection){
|
|
case css::drawing::BarCodeErrorCorrection::LOW :
|
|
temp = "low";
|
|
break;
|
|
case css::drawing::BarCodeErrorCorrection::MEDIUM:
|
|
temp = "medium";
|
|
break;
|
|
case css::drawing::BarCodeErrorCorrection::QUARTILE:
|
|
temp = "quartile";
|
|
break;
|
|
case css::drawing::BarCodeErrorCorrection::HIGH:
|
|
temp = "high";
|
|
break;
|
|
}
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_ERROR_CORRECTION, temp);
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_BORDER, OUStringBuffer(20).append(aBarCode.Border).makeStringAndClear());
|
|
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_TYPE, OUStringBuffer(20).append(aBarCode.Type).makeStringAndClear());
|
|
|
|
SvXMLElementExport aBarCodeElement(mrExport, XML_NAMESPACE_LO_EXT, XML_QRCODE, true,
|
|
true);
|
|
}
|
|
|
|
void XMLShapeExport::ExportGraphicDefaults()
|
|
{
|
|
rtl::Reference<XMLStyleExport> aStEx(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get()));
|
|
|
|
// construct PropertySetMapper
|
|
rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( CreateShapePropMapper( mrExport ) );
|
|
static_cast<XMLShapeExportPropertyMapper*>(xPropertySetMapper.get())->SetAutoStyles( false );
|
|
|
|
// chain text attributes
|
|
xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(mrExport));
|
|
|
|
// chain special Writer/text frame default attributes
|
|
xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaDefaultExtPropMapper(mrExport));
|
|
|
|
// write graphic family default style
|
|
uno::Reference< lang::XMultiServiceFactory > xFact( mrExport.GetModel(), uno::UNO_QUERY );
|
|
if( !xFact.is() )
|
|
return;
|
|
|
|
try
|
|
{
|
|
uno::Reference< beans::XPropertySet > xDefaults( xFact->createInstance(u"com.sun.star.drawing.Defaults"_ustr), uno::UNO_QUERY );
|
|
if( xDefaults.is() )
|
|
{
|
|
aStEx->exportDefaultStyle( xDefaults, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper );
|
|
|
|
// write graphic styles (family name differs depending on the module)
|
|
aStEx->exportStyleFamily(u"graphics"_ustr, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
|
|
aStEx->exportStyleFamily(u"GraphicStyles"_ustr, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
|
|
}
|
|
}
|
|
catch(const lang::ServiceNotRegisteredException&)
|
|
{
|
|
}
|
|
}
|
|
|
|
void XMLShapeExport::onExport( const css::uno::Reference < css::drawing::XShape >& )
|
|
{
|
|
}
|
|
|
|
const rtl::Reference< XMLTableExport >& XMLShapeExport::GetShapeTableExport()
|
|
{
|
|
if( !mxShapeTableExport.is() )
|
|
{
|
|
rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrExport.GetModel(), mrExport ) );
|
|
rtl::Reference < XMLPropertySetMapper > xMapper( new XMLShapePropertySetMapper( xFactory, true ) );
|
|
mrExport.GetTextParagraphExport(); // get or create text paragraph export
|
|
rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( new XMLShapeExportPropertyMapper( xMapper, mrExport ) );
|
|
mxShapeTableExport = new XMLTableExport( mrExport, xPropertySetMapper, xFactory );
|
|
}
|
|
|
|
return mxShapeTableExport;
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet,
|
|
XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
// get matrix
|
|
::basegfx::B2DHomMatrix aMatrix;
|
|
ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
|
|
|
|
// decompose and correct about pRefPoint
|
|
::basegfx::B2DTuple aTRScale;
|
|
double fTRShear(0.0);
|
|
double fTRRotate(0.0);
|
|
::basegfx::B2DTuple aTRTranslate;
|
|
ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
|
|
|
|
// use features and write
|
|
ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix,
|
|
const uno::Reference< beans::XPropertySet >& xPropSet)
|
|
{
|
|
/* Get <TransformationInHoriL2R>, if it exist
|
|
and if the document is exported into the OpenOffice.org file format.
|
|
This property only exists at service css::text::Shape - the
|
|
Writer UNO service for shapes.
|
|
This code is needed, because the positioning attributes in the
|
|
OpenOffice.org file format are given in horizontal left-to-right layout
|
|
regardless the layout direction the shape is in. In the OASIS Open Office
|
|
file format the positioning attributes are correctly given in the layout
|
|
direction the shape is in. Thus, this code provides the conversion from
|
|
the OASIS Open Office file format to the OpenOffice.org file format. (#i28749#)
|
|
*/
|
|
uno::Any aAny;
|
|
if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
|
|
xPropSet->getPropertySetInfo()->hasPropertyByName(u"TransformationInHoriL2R"_ustr) )
|
|
{
|
|
aAny = xPropSet->getPropertyValue(u"TransformationInHoriL2R"_ustr);
|
|
}
|
|
else
|
|
{
|
|
aAny = xPropSet->getPropertyValue(u"Transformation"_ustr);
|
|
}
|
|
drawing::HomogenMatrix3 aMatrix;
|
|
aAny >>= aMatrix;
|
|
|
|
rMatrix.set(0, 0, aMatrix.Line1.Column1);
|
|
rMatrix.set(0, 1, aMatrix.Line1.Column2);
|
|
rMatrix.set(0, 2, aMatrix.Line1.Column3);
|
|
rMatrix.set(1, 0, aMatrix.Line2.Column1);
|
|
rMatrix.set(1, 1, aMatrix.Line2.Column2);
|
|
rMatrix.set(1, 2, aMatrix.Line2.Column3);
|
|
// For this to be a valid 2D transform matrix, the last row must be [0,0,1]
|
|
assert( aMatrix.Line3.Column1 == 0 );
|
|
assert( aMatrix.Line3.Column2 == 0 );
|
|
assert( aMatrix.Line3.Column3 == 1 );
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale,
|
|
double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, css::awt::Point* pRefPoint)
|
|
{
|
|
// decompose matrix
|
|
rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear);
|
|
|
|
// correct translation about pRefPoint
|
|
if(pRefPoint)
|
|
{
|
|
rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y);
|
|
}
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale, double fTRShear,
|
|
double fTRRotate, ::basegfx::B2DTuple const & rTRTranslate, const XMLShapeExportFlags nFeatures)
|
|
{
|
|
// always write Size (rTRScale) since this statement carries the union
|
|
// of the object
|
|
OUString aStr;
|
|
OUStringBuffer sStringBuffer;
|
|
::basegfx::B2DTuple aTRScale(rTRScale);
|
|
|
|
// svg: width
|
|
if(!(nFeatures & XMLShapeExportFlags::WIDTH))
|
|
{
|
|
aTRScale.setX(1.0);
|
|
}
|
|
else
|
|
{
|
|
if( aTRScale.getX() > 0.0 )
|
|
aTRScale.setX(aTRScale.getX() - 1.0);
|
|
else if( aTRScale.getX() < 0.0 )
|
|
aTRScale.setX(aTRScale.getX() + 1.0);
|
|
}
|
|
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
basegfx::fround(aTRScale.getX()));
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr);
|
|
|
|
// svg: height
|
|
if(!(nFeatures & XMLShapeExportFlags::HEIGHT))
|
|
{
|
|
aTRScale.setY(1.0);
|
|
}
|
|
else
|
|
{
|
|
if( aTRScale.getY() > 0.0 )
|
|
aTRScale.setY(aTRScale.getY() - 1.0);
|
|
else if( aTRScale.getY() < 0.0 )
|
|
aTRScale.setY(aTRScale.getY() + 1.0);
|
|
}
|
|
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
basegfx::fround(aTRScale.getY()));
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr);
|
|
|
|
// decide if transformation is necessary
|
|
bool bTransformationIsNecessary(fTRShear != 0.0 || fTRRotate != 0.0);
|
|
|
|
if(bTransformationIsNecessary)
|
|
{
|
|
// write transformation, but WITHOUT scale which is exported as size above
|
|
SdXMLImExTransform2D aTransform;
|
|
|
|
aTransform.AddSkewX(atan(fTRShear));
|
|
|
|
// #i78696#
|
|
// fTRRotate is mathematically correct, but due to the error
|
|
// we export/import it mirrored. Since the API implementation is fixed and
|
|
// uses the correctly oriented angle, it is necessary for compatibility to
|
|
// mirror the angle here to stay at the old behaviour. There is a follow-up
|
|
// task (#i78698#) to fix this in the next ODF FileFormat version
|
|
aTransform.AddRotate(-fTRRotate);
|
|
|
|
aTransform.AddTranslate(rTRTranslate);
|
|
|
|
// does transformation need to be exported?
|
|
if(aTransform.NeedsAction())
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
|
|
}
|
|
else
|
|
{
|
|
// no shear, no rotate; just add object position to export and we are done
|
|
if(nFeatures & XMLShapeExportFlags::X)
|
|
{
|
|
// svg: x
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
basegfx::fround(rTRTranslate.getX()));
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr);
|
|
}
|
|
|
|
if(nFeatures & XMLShapeExportFlags::Y)
|
|
{
|
|
// svg: y
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
basegfx::fround(rTRTranslate.getY()));
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const OUString& rClass )
|
|
{
|
|
bool bIsEmpty = false;
|
|
|
|
// write presentation class entry
|
|
mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass);
|
|
|
|
if( xPropSet.is() )
|
|
{
|
|
uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
|
|
|
|
|
|
// is empty pres. shape?
|
|
if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(u"IsEmptyPresentationObject"_ustr))
|
|
{
|
|
xPropSet->getPropertyValue(u"IsEmptyPresentationObject"_ustr) >>= bIsEmpty;
|
|
if( bIsEmpty )
|
|
mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE);
|
|
}
|
|
|
|
// is user-transformed?
|
|
if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(u"IsPlaceholderDependent"_ustr))
|
|
{
|
|
bool bTemp = false;
|
|
xPropSet->getPropertyValue(u"IsPlaceholderDependent"_ustr) >>= bTemp;
|
|
if(!bTemp)
|
|
mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE);
|
|
}
|
|
}
|
|
|
|
return bIsEmpty;
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape, TextPNS eExtensionNS )
|
|
{
|
|
if (eExtensionNS == TextPNS::EXTENSION)
|
|
{
|
|
if ((mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
|
|
{
|
|
return; // do not export to ODF 1.1/1.2/1.3
|
|
}
|
|
}
|
|
uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
|
|
if( xText.is() )
|
|
{
|
|
uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY );
|
|
if( xEnumAccess.is() && xEnumAccess->hasElements() )
|
|
mrExport.GetTextParagraphExport()->exportText( xText, false, true, eExtensionNS );
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
enum class Found {
|
|
NONE = 0x0000,
|
|
CLICKACTION = 0x0001,
|
|
BOOKMARK = 0x0002,
|
|
EFFECT = 0x0004,
|
|
PLAYFULL = 0x0008,
|
|
VERB = 0x0010,
|
|
SOUNDURL = 0x0020,
|
|
SPEED = 0x0040,
|
|
CLICKEVENTTYPE = 0x0080,
|
|
MACRO = 0x0100,
|
|
LIBRARY = 0x0200,
|
|
};
|
|
|
|
}
|
|
|
|
namespace o3tl {
|
|
template<> struct typed_flags<Found> : is_typed_flags<Found, 0x03ff> {};
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape )
|
|
{
|
|
uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY );
|
|
if( !xEventsSupplier.is() )
|
|
return;
|
|
|
|
uno::Reference< container::XNameAccess > xEvents = xEventsSupplier->getEvents();
|
|
SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" );
|
|
if( !xEvents.is() )
|
|
return;
|
|
|
|
Found nFound = Found::NONE;
|
|
|
|
OUString aClickEventType;
|
|
presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
|
|
presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
|
|
presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW;
|
|
OUString aStrSoundURL;
|
|
bool bPlayFull = false;
|
|
sal_Int32 nVerb = 0;
|
|
OUString aStrMacro;
|
|
OUString aStrLibrary;
|
|
OUString aStrBookmark;
|
|
|
|
uno::Sequence< beans::PropertyValue > aClickProperties;
|
|
if( xEvents->hasByName( gsOnClick ) && (xEvents->getByName( gsOnClick ) >>= aClickProperties) )
|
|
{
|
|
for (const auto& rProperty : aClickProperties)
|
|
{
|
|
if( !( nFound & Found::CLICKEVENTTYPE ) && rProperty.Name == gsEventType )
|
|
{
|
|
if( rProperty.Value >>= aClickEventType )
|
|
nFound |= Found::CLICKEVENTTYPE;
|
|
}
|
|
else if( !( nFound & Found::CLICKACTION ) && rProperty.Name == gsClickAction )
|
|
{
|
|
if( rProperty.Value >>= eClickAction )
|
|
nFound |= Found::CLICKACTION;
|
|
}
|
|
else if( !( nFound & Found::MACRO ) && ( rProperty.Name == gsMacroName || rProperty.Name == gsScript ) )
|
|
{
|
|
if( rProperty.Value >>= aStrMacro )
|
|
nFound |= Found::MACRO;
|
|
}
|
|
else if( !( nFound & Found::LIBRARY ) && rProperty.Name == gsLibrary )
|
|
{
|
|
if( rProperty.Value >>= aStrLibrary )
|
|
nFound |= Found::LIBRARY;
|
|
}
|
|
else if( !( nFound & Found::EFFECT ) && rProperty.Name == gsEffect )
|
|
{
|
|
if( rProperty.Value >>= eEffect )
|
|
nFound |= Found::EFFECT;
|
|
}
|
|
else if( !( nFound & Found::BOOKMARK ) && rProperty.Name == gsBookmark )
|
|
{
|
|
if( rProperty.Value >>= aStrBookmark )
|
|
nFound |= Found::BOOKMARK;
|
|
}
|
|
else if( !( nFound & Found::SPEED ) && rProperty.Name == gsSpeed )
|
|
{
|
|
if( rProperty.Value >>= eSpeed )
|
|
nFound |= Found::SPEED;
|
|
}
|
|
else if( !( nFound & Found::SOUNDURL ) && rProperty.Name == gsSoundURL )
|
|
{
|
|
if( rProperty.Value >>= aStrSoundURL )
|
|
nFound |= Found::SOUNDURL;
|
|
}
|
|
else if( !( nFound & Found::PLAYFULL ) && rProperty.Name == gsPlayFull )
|
|
{
|
|
if( rProperty.Value >>= bPlayFull )
|
|
nFound |= Found::PLAYFULL;
|
|
}
|
|
else if( !( nFound & Found::VERB ) && rProperty.Name == gsVerb )
|
|
{
|
|
if( rProperty.Value >>= nVerb )
|
|
nFound |= Found::VERB;
|
|
}
|
|
}
|
|
}
|
|
|
|
// create the XML elements
|
|
|
|
if( aClickEventType == gsPresentation )
|
|
{
|
|
if( !(nFound & Found::CLICKACTION) || (eClickAction == presentation::ClickAction_NONE) )
|
|
return;
|
|
|
|
SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
|
|
|
|
enum XMLTokenEnum eStrAction;
|
|
|
|
switch( eClickAction )
|
|
{
|
|
case presentation::ClickAction_PREVPAGE: eStrAction = XML_PREVIOUS_PAGE; break;
|
|
case presentation::ClickAction_NEXTPAGE: eStrAction = XML_NEXT_PAGE; break;
|
|
case presentation::ClickAction_FIRSTPAGE: eStrAction = XML_FIRST_PAGE; break;
|
|
case presentation::ClickAction_LASTPAGE: eStrAction = XML_LAST_PAGE; break;
|
|
case presentation::ClickAction_INVISIBLE: eStrAction = XML_HIDE; break;
|
|
case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break;
|
|
case presentation::ClickAction_PROGRAM: eStrAction = XML_EXECUTE; break;
|
|
case presentation::ClickAction_BOOKMARK: eStrAction = XML_SHOW; break;
|
|
case presentation::ClickAction_DOCUMENT: eStrAction = XML_SHOW; break;
|
|
case presentation::ClickAction_MACRO: eStrAction = XML_EXECUTE_MACRO; break;
|
|
case presentation::ClickAction_VERB: eStrAction = XML_VERB; break;
|
|
case presentation::ClickAction_VANISH: eStrAction = XML_FADE_OUT; break;
|
|
case presentation::ClickAction_SOUND: eStrAction = XML_SOUND; break;
|
|
default:
|
|
OSL_FAIL( "unknown presentation::ClickAction found!" );
|
|
eStrAction = XML_UNKNOWN;
|
|
}
|
|
|
|
OUString aEventQName(
|
|
mrExport.GetNamespaceMap().GetQNameByKey(
|
|
XML_NAMESPACE_DOM, u"click"_ustr ) );
|
|
mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
|
|
mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction );
|
|
|
|
if( eClickAction == presentation::ClickAction_VANISH )
|
|
{
|
|
if( nFound & Found::EFFECT )
|
|
{
|
|
XMLEffect eKind;
|
|
XMLEffectDirection eDirection;
|
|
sal_Int16 nStartScale;
|
|
bool bIn;
|
|
|
|
SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn );
|
|
|
|
if( eKind != EK_none )
|
|
{
|
|
SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap );
|
|
mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() );
|
|
}
|
|
|
|
if( eDirection != ED_none )
|
|
{
|
|
SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap );
|
|
mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() );
|
|
}
|
|
|
|
if( nStartScale != -1 )
|
|
{
|
|
::sax::Converter::convertPercent( msBuffer, nStartScale );
|
|
mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() );
|
|
}
|
|
}
|
|
|
|
if( nFound & Found::SPEED && eEffect != presentation::AnimationEffect_NONE )
|
|
{
|
|
if( eSpeed != presentation::AnimationSpeed_MEDIUM )
|
|
{
|
|
SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap );
|
|
mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( eClickAction == presentation::ClickAction_PROGRAM ||
|
|
eClickAction == presentation::ClickAction_BOOKMARK ||
|
|
eClickAction == presentation::ClickAction_DOCUMENT )
|
|
{
|
|
if( eClickAction == presentation::ClickAction_BOOKMARK )
|
|
msBuffer.append( '#' );
|
|
|
|
msBuffer.append( aStrBookmark );
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
|
|
}
|
|
|
|
if( ( nFound & Found::VERB ) && eClickAction == presentation::ClickAction_VERB )
|
|
{
|
|
msBuffer.append( nVerb );
|
|
mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear());
|
|
}
|
|
|
|
SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, true, true);
|
|
|
|
if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND )
|
|
{
|
|
if( ( nFound & Found::SOUNDURL ) && !aStrSoundURL.isEmpty() )
|
|
{
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
|
|
if( nFound & Found::PLAYFULL && bPlayFull )
|
|
mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE );
|
|
|
|
SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true );
|
|
}
|
|
}
|
|
}
|
|
else if( aClickEventType == gsStarBasic )
|
|
{
|
|
if( nFound & Found::MACRO )
|
|
{
|
|
SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
|
|
|
|
mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE,
|
|
mrExport.GetNamespaceMap().GetQNameByKey(
|
|
XML_NAMESPACE_OOO,
|
|
u"starbasic"_ustr ) );
|
|
OUString aEventQName(
|
|
mrExport.GetNamespaceMap().GetQNameByKey(
|
|
XML_NAMESPACE_DOM, u"click"_ustr ) );
|
|
mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
|
|
|
|
if( nFound & Found::LIBRARY )
|
|
{
|
|
const OUString& sLocation( GetXMLToken(
|
|
(aStrLibrary.equalsIgnoreAsciiCase("StarOffice") ||
|
|
aStrLibrary.equalsIgnoreAsciiCase("application") ) ? XML_APPLICATION
|
|
: XML_DOCUMENT ) );
|
|
mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME,
|
|
sLocation + ":" + aStrMacro);
|
|
}
|
|
else
|
|
{
|
|
mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro );
|
|
}
|
|
|
|
SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
|
|
}
|
|
}
|
|
else if( aClickEventType == gsScript )
|
|
{
|
|
if( nFound & Found::MACRO )
|
|
{
|
|
SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
|
|
|
|
mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey(
|
|
XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) );
|
|
OUString aEventQName(
|
|
mrExport.GetNamespaceMap().GetQNameByKey(
|
|
XML_NAMESPACE_DOM, u"click"_ustr ) );
|
|
mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, u"simple"_ustr );
|
|
|
|
SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** #i68101# export shape Title and Description */
|
|
void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape )
|
|
{
|
|
try
|
|
{
|
|
OUString aTitle;
|
|
OUString aDescription;
|
|
|
|
uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
|
|
xProps->getPropertyValue(u"Title"_ustr) >>= aTitle;
|
|
xProps->getPropertyValue(u"Description"_ustr) >>= aDescription;
|
|
|
|
if(!aTitle.isEmpty())
|
|
{
|
|
SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true, false);
|
|
mrExport.Characters( aTitle );
|
|
}
|
|
|
|
if(!aDescription.isEmpty())
|
|
{
|
|
SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, true, false );
|
|
mrExport.Characters( aDescription );
|
|
}
|
|
}
|
|
catch( uno::Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting Title and/or Description for shape" );
|
|
}
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
|
|
if(!(xShapes.is() && xShapes->getCount()))
|
|
return;
|
|
|
|
// write group shape
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
|
|
// #89764# if export of position is suppressed for group shape,
|
|
// positions of contained objects should be written relative to
|
|
// the upper left edge of the group.
|
|
awt::Point aUpperLeft;
|
|
|
|
if(!(nFeatures & XMLShapeExportFlags::POSITION))
|
|
{
|
|
nFeatures |= XMLShapeExportFlags::POSITION;
|
|
aUpperLeft = xShape->getPosition();
|
|
pRefPoint = &aUpperLeft;
|
|
}
|
|
|
|
// write members
|
|
exportShapes( xShapes, nFeatures, pRefPoint );
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportTextBoxShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// presentation attribute (if presentation)
|
|
bool bIsPresShape(false);
|
|
bool bIsEmptyPresObj(false);
|
|
OUString aStr;
|
|
|
|
switch(eShapeType)
|
|
{
|
|
case XmlShapeType::PresSubtitleShape:
|
|
{
|
|
aStr = GetXMLToken(XML_SUBTITLE);
|
|
bIsPresShape = true;
|
|
break;
|
|
}
|
|
case XmlShapeType::PresTitleTextShape:
|
|
{
|
|
aStr = GetXMLToken(XML_TITLE);
|
|
bIsPresShape = true;
|
|
break;
|
|
}
|
|
case XmlShapeType::PresOutlinerShape:
|
|
{
|
|
aStr = GetXMLToken(XML_PRESENTATION_OUTLINE);
|
|
bIsPresShape = true;
|
|
break;
|
|
}
|
|
case XmlShapeType::PresNotesShape:
|
|
{
|
|
aStr = GetXMLToken(XML_NOTES);
|
|
bIsPresShape = true;
|
|
break;
|
|
}
|
|
case XmlShapeType::PresHeaderShape:
|
|
{
|
|
aStr = GetXMLToken(XML_HEADER);
|
|
bIsPresShape = true;
|
|
break;
|
|
}
|
|
case XmlShapeType::PresFooterShape:
|
|
{
|
|
aStr = GetXMLToken(XML_FOOTER);
|
|
bIsPresShape = true;
|
|
break;
|
|
}
|
|
case XmlShapeType::PresSlideNumberShape:
|
|
{
|
|
aStr = GetXMLToken(XML_PAGE_NUMBER);
|
|
bIsPresShape = true;
|
|
break;
|
|
}
|
|
case XmlShapeType::PresDateTimeShape:
|
|
{
|
|
aStr = GetXMLToken(XML_DATE_TIME);
|
|
bIsPresShape = true;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
if(bIsPresShape)
|
|
bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr );
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
|
|
XML_FRAME, bCreateNewline, true );
|
|
|
|
// evtl. corner radius?
|
|
sal_Int32 nCornerRadius(0);
|
|
xPropSet->getPropertyValue(u"CornerRadius"_ustr) >>= nCornerRadius;
|
|
if(nCornerRadius)
|
|
{
|
|
OUStringBuffer sStringBuffer;
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
nCornerRadius);
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
|
|
}
|
|
|
|
{
|
|
// write text-box
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, true, true);
|
|
if(!bIsEmptyPresObj)
|
|
ImpExportText( xShape );
|
|
}
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportRectangleShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
// evtl. corner radius?
|
|
sal_Int32 nCornerRadius(0);
|
|
xPropSet->getPropertyValue(u"CornerRadius"_ustr) >>= nCornerRadius;
|
|
if(nCornerRadius)
|
|
{
|
|
OUStringBuffer sStringBuffer;
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
nCornerRadius);
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
|
|
}
|
|
|
|
// write rectangle
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
ImpExportText( xShape );
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportLineShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
OUString aStr;
|
|
OUStringBuffer sStringBuffer;
|
|
awt::Point aStart(0,0);
|
|
awt::Point aEnd(1,1);
|
|
|
|
// #85920# use 'Geometry' to get the points of the line
|
|
// since this slot take anchor pos into account.
|
|
|
|
// get matrix
|
|
::basegfx::B2DHomMatrix aMatrix;
|
|
ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
|
|
|
|
// decompose and correct about pRefPoint
|
|
::basegfx::B2DTuple aTRScale;
|
|
double fTRShear(0.0);
|
|
double fTRRotate(0.0);
|
|
::basegfx::B2DTuple aTRTranslate;
|
|
ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
|
|
|
|
// create base position
|
|
awt::Point aBasePosition(basegfx::fround(aTRTranslate.getX()),
|
|
basegfx::fround(aTRTranslate.getY()));
|
|
|
|
if (xPropSet->getPropertySetInfo()->hasPropertyByName(u"Geometry"_ustr))
|
|
{
|
|
// get the two points
|
|
uno::Any aAny(xPropSet->getPropertyValue(u"Geometry"_ustr));
|
|
if (auto pSourcePolyPolygon
|
|
= o3tl::tryAccess<drawing::PointSequenceSequence>(aAny))
|
|
{
|
|
if (pSourcePolyPolygon->getLength() > 0)
|
|
{
|
|
const drawing::PointSequence& rInnerSequence = (*pSourcePolyPolygon)[0];
|
|
if (rInnerSequence.hasElements())
|
|
{
|
|
const awt::Point& rPoint = rInnerSequence[0];
|
|
aStart = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
|
|
}
|
|
if (rInnerSequence.getLength() > 1)
|
|
{
|
|
const awt::Point& rPoint = rInnerSequence[1];
|
|
aEnd = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( nFeatures & XMLShapeExportFlags::X )
|
|
{
|
|
// svg: x1
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
aStart.X);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
|
|
}
|
|
else
|
|
{
|
|
aEnd.X -= aStart.X;
|
|
}
|
|
|
|
if( nFeatures & XMLShapeExportFlags::Y )
|
|
{
|
|
// svg: y1
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
aStart.Y);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
|
|
}
|
|
else
|
|
{
|
|
aEnd.Y -= aStart.Y;
|
|
}
|
|
|
|
// svg: x2
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
aEnd.X);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
|
|
|
|
// svg: y2
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
aEnd.Y);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
|
|
|
|
// write line
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_LINE, bCreateNewline, true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
ImpExportText( xShape );
|
|
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportEllipseShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// get size to decide between Circle and Ellipse
|
|
awt::Size aSize = xShape->getSize();
|
|
sal_Int32 nRx((aSize.Width + 1) / 2);
|
|
sal_Int32 nRy((aSize.Height + 1) / 2);
|
|
bool bCircle(nRx == nRy);
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
drawing::CircleKind eKind = drawing::CircleKind_FULL;
|
|
xPropSet->getPropertyValue(u"CircleKind"_ustr) >>= eKind;
|
|
if( eKind != drawing::CircleKind_FULL )
|
|
{
|
|
OUStringBuffer sStringBuffer;
|
|
sal_Int32 nStartAngle = 0;
|
|
sal_Int32 nEndAngle = 0;
|
|
xPropSet->getPropertyValue(u"CircleStartAngle"_ustr) >>= nStartAngle;
|
|
xPropSet->getPropertyValue(u"CircleEndAngle"_ustr) >>= nEndAngle;
|
|
|
|
const double dStartAngle = nStartAngle / 100.0;
|
|
const double dEndAngle = nEndAngle / 100.0;
|
|
|
|
// export circle kind
|
|
SvXMLUnitConverter::convertEnum( sStringBuffer, eKind, aXML_CircleKind_EnumMap );
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_KIND, sStringBuffer.makeStringAndClear() );
|
|
|
|
// export start angle
|
|
::sax::Converter::convertDouble( sStringBuffer, dStartAngle );
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_ANGLE, sStringBuffer.makeStringAndClear() );
|
|
|
|
// export end angle
|
|
::sax::Converter::convertDouble( sStringBuffer, dEndAngle );
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_ANGLE, sStringBuffer.makeStringAndClear() );
|
|
}
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
|
|
// write ellipse or circle
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW,
|
|
bCircle ? XML_CIRCLE : XML_ELLIPSE,
|
|
bCreateNewline, true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
ImpExportText( xShape );
|
|
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportPolygonShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
bool bBezier(eShapeType == XmlShapeType::DrawClosedBezierShape
|
|
|| eShapeType == XmlShapeType::DrawOpenBezierShape);
|
|
|
|
// get matrix
|
|
::basegfx::B2DHomMatrix aMatrix;
|
|
ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
|
|
|
|
// decompose and correct about pRefPoint
|
|
::basegfx::B2DTuple aTRScale;
|
|
double fTRShear(0.0);
|
|
double fTRRotate(0.0);
|
|
::basegfx::B2DTuple aTRTranslate;
|
|
ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
|
|
|
|
// use features and write
|
|
ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
|
|
|
|
// create and export ViewBox
|
|
awt::Size aSize(basegfx::fround<tools::Long>(aTRScale.getX()),
|
|
basegfx::fround<tools::Long>(aTRScale.getY()));
|
|
SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
|
|
// prepare name (with most used)
|
|
enum ::xmloff::token::XMLTokenEnum eName(XML_PATH);
|
|
|
|
uno::Any aAny( xPropSet->getPropertyValue(u"Geometry"_ustr) );
|
|
basegfx::B2DPolyPolygon aPolyPolygon;
|
|
|
|
// tdf#145240 the Any can contain PolyPolygonBezierCoords or PointSequenceSequence
|
|
// (see OWN_ATTR_BASE_GEOMETRY in SvxShapePolyPolygon::getPropertyValueImpl),
|
|
// so be more flexible in interpreting it. Try to access bezier first:
|
|
{
|
|
auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
|
|
|
|
if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
|
|
{
|
|
aPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pSourcePolyPolygon);
|
|
}
|
|
}
|
|
|
|
// if received no data, try to access point sequence second:
|
|
if(0 == aPolyPolygon.count())
|
|
{
|
|
auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny);
|
|
|
|
if(pSourcePolyPolygon)
|
|
{
|
|
aPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pSourcePolyPolygon);
|
|
}
|
|
}
|
|
|
|
if(aPolyPolygon.count())
|
|
{
|
|
if(!bBezier && !aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count())
|
|
{
|
|
// simple polygon shape, can be written as svg:points sequence
|
|
const basegfx::B2DPolygon& aPolygon(aPolyPolygon.getB2DPolygon(0));
|
|
const OUString aPointString(basegfx::utils::exportToSvgPoints(aPolygon));
|
|
|
|
// write point array
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString);
|
|
|
|
// set name
|
|
eName = aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE;
|
|
}
|
|
else
|
|
{
|
|
// complex polygon shape, write as svg:d
|
|
const OUString aPolygonString(
|
|
basegfx::utils::exportToSvgD(
|
|
aPolyPolygon,
|
|
true, // bUseRelativeCoordinates
|
|
false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
|
|
true)); // bHandleRelativeNextPointCompatible
|
|
|
|
// write point array
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
|
|
}
|
|
}
|
|
|
|
// write object, but after attributes are added since this call will
|
|
// consume all of these added attributes and the destructor will close the
|
|
// scope. Also before text is added; this may add sub-scopes as needed
|
|
SvXMLElementExport aOBJ(
|
|
mrExport,
|
|
XML_NAMESPACE_DRAW,
|
|
eName,
|
|
bCreateNewline,
|
|
true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
ImpExportText( xShape );
|
|
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
OUString getNameFromStreamURL(std::u16string_view rURL)
|
|
{
|
|
static constexpr std::u16string_view sPackageURL(u"vnd.sun.star.Package:");
|
|
|
|
OUString sResult;
|
|
|
|
if (o3tl::starts_with(rURL, sPackageURL))
|
|
{
|
|
std::u16string_view sRequestedName = rURL.substr(sPackageURL.size());
|
|
size_t nLastIndex = sRequestedName.rfind('/');
|
|
if (nLastIndex != std::u16string_view::npos && nLastIndex + 1 < sRequestedName.size())
|
|
sRequestedName = sRequestedName.substr(nLastIndex + 1);
|
|
nLastIndex = sRequestedName.rfind('.');
|
|
if (nLastIndex != std::u16string_view::npos)
|
|
sRequestedName = sRequestedName.substr(0, nLastIndex);
|
|
if (!sRequestedName.empty())
|
|
sResult = sRequestedName;
|
|
}
|
|
|
|
return sResult;
|
|
}
|
|
|
|
} // end anonymous namespace
|
|
|
|
void XMLShapeExport::ImpExportGraphicObjectShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
bool bIsEmptyPresObj = false;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
if(eShapeType == XmlShapeType::PresGraphicObjectShape)
|
|
bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_GRAPHIC) );
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
|
|
XML_FRAME, bCreateNewline, true );
|
|
|
|
if (!bIsEmptyPresObj)
|
|
{
|
|
uno::Reference<graphic::XGraphic> xGraphic;
|
|
OUString sOutMimeType;
|
|
|
|
{
|
|
OUString aStreamURL;
|
|
xPropSet->getPropertyValue(u"GraphicStreamURL"_ustr) >>= aStreamURL;
|
|
OUString sRequestedName = getNameFromStreamURL(aStreamURL);
|
|
|
|
xPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
|
|
|
|
OUString sInternalURL;
|
|
|
|
if (xGraphic.is())
|
|
sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, sOutMimeType, sRequestedName);
|
|
|
|
if (!sInternalURL.isEmpty())
|
|
{
|
|
// apply possible changed stream URL to embedded image object
|
|
if (!sRequestedName.isEmpty())
|
|
{
|
|
OUString newStreamURL = u"vnd.sun.star.Package:"_ustr;
|
|
if (sInternalURL[0] == '#')
|
|
{
|
|
newStreamURL += sInternalURL.subView(1, sInternalURL.getLength() - 1);
|
|
}
|
|
else
|
|
{
|
|
newStreamURL += sInternalURL;
|
|
}
|
|
|
|
if (newStreamURL != aStreamURL)
|
|
{
|
|
xPropSet->setPropertyValue(u"GraphicStreamURL"_ustr, uno::Any(newStreamURL));
|
|
}
|
|
}
|
|
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
|
|
}
|
|
}
|
|
|
|
{
|
|
if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
|
|
{
|
|
if (sOutMimeType.isEmpty())
|
|
{
|
|
GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType);
|
|
}
|
|
if (!sOutMimeType.isEmpty())
|
|
{ // ODF 1.3 OFFICE-3943
|
|
GetExport().AddAttribute(
|
|
SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
|
|
? XML_NAMESPACE_DRAW
|
|
: XML_NAMESPACE_LO_EXT,
|
|
u"mime-type"_ustr, sOutMimeType);
|
|
}
|
|
}
|
|
|
|
SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
|
|
|
|
// optional office:binary-data
|
|
if (xGraphic.is())
|
|
{
|
|
mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
|
|
}
|
|
if (!bIsEmptyPresObj)
|
|
ImpExportText(xShape);
|
|
}
|
|
|
|
//Resolves: fdo#62461 put preferred image first above, followed by
|
|
//fallback here
|
|
if (!bIsEmptyPresObj
|
|
&& officecfg::Office::Common::Save::Graphic::AddReplacementImages::get())
|
|
{
|
|
uno::Reference<graphic::XGraphic> xReplacementGraphic;
|
|
xPropSet->getPropertyValue(u"ReplacementGraphic"_ustr) >>= xReplacementGraphic;
|
|
|
|
// If there is no url, then the graphic is empty
|
|
if (xReplacementGraphic.is())
|
|
{
|
|
OUString aMimeType;
|
|
const OUString aHref = mrExport.AddEmbeddedXGraphic(xReplacementGraphic, aMimeType);
|
|
|
|
if (aMimeType.isEmpty())
|
|
mrExport.GetGraphicMimeTypeFromStream(xReplacementGraphic, aMimeType);
|
|
|
|
if (!aHref.isEmpty())
|
|
{
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
|
|
}
|
|
|
|
if (!aMimeType.isEmpty() && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
|
|
{ // ODF 1.3 OFFICE-3943
|
|
mrExport.AddAttribute(
|
|
SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
|
|
? XML_NAMESPACE_DRAW
|
|
: XML_NAMESPACE_LO_EXT,
|
|
u"mime-type"_ustr, aMimeType);
|
|
}
|
|
|
|
SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
|
|
|
|
// optional office:binary-data
|
|
mrExport.AddEmbeddedXGraphicAsBase64(xReplacementGraphic);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
|
|
// image map
|
|
GetExport().GetImageMapExport().Export( xPropSet );
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
|
|
// Signature Line, QR Code - needs to be after the images!
|
|
if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
|
|
{
|
|
ImpExportSignatureLine(xShape);
|
|
ImpExportQRCode(xShape);
|
|
}
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportChartShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint,
|
|
comphelper::AttributeList* pAttrList )
|
|
{
|
|
ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList );
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportControlShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(xPropSet.is())
|
|
{
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
}
|
|
|
|
uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY );
|
|
SAL_WARN_IF( !xControl.is(), "xmloff", "Control shape is not supporting XControlShape" );
|
|
if( xControl.is() )
|
|
{
|
|
uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY );
|
|
SAL_WARN_IF( !xControlModel.is(), "xmloff", "Control shape has not XControlModel" );
|
|
if( xControlModel.is() )
|
|
{
|
|
OUString sControlId = mrExport.GetFormExport()->getControlId( xControlModel );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, sControlId );
|
|
}
|
|
}
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportConnectorShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
|
|
{
|
|
uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
|
|
|
|
OUString aStr;
|
|
OUStringBuffer sStringBuffer;
|
|
|
|
// export connection kind
|
|
drawing::ConnectorType eType = drawing::ConnectorType_STANDARD;
|
|
uno::Any aAny = xProps->getPropertyValue(u"EdgeKind"_ustr);
|
|
aAny >>= eType;
|
|
|
|
if( eType != drawing::ConnectorType_STANDARD )
|
|
{
|
|
SvXMLUnitConverter::convertEnum( sStringBuffer, eType, aXML_ConnectionKind_EnumMap );
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr);
|
|
}
|
|
|
|
// export line skew
|
|
sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0;
|
|
|
|
aAny = xProps->getPropertyValue(u"EdgeLine1Delta"_ustr);
|
|
aAny >>= nDelta1;
|
|
aAny = xProps->getPropertyValue(u"EdgeLine2Delta"_ustr);
|
|
aAny >>= nDelta2;
|
|
aAny = xProps->getPropertyValue(u"EdgeLine3Delta"_ustr);
|
|
aAny >>= nDelta3;
|
|
|
|
if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 )
|
|
{
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
nDelta1);
|
|
if( nDelta2 != 0 || nDelta3 != 0 )
|
|
{
|
|
sStringBuffer.append( ' ' );
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
nDelta2);
|
|
if( nDelta3 != 0 )
|
|
{
|
|
sStringBuffer.append( ' ' );
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(
|
|
sStringBuffer, nDelta3);
|
|
}
|
|
}
|
|
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr);
|
|
}
|
|
|
|
// export start and end point
|
|
awt::Point aStart(0,0);
|
|
awt::Point aEnd(1,1);
|
|
|
|
/* Get <StartPositionInHoriL2R> and
|
|
<EndPositionInHoriL2R>, if they exist and if the document is exported
|
|
into the OpenOffice.org file format.
|
|
These properties only exist at service css::text::Shape - the
|
|
Writer UNO service for shapes.
|
|
This code is needed, because the positioning attributes in the
|
|
OpenOffice.org file format are given in horizontal left-to-right layout
|
|
regardless the layout direction the shape is in. In the OASIS Open Office
|
|
file format the positioning attributes are correctly given in the layout
|
|
direction the shape is in. Thus, this code provides the conversion from
|
|
the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
|
|
*/
|
|
if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
|
|
xProps->getPropertySetInfo()->hasPropertyByName(u"StartPositionInHoriL2R"_ustr) &&
|
|
xProps->getPropertySetInfo()->hasPropertyByName(u"EndPositionInHoriL2R"_ustr) )
|
|
{
|
|
xProps->getPropertyValue(u"StartPositionInHoriL2R"_ustr) >>= aStart;
|
|
xProps->getPropertyValue(u"EndPositionInHoriL2R"_ustr) >>= aEnd;
|
|
}
|
|
else
|
|
{
|
|
xProps->getPropertyValue(u"StartPosition"_ustr) >>= aStart;
|
|
xProps->getPropertyValue(u"EndPosition"_ustr) >>= aEnd;
|
|
}
|
|
|
|
if( pRefPoint )
|
|
{
|
|
aStart.X -= pRefPoint->X;
|
|
aStart.Y -= pRefPoint->Y;
|
|
aEnd.X -= pRefPoint->X;
|
|
aEnd.Y -= pRefPoint->Y;
|
|
}
|
|
|
|
if( nFeatures & XMLShapeExportFlags::X )
|
|
{
|
|
// svg: x1
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
aStart.X);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
|
|
}
|
|
else
|
|
{
|
|
aEnd.X -= aStart.X;
|
|
}
|
|
|
|
if( nFeatures & XMLShapeExportFlags::Y )
|
|
{
|
|
// svg: y1
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
aStart.Y);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
|
|
}
|
|
else
|
|
{
|
|
aEnd.Y -= aStart.Y;
|
|
}
|
|
|
|
// svg: x2
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
|
|
|
|
// svg: y2
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
|
|
|
|
// #i39320#
|
|
uno::Reference< uno::XInterface > xRefS;
|
|
uno::Reference< uno::XInterface > xRefE;
|
|
|
|
// export start connection
|
|
xProps->getPropertyValue(u"StartShape"_ustr) >>= xRefS;
|
|
if( xRefS.is() )
|
|
{
|
|
const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS );
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId);
|
|
|
|
aAny = xProps->getPropertyValue(u"StartGluePointIndex"_ustr);
|
|
sal_Int32 nGluePointId = 0;
|
|
if( aAny >>= nGluePointId )
|
|
{
|
|
if( nGluePointId != -1 )
|
|
{
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::number( nGluePointId ));
|
|
}
|
|
}
|
|
}
|
|
|
|
// export end connection
|
|
xProps->getPropertyValue(u"EndShape"_ustr) >>= xRefE;
|
|
if( xRefE.is() )
|
|
{
|
|
const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE );
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId);
|
|
|
|
aAny = xProps->getPropertyValue(u"EndGluePointIndex"_ustr);
|
|
sal_Int32 nGluePointId = 0;
|
|
if( aAny >>= nGluePointId )
|
|
{
|
|
if( nGluePointId != -1 )
|
|
{
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::number( nGluePointId ));
|
|
}
|
|
}
|
|
}
|
|
|
|
// get PolygonBezier
|
|
aAny = xProps->getPropertyValue(u"PolyPolygonBezier"_ustr);
|
|
auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
|
|
if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
|
|
{
|
|
const basegfx::B2DPolyPolygon aPolyPolygon(
|
|
basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
|
|
*pSourcePolyPolygon));
|
|
const OUString aPolygonString(
|
|
basegfx::utils::exportToSvgD(
|
|
aPolyPolygon,
|
|
true, // bUseRelativeCoordinates
|
|
false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
|
|
true)); // bHandleRelativeNextPointCompatible
|
|
|
|
// write point array
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
|
|
}
|
|
|
|
// get matrix
|
|
::basegfx::B2DHomMatrix aMatrix;
|
|
ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xProps);
|
|
|
|
// decompose and correct about pRefPoint
|
|
::basegfx::B2DTuple aTRScale;
|
|
double fTRShear(0.0);
|
|
double fTRRotate(0.0);
|
|
::basegfx::B2DTuple aTRTranslate;
|
|
ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear,
|
|
fTRRotate, aTRTranslate, pRefPoint);
|
|
|
|
// fdo#49678: create and export ViewBox
|
|
awt::Size aSize(basegfx::fround<tools::Long>(aTRScale.getX()),
|
|
basegfx::fround<tools::Long>(aTRScale.getY()));
|
|
SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
|
|
|
|
// write connector shape. Add Export later.
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
ImpExportText( xShape );
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportMeasureShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point const * pRefPoint /* = NULL */)
|
|
{
|
|
uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
|
|
|
|
OUString aStr;
|
|
OUStringBuffer sStringBuffer;
|
|
|
|
// export start and end point
|
|
awt::Point aStart(0,0);
|
|
awt::Point aEnd(1,1);
|
|
|
|
/* Get <StartPositionInHoriL2R> and
|
|
<EndPositionInHoriL2R>, if they exist and if the document is exported
|
|
into the OpenOffice.org file format.
|
|
These properties only exist at service css::text::Shape - the
|
|
Writer UNO service for shapes.
|
|
This code is needed, because the positioning attributes in the
|
|
OpenOffice.org file format are given in horizontal left-to-right layout
|
|
regardless the layout direction the shape is in. In the OASIS Open Office
|
|
file format the positioning attributes are correctly given in the layout
|
|
direction the shape is in. Thus, this code provides the conversion from
|
|
the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
|
|
*/
|
|
if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
|
|
xProps->getPropertySetInfo()->hasPropertyByName(u"StartPositionInHoriL2R"_ustr) &&
|
|
xProps->getPropertySetInfo()->hasPropertyByName(u"EndPositionInHoriL2R"_ustr) )
|
|
{
|
|
xProps->getPropertyValue(u"StartPositionInHoriL2R"_ustr) >>= aStart;
|
|
xProps->getPropertyValue(u"EndPositionInHoriL2R"_ustr) >>= aEnd;
|
|
}
|
|
else
|
|
{
|
|
xProps->getPropertyValue(u"StartPosition"_ustr) >>= aStart;
|
|
xProps->getPropertyValue(u"EndPosition"_ustr) >>= aEnd;
|
|
}
|
|
|
|
if( pRefPoint )
|
|
{
|
|
aStart.X -= pRefPoint->X;
|
|
aStart.Y -= pRefPoint->Y;
|
|
aEnd.X -= pRefPoint->X;
|
|
aEnd.Y -= pRefPoint->Y;
|
|
}
|
|
|
|
if( nFeatures & XMLShapeExportFlags::X )
|
|
{
|
|
// svg: x1
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
aStart.X);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
|
|
}
|
|
else
|
|
{
|
|
aEnd.X -= aStart.X;
|
|
}
|
|
|
|
if( nFeatures & XMLShapeExportFlags::Y )
|
|
{
|
|
// svg: y1
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
aStart.Y);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
|
|
}
|
|
else
|
|
{
|
|
aEnd.Y -= aStart.Y;
|
|
}
|
|
|
|
// svg: x2
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
|
|
|
|
// svg: y2
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
|
|
|
|
// write measure shape
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
|
|
uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
|
|
if( xText.is() )
|
|
mrExport.GetTextParagraphExport()->exportText( xText );
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportOLE2Shape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */,
|
|
comphelper::AttributeList* pAttrList /* = NULL */ )
|
|
{
|
|
uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
|
|
|
|
SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "ole shape is not implementing needed interfaces");
|
|
if(!(xPropSet.is() && xNamed.is()))
|
|
return;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
bool bIsEmptyPresObj = false;
|
|
|
|
// presentation settings
|
|
if(eShapeType == XmlShapeType::PresOLE2Shape)
|
|
bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
|
|
else if(eShapeType == XmlShapeType::PresChartShape)
|
|
bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_CHART) );
|
|
else if(eShapeType == XmlShapeType::PresSheetShape)
|
|
bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
|
|
OUString sPersistName;
|
|
SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
|
|
XML_FRAME, bCreateNewline, true );
|
|
|
|
if (!bIsEmptyPresObj)
|
|
{
|
|
if (pAttrList)
|
|
{
|
|
mrExport.AddAttributeList(pAttrList);
|
|
}
|
|
|
|
OUString sClassId;
|
|
OUString sURL;
|
|
bool bInternal = false;
|
|
xPropSet->getPropertyValue(u"IsInternal"_ustr) >>= bInternal;
|
|
|
|
{
|
|
|
|
if ( bInternal )
|
|
{
|
|
// OOo internal links have no storage persistence, URL is stored in the XML file
|
|
// the result LinkURL is empty in case the object is not a link
|
|
xPropSet->getPropertyValue(u"LinkURL"_ustr) >>= sURL;
|
|
}
|
|
|
|
xPropSet->getPropertyValue(u"PersistName"_ustr) >>= sPersistName;
|
|
if ( sURL.isEmpty() )
|
|
{
|
|
if( !sPersistName.isEmpty() )
|
|
{
|
|
sURL = "vnd.sun.star.EmbeddedObject:" + sPersistName;
|
|
}
|
|
}
|
|
|
|
if( !bInternal )
|
|
xPropSet->getPropertyValue(u"CLSID"_ustr) >>= sClassId;
|
|
|
|
if( !sClassId.isEmpty() )
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId );
|
|
|
|
if(!bExportEmbedded)
|
|
{
|
|
// xlink:href
|
|
if( !sURL.isEmpty() )
|
|
{
|
|
// #96717# in theorie, if we don't have a URL we shouldn't even
|
|
// export this OLE shape. But practically it's too risky right now
|
|
// to change this so we better dispose this on load
|
|
sURL = mrExport.AddEmbeddedObject( sURL );
|
|
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
|
|
}
|
|
else
|
|
{
|
|
// tdf#153179 Export the preview graphic of the object if the object is missing.
|
|
uno::Reference<graphic::XGraphic> xGraphic;
|
|
xPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
|
|
|
|
if (xGraphic.is())
|
|
{
|
|
OUString aMimeType;
|
|
const OUString aHref = mrExport.AddEmbeddedXGraphic(xGraphic, aMimeType);
|
|
|
|
if (aMimeType.isEmpty())
|
|
mrExport.GetGraphicMimeTypeFromStream(xGraphic, aMimeType);
|
|
|
|
if (!aHref.isEmpty())
|
|
{
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
|
|
}
|
|
|
|
if (!aMimeType.isEmpty()
|
|
&& GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
|
|
{ // ODF 1.3 OFFICE-3943
|
|
mrExport.AddAttribute(SvtSaveOptions::ODFSVER_013
|
|
<= GetExport().getSaneDefaultVersion()
|
|
? XML_NAMESPACE_DRAW
|
|
: XML_NAMESPACE_LO_EXT,
|
|
u"mime-type"_ustr, aMimeType);
|
|
}
|
|
|
|
SvXMLElementExport aImageElem(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true,
|
|
true);
|
|
|
|
// optional office:binary-data
|
|
mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
|
|
|
|
ImpExportEvents(xShape);
|
|
ImpExportGluePoints(xShape);
|
|
ImpExportDescription(xShape);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enum XMLTokenEnum eElem = sClassId.isEmpty() ? XML_OBJECT : XML_OBJECT_OLE ;
|
|
SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, true, true );
|
|
|
|
// tdf#112547 export text as child of draw:object, where import expects it
|
|
if (!bIsEmptyPresObj && supportsText(eShapeType))
|
|
{
|
|
// #i118485# Add text export, the draw OLE shape allows text now
|
|
ImpExportText( xShape, TextPNS::EXTENSION );
|
|
}
|
|
|
|
if(bExportEmbedded && !bIsEmptyPresObj)
|
|
{
|
|
if(bInternal)
|
|
{
|
|
// embedded XML
|
|
uno::Reference< lang::XComponent > xComp;
|
|
xPropSet->getPropertyValue(u"Model"_ustr) >>= xComp;
|
|
SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" );
|
|
mrExport.ExportEmbeddedOwnObject( xComp );
|
|
}
|
|
else
|
|
{
|
|
// embed as Base64
|
|
// this is an alien object ( currently MSOLE is the only supported type of such objects )
|
|
// in case it is not an OASIS format the object should be asked to store replacement image if possible
|
|
|
|
OUString sURLRequest( sURL );
|
|
if ( !( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) )
|
|
sURLRequest += "?oasis=false";
|
|
mrExport.AddEmbeddedObjectAsBase64( sURLRequest );
|
|
}
|
|
}
|
|
}
|
|
if( !bIsEmptyPresObj )
|
|
{
|
|
OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + sPersistName;
|
|
if( !bExportEmbedded )
|
|
{
|
|
sURL = GetExport().AddEmbeddedObject( sURL );
|
|
mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
|
|
}
|
|
|
|
SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
|
|
XML_IMAGE, false, true );
|
|
|
|
if( bExportEmbedded )
|
|
GetExport().AddEmbeddedObjectAsBase64( sURL );
|
|
}
|
|
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportPageShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// #86163# Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
// export page number used for this page
|
|
uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
|
|
static constexpr OUString aPageNumberStr(u"PageNumber"_ustr);
|
|
if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr))
|
|
{
|
|
sal_Int32 nPageNumber = 0;
|
|
xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber;
|
|
if( nPageNumber )
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::number(nPageNumber));
|
|
}
|
|
|
|
// a presentation page shape, normally used on notes pages only. If
|
|
// it is used not as presentation shape, it may have been created with
|
|
// copy-paste exchange between draw and impress (this IS possible...)
|
|
if(eShapeType == XmlShapeType::PresPageShape)
|
|
{
|
|
mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS,
|
|
XML_PAGE);
|
|
}
|
|
|
|
// write Page shape
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, true);
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportCaptionShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
// evtl. corner radius?
|
|
sal_Int32 nCornerRadius(0);
|
|
xPropSet->getPropertyValue(u"CornerRadius"_ustr) >>= nCornerRadius;
|
|
if(nCornerRadius)
|
|
{
|
|
OUStringBuffer sStringBuffer;
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
nCornerRadius);
|
|
mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
|
|
}
|
|
|
|
awt::Point aCaptionPoint;
|
|
xPropSet->getPropertyValue(u"CaptionPoint"_ustr) >>= aCaptionPoint;
|
|
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
|
|
aCaptionPoint.X);
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() );
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
|
|
aCaptionPoint.Y);
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() );
|
|
|
|
// write Caption shape. Add export later.
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
bool bAnnotation( (nFeatures & XMLShapeExportFlags::ANNOTATION) == XMLShapeExportFlags::ANNOTATION );
|
|
|
|
SvXMLElementExport aObj( mrExport,
|
|
(bAnnotation ? XML_NAMESPACE_OFFICE
|
|
: XML_NAMESPACE_DRAW),
|
|
(bAnnotation ? XML_ANNOTATION : XML_CAPTION),
|
|
bCreateNewline, true );
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
if( bAnnotation )
|
|
mrExport.exportAnnotationMeta( xShape );
|
|
ImpExportText( xShape );
|
|
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportFrameShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
|
|
XML_FRAME, bCreateNewline, true );
|
|
|
|
// export frame url
|
|
OUString aStr;
|
|
xPropSet->getPropertyValue(u"FrameURL"_ustr) >>= aStr;
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
|
|
|
|
// export name
|
|
xPropSet->getPropertyValue(u"FrameName"_ustr) >>= aStr;
|
|
if( !aStr.isEmpty() )
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr );
|
|
|
|
// write floating frame
|
|
{
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, true, true);
|
|
}
|
|
|
|
ImpExportDescription(xShape);
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportAppletShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
|
|
XML_FRAME, bCreateNewline, true );
|
|
|
|
// export frame url
|
|
OUString aStr;
|
|
xPropSet->getPropertyValue(u"AppletCodeBase"_ustr) >>= aStr;
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
|
|
|
|
// export draw:applet-name
|
|
xPropSet->getPropertyValue(u"AppletName"_ustr) >>= aStr;
|
|
if( !aStr.isEmpty() )
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr );
|
|
|
|
// export draw:code
|
|
xPropSet->getPropertyValue(u"AppletCode"_ustr) >>= aStr;
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr );
|
|
|
|
// export draw:may-script
|
|
bool bIsScript = false;
|
|
xPropSet->getPropertyValue(u"AppletIsScript"_ustr) >>= bIsScript;
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE );
|
|
|
|
{
|
|
// write applet
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, true, true);
|
|
|
|
// export parameters
|
|
uno::Sequence< beans::PropertyValue > aCommands;
|
|
xPropSet->getPropertyValue(u"AppletCommands"_ustr) >>= aCommands;
|
|
for (const auto& rCommand : aCommands)
|
|
{
|
|
rCommand.Value >>= aStr;
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
|
|
SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
|
|
}
|
|
}
|
|
|
|
ImpExportDescription(xShape);
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportPluginShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
|
|
XML_FRAME, bCreateNewline, true );
|
|
|
|
// export plugin url
|
|
OUString aStr;
|
|
xPropSet->getPropertyValue(u"PluginURL"_ustr) >>= aStr;
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
|
|
|
|
// export mime-type
|
|
xPropSet->getPropertyValue(u"PluginMimeType"_ustr) >>= aStr;
|
|
if(!aStr.isEmpty())
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr );
|
|
|
|
{
|
|
// write plugin
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, true, true);
|
|
|
|
// export parameters
|
|
uno::Sequence< beans::PropertyValue > aCommands;
|
|
xPropSet->getPropertyValue(u"PluginCommands"_ustr) >>= aCommands;
|
|
for (const auto& rCommand : aCommands)
|
|
{
|
|
rCommand.Value >>= aStr;
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
|
|
SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
|
|
}
|
|
}
|
|
|
|
ImpExportDescription(xShape);
|
|
}
|
|
|
|
static void lcl_CopyStream(
|
|
uno::Reference<io::XInputStream> const& xInStream,
|
|
uno::Reference<embed::XStorage> const& xTarget,
|
|
OUString const& rPath, const OUString& rMimeType)
|
|
{
|
|
::comphelper::LifecycleProxy proxy;
|
|
uno::Reference<io::XStream> const xStream(
|
|
::comphelper::OStorageHelper::GetStreamAtPackageURL(xTarget, rPath,
|
|
embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, proxy));
|
|
uno::Reference<io::XOutputStream> const xOutStream(
|
|
(xStream.is()) ? xStream->getOutputStream() : nullptr);
|
|
if (!xOutStream.is())
|
|
{
|
|
SAL_WARN("xmloff", "no output stream");
|
|
throw uno::Exception(u"no output stream"_ustr,nullptr);
|
|
}
|
|
uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
|
|
uno::UNO_QUERY);
|
|
if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
|
|
xStreamProps->setPropertyValue(u"MediaType"_ustr,
|
|
uno::Any(rMimeType));
|
|
xStreamProps->setPropertyValue( // turn off compression
|
|
u"Compressed"_ustr,
|
|
uno::Any(false));
|
|
}
|
|
::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
|
|
xOutStream->closeOutput();
|
|
proxy.commitStorages();
|
|
}
|
|
|
|
static OUString
|
|
lcl_StoreMediaAndGetURL(SvXMLExport & rExport,
|
|
uno::Reference<beans::XPropertySet> const& xPropSet,
|
|
OUString const& rURL, const OUString& rMimeType)
|
|
{
|
|
OUString urlPath;
|
|
if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &urlPath))
|
|
{
|
|
try // video is embedded
|
|
{
|
|
uno::Reference<embed::XStorage> const xTarget(
|
|
rExport.GetTargetStorage(), uno::UNO_SET_THROW);
|
|
uno::Reference<io::XInputStream> xInStream;
|
|
xPropSet->getPropertyValue(u"PrivateStream"_ustr)
|
|
>>= xInStream;
|
|
|
|
if (!xInStream.is())
|
|
{
|
|
SAL_WARN("xmloff", "no input stream");
|
|
return OUString();
|
|
}
|
|
|
|
lcl_CopyStream(xInStream, xTarget, rURL, rMimeType);
|
|
|
|
return urlPath;
|
|
}
|
|
catch (uno::Exception const&)
|
|
{
|
|
TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media");
|
|
}
|
|
return OUString();
|
|
}
|
|
else
|
|
{
|
|
return rExport.GetRelativeReference(rURL); // linked
|
|
}
|
|
}
|
|
|
|
namespace
|
|
{
|
|
void ExportGraphicPreview(const uno::Reference<graphic::XGraphic>& xGraphic, SvXMLExport& rExport, std::u16string_view rPrefix, std::u16string_view rExtension, const OUString& rMimeType)
|
|
{
|
|
const bool bExportEmbedded(rExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
|
|
|
|
if( xGraphic.is() ) try
|
|
{
|
|
uno::Reference< uno::XComponentContext > xContext = rExport.getComponentContext();
|
|
|
|
uno::Reference< embed::XStorage > xPictureStorage;
|
|
uno::Reference< embed::XStorage > xStorage;
|
|
uno::Reference< io::XStream > xPictureStream;
|
|
|
|
OUString sPictureName;
|
|
if( bExportEmbedded )
|
|
{
|
|
xPictureStream.set( xContext->getServiceManager()->createInstanceWithContext( u"com.sun.star.comp.MemoryStream"_ustr, xContext), uno::UNO_QUERY_THROW );
|
|
}
|
|
else
|
|
{
|
|
xStorage.set( rExport.GetTargetStorage(), uno::UNO_SET_THROW );
|
|
|
|
xPictureStorage.set( xStorage->openStorageElement( u"Pictures"_ustr , ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
|
|
|
|
sal_Int32 nIndex = 0;
|
|
do
|
|
{
|
|
sPictureName = rPrefix + OUString::number( ++nIndex ) + rExtension;
|
|
}
|
|
while( xPictureStorage->hasByName( sPictureName ) );
|
|
|
|
xPictureStream.set( xPictureStorage->openStreamElement( sPictureName, ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
|
|
}
|
|
|
|
uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) );
|
|
uno::Sequence< beans::PropertyValue > aArgs{
|
|
comphelper::makePropertyValue(u"MimeType"_ustr, rMimeType ),
|
|
comphelper::makePropertyValue(u"OutputStream"_ustr, xPictureStream->getOutputStream())
|
|
};
|
|
xProvider->storeGraphic( xGraphic, aArgs );
|
|
|
|
if( xPictureStorage.is() )
|
|
{
|
|
uno::Reference< embed::XTransactedObject > xTrans( xPictureStorage, uno::UNO_QUERY );
|
|
if( xTrans.is() )
|
|
xTrans->commit();
|
|
}
|
|
|
|
if( !bExportEmbedded )
|
|
{
|
|
OUString sURL = "Pictures/" + sPictureName;
|
|
rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
|
|
rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
|
|
}
|
|
|
|
SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_IMAGE, false, true );
|
|
|
|
if( bExportEmbedded )
|
|
{
|
|
uno::Reference< io::XSeekableInputStream > xSeekable( xPictureStream, uno::UNO_QUERY_THROW );
|
|
xSeekable->seek(0);
|
|
|
|
XMLBase64Export aBase64Exp( rExport );
|
|
aBase64Exp.exportOfficeBinaryDataElement( uno::Reference < io::XInputStream >( xPictureStream, uno::UNO_QUERY_THROW ) );
|
|
}
|
|
}
|
|
catch( uno::Exception const & )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("xmloff.draw");
|
|
}
|
|
}
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportMediaShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
if(eShapeType == XmlShapeType::PresMediaShape)
|
|
{
|
|
(void)ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
|
|
}
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
|
|
XML_FRAME, bCreateNewline, true );
|
|
|
|
// export media url
|
|
OUString aMediaURL;
|
|
xPropSet->getPropertyValue(u"MediaURL"_ustr) >>= aMediaURL;
|
|
OUString sMimeType;
|
|
xPropSet->getPropertyValue(u"MediaMimeType"_ustr) >>= sMimeType;
|
|
|
|
OUString const persistentURL =
|
|
lcl_StoreMediaAndGetURL(GetExport(), xPropSet, aMediaURL, sMimeType);
|
|
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, persistentURL );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
|
|
mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
|
|
|
|
// export mime-type
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType );
|
|
|
|
// write plugin
|
|
auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true);
|
|
|
|
// export parameters
|
|
static constexpr OUString aFalseStr( u"false"_ustr );
|
|
static constexpr OUString aTrueStr( u"true"_ustr );
|
|
|
|
bool bLoop = false;
|
|
static constexpr OUString aLoopStr( u"Loop"_ustr );
|
|
xPropSet->getPropertyValue( aLoopStr ) >>= bLoop;
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aLoopStr );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bLoop ? aTrueStr : aFalseStr );
|
|
delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
|
|
|
|
bool bMute = false;
|
|
static constexpr OUString aMuteStr( u"Mute"_ustr );
|
|
xPropSet->getPropertyValue( aMuteStr ) >>= bMute;
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aMuteStr );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bMute ? aTrueStr : aFalseStr );
|
|
delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
|
|
|
|
sal_Int16 nVolumeDB = 0;
|
|
xPropSet->getPropertyValue(u"VolumeDB"_ustr) >>= nVolumeDB;
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, u"VolumeDB"_ustr );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, OUString::number( nVolumeDB ) );
|
|
delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
|
|
|
|
media::ZoomLevel eZoom;
|
|
OUString aZoomValue;
|
|
xPropSet->getPropertyValue(u"Zoom"_ustr) >>= eZoom;
|
|
switch( eZoom )
|
|
{
|
|
case media::ZoomLevel_ZOOM_1_TO_4 : aZoomValue = "25%"; break;
|
|
case media::ZoomLevel_ZOOM_1_TO_2 : aZoomValue = "50%"; break;
|
|
case media::ZoomLevel_ORIGINAL : aZoomValue = "100%"; break;
|
|
case media::ZoomLevel_ZOOM_2_TO_1 : aZoomValue = "200%"; break;
|
|
case media::ZoomLevel_ZOOM_4_TO_1 : aZoomValue = "400%"; break;
|
|
case media::ZoomLevel_FIT_TO_WINDOW: aZoomValue = "fit"; break;
|
|
case media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT: aZoomValue = "fixedfit"; break;
|
|
case media::ZoomLevel_FULLSCREEN : aZoomValue = "fullscreen"; break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if( !aZoomValue.isEmpty() )
|
|
{
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, u"Zoom"_ustr );
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aZoomValue );
|
|
delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
|
|
}
|
|
|
|
pPluginOBJ.reset();
|
|
|
|
if (officecfg::Office::Common::Save::Graphic::AddReplacementImages::get())
|
|
{
|
|
uno::Reference<graphic::XGraphic> xGraphic;
|
|
xPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
|
|
Graphic aGraphic(xGraphic);
|
|
if (!aGraphic.IsNone())
|
|
{
|
|
// The media has a preview, export it.
|
|
ExportGraphicPreview(xGraphic, mrExport, u"MediaPreview", u".png", u"image/png"_ustr);
|
|
}
|
|
}
|
|
|
|
ImpExportDescription(xShape);
|
|
}
|
|
|
|
void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
|
|
{
|
|
uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
|
|
if(!(xShapes.is() && xShapes->getCount()))
|
|
return;
|
|
|
|
uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
|
|
SAL_WARN_IF( !xPropSet.is(), "xmloff", "XMLShapeExport::ImpExport3DSceneShape can't export a scene without a propertyset" );
|
|
if( !xPropSet.is() )
|
|
return;
|
|
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
// 3d attributes
|
|
export3DSceneAttributes( xPropSet );
|
|
|
|
// write 3DScene shape
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DR3D, XML_SCENE, bCreateNewline, true);
|
|
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
|
|
// write 3DSceneLights
|
|
export3DLamps( xPropSet );
|
|
|
|
// #89764# if export of position is suppressed for group shape,
|
|
// positions of contained objects should be written relative to
|
|
// the upper left edge of the group.
|
|
awt::Point aUpperLeft;
|
|
|
|
if(!(nFeatures & XMLShapeExportFlags::POSITION))
|
|
{
|
|
nFeatures |= XMLShapeExportFlags::POSITION;
|
|
aUpperLeft = xShape->getPosition();
|
|
pRefPoint = &aUpperLeft;
|
|
}
|
|
|
|
// write members
|
|
exportShapes( xShapes, nFeatures, pRefPoint );
|
|
}
|
|
|
|
void XMLShapeExport::ImpExport3DShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XmlShapeType eShapeType)
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if(!xPropSet.is())
|
|
return;
|
|
|
|
OUString aStr;
|
|
OUStringBuffer sStringBuffer;
|
|
|
|
// transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
|
|
uno::Any aAny = xPropSet->getPropertyValue(u"D3DTransformMatrix"_ustr);
|
|
drawing::HomogenMatrix aHomMat;
|
|
aAny >>= aHomMat;
|
|
SdXMLImExTransform3D aTransform;
|
|
aTransform.AddHomogenMatrix(aHomMat);
|
|
if(aTransform.NeedsAction())
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
|
|
|
|
switch(eShapeType)
|
|
{
|
|
case XmlShapeType::Draw3DCubeObject:
|
|
{
|
|
// minEdge
|
|
aAny = xPropSet->getPropertyValue(u"D3DPosition"_ustr);
|
|
drawing::Position3D aPosition3D;
|
|
aAny >>= aPosition3D;
|
|
::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
|
|
|
|
// maxEdge
|
|
aAny = xPropSet->getPropertyValue(u"D3DSize"_ustr);
|
|
drawing::Direction3D aDirection3D;
|
|
aAny >>= aDirection3D;
|
|
::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
|
|
|
|
// transform maxEdge from distance to pos
|
|
aDir3D = aPos3D + aDir3D;
|
|
|
|
// write minEdge
|
|
if(aPos3D != ::basegfx::B3DVector(-2500.0, -2500.0, -2500.0)) // write only when not default
|
|
{
|
|
SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MIN_EDGE, aStr);
|
|
}
|
|
|
|
// write maxEdge
|
|
if(aDir3D != ::basegfx::B3DVector(2500.0, 2500.0, 2500.0)) // write only when not default
|
|
{
|
|
SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MAX_EDGE, aStr);
|
|
}
|
|
|
|
// write 3DCube shape
|
|
// #i123542# Do this *after* the attributes are added, else these will be lost since opening
|
|
// the scope will clear the global attribute list at the exporter
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_CUBE, true, true);
|
|
|
|
break;
|
|
}
|
|
case XmlShapeType::Draw3DSphereObject:
|
|
{
|
|
// Center
|
|
aAny = xPropSet->getPropertyValue(u"D3DPosition"_ustr);
|
|
drawing::Position3D aPosition3D;
|
|
aAny >>= aPosition3D;
|
|
::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
|
|
|
|
// Size
|
|
aAny = xPropSet->getPropertyValue(u"D3DSize"_ustr);
|
|
drawing::Direction3D aDirection3D;
|
|
aAny >>= aDirection3D;
|
|
::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
|
|
|
|
// write Center
|
|
if(aPos3D != ::basegfx::B3DVector(0.0, 0.0, 0.0)) // write only when not default
|
|
{
|
|
SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_CENTER, aStr);
|
|
}
|
|
|
|
// write Size
|
|
if(aDir3D != ::basegfx::B3DVector(5000.0, 5000.0, 5000.0)) // write only when not default
|
|
{
|
|
SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SIZE, aStr);
|
|
}
|
|
|
|
// write 3DSphere shape
|
|
// #i123542# Do this *after* the attributes are added, else these will be lost since opening
|
|
// the scope will clear the global attribute list at the exporter
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_SPHERE, true, true);
|
|
|
|
break;
|
|
}
|
|
case XmlShapeType::Draw3DLatheObject:
|
|
case XmlShapeType::Draw3DExtrudeObject:
|
|
{
|
|
// write special 3DLathe/3DExtrude attributes, get 3D tools::PolyPolygon as drawing::PolyPolygonShape3D
|
|
aAny = xPropSet->getPropertyValue(u"D3DPolyPolygon3D"_ustr);
|
|
drawing::PolyPolygonShape3D aUnoPolyPolygon3D;
|
|
aAny >>= aUnoPolyPolygon3D;
|
|
|
|
// convert to 3D PolyPolygon
|
|
const basegfx::B3DPolyPolygon aPolyPolygon3D(
|
|
basegfx::utils::UnoPolyPolygonShape3DToB3DPolyPolygon(
|
|
aUnoPolyPolygon3D));
|
|
|
|
// convert to 2D tools::PolyPolygon using identity 3D transformation (just grep X and Y)
|
|
const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion;
|
|
const basegfx::B2DPolyPolygon aPolyPolygon(
|
|
basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(
|
|
aPolyPolygon3D,
|
|
aB3DHomMatrixFor2DConversion));
|
|
|
|
// get 2D range of it
|
|
const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange());
|
|
|
|
// export ViewBox
|
|
SdXMLImExViewBox aViewBox(
|
|
aPolyPolygonRange.getMinX(),
|
|
aPolyPolygonRange.getMinY(),
|
|
aPolyPolygonRange.getWidth(),
|
|
aPolyPolygonRange.getHeight());
|
|
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
|
|
|
|
// prepare svg:d string
|
|
const OUString aPolygonString(
|
|
basegfx::utils::exportToSvgD(
|
|
aPolyPolygon,
|
|
true, // bUseRelativeCoordinates
|
|
false, // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now
|
|
true)); // bHandleRelativeNextPointCompatible
|
|
|
|
// write point array
|
|
mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
|
|
|
|
if(eShapeType == XmlShapeType::Draw3DLatheObject)
|
|
{
|
|
// write 3DLathe shape
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_ROTATE, true, true);
|
|
}
|
|
else
|
|
{
|
|
// write 3DExtrude shape
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_EXTRUDE, true, true);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/** helper for chart that adds all attributes of a 3d scene element to the export */
|
|
void XMLShapeExport::export3DSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
|
|
{
|
|
OUString aStr;
|
|
OUStringBuffer sStringBuffer;
|
|
|
|
// world transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
|
|
uno::Any aAny = xPropSet->getPropertyValue(u"D3DTransformMatrix"_ustr);
|
|
drawing::HomogenMatrix aHomMat;
|
|
aAny >>= aHomMat;
|
|
SdXMLImExTransform3D aTransform;
|
|
aTransform.AddHomogenMatrix(aHomMat);
|
|
if(aTransform.NeedsAction())
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
|
|
|
|
// VRP, VPN, VUP
|
|
aAny = xPropSet->getPropertyValue(u"D3DCameraGeometry"_ustr);
|
|
drawing::CameraGeometry aCamGeo;
|
|
aAny >>= aCamGeo;
|
|
|
|
::basegfx::B3DVector aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ);
|
|
if(aVRP != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
|
|
{
|
|
SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVRP);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VRP, aStr);
|
|
}
|
|
|
|
::basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ);
|
|
if(aVPN != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
|
|
{
|
|
SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVPN);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VPN, aStr);
|
|
}
|
|
|
|
::basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ);
|
|
if(aVUP != ::basegfx::B3DVector(0.0, 1.0, 0.0)) // write only when not default
|
|
{
|
|
SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVUP);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VUP, aStr);
|
|
}
|
|
|
|
// projection "D3DScenePerspective" drawing::ProjectionMode
|
|
aAny = xPropSet->getPropertyValue(u"D3DScenePerspective"_ustr);
|
|
drawing::ProjectionMode aPrjMode;
|
|
aAny >>= aPrjMode;
|
|
if(aPrjMode == drawing::ProjectionMode_PARALLEL)
|
|
aStr = GetXMLToken(XML_PARALLEL);
|
|
else
|
|
aStr = GetXMLToken(XML_PERSPECTIVE);
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_PROJECTION, aStr);
|
|
|
|
// distance
|
|
aAny = xPropSet->getPropertyValue(u"D3DSceneDistance"_ustr);
|
|
sal_Int32 nDistance = 0;
|
|
aAny >>= nDistance;
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
nDistance);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DISTANCE, aStr);
|
|
|
|
// focalLength
|
|
aAny = xPropSet->getPropertyValue(u"D3DSceneFocalLength"_ustr);
|
|
sal_Int32 nFocalLength = 0;
|
|
aAny >>= nFocalLength;
|
|
mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
|
|
nFocalLength);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, aStr);
|
|
|
|
// shadowSlant
|
|
aAny = xPropSet->getPropertyValue(u"D3DSceneShadowSlant"_ustr);
|
|
sal_Int16 nShadowSlant = 0;
|
|
aAny >>= nShadowSlant;
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, OUString::number(static_cast<sal_Int32>(nShadowSlant)));
|
|
|
|
// shadeMode
|
|
aAny = xPropSet->getPropertyValue(u"D3DSceneShadeMode"_ustr);
|
|
drawing::ShadeMode aShadeMode;
|
|
if(aAny >>= aShadeMode)
|
|
{
|
|
if(aShadeMode == drawing::ShadeMode_FLAT)
|
|
aStr = GetXMLToken(XML_FLAT);
|
|
else if(aShadeMode == drawing::ShadeMode_PHONG)
|
|
aStr = GetXMLToken(XML_PHONG);
|
|
else if(aShadeMode == drawing::ShadeMode_SMOOTH)
|
|
aStr = GetXMLToken(XML_GOURAUD);
|
|
else
|
|
aStr = GetXMLToken(XML_DRAFT);
|
|
}
|
|
else
|
|
{
|
|
// ShadeMode enum not there, write default
|
|
aStr = GetXMLToken(XML_GOURAUD);
|
|
}
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr);
|
|
|
|
// ambientColor
|
|
aAny = xPropSet->getPropertyValue(u"D3DSceneAmbientColor"_ustr);
|
|
sal_Int32 nAmbientColor = 0;
|
|
aAny >>= nAmbientColor;
|
|
::sax::Converter::convertColor(sStringBuffer, nAmbientColor);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, aStr);
|
|
|
|
// lightingMode
|
|
aAny = xPropSet->getPropertyValue(u"D3DSceneTwoSidedLighting"_ustr);
|
|
bool bTwoSidedLighting = false;
|
|
aAny >>= bTwoSidedLighting;
|
|
::sax::Converter::convertBool(sStringBuffer, bTwoSidedLighting);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, aStr);
|
|
}
|
|
|
|
/** helper for chart that exports all lamps from the propertyset */
|
|
void XMLShapeExport::export3DLamps( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
|
|
{
|
|
// write lamps 1..8 as content
|
|
OUString aStr;
|
|
OUStringBuffer sStringBuffer;
|
|
|
|
static constexpr OUStringLiteral aColorPropName(u"D3DSceneLightColor");
|
|
static constexpr OUStringLiteral aDirectionPropName(u"D3DSceneLightDirection");
|
|
static constexpr OUStringLiteral aLightOnPropName(u"D3DSceneLightOn");
|
|
|
|
::basegfx::B3DVector aLightDirection;
|
|
drawing::Direction3D aLightDir;
|
|
bool bLightOnOff = false;
|
|
for(sal_Int32 nLamp = 1; nLamp <= 8; nLamp++)
|
|
{
|
|
OUString aIndexStr = OUString::number( nLamp );
|
|
|
|
// lightcolor
|
|
OUString aPropName = aColorPropName + aIndexStr;
|
|
sal_Int32 nLightColor = 0;
|
|
xPropSet->getPropertyValue( aPropName ) >>= nLightColor;
|
|
::sax::Converter::convertColor(sStringBuffer, nLightColor);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, aStr);
|
|
|
|
// lightdirection
|
|
aPropName = aDirectionPropName + aIndexStr;
|
|
xPropSet->getPropertyValue(aPropName) >>= aLightDir;
|
|
aLightDirection = ::basegfx::B3DVector(aLightDir.DirectionX, aLightDir.DirectionY, aLightDir.DirectionZ);
|
|
SvXMLUnitConverter::convertB3DVector(sStringBuffer, aLightDirection);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIRECTION, aStr);
|
|
|
|
// lighton
|
|
aPropName = aLightOnPropName + aIndexStr;
|
|
xPropSet->getPropertyValue(aPropName) >>= bLightOnOff;
|
|
::sax::Converter::convertBool(sStringBuffer, bLightOnOff);
|
|
aStr = sStringBuffer.makeStringAndClear();
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_ENABLED, aStr);
|
|
|
|
// specular
|
|
mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SPECULAR,
|
|
nLamp == 1 ? XML_TRUE : XML_FALSE);
|
|
|
|
// write light entry
|
|
SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_LIGHT, true, true);
|
|
}
|
|
}
|
|
|
|
|
|
// using namespace css::io;
|
|
// using namespace ::xmloff::EnhancedCustomShapeToken;
|
|
|
|
|
|
static void ExportParameter( OUStringBuffer& rStrBuffer, const css::drawing::EnhancedCustomShapeParameter& rParameter )
|
|
{
|
|
if ( !rStrBuffer.isEmpty() )
|
|
rStrBuffer.append( ' ' );
|
|
if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
|
|
{
|
|
double fNumber = 0.0;
|
|
rParameter.Value >>= fNumber;
|
|
::rtl::math::doubleToUStringBuffer( rStrBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true );
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 nValue = 0;
|
|
rParameter.Value >>= nValue;
|
|
|
|
switch( rParameter.Type )
|
|
{
|
|
case css::drawing::EnhancedCustomShapeParameterType::EQUATION :
|
|
{
|
|
rStrBuffer.append( "?f" + OUString::number( nValue ) );
|
|
}
|
|
break;
|
|
|
|
case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT :
|
|
{
|
|
rStrBuffer.append( '$' );
|
|
rStrBuffer.append( nValue );
|
|
}
|
|
break;
|
|
|
|
case css::drawing::EnhancedCustomShapeParameterType::BOTTOM :
|
|
rStrBuffer.append( GetXMLToken( XML_BOTTOM ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::RIGHT :
|
|
rStrBuffer.append( GetXMLToken( XML_RIGHT ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::TOP :
|
|
rStrBuffer.append( GetXMLToken( XML_TOP ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::LEFT :
|
|
rStrBuffer.append( GetXMLToken( XML_LEFT ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::XSTRETCH :
|
|
rStrBuffer.append( GetXMLToken( XML_XSTRETCH ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::YSTRETCH :
|
|
rStrBuffer.append( GetXMLToken( XML_YSTRETCH ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::HASSTROKE :
|
|
rStrBuffer.append( GetXMLToken( XML_HASSTROKE ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::HASFILL :
|
|
rStrBuffer.append( GetXMLToken( XML_HASFILL ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::WIDTH :
|
|
rStrBuffer.append( GetXMLToken( XML_WIDTH ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::HEIGHT :
|
|
rStrBuffer.append( GetXMLToken( XML_HEIGHT ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH :
|
|
rStrBuffer.append( GetXMLToken( XML_LOGWIDTH ) ); break;
|
|
case css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT :
|
|
rStrBuffer.append( GetXMLToken( XML_LOGHEIGHT ) ); break;
|
|
default :
|
|
rStrBuffer.append( nValue );
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ImpExportEquations( SvXMLExport& rExport, const uno::Sequence< OUString >& rEquations )
|
|
{
|
|
sal_Int32 i;
|
|
for ( i = 0; i < rEquations.getLength(); i++ )
|
|
{
|
|
OUString aStr= "f" + OUString::number( i );
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aStr );
|
|
|
|
aStr = rEquations[ i ];
|
|
sal_Int32 nIndex = 0;
|
|
do
|
|
{
|
|
nIndex = aStr.indexOf( '?', nIndex );
|
|
if ( nIndex != -1 )
|
|
{
|
|
aStr = OUString::Concat(aStr.subView(0, nIndex + 1)) + "f"
|
|
+ aStr.subView(nIndex + 1, aStr.getLength() - nIndex - 1);
|
|
nIndex++;
|
|
}
|
|
} while( nIndex != -1 );
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FORMULA, aStr );
|
|
SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_EQUATION, true, true );
|
|
}
|
|
}
|
|
|
|
static void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::PropertyValues >& rHandles )
|
|
{
|
|
if ( !rHandles.hasElements() )
|
|
return;
|
|
|
|
OUString aStr;
|
|
OUStringBuffer aStrBuffer;
|
|
|
|
for ( const uno::Sequence< beans::PropertyValue >& rPropSeq : rHandles )
|
|
{
|
|
bool bPosition = false;
|
|
for ( const beans::PropertyValue& rPropVal : rPropSeq )
|
|
{
|
|
switch( EASGet( rPropVal.Name ) )
|
|
{
|
|
case EAS_Position :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameterPair aPosition;
|
|
if ( rPropVal.Value >>= aPosition )
|
|
{
|
|
ExportParameter( aStrBuffer, aPosition.First );
|
|
ExportParameter( aStrBuffer, aPosition.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
|
|
// Keep it for backward compatibility
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION, aStr );
|
|
|
|
SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
|
|
if (eVersion >= SvtSaveOptions::ODFSVER_014)
|
|
{
|
|
comphelper::SequenceAsHashMap aPropSeqMap(rPropSeq);
|
|
if (aPropSeqMap.contains(u"Polar"_ustr))
|
|
{
|
|
ExportParameter( aStrBuffer, aPosition.First );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_RADIUS, aStr);
|
|
|
|
ExportParameter( aStrBuffer, aPosition.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_ANGLE, aStr);
|
|
}
|
|
else
|
|
{
|
|
ExportParameter( aStrBuffer, aPosition.First );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION_X, aStr );
|
|
|
|
ExportParameter( aStrBuffer, aPosition.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION_Y, aStr );
|
|
}
|
|
}
|
|
|
|
bPosition = true;
|
|
}
|
|
}
|
|
break;
|
|
case EAS_MirroredX :
|
|
{
|
|
bool bMirroredX;
|
|
if ( rPropVal.Value >>= bMirroredX )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_HORIZONTAL,
|
|
bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_MirroredY :
|
|
{
|
|
bool bMirroredY;
|
|
if ( rPropVal.Value >>= bMirroredY )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_VERTICAL,
|
|
bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_Switched :
|
|
{
|
|
bool bSwitched;
|
|
if ( rPropVal.Value >>= bSwitched )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_SWITCHED,
|
|
bSwitched ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_Polar :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameterPair aPolar;
|
|
if ( rPropVal.Value >>= aPolar )
|
|
{
|
|
ExportParameter( aStrBuffer, aPolar.First );
|
|
ExportParameter( aStrBuffer, aPolar.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
// Keep it for backward compatibility
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR, aStr );
|
|
|
|
SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
|
|
if (eVersion >= SvtSaveOptions::ODFSVER_014)
|
|
{
|
|
ExportParameter( aStrBuffer, aPolar.First );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_POLE_X, aStr );
|
|
|
|
ExportParameter( aStrBuffer, aPolar.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_POLE_Y, aStr );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EAS_RadiusRangeMinimum :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
|
|
if ( rPropVal.Value >>= aRadiusRangeMinimum )
|
|
{
|
|
ExportParameter( aStrBuffer, aRadiusRangeMinimum );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MINIMUM, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_RadiusRangeMaximum :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
|
|
if ( rPropVal.Value >>= aRadiusRangeMaximum )
|
|
{
|
|
ExportParameter( aStrBuffer, aRadiusRangeMaximum );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MAXIMUM, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_RangeXMinimum :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameter aXRangeMinimum;
|
|
if ( rPropVal.Value >>= aXRangeMinimum )
|
|
{
|
|
ExportParameter( aStrBuffer, aXRangeMinimum );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MINIMUM, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_RangeXMaximum :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameter aXRangeMaximum;
|
|
if ( rPropVal.Value >>= aXRangeMaximum )
|
|
{
|
|
ExportParameter( aStrBuffer, aXRangeMaximum );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MAXIMUM, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_RangeYMinimum :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameter aYRangeMinimum;
|
|
if ( rPropVal.Value >>= aYRangeMinimum )
|
|
{
|
|
ExportParameter( aStrBuffer, aYRangeMinimum );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MINIMUM, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_RangeYMaximum :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameter aYRangeMaximum;
|
|
if ( rPropVal.Value >>= aYRangeMaximum )
|
|
{
|
|
ExportParameter( aStrBuffer, aYRangeMaximum );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MAXIMUM, aStr );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if ( bPosition )
|
|
SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_HANDLE, true, true );
|
|
else
|
|
rExport.ClearAttrList();
|
|
}
|
|
}
|
|
|
|
static void ImpExportEnhancedPath( SvXMLExport& rExport,
|
|
const uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair >& rCoordinates,
|
|
const uno::Sequence< css::drawing::EnhancedCustomShapeSegment >& rSegments,
|
|
bool bExtended = false )
|
|
{
|
|
|
|
OUString aStr;
|
|
OUStringBuffer aStrBuffer;
|
|
bool bNeedExtended = false;
|
|
|
|
sal_Int32 i, j, k, l;
|
|
|
|
sal_Int32 nCoords = rCoordinates.getLength();
|
|
sal_Int32 nSegments = rSegments.getLength();
|
|
bool bSimpleSegments = nSegments == 0;
|
|
if ( bSimpleSegments )
|
|
nSegments = 4;
|
|
for ( j = i = 0; j < nSegments; j++ )
|
|
{
|
|
css::drawing::EnhancedCustomShapeSegment aSegment;
|
|
if ( bSimpleSegments )
|
|
{
|
|
// if there are not enough segments we will default them
|
|
switch( j )
|
|
{
|
|
case 0 :
|
|
{
|
|
aSegment.Count = 1;
|
|
aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
|
|
}
|
|
break;
|
|
case 1 :
|
|
{
|
|
aSegment.Count = static_cast<sal_Int16>(std::min( nCoords - 1, sal_Int32(32767) ));
|
|
aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
|
|
}
|
|
break;
|
|
case 2 :
|
|
{
|
|
aSegment.Count = 1;
|
|
aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
|
|
}
|
|
break;
|
|
case 3 :
|
|
{
|
|
aSegment.Count = 1;
|
|
aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
aSegment = rSegments[ j ];
|
|
|
|
if ( !aStrBuffer.isEmpty() )
|
|
aStrBuffer.append( ' ' );
|
|
|
|
sal_Int32 nParameter = 0;
|
|
switch( aSegment.Command )
|
|
{
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
|
|
aStrBuffer.append( 'Z' ); break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
|
|
aStrBuffer.append( 'N' ); break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
|
|
aStrBuffer.append( 'F' ); break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
|
|
aStrBuffer.append( 'S' ); break;
|
|
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
|
|
aStrBuffer.append( 'M' ); nParameter = 1; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO :
|
|
aStrBuffer.append( 'L' ); nParameter = 1; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
|
|
aStrBuffer.append( 'C' ); nParameter = 3; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
|
|
aStrBuffer.append( 'T' ); nParameter = 3; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
|
|
aStrBuffer.append( 'U' ); nParameter = 3; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
|
|
aStrBuffer.append( 'A' ); nParameter = 4; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::ARC :
|
|
aStrBuffer.append( 'B' ); nParameter = 4; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
|
|
aStrBuffer.append( 'W' ); nParameter = 4; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
|
|
aStrBuffer.append( 'V' ); nParameter = 4; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
|
|
aStrBuffer.append( 'X' ); nParameter = 1; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
|
|
aStrBuffer.append( 'Y' ); nParameter = 1; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO :
|
|
aStrBuffer.append( 'Q' ); nParameter = 2; break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO :
|
|
if ( bExtended ) {
|
|
aStrBuffer.append( 'G' );
|
|
nParameter = 2;
|
|
} else {
|
|
aStrBuffer.setLength( aStrBuffer.getLength() - 1);
|
|
bNeedExtended = true;
|
|
i += 2;
|
|
}
|
|
break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN :
|
|
if ( bExtended )
|
|
aStrBuffer.append( 'H' );
|
|
else
|
|
bNeedExtended = true;
|
|
break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS :
|
|
if ( bExtended )
|
|
aStrBuffer.append( 'I' );
|
|
else
|
|
bNeedExtended = true;
|
|
break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN :
|
|
if ( bExtended )
|
|
aStrBuffer.append( 'J' );
|
|
else
|
|
bNeedExtended = true;
|
|
break;
|
|
case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS :
|
|
if ( bExtended )
|
|
aStrBuffer.append( 'K' );
|
|
else
|
|
bNeedExtended = true;
|
|
break;
|
|
default : // ups, seems to be something wrong
|
|
{
|
|
aSegment.Count = 1;
|
|
aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
|
|
}
|
|
break;
|
|
}
|
|
if ( nParameter )
|
|
{
|
|
for ( k = 0; k < aSegment.Count; k++ )
|
|
{
|
|
if ( ( i + nParameter ) <= nCoords )
|
|
{
|
|
for ( l = 0; l < nParameter; l++ )
|
|
{
|
|
ExportParameter( aStrBuffer, rCoordinates[ i ].First );
|
|
ExportParameter( aStrBuffer, rCoordinates[ i++ ].Second );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
j = nSegments; // error -> exiting
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( bExtended ? XML_NAMESPACE_DRAW_EXT : XML_NAMESPACE_DRAW, XML_ENHANCED_PATH, aStr );
|
|
if (!bExtended && bNeedExtended && (rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
|
|
ImpExportEnhancedPath( rExport, rCoordinates, rSegments, true );
|
|
}
|
|
|
|
static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Reference< beans::XPropertySet >& xPropSet )
|
|
{
|
|
bool bEquations = false;
|
|
uno::Sequence< OUString > aEquations;
|
|
|
|
bool bHandles = false;
|
|
uno::Sequence< beans::PropertyValues > aHandles;
|
|
|
|
uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
|
|
uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
|
|
|
|
uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentValues;
|
|
|
|
OUString aStr;
|
|
OUStringBuffer aStrBuffer;
|
|
double fTextRotateAngle(0.0);
|
|
double fTextPreRotateAngle(0.0); // will be consolidated with fTextRotateAngle at the end
|
|
SvXMLUnitConverter& rUnitConverter = rExport.GetMM100UnitConverter();
|
|
|
|
uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
|
|
|
|
// geometry
|
|
static constexpr OUString sCustomShapeGeometry( u"CustomShapeGeometry"_ustr );
|
|
if ( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( sCustomShapeGeometry ) )
|
|
{
|
|
uno::Any aGeoPropSet( xPropSet->getPropertyValue( sCustomShapeGeometry ) );
|
|
uno::Sequence< beans::PropertyValue > aGeoPropSeq;
|
|
|
|
if ( aGeoPropSet >>= aGeoPropSeq )
|
|
{
|
|
bool bCoordinates = false;
|
|
OUString aCustomShapeType( u"non-primitive"_ustr );
|
|
|
|
for (const beans::PropertyValue& rGeoProp : aGeoPropSeq)
|
|
{
|
|
switch( EASGet( rGeoProp.Name ) )
|
|
{
|
|
case EAS_Type :
|
|
{
|
|
rGeoProp.Value >>= aCustomShapeType;
|
|
}
|
|
break;
|
|
case EAS_MirroredX :
|
|
{
|
|
bool bMirroredX;
|
|
if ( rGeoProp.Value >>= bMirroredX )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_HORIZONTAL,
|
|
bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_MirroredY :
|
|
{
|
|
bool bMirroredY;
|
|
if ( rGeoProp.Value >>= bMirroredY )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_VERTICAL,
|
|
bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_ViewBox :
|
|
{
|
|
awt::Rectangle aRect;
|
|
if ( rGeoProp.Value >>= aRect )
|
|
{
|
|
SdXMLImExViewBox aViewBox( aRect.X, aRect.Y, aRect.Width, aRect.Height );
|
|
rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_TextPreRotateAngle :
|
|
{
|
|
rGeoProp.Value >>= fTextPreRotateAngle;
|
|
}
|
|
break;
|
|
case EAS_TextRotateAngle :
|
|
{
|
|
rGeoProp.Value >>= fTextRotateAngle;
|
|
}
|
|
break;
|
|
case EAS_Extrusion :
|
|
{
|
|
uno::Sequence< beans::PropertyValue > aExtrusionPropSeq;
|
|
if ( rGeoProp.Value >>= aExtrusionPropSeq )
|
|
{
|
|
bool bSkewValuesProvided = false;
|
|
for (const beans::PropertyValue& rProp : aExtrusionPropSeq)
|
|
{
|
|
switch( EASGet( rProp.Name ) )
|
|
{
|
|
case EAS_Extrusion :
|
|
{
|
|
bool bExtrusionOn;
|
|
if ( rProp.Value >>= bExtrusionOn )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION,
|
|
bExtrusionOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_Brightness :
|
|
{
|
|
double fExtrusionBrightness = 0;
|
|
if ( rProp.Value >>= fExtrusionBrightness )
|
|
{
|
|
::sax::Converter::convertDouble(
|
|
aStrBuffer,
|
|
fExtrusionBrightness,
|
|
false,
|
|
util::MeasureUnit::PERCENT,
|
|
util::MeasureUnit::PERCENT);
|
|
aStrBuffer.append( '%' );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_BRIGHTNESS, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Depth :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair;
|
|
if ( rProp.Value >>= aDepthParaPair )
|
|
{
|
|
double fDepth = 0;
|
|
if ( aDepthParaPair.First.Value >>= fDepth )
|
|
{
|
|
rExport.GetMM100UnitConverter().convertDouble( aStrBuffer, fDepth );
|
|
ExportParameter( aStrBuffer, aDepthParaPair.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DEPTH, aStr );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Diffusion :
|
|
{
|
|
double fExtrusionDiffusion = 0;
|
|
if ( rProp.Value >>= fExtrusionDiffusion )
|
|
{
|
|
::sax::Converter::convertDouble(
|
|
aStrBuffer,
|
|
fExtrusionDiffusion,
|
|
false,
|
|
util::MeasureUnit::PERCENT,
|
|
util::MeasureUnit::PERCENT);
|
|
aStrBuffer.append( '%' );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DIFFUSION, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_NumberOfLineSegments :
|
|
{
|
|
sal_Int32 nExtrusionNumberOfLineSegments = 0;
|
|
if ( rProp.Value >>= nExtrusionNumberOfLineSegments )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_NUMBER_OF_LINE_SEGMENTS, OUString::number( nExtrusionNumberOfLineSegments ) );
|
|
}
|
|
break;
|
|
case EAS_LightFace :
|
|
{
|
|
bool bExtrusionLightFace;
|
|
if ( rProp.Value >>= bExtrusionLightFace )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_LIGHT_FACE,
|
|
bExtrusionLightFace ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_FirstLightHarsh :
|
|
{
|
|
bool bExtrusionFirstLightHarsh;
|
|
if ( rProp.Value >>= bExtrusionFirstLightHarsh )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_HARSH,
|
|
bExtrusionFirstLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_SecondLightHarsh :
|
|
{
|
|
bool bExtrusionSecondLightHarsh;
|
|
if ( rProp.Value >>= bExtrusionSecondLightHarsh )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_HARSH,
|
|
bExtrusionSecondLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_FirstLightLevel :
|
|
{
|
|
double fExtrusionFirstLightLevel = 0;
|
|
if ( rProp.Value >>= fExtrusionFirstLightLevel )
|
|
{
|
|
fExtrusionFirstLightLevel =
|
|
std::clamp(fExtrusionFirstLightLevel, 0.0, 100.0);
|
|
::sax::Converter::convertDouble(
|
|
aStrBuffer,
|
|
fExtrusionFirstLightLevel,
|
|
false,
|
|
util::MeasureUnit::PERCENT,
|
|
util::MeasureUnit::PERCENT);
|
|
aStrBuffer.append( '%' );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_LEVEL, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_SecondLightLevel :
|
|
{
|
|
double fExtrusionSecondLightLevel = 0;
|
|
if ( rProp.Value >>= fExtrusionSecondLightLevel )
|
|
{
|
|
fExtrusionSecondLightLevel =
|
|
std::clamp(fExtrusionSecondLightLevel, 0.0, 100.0);
|
|
::sax::Converter::convertDouble(
|
|
aStrBuffer,
|
|
fExtrusionSecondLightLevel,
|
|
false,
|
|
util::MeasureUnit::PERCENT,
|
|
util::MeasureUnit::PERCENT);
|
|
aStrBuffer.append( '%' );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_LEVEL, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_FirstLightDirection :
|
|
{
|
|
drawing::Direction3D aExtrusionFirstLightDirection;
|
|
if ( rProp.Value >>= aExtrusionFirstLightDirection )
|
|
{
|
|
::basegfx::B3DVector aVec3D( aExtrusionFirstLightDirection.DirectionX, aExtrusionFirstLightDirection.DirectionY,
|
|
aExtrusionFirstLightDirection.DirectionZ );
|
|
SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_DIRECTION, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_SecondLightDirection :
|
|
{
|
|
drawing::Direction3D aExtrusionSecondLightDirection;
|
|
if ( rProp.Value >>= aExtrusionSecondLightDirection )
|
|
{
|
|
::basegfx::B3DVector aVec3D( aExtrusionSecondLightDirection.DirectionX, aExtrusionSecondLightDirection.DirectionY,
|
|
aExtrusionSecondLightDirection.DirectionZ );
|
|
SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_DIRECTION, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Metal :
|
|
{
|
|
bool bExtrusionMetal;
|
|
if ( rProp.Value >>= bExtrusionMetal )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL,
|
|
bExtrusionMetal ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_MetalType :
|
|
{
|
|
// In ODF since ODF 1.4. Before 1.4, export only in extended.
|
|
sal_Int16 eMetalType;
|
|
if (rProp.Value >>= eMetalType)
|
|
{
|
|
// LibreOffice had used the same values as later specified in ODF 1.4
|
|
if (eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible)
|
|
aStr = "loext:MetalMSCompatible";
|
|
else
|
|
aStr = "draw:MetalODF";
|
|
|
|
SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
|
|
if (eVersion >= SvtSaveOptions::ODFSVER_014)
|
|
{
|
|
if (!(eVersion & SvtSaveOptions::ODFSVER_EXTENDED)
|
|
&& eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible)
|
|
rExport.AddAttribute(XML_NAMESPACE_XMLNS, XML_NP_LO_EXT, XML_N_LO_EXT);
|
|
rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL_TYPE, aStr);
|
|
}
|
|
else if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)
|
|
{
|
|
rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_EXTRUSION_METAL_TYPE, aStr);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EAS_ShadeMode :
|
|
{
|
|
// shadeMode
|
|
drawing::ShadeMode eShadeMode;
|
|
if( rProp.Value >>= eShadeMode )
|
|
{
|
|
if( eShadeMode == drawing::ShadeMode_FLAT )
|
|
aStr = GetXMLToken( XML_FLAT );
|
|
else if( eShadeMode == drawing::ShadeMode_PHONG )
|
|
aStr = GetXMLToken( XML_PHONG );
|
|
else if( eShadeMode == drawing::ShadeMode_SMOOTH )
|
|
aStr = GetXMLToken( XML_GOURAUD );
|
|
else
|
|
aStr = GetXMLToken( XML_DRAFT );
|
|
}
|
|
else
|
|
{
|
|
// ShadeMode enum not there, write default
|
|
aStr = GetXMLToken( XML_FLAT);
|
|
}
|
|
rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr );
|
|
}
|
|
break;
|
|
case EAS_RotateAngle :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameterPair aRotateAngleParaPair;
|
|
if ( rProp.Value >>= aRotateAngleParaPair )
|
|
{
|
|
ExportParameter( aStrBuffer, aRotateAngleParaPair.First );
|
|
ExportParameter( aStrBuffer, aRotateAngleParaPair.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_ANGLE, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_RotationCenter :
|
|
{
|
|
drawing::Direction3D aExtrusionRotationCenter;
|
|
if ( rProp.Value >>= aExtrusionRotationCenter )
|
|
{
|
|
::basegfx::B3DVector aVec3D( aExtrusionRotationCenter.DirectionX, aExtrusionRotationCenter.DirectionY,
|
|
aExtrusionRotationCenter.DirectionZ );
|
|
SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_CENTER, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Shininess :
|
|
{
|
|
double fExtrusionShininess = 0;
|
|
if ( rProp.Value >>= fExtrusionShininess )
|
|
{
|
|
::sax::Converter::convertDouble(
|
|
aStrBuffer,
|
|
fExtrusionShininess,
|
|
false,
|
|
util::MeasureUnit::PERCENT,
|
|
util::MeasureUnit::PERCENT);
|
|
aStrBuffer.append( '%' );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SHININESS, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Skew :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair;
|
|
if ( rProp.Value >>= aSkewParaPair )
|
|
{
|
|
bSkewValuesProvided = true;
|
|
ExportParameter( aStrBuffer, aSkewParaPair.First );
|
|
ExportParameter( aStrBuffer, aSkewParaPair.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Specularity :
|
|
{
|
|
double fExtrusionSpecularity = 0;
|
|
if ( rProp.Value >>= fExtrusionSpecularity )
|
|
{
|
|
// ODF 1.0/1.1 allow arbitrary percent, ODF 1.2/1.3 restrict it to 0%-100%,
|
|
// ODF 1.4 restricts it to non negative percent.
|
|
SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
|
|
if (fExtrusionSpecularity > 100.0 && eVersion & SvtSaveOptions::ODFSVER_EXTENDED
|
|
&& eVersion >= SvtSaveOptions::ODFSVER_012 && eVersion < SvtSaveOptions::ODFSVER_014)
|
|
{
|
|
// tdf#147580 write values > 100% in loext
|
|
::sax::Converter::convertDouble(
|
|
aStrBuffer,
|
|
fExtrusionSpecularity,
|
|
false,
|
|
util::MeasureUnit::PERCENT,
|
|
util::MeasureUnit::PERCENT);
|
|
aStrBuffer.append( '%' );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_EXTRUSION_SPECULARITY_LOEXT, aStr );
|
|
}
|
|
// clamp fExtrusionSpecularity to allowed values
|
|
if (eVersion >= SvtSaveOptions::ODFSVER_012 && eVersion < SvtSaveOptions::ODFSVER_014)
|
|
fExtrusionSpecularity = std::clamp<double>(fExtrusionSpecularity, 0.0, 100.0);
|
|
else if (eVersion >= SvtSaveOptions::ODFSVER_014)
|
|
fExtrusionSpecularity = std::max<double>(0.0, fExtrusionSpecularity);
|
|
// write percent
|
|
::sax::Converter::convertDouble(
|
|
aStrBuffer,
|
|
fExtrusionSpecularity,
|
|
false,
|
|
util::MeasureUnit::PERCENT,
|
|
util::MeasureUnit::PERCENT);
|
|
aStrBuffer.append( '%' );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SPECULARITY, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_ProjectionMode :
|
|
{
|
|
drawing::ProjectionMode eProjectionMode;
|
|
if ( rProp.Value >>= eProjectionMode )
|
|
rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_PROJECTION,
|
|
eProjectionMode == drawing::ProjectionMode_PARALLEL ? GetXMLToken( XML_PARALLEL ) : GetXMLToken( XML_PERSPECTIVE ) );
|
|
}
|
|
break;
|
|
case EAS_ViewPoint :
|
|
{
|
|
drawing::Position3D aExtrusionViewPoint;
|
|
if ( rProp.Value >>= aExtrusionViewPoint )
|
|
{
|
|
rUnitConverter.convertPosition3D( aStrBuffer, aExtrusionViewPoint );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_VIEWPOINT, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Origin :
|
|
{
|
|
css::drawing::EnhancedCustomShapeParameterPair aOriginParaPair;
|
|
if ( rProp.Value >>= aOriginParaPair )
|
|
{
|
|
ExportParameter( aStrBuffer, aOriginParaPair.First );
|
|
ExportParameter( aStrBuffer, aOriginParaPair.Second );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ORIGIN, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Color :
|
|
{
|
|
bool bExtrusionColor;
|
|
if ( rProp.Value >>= bExtrusionColor )
|
|
{
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_COLOR,
|
|
bExtrusionColor ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
// tdf#141301: no specific skew values provided
|
|
if (!bSkewValuesProvided)
|
|
{
|
|
// so we need to export default values explicitly
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, u"50 -135"_ustr);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EAS_TextPath :
|
|
{
|
|
uno::Sequence< beans::PropertyValue > aTextPathPropSeq;
|
|
if ( rGeoProp.Value >>= aTextPathPropSeq )
|
|
{
|
|
for (const beans::PropertyValue& rProp : aTextPathPropSeq)
|
|
{
|
|
switch( EASGet( rProp.Name ) )
|
|
{
|
|
case EAS_TextPath :
|
|
{
|
|
bool bTextPathOn;
|
|
if ( rProp.Value >>= bTextPathOn )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH,
|
|
bTextPathOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_TextPathMode :
|
|
{
|
|
css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode;
|
|
if ( rProp.Value >>= eTextPathMode )
|
|
{
|
|
switch ( eTextPathMode )
|
|
{
|
|
case css::drawing::EnhancedCustomShapeTextPathMode_NORMAL: aStr = GetXMLToken( XML_NORMAL ); break;
|
|
case css::drawing::EnhancedCustomShapeTextPathMode_PATH : aStr = GetXMLToken( XML_PATH ); break;
|
|
case css::drawing::EnhancedCustomShapeTextPathMode_SHAPE : aStr = GetXMLToken( XML_SHAPE ); break;
|
|
default:
|
|
break;
|
|
}
|
|
if ( !aStr.isEmpty() )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_MODE, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_ScaleX :
|
|
{
|
|
bool bScaleX;
|
|
if ( rProp.Value >>= bScaleX )
|
|
{
|
|
aStr = bScaleX ? GetXMLToken( XML_SHAPE ) : GetXMLToken( XML_PATH );
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SCALE, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_SameLetterHeights :
|
|
{
|
|
bool bSameLetterHeights;
|
|
if ( rProp.Value >>= bSameLetterHeights )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SAME_LETTER_HEIGHTS,
|
|
bSameLetterHeights ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Path :
|
|
{
|
|
uno::Sequence< beans::PropertyValue > aPathPropSeq;
|
|
if ( rGeoProp.Value >>= aPathPropSeq )
|
|
{
|
|
for (const beans::PropertyValue& rProp : aPathPropSeq)
|
|
{
|
|
switch( EASGet( rProp.Name ) )
|
|
{
|
|
case EAS_SubViewSize:
|
|
{
|
|
// export draw:sub-view-size (do not export in ODF 1.3 or older)
|
|
if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
uno::Sequence< awt::Size > aSubViewSizes;
|
|
rProp.Value >>= aSubViewSizes;
|
|
|
|
for ( int nIdx = 0; nIdx < aSubViewSizes.getLength(); nIdx++ )
|
|
{
|
|
if ( nIdx )
|
|
aStrBuffer.append(' ');
|
|
aStrBuffer.append( aSubViewSizes[nIdx].Width );
|
|
aStrBuffer.append(' ');
|
|
aStrBuffer.append( aSubViewSizes[nIdx].Height );
|
|
}
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW_EXT, XML_SUB_VIEW_SIZE, aStr );
|
|
}
|
|
break;
|
|
case EAS_ExtrusionAllowed :
|
|
{
|
|
bool bExtrusionAllowed;
|
|
if ( rProp.Value >>= bExtrusionAllowed )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ALLOWED,
|
|
bExtrusionAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_ConcentricGradientFillAllowed :
|
|
{
|
|
bool bConcentricGradientFillAllowed;
|
|
if ( rProp.Value >>= bConcentricGradientFillAllowed )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONCENTRIC_GRADIENT_FILL_ALLOWED,
|
|
bConcentricGradientFillAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_TextPathAllowed :
|
|
{
|
|
bool bTextPathAllowed;
|
|
if ( rProp.Value >>= bTextPathAllowed )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_ALLOWED,
|
|
bTextPathAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
|
|
}
|
|
break;
|
|
case EAS_GluePoints :
|
|
{
|
|
css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> aGluePoints;
|
|
if ( rProp.Value >>= aGluePoints )
|
|
{
|
|
if ( aGluePoints.hasElements() )
|
|
{
|
|
for (const auto& rGluePoint : aGluePoints)
|
|
{
|
|
ExportParameter( aStrBuffer, rGluePoint.First );
|
|
ExportParameter( aStrBuffer, rGluePoint.Second );
|
|
}
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
}
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINTS, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_GluePointType :
|
|
{
|
|
sal_Int16 nGluePointType = sal_Int16();
|
|
if ( rProp.Value >>= nGluePointType )
|
|
{
|
|
switch ( nGluePointType )
|
|
{
|
|
case css::drawing::EnhancedCustomShapeGluePointType::NONE : aStr = GetXMLToken( XML_NONE ); break;
|
|
case css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS : aStr = GetXMLToken( XML_SEGMENTS ); break;
|
|
case css::drawing::EnhancedCustomShapeGluePointType::RECT : aStr = GetXMLToken( XML_RECTANGLE ); break;
|
|
}
|
|
if ( !aStr.isEmpty() )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINT_TYPE, aStr );
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Coordinates :
|
|
{
|
|
bCoordinates = ( rProp.Value >>= aCoordinates );
|
|
}
|
|
break;
|
|
case EAS_Segments :
|
|
{
|
|
rProp.Value >>= aSegments;
|
|
}
|
|
break;
|
|
case EAS_StretchX :
|
|
{
|
|
sal_Int32 nStretchPoint = 0;
|
|
if ( rProp.Value >>= nStretchPoint )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_X, OUString::number( nStretchPoint ) );
|
|
}
|
|
break;
|
|
case EAS_StretchY :
|
|
{
|
|
sal_Int32 nStretchPoint = 0;
|
|
if ( rProp.Value >>= nStretchPoint )
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_Y, OUString::number( nStretchPoint ) );
|
|
}
|
|
break;
|
|
case EAS_TextFrames :
|
|
{
|
|
css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aPathTextFrames;
|
|
if ( rProp.Value >>= aPathTextFrames )
|
|
{
|
|
if ( aPathTextFrames.hasElements() )
|
|
{
|
|
for (const auto& rPathTextFrame : aPathTextFrames)
|
|
{
|
|
ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.First );
|
|
ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.Second );
|
|
ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.First );
|
|
ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.Second );
|
|
}
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
}
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_AREAS, aStr );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EAS_Equations :
|
|
{
|
|
bEquations = ( rGeoProp.Value >>= aEquations );
|
|
}
|
|
break;
|
|
case EAS_Handles :
|
|
{
|
|
bHandles = ( rGeoProp.Value >>= aHandles );
|
|
}
|
|
break;
|
|
case EAS_AdjustmentValues :
|
|
{
|
|
rGeoProp.Value >>= aAdjustmentValues;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} // for
|
|
|
|
// ToDo: Where is TextPreRotateAngle still used? We cannot save it in ODF.
|
|
fTextRotateAngle += fTextPreRotateAngle;
|
|
// Workaround for writing-mode bt-lr and tb-rl90 in ODF strict,
|
|
// otherwise loext:writing-mode is used in style export.
|
|
if (!(rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
|
|
{
|
|
if (xPropSetInfo->hasPropertyByName(u"WritingMode"_ustr))
|
|
{
|
|
sal_Int16 nDirection = -1;
|
|
xPropSet->getPropertyValue(u"WritingMode"_ustr) >>= nDirection;
|
|
if (nDirection == text::WritingMode2::TB_RL90)
|
|
fTextRotateAngle -= 90;
|
|
else if (nDirection == text::WritingMode2::BT_LR)
|
|
fTextRotateAngle -= 270;
|
|
}
|
|
}
|
|
if (fTextRotateAngle != 0)
|
|
{
|
|
::sax::Converter::convertDouble( aStrBuffer, fTextRotateAngle );
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_ROTATE_ANGLE, aStr );
|
|
}
|
|
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TYPE, aCustomShapeType );
|
|
|
|
// adjustments
|
|
sal_Int32 nAdjustmentValues = aAdjustmentValues.getLength();
|
|
if ( nAdjustmentValues )
|
|
{
|
|
sal_Int32 i, nValue = 0;
|
|
for ( i = 0; i < nAdjustmentValues; i++ )
|
|
{
|
|
if ( i )
|
|
aStrBuffer.append( ' ' );
|
|
|
|
const css::drawing::EnhancedCustomShapeAdjustmentValue& rAdj = aAdjustmentValues[ i ];
|
|
if ( rAdj.State == beans::PropertyState_DIRECT_VALUE )
|
|
{
|
|
if ( rAdj.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
|
|
{
|
|
double fValue = 0.0;
|
|
rAdj.Value >>= fValue;
|
|
::sax::Converter::convertDouble(aStrBuffer, fValue);
|
|
}
|
|
else
|
|
{
|
|
rAdj.Value >>= nValue;
|
|
aStrBuffer.append(nValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this should not be, but better than setting nothing
|
|
aStrBuffer.append("0");
|
|
}
|
|
}
|
|
aStr = aStrBuffer.makeStringAndClear();
|
|
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MODIFIERS, aStr );
|
|
}
|
|
if ( bCoordinates )
|
|
ImpExportEnhancedPath( rExport, aCoordinates, aSegments );
|
|
}
|
|
}
|
|
SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_ENHANCED_GEOMETRY, true, true );
|
|
if ( bEquations )
|
|
ImpExportEquations( rExport, aEquations );
|
|
if ( bHandles )
|
|
ImpExportHandles( rExport, aHandles );
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportCustomShape(
|
|
const uno::Reference< drawing::XShape >& xShape,
|
|
XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
|
|
{
|
|
const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
if ( !xPropSet.is() )
|
|
return;
|
|
|
|
uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
|
|
|
|
// Transformation
|
|
ImpExportNewTrans( xPropSet, nFeatures, pRefPoint );
|
|
|
|
if ( xPropSetInfo.is() )
|
|
{
|
|
OUString aStr;
|
|
if ( xPropSetInfo->hasPropertyByName( u"CustomShapeEngine"_ustr ) )
|
|
{
|
|
uno::Any aEngine( xPropSet->getPropertyValue( u"CustomShapeEngine"_ustr ) );
|
|
if ( ( aEngine >>= aStr ) && !aStr.isEmpty() )
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ENGINE, aStr );
|
|
}
|
|
if ( xPropSetInfo->hasPropertyByName( u"CustomShapeData"_ustr ) )
|
|
{
|
|
uno::Any aData( xPropSet->getPropertyValue( u"CustomShapeData"_ustr ) );
|
|
if ( ( aData >>= aStr ) && !aStr.isEmpty() )
|
|
mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DATA, aStr );
|
|
}
|
|
}
|
|
bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
|
|
SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, bCreateNewline, true );
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
ImpExportText( xShape );
|
|
ImpExportEnhancedGeometry( mrExport, xPropSet );
|
|
|
|
}
|
|
|
|
void XMLShapeExport::ImpExportTableShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
|
|
{
|
|
uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
|
|
uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
|
|
|
|
SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "xmloff::XMLShapeExport::ImpExportTableShape(), table shape is not implementing needed interfaces");
|
|
if(!(xPropSet.is() && xNamed.is()))
|
|
return;
|
|
|
|
try
|
|
{
|
|
// Transformation
|
|
ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
|
|
|
|
bool bIsEmptyPresObj = false;
|
|
|
|
// presentation settings
|
|
if(eShapeType == XmlShapeType::PresTableShape)
|
|
bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
|
|
|
|
const bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE );
|
|
|
|
SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, XML_FRAME, bCreateNewline, true );
|
|
|
|
// do not export in ODF 1.1 or older
|
|
if (mrExport.getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
|
|
{
|
|
if( !bIsEmptyPresObj )
|
|
{
|
|
uno::Reference< container::XNamed > xTemplate( xPropSet->getPropertyValue(u"TableTemplate"_ustr), uno::UNO_QUERY );
|
|
if( xTemplate.is() )
|
|
{
|
|
const OUString sTemplate( xTemplate->getName() );
|
|
if( !sTemplate.isEmpty() )
|
|
{
|
|
mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TEMPLATE_NAME, sTemplate );
|
|
|
|
for( const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; !pEntry->IsEnd(); pEntry++ )
|
|
{
|
|
try
|
|
{
|
|
bool bBool = false;
|
|
xPropSet->getPropertyValue( pEntry->getApiName() ) >>= bBool;
|
|
if( bBool )
|
|
mrExport.AddAttribute(pEntry->mnNameSpace, pEntry->meXMLName, XML_TRUE );
|
|
}
|
|
catch( uno::Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("xmloff.draw");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
|
|
GetShapeTableExport()->exportTable( xRange );
|
|
}
|
|
}
|
|
|
|
if (!bIsEmptyPresObj
|
|
&& officecfg::Office::Common::Save::Graphic::AddReplacementImages::get())
|
|
{
|
|
uno::Reference< graphic::XGraphic > xGraphic( xPropSet->getPropertyValue(u"ReplacementGraphic"_ustr), uno::UNO_QUERY );
|
|
ExportGraphicPreview(xGraphic, mrExport, u"TablePreview", u".svm", u"image/x-vclgraphic"_ustr);
|
|
}
|
|
|
|
ImpExportEvents( xShape );
|
|
ImpExportGluePoints( xShape );
|
|
ImpExportDescription( xShape ); // #i68101#
|
|
}
|
|
catch( uno::Exception const & )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("xmloff.draw");
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|