sw/qa/extras/uiwriter/data/tdf151548_tabNavigation2.docx |binary sw/qa/extras/uiwriter/uiwriter4.cxx | 55 +++++++++++++++ sw/source/core/crsr/crstrvl.cxx | 22 +++--- 3 files changed, 67 insertions(+), 10 deletions(-)
New commits: commit 441d0b0fb2eef890a465c061a3d68a07c4a51832 Author: Justin Luth <justin.l...@collabora.com> AuthorDate: Fri Jan 27 19:03:35 2023 -0500 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jan 30 08:36:52 2023 +0000 tdf#151548 sw content controls: actually gotoFormatContentControl The cursor kindof needs to change when going to a content control, so don't return early just because there will be no selection. Instead, set the cursor at the beginning of the control, and simply skip the selection part. Without this, it was not possible for the keyboard navigation to jump to rich/plain text or comboboxes that were no longer showing placeholder content. Change-Id: I055ece1d296c6cdf70d6bc7c1df7797bf09532c9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146266 Tested-by: Jenkins Reviewed-by: Justin Luth <jl...@mail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/uiwriter/data/tdf151548_tabNavigation2.docx b/sw/qa/extras/uiwriter/data/tdf151548_tabNavigation2.docx new file mode 100644 index 000000000000..d1b81dfca3ef Binary files /dev/null and b/sw/qa/extras/uiwriter/data/tdf151548_tabNavigation2.docx differ diff --git a/sw/qa/extras/uiwriter/uiwriter4.cxx b/sw/qa/extras/uiwriter/uiwriter4.cxx index c8e99868a790..64ce10b9d833 100644 --- a/sw/qa/extras/uiwriter/uiwriter4.cxx +++ b/sw/qa/extras/uiwriter/uiwriter4.cxx @@ -1491,6 +1491,61 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf95699) pFieldMark->GetFieldname()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf151548_tabNavigation2) +{ + // given a form-protected doc with 2 unchecked legacy fieldmark checkboxes, 1 modern + // checkbox, and a couple of other content controls that are not supposed to + // have their contents selected upon entry into the control (i.e. no placeholder text). + createSwDoc("tdf151548_tabNavigation2.docx"); + SwDoc* pDoc = getSwDoc(); + SwXTextDocument* pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pMarkAccess->getFieldmarksCount()); + + // verify that the checkboxes start off in the unchecked state + for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it) + { + sw::mark::ICheckboxFieldmark* pCheckBox + = dynamic_cast<::sw::mark::ICheckboxFieldmark*>(*it); + CPPUNIT_ASSERT(!pCheckBox->IsChecked()); + } + + // Toggle on the legacy checkbox + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE); + // Tab to the next control - the modern checkbox + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); + // Tab to the next control - the second legacy checkbox, and toggle it on. + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE); + // Tab to the next control - a plain text control without placeholder text + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); + // Tab to the next control - a combobox with custom text + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); + Scheduler::ProcessEventsToIdle(); + + for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it) + { + sw::mark::ICheckboxFieldmark* pCheckBox + = dynamic_cast<::sw::mark::ICheckboxFieldmark*>(*it); + // verify that the legacy checkbox became checked by the first loop. + CPPUNIT_ASSERT(pCheckBox->IsChecked()); + + // This is where it was failing. Tab got stuck moving into the plain text/combobox, + // so it could never loop around. At this point we are at the end of the loop, + // so the next tab should take us back to the beginning with the first legacy checkbox. + + // Tab to the legacy checkbox, and toggle it off. + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(!pCheckBox->IsChecked()); + + // Tab to the next content control + pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); + } +} + CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf151548_tabNavigation) { // given a form-protected doc with 4 unchecked legacy fieldmark checkboxes (and several modern diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx index 9cf9f77a4d76..f55ede18d43d 100644 --- a/sw/source/core/crsr/crstrvl.cxx +++ b/sw/source/core/crsr/crstrvl.cxx @@ -829,12 +829,6 @@ bool SwCursorShell::GotoFootnoteAnchor(const SwTextFootnote& rTextFootnote) bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rContentControl) { std::shared_ptr<SwContentControl> pContentControl = rContentControl.GetContentControl(); - if (!pContentControl->GetShowingPlaceHolder() && !pContentControl->GetCheckbox() - && !pContentControl->GetSelectedListItem() && !pContentControl->GetSelectedDate()) - { - return false; - } - const SwTextContentControl* pTextContentControl = pContentControl->GetTextAttr(); if (!pTextContentControl) return false; @@ -845,14 +839,22 @@ bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rCont SwCursor* pCursor = getShellCursor(true); SwCursorSaveState aSaveState(*pCursor); - pCursor->SetMark(); SwTextNode* pTextNode = pContentControl->GetTextNode(); // Don't select the text attribute itself at the start. sal_Int32 nStart = pTextContentControl->GetStart() + 1; pCursor->GetPoint()->Assign(*pTextNode, nStart); - // Don't select the CH_TXTATR_BREAKWORD itself at the end. - sal_Int32 nEnd = *pTextContentControl->End() - 1; - pCursor->GetMark()->Assign(*pTextNode, nEnd); + + // select contents for certain controls or conditions + if (pContentControl->GetShowingPlaceHolder() || pContentControl->GetCheckbox() + || pContentControl->GetSelectedListItem() || pContentControl->GetSelectedDate()) + { + pCursor->SetMark(); + // Don't select the CH_TXTATR_BREAKWORD itself at the end. + sal_Int32 nEnd = *pTextContentControl->End() - 1; + pCursor->GetMark()->Assign(*pTextNode, nEnd); + } + else + ClearMark(); bool bRet = !pCursor->IsSelOvr(); if (bRet)