Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */