tdf#145359 related: SdNavigator dnd
This is an enhancement patch that provides drag and drop capability
within the Navigator page object tree to allow arranging object
navigation order and grouping of objects.
Change-Id: I76996cd909765fb3503cf077566bec267b7705e2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142640
Tested-by: Jenkins
Reviewed-by: Jim Raykowski <raykowj@gmail.com>
diff --git a/sd/source/ui/dlg/navigatr.cxx b/sd/source/ui/dlg/navigatr.cxx
index 98883e7..cdc2db1 100644
--- a/sd/source/ui/dlg/navigatr.cxx
+++ b/sd/source/ui/dlg/navigatr.cxx
@@ -808,7 +808,7 @@ void SdNavigatorControllerItem::StateChangedAtToolBoxControl( sal_uInt16 nSId,
if (nState & NavState::TableUpdate)
{
// InitTlb; is initiated by Slot
if (maUpdateRequest)
if (maUpdateRequest && !pNavigatorWin->GetObjects().get_treeview().has_focus())
maUpdateRequest();
}
}
diff --git a/sd/source/ui/dlg/sdtreelb.cxx b/sd/source/ui/dlg/sdtreelb.cxx
index 8a9002a..a90a76a 100644
--- a/sd/source/ui/dlg/sdtreelb.cxx
+++ b/sd/source/ui/dlg/sdtreelb.cxx
@@ -379,8 +379,8 @@ namespace
std::unique_ptr<weld::TreeIter> xSourceParent(rTreeView.make_iterator(xSource.get()));
bool bSourceHasParent = rTreeView.iter_parent(*xSourceParent);
// level 1 objects only
if (!bSourceHasParent || rTreeView.get_iter_depth(*xSourceParent))
// disallow root drag
if (!bSourceHasParent)
return false;
SdrObject* pSourceObject = weld::fromId<SdrObject*>(rTreeView.get_id(*xSource));
@@ -495,20 +495,36 @@ sal_Int8 SdPageObjsTLVDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
return DND_ACTION_NONE;
// disallow when root is drop target
if (m_rTreeView.get_iter_depth(*xTarget) == 0)
return DND_ACTION_NONE;
// disallow if there is no source entry selected
std::unique_ptr<weld::TreeIter> xSource(m_rTreeView.make_iterator());
if (!m_rTreeView.get_selected(xSource.get()))
return DND_ACTION_NONE;
// disallow when root is source
if (m_rTreeView.get_iter_depth(*xSource) == 0)
return DND_ACTION_NONE;
// disallow when the source is the parent or ancestoral parent of the target
std::unique_ptr<weld::TreeIter> xTargetParent(m_rTreeView.make_iterator(xTarget.get()));
while (m_rTreeView.get_iter_depth(*xTargetParent))
m_rTreeView.iter_parent(*xTargetParent);
while (m_rTreeView.get_iter_depth(*xTargetParent) > 1)
{
if (!m_rTreeView.iter_parent(*xTargetParent) ||
m_rTreeView.iter_compare(*xSource, *xTargetParent) == 0)
return DND_ACTION_NONE;
}
std::unique_ptr<weld::TreeIter> xSourceParent(m_rTreeView.make_iterator(xSource.get()));
while (m_rTreeView.get_iter_depth(*xSourceParent))
m_rTreeView.iter_parent(*xSourceParent);
// can only drop within the same page
if (m_rTreeView.iter_compare(*xTargetParent, *xSourceParent) != 0)
// disallow drop when source and target are not within the same page
std::unique_ptr<weld::TreeIter> xSourcePage(m_rTreeView.make_iterator(xSource.get()));
std::unique_ptr<weld::TreeIter> xTargetPage(m_rTreeView.make_iterator(xTarget.get()));
while (m_rTreeView.get_iter_depth(*xTargetPage))
m_rTreeView.iter_parent(*xTargetPage);
while (m_rTreeView.get_iter_depth(*xSourcePage))
m_rTreeView.iter_parent(*xSourcePage);
if (m_rTreeView.iter_compare(*xTargetPage, *xSourcePage) != 0)
return DND_ACTION_NONE;
return DND_ACTION_MOVE;
@@ -529,35 +545,73 @@ sal_Int8 SdPageObjsTLVDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt )
return DND_ACTION_NONE;
std::unique_ptr<weld::TreeIter> xTarget(m_rTreeView.make_iterator());
if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), false))
return DND_ACTION_NONE;
int nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget) + 1;
auto nIterCompare = m_rTreeView.iter_compare(*xSource, *xTarget);
if (nIterCompare == 0)
{
// drop position is the same as source position
return DND_ACTION_NONE;
}
SdrObject* pTargetObject = weld::fromId<SdrObject*>(m_rTreeView.get_id(*xTarget));
SdrObject* pSourceObject = weld::fromId<SdrObject*>(m_rTreeView.get_id(*xSource));
if (pSourceObject == reinterpret_cast<SdrObject*>(1))
pSourceObject = nullptr;
if (pTargetObject == reinterpret_cast<SdrObject*>(1))
pTargetObject = nullptr;
if (pTargetObject != nullptr && pSourceObject != nullptr)
{
SdrPage* pObjectList = pSourceObject->getSdrPageFromSdrObject();
if (pObjectList != nullptr)
{
sal_uInt32 nNewPosition;
if (pTargetObject == reinterpret_cast<SdrObject*>(1))
{
nNewPosition = 0;
nTargetPos = 0;
}
else
nNewPosition = pTargetObject->GetNavigationPosition() + 1;
pObjectList->SetObjectNavigationPosition(*pSourceObject, nNewPosition);
}
std::unique_ptr<weld::TreeIter> xSourceParent(m_rTreeView.make_iterator(xSource.get()));
m_rTreeView.iter_parent(*xSourceParent);
std::unique_ptr<weld::TreeIter> xTargetParent(m_rTreeView.make_iterator(xTarget.get()));
m_rTreeView.iter_parent(*xTargetParent);
m_rTreeView.move_subtree(*xSource, xSourceParent.get(), nTargetPos);
int nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget);
// Make the tree view what the model will be when it is changed below.
m_rTreeView.move_subtree(*xSource, xTargetParent.get(), nTargetPos);
m_rTreeView.iter_previous_sibling(*xTarget);
m_rTreeView.set_cursor(*xTarget);
if (m_rTreeView.iter_compare(*xSourceParent, *xTargetParent) == 0 && nIterCompare < 0)
nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget);
// Remove the source object from soure parent list and insert it in the target parent list.
SdrObject* pSourceParentObject = weld::fromId<SdrObject*>(m_rTreeView.get_id(*xSourceParent));
SdrObject* pTargetParentObject = weld::fromId<SdrObject*>(m_rTreeView.get_id(*xTargetParent));
// Presumably there is need for a hard reference to hold on to the removed object so it is
// guaranteed to be valid for insert back into an object list.
rtl::Reference<SdrObject> rSourceObject;
// remove object
if (pSourceParentObject == reinterpret_cast<SdrObject*>(1))
{
rSourceObject = pObjectList->NbcRemoveObject(pSourceObject->GetOrdNum());
}
else
{
SdrObjList* pList = pSourceParentObject->GetSubList();
rSourceObject = pList->NbcRemoveObject(pSourceObject->GetOrdNum());
}
// insert object
if (pTargetParentObject == reinterpret_cast<SdrObject*>(1))
{
pObjectList->NbcInsertObject(rSourceObject.get());
pObjectList->SetObjectNavigationPosition(*rSourceObject, nTargetPos);
}
else
{
SdrObjList* pList = pTargetParentObject->GetSubList();
pList->NbcInsertObject(rSourceObject.get(), nTargetPos);
pList->SetObjectNavigationPosition(*rSourceObject, nTargetPos);
}
}
return DND_ACTION_NONE;
diff --git a/sd/uiconfig/simpress/ui/navigatorpanel.ui b/sd/uiconfig/simpress/ui/navigatorpanel.ui
index 98d22df..1059f7e 100644
--- a/sd/uiconfig/simpress/ui/navigatorpanel.ui
+++ b/sd/uiconfig/simpress/ui/navigatorpanel.ui
@@ -1,33 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.36.0 -->
<!-- Generated with glade 3.40.0 -->
<interface domain="sd">
<requires lib="gtk+" version="3.20"/>
<object class="GtkMenu" id="dragmodemenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<object class="GtkRadioMenuItem" id="1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes" context="navigatorpanelSTR_DRAGTYPE_URL">Insert as Hyperlink</property>
<property name="draw_as_radio">True</property>
<property name="draw-as-radio">True</property>
</object>
</child>
<child>
<object class="GtkRadioMenuItem" id="2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes" context="navigatorpanel|STR_DRAGTYPE_LINK">Insert as Link</property>
<property name="draw_as_radio">True</property>
<property name="draw-as-radio">True</property>
<property name="group">1</property>
</object>
</child>
<child>
<object class="GtkRadioMenuItem" id="3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes" context="navigatorpanel|STR_DRAGTYPE_EMBEDDED">Insert as Copy</property>
<property name="draw_as_radio">True</property>
<property name="draw-as-radio">True</property>
<property name="group">1</property>
</object>
</child>
@@ -45,24 +45,24 @@
<!-- n-columns=1 n-rows=1 -->
<object class="GtkGrid" id="NavigatorPanel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="border_width">6</property>
<property name="border-width">6</property>
<child>
<!-- n-columns=1 n-rows=1 -->
<!-- n-columns=1 n-rows=3 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="row_spacing">3</property>
<property name="column_spacing">6</property>
<property name="row-spacing">3</property>
<property name="column-spacing">6</property>
<child>
<object class="GtkComboBoxText" id="documents">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes" context="navigatorpanel|documents|tooltip_text">Document</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes" context="navigatorpanel|documents|tooltip_text">Document</property>
<child internal-child="accessible">
<object class="AtkObject" id="documents-atkobject">
<property name="AtkObject::accessible-name" translatable="yes" context="navigatorpanel|documents-atkobject">Active Window</property>
@@ -71,30 +71,29 @@
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="tree">
<property name="width_request">-1</property>
<property name="width-request">-1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="model">liststore2</property>
<property name="headers_visible">False</property>
<property name="headers-visible">False</property>
<property name="reorderable">True</property>
<property name="search_column">1</property>
<property name="enable_tree_lines">True</property>
<property name="search-column">1</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="Macro Library List-selection11"/>
</child>
@@ -125,22 +124,23 @@
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="toolbox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property>
<property name="toolbar_style">icons</property>
<property name="toolbar-style">icons</property>
<property name="icon_size">2</property>
<child>
<object class="GtkToolButton" id="first">
<property name="visible">True</property>
<property name="tooltip_text" translatable="yes" context="navigatorpanel|first|tooltip_text">First Slide</property>
<property name="icon_name">sd/res/nv03.png</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes" context="navigatorpanel|first|tooltip_text">First Slide</property>
<property name="icon-name">sd/res/nv03.png</property>
<child internal-child="accessible">
<object class="AtkObject" id="first-atkobject">
<property name="AtkObject::accessible-description" translatable="yes" context="navigatorpanel|extended_tip|first">Jumps to the first page.</property>
@@ -155,8 +155,9 @@
<child>
<object class="GtkToolButton" id="previous">
<property name="visible">True</property>
<property name="tooltip_text" translatable="yes" context="navigatorpanel|previous|tooltip_text">Previous Slide</property>
<property name="icon_name">sd/res/nv04.png</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes" context="navigatorpanel|previous|tooltip_text">Previous Slide</property>
<property name="icon-name">sd/res/nv04.png</property>
<child internal-child="accessible">
<object class="AtkObject" id="previous-atkobject">
<property name="AtkObject::accessible-description" translatable="yes" context="navigatorpanel|extended_tip|previous">Moves back one page.</property>
@@ -171,8 +172,9 @@
<child>
<object class="GtkToolButton" id="next">
<property name="visible">True</property>
<property name="tooltip_text" translatable="yes" context="navigatorpanel|next|tooltip_text">Next Slide</property>
<property name="icon_name">sd/res/nv05.png</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes" context="navigatorpanel|next|tooltip_text">Next Slide</property>
<property name="icon-name">sd/res/nv05.png</property>
<child internal-child="accessible">
<object class="AtkObject" id="next-atkobject">
<property name="AtkObject::accessible-description" translatable="yes" context="navigatorpanel|extended_tip|next">Move forward one page.</property>
@@ -187,8 +189,9 @@
<child>
<object class="GtkToolButton" id="last">
<property name="visible">True</property>
<property name="tooltip_text" translatable="yes" context="navigatorpanel|last|tooltip_text">Last Slide</property>
<property name="icon_name">sd/res/nv06.png</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes" context="navigatorpanel|last|tooltip_text">Last Slide</property>
<property name="icon-name">sd/res/nv06.png</property>
<child internal-child="accessible">
<object class="AtkObject" id="last-atkobject">
<property name="AtkObject::accessible-description" translatable="yes" context="navigatorpanel|extended_tip|last">Jumps to the last page.</property>
@@ -203,7 +206,7 @@
<child>
<object class="GtkSeparatorToolItem" id="separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="hexpand">True</property>
</object>
@@ -215,8 +218,9 @@
<child>
<object class="GtkMenuToolButton" id="dragmode">
<property name="visible">True</property>
<property name="tooltip_text" translatable="yes" context="navigatorpanel|dragmode|tooltip_text">Drag Mode</property>
<property name="icon_name">sd/res/nv09.png</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes" context="navigatorpanel|dragmode|tooltip_text">Drag Mode</property>
<property name="icon-name">sd/res/nv09.png</property>
<child internal-child="accessible">
<object class="AtkObject" id="dragmode-atkobject">
<property name="AtkObject::accessible-description" translatable="yes" context="navigatorpanel|extended_tip|dragmode">Drag and drop slides and named objects into the active slide.</property>
@@ -231,8 +235,9 @@
<child>
<object class="GtkMenuToolButton" id="shapes">
<property name="visible">True</property>
<property name="tooltip_text" translatable="yes" context="navigatorpanel|shapes|tooltip_text">Show Shapes</property>
<property name="icon_name">sd/res/graphic.png</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes" context="navigatorpanel|shapes|tooltip_text">Show Shapes</property>
<property name="icon-name">sd/res/graphic.png</property>
<child internal-child="accessible">
<object class="AtkObject" id="shapes-atkobject">
<property name="AtkObject::accessible-description" translatable="yes" context="navigatorpanel|extended_tip|shapes">In the submenu you can choose to display a list of all shapes or only the named shapes. Use drag-and-drop in the list to reorder the shapes. When you set the focus to a slide and press the Tab key, the next shape in the defined order is selected.</property>
@@ -246,14 +251,14 @@
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child internal-child="accessible">
@@ -264,23 +269,23 @@
</object>
<object class="GtkMenu" id="shapemenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<object class="GtkRadioMenuItem" id="named">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes" context="navigatorpanel|STR_NAVIGATOR_SHOW_NAMED_SHAPES">Named shapes</property>
<property name="use_underline">True</property>
<property name="draw_as_radio">True</property>
<property name="use-underline">True</property>
<property name="draw-as-radio">True</property>
</object>
</child>
<child>
<object class="GtkRadioMenuItem" id="all">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes" context="navigatorpanel|STR_NAVIGATOR_SHOW_ALL_SHAPES">All shapes</property>
<property name="use_underline">True</property>
<property name="draw_as_radio">True</property>
<property name="use-underline">True</property>
<property name="draw-as-radio">True</property>
<property name="group">named</property>
</object>
</child>