sc/qa/unit/ucalc.cxx | 38 ++++++++++++++++++++++ sc/source/core/tool/reffind.cxx | 2 - sc/source/ui/view/editsh.cxx | 67 ++++++++++++++++++++++++++++------------ 3 files changed, 87 insertions(+), 20 deletions(-)
New commits: commit 3d65a92eaba1b8a2aa90a6b5188c2631465c7f4d Author: Mike Kaganski <[email protected]> AuthorDate: Sat Dec 13 21:34:44 2025 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Sat Dec 13 19:10:24 2025 +0100 tdf#168818: handle multiline formulas when toggling reference This is a longstanding TODO from commit 8204d322379cbc054fb834911d88fb0fe3b040c6 (ScInputHandler::UpdateFormulaMode() also for multi-line formulas, 2022-01-24). Change-Id: Ic9872cd170bd71b0585b481677b620c97d68a9d7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195606 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 4377a3cca636..34b6f4e2bda0 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -3559,6 +3559,44 @@ CPPUNIT_TEST_FIXTURE(Test, testToggleRefFlag) CPPUNIT_ASSERT_EQUAL(u"=A1+4"_ustr, aFormula); } + { + // Calc A1, with newlines in the formula: + OUString aFormula(u"=SUM( A1:A10 )"_ustr); + ScAddress aPos(1, 1, 0); + ScRefFinder aFinder(aFormula, aPos, *m_pDoc, formula::FormulaGrammar::CONV_OOO); + + // Original + CPPUNIT_ASSERT_EQUAL(aFormula, aFinder.GetText()); + + // Set the cursor at the 'A1' part and toggle + aFinder.ToggleRel(6, 6); + CPPUNIT_ASSERT_EQUAL(u"=SUM( $A$1:A10 )"_ustr, aFinder.GetText()); + // Selected: "$A$1" + CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aFinder.GetSelStart()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(10), aFinder.GetSelEnd()); + + // Set the cursor behind the 'A10' part and toggle + aFinder.ToggleRel(14, 14); + CPPUNIT_ASSERT_EQUAL(u"=SUM( $A$1:$A$10 )"_ustr, aFinder.GetText()); + // Selected: "$A$10" + CPPUNIT_ASSERT_EQUAL(sal_Int32(11), aFinder.GetSelStart()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(16), aFinder.GetSelEnd()); + + // Set the cursor around an area including a newline and toggle + aFinder.ToggleRel(2, 6); + CPPUNIT_ASSERT_EQUAL(u"=SUM( A$1:$A$10 )"_ustr, aFinder.GetText()); + // Selected: "A$1" + CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aFinder.GetSelStart()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(9), aFinder.GetSelEnd()); + + // Select all and toggle + aFinder.ToggleRel(0, 16); + CPPUNIT_ASSERT_EQUAL(u"=SUM( $A1:A$10 )"_ustr, aFinder.GetText()); + // Selected: "$A1:A$10" + CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aFinder.GetSelStart()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(14), aFinder.GetSelEnd()); + } + // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and // partial selection within formula string. diff --git a/sc/source/core/tool/reffind.cxx b/sc/source/core/tool/reffind.cxx index 10522310f851..1d811e5ea48d 100644 --- a/sc/source/core/tool/reffind.cxx +++ b/sc/source/core/tool/reffind.cxx @@ -31,7 +31,7 @@ namespace { // Include colon; addresses in range reference are handled individually. const sal_Unicode pDelimiters[] = { - '=','(',')','+','-','*','/','^','&',' ','{','}','<','>',':', 0 + '=','(',')','+','-','*','/','^','&',' ','{','}','<','>',':',' ',0 }; bool IsText( sal_Unicode c ) diff --git a/sc/source/ui/view/editsh.cxx b/sc/source/ui/view/editsh.cxx index 10fed924daf5..9d5de6cdcab5 100644 --- a/sc/source/ui/view/editsh.cxx +++ b/sc/source/ui/view/editsh.cxx @@ -532,30 +532,59 @@ void ScEditShell::Execute( SfxRequest& rReq ) case SID_TOGGLE_REL: { - /* TODO: MLFORMULA: this should work also with multi-line formulas. */ - if (rEngine.GetParagraphCount() == 1) + auto PaMToStringIndex = [](const OUString& s, EPaM pam) { - OUString aText = rEngine.GetText(); - ESelection aSel = pEditView->GetSelection(); // current View - - ScDocument& rDoc = rViewData.GetDocument(); - ScRefFinder aFinder(aText, rViewData.GetCurPos(), rDoc, rDoc.GetAddressConvention()); - aFinder.ToggleRel(aSel.start.nIndex, aSel.end.nIndex); - if (aFinder.GetFound()) + sal_Int32 index = 0; + for (; pam.nPara > 0; --pam.nPara) { - const OUString& aNew = aFinder.GetText(); - ESelection aNewSel( 0,aFinder.GetSelStart(), 0,aFinder.GetSelEnd() ); - rEngine.SetText( aNew ); - pTableView->SetSelection( aNewSel ); - if ( pTopView ) + index = s.indexOf(' ', index) + 1; // becomes 0 on "not found" + if (index <= 0) + return s.getLength(); + } + index += pam.nIndex; + return std::min(index, s.getLength()); + }; + auto StringIndexToPaM = [](const OUString& s, sal_Int32 index) + { + EPaM pam; + for (sal_Int32 i = 0; i < index; ++i) + { + if (s[i] == ' ') { - pTopView->getEditEngine().SetText( aNew ); - pTopView->SetSelection( aNewSel ); + ++pam.nPara; + pam.nIndex = 0; } - - // reference is being selected -> do not overwrite when typing - bSetSelIsRef = true; + else + { + ++pam.nIndex; + } + } + return pam; + }; + + OUString aText = rEngine.GetText(LINEEND_LF); + ESelection aSel = pEditView->GetSelection(); // current View + sal_Int32 nStart = PaMToStringIndex(aText, aSel.start); + sal_Int32 nEnd = PaMToStringIndex(aText, aSel.end); + + ScDocument& rDoc = rViewData.GetDocument(); + ScRefFinder aFinder(aText, rViewData.GetCurPos(), rDoc, rDoc.GetAddressConvention()); + aFinder.ToggleRel(nStart, nEnd); + if (aFinder.GetFound()) + { + const OUString& aNew = aFinder.GetText(); + ESelection aNewSel(StringIndexToPaM(aNew, aFinder.GetSelStart())); + aNewSel.end = StringIndexToPaM(aNew, aFinder.GetSelEnd()); + rEngine.SetText( aNew ); + pTableView->SetSelection( aNewSel ); + if ( pTopView ) + { + pTopView->getEditEngine().SetText( aNew ); + pTopView->SetSelection( aNewSel ); } + + // reference is being selected -> do not overwrite when typing + bSetSelIsRef = true; } } break;
