diff options
-rw-r--r-- | include/oox/drawingml/drawingmltypes.hxx | 7 | ||||
-rw-r--r-- | include/oox/drawingml/shape.hxx | 10 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/diagramlayoutatoms.cxx | 133 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/diagramlayoutatoms.hxx | 27 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/layoutatomvisitors.cxx | 7 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/layoutnodecontext.cxx | 1 | ||||
-rw-r--r-- | oox/source/drawingml/shape.cxx | 7 | ||||
-rw-r--r-- | sd/qa/unit/data/pptx/smartart-picture-strip.pptx | bin | 0 -> 52395 bytes | |||
-rw-r--r-- | sd/qa/unit/import-tests-smartart.cxx | 85 |
9 files changed, 250 insertions, 27 deletions
diff --git a/include/oox/drawingml/drawingmltypes.hxx b/include/oox/drawingml/drawingmltypes.hxx index c4f05fcdd84e..2abe05767d6a 100644 --- a/include/oox/drawingml/drawingmltypes.hxx +++ b/include/oox/drawingml/drawingmltypes.hxx @@ -190,6 +190,13 @@ inline float convertEmuToPoints( sal_Int64 nValue ) return static_cast<float>(nValue) / EMU_PER_PT; } +/** Converts the passed double value from points to mm. */ +inline double convertPointToMms(double fValue) +{ + constexpr double fFactor = static_cast<double>(EMU_PER_PT) / (EMU_PER_HMM * 100); + return fValue * fFactor; +} + /** A structure for a point with 64-bit integer components. */ struct EmuPoint { diff --git a/include/oox/drawingml/shape.hxx b/include/oox/drawingml/shape.hxx index 4a571213a090..40a80ae113dc 100644 --- a/include/oox/drawingml/shape.hxx +++ b/include/oox/drawingml/shape.hxx @@ -226,6 +226,13 @@ public: sal_Int32 getDataNodeType() const { return mnDataNodeType; } + void setAspectRatio(double fAspectRatio) { mfAspectRatio = fAspectRatio; } + + double getAspectRatio() const { return mfAspectRatio; } + + /// Changes reference semantics to value semantics for fill properties. + void cloneFillProperties(); + protected: css::uno::Reference< css::drawing::XShape > const & @@ -348,6 +355,9 @@ private: /// Type of data node for an in-diagram shape. sal_Int32 mnDataNodeType = 0; + + /// Aspect ratio for an in-diagram shape. + double mfAspectRatio = 0; }; } } diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx index 09edf0022259..247b99d0baad 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -65,6 +65,24 @@ bool isFontUnit(sal_Int32 nUnit) return nUnit == oox::XML_primFontSz || nUnit == oox::XML_secFontSz; } +/// Determines which UNO property should be set for a given constraint type. +sal_Int32 getPropertyFromConstraint(sal_Int32 nConstraint) +{ + switch (nConstraint) + { + case oox::XML_lMarg: + return oox::PROP_TextLeftDistance; + case oox::XML_rMarg: + return oox::PROP_TextRightDistance; + case oox::XML_tMarg: + return oox::PROP_TextUpperDistance; + case oox::XML_bMarg: + return oox::PROP_TextLowerDistance; + } + + return 0; +} + /// Determines the connector shape type from a linear alg. sal_Int32 getConnectorType(const oox::drawingml::LayoutNode* pNode) { @@ -246,7 +264,7 @@ void LayoutAtom::dump(int level) pAtom->dump(level + 1); } -ForEachAtom::ForEachAtom(const LayoutNode& rLayoutNode, const Reference< XFastAttributeList >& xAttributes) : +ForEachAtom::ForEachAtom(LayoutNode& rLayoutNode, const Reference< XFastAttributeList >& xAttributes) : LayoutAtom(rLayoutNode) { maIter.loadFromXAttr(xAttributes); @@ -273,7 +291,7 @@ const std::vector<LayoutAtomPtr>& ChooseAtom::getChildren() const return maEmptyChildren; } -ConditionAtom::ConditionAtom(const LayoutNode& rLayoutNode, bool isElse, const Reference< XFastAttributeList >& xAttributes) : +ConditionAtom::ConditionAtom(LayoutNode& rLayoutNode, bool isElse, const Reference< XFastAttributeList >& xAttributes) : LayoutAtom(rLayoutNode), mIsElse(isElse) { @@ -447,6 +465,21 @@ void ConstraintAtom::accept( LayoutAtomVisitor& rVisitor ) void ConstraintAtom::parseConstraint(std::vector<Constraint>& rConstraints, bool bRequireForName) const { + // Whitelist for cases where empty forName is handled. + if (bRequireForName) + { + switch (maConstraint.mnType) + { + case XML_sp: + case XML_lMarg: + case XML_rMarg: + case XML_tMarg: + case XML_bMarg: + bRequireForName = false; + break; + } + } + if (bRequireForName && maConstraint.msForName.isEmpty()) return; @@ -464,7 +497,7 @@ void AlgAtom::accept( LayoutAtomVisitor& rVisitor ) } void AlgAtom::layoutShape( const ShapePtr& rShape, - const std::vector<Constraint>& rOwnConstraints ) const + const std::vector<Constraint>& rOwnConstraints ) { // Algorithm result may depend on the parent constraints as well. std::vector<Constraint> aMergedConstraints; @@ -860,6 +893,18 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0) break; + // Parse constraints, only self spacing from height as a start. + double fSpaceFromConstraint = 0; + for (const auto& rConstr : rConstraints) + { + if (rConstr.mnRefType == XML_h) + { + if (rConstr.mnType == XML_sp && rConstr.msForName.isEmpty()) + fSpaceFromConstraint = rConstr.mfFactor; + } + } + bool bSpaceFromConstraints = fSpaceFromConstraint != 0; + const sal_Int32 nDir = maMap.count(XML_grDir) ? maMap.find(XML_grDir)->second : XML_tL; sal_Int32 nIncX = 1; sal_Int32 nIncY = 1; @@ -871,38 +916,67 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, case XML_bR: nIncX = -1; nIncY = -1; break; } - // TODO: get values from constraints sal_Int32 nCount = rShape->getChildren().size(); - double fSpace = 0.3; + // Defaults in case not provided by constraints. + double fSpace = bSpaceFromConstraints ? fSpaceFromConstraint : 0.3; double fAspectRatio = 0.54; // diagram should not spill outside, earlier it was 0.6 sal_Int32 nCol = 1; sal_Int32 nRow = 1; - for ( ; nRow<nCount; nRow++) + double fChildAspectRatio = rShape->getChildren()[0]->getAspectRatio(); + if (nCount <= fChildAspectRatio) + // Child aspect ratio request (width/height) is N, and we have at most N shapes. + // This means we don't need multiple columns. + nRow = nCount; + else { - nCol = (nCount+nRow-1) / nRow; - const double fShapeHeight = rShape->getSize().Height; - const double fShapeWidth = rShape->getSize().Width; - if ((fShapeHeight / nCol) / (fShapeWidth / nRow) >= fAspectRatio) - break; + for ( ; nRow<nCount; nRow++) + { + nCol = (nCount+nRow-1) / nRow; + const double fShapeHeight = rShape->getSize().Height; + const double fShapeWidth = rShape->getSize().Width; + if ((fShapeHeight / nCol) / (fShapeWidth / nRow) >= fAspectRatio) + break; + } } SAL_INFO("oox.drawingml", "Snake layout grid: " << nCol << "x" << nRow); sal_Int32 nWidth = rShape->getSize().Width / (nCol + (nCol-1)*fSpace); - const awt::Size aChildSize(nWidth, nWidth * fAspectRatio); + awt::Size aChildSize(nWidth, nWidth * fAspectRatio); + if (nCol == 1 && nRow > 1) + { + // We have a single column, so count the height based on the parent height, not + // based on width. + // Space occurs inside children; also double amount of space is needed outside (on + // both sides), if the factor comes from a constraint. + sal_Int32 nNumSpaces = -1; + if (bSpaceFromConstraints) + nNumSpaces += 4; + sal_Int32 nHeight + = rShape->getSize().Height / (nRow + (nRow + nNumSpaces) * fSpace); + + if (fChildAspectRatio > 1) + { + // Shrink width if the aspect ratio requires it. + nWidth = std::min(rShape->getSize().Width, + static_cast<sal_Int32>(nHeight * fChildAspectRatio)); + aChildSize = awt::Size(nWidth, nHeight); + } + } 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; + else if (bSpaceFromConstraints) + // Initial vertical offset to have upper spacing (outside, so double amount). + aCurrPos.Y = aChildSize.Height * fSpace * 2; sal_Int32 nStartX = aCurrPos.X; sal_Int32 nColIdx = 0,index = 0; - sal_Int32 num = rShape->getChildren().size(); - const sal_Int32 aContDir = maMap.count(XML_contDir) ? maMap.find(XML_contDir)->second : XML_sameDir; switch(aContDir) @@ -922,7 +996,7 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, if(++nColIdx == nCol) // condition for next row { // if last row, then position children according to number of shapes. - if((index+1)%nCol!=0 && (index+1)>=3 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol) + if((index+1)%nCol!=0 && (index+1)>=3 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol) // position first child of last row aCurrPos.X = nStartX + (nIncX * (aChildSize.Width + fSpace*aChildSize.Width))/2; else @@ -961,10 +1035,10 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, if(++nColIdx == nCol) // condition for next row { // if last row, then position children according to number of shapes. - if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol && ((index/nCol)+1)%2==0) + if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol && ((index/nCol)+1)%2==0) // position first child of last row aCurrPos.X -= aChildSize.Width*3/2; - else if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol && ((index/nCol)+1)%2!=0) + else if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol && ((index/nCol)+1)%2!=0) aCurrPos.X = nStartX + (nIncX * (aChildSize.Width + fSpace*aChildSize.Width))/2; else if(((index/nCol)+1)%2!=0) aCurrPos.X = nStartX; @@ -997,6 +1071,29 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, case XML_tx: { // adjust text alignment + + // Parse constraints, only self margins as a start. + for (const auto& rConstr : rConstraints) + { + if (rConstr.mnRefType == XML_w) + { + if (!rConstr.msForName.isEmpty()) + continue; + + sal_Int32 nProperty = getPropertyFromConstraint(rConstr.mnType); + if (!nProperty) + continue; + + // PowerPoint takes size as points, but gives margin as MMs. + double fFactor = convertPointToMms(rConstr.mfFactor); + + // DrawingML works in EMUs, UNO API works in MM100s. + sal_Int32 nValue = rShape->getSize().Width * fFactor / EMU_PER_HMM; + + rShape->getShapeProperties().setProperty(nProperty, nValue); + } + } + // TODO: adjust text size to fit shape TextBodyPtr pTextBody = rShape->getTextBody(); if (!pTextBody || @@ -1220,6 +1317,8 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode " processing shape type " << rShape->getCustomShapeProperties()->getShapePresetType() << " for layout node named \"" << msName << "\""); + if (pPresNode->mpShape) + rShape->getFillProperties().assignUsed(pPresNode->mpShape->getFillProperties()); } // TODO(Q1): apply styling & coloring - take presentation diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx index 75149a5cbecd..9b184f917f17 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -91,10 +91,10 @@ typedef std::shared_ptr< LayoutAtom > LayoutAtomPtr; class LayoutAtom { public: - LayoutAtom(const LayoutNode& rLayoutNode) : mrLayoutNode(rLayoutNode) {} + LayoutAtom(LayoutNode& rLayoutNode) : mrLayoutNode(rLayoutNode) {} virtual ~LayoutAtom() { } - const LayoutNode& getLayoutNode() const + LayoutNode& getLayoutNode() { return mrLayoutNode; } /** visitor acceptance @@ -127,7 +127,7 @@ public: void dump(int level = 0); protected: - const LayoutNode& mrLayoutNode; + LayoutNode& mrLayoutNode; std::vector< LayoutAtomPtr > mpChildNodes; std::weak_ptr<LayoutAtom> mpParent; OUString msName; @@ -137,7 +137,7 @@ class ConstraintAtom : public LayoutAtom { public: - ConstraintAtom(const LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode) {} + ConstraintAtom(LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode) {} virtual void accept( LayoutAtomVisitor& ) override; Constraint& getConstraint() { return maConstraint; } @@ -150,7 +150,7 @@ class AlgAtom : public LayoutAtom { public: - AlgAtom(const LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode), mnType(0), maMap() {} + AlgAtom(LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode), mnType(0), maMap() {} typedef std::map<sal_Int32,sal_Int32> ParamMap; @@ -161,7 +161,7 @@ public: void addParam( sal_Int32 nType, sal_Int32 nVal ) { maMap[nType]=nVal; } void layoutShape( const ShapePtr& rShape, - const std::vector<Constraint>& rConstraints ) const; + const std::vector<Constraint>& rConstraints ); /// Gives access to <dgm:alg type="..."/>. sal_Int32 getType() const { return mnType; } @@ -171,6 +171,8 @@ public: void setAspectRatio(double fAspectRatio) { mfAspectRatio = fAspectRatio; } + double getAspectRatio() const { return mfAspectRatio; } + private: sal_Int32 mnType; ParamMap maMap; @@ -184,7 +186,7 @@ class ForEachAtom : public LayoutAtom { public: - explicit ForEachAtom(const LayoutNode& rLayoutNode, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes); + explicit ForEachAtom(LayoutNode& rLayoutNode, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes); IteratorAttr & iterator() { return maIter; } @@ -200,7 +202,7 @@ class ConditionAtom : public LayoutAtom { public: - explicit ConditionAtom(const LayoutNode& rLayoutNode, bool isElse, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes); + explicit ConditionAtom(LayoutNode& rLayoutNode, bool isElse, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes); virtual void accept( LayoutAtomVisitor& ) override; bool getDecision() const; private: @@ -220,7 +222,7 @@ class ChooseAtom : public LayoutAtom { public: - ChooseAtom(const LayoutNode& rLayoutNode) + ChooseAtom(LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode) #if defined __clang__ && __clang_major__ == 3 && __clang_minor__ == 8 , maEmptyChildren() @@ -264,6 +266,10 @@ public: const LayoutNode* getParentLayoutNode() const; + void setAlgAtom(AlgAtomPtr pAlgAtom) { mpAlgAtom = pAlgAtom; } + + AlgAtomPtr getAlgAtom() const { return mpAlgAtom.lock(); } + private: const Diagram& mrDgm; VarMap mVariables; @@ -272,6 +278,7 @@ private: ShapePtr mpExistingShape; std::vector<ShapePtr> mpNodeShapes; sal_Int32 mnChildOrder; + std::weak_ptr<AlgAtom> mpAlgAtom; }; typedef std::shared_ptr< LayoutNode > LayoutNodePtr; @@ -280,7 +287,7 @@ class ShapeAtom : public LayoutAtom { public: - ShapeAtom(const LayoutNode& rLayoutNode, const ShapePtr& pShape) : LayoutAtom(rLayoutNode), mpShapeTemplate(pShape) {} + ShapeAtom(LayoutNode& rLayoutNode, const ShapePtr& pShape) : LayoutAtom(rLayoutNode), mpShapeTemplate(pShape) {} virtual void accept( LayoutAtomVisitor& ) override; const ShapePtr& getShapeTemplate() const { return mpShapeTemplate; } diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx index e2d6c4681b5c..4e69e8c8725b 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx @@ -131,6 +131,8 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) if (rAtom.setupShape(pShape, pNewNode)) { pShape->setInternalName(rAtom.getName()); + if (AlgAtomPtr pAlgAtom = rAtom.getAlgAtom()) + pShape->setAspectRatio(pAlgAtom->getAspectRatio()); rAtom.addNodeShape(pShape); } } @@ -151,6 +153,8 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) if (rAtom.setupShape(pShape, pNewNode)) { pShape->setInternalName(rAtom.getName()); + if (AlgAtomPtr pAlgAtom = rAtom.getAlgAtom()) + pShape->setAspectRatio(pAlgAtom->getAspectRatio()); pCurrParent->addChild(pShape); pCurrParent = pShape; rAtom.addNodeShape(pShape); @@ -270,6 +274,9 @@ void ShapeTemplateVisitor::visit(ShapeAtom& rAtom) // TODO(F3): cloned shape shares all properties by reference, // don't change them! mpShape.reset(new Shape(pCurrShape)); + // Fill properties have to be changed as sometimes only the presentation node contains the blip + // fill, unshare those. + mpShape->cloneFillProperties(); } void ShapeLayoutingVisitor::defaultVisit(LayoutAtom const & rAtom) diff --git a/oox/source/drawingml/diagram/layoutnodecontext.cxx b/oox/source/drawingml/diagram/layoutnodecontext.cxx index 24264135478b..646ab5ecd3da 100644 --- a/oox/source/drawingml/diagram/layoutnodecontext.cxx +++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx @@ -230,6 +230,7 @@ LayoutNodeContext::onCreateContext( ::sal_Int32 aElement, // CT_Algorithm AlgAtomPtr pAtom( new AlgAtom(mpNode->getLayoutNode()) ); LayoutAtom::connect(mpNode, pAtom); + mpNode->getLayoutNode().setAlgAtom(pAtom); return new AlgorithmContext( *this, rAttribs, pAtom ); } case DGM_TOKEN( choose ): diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 55d154642960..4c552194b08a 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -178,6 +178,7 @@ Shape::Shape( const ShapePtr& pSourceShape ) , mnZOrder(pSourceShape->mnZOrder) , mnZOrderOff(pSourceShape->mnZOrderOff) , mnDataNodeType(pSourceShape->mnDataNodeType) +, mfAspectRatio(pSourceShape->mfAspectRatio) {} Shape::~Shape() @@ -1806,6 +1807,12 @@ uno::Sequence< uno::Sequence< uno::Any > > Shape::resolveRelationshipsOfTypeFro return xRelListTemp; } +void Shape::cloneFillProperties() +{ + auto pFillProperties = std::make_shared<FillProperties>(); + pFillProperties->assignUsed(*mpFillPropertiesPtr); + mpFillPropertiesPtr = pFillProperties; +} } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/qa/unit/data/pptx/smartart-picture-strip.pptx b/sd/qa/unit/data/pptx/smartart-picture-strip.pptx Binary files differnew file mode 100644 index 000000000000..bfb8d4f2c1bd --- /dev/null +++ b/sd/qa/unit/data/pptx/smartart-picture-strip.pptx diff --git a/sd/qa/unit/import-tests-smartart.cxx b/sd/qa/unit/import-tests-smartart.cxx index 29f998ce6f43..b1ced877c00d 100644 --- a/sd/qa/unit/import-tests-smartart.cxx +++ b/sd/qa/unit/import-tests-smartart.cxx @@ -15,6 +15,7 @@ #include <com/sun/star/text/XText.hpp> #include <comphelper/sequenceashashmap.hxx> +#include <oox/drawingml/drawingmltypes.hxx> using namespace ::com::sun::star; @@ -52,6 +53,7 @@ public: void testContinuousBlockProcess(); void testOrgChart(); void testCycleMatrix(); + void testPictureStrip(); CPPUNIT_TEST_SUITE(SdImportTestSmartArt); @@ -69,6 +71,7 @@ public: CPPUNIT_TEST(testContinuousBlockProcess); CPPUNIT_TEST(testOrgChart); CPPUNIT_TEST(testCycleMatrix); + CPPUNIT_TEST(testPictureStrip); CPPUNIT_TEST_SUITE_END(); }; @@ -640,6 +643,88 @@ void SdImportTestSmartArt::testCycleMatrix() xDocShRef->DoClose(); } +void SdImportTestSmartArt::testPictureStrip() +{ + sd::DrawDocShellRef xDocShRef = loadURL( + m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/smartart-picture-strip.pptx"), PPTX); + uno::Reference<drawing::XShape> xGroup(getShapeFromPage(0, 0, xDocShRef), uno::UNO_QUERY); + CPPUNIT_ASSERT(xGroup.is()); + + uno::Reference<beans::XPropertySet> xFirstImage(getChildShape(getChildShape(xGroup, 0), 1), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstImage.is()); + drawing::FillStyle eFillStyle = drawing::FillStyle_NONE; + xFirstImage->getPropertyValue("FillStyle") >>= eFillStyle; + // Without the accompanying fix in place, this test would have failed: fill style was solid, not + // bitmap. + CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP, eFillStyle); + + uno::Reference<graphic::XGraphic> xGraphic; + xFirstImage->getPropertyValue("FillBitmap") >>= xGraphic; + Graphic aFirstGraphic(xGraphic); + + uno::Reference<beans::XPropertySet> xSecondImage(getChildShape(getChildShape(xGroup, 1), 1), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xSecondImage.is()); + eFillStyle = drawing::FillStyle_NONE; + xSecondImage->getPropertyValue("FillStyle") >>= eFillStyle; + CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP, eFillStyle); + + xSecondImage->getPropertyValue("FillBitmap") >>= xGraphic; + Graphic aSecondGraphic(xGraphic); + // Without the accompanying fix in place, this test would have failed: both xFirstImage and + // xSecondImage had the bitmap fill from the second shape. + CPPUNIT_ASSERT(aFirstGraphic.GetChecksum() != aSecondGraphic.GetChecksum()); + + // Test that the 3 images are in a single column, in 3 rows. + uno::Reference<drawing::XShape> xFirstImageShape(xFirstImage, uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstImage.is()); + uno::Reference<drawing::XShape> xSecondImageShape(xSecondImage, uno::UNO_QUERY); + CPPUNIT_ASSERT(xSecondImage.is()); + uno::Reference<drawing::XShape> xThirdImageShape(getChildShape(getChildShape(xGroup, 2), 1), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xThirdImageShape.is()); + // Without the accompanying fix in place, this test would have failed: the first and the second + // image were in the same row. + CPPUNIT_ASSERT_EQUAL(xFirstImageShape->getPosition().X, xSecondImageShape->getPosition().X); + CPPUNIT_ASSERT_EQUAL(xSecondImageShape->getPosition().X, xThirdImageShape->getPosition().X); + CPPUNIT_ASSERT_GREATER(xFirstImageShape->getPosition().Y, xSecondImageShape->getPosition().Y); + CPPUNIT_ASSERT_GREATER(xSecondImageShape->getPosition().Y, xThirdImageShape->getPosition().Y); + + // Make sure that the title shape doesn't overlap with the diagram. + // Note that real "no overlap" is asserted here, though in fact what we want is a less strict + // condition: that no text part of the title shape and the diagram overlaps. + uno::Reference<drawing::XShape> xTitle(getShapeFromPage(1, 0, xDocShRef), uno::UNO_QUERY); + CPPUNIT_ASSERT(xTitle.is()); + // Without the accompanying fix in place, this test would have failed with 'Expected greater + // than: 2873; Actual : 2320', i.e. the title shape and the diagram overlapped. + CPPUNIT_ASSERT_GREATER(xTitle->getPosition().Y + xTitle->getSize().Height, + xGroup->getPosition().Y); + + // Make sure that left margin is 60% of width (if you count width in points and margin in mms). + uno::Reference<beans::XPropertySet> xFirstText(getChildShape(getChildShape(xGroup, 0), 0), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstText.is()); + sal_Int32 nTextLeftDistance = 0; + xFirstText->getPropertyValue("TextLeftDistance") >>= nTextLeftDistance; + uno::Reference<drawing::XShape> xFirstTextShape(xFirstText, uno::UNO_QUERY); + CPPUNIT_ASSERT(xFirstTextShape.is()); + sal_Int32 nWidth = xFirstTextShape->getSize().Width; + double fFactor = oox::drawingml::convertPointToMms(0.6); + // Without the accompanying fix in place, this test would have failed with 'Expected: 3440, + // Actual : 263', i.e. the left margin was too small. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(nWidth * fFactor), nTextLeftDistance); + + // Make sure that aspect ratio is not ignored, i.e. width is not larger than height 3 times. + uno::Reference<drawing::XShape> xFirstPair = getChildShape(xGroup, 0); + awt::Size aFirstPairSize = xFirstPair->getSize(); + // Without the accompanying fix in place, this test would have failed: bad width was 16932, good + // width is 12540, but let's accept 12541 as well. + CPPUNIT_ASSERT_LESSEQUAL(aFirstPairSize.Height * 3 + 1, aFirstPairSize.Width); + + xDocShRef->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTestSmartArt); CPPUNIT_PLUGIN_IMPLEMENT(); |