diff options
author | Jacobo Aragunde Pérez <jaragunde@igalia.com> | 2014-02-21 14:36:04 +0100 |
---|---|---|
committer | Jacobo Aragunde Pérez <jaragunde@igalia.com> | 2014-02-24 13:26:40 +0100 |
commit | 1428ec6f4e2bfe0d8654a9ccc713e274e08c6423 (patch) | |
tree | ef84f22ab4203fa3b13195b4ebeb35ba0a4f5d3d /sw | |
parent | ad7fdc4e0f8b0777513c10d44026544093b85df4 (diff) |
sw: Preserve embedded spreadsheets in docx
Embedded spreadsheets consist on two files:
* The spreadsheet found in word/embeddings/ directory.
* A preview image found in word/media/ directory.
This patch saves these two files and writes the proper XML to the
document. It looks like this:
<w:object>
<v:shape id="ole_rId2"
style="width:362.55pt;height:145.7pt" o:ole="">
<v:imagedata r:id="rId3" />
</v:shape>
<o:OLEObject Type="Embed" ProgID="Excel.Sheet.12"
ShapeID="ole_rId2" DrawAspect="Content"
ObjectID="_227653443" r:id="rId2" />
</w:object>
Some simplifications were done in comparison with the XML generated
by Word; the lines above seem to be the minimum working code.
Similarly to drawings, charts, etc. our code postpones the actual
process of the OLE objects until the rPr tag is closed.
TODO:
* Unit tests.
* Add information about xlsx extension to [Content_Types].xml
* Without that, Word doesn't detect the OLE as an spreadsheet.
Change-Id: Ia0c797b72cd6e99ca9ad7fa11897b62ab3867a5e
Diffstat (limited to 'sw')
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 85 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 11 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxexport.cxx | 41 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxexport.hxx | 7 |
4 files changed, 144 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 132213138cad..469585492ebc 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -1071,6 +1071,9 @@ void DocxAttributeOutput::StartRunProperties() assert(!m_postponedDMLDrawing); m_postponedDMLDrawing = new std::list< PostponedDrawing >; + + assert( !m_postponedOLE ); + m_postponedOLE = new std::list< PostponedOLE >; } void DocxAttributeOutput::InitCollectedRunProperties() @@ -1326,6 +1329,8 @@ void DocxAttributeOutput::EndRunProperties( const SwRedlineData* pRedlineData ) WritePostponedVMLDrawing(); WritePostponedDMLDrawing(); + WritePostponedOLE(); + // merge the properties _before_ the run text (strictly speaking, just // after the start of the run) m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND ); @@ -3306,6 +3311,8 @@ void DocxAttributeOutput::WriteOLE2Obj( const SdrObject* pSdrObj, SwOLENode& rOL return; if( WriteOLEMath( pSdrObj, rOLENode, rSize )) return; + if( PostponeOLE( pSdrObj, rOLENode, rSize, pFlyFrmFmt )) + return; // Then we fall back to just export the object as a graphic. if( m_postponedGraphic == NULL ) FlyFrameGraphic( 0, rSize, pFlyFrmFmt, &rOLENode ); @@ -3467,6 +3474,83 @@ void DocxAttributeOutput::WritePostponedFormControl(const SdrObject* pObject) } } +bool DocxAttributeOutput::PostponeOLE( const SdrObject*, SwOLENode& rNode, const Size& rSize, const SwFlyFrmFmt* pFlyFrmFmt ) +{ + if( m_postponedVMLDrawing == NULL ) + return false; + m_postponedOLE->push_back( PostponedOLE( &rNode, rSize, pFlyFrmFmt ) ); + return true; +} + +/* + * Write w:object hierarchy for embedded objects after end element of w:rPr tag. + */ +void DocxAttributeOutput::WritePostponedOLE() +{ + if( m_postponedOLE == NULL ) + return; + + SAL_INFO( "sw.ww8", OSL_THIS_FUNC ); + + for( std::list< PostponedOLE >::iterator it = m_postponedOLE->begin(); + it != m_postponedOLE->end(); + ++it ) + { + // write embedded file + OString sId = m_rExport.WriteOLENode( *it->object ); + + if( sId.isEmpty() ) + { + // the embedded file could not be saved + // fallback: save as an image + FlyFrameGraphic( 0, it->size, it->frame, it->object ); + continue; + } + + // write preview image + const Graphic* pGraphic = const_cast< SwOLENode* >( it->object )->GetGraphic(); + OUString sImageId = m_rDrawingML.WriteImage( *pGraphic ); + + m_pSerializer->startElementNS( XML_w, XML_object, FSEND ); + + OStringBuffer sShapeStyle, sShapeId; + sShapeStyle.append( "width:" ).append( double( it->size.Width() ) / 20 ) + .append( "pt;height:" ).append( double( it->size.Height() ) / 20 ) + .append( "pt" ); //from VMLExport::AddRectangleDimensions(), it does: value/20 + sShapeId.append( "ole_" ).append( sId ); + + // shape definition + m_pSerializer->startElementNS( XML_v, XML_shape, + XML_id, sShapeId.getStr(), + XML_style, sShapeStyle.getStr(), + FSNS( XML_o, XML_ole ), "", //compulsory, even if it's empty + FSEND ); + + // shape filled with the preview image + m_pSerializer->singleElementNS( XML_v, XML_imagedata, + FSNS( XML_r, XML_id ), OUStringToOString( sImageId, RTL_TEXTENCODING_UTF8 ).getStr(), + FSEND ); + + m_pSerializer->endElementNS( XML_v, XML_shape ); + + // 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_ShapeID, sShapeId.getStr(), + XML_DrawAspect, "Content", + XML_ObjectID, "_" + OString::number( rand() ), + FSNS( XML_r, XML_id ), sId.getStr(), + FSEND ); + + m_pSerializer->endElementNS( XML_w, XML_object ); + } + + // clear list of postponed objects + delete m_postponedOLE; + m_postponedOLE = NULL; +} + /* * Write w:pict hierarchy end element of w:rPr tag. */ @@ -6520,6 +6604,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSeri m_postponedDiagram( NULL ), m_postponedVMLDrawing(NULL), m_postponedDMLDrawing(NULL), + m_postponedOLE( NULL ), m_postponedMath( NULL ), m_postponedChart( NULL ), pendingPlaceholder( NULL ), diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 30474f17b35c..de98b3c8b64c 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -393,6 +393,7 @@ private: void WriteOLE2Obj( const SdrObject* pSdrObj, SwOLENode& rNode, const Size& rSize, const SwFlyFrmFmt* pFlyFrmFmt); bool WriteOLEChart( const SdrObject* pSdrObj, const Size& rSize ); bool WriteOLEMath( const SdrObject* pSdrObj, const SwOLENode& rNode, const Size& rSize ); + bool PostponeOLE( const SdrObject* pSdrObj, SwOLENode& rNode, const Size& rSize, const SwFlyFrmFmt* pFlyFrmFmt ); /// checks whether the current component is a diagram bool IsDiagram (const SdrObject* sdrObject); @@ -668,6 +669,7 @@ private: void WritePostponedFormControl(const SdrObject* pObject); void WritePostponedDiagram(); void WritePostponedChart(); + void WritePostponedOLE(); void WritePostponedVMLDrawing(); void WritePostponedDMLDrawing(); @@ -786,6 +788,15 @@ private: std::list< PostponedDrawing >* m_postponedVMLDrawing; std::list< PostponedDrawing >* m_postponedDMLDrawing; + struct PostponedOLE + { + PostponedOLE( SwOLENode* rObject, const Size rSize, const SwFlyFrmFmt* rFrame ) : object( rObject ), size( rSize ), frame( rFrame ) {}; + SwOLENode* object; + const Size size; + const SwFlyFrmFmt* frame; + }; + std::list< PostponedOLE >* m_postponedOLE; + const SwOLENode* m_postponedMath; const SdrObject* m_postponedChart; Size m_postponedChartSize; diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 321e01e6e5ec..41e70834de67 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -66,6 +66,7 @@ #include "ww8par.hxx" #include "ww8scan.hxx" #include <oox/token/properties.hxx> +#include <comphelper/embeddedobjectcontainer.hxx> #include <comphelper/string.hxx> #include <rtl/ustrbuf.hxx> #include <vcl/font.hxx> @@ -357,6 +358,45 @@ OString DocxExport::OutputChart( uno::Reference< frame::XModel >& xModel, sal_In return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 ); } +OString DocxExport::WriteOLENode( const SwOLENode& rNode ) +{ + 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 ); + + OUString sFileName = "embeddings/Microsoft_Excel_Worksheet" + OUString::number( ++m_nOLEObjects ) + ".xlsx"; + uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream( OUStringBuffer() + .appendAscii( "word/" ) + .append( sFileName ) + .makeStringAndClear(), + sMediaType ); + + if( lcl_CopyStream( xInStream, xOutStream ) ) + + sId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(), + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package", + sFileName, false ); + + return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 ); +} + +// function copied from embeddedobj/source/msole/oleembed.cxx +bool DocxExport::lcl_CopyStream( uno::Reference<io::XInputStream> xIn, uno::Reference<io::XOutputStream> xOut ) +{ + const sal_Int32 nChunkSize = 4096; + uno::Sequence< sal_Int8 > aData(nChunkSize); + sal_Int32 nTotalRead = 0; + sal_Int32 nRead = 0; + do + { + nRead = xIn->readBytes(aData, nChunkSize); + nTotalRead += nRead; + xOut->writeBytes(aData); + } while (nRead == nChunkSize); + return nTotalRead != 0; +} + void DocxExport::OutputDML(uno::Reference<drawing::XShape>& xShape) { uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW); @@ -1319,6 +1359,7 @@ DocxExport::DocxExport( DocxExportFilter *pFilter, SwDoc *pDocument, SwPaM *pCur m_pSections( NULL ), m_nHeaders( 0 ), m_nFooters( 0 ), + m_nOLEObjects( 0 ), m_nHeadersFootersInSection(0), m_pVMLExport( NULL ), m_pSdrExport( NULL ) diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx index d058302d34a3..60779669fae0 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -29,6 +29,7 @@ #include <cstdio> #include <vector> #include <boost/optional.hpp> +#include <ndole.hxx> class DocxAttributeOutput; class DocxExportFilter; @@ -84,6 +85,9 @@ class DocxExport : public MSWordExportBase /// Footer counter. sal_Int32 m_nFooters; + /// OLE objects counter. + sal_Int32 m_nOLEObjects; + ///Footer and Header counter in Section properties sal_Int32 m_nHeadersFootersInSection; @@ -159,6 +163,9 @@ 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 ); + bool lcl_CopyStream( css::uno::Reference< css::io::XInputStream> xIn, css::uno::Reference< css::io::XOutputStream > xOut ); + /// Writes the shape using drawingML syntax. void OutputDML( com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape ); |