From 76478f9938a5f6d96ac65b3b633280024b60baed Mon Sep 17 00:00:00 2001 From: Grzegorz Araminowicz Date: Tue, 11 Jun 2019 08:31:18 +0200 Subject: SmartArt: support ForEach references ForEach 'ref' parameter causes specified ForEach node to be used instead. Used to create recursive structures like organisation charts. Change-Id: Iee61b2e103759355b59beb8d3f33eb3cce47c590 Reviewed-on: https://gerrit.libreoffice.org/74271 Tested-by: Jenkins Reviewed-by: Grzegorz Araminowicz --- oox/source/drawingml/diagram/diagram.hxx | 10 +++++ .../drawingml/diagram/diagramlayoutatoms.cxx | 14 +++++++ .../drawingml/diagram/diagramlayoutatoms.hxx | 6 +++ .../drawingml/diagram/layoutatomvisitors.cxx | 14 +++++++ oox/source/drawingml/diagram/layoutnodecontext.cxx | 5 ++- sd/qa/unit/data/pptx/smartart-recursion.pptx | Bin 0 -> 52943 bytes sd/qa/unit/import-tests-smartart.cxx | 42 +++++++++++++++++++++ 7 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 sd/qa/unit/data/pptx/smartart-recursion.pptx diff --git a/oox/source/drawingml/diagram/diagram.hxx b/oox/source/drawingml/diagram/diagram.hxx index 91cb0f39fd2c..cf12dce576a7 100644 --- a/oox/source/drawingml/diagram/diagram.hxx +++ b/oox/source/drawingml/diagram/diagram.hxx @@ -149,6 +149,8 @@ typedef std::vector< Point > Points; class Diagram; class LayoutNode; typedef std::shared_ptr< LayoutNode > LayoutNodePtr; +class LayoutAtom; +typedef std::shared_ptr LayoutAtomPtr; typedef std::map< OUString, css::uno::Reference > DiagramDomMap; @@ -205,6 +207,8 @@ private: typedef std::shared_ptr< DiagramData > DiagramDataPtr; +typedef std::map LayoutAtomMap; + class DiagramLayout { public: @@ -233,6 +237,8 @@ public: { return mpStyleData; } const DiagramDataPtr & getStyleData() const { return mpStyleData; } + LayoutAtomMap & getLayoutAtomMap() + { return maLayoutAtomMap; } private: const Diagram& mrDgm; @@ -248,6 +254,8 @@ private: // TODO // catLst // clrData + + LayoutAtomMap maLayoutAtomMap; }; typedef std::shared_ptr< DiagramLayout > DiagramLayoutPtr; @@ -283,6 +291,8 @@ public: { return mpData; } void setLayout( const DiagramLayoutPtr & pLayout ) { mpLayout = pLayout; } + const DiagramLayoutPtr& getLayout() const + { return mpLayout; } DiagramQStyleMap& getStyles() { return maStyles; } const DiagramQStyleMap& getStyles() const { return maStyles; } diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx index f9c443c5d626..6497e3ba22cf 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -229,6 +229,20 @@ void ForEachAtom::accept( LayoutAtomVisitor& rVisitor ) rVisitor.visit(*this); } +LayoutAtomPtr ForEachAtom::getRefAtom() +{ + if (!msRef.isEmpty()) + { + const LayoutAtomMap& rLayoutAtomMap = getLayoutNode().getDiagram().getLayout()->getLayoutAtomMap(); + LayoutAtomMap::const_iterator pRefAtom = rLayoutAtomMap.find(msRef); + if (pRefAtom != rLayoutAtomMap.end()) + return pRefAtom->second; + else + SAL_WARN("oox.drawingml", "ForEach reference \"" << msRef << "\" not found"); + } + return LayoutAtomPtr(); +} + void ChooseAtom::accept( LayoutAtomVisitor& rVisitor ) { rVisitor.visit(*this); diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx index 8a11ed5cbac8..9fff33686dd6 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -188,10 +188,16 @@ public: IteratorAttr & iterator() { return maIter; } + void setRef(const OUString& rsRef) + { msRef = rsRef; } + const OUString& getRef() const + { return msRef; } virtual void accept( LayoutAtomVisitor& ) override; + LayoutAtomPtr getRefAtom(); private: IteratorAttr maIter; + OUString msRef; }; typedef std::shared_ptr< ForEachAtom > ForEachAtomPtr; diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx index cd7b82aa9efd..5d6f0065241d 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx @@ -48,6 +48,13 @@ void ShapeCreationVisitor::visit(AlgAtom& rAtom) void ShapeCreationVisitor::visit(ForEachAtom& rAtom) { + if (!rAtom.getRef().isEmpty()) + { + if (LayoutAtomPtr pRefAtom = rAtom.getRefAtom()) + pRefAtom->accept(*this); + return; + } + if (rAtom.iterator().mbHideLastTrans && rAtom.iterator().mnAxis == XML_followSib) { // If last transition is hidden and the axis is the follow sibling, @@ -276,6 +283,13 @@ void ShapeLayoutingVisitor::visit(AlgAtom& rAtom) void ShapeLayoutingVisitor::visit(ForEachAtom& rAtom) { + if (!rAtom.getRef().isEmpty()) + { + if (LayoutAtomPtr pRefAtom = rAtom.getRefAtom()) + pRefAtom->accept(*this); + return; + } + defaultVisit(rAtom); } diff --git a/oox/source/drawingml/diagram/layoutnodecontext.cxx b/oox/source/drawingml/diagram/layoutnodecontext.cxx index e984862c44b4..8e3e3c2f6eb4 100644 --- a/oox/source/drawingml/diagram/layoutnodecontext.cxx +++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx @@ -141,8 +141,11 @@ public: ForEachContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, const ForEachAtomPtr& pAtom ) : LayoutNodeContext( rParent, rAttribs, pAtom ) { - rAttribs.getString( XML_ref ); + pAtom->setRef(rAttribs.getString(XML_ref).get()); pAtom->iterator().loadFromXAttr( rAttribs.getFastAttributeList() ); + + LayoutAtomMap& rLayoutAtomMap = pAtom->getLayoutNode().getDiagram().getLayout()->getLayoutAtomMap(); + rLayoutAtomMap[pAtom->getName()] = pAtom; } }; diff --git a/sd/qa/unit/data/pptx/smartart-recursion.pptx b/sd/qa/unit/data/pptx/smartart-recursion.pptx new file mode 100644 index 000000000000..205db6b703de Binary files /dev/null and b/sd/qa/unit/data/pptx/smartart-recursion.pptx differ diff --git a/sd/qa/unit/import-tests-smartart.cxx b/sd/qa/unit/import-tests-smartart.cxx index 775411c57bba..944e583df040 100644 --- a/sd/qa/unit/import-tests-smartart.cxx +++ b/sd/qa/unit/import-tests-smartart.cxx @@ -79,6 +79,7 @@ public: void testFontSize(); void testVerticalBlockList(); void testBulletList(); + void testRecursion(); CPPUNIT_TEST_SUITE(SdImportTestSmartArt); @@ -119,6 +120,7 @@ public: CPPUNIT_TEST(testFontSize); CPPUNIT_TEST(testVerticalBlockList); CPPUNIT_TEST(testBulletList); + CPPUNIT_TEST(testRecursion); CPPUNIT_TEST_SUITE_END(); }; @@ -1273,6 +1275,46 @@ void SdImportTestSmartArt::testBulletList() xDocShRef->DoClose(); } +void SdImportTestSmartArt::testRecursion() +{ + sd::DrawDocShellRef xDocShRef = loadURL( + m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/smartart-recursion.pptx"), PPTX); + + uno::Reference xGroup(getShapeFromPage(0, 0, xDocShRef), uno::UNO_QUERY); + uno::Reference xGroup1(xGroup->getByIndex(1), uno::UNO_QUERY); + + uno::Reference xGroupA(xGroup1->getByIndex(0), uno::UNO_QUERY); + uno::Reference xTextA(xGroupA->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("A"), xTextA->getString()); + + uno::Reference xGroupB(xGroup1->getByIndex(1), uno::UNO_QUERY); + // 5 connectors, B1 with children, B2 with children + CPPUNIT_ASSERT_EQUAL(static_cast(7), xGroupB->getCount()); + + uno::Reference xGroupB1(xGroupB->getByIndex(1), uno::UNO_QUERY); + + uno::Reference xGroupB1a(xGroupB1->getByIndex(0), uno::UNO_QUERY); + uno::Reference xTextB1(xGroupB1a->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("B1"), xTextB1->getString()); + + uno::Reference xGroupC12(xGroupB1->getByIndex(1), uno::UNO_QUERY); + uno::Reference xTextC1(getChildShape(getChildShape(getChildShape(xGroupC12, 0), 0), 0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("C1"), xTextC1->getString()); + uno::Reference xTextC2(getChildShape(getChildShape(getChildShape(xGroupC12, 1), 0), 0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("C2"), xTextC2->getString()); + + uno::Reference xGroupB2(xGroupB->getByIndex(5), uno::UNO_QUERY); + + uno::Reference xGroupB2a(xGroupB2->getByIndex(0), uno::UNO_QUERY); + uno::Reference xTextB2(xGroupB2a->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("B2"), xTextB2->getString()); + + uno::Reference xGroupC3(xGroupB2->getByIndex(1), uno::UNO_QUERY); + uno::Reference xTextC3(getChildShape(getChildShape(getChildShape(xGroupC3, 0), 0), 0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("C3"), xTextC3->getString()); + + xDocShRef->DoClose(); +} CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTestSmartArt); -- cgit v1.2.3