diff options
author | Jim Raykowski <raykowj@gmail.com> | 2022-10-16 22:07:32 -0800 |
---|---|---|
committer | Jim Raykowski <raykowj@gmail.com> | 2022-10-30 23:52:35 +0100 |
commit | 060c529c9c450ddc22912ee88af5305c1fd063f3 (patch) | |
tree | c25036d95a69a0e2a8e778d9a52fbbc5a90d69f7 /sd | |
parent | 824b70fc473f96fca480f3d0d64f63234666db2b (diff) |
tdf#129610 SdNavigator: Realize multiple selection of objects
This enhancement patch makes possible, mutiple selection of objects
in the draw view using the Navigator page/objects tree. Standard
multi-select mouse and keyboard methods, Ctrl/Shift + mouse button/
keyboard navigation keys, seem to work as expected with gtk3,
x11, and qt vcl backends. Double mouse click and the Enter key, moves
keyboard focus to the selected objects selection frame. Single mouse
click and keyboard navigation keys select the object in the view
while keeping the keyboard focus in the Navigator tree. Patch code
done to make navigation to empty name objects, commit
f0878173e1963cf8db5f60ced6d19da24e18bc41, is moved to the
SdNavigatorWin selection object handler, ClickObjectHdl, by this
patch.
UITesting:
TreeListEntryUIObject "DOUBLECLICK" action change:
Multiple selection as implemented in this patch, requires the tree
list entry to become the cursor entry when selected.
Change-Id: I58a36117242e40ce2811488c1fa8ef2aa72b28e5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141440
Tested-by: Jenkins
Reviewed-by: Jim Raykowski <raykowj@gmail.com>
Diffstat (limited to 'sd')
-rw-r--r-- | sd/source/ui/dlg/navigatr.cxx | 96 | ||||
-rw-r--r-- | sd/source/ui/dlg/sdtreelb.cxx | 46 | ||||
-rw-r--r-- | sd/source/ui/inc/navigatr.hxx | 1 | ||||
-rw-r--r-- | sd/source/ui/inc/sdtreelb.hxx | 24 |
4 files changed, 125 insertions, 42 deletions
diff --git a/sd/source/ui/dlg/navigatr.cxx b/sd/source/ui/dlg/navigatr.cxx index 6aca8fd0f2fb..162b3011a23d 100644 --- a/sd/source/ui/dlg/navigatr.cxx +++ b/sd/source/ui/dlg/navigatr.cxx @@ -67,6 +67,7 @@ SdNavigatorWin::SdNavigatorWin(weld::Widget* pParent, SfxBindings* pInBindings, mxTlbObjects->connect_row_activated(LINK(this, SdNavigatorWin, ClickObjectHdl)); mxTlbObjects->set_selection_mode(SelectionMode::Multiple); + mxTlbObjects->connect_mouse_release(LINK(this, SdNavigatorWin, MouseReleaseHdl)); mxToolbox->connect_clicked(LINK(this, SdNavigatorWin, SelectToolboxHdl)); mxToolbox->connect_menu_toggled(LINK(this, SdNavigatorWin, DropdownClickToolBoxHdl)); @@ -232,6 +233,11 @@ SdPageObjsTLV& SdNavigatorWin::GetObjects() return *mxTlbObjects; } +IMPL_STATIC_LINK_NOARG(SdNavigatorWin, MouseReleaseHdl, const MouseEvent&, bool) +{ + return true; +} + IMPL_LINK(SdNavigatorWin, SelectToolboxHdl, const OString&, rCommand, void) { PageJump ePage = PAGE_NONE; @@ -291,14 +297,80 @@ IMPL_LINK_NOARG(SdNavigatorWin, ClickObjectHdl, weld::TreeView&, bool) // if it is the active window, we jump to the page if( pInfo && pInfo->IsActive() ) { - OUString aStr(mxTlbObjects->get_selected_text()); + OUString aStr(mxTlbObjects->get_cursor_text()); if( !aStr.isEmpty() ) { - SfxStringItem aItem( SID_NAVIGATOR_OBJECT, aStr ); - mpBindings->GetDispatcher()->ExecuteList( - SID_NAVIGATOR_OBJECT, - SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem }); + sd::DrawDocShell* pDocShell = pInfo->mpDocShell; + if (!pDocShell) + return false; + sd::ViewShell* pViewShell = pDocShell->GetViewShell(); + if (!pViewShell) + return false; + SdrView* pDrawView = pViewShell->GetDrawView(); + if (!pDrawView) + return false; + + // Save the selected tree entries re-mark the objects in the view after navigation. + auto vSelectedEntryIds = mxTlbObjects->GetSelectedEntryIds(); + + // Page entries in the tree have id value 1. Object entries have id value of + // the address of the pointer to the object. + const auto& rCursorEntryId = mxTlbObjects->get_cursor_id(); + auto nCursorEntryId = rCursorEntryId.toInt64(); + SdrObject* pCursorEntryObject = weld::fromId<SdrObject*>(rCursorEntryId); + + bool bIsCursorEntrySelected(std::find(vSelectedEntryIds.begin(), + vSelectedEntryIds.end(), + rCursorEntryId) != vSelectedEntryIds.end()); + + if (bIsCursorEntrySelected) + { + // Set a temporary name, if need be, so the object can be navigated to. + bool bCursorEntryObjectHasEmptyName = false; + if (nCursorEntryId != 1 && pCursorEntryObject + && pCursorEntryObject->GetName().isEmpty()) + { + bCursorEntryObjectHasEmptyName = true; + bool bUndo = pCursorEntryObject->getSdrModelFromSdrObject().IsUndoEnabled(); + pCursorEntryObject->getSdrModelFromSdrObject().EnableUndo(false); + pCursorEntryObject->SetName(aStr, false); + pCursorEntryObject->getSdrModelFromSdrObject().EnableUndo(bUndo); + } + + // All objects are unmarked when navigating to an object. + SfxStringItem aItem(SID_NAVIGATOR_OBJECT, aStr); + mpBindings->GetDispatcher()->ExecuteList(SID_NAVIGATOR_OBJECT, + SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem }); + + if (bCursorEntryObjectHasEmptyName) + { + bool bUndo = pCursorEntryObject->getSdrModelFromSdrObject().IsUndoEnabled(); + pCursorEntryObject->getSdrModelFromSdrObject().EnableUndo(false); + pCursorEntryObject->SetName(OUString(), false); + pCursorEntryObject->getSdrModelFromSdrObject().EnableUndo(bUndo); + } + + // re-mark the objects + if (bIsCursorEntrySelected) + { + // Mark the objects in the view that are selected in the Navigator tree. + for (auto& rEntryId: vSelectedEntryIds) + { + if (rEntryId != "1") + { + SdrObject* pEntryObject = weld::fromId<SdrObject*>(rEntryId); + if (pEntryObject) + pDrawView->MarkObj(pEntryObject, pDrawView->GetSdrPageView()); + } + } + } + } + else if (nCursorEntryId != 1 && pCursorEntryObject) + { + // unmark + pDrawView->MarkObj(pCursorEntryObject, pDrawView->GetSdrPageView(), true); + } // moved here from SetGetFocusHdl. Reset the // focus only if something has been selected in the @@ -316,17 +388,9 @@ IMPL_LINK_NOARG(SdNavigatorWin, ClickObjectHdl, weld::TreeView&, bool) // still the slide sorter. Explicitly try to grab the draw // shell focus, so follow-up operations work with the object // and not with the whole slide. - sd::DrawDocShell* pDocShell = pInfo->mpDocShell; - if (pDocShell) - { - sd::ViewShell* pViewShell = pDocShell->GetViewShell(); - if (pViewShell) - { - vcl::Window* pWindow = pViewShell->GetActiveWindow(); - if (pWindow) - pWindow->GrabFocus(); - } - } + vcl::Window* pWindow = pViewShell->GetActiveWindow(); + if (pWindow) + pWindow->GrabFocus(); if (!mxTlbObjects->IsNavigationGrabsFocus()) // This is the case when keyboard navigation inside the diff --git a/sd/source/ui/dlg/sdtreelb.cxx b/sd/source/ui/dlg/sdtreelb.cxx index 3e86c4bc2376..d63b1cf13645 100644 --- a/sd/source/ui/dlg/sdtreelb.cxx +++ b/sd/source/ui/dlg/sdtreelb.cxx @@ -304,7 +304,9 @@ IMPL_LINK(SdPageObjsTLV, KeyInputHdl, const KeyEvent&, rKEvt, bool) else m_xTreeView->expand_row(*xCursor); } + m_bNavigationGrabsFocus = true; m_aRowActivatedHdl.Call(*m_xTreeView); + m_bNavigationGrabsFocus = false; return true; } return m_aKeyPressHdl.Call(rKEvt); @@ -319,6 +321,9 @@ IMPL_LINK(SdPageObjsTLV, MousePressHdl, const MouseEvent&, rMEvt, bool) IMPL_LINK_NOARG(SdPageObjsTLV, MouseReleaseHdl, const MouseEvent&, bool) { + if (m_aMouseReleaseHdl.IsSet() && m_aMouseReleaseHdl.Call(MouseEvent())) + return false; + m_bSelectionHandlerNavigates = false; m_bNavigationGrabsFocus = true; return false; @@ -666,7 +671,7 @@ IMPL_LINK_NOARG(SdPageObjsTLV, RowActivatedHdl, weld::TreeView&, bool) Application::RemoveUserEvent(m_nRowActivateEventId); // post the event to process row activate after mouse press event m_nRowActivateEventId = Application::PostUserEvent(LINK(this, SdPageObjsTLV, AsyncRowActivatedHdl)); - return true; + return false; } IMPL_LINK_NOARG(SdPageObjsTLV, AsyncSelectHdl, void*, void) @@ -689,30 +694,7 @@ void SdPageObjsTLV::Select() m_aChangeHdl.Call(*m_xTreeView); if (m_bSelectionHandlerNavigates) - { - // Page items in the tree are given user data value 1. - // Drawing object items are given user data value of the object pointer they represent. - sal_Int64 nUserData = m_xTreeView->get_selected_id().toInt64(); - if (nUserData != 1) - { - SdrObject* pObject = reinterpret_cast<SdrObject*>(nUserData); - if (pObject && pObject->GetName().isEmpty()) - { - const bool bUndo = pObject->getSdrModelFromSdrObject().IsUndoEnabled(); - pObject->getSdrModelFromSdrObject().EnableUndo(false); - pObject->SetName(m_xTreeView->get_selected_text(), false); - pObject->getSdrModelFromSdrObject().EnableUndo(bUndo); - m_aRowActivatedHdl.Call(*m_xTreeView); - pObject->getSdrModelFromSdrObject().EnableUndo(false); - pObject->SetName(OUString(), false); - pObject->getSdrModelFromSdrObject().EnableUndo(bUndo); - } - else - m_aRowActivatedHdl.Call(*m_xTreeView); - } - else - m_aRowActivatedHdl.Call(*m_xTreeView); - } + m_aRowActivatedHdl.Call(*m_xTreeView); if (!m_pNavigator) { @@ -724,7 +706,7 @@ void SdPageObjsTLV::Select() OUString aURL = INetURLObject(pDocShell->GetMedium()->GetPhysicalName(), INetProtocol::File).GetMainURL(INetURLObject::DecodeMechanism::NONE); NavigatorDragType eDragType = m_pNavigator->GetNavigatorDragType(); - OUString sSelectedEntry = m_xTreeView->get_selected_text(); + OUString sSelectedEntry = get_cursor_text(); // what about multiple selections? aURL += "#" + sSelectedEntry; INetBookmark aBookmark(aURL, sSelectedEntry); @@ -791,6 +773,18 @@ std::vector<OUString> SdPageObjsTLV::GetSelectEntryList(const int nDepth) const return aEntries; } +std::vector<OUString> SdPageObjsTLV::GetSelectedEntryIds() const +{ + std::vector<OUString> vEntryIds; + + m_xTreeView->selected_foreach([this, &vEntryIds](weld::TreeIter& rEntry){ + vEntryIds.push_back(m_xTreeView->get_id(rEntry)); + return false; + }); + + return vEntryIds; +} + /** * Checks if it is a draw file and opens the BookmarkDoc depending of * the provided Docs diff --git a/sd/source/ui/inc/navigatr.hxx b/sd/source/ui/inc/navigatr.hxx index 7eeb2551a778..f0b7d1fca5e8 100644 --- a/sd/source/ui/inc/navigatr.hxx +++ b/sd/source/ui/inc/navigatr.hxx @@ -158,6 +158,7 @@ private: DECL_DLLPRIVATE_LINK( MenuSelectHdl, const OString&, void ); DECL_DLLPRIVATE_LINK( ShapeFilterCallback, const OString&, void ); DECL_DLLPRIVATE_LINK( KeyInputHdl, const KeyEvent&, bool ); + DECL_DLLPRIVATE_STATIC_LINK(SdNavigatorWin, MouseReleaseHdl, const MouseEvent&, bool); void SetDragImage(); diff --git a/sd/source/ui/inc/sdtreelb.hxx b/sd/source/ui/inc/sdtreelb.hxx index 84432f180834..38a797519654 100644 --- a/sd/source/ui/inc/sdtreelb.hxx +++ b/sd/source/ui/inc/sdtreelb.hxx @@ -105,6 +105,7 @@ private: Link<weld::TreeView&, void> m_aChangeHdl; Link<weld::TreeView&, bool> m_aRowActivatedHdl; Link<const KeyEvent&, bool> m_aKeyPressHdl; + Link<const MouseEvent&, bool> m_aMouseReleaseHdl; /** Return the name of the object. When the object has no user supplied name and the bCreate flag is <TRUE/> then a name is created @@ -216,6 +217,11 @@ public: m_aKeyPressHdl = rLink; } + void connect_mouse_release(const Link<const MouseEvent&, bool>& rLink) + { + m_aMouseReleaseHdl = rLink; + } + bool HasSelectedChildren(std::u16string_view rName); bool SelectEntry(std::u16string_view rName); void SelectEntry(const SdrObject* pObj); @@ -265,6 +271,22 @@ public: m_xTreeView->unselect_all(); } + OUString get_cursor_text() const + { + std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator()); + if (m_xTreeView->get_cursor(xIter.get())) + return m_xTreeView->get_text(*xIter); + return OUString(); + } + + OUString get_cursor_id() const + { + std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator()); + if (m_xTreeView->get_cursor(xIter.get())) + return m_xTreeView->get_id(*xIter); + return OUString(); + } + void SetViewFrame(const SfxViewFrame* pViewFrame); void Fill(const SdDrawDocument*, bool bAllPages, const OUString& rDocName); @@ -324,6 +346,8 @@ public: std::vector<OUString> GetSelectEntryList(const int nDepth) const; + std::vector<OUString> GetSelectedEntryIds() const; + SdDrawDocument* GetBookmarkDoc(SfxMedium* pMedium = nullptr); bool IsLinkableSelected() const { return m_bLinkableSelected; } |