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/layoutatomvisitors.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 "layoutatomvisitors.hxx"
21
22
#include <drawingml/customshapeproperties.hxx>
23
24
#include <sal/log.hxx>
25
26
using namespace ::com::sun::star;
27
using namespace ::com::sun::star::xml::sax;
28
29
namespace oox::drawingml
30
{
31
void ShapeCreationVisitor::visit(ConstraintAtom& /*rAtom*/)
32
3.36k
{
33
    // stop processing
34
3.36k
}
35
36
void ShapeCreationVisitor::visit(RuleAtom& /*rAtom*/)
37
482
{
38
    // stop processing
39
482
}
40
41
void ShapeCreationVisitor::visit(AlgAtom& rAtom)
42
902
{
43
902
    if (meLookFor == ALGORITHM)
44
451
    {
45
451
        mpParentShape->setAspectRatio(rAtom.getAspectRatio());
46
451
        mpParentShape->setVerticalShapesCount(rAtom.getVerticalShapesCount(mpParentShape));
47
451
    }
48
902
}
49
50
void ShapeCreationVisitor::visit(LayoutNode& rAtom)
51
900
{
52
900
    if (meLookFor != LAYOUT_NODE)
53
428
        return;
54
55
    // stop processing if it's not a child of previous LayoutNode
56
57
472
    const DiagramData::PointsNameMap::const_iterator aDataNode
58
472
        = mrDgm.getData()->getPointsPresNameMap().find(rAtom.getName());
59
472
    if (aDataNode == mrDgm.getData()->getPointsPresNameMap().end()
60
463
        || mnCurrIdx >= static_cast<sal_Int32>(aDataNode->second.size()))
61
9
        return;
62
63
463
    const svx::diagram::Point* pNewNode = aDataNode->second.at(mnCurrIdx);
64
463
    if (!mpCurrentNode || !pNewNode)
65
0
        return;
66
67
463
    bool bIsChild = false;
68
463
    for (const auto& aConnection : mrDgm.getData()->getConnections())
69
13.9k
        if (aConnection.msSourceId == mpCurrentNode->msModelId
70
3.07k
            && aConnection.msDestId == pNewNode->msModelId)
71
451
            bIsChild = true;
72
73
463
    if (!bIsChild)
74
12
        return;
75
76
451
    ShapePtr xCurrParent(mpParentShape);
77
78
451
    if (rAtom.getExistingShape())
79
44
    {
80
        // reuse existing shape
81
44
        ShapePtr pShape = rAtom.getExistingShape();
82
44
        if (rAtom.setupShape(pShape, pNewNode, mnCurrIdx))
83
44
        {
84
44
            pShape->setInternalName(rAtom.getName());
85
44
            rAtom.addNodeShape(pShape);
86
44
            mrDgm.getLayout()->getPresPointShapeMap()[pNewNode] = std::move(pShape);
87
44
        }
88
44
    }
89
407
    else
90
407
    {
91
407
        ShapeTemplateVisitor aTemplateVisitor(mrDgm, pNewNode);
92
407
        aTemplateVisitor.defaultVisit(rAtom);
93
407
        ShapePtr pShape = aTemplateVisitor.getShapeCopy();
94
95
407
        if (pShape)
96
407
        {
97
407
            SAL_INFO("oox.drawingml",
98
407
                     "processing shape type "
99
407
                         << (pShape->getCustomShapeProperties()->getShapePresetType()));
100
101
407
            if (rAtom.setupShape(pShape, pNewNode, mnCurrIdx))
102
407
            {
103
407
                pShape->setInternalName(rAtom.getName());
104
407
                xCurrParent->addChild(pShape);
105
407
                xCurrParent = pShape;
106
407
                rAtom.addNodeShape(pShape);
107
407
                mrDgm.getLayout()->getPresPointShapeMap()[pNewNode] = std::move(pShape);
108
407
            }
109
407
        }
110
0
        else
111
0
        {
112
0
            SAL_WARN("oox.drawingml",
113
0
                     "ShapeCreationVisitor::visit: no shape set while processing layoutnode named "
114
0
                         << rAtom.getName());
115
0
        }
116
407
    }
117
118
451
    const svx::diagram::Point* pPreviousNode = mpCurrentNode;
119
451
    mpCurrentNode = pNewNode;
120
121
    // set new parent for children
122
451
    ShapePtr xPreviousParent(mpParentShape);
123
451
    mpParentShape = std::move(xCurrParent);
124
125
    // process children
126
451
    meLookFor = LAYOUT_NODE;
127
451
    defaultVisit(rAtom);
128
129
451
    meLookFor = ALGORITHM;
130
451
    defaultVisit(rAtom);
131
451
    meLookFor = LAYOUT_NODE;
132
133
    // restore parent
134
451
    mpParentShape = std::move(xPreviousParent);
135
451
    mpCurrentNode = pPreviousNode;
136
451
}
137
138
void ShapeCreationVisitor::visit(ShapeAtom& /*rAtom*/)
139
902
{
140
    // stop processing
141
902
}
142
143
void ShapeTemplateVisitor::visit(ConstraintAtom& /*rAtom*/)
144
1.27k
{
145
    // stop processing
146
1.27k
}
147
148
void ShapeTemplateVisitor::visit(RuleAtom& /*rAtom*/)
149
241
{
150
    // stop processing
151
241
}
152
153
void ShapeTemplateVisitor::visit(AlgAtom& /*rAtom*/)
154
407
{
155
    // stop processing
156
407
}
157
158
void ShapeTemplateVisitor::visit(ForEachAtom& /*rAtom*/)
159
18
{
160
    // stop processing
161
18
}
162
163
void ShapeTemplateVisitor::visit(LayoutNode& /*rAtom*/)
164
98
{
165
    // stop processing - only traverse Condition/Choose atoms
166
98
}
167
168
void ShapeTemplateVisitor::visit(ShapeAtom& rAtom)
169
407
{
170
407
    if (mpShape)
171
0
    {
172
0
        SAL_WARN("oox.drawingml", "multiple shapes encountered inside LayoutNode");
173
0
        return;
174
0
    }
175
176
407
    const ShapePtr& pCurrShape(rAtom.getShapeTemplate());
177
178
    // TODO(F3): cloned shape shares all properties by reference,
179
    // don't change them!
180
407
    mpShape = std::make_shared<Shape>(pCurrShape);
181
    // Fill properties have to be changed as sometimes only the presentation node contains the blip
182
    // fill, unshare those.
183
407
    mpShape->cloneFillProperties();
184
185
    // add/set ModelID from current node to allow later association
186
407
    if (mpCurrentNode)
187
407
        mpShape->setDiagramDataModelID(mpCurrentNode->msModelId);
188
407
}
189
190
void ShapeLayoutingVisitor::visit(ConstraintAtom& rAtom)
191
6.72k
{
192
6.72k
    if (meLookFor == CONSTRAINT)
193
1.68k
        rAtom.parseConstraint(maConstraints, /*bRequireForName=*/true);
194
6.72k
}
195
196
void ShapeLayoutingVisitor::visit(RuleAtom& rAtom)
197
964
{
198
964
    if (meLookFor == RULE)
199
241
        rAtom.parseRule(maRules);
200
964
}
201
202
void ShapeLayoutingVisitor::visit(AlgAtom& rAtom)
203
1.80k
{
204
1.80k
    if (meLookFor == ALGORITHM)
205
451
    {
206
451
        const PresPointShapeMap aMap
207
451
            = rAtom.getLayoutNode().getDiagram().getLayout()->getPresPointShapeMap();
208
451
        auto pShape = aMap.find(mpCurrentNode);
209
451
        if (pShape != aMap.end())
210
451
            rAtom.layoutShape(pShape->second, maConstraints, maRules);
211
451
    }
212
1.80k
}
213
214
void ShapeLayoutingVisitor::visit(LayoutNode& rAtom)
215
1.75k
{
216
1.75k
    if (meLookFor != LAYOUT_NODE)
217
1.28k
        return;
218
219
    // stop processing if it's not a child of previous LayoutNode
220
221
472
    const DiagramData::PointsNameMap::const_iterator aDataNode
222
472
        = mrDgm.getData()->getPointsPresNameMap().find(rAtom.getName());
223
472
    if (aDataNode == mrDgm.getData()->getPointsPresNameMap().end()
224
463
        || mnCurrIdx >= static_cast<sal_Int32>(aDataNode->second.size()))
225
9
        return;
226
227
463
    const svx::diagram::Point* pNewNode = aDataNode->second.at(mnCurrIdx);
228
463
    if (!mpCurrentNode || !pNewNode)
229
0
        return;
230
231
463
    bool bIsChild = false;
232
463
    for (const auto& aConnection : mrDgm.getData()->getConnections())
233
13.9k
        if (aConnection.msSourceId == mpCurrentNode->msModelId
234
3.07k
            && aConnection.msDestId == pNewNode->msModelId)
235
451
            bIsChild = true;
236
237
463
    if (!bIsChild)
238
12
        return;
239
240
451
    size_t nParentConstraintsNumber = maConstraints.size();
241
242
451
    const svx::diagram::Point* pPreviousNode = mpCurrentNode;
243
451
    mpCurrentNode = pNewNode;
244
245
    // process alg atoms first, nested layout nodes afterwards
246
451
    meLookFor = CONSTRAINT;
247
451
    defaultVisit(rAtom);
248
451
    meLookFor = RULE;
249
451
    defaultVisit(rAtom);
250
451
    meLookFor = ALGORITHM;
251
451
    defaultVisit(rAtom);
252
451
    meLookFor = LAYOUT_NODE;
253
451
    defaultVisit(rAtom);
254
255
451
    mpCurrentNode = pPreviousNode;
256
257
    // delete added constraints, keep parent constraints
258
451
    maConstraints.erase(maConstraints.begin() + nParentConstraintsNumber, maConstraints.end());
259
451
}
260
261
void ShapeLayoutingVisitor::visit(ShapeAtom& /*rAtom*/)
262
1.80k
{
263
    // stop processing
264
1.80k
}
265
}
266
267
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */