summaryrefslogtreecommitdiff
path: root/sc/source/ui/app/inputhdl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/app/inputhdl.cxx')
-rw-r--r--sc/source/ui/app/inputhdl.cxx101
1 files changed, 83 insertions, 18 deletions
diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx
index 9c553cec8614..97c86b34b00d 100644
--- a/sc/source/ui/app/inputhdl.cxx
+++ b/sc/source/ui/app/inputhdl.cxx
@@ -162,15 +162,42 @@ OUString getExactMatch(const ScTypedCaseStrSet& rDataSet, const OUString& rStrin
return rString;
}
+// This assumes that rResults is a sorted ring w.r.t ScTypedStrData::LessCaseInsensitive() or
+// in the reverse direction, whose origin is specified by nRingOrigin.
+sal_Int32 getLongestCommonPrefixLength(const std::vector<OUString>& rResults, const OUString& rUserEntry, sal_Int32 nRingOrigin)
+{
+ sal_Int32 nResults = rResults.size();
+ if (!nResults)
+ return 0;
+
+ if (nResults == 1)
+ return rResults[0].getLength();
+
+ sal_Int32 nMinLen = rUserEntry.getLength();
+ sal_Int32 nLastIdx = nRingOrigin ? nRingOrigin - 1 : nResults - 1;
+ const OUString& rFirst = rResults[nRingOrigin];
+ const OUString& rLast = rResults[nLastIdx];
+ const sal_Int32 nMaxLen = std::min(rFirst.getLength(), rLast.getLength());
+
+ for (sal_Int32 nLen = nMaxLen; nLen > nMinLen; --nLen)
+ {
+ if (ScGlobal::GetTransliteration().isMatch(rFirst.copy(0, nLen), rLast))
+ return nLen;
+ }
+
+ return nMinLen;
+}
+
ScTypedCaseStrSet::const_iterator findTextAll(
const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator const & itPos,
- const OUString& rStart, ::std::vector< OUString > &rResultVec, bool bBack, size_t nMax = 0)
+ const OUString& rStart, ::std::vector< OUString > &rResultVec, bool bBack, sal_Int32* pLongestPrefixLen = nullptr)
{
rResultVec.clear(); // clear contents
if (!rDataSet.size())
return rDataSet.end();
+ sal_Int32 nRingOrigin = 0;
size_t nCount = 0;
ScTypedCaseStrSet::const_iterator retit;
if ( bBack ) // Backwards
@@ -198,7 +225,10 @@ ScTypedCaseStrSet::const_iterator findTextAll(
{
++it;
if ( it == rDataSet.rend() ) // go to the first if reach the end
+ {
it = rDataSet.rbegin();
+ nRingOrigin = nCount;
+ }
if ( bFirstTime )
bFirstTime = false;
@@ -221,8 +251,6 @@ ScTypedCaseStrSet::const_iterator findTextAll(
std::advance(retit, nPos);
}
++nCount;
- if (nMax > 0 && nCount >= nMax)
- break;
}
}
else // Forwards
@@ -238,7 +266,10 @@ ScTypedCaseStrSet::const_iterator findTextAll(
{
++it;
if ( it == rDataSet.end() ) // go to the first if reach the end
+ {
it = rDataSet.begin();
+ nRingOrigin = nCount;
+ }
if ( bFirstTime )
bFirstTime = false;
@@ -255,11 +286,21 @@ ScTypedCaseStrSet::const_iterator findTextAll(
if ( nCount == 0 )
retit = it; // remember first match iterator
++nCount;
- if (nMax > 0 && nCount >= nMax)
- break;
}
}
+ if (pLongestPrefixLen)
+ {
+ if (nRingOrigin >= static_cast<sal_Int32>(nCount))
+ {
+ // All matches were picked when rDataSet was read in one direction.
+ nRingOrigin = 0;
+ }
+ // rResultsVec is a sorted ring with nRingOrigin "origin".
+ // The direction of sorting is not important for getLongestCommonPrefixLength.
+ *pLongestPrefixLen = getLongestCommonPrefixLength(rResultVec, rStart, nRingOrigin);
+ }
+
if ( nCount > 0 ) // at least one function has matched
return retit;
return rDataSet.end(); // no matching text found
@@ -788,6 +829,7 @@ ScInputHandler::ScInputHandler()
bProtected( false ),
bLastIsSymbol( false ),
mbDocumentDisposing(false),
+ mbPartialPrefix(false),
nValidation( 0 ),
eAttrAdjust( SvxCellHorJustify::Standard ),
aScaleX( 1,1 ),
@@ -1971,24 +2013,28 @@ void ScInputHandler::UseColData() // When typing
std::vector< OUString > aResultVec;
OUString aNew;
+ sal_Int32 nLongestPrefixLen = 0;
miAutoPosColumn = pColumnData->end();
- miAutoPosColumn = findTextAll(*pColumnData, miAutoPosColumn, aText, aResultVec, false, 2);
- bool bShowCompletion = (aResultVec.size() == 1);
- bUseTab = (aResultVec.size() == 2);
- if (bUseTab)
+ mbPartialPrefix = false;
+ miAutoPosColumn = findTextAll(*pColumnData, miAutoPosColumn, aText, aResultVec, false, &nLongestPrefixLen);
+
+ if (nLongestPrefixLen <= 0 || aResultVec.empty())
+ return;
+
+ if (aResultVec.size() > 1)
{
- // Allow cycling through possible matches using shortcut.
- // Make miAutoPosColumn invalid so that Ctrl+TAB provides the first matching one.
+ mbPartialPrefix = true;
+ bUseTab = true; // Allow Ctrl (+ Shift + ) + TAB cycling.
miAutoPosColumn = pColumnData->end();
- aAutoSearch = aText;
- return;
- }
- if (!bShowCompletion)
- return;
+ // Display the rest of longest common prefix as suggestion.
+ aNew = aResultVec[0].copy(0, nLongestPrefixLen);
+ }
+ else
+ {
+ aNew = aResultVec[0];
+ }
- assert(miAutoPosColumn != pColumnData->end());
- aNew = aResultVec[0];
// Strings can contain line endings (e.g. due to dBase import),
// which would result in multiple paragraphs here, which is not desirable.
//! Then GetExactMatch doesn't work either
@@ -2047,6 +2093,7 @@ void ScInputHandler::NextAutoEntry( bool bBack )
// match found!
miAutoPosColumn = itNew;
bInOwnChange = true; // disable ModifyHdl (reset below)
+ mbPartialPrefix = false;
lcl_RemoveLineEnd( aNew );
OUString aIns = aNew.copy(aAutoSearch.getLength());
@@ -2942,6 +2989,7 @@ void ScInputHandler::EnterHandler( ScEnterMode nBlockMode )
if (bInEnterHandler) return;
bInEnterHandler = true;
bInOwnChange = true; // disable ModifyHdl (reset below)
+ mbPartialPrefix = false;
ImplCreateEditEngine();
@@ -3306,6 +3354,7 @@ void ScInputHandler::CancelHandler()
ImplCreateEditEngine();
bModified = false;
+ mbPartialPrefix = false;
// Don't rely on ShowRefFrame switching the active view synchronously
// execute the function directly on the correct view's bindings instead
@@ -3598,6 +3647,22 @@ bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false
// Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
return false;
+ // There is a partial autocomplete suggestion.
+ // Allow its completion with right arrow key (without modifiers).
+ if (mbPartialPrefix && nCode == KEY_RIGHT && !bControl && !bShift && !bAlt &&
+ (pTopView || pTableView))
+ {
+ if (pTopView)
+ pTopView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
+ if (pTableView)
+ pTableView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
+
+ mbPartialPrefix = false;
+
+ // Indicate that this event has been consumed and ScTabViewShell should not act on this.
+ return true;
+ }
+
if (!bControl && nCode == KEY_TAB)
{
// Normal TAB moves the cursor right.