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 92cbe0a8b8850faa495b8b3fbdcfd18380d5d4d9
Author:     Mike Kaganski <[email protected]>
AuthorDate: Sat Dec 13 21:34:44 2025 +0500
Commit:     Xisco Fauli <[email protected]>
CommitDate: Mon Dec 15 10:55:15 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]>
    (cherry picked from commit 3d65a92eaba1b8a2aa90a6b5188c2631465c7f4d)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195629
    Reviewed-by: Xisco Fauli <[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;

Reply via email to