sw: write other types of embeddings properly to docx
Improves patch 1428ec6f4e2bfe0d8654a9ccc713e274e08c6423 When embedding an object into a docx, several things interact: * The properties in the <o:OLEObject> tag in document.xml * The ContentType for the file defined in [Content_Types].xml * The Type of the Relationship defined in document.xml.rels You need the right combination of those three elements for Word to properly recognize the embeddings in exported documents. To know which values must be written, I store some interoperability information in the import phase in the document grab bag. The relevant information is the value of the ProgID attribute in the <o:OLEObject> tag. I have defined three cases depending on the value of ProgID, but more could be needed in the future: * Embedded xlsx sheet. * Embedded pptx presentation. * Generic OLE, this should work with embedded odt/ods in combination with the ProgID attribute stored in the import phase. Change-Id: I26336cb3fe47bd33e1cef11dd1c7edcf390f2e56
This commit is contained in:
parent
72d9fa114a
commit
1c993627d8
@ -2579,7 +2579,7 @@ DECLARE_OOXMLEXPORT_TEST(testEmbeddedXlsx, "embedded-xlsx.docx")
|
||||
int nImageFiles = 0;
|
||||
for (int i=0; i<names.getLength(); i++)
|
||||
{
|
||||
if(names[i].startsWith("word/embeddings/Microsoft_Excel_Worksheet"))
|
||||
if(names[i].startsWith("word/embeddings/oleObject"))
|
||||
nSheetFiles++;
|
||||
if(names[i].startsWith("word/media/image"))
|
||||
nImageFiles++;
|
||||
|
@ -3568,12 +3568,53 @@ void DocxAttributeOutput::WritePostponedOLE()
|
||||
|
||||
SAL_INFO( "sw.ww8", OSL_THIS_FUNC );
|
||||
|
||||
// get interoperability information about embedded objects
|
||||
uno::Reference< beans::XPropertySet > xPropSet( m_rExport.pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
|
||||
OUString pName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
|
||||
uno::Sequence< beans::PropertyValue > aGrabBag, aObjectsInteropList;
|
||||
xPropSet->getPropertyValue( pName ) >>= aGrabBag;
|
||||
for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
|
||||
if ( aGrabBag[i].Name == "EmbeddedObjects" )
|
||||
{
|
||||
aGrabBag[i].Value >>= aObjectsInteropList;
|
||||
break;
|
||||
}
|
||||
|
||||
for( std::list< PostponedOLE >::iterator it = m_postponedOLE->begin();
|
||||
it != m_postponedOLE->end();
|
||||
++it )
|
||||
{
|
||||
SwOLEObj& aObject = it->object->GetOLEObj();
|
||||
uno::Reference < embed::XEmbeddedObject > xObj( aObject.GetOleRef() );
|
||||
comphelper::EmbeddedObjectContainer* aContainer = aObject.GetObject().GetContainer();
|
||||
OUString sObjectName = aContainer->GetEmbeddedObjectName( xObj );
|
||||
|
||||
// set some attributes according to the type of the embedded object
|
||||
OUString sProgID, sMediaType, sRelationType;
|
||||
for( sal_Int32 i=0; i < aObjectsInteropList.getLength(); ++i )
|
||||
if ( aObjectsInteropList[i].Name == sObjectName )
|
||||
{
|
||||
aObjectsInteropList[i].Value >>= sProgID;
|
||||
break;
|
||||
}
|
||||
if( sProgID.startsWith("Excel.Sheet") )
|
||||
{
|
||||
sMediaType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
sRelationType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
|
||||
}
|
||||
else if( sProgID.startsWith("PowerPoint.Show") )
|
||||
{
|
||||
sMediaType = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
||||
sRelationType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
|
||||
}
|
||||
else
|
||||
{
|
||||
sMediaType = "application/vnd.openxmlformats-officedocument.oleObject";
|
||||
sRelationType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
|
||||
}
|
||||
|
||||
// write embedded file
|
||||
OString sId = m_rExport.WriteOLENode( *it->object );
|
||||
OString sId = m_rExport.WriteOLEObject( aObject, sMediaType, sRelationType );
|
||||
|
||||
if( sId.isEmpty() )
|
||||
{
|
||||
@ -3612,7 +3653,7 @@ void DocxAttributeOutput::WritePostponedOLE()
|
||||
// OLE object definition
|
||||
m_pSerializer->singleElementNS( XML_o, XML_OLEObject,
|
||||
XML_Type, "Embed",
|
||||
XML_ProgID,"Excel.Sheet.12", //TODO: should be auto-detected somehow
|
||||
XML_ProgID, OUStringToOString( sProgID, RTL_TEXTENCODING_UTF8 ).getStr(),
|
||||
XML_ShapeID, sShapeId.getStr(),
|
||||
XML_DrawAspect, "Content",
|
||||
XML_ObjectID, "_" + OString::number( rand() ),
|
||||
|
@ -358,25 +358,23 @@ OString DocxExport::OutputChart( uno::Reference< frame::XModel >& xModel, sal_In
|
||||
return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
|
||||
}
|
||||
|
||||
OString DocxExport::WriteOLENode( const SwOLENode& rNode )
|
||||
OString DocxExport::WriteOLEObject( SwOLEObj& rObject, OUString sMediaType, OUString sRelationType )
|
||||
{
|
||||
uno::Reference <embed::XEmbeddedObject> xObj( const_cast<SwOLENode&>(rNode).GetOLEObj().GetOleRef() );
|
||||
OUString sId, sMediaType;
|
||||
comphelper::EmbeddedObjectContainer* aContainer = const_cast<SwOLENode&>(rNode).GetOLEObj().GetObject().GetContainer();
|
||||
uno::Reference< io::XInputStream > xInStream = aContainer->GetObjectStream( xObj, &sMediaType );
|
||||
uno::Reference <embed::XEmbeddedObject> xObj( rObject.GetOleRef() );
|
||||
comphelper::EmbeddedObjectContainer* aContainer = rObject.GetObject().GetContainer();
|
||||
uno::Reference< io::XInputStream > xInStream = aContainer->GetObjectStream( xObj, NULL );
|
||||
|
||||
OUString sFileName = "embeddings/Microsoft_Excel_Worksheet" + OUString::number( ++m_nOLEObjects ) + ".xlsx";
|
||||
OUString sFileName = "embeddings/oleObject" + OUString::number( ++m_nOLEObjects ) + ".bin";
|
||||
uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream( OUStringBuffer()
|
||||
.appendAscii( "word/" )
|
||||
.append( sFileName )
|
||||
.makeStringAndClear(),
|
||||
sMediaType );
|
||||
|
||||
OUString sId;
|
||||
if( lcl_CopyStream( xInStream, xOutStream ) )
|
||||
|
||||
sId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/package",
|
||||
sFileName, false );
|
||||
sRelationType, sFileName, false );
|
||||
|
||||
return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ public:
|
||||
|
||||
/// Returns the relationd id
|
||||
OString OutputChart( com::sun::star::uno::Reference< com::sun::star::frame::XModel >& xModel, sal_Int32 nCount, ::sax_fastparser::FSHelperPtr m_pSerializer );
|
||||
OString WriteOLENode( const SwOLENode& rNode );
|
||||
OString WriteOLEObject( SwOLEObj& rObject, OUString sMediaType, OUString sRelationType );
|
||||
bool lcl_CopyStream( css::uno::Reference< css::io::XInputStream> xIn, css::uno::Reference< css::io::XOutputStream > xOut );
|
||||
|
||||
/// Writes the shape using drawingML syntax.
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <PropertyMap.hxx>
|
||||
#include "GraphicHelpers.hxx"
|
||||
|
||||
#include <editeng/unoprnms.hxx>
|
||||
#include <ooxml/resourceids.hxx>
|
||||
#include <rtl/ustring.hxx>
|
||||
#include <com/sun/star/beans/PropertyValue.hpp>
|
||||
@ -170,6 +171,48 @@ void OLEHandler::lcl_sprm(Sprm & rSprm)
|
||||
}
|
||||
|
||||
|
||||
void OLEHandler::saveInteropProperties( uno::Reference< text::XTextDocument > xTextDocument, OUString sObjectName )
|
||||
{
|
||||
const OUString sGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
|
||||
const OUString sEmbeddingsPropName = "EmbeddedObjects";
|
||||
|
||||
// get interop grab bag from document
|
||||
uno::Reference< beans::XPropertySet > xDocProps( xTextDocument, uno::UNO_QUERY );
|
||||
uno::Sequence< beans::PropertyValue > aGrabBag;
|
||||
xDocProps->getPropertyValue( sGrabBagPropName ) >>= aGrabBag;
|
||||
|
||||
// get EmbeddedObjects property inside grab bag
|
||||
sal_Int32 i = 0;
|
||||
sal_Int32 nBagLength = aGrabBag.getLength();
|
||||
uno::Sequence< beans::PropertyValue > objectsList;
|
||||
for( ; i < nBagLength; ++i )
|
||||
if ( aGrabBag[i].Name == sEmbeddingsPropName )
|
||||
{
|
||||
aGrabBag[i].Value >>= objectsList;
|
||||
break;
|
||||
}
|
||||
|
||||
// save ProgID of current object
|
||||
sal_Int32 length = objectsList.getLength();
|
||||
objectsList.realloc( length + 1 );
|
||||
objectsList[length].Name = sObjectName;
|
||||
objectsList[length].Value = uno::Any( m_sProgId );
|
||||
|
||||
// put objects list back into the grab bag
|
||||
if( i == nBagLength )
|
||||
{
|
||||
aGrabBag.realloc( nBagLength + 1 );
|
||||
aGrabBag[nBagLength].Name = sEmbeddingsPropName;
|
||||
aGrabBag[nBagLength].Value = uno::Any( objectsList );
|
||||
}
|
||||
else
|
||||
aGrabBag[i].Value = uno::Any( objectsList );
|
||||
|
||||
// put grab bag back into the document
|
||||
xDocProps->setPropertyValue( sGrabBagPropName, uno::Any( aGrabBag ) );
|
||||
}
|
||||
|
||||
|
||||
OUString OLEHandler::copyOLEOStream( uno::Reference< text::XTextDocument > xTextDocument )
|
||||
{
|
||||
OUString sRet;
|
||||
@ -202,6 +245,8 @@ OUString OLEHandler::copyOLEOStream( uno::Reference< text::XTextDocument > xText
|
||||
}
|
||||
}
|
||||
|
||||
saveInteropProperties( xTextDocument, aURL );
|
||||
|
||||
static const OUString sProtocol("vnd.sun.star.EmbeddedObject:");
|
||||
OUString aPersistName( xEmbeddedResolver->resolveEmbeddedObjectURL( aURL ) );
|
||||
sRet = aPersistName.copy( sProtocol.getLength() );
|
||||
|
@ -69,6 +69,10 @@ class OLEHandler : public LoggedProperties
|
||||
virtual void lcl_attribute(Id Name, Value & val);
|
||||
virtual void lcl_sprm(Sprm & sprm);
|
||||
|
||||
// Interoperability
|
||||
virtual void saveInteropProperties( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextDocument > xTextDocument,
|
||||
OUString sObjectName );
|
||||
|
||||
public:
|
||||
OLEHandler();
|
||||
virtual ~OLEHandler();
|
||||
|
Loading…
x
Reference in New Issue
Block a user