comphelper/source/container/embeddedobjectcontainer.cxx | 46 ++++++-- filter/source/msfilter/eschesdo.cxx | 8 - include/comphelper/embeddedobjectcontainer.hxx | 4 sw/qa/extras/ooxmlexport/data/embedded-xlsx.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport.cxx | 31 +++++ sw/source/filter/ww8/docxattributeoutput.cxx | 85 ++++++++++++++++ sw/source/filter/ww8/docxattributeoutput.hxx | 11 ++ sw/source/filter/ww8/docxexport.cxx | 41 +++++++ sw/source/filter/ww8/docxexport.hxx | 7 + 9 files changed, 217 insertions(+), 16 deletions(-)
New commits: commit 9fab183d4d8b377b155c39952a534712b245c5a9 Author: Jacobo Aragunde Pérez <jaragu...@igalia.com> Date: Mon Feb 24 12:13:45 2014 +0100 sw: Unit test for spreadsheets embedded in docx Change-Id: I0a91ea0ca36d57320c3495a5cedba7924d3a7ea7 diff --git a/sw/qa/extras/ooxmlexport/data/embedded-xlsx.docx b/sw/qa/extras/ooxmlexport/data/embedded-xlsx.docx new file mode 100644 index 0000000..3b9dd2a Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/embedded-xlsx.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx index c1d81ca..1ee6af8 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx @@ -3467,6 +3467,37 @@ DECLARE_OOXMLEXPORT_TEST(testAbi11739, "abi11739.docx") CPPUNIT_ASSERT(getXPathPosition(pXmlDoc, "/w:styles/w:style[11]", "unhideWhenUsed") < getXPathPosition(pXmlDoc, "/w:styles/w:style[11]", "qFormat")); } +DECLARE_OOXMLEXPORT_TEST(testEmbeddedXlsx, "embedded-xlsx.docx") +{ + // check there are two objects and they are FrameShapes + uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xDraws(xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xDraws->getCount()); + CPPUNIT_ASSERT_EQUAL(OUString("FrameShape"), getShape(1)->getShapeType()); + CPPUNIT_ASSERT_EQUAL(OUString("FrameShape"), getShape(2)->getShapeType()); + + // check the objects are present in the exported document.xml + xmlDocPtr pXmlDocument = parseExport("word/document.xml"); + if (!pXmlDocument) + return; + assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/w:object", 2); + + // finally check the embedded files are present in the zipped document + uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), m_aTempFile.GetURL()); + uno::Sequence<OUString> names = xNameAccess->getElementNames(); + sal_Int32 nSheetFiles = 0; + sal_Int32 nImageFiles = 0; + for (int i=0; i<names.getLength(); i++) + { + if(names[i].startsWith("word/embeddings/Microsoft_Excel_Worksheet")) + nSheetFiles++; + if(names[i].startsWith("word/media/image")) + nImageFiles++; + } + CPPUNIT_ASSERT_EQUAL(2, nSheetFiles); + CPPUNIT_ASSERT_EQUAL(2, nImageFiles); +} + #endif CPPUNIT_PLUGIN_IMPLEMENT(); commit 1428ec6f4e2bfe0d8654a9ccc713e274e08c6423 Author: Jacobo Aragunde Pérez <jaragu...@igalia.com> Date: Fri Feb 21 14:36:04 2014 +0100 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 diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 1322131..4695854 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 30474f1..de98b3c 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 321e01e..41e7083 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 d058302..6077966 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 ); commit ad7fdc4e0f8b0777513c10d44026544093b85df4 Author: Jacobo Aragunde Pérez <jaragu...@igalia.com> Date: Tue Feb 18 13:32:43 2014 +0100 filter: Code reduction, prevents crash. Not all shape types have the full com.sun.star. prefix, for example FrameShape. The existing code would crash in that case, but the new code doesn't. Change-Id: I9aa3d0f20f48ab91a6770e8409a8da2028816504 diff --git a/filter/source/msfilter/eschesdo.cxx b/filter/source/msfilter/eschesdo.cxx index a7d7e41..6b742ba 100644 --- a/filter/source/msfilter/eschesdo.cxx +++ b/filter/source/msfilter/eschesdo.cxx @@ -1186,14 +1186,10 @@ void ImplEESdrObject::Init( ImplEESdrWriter& rEx ) mXPropSet = Reference< XPropertySet >::query( mXShape ); if( mXPropSet.is() ) { - static const sal_Char aPrefix[] = "com.sun.star."; - static const sal_Int32 nPrefix = sizeof(aPrefix)-1; - // detect name first to make below test (is group) work mType = OUString( mXShape->getShapeType() ); - mType = mType.copy( nPrefix ); // strip "com.sun.star." - sal_Int32 nPos = mType.indexOf( "Shape" ); - mType = mType.replaceAt( nPos, 5, "" ); + mType.startsWith( "com.sun.star.", &mType ); // strip "com.sun.star." + mType.endsWith( "Shape", &mType ); // strip "Shape" if(GetType() == "drawing.Group") { commit c69ae9f8f80988afd31ec5a936984e131e18db7f Author: Jacobo Aragunde Pérez <jaragu...@igalia.com> Date: Fri Feb 14 18:14:50 2014 +0100 comphelper: EmbeddedObjectContainer::GetObjectStream methods These methods were added to provide access to the stream to the embedded object itself. Change-Id: I0a47a54852cddbd5ddd0a6599bba21999afd96ba diff --git a/comphelper/source/container/embeddedobjectcontainer.cxx b/comphelper/source/container/embeddedobjectcontainer.cxx index a3cdfa4..d296c9f 100644 --- a/comphelper/source/container/embeddedobjectcontainer.cxx +++ b/comphelper/source/container/embeddedobjectcontainer.cxx @@ -1206,6 +1206,46 @@ uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( c return GetGraphicStream( GetEmbeddedObjectName( xObj ), pMediaType ); } +uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetObjectStream( const OUString& aName, OUString* pMediaType ) +{ + SAL_INFO( "comphelper.container", "comphelper::EmbeddedObjectContainer::GetObjectStream( Name )" ); + + uno::Reference < io::XInputStream > xInputStream; + + SAL_WARN_IF( aName.isEmpty(), "comphelper.container", "Retrieving stream for unknown object!" ); + if ( !aName.isEmpty() ) + { + try + { + uno::Reference < io::XStream > xStream = pImpl->mxStorage->cloneStreamElement( aName ); //get a readonly clone + xInputStream = xStream->getInputStream(); + if ( pMediaType ) + { + uno::Reference < beans::XPropertySet > xSet( xInputStream, uno::UNO_QUERY ); + if ( xSet.is() ) + { + uno::Any aAny = xSet->getPropertyValue("MediaType"); + aAny >>= *pMediaType; + } + } + } + catch (const uno::Exception&) + { + } + } + + return xInputStream; +} + +uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetObjectStream( const uno::Reference < embed::XEmbeddedObject >& xObj, OUString* pMediaType ) +{ + + SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Object )" ); + + // try to load it from the container storage + return GetObjectStream( GetEmbeddedObjectName( xObj ), pMediaType ); +} + bool EmbeddedObjectContainer::InsertGraphicStream( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const OUString& rObjectName, const OUString& rMediaType ) { SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::InsertGraphicStream" ); diff --git a/include/comphelper/embeddedobjectcontainer.hxx b/include/comphelper/embeddedobjectcontainer.hxx index 742ae4a..28be667 100644 --- a/include/comphelper/embeddedobjectcontainer.hxx +++ b/include/comphelper/embeddedobjectcontainer.hxx @@ -135,6 +135,10 @@ public: // move an embedded object to another container (keep the persistent name) bool MoveEmbeddedObject( const OUString& rName, EmbeddedObjectContainer& ); + // get the stored representation for the object + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > GetObjectStream( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >&, OUString* pMediaType=0 ); + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > GetObjectStream( const OUString& aName, OUString* pMediaType ); + // get the stored graphical representation for the object com::sun::star::uno::Reference < com::sun::star::io::XInputStream > GetGraphicStream( const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >&, OUString* pMediaType=0 ); commit 20a174ac1243fb6ad322347eb99c2d014bd4ca95 Author: Jacobo Aragunde Pérez <jaragu...@igalia.com> Date: Fri Feb 14 17:59:40 2014 +0100 comphelper: code refactor Change-Id: Ica71d0691cf02aeaa03b6570015d9828cd7daeed diff --git a/comphelper/source/container/embeddedobjectcontainer.cxx b/comphelper/source/container/embeddedobjectcontainer.cxx index c3c321c..a3cdfa4 100644 --- a/comphelper/source/container/embeddedobjectcontainer.cxx +++ b/comphelper/source/container/embeddedobjectcontainer.cxx @@ -1202,22 +1202,8 @@ uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( c { SAL_INFO( "comphelper.container", "comphelper (mv76033) comphelper::EmbeddedObjectContainer::GetGraphicStream( Object )" ); - // get the object name - OUString aName; - EmbeddedObjectContainerNameMap::iterator aIt = pImpl->maObjectContainer.begin(); - while ( aIt != pImpl->maObjectContainer.end() ) - { - if ( (*aIt).second == xObj ) - { - aName = (*aIt).first; - break; - } - - ++aIt; - } - // try to load it from the container storage - return GetGraphicStream( aName, pMediaType ); + return GetGraphicStream( GetEmbeddedObjectName( xObj ), pMediaType ); } bool EmbeddedObjectContainer::InsertGraphicStream( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& rStream, const OUString& rObjectName, const OUString& rMediaType )
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits