sc/qa/unit/tiledrendering/SheetViewTest.cxx |   72 ++++++++++++++++++++++++++++
 sc/source/core/data/SheetViewManager.cxx    |    1 
 sc/source/ui/inc/viewdata.hxx               |    2 
 sc/source/ui/view/viewdata.cxx              |   31 +++++++-----
 sc/source/ui/view/viewfun3.cxx              |   18 +++++--
 5 files changed, 107 insertions(+), 17 deletions(-)

New commits:
commit e6cf2c90f14097a1c2ebbd013ccb06276054ad17
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Mon Aug 11 17:27:18 2025 +0200
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Fri Sep 12 20:57:01 2025 +0200

    sc: test ".uno:RemoveSheetView" to remove current sheet view
    
    Also fix issues found with the test.
    
    We need to broadcast that the table was inserted or it won't
    properly be accounted for ViewData, which will cause an assert
    to fail.
    
    Change-Id: I0c086e16090d40e8a663217b36d04d4de99966cb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189386
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/sc/qa/unit/tiledrendering/SheetViewTest.cxx 
b/sc/qa/unit/tiledrendering/SheetViewTest.cxx
index 834bfe2d8ea1..b11d898c4882 100644
--- a/sc/qa/unit/tiledrendering/SheetViewTest.cxx
+++ b/sc/qa/unit/tiledrendering/SheetViewTest.cxx
@@ -186,6 +186,78 @@ CPPUNIT_TEST_FIXTURE(SheetViewTest, 
testSyncValuesBetweenMainSheetAndSheetView)
     CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA2SheetView));
 }
 
+CPPUNIT_TEST_FIXTURE(SheetViewTest, testRemoveSheetView)
+{
+    // Create two views, and leave the second one current.
+    ScModelObj* pModelObj = createDoc("SheetView_AutoFilter.ods");
+    
pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    ScDocument* pDocument = pModelObj->GetDocument();
+
+    // Setup views
+    ScTestViewCallback aView1;
+    ScTabViewShell* pTabView1 = aView1.getTabViewShell();
+    SfxLokHelper::createView();
+    Scheduler::ProcessEventsToIdle();
+    ScTestViewCallback aView2;
+    ScTabViewShell* pTabView2 = aView2.getTabViewShell();
+    CPPUNIT_ASSERT(pTabView1 != pTabView2);
+    CPPUNIT_ASSERT(aView1.getViewID() != aView2.getViewID());
+
+    // Switch to View1
+    SfxLokHelper::setView(aView1.getViewID());
+    Scheduler::ProcessEventsToIdle();
+
+    // Create a new sheet view for view 1
+    dispatchCommand(mxComponent, u".uno:NewSheetView"_ustr, {});
+    Scheduler::ProcessEventsToIdle();
+
+    // Check AutoFilter values for each view
+    CPPUNIT_ASSERT_EQUAL(u"4"_ustr, pTabView1->GetCurrentString(0, 1));
+    CPPUNIT_ASSERT_EQUAL(u"5"_ustr, pTabView1->GetCurrentString(0, 2));
+    CPPUNIT_ASSERT_EQUAL(u"3"_ustr, pTabView1->GetCurrentString(0, 3));
+    CPPUNIT_ASSERT_EQUAL(u"7"_ustr, pTabView1->GetCurrentString(0, 4));
+
+    CPPUNIT_ASSERT_EQUAL(u"4"_ustr, pTabView2->GetCurrentString(0, 1));
+    CPPUNIT_ASSERT_EQUAL(u"5"_ustr, pTabView2->GetCurrentString(0, 2));
+    CPPUNIT_ASSERT_EQUAL(u"3"_ustr, pTabView2->GetCurrentString(0, 3));
+    CPPUNIT_ASSERT_EQUAL(u"7"_ustr, pTabView2->GetCurrentString(0, 4));
+
+    // Switch to View2
+    SfxLokHelper::setView(aView2.getViewID());
+    Scheduler::ProcessEventsToIdle();
+
+    // Sort AutoFilter descending
+    dispatchCommand(mxComponent, u".uno:SortDescending"_ustr, {});
+    Scheduler::ProcessEventsToIdle();
+
+    // Check values are sorted for view 2
+    CPPUNIT_ASSERT_EQUAL(u"7"_ustr, pTabView2->GetCurrentString(0, 1));
+    CPPUNIT_ASSERT_EQUAL(u"5"_ustr, pTabView2->GetCurrentString(0, 2));
+    CPPUNIT_ASSERT_EQUAL(u"4"_ustr, pTabView2->GetCurrentString(0, 3));
+    CPPUNIT_ASSERT_EQUAL(u"3"_ustr, pTabView2->GetCurrentString(0, 4));
+
+    // Sheet view must be present
+    auto pSheetViewManager = pDocument->GetSheetViewManager(0);
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pSheetViewManager->getSheetViews().size());
+
+    // There should be 2 tables
+    CPPUNIT_ASSERT_EQUAL(SCTAB(2), pDocument->GetTableCount());
+
+    // Switch to View1
+    SfxLokHelper::setView(aView1.getViewID());
+    Scheduler::ProcessEventsToIdle();
+
+    // We remove the current sheet view
+    dispatchCommand(mxComponent, u".uno:RemoveSheetView"_ustr, {});
+    Scheduler::ProcessEventsToIdle();
+
+    // No more sheet view
+    CPPUNIT_ASSERT_EQUAL(size_t(0), pSheetViewManager->getSheetViews().size());
+
+    // Only 1 table left
+    CPPUNIT_ASSERT_EQUAL(SCTAB(1), pDocument->GetTableCount());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/SheetViewManager.cxx 
b/sc/source/core/data/SheetViewManager.cxx
index e4e3858fbcdc..a57ea9666025 100644
--- a/sc/source/core/data/SheetViewManager.cxx
+++ b/sc/source/core/data/SheetViewManager.cxx
@@ -26,6 +26,7 @@ bool SheetViewManager::remove(SheetViewID nID)
     if (nID >= 0 && o3tl::make_unsigned(nID) < maViews.size())
     {
         maViews.erase(maViews.begin() + nID);
+        return true;
     }
     return false;
 }
diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx
index 569b2d19f409..b47865ec5ec7 100644
--- a/sc/source/ui/view/viewfun3.cxx
+++ b/sc/source/ui/view/viewfun3.cxx
@@ -64,6 +64,7 @@
 #include <clipoptions.hxx>
 #include <gridwin.hxx>
 #include <SheetView.hxx>
+#include <uiitems.hxx>
 #include <com/sun/star/util/XCloneable.hpp>
 
 using namespace com::sun::star;
@@ -2068,6 +2069,9 @@ void ScViewFunc::MakeNewSheetView()
     SCTAB nSheetViewTab = nTab + 1;
     if (rDocument.CopyTab(nTab, nSheetViewTab))
     {
+        GetViewData().GetDocShell().Broadcast(ScTablesHint(SC_TAB_INSERTED, 
nSheetViewTab));
+        SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScTablesChanged));
+
         // Add and register the created sheet view
         rDocument.SetSheetView(nSheetViewTab, true);
         sc::SheetViewID nSheetViewID = rDocument.CreateNewSheetView(nTab, 
nSheetViewTab);
@@ -2076,6 +2080,9 @@ void ScViewFunc::MakeNewSheetView()
         // Update
         GetViewData().SetTabNo(nSheetViewTab); // force add the sheet view tab
         GetViewData().SetTabNo(nTab); // then change back to the current tab
+
+        ScDocShell& rDocSh = GetViewData().GetDocShell();
+        rDocSh.PostPaintGridAll();
         PaintExtras(); // update Tab Control
     }
 }
@@ -2086,18 +2093,19 @@ void ScViewFunc::RemoveCurrentSheetView()
     if (nSheetViewID == sc::DefaultSheetViewID)
         return;
 
-    SCTAB nTab = GetViewData().GetTabNumber();
     ScDocument& rDocument = GetViewData().GetDocument();
-    SCTAB nSheetViewTab = rDocument.GetSheetViewNumber(nTab, nSheetViewID);
-
+    SCTAB nTab = GetViewData().GetTabNumber();
     auto pSheetManager = rDocument.GetSheetViewManager(nTab);
+    if (!pSheetManager)
+        return;
+
+    SCTAB nSheetViewTab = rDocument.GetSheetViewNumber(nTab, nSheetViewID);
     pSheetManager->remove(nSheetViewID);
     GetViewData().SetSheetViewID(sc::DefaultSheetViewID);
     GetViewData().SetTabNo(nTab);
     GetViewData().GetDocFunc().DeleteTable(nSheetViewTab, true);
 
-    ScDocShell& rDocSh = GetViewData().GetDocShell();
-    rDocSh.PostPaintGridAll();
+    GetViewData().GetDocShell().PostPaintGridAll();
     PaintExtras();
 }
 
commit 202a1fead00d235c2b7e330d906e852a0e597380
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Sep 4 17:10:53 2025 +0200
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Fri Sep 12 20:56:51 2025 +0200

    sc: fix scrolling in sheet view, add check if a tab no. is valid
    
    Scrolling needs to use the tab number of the actual sheet we are
    currently using in the UI. The same goes for the grid.
    
    Added a function to check if a tab number is currently valid, to
    reduce duplication and to make the code a bit more readable.
    
    Change-Id: I4e76a61efaa3632b020cfd75ea77c0809f08f6da
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190598
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    Tested-by: Jenkins

diff --git a/sc/source/ui/inc/viewdata.hxx b/sc/source/ui/inc/viewdata.hxx
index 2e0e3b8270c2..86021bf92bf0 100644
--- a/sc/source/ui/inc/viewdata.hxx
+++ b/sc/source/ui/inc/viewdata.hxx
@@ -349,6 +349,8 @@ private:
     void          UpdateCurrentTab();
     ScViewDataTable* FetchTableData(SCTAB) const;
 
+    bool IsValidTabNumber(SCTAB nTabNumber) const;
+
 public:
     ScViewData( ScDocShell& rDocSh, ScTabViewShell* pViewSh );
     ~ScViewData() COVERITY_NOEXCEPT_FALSE;
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index 577b0a085f7d..4ff40391ca6e 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -843,9 +843,15 @@ ScViewData::~ScViewData() COVERITY_NOEXCEPT_FALSE
 
 ScDBFunc* ScViewData::GetView() const { return pView; }
 
+bool ScViewData::IsValidTabNumber(SCTAB nTabNumber) const
+{
+    return nTabNumber >= 0 || o3tl::make_unsigned(nTabNumber) < 
maTabData.size();
+}
+
 void ScViewData::UpdateCurrentTab()
 {
-    assert(0 <= mnTabNumber && o3tl::make_unsigned(mnTabNumber) < 
maTabData.size());
+    assert(IsValidTabNumber(GetTabNumber()));
+
     pThisTab = maTabData[mnTabNumber].get();
     while (!pThisTab)
     {
@@ -894,7 +900,8 @@ void ScViewData::InsertTabs( SCTAB nTab, SCTAB nNewSheets )
 
 void ScViewData::DeleteTab( SCTAB nTab )
 {
-    assert(nTab < static_cast<SCTAB>(maTabData.size()));
+    assert(IsValidTabNumber(nTab));
+
     maTabData.erase(maTabData.begin() + nTab);
 
     if (o3tl::make_unsigned(GetTabNumber()) >= maTabData.size())
@@ -1090,7 +1097,7 @@ void ScViewData::SetZoom( const Fraction& rNewX, const 
Fraction& rNewY, bool bAl
 void ScViewData::SetShowGrid( bool bShow )
 {
     CreateSelectedTabData();
-    maTabData[CurrentTabForData()]->bShowGrid = bShow;
+    maTabData[GetTabNumber()]->bShowGrid = bShow;
 }
 
 void ScViewData::RefreshZoom()
@@ -1411,7 +1418,7 @@ SCROW ScViewData::GetPosY( ScVSplitPos eWhich, SCTAB 
nForTab ) const
 
 ScViewDataTable* ScViewData::FetchTableData(SCTAB nTabIndex) const
 {
-    if (!ValidTab(nTabIndex) || (nTabIndex >= 
static_cast<SCTAB>(maTabData.size())))
+    if (!ValidTab(nTabIndex) || !IsValidTabNumber(nTabIndex))
         return nullptr;
     ScViewDataTable* pRet = maTabData[nTabIndex].get();
     SAL_WARN_IF(!pRet, "sc.viewdata", "ScViewData::FetchTableData: hidden 
sheet = " << nTabIndex);
@@ -2429,12 +2436,12 @@ Point ScViewData::GetScrPos( SCCOL nWhereX, SCROW 
nWhereY, ScSplitPos eWhich,
     }
 
     if (nForTab == -1)
-        nForTab = CurrentTabForData();
-    bool bForCurTab = (nForTab == CurrentTabForData());
+        nForTab = GetTabNumber();
+    bool bForCurTab = (nForTab == GetTabNumber());
     if (!bForCurTab && (!ValidTab(nForTab) || (nForTab >= 
static_cast<SCTAB>(maTabData.size()))))
     {
         SAL_WARN("sc.viewdata", "ScViewData::GetScrPos :  invalid nForTab = " 
<< nForTab);
-        nForTab = CurrentTabForData();
+        nForTab = GetTabNumber();
         bForCurTab = true;
     }
 
@@ -4070,7 +4077,7 @@ bool ScViewData::IsOle() const
 bool ScViewData::UpdateFixX( SCTAB nTab ) // true = value changed
 {
     if (!ValidTab(nTab)) // Default
-        nTab = CurrentTabForData(); // current table
+        nTab = GetTabNumber(); // current table
 
     if (!pView || maTabData[nTab]->eHSplitMode != SC_SPLIT_FIX)
         return false;
@@ -4094,7 +4101,7 @@ bool ScViewData::UpdateFixX( SCTAB nTab ) // true = value 
changed
     if (nNewPos != maTabData[nTab]->nHSplitPos)
     {
         maTabData[nTab]->nHSplitPos = nNewPos;
-        if (nTab == CurrentTabForData())
+        if (nTab == GetTabNumber())
             RecalcPixPos();                 // should not be needed
         return true;
     }
@@ -4105,7 +4112,7 @@ bool ScViewData::UpdateFixX( SCTAB nTab ) // true = value 
changed
 bool ScViewData::UpdateFixY( SCTAB nTab ) // true = value changed
 {
     if (!ValidTab(nTab)) // Default
-        nTab = CurrentTabForData(); // current table
+        nTab = GetTabNumber(); // current table
 
     if (!pView || maTabData[nTab]->eVSplitMode != SC_SPLIT_FIX)
         return false;
@@ -4129,7 +4136,7 @@ bool ScViewData::UpdateFixY( SCTAB nTab ) // true = value 
changed
     if (nNewPos != maTabData[nTab]->nVSplitPos)
     {
         maTabData[nTab]->nVSplitPos = nNewPos;
-        if (nTab == CurrentTabForData())
+        if (nTab == GetTabNumber())
             RecalcPixPos();                 // should not be needed
         return true;
     }
@@ -4277,7 +4284,7 @@ bool ScViewData::SetLOKSheetFreezeIndex(const SCCOLROW 
nFreezeIndex, bool bIsCol
     {
         nForTab = CurrentTabForData();
     }
-    else if (!ValidTab(nForTab) || (nForTab >= 
static_cast<SCTAB>(maTabData.size())))
+    else if (!ValidTab(nForTab) || !IsValidTabNumber(nForTab))
     {
         SAL_WARN("sc.viewdata", "ScViewData::SetLOKSheetFreezeIndex :  invalid 
nForTab = " << nForTab);
         return false;

Reply via email to