tdf#38194 related: introduce StylesList control

Change-Id: I31202c213e034ab96f28e16d1f6a59b52f47507d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117918
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/sfx2/Library_sfx.mk b/sfx2/Library_sfx.mk
index fff97d0..39b5438 100644
--- a/sfx2/Library_sfx.mk
+++ b/sfx2/Library_sfx.mk
@@ -203,6 +203,7 @@ $(eval $(call gb_Library_add_exception_objects,sfx,\
    sfx2/source/dialog/styledlg \
    sfx2/source/dialog/tabdlg \
    sfx2/source/dialog/templdlg \
    sfx2/source/dialog/StyleList \
    sfx2/source/dialog/titledockwin \
    sfx2/source/dialog/tplcitem \
    sfx2/source/dialog/tplpitem \
diff --git a/sfx2/source/dialog/StyleList.cxx b/sfx2/source/dialog/StyleList.cxx
new file mode 100644
index 0000000..8525c62
--- /dev/null
+++ b/sfx2/source/dialog/StyleList.cxx
@@ -0,0 +1,1814 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <memory>

#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <vcl/commandevent.hxx>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/event.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weldutils.hxx>
#include <svl/intitem.hxx>
#include <svl/stritem.hxx>
#include <svl/style.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/frame/ModuleManager.hpp>
#include <com/sun/star/frame/UnknownModuleException.hpp>
#include <officecfg/Office/Common.hxx>

#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <tools/diagnose_ex.h>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/templdlg.hxx>
#include <templdgi.hxx>
#include <tplcitem.hxx>
#include <sfx2/styfitem.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/newstyle.hxx>
#include <sfx2/tplpitem.hxx>
#include <sfx2/sfxresid.hxx>

#include <sfx2/sfxsids.hrc>
#include <sfx2/strings.hrc>
#include <sfx2/docfac.hxx>
#include <sfx2/module.hxx>
#include <helpids.h>
#include <sfx2/viewfrm.hxx>

#include <comphelper/string.hxx>

#include <sfx2/StyleManager.hxx>
#include <sfx2/StylePreviewRenderer.hxx>

#include <StyleList.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/menu.hxx>

using namespace css;
using namespace css::beans;
using namespace css::frame;
using namespace css::uno;

// Constructor

StyleList::StyleList(weld::Builder* pBuilder, std::optional<SfxStyleFamilies> xFamilies,
                     SfxBindings* pBindings, SfxCommonTemplateDialog_Impl* Parent,
                     SfxModule* Module, weld::Container* pC, OString treeviewname,
                     OString flatviewname)
    : m_bHierarchical(false)
    , m_bAllowReParentDrop(false)
    , m_bNewByExampleDisabled(false)
    , m_bDontUpdate(false)
    , m_bTreeDrag(true)
    , m_bCanEdit(false)
    , m_bCanHide(true)
    , m_bCanShow(false)
    , m_bCanNew(true)
    , m_bUpdateFamily(false)
    , m_bCanDel(false)
    , m_bBindingUpdate(true)
    , m_pStyleSheetPool(nullptr)
    , m_nActFilter(0)
    , m_xFmtLb(pBuilder->weld_tree_view(flatviewname))
    , m_xTreeBox(pBuilder->weld_tree_view(treeviewname))
    , m_xStyleFamilies(xFamilies)
    , m_nActFamily(0xffff)
    , m_nAppFilter(SfxStyleSearchBits::Auto)
    , m_pParentDialog(Parent)
    , m_pBindings(pBindings)
    , m_Module(Module)
    , m_nModifier(0)
    , m_pContainer(pC)
{
    m_xFmtLb->set_help_id(HID_TEMPLATE_FMT);
}

// Destructor

StyleList::~StyleList() {}

// Called in the destructor of Dialog
// Cleans up the StyleList individual components while closing the application
IMPL_LINK_NOARG(StyleList, Cleanup, void*, void)
{
    if (m_pStyleSheetPool)
        EndListening(*m_pStyleSheetPool);
    m_pStyleSheetPool = nullptr;
    m_xTreeView1DropTargetHelper.reset();
    m_xTreeView2DropTargetHelper.reset();
    m_xTreeBox.reset();
    m_xFmtLb.reset();
    pIdle.reset();
}

void StyleList::CreateContextMenu()
{
    if (m_bBindingUpdate)
    {
        m_pBindings->Invalidate(SID_STYLE_NEW, true);
        m_pBindings->Update(SID_STYLE_NEW);
        m_bBindingUpdate = false;
    }
    mxMenu.reset();
    mxMenuBuilder.reset(Application::CreateBuilder(nullptr, "sfx/ui/stylecontextmenu.ui"));
    mxMenu = mxMenuBuilder->weld_menu("menu");
    mxMenu->set_sensitive("edit", m_bCanEdit);
    mxMenu->set_sensitive("delete", m_bCanDel);
    mxMenu->set_sensitive("new", m_bCanNew);
    mxMenu->set_sensitive("hide", m_bCanHide);
    mxMenu->set_sensitive("show", m_bCanShow);

    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
    {
        mxMenu->set_sensitive("edit", false);
        mxMenu->set_sensitive("new", false);
    }
    if (pItem && pItem->GetFamily() == SfxStyleFamily::Pseudo)
    {
        const OUString aTemplName(GetSelectedEntry());
        if (aTemplName == "No List")
        {
            mxMenu->set_sensitive("edit", false);
            mxMenu->set_sensitive("new", false);
            mxMenu->set_sensitive("hide", false);
        }
    }
}

IMPL_LINK_NOARG(StyleList, ReadResource, void*, size_t)
{
    // Read global user resource
    for (auto& i : m_pFamilyState)
        i.reset();

    SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
    m_pCurObjShell = pViewFrame->GetObjectShell();
    m_Module = m_pCurObjShell ? m_pCurObjShell->GetModule() : nullptr;
    if (m_Module)
        m_xStyleFamilies = m_Module->CreateStyleFamilies();
    if (!m_xStyleFamilies)
        m_xStyleFamilies.emplace();

    m_nActFilter = 0xffff;
    // Assigning value to Dialog's nActFilter so that both nActFilters are in sync
    m_pParentDialog->SetFilterByIndex(m_nActFilter);
    if (m_pCurObjShell)
    {
        m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(m_pCurObjShell));
        // Assigning value to Dialog's nActFilter so that both nActFilters are in sync
        m_pParentDialog->SetFilterByIndex(m_nActFilter);
        if (0xffff == m_nActFilter)
        {
            m_nActFilter = m_pCurObjShell->GetAutoStyleFilterIndex();
            m_pParentDialog->SetFilterByIndex(m_nActFilter);
        }
    }
    size_t nCount = m_xStyleFamilies->size();
    m_pBindings->ENTERREGISTRATIONS();

    size_t i;
    for (i = 0; i < nCount; ++i)
    {
        sal_uInt16 nSlot = 0;
        switch (m_xStyleFamilies->at(i).GetFamily())
        {
            case SfxStyleFamily::Char:
                nSlot = SID_STYLE_FAMILY1;
                break;
            case SfxStyleFamily::Para:
                nSlot = SID_STYLE_FAMILY2;
                break;
            case SfxStyleFamily::Frame:
                nSlot = SID_STYLE_FAMILY3;
                break;
            case SfxStyleFamily::Page:
                nSlot = SID_STYLE_FAMILY4;
                break;
            case SfxStyleFamily::Pseudo:
                nSlot = SID_STYLE_FAMILY5;
                break;
            case SfxStyleFamily::Table:
                nSlot = SID_STYLE_FAMILY6;
                break;
            default:
                OSL_FAIL("unknown StyleFamily");
                break;
        }
        pBoundItems[i].reset(new SfxTemplateControllerItem(nSlot, *m_pParentDialog, *m_pBindings));
    }
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_WATERCAN, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_NEW_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_UPDATE_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_NEW, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_DRAGHIERARCHIE, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_EDIT, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_DELETE, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_FAMILY, *m_pParentDialog, *m_pBindings));
    m_pBindings->LEAVEREGISTRATIONS();

    for (; i < COUNT_BOUND_FUNC; ++i)
        pBoundItems[i] = nullptr;

    StartListening(*m_pBindings);

    for (i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++)
        m_pBindings->Update(i);

    return nCount;
}

void StyleList::EnableNewByExample(bool newByExampleDisabled)
{
    m_bNewByExampleDisabled = newByExampleDisabled;
}

class TreeViewDropTarget final : public DropTargetHelper
{
private:
    StyleList& m_rParent;

public:
    TreeViewDropTarget(StyleList& rStyleList, weld::TreeView& rTreeView)
        : DropTargetHelper(rTreeView.get_drop_target())
        , m_rParent(rStyleList)
    {
    }

    virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
    {
        return m_rParent.AcceptDrop(rEvt, *this);
    }

    virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
    {
        return m_rParent.ExecuteDrop(rEvt);
    }
};

IMPL_LINK(StyleList, FilterSelect, sal_uInt16, mActFilter, void)
{
    m_nActFilter = mActFilter;
    SfxObjectShell* const pDocShell = m_aSaveSelection.Call(nullptr);
    SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
    m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
    if (pOldStyleSheetPool != m_pStyleSheetPool)
    {
        if (pOldStyleSheetPool)
            EndListening(*pOldStyleSheetPool);
        if (m_pStyleSheetPool)
            StartListening(*m_pStyleSheetPool);
    }
}

IMPL_LINK(StyleList, SetFamily, sal_uInt16, nId, void)
{
    if (m_nActFamily != 0xFFFF)
        m_pParentDialog->CheckItem(OString::number(m_nActFamily), false);
    m_nActFamily = nId;
    if (nId != 0xFFFF)
    {
        m_bUpdateFamily = true;
    }
}

void StyleList::InvalidateBindings()
{
    m_pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
    m_pBindings->Update(SID_STYLE_NEW_BY_EXAMPLE);
    m_pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
    m_pBindings->Update(SID_STYLE_UPDATE_BY_EXAMPLE);
    m_pBindings->Invalidate(SID_STYLE_WATERCAN, true);
    m_pBindings->Update(SID_STYLE_WATERCAN);
    m_pBindings->Invalidate(SID_STYLE_NEW, true);
    m_pBindings->Update(SID_STYLE_NEW);
    m_pBindings->Invalidate(SID_STYLE_DRAGHIERARCHIE, true);
    m_pBindings->Update(SID_STYLE_DRAGHIERARCHIE);
}

void StyleList::Initialize()
{
    m_pBindings->Invalidate(SID_STYLE_FAMILY);
    m_pBindings->Update(SID_STYLE_FAMILY);

    m_xFmtLb->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
    m_xFmtLb->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
    m_xFmtLb->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
    m_xFmtLb->connect_changed(LINK(this, StyleList, FmtSelectHdl));
    m_xFmtLb->connect_popup_menu(LINK(this, StyleList, PopupFlatMenuHdl));
    m_xFmtLb->connect_key_press(LINK(this, StyleList, KeyInputHdl));
    m_xFmtLb->set_selection_mode(SelectionMode::Multiple);
    m_xTreeBox->connect_changed(LINK(this, StyleList, FmtSelectHdl));
    m_xTreeBox->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
    m_xTreeBox->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
    m_xTreeBox->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
    m_xTreeBox->connect_popup_menu(LINK(this, StyleList, PopupTreeMenuHdl));
    m_xTreeBox->connect_key_press(LINK(this, StyleList, KeyInputHdl));
    m_xTreeBox->connect_drag_begin(LINK(this, StyleList, DragBeginHdl));
    m_xTreeView1DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xFmtLb));
    m_xTreeView2DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xTreeBox));

    m_pParentDialog->connect_stylelist_read_resource(LINK(this, StyleList, ReadResource));
    m_pParentDialog->connect_stylelist_clear(LINK(this, StyleList, Clear));
    m_pParentDialog->connect_stylelist_cleanup(LINK(this, StyleList, Cleanup));
    m_pParentDialog->connect_stylelist_execute_drop(LINK(this, StyleList, ExecuteDrop));
    m_pParentDialog->connect_stylelist_execute_new_menu(
        LINK(this, StyleList, NewMenuExecuteAction));
    m_pParentDialog->connect_stylelist_for_watercan(LINK(this, StyleList, IsSafeForWaterCan));
    m_pParentDialog->connect_stylelist_has_selected_style(LINK(this, StyleList, HasSelectedStyle));
    m_pParentDialog->connect_stylelist_update_styles(LINK(this, StyleList, UpdateStyles));
    m_pParentDialog->connect_stylelist_update_family(LINK(this, StyleList, UpdateFamily));
    m_pParentDialog->connect_stylelist_update_style_dependents(
        LINK(this, StyleList, UpdateStyleDependents));
    m_pParentDialog->connect_stylelist_enable_tree_drag(LINK(this, StyleList, EnableTreeDrag));
    m_pParentDialog->connect_stylelist_filter_select(LINK(this, StyleList, FilterSelect));
    m_pParentDialog->connect_stylelist_enable_delete(LINK(this, StyleList, EnableDelete));
    m_pParentDialog->connect_stylelist_set_water_can_state(LINK(this, StyleList, SetWaterCanState));
    m_pParentDialog->connect_family_select(LINK(this, StyleList, FamilySelect));
    m_pParentDialog->connect_set_family(LINK(this, StyleList, SetFamily));

    int nTreeHeight = m_xFmtLb->get_height_rows(8);
    m_xFmtLb->set_size_request(-1, nTreeHeight);
    m_xTreeBox->set_size_request(-1, nTreeHeight);

    m_xFmtLb->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
    m_xFmtLb->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
    m_xTreeBox->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
    m_xTreeBox->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
    bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
    m_xFmtLb->set_column_custom_renderer(0, bCustomPreview);
    m_xTreeBox->set_column_custom_renderer(0, bCustomPreview);

    m_xFmtLb->set_visible(!m_bHierarchical);
    m_xTreeBox->set_visible(m_bHierarchical);
    Update();
}

IMPL_LINK_NOARG(StyleList, UpdateFamily, void*, void)
{
    m_bUpdateFamily = false;

    SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
    SfxViewFrame* pViewFrame = pDispat->GetFrame();
    SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();

    SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
    m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
    if (pOldStyleSheetPool != m_pStyleSheetPool)
    {
        if (pOldStyleSheetPool)
            EndListening(*pOldStyleSheetPool);
        if (m_pStyleSheetPool)
            StartListening(*m_pStyleSheetPool);
    }

    m_bTreeDrag = true;
    m_bCanNew = m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
    m_pParentDialog->EnableNew(m_bCanNew);
    m_bTreeDrag = true;
    if (m_pStyleSheetPool)
    {
        if (!m_xTreeBox->get_visible())
            UpdateStyles(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
        else
        {
            UpdateStyles(StyleFlags::UpdateFamily);
            FillTreeBox(GetActualFamily());
        }
    }

    InvalidateBindings();
}

bool StyleList::EnableExecute()
{
    return m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
}

void StyleList::connect_LoadFactoryStyleFilter(const Link<SfxObjectShell const*, sal_Int32>& rLink)
{
    m_aLoadFactoryStyleFilter = rLink;
}

void StyleList::connect_SaveSelection(const Link<void*, SfxObjectShell*> rLink)
{
    m_aSaveSelection = rLink;
}

void StyleList::connect_UpdateStyleDependents(const Link<void*, void> rLink)
{
    m_aUpdateStyleDependents = rLink;
}

/** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
    create a style out of the current selection.
*/
sal_Int8 StyleList::AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
{
    if (rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR))
    {
        // special case: page styles are allowed to create new styles by example
        // but not allowed to be created by drag and drop
        if (GetActualFamily() == SfxStyleFamily::Page || m_bNewByExampleDisabled)
            return DND_ACTION_NONE;
        else
            return DND_ACTION_COPY;
    }
    // to enable the autoscroll when we're close to the edges
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    pTreeView->get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
    return DND_ACTION_MOVE;
}

// handles drop of content in treeview when creating a new style
IMPL_LINK(StyleList, ExecuteDrop, const ExecuteDropEvent&, rEvt, sal_Int8)
{
    SfxObjectShell* pDocShell = m_pCurObjShell;
    if (pDocShell)
    {
        TransferableDataHelper aHelper(rEvt.maDropEvent.Transferable);
        sal_uInt32 nFormatCount = aHelper.GetFormatCount();

        sal_Int8 nRet = DND_ACTION_NONE;

        bool bFormatFound = false;

        for (sal_uInt32 i = 0; i < nFormatCount; ++i)
        {
            SotClipboardFormatId nId = aHelper.GetFormat(i);
            TransferableObjectDescriptor aDesc;

            if (aHelper.GetTransferableObjectDescriptor(nId, aDesc))
            {
                if (aDesc.maClassName == pDocShell->GetFactory().GetClassId())
                {
                    Application::PostUserEvent(
                        LINK(m_pParentDialog, SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop));

                    bFormatFound = true;
                    nRet = rEvt.mnAction;
                    break;
                }
            }
        }

        if (bFormatFound)
            return nRet;
    }

    if (!m_xTreeBox->get_visible())
        return DND_ACTION_NONE;

    if (!m_bAllowReParentDrop)
        return DND_ACTION_NONE;

    // otherwise if we're dragging with the treeview to set a new parent of the dragged style
    weld::TreeView* pSource = m_xTreeBox->get_drag_source();
    // only dragging within the same widget allowed
    if (!pSource || pSource != m_xTreeBox.get())
        return DND_ACTION_NONE;

    std::unique_ptr<weld::TreeIter> xSource(m_xTreeBox->make_iterator());
    if (!m_xTreeBox->get_selected(xSource.get()))
        return DND_ACTION_NONE;

    std::unique_ptr<weld::TreeIter> xTarget(m_xTreeBox->make_iterator());
    if (!m_xTreeBox->get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
    {
        // if nothing under the mouse, use the last row
        int nChildren = m_xTreeBox->n_children();
        if (!nChildren)
            return DND_ACTION_NONE;
        if (!m_xTreeBox->get_iter_first(*xTarget)
            || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
            return DND_ACTION_NONE;
        while (m_xTreeBox->get_row_expanded(*xTarget))
        {
            nChildren = m_xTreeBox->iter_n_children(*xTarget);
            if (!m_xTreeBox->iter_children(*xTarget)
                || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
                return DND_ACTION_NONE;
        }
    }
    OUString aTargetStyle = m_xTreeBox->get_text(*xTarget);
    DropHdl(m_xTreeBox->get_text(*xSource), aTargetStyle);
    m_xTreeBox->unset_drag_dest_row();
    FillTreeBox(GetActualFamily());
    m_pParentDialog->SelectStyle(aTargetStyle, false, *this);
    return DND_ACTION_NONE;
}

IMPL_LINK_NOARG(StyleList, NewMenuExecuteAction, void*, void)
{
    if (m_pStyleSheetPool && m_nActFamily != 0xffff)
    {
        const SfxStyleFamily eFam = GetFamilyItem()->GetFamily();
        const SfxStyleFamilyItem* pItem = GetFamilyItem();
        SfxStyleSearchBits nFilter(SfxStyleSearchBits::Auto);
        if (pItem && m_nActFilter != 0xffff)
            nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
        if (nFilter == SfxStyleSearchBits::Auto) // automatic
            nFilter = m_nAppFilter;

        // why? : FloatingWindow must not be parent of a modal dialog
        SfxNewStyleDlg aDlg(m_pContainer, *m_pStyleSheetPool, eFam);
        auto nResult = aDlg.run();
        if (nResult == RET_OK)
        {
            const OUString aTemplName(aDlg.GetName());
            m_pParentDialog->Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE, aTemplName, "",
                                          static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()),
                                          *this, nFilter);
            m_aUpdateFamily.Call(*this);
        }
    }
}

void StyleList::DropHdl(const OUString& rStyle, const OUString& rParent)
{
    m_bDontUpdate = true;
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    const SfxStyleFamily eFam = pItem->GetFamily();
    m_pStyleSheetPool->SetParent(eFam, rStyle, rParent);
    m_bDontUpdate = false;
}

void StyleList::PrepareMenu(const Point& rPos)
{
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    std::unique_ptr<weld::TreeIter> xIter(pTreeView->make_iterator());
    if (pTreeView->get_dest_row_at_pos(rPos, xIter.get(), false) && !pTreeView->is_selected(*xIter))
    {
        pTreeView->unselect_all();
        pTreeView->set_cursor(*xIter);
        pTreeView->select(*xIter);
    }
    FmtSelectHdl(*pTreeView);
}

/** Internal structure for the establishment of the hierarchical view */
namespace
{
class StyleTree_Impl;
}

typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;

namespace
{
class StyleTree_Impl
{
private:
    OUString aName;
    OUString aParent;
    StyleTreeArr_Impl pChildren;

public:
    bool HasParent() const { return !aParent.isEmpty(); }

    StyleTree_Impl(const OUString& rName, const OUString& rParent)
        : aName(rName)
        , aParent(rParent)
        , pChildren(0)
    {
    }

    const OUString& getName() const { return aName; }
    const OUString& getParent() const { return aParent; }
    StyleTreeArr_Impl& getChildren() { return pChildren; }
};
}

static void MakeTree_Impl(StyleTreeArr_Impl& rArr, const OUString& aUIName)
{
    const comphelper::string::NaturalStringSorter aSorter(
        ::comphelper::getProcessComponentContext(),
        Application::GetSettings().GetLanguageTag().getLocale());

    std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
    styleFinder.reserve(rArr.size());
    for (const auto& pEntry : rArr)
    {
        styleFinder.emplace(pEntry->getName(), pEntry.get());
    }

    // Arrange all under their Parents
    for (auto& pEntry : rArr)
    {
        if (!pEntry->HasParent())
            continue;
        auto it = styleFinder.find(pEntry->getParent());
        if (it != styleFinder.end())
        {
            StyleTree_Impl* pCmp = it->second;
            // Insert child entries sorted
            auto iPos = std::lower_bound(
                pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
                [&aSorter](std::unique_ptr<StyleTree_Impl> const& pEntry1,
                           std::unique_ptr<StyleTree_Impl> const& pEntry2) {
                    return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
                });
            pCmp->getChildren().insert(iPos, std::move(pEntry));
        }
    }

    // Only keep tree roots in rArr, child elements can be accessed through the hierarchy
    rArr.erase(
        std::remove_if(rArr.begin(), rArr.end(),
                       [](std::unique_ptr<StyleTree_Impl> const& pEntry) { return !pEntry; }),
        rArr.end());

    // tdf#91106 sort top level styles
    std::sort(rArr.begin(), rArr.end());
    std::sort(rArr.begin(), rArr.end(),
              [&aSorter, &aUIName](std::unique_ptr<StyleTree_Impl> const& pEntry1,
                                   std::unique_ptr<StyleTree_Impl> const& pEntry2) {
                  if (pEntry2->getName() == aUIName)
                      return false;
                  if (pEntry1->getName() == aUIName)
                      return true; // default always first
                  return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
              });
}

static bool IsExpanded_Impl(const std::vector<OUString>& rEntries, std::u16string_view rStr)
{
    for (const auto& rEntry : rEntries)
    {
        if (rEntry == rStr)
            return true;
    }
    return false;
}

static void FillBox_Impl(weld::TreeView& rBox, StyleTree_Impl* pEntry,
                         const std::vector<OUString>& rEntries, SfxStyleFamily eStyleFamily,
                         const weld::TreeIter* pParent)
{
    std::unique_ptr<weld::TreeIter> xResult = rBox.make_iterator();
    const OUString& rName = pEntry->getName();
    rBox.insert(pParent, -1, &rName, &rName, nullptr, nullptr, false, xResult.get());

    for (size_t i = 0; i < pEntry->getChildren().size(); ++i)
        FillBox_Impl(rBox, pEntry->getChildren()[i].get(), rEntries, eStyleFamily, xResult.get());
}

namespace SfxTemplate
{
// converts from SFX_STYLE_FAMILY Ids to 1-6
static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
{
    switch (nFamily)
    {
        case SfxStyleFamily::Char:
            return 1;
        case SfxStyleFamily::Para:
            return 2;
        case SfxStyleFamily::Frame:
            return 3;
        case SfxStyleFamily::Page:
            return 4;
        case SfxStyleFamily::Pseudo:
            return 5;
        case SfxStyleFamily::Table:
            return 6;
        default:
            return 0xffff;
    }
}
// converts from 1-6 to SFX_STYLE_FAMILY Ids
static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
{
    switch (nId)
    {
        case 1:
            return SfxStyleFamily::Char;
        case 2:
            return SfxStyleFamily::Para;
        case 3:
            return SfxStyleFamily::Frame;
        case 4:
            return SfxStyleFamily::Page;
        case 5:
            return SfxStyleFamily::Pseudo;
        case 6:
            return SfxStyleFamily::Table;
        default:
            return SfxStyleFamily::All;
    }
}
}

sal_uInt16 StyleList::StyleNrToInfoOffset(sal_uInt16 nId)
{
    const SfxStyleFamilyItem& rItem = m_xStyleFamilies->at(nId);
    return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily()) - 1;
}

// Helper function: Access to the current family item
const SfxStyleFamilyItem* StyleList::GetFamilyItem() const
{
    const size_t nCount = m_xStyleFamilies->size();
    for (size_t i = 0; i < nCount; ++i)
    {
        const SfxStyleFamilyItem& rItem = m_xStyleFamilies->at(i);
        sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
        if (nId == m_nActFamily)
            return &rItem;
    }
    return nullptr;
}

void StyleList::GetSelectedStyle() const
{
    const OUString aTemplName(GetSelectedEntry());
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
}

// Used to get the current selected entry in visible treeview
OUString StyleList::GetSelectedEntry() const
{
    OUString aRet;
    if (m_xTreeBox->get_visible())
        aRet = m_xTreeBox->get_selected_text();
    else
        aRet = m_xFmtLb->get_selected_text();
    return aRet;
}

/**
 * Is it safe to show the water-can / fill icon. If we've a
 * hierarchical widget - we have only single select, otherwise
 * we need to check if we have a multi-selection. We either have
 * a m_xTreeBox showing or an m_xFmtLb (which we hide when not shown)
 */
IMPL_LINK_NOARG(StyleList, IsSafeForWaterCan, void*, bool)
{
    if (m_xTreeBox->get_visible())
        return m_xTreeBox->get_selected_index() != -1;
    else
        return m_xFmtLb->count_selected_rows() == 1;
}

IMPL_LINK(StyleList, SetWaterCanState, const SfxBoolItem*, pItem, void)
{
    size_t nCount = m_xStyleFamilies->size();
    m_pBindings->EnterRegistrations();
    for (size_t n = 0; n < nCount; n++)
    {
        SfxControllerItem* pCItem = pBoundItems[n].get();
        bool bChecked = pItem && pItem->GetValue();
        if (pCItem->IsBound() == bChecked)
        {
            if (!bChecked)
                pCItem->ReBind();
            else
                pCItem->UnBind();
        }
    }
    m_pBindings->LeaveRegistrations();
}

IMPL_LINK(StyleList, FamilySelect, sal_uInt16, nEntry, void)
{
    m_nActFamily = nEntry;
    SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
    SfxUInt16Item const aItem(SID_STYLE_FAMILY,
                              static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
    pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
    m_pBindings->Invalidate(SID_STYLE_FAMILY);
    m_pBindings->Update(SID_STYLE_FAMILY);
    m_aUpdateFamily.Call(*this);
}

// It selects the style in treeview
// bIsCallBack is true for the selected style. For eg. if "Addressee" is selected in
// styles, bIsCallBack will be true for it.
void StyleList::SelectStyle(const OUString& rStr, bool bIsCallback)
{
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (!pItem)
        return;
    const SfxStyleFamily eFam = pItem->GetFamily();
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(rStr, eFam);
    if (pStyle)
    {
        bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
        m_pParentDialog->EnableEdit(bReadWrite);
        m_pParentDialog->EnableHide(bReadWrite && !pStyle->IsHidden() && !pStyle->IsUsed());
        m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden());
    }
    else
    {
        m_pParentDialog->EnableEdit(false);
        m_pParentDialog->EnableHide(false);
        m_pParentDialog->EnableShow(false);
    }

    if (!bIsCallback)
    {
        if (m_xTreeBox->get_visible())
        {
            if (!rStr.isEmpty())
            {
                std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
                bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
                while (bEntry)
                {
                    if (m_xTreeBox->get_text(*xEntry) == rStr)
                    {
                        m_xTreeBox->scroll_to_row(*xEntry);
                        m_xTreeBox->select(*xEntry);
                        break;
                    }
                    bEntry = m_xTreeBox->iter_next(*xEntry);
                }
            }
            else if (eFam == SfxStyleFamily::Pseudo)
            {
                std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
                if (m_xTreeBox->get_iter_first(*xEntry))
                {
                    m_xTreeBox->scroll_to_row(*xEntry);
                    m_xTreeBox->select(*xEntry);
                }
            }
            else
                m_xTreeBox->unselect_all();
        }
        else
        {
            bool bSelect = !rStr.isEmpty();
            if (bSelect)
            {
                std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
                bool bEntry = m_xFmtLb->get_iter_first(*xEntry);
                while (bEntry && m_xFmtLb->get_text(*xEntry) != rStr)
                    bEntry = m_xFmtLb->iter_next(*xEntry);
                if (!bEntry)
                    bSelect = false;
                else
                {
                    if (!m_xFmtLb->is_selected(*xEntry))
                    {
                        m_xFmtLb->unselect_all();
                        m_xFmtLb->scroll_to_row(*xEntry);
                        m_xFmtLb->select(*xEntry);
                    }
                }
            }

            if (!bSelect)
            {
                m_xFmtLb->unselect_all();
                m_pParentDialog->EnableEdit(false);
                m_pParentDialog->EnableHide(false);
                m_pParentDialog->EnableShow(false);
            }
        }
    }
}

static void MakeExpanded_Impl(const weld::TreeView& rBox, std::vector<OUString>& rEntries)
{
    std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator();
    if (rBox.get_iter_first(*xEntry))
    {
        do
        {
            if (rBox.get_row_expanded(*xEntry))
                rEntries.push_back(rBox.get_text(*xEntry));
        } while (rBox.iter_next(*xEntry));
    }
}

IMPL_LINK(StyleList, EnableTreeDrag, bool, m_bEnable, void)
{
    if (m_pStyleSheetPool)
    {
        const SfxStyleFamilyItem* pItem = GetFamilyItem();
        SfxStyleSheetBase* pStyle = pItem ? m_pStyleSheetPool->First(pItem->GetFamily()) : nullptr;
        m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bEnable;
    }
    m_bTreeDrag = m_bEnable;
    m_pParentDialog->SetEnableDrag(m_bTreeDrag);
}

// Fill the treeview

void StyleList::FillTreeBox(SfxStyleFamily eFam)
{
    assert(m_xTreeBox && "FillTreeBox() without treebox");
    if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
        return;

    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (!pItem)
        return;

    StyleTreeArr_Impl aArr;
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, SfxStyleSearchBits::AllVisible);

    m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bTreeDrag;

    while (pStyle)
    {
        StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent());
        aArr.emplace_back(pNew);
        pStyle = m_pStyleSheetPool->Next();
    }
    OUString aUIName = getDefaultStyleName(eFam);
    MakeTree_Impl(aArr, aUIName);
    std::vector<OUString> aEntries;
    MakeExpanded_Impl(*m_xTreeBox, aEntries);
    m_xTreeBox->freeze();
    m_xTreeBox->clear();
    const sal_uInt16 nCount = aArr.size();

    for (sal_uInt16 i = 0; i < nCount; ++i)
    {
        FillBox_Impl(*m_xTreeBox, aArr[i].get(), aEntries, eFam, nullptr);
        aArr[i].reset();
    }

    m_pParentDialog->EnableItem("watercan", false);

    SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();

    m_xTreeBox->thaw();

    std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
    bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
    if (bEntry && nCount)
        m_xTreeBox->expand_row(*xEntry);

    while (bEntry)
    {
        if (IsExpanded_Impl(aEntries, m_xTreeBox->get_text(*xEntry)))
            m_xTreeBox->expand_row(*xEntry);
        bEntry = m_xTreeBox->iter_next(*xEntry);
    }

    OUString aStyle;
    if (pState) // Select current entry
        aStyle = pState->GetStyleName();
    m_pParentDialog->SelectStyle(aStyle, false, *this);
    EnableDelete(nullptr);
}

static OUString lcl_GetStyleFamilyName(SfxStyleFamily nFamily)
{
    if (nFamily == SfxStyleFamily::Char)
        return "CharacterStyles";
    if (nFamily == SfxStyleFamily::Para)
        return "ParagraphStyles";
    if (nFamily == SfxStyleFamily::Page)
        return "PageStyles";
    if (nFamily == SfxStyleFamily::Table)
        return "TableStyles";
    if (nFamily == SfxStyleFamily::Pseudo)
        return "NumberingStyles";
    return OUString();
}

OUString StyleList::getDefaultStyleName(const SfxStyleFamily eFam)
{
    OUString sDefaultStyle;
    OUString aFamilyName = lcl_GetStyleFamilyName(eFam);
    if (aFamilyName == "TableStyles")
        sDefaultStyle = "Default Style";
    else if (aFamilyName == "NumberingStyles")
        sDefaultStyle = "No List";
    else
        sDefaultStyle = "Standard";
    uno::Reference<style::XStyleFamiliesSupplier> xModel(m_pCurObjShell->GetModel(),
                                                         uno::UNO_QUERY);
    OUString aUIName;
    try
    {
        uno::Reference<container::XNameAccess> xStyles;
        uno::Reference<container::XNameAccess> xCont = xModel->getStyleFamilies();
        xCont->getByName(aFamilyName) >>= xStyles;
        uno::Reference<beans::XPropertySet> xInfo;
        xStyles->getByName(sDefaultStyle) >>= xInfo;
        xInfo->getPropertyValue("DisplayName") >>= aUIName;
    }
    catch (const uno::Exception&)
    {
    }
    return aUIName;
}

SfxStyleFamily StyleList::GetActualFamily() const
{
    const SfxStyleFamilyItem* pFamilyItem = GetFamilyItem();
    if (!pFamilyItem || m_nActFamily == 0xffff)
        return SfxStyleFamily::Para;
    else
        return pFamilyItem->GetFamily();
}

IMPL_LINK_NOARG(StyleList, HasSelectedStyle, void*, bool)
{
    return m_xTreeBox->get_visible() ? m_xTreeBox->get_selected_index() != -1
                                     : m_xFmtLb->count_selected_rows() != 0;
}

IMPL_LINK_NOARG(StyleList, UpdateStyleDependents, void*, void)
{
    // Trigger Help PI. Only when the watercan is on
    if (m_nActFamily != 0xffff && m_pParentDialog->IsCheckedItem("watercan") &&
        // only if that region is allowed
        nullptr != m_pFamilyState[m_nActFamily - 1]
        && (m_xTreeBox || m_xFmtLb->count_selected_rows() <= 1))
    {
        m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, "", "", 0, *this);
        m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, GetSelectedEntry(), "",
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
    }
}

// Comes into action when the current style is changed
IMPL_LINK(StyleList, UpdateStyles, StyleFlags, nFlags, void)
{
    OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (!pItem)
    {
        // Is the case for the template catalog
        const size_t nFamilyCount = m_xStyleFamilies->size();
        size_t n;
        for (n = 0; n < nFamilyCount; n++)
            if (m_pFamilyState[StyleNrToInfoOffset(n)])
                break;
        if (n == nFamilyCount)
            // It happens sometimes, God knows why
            return;
        m_nAppFilter = m_pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
        m_pParentDialog->SetApplicationFilter(m_nAppFilter);
        m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1);
        pItem = GetFamilyItem();
    }

    const SfxStyleFamily eFam = pItem->GetFamily();

    SfxStyleSearchBits nFilter(m_nActFilter < pItem->GetFilterList().size()
                                   ? pItem->GetFilterList()[m_nActFilter].nFlags
                                   : SfxStyleSearchBits::Auto);
    if (nFilter == SfxStyleSearchBits::Auto) // automatic
        nFilter = m_nAppFilter;

    OSL_ENSURE(m_pStyleSheetPool, "no StyleSheetPool");
    if (!m_pStyleSheetPool)
        return;

    pItem = GetFamilyItem();

    m_aUpdateStyles.Call(nFlags);

    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, nFilter);

    std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
    bool bEntry = m_xFmtLb->get_iter_first(*xEntry);
    std::vector<OUString> aStrings;

    comphelper::string::NaturalStringSorter aSorter(
        ::comphelper::getProcessComponentContext(),
        Application::GetSettings().GetLanguageTag().getLocale());

    while (pStyle)
    {
        aStrings.push_back(pStyle->GetName());
        pStyle = m_pStyleSheetPool->Next();
    }
    OUString aUIName = getDefaultStyleName(eFam);

    // Paradoxically, with a list and non-Latin style names,
    // sorting twice is faster than sorting once.
    // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
    // Then the second sort needs to call its (much more expensive) comparator less often.
    std::sort(aStrings.begin(), aStrings.end());
    std::sort(aStrings.begin(), aStrings.end(),
              [&aSorter, &aUIName](const OUString& rLHS, const OUString& rRHS) {
                  if (rRHS == aUIName)
                      return false;
                  if (rLHS == aUIName)
                      return true; // default always first
                  return aSorter.compare(rLHS, rRHS) < 0;
              });

    size_t nCount = aStrings.size();
    size_t nPos = 0;
    while (nPos < nCount && bEntry && aStrings[nPos] == m_xFmtLb->get_text(*xEntry))
    {
        ++nPos;
        bEntry = m_xFmtLb->iter_next(*xEntry);
    }

    if (nPos < nCount || bEntry)
    {
        // Fills the display box
        m_xFmtLb->freeze();
        m_xFmtLb->clear();

        for (nPos = 0; nPos < nCount; ++nPos)
            m_xFmtLb->append(aStrings[nPos], aStrings[nPos]);

        m_xFmtLb->thaw();
    }
    // Selects the current style if any
    SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
    OUString aStyle;
    if (pState)
        aStyle = pState->GetStyleName();
    m_pParentDialog->SelectStyle(aStyle, false, *this);
    EnableDelete(nullptr);
}

void StyleList::SetFamilyState(sal_uInt16 nSlotId, const SfxTemplateItem* pItem)
{
    sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
    m_pFamilyState[nIdx].reset();
    if (pItem)
        m_pFamilyState[nIdx].reset(new SfxTemplateItem(*pItem));
    m_bUpdateFamily = true;
}

void StyleList::SetHierarchical()
{
    m_bHierarchical = true;
    const OUString aSelectEntry(GetSelectedEntry());
    m_xFmtLb->hide();
    FillTreeBox(GetActualFamily());
    m_pParentDialog->SelectStyle(aSelectEntry, false, *this);
    m_xTreeBox->show();
}

void StyleList::SetFilterControlsHandle()
{
    m_xTreeBox->hide();
    m_xFmtLb->show();
    m_bHierarchical = false;
}

// Handler for the New-Buttons
void StyleList::NewHdl()
{
    if (m_nActFamily == 0xffff
        || !(m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1))
        return;

    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    const SfxStyleFamily eFam = pItem->GetFamily();
    SfxStyleSearchBits nMask(SfxStyleSearchBits::Auto);
    if (m_nActFilter != 0xffff)
        nMask = pItem->GetFilterList()[m_nActFilter].nFlags;
    if (nMask == SfxStyleSearchBits::Auto) // automatic
        nMask = m_nAppFilter;

    m_pParentDialog->Execute_Impl(SID_STYLE_NEW, "", GetSelectedEntry(),
                                  static_cast<sal_uInt16>(eFam), *this, nMask);
}

// Handler for the edit-Buttons
void StyleList::EditHdl()
{
    if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
    {
        sal_uInt16 nFilter = m_nActFilter;
        OUString aTemplName(GetSelectedEntry());
        GetSelectedStyle(); // -Wall required??
        m_pParentDialog->Execute_Impl(SID_STYLE_EDIT, aTemplName, OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
                                      SfxStyleSearchBits::Auto, &nFilter);
    }
}

// Handler for the Delete-Buttons
void StyleList::DeleteHdl()
{
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
        return;

    bool bUsedStyle = false; // one of the selected styles are used in the document?

    std::vector<std::unique_ptr<weld::TreeIter>> aList;
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    const SfxStyleFamilyItem* pItem = GetFamilyItem();

    OUStringBuffer aMsg;
    aMsg.append(SfxResId(STR_DELETE_STYLE_USED) + SfxResId(STR_DELETE_STYLE));

    pTreeView->selected_foreach(
        [this, pTreeView, pItem, &aList, &bUsedStyle, &aMsg](weld::TreeIter& rEntry) {
            aList.emplace_back(pTreeView->make_iterator(&rEntry));
            // check the style is used or not
            const OUString aTemplName(pTreeView->get_text(rEntry));

            SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());

            if (pStyle->IsUsed()) // pStyle is in use in the document?
            {
                if (bUsedStyle) // add a separator for the second and later styles
                    aMsg.append(", ");
                aMsg.append(aTemplName);
                bUsedStyle = true;
            }

            return false;
        });

    bool aApproved = false;

    // we only want to show the dialog once and if we want to delete a style in use (UX-advice)
    if (bUsedStyle)
    {
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
            pTreeView, VclMessageType::Question, VclButtonsType::YesNo, aMsg.makeStringAndClear()));
        aApproved = xBox->run() == RET_YES;
    }

    // if there are no used styles selected or the user approved the changes
    if (bUsedStyle && !aApproved)
        return;

    for (auto const& elem : aList)
    {
        const OUString aTemplName(pTreeView->get_text(*elem));
        m_bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting
        m_pParentDialog->Execute_Impl(SID_STYLE_DELETE, aTemplName, OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);

        if (m_xTreeBox->get_visible())
        {
            weld::RemoveParentKeepChildren(*m_xTreeBox, *elem);
            m_bDontUpdate = false;
        }
    }
    m_bDontUpdate = false; // if everything is deleted set m_bDontUpdate back to false
    UpdateStyles(StyleFlags::UpdateFamilyList); // and force-update the list
}

void StyleList::HideHdl()
{
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
        return;

    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
        OUString aTemplName = pTreeView->get_text(rEntry);

        m_pParentDialog->Execute_Impl(SID_STYLE_HIDE, aTemplName, OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);

        return false;
    });
}

void StyleList::ShowHdl()
{
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
        return;

    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
        OUString aTemplName = pTreeView->get_text(rEntry);

        m_pParentDialog->Execute_Impl(SID_STYLE_SHOW, aTemplName, OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);

        return false;
    });
}

IMPL_LINK_NOARG(StyleList, EnableDelete, void*, void)
{
    bool bEnableDelete(false);
    if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
    {
        OSL_ENSURE(m_pStyleSheetPool, "No StyleSheetPool");
        const OUString aTemplName(GetSelectedEntry());
        const SfxStyleFamilyItem* pItem = GetFamilyItem();
        const SfxStyleFamily eFam = pItem->GetFamily();
        SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
        if (pItem->GetFilterList().size() > m_nActFilter)
            nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
        if (nFilter == SfxStyleSearchBits::Auto) // automatic
            nFilter = m_nAppFilter;
        const SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(
            aTemplName, eFam, m_xTreeBox->get_visible() ? SfxStyleSearchBits::All : nFilter);

        OSL_ENSURE(pStyle, "Style not found");
        if (pStyle && pStyle->IsUserDefined())
        {
            if (pStyle->HasClearParentSupport() || !pStyle->IsUsed())
            {
                bEnableDelete = true;
            }
            else if (pStyle->GetFamily() == SfxStyleFamily::Page)
            {
                // Hack to allow Calc page styles to be deleted,
                // remove when IsUsed is fixed for Calc page styles.
                SfxViewFrame* pFrame = m_pCurObjShell->GetFrame();
                if (pFrame)
                {
                    uno::Reference<frame::XFrame> xFrame = pFrame->GetFrame().GetFrameInterface();
                    if (vcl::CommandInfoProvider::GetModuleIdentifier(xFrame)
                        == "com.sun.star.sheet.SpreadsheetDocument")
                    {
                        bEnableDelete = true;
                    }
                }
            }
        }
    }
    m_pParentDialog->EnableDel(bEnableDelete);
}

IMPL_LINK_NOARG(StyleList, Clear, void*, void)
{
    m_xStyleFamilies.reset();
    for (auto& i : m_pFamilyState)
        i.reset();
    m_pCurObjShell = nullptr;
    for (auto& i : pBoundItems)
        i.reset();
}

void StyleList::ShowMenu(const CommandEvent& rCEvt)
{
    CreateContextMenu();
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    OString sCommand(
        mxMenu->popup_at_rect(pTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1))));
    MenuSelect(sCommand);
}

void StyleList::MenuSelect(const OString& rIdent)
{
    sLastItemIdent = rIdent;
    if (sLastItemIdent.isEmpty())
        return;
    Application::PostUserEvent(LINK(this, StyleList, MenuSelectAsyncHdl)); /***check this****/
}

void StyleList::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
{
    const SfxHintId nId = rHint.GetId();

    switch (nId)
    {
        case SfxHintId::UpdateDone:
        {
            SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
            SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
            if (m_pParentDialog->GetNotifyUpdate()
                && (!m_pParentDialog->IsCheckedItem("watercan")
                    || (pDocShell && pDocShell->GetStyleSheetPool() != m_pStyleSheetPool)))
            {
                m_pParentDialog->SetNotifyupdate(false);
                Update();
            }
            else if (m_bUpdateFamily)
            {
                m_aUpdateFamily.Call(*this);
            }

            if (m_pStyleSheetPool)
            {
                OUString aStr = GetSelectedEntry();
                if (!aStr.isEmpty())
                {
                    const SfxStyleFamilyItem* pItem = GetFamilyItem();
                    if (!pItem)
                        break;
                    const SfxStyleFamily eFam = pItem->GetFamily();
                    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aStr, eFam);
                    if (pStyle)
                    {
                        bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
                        m_pParentDialog->EnableEdit(bReadWrite);
                        m_pParentDialog->EnableHide(bReadWrite && !pStyle->IsUsed()
                                                    && !pStyle->IsHidden());
                        m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden());
                    }
                    else
                    {
                        m_pParentDialog->EnableEdit(false);
                        m_pParentDialog->EnableHide(false);
                        m_pParentDialog->EnableShow(false);
                    }
                }
            }
            break;
        }

        // Necessary if switching between documents and in both documents
        // the same template is used. Do not immediately call Update_Impl,
        // for the case that one of the documents is an internal InPlaceObject!
        case SfxHintId::DocChanged:
            m_pParentDialog->SetNotifyupdate(true);
            break;
        case SfxHintId::Dying:
        {
            EndListening(*m_pStyleSheetPool);
            m_pStyleSheetPool = nullptr;
            break;
        }
        default:
            break;
    }

    // Do not set timer when the stylesheet pool is in the box, because it is
    // possible that a new one is registered after the timer is up -
    // works bad in UpdateStyles_Impl ()!

    if (!m_bDontUpdate && nId != SfxHintId::Dying
        && (dynamic_cast<const SfxStyleSheetPoolHint*>(&rHint)
            || dynamic_cast<const SfxStyleSheetHint*>(&rHint)
            || dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint)
            || nId == SfxHintId::StyleSheetModified))
    {
        if (!pIdle)
        {
            pIdle.reset(new Idle("SfxCommonTemplate"));
            pIdle->SetPriority(TaskPriority::LOWEST);
            pIdle->SetInvokeHandler(LINK(this, StyleList, TimeOut));
        }
        pIdle->Start();
    }
}

IMPL_LINK_NOARG(StyleList, TimeOut, Timer*, void)
{
    if (!m_bDontUpdate)
    {
        m_bDontUpdate = true;
        if (!m_xTreeBox->get_visible())
            UpdateStyles(StyleFlags::UpdateFamilyList);
        else
        {
            FillTreeBox(GetActualFamily());
            SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
            if (pState)
            {
                m_pParentDialog->SelectStyle(pState->GetStyleName(), false, *this);
                EnableDelete(nullptr);
            }
        }
        m_bDontUpdate = false;
        pIdle.reset();
    }
    else
        pIdle->Start();
}

IMPL_LINK_NOARG(StyleList, MenuSelectAsyncHdl, void*, void)
{
    if (sLastItemIdent == "new")
        NewHdl();
    else if (sLastItemIdent == "edit")
        EditHdl();
    else if (sLastItemIdent == "delete")
        DeleteHdl();
    else if (sLastItemIdent == "hide")
        HideHdl();
    else if (sLastItemIdent == "show")
        ShowHdl();
}

// Double-click on a style sheet in the ListBox is applied.
IMPL_LINK(StyleList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
{
    rUnsetDragIcon = false;
    // Allow normal processing. only if bAllowReParentDrop is true
    return !m_bAllowReParentDrop;
}

IMPL_LINK(StyleList, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
{
    bool bRet = false;
    const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
    if (m_bCanDel && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_DELETE)
    {
        DeleteHdl();
        bRet = true;
    }
    return bRet;
}

IMPL_LINK(StyleList, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
{
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    const OUString aTemplName(pTreeView->get_text(rEntry));
    OUString sQuickHelpText(aTemplName);

    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (!pItem)
        return sQuickHelpText;
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());

    if (pStyle && pStyle->IsUsed()) // pStyle is in use in the document?
    {
        OUString sUsedBy;
        if (pStyle->GetFamily() == SfxStyleFamily::Pseudo)
            sUsedBy = pStyle->GetUsedBy();

        if (!sUsedBy.isEmpty())
        {
            const sal_Int32 nMaxLen = 80;
            if (sUsedBy.getLength() > nMaxLen)
            {
                sUsedBy = OUString::Concat(sUsedBy.subView(0, nMaxLen)) + "...";
            }

            OUString aMessage = SfxResId(STR_STYLEUSEDBY);
            aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy);
            sQuickHelpText = aTemplName + " " + aMessage;
        }
    }

    return sQuickHelpText;
}

IMPL_LINK(StyleList, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
{
    vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
    const ::tools::Rectangle& rRect = std::get<1>(aPayload);
    ::tools::Rectangle aRect(
        rRect.TopLeft(),
        Size(rRenderContext.GetOutputSize().Width() - rRect.Left(), rRect.GetHeight()));
    bool bSelected = std::get<2>(aPayload);
    const OUString& rId = std::get<3>(aPayload);

    rRenderContext.Push(PushFlags::TEXTCOLOR);
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    if (bSelected)
        rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
    else
        rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());

    bool bSuccess = false;

    SfxObjectShell* pShell = SfxObjectShell::Current();
    sfx2::StyleManager* pStyleManager = pShell ? pShell->GetStyleManager() : nullptr;

    if (pStyleManager)
    {
        const SfxStyleFamilyItem* pItem = GetFamilyItem();
        SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(rId, pItem->GetFamily());

        if (pStyleSheet)
        {
            rRenderContext.Push(PushFlags::ALL);
            sal_Int32 nSize = aRect.GetHeight();
            std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
                pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
            bSuccess = pStylePreviewRenderer->recalculate() && pStylePreviewRenderer->render(aRect);
            rRenderContext.Pop();
        }
    }

    if (!bSuccess)
        rRenderContext.DrawText(aRect, rId, DrawTextFlags::Left | DrawTextFlags::VCenter);

    rRenderContext.Pop();
}

// Selection of a template during the Watercan-Status
IMPL_LINK(StyleList, FmtSelectHdl, weld::TreeView&, rListBox, void)
{
    std::unique_ptr<weld::TreeIter> xHdlEntry = rListBox.make_iterator();
    if (!rListBox.get_cursor(xHdlEntry.get()))
        return;

    if (rListBox.is_selected(*xHdlEntry))
        m_aUpdateStyleDependents.Call(nullptr);

    m_pParentDialog->SelectStyle(rListBox.get_text(*xHdlEntry), true, *this);
}

IMPL_LINK_NOARG(StyleList, TreeListApplyHdl, weld::TreeView&, bool)
{
    // only if that region is allowed
    if (m_nActFamily != 0xffff && nullptr != m_pFamilyState[m_nActFamily - 1]
        && !GetSelectedEntry().isEmpty())
    {
        m_pParentDialog->Execute_Impl(SID_STYLE_APPLY, GetSelectedEntry(), OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
                                      SfxStyleSearchBits::Auto, nullptr, &m_nModifier);
    }
    // After selecting a focused item if possible again on the app window
    if (dynamic_cast<const SfxTemplateDialog_Impl*>(m_pParentDialog) != nullptr)
    {
        SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
        SfxViewShell* pVu = pViewFrame->GetViewShell();
        vcl::Window* pAppWin = pVu ? pVu->GetWindow() : nullptr;
        if (pAppWin)
            pAppWin->GrabFocus();
    }

    return true;
}

IMPL_LINK(StyleList, MousePressHdl, const MouseEvent&, rMEvt, bool)
{
    m_nModifier = rMEvt.GetModifier();
    return false;
}

// Notice from SfxBindings that the update is completed. Pushes out the update
// of the display.
void StyleList::Update()
{
    bool bDocChanged = false;
    SfxStyleSheetBasePool* pNewPool = nullptr;
    SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
    SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
    if (pDocShell)
        pNewPool = pDocShell->GetStyleSheetPool();

    if (pNewPool != m_pStyleSheetPool && pDocShell)
    {
        SfxModule* pNewModule = pDocShell->GetModule();
        if (pNewModule && pNewModule != m_Module)
        {
            m_aClearResource.Call(nullptr);
            m_aReadResource.Call(*this);
        }
        if (m_pStyleSheetPool)
        {
            EndListening(*m_pStyleSheetPool);
            m_pStyleSheetPool = nullptr;
        }

        if (pNewPool)
        {
            StartListening(*pNewPool);
            m_pStyleSheetPool = pNewPool;
            bDocChanged = true;
        }
    }

    if (m_bUpdateFamily)
        m_aUpdateFamily.Call(*this);

    sal_uInt16 i;
    for (i = 0; i < MAX_FAMILIES; ++i)
        if (m_pFamilyState[i])
            break;
    if (i == MAX_FAMILIES || !pNewPool)
        // nothing is allowed
        return;

    SfxTemplateItem* pItem = nullptr;
    // current region not within the allowed region or default
    if (m_nActFamily == 0xffff || nullptr == (pItem = m_pFamilyState[m_nActFamily - 1].get()))
    {
        m_pParentDialog->CheckItem(OString::number(m_nActFamily), false);
        const size_t nFamilyCount = m_xStyleFamilies->size();
        size_t n;
        for (n = 0; n < nFamilyCount; n++)
            if (m_pFamilyState[StyleNrToInfoOffset(n)])
                break;

        std::unique_ptr<SfxTemplateItem>& pNewItem = m_pFamilyState[StyleNrToInfoOffset(n)];
        m_nAppFilter = pNewItem->GetValue();
        m_pParentDialog->SetApplicationFilter(m_nAppFilter);
        m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1);
        pItem = pNewItem.get();
    }
    else if (bDocChanged)
    {
        // other DocShell -> all new
        m_pParentDialog->CheckItem(OString::number(m_nActFamily));
        m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(pDocShell));
        m_pParentDialog->SetFilterByIndex(m_nActFilter);
        if (0xffff == m_nActFilter)
        {
            m_nActFilter = pDocShell->GetAutoStyleFilterIndex();
            m_pParentDialog->SetFilterByIndex(m_nActFilter);
        }

        m_nAppFilter = pItem->GetValue();
        m_pParentDialog->SetApplicationFilter(m_nAppFilter);
        if (!m_xTreeBox->get_visible())
        {
            UpdateStyles(StyleFlags::UpdateFamilyList);
        }
        else
            FillTreeBox(GetActualFamily());
    }
    else
    {
        // other filters for automatic
        m_pParentDialog->CheckItem(OString::number(m_nActFamily));
        const SfxStyleFamilyItem* pStyleItem = GetFamilyItem();
        if (pStyleItem
            && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[m_nActFilter].nFlags
            && m_nAppFilter != pItem->GetValue())
        {
            m_nAppFilter = pItem->GetValue();
            m_pParentDialog->SetApplicationFilter(m_nAppFilter);
            if (!m_xTreeBox->get_visible())
                UpdateStyles(StyleFlags::UpdateFamilyList);
            else
                FillTreeBox(GetActualFamily());
        }
        else
        {
            m_nAppFilter = pItem->GetValue();
            m_pParentDialog->SetApplicationFilter(m_nAppFilter);
        }
    }
    const OUString aStyle(pItem->GetStyleName());
    m_pParentDialog->SelectStyle(aStyle, false, *this);
    EnableDelete(nullptr);
    m_pParentDialog->EnableNew(m_bCanNew);
}

void StyleList::EnablePreview(bool bCustomPreview)
{
    m_xFmtLb->clear();
    m_xFmtLb->set_column_custom_renderer(0, bCustomPreview);
    m_xTreeBox->clear();
    m_xTreeBox->set_column_custom_renderer(0, bCustomPreview);
}

const SfxStyleFamilyItem& StyleList::GetFamilyItemByIndex(size_t i) const
{
    return m_xStyleFamilies->at(i);
}

IMPL_STATIC_LINK(StyleList, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
{
    vcl::RenderContext& rRenderContext = aPayload.first;
    return Size(42, 32 * rRenderContext.GetDPIScaleFactor());
}

IMPL_LINK(StyleList, PopupFlatMenuHdl, const CommandEvent&, rCEvt, bool)
{
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
        return false;

    PrepareMenu(rCEvt.GetMousePosPixel());

    if (m_xFmtLb->count_selected_rows() <= 0)
    {
        m_pParentDialog->EnableEdit(false);
        m_pParentDialog->EnableDel(false);
    }

    ShowMenu(rCEvt);

    return true;
}

IMPL_LINK(StyleList, PopupTreeMenuHdl, const CommandEvent&, rCEvt, bool)
{
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
        return false;

    PrepareMenu(rCEvt.GetMousePosPixel());

    ShowMenu(rCEvt);

    return true;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/dialog/templdlg.cxx b/sfx2/source/dialog/templdlg.cxx
index 8951cfb..ae0d646 100644
--- a/sfx2/source/dialog/templdlg.cxx
+++ b/sfx2/source/dialog/templdlg.cxx
@@ -110,258 +110,16 @@ private:
    DeletionWatcher *const m_pPrevious; /// let's add more epicycles!
};

/** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
    create a style out of the current selection.
*/
sal_Int8 SfxCommonTemplateDialog_Impl::AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
{
    if (rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR))
    {
        // special case: page styles are allowed to create new styles by example
        // but not allowed to be created by drag and drop
        if (GetActualFamily() == SfxStyleFamily::Page || bNewByExampleDisabled)
            return DND_ACTION_NONE;
        else
            return DND_ACTION_COPY;
    }

    // to enable the autoscroll when we're close to the edges
    weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
    pTreeView->get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
    return DND_ACTION_MOVE;
}

sal_Int8 SfxCommonTemplateDialog_Impl::ExecuteDrop(const ExecuteDropEvent& rEvt)
{
    // handle drop of content into the treeview to create a new style
    SfxObjectShell* pDocShell = GetObjectShell();
    if (pDocShell)
    {
        TransferableDataHelper aHelper(rEvt.maDropEvent.Transferable);
        sal_uInt32 nFormatCount = aHelper.GetFormatCount();

        sal_Int8 nRet = DND_ACTION_NONE;

        bool bFormatFound = false;

        for ( sal_uInt32 i = 0; i < nFormatCount; ++i )
        {
            SotClipboardFormatId nId = aHelper.GetFormat(i);
            TransferableObjectDescriptor aDesc;

            if ( aHelper.GetTransferableObjectDescriptor( nId, aDesc ) )
            {
                if ( aDesc.maClassName == pDocShell->GetFactory().GetClassId() )
                {
                    Application::PostUserEvent(LINK(this, SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop));

                    bFormatFound = true;
                    nRet =  rEvt.mnAction;
                    break;
                }
            }
        }

        if (bFormatFound)
            return nRet;
    }

    if (!mxTreeBox->get_visible())
        return DND_ACTION_NONE;

    if (!bAllowReParentDrop)
        return DND_ACTION_NONE;

    // otherwise if we're dragging with the treeview to set a new parent of the dragged style
    weld::TreeView* pSource = mxTreeBox->get_drag_source();
    // only dragging within the same widget allowed
    if (!pSource || pSource != mxTreeBox.get())
        return DND_ACTION_NONE;

    std::unique_ptr<weld::TreeIter> xSource(mxTreeBox->make_iterator());
    if (!mxTreeBox->get_selected(xSource.get()))
        return DND_ACTION_NONE;

    std::unique_ptr<weld::TreeIter> xTarget(mxTreeBox->make_iterator());
    if (!mxTreeBox->get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
    {
        // if nothing under the mouse, use the last row
        int nChildren = mxTreeBox->n_children();
        if (!nChildren)
            return DND_ACTION_NONE;
        if (!mxTreeBox->get_iter_first(*xTarget) || !mxTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
            return DND_ACTION_NONE;
        while (mxTreeBox->get_row_expanded(*xTarget))
        {
            nChildren = mxTreeBox->iter_n_children(*xTarget);
            if (!mxTreeBox->iter_children(*xTarget) || !mxTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
                return DND_ACTION_NONE;
        }
    }
    OUString aTargetStyle = mxTreeBox->get_text(*xTarget);
    DropHdl(mxTreeBox->get_text(*xSource), aTargetStyle);
    mxTreeBox->unset_drag_dest_row();
    FillTreeBox();
    SelectStyle(aTargetStyle, false);
    m_aStyleListExecuteDrop.Call(rEvt);
    return DND_ACTION_NONE;
}

IMPL_LINK(SfxCommonTemplateDialog_Impl, DragBeginHdl, bool&, rUnsetDragIcon, bool)
{
    rUnsetDragIcon = false;
    // Allow normal processing. only if bAllowReParentDrop is true
    return !bAllowReParentDrop;
}

IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop, void*, void)
{
    ActionSelect("new");
}

IMPL_LINK(SfxCommonTemplateDialog_Impl, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
{
    bool bRet = false;
    const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
    if (bCanDel && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_DELETE)
    {
        DeleteHdl();
        bRet =  true;
    }
    return bRet;
}

IMPL_LINK(SfxCommonTemplateDialog_Impl, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
{
    weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
    const OUString aTemplName(pTreeView->get_text(rEntry));
    OUString sQuickHelpText(aTemplName);

    const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
    if (!pItem)
        return sQuickHelpText;
    SfxStyleSheetBase* pStyle = pStyleSheetPool->Find(aTemplName, pItem->GetFamily());

    if (pStyle && pStyle->IsUsed())  // pStyle is in use in the document?
    {
        OUString sUsedBy;
        if (pStyle->GetFamily() == SfxStyleFamily::Pseudo)
            sUsedBy = pStyle->GetUsedBy();

        if (!sUsedBy.isEmpty())
        {
            const sal_Int32 nMaxLen = 80;
            if (sUsedBy.getLength() > nMaxLen)
            {
                sUsedBy = OUString::Concat(sUsedBy.subView(0, nMaxLen)) + "...";
            }

            OUString aMessage = SfxResId(STR_STYLEUSEDBY);
            aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy);
            sQuickHelpText = aTemplName + " " + aMessage;
        }
    }

    return sQuickHelpText;
}

IMPL_STATIC_LINK(SfxCommonTemplateDialog_Impl, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
{
    vcl::RenderContext& rRenderContext = aPayload.first;
    return Size(42, 32 * rRenderContext.GetDPIScaleFactor());
}

IMPL_LINK(SfxCommonTemplateDialog_Impl, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
{
    vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
    const ::tools::Rectangle& rRect = std::get<1>(aPayload);
    ::tools::Rectangle aRect(rRect.TopLeft(), Size(rRenderContext.GetOutputSize().Width() - rRect.Left(), rRect.GetHeight()));
    bool bSelected = std::get<2>(aPayload);
    const OUString& rId = std::get<3>(aPayload);

    rRenderContext.Push(PushFlags::TEXTCOLOR);
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    if (bSelected)
        rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
    else
        rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());

    bool bSuccess = false;

    SfxObjectShell* pShell = SfxObjectShell::Current();
    sfx2::StyleManager* pStyleManager = pShell ? pShell->GetStyleManager(): nullptr;

    if (pStyleManager)
    {
        const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
        SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(rId, pItem->GetFamily());

        if (pStyleSheet)
        {
            rRenderContext.Push(PushFlags::ALL);
            sal_Int32 nSize = aRect.GetHeight();
            std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
                pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
            bSuccess = pStylePreviewRenderer->recalculate() && pStylePreviewRenderer->render(aRect);
            rRenderContext.Pop();
        }
    }

    if (!bSuccess)
        rRenderContext.DrawText(aRect, rId, DrawTextFlags::Left | DrawTextFlags::VCenter);

    rRenderContext.Pop();
}

IMPL_LINK(SfxCommonTemplateDialog_Impl, PopupFlatMenuHdl, const CommandEvent&, rCEvt, bool)
{
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
        return false;

    PrepareMenu(rCEvt.GetMousePosPixel());

    if (mxFmtLb->count_selected_rows() <= 0)
    {
        EnableEdit(false);
        EnableDel(false);
    }

    ShowMenu(rCEvt);

    return true;
}

void SfxCommonTemplateDialog_Impl::PrepareMenu(const Point& rPos)
{
    weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
    std::unique_ptr<weld::TreeIter> xIter(pTreeView->make_iterator());
    if (pTreeView->get_dest_row_at_pos(rPos, xIter.get(), false) && !pTreeView->is_selected(*xIter))
    {
        pTreeView->unselect_all();
        pTreeView->set_cursor(*xIter);
        pTreeView->select(*xIter);
        FmtSelectHdl(*pTreeView);
    }
}

void SfxCommonTemplateDialog_Impl::ShowMenu(const CommandEvent& rCEvt)
{
    CreateContextMenu();

    weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
    OString sCommand(mxMenu->popup_at_rect(pTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
    MenuSelect(sCommand);
}

IMPL_LINK(SfxCommonTemplateDialog_Impl, PopupTreeMenuHdl, const CommandEvent&, rCEvt, bool)
{
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
        return false;

    PrepareMenu(rCEvt.GetMousePosPixel());

    ShowMenu(rCEvt);

    return true;
    ActionSelect("new", m_aStyleList);
}

SfxTemplatePanelControl::SfxTemplatePanelControl(SfxBindings* pBindings, weld::Widget* pParent)
@@ -375,119 +133,6 @@ SfxTemplatePanelControl::~SfxTemplatePanelControl()
{
}

static void MakeExpanded_Impl(const weld::TreeView& rBox, std::vector<OUString>& rEntries)
{
    std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator();
    if (rBox.get_iter_first(*xEntry))
    {
        do
        {
            if (rBox.get_row_expanded(*xEntry))
                rEntries.push_back(rBox.get_text(*xEntry));
        } while (rBox.iter_next(*xEntry));
    }
}

/** Internal structure for the establishment of the hierarchical view */
namespace {

class StyleTree_Impl;

}

typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;

namespace {

class StyleTree_Impl
{
private:
    OUString aName;
    OUString aParent;
    StyleTreeArr_Impl pChildren;

public:
    bool HasParent() const { return !aParent.isEmpty(); }

    StyleTree_Impl(const OUString &rName, const OUString &rParent):
        aName(rName), aParent(rParent), pChildren(0) {}

    const OUString& getName() const { return aName; }
    const OUString& getParent() const { return aParent; }
    StyleTreeArr_Impl& getChildren() { return pChildren; }
};

}

static void MakeTree_Impl(StyleTreeArr_Impl& rArr, const OUString& aUIName)
{
    const comphelper::string::NaturalStringSorter aSorter(
        ::comphelper::getProcessComponentContext(),
        Application::GetSettings().GetLanguageTag().getLocale());

    std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
    styleFinder.reserve(rArr.size());
    for (const auto& pEntry : rArr)
    {
        styleFinder.emplace(pEntry->getName(), pEntry.get());
    }

    // Arrange all under their Parents
    for (auto& pEntry : rArr)
    {
        if (!pEntry->HasParent())
            continue;
        auto it = styleFinder.find(pEntry->getParent());
        if (it != styleFinder.end())
        {
            StyleTree_Impl* pCmp = it->second;
            // Insert child entries sorted
            auto iPos = std::lower_bound(pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
                [&aSorter](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) { return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0; });
            pCmp->getChildren().insert(iPos, std::move(pEntry));
        }
    }

    // Only keep tree roots in rArr, child elements can be accessed through the hierarchy
    rArr.erase(std::remove_if(rArr.begin(), rArr.end(), [](std::unique_ptr<StyleTree_Impl> const & pEntry) { return !pEntry; }), rArr.end());

    // tdf#91106 sort top level styles
    std::sort(rArr.begin(), rArr.end());
    std::sort(rArr.begin(), rArr.end(),
        [&aSorter, &aUIName](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) {
            if (pEntry2->getName() == aUIName)
                return false;
            if (pEntry1->getName() == aUIName)
                return true; // default always first
            return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
        });
}

static bool IsExpanded_Impl( const std::vector<OUString>& rEntries,
                             std::u16string_view rStr)
{
    for (const auto & rEntry : rEntries)
    {
        if (rEntry == rStr)
            return true;
    }
    return false;
}

static void FillBox_Impl(weld::TreeView& rBox,
                         StyleTree_Impl* pEntry,
                         const std::vector<OUString>& rEntries,
                         SfxStyleFamily eStyleFamily,
                         const weld::TreeIter* pParent)
{
    std::unique_ptr<weld::TreeIter> xResult = rBox.make_iterator();
    const OUString& rName = pEntry->getName();
    rBox.insert(pParent, -1, &rName, &rName, nullptr, nullptr, false, xResult.get());

    for (size_t i = 0; i < pEntry->getChildren().size(); ++i)
        FillBox_Impl(rBox, pEntry->getChildren()[i].get(), rEntries, eStyleFamily, xResult.get());
}

namespace SfxTemplate
{
    // converts from SFX_STYLE_FAMILY Ids to 1-6
@@ -504,21 +149,48 @@ namespace SfxTemplate
            default:                     return 0xffff;
        }
    }
}

    // converts from 1-6 to SFX_STYLE_FAMILY Ids
    static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
    {
        switch (nId)
        {
            case 1: return SfxStyleFamily::Char;
            case 2: return SfxStyleFamily::Para;
            case 3: return SfxStyleFamily::Frame;
            case 4: return SfxStyleFamily::Page;
            case 5: return SfxStyleFamily::Pseudo;
            case 6: return SfxStyleFamily::Table;
            default: return SfxStyleFamily::All;
        }
    }
void SfxCommonTemplateDialog_Impl::connect_stylelist_execute_drop(
    const Link<const ExecuteDropEvent&, sal_Int8>& rLink)
{
    m_aStyleListExecuteDrop = rLink;
}

void SfxCommonTemplateDialog_Impl::connect_stylelist_has_selected_style(const Link<void*, bool>& rLink)
{
    m_aStyleListHasSelectedStyle = rLink;
}

void SfxCommonTemplateDialog_Impl::connect_stylelist_update_style_dependents(const Link<void*, void>& rLink)
{
    m_aStyleListUpdateStyleDependents = rLink;
}

void SfxCommonTemplateDialog_Impl::connect_stylelist_enable_tree_drag(const Link<bool, void> rLink)
{
    m_aStyleListEnableTreeDrag = rLink;
}

void SfxCommonTemplateDialog_Impl::connect_stylelist_filter_select(Link<sal_uInt16, void> rLink)
{
    m_aStyleListFilterSelect = rLink;
}

void SfxCommonTemplateDialog_Impl::connect_stylelist_enable_delete(const Link<void*, void> rLink)
{
    m_aStyleListEnableDelete = rLink;
}

void SfxCommonTemplateDialog_Impl::connect_stylelist_set_water_can_state(
    const Link<const SfxBoolItem*, void> rLink)
{
    m_aStyleListSetWaterCanState = rLink;
}

void SfxCommonTemplateDialog_Impl::connect_family_select(const Link<sal_uInt16, void> rLink)
{
    m_aStyleListFamilySelect = rLink;
}

// Constructor
@@ -527,49 +199,27 @@ SfxCommonTemplateDialog_Impl::SfxCommonTemplateDialog_Impl(SfxBindings* pB, weld
    : pBindings(pB)
    , mpContainer(pC)
    , pModule(nullptr)
    , pStyleSheetPool(nullptr)
    , pCurObjShell(nullptr)
    , xModuleManager(frame::ModuleManager::create(::comphelper::getProcessComponentContext()))
    , m_pDeletionWatcher(nullptr)
    , mxFmtLb(pBuilder->weld_tree_view("flatview"))
    , mxTreeBox(pBuilder->weld_tree_view("treeview"))
    , m_aStyleList(pBuilder, mxStyleFamilies, pB, this, pModule, pC, "treeview", "flatview")
    , mxPreviewCheckbox(pBuilder->weld_check_button("showpreview"))
    , mxFilterLb(pBuilder->weld_combo_box("filter"))

    , nActFamily(0xffff)
    , nActFilter(0)
    , nAppFilter(SfxStyleSearchBits::Auto)

    , m_nModifier(0)
    , bDontUpdate(false)
    , bIsWater(false)
    , bUpdate(false)
    , bUpdateFamily(false)
    , bCanEdit(false)
    , bCanDel(false)
    , bCanNew(true)
    , bCanHide(true)
    , bCanShow(false)
    , bWaterDisabled(false)
    , bNewByExampleDisabled(false)
    , bUpdateByExampleDisabled(false)
    , bTreeDrag(true)
    , bAllowReParentDrop(false)
    , bHierarchical(false)
    , m_bWantHierarchical(false)
    , bBindingUpdate(true)
{
    mxFmtLb->set_help_id(HID_TEMPLATE_FMT);
    mxFilterLb->set_help_id(HID_TEMPLATE_FILTER);
    mxPreviewCheckbox->set_active(officecfg::Office::Common::StylesAndFormatting::Preview::get());
}

sal_uInt16 SfxCommonTemplateDialog_Impl::StyleNrToInfoOffset(sal_uInt16 nId)
{
    const SfxStyleFamilyItem& rItem = mxStyleFamilies->at( nId );
    return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily())-1;
}

void SfxTemplateDialog_Impl::EnableEdit(bool bEnable)
{
    SfxCommonTemplateDialog_Impl::EnableEdit( bEnable );
@@ -577,79 +227,10 @@ void SfxTemplateDialog_Impl::EnableEdit(bool bEnable)
        EnableItem("update", bEnable);
}

void SfxCommonTemplateDialog_Impl::ReadResource()
IMPL_LINK(SfxCommonTemplateDialog_Impl, ReadResource_Hdl, StyleList&, rStyleList, void)
{
    // Read global user resource
    for (auto & i : pFamilyState)
        i.reset();

    SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
    pCurObjShell = pViewFrame->GetObjectShell();
    pModule = pCurObjShell ? pCurObjShell->GetModule() : nullptr;
    if (pModule)
        mxStyleFamilies = pModule->CreateStyleFamilies();
    if (!mxStyleFamilies)
        mxStyleFamilies.emplace();

    nActFilter = 0xffff;
    if (pCurObjShell)
    {
        nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pCurObjShell ) );
        if ( 0xffff == nActFilter )
            nActFilter = pCurObjShell->GetAutoStyleFilterIndex();
    }

    // Paste in the toolbox
    // reverse order, since always inserted at the head
    size_t nCount = mxStyleFamilies->size();

    pBindings->ENTERREGISTRATIONS();

    size_t i;
    for (i = 0; i < nCount; ++i)
    {
        sal_uInt16 nSlot = 0;
        switch (mxStyleFamilies->at(i).GetFamily())
        {
            case SfxStyleFamily::Char:
                nSlot = SID_STYLE_FAMILY1; break;
            case SfxStyleFamily::Para:
                nSlot = SID_STYLE_FAMILY2; break;
            case SfxStyleFamily::Frame:
                nSlot = SID_STYLE_FAMILY3; break;
            case SfxStyleFamily::Page:
                nSlot = SID_STYLE_FAMILY4; break;
            case SfxStyleFamily::Pseudo:
                nSlot = SID_STYLE_FAMILY5; break;
            case SfxStyleFamily::Table:
                nSlot = SID_STYLE_FAMILY6; break;
            default: OSL_FAIL("unknown StyleFamily"); break;
        }
        pBoundItems[i].reset(
            new SfxTemplateControllerItem(nSlot, *this, *pBindings) );
    }
    pBoundItems[i++].reset( new SfxTemplateControllerItem(
        SID_STYLE_WATERCAN, *this, *pBindings) );
    pBoundItems[i++].reset( new SfxTemplateControllerItem(
        SID_STYLE_NEW_BY_EXAMPLE, *this, *pBindings) );
    pBoundItems[i++].reset( new SfxTemplateControllerItem(
        SID_STYLE_UPDATE_BY_EXAMPLE, *this, *pBindings) );
    pBoundItems[i++].reset( new SfxTemplateControllerItem(
        SID_STYLE_NEW, *this, *pBindings) );
    pBoundItems[i++].reset( new SfxTemplateControllerItem(
        SID_STYLE_DRAGHIERARCHIE, *this, *pBindings) );
    pBoundItems[i++].reset( new SfxTemplateControllerItem(
        SID_STYLE_EDIT, *this, *pBindings) );
    pBoundItems[i++].reset( new SfxTemplateControllerItem(
        SID_STYLE_DELETE, *this, *pBindings) );
    pBoundItems[i++].reset( new SfxTemplateControllerItem(
        SID_STYLE_FAMILY, *this, *pBindings) );
    pBindings->LEAVEREGISTRATIONS();

    for(; i < COUNT_BOUND_FUNC; ++i)
        pBoundItems[i] = nullptr;

    StartListening(*pBindings);
    size_t nCount = m_aStyleListReadResource.Call(nullptr);

// Insert in the reverse order of occurrence in the Style Families. This is for
// the toolbar of the designer. The list box of the catalog respects the
@@ -666,29 +247,16 @@ void SfxCommonTemplateDialog_Impl::ReadResource()

    for( ; nCount--; )
    {
        const SfxStyleFamilyItem &rItem = mxStyleFamilies->at( nCount );
        const SfxStyleFamilyItem &rItem = rStyleList.GetFamilyItemByIndex( nCount );
        sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId( rItem.GetFamily() );
        InsertFamilyItem(nId, rItem);
    }

    for ( i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++ )
        pBindings->Update(i);
}

void SfxCommonTemplateDialog_Impl::ClearResource()
IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, ClearResource_Hdl, void*, void)
{
    ClearFamilyList();
    impl_clear();
}

void SfxCommonTemplateDialog_Impl::impl_clear()
{
    mxStyleFamilies.reset();
    for (auto & i : pFamilyState)
        i.reset();
    for (auto & i : pBoundItems)
        i.reset();
    pCurObjShell = nullptr;
    m_aStyleListClear.Call(nullptr);
}

SfxCommonTemplateDialog_Impl::DeletionWatcher *
@@ -700,115 +268,93 @@ SfxCommonTemplateDialog_Impl::impl_setDeletionWatcher(
    return pRet;
}

class TreeViewDropTarget final : public DropTargetHelper
{
private:
    SfxCommonTemplateDialog_Impl& m_rParent;

public:
    TreeViewDropTarget(SfxCommonTemplateDialog_Impl& rDialog, weld::TreeView& rTreeView)
        : DropTargetHelper(rTreeView.get_drop_target())
        , m_rParent(rDialog)
    {
    }

    virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
    {
        return m_rParent.AcceptDrop(rEvt, *this);
    }

    virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
    {
        return m_rParent.ExecuteDrop(rEvt);
    }
};

void SfxCommonTemplateDialog_Impl::Initialize()
{
    // Read global user resource
    ReadResource();
    pBindings->Invalidate( SID_STYLE_FAMILY );
    pBindings->Update( SID_STYLE_FAMILY );
    m_aStyleList.connect_ReadResource(LINK(this, SfxCommonTemplateDialog_Impl, ReadResource_Hdl));
    m_aStyleList.connect_ClearResource(LINK(this, SfxCommonTemplateDialog_Impl, ClearResource_Hdl));
    m_aStyleList.connect_LoadFactoryStyleFilter(LINK(this, SfxCommonTemplateDialog_Impl, LoadFactoryStyleFilter_Hdl));
    m_aStyleList.connect_SaveSelection(LINK(this, SfxCommonTemplateDialog_Impl, SaveSelection_Hdl));
    m_aStyleList.connect_UpdateStyleDependents(LINK(this, SfxCommonTemplateDialog_Impl, UpdateStyleDependents_Hdl));
    m_aStyleList.connect_UpdateFamily(LINK(this, SfxCommonTemplateDialog_Impl, UpdateFamily_Hdl));
    m_aStyleList.connect_UpdateStyles(LINK(this, SfxCommonTemplateDialog_Impl, UpdateStyles_Hdl));

    mxFilterLb->connect_changed(LINK(this, SfxCommonTemplateDialog_Impl, FilterSelectHdl));
    mxFmtLb->connect_row_activated(LINK( this, SfxCommonTemplateDialog_Impl, TreeListApplyHdl));
    mxFmtLb->connect_mouse_press(LINK(this, SfxCommonTemplateDialog_Impl, MousePressHdl));
    mxFmtLb->connect_query_tooltip(LINK(this, SfxCommonTemplateDialog_Impl, QueryTooltipHdl));
    mxFmtLb->connect_changed(LINK(this, SfxCommonTemplateDialog_Impl, FmtSelectHdl));
    mxFmtLb->connect_popup_menu(LINK(this, SfxCommonTemplateDialog_Impl, PopupFlatMenuHdl));
    mxFmtLb->connect_key_press(LINK(this, SfxCommonTemplateDialog_Impl, KeyInputHdl));
    mxFmtLb->set_selection_mode(SelectionMode::Multiple);
    mxTreeBox->connect_changed(LINK(this, SfxCommonTemplateDialog_Impl, FmtSelectHdl));
    mxTreeBox->connect_row_activated(LINK( this, SfxCommonTemplateDialog_Impl, TreeListApplyHdl));
    mxTreeBox->connect_mouse_press(LINK(this, SfxCommonTemplateDialog_Impl, MousePressHdl));
    mxTreeBox->connect_query_tooltip(LINK(this, SfxCommonTemplateDialog_Impl, QueryTooltipHdl));
    mxTreeBox->connect_popup_menu(LINK(this, SfxCommonTemplateDialog_Impl, PopupTreeMenuHdl));
    mxTreeBox->connect_key_press(LINK(this, SfxCommonTemplateDialog_Impl, KeyInputHdl));
    mxTreeBox->connect_drag_begin(LINK(this, SfxCommonTemplateDialog_Impl, DragBeginHdl));
    mxPreviewCheckbox->connect_toggled(LINK(this, SfxCommonTemplateDialog_Impl, PreviewHdl));
    m_xTreeView1DropTargetHelper.reset(new TreeViewDropTarget(*this, *mxFmtLb));
    m_xTreeView2DropTargetHelper.reset(new TreeViewDropTarget(*this, *mxTreeBox));
    m_aStyleList.Initialize();
}

    int nTreeHeight = mxFmtLb->get_height_rows(8);
    mxFmtLb->set_size_request(-1, nTreeHeight);
    mxTreeBox->set_size_request(-1, nTreeHeight);
IMPL_LINK(SfxCommonTemplateDialog_Impl, UpdateStyles_Hdl, StyleFlags, nFlags, void)
{
    const SfxStyleFamilyItem* pItem = m_aStyleList.GetFamilyItem();
    SfxStyleSearchBits nFilter(nActFilter < pItem->GetFilterList().size()
                                   ? pItem->GetFilterList()[nActFilter].nFlags
                                   : SfxStyleSearchBits::Auto);
    if (nFilter == SfxStyleSearchBits::Auto) // automatic
        nFilter = nAppFilter;

    mxFmtLb->connect_custom_get_size(LINK(this, SfxCommonTemplateDialog_Impl, CustomGetSizeHdl));
    mxFmtLb->connect_custom_render(LINK(this, SfxCommonTemplateDialog_Impl, CustomRenderHdl));
    mxTreeBox->connect_custom_get_size(LINK(this, SfxCommonTemplateDialog_Impl, CustomGetSizeHdl));
    mxTreeBox->connect_custom_render(LINK(this, SfxCommonTemplateDialog_Impl, CustomRenderHdl));
    bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
    mxFmtLb->set_column_custom_renderer(0, bCustomPreview);
    mxTreeBox->set_column_custom_renderer(0, bCustomPreview);
    if (nFlags & StyleFlags::UpdateFamily) // Update view type list (Hierarchical, All, etc.
    {
        CheckItem(OString::number(nActFamily)); // check Button in Toolbox

    mxFmtLb->set_visible(!bHierarchical);
    mxTreeBox->set_visible(bHierarchical);
        mxFilterLb->freeze();
        mxFilterLb->clear();

    Update_Impl();
        //insert hierarchical at the beginning
        mxFilterLb->append(OUString::number(static_cast<int>(SfxStyleSearchBits::All)),
                           SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
        const SfxStyleFilter& rFilter = pItem->GetFilterList();
        for (const SfxFilterTuple& i : rFilter)
            mxFilterLb->append(OUString::number(static_cast<int>(i.nFlags)), i.aName);
        mxFilterLb->thaw();

        if (nActFilter < mxFilterLb->get_count() - 1)
            mxFilterLb->set_active(nActFilter + 1);
        else
        {
            nActFilter = 0;
            m_aStyleList.SetFilterIdx(nActFilter);
            mxFilterLb->set_active(1);
            nFilter = (nActFilter < rFilter.size()) ? rFilter[nActFilter].nFlags
                                                    : SfxStyleSearchBits::Auto;
        }

        // if the tree view again, select family hierarchy
        if (m_aStyleList.IsTreeView() || m_bWantHierarchical)
        {
            mxFilterLb->set_active_text(SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
            EnableHierarchical(true, m_aStyleList);
        }
    }
    else
    {
        if (nActFilter < mxFilterLb->get_count() - 1)
            mxFilterLb->set_active(nActFilter + 1);
        else
        {
            nActFilter = 0;
            m_aStyleList.SetFilterIdx(nActFilter);
            mxFilterLb->set_active(1);
        }
    }

    if (!(nFlags & StyleFlags::UpdateFamilyList))
        return;

    EnableItem("watercan", false);
}

SfxCommonTemplateDialog_Impl::~SfxCommonTemplateDialog_Impl()
{
    if ( bIsWater )
        Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
    impl_clear();
    if ( pStyleSheetPool )
        EndListening(*pStyleSheetPool);
    pStyleSheetPool = nullptr;
    m_xTreeView1DropTargetHelper.reset();
    m_xTreeView2DropTargetHelper.reset();
    mxTreeBox.reset();
    pIdle.reset();
        Execute_Impl(SID_STYLE_WATERCAN, "", "", 0, m_aStyleList);
    m_aStyleListClear.Call(nullptr);
    m_aStyleListCleanup.Call(nullptr);
    if ( m_pDeletionWatcher )
        m_pDeletionWatcher->signal();
    mxFmtLb.reset();
    mxPreviewCheckbox.reset();
    mxFilterLb.reset();
}

// Helper function: Access to the current family item
const SfxStyleFamilyItem *SfxCommonTemplateDialog_Impl::GetFamilyItem_Impl() const
{
    const size_t nCount = mxStyleFamilies->size();
    for(size_t i = 0; i < nCount; ++i)
    {
        const SfxStyleFamilyItem &rItem = mxStyleFamilies->at( i );
        sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
        if(nId == nActFamily)
            return &rItem;
    }
    return nullptr;
}

void SfxCommonTemplateDialog_Impl::GetSelectedStyle() const
{
    if (!IsInitialized() || !pStyleSheetPool || !HasSelectedStyle())
        return;
    const OUString aTemplName( GetSelectedEntry() );
    const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
    pStyleSheetPool->Find( aTemplName, pItem->GetFamily() );
}

/**
 * Is it safe to show the water-can / fill icon. If we've a
 * hierarchical widget - we have only single select, otherwise
@@ -817,124 +363,25 @@ void SfxCommonTemplateDialog_Impl::GetSelectedStyle() const
 */
bool SfxCommonTemplateDialog_Impl::IsSafeForWaterCan() const
{
    if (mxTreeBox->get_visible())
        return mxTreeBox->get_selected_index() != -1;
    else
        return mxFmtLb->count_selected_rows() == 1;
    return m_aStyleListWaterCan.Call(nullptr);
}

void SfxCommonTemplateDialog_Impl::SelectStyle(const OUString &rStr, bool bIsCallback)
void SfxCommonTemplateDialog_Impl::SelectStyle(const OUString &rStr, bool bIsCallback, StyleList& rStyleList)
{
    const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
    if ( !pItem )
        return;
    const SfxStyleFamily eFam = pItem->GetFamily();
    SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( rStr, eFam );
    if( pStyle )
    {
        bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
        EnableEdit( bReadWrite );
        EnableHide( bReadWrite && !pStyle->IsHidden( ) && !pStyle->IsUsed( ) );
        EnableShow( bReadWrite && pStyle->IsHidden( ) );
    }
    else
    {
        EnableEdit(false);
        EnableHide(false);
        EnableShow(false);
    }

    if (!bIsCallback)
    {
        if (mxTreeBox->get_visible())
        {
            if (!rStr.isEmpty())
            {
                std::unique_ptr<weld::TreeIter> xEntry = mxTreeBox->make_iterator();
                bool bEntry = mxTreeBox->get_iter_first(*xEntry);
                while (bEntry)
                {
                    if (mxTreeBox->get_text(*xEntry) == rStr)
                    {
                        mxTreeBox->scroll_to_row(*xEntry);
                        mxTreeBox->select(*xEntry);
                        break;
                    }
                    bEntry = mxTreeBox->iter_next(*xEntry);
                }
            }
            else if (eFam == SfxStyleFamily::Pseudo)
            {
                std::unique_ptr<weld::TreeIter> xEntry = mxTreeBox->make_iterator();
                if (mxTreeBox->get_iter_first(*xEntry))
                {
                    mxTreeBox->scroll_to_row(*xEntry);
                    mxTreeBox->select(*xEntry);
                }
            }
            else
                mxTreeBox->unselect_all();
        }
        else
        {
            bool bSelect = !rStr.isEmpty();
            if (bSelect)
            {
                std::unique_ptr<weld::TreeIter> xEntry = mxFmtLb->make_iterator();
                bool bEntry = mxFmtLb->get_iter_first(*xEntry);
                while (bEntry && mxFmtLb->get_text(*xEntry) != rStr)
                    bEntry = mxFmtLb->iter_next(*xEntry);
                if (!bEntry)
                    bSelect = false;
                else
                {
                    if (!mxFmtLb->is_selected(*xEntry))
                    {
                        mxFmtLb->unselect_all();
                        mxFmtLb->scroll_to_row(*xEntry);
                        mxFmtLb->select(*xEntry);
                    }
                }
            }

            if (!bSelect)
            {
                mxFmtLb->unselect_all();
                EnableEdit(false);
                EnableHide(false);
                EnableShow(false);
            }
        }
    }
    rStyleList.SelectStyle(rStr, bIsCallback);

    bWaterDisabled = !IsSafeForWaterCan();

    if (!bIsCallback)
    {
        // tdf#134598 call UpdateStyleDependents to update watercan
        UpdateStyleDependents();
        UpdateStyleDependents_Hdl(nullptr);
    }
}

OUString SfxCommonTemplateDialog_Impl::GetSelectedEntry() const
{
    OUString aRet;
    if (mxTreeBox->get_visible())
        aRet = mxTreeBox->get_selected_text();
    else
        aRet = mxFmtLb->get_selected_text();
    return aRet;
}

void SfxCommonTemplateDialog_Impl::EnableTreeDrag(bool bEnable)
{
    if (pStyleSheetPool)
    {
        const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
        SfxStyleSheetBase* pStyle = pItem ? pStyleSheetPool->First(pItem->GetFamily()) : nullptr;
        bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && bEnable;
    }
    bTreeDrag = bEnable;
    m_aStyleListEnableTreeDrag.Call(bEnable);
}

static OUString lcl_GetStyleFamilyName( SfxStyleFamily nFamily )
@@ -952,7 +399,7 @@ static OUString lcl_GetStyleFamilyName( SfxStyleFamily nFamily )
    return OUString();
}

OUString SfxCommonTemplateDialog_Impl::getDefaultStyleName( const SfxStyleFamily eFam )
OUString SfxCommonTemplateDialog_Impl::getDefaultStyleName( const SfxStyleFamily eFam, StyleList& rStyleList )
{
    OUString sDefaultStyle;
    OUString aFamilyName = lcl_GetStyleFamilyName(eFam);
@@ -962,7 +409,7 @@ OUString SfxCommonTemplateDialog_Impl::getDefaultStyleName( const SfxStyleFamily
        sDefaultStyle = "No List";
    else
        sDefaultStyle = "Standard";
    uno::Reference< style::XStyleFamiliesSupplier > xModel(GetObjectShell()->GetModel(), uno::UNO_QUERY);
    uno::Reference<style::XStyleFamiliesSupplier> xModel(rStyleList.GetObjectShell()->GetModel(), uno::UNO_QUERY);
    OUString aUIName;
    try
    {
@@ -979,210 +426,6 @@ OUString SfxCommonTemplateDialog_Impl::getDefaultStyleName( const SfxStyleFamily
    return aUIName;
}

void SfxCommonTemplateDialog_Impl::FillTreeBox()
{
    assert(mxTreeBox && "FillTreeBox() without treebox");
    if (!pStyleSheetPool || nActFamily == 0xffff)
        return;

    const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
    if (!pItem)
        return;
    const SfxStyleFamily eFam = pItem->GetFamily();
    StyleTreeArr_Impl aArr;
    SfxStyleSheetBase* pStyle = pStyleSheetPool->First(eFam, SfxStyleSearchBits::AllVisible);

    bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && bTreeDrag;

    while (pStyle)
    {
        StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent());
        aArr.emplace_back(pNew);
        pStyle = pStyleSheetPool->Next();
    }
    OUString aUIName = getDefaultStyleName(eFam);
    MakeTree_Impl(aArr, aUIName);
    std::vector<OUString> aEntries;
    MakeExpanded_Impl(*mxTreeBox, aEntries);
    mxTreeBox->freeze();
    mxTreeBox->clear();
    const sal_uInt16 nCount = aArr.size();

    for (sal_uInt16 i = 0; i < nCount; ++i)
    {
        FillBox_Impl(*mxTreeBox, aArr[i].get(), aEntries, eFam, nullptr);
        aArr[i].reset();
    }

    EnableItem("watercan", false);

    SfxTemplateItem* pState = pFamilyState[nActFamily - 1].get();

    mxTreeBox->thaw();

    std::unique_ptr<weld::TreeIter> xEntry = mxTreeBox->make_iterator();
    bool bEntry = mxTreeBox->get_iter_first(*xEntry);
    if (bEntry && nCount)
        mxTreeBox->expand_row(*xEntry);

    while (bEntry)
    {
        if (IsExpanded_Impl(aEntries, mxTreeBox->get_text(*xEntry)))
            mxTreeBox->expand_row(*xEntry);
        bEntry = mxTreeBox->iter_next(*xEntry);
    }

    OUString aStyle;
    if(pState)  // Select current entry
        aStyle = pState->GetStyleName();
    SelectStyle(aStyle, false);
    EnableDelete();
}

bool SfxCommonTemplateDialog_Impl::HasSelectedStyle() const
{
    return mxTreeBox->get_visible() ? mxTreeBox->get_selected_index() != -1
                                    : mxFmtLb->count_selected_rows() != 0;
}

// internal: Refresh the display
// nFlags: what we should update.
void SfxCommonTemplateDialog_Impl::UpdateStyles_Impl(StyleFlags nFlags)
{
    OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
    const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
    if (!pItem)
    {
        // Is the case for the template catalog
        const size_t nFamilyCount = mxStyleFamilies->size();
        size_t n;
        for( n = 0; n < nFamilyCount; n++ )
            if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break;
        if ( n == nFamilyCount )
            // It happens sometimes, God knows why
            return;
        nAppFilter = pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
        FamilySelect(  StyleNrToInfoOffset(n)+1 );
        pItem = GetFamilyItem_Impl();
    }

    const SfxStyleFamily eFam = pItem->GetFamily();

    SfxStyleSearchBits nFilter (nActFilter < pItem->GetFilterList().size() ? pItem->GetFilterList()[nActFilter].nFlags : SfxStyleSearchBits::Auto);
    if (nFilter == SfxStyleSearchBits::Auto)   // automatic
        nFilter = nAppFilter;

    OSL_ENSURE(pStyleSheetPool, "no StyleSheetPool");
    if(!pStyleSheetPool)
        return;

    pItem = GetFamilyItem_Impl();
    if(nFlags & StyleFlags::UpdateFamily)   // Update view type list (Hierarchical, All, etc.
    {
        CheckItem(OString::number(nActFamily));    // check Button in Toolbox

        mxFilterLb->freeze();
        mxFilterLb->clear();

        //insert hierarchical at the beginning
        mxFilterLb->append(OUString::number(static_cast<int>(SfxStyleSearchBits::All)), SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
        const SfxStyleFilter& rFilter = pItem->GetFilterList();
        for (const SfxFilterTuple& i : rFilter)
            mxFilterLb->append(OUString::number(static_cast<int>(i.nFlags)), i.aName);
        mxFilterLb->thaw();

        if (nActFilter < mxFilterLb->get_count() - 1)
            mxFilterLb->set_active(nActFilter + 1);
        else
        {
            nActFilter = 0;
            mxFilterLb->set_active(1);
            nFilter = (nActFilter < rFilter.size()) ? rFilter[nActFilter].nFlags : SfxStyleSearchBits::Auto;
        }

        // if the tree view again, select family hierarchy
        if (mxTreeBox->get_visible() || m_bWantHierarchical)
        {
            mxFilterLb->set_active_text(SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
            EnableHierarchical(true);
        }
    }
    else
    {
        if (nActFilter < mxFilterLb->get_count() - 1)
            mxFilterLb->set_active(nActFilter + 1);
        else
        {
            nActFilter = 0;
            mxFilterLb->set_active(1);
        }
    }

    if(!(nFlags & StyleFlags::UpdateFamilyList))
        return;

    EnableItem("watercan", false);

    SfxStyleSheetBase *pStyle = pStyleSheetPool->First(eFam, nFilter);

    std::unique_ptr<weld::TreeIter> xEntry = mxFmtLb->make_iterator();
    bool bEntry = mxFmtLb->get_iter_first(*xEntry);
    std::vector<OUString> aStrings;

    comphelper::string::NaturalStringSorter aSorter(
        ::comphelper::getProcessComponentContext(),
        Application::GetSettings().GetLanguageTag().getLocale());

    while( pStyle )
    {
        aStrings.push_back(pStyle->GetName());
        pStyle = pStyleSheetPool->Next();
    }
    OUString aUIName = getDefaultStyleName(eFam);

    // Paradoxically, with a list and non-Latin style names,
    // sorting twice is faster than sorting once.
    // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
    // Then the second sort needs to call its (much more expensive) comparator less often.
    std::sort(aStrings.begin(), aStrings.end());
    std::sort(aStrings.begin(), aStrings.end(),
       [&aSorter, &aUIName](const OUString& rLHS, const OUString& rRHS) {
            if(rRHS == aUIName)
                return false;
            if(rLHS == aUIName)
                return true; // default always first
            return aSorter.compare(rLHS, rRHS) < 0;
       });

    size_t nCount = aStrings.size();
    size_t nPos = 0;
    while (nPos < nCount && bEntry &&
           aStrings[nPos] == mxFmtLb->get_text(*xEntry))
    {
        ++nPos;
        bEntry = mxFmtLb->iter_next(*xEntry);
    }

    if (nPos < nCount || bEntry)
    {
        // Fills the display box
        mxFmtLb->freeze();
        mxFmtLb->clear();

        for (nPos = 0; nPos < nCount; ++nPos)
            mxFmtLb->append(aStrings[nPos], aStrings[nPos]);

        mxFmtLb->thaw();
    }
    // Selects the current style if any
    SfxTemplateItem *pState = pFamilyState[nActFamily-1].get();
    OUString aStyle;
    if(pState)
        aStyle = pState->GetStyleName();
    SelectStyle(aStyle, false);
    EnableDelete();
}

// Updated display: Watering the house
void SfxCommonTemplateDialog_Impl::SetWaterCanState(const SfxBoolItem *pItem)
{
@@ -1207,21 +450,7 @@ void SfxCommonTemplateDialog_Impl::SetWaterCanState(const SfxBoolItem *pItem)

// Ignore while in watercan mode statusupdates

    size_t nCount = mxStyleFamilies->size();
    pBindings->EnterRegistrations();
    for(size_t n = 0; n < nCount; n++)
    {
        SfxControllerItem *pCItem=pBoundItems[n].get();
        bool bChecked = pItem && pItem->GetValue();
        if( pCItem->IsBound() == bChecked )
        {
            if( !bChecked )
                pCItem->ReBind();
            else
                pCItem->UnBind();
        }
    }
    pBindings->LeaveRegistrations();
    m_aStyleListSetWaterCanState.Call(pItem);
}

// Item with the status of a Family is copied and noted
@@ -1229,256 +458,16 @@ void SfxCommonTemplateDialog_Impl::SetWaterCanState(const SfxBoolItem *pItem)
// See also: <SfxBindings::AddDoneHdl(const Link &)>
void SfxCommonTemplateDialog_Impl::SetFamilyState( sal_uInt16 nSlotId, const SfxTemplateItem* pItem )
{
    sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
    pFamilyState[nIdx].reset();
    if ( pItem )
        pFamilyState[nIdx].reset( new SfxTemplateItem(*pItem) );
    m_aStyleList.SetFamilyState(nSlotId, pItem);
    bUpdate = true;

    // If used templates (how the hell you find this out??)
    bUpdateFamily = true;
}

// Notice from SfxBindings that the update is completed. Pushes out the update
// of the display.
void SfxCommonTemplateDialog_Impl::Update_Impl()
{
    bool bDocChanged=false;
    SfxStyleSheetBasePool* pNewPool = nullptr;
    SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
    SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
    if( pDocShell )
        pNewPool = pDocShell->GetStyleSheetPool();

    if ( pNewPool != pStyleSheetPool && pDocShell )
    {
        SfxModule* pNewModule = pDocShell->GetModule();
        if( pNewModule && pNewModule != pModule )
        {
            ClearResource();
            ReadResource();
        }
        if ( pStyleSheetPool )
        {
            EndListening(*pStyleSheetPool);
            pStyleSheetPool = nullptr;
        }

        if ( pNewPool )
        {
            StartListening(*pNewPool);
            pStyleSheetPool = pNewPool;
            bDocChanged=true;
        }
    }

    if (bUpdateFamily)
        UpdateFamily_Impl();

    sal_uInt16 i;
    for(i = 0; i < MAX_FAMILIES; ++i)
        if(pFamilyState[i])
            break;
    if(i == MAX_FAMILIES || !pNewPool)
        // nothing is allowed
        return;

    SfxTemplateItem *pItem = nullptr;
    // current region not within the allowed region or default
    if(nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get() ) )
    {
         CheckItem(OString::number(nActFamily), false);
         const size_t nFamilyCount = mxStyleFamilies->size();
         size_t n;
         for( n = 0; n < nFamilyCount; n++ )
             if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break;

         std::unique_ptr<SfxTemplateItem> & pNewItem = pFamilyState[StyleNrToInfoOffset(n)];
         nAppFilter = pNewItem->GetValue();
         FamilySelect( StyleNrToInfoOffset(n) + 1 );
         pItem = pNewItem.get();
    }
    else if( bDocChanged )
    {
         // other DocShell -> all new
         CheckItem(OString::number(nActFamily));
         nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pDocShell ) );
         if ( 0xffff == nActFilter )
            nActFilter = pDocShell->GetAutoStyleFilterIndex();

         nAppFilter = pItem->GetValue();
         if (!mxTreeBox->get_visible())
         {
             UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
         }
         else
             FillTreeBox();
    }
    else
    {
         // other filters for automatic
         CheckItem(OString::number(nActFamily));
         const SfxStyleFamilyItem *pStyleItem =  GetFamilyItem_Impl();
         if ( pStyleItem && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[nActFilter].nFlags
            && nAppFilter != pItem->GetValue())
         {
             nAppFilter = pItem->GetValue();
             if (!mxTreeBox->get_visible())
                 UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
             else
                 FillTreeBox();
         }
         else
             nAppFilter = pItem->GetValue();
    }
    const OUString aStyle(pItem->GetStyleName());
    SelectStyle(aStyle, false);
    EnableDelete();
    EnableNew( bCanNew );
}

IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, TimeOut, Timer *, void )
{
    if(!bDontUpdate)
    {
        bDontUpdate=true;
        if (!mxTreeBox->get_visible())
            UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
        else
        {
            FillTreeBox();
            SfxTemplateItem *pState = pFamilyState[nActFamily-1].get();
            if(pState)
            {
                SelectStyle(pState->GetStyleName(), false);
                EnableDelete();
            }
        }
        bDontUpdate=false;
        pIdle.reset();
    }
    else
        pIdle->Start();
}

void SfxCommonTemplateDialog_Impl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
{
    const SfxHintId nId = rHint.GetId();

    // tap update
    switch(nId)
    {
        case SfxHintId::UpdateDone:
            {
                SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
                SfxObjectShell *pDocShell = pViewFrame->GetObjectShell();
                if (
                        bUpdate &&
                        (
                         !IsCheckedItem("watercan") ||
                         (pDocShell && pDocShell->GetStyleSheetPool() != pStyleSheetPool)
                        )
                   )
                {
                    bUpdate = false;
                    Update_Impl();
                }
                else if ( bUpdateFamily )
                {
                    UpdateFamily_Impl();
                }

                if( pStyleSheetPool )
                {
                    OUString aStr = GetSelectedEntry();
                    if (!aStr.isEmpty())
                    {
                        const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
                        if( !pItem ) break;
                        const SfxStyleFamily eFam = pItem->GetFamily();
                        SfxStyleSheetBase *pStyle = pStyleSheetPool->Find( aStr, eFam );
                        if( pStyle )
                        {
                            bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
                            EnableEdit( bReadWrite );
                            EnableHide( bReadWrite && !pStyle->IsUsed( ) && !pStyle->IsHidden( ) );
                            EnableShow( bReadWrite && pStyle->IsHidden( ) );
                        }
                        else
                        {
                            EnableEdit(false);
                            EnableHide(false);
                            EnableShow(false);
                        }
                    }
                }
                break;
            }

            // Necessary if switching between documents and in both documents
            // the same template is used. Do not immediately call Update_Impl,
            // for the case that one of the documents is an internal InPlaceObject!
        case SfxHintId::DocChanged:
            bUpdate = true;
        break;
        case SfxHintId::Dying:
            {
                EndListening(*pStyleSheetPool);
                pStyleSheetPool=nullptr;
                break;
            }
        default: break;
    }

    // Do not set timer when the stylesheet pool is in the box, because it is
    // possible that a new one is registered after the timer is up -
    // works bad in UpdateStyles_Impl ()!

    if(!bDontUpdate && nId != SfxHintId::Dying &&
       (dynamic_cast<const SfxStyleSheetPoolHint*>(&rHint) ||
        dynamic_cast<const SfxStyleSheetHint*>(&rHint) ||
        dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint) ||
        nId == SfxHintId::StyleSheetModified))
    {
        if(!pIdle)
        {
            pIdle.reset(new Idle("SfxCommonTemplate"));
            pIdle->SetPriority(TaskPriority::LOWEST);
            pIdle->SetInvokeHandler(LINK(this,SfxCommonTemplateDialog_Impl,TimeOut));
        }
        pIdle->Start();

    }
}

// Other filters; can be switched by the users or as a result of new or
// editing, if the current document has been assigned a different filter.
void SfxCommonTemplateDialog_Impl::FilterSelect(
                sal_uInt16 nEntry,  // Idx of the new Filters
                bool bForce )   // Force update, even if the new filter is
                                // equal to the current
{
    if( nEntry == nActFilter && !bForce )
        return;

    nActFilter = nEntry;
    SfxObjectShell *const pDocShell = SaveSelection();
    SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool;
    pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr;
    if ( pOldStyleSheetPool != pStyleSheetPool )
    {
        if ( pOldStyleSheetPool )
            EndListening(*pOldStyleSheetPool);
        if ( pStyleSheetPool )
            StartListening(*pStyleSheetPool);
    }

    UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
}

// Internal: Perform functions through the Dispatcher
bool SfxCommonTemplateDialog_Impl::Execute_Impl(
    sal_uInt16 nId, const OUString &rStr, const OUString& rRefStr, sal_uInt16 nFamily,
    sal_uInt16 nId, const OUString &rStr, const OUString& rRefStr, sal_uInt16 nFamily, StyleList& rStyleList,
    SfxStyleSearchBits nMask, sal_uInt16 *pIdx, const sal_uInt16* pModifier)
{
    SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl();
@@ -1497,7 +486,7 @@ bool SfxCommonTemplateDialog_Impl::Execute_Impl(
    if(SID_STYLE_UPDATE_BY_EXAMPLE == nId)
    {
        // Special solution for Numbering update in Writer
        const OUString aTemplName(GetSelectedEntry());
        const OUString aTemplName(rStyleList.GetSelectedEntry());
        aUpdName.SetValue(aTemplName);
        pItems[ nCount++ ] = &aUpdName;
    }
@@ -1518,14 +507,15 @@ bool SfxCommonTemplateDialog_Impl::Execute_Impl(
    if ( !pItem || aDeleted )
        return false;

    if ( (nId == SID_STYLE_NEW || SID_STYLE_EDIT == nId) && (mxTreeBox->get_visible() || mxFmtLb->count_selected_rows() <= 1) )
    if ((nId == SID_STYLE_NEW || SID_STYLE_EDIT == nId)
        && rStyleList.EnableExecute())
    {
        const SfxUInt16Item *pFilterItem = dynamic_cast< const SfxUInt16Item* >(pItem);
        assert(pFilterItem);
        SfxStyleSearchBits nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue()) & ~SfxStyleSearchBits::UserDefined;
        if(nFilterFlags == SfxStyleSearchBits::Auto)       // User Template?
            nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue());
        const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl();
        const SfxStyleFamilyItem *pFamilyItem = rStyleList.GetFamilyItem();
        const size_t nFilterCount = pFamilyItem->GetFilterList().size();

        for ( size_t i = 0; i < nFilterCount; ++i )
@@ -1541,44 +531,52 @@ bool SfxCommonTemplateDialog_Impl::Execute_Impl(
}

// Handler Listbox of Filter
void SfxCommonTemplateDialog_Impl::EnableHierarchical(bool const bEnable)
void SfxCommonTemplateDialog_Impl::EnableHierarchical(bool const bEnable, StyleList& rStyleList)
{
    if (bEnable)
    {
        if (!bHierarchical)
        if (!rStyleList.IsHierarchical())
        {
            // Turn on treeView
            bHierarchical=true;
            m_bWantHierarchical = true;
            SaveSelection(); // fdo#61429 store "hierarchical"
            const OUString aSelectEntry( GetSelectedEntry());
            mxFmtLb->hide();
            FillTreeBox();
            SelectStyle(aSelectEntry, false);
            mxTreeBox->show();
            SaveSelection_Hdl(nullptr); // fdo#61429 store "hierarchical"
            m_aStyleList.SetHierarchical();
        }
    }
    else
    {
        mxTreeBox->hide();
        mxFmtLb->show();
        m_aStyleList.SetFilterControlsHandle();
        // If bHierarchical, then the family can have changed
        // minus one since hierarchical is inserted at the start
        m_bWantHierarchical = false; // before FilterSelect
        FilterSelect(mxFilterLb->get_active() - 1, bHierarchical );
        bHierarchical=false;
        FilterSelect(mxFilterLb->get_active() - 1, rStyleList.IsHierarchical() );
    }
}

// Other filters; can be switched by the users or as a result of new or
// editing, if the current document has been assigned a different filter.
void SfxCommonTemplateDialog_Impl::FilterSelect(
    sal_uInt16 nEntry, // Idx of the new Filters
    bool bForce) // Force update, even if the new filter is equal to the current
{
    if (nEntry == nActFilter && !bForce)
        return;

    nActFilter = nEntry;
    m_aStyleListFilterSelect.Call(nActFilter);

    m_aStyleListUpdateStyles.Call(StyleFlags::UpdateFamilyList);
}

IMPL_LINK(SfxCommonTemplateDialog_Impl, FilterSelectHdl, weld::ComboBox&, rBox, void)
{
    if (SfxResId(STR_STYLE_FILTER_HIERARCHICAL) == rBox.get_active_text())
    {
        EnableHierarchical(true);
        EnableHierarchical(true, m_aStyleList);
    }
    else
    {
        EnableHierarchical(false);
        EnableHierarchical(false, m_aStyleList);
    }
}

@@ -1590,17 +588,11 @@ void SfxCommonTemplateDialog_Impl::FamilySelect(sal_uInt16 nEntry, bool bPreview
    {
        CheckItem(OString::number(nActFamily), false);
        nActFamily = nEntry;
        SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl();
        SfxUInt16Item const aItem(SID_STYLE_FAMILY,
                static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
        pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
        pBindings->Invalidate( SID_STYLE_FAMILY );
        pBindings->Update( SID_STYLE_FAMILY );
        UpdateFamily_Impl();
        m_aStyleListFamilySelect.Call(nEntry);
    }
}

void SfxCommonTemplateDialog_Impl::ActionSelect(const OString& rEntry)
void SfxCommonTemplateDialog_Impl::ActionSelect(const OString& rEntry, StyleList& rStyleList)
{
    if (rEntry == "watercan")
    {
@@ -1608,18 +600,16 @@ void SfxCommonTemplateDialog_Impl::ActionSelect(const OString& rEntry)
        bool bCheck;
        SfxBoolItem aBool;
        // when a template is chosen.
        if (!bOldState && HasSelectedStyle())
        if (!bOldState && m_aStyleListHasSelectedStyle.Call(nullptr))
        {
            const OUString aTemplName(
                GetSelectedEntry());
            Execute_Impl(
                SID_STYLE_WATERCAN, aTemplName, "",
                static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
            const OUString aTemplName(rStyleList.GetSelectedEntry());
            Execute_Impl(SID_STYLE_WATERCAN, aTemplName, "",
                         static_cast<sal_uInt16>(m_aStyleList.GetFamilyItem()->GetFamily()), rStyleList);
            bCheck = true;
        }
        else
        {
            Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
            Execute_Impl(SID_STYLE_WATERCAN, "", "", 0, rStyleList);
            bCheck = false;
        }
        CheckItem(rEntry, bCheck);
@@ -1628,35 +618,13 @@ void SfxCommonTemplateDialog_Impl::ActionSelect(const OString& rEntry)
    }
    else if (rEntry == "new" || rEntry == "newmenu")
    {
        if(pStyleSheetPool && nActFamily != 0xffff)
        {
            const SfxStyleFamily eFam=GetFamilyItem_Impl()->GetFamily();
            const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
            SfxStyleSearchBits nFilter(SfxStyleSearchBits::Auto);
            if (pItem && nActFilter != 0xffff)
                nFilter = pItem->GetFilterList()[nActFilter].nFlags;
            if (nFilter == SfxStyleSearchBits::Auto)    // automatic
                nFilter = nAppFilter;

            // why? : FloatingWindow must not be parent of a modal dialog
            SfxNewStyleDlg aDlg(mpContainer, *pStyleSheetPool, eFam);
            auto nResult = aDlg.run();
            if (nResult ==  RET_OK)
            {
                const OUString aTemplName(aDlg.GetName());
                Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE,
                             aTemplName, "",
                             static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
                             nFilter);
                UpdateFamily_Impl();
            }
        }
        m_aStyleListNewMenu.Call(nullptr);
    }
    else if (rEntry == "update")
    {
        Execute_Impl(SID_STYLE_UPDATE_BY_EXAMPLE,
                "", "",
                static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
                static_cast<sal_uInt16>(m_aStyleList.GetFamilyItem()->GetFamily()), rStyleList);
    }
    else if (rEntry == "load")
        SfxGetpApp()->GetDispatcher_Impl()->Execute(SID_TEMPLATE_LOAD);
@@ -1687,7 +655,7 @@ static OUString getModuleIdentifier( const Reference< XModuleManager2 >& i_xModM
    return sIdentifier;
}

sal_Int32 SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter( SfxObjectShell const * i_pObjSh )
IMPL_LINK(SfxCommonTemplateDialog_Impl, LoadFactoryStyleFilter_Hdl, SfxObjectShell const*, i_pObjSh, sal_Int32)
{
    OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );

@@ -1710,7 +678,7 @@ void SfxCommonTemplateDialog_Impl::SaveFactoryStyleFilter( SfxObjectShell const 
    xModuleManager->replaceByName( getModuleIdentifier( xModuleManager, i_pObjSh ), makeAny( lProps ) );
}

SfxObjectShell* SfxCommonTemplateDialog_Impl::SaveSelection()
IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, SaveSelection_Hdl, void*, SfxObjectShell*)
{
    SfxViewFrame *const pViewFrame(pBindings->GetDispatcher_Impl()->GetFrame());
    SfxObjectShell *const pDocShell(pViewFrame->GetObjectShell());
@@ -1722,219 +690,6 @@ SfxObjectShell* SfxCommonTemplateDialog_Impl::SaveSelection()
    return pDocShell;
}

void SfxCommonTemplateDialog_Impl::DropHdl(const OUString& rStyle, const OUString& rParent)
{
    bDontUpdate = true;
    const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
    const SfxStyleFamily eFam = pItem->GetFamily();
    pStyleSheetPool->SetParent(eFam, rStyle, rParent);
    bDontUpdate = false;
}

// Handler for the New-Buttons
void SfxCommonTemplateDialog_Impl::NewHdl()
{
    if ( nActFamily == 0xffff || !(mxTreeBox->get_visible() || mxFmtLb->count_selected_rows() <= 1))
        return;

    const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
    const SfxStyleFamily eFam = pItem->GetFamily();
    SfxStyleSearchBits nMask(SfxStyleSearchBits::Auto);
    if (nActFilter != 0xffff)
        nMask = pItem->GetFilterList()[nActFilter].nFlags;
    if (nMask == SfxStyleSearchBits::Auto)    // automatic
        nMask = nAppFilter;

    Execute_Impl(SID_STYLE_NEW,
                 "", GetSelectedEntry(),
                 static_cast<sal_uInt16>(eFam),
                 nMask);
}

// Handler for the edit-Buttons
void SfxCommonTemplateDialog_Impl::EditHdl()
{
    if(IsInitialized() && HasSelectedStyle())
    {
        sal_uInt16 nFilter = nActFilter;
        OUString aTemplName(GetSelectedEntry());
        GetSelectedStyle(); // -Wall required??
        Execute_Impl( SID_STYLE_EDIT, aTemplName, OUString(),
                          static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()), SfxStyleSearchBits::Auto, &nFilter );
    }
}

// Handler for the Delete-Buttons
void SfxCommonTemplateDialog_Impl::DeleteHdl()
{
    if ( !IsInitialized() || !HasSelectedStyle() )
        return;

    bool bUsedStyle = false;     // one of the selected styles are used in the document?

    std::vector<std::unique_ptr<weld::TreeIter>> aList;
    weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
    const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();

    OUStringBuffer aMsg;
    aMsg.append(SfxResId(STR_DELETE_STYLE_USED) + SfxResId(STR_DELETE_STYLE));

    pTreeView->selected_foreach([this, pTreeView, pItem, &aList, &bUsedStyle, &aMsg](weld::TreeIter& rEntry){
        aList.emplace_back(pTreeView->make_iterator(&rEntry));
        // check the style is used or not
        const OUString aTemplName(pTreeView->get_text(rEntry));

        SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( aTemplName, pItem->GetFamily() );

        if ( pStyle->IsUsed() )  // pStyle is in use in the document?
        {
            if (bUsedStyle) // add a separator for the second and later styles
                aMsg.append(", ");
            aMsg.append(aTemplName);
            bUsedStyle = true;
        }

        return false;
    });

    bool aApproved = false;

    // we only want to show the dialog once and if we want to delete a style in use (UX-advice)
    if (bUsedStyle)
    {
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pTreeView,
                                                  VclMessageType::Question, VclButtonsType::YesNo,
                                                  aMsg.makeStringAndClear()));
        aApproved = xBox->run() == RET_YES;
    }

    // if there are no used styles selected or the user approved the changes
    if ( bUsedStyle && !aApproved )
        return;

    for (auto const& elem : aList)
    {
        const OUString aTemplName(pTreeView->get_text(*elem));
        bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting
        Execute_Impl( SID_STYLE_DELETE, aTemplName,
                      OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );

        if (mxTreeBox->get_visible())
        {
            weld::RemoveParentKeepChildren(*mxTreeBox, *elem);
            bDontUpdate = false;
        }
    }
    bDontUpdate = false; //if everything is deleted set bDontUpdate back to false
    UpdateStyles_Impl(StyleFlags::UpdateFamilyList); //and force-update the list
}

void SfxCommonTemplateDialog_Impl::HideHdl()
{
    if ( !IsInitialized() || !HasSelectedStyle() )
        return;

    weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
    pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry){
        OUString aTemplName = pTreeView->get_text(rEntry);

        Execute_Impl( SID_STYLE_HIDE, aTemplName,
                      OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );

        return false;
    });
}

void SfxCommonTemplateDialog_Impl::ShowHdl()
{
    if ( !IsInitialized() || !HasSelectedStyle() )
        return;

    weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
    pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry){
        OUString aTemplName = pTreeView->get_text(rEntry);

        Execute_Impl( SID_STYLE_SHOW, aTemplName,
                      OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );

        return false;
    });
}

void SfxCommonTemplateDialog_Impl::EnableDelete()
{
    bool bEnableDelete(false);
    if(IsInitialized() && HasSelectedStyle())
    {
        OSL_ENSURE(pStyleSheetPool, "No StyleSheetPool");
        const OUString aTemplName(GetSelectedEntry());
        const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
        const SfxStyleFamily eFam = pItem->GetFamily();
        SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
        if (pItem->GetFilterList().size() > nActFilter)
            nFilter = pItem->GetFilterList()[nActFilter].nFlags;
        if(nFilter == SfxStyleSearchBits::Auto)    // automatic
            nFilter = nAppFilter;
        const SfxStyleSheetBase *pStyle =
            pStyleSheetPool->Find(aTemplName,eFam, mxTreeBox->get_visible() ? SfxStyleSearchBits::All : nFilter);

        OSL_ENSURE(pStyle, "Style not found");
        if (pStyle && pStyle->IsUserDefined())
        {
            if (pStyle->HasClearParentSupport() || !pStyle->IsUsed())
            {
                bEnableDelete = true;
            }
            else if (pStyle->GetFamily() == SfxStyleFamily::Page)
            {
                // Hack to allow Calc page styles to be deleted,
                // remove when IsUsed is fixed for Calc page styles.
                SfxViewFrame* pFrame = GetObjectShell()->GetFrame();
                if (pFrame)
                {
                    uno::Reference<frame::XFrame > xFrame = pFrame->GetFrame().GetFrameInterface();
                    if (vcl::CommandInfoProvider::GetModuleIdentifier(xFrame) == "com.sun.star.sheet.SpreadsheetDocument")
                    {
                        bEnableDelete = true;
                    }
                }
            }
        }
    }
    EnableDel(bEnableDelete);
}

IMPL_LINK(SfxCommonTemplateDialog_Impl, MousePressHdl, const MouseEvent&, rMEvt, bool)
{
    m_nModifier = rMEvt.GetModifier();
    return false;
}

// Double-click on a style sheet in the ListBox is applied.
IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, TreeListApplyHdl, weld::TreeView&, bool)
{
    // only if that region is allowed
    if ( IsInitialized() && nullptr != pFamilyState[nActFamily-1] &&
         !GetSelectedEntry().isEmpty() )
    {
        Execute_Impl(SID_STYLE_APPLY,
                     GetSelectedEntry(), OUString(),
                     static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
                     SfxStyleSearchBits::Auto, nullptr, &m_nModifier);
    }
    // After selecting a focused item if possible again on the app window
    if ( dynamic_cast< const SfxTemplateDialog_Impl* >(this) !=  nullptr )
    {
        SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
        SfxViewShell *pVu = pViewFrame->GetViewShell();
        vcl::Window *pAppWin = pVu ? pVu->GetWindow(): nullptr;
        if(pAppWin)
            pAppWin->GrabFocus();
    }

    return true;
}

IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, PreviewHdl, weld::Toggleable&, void)
{
    std::shared_ptr<comphelper::ConfigurationChanges> batch( comphelper::ConfigurationChanges::create() );
@@ -1942,75 +697,16 @@ IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, PreviewHdl, weld::Toggleable&, voi
    officecfg::Office::Common::StylesAndFormatting::Preview::set(bCustomPreview, batch );
    batch->commit();

    mxFmtLb->clear();
    mxFmtLb->set_column_custom_renderer(0, bCustomPreview);
    mxTreeBox->clear();
    mxTreeBox->set_column_custom_renderer(0, bCustomPreview);
    m_aStyleList.EnablePreview(bCustomPreview);

    FamilySelect(nActFamily, true);
}

// Selection of a template during the Watercan-Status
IMPL_LINK(SfxCommonTemplateDialog_Impl, FmtSelectHdl, weld::TreeView&, rListBox, void)
IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, UpdateStyleDependents_Hdl, void*, void)
{
    std::unique_ptr<weld::TreeIter> xHdlEntry = rListBox.make_iterator();
    if (!rListBox.get_cursor(xHdlEntry.get()))
        return;

    if (rListBox.is_selected(*xHdlEntry))
        UpdateStyleDependents();

    SelectStyle(rListBox.get_text(*xHdlEntry), true);
}

void SfxCommonTemplateDialog_Impl::UpdateStyleDependents()
{
    // Trigger Help PI. Only when the watercan is on
    if ( IsInitialized() &&
         IsCheckedItem("watercan") &&
         // only if that region is allowed
         nullptr != pFamilyState[nActFamily-1] && (mxTreeBox || mxFmtLb->count_selected_rows() <= 1) )
    {
        Execute_Impl(SID_STYLE_WATERCAN,
                     "", "", 0);
        Execute_Impl(SID_STYLE_WATERCAN,
                     GetSelectedEntry(), "",
                     static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
    }
    m_aStyleListUpdateStyleDependents.Call(nullptr);
    EnableItem("watercan", !bWaterDisabled);
    EnableDelete();
}

void SfxCommonTemplateDialog_Impl::MenuSelect(const OString& rIdent)
{
    sLastItemIdent = rIdent;
    if (sLastItemIdent.isEmpty())
        return;
    Application::PostUserEvent(
        LINK(this, SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl));
}

IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl, void*, void)
{
    if (sLastItemIdent == "new")
        NewHdl();
    else if (sLastItemIdent == "edit")
        EditHdl();
    else if (sLastItemIdent == "delete")
        DeleteHdl();
    else if (sLastItemIdent == "hide")
        HideHdl();
    else if (sLastItemIdent == "show")
        ShowHdl();
}

SfxStyleFamily SfxCommonTemplateDialog_Impl::GetActualFamily() const
{
    const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl();
    if( !pFamilyItem || nActFamily == 0xffff )
        return SfxStyleFamily::Para;
    else
        return pFamilyItem->GetFamily();
    m_aStyleListEnableDelete.Call(nullptr);
}

void SfxCommonTemplateDialog_Impl::EnableExample_Impl(sal_uInt16 nId, bool bEnable)
@@ -2019,6 +715,7 @@ void SfxCommonTemplateDialog_Impl::EnableExample_Impl(sal_uInt16 nId, bool bEnab
    if (nId == SID_STYLE_NEW_BY_EXAMPLE)
    {
        bNewByExampleDisabled = bDisable;
        m_aStyleList.EnableNewByExample(bNewByExampleDisabled);
        EnableItem("new", bEnable);
        EnableItem("newmenu", bEnable);
    }
@@ -2029,41 +726,6 @@ void SfxCommonTemplateDialog_Impl::EnableExample_Impl(sal_uInt16 nId, bool bEnab
    }
}

void SfxCommonTemplateDialog_Impl::CreateContextMenu()
{
    if ( bBindingUpdate )
    {
        pBindings->Invalidate( SID_STYLE_NEW, true );
        pBindings->Update( SID_STYLE_NEW );
        bBindingUpdate = false;
    }
    mxMenu.reset();
    mxMenuBuilder.reset(Application::CreateBuilder(nullptr, "sfx/ui/stylecontextmenu.ui"));
    mxMenu = mxMenuBuilder->weld_menu("menu");
    mxMenu->set_sensitive("edit", bCanEdit);
    mxMenu->set_sensitive("delete", bCanDel);
    mxMenu->set_sensitive("new", bCanNew);
    mxMenu->set_sensitive("hide", bCanHide);
    mxMenu->set_sensitive("show", bCanShow);

    const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
    if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
    {
        mxMenu->set_sensitive("edit", false);
        mxMenu->set_sensitive("new", false);
    }
    if (pItem && pItem->GetFamily() == SfxStyleFamily::Pseudo)
    {
        const OUString aTemplName(GetSelectedEntry());
        if (aTemplName == "No List")
        {
            mxMenu->set_sensitive("edit", false);
            mxMenu->set_sensitive("new", false);
            mxMenu->set_sensitive("hide", false);
        }
    }
}

SfxTemplateDialog_Impl::SfxTemplateDialog_Impl(SfxBindings* pB, SfxTemplatePanelControl* pDlgWindow)
    : SfxCommonTemplateDialog_Impl(pB, pDlgWindow->get_container(), pDlgWindow->get_builder())
    , m_xActionTbL(pDlgWindow->get_builder()->weld_toolbar("left"))
@@ -2159,20 +821,6 @@ void SfxTemplateDialog_Impl::ClearFamilyList()

}

void SfxCommonTemplateDialog_Impl::InvalidateBindings()
{
    pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
    pBindings->Update( SID_STYLE_NEW_BY_EXAMPLE );
    pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
    pBindings->Update( SID_STYLE_UPDATE_BY_EXAMPLE );
    pBindings->Invalidate( SID_STYLE_WATERCAN, true);
    pBindings->Update( SID_STYLE_WATERCAN );
    pBindings->Invalidate( SID_STYLE_NEW, true);
    pBindings->Update( SID_STYLE_NEW );
    pBindings->Invalidate( SID_STYLE_DRAGHIERARCHIE, true);
    pBindings->Update( SID_STYLE_DRAGHIERARCHIE );
}

SfxTemplateDialog_Impl::~SfxTemplateDialog_Impl()
{
    m_xToolbarDropTargetHelper.reset();
@@ -2183,7 +831,7 @@ SfxTemplateDialog_Impl::~SfxTemplateDialog_Impl()
void SfxTemplateDialog_Impl::EnableItem(const OString& rMesId, bool bCheck)
{
    if (rMesId == "watercan" && !bCheck && IsCheckedItem("watercan"))
        Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
        Execute_Impl(SID_STYLE_WATERCAN, "", "", 0, m_aStyleList);
    m_xActionTbR->set_item_sensitive(rMesId, bCheck);
}

@@ -2215,7 +863,7 @@ IMPL_LINK(SfxTemplateDialog_Impl, ToolBoxRSelect, const OString&, rEntry, void)
    if (rEntry == "newmenu")
        m_xActionTbR->set_menu_item_active(rEntry, !m_xActionTbR->get_menu_item_active(rEntry));
    else
        ActionSelect(rEntry);
        ActionSelect(rEntry, m_aStyleList);
}

void SfxTemplateDialog_Impl::FillToolMenu()
@@ -2240,7 +888,7 @@ IMPL_LINK(SfxTemplateDialog_Impl, ToolMenuSelectHdl, const OString&, rMenuId, vo
{
    if (rMenuId.isEmpty())
        return;
    ActionSelect(rMenuId);
    ActionSelect(rMenuId, m_aStyleList);
}

void SfxCommonTemplateDialog_Impl::SetFamily(SfxStyleFamily const nFamily)
@@ -2249,58 +897,28 @@ void SfxCommonTemplateDialog_Impl::SetFamily(SfxStyleFamily const nFamily)
    assert((0 < nId && nId <= MAX_FAMILIES) || 0xffff == nId);
    if ( nId != nActFamily )
    {
        if ( nActFamily != 0xFFFF )
            CheckItem(OString::number(nActFamily), false);
        m_aStyleListSetFamily.Call(nId);
        nActFamily = nId;
        if ( nId != 0xFFFF )
            bUpdateFamily = true;
    }
}

void SfxCommonTemplateDialog_Impl::UpdateFamily_Impl()
IMPL_LINK(SfxCommonTemplateDialog_Impl, UpdateFamily_Hdl, StyleList&, rStyleList, void)
{
    bUpdateFamily = false;

    SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl();
    SfxViewFrame *pViewFrame = pDispat->GetFrame();
    SfxObjectShell *pDocShell = pViewFrame->GetObjectShell();

    SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool;
    pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr;
    if ( pOldStyleSheetPool != pStyleSheetPool )
    {
        if ( pOldStyleSheetPool )
            EndListening(*pOldStyleSheetPool);
        if ( pStyleSheetPool )
            StartListening(*pStyleSheetPool);
    }

    bWaterDisabled = false;
    bCanNew = mxTreeBox->get_visible() || mxFmtLb->count_selected_rows() <= 1;
    bTreeDrag = true;
    bUpdateByExampleDisabled = false;

    if (pStyleSheetPool)
    {
        if (!mxTreeBox->get_visible())
            UpdateStyles_Impl(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
        else
        {
            UpdateStyles_Impl(StyleFlags::UpdateFamily);
            FillTreeBox();
        }
    }

    InvalidateBindings();
    m_aStyleListUpdateFamily.Call(nullptr);

    if (IsCheckedItem("watercan") &&
         // only if that area is allowed
         nullptr != pFamilyState[nActFamily - 1])
        // only if that area is allowed
        rStyleList.CurrentFamilyHasState())
    {
        Execute_Impl(SID_STYLE_APPLY,
                     GetSelectedEntry(),
                     OUString(),
                     static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
        Execute_Impl(SID_STYLE_APPLY, rStyleList.GetSelectedEntry(), OUString(),
                     static_cast<sal_uInt16>(rStyleList.GetFamilyItem()->GetFamily()), rStyleList);
    }
}

diff --git a/sfx2/source/inc/StyleList.hxx b/sfx2/source/inc/StyleList.hxx
new file mode 100644
index 0000000..65bb21c
--- /dev/null
+++ b/sfx2/source/inc/StyleList.hxx
@@ -0,0 +1,235 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#pragma once

#include <sal/config.h>

class SfxObjectShell;
class SfxStyleFamilyItem;
class SfxTemplateItem;
class SfxCommonTemplateDialog_Impl;

enum class StyleFlags
{
    NONE = 0,
    UpdateFamilyList = 1,
    UpdateFamily = 2
};

namespace o3tl
{
template <> struct typed_flags<StyleFlags> : is_typed_flags<StyleFlags, 3>
{
};
}

class TreeViewDropTarget;

constexpr int MAX_FAMILIES = 6;
constexpr int COUNT_BOUND_FUNC = 14;

class StyleList : public SfxListener
{
    friend class TreeViewDropTarget;
    friend class SfxTemplateControllerItem;

public:
    // Constructor
    StyleList(weld::Builder* pBuilder, std::optional<SfxStyleFamilies> xFamilies,
              SfxBindings* pBindings, SfxCommonTemplateDialog_Impl* Parent, SfxModule* Module,
              weld::Container* pC, OString treeviewname, OString flatviewname);

    // Destructor
    ~StyleList();

    // This function connects m_xTreeBox, m_xFmtLb and m_pParentDialog with certain LINKs
    void Initialize();

    // It selects the style in treeview
    // bIsCallBack is true for the selected style. For eg. if "Addressee" is selected in
    // styles, bIsCallBack will be true for it.
    void SelectStyle(const OUString& rStr, bool bIsCallback);
    // Checks whether a family has a saved state
    bool CurrentFamilyHasState() { return nullptr != m_pFamilyState[m_nActFamily - 1]; }

    // This function is a subpart of Dialog's SetFamilyState
    // When a new style is selected for use, it resets it.
    void SetFamilyState(sal_uInt16 nSlotId, const SfxTemplateItem* pItem);

    // It is used in Dialog's EnableExample_Impl
    // When the value of m_bNewbyExampleDisabled is updated there
    // while creating a new style by example,
    // the corresponding value gets updated here too.
    void EnableNewByExample(bool newByExampleDisabled);

    // This function is used to set a hierarchical view.
    void SetHierarchical();
    // This function handles the controls while setting a filter except heirarchical
    void SetFilterControlsHandle();
    // Return whether treeview is visible
    // It is used in StyleList's UpdateStyles_Hdl
    // It is used to defaultly set the heirarchical view
    bool IsTreeView() { return m_xTreeBox->get_visible(); }

    // Dialog and StyleList have their own copies of m_nActFilter
    // When this value gets updated in Dialog's UpdateStyles_Hdl while setting a filter,
    // the corresponding value gets updated here too.
    void SetFilterIdx(sal_uInt16 filter) { m_nActFilter = filter; }

    // Helper function: Access to the current family item
    // Used in Dialog's updateStyleHandler, Execute_Impl etc...
    const SfxStyleFamilyItem* GetFamilyItem() const;
    // Used to get the current selected entry in treeview
    // Used in Dialog's Execute_Impl, Action_Select etc...
    OUString GetSelectedEntry() const;
    // Returns the Family Item at ith index
    // Used in Dialog's ReadResource_Hdl
    const SfxStyleFamilyItem& GetFamilyItemByIndex(size_t i) const;
    const SfxObjectShell* GetObjectShell() const { return m_pCurObjShell; }
    bool IsHierarchical() const { return m_bHierarchical; }

    void Enabledel(bool candel) { m_bCanDel = candel; }
    void Enablehide(bool canhide) { m_bCanHide = canhide; }
    void Enableshow(bool canshow) { m_bCanShow = canshow; }
    void Enablenew(bool cannew) { m_bCanNew = cannew; }
    void Enableedit(bool canedit) { m_bCanEdit = canedit; }
    // Handles the enabling/Disabling of Preview
    void EnablePreview(bool bCustomPreview);
    // Used in Dialog's Execute_Impl
    // It is a necessary condition to execute a style
    bool EnableExecute();

    void connect_UpdateStyles(const Link<StyleFlags, void>& rLink) { m_aUpdateStyles = rLink; }
    void connect_ReadResource(const Link<StyleList&, void>& rLink) { m_aReadResource = rLink; }
    void connect_ClearResource(const Link<void*, void>& rLink) { m_aClearResource = rLink; }
    void connect_LoadFactoryStyleFilter(const Link<SfxObjectShell const*, sal_Int32>& rLink);
    void connect_SaveSelection(const Link<void*, SfxObjectShell*> rLink);
    void connect_UpdateStyleDependents(const Link<void*, void> rLink);
    void connect_UpdateFamily(const Link<StyleList&, void> rLink) { m_aUpdateFamily = rLink; }

private:
    void FillTreeBox(SfxStyleFamily eFam);

    OUString getDefaultStyleName(const SfxStyleFamily eFam);
    SfxStyleFamily GetActualFamily() const;
    void GetSelectedStyle() const;

    sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper);
    void DropHdl(const OUString& rStyle, const OUString& rParent);

    void MenuSelect(const OString& rIdent);
    void PrepareMenu(const Point& rPos);
    void ShowMenu(const CommandEvent& rCEvt);
    void CreateContextMenu();

    void Notify(SfxBroadcaster& rBC, const SfxHint& rHint);

    // In which FamilyState do I have to look, in order to get the
    // information of the ith Family in the pStyleFamilies.
    sal_uInt16 StyleNrToInfoOffset(sal_uInt16 i);

    DECL_LINK(ReadResource, void*, size_t);
    DECL_LINK(Clear, void*, void);
    DECL_LINK(Cleanup, void*, void);
    DECL_LINK(ExecuteDrop, const ExecuteDropEvent&, sal_Int8);
    DECL_LINK(NewMenuExecuteAction, void*, void);
    DECL_LINK(IsSafeForWaterCan, void*, bool);
    DECL_LINK(HasSelectedStyle, void*, bool);
    DECL_LINK(UpdateFamily, void*, void);
    DECL_LINK(UpdateStyles, StyleFlags, void);
    DECL_LINK(UpdateStyleDependents, void*, void);
    DECL_LINK(TimeOut, Timer*, void);
    DECL_LINK(EnableTreeDrag, bool, void);
    DECL_LINK(EnableDelete, void*, void);
    DECL_LINK(FilterSelect, sal_uInt16, void);
    DECL_LINK(SetWaterCanState, const SfxBoolItem*, void);
    DECL_LINK(SetFamily, sal_uInt16, void);
    DECL_LINK(FamilySelect, sal_uInt16, void);

    void InvalidateBindings();

    void Update();
    Link<StyleFlags, void> m_aUpdateStyles;
    Link<StyleList&, void> m_aReadResource;
    Link<void*, void> m_aClearResource;
    Link<SfxObjectShell const*, sal_Int32> m_aLoadFactoryStyleFilter;
    Link<void*, SfxObjectShell*> m_aSaveSelection;
    Link<void*, void> m_aUpdateStyleDependents;
    Link<StyleList&, void> m_aUpdateFamily;

    void NewHdl();
    void EditHdl();
    void DeleteHdl();
    void HideHdl();
    void ShowHdl();

    DECL_LINK(DragBeginHdl, bool&, bool);
    DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
    DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString);
    DECL_LINK(CustomRenderHdl, weld::TreeView::render_args, void);
    DECL_LINK(FmtSelectHdl, weld::TreeView&, void);
    DECL_LINK(TreeListApplyHdl, weld::TreeView&, bool);
    DECL_LINK(MousePressHdl, const MouseEvent&, bool);
    DECL_STATIC_LINK(StyleList, CustomGetSizeHdl, weld::TreeView::get_size_args, Size);
    DECL_LINK(PopupFlatMenuHdl, const CommandEvent&, bool);
    DECL_LINK(PopupTreeMenuHdl, const CommandEvent&, bool);
    DECL_LINK(MenuSelectAsyncHdl, void*, void);

    bool m_bHierarchical : 1;

    bool m_bAllowReParentDrop : 1;
    bool m_bNewByExampleDisabled : 1;
    bool m_bDontUpdate : 1;
    bool m_bTreeDrag : 1;
    bool m_bCanEdit : 1;
    bool m_bCanHide : 1;
    bool m_bCanShow : 1;
    bool m_bCanNew : 1;
    bool m_bUpdateFamily : 1;
    bool m_bCanDel : 1;
    bool m_bBindingUpdate : 1;
    SfxStyleSheetBasePool* m_pStyleSheetPool;
    sal_uInt16 m_nActFilter;
    std::unique_ptr<weld::TreeView> m_xFmtLb;
    std::unique_ptr<weld::TreeView> m_xTreeBox;

    std::unique_ptr<weld::Builder> mxMenuBuilder;
    std::unique_ptr<weld::Menu> mxMenu;

    std::optional<SfxStyleFamilies> m_xStyleFamilies;
    std::array<std::unique_ptr<SfxTemplateItem>, MAX_FAMILIES> m_pFamilyState;
    SfxObjectShell* m_pCurObjShell;
    sal_uInt16 m_nActFamily;
    SfxStyleSearchBits m_nAppFilter;

    std::unique_ptr<TreeViewDropTarget> m_xTreeView1DropTargetHelper;
    std::unique_ptr<TreeViewDropTarget> m_xTreeView2DropTargetHelper;

    SfxCommonTemplateDialog_Impl* m_pParentDialog;
    SfxBindings* m_pBindings;
    std::array<std::unique_ptr<SfxTemplateControllerItem>, COUNT_BOUND_FUNC> pBoundItems;

    std::unique_ptr<Idle> pIdle;

    OString sLastItemIdent;
    SfxModule* m_Module;
    sal_uInt16 m_nModifier;
    weld::Container* m_pContainer;
};
diff --git a/sfx2/source/inc/templdgi.hxx b/sfx2/source/inc/templdgi.hxx
index 61d6de8..daedd86 100644
--- a/sfx2/source/inc/templdgi.hxx
+++ b/sfx2/source/inc/templdgi.hxx
@@ -41,6 +41,8 @@ class SfxTemplateControllerItem;

#include <vcl/idle.hxx>

#include "StyleList.hxx"

class SfxStyleFamilyItem;
class SfxTemplateItem;
class SfxBindings;
@@ -54,26 +56,14 @@ namespace com::sun::star::frame {
    class XModuleManager2;
}

enum class StyleFlags {
    NONE=0, UpdateFamilyList=1, UpdateFamily=2
};
namespace o3tl {
    template<> struct typed_flags<StyleFlags> : is_typed_flags<StyleFlags, 3> {};
}

class TreeViewDropTarget;

class SfxCommonTemplateDialog_Impl : public SfxListener
class SfxCommonTemplateDialog_Impl
{
private:
    class DeletionWatcher;
    friend class DeletionWatcher;

    void ReadResource();
    void ClearResource();
    void impl_clear();
    DeletionWatcher* impl_setDeletionWatcher(DeletionWatcher* pNewWatcher);
    OUString getDefaultStyleName( const SfxStyleFamily eFam );
    static OUString getDefaultStyleName( const SfxStyleFamily eFam, StyleList& rStyleList );

protected:
#define MAX_FAMILIES            6
@@ -82,177 +72,158 @@ protected:
    friend class SfxTemplateControllerItem;

    SfxBindings* pBindings;
    std::array<std::unique_ptr<SfxTemplateControllerItem>, COUNT_BOUND_FUNC> pBoundItems;

    weld::Container* mpContainer;
    std::unique_ptr<weld::Builder> mxMenuBuilder;
    std::unique_ptr<weld::Menu> mxMenu;
    OString sLastItemIdent;
    SfxModule* pModule;
    std::unique_ptr<Idle> pIdle;

    std::optional<SfxStyleFamilies> mxStyleFamilies;
    std::array<std::unique_ptr<SfxTemplateItem>, MAX_FAMILIES> pFamilyState;
    SfxStyleSheetBasePool* pStyleSheetPool;
    SfxObjectShell* pCurObjShell;
    css::uno::Reference<css::frame::XModuleManager2> xModuleManager;
    DeletionWatcher* m_pDeletionWatcher;

    std::unique_ptr<weld::TreeView> mxFmtLb;
    std::unique_ptr<weld::TreeView> mxTreeBox;
    StyleList m_aStyleList;
    std::unique_ptr<weld::CheckButton> mxPreviewCheckbox;
    std::unique_ptr<weld::ComboBox> mxFilterLb;
    std::unique_ptr<TreeViewDropTarget> m_xTreeView1DropTargetHelper;
    std::unique_ptr<TreeViewDropTarget> m_xTreeView2DropTargetHelper;

    sal_uInt16 nActFamily; // Id in the ToolBox = Position - 1
    sal_uInt16 nActFilter; // FilterIdx
    SfxStyleSearchBits nAppFilter; // Filter, which has set the application (for automatic)

    sal_uInt16 m_nModifier;
    bool bDontUpdate :1;
    bool bIsWater :1;
    bool bUpdate :1;
    bool bUpdateFamily :1;
    bool bCanEdit :1;
    bool bCanDel :1;
    bool bCanNew :1;
    bool bCanHide :1;
    bool bCanShow :1;
    bool bWaterDisabled :1;
    bool bNewByExampleDisabled :1;
    bool bUpdateByExampleDisabled :1;
    bool bTreeDrag :1;
    bool bAllowReParentDrop:1;
    bool bHierarchical :1;
    bool m_bWantHierarchical :1;
    bool bBindingUpdate :1;

    Link<void*, size_t> m_aStyleListReadResource;
    Link<void*, void> m_aStyleListClear;
    Link<void*, void> m_aStyleListCleanup;
    Link<const ExecuteDropEvent&, sal_Int8> m_aStyleListExecuteDrop;
    Link<void*, void> m_aStyleListNewMenu;
    Link<void*, bool> m_aStyleListWaterCan;
    Link<void*, bool> m_aStyleListHasSelectedStyle;
    Link<StyleFlags, void> m_aStyleListUpdateStyles;
    Link<void*, void> m_aStyleListUpdateFamily;
    Link<SfxHintId, void> m_aStyleListNotify;
    Link<void*, void> m_aStyleListUpdateStyleDependents;
    Link<bool, void> m_aStyleListEnableTreeDrag;
    Link<sal_uInt16, void> m_aStyleListFilterSelect;
    Link<void*, void> m_aStyleListEnableDelete;
    Link<const SfxBoolItem*, void> m_aStyleListSetWaterCanState;
    Link<sal_uInt16, void> m_aStyleListFamilySelect;
    Link<sal_uInt16, void> m_aStyleListSetFamily;

    DECL_LINK(FilterSelectHdl, weld::ComboBox&, void );
    DECL_LINK(FmtSelectHdl, weld::TreeView&, void);
    DECL_LINK(TreeListApplyHdl, weld::TreeView&, bool);
    DECL_LINK(MousePressHdl, const MouseEvent&, bool);
    DECL_LINK(TimeOut, Timer*, void );
    DECL_LINK(PreviewHdl, weld::Toggleable&, void);
    DECL_LINK(PopupFlatMenuHdl, const CommandEvent&, bool);
    DECL_LINK(PopupTreeMenuHdl, const CommandEvent&, bool);
    DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
    DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString);
    DECL_LINK(OnAsyncExecuteDrop, void *, void);
    DECL_LINK(DragBeginHdl, bool&, bool);
    DECL_LINK(CustomRenderHdl, weld::TreeView::render_args, void);
    DECL_STATIC_LINK(SfxCommonTemplateDialog_Impl, CustomGetSizeHdl, weld::TreeView::get_size_args, Size);

    void DropHdl(const OUString& rStyle, const OUString& rParent);

    virtual void EnableItem(const OString& /*rMesId*/, bool /*bCheck*/ = true)
    {}
    virtual void CheckItem(const OString& /*rMesId*/, bool /*bCheck*/ = true)
    {}
    virtual bool IsCheckedItem(const OString& /*rMesId*/ )
    {
        return true;
    }

    void InvalidateBindings();
    virtual void InsertFamilyItem(sal_uInt16 nId, const SfxStyleFamilyItem& rItem) = 0;
    virtual void EnableFamilyItem(sal_uInt16 nId, bool bEnabled) = 0;
    virtual void ClearFamilyList() = 0;
    virtual void ReplaceUpdateButtonByMenu();

    void NewHdl();
    void EditHdl();
    void DeleteHdl();
    void HideHdl();
    void ShowHdl();

    bool Execute_Impl(sal_uInt16 nId, const OUString& rStr, const OUString& rRefStr,
                      sal_uInt16 nFamily, SfxStyleSearchBits nMask = SfxStyleSearchBits::Auto,
                      sal_uInt16* pIdx = nullptr, const sal_uInt16* pModifier = nullptr );

    void UpdateStyles_Impl(StyleFlags nFlags);
    const SfxStyleFamilyItem* GetFamilyItem_Impl() const;
    bool IsInitialized() const
    {
        return nActFamily != 0xffff;
    }
    void EnableDelete();
    void Initialize();
    void EnableHierarchical(bool);
    void EnableHierarchical(bool, StyleList& rStyleList);

    void FilterSelect( sal_uInt16 nFilterIdx, bool bForce );
    void SetFamilyState( sal_uInt16 nSlotId, const SfxTemplateItem* );
    void SetWaterCanState( const SfxBoolItem* pItem );
    bool IsSafeForWaterCan() const;

    void SelectStyle(const OUString& rStyle, bool bIsCallback);
    void UpdateStyleDependents();
    bool HasSelectedStyle() const;
    void GetSelectedStyle() const;
    void FillTreeBox();
    void Update_Impl();
    void UpdateFamily_Impl();

    // In which FamilyState do I have to look, in order to get the
    // information of the ith Family in the pStyleFamilies.
    sal_uInt16 StyleNrToInfoOffset( sal_uInt16 i );

    void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;

    void FamilySelect( sal_uInt16 nId, bool bPreviewRefresh = false );
    void SetFamily(SfxStyleFamily nFamily);
    void ActionSelect(const OString& rId);
    void ActionSelect(const OString& rId, StyleList& rStyleList);

    sal_Int32 LoadFactoryStyleFilter( SfxObjectShell const * i_pObjSh );
    void SaveFactoryStyleFilter( SfxObjectShell const * i_pObjSh, sal_Int32 i_nFilter );
    SfxObjectShell* SaveSelection();
    void SaveFactoryStyleFilter(SfxObjectShell const* i_pObjSh, sal_Int32 i_nFilter);

    void PrepareMenu(const Point& rPos);
    void ShowMenu(const CommandEvent& rCEvt);
    DECL_LINK(ReadResource_Hdl, StyleList&, void);
    DECL_LINK(ClearResource_Hdl, void*, void);
    DECL_LINK(SaveSelection_Hdl, void*, SfxObjectShell*);
    DECL_LINK(LoadFactoryStyleFilter_Hdl, SfxObjectShell const*, sal_Int32);
    DECL_LINK(UpdateStyles_Hdl, StyleFlags, void);
    DECL_LINK(UpdateFamily_Hdl, StyleList&, void);
    DECL_LINK(UpdateStyleDependents_Hdl, void*, void);

public:
    // Used in StyleList::NewMenuExecuteAction, StyleList::UpdateStyleDependents, StyleList::NewHdl,  EditHdl...
    // It comes into action whenever an existing style is selected for use, or a new style is created etc..
    bool Execute_Impl(sal_uInt16 nId, const OUString& rStr, const OUString& rRefStr,
                      sal_uInt16 nFamily, StyleList& rStyleList, SfxStyleSearchBits nMask = SfxStyleSearchBits::Auto,
                      sal_uInt16* pIdx = nullptr, const sal_uInt16* pModifier = nullptr);

    SfxCommonTemplateDialog_Impl(SfxBindings* pB, weld::Container*, weld::Builder* pBuilder);
    virtual ~SfxCommonTemplateDialog_Impl() override;

    void MenuSelect(const OString& rIdent);
    DECL_LINK( MenuSelectAsyncHdl, void*, void );

    virtual void EnableEdit( bool b )
    {
        bCanEdit = b;
    }
    void EnableDel( bool b )
    {
        bCanDel = b;
    }
    void EnableNew( bool b )
    {
        bCanNew = b;
    }
    void EnableHide( bool b )
    {
        bCanHide = b;
    }
    void EnableShow( bool b )
    {
        bCanShow = b;
    }

    void EnableTreeDrag(bool b);
    void EnableExample_Impl(sal_uInt16 nId, bool bEnable);
    SfxStyleFamily GetActualFamily() const;
    OUString GetSelectedEntry() const;

    SfxObjectShell* GetObjectShell() const
    {
        return pCurObjShell;
    }

    sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper);
    // This function handles drop of content into the treeview to create a new style
    sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
    // This function is used when a newstyle is created
    DECL_LINK(OnAsyncExecuteDrop, void*, void);

    void CreateContextMenu();
    // Used in StyleList::UpdateStyles, StyleList::Update
    // Whenever a new family(Eg. Character, List etc.) is selected it comes into action
    void FamilySelect(sal_uInt16 nId, bool bPreviewRefresh = false);

    // Constructor
    SfxCommonTemplateDialog_Impl(SfxBindings* pB, weld::Container*, weld::Builder* pBuilder);

    // Destructor
    virtual ~SfxCommonTemplateDialog_Impl();

    // Used in StyleList::SelectStyle, StyleList::Notify, IMPL_LINK(PopupFlatMenuHdl)
    // These functions are used when a style is edited, deleted, created etc..
    virtual void EnableEdit(bool b) { m_aStyleList.Enableedit(b); }
    void EnableDel(bool b) { m_aStyleList.Enabledel(b); }
    void EnableNew(bool b) { m_aStyleList.Enablenew(b); }
    void EnableHide(bool b) { m_aStyleList.Enablehide(b); }
    void EnableShow(bool b) { m_aStyleList.Enableshow(b); }

    // Used in TreeDrag
    void EnableTreeDrag(bool b);
    // Dialog and StyleList have their own copies of variable bTreeDrag.
    // When TreeDrag is enabled in StyleList, the value of m_bTreeDrag is updated in StyleList
    // This function updates the value of bTreeDrag here too.
    void SetEnableDrag(bool treedrag) { bTreeDrag = treedrag; }
    // It comes into action when a style is created or updated or newmenu is created
    void EnableExample_Impl(sal_uInt16 nId, bool bEnable);

    // This comes into action when a family is selected or a style is applied for use
    virtual void CheckItem(const OString& /*rMesId*/, bool /*bCheck*/ = true) {}
    // This is used for watercan or when newmenu or watercan is enabled or updated
    virtual void EnableItem(const OString& /*rMesId*/, bool /*bCheck*/ = true) {}
    // This is used for watercan
    virtual bool IsCheckedItem(const OString& /*rMesId*/) { return true; }

    // This is used when a style is selected
    void SelectStyle(const OUString& rStyle, bool bIsCallback, StyleList& rStyleList);

    // Dialog and StyleList have their own copies of variable nAppFilter.
    // When a filter is applied, it comes into action and updates the value of nAppFilter
    void SetApplicationFilter(SfxStyleSearchBits filter) { nAppFilter = filter; }
    // Dialog and StyleList have their own copies of variable nActFilter.
    // When a filter is applied, it comes into action and updates the value of nActFilter
    void SetFilterByIndex(sal_uInt16 filter) { nActFilter = filter; }

    // This function return the value of bUpdate in Stylelist
    // This value is used in StyleList's Notify
    bool GetNotifyUpdate() { return bUpdate; }
    // This function sets the value of bUpdate in Dialog
    // This function is used in StyleList's Notify to update the value of bUpdate when required
    void SetNotifyupdate(bool b) { bUpdate = b; }

    void connect_stylelist_read_resource(const Link<void*, size_t>& rLink) { m_aStyleListReadResource = rLink; }
    void connect_stylelist_clear(const Link<void*, void>& rLink) { m_aStyleListClear = rLink; }
    void connect_stylelist_cleanup(const Link<void*, void>& rLink) { m_aStyleListCleanup = rLink; }
    void connect_stylelist_execute_drop(const Link<const ExecuteDropEvent&, sal_Int8>& rLink);
    void connect_stylelist_execute_new_menu(const Link<void*, void>& rLink) { m_aStyleListNewMenu = rLink; }
    void connect_stylelist_for_watercan(const Link<void*, bool>& rLink) { m_aStyleListWaterCan = rLink; }
    void connect_stylelist_has_selected_style(const Link<void*, bool>& rLink);
    void connect_stylelist_update_styles(const Link<StyleFlags, void> rLink) { m_aStyleListUpdateStyles = rLink; }
    void connect_stylelist_update_family(const Link<void*, void> rLink) { m_aStyleListUpdateFamily = rLink; }
    void connect_stylelist_update_style_dependents(const Link<void*, void>& rLink);
    void connect_stylelist_enable_tree_drag(const Link<bool, void> rLink);
    void connect_stylelist_notify(const Link<SfxHintId, void> rLink) { m_aStyleListNotify = rLink; }
    void connect_stylelist_filter_select(Link<sal_uInt16, void> rLink);
    void connect_stylelist_enable_delete(const Link<void*, void> rLink);
    void connect_stylelist_set_water_can_state(const Link<const SfxBoolItem*, void> rLink);
    void connect_family_select(const Link<sal_uInt16, void> rLink);
    void connect_set_family(const Link<sal_uInt16, void> rLink) { m_aStyleListSetFamily = rLink; }
};

class ToolbarDropTarget;