sd/inc/drawdoc.hxx | 1 sd/source/core/drawdoc2.cxx | 83 +++++++++++++++++++++++++++++++ sd/source/filter/eppt/eppt.cxx | 2 sd/source/filter/eppt/epptbase.hxx | 1 sd/source/filter/eppt/epptso.cxx | 4 + sd/source/filter/eppt/pptx-epptbase.cxx | 22 +++++++- sd/source/filter/eppt/pptx-epptooxml.cxx | 26 ++++++++- 7 files changed, 133 insertions(+), 6 deletions(-)
New commits: commit c61a18baa2fdc6f709a6933990253b9a14b88c80 Author: Mohit Marathe <[email protected]> AuthorDate: Mon Dec 1 19:13:40 2025 +0530 Commit: Mohit Marathe <[email protected]> CommitDate: Tue Jan 13 08:55:02 2026 +0100 sd: indicate page order using connectors in canvas page The connectors are glued to the preview shapes. Signed-off-by: Mohit Marathe <[email protected]> Change-Id: I168208899b06e3c6d3b24f5e4055894310b12e22 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194923 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Michael Stahl <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196711 diff --git a/sd/inc/drawdoc.hxx b/sd/inc/drawdoc.hxx index 9d5c33d1a3b7..e267595d8c67 100644 --- a/sd/inc/drawdoc.hxx +++ b/sd/inc/drawdoc.hxx @@ -1152,6 +1152,7 @@ private: SAL_DLLPRIVATE void populatePagePreviewsGrid(); SAL_DLLPRIVATE void updatePagePreviewsGrid(SdPage* pPage); + SAL_DLLPRIVATE void connectPagePreviews(); SAL_DLLPRIVATE virtual void PageListChanged() override; SAL_DLLPRIVATE virtual void MasterPageListChanged() override; diff --git a/sd/source/core/drawdoc2.cxx b/sd/source/core/drawdoc2.cxx index 043803d3f58a..96471dace0fa 100644 --- a/sd/source/core/drawdoc2.cxx +++ b/sd/source/core/drawdoc2.cxx @@ -28,6 +28,7 @@ #include <svx/svdopage.hxx> #include <svx/svdoole2.hxx> #include <svx/svdundo.hxx> +#include <svx/svdoedge.hxx> #include <vcl/svapp.hxx> #include <editeng/eeitem.hxx> #include <editeng/editobj.hxx> @@ -54,8 +55,16 @@ #include <undo/undomanager.hxx> #include <sfx2/lokhelper.hxx> #include <unomodel.hxx> +#include <svx/constructhelper.hxx> + +#include <svx/strings.hrc> +#include <svx/svdobj.hxx> +#include <svx/sxekitm.hxx> +#include <svx/xlnedit.hxx> +#include <svx/xlnedwit.hxx> #include <DrawDocShell.hxx> +#include <ViewShell.hxx> #include "PageListWatcher.hxx" #include <strings.hxx> @@ -1518,6 +1527,7 @@ void SdDrawDocument::ImportCanvasPage() pPage->NbcRemoveObject(0); } populatePagePreviewsGrid(); + connectPagePreviews(); } } @@ -1638,6 +1648,7 @@ sal_uInt16 SdDrawDocument::GetOrInsertCanvasPage() } populatePagePreviewsGrid(); + connectPagePreviews(); return pCanvasPage->GetPageNum() / 2; } @@ -1745,4 +1756,74 @@ void SdDrawDocument::updatePagePreviewsGrid(SdPage* pPage) mpCanvasPage->CreatePresObj(PresObjKind::PagePreview, true, ::tools::Rectangle(Point(nX,nY), Size(nPreviewWidth, nPreviewHeight)), OUString(), nPageNum); } } + +void SdDrawDocument::connectPagePreviews() +{ + if (!HasCanvasPage()) + return; + SdrObjList* pObjList = mpCanvasPage.get(); + std::vector<SdrPageObj*> aPageOrder(GetSdPageCount(PageKind::Standard) - 1, nullptr); + + SdrObjListIter aIter(pObjList, SdrIterMode::Flat); + for (SdrObject* pObj = aIter.Next(); pObj; pObj = aIter.Next()) + { + if (pObj->GetObjIdentifier() == SdrObjKind::Page) + { + SdrPageObj* pPageObj = static_cast<SdrPageObj*>(pObj); + SdPage* pPage = static_cast<SdPage*>(pPageObj->GetReferencedPage()); + sal_uInt16 nIndex = (pPage->GetPageNum() - 1) / 2 - 1; // without canvas page + aPageOrder[nIndex] = pPageObj; + } + } + + for (size_t i = 0; i < aPageOrder.size() - 1; i++) + { + SdrPageObj* pPageObj1 = aPageOrder[i]; + SdrPageObj* pPageObj2 = aPageOrder[i + 1]; + + ::tools::Rectangle aRect1 = pPageObj1->GetSnapRect(); + ::tools::Rectangle aRect2 = pPageObj2->GetSnapRect(); + + Point aStart(aRect1.RightCenter()); + Point aEnd(aRect2.LeftCenter()); + + rtl::Reference<SdrObject> pObj( + SdrObjFactory::MakeNewObject(*this, SdrInventor::Default, SdrObjKind::Edge)); + + SdrEdgeObj* pEdge = dynamic_cast<SdrEdgeObj*>(pObj.get()); + pEdge->SetTailPoint(true, aStart); + pEdge->SetTailPoint(false, aEnd); + + // glue the connectors to preview shapes + pEdge->ConnectToNode(true, pPageObj1); + pEdge->ConnectToNode(false, pPageObj2); + + SfxItemSet aAttr(GetPool()); + + // curved connector + aAttr.Put(SdrEdgeKindItem(SdrEdgeKind::Bezier)); + + // copied from FuConstructRectangle::SetLineEnds + ::basegfx::B2DPolyPolygon aArrow( + ConstructHelper::GetLineEndPoly(RID_SVXSTR_ARROW, *this)); + if (!aArrow.count()) + { + ::basegfx::B2DPolygon aNewArrow; + aNewArrow.append(::basegfx::B2DPoint(10.0, 0.0)); + aNewArrow.append(::basegfx::B2DPoint(0.0, 30.0)); + aNewArrow.append(::basegfx::B2DPoint(20.0, 30.0)); + aNewArrow.setClosed(true); + aArrow.append(aNewArrow); + } + + ::tools::Long nWidth = 600; + aAttr.Put(XLineEndItem(SdResId(RID_SVXSTR_ARROW), aArrow)); + aAttr.Put(XLineEndWidthItem(nWidth)); + + pEdge->SetMergedItemSet(aAttr); + + pObj->SetMarkProtect(true); + mpCanvasPage->NbcInsertObject(pObj.get()); + } +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit ce8bbe12e7bbf193e7afcf33c7a279f09793d2e5 Author: Mohit Marathe <[email protected]> AuthorDate: Wed Nov 26 16:56:03 2025 +0530 Commit: Mohit Marathe <[email protected]> CommitDate: Tue Jan 13 08:54:51 2026 +0100 sd: do not export canvas master page to pptx Signed-off-by: Mohit Marathe <[email protected]> Change-Id: I827c2325788552cdfd424fd69d0384fa6d2b88bc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194699 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Michael Stahl <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196710 diff --git a/sd/source/core/drawdoc2.cxx b/sd/source/core/drawdoc2.cxx index d31a4ed1dd33..043803d3f58a 100644 --- a/sd/source/core/drawdoc2.cxx +++ b/sd/source/core/drawdoc2.cxx @@ -1507,6 +1507,8 @@ void SdDrawDocument::ImportCanvasPage() pPage->SetCanvasPage(); pPage->SetExcluded(true); mpCanvasPage = pPage; + SdPage* pMPage = static_cast<SdPage*>(&pPage->TRG_GetMasterPage()); + pMPage->SetCanvasMasterPage(); // re-populate the previews grid if not valid if (!bIsCanvasPageValid) { diff --git a/sd/source/filter/eppt/eppt.cxx b/sd/source/filter/eppt/eppt.cxx index 8f4123c38791..2ba6c5c6f4d6 100644 --- a/sd/source/filter/eppt/eppt.cxx +++ b/sd/source/filter/eppt/eppt.cxx @@ -1300,6 +1300,8 @@ void PPTWriter::ImplWriteAtomEnding() // write MasterPages persists for ( i = 0; i < mnMasterPages; i++ ) { + if (i == mnCanvasMasterIndex) + continue; nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainMaster | i ); if ( nOfs ) { diff --git a/sd/source/filter/eppt/epptbase.hxx b/sd/source/filter/eppt/epptbase.hxx index 560676aa04ab..a932e233e9d3 100644 --- a/sd/source/filter/eppt/epptbase.hxx +++ b/sd/source/filter/eppt/epptbase.hxx @@ -345,6 +345,7 @@ protected: sal_uInt32 mnPages; ///< number of Slides ( w/o master pages & notes & handout ) sal_uInt32 mnMasterPages; + sal_uInt32 mnCanvasMasterIndex; Fraction maFraction; MapMode maMapModeSrc; diff --git a/sd/source/filter/eppt/epptso.cxx b/sd/source/filter/eppt/epptso.cxx index d2537f1feb08..ed3d5b8e9827 100644 --- a/sd/source/filter/eppt/epptso.cxx +++ b/sd/source/filter/eppt/epptso.cxx @@ -322,13 +322,15 @@ sal_uInt32 PPTWriter::ImplDocumentListContainer( SvStream* pStrm ) sal_uInt32 PPTWriter::ImplMasterSlideListContainer( SvStream* pStrm ) { - sal_uInt32 i, nSize = 28 * mnMasterPages + 8; + sal_uInt32 i, nSize = 28 * (mnMasterPages - static_cast<int>(mbHasCanvasPage)) + 8; if ( pStrm ) { pStrm->WriteUInt32( 0x1f | ( EPP_SlideListWithText << 16 ) ).WriteUInt32( nSize - 8 ); for ( i = 0; i < mnMasterPages; i++ ) { + if (i == mnCanvasMasterIndex) + continue; pStrm->WriteUInt32( EPP_SlidePersistAtom << 16 ).WriteUInt32( 20 ); mpPptEscherEx->InsertPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, pStrm->Tell() ); pStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINMASTER_PERSIST_KEY ) diff --git a/sd/source/filter/eppt/pptx-epptbase.cxx b/sd/source/filter/eppt/pptx-epptbase.cxx index 5d3d88972870..1d7eb254910d 100644 --- a/sd/source/filter/eppt/pptx-epptbase.cxx +++ b/sd/source/filter/eppt/pptx-epptbase.cxx @@ -22,6 +22,7 @@ #include "epptbase.hxx" #include "epptdef.hxx" #include "../ppt/pptanimations.hxx" +#include <sdpage.hxx> #include <unomodel.hxx> #include <o3tl/any.hxx> @@ -110,6 +111,7 @@ PPTWriterBase::PPTWriterBase() , mnAngle(0) , mnPages(0) , mnMasterPages(0) + , mnCanvasMasterIndex(SAL_MAX_UINT32) , maFraction(1, 576) , maMapModeSrc(MapUnit::Map100thMM) , maMapModeDest(MapUnit::MapInch, Point(), maFraction, maFraction) @@ -130,6 +132,7 @@ PPTWriterBase::PPTWriterBase( const rtl::Reference< SdXImpressDocument > & rXMod , mnAngle(0) , mnPages(0) , mnMasterPages(0) + , mnCanvasMasterIndex(SAL_MAX_UINT32) , maFraction(1, 576) , maMapModeSrc(MapUnit::Map100thMM) , maMapModeDest(MapUnit::MapInch, Point(), maFraction, maFraction) @@ -196,6 +199,8 @@ void PPTWriterBase::exportPPT( const std::vector< css::beans::PropertyValue >& r for ( i = 0; i < mnMasterPages; i++ ) { + if (i == mnCanvasMasterIndex) + continue; if ( !CreateSlideMaster( i ) ) return; } @@ -243,6 +248,19 @@ bool PPTWriterBase::InitSOIface() mbHasCanvasPage = true; else mbHasCanvasPage = false; + + for (sal_uInt32 i = 0; i < mnMasterPages; i++) + { + if (GetPageByIndex(i, MASTER)) + { + SdPage* pPage = SdPage::getImplementation(mXDrawPage); + if (pPage && pPage->IsCanvasMasterPage()) + { + mnCanvasMasterIndex = i; + break; + } + } + } return true; } return false; @@ -465,7 +483,7 @@ sal_uInt32 PPTWriterBase::GetMasterIndex( PageType ePageType ) } } if ( ePageType == NOTICE ) - nRetValue += mnMasterPages; + nRetValue += mnMasterPages - static_cast<int>(mbHasCanvasPage); return nRetValue; } @@ -484,6 +502,8 @@ bool PPTWriterBase::GetStyleSheets() for ( nPageNum = 0; nPageNum < mnMasterPages; nPageNum++ ) { + if (nPageNum == mnCanvasMasterIndex) + continue; Reference< XNamed > aXNamed; diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index 9504079d2f65..af2168caf0a5 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -1909,6 +1909,8 @@ void PowerPointExport::FindEquivalentMasterPages() maEquivalentMasters.resize(mnMasterPages, SAL_MAX_UINT32); for (sal_uInt32 i = 0; i < mnMasterPages; i++) { + if (i == mnCanvasMasterIndex) + continue; css::uno::Reference<css::drawing::XDrawPage> xDrawPage; uno::Any aAny(xDrawPages->getByIndex(i)); aAny >>= xDrawPage; @@ -1929,11 +1931,13 @@ void PowerPointExport::FindEquivalentMasterPages() for (sal_uInt32 i = 0; i < mnMasterPages; i++) { - if (!maMastersLayouts[i].first || maEquivalentMasters[i] != SAL_MAX_UINT32) + if (!maMastersLayouts[i].first || maEquivalentMasters[i] != SAL_MAX_UINT32 + || i == mnCanvasMasterIndex) continue; for (sal_uInt32 j = i + 1; j < mnMasterPages; j++) { - if (!maMastersLayouts[j].first || maEquivalentMasters[j] != SAL_MAX_UINT32) + if (!maMastersLayouts[j].first || maEquivalentMasters[j] != SAL_MAX_UINT32 + || j == mnCanvasMasterIndex) continue; if (lcl_ComparePageProperties(maMastersLayouts[i].first, maMastersLayouts[j].first) @@ -1959,6 +1963,8 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro { SAL_INFO("sd.eppt", "write master slide: " << nPageNum << " --------------"); + assert(mnCanvasMasterIndex != nPageNum); + if (nPageNum != GetEquivalentMasterPage(nPageNum) && GetEquivalentMasterPage(nPageNum) != SAL_MAX_UINT32) { @@ -1979,6 +1985,8 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro // Close the list tag if it was the last one if (nPageNum == mnMasterPages - 1) mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst); + if (mnCanvasMasterIndex == mnMasterPages - 1 && nPageNum == mnMasterPages - 2) + mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst); return; } @@ -1986,6 +1994,8 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro // slides list if (nPageNum == 0) mPresentationFS->startElementNS(XML_p, XML_sldMasterIdLst); + if (mnCanvasMasterIndex == 0 && nPageNum == 1) + mPresentationFS->startElementNS(XML_p, XML_sldMasterIdLst); OUString sRelId = addRelation(mPresentationFS->getOutputStream(), oox::getRelationship(Relationship::SLIDEMASTER), @@ -1995,6 +2005,12 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro XML_id, OString::number(GetNewSlideMasterId()), FSNS(XML_r, XML_id), sRelId); + // if canvas master page is the last one, close the list tag before that + if (mnCanvasMasterIndex == mnMasterPages - 1) + { + if (nPageNum == mnMasterPages - 2) + mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst); + } if (nPageNum == mnMasterPages - 1) mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst); @@ -2156,6 +2172,8 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro // Add layouts of other Impress masters that came from a single pptx master with multiple layouts for (sal_uInt32 i = 0; i < mnMasterPages; i++) { + if (i == mnCanvasMasterIndex) + continue; if (i != nPageNum && maEquivalentMasters[i] == nPageNum) { aLayouts = getLayoutsUsedForMaster(maMastersLayouts[i].first); @@ -2743,12 +2761,12 @@ void PowerPointExport::WriteNotesMaster() auto pTheme = std::make_shared<model::Theme>("Office Theme"); pTheme->setColorSet(std::make_shared<model::ColorSet>(*pDefaultColorSet)); - WriteTheme(mnMasterPages, pTheme.get()); + WriteTheme(mnMasterPages - static_cast<int>(mbHasCanvasPage), pTheme.get()); // add implicit relation to the presentation theme addRelation(pFS->getOutputStream(), oox::getRelationship(Relationship::THEME), - Concat2View("../theme/theme" + OUString::number(mnMasterPages + 1) + ".xml")); + Concat2View("../theme/theme" + OUString::number(mnMasterPages + 1 - static_cast<int>(mbHasCanvasPage)) + ".xml")); } pFS->startElementNS(XML_p, XML_notesMaster, presentationNamespaces(*this));
