1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
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>
74 using namespace css::beans
;
75 using namespace css::frame
;
76 using namespace css::uno
;
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)
92 , m_bUpdateFamily(false)
94 , m_bBindingUpdate(true)
95 , m_pStyleSheetPool(nullptr)
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
)
108 m_xFmtLb
->set_help_id(HID_TEMPLATE_FMT
);
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();
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;
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
)
170 SfxViewFrame
* pViewFrame
= m_pBindings
->GetDispatcher_Impl()->GetFrame();
171 m_pCurObjShell
= pViewFrame
->GetObjectShell();
172 m_Module
= m_pCurObjShell
? m_pCurObjShell
->GetModule() : nullptr;
174 m_xStyleFamilies
= m_Module
->CreateStyleFamilies();
175 if (!m_xStyleFamilies
)
176 m_xStyleFamilies
.emplace();
178 m_nActFilter
= 0xffff;
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();
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
;
200 case SfxStyleFamily::Para
:
201 nSlot
= SID_STYLE_FAMILY2
;
203 case SfxStyleFamily::Frame
:
204 nSlot
= SID_STYLE_FAMILY3
;
206 case SfxStyleFamily::Page
:
207 nSlot
= SID_STYLE_FAMILY4
;
209 case SfxStyleFamily::Pseudo
:
210 nSlot
= SID_STYLE_FAMILY5
;
212 case SfxStyleFamily::Table
:
213 nSlot
= SID_STYLE_FAMILY6
;
216 OSL_FAIL("unknown StyleFamily");
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
);
250 void StyleList::EnableNewByExample(bool newByExampleDisabled
)
252 m_bNewByExampleDisabled
= newByExampleDisabled
;
255 class TreeViewDropTarget final
: public DropTargetHelper
258 StyleList
& m_rParent
;
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
;
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);
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
);
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
);
395 m_bCanNew
= m_xTreeBox
->get_visible() || m_xFmtLb
->count_selected_rows() <= 1;
396 m_pParentDialog
->EnableNew(m_bCanNew
, this);
398 if (m_pStyleSheetPool
)
400 if (!m_xTreeBox
->get_visible())
401 UpdateStyles(StyleFlags::UpdateFamily
| StyleFlags::UpdateFamilyList
);
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
;
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
;
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
),
479 nRet
= rEvt
.mnAction
;
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();
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)
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,
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 */
583 class StyleTree_Impl
;
586 typedef std::vector
<std::unique_ptr
<StyleTree_Impl
>> StyleTreeArr_Impl
;
595 StyleTreeArr_Impl pChildren
;
598 bool HasParent() const { return !aParent
.isEmpty(); }
600 StyleTree_Impl(const OUString
& rName
, const OUString
& rParent
)
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())
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
648 std::remove_if(rArr
.begin(), rArr
.end(),
649 [](std::unique_ptr
<StyleTree_Impl
> const& pEntry
) { return !pEntry
; }),
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
)
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
)
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
)
694 case SfxStyleFamily::Char
:
696 case SfxStyleFamily::Para
:
698 case SfxStyleFamily::Frame
:
700 case SfxStyleFamily::Page
:
702 case SfxStyleFamily::Pseudo
:
704 case SfxStyleFamily::Table
:
710 // converts from 1-6 to SFX_STYLE_FAMILY Ids
711 static SfxStyleFamily
NIdToSfxFamilyId(sal_uInt16 nId
)
716 return SfxStyleFamily::Char
;
718 return SfxStyleFamily::Para
;
720 return SfxStyleFamily::Frame
;
722 return SfxStyleFamily::Page
;
724 return SfxStyleFamily::Pseudo
;
726 return SfxStyleFamily::Table
;
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
)
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
764 if (m_xTreeBox
->get_visible())
765 aRet
= m_xTreeBox
->get_selected_text();
767 aRet
= m_xFmtLb
->get_selected_text();
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;
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
)
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
);
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();
825 const SfxStyleFamily eFam
= pItem
->GetFamily();
826 SfxStyleSheetBase
* pStyle
= m_pStyleSheetPool
->Find(rStr
, eFam
);
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);
836 m_pParentDialog
->EnableEdit(false, this);
837 m_pParentDialog
->EnableHide(false, this);
838 m_pParentDialog
->EnableShow(false, this);
844 if (m_xTreeBox
->get_visible())
848 std::unique_ptr
<weld::TreeIter
> xEntry
= m_xTreeBox
->make_iterator();
849 bool bEntry
= m_xTreeBox
->get_iter_first(*xEntry
);
852 if (m_xTreeBox
->get_text(*xEntry
) == rStr
)
854 m_xTreeBox
->scroll_to_row(*xEntry
);
855 m_xTreeBox
->select(*xEntry
);
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
);
871 m_xTreeBox
->unselect_all();
875 bool bSelect
= !rStr
.isEmpty();
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
);
886 if (!m_xFmtLb
->is_selected(*xEntry
))
888 m_xFmtLb
->unselect_all();
889 m_xFmtLb
->scroll_to_row(*xEntry
);
890 m_xFmtLb
->select(*xEntry
);
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
;
931 void StyleList::FillTreeBox(SfxStyleFamily eFam
)
933 assert(m_xTreeBox
&& "FillTreeBox() without treebox");
934 if (!m_pStyleSheetPool
|| m_nActFamily
== 0xffff)
937 const SfxStyleFamilyItem
* pItem
= GetFamilyItem();
941 StyleTreeArr_Impl aArr
;
942 SfxStyleSheetBase
* pStyle
= m_pStyleSheetPool
->First(eFam
, SfxStyleSearchBits::AllVisible
);
944 m_bAllowReParentDrop
= pStyle
&& pStyle
->HasParentSupport() && m_bTreeDrag
;
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();
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);
966 m_pParentDialog
->EnableItem("watercan", false);
968 SfxTemplateItem
* pState
= m_pFamilyState
[m_nActFamily
- 1].get();
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
);
979 if (IsExpanded_Impl(aEntries
, m_xTreeBox
->get_text(*xEntry
)))
980 m_xTreeBox
->expand_row(*xEntry
);
981 bEntry
= m_xTreeBox
->iter_next(*xEntry
);
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
)
999 if (nFamily
== SfxStyleFamily::Table
)
1000 return "TableStyles";
1001 if (nFamily
== SfxStyleFamily::Pseudo
)
1002 return "NumberingStyles";
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";
1015 sDefaultStyle
= "Standard";
1016 uno::Reference
<style::XStyleFamiliesSupplier
> xModel(m_pCurObjShell
->GetModel(),
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
&)
1034 SfxStyleFamily
StyleList::GetActualFamily() const
1036 const SfxStyleFamilyItem
* pFamilyItem
= GetFamilyItem();
1037 if (!pFamilyItem
|| m_nActFamily
== 0xffff)
1038 return SfxStyleFamily::Para
;
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();
1069 // Is the case for the template catalog
1070 const size_t nFamilyCount
= m_xStyleFamilies
->size();
1072 for (n
= 0; n
< nFamilyCount
; n
++)
1073 if (m_pFamilyState
[StyleNrToInfoOffset(n
)])
1075 if (n
== nFamilyCount
)
1076 // It happens sometimes, God knows why
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
)
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());
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
)
1125 if (rLHS
== aUIName
)
1126 return true; // default always first
1127 return aSorter
.compare(rLHS
, rRHS
) < 0;
1130 size_t nCount
= aStrings
.size();
1132 while (nPos
< nCount
&& bEntry
&& aStrings
[nPos
] == m_xFmtLb
->get_text(*xEntry
))
1135 bEntry
= m_xFmtLb
->iter_next(*xEntry
);
1138 if (nPos
< nCount
|| bEntry
)
1140 // Fills the display box
1144 for (nPos
= 0; nPos
< nCount
; ++nPos
)
1145 m_xFmtLb
->append(aStrings
[nPos
], aStrings
[nPos
]);
1149 // Selects the current style if any
1150 SfxTemplateItem
* pState
= m_pFamilyState
[m_nActFamily
- 1].get();
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();
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());
1172 FillTreeBox(GetActualFamily());
1173 m_pParentDialog
->SelectStyle(aSelectEntry
, false, *this);
1177 void StyleList::SetFilterControlsHandle()
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))
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))
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
1244 aMsg
.append(aTemplName
);
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)
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
)
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))
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);
1298 void StyleList::ShowHdl()
1300 if (m_nActFamily
== 0xffff || !HasSelectedStyle(nullptr))
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);
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
)
1348 m_pCurObjShell
= nullptr;
1349 for (auto& i
: pBoundItems
)
1353 void StyleList::ShowMenu(const CommandEvent
& rCEvt
)
1355 CreateContextMenu();
1356 weld::TreeView
* pTreeView
= m_xTreeBox
->get_visible() ? m_xTreeBox
.get() : m_xFmtLb
.get();
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())
1367 Application::PostUserEvent(LINK(this, StyleList
, MenuSelectAsyncHdl
)); /***check this****/
1370 void StyleList::Notify(SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
1372 const SfxHintId nId
= rHint
.GetId();
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);
1387 else if (m_bUpdateFamily
)
1390 m_aUpdateFamily
.Call(*this);
1393 if (m_pStyleSheetPool
)
1395 OUString aStr
= GetSelectedEntry();
1396 if (!aStr
.isEmpty())
1398 const SfxStyleFamilyItem
* pItem
= GetFamilyItem();
1401 const SfxStyleFamily eFam
= pItem
->GetFamily();
1402 SfxStyleSheetBase
* pStyle
= m_pStyleSheetPool
->Find(aStr
, eFam
);
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);
1413 m_pParentDialog
->EnableEdit(false, this);
1414 m_pParentDialog
->EnableHide(false, this);
1415 m_pParentDialog
->EnableShow(false, this);
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);
1428 case SfxHintId::Dying
:
1430 EndListening(*m_pStyleSheetPool
);
1431 m_pStyleSheetPool
= nullptr;
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
))
1450 pIdle
.reset(new Idle("SfxCommonTemplate"));
1451 pIdle
->SetPriority(TaskPriority::LOWEST
);
1452 pIdle
->SetInvokeHandler(LINK(this, StyleList
, TimeOut
));
1458 IMPL_LINK_NOARG(StyleList
, TimeOut
, Timer
*, void)
1462 m_bDontUpdate
= true;
1463 if (!m_xTreeBox
->get_visible())
1464 UpdateStyles(StyleFlags::UpdateFamilyList
);
1467 FillTreeBox(GetActualFamily());
1468 SfxTemplateItem
* pState
= m_pFamilyState
[m_nActFamily
- 1].get();
1471 m_pParentDialog
->SelectStyle(pState
->GetStyleName(), false, *this);
1472 EnableDelete(nullptr);
1475 m_bDontUpdate
= false;
1482 IMPL_LINK_NOARG(StyleList
, MenuSelectAsyncHdl
, void*, void)
1484 if (sLastItemIdent
== "new")
1486 else if (sLastItemIdent
== "edit")
1488 else if (sLastItemIdent
== "delete")
1490 else if (sLastItemIdent
== "hide")
1492 else if (sLastItemIdent
== "show")
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)
1507 const vcl::KeyCode
& rKeyCode
= rKeyEvent
.GetKeyCode();
1508 if (m_bCanDel
&& !rKeyCode
.GetModifier() && rKeyCode
.GetCode() == KEY_DELETE
)
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();
1524 return sQuickHelpText
;
1525 SfxStyleSheetBase
* pStyle
= m_pStyleSheetPool
->Find(aTemplName
, pItem
->GetFamily());
1527 if (pStyle
&& pStyle
->IsUsed()) // pStyle is in use in the document?
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(
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();
1563 rRenderContext
.SetTextColor(rStyleSettings
.GetHighlightTextColor());
1565 rRenderContext
.SetTextColor(rStyleSettings
.GetDialogTextColor());
1567 bool bSuccess
= false;
1569 SfxObjectShell
* pShell
= SfxObjectShell::Current();
1570 sfx2::StyleManager
* pStyleManager
= pShell
? pShell
->GetStyleManager() : nullptr;
1574 const SfxStyleFamilyItem
* pItem
= GetFamilyItem();
1575 SfxStyleSheetBase
* pStyleSheet
= pStyleManager
->Search(rId
, pItem
->GetFamily());
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();
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()))
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;
1621 pAppWin
->GrabFocus();
1627 IMPL_LINK(StyleList
, MousePressHdl
, const MouseEvent
&, rMEvt
, bool)
1629 m_nModifier
= rMEvt
.GetModifier();
1633 // Notice from SfxBindings that the update is completed. Pushes out the update
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();
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;
1660 StartListening(*pNewPool
);
1661 m_pStyleSheetPool
= pNewPool
;
1666 if (m_bUpdateFamily
)
1669 m_aUpdateFamily
.Call(*this);
1673 for (i
= 0; i
< MAX_FAMILIES
; ++i
)
1674 if (m_pFamilyState
[i
])
1676 if (i
== MAX_FAMILIES
|| !pNewPool
)
1677 // nothing is allowed
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();
1687 for (n
= 0; n
< nFamilyCount
; n
++)
1688 if (m_pFamilyState
[StyleNrToInfoOffset(n
)])
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
);
1713 FillTreeBox(GetActualFamily());
1717 // other filters for automatic
1718 m_pParentDialog
->CheckItem(OString::number(m_nActFamily
));
1719 const SfxStyleFamilyItem
* pStyleItem
= GetFamilyItem();
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
);
1728 FillTreeBox(GetActualFamily());
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
)
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
)
1765 PrepareMenu(rCEvt
.GetMousePosPixel());
1767 if (m_xFmtLb
->count_selected_rows() <= 0)
1769 m_pParentDialog
->EnableEdit(false, this);
1770 m_pParentDialog
->EnableDel(false, this);
1778 IMPL_LINK(StyleList
, PopupTreeMenuHdl
, const CommandEvent
&, rCEvt
, bool)
1780 if (rCEvt
.GetCommand() != CommandEventId::ContextMenu
)
1783 PrepareMenu(rCEvt
.GetMousePosPixel());
1789 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */