Use COMReference to handle COM pointers in CreateShortcut
[LibreOffice.git] / sfx2 / source / dialog / StyleList.cxx
blobb63059e14ee94fa4b9ab692cd2e005fc9ea4ec2f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <unordered_map>
23 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <utility>
27 #include <vcl/commandevent.hxx>
28 #include <vcl/commandinfoprovider.hxx>
29 #include <vcl/event.hxx>
30 #include <vcl/settings.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/weldutils.hxx>
33 #include <vcl/window.hxx>
34 #include <svl/intitem.hxx>
35 #include <svl/style.hxx>
36 #include <svl/itemset.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <officecfg/Office/Common.hxx>
40 #include <osl/diagnose.h>
41 #include <sfx2/dispatch.hxx>
42 #include <sfx2/bindings.hxx>
43 #include <templdgi.hxx>
44 #include <tplcitem.hxx>
45 #include <sfx2/styfitem.hxx>
46 #include <sfx2/objsh.hxx>
47 #include <sfx2/viewsh.hxx>
48 #include <sfx2/newstyle.hxx>
49 #include <sfx2/tplpitem.hxx>
50 #include <sfx2/sfxresid.hxx>
52 #include <sfx2/sfxsids.hrc>
53 #include <sfx2/strings.hrc>
54 #include <sfx2/docfac.hxx>
55 #include <sfx2/module.hxx>
56 #include <helpids.h>
57 #include <sfx2/viewfrm.hxx>
59 #include <comphelper/string.hxx>
61 #include <sfx2/StyleManager.hxx>
62 #include <sfx2/StylePreviewRenderer.hxx>
64 #include <StyleList.hxx>
66 #include <vcl/virdev.hxx>
67 #include <basegfx/color/bcolortools.hxx>
68 #include <random>
70 using namespace css;
71 using namespace css::beans;
72 using namespace css::frame;
73 using namespace css::uno;
75 class TreeViewDropTarget final : public DropTargetHelper
77 private:
78 StyleList& m_rParent;
80 public:
81 TreeViewDropTarget(StyleList& rStyleList, weld::TreeView& rTreeView)
82 : DropTargetHelper(rTreeView.get_drop_target())
83 , m_rParent(rStyleList)
87 virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
89 return m_rParent.AcceptDrop(rEvt, *this);
92 virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
94 return m_rParent.ExecuteDrop(rEvt);
98 namespace
100 Color ColorHash(std::u16string_view rString)
102 static constexpr auto aSaturationArray = std::to_array<sal_uInt16>({ 90, 75, 60 });
103 static constexpr auto aBrightnessArray = std::to_array<sal_uInt16>({ 100, 80, 60 });
104 static constexpr auto aTintOrShadeArray
105 = std::to_array<sal_Int16>({ 1'500, 3'000, 4'500, 6'500, 7'500 });
107 sal_uInt32 nStringHash = rtl_ustr_hashCode_WithLength(rString.data(), rString.length());
109 // Twist the hash number with a RNG twister so we can get very different number even when the string hash
110 // differs only slightly. For example "Heading 1" and "Heading 2" are very close, so we would get a color
111 // that is very similar and with number quantization could result in the same color.
112 std::mt19937 twister;
113 twister.seed(nStringHash); // setting the hash for
114 nStringHash = twister();
116 double fHue = (nStringHash % 60) * 6;
117 nStringHash = nStringHash / 60;
119 double fSaturation = aSaturationArray[nStringHash % aSaturationArray.size()];
120 nStringHash = nStringHash / aSaturationArray.size();
122 double fBrightness = aBrightnessArray[nStringHash % aBrightnessArray.size()];
123 nStringHash = nStringHash / aBrightnessArray.size();
125 auto aColor = Color::HSBtoRGB(fHue, fSaturation, fBrightness);
126 double fTintOrShade = aTintOrShadeArray[nStringHash % aTintOrShadeArray.size()];
127 aColor.ApplyTintOrShade(fTintOrShade);
129 return aColor;
132 // used to disallow the default character style in the styles highlighter character styles color map
133 std::optional<OUString> sDefaultCharStyleUIName;
136 // Constructor
138 StyleList::StyleList(weld::Builder* pBuilder, SfxBindings* pBindings,
139 SfxCommonTemplateDialog_Impl* Parent, weld::Container* pC,
140 const OUString& treeviewname, const OUString& flatviewname)
141 : m_bHierarchical(false)
142 , m_bAllowReParentDrop(false)
143 , m_bNewByExampleDisabled(false)
144 , m_bDontUpdate(false)
145 , m_bTreeDrag(true)
146 , m_bCanEdit(false)
147 , m_bCanHide(true)
148 , m_bCanShow(false)
149 , m_bCanNew(true)
150 , m_bUpdateFamily(false)
151 , m_bCanDel(false)
152 , m_bBindingUpdate(true)
153 , m_pStyleSheetPool(nullptr)
154 , m_nActFilter(0)
155 , m_xFmtLb(pBuilder->weld_tree_view(flatviewname))
156 , m_xTreeBox(pBuilder->weld_tree_view(treeviewname))
157 , m_pCurObjShell(nullptr)
158 , m_nActFamily(0xffff)
159 , m_nAppFilter(SfxStyleSearchBits::Auto)
160 , m_pParentDialog(Parent)
161 , m_pBindings(pBindings)
162 , m_Module(nullptr)
163 , m_nModifier(0)
164 , m_pContainer(pC)
166 m_xFmtLb->set_help_id(HID_TEMPLATE_FMT);
168 uno::Reference<frame::XFrame> xFrame
169 = m_pBindings->GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface();
170 m_bModuleHasStylesHighlighterFeature
171 = vcl::CommandInfoProvider::GetModuleIdentifier(xFrame) == "com.sun.star.text.TextDocument";
174 // Destructor
176 StyleList::~StyleList() {}
178 // Called in the destructor of Dialog
179 // Cleans up the StyleList individual components while closing the application
180 IMPL_LINK_NOARG(StyleList, Cleanup, void*, void)
182 if (m_pStyleSheetPool)
183 EndListening(*m_pStyleSheetPool);
184 m_pStyleSheetPool = nullptr;
185 m_xTreeView1DropTargetHelper.reset();
186 m_xTreeView2DropTargetHelper.reset();
187 m_xTreeBox.reset();
188 m_xFmtLb.reset();
189 pIdle.reset();
192 void StyleList::CreateContextMenu()
194 if (m_bBindingUpdate)
196 m_pBindings->Invalidate(SID_STYLE_NEW, true);
197 m_pBindings->Update(SID_STYLE_NEW);
198 m_bBindingUpdate = false;
200 mxMenu.reset();
201 mxMenuBuilder = Application::CreateBuilder(m_pContainer, u"sfx/ui/stylecontextmenu.ui"_ustr);
202 mxMenu = mxMenuBuilder->weld_menu(u"menu"_ustr);
203 mxMenu->set_sensitive(u"edit"_ustr, m_bCanEdit);
204 mxMenu->set_sensitive(u"delete"_ustr, m_bCanDel);
205 mxMenu->set_sensitive(u"new"_ustr, m_bCanNew);
206 mxMenu->set_sensitive(u"hide"_ustr, m_bCanHide);
207 mxMenu->set_sensitive(u"show"_ustr, m_bCanShow);
209 const SfxStyleFamilyItem* pItem = GetFamilyItem();
210 if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
212 mxMenu->set_sensitive(u"edit"_ustr, false);
213 mxMenu->set_sensitive(u"new"_ustr, false);
215 if (pItem && pItem->GetFamily() == SfxStyleFamily::Pseudo)
217 const OUString aTemplName(GetSelectedEntry());
218 if (aTemplName == "No List")
220 mxMenu->set_sensitive(u"edit"_ustr, false);
221 mxMenu->set_sensitive(u"new"_ustr, false);
222 mxMenu->set_sensitive(u"hide"_ustr, false);
227 IMPL_LINK_NOARG(StyleList, ReadResource, void*, size_t)
229 // Read global user resource
230 for (auto& i : m_pFamilyState)
231 i.reset();
233 SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
234 m_pCurObjShell = pViewFrame->GetObjectShell();
235 m_Module = m_pCurObjShell ? m_pCurObjShell->GetModule() : nullptr;
236 if (m_Module)
237 m_xStyleFamilies = m_Module->CreateStyleFamilies();
238 if (!m_xStyleFamilies)
239 m_xStyleFamilies.emplace();
241 m_nActFilter = 0xffff;
243 if (m_pCurObjShell)
245 m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(m_pCurObjShell));
246 if (0xffff == m_nActFilter)
248 m_nActFilter = m_pCurObjShell->GetAutoStyleFilterIndex();
250 if (m_bModuleHasStylesHighlighterFeature)
251 sDefaultCharStyleUIName = getDefaultStyleName(SfxStyleFamily::Char);
253 size_t nCount = m_xStyleFamilies->size();
254 m_pBindings->ENTERREGISTRATIONS();
256 size_t i;
257 for (i = 0; i < nCount; ++i)
259 sal_uInt16 nSlot = 0;
260 switch (m_xStyleFamilies->at(i).GetFamily())
262 case SfxStyleFamily::Char:
263 nSlot = SID_STYLE_FAMILY1;
264 break;
265 case SfxStyleFamily::Para:
266 nSlot = SID_STYLE_FAMILY2;
267 break;
268 case SfxStyleFamily::Frame:
269 nSlot = SID_STYLE_FAMILY3;
270 break;
271 case SfxStyleFamily::Page:
272 nSlot = SID_STYLE_FAMILY4;
273 break;
274 case SfxStyleFamily::Pseudo:
275 nSlot = SID_STYLE_FAMILY5;
276 break;
277 case SfxStyleFamily::Table:
278 nSlot = SID_STYLE_FAMILY6;
279 break;
280 default:
281 OSL_FAIL("unknown StyleFamily");
282 break;
284 pBoundItems[i].reset(new SfxTemplateControllerItem(nSlot, *m_pParentDialog, *m_pBindings));
286 pBoundItems[i++].reset(
287 new SfxTemplateControllerItem(SID_STYLE_WATERCAN, *m_pParentDialog, *m_pBindings));
288 pBoundItems[i++].reset(
289 new SfxTemplateControllerItem(SID_STYLE_NEW_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
290 pBoundItems[i++].reset(
291 new SfxTemplateControllerItem(SID_STYLE_UPDATE_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
292 pBoundItems[i++].reset(
293 new SfxTemplateControllerItem(SID_STYLE_NEW, *m_pParentDialog, *m_pBindings));
294 pBoundItems[i++].reset(
295 new SfxTemplateControllerItem(SID_STYLE_DRAGHIERARCHIE, *m_pParentDialog, *m_pBindings));
296 pBoundItems[i++].reset(
297 new SfxTemplateControllerItem(SID_STYLE_EDIT, *m_pParentDialog, *m_pBindings));
298 pBoundItems[i++].reset(
299 new SfxTemplateControllerItem(SID_STYLE_DELETE, *m_pParentDialog, *m_pBindings));
300 pBoundItems[i++].reset(
301 new SfxTemplateControllerItem(SID_STYLE_FAMILY, *m_pParentDialog, *m_pBindings));
302 m_pBindings->LEAVEREGISTRATIONS();
304 for (; i < COUNT_BOUND_FUNC; ++i)
305 pBoundItems[i] = nullptr;
307 StartListening(*m_pBindings);
309 for (i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++)
310 m_pBindings->Update(i);
312 return nCount;
315 void StyleList::EnableNewByExample(bool newByExampleDisabled)
317 m_bNewByExampleDisabled = newByExampleDisabled;
320 void StyleList::FilterSelect(sal_uInt16 nActFilter, bool bsetFilter)
322 m_nActFilter = nActFilter;
323 if (bsetFilter)
325 SfxObjectShell* const pDocShell = m_aSaveSelection.Call(*this);
326 SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
327 m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
328 if (pOldStyleSheetPool != m_pStyleSheetPool)
330 if (pOldStyleSheetPool)
331 EndListening(*pOldStyleSheetPool);
332 if (m_pStyleSheetPool)
333 StartListening(*m_pStyleSheetPool);
336 UpdateStyles(StyleFlags::UpdateFamilyList);
339 IMPL_LINK(StyleList, SetFamily, sal_uInt16, nId, void)
341 if (m_nActFamily != 0xFFFF)
342 m_pParentDialog->CheckItem(OUString::number(m_nActFamily), false);
343 m_nActFamily = nId;
344 if (nId != 0xFFFF)
346 m_bUpdateFamily = true;
350 void StyleList::InvalidateBindings()
352 m_pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
353 m_pBindings->Update(SID_STYLE_NEW_BY_EXAMPLE);
354 m_pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
355 m_pBindings->Update(SID_STYLE_UPDATE_BY_EXAMPLE);
356 m_pBindings->Invalidate(SID_STYLE_WATERCAN, true);
357 m_pBindings->Update(SID_STYLE_WATERCAN);
358 m_pBindings->Invalidate(SID_STYLE_NEW, true);
359 m_pBindings->Update(SID_STYLE_NEW);
360 m_pBindings->Invalidate(SID_STYLE_DRAGHIERARCHIE, true);
361 m_pBindings->Update(SID_STYLE_DRAGHIERARCHIE);
364 void StyleList::Initialize()
366 m_pBindings->Invalidate(SID_STYLE_FAMILY);
367 m_pBindings->Update(SID_STYLE_FAMILY);
369 m_xFmtLb->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
370 m_xFmtLb->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
371 m_xFmtLb->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
372 m_xFmtLb->connect_selection_changed(LINK(this, StyleList, FmtSelectHdl));
373 m_xFmtLb->connect_popup_menu(LINK(this, StyleList, PopupFlatMenuHdl));
374 m_xFmtLb->connect_key_press(LINK(this, StyleList, KeyInputHdl));
375 m_xFmtLb->set_selection_mode(SelectionMode::Multiple);
376 m_xTreeBox->connect_selection_changed(LINK(this, StyleList, FmtSelectHdl));
377 m_xTreeBox->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
378 m_xTreeBox->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
379 m_xTreeBox->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
380 m_xTreeBox->connect_popup_menu(LINK(this, StyleList, PopupTreeMenuHdl));
381 m_xTreeBox->connect_key_press(LINK(this, StyleList, KeyInputHdl));
382 m_xTreeBox->connect_drag_begin(LINK(this, StyleList, DragBeginHdl));
383 m_xTreeView1DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xFmtLb));
384 m_xTreeView2DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xTreeBox));
386 m_pParentDialog->connect_stylelist_read_resource(LINK(this, StyleList, ReadResource));
387 m_pParentDialog->connect_stylelist_clear(LINK(this, StyleList, Clear));
388 m_pParentDialog->connect_stylelist_cleanup(LINK(this, StyleList, Cleanup));
389 m_pParentDialog->connect_stylelist_execute_drop(LINK(this, StyleList, ExecuteDrop));
390 m_pParentDialog->connect_stylelist_execute_new_menu(
391 LINK(this, StyleList, NewMenuExecuteAction));
392 m_pParentDialog->connect_stylelist_for_watercan(LINK(this, StyleList, IsSafeForWaterCan));
393 m_pParentDialog->connect_stylelist_has_selected_style(LINK(this, StyleList, HasSelectedStyle));
394 m_pParentDialog->connect_stylelist_update_style_dependents(
395 LINK(this, StyleList, UpdateStyleDependents));
396 m_pParentDialog->connect_stylelist_enable_tree_drag(LINK(this, StyleList, EnableTreeDrag));
397 m_pParentDialog->connect_stylelist_enable_delete(LINK(this, StyleList, EnableDelete));
398 m_pParentDialog->connect_stylelist_set_water_can_state(LINK(this, StyleList, SetWaterCanState));
399 m_pParentDialog->connect_set_family(LINK(this, StyleList, SetFamily));
401 int nTreeHeight = m_xFmtLb->get_height_rows(8);
402 m_xFmtLb->set_size_request(-1, nTreeHeight);
403 m_xTreeBox->set_size_request(-1, nTreeHeight);
405 m_xFmtLb->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
406 m_xFmtLb->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
407 m_xTreeBox->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
408 m_xTreeBox->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
409 bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
410 m_xFmtLb->set_column_custom_renderer(1, bCustomPreview);
411 m_xTreeBox->set_column_custom_renderer(1, bCustomPreview);
413 m_xFmtLb->set_visible(!m_bHierarchical);
414 m_xTreeBox->set_visible(m_bHierarchical);
415 Update();
418 void StyleList::UpdateFamily()
420 m_bUpdateFamily = false;
422 SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
423 SfxViewFrame* pViewFrame = pDispat->GetFrame();
424 SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
426 SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
427 m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
428 if (pOldStyleSheetPool != m_pStyleSheetPool)
430 if (pOldStyleSheetPool)
431 EndListening(*pOldStyleSheetPool);
432 if (m_pStyleSheetPool)
433 StartListening(*m_pStyleSheetPool);
436 m_bTreeDrag = true;
437 m_bCanNew = m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
438 m_pParentDialog->EnableNew(m_bCanNew, this);
439 m_bTreeDrag = true;
440 if (m_pStyleSheetPool)
442 if (!m_xTreeBox->get_visible())
443 UpdateStyles(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
444 else
446 UpdateStyles(StyleFlags::UpdateFamily);
447 FillTreeBox(GetActualFamily());
451 InvalidateBindings();
454 bool StyleList::EnableExecute()
456 return m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
459 void StyleList::connect_LoadFactoryStyleFilter(const Link<SfxObjectShell const*, sal_Int32>& rLink)
461 m_aLoadFactoryStyleFilter = rLink;
464 void StyleList::connect_SaveSelection(const Link<StyleList&, SfxObjectShell*> rLink)
466 m_aSaveSelection = rLink;
469 /** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
470 create a style out of the current selection.
472 sal_Int8 StyleList::AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
474 if (rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR))
476 // special case: page styles are allowed to create new styles by example
477 // but not allowed to be created by drag and drop
478 if (GetActualFamily() == SfxStyleFamily::Page || m_bNewByExampleDisabled)
479 return DND_ACTION_NONE;
480 else
481 return DND_ACTION_COPY;
483 // to enable the autoscroll when we're close to the edges
484 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
485 pTreeView->get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
486 return DND_ACTION_MOVE;
489 // handles drop of content in treeview when creating a new style
490 IMPL_LINK(StyleList, ExecuteDrop, const ExecuteDropEvent&, rEvt, sal_Int8)
492 SfxObjectShell* pDocShell = m_pCurObjShell;
493 if (pDocShell)
495 TransferableDataHelper aHelper(rEvt.maDropEvent.Transferable);
496 sal_uInt32 nFormatCount = aHelper.GetFormatCount();
498 sal_Int8 nRet = DND_ACTION_NONE;
500 bool bFormatFound = false;
502 for (sal_uInt32 i = 0; i < nFormatCount; ++i)
504 SotClipboardFormatId nId = aHelper.GetFormat(i);
505 TransferableObjectDescriptor aDesc;
507 if (aHelper.GetTransferableObjectDescriptor(nId, aDesc))
509 if (aDesc.maClassName == pDocShell->GetFactory().GetClassId())
511 Application::PostUserEvent(
512 LINK(m_pParentDialog, SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop),
513 this);
515 bFormatFound = true;
516 nRet = rEvt.mnAction;
517 break;
522 if (bFormatFound)
523 return nRet;
526 if (!m_xTreeBox->get_visible())
527 return DND_ACTION_NONE;
529 if (!m_bAllowReParentDrop)
530 return DND_ACTION_NONE;
532 // otherwise if we're dragging with the treeview to set a new parent of the dragged style
533 weld::TreeView* pSource = m_xTreeBox->get_drag_source();
534 // only dragging within the same widget allowed
535 if (!pSource || pSource != m_xTreeBox.get())
536 return DND_ACTION_NONE;
538 std::unique_ptr<weld::TreeIter> xSource(m_xTreeBox->make_iterator());
539 if (!m_xTreeBox->get_selected(xSource.get()))
540 return DND_ACTION_NONE;
542 std::unique_ptr<weld::TreeIter> xTarget(m_xTreeBox->make_iterator());
543 if (!m_xTreeBox->get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
545 // if nothing under the mouse, use the last row
546 int nChildren = m_xTreeBox->n_children();
547 if (!nChildren)
548 return DND_ACTION_NONE;
549 if (!m_xTreeBox->get_iter_first(*xTarget)
550 || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
551 return DND_ACTION_NONE;
552 while (m_xTreeBox->get_row_expanded(*xTarget))
554 nChildren = m_xTreeBox->iter_n_children(*xTarget);
555 if (!m_xTreeBox->iter_children(*xTarget)
556 || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
557 return DND_ACTION_NONE;
560 OUString aTargetStyle = m_xTreeBox->get_text(*xTarget);
561 DropHdl(m_xTreeBox->get_text(*xSource), aTargetStyle);
562 m_xTreeBox->unset_drag_dest_row();
563 FillTreeBox(GetActualFamily());
564 m_pParentDialog->SelectStyle(aTargetStyle, false, *this);
565 return DND_ACTION_NONE;
568 IMPL_LINK_NOARG(StyleList, NewMenuExecuteAction, void*, void)
570 if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
571 return;
573 const SfxStyleFamily eFam = GetFamilyItem()->GetFamily();
574 const SfxStyleFamilyItem* pItem = GetFamilyItem();
575 SfxStyleSearchBits nFilter(SfxStyleSearchBits::Auto);
576 if (pItem && m_nActFilter != 0xffff)
577 nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
578 if (nFilter == SfxStyleSearchBits::Auto) // automatic
579 nFilter = m_nAppFilter;
581 // why? : FloatingWindow must not be parent of a modal dialog
582 SfxNewStyleDlg aDlg(m_pContainer, *m_pStyleSheetPool, eFam);
583 auto nResult = aDlg.run();
584 if (nResult == RET_OK)
586 const OUString aTemplName(aDlg.GetName());
587 m_pParentDialog->Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE, aTemplName, u""_ustr,
588 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
589 nFilter);
590 UpdateFamily();
591 m_aUpdateFamily.Call(*this);
595 void StyleList::DropHdl(const OUString& rStyle, const OUString& rParent)
597 m_bDontUpdate = true;
598 const SfxStyleFamilyItem* pItem = GetFamilyItem();
599 const SfxStyleFamily eFam = pItem->GetFamily();
600 if (auto pStyle = m_pStyleSheetPool->Find(rStyle, eFam))
601 pStyle->SetParent(rParent);
602 m_bDontUpdate = false;
605 void StyleList::PrepareMenu(const Point& rPos)
607 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
608 std::unique_ptr<weld::TreeIter> xIter(pTreeView->make_iterator());
609 if (pTreeView->get_dest_row_at_pos(rPos, xIter.get(), false) && !pTreeView->is_selected(*xIter))
611 pTreeView->unselect_all();
612 pTreeView->set_cursor(*xIter);
613 pTreeView->select(*xIter);
615 FmtSelectHdl(*pTreeView);
618 /** Internal structure for the establishment of the hierarchical view */
619 namespace
621 class StyleTree_Impl;
624 typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;
626 namespace
628 class StyleTree_Impl
630 private:
631 OUString aName;
632 OUString aParent;
633 StyleTreeArr_Impl pChildren;
635 public:
636 bool HasParent() const { return !aParent.isEmpty(); }
638 StyleTree_Impl(OUString _aName, OUString _aParent)
639 : aName(std::move(_aName))
640 , aParent(std::move(_aParent))
641 , pChildren(0)
645 const OUString& getName() const { return aName; }
646 const OUString& getParent() const { return aParent; }
647 StyleTreeArr_Impl& getChildren() { return pChildren; }
651 static void MakeTree_Impl(StyleTreeArr_Impl& rArr, const OUString& aUIName)
653 const comphelper::string::NaturalStringSorter aSorter(
654 ::comphelper::getProcessComponentContext(),
655 Application::GetSettings().GetLanguageTag().getLocale());
657 std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
658 styleFinder.reserve(rArr.size());
659 for (const auto& pEntry : rArr)
661 styleFinder.emplace(pEntry->getName(), pEntry.get());
664 // Arrange all under their Parents
665 for (auto& pEntry : rArr)
667 if (!pEntry->HasParent())
668 continue;
669 auto it = styleFinder.find(pEntry->getParent());
670 if (it != styleFinder.end())
672 StyleTree_Impl* pCmp = it->second;
673 // Insert child entries sorted
674 auto iPos = std::lower_bound(
675 pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
676 [&aSorter](std::unique_ptr<StyleTree_Impl> const& pEntry1,
677 std::unique_ptr<StyleTree_Impl> const& pEntry2) {
678 return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
680 pCmp->getChildren().insert(iPos, std::move(pEntry));
684 // Only keep tree roots in rArr, child elements can be accessed through the hierarchy
685 std::erase_if(rArr, [](std::unique_ptr<StyleTree_Impl> const& pEntry) { return !pEntry; });
687 // tdf#91106 sort top level styles
688 std::sort(rArr.begin(), rArr.end());
689 std::sort(rArr.begin(), rArr.end(),
690 [&aSorter, &aUIName](std::unique_ptr<StyleTree_Impl> const& pEntry1,
691 std::unique_ptr<StyleTree_Impl> const& pEntry2) {
692 if (pEntry2->getName() == aUIName)
693 return false;
694 if (pEntry1->getName() == aUIName)
695 return true; // default always first
696 return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
700 static bool IsExpanded_Impl(const std::vector<OUString>& rEntries, std::u16string_view rStr)
702 for (const auto& rEntry : rEntries)
704 if (rEntry == rStr)
705 return true;
707 return false;
710 static void lcl_Update(weld::TreeView& rTreeView, weld::TreeIter& rIter, const OUString& rName,
711 SfxStyleFamily eFam, SfxViewShell* pViewSh)
713 Color aColor = ColorHash(rName);
715 int nColor;
716 if (eFam == SfxStyleFamily::Para)
718 StylesHighlighterColorMap& rParaStylesColorMap
719 = pViewSh->GetStylesHighlighterParaColorMap();
720 nColor = rParaStylesColorMap.size();
721 rParaStylesColorMap[rName] = std::pair(aColor, nColor);
723 else
725 StylesHighlighterColorMap& rCharStylesColorMap
726 = pViewSh->GetStylesHighlighterCharColorMap();
727 nColor = rCharStylesColorMap.size();
728 rCharStylesColorMap[rName] = std::pair(aColor, nColor);
729 // don't show a color or number for default character style 'No Character Style' entry
730 if (rName == sDefaultCharStyleUIName.value() /*"No Character Style"*/)
732 rTreeView.set_id(rIter, rName);
733 rTreeView.set_text(rIter, rName);
734 return;
738 // draw the color rectangle and number image
739 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
740 Size aImageSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
741 ScopedVclPtrInstance<VirtualDevice> xDevice;
742 xDevice->SetOutputSize(aImageSize);
743 xDevice->SetFillColor(aColor);
744 const tools::Rectangle aRect(Point(0, 0), aImageSize);
745 xDevice->DrawRect(aRect);
746 xDevice->SetTextColor(COL_BLACK);
747 xDevice->DrawText(aRect, OUString::number(nColor),
748 DrawTextFlags::Center | DrawTextFlags::VCenter);
750 rTreeView.set_id(rIter, rName);
751 rTreeView.set_text(rIter, rName);
752 rTreeView.set_image(rIter, *xDevice);
755 static void FillBox_Impl(weld::TreeView& rBox, StyleTreeArr_Impl& rTreeArray,
756 SfxStyleFamily eStyleFamily, const weld::TreeIter* pParent,
757 bool blcl_insert, SfxViewShell* pViewShell,
758 SfxStyleSheetBasePool* pStyleSheetPool)
760 if (rTreeArray.empty())
761 return;
762 rBox.bulk_insert_for_each(rTreeArray.size(),
763 [&rTreeArray, blcl_insert, pStyleSheetPool, eStyleFamily, &rBox,
764 pViewShell](weld::TreeIter& rIter, int i) {
765 StyleTree_Impl* pChildEntry = rTreeArray[i].get();
766 const OUString& rChildName = pChildEntry->getName();
767 if (blcl_insert)
769 const SfxStyleSheetBase* pStyle = nullptr;
770 if (pStyleSheetPool)
771 pStyle = pStyleSheetPool->Find(rChildName, eStyleFamily);
772 if (pStyle && pStyle->IsUsed())
773 lcl_Update(rBox, rIter, rChildName, eStyleFamily,
774 pViewShell);
775 else
777 rBox.set_id(rIter, rChildName);
778 rBox.set_text(rIter, rChildName);
781 else
783 rBox.set_id(rIter, rChildName);
784 rBox.set_text(rIter, rChildName);
787 pParent, nullptr, /*bGoingToSetText*/ true);
789 std::unique_ptr<weld::TreeIter> xChildParentIter = rBox.make_iterator(pParent);
790 if (!pParent)
791 (void)rBox.get_iter_first(*xChildParentIter);
792 else
793 (void)rBox.iter_children(*xChildParentIter);
794 for (size_t i = 0; i < rTreeArray.size(); ++i)
796 FillBox_Impl(rBox, rTreeArray[i]->getChildren(), eStyleFamily, xChildParentIter.get(),
797 blcl_insert, pViewShell, pStyleSheetPool);
798 (void)rBox.iter_next_sibling(*xChildParentIter);
802 namespace SfxTemplate
804 // converts from SFX_STYLE_FAMILY Ids to 1-6
805 static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
807 switch (nFamily)
809 case SfxStyleFamily::Char:
810 return 1;
811 case SfxStyleFamily::Para:
812 return 2;
813 case SfxStyleFamily::Frame:
814 return 3;
815 case SfxStyleFamily::Page:
816 return 4;
817 case SfxStyleFamily::Pseudo:
818 return 5;
819 case SfxStyleFamily::Table:
820 return 6;
821 default:
822 return 0xffff;
825 // converts from 1-6 to SFX_STYLE_FAMILY Ids
826 static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
828 switch (nId)
830 case 1:
831 return SfxStyleFamily::Char;
832 case 2:
833 return SfxStyleFamily::Para;
834 case 3:
835 return SfxStyleFamily::Frame;
836 case 4:
837 return SfxStyleFamily::Page;
838 case 5:
839 return SfxStyleFamily::Pseudo;
840 case 6:
841 return SfxStyleFamily::Table;
842 default:
843 return SfxStyleFamily::All;
848 sal_uInt16 StyleList::StyleNrToInfoOffset(sal_uInt16 nId)
850 const SfxStyleFamilyItem& rItem = m_xStyleFamilies->at(nId);
851 return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily()) - 1;
854 // Helper function: Access to the current family item
855 const SfxStyleFamilyItem* StyleList::GetFamilyItem() const
857 const size_t nCount = m_xStyleFamilies->size();
858 for (size_t i = 0; i < nCount; ++i)
860 const SfxStyleFamilyItem& rItem = m_xStyleFamilies->at(i);
861 sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
862 if (nId == m_nActFamily)
863 return &rItem;
865 return nullptr;
868 void StyleList::GetSelectedStyle() const
870 const OUString aTemplName(GetSelectedEntry());
871 const SfxStyleFamilyItem* pItem = GetFamilyItem();
872 m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
875 // Used to get the current selected entry in visible treeview
876 OUString StyleList::GetSelectedEntry() const
878 OUString aRet;
879 if (m_xTreeBox->get_visible())
880 aRet = m_xTreeBox->get_selected_text();
881 else
882 aRet = m_xFmtLb->get_selected_text();
883 return aRet;
887 * Is it safe to show the water-can / fill icon. If we've a
888 * hierarchical widget - we have only single select, otherwise
889 * we need to check if we have a multi-selection. We either have
890 * a m_xTreeBox showing or an m_xFmtLb (which we hide when not shown)
892 IMPL_LINK_NOARG(StyleList, IsSafeForWaterCan, void*, bool)
894 if (m_xTreeBox->get_visible())
895 return m_xTreeBox->get_selected_index() != -1;
896 else
897 return m_xFmtLb->count_selected_rows() == 1;
900 IMPL_LINK(StyleList, SetWaterCanState, const SfxBoolItem*, pItem, void)
902 size_t nCount = m_xStyleFamilies->size();
903 m_pBindings->EnterRegistrations();
904 for (size_t n = 0; n < nCount; n++)
906 SfxControllerItem* pCItem = pBoundItems[n].get();
907 bool bChecked = pItem && pItem->GetValue();
908 if (pCItem->IsBound() == bChecked)
910 if (!bChecked)
911 pCItem->ReBind();
912 else
913 pCItem->UnBind();
916 m_pBindings->LeaveRegistrations();
919 void StyleList::FamilySelect(sal_uInt16 nEntry, bool bRefresh)
921 if (bRefresh)
923 bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
924 m_xFmtLb->clear();
925 m_xFmtLb->set_column_custom_renderer(1, bCustomPreview);
926 m_xTreeBox->clear();
927 m_xTreeBox->set_column_custom_renderer(1, bCustomPreview);
929 m_nActFamily = nEntry;
930 SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
931 SfxUInt16Item const aItem(SID_STYLE_FAMILY,
932 static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
933 pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
934 m_pBindings->Invalidate(SID_STYLE_FAMILY);
935 m_pBindings->Update(SID_STYLE_FAMILY);
936 UpdateFamily();
937 m_aUpdateFamily.Call(*this);
940 // It selects the style in treeview
941 // bIsCallBack is true for the selected style. For eg. if "Addressee" is selected in
942 // styles, bIsCallBack will be true for it.
943 void StyleList::SelectStyle(const OUString& rStr, bool bIsCallback)
945 const SfxStyleFamilyItem* pItem = GetFamilyItem();
946 if (!pItem)
947 return;
948 const SfxStyleFamily eFam = pItem->GetFamily();
949 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(rStr, eFam);
950 if (pStyle)
952 bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
953 m_pParentDialog->EnableEdit(bReadWrite, this);
954 m_pParentDialog->EnableHide(bReadWrite && !pStyle->IsHidden() && !pStyle->IsUsed(), this);
955 m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden(), this);
957 else
959 m_pParentDialog->EnableEdit(false, this);
960 m_pParentDialog->EnableHide(false, this);
961 m_pParentDialog->EnableShow(false, this);
964 if (bIsCallback)
965 return;
967 if (m_xTreeBox->get_visible())
969 if (!rStr.isEmpty())
971 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
972 bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
973 while (bEntry)
975 if (m_xTreeBox->get_text(*xEntry) == rStr)
977 m_xTreeBox->scroll_to_row(*xEntry);
978 m_xTreeBox->select(*xEntry);
979 break;
981 bEntry = m_xTreeBox->iter_next(*xEntry);
984 else if (eFam == SfxStyleFamily::Pseudo)
986 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
987 if (m_xTreeBox->get_iter_first(*xEntry))
989 m_xTreeBox->scroll_to_row(*xEntry);
990 m_xTreeBox->select(*xEntry);
993 else
994 m_xTreeBox->unselect_all();
996 else
998 bool bSelect = !rStr.isEmpty();
999 if (bSelect)
1001 std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
1002 bool bEntry = m_xFmtLb->get_iter_first(*xEntry);
1003 while (bEntry && m_xFmtLb->get_text(*xEntry) != rStr)
1004 bEntry = m_xFmtLb->iter_next(*xEntry);
1005 if (!bEntry)
1006 bSelect = false;
1007 else
1009 if (!m_xFmtLb->is_selected(*xEntry))
1011 m_xFmtLb->unselect_all();
1012 m_xFmtLb->scroll_to_row(*xEntry);
1013 m_xFmtLb->select(*xEntry);
1018 if (!bSelect)
1020 m_xFmtLb->unselect_all();
1021 m_pParentDialog->EnableEdit(false, this);
1022 m_pParentDialog->EnableHide(false, this);
1023 m_pParentDialog->EnableShow(false, this);
1028 static void MakeExpanded_Impl(const weld::TreeView& rBox, std::vector<OUString>& rEntries)
1030 std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator();
1031 if (rBox.get_iter_first(*xEntry))
1035 if (rBox.get_row_expanded(*xEntry))
1036 rEntries.push_back(rBox.get_text(*xEntry));
1037 } while (rBox.iter_next(*xEntry));
1041 IMPL_LINK(StyleList, EnableTreeDrag, bool, m_bEnable, void)
1043 if (m_pStyleSheetPool)
1045 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1046 SfxStyleSheetBase* pStyle = pItem ? m_pStyleSheetPool->First(pItem->GetFamily()) : nullptr;
1047 m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bEnable;
1049 m_bTreeDrag = m_bEnable;
1052 // Fill the treeview
1054 void StyleList::FillTreeBox(SfxStyleFamily eFam)
1056 assert(m_xTreeBox && "FillTreeBox() without treebox");
1057 if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
1058 return;
1060 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1061 if (!pItem)
1062 return;
1064 StyleTreeArr_Impl aArr;
1065 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, SfxStyleSearchBits::All);
1067 m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bTreeDrag;
1069 while (pStyle)
1071 if (pStyle->IsHidden()
1072 && (pStyle->GetFamily() == SfxStyleFamily::Page
1073 || pStyle->GetFamily() == SfxStyleFamily::Pseudo
1074 || pStyle->GetFamily() == SfxStyleFamily::Table))
1076 else
1078 StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent());
1079 aArr.emplace_back(pNew);
1081 pStyle = m_pStyleSheetPool->Next();
1083 OUString aUIName = getDefaultStyleName(eFam);
1084 MakeTree_Impl(aArr, aUIName);
1085 std::vector<OUString> aEntries;
1086 MakeExpanded_Impl(*m_xTreeBox, aEntries);
1087 m_xTreeBox->freeze();
1088 m_xTreeBox->clear();
1089 const sal_uInt16 nCount = aArr.size();
1091 SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
1092 StylesHighlighterColorMap* pHighlighterColorMap = nullptr;
1093 bool bOrigMapHasEntries = false;
1094 if (pViewShell && m_bModuleHasStylesHighlighterFeature)
1096 if (eFam == SfxStyleFamily::Para)
1097 pHighlighterColorMap = &pViewShell->GetStylesHighlighterParaColorMap();
1098 else if (eFam == SfxStyleFamily::Char)
1099 pHighlighterColorMap = &pViewShell->GetStylesHighlighterCharColorMap();
1102 if (pHighlighterColorMap && !pHighlighterColorMap->empty())
1104 bOrigMapHasEntries = true;
1105 pHighlighterColorMap->clear();
1108 bool blcl_insert = pViewShell && m_bModuleHasStylesHighlighterFeature
1109 && ((eFam == SfxStyleFamily::Para && m_bHighlightParaStyles)
1110 || (eFam == SfxStyleFamily::Char && m_bHighlightCharStyles));
1112 FillBox_Impl(*m_xTreeBox, aArr, eFam, nullptr, blcl_insert, pViewShell, m_pStyleSheetPool);
1113 for (sal_uInt16 i = 0; i < nCount; ++i)
1114 aArr[i].reset();
1116 m_xTreeBox->columns_autosize();
1118 m_pParentDialog->EnableItem(u"watercan"_ustr, false);
1120 SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
1122 m_xTreeBox->thaw();
1124 // make view update
1125 if (pViewShell && pHighlighterColorMap
1126 && (!pHighlighterColorMap->empty() || bOrigMapHasEntries))
1127 static_cast<SfxListener*>(pViewShell)
1128 ->Notify(*m_pStyleSheetPool, SfxHint(SfxHintId::StylesHighlighterModified));
1130 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
1131 bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
1132 if (bEntry && nCount)
1133 m_xTreeBox->expand_row(*xEntry);
1135 while (bEntry)
1137 if (IsExpanded_Impl(aEntries, m_xTreeBox->get_text(*xEntry)))
1138 m_xTreeBox->expand_row(*xEntry);
1139 bEntry = m_xTreeBox->iter_next(*xEntry);
1142 OUString aStyle;
1143 if (pState) // Select current entry
1144 aStyle = pState->GetStyleName();
1145 m_pParentDialog->SelectStyle(aStyle, false, *this);
1146 EnableDelete(nullptr);
1149 static OUString lcl_GetStyleFamilyName(SfxStyleFamily nFamily)
1151 if (nFamily == SfxStyleFamily::Char)
1152 return u"CharacterStyles"_ustr;
1153 if (nFamily == SfxStyleFamily::Para)
1154 return u"ParagraphStyles"_ustr;
1155 if (nFamily == SfxStyleFamily::Page)
1156 return u"PageStyles"_ustr;
1157 if (nFamily == SfxStyleFamily::Table)
1158 return u"TableStyles"_ustr;
1159 if (nFamily == SfxStyleFamily::Pseudo)
1160 return u"NumberingStyles"_ustr;
1161 return OUString();
1164 OUString StyleList::getDefaultStyleName(const SfxStyleFamily eFam)
1166 OUString sDefaultStyle;
1167 OUString aFamilyName = lcl_GetStyleFamilyName(eFam);
1168 if (aFamilyName == "TableStyles")
1169 sDefaultStyle = "Default Style";
1170 else if (aFamilyName == "NumberingStyles")
1171 sDefaultStyle = "No List";
1172 else
1173 sDefaultStyle = "Standard";
1174 uno::Reference<style::XStyleFamiliesSupplier> xModel(m_pCurObjShell->GetModel(),
1175 uno::UNO_QUERY);
1176 OUString aUIName;
1179 uno::Reference<container::XNameAccess> xStyles;
1180 uno::Reference<container::XNameAccess> xCont = xModel->getStyleFamilies();
1181 xCont->getByName(aFamilyName) >>= xStyles;
1182 uno::Reference<beans::XPropertySet> xInfo;
1183 xStyles->getByName(sDefaultStyle) >>= xInfo;
1184 xInfo->getPropertyValue(u"DisplayName"_ustr) >>= aUIName;
1186 catch (const uno::Exception&)
1189 return aUIName;
1192 SfxStyleFamily StyleList::GetActualFamily() const
1194 const SfxStyleFamilyItem* pFamilyItem = GetFamilyItem();
1195 if (!pFamilyItem || m_nActFamily == 0xffff)
1196 return SfxStyleFamily::Para;
1197 else
1198 return pFamilyItem->GetFamily();
1201 IMPL_LINK_NOARG(StyleList, HasSelectedStyle, void*, bool)
1203 return m_xTreeBox->get_visible() ? m_xTreeBox->get_selected_index() != -1
1204 : m_xFmtLb->count_selected_rows() != 0;
1207 IMPL_LINK_NOARG(StyleList, UpdateStyleDependents, void*, void)
1209 // Trigger Help PI. Only when the watercan is on
1210 if (m_nActFamily != 0xffff && m_pParentDialog->IsCheckedItem(u"watercan"_ustr) &&
1211 // only if that region is allowed
1212 nullptr != m_pFamilyState[m_nActFamily - 1] && IsSafeForWaterCan(nullptr))
1214 m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, u""_ustr, u""_ustr, 0, *this);
1215 m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, GetSelectedEntry(), u""_ustr,
1216 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1220 // Comes into action when the current style is changed
1221 void StyleList::UpdateStyles(StyleFlags nFlags)
1223 OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
1224 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1225 if (!pItem)
1227 // Is the case for the template catalog
1228 const size_t nFamilyCount = m_xStyleFamilies->size();
1229 size_t n;
1230 for (n = 0; n < nFamilyCount; n++)
1231 if (m_pFamilyState[StyleNrToInfoOffset(n)])
1232 break;
1233 if (n == nFamilyCount)
1234 // It happens sometimes, God knows why
1235 return;
1236 m_nAppFilter = m_pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
1237 m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1, *this);
1238 pItem = GetFamilyItem();
1241 const SfxStyleFamily eFam = pItem->GetFamily();
1243 SfxStyleSearchBits nFilter(m_nActFilter < pItem->GetFilterList().size()
1244 ? pItem->GetFilterList()[m_nActFilter].nFlags
1245 : SfxStyleSearchBits::Auto);
1246 if (nFilter == SfxStyleSearchBits::Auto) // automatic
1247 nFilter = m_nAppFilter;
1249 OSL_ENSURE(m_pStyleSheetPool, "no StyleSheetPool");
1250 if (!m_pStyleSheetPool)
1251 return;
1253 m_aUpdateStyles.Call(nFlags);
1255 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, nFilter);
1257 std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
1258 std::vector<OUString> aStrings;
1260 comphelper::string::NaturalStringSorter aSorter(
1261 ::comphelper::getProcessComponentContext(),
1262 Application::GetSettings().GetLanguageTag().getLocale());
1264 while (pStyle)
1266 aStrings.push_back(pStyle->GetName());
1267 pStyle = m_pStyleSheetPool->Next();
1269 OUString aUIName = getDefaultStyleName(eFam);
1271 // Paradoxically, with a list and non-Latin style names,
1272 // sorting twice is faster than sorting once.
1273 // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
1274 // Then the second sort needs to call its (much more expensive) comparator less often.
1275 std::sort(aStrings.begin(), aStrings.end());
1276 std::sort(aStrings.begin(), aStrings.end(),
1277 [&aSorter, &aUIName](const OUString& rLHS, const OUString& rRHS) {
1278 if (rRHS == aUIName)
1279 return false;
1280 if (rLHS == aUIName)
1281 return true; // default always first
1282 return aSorter.compare(rLHS, rRHS) < 0;
1285 // Fill the display box
1286 m_xFmtLb->freeze();
1287 m_xFmtLb->clear();
1289 SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
1290 StylesHighlighterColorMap* pHighlighterColorMap = nullptr;
1291 bool bOrigMapHasEntries = false;
1292 if (pViewShell && m_bModuleHasStylesHighlighterFeature)
1294 if (eFam == SfxStyleFamily::Para)
1295 pHighlighterColorMap = &pViewShell->GetStylesHighlighterParaColorMap();
1296 else if (eFam == SfxStyleFamily::Char)
1297 pHighlighterColorMap = &pViewShell->GetStylesHighlighterCharColorMap();
1300 if (pHighlighterColorMap && !pHighlighterColorMap->empty())
1302 bOrigMapHasEntries = true;
1303 pHighlighterColorMap->clear();
1306 size_t nCount = aStrings.size();
1308 if (pViewShell && m_bModuleHasStylesHighlighterFeature
1309 && ((eFam == SfxStyleFamily::Para && m_bHighlightParaStyles)
1310 || (eFam == SfxStyleFamily::Char && m_bHighlightCharStyles)))
1312 m_xFmtLb->bulk_insert_for_each(
1313 nCount,
1314 [this, &aStrings, eFam, pViewShell](weld::TreeIter& rIter, int nIdx) {
1315 auto pChildStyle = m_pStyleSheetPool->Find(aStrings[nIdx], eFam);
1316 if (pChildStyle && pChildStyle->IsUsed())
1317 lcl_Update(*m_xFmtLb, rIter, aStrings[nIdx], eFam, pViewShell);
1318 else
1320 m_xFmtLb->set_id(rIter, aStrings[nIdx]);
1321 m_xFmtLb->set_text(rIter, aStrings[nIdx]);
1324 nullptr, nullptr, /*bGoingToSetText*/ true);
1326 else
1328 m_xFmtLb->bulk_insert_for_each(nCount,
1329 [this, &aStrings](weld::TreeIter& rIter, int nIdx) {
1330 m_xFmtLb->set_id(rIter, aStrings[nIdx]);
1331 m_xFmtLb->set_text(rIter, aStrings[nIdx]);
1333 nullptr, nullptr, /*bGoingToSetText*/ true);
1336 m_xFmtLb->columns_autosize();
1338 m_xFmtLb->thaw();
1340 // make view update
1341 if (pViewShell && pHighlighterColorMap
1342 && (!pHighlighterColorMap->empty() || bOrigMapHasEntries))
1343 static_cast<SfxListener*>(pViewShell)
1344 ->Notify(*m_pStyleSheetPool, SfxHint(SfxHintId::StylesHighlighterModified));
1346 // Selects the current style if any
1347 SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
1348 OUString aStyle;
1349 if (pState)
1350 aStyle = pState->GetStyleName();
1351 m_pParentDialog->SelectStyle(aStyle, false, *this);
1352 EnableDelete(nullptr);
1355 void StyleList::SetFamilyState(sal_uInt16 nSlotId, const SfxTemplateItem* pItem)
1357 sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
1358 m_pFamilyState[nIdx].reset();
1359 if (pItem)
1360 m_pFamilyState[nIdx].reset(new SfxTemplateItem(*pItem));
1361 m_bUpdateFamily = true;
1364 void StyleList::SetHierarchical()
1366 m_bHierarchical = true;
1367 const OUString aSelectEntry(GetSelectedEntry());
1368 m_xFmtLb->hide();
1369 FillTreeBox(GetActualFamily());
1370 m_pParentDialog->SelectStyle(aSelectEntry, false, *this);
1371 m_xTreeBox->show();
1374 void StyleList::SetFilterControlsHandle()
1376 m_xTreeBox->hide();
1377 m_xFmtLb->show();
1378 m_bHierarchical = false;
1381 // Handler for the New-Buttons
1382 void StyleList::NewHdl()
1384 if (m_nActFamily == 0xffff
1385 || !(m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1))
1386 return;
1388 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1389 const SfxStyleFamily eFam = pItem->GetFamily();
1390 SfxStyleSearchBits nMask(SfxStyleSearchBits::Auto);
1391 if (m_nActFilter != 0xffff)
1392 nMask = pItem->GetFilterList()[m_nActFilter].nFlags;
1393 if (nMask == SfxStyleSearchBits::Auto) // automatic
1394 nMask = m_nAppFilter;
1396 m_pParentDialog->Execute_Impl(SID_STYLE_NEW, u""_ustr, GetSelectedEntry(),
1397 static_cast<sal_uInt16>(eFam), *this, nMask);
1400 // Handler for the edit-Buttons
1401 void StyleList::EditHdl()
1403 if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
1405 sal_uInt16 nFilter = m_nActFilter;
1406 OUString aTemplName(GetSelectedEntry());
1407 GetSelectedStyle(); // -Wall required??
1408 m_pParentDialog->Execute_Impl(SID_STYLE_EDIT, aTemplName, OUString(),
1409 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
1410 SfxStyleSearchBits::Auto, &nFilter);
1414 // Handler for the Delete-Buttons
1415 void StyleList::DeleteHdl()
1417 if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1418 return;
1420 bool bUsedStyle = false; // one of the selected styles are used in the document?
1422 std::vector<std::unique_ptr<weld::TreeIter>> aList;
1423 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1424 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1426 OUStringBuffer aMsg(SfxResId(STR_DELETE_STYLE_USED) + SfxResId(STR_DELETE_STYLE));
1428 pTreeView->selected_foreach(
1429 [this, pTreeView, pItem, &aList, &bUsedStyle, &aMsg](weld::TreeIter& rEntry) {
1430 aList.emplace_back(pTreeView->make_iterator(&rEntry));
1431 // check the style is used or not
1432 const OUString aTemplName(pTreeView->get_text(rEntry));
1434 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
1436 if (pStyle->IsUsed()) // pStyle is in use in the document?
1438 if (bUsedStyle) // add a separator for the second and later styles
1439 aMsg.append(", ");
1440 aMsg.append(aTemplName);
1441 bUsedStyle = true;
1444 return false;
1447 bool aApproved = false;
1449 // we only want to show the dialog once and if we want to delete a style in use (UX-advice)
1450 if (bUsedStyle)
1452 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
1453 pTreeView, VclMessageType::Question, VclButtonsType::YesNo, aMsg.makeStringAndClear()));
1454 aApproved = xBox->run() == RET_YES;
1457 // if there are no used styles selected or the user approved the changes
1458 if (bUsedStyle && !aApproved)
1459 return;
1461 for (auto const& elem : aList)
1463 const OUString aTemplName(pTreeView->get_text(*elem));
1464 m_bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting
1465 m_pParentDialog->Execute_Impl(SID_STYLE_DELETE, aTemplName, OUString(),
1466 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1468 if (m_xTreeBox->get_visible())
1470 weld::RemoveParentKeepChildren(*m_xTreeBox, *elem);
1471 m_bDontUpdate = false;
1474 m_bDontUpdate = false; // if everything is deleted set m_bDontUpdate back to false
1475 UpdateStyles(StyleFlags::UpdateFamilyList); // and force-update the list
1478 void StyleList::HideHdl()
1480 if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1481 return;
1483 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1484 pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
1485 OUString aTemplName = pTreeView->get_text(rEntry);
1487 m_pParentDialog->Execute_Impl(SID_STYLE_HIDE, aTemplName, OUString(),
1488 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1490 return false;
1494 void StyleList::ShowHdl()
1496 if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1497 return;
1499 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1500 pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
1501 OUString aTemplName = pTreeView->get_text(rEntry);
1503 m_pParentDialog->Execute_Impl(SID_STYLE_SHOW, aTemplName, OUString(),
1504 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1506 return false;
1510 IMPL_LINK_NOARG(StyleList, EnableDelete, void*, void)
1512 bool bEnableDelete(false);
1513 if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
1515 OSL_ENSURE(m_pStyleSheetPool, "No StyleSheetPool");
1516 const OUString aTemplName(GetSelectedEntry());
1517 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1518 const SfxStyleFamily eFam = pItem->GetFamily();
1519 SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
1520 if (pItem->GetFilterList().size() > m_nActFilter)
1521 nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
1522 if (nFilter == SfxStyleSearchBits::Auto) // automatic
1523 nFilter = m_nAppFilter;
1524 const SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(
1525 aTemplName, eFam, m_xTreeBox->get_visible() ? SfxStyleSearchBits::All : nFilter);
1527 OSL_ENSURE(pStyle, "Style not found");
1528 if (pStyle && pStyle->IsUserDefined())
1530 if (pStyle->HasClearParentSupport() || !pStyle->IsUsed())
1532 bEnableDelete = true;
1536 m_pParentDialog->EnableDel(bEnableDelete, this);
1539 IMPL_LINK_NOARG(StyleList, Clear, void*, void)
1541 if (m_pCurObjShell && m_bModuleHasStylesHighlighterFeature)
1543 SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
1544 if (pViewShell)
1546 pViewShell->GetStylesHighlighterParaColorMap().clear();
1547 pViewShell->GetStylesHighlighterCharColorMap().clear();
1550 m_xStyleFamilies.reset();
1551 for (auto& i : m_pFamilyState)
1552 i.reset();
1553 m_pCurObjShell = nullptr;
1554 for (auto& i : pBoundItems)
1555 i.reset();
1558 IMPL_LINK(StyleList, OnPopupEnd, const OUString&, sCommand, void) { MenuSelect(sCommand); }
1560 void StyleList::ShowMenu(const CommandEvent& rCEvt)
1562 CreateContextMenu();
1563 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1564 mxMenu->connect_activate(LINK(this, StyleList, OnPopupEnd));
1565 mxMenu->popup_at_rect(pTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
1568 void StyleList::MenuSelect(const OUString& rIdent)
1570 sLastItemIdent = rIdent;
1571 if (sLastItemIdent.isEmpty())
1572 return;
1573 Application::PostUserEvent(LINK(this, StyleList, MenuSelectAsyncHdl)); /***check this****/
1576 void StyleList::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1578 const SfxHintId nId = rHint.GetId();
1580 switch (nId)
1582 case SfxHintId::UpdateDone:
1584 SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1585 SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
1586 if (m_pParentDialog->GetNotifyUpdate()
1587 && (!m_pParentDialog->IsCheckedItem(u"watercan"_ustr)
1588 || (pDocShell && pDocShell->GetStyleSheetPool() != m_pStyleSheetPool)))
1590 m_pParentDialog->SetNotifyupdate(false);
1591 Update();
1593 else if (m_bUpdateFamily)
1595 UpdateFamily();
1596 m_aUpdateFamily.Call(*this);
1599 if (m_pStyleSheetPool)
1601 OUString aStr = GetSelectedEntry();
1602 if (!aStr.isEmpty())
1604 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1605 if (!pItem)
1606 break;
1607 const SfxStyleFamily eFam = pItem->GetFamily();
1608 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aStr, eFam);
1609 if (pStyle)
1611 bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
1612 m_pParentDialog->EnableEdit(bReadWrite, this);
1613 m_pParentDialog->EnableHide(
1614 bReadWrite && !pStyle->IsUsed() && !pStyle->IsHidden(), this);
1615 m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden(), this);
1617 else
1619 m_pParentDialog->EnableEdit(false, this);
1620 m_pParentDialog->EnableHide(false, this);
1621 m_pParentDialog->EnableShow(false, this);
1625 break;
1628 // Necessary if switching between documents and in both documents
1629 // the same template is used. Do not immediately call Update_Impl,
1630 // for the case that one of the documents is an internal InPlaceObject!
1631 case SfxHintId::DocChanged:
1632 m_pParentDialog->SetNotifyupdate(true);
1633 break;
1634 case SfxHintId::Dying:
1636 EndListening(*m_pStyleSheetPool);
1637 m_pStyleSheetPool = nullptr;
1638 break;
1640 default:
1641 break;
1644 // Do not set timer when the stylesheet pool is in the box, because it is
1645 // possible that a new one is registered after the timer is up -
1646 // works bad in UpdateStyles_Impl ()!
1648 if (!m_bDontUpdate && nId != SfxHintId::Dying
1649 && (nId == SfxHintId::SfxStyleSheetPool || dynamic_cast<const SfxStyleSheetHint*>(&rHint)
1650 || nId == SfxHintId::StyleSheetModifiedExtended)) // ie. SfxStyleSheetModifiedHint
1652 if (!pIdle)
1654 pIdle.reset(new Idle("SfxCommonTemplate"));
1655 pIdle->SetPriority(TaskPriority::LOWEST);
1656 pIdle->SetInvokeHandler(LINK(this, StyleList, TimeOut));
1658 pIdle->Start();
1662 IMPL_LINK_NOARG(StyleList, TimeOut, Timer*, void)
1664 if (!m_bDontUpdate)
1666 m_bDontUpdate = true;
1667 if (!m_xTreeBox->get_visible())
1668 UpdateStyles(StyleFlags::UpdateFamilyList);
1669 else
1671 FillTreeBox(GetActualFamily());
1672 SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
1673 if (pState)
1675 m_pParentDialog->SelectStyle(pState->GetStyleName(), false, *this);
1676 EnableDelete(nullptr);
1679 m_bDontUpdate = false;
1680 pIdle.reset();
1682 else
1683 pIdle->Start();
1686 IMPL_LINK_NOARG(StyleList, MenuSelectAsyncHdl, void*, void)
1688 if (sLastItemIdent == "new")
1689 NewHdl();
1690 else if (sLastItemIdent == "edit")
1691 EditHdl();
1692 else if (sLastItemIdent == "delete")
1693 DeleteHdl();
1694 else if (sLastItemIdent == "hide")
1695 HideHdl();
1696 else if (sLastItemIdent == "show")
1697 ShowHdl();
1699 mxMenu.reset();
1700 mxMenuBuilder.reset();
1703 // Double-click on a style sheet in the ListBox is applied.
1704 IMPL_LINK(StyleList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
1706 rUnsetDragIcon = false;
1707 // Allow normal processing. only if bAllowReParentDrop is true
1708 return !m_bAllowReParentDrop;
1711 IMPL_LINK(StyleList, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
1713 bool bRet = false;
1714 const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
1715 if (m_bCanDel && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_DELETE)
1717 DeleteHdl();
1718 bRet = true;
1720 return bRet;
1723 IMPL_LINK(StyleList, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
1725 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1726 const OUString aTemplName(pTreeView->get_text(rEntry));
1727 OUString sQuickHelpText(aTemplName);
1729 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1730 if (!pItem)
1731 return sQuickHelpText;
1732 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
1733 if (pStyle && pStyle->IsUsed()) // pStyle is in use in the document?
1735 OUString sUsedBy;
1736 if (pStyle->GetFamily() == SfxStyleFamily::Pseudo)
1737 sUsedBy = pStyle->GetUsedBy();
1739 if (!sUsedBy.isEmpty())
1741 const sal_Int32 nMaxLen = 80;
1742 if (sUsedBy.getLength() > nMaxLen)
1744 sUsedBy = OUString::Concat(sUsedBy.subView(0, nMaxLen)) + "...";
1747 OUString aMessage = SfxResId(STR_STYLEUSEDBY);
1748 aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy);
1749 sQuickHelpText = aTemplName + " " + aMessage;
1753 return sQuickHelpText;
1756 IMPL_LINK(StyleList, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
1758 vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
1759 const ::tools::Rectangle& rRect = std::get<1>(aPayload);
1760 ::tools::Rectangle aRect(
1761 rRect.TopLeft(),
1762 Size(rRenderContext.GetOutputSize().Width() - rRect.Left(), rRect.GetHeight()));
1763 bool bSelected = std::get<2>(aPayload);
1764 const OUString& rId = std::get<3>(aPayload);
1766 rRenderContext.Push(vcl::PushFlags::TEXTCOLOR);
1767 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1768 if (bSelected)
1769 rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
1770 else
1771 rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
1773 bool bSuccess = false;
1775 SfxObjectShell* pShell = SfxObjectShell::Current();
1776 sfx2::StyleManager* pStyleManager = pShell ? pShell->GetStyleManager() : nullptr;
1778 if (pStyleManager)
1780 if (const SfxStyleFamilyItem* pItem = GetFamilyItem())
1782 SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(rId, pItem->GetFamily());
1784 if (pStyleSheet)
1786 rRenderContext.Push(vcl::PushFlags::ALL);
1787 // tdf#119919 - show "hidden" styles as disabled to not move children onto root node
1788 if (pStyleSheet->IsHidden() && m_bHierarchical)
1789 rRenderContext.SetTextColor(rStyleSettings.GetDisableColor());
1791 sal_Int32 nSize = aRect.GetHeight();
1792 std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
1793 pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
1794 bSuccess
1795 = pStylePreviewRenderer->recalculate() && pStylePreviewRenderer->render(aRect);
1796 rRenderContext.Pop();
1801 if (!bSuccess)
1802 rRenderContext.DrawText(aRect, rId, DrawTextFlags::Left | DrawTextFlags::VCenter);
1804 rRenderContext.Pop();
1807 // Selection of a template during the Watercan-Status
1808 IMPL_LINK(StyleList, FmtSelectHdl, weld::TreeView&, rListBox, void)
1810 std::unique_ptr<weld::TreeIter> xHdlEntry = rListBox.make_iterator();
1811 if (!rListBox.get_cursor(xHdlEntry.get()))
1812 return;
1814 m_pParentDialog->SelectStyle(rListBox.get_text(*xHdlEntry), true, *this);
1817 IMPL_LINK_NOARG(StyleList, TreeListApplyHdl, weld::TreeView&, bool)
1819 // only if that region is allowed
1820 if (m_nActFamily != 0xffff && nullptr != m_pFamilyState[m_nActFamily - 1]
1821 && !GetSelectedEntry().isEmpty())
1823 m_pParentDialog->Execute_Impl(SID_STYLE_APPLY, GetSelectedEntry(), OUString(),
1824 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
1825 SfxStyleSearchBits::Auto, nullptr, &m_nModifier);
1827 // After selecting a focused item if possible again on the app window
1828 if (dynamic_cast<const SfxTemplateDialog_Impl*>(m_pParentDialog) != nullptr)
1830 SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1831 SfxViewShell* pVu = pViewFrame->GetViewShell();
1832 vcl::Window* pAppWin = pVu ? pVu->GetWindow() : nullptr;
1833 if (pAppWin)
1834 pAppWin->GrabFocus();
1837 return true;
1840 IMPL_LINK(StyleList, MousePressHdl, const MouseEvent&, rMEvt, bool)
1842 m_nModifier = rMEvt.GetModifier();
1843 return false;
1846 // Notice from SfxBindings that the update is completed. Pushes out the update
1847 // of the display.
1848 void StyleList::Update()
1850 bool bDocChanged = false;
1851 SfxStyleSheetBasePool* pNewPool = nullptr;
1852 SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1853 SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
1854 if (pDocShell)
1855 pNewPool = pDocShell->GetStyleSheetPool();
1857 if (pNewPool != m_pStyleSheetPool && pDocShell)
1859 SfxModule* pNewModule = pDocShell->GetModule();
1860 if (pNewModule && pNewModule != m_Module)
1862 m_aClearResource.Call(nullptr);
1863 m_aReadResource.Call(*this);
1865 if (m_pStyleSheetPool)
1867 EndListening(*m_pStyleSheetPool);
1868 m_pStyleSheetPool = nullptr;
1871 if (pNewPool)
1873 StartListening(*pNewPool);
1874 m_pStyleSheetPool = pNewPool;
1875 bDocChanged = true;
1879 if (m_bUpdateFamily)
1881 UpdateFamily();
1882 m_aUpdateFamily.Call(*this);
1885 sal_uInt16 i;
1886 for (i = 0; i < MAX_FAMILIES; ++i)
1887 if (m_pFamilyState[i])
1888 break;
1889 if (i == MAX_FAMILIES || !pNewPool)
1890 // nothing is allowed
1891 return;
1893 SfxTemplateItem* pItem = nullptr;
1894 // current region not within the allowed region or default
1895 if (m_nActFamily == 0xffff || nullptr == (pItem = m_pFamilyState[m_nActFamily - 1].get()))
1897 m_pParentDialog->CheckItem(OUString::number(m_nActFamily), false);
1898 const size_t nFamilyCount = m_xStyleFamilies->size();
1899 size_t n;
1900 for (n = 0; n < nFamilyCount; n++)
1901 if (m_pFamilyState[StyleNrToInfoOffset(n)])
1902 break;
1904 std::unique_ptr<SfxTemplateItem>& pNewItem = m_pFamilyState[StyleNrToInfoOffset(n)];
1905 m_nAppFilter = pNewItem->GetValue();
1906 m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1, *this);
1907 pItem = pNewItem.get();
1909 else if (bDocChanged)
1911 // other DocShell -> all new
1912 m_pParentDialog->CheckItem(OUString::number(m_nActFamily));
1913 m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(pDocShell));
1914 m_pParentDialog->IsUpdate(*this);
1915 if (0xffff == m_nActFilter)
1917 m_nActFilter = pDocShell->GetAutoStyleFilterIndex();
1920 m_nAppFilter = pItem->GetValue();
1921 if (!m_xTreeBox->get_visible())
1923 UpdateStyles(StyleFlags::UpdateFamilyList);
1925 else
1926 FillTreeBox(GetActualFamily());
1928 else
1930 // other filters for automatic
1931 m_pParentDialog->CheckItem(OUString::number(m_nActFamily));
1932 const SfxStyleFamilyItem* pStyleItem = GetFamilyItem();
1933 if (pStyleItem
1934 && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[m_nActFilter].nFlags
1935 && m_nAppFilter != pItem->GetValue())
1937 m_nAppFilter = pItem->GetValue();
1938 if (!m_xTreeBox->get_visible())
1939 UpdateStyles(StyleFlags::UpdateFamilyList);
1940 else
1941 FillTreeBox(GetActualFamily());
1943 else
1945 m_nAppFilter = pItem->GetValue();
1948 const OUString aStyle(pItem->GetStyleName());
1949 m_pParentDialog->SelectStyle(aStyle, false, *this);
1950 EnableDelete(nullptr);
1951 m_pParentDialog->EnableNew(m_bCanNew, this);
1954 const SfxStyleFamilyItem& StyleList::GetFamilyItemByIndex(size_t i) const
1956 return m_xStyleFamilies->at(i);
1959 IMPL_STATIC_LINK(StyleList, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
1961 vcl::RenderContext& rRenderContext = aPayload.first;
1962 return Size(42, 32 * rRenderContext.GetDPIScaleFactor());
1965 IMPL_LINK(StyleList, PopupFlatMenuHdl, const CommandEvent&, rCEvt, bool)
1967 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1968 return false;
1970 PrepareMenu(rCEvt.GetMousePosPixel());
1972 if (m_xFmtLb->count_selected_rows() <= 0)
1974 m_pParentDialog->EnableEdit(false, this);
1975 m_pParentDialog->EnableDel(false, this);
1978 ShowMenu(rCEvt);
1980 return true;
1983 IMPL_LINK(StyleList, PopupTreeMenuHdl, const CommandEvent&, rCEvt, bool)
1985 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1986 return false;
1988 PrepareMenu(rCEvt.GetMousePosPixel());
1990 ShowMenu(rCEvt);
1992 return true;
1994 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */