sd/inc/drawdoc.hxx                                     |   10 +-
 sd/inc/pres.hxx                                        |    1 
 sd/inc/sdpage.hxx                                      |    2 
 sd/source/core/drawdoc2.cxx                            |   85 ++++++++++++++++-
 sd/source/core/sdpage.cxx                              |   20 +++-
 sd/source/ui/slidesorter/controller/SlsSlotManager.cxx |    2 
 sd/source/ui/unoidl/unopage.cxx                        |    3 
 sd/source/ui/view/drviews2.cxx                         |    2 
 8 files changed, 117 insertions(+), 8 deletions(-)

New commits:
commit 62f9434a216984bcc0499549e36099bc88296f45
Author:     Mohit Marathe <[email protected]>
AuthorDate: Mon Oct 13 20:36:55 2025 +0530
Commit:     Michael Stahl <[email protected]>
CommitDate: Mon Jan 12 13:01:40 2026 +0100

    sd: populate page previews grid in canvas page
    
    Signed-off-by: Mohit Marathe <[email protected]>
    Change-Id: I9058a857cad403b78c20e3f771e1531d7f641a38
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192767
    Reviewed-by: Michael Stahl <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196693

diff --git a/sd/inc/drawdoc.hxx b/sd/inc/drawdoc.hxx
index db7656d450b1..fdb41267ab66 100644
--- a/sd/inc/drawdoc.hxx
+++ b/sd/inc/drawdoc.hxx
@@ -413,6 +413,8 @@ private:
 
     sal_Int32 mnImagePreferredDPI;
 
+    rtl::Reference<SdPage> mpCanvasPage;
+
     SAL_DLLPRIVATE virtual css::uno::Reference< css::frame::XModel > 
createUnoModel() override;
 
 public:
@@ -999,8 +1001,7 @@ public:
         bool bIsPageObj,
         const sal_Int32 nInsertPosition);
 
-
-    SAL_DLLPRIVATE sal_uInt16 InsertCanvasPage ();
+    SAL_DLLPRIVATE sal_uInt16 GetOrInsertCanvasPage ();
 
     /** return the document fonts for latin, cjk and ctl according to the 
current
         languages set at this document */
@@ -1138,6 +1139,11 @@ private:
         bool bIsPageBack,
         bool bIsPageObj);
 
+    SAL_DLLPRIVATE bool hasCanvasPage() const { return mpCanvasPage != 
nullptr; }
+
+    SAL_DLLPRIVATE void populatePagePreviewsGrid();
+    SAL_DLLPRIVATE void updateCanvasPreviewsGrid();
+
     SAL_DLLPRIVATE virtual void PageListChanged() override;
     SAL_DLLPRIVATE virtual void MasterPageListChanged() override;
 };
diff --git a/sd/inc/pres.hxx b/sd/inc/pres.hxx
index ab2b44adf6c5..b0780b9dd47d 100644
--- a/sd/inc/pres.hxx
+++ b/sd/inc/pres.hxx
@@ -32,6 +32,7 @@ enum class PresObjKind
     Page,
     Handout,
     Notes,
+    PagePreview,
     Header,
     Footer,
     DateTime,
diff --git a/sd/inc/sdpage.hxx b/sd/inc/sdpage.hxx
index a63a362373f3..013fecbccb56 100644
--- a/sd/inc/sdpage.hxx
+++ b/sd/inc/sdpage.hxx
@@ -168,7 +168,7 @@ public:
     sd::ShapeList&  GetPresentationShapeList() { return 
maPresentationShapeList; }
 
     void EnsureMasterPageDefaultBackground();
-    SD_DLLPUBLIC SdrObject* CreatePresObj(PresObjKind eObjKind, bool 
bVertical, const ::tools::Rectangle& rRect, const OUString& rCustomPrompt = 
OUString());
+    SD_DLLPUBLIC SdrObject* CreatePresObj(PresObjKind eObjKind, bool 
bVertical, const ::tools::Rectangle& rRect, const OUString& rCustomPrompt = 
OUString(), const sal_uInt16 nPagePreviewNum = 0xffff);
     SD_DLLPUBLIC rtl::Reference<SdrObject> CreateDefaultPresObj(PresObjKind 
eObjKind);
     SD_DLLPUBLIC void DestroyDefaultPresObj(PresObjKind eObjKind);
     SD_DLLPUBLIC SdrObject* GetPresObj(PresObjKind eObjKind, int nIndex = 1, 
bool bFuzzySearch = false );
diff --git a/sd/source/core/drawdoc2.cxx b/sd/source/core/drawdoc2.cxx
index 65efc70f84f9..19ae5cf93bcd 100644
--- a/sd/source/core/drawdoc2.cxx
+++ b/sd/source/core/drawdoc2.cxx
@@ -457,6 +457,9 @@ void SdDrawDocument::InsertPage(SdrPage* pPage, sal_uInt16 
nPos)
         SdXImpressDocument* pDoc = getUnoModel();
         SfxLokHelper::notifyDocumentSizeChangedAllViews(pDoc);
     }
+
+    if (hasCanvasPage())
+        updateCanvasPreviewsGrid();
 }
 
 // Override SfxBaseModel::getUnoModel and return a more concrete type
@@ -471,6 +474,9 @@ void SdDrawDocument::DeletePage(sal_uInt16 nPgNum)
     FmFormModel::DeletePage(nPgNum);
 
     UpdatePageObjectsInNotes(nPgNum);
+
+    if (hasCanvasPage())
+        updateCanvasPreviewsGrid();
 }
 
 // Remove page
@@ -494,6 +500,9 @@ rtl::Reference<SdrPage> 
SdDrawDocument::RemovePage(sal_uInt16 nPgNum)
         SfxLokHelper::notifyDocumentSizeChangedAllViews(pDoc);
     }
 
+    if (hasCanvasPage())
+        updateCanvasPreviewsGrid();
+
     return pPage;
 }
 
@@ -1445,8 +1454,11 @@ void SdDrawDocument::SetupNewPage (
     }
 }
 
-sal_uInt16 SdDrawDocument::InsertCanvasPage()
+sal_uInt16 SdDrawDocument::GetOrInsertCanvasPage()
 {
+    if (hasCanvasPage())
+        return mpCanvasPage->GetPageNum() / 2;
+
     sal_uInt16 nLastPageNum = GetSdPageCount(PageKind::Standard);
     SdPage* pLastStandardPage = GetSdPage(nLastPageNum - 1, 
PageKind::Standard);
 
@@ -1457,6 +1469,10 @@ sal_uInt16 SdDrawDocument::InsertCanvasPage()
     const Size aCanvasSize(500000, 500000);
 
     ResizeCurrentPage(pCanvasPage, aCanvasSize, PageKind::Standard);
+    pCanvasPage->SetCanvasPage();
+    mpCanvasPage = pCanvasPage;
+
+    populatePagePreviewsGrid();
 
     return pCanvasPage->GetPageNum() / 2;
 }
@@ -1466,4 +1482,71 @@ sd::UndoManager* SdDrawDocument::GetUndoManager() const
     return mpDocSh ? dynamic_cast< sd::UndoManager* 
>(mpDocSh->GetUndoManager()) : nullptr;
 }
 
+static int calculateGridColumns(const sal_uInt16 nCnt)
+{
+    int n = static_cast<int>(nCnt);
+    int srqtN = std::round(std::sqrt(n));
+
+    return (n % srqtN) ? srqtN + 1 : srqtN;
+}
+
+void SdDrawDocument::populatePagePreviewsGrid()
+{
+    sal_uInt16 nPageCnt = GetSdPageCount(PageKind::Standard) - 1; // don't 
count the canvas page
+    sal_uInt16 nTotalCol = 
static_cast<sal_uInt16>(calculateGridColumns(nPageCnt));
+    sal_uInt16 nTotalRow = nPageCnt / nTotalCol + (nPageCnt % nTotalCol ? 1 : 
0);
+
+    // width and height of a standard 16:9 page
+    sal_uInt16 nWidth = 28000;
+    sal_uInt16 nHeight = 15750;
+
+    // the factor by which width & height will be divided
+    sal_uInt8 nFactor = 3;
+
+    // TODO: this should also vary based on the available space
+    sal_uInt16 nGapWidth = 500;
+    sal_uInt16 nGapHeight = 500;
+
+    ::tools::Long nPreviewWidth;
+    ::tools::Long nPreviewHeight;
+    ::tools::Long nTotalGridWidth;
+    ::tools::Long nTotalGridHeight;
+    do
+    {
+        nTotalGridWidth = (nTotalCol - 1) * nGapWidth;
+        nTotalGridHeight = (nTotalRow - 1) * nGapHeight;
+        nPreviewWidth = (nWidth / nFactor);
+        nPreviewHeight = (nHeight / nFactor);
+        nTotalGridWidth += nPreviewWidth * nTotalCol;
+        nTotalGridHeight += nPreviewHeight * nTotalRow;
+        nFactor++;
+    }
+    while (nTotalGridWidth >= mpCanvasPage->GetWidth() ||
+            nTotalGridHeight >= mpCanvasPage->GetHeight());
+
+    ::tools::Long nY = (mpCanvasPage->GetHeight() - nTotalGridHeight) / 2;
+    for (sal_uInt16 nRow = 0; nRow < nTotalRow; nRow++)
+    {
+        ::tools::Long nX = (mpCanvasPage->GetWidth() - nTotalGridWidth) / 2;
+        for (sal_uInt16 nCol = 0; nCol < nTotalCol; nCol++)
+        {
+            sal_uInt16 nCurrentPageIndex = nTotalCol * nRow + nCol;
+            if (nCurrentPageIndex == nPageCnt)
+                return;
+            SdPage* pPage = GetSdPage(nCurrentPageIndex, PageKind::Standard);
+            if (pPage->IsCanvasPage()) break;
+            const sal_uInt16 nPageNum = pPage->GetPageNum();
+            mpCanvasPage->CreatePresObj(PresObjKind::PagePreview, true, 
::tools::Rectangle(Point(nX, nY), Size(nPreviewWidth, nPreviewHeight)), 
OUString(), nPageNum);
+            nX += nPreviewWidth + nGapWidth;
+        }
+        nY += nPreviewHeight + nGapHeight;
+    }
+}
+
+void SdDrawDocument::updateCanvasPreviewsGrid()
+{
+    SdrPage* pPage = mpCanvasPage.get();
+    pPage->ClearSdrObjList();
+    populatePagePreviewsGrid();
+}
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/sdpage.cxx b/sd/source/core/sdpage.cxx
index a5cea90e493f..1918e12b2827 100644
--- a/sd/source/core/sdpage.cxx
+++ b/sd/source/core/sdpage.cxx
@@ -285,7 +285,7 @@ void SdPage::EnsureMasterPageDefaultBackground()
 
 /** creates a presentation object with the given PresObjKind on this page. A 
user call will be set
 */
-SdrObject* SdPage::CreatePresObj(PresObjKind eObjKind, bool bVertical, const 
::tools::Rectangle& rRect, const OUString& rCustomPrompt)
+SdrObject* SdPage::CreatePresObj(PresObjKind eObjKind, bool bVertical, const 
::tools::Rectangle& rRect, const OUString& rCustomPrompt, const sal_uInt16 
nPagePreviewNum)
 {
     SfxUndoManager* pUndoManager(static_cast< SdDrawDocument& 
>(getSdrModelFromSdrPage()).GetUndoManager());
     const bool bUndo = pUndoManager && pUndoManager->IsInListAction() && 
IsInserted();
@@ -428,6 +428,22 @@ SdrObject* SdPage::CreatePresObj(PresObjKind eObjKind, 
bool bVertical, const ::t
         }
         break;
 
+        case PresObjKind::PagePreview:
+        {
+            if (nPagePreviewNum < getSdrModelFromSdrPage().GetPageCount())
+            {
+                pSdrObj = new SdrPageObj(getSdrModelFromSdrPage(), 
getSdrModelFromSdrPage().GetPage(nPagePreviewNum));
+            }
+            else
+            {
+                pSdrObj = new SdrPageObj(getSdrModelFromSdrPage());
+            }
+            pSdrObj->SetMarkProtect(false);
+            pSdrObj->SetResizeProtect(false);
+            pSdrObj->SetMoveProtect(false);
+        }
+        break;
+
         case PresObjKind::Header:
         case PresObjKind::Footer:
         case PresObjKind::DateTime:
@@ -916,7 +932,7 @@ const o3tl::enumarray<PresObjKind, const char*> 
PresObjKindVector = {
     "PRESOBJ_TEXT" ,"PRESOBJ_GRAPHIC" , "PRESOBJ_OBJECT",
     "PRESOBJ_CHART", "PRESOBJ_ORGCHART", "PRESOBJ_TABLE",
     "PRESOBJ_PAGE", "PRESOBJ_HANDOUT",
-    "PRESOBJ_NOTES","PRESOBJ_HEADER", "PRESOBJ_FOOTER",
+    "PRESOBJ_NOTES", "PRESOBJ_PAGEPREVIEW", "PRESOBJ_HEADER", "PRESOBJ_FOOTER",
     "PRESOBJ_DATETIME", "PRESOBJ_SLIDENUMBER", "PRESOBJ_CALC",
     "PRESOBJ_MEDIA"
 };
diff --git a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx 
b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx
index 04f6f57ea3ce..00976414946b 100644
--- a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx
+++ b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx
@@ -251,7 +251,7 @@ void SlotManager::FuTemporary (SfxRequest& rRequest)
         case SID_INSERT_CANVAS_SLIDE:
         {
             SdDrawDocument* pDoc = pShell->GetDoc();
-            sal_uInt16 nCanvasPageIndex = pDoc->InsertCanvasPage();
+            sal_uInt16 nCanvasPageIndex = pDoc->GetOrInsertCanvasPage();
             SdPage* pCanvasPage = 
static_cast<SdPage*>(pDoc->GetPage(nCanvasPageIndex));
 
             view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
diff --git a/sd/source/ui/unoidl/unopage.cxx b/sd/source/ui/unoidl/unopage.cxx
index 40e48670955c..201fe8eca737 100644
--- a/sd/source/ui/unoidl/unopage.cxx
+++ b/sd/source/ui/unoidl/unopage.cxx
@@ -1480,6 +1480,9 @@ Reference< drawing::XShape >  
SdGenericDrawPage::CreateShape(SdrObject *pObj) co
             case PresObjKind::Handout:
                 aShapeType += "HandoutShape";
                 break;
+            case PresObjKind::PagePreview:
+                aShapeType += "PageShape";
+                break;
             case PresObjKind::Notes:
                 aShapeType += "NotesShape";
                 break;
diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx
index 626677a63bf7..3c590da5d15a 100644
--- a/sd/source/ui/view/drviews2.cxx
+++ b/sd/source/ui/view/drviews2.cxx
@@ -1401,7 +1401,7 @@ void DrawViewShell::FuTemporary(SfxRequest& rReq)
         break;
         case SID_INSERT_CANVAS_SLIDE:
         {
-            sal_uInt16 nCanvasPageIndex = GetDoc()->InsertCanvasPage();
+            sal_uInt16 nCanvasPageIndex = GetDoc()->GetOrInsertCanvasPage();
             Cancel(); // Don't know what this does
             SwitchPage(nCanvasPageIndex);
             rReq.Done();

Reply via email to