Related: tdf#130326 allow bulk_insert_for_each to insert under a node

Change-Id: Iad14638a33710ef0b790c702e7eab2283726f2fb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114571
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/cui/source/tabpages/autocdlg.cxx b/cui/source/tabpages/autocdlg.cxx
index 55fee3ed..c682662 100644
--- a/cui/source/tabpages/autocdlg.cxx
+++ b/cui/source/tabpages/autocdlg.cxx
@@ -836,7 +836,7 @@ void OfaAutocorrReplacePage::RefillReplaceBox(bool bFromReset,
            {
                aFormatText.insert(rDouble.sShort);
            }
        }, &m_aReplaceFixedWidths);
        }, nullptr, &m_aReplaceFixedWidths);
    }
    else
    {
@@ -862,7 +862,7 @@ void OfaAutocorrReplacePage::RefillReplaceBox(bool bFromReset,
            {
                aFormatText.insert(elem.GetShort());
            }
        }, &m_aReplaceFixedWidths);
        }, nullptr, &m_aReplaceFixedWidths);
        m_xNewReplacePB->set_sensitive(false);
        m_xDeleteReplacePB->set_sensitive(false);
    }
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 26e7f32..c055ee0 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -1133,7 +1133,8 @@ public:
    virtual void selected_foreach(const std::function<bool(TreeIter&)>& func) = 0;
    // call func on each visible element until func returns true or we run out of elements
    virtual void visible_foreach(const std::function<bool(TreeIter&)>& func) = 0;
    // clear the tree, then add nSourceCount rows, call func on each row
    // clear the children of pParent (whole tree if nullptr),
    // then add nSourceCount rows under pParent, call func on each row
    // inserted with an arg of the index that this row will be when bulk insert
    // ends.
    //
@@ -1145,6 +1146,7 @@ public:
    // be scrolled into view horizontally.
    virtual void bulk_insert_for_each(int nSourceCount,
                                      const std::function<void(TreeIter&, int nSourceIndex)>& func,
                                      const weld::TreeIter* pParent = nullptr,
                                      const std::vector<int>* pFixedWidths = nullptr)
        = 0;

diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx
index 201313f..55072f5 100644
--- a/sc/source/ui/cctrl/checklistmenu.cxx
+++ b/sc/source/ui/cctrl/checklistmenu.cxx
@@ -802,7 +802,7 @@ IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void)
                size_t nIndex = aShownIndexes[i];
                insertMember(*mpChecks, rIter, maMembers[nIndex], true);
                ++nSelCount;
            }, &aFixedWidths);
            }, nullptr, &aFixedWidths);
        }
    }

@@ -1256,7 +1256,7 @@ size_t ScCheckListMenuControl::initMembers(int nMaxMemberWidth)
            insertMember(*mpChecks, rIter, maMembers[i], maMembers[i].mbVisible);
            if (maMembers[i].mbVisible)
                ++nVisMemCount;
        }, &aFixedWidths);
        }, nullptr, &aFixedWidths);
    }
    else
    {
diff --git a/sc/source/ui/navipi/content.cxx b/sc/source/ui/navipi/content.cxx
index 6f4d921..53b4e41 100644
--- a/sc/source/ui/navipi/content.cxx
+++ b/sc/source/ui/navipi/content.cxx
@@ -879,52 +879,51 @@ void ScContentTree::GetDrawNames( ScContentId nType )
    if (!pDoc)
        return;

    ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
    if (!pDrawLayer)
        return;

    SfxObjectShell* pShell = pDoc->GetDocumentShell();
    if (!pShell)
        return;

    // iterate in flat mode for groups
    SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;

    ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
    SfxObjectShell* pShell = pDoc->GetDocumentShell();
    if (!(pDrawLayer && pShell))
        return;

    std::vector<OUString> aNames;
    SCTAB nTabCount = pDoc->GetTableCount();
    int treeNodeCount = 0;
    for (SCTAB nTab=0; nTab<nTabCount; nTab++)
    {
        SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
        OSL_ENSURE(pPage,"Page ?");
        if (pPage)
        if (!pPage)
            continue;
        SdrObjListIter aIter(pPage, eIter);
        SdrObject* pObject = aIter.Next();
        while (pObject)
        {
            SdrObjListIter aIter( pPage, eIter );
            SdrObject* pObject = aIter.Next();
            while (pObject)
            if (IsPartOfType(nType, pObject->GetObjIdentifier()))
            {
                if ( IsPartOfType( nType, pObject->GetObjIdentifier() ) )
                OUString aName = ScDrawLayer::GetVisibleName(pObject);
                if (!aName.isEmpty())
                    aNames.push_back(aName);
                if (aNames.size() > MAX_TREE_NODES)
                {
                    OUString aName = ScDrawLayer::GetVisibleName( pObject );
                    if (!aName.isEmpty())
                    {
                        weld::TreeIter* pParent = m_aRootNodes[nType].get();
                        if (pParent)
                        {
                            m_xTreeView->insert(pParent, -1, &aName, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
                            m_xTreeView->set_sensitive(*m_xScratchIter, true);
                            treeNodeCount++;
                            if (treeNodeCount > MAX_TREE_NODES)
                            {
                                SAL_WARN("sc", "too many tree nodes, ignoring the rest");
                                return;
                            }
                        }//end if parent
                        else
                            SAL_WARN("sc", "InsertContent without parent");
                    }
                    SAL_WARN("sc", "too many tree nodes, ignoring the rest");
                    break;
                }

                pObject = aIter.Next();
            }
            pObject = aIter.Next();
        }
    }

    weld::TreeIter* pParent = m_aRootNodes[nType].get();
    assert(pParent && "InsertContent without parent");
    // insert all of these in one go under pParent
    m_xTreeView->bulk_insert_for_each(aNames.size(), [this, &aNames](weld::TreeIter& rIter, int nIndex) {
        m_xTreeView->set_text(rIter, aNames[nIndex]);
        m_xTreeView->set_sensitive(rIter, true);
    }, pParent);
}

void ScContentTree::GetGraphicNames()
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index 7f51cf5..f71ce7a 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -1448,6 +1448,7 @@ public:
    virtual void
    bulk_insert_for_each(int nSourceCount,
                         const std::function<void(weld::TreeIter&, int nSourceIndex)>& func,
                         const weld::TreeIter* pParent = nullptr,
                         const std::vector<int>* pFixedWidths = nullptr) override;

    virtual void set_font_color(int pos, const Color& rColor) override;
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 7d9be31..585fbeb 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -3819,10 +3819,19 @@ void SalInstanceTreeView::insert_separator(int pos, const OUString& /*rId*/)

void SalInstanceTreeView::bulk_insert_for_each(
    int nSourceCount, const std::function<void(weld::TreeIter&, int nSourceIndex)>& func,
    const std::vector<int>* pFixedWidths)
    const weld::TreeIter* pParent, const std::vector<int>* pFixedWidths)
{
    const SalInstanceTreeIter* pVclIter = static_cast<const SalInstanceTreeIter*>(pParent);
    SvTreeListEntry* pVclParent = pVclIter ? pVclIter->iter : nullptr;

    freeze();
    clear();
    if (!pVclParent)
        clear();
    else
    {
        while (SvTreeListEntry* pChild = m_xTreeView->FirstChild(pVclParent))
            m_xTreeView->RemoveEntry(pChild);
    }
    SalInstanceTreeIter aVclIter(static_cast<SvTreeListEntry*>(nullptr));

    m_xTreeView->nTreeFlags |= SvTreeFlags::MANINS;
@@ -3840,7 +3849,7 @@ void SalInstanceTreeView::bulk_insert_for_each(
        if (bHasAutoCheckButton)
            AddStringItem(aVclIter.iter, "", -1);
        aVclIter.iter->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
        m_xTreeView->Insert(aVclIter.iter, nullptr, TREELIST_APPEND);
        m_xTreeView->Insert(aVclIter.iter, pVclParent, TREELIST_APPEND);
        func(aVclIter, i);

        if (!pFixedWidths)
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 9d40868..8f261d1 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -9950,14 +9950,14 @@ void list_store_clear(GtkTreeModel* pTreeModel)
    gtk_list_store_clear(GTK_LIST_STORE(pTreeModel));
}

void tree_store_remove(GtkTreeModel* pTreeModel, GtkTreeIter *pIter)
bool tree_store_remove(GtkTreeModel* pTreeModel, GtkTreeIter *pIter)
{
    gtk_tree_store_remove(GTK_TREE_STORE(pTreeModel), pIter);
    return gtk_tree_store_remove(GTK_TREE_STORE(pTreeModel), pIter);
}

void list_store_remove(GtkTreeModel* pTreeModel, GtkTreeIter *pIter)
bool list_store_remove(GtkTreeModel* pTreeModel, GtkTreeIter *pIter)
{
    gtk_list_store_remove(GTK_LIST_STORE(pTreeModel), pIter);
    return gtk_list_store_remove(GTK_LIST_STORE(pTreeModel), pIter);
}

void tree_store_swap(GtkTreeModel* pTreeModel, GtkTreeIter* pIter1, GtkTreeIter* pIter2)
@@ -10006,7 +10006,7 @@ private:
    typedef void(*clearFnc)(GtkTreeModel*);
    clearFnc m_Clear;

    typedef void(*removeFnc)(GtkTreeModel*, GtkTreeIter*);
    typedef bool(*removeFnc)(GtkTreeModel*, GtkTreeIter*);
    removeFnc m_Remove;

    typedef void(*swapFnc)(GtkTreeModel*, GtkTreeIter*, GtkTreeIter*);
@@ -11093,10 +11093,23 @@ public:
    }

    virtual void bulk_insert_for_each(int nSourceCount, const std::function<void(weld::TreeIter&, int nSourceIndex)>& func,
                                      const weld::TreeIter* pParent,
                                      const std::vector<int>* pFixedWidths) override
    {
        GtkInstanceTreeIter* pGtkIter = const_cast<GtkInstanceTreeIter*>(static_cast<const GtkInstanceTreeIter*>(pParent));

        freeze();
        clear();
        if (!pGtkIter)
            clear();
        else
        {
            GtkTreeIter restore(pGtkIter->iter);

            if (iter_children(*pGtkIter))
                while (m_Remove(m_pTreeModel, &pGtkIter->iter));

            pGtkIter->iter = restore;
        }
        GtkInstanceTreeIter aGtkIter(nullptr);

        if (pFixedWidths)
@@ -11105,7 +11118,7 @@ public:
        while (nSourceCount)
        {
            // tdf#125241 inserting backwards is massively faster
            m_Prepend(m_pTreeModel, &aGtkIter.iter, nullptr);
            m_Prepend(m_pTreeModel, &aGtkIter.iter, pGtkIter ? &pGtkIter->iter : nullptr);
            func(aGtkIter, --nSourceCount);
        }