Resolves: tdf#147203 allow dnd between autotext categories

restores various methods removed as unused since original
regression at

commit 4830a1bae89a8ed60696503e315ffd42c70dff74
Date:   Thu May 30 16:12:23 2019 +0100

    weld SwGlossaryDlg

Change-Id: I5c6186b9f45f3c0957926de2861eb6bc76dda73d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143363
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/sw/inc/shellio.hxx b/sw/inc/shellio.hxx
index e476b53..0fe3985 100644
--- a/sw/inc/shellio.hxx
+++ b/sw/inc/shellio.hxx
@@ -327,6 +327,8 @@ public:

    bool   Delete( sal_uInt16 );
    void   Rename( sal_uInt16, const OUString*, const OUString* );
    ErrCode const & CopyBlock( SwTextBlocks const & rSource, OUString& rSrcShort,
                                    const OUString& rLong );

    bool   BeginGetDoc( sal_uInt16 );   // Read text modules.
    void   EndGetDoc();                     // Release text modules.
diff --git a/sw/source/core/inc/SwXMLTextBlocks.hxx b/sw/source/core/inc/SwXMLTextBlocks.hxx
index bd6458e..9132b59 100644
--- a/sw/source/core/inc/SwXMLTextBlocks.hxx
+++ b/sw/source/core/inc/SwXMLTextBlocks.hxx
@@ -61,6 +61,7 @@ public:
    virtual ~SwXMLTextBlocks() override;
    virtual ErrCode Delete( sal_uInt16 ) override;
    virtual ErrCode Rename( sal_uInt16, const OUString& ) override;
    virtual ErrCode CopyBlock( SwImpBlocks& rImp, OUString& rShort, const OUString& rLong) override;
    virtual void  ClearDoc() override;
    virtual ErrCode GetDoc( sal_uInt16 ) override;
    virtual ErrCode BeginPutDoc( const OUString&, const OUString& ) override;
diff --git a/sw/source/core/inc/swblocks.hxx b/sw/source/core/inc/swblocks.hxx
index d822acb..7bd877a 100644
--- a/sw/source/core/inc/swblocks.hxx
+++ b/sw/source/core/inc/swblocks.hxx
@@ -106,6 +106,7 @@ public:

    virtual ErrCode Delete( sal_uInt16 ) = 0;
    virtual ErrCode Rename( sal_uInt16, const OUString& ) = 0;
    virtual ErrCode CopyBlock( SwImpBlocks& rImp, OUString& rShort, const OUString& rLong) = 0;
    virtual ErrCode GetDoc( sal_uInt16 ) = 0;
    virtual ErrCode BeginPutDoc( const OUString&, const OUString& ) = 0;
    virtual ErrCode PutDoc() = 0;
diff --git a/sw/source/core/swg/SwXMLTextBlocks.cxx b/sw/source/core/swg/SwXMLTextBlocks.cxx
index f48d007..3bb108c 100644
--- a/sw/source/core/swg/SwXMLTextBlocks.cxx
+++ b/sw/source/core/swg/SwXMLTextBlocks.cxx
@@ -232,6 +232,59 @@ ErrCode SwXMLTextBlocks::Rename( sal_uInt16 nIdx, const OUString& rNewShort )
    return ERRCODE_NONE;
}

ErrCode SwXMLTextBlocks::CopyBlock( SwImpBlocks& rDestImp, OUString& rShort,
                                                    const OUString& rLong)
{
    ErrCode nError = ERRCODE_NONE;
    OpenFile();
    rDestImp.OpenFile(false);
    const OUString aGroup( rShort );
    bool bTextOnly = IsOnlyTextBlock ( rShort ) ;//pImp->pBlkRoot->IsStream( aGroup );
    sal_uInt16 nIndex = GetIndex ( rShort );
    OUString sPackageName( GetPackageName (nIndex) );
    OUString sDestShortName( sPackageName );
    sal_uInt16 nIdx = 0;

    OSL_ENSURE( m_xBlkRoot.is(), "No storage set" );
    if(!m_xBlkRoot.is())
        return ERR_SWG_WRITE_ERROR;

    uno::Reference < container::XNameAccess > xAccess(static_cast<SwXMLTextBlocks&>(rDestImp).m_xBlkRoot);
    while ( xAccess->hasByName( sDestShortName ) )
    {
        ++nIdx;
        // If someone is that crazy ...
        if(USHRT_MAX == nIdx)
        {
            CloseFile();
            rDestImp.CloseFile();
            return ERR_SWG_WRITE_ERROR;
        }
        sDestShortName = sPackageName + OUString::number( nIdx );
    }

    try
    {
        uno::Reference < embed::XStorage > rSourceRoot = m_xBlkRoot->openStorageElement( aGroup, embed::ElementModes::READ );
        uno::Reference < embed::XStorage > rDestRoot = static_cast<SwXMLTextBlocks&>(rDestImp).m_xBlkRoot->openStorageElement( sDestShortName, embed::ElementModes::READWRITE );
        rSourceRoot->copyToStorage( rDestRoot );
    }
    catch (const uno::Exception&)
    {
        nError = ERR_SWG_WRITE_ERROR;
    }

    if(!nError)
    {
        rShort = sDestShortName;
        static_cast<SwXMLTextBlocks&>(rDestImp).AddName( rShort, rLong, bTextOnly );
        static_cast<SwXMLTextBlocks&>(rDestImp).MakeBlockList();
    }
    CloseFile();
    rDestImp.CloseFile();
    return nError;
}

ErrCode SwXMLTextBlocks::StartPutBlock( const OUString& rShort, const OUString& rPackageName )
{
    OSL_ENSURE( m_xBlkRoot.is(), "No storage set" );
diff --git a/sw/source/core/swg/swblocks.cxx b/sw/source/core/swg/swblocks.cxx
index d9ccbe4..fb47693 100644
--- a/sw/source/core/swg/swblocks.cxx
+++ b/sw/source/core/swg/swblocks.cxx
@@ -346,6 +346,16 @@ void SwTextBlocks::Rename( sal_uInt16 n, const OUString* s, const OUString* l )
    m_pImp->Touch();
}

ErrCode const & SwTextBlocks::CopyBlock( SwTextBlocks const & rSource, OUString& rSrcShort,
                                const OUString& rLong )
{
    if (m_pImp->m_bInPutMuchBlocks)
        m_nErr = ERR_SWG_INTERNAL_ERROR;
    else
        m_nErr = m_pImp->CopyBlock(*rSource.m_pImp, rSrcShort, rLong);
    return m_nErr;
}

bool SwTextBlocks::BeginGetDoc( sal_uInt16 n )
{
    if( m_pImp && !m_pImp->m_bInPutMuchBlocks )
diff --git a/sw/source/ui/misc/glossary.cxx b/sw/source/ui/misc/glossary.cxx
index 2f3347d..ae3ce4f 100644
--- a/sw/source/ui/misc/glossary.cxx
+++ b/sw/source/ui/misc/glossary.cxx
@@ -22,6 +22,7 @@
#include <o3tl/any.hxx>
#include <vcl/event.hxx>
#include <vcl/svapp.hxx>
#include <vcl/transfer.hxx>
#include <vcl/weld.hxx>
#include <svl/stritem.hxx>
#include <svl/macitem.hxx>
@@ -176,6 +177,117 @@ IMPL_LINK(SwGlossaryDlg, TextFilterHdl, OUString&, rTest, bool)
    return true;
}

class SwGlossaryDropTarget : public DropTargetHelper
{
private:
    weld::TreeView& m_rTreeView;
    SwGlossaryHdl* m_pGlosHdl;

    virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
    {
        weld::TreeView* pSource = m_rTreeView.get_drag_source();
        if (!pSource || pSource != &m_rTreeView)
            return DND_ACTION_NONE;

        std::unique_ptr<weld::TreeIter> xSelected(pSource->make_iterator());
        bool bSelected = pSource->get_selected(xSelected.get());
        if (!bSelected)
            return DND_ACTION_NONE;

        while (pSource->get_iter_depth(*xSelected))
            (void)pSource->iter_parent(*xSelected);

        GroupUserData* pSrcRootData = weld::fromId<GroupUserData*>(pSource->get_id(*xSelected));
        GroupUserData* pDestRootData = nullptr;

        std::unique_ptr<weld::TreeIter> xDestEntry(m_rTreeView.make_iterator());
        bool bEntry = m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xDestEntry.get(), true);
        if (bEntry)
        {
            while (m_rTreeView.get_iter_depth(*xDestEntry))
                (void)m_rTreeView.iter_parent(*xDestEntry);
            pDestRootData = weld::fromId<GroupUserData*>(m_rTreeView.get_id(*xDestEntry));
        }
        if (pDestRootData == pSrcRootData)
            return DND_ACTION_NONE;
        sal_uInt8 nRet = DND_ACTION_COPY;
        const bool bCheckForMove = rEvt.mnAction & DND_ACTION_MOVE;
        if (bCheckForMove && !pSrcRootData->bReadonly)
            nRet |= DND_ACTION_MOVE;
        return nRet;
    }

    virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
    {
        weld::TreeView* pSource = m_rTreeView.get_drag_source();
        if (!pSource)
            return DND_ACTION_NONE;

        std::unique_ptr<weld::TreeIter> xDestEntry(m_rTreeView.make_iterator());
        bool bEntry = m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xDestEntry.get(), true);
        if (!bEntry)
            return DND_ACTION_NONE;

        std::unique_ptr<weld::TreeIter> xSelected(pSource->make_iterator());
        bool bSelected = pSource->get_selected(xSelected.get());
        if (!bSelected)
            return DND_ACTION_NONE;

        std::unique_ptr<weld::TreeIter> xSrcParent(pSource->make_iterator(xSelected.get()));
        while (pSource->get_iter_depth(*xSrcParent))
            (void)pSource->iter_parent(*xSrcParent);

        std::unique_ptr<weld::TreeIter> xDestParent(pSource->make_iterator(xDestEntry.get()));
        while (pSource->get_iter_depth(*xDestParent))
            (void)pSource->iter_parent(*xDestParent);

        GroupUserData* pSrcParent = weld::fromId<GroupUserData*>(pSource->get_id(*xSrcParent));
        GroupUserData* pDestParent = weld::fromId<GroupUserData*>(m_rTreeView.get_id(*xDestParent));

        if (pDestParent != pSrcParent)
        {
            weld::WaitObject aBusy(&m_rTreeView);

            OUString sSourceGroup = pSrcParent->sGroupName
                + OUStringChar(GLOS_DELIM)
                + OUString::number(pSrcParent->nPathIdx);

            m_pGlosHdl->SetCurGroup(sSourceGroup);
            OUString sTitle(pSource->get_text(*xSelected));
            OUString sShortName(pSource->get_id(*xSelected));

            OUString sDestName = pDestParent->sGroupName
                + OUStringChar(GLOS_DELIM)
                + OUString::number(pDestParent->nPathIdx);

            bool bIsMove = rEvt.mnAction & DND_ACTION_MOVE;

            const bool bRet = m_pGlosHdl->CopyOrMove(sSourceGroup, sShortName,
                            sDestName, sTitle, bIsMove);

            if(bRet)
            {
                m_rTreeView.insert(xDestParent.get(), -1, &sTitle, &sShortName,
                                       nullptr, nullptr, false, nullptr);
                if (bIsMove)
                {
                    pSource->remove(*xSelected);
                }
            }
        }

        return DND_ACTION_NONE;
    }

public:
    SwGlossaryDropTarget(weld::TreeView& rTreeView, SwGlossaryHdl* pGlosHdl)
        : DropTargetHelper(rTreeView.get_drop_target())
        , m_rTreeView(rTreeView)
        , m_pGlosHdl(pGlosHdl)
    {
    }
};

SwGlossaryDlg::SwGlossaryDlg(SfxViewFrame const * pViewFrame,
                             SwGlossaryHdl * pGlosHdl, SwWrtShell *pWrtShell)
    : SfxDialogController(pViewFrame->GetFrameWeld(), "modules/swriter/ui/autotext.ui", "AutoTextDialog")
@@ -221,6 +333,11 @@ SwGlossaryDlg::SwGlossaryDlg(SfxViewFrame const * pViewFrame,
    m_xCategoryBox->connect_row_activated(LINK(this, SwGlossaryDlg, NameDoubleClick));
    m_xCategoryBox->connect_changed(LINK(this, SwGlossaryDlg, GrpSelect));
    m_xCategoryBox->connect_key_press(LINK(this, SwGlossaryDlg, KeyInputHdl));

    m_xDropTarget.reset(new SwGlossaryDropTarget(*m_xCategoryBox, pGlosHdl));
    rtl::Reference<TransferDataContainer> xHelper(new TransferDataContainer);
    m_xCategoryBox->enable_drag_source(xHelper, DND_ACTION_COPYMOVE);

    m_xBibBtn->connect_clicked(LINK(this,SwGlossaryDlg,BibHdl));

    m_xInsertBtn->connect_clicked(LINK(this,SwGlossaryDlg,InsertHdl));
diff --git a/sw/source/uibase/dochdl/gloshdl.cxx b/sw/source/uibase/dochdl/gloshdl.cxx
index 9f2e070..4820584 100644
--- a/sw/source/uibase/dochdl/gloshdl.cxx
+++ b/sw/source/uibase/dochdl/gloshdl.cxx
@@ -196,6 +196,28 @@ void SwGlossaryHdl::RenameGroup(const OUString& rOld, OUString& rNew, const OUSt
    }
}

bool SwGlossaryHdl::CopyOrMove(const OUString& rSourceGroupName, OUString& rSourceShortName,
                               const OUString& rDestGroupName, const OUString& rLongName, bool bMove)
{
    std::unique_ptr<SwTextBlocks> pSourceGroup = m_rStatGlossaries.GetGroupDoc(rSourceGroupName);
    std::unique_ptr<SwTextBlocks> pDestGroup = m_rStatGlossaries.GetGroupDoc(rDestGroupName);
    if (pDestGroup->IsReadOnly() || (bMove && pSourceGroup->IsReadOnly()) )
    {
        return false;
    }

    //The index must be determined here because rSourceShortName maybe changed in CopyBlock
    sal_uInt16 nDeleteIdx = pSourceGroup->GetIndex( rSourceShortName );
    OSL_ENSURE(USHRT_MAX != nDeleteIdx, "entry not found");
    ErrCode nRet = pSourceGroup->CopyBlock( *pDestGroup, rSourceShortName, rLongName );
    if(!nRet && bMove)
    {
        // the index must be existing
        nRet = pSourceGroup->Delete( nDeleteIdx ) ? ERRCODE_NONE : ErrCode(1);
    }
    return !nRet;
}

// delete an autotext-file-group
bool SwGlossaryHdl::DelGroup(const OUString &rGrpName)
{
diff --git a/sw/source/uibase/inc/gloshdl.hxx b/sw/source/uibase/inc/gloshdl.hxx
index 812609f..530d0b6 100644
--- a/sw/source/uibase/inc/gloshdl.hxx
+++ b/sw/source/uibase/inc/gloshdl.hxx
@@ -62,6 +62,8 @@ public:

    bool    Rename( const OUString& rOldShortName, const OUString& rNewShortName,
                        const OUString& rNewName);
    bool    CopyOrMove( const OUString& rSourceGroupName, OUString& rSourceShortName,
                        const OUString& rDestGroupName, const OUString& rLongName, bool bMove );
    bool    HasShortName(const OUString &rShortName) const;
    // when NewGlossary is called from Basic then the previously set group should
    // be newly created if applicable.
diff --git a/sw/source/uibase/inc/glossary.hxx b/sw/source/uibase/inc/glossary.hxx
index ada0797..d0a99a86a 100644
--- a/sw/source/uibase/inc/glossary.hxx
+++ b/sw/source/uibase/inc/glossary.hxx
@@ -39,6 +39,8 @@ class SwOneExampleFrame;

const short RET_EDIT = 100;

class SwGlossaryDropTarget;

class SwGlossaryDlg final : public SfxDialogController
{
    friend class SwNewGlosNameDlg;
@@ -76,6 +78,7 @@ class SwGlossaryDlg final : public SfxDialogController
    std::unique_ptr<weld::Button> m_xPathBtn;
    std::unique_ptr<SwOneExampleFrame> m_xExampleFrame;
    std::unique_ptr<weld::CustomWeld> m_xExampleFrameWin;
    std::unique_ptr<SwGlossaryDropTarget> m_xDropTarget;

    void EnableShortName(bool bOn = true);
    void ShowPreview();
diff --git a/sw/uiconfig/swriter/ui/autotext.ui b/sw/uiconfig/swriter/ui/autotext.ui
index ce59f4b..19f3c63 100644
--- a/sw/uiconfig/swriter/ui/autotext.ui
+++ b/sw/uiconfig/swriter/ui/autotext.ui
@@ -484,7 +484,9 @@
                        <property name="model">liststore1</property>
                        <property name="headers-visible">False</property>
                        <property name="headers-clickable">False</property>
                        <property name="reorderable">True</property>
                        <property name="search-column">0</property>
                        <property name="enable-tree-lines">True</property>
                        <child internal-child="selection">
                          <object class="GtkTreeSelection" id="treeview-selection1"/>
                        </child>