285 lines
9.8 KiB
C++
285 lines
9.8 KiB
C++
/* -*- 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 <basegfx/matrix/b2dhommatrix.hxx>
|
|
#include <oox/shape/ShapeFilterBase.hxx>
|
|
#include <oox/ppt/pptimport.hxx>
|
|
#include <drawingml/fillproperties.hxx>
|
|
#include <svx/svdmodel.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <oox/drawingml/themefragmenthandler.hxx>
|
|
#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
|
|
#include <utility>
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
namespace oox::drawingml {
|
|
|
|
bool AdvancedDiagramHelper::hasDiagramData() const
|
|
{
|
|
return mpDiagramPtr && mpDiagramPtr->getData();
|
|
}
|
|
|
|
AdvancedDiagramHelper::AdvancedDiagramHelper(
|
|
std::shared_ptr< Diagram > xDiagramPtr,
|
|
std::shared_ptr<::oox::drawingml::Theme> xTheme,
|
|
css::awt::Size aImportSize,
|
|
bool bSelfCreated)
|
|
: svx::diagram::IDiagramHelper(bSelfCreated)
|
|
, mpDiagramPtr(std::move(xDiagramPtr))
|
|
, mpThemePtr(std::move(xTheme))
|
|
, 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<Shape>( "com.sun.star.drawing.GroupShape" );
|
|
pShapePtr->setDiagramType();
|
|
pShapePtr->setSize(maImportSize);
|
|
|
|
// Re-create the oox::Shapes for the diagram content
|
|
mpDiagramPtr->addTo(pShapePtr, true);
|
|
|
|
// 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());
|
|
const css::uno::Reference<css::uno::XComponentContext>& xContext(comphelper::getProcessComponentContext());
|
|
rtl::Reference<oox::shape::ShapeFilterBase> xFilter(new oox::shape::ShapeFilterBase(xContext));
|
|
|
|
// set oox::Theme at Filter. All LineStyle/FillStyle/Colors/Attributes
|
|
// will be taken from there
|
|
// also need to use theme when geometry gets self-created the first time
|
|
if(UseDiagramThemeData() || !isSelfCreated())
|
|
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<drawing::XShapes> 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();
|
|
|
|
if (isSelfCreated())
|
|
{
|
|
// already secured at import, re-apply secured data from ModelData
|
|
if(UseDiagramModelData())
|
|
mpDiagramPtr->getData()->restoreDataFromShapeToModelAfterDiagramImport(*pShapePtr);
|
|
}
|
|
else
|
|
{
|
|
// secure data from ModelData for the 1st time for shapes except BackgroundShape
|
|
if(UseDiagramModelData())
|
|
mpDiagramPtr->getData()->secureDataFromShapeToModelAfterDiagramImport(*pShapePtr);
|
|
|
|
// note that shapes are now self-created
|
|
setSelfCreated();
|
|
}
|
|
|
|
// Re-apply remembered geometry
|
|
rTarget.TRSetBaseGeometry(aTransformation, aPolyPolygon);
|
|
}
|
|
|
|
OUString AdvancedDiagramHelper::getString() const
|
|
{
|
|
if(hasDiagramData())
|
|
{
|
|
return mpDiagramPtr->getData()->getString();
|
|
}
|
|
|
|
return OUString();
|
|
}
|
|
|
|
std::vector<std::pair<OUString, OUString>> AdvancedDiagramHelper::getChildren(const OUString& rParentId) const
|
|
{
|
|
if(hasDiagramData())
|
|
{
|
|
return mpDiagramPtr->getData()->getChildren(rParentId);
|
|
}
|
|
|
|
return std::vector<std::pair<OUString, OUString>>();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
const 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<AdvancedDiagramHelper*>(this)->mpThemePtr = std::make_shared<oox::drawingml::Theme>();
|
|
auto pTheme = std::make_shared<model::Theme>();
|
|
mpThemePtr->setTheme(pTheme);
|
|
|
|
// import Theme ModelData
|
|
rxFilter->importFragment(
|
|
new ThemeFragmentHandler(*rxFilter, OUString(), *mpThemePtr, *pTheme),
|
|
uno::Reference< css::xml::sax::XFastSAXSerializable >(
|
|
xThemeDocument,
|
|
uno::UNO_QUERY_THROW));
|
|
}
|
|
}
|
|
|
|
return mpThemePtr;
|
|
}
|
|
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|