/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "diagramhelper.hxx" #include "diagram.hxx" #include #include #include #include #include #include #include #include using namespace ::com::sun::star; namespace oox::drawingml { bool AdvancedDiagramHelper::hasDiagramData() const { return mpDiagramPtr && mpDiagramPtr->getData(); } AdvancedDiagramHelper::AdvancedDiagramHelper( const std::shared_ptr< Diagram >& rDiagramPtr, const std::shared_ptr<::oox::drawingml::Theme>& rTheme, css::awt::Size aImportSize) : svx::diagram::IDiagramHelper() , mpDiagramPtr(rDiagramPtr) , mpThemePtr(rTheme) , maImportSize(aImportSize) { } AdvancedDiagramHelper::~AdvancedDiagramHelper() { } void AdvancedDiagramHelper::reLayout(SdrObjGroup& rTarget) { if(!mpDiagramPtr) { return; } // Rescue/remember geometric transformation of existing Diagram basegfx::B2DHomMatrix aTransformation; basegfx::B2DPolyPolygon aPolyPolygon; rTarget.TRGetBaseGeometry(aTransformation, aPolyPolygon); // create temporary oox::Shape as target. No longer needed is to keep/remember // the original oox::Shape to do that. Use original Size and Pos from initial import // to get the same layout(s) oox::drawingml::ShapePtr pShapePtr = std::make_shared( "com.sun.star.drawing.GroupShape" ); pShapePtr->setDiagramType(); pShapePtr->setSize(maImportSize); // Re-create the oox::Shapes for the diagram content mpDiagramPtr->addTo(pShapePtr); // Delete all existing shapes in that group to prepare re-creation rTarget.getChildrenOfSdrObject()->ClearSdrObjList(); // For re-creation we need to use ::addShape functionality from the // oox import filter since currently Shape import is very tightly // coupled to Shape creation. It converts a oox::Shape representation // combined with an oox::Theme to incarnated XShapes representing the // Diagram. // To use that functionality, we have to create a temporary filter // (based on ShapeFilterBase). Problems are that this needs to know // the oox:Theme and a ComponentModel from TargetDocument. // The DiagramHelper holds/delivers the oox::Theme to use, so // it does not need to be re-imported from oox repeatedly. // The ComponentModel can be derived from the existing XShape/GroupShape // when knowing where to get it from, making it independent from app. // // NOTE: Using another (buffered) oox::Theme would allow to re-create // using another theming in the future. // NOTE: The incarnation of import filter (ShapeFilterBase) is only // used for XShape creation, no xml snippets/data gets imported // here. XShape creation may be isolated in the future. SdrModel& rModel(rTarget.getSdrModelFromSdrObject()); uno::Reference< uno::XInterface > const & rUnoModel(rModel.getUnoModel()); css::uno::Reference xContext(comphelper::getProcessComponentContext()); rtl::Reference xFilter(new oox::shape::ShapeFilterBase(xContext)); // set oox::Theme at Filter. All LineStyle/FillStyle/Colors/Attributes // will be taken from there if(UseDiagramThemeData()) xFilter->setCurrentTheme(getOrCreateThemePtr(xFilter)); css::uno::Reference< css::lang::XComponent > aComponentModel( rUnoModel, uno::UNO_QUERY ); xFilter->setTargetDocument(aComponentModel); // set DiagramFontHeights xFilter->setDiagramFontHeights(&mpDiagramPtr->getDiagramFontHeights()); // Prepare the target for the to-be-created XShapes uno::Reference xShapes(rTarget.getUnoShape(), uno::UNO_QUERY_THROW); for (auto const& child : pShapePtr->getChildren()) { // Create all sub-shapes. This will recursively create needed geometry using // filter-internal ::createShapes child->addShape( *xFilter, xFilter->getCurrentTheme(), xShapes, aTransformation, pShapePtr->getFillProperties()); } // sync FontHeights mpDiagramPtr->syncDiagramFontHeights(); // re-apply secured data from ModelData if(UseDiagramModelData()) mpDiagramPtr->getData()->restoreDataFromShapeToModelAfterDiagramImport(*pShapePtr); // Re-apply remembered geometry rTarget.TRSetBaseGeometry(aTransformation, aPolyPolygon); } OUString AdvancedDiagramHelper::getString() const { if(hasDiagramData()) { return mpDiagramPtr->getData()->getString(); } return OUString(); } std::vector> AdvancedDiagramHelper::getChildren(const OUString& rParentId) const { if(hasDiagramData()) { return mpDiagramPtr->getData()->getChildren(rParentId); } return std::vector>(); } OUString AdvancedDiagramHelper::addNode(const OUString& rText) { OUString aRetval; if(hasDiagramData()) { aRetval = mpDiagramPtr->getData()->addNode(rText); // reset temporary buffered ModelData association lists & rebuild them // and the Diagram DataModel mpDiagramPtr->getData()->buildDiagramDataModel(true); // also reset temporary buffered layout data - that might // still refer to changed oox::Shape data mpDiagramPtr->getLayout()->getPresPointShapeMap().clear(); } return aRetval; } bool AdvancedDiagramHelper::removeNode(const OUString& rNodeId) { bool bRetval(false); if(hasDiagramData()) { bRetval = mpDiagramPtr->getData()->removeNode(rNodeId); // reset temporary buffered ModelData association lists & rebuild them // and the Diagram DataModel mpDiagramPtr->getData()->buildDiagramDataModel(true); // also reset temporary buffered layout data - that might // still refer to changed oox::Shape data mpDiagramPtr->getLayout()->getPresPointShapeMap().clear(); } return bRetval; } svx::diagram::DiagramDataStatePtr AdvancedDiagramHelper::extractDiagramDataState() const { if(!mpDiagramPtr) { return svx::diagram::DiagramDataStatePtr(); } return mpDiagramPtr->getData()->extractDiagramDataState(); } void AdvancedDiagramHelper::applyDiagramDataState(const svx::diagram::DiagramDataStatePtr& rState) { if(!mpDiagramPtr) { return; } mpDiagramPtr->getData()->applyDiagramDataState(rState); } void AdvancedDiagramHelper::doAnchor(SdrObjGroup& rTarget, ::oox::drawingml::Shape& rRootShape) { if(!mpDiagramPtr) { return; } mpDiagramPtr->syncDiagramFontHeights(); // 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. mpDiagramPtr->getData()->secureDataFromShapeToModelAfterDiagramImport(rRootShape); anchorToSdrObjGroup(rTarget); } std::shared_ptr< ::oox::drawingml::Theme > AdvancedDiagramHelper::getOrCreateThemePtr( rtl::Reference< oox::shape::ShapeFilterBase >& rxFilter) const { // (Re-)Use already existing Theme if existing/imported if possible. // If not, re-import Theme if data is available and thus possible if(hasDiagramData() && (ForceThemePtrRecreation() || !mpThemePtr)) { // get the originally imported dom::XDocument const uno::Reference< css::xml::dom::XDocument >& xThemeDocument(mpDiagramPtr->getData()->getThemeDocument()); if(xThemeDocument) { // reset local Theme ModelData *always* to get rid of former data that would // else be added additionally const_cast(this)->mpThemePtr = std::make_shared(); // import Theme ModelData rxFilter->importFragment( new ThemeFragmentHandler( *rxFilter, OUString(), *mpThemePtr ), uno::Reference< css::xml::sax::XFastSAXSerializable >( xThemeDocument, uno::UNO_QUERY_THROW)); } } return mpThemePtr; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */