diff --git a/sd/qa/unit/data/pptx/pres-with-notes.pptx b/sd/qa/unit/data/pptx/pres-with-notes.pptx new file mode 100644 index 000000000000..25f9692a2a1c Binary files /dev/null and b/sd/qa/unit/data/pptx/pres-with-notes.pptx differ diff --git a/sd/qa/unit/export-tests-ooxml4.cxx b/sd/qa/unit/export-tests-ooxml4.cxx index 63af283d664f..0e11eb581bf0 100644 --- a/sd/qa/unit/export-tests-ooxml4.cxx +++ b/sd/qa/unit/export-tests-ooxml4.cxx @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -1095,6 +1096,40 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testTdf102261_testParaTabStopDefaultDis } } +CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testNotesAuthorDate) +{ + createSdImpressDoc("pptx/pres-with-notes.pptx"); + + auto pBatch(comphelper::ConfigurationChanges::create()); + // 1. Remove all personal info, but keep note info + officecfg::Office::Common::Security::Scripting::RemovePersonalInfoOnSaving::set(true, pBatch); + officecfg::Office::Common::Security::Scripting::KeepNoteAuthorDateInfoOnSaving::set(true, + pBatch); + pBatch->commit(); + + saveAndReload(u"Impress Office Open XML"_ustr); + + xmlDocUniquePtr pXml = parseExport(u"ppt/commentAuthors.xml"_ustr); + assertXPath(pXml, "/p:cmAuthorLst/p:cmAuthor[@id=0]"_ostr, "name"_ostr, "Hans Wurst"); + assertXPath(pXml, "/p:cmAuthorLst/p:cmAuthor[@id=1]"_ostr, "name"_ostr, "Max Muster"); + + pXml = parseExport(u"ppt/comments/comment1.xml"_ustr); + assertXPath(pXml, "/p:cmLst/p:cm"_ostr, "dt"_ostr, "2024-06-13T12:03:08.000000000"); + + // 2. Remove all personal info + officecfg::Office::Common::Security::Scripting::KeepNoteAuthorDateInfoOnSaving::set(false, + pBatch); + pBatch->commit(); + saveAndReload(u"Impress Office Open XML"_ustr); + + pXml = parseExport(u"ppt/commentAuthors.xml"_ustr); + assertXPath(pXml, "/p:cmAuthorLst/p:cmAuthor[@id=0]"_ostr, "name"_ostr, "Author1"); + assertXPath(pXml, "/p:cmAuthorLst/p:cmAuthor[@id=1]"_ostr, "name"_ostr, "Author2"); + + pXml = parseExport(u"ppt/comments/comment1.xml"_ustr); + assertXPathNoAttribute(pXml, "/p:cmLst/p:cm"_ostr, "dt"_ostr); +} + CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testTableCellVerticalPropertyRoundtrip) { createSdImpressDoc("pptx/tcPr-vert-roundtrip.pptx"); diff --git a/sd/source/filter/eppt/epptooxml.hxx b/sd/source/filter/eppt/epptooxml.hxx index c187c90c721c..9646afb865d8 100644 --- a/sd/source/filter/eppt/epptooxml.hxx +++ b/sd/source/filter/eppt/epptooxml.hxx @@ -22,6 +22,7 @@ #include #include #include +#include #include "epptbase.hxx" using ::sax_fastparser::FSHelperPtr; @@ -139,6 +140,7 @@ private: ::sax_fastparser::FSHelperPtr mPresentationFS; LayoutInfo mLayoutInfo[OOXML_LAYOUT_SIZE]; + std::unique_ptr mpAuthorIDs; // map authors to remove personal info std::vector< ::sax_fastparser::FSHelperPtr > mpSlidesFSArray; sal_Int32 mnLayoutFileIdMax; @@ -158,6 +160,8 @@ private: /// Map of placeholder indexes for Master placeholders std::unordered_map< css::uno::Reference, sal_Int32 > maPlaceholderShapeToIndexMap; + // Get author id to remove personal info + size_t GetInfoID( const OUString sPersonalInfo ) const { return mpAuthorIDs->GetInfoID(sPersonalInfo); } struct AuthorComments { sal_Int32 nId; sal_Int32 nLastIndex; diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index 2d9e51e40fa5..728682f955d6 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -342,6 +343,7 @@ ShapeExport& PowerPointShapeExport::WriteUnknownShape(const Reference< XShape >& PowerPointExport::PowerPointExport(const Reference< XComponentContext >& rContext, const uno::Sequence& rArguments) : XmlFilterBase(rContext) + , mpAuthorIDs( new SvtSecurityMapPersonalInfo ) , mnLayoutFileIdMax(1) , mnSlideIdMax(1 << 8) , mnSlideMasterIdMax(1U << 31) @@ -1166,6 +1168,12 @@ bool PowerPointExport::WriteComments(sal_uInt32 nPageNum) 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); @@ -1180,16 +1188,30 @@ bool PowerPointExport::WriteComments(sal_uInt32 nPageNum) RealPoint2D aRealPoint2D(xAnnotation->getPosition()); Reference< XText > xText(xAnnotation->getTextRange()); sal_Int32 nLastIndex; - sal_Int32 nId = GetAuthorIdAndLastIndex(xAnnotation->getAuthor(), nLastIndex); + OUString sAuthor(bRemoveCommentAuthorDates + ? "Author" + + OUString::number(GetInfoID(xAnnotation->getAuthor())) + : xAnnotation->getAuthor()); + sal_Int32 nId = GetAuthorIdAndLastIndex(sAuthor, 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); - pFS->startElementNS(XML_p, XML_cm, - XML_authorId, OString::number(nId), - XML_dt, cDateTime, - XML_idx, OString::number(nLastIndex)); + 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))),