LibreOffice Module oox (master)  1
diagramhelper.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "diagramhelper.hxx"
21 #include "diagram.hxx"
22 
25 #include <oox/ppt/pptimport.hxx>
27 #include <svx/svdmodel.hxx>
30 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
31 
32 using namespace ::com::sun::star;
33 
34 namespace oox::drawingml {
35 
37 {
38  return mpDiagramPtr && mpDiagramPtr->getData();
39 }
40 
42  const std::shared_ptr< Diagram >& rDiagramPtr,
43  const std::shared_ptr<::oox::drawingml::Theme>& rTheme,
44  css::awt::Size aImportSize)
45 : svx::diagram::IDiagramHelper()
46 , mpDiagramPtr(rDiagramPtr)
47 , mpThemePtr(rTheme)
48 , maImportSize(aImportSize)
49 {
50 }
51 
53 {
54 }
55 
57 {
58  if(!mpDiagramPtr)
59  {
60  return;
61  }
62 
63  // Rescue/remember geometric transformation of existing Diagram
64  basegfx::B2DHomMatrix aTransformation;
65  basegfx::B2DPolyPolygon aPolyPolygon;
66  rTarget.TRGetBaseGeometry(aTransformation, aPolyPolygon);
67 
68  // create temporary oox::Shape as target. No longer needed is to keep/remember
69  // the original oox::Shape to do that. Use original Size and Pos from initial import
70  // to get the same layout(s)
71  oox::drawingml::ShapePtr pShapePtr = std::make_shared<Shape>( "com.sun.star.drawing.GroupShape" );
72  pShapePtr->setDiagramType();
73  pShapePtr->setSize(maImportSize);
74 
75  // Re-create the oox::Shapes for the diagram content
76  mpDiagramPtr->addTo(pShapePtr);
77 
78  // Delete all existing shapes in that group to prepare re-creation
80 
81  // For re-creation we need to use ::addShape functionality from the
82  // oox import filter since currently Shape import is very tightly
83  // coupled to Shape creation. It converts a oox::Shape representation
84  // combined with an oox::Theme to incarnated XShapes representing the
85  // Diagram.
86  // To use that functionality, we have to create a temporary filter
87  // (based on ShapeFilterBase). Problems are that this needs to know
88  // the oox:Theme and a ComponentModel from TargetDocument.
89  // The DiagramHelper holds/delivers the oox::Theme to use, so
90  // it does not need to be re-imported from oox repeatedly.
91  // The ComponentModel can be derived from the existing XShape/GroupShape
92  // when knowing where to get it from, making it independent from app.
93  //
94  // NOTE: Using another (buffered) oox::Theme would allow to re-create
95  // using another theming in the future.
96  // NOTE: The incarnation of import filter (ShapeFilterBase) is only
97  // used for XShape creation, no xml snippets/data gets imported
98  // here. XShape creation may be isolated in the future.
99  SdrModel& rModel(rTarget.getSdrModelFromSdrObject());
100  uno::Reference< uno::XInterface > const & rUnoModel(rModel.getUnoModel());
101  css::uno::Reference<css::uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
103 
104  // set oox::Theme at Filter. All LineStyle/FillStyle/Colors/Attributes
105  // will be taken from there
106  if(UseDiagramThemeData())
107  xFilter->setCurrentTheme(getOrCreateThemePtr(xFilter));
108 
109  css::uno::Reference< css::lang::XComponent > aComponentModel( rUnoModel, uno::UNO_QUERY );
110  xFilter->setTargetDocument(aComponentModel);
111 
112  // set DiagramFontHeights
113  xFilter->setDiagramFontHeights(&mpDiagramPtr->getDiagramFontHeights());
114 
115  // Prepare the target for the to-be-created XShapes
116  uno::Reference<drawing::XShapes> xShapes(rTarget.getUnoShape(), uno::UNO_QUERY_THROW);
117 
118  for (auto const& child : pShapePtr->getChildren())
119  {
120  // Create all sub-shapes. This will recursively create needed geometry using
121  // filter-internal ::createShapes
122  child->addShape(
123  *xFilter,
124  xFilter->getCurrentTheme(),
125  xShapes,
126  aTransformation,
127  pShapePtr->getFillProperties());
128  }
129 
130  // sync FontHeights
131  mpDiagramPtr->syncDiagramFontHeights();
132 
133  // re-apply secured data from ModelData
134  if(UseDiagramModelData())
135  mpDiagramPtr->getData()->restoreDataFromShapeToModelAfterDiagramImport(*pShapePtr);
136 
137  // Re-apply remembered geometry
138  rTarget.TRSetBaseGeometry(aTransformation, aPolyPolygon);
139 }
140 
142 {
143  if(hasDiagramData())
144  {
145  return mpDiagramPtr->getData()->getString();
146  }
147 
148  return OUString();
149 }
150 
151 std::vector<std::pair<OUString, OUString>> AdvancedDiagramHelper::getChildren(const OUString& rParentId) const
152 {
153  if(hasDiagramData())
154  {
155  return mpDiagramPtr->getData()->getChildren(rParentId);
156  }
157 
158  return std::vector<std::pair<OUString, OUString>>();
159 }
160 
161 OUString AdvancedDiagramHelper::addNode(const OUString& rText)
162 {
163  OUString aRetval;
164 
165  if(hasDiagramData())
166  {
167  aRetval = mpDiagramPtr->getData()->addNode(rText);
168 
169  // reset temporary buffered ModelData association lists & rebuild them
170  // and the Diagram DataModel
171  mpDiagramPtr->getData()->buildDiagramDataModel(true);
172 
173  // also reset temporary buffered layout data - that might
174  // still refer to changed oox::Shape data
175  mpDiagramPtr->getLayout()->getPresPointShapeMap().clear();
176  }
177 
178  return aRetval;
179 }
180 
181 bool AdvancedDiagramHelper::removeNode(const OUString& rNodeId)
182 {
183  bool bRetval(false);
184 
185  if(hasDiagramData())
186  {
187  bRetval = mpDiagramPtr->getData()->removeNode(rNodeId);
188 
189  // reset temporary buffered ModelData association lists & rebuild them
190  // and the Diagram DataModel
191  mpDiagramPtr->getData()->buildDiagramDataModel(true);
192 
193  // also reset temporary buffered layout data - that might
194  // still refer to changed oox::Shape data
195  mpDiagramPtr->getLayout()->getPresPointShapeMap().clear();
196  }
197 
198  return bRetval;
199 }
200 
202 {
203  if(!mpDiagramPtr)
204  {
206  }
207 
208  return mpDiagramPtr->getData()->extractDiagramDataState();
209 }
210 
212 {
213  if(!mpDiagramPtr)
214  {
215  return;
216  }
217 
218  mpDiagramPtr->getData()->applyDiagramDataState(rState);
219 }
220 
222 {
223  if(!mpDiagramPtr)
224  {
225  return;
226  }
227 
228  mpDiagramPtr->syncDiagramFontHeights();
229 
230  // After Diagram import, parts of the Diagram ModelData is at the
231  // oox::drawingml::Shape. Since these objects are temporary helpers,
232  // secure that data at the Diagram ModelData by copying.
233  mpDiagramPtr->getData()->secureDataFromShapeToModelAfterDiagramImport(rRootShape);
234 
235  anchorToSdrObjGroup(rTarget);
236 }
237 
238 std::shared_ptr< ::oox::drawingml::Theme > AdvancedDiagramHelper::getOrCreateThemePtr(
240 {
241  // (Re-)Use already existing Theme if existing/imported if possible.
242  // If not, re-import Theme if data is available and thus possible
244  {
245  // get the originally imported dom::XDocument
246  const uno::Reference< css::xml::dom::XDocument >& xThemeDocument(mpDiagramPtr->getData()->getThemeDocument());
247 
248  if(xThemeDocument)
249  {
250  // reset local Theme ModelData *always* to get rid of former data that would
251  // else be added additionally
252  const_cast<AdvancedDiagramHelper*>(this)->mpThemePtr = std::make_shared<oox::drawingml::Theme>();
253 
254  // import Theme ModelData
255  rxFilter->importFragment(
257  *rxFilter, OUString(), *mpThemePtr ),
258  uno::Reference< css::xml::sax::XFastSAXSerializable >(
259  xThemeDocument,
260  uno::UNO_QUERY_THROW));
261  }
262  }
263 
264  return mpThemePtr;
265 }
266 
267 }
268 
269 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::shared_ptr< ::oox::drawingml::Theme > getOrCreateThemePtr(rtl::Reference< oox::shape::ShapeFilterBase > &rxFilter) const
AdvancedDiagramHelper(const std::shared_ptr< Diagram > &rDiagramPtr, const std::shared_ptr<::oox::drawingml::Theme > &rTheme, css::awt::Size aImportSize)
virtual bool removeNode(const OUString &rNodeId) override
std::shared_ptr< DiagramDataState > DiagramDataStatePtr
bool UseDiagramThemeData() const
virtual std::vector< std::pair< OUString, OUString > > getChildren(const OUString &rParentId) const override
virtual css::uno::Reference< css::drawing::XShape > getUnoShape()
virtual std::shared_ptr< svx::diagram::DiagramDataState > extractDiagramDataState() const override
virtual OUString addNode(const OUString &rText) override
virtual void reLayout(SdrObjGroup &rTarget) override
virtual void TRSetBaseGeometry(const basegfx::B2DHomMatrix &rMatrix, const basegfx::B2DPolyPolygon &rPolyPolygon)
SdrModel & getSdrModelFromSdrObject() const
void doAnchor(SdrObjGroup &rTarget,::oox::drawingml::Shape &rRootShape)
bool ForceThemePtrRecreation() const
virtual SdrObjList * getChildrenOfSdrObject() const override
void anchorToSdrObjGroup(SdrObjGroup &rTarget)
const std::shared_ptr< Diagram > mpDiagramPtr
std::shared_ptr<::oox::drawingml::Theme > mpThemePtr
void ClearSdrObjList()
bool UseDiagramModelData() const
Reference< XComponentContext > getProcessComponentContext()
std::shared_ptr< Shape > ShapePtr
virtual bool TRGetBaseGeometry(basegfx::B2DHomMatrix &rMatrix, basegfx::B2DPolyPolygon &rPolyPolygon) const
virtual void applyDiagramDataState(const std::shared_ptr< svx::diagram::DiagramDataState > &rState) override
virtual OUString getString() const override