diff options
author | Caolán McNamara <caolanm@redhat.com> | 2019-11-29 10:21:11 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2019-12-01 20:51:12 +0100 |
commit | 19d17a739cc61341ca74cfa485e919c6012fe28c (patch) | |
tree | be3823e68681d796275149d08059872dde680534 /vcl | |
parent | b1f9e704cb9148b6e211005dab0cd153957a1b2b (diff) |
weld FmFieldWin
needs drag source support
fixes a leak of ColumnInfo data as well
Change-Id: I671834726aed3fd4de096b56baaa592f51a9e73e
Reviewed-on: https://gerrit.libreoffice.org/84147
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/treeglue.hxx | 7 | ||||
-rw-r--r-- | vcl/inc/unx/gtk/gtkinst.hxx | 7 | ||||
-rw-r--r-- | vcl/source/app/salvtables.cxx | 14 | ||||
-rw-r--r-- | vcl/source/treelist/treelistbox.cxx | 27 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkframe.cxx | 34 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 98 |
6 files changed, 161 insertions, 26 deletions
diff --git a/vcl/inc/treeglue.hxx b/vcl/inc/treeglue.hxx index 69975035bbcc..9de3a9d4222a 100644 --- a/vcl/inc/treeglue.hxx +++ b/vcl/inc/treeglue.hxx @@ -56,7 +56,7 @@ public: class LclTabListBox final : 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 74409d3cb51f..b4a516b3a28a 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 b7e974e02195..3bfc4e1e92a7 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -3438,7 +3438,7 @@ private: 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; @@ -4350,6 +4350,11 @@ public: set_id(rVclIter.iter, rId); } + virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants) override + { + m_xTreeView->SetDragHelper(rHelper, eDNDConstants); + } + virtual void set_selection_mode(SelectionMode eMode) override { m_xTreeView->SetSelectionMode(eMode); @@ -4582,7 +4587,7 @@ public: 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>()); @@ -4651,9 +4656,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 601574b95d23..fc73a389bfb2 100644 --- a/vcl/source/treelist/treelistbox.cxx +++ b/vcl/source/treelist/treelistbox.cxx @@ -373,6 +373,7 @@ SvTreeListBox::SvTreeListBox(vcl::Window* pParent, WinBits nWinStyle) : mbQuickSearch(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 91df150c26cf..8483304923e9 100644 --- a/vcl/unx/gtk3/gtk3gtkframe.cxx +++ b/vcl/unx/gtk3/gtk3gtkframe.cxx @@ -4231,18 +4231,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 @@ -4257,11 +4277,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 976ed97be496..39b3357fe4a2 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -22,6 +22,7 @@ #include <headless/svpvd.hxx> #include <headless/svpbmp.hxx> #include <vcl/inputtypes.hxx> +#include <vcl/transfer.hxx> #include <unx/genpspgraphics.h> #include <rtl/strbuf.hxx> #include <sal/log.hxx> @@ -7945,6 +7946,18 @@ namespace return -1; } + GdkDragAction VclToGdk(sal_Int8 dragOperation) + { + GdkDragAction eRet(static_cast<GdkDragAction>(0)); + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY) + eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_COPY); + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE) + eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_MOVE); + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK) + eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_LINK); + return eRet; + } + struct GtkInstanceTreeIter : public weld::TreeIter { GtkInstanceTreeIter(const GtkInstanceTreeIter* pOrig) @@ -7993,6 +8006,7 @@ private: std::vector<int> m_aSavedSortColumns; std::vector<int> m_aViewColToModelCol; std::vector<int> m_aModelColToViewCol; + rtl::Reference<GtkDragSource> m_xDragSource; bool m_bWorkAroundBadDragRegion; bool m_bInDrag; gint m_nTextCol; @@ -8008,6 +8022,9 @@ private: gulong m_nPopupMenuSignalId; gulong m_nDragBeginSignalId; gulong m_nDragEndSignalId; + gulong m_nDragFailedSignalId; + gulong m_nDragDataDeleteignalId; + gulong m_nDragGetSignalId; gulong m_nKeyPressSignalId; ImplSVEvent* m_pChangeEvent; @@ -8392,15 +8409,63 @@ private: return default_sort_func(pModel, a, b, m_xSorter.get()); } - static void signalDragBegin(GtkWidget*, GdkDragContext*, gpointer widget) + static void signalDragBegin(GtkWidget*, GdkDragContext* context, gpointer widget) { GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); - g_DragSource = pThis; + 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); + } } - static void signalDragEnd(GtkWidget*, GdkDragContext*, gpointer) + 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) @@ -8463,6 +8528,9 @@ public: , 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_pChangeEvent(nullptr) { @@ -9649,6 +9717,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(); @@ -9876,6 +9962,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); GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore); g_signal_handler_disconnect(pModel, m_nRowDeletedSignalId); |