sc/inc/SheetView.hxx | 3 sc/inc/document.hxx | 3 sc/qa/unit/tiledrendering/SheetViewTest.cxx | 87 ++++++++++++ sc/source/core/data/SheetView.cxx | 6 sc/source/core/data/document10.cxx | 10 + sc/source/ui/inc/viewfunc.hxx | 2 sc/source/ui/view/viewfun3.cxx | 7 - sc/source/ui/view/viewfunc.cxx | 195 ++++++++++++++++++---------- 8 files changed, 242 insertions(+), 71 deletions(-)
New commits: commit 499ad5f166ece962fa17519b106f649023c58ad0 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Tue Jul 22 23:58:02 2025 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Sep 11 09:21:42 2025 +0200 sc: sync a change to the sheet view and the default view Change-Id: I58486928c4655da9385e58210cd707250946b16d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188192 Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> Tested-by: Jenkins (cherry picked from commit 945e527680d9701550a65f376aa12361dd1722d7) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190762 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/sc/inc/SheetView.hxx b/sc/inc/SheetView.hxx index abb0a3278ca7..cc29eb196423 100644 --- a/sc/inc/SheetView.hxx +++ b/sc/inc/SheetView.hxx @@ -10,6 +10,7 @@ #pragma once #include <vector> #include "SheetViewTypes.hxx" +#include "types.hxx" class ScTable; @@ -30,6 +31,7 @@ public: SheetView(ScTable* pTable); ScTable* getTablePointer() const; + SCTAB getTableNumber() const; /** A sheet view is valid if the pointer to the table is set */ bool isValid() const; @@ -49,6 +51,7 @@ public: /** Returns a sheet view for the ID. */ SheetView get(SheetViewID nID); + std::vector<SheetView> const& getSheetViews() { return maViews; } }; } diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 61c914f532bc..421767370a4c 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -120,7 +120,7 @@ class ExternalDataMapper; class Sparkline; class SparklineGroup; class SparklineList; - +class SheetViewManager; } class Fraction; @@ -2403,6 +2403,7 @@ public: /** Return the sheet view table for the ID */ SCTAB GetSheetViewNumber(SCTAB nTab, sc::SheetViewID nID); + std::shared_ptr<sc::SheetViewManager> GetSheetViewManager(SCTAB nTable); bool IsSheetView(SCTAB nTab) const; void SetSheetView(SCTAB nTab, bool bSheetView); diff --git a/sc/qa/unit/tiledrendering/SheetViewTest.cxx b/sc/qa/unit/tiledrendering/SheetViewTest.cxx index 6ab45f35e005..4907d970c004 100644 --- a/sc/qa/unit/tiledrendering/SheetViewTest.cxx +++ b/sc/qa/unit/tiledrendering/SheetViewTest.cxx @@ -86,6 +86,93 @@ CPPUNIT_TEST_FIXTURE(SheetViewTest, testSheetViewAutoFilter) CPPUNIT_ASSERT_EQUAL(u"7"_ustr, pTabView1->GetCurrentString(0, 4)); } +CPPUNIT_TEST_FIXTURE(SheetViewTest, testSyncValuesBetweenMainSheetAndSheetView) +{ + // Create two views, and leave the second one current. + ScModelObj* pModelObj = createDoc("empty.ods"); + pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + ScDocument* pDocument = pModelObj->GetDocument(); + + // Setup 2 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()); + + // Setup data + // String in A1, and a formula in A2 + ScAddress aA1(0, 0, 0); + ScAddress aA1SheetView(0, 0, 1); + + ScAddress aA2(0, 1, 0); + ScAddress aA2SheetView(0, 1, 1); + + typeCharsInCell(std::string("ABCD"), aA1.Col(), aA1.Row(), pTabView1, pModelObj); + typeCharsInCell(std::string("=UPPER(\"A\"&\"b\"&\"C\"&\"d\")"), aA2.Col(), aA2.Row(), pTabView1, + pModelObj); + + CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pDocument->GetString(aA1)); + CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pDocument->GetString(aA2)); + + // Check what the View1 and View2 sees + CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pTabView1->GetCurrentString(aA1.Col(), aA1.Row())); + CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pTabView2->GetCurrentString(aA1.Col(), aA1.Row())); + + CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pTabView1->GetCurrentString(aA2.Col(), aA2.Row())); + CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pTabView2->GetCurrentString(aA2.Col(), aA2.Row())); + + // Create a sheet view in View2 + SfxLokHelper::setView(aView2.getViewID()); + Scheduler::ProcessEventsToIdle(); + dispatchCommand(mxComponent, u".uno:NewSheetView"_ustr, {}); + + // Change content in View1 with default view -> default view ro sheet view sync + SfxLokHelper::setView(aView1.getViewID()); + typeCharsInCell(std::string("XYZ"), aA1.Col(), aA1.Row(), pTabView1, pModelObj); + typeCharsInCell(std::string("=UPPER(\"x\"&\"Y\"&\"z\""), aA2.Col(), aA2.Row(), pTabView1, + pModelObj); + + // Check the content is synced + CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pTabView1->GetCurrentString(aA1.Col(), aA1.Row())); + CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pTabView2->GetCurrentString(aA1.Col(), aA1.Row())); + + CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pTabView1->GetCurrentString(aA2.Col(), aA2.Row())); + CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pTabView2->GetCurrentString(aA2.Col(), aA2.Row())); + + // Check the content directly in sheets + CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pDocument->GetString(aA1)); + CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pDocument->GetString(aA1SheetView)); + + CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pDocument->GetString(aA2)); + CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pDocument->GetString(aA2SheetView)); + + // Change content in the View2 with the sheet view -> sheet view to default view sync + SfxLokHelper::setView(aView2.getViewID()); + Scheduler::ProcessEventsToIdle(); + + typeCharsInCell(std::string("ABC123"), aA1.Col(), aA1.Row(), pTabView2, pModelObj); + typeCharsInCell(std::string("=UPPER(\"aBc\"&\"123\""), aA2.Col(), aA2.Row(), pTabView2, + pModelObj); + + // Check the content is synced + CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pTabView1->GetCurrentString(aA1.Col(), aA1.Row())); + CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pTabView2->GetCurrentString(aA1.Col(), aA1.Row())); + + CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pTabView1->GetCurrentString(aA2.Col(), aA2.Row())); + CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pTabView2->GetCurrentString(aA2.Col(), aA2.Row())); + + // Check the content directly in sheets + CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA1)); + CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA1SheetView)); + + CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA2)); + CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA2SheetView)); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/SheetView.cxx b/sc/source/core/data/SheetView.cxx index 05ae7a72cc70..d96719eb13ad 100644 --- a/sc/source/core/data/SheetView.cxx +++ b/sc/source/core/data/SheetView.cxx @@ -8,6 +8,7 @@ */ #include <SheetView.hxx> +#include <table.hxx> namespace sc { @@ -18,6 +19,11 @@ SheetView::SheetView(ScTable* pTable) ScTable* SheetView::getTablePointer() const { return mpTable; } bool SheetView::isValid() const { return mpTable; } +SCTAB SheetView::getTableNumber() const +{ + assert(mpTable); + return mpTable->GetTab(); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index 57eac290b43c..64df5c36af0e 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -1148,6 +1148,16 @@ sc::SheetViewID ScDocument::CreateNewSheetView(SCTAB nMainTable, SCTAB nSheetVie return -1; } +std::shared_ptr<sc::SheetViewManager> ScDocument::GetSheetViewManager(SCTAB nTable) +{ + if (ScTable* pTable = FetchTable(nTable)) + { + if (!pTable->IsSheetView()) + return pTable->GetSheetViewManager(); + } + return {}; +} + SCTAB ScDocument::GetSheetViewNumber(SCTAB nTab, sc::SheetViewID nID) { if (ScTable* pMainSheet = FetchTable(nTab)) diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx index 5352dc27d615..a075f7e68d45 100644 --- a/sc/source/ui/inc/viewfunc.hxx +++ b/sc/source/ui/inc/viewfunc.hxx @@ -78,7 +78,7 @@ public: ScViewFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ); ~ScViewFunc(); - SC_DLLPUBLIC const ScPatternAttr* GetSelectionPattern (); + SC_DLLPUBLIC const ScPatternAttr* GetSelectionPattern(); SC_DLLPUBLIC OUString GetCurrentString(SCCOL nCol, SCROW nRow); void GetSelectionFrame( diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx index 801444d763bb..959777729519 100644 --- a/sc/source/ui/view/viewfun3.cxx +++ b/sc/source/ui/view/viewfun3.cxx @@ -2069,10 +2069,15 @@ void ScViewFunc::MakeNewSheetView() SCTAB nSheetViewTab = nTab + 1; if (rDoc.CopyTab(nTab, nSheetViewTab)) { - SetTabNo(nSheetViewTab); + // Add and register the created sheet view rDoc.SetSheetView(nSheetViewTab, true); sc::SheetViewID nSheetViewID = rDoc.CreateNewSheetView(nTab, nSheetViewTab); GetViewData().SetSheetViewID(nSheetViewID); + + // Update + GetViewData().SetTabNo(nSheetViewTab); // force add the sheet view tab + GetViewData().SetTabNo(nTab); // then change back to the current tab + PaintExtras(); // update Tab Control } } diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx index b595eb253bac..e39f68db126a 100644 --- a/sc/source/ui/view/viewfunc.cxx +++ b/sc/source/ui/view/viewfunc.cxx @@ -77,6 +77,7 @@ #include <columnspanset.hxx> #include <stringutil.hxx> #include <SparklineList.hxx> +#include <SheetView.hxx> #include <memory> @@ -665,34 +666,10 @@ void ScViewFunc::EnterDataToCurrentCell(const OUString& rString, const EditTextO EnterData(nCol, nRow, nTab, rString, pData, bMatrixExpand); } -// input - undo OK -void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, - const OUString& rString, - const EditTextObject* pData, - bool bMatrixExpand ) +namespace +{ +bool checkFormula(ScDocument& rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString) { - ScDocument& rDoc = GetViewData().GetDocument(); - ScMarkData aMark(GetViewData().GetMarkData()); - bool bRecord = rDoc.IsUndoEnabled(); - SCTAB i; - - ScDocShell* pDocSh = GetViewData().GetDocShell(); - ScDocFunc &rFunc = GetViewData().GetDocFunc(); - std::shared_ptr<ScDocShellModificator> xModificator = std::make_shared<ScDocShellModificator>(*pDocSh); - - ScEditableTester aTester( rDoc, nCol,nRow, nCol,nRow, aMark ); - if (!aTester.IsEditable()) - { - ErrorMessage(aTester.GetMessageId()); - PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there - return; - } - - if ( bRecord ) - rFunc.EnterListAction( STR_UNDO_ENTERDATA ); - - bool bFormula = false; - // do not check formula if it is a text cell sal_uInt32 format = rDoc.GetNumberFormat( nCol, nRow, nTab ); SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); @@ -702,7 +679,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, if ( rString[0] == '=' ) { // handle as formula - bFormula = true; + return true; } else if ( rString[0] == '+' || rString[0] == '-' ) { @@ -722,65 +699,147 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, double fNumber = 0; if ( !pFormatter->IsNumberFormat( aString, format, fNumber ) ) { - bFormula = true; + return true; } } } } + return false; +} - bool bNumFmtChanged = false; - if ( bFormula ) - { // formula, compile with autoCorrection - i = aMark.GetFirstSelected(); - auto xPosPtr = std::make_shared<ScAddress>(nCol, nRow, i); - auto xCompPtr = std::make_shared<ScCompiler>(rDoc, *xPosPtr, rDoc.GetGrammar(), true, false); - std::unique_ptr<EditTextObject> xTextObject(pData ? pData->Clone() : nullptr); +void applyFormulaToCell(ScViewFunc& rViewFunc, SCCOL nCol, SCROW nRow, SCTAB nTab, OUString const& rString, + const EditTextObject* pData, std::shared_ptr<ScDocShellModificator> xModificator, + ScMarkData const& rMark, bool bMatrixExpand, bool bRecord, bool& rbNumFmtChanged) +{ + ScDocument& rDoc = rViewFunc.GetViewData().GetDocument(); - //2do: enable/disable autoCorrection via calcoptions - xCompPtr->SetAutoCorrection( true ); - if ( rString[0] == '+' || rString[0] == '-' ) - { - xCompPtr->SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK ); - } + // formula, compile with autoCorrection + auto xPosPtr = std::make_shared<ScAddress>(nCol, nRow, nTab); + auto xCompPtr = std::make_shared<ScCompiler>(rDoc, *xPosPtr, rDoc.GetGrammar(), true, false); + std::unique_ptr<EditTextObject> xTextObject(pData ? pData->Clone() : nullptr); + + //2do: enable/disable autoCorrection via calcoptions + xCompPtr->SetAutoCorrection( true ); + if ( rString[0] == '+' || rString[0] == '-' ) + { + xCompPtr->SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK ); + } + + OUString aFormula( rString ); + + FormulaProcessingContext context_instance { + std::move(xPosPtr), std::move(xCompPtr), xModificator, nullptr, + nullptr, std::move(xTextObject), rMark, rViewFunc, OUString(), + aFormula, rString, nCol, nRow, nTab, bMatrixExpand, rbNumFmtChanged, + bRecord + }; + + parseAndCorrectFormula(std::make_shared<FormulaProcessingContext>(context_instance)); +} - OUString aFormula( rString ); +void applyText(ScViewFunc& rViewFunc, SCCOL nCol, SCROW nRow, SCTAB nTab, OUString const& rString, bool& rbNumFmtChanged) +{ + ScViewData& rViewData = rViewFunc.GetViewData(); + ScDocument& rDoc = rViewData.GetDocument(); + ScDocShell& rDocSh = *rViewData.GetDocShell(); + ScFieldEditEngine& rEngine = rDoc.GetEditEngine(); + ScDocFunc& rFunc = rViewData.GetDocFunc(); - FormulaProcessingContext context_instance{ - std::move(xPosPtr), std::move(xCompPtr), std::move(xModificator), nullptr, - nullptr, std::move(xTextObject), std::move(aMark), *this, - OUString(), aFormula, rString, nCol, - nRow, nTab, bMatrixExpand, bNumFmtChanged, - bRecord - }; + bool bNumFmtSet = false; + const ScAddress aAddress(nCol, nRow, nTab); - parseAndCorrectFormula(std::make_shared<FormulaProcessingContext>(context_instance)); + // tdf#104902 - handle embedded newline + if (ScStringUtil::isMultiline(rString)) + { + rEngine.SetTextCurrentDefaults(rString); + rDoc.SetEditText(aAddress, rEngine.CreateTextObject()); + rDocSh.AdjustRowHeight(nRow, nRow, nTab); } else { - ScFieldEditEngine& rEngine = rDoc.GetEditEngine(); - for (const auto& rTab : aMark) + rFunc.SetNormalString(bNumFmtSet, aAddress, rString, false); + } + + if (bNumFmtSet) + { + /* FIXME: if set on any sheet results in changed only on + * sheet nTab for TestFormatArea() and DoAutoAttributes() */ + rbNumFmtChanged = true; + } +} + +} +// input - undo OK +void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, + const OUString& rString, + const EditTextObject* pData, + bool bMatrixExpand ) +{ + ScDocument& rDoc = GetViewData().GetDocument(); + ScMarkData aMark(GetViewData().GetMarkData()); + bool bRecord = rDoc.IsUndoEnabled(); + + ScDocShell* pDocSh = GetViewData().GetDocShell(); + ScDocFunc &rFunc = GetViewData().GetDocFunc(); + std::shared_ptr<ScDocShellModificator> xModificator = std::make_shared<ScDocShellModificator>(*pDocSh); + + ScEditableTester aTester( rDoc, nCol,nRow, nCol,nRow, aMark ); + if (!aTester.IsEditable()) + { + ErrorMessage(aTester.GetMessageId()); + PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there + return; + } + + if ( bRecord ) + rFunc.EnterListAction( STR_UNDO_ENTERDATA ); + + bool bFormula = checkFormula(rDoc, nCol, nRow, nTab, rString); + bool bNumFmtChanged = false; + + if ( bFormula ) + { + SCTAB nSelectedTab = aMark.GetFirstSelected(); + applyFormulaToCell(*this, nCol, nRow, nTab, rString, pData, xModificator, aMark, bMatrixExpand, bRecord, bNumFmtChanged); + if (!rDoc.IsSheetView(nSelectedTab)) { - bool bNumFmtSet = false; - const ScAddress aScAddress(nCol, nRow, rTab); + auto pManager = rDoc.GetSheetViewManager(nSelectedTab); - // tdf#104902 - handle embedded newline - if (ScStringUtil::isMultiline(rString)) + for (auto const& rSheetView : pManager->getSheetViews()) { - rEngine.SetTextCurrentDefaults(rString); - rDoc.SetEditText(aScAddress, rEngine.CreateTextObject()); - pDocSh->AdjustRowHeight(nRow, nRow, rTab); + if (!rSheetView.isValid()) + continue; + + SCTAB nSheetViewTab = rSheetView.getTableNumber(); + + ScMarkData aSheetViewMark(rDoc.GetSheetLimits()); + aSheetViewMark.SelectTable(nSheetViewTab, false); + ScRange aSheetViewRange(aMark.GetMarkArea()); + aSheetViewRange.aStart.SetTab(nSheetViewTab); + aSheetViewRange.aEnd.SetTab(nSheetViewTab); + aSheetViewMark.SetMarkArea(aSheetViewRange); + + applyFormulaToCell(*this, nCol, nRow, nSheetViewTab, rString, pData, xModificator, aSheetViewMark, bMatrixExpand, bRecord, bNumFmtChanged); } - else + } + } + else + { + for (const auto& rTab : aMark) + { + if (!rDoc.IsSheetView(rTab)) { - rFunc.SetNormalString(bNumFmtSet, aScAddress, rString, false); - } + auto pManager = rDoc.GetSheetViewManager(rTab); + for (auto const& rSheetView : pManager->getSheetViews()) + { + if (!rSheetView.isValid()) + continue; - if (bNumFmtSet) - { - /* FIXME: if set on any sheet results in changed only on - * sheet nTab for TestFormatArea() and DoAutoAttributes() */ - bNumFmtChanged = true; + SCTAB nSheetViewTab = rSheetView.getTableNumber(); + applyText(*this, nCol, nRow, nSheetViewTab, rString, bNumFmtChanged); + } } + applyText(*this, nCol, nRow, rTab, rString, bNumFmtChanged); } performAutoFormatAndUpdate(rString, aMark, nCol, nRow, nTab, bNumFmtChanged, bRecord, xModificator, *this); }