1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <oox/drawingml/clrscheme.hxx>
22 #include <oox/token/namespaces.hxx>
23 #include <oox/token/tokens.hxx>
24 #include <oox/token/relationship.hxx>
25 #include <oox/ole/vbaproject.hxx>
26 #include "epptooxml.hxx"
27 #include <oox/export/shapes.hxx>
29 #include <comphelper/sequenceashashmap.hxx>
30 #include <comphelper/storagehelper.hxx>
31 #include <sax/fshelper.hxx>
32 #include <rtl/ustrbuf.hxx>
33 #include <sal/log.hxx>
34 #include <com/sun/star/animations/TransitionType.hpp>
35 #include <com/sun/star/animations/TransitionSubType.hpp>
36 #include <com/sun/star/beans/XPropertySetInfo.hpp>
37 #include <com/sun/star/drawing/FillStyle.hpp>
38 #include <com/sun/star/drawing/XDrawPages.hpp>
39 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
40 #include <com/sun/star/embed/ElementModes.hpp>
41 #include <com/sun/star/geometry/RealPoint2D.hpp>
42 #include <com/sun/star/office/XAnnotationEnumeration.hpp>
43 #include <com/sun/star/office/XAnnotationAccess.hpp>
44 #include <com/sun/star/presentation/AnimationSpeed.hpp>
45 #include <com/sun/star/util/DateTime.hpp>
46 #include <com/sun/star/task/XStatusIndicator.hpp>
47 #include <com/sun/star/frame/XModel.hpp>
48 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 #include <oox/export/utils.hxx>
52 #include "pptx-animations.hxx"
53 #include "../ppt/pptanimations.hxx"
55 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
56 #include <com/sun/star/document/XStorageBasedDocument.hpp>
58 #if OSL_DEBUG_LEVEL > 1
59 #include <com/sun/star/drawing/RectanglePoint.hpp>
62 // presentation namespaces
63 #define PNMSS FSNS(XML_xmlns, XML_a), OUStringToOString(this->getNamespaceURL(OOX_NS(dml)), RTL_TEXTENCODING_UTF8).getStr(), \
64 FSNS(XML_xmlns, XML_p), OUStringToOString(this->getNamespaceURL(OOX_NS(ppt)), RTL_TEXTENCODING_UTF8).getStr(), \
65 FSNS(XML_xmlns, XML_r), OUStringToOString(this->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(), \
66 FSNS(XML_xmlns, XML_p14), OUStringToOString(this->getNamespaceURL(OOX_NS(p14)), RTL_TEXTENCODING_UTF8).getStr(), \
67 FSNS(XML_xmlns, XML_p15), OUStringToOString(this->getNamespaceURL(OOX_NS(p15)), RTL_TEXTENCODING_UTF8).getStr(), \
68 FSNS(XML_xmlns, XML_mc), OUStringToOString(this->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr()
71 using namespace ::com::sun::star
;
72 using namespace ::com::sun::star::animations
;
73 using namespace ::com::sun::star::beans
;
74 using namespace ::com::sun::star::container
;
75 using namespace ::com::sun::star::drawing
;
76 using namespace ::com::sun::star::geometry
;
77 using namespace ::com::sun::star::presentation
;
78 using namespace ::com::sun::star::office
;
79 using namespace ::com::sun::star::text
;
80 using namespace ::com::sun::star::uno
;
81 using namespace ::com::sun::star::util
;
82 using namespace ::ppt
;
83 using ::com::sun::star::beans::XPropertySet
;
84 using ::com::sun::star::beans::XPropertySetInfo
;
85 using ::com::sun::star::container::XIndexAccess
;
86 using ::sax_fastparser::FSHelperPtr
;
87 using namespace oox::drawingml
;
88 using namespace oox::core
;
90 #if OSL_DEBUG_LEVEL > 1
91 void dump_pset(Reference
< XPropertySet
> const& rXPropSet
);
99 class PowerPointShapeExport
: public ShapeExport
101 PowerPointExport
& mrExport
;
105 PowerPointShapeExport(FSHelperPtr pFS
, ShapeHashMap
* pShapeMap
, PowerPointExport
* pFB
);
106 void SetMaster(bool bMaster
);
107 void SetPageType(PageType ePageType
);
108 ShapeExport
& WriteNonVisualProperties(const Reference
< XShape
>& xShape
) override
;
109 ShapeExport
& WriteTextShape(const Reference
< XShape
>& xShape
) override
;
110 ShapeExport
& WriteUnknownShape(const Reference
< XShape
>& xShape
) override
;
111 ShapeExport
& WritePlaceholderShape(const Reference
< XShape
>& xShape
, PlaceholderType ePlaceholder
);
112 ShapeExport
& WritePageShape(const Reference
< XShape
>& xShape
, PageType ePageType
, bool bPresObj
);
115 bool WritePlaceholder(const Reference
< XShape
>& xShape
, PlaceholderType ePlaceholder
, bool bMaster
);
121 void WriteSndAc(const FSHelperPtr
& pFS
, const OUString
& sSoundRelId
, const OUString
& sSoundName
)
123 pFS
->startElementNS(XML_p
, XML_sndAc
);
124 pFS
->startElementNS(XML_p
, XML_stSnd
);
125 pFS
->singleElementNS(XML_p
, XML_snd
,
126 FSNS(XML_r
, XML_embed
), sSoundRelId
.isEmpty() ? nullptr : sSoundRelId
.toUtf8().getStr(),
127 XML_name
, sSoundName
.isEmpty() ? nullptr : sSoundName
.toUtf8().getStr());
128 pFS
->endElement(FSNS(XML_p
, XML_stSnd
));
129 pFS
->endElement(FSNS(XML_p
, XML_sndAc
));
140 LAYOUT_TITLE_CONTENT
,
141 LAYOUT_TITLE_2CONTENT
,
143 LAYOUT_CENTERED_TEXT
,
144 LAYOUT_TITLE_2CONTENT_CONTENT
,
145 LAYOUT_TITLE_CONTENT_2CONTENT
,
146 LAYOUT_TITLE_2CONTENT_OVER_CONTENT
,
147 LAYOUT_TITLE_CONTENT_OVER_CONTENT
,
148 LAYOUT_TITLE_4CONTENT
,
149 LAYOUT_TITLE_6CONTENT
,
153 struct PPTXLayoutInfo
160 static const PPTXLayoutInfo aLayoutInfo
[LAYOUT_SIZE
] =
162 { 20, "Blank Slide", "blank" },
163 { 0, "Title Slide", "tx" },
164 { 1, "Title, Content", "obj" },
165 { 3, "Title, 2 Content", "twoObj" },
166 { 19, "Title Only", "titleOnly" },
167 { 32, "Centered Text", "objOnly" }, // not exactly, but close
168 { 15, "Title, 2 Content and Content", "twoObjAndObj" },
169 { 12, "Title Content and 2 Content", "objAndTwoObj" },
170 { 16, "Title, 2 Content over Content", "twoObjOverTx" }, // not exactly, but close
171 { 14, "Title, Content over Content", "objOverTx" }, // not exactly, but close
172 { 18, "Title, 4 Content", "fourObj" },
173 { 34, "Title, 6 Content", "blank" } // not defined => blank
176 int PowerPointExport::GetPPTXLayoutId(int nOffset
)
178 int nId
= LAYOUT_BLANK
;
180 SAL_INFO("sd.eppt", "GetPPTXLayoutId " << nOffset
);
185 nId
= LAYOUT_TITLE_SLIDE
;
188 nId
= LAYOUT_TITLE_CONTENT
;
191 nId
= LAYOUT_TITLE_2CONTENT
;
197 nId
= LAYOUT_TITLE_2CONTENT_CONTENT
;
200 nId
= LAYOUT_TITLE_CONTENT_2CONTENT
;
203 nId
= LAYOUT_TITLE_2CONTENT_OVER_CONTENT
;
206 nId
= LAYOUT_TITLE_CONTENT_OVER_CONTENT
;
209 nId
= LAYOUT_TITLE_4CONTENT
;
212 nId
= LAYOUT_CENTERED_TEXT
;
215 nId
= LAYOUT_TITLE_6CONTENT
;
226 PowerPointShapeExport::PowerPointShapeExport(FSHelperPtr pFS
, ShapeHashMap
* pShapeMap
,
227 PowerPointExport
* pFB
)
228 : ShapeExport(XML_p
, std::move(pFS
), pShapeMap
, pFB
)
230 , mePageType(UNDEFINED
)
235 void PowerPointShapeExport::SetMaster(bool bMaster
)
240 void PowerPointShapeExport::SetPageType(PageType ePageType
)
242 mePageType
= ePageType
;
245 ShapeExport
& PowerPointShapeExport::WriteNonVisualProperties(const Reference
< XShape
>&)
247 GetFS()->singleElementNS(XML_p
, XML_nvPr
);
252 ShapeExport
& PowerPointShapeExport::WriteTextShape(const Reference
< XShape
>& xShape
)
254 OUString sShapeType
= xShape
->getShapeType();
256 SAL_INFO("sd.eppt", "shape(text) : " << sShapeType
.toUtf8());
258 if (sShapeType
== "com.sun.star.drawing.TextShape" || sShapeType
== "com.sun.star.drawing.GraphicObjectShape")
260 ShapeExport::WriteTextShape(xShape
);
262 else if (sShapeType
== "com.sun.star.presentation.DateTimeShape")
264 if (!WritePlaceholder(xShape
, DateAndTime
, mbMaster
))
265 ShapeExport::WriteTextShape(xShape
);
267 else if (sShapeType
== "com.sun.star.presentation.FooterShape")
269 if (!WritePlaceholder(xShape
, Footer
, mbMaster
))
270 ShapeExport::WriteTextShape(xShape
);
272 else if (sShapeType
== "com.sun.star.presentation.HeaderShape")
274 if (!WritePlaceholder(xShape
, Header
, mbMaster
))
275 ShapeExport::WriteTextShape(xShape
);
277 else if (sShapeType
== "com.sun.star.presentation.NotesShape")
279 if (mePageType
== NOTICE
&& mrExport
.GetPresObj())
280 WritePlaceholderShape(xShape
, Notes
);
282 ShapeExport::WriteTextShape(xShape
);
284 else if (sShapeType
== "com.sun.star.presentation.OutlinerShape")
286 if (!WritePlaceholder(xShape
, Outliner
, mbMaster
))
287 ShapeExport::WriteTextShape(xShape
);
289 else if (sShapeType
== "com.sun.star.presentation.SlideNumberShape")
291 if (!WritePlaceholder(xShape
, SlideNumber
, mbMaster
))
292 ShapeExport::WriteTextShape(xShape
);
294 else if (sShapeType
== "com.sun.star.presentation.TitleTextShape")
296 if (!WritePlaceholder(xShape
, Title
, mbMaster
))
297 ShapeExport::WriteTextShape(xShape
);
300 SAL_WARN("sd.eppt", "PowerPointShapeExport::WriteTextShape: shape of type '" << sShapeType
<< "' is ignored");
305 ShapeExport
& PowerPointShapeExport::WriteUnknownShape(const Reference
< XShape
>& xShape
)
307 OUString sShapeType
= xShape
->getShapeType();
309 SAL_INFO("sd.eppt", "shape(unknown): " << sShapeType
.toUtf8());
311 if (sShapeType
== "com.sun.star.presentation.PageShape")
313 WritePageShape(xShape
, mePageType
, mrExport
.GetPresObj());
315 else if (sShapeType
== "com.sun.star.presentation.SubtitleShape")
317 if(mePageType
!= MASTER
)
319 if (!WritePlaceholder(xShape
, Subtitle
, mbMaster
))
320 ShapeExport::WriteTextShape(xShape
);
324 SAL_WARN("sd.eppt", "unknown shape not handled: " << sShapeType
.toUtf8());
329 PowerPointExport::PowerPointExport(const Reference
< XComponentContext
>& rContext
, const uno::Sequence
<uno::Any
>& rArguments
)
330 : XmlFilterBase(rContext
)
332 , mnLayoutFileIdMax(1)
333 , mnSlideIdMax(1 << 8)
334 , mnSlideMasterIdMax(1U << 31)
335 , mnAnimationNodeIdMax(1)
337 , mbCreateNotes(false)
339 comphelper::SequenceAsHashMap
aArgumentsMap(rArguments
);
340 mbPptm
= aArgumentsMap
.getUnpackedValueOrDefault("IsPPTM", false);
341 mbExportTemplate
= aArgumentsMap
.getUnpackedValueOrDefault("IsTemplate", false);
344 PowerPointExport::~PowerPointExport()
348 void PowerPointExport::writeDocumentProperties()
350 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(mXModel
, uno::UNO_QUERY
);
351 uno::Reference
<document::XDocumentProperties
> xDocProps
= xDPS
->getDocumentProperties();
355 bool bSecurityOptOpenReadOnly
= false;
356 uno::Reference
< lang::XMultiServiceFactory
> xFactory(mXModel
, uno::UNO_QUERY
);
357 uno::Reference
< beans::XPropertySet
> xSettings(xFactory
->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY
);
360 xSettings
->getPropertyValue("LoadReadonly") >>= bSecurityOptOpenReadOnly
;
365 exportDocumentProperties(xDocProps
, bSecurityOptOpenReadOnly
);
368 exportCustomFragments();
371 bool PowerPointExport::importDocument() throw()
376 bool PowerPointExport::exportDocument()
378 DrawingML::ResetCounters();
381 mXModel
= getModel();
383 //write document properties
384 writeDocumentProperties();
386 addRelation(oox::getRelationship(Relationship::OFFICEDOCUMENT
), "ppt/presentation.xml");
391 if (mbExportTemplate
)
393 aMediaType
= "application/vnd.ms-powerpoint.template.macroEnabled.main+xml";
397 aMediaType
= "application/vnd.ms-powerpoint.presentation.macroEnabled.main+xml";
402 if (mbExportTemplate
)
404 aMediaType
= "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml";
408 aMediaType
= "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml";
412 mPresentationFS
= openFragmentStreamWithSerializer("ppt/presentation.xml", aMediaType
);
414 addRelation(mPresentationFS
->getOutputStream(),
415 oox::getRelationship(Relationship::THEME
),
418 mPresentationFS
->startElementNS(XML_p
, XML_presentation
, PNMSS
);
420 mXStatusIndicator
= getStatusIndicator();
422 std::vector
< PropertyValue
> aProperties
;
423 PropertyValue aProperty
;
424 aProperty
.Name
= "BaseURI";
425 aProperty
.Value
<<= getFileUrl();
426 aProperties
.push_back(aProperty
);
428 exportPPT(aProperties
);
430 mPresentationFS
->singleElementNS(XML_p
, XML_sldSz
,
431 XML_cx
, OString::number(PPTtoEMU(maDestPageSize
.Width
)),
432 XML_cy
, OString::number(PPTtoEMU(maDestPageSize
.Height
)));
433 // for some reason if added before slides list it will not load the slides (alas with error reports) in mso
434 mPresentationFS
->singleElementNS(XML_p
, XML_notesSz
,
435 XML_cx
, OString::number(PPTtoEMU(maNotesPageSize
.Width
)),
436 XML_cy
, OString::number(PPTtoEMU(maNotesPageSize
.Height
)));
442 mPresentationFS
->endElementNS(XML_p
, XML_presentation
);
443 mPresentationFS
.reset();
444 // Free all FSHelperPtr, to flush data before committing storage
445 mpSlidesFSArray
.clear();
455 ::oox::ole::VbaProject
* PowerPointExport::implCreateVbaProject() const
457 return new ::oox::ole::VbaProject(getComponentContext(), getModel(), "Impress");
460 void PowerPointExport::ImplWriteBackground(const FSHelperPtr
& pFS
, const Reference
< XPropertySet
>& rXPropSet
)
462 FillStyle
aFillStyle(FillStyle_NONE
);
463 if (ImplGetPropertyValue(rXPropSet
, "FillStyle"))
466 if (aFillStyle
== FillStyle_NONE
||
467 aFillStyle
== FillStyle_HATCH
)
470 pFS
->startElementNS(XML_p
, XML_bg
);
471 pFS
->startElementNS(XML_p
, XML_bgPr
);
473 PowerPointShapeExport
aDML(pFS
, &maShapeMap
, this);
474 aDML
.SetBackgroundDark(mbIsBackgroundDark
);
475 aDML
.WriteFill(rXPropSet
);
477 pFS
->endElementNS(XML_p
, XML_bgPr
);
478 pFS
->endElementNS(XML_p
, XML_bg
);
483 <p:cNvPr id=\"1\" name=\"\"/>\
489 <a:off x=\"0\" y=\"0\"/>\
490 <a:ext cx=\"0\" cy=\"0\"/>\
491 <a:chOff x=\"0\" y=\"0\"/>\
492 <a:chExt cx=\"0\" cy=\"0\"/>\
496 const char* PowerPointExport::GetSideDirection(sal_uInt8 nDirection
)
498 const char* pDirection
= nullptr;
519 const char* PowerPointExport::GetCornerDirection(sal_uInt8 nDirection
)
521 const char* pDirection
= nullptr;
542 const char* PowerPointExport::Get8Direction(sal_uInt8 nDirection
)
544 const char* pDirection
= GetSideDirection(nDirection
);
547 pDirection
= GetCornerDirection(nDirection
);
552 void PowerPointExport::WriteTransition(const FSHelperPtr
& pFS
)
554 FadeEffect eFadeEffect
= FadeEffect_NONE
;
555 if (ImplGetPropertyValue(mXPagePropSet
, "Effect"))
556 mAny
>>= eFadeEffect
;
558 sal_Int16 nTransitionType
= 0, nTransitionSubtype
= 0;
559 sal_Int8 nPPTTransitionType
= 0;
560 sal_uInt8 nDirection
= 0;
563 OUString sSoundRelId
;
566 if (ImplGetPropertyValue(mXPagePropSet
, "TransitionType") && (mAny
>>= nTransitionType
) &&
567 ImplGetPropertyValue(mXPagePropSet
, "TransitionSubtype") && (mAny
>>= nTransitionSubtype
))
568 nPPTTransitionType
= GetTransition(nTransitionType
, nTransitionSubtype
, eFadeEffect
, nDirection
);
570 if (!nPPTTransitionType
&& eFadeEffect
!= FadeEffect_NONE
)
571 nPPTTransitionType
= GetTransition(eFadeEffect
, nDirection
);
573 if (ImplGetPropertyValue(mXPagePropSet
, "Sound") && (mAny
>>= sSoundUrl
))
574 embedEffectAudio(pFS
, sSoundUrl
, sSoundRelId
, sSoundName
);
576 bool bOOXmlSpecificTransition
= false;
578 sal_Int32 nTransition
= 0;
579 const char* pDirection
= nullptr;
580 const char* pOrientation
= nullptr;
581 const char* pThruBlk
= nullptr;
582 const char* pSpokes
= nullptr;
584 char pSpokesTmp
[2] = "0";
587 sal_Int32 nTransition14
= 0;
588 const char* pDirection14
= nullptr;
589 const char* pInverted
= nullptr;
590 const char* pPattern
= nullptr; // diamond or hexagon
593 const char* pPresetTransition
= nullptr;
595 if (!nPPTTransitionType
)
597 switch (nTransitionType
)
599 case animations::TransitionType::BARWIPE
:
601 if (nTransitionSubtype
== animations::TransitionSubType::FADEOVERCOLOR
)
603 nTransition
= XML_cut
;
605 bOOXmlSpecificTransition
= true;
609 case animations::TransitionType::MISCSHAPEWIPE
:
611 switch (nTransitionSubtype
)
613 case animations::TransitionSubType::TOPTOBOTTOM
: // Turn around
614 nTransition
= XML_fade
;
615 nTransition14
= XML_flip
;
617 bOOXmlSpecificTransition
= true;
619 case animations::TransitionSubType::BOTTOMRIGHT
: // Rochade
620 nTransition
= XML_fade
;
621 nTransition14
= XML_switch
;
623 bOOXmlSpecificTransition
= true;
625 case animations::TransitionSubType::VERTICAL
: // Vortex
626 nTransition
= XML_fade
;
627 nTransition14
= XML_vortex
;
628 bOOXmlSpecificTransition
= true;
630 case animations::TransitionSubType::HORIZONTAL
: // Ripple
631 nTransition
= XML_fade
;
632 nTransition14
= XML_ripple
;
633 bOOXmlSpecificTransition
= true;
635 case animations::TransitionSubType::LEFTTORIGHT
: // Fall
636 nTransition
= XML_fade
;
637 pPresetTransition
= "fallOver";
638 bOOXmlSpecificTransition
= true;
640 case animations::TransitionSubType::CORNERSIN
: // Inside turning cube
643 case animations::TransitionSubType::CORNERSOUT
: // Outside turning cube
644 nTransition
= XML_fade
;
645 nTransition14
= XML_prism
;
646 bOOXmlSpecificTransition
= true;
648 case animations::TransitionSubType::DIAMOND
: // Glitter
649 nTransition
= XML_fade
;
650 nTransition14
= XML_glitter
;
652 pPattern
= "hexagon";
653 bOOXmlSpecificTransition
= true;
655 case animations::TransitionSubType::HEART
: // Honeycomb
656 nTransition
= XML_fade
;
657 nTransition14
= XML_honeycomb
;
658 bOOXmlSpecificTransition
= true;
666 AnimationSpeed animationSpeed
= AnimationSpeed_MEDIUM
;
667 const char* speed
= nullptr;
668 sal_Int32 advanceTiming
= -1;
669 sal_Int32 changeType
= 0;
671 sal_Int32 nTransitionDuration
= -1;
672 bool isTransitionDurationSet
= false;
674 // try to use TransitionDuration instead of old Speed property
675 if (ImplGetPropertyValue(mXPagePropSet
, "TransitionDuration"))
677 double fTransitionDuration
= -1.0;
678 mAny
>>= fTransitionDuration
;
679 if (fTransitionDuration
>= 0)
681 nTransitionDuration
= fTransitionDuration
* 1000.0;
683 // override values because in MS formats meaning of fast/medium/slow is different
684 if (nTransitionDuration
<= 500)
689 else if (nTransitionDuration
>= 1000)
698 bool isStandardValue
= nTransitionDuration
== 500
699 || nTransitionDuration
== 750
700 || nTransitionDuration
== 1000;
703 isTransitionDurationSet
= true;
706 else if (ImplGetPropertyValue(mXPagePropSet
, "Speed"))
708 mAny
>>= animationSpeed
;
710 switch (animationSpeed
)
713 case AnimationSpeed_MEDIUM
:
716 case AnimationSpeed_SLOW
:
719 case AnimationSpeed_FAST
:
724 // check if we resolved what transition to export or time is set
725 if (!nPPTTransitionType
&& !bOOXmlSpecificTransition
&& !isTransitionDurationSet
)
728 if (ImplGetPropertyValue(mXPagePropSet
, "Change"))
731 // 1 means automatic, 2 half automatic - not sure what it means - at least I don't see it in UI
732 if (changeType
== 1 && ImplGetPropertyValue(mXPagePropSet
, "Duration"))
733 mAny
>>= advanceTiming
;
735 if (!bOOXmlSpecificTransition
)
737 switch (nPPTTransitionType
)
739 case PPT_TRANSITION_TYPE_BLINDS
:
740 nTransition
= XML_blinds
;
741 pDirection
= (nDirection
== 0) ? "vert" : "horz";
743 case PPT_TRANSITION_TYPE_CHECKER
:
744 nTransition
= XML_checker
;
745 pDirection
= (nDirection
== 1) ? "vert" : "horz";
747 case PPT_TRANSITION_TYPE_CIRCLE
:
748 nTransition
= XML_circle
;
750 case PPT_TRANSITION_TYPE_COMB
:
751 nTransition
= XML_comb
;
752 pDirection
= (nDirection
== 1) ? "vert" : "horz";
754 case PPT_TRANSITION_TYPE_COVER
:
755 nTransition
= XML_cover
;
756 pDirection
= Get8Direction(nDirection
);
758 case PPT_TRANSITION_TYPE_DIAMOND
:
759 nTransition
= XML_diamond
;
761 case PPT_TRANSITION_TYPE_DISSOLVE
:
762 nTransition
= XML_dissolve
;
764 case PPT_TRANSITION_TYPE_FADE
:
765 nTransition
= XML_fade
;
768 case PPT_TRANSITION_TYPE_SMOOTHFADE
:
769 nTransition
= XML_fade
;
771 case PPT_TRANSITION_TYPE_NEWSFLASH
:
772 nTransition
= XML_newsflash
;
774 case PPT_TRANSITION_TYPE_PLUS
:
775 nTransition
= XML_plus
;
777 case PPT_TRANSITION_TYPE_PULL
:
778 nTransition
= XML_pull
;
779 pDirection
= Get8Direction(nDirection
);
781 case PPT_TRANSITION_TYPE_PUSH
:
782 nTransition
= XML_push
;
783 pDirection
= GetSideDirection(nDirection
);
785 case PPT_TRANSITION_TYPE_RANDOM
:
786 nTransition
= XML_random
;
788 case PPT_TRANSITION_TYPE_RANDOM_BARS
:
789 nTransition
= XML_randomBar
;
790 pDirection
= (nDirection
== 1) ? "vert" : "horz";
792 case PPT_TRANSITION_TYPE_SPLIT
:
793 nTransition
= XML_split
;
794 pDirection
= (nDirection
& 1) ? "in" : "out";
795 pOrientation
= (nDirection
< 2) ? "horz" : "vert";
797 case PPT_TRANSITION_TYPE_STRIPS
:
798 nTransition
= XML_strips
;
799 pDirection
= GetCornerDirection(nDirection
);
801 case PPT_TRANSITION_TYPE_WEDGE
:
802 nTransition
= XML_wedge
;
804 case PPT_TRANSITION_TYPE_WHEEL
:
805 nTransition
= XML_wheel
;
806 if (nDirection
!= 4 && nDirection
<= 9)
808 pSpokesTmp
[0] = '0' + nDirection
;
809 pSpokes
= pSpokesTmp
;
812 case PPT_TRANSITION_TYPE_WIPE
:
813 nTransition
= XML_wipe
;
814 pDirection
= GetSideDirection(nDirection
);
816 case PPT_TRANSITION_TYPE_ZOOM
:
817 nTransition
= XML_zoom
;
818 pDirection
= (nDirection
== 1) ? "in" : "out";
820 // coverity[dead_error_line] - following conditions exist to avoid compiler warning
821 case PPT_TRANSITION_TYPE_NONE
:
828 bool isAdvanceTimingSet
= advanceTiming
!= -1;
829 if (nTransition14
|| pPresetTransition
|| isTransitionDurationSet
)
831 const char* pRequiresNS
= (nTransition14
|| isTransitionDurationSet
) ? "p14" : "p15";
833 pFS
->startElement(FSNS(XML_mc
, XML_AlternateContent
));
834 pFS
->startElement(FSNS(XML_mc
, XML_Choice
), XML_Requires
, pRequiresNS
);
836 if(isTransitionDurationSet
&& isAdvanceTimingSet
)
838 pFS
->startElementNS(XML_p
, XML_transition
,
840 XML_advTm
, OString::number(advanceTiming
* 1000),
841 FSNS(XML_p14
, XML_dur
), OString::number(nTransitionDuration
));
843 else if(isTransitionDurationSet
)
845 pFS
->startElementNS(XML_p
, XML_transition
,
847 FSNS(XML_p14
, XML_dur
), OString::number(nTransitionDuration
));
849 else if(isAdvanceTimingSet
)
851 pFS
->startElementNS(XML_p
, XML_transition
,
853 XML_advTm
, OString::number(advanceTiming
* 1000));
857 pFS
->startElementNS(XML_p
, XML_transition
, XML_spd
, speed
);
862 pFS
->singleElementNS(XML_p14
, nTransition14
,
863 XML_isInverted
, pInverted
,
864 XML_dir
, pDirection14
,
865 XML_pattern
, pPattern
);
867 else if (pPresetTransition
)
869 pFS
->singleElementNS(XML_p15
, XML_prstTrans
,
870 XML_prst
, pPresetTransition
);
872 else if (isTransitionDurationSet
&& nTransition
)
874 pFS
->singleElementNS(XML_p
, nTransition
,
876 XML_orient
, pOrientation
,
878 XML_thruBlk
, pThruBlk
);
881 if (!sSoundRelId
.isEmpty())
882 WriteSndAc(pFS
, sSoundRelId
, sSoundName
);
884 pFS
->endElement(FSNS(XML_p
, XML_transition
));
886 pFS
->endElement(FSNS(XML_mc
, XML_Choice
));
887 pFS
->startElement(FSNS(XML_mc
, XML_Fallback
));
890 pFS
->startElementNS(XML_p
, XML_transition
,
892 XML_advTm
, isAdvanceTimingSet
? OString::number(advanceTiming
* 1000).getStr() : nullptr);
896 pFS
->singleElementNS(XML_p
, nTransition
,
898 XML_orient
, pOrientation
,
900 XML_thruBlk
, pThruBlk
);
903 if (!sSoundRelId
.isEmpty())
904 WriteSndAc(pFS
, sSoundRelId
, sSoundName
);
906 pFS
->endElementNS(XML_p
, XML_transition
);
908 if (nTransition14
|| pPresetTransition
|| isTransitionDurationSet
)
910 pFS
->endElement(FSNS(XML_mc
, XML_Fallback
));
911 pFS
->endElement(FSNS(XML_mc
, XML_AlternateContent
));
915 static OUString
lcl_GetInitials(const OUString
& sName
)
919 if (!sName
.isEmpty())
921 sRet
.append(sName
[0]);
922 sal_Int32 nStart
= 0, nOffset
;
924 while ((nOffset
= sName
.indexOf(' ', nStart
)) != -1)
926 if (nOffset
+ 1 < sName
.getLength())
927 sRet
.append(sName
[ nOffset
+ 1 ]);
928 nStart
= nOffset
+ 1;
932 return sRet
.makeStringAndClear();
935 void PowerPointExport::WriteAuthors()
937 if (maAuthors
.empty())
940 FSHelperPtr pFS
= openFragmentStreamWithSerializer("ppt/commentAuthors.xml",
941 "application/vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml");
942 addRelation(mPresentationFS
->getOutputStream(),
943 oox::getRelationship(Relationship::COMMENTAUTHORS
),
944 "commentAuthors.xml");
946 pFS
->startElementNS(XML_p
, XML_cmAuthorLst
,
947 FSNS(XML_xmlns
, XML_p
), this->getNamespaceURL(OOX_NS(ppt
)).toUtf8());
949 for (const AuthorsMap::value_type
& i
: maAuthors
)
951 pFS
->singleElementNS(XML_p
, XML_cmAuthor
,
952 XML_id
, OString::number(i
.second
.nId
),
953 XML_name
, i
.first
.toUtf8(),
954 XML_initials
, lcl_GetInitials(i
.first
).toUtf8(),
955 XML_lastIdx
, OString::number(i
.second
.nLastIndex
),
956 XML_clrIdx
, OString::number(i
.second
.nId
));
959 pFS
->endElementNS(XML_p
, XML_cmAuthorLst
);
962 sal_Int32
PowerPointExport::GetAuthorIdAndLastIndex(const OUString
& sAuthor
, sal_Int32
& nLastIndex
)
964 if (maAuthors
.count(sAuthor
) <= 0)
966 struct AuthorComments aAuthorComments
;
968 aAuthorComments
.nId
= maAuthors
.size();
969 aAuthorComments
.nLastIndex
= 0;
971 maAuthors
[ sAuthor
] = aAuthorComments
;
974 nLastIndex
= ++maAuthors
[ sAuthor
].nLastIndex
;
976 return maAuthors
[ sAuthor
].nId
;
979 bool PowerPointExport::WriteComments(sal_uInt32 nPageNum
)
981 Reference
< XAnnotationAccess
> xAnnotationAccess(mXDrawPage
, uno::UNO_QUERY
);
982 if (xAnnotationAccess
.is())
984 Reference
< XAnnotationEnumeration
> xAnnotationEnumeration(xAnnotationAccess
->createAnnotationEnumeration());
986 if (xAnnotationEnumeration
->hasMoreElements())
988 FSHelperPtr pFS
= openFragmentStreamWithSerializer(OUStringBuffer()
989 .append("ppt/comments/comment")
990 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
992 .makeStringAndClear(),
993 "application/vnd.openxmlformats-officedocument.presentationml.comments+xml");
995 pFS
->startElementNS(XML_p
, XML_cmLst
,
996 FSNS(XML_xmlns
, XML_p
), this->getNamespaceURL(OOX_NS(ppt
)).toUtf8());
1000 Reference
< XAnnotation
> xAnnotation(xAnnotationEnumeration
->nextElement());
1001 DateTime
aDateTime(xAnnotation
->getDateTime());
1002 RealPoint2D
aRealPoint2D(xAnnotation
->getPosition());
1003 Reference
< XText
> xText(xAnnotation
->getTextRange());
1004 sal_Int32 nLastIndex
;
1005 sal_Int32 nId
= GetAuthorIdAndLastIndex(xAnnotation
->getAuthor(), nLastIndex
);
1006 char cDateTime
[sizeof("-32768-65535-65535T65535:65535:65535.4294967295")];
1007 // reserve enough space for hypothetical max length
1009 snprintf(cDateTime
, sizeof cDateTime
, "%02" SAL_PRIdINT32
"-%02" SAL_PRIuUINT32
"-%02" SAL_PRIuUINT32
"T%02" SAL_PRIuUINT32
":%02" SAL_PRIuUINT32
":%02" SAL_PRIuUINT32
".%09" SAL_PRIuUINT32
, sal_Int32(aDateTime
.Year
), sal_uInt32(aDateTime
.Month
), sal_uInt32(aDateTime
.Day
), sal_uInt32(aDateTime
.Hours
), sal_uInt32(aDateTime
.Minutes
), sal_uInt32(aDateTime
.Seconds
), aDateTime
.NanoSeconds
);
1011 pFS
->startElementNS(XML_p
, XML_cm
,
1012 XML_authorId
, OString::number(nId
),
1014 XML_idx
, OString::number(nLastIndex
));
1016 pFS
->singleElementNS(XML_p
, XML_pos
,
1017 XML_x
, OString::number(static_cast<sal_Int64
>((57600*aRealPoint2D
.X
+ 1270)/2540.0)),
1018 XML_y
, OString::number(static_cast<sal_Int64
>((57600*aRealPoint2D
.Y
+ 1270)/2540.0)));
1020 pFS
->startElementNS(XML_p
, XML_text
);
1021 pFS
->write(xText
->getString());
1022 pFS
->endElementNS(XML_p
, XML_text
);
1024 pFS
->endElementNS(XML_p
, XML_cm
);
1027 while (xAnnotationEnumeration
->hasMoreElements());
1029 pFS
->endElementNS(XML_p
, XML_cmLst
);
1038 void PowerPointExport::WriteVBA()
1043 uno::Reference
<document::XStorageBasedDocument
> xStorageBasedDocument(getModel(), uno::UNO_QUERY
);
1044 if (!xStorageBasedDocument
.is())
1047 uno::Reference
<embed::XStorage
> xDocumentStorage
= xStorageBasedDocument
->getDocumentStorage();
1048 OUString
aMacrosName("_MS_VBA_Macros");
1049 if (!xDocumentStorage
.is() || !xDocumentStorage
->hasByName(aMacrosName
))
1052 const sal_Int32 nOpenMode
= embed::ElementModes::READ
;
1053 uno::Reference
<io::XInputStream
> xMacrosStream(xDocumentStorage
->openStreamElement(aMacrosName
, nOpenMode
), uno::UNO_QUERY
);
1054 if (!xMacrosStream
.is())
1057 uno::Reference
<io::XOutputStream
> xOutputStream
= openFragmentStream("ppt/vbaProject.bin", "application/vnd.ms-office.vbaProject");
1058 comphelper::OStorageHelper::CopyInputToOutput(xMacrosStream
, xOutputStream
);
1060 // Write the relationship.
1061 addRelation(mPresentationFS
->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT
), "vbaProject.bin");
1064 void PowerPointExport::ImplWriteSlide(sal_uInt32 nPageNum
, sal_uInt32 nMasterNum
, sal_uInt16
/* nMode */,
1065 bool bHasBackground
, Reference
< XPropertySet
> const& aXBackgroundPropSet
)
1067 SAL_INFO("sd.eppt", "write slide: " << nPageNum
<< "\n----------------");
1071 mPresentationFS
->startElementNS(XML_p
, XML_sldIdLst
);
1073 // add explicit relation of presentation to this slide
1074 OUString sRelId
= addRelation(mPresentationFS
->getOutputStream(),
1075 oox::getRelationship(Relationship::SLIDE
),
1077 .append("slides/slide")
1078 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1080 .makeStringAndClear());
1082 mPresentationFS
->singleElementNS(XML_p
, XML_sldId
,
1083 XML_id
, OString::number(GetNewSlideId()),
1084 FSNS(XML_r
, XML_id
), sRelId
.toUtf8());
1086 if (nPageNum
== mnPages
- 1)
1087 mPresentationFS
->endElementNS(XML_p
, XML_sldIdLst
);
1089 FSHelperPtr pFS
= openFragmentStreamWithSerializer(OUStringBuffer()
1090 .append("ppt/slides/slide")
1091 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1093 .makeStringAndClear(),
1094 "application/vnd.openxmlformats-officedocument.presentationml.slide+xml");
1096 if (mpSlidesFSArray
.size() < mnPages
)
1097 mpSlidesFSArray
.resize(mnPages
);
1098 mpSlidesFSArray
[ nPageNum
] = pFS
;
1100 const char* pShow
= nullptr;
1102 if (ImplGetPropertyValue(mXPagePropSet
, "Visible"))
1105 if ((mAny
>>= bShow
) && !bShow
)
1109 pFS
->startElementNS(XML_p
, XML_sld
, PNMSS
, XML_show
, pShow
);
1111 pFS
->startElementNS(XML_p
, XML_cSld
);
1116 ImplWriteBackground(pFS
, aXBackgroundPropSet
);
1119 WriteShapeTree(pFS
, NORMAL
, false);
1121 pFS
->endElementNS(XML_p
, XML_cSld
);
1123 WriteTransition(pFS
);
1124 WriteAnimations(pFS
, mXDrawPage
, *this);
1126 pFS
->endElementNS(XML_p
, XML_sld
);
1128 // add implicit relation to slide layout
1129 addRelation(pFS
->getOutputStream(),
1130 oox::getRelationship(Relationship::SLIDELAYOUT
),
1132 .append("../slideLayouts/slideLayout")
1133 .append(GetLayoutFileId(GetPPTXLayoutId(GetLayoutOffset(mXPagePropSet
)), nMasterNum
))
1135 .makeStringAndClear());
1137 if (WriteComments(nPageNum
))
1138 // add implicit relation to slide comments
1139 addRelation(pFS
->getOutputStream(),
1140 oox::getRelationship(Relationship::COMMENTS
),
1142 .append("../comments/comment")
1143 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1145 .makeStringAndClear());
1147 SAL_INFO("sd.eppt", "----------------");
1150 void PowerPointExport::ImplWriteNotes(sal_uInt32 nPageNum
)
1152 if (!mbCreateNotes
|| !ContainsOtherShapeThanPlaceholders())
1155 SAL_INFO("sd.eppt", "write Notes " << nPageNum
<< "\n----------------");
1157 FSHelperPtr pFS
= openFragmentStreamWithSerializer(OUStringBuffer()
1158 .append("ppt/notesSlides/notesSlide")
1159 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1161 .makeStringAndClear(),
1162 "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml");
1164 pFS
->startElementNS(XML_p
, XML_notes
, PNMSS
);
1166 pFS
->startElementNS(XML_p
, XML_cSld
);
1168 WriteShapeTree(pFS
, NOTICE
, false);
1170 pFS
->endElementNS(XML_p
, XML_cSld
);
1172 pFS
->endElementNS(XML_p
, XML_notes
);
1174 // add implicit relation to slide
1175 addRelation(pFS
->getOutputStream(),
1176 oox::getRelationship(Relationship::SLIDE
),
1178 .append("../slides/slide")
1179 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1181 .makeStringAndClear());
1183 // add slide implicit relation to notes
1184 if (nPageNum
< mpSlidesFSArray
.size())
1185 addRelation(mpSlidesFSArray
[ nPageNum
]->getOutputStream(),
1186 oox::getRelationship(Relationship::NOTESSLIDE
),
1188 .append("../notesSlides/notesSlide")
1189 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1191 .makeStringAndClear());
1193 // add implicit relation to notes master
1194 addRelation(pFS
->getOutputStream(),
1195 oox::getRelationship(Relationship::NOTESMASTER
),
1196 "../notesMasters/notesMaster1.xml");
1198 SAL_INFO("sd.eppt", "-----------------");
1201 void PowerPointExport::AddLayoutIdAndRelation(const FSHelperPtr
& pFS
, sal_Int32 nLayoutFileId
)
1203 // add implicit relation of slide master to slide layout
1204 OUString sRelId
= addRelation(pFS
->getOutputStream(),
1205 oox::getRelationship(Relationship::SLIDELAYOUT
),
1207 .append("../slideLayouts/slideLayout")
1208 .append(nLayoutFileId
)
1210 .makeStringAndClear());
1212 pFS
->singleElementNS(XML_p
, XML_sldLayoutId
,
1213 XML_id
, OString::number(GetNewSlideMasterId()),
1214 FSNS(XML_r
, XML_id
), sRelId
.toUtf8());
1217 void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum
, Reference
< XPropertySet
> const& aXBackgroundPropSet
)
1219 SAL_INFO("sd.eppt", "write master slide: " << nPageNum
<< "\n--------------");
1223 mPresentationFS
->startElementNS(XML_p
, XML_sldMasterIdLst
);
1225 OUString sRelId
= addRelation(mPresentationFS
->getOutputStream(),
1226 oox::getRelationship(Relationship::SLIDEMASTER
),
1228 .append("slideMasters/slideMaster")
1229 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1231 .makeStringAndClear());
1233 mPresentationFS
->singleElementNS(XML_p
, XML_sldMasterId
,
1234 XML_id
, OString::number(GetNewSlideMasterId()),
1235 FSNS(XML_r
, XML_id
), sRelId
.toUtf8());
1237 if (nPageNum
== mnMasterPages
- 1)
1238 mPresentationFS
->endElementNS(XML_p
, XML_sldMasterIdLst
);
1241 openFragmentStreamWithSerializer(OUStringBuffer()
1242 .append("ppt/slideMasters/slideMaster")
1243 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1245 .makeStringAndClear(),
1246 "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml");
1248 // write theme per master
1249 WriteTheme(nPageNum
);
1251 // add implicit relation to the presentation theme
1252 addRelation(pFS
->getOutputStream(),
1253 oox::getRelationship(Relationship::THEME
),
1255 .append("../theme/theme")
1256 .append(static_cast<sal_Int32
>(nPageNum
) + 1)
1258 .makeStringAndClear());
1260 pFS
->startElementNS(XML_p
, XML_sldMaster
, PNMSS
);
1262 pFS
->startElementNS(XML_p
, XML_cSld
);
1264 ImplWriteBackground(pFS
, aXBackgroundPropSet
);
1265 WriteShapeTree(pFS
, MASTER
, true);
1267 pFS
->endElementNS(XML_p
, XML_cSld
);
1269 // color map - now it uses colors from hardcoded theme, once we eventually generate theme, this might need update
1270 pFS
->singleElementNS(XML_p
, XML_clrMap
,
1275 XML_accent1
, "accent1",
1276 XML_accent2
, "accent2",
1277 XML_accent3
, "accent3",
1278 XML_accent4
, "accent4",
1279 XML_accent5
, "accent5",
1280 XML_accent6
, "accent6",
1282 XML_folHlink
, "folHlink");
1284 // use master's id type as they have same range, mso does that as well
1285 pFS
->startElementNS(XML_p
, XML_sldLayoutIdLst
);
1287 for (int i
= 0; i
< LAYOUT_SIZE
; i
++)
1289 sal_Int32 nLayoutFileId
= GetLayoutFileId(i
, nPageNum
);
1290 if (nLayoutFileId
> 0)
1292 AddLayoutIdAndRelation(pFS
, nLayoutFileId
);
1296 ImplWritePPTXLayout(i
, nPageNum
);
1297 AddLayoutIdAndRelation(pFS
, GetLayoutFileId(i
, nPageNum
));
1301 pFS
->endElementNS(XML_p
, XML_sldLayoutIdLst
);
1303 pFS
->endElementNS(XML_p
, XML_sldMaster
);
1305 SAL_INFO("sd.eppt", "----------------");
1308 sal_Int32
PowerPointExport::GetLayoutFileId(sal_Int32 nOffset
, sal_uInt32 nMasterNum
)
1310 SAL_INFO("sd.eppt", "GetLayoutFileId offset: " << nOffset
<< " master: " << nMasterNum
);
1311 if (mLayoutInfo
[ nOffset
].mnFileIdArray
.size() <= nMasterNum
)
1314 return mLayoutInfo
[ nOffset
].mnFileIdArray
[ nMasterNum
];
1317 void PowerPointExport::ImplWritePPTXLayout(sal_Int32 nOffset
, sal_uInt32 nMasterNum
)
1319 SAL_INFO("sd.eppt", "write layout: " << nOffset
);
1321 Reference
< drawing::XDrawPagesSupplier
> xDPS(getModel(), uno::UNO_QUERY
);
1322 Reference
< drawing::XDrawPages
> xDrawPages
= xDPS
->getDrawPages();
1323 Reference
< drawing::XDrawPage
> xSlide
= xDrawPages
->insertNewByIndex(xDrawPages
->getCount());
1327 printf("new page created\n");
1330 Reference
< beans::XPropertySet
> xPropSet(xSlide
, uno::UNO_QUERY
);
1331 xPropSet
->setPropertyValue("Layout", makeAny(short(aLayoutInfo
[ nOffset
].nType
)));
1332 #if OSL_DEBUG_LEVEL > 1
1333 dump_pset(xPropSet
);
1335 mXPagePropSet
.set(xSlide
, UNO_QUERY
);
1338 if (mLayoutInfo
[ nOffset
].mnFileIdArray
.size() < mnMasterPages
)
1340 mLayoutInfo
[ nOffset
].mnFileIdArray
.resize(mnMasterPages
);
1343 if (mLayoutInfo
[ nOffset
].mnFileIdArray
[ nMasterNum
] != 0)
1347 = openFragmentStreamWithSerializer(OUStringBuffer()
1348 .append("ppt/slideLayouts/slideLayout")
1349 .append(mnLayoutFileIdMax
)
1351 .makeStringAndClear(),
1352 "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml");
1354 // add implicit relation of slide layout to slide master
1355 addRelation(pFS
->getOutputStream(),
1356 oox::getRelationship(Relationship::SLIDEMASTER
),
1358 .append("../slideMasters/slideMaster")
1359 .append(static_cast<sal_Int32
>(nMasterNum
) + 1)
1361 .makeStringAndClear());
1363 pFS
->startElementNS(XML_p
, XML_sldLayout
,
1365 XML_type
, aLayoutInfo
[ nOffset
].sType
,
1368 pFS
->startElementNS(XML_p
, XML_cSld
,
1369 XML_name
, aLayoutInfo
[ nOffset
].sName
);
1370 //pFS->write( MINIMAL_SPTREE ); // TODO: write actual shape tree
1371 WriteShapeTree(pFS
, LAYOUT
, true);
1373 pFS
->endElementNS(XML_p
, XML_cSld
);
1375 pFS
->endElementNS(XML_p
, XML_sldLayout
);
1377 mLayoutInfo
[ nOffset
].mnFileIdArray
[ nMasterNum
] = mnLayoutFileIdMax
;
1379 mnLayoutFileIdMax
++;
1381 xDrawPages
->remove(xSlide
);
1384 void PowerPointExport::WriteShapeTree(const FSHelperPtr
& pFS
, PageType ePageType
, bool bMaster
)
1386 PowerPointShapeExport
aDML(pFS
, &maShapeMap
, this);
1387 aDML
.SetMaster(bMaster
);
1388 aDML
.SetPageType(ePageType
);
1389 aDML
.SetBackgroundDark(mbIsBackgroundDark
);
1391 pFS
->startElementNS(XML_p
, XML_spTree
);
1392 pFS
->write(MAIN_GROUP
);
1394 ResetGroupTable(mXShapes
->getCount());
1396 while (GetNextGroupEntry())
1399 sal_uInt32 nGroups
= GetGroupsClosed();
1400 for (sal_uInt32 i
= 0; i
< nGroups
; i
++)
1402 SAL_INFO("sd.eppt", "leave group");
1405 if (GetShapeByIndex(GetCurrentGroupIndex(), true))
1407 SAL_INFO("sd.eppt", "mType: " << mType
);
1408 if (DrawingML::IsDiagram(mXShape
))
1409 WriteDiagram(pFS
, aDML
, mXShape
, mnDiagramId
++);
1411 aDML
.WriteShape(mXShape
);
1415 pFS
->endElementNS(XML_p
, XML_spTree
);
1418 ShapeExport
& PowerPointShapeExport::WritePageShape(const Reference
< XShape
>& xShape
, PageType ePageType
, bool bPresObj
)
1420 if ((ePageType
== NOTICE
&& bPresObj
) || ePageType
== LAYOUT
|| ePageType
== MASTER
)
1421 return WritePlaceholderShape(xShape
, SlideImage
);
1423 return WriteTextShape(xShape
);
1426 bool PowerPointShapeExport::WritePlaceholder(const Reference
< XShape
>& xShape
, PlaceholderType ePlaceholder
, bool bMaster
)
1428 SAL_INFO("sd.eppt", "WritePlaceholder " << bMaster
<< " " << ShapeExport::NonEmptyText(xShape
));
1429 if (bMaster
&& ShapeExport::NonEmptyText(xShape
))
1431 WritePlaceholderShape(xShape
, ePlaceholder
);
1439 ShapeExport
& PowerPointShapeExport::WritePlaceholderShape(const Reference
< XShape
>& xShape
, PlaceholderType ePlaceholder
)
1441 mpFS
->startElementNS(XML_p
, XML_sp
);
1443 // non visual shape properties
1444 mpFS
->startElementNS(XML_p
, XML_nvSpPr
);
1445 const OString
aPlaceholderID("PlaceHolder " + OString::number(mnShapeIdMax
++));
1446 WriteNonVisualDrawingProperties(xShape
, aPlaceholderID
.getStr());
1447 mpFS
->startElementNS(XML_p
, XML_cNvSpPr
);
1448 mpFS
->singleElementNS(XML_a
, XML_spLocks
, XML_noGrp
, "1");
1449 mpFS
->endElementNS(XML_p
, XML_cNvSpPr
);
1450 mpFS
->startElementNS(XML_p
, XML_nvPr
);
1452 const char* pType
= nullptr;
1453 switch (ePlaceholder
)
1483 SAL_INFO("sd.eppt", "warning: unhandled placeholder type: " << ePlaceholder
);
1485 SAL_INFO("sd.eppt", "write placeholder " << pType
);
1486 mpFS
->singleElementNS(XML_p
, XML_ph
, XML_type
, pType
);
1487 mpFS
->endElementNS(XML_p
, XML_nvPr
);
1488 mpFS
->endElementNS(XML_p
, XML_nvSpPr
);
1490 // visual shape properties
1491 mpFS
->startElementNS(XML_p
, XML_spPr
);
1492 WriteShapeTransformation(xShape
, XML_a
);
1493 WritePresetShape("rect");
1494 Reference
< XPropertySet
> xProps(xShape
, UNO_QUERY
);
1496 WriteBlipFill(xProps
, "Graphic");
1497 mpFS
->endElementNS(XML_p
, XML_spPr
);
1499 WriteTextBox(xShape
, XML_p
);
1501 mpFS
->endElementNS(XML_p
, XML_sp
);
1506 #define SYS_COLOR_SCHEMES " <a:dk1>\
1507 <a:sysClr val=\"windowText\" lastClr=\"000000\"/>\
1510 <a:sysClr val=\"window\" lastClr=\"FFFFFF\"/>\
1513 #define MINIMAL_THEME " <a:fontScheme name=\"Office\">\
1515 <a:latin typeface=\"Arial\"/>\
1516 <a:ea typeface=\"DejaVu Sans\"/>\
1517 <a:cs typeface=\"DejaVu Sans\"/>\
1520 <a:latin typeface=\"Arial\"/>\
1521 <a:ea typeface=\"DejaVu Sans\"/>\
1522 <a:cs typeface=\"DejaVu Sans\"/>\
1525 <a:fmtScheme name=\"Office\">\
1528 <a:schemeClr val=\"phClr\"/>\
1530 <a:gradFill rotWithShape=\"1\">\
1533 <a:schemeClr val=\"phClr\">\
1534 <a:tint val=\"50000\"/>\
1535 <a:satMod val=\"300000\"/>\
1538 <a:gs pos=\"35000\">\
1539 <a:schemeClr val=\"phClr\">\
1540 <a:tint val=\"37000\"/>\
1541 <a:satMod val=\"300000\"/>\
1544 <a:gs pos=\"100000\">\
1545 <a:schemeClr val=\"phClr\">\
1546 <a:tint val=\"15000\"/>\
1547 <a:satMod val=\"350000\"/>\
1551 <a:lin ang=\"16200000\" scaled=\"1\"/>\
1553 <a:gradFill rotWithShape=\"1\">\
1556 <a:schemeClr val=\"phClr\">\
1557 <a:shade val=\"51000\"/>\
1558 <a:satMod val=\"130000\"/>\
1561 <a:gs pos=\"80000\">\
1562 <a:schemeClr val=\"phClr\">\
1563 <a:shade val=\"93000\"/>\
1564 <a:satMod val=\"130000\"/>\
1567 <a:gs pos=\"100000\">\
1568 <a:schemeClr val=\"phClr\">\
1569 <a:shade val=\"94000\"/>\
1570 <a:satMod val=\"135000\"/>\
1574 <a:lin ang=\"16200000\" scaled=\"0\"/>\
1578 <a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
1580 <a:schemeClr val=\"phClr\">\
1581 <a:shade val=\"95000\"/>\
1582 <a:satMod val=\"105000\"/>\
1585 <a:prstDash val=\"solid\"/>\
1588 <a:ln w=\"25400\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
1590 <a:schemeClr val=\"phClr\"/>\
1592 <a:prstDash val=\"solid\"/>\
1595 <a:ln w=\"38100\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
1597 <a:schemeClr val=\"phClr\"/>\
1599 <a:prstDash val=\"solid\"/>\
1606 <a:outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\" rotWithShape=\"0\">\
1607 <a:srgbClr val=\"000000\">\
1608 <a:alpha val=\"38000\"/>\
1615 <a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">\
1616 <a:srgbClr val=\"000000\">\
1617 <a:alpha val=\"35000\"/>\
1624 <a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">\
1625 <a:srgbClr val=\"000000\">\
1626 <a:alpha val=\"35000\"/>\
1631 <a:camera prst=\"orthographicFront\">\
1632 <a:rot lat=\"0\" lon=\"0\" rev=\"0\"/>\
1634 <a:lightRig rig=\"threePt\" dir=\"t\">\
1635 <a:rot lat=\"0\" lon=\"0\" rev=\"1200000\"/>\
1639 <a:bevelT w=\"63500\" h=\"25400\"/>\
1642 </a:effectStyleLst>\
1645 <a:schemeClr val=\"phClr\"/>\
1647 <a:gradFill rotWithShape=\"1\">\
1650 <a:schemeClr val=\"phClr\">\
1651 <a:tint val=\"40000\"/>\
1652 <a:satMod val=\"350000\"/>\
1655 <a:gs pos=\"40000\">\
1656 <a:schemeClr val=\"phClr\">\
1657 <a:tint val=\"45000\"/>\
1658 <a:shade val=\"99000\"/>\
1659 <a:satMod val=\"350000\"/>\
1662 <a:gs pos=\"100000\">\
1663 <a:schemeClr val=\"phClr\">\
1664 <a:shade val=\"20000\"/>\
1665 <a:satMod val=\"255000\"/>\
1669 <a:path path=\"circle\">\
1670 <a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/>\
1673 <a:gradFill rotWithShape=\"1\">\
1676 <a:schemeClr val=\"phClr\">\
1677 <a:tint val=\"80000\"/>\
1678 <a:satMod val=\"300000\"/>\
1681 <a:gs pos=\"100000\">\
1682 <a:schemeClr val=\"phClr\">\
1683 <a:shade val=\"30000\"/>\
1684 <a:satMod val=\"200000\"/>\
1688 <a:path path=\"circle\">\
1689 <a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/>\
1692 </a:bgFillStyleLst>\
1695 void PowerPointExport::WriteDefaultColorSchemes(const FSHelperPtr
& pFS
)
1697 for (int nId
= PredefinedClrSchemeId::dk2
; nId
!= PredefinedClrSchemeId::Count
; nId
++)
1699 OUString sName
= PredefinedClrNames
[static_cast<PredefinedClrSchemeId
>(nId
)];
1700 sal_Int32 nColor
= 0;
1704 case PredefinedClrSchemeId::dk2
:
1707 case PredefinedClrSchemeId::lt2
:
1710 case PredefinedClrSchemeId::accent1
:
1713 case PredefinedClrSchemeId::accent2
:
1716 case PredefinedClrSchemeId::accent3
:
1719 case PredefinedClrSchemeId::accent4
:
1722 case PredefinedClrSchemeId::accent5
:
1725 case PredefinedClrSchemeId::accent6
:
1728 case PredefinedClrSchemeId::hlink
:
1731 case PredefinedClrSchemeId::folHlink
:
1736 OUString sOpenColorScheme
= OUStringBuffer()
1740 .makeStringAndClear();
1741 pFS
->write(sOpenColorScheme
);
1743 pFS
->singleElementNS(XML_a
, XML_srgbClr
, XML_val
, I32SHEX(nColor
));
1745 OUString sCloseColorScheme
= OUStringBuffer()
1749 .makeStringAndClear();
1750 pFS
->write(sCloseColorScheme
);
1754 bool PowerPointExport::WriteColorSchemes(const FSHelperPtr
& pFS
, const OUString
& rThemePath
)
1758 uno::Reference
<beans::XPropertySet
> xDocProps(getModel(), uno::UNO_QUERY
);
1761 uno::Reference
<beans::XPropertySetInfo
> xPropsInfo
= xDocProps
->getPropertySetInfo();
1763 const OUString aGrabBagPropName
= "InteropGrabBag";
1764 if (xPropsInfo
.is() && xPropsInfo
->hasPropertyByName(aGrabBagPropName
))
1766 comphelper::SequenceAsHashMap
aGrabBag(xDocProps
->getPropertyValue(aGrabBagPropName
));
1767 uno::Sequence
<beans::PropertyValue
> aCurrentTheme
;
1769 aGrabBag
.getValue(rThemePath
) >>= aCurrentTheme
;
1771 if (!aCurrentTheme
.hasElements())
1774 // Order is important
1775 for (int nId
= PredefinedClrSchemeId::dk2
; nId
!= PredefinedClrSchemeId::Count
; nId
++)
1777 OUString sName
= PredefinedClrNames
[static_cast<PredefinedClrSchemeId
>(nId
)];
1778 sal_Int32 nColor
= 0;
1780 for (auto aIt
= aCurrentTheme
.begin(); aIt
!= aCurrentTheme
.end(); aIt
++)
1782 if (aIt
->Name
== sName
)
1784 aIt
->Value
>>= nColor
;
1789 OUString sOpenColorScheme
= OUStringBuffer()
1793 .makeStringAndClear();
1794 pFS
->write(sOpenColorScheme
);
1796 pFS
->singleElementNS(XML_a
, XML_srgbClr
, XML_val
, I32SHEX(nColor
));
1798 OUString sCloseColorScheme
= OUStringBuffer()
1802 .makeStringAndClear();
1803 pFS
->write(sCloseColorScheme
);
1806 // TODO: write complete color schemes & only if successful, protection against partial export
1811 catch (const uno::Exception
&)
1813 SAL_WARN("writerfilter", "Failed to save documents grab bag");
1819 void PowerPointExport::WriteTheme(sal_Int32 nThemeNum
)
1821 OUString sThemePath
= OUStringBuffer()
1822 .append("ppt/theme/theme")
1823 .append(nThemeNum
+ 1)
1825 .makeStringAndClear();
1827 FSHelperPtr pFS
= openFragmentStreamWithSerializer(sThemePath
,
1828 "application/vnd.openxmlformats-officedocument.theme+xml");
1830 pFS
->startElementNS(XML_a
, XML_theme
,
1831 FSNS(XML_xmlns
, XML_a
), this->getNamespaceURL(OOX_NS(dml
)).toUtf8(),
1832 XML_name
, "Office Theme");
1834 pFS
->startElementNS(XML_a
, XML_themeElements
);
1835 pFS
->startElementNS(XML_a
, XML_clrScheme
, XML_name
, "Office");
1837 pFS
->write(SYS_COLOR_SCHEMES
);
1839 if (!WriteColorSchemes(pFS
, sThemePath
))
1841 // if style is not defined, try to use first one
1842 if (!WriteColorSchemes(pFS
, "ppt/theme/theme1.xml"))
1844 // color schemes are required - use default values
1845 WriteDefaultColorSchemes(pFS
);
1849 pFS
->endElementNS(XML_a
, XML_clrScheme
);
1851 // export remaining part
1852 pFS
->write(MINIMAL_THEME
);
1854 pFS
->endElementNS(XML_a
, XML_themeElements
);
1855 pFS
->endElementNS(XML_a
, XML_theme
);
1858 bool PowerPointExport::ImplCreateDocument()
1860 mbCreateNotes
= false;
1862 for (sal_uInt32 i
= 0; i
< mnPages
; i
++)
1864 if (!GetPageByIndex(i
, NOTICE
))
1867 if (ContainsOtherShapeThanPlaceholders())
1869 mbCreateNotes
= true;
1877 void PowerPointExport::WriteNotesMaster()
1879 SAL_INFO("sd.eppt", "write Notes master\n---------------");
1881 mPresentationFS
->startElementNS(XML_p
, XML_notesMasterIdLst
);
1883 OUString sRelId
= addRelation(mPresentationFS
->getOutputStream(),
1884 oox::getRelationship(Relationship::NOTESMASTER
),
1885 "notesMasters/notesMaster1.xml");
1887 mPresentationFS
->singleElementNS(XML_p
, XML_notesMasterId
,
1888 FSNS(XML_r
, XML_id
), sRelId
.toUtf8());
1890 mPresentationFS
->endElementNS(XML_p
, XML_notesMasterIdLst
);
1893 openFragmentStreamWithSerializer("ppt/notesMasters/notesMaster1.xml",
1894 "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml");
1895 // write theme per master
1896 WriteTheme(mnMasterPages
);
1898 // add implicit relation to the presentation theme
1899 addRelation(pFS
->getOutputStream(),
1900 oox::getRelationship(Relationship::THEME
),
1902 .append("../theme/theme")
1903 .append(static_cast<sal_Int32
>(mnMasterPages
) + 1)
1905 .makeStringAndClear());
1907 pFS
->startElementNS(XML_p
, XML_notesMaster
, PNMSS
);
1909 pFS
->startElementNS(XML_p
, XML_cSld
);
1911 Reference
< XPropertySet
> aXBackgroundPropSet
;
1912 if (ImplGetPropertyValue(mXPagePropSet
, "Background") &&
1913 (mAny
>>= aXBackgroundPropSet
))
1914 ImplWriteBackground(pFS
, aXBackgroundPropSet
);
1916 WriteShapeTree(pFS
, NOTICE
, true);
1918 pFS
->endElementNS(XML_p
, XML_cSld
);
1920 // color map - now it uses colors from hardcoded theme, once we eventually generate theme, this might need update
1921 pFS
->singleElementNS(XML_p
, XML_clrMap
,
1926 XML_accent1
, "accent1",
1927 XML_accent2
, "accent2",
1928 XML_accent3
, "accent3",
1929 XML_accent4
, "accent4",
1930 XML_accent5
, "accent5",
1931 XML_accent6
, "accent6",
1933 XML_folHlink
, "folHlink");
1935 pFS
->endElementNS(XML_p
, XML_notesMaster
);
1937 SAL_INFO("sd.eppt", "----------------");
1940 void PowerPointExport::embedEffectAudio(const FSHelperPtr
& pFS
, const OUString
& sUrl
, OUString
& sRelId
, OUString
& sName
)
1942 comphelper::LifecycleProxy aProxy
;
1944 if (!sUrl
.endsWithIgnoreAsciiCase(".wav"))
1947 uno::Reference
<io::XInputStream
> xAudioStream
;
1948 if (sUrl
.startsWith("vnd.sun.star.Package:"))
1950 uno::Reference
<document::XStorageBasedDocument
> xStorageBasedDocument(getModel(), uno::UNO_QUERY
);
1951 if (!xStorageBasedDocument
.is())
1954 uno::Reference
<embed::XStorage
> xDocumentStorage
= xStorageBasedDocument
->getDocumentStorage();
1955 if (!xDocumentStorage
.is())
1958 uno::Reference
<io::XStream
> xStream
= comphelper::OStorageHelper::GetStreamAtPackageURL(xDocumentStorage
, sUrl
,
1959 css::embed::ElementModes::READ
, aProxy
);
1962 xAudioStream
= xStream
->getInputStream();
1965 xAudioStream
= comphelper::OStorageHelper::GetInputStreamFromURL(sUrl
, getComponentContext());
1967 if (!xAudioStream
.is())
1970 int nLastSlash
= sUrl
.lastIndexOf('/');
1971 sName
= sUrl
.copy(nLastSlash
>= 0 ? nLastSlash
+ 1 : 0);
1973 OUString sPath
= "../media/" + sName
;
1974 sRelId
= addRelation(pFS
->getOutputStream(),
1975 oox::getRelationship(Relationship::AUDIO
), sPath
);
1977 uno::Reference
<io::XOutputStream
> xOutputStream
= openFragmentStream(sPath
.replaceAt(0, 2, "/ppt"),
1980 comphelper::OStorageHelper::CopyInputToOutput(xAudioStream
, xOutputStream
);
1983 sal_Int32
PowerPointExport::GetShapeID(const Reference
<XShape
>& rXShape
)
1985 return ShapeExport::GetShapeID(rXShape
, &maShapeMap
);
1988 sal_Int32
PowerPointExport::GetNextAnimationNodeID()
1990 return mnAnimationNodeIdMax
++;
1993 bool PowerPointExport::ImplCreateMainNotes()
2001 OUString
PowerPointExport::getImplementationName()
2003 return "com.sun.star.comp.Impress.oox.PowerPointExport";
2006 void PowerPointExport::WriteDiagram(const FSHelperPtr
& pFS
, PowerPointShapeExport
& rDML
, const css::uno::Reference
<css::drawing::XShape
>& rXShape
, int nDiagramId
)
2008 SAL_INFO("sd.eppt", "writing Diagram " + OUString::number(nDiagramId
));
2009 pFS
->startElementNS(XML_p
, XML_graphicFrame
);
2010 rDML
.WriteDiagram(rXShape
, nDiagramId
);
2011 pFS
->endElementNS(XML_p
, XML_graphicFrame
);
2015 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
2016 css_comp_Impress_oox_PowerPointExport(uno::XComponentContext
* rxCtxt
,
2017 uno::Sequence
<css::uno::Any
> const& rArguments
)
2019 return cppu::acquire(new PowerPointExport(rxCtxt
, rArguments
));
2022 #if OSL_DEBUG_LEVEL > 1
2023 void dump_pset(Reference
< XPropertySet
> const& rXPropSet
)
2025 Reference
< XPropertySetInfo
> info
= rXPropSet
->getPropertySetInfo();
2026 Sequence
< beans::Property
> props
= info
->getProperties();
2028 for (int i
=0; i
< props
.getLength(); i
++)
2030 OString name
= OUStringToOString(props
[i
].Name
, RTL_TEXTENCODING_UTF8
);
2032 Any value
= rXPropSet
->getPropertyValue(props
[i
].Name
);
2037 RectanglePoint pointValue
;
2039 if (value
>>= strValue
)
2040 SAL_INFO("sd.eppt", name
<< " = \"" << strValue
<< "\"");
2041 else if (value
>>= intValue
)
2042 SAL_INFO("sd.eppt", name
<< " = " << intValue
<< "(hex : " << std::hex
<< intValue
<< ")");
2043 else if (value
>>= boolValue
)
2044 SAL_INFO("sd.eppt", name
<< " = " << boolValue
<< " (bool)");
2045 else if (value
>>= pointValue
)
2046 SAL_INFO("sd.eppt", name
<< " = " << pointValue
<< " (RectanglePoint)");
2048 SAL_INFO("sd.eppt", "??? <unhandled type>");
2053 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */