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));

Reply via email to