/src/libreoffice/oox/source/drawingml/diagram/diagramhelper.cxx
Line | Count | Source |
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 | | |
23 | | #include <basegfx/matrix/b2dhommatrix.hxx> |
24 | | #include <oox/shape/ShapeFilterBase.hxx> |
25 | | #include <oox/ppt/pptimport.hxx> |
26 | | #include <drawingml/fillproperties.hxx> |
27 | | #include <svx/svdmodel.hxx> |
28 | | #include <comphelper/processfactory.hxx> |
29 | | #include <oox/drawingml/themefragmenthandler.hxx> |
30 | | #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp> |
31 | | #include <utility> |
32 | | |
33 | | using namespace ::com::sun::star; |
34 | | |
35 | | namespace oox::drawingml { |
36 | | |
37 | | bool AdvancedDiagramHelper::hasDiagramData() const |
38 | 0 | { |
39 | 0 | return mpDiagramPtr && mpDiagramPtr->getData(); |
40 | 0 | } |
41 | | |
42 | | AdvancedDiagramHelper::AdvancedDiagramHelper( |
43 | | std::shared_ptr< Diagram > xDiagramPtr, |
44 | | std::shared_ptr<::oox::drawingml::Theme> xTheme, |
45 | | css::awt::Size aImportSize, |
46 | | bool bSelfCreated) |
47 | 135 | : svx::diagram::IDiagramHelper(bSelfCreated) |
48 | 135 | , mpDiagramPtr(std::move(xDiagramPtr)) |
49 | 135 | , mpThemePtr(std::move(xTheme)) |
50 | 135 | , maImportSize(aImportSize) |
51 | 135 | { |
52 | 135 | } |
53 | | |
54 | | AdvancedDiagramHelper::~AdvancedDiagramHelper() |
55 | 135 | { |
56 | 135 | } |
57 | | |
58 | | void AdvancedDiagramHelper::reLayout(SdrObjGroup& rTarget) |
59 | 0 | { |
60 | 0 | if(!mpDiagramPtr) |
61 | 0 | { |
62 | 0 | return; |
63 | 0 | } |
64 | | |
65 | | // Rescue/remember geometric transformation of existing Diagram |
66 | 0 | basegfx::B2DHomMatrix aTransformation; |
67 | 0 | basegfx::B2DPolyPolygon aPolyPolygon; |
68 | 0 | rTarget.TRGetBaseGeometry(aTransformation, aPolyPolygon); |
69 | | |
70 | | // create temporary oox::Shape as target. No longer needed is to keep/remember |
71 | | // the original oox::Shape to do that. Use original Size and Pos from initial import |
72 | | // to get the same layout(s) |
73 | 0 | oox::drawingml::ShapePtr pShapePtr = std::make_shared<Shape>( "com.sun.star.drawing.GroupShape" ); |
74 | 0 | pShapePtr->setDiagramType(); |
75 | 0 | pShapePtr->setSize(maImportSize); |
76 | | |
77 | | // Re-create the oox::Shapes for the diagram content |
78 | 0 | mpDiagramPtr->addTo(pShapePtr, true); |
79 | | |
80 | | // Delete all existing shapes in that group to prepare re-creation |
81 | 0 | rTarget.getChildrenOfSdrObject()->ClearSdrObjList(); |
82 | | |
83 | | // For re-creation we need to use ::addShape functionality from the |
84 | | // oox import filter since currently Shape import is very tightly |
85 | | // coupled to Shape creation. It converts a oox::Shape representation |
86 | | // combined with an oox::Theme to incarnated XShapes representing the |
87 | | // Diagram. |
88 | | // To use that functionality, we have to create a temporary filter |
89 | | // (based on ShapeFilterBase). Problems are that this needs to know |
90 | | // the oox:Theme and a ComponentModel from TargetDocument. |
91 | | // The DiagramHelper holds/delivers the oox::Theme to use, so |
92 | | // it does not need to be re-imported from oox repeatedly. |
93 | | // The ComponentModel can be derived from the existing XShape/GroupShape |
94 | | // when knowing where to get it from, making it independent from app. |
95 | | // |
96 | | // NOTE: Using another (buffered) oox::Theme would allow to re-create |
97 | | // using another theming in the future. |
98 | | // NOTE: The incarnation of import filter (ShapeFilterBase) is only |
99 | | // used for XShape creation, no xml snippets/data gets imported |
100 | | // here. XShape creation may be isolated in the future. |
101 | 0 | SdrModel& rModel(rTarget.getSdrModelFromSdrObject()); |
102 | 0 | uno::Reference< uno::XInterface > const & rUnoModel(rModel.getUnoModel()); |
103 | 0 | const css::uno::Reference<css::uno::XComponentContext>& xContext(comphelper::getProcessComponentContext()); |
104 | 0 | rtl::Reference<oox::shape::ShapeFilterBase> xFilter(new oox::shape::ShapeFilterBase(xContext)); |
105 | | |
106 | | // set oox::Theme at Filter. All LineStyle/FillStyle/Colors/Attributes |
107 | | // will be taken from there |
108 | | // also need to use theme when geometry gets self-created the first time |
109 | 0 | if(UseDiagramThemeData() || !isSelfCreated()) |
110 | 0 | xFilter->setCurrentTheme(getOrCreateThemePtr(xFilter)); |
111 | |
|
112 | 0 | css::uno::Reference< css::lang::XComponent > aComponentModel( rUnoModel, uno::UNO_QUERY ); |
113 | 0 | xFilter->setTargetDocument(aComponentModel); |
114 | | |
115 | | // set DiagramFontHeights |
116 | 0 | xFilter->setDiagramFontHeights(&mpDiagramPtr->getDiagramFontHeights()); |
117 | | |
118 | | // Prepare the target for the to-be-created XShapes |
119 | 0 | uno::Reference<drawing::XShapes> xShapes(rTarget.getUnoShape(), uno::UNO_QUERY_THROW); |
120 | |
|
121 | 0 | for (auto const& child : pShapePtr->getChildren()) |
122 | 0 | { |
123 | | // Create all sub-shapes. This will recursively create needed geometry using |
124 | | // filter-internal ::createShapes |
125 | 0 | child->addShape( |
126 | 0 | *xFilter, |
127 | 0 | xFilter->getCurrentTheme(), |
128 | 0 | xShapes, |
129 | 0 | aTransformation, |
130 | 0 | pShapePtr->getFillProperties()); |
131 | 0 | } |
132 | | |
133 | | // sync FontHeights |
134 | 0 | mpDiagramPtr->syncDiagramFontHeights(); |
135 | |
|
136 | 0 | if (isSelfCreated()) |
137 | 0 | { |
138 | | // already secured at import, re-apply secured data from ModelData |
139 | 0 | if(UseDiagramModelData()) |
140 | 0 | mpDiagramPtr->getData()->restoreDataFromShapeToModelAfterDiagramImport(*pShapePtr); |
141 | 0 | } |
142 | 0 | else |
143 | 0 | { |
144 | | // secure data from ModelData for the 1st time for shapes except BackgroundShape |
145 | 0 | if(UseDiagramModelData()) |
146 | 0 | mpDiagramPtr->getData()->secureDataFromShapeToModelAfterDiagramImport(*pShapePtr); |
147 | | |
148 | | // note that shapes are now self-created |
149 | 0 | setSelfCreated(); |
150 | 0 | } |
151 | | |
152 | | // Re-apply remembered geometry |
153 | 0 | rTarget.TRSetBaseGeometry(aTransformation, aPolyPolygon); |
154 | 0 | } |
155 | | |
156 | | OUString AdvancedDiagramHelper::getString() const |
157 | 0 | { |
158 | 0 | if(hasDiagramData()) |
159 | 0 | { |
160 | 0 | return mpDiagramPtr->getData()->getString(); |
161 | 0 | } |
162 | | |
163 | 0 | return OUString(); |
164 | 0 | } |
165 | | |
166 | | std::vector<std::pair<OUString, OUString>> AdvancedDiagramHelper::getChildren(const OUString& rParentId) const |
167 | 0 | { |
168 | 0 | if(hasDiagramData()) |
169 | 0 | { |
170 | 0 | return mpDiagramPtr->getData()->getChildren(rParentId); |
171 | 0 | } |
172 | | |
173 | 0 | return std::vector<std::pair<OUString, OUString>>(); |
174 | 0 | } |
175 | | |
176 | | OUString AdvancedDiagramHelper::addNode(const OUString& rText) |
177 | 0 | { |
178 | 0 | OUString aRetval; |
179 | |
|
180 | 0 | if(hasDiagramData()) |
181 | 0 | { |
182 | 0 | aRetval = mpDiagramPtr->getData()->addNode(rText); |
183 | | |
184 | | // reset temporary buffered ModelData association lists & rebuild them |
185 | | // and the Diagram DataModel |
186 | 0 | mpDiagramPtr->getData()->buildDiagramDataModel(true); |
187 | | |
188 | | // also reset temporary buffered layout data - that might |
189 | | // still refer to changed oox::Shape data |
190 | 0 | mpDiagramPtr->getLayout()->getPresPointShapeMap().clear(); |
191 | 0 | } |
192 | |
|
193 | 0 | return aRetval; |
194 | 0 | } |
195 | | |
196 | | bool AdvancedDiagramHelper::removeNode(const OUString& rNodeId) |
197 | 0 | { |
198 | 0 | bool bRetval(false); |
199 | |
|
200 | 0 | if(hasDiagramData()) |
201 | 0 | { |
202 | 0 | bRetval = mpDiagramPtr->getData()->removeNode(rNodeId); |
203 | | |
204 | | // reset temporary buffered ModelData association lists & rebuild them |
205 | | // and the Diagram DataModel |
206 | 0 | mpDiagramPtr->getData()->buildDiagramDataModel(true); |
207 | | |
208 | | // also reset temporary buffered layout data - that might |
209 | | // still refer to changed oox::Shape data |
210 | 0 | mpDiagramPtr->getLayout()->getPresPointShapeMap().clear(); |
211 | 0 | } |
212 | |
|
213 | 0 | return bRetval; |
214 | 0 | } |
215 | | |
216 | | svx::diagram::DiagramDataStatePtr AdvancedDiagramHelper::extractDiagramDataState() const |
217 | 0 | { |
218 | 0 | if(!mpDiagramPtr) |
219 | 0 | { |
220 | 0 | return svx::diagram::DiagramDataStatePtr(); |
221 | 0 | } |
222 | | |
223 | 0 | return mpDiagramPtr->getData()->extractDiagramDataState(); |
224 | 0 | } |
225 | | |
226 | | void AdvancedDiagramHelper::applyDiagramDataState(const svx::diagram::DiagramDataStatePtr& rState) |
227 | 0 | { |
228 | 0 | if(!mpDiagramPtr) |
229 | 0 | { |
230 | 0 | return; |
231 | 0 | } |
232 | | |
233 | 0 | mpDiagramPtr->getData()->applyDiagramDataState(rState); |
234 | 0 | } |
235 | | |
236 | | void AdvancedDiagramHelper::doAnchor(SdrObjGroup& rTarget, ::oox::drawingml::Shape& rRootShape) |
237 | 135 | { |
238 | 135 | if(!mpDiagramPtr) |
239 | 0 | { |
240 | 0 | return; |
241 | 0 | } |
242 | | |
243 | 135 | mpDiagramPtr->syncDiagramFontHeights(); |
244 | | |
245 | | // After Diagram import, parts of the Diagram ModelData is at the |
246 | | // oox::drawingml::Shape. Since these objects are temporary helpers, |
247 | | // secure that data at the Diagram ModelData by copying. |
248 | 135 | mpDiagramPtr->getData()->secureDataFromShapeToModelAfterDiagramImport(rRootShape); |
249 | | |
250 | 135 | anchorToSdrObjGroup(rTarget); |
251 | 135 | } |
252 | | |
253 | | const std::shared_ptr< ::oox::drawingml::Theme >& AdvancedDiagramHelper::getOrCreateThemePtr( |
254 | | const rtl::Reference< oox::shape::ShapeFilterBase >& rxFilter) const |
255 | 0 | { |
256 | | // (Re-)Use already existing Theme if existing/imported if possible. |
257 | | // If not, re-import Theme if data is available and thus possible |
258 | 0 | if(hasDiagramData() && (ForceThemePtrRecreation() || !mpThemePtr)) |
259 | 0 | { |
260 | | // get the originally imported dom::XDocument |
261 | 0 | const uno::Reference< css::xml::dom::XDocument >& xThemeDocument(mpDiagramPtr->getData()->getThemeDocument()); |
262 | |
|
263 | 0 | if(xThemeDocument) |
264 | 0 | { |
265 | | // reset local Theme ModelData *always* to get rid of former data that would |
266 | | // else be added additionally |
267 | 0 | const_cast<AdvancedDiagramHelper*>(this)->mpThemePtr = std::make_shared<oox::drawingml::Theme>(); |
268 | 0 | auto pTheme = std::make_shared<model::Theme>(); |
269 | 0 | mpThemePtr->setTheme(pTheme); |
270 | | |
271 | | // import Theme ModelData |
272 | 0 | rxFilter->importFragment( |
273 | 0 | new ThemeFragmentHandler(*rxFilter, OUString(), *mpThemePtr, *pTheme), |
274 | 0 | uno::Reference< css::xml::sax::XFastSAXSerializable >( |
275 | 0 | xThemeDocument, |
276 | 0 | uno::UNO_QUERY_THROW)); |
277 | 0 | } |
278 | 0 | } |
279 | |
|
280 | 0 | return mpThemePtr; |
281 | 0 | } |
282 | | |
283 | | } |
284 | | |
285 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |