summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorJacobo Aragunde Pérez <jaragunde@igalia.com>2014-02-21 14:36:04 +0100
committerJacobo Aragunde Pérez <jaragunde@igalia.com>2014-02-24 13:26:40 +0100
commit1428ec6f4e2bfe0d8654a9ccc713e274e08c6423 (patch)
treeef84f22ab4203fa3b13195b4ebeb35ba0a4f5d3d /sw
parentad7fdc4e0f8b0777513c10d44026544093b85df4 (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.cxx85
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx11
-rw-r--r--sw/source/filter/ww8/docxexport.cxx41
-rw-r--r--sw/source/filter/ww8/docxexport.hxx7
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 );