oox/source/drawingml/diagram/datamodel.cxx | 59 +++++++++++++++++++++++++++-- oox/source/drawingml/diagram/datamodel.hxx | 11 ++++- oox/source/drawingml/diagram/diagram.cxx | 8 +++ 3 files changed, 71 insertions(+), 7 deletions(-)
New commits: commit 2b56631f9406b29eebcfcbe8dec5348590b4b817 Author: Armin Le Grand (Allotropia) <armin.le.gr...@me.com> AuthorDate: Fri Mar 25 16:34:30 2022 +0100 Commit: Armin Le Grand <armin.le.gr...@me.com> CommitDate: Sat Mar 26 15:36:01 2022 +0100 Advanced Diagram support: Preparations to make oox-Shape temporary When we come from the LO-side of things and need to (re)create the Diagram, no oox-Shapes can exist by definition. That forces to see oox-Shapes as temporary helper objects. Since some ModelData is at the oox-Shape after importing a Diagram that data needs to be identified and added to the Diagram ModelData. On the other path, when (re)creating a Diagram from the ModelData, oox-Shapes are needed to use the currently existing mechanism in the import-Filter to create XShapes froom the oox-Shapes. In that path, the Diagram ModelData needs to be applied to the newly created oox-Shape. For now I have identified e.g. the Text as such data value. In the future there may be more ModelData of that type identified and may need to be added. To support that, I have added methods to do that. It may even be feasible in debug builds to add code to compare the imported oox-Shape with a temporarily (re)created one to allow easier identification of yet missing secured/copied ModelData. To make that mechanism obligatory I have added code in DiagramData::build() that deletes all oox-Shapes which were created at Diagam import. This is necessary. That way, the (re)creation is used for Diagram re-creation and can be already used and tested. Deleting all oox-Shapes in build() immediately triggered an error in a UnitTest: testPictureStrip. This shows that here some ModelData in form of BitmapData is not secured - proof of concept and what I described above. To get forward, I adapted to not delete oox-Shapes when Diagram import is executed. Thus, the UnitTests work, and the ReCreate can be used to trigger that behaviour. As an end result this has to be re-activated. It allows now to search and add the missing model data from the test file used in that UnitTest. Change-Id: I6bc39a0898c7be1b4c656875f6d7508c36c9bea8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132127 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/oox/source/drawingml/diagram/datamodel.cxx b/oox/source/drawingml/diagram/datamodel.cxx index c68ee40cd71c..325259295fef 100644 --- a/oox/source/drawingml/diagram/datamodel.cxx +++ b/oox/source/drawingml/diagram/datamodel.cxx @@ -68,11 +68,53 @@ Shape* DiagramData::getOrCreateAssociatedShape(const dgm::Point& rPoint, bool bC if(!rShapePtr && bCreateOnDemand) { const_cast<ShapePtr&>(rShapePtr) = std::make_shared<Shape>(); + + // If we did create a new oox::drawingml::Shape, directly apply + // available data from the Diagram ModelData to it as preparation + restoreDataFromModelToShapeAfterReCreation(rPoint, *rShapePtr); } return rShapePtr.get(); } +void DiagramData::restoreDataFromModelToShapeAfterReCreation(const dgm::Point& rPoint, Shape& rNewShape) const +{ + // If we did create a new oox::drawingml::Shape, directly apply + // available data from the Diagram ModelData to it as preparation + + // This is e.g. the Text, but may get more (styles?) + const auto pTextForShape = maPointTextMap.find(rPoint.msModelId); + if (pTextForShape != maPointTextMap.end()) + { + rNewShape.setTextBody(pTextForShape->second); + } +} + +void DiagramData::secureDataFromShapeToModelAfterDiagramImport() +{ + // After Diagram import, parts of the Diagram ModelData is at the + // oox::drawingml::Shape. Since these objects are temporary helpers, + // secure that data at the Diagram ModelData by copying. + + // This is currently mainly the Text, but may get more (styles?) + for (auto & point : maPoints) + { + Shape* pShapeCandidate(getOrCreateAssociatedShape(point)); + + if(nullptr != pShapeCandidate + && pShapeCandidate->getTextBody() + && !pShapeCandidate->getTextBody()->isEmpty()) + { + maPointTextMap[point.msModelId] = pShapeCandidate->getTextBody(); + } + } + + // At this place a mechanism to find missing data should be added: + // Create a Shape from so-far secured data & compare it with the + // imported one. Report differences to allow extending the mechanism + // more easily. +} + DiagramData::DiagramData() : mpFillProperties( std::make_shared<FillProperties>() ) { @@ -242,7 +284,7 @@ OUString DiagramData::addNode(const OUString& rText) maPoints.push_back(aDataPoint); maPoints.push_back(aPresPoint); - build(); + build(true); return sNewNodeId; } @@ -294,7 +336,7 @@ bool DiagramData::removeNode(const OUString& rNodeId) // TODO: fix source/dest order - build(); + build(true); return true; } @@ -338,8 +380,14 @@ static sal_Int32 calcDepth( std::u16string_view rNodeName, return 0; } -void DiagramData::build() +void DiagramData::build(bool bClearOoxShapes) { + // Delete/remove all existing oox::drawingml::Shape + if(bClearOoxShapes) + { + maPointShapeMap.clear(); + } + // build name-object maps maPointNameMap.clear(); maPointsPresNameMap.clear(); @@ -384,8 +432,11 @@ void DiagramData::build() output << "];" << std::endl; #endif + // Create/get shape. Re-create here, that may also set needed + // and available data from the Diagram ModelData at the Shape + Shape* pShape(getOrCreateAssociatedShape(point, true)); + // does currpoint have any text set? - Shape* pShape(getOrCreateAssociatedShape(point)); if( nullptr != pShape && pShape->getTextBody() && !pShape->getTextBody()->isEmpty() ) { #ifdef DEBUG_OOX_DIAGRAM diff --git a/oox/source/drawingml/diagram/datamodel.hxx b/oox/source/drawingml/diagram/datamodel.hxx index 8e4417652a57..292b31c6dabd 100644 --- a/oox/source/drawingml/diagram/datamodel.hxx +++ b/oox/source/drawingml/diagram/datamodel.hxx @@ -146,6 +146,7 @@ class DiagramData { public: typedef std::map< OUString, ShapePtr > PointShapeMap; + typedef std::map< OUString, TextBodyPtr > PointTextMap; typedef std::map< OUString, dgm::Point* > PointNameMap; typedef std::map< OUString, std::vector<dgm::Point*> > PointsNameMap; typedef std::map< OUString, const dgm::Connection* > ConnectionNameMap; @@ -163,7 +164,7 @@ public: virtual ~DiagramData() {} // creates temporary processing data from model data - void build(); + void build(bool bClearOoxShapes); FillPropertiesPtr & getFillProperties() { return mpFillProperties; } @@ -189,6 +190,10 @@ public: Shape* getOrCreateAssociatedShape(const dgm::Point& rPoint, bool bCreateOnDemand = false) const; + // get/set data between Diagram DataModel and oox::drawingml::Shape + void secureDataFromShapeToModelAfterDiagramImport(); + void restoreDataFromModelToShapeAfterReCreation(const dgm::Point& rPoint, Shape& rNewShape) const; + private: void getChildrenString(OUStringBuffer& rBuf, const dgm::Point* pPoint, sal_Int32 nLevel) const; void addConnection(sal_Int32 nType, const OUString& sSourceId, const OUString& sDestId); @@ -198,9 +203,11 @@ private: // the model definition, // - FillStyle - // - logic connections/associations + // - Texts for oox::drawingml::Points/dgm::Points, associated by ModelId + // - logic connections/assoziations // - data point entries FillPropertiesPtr mpFillProperties; + PointTextMap maPointTextMap; dgm::Connections maConnections; dgm::Points maPoints; diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx index c27c60b529ec..a1300ee908c8 100644 --- a/oox/source/drawingml/diagram/diagram.cxx +++ b/oox/source/drawingml/diagram/diagram.cxx @@ -403,8 +403,14 @@ void loadDiagram( ShapePtr const & pShape, } } + // After Diagram import, parts of the Diagram ModelData is at the + // oox::drawingml::Shape. Since these objects are temporary helpers, + // secure that data at the Diagram ModelData by copying. + pData->secureDataFromShapeToModelAfterDiagramImport(); + // collect data, init maps - pData->build(); + // for Diagram import, do - for now - NOT clear all oox::drawingml::Shape + pData->build(false); // diagram loaded. now lump together & attach to shape pDiagram->addTo(pShape);