/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include "oox/core/xmlfilterbase.hxx" #include "oox/export/shapes.hxx" #include "oox/export/utils.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::css; using namespace ::css::beans; using namespace ::css::uno; using namespace ::css::drawing; using namespace ::css::i18n; using namespace ::css::table; using namespace ::css::container; using namespace ::css::document; using namespace ::css::text; using ::css::graphic::XGraphic; using ::css::io::XOutputStream; using ::css::lang::XComponent; using ::css::chart2::XChartDocument; using ::css::frame::XModel; using ::css::sheet::XSpreadsheetDocument; using ::oox::core::XmlFilterBase; using ::sax_fastparser::FSHelperPtr; #define IDS(x) OString(OStringLiteral(#x " ") + OString::number( mnShapeIdMax++ )).getStr() namespace oox { namespace drawingml { #define GETA(propName) \ GetProperty( rXPropSet, OUString(#propName)) #define GETAD(propName) \ ( GetPropertyAndState( rXPropSet, rXPropState, OUString(#propName), eState ) && eState == beans::PropertyState_DIRECT_VALUE ) #define GET(variable, propName) \ if ( GETA(propName) ) \ mAny >>= variable; // not thread safe int ShapeExport::mnSpreadsheetCounter = 1; ShapeExport::ShapeExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, ShapeHashMap* pShapeMap, XmlFilterBase* pFB, DocumentType eDocumentType, DMLTextExport* pTextExport ) : DrawingML( pFS, pFB, eDocumentType, pTextExport ) , mnShapeIdMax( 1 ) , mnPictureIdMax( 1 ) , mnXmlNamespace( nXmlNamespace ) , maFraction( 1, 576 ) , maMapModeSrc( MAP_100TH_MM ) , maMapModeDest( MAP_INCH, Point(), maFraction, maFraction ) , mpShapeMap( pShapeMap ? pShapeMap : &maShapeMap ) { } awt::Size ShapeExport::MapSize( const awt::Size& rSize ) const { Size aRetSize( OutputDevice::LogicToLogic( Size( rSize.Width, rSize.Height ), maMapModeSrc, maMapModeDest ) ); if ( !aRetSize.Width() ) aRetSize.Width()++; if ( !aRetSize.Height() ) aRetSize.Height()++; return awt::Size( aRetSize.Width(), aRetSize.Height() ); } bool ShapeExport::NonEmptyText( Reference< XInterface > xIface ) { Reference< XPropertySet > xPropSet( xIface, UNO_QUERY ); if( xPropSet.is() ) { Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); if ( xPropSetInfo.is() ) { if ( xPropSetInfo->hasPropertyByName( "IsEmptyPresentationObject" ) ) { bool bIsEmptyPresObj = false; if ( xPropSet->getPropertyValue( "IsEmptyPresentationObject" ) >>= bIsEmptyPresObj ) { DBG(fprintf(stderr, "empty presentation object %d, props:\n", bIsEmptyPresObj)); if( bIsEmptyPresObj ) return true; } } if ( xPropSetInfo->hasPropertyByName( "IsPresentationObject" ) ) { bool bIsPresObj = false; if ( xPropSet->getPropertyValue( "IsPresentationObject" ) >>= bIsPresObj ) { DBG(fprintf(stderr, "presentation object %d, props:\n", bIsPresObj)); if( bIsPresObj ) return true; } } } } Reference< XSimpleText > xText( xIface, UNO_QUERY ); if( xText.is() ) return xText->getString().getLength(); return false; } ShapeExport& ShapeExport::WriteBezierShape( Reference< XShape > xShape, bool bClosed ) { DBG(fprintf(stderr, "write open bezier shape\n")); FSHelperPtr pFS = GetFS(); pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND ); tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon( xShape ); Rectangle aRect( aPolyPolygon.GetBoundRect() ); #if OSL_DEBUG_LEVEL > 0 awt::Size size = MapSize( awt::Size( aRect.GetWidth(), aRect.GetHeight() ) ); DBG(fprintf(stderr, "poly count %d\nsize: %d x %d", aPolyPolygon.Count(), int( size.Width ), int( size.Height ))); #endif // non visual shape properties if (GetDocumentType() != DOCUMENT_DOCX) { pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, IDS( Freeform ), FSEND ); } pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND ); if (GetDocumentType() != DOCUMENT_DOCX) { WriteNonVisualProperties( xShape ); pFS->endElementNS( mnXmlNamespace, XML_nvSpPr ); } // visual shape properties pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND ); WriteTransformation( aRect, XML_a ); WritePolyPolygon( aPolyPolygon ); Reference< XPropertySet > xProps( xShape, UNO_QUERY ); if( xProps.is() ) { if( bClosed ) WriteFill( xProps ); WriteOutline( xProps ); } pFS->endElementNS( mnXmlNamespace, XML_spPr ); // write text WriteTextBox( xShape, mnXmlNamespace ); pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) ); return *this; } ShapeExport& ShapeExport::WriteClosedBezierShape( Reference< XShape > xShape ) { return WriteBezierShape( xShape, true ); } ShapeExport& ShapeExport::WriteOpenBezierShape( Reference< XShape > xShape ) { return WriteBezierShape( xShape, false ); } ShapeExport& ShapeExport::WriteGroupShape(uno::Reference xShape) { FSHelperPtr pFS = GetFS(); bool bToplevel = !m_xParent.is(); if (!bToplevel) mnXmlNamespace = XML_wpg; pFS->startElementNS(mnXmlNamespace, (bToplevel ? XML_wgp : XML_grpSp), FSEND); // non visual properties pFS->singleElementNS(mnXmlNamespace, XML_cNvGrpSpPr, FSEND); // visual properties pFS->startElementNS(mnXmlNamespace, XML_grpSpPr, FSEND); WriteShapeTransformation(xShape, XML_a); pFS->endElementNS(mnXmlNamespace, XML_grpSpPr); uno::Reference xGroupShape(xShape, uno::UNO_QUERY_THROW); uno::Reference xParent = m_xParent; m_xParent = xShape; for (sal_Int32 i = 0; i < xGroupShape->getCount(); ++i) { uno::Reference xChild(xGroupShape->getByIndex(i), uno::UNO_QUERY_THROW); sal_Int32 nSavedNamespace = mnXmlNamespace; uno::Reference xServiceInfo(xChild, uno::UNO_QUERY_THROW); if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape")) mnXmlNamespace = XML_pic; else mnXmlNamespace = XML_wps; WriteShape(xChild); mnXmlNamespace = nSavedNamespace; } m_xParent = xParent; pFS->endElementNS(mnXmlNamespace, (bToplevel ? XML_wgp : XML_grpSp)); return *this; } ShapeExport& ShapeExport::WriteCustomShape( Reference< XShape > xShape ) { DBG(fprintf(stderr, "write custom shape\n")); Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY ); bool bPredefinedHandlesUsed = true; OUString sShapeType; sal_uInt32 nMirrorFlags = 0; MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( xShape, nMirrorFlags, sShapeType ); SdrObjCustomShape* pShape = (SdrObjCustomShape*) GetSdrObjectFromXShape( xShape ); bool bIsDefaultObject = EscherPropertyContainer::IsDefaultObject( pShape, eShapeType ); const char* sPresetShape = msfilter::util::GetOOXMLPresetGeometry( USS( sShapeType ) ); DBG(fprintf(stderr, "custom shape type: %s ==> %s\n", USS( sShapeType ), sPresetShape)); Sequence< PropertyValue > aGeometrySeq; sal_Int32 nAdjustmentValuesIndex = -1; bool bFlipH = false; bool bFlipV = false; if( GETA( CustomShapeGeometry ) ) { DBG(fprintf(stderr, "got custom shape geometry\n")); if( mAny >>= aGeometrySeq ) { DBG(fprintf(stderr, "got custom shape geometry sequence\n")); for( int i = 0; i < aGeometrySeq.getLength(); i++ ) { const PropertyValue& rProp = aGeometrySeq[ i ]; DBG(fprintf(stderr, "geometry property: %s\n", USS( rProp.Name ))); if ( rProp.Name == "MirroredX" ) rProp.Value >>= bFlipH; if ( rProp.Name == "MirroredY" ) rProp.Value >>= bFlipV; if ( rProp.Name == "AdjustmentValues" ) nAdjustmentValuesIndex = i; else if ( rProp.Name == "Handles" ) { if( !bIsDefaultObject ) bPredefinedHandlesUsed = false; // TODO: update nAdjustmentsWhichNeedsToBeConverted here } else if ( rProp.Name == "PresetTextWarp" ) { rProp.Value >>= m_presetWarp; } } } } FSHelperPtr pFS = GetFS(); pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND ); // non visual shape properties if (GetDocumentType() != DOCUMENT_DOCX) { pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, IDS( CustomShape ), FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND ); WriteNonVisualProperties( xShape ); pFS->endElementNS( mnXmlNamespace, XML_nvSpPr ); } else pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, FSEND); // visual shape properties pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND ); WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, false); if( sShapeType == "ooxml-non-primitive" ) // non-primitiv -> custom geometry { WritePolyPolygon( EscherPropertyContainer::GetPolyPolygon( xShape ) ); } else // preset geometry { if( nAdjustmentValuesIndex != -1 ) { sal_Int32 nAdjustmentsWhichNeedsToBeConverted = 0; WritePresetShape( sPresetShape, eShapeType, bPredefinedHandlesUsed, nAdjustmentsWhichNeedsToBeConverted, aGeometrySeq[ nAdjustmentValuesIndex ] ); } else WritePresetShape( sPresetShape ); } if( rXPropSet.is() ) { WriteFill( rXPropSet ); WriteOutline( rXPropSet ); WriteShapeEffects( rXPropSet ); WriteShape3DEffects( rXPropSet ); } pFS->endElementNS( mnXmlNamespace, XML_spPr ); pFS->startElementNS( mnXmlNamespace, XML_style, FSEND ); WriteShapeStyle( rXPropSet ); pFS->endElementNS( mnXmlNamespace, XML_style ); // write text WriteTextBox( xShape, mnXmlNamespace ); pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) ); return *this; } ShapeExport& ShapeExport::WriteEllipseShape( Reference< XShape > xShape ) { DBG(fprintf(stderr, "write ellipse shape\n")); FSHelperPtr pFS = GetFS(); pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND ); // TODO: arc, section, cut, connector // non visual shape properties if (GetDocumentType() != DOCUMENT_DOCX) { pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, IDS( Ellipse ), FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND ); WriteNonVisualProperties( xShape ); pFS->endElementNS( mnXmlNamespace, XML_nvSpPr ); } else pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, FSEND); // visual shape properties pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND ); WriteShapeTransformation( xShape, XML_a, false, false, false); WritePresetShape( "ellipse" ); Reference< XPropertySet > xProps( xShape, UNO_QUERY ); if( xProps.is() ) { WriteFill( xProps ); WriteOutline( xProps ); } pFS->endElementNS( mnXmlNamespace, XML_spPr ); // write text WriteTextBox( xShape, mnXmlNamespace ); pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) ); return *this; } ShapeExport& ShapeExport::WriteGraphicObjectShape( Reference< XShape > xShape ) { WriteGraphicObjectShapePart( xShape ); return *this; } void ShapeExport::WriteGraphicObjectShapePart( Reference< XShape > xShape, const Graphic* pGraphic ) { DBG(fprintf(stderr, "write graphic object shape\n")); if( NonEmptyText( xShape ) ) { // avoid treating all 'IsPresentationObject' objects as having text. Reference< XSimpleText > xText( xShape, UNO_QUERY ); if( xText.is() && xText->getString().getLength() ) { DBG(fprintf(stderr, "graphicObject: wrote only text\n")); WriteTextShape( xShape ); //DBG(dump_pset(mXPropSet)); return; } } DBG(fprintf(stderr, "graphicObject without text\n")); OUString sGraphicURL; Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY ); if( !pGraphic && ( !xShapeProps.is() || !( xShapeProps->getPropertyValue( "GraphicURL" ) >>= sGraphicURL ) ) ) { DBG(fprintf(stderr, "no graphic URL found\n")); return; } FSHelperPtr pFS = GetFS(); if (GetDocumentType() != DOCUMENT_DOCX) pFS->startElementNS( mnXmlNamespace, XML_pic, FSEND ); else pFS->startElementNS( mnXmlNamespace, XML_pic, FSNS(XML_xmlns, XML_pic), "http://schemas.openxmlformats.org/drawingml/2006/picture", FSEND ); pFS->startElementNS( mnXmlNamespace, XML_nvPicPr, FSEND ); OUString sName, sDescr; bool bHaveName, bHaveDesc; if ( ( bHaveName= GetProperty( xShapeProps, "Name" ) ) ) mAny >>= sName; if ( ( bHaveDesc = GetProperty( xShapeProps, "Description" ) ) ) mAny >>= sDescr; pFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, bHaveName ? USS( sName ) : OString( "Picture " + OString::number( mnPictureIdMax++ )).getStr(), XML_descr, bHaveDesc ? USS( sDescr ) : NULL, FSEND ); // OOXTODO: //cNvPr children: XML_extLst, XML_hlinkClick, XML_hlinkHover pFS->singleElementNS( mnXmlNamespace, XML_cNvPicPr, // OOXTODO: XML_preferRelativeSize FSEND ); WriteNonVisualProperties( xShape ); pFS->endElementNS( mnXmlNamespace, XML_nvPicPr ); pFS->startElementNS( mnXmlNamespace, XML_blipFill, FSEND ); WriteBlip( xShapeProps, sGraphicURL, false, pGraphic ); WriteSrcRect( xShapeProps, sGraphicURL ); // now we stretch always when we get pGraphic (when changing that // behavior, test n#780830 for regression, where the OLE sheet might get tiled bool bStretch = false; if( !pGraphic && GetProperty( xShapeProps, "FillBitmapStretch" ) ) mAny >>= bStretch; if ( pGraphic || bStretch ) pFS->singleElementNS( XML_a, XML_stretch, FSEND ); pFS->endElementNS( mnXmlNamespace, XML_blipFill ); // visual shape properties pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND ); WriteShapeTransformation( xShape, XML_a, false, false, false); WritePresetShape( "rect" ); // graphic object can come with the frame (bnc#654525) WriteOutline( xShapeProps ); WriteShapeEffects( xShapeProps ); WriteShape3DEffects( xShapeProps ); pFS->endElementNS( mnXmlNamespace, XML_spPr ); pFS->endElementNS( mnXmlNamespace, XML_pic ); } ShapeExport& ShapeExport::WriteConnectorShape( Reference< XShape > xShape ) { bool bFlipH = false; bool bFlipV = false; DBG(fprintf(stderr, "write connector shape\n")); FSHelperPtr pFS = GetFS(); const char* sGeometry = "line"; Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY ); Reference< XPropertyState > rXPropState( xShape, UNO_QUERY ); awt::Point aStartPoint, aEndPoint; Reference< XShape > rXShapeA; Reference< XShape > rXShapeB; PropertyState eState; ConnectorType eConnectorType; if( GETAD( EdgeKind ) ) { mAny >>= eConnectorType; switch( eConnectorType ) { case ConnectorType_CURVE: sGeometry = "curvedConnector3"; break; case ConnectorType_STANDARD: sGeometry = "bentConnector3"; break; default: case ConnectorType_LINE: case ConnectorType_LINES: sGeometry = "straightConnector1"; break; } if( GETAD( EdgeStartPoint ) ) { mAny >>= aStartPoint; if( GETAD( EdgeEndPoint ) ) { mAny >>= aEndPoint; } } GET( rXShapeA, EdgeStartConnection ); GET( rXShapeB, EdgeEndConnection ); } EscherConnectorListEntry aConnectorEntry( xShape, aStartPoint, rXShapeA, aEndPoint, rXShapeB ); Rectangle aRect( Point( aStartPoint.X, aStartPoint.Y ), Point( aEndPoint.X, aEndPoint.Y ) ); if( aRect.getWidth() < 0 ) { bFlipH = true; aRect.setX( aEndPoint.X ); aRect.setWidth( aStartPoint.X - aEndPoint.X ); } if( aRect.getHeight() < 0 ) { bFlipV = true; aRect.setY( aEndPoint.Y ); aRect.setHeight( aStartPoint.Y - aEndPoint.Y ); } pFS->startElementNS( mnXmlNamespace, XML_cxnSp, FSEND ); // non visual shape properties pFS->startElementNS( mnXmlNamespace, XML_nvCxnSpPr, FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, IDS( Line ), FSEND ); // non visual connector shape drawing properties pFS->startElementNS( mnXmlNamespace, XML_cNvCxnSpPr, FSEND ); WriteConnectorConnections( aConnectorEntry, GetShapeID( rXShapeA ), GetShapeID( rXShapeB ) ); pFS->endElementNS( mnXmlNamespace, XML_cNvCxnSpPr ); pFS->singleElementNS( mnXmlNamespace, XML_nvPr, FSEND ); pFS->endElementNS( mnXmlNamespace, XML_nvCxnSpPr ); // visual shape properties pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND ); WriteTransformation( aRect, XML_a, bFlipH, bFlipV ); // TODO: write adjustments (ppt export doesn't work well there either) WritePresetShape( sGeometry ); Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY ); if( xShapeProps.is() ) WriteOutline( xShapeProps ); pFS->endElementNS( mnXmlNamespace, XML_spPr ); // write text WriteTextBox( xShape, mnXmlNamespace ); pFS->endElementNS( mnXmlNamespace, XML_cxnSp ); return *this; } ShapeExport& ShapeExport::WriteLineShape( Reference< XShape > xShape ) { bool bFlipH = false; bool bFlipV = false; DBG(fprintf(stderr, "write line shape\n")); FSHelperPtr pFS = GetFS(); pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND ); tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon( xShape ); if( aPolyPolygon.Count() == 1 && aPolyPolygon[ 0 ].GetSize() == 2) { const Polygon& rPoly = aPolyPolygon[ 0 ]; bFlipH = ( rPoly[ 0 ].X() > rPoly[ 1 ].X() ); bFlipV = ( rPoly[ 0 ].Y() > rPoly[ 1 ].Y() ); } // non visual shape properties if (GetDocumentType() != DOCUMENT_DOCX) { pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, IDS( Line ), FSEND ); } pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND ); if (GetDocumentType() != DOCUMENT_DOCX) { WriteNonVisualProperties( xShape ); pFS->endElementNS( mnXmlNamespace, XML_nvSpPr ); } // visual shape properties pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND ); WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, true); WritePresetShape( "line" ); Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY ); if( xShapeProps.is() ) WriteOutline( xShapeProps ); pFS->endElementNS( mnXmlNamespace, XML_spPr ); // write text WriteTextBox( xShape, mnXmlNamespace ); pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) ); return *this; } ShapeExport& ShapeExport::WriteNonVisualDrawingProperties( Reference< XShape > xShape, const char* pName ) { GetFS()->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, pName, FSEND ); return *this; } ShapeExport& ShapeExport::WriteNonVisualProperties( Reference< XShape > ) { // Override to generate //nvPr elements. return *this; } ShapeExport& ShapeExport::WriteRectangleShape( Reference< XShape > xShape ) { DBG(fprintf(stderr, "write rectangle shape\n")); FSHelperPtr pFS = GetFS(); pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND ); sal_Int32 nRadius = 0; Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY ); if( xShapeProps.is() ) { xShapeProps->getPropertyValue( "CornerRadius" ) >>= nRadius; } if( nRadius ) { nRadius = MapSize( awt::Size( nRadius, 0 ) ).Width; } // non visual shape properties if (GetDocumentType() == DOCUMENT_DOCX) pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND ); pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, IDS( Rectangle ), FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, FSEND ); WriteNonVisualProperties( xShape ); pFS->endElementNS( mnXmlNamespace, XML_nvSpPr ); // visual shape properties pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND ); WriteShapeTransformation( xShape, XML_a, false, false, false); WritePresetShape( "rect" ); Reference< XPropertySet > xProps( xShape, UNO_QUERY ); if( xProps.is() ) { WriteFill( xProps ); WriteOutline( xProps ); } pFS->endElementNS( mnXmlNamespace, XML_spPr ); // write text WriteTextBox( xShape, mnXmlNamespace ); pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) ); return *this; } typedef ShapeExport& (ShapeExport::*ShapeConverter)( Reference< XShape > ); typedef boost::unordered_map< const char*, ShapeConverter, rtl::CStringHash, rtl::CStringEqual> NameToConvertMapType; static const NameToConvertMapType& lcl_GetConverters(DrawingML::DocumentType eDocumentType) { static bool shape_map_inited = false; static NameToConvertMapType shape_converters; if( shape_map_inited ) { return shape_converters; } shape_converters[ "com.sun.star.drawing.ClosedBezierShape" ] = &ShapeExport::WriteClosedBezierShape; shape_converters[ "com.sun.star.drawing.ConnectorShape" ] = &ShapeExport::WriteConnectorShape; shape_converters[ "com.sun.star.drawing.CustomShape" ] = &ShapeExport::WriteCustomShape; shape_converters[ "com.sun.star.drawing.EllipseShape" ] = &ShapeExport::WriteEllipseShape; shape_converters[ "com.sun.star.drawing.GraphicObjectShape" ] = &ShapeExport::WriteGraphicObjectShape; shape_converters[ "com.sun.star.drawing.LineShape" ] = &ShapeExport::WriteLineShape; shape_converters[ "com.sun.star.drawing.OpenBezierShape" ] = &ShapeExport::WriteOpenBezierShape; shape_converters[ "com.sun.star.drawing.RectangleShape" ] = &ShapeExport::WriteRectangleShape; shape_converters[ "com.sun.star.drawing.OLE2Shape" ] = &ShapeExport::WriteOLE2Shape; shape_converters[ "com.sun.star.drawing.TableShape" ] = &ShapeExport::WriteTableShape; shape_converters[ "com.sun.star.drawing.TextShape" ] = &ShapeExport::WriteTextShape; shape_converters[ "com.sun.star.presentation.GraphicObjectShape" ] = &ShapeExport::WriteGraphicObjectShape; shape_converters[ "com.sun.star.presentation.OLE2Shape" ] = &ShapeExport::WriteOLE2Shape; shape_converters[ "com.sun.star.presentation.TableShape" ] = &ShapeExport::WriteTableShape; shape_converters[ "com.sun.star.presentation.TextShape" ] = &ShapeExport::WriteTextShape; shape_converters[ "com.sun.star.presentation.DateTimeShape" ] = &ShapeExport::WriteTextShape; shape_converters[ "com.sun.star.presentation.FooterShape" ] = &ShapeExport::WriteTextShape; shape_converters[ "com.sun.star.presentation.HeaderShape" ] = &ShapeExport::WriteTextShape; shape_converters[ "com.sun.star.presentation.NotesShape" ] = &ShapeExport::WriteTextShape; shape_converters[ "com.sun.star.presentation.OutlinerShape" ] = &ShapeExport::WriteTextShape; shape_converters[ "com.sun.star.presentation.SlideNumberShape" ] = &ShapeExport::WriteTextShape; shape_converters[ "com.sun.star.presentation.TitleTextShape" ] = &ShapeExport::WriteTextShape; if (eDocumentType == DrawingML::DOCUMENT_DOCX) shape_converters[ "com.sun.star.drawing.GroupShape" ] = &ShapeExport::WriteGroupShape; shape_map_inited = true; return shape_converters; } ShapeExport& ShapeExport::WriteShape( Reference< XShape > xShape ) { OUString sShapeType = xShape->getShapeType(); DBG( fprintf( stderr, "write shape: %s\n", USS( sShapeType ) ) ); NameToConvertMapType::const_iterator aConverter = lcl_GetConverters(GetDocumentType()).find( USS( sShapeType ) ); if( aConverter == lcl_GetConverters(GetDocumentType()).end() ) { DBG( fprintf( stderr, "unknown shape\n" ) ); return WriteUnknownShape( xShape ); } (this->*(aConverter->second))( xShape ); return *this; } ShapeExport& ShapeExport::WriteTextBox( Reference< XInterface > xIface, sal_Int32 nXmlNamespace ) { // In case this shape has an associated textbox, then export that, and we're done. if (GetDocumentType() == DOCUMENT_DOCX && GetTextExport()) { uno::Reference xPropertySet(xIface, uno::UNO_QUERY); if (xPropertySet.is()) { uno::Reference xPropertySetInfo = xPropertySet->getPropertySetInfo(); if (xPropertySetInfo->hasPropertyByName("TextBox") && xPropertySet->getPropertyValue("TextBox").get()) { GetTextExport()->WriteTextBox(uno::Reference(xIface, uno::UNO_QUERY_THROW)); WriteText( xIface, m_presetWarp, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace ); return *this; } } } if( NonEmptyText( xIface ) ) { FSHelperPtr pFS = GetFS(); pFS->startElementNS( nXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_txBody : XML_txbx), FSEND ); WriteText( xIface, m_presetWarp, /*bBodyPr=*/(GetDocumentType() != DOCUMENT_DOCX), /*bText=*/true ); pFS->endElementNS( nXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_txBody : XML_txbx) ); if (GetDocumentType() == DOCUMENT_DOCX) WriteText( xIface, m_presetWarp, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace ); } else if (GetDocumentType() == DOCUMENT_DOCX) mpFS->singleElementNS(nXmlNamespace, XML_bodyPr, FSEND); return *this; } void ShapeExport::WriteTable( Reference< XShape > rXShape ) { OSL_TRACE("write table"); Reference< XTable > xTable; Reference< XPropertySet > xPropSet( rXShape, UNO_QUERY ); mpFS->startElementNS( XML_a, XML_graphic, FSEND ); mpFS->startElementNS( XML_a, XML_graphicData, XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/table", FSEND ); if ( xPropSet.is() && ( xPropSet->getPropertyValue( "Model" ) >>= xTable ) ) { mpFS->startElementNS( XML_a, XML_tbl, FSEND ); mpFS->singleElementNS( XML_a, XML_tblPr, FSEND ); Reference< container::XIndexAccess > xColumns( xTable->getColumns(), UNO_QUERY_THROW ); Reference< container::XIndexAccess > xRows( xTable->getRows(), UNO_QUERY_THROW ); sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() ); sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() ); mpFS->startElementNS( XML_a, XML_tblGrid, FSEND ); for ( sal_Int32 x = 0; x < nColumnCount; x++ ) { Reference< XPropertySet > xColPropSet( xColumns->getByIndex( x ), UNO_QUERY_THROW ); sal_Int32 nWidth(0); xColPropSet->getPropertyValue( "Width" ) >>= nWidth; mpFS->singleElementNS( XML_a, XML_gridCol, XML_w, I64S(MM100toEMU(nWidth)), FSEND ); } mpFS->endElementNS( XML_a, XML_tblGrid ); for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ ) { Reference< XPropertySet > xRowPropSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW ); sal_Int32 nRowHeight(0); xRowPropSet->getPropertyValue( "Height" ) >>= nRowHeight; mpFS->startElementNS( XML_a, XML_tr, XML_h, I64S( MM100toEMU( nRowHeight ) ), FSEND ); for( sal_Int32 nColumn = 0; nColumn < nColumnCount; nColumn++ ) { Reference< XMergeableCell > xCell( xTable->getCellByPosition( nColumn, nRow ), UNO_QUERY_THROW ); if ( !xCell->isMerged() ) { mpFS->startElementNS( XML_a, XML_tc, FSEND ); WriteTextBox( xCell, XML_a ); mpFS->singleElementNS( XML_a, XML_tcPr, FSEND ); mpFS->endElementNS( XML_a, XML_tc ); } } mpFS->endElementNS( XML_a, XML_tr ); } mpFS->endElementNS( XML_a, XML_tbl ); } mpFS->endElementNS( XML_a, XML_graphicData ); mpFS->endElementNS( XML_a, XML_graphic ); } ShapeExport& ShapeExport::WriteTableShape( Reference< XShape > xShape ) { FSHelperPtr pFS = GetFS(); OSL_TRACE("write table shape"); pFS->startElementNS( mnXmlNamespace, XML_graphicFrame, FSEND ); pFS->startElementNS( mnXmlNamespace, XML_nvGraphicFramePr, FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, IDS(Table), FSEND ); pFS->singleElementNS( mnXmlNamespace, XML_cNvGraphicFramePr, FSEND ); if( GetDocumentType() == DOCUMENT_PPTX ) pFS->singleElementNS( mnXmlNamespace, XML_nvPr, FSEND ); pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr ); WriteShapeTransformation( xShape, mnXmlNamespace, false); WriteTable( xShape ); pFS->endElementNS( mnXmlNamespace, XML_graphicFrame ); return *this; } ShapeExport& ShapeExport::WriteTextShape( Reference< XShape > xShape ) { FSHelperPtr pFS = GetFS(); pFS->startElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp), FSEND ); // non visual shape properties if (GetDocumentType() != DOCUMENT_DOCX) { pFS->startElementNS( mnXmlNamespace, XML_nvSpPr, FSEND ); WriteNonVisualDrawingProperties( xShape, IDS( TextShape ) ); } pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr, XML_txBox, "1", FSEND ); if (GetDocumentType() != DOCUMENT_DOCX) { WriteNonVisualProperties( xShape ); pFS->endElementNS( mnXmlNamespace, XML_nvSpPr ); } // visual shape properties pFS->startElementNS( mnXmlNamespace, XML_spPr, FSEND ); WriteShapeTransformation( xShape, XML_a, false, false, false); WritePresetShape( "rect" ); uno::Reference xPropertySet(xShape, UNO_QUERY); WriteBlipOrNormalFill(xPropertySet, "GraphicURL"); WriteOutline(xPropertySet); pFS->endElementNS( mnXmlNamespace, XML_spPr ); WriteTextBox( xShape, mnXmlNamespace ); pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp) ); return *this; } ShapeExport& ShapeExport::WriteOLE2Shape( Reference< XShape > xShape ) { Reference< XPropertySet > xPropSet( xShape, UNO_QUERY ); if( xPropSet.is() ) { if( GetProperty( xPropSet, "Model" ) ) { Reference< XChartDocument > xChartDoc; mAny >>= xChartDoc; if( xChartDoc.is() ) { //export the chart Reference< XModel > xModel( xChartDoc, UNO_QUERY ); ChartExport aChartExport( mnXmlNamespace, GetFS(), xModel, GetFB(), GetDocumentType() ); static sal_Int32 nChartCount = 0; aChartExport.WriteChartObj( xShape, ++nChartCount ); } else { // this part now supports only embedded spreadsheets, it can be extended to support remaining ooxml documents // only exporter, counter and object filename are specific to spreadsheet Reference< XSpreadsheetDocument > xSheetDoc( mAny, UNO_QUERY ); if( xSheetDoc.is() && mpFB) { Reference< XComponent > xDocument( mAny, UNO_QUERY ); if( xDocument.is() ) { Reference< XOutputStream > xOutStream = mpFB->openFragmentStream( OUStringBuffer() .appendAscii( GetComponentDir() ) .appendAscii( "/embeddings/spreadsheet" ) .append( (sal_Int32) mnSpreadsheetCounter ) .appendAscii( ".xlsx" ) .makeStringAndClear(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ); // export the embedded document Sequence< PropertyValue > rMedia(1); rMedia[0].Name = utl::MediaDescriptor::PROP_STREAMFOROUTPUT(); rMedia[0].Value <<= xOutStream; Reference< XExporter > xExporter( mpFB->getComponentContext()->getServiceManager()-> createInstanceWithContext( "com.sun.star.comp.oox.xls.ExcelFilter", mpFB->getComponentContext() ), UNO_QUERY_THROW ); xExporter->setSourceDocument( xDocument ); Reference< XFilter >( xExporter, UNO_QUERY_THROW )-> filter( rMedia ); xOutStream->closeOutput(); OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(), "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package", OUStringBuffer() .appendAscii( GetRelationCompPrefix() ) .appendAscii( "embeddings/spreadsheet" ) .append( (sal_Int32) mnSpreadsheetCounter ++ ) .appendAscii( ".xlsx" ) .makeStringAndClear() ); mpFS->startElementNS( mnXmlNamespace, XML_graphicFrame, FSEND ); mpFS->startElementNS( mnXmlNamespace, XML_nvGraphicFramePr, FSEND ); mpFS->singleElementNS( mnXmlNamespace, XML_cNvPr, XML_id, I32S( GetNewShapeID( xShape ) ), XML_name, IDS(Object), FSEND ); mpFS->singleElementNS( mnXmlNamespace, XML_cNvGraphicFramePr, FSEND ); if( GetDocumentType() == DOCUMENT_PPTX ) mpFS->singleElementNS( mnXmlNamespace, XML_nvPr, FSEND ); mpFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr ); WriteShapeTransformation( xShape, mnXmlNamespace ); mpFS->startElementNS( XML_a, XML_graphic, FSEND ); mpFS->startElementNS( XML_a, XML_graphicData, XML_uri, "http://schemas.openxmlformats.org/presentationml/2006/ole", FSEND ); mpFS->startElementNS( mnXmlNamespace, XML_oleObj, XML_name, "Spreadsheet", FSNS(XML_r, XML_id), USS( sRelId ), FSEND ); mpFS->singleElementNS( mnXmlNamespace, XML_embed, FSEND ); // pic element SdrObject* pSdrOLE2( GetSdrObjectFromXShape( xShape ) ); if ( pSdrOLE2 && pSdrOLE2->ISA( SdrOle2Obj ) ) { const Graphic* pGraphic = ((SdrOle2Obj*)pSdrOLE2)->GetGraphic(); if ( pGraphic ) WriteGraphicObjectShapePart( xShape, pGraphic ); } mpFS->endElementNS( mnXmlNamespace, XML_oleObj ); mpFS->endElementNS( XML_a, XML_graphicData ); mpFS->endElementNS( XML_a, XML_graphic ); mpFS->endElementNS( mnXmlNamespace, XML_graphicFrame ); } } } } } return *this; } ShapeExport& ShapeExport::WriteUnknownShape( Reference< XShape > ) { // Override this method to do something useful. return *this; } size_t ShapeExport::ShapeHash::operator()( const Reference < XShape > rXShape ) const { return rXShape->getShapeType().hashCode(); } sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape > rXShape ) { return GetNewShapeID( rXShape, GetFB() ); } sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape > rXShape, XmlFilterBase* pFB ) { if( !rXShape.is() ) return -1; sal_Int32 nID = pFB->GetUniqueId(); (*mpShapeMap)[ rXShape ] = nID; return nID; } sal_Int32 ShapeExport::GetShapeID( const Reference< XShape > rXShape ) { return GetShapeID( rXShape, mpShapeMap ); } sal_Int32 ShapeExport::GetShapeID( const Reference< XShape > rXShape, ShapeHashMap* pShapeMap ) { if( !rXShape.is() ) return -1; ShapeHashMap::const_iterator aIter = pShapeMap->find( rXShape ); if( aIter == pShapeMap->end() ) return -1; return aIter->second; } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */