diff options
author | Jim Raykowski <raykowj@gmail.com> | 2023-04-27 20:32:03 -0800 |
---|---|---|
committer | Jim Raykowski <raykowj@gmail.com> | 2023-05-07 01:23:20 +0200 |
commit | 50deb478e97aa9cfd023c5fa2f9d567b0b5797c2 (patch) | |
tree | 2f1adf74f4be9764d3d0262756bd11d4078f4cda /sw | |
parent | 45646542a638ec452b00c0c36a8a65d7194defcc (diff) |
tdf#154211 SwNavigator: select range of content by shift + double-
click or shift + enter key
Enhancement to make a selection from the current cursor position in
the document to the position in the document that is navigated to
when a content entry in the Navigator tree is double clicked or the
enter key is pressed.
No selection is made when the current cursor position is in a table,
header, footer, footnote, or frame.
To make shift + double-click behavior for x11 and qt5 the same as
gtk3, FunctionSet::SetCursorAtPoint is added to the Shift case for
SelectionMode::Single in SelectionEngine::SelMouseButtonDown.
Change-Id: Id845dad8011ff7777a24f9b2730f10c62271c368
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151157
Tested-by: Jenkins
Reviewed-by: Jim Raykowski <raykowj@gmail.com>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/source/uibase/inc/conttree.hxx | 5 | ||||
-rw-r--r-- | sw/source/uibase/utlui/content.cxx | 132 |
2 files changed, 112 insertions, 25 deletions
diff --git a/sw/source/uibase/inc/conttree.hxx b/sw/source/uibase/inc/conttree.hxx index 5bcdc9013e89..ee04aeabac40 100644 --- a/sw/source/uibase/inc/conttree.hxx +++ b/sw/source/uibase/inc/conttree.hxx @@ -134,6 +134,9 @@ class SwContentTree final : public SfxListener bool m_bDocHasChanged = true; bool m_bIgnoreDocChange = false; // used to prevent tracking update + ImplSVEvent* m_nRowActivateEventId = nullptr; + bool m_bSelectTo = false; + std::unique_ptr<weld::TreeIter> m_xOverlayCompareEntry; std::unique_ptr<sdr::overlay::OverlayObject> m_xOverlayObject; @@ -199,6 +202,7 @@ class SwContentTree final : public SfxListener /** Collapse - Remember the state for content types. */ DECL_LINK(CollapseHdl, const weld::TreeIter&, bool); DECL_LINK(ContentDoubleClickHdl, weld::TreeView&, bool); + DECL_LINK(AsyncContentDoubleClickHdl, void*, void); DECL_LINK(SelectHdl, weld::TreeView&, void); DECL_LINK(FocusInHdl, weld::Widget&, void); DECL_LINK(KeyInputHdl, const KeyEvent&, bool); @@ -208,6 +212,7 @@ class SwContentTree final : public SfxListener DECL_LINK(TimerUpdate, Timer *, void); DECL_LINK(OverlayObjectDelayTimerHdl, Timer *, void); DECL_LINK(MouseMoveHdl, const MouseEvent&, bool); + DECL_LINK(MousePressHdl, const MouseEvent&, bool); public: SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNavigationPI* pDialog); diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx index 86975a413004..05721ad4e348 100644 --- a/sw/source/uibase/utlui/content.cxx +++ b/sw/source/uibase/utlui/content.cxx @@ -1102,6 +1102,7 @@ SwContentTree::SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNaviga m_xTreeView->connect_query_tooltip(LINK(this, SwContentTree, QueryTooltipHdl)); m_xTreeView->connect_drag_begin(LINK(this, SwContentTree, DragBeginHdl)); m_xTreeView->connect_mouse_move(LINK(this, SwContentTree, MouseMoveHdl)); + m_xTreeView->connect_mouse_press(LINK(this, SwContentTree, MousePressHdl)); for (ContentTypeId i : o3tl::enumrange<ContentTypeId>()) { @@ -1142,6 +1143,12 @@ SwContentTree::~SwContentTree() SetActiveShell(nullptr); } +IMPL_LINK(SwContentTree, MousePressHdl, const MouseEvent&, rMEvt, bool) +{ + m_bSelectTo = rMEvt.IsShift() && (m_pConfig->IsNavigateOnSelect() || rMEvt.GetClicks() == 2); + return false; +} + IMPL_LINK(SwContentTree, MouseMoveHdl, const MouseEvent&, rMEvt, bool) { if (m_eState == State::HIDDEN) @@ -2332,9 +2339,36 @@ IMPL_LINK(SwContentTree, CollapseHdl, const weld::TreeIter&, rParent, bool) // Also on double click will be initially opened only. IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, weld::TreeView&, bool) { + if (m_nRowActivateEventId) + Application::RemoveUserEvent(m_nRowActivateEventId); + // post the event to process row activate after mouse press event to be able to set key + // modifier for selection feature (tdf#154211) + m_nRowActivateEventId + = Application::PostUserEvent(LINK(this, SwContentTree, AsyncContentDoubleClickHdl)); + bool bConsumed = false; std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator()); + if (m_xTreeView->get_cursor(xEntry.get()) && lcl_IsContent(*xEntry, *m_xTreeView) && + (State::HIDDEN != m_eState)) + { + SwContent* pCnt = weld::fromId<SwContent*>(m_xTreeView->get_id(*xEntry)); + assert(pCnt && "no UserData"); + if (pCnt && !pCnt->IsInvisible()) + { + // fdo#36308 don't expand outlines on double-click + bConsumed = pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE; + } + } + + return bConsumed; // false/true == allow/disallow more to be done, i.e. expand/collapse children +} + +IMPL_LINK_NOARG(SwContentTree, AsyncContentDoubleClickHdl, void*, void) +{ + m_nRowActivateEventId = nullptr; + + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator()); bool bEntry = m_xTreeView->get_cursor(xEntry.get()); // Is it a content type? OSL_ENSURE(bEntry, "no current entry!"); @@ -2358,13 +2392,9 @@ IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, weld::TreeView&, bool) } //Jump to content type: GotoContent(pCnt); - // fdo#36308 don't expand outlines on double-click - bConsumed = pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE; } } } - - return bConsumed; // false/true == allow/disallow more to be done, i.e. expand/collapse children } namespace @@ -4191,6 +4221,10 @@ IMPL_LINK(SwContentTree, KeyInputHdl, const KeyEvent&, rEvent, bool) else ContentDoubleClickHdl(*m_xTreeView); break; + case KEY_SHIFT: + m_bSelectTo = true; + ContentDoubleClickHdl(*m_xTreeView); + break; } } } @@ -5169,13 +5203,18 @@ void SwContentTree::EditEntry(const weld::TreeIter& rEntry, EditEntryMode nMode) static void lcl_AssureStdModeAtShell(SwWrtShell* pWrtShell) { // deselect any drawing or frame and leave editing mode - SdrView* pSdrView = pWrtShell->GetDrawView(); - if (pSdrView && pSdrView->IsTextEdit() ) + if (SdrView* pSdrView = pWrtShell->GetDrawView()) { - bool bLockView = pWrtShell->IsViewLocked(); - pWrtShell->LockView(true); - pWrtShell->EndTextEdit(); - pWrtShell->LockView(bLockView); + if (pSdrView->IsTextEdit()) + { + bool bLockView = pWrtShell->IsViewLocked(); + pWrtShell->LockView(true); + pWrtShell->EndTextEdit(); + pWrtShell->LockView(bLockView); + } + // go out of the frame + Point aPt(LONG_MIN, LONG_MIN); + pWrtShell->SelectObj(aPt, SW_LEAVE_FRAME); } if (pWrtShell->IsSelFrameMode() || pWrtShell->IsObjSelected()) @@ -5219,9 +5258,27 @@ void SwContentTree::CopyOutlineSelections() void SwContentTree::GotoContent(const SwContent* pCnt) { + if (m_bSelectTo) + { + if (m_pActiveShell->IsCursorInTable() || + (m_pActiveShell->GetCursor()->GetPoint()->nNode.GetIndex() <= + m_pActiveShell->GetDoc()->GetNodes().GetEndOfExtras().GetIndex())) + { + m_bSelectTo = false; + m_pActiveShell->GetView().GetEditWin().GrabFocus(); + return; + } + } + m_nLastGotoContentWasOutlinePos = SwOutlineNodes::npos; m_sSelectedItem = ""; lcl_AssureStdModeAtShell(m_pActiveShell); + + std::optional<std::unique_ptr<SwPosition>> oPosition; + if (m_bSelectTo) + oPosition.emplace(new SwPosition(m_pActiveShell->GetCursor()->GetPoint()->nNode, + m_pActiveShell->GetCursor()->GetPoint()->nContent)); + switch(m_nLastSelType = pCnt->GetParent()->GetType()) { case ContentTypeId::TEXTFIELD: @@ -5306,25 +5363,50 @@ void SwContentTree::GotoContent(const SwContent* pCnt) default: break; } - if (m_pActiveShell->IsFrameSelected() || m_pActiveShell->IsObjSelected()) + if (m_bSelectTo) { - m_pActiveShell->HideCursor(); - m_pActiveShell->EnterSelFrameMode(); - } + m_pActiveShell->SttCursorMove(); + while (m_pActiveShell->IsCursorInTable()) + { + m_pActiveShell->MoveTable(GotoCurrTable, fnTableStart); + if (!m_pActiveShell->Left(SwCursorSkipMode::Chars, false, 1, false)) + break; // Table is at the beginning of the document. It can't be selected this way. + } + m_pActiveShell->EndCursorMove(); - SwView& rView = m_pActiveShell->GetView(); - rView.StopShellTimer(); - rView.GetPostItMgr()->SetActiveSidebarWin(nullptr); - rView.GetEditWin().GrabFocus(); + lcl_AssureStdModeAtShell(m_pActiveShell); + + m_pActiveShell->SetMark(); + m_pActiveShell->GetCursor()->GetMark()->nNode = oPosition.value()->nNode; + m_pActiveShell->GetCursor()->GetMark()->nContent = oPosition.value()->nContent; + m_pActiveShell->UpdateCursor(); + + m_pActiveShell->GetView().GetEditWin().GrabFocus(); - // Assure cursor is in visible view area. - // (tdf#147041) Always show the navigated outline at the top of the visible view area. - if (pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE || - (!m_pActiveShell->IsCursorVisible() && !m_pActiveShell->IsFrameSelected() && - !m_pActiveShell->IsObjSelected())) + m_bSelectTo = false; + } + else { - Point aPoint(rView.GetVisArea().getX(), m_pActiveShell->GetCursorDocPos().getY()); - rView.SetVisArea(aPoint); + if (m_pActiveShell->IsFrameSelected() || m_pActiveShell->IsObjSelected()) + { + m_pActiveShell->HideCursor(); + m_pActiveShell->EnterSelFrameMode(); + } + + SwView& rView = m_pActiveShell->GetView(); + rView.StopShellTimer(); + rView.GetPostItMgr()->SetActiveSidebarWin(nullptr); + rView.GetEditWin().GrabFocus(); + + // Assure cursor is in visible view area. + // (tdf#147041) Always show the navigated outline at the top of the visible view area. + if (pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE || + (!m_pActiveShell->IsCursorVisible() && !m_pActiveShell->IsFrameSelected() && + !m_pActiveShell->IsObjSelected())) + { + Point aPoint(rView.GetVisArea().getX(), m_pActiveShell->GetCursorDocPos().getY()); + rView.SetVisArea(aPoint); + } } } |