diff options
-rw-r--r-- | chart2/qa/extras/chart2export.cxx | 30 | ||||
-rw-r--r-- | chart2/qa/extras/data/xlsx/tdf128621.xlsx | bin | 0 -> 15011 bytes | |||
-rw-r--r-- | include/oox/export/chartexport.hxx | 2 | ||||
-rw-r--r-- | include/oox/export/drawingml.hxx | 10 | ||||
-rw-r--r-- | include/oox/token/relationship.hxx | 1 | ||||
-rw-r--r-- | oox/source/export/chartexport.cxx | 108 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 69 | ||||
-rw-r--r-- | oox/source/token/relationship.inc | 1 | ||||
-rw-r--r-- | oox/source/token/tokens.txt | 1 | ||||
-rw-r--r-- | sc/source/filter/excel/xeescher.cxx | 2 | ||||
-rw-r--r-- | sc/source/filter/excel/xestream.cxx | 2 | ||||
-rw-r--r-- | sc/source/filter/inc/xcl97rec.hxx | 5 | ||||
-rw-r--r-- | sc/source/filter/xcl97/xcl97rec.cxx | 17 |
13 files changed, 228 insertions, 20 deletions
diff --git a/chart2/qa/extras/chart2export.cxx b/chart2/qa/extras/chart2export.cxx index d92e06cdc01c..d0cd3be67d66 100644 --- a/chart2/qa/extras/chart2export.cxx +++ b/chart2/qa/extras/chart2export.cxx @@ -185,6 +185,7 @@ public: void testTdf138204(); void testTdf138181(); void testCustomShapeText(); + void testuserShapesXLSX(); CPPUNIT_TEST_SUITE(Chart2ExportTest); CPPUNIT_TEST(testErrorBarXLSX); @@ -332,6 +333,7 @@ public: CPPUNIT_TEST(testTdf138204); CPPUNIT_TEST(testTdf138181); CPPUNIT_TEST(testCustomShapeText); + CPPUNIT_TEST(testuserShapesXLSX); CPPUNIT_TEST_SUITE_END(); @@ -3056,6 +3058,34 @@ void Chart2ExportTest::testCustomShapeText() CPPUNIT_ASSERT(!xRange->getString().isEmpty()); } +void Chart2ExportTest::testuserShapesXLSX() +{ + load("/chart2/qa/extras/data/xlsx/", "tdf128621.xlsx"); + reload("Calc Office Open XML"); + + Reference< chart2::XChartDocument> xChartDoc = getChartDocFromSheet(0, mxComponent); + CPPUNIT_ASSERT(xChartDoc.is()); + + // test that the custom shape exists + Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xChartDoc, UNO_QUERY_THROW); + Reference<drawing::XDrawPage> xDrawPage(xDrawPageSupplier->getDrawPage(), UNO_SET_THROW); + Reference<drawing::XShape> xCustomShape(xDrawPage->getByIndex(1), UNO_QUERY_THROW); + CPPUNIT_ASSERT(xCustomShape.is()); + // test type of shape + CPPUNIT_ASSERT(xCustomShape->getShapeType().endsWith("CustomShape")); + // test custom shape position + awt::Point aPosition = xCustomShape->getPosition(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1356, aPosition.X, 300); + CPPUNIT_ASSERT_DOUBLES_EQUAL(9107, aPosition.Y, 300); + // test custom shape size + awt::Size aSize = xCustomShape->getSize(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(9520, aSize.Width, 300); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1805, aSize.Height, 300); + // test custom shape text + Reference< text::XText > xRange(xCustomShape, uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT(!xRange->getString().isEmpty()); +} + CPPUNIT_TEST_SUITE_REGISTRATION(Chart2ExportTest); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/chart2/qa/extras/data/xlsx/tdf128621.xlsx b/chart2/qa/extras/data/xlsx/tdf128621.xlsx Binary files differnew file mode 100644 index 000000000000..93a6822da951 --- /dev/null +++ b/chart2/qa/extras/data/xlsx/tdf128621.xlsx diff --git a/include/oox/export/chartexport.hxx b/include/oox/export/chartexport.hxx index b900c68b51a2..b6ed39c72dbb 100644 --- a/include/oox/export/chartexport.hxx +++ b/include/oox/export/chartexport.hxx @@ -27,6 +27,7 @@ #include <com/sun/star/uno/Sequence.hxx> #include <oox/dllapi.h> #include <oox/export/drawingml.hxx> +#include <oox/export/shapes.hxx> #include <oox/export/utils.hxx> #include <oox/token/tokens.hxx> #include <rtl/ustring.hxx> @@ -140,6 +141,7 @@ private: const OUString* pSubText = nullptr ); void exportPlotArea( const css::uno::Reference< css::chart::XChartDocument >& rChartDoc ); + void exportAdditionalShapes( const css::uno::Reference<css::chart::XChartDocument >& rChartDoc ); void exportFill( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ); void exportSolidFill(const css::uno::Reference<css::beans::XPropertySet>& xPropSet); void exportGradientFill( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ); diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index 9f87e54c1361..afd1d994eafd 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -141,6 +141,8 @@ private: static int mnImageCounter; static int mnWdpImageCounter; static std::map<OUString, OUString> maWdpCache; + static sal_Int32 mnDrawingMLCount; + static sal_Int32 mnVmlCount; /// To specify where write eg. the images to (like 'ppt', or 'word' - according to the OPC). DocumentType meDocumentType; @@ -293,12 +295,20 @@ public: void writeDiagramRels(const css::uno::Sequence<css::uno::Sequence<css::uno::Any>>& xRelSeq, const css::uno::Reference<css::io::XOutputStream>& xOutStream, const OUString& sGrabBagProperyName, int nDiagramId); + static void WriteFromTo(const css::uno::Reference<css::drawing::XShape>& rXShape, const css::awt::Size& aPageSize, + const sax_fastparser::FSHelperPtr& pDrawing); + static bool IsGroupShape( const css::uno::Reference< css::drawing::XShape >& rXShape ); static bool IsDiagram(const css::uno::Reference<css::drawing::XShape>& rXShape); sal_Int32 getBulletMarginIndentation (const css::uno::Reference< css::beans::XPropertySet >& rXPropSet,sal_Int16 nLevel, std::u16string_view propName); static void ResetCounters(); + static void ResetMlCounters(); + + static sal_Int32 getNewDrawingUniqueId() { return ++mnDrawingMLCount; } + static sal_Int32 getNewVMLUniqueId() { return ++mnVmlCount; } + // A Helper to decide the script type for given text in order to call WriteRunProperties. static sal_Int16 GetScriptType(const OUString& rStr); diff --git a/include/oox/token/relationship.hxx b/include/oox/token/relationship.hxx index adffd4b6617e..fbba99768711 100644 --- a/include/oox/token/relationship.hxx +++ b/include/oox/token/relationship.hxx @@ -20,6 +20,7 @@ enum class Relationship { ACTIVEXCONTROLBINARY, CHART, + CHARTUSERSHAPES, COMMENTS, COMMENTAUTHORS, CONTROL, diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx index e87fba060646..24fc7dc88aad 100644 --- a/oox/source/export/chartexport.cxx +++ b/oox/source/export/chartexport.cxx @@ -74,6 +74,7 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/container/XNameAccess.hpp> #include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/drawing/XShapes.hpp> #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/LineStyle.hpp> #include <com/sun/star/awt/XBitmap.hpp> @@ -927,6 +928,9 @@ void ChartExport::exportChartSpace( const Reference< css::chart::XChartDocument //XML_externalData exportExternalData(xChartDoc); + // export additional shapes in chart + exportAdditionalShapes(xChartDoc); + pFS->endElement( FSNS( XML_c, XML_chartSpace ) ); } @@ -977,6 +981,110 @@ void ChartExport::exportExternalData( const Reference< css::chart::XChartDocumen pFS->singleElementNS(XML_c, XML_externalData, FSNS(XML_r, XML_id), sRelId); } +void ChartExport::exportAdditionalShapes( const Reference< css::chart::XChartDocument >& xChartDoc ) +{ + Reference< beans::XPropertySet > xDocPropSet(xChartDoc, uno::UNO_QUERY); + if (xDocPropSet.is()) + { + css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes; + // get a sequence of non-chart shapes + try + { + Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes"); + if( (aShapesAny >>= mxAdditionalShapes) && mxAdditionalShapes.is() ) + { + OUString sId; + const char* sFullPath = nullptr; + const char* sRelativePath = nullptr; + sal_Int32 nDrawing = getNewDrawingUniqueId(); + + switch (GetDocumentType()) + { + case DOCUMENT_DOCX: + { + sFullPath = "word/drawings/drawing"; + sRelativePath = "../drawings/drawing"; + break; + } + case DOCUMENT_PPTX: + { + sFullPath = "ppt/drawings/drawing"; + sRelativePath = "../drawings/drawing"; + break; + } + case DOCUMENT_XLSX: + { + sFullPath = "xl/drawings/drawing"; + sRelativePath = "../drawings/drawing"; + break; + } + default: + { + sFullPath = "drawings/drawing"; + sRelativePath = "drawings/drawing"; + break; + } + } + OUString sFullStream = OUStringBuffer() + .appendAscii(sFullPath) + .append(nDrawing) + .append(".xml") + .makeStringAndClear(); + OUString sRelativeStream = OUStringBuffer() + .appendAscii(sRelativePath) + .append(nDrawing) + .append(".xml") + .makeStringAndClear(); + + sax_fastparser::FSHelperPtr pDrawing = CreateOutputStream( + sFullStream, + sRelativeStream, + GetFS()->getOutputStream(), + "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml", + OUStringToOString(oox::getRelationship(Relationship::CHARTUSERSHAPES), RTL_TEXTENCODING_UTF8).getStr(), + &sId); + + GetFS()->singleElementNS(XML_c, XML_userShapes, FSNS(XML_r, XML_id), sId); + + XmlFilterBase* pFB = GetFB(); + pDrawing->startElement(FSNS(XML_c, XML_userShapes), + FSNS(XML_xmlns, XML_cdr), pFB->getNamespaceURL(OOX_NS(dmlChartDr)), + FSNS(XML_xmlns, XML_a), pFB->getNamespaceURL(OOX_NS(dml)), + FSNS(XML_xmlns, XML_c), pFB->getNamespaceURL(OOX_NS(dmlChart))); + + const sal_Int32 nShapeCount(mxAdditionalShapes->getCount()); + for (sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++) + { + Reference< drawing::XShape > xShape; + mxAdditionalShapes->getByIndex(nShapeId) >>= xShape; + SAL_WARN_IF(!xShape.is(), "xmloff.chart", "Shape without an XShape?"); + if (!xShape.is()) + continue; + + // TODO: absSizeAnchor: we import both (absSizeAnchor and relSizeAnchor), but there is no essential difference between them. + pDrawing->startElement(FSNS(XML_cdr, XML_relSizeAnchor)); + uno::Reference< beans::XPropertySet > xShapeProperties(xShape, uno::UNO_QUERY); + if( xShapeProperties.is() ) + { + Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY); + awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT); + WriteFromTo( xShape, aPageSize, pDrawing ); + + ShapeExport aExport(XML_cdr, pDrawing, nullptr, GetFB(), GetDocumentType()); + aExport.WriteShape(xShape); + } + pDrawing->endElement(FSNS(XML_cdr, XML_relSizeAnchor)); + } + pDrawing->endElement(FSNS(XML_c, XML_userShapes)); + } + } + catch (const uno::Exception&) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found"); + } + } +} + void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xChartDoc ) { Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY ); diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 5374812fa094..f291de8662ef 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -209,6 +209,8 @@ void WriteGradientPath(const awt::Gradient& rGradient, const FSHelperPtr& pFS, c int DrawingML::mnImageCounter = 1; int DrawingML::mnWdpImageCounter = 1; std::map<OUString, OUString> DrawingML::maWdpCache; +sal_Int32 DrawingML::mnDrawingMLCount = 0; +sal_Int32 DrawingML::mnVmlCount = 0; sal_Int16 DrawingML::GetScriptType(const OUString& rStr) { @@ -241,6 +243,12 @@ void DrawingML::ResetCounters() maWdpCache.clear(); } +void DrawingML::ResetMlCounters() +{ + mnDrawingMLCount = 0; + mnVmlCount = 0; +} + bool DrawingML::GetProperty( const Reference< XPropertySet >& rXPropertySet, const OUString& aName ) { try @@ -4952,6 +4960,67 @@ void DrawingML::writeDiagramRels(const uno::Sequence<uno::Sequence<uno::Any>>& x } } +void DrawingML::WriteFromTo(const uno::Reference<css::drawing::XShape>& rXShape, const awt::Size& aPageSize, + const FSHelperPtr& pDrawing) +{ + awt::Point aTopLeft = rXShape->getPosition(); + awt::Size aSize = rXShape->getSize(); + + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rXShape.get()); + if (pObj) + { + sal_Int32 nRotation = pObj->GetRotateAngle(); + if (nRotation != 0) + { + sal_Int16 nHalfWidth = aSize.Width / 2; + sal_Int16 nHalfHeight = aSize.Height / 2; + // aTopLeft needs correction for rotated customshapes + if (pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE) + { + const tools::Rectangle& aSnapRect(pObj->GetSnapRect()); // bounding box of the rotated shape + aTopLeft.X = aSnapRect.getX() + (aSnapRect.GetWidth() / 2) - nHalfWidth; + aTopLeft.Y = aSnapRect.getY() + (aSnapRect.GetHeight() / 2) - nHalfHeight; + } + + // MSO changes the anchor positions at these angles and that does an extra 90 degrees + // rotation on our shapes, so we output it in such position that MSO + // can draw this shape correctly. + if ((nRotation >= 45 * 100 && nRotation < 135 * 100) || (nRotation >= 225 * 100 && nRotation < 315 * 100)) + { + aTopLeft.X = aTopLeft.X - nHalfHeight + nHalfWidth; + aTopLeft.Y = aTopLeft.Y - nHalfWidth + nHalfHeight; + + std::swap(aSize.Width, aSize.Height); + } + } + } + + tools::Rectangle aLocation(aTopLeft.X, aTopLeft.Y, aTopLeft.X + aSize.Width, aTopLeft.Y + aSize.Height); + double nXpos = static_cast<double>(aLocation.TopLeft().getX()) / static_cast<double>(aPageSize.Width); + double nYpos = static_cast<double>(aLocation.TopLeft().getY()) / static_cast<double>(aPageSize.Height); + + pDrawing->startElement(FSNS(XML_cdr, XML_from)); + pDrawing->startElement(FSNS(XML_cdr, XML_x)); + pDrawing->write(nXpos); + pDrawing->endElement(FSNS(XML_cdr, XML_x)); + pDrawing->startElement(FSNS(XML_cdr, XML_y)); + pDrawing->write(nYpos); + pDrawing->endElement(FSNS(XML_cdr, XML_y)); + pDrawing->endElement(FSNS(XML_cdr, XML_from)); + + nXpos = static_cast<double>(aLocation.BottomRight().getX()) / static_cast<double>(aPageSize.Width); + nYpos = static_cast<double>(aLocation.BottomRight().getY()) / static_cast<double>(aPageSize.Height); + + pDrawing->startElement(FSNS(XML_cdr, XML_to)); + pDrawing->startElement(FSNS(XML_cdr, XML_x)); + pDrawing->write(nXpos); + pDrawing->endElement(FSNS(XML_cdr, XML_x)); + pDrawing->startElement(FSNS(XML_cdr, XML_y)); + pDrawing->write(nYpos); + pDrawing->endElement(FSNS(XML_cdr, XML_y)); + pDrawing->endElement(FSNS(XML_cdr, XML_to)); +} + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/token/relationship.inc b/oox/source/token/relationship.inc index 2b973ded1653..e0b282c94848 100644 --- a/oox/source/token/relationship.inc +++ b/oox/source/token/relationship.inc @@ -1,5 +1,6 @@ {Relationship::ACTIVEXCONTROLBINARY, "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary"}, {Relationship::CHART, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"}, +{Relationship::CHARTUSERSHAPES, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartUserShapes"}, {Relationship::COMMENTS, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"}, {Relationship::COMMENTAUTHORS, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/commentAuthors"}, {Relationship::CONTROL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control"}, diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index 27396f5b8dfa..e81ff50a217c 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -1024,6 +1024,7 @@ byte c c15 cBhvr +cdr cGp cGpRule cMediaNode diff --git a/sc/source/filter/excel/xeescher.cxx b/sc/source/filter/excel/xeescher.cxx index 22c2462df750..37bb6593b62a 100644 --- a/sc/source/filter/excel/xeescher.cxx +++ b/sc/source/filter/excel/xeescher.cxx @@ -1248,7 +1248,7 @@ OUString XclExpTbxControlObj::SaveControlPropertiesXml(XclExpXmlStream& rStrm) c { case EXC_OBJTYPE_CHECKBOX: { - const sal_Int32 nDrawing = XclExpObjList::getNewDrawingUniqueId(); + const sal_Int32 nDrawing = DrawingML::getNewDrawingUniqueId(); sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream( XclXmlUtils::GetStreamName( "xl/", "ctrlProps/ctrlProps", nDrawing ), XclXmlUtils::GetStreamName( "../", "ctrlProps/ctrlProps", nDrawing ), diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index f7b0c77f1381..14e0fb24be2c 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -1021,7 +1021,7 @@ bool XclExpXmlStream::exportDocument() // SfxMedium::GetOutStream() anywhere in the xlsx export filter code! // Instead, write via XOutputStream instance. tools::SvRef<SotStorage> rStorage = static_cast<SotStorage*>(nullptr); - XclExpObjList::ResetCounters(); + drawingml::DrawingML::ResetMlCounters(); XclExpRootData aData( EXC_BIFF8, *pShell->GetMedium (), rStorage, rDoc, diff --git a/sc/source/filter/inc/xcl97rec.hxx b/sc/source/filter/inc/xcl97rec.hxx index 90ca18c8990c..8b6f55e494ac 100644 --- a/sc/source/filter/inc/xcl97rec.hxx +++ b/sc/source/filter/inc/xcl97rec.hxx @@ -82,12 +82,7 @@ public: virtual void Save( XclExpStream& rStrm ) override; virtual void SaveXml( XclExpXmlStream& rStrm ) override; - static void ResetCounters(); - - static sal_Int32 getNewDrawingUniqueId() { return ++mnDrawingMLCount; } - private: - static sal_Int32 mnDrawingMLCount, mnVmlCount; SCTAB mnScTab; XclEscherEx& mrEscherEx; diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx index 1fde9272f3f5..da087a93c2f4 100644 --- a/sc/source/filter/xcl97/xcl97rec.cxx +++ b/sc/source/filter/xcl97/xcl97rec.cxx @@ -81,9 +81,6 @@ using ::oox::drawingml::ShapeExport; using ::oox::vml::VMLExport; using namespace oox; -sal_Int32 XclExpObjList::mnDrawingMLCount; -sal_Int32 XclExpObjList::mnVmlCount; - XclExpObjList::XclExpObjList( const XclExpRoot& rRoot, XclEscherEx& rEscherEx ) : XclExpRoot( rRoot ), mnScTab( rRoot.GetCurrScTab() ), @@ -237,7 +234,7 @@ void SaveDrawingMLObjects( XclExpObjList& rList, XclExpXmlStream& rStrm ) if (aList.empty()) return; - sal_Int32 nDrawing = XclExpObjList::getNewDrawingUniqueId(); + sal_Int32 nDrawing = drawingml::DrawingML::getNewDrawingUniqueId(); OUString sId; sax_fastparser::FSHelperPtr pDrawing = rStrm.CreateOutputStream( XclXmlUtils::GetStreamName( "xl/", "drawings/drawing", nDrawing ), @@ -318,12 +315,12 @@ void SaveFormControlObjects(XclExpObjList& rList, XclExpXmlStream& rStrm) rWorksheet->endElement(FSNS(XML_mc, XML_AlternateContent)); } -void SaveVmlObjects( XclExpObjList& rList, XclExpXmlStream& rStrm, sal_Int32& nVmlCount ) +void SaveVmlObjects( XclExpObjList& rList, XclExpXmlStream& rStrm ) { if( GetVmlObjectCount( rList ) == 0 ) return; - sal_Int32 nDrawing = ++nVmlCount; + sal_Int32 nDrawing = drawingml::DrawingML::getNewVMLUniqueId(); OUString sId; sax_fastparser::FSHelperPtr pVmlDrawing = rStrm.CreateOutputStream( XclXmlUtils::GetStreamName( "xl/", "drawings/vmlDrawing", nDrawing ), @@ -365,16 +362,10 @@ void XclExpObjList::SaveXml( XclExpXmlStream& rStrm ) return; SaveDrawingMLObjects( *this, rStrm ); - SaveVmlObjects( *this, rStrm, mnVmlCount ); + SaveVmlObjects( *this, rStrm ); SaveFormControlObjects( *this, rStrm ); } -void XclExpObjList::ResetCounters() -{ - mnDrawingMLCount = 0; - mnVmlCount = 0; -} - // --- class XclObj -------------------------------------------------- XclObj::XclObj( XclExpObjectManager& rObjMgr, sal_uInt16 nObjType, bool bOwnEscher ) : |