LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / dialog / StyleList.cxx
blobf8bcf6ee17999718cb07b2291b3db5f7e8a7fc57
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>
22 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/container/XNameAccess.hpp>
25 #include <vcl/commandevent.hxx>
26 #include <vcl/commandinfoprovider.hxx>
27 #include <vcl/event.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/weldutils.hxx>
31 #include <svl/intitem.hxx>
32 #include <svl/stritem.hxx>
33 #include <svl/style.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/sequenceashashmap.hxx>
36 #include <com/sun/star/beans/PropertyValue.hpp>
37 #include <com/sun/star/frame/ModuleManager.hpp>
38 #include <com/sun/star/frame/UnknownModuleException.hpp>
39 #include <officecfg/Office/Common.hxx>
41 #include <sal/log.hxx>
42 #include <osl/diagnose.h>
43 #include <tools/diagnose_ex.h>
44 #include <sfx2/app.hxx>
45 #include <sfx2/dispatch.hxx>
46 #include <sfx2/bindings.hxx>
47 #include <sfx2/templdlg.hxx>
48 #include <templdgi.hxx>
49 #include <tplcitem.hxx>
50 #include <sfx2/styfitem.hxx>
51 #include <sfx2/objsh.hxx>
52 #include <sfx2/viewsh.hxx>
53 #include <sfx2/newstyle.hxx>
54 #include <sfx2/tplpitem.hxx>
55 #include <sfx2/sfxresid.hxx>
57 #include <sfx2/sfxsids.hrc>
58 #include <sfx2/strings.hrc>
59 #include <sfx2/docfac.hxx>
60 #include <sfx2/module.hxx>
61 #include <helpids.h>
62 #include <sfx2/viewfrm.hxx>
64 #include <comphelper/string.hxx>
66 #include <sfx2/StyleManager.hxx>
67 #include <sfx2/StylePreviewRenderer.hxx>
69 #include <StyleList.hxx>
70 #include <vcl/toolbox.hxx>
71 #include <vcl/menu.hxx>
73 using namespace css;
74 using namespace css::beans;
75 using namespace css::frame;
76 using namespace css::uno;
78 // Constructor
80 StyleList::StyleList(weld::Builder* pBuilder, SfxBindings* pBindings,
81 SfxCommonTemplateDialog_Impl* Parent, weld::Container* pC,
82 OString treeviewname, OString flatviewname)
83 : m_bHierarchical(false)
84 , m_bAllowReParentDrop(false)
85 , m_bNewByExampleDisabled(false)
86 , m_bDontUpdate(false)
87 , m_bTreeDrag(true)
88 , m_bCanEdit(false)
89 , m_bCanHide(true)
90 , m_bCanShow(false)
91 , m_bCanNew(true)
92 , m_bUpdateFamily(false)
93 , m_bCanDel(false)
94 , m_bBindingUpdate(true)
95 , m_pStyleSheetPool(nullptr)
96 , m_nActFilter(0)
97 , m_xFmtLb(pBuilder->weld_tree_view(flatviewname))
98 , m_xTreeBox(pBuilder->weld_tree_view(treeviewname))
99 , m_pCurObjShell(nullptr)
100 , m_nActFamily(0xffff)
101 , m_nAppFilter(SfxStyleSearchBits::Auto)
102 , m_pParentDialog(Parent)
103 , m_pBindings(pBindings)
104 , m_Module(nullptr)
105 , m_nModifier(0)
106 , m_pContainer(pC)
108 m_xFmtLb->set_help_id(HID_TEMPLATE_FMT);
111 // Destructor
113 StyleList::~StyleList() {}
115 // Called in the destructor of Dialog
116 // Cleans up the StyleList individual components while closing the application
117 IMPL_LINK_NOARG(StyleList, Cleanup, void*, void)
119 if (m_pStyleSheetPool)
120 EndListening(*m_pStyleSheetPool);
121 m_pStyleSheetPool = nullptr;
122 m_xTreeView1DropTargetHelper.reset();
123 m_xTreeView2DropTargetHelper.reset();
124 m_xTreeBox.reset();
125 m_xFmtLb.reset();
126 pIdle.reset();
129 void StyleList::CreateContextMenu()
131 if (m_bBindingUpdate)
133 m_pBindings->Invalidate(SID_STYLE_NEW, true);
134 m_pBindings->Update(SID_STYLE_NEW);
135 m_bBindingUpdate = false;
137 mxMenu.reset();
138 mxMenuBuilder = Application::CreateBuilder(nullptr, "sfx/ui/stylecontextmenu.ui");
139 mxMenu = mxMenuBuilder->weld_menu("menu");
140 mxMenu->set_sensitive("edit", m_bCanEdit);
141 mxMenu->set_sensitive("delete", m_bCanDel);
142 mxMenu->set_sensitive("new", m_bCanNew);
143 mxMenu->set_sensitive("hide", m_bCanHide);
144 mxMenu->set_sensitive("show", m_bCanShow);
146 const SfxStyleFamilyItem* pItem = GetFamilyItem();
147 if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
149 mxMenu->set_sensitive("edit", false);
150 mxMenu->set_sensitive("new", false);
152 if (pItem && pItem->GetFamily() == SfxStyleFamily::Pseudo)
154 const OUString aTemplName(GetSelectedEntry());
155 if (aTemplName == "No List")
157 mxMenu->set_sensitive("edit", false);
158 mxMenu->set_sensitive("new", false);
159 mxMenu->set_sensitive("hide", false);
164 IMPL_LINK_NOARG(StyleList, ReadResource, void*, size_t)
166 // Read global user resource
167 for (auto& i : m_pFamilyState)
168 i.reset();
170 SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
171 m_pCurObjShell = pViewFrame->GetObjectShell();
172 m_Module = m_pCurObjShell ? m_pCurObjShell->GetModule() : nullptr;
173 if (m_Module)
174 m_xStyleFamilies = m_Module->CreateStyleFamilies();
175 if (!m_xStyleFamilies)
176 m_xStyleFamilies.emplace();
178 m_nActFilter = 0xffff;
180 if (m_pCurObjShell)
182 m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(m_pCurObjShell));
183 if (0xffff == m_nActFilter)
185 m_nActFilter = m_pCurObjShell->GetAutoStyleFilterIndex();
188 size_t nCount = m_xStyleFamilies->size();
189 m_pBindings->ENTERREGISTRATIONS();
191 size_t i;
192 for (i = 0; i < nCount; ++i)
194 sal_uInt16 nSlot = 0;
195 switch (m_xStyleFamilies->at(i).GetFamily())
197 case SfxStyleFamily::Char:
198 nSlot = SID_STYLE_FAMILY1;
199 break;
200 case SfxStyleFamily::Para:
201 nSlot = SID_STYLE_FAMILY2;
202 break;
203 case SfxStyleFamily::Frame:
204 nSlot = SID_STYLE_FAMILY3;
205 break;
206 case SfxStyleFamily::Page:
207 nSlot = SID_STYLE_FAMILY4;
208 break;
209 case SfxStyleFamily::Pseudo:
210 nSlot = SID_STYLE_FAMILY5;
211 break;
212 case SfxStyleFamily::Table:
213 nSlot = SID_STYLE_FAMILY6;
214 break;
215 default:
216 OSL_FAIL("unknown StyleFamily");
217 break;
219 pBoundItems[i].reset(new SfxTemplateControllerItem(nSlot, *m_pParentDialog, *m_pBindings));
221 pBoundItems[i++].reset(
222 new SfxTemplateControllerItem(SID_STYLE_WATERCAN, *m_pParentDialog, *m_pBindings));
223 pBoundItems[i++].reset(
224 new SfxTemplateControllerItem(SID_STYLE_NEW_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
225 pBoundItems[i++].reset(
226 new SfxTemplateControllerItem(SID_STYLE_UPDATE_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
227 pBoundItems[i++].reset(
228 new SfxTemplateControllerItem(SID_STYLE_NEW, *m_pParentDialog, *m_pBindings));
229 pBoundItems[i++].reset(
230 new SfxTemplateControllerItem(SID_STYLE_DRAGHIERARCHIE, *m_pParentDialog, *m_pBindings));
231 pBoundItems[i++].reset(
232 new SfxTemplateControllerItem(SID_STYLE_EDIT, *m_pParentDialog, *m_pBindings));
233 pBoundItems[i++].reset(
234 new SfxTemplateControllerItem(SID_STYLE_DELETE, *m_pParentDialog, *m_pBindings));
235 pBoundItems[i++].reset(
236 new SfxTemplateControllerItem(SID_STYLE_FAMILY, *m_pParentDialog, *m_pBindings));
237 m_pBindings->LEAVEREGISTRATIONS();
239 for (; i < COUNT_BOUND_FUNC; ++i)
240 pBoundItems[i] = nullptr;
242 StartListening(*m_pBindings);
244 for (i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++)
245 m_pBindings->Update(i);
247 return nCount;
250 void StyleList::EnableNewByExample(bool newByExampleDisabled)
252 m_bNewByExampleDisabled = newByExampleDisabled;
255 class TreeViewDropTarget final : public DropTargetHelper
257 private:
258 StyleList& m_rParent;
260 public:
261 TreeViewDropTarget(StyleList& rStyleList, weld::TreeView& rTreeView)
262 : DropTargetHelper(rTreeView.get_drop_target())
263 , m_rParent(rStyleList)
267 virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
269 return m_rParent.AcceptDrop(rEvt, *this);
272 virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
274 return m_rParent.ExecuteDrop(rEvt);
278 void StyleList::FilterSelect(sal_uInt16 nActFilter, bool bsetFilter)
280 m_nActFilter = nActFilter;
281 if (bsetFilter)
283 SfxObjectShell* const pDocShell = m_aSaveSelection.Call(*this);
284 SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
285 m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
286 if (pOldStyleSheetPool != m_pStyleSheetPool)
288 if (pOldStyleSheetPool)
289 EndListening(*pOldStyleSheetPool);
290 if (m_pStyleSheetPool)
291 StartListening(*m_pStyleSheetPool);
294 UpdateStyles(StyleFlags::UpdateFamilyList);
297 IMPL_LINK(StyleList, SetFamily, sal_uInt16, nId, void)
299 if (m_nActFamily != 0xFFFF)
300 m_pParentDialog->CheckItem(OString::number(m_nActFamily), false);
301 m_nActFamily = nId;
302 if (nId != 0xFFFF)
304 m_bUpdateFamily = true;
308 void StyleList::InvalidateBindings()
310 m_pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
311 m_pBindings->Update(SID_STYLE_NEW_BY_EXAMPLE);
312 m_pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
313 m_pBindings->Update(SID_STYLE_UPDATE_BY_EXAMPLE);
314 m_pBindings->Invalidate(SID_STYLE_WATERCAN, true);
315 m_pBindings->Update(SID_STYLE_WATERCAN);
316 m_pBindings->Invalidate(SID_STYLE_NEW, true);
317 m_pBindings->Update(SID_STYLE_NEW);
318 m_pBindings->Invalidate(SID_STYLE_DRAGHIERARCHIE, true);
319 m_pBindings->Update(SID_STYLE_DRAGHIERARCHIE);
322 void StyleList::Initialize()
324 m_pBindings->Invalidate(SID_STYLE_FAMILY);
325 m_pBindings->Update(SID_STYLE_FAMILY);
327 m_xFmtLb->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
328 m_xFmtLb->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
329 m_xFmtLb->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
330 m_xFmtLb->connect_changed(LINK(this, StyleList, FmtSelectHdl));
331 m_xFmtLb->connect_popup_menu(LINK(this, StyleList, PopupFlatMenuHdl));
332 m_xFmtLb->connect_key_press(LINK(this, StyleList, KeyInputHdl));
333 m_xFmtLb->set_selection_mode(SelectionMode::Multiple);
334 m_xTreeBox->connect_changed(LINK(this, StyleList, FmtSelectHdl));
335 m_xTreeBox->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
336 m_xTreeBox->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
337 m_xTreeBox->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
338 m_xTreeBox->connect_popup_menu(LINK(this, StyleList, PopupTreeMenuHdl));
339 m_xTreeBox->connect_key_press(LINK(this, StyleList, KeyInputHdl));
340 m_xTreeBox->connect_drag_begin(LINK(this, StyleList, DragBeginHdl));
341 m_xTreeView1DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xFmtLb));
342 m_xTreeView2DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xTreeBox));
344 m_pParentDialog->connect_stylelist_read_resource(LINK(this, StyleList, ReadResource));
345 m_pParentDialog->connect_stylelist_clear(LINK(this, StyleList, Clear));
346 m_pParentDialog->connect_stylelist_cleanup(LINK(this, StyleList, Cleanup));
347 m_pParentDialog->connect_stylelist_execute_drop(LINK(this, StyleList, ExecuteDrop));
348 m_pParentDialog->connect_stylelist_execute_new_menu(
349 LINK(this, StyleList, NewMenuExecuteAction));
350 m_pParentDialog->connect_stylelist_for_watercan(LINK(this, StyleList, IsSafeForWaterCan));
351 m_pParentDialog->connect_stylelist_has_selected_style(LINK(this, StyleList, HasSelectedStyle));
352 m_pParentDialog->connect_stylelist_update_style_dependents(
353 LINK(this, StyleList, UpdateStyleDependents));
354 m_pParentDialog->connect_stylelist_enable_tree_drag(LINK(this, StyleList, EnableTreeDrag));
355 m_pParentDialog->connect_stylelist_enable_delete(LINK(this, StyleList, EnableDelete));
356 m_pParentDialog->connect_stylelist_set_water_can_state(LINK(this, StyleList, SetWaterCanState));
357 m_pParentDialog->connect_set_family(LINK(this, StyleList, SetFamily));
359 int nTreeHeight = m_xFmtLb->get_height_rows(8);
360 m_xFmtLb->set_size_request(-1, nTreeHeight);
361 m_xTreeBox->set_size_request(-1, nTreeHeight);
363 m_xFmtLb->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
364 m_xFmtLb->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
365 m_xTreeBox->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
366 m_xTreeBox->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
367 bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
368 m_xFmtLb->set_column_custom_renderer(0, bCustomPreview);
369 m_xTreeBox->set_column_custom_renderer(0, bCustomPreview);
371 m_xFmtLb->set_visible(!m_bHierarchical);
372 m_xTreeBox->set_visible(m_bHierarchical);
373 Update();
376 void StyleList::UpdateFamily()
378 m_bUpdateFamily = false;
380 SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
381 SfxViewFrame* pViewFrame = pDispat->GetFrame();
382 SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
384 SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
385 m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
386 if (pOldStyleSheetPool != m_pStyleSheetPool)
388 if (pOldStyleSheetPool)
389 EndListening(*pOldStyleSheetPool);
390 if (m_pStyleSheetPool)
391 StartListening(*m_pStyleSheetPool);
394 m_bTreeDrag = true;
395 m_bCanNew = m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
396 m_pParentDialog->EnableNew(m_bCanNew, this);
397 m_bTreeDrag = true;
398 if (m_pStyleSheetPool)
400 if (!m_xTreeBox->get_visible())
401 UpdateStyles(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
402 else
404 UpdateStyles(StyleFlags::UpdateFamily);
405 FillTreeBox(GetActualFamily());
409 InvalidateBindings();
412 bool StyleList::EnableExecute()
414 return m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
417 void StyleList::connect_LoadFactoryStyleFilter(const Link<SfxObjectShell const*, sal_Int32>& rLink)
419 m_aLoadFactoryStyleFilter = rLink;
422 void StyleList::connect_SaveSelection(const Link<StyleList&, SfxObjectShell*> rLink)
424 m_aSaveSelection = rLink;
427 void StyleList::connect_UpdateStyleDependents(const Link<void*, void> rLink)
429 m_aUpdateStyleDependents = rLink;
432 /** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
433 create a style out of the current selection.
435 sal_Int8 StyleList::AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
437 if (rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR))
439 // special case: page styles are allowed to create new styles by example
440 // but not allowed to be created by drag and drop
441 if (GetActualFamily() == SfxStyleFamily::Page || m_bNewByExampleDisabled)
442 return DND_ACTION_NONE;
443 else
444 return DND_ACTION_COPY;
446 // to enable the autoscroll when we're close to the edges
447 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
448 pTreeView->get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
449 return DND_ACTION_MOVE;
452 // handles drop of content in treeview when creating a new style
453 IMPL_LINK(StyleList, ExecuteDrop, const ExecuteDropEvent&, rEvt, sal_Int8)
455 SfxObjectShell* pDocShell = m_pCurObjShell;
456 if (pDocShell)
458 TransferableDataHelper aHelper(rEvt.maDropEvent.Transferable);
459 sal_uInt32 nFormatCount = aHelper.GetFormatCount();
461 sal_Int8 nRet = DND_ACTION_NONE;
463 bool bFormatFound = false;
465 for (sal_uInt32 i = 0; i < nFormatCount; ++i)
467 SotClipboardFormatId nId = aHelper.GetFormat(i);
468 TransferableObjectDescriptor aDesc;
470 if (aHelper.GetTransferableObjectDescriptor(nId, aDesc))
472 if (aDesc.maClassName == pDocShell->GetFactory().GetClassId())
474 Application::PostUserEvent(
475 LINK(m_pParentDialog, SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop),
476 this);
478 bFormatFound = true;
479 nRet = rEvt.mnAction;
480 break;
485 if (bFormatFound)
486 return nRet;
489 if (!m_xTreeBox->get_visible())
490 return DND_ACTION_NONE;
492 if (!m_bAllowReParentDrop)
493 return DND_ACTION_NONE;
495 // otherwise if we're dragging with the treeview to set a new parent of the dragged style
496 weld::TreeView* pSource = m_xTreeBox->get_drag_source();
497 // only dragging within the same widget allowed
498 if (!pSource || pSource != m_xTreeBox.get())
499 return DND_ACTION_NONE;
501 std::unique_ptr<weld::TreeIter> xSource(m_xTreeBox->make_iterator());
502 if (!m_xTreeBox->get_selected(xSource.get()))
503 return DND_ACTION_NONE;
505 std::unique_ptr<weld::TreeIter> xTarget(m_xTreeBox->make_iterator());
506 if (!m_xTreeBox->get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
508 // if nothing under the mouse, use the last row
509 int nChildren = m_xTreeBox->n_children();
510 if (!nChildren)
511 return DND_ACTION_NONE;
512 if (!m_xTreeBox->get_iter_first(*xTarget)
513 || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
514 return DND_ACTION_NONE;
515 while (m_xTreeBox->get_row_expanded(*xTarget))
517 nChildren = m_xTreeBox->iter_n_children(*xTarget);
518 if (!m_xTreeBox->iter_children(*xTarget)
519 || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
520 return DND_ACTION_NONE;
523 OUString aTargetStyle = m_xTreeBox->get_text(*xTarget);
524 DropHdl(m_xTreeBox->get_text(*xSource), aTargetStyle);
525 m_xTreeBox->unset_drag_dest_row();
526 FillTreeBox(GetActualFamily());
527 m_pParentDialog->SelectStyle(aTargetStyle, false, *this);
528 return DND_ACTION_NONE;
531 IMPL_LINK_NOARG(StyleList, NewMenuExecuteAction, void*, void)
533 if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
534 return;
536 const SfxStyleFamily eFam = GetFamilyItem()->GetFamily();
537 const SfxStyleFamilyItem* pItem = GetFamilyItem();
538 SfxStyleSearchBits nFilter(SfxStyleSearchBits::Auto);
539 if (pItem && m_nActFilter != 0xffff)
540 nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
541 if (nFilter == SfxStyleSearchBits::Auto) // automatic
542 nFilter = m_nAppFilter;
544 // why? : FloatingWindow must not be parent of a modal dialog
545 SfxNewStyleDlg aDlg(m_pContainer, *m_pStyleSheetPool, eFam);
546 auto nResult = aDlg.run();
547 if (nResult == RET_OK)
549 const OUString aTemplName(aDlg.GetName());
550 m_pParentDialog->Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE, aTemplName, "",
551 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
552 nFilter);
553 UpdateFamily();
554 m_aUpdateFamily.Call(*this);
558 void StyleList::DropHdl(const OUString& rStyle, const OUString& rParent)
560 m_bDontUpdate = true;
561 const SfxStyleFamilyItem* pItem = GetFamilyItem();
562 const SfxStyleFamily eFam = pItem->GetFamily();
563 m_pStyleSheetPool->SetParent(eFam, rStyle, rParent);
564 m_bDontUpdate = false;
567 void StyleList::PrepareMenu(const Point& rPos)
569 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
570 std::unique_ptr<weld::TreeIter> xIter(pTreeView->make_iterator());
571 if (pTreeView->get_dest_row_at_pos(rPos, xIter.get(), false) && !pTreeView->is_selected(*xIter))
573 pTreeView->unselect_all();
574 pTreeView->set_cursor(*xIter);
575 pTreeView->select(*xIter);
577 FmtSelectHdl(*pTreeView);
580 /** Internal structure for the establishment of the hierarchical view */
581 namespace
583 class StyleTree_Impl;
586 typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;
588 namespace
590 class StyleTree_Impl
592 private:
593 OUString aName;
594 OUString aParent;
595 StyleTreeArr_Impl pChildren;
597 public:
598 bool HasParent() const { return !aParent.isEmpty(); }
600 StyleTree_Impl(const OUString& rName, const OUString& rParent)
601 : aName(rName)
602 , aParent(rParent)
603 , pChildren(0)
607 const OUString& getName() const { return aName; }
608 const OUString& getParent() const { return aParent; }
609 StyleTreeArr_Impl& getChildren() { return pChildren; }
613 static void MakeTree_Impl(StyleTreeArr_Impl& rArr, const OUString& aUIName)
615 const comphelper::string::NaturalStringSorter aSorter(
616 ::comphelper::getProcessComponentContext(),
617 Application::GetSettings().GetLanguageTag().getLocale());
619 std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
620 styleFinder.reserve(rArr.size());
621 for (const auto& pEntry : rArr)
623 styleFinder.emplace(pEntry->getName(), pEntry.get());
626 // Arrange all under their Parents
627 for (auto& pEntry : rArr)
629 if (!pEntry->HasParent())
630 continue;
631 auto it = styleFinder.find(pEntry->getParent());
632 if (it != styleFinder.end())
634 StyleTree_Impl* pCmp = it->second;
635 // Insert child entries sorted
636 auto iPos = std::lower_bound(
637 pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
638 [&aSorter](std::unique_ptr<StyleTree_Impl> const& pEntry1,
639 std::unique_ptr<StyleTree_Impl> const& pEntry2) {
640 return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
642 pCmp->getChildren().insert(iPos, std::move(pEntry));
646 // Only keep tree roots in rArr, child elements can be accessed through the hierarchy
647 rArr.erase(
648 std::remove_if(rArr.begin(), rArr.end(),
649 [](std::unique_ptr<StyleTree_Impl> const& pEntry) { return !pEntry; }),
650 rArr.end());
652 // tdf#91106 sort top level styles
653 std::sort(rArr.begin(), rArr.end());
654 std::sort(rArr.begin(), rArr.end(),
655 [&aSorter, &aUIName](std::unique_ptr<StyleTree_Impl> const& pEntry1,
656 std::unique_ptr<StyleTree_Impl> const& pEntry2) {
657 if (pEntry2->getName() == aUIName)
658 return false;
659 if (pEntry1->getName() == aUIName)
660 return true; // default always first
661 return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
665 static bool IsExpanded_Impl(const std::vector<OUString>& rEntries, std::u16string_view rStr)
667 for (const auto& rEntry : rEntries)
669 if (rEntry == rStr)
670 return true;
672 return false;
675 static void FillBox_Impl(weld::TreeView& rBox, StyleTree_Impl* pEntry,
676 const std::vector<OUString>& rEntries, SfxStyleFamily eStyleFamily,
677 const weld::TreeIter* pParent)
679 std::unique_ptr<weld::TreeIter> xResult = rBox.make_iterator();
680 const OUString& rName = pEntry->getName();
681 rBox.insert(pParent, -1, &rName, &rName, nullptr, nullptr, false, xResult.get());
683 for (size_t i = 0; i < pEntry->getChildren().size(); ++i)
684 FillBox_Impl(rBox, pEntry->getChildren()[i].get(), rEntries, eStyleFamily, xResult.get());
687 namespace SfxTemplate
689 // converts from SFX_STYLE_FAMILY Ids to 1-6
690 static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
692 switch (nFamily)
694 case SfxStyleFamily::Char:
695 return 1;
696 case SfxStyleFamily::Para:
697 return 2;
698 case SfxStyleFamily::Frame:
699 return 3;
700 case SfxStyleFamily::Page:
701 return 4;
702 case SfxStyleFamily::Pseudo:
703 return 5;
704 case SfxStyleFamily::Table:
705 return 6;
706 default:
707 return 0xffff;
710 // converts from 1-6 to SFX_STYLE_FAMILY Ids
711 static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
713 switch (nId)
715 case 1:
716 return SfxStyleFamily::Char;
717 case 2:
718 return SfxStyleFamily::Para;
719 case 3:
720 return SfxStyleFamily::Frame;
721 case 4:
722 return SfxStyleFamily::Page;
723 case 5:
724 return SfxStyleFamily::Pseudo;
725 case 6:
726 return SfxStyleFamily::Table;
727 default:
728 return SfxStyleFamily::All;
733 sal_uInt16 StyleList::StyleNrToInfoOffset(sal_uInt16 nId)
735 const SfxStyleFamilyItem& rItem = m_xStyleFamilies->at(nId);
736 return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily()) - 1;
739 // Helper function: Access to the current family item
740 const SfxStyleFamilyItem* StyleList::GetFamilyItem() const
742 const size_t nCount = m_xStyleFamilies->size();
743 for (size_t i = 0; i < nCount; ++i)
745 const SfxStyleFamilyItem& rItem = m_xStyleFamilies->at(i);
746 sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
747 if (nId == m_nActFamily)
748 return &rItem;
750 return nullptr;
753 void StyleList::GetSelectedStyle() const
755 const OUString aTemplName(GetSelectedEntry());
756 const SfxStyleFamilyItem* pItem = GetFamilyItem();
757 m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
760 // Used to get the current selected entry in visible treeview
761 OUString StyleList::GetSelectedEntry() const
763 OUString aRet;
764 if (m_xTreeBox->get_visible())
765 aRet = m_xTreeBox->get_selected_text();
766 else
767 aRet = m_xFmtLb->get_selected_text();
768 return aRet;
772 * Is it safe to show the water-can / fill icon. If we've a
773 * hierarchical widget - we have only single select, otherwise
774 * we need to check if we have a multi-selection. We either have
775 * a m_xTreeBox showing or an m_xFmtLb (which we hide when not shown)
777 IMPL_LINK_NOARG(StyleList, IsSafeForWaterCan, void*, bool)
779 if (m_xTreeBox->get_visible())
780 return m_xTreeBox->get_selected_index() != -1;
781 else
782 return m_xFmtLb->count_selected_rows() == 1;
785 IMPL_LINK(StyleList, SetWaterCanState, const SfxBoolItem*, pItem, void)
787 size_t nCount = m_xStyleFamilies->size();
788 m_pBindings->EnterRegistrations();
789 for (size_t n = 0; n < nCount; n++)
791 SfxControllerItem* pCItem = pBoundItems[n].get();
792 bool bChecked = pItem && pItem->GetValue();
793 if (pCItem->IsBound() == bChecked)
795 if (!bChecked)
796 pCItem->ReBind();
797 else
798 pCItem->UnBind();
801 m_pBindings->LeaveRegistrations();
804 void StyleList::FamilySelect(sal_uInt16 nEntry)
806 m_nActFamily = nEntry;
807 SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
808 SfxUInt16Item const aItem(SID_STYLE_FAMILY,
809 static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
810 pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
811 m_pBindings->Invalidate(SID_STYLE_FAMILY);
812 m_pBindings->Update(SID_STYLE_FAMILY);
813 UpdateFamily();
814 m_aUpdateFamily.Call(*this);
817 // It selects the style in treeview
818 // bIsCallBack is true for the selected style. For eg. if "Addressee" is selected in
819 // styles, bIsCallBack will be true for it.
820 void StyleList::SelectStyle(const OUString& rStr, bool bIsCallback)
822 const SfxStyleFamilyItem* pItem = GetFamilyItem();
823 if (!pItem)
824 return;
825 const SfxStyleFamily eFam = pItem->GetFamily();
826 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(rStr, eFam);
827 if (pStyle)
829 bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
830 m_pParentDialog->EnableEdit(bReadWrite, this);
831 m_pParentDialog->EnableHide(bReadWrite && !pStyle->IsHidden() && !pStyle->IsUsed(), this);
832 m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden(), this);
834 else
836 m_pParentDialog->EnableEdit(false, this);
837 m_pParentDialog->EnableHide(false, this);
838 m_pParentDialog->EnableShow(false, this);
841 if (bIsCallback)
842 return;
844 if (m_xTreeBox->get_visible())
846 if (!rStr.isEmpty())
848 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
849 bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
850 while (bEntry)
852 if (m_xTreeBox->get_text(*xEntry) == rStr)
854 m_xTreeBox->scroll_to_row(*xEntry);
855 m_xTreeBox->select(*xEntry);
856 break;
858 bEntry = m_xTreeBox->iter_next(*xEntry);
861 else if (eFam == SfxStyleFamily::Pseudo)
863 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
864 if (m_xTreeBox->get_iter_first(*xEntry))
866 m_xTreeBox->scroll_to_row(*xEntry);
867 m_xTreeBox->select(*xEntry);
870 else
871 m_xTreeBox->unselect_all();
873 else
875 bool bSelect = !rStr.isEmpty();
876 if (bSelect)
878 std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
879 bool bEntry = m_xFmtLb->get_iter_first(*xEntry);
880 while (bEntry && m_xFmtLb->get_text(*xEntry) != rStr)
881 bEntry = m_xFmtLb->iter_next(*xEntry);
882 if (!bEntry)
883 bSelect = false;
884 else
886 if (!m_xFmtLb->is_selected(*xEntry))
888 m_xFmtLb->unselect_all();
889 m_xFmtLb->scroll_to_row(*xEntry);
890 m_xFmtLb->select(*xEntry);
895 if (!bSelect)
897 m_xFmtLb->unselect_all();
898 m_pParentDialog->EnableEdit(false, this);
899 m_pParentDialog->EnableHide(false, this);
900 m_pParentDialog->EnableShow(false, this);
905 static void MakeExpanded_Impl(const weld::TreeView& rBox, std::vector<OUString>& rEntries)
907 std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator();
908 if (rBox.get_iter_first(*xEntry))
912 if (rBox.get_row_expanded(*xEntry))
913 rEntries.push_back(rBox.get_text(*xEntry));
914 } while (rBox.iter_next(*xEntry));
918 IMPL_LINK(StyleList, EnableTreeDrag, bool, m_bEnable, void)
920 if (m_pStyleSheetPool)
922 const SfxStyleFamilyItem* pItem = GetFamilyItem();
923 SfxStyleSheetBase* pStyle = pItem ? m_pStyleSheetPool->First(pItem->GetFamily()) : nullptr;
924 m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bEnable;
926 m_bTreeDrag = m_bEnable;
929 // Fill the treeview
931 void StyleList::FillTreeBox(SfxStyleFamily eFam)
933 assert(m_xTreeBox && "FillTreeBox() without treebox");
934 if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
935 return;
937 const SfxStyleFamilyItem* pItem = GetFamilyItem();
938 if (!pItem)
939 return;
941 StyleTreeArr_Impl aArr;
942 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, SfxStyleSearchBits::AllVisible);
944 m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bTreeDrag;
946 while (pStyle)
948 StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent());
949 aArr.emplace_back(pNew);
950 pStyle = m_pStyleSheetPool->Next();
952 OUString aUIName = getDefaultStyleName(eFam);
953 MakeTree_Impl(aArr, aUIName);
954 std::vector<OUString> aEntries;
955 MakeExpanded_Impl(*m_xTreeBox, aEntries);
956 m_xTreeBox->freeze();
957 m_xTreeBox->clear();
958 const sal_uInt16 nCount = aArr.size();
960 for (sal_uInt16 i = 0; i < nCount; ++i)
962 FillBox_Impl(*m_xTreeBox, aArr[i].get(), aEntries, eFam, nullptr);
963 aArr[i].reset();
966 m_pParentDialog->EnableItem("watercan", false);
968 SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
970 m_xTreeBox->thaw();
972 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
973 bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
974 if (bEntry && nCount)
975 m_xTreeBox->expand_row(*xEntry);
977 while (bEntry)
979 if (IsExpanded_Impl(aEntries, m_xTreeBox->get_text(*xEntry)))
980 m_xTreeBox->expand_row(*xEntry);
981 bEntry = m_xTreeBox->iter_next(*xEntry);
984 OUString aStyle;
985 if (pState) // Select current entry
986 aStyle = pState->GetStyleName();
987 m_pParentDialog->SelectStyle(aStyle, false, *this);
988 EnableDelete(nullptr);
991 static OUString lcl_GetStyleFamilyName(SfxStyleFamily nFamily)
993 if (nFamily == SfxStyleFamily::Char)
994 return "CharacterStyles";
995 if (nFamily == SfxStyleFamily::Para)
996 return "ParagraphStyles";
997 if (nFamily == SfxStyleFamily::Page)
998 return "PageStyles";
999 if (nFamily == SfxStyleFamily::Table)
1000 return "TableStyles";
1001 if (nFamily == SfxStyleFamily::Pseudo)
1002 return "NumberingStyles";
1003 return OUString();
1006 OUString StyleList::getDefaultStyleName(const SfxStyleFamily eFam)
1008 OUString sDefaultStyle;
1009 OUString aFamilyName = lcl_GetStyleFamilyName(eFam);
1010 if (aFamilyName == "TableStyles")
1011 sDefaultStyle = "Default Style";
1012 else if (aFamilyName == "NumberingStyles")
1013 sDefaultStyle = "No List";
1014 else
1015 sDefaultStyle = "Standard";
1016 uno::Reference<style::XStyleFamiliesSupplier> xModel(m_pCurObjShell->GetModel(),
1017 uno::UNO_QUERY);
1018 OUString aUIName;
1021 uno::Reference<container::XNameAccess> xStyles;
1022 uno::Reference<container::XNameAccess> xCont = xModel->getStyleFamilies();
1023 xCont->getByName(aFamilyName) >>= xStyles;
1024 uno::Reference<beans::XPropertySet> xInfo;
1025 xStyles->getByName(sDefaultStyle) >>= xInfo;
1026 xInfo->getPropertyValue("DisplayName") >>= aUIName;
1028 catch (const uno::Exception&)
1031 return aUIName;
1034 SfxStyleFamily StyleList::GetActualFamily() const
1036 const SfxStyleFamilyItem* pFamilyItem = GetFamilyItem();
1037 if (!pFamilyItem || m_nActFamily == 0xffff)
1038 return SfxStyleFamily::Para;
1039 else
1040 return pFamilyItem->GetFamily();
1043 IMPL_LINK_NOARG(StyleList, HasSelectedStyle, void*, bool)
1045 return m_xTreeBox->get_visible() ? m_xTreeBox->get_selected_index() != -1
1046 : m_xFmtLb->count_selected_rows() != 0;
1049 IMPL_LINK_NOARG(StyleList, UpdateStyleDependents, void*, void)
1051 // Trigger Help PI. Only when the watercan is on
1052 if (m_nActFamily != 0xffff && m_pParentDialog->IsCheckedItem("watercan") &&
1053 // only if that region is allowed
1054 nullptr != m_pFamilyState[m_nActFamily - 1] && IsSafeForWaterCan(nullptr))
1056 m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, "", "", 0, *this);
1057 m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, GetSelectedEntry(), "",
1058 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1062 // Comes into action when the current style is changed
1063 void StyleList::UpdateStyles(StyleFlags nFlags)
1065 OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
1066 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1067 if (!pItem)
1069 // Is the case for the template catalog
1070 const size_t nFamilyCount = m_xStyleFamilies->size();
1071 size_t n;
1072 for (n = 0; n < nFamilyCount; n++)
1073 if (m_pFamilyState[StyleNrToInfoOffset(n)])
1074 break;
1075 if (n == nFamilyCount)
1076 // It happens sometimes, God knows why
1077 return;
1078 m_nAppFilter = m_pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
1079 m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1, *this);
1080 pItem = GetFamilyItem();
1083 const SfxStyleFamily eFam = pItem->GetFamily();
1085 SfxStyleSearchBits nFilter(m_nActFilter < pItem->GetFilterList().size()
1086 ? pItem->GetFilterList()[m_nActFilter].nFlags
1087 : SfxStyleSearchBits::Auto);
1088 if (nFilter == SfxStyleSearchBits::Auto) // automatic
1089 nFilter = m_nAppFilter;
1091 OSL_ENSURE(m_pStyleSheetPool, "no StyleSheetPool");
1092 if (!m_pStyleSheetPool)
1093 return;
1095 pItem = GetFamilyItem();
1097 m_aUpdateStyles.Call(nFlags);
1099 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, nFilter);
1101 std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
1102 bool bEntry = m_xFmtLb->get_iter_first(*xEntry);
1103 std::vector<OUString> aStrings;
1105 comphelper::string::NaturalStringSorter aSorter(
1106 ::comphelper::getProcessComponentContext(),
1107 Application::GetSettings().GetLanguageTag().getLocale());
1109 while (pStyle)
1111 aStrings.push_back(pStyle->GetName());
1112 pStyle = m_pStyleSheetPool->Next();
1114 OUString aUIName = getDefaultStyleName(eFam);
1116 // Paradoxically, with a list and non-Latin style names,
1117 // sorting twice is faster than sorting once.
1118 // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
1119 // Then the second sort needs to call its (much more expensive) comparator less often.
1120 std::sort(aStrings.begin(), aStrings.end());
1121 std::sort(aStrings.begin(), aStrings.end(),
1122 [&aSorter, &aUIName](const OUString& rLHS, const OUString& rRHS) {
1123 if (rRHS == aUIName)
1124 return false;
1125 if (rLHS == aUIName)
1126 return true; // default always first
1127 return aSorter.compare(rLHS, rRHS) < 0;
1130 size_t nCount = aStrings.size();
1131 size_t nPos = 0;
1132 while (nPos < nCount && bEntry && aStrings[nPos] == m_xFmtLb->get_text(*xEntry))
1134 ++nPos;
1135 bEntry = m_xFmtLb->iter_next(*xEntry);
1138 if (nPos < nCount || bEntry)
1140 // Fills the display box
1141 m_xFmtLb->freeze();
1142 m_xFmtLb->clear();
1144 for (nPos = 0; nPos < nCount; ++nPos)
1145 m_xFmtLb->append(aStrings[nPos], aStrings[nPos]);
1147 m_xFmtLb->thaw();
1149 // Selects the current style if any
1150 SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
1151 OUString aStyle;
1152 if (pState)
1153 aStyle = pState->GetStyleName();
1154 m_pParentDialog->SelectStyle(aStyle, false, *this);
1155 EnableDelete(nullptr);
1158 void StyleList::SetFamilyState(sal_uInt16 nSlotId, const SfxTemplateItem* pItem)
1160 sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
1161 m_pFamilyState[nIdx].reset();
1162 if (pItem)
1163 m_pFamilyState[nIdx].reset(new SfxTemplateItem(*pItem));
1164 m_bUpdateFamily = true;
1167 void StyleList::SetHierarchical()
1169 m_bHierarchical = true;
1170 const OUString aSelectEntry(GetSelectedEntry());
1171 m_xFmtLb->hide();
1172 FillTreeBox(GetActualFamily());
1173 m_pParentDialog->SelectStyle(aSelectEntry, false, *this);
1174 m_xTreeBox->show();
1177 void StyleList::SetFilterControlsHandle()
1179 m_xTreeBox->hide();
1180 m_xFmtLb->show();
1181 m_bHierarchical = false;
1184 // Handler for the New-Buttons
1185 void StyleList::NewHdl()
1187 if (m_nActFamily == 0xffff
1188 || !(m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1))
1189 return;
1191 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1192 const SfxStyleFamily eFam = pItem->GetFamily();
1193 SfxStyleSearchBits nMask(SfxStyleSearchBits::Auto);
1194 if (m_nActFilter != 0xffff)
1195 nMask = pItem->GetFilterList()[m_nActFilter].nFlags;
1196 if (nMask == SfxStyleSearchBits::Auto) // automatic
1197 nMask = m_nAppFilter;
1199 m_pParentDialog->Execute_Impl(SID_STYLE_NEW, "", GetSelectedEntry(),
1200 static_cast<sal_uInt16>(eFam), *this, nMask);
1203 // Handler for the edit-Buttons
1204 void StyleList::EditHdl()
1206 if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
1208 sal_uInt16 nFilter = m_nActFilter;
1209 OUString aTemplName(GetSelectedEntry());
1210 GetSelectedStyle(); // -Wall required??
1211 m_pParentDialog->Execute_Impl(SID_STYLE_EDIT, aTemplName, OUString(),
1212 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
1213 SfxStyleSearchBits::Auto, &nFilter);
1217 // Handler for the Delete-Buttons
1218 void StyleList::DeleteHdl()
1220 if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1221 return;
1223 bool bUsedStyle = false; // one of the selected styles are used in the document?
1225 std::vector<std::unique_ptr<weld::TreeIter>> aList;
1226 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1227 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1229 OUStringBuffer aMsg;
1230 aMsg.append(SfxResId(STR_DELETE_STYLE_USED) + SfxResId(STR_DELETE_STYLE));
1232 pTreeView->selected_foreach(
1233 [this, pTreeView, pItem, &aList, &bUsedStyle, &aMsg](weld::TreeIter& rEntry) {
1234 aList.emplace_back(pTreeView->make_iterator(&rEntry));
1235 // check the style is used or not
1236 const OUString aTemplName(pTreeView->get_text(rEntry));
1238 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
1240 if (pStyle->IsUsed()) // pStyle is in use in the document?
1242 if (bUsedStyle) // add a separator for the second and later styles
1243 aMsg.append(", ");
1244 aMsg.append(aTemplName);
1245 bUsedStyle = true;
1248 return false;
1251 bool aApproved = false;
1253 // we only want to show the dialog once and if we want to delete a style in use (UX-advice)
1254 if (bUsedStyle)
1256 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
1257 pTreeView, VclMessageType::Question, VclButtonsType::YesNo, aMsg.makeStringAndClear()));
1258 aApproved = xBox->run() == RET_YES;
1261 // if there are no used styles selected or the user approved the changes
1262 if (bUsedStyle && !aApproved)
1263 return;
1265 for (auto const& elem : aList)
1267 const OUString aTemplName(pTreeView->get_text(*elem));
1268 m_bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting
1269 m_pParentDialog->Execute_Impl(SID_STYLE_DELETE, aTemplName, OUString(),
1270 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1272 if (m_xTreeBox->get_visible())
1274 weld::RemoveParentKeepChildren(*m_xTreeBox, *elem);
1275 m_bDontUpdate = false;
1278 m_bDontUpdate = false; // if everything is deleted set m_bDontUpdate back to false
1279 UpdateStyles(StyleFlags::UpdateFamilyList); // and force-update the list
1282 void StyleList::HideHdl()
1284 if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1285 return;
1287 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1288 pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
1289 OUString aTemplName = pTreeView->get_text(rEntry);
1291 m_pParentDialog->Execute_Impl(SID_STYLE_HIDE, aTemplName, OUString(),
1292 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1294 return false;
1298 void StyleList::ShowHdl()
1300 if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1301 return;
1303 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1304 pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
1305 OUString aTemplName = pTreeView->get_text(rEntry);
1307 m_pParentDialog->Execute_Impl(SID_STYLE_SHOW, aTemplName, OUString(),
1308 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1310 return false;
1314 IMPL_LINK_NOARG(StyleList, EnableDelete, void*, void)
1316 bool bEnableDelete(false);
1317 if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
1319 OSL_ENSURE(m_pStyleSheetPool, "No StyleSheetPool");
1320 const OUString aTemplName(GetSelectedEntry());
1321 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1322 const SfxStyleFamily eFam = pItem->GetFamily();
1323 SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
1324 if (pItem->GetFilterList().size() > m_nActFilter)
1325 nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
1326 if (nFilter == SfxStyleSearchBits::Auto) // automatic
1327 nFilter = m_nAppFilter;
1328 const SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(
1329 aTemplName, eFam, m_xTreeBox->get_visible() ? SfxStyleSearchBits::All : nFilter);
1331 OSL_ENSURE(pStyle, "Style not found");
1332 if (pStyle && pStyle->IsUserDefined())
1334 if (pStyle->HasClearParentSupport() || !pStyle->IsUsed())
1336 bEnableDelete = true;
1340 m_pParentDialog->EnableDel(bEnableDelete, this);
1343 IMPL_LINK_NOARG(StyleList, Clear, void*, void)
1345 m_xStyleFamilies.reset();
1346 for (auto& i : m_pFamilyState)
1347 i.reset();
1348 m_pCurObjShell = nullptr;
1349 for (auto& i : pBoundItems)
1350 i.reset();
1353 void StyleList::ShowMenu(const CommandEvent& rCEvt)
1355 CreateContextMenu();
1356 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1357 OString sCommand(
1358 mxMenu->popup_at_rect(pTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1))));
1359 MenuSelect(sCommand);
1362 void StyleList::MenuSelect(const OString& rIdent)
1364 sLastItemIdent = rIdent;
1365 if (sLastItemIdent.isEmpty())
1366 return;
1367 Application::PostUserEvent(LINK(this, StyleList, MenuSelectAsyncHdl)); /***check this****/
1370 void StyleList::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1372 const SfxHintId nId = rHint.GetId();
1374 switch (nId)
1376 case SfxHintId::UpdateDone:
1378 SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1379 SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
1380 if (m_pParentDialog->GetNotifyUpdate()
1381 && (!m_pParentDialog->IsCheckedItem("watercan")
1382 || (pDocShell && pDocShell->GetStyleSheetPool() != m_pStyleSheetPool)))
1384 m_pParentDialog->SetNotifyupdate(false);
1385 Update();
1387 else if (m_bUpdateFamily)
1389 UpdateFamily();
1390 m_aUpdateFamily.Call(*this);
1393 if (m_pStyleSheetPool)
1395 OUString aStr = GetSelectedEntry();
1396 if (!aStr.isEmpty())
1398 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1399 if (!pItem)
1400 break;
1401 const SfxStyleFamily eFam = pItem->GetFamily();
1402 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aStr, eFam);
1403 if (pStyle)
1405 bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
1406 m_pParentDialog->EnableEdit(bReadWrite, this);
1407 m_pParentDialog->EnableHide(
1408 bReadWrite && !pStyle->IsUsed() && !pStyle->IsHidden(), this);
1409 m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden(), this);
1411 else
1413 m_pParentDialog->EnableEdit(false, this);
1414 m_pParentDialog->EnableHide(false, this);
1415 m_pParentDialog->EnableShow(false, this);
1419 break;
1422 // Necessary if switching between documents and in both documents
1423 // the same template is used. Do not immediately call Update_Impl,
1424 // for the case that one of the documents is an internal InPlaceObject!
1425 case SfxHintId::DocChanged:
1426 m_pParentDialog->SetNotifyupdate(true);
1427 break;
1428 case SfxHintId::Dying:
1430 EndListening(*m_pStyleSheetPool);
1431 m_pStyleSheetPool = nullptr;
1432 break;
1434 default:
1435 break;
1438 // Do not set timer when the stylesheet pool is in the box, because it is
1439 // possible that a new one is registered after the timer is up -
1440 // works bad in UpdateStyles_Impl ()!
1442 if (!m_bDontUpdate && nId != SfxHintId::Dying
1443 && (dynamic_cast<const SfxStyleSheetPoolHint*>(&rHint)
1444 || dynamic_cast<const SfxStyleSheetHint*>(&rHint)
1445 || dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint)
1446 || nId == SfxHintId::StyleSheetModified))
1448 if (!pIdle)
1450 pIdle.reset(new Idle("SfxCommonTemplate"));
1451 pIdle->SetPriority(TaskPriority::LOWEST);
1452 pIdle->SetInvokeHandler(LINK(this, StyleList, TimeOut));
1454 pIdle->Start();
1458 IMPL_LINK_NOARG(StyleList, TimeOut, Timer*, void)
1460 if (!m_bDontUpdate)
1462 m_bDontUpdate = true;
1463 if (!m_xTreeBox->get_visible())
1464 UpdateStyles(StyleFlags::UpdateFamilyList);
1465 else
1467 FillTreeBox(GetActualFamily());
1468 SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
1469 if (pState)
1471 m_pParentDialog->SelectStyle(pState->GetStyleName(), false, *this);
1472 EnableDelete(nullptr);
1475 m_bDontUpdate = false;
1476 pIdle.reset();
1478 else
1479 pIdle->Start();
1482 IMPL_LINK_NOARG(StyleList, MenuSelectAsyncHdl, void*, void)
1484 if (sLastItemIdent == "new")
1485 NewHdl();
1486 else if (sLastItemIdent == "edit")
1487 EditHdl();
1488 else if (sLastItemIdent == "delete")
1489 DeleteHdl();
1490 else if (sLastItemIdent == "hide")
1491 HideHdl();
1492 else if (sLastItemIdent == "show")
1493 ShowHdl();
1496 // Double-click on a style sheet in the ListBox is applied.
1497 IMPL_LINK(StyleList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
1499 rUnsetDragIcon = false;
1500 // Allow normal processing. only if bAllowReParentDrop is true
1501 return !m_bAllowReParentDrop;
1504 IMPL_LINK(StyleList, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
1506 bool bRet = false;
1507 const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
1508 if (m_bCanDel && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_DELETE)
1510 DeleteHdl();
1511 bRet = true;
1513 return bRet;
1516 IMPL_LINK(StyleList, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
1518 weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1519 const OUString aTemplName(pTreeView->get_text(rEntry));
1520 OUString sQuickHelpText(aTemplName);
1522 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1523 if (!pItem)
1524 return sQuickHelpText;
1525 SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
1527 if (pStyle && pStyle->IsUsed()) // pStyle is in use in the document?
1529 OUString sUsedBy;
1530 if (pStyle->GetFamily() == SfxStyleFamily::Pseudo)
1531 sUsedBy = pStyle->GetUsedBy();
1533 if (!sUsedBy.isEmpty())
1535 const sal_Int32 nMaxLen = 80;
1536 if (sUsedBy.getLength() > nMaxLen)
1538 sUsedBy = OUString::Concat(sUsedBy.subView(0, nMaxLen)) + "...";
1541 OUString aMessage = SfxResId(STR_STYLEUSEDBY);
1542 aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy);
1543 sQuickHelpText = aTemplName + " " + aMessage;
1547 return sQuickHelpText;
1550 IMPL_LINK(StyleList, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
1552 vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
1553 const ::tools::Rectangle& rRect = std::get<1>(aPayload);
1554 ::tools::Rectangle aRect(
1555 rRect.TopLeft(),
1556 Size(rRenderContext.GetOutputSize().Width() - rRect.Left(), rRect.GetHeight()));
1557 bool bSelected = std::get<2>(aPayload);
1558 const OUString& rId = std::get<3>(aPayload);
1560 rRenderContext.Push(vcl::PushFlags::TEXTCOLOR);
1561 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1562 if (bSelected)
1563 rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
1564 else
1565 rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
1567 bool bSuccess = false;
1569 SfxObjectShell* pShell = SfxObjectShell::Current();
1570 sfx2::StyleManager* pStyleManager = pShell ? pShell->GetStyleManager() : nullptr;
1572 if (pStyleManager)
1574 const SfxStyleFamilyItem* pItem = GetFamilyItem();
1575 SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(rId, pItem->GetFamily());
1577 if (pStyleSheet)
1579 rRenderContext.Push(vcl::PushFlags::ALL);
1580 sal_Int32 nSize = aRect.GetHeight();
1581 std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
1582 pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
1583 bSuccess = pStylePreviewRenderer->recalculate() && pStylePreviewRenderer->render(aRect);
1584 rRenderContext.Pop();
1588 if (!bSuccess)
1589 rRenderContext.DrawText(aRect, rId, DrawTextFlags::Left | DrawTextFlags::VCenter);
1591 rRenderContext.Pop();
1594 // Selection of a template during the Watercan-Status
1595 IMPL_LINK(StyleList, FmtSelectHdl, weld::TreeView&, rListBox, void)
1597 std::unique_ptr<weld::TreeIter> xHdlEntry = rListBox.make_iterator();
1598 if (!rListBox.get_cursor(xHdlEntry.get()))
1599 return;
1601 m_pParentDialog->SelectStyle(rListBox.get_text(*xHdlEntry), true, *this);
1604 IMPL_LINK_NOARG(StyleList, TreeListApplyHdl, weld::TreeView&, bool)
1606 // only if that region is allowed
1607 if (m_nActFamily != 0xffff && nullptr != m_pFamilyState[m_nActFamily - 1]
1608 && !GetSelectedEntry().isEmpty())
1610 m_pParentDialog->Execute_Impl(SID_STYLE_APPLY, GetSelectedEntry(), OUString(),
1611 static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
1612 SfxStyleSearchBits::Auto, nullptr, &m_nModifier);
1614 // After selecting a focused item if possible again on the app window
1615 if (dynamic_cast<const SfxTemplateDialog_Impl*>(m_pParentDialog) != nullptr)
1617 SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1618 SfxViewShell* pVu = pViewFrame->GetViewShell();
1619 vcl::Window* pAppWin = pVu ? pVu->GetWindow() : nullptr;
1620 if (pAppWin)
1621 pAppWin->GrabFocus();
1624 return true;
1627 IMPL_LINK(StyleList, MousePressHdl, const MouseEvent&, rMEvt, bool)
1629 m_nModifier = rMEvt.GetModifier();
1630 return false;
1633 // Notice from SfxBindings that the update is completed. Pushes out the update
1634 // of the display.
1635 void StyleList::Update()
1637 bool bDocChanged = false;
1638 SfxStyleSheetBasePool* pNewPool = nullptr;
1639 SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1640 SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
1641 if (pDocShell)
1642 pNewPool = pDocShell->GetStyleSheetPool();
1644 if (pNewPool != m_pStyleSheetPool && pDocShell)
1646 SfxModule* pNewModule = pDocShell->GetModule();
1647 if (pNewModule && pNewModule != m_Module)
1649 m_aClearResource.Call(nullptr);
1650 m_aReadResource.Call(*this);
1652 if (m_pStyleSheetPool)
1654 EndListening(*m_pStyleSheetPool);
1655 m_pStyleSheetPool = nullptr;
1658 if (pNewPool)
1660 StartListening(*pNewPool);
1661 m_pStyleSheetPool = pNewPool;
1662 bDocChanged = true;
1666 if (m_bUpdateFamily)
1668 UpdateFamily();
1669 m_aUpdateFamily.Call(*this);
1672 sal_uInt16 i;
1673 for (i = 0; i < MAX_FAMILIES; ++i)
1674 if (m_pFamilyState[i])
1675 break;
1676 if (i == MAX_FAMILIES || !pNewPool)
1677 // nothing is allowed
1678 return;
1680 SfxTemplateItem* pItem = nullptr;
1681 // current region not within the allowed region or default
1682 if (m_nActFamily == 0xffff || nullptr == (pItem = m_pFamilyState[m_nActFamily - 1].get()))
1684 m_pParentDialog->CheckItem(OString::number(m_nActFamily), false);
1685 const size_t nFamilyCount = m_xStyleFamilies->size();
1686 size_t n;
1687 for (n = 0; n < nFamilyCount; n++)
1688 if (m_pFamilyState[StyleNrToInfoOffset(n)])
1689 break;
1691 std::unique_ptr<SfxTemplateItem>& pNewItem = m_pFamilyState[StyleNrToInfoOffset(n)];
1692 m_nAppFilter = pNewItem->GetValue();
1693 m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1, *this);
1694 pItem = pNewItem.get();
1696 else if (bDocChanged)
1698 // other DocShell -> all new
1699 m_pParentDialog->CheckItem(OString::number(m_nActFamily));
1700 m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(pDocShell));
1701 m_pParentDialog->IsUpdate(true, *this);
1702 if (0xffff == m_nActFilter)
1704 m_nActFilter = pDocShell->GetAutoStyleFilterIndex();
1707 m_nAppFilter = pItem->GetValue();
1708 if (!m_xTreeBox->get_visible())
1710 UpdateStyles(StyleFlags::UpdateFamilyList);
1712 else
1713 FillTreeBox(GetActualFamily());
1715 else
1717 // other filters for automatic
1718 m_pParentDialog->CheckItem(OString::number(m_nActFamily));
1719 const SfxStyleFamilyItem* pStyleItem = GetFamilyItem();
1720 if (pStyleItem
1721 && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[m_nActFilter].nFlags
1722 && m_nAppFilter != pItem->GetValue())
1724 m_nAppFilter = pItem->GetValue();
1725 if (!m_xTreeBox->get_visible())
1726 UpdateStyles(StyleFlags::UpdateFamilyList);
1727 else
1728 FillTreeBox(GetActualFamily());
1730 else
1732 m_nAppFilter = pItem->GetValue();
1735 const OUString aStyle(pItem->GetStyleName());
1736 m_pParentDialog->SelectStyle(aStyle, false, *this);
1737 EnableDelete(nullptr);
1738 m_pParentDialog->EnableNew(m_bCanNew, this);
1741 void StyleList::EnablePreview(bool bCustomPreview)
1743 m_xFmtLb->clear();
1744 m_xFmtLb->set_column_custom_renderer(0, bCustomPreview);
1745 m_xTreeBox->clear();
1746 m_xTreeBox->set_column_custom_renderer(0, bCustomPreview);
1749 const SfxStyleFamilyItem& StyleList::GetFamilyItemByIndex(size_t i) const
1751 return m_xStyleFamilies->at(i);
1754 IMPL_STATIC_LINK(StyleList, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
1756 vcl::RenderContext& rRenderContext = aPayload.first;
1757 return Size(42, 32 * rRenderContext.GetDPIScaleFactor());
1760 IMPL_LINK(StyleList, PopupFlatMenuHdl, const CommandEvent&, rCEvt, bool)
1762 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1763 return false;
1765 PrepareMenu(rCEvt.GetMousePosPixel());
1767 if (m_xFmtLb->count_selected_rows() <= 0)
1769 m_pParentDialog->EnableEdit(false, this);
1770 m_pParentDialog->EnableDel(false, this);
1773 ShowMenu(rCEvt);
1775 return true;
1778 IMPL_LINK(StyleList, PopupTreeMenuHdl, const CommandEvent&, rCEvt, bool)
1780 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1781 return false;
1783 PrepareMenu(rCEvt.GetMousePosPixel());
1785 ShowMenu(rCEvt);
1787 return true;
1789 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */