oox/source/drawingml/diagram/diagram.hxx | 10 ++++ oox/source/drawingml/diagram/diagramlayoutatoms.cxx | 27 ++++++++++-- oox/source/drawingml/diagram/diagramlayoutatoms.hxx | 18 ++++++-- oox/source/drawingml/diagram/layoutatomvisitors.cxx | 38 ++++++++++++++---- oox/source/drawingml/diagram/layoutatomvisitors.hxx | 6 ++ oox/source/drawingml/diagram/layoutnodecontext.cxx | 5 +- sd/qa/unit/data/pptx/smartart-recursion.pptx |binary sd/qa/unit/import-tests-smartart.cxx | 42 ++++++++++++++++++++ 8 files changed, 128 insertions(+), 18 deletions(-)
New commits: commit 674d58312a3682df6be2cf8680aab4e3d1528789 Author: Grzegorz Araminowicz <grzegorz.araminow...@collabora.com> AuthorDate: Tue Jun 11 08:31:18 2019 +0200 Commit: Grzegorz Araminowicz <grzegorz.araminow...@collabora.com> CommitDate: Wed Jul 10 22:11:24 2019 +0200 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 <grzegorz.araminow...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/75340 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/oox/source/drawingml/diagram/diagram.hxx b/oox/source/drawingml/diagram/diagram.hxx index a0955b124230..c5b8ec10eaf6 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<LayoutAtom> LayoutAtomPtr; typedef std::map< OUString, css::uno::Reference<css::xml::dom::XDocument> > DiagramDomMap; @@ -205,6 +207,8 @@ private: typedef std::shared_ptr< DiagramData > DiagramDataPtr; +typedef std::map<OUString, LayoutAtomPtr> 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 ad4e8962a4a4..63aceb0df920 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -281,6 +281,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 0291b87cc97a..842acc0757f6 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -191,10 +191,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 5b79dafbc46b..d7c8448666fb 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().mnAxis == XML_followSib) { // If the axis is the follow sibling, then the last atom should not be @@ -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 10070063c8ec..0d022ca41504 100644 --- a/oox/source/drawingml/diagram/layoutnodecontext.cxx +++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx @@ -142,8 +142,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 930006fd3931..59d09a7d4204 100644 --- a/sd/qa/unit/import-tests-smartart.cxx +++ b/sd/qa/unit/import-tests-smartart.cxx @@ -76,6 +76,7 @@ public: void testFontSize(); void testVerticalBlockList(); void testBulletList(); + void testRecursion(); CPPUNIT_TEST_SUITE(SdImportTestSmartArt); @@ -114,6 +115,7 @@ public: CPPUNIT_TEST(testFontSize); CPPUNIT_TEST(testVerticalBlockList); CPPUNIT_TEST(testBulletList); + CPPUNIT_TEST(testRecursion); CPPUNIT_TEST_SUITE_END(); }; @@ -1105,6 +1107,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<drawing::XShapes> xGroup(getShapeFromPage(0, 0, xDocShRef), uno::UNO_QUERY); + uno::Reference<drawing::XShapes> xGroup1(xGroup->getByIndex(1), uno::UNO_QUERY); + + uno::Reference<drawing::XShapes> xGroupA(xGroup1->getByIndex(0), uno::UNO_QUERY); + uno::Reference<text::XText> xTextA(xGroupA->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("A"), xTextA->getString()); + + uno::Reference<drawing::XShapes> xGroupB(xGroup1->getByIndex(1), uno::UNO_QUERY); + // 5 connectors, B1 with children, B2 with children + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(7), xGroupB->getCount()); + + uno::Reference<drawing::XShapes> xGroupB1(xGroupB->getByIndex(1), uno::UNO_QUERY); + + uno::Reference<drawing::XShapes> xGroupB1a(xGroupB1->getByIndex(0), uno::UNO_QUERY); + uno::Reference<text::XText> xTextB1(xGroupB1a->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("B1"), xTextB1->getString()); + + uno::Reference<drawing::XShape> xGroupC12(xGroupB1->getByIndex(1), uno::UNO_QUERY); + uno::Reference<text::XText> xTextC1(getChildShape(getChildShape(getChildShape(xGroupC12, 0), 0), 0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("C1"), xTextC1->getString()); + uno::Reference<text::XText> xTextC2(getChildShape(getChildShape(getChildShape(xGroupC12, 1), 0), 0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("C2"), xTextC2->getString()); + + uno::Reference<drawing::XShapes> xGroupB2(xGroupB->getByIndex(5), uno::UNO_QUERY); + + uno::Reference<drawing::XShapes> xGroupB2a(xGroupB2->getByIndex(0), uno::UNO_QUERY); + uno::Reference<text::XText> xTextB2(xGroupB2a->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("B2"), xTextB2->getString()); + + uno::Reference<drawing::XShape> xGroupC3(xGroupB2->getByIndex(1), uno::UNO_QUERY); + uno::Reference<text::XText> 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); commit 70f9f5fb2a724373742285ecc1e74393d5226421 Author: Grzegorz Araminowicz <grzegorz.araminow...@collabora.com> AuthorDate: Fri Jun 14 15:12:33 2019 +0200 Commit: Grzegorz Araminowicz <grzegorz.araminow...@collabora.com> CommitDate: Wed Jul 10 22:11:13 2019 +0200 SmartArt: support multiple levels of shapes in LayoutNodes it is needed for recurrent ForEach node, so that shapes on different levels are divided and can be layouted separately Change-Id: Iefbc82925078fe2346858748259680fa8ea252d6 Reviewed-on: https://gerrit.libreoffice.org/74043 Tested-by: Jenkins Reviewed-by: Grzegorz Araminowicz <grzegorz.araminow...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/75366 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx index a4b80548e3dd..ad4e8962a4a4 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -159,12 +159,16 @@ bool containsDataNodeType(const oox::drawingml::ShapePtr& pShape, sal_Int32 nTyp */ void calculateHierChildOffsetScale(const oox::drawingml::ShapePtr& pShape, const oox::drawingml::LayoutNode* pParent, sal_Int32& rXOffset, - double& rWidthScale) + double& rWidthScale, sal_Int32 nLevel) { if (!pParent) return; - const std::vector<oox::drawingml::ShapePtr>& rParents = pParent->getNodeShapes(); + auto pShapes = pParent->getNodeShapes().find(nLevel - 1); + if (pShapes == pParent->getNodeShapes().end()) + return; + + const std::vector<oox::drawingml::ShapePtr>& rParents = pShapes->second; for (size_t nParent = 0; nParent < rParents.size(); ++nParent) { const oox::drawingml::ShapePtr& pParentShape = rParents[nParent]; @@ -499,7 +503,8 @@ void AlgAtom::accept( LayoutAtomVisitor& rVisitor ) } void AlgAtom::layoutShape( const ShapePtr& rShape, - const std::vector<Constraint>& rConstraints ) + const std::vector<Constraint>& rConstraints, + sal_Int32 nShapeLevel ) { switch(mnType) { @@ -743,7 +748,7 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, sal_Int32 nXOffset = 0; double fWidthScale = 1.0; if (mnType == XML_hierChild) - calculateHierChildOffsetScale(rShape, getLayoutNode().getParentLayoutNode(), nXOffset, fWidthScale); + calculateHierChildOffsetScale(rShape, getLayoutNode().getParentLayoutNode(), nXOffset, fWidthScale, nShapeLevel); awt::Size aChildSize = rShape->getSize(); if (nDir == XML_fromT) diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx index d70878e063aa..0291b87cc97a 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -161,7 +161,8 @@ public: void addParam( sal_Int32 nType, sal_Int32 nVal ) { maMap[nType]=nVal; } void layoutShape( const ShapePtr& rShape, - const std::vector<Constraint>& rConstraints ); + const std::vector<Constraint>& rConstraints, + sal_Int32 nShapeLevel ); /// Gives access to <dgm:alg type="..."/>. sal_Int32 getType() const { return mnType; } @@ -239,6 +240,7 @@ class LayoutNode { public: typedef std::map<sal_Int32, OUString> VarMap; + typedef std::map<sal_Int32, std::vector<ShapePtr>> ShapeLevelMap; LayoutNode(const Diagram& rDgm) : LayoutAtom(*this), mrDgm(rDgm), mnChildOrder(0) {} const Diagram& getDiagram() const @@ -256,10 +258,10 @@ public: { mpExistingShape = pShape; } const ShapePtr& getExistingShape() const { return mpExistingShape; } - const std::vector<ShapePtr> & getNodeShapes() const + const ShapeLevelMap& getNodeShapes() const { return mpNodeShapes; } - void addNodeShape(const ShapePtr& pShape) - { mpNodeShapes.push_back(pShape); } + void addNodeShape(const ShapePtr& pShape, sal_Int32 nLevel) + { mpNodeShapes[nLevel].push_back(pShape); } bool setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode ) const; @@ -276,7 +278,7 @@ private: OUString msMoveWith; OUString msStyleLabel; ShapePtr mpExistingShape; - std::vector<ShapePtr> mpNodeShapes; + ShapeLevelMap mpNodeShapes; sal_Int32 mnChildOrder; std::weak_ptr<AlgAtom> mpAlgAtom; }; diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx index 4e1a3689e3e4..5b79dafbc46b 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx @@ -135,7 +135,7 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) pShape->setInternalName(rAtom.getName()); if (AlgAtomPtr pAlgAtom = rAtom.getAlgAtom()) pShape->setAspectRatio(pAlgAtom->getAspectRatio()); - rAtom.addNodeShape(pShape); + rAtom.addNodeShape(pShape, mnCurrLevel); } } else @@ -148,9 +148,8 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) { SAL_INFO( "oox.drawingml", - "processing shape type " - << (pShape->getCustomShapeProperties() - ->getShapePresetType())); + "processing shape type " << (pShape->getCustomShapeProperties()->getShapePresetType()) + << " level " << mnCurrLevel); if (rAtom.setupShape(pShape, pNewNode)) { @@ -159,7 +158,7 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) pShape->setAspectRatio(pAlgAtom->getAspectRatio()); pCurrParent->addChild(pShape); pCurrParent = pShape; - rAtom.addNodeShape(pShape); + rAtom.addNodeShape(pShape, mnCurrLevel); } } else @@ -174,11 +173,13 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) // set new parent for children ShapePtr pPreviousParent(mpParentShape); mpParentShape=pCurrParent; + mnCurrLevel++; // process children defaultVisit(rAtom); // restore parent + mnCurrLevel--; mpParentShape=pPreviousParent; mpCurrentNode = pPreviousNode; @@ -266,8 +267,10 @@ void ShapeLayoutingVisitor::visit(AlgAtom& rAtom) { if (meLookFor == ALGORITHM) { - for (const auto& pShape : rAtom.getLayoutNode().getNodeShapes()) - rAtom.layoutShape(pShape, maConstraints); + auto pShapes = rAtom.getLayoutNode().getNodeShapes().find(mnCurrLevel); + if (pShapes != rAtom.getLayoutNode().getNodeShapes().end()) + for (const auto& pShape : pShapes->second) + rAtom.layoutShape(pShape, maConstraints, mnCurrLevel); } } @@ -291,6 +294,10 @@ void ShapeLayoutingVisitor::visit(LayoutNode& rAtom) if (meLookFor != LAYOUT_NODE) return; + // stop processing if there is no more shapes on this level + if (rAtom.getNodeShapes().empty() || mnCurrLevel > rAtom.getNodeShapes().rbegin()->first) + return; + size_t nParentConstraintsNumber = maConstraints.size(); // process alg atoms first, nested layout nodes afterwards @@ -298,8 +305,11 @@ void ShapeLayoutingVisitor::visit(LayoutNode& rAtom) defaultVisit(rAtom); meLookFor = ALGORITHM; defaultVisit(rAtom); + + mnCurrLevel++; meLookFor = LAYOUT_NODE; defaultVisit(rAtom); + mnCurrLevel--; // delete added constraints, keep parent constraints maConstraints.erase(maConstraints.begin() + nParentConstraintsNumber, maConstraints.end()); diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.hxx b/oox/source/drawingml/diagram/layoutatomvisitors.hxx index f395f6a68668..4a61a75eb0f5 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.hxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.hxx @@ -35,6 +35,7 @@ class ShapeCreationVisitor : public LayoutAtomVisitor sal_Int32 mnCurrIdx; sal_Int32 mnCurrStep = 0; sal_Int32 mnCurrCnt = 0; + sal_Int32 mnCurrLevel; const dgm::Point* mpCurrentNode; void defaultVisit(LayoutAtom const & rAtom); @@ -52,6 +53,7 @@ public: mpParentShape(rParentShape), mrDgm(rDgm), mnCurrIdx(0), + mnCurrLevel(0), mpCurrentNode(rDgm.getData()->getRootPoint()) {} }; @@ -78,6 +80,7 @@ class ShapeLayoutingVisitor : public LayoutAtomVisitor { std::vector<Constraint> maConstraints; enum {LAYOUT_NODE, CONSTRAINT, ALGORITHM} meLookFor; + sal_Int32 mnCurrLevel; void defaultVisit(LayoutAtom const & rAtom); virtual void visit(ConstraintAtom& rAtom) override; @@ -90,7 +93,8 @@ class ShapeLayoutingVisitor : public LayoutAtomVisitor public: ShapeLayoutingVisitor() : - meLookFor(LAYOUT_NODE) + meLookFor(LAYOUT_NODE), + mnCurrLevel(0) {} }; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits