Resolves: tdf#144547 ScRangeFindList: handle references in multi-line formula
Also fix a color attribution error if when dragging the reference
the new reference string is longer (colored too short) or shorter
(colored too much including the next characters/operator/...) than
the old reference string.
Change-Id: I1b39fd5778d75290a0233f51a4198753fa858f48
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150979
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx
index c0ee119..00fc7e4 100644
--- a/sc/source/ui/app/inputhdl.cxx
+++ b/sc/source/ui/app/inputhdl.cxx
@@ -341,6 +341,20 @@ void ScInputHandler::SendReferenceMarks( const SfxViewShell* pViewShell,
LOK_CALLBACK_REFERENCE_MARKS, aPayload );
}
static inline void incPos( const sal_Unicode c, sal_Int32& rPos, ESelection& rSel )
{
++rPos;
if (c == '\n')
{
++rSel.nEndPara;
rSel.nEndPos = 0;
}
else
{
++rSel.nEndPos;
}
}
void ScInputHandler::InitRangeFinder( const OUString& rFormula )
{
DeleteRangeFinder();
@@ -350,7 +364,7 @@ void ScInputHandler::InitRangeFinder( const OUString& rFormula )
ScDocument& rDoc = pDocSh->GetDocument();
const sal_Unicode cSheetSep = rDoc.GetSheetSeparator();
OUString aDelimiters = ScEditUtil::ModifyDelimiters(" !~\"");
OUString aDelimiters = ScEditUtil::ModifyDelimiters(" !~\"\t\n");
// delimiters (in addition to ScEditUtil): only characters that are
// allowed in formulas next to references and the quotation mark (so
// string constants can be skipped)
@@ -366,6 +380,7 @@ void ScInputHandler::InitRangeFinder( const OUString& rFormula )
sal_Int32 nLen = rFormula.getLength();
sal_Int32 nPos = 0;
sal_Int32 nStart = 0;
ESelection aSel;
sal_uInt16 nCount = 0;
ScRange aRange;
while ( nPos < nLen && nCount < RANGEFIND_MAX )
@@ -375,14 +390,16 @@ void ScInputHandler::InitRangeFinder( const OUString& rFormula )
{
if ( pChar[nPos] == '"' ) // String
{
++nPos;
incPos( pChar[nPos], nPos, aSel);
while (nPos<nLen && pChar[nPos] != '"') // Skip until end
++nPos;
incPos( pChar[nPos], nPos, aSel);
}
++nPos; // Separator or closing quote
incPos( pChar[nPos], nPos, aSel); // Separator or closing quote
}
// text between separators
// Text between separators. We only consider within one line/paragraph.
aSel.nStartPara = aSel.nEndPara;
aSel.nStartPos = aSel.nEndPos;
nStart = nPos;
handle_r1c1:
{
@@ -400,7 +417,7 @@ handle_r1c1:
if (ScGlobal::UnicodeStrChr(aDelimiters.getStr(), pChar[nPos]))
break;
}
++nPos;
incPos( pChar[nPos], nPos, aSel);
}
}
@@ -411,7 +428,7 @@ handle_r1c1:
'-' == pChar[nPos] && '[' == pChar[nPos-1] &&
formula::FormulaGrammar::CONV_XL_R1C1 == rDoc.GetAddressConvention() )
{
nPos++;
incPos( pChar[nPos], nPos, aSel);
goto handle_r1c1;
}
@@ -443,9 +460,8 @@ handle_r1c1:
pRangeFindList.reset(new ScRangeFindList( pDocSh->GetTitle() ));
}
Color nColor = pRangeFindList->Insert( ScRangeFindData( aRange, nFlags, nStart, nPos ) );
Color nColor = pRangeFindList->Insert( ScRangeFindData( aRange, nFlags, aSel));
ESelection aSel( 0, nStart, 0, nPos );
SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
aSet.Put( SvxColorItem( nColor, EE_CHAR_COLOR ) );
mpEditEngine->QuickSetAttribs( aSet, aSel );
@@ -620,8 +636,9 @@ static void lcl_Replace( EditView* pView, const OUString& rNewStr, const ESelect
// To do that we need to cancel the selection from above (before QuickInsertText)
pView->InsertText( OUString() );
sal_Int32 nLen = pEngine->GetTextLen(0);
ESelection aSel( 0, nLen, 0, nLen );
const sal_Int32 nPara = pEngine->GetParagraphCount() - 1;
const sal_Int32 nLen = pEngine->GetTextLen(nPara);
ESelection aSel( nPara, nLen, nPara, nLen );
pView->SetSelection( aSel ); // Set cursor to the end
}
@@ -631,8 +648,6 @@ void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
{
ScRangeFindData& rData = pRangeFindList->GetObject( nIndex );
sal_Int32 nOldStart = rData.nSelStart;
sal_Int32 nOldEnd = rData.nSelEnd;
Color nNewColor = pRangeFindList->FindColor( rNew, nIndex );
ScRange aJustified = rNew;
@@ -640,32 +655,39 @@ void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
ScDocument& rDoc = pDocView->GetViewData().GetDocument();
const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
OUString aNewStr(aJustified.Format(rDoc, rData.nFlags, aAddrDetails));
ESelection aOldSel( 0, nOldStart, 0, nOldEnd );
SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
DataChanging();
lcl_Replace( pTopView, aNewStr, aOldSel );
lcl_Replace( pTableView, aNewStr, aOldSel );
lcl_Replace( pTopView, aNewStr, rData.maSel );
lcl_Replace( pTableView, aNewStr, rData.maSel );
// We are within one paragraph.
const sal_Int32 nDiff = aNewStr.getLength() - (rData.maSel.nEndPos - rData.maSel.nStartPos);
rData.maSel.nEndPos += nDiff;
aSet.Put( SvxColorItem( nNewColor, EE_CHAR_COLOR ) );
mpEditEngine->QuickSetAttribs( aSet, aOldSel );
mpEditEngine->QuickSetAttribs( aSet, rData.maSel );
bInRangeUpdate = true;
DataChanged();
bInRangeUpdate = false;
tools::Long nDiff = aNewStr.getLength() - static_cast<tools::Long>(nOldEnd-nOldStart);
rData.aRef = rNew;
rData.nSelEnd = rData.nSelEnd + nDiff;
rData.nColor = nNewColor;
sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFindList->Count());
for (sal_uInt16 i=nIndex+1; i<nCount; i++)
if (nDiff)
{
ScRangeFindData& rNext = pRangeFindList->GetObject( i );
rNext.nSelStart = rNext.nSelStart + nDiff;
rNext.nSelEnd = rNext.nSelEnd + nDiff;
const size_t nCount = pRangeFindList->Count();
for (size_t i = nIndex + 1; i < nCount; ++i)
{
ScRangeFindData& rNext = pRangeFindList->GetObject( i );
if (rNext.maSel.nStartPara != rData.maSel.nStartPara)
break;
rNext.maSel.nStartPos += nDiff;
rNext.maSel.nEndPos += nDiff;
}
}
EditView* pActiveView = pTopView ? pTopView : pTableView;
diff --git a/sc/source/ui/inc/rfindlst.hxx b/sc/source/ui/inc/rfindlst.hxx
index 18e13a09..216264c 100644
--- a/sc/source/ui/inc/rfindlst.hxx
+++ b/sc/source/ui/inc/rfindlst.hxx
@@ -22,19 +22,19 @@
#include <tools/color.hxx>
#include <address.hxx>
#include <tools/solar.h>
#include <editeng/editdata.hxx>
#include <vector>
struct ScRangeFindData
{
ScRange aRef;
ESelection maSel;
ScRefFlags nFlags;
sal_Int32 nSelStart;
sal_Int32 nSelEnd;
Color nColor;
ScRangeFindData( const ScRange& rR, ScRefFlags nF, sal_Int32 nS, sal_Int32 nE ) :
aRef(rR), nFlags(nF), nSelStart(nS), nSelEnd(nE) {}
ScRangeFindData( const ScRange& rR, ScRefFlags nF, const ESelection& rSel ) :
aRef(rR), maSel(rSel), nFlags(nF) {}
};
class ScRangeFindList
@@ -47,10 +47,10 @@ class ScRangeFindList
public:
ScRangeFindList(OUString aName);
sal_uLong Count() const { return maEntries.size(); }
size_t Count() const { return maEntries.size(); }
Color Insert( const ScRangeFindData &rNew );
ScRangeFindData& GetObject( sal_uLong nIndex ) { return maEntries[nIndex]; }
ScRangeFindData& GetObject( size_t nIndex ) { return maEntries[nIndex]; }
void SetHidden( bool bSet ) { bHidden = bSet; }