summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Raykowski <raykowj@gmail.com>2022-10-16 22:07:32 -0800
committerJim Raykowski <raykowj@gmail.com>2022-10-30 23:52:35 +0100
commit060c529c9c450ddc22912ee88af5305c1fd063f3 (patch)
treec25036d95a69a0e2a8e778d9a52fbbc5a90d69f7
parent824b70fc473f96fca480f3d0d64f63234666db2b (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>
-rw-r--r--sd/source/ui/dlg/navigatr.cxx96
-rw-r--r--sd/source/ui/dlg/sdtreelb.cxx46
-rw-r--r--sd/source/ui/inc/navigatr.hxx1
-rw-r--r--sd/source/ui/inc/sdtreelb.hxx24
-rw-r--r--vcl/source/treelist/uiobject.cxx2
5 files changed, 126 insertions, 43 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; }
diff --git a/vcl/source/treelist/uiobject.cxx b/vcl/source/treelist/uiobject.cxx
index 89d92808c3fb..4ab051a868e1 100644
--- a/vcl/source/treelist/uiobject.cxx
+++ b/vcl/source/treelist/uiobject.cxx
@@ -157,7 +157,7 @@ void TreeListEntryUIObject::execute(const OUString& rAction, const StringMap& /*
}
else if (rAction == "DOUBLECLICK")
{
- mxTreeList->Select(mpEntry);
+ mxTreeList->SetCurEntry(mpEntry);
mxTreeList->DoubleClickHdl();
}
}