[Libreoffice-commits] core.git: 3 commits - oox/source

Grzegorz Araminowicz g.araminowicz at gmail.com
Thu Jul 20 08:05:38 UTC 2017


 oox/source/drawingml/diagram/diagram.cxx                |    6 
 oox/source/drawingml/diagram/diagramfragmenthandler.cxx |   10 
 oox/source/drawingml/diagram/diagramlayoutatoms.cxx     |  247 ++++++----------
 oox/source/drawingml/diagram/diagramlayoutatoms.hxx     |   24 +
 oox/source/drawingml/diagram/layoutatomvisitors.cxx     |  148 +++++++--
 oox/source/drawingml/diagram/layoutatomvisitors.hxx     |   35 +-
 oox/source/drawingml/diagram/layoutnodecontext.cxx      |   32 --
 7 files changed, 286 insertions(+), 216 deletions(-)

New commits:
commit 558ded72d2a39fd0eac1f3f375b446c72b7141e5
Author: Grzegorz Araminowicz <g.araminowicz at gmail.com>
Date:   Wed Jul 19 22:08:38 2017 +0200

    SmartArt: shape styling
    
    Change-Id: I7e9ab4c2286fd803cd518dd01ab8ebd5ac2d8428

diff --git a/oox/source/drawingml/diagram/diagramfragmenthandler.cxx b/oox/source/drawingml/diagram/diagramfragmenthandler.cxx
index a85fe611dd18..1ad24270477e 100644
--- a/oox/source/drawingml/diagram/diagramfragmenthandler.cxx
+++ b/oox/source/drawingml/diagram/diagramfragmenthandler.cxx
@@ -122,7 +122,7 @@ DiagramQStylesFragmentHandler::DiagramQStylesFragmentHandler( XmlFilterBase& rFi
                                                                                const AttributeList& rAttribs )
 {
     // state-table like way of navigating the color fragment. we
-    // currently ignore everything except styleLbl in the colorsDef
+    // currently ignore everything except styleLbl in the styleDef
     // element
     switch( getCurrentElement() )
     {
@@ -136,16 +136,16 @@ DiagramQStylesFragmentHandler::DiagramQStylesFragmentHandler( XmlFilterBase& rFi
         {
             switch( nElement )
             {
-                case DGM_TOKEN(lnRef) :     // CT_StyleMatrixReference
+                case A_TOKEN(lnRef):     // CT_StyleMatrixReference
                     return createStyleMatrixContext(nElement,rAttribs,
                                                     maStyleEntry.maLineStyle);
-                case DGM_TOKEN(fillRef) :   // CT_StyleMatrixReference
+                case A_TOKEN(fillRef):   // CT_StyleMatrixReference
                     return createStyleMatrixContext(nElement,rAttribs,
                                                     maStyleEntry.maFillStyle);
-                case DGM_TOKEN(effectRef) : // CT_StyleMatrixReference
+                case A_TOKEN(effectRef): // CT_StyleMatrixReference
                     return createStyleMatrixContext(nElement,rAttribs,
                                                     maStyleEntry.maEffectStyle);
-                case DGM_TOKEN(fontRef) :   // CT_FontRe    ference
+                case A_TOKEN(fontRef):   // CT_FontReference
                     return createStyleMatrixContext(nElement,rAttribs,
                                                     maStyleEntry.maTextStyle);
             }
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index 1bad1f0f4ece..fef4ad22e44a 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -320,15 +320,16 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const Diagram& rDgm, sal_uI
     if( aDataNode != rDgm.getData()->getPointsPresNameMap().end() &&
         aDataNode->second.size() > nIdx )
     {
+        const dgm::Point* aPresNode = aDataNode->second.at(nIdx);
         SAL_INFO(
             "oox.drawingml",
             "Filling content from " << nIdx << "th layout node named \""
                 << msName << "\", modelId \""
-                << aDataNode->second.at(nIdx)->msModelId << "\"");
+                << aPresNode->msModelId << "\"");
 
         // got the presentation node - now, need the actual data node:
         const DiagramData::StringMap::const_iterator aNodeName=rDgm.getData()->getPresOfNameMap().find(
-            aDataNode->second.at(nIdx)->msModelId);
+            aPresNode->msModelId);
         if( aNodeName != rDgm.getData()->getPresOfNameMap().end() )
         {
             DiagramData::StringMap::value_type::second_type::const_iterator aVecIter=aNodeName->second.begin();
@@ -404,22 +405,30 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const Diagram& rDgm, sal_uI
                     << " for layout node named \"" << msName << "\"");
         }
 
-        // TODO(Q1): apply styling & coloring - taking
-        // layout node's styleLbl for both style & color
-        // now, but docs are a bit unclear on this
-        if( !msStyleLabel.isEmpty() )
+        // TODO(Q1): apply styling & coloring - take presentation
+        // point's presStyleLbl for both style & color
+        // if not found use layout node's styleLbl
+        // however, docs are a bit unclear on this
+        OUString aStyleLabel = aPresNode->msPresentationLayoutStyleLabel;
+        if (aStyleLabel.isEmpty())
+            aStyleLabel = msStyleLabel;
+        if( !aStyleLabel.isEmpty() )
         {
-            const DiagramQStyleMap::const_iterator aStyle=rDgm.getStyles().find(msStyleLabel);
+            const DiagramQStyleMap::const_iterator aStyle = rDgm.getStyles().find(aStyleLabel);
             if( aStyle != rDgm.getStyles().end() )
             {
-                rShape->getShapeStyleRefs()[XML_fillRef] = aStyle->second.maFillStyle;
-                rShape->getShapeStyleRefs()[XML_lnRef] = aStyle->second.maLineStyle;
-                rShape->getShapeStyleRefs()[XML_effectRef] = aStyle->second.maEffectStyle;
-                rShape->getShapeStyleRefs()[XML_fontRef] = aStyle->second.maTextStyle;
-                Color aColor=aStyle->second.maTextStyle.maPhClr;
+                const DiagramStyle& rStyle = aStyle->second;
+                rShape->getShapeStyleRefs()[XML_fillRef] = rStyle.maFillStyle;
+                rShape->getShapeStyleRefs()[XML_lnRef] = rStyle.maLineStyle;
+                rShape->getShapeStyleRefs()[XML_effectRef] = rStyle.maEffectStyle;
+                rShape->getShapeStyleRefs()[XML_fontRef] = rStyle.maTextStyle;
+            }
+            else
+            {
+                SAL_WARN("oox.drawingml", "Style " << aStyleLabel << " not found");
             }
 
-            const DiagramColorMap::const_iterator aColor=rDgm.getColors().find(msStyleLabel);
+            const DiagramColorMap::const_iterator aColor = rDgm.getColors().find(aStyleLabel);
             if( aColor != rDgm.getColors().end() )
             {
                 const DiagramColor& rColor=aColor->second;
@@ -433,12 +442,6 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const Diagram& rDgm, sal_uI
                     rShape->getShapeStyleRefs()[XML_fontRef].maPhClr = rColor.maTextFillColor;
             }
         }
-        else
-        {
-            // if no style label apply at least some fill color
-            rShape->getShapeStyleRefs()[XML_fillRef].maPhClr.setScrgbClr(0, 0, 0);
-            rShape->getShapeStyleRefs()[XML_fillRef].mnThemedIdx = 2;
-        }
 
         // even if no data node found, successful anyway. it's
         // contained at the layoutnode
commit 47e52b47845265ba126c30eba149e90689538b93
Author: Grzegorz Araminowicz <g.araminowicz at gmail.com>
Date:   Thu Jul 13 18:39:42 2017 +0200

    SmartArt: more layout work
    
    * basic layout algorithms implementation
    * change layouting order to "from top"
    
    Change-Id: I8ef397fa0e39bb6d8cda2d1387b663980f134a59

diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx
index 533156bbfb86..175df73e9420 100644
--- a/oox/source/drawingml/diagram/diagram.cxx
+++ b/oox/source/drawingml/diagram/diagram.cxx
@@ -328,7 +328,11 @@ void Diagram::addTo( const ShapePtr & pParentShape )
         // create Shape hierarchy
         ShapeCreationVisitor aCreationVisitor(pParentShape, *this);
         mpLayout->getNode()->setExistingShape(pParentShape);
-        mpLayout->getNode()->accept( aCreationVisitor );
+        mpLayout->getNode()->accept(aCreationVisitor);
+
+        // layout shapes - now all shapes are created
+        ShapeLayoutingVisitor aLayoutingVisitor;
+        mpLayout->getNode()->accept(aLayoutingVisitor);
     }
     pParentShape->setDiagramDoms( getDomsAsPropertyValues() );
 }
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index daf0edf52c5a..1bad1f0f4ece 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -149,59 +149,13 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
     {
         case XML_composite:
         {
-            if( rShape->getChildren().empty() )
-            {
-                rShape->setSize(awt::Size(50,50));
-                break;
-            }
-
-            // just put stuff below each other
-            const sal_Int32 nIncX=0;
-            const sal_Int32 nIncY=1;
-
-            std::vector<ShapePtr>::const_iterator aCurrShape=rShape->getChildren().begin();
-            const std::vector<ShapePtr>::const_iterator aLastShape=rShape->getChildren().end();
-
-            // find biggest shape
-            awt::Size aMaxSize;
-            while( aCurrShape != aLastShape )
-            {
-                const awt::Size& sz=(*aCurrShape)->getSize();
-
-                aMaxSize.Width = std::max(
-                    aMaxSize.Width,
-                    sz.Width);
-                aMaxSize.Height = std::max(
-                    aMaxSize.Height,
-                    sz.Height);
+            // all shapes fill parent
 
-                ++aCurrShape;
-            }
-
-            aCurrShape=rShape->getChildren().begin();
-            const awt::Point aStartPos=(*aCurrShape)->getPosition();
-            awt::Point aCurrPos=aStartPos;
-            awt::Size  aTotalSize;
-            aTotalSize.Width = aMaxSize.Width;
-            while( aCurrShape != aLastShape )
+            for (auto & aCurrShape : rShape->getChildren())
             {
-                const awt::Size& sz=(*aCurrShape)->getSize();
-                (*aCurrShape)->setPosition(aCurrPos);
-                (*aCurrShape)->setSize(
-                    awt::Size(aMaxSize.Width,
-                              sz.Height));
-
-                aTotalSize.Height = std::max(
-                    aTotalSize.Height,
-                    aCurrPos.Y + sz.Height);
-
-                aCurrPos.X += nIncX*sz.Width;
-                aCurrPos.Y += nIncY*sz.Height;
-
-                ++aCurrShape;
+                aCurrShape->setSize(rShape->getSize());
+                aCurrShape->setChildSize(rShape->getSize());
             }
-
-            rShape->setSize(aTotalSize);
             break;
         }
 
@@ -210,11 +164,8 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
 
         case XML_cycle:
         {
-            if( rShape->getChildren().empty() )
-            {
-                rShape->setSize(awt::Size(50,50));
+            if (rShape->getChildren().empty())
                 break;
-            }
 
             const sal_Int32 nStartAngle=maMap.count(XML_stAng) ? maMap.find(XML_stAng)->second : 0;
             const sal_Int32 nSpanAngle=maMap.count(XML_spanAng) ? maMap.find(XML_spanAng)->second : 360;
@@ -241,27 +192,15 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
 
             // layout shapes
             const sal_Int32 nMaxDim=std::max(aMaxSize.Width,aMaxSize.Height);
-            awt::Size aTotalSize;
             aCurrShape=rShape->getChildren().begin();
             for( sal_Int32 i=0; i<nShapes; ++i, ++aCurrShape )
             {
-                const awt::Size& sz=(*aCurrShape)->getSize();
-
                 const double r=nShapes*nMaxDim/F_2PI * 360.0/nSpanAngle;
                 const awt::Point aCurrPos(
                     r + r*sin( (double(i)*nSpanAngle/nShapes + nStartAngle)*F_PI180 ),
                     r - r*cos( (double(i)*nSpanAngle/nShapes + nStartAngle)*F_PI180 ) );
                 (*aCurrShape)->setPosition(aCurrPos);
-
-                aTotalSize.Width = std::max(
-                    aTotalSize.Width,
-                    aCurrPos.X + sz.Width);
-                aTotalSize.Height = std::max(
-                    aTotalSize.Height,
-                    aCurrPos.Y + sz.Height);
             }
-
-            rShape->setSize(aTotalSize);
             break;
         }
 
@@ -270,97 +209,103 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
             break;
 
         case XML_lin:
-        case XML_snake:
         {
-            if( rShape->getChildren().empty() )
-            {
-                rShape->setSize(awt::Size(50,50));
+            // spread childres evenly across one axis, strech across second
+
+            if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0)
                 break;
-            }
 
-            const sal_Int32 nDir=maMap.count(XML_linDir) ? maMap.find(XML_linDir)->second : XML_fromL;
-            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);
+            const sal_Int32 nDir = maMap.count(XML_linDir) ? maMap.find(XML_linDir)->second : XML_fromL;
+            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);
 
-            std::vector<ShapePtr>::const_iterator aCurrShape=rShape->getChildren().begin();
-            const std::vector<ShapePtr>::const_iterator aLastShape=rShape->getChildren().end();
-            const awt::Point aStartPos=(*aCurrShape)->getPosition();
-            awt::Point aCurrPos=aStartPos;
-            awt::Size  aTotalSize;
-            while( aCurrShape != aLastShape )
-            {
-                const awt::Size& sz=(*aCurrShape)->getSize();
-                (*aCurrShape)->setPosition(aCurrPos);
+            // TODO: get values from constraints
+            sal_Int32 nCount = rShape->getChildren().size();
+            double fSpace = 0.3;
 
-                aTotalSize.Width = std::max(
-                    aTotalSize.Width,
-                    aCurrPos.X + sz.Width);
-                aTotalSize.Height = std::max(
-                    aTotalSize.Height,
-                    aCurrPos.Y + sz.Height);
+            awt::Size aChildSize = rShape->getSize();
+            if (nIncX)
+                aChildSize.Width /= (nCount + (nCount-1)*fSpace);
+            if (nIncY)
+                aChildSize.Height /= (nCount + (nCount-1)*fSpace);
 
-                // HACK: the spacing is arbitrary
-                aCurrPos.X += nIncX*(sz.Width+5);
-                aCurrPos.Y += nIncY*(sz.Height+5);
-
-                ++aCurrShape;
+            awt::Point aCurrPos = rShape->getChildren().front()->getPosition();
+            for (auto & aCurrShape : rShape->getChildren())
+            {
+                aCurrShape->setPosition(aCurrPos);
+                aCurrShape->setSize(aChildSize);
+                aCurrShape->setChildSize(aChildSize);
+                aCurrPos.X += nIncX * (aChildSize.Width + fSpace*aChildSize.Width);
+                aCurrPos.Y += nIncY * (aChildSize.Height + fSpace*aChildSize.Height);
             }
-
-            rShape->setSize(aTotalSize);
             break;
         }
 
         case XML_pyra:
             break;
 
-        case XML_sp:
-            // HACK. Handled one level higher. Or rather, planned to
-            break;
-
-        case XML_tx:
+        case XML_snake:
         {
-            TextBodyPtr pTextBody=rShape->getTextBody();
-            if( !pTextBody ||
-                pTextBody->getParagraphs().empty() ||
-                pTextBody->getParagraphs().front()->getRuns().empty() )
-            {
-                rShape->setSize(awt::Size(5,5));
+            // find optimal grid to layout children that have fixed aspect ratio
+
+            if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0)
                 break;
-            }
 
-            // HACK - count chars & paragraphs to come up with *some*
-            // notion of necessary size
-            const sal_Int32 nHackyFontHeight=50;
-            const sal_Int32 nHackyFontWidth=20;
-            awt::Size aTotalSize;
-            for( size_t nPara=0; nPara<pTextBody->getParagraphs().size(); ++nPara )
+            // TODO: get values from constraints
+            sal_Int32 nCount = rShape->getChildren().size();
+            double fSpace = 0.3;
+            double fAspectRatio = 0.6;
+
+            sal_Int32 nCol = 1;
+            sal_Int32 nRow = 1;
+            for ( ; nCol<nCount; nCol++)
             {
-                aTotalSize.Height += nHackyFontHeight;
+                nRow = (nCount+nCol-1) / nCol;
+                if ((rShape->getSize().Height / nRow) / (rShape->getSize().Width / nCol) >= fAspectRatio)
+                    break;
+            }
+            SAL_INFO("oox.drawingml", "Snake layout grid: " << nCol << "x" << nRow);
 
-                sal_Int32 nLocalWidth=0;
-                for( size_t nRun=0; nRun<pTextBody->getParagraphs().at(nPara)->getRuns().size(); ++nRun )
-                    nLocalWidth +=
-                        pTextBody->getParagraphs().at(nPara)->getRuns().at(nRun)->getText().getLength()
-                        * nHackyFontWidth;
+            sal_Int32 nWidth = rShape->getSize().Width / (nCol + (nCol-1)*fSpace);
+            const awt::Size aChildSize(nWidth, nWidth * fAspectRatio);
 
-                aTotalSize.Width = std::max(
-                    aTotalSize.Width,
-                    nLocalWidth);
-            }
+            awt::Point aStartPos = rShape->getChildren().front()->getPosition();
+            awt::Point aCurrPos = aStartPos;
+            sal_Int32 nColIdx = 0;
 
-            rShape->setSize(aTotalSize);
+            for (auto & aCurrShape : rShape->getChildren())
+            {
+                aCurrShape->setPosition(aCurrPos);
+                aCurrShape->setSize(aChildSize);
+                aCurrShape->setChildSize(aChildSize);
+                aCurrPos.X += aChildSize.Width + fSpace*aChildSize.Width;
+                if (++nColIdx == nCol)
+                {
+                    aStartPos.Y += aChildSize.Height + fSpace*aChildSize.Height;
+                    aCurrPos = aStartPos;
+                    nColIdx = 0;
+                }
+            }
             break;
         }
 
+        case XML_sp:
+            // HACK. Handled one level higher. Or rather, planned to
+            break;
+
+        case XML_tx:
+            // TODO: adjust text size to fit shape
+            break;
+
         default:
             break;
     }
 
     SAL_INFO(
         "oox.drawingml",
-        "Layouting shape " << rName << ": (" << rShape->getPosition().X << ","
-        << rShape->getPosition().Y << "," << rShape->getSize().Width << ","
-        << rShape->getSize().Height << ")");
+        "Layouting shape " << rName << ", alg type: " << mnType << ", ("
+        << rShape->getPosition().X << "," << rShape->getPosition().Y << ","
+        << rShape->getSize().Width << "," << rShape->getSize().Height << ")");
 }
 
 void LayoutNode::accept( LayoutAtomVisitor& rVisitor )
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
index 7a168528c0ec..a6123ccbd62c 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
@@ -242,6 +242,8 @@ public:
         { mpExistingShape = pShape; }
     const ShapePtr& getExistingShape() const
         { return mpExistingShape; }
+    std::vector<ShapePtr> & getNodeShapes()
+        { return mpNodeShapes; }
 
     bool setupShape( const ShapePtr& rShape,
                      const Diagram& rDgm,
@@ -252,6 +254,7 @@ private:
     OUString                     msMoveWith;
     OUString                     msStyleLabel;
     ShapePtr                     mpExistingShape;
+    std::vector<ShapePtr>        mpNodeShapes;
     sal_Int32                    mnChildOrder;
 };
 
diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx
index ade7e4ccfec9..a580da73ff32 100755
--- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx
+++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx
@@ -97,7 +97,9 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom)
 
     if (rAtom.getExistingShape())
     {
-        rAtom.setupShape(rAtom.getExistingShape(), mrDgm, mnCurrIdx);
+        // reuse existing shape
+        if (rAtom.setupShape(rAtom.getExistingShape(), mrDgm, mnCurrIdx))
+            rAtom.getNodeShapes().push_back(rAtom.getExistingShape());
     }
     else
     {
@@ -117,6 +119,7 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom)
             {
                 pCurrParent->addChild(pShape);
                 pCurrParent = pShape;
+                rAtom.getNodeShapes().push_back(pShape);
             }
         }
         else
@@ -135,10 +138,11 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom)
     // restore parent
     mpParentShape=pPreviousParent;
 
-    // layout shapes - now all child shapes are created
-    ShapeLayoutingVisitor aLayoutingVisitor(pCurrParent,
-                                            rAtom.getName());
-    aLayoutingVisitor.defaultVisit(rAtom);
+    // remove unneeded empty group shapes
+    pCurrParent->getChildren().erase(
+        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());
 }
 
 void ShapeCreationVisitor::visit(ShapeAtom& /*rAtom*/)
@@ -212,12 +216,16 @@ void ShapeLayoutingVisitor::visit(ConstraintAtom& /*rAtom*/)
 
 void ShapeLayoutingVisitor::visit(AlgAtom& rAtom)
 {
-    rAtom.layoutShape(mpParentShape, maName);
+    if (mbLookForAlg && mpCurrentLayoutNode)
+    {
+        for (const auto& pShape : mpCurrentLayoutNode->getNodeShapes())
+            rAtom.layoutShape(pShape, mpCurrentLayoutNode->getName());
+    }
 }
 
-void ShapeLayoutingVisitor::visit(ForEachAtom& /*rAtom*/)
+void ShapeLayoutingVisitor::visit(ForEachAtom& rAtom)
 {
-    // stop processing
+    defaultVisit(rAtom);
 }
 
 void ShapeLayoutingVisitor::visit(ConditionAtom& rAtom)
@@ -230,9 +238,21 @@ void ShapeLayoutingVisitor::visit(ChooseAtom& rAtom)
     defaultVisit(rAtom);
 }
 
-void ShapeLayoutingVisitor::visit(LayoutNode& /*rAtom*/)
+void ShapeLayoutingVisitor::visit(LayoutNode& rAtom)
 {
-    // stop processing - only traverse Condition/Choose atoms
+    if (mbLookForAlg)
+        return;
+
+    LayoutNode* pPreviousLayoutNode = mpCurrentLayoutNode;
+    mpCurrentLayoutNode = &rAtom;
+
+    // process alg atoms first, nested layout nodes afterwards
+    mbLookForAlg = true;
+    defaultVisit(rAtom);
+    mbLookForAlg = false;
+    defaultVisit(rAtom);
+
+    mpCurrentLayoutNode = pPreviousLayoutNode;
 }
 
 void ShapeLayoutingVisitor::visit(ShapeAtom& /*rAtom*/)
diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.hxx b/oox/source/drawingml/diagram/layoutatomvisitors.hxx
index 28558f69bb24..3ffef36d8954 100755
--- a/oox/source/drawingml/diagram/layoutatomvisitors.hxx
+++ b/oox/source/drawingml/diagram/layoutatomvisitors.hxx
@@ -72,9 +72,10 @@ public:
 
 class ShapeLayoutingVisitor : public LayoutAtomVisitor
 {
-    ShapePtr mpParentShape;
-    OUString maName;
+    LayoutNode* mpCurrentLayoutNode;
+    bool mbLookForAlg;
 
+    void defaultVisit(LayoutAtom& rAtom);
     virtual void visit(ConstraintAtom& rAtom) override;
     virtual void visit(AlgAtom& rAtom) override;
     virtual void visit(ForEachAtom& rAtom) override;
@@ -84,13 +85,10 @@ class ShapeLayoutingVisitor : public LayoutAtomVisitor
     virtual void visit(ShapeAtom& rAtom) override;
 
 public:
-    ShapeLayoutingVisitor(const ShapePtr& rParentShape,
-                          const OUString& rName) :
-        mpParentShape(rParentShape),
-        maName(rName)
+    ShapeLayoutingVisitor() :
+        mpCurrentLayoutNode(nullptr),
+        mbLookForAlg(false)
     {}
-
-    void defaultVisit(LayoutAtom& rAtom);
 };
 
 class ShallowPresNameVisitor : public LayoutAtomVisitor
commit 21f28f94744b4378ba45b1361870592dd7cfabb2
Author: Grzegorz Araminowicz <g.araminowicz at gmail.com>
Date:   Sat Jul 1 14:10:53 2017 +0200

    SmartArt: add ShapeAtom to store shape template instead of LayoutNode
    
    it allows to load shapes inside choose/if
    
    Change-Id: I8040967d1f769796f6ad6b2d0c7b5ce698f89ee3

diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index d32e2f963b59..daf0edf52c5a 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -511,6 +511,11 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const Diagram& rDgm, sal_uI
     return false;
 }
 
+void ShapeAtom::accept( LayoutAtomVisitor& rVisitor )
+{
+    rVisitor.visit(*this);
+}
+
 } }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
index d5b9fcdf9e29..7a168528c0ec 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
@@ -238,12 +238,8 @@ public:
         { msStyleLabel = sLabel; }
     void setChildOrder( sal_Int32 nOrder )
         { mnChildOrder = nOrder; }
-    void setShapeTemplate( const ShapePtr& pShape )
-        { mpShapeTemplate = pShape; }
     void setExistingShape( const ShapePtr& pShape )
         { mpExistingShape = pShape; }
-    const ShapePtr& getShapeTemplate() const
-        { return mpShapeTemplate; }
     const ShapePtr& getExistingShape() const
         { return mpExistingShape; }
 
@@ -255,13 +251,27 @@ private:
     VarMap                       mVariables;
     OUString                     msMoveWith;
     OUString                     msStyleLabel;
-    ShapePtr                     mpShapeTemplate;
     ShapePtr                     mpExistingShape;
     sal_Int32                    mnChildOrder;
 };
 
 typedef std::shared_ptr< LayoutNode > LayoutNodePtr;
 
+class ShapeAtom
+    : public LayoutAtom
+{
+public:
+    ShapeAtom(const ShapePtr& pShape) : mpShapeTemplate(pShape) {}
+    virtual void accept( LayoutAtomVisitor& ) override;
+    const ShapePtr& getShapeTemplate() const
+        { return mpShapeTemplate; }
+
+private:
+    ShapePtr mpShapeTemplate;
+};
+
+typedef std::shared_ptr< ShapeAtom > ShapeAtomPtr;
+
 struct LayoutAtomVisitor
 {
     virtual ~LayoutAtomVisitor() {}
@@ -271,6 +281,7 @@ struct LayoutAtomVisitor
     virtual void visit(ConditionAtom& rAtom) = 0;
     virtual void visit(ChooseAtom& rAtom) = 0;
     virtual void visit(LayoutNode& rAtom) = 0;
+    virtual void visit(ShapeAtom& rAtom) = 0;
 };
 
 } }
diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx
index fd6e9d7b7e1b..ade7e4ccfec9 100755
--- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx
+++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx
@@ -94,34 +94,35 @@ void ShapeCreationVisitor::visit(ChooseAtom& rAtom)
 void ShapeCreationVisitor::visit(LayoutNode& rAtom)
 {
     ShapePtr pCurrParent(mpParentShape);
-    ShapePtr pCurrShape(rAtom.getShapeTemplate());
 
     if (rAtom.getExistingShape())
     {
         rAtom.setupShape(rAtom.getExistingShape(), mrDgm, mnCurrIdx);
     }
-    else if( pCurrShape )
+    else
     {
-        SAL_INFO(
-            "oox.drawingml",
-            "processing shape type "
-                << (pCurrShape->getCustomShapeProperties()
-                    ->getShapePresetType()));
-
-        // TODO(F3): cloned shape shares all properties by reference,
-        // don't change them!
-        ShapePtr pClonedShape(
-            new Shape( pCurrShape ));
-
-        if( rAtom.setupShape(pClonedShape, mrDgm, mnCurrIdx) )
+        ShapeTemplateVisitor aTemplateVisitor;
+        aTemplateVisitor.defaultVisit(rAtom);
+        ShapePtr pShape = aTemplateVisitor.getShapeCopy();
+
+        if (pShape)
         {
-            pCurrParent->addChild(pClonedShape);
-            pCurrParent = pClonedShape;
+            SAL_INFO(
+                "oox.drawingml",
+                "processing shape type "
+                    << (pShape->getCustomShapeProperties()
+                        ->getShapePresetType()));
+
+            if (rAtom.setupShape(pShape, mrDgm, mnCurrIdx))
+            {
+                pCurrParent->addChild(pShape);
+                pCurrParent = pShape;
+            }
+        }
+        else
+        {
+            SAL_WARN("oox.drawingml", "ShapeCreationVisitor::visit: no shape set while processing layoutnode named " << rAtom.getName());
         }
-    }
-    else
-    {
-        SAL_WARN("oox.drawingml", "ShapeCreationVisitor::visit: no shape set while processing layoutnode named " << rAtom.getName() );
     }
 
     // set new parent for children
@@ -140,6 +141,63 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom)
     aLayoutingVisitor.defaultVisit(rAtom);
 }
 
+void ShapeCreationVisitor::visit(ShapeAtom& /*rAtom*/)
+{
+    // stop processing
+}
+
+void ShapeTemplateVisitor::defaultVisit(LayoutAtom& rAtom)
+{
+    // visit all children, one of them needs to be the layout algorithm
+    for (const auto& pAtom : rAtom.getChildren())
+        pAtom->accept(*this);
+}
+
+void ShapeTemplateVisitor::visit(ConstraintAtom& /*rAtom*/)
+{
+    // stop processing
+}
+
+void ShapeTemplateVisitor::visit(AlgAtom& /*rAtom*/)
+{
+    // stop processing
+}
+
+void ShapeTemplateVisitor::visit(ForEachAtom& /*rAtom*/)
+{
+    // stop processing
+}
+
+void ShapeTemplateVisitor::visit(ConditionAtom& rAtom)
+{
+    defaultVisit(rAtom);
+}
+
+void ShapeTemplateVisitor::visit(ChooseAtom& rAtom)
+{
+    defaultVisit(rAtom);
+}
+
+void ShapeTemplateVisitor::visit(LayoutNode& /*rAtom*/)
+{
+    // stop processing - only traverse Condition/Choose atoms
+}
+
+void ShapeTemplateVisitor::visit(ShapeAtom& rAtom)
+{
+    if (mpShape)
+    {
+        SAL_WARN("oox.drawingml", "multiple shapes encountered inside LayoutNode");
+        return;
+    }
+
+    ShapePtr pCurrShape(rAtom.getShapeTemplate());
+
+    // TODO(F3): cloned shape shares all properties by reference,
+    // don't change them!
+    mpShape.reset(new Shape(pCurrShape));
+}
+
 void ShapeLayoutingVisitor::defaultVisit(LayoutAtom& rAtom)
 {
     // visit all children, one of them needs to be the layout algorithm
@@ -177,6 +235,11 @@ void ShapeLayoutingVisitor::visit(LayoutNode& /*rAtom*/)
     // stop processing - only traverse Condition/Choose atoms
 }
 
+void ShapeLayoutingVisitor::visit(ShapeAtom& /*rAtom*/)
+{
+    // stop processing
+}
+
 void ShallowPresNameVisitor::defaultVisit(LayoutAtom& rAtom)
 {
     // visit all children, at least one of them needs to have proper
@@ -219,6 +282,11 @@ void ShallowPresNameVisitor::visit(LayoutNode& rAtom)
                          aDataNode->second.size());
 }
 
+void ShallowPresNameVisitor::visit(ShapeAtom& /*rAtom*/)
+{
+    // stop processing
+}
+
 } }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.hxx b/oox/source/drawingml/diagram/layoutatomvisitors.hxx
index 9353f4ba0a4b..28558f69bb24 100755
--- a/oox/source/drawingml/diagram/layoutatomvisitors.hxx
+++ b/oox/source/drawingml/diagram/layoutatomvisitors.hxx
@@ -41,6 +41,7 @@ class ShapeCreationVisitor : public LayoutAtomVisitor
     virtual void visit(ConditionAtom& rAtom) override;
     virtual void visit(ChooseAtom& rAtom) override;
     virtual void visit(LayoutNode& rAtom) override;
+    virtual void visit(ShapeAtom& rAtom) override;
 
 public:
     ShapeCreationVisitor(const ShapePtr& rParentShape,
@@ -51,6 +52,24 @@ public:
     {}
 };
 
+class ShapeTemplateVisitor : public LayoutAtomVisitor
+{
+    ShapePtr mpShape;
+
+    virtual void visit(ConstraintAtom& rAtom) override;
+    virtual void visit(AlgAtom& rAtom) override;
+    virtual void visit(ForEachAtom& rAtom) override;
+    virtual void visit(ConditionAtom& rAtom) override;
+    virtual void visit(ChooseAtom& rAtom) override;
+    virtual void visit(LayoutNode& rAtom) override;
+    virtual void visit(ShapeAtom& rAtom) override;
+
+public:
+    void defaultVisit(LayoutAtom& rAtom);
+    ShapePtr getShapeCopy() const
+        { return mpShape; }
+};
+
 class ShapeLayoutingVisitor : public LayoutAtomVisitor
 {
     ShapePtr mpParentShape;
@@ -62,6 +81,7 @@ class ShapeLayoutingVisitor : public LayoutAtomVisitor
     virtual void visit(ConditionAtom& rAtom) override;
     virtual void visit(ChooseAtom& rAtom) override;
     virtual void visit(LayoutNode& rAtom) override;
+    virtual void visit(ShapeAtom& rAtom) override;
 
 public:
     ShapeLayoutingVisitor(const ShapePtr& rParentShape,
@@ -85,6 +105,7 @@ class ShallowPresNameVisitor : public LayoutAtomVisitor
     virtual void visit(ConditionAtom& rAtom) override;
     virtual void visit(ChooseAtom& rAtom) override;
     virtual void visit(LayoutNode& rAtom) override;
+    virtual void visit(ShapeAtom& rAtom) override;
 
 public:
     explicit ShallowPresNameVisitor(const Diagram& rDgm) :
diff --git a/oox/source/drawingml/diagram/layoutnodecontext.cxx b/oox/source/drawingml/diagram/layoutnodecontext.cxx
index 5d66de142c96..715e94d72eab 100644
--- a/oox/source/drawingml/diagram/layoutnodecontext.cxx
+++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx
@@ -246,31 +246,23 @@ LayoutNodeContext::onCreateContext( ::sal_Int32 aElement,
     }
     case DGM_TOKEN( shape ):
     {
-        LayoutNodePtr pNode(std::dynamic_pointer_cast<LayoutNode>(mpNode));
-        if( pNode )
-        {
-            ShapePtr pShape;
-
-            if( rAttribs.hasAttribute( XML_type ) )
-            {
-                pShape.reset( new Shape("com.sun.star.drawing.CustomShape") );
-                const sal_Int32 nType(rAttribs.getToken( XML_type, XML_obj ));
-                pShape->setSubType( nType );
-                pShape->getCustomShapeProperties()->setShapePresetType( nType );
-            }
-            else
-            {
-                pShape.reset( new Shape("com.sun.star.drawing.GroupShape") );
-            }
+        ShapePtr pShape;
 
-            pNode->setShapeTemplate( pShape );
-            return new ShapeContext( *this, ShapePtr(), pShape );
+        if( rAttribs.hasAttribute( XML_type ) )
+        {
+            pShape.reset( new Shape("com.sun.star.drawing.CustomShape") );
+            const sal_Int32 nType(rAttribs.getToken( XML_type, XML_obj ));
+            pShape->setSubType( nType );
+            pShape->getCustomShapeProperties()->setShapePresetType( nType );
         }
         else
         {
-            SAL_WARN("oox",  "OOX: encountered a shape in a non layoutNode context" );
+            pShape.reset( new Shape("com.sun.star.drawing.GroupShape") );
         }
-        break;
+
+        ShapeAtomPtr pAtom( new ShapeAtom(pShape) );
+        mpNode->addChild( pAtom );
+        return new ShapeContext( *this, ShapePtr(), pShape );
     }
     case DGM_TOKEN( extLst ):
         return nullptr;


More information about the Libreoffice-commits mailing list