LibreOffice Module oox (master) 1
datamodel.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 "datamodel.hxx"
21
22#include <rtl/ustrbuf.hxx>
23#include <sal/log.hxx>
27#include <drawingml/textrun.hxx>
29#include <com/sun/star/beans/XPropertyState.hpp>
30#include <com/sun/star/drawing/FillStyle.hpp>
31#include <com/sun/star/drawing/LineStyle.hpp>
32#include <editeng/unoprnms.hxx>
33
34#include <unordered_set>
35
36using namespace ::com::sun::star;
37
38namespace oox::drawingml {
39
40Shape* DiagramData::getOrCreateAssociatedShape(const svx::diagram::Point& rPoint, bool bCreateOnDemand) const
41{
42 if(maPointShapeMap.end() == maPointShapeMap.find(rPoint.msModelId))
43 {
44 const_cast<DiagramData*>(this)->maPointShapeMap[rPoint.msModelId] = ShapePtr();
45 }
46
47 const ShapePtr& rShapePtr = maPointShapeMap.find(rPoint.msModelId)->second;
48
49 if(!rShapePtr && bCreateOnDemand)
50 {
51 const_cast<ShapePtr&>(rShapePtr) = std::make_shared<Shape>();
52
53 // If we did create a new oox::drawingml::Shape, directly apply
54 // available data from the Diagram ModelData to it as preparation
56 }
57
58 return rShapePtr.get();
59}
60
62{
63 // If we did create a new oox::drawingml::Shape, directly apply
64 // available data from the Diagram ModelData to it as preparation
65
66 // This is e.g. the Text, but may get more (styles?)
67 if(!rPoint.msTextBody->msText.isEmpty())
68 {
69 TextBodyPtr aNewTextBody(std::make_shared<TextBody>());
70 rNewShape.setTextBody(aNewTextBody);
71 TextRunPtr pTextRun = std::make_shared<TextRun>();
72 pTextRun->getText() = rPoint.msTextBody->msText;
73 aNewTextBody->addParagraph().addRun(pTextRun);
74
75 if(!rPoint.msTextBody->maTextProps.empty())
76 {
77 oox::PropertyMap& rTargetMap(aNewTextBody->getTextProperties().maPropertyMap);
78
79 for (auto const& prop : rPoint.msTextBody->maTextProps)
80 {
81 const sal_Int32 nPropId(oox::PropertyMap::getPropertyId(prop.first));
82 if(nPropId > 0)
83 rTargetMap.setAnyProperty(nPropId, prop.second);
84 }
85 }
86 }
87}
88
89static void addProperty(const OUString& rName,
90 const css::uno::Reference< css::beans::XPropertySetInfo >& xInfo,
91 std::vector< std::pair< OUString, css::uno::Any >>& rTarget,
92 const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
93{
94 if(xInfo->hasPropertyByName(rName))
95 rTarget.push_back(std::pair(OUString(rName), xPropSet->getPropertyValue(rName)));
96}
97
99{
100 const std::vector< ShapePtr >& rChildren(rShape.getChildren());
101
102 if(!rChildren.empty())
103 {
104 // group shape
105 for (auto& child : rChildren)
106 {
108 }
109
110 // if group shape we are done. Do not secure properties for group shapes
111 return;
112 }
113
114 // we need a XShape
115 const css::uno::Reference< css::drawing::XShape > &rXShape(rShape.getXShape());
116 if(!rXShape)
117 return;
118
119 // we need a ModelID for association
120 if(rShape.getDiagramDataModelID().isEmpty())
121 return;
122
123 // define target to save to
124 svx::diagram::PointStyle* pTarget(nullptr);
125 const bool bIsBackgroundShape(rShape.getDiagramDataModelID() == msBackgroundShapeModelID);
126
127 if(bIsBackgroundShape)
128 {
129 // if BackgroundShape, create properties & set as target
131 maBackgroundShapeStyle = std::make_shared< svx::diagram::PointStyle >();
132 pTarget = maBackgroundShapeStyle.get();
133 }
134 else
135 {
136 // if Shape, seek association
137 for (auto & point : maPoints)
138 {
139 if(point.msModelId == rShape.getDiagramDataModelID())
140 {
141 // found - create properties & set as target
142 pTarget = point.msPointStylePtr.get();
143
144 // we are done, there is no 2nd shape with the same ModelID by definition
145 break;
146 }
147 }
148 }
149
150 // no target -> nothing to do
151 if(nullptr == pTarget)
152 return;
153
154#ifdef DBG_UTIL
155 // to easier decide which additional properties may/should be preserved,
156 // create a full list of set properties to browse/decide (in debugger)
157 const css::uno::Reference< css::beans::XPropertyState > xAllPropStates(rXShape, css::uno::UNO_QUERY);
158 const css::uno::Reference< css::beans::XPropertySet > xAllPropSet( rXShape, css::uno::UNO_QUERY );
159 const css::uno::Sequence< css::beans::Property > allSequence(xAllPropSet->getPropertySetInfo()->getProperties());
160 std::vector< std::pair< OUString, css::uno::Any >> allSetProps;
161 for (auto& rProp : allSequence)
162 {
163 try
164 {
165 if (xAllPropStates->getPropertyState(rProp.Name) == css::beans::PropertyState::PropertyState_DIRECT_VALUE)
166 {
167 css::uno::Any aValue(xAllPropSet->getPropertyValue(rProp.Name));
168 if(aValue.hasValue())
169 allSetProps.push_back(std::pair(rProp.Name, aValue));
170 }
171 }
172 catch (...)
173 {
174 }
175 }
176#endif
177
178 const css::uno::Reference< css::beans::XPropertySet > xPropSet( rXShape, css::uno::UNO_QUERY );
179 if(!xPropSet)
180 return;
181
182 const css::uno::Reference< css::lang::XServiceInfo > xServiceInfo( rXShape, css::uno::UNO_QUERY );
183 if(!xServiceInfo)
184 return;
185
186 const css::uno::Reference< css::beans::XPropertySetInfo > xInfo(xPropSet->getPropertySetInfo());
187 if (!xInfo.is())
188 return;
189
190 // Note: The Text may also be secured here, so it may also be possible to
191 // secure/store it at PointStyle instead of at TextBody, same maybe evaluated
192 // for the text attributes - where when securing here the attributes would be
193 // in our UNO API format already.
194 // if(xServiceInfo->supportsService("com.sun.star.drawing.Text"))
195 // {
196 // css::uno::Reference< css::text::XText > xText(rXShape, css::uno::UNO_QUERY);
197 // const OUString aText(xText->getString());
198 //
199 // if(!aText.isEmpty())
200 // {
201 // }
202 // }
203
204 // Add all kinds of properties that are needed to re-create the XShape.
205 // For now this is a minimal example-selection, it will need to be extended
206 // over time for all kind of cases/properties
207
208 // text properties
209 if(!bIsBackgroundShape
210 && xServiceInfo->supportsService("com.sun.star.drawing.TextProperties"))
211 {
212 addProperty(UNO_NAME_CHAR_COLOR, xInfo, pTarget->maProperties, xPropSet);
213 addProperty(UNO_NAME_CHAR_HEIGHT, xInfo, pTarget->maProperties, xPropSet);
214 addProperty(UNO_NAME_CHAR_SHADOWED, xInfo, pTarget->maProperties, xPropSet);
215 addProperty(UNO_NAME_CHAR_WEIGHT, xInfo, pTarget->maProperties, xPropSet);
216 }
217
218 // fill properties
219 if(xServiceInfo->supportsService("com.sun.star.drawing.FillProperties"))
220 {
221 css::drawing::FillStyle eFillStyle(css::drawing::FillStyle_NONE);
222 if (xInfo->hasPropertyByName(UNO_NAME_FILLSTYLE))
223 xPropSet->getPropertyValue(UNO_NAME_FILLSTYLE) >>= eFillStyle;
224
225 if(css::drawing::FillStyle_NONE != eFillStyle)
226 {
227 addProperty(UNO_NAME_FILLSTYLE, xInfo, pTarget->maProperties, xPropSet);
228
229 switch(eFillStyle)
230 {
231 case css::drawing::FillStyle_SOLID:
232 {
233 addProperty(UNO_NAME_FILLCOLOR, xInfo, pTarget->maProperties, xPropSet);
234 break;
235 }
236 default:
237 case css::drawing::FillStyle_NONE:
238 case css::drawing::FillStyle_GRADIENT:
239 case css::drawing::FillStyle_HATCH:
240 case css::drawing::FillStyle_BITMAP:
241 break;
242 }
243 }
244 }
245
246 // line properties
247 if(!bIsBackgroundShape
248 && xServiceInfo->supportsService("com.sun.star.drawing.LineProperties"))
249 {
250 css::drawing::LineStyle eLineStyle(css::drawing::LineStyle_NONE);
251 if (xInfo->hasPropertyByName(UNO_NAME_LINESTYLE))
252 xPropSet->getPropertyValue(UNO_NAME_LINESTYLE) >>= eLineStyle;
253
254 if(css::drawing::LineStyle_NONE != eLineStyle)
255 {
256 addProperty(UNO_NAME_LINESTYLE, xInfo, pTarget->maProperties, xPropSet);
257 addProperty(UNO_NAME_LINECOLOR, xInfo, pTarget->maProperties, xPropSet);
258 addProperty(UNO_NAME_LINEWIDTH, xInfo, pTarget->maProperties, xPropSet);
259
260 switch(eLineStyle)
261 {
262 case css::drawing::LineStyle_SOLID:
263 break;
264 default:
265 case css::drawing::LineStyle_NONE:
266 case css::drawing::LineStyle_DASH:
267 break;
268 }
269 }
270 }
271}
272
274{
275 const std::vector< ShapePtr >& rChildren(rRootShape.getChildren());
276
277 for (auto& child : rChildren)
278 {
280 }
281
282 // After Diagram import, parts of the Diagram ModelData is at the
283 // oox::drawingml::Shape. Since these objects are temporary helpers,
284 // secure that data at the Diagram ModelData by copying.
285
286 // This is currently mainly the Text, but may get more (styles?)
287 for (auto & point : maPoints)
288 {
289 Shape* pShapeCandidate(getOrCreateAssociatedShape(point));
290
291 if(nullptr != pShapeCandidate)
292 {
293 if(pShapeCandidate->getTextBody() && !pShapeCandidate->getTextBody()->isEmpty())
294 {
295 point.msTextBody->msText = pShapeCandidate->getTextBody()->toString();
296
297 const uno::Sequence< beans::PropertyValue > aTextProps(
298 pShapeCandidate->getTextBody()->getTextProperties().maPropertyMap.makePropertyValueSequence());
299
300 for (auto const& prop : aTextProps)
301 point.msTextBody->maTextProps.push_back(std::pair(prop.Name, prop.Value));
302 }
303
304 // At this place a mechanism to find missing data should be added:
305 // Create a Shape from so-far secured data & compare it with the
306 // imported one. Report differences to allow extending the mechanism
307 // more easily.
308#ifdef DBG_UTIL
309 // The original is pShapeCandidate, re-create potential new oox::drawingml::Shape
310 // as aNew to be able to compare these
311 ShapePtr aNew(std::make_shared<Shape>());
313
314 // Unfortunately oox::drawingml::Shape has no operator==. I tried to add
315 // one, but that is too expensive. I stopped at oox::drawingml::Color.
316 // To compare it is necessary to use the debugger, or for single aspects
317 // of the oox data it might be possible to call local dump() methods at
318 // both instances to compare them/their output
319
320 // bool bSame(aNew.get() == pShapeCandidate);
321#endif
322 }
323 }
324}
325
327{
328 const std::vector< ShapePtr >& rChildren(rShape.getChildren());
329
330 if(!rChildren.empty())
331 {
332 // group shape
333 for (auto& child : rChildren)
334 {
336 }
337
338 // if group shape we are done. Do not restore properties for group shapes
339 return;
340 }
341
342 // we need a XShape
343 const css::uno::Reference< css::drawing::XShape > &rXShape(rShape.getXShape());
344 if(!rXShape)
345 return;
346
347 // we need a ModelID for association
348 if(rShape.getDiagramDataModelID().isEmpty())
349 return;
350
351 // define source to save to
352 svx::diagram::PointStyle* pSource(nullptr);
353
355 {
356 // if BackgroundShape, set BackgroundShapeStyle as source
358 pSource = maBackgroundShapeStyle.get();
359 }
360 else
361 {
362 // if Shape, seek association
363 for (auto & point : maPoints)
364 {
365 if(point.msModelId == rShape.getDiagramDataModelID())
366 {
367 // found - create properties & set as source
368 pSource = point.msPointStylePtr.get();
369
370 // we are done, there is no 2nd shape with the same ModelID by definition
371 break;
372 }
373 }
374 }
375
376 // no source -> nothing to do
377 if(nullptr == pSource)
378 return;
379
380 // get target PropertySet of new XShape
381 css::uno::Reference<css::beans::XPropertySet> xPropSet(rXShape, css::uno::UNO_QUERY);
382 if(!xPropSet)
383 return;
384
385 // apply properties
386 for (auto const& prop : pSource->maProperties)
387 {
388 xPropSet->setPropertyValue(prop.first, prop.second);
389 }
390}
391
393{
394 const std::vector< ShapePtr >& rChildren(rRootShape.getChildren());
395
396 for (auto& child : rChildren)
397 {
399 }
400}
401
403: svx::diagram::DiagramData()
404, mpBackgroundShapeFillProperties( std::make_shared<FillProperties>() )
405{
406}
407
409{
410}
411
412static void Connection_dump(const svx::diagram::Connection& rConnection)
413{
414 SAL_INFO(
415 "oox.drawingml",
416 "cnx modelId " << rConnection.msModelId << ", srcId " << rConnection.msSourceId << ", dstId "
417 << rConnection.msDestId << ", parTransId " << rConnection.msParTransId << ", presId "
418 << rConnection.msPresId << ", sibTransId " << rConnection.msSibTransId << ", srcOrd "
419 << rConnection.mnSourceOrder << ", dstOrd " << rConnection.mnDestOrder);
420}
421
422static void Point_dump(const svx::diagram::Point& rPoint, const Shape* pShape)
423{
424 SAL_INFO(
425 "oox.drawingml",
426 "pt text " << pShape << ", cnxId " << rPoint.msCnxId << ", modelId "
427 << rPoint.msModelId << ", type " << rPoint.mnXMLType);
428}
429
431{
432 SAL_INFO("oox.drawingml", "Dgm: DiagramData # of cnx: " << maConnections.size() );
433 for (const auto& rConnection : maConnections)
434 Connection_dump(rConnection);
435
436 SAL_INFO("oox.drawingml", "Dgm: DiagramData # of pt: " << maPoints.size() );
437 for (const auto& rPoint : maPoints)
438 Point_dump(rPoint, getOrCreateAssociatedShape(rPoint));
439}
440
441void DiagramData::buildDiagramDataModel(bool bClearOoxShapes)
442{
443 if(bClearOoxShapes)
444 {
445 // Delete/remove all existing oox::drawingml::Shape
446 maPointShapeMap.clear();
447 }
448
449 // call parent
451
452 if(bClearOoxShapes)
453 {
454 // re-create all existing oox::drawingml::Shape
455 svx::diagram::Points& rPoints = getPoints();
456
457 for (auto & point : rPoints)
458 {
459 // Create/get shape. Re-create here, that may also set needed
460 // and available data from the Diagram ModelData at the Shape
462 }
463 }
464}
465
466}
467
468/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
A helper that maps property identifiers to property values.
Definition: propertymap.hxx:52
bool setAnyProperty(sal_Int32 nPropId, const css::uno::Any &rValue)
Sets the specified property to the passed value.
static sal_Int32 getPropertyId(std::u16string_view sPropName)
Returns the property identifier of the passed name.
virtual void dump() const
Definition: datamodel.cxx:430
void secureDataFromShapeToModelAfterDiagramImport(::oox::drawingml::Shape &rRootShape)
Definition: datamodel.cxx:273
void restoreDataFromShapeToModelAfterDiagramImport(::oox::drawingml::Shape &rRootShape)
Definition: datamodel.cxx:392
static void restoreDataFromModelToShapeAfterReCreation(const svx::diagram::Point &rPoint, Shape &rNewShape)
Definition: datamodel.cxx:61
void restoreStyleDataFromShapeToModel(::oox::drawingml::Shape &rShape)
Definition: datamodel.cxx:326
PointShapeMap maPointShapeMap
Definition: datamodel.hxx:70
Shape * getOrCreateAssociatedShape(const svx::diagram::Point &rPoint, bool bCreateOnDemand=false) const
Definition: datamodel.cxx:40
virtual void buildDiagramDataModel(bool bClearOoxShapes)
Definition: datamodel.cxx:441
void secureStyleDataFromShapeToModel(::oox::drawingml::Shape &rShape)
Definition: datamodel.cxx:98
std::vector< ShapePtr > & getChildren()
Definition: shape.hxx:168
const OUString & getDiagramDataModelID() const
Definition: shape.hxx:123
const css::uno::Reference< css::drawing::XShape > & getXShape() const
Definition: shape.hxx:215
const TextBodyPtr & getTextBody() const
Definition: shape.hxx:195
void setTextBody(const TextBodyPtr &pTextBody)
Definition: shape.cxx:2110
PointStylePtr maBackgroundShapeStyle
virtual void buildDiagramDataModel(bool bClearOoxShapes)
FilterGroup & rTarget
#define SAL_INFO(area, stream)
def point()
std::shared_ptr< T > make_shared(Args &&... args)
static void Connection_dump(const svx::diagram::Connection &rConnection)
Definition: datamodel.cxx:412
std::shared_ptr< Shape > ShapePtr
std::shared_ptr< TextRun > TextRunPtr
Definition: textrun.hxx:65
static void addProperty(const OUString &rName, const css::uno::Reference< css::beans::XPropertySetInfo > &xInfo, std::vector< std::pair< OUString, css::uno::Any > > &rTarget, const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
Definition: datamodel.cxx:89
static void Point_dump(const svx::diagram::Point &rPoint, const Shape *pShape)
Definition: datamodel.cxx:422
std::shared_ptr< TextBody > TextBodyPtr
std::vector< Point > Points
std::vector< std::pair< OUString, css::uno::Any > > maProperties
TypeConstant mnXMLType
TextBodyPtr msTextBody
constexpr OUStringLiteral UNO_NAME_FILLCOLOR
constexpr OUStringLiteral UNO_NAME_CHAR_SHADOWED
constexpr OUStringLiteral UNO_NAME_LINESTYLE
constexpr OUStringLiteral UNO_NAME_LINEWIDTH
constexpr OUStringLiteral UNO_NAME_FILLSTYLE
constexpr OUStringLiteral UNO_NAME_CHAR_COLOR
constexpr OUStringLiteral UNO_NAME_CHAR_HEIGHT
constexpr OUStringLiteral UNO_NAME_LINECOLOR
constexpr OUStringLiteral UNO_NAME_CHAR_WEIGHT