/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <stdio.h>
#include <oox/drawingml/clrscheme.hxx>
#include <oox/token/namespaces.hxx>
#include <oox/token/tokens.hxx>
#include <oox/token/relationship.hxx>
#include <oox/ole/vbaproject.hxx>
#include "epptooxml.hxx"
#include <oox/export/shapes.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <comphelper/storagehelper.hxx>
#include <comphelper/xmltools.hxx>
#include <sax/fshelper.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <tools/UnitConversion.hxx>
#include <tools/datetime.hxx>
#include <unotools/securityoptions.hxx>
#include <com/sun/star/animations/TransitionType.hpp>
#include <com/sun/star/animations/TransitionSubType.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/XDrawPages.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/geometry/RealPoint2D.hpp>
#include <com/sun/star/office/XAnnotationEnumeration.hpp>
#include <com/sun/star/office/XAnnotationAccess.hpp>
#include <com/sun/star/presentation/AnimationSpeed.hpp>
#include <com/sun/star/util/DateTime.hpp>
#include <com/sun/star/task/XStatusIndicator.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp>
#include <com/sun/star/container/XIndexContainer.hpp>
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/presentation/XPresentationSupplier.hpp>
#include <comphelper/diagnose_ex.hxx>
#include <oox/export/utils.hxx>
#include <oox/export/ThemeExport.hxx>
#include <docmodel/theme/Theme.hxx>
#include "pptx-animations.hxx"
#include "../ppt/pptanimations.hxx"
#include <i18nlangtag/languagetag.hxx>
#include <svx/sdrmasterpagedescriptor.hxx>
#include <svx/svdpage.hxx>
#include <svx/unoapi.hxx>
#include <svx/svdogrp.hxx>
#include <svx/ColorSets.hxx>
#include <sdmod.hxx>
#include <sdpage.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/document/XStorageBasedDocument.hpp>
#include <utility>
#if OSL_DEBUG_LEVEL > 1
#include <com/sun/star/drawing/RectanglePoint.hpp>
#endif
// presentation namespaces
#define PNMSS FSNS(XML_xmlns, XML_a), this->getNamespaceURL(OOX_NS(dml)), \
FSNS(XML_xmlns, XML_p), this->getNamespaceURL(OOX_NS(ppt)), \
FSNS(XML_xmlns, XML_r), this->getNamespaceURL(OOX_NS(officeRel)), \
FSNS(XML_xmlns, XML_p14), this->getNamespaceURL(OOX_NS(p14)), \
FSNS(XML_xmlns, XML_p15), this->getNamespaceURL(OOX_NS(p15)), \
FSNS(XML_xmlns, XML_mc), this->getNamespaceURL(OOX_NS(mce))
// presentationPr namespace
#define PPRNMSS FSNS(XML_xmlns, XML_a), this->getNamespaceURL(OOX_NS(dml)), \
FSNS(XML_xmlns, XML_r), this->getNamespaceURL(OOX_NS(officeRel)), \
FSNS(XML_xmlns, XML_p), this->getNamespaceURL(OOX_NS(ppt))
using namespace ::com::sun::star;
using namespace ::com::sun::star::animations;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::geometry;
using namespace ::com::sun::star::presentation;
using namespace ::com::sun::star::office;
using namespace ::com::sun::star::text;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
using namespace ::ppt;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::beans::XPropertySetInfo;
using ::sax_fastparser::FSHelperPtr;
using namespace oox::drawingml;
using namespace oox::core;
#if OSL_DEBUG_LEVEL > 1
void dump_pset(Reference< XPropertySet > const& rXPropSet);
#endif
namespace oox::core
{
class PowerPointShapeExport : public ShapeExport
{
PowerPointExport& mrExport;
PageType mePageType;
bool mbMaster;
public:
PowerPointShapeExport(FSHelperPtr pFS, ShapeHashMap* pShapeMap, PowerPointExport* pFB);
void SetMaster(bool bMaster);
void SetPageType(PageType ePageType);
ShapeExport& WriteNonVisualProperties(const Reference< XShape >& xShape) override;
ShapeExport& WriteTextShape(const Reference< XShape >& xShape) override;
ShapeExport& WriteUnknownShape(const Reference< XShape >& xShape) override;
ShapeExport& WritePlaceholderShape(const Reference< XShape >& xShape, PlaceholderType ePlaceholder);
/** Writes a placeholder shape that references the placeholder on the master slide */
ShapeExport& WritePlaceholderReferenceShape(PlaceholderType ePlaceholder, sal_Int32 nReferencedPlaceholderIdx, PageType ePageType, const Reference<XPropertySet>& rXPagePropSet);
ShapeExport& WritePageShape(const Reference< XShape >& xShape, PageType ePageType, bool bPresObj);
/** Writes textbody of a placeholder that references the placeholder on the master slide */
ShapeExport& WritePlaceholderReferenceTextBody(PlaceholderType ePlaceholder, PageType ePageType, const Reference<XPropertySet> xPagePropSet);
// helper parts
bool WritePlaceholder(const Reference< XShape >& xShape, PlaceholderType ePlaceholder, bool bMaster);
};
namespace
{
void WriteSndAc(const FSHelperPtr& pFS, const OUString& sSoundRelId, const OUString& sSoundName)
{
pFS->startElementNS(XML_p, XML_sndAc);
pFS->startElementNS(XML_p, XML_stSnd);
pFS->singleElementNS(XML_p, XML_snd, FSNS(XML_r, XML_embed),
sax_fastparser::UseIf(sSoundRelId, !sSoundRelId.isEmpty()), XML_name,
sax_fastparser::UseIf(sSoundName, !sSoundName.isEmpty()));
pFS->endElement(FSNS(XML_p, XML_stSnd));
pFS->endElement(FSNS(XML_p, XML_sndAc));
}
const char* getPlaceholderTypeName(PlaceholderType ePlaceholder)
{
switch (ePlaceholder)
{
case SlideImage:
return "sldImg";
case Notes:
return "body";
case Header:
return "hdr";
case Footer:
return "ftr";
case SlideNumber:
return "sldNum";
case DateAndTime:
return "dt";
case Outliner:
return "body";
case Title:
return "title";
case Subtitle:
return "subTitle";
default:
SAL_INFO("sd.eppt", "warning: unhandled placeholder type: " << ePlaceholder);
return "";
}
}
}
}
namespace {
struct PPTXLayoutInfo
{
int nType;
const char* sName;
const char* sType;
};
}
const PPTXLayoutInfo aLayoutInfo[OOXML_LAYOUT_SIZE] =
{
{ 0, "Title Slide", "title" },
{ 1, "Title and text", "tx" },
{ 2, "Title and chart", "chart" },
{ 3, "Title, text on left, text on right", "twoObj" },
{ 4, "Title, text on left and chart on right", "txAndChart" },
{ 6, "Title, text on left, clip art on right", "txAndClipArt" },
{ 6, "Title, text on left, media on right", "txAndMedia" },
{ 7, "Title, chart on left and text on right", "chartAndTx" },
{ 8, "Title and table", "tbl" },
{ 9, "Title, clipart on left, text on right", "clipArtAndTx" },
{ 10, "Title, text on left, object on right", "txAndObj" },
{ 1, "Title and object", "obj" },
{ 12, "Title, text on left, two objects on right", "txAndTwoObj" },
{ 13, "Title, object on left, text on right", "objAndTx" },
{ 14, "Title, object on top, text on bottom", "objOverTx" },
{ 15, "Title, two objects on left, text on right", "twoObjAndTx" },
{ 16, "Title, two objects on top, text on bottom", "twoObjOverTx" },
{ 17, "Title, text on top, object on bottom", "txOverObj" },
{ 18, "Title and four objects", "fourObj" },
{ 19, "Title Only", "titleOnly" },
{ 20, "Blank Slide", "blank" },
{ 21, "Vertical title on right, vertical text on top, chart on bottom", "vertTitleAndTxOverChart" },
{ 22, "Vertical title on right, vertical text on left", "vertTitleAndTx" },
{ 23, "Title and vertical text body", "vertTx" },
{ 24, "Title, clip art on left, vertical text on right", "clipArtAndVertTx" },
{ 20, "Title, two objects each with text", "twoTxTwoObj" },
{ 15, "Title, two objects on left, one object on right", "twoObjAndObj" },
{ 20, "Title, object and caption text", "objTx" },
{ 20, "Title, picture, and caption text", "picTx" },
{ 20, "Section header title and subtitle text", "secHead" },
{ 32, "Object only", "objOnly" },
{ 12, "Title, one object on left, two objects on right", "objAndTwoObj" },
{ 20, "Title, media on left, text on right", "mediaAndTx" },
{ 34, "Title, 6 Content", "blank" }, // not defined in OOXML => blank
{ 2, "Title and diagram", "dgm" },
{ 0, "Custom layout defined by user", "cust" },
};
PowerPointShapeExport::PowerPointShapeExport(FSHelperPtr pFS, ShapeHashMap* pShapeMap,
PowerPointExport* pFB)
: ShapeExport(XML_p, std::move(pFS), pShapeMap, pFB)
, mrExport(*pFB)
, mePageType(UNDEFINED)
, mbMaster(false)
{
}
void PowerPointShapeExport::SetMaster(bool bMaster)
{
mbMaster = bMaster;
}
void PowerPointShapeExport::SetPageType(PageType ePageType)
{
mePageType = ePageType;
}
ShapeExport& PowerPointShapeExport::WriteNonVisualProperties(const Reference< XShape >&)
{
GetFS()->singleElementNS(XML_p, XML_nvPr);
return *this;
}
ShapeExport& PowerPointShapeExport::WriteTextShape(const Reference< XShape >& xShape)
{
OUString sShapeType = xShape->getShapeType();
SAL_INFO("sd.eppt", "shape(text) : " << sShapeType.toUtf8());
if (sShapeType == "com.sun.star.drawing.TextShape" || sShapeType == "com.sun.star.drawing.GraphicObjectShape")
{
ShapeExport::WriteTextShape(xShape);
}
else if (sShapeType == "com.sun.star.presentation.DateTimeShape")
{
if (!WritePlaceholder(xShape, DateAndTime, mbMaster))
ShapeExport::WriteTextShape(xShape);
}
else if (sShapeType == "com.sun.star.presentation.FooterShape")
{
if (!WritePlaceholder(xShape, Footer, mbMaster))
ShapeExport::WriteTextShape(xShape);
}
else if (sShapeType == "com.sun.star.presentation.HeaderShape")
{
if (!WritePlaceholder(xShape, Header, mbMaster))
ShapeExport::WriteTextShape(xShape);
}
else if (sShapeType == "com.sun.star.presentation.NotesShape")
{
if (mePageType == NOTICE && mrExport.GetPresObj())
WritePlaceholderShape(xShape, Notes);
else
ShapeExport::WriteTextShape(xShape);
}
else if (sShapeType == "com.sun.star.presentation.OutlinerShape")
{
if (!WritePlaceholder(xShape, Outliner, mbMaster))
ShapeExport::WriteTextShape(xShape);
}
else if (sShapeType == "com.sun.star.presentation.SlideNumberShape")
{
if (!WritePlaceholder(xShape, SlideNumber, mbMaster))
ShapeExport::WriteTextShape(xShape);
}
else if (sShapeType == "com.sun.star.presentation.TitleTextShape")
{
if (!WritePlaceholder(xShape, Title, mbMaster))
ShapeExport::WriteTextShape(xShape);
}
else
SAL_WARN("sd.eppt", "PowerPointShapeExport::WriteTextShape: shape of type '" << sShapeType << "' is ignored");
return *this;
}
ShapeExport& PowerPointShapeExport::WriteUnknownShape(const Reference< XShape >& xShape)
{
OUString sShapeType = xShape->getShapeType();
SAL_INFO("sd.eppt", "shape(unknown): " << sShapeType.toUtf8());
if (sShapeType == "com.sun.star.presentation.PageShape")
{
WritePageShape(xShape, mePageType, mrExport.GetPresObj());
}
else if (sShapeType == "com.sun.star.presentation.SubtitleShape")
{
if(mePageType != MASTER)
{
if (!WritePlaceholder(xShape, Subtitle, mbMaster))
ShapeExport::WriteTextShape(xShape);
}
}
else
SAL_WARN("sd.eppt", "unknown shape not handled: " << sShapeType.toUtf8());
return *this;
}
PowerPointExport::PowerPointExport(const Reference< XComponentContext >& rContext, const uno::Sequence<uno::Any>& rArguments)
: XmlFilterBase(rContext)
, mpAuthorIDs( new SvtSecurityMapPersonalInfo )
, mnLayoutFileIdMax(1)
, mnSlideIdMax(1 << 8)
, mnSlideMasterIdMax(1U << 31)
, mnAnimationNodeIdMax(1)
, mnDiagramId(1)
, mbCreateNotes(false)
, mnPlaceholderIndexMax(1)
{
comphelper::SequenceAsHashMap aArgumentsMap(rArguments);
mbPptm = aArgumentsMap.getUnpackedValueOrDefault(u"IsPPTM"_ustr, false);
mbExportTemplate = aArgumentsMap.getUnpackedValueOrDefault(u"IsTemplate"_ustr, false);
}
PowerPointExport::~PowerPointExport()
{
}
void PowerPointExport::writeDocumentProperties()
{
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(mXModel, uno::UNO_QUERY);
uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
if (xDocProps.is())
{
bool bSecurityOptOpenReadOnly = false;
uno::Reference< lang::XMultiServiceFactory > xFactory(mXModel, uno::UNO_QUERY);
uno::Reference< beans::XPropertySet > xSettings(xFactory->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY);
try
{
xSettings->getPropertyValue(u"LoadReadonly"_ustr) >>= bSecurityOptOpenReadOnly;
}
catch( Exception& )
{
}
exportDocumentProperties(xDocProps, bSecurityOptOpenReadOnly);
}
exportCustomFragments();
}
bool PowerPointExport::importDocument() noexcept
{
return false;
}
bool PowerPointExport::exportDocument()
{
drawingml::DrawingML::ResetMlCounters();
auto& rGraphicExportCache = drawingml::GraphicExportCache::get();
rGraphicExportCache.push();
maShapeMap.clear();
mXModel = getModel();
//write document properties
writeDocumentProperties();
addRelation(oox::getRelationship(Relationship::OFFICEDOCUMENT), u"ppt/presentation.xml");
OUString aMediaType;
if (mbPptm)
{
if (mbExportTemplate)
{
aMediaType = "application/vnd.ms-powerpoint.template.macroEnabled.main+xml";
}
else
{
aMediaType = "application/vnd.ms-powerpoint.presentation.macroEnabled.main+xml";
}
}
else
{
if (mbExportTemplate)
{
aMediaType = "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml";
}
else
{
aMediaType = "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml";
}
}
mPresentationFS = openFragmentStreamWithSerializer(u"ppt/presentation.xml"_ustr, aMediaType);
addRelation(mPresentationFS->getOutputStream(),
oox::getRelationship(Relationship::THEME),
u"theme/theme1.xml");
mPresentationFS->startElementNS(XML_p, XML_presentation, PNMSS);
mXStatusIndicator = getStatusIndicator();
std::vector< PropertyValue > aProperties;
PropertyValue aProperty;
aProperty.Name = "BaseURI";
aProperty.Value <<= getFileUrl();
aProperties.push_back(aProperty);
exportPPT(aProperties);
mPresentationFS->singleElementNS(XML_p, XML_sldSz,
XML_cx, OString::number(PPTtoEMU(maDestPageSize.Width)),
XML_cy, OString::number(PPTtoEMU(maDestPageSize.Height)));
// for some reason if added before slides list it will not load the slides (alas with error reports) in mso
mPresentationFS->singleElementNS(XML_p, XML_notesSz,
XML_cx, OString::number(PPTtoEMU(maNotesPageSize.Width)),
XML_cy, OString::number(PPTtoEMU(maNotesPageSize.Height)));
WriteCustomSlideShow();
WritePresentationProps();
WriteAuthors();
WriteVBA();
WriteModifyVerifier();
mPresentationFS->endElementNS(XML_p, XML_presentation);
mPresentationFS->endDocument();
mPresentationFS.reset();
// Free all FSHelperPtr, to flush data before committing storage
for (auto& serializer : mpSlidesFSArray)
{
if (!serializer)
continue;
serializer->endDocument();
}
mpSlidesFSArray.clear();
commitStorage();
rGraphicExportCache.pop();
maShapeMap.clear();
maAuthors.clear();
maRelId.clear();
return true;
}
::oox::ole::VbaProject* PowerPointExport::implCreateVbaProject() const
{
return new ::oox::ole::VbaProject(getComponentContext(), getModel(), u"Impress");
}
void PowerPointExport::WriteCustomSlideShow()
{
Reference<XCustomPresentationSupplier> aXCPSup(mXModel, css::uno::UNO_QUERY);
if (!aXCPSup.is() || !aXCPSup->getCustomPresentations()->hasElements())
return;
mPresentationFS->startElementNS(XML_p, XML_custShowLst);
Reference<XDrawPagesSupplier> xDPS(getModel(), uno::UNO_QUERY_THROW);
Reference<XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
Reference<XNameContainer> aXNameCont(aXCPSup->getCustomPresentations());
const Sequence<OUString> aNameSeq(aXNameCont->getElementNames());
OUString sRelId;
sal_uInt32 nCustomShowIndex = 0;
sal_Int32 nSlideCount = xDrawPages->getCount();
for (OUString const& customShowName : aNameSeq)
{
mPresentationFS->startElementNS(XML_p, XML_custShow, XML_name, customShowName, XML_id,
OUString::number(nCustomShowIndex++));
mAny = aXNameCont->getByName(customShowName);
Reference<XIndexContainer> aXIContainer;
if (mAny >>= aXIContainer)
{
mPresentationFS->startElementNS(XML_p, XML_sldLst);
sal_Int32 nCustomShowSlideCount = aXIContainer->getCount();
for (sal_Int32 i = 0; i < nCustomShowSlideCount; ++i)
{
Reference<XDrawPage> aXCustomShowDrawPage;
aXIContainer->getByIndex(i) >>= aXCustomShowDrawPage;
Reference<XNamed> aXName(aXCustomShowDrawPage, UNO_QUERY_THROW);
OUString sCustomShowSlideName = aXName->getName();
for (sal_Int32 j = 0; j < nSlideCount; ++j)
{
Reference<XDrawPage> xDrawPage;
xDrawPages->getByIndex(j) >>= xDrawPage;
Reference<XNamed> xNamed(xDrawPage, UNO_QUERY_THROW);
OUString sSlideName = xNamed->getName();
if (sCustomShowSlideName == sSlideName)
{
sRelId = maRelId[j];
break;
}
}
mPresentationFS->singleElementNS(XML_p, XML_sld, FSNS(XML_r, XML_id), sRelId);
}
mPresentationFS->endElementNS(XML_p, XML_sldLst);
}
mPresentationFS->endElementNS(XML_p, XML_custShow);
}
mPresentationFS->endElementNS(XML_p, XML_custShowLst);
}
void PowerPointExport::ImplWriteBackground(const FSHelperPtr& pFS, const Reference< XPropertySet >& rXPropSet)
{
FillStyle aFillStyle(FillStyle_NONE);
if (ImplGetPropertyValue(rXPropSet, u"FillStyle"_ustr))
mAny >>= aFillStyle;
if (aFillStyle == FillStyle_NONE ||
aFillStyle == FillStyle_HATCH)
return;
pFS->startElementNS(XML_p, XML_bg);
pFS->startElementNS(XML_p, XML_bgPr);
PowerPointShapeExport aDML(pFS, &maShapeMap, this);
aDML.SetBackgroundDark(mbIsBackgroundDark);
aDML.WriteFill(rXPropSet, maPageSize);
pFS->endElementNS(XML_p, XML_bgPr);
pFS->endElementNS(XML_p, XML_bg);
}
#define MAIN_GROUP \
"<p:nvGrpSpPr>\
<p:cNvPr id=\"1\" name=\"\"/>\
<p:cNvGrpSpPr/>\
<p:nvPr/>\
</p:nvGrpSpPr>\
<p:grpSpPr>\
<a:xfrm>\
<a:off x=\"0\" y=\"0\"/>\
<a:ext cx=\"0\" cy=\"0\"/>\
<a:chOff x=\"0\" y=\"0\"/>\
<a:chExt cx=\"0\" cy=\"0\"/>\
</a:xfrm>\
</p:grpSpPr>"
const char* PowerPointExport::GetSideDirection(sal_uInt8 nDirection)
{
const char* pDirection = nullptr;
switch (nDirection)
{
case 0:
pDirection = "l";
break;
case 1:
pDirection = "u";
break;
case 2:
pDirection = "r";
break;
case 3:
pDirection = "d";
break;
}
return pDirection;
}
const char* PowerPointExport::GetCornerDirection(sal_uInt8 nDirection)
{
const char* pDirection = nullptr;
switch (nDirection)
{
case 4:
pDirection = "lu";
break;
case 5:
pDirection = "ru";
break;
case 6:
pDirection = "ld";
break;
case 7:
pDirection = "rd";
break;
}
return pDirection;
}
const char* PowerPointExport::Get8Direction(sal_uInt8 nDirection)
{
const char* pDirection = GetSideDirection(nDirection);
if (!pDirection)
pDirection = GetCornerDirection(nDirection);
return pDirection;
}
void PowerPointExport::WriteTransition(const FSHelperPtr& pFS)
{
FadeEffect eFadeEffect = FadeEffect_NONE;
if (ImplGetPropertyValue(mXPagePropSet, u"Effect"_ustr))
mAny >>= eFadeEffect;
sal_Int16 nTransitionType = 0, nTransitionSubtype = 0;
sal_Int8 nPPTTransitionType = 0;
sal_uInt8 nDirection = 0;
OUString sSoundUrl;
OUString sSoundRelId;
OUString sSoundName;
if (ImplGetPropertyValue(mXPagePropSet, u"TransitionType"_ustr) && (mAny >>= nTransitionType) &&
ImplGetPropertyValue(mXPagePropSet, u"TransitionSubtype"_ustr) && (mAny >>= nTransitionSubtype))
{
// FADEOVERCOLOR with black -> fade, with white -> flash
sal_Int32 nTransitionFadeColor = 0;
if( ImplGetPropertyValue(mXPagePropSet, u"TransitionFadeColor"_ustr))
mAny >>= nTransitionFadeColor;
nPPTTransitionType = GetTransition(nTransitionType, nTransitionSubtype, eFadeEffect, nTransitionFadeColor, nDirection);
}
if (!nPPTTransitionType && eFadeEffect != FadeEffect_NONE)
nPPTTransitionType = GetTransition(eFadeEffect, nDirection);
if (ImplGetPropertyValue(mXPagePropSet, u"Sound"_ustr) && (mAny >>= sSoundUrl))
embedEffectAudio(pFS, sSoundUrl, sSoundRelId, sSoundName);
bool bOOXmlSpecificTransition = false;
sal_Int32 nTransition = 0;
const char* pDirection = nullptr;
const char* pOrientation = nullptr;
const char* pThruBlk = nullptr;
const char* pSpokes = nullptr;
char pSpokesTmp[2] = "0";
// p14
sal_Int32 nTransition14 = 0;
const char* pDirection14 = nullptr;
const char* pInverted = nullptr;
const char* pPattern = nullptr; // diamond or hexagon
//p15
const char* pPresetTransition = nullptr;
if (!nPPTTransitionType)
{
switch (nTransitionType)
{
case animations::TransitionType::BARWIPE:
{
if (nTransitionSubtype == animations::TransitionSubType::FADEOVERCOLOR)
{
nTransition = XML_cut;
pThruBlk = "true";
bOOXmlSpecificTransition = true;
}
break;
}
case animations::TransitionType::MISCSHAPEWIPE:
{
switch (nTransitionSubtype)
{
case animations::TransitionSubType::TOPTOBOTTOM: // Turn around
nTransition = XML_fade;
nTransition14 = XML_flip;
pDirection14 = "l";
bOOXmlSpecificTransition = true;
break;
case animations::TransitionSubType::BOTTOMRIGHT: // Rochade
nTransition = XML_fade;
nTransition14 = XML_switch;
pDirection14 = "r";
bOOXmlSpecificTransition = true;
break;
case animations::TransitionSubType::VERTICAL: // Vortex
nTransition = XML_fade;
nTransition14 = XML_vortex;
bOOXmlSpecificTransition = true;
break;
case animations::TransitionSubType::HORIZONTAL: // Ripple
nTransition = XML_fade;
nTransition14 = XML_ripple;
bOOXmlSpecificTransition = true;
break;
case animations::TransitionSubType::LEFTTORIGHT: // Fall
nTransition = XML_fade;
pPresetTransition = "fallOver";
bOOXmlSpecificTransition = true;
break;
case animations::TransitionSubType::CORNERSIN: // Inside turning cube
pInverted = "true";
[[fallthrough]];
case animations::TransitionSubType::CORNERSOUT: // Outside turning cube
nTransition = XML_fade;
nTransition14 = XML_prism;
bOOXmlSpecificTransition = true;
break;
case animations::TransitionSubType::DIAMOND: // Glitter
nTransition = XML_fade;
nTransition14 = XML_glitter;
pDirection14 = "l";
pPattern = "hexagon";
bOOXmlSpecificTransition = true;
break;
case animations::TransitionSubType::HEART: // Honeycomb
nTransition = XML_fade;
nTransition14 = XML_honeycomb;
bOOXmlSpecificTransition = true;
break;
}
break;
}
}
}
AnimationSpeed animationSpeed = AnimationSpeed_MEDIUM;
const char* speed = nullptr;
sal_Int32 advanceTiming = -1;
sal_Int32 changeType = 0;
sal_Int32 nTransitionDuration = -1;
bool isTransitionDurationSet = false;
// try to use TransitionDuration instead of old Speed property
if (ImplGetPropertyValue(mXPagePropSet, u"TransitionDuration"_ustr))
{
double fTransitionDuration = -1.0;
mAny >>= fTransitionDuration;
if (fTransitionDuration >= 0)
{
nTransitionDuration = fTransitionDuration * 1000.0;
// override values because in MS formats meaning of fast/medium/slow is different
if (nTransitionDuration <= 500)
{
// fast is default
speed = nullptr;
}
else if (nTransitionDuration >= 1000)
{
speed = "slow";
}
else
{
speed = "med";
}
bool isStandardValue = nTransitionDuration == 500
|| nTransitionDuration == 750
|| nTransitionDuration == 1000;
if(!isStandardValue)
isTransitionDurationSet = true;
}
}
else if (ImplGetPropertyValue(mXPagePropSet, u"Speed"_ustr))
{
mAny >>= animationSpeed;
switch (animationSpeed)
{
default:
case AnimationSpeed_MEDIUM:
speed = "med";
break;
case AnimationSpeed_SLOW:
speed = "slow";
break;
case AnimationSpeed_FAST:
break;
}
}
// check if we resolved what transition to export or time is set
if (!nPPTTransitionType && !bOOXmlSpecificTransition && !isTransitionDurationSet)
return;
if (ImplGetPropertyValue(mXPagePropSet, u"Change"_ustr))
mAny >>= changeType;
// 1 means automatic, 2 half automatic - not sure what it means - at least I don't see it in UI
if (changeType == 1 && ImplGetPropertyValue(mXPagePropSet, u"Duration"_ustr))
mAny >>= advanceTiming;
if (!bOOXmlSpecificTransition)
{
switch (nPPTTransitionType)
{
case PPT_TRANSITION_TYPE_BLINDS:
nTransition = XML_blinds;
pDirection = (nDirection == 0) ? "vert" : "horz";
break;
case PPT_TRANSITION_TYPE_CHECKER:
nTransition = XML_checker;
pDirection = (nDirection == 1) ? "vert" : "horz";
break;
case PPT_TRANSITION_TYPE_CIRCLE:
nTransition = XML_circle;
break;
case PPT_TRANSITION_TYPE_COMB:
nTransition = XML_comb;
pDirection = (nDirection == 1) ? "vert" : "horz";
break;
case PPT_TRANSITION_TYPE_COVER:
nTransition = XML_cover;
pDirection = Get8Direction(nDirection);
break;
case PPT_TRANSITION_TYPE_DIAMOND:
nTransition = XML_diamond;
break;
case PPT_TRANSITION_TYPE_DISSOLVE:
nTransition = XML_dissolve;
break;
case PPT_TRANSITION_TYPE_FADE:
nTransition = XML_fade;
pThruBlk = "true";
break;
case PPT_TRANSITION_TYPE_SMOOTHFADE:
nTransition = XML_fade;
break;
case PPT_TRANSITION_TYPE_NEWSFLASH:
nTransition = XML_newsflash;
break;
case PPT_TRANSITION_TYPE_PLUS:
nTransition = XML_plus;
break;
case PPT_TRANSITION_TYPE_PULL:
nTransition = XML_pull;
pDirection = Get8Direction(nDirection);
break;
case PPT_TRANSITION_TYPE_PUSH:
nTransition = XML_push;
pDirection = GetSideDirection(nDirection);
break;
case PPT_TRANSITION_TYPE_RANDOM:
nTransition = XML_random;
break;
case PPT_TRANSITION_TYPE_RANDOM_BARS:
nTransition = XML_randomBar;
pDirection = (nDirection == 1) ? "vert" : "horz";
break;
case PPT_TRANSITION_TYPE_SPLIT:
nTransition = XML_split;
pDirection = (nDirection & 1) ? "in" : "out";
pOrientation = (nDirection < 2) ? "horz" : "vert";
break;
case PPT_TRANSITION_TYPE_STRIPS:
nTransition = XML_strips;
pDirection = GetCornerDirection(nDirection);
break;
case PPT_TRANSITION_TYPE_WEDGE:
nTransition = XML_wedge;
break;
case PPT_TRANSITION_TYPE_WHEEL:
nTransition = XML_wheel;
if (nDirection != 4 && nDirection <= 9)
{
pSpokesTmp[0] = '0' + nDirection;
pSpokes = pSpokesTmp;
}
break;
case PPT_TRANSITION_TYPE_WIPE:
nTransition = XML_wipe;
pDirection = GetSideDirection(nDirection);
break;
case PPT_TRANSITION_TYPE_ZOOM:
nTransition = XML_zoom;
pDirection = (nDirection == 1) ? "in" : "out";
break;
case PPT_TRANSITION_TYPE_FLASH:
nTransition14 = XML_flash;
nTransition = XML_fade;
bOOXmlSpecificTransition = true;
break;
// coverity[dead_error_line] - following conditions exist to avoid compiler warning
case PPT_TRANSITION_TYPE_NONE:
default:
nTransition = 0;
break;
}
}
bool isAdvanceTimingSet = advanceTiming != -1;
if (nTransition14 || pPresetTransition || isTransitionDurationSet)
{
const char* pRequiresNS = (nTransition14 || isTransitionDurationSet) ? "p14" : "p15";
pFS->startElement(FSNS(XML_mc, XML_AlternateContent));
pFS->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, pRequiresNS);
if(isTransitionDurationSet && isAdvanceTimingSet)
{
pFS->startElementNS(XML_p, XML_transition,
XML_spd, speed,
XML_advTm, OString::number(advanceTiming * 1000),
FSNS(XML_p14, XML_dur), OString::number(nTransitionDuration));
}
else if(isTransitionDurationSet)
{
pFS->startElementNS(XML_p, XML_transition,
XML_spd, speed,
FSNS(XML_p14, XML_dur), OString::number(nTransitionDuration));
}
else if(isAdvanceTimingSet)
{
pFS->startElementNS(XML_p, XML_transition,
XML_spd, speed,
XML_advTm, OString::number(advanceTiming * 1000));
}
else
{
pFS->startElementNS(XML_p, XML_transition, XML_spd, speed);
}
if (nTransition14)
{
pFS->singleElementNS(XML_p14, nTransition14,
XML_isInverted, pInverted,
XML_dir, pDirection14,
XML_pattern, pPattern);
}
else if (pPresetTransition)
{
pFS->singleElementNS(XML_p15, XML_prstTrans,
XML_prst, pPresetTransition);
}
else if (isTransitionDurationSet && nTransition)
{
pFS->singleElementNS(XML_p, nTransition,
XML_dir, pDirection,
XML_orient, pOrientation,
XML_spokes, pSpokes,
XML_thruBlk, pThruBlk);
}
if (!sSoundRelId.isEmpty())
WriteSndAc(pFS, sSoundRelId, sSoundName);
pFS->endElement(FSNS(XML_p, XML_transition));
pFS->endElement(FSNS(XML_mc, XML_Choice));
pFS->startElement(FSNS(XML_mc, XML_Fallback));
}
pFS->startElementNS(XML_p, XML_transition,
XML_spd, speed,
XML_advTm, sax_fastparser::UseIf(OString::number(advanceTiming * 1000), isAdvanceTimingSet));
if (nTransition)
{
pFS->singleElementNS(XML_p, nTransition,
XML_dir, pDirection,
XML_orient, pOrientation,
XML_spokes, pSpokes,
XML_thruBlk, pThruBlk);
}
if (!sSoundRelId.isEmpty())
WriteSndAc(pFS, sSoundRelId, sSoundName);
pFS->endElementNS(XML_p, XML_transition);
if (nTransition14 || pPresetTransition || isTransitionDurationSet)
{
pFS->endElement(FSNS(XML_mc, XML_Fallback));
pFS->endElement(FSNS(XML_mc, XML_AlternateContent));
}
}
void PowerPointExport::WriteAuthors()
{
if (maAuthors.empty())
return;
FSHelperPtr pFS = openFragmentStreamWithSerializer(u"ppt/commentAuthors.xml"_ustr,
u"application/vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml"_ustr);
addRelation(mPresentationFS->getOutputStream(),
oox::getRelationship(Relationship::COMMENTAUTHORS),
u"commentAuthors.xml");
pFS->startElementNS(XML_p, XML_cmAuthorLst,
FSNS(XML_xmlns, XML_p), getNamespaceURL(OOX_NS(ppt)));
for (const AuthorsMap::value_type& i : maAuthors)
{
pFS->singleElementNS(XML_p, XML_cmAuthor,
XML_id, OString::number(i.second.nId),
XML_name, i.first,
XML_initials, i.second.sInitials,
XML_lastIdx, OString::number(i.second.nLastIndex),
XML_clrIdx, OString::number(i.second.nId));
}
pFS->endElementNS(XML_p, XML_cmAuthorLst);
pFS->endDocument();
}
sal_Int32 PowerPointExport::GetAuthorIdAndLastIndex(const OUString& sAuthor,
const OUString& sInitials,
sal_Int32& nLastIndex)
{
if (maAuthors.count(sAuthor) <= 0)
maAuthors.emplace(sAuthor, AuthorComments(maAuthors.size(), 0, sInitials));
nLastIndex = ++maAuthors[ sAuthor ].nLastIndex;
return maAuthors[ sAuthor ].nId;
}
void PowerPointExport::WritePresentationProps()
{
Reference<XPresentationSupplier> xPresentationSupplier(mXModel, uno::UNO_QUERY);
if (!xPresentationSupplier.is())
return;
Reference<beans::XPropertySet> xPresentationProps(xPresentationSupplier->getPresentation(),
uno::UNO_QUERY);
bool bEndlessVal = xPresentationProps->getPropertyValue(u"IsEndless"_ustr).get<bool>();
bool bChangeManually = xPresentationProps->getPropertyValue(u"IsAutomatic"_ustr).get<bool>();
OUString sFirstPage = xPresentationProps->getPropertyValue(u"FirstPage"_ustr).get<OUString>();
OUString sCustomShow = xPresentationProps->getPropertyValue(u"CustomShow"_ustr).get<OUString>();
FSHelperPtr pFS = openFragmentStreamWithSerializer(
u"ppt/presProps.xml"_ustr,
u"application/vnd.openxmlformats-officedocument.presentationml.presProps+xml"_ustr);
addRelation(mPresentationFS->getOutputStream(),
oox::getRelationship(Relationship::PRESPROPS), u"presProps.xml");
pFS->startElementNS(XML_p, XML_presentationPr, PPRNMSS);
pFS->startElementNS(XML_p, XML_showPr, XML_loop, sax_fastparser::UseIf("1", bEndlessVal),
XML_useTimings, sax_fastparser::UseIf("0", bChangeManually),
XML_showNarration, "1");
Reference<drawing::XDrawPagesSupplier> xDPS(mXModel, uno::UNO_QUERY_THROW);
Reference<drawing::XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
if (!sFirstPage.isEmpty())
{
sal_Int32 nStartSlide = 1;
sal_Int32 nEndSlide = xDrawPages->getCount();
for (sal_Int32 i = 0; i < nEndSlide; i++)
{
Reference<drawing::XDrawPage> xDrawPage;
xDrawPages->getByIndex(i) >>= xDrawPage;
Reference<container::XNamed> xNamed(xDrawPage, uno::UNO_QUERY_THROW);
if (xNamed->getName() == sFirstPage)
{
nStartSlide = i + 1;
break;
}
}
pFS->singleElementNS(XML_p, XML_sldRg, XML_st, OUString::number(nStartSlide), XML_end,
OUString::number(nEndSlide));
}
if (!sCustomShow.isEmpty())
{
css::uno::Reference<css::presentation::XCustomPresentationSupplier>
XCustPresentationSupplier(mXModel, css::uno::UNO_QUERY_THROW);
css::uno::Reference<css::container::XNameContainer> mxCustShows;
mxCustShows = XCustPresentationSupplier->getCustomPresentations();
const css::uno::Sequence<OUString> aNameSeq(mxCustShows->getElementNames());
sal_Int32 nCustShowIndex = 0;
for (sal_Int32 i = 0; i < aNameSeq.getLength(); i++)
{
if (aNameSeq[i] == sCustomShow)
{
nCustShowIndex = i;
break;
}
}
pFS->singleElementNS(XML_p, XML_custShow, XML_id, OUString::number(nCustShowIndex));
}
pFS->endElementNS(XML_p, XML_showPr);
pFS->endElementNS(XML_p, XML_presentationPr);
pFS->endDocument();
}
bool PowerPointExport::WriteComments(sal_uInt32 nPageNum)
{
Reference< XAnnotationAccess > xAnnotationAccess(mXDrawPage, uno::UNO_QUERY);
if (xAnnotationAccess.is())
{
Reference< XAnnotationEnumeration > xAnnotationEnumeration(xAnnotationAccess->createAnnotationEnumeration());
if (xAnnotationEnumeration->hasMoreElements())
{
bool bRemoveCommentAuthorDates
= SvtSecurityOptions::IsOptionSet(
SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo)
&& !SvtSecurityOptions::IsOptionSet(
SvtSecurityOptions::EOption::DocWarnKeepNoteAuthorDateInfo);
FSHelperPtr pFS = openFragmentStreamWithSerializer(
"ppt/comments/comment" + OUString::number(nPageNum + 1) + ".xml",
u"application/vnd.openxmlformats-officedocument.presentationml.comments+xml"_ustr);
pFS->startElementNS(XML_p, XML_cmLst,
FSNS(XML_xmlns, XML_p), this->getNamespaceURL(OOX_NS(ppt)));
do
{
Reference< XAnnotation > xAnnotation(xAnnotationEnumeration->nextElement());
util::DateTime aDateTime(xAnnotation->getDateTime());
RealPoint2D aRealPoint2D(xAnnotation->getPosition());
Reference< XText > xText(xAnnotation->getTextRange());
sal_Int32 nLastIndex;
OUString sAuthor(bRemoveCommentAuthorDates
? "Author"
+ OUString::number(GetInfoID(xAnnotation->getAuthor()))
: xAnnotation->getAuthor());
OUString sInitials(bRemoveCommentAuthorDates
? "A" + OUString::number(GetInfoID(xAnnotation->getAuthor()))
: xAnnotation->getInitials());
sal_Int32 nId = GetAuthorIdAndLastIndex(sAuthor, sInitials, nLastIndex);
char cDateTime[sizeof("-32768-65535-65535T65535:65535:65535.4294967295")];
// reserve enough space for hypothetical max length
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);
util::DateTime aEmptyDate;
if (bRemoveCommentAuthorDates || aDateTime == aEmptyDate)
{
pFS->startElementNS(XML_p, XML_cm,
XML_authorId, OString::number(nId),
XML_idx, OString::number(nLastIndex));
}
else
{
pFS->startElementNS(XML_p, XML_cm,
XML_authorId, OString::number(nId),
XML_dt, cDateTime,
XML_idx, OString::number(nLastIndex));
}
pFS->singleElementNS(XML_p, XML_pos,
XML_x, OString::number(std::round(convertMm100ToMasterUnit(aRealPoint2D.X * 100))),
XML_y, OString::number(std::round(convertMm100ToMasterUnit(aRealPoint2D.Y * 100))));
pFS->startElementNS(XML_p, XML_text);
pFS->write(xText->getString());
pFS->endElementNS(XML_p, XML_text);
pFS->endElementNS(XML_p, XML_cm);
}
while (xAnnotationEnumeration->hasMoreElements());
pFS->endElementNS(XML_p, XML_cmLst);
pFS->endDocument();
return true;
}
}
return false;
}
void PowerPointExport::WriteVBA()
{
if (!mbPptm)
return;
uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(getModel(), uno::UNO_QUERY);
if (!xStorageBasedDocument.is())
return;
uno::Reference<embed::XStorage> xDocumentStorage = xStorageBasedDocument->getDocumentStorage();
OUString aMacrosName(u"_MS_VBA_Macros"_ustr);
if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aMacrosName))
return;
const sal_Int32 nOpenMode = embed::ElementModes::READ;
uno::Reference<io::XInputStream> xMacrosStream(xDocumentStorage->openStreamElement(aMacrosName, nOpenMode), uno::UNO_QUERY);
if (!xMacrosStream.is())
return;
uno::Reference<io::XOutputStream> xOutputStream = openFragmentStream(u"ppt/vbaProject.bin"_ustr, u"application/vnd.ms-office.vbaProject"_ustr);
comphelper::OStorageHelper::CopyInputToOutput(xMacrosStream, xOutputStream);
// Write the relationship.
addRelation(mPresentationFS->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), u"vbaProject.bin");
}
void PowerPointExport::WriteModifyVerifier()
{
Sequence<PropertyValue> aInfo;
try
{
Reference<lang::XMultiServiceFactory> xFactory(mXModel, UNO_QUERY);
Reference<XPropertySet> xDocSettings(
xFactory->createInstance(u"com.sun.star.document.Settings"_ustr), UNO_QUERY);
xDocSettings->getPropertyValue(u"ModifyPasswordInfo"_ustr) >>= aInfo;
}
catch (const Exception&)
{
}
if (aInfo.hasElements())
{
OUString sAlgorithm, sSalt, sHash;
sal_Int32 nCount = 0;
for (auto& prop : aInfo)
{
if (prop.Name == "algorithm-name")
prop.Value >>= sAlgorithm;
else if (prop.Name == "salt")
prop.Value >>= sSalt;
else if (prop.Name == "iteration-count")
prop.Value >>= nCount;
else if (prop.Name == "hash")
prop.Value >>= sHash;
}
if (!sAlgorithm.isEmpty() && !sSalt.isEmpty() && !sHash.isEmpty())
{
sal_Int32 nAlgorithmSid = 0;
if (sAlgorithm == "MD2")
nAlgorithmSid = 1;
else if (sAlgorithm == "MD4")
nAlgorithmSid = 2;
else if (sAlgorithm == "MD5")
nAlgorithmSid = 3;
else if (sAlgorithm == "SHA-1")
nAlgorithmSid = 4;
else if (sAlgorithm == "MAC")
nAlgorithmSid = 5;
else if (sAlgorithm == "RIPEMD")
nAlgorithmSid = 6;
else if (sAlgorithm == "RIPEMD-160")
nAlgorithmSid = 7;
else if (sAlgorithm == "HMAC")
nAlgorithmSid = 9;
else if (sAlgorithm == "SHA-256")
nAlgorithmSid = 12;
else if (sAlgorithm == "SHA-384")
nAlgorithmSid = 13;
else if (sAlgorithm == "SHA-512")
nAlgorithmSid = 14;
if (nAlgorithmSid != 0)
mPresentationFS->singleElementNS(XML_p, XML_modifyVerifier,
XML_cryptProviderType, "rsaAES",
XML_cryptAlgorithmClass, "hash",
XML_cryptAlgorithmType, "typeAny",
XML_cryptAlgorithmSid, OString::number(nAlgorithmSid),
XML_spinCount, OString::number(nCount),
XML_saltData, sSalt,
XML_hashData, sHash);
}
}
}
void PowerPointExport::ImplWriteSlide(sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 /* nMode */,
bool bHasBackground, Reference< XPropertySet > const& aXBackgroundPropSet)
{
SAL_INFO("sd.eppt", "write slide: " << nPageNum << "\n----------------");
// slides list
if (nPageNum == 0)
mPresentationFS->startElementNS(XML_p, XML_sldIdLst);
// add explicit relation of presentation to this slide
OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
oox::getRelationship(Relationship::SLIDE),
Concat2View("slides/slide" + OUString::number(nPageNum + 1) +".xml"));
mPresentationFS->singleElementNS(XML_p, XML_sldId,
XML_id, OString::number(GetNewSlideId()),
FSNS(XML_r, XML_id), sRelId);
maRelId.push_back(sRelId);
if (nPageNum == mnPages - 1)
mPresentationFS->endElementNS(XML_p, XML_sldIdLst);
FSHelperPtr pFS = openFragmentStreamWithSerializer(
"ppt/slides/slide" + OUString::number(nPageNum + 1) + ".xml",
u"application/vnd.openxmlformats-officedocument.presentationml.slide+xml"_ustr);
if (mpSlidesFSArray.size() < mnPages)
mpSlidesFSArray.resize(mnPages);
mpSlidesFSArray[ nPageNum ] = pFS;
const char* pShow = nullptr;
const char* pShowMasterShape = nullptr;
if (ImplGetPropertyValue(mXPagePropSet, u"Visible"_ustr))
{
bool bShow(false);
if ((mAny >>= bShow) && !bShow)
pShow = "0";
}
if (ImplGetPropertyValue(mXPagePropSet, u"IsBackgroundObjectsVisible"_ustr))
{
bool bShowMasterShape(false);
if ((mAny >>= bShowMasterShape) && !bShowMasterShape)
pShowMasterShape = "0";
}
pFS->startElementNS(XML_p, XML_sld, PNMSS, XML_show, pShow, XML_showMasterSp, pShowMasterShape);
pFS->startElementNS(XML_p, XML_cSld);
// background
if (bHasBackground)
{
ImplWriteBackground(pFS, aXBackgroundPropSet);
}
WriteShapeTree(pFS, NORMAL, false);
pFS->endElementNS(XML_p, XML_cSld);
WriteTransition(pFS);
WriteAnimations(pFS, mXDrawPage, *this);
pFS->endElementNS(XML_p, XML_sld);
// add implicit relation to slide layout
addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::SLIDELAYOUT),
Concat2View("../slideLayouts/slideLayout" +
OUString::number(GetLayoutFileId(GetLayoutOffset(mXPagePropSet), nMasterNum)) +
".xml"));
if (WriteComments(nPageNum))
// add implicit relation to slide comments
addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::COMMENTS),
Concat2View("../comments/comment" + OUString::number(nPageNum + 1) + ".xml"));
SAL_INFO("sd.eppt", "----------------");
}
void PowerPointExport::ImplWriteNotes(sal_uInt32 nPageNum)
{
if (!mbCreateNotes || !ContainsOtherShapeThanPlaceholders())
return;
SAL_INFO("sd.eppt", "write Notes " << nPageNum << "\n----------------");
FSHelperPtr pFS = openFragmentStreamWithSerializer(
"ppt/notesSlides/notesSlide" +
OUString::number(nPageNum + 1) +
".xml",
u"application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml"_ustr);
pFS->startElementNS(XML_p, XML_notes, PNMSS);
pFS->startElementNS(XML_p, XML_cSld);
WriteShapeTree(pFS, NOTICE, false);
pFS->endElementNS(XML_p, XML_cSld);
pFS->endElementNS(XML_p, XML_notes);
// add implicit relation to slide
addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::SLIDE),
Concat2View("../slides/slide" + OUString::number(nPageNum + 1) + ".xml"));
// add slide implicit relation to notes
if (nPageNum < mpSlidesFSArray.size())
addRelation(mpSlidesFSArray[ nPageNum ]->getOutputStream(),
oox::getRelationship(Relationship::NOTESSLIDE),
Concat2View("../notesSlides/notesSlide" + OUString::number(nPageNum + 1) + ".xml"));
// add implicit relation to notes master
addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::NOTESMASTER),
u"../notesMasters/notesMaster1.xml");
SAL_INFO("sd.eppt", "-----------------");
pFS->endDocument();
}
void PowerPointExport::AddLayoutIdAndRelation(const FSHelperPtr& pFS, sal_Int32 nLayoutFileId)
{
// add implicit relation of slide master to slide layout
OUString sRelId = addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::SLIDELAYOUT),
Concat2View("../slideLayouts/slideLayout" + OUString::number(nLayoutFileId) + ".xml"));
pFS->singleElementNS(XML_p, XML_sldLayoutId,
XML_id, OString::number(GetNewSlideMasterId()),
FSNS(XML_r, XML_id), sRelId);
}
void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPropertySet > const& aXBackgroundPropSet)
{
SAL_INFO("sd.eppt", "write master slide: " << nPageNum << "\n--------------");
// slides list
if (nPageNum == 0)
mPresentationFS->startElementNS(XML_p, XML_sldMasterIdLst);
OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
oox::getRelationship(Relationship::SLIDEMASTER),
Concat2View("slideMasters/slideMaster" + OUString::number(nPageNum + 1) + ".xml"));
mPresentationFS->singleElementNS(XML_p, XML_sldMasterId,
XML_id, OString::number(GetNewSlideMasterId()),
FSNS(XML_r, XML_id), sRelId);
if (nPageNum == mnMasterPages - 1)
mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst);
FSHelperPtr pFS =
openFragmentStreamWithSerializer("ppt/slideMasters/slideMaster" +
OUString::number(nPageNum + 1) + ".xml",
u"application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"_ustr);
SdrPage* pMasterPage = SdPage::getImplementation(mXDrawPage);
model::Theme* pTheme = nullptr;
if (pMasterPage)
{
pTheme = pMasterPage->getSdrPageProperties().getTheme().get();
}
// write theme per master
WriteTheme(nPageNum, pTheme);
// add implicit relation to the presentation theme
addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::THEME),
Concat2View("../theme/theme" + OUString::number(nPageNum + 1) + ".xml"));
pFS->startElementNS(XML_p, XML_sldMaster, PNMSS);
pFS->startElementNS(XML_p, XML_cSld);
if (aXBackgroundPropSet)
ImplWriteBackground(pFS, aXBackgroundPropSet);
WriteShapeTree(pFS, MASTER, true);
pFS->endElementNS(XML_p, XML_cSld);
css::uno::Reference< css::beans::XPropertySet > xDocPropSet(getModel(), uno::UNO_QUERY);
if (xDocPropSet.is())
{
uno::Sequence<beans::PropertyValue> aGrabBag;
if (xDocPropSet->getPropertySetInfo()->hasPropertyByName(u"InteropGrabBag"_ustr))
xDocPropSet->getPropertyValue(u"InteropGrabBag"_ustr) >>= aGrabBag;
std::vector<OUString> aClrMap;
aClrMap.reserve(12);
uno::Sequence<beans::PropertyValue> aClrMapPropValue;
if(aGrabBag.hasElements())
{
for (const auto& rProp : aGrabBag)
{
if (rProp.Name == "OOXColorMap")
{
rProp.Value >>= aClrMapPropValue;
break;
}
}
}
if (aClrMapPropValue.getLength())
{
OUString sName;
sal_Int32 nToken = XML_TOKEN_INVALID;
for(const auto& item : aClrMapPropValue)
{
item.Value >>= nToken;
switch (nToken)
{
case XML_dk1: sName = u"dk1"_ustr; break;
case XML_lt1: sName = u"lt1"_ustr; break;
case XML_dk2: sName = u"dk2"_ustr; break;
case XML_lt2: sName = u"lt2"_ustr; break;
case XML_accent1: sName = u"accent1"_ustr; break;
case XML_accent2: sName = u"accent2"_ustr; break;
case XML_accent3: sName = u"accent3"_ustr; break;
case XML_accent4: sName = u"accent4"_ustr; break;
case XML_accent5: sName = u"accent5"_ustr; break;
case XML_accent6: sName = u"accent6"_ustr; break;
case XML_hlink: sName = u"hlink"_ustr; break;
case XML_folHlink: sName = u"folHlink"_ustr; break;
}
aClrMap.push_back(sName);
}
assert(aClrMap.size() == 12 && "missing entries for ClrMap");
}
else
{
// default clrMap to export ".odp" files to ".pptx"
aClrMap = { u"lt1"_ustr, u"dk1"_ustr, u"lt2"_ustr, u"dk2"_ustr,
u"accent1"_ustr, u"accent2"_ustr, u"accent3"_ustr, u"accent4"_ustr,
u"accent5"_ustr, u"accent6"_ustr, u"hlink"_ustr, u"folHlink"_ustr };
}
pFS->singleElementNS(XML_p, XML_clrMap,
XML_bg1, aClrMap[0],
XML_tx1, aClrMap[1],
XML_bg2, aClrMap[2],
XML_tx2, aClrMap[3],
XML_accent1, aClrMap[4],
XML_accent2, aClrMap[5],
XML_accent3, aClrMap[6],
XML_accent4, aClrMap[7],
XML_accent5, aClrMap[8],
XML_accent6, aClrMap[9],
XML_hlink, aClrMap[10],
XML_folHlink, aClrMap[11]);
}
// use master's id type as they have same range, mso does that as well
pFS->startElementNS(XML_p, XML_sldLayoutIdLst);
auto getLayoutsUsedForMaster = [](SdrPage* pMaster) -> std::unordered_set<sal_Int32>
{
if (!pMaster)
return {};
std::unordered_set<sal_Int32> aUsedLayouts{};
for (const auto* pPageUser : pMaster->GetPageUsers())
{
const auto* pMasterPageDescriptor
= dynamic_cast<const sdr::MasterPageDescriptor*>(pPageUser);
if (!pMasterPageDescriptor)
continue;
AutoLayout eLayout
= static_cast<SdPage&>(pMasterPageDescriptor->GetOwnerPage()).GetAutoLayout();
aUsedLayouts.insert(eLayout);
}
return aUsedLayouts;
};
std::unordered_set<sal_Int32> aLayouts = getLayoutsUsedForMaster(pMasterPage);
css::uno::Reference< css::beans::XPropertySet > xPagePropSet;
xPagePropSet.set(mXDrawPage, UNO_QUERY);
if (xPagePropSet.is())
{
uno::Any aAny;
if (GetPropertyValue(aAny, xPagePropSet, u"SlideLayout"_ustr))
aLayouts.insert(aAny.get<sal_Int32>());
}
OUString aSlideName;
Reference< XNamed > xNamed(mXDrawPage, UNO_QUERY);
if (xNamed.is())
aSlideName = xNamed->getName();
for (auto nLayout : aLayouts)
{
ImplWritePPTXLayout(nLayout, nPageNum, aSlideName);
AddLayoutIdAndRelation(pFS, GetLayoutFileId(nLayout, nPageNum));
}
pFS->endElementNS(XML_p, XML_sldLayoutIdLst);
pFS->endElementNS(XML_p, XML_sldMaster);
SAL_INFO("sd.eppt", "----------------");
pFS->endDocument();
}
sal_Int32 PowerPointExport::GetLayoutFileId(sal_Int32 nOffset, sal_uInt32 nMasterNum)
{
SAL_INFO("sd.eppt", "GetLayoutFileId offset: " << nOffset << " master: " << nMasterNum);
if (mLayoutInfo[ nOffset ].mnFileIdArray.size() <= nMasterNum)
return 0;
return mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ];
}
void PowerPointExport::ImplWritePPTXLayout(sal_Int32 nOffset, sal_uInt32 nMasterNum, const OUString& aSlideName)
{
SAL_INFO("sd.eppt", "write layout: " << nOffset);
Reference< drawing::XDrawPagesSupplier > xDPS(getModel(), uno::UNO_QUERY);
Reference< drawing::XDrawPages > xDrawPages = xDPS->getDrawPages();
Reference< drawing::XDrawPage > xSlide = xDrawPages->insertNewByIndex(xDrawPages->getCount());
#if OSL_DEBUG_LEVEL >= 2
if (xSlide.is())
printf("new page created\n");
#endif
Reference< beans::XPropertySet > xPropSet(xSlide, uno::UNO_QUERY);
xPropSet->setPropertyValue(u"Layout"_ustr, Any(short(aLayoutInfo[ nOffset ].nType)));
#if OSL_DEBUG_LEVEL > 1
dump_pset(xPropSet);
#endif
mXPagePropSet.set(xSlide, UNO_QUERY);
mXShapes = xSlide;
if (mLayoutInfo[ nOffset ].mnFileIdArray.size() < mnMasterPages)
{
mLayoutInfo[ nOffset ].mnFileIdArray.resize(mnMasterPages);
}
if (mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ] != 0)
return;
FSHelperPtr pFS
= openFragmentStreamWithSerializer("ppt/slideLayouts/slideLayout" +
OUString::number(mnLayoutFileIdMax) + ".xml",
u"application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"_ustr);
// add implicit relation of slide layout to slide master
addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::SLIDEMASTER),
Concat2View("../slideMasters/slideMaster" + OUString::number(nMasterNum + 1) + ".xml"));
pFS->startElementNS(XML_p, XML_sldLayout,
PNMSS,
XML_type, aLayoutInfo[ nOffset ].sType,
XML_preserve, "1");
if (!aSlideName.isEmpty())
{
pFS->startElementNS(XML_p, XML_cSld,
XML_name, aSlideName);
}
else
{
pFS->startElementNS(XML_p, XML_cSld,
XML_name, aLayoutInfo[nOffset].sName);
}
//pFS->write( MINIMAL_SPTREE ); // TODO: write actual shape tree
WriteShapeTree(pFS, LAYOUT, true);
pFS->endElementNS(XML_p, XML_cSld);
pFS->endElementNS(XML_p, XML_sldLayout);
mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ] = mnLayoutFileIdMax;
mnLayoutFileIdMax ++;
xDrawPages->remove(xSlide);
pFS->endDocument();
}
void PowerPointExport::WriteShapeTree(const FSHelperPtr& pFS, PageType ePageType, bool bMaster)
{
PowerPointShapeExport aDML(pFS, &maShapeMap, this);
aDML.SetMaster(bMaster);
aDML.SetPageType(ePageType);
aDML.SetBackgroundDark(mbIsBackgroundDark);
pFS->startElementNS(XML_p, XML_spTree);
pFS->write(MAIN_GROUP);
ResetGroupTable(mXShapes->getCount());
while (GetNextGroupEntry())
{
sal_uInt32 nGroups = GetGroupsClosed();
for (sal_uInt32 i = 0; i < nGroups; i++)
{
SAL_INFO("sd.eppt", "leave group");
}
if (GetShapeByIndex(GetCurrentGroupIndex(), true))
{
SAL_INFO("sd.eppt", "mType: " << mType);
const SdrObjGroup* pDiagramCandidate(dynamic_cast<const SdrObjGroup*>(SdrObject::getSdrObjectFromXShape(mXShape)));
const bool bIsDiagram(nullptr != pDiagramCandidate && pDiagramCandidate->isDiagram());
if (bIsDiagram)
WriteDiagram(pFS, aDML, mXShape, mnDiagramId++);
else
aDML.WriteShape(mXShape);
}
}
if ( ePageType == NORMAL || ePageType == LAYOUT )
WritePlaceholderReferenceShapes(aDML, ePageType);
pFS->endElementNS(XML_p, XML_spTree);
}
ShapeExport& PowerPointShapeExport::WritePageShape(const Reference< XShape >& xShape, PageType ePageType, bool bPresObj)
{
if ((ePageType == NOTICE && bPresObj) || ePageType == LAYOUT || ePageType == MASTER)
return WritePlaceholderShape(xShape, SlideImage);
return WriteTextShape(xShape);
}
bool PowerPointShapeExport::WritePlaceholder(const Reference< XShape >& xShape, PlaceholderType ePlaceholder, bool bMaster)
{
SAL_INFO("sd.eppt", "WritePlaceholder " << bMaster << " " << ShapeExport::NonEmptyText(xShape));
if (!xShape)
return false;
try
{
Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
if (xShapeProps->getPropertyValue(u"IsPresentationObject"_ustr).get<bool>())
{
WritePlaceholderShape(xShape, ePlaceholder);
return true;
}
}
catch (Exception&)
{
return false;
}
return false;
}
ShapeExport& PowerPointShapeExport::WritePlaceholderShape(const Reference< XShape >& xShape, PlaceholderType ePlaceholder)
{
Reference<XPropertySet> xProps(xShape, UNO_QUERY);
bool bUseBackground(false);
if (xProps.is() && xProps->getPropertySetInfo()->hasPropertyByName(u"FillUseSlideBackground"_ustr))
xProps->getPropertyValue(u"FillUseSlideBackground"_ustr) >>= bUseBackground;
if (bUseBackground)
mpFS->startElementNS(XML_p, XML_sp, XML_useBgFill, "1");
else
mpFS->startElementNS(XML_p, XML_sp);
// non visual shape properties
mpFS->startElementNS(XML_p, XML_nvSpPr);
const OString aPlaceholderID("PlaceHolder " + OString::number(mnShapeIdMax++));
WriteNonVisualDrawingProperties(xShape, aPlaceholderID.getStr());
mpFS->startElementNS(XML_p, XML_cNvSpPr);
mpFS->singleElementNS(XML_a, XML_spLocks, XML_noGrp, "1");
mpFS->endElementNS(XML_p, XML_cNvSpPr);
mpFS->startElementNS(XML_p, XML_nvPr);
bool bUsePlaceholderIndex
= ePlaceholder == Footer || ePlaceholder == DateAndTime || ePlaceholder == SlideNumber;
const char* pType = getPlaceholderTypeName(ePlaceholder);
SAL_INFO("sd.eppt", "write placeholder " << pType);
if (bUsePlaceholderIndex)
{
mpFS->singleElementNS(
XML_p, XML_ph, XML_type, pType, XML_idx,
OString::number(
static_cast<PowerPointExport*>(GetFB())->CreateNewPlaceholderIndex(xShape)));
}
else
{
if ((mePageType == PageType::LAYOUT || mePageType == PageType::NORMAL)
&& ePlaceholder == Outliner)
mpFS->singleElementNS(XML_p, XML_ph);
else
mpFS->singleElementNS(XML_p, XML_ph, XML_type, pType);
}
mpFS->endElementNS(XML_p, XML_nvPr);
mpFS->endElementNS(XML_p, XML_nvSpPr);
// visual shape properties
mpFS->startElementNS(XML_p, XML_spPr);
WriteShapeTransformation(xShape, XML_a);
WritePresetShape("rect"_ostr);
if (xProps.is())
{
WriteBlipFill(xProps, u"Graphic"_ustr);
// Do not forget to export the visible properties.
WriteFill( xProps, xShape->getSize());
WriteOutline( xProps );
WriteShapeEffects( xProps );
bool bHas3DEffectinShape = false;
uno::Sequence<beans::PropertyValue> grabBag;
if (xProps->getPropertySetInfo()->hasPropertyByName(u"InteropGrabBag"_ustr))
xProps->getPropertyValue(u"InteropGrabBag"_ustr) >>= grabBag;
for (auto const& it : grabBag)
if (it.Name == "3DEffectProperties")
bHas3DEffectinShape = true;
if( bHas3DEffectinShape)
Write3DEffects( xProps, /*bIsText=*/false );
}
mpFS->endElementNS(XML_p, XML_spPr);
WriteTextBox(xShape, XML_p, /*bWritePropertiesAsLstStyles=*/bUsePlaceholderIndex);
mpFS->endElementNS(XML_p, XML_sp);
return *this;
}
ShapeExport& PowerPointShapeExport::WritePlaceholderReferenceShape(
PlaceholderType ePlaceholder, sal_Int32 nReferencedPlaceholderIdx, PageType ePageType,
const Reference<XPropertySet>& rXPagePropSet)
{
mpFS->startElementNS(XML_p, XML_sp);
// non visual shape properties
mpFS->startElementNS(XML_p, XML_nvSpPr);
const OString aPlaceholderID("PlaceHolder " + OString::number(mnShapeIdMax++));
GetFS()->singleElementNS(XML_p, XML_cNvPr, XML_id, OString::number(mnShapeIdMax), XML_name,
aPlaceholderID);
mpFS->startElementNS(XML_p, XML_cNvSpPr);
mpFS->singleElementNS(XML_a, XML_spLocks, XML_noGrp, "1");
mpFS->endElementNS(XML_p, XML_cNvSpPr);
mpFS->startElementNS(XML_p, XML_nvPr);
const char* pType = getPlaceholderTypeName(ePlaceholder);
mpFS->singleElementNS(XML_p, XML_ph, XML_type, pType, XML_idx,
OString::number(nReferencedPlaceholderIdx));
mpFS->endElementNS(XML_p, XML_nvPr);
mpFS->endElementNS(XML_p, XML_nvSpPr);
// visual shape properties
mpFS->startElementNS(XML_p, XML_spPr);
mpFS->endElementNS(XML_p, XML_spPr);
WritePlaceholderReferenceTextBody(ePlaceholder, ePageType, rXPagePropSet);
mpFS->endElementNS(XML_p, XML_sp);
return *this;
}
ShapeExport& PowerPointShapeExport::WritePlaceholderReferenceTextBody(
PlaceholderType ePlaceholder, PageType ePageType, const Reference<XPropertySet> xPagePropSet)
{
mpFS->startElementNS(XML_p, XML_txBody);
mpFS->singleElementNS(XML_a, XML_bodyPr);
mpFS->startElementNS(XML_a, XML_p);
switch (ePlaceholder)
{
case Header:
break;
case Footer:
{
OUString aFooterText;
if (ePageType == LAYOUT)
{
aFooterText = "Footer";
}
else
{
xPagePropSet->getPropertyValue(u"FooterText"_ustr) >>= aFooterText;
}
mpFS->startElementNS(XML_a, XML_r);
mpFS->startElementNS(XML_a, XML_t);
mpFS->writeEscaped(aFooterText);
mpFS->endElementNS(XML_a, XML_t);
mpFS->endElementNS(XML_a, XML_r);
break;
}
case SlideNumber:
{
OUString aSlideNum;
sal_Int32 nSlideNum = 0;
if (ePageType == LAYOUT)
{
aSlideNum = "<#>";
}
else
{
xPagePropSet->getPropertyValue(u"Number"_ustr) >>= nSlideNum;
aSlideNum = OUString::number(nSlideNum);
}
OString aUUID(comphelper::xml::generateGUIDString());
mpFS->startElementNS(XML_a, XML_fld, XML_id, aUUID, XML_type, "slidenum");
mpFS->startElementNS(XML_a, XML_t);
mpFS->writeEscaped(aSlideNum);
mpFS->endElementNS(XML_a, XML_t);
mpFS->endElementNS(XML_a, XML_fld);
break;
}
case DateAndTime:
{
OUString aDateTimeType = u"datetime1"_ustr;
bool bIsDateTimeFixed = false;
xPagePropSet->getPropertyValue(u"IsDateTimeFixed"_ustr) >>= bIsDateTimeFixed;
OUString aDateTimeText = u"Date"_ustr;
const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
if(ePageType != LAYOUT && !bIsDateTimeFixed)
{
sal_Int32 nDateTimeFormat = 0;
xPagePropSet->getPropertyValue(u"DateTimeFormat"_ustr) >>= nDateTimeFormat;
// 4 LSBs represent the date
SvxDateFormat eDate = static_cast<SvxDateFormat>(nDateTimeFormat & 0x0f);
// the 4 bits after the date bits represent the time
SvxTimeFormat eTime = static_cast<SvxTimeFormat>(nDateTimeFormat >> 4);
aDateTimeType = GetDatetimeTypeFromDateTime(eDate, eTime);
if (aDateTimeType == "datetime")
aDateTimeType = "datetime1";
::DateTime aDateTime( ::DateTime::SYSTEM );
aDateTimeText = SvxDateTimeField::GetFormatted(
aDateTime, aDateTime, eDate,
eTime, *(SD_MOD()->GetNumberFormatter()),
rLanguageTag.getLanguageType());
}
if(!bIsDateTimeFixed)
{
OString aUUID(comphelper::xml::generateGUIDString());
mpFS->startElementNS(XML_a, XML_fld, XML_id, aUUID, XML_type, aDateTimeType);
}
else
{
xPagePropSet->getPropertyValue(u"DateTimeText"_ustr) >>= aDateTimeText;
mpFS->startElementNS(XML_a, XML_r);
}
mpFS->startElementNS(XML_a, XML_rPr, XML_lang, rLanguageTag.getBcp47MS());
mpFS->endElementNS(XML_a, XML_rPr);
mpFS->startElementNS(XML_a, XML_t);
mpFS->writeEscaped(aDateTimeText);
mpFS->endElementNS(XML_a, XML_t);
mpFS->endElementNS(XML_a, bIsDateTimeFixed ? XML_r : XML_fld);
break;
}
default:
SAL_INFO("sd.eppt", "warning: no defined textbody for referenced placeholder type: "
<< ePlaceholder);
}
mpFS->endElementNS(XML_a, XML_p);
mpFS->endElementNS(XML_p, XML_txBody);
return *this;
}
void PowerPointExport::WriteDefaultColorSchemes(const FSHelperPtr& pFS)
{
for (int nId = PredefinedClrSchemeId::dk2; nId != PredefinedClrSchemeId::Count; nId++)
{
OUString sName(getPredefinedClrNames(static_cast<PredefinedClrSchemeId>(nId)));
sal_Int32 nColor = 0;
switch (nId)
{
case PredefinedClrSchemeId::dk2:
nColor = 0x1F497D;
break;
case PredefinedClrSchemeId::lt2:
nColor = 0xEEECE1;
break;
case PredefinedClrSchemeId::accent1:
nColor = 0x4F81BD;
break;
case PredefinedClrSchemeId::accent2:
nColor = 0xC0504D;
break;
case PredefinedClrSchemeId::accent3:
nColor = 0x9BBB59;
break;
case PredefinedClrSchemeId::accent4:
nColor = 0x8064A2;
break;
case PredefinedClrSchemeId::accent5:
nColor = 0x4BACC6;
break;
case PredefinedClrSchemeId::accent6:
nColor = 0xF79646;
break;
case PredefinedClrSchemeId::hlink:
nColor = 0x0000FF;
break;
case PredefinedClrSchemeId::folHlink:
nColor = 0x800080;
break;
}
OUString sOpenColorScheme = "<a:" + sName + ">";
pFS->write(sOpenColorScheme);
pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor));
OUString sCloseColorScheme = "</a:" + sName + ">";
pFS->write(sCloseColorScheme);
}
}
void PowerPointExport::WriteTheme(sal_Int32 nThemeNum, model::Theme* pTheme)
{
if (!pTheme)
return;
OUString sThemePath = "ppt/theme/theme" + OUString::number(nThemeNum + 1) + ".xml";
oox::ThemeExport aThemeExport(this, DOCUMENT_PPTX);
aThemeExport.write(sThemePath, *pTheme);
}
bool PowerPointExport::ImplCreateDocument()
{
mbCreateNotes = false;
for (sal_uInt32 i = 0; i < mnPages; i++)
{
if (!GetPageByIndex(i, NOTICE))
return false;
if (ContainsOtherShapeThanPlaceholders())
{
mbCreateNotes = true;
break;
}
}
return true;
}
void PowerPointExport::WriteNotesMaster()
{
SAL_INFO("sd.eppt", "write Notes master\n---------------");
mPresentationFS->startElementNS(XML_p, XML_notesMasterIdLst);
OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
oox::getRelationship(Relationship::NOTESMASTER),
u"notesMasters/notesMaster1.xml");
mPresentationFS->singleElementNS(XML_p, XML_notesMasterId,
FSNS(XML_r, XML_id), sRelId);
mPresentationFS->endElementNS(XML_p, XML_notesMasterIdLst);
FSHelperPtr pFS =
openFragmentStreamWithSerializer(u"ppt/notesMasters/notesMaster1.xml"_ustr,
u"application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml"_ustr);
// write theme per master
// TODO: Need to implement theme support for note master, so the
// note master has his own theme associated.
// For now just use the default theme
auto const* pDefaultColorSet = svx::ColorSets::get().getColorSet(u"LibreOffice");
if (pDefaultColorSet)
{
auto pTheme = std::make_shared<model::Theme>("Office Theme");
pTheme->setColorSet(std::make_shared<model::ColorSet>(*pDefaultColorSet));
WriteTheme(mnMasterPages, pTheme.get());
// add implicit relation to the presentation theme
addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::THEME),
Concat2View("../theme/theme" + OUString::number(mnMasterPages + 1) + ".xml"));
}
pFS->startElementNS(XML_p, XML_notesMaster, PNMSS);
pFS->startElementNS(XML_p, XML_cSld);
Reference< XPropertySet > aXBackgroundPropSet;
if (ImplGetPropertyValue(mXPagePropSet, u"Background"_ustr) &&
(mAny >>= aXBackgroundPropSet))
ImplWriteBackground(pFS, aXBackgroundPropSet);
WriteShapeTree(pFS, NOTICE, true);
pFS->endElementNS(XML_p, XML_cSld);
// color map - now it uses colors from hardcoded theme, once we eventually generate theme, this might need update
pFS->singleElementNS(XML_p, XML_clrMap,
XML_bg1, "lt1",
XML_bg2, "lt2",
XML_tx1, "dk1",
XML_tx2, "dk2",
XML_accent1, "accent1",
XML_accent2, "accent2",
XML_accent3, "accent3",
XML_accent4, "accent4",
XML_accent5, "accent5",
XML_accent6, "accent6",
XML_hlink, "hlink",
XML_folHlink, "folHlink");
pFS->endElementNS(XML_p, XML_notesMaster);
SAL_INFO("sd.eppt", "----------------");
pFS->endDocument();
}
void PowerPointExport::embedEffectAudio(const FSHelperPtr& pFS, const OUString& sUrl, OUString& sRelId, OUString& sName)
{
comphelper::LifecycleProxy aProxy;
if (!sUrl.endsWithIgnoreAsciiCase(".wav"))
return;
uno::Reference<io::XInputStream> xAudioStream;
try
{
if (sUrl.startsWith("vnd.sun.star.Package:"))
{
uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(getModel(), uno::UNO_QUERY);
if (!xStorageBasedDocument.is())
return;
uno::Reference<embed::XStorage> xDocumentStorage = xStorageBasedDocument->getDocumentStorage();
if (!xDocumentStorage.is())
return;
uno::Reference<io::XStream> xStream = comphelper::OStorageHelper::GetStreamAtPackageURL(xDocumentStorage, sUrl,
css::embed::ElementModes::READ, aProxy);
if (xStream.is())
xAudioStream = xStream->getInputStream();
}
else
xAudioStream = comphelper::OStorageHelper::GetInputStreamFromURL(sUrl, getComponentContext());
}
catch (const Exception&)
{
TOOLS_WARN_EXCEPTION("sd", "PowerPointExport::embedEffectAudio");
}
if (!xAudioStream.is())
return;
int nLastSlash = sUrl.lastIndexOf('/');
sName = sUrl.copy(nLastSlash >= 0 ? nLastSlash + 1 : 0);
OUString sPath = "../media/" + sName;
sRelId = addRelation(pFS->getOutputStream(),
oox::getRelationship(Relationship::AUDIO), sPath);
uno::Reference<io::XOutputStream> xOutputStream = openFragmentStream(sPath.replaceAt(0, 2, u"/ppt"),
u"audio/x-wav"_ustr);
comphelper::OStorageHelper::CopyInputToOutput(xAudioStream, xOutputStream);
}
sal_Int32 PowerPointExport::GetShapeID(const Reference<XShape>& rXShape)
{
return ShapeExport::GetShapeID(rXShape, &maShapeMap);
}
sal_Int32 PowerPointExport::GetNextAnimationNodeID()
{
return mnAnimationNodeIdMax++;
}
bool PowerPointExport::ImplCreateMainNotes()
{
if (mbCreateNotes)
WriteNotesMaster();
return true;
}
OUString PowerPointExport::getImplementationName()
{
return u"com.sun.star.comp.Impress.oox.PowerPointExport"_ustr;
}
void PowerPointExport::WriteDiagram(const FSHelperPtr& pFS, PowerPointShapeExport& rDML, const css::uno::Reference<css::drawing::XShape>& rXShape, int nDiagramId)
{
SAL_INFO("sd.eppt", "writing Diagram " + OUString::number(nDiagramId));
pFS->startElementNS(XML_p, XML_graphicFrame);
rDML.WriteDiagram(rXShape, nDiagramId);
pFS->endElementNS(XML_p, XML_graphicFrame);
}
void PowerPointExport::WritePlaceholderReferenceShapes(PowerPointShapeExport& rDML, PageType ePageType)
{
bool bCheckProps = ePageType == NORMAL;
Reference<XShape> xShape;
Any aAny;
OUString aText;
if (ePageType == LAYOUT
|| (bCheckProps && PropValue::GetPropertyValue(aAny, mXPagePropSet, u"IsFooterVisible"_ustr, true)
&& aAny == true && GetPropertyValue(aAny, mXPagePropSet, u"FooterText"_ustr, true)
&& (aAny >>= aText) && !aText.isEmpty()))
{
if ((xShape = GetReferencedPlaceholderXShape(Footer, ePageType)))
{
const auto iter = maPlaceholderShapeToIndexMap.find(xShape);
assert(iter != maPlaceholderShapeToIndexMap.end());
rDML.WritePlaceholderReferenceShape(Footer,
iter->second,
ePageType, mXPagePropSet);
}
}
if (ePageType == LAYOUT
|| (bCheckProps
&& PropValue::GetPropertyValue(aAny, mXPagePropSet, u"IsPageNumberVisible"_ustr, true)
&& aAny == true))
{
if ((xShape = GetReferencedPlaceholderXShape(SlideNumber, ePageType)))
{
const auto iter = maPlaceholderShapeToIndexMap.find(xShape);
assert(iter != maPlaceholderShapeToIndexMap.end());
rDML.WritePlaceholderReferenceShape(SlideNumber,
iter->second,
ePageType, mXPagePropSet);
}
}
if (ePageType == LAYOUT
|| (bCheckProps
&& PropValue::GetPropertyValue(aAny, mXPagePropSet, u"IsDateTimeVisible"_ustr, true)
&& aAny == true
&& ((GetPropertyValue(aAny, mXPagePropSet, u"DateTimeText"_ustr, true) && (aAny >>= aText)
&& !aText.isEmpty())
|| mXPagePropSet->getPropertyValue(u"IsDateTimeFixed"_ustr) == false)))
{
if ((xShape = GetReferencedPlaceholderXShape(DateAndTime, ePageType)))
{
const auto iter = maPlaceholderShapeToIndexMap.find(xShape);
assert(iter != maPlaceholderShapeToIndexMap.end());
rDML.WritePlaceholderReferenceShape(DateAndTime,
iter->second,
ePageType, mXPagePropSet);
}
}
}
sal_Int32 PowerPointExport::CreateNewPlaceholderIndex(const css::uno::Reference<XShape> &rXShape)
{
maPlaceholderShapeToIndexMap.insert({rXShape, mnPlaceholderIndexMax});
return mnPlaceholderIndexMax++;
}
Reference<XShape> PowerPointExport::GetReferencedPlaceholderXShape(const PlaceholderType eType,
PageType ePageType) const
{
PresObjKind ePresObjKind = PresObjKind::NONE;
switch (eType)
{
case oox::core::None:
break;
case oox::core::SlideImage:
break;
case oox::core::Notes:
break;
case oox::core::Header:
ePresObjKind = PresObjKind::Header;
break;
case oox::core::Footer:
ePresObjKind = PresObjKind::Footer;
break;
case oox::core::SlideNumber:
ePresObjKind = PresObjKind::SlideNumber;
break;
case oox::core::DateAndTime:
ePresObjKind = PresObjKind::DateTime;
break;
case oox::core::Outliner:
break;
case oox::core::Title:
ePresObjKind = PresObjKind::Title;
break;
case oox::core::Subtitle:
break;
}
if (ePresObjKind != PresObjKind::NONE)
{
SdPage* pMasterPage;
if (ePageType == LAYOUT)
{
// since Layout pages do not have drawpages themselves - mXDrawPage is still the master they reference to..
pMasterPage = SdPage::getImplementation(mXDrawPage);
}
else
{
pMasterPage = &static_cast<SdPage&>(SdPage::getImplementation(mXDrawPage)->TRG_GetMasterPage());
}
if (SdrObject* pMasterFooter = pMasterPage->GetPresObj(ePresObjKind))
return GetXShapeForSdrObject(pMasterFooter);
}
return nullptr;
}
// UNO component
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
css_comp_Impress_oox_PowerPointExport(uno::XComponentContext* rxCtxt,
uno::Sequence<css::uno::Any> const& rArguments)
{
return cppu::acquire(new PowerPointExport(rxCtxt, rArguments));
}
#if OSL_DEBUG_LEVEL > 1
void dump_pset(Reference< XPropertySet > const& rXPropSet)
{
Reference< XPropertySetInfo > info = rXPropSet->getPropertySetInfo();
Sequence< beans::Property > props = info->getProperties();
for (int i=0; i < props.getLength(); i++)
{
OString name = OUStringToOString(props [i].Name, RTL_TEXTENCODING_UTF8);
Any value = rXPropSet->getPropertyValue(props [i].Name);
OUString strValue;
sal_Int32 intValue;
bool boolValue;
RectanglePoint pointValue;
if (value >>= strValue)
SAL_INFO("sd.eppt", name << " = \"" << strValue << "\"");
else if (value >>= intValue)
SAL_INFO("sd.eppt", name << " = " << intValue << "(hex : " << std::hex << intValue << ")");
else if (value >>= boolValue)
SAL_INFO("sd.eppt", name << " = " << boolValue << " (bool)");
else if (value >>= pointValue)
SAL_INFO("sd.eppt", name << " = " << static_cast<int>(pointValue) << " (RectanglePoint)");
else
SAL_INFO("sd.eppt", "??? <unhandled type>");
}
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V530 The return value of function 'addRelation' is required to be utilized.
↑ V547 Expression 'advanceTiming != - 1' is always false.
↑ V547 Expression '!bOOXmlSpecificTransition' is always true.
↑ V547 Expression 'isAdvanceTimingSet' is always false.
↑ V547 Expression 'pPresetTransition' is always false.
↑ V547 Expression 'bUseBackground' is always false.
↑ V547 Expression '!bIsDateTimeFixed' is always true.
↑ V547 Expression 'bIsDateTimeFixed' is always false.
↑ V560 A part of conditional expression is always true: aFillStyle == FillStyle_NONE.
↑ V560 A part of conditional expression is always false: aFillStyle == FillStyle_HATCH.
↑ V560 A part of conditional expression is always true: !bOOXmlSpecificTransition.
↑ V560 A part of conditional expression is always false: changeType == 1.
↑ V560 A part of conditional expression is always false: pPresetTransition.
↑ V560 A part of conditional expression is always false: pPresetTransition.
↑ V560 A part of conditional expression is always true: !bIsDateTimeFixed.
↑ V785 Constant expression in switch statement.
↑ V785 Constant expression in switch statement.
↑ V785 Constant expression in switch statement.
↑ V1019 Compound assignment expression 'mAny >>= nTransitionType' is used inside condition.
↑ V1019 Compound assignment expression 'mAny >>= nTransitionSubtype' is used inside condition.
↑ V1019 Compound assignment expression 'mAny >>= sSoundUrl' is used inside condition.
↑ V1019 Compound assignment expression 'mAny >>= aXBackgroundPropSet' is used inside condition.
↑ V1019 Compound assignment expression 'aAny >>= aText' is used inside condition.
↑ V1019 Compound assignment expression 'aAny >>= aText' is used inside condition.