officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu |    
8 +
 sd/inc/app.hrc                                                           |    
1 
 sd/inc/drawdoc.hxx                                                       |    
4 
 sd/sdi/_drvwsh.sdi                                                       |    
5 
 sd/sdi/sdraw.sdi                                                         |   
17 ++
 sd/source/core/drawdoc2.cxx                                              |   
79 +++++++++-
 sd/source/ui/view/drviews2.cxx                                           |   
10 +
 7 files changed, 123 insertions(+), 1 deletion(-)

New commits:
commit b7992d7a8f0a6ea747ff76e25582de259a4e2868
Author:     Mohit Marathe <[email protected]>
AuthorDate: Fri Oct 24 12:34:55 2025 +0530
Commit:     Michael Stahl <[email protected]>
CommitDate: Thu Nov 6 19:00:56 2025 +0100

    sd: add support for shuffling slides from canvas page
    
    added .uno:ReshufflePages which when executed will re-order the pages
    based on the position of their previews on the canvas page.
    
    Sorting logic:
    1. Sort the previews based on their y-center
    2. Form a row if the y-centers are within a tolerance limit
    3. Sort the row based on their x-center (also considering RTL locale)
    4. Repeat for each rows
    
    Signed-off-by: Mohit Marathe <[email protected]>
    Change-Id: If654e0cc14686aed2ad6cd69f2dc81249924ee2c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192940
    Reviewed-by: Michael Stahl <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git 
a/officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu 
b/officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu
index 3b53ffb9e7e1..65dafd620765 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu
@@ -2447,6 +2447,14 @@
           <value>1</value>
         </prop>
       </node>
+      <node oor:name=".uno:ReshufflePages" oor:op="replace">
+        <prop oor:name="Label" oor:type="xs:string">
+          <value xml:lang="en-US">Re-order pages</value>
+        </prop>
+        <prop oor:name="Properties" oor:type="xs:int">
+          <value>1</value>
+        </prop>
+      </node>
       <node oor:name=".uno:AssignLayout?WhatLayout:long=20" oor:op="replace">
         <prop oor:name="Label" oor:type="xs:string">
           <value xml:lang="en-US">Blank Slide</value>
diff --git a/sd/inc/app.hrc b/sd/inc/app.hrc
index 16433cd14ec8..1b63519f326e 100644
--- a/sd/inc/app.hrc
+++ b/sd/inc/app.hrc
@@ -377,6 +377,7 @@
     // FREE
 #define SID_INSERTPAGE_QUICK                (SID_SD_START+352)
 #define SID_INSERT_CANVAS_SLIDE             (SID_SD_START+353)
+#define SID_SHUFFLE_PAGES                   (SID_SD_START+354)
     // FREE
 #define SID_INSERT_FLD_PAGE_TITLE           (SID_SD_START+356)
 #define SID_INSERT_FLD_DATE_VAR             (SID_SD_START+357)
diff --git a/sd/inc/drawdoc.hxx b/sd/inc/drawdoc.hxx
index f08c9cdcabbe..46cf1007113c 100644
--- a/sd/inc/drawdoc.hxx
+++ b/sd/inc/drawdoc.hxx
@@ -1100,6 +1100,10 @@ public:
         bool bUndo = true,
         const OUString& sNewName = OUString());
 
+    /** Re-order the pages based on the position of their previews on canvas 
page.
+     */
+    void ReshufflePages();
+
 private:
 
     void UpdatePageRelativeURLsImpl(const std::function<void(const 
SvxFieldItem & rFieldItem, editeng::SvxFieldItemUpdater& rFieldItemUpdater)>& 
rItemCallback);
diff --git a/sd/sdi/_drvwsh.sdi b/sd/sdi/_drvwsh.sdi
index d934a9f12b10..d5e9fb31cfd9 100644
--- a/sd/sdi/_drvwsh.sdi
+++ b/sd/sdi/_drvwsh.sdi
@@ -165,6 +165,11 @@ interface DrawView
         ExecMethod = FuTemporary ;
         StateMethod = GetMenuState ;
     ]
+    SID_SHUFFLE_PAGES
+    [
+        ExecMethod = FuTemporary ;
+        StateMethod = GetMenuState ;
+    ]
     SID_HYPERLINK_SETLINK // ole : no, status : no
     [
         ExecMethod = FuTemporary ;
diff --git a/sd/sdi/sdraw.sdi b/sd/sdi/sdraw.sdi
index 819ff5f31cd0..aa3dafb09349 100644
--- a/sd/sdi/sdraw.sdi
+++ b/sd/sdi/sdraw.sdi
@@ -2246,6 +2246,23 @@ SfxVoidItem InsertCanvasSlide SID_INSERT_CANVAS_SLIDE
     GroupId = SfxGroupId::Insert;
 ]
 
+SfxVoidItem ReshufflePages SID_SHUFFLE_PAGES
+()
+[
+    AutoUpdate = FALSE,
+    FastCall = FALSE,
+    ReadOnlyDoc = FALSE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+    AccelConfig = TRUE,
+    MenuConfig = TRUE,
+    ToolBoxConfig = TRUE,
+    GroupId = SfxGroupId::Modify;
+]
+
 SfxVoidItem InsertPageField SID_INSERT_FLD_PAGE
 ()
 [
diff --git a/sd/source/core/drawdoc2.cxx b/sd/source/core/drawdoc2.cxx
index a32499255b55..786932b8bf04 100644
--- a/sd/source/core/drawdoc2.cxx
+++ b/sd/source/core/drawdoc2.cxx
@@ -17,6 +17,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
+#include <algorithm>
 #include <vcl/settings.hxx>
 
 #include <sal/log.hxx>
@@ -1471,6 +1472,79 @@ void SdDrawDocument::SetupNewPage (
     }
 }
 
+void SdDrawDocument::ReshufflePages()
+{
+    SdrObjList* pObjList = mpCanvasPage.get();
+    std::vector<SdrPageObj*> aPageOrder;
+
+    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);
+            aPageOrder.push_back(pPageObj);
+        }
+    }
+
+    // Sort the previews by comparing their y-center (compare x-center as a 
tie-breaker)
+    std::sort(aPageOrder.begin(), aPageOrder.end(),
+        [](const SdrPageObj* pObj1, const SdrPageObj* pObj2) {
+              const ::tools::Rectangle& rect1 = pObj1->GetSnapRect();
+              const ::tools::Rectangle& rect2 = pObj2->GetSnapRect();
+              const ::tools::Long yCenter1 = (rect1.Top() + rect1.Bottom()) / 
2;
+              const ::tools::Long yCenter2 = (rect2.Top() + rect2.Bottom()) / 
2;
+
+              if (yCenter1 != yCenter2)
+                  return yCenter1 < yCenter2;
+
+              const ::tools::Long xCenter1 = (rect1.Left() + rect1.Right()) / 
2;
+              const ::tools::Long xCenter2 = (rect2.Left() + rect2.Right()) / 
2;
+              return xCenter1 < xCenter2;
+        }
+    );
+
+    const bool bIsRTL = AllSettings::GetLayoutRTL();
+
+    // Form a row, and sort them based on their x-center
+    for (size_t rowStart = 0; rowStart < aPageOrder.size();)
+    {
+        const ::tools::Rectangle& rect0 = aPageOrder[rowStart]->GetSnapRect();
+        const ::tools::Long top = rect0.Top();
+        const ::tools::Long bottom = rect0.Bottom();
+
+        size_t rowEnd = rowStart;
+        while (rowEnd < aPageOrder.size())
+        {
+            const ::tools::Rectangle& rect = aPageOrder[rowEnd]->GetSnapRect();
+            const ::tools::Long yCenter = (rect.Top() + rect.Bottom()) / 2;
+
+            if (yCenter < top || yCenter > bottom)
+                break;
+            rowEnd++;
+        }
+
+        std::stable_sort(aPageOrder.begin() + rowStart, aPageOrder.begin() + 
rowEnd,
+            [&bIsRTL](const SdrPageObj* pObj1, const SdrPageObj* pObj2) {
+            const ::tools::Rectangle& rect1 = pObj1->GetSnapRect();
+            const ::tools::Rectangle& rect2 = pObj2->GetSnapRect();
+            const ::tools::Long xCenter1 = (rect1.Left() + rect1.Right()) / 2;
+            const ::tools::Long xCenter2 = (rect2.Left() + rect2.Right()) / 2;
+
+            return bIsRTL ? (xCenter1 > xCenter2) : (xCenter1 < xCenter2);
+        });
+    }
+
+    for (size_t i = 0; i < aPageOrder.size(); i++)
+    {
+        SdPage* pPage = 
static_cast<SdPage*>(aPageOrder[i]->GetReferencedPage());
+        sal_uInt16 nCurrentPageNum = pPage->GetPageNum();
+        sal_uInt16 nTargetPageNum = 2 * i + 1;
+        MovePage(nCurrentPageNum, nTargetPageNum); // Standard page
+        MovePage(nCurrentPageNum + 1, nTargetPageNum + 1); // Notes page
+    }
+}
+
 sal_uInt16 SdDrawDocument::GetOrInsertCanvasPage()
 {
     if (HasCanvasPage())
@@ -1479,7 +1553,10 @@ sal_uInt16 SdDrawDocument::GetOrInsertCanvasPage()
     sal_uInt16 nLastPageNum = GetSdPageCount(PageKind::Standard);
     SdPage* pLastStandardPage = GetSdPage(nLastPageNum - 1, 
PageKind::Standard);
 
-    sal_uInt16 nCanvasPageNum = CreatePage(pLastStandardPage, 
PageKind::Standard, u"Canvas Page"_ustr, u"Canvas notes page"_ustr, 
AutoLayout::AUTOLAYOUT_NONE, AutoLayout::AUTOLAYOUT_NONE, false, true, 
pLastStandardPage->GetPageNum() + 2);
+    sal_uInt16 nCanvasPageNum = CreatePage(pLastStandardPage, 
PageKind::Standard,
+                                           u"Canvas Page"_ustr, u"Canvas notes 
page"_ustr,
+                                           AutoLayout::AUTOLAYOUT_NONE, 
AutoLayout::AUTOLAYOUT_NONE,
+                                           false, true, 
pLastStandardPage->GetPageNum() + 2);
 
     SdPage* pCanvasPage = GetSdPage(nCanvasPageNum, PageKind::Standard);
     if (!pCanvasPage)
diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx
index 47264a5f0b20..4e4b2bb3dba7 100644
--- a/sd/source/ui/view/drviews2.cxx
+++ b/sd/source/ui/view/drviews2.cxx
@@ -1402,6 +1402,16 @@ void DrawViewShell::FuTemporary(SfxRequest& rReq)
         }
         break;
 
+        case SID_SHUFFLE_PAGES:
+        {
+            if (!GetDoc()->HasCanvasPage())
+                break;
+            GetDoc()->ReshufflePages();
+            Cancel();
+            rReq.Done();
+        }
+        break;
+
         case SID_DUPLICATE_PAGE:
         {
             auto slideSorter = 
sd::slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase());

Reply via email to