sw/source/uibase/inc/conttree.hxx  |    5 +
 sw/source/uibase/utlui/content.cxx |  132 +++++++++++++++++++++++++++++--------
 vcl/source/window/seleng.cxx       |    1 
 3 files changed, 113 insertions(+), 25 deletions(-)

New commits:
commit 50deb478e97aa9cfd023c5fa2f9d567b0b5797c2
Author:     Jim Raykowski <rayk...@gmail.com>
AuthorDate: Thu Apr 27 20:32:03 2023 -0800
Commit:     Jim Raykowski <rayk...@gmail.com>
CommitDate: Sun May 7 01:23:20 2023 +0200

    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 <rayk...@gmail.com>

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,8 +2339,35 @@ 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?
@@ -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);
+        }
     }
 }
 
diff --git a/vcl/source/window/seleng.cxx b/vcl/source/window/seleng.cxx
index f81ffe6cd6d3..9cb70cf99d83 100644
--- a/vcl/source/window/seleng.cxx
+++ b/vcl/source/window/seleng.cxx
@@ -181,6 +181,7 @@ bool SelectionEngine::SelMouseButtonDown( const MouseEvent& 
rMEvt )
             {
                 ReleaseMouse();
                 nFlags &= ~SelectionEngineFlags::IN_SEL;
+                pFunctionSet->SetCursorAtPoint(aPos);
                 return false;
             }
             if ( nFlags & SelectionEngineFlags::ADD_ALW )

Reply via email to