summaryrefslogtreecommitdiffstats
path: root/oox
diff options
context:
space:
mode:
authorGrzegorz Araminowicz <grzegorz.araminowicz@collabora.com>2019-07-07 14:12:05 +0200
committerGrzegorz Araminowicz <grzegorz.araminowicz@collabora.com>2019-07-11 10:59:16 +0200
commit53af44593672cd456b32d4aba56220f10dad16ae (patch)
treed2c644da56eb5ff3e3a7fc7774307ae0f2ceb02b /oox
parentSmartArt: better detecting connector arrow type (diff)
downloadcore-53af44593672cd456b32d4aba56220f10dad16ae.tar.gz
core-53af44593672cd456b32d4aba56220f10dad16ae.zip
SmartArt: improve organization chart layout
layout shapes in two steps: * first calculate vertical child shapes count for every shape (taking into accout hierBranch alg variable) * then actual layout using that count to calculate size for subtrees Change-Id: I2e5ca34ed3383aa9502c52511cc1fb2bee215572 Reviewed-on: https://gerrit.libreoffice.org/75195 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/75396 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Grzegorz Araminowicz <grzegorz.araminowicz@collabora.com>
Diffstat (limited to 'oox')
-rw-r--r--oox/source/drawingml/diagram/diagramlayoutatoms.cxx107
-rw-r--r--oox/source/drawingml/diagram/diagramlayoutatoms.hxx1
-rw-r--r--oox/source/drawingml/diagram/layoutatomvisitorbase.hxx4
-rw-r--r--oox/source/drawingml/diagram/layoutatomvisitors.cxx22
-rw-r--r--oox/source/drawingml/diagram/layoutatomvisitors.hxx4
5 files changed, 102 insertions, 36 deletions
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index 9c83d95fea5d..93d12f23db8d 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -418,6 +418,40 @@ sal_Int32 AlgAtom::getConnectorType()
return oox::XML_rightArrow;
}
+sal_Int32 AlgAtom::getVerticalShapesCount(const ShapePtr& rShape)
+{
+ if (rShape->getChildren().empty())
+ return (rShape->getSubType() != XML_conn) ? 1 : 0;
+
+ sal_Int32 nDir = XML_fromL;
+ if (mnType == XML_hierRoot)
+ nDir = XML_fromT;
+ else if (maMap.count(XML_linDir))
+ nDir = maMap.find(XML_linDir)->second;
+
+ const sal_Int32 nSecDir = maMap.count(XML_secLinDir) ? maMap.find(XML_secLinDir)->second : 0;
+
+ sal_Int32 nCount = 0;
+ if (nDir == XML_fromT || nDir == XML_fromB)
+ {
+ for (ShapePtr& pChild : rShape->getChildren())
+ nCount += pChild->getVerticalShapesCount();
+ }
+ else if ((nDir == XML_fromL || nDir == XML_fromR) && nSecDir == XML_fromT)
+ {
+ for (ShapePtr& pChild : rShape->getChildren())
+ nCount += pChild->getVerticalShapesCount();
+ nCount = (nCount + 1) / 2;
+ }
+ else
+ {
+ for (ShapePtr& pChild : rShape->getChildren())
+ nCount = std::max(nCount, pChild->getVerticalShapesCount());
+ }
+
+ return nCount;
+}
+
void AlgAtom::layoutShape( const ShapePtr& rShape,
const std::vector<Constraint>& rConstraints )
{
@@ -621,6 +655,9 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
case XML_hierChild:
case XML_hierRoot:
{
+ if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0)
+ break;
+
// hierRoot is the manager -> employees vertical linear path,
// hierChild is the first employee -> last employee horizontal
// linear path.
@@ -630,31 +667,20 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
else if (maMap.count(XML_linDir))
nDir = maMap.find(XML_linDir)->second;
- if (rShape->getChildren().empty() || rShape->getSize().Width == 0
- || rShape->getSize().Height == 0)
- break;
+ const sal_Int32 nSecDir = maMap.count(XML_secLinDir) ? maMap.find(XML_secLinDir)->second : 0;
sal_Int32 nCount = rShape->getChildren().size();
if (mnType == XML_hierChild)
{
- // Connectors should not influence the size of non-connect
- // shapes.
+ // Connectors should not influence the size of non-connect shapes.
nCount = std::count_if(
rShape->getChildren().begin(), rShape->getChildren().end(),
[](const ShapePtr& pShape) { return pShape->getSubType() != XML_conn; });
}
- // A manager node's height should be independent from if it has
- // assistants and employees, compensate for that.
- bool bTop = mnType == XML_hierRoot && rShape->getInternalName() == "hierRoot1";
-
- // Add spacing, so connectors have a chance to be visible.
- double fSpace = (nCount > 1 || bTop) ? 0.3 : 0;
-
- double fHeightScale = 1.0;
- if (mnType == XML_hierRoot && nCount < 3 && bTop)
- fHeightScale = fHeightScale * nCount / 3;
+ const double fSpaceWidth = 0.1;
+ const double fSpaceHeight = 0.3;
if (mnType == XML_hierRoot && nCount == 3)
{
@@ -665,18 +691,31 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
std::swap(rChildren[1], rChildren[2]);
}
+ sal_Int32 nHorizontalShapesCount = 1;
+ if (nSecDir == XML_fromT)
+ nHorizontalShapesCount = 2;
+ else if (nDir == XML_fromL || nDir == XML_fromR)
+ nHorizontalShapesCount = nCount;
+
awt::Size aChildSize = rShape->getSize();
- if (nDir == XML_fromT)
- {
- aChildSize.Height /= (nCount + nCount * fSpace);
- }
- else
- aChildSize.Width /= nCount;
- aChildSize.Height *= fHeightScale;
+ aChildSize.Height /= (rShape->getVerticalShapesCount() + (rShape->getVerticalShapesCount() - 1) * fSpaceHeight);
+ aChildSize.Width /= (nHorizontalShapesCount + (nHorizontalShapesCount - 1) * fSpaceWidth);
+
awt::Size aConnectorSize = aChildSize;
aConnectorSize.Width = 1;
awt::Point aChildPos(0, 0);
+
+ // indent children to show they are descendants, not siblings
+ if (mnType == XML_hierChild && nHorizontalShapesCount == 1)
+ {
+ const double fChildIndent = 0.1;
+ aChildPos.X = aChildSize.Width * fChildIndent;
+ aChildSize.Width *= (1 - 2 * fChildIndent);
+ }
+
+ sal_Int32 nIdx = 0;
+ sal_Int32 nRowHeight = 0;
for (auto& pChild : rShape->getChildren())
{
pChild->setPosition(aChildPos);
@@ -690,13 +729,27 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
continue;
}
- pChild->setSize(aChildSize);
- pChild->setChildSize(aChildSize);
+ awt::Size aCurrSize = aChildSize;
+ aCurrSize.Height *= pChild->getVerticalShapesCount() + (pChild->getVerticalShapesCount() - 1) * fSpaceHeight;
- if (nDir == XML_fromT)
- aChildPos.Y += aChildSize.Height + aChildSize.Height * fSpace;
+ pChild->setSize(aCurrSize);
+ pChild->setChildSize(aCurrSize);
+
+ if (nDir == XML_fromT || nDir == XML_fromB)
+ aChildPos.Y += aCurrSize.Height + aChildSize.Height * fSpaceHeight;
else
- aChildPos.X += aChildSize.Width;
+ aChildPos.X += aCurrSize.Width + aCurrSize.Width * fSpaceWidth;
+
+ nRowHeight = std::max(nRowHeight, aCurrSize.Height);
+
+ if (nSecDir == XML_fromT && nIdx % 2 == 1)
+ {
+ aChildPos.X = 0;
+ aChildPos.Y += nRowHeight + aChildSize.Height * fSpaceHeight;
+ nRowHeight = 0;
+ }
+
+ nIdx++;
}
break;
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
index c742f604a409..e6089a96f4d3 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
@@ -160,6 +160,7 @@ public:
{ mnType = nToken; }
void addParam( sal_Int32 nType, sal_Int32 nVal )
{ maMap[nType]=nVal; }
+ sal_Int32 getVerticalShapesCount(const ShapePtr& rShape);
void layoutShape( const ShapePtr& rShape,
const std::vector<Constraint>& rConstraints );
diff --git a/oox/source/drawingml/diagram/layoutatomvisitorbase.hxx b/oox/source/drawingml/diagram/layoutatomvisitorbase.hxx
index 7007cf283070..ff12f82e2f96 100644
--- a/oox/source/drawingml/diagram/layoutatomvisitorbase.hxx
+++ b/oox/source/drawingml/diagram/layoutatomvisitorbase.hxx
@@ -50,7 +50,8 @@ public:
mpCurrentNode(pRootPoint),
mnCurrIdx(0),
mnCurrStep(0),
- mnCurrCnt(0)
+ mnCurrCnt(0),
+ meLookFor(LAYOUT_NODE)
{}
void defaultVisit(LayoutAtom const& rAtom);
@@ -67,6 +68,7 @@ protected:
sal_Int32 mnCurrIdx;
sal_Int32 mnCurrStep;
sal_Int32 mnCurrCnt;
+ enum {LAYOUT_NODE, CONSTRAINT, ALGORITHM} meLookFor;
};
class ShallowPresNameVisitor : public LayoutAtomVisitorBase
diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx
index 31b853664577..4bfadc3affe8 100644
--- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx
+++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx
@@ -37,11 +37,18 @@ void ShapeCreationVisitor::visit(ConstraintAtom& /*rAtom*/)
void ShapeCreationVisitor::visit(AlgAtom& rAtom)
{
- mpParentShape->setAspectRatio(rAtom.getAspectRatio());
+ if (meLookFor == ALGORITHM)
+ {
+ mpParentShape->setAspectRatio(rAtom.getAspectRatio());
+ mpParentShape->setVerticalShapesCount(rAtom.getVerticalShapesCount(mpParentShape));
+ }
}
void ShapeCreationVisitor::visit(LayoutNode& rAtom)
{
+ if (meLookFor != LAYOUT_NODE)
+ return;
+
// stop processing if it's not a child of previous LayoutNode
const DiagramData::PointsNameMap::const_iterator aDataNode = mrDgm.getData()->getPointsPresNameMap().find(rAtom.getName());
@@ -108,17 +115,22 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom)
mpParentShape=pCurrParent;
// process children
+ meLookFor = LAYOUT_NODE;
defaultVisit(rAtom);
- // restore parent
- mpParentShape=pPreviousParent;
- mpCurrentNode = pPreviousNode;
-
// 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());
+
+ meLookFor = ALGORITHM;
+ defaultVisit(rAtom);
+ meLookFor = LAYOUT_NODE;
+
+ // restore parent
+ mpParentShape=pPreviousParent;
+ mpCurrentNode = pPreviousNode;
}
void ShapeCreationVisitor::visit(ShapeAtom& /*rAtom*/)
diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.hxx b/oox/source/drawingml/diagram/layoutatomvisitors.hxx
index 2950fb01a17c..656f61d79e6a 100644
--- a/oox/source/drawingml/diagram/layoutatomvisitors.hxx
+++ b/oox/source/drawingml/diagram/layoutatomvisitors.hxx
@@ -74,8 +74,7 @@ class ShapeLayoutingVisitor : public LayoutAtomVisitorBase
{
public:
ShapeLayoutingVisitor(const Diagram& rDgm, const dgm::Point* pRootPoint) :
- LayoutAtomVisitorBase(rDgm, pRootPoint),
- meLookFor(LAYOUT_NODE)
+ LayoutAtomVisitorBase(rDgm, pRootPoint)
{}
using LayoutAtomVisitorBase::visit;
@@ -86,7 +85,6 @@ public:
private:
std::vector<Constraint> maConstraints;
- enum {LAYOUT_NODE, CONSTRAINT, ALGORITHM} meLookFor;
};
} }