include/vcl/salvtables.hxx | 5 + include/vcl/transfer.hxx | 2 include/vcl/treelistbox.hxx | 6 ++ include/vcl/weld.hxx | 10 +++ vcl/inc/treeglue.hxx | 7 +- vcl/inc/unx/gtk/gtkinst.hxx | 7 ++ vcl/source/app/salvtables.cxx | 12 +++- vcl/source/treelist/treelistbox.cxx | 27 +++++++--- vcl/unx/gtk3/gtk3gtkframe.cxx | 34 +++++++++---- vcl/unx/gtk3/gtk3gtkinst.cxx | 92 ++++++++++++++++++++++++++++++++++++ 10 files changed, 178 insertions(+), 24 deletions(-)
New commits: commit d4268144906ef261c6a7e32502925edd5c6dc16b Author: Szymon Kłos <szymon.k...@collabora.com> AuthorDate: Sat Dec 19 15:52:33 2020 +0100 Commit: Szymon Kłos <szymon.k...@collabora.com> CommitDate: Sat Dec 19 17:54:01 2020 +0100 Start Drag event support part of 19d17a7 Change-Id: I1a1b5fd4f4aedbf79f64fdb4334aadc014b4eabb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/108026 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Szymon Kłos <szymon.k...@collabora.com> diff --git a/include/vcl/salvtables.hxx b/include/vcl/salvtables.hxx index 401cbb0702a3..b96d02f0a5a8 100644 --- a/include/vcl/salvtables.hxx +++ b/include/vcl/salvtables.hxx @@ -1138,7 +1138,7 @@ protected: DECL_LINK(HeaderBarClickedHdl, HeaderBar*, void); DECL_LINK(ToggleHdl, SvLBoxButtonData*, void); DECL_LINK(ModelChangedHdl, SvTreeListBox*, void); - DECL_LINK(StartDragHdl, SvTreeListBox*, void); + DECL_LINK(StartDragHdl, SvTreeListBox*, bool); DECL_STATIC_LINK(SalInstanceTreeView, FinishDragHdl, SvTreeListBox*, void); DECL_LINK(EditingEntryHdl, SvTreeListEntry*, bool); typedef std::pair<SvTreeListEntry*, OUString> IterString; @@ -1373,6 +1373,9 @@ public: virtual void set_id(const weld::TreeIter& rIter, const OUString& rId) override; + virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper, + sal_uInt8 eDNDConstants) override; + virtual void set_selection_mode(SelectionMode eMode) override; virtual void all_foreach(const std::function<bool(weld::TreeIter&)>& func) override; diff --git a/include/vcl/transfer.hxx b/include/vcl/transfer.hxx index 75af922a007c..a0b773984d3b 100644 --- a/include/vcl/transfer.hxx +++ b/include/vcl/transfer.hxx @@ -483,7 +483,7 @@ public: struct TransferDataContainer_Impl; -class VCL_DLLPUBLIC TransferDataContainer final : public TransferableHelper +class VCL_DLLPUBLIC TransferDataContainer : public TransferableHelper { std::unique_ptr<TransferDataContainer_Impl> pImpl; diff --git a/include/vcl/treelistbox.hxx b/include/vcl/treelistbox.hxx index d0fcfabd9e01..537e4abc7a8d 100644 --- a/include/vcl/treelistbox.hxx +++ b/include/vcl/treelistbox.hxx @@ -227,9 +227,13 @@ class VCL_DLLPUBLIC SvTreeListBox SelectionMode eSelMode; sal_Int32 nMinWidthInChars; + sal_Int8 mnDragAction; + SvTreeListEntry* pEdEntry; SvLBoxItem* pEdItem; + rtl::Reference<TransferDataContainer> m_xTransferHelper; + protected: std::unique_ptr<SvImpLBox> pImpl; short nColumns; @@ -736,6 +740,8 @@ public: void SetForceMakeVisible(bool bEnable); virtual FactoryFunction GetUITestFactory() const override; + + void SetDragHelper(rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants); }; class SvInplaceEdit2 diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index 496f1e718f7c..3acf96b1fcf7 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -63,6 +63,7 @@ enum class PointerStyle; class SvNumberFormatter; class KeyEvent; class MouseEvent; +class TransferDataContainer; class OutputDevice; class VirtualDevice; struct SystemEnvData; @@ -709,7 +710,10 @@ protected: Link<const TreeIter&, bool> m_aCollapsingHdl; Link<TreeView&, void> m_aVisibleRangeChangedHdl; Link<TreeView&, void> m_aModelChangedHdl; + // if handler returns true, then menu has been show and event is consumed Link<const CommandEvent&, bool> m_aPopupMenuHdl; + // if handler returns true, drag is disallowed + Link<TreeView&, bool> m_aDragBeginHdl; std::function<int(const weld::TreeIter&, const weld::TreeIter&)> m_aCustomSort; std::vector<int> m_aRadioIndexes; @@ -978,6 +982,12 @@ public: m_aPopupMenuHdl = rLink; } + virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rTransferrable, + sal_uInt8 eDNDConstants) + = 0; + + void connect_drag_begin(const Link<TreeView&, bool>& rLink) { m_aDragBeginHdl = rLink; } + //all of them void select_all() { unselect(-1); } void unselect_all() { select(-1); } diff --git a/vcl/inc/treeglue.hxx b/vcl/inc/treeglue.hxx index 69641906aa17..49eccdbca4d5 100644 --- a/vcl/inc/treeglue.hxx +++ b/vcl/inc/treeglue.hxx @@ -56,7 +56,7 @@ public: class LclTabListBox : public SvTabListBox { Link<SvTreeListBox*, void> m_aModelChangedHdl; - Link<SvTreeListBox*, void> m_aStartDragHdl; + Link<SvTreeListBox*, bool> m_aStartDragHdl; Link<SvTreeListBox*, void> m_aEndDragHdl; Link<SvTreeListEntry*, bool> m_aEditingEntryHdl; Link<std::pair<SvTreeListEntry*, OUString>, bool> m_aEditedEntryHdl; @@ -68,7 +68,7 @@ public: } void SetModelChangedHdl(const Link<SvTreeListBox*, void>& rLink) { m_aModelChangedHdl = rLink; } - void SetStartDragHdl(const Link<SvTreeListBox*, void>& rLink) { m_aStartDragHdl = rLink; } + void SetStartDragHdl(const Link<SvTreeListBox*, bool>& rLink) { m_aStartDragHdl = rLink; } void SetEndDragHdl(const Link<SvTreeListBox*, void>& rLink) { m_aEndDragHdl = rLink; } void SetEditingEntryHdl(const Link<SvTreeListEntry*, bool>& rLink) { @@ -86,7 +86,8 @@ public: virtual void StartDrag(sal_Int8 nAction, const Point& rPosPixel) override { - m_aStartDragHdl.Call(this); + if (m_aStartDragHdl.Call(this)) + return; SvTabListBox::StartDrag(nAction, rPosPixel); } diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx index 4cf7369c7992..f2d049448a5c 100644 --- a/vcl/inc/unx/gtk/gtkinst.hxx +++ b/vcl/inc/unx/gtk/gtkinst.hxx @@ -150,6 +150,13 @@ public: { } + void set_datatransfer(const css::uno::Reference<css::datatransfer::XTransferable>& rTrans, + const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener); + + std::vector<GtkTargetEntry> FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats); + + void setActiveDragSource(); + virtual ~GtkDragSource() override; // XDragSource diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 4285b037c880..ee0e074bad2e 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -4294,6 +4294,11 @@ void SalInstanceTreeView::set_id(const weld::TreeIter& rIter, const OUString& rI set_id(rVclIter.iter, rId); } +void SalInstanceTreeView::enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants) +{ + m_xTreeView->SetDragHelper(rHelper, eDNDConstants); +} + void SalInstanceTreeView::set_selection_mode(SelectionMode eMode) { m_xTreeView->SetSelectionMode(eMode); @@ -4538,7 +4543,7 @@ SalInstanceTreeView::~SalInstanceTreeView() else { static_cast<LclTabListBox&>(*m_xTreeView).SetEndDragHdl(Link<SvTreeListBox*, void>()); - static_cast<LclTabListBox&>(*m_xTreeView).SetStartDragHdl(Link<SvTreeListBox*, void>()); + static_cast<LclTabListBox&>(*m_xTreeView).SetStartDragHdl(Link<SvTreeListBox*, bool>()); static_cast<LclTabListBox&>(*m_xTreeView).SetModelChangedHdl(Link<SvTreeListBox*, void>()); } m_xTreeView->SetPopupMenuHdl(Link<const CommandEvent&, bool>()); @@ -4604,9 +4609,12 @@ IMPL_LINK_NOARG(SalInstanceTreeView, ModelChangedHdl, SvTreeListBox*, void) signal_model_changed(); } -IMPL_LINK_NOARG(SalInstanceTreeView, StartDragHdl, SvTreeListBox*, void) +IMPL_LINK_NOARG(SalInstanceTreeView, StartDragHdl, SvTreeListBox*, bool) { + if (m_aDragBeginHdl.Call(*this)) + return true; g_DragSource = this; + return false; } IMPL_STATIC_LINK_NOARG(SalInstanceTreeView, FinishDragHdl, SvTreeListBox*, void) diff --git a/vcl/source/treelist/treelistbox.cxx b/vcl/source/treelist/treelistbox.cxx index 6c91289f019d..f6653c7b508d 100644 --- a/vcl/source/treelist/treelistbox.cxx +++ b/vcl/source/treelist/treelistbox.cxx @@ -373,6 +373,7 @@ SvTreeListBox::SvTreeListBox(vcl::Window* pParent, WinBits nWinStyle) : mbHoverSelection(false), eSelMode(SelectionMode::NONE), nMinWidthInChars(0), + mnDragAction(DND_ACTION_COPYMOVE | DND_ACTION_LINK), mbCenterAndClipText(false) { nImpFlags = SvTreeListBoxFlags::NONE; @@ -1152,7 +1153,6 @@ void SvTreeListBox::SetupDragOrigin() void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel ) { - Point aEventPos( rPosPixel ); MouseEvent aMouseEvt( aEventPos, 1, MouseEventModifiers::SELECT, MOUSE_LEFT ); MouseButtonUp( aMouseEvt ); @@ -1170,8 +1170,17 @@ void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel ) return; } - rtl::Reference<TransferDataContainer> pContainer = new TransferDataContainer; - nDragDropMode = NotifyStartDrag( *pContainer, pEntry ); + rtl::Reference<TransferDataContainer> xContainer = m_xTransferHelper; + + if (!xContainer) + { + xContainer.set(new TransferDataContainer); + // apparently some (unused) content is needed + xContainer->CopyAnyData( SotClipboardFormatId::TREELISTBOX, + "unused", SAL_N_ELEMENTS("unused") ); + } + + nDragDropMode = NotifyStartDrag( *xContainer, pEntry ); if( nDragDropMode == DragDropMode::NONE || 0 == GetSelectionCount() ) { nDragDropMode = nOldDragMode; @@ -1181,10 +1190,6 @@ void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel ) SetupDragOrigin(); - // apparently some (unused) content is needed - pContainer->CopyAnyData( SotClipboardFormatId::TREELISTBOX, - "unused", SAL_N_ELEMENTS("unused") ); - bool bOldUpdateMode = Control::IsUpdateMode(); Control::SetUpdateMode( true ); Update(); @@ -1196,7 +1201,13 @@ void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel ) // (GetSourceListBox()->EnableSelectionAsDropTarget( true, true );) EnableSelectionAsDropTarget( false ); - pContainer->StartDrag( this, DND_ACTION_COPYMOVE | DND_ACTION_LINK, GetDragFinishedHdl() ); + xContainer->StartDrag(this, mnDragAction, GetDragFinishedHdl()); +} + +void SvTreeListBox::SetDragHelper(rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants) +{ + m_xTransferHelper = rHelper; + mnDragAction = eDNDConstants; } void SvTreeListBox::DragFinished( sal_Int8 diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx index 4651f81a0830..4156316a7c3c 100644 --- a/vcl/unx/gtk3/gtk3gtkframe.cxx +++ b/vcl/unx/gtk3/gtk3gtkframe.cxx @@ -4227,18 +4227,38 @@ sal_uIntPtr GtkSalFrame::GetNativeWindowHandle() return GetNativeWindowHandle(m_pWindow); } +void GtkDragSource::set_datatransfer(const css::uno::Reference<css::datatransfer::XTransferable>& rTrans, + const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener) +{ + m_xListener = rListener; + m_xTrans = rTrans; +} + +void GtkDragSource::setActiveDragSource() +{ + // For LibreOffice internal D&D we provide the Transferable without Gtk + // intermediaries as a shortcut, see tdf#100097 for how dbaccess depends on this + g_ActiveDragSource = this; + g_DropSuccessSet = false; + g_DropSuccess = false; +} + +std::vector<GtkTargetEntry> GtkDragSource::FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats) +{ + return m_aConversionHelper.FormatsToGtk(rFormats); +} + void GtkDragSource::startDrag(const datatransfer::dnd::DragGestureEvent& rEvent, sal_Int8 sourceActions, sal_Int32 /*cursor*/, sal_Int32 /*image*/, const css::uno::Reference<css::datatransfer::XTransferable>& rTrans, const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener) { - m_xListener = rListener; - m_xTrans = rTrans; + set_datatransfer(rTrans, rListener); if (m_pFrame) { - css::uno::Sequence<css::datatransfer::DataFlavor> aFormats = rTrans->getTransferDataFlavors(); - std::vector<GtkTargetEntry> aGtkTargets(m_aConversionHelper.FormatsToGtk(aFormats)); + auto aFormats = m_xTrans->getTransferDataFlavors(); + std::vector<GtkTargetEntry> aGtkTargets(FormatsToGtk(aFormats)); GtkTargetList *pTargetList = gtk_target_list_new(aGtkTargets.data(), aGtkTargets.size()); gint nDragButton = 1; // default to left button @@ -4253,11 +4273,7 @@ void GtkDragSource::startDrag(const datatransfer::dnd::DragGestureEvent& rEvent, nDragButton = 2; } - // For LibreOffice internal D&D we provide the Transferable without Gtk - // intermediaries as a shortcut, see tdf#100097 for how dbaccess depends on this - g_ActiveDragSource = this; - g_DropSuccessSet = false; - g_DropSuccess = false; + setActiveDragSource(); m_pFrame->startDrag(nDragButton, rEvent.DragOriginX, rEvent.DragOriginY, VclToGdk(sourceActions), pTargetList); diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 8850c8f87c88..b5251c2cd90f 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -8168,6 +8168,7 @@ private: o3tl::sorted_vector<GtkTreePath*, CompareGtkTreePath> m_aExpandingPlaceHolderParents; std::vector<GtkSortType> m_aSavedSortTypes; std::vector<int> m_aSavedSortColumns; + rtl::Reference<GtkDragSource> m_xDragSource; bool m_bWorkAroundBadDragRegion; bool m_bInDrag; gint m_nTextCol; @@ -8186,6 +8187,9 @@ private: gulong m_nPopupMenuSignalId; gulong m_nDragBeginSignalId; gulong m_nDragEndSignalId; + gulong m_nDragFailedSignalId; + gulong m_nDragDataDeleteignalId; + gulong m_nDragGetSignalId; gulong m_nKeyPressSignalId; GtkAdjustment* m_pVAdjustment; ImplSVEvent* m_pChangeEvent; @@ -8643,6 +8647,65 @@ private: return default_sort_func(pModel, a, b, m_xSorter.get()); } + static void signalDragBegin(GtkWidget*, GdkDragContext* context, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->signal_drag_begin(context); + } + + void ensure_drag_source() + { + if (!m_xDragSource) + { + m_xDragSource.set(new GtkDragSource); + + m_nDragFailedSignalId = g_signal_connect(m_pWidget, "drag-failed", G_CALLBACK(signalDragFailed), this); + m_nDragDataDeleteignalId = g_signal_connect(m_pWidget, "drag-data-delete", G_CALLBACK(signalDragDelete), this); + m_nDragGetSignalId = g_signal_connect(m_pWidget, "drag-data-get", G_CALLBACK(signalDragDataGet), this); + } + } + + void signal_drag_begin(GdkDragContext* context) + { + if (m_aDragBeginHdl.Call(*this)) + { + gtk_drag_cancel(context); + return; + } + g_DragSource = this; + if (!m_xDragSource) + return; + m_xDragSource->setActiveDragSource(); + } + + static void signalDragEnd(GtkWidget* /*widget*/, GdkDragContext* context, gpointer widget) + { + g_DragSource = nullptr; + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + if (pThis->m_xDragSource.is()) + pThis->m_xDragSource->dragEnd(context); + } + + static gboolean signalDragFailed(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkDragResult /*result*/, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->m_xDragSource->dragFailed(); + return false; + } + + static void signalDragDelete(GtkWidget* /*widget*/, GdkDragContext* /*context*/, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->m_xDragSource->dragDelete(); + } + + static void signalDragDataGet(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkSelectionData *data, guint info, + guint /*time*/, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->m_xDragSource->dragDataGet(data, info); + } + bool signal_key_press(GdkEventKey* pEvent) { if (pEvent->keyval != GDK_KEY_Left && pEvent->keyval != GDK_KEY_Right) @@ -8749,6 +8812,11 @@ public: , m_nTestCollapseRowSignalId(g_signal_connect(pTreeView, "test-collapse-row", G_CALLBACK(signalTestCollapseRow), this)) , m_nVAdjustmentChangedSignalId(0) , m_nPopupMenuSignalId(g_signal_connect(pTreeView, "popup-menu", G_CALLBACK(signalPopupMenu), this)) + , m_nDragBeginSignalId(g_signal_connect(pTreeView, "drag-begin", G_CALLBACK(signalDragBegin), this)) + , m_nDragEndSignalId(g_signal_connect(pTreeView, "drag-end", G_CALLBACK(signalDragEnd), this)) + , m_nDragFailedSignalId(0) + , m_nDragDataDeleteignalId(0) + , m_nDragGetSignalId(0) , m_nKeyPressSignalId(g_signal_connect(pTreeView, "key-press-event", G_CALLBACK(signalKeyPress), this)) , m_pVAdjustment(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(pTreeView))) , m_pChangeEvent(nullptr) @@ -9980,6 +10048,24 @@ public: gtk_widget_hide(m_pWidget); } + virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants) override + { + css::uno::Reference<css::datatransfer::XTransferable> xTrans(rHelper.get()); + css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> xListener(rHelper.get()); + + ensure_drag_source(); + + auto aFormats = xTrans->getTransferDataFlavors(); + std::vector<GtkTargetEntry> aGtkTargets(m_xDragSource->FormatsToGtk(aFormats)); + + gtk_tree_view_enable_model_drag_source(m_pTreeView, GDK_BUTTON1_MASK, aGtkTargets.data(), aGtkTargets.size(), VclToGdk(eDNDConstants)); + + for (auto &a : aGtkTargets) + g_free(a.target); + + m_xDragSource->set_datatransfer(xTrans, xListener); + } + virtual void set_selection_mode(SelectionMode eMode) override { disable_notify_events(); @@ -10228,6 +10314,12 @@ public: g_signal_handler_disconnect(m_pTreeView, m_nKeyPressSignalId); g_signal_handler_disconnect(m_pTreeView, m_nDragEndSignalId); g_signal_handler_disconnect(m_pTreeView, m_nDragBeginSignalId); + if (m_nDragFailedSignalId) + g_signal_handler_disconnect(m_pTreeView, m_nDragFailedSignalId); + if (m_nDragDataDeleteignalId) + g_signal_handler_disconnect(m_pTreeView, m_nDragDataDeleteignalId); + if (m_nDragGetSignalId) + g_signal_handler_disconnect(m_pTreeView, m_nDragGetSignalId); g_signal_handler_disconnect(m_pTreeView, m_nPopupMenuSignalId); g_signal_handler_disconnect(m_pTreeModel, m_nRowDeletedSignalId); g_signal_handler_disconnect(m_pTreeModel, m_nRowInsertedSignalId); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits