[Libreoffice-commits] core.git: include/svx include/vcl svx/source svx/uiconfig svx/UIConfig_svx.mk vcl/inc vcl/source vcl/unx

Caolán McNamara (via logerrit) logerrit at kemper.freedesktop.org
Sun Dec 1 19:51:55 UTC 2019


 include/svx/dbaexchange.hxx         |   12 -
 include/vcl/transfer.hxx            |    2 
 include/vcl/treelistbox.hxx         |    6 
 include/vcl/weld.hxx                |   10 +
 svx/UIConfig_svx.mk                 |    1 
 svx/source/fmcomp/dbaexchange.cxx   |   29 ++--
 svx/source/form/tabwin.cxx          |  220 ++++++++++--------------------------
 svx/source/inc/tabwin.hxx           |   63 ++--------
 svx/uiconfig/ui/formfielddialog.ui  |   99 ++++++++++++++++
 vcl/inc/treeglue.hxx                |    7 -
 vcl/inc/unx/gtk/gtkinst.hxx         |    7 +
 vcl/source/app/salvtables.cxx       |   14 +-
 vcl/source/treelist/treelistbox.cxx |   27 +++-
 vcl/unx/gtk3/gtk3gtkframe.cxx       |   34 ++++-
 vcl/unx/gtk3/gtk3gtkinst.cxx        |   98 +++++++++++++++-
 15 files changed, 381 insertions(+), 248 deletions(-)

New commits:
commit 19d17a739cc61341ca74cfa485e919c6012fe28c
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Fri Nov 29 10:21:11 2019 +0000
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Sun Dec 1 20:51:12 2019 +0100

    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 at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/include/svx/dbaexchange.hxx b/include/svx/dbaexchange.hxx
index d831dc4e2ed0..bccdf5bacf00 100644
--- a/include/svx/dbaexchange.hxx
+++ b/include/svx/dbaexchange.hxx
@@ -51,15 +51,17 @@ namespace svx
 
     //= OColumnTransferable
 
-    class SAL_WARN_UNUSED SVX_DLLPUBLIC OColumnTransferable final : public TransferableHelper
+    class SAL_WARN_UNUSED SVX_DLLPUBLIC OColumnTransferable final : public TransferDataContainer
     {
     public:
+        OColumnTransferable(ColumnTransferFormatFlags nFormats);
+
         /** construct the transferable from a data access descriptor
 
             Note that some of the aspects, in particular all which cannot be represented
             as string, can only be transported via the CTF_COLUMN_DESCRIPTOR format.
 
-        @param _rDescriptor
+        @param rDescriptor
             The descriptor for the column. It must contain at least
             <ul><li>information sufficient to create a connection, that is, either one of DataSource, DatabaseLocation,
                     ConnectionResource, and DataAccessDescriptorProperty::Connection</li>
@@ -68,10 +70,8 @@ namespace svx
                 <li>a ColumnName or ColumnObject</li>
             </ul>
         */
-        OColumnTransferable(
-            const ODataAccessDescriptor& _rDescriptor,
-            ColumnTransferFormatFlags    _nFormats
-        );
+        void setDescriptor(const ODataAccessDescriptor& rDescriptor);
+
 
         /** construct the transferable from a DatabaseForm component and a field name
 
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 ecb1ce8029af..cb4945a96717 100644
--- a/include/vcl/treelistbox.hxx
+++ b/include/vcl/treelistbox.hxx
@@ -225,9 +225,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;
@@ -726,6 +730,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 abe71e42fedb..e7025b134506 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;
@@ -686,7 +687,10 @@ protected:
     Link<const TreeIter&, bool> m_aExpandingHdl;
     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;
@@ -937,6 +941,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/svx/UIConfig_svx.mk b/svx/UIConfig_svx.mk
index 9f6a55c266e3..f4a7e0abddb4 100644
--- a/svx/UIConfig_svx.mk
+++ b/svx/UIConfig_svx.mk
@@ -49,6 +49,7 @@ $(eval $(call gb_UIConfig_add_uifiles,svx,\
 	svx/uiconfig/ui/fontworkgallerydialog \
 	svx/uiconfig/ui/fontworkspacingdialog \
 	svx/uiconfig/ui/formdatamenu \
+	svx/uiconfig/ui/formfielddialog \
 	svx/uiconfig/ui/formlinkwarndialog \
 	svx/uiconfig/ui/formnavimenu \
 	svx/uiconfig/ui/functionmenu \
diff --git a/svx/source/fmcomp/dbaexchange.cxx b/svx/source/fmcomp/dbaexchange.cxx
index 0e6df6cfb871..698a7e6e6055 100644
--- a/svx/source/fmcomp/dbaexchange.cxx
+++ b/svx/source/fmcomp/dbaexchange.cxx
@@ -42,18 +42,22 @@ namespace svx
     using namespace ::com::sun::star::container;
     using namespace ::com::sun::star::datatransfer;
 
-    OColumnTransferable::OColumnTransferable(const ODataAccessDescriptor& _rDescriptor, ColumnTransferFormatFlags _nFormats )
-        :m_nFormatFlags(_nFormats)
+    OColumnTransferable::OColumnTransferable(ColumnTransferFormatFlags nFormats)
+        : m_nFormatFlags(nFormats)
+    {
+    }
+
+    void OColumnTransferable::setDescriptor(const ODataAccessDescriptor& rDescriptor)
     {
         OUString sDataSource, sDatabaseLocation, sConnectionResource, sCommand, sFieldName;
-        if ( _rDescriptor.has( DataAccessDescriptorProperty::DataSource ) )         _rDescriptor[ DataAccessDescriptorProperty::DataSource ] >>= sDataSource;
-        if ( _rDescriptor.has( DataAccessDescriptorProperty::DatabaseLocation ) )   _rDescriptor[ DataAccessDescriptorProperty::DatabaseLocation ] >>= sDatabaseLocation;
-        if ( _rDescriptor.has( DataAccessDescriptorProperty::ConnectionResource ) ) _rDescriptor[ DataAccessDescriptorProperty::ConnectionResource ] >>= sConnectionResource;
-        if ( _rDescriptor.has( DataAccessDescriptorProperty::Command ) )            _rDescriptor[ DataAccessDescriptorProperty::Command ] >>= sCommand;
-        if ( _rDescriptor.has( DataAccessDescriptorProperty::ColumnName ) )         _rDescriptor[ DataAccessDescriptorProperty::ColumnName ] >>= sFieldName;
+        if ( rDescriptor.has( DataAccessDescriptorProperty::DataSource ) )         rDescriptor[ DataAccessDescriptorProperty::DataSource ] >>= sDataSource;
+        if ( rDescriptor.has( DataAccessDescriptorProperty::DatabaseLocation ) )   rDescriptor[ DataAccessDescriptorProperty::DatabaseLocation ] >>= sDatabaseLocation;
+        if ( rDescriptor.has( DataAccessDescriptorProperty::ConnectionResource ) ) rDescriptor[ DataAccessDescriptorProperty::ConnectionResource ] >>= sConnectionResource;
+        if ( rDescriptor.has( DataAccessDescriptorProperty::Command ) )            rDescriptor[ DataAccessDescriptorProperty::Command ] >>= sCommand;
+        if ( rDescriptor.has( DataAccessDescriptorProperty::ColumnName ) )         rDescriptor[ DataAccessDescriptorProperty::ColumnName ] >>= sFieldName;
 
         sal_Int32 nCommandType = CommandType::TABLE;
-        OSL_VERIFY( _rDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType );
+        OSL_VERIFY( rDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType );
 
 
         implConstruct(
@@ -62,14 +66,13 @@ namespace svx
 
         if ( m_nFormatFlags & ColumnTransferFormatFlags::COLUMN_DESCRIPTOR )
         {
-            if ( _rDescriptor.has( DataAccessDescriptorProperty::Connection ) )
-                m_aDescriptor[ DataAccessDescriptorProperty::Connection ] = _rDescriptor[ DataAccessDescriptorProperty::Connection ];
-            if ( _rDescriptor.has( DataAccessDescriptorProperty::ColumnObject ) )
-                m_aDescriptor[ DataAccessDescriptorProperty::ColumnObject ] = _rDescriptor[ DataAccessDescriptorProperty::ColumnObject ];
+            if ( rDescriptor.has( DataAccessDescriptorProperty::Connection ) )
+                m_aDescriptor[ DataAccessDescriptorProperty::Connection ] = rDescriptor[ DataAccessDescriptorProperty::Connection ];
+            if ( rDescriptor.has( DataAccessDescriptorProperty::ColumnObject ) )
+                m_aDescriptor[ DataAccessDescriptorProperty::ColumnObject ] = rDescriptor[ DataAccessDescriptorProperty::ColumnObject ];
         }
     }
 
-
     OColumnTransferable::OColumnTransferable(const Reference< XPropertySet >& _rxForm,
             const OUString& _rFieldName, const Reference< XPropertySet >& _rxColumn,
             const Reference< XConnection >& _rxConnection, ColumnTransferFormatFlags _nFormats)
diff --git a/svx/source/form/tabwin.cxx b/svx/source/form/tabwin.cxx
index 8e91d42804d4..09ab384fdcdc 100644
--- a/svx/source/form/tabwin.cxx
+++ b/svx/source/form/tabwin.cxx
@@ -24,7 +24,6 @@
 
 #include <svx/strings.hrc>
 #include <svx/svxids.hrc>
-#include <svx/dbaexchange.hxx>
 #include <com/sun/star/sdb/CommandType.hpp>
 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
@@ -59,8 +58,6 @@
 const long STD_WIN_SIZE_X = 120;
 const long STD_WIN_SIZE_Y = 150;
 
-const long LISTBOX_BORDER = 2;
-
 using namespace ::com::sun::star::sdbc;
 using namespace ::com::sun::star::sdb;
 using namespace ::com::sun::star::uno;
@@ -74,8 +71,6 @@ using namespace ::svxform;
 using namespace ::svx;
 using namespace ::dbtools;
 
-namespace {
-
 struct ColumnInfo
 {
     OUString const sColumnName;
@@ -85,9 +80,7 @@ struct ColumnInfo
     }
 };
 
-}
-
-static void lcl_addToList( SvTreeListBox& _rListBox, const uno::Reference< container::XNameAccess>& i_xColumns )
+void FmFieldWin::addToList(const uno::Reference< container::XNameAccess>& i_xColumns )
 {
     const uno::Sequence< OUString > aEntries = i_xColumns->getElementNames();
     for ( const OUString& rEntry : aEntries )
@@ -96,124 +89,77 @@ static void lcl_addToList( SvTreeListBox& _rListBox, const uno::Reference< conta
         OUString sLabel;
         if ( xColumn->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) )
             xColumn->getPropertyValue(FM_PROP_LABEL) >>= sLabel;
+        m_aListBoxData.emplace_back(new ColumnInfo(rEntry));
+        OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_aListBoxData.back().get())));
         if ( !sLabel.isEmpty() )
-            _rListBox.InsertEntry( sLabel, nullptr, false, TREELIST_APPEND, new ColumnInfo(rEntry) );
+            m_xListBox->append(sId, sLabel);
         else
-            _rListBox.InsertEntry( rEntry, nullptr, false, TREELIST_APPEND, new ColumnInfo(rEntry) );
+            m_xListBox->append(sId, rEntry);
     }
 }
 
-FmFieldWinListBox::FmFieldWinListBox( FmFieldWin* pParent )
-    :SvTreeListBox( pParent, WB_HASBUTTONS|WB_BORDER )
-    ,pTabWin( pParent )
-{
-    SetHelpId( HID_FIELD_SEL );
-
-    SetHighlightRange( );
-}
-
-FmFieldWinListBox::~FmFieldWinListBox()
-{
-    disposeOnce();
-}
-
-void FmFieldWinListBox::dispose()
-{
-    pTabWin.clear();
-    SvTreeListBox::dispose();
-}
-
-
-sal_Int8 FmFieldWinListBox::AcceptDrop( const AcceptDropEvent& /*rEvt*/ )
-{
-    return DND_ACTION_NONE;
-}
-
-
-sal_Int8 FmFieldWinListBox::ExecuteDrop( const ExecuteDropEvent& /*rEvt*/ )
+IMPL_LINK_NOARG(FmFieldWin, DragBeginHdl, weld::TreeView&, bool)
 {
-    return DND_ACTION_NONE;
-}
-
-
-bool FmFieldWinListBox::DoubleClickHdl()
-{
-    if ( pTabWin->createSelectionControls() )
-        return true;
-
-    return SvTreeListBox::DoubleClickHdl();
-}
-
-
-void FmFieldWinListBox::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ )
-{
-    SvTreeListEntry* pSelected = FirstSelected();
+    ColumnInfo* pSelected = reinterpret_cast<ColumnInfo*>(m_xListBox->get_selected_id().toInt64());
     if (!pSelected)
+    {
         // no drag without a field
-        return;
+        return true;
+    }
 
     svx::ODataAccessDescriptor aDescriptor;
-    aDescriptor[ DataAccessDescriptorProperty::DataSource ] <<= pTabWin->GetDatabaseName();
-    aDescriptor[ DataAccessDescriptorProperty::Connection ] <<= pTabWin->GetConnection().getTyped();
-    aDescriptor[ DataAccessDescriptorProperty::Command ]    <<= pTabWin->GetObjectName();
-    aDescriptor[ DataAccessDescriptorProperty::CommandType ]<<= pTabWin->GetObjectType();
-    ColumnInfo* pInfo = static_cast<ColumnInfo*>(pSelected->GetUserData());
-    aDescriptor[ DataAccessDescriptorProperty::ColumnName ] <<= pInfo->sColumnName;
-
-    rtl::Reference<OColumnTransferable> pTransferColumn = new OColumnTransferable(
-        aDescriptor, ColumnTransferFormatFlags::FIELD_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE | ColumnTransferFormatFlags::COLUMN_DESCRIPTOR
-    );
-    EndSelection();
-    pTransferColumn->StartDrag( this, DND_ACTION_COPY );
+    aDescriptor[ DataAccessDescriptorProperty::DataSource ] <<= GetDatabaseName();
+    aDescriptor[ DataAccessDescriptorProperty::Connection ] <<= GetConnection().getTyped();
+    aDescriptor[ DataAccessDescriptorProperty::Command ]    <<= GetObjectName();
+    aDescriptor[ DataAccessDescriptorProperty::CommandType ]<<= GetObjectType();
+    aDescriptor[ DataAccessDescriptorProperty::ColumnName ] <<= pSelected->sColumnName;
+
+    m_xHelper->setDescriptor(aDescriptor);
+
+    return false;
 }
 
-FmFieldWin::FmFieldWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr, vcl::Window* _pParent)
-            :SfxFloatingWindow(_pBindings, _pMgr, _pParent, WinBits(WB_STDMODELESS|WB_SIZEABLE))
-            ,SfxControllerItem(SID_FM_FIELDS_CONTROL, *_pBindings)
-            ,::comphelper::OPropertyChangeListener(m_aMutex)
-            ,m_nObjectType(0)
+FmFieldWin::FmFieldWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr, weld::Window* _pParent)
+    : SfxModelessDialogController(_pBindings, _pMgr, _pParent, "svx/ui/formfielddialog.ui", "FormFieldDialog")
+    , SfxControllerItem(SID_FM_FIELDS_CONTROL, *_pBindings)
+    , comphelper::OPropertyChangeListener(m_aMutex)
+    , m_xListBox(m_xBuilder->weld_tree_view("treeview"))
+    , m_nObjectType(0)
 {
-    SetHelpId( HID_FIELD_SEL_WIN );
+    m_xDialog->set_help_id(HID_FIELD_SEL_WIN);
+    m_xListBox->set_help_id(HID_FIELD_SEL);
+
+    m_xListBox->connect_row_activated(LINK(this, FmFieldWin, RowActivatedHdl));
+    m_xHelper.set(new OColumnTransferable(
+        ColumnTransferFormatFlags::FIELD_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE | ColumnTransferFormatFlags::COLUMN_DESCRIPTOR
+    ));
+    rtl::Reference<TransferDataContainer> xHelper(m_xHelper.get());
+    m_xListBox->enable_drag_source(xHelper, DND_ACTION_COPY);
+    m_xListBox->connect_drag_begin(LINK(this, FmFieldWin, DragBeginHdl));
 
-    SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetFaceColor()) );
-    pListBox = VclPtr<FmFieldWinListBox>::Create( this );
-    pListBox->Show();
     UpdateContent(nullptr);
-    SetSizePixel(Size(STD_WIN_SIZE_X,STD_WIN_SIZE_Y));
+    m_xDialog->set_size_request(STD_WIN_SIZE_X, STD_WIN_SIZE_Y);
 }
 
-
 FmFieldWin::~FmFieldWin()
 {
-    disposeOnce();
-}
-
-void FmFieldWin::dispose()
-{
-    if (m_pChangeListener.is())
+    if (m_xChangeListener.is())
     {
-        m_pChangeListener->dispose();
-        m_pChangeListener.clear();
+        m_xChangeListener->dispose();
+        m_xChangeListener.clear();
     }
-    pListBox.disposeAndClear();
     ::SfxControllerItem::dispose();
-    SfxFloatingWindow::dispose();
 }
 
-
-void FmFieldWin::GetFocus()
+IMPL_LINK_NOARG(FmFieldWin, RowActivatedHdl, weld::TreeView&, bool)
 {
-    if ( pListBox )
-        pListBox->GrabFocus();
-    else
-        SfxFloatingWindow::GetFocus();
+    return createSelectionControls();
 }
 
-
-bool FmFieldWin::createSelectionControls( )
+bool FmFieldWin::createSelectionControls()
 {
-    SvTreeListEntry* pSelected = pListBox->FirstSelected();
-    if ( pSelected )
+    ColumnInfo* pSelected = reinterpret_cast<ColumnInfo*>(m_xListBox->get_selected_id().toInt64());
+    if (pSelected)
     {
         // build a descriptor for the currently selected field
         ODataAccessDescriptor aDescr;
@@ -223,8 +169,7 @@ bool FmFieldWin::createSelectionControls( )
 
         aDescr[ DataAccessDescriptorProperty::Command ]     <<= GetObjectName();
         aDescr[ DataAccessDescriptorProperty::CommandType ] <<= GetObjectType();
-        ColumnInfo* pInfo = static_cast<ColumnInfo*>(pSelected->GetUserData());
-        aDescr[ DataAccessDescriptorProperty::ColumnName ]  <<= pInfo->sColumnName;//OUString( pListBox->GetEntryText( pSelected) );
+        aDescr[ DataAccessDescriptorProperty::ColumnName ]  <<= pSelected->sColumnName;
 
         // transfer this to the SFX world
         SfxUnoAnyItem aDescriptorItem( SID_FM_DATACCESS_DESCRIPTOR, makeAny( aDescr.createPropertyValueSequence() ) );
@@ -240,30 +185,12 @@ bool FmFieldWin::createSelectionControls( )
     return nullptr != pSelected;
 }
 
-
-bool FmFieldWin::PreNotify( NotifyEvent& _rNEvt )
-{
-    if ( MouseNotifyEvent::KEYINPUT == _rNEvt.GetType() )
-    {
-        const vcl::KeyCode& rKeyCode = _rNEvt.GetKeyEvent()->GetKeyCode();
-        if ( ( 0 == rKeyCode.GetModifier() ) && ( KEY_RETURN == rKeyCode.GetCode() ) )
-        {
-            if ( createSelectionControls() )
-                return true;
-        }
-    }
-
-    return SfxFloatingWindow::PreNotify( _rNEvt );
-}
-
-
 void FmFieldWin::_propertyChanged(const css::beans::PropertyChangeEvent& evt)
 {
     css::uno::Reference< css::form::XForm >  xForm(evt.Source, css::uno::UNO_QUERY);
     UpdateContent(xForm);
 }
 
-
 void FmFieldWin::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
 {
     if (!pState  || SID_FM_FIELDS_CONTROL != nSID)
@@ -278,12 +205,12 @@ void FmFieldWin::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoo
         UpdateContent(nullptr);
 }
 
-
 void FmFieldWin::UpdateContent(FmFormShell const * pShell)
 {
-    pListBox->Clear();
+    m_xListBox->clear();
+    m_aListBoxData.clear();
     OUString aTitle(SvxResId(RID_STR_FIELDSELECTION));
-    SetText( aTitle );
+    m_xDialog->set_title(aTitle);
 
     if (!pShell || !pShell->GetImpl())
         return;
@@ -293,15 +220,15 @@ void FmFieldWin::UpdateContent(FmFormShell const * pShell)
         UpdateContent( xForm );
 }
 
-
 void FmFieldWin::UpdateContent(const css::uno::Reference< css::form::XForm > & xForm)
 {
     try
     {
         // delete ListBox
-        pListBox->Clear();
+        m_xListBox->clear();
+        m_aListBoxData.clear();
         OUString aTitle(SvxResId(RID_STR_FIELDSELECTION));
-        SetText(aTitle);
+        m_xDialog->set_title(aTitle);
 
         if (!xForm.is())
             return;
@@ -328,7 +255,7 @@ void FmFieldWin::UpdateContent(const css::uno::Reference< css::form::XForm > & x
             Reference< XComponent > xKeepFieldsAlive;
             Reference< XNameAccess > xColumns = getFieldsByCommandDescriptor( m_aConnection, m_nObjectType, m_aObjectName,xKeepFieldsAlive );
             if ( xColumns.is() )
-                lcl_addToList(*pListBox,xColumns);
+                addToList(xColumns);
         }
 
         // set prefix
@@ -348,19 +275,19 @@ void FmFieldWin::UpdateContent(const css::uno::Reference< css::form::XForm > & x
         }
 
         // listen for changes at ControlSource in PropertySet
-        if (m_pChangeListener.is())
+        if (m_xChangeListener.is())
         {
-            m_pChangeListener->dispose();
-            m_pChangeListener.clear();
+            m_xChangeListener->dispose();
+            m_xChangeListener.clear();
         }
-        m_pChangeListener = new ::comphelper::OPropertyChangeMultiplexer(this, xSet);
-        m_pChangeListener->addProperty(FM_PROP_DATASOURCE);
-        m_pChangeListener->addProperty(FM_PROP_COMMAND);
-        m_pChangeListener->addProperty(FM_PROP_COMMANDTYPE);
+        m_xChangeListener = new ::comphelper::OPropertyChangeMultiplexer(this, xSet);
+        m_xChangeListener->addProperty(FM_PROP_DATASOURCE);
+        m_xChangeListener->addProperty(FM_PROP_COMMAND);
+        m_xChangeListener->addProperty(FM_PROP_COMMANDTYPE);
 
         // set title
         aTitle += " " + aPrefix + " " + m_aObjectName;
-        SetText( aTitle );
+        m_xDialog->set_title(aTitle);
     }
     catch( const Exception& )
     {
@@ -368,41 +295,20 @@ void FmFieldWin::UpdateContent(const css::uno::Reference< css::form::XForm > & x
     }
 }
 
-
-void FmFieldWin::Resize()
-{
-    SfxFloatingWindow::Resize();
-
-    Size aOutputSize( GetOutputSizePixel() );
-
-
-    // adapt size of css::form::ListBox
-    Point aLBPos( LISTBOX_BORDER, LISTBOX_BORDER );
-    Size aLBSize( aOutputSize );
-    aLBSize.AdjustWidth( -(2*LISTBOX_BORDER) );
-    aLBSize.AdjustHeight( -(2*LISTBOX_BORDER) );
-
-    pListBox->SetPosSizePixel( aLBPos, aLBSize );
-}
-
-
 void FmFieldWin::FillInfo( SfxChildWinInfo& rInfo ) const
 {
     rInfo.bVisible = false;
 }
 
-
-SFX_IMPL_FLOATINGWINDOW(FmFieldWinMgr, SID_FM_ADD_FIELD)
-
+SFX_IMPL_MODELESSDIALOGCONTOLLER(FmFieldWinMgr, SID_FM_ADD_FIELD)
 
 FmFieldWinMgr::FmFieldWinMgr(vcl::Window* _pParent, sal_uInt16 _nId,
                SfxBindings* _pBindings, SfxChildWinInfo const * _pInfo)
               :SfxChildWindow(_pParent, _nId)
 {
-    SetWindow( VclPtr<FmFieldWin>::Create(_pBindings, this, _pParent) );
+    SetController(std::make_shared<FmFieldWin>(_pBindings, this, _pParent->GetFrameWeld()));
     SetHideNotDelete(true);
-    static_cast<SfxFloatingWindow*>(GetWindow())->Initialize( _pInfo );
+    static_cast<FmFieldWin*>(GetController().get())->Initialize(_pInfo);
 }
 
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/tabwin.hxx b/svx/source/inc/tabwin.hxx
index 9645ff5a1343..17bdbe6da534 100644
--- a/svx/source/inc/tabwin.hxx
+++ b/svx/source/inc/tabwin.hxx
@@ -23,6 +23,7 @@
 #include <sfx2/basedlgs.hxx>
 #include <sfx2/childwin.hxx>
 #include <sfx2/ctrlitem.hxx>
+#include <svx/dbaexchange.hxx>
 #include <com/sun/star/form/XForm.hpp>
 
 #include <comphelper/propmultiplex.hxx>
@@ -30,61 +31,34 @@
 #include <connectivity/dbtools.hxx>
 
 
-class FmFieldWin;
-class FmFieldWinListBox
-                    :public SvTreeListBox
-{
-    VclPtr<FmFieldWin> pTabWin;
-
-protected:
-//  virtual void Command( const CommandEvent& rEvt );
-
-public:
-    FmFieldWinListBox( FmFieldWin* pParent );
-    virtual ~FmFieldWinListBox() override;
-    virtual void dispose() override;
-
-    sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
-    sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
-
-protected:
-    // DragSourceHelper
-    virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
-
-    // SvTreeListBox
-    virtual bool DoubleClickHdl() override;
-
-    using SvTreeListBox::ExecuteDrop;
-};
-
-
 class FmFormShell;
+struct ColumnInfo;
 
-
-class FmFieldWin :public SfxFloatingWindow
-                    ,public SfxControllerItem
-                    ,public ::comphelper::OPropertyChangeListener
+class FmFieldWin : public SfxModelessDialogController
+                 , public SfxControllerItem
+                 , public ::comphelper::OPropertyChangeListener
 {
     ::osl::Mutex        m_aMutex;
-    VclPtr<FmFieldWinListBox> pListBox;
+    std::unique_ptr<weld::TreeView> m_xListBox;
+    std::vector<std::unique_ptr<ColumnInfo>> m_aListBoxData;
     ::dbtools::SharedConnection
                        m_aConnection;
     OUString    m_aDatabaseName,
                        m_aObjectName;
     sal_Int32          m_nObjectType;
 
-    rtl::Reference<::comphelper::OPropertyChangeMultiplexer>  m_pChangeListener;
+    rtl::Reference<comphelper::OPropertyChangeMultiplexer>  m_xChangeListener;
+    rtl::Reference<svx::OColumnTransferable> m_xHelper;
 
+    void addToList(const css::uno::Reference<css::container::XNameAccess>& i_xColumns);
+
+    DECL_LINK(RowActivatedHdl, weld::TreeView&, bool);
+    DECL_LINK(DragBeginHdl, weld::TreeView&, bool);
 public:
-    FmFieldWin(SfxBindings *pBindings,
-               SfxChildWindow *pMgr, vcl::Window* pParent);
+    FmFieldWin(SfxBindings *pBindings, SfxChildWindow *pMgr, weld::Window* pParent);
 
     virtual ~FmFieldWin() override;
-    virtual void dispose() override;
-    virtual void Resize() override;
-    using SfxFloatingWindow::Close;
-    virtual void GetFocus() override;
-    virtual bool PreNotify( NotifyEvent& _rNEvt ) override;
+
     virtual void StateChanged(sal_uInt16 nSID, SfxItemState eState,
                               const SfxPoolItem* pState) override;
 
@@ -92,10 +66,10 @@ public:
     void UpdateContent(const css::uno::Reference< css::form::XForm > &);
     void FillInfo( SfxChildWinInfo& rInfo ) const override;
 
-    const OUString&      GetDatabaseName() const { return m_aDatabaseName; }
+    const OUString& GetDatabaseName() const { return m_aDatabaseName; }
     const ::dbtools::SharedConnection& GetConnection() const { return m_aConnection; }
-    const OUString&      GetObjectName() const { return m_aObjectName; }
-    sal_Int32                   GetObjectType() const { return m_nObjectType; }
+    const OUString& GetObjectName() const { return m_aObjectName; }
+    sal_Int32 GetObjectType() const { return m_nObjectType; }
 
     bool    createSelectionControls( );
 
@@ -105,7 +79,6 @@ protected:
 
 protected:
     using SfxControllerItem::GetBindings;
-    using SfxFloatingWindow::StateChanged;
 };
 
 
diff --git a/svx/uiconfig/ui/formfielddialog.ui b/svx/uiconfig/ui/formfielddialog.ui
new file mode 100644
index 000000000000..3a3d56441852
--- /dev/null
+++ b/svx/uiconfig/ui/formfielddialog.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+  <requires lib="gtk+" version="3.18"/>
+  <object class="GtkTreeStore" id="liststore1">
+    <columns>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkDialog" id="FormFieldDialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">6</property>
+    <property name="default_width">0</property>
+    <property name="default_height">0</property>
+    <property name="type_hint">dialog</property>
+    <child>
+      <placeholder/>
+    </child>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="no_show_all">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="container">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <child>
+              <object class="GtkScrolledWindow">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="shadow_type">in</property>
+                <child>
+                  <object class="GtkTreeView" id="treeview">
+                    <property name="visible">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">liststore1</property>
+                    <property name="headers_visible">False</property>
+                    <property name="reorderable">True</property>
+                    <property name="search_column">0</property>
+                    <property name="show_expanders">False</property>
+                    <child internal-child="selection">
+                      <object class="GtkTreeSelection" id="Macro Library List-selection2"/>
+                    </child>
+                    <child>
+                      <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+                        <property name="resizable">True</property>
+                        <child>
+                          <object class="GtkCellRendererText" id="cellrenderer1"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
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);


More information about the Libreoffice-commits mailing list