From 73cc724dc35551ea349b3da0c4ecd6cba2fdd0ae Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Tue, 13 Nov 2018 18:00:50 +0100 Subject: [PATCH] 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 Tested-by: Caolán McNamara --- diff --git a/include/oox/drawingml/shape.hxx b/include/oox/drawingml/shape.hxx index 6028a11..e04a58beb 100644 --- a/include/oox/drawingml/shape.hxx +++ b/include/oox/drawingml/shape.hxx @@ -214,6 +214,14 @@ 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 @@ bool mbHasLinkedTxbx; // this text box has linked text box ? css::uno::Sequence 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 c1aaf6e..5024709 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -54,6 +54,50 @@ 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(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 @@ rVisitor.visit(*this); } -void ConstraintAtom::parseConstraint(std::vector& rConstraints) const +void ConstraintAtom::parseConstraint(std::vector& 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 @@ const std::vector& rOwnConstraints ) const { // Algorithm result may depend on the parent constraints as well. - std::vector aParentConstraints; + std::vector aMergedConstraints; const LayoutNode* pParent = getLayoutNode().getParentLayoutNode(); if (pParent) { @@ -298,10 +344,12 @@ { auto pConstraintAtom = dynamic_cast(pChild.get()); if (pConstraintAtom) - pConstraintAtom->parseConstraint(aParentConstraints); + pConstraintAtom->parseConstraint(aMergedConstraints, /*bRequireForName=*/true); } } - const std::vector& rConstraints = rOwnConstraints.empty() ? aParentConstraints : rOwnConstraints; + aMergedConstraints.insert(aMergedConstraints.end(), rOwnConstraints.begin(), + rOwnConstraints.end()); + const std::vector& rConstraints = aMergedConstraints; switch(mnType) { @@ -327,7 +375,19 @@ 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 @@ } 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 aDirectConstraints; + const LayoutNode& rLayoutNode = getLayoutNode(); + for (const auto& pChild : rLayoutNode.getChildren()) + { + auto pConstraintAtom = dynamic_cast(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,9 +535,24 @@ 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; + + // Find out which contraint is relevant for which (internal) name. + LayoutPropertyMap aProperties; + for (const auto& rConstraint : rConstraints) + { + if (rConstraint.msForName.isEmpty()) + continue; + + 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) @@ -443,18 +565,6 @@ 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) - { - if (rConstraint.msForName.isEmpty()) - continue; - - LayoutProperty& rProperty = aProperties[rConstraint.msForName]; - if (rConstraint.mnType == XML_w) - rProperty[XML_w] = rShape->getSize().Width * rConstraint.mfFactor; - } // See if children requested more than 100% space in total: scale // down in that case. @@ -500,7 +610,7 @@ 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 @@ } 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 @@ if( aVecIter->second != -1 ) rPara.getProperties().setLevel(aVecIter->second); - rPara.addRun( - aDataNode2->second->mpShape->getTextBody()->getParagraphs().front()->getRuns().front()); + std::shared_ptr 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 3d4d9c0..500495b 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -141,7 +141,7 @@ virtual void accept( LayoutAtomVisitor& ) override; Constraint& getConstraint() { return maConstraint; } - void parseConstraint(std::vector& rConstraints) const; + void parseConstraint(std::vector& rConstraints, bool bRequireForName) const; private: Constraint maConstraint; }; @@ -162,6 +162,13 @@ { maMap[nType]=nVal; } void layoutShape( const ShapePtr& rShape, const std::vector& rConstraints ) const; + + /// Gives access to . + sal_Int32 getType() const { return mnType; } + + /// Gives access to . + 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 ce8e6ab..49a664c 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx @@ -46,6 +46,14 @@ 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& rChildren=rAtom.getChildren(); sal_Int32 nChildren=1; @@ -65,7 +73,11 @@ 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; mnCurrIdx0; mnCurrIdx+=nStep ) { // TODO there is likely some conditions @@ -75,6 +87,8 @@ // and restore idx mnCurrIdx = nOldIdx; + mnCurrStep = nOldStep; + mnCurrCnt = nOldCnt; } void ShapeCreationVisitor::visit(ConditionAtom& rAtom) @@ -166,6 +180,38 @@ 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& 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::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 2997391..f395f6a 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.hxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.hxx @@ -33,6 +33,8 @@ 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 257f490..ad62ba5 100644 --- a/oox/source/drawingml/diagram/layoutnodecontext.cxx +++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx @@ -209,6 +209,8 @@ 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 2926614..16bc511 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -175,6 +175,8 @@ , maLinkedTxbxAttr() , mbHasLinkedTxbx(false) , maDiagramDoms( pSourceShape->maDiagramDoms ) +, mnZOrder(pSourceShape->mnZOrder) +, mnZOrderOff(pSourceShape->mnZOrderOff) {} Shape::~Shape()