weld SwChangeDBDlg

Change-Id: Ie0fc6a6346f9c777b7172a0b641a2783cf633c1d
Reviewed-on: https://gerrit.libreoffice.org/68544
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 4802713..6000bb5 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -552,6 +552,10 @@ public:
    {
        insert(pParent, -1, &rStr, &rId, &rImage, nullptr, nullptr, false, nullptr);
    }
    void append(weld::TreeIter* pParent, const OUString& rStr)
    {
        insert(pParent, -1, &rStr, nullptr, nullptr, nullptr, nullptr, false, nullptr);
    }
    void append(const OUString& rId, const OUString& rStr, VirtualDevice& rImage)
    {
        insert(nullptr, -1, &rStr, &rId, nullptr, &rImage, nullptr, false, nullptr);
diff --git a/sw/qa/uitest/writer_tests2/exchangeDatabase.py b/sw/qa/uitest/writer_tests2/exchangeDatabase.py
index 1697a16..d255bd1 100644
--- a/sw/qa/uitest/writer_tests2/exchangeDatabase.py
+++ b/sw/qa/uitest/writer_tests2/exchangeDatabase.py
@@ -42,7 +42,7 @@ class exchangeDB(UITestCase):
        xTreeEntry2 = xTreeEntry.getChild('0')                 #Available Databases
        xTreeEntry2.executeAction("SELECT", tuple())          #Click on the biblio

        xDefineBtn = xExDBDlg.getChild("define")
        xDefineBtn = xExDBDlg.getChild("ok")
        xDefineBtn.executeAction("CLICK", tuple())

        self.ui_test.execute_dialog_through_command(".uno:ChangeDatabaseField")
@@ -55,4 +55,4 @@ class exchangeDB(UITestCase):

        self.ui_test.close_doc()

# vim: set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/ui/dialog/swdlgfact.cxx b/sw/source/ui/dialog/swdlgfact.cxx
index 656a670..b60c775 100644
--- a/sw/source/ui/dialog/swdlgfact.cxx
+++ b/sw/source/ui/dialog/swdlgfact.cxx
@@ -789,8 +789,7 @@ VclPtr<AbstractSwBreakDlg> SwAbstractDialogFactory_Impl::CreateSwBreakDlg(weld::
VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwChangeDBDlg(SwView& rVw)
{
#if HAVE_FEATURE_DBCONNECTIVITY
    VclPtr<Dialog> pDlg = VclPtr<SwChangeDBDlg>::Create(rVw);
    return VclPtr<VclAbstractDialog_Impl>::Create(pDlg);
    return VclPtr<AbstractGenericDialog_Impl>::Create(std::make_unique<SwChangeDBDlg>(rVw));
#else
    (void) rVw;
    return nullptr;
diff --git a/sw/source/ui/fldui/changedb.cxx b/sw/source/ui/fldui/changedb.cxx
index 54854cd..4ddfff3 100644
--- a/sw/source/ui/fldui/changedb.cxx
+++ b/sw/source/ui/fldui/changedb.cxx
@@ -50,35 +50,35 @@ using namespace ::com::sun::star::uno;

// edit insert-field
SwChangeDBDlg::SwChangeDBDlg(SwView const & rVw)
    : SvxStandardDialog(&rVw.GetViewFrame()->GetWindow(), "ExchangeDatabasesDialog",
        "modules/swriter/ui/exchangedatabases.ui")
    : SfxDialogController(rVw.GetViewFrame()->GetWindow().GetFrameWeld(), "modules/swriter/ui/exchangedatabases.ui",
                          "ExchangeDatabasesDialog")
    , pSh(rVw.GetWrtShellPtr())
    , m_xUsedDBTLB(m_xBuilder->weld_tree_view("inuselb"))
    , m_xAvailDBTLB(new DBTreeList(m_xBuilder->weld_tree_view("availablelb")))
    , m_xAddDBPB(m_xBuilder->weld_button("browse"))
    , m_xDocDBNameFT(m_xBuilder->weld_label("dbnameft"))
    , m_xDefineBT(m_xBuilder->weld_button("ok"))
{
    get(m_pUsedDBTLB, "inuselb");
    get(m_pAvailDBTLB, "availablelb");
    get(m_pAddDBPB, "browse");
    get(m_pDocDBNameFT, "dbnameft");
    get(m_pDefineBT, "define");
    m_pAvailDBTLB->SetWrtShell(*pSh);
    int nWidth = m_xUsedDBTLB->get_approximate_digit_width() * 25;
    int nHeight = m_xUsedDBTLB->get_height_rows(8);
    m_xUsedDBTLB->set_size_request(nWidth, nHeight);
    m_xAvailDBTLB->set_size_request(nWidth, nHeight);

    m_xAvailDBTLB->SetWrtShell(*pSh);
    FillDBPopup();

    ShowDBName(pSh->GetDBData());
    m_pDefineBT->SetClickHdl(LINK(this, SwChangeDBDlg, ButtonHdl));
    m_pAddDBPB->SetClickHdl(LINK(this, SwChangeDBDlg, AddDBHdl));
    m_xDefineBT->connect_clicked(LINK(this, SwChangeDBDlg, ButtonHdl));
    m_xAddDBPB->connect_clicked(LINK(this, SwChangeDBDlg, AddDBHdl));

    m_pUsedDBTLB->SetSelectionMode(SelectionMode::Multiple);
    m_pUsedDBTLB->SetStyle(m_pUsedDBTLB->GetStyle()|WB_HASLINES|WB_CLIPCHILDREN|WB_SORT|WB_HASBUTTONS|WB_HASBUTTONSATROOT|WB_HSCROLL);
    m_pUsedDBTLB->SetSpaceBetweenEntries(0);
    m_pUsedDBTLB->SetNodeBitmaps(Image(StockImage::Yes, RID_BMP_COLLAPSE),
                                 Image(StockImage::Yes, RID_BMP_EXPAND));
    m_xUsedDBTLB->set_selection_mode(SelectionMode::Multiple);
    m_xUsedDBTLB->make_sorted();

    Link<SvTreeListBox*,void> aLink = LINK(this, SwChangeDBDlg, TreeSelectHdl);
    Link<weld::TreeView&,void> aLink = LINK(this, SwChangeDBDlg, TreeSelectHdl);

    m_pUsedDBTLB->SetSelectHdl(aLink);
    m_pUsedDBTLB->SetDeselectHdl(aLink);
    m_pAvailDBTLB->SetSelectHdl(aLink);
    m_pAvailDBTLB->SetSelectHdl(aLink);
    TreeSelectHdl(nullptr);
    m_xUsedDBTLB->connect_changed(aLink);
    m_xAvailDBTLB->connect_changed(aLink);
    TreeSelect();
}

// initialise database listboxes
@@ -87,7 +87,8 @@ void SwChangeDBDlg::FillDBPopup()
    Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
    Reference<XDatabaseContext> xDBContext = DatabaseContext::create(xContext);
    const SwDBData& rDBData = pSh->GetDBData();
    m_pAvailDBTLB->Select(rDBData.sDataSource, rDBData.sCommand, OUString());
    m_xAvailDBTLB->Select(rDBData.sDataSource, rDBData.sCommand, OUString());
    TreeSelect();

    std::vector<OUString> aAllDBNames;

@@ -104,106 +105,101 @@ void SwChangeDBDlg::FillDBPopup()
    pSh->GetAllUsedDB( aDBNameList, &aAllDBNames );

    size_t nCount = aDBNameList.size();
    m_pUsedDBTLB->Clear();
    SvTreeListEntry *pFirst = nullptr;
    SvTreeListEntry *pLast = nullptr;
    m_xUsedDBTLB->clear();
    std::unique_ptr<weld::TreeIter> xFirst;

    for(size_t k = 0; k < nCount; k++)
    {
        pLast = Insert(aDBNameList[k].getToken(0, ';'));
        if (!pFirst)
            pFirst = pLast;
        std::unique_ptr<weld::TreeIter> xLast = Insert(aDBNameList[k].getToken(0, ';'));
        if (!xFirst)
            xFirst = std::move(xLast);
    }

    if (pFirst)
    if (xFirst)
    {
        m_pUsedDBTLB->MakeVisible(pFirst);
        m_pUsedDBTLB->Select(pFirst);
        m_xUsedDBTLB->expand_row(*xFirst);
        m_xUsedDBTLB->scroll_to_row(*xFirst);
        m_xUsedDBTLB->select(*xFirst);
    }

}

SvTreeListEntry* SwChangeDBDlg::Insert(const OUString& rDBName)
std::unique_ptr<weld::TreeIter> SwChangeDBDlg::Insert(const OUString& rDBName)
{
    sal_Int32 nIdx{ 0 };
    const OUString sDBName(rDBName.getToken(0, DB_DELIM, nIdx));
    const OUString sTableName(rDBName.getToken(0, DB_DELIM, nIdx));
    sal_IntPtr nCommandType = rDBName.getToken(0, DB_DELIM, nIdx).toInt32();
    SvTreeListEntry* pParent;
    SvTreeListEntry* pChild;
    OUString sUserData = rDBName.getToken(0, DB_DELIM, nIdx);
    sal_Int32 nCommandType = sUserData.toInt32();

    sal_uLong nParent = 0;
    sal_uLong nChild = 0;
    OUString aTableImg(RID_BMP_DBTABLE);
    OUString aDBImg(RID_BMP_DB);
    OUString aQueryImg(RID_BMP_DBQUERY);
    OUString& rToInsert = nCommandType ? aQueryImg : aTableImg;

    Image aTableImg(StockImage::Yes, RID_BMP_DBTABLE);
    Image aDBImg(StockImage::Yes, RID_BMP_DB);
    Image aQueryImg(StockImage::Yes, RID_BMP_DBQUERY);
    Image& rToInsert = nCommandType ? aQueryImg : aTableImg;
    while ((pParent = m_pUsedDBTLB->GetEntry(nParent++)) != nullptr)
    std::unique_ptr<weld::TreeIter> xIter(m_xUsedDBTLB->make_iterator());
    if (m_xUsedDBTLB->get_iter_first(*xIter))
    {
        if (sDBName == m_pUsedDBTLB->GetEntryText(pParent))
        do
        {
            while ((pChild = m_pUsedDBTLB->GetEntry(pParent, nChild++)) != nullptr)
            if (sDBName == m_xUsedDBTLB->get_text(*xIter))
            {
                if (sTableName == m_pUsedDBTLB->GetEntryText(pChild))
                    return pChild;
                if (m_xUsedDBTLB->iter_children(*xIter))
                {
                    do
                    {
                        if (sTableName == m_xUsedDBTLB->get_text(*xIter))
                            return xIter;
                    } while (m_xUsedDBTLB->iter_next_sibling(*xIter));
                    m_xUsedDBTLB->iter_parent(*xIter);
                }
                m_xUsedDBTLB->insert(xIter.get(), -1, &sTableName, &sUserData, nullptr, nullptr,
                                     &rToInsert, false, xIter.get());
                return xIter;
            }
            SvTreeListEntry* pRet = m_pUsedDBTLB->InsertEntry(sTableName, rToInsert, rToInsert, pParent);
            pRet->SetUserData(reinterpret_cast<void*>(nCommandType));
            return pRet;
        }
        } while (m_xUsedDBTLB->iter_next_sibling(*xIter));
    }
    pParent = m_pUsedDBTLB->InsertEntry(sDBName, aDBImg, aDBImg);

    SvTreeListEntry* pRet = m_pUsedDBTLB->InsertEntry(sTableName, rToInsert, rToInsert, pParent);
    pRet->SetUserData(reinterpret_cast<void*>(nCommandType));
    return pRet;
    m_xUsedDBTLB->insert(nullptr, -1, &sDBName, nullptr, nullptr, nullptr,
                         &aDBImg, false, xIter.get());
    m_xUsedDBTLB->insert(xIter.get(), -1, &sTableName, &sUserData, nullptr, nullptr,
                         &rToInsert, false, xIter.get());
    return xIter;
}

// destroy dialog
SwChangeDBDlg::~SwChangeDBDlg()
{
    disposeOnce();
}

void SwChangeDBDlg::dispose()
short SwChangeDBDlg::run()
{
    m_pUsedDBTLB.clear();
    m_pAvailDBTLB.clear();
    m_pAddDBPB.clear();
    m_pDocDBNameFT.clear();
    m_pDefineBT.clear();
    SvxStandardDialog::dispose();
    short nRet = SfxDialogController::run();
    if (nRet == RET_OK)
        UpdateFields();
    return nRet;
}

// close
void SwChangeDBDlg::Apply()
{
    UpdateFields();
}
void SwChangeDBDlg::UpdateFields()
{
    std::vector<OUString> aDBNames;
    aDBNames.reserve(m_pUsedDBTLB->GetSelectionCount());
    SvTreeListEntry* pEntry = m_pUsedDBTLB->FirstSelected();

    while( pEntry )
    {
        if( m_pUsedDBTLB->GetParent( pEntry ))
    m_xUsedDBTLB->selected_foreach([this, &aDBNames](weld::TreeIter& rEntry){
        if (m_xUsedDBTLB->get_iter_depth(rEntry))
        {
            OUString sTmp(m_pUsedDBTLB->GetEntryText( m_pUsedDBTLB->GetParent( pEntry )) +
                          OUStringLiteral1(DB_DELIM) + m_pUsedDBTLB->GetEntryText( pEntry ) + OUStringLiteral1(DB_DELIM) +
                          OUString::number(static_cast<int>(reinterpret_cast<sal_uLong>(pEntry->GetUserData()))));
            std::unique_ptr<weld::TreeIter> xIter(m_xUsedDBTLB->make_iterator(&rEntry));
            m_xUsedDBTLB->iter_parent(*xIter);
            OUString sTmp(m_xUsedDBTLB->get_text(*xIter) +
                          OUStringLiteral1(DB_DELIM) + m_xUsedDBTLB->get_text(rEntry) + OUStringLiteral1(DB_DELIM) +
                          m_xUsedDBTLB->get_id(rEntry));
            aDBNames.push_back(sTmp);
        }
        pEntry = m_pUsedDBTLB->NextSelected(pEntry);
    }
    });

    pSh->StartAllAction();
    OUString sTableName;
    OUString sColumnName;
    sal_Bool bIsTable = false;
    const OUString DBName(m_pAvailDBTLB->GetDBName(sTableName, sColumnName, &bIsTable));
    const OUString DBName(m_xAvailDBTLB->GetDBName(sTableName, sColumnName, &bIsTable));
    const OUString sTemp = DBName
        + OUStringLiteral1(DB_DELIM)
        + sTableName
@@ -215,52 +211,60 @@ void SwChangeDBDlg::UpdateFields()
    pSh->EndAllAction();
}

IMPL_LINK_NOARG(SwChangeDBDlg, ButtonHdl, Button*, void)
IMPL_LINK_NOARG(SwChangeDBDlg, ButtonHdl, weld::Button&, void)
{
    OUString sTableName;
    OUString sColumnName;
    SwDBData aData;
    sal_Bool bIsTable = false;
    aData.sDataSource = m_pAvailDBTLB->GetDBName(sTableName, sColumnName, &bIsTable);
    aData.sDataSource = m_xAvailDBTLB->GetDBName(sTableName, sColumnName, &bIsTable);
    aData.sCommand = sTableName;
    aData.nCommandType = bIsTable ? 0 : 1;
    pSh->ChgDBData(aData);
    ShowDBName(pSh->GetDBData());
    EndDialog(RET_OK);
    m_xDialog->response(RET_OK);
}

IMPL_LINK_NOARG(SwChangeDBDlg, TreeSelectHdl, SvTreeListBox*, void)
IMPL_LINK_NOARG(SwChangeDBDlg, TreeSelectHdl, weld::TreeView&, void)
{
    SvTreeListEntry* pEntry = m_pAvailDBTLB->GetCurEntry();

    if (pEntry)
    {
        bool bEnable = false;
        if (m_pAvailDBTLB->GetParent(pEntry))
            bEnable = true;
        m_pDefineBT->Enable( bEnable );
    }
    TreeSelect();
}

void SwChangeDBDlg::TreeSelect()
{
    bool bEnable = false;
    std::unique_ptr<weld::TreeIter> xIter(m_xAvailDBTLB->make_iterator());
    if (m_xAvailDBTLB->get_selected(xIter.get()))
    {
        if (m_xAvailDBTLB->get_iter_depth(*xIter))
            bEnable = true;
    }
    m_xDefineBT->set_sensitive(bEnable);
}


// convert database name for display
void SwChangeDBDlg::ShowDBName(const SwDBData& rDBData)
{
    if (rDBData.sDataSource.isEmpty() && rDBData.sCommand.isEmpty())
    {
        m_pDocDBNameFT->SetText(SwResId(SW_STR_NONE));
        m_xDocDBNameFT->set_label(SwResId(SW_STR_NONE));
    }
    else
    {
        const OUString sName(rDBData.sDataSource + "." + rDBData.sCommand);
        m_pDocDBNameFT->SetText(sName.replaceAll("~", "~~"));
        m_xDocDBNameFT->set_label(sName.replaceAll("~", "~~"));
    }
}

IMPL_LINK_NOARG(SwChangeDBDlg, AddDBHdl, Button*, void)
IMPL_LINK_NOARG(SwChangeDBDlg, AddDBHdl, weld::Button&, void)
{
    const OUString sNewDB = SwDBManager::LoadAndRegisterDataSource(GetFrameWeld());
    const OUString sNewDB = SwDBManager::LoadAndRegisterDataSource(m_xDialog.get());
    if (!sNewDB.isEmpty())
        m_pAvailDBTLB->AddDataSource(sNewDB);
    {
        m_xAvailDBTLB->AddDataSource(sNewDB);
        TreeSelect();
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/dbui/dbtree.cxx b/sw/source/uibase/dbui/dbtree.cxx
index 8daa167..34840d8 100644
--- a/sw/source/uibase/dbui/dbtree.cxx
+++ b/sw/source/uibase/dbui/dbtree.cxx
@@ -486,4 +486,290 @@ void SwDBTreeList::SetWrtShell(SwWrtShell& rSh)
        InitTreeList();
}

DBTreeList::DBTreeList(std::unique_ptr<weld::TreeView> xTreeView)
    : bInitialized(false)
    , bShowColumns(false)
    , pImpl(new SwDBTreeList_Impl)
    , m_xTreeView(std::move(xTreeView))
{
    m_xTreeView->connect_expanding(LINK(this, DBTreeList, RequestingChildrenHdl));
#if 0
    if (m_xTreeView->get_visible())
        InitTreeList();
#endif
}

DBTreeList::~DBTreeList()
{
}

void DBTreeList::InitTreeList()
{
    if (!pImpl->HasContext() && pImpl->GetWrtShell())
        return;

//TODO    SetDragDropMode(DragDropMode::APP_COPY);

//TODO    GetModel()->SetCompareHdl(LINK(this, DBTreeList, DBCompare));

    Sequence< OUString > aDBNames = pImpl->GetContext()->getElementNames();
    auto const sort = comphelper::string::NaturalStringSorter(
        comphelper::getProcessComponentContext(),
        Application::GetSettings().GetUILanguageTag().getLocale());
    std::sort(
        aDBNames.begin(), aDBNames.end(),
        [&sort](OUString const & x, OUString const & y)
        { return sort.compare(x, y) < 0; });
    const OUString* pDBNames = aDBNames.getConstArray();
    sal_Int32 nCount = aDBNames.getLength();

    OUString aImg(RID_BMP_DB);
    for (sal_Int32 i = 0; i < nCount; ++i)
    {
        OUString sDBName(pDBNames[i]);
        Reference<XConnection> xConnection = pImpl->GetConnection(sDBName);
        if (xConnection.is())
        {
            m_xTreeView->insert(nullptr, -1, &sDBName, nullptr, nullptr, nullptr, &aImg, true, nullptr);
        }
    }
    Select(OUString(), OUString(), OUString());

    bInitialized = true;
}

void DBTreeList::AddDataSource(const OUString& rSource)
{
    OUString aImg(RID_BMP_DB);
    std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
    m_xTreeView->insert(nullptr, -1, &rSource, nullptr, nullptr, nullptr, &aImg, true, xIter.get());
    m_xTreeView->select(*xIter);
}

IMPL_LINK(DBTreeList, RequestingChildrenHdl, weld::TreeIter&, rParent, bool)
{
    if (!m_xTreeView->iter_has_child(rParent))
    {
        if (m_xTreeView->get_iter_depth(rParent)) // column names
        {
            try
            {
                std::unique_ptr<weld::TreeIter> xGrandParent(m_xTreeView->make_iterator(&rParent));
                m_xTreeView->iter_parent(*xGrandParent);
                OUString sSourceName = m_xTreeView->get_text(*xGrandParent);
                OUString sTableName = m_xTreeView->get_text(rParent);

                if(!pImpl->GetContext()->hasByName(sSourceName))
                    return true;
                Reference<XConnection> xConnection = pImpl->GetConnection(sSourceName);
                bool bTable = m_xTreeView->get_id(rParent).isEmpty();
                Reference<XColumnsSupplier> xColsSupplier;
                if(bTable)
                {
                    Reference<XTablesSupplier> xTSupplier(xConnection, UNO_QUERY);
                    if(xTSupplier.is())
                    {
                        Reference<XNameAccess> xTables = xTSupplier->getTables();
                        OSL_ENSURE(xTables->hasByName(sTableName), "table not available anymore?");
                        try
                        {
                            Any aTable = xTables->getByName(sTableName);
                            Reference<XPropertySet> xPropSet;
                            aTable >>= xPropSet;
                            xColsSupplier.set(xPropSet, UNO_QUERY);
                        }
                        catch (const Exception&)
                        {
                        }
                    }
                }
                else
                {
                    Reference<XQueriesSupplier> xQSupplier(xConnection, UNO_QUERY);
                    if(xQSupplier.is())
                    {
                        Reference<XNameAccess> xQueries = xQSupplier->getQueries();
                        OSL_ENSURE(xQueries->hasByName(sTableName), "table not available anymore?");
                        try
                        {
                            Any aQuery = xQueries->getByName(sTableName);
                            Reference<XPropertySet> xPropSet;
                            aQuery >>= xPropSet;
                            xColsSupplier.set(xPropSet, UNO_QUERY);
                        }
                        catch (const Exception&)
                        {
                        }
                    }
                }

                if(xColsSupplier.is())
                {
                    Reference <XNameAccess> xCols = xColsSupplier->getColumns();
                    Sequence< OUString> aColNames = xCols->getElementNames();
                    const OUString* pColNames = aColNames.getConstArray();
                    long nCount = aColNames.getLength();
                    for (long i = 0; i < nCount; i++)
                    {
                        OUString sName = pColNames[i];
                        m_xTreeView->append(&rParent, sName);
                    }
                }
            }
            catch (const Exception&)
            {
            }
        }
        else    // table names
        {
            try
            {
                OUString sSourceName = m_xTreeView->get_text(rParent);
                if (!pImpl->GetContext()->hasByName(sSourceName))
                    return true;
                Reference<XConnection> xConnection = pImpl->GetConnection(sSourceName);
                if (xConnection.is())
                {
                    Reference<XTablesSupplier> xTSupplier(xConnection, UNO_QUERY);
                    if(xTSupplier.is())
                    {
                        Reference<XNameAccess> xTables = xTSupplier->getTables();
                        Sequence< OUString> aTableNames = xTables->getElementNames();
                        OUString sTableName;
                        long nCount = aTableNames.getLength();
                        const OUString* pTableNames = aTableNames.getConstArray();
                        OUString aImg(RID_BMP_DBTABLE);
                        for (long i = 0; i < nCount; i++)
                        {
                            sTableName = pTableNames[i];
                            m_xTreeView->insert(&rParent, -1, &sTableName, nullptr,
                                                nullptr, nullptr, &aImg, bShowColumns, nullptr);
                        }
                    }

                    Reference<XQueriesSupplier> xQSupplier(xConnection, UNO_QUERY);
                    if(xQSupplier.is())
                    {
                        Reference<XNameAccess> xQueries = xQSupplier->getQueries();
                        Sequence< OUString> aQueryNames = xQueries->getElementNames();
                        OUString sQueryName;
                        long nCount = aQueryNames.getLength();
                        const OUString* pQueryNames = aQueryNames.getConstArray();
                        OUString aImg(RID_BMP_DBQUERY);
                        for (long i = 0; i < nCount; i++)
                        {
                            sQueryName = pQueryNames[i];
                            //to discriminate between queries and tables the user data of query entries is set
                            OUString sId(OUString::number(1));
                            m_xTreeView->insert(&rParent, -1, &sQueryName, &sId,
                                                nullptr, nullptr, &aImg, bShowColumns, nullptr);
                        }
                    }
                }
            }
            catch (const Exception&)
            {
            }
        }
    }
    return true;
}

#if 0
IMPL_LINK( DBTreeList, DBCompare, const SvSortData&, rData, sal_Int32 )
{
    SvTreeListEntry* pRight = const_cast<SvTreeListEntry*>(rData.pRight);

    if (GetParent(pRight) && GetParent(GetParent(pRight)))
        return 1; // don't sort column names

    return DefaultCompare(rData);   // otherwise call base class
}
#endif

OUString DBTreeList::GetDBName(OUString& rTableName, OUString& rColumnName, sal_Bool* pbIsTable)
{
    OUString sDBName;
    std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
    if (m_xTreeView->get_selected(xIter.get()) && m_xTreeView->get_iter_depth(*xIter))
    {
        if (m_xTreeView->get_iter_depth(*xIter) > 2)
        {
            rColumnName = m_xTreeView->get_text(*xIter);
            m_xTreeView->iter_parent(*xIter); // column name was selected
        }
        if (pbIsTable)
        {
            *pbIsTable = m_xTreeView->get_id(*xIter).isEmpty();
        }
        rTableName = m_xTreeView->get_text(*xIter);
        m_xTreeView->iter_parent(*xIter);
        sDBName = m_xTreeView->get_text(*xIter);
    }
    return sDBName;
}

// Format: database.table
void DBTreeList::Select(const OUString& rDBName, const OUString& rTableName, const OUString& rColumnName)
{
    std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator());
    if (!m_xTreeView->get_iter_first(*xParent))
        return;

    do
    {
        if (rDBName == m_xTreeView->get_text(*xParent))
        {
            if (!m_xTreeView->iter_has_child(*xParent))
                m_xTreeView->expand_row(*xParent);
            std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xParent.get()));
            if (!m_xTreeView->iter_children(*xChild))
                continue;
            do
            {
                if (rTableName == m_xTreeView->get_text(*xChild))
                {
                    m_xTreeView->copy_iterator(*xChild, *xParent);

                    bool bNoChild = false;
                    if (bShowColumns && !rColumnName.isEmpty())
                    {
                        if (!m_xTreeView->iter_has_child(*xParent))
                            m_xTreeView->expand_row(*xParent);

                        bNoChild = true;
                        if (m_xTreeView->iter_children(*xChild))
                        {
                            do
                            {
                                if (rColumnName == m_xTreeView->get_text(*xChild))
                                {
                                    bNoChild = false;
                                    break;
                                }
                            }
                            while (m_xTreeView->iter_next_sibling(*xChild));
                        }
                    }

                    if (bNoChild)
                        m_xTreeView->copy_iterator(*xParent, *xChild);

                    m_xTreeView->scroll_to_row(*xChild);
                    m_xTreeView->select(*xChild);
                    return;
                }
            }
            while (m_xTreeView->iter_next_sibling(*xChild));
        }
    } while (m_xTreeView->iter_next_sibling(*xParent));
}

void DBTreeList::SetWrtShell(SwWrtShell& rSh)
{
    pImpl->SetWrtShell(rSh);
    if (m_xTreeView->get_visible() && !bInitialized)
        InitTreeList();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/changedb.hxx b/sw/source/uibase/inc/changedb.hxx
index b2563f0..9beae0b 100644
--- a/sw/source/uibase/inc/changedb.hxx
+++ b/sw/source/uibase/inc/changedb.hxx
@@ -19,11 +19,8 @@
#ifndef INCLUDED_SW_SOURCE_UIBASE_INC_CHANGEDB_HXX
#define INCLUDED_SW_SOURCE_UIBASE_INC_CHANGEDB_HXX

#include <vcl/bitmap.hxx>
#include <vcl/button.hxx>
#include <vcl/fixed.hxx>
#include <vcl/treelistbox.hxx>
#include <svx/stddlg.hxx>
#include <vcl/weld.hxx>
#include "dbtree.hxx"

class SwFieldMgr;
@@ -32,30 +29,31 @@ class SwWrtShell;
struct SwDBData;

// exchange database at fields
class SwChangeDBDlg: public SvxStandardDialog
class SwChangeDBDlg : public SfxDialogController
{
    VclPtr<SvTreeListBox>  m_pUsedDBTLB;
    VclPtr<SwDBTreeList>   m_pAvailDBTLB;
    VclPtr<PushButton>     m_pAddDBPB;
    VclPtr<FixedText>      m_pDocDBNameFT;
    VclPtr<PushButton>     m_pDefineBT;

    SwWrtShell      *pSh;

    DECL_LINK(TreeSelectHdl, SvTreeListBox*, void);
    DECL_LINK(ButtonHdl, Button*, void);
    DECL_LINK(AddDBHdl, Button*, void);
    std::unique_ptr<weld::TreeView> m_xUsedDBTLB;
    std::unique_ptr<DBTreeList> m_xAvailDBTLB;
    std::unique_ptr<weld::Button> m_xAddDBPB;
    std::unique_ptr<weld::Label> m_xDocDBNameFT;
    std::unique_ptr<weld::Button> m_xDefineBT;

    virtual void    Apply() override;
    void TreeSelect();

    DECL_LINK(TreeSelectHdl, weld::TreeView&, void);
    DECL_LINK(ButtonHdl, weld::Button&, void);
    DECL_LINK(AddDBHdl, weld::Button&, void);

    void            UpdateFields();
    void            FillDBPopup();
    SvTreeListEntry*    Insert(const OUString& rDBName);
    std::unique_ptr<weld::TreeIter> Insert(const OUString& rDBName);
    void            ShowDBName(const SwDBData& rDBData);

public:
    SwChangeDBDlg(SwView const & rVw);
    virtual short run() override;
    virtual ~SwChangeDBDlg() override;
    virtual void dispose() override;
};

#endif
diff --git a/sw/source/uibase/inc/dbtree.hxx b/sw/source/uibase/inc/dbtree.hxx
index 333f850..c9634b6 100644
--- a/sw/source/uibase/inc/dbtree.hxx
+++ b/sw/source/uibase/inc/dbtree.hxx
@@ -21,6 +21,7 @@

#include <memory>
#include <vcl/treelistbox.hxx>
#include <vcl/weld.hxx>

#include <swdllapi.h>
#include <swtypes.hxx>
@@ -62,6 +63,40 @@ public:
    void    AddDataSource(const OUString& rSource);
};

class SW_DLLPUBLIC DBTreeList
{
    bool            bInitialized;
    bool            bShowColumns;

    rtl::Reference<SwDBTreeList_Impl> pImpl;
    std::unique_ptr<weld::TreeView> m_xTreeView;
#if 0

    DECL_DLLPRIVATE_LINK( DBCompare, const SvSortData&, sal_Int32 );
#endif
    DECL_DLLPRIVATE_LINK(RequestingChildrenHdl, weld::TreeIter&, bool);
    SAL_DLLPRIVATE void          InitTreeList();

public:
    DBTreeList(std::unique_ptr<weld::TreeView> xTreeView);
    ~DBTreeList();

    OUString GetDBName(OUString& rTableName, OUString& rColumnName, sal_Bool* pbIsTable = nullptr);

    void    Select( const OUString& rDBName, const OUString& rTableName,
                    const OUString& rColumnName );

    void    SetWrtShell(SwWrtShell& rSh);

    void    AddDataSource(const OUString& rSource);

    void connect_changed(const Link<weld::TreeView&, void>& rLink) { m_xTreeView->connect_changed(rLink); }
    std::unique_ptr<weld::TreeIter> make_iterator(const weld::TreeIter* pOrig = nullptr) const { return m_xTreeView->make_iterator(pOrig); }
    bool get_selected(weld::TreeIter* pIter) const { return m_xTreeView->get_selected(pIter); }
    int get_iter_depth(const weld::TreeIter& rIter) const { return m_xTreeView->get_iter_depth(rIter); }
    void set_size_request(int nWidth, int nHeight) { m_xTreeView->set_size_request(nWidth, nHeight); }
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/uiconfig/swriter/ui/exchangedatabases.ui b/sw/uiconfig/swriter/ui/exchangedatabases.ui
index d2a4486..44f3285c 100644
--- a/sw/uiconfig/swriter/ui/exchangedatabases.ui
+++ b/sw/uiconfig/swriter/ui/exchangedatabases.ui
@@ -1,12 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.0 -->
<!-- Generated with glade 3.22.1 -->
<interface domain="sw">
  <requires lib="gtk+" version="3.18"/>
  <object class="GtkTreeStore" id="liststore1">
    <columns>
      <!-- column-name expander -->
      <column type="GdkPixbuf"/>
      <!-- column-name text -->
      <column type="gchararray"/>
      <!-- column-name id -->
      <column type="gchararray"/>
    </columns>
  </object>
  <object class="GtkTreeStore" id="liststore2">
    <columns>
      <!-- column-name expander -->
      <column type="GdkPixbuf"/>
      <!-- column-name text -->
      <column type="gchararray"/>
      <!-- column-name id -->
      <column type="gchararray"/>
    </columns>
  </object>
  <object class="GtkDialog" id="ExchangeDatabasesDialog">
    <property name="can_focus">False</property>
    <property name="border_width">6</property>
    <property name="title" translatable="yes" context="exchangedatabases|ExchangeDatabasesDialog">Exchange Databases</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>
@@ -17,7 +40,7 @@
            <property name="can_focus">False</property>
            <property name="layout_style">end</property>
            <child>
              <object class="GtkButton" id="define">
              <object class="GtkButton" id="ok">
                <property name="label" translatable="yes" context="exchangedatabases|define">Define</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
@@ -57,6 +80,7 @@
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">2</property>
                <property name="secondary">True</property>
              </packing>
            </child>
          </object>
@@ -102,32 +126,28 @@
                          <object class="GtkLabel" id="label5">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="xalign">0</property>
                            <property name="label" translatable="yes" context="exchangedatabases|label5">Databases in Use</property>
                            <property name="use_underline">True</property>
                            <property name="mnemonic_widget">inuselb:border</property>
                            <property name="mnemonic_widget">inuselb</property>
                            <property name="xalign">0</property>
                          </object>
                          <packing>
                            <property name="left_attach">0</property>
                            <property name="top_attach">0</property>
                            <property name="width">1</property>
                            <property name="height">1</property>
                          </packing>
                        </child>
                        <child>
                          <object class="GtkLabel" id="label6">
                            <property name="visible">True</property>
                            <property name="can_focus">False</property>
                            <property name="xalign">0</property>
                            <property name="label" translatable="yes" context="exchangedatabases|label6">_Available Databases</property>
                            <property name="use_underline">True</property>
                            <property name="mnemonic_widget">availablelb:border</property>
                            <property name="mnemonic_widget">availablelb</property>
                            <property name="xalign">0</property>
                          </object>
                          <packing>
                            <property name="left_attach">1</property>
                            <property name="top_attach">0</property>
                            <property name="width">1</property>
                            <property name="height">1</property>
                          </packing>
                        </child>
                        <child>
@@ -142,8 +162,6 @@
                          <packing>
                            <property name="left_attach">1</property>
                            <property name="top_attach">2</property>
                            <property name="width">1</property>
                            <property name="height">1</property>
                          </packing>
                        </child>
                        <child>
@@ -152,45 +170,113 @@
                            <property name="can_focus">False</property>
                            <property name="margin_top">12</property>
                            <property name="margin_bottom">12</property>
                            <property name="xalign">0</property>
                            <property name="label" translatable="yes" context="exchangedatabases|label7">Use this dialog to replace the databases you access in your document via database fields, with other databases. You can only make one change at a time. Multiple selection is possible in the list on the left.
Use the browse button to select a database file.</property>
                            <property name="wrap">True</property>
                            <property name="width_chars">72</property>
                            <property name="max_width_chars">72</property>
                            <property name="xalign">0</property>
                          </object>
                          <packing>
                            <property name="left_attach">0</property>
                            <property name="top_attach">3</property>
                            <property name="width">2</property>
                            <property name="height">1</property>
                          </packing>
                        </child>
                        <child>
                          <object class="vcllo-SvTreeListBox" id="inuselb:border">
                          <object class="GtkScrolledWindow">
                            <property name="visible">True</property>
                            <property name="can_focus">False</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="inuselb">
                                <property name="width_request">-1</property>
                                <property name="visible">True</property>
                                <property name="can_focus">True</property>
                                <property name="receives_default">True</property>
                                <property name="hexpand">True</property>
                                <property name="vexpand">True</property>
                                <property name="model">liststore1</property>
                                <property name="headers_visible">False</property>
                                <property name="show_expanders">True</property>
                                <property name="search_column">1</property>
                                <property name="enable_tree_lines">True</property>
                                <child internal-child="selection">
                                  <object class="GtkTreeSelection" id="Macro Library List-selection1"/>
                                </child>
                                <child>
                                  <object class="GtkTreeViewColumn" id="treeviewcolumn2">
                                    <property name="spacing">6</property>
                                    <child>
                                      <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/>
                                      <attributes>
                                        <attribute name="pixbuf">0</attribute>
                                      </attributes>
                                    </child>
                                    <child>
                                      <object class="GtkCellRendererText" id="cellrenderertext2"/>
                                      <attributes>
                                        <attribute name="text">1</attribute>
                                      </attributes>
                                    </child>
                                  </object>
                                </child>
                              </object>
                            </child>
                          </object>
                          <packing>
                            <property name="left_attach">0</property>
                            <property name="top_attach">1</property>
                            <property name="width">1</property>
                            <property name="height">1</property>
                          </packing>
                        </child>
                        <child>
                          <object class="swlo-SwDBTreeList" id="availablelb:border">
                          <object class="GtkScrolledWindow">
                            <property name="visible">True</property>
                            <property name="can_focus">False</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="availablelb">
                                <property name="width_request">-1</property>
                                <property name="visible">True</property>
                                <property name="can_focus">True</property>
                                <property name="receives_default">True</property>
                                <property name="hexpand">True</property>
                                <property name="vexpand">True</property>
                                <property name="model">liststore2</property>
                                <property name="headers_visible">False</property>
                                <property name="show_expanders">True</property>
                                <property name="search_column">1</property>
                                <property name="enable_tree_lines">True</property>
                                <child internal-child="selection">
                                  <object class="GtkTreeSelection" id="Macro Library List-selection2"/>
                                </child>
                                <child>
                                  <object class="GtkTreeViewColumn" id="treeviewcolumn8">
                                    <property name="spacing">6</property>
                                    <child>
                                      <object class="GtkCellRendererPixbuf" id="cellrenderertext5"/>
                                      <attributes>
                                        <attribute name="pixbuf">0</attribute>
                                      </attributes>
                                    </child>
                                    <child>
                                      <object class="GtkCellRendererText" id="cellrenderertext6"/>
                                      <attributes>
                                        <attribute name="text">1</attribute>
                                      </attributes>
                                    </child>
                                  </object>
                                </child>
                              </object>
                            </child>
                          </object>
                          <packing>
                            <property name="left_attach">1</property>
                            <property name="top_attach">1</property>
                            <property name="width">1</property>
                            <property name="height">1</property>
                          </packing>
                        </child>
                        <child>
@@ -238,7 +324,7 @@ Use the browse button to select a database file.</property>
                  <object class="GtkLabel" id="dbnameft">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="label" translatable="no">DataSource.Command</property>
                    <property name="label">DataSource.Command</property>
                  </object>
                  <packing>
                    <property name="expand">False</property>
@@ -263,7 +349,7 @@ Use the browse button to select a database file.</property>
      </object>
    </child>
    <action-widgets>
      <action-widget response="0">define</action-widget>
      <action-widget response="-5">ok</action-widget>
      <action-widget response="-7">close</action-widget>
      <action-widget response="-11">help</action-widget>
    </action-widgets>