Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/oox/source/ppt/presentationfragmenthandler.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 <comphelper/anytostring.hxx>
21
#include <comphelper/propertyvalue.hxx>
22
#include <comphelper/sequence.hxx>
23
#include <comphelper/sequenceashashmap.hxx>
24
#include <o3tl/string_view.hxx>
25
#include <sal/log.hxx>
26
#include <tools/multisel.hxx>
27
#include <comphelper/diagnose_ex.hxx>
28
29
#include <frozen/bits/defines.h>
30
#include <frozen/bits/elsa_std.h>
31
#include <frozen/unordered_map.h>
32
33
#include <com/sun/star/container/XNamed.hpp>
34
#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
35
#include <com/sun/star/drawing/XDrawPages.hpp>
36
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
37
#include <com/sun/star/drawing/XMasterPageTarget.hpp>
38
#include <com/sun/star/frame/XModel.hpp>
39
#include <com/sun/star/io/XInputStream.hpp>
40
#include <com/sun/star/text/XTextField.hpp>
41
#include <com/sun/star/xml/dom/XDocument.hpp>
42
#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
43
#include <com/sun/star/presentation/XPresentationPage.hpp>
44
#include <com/sun/star/task/XStatusIndicator.hpp>
45
#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp>
46
#include <com/sun/star/container/XIndexContainer.hpp>
47
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
48
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
49
#include <com/sun/star/container/XNameContainer.hpp>
50
51
#include <oox/drawingml/theme.hxx>
52
#include <oox/drawingml/drawingmltypes.hxx>
53
#include <oox/drawingml/themefragmenthandler.hxx>
54
#include <drawingml/textliststylecontext.hxx>
55
#include <oox/helper/attributelist.hxx>
56
#include <oox/ole/olestorage.hxx>
57
#include <oox/ole/vbaproject.hxx>
58
#include <oox/ppt/pptshape.hxx>
59
#include <oox/ppt/presentationfragmenthandler.hxx>
60
#include <oox/ppt/slidefragmenthandler.hxx>
61
#include <oox/ppt/layoutfragmenthandler.hxx>
62
#include <oox/ppt/pptimport.hxx>
63
#include <oox/token/namespaces.hxx>
64
#include <oox/token/tokens.hxx>
65
#include <sax/fastattribs.hxx>
66
67
#include <com/sun/star/office/XAnnotation.hpp>
68
#include <com/sun/star/office/XAnnotationAccess.hpp>
69
#include <ooxresid.hxx>
70
#include <strings.hrc>
71
72
#include "EmbeddedFontListContext.hxx"
73
74
using namespace ::com::sun::star;
75
using namespace ::oox::core;
76
using namespace ::oox::drawingml;
77
using namespace ::com::sun::star::uno;
78
using namespace ::com::sun::star::beans;
79
using namespace ::com::sun::star::drawing;
80
using namespace ::com::sun::star::presentation;
81
using namespace ::com::sun::star::xml::sax;
82
83
namespace oox::ppt
84
{
85
86
namespace
87
{
88
constexpr auto constPredefinedClrTokens = frozen::make_unordered_map<PredefinedClrSchemeId, sal_Int32>
89
({
90
    { dk1, XML_dk1 },
91
    { lt1, XML_lt1 },
92
    { dk2, XML_dk2 },
93
    { lt2, XML_lt2 },
94
    { accent1, XML_accent1 },
95
    { accent2, XML_accent2 },
96
    { accent3, XML_accent3 },
97
    { accent4, XML_accent4 },
98
    { accent5, XML_accent5 },
99
    { accent6, XML_accent6 },
100
    { hlink, XML_hlink },
101
    { folHlink, XML_folHlink }
102
});
103
104
sal_Int32 getPredefinedClrTokens(PredefinedClrSchemeId eID)
105
18.0k
{
106
18.0k
    auto iterator = constPredefinedClrTokens.find(eID);
107
18.0k
    if (iterator == constPredefinedClrTokens.end())
108
0
        return XML_TOKEN_INVALID;
109
18.0k
    return iterator->second;
110
18.0k
}
111
} // end anonymous ns
112
113
PresentationFragmentHandler::PresentationFragmentHandler(XmlFilterBase& rFilter, const OUString& rFragmentPath)
114
2.05k
    : FragmentHandler2( rFilter, rFragmentPath )
115
2.05k
    , mpTextListStyle( std::make_shared<TextListStyle>() )
116
2.05k
    , mbCommentAuthorsRead(false)
117
2.05k
{
118
2.05k
    TextParagraphPropertiesArray& rParagraphDefaultsVector( mpTextListStyle->getListStyle() );
119
2.05k
    for (auto & elem : rParagraphDefaultsVector)
120
18.4k
    {
121
        // ppt is having zero bottom margin per default, whereas OOo is 0,5cm,
122
        // so this attribute needs to be set always
123
18.4k
        elem.getParaBottomMargin() = TextSpacing( 0 );
124
18.4k
    }
125
2.05k
}
126
127
PresentationFragmentHandler::~PresentationFragmentHandler() noexcept
128
2.05k
{
129
2.05k
}
130
131
void PresentationFragmentHandler::importSlideNames(const XmlFilterBase& rFilter, const std::vector<SlidePersistPtr>& rSlidePersist)
132
2.02k
{
133
2.02k
    sal_Int32 nMaxPages = rSlidePersist.size();
134
6.04k
    for (sal_Int32 nPage = 0; nPage < nMaxPages; nPage++)
135
4.02k
    {
136
4.02k
        auto aShapeMap = rSlidePersist[nPage]->getShapeMap();
137
4.02k
        auto aIter = std::find_if(aShapeMap.begin(), aShapeMap.end(),
138
4.64k
                                  [](const std::pair<OUString, ShapePtr>& element) {
139
4.64k
                                      auto pShapePtr = element.second;
140
4.64k
                                      return (pShapePtr
141
4.64k
                                              && (pShapePtr->getSubType() == XML_title
142
4.57k
                                                  || pShapePtr->getSubType() == XML_ctrTitle));
143
4.64k
                                  });
144
4.02k
        if (aIter != aShapeMap.end())
145
278
        {
146
278
            OUString aTitleText;
147
278
            Reference<text::XTextRange> xText(aIter->second->getXShape(), UNO_QUERY_THROW);
148
278
            aTitleText = xText->getString();
149
            // just a magic value but we don't want to drop out slide names which are too long
150
278
            if (aTitleText.getLength() > 63)
151
9
                aTitleText = aTitleText.copy(0, 63);
152
278
            bool bUseTitleAsSlideName = !aTitleText.isEmpty();
153
            // check duplicated title name
154
278
            if (bUseTitleAsSlideName)
155
136
            {
156
136
                sal_Int32 nCount = 1;
157
136
                Reference<XDrawPagesSupplier> xDPS(rFilter.getModel(), UNO_QUERY_THROW);
158
136
                Reference<XDrawPages> xDrawPages(xDPS->getDrawPages(), UNO_SET_THROW);
159
149
                for (sal_Int32 i = 0; i < nPage; ++i)
160
13
                {
161
13
                    Reference<XDrawPage> xDrawPage(xDrawPages->getByIndex(i), UNO_QUERY);
162
13
                    Reference<container::XNamed> xNamed(xDrawPage, UNO_QUERY_THROW);
163
13
                    std::u16string_view sRest;
164
13
                    if (o3tl::starts_with(xNamed->getName(), aTitleText, &sRest)
165
9
                        && (sRest.empty()
166
0
                            || (o3tl::starts_with(sRest, u" (") && o3tl::ends_with(sRest, u")")
167
0
                                && o3tl::toInt32(sRest.substr(2, sRest.size() - 3)) > 0)))
168
9
                        nCount++;
169
13
                }
170
136
                Reference<container::XNamed> xName(rSlidePersist[nPage]->getPage(), UNO_QUERY_THROW);
171
136
                xName->setName(
172
136
                    aTitleText
173
136
                    + (nCount == 1 ? u""_ustr : " (" + OUString::number(nCount) + ")"));
174
136
            }
175
278
        }
176
4.02k
    }
177
2.02k
}
178
179
void PresentationFragmentHandler::importCustomSlideShow(std::vector<CustomShow>& rCustomShowList)
180
0
{
181
0
    PowerPointImport& rFilter = dynamic_cast<PowerPointImport&>(getFilter());
182
0
    Reference<frame::XModel> xModel(rFilter.getModel());
183
0
    Reference<XDrawPagesSupplier> xDrawPagesSupplier(xModel, UNO_QUERY_THROW);
184
0
    Reference<XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages(), UNO_SET_THROW);
185
186
0
    Reference<css::lang::XSingleServiceFactory> mxShowFactory;
187
0
    Reference<css::container::XNameContainer> mxShows;
188
0
    Reference<XCustomPresentationSupplier> xShowsSupplier(xModel, UNO_QUERY);
189
0
    if (xShowsSupplier.is())
190
0
    {
191
0
        mxShows = xShowsSupplier->getCustomPresentations();
192
0
        mxShowFactory.set(mxShows, UNO_QUERY);
193
0
    }
194
195
0
    for (size_t i = 0; i < rCustomShowList.size(); ++i)
196
0
    {
197
0
        Reference<css::container::XIndexContainer> xShow(mxShowFactory->createInstance(),
198
0
                                                                    UNO_QUERY);
199
0
        if (xShow.is())
200
0
        {
201
0
            static constexpr OUString sSlide = u"slides/slide"_ustr;
202
0
            for (size_t j = 0; j < rCustomShowList[i].maSldLst.size(); ++j)
203
0
            {
204
0
                OUString sCustomSlide = rCustomShowList[i].maSldLst[j];
205
0
                sal_Int32 nPageNumber = 0;
206
0
                if (sCustomSlide.match(sSlide))
207
0
                    nPageNumber = o3tl::toInt32(sCustomSlide.subView(sSlide.getLength()));
208
209
0
                Reference<XDrawPage> xPage;
210
0
                xDrawPages->getByIndex(nPageNumber - 1) >>= xPage;
211
0
                if (xPage.is())
212
0
                    xShow->insertByIndex(xShow->getCount(), Any(xPage));
213
0
            }
214
215
0
            Any aAny;
216
0
            aAny <<= xShow;
217
0
            mxShows->insertByName(rCustomShowList[i].maCustomShowName, aAny);
218
0
        }
219
0
    }
220
0
}
221
222
void PresentationFragmentHandler::importMasterSlide(const Reference<frame::XModel>& xModel,
223
                                                    PowerPointImport& rFilter,
224
                                                    const OUString& rMasterFragmentPath)
225
2.12k
{
226
2.12k
    OUString aLayoutFragmentPath;
227
2.12k
    SlidePersistPtr pMasterPersistPtr;
228
2.12k
    Reference< drawing::XDrawPage > xMasterPage;
229
2.12k
    Reference< drawing::XMasterPagesSupplier > xMPS( xModel, uno::UNO_QUERY_THROW );
230
2.12k
    Reference< drawing::XDrawPages > xMasterPages( xMPS->getMasterPages(), uno::UNO_SET_THROW );
231
2.12k
    RelationsRef xMasterRelations = rFilter.importRelations( rMasterFragmentPath );
232
233
2.12k
    for (const auto& rEntry : *xMasterRelations)
234
16.6k
    {
235
16.6k
        if (!rEntry.second.maType.endsWith("relationships/slideLayout"))
236
1.99k
            continue;
237
238
14.6k
        aLayoutFragmentPath = xMasterRelations->getFragmentPathFromRelation(rEntry.second);
239
240
14.6k
        sal_Int32 nIndex;
241
14.6k
        if( rFilter.getMasterPages().empty() )
242
1.89k
        {
243
1.89k
            nIndex = 0;
244
1.89k
            xMasterPages->getByIndex( nIndex ) >>= xMasterPage;
245
1.89k
        }
246
12.7k
        else
247
12.7k
        {
248
12.7k
            nIndex = xMasterPages->getCount();
249
12.7k
            xMasterPage = xMasterPages->insertNewByIndex( nIndex );
250
12.7k
        }
251
252
14.6k
        pMasterPersistPtr = std::make_shared<SlidePersist>( rFilter, true, false, xMasterPage,
253
14.6k
                                                            std::make_shared<PPTShape>( Master, u"com.sun.star.drawing.GroupShape"_ustr ), mpTextListStyle );
254
14.6k
        pMasterPersistPtr->setLayoutPath( aLayoutFragmentPath );
255
14.6k
        rFilter.getMasterPages().push_back( pMasterPersistPtr );
256
14.6k
        rFilter.setActualSlidePersist( pMasterPersistPtr );
257
14.6k
        FragmentHandlerRef xMasterFragmentHandler( new SlideFragmentHandler( rFilter, rMasterFragmentPath, pMasterPersistPtr, Master ) );
258
259
        // set the correct theme
260
14.6k
        OUString aThemeFragmentPath = xMasterFragmentHandler->getFragmentPathFromFirstTypeFromOfficeDoc( u"theme" );
261
14.6k
        if( !aThemeFragmentPath.isEmpty() )
262
14.6k
        {
263
14.6k
            std::map< OUString, oox::drawingml::ThemePtr >& rThemes( rFilter.getThemes() );
264
14.6k
            std::map< OUString, oox::drawingml::ThemePtr >::iterator aIter2( rThemes.find( aThemeFragmentPath ) );
265
14.6k
            if( aIter2 == rThemes.end() )
266
1.96k
            {
267
1.96k
                oox::drawingml::ThemePtr pThemePtr = std::make_shared<oox::drawingml::Theme>();
268
1.96k
                pMasterPersistPtr->setTheme( pThemePtr );
269
1.96k
                Reference<xml::dom::XDocument> xDoc=
270
1.96k
                    rFilter.importFragment(aThemeFragmentPath);
271
272
1.96k
                auto pTheme = std::make_shared<model::Theme>();
273
1.96k
                pThemePtr->setTheme(pTheme);
274
275
1.96k
                rFilter.importFragment(
276
1.96k
                    new ThemeFragmentHandler(rFilter, aThemeFragmentPath, *pThemePtr, *pTheme),
277
1.96k
                    Reference<xml::sax::XFastSAXSerializable>(
278
1.96k
                        xDoc,
279
1.96k
                        UNO_QUERY_THROW));
280
1.96k
                rThemes[ aThemeFragmentPath ] = pThemePtr;
281
1.96k
                pThemePtr->setFragment(xDoc);
282
1.96k
                saveThemeToGrabBag(pThemePtr, nIndex + 1);
283
1.96k
            }
284
12.6k
            else
285
12.6k
            {
286
12.6k
                pMasterPersistPtr->setTheme( (*aIter2).second );
287
12.6k
            }
288
14.6k
        }
289
14.6k
        importSlide( xMasterFragmentHandler, pMasterPersistPtr );
290
14.6k
        rFilter.importFragment( new LayoutFragmentHandler( rFilter, aLayoutFragmentPath, pMasterPersistPtr ) );
291
14.6k
        pMasterPersistPtr->createBackground( rFilter );
292
14.6k
        pMasterPersistPtr->createXShapes( rFilter );
293
294
14.6k
        saveColorMapToGrabBag(pMasterPersistPtr->getClrMap());
295
296
14.6k
        uno::Reference< beans::XPropertySet > xSet(pMasterPersistPtr->getPage(), uno::UNO_QUERY_THROW);
297
14.6k
        xSet->setPropertyValue(u"SlideLayout"_ustr, Any(pMasterPersistPtr->getLayoutFromValueToken()));
298
299
14.6k
        oox::drawingml::ThemePtr pTheme = pMasterPersistPtr->getTheme();
300
14.6k
        if (pTheme)
301
14.4k
        {
302
14.4k
            pTheme->addTheme(pMasterPersistPtr->getPage());
303
14.4k
        }
304
14.6k
    }
305
2.12k
}
306
307
void PresentationFragmentHandler::saveThemeToGrabBag(const oox::drawingml::ThemePtr& pThemePtr,
308
                                                     sal_Int32 nThemeIdx)
309
1.80k
{
310
1.80k
    if (!pThemePtr)
311
0
        return;
312
313
1.80k
    try
314
1.80k
    {
315
1.80k
        uno::Reference<beans::XPropertySet> xDocProps(getFilter().getModel(), uno::UNO_QUERY);
316
1.80k
        if (xDocProps.is())
317
1.80k
        {
318
1.80k
            uno::Reference<beans::XPropertySetInfo> xPropsInfo = xDocProps->getPropertySetInfo();
319
320
1.80k
            static constexpr OUString aGrabBagPropName = u"InteropGrabBag"_ustr;
321
1.80k
            if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(aGrabBagPropName))
322
1.80k
            {
323
                // get existing grab bag
324
1.80k
                comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue(aGrabBagPropName));
325
326
1.80k
                comphelper::SequenceAsHashMap aThemesHashMap;
327
328
                // create current theme
329
1.80k
                uno::Sequence<beans::PropertyValue> aCurrentTheme(PredefinedClrSchemeId::Count);
330
1.80k
                auto pCurrentTheme = aCurrentTheme.getArray();
331
332
1.80k
                ClrScheme rClrScheme = pThemePtr->getClrScheme();
333
19.8k
                for (int nId = PredefinedClrSchemeId::dk2; nId != PredefinedClrSchemeId::Count; nId++)
334
18.0k
                {
335
18.0k
                    auto eID = static_cast<PredefinedClrSchemeId>(nId);
336
18.0k
                    sal_uInt32 nToken = getPredefinedClrTokens(eID);
337
18.0k
                    OUString sName(getPredefinedClrNames(eID));
338
18.0k
                    ::Color nColor;
339
340
18.0k
                    rClrScheme.getColor(nToken, nColor);
341
342
18.0k
                    pCurrentTheme[nId].Name = sName;
343
18.0k
                    pCurrentTheme[nId].Value <<= nColor;
344
18.0k
                }
345
346
347
1.80k
                uno::Sequence<beans::PropertyValue> aTheme{
348
                    // add new theme to the sequence
349
                    // Export code uses the master slide's index to find the right theme
350
                    // so use the same index in the grabbag.
351
1.80k
                    comphelper::makePropertyValue(
352
1.80k
                        "ppt/theme/theme" + OUString::number(nThemeIdx) + ".xml", aCurrentTheme),
353
                    // store DOM fragment for SmartArt re-generation
354
1.80k
                    comphelper::makePropertyValue(u"OOXTheme"_ustr, pThemePtr->getFragment())
355
1.80k
                };
356
357
1.80k
                aThemesHashMap << aTheme;
358
359
                // put the new items
360
1.80k
                aGrabBag.update(aThemesHashMap);
361
362
                // put it back to the document
363
1.80k
                xDocProps->setPropertyValue(aGrabBagPropName, uno::Any(aGrabBag.getAsConstPropertyValueList()));
364
1.80k
            }
365
1.80k
        }
366
1.80k
    }
367
1.80k
    catch (const uno::Exception&)
368
1.80k
    {
369
0
        SAL_WARN("oox", "oox::ppt::PresentationFragmentHandler::saveThemeToGrabBag, Failed to save grab bag");
370
0
    }
371
1.80k
}
372
373
void PresentationFragmentHandler::saveColorMapToGrabBag(const oox::drawingml::ClrMapPtr& pClrMapPtr)
374
14.4k
{
375
14.4k
    if (!pClrMapPtr)
376
6.83k
        return;
377
378
7.60k
    try
379
7.60k
    {
380
7.60k
        uno::Reference<beans::XPropertySet> xDocProps(getFilter().getModel(), uno::UNO_QUERY);
381
7.60k
        if (xDocProps.is())
382
7.60k
        {
383
7.60k
            uno::Reference<beans::XPropertySetInfo> xPropsInfo = xDocProps->getPropertySetInfo();
384
385
7.60k
            static constexpr OUString aGrabBagPropName = u"InteropGrabBag"_ustr;
386
7.60k
            if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(aGrabBagPropName))
387
7.60k
            {
388
7.60k
                static constexpr auto constTokenArray = std::to_array<sal_Int32>({
389
7.60k
                        XML_bg1,     XML_tx1,     XML_bg2,     XML_tx2,
390
7.60k
                        XML_accent1, XML_accent2, XML_accent3, XML_accent4,
391
7.60k
                        XML_accent5, XML_accent6, XML_hlink,   XML_folHlink
392
7.60k
                });
393
394
7.60k
                comphelper::SequenceAsHashMap aClrMapHashMap;
395
7.60k
                comphelper::SequenceAsHashMap aGrabBag(
396
7.60k
                    xDocProps->getPropertyValue(aGrabBagPropName));
397
398
7.60k
                std::vector<beans::PropertyValue> aClrMapList;
399
7.60k
                size_t nColorMapSize = constTokenArray.size();
400
7.60k
                aClrMapList.reserve(nColorMapSize);
401
98.9k
                for (size_t i = 0; i < nColorMapSize; ++i)
402
91.3k
                {
403
91.3k
                    sal_Int32 nToken = constTokenArray[i];
404
91.3k
                    pClrMapPtr->getColorMap(nToken);
405
91.3k
                    aClrMapList.push_back(
406
91.3k
                        comphelper::makePropertyValue(OUString::number(i), nToken));
407
91.3k
                }
408
409
7.60k
                uno::Sequence<beans::PropertyValue> aClrMapPropValue{ comphelper::makePropertyValue(
410
7.60k
                    u"OOXColorMap"_ustr,
411
7.60k
                    uno::Any(comphelper::containerToSequence(aClrMapList))) };
412
413
7.60k
                aClrMapHashMap << aClrMapPropValue;
414
7.60k
                aGrabBag.update(aClrMapHashMap);
415
416
7.60k
                xDocProps->setPropertyValue(aGrabBagPropName,
417
7.60k
                                            uno::Any(aGrabBag.getAsConstPropertyValueList()));
418
7.60k
            }
419
7.60k
        }
420
7.60k
    }
421
7.60k
    catch (const uno::Exception&)
422
7.60k
    {
423
0
        SAL_WARN("oox", "oox::ppt::PresentationFragmentHandler::saveColorMapToGrabBag, Failed to save grab bag");
424
0
    }
425
7.60k
}
426
427
void PresentationFragmentHandler::importMasterSlides()
428
2.02k
{
429
2.02k
    OUString aMasterFragmentPath;
430
2.02k
    PowerPointImport& rFilter = dynamic_cast<PowerPointImport&>(getFilter());
431
2.02k
    Reference<frame::XModel> xModel(rFilter.getModel());
432
433
4.15k
    for (size_t nMaster = 0; nMaster < maSlideMasterVector.size(); ++nMaster)
434
2.12k
    {
435
2.12k
        aMasterFragmentPath = getFragmentPathFromRelId(maSlideMasterVector[nMaster]);
436
2.12k
        importMasterSlide(xModel, rFilter, aMasterFragmentPath);
437
2.12k
    }
438
2.02k
}
439
440
void PresentationFragmentHandler::importSlide(sal_uInt32 nSlide, bool bFirstPage, bool bImportNotesPage)
441
4.20k
{
442
4.20k
    PowerPointImport& rFilter = dynamic_cast< PowerPointImport& >( getFilter() );
443
444
4.20k
    Reference< frame::XModel > xModel( rFilter.getModel() );
445
4.20k
    Reference< drawing::XDrawPage > xSlide;
446
447
    // importing slide pages and its corresponding notes page
448
4.20k
    Reference< drawing::XDrawPagesSupplier > xDPS( xModel, uno::UNO_QUERY_THROW );
449
4.20k
    Reference< drawing::XDrawPages > xDrawPages( xDPS->getDrawPages(), uno::UNO_SET_THROW );
450
451
4.20k
    try {
452
453
4.20k
        if( bFirstPage )
454
2.02k
        {
455
2.02k
            xDrawPages->getByIndex( 0 ) >>= xSlide;
456
2.02k
            importMasterSlides();
457
2.02k
        }
458
2.18k
        else
459
2.18k
            xSlide = xDrawPages->insertNewByIndex( xDrawPages->getCount() );
460
461
4.20k
        OUString aSlideFragmentPath = getFragmentPathFromRelId( maSlidesVector[ nSlide ] );
462
4.20k
        if( !aSlideFragmentPath.isEmpty() )
463
4.02k
        {
464
4.02k
            SlidePersistPtr pMasterPersistPtr;
465
4.02k
            SlidePersistPtr pSlidePersistPtr = std::make_shared<SlidePersist>( rFilter, false, false, xSlide,
466
4.02k
                                std::make_shared<PPTShape>( Slide, u"com.sun.star.drawing.GroupShape"_ustr ), mpTextListStyle );
467
468
4.02k
            FragmentHandlerRef xSlideFragmentHandler( new SlideFragmentHandler( rFilter, aSlideFragmentPath, pSlidePersistPtr, Slide ) );
469
470
            // importing the corresponding masterpage/layout
471
4.02k
            OUString aLayoutFragmentPath = xSlideFragmentHandler->getFragmentPathFromFirstTypeFromOfficeDoc( u"slideLayout" );
472
4.02k
            OUString aCommentFragmentPath = xSlideFragmentHandler->getFragmentPathFromFirstTypeFromOfficeDoc( u"comments" );
473
4.02k
            if ( !aLayoutFragmentPath.isEmpty() )
474
2.97k
            {
475
                // importing layout
476
2.97k
                RelationsRef xLayoutRelations = rFilter.importRelations( aLayoutFragmentPath );
477
2.97k
                OUString aMasterFragmentPath = xLayoutRelations->getFragmentPathFromFirstTypeFromOfficeDoc( u"slideMaster" );
478
2.97k
                if( !aMasterFragmentPath.isEmpty() )
479
2.53k
                {
480
                    // check if the corresponding masterpage+layout has already been imported
481
2.53k
                    std::vector< SlidePersistPtr >& rMasterPages( rFilter.getMasterPages() );
482
2.53k
                    for (auto const& masterPage : rMasterPages)
483
5.84k
                    {
484
5.84k
                        if ( ( masterPage->getPath() == aMasterFragmentPath ) && ( masterPage->getLayoutPath() == aLayoutFragmentPath ) )
485
2.26k
                        {
486
2.26k
                            pMasterPersistPtr = masterPage;
487
2.26k
                            break;
488
2.26k
                        }
489
5.84k
                    }
490
2.53k
                }
491
2.97k
            }
492
493
            // importing slide page
494
4.02k
            if (pMasterPersistPtr) {
495
2.26k
                pSlidePersistPtr->setMasterPersist( pMasterPersistPtr );
496
2.26k
                pSlidePersistPtr->setTheme( pMasterPersistPtr->getTheme() );
497
2.26k
                Reference< drawing::XMasterPageTarget > xMasterPageTarget( pSlidePersistPtr->getPage(), UNO_QUERY );
498
2.26k
                if( xMasterPageTarget.is() )
499
2.26k
                    xMasterPageTarget->setMasterPage( pMasterPersistPtr->getPage() );
500
2.26k
            }
501
4.02k
            rFilter.getDrawPages().push_back( pSlidePersistPtr );
502
4.02k
            rFilter.setActualSlidePersist( pSlidePersistPtr );
503
4.02k
            importSlide( xSlideFragmentHandler, pSlidePersistPtr );
504
4.02k
            pSlidePersistPtr->createBackground( rFilter );
505
4.02k
            pSlidePersistPtr->createXShapes( rFilter );
506
507
4.02k
            if(bImportNotesPage) {
508
509
                // now importing the notes page
510
4.02k
                OUString aNotesFragmentPath = xSlideFragmentHandler->getFragmentPathFromFirstTypeFromOfficeDoc( u"notesSlide" );
511
4.02k
                if( !aNotesFragmentPath.isEmpty() )
512
90
                {
513
90
                    Reference< XPresentationPage > xPresentationPage( xSlide, UNO_QUERY );
514
90
                    if ( xPresentationPage.is() )
515
90
                    {
516
90
                        Reference< XDrawPage > xNotesPage( xPresentationPage->getNotesPage() );
517
90
                        if ( xNotesPage.is() )
518
90
                        {
519
90
                            SlidePersistPtr pNotesPersistPtr = std::make_shared<SlidePersist>( rFilter, false, true, xNotesPage,
520
90
                                std::make_shared<PPTShape>( Slide, u"com.sun.star.drawing.GroupShape"_ustr ), mpTextListStyle );
521
90
                            FragmentHandlerRef xNotesFragmentHandler( new SlideFragmentHandler( getFilter(), aNotesFragmentPath, pNotesPersistPtr, Slide ) );
522
90
                            rFilter.getNotesPages().push_back( pNotesPersistPtr );
523
90
                            rFilter.setActualSlidePersist( pNotesPersistPtr );
524
90
                            importSlide( xNotesFragmentHandler, pNotesPersistPtr );
525
90
                            pNotesPersistPtr->createBackground( rFilter );
526
90
                            pNotesPersistPtr->createXShapes( rFilter );
527
90
                        }
528
90
                    }
529
90
                }
530
4.02k
            }
531
532
4.02k
            if( !mbCommentAuthorsRead && !aCommentFragmentPath.isEmpty() )
533
18
            {
534
                // Comments are present and commentAuthors.xml has still not been read
535
18
                mbCommentAuthorsRead = true;
536
18
                Reference< XPresentationPage > xPresentationPage( xSlide, UNO_QUERY );
537
18
                Reference< XDrawPage > xCommentAuthorsPage( xPresentationPage->getNotesPage() );
538
18
                SlidePersistPtr pCommentAuthorsPersistPtr =
539
18
                    std::make_shared<SlidePersist>( rFilter, false, true, xCommentAuthorsPage,
540
18
                                      std::make_shared<PPTShape>(
541
18
                                              Slide, u"com.sun.star.drawing.GroupShape"_ustr ),
542
18
                                      mpTextListStyle );
543
18
                FragmentHandlerRef xCommentAuthorsFragmentHandler(
544
18
                    new SlideFragmentHandler( getFilter(),
545
18
                                              u"ppt/commentAuthors.xml"_ustr,
546
18
                                              pCommentAuthorsPersistPtr,
547
18
                                              Slide ) );
548
549
18
                getFilter().importFragment( xCommentAuthorsFragmentHandler );
550
18
                maAuthorList.setValues( pCommentAuthorsPersistPtr->getCommentAuthors() );
551
18
            }
552
4.02k
            if( !aCommentFragmentPath.isEmpty() )
553
26
            {
554
26
                Reference< XPresentationPage > xPresentationPage( xSlide, UNO_QUERY );
555
26
                Reference< XDrawPage > xCommentsPage( xPresentationPage->getNotesPage() );
556
26
                SlidePersistPtr pCommentsPersistPtr =
557
26
                    std::make_shared<SlidePersist>(
558
26
                        rFilter, false, true, xCommentsPage,
559
26
                        std::make_shared<PPTShape>(
560
26
                                Slide, u"com.sun.star.drawing.GroupShape"_ustr ),
561
26
                        mpTextListStyle );
562
563
26
                FragmentHandlerRef xCommentsFragmentHandler(
564
26
                    new SlideFragmentHandler(
565
26
                        getFilter(),
566
26
                        aCommentFragmentPath,
567
26
                        pCommentsPersistPtr,
568
26
                        Slide ) );
569
26
                pCommentsPersistPtr->getCommentsList().cmLst.clear();
570
26
                getFilter().importFragment( xCommentsFragmentHandler );
571
572
26
                if (!pCommentsPersistPtr->getCommentsList().cmLst.empty())
573
21
                {
574
                    //set comment chars for last comment on slide
575
21
                    SlideFragmentHandler* comment_handler =
576
21
                        dynamic_cast<SlideFragmentHandler*>(xCommentsFragmentHandler.get());
577
21
                    assert(comment_handler);
578
                    // some comments have no text -> set empty string as text to avoid
579
                    // crash (back() on empty vector is undefined) and losing other
580
                    // comment data that might be there (author, position, timestamp etc.)
581
21
                    pCommentsPersistPtr->getCommentsList().cmLst.back().setText(
582
21
                            comment_handler->getCharVector().empty() ? u""_ustr :
583
21
                            comment_handler->getCharVector().back() );
584
21
                }
585
26
                pCommentsPersistPtr->getCommentAuthors().setValues(maAuthorList);
586
587
                //insert all comments from commentsList
588
73
                for(int i=0; i<pCommentsPersistPtr->getCommentsList().getSize(); i++)
589
47
                {
590
47
                    try {
591
47
                        Comment aComment = pCommentsPersistPtr->getCommentsList().getCommentAtIndex(i);
592
47
                        uno::Reference< office::XAnnotationAccess > xAnnotationAccess( xSlide, UNO_QUERY_THROW );
593
47
                        uno::Reference< office::XAnnotation > xAnnotation( xAnnotationAccess->createAndInsertAnnotation() );
594
47
                        int nPosX = aComment.getIntX();
595
47
                        int nPosY = aComment.getIntY();
596
47
                        xAnnotation->setPosition(
597
47
                            geometry::RealPoint2D(
598
47
                                ::oox::drawingml::convertEmuToHmm( nPosX ) * 15.87,
599
47
                                ::oox::drawingml::convertEmuToHmm( nPosY ) * 15.87 ) );
600
47
                        xAnnotation->setAuthor( aComment.getAuthor(maAuthorList) );
601
47
                        xAnnotation->setInitials( aComment.getInitials(maAuthorList) );
602
47
                        xAnnotation->setDateTime( aComment.getDateTime() );
603
47
                        uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
604
47
                        xText->setString( aComment.get_text());
605
47
                    } catch( css::lang::IllegalArgumentException& ) {}
606
47
                }
607
26
            }
608
4.02k
        }
609
4.20k
    }
610
4.20k
    catch( uno::Exception& )
611
4.20k
    {
612
164
        TOOLS_WARN_EXCEPTION( "oox", "oox::ppt::PresentationFragmentHandler::EndDocument()" );
613
164
    }
614
4.20k
}
615
616
void PresentationFragmentHandler::finalizeImport()
617
2.03k
{
618
2.03k
    PowerPointImport& rFilter = dynamic_cast< PowerPointImport& >( getFilter() );
619
620
2.03k
    sal_Int32 nPageCount = maSlidesVector.size();
621
622
    // we will take the FilterData property "PageRange" if available, otherwise full range is used
623
2.03k
    comphelper::SequenceAsHashMap& rFilterData = rFilter.getFilterData();
624
625
    // writing back the original PageCount of this document, it can be accessed from the XModel
626
    // via getArgs after the import.
627
2.03k
    rFilterData[u"OriginalPageCount"_ustr] <<= nPageCount;
628
2.03k
    bool bImportNotesPages = rFilterData.getUnpackedValueOrDefault(u"ImportNotesPages"_ustr, true);
629
2.03k
    OUString aPageRange = rFilterData.getUnpackedValueOrDefault(u"PageRange"_ustr, OUString());
630
631
2.03k
    if( !aPageRange.getLength() )
632
2.03k
    {
633
2.03k
        aPageRange = "1-" + OUString::number( nPageCount );
634
2.03k
    }
635
636
2.03k
    StringRangeEnumerator aRangeEnumerator( aPageRange, 0, nPageCount - 1 );
637
2.03k
    if (aRangeEnumerator.size())
638
2.02k
    {
639
        // todo: localized progress bar text
640
2.02k
        const Reference< task::XStatusIndicator >& rxStatusIndicator( getFilter().getStatusIndicator() );
641
2.02k
        if ( rxStatusIndicator.is() )
642
0
            rxStatusIndicator->start( OUString(), 10000 );
643
644
2.02k
        try
645
2.02k
        {
646
2.02k
            int nPagesImported = 0;
647
2.02k
            for (sal_Int32 elem : aRangeEnumerator)
648
4.20k
            {
649
4.20k
                if ( rxStatusIndicator.is() )
650
0
                    rxStatusIndicator->setValue((nPagesImported * 10000) / aRangeEnumerator.size());
651
652
4.20k
                importSlide(elem, !nPagesImported, bImportNotesPages);
653
4.20k
                nPagesImported++;
654
4.20k
            }
655
2.02k
            importSlideNames( rFilter, rFilter.getDrawPages());
656
2.02k
            if (!maCustomShowList.empty())
657
0
                importCustomSlideShow(maCustomShowList);
658
2.02k
        }
659
2.02k
        catch( uno::Exception& )
660
2.02k
        {
661
0
            TOOLS_WARN_EXCEPTION( "oox", "oox::ppt::PresentationFragmentHandler::finalizeImport()" );
662
0
        }
663
        // todo error handling;
664
2.02k
        if ( rxStatusIndicator.is() )
665
0
            rxStatusIndicator->end();
666
2.02k
    }
667
668
    // open the VBA project storage
669
2.03k
    OUString aVbaFragmentPath = getFragmentPathFromFirstType(CREATE_MSOFFICE_RELATION_TYPE("vbaProject"));
670
2.03k
    if (!aVbaFragmentPath.isEmpty())
671
0
    {
672
0
        uno::Reference<io::XInputStream> xInStrm = getFilter().openInputStream(aVbaFragmentPath);
673
0
        if (xInStrm.is())
674
0
        {
675
0
            StorageRef xPrjStrg = std::make_shared<oox::ole::OleStorage>(getFilter().getComponentContext(), xInStrm, false);
676
0
            getFilter().getVbaProject().importVbaProject(*xPrjStrg);
677
0
        }
678
0
    }
679
2.03k
}
680
681
// CT_Presentation
682
::oox::core::ContextHandlerRef PresentationFragmentHandler::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
683
18.6k
{
684
18.6k
    switch( aElementToken )
685
18.6k
    {
686
2.02k
    case PPT_TOKEN( presentation ):
687
2.02k
        mbEmbedTrueTypeFonts = rAttribs.getBool(XML_embedTrueTypeFonts, false);
688
2.02k
        return this;
689
2.02k
    case PPT_TOKEN( sldMasterIdLst ):
690
2.25k
    case PPT_TOKEN( notesMasterIdLst ):
691
4.28k
    case PPT_TOKEN( sldIdLst ):
692
4.28k
        return this;
693
2.12k
    case PPT_TOKEN( sldMasterId ):
694
2.12k
        maSlideMasterVector.push_back( rAttribs.getStringDefaulted( R_TOKEN( id )) );
695
2.12k
        return this;
696
4.20k
    case PPT_TOKEN( sldId ):
697
4.20k
        maSlidesVector.push_back( rAttribs.getStringDefaulted( R_TOKEN( id )) );
698
4.20k
        return this;
699
230
    case PPT_TOKEN( notesMasterId ):
700
230
        maNotesMasterVector.push_back( rAttribs.getStringDefaulted( R_TOKEN( id )) );
701
230
        return this;
702
2.02k
    case PPT_TOKEN( sldSz ):
703
2.02k
        maSlideSize = GetSize2D( rAttribs.getFastAttributeList() );
704
2.02k
        return this;
705
2.02k
    case PPT_TOKEN( notesSz ):
706
2.02k
        maNotesSize = GetSize2D( rAttribs.getFastAttributeList() );
707
2.02k
        return this;
708
19
    case PPT_TOKEN( custShowLst ):
709
19
        return new CustomShowListContext( *this, maCustomShowList );
710
827
    case PPT_TOKEN( defaultTextStyle ):
711
827
        return new TextListStyleContext( *this, *mpTextListStyle );
712
0
    case PPT_TOKEN(embeddedFontLst):
713
0
    {
714
0
        uno::Reference<beans::XPropertySet> xDocSettings(getFilter().getModelFactory()->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY);
715
0
        return new EmbeddedFontListContext(*this, mbEmbedTrueTypeFonts, xDocSettings);
716
2.25k
    }
717
0
    case PPT_TOKEN( modifyVerifier ):
718
0
        OUString sAlgorithmClass = rAttribs.getStringDefaulted(XML_cryptAlgorithmClass);
719
0
        OUString sAlgorithmType = rAttribs.getStringDefaulted(XML_cryptAlgorithmType);
720
0
        sal_Int32 nAlgorithmSid = rAttribs.getInteger(XML_cryptAlgorithmSid, 0);
721
0
        sal_Int32 nSpinCount = rAttribs.getInteger(XML_spinCount, 0);
722
0
        OUString sSalt = rAttribs.getStringDefaulted(XML_saltData);
723
0
        OUString sHash = rAttribs.getStringDefaulted(XML_hashData);
724
0
        if (sAlgorithmClass == "hash" && sAlgorithmType == "typeAny" && nAlgorithmSid != 0
725
0
            && !sSalt.isEmpty() && !sHash.isEmpty())
726
0
        {
727
0
            OUString sAlgorithmName;
728
0
            switch (nAlgorithmSid)
729
0
            {
730
0
                case 1:
731
0
                    sAlgorithmName = "MD2";
732
0
                    break;
733
0
                case 2:
734
0
                    sAlgorithmName = "MD4";
735
0
                    break;
736
0
                case 3:
737
0
                    sAlgorithmName = "MD5";
738
0
                    break;
739
0
                case 4:
740
0
                    sAlgorithmName = "SHA-1";
741
0
                    break;
742
0
                case 5:
743
0
                    sAlgorithmName = "MAC";
744
0
                    break;
745
0
                case 6:
746
0
                    sAlgorithmName = "RIPEMD";
747
0
                    break;
748
0
                case 7:
749
0
                    sAlgorithmName = "RIPEMD-160";
750
0
                    break;
751
0
                case 9:
752
0
                    sAlgorithmName = "HMAC";
753
0
                    break;
754
0
                case 12:
755
0
                    sAlgorithmName = "SHA-256";
756
0
                    break;
757
0
                case 13:
758
0
                    sAlgorithmName = "SHA-384";
759
0
                    break;
760
0
                case 14:
761
0
                    sAlgorithmName = "SHA-512";
762
0
                    break;
763
0
                default:; // 8, 10, 11, any other value: Undefined.
764
0
            }
765
766
0
            if (!sAlgorithmName.isEmpty())
767
0
            {
768
0
                uno::Sequence<beans::PropertyValue> aResult{
769
0
                    comphelper::makePropertyValue(u"algorithm-name"_ustr, sAlgorithmName),
770
0
                    comphelper::makePropertyValue(u"salt"_ustr, sSalt),
771
0
                    comphelper::makePropertyValue(u"iteration-count"_ustr, nSpinCount),
772
0
                    comphelper::makePropertyValue(u"hash"_ustr, sHash)
773
0
                };
774
0
                try
775
0
                {
776
0
                    uno::Reference<beans::XPropertySet> xDocSettings(
777
0
                        getFilter().getModelFactory()->createInstance(
778
0
                            u"com.sun.star.document.Settings"_ustr),
779
0
                        uno::UNO_QUERY);
780
0
                    xDocSettings->setPropertyValue(u"ModifyPasswordInfo"_ustr, uno::Any(aResult));
781
0
                }
782
0
                catch (const uno::Exception&)
783
0
                {
784
0
                }
785
0
            }
786
0
        }
787
0
        return this;
788
18.6k
    }
789
860
    return this;
790
18.6k
}
791
792
void PresentationFragmentHandler::importSlide( const FragmentHandlerRef& rxSlideFragmentHandler,
793
        const SlidePersistPtr& rSlidePersistPtr )
794
18.5k
{
795
18.5k
    Reference< drawing::XDrawPage > xSlide( rSlidePersistPtr->getPage() );
796
18.5k
    SlidePersistPtr pMasterPersistPtr( rSlidePersistPtr->getMasterPersist() );
797
18.5k
    if ( pMasterPersistPtr )
798
2.26k
    {
799
        // Setting "Layout" property adds extra title and outliner preset shapes to the master slide
800
2.26k
        Reference< drawing::XDrawPage > xMasterSlide(pMasterPersistPtr->getPage());
801
2.26k
        const int nCount = xMasterSlide->getCount();
802
803
2.26k
        uno::Reference< beans::XPropertySet > xSet( xSlide, uno::UNO_QUERY_THROW );
804
2.26k
        xSet->setPropertyValue( u"Layout"_ustr, Any( pMasterPersistPtr->getLayoutFromValueToken() ) );
805
806
4.21k
        while( nCount < xMasterSlide->getCount())
807
1.94k
        {
808
1.94k
            Reference< drawing::XShape > xShape;
809
1.94k
            xMasterSlide->getByIndex(xMasterSlide->getCount()-1) >>= xShape;
810
1.94k
            xMasterSlide->remove(xShape);
811
1.94k
        }
812
2.26k
    }
813
31.7k
    while( xSlide->getCount() )
814
13.2k
    {
815
13.2k
        Reference< drawing::XShape > xShape;
816
13.2k
        xSlide->getByIndex(0) >>= xShape;
817
13.2k
        xSlide->remove( xShape );
818
13.2k
    }
819
820
18.5k
    Reference< XPropertySet > xPropertySet( xSlide, UNO_QUERY );
821
18.5k
    if ( xPropertySet.is() )
822
18.5k
    {
823
18.5k
        awt::Size& rPageSize( rSlidePersistPtr->isNotesPage() ? maNotesSize : maSlideSize );
824
18.5k
        xPropertySet->setPropertyValue( u"Width"_ustr, Any( rPageSize.Width ) );
825
18.5k
        xPropertySet->setPropertyValue( u"Height"_ustr, Any( rPageSize.Height ) );
826
827
18.5k
        oox::ppt::HeaderFooter aHeaderFooter( rSlidePersistPtr->getHeaderFooter() );
828
18.5k
        if ( !rSlidePersistPtr->isMasterPage() )
829
4.11k
            aHeaderFooter.mbSlideNumber = aHeaderFooter.mbHeader = aHeaderFooter.mbFooter = aHeaderFooter.mbDateTime = false;
830
18.5k
        try
831
18.5k
        {
832
18.5k
            if ( rSlidePersistPtr->isNotesPage() )
833
90
                xPropertySet->setPropertyValue( u"IsHeaderVisible"_ustr, Any( aHeaderFooter.mbHeader ) );
834
18.5k
            xPropertySet->setPropertyValue( u"IsFooterVisible"_ustr, Any( aHeaderFooter.mbFooter ) );
835
18.5k
            xPropertySet->setPropertyValue( u"IsDateTimeVisible"_ustr, Any( aHeaderFooter.mbDateTime ) );
836
18.5k
            xPropertySet->setPropertyValue( u"IsPageNumberVisible"_ustr, Any( aHeaderFooter.mbSlideNumber ) );
837
18.5k
        }
838
18.5k
        catch( uno::Exception& )
839
18.5k
        {
840
14.4k
        }
841
18.5k
    }
842
18.5k
    rSlidePersistPtr->setPath( rxSlideFragmentHandler->getFragmentPath() );
843
18.5k
    getFilter().importFragment( rxSlideFragmentHandler );
844
18.5k
}
845
846
}
847
848
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */