editeng/source/editeng/editview.cxx | 7 +- include/editeng/editview.hxx | 2 sc/source/ui/inc/gridwin.hxx | 2 sc/source/ui/view/gridwin.cxx | 89 ++++++++++-------------------------- 4 files changed, 31 insertions(+), 69 deletions(-)
New commits: commit 8238b887ccecb425f17166d2380afb208bbfdfbb Author: Justin Luth <[email protected]> AuthorDate: Mon Feb 21 10:17:36 2022 +0200 Commit: Eike Rathke <[email protected]> CommitDate: Fri Feb 25 15:22:46 2022 +0100 tdf#81894 sc spelling: choose correct cell when in edit mode In edit mode, text that is too large to fit inside the cell will expand to cover other columns (or rows if cell wraps). GetPosFromPixel doesn't account for this, so it needs to be done separately. (SHOULD the function itself take this into account? Probably, but it is used a LOT, so I'm afraid to mess with it.) This patch fixes two situations in bug 81894 comment 25's example. 1.) Open Francewhoa---2017-May-29---speadsheet.ods 2.) Double click on A1 to enter edit mode. Notice that the cell expands to cover A1:A3. 3.) Right click on "productivityy". Before the patch, the spell check was inspecting empty cell A2, and thus showed the edit popup. With the patch, the spell check is using cell A1, and thus provides spelling suggestions, as expected. [This patch depends on this bug report's prior comit.] 4.) Look at B3 and notice misspelled words spilling over from A3. Double click on B3 to enter edit mode. 5.) Right click on the position where the misspelled word had been. Before the patch, a spelling suggestion was provided, even though we right-clicked on an empty place in a different col. After the patch, we get the normal edit popup. Change-Id: I58fbf60711a5c010263b525a96383a805be1b3ca Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130298 Tested-by: Jenkins Reviewed-by: Eike Rathke <[email protected]> diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 5a8c9625c332..0f01233d64a9 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -3182,9 +3182,24 @@ void ScGridWindow::Command( const CommandEvent& rCEvt ) Point aPosPixel = rCEvt.GetMousePosPixel(); Point aMenuPos = aPosPixel; + bool bPosIsInEditView = mrViewData.HasEditView(eWhich); SCCOL nCellX = -1; SCROW nCellY = -1; mrViewData.GetPosFromPixel(aPosPixel.X(), aPosPixel.Y(), eWhich, nCellX, nCellY); + // GetPosFromPixel ignores the fact that when editing a cell, the cell might grow to cover + // other rows/columns. In addition, the mouse might now be outside the edited cell. + if (bPosIsInEditView) + { + if (nCellX >= mrViewData.GetEditViewCol() && nCellX <= mrViewData.GetEditEndCol()) + nCellX = mrViewData.GetEditViewCol(); + else + bPosIsInEditView = false; + + if (nCellY >= mrViewData.GetEditViewRow() && nCellY <= mrViewData.GetEditEndRow()) + nCellY = mrViewData.GetEditViewRow(); + else + bPosIsInEditView = false; + } bool bSpellError = false; SCCOL nColSpellError = nCellX; @@ -3216,7 +3231,7 @@ void ScGridWindow::Command( const CommandEvent& rCEvt ) // Find the first string to the left for spell checking in case the current cell is empty. ScAddress aPos(nCellX, nCellY, nTab); ScRefCellValue aSpellCheckCell(rDoc, aPos); - while (aSpellCheckCell.meType == CELLTYPE_NONE) + while (!bPosIsInEditView && aSpellCheckCell.meType == CELLTYPE_NONE) { // Loop until we get the first non-empty cell in the row. aPos.IncCol(-1); commit cf18038c66075f7a18d89e47f3a2ab1a5bf7c4fd Author: Justin Luth <[email protected]> AuthorDate: Sat Feb 19 20:22:23 2022 +0200 Commit: Eike Rathke <[email protected]> CommitDate: Fri Feb 25 15:22:32 2022 +0100 tdf#81894 sc spelling: eliminate separate(inaccurate) check ExecuteSpellPopup is quite accurate at identifying whether the spelling at PosPixel is a spelling error or not. If it is not a misspelled word, then it just silently returns. If we make this a bDone flag, then it will just move on to the normal right-click dialog. There are a few additional scenarios that need to be handled (mainly in terms of showing the edit-mode menu instead of the full format menu, and also not always returning the correct row/col when in edit mode). I will do them in separate patches so that each edge case can be clearly seen and handled. They all rely on this patch being applied first. This is the base patch. Too many things simply don't work with the interim check, so I removed it. (Part of the problem is that EditView kicks on and off, and then a new CompleteOnlineSpelling needs to be run before IsWrongSpelledWordAtPos can return a meaningful answer.) This patch specifically fixes the problem of not opening SpellPopup on a misspelled word in a wrapped-cell. Steps to reproduce: 1.) Open LOv4304.ods from bug 81894 comment 6. 2.) Right-click on "spellng" in cell B12. Before the patch, a full format popup was displayed (not in edit mode) because IsSpellErrorAtPos returned false, when it should have been true. With this patch, spelling suggestions are provided. As an example of an edge case, also notice: 3.) double-click on cell B4 (to enter edit mode) 4.) right click on "spellng" which appears to be in D4 Before the patch, nothing happened at all, but with the patch at least the fall-back menu is displayed. (EditView never switches out of cell B, so SpellPopup is looking at wrong information.) Change-Id: I91d413debc58de832dc7413034618e9e2bae3dd5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130297 Tested-by: Jenkins Reviewed-by: Justin Luth <[email protected]> Reviewed-by: Eike Rathke <[email protected]> diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx index a422cb55c85e..17ecb94b9dd1 100644 --- a/editeng/source/editeng/editview.cxx +++ b/editeng/source/editeng/editview.cxx @@ -978,7 +978,7 @@ static void LOKSendSpellPopupMenu(const weld::Menu& rMenu, LanguageType nGuessLa pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, aStream.str().c_str()); } -void EditView::ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbackInfo&,void> &rCallBack) +bool EditView::ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbackInfo&,void> &rCallBack) { OutputDevice& rDevice = pImpEditView->GetOutputDevice(); Point aPos(rDevice.PixelToLogic(rPosPixel)); @@ -987,7 +987,7 @@ void EditView::ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbac Reference< linguistic2::XSpellChecker1 > xSpeller( pImpEditView->pEditEngine->pImpEditEngine->GetSpeller() ); ESelection aOldSel = GetSelection(); if ( !(xSpeller.is() && pImpEditView->IsWrongSpelledWord( aPaM, true )) ) - return; + return false; // PaMtoEditCursor returns Logical units tools::Rectangle aTempRect = pImpEditView->pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, GetCursorFlags::TextOnly ); @@ -1167,7 +1167,7 @@ void EditView::ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbac xPopupMenu->remove("autocorrectdlg"); LOKSendSpellPopupMenu(*xPopupMenu, nGuessLangWord, nGuessLangPara, nWords); - return; + return true; } OString sId = xPopupMenu->popup_at_rect(pPopupParent, aTempRect); @@ -1267,6 +1267,7 @@ void EditView::ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbac { SetSelection( aOldSel ); } + return true; } OUString EditView::SpellIgnoreWord() diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx index 61b659dfb152..6d3a09664767 100644 --- a/include/editeng/editview.hxx +++ b/include/editeng/editview.hxx @@ -305,7 +305,7 @@ public: bool IsCursorAtWrongSpelledWord(); bool IsWrongSpelledWordAtPos( const Point& rPosPixel, bool bMarkIfWrong = false ); - void ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbackInfo&,void>& rCallBack); + bool ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbackInfo&,void>& rCallBack); OUString SpellIgnoreWord(); void InsertField( const SvxFieldItem& rFld ); diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx index 12535cd313e0..988bf55d2a17 100644 --- a/sc/source/ui/inc/gridwin.hxx +++ b/sc/source/ui/inc/gridwin.hxx @@ -283,8 +283,6 @@ class SAL_DLLPUBLIC_RTTI ScGridWindow : public vcl::Window, public DropTargetHel bool GetEditUrl( const Point& rPos, OUString* pName=nullptr, OUString* pUrl=nullptr, OUString* pTarget=nullptr ); - bool IsSpellErrorAtPos( const Point& rPos, SCCOL nCol1, SCROW nRow ); - bool HitRangeFinder( const Point& rMouse, RfCorner& rCorner, sal_uInt16* pIndex, SCCOL* pAddX, SCROW* pAddY ); diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 1357a543659c..5a8c9625c332 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -3229,12 +3229,9 @@ void ScGridWindow::Command( const CommandEvent& rCEvt ) if (aPos.Col() >= 0 && (aSpellCheckCell.meType == CELLTYPE_STRING || aSpellCheckCell.meType == CELLTYPE_EDIT)) nColSpellError = aPos.Col(); + // Is there a missspelled word somewhere in the cell? + // A "yes" does not mean that the word under the mouse pointer is wrong though. bSpellError = (mpSpellCheckCxt->isMisspelled(nColSpellError, nCellY)); - if (bSpellError) - { - // Check and see if a misspelled word is under the mouse pointer. - bSpellError = IsSpellErrorAtPos(aPosPixel, nColSpellError, nCellY); - } } // #i18735# First select the item under the mouse pointer. @@ -3248,7 +3245,7 @@ void ScGridWindow::Command( const CommandEvent& rCEvt ) if ( !bEdit ) { // Edit cell with spelling errors? - // tdf#127341 the formally used GetEditUrl(aPosPixel) additionally + // tdf#127341 the formerly used GetEditUrl(aPosPixel) additionally // to bSpellError activated EditMode here for right-click on URL // which prevents the regular context-menu from appearing. Since this // is more expected than the context-menu for editing an URL, I removed @@ -3300,13 +3297,18 @@ void ScGridWindow::Command( const CommandEvent& rCEvt ) const OUString sOldText = pHdl ? pHdl->GetEditString() : ""; + // Only done/shown if a misspelled word is actually under the mouse pointer. Link<SpellCallbackInfo&,void> aLink = LINK( this, ScGridWindow, PopupSpellingHdl ); - pEditView->ExecuteSpellPopup(aMenuPos, aLink); + bDone = pEditView->ExecuteSpellPopup(aMenuPos, aLink); if (pHdl && pHdl->GetEditString() != sOldText) pHdl->EnterHandler(); - bDone = true; + if (!bDone && nColSpellError != nCellX) + { + // NOTE: This call can change the selection, and the view state (edit mode, etc). + SelectForContextMenu(aPosPixel, nCellX, nCellY); + } } } else if ( !bMouse ) @@ -5767,60 +5769,6 @@ bool ScGridWindow::GetEditUrl( const Point& rPos, return false; } -bool ScGridWindow::IsSpellErrorAtPos( const Point& rPos, SCCOL nCol1, SCROW nRow ) -{ - if (!mpSpellCheckCxt) - return false; - - SCTAB nTab = mrViewData.GetTabNo(); - ScDocShell* pDocSh = mrViewData.GetDocShell(); - ScDocument& rDoc = pDocSh->GetDocument(); - - ScAddress aCellPos(nCol1, nRow, nTab); - ScRefCellValue aCell(rDoc, aCellPos); - if (aCell.meType != CELLTYPE_STRING && aCell.meType != CELLTYPE_EDIT) - return false; - - const std::vector<editeng::MisspellRanges>* pRanges = mpSpellCheckCxt->getMisspellRanges(nCol1, nRow); - if (!pRanges) - return false; - - const ScPatternAttr* pPattern = rDoc.GetPattern(nCol1, nRow, nTab); - - tools::Rectangle aEditRect = mrViewData.GetEditArea(eWhich, nCol1, nRow, this, pPattern, false); - if (rPos.Y() < aEditRect.Top()) - return false; - - std::shared_ptr<ScFieldEditEngine> pEngine = createEditEngine(pDocSh, *pPattern); - - Size aPaperSize(1000000, 1000000); - pEngine->SetPaperSize(aPaperSize); - - if (aCell.meType == CELLTYPE_EDIT) - pEngine->SetTextCurrentDefaults(*aCell.mpEditText); - else - pEngine->SetTextCurrentDefaults(aCell.mpString->getString()); - - tools::Long nTextWidth = static_cast<tools::Long>(pEngine->CalcTextWidth()); - - MapMode aEditMode = mrViewData.GetLogicMode(eWhich); - tools::Rectangle aLogicEdit = PixelToLogic(aEditRect, aEditMode); - Point aLogicClick = PixelToLogic(rPos, aEditMode); - - aLogicEdit.setWidth(nTextWidth + 1); - - if (!aLogicEdit.Contains(aLogicClick)) - return false; - - pEngine->SetControlWord(pEngine->GetControlWord() | EEControlBits::ONLINESPELLING); - pEngine->SetAllMisspellRanges(*pRanges); - - EditView aTempView(pEngine.get(), this); - aTempView.SetOutputArea(aLogicEdit); - - return aTempView.IsWrongSpelledWordAtPos(rPos); -} - bool ScGridWindow::HasScenarioButton( const Point& rPosPixel, ScRange& rScenRange ) { ScDocument& rDoc = mrViewData.GetDocument();
