Rebased ref, commits from common ancestor: commit 350f994d43660b75bfd21990edabdb1c8adb839e Author: Rafael Lima <rafael.palma.l...@gmail.com> AuthorDate: Fri Jul 30 15:53:01 2021 +0200 Commit: Gerrit Code Review <ger...@gerrit.libreoffice.org> CommitDate: Fri Jul 30 15:53:01 2021 +0200
Update git submodules * Update helpcontent2 from branch 'master' to 1951014d9e7c5270904789c2964d35fca8487134 - Rewrite SF_Services with Python support focusing user scripts only Change-Id: Ib3748c3fbe43e25e3a9aa895519f08ec3b11b953 Reviewed-on: https://gerrit.libreoffice.org/c/help/+/119612 Tested-by: Jenkins Reviewed-by: Jean-Pierre Ledure <j...@ledure.be> diff --git a/helpcontent2 b/helpcontent2 index 4a07d8d492c5..1951014d9e7c 160000 --- a/helpcontent2 +++ b/helpcontent2 @@ -1 +1 @@ -Subproject commit 4a07d8d492c50f0e2db3200790f92e9e18bb5144 +Subproject commit 1951014d9e7c5270904789c2964d35fca8487134 commit 66fceca24ee0fccd03f23afc689d82c794a2d57e Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Fri Jul 30 14:29:27 2021 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Fri Jul 30 15:23:52 2021 +0200 osl::Mutex->std::mutex in FmXDisposeListener Change-Id: I213499d4c707194c516cafe2ee323e61566cac71 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119706 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/include/svx/fmtools.hxx b/include/svx/fmtools.hxx index 1ead9069b4f0..869023f06f7f 100644 --- a/include/svx/fmtools.hxx +++ b/include/svx/fmtools.hxx @@ -31,6 +31,7 @@ #include <rtl/ref.hxx> #include <cppuhelper/implbase.hxx> #include <o3tl/sorted_vector.hxx> +#include <mutex> namespace com::sun::star::awt { class XWindow; } namespace com::sun::star::beans { class XPropertySet; } @@ -132,7 +133,7 @@ class SAL_WARN_UNUSED FmXDisposeListener friend class FmXDisposeMultiplexer; rtl::Reference<FmXDisposeMultiplexer> m_pAdapter; - osl::Mutex m_aMutex; + std::mutex m_aMutex; public: virtual ~FmXDisposeListener(); diff --git a/svx/source/form/fmtools.cxx b/svx/source/form/fmtools.cxx index e9f641309d0b..e8e0a5e1a328 100644 --- a/svx/source/form/fmtools.cxx +++ b/svx/source/form/fmtools.cxx @@ -235,7 +235,7 @@ FmXDisposeListener::~FmXDisposeListener() void FmXDisposeListener::setAdapter(FmXDisposeMultiplexer* pAdapter) { - ::osl::MutexGuard aGuard(m_aMutex); + std::lock_guard aGuard(m_aMutex); m_pAdapter = pAdapter; } commit 7b5922eb666e5f153060468b271d99510adb422e Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Fri Jul 30 10:10:55 2021 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Fri Jul 30 14:07:43 2021 +0200 osl::Mutex->std::mutex in DispatchHelper Change-Id: I6443f604f7f5cacc4b3d67bb6dab07706c82a9a7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119700 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/framework/source/services/dispatchhelper.cxx b/framework/source/services/dispatchhelper.cxx index 380eab11ec67..cfa4a8a2bbe1 100644 --- a/framework/source/services/dispatchhelper.cxx +++ b/framework/source/services/dispatchhelper.cxx @@ -53,6 +53,7 @@ css::uno::Sequence<OUString> SAL_CALL DispatchHelper::getSupportedServiceNames() */ DispatchHelper::DispatchHelper(const css::uno::Reference<css::uno::XComponentContext>& xContext) : m_xContext(xContext) + , m_aBlockFlag(false) { } @@ -91,11 +92,12 @@ css::uno::Any SAL_CALL DispatchHelper::executeDispatch( } // parse given URL + css::uno::Reference<css::util::XURLTransformer> xParser; /* SAFE { */ - osl::ClearableMutexGuard aReadLock(m_mutex); - css::uno::Reference<css::util::XURLTransformer> xParser - = css::util::URLTransformer::create(m_xContext); - aReadLock.clear(); + { + std::lock_guard aReadLock(m_mutex); + xParser = css::util::URLTransformer::create(m_xContext); + } /* } SAFE */ css::util::URL aURL; @@ -148,16 +150,18 @@ DispatchHelper::executeDispatch(const css::uno::Reference<css::frame::XDispatch> css::uno::UNO_QUERY); /* SAFE { */ { - osl::MutexGuard aWriteLock(m_mutex); + std::lock_guard aWriteLock(m_mutex); m_xBroadcaster = xNotifyDispatch; - m_aBlock.reset(); + m_aBlockFlag = false; } /* } SAFE */ // dispatch it and wait for a notification // TODO/MBA: waiting in main thread?! xNotifyDispatch->dispatchWithNotification(aURL, aArguments, xListener); - m_aBlock.wait(); // wait for result + + std::unique_lock aWriteLock(m_mutex); + m_aBlock.wait(aWriteLock, [this] { return m_aBlockFlag; }); // wait for result } else { @@ -180,9 +184,10 @@ DispatchHelper::executeDispatch(const css::uno::Reference<css::frame::XDispatch> */ void SAL_CALL DispatchHelper::dispatchFinished(const css::frame::DispatchResultEvent& aResult) { - osl::MutexGuard g(m_mutex); + std::lock_guard g(m_mutex); m_aResult <<= aResult; - m_aBlock.set(); + m_aBlockFlag = true; + m_aBlock.notify_one(); m_xBroadcaster.clear(); } @@ -193,9 +198,10 @@ void SAL_CALL DispatchHelper::dispatchFinished(const css::frame::DispatchResultE */ void SAL_CALL DispatchHelper::disposing(const css::lang::EventObject&) { - osl::MutexGuard g(m_mutex); + std::lock_guard g(m_mutex); m_aResult.clear(); - m_aBlock.set(); + m_aBlockFlag = true; + m_aBlock.notify_one(); m_xBroadcaster.clear(); } } diff --git a/include/framework/dispatchhelper.hxx b/include/framework/dispatchhelper.hxx index f362f30ab633..ca7e2b2ccf12 100644 --- a/include/framework/dispatchhelper.hxx +++ b/include/framework/dispatchhelper.hxx @@ -28,7 +28,8 @@ #include <cppuhelper/implbase.hxx> #include <framework/fwkdllapi.h> -#include <osl/conditn.hxx> +#include <condition_variable> +#include <mutex> namespace com::sun::star::lang { @@ -57,17 +58,15 @@ class UNLESS_MERGELIBS(FWK_DLLPUBLIC) DispatchHelper final : public ::cppu::WeakImplHelper<css::lang::XServiceInfo, css::frame::XDispatchHelper, css::frame::XDispatchResultListener> { - // member - -private: - osl::Mutex m_mutex; + std::mutex m_mutex; /** global uno service manager. Can be used to create own needed services. */ css::uno::Reference<css::uno::XComponentContext> m_xContext; /** used to wait for asynchronous listener callbacks. */ - ::osl::Condition m_aBlock; + std::condition_variable m_aBlock; + bool m_aBlockFlag; css::uno::Any m_aResult; commit 74f4a1796f94477d459c71d0a0aaa8f4a430e208 Author: Gopi Krishna Menon <gopi.me...@collabora.com> AuthorDate: Thu Jul 29 15:21:13 2021 +0530 Commit: Tor Lillqvist <t...@collabora.com> CommitDate: Fri Jul 30 13:07:49 2021 +0200 Fix Nesting Level Bug in ProfileZone Moves the profile zone global nesting variable into the source from header and makes it threadlocal Change-Id: I97751f5c532d8e0e36adb7d9d383bd88f752953f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119662 Tested-by: Jenkins Reviewed-by: Tor Lillqvist <t...@collabora.com> diff --git a/comphelper/source/misc/traceevent.cxx b/comphelper/source/misc/traceevent.cxx index c379bbb97f7e..8b1a9c09427a 100644 --- a/comphelper/source/misc/traceevent.cxx +++ b/comphelper/source/misc/traceevent.cxx @@ -29,7 +29,8 @@ std::size_t TraceEvent::s_nBufferSize = 0; void (*TraceEvent::s_pBufferFullCallback)() = nullptr; int AsyncEvent::s_nIdCounter = 0; -int ProfileZone::s_nNesting = 0; + +static thread_local int nProfileZoneNesting = 0; // Level of Nested Profile Zones namespace { @@ -134,6 +135,10 @@ void ProfileZone::addRecording() + OUString::number(osl_getThreadIdentifier(nullptr)) + "},"); } +int ProfileZone::getNestingLevel() { return nProfileZoneNesting; } + +void ProfileZone::setNestingLevel(int nNestingLevel) { nProfileZoneNesting = nNestingLevel; } + } // namespace comphelper /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/comphelper/profilezone.hxx b/include/comphelper/profilezone.hxx index b96b26baffc1..71f9fa30b6dc 100644 --- a/include/comphelper/profilezone.hxx +++ b/include/comphelper/profilezone.hxx @@ -22,13 +22,14 @@ namespace comphelper { class COMPHELPER_DLLPUBLIC ProfileZone : public NamedEvent { - static int s_nNesting; // level of nested zones. - long long m_nCreateTime; int m_nNesting; void addRecording(); + static void setNestingLevel(int nNestingLevel); + static int getNestingLevel(); + ProfileZone(const char* sName, const OUString& sArgs) : NamedEvent(sName, sArgs) , m_nNesting(-1) @@ -37,7 +38,8 @@ class COMPHELPER_DLLPUBLIC ProfileZone : public NamedEvent { m_nCreateTime = getNow(); - m_nNesting = s_nNesting++; + m_nNesting = getNestingLevel(); + setNestingLevel(getNestingLevel() + 1); } else m_nCreateTime = 0; @@ -65,9 +67,9 @@ public: { if (m_nCreateTime > 0) { - s_nNesting--; + setNestingLevel(getNestingLevel() - 1); - if (m_nNesting != s_nNesting) + if (m_nNesting != getNestingLevel()) { SAL_WARN("comphelper.traceevent", "Incorrect ProfileZone nesting for " << m_sName); } commit 172f589471edcac9a4974132a3145b721942879a Author: Anshu <anshukhar...@gmail.com> AuthorDate: Sat Jun 26 08:34:06 2021 +0530 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Fri Jul 30 12:14:24 2021 +0200 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.kagan...@collabora.com> diff --git a/sfx2/Library_sfx.mk b/sfx2/Library_sfx.mk index fff97d011a02..39b5438c65a2 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 000000000000..8525c620b2dd --- /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 8951cfb71cbf..ae0d646abc75 100644 --- a/sfx2/source/dialog/templdlg.cxx +++ b/sfx2/source/dialog/templdlg.cxx @@ -110,415 +110,87 @@ 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; + ActionSelect("new", m_aStyleList); } -IMPL_LINK(SfxCommonTemplateDialog_Impl, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString) +SfxTemplatePanelControl::SfxTemplatePanelControl(SfxBindings* pBindings, weld::Widget* pParent) + : PanelLayout(pParent, "TemplatePanel", "sfx/ui/templatepanel.ui") + , pImpl(new SfxTemplateDialog_Impl(pBindings, this)) { - 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; + OSL_ASSERT(pBindings!=nullptr); } -IMPL_STATIC_LINK(SfxCommonTemplateDialog_Impl, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size) +SfxTemplatePanelControl::~SfxTemplatePanelControl() { - vcl::RenderContext& rRenderContext = aPayload.first; - return Size(42, 32 * rRenderContext.GetDPIScaleFactor()); } -IMPL_LINK(SfxCommonTemplateDialog_Impl, CustomRenderHdl, weld::TreeView::render_args, aPayload, void) +namespace SfxTemplate { - 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) + // converts from SFX_STYLE_FAMILY Ids to 1-6 + static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily) { - const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl(); - SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(rId, pItem->GetFamily()); - - if (pStyleSheet) + switch ( nFamily ) { - 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(); + 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; } } - - if (!bSuccess) - rRenderContext.DrawText(aRect, rId, DrawTextFlags::Left | DrawTextFlags::VCenter); - - rRenderContext.Pop(); } -IMPL_LINK(SfxCommonTemplateDialog_Impl, PopupFlatMenuHdl, const CommandEvent&, rCEvt, bool) +void SfxCommonTemplateDialog_Impl::connect_stylelist_execute_drop( + const Link<const ExecuteDropEvent&, sal_Int8>& rLink) { - if (rCEvt.GetCommand() != CommandEventId::ContextMenu) - return false; - - PrepareMenu(rCEvt.GetMousePosPixel()); - - if (mxFmtLb->count_selected_rows() <= 0) - { - EnableEdit(false); - EnableDel(false); - } - - ShowMenu(rCEvt); - - return true; + m_aStyleListExecuteDrop = rLink; } -void SfxCommonTemplateDialog_Impl::PrepareMenu(const Point& rPos) +void SfxCommonTemplateDialog_Impl::connect_stylelist_has_selected_style(const Link<void*, bool>& rLink) { - 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); - } + m_aStyleListHasSelectedStyle = rLink; } -void SfxCommonTemplateDialog_Impl::ShowMenu(const CommandEvent& rCEvt) +void SfxCommonTemplateDialog_Impl::connect_stylelist_update_style_dependents(const Link<void*, void>& rLink) { - 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); + m_aStyleListUpdateStyleDependents = rLink; } -IMPL_LINK(SfxCommonTemplateDialog_Impl, PopupTreeMenuHdl, const CommandEvent&, rCEvt, bool) +void SfxCommonTemplateDialog_Impl::connect_stylelist_enable_tree_drag(const Link<bool, void> rLink) { - if (rCEvt.GetCommand() != CommandEventId::ContextMenu) - return false; - - PrepareMenu(rCEvt.GetMousePosPixel()); - - ShowMenu(rCEvt); - - return true; + m_aStyleListEnableTreeDrag = rLink; } -SfxTemplatePanelControl::SfxTemplatePanelControl(SfxBindings* pBindings, weld::Widget* pParent) - : PanelLayout(pParent, "TemplatePanel", "sfx/ui/templatepanel.ui") - , pImpl(new SfxTemplateDialog_Impl(pBindings, this)) -{ - OSL_ASSERT(pBindings!=nullptr); -} - -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) +void SfxCommonTemplateDialog_Impl::connect_stylelist_filter_select(Link<sal_uInt16, void> rLink) { - 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; - }); + m_aStyleListFilterSelect = rLink; } -static bool IsExpanded_Impl( const std::vector<OUString>& rEntries, - std::u16string_view rStr) +void SfxCommonTemplateDialog_Impl::connect_stylelist_enable_delete(const Link<void*, void> rLink) { - for (const auto & rEntry : rEntries) - { - if (rEntry == rStr) - return true; - } - return false; + m_aStyleListEnableDelete = rLink; } -static void FillBox_Impl(weld::TreeView& rBox, - StyleTree_Impl* pEntry, - const std::vector<OUString>& rEntries, - SfxStyleFamily eStyleFamily, - const weld::TreeIter* pParent) +void SfxCommonTemplateDialog_Impl::connect_stylelist_set_water_can_state( + const Link<const SfxBoolItem*, void> rLink) { - 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()); + m_aStyleListSetWaterCanState = rLink; } -namespace SfxTemplate +void SfxCommonTemplateDialog_Impl::connect_family_select(const Link<sal_uInt16, void> rLink) { - // 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; - } - } + 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,392 +268,40 @@ 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)); ... etc. - the rest is truncated