include/oox/drawingml/shape.hxx | 14 oox/source/drawingml/diagram/diagramlayoutatoms.cxx | 176 ++++++++++-- oox/source/drawingml/diagram/diagramlayoutatoms.hxx | 9 oox/source/drawingml/diagram/layoutatomvisitors.cxx | 48 +++ oox/source/drawingml/diagram/layoutatomvisitors.hxx | 2 oox/source/drawingml/diagram/layoutnodecontext.cxx | 2 oox/source/drawingml/shape.cxx | 2 sd/qa/unit/data/pptx/smartart-accent-process.pptx |binary sd/qa/unit/data/pptx/smartart-continuous-block-process.pptx |binary sd/qa/unit/import-tests-smartart.cxx | 126 ++++++++ 10 files changed, 352 insertions(+), 27 deletions(-)
New commits: commit 73cc724dc35551ea349b3da0c4ecd6cba2fdd0ae Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Nov 13 18:00:50 2018 +0100 Commit: Caolán McNamara <caol...@redhat.com> CommitDate: Wed Dec 19 22:09:44 2018 +0100 Related: tdf#117761 oox smartart: backport fixes related to process types This is a combination of 9 commits. This is the 1st commit: oox smartart, accent process: add support for reading values from constraints (cherry picked from commit b389aafee9cfba9dc4dfa552347be39ff9fe41b2) This is the commit #2: oox smartart, accent process: add support for zorder offsets (cherry picked from commit cd348a6244a092c251a8e1362cd78de562d7bef6) This is the commit #3: oox smartart, accent process: fix overlapping shape pairs (cherry picked from commit 67e062aa5e5946d4985921fe2b6f87766f363ddc) This is the commit #4: oox smartart, accent process: handle multiple runs from a data point (cherry picked from commit cfa76f538a44d4396574ece59e8a3953c22c6eb7) This is the commit #5: oox smartart, accent process: handle followSib axis of forEach (cherry picked from commit aedc5427e4b6645ff3257e523c33190cf5e1934d) This is the commit #6: oox smartart, accent process: handle connector shape between pairs (cherry picked from commit 7f66a340933339974b5c6d70af4ae3c17e4f001a) This is the commit #7: oox smartart, accent process: adjust size of connector from constraints (cherry picked from commit ddc2786831367577967e806d603f337a2e42806a) This is the commit #8: oox smartart, continuous block process: read space width from constraint (cherry picked from commit ee6787fc5597b7f730c4ee3a1f2a1b261d0a5644) Conflicts: oox/source/drawingml/diagram/diagramlayoutatoms.cxx This is the commit #9: oox smartart, accent process: fix missing bullets and large para indent (cherry picked from commit 6277a767f33bb5327408dafff2fed199087e938d) Change-Id: I60bbee75f3e834551ebb1963a2f42101f3bd91d4 Reviewed-on: https://gerrit.libreoffice.org/65352 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> diff --git a/include/oox/drawingml/shape.hxx b/include/oox/drawingml/shape.hxx index 6028a11c2bc0..e04a58beb4a6 100644 --- a/include/oox/drawingml/shape.hxx +++ b/include/oox/drawingml/shape.hxx @@ -214,6 +214,14 @@ public: const LinkedTxbxAttr& getLinkedTxbxAttributes() { return maLinkedTxbxAttr; }; bool isLinkedTxbx() { return mbHasLinkedTxbx; }; + void setZOrder(sal_Int32 nZOrder) { mnZOrder = nZOrder; } + + sal_Int32 getZOrder() const { return mnZOrder; } + + void setZOrderOff(sal_Int32 nZOrderOff) { mnZOrderOff = nZOrderOff; } + + sal_Int32 getZOrderOff() const { return mnZOrderOff; } + protected: css::uno::Reference< css::drawing::XShape > const & @@ -327,6 +335,12 @@ private: bool mbHasLinkedTxbx; // this text box has linked text box ? css::uno::Sequence<css::beans::PropertyValue> maDiagramDoms; + + /// Z-Order. + sal_Int32 mnZOrder = 0; + + /// Z-Order offset. + sal_Int32 mnZOrderOff = 0; }; } } diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx index c1aaf6e07025..502470933e8f 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -54,6 +54,50 @@ oox::OptValue<sal_Int32> findProperty(const oox::drawingml::LayoutPropertyMap& r return oRet; } + +/** + * Determines if nUnit is a font unit (measured in points) or not (measured in + * millimeters). + */ +bool isFontUnit(sal_Int32 nUnit) +{ + return nUnit == oox::XML_primFontSz || nUnit == oox::XML_secFontSz; +} + +/// Determines the connector shape type from a linear alg. +sal_Int32 getConnectorType(const oox::drawingml::LayoutNode* pNode) +{ + sal_Int32 nType = oox::XML_rightArrow; + + if (!pNode) + return nType; + + for (const auto& pChild : pNode->getChildren()) + { + auto pAlgAtom = dynamic_cast<oox::drawingml::AlgAtom*>(pChild.get()); + if (!pAlgAtom) + continue; + + if (pAlgAtom->getType() != oox::XML_lin) + continue; + + sal_Int32 nDir = oox::XML_fromL; + if (pAlgAtom->getMap().count(oox::XML_linDir)) + nDir = pAlgAtom->getMap().find(oox::XML_linDir)->second; + + switch (nDir) + { + case oox::XML_fromL: + nType = oox::XML_rightArrow; + break; + case oox::XML_fromR: + nType = oox::XML_leftArrow; + break; + } + } + + return nType; +} } namespace oox { namespace drawingml { @@ -269,13 +313,15 @@ void ConstraintAtom::accept( LayoutAtomVisitor& rVisitor ) rVisitor.visit(*this); } -void ConstraintAtom::parseConstraint(std::vector<Constraint>& rConstraints) const +void ConstraintAtom::parseConstraint(std::vector<Constraint>& rConstraints, + bool bRequireForName) const { + if (bRequireForName && maConstraint.msForName.isEmpty()) + return; + // accepting only basic equality constraints - if (!maConstraint.msForName.isEmpty() && - (maConstraint.mnOperator == XML_none || maConstraint.mnOperator == XML_equ) && - maConstraint.mnType != XML_none && - maConstraint.mfValue == 0) + if ((maConstraint.mnOperator == XML_none || maConstraint.mnOperator == XML_equ) + && maConstraint.mnType != XML_none) { rConstraints.push_back(maConstraint); } @@ -290,7 +336,7 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, const std::vector<Constraint>& rOwnConstraints ) const { // Algorithm result may depend on the parent constraints as well. - std::vector<Constraint> aParentConstraints; + std::vector<Constraint> aMergedConstraints; const LayoutNode* pParent = getLayoutNode().getParentLayoutNode(); if (pParent) { @@ -298,10 +344,12 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, { auto pConstraintAtom = dynamic_cast<ConstraintAtom*>(pChild.get()); if (pConstraintAtom) - pConstraintAtom->parseConstraint(aParentConstraints); + pConstraintAtom->parseConstraint(aMergedConstraints, /*bRequireForName=*/true); } } - const std::vector<Constraint>& rConstraints = rOwnConstraints.empty() ? aParentConstraints : rOwnConstraints; + aMergedConstraints.insert(aMergedConstraints.end(), rOwnConstraints.begin(), + rOwnConstraints.end()); + const std::vector<Constraint>& rConstraints = aMergedConstraints; switch(mnType) { @@ -327,7 +375,19 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, if (aRefType != aRef->second.end()) aProperties[rConstr.msForName][rConstr.mnType] = aRefType->second * rConstr.mfFactor; else - aProperties[rConstr.msForName][rConstr.mnType] = 0; // TODO: val + { + // Values are never in EMU, while oox::drawingml::Shape + // position and size are always in EMU. + double fUnitFactor = 0; + if (isFontUnit(rConstr.mnRefType)) + // Points -> EMU. + fUnitFactor = EMU_PER_PT; + else + // Millimeters -> EMU. + fUnitFactor = EMU_PER_HMM * 100; + aProperties[rConstr.msForName][rConstr.mnType] + = rConstr.mfValue * fUnitFactor; + } } } @@ -376,7 +436,54 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, } case XML_conn: + { + if (rShape->getSubType() == XML_conn) + { + // There is no shape type "conn", replace it by an arrow based + // on the direction of the parent linear layout. + sal_Int32 nType = getConnectorType(pParent); + + rShape->setSubType(nType); + rShape->getCustomShapeProperties()->setShapePresetType(nType); + } + + // Parse constraints to adjust the size. + std::vector<Constraint> aDirectConstraints; + const LayoutNode& rLayoutNode = getLayoutNode(); + for (const auto& pChild : rLayoutNode.getChildren()) + { + auto pConstraintAtom = dynamic_cast<ConstraintAtom*>(pChild.get()); + if (pConstraintAtom) + pConstraintAtom->parseConstraint(aDirectConstraints, /*bRequireForName=*/false); + } + + LayoutPropertyMap aProperties; + LayoutProperty& rParent = aProperties[""]; + rParent[XML_w] = rShape->getSize().Width; + rParent[XML_h] = rShape->getSize().Height; + rParent[XML_l] = 0; + rParent[XML_t] = 0; + rParent[XML_r] = rShape->getSize().Width; + rParent[XML_b] = rShape->getSize().Height; + for (const auto& rConstr : aDirectConstraints) + { + const LayoutPropertyMap::const_iterator aRef + = aProperties.find(rConstr.msRefForName); + if (aRef != aProperties.end()) + { + const LayoutProperty::const_iterator aRefType + = aRef->second.find(rConstr.mnRefType); + if (aRefType != aRef->second.end()) + aProperties[rConstr.msForName][rConstr.mnType] + = aRefType->second * rConstr.mfFactor; + } + } + awt::Size aSize; + aSize.Width = rParent[XML_w]; + aSize.Height = rParent[XML_h]; + rShape->setSize(aSize); break; + } case XML_cycle: { @@ -428,22 +535,9 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, const sal_Int32 nIncX = nDir==XML_fromL ? 1 : (nDir==XML_fromR ? -1 : 0); const sal_Int32 nIncY = nDir==XML_fromT ? 1 : (nDir==XML_fromB ? -1 : 0); - // TODO: get values from constraints sal_Int32 nCount = rShape->getChildren().size(); double fSpace = 0.3; - awt::Size aChildSize = rShape->getSize(); - if (nDir == XML_fromL || nDir == XML_fromR) - aChildSize.Width /= (nCount + (nCount-1)*fSpace); - else if (nDir == XML_fromT || nDir == XML_fromB) - aChildSize.Height /= (nCount + (nCount-1)*fSpace); - - awt::Point aCurrPos(0, 0); - if (nIncX == -1) - aCurrPos.X = rShape->getSize().Width - aChildSize.Width; - if (nIncY == -1) - aCurrPos.Y = rShape->getSize().Height - aChildSize.Height; - // Find out which contraint is relevant for which (internal) name. LayoutPropertyMap aProperties; for (const auto& rConstraint : rConstraints) @@ -454,8 +548,24 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, LayoutProperty& rProperty = aProperties[rConstraint.msForName]; if (rConstraint.mnType == XML_w) rProperty[XML_w] = rShape->getSize().Width * rConstraint.mfFactor; + + // TODO: get values from differently named constraints as well + if (rConstraint.msForName == "sibTrans" && rConstraint.mnType == XML_w) + fSpace = rConstraint.mfFactor; } + awt::Size aChildSize = rShape->getSize(); + if (nDir == XML_fromL || nDir == XML_fromR) + aChildSize.Width /= (nCount + (nCount-1)*fSpace); + else if (nDir == XML_fromT || nDir == XML_fromB) + aChildSize.Height /= (nCount + (nCount-1)*fSpace); + + awt::Point aCurrPos(0, 0); + if (nIncX == -1) + aCurrPos.X = rShape->getSize().Width - aChildSize.Width; + if (nIncY == -1) + aCurrPos.Y = rShape->getSize().Height - aChildSize.Height; + // See if children requested more than 100% space in total: scale // down in that case. sal_Int32 nTotalWidth = 0; @@ -500,7 +610,7 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, aSize.Width *= fWidthScale; aCurrShape->setSize(aSize); - aCurrShape->setChildSize(aChildSize); + aCurrShape->setChildSize(aSize); aCurrPos.X += nIncX * (aSize.Width + fSpace*aSize.Width); aCurrPos.Y += nIncY * (aChildSize.Height + fSpace*aChildSize.Height); } @@ -711,13 +821,27 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, } ParamMap::const_iterator aBulletLvl = maMap.find(XML_stBulletLvl); + int nStartBulletsAtLevel = 0; if (aBulletLvl != maMap.end()) + { nBaseLevel -= aBulletLvl->second; + nStartBulletsAtLevel = aBulletLvl->second; + } for (auto & aParagraph : pTextBody->getParagraphs()) { sal_Int32 nLevel = aParagraph->getProperties().getLevel(); aParagraph->getProperties().setLevel(nLevel - nBaseLevel); + if (nStartBulletsAtLevel > 0 && nLevel >= nStartBulletsAtLevel) + { + // It is not possible to change the bullet style for text. + sal_Int32 nLeftMargin = 285750 * (nLevel - nStartBulletsAtLevel) / EMU_PER_HMM; + aParagraph->getProperties().getParaLeftMargin() = nLeftMargin; + aParagraph->getProperties().getFirstLineIndentation() = -285750 / EMU_PER_HMM; + OUString aBulletChar = OUString::fromUtf8(u8"•"); + aParagraph->getProperties().getBulletList().setBulletChar(aBulletChar); + aParagraph->getProperties().getBulletList().setSuffixNone(); + } } // explicit alignment @@ -821,8 +945,10 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode if( aVecIter->second != -1 ) rPara.getProperties().setLevel(aVecIter->second); - rPara.addRun( - aDataNode2->second->mpShape->getTextBody()->getParagraphs().front()->getRuns().front()); + std::shared_ptr<TextParagraph> pSourceParagraph + = aDataNode2->second->mpShape->getTextBody()->getParagraphs().front(); + for (const auto& pRun : pSourceParagraph->getRuns()) + rPara.addRun(pRun); rPara.getProperties().apply( aDataNode2->second->mpShape->getTextBody()->getParagraphs().front()->getProperties()); } diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx index 3d4d9c05aae2..500495b6f2ca 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -141,7 +141,7 @@ public: virtual void accept( LayoutAtomVisitor& ) override; Constraint& getConstraint() { return maConstraint; } - void parseConstraint(std::vector<Constraint>& rConstraints) const; + void parseConstraint(std::vector<Constraint>& rConstraints, bool bRequireForName) const; private: Constraint maConstraint; }; @@ -162,6 +162,13 @@ public: { maMap[nType]=nVal; } void layoutShape( const ShapePtr& rShape, const std::vector<Constraint>& rConstraints ) const; + + /// Gives access to <dgm:alg type="..."/>. + sal_Int32 getType() const { return mnType; } + + /// Gives access to <dgm:param type="..." val="..."/>. + const ParamMap& getMap() const { return maMap; } + private: sal_Int32 mnType; ParamMap maMap; diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx index ce8e6ab72b9e..49a664c1e821 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx @@ -46,6 +46,14 @@ void ShapeCreationVisitor::visit(AlgAtom& rAtom) void ShapeCreationVisitor::visit(ForEachAtom& rAtom) { + if (rAtom.iterator().mnAxis == XML_followSib) + { + // If the axis is the follow sibling, then the last atom should not be + // visited. + if (mnCurrIdx + mnCurrStep >= mnCurrCnt) + return; + } + const std::vector<LayoutAtomPtr>& rChildren=rAtom.getChildren(); sal_Int32 nChildren=1; @@ -65,7 +73,11 @@ void ShapeCreationVisitor::visit(ForEachAtom& rAtom) rAtom.iterator().mnCnt==-1 ? nChildren : rAtom.iterator().mnCnt); const sal_Int32 nOldIdx=mnCurrIdx; + const sal_Int32 nOldStep = mnCurrStep; + const sal_Int32 nOldCnt = mnCurrCnt; const sal_Int32 nStep=rAtom.iterator().mnStep; + mnCurrStep = nStep; + mnCurrCnt = nCnt; for( mnCurrIdx=0; mnCurrIdx<nCnt && nStep>0; mnCurrIdx+=nStep ) { // TODO there is likely some conditions @@ -75,6 +87,8 @@ void ShapeCreationVisitor::visit(ForEachAtom& rAtom) // and restore idx mnCurrIdx = nOldIdx; + mnCurrStep = nOldStep; + mnCurrCnt = nOldCnt; } void ShapeCreationVisitor::visit(ConditionAtom& rAtom) @@ -166,6 +180,38 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) std::remove_if(pCurrParent->getChildren().begin(), pCurrParent->getChildren().end(), [] (const ShapePtr & aChild) { return aChild->getServiceName() == "com.sun.star.drawing.GroupShape" && aChild->getChildren().empty(); }), pCurrParent->getChildren().end()); + + // Offset the children from their default z-order stacking, if necessary. + std::vector<ShapePtr>& rChildren = pCurrParent->getChildren(); + for (size_t i = 0; i < rChildren.size(); ++i) + rChildren[i]->setZOrder(i); + + for (size_t i = 0; i < rChildren.size(); ++i) + { + const ShapePtr& pChild = rChildren[i]; + sal_Int32 nZOrderOff = pChild->getZOrderOff(); + if (nZOrderOff <= 0) + continue; + + // Increase my ZOrder by nZOrderOff. + pChild->setZOrder(pChild->getZOrder() + nZOrderOff); + pChild->setZOrderOff(0); + + for (sal_Int32 j = 0; j < nZOrderOff; ++j) + { + size_t nIndex = i + j + 1; + if (nIndex >= rChildren.size()) + break; + + // Decrease the ZOrder of the next nZOrderOff elements by one. + const ShapePtr& pNext = rChildren[nIndex]; + pNext->setZOrder(pNext->getZOrder() - 1); + } + } + + // Now that the ZOrders are adjusted, sort the children. + std::sort(rChildren.begin(), rChildren.end(), + [](const ShapePtr& a, const ShapePtr& b) { return a->getZOrder() < b->getZOrder(); }); } void ShapeCreationVisitor::visit(ShapeAtom& /*rAtom*/) @@ -235,7 +281,7 @@ void ShapeLayoutingVisitor::defaultVisit(LayoutAtom const & rAtom) void ShapeLayoutingVisitor::visit(ConstraintAtom& rAtom) { if (meLookFor == CONSTRAINT) - rAtom.parseConstraint(maConstraints); + rAtom.parseConstraint(maConstraints, /*bRequireForName=*/true); } void ShapeLayoutingVisitor::visit(AlgAtom& rAtom) diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.hxx b/oox/source/drawingml/diagram/layoutatomvisitors.hxx index 299739186315..f395f6a68668 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.hxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.hxx @@ -33,6 +33,8 @@ class ShapeCreationVisitor : public LayoutAtomVisitor ShapePtr mpParentShape; const Diagram& mrDgm; sal_Int32 mnCurrIdx; + sal_Int32 mnCurrStep = 0; + sal_Int32 mnCurrCnt = 0; const dgm::Point* mpCurrentNode; void defaultVisit(LayoutAtom const & rAtom); diff --git a/oox/source/drawingml/diagram/layoutnodecontext.cxx b/oox/source/drawingml/diagram/layoutnodecontext.cxx index 257f490f7c7c..ad62ba5d712b 100644 --- a/oox/source/drawingml/diagram/layoutnodecontext.cxx +++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx @@ -209,6 +209,8 @@ LayoutNodeContext::onCreateContext( ::sal_Int32 aElement, pShape->setDiagramRotation(rAttribs.getInteger(XML_rot, 0) * PER_DEGREE); + pShape->setZOrderOff(rAttribs.getInteger(XML_zOrderOff, 0)); + ShapeAtomPtr pAtom( new ShapeAtom(mpNode->getLayoutNode(), pShape) ); LayoutAtom::connect(mpNode, pAtom); return new ShapeContext( *this, ShapePtr(), pShape ); diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 2926614b8efc..16bc511743b1 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -175,6 +175,8 @@ Shape::Shape( const ShapePtr& pSourceShape ) , maLinkedTxbxAttr() , mbHasLinkedTxbx(false) , maDiagramDoms( pSourceShape->maDiagramDoms ) +, mnZOrder(pSourceShape->mnZOrder) +, mnZOrderOff(pSourceShape->mnZOrderOff) {} Shape::~Shape() diff --git a/sd/qa/unit/data/pptx/smartart-accent-process.pptx b/sd/qa/unit/data/pptx/smartart-accent-process.pptx new file mode 100644 index 000000000000..8710e7f170a9 Binary files /dev/null and b/sd/qa/unit/data/pptx/smartart-accent-process.pptx differ diff --git a/sd/qa/unit/data/pptx/smartart-continuous-block-process.pptx b/sd/qa/unit/data/pptx/smartart-continuous-block-process.pptx new file mode 100644 index 000000000000..b2ef58f0bbb3 Binary files /dev/null and b/sd/qa/unit/data/pptx/smartart-continuous-block-process.pptx differ diff --git a/sd/qa/unit/import-tests-smartart.cxx b/sd/qa/unit/import-tests-smartart.cxx index d561f138f16f..b83de20890b1 100644 --- a/sd/qa/unit/import-tests-smartart.cxx +++ b/sd/qa/unit/import-tests-smartart.cxx @@ -14,6 +14,8 @@ #include <com/sun/star/style/ParagraphAdjust.hpp> #include <com/sun/star/text/XText.hpp> +#include <comphelper/sequenceashashmap.hxx> + using namespace ::com::sun::star; class SdImportTestSmartArt : public SdModelTestBase @@ -29,6 +31,8 @@ public: void testVertialBoxList(); void testVertialBracketList(); void testTableList(); + void testAccentProcess(); + void testContinuousBlockProcess(); CPPUNIT_TEST_SUITE(SdImportTestSmartArt); @@ -42,6 +46,8 @@ public: CPPUNIT_TEST(testVertialBoxList); CPPUNIT_TEST(testVertialBracketList); CPPUNIT_TEST(testTableList); + CPPUNIT_TEST(testAccentProcess); + CPPUNIT_TEST(testContinuousBlockProcess); CPPUNIT_TEST_SUITE_END(); }; @@ -276,6 +282,126 @@ void SdImportTestSmartArt::testTableList() xDocShRef->DoClose(); } +void SdImportTestSmartArt::testAccentProcess() +{ + sd::DrawDocShellRef xDocShRef = loadURL( + m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/smartart-accent-process.pptx"), PPTX); + uno::Reference<drawing::XShapes> xGroup(getShapeFromPage(0, 0, xDocShRef), uno::UNO_QUERY); + CPPUNIT_ASSERT(xGroup.is()); + // 3 children: first pair, connector, second pair. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(3), xGroup->getCount()); + uno::Reference<drawing::XShape> xGroupShape(xGroup, uno::UNO_QUERY); + CPPUNIT_ASSERT(xGroupShape.is()); + + // The pair is a parent (shape + text) and a child, so 3 shapes in total. + // The order is importent, first is at the back, last is at the front. + uno::Reference<drawing::XShapes> xFirstPair(xGroup->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstPair.is()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(3), xFirstPair->getCount()); + + uno::Reference<text::XText> xFirstParentText(xFirstPair->getByIndex(1), uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstParentText.is()); + CPPUNIT_ASSERT_EQUAL(OUString("a"), xFirstParentText->getString()); + uno::Reference<drawing::XShape> xFirstParent(xFirstParentText, uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstParent.is()); + int nFirstParentTop = xFirstParent->getPosition().Y; + + uno::Reference<text::XText> xFirstChildText(xFirstPair->getByIndex(2), uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstChildText.is()); + CPPUNIT_ASSERT_EQUAL(OUString("b"), xFirstChildText->getString()); + uno::Reference<drawing::XShape> xFirstChild(xFirstChildText, uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstChildText.is()); + + { + uno::Reference<container::XEnumerationAccess> xParasAccess(xFirstChildText, uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParas = xParasAccess->createEnumeration(); + uno::Reference<beans::XPropertySet> xPara(xParas->nextElement(), uno::UNO_QUERY); + // Without the accompanying fix in place, this test would have failed + // with 'Expected: 0; Actual : 1270', i.e. there was a large + // unexpected left margin. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), + xPara->getPropertyValue("ParaLeftMargin").get<sal_Int32>()); + + uno::Reference<container::XIndexAccess> xRules(xPara->getPropertyValue("NumberingRules"), + uno::UNO_QUERY); + comphelper::SequenceAsHashMap aRule(xRules->getByIndex(1)); + CPPUNIT_ASSERT_EQUAL(OUString::fromUtf8(u8"•"), aRule["BulletChar"].get<OUString>()); + } + + int nFirstChildTop = xFirstChild->getPosition().Y; + int nFirstChildRight = xFirstChild->getPosition().X + xFirstChild->getSize().Width; + + // First child is below the first parent. + // Without the accompanying fix in place, this test would have failed with + // 'Expected less than: 3881, Actual : 3881', i.e. xFirstChild was not + // below xFirstParent (a good position is 9081). + CPPUNIT_ASSERT_LESS(nFirstChildTop, nFirstParentTop); + + // Make sure that we have an arrow shape between the two pairs. + uno::Reference<beans::XPropertySet> xArrow(xGroup->getByIndex(1), uno::UNO_QUERY); + CPPUNIT_ASSERT(xArrow.is()); + comphelper::SequenceAsHashMap aCustomShapeGeometry( + xArrow->getPropertyValue("CustomShapeGeometry")); + // Without the accompanying fix in place, this test would have failed, i.e. + // the custom shape lacked a type -> arrow was not visible. + CPPUNIT_ASSERT(aCustomShapeGeometry["Type"].has<OUString>()); + OUString aType = aCustomShapeGeometry["Type"].get<OUString>(); + CPPUNIT_ASSERT_EQUAL(OUString("ooxml-rightArrow"), aType); + + // Make sure that height of the arrow is less than its width. + uno::Reference<drawing::XShape> xArrowShape(xArrow, uno::UNO_QUERY); + CPPUNIT_ASSERT(xArrowShape.is()); + awt::Size aArrowSize = xArrowShape->getSize(); + CPPUNIT_ASSERT_LESS(aArrowSize.Width, aArrowSize.Height); + + uno::Reference<drawing::XShapes> xSecondPair(xGroup->getByIndex(2), uno::UNO_QUERY); + CPPUNIT_ASSERT(xSecondPair.is()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(3), xSecondPair->getCount()); + uno::Reference<text::XText> xSecondParentText(xSecondPair->getByIndex(1), uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstParentText.is()); + // Without the accompanying fix in place, this test would have failed with + // 'Expected: cc; Actual : c', i.e. non-first runs on data points were ignored. + CPPUNIT_ASSERT_EQUAL(OUString("cc"), xSecondParentText->getString()); + uno::Reference<drawing::XShape> xSecondParent(xSecondParentText, uno::UNO_QUERY); + CPPUNIT_ASSERT(xSecondParent.is()); + int nSecondParentLeft = xSecondParent->getPosition().X; + // Without the accompanying fix in place, this test would have failed with + // 'Expected less than: 12700; Actual : 18540', i.e. the "b" and "c" + // shapes overlapped. + CPPUNIT_ASSERT_LESS(nSecondParentLeft, nFirstChildRight); + + xDocShRef->DoClose(); +} + +void SdImportTestSmartArt::testContinuousBlockProcess() +{ + sd::DrawDocShellRef xDocShRef = loadURL( + m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/smartart-continuous-block-process.pptx"), + PPTX); + uno::Reference<drawing::XShapes> xGroup(getShapeFromPage(0, 0, xDocShRef), uno::UNO_QUERY); + CPPUNIT_ASSERT(xGroup.is()); + // 2 children: background, foreground. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), xGroup->getCount()); + + uno::Reference<drawing::XShapes> xLinear(xGroup->getByIndex(1), uno::UNO_QUERY); + CPPUNIT_ASSERT(xLinear.is()); + // 3 children: A, B and C. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(3), xLinear->getCount()); + + uno::Reference<text::XText> xA(xLinear->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT(xA.is()); + CPPUNIT_ASSERT_EQUAL(OUString("A"), xA->getString()); + uno::Reference<drawing::XShape> xAShape(xA, uno::UNO_QUERY); + CPPUNIT_ASSERT(xAShape.is()); + // Without the accompanying fix in place, this test would have failed: the + // theoretically correct value is 5462 mm100 (16933 is the total width, and + // need to divide that to 1, 0.5, 1, 0.5 and 1 units), while the old value + // was 4703 and the new one is 5461. + CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(5000), xAShape->getSize().Width); + + xDocShRef->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTestSmartArt); CPPUNIT_PLUGIN_IMPLEMENT(); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits