diff options
-rw-r--r-- | oox/source/drawingml/diagram/diagram.cxx | 11 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/diagram.hxx | 8 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/diagramlayoutatoms.cxx | 71 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/diagramlayoutatoms.hxx | 4 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/layoutnodecontext.cxx | 16 | ||||
-rw-r--r-- | sd/qa/unit/data/pptx/smartart-cycle-matrix.pptx | bin | 0 -> 56986 bytes | |||
-rw-r--r-- | sd/qa/unit/import-tests-smartart.cxx | 93 |
7 files changed, 181 insertions, 22 deletions
diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx index 4664a55e594c..daddf1fa6991 100644 --- a/oox/source/drawingml/diagram/diagram.cxx +++ b/oox/source/drawingml/diagram/diagram.cxx @@ -270,8 +270,10 @@ void Diagram::build( ) if( connection.mnType == XML_presOf ) { DiagramData::StringMap::value_type::second_type& rVec=getData()->getPresOfNameMap()[connection.msDestId]; - rVec.emplace_back( - connection.msSourceId,sal_Int32(0)); + DiagramData::SourceIdAndDepth aSourceIdAndDepth; + aSourceIdAndDepth.msSourceId = connection.msSourceId; + aSourceIdAndDepth.mnDepth = 0; + rVec[connection.mnDestOrder] = aSourceIdAndDepth; } } @@ -281,9 +283,8 @@ void Diagram::build( ) { for (auto & elem : elemPresOf.second) { - const sal_Int32 nDepth=calcDepth(elem.first, - getData()->getConnections()); - elem.second = nDepth != 0 ? nDepth : -1; + const sal_Int32 nDepth = calcDepth(elem.second.msSourceId, getData()->getConnections()); + elem.second.mnDepth = nDepth != 0 ? nDepth : -1; if (nDepth > getData()->getMaxDepth()) getData()->setMaxDepth(nDepth); } diff --git a/oox/source/drawingml/diagram/diagram.hxx b/oox/source/drawingml/diagram/diagram.hxx index 242ff09fa152..a0955b124230 100644 --- a/oox/source/drawingml/diagram/diagram.hxx +++ b/oox/source/drawingml/diagram/diagram.hxx @@ -160,8 +160,14 @@ public: typedef std::map< OUString, std::vector<dgm::Point*> > PointsNameMap; typedef std::map< OUString, const dgm::Connection* > ConnectionNameMap; + struct SourceIdAndDepth + { + OUString msSourceId; + sal_Int32 mnDepth = 0; + }; + /// Tracks connections: destination id -> {destination order, details} map. typedef std::map< OUString, - std::vector<std::pair<OUString,sal_Int32> > > StringMap; + std::map<sal_Int32, SourceIdAndDepth > > StringMap; DiagramData(); FillPropertiesPtr & getFillProperties() diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx index 513dc9926e82..09edf0022259 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -369,6 +369,14 @@ sal_Int32 ConditionAtom::getNodeCount() const if (aCxn.mnType == XML_parOf && aCxn.msSourceId == sNodeId) nCount++; } + else + { + // No presentation child is a presentation of a model node: just + // count presentation children. + for (const auto& aCxn : mrLayoutNode.getDiagram().getData()->getConnections()) + if (aCxn.mnType == XML_presParOf && aCxn.msSourceId == pPoint->msModelId) + nCount++; + } } return nCount; } @@ -482,12 +490,29 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, 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; + + sal_Int32 nParentXOffset = 0; + if (mfAspectRatio != 1.0) + { + 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; + } + else + { + // Shrink width to be only as large as height. + rParent[XML_w] = std::min(rShape->getSize().Width, rShape->getSize().Height); + rParent[XML_h] = rShape->getSize().Height; + if (rParent[XML_w] < rShape->getSize().Width) + nParentXOffset = (rShape->getSize().Width - rParent[XML_w]) / 2; + rParent[XML_l] = nParentXOffset; + rParent[XML_t] = 0; + rParent[XML_r] = rShape->getSize().Width - rParent[XML_l]; + rParent[XML_b] = rShape->getSize().Height; + } for (const auto & rConstr : rConstraints) { @@ -526,25 +551,30 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, LayoutProperty::const_iterator it, it2; if ( (it = rProp.find(XML_w)) != rProp.end() ) - aSize.Width = it->second; + aSize.Width = std::min(it->second, rShape->getSize().Width); if ( (it = rProp.find(XML_h)) != rProp.end() ) - aSize.Height = it->second; + aSize.Height = std::min(it->second, rShape->getSize().Height); if ( (it = rProp.find(XML_l)) != rProp.end() ) aPos.X = it->second; else if ( (it = rProp.find(XML_ctrX)) != rProp.end() ) aPos.X = it->second - aSize.Width/2; + else if ((it = rProp.find(XML_r)) != rProp.end()) + aPos.X = it->second - aSize.Width; if ( (it = rProp.find(XML_t)) != rProp.end()) aPos.Y = it->second; else if ( (it = rProp.find(XML_ctrY)) != rProp.end() ) aPos.Y = it->second - aSize.Height/2; + else if ((it = rProp.find(XML_b)) != rProp.end()) + aPos.Y = it->second - aSize.Height; if ( (it = rProp.find(XML_l)) != rProp.end() && (it2 = rProp.find(XML_r)) != rProp.end() ) aSize.Width = it2->second - it->second; if ( (it = rProp.find(XML_t)) != rProp.end() && (it2 = rProp.find(XML_b)) != rProp.end() ) aSize.Height = it2->second - it->second; + aPos.X += nParentXOffset; aSize.Width = std::min(aSize.Width, rShape->getSize().Width - aPos.X); aSize.Height = std::min(aSize.Height, rShape->getSize().Height - aPos.Y); } @@ -1096,11 +1126,21 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode { DiagramData::StringMap::value_type::second_type::const_iterator aVecIter=aNodeName->second.begin(); const DiagramData::StringMap::value_type::second_type::const_iterator aVecEnd=aNodeName->second.end(); + // Calculate the depth of what is effectively the topmost element. + sal_Int32 nMinDepth = std::numeric_limits<sal_Int32>::max(); + for (const auto& rPair : aNodeName->second) + { + if (rPair.second.mnDepth < nMinDepth) + nMinDepth = rPair.second.mnDepth; + } + while( aVecIter != aVecEnd ) { + const auto& rPair = *aVecIter; + const DiagramData::SourceIdAndDepth& rItem = rPair.second; DiagramData::PointNameMap& rMap = mrDgm.getData()->getPointNameMap(); // pPresNode is the presentation node of the aDataNode2 data node. - DiagramData::PointNameMap::const_iterator aDataNode2 = rMap.find(aVecIter->first); + DiagramData::PointNameMap::const_iterator aDataNode2 = rMap.find(rItem.msSourceId); if (aDataNode2 == rMap.end()) { //busted, skip it @@ -1110,7 +1150,7 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode rShape->setDataNodeType(aDataNode2->second->mnType); - if( aVecIter->second == 0 ) + if( rItem.mnDepth == 0 ) { // grab shape attr from topmost element(s) rShape->getShapeProperties() = aDataNode2->second->mpShape->getShapeProperties(); @@ -1127,6 +1167,13 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode << " added for layout node named \"" << msName << "\""); } + else if (rItem.mnDepth == nMinDepth) + { + // If no real topmost element, then take properties from the one that's the closest + // to topmost. + rShape->getLineProperties() = aDataNode2->second->mpShape->getLineProperties(); + rShape->getFillProperties() = aDataNode2->second->mpShape->getFillProperties(); + } // append text with right outline level if( aDataNode2->second->mpShape->getTextBody() && @@ -1152,8 +1199,8 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode for (const auto& pSourceParagraph : rSourceParagraphs) { TextParagraph& rPara = pTextBody->addParagraph(); - if (aVecIter->second != -1) - rPara.getProperties().setLevel(aVecIter->second); + if (rItem.mnDepth != -1) + rPara.getProperties().setLevel(rItem.mnDepth); for (const auto& pRun : pSourceParagraph->getRuns()) rPara.addRun(pRun); diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx index 500495b6f2ca..75149a5cbecd 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -169,9 +169,13 @@ public: /// Gives access to <dgm:param type="..." val="..."/>. const ParamMap& getMap() const { return maMap; } + void setAspectRatio(double fAspectRatio) { mfAspectRatio = fAspectRatio; } + private: sal_Int32 mnType; ParamMap maMap; + /// Aspect ratio is not integer, so not part of maMap. + double mfAspectRatio = 0; }; typedef std::shared_ptr< AlgAtom > AlgAtomPtr; diff --git a/oox/source/drawingml/diagram/layoutnodecontext.cxx b/oox/source/drawingml/diagram/layoutnodecontext.cxx index ad62ba5d712b..24264135478b 100644 --- a/oox/source/drawingml/diagram/layoutnodecontext.cxx +++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx @@ -66,10 +66,18 @@ public: { case DGM_TOKEN( param ): { - const sal_Int32 nValTok = rAttribs.getToken( XML_val, 0 ); - mpNode->addParam( - rAttribs.getToken( XML_type, 0 ), - nValTok>0 ? nValTok : rAttribs.getInteger( XML_val, 0 ) ); + sal_Int32 nType = rAttribs.getToken(XML_type, 0); + switch (nType) + { + case XML_ar: + mpNode->setAspectRatio(rAttribs.getDouble(XML_val, 0)); + break; + default: + const sal_Int32 nValTok = rAttribs.getToken(XML_val, 0); + mpNode->addParam(nType, nValTok > 0 ? nValTok + : rAttribs.getInteger(XML_val, 0)); + break; + } break; } default: diff --git a/sd/qa/unit/data/pptx/smartart-cycle-matrix.pptx b/sd/qa/unit/data/pptx/smartart-cycle-matrix.pptx Binary files differnew file mode 100644 index 000000000000..fb1cb7ea2c2e --- /dev/null +++ b/sd/qa/unit/data/pptx/smartart-cycle-matrix.pptx diff --git a/sd/qa/unit/import-tests-smartart.cxx b/sd/qa/unit/import-tests-smartart.cxx index 9de4061a072b..29f998ce6f43 100644 --- a/sd/qa/unit/import-tests-smartart.cxx +++ b/sd/qa/unit/import-tests-smartart.cxx @@ -51,6 +51,7 @@ public: void testAccentProcess(); void testContinuousBlockProcess(); void testOrgChart(); + void testCycleMatrix(); CPPUNIT_TEST_SUITE(SdImportTestSmartArt); @@ -67,6 +68,7 @@ public: CPPUNIT_TEST(testAccentProcess); CPPUNIT_TEST(testContinuousBlockProcess); CPPUNIT_TEST(testOrgChart); + CPPUNIT_TEST(testCycleMatrix); CPPUNIT_TEST_SUITE_END(); }; @@ -547,6 +549,97 @@ void SdImportTestSmartArt::testOrgChart() xDocShRef->DoClose(); } +void SdImportTestSmartArt::testCycleMatrix() +{ + sd::DrawDocShellRef xDocShRef = loadURL( + m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/smartart-cycle-matrix.pptx"), PPTX); + uno::Reference<drawing::XShape> xGroup(getShapeFromPage(0, 0, xDocShRef), uno::UNO_QUERY); + CPPUNIT_ASSERT(xGroup.is()); + + // Without the accompanying fix in place, this test would have failed: the height was 12162, + // which is not the mm100 equivalent of the 4064000 EMU in the input file. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11287), xGroup->getSize().Height); + + uno::Reference<text::XText> xA1(getChildShape(getChildShape(xGroup, 1), 0), uno::UNO_QUERY); + CPPUNIT_ASSERT(xA1.is()); + CPPUNIT_ASSERT_EQUAL(OUString("A1"), xA1->getString()); + + // Test fill color of B1, should be orange. + uno::Reference<text::XText> xB1(getChildShape(getChildShape(xGroup, 1), 1), uno::UNO_QUERY); + CPPUNIT_ASSERT(xB1.is()); + CPPUNIT_ASSERT_EQUAL(OUString("B1"), xB1->getString()); + + uno::Reference<beans::XPropertySet> xB1Props(xB1, uno::UNO_QUERY); + CPPUNIT_ASSERT(xB1Props.is()); + sal_Int32 nFillColor = 0; + xB1Props->getPropertyValue("FillColor") >>= nFillColor; + // Without the accompanying fix in place, this test would have failed: the background color was + // 0x4f81bd, i.e. blue, not orange. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xf79646), nFillColor); + + // Without the accompanying fix in place, this test would have failed: the + // content of the "A2" shape was lost. + uno::Reference<text::XText> xA2(getChildShape(getChildShape(getChildShape(xGroup, 0), 0), 1), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xA2.is()); + CPPUNIT_ASSERT_EQUAL(OUString("A2"), xA2->getString()); + + // Test that the layout of shapes is like this: + // A2 B2 + // D2 C2 + + uno::Reference<drawing::XShape> xA2Shape(xA2, uno::UNO_QUERY); + CPPUNIT_ASSERT(xA2Shape.is()); + + uno::Reference<text::XText> xB2(getChildShape(getChildShape(getChildShape(xGroup, 0), 1), 1), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xB2.is()); + CPPUNIT_ASSERT_EQUAL(OUString("B2"), xB2->getString()); + uno::Reference<drawing::XShape> xB2Shape(xB2, uno::UNO_QUERY); + CPPUNIT_ASSERT(xB2Shape.is()); + + // Test line color of B2, should be orange. + uno::Reference<beans::XPropertySet> xB2Props(xB2, uno::UNO_QUERY); + CPPUNIT_ASSERT(xB2Props.is()); + sal_Int32 nLineColor = 0; + xB2Props->getPropertyValue("LineColor") >>= nLineColor; + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xf79646), nLineColor); + + uno::Reference<text::XText> xC2(getChildShape(getChildShape(getChildShape(xGroup, 0), 2), 1), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xC2.is()); + // Without the accompanying fix in place, this test would have failed, i.e. the order of the + // lines in the shape were wrong: C2-1\nC2-4\nC2-3\nC2-2. + CPPUNIT_ASSERT_EQUAL(OUString("C2-1\nC2-2\nC2-3\nC2-4"), xC2->getString()); + uno::Reference<drawing::XShape> xC2Shape(xC2, uno::UNO_QUERY); + CPPUNIT_ASSERT(xC2Shape.is()); + + uno::Reference<text::XText> xD2(getChildShape(getChildShape(getChildShape(xGroup, 0), 3), 1), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xD2.is()); + CPPUNIT_ASSERT_EQUAL(OUString("D2"), xD2->getString()); + uno::Reference<drawing::XShape> xD2Shape(xD2, uno::UNO_QUERY); + CPPUNIT_ASSERT(xD2Shape.is()); + + // Without the accompanying fix in place, this test would have failed, i.e. + // the A2 and B2 shapes had the same horizontal position, while B2 should + // be on the right of A2. + CPPUNIT_ASSERT_GREATER(xA2Shape->getPosition().X, xB2Shape->getPosition().X); + CPPUNIT_ASSERT_EQUAL(xA2Shape->getPosition().Y, xB2Shape->getPosition().Y); + CPPUNIT_ASSERT_GREATER(xA2Shape->getPosition().X, xC2Shape->getPosition().X); + CPPUNIT_ASSERT_GREATER(xA2Shape->getPosition().Y, xC2Shape->getPosition().Y); + CPPUNIT_ASSERT_EQUAL(xA2Shape->getPosition().X, xD2Shape->getPosition().X); + CPPUNIT_ASSERT_GREATER(xA2Shape->getPosition().Y, xD2Shape->getPosition().Y); + + // Without the accompanying fix in place, this test would have failed: width was expected to be + // 4887, was actually 7331. + uno::Reference<drawing::XShape> xA1Shape(xA1, uno::UNO_QUERY); + CPPUNIT_ASSERT(xA1Shape.is()); + CPPUNIT_ASSERT_EQUAL(xA1Shape->getSize().Height, xA1Shape->getSize().Width); + + xDocShRef->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTestSmartArt); CPPUNIT_PLUGIN_IMPLEMENT(); |