xref: /core/sfx2/source/dialog/templdlg.cxx (revision 107399d6)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 
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>
40 
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>
56 
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>
63 
64 #include <comphelper/string.hxx>
65 
66 #include <sfx2/StyleManager.hxx>
67 #include <sfx2/StylePreviewRenderer.hxx>
68 
69 using namespace css;
70 using namespace css::beans;
71 using namespace css::frame;
72 using namespace css::uno;
73 
74 class SfxCommonTemplateDialog_Impl::DeletionWatcher
75 {
76     typedef void (DeletionWatcher::* bool_type)();
77 
78 public:
79     explicit DeletionWatcher(SfxCommonTemplateDialog_Impl& rDialog)
80         : m_pDialog(&rDialog)
81         , m_pPrevious(m_pDialog->impl_setDeletionWatcher(this))
82     {
83     }
84 
85     ~DeletionWatcher()
86     {
87         if (m_pDialog)
88             m_pDialog->impl_setDeletionWatcher(m_pPrevious);
89     }
90 
91     DeletionWatcher(const DeletionWatcher&) = delete;
92     DeletionWatcher& operator=(const DeletionWatcher&) = delete;
93 
94     // Signal that the dialog was deleted
95     void signal()
96     {
97         m_pDialog = nullptr;
98         if (m_pPrevious)
99             m_pPrevious->signal();
100     }
101 
102     // Return true if the dialog was deleted
103     operator bool_type() const
104     {
105         return m_pDialog ? nullptr : &DeletionWatcher::signal;
106     }
107 
108 private:
109     SfxCommonTemplateDialog_Impl* m_pDialog;
110     DeletionWatcher *const m_pPrevious; /// let's add more epicycles!
111 };
112 
113 /** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
114     create a style out of the current selection.
115 */
116 sal_Int8 SfxCommonTemplateDialog_Impl::AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
117 {
118     if (rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR))
119     {
120         // special case: page styles are allowed to create new styles by example
121         // but not allowed to be created by drag and drop
122         if (GetActualFamily() == SfxStyleFamily::Page || bNewByExampleDisabled)
123             return DND_ACTION_NONE;
124         else
125             return DND_ACTION_COPY;
126     }
127 
128     // to enable the autoscroll when we're close to the edges
129     weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
130     pTreeView->get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
131     return DND_ACTION_MOVE;
132 }
133 
134 sal_Int8 SfxCommonTemplateDialog_Impl::ExecuteDrop(const ExecuteDropEvent& rEvt)
135 {
136     // handle drop of content into the treeview to create a new style
137     SfxObjectShell* pDocShell = GetObjectShell();
138     if (pDocShell)
139     {
140         TransferableDataHelper aHelper(rEvt.maDropEvent.Transferable);
141         sal_uInt32 nFormatCount = aHelper.GetFormatCount();
142 
143         sal_Int8 nRet = DND_ACTION_NONE;
144 
145         bool bFormatFound = false;
146 
147         for ( sal_uInt32 i = 0; i < nFormatCount; ++i )
148         {
149             SotClipboardFormatId nId = aHelper.GetFormat(i);
150             TransferableObjectDescriptor aDesc;
151 
152             if ( aHelper.GetTransferableObjectDescriptor( nId, aDesc ) )
153             {
154                 if ( aDesc.maClassName == pDocShell->GetFactory().GetClassId() )
155                 {
156                     Application::PostUserEvent(LINK(this, SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop));
157 
158                     bFormatFound = true;
159                     nRet =  rEvt.mnAction;
160                     break;
161                 }
162             }
163         }
164 
165         if (bFormatFound)
166             return nRet;
167     }
168 
169     if (!mxTreeBox->get_visible())
170         return DND_ACTION_NONE;
171 
172     if (!bAllowReParentDrop)
173         return DND_ACTION_NONE;
174 
175     // otherwise if we're dragging with the treeview to set a new parent of the dragged style
176     weld::TreeView* pSource = mxTreeBox->get_drag_source();
177     // only dragging within the same widget allowed
178     if (!pSource || pSource != mxTreeBox.get())
179         return DND_ACTION_NONE;
180 
181     std::unique_ptr<weld::TreeIter> xSource(mxTreeBox->make_iterator());
182     if (!mxTreeBox->get_selected(xSource.get()))
183         return DND_ACTION_NONE;
184 
185     std::unique_ptr<weld::TreeIter> xTarget(mxTreeBox->make_iterator());
186     if (!mxTreeBox->get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
187     {
188         // if nothing under the mouse, use the last row
189         int nChildren = mxTreeBox->n_children();
190         if (!nChildren)
191             return DND_ACTION_NONE;
192         if (!mxTreeBox->get_iter_first(*xTarget) || !mxTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
193             return DND_ACTION_NONE;
194         while (mxTreeBox->get_row_expanded(*xTarget))
195         {
196             nChildren = mxTreeBox->iter_n_children(*xTarget);
197             if (!mxTreeBox->iter_children(*xTarget) || !mxTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
198                 return DND_ACTION_NONE;
199         }
200     }
201     OUString aTargetStyle = mxTreeBox->get_text(*xTarget);
202     DropHdl(mxTreeBox->get_text(*xSource), aTargetStyle);
203     mxTreeBox->unset_drag_dest_row();
204     FillTreeBox();
205     SelectStyle(aTargetStyle, false);
206     return DND_ACTION_NONE;
207 }
208 
209 IMPL_LINK(SfxCommonTemplateDialog_Impl, DragBeginHdl, bool&, rUnsetDragIcon, bool)
210 {
211     rUnsetDragIcon = false;
212     // Allow normal processing. only if bAllowReParentDrop is true
213     return !bAllowReParentDrop;
214 }
215 
216 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop, void*, void)
217 {
218     ActionSelect("new");
219 }
220 
221 IMPL_LINK(SfxCommonTemplateDialog_Impl, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
222 {
223     bool bRet = false;
224     const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
225     if (bCanDel && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_DELETE)
226     {
227         DeleteHdl();
228         bRet =  true;
229     }
230     return bRet;
231 }
232 
233 IMPL_LINK(SfxCommonTemplateDialog_Impl, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
234 {
235     weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
236     const OUString aTemplName(pTreeView->get_text(rEntry));
237     OUString sQuickHelpText(aTemplName);
238 
239     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
240     if (!pItem)
241         return sQuickHelpText;
242     SfxStyleSheetBase* pStyle = pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
243 
244     if (pStyle && pStyle->IsUsed())  // pStyle is in use in the document?
245     {
246         OUString sUsedBy;
247         if (pStyle->GetFamily() == SfxStyleFamily::Pseudo)
248             sUsedBy = pStyle->GetUsedBy();
249 
250         if (!sUsedBy.isEmpty())
251         {
252             const sal_Int32 nMaxLen = 80;
253             if (sUsedBy.getLength() > nMaxLen)
254             {
255                 sUsedBy = OUString::Concat(sUsedBy.subView(0, nMaxLen)) + "...";
256             }
257 
258             OUString aMessage = SfxResId(STR_STYLEUSEDBY);
259             aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy);
260             sQuickHelpText = aTemplName + " " + aMessage;
261         }
262     }
263 
264     return sQuickHelpText;
265 }
266 
267 IMPL_STATIC_LINK(SfxCommonTemplateDialog_Impl, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
268 {
269     vcl::RenderContext& rRenderContext = aPayload.first;
270     return Size(42, 32 * rRenderContext.GetDPIScaleFactor());
271 }
272 
273 IMPL_LINK(SfxCommonTemplateDialog_Impl, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
274 {
275     vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
276     const ::tools::Rectangle& rRect = std::get<1>(aPayload);
277     ::tools::Rectangle aRect(rRect.TopLeft(), Size(rRenderContext.GetOutputSize().Width() - rRect.Left(), rRect.GetHeight()));
278     bool bSelected = std::get<2>(aPayload);
279     const OUString& rId = std::get<3>(aPayload);
280 
281     rRenderContext.Push(PushFlags::TEXTCOLOR);
282     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
283     if (bSelected)
284         rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
285     else
286         rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
287 
288     bool bSuccess = false;
289 
290     SfxObjectShell* pShell = SfxObjectShell::Current();
291     sfx2::StyleManager* pStyleManager = pShell ? pShell->GetStyleManager(): nullptr;
292 
293     if (pStyleManager)
294     {
295         const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
296         SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(rId, pItem->GetFamily());
297 
298         if (pStyleSheet)
299         {
300             rRenderContext.Push(PushFlags::ALL);
301             sal_Int32 nSize = aRect.GetHeight();
302             std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
303                 pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
304             bSuccess = pStylePreviewRenderer->recalculate() && pStylePreviewRenderer->render(aRect);
305             rRenderContext.Pop();
306         }
307     }
308 
309     if (!bSuccess)
310         rRenderContext.DrawText(aRect, rId, DrawTextFlags::Left | DrawTextFlags::VCenter);
311 
312     rRenderContext.Pop();
313 }
314 
315 IMPL_LINK(SfxCommonTemplateDialog_Impl, PopupFlatMenuHdl, const CommandEvent&, rCEvt, bool)
316 {
317     if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
318         return false;
319 
320     PrepareMenu(rCEvt.GetMousePosPixel());
321 
322     if (mxFmtLb->count_selected_rows() <= 0)
323     {
324         EnableEdit(false);
325         EnableDel(false);
326     }
327 
328     ShowMenu(rCEvt);
329 
330     return true;
331 }
332 
333 void SfxCommonTemplateDialog_Impl::PrepareMenu(const Point& rPos)
334 {
335     weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
336     std::unique_ptr<weld::TreeIter> xIter(pTreeView->make_iterator());
337     if (pTreeView->get_dest_row_at_pos(rPos, xIter.get(), false) && !pTreeView->is_selected(*xIter))
338     {
339         pTreeView->unselect_all();
340         pTreeView->set_cursor(*xIter);
341         pTreeView->select(*xIter);
342         FmtSelectHdl(*pTreeView);
343     }
344 }
345 
346 void SfxCommonTemplateDialog_Impl::ShowMenu(const CommandEvent& rCEvt)
347 {
348     CreateContextMenu();
349 
350     weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
351     OString sCommand(mxMenu->popup_at_rect(pTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
352     MenuSelect(sCommand);
353 }
354 
355 IMPL_LINK(SfxCommonTemplateDialog_Impl, PopupTreeMenuHdl, const CommandEvent&, rCEvt, bool)
356 {
357     if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
358         return false;
359 
360     PrepareMenu(rCEvt.GetMousePosPixel());
361 
362     ShowMenu(rCEvt);
363 
364     return true;
365 }
366 
367 SfxTemplatePanelControl::SfxTemplatePanelControl(SfxBindings* pBindings, vcl::Window* pParentWindow)
368     : PanelLayout(pParentWindow, "TemplatePanel", "sfx/ui/templatepanel.ui", nullptr)
369     , pImpl(new SfxTemplateDialog_Impl(pBindings, this))
370 {
371     OSL_ASSERT(pBindings!=nullptr);
372 }
373 
374 SfxTemplatePanelControl::~SfxTemplatePanelControl()
375 {
376     disposeOnce();
377 }
378 
379 void SfxTemplatePanelControl::dispose()
380 {
381     pImpl.reset();
382     PanelLayout::dispose();
383 }
384 
385 static void MakeExpanded_Impl(const weld::TreeView& rBox, std::vector<OUString>& rEntries)
386 {
387     std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator();
388     if (rBox.get_iter_first(*xEntry))
389     {
390         do
391         {
392             if (rBox.get_row_expanded(*xEntry))
393                 rEntries.push_back(rBox.get_text(*xEntry));
394         } while (rBox.iter_next(*xEntry));
395     }
396 }
397 
398 /** Internal structure for the establishment of the hierarchical view */
399 namespace {
400 
401 class StyleTree_Impl;
402 
403 }
404 
405 typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;
406 
407 namespace {
408 
409 class StyleTree_Impl
410 {
411 private:
412     OUString aName;
413     OUString aParent;
414     StyleTreeArr_Impl pChildren;
415 
416 public:
417     bool HasParent() const { return !aParent.isEmpty(); }
418 
419     StyleTree_Impl(const OUString &rName, const OUString &rParent):
420         aName(rName), aParent(rParent), pChildren(0) {}
421 
422     const OUString& getName() const { return aName; }
423     const OUString& getParent() const { return aParent; }
424     StyleTreeArr_Impl& getChildren() { return pChildren; }
425 };
426 
427 }
428 
429 static void MakeTree_Impl(StyleTreeArr_Impl& rArr, const OUString& aUIName)
430 {
431     const comphelper::string::NaturalStringSorter aSorter(
432         ::comphelper::getProcessComponentContext(),
433         Application::GetSettings().GetLanguageTag().getLocale());
434 
435     std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
436     styleFinder.reserve(rArr.size());
437     for (const auto& pEntry : rArr)
438     {
439         styleFinder.emplace(pEntry->getName(), pEntry.get());
440     }
441 
442     // Arrange all under their Parents
443     for (auto& pEntry : rArr)
444     {
445         if (!pEntry->HasParent())
446             continue;
447         auto it = styleFinder.find(pEntry->getParent());
448         if (it != styleFinder.end())
449         {
450             StyleTree_Impl* pCmp = it->second;
451             // Insert child entries sorted
452             auto iPos = std::lower_bound(pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
453                 [&aSorter](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) { return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0; });
454             pCmp->getChildren().insert(iPos, std::move(pEntry));
455         }
456     }
457 
458     // Only keep tree roots in rArr, child elements can be accessed through the hierarchy
459     rArr.erase(std::remove_if(rArr.begin(), rArr.end(), [](std::unique_ptr<StyleTree_Impl> const & pEntry) { return !pEntry; }), rArr.end());
460 
461     // tdf#91106 sort top level styles
462     std::sort(rArr.begin(), rArr.end());
463     std::sort(rArr.begin(), rArr.end(),
464         [&aSorter, &aUIName](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) {
465             if (pEntry2->getName() == aUIName)
466                 return false;
467             if (pEntry1->getName() == aUIName)
468                 return true; // default always first
469             return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
470         });
471 }
472 
473 static bool IsExpanded_Impl( const std::vector<OUString>& rEntries,
474                              std::u16string_view rStr)
475 {
476     for (const auto & rEntry : rEntries)
477     {
478         if (rEntry == rStr)
479             return true;
480     }
481     return false;
482 }
483 
484 static void FillBox_Impl(weld::TreeView& rBox,
485                          StyleTree_Impl* pEntry,
486                          const std::vector<OUString>& rEntries,
487                          SfxStyleFamily eStyleFamily,
488                          const weld::TreeIter* pParent)
489 {
490     std::unique_ptr<weld::TreeIter> xResult = rBox.make_iterator();
491     const OUString& rName = pEntry->getName();
492     rBox.insert(pParent, -1, &rName, &rName, nullptr, nullptr, false, xResult.get());
493 
494     for (size_t i = 0; i < pEntry->getChildren().size(); ++i)
495         FillBox_Impl(rBox, pEntry->getChildren()[i].get(), rEntries, eStyleFamily, xResult.get());
496 }
497 
498 namespace SfxTemplate
499 {
500     // converts from SFX_STYLE_FAMILY Ids to 1-6
501     static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
502     {
503         switch ( nFamily )
504         {
505             case SfxStyleFamily::Char:   return 1;
506             case SfxStyleFamily::Para:   return 2;
507             case SfxStyleFamily::Frame:  return 3;
508             case SfxStyleFamily::Page:   return 4;
509             case SfxStyleFamily::Pseudo: return 5;
510             case SfxStyleFamily::Table:  return 6;
511             default:                     return 0xffff;
512         }
513     }
514 
515     // converts from 1-6 to SFX_STYLE_FAMILY Ids
516     static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
517     {
518         switch (nId)
519         {
520             case 1: return SfxStyleFamily::Char;
521             case 2: return SfxStyleFamily::Para;
522             case 3: return SfxStyleFamily::Frame;
523             case 4: return SfxStyleFamily::Page;
524             case 5: return SfxStyleFamily::Pseudo;
525             case 6: return SfxStyleFamily::Table;
526             default: return SfxStyleFamily::All;
527         }
528     }
529 }
530 
531 // Constructor
532 
533 SfxCommonTemplateDialog_Impl::SfxCommonTemplateDialog_Impl(SfxBindings* pB, weld::Container* pC, weld::Builder* pBuilder)
534     : pBindings(pB)
535     , mpContainer(pC)
536     , pModule(nullptr)
537     , pStyleSheetPool(nullptr)
538     , pCurObjShell(nullptr)
539     , xModuleManager(frame::ModuleManager::create(::comphelper::getProcessComponentContext()))
540     , m_pDeletionWatcher(nullptr)
541     , mxFmtLb(pBuilder->weld_tree_view("flatview"))
542     , mxTreeBox(pBuilder->weld_tree_view("treeview"))
543     , mxPreviewCheckbox(pBuilder->weld_check_button("showpreview"))
544     , mxFilterLb(pBuilder->weld_combo_box("filter"))
545 
546     , nActFamily(0xffff)
547     , nActFilter(0)
548     , nAppFilter(SfxStyleSearchBits::Auto)
549 
550     , m_nModifier(0)
551     , bDontUpdate(false)
552     , bIsWater(false)
553     , bUpdate(false)
554     , bUpdateFamily(false)
555     , bCanEdit(false)
556     , bCanDel(false)
557     , bCanNew(true)
558     , bCanHide(true)
559     , bCanShow(false)
560     , bWaterDisabled(false)
561     , bNewByExampleDisabled(false)
562     , bUpdateByExampleDisabled(false)
563     , bTreeDrag(true)
564     , bAllowReParentDrop(false)
565     , bHierarchical(false)
566     , m_bWantHierarchical(false)
567     , bBindingUpdate(true)
568 {
569     mxFmtLb->set_help_id(HID_TEMPLATE_FMT);
570     mxFilterLb->set_help_id(HID_TEMPLATE_FILTER);
571     mxPreviewCheckbox->set_active(officecfg::Office::Common::StylesAndFormatting::Preview::get());
572 }
573 
574 sal_uInt16 SfxCommonTemplateDialog_Impl::StyleNrToInfoOffset(sal_uInt16 nId)
575 {
576     const SfxStyleFamilyItem& rItem = pStyleFamilies->at( nId );
577     return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily())-1;
578 }
579 
580 void SfxTemplateDialog_Impl::EnableEdit(bool bEnable)
581 {
582     SfxCommonTemplateDialog_Impl::EnableEdit( bEnable );
583     if( !bEnable || !bUpdateByExampleDisabled )
584         EnableItem("update", bEnable);
585 }
586 
587 void SfxCommonTemplateDialog_Impl::ReadResource()
588 {
589     // Read global user resource
590     for (auto & i : pFamilyState)
591         i.reset();
592 
593     SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
594     pCurObjShell = pViewFrame->GetObjectShell();
595     pModule = pCurObjShell ? pCurObjShell->GetModule() : nullptr;
596     if (pModule)
597         pStyleFamilies = pModule->CreateStyleFamilies();
598     if (!pStyleFamilies)
599         pStyleFamilies.reset(new SfxStyleFamilies);
600 
601     nActFilter = 0xffff;
602     if (pCurObjShell)
603     {
604         nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pCurObjShell ) );
605         if ( 0xffff == nActFilter )
606             nActFilter = pCurObjShell->GetAutoStyleFilterIndex();
607     }
608 
609     // Paste in the toolbox
610     // reverse order, since always inserted at the head
611     size_t nCount = pStyleFamilies->size();
612 
613     pBindings->ENTERREGISTRATIONS();
614 
615     size_t i;
616     for (i = 0; i < nCount; ++i)
617     {
618         sal_uInt16 nSlot = 0;
619         switch (pStyleFamilies->at(i).GetFamily())
620         {
621             case SfxStyleFamily::Char:
622                 nSlot = SID_STYLE_FAMILY1; break;
623             case SfxStyleFamily::Para:
624                 nSlot = SID_STYLE_FAMILY2; break;
625             case SfxStyleFamily::Frame:
626                 nSlot = SID_STYLE_FAMILY3; break;
627             case SfxStyleFamily::Page:
628                 nSlot = SID_STYLE_FAMILY4; break;
629             case SfxStyleFamily::Pseudo:
630                 nSlot = SID_STYLE_FAMILY5; break;
631             case SfxStyleFamily::Table:
632                 nSlot = SID_STYLE_FAMILY6; break;
633             default: OSL_FAIL("unknown StyleFamily"); break;
634         }
635         pBoundItems[i].reset(
636             new SfxTemplateControllerItem(nSlot, *this, *pBindings) );
637     }
638     pBoundItems[i++].reset( new SfxTemplateControllerItem(
639         SID_STYLE_WATERCAN, *this, *pBindings) );
640     pBoundItems[i++].reset( new SfxTemplateControllerItem(
641         SID_STYLE_NEW_BY_EXAMPLE, *this, *pBindings) );
642     pBoundItems[i++].reset( new SfxTemplateControllerItem(
643         SID_STYLE_UPDATE_BY_EXAMPLE, *this, *pBindings) );
644     pBoundItems[i++].reset( new SfxTemplateControllerItem(
645         SID_STYLE_NEW, *this, *pBindings) );
646     pBoundItems[i++].reset( new SfxTemplateControllerItem(
647         SID_STYLE_DRAGHIERARCHIE, *this, *pBindings) );
648     pBoundItems[i++].reset( new SfxTemplateControllerItem(
649         SID_STYLE_EDIT, *this, *pBindings) );
650     pBoundItems[i++].reset( new SfxTemplateControllerItem(
651         SID_STYLE_DELETE, *this, *pBindings) );
652     pBoundItems[i++].reset( new SfxTemplateControllerItem(
653         SID_STYLE_FAMILY, *this, *pBindings) );
654     pBindings->LEAVEREGISTRATIONS();
655 
656     for(; i < COUNT_BOUND_FUNC; ++i)
657         pBoundItems[i] = nullptr;
658 
659     StartListening(*pBindings);
660 
661 // Insert in the reverse order of occurrence in the Style Families. This is for
662 // the toolbar of the designer. The list box of the catalog respects the
663 // correct order by itself.
664 
665 // Sequences: the order of Resource = the order of Toolbar for example list box.
666 // Order of ascending SIDs: Low SIDs are displayed first when templates of
667 // several families are active.
668 
669     // in the Writer the UpdateStyleByExample Toolbox button is removed and
670     // the NewStyle button gets a PopupMenu
671     if(nCount > 4)
672         ReplaceUpdateButtonByMenu();
673 
674     for( ; nCount--; )
675     {
676         const SfxStyleFamilyItem &rItem = pStyleFamilies->at( nCount );
677         sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId( rItem.GetFamily() );
678         InsertFamilyItem(nId, rItem);
679     }
680 
681     for ( i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++ )
682         pBindings->Update(i);
683 }
684 
685 void SfxCommonTemplateDialog_Impl::ClearResource()
686 {
687     ClearFamilyList();
688     impl_clear();
689 }
690 
691 void SfxCommonTemplateDialog_Impl::impl_clear()
692 {
693     pStyleFamilies.reset();
694     for (auto & i : pFamilyState)
695         i.reset();
696     for (auto & i : pBoundItems)
697         i.reset();
698     pCurObjShell = nullptr;
699 }
700 
701 SfxCommonTemplateDialog_Impl::DeletionWatcher *
702 SfxCommonTemplateDialog_Impl::impl_setDeletionWatcher(
703         DeletionWatcher *const pNewWatcher)
704 {
705     DeletionWatcher *const pRet(m_pDeletionWatcher);
706     m_pDeletionWatcher = pNewWatcher;
707     return pRet;
708 }
709 
710 class TreeViewDropTarget final : public DropTargetHelper
711 {
712 private:
713     SfxCommonTemplateDialog_Impl& m_rParent;
714 
715 public:
716     TreeViewDropTarget(SfxCommonTemplateDialog_Impl& rDialog, weld::TreeView& rTreeView)
717         : DropTargetHelper(rTreeView.get_drop_target())
718         , m_rParent(rDialog)
719     {
720     }
721 
722     virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
723     {
724         return m_rParent.AcceptDrop(rEvt, *this);
725     }
726 
727     virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
728     {
729         return m_rParent.ExecuteDrop(rEvt);
730     }
731 };
732 
733 void SfxCommonTemplateDialog_Impl::Initialize()
734 {
735     // Read global user resource
736     ReadResource();
737     pBindings->Invalidate( SID_STYLE_FAMILY );
738     pBindings->Update( SID_STYLE_FAMILY );
739 
740     mxFilterLb->connect_changed(LINK(this, SfxCommonTemplateDialog_Impl, FilterSelectHdl));
741     mxFmtLb->connect_row_activated(LINK( this, SfxCommonTemplateDialog_Impl, TreeListApplyHdl));
742     mxFmtLb->connect_mouse_press(LINK(this, SfxCommonTemplateDialog_Impl, MousePressHdl));
743     mxFmtLb->connect_query_tooltip(LINK(this, SfxCommonTemplateDialog_Impl, QueryTooltipHdl));
744     mxFmtLb->connect_changed(LINK(this, SfxCommonTemplateDialog_Impl, FmtSelectHdl));
745     mxFmtLb->connect_popup_menu(LINK(this, SfxCommonTemplateDialog_Impl, PopupFlatMenuHdl));
746     mxFmtLb->connect_key_press(LINK(this, SfxCommonTemplateDialog_Impl, KeyInputHdl));
747     mxFmtLb->set_selection_mode(SelectionMode::Multiple);
748     mxTreeBox->connect_changed(LINK(this, SfxCommonTemplateDialog_Impl, FmtSelectHdl));
749     mxTreeBox->connect_row_activated(LINK( this, SfxCommonTemplateDialog_Impl, TreeListApplyHdl));
750     mxTreeBox->connect_mouse_press(LINK(this, SfxCommonTemplateDialog_Impl, MousePressHdl));
751     mxTreeBox->connect_query_tooltip(LINK(this, SfxCommonTemplateDialog_Impl, QueryTooltipHdl));
752     mxTreeBox->connect_popup_menu(LINK(this, SfxCommonTemplateDialog_Impl, PopupTreeMenuHdl));
753     mxTreeBox->connect_key_press(LINK(this, SfxCommonTemplateDialog_Impl, KeyInputHdl));
754     mxTreeBox->connect_drag_begin(LINK(this, SfxCommonTemplateDialog_Impl, DragBeginHdl));
755     mxPreviewCheckbox->connect_clicked(LINK(this, SfxCommonTemplateDialog_Impl, PreviewHdl));
756     m_xTreeView1DropTargetHelper.reset(new TreeViewDropTarget(*this, *mxFmtLb));
757     m_xTreeView2DropTargetHelper.reset(new TreeViewDropTarget(*this, *mxTreeBox));
758 
759     int nTreeHeight = mxFmtLb->get_height_rows(8);
760     mxFmtLb->set_size_request(-1, nTreeHeight);
761     mxTreeBox->set_size_request(-1, nTreeHeight);
762 
763     mxFmtLb->connect_custom_get_size(LINK(this, SfxCommonTemplateDialog_Impl, CustomGetSizeHdl));
764     mxFmtLb->connect_custom_render(LINK(this, SfxCommonTemplateDialog_Impl, CustomRenderHdl));
765     mxTreeBox->connect_custom_get_size(LINK(this, SfxCommonTemplateDialog_Impl, CustomGetSizeHdl));
766     mxTreeBox->connect_custom_render(LINK(this, SfxCommonTemplateDialog_Impl, CustomRenderHdl));
767     bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
768     mxFmtLb->set_column_custom_renderer(0, bCustomPreview);
769     mxTreeBox->set_column_custom_renderer(0, bCustomPreview);
770 
771     mxFmtLb->set_visible(!bHierarchical);
772     mxTreeBox->set_visible(bHierarchical);
773 
774     Update_Impl();
775 }
776 
777 SfxCommonTemplateDialog_Impl::~SfxCommonTemplateDialog_Impl()
778 {
779     if ( bIsWater )
780         Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
781     impl_clear();
782     if ( pStyleSheetPool )
783         EndListening(*pStyleSheetPool);
784     pStyleSheetPool = nullptr;
785     m_xTreeView1DropTargetHelper.reset();
786     m_xTreeView2DropTargetHelper.reset();
787     mxTreeBox.reset();
788     pIdle.reset();
789     if ( m_pDeletionWatcher )
790         m_pDeletionWatcher->signal();
791     mxFmtLb.reset();
792     mxPreviewCheckbox.reset();
793     mxFilterLb.reset();
794 }
795 
796 // Helper function: Access to the current family item
797 const SfxStyleFamilyItem *SfxCommonTemplateDialog_Impl::GetFamilyItem_Impl() const
798 {
799     const size_t nCount = pStyleFamilies->size();
800     for(size_t i = 0; i < nCount; ++i)
801     {
802         const SfxStyleFamilyItem &rItem = pStyleFamilies->at( i );
803         sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
804         if(nId == nActFamily)
805             return &rItem;
806     }
807     return nullptr;
808 }
809 
810 void SfxCommonTemplateDialog_Impl::GetSelectedStyle() const
811 {
812     if (!IsInitialized() || !pStyleSheetPool || !HasSelectedStyle())
813         return;
814     const OUString aTemplName( GetSelectedEntry() );
815     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
816     pStyleSheetPool->Find( aTemplName, pItem->GetFamily() );
817 }
818 
819 /**
820  * Is it safe to show the water-can / fill icon. If we've a
821  * hierarchical widget - we have only single select, otherwise
822  * we need to check if we have a multi-selection. We either have
823  * a mxTreeBox showing or an mxFmtLb (which we hide when not shown)
824  */
825 bool SfxCommonTemplateDialog_Impl::IsSafeForWaterCan() const
826 {
827     if (mxTreeBox->get_visible())
828         return mxTreeBox->get_selected_index() != -1;
829     else
830         return mxFmtLb->count_selected_rows() == 1;
831 }
832 
833 void SfxCommonTemplateDialog_Impl::SelectStyle(const OUString &rStr, bool bIsCallback)
834 {
835     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
836     if ( !pItem )
837         return;
838     const SfxStyleFamily eFam = pItem->GetFamily();
839     SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( rStr, eFam );
840     if( pStyle )
841     {
842         bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
843         EnableEdit( bReadWrite );
844         EnableHide( bReadWrite && !pStyle->IsHidden( ) && !pStyle->IsUsed( ) );
845         EnableShow( bReadWrite && pStyle->IsHidden( ) );
846     }
847     else
848     {
849         EnableEdit(false);
850         EnableHide(false);
851         EnableShow(false);
852     }
853 
854     if (!bIsCallback)
855     {
856         if (mxTreeBox->get_visible())
857         {
858             if (!rStr.isEmpty())
859             {
860                 std::unique_ptr<weld::TreeIter> xEntry = mxTreeBox->make_iterator();
861                 bool bEntry = mxTreeBox->get_iter_first(*xEntry);
862                 while (bEntry)
863                 {
864                     if (mxTreeBox->get_text(*xEntry) == rStr)
865                     {
866                         mxTreeBox->scroll_to_row(*xEntry);
867                         mxTreeBox->select(*xEntry);
868                         break;
869                     }
870                     bEntry = mxTreeBox->iter_next(*xEntry);
871                 }
872             }
873             else
874                 mxTreeBox->unselect_all();
875         }
876         else
877         {
878             bool bSelect = !rStr.isEmpty();
879             if (bSelect)
880             {
881                 std::unique_ptr<weld::TreeIter> xEntry = mxFmtLb->make_iterator();
882                 bool bEntry = mxFmtLb->get_iter_first(*xEntry);
883                 while (bEntry && mxFmtLb->get_text(*xEntry) != rStr)
884                     bEntry = mxFmtLb->iter_next(*xEntry);
885                 if (!bEntry)
886                     bSelect = false;
887                 else
888                 {
889                     if (!mxFmtLb->is_selected(*xEntry))
890                     {
891                         mxFmtLb->unselect_all();
892                         mxFmtLb->scroll_to_row(*xEntry);
893                         mxFmtLb->select(*xEntry);
894                     }
895                 }
896             }
897 
898             if (!bSelect)
899             {
900                 mxFmtLb->unselect_all();
901                 EnableEdit(false);
902                 EnableHide(false);
903                 EnableShow(false);
904             }
905         }
906     }
907 
908     bWaterDisabled = !IsSafeForWaterCan();
909 
910     if (!bIsCallback)
911     {
912         // tdf#134598 call UpdateStyleDependents to update watercan
913         UpdateStyleDependents();
914     }
915 }
916 
917 OUString SfxCommonTemplateDialog_Impl::GetSelectedEntry() const
918 {
919     OUString aRet;
920     if (mxTreeBox->get_visible())
921         aRet = mxTreeBox->get_selected_text();
922     else
923         aRet = mxFmtLb->get_selected_text();
924     return aRet;
925 }
926 
927 void SfxCommonTemplateDialog_Impl::EnableTreeDrag(bool bEnable)
928 {
929     if (pStyleSheetPool)
930     {
931         const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
932         SfxStyleSheetBase* pStyle = pItem ? pStyleSheetPool->First(pItem->GetFamily()) : nullptr;
933         bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && bEnable;
934     }
935     bTreeDrag = bEnable;
936 }
937 
938 static OUString lcl_GetStyleFamilyName( SfxStyleFamily nFamily )
939 {
940     if(nFamily == SfxStyleFamily::Char)
941         return "CharacterStyles" ;
942     if(nFamily == SfxStyleFamily::Para)
943         return "ParagraphStyles";
944     if(nFamily == SfxStyleFamily::Page)
945         return "PageStyles";
946     if(nFamily == SfxStyleFamily::Table)
947         return "TableStyles";
948     return OUString();
949 }
950 
951 OUString SfxCommonTemplateDialog_Impl::getDefaultStyleName( const SfxStyleFamily eFam )
952 {
953     OUString sDefaultStyle;
954     OUString aFamilyName = lcl_GetStyleFamilyName(eFam);
955     if( aFamilyName == "TableStyles" )
956         sDefaultStyle = "Default Style";
957     else
958         sDefaultStyle = "Standard";
959     uno::Reference< style::XStyleFamiliesSupplier > xModel(GetObjectShell()->GetModel(), uno::UNO_QUERY);
960     OUString aUIName;
961     try
962     {
963         uno::Reference< container::XNameAccess > xStyles;
964         uno::Reference< container::XNameAccess > xCont = xModel->getStyleFamilies();
965         xCont->getByName( aFamilyName ) >>= xStyles;
966         uno::Reference< beans::XPropertySet > xInfo;
967         xStyles->getByName( sDefaultStyle ) >>= xInfo;
968         xInfo->getPropertyValue("DisplayName") >>= aUIName;
969     }
970     catch (const uno::Exception&)
971     {
972     }
973     return aUIName;
974 }
975 
976 void SfxCommonTemplateDialog_Impl::FillTreeBox()
977 {
978     assert(mxTreeBox && "FillTreeBox() without treebox");
979     if (!pStyleSheetPool || nActFamily == 0xffff)
980         return;
981 
982     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
983     if (!pItem)
984         return;
985     const SfxStyleFamily eFam = pItem->GetFamily();
986     StyleTreeArr_Impl aArr;
987     SfxStyleSheetBase* pStyle = pStyleSheetPool->First(eFam, SfxStyleSearchBits::AllVisible);
988 
989     bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && bTreeDrag;
990 
991     while (pStyle)
992     {
993         StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent());
994         aArr.emplace_back(pNew);
995         pStyle = pStyleSheetPool->Next();
996     }
997     OUString aUIName = getDefaultStyleName(eFam);
998     MakeTree_Impl(aArr, aUIName);
999     std::vector<OUString> aEntries;
1000     MakeExpanded_Impl(*mxTreeBox, aEntries);
1001     mxTreeBox->freeze();
1002     mxTreeBox->clear();
1003     const sal_uInt16 nCount = aArr.size();
1004 
1005     for (sal_uInt16 i = 0; i < nCount; ++i)
1006     {
1007         FillBox_Impl(*mxTreeBox, aArr[i].get(), aEntries, eFam, nullptr);
1008         aArr[i].reset();
1009     }
1010 
1011     EnableItem("watercan", false);
1012 
1013     SfxTemplateItem* pState = pFamilyState[nActFamily - 1].get();
1014 
1015     mxTreeBox->thaw();
1016 
1017     std::unique_ptr<weld::TreeIter> xEntry = mxTreeBox->make_iterator();
1018     bool bEntry = mxTreeBox->get_iter_first(*xEntry);
1019     if (bEntry && nCount)
1020         mxTreeBox->expand_row(*xEntry);
1021 
1022     while (bEntry)
1023     {
1024         if (IsExpanded_Impl(aEntries, mxTreeBox->get_text(*xEntry)))
1025             mxTreeBox->expand_row(*xEntry);
1026         bEntry = mxTreeBox->iter_next(*xEntry);
1027     }
1028 
1029     OUString aStyle;
1030     if(pState)  // Select current entry
1031         aStyle = pState->GetStyleName();
1032     SelectStyle(aStyle, false);
1033     EnableDelete();
1034 }
1035 
1036 bool SfxCommonTemplateDialog_Impl::HasSelectedStyle() const
1037 {
1038     return mxTreeBox->get_visible() ? mxTreeBox->get_selected_index() != -1
1039                                     : mxFmtLb->count_selected_rows() != 0;
1040 }
1041 
1042 // internal: Refresh the display
1043 // nFlags: what we should update.
1044 void SfxCommonTemplateDialog_Impl::UpdateStyles_Impl(StyleFlags nFlags)
1045 {
1046     OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
1047     const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1048     if (!pItem)
1049     {
1050         // Is the case for the template catalog
1051         const size_t nFamilyCount = pStyleFamilies->size();
1052         size_t n;
1053         for( n = 0; n < nFamilyCount; n++ )
1054             if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break;
1055         if ( n == nFamilyCount )
1056             // It happens sometimes, God knows why
1057             return;
1058         nAppFilter = pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
1059         FamilySelect(  StyleNrToInfoOffset(n)+1 );
1060         pItem = GetFamilyItem_Impl();
1061     }
1062 
1063     const SfxStyleFamily eFam = pItem->GetFamily();
1064 
1065     SfxStyleSearchBits nFilter (nActFilter < pItem->GetFilterList().size() ? pItem->GetFilterList()[nActFilter].nFlags : SfxStyleSearchBits::Auto);
1066     if (nFilter == SfxStyleSearchBits::Auto)   // automatic
1067         nFilter = nAppFilter;
1068 
1069     OSL_ENSURE(pStyleSheetPool, "no StyleSheetPool");
1070     if(!pStyleSheetPool)
1071         return;
1072 
1073     pItem = GetFamilyItem_Impl();
1074     if(nFlags & StyleFlags::UpdateFamily)   // Update view type list (Hierarchical, All, etc.
1075     {
1076         CheckItem(OString::number(nActFamily));    // check Button in Toolbox
1077 
1078         mxFilterLb->freeze();
1079         mxFilterLb->clear();
1080 
1081         //insert hierarchical at the beginning
1082         mxFilterLb->append(OUString::number(static_cast<int>(SfxStyleSearchBits::All)), SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
1083         const SfxStyleFilter& rFilter = pItem->GetFilterList();
1084         for (const SfxFilterTuple& i : rFilter)
1085             mxFilterLb->append(OUString::number(static_cast<int>(i.nFlags)), i.aName);
1086         mxFilterLb->thaw();
1087 
1088         if (nActFilter < mxFilterLb->get_count() - 1)
1089             mxFilterLb->set_active(nActFilter + 1);
1090         else
1091         {
1092             nActFilter = 0;
1093             mxFilterLb->set_active(1);
1094             nFilter = (nActFilter < rFilter.size()) ? rFilter[nActFilter].nFlags : SfxStyleSearchBits::Auto;
1095         }
1096 
1097         // if the tree view again, select family hierarchy
1098         if (mxTreeBox->get_visible() || m_bWantHierarchical)
1099         {
1100             mxFilterLb->set_active_text(SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
1101             EnableHierarchical(true);
1102         }
1103     }
1104     else
1105     {
1106         if (nActFilter < mxFilterLb->get_count() - 1)
1107             mxFilterLb->set_active(nActFilter + 1);
1108         else
1109         {
1110             nActFilter = 0;
1111             mxFilterLb->set_active(1);
1112         }
1113     }
1114 
1115     if(!(nFlags & StyleFlags::UpdateFamilyList))
1116         return;
1117 
1118     EnableItem("watercan", false);
1119 
1120     SfxStyleSheetBase *pStyle = pStyleSheetPool->First(eFam, nFilter);
1121 
1122     std::unique_ptr<weld::TreeIter> xEntry = mxFmtLb->make_iterator();
1123     bool bEntry = mxFmtLb->get_iter_first(*xEntry);
1124     std::vector<OUString> aStrings;
1125 
1126     comphelper::string::NaturalStringSorter aSorter(
1127         ::comphelper::getProcessComponentContext(),
1128         Application::GetSettings().GetLanguageTag().getLocale());
1129 
1130     while( pStyle )
1131     {
1132         aStrings.push_back(pStyle->GetName());
1133         pStyle = pStyleSheetPool->Next();
1134     }
1135     OUString aUIName = getDefaultStyleName(eFam);
1136 
1137     // Paradoxically, with a list and non-Latin style names,
1138     // sorting twice is faster than sorting once.
1139     // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
1140     // Then the second sort needs to call its (much more expensive) comparator less often.
1141     std::sort(aStrings.begin(), aStrings.end());
1142     std::sort(aStrings.begin(), aStrings.end(),
1143        [&aSorter, &aUIName](const OUString& rLHS, const OUString& rRHS) {
1144             if(rRHS == aUIName)
1145                 return false;
1146             if(rLHS == aUIName)
1147                 return true; // default always first
1148             return aSorter.compare(rLHS, rRHS) < 0;
1149        });
1150 
1151     size_t nCount = aStrings.size();
1152     size_t nPos = 0;
1153     while (nPos < nCount && bEntry &&
1154            aStrings[nPos] == mxFmtLb->get_text(*xEntry))
1155     {
1156         ++nPos;
1157         bEntry = mxFmtLb->iter_next(*xEntry);
1158     }
1159 
1160     if (nPos < nCount || bEntry)
1161     {
1162         // Fills the display box
1163         mxFmtLb->freeze();
1164         mxFmtLb->clear();
1165 
1166         for (nPos = 0; nPos < nCount; ++nPos)
1167             mxFmtLb->append(aStrings[nPos], aStrings[nPos]);
1168 
1169         mxFmtLb->thaw();
1170     }
1171     // Selects the current style if any
1172     SfxTemplateItem *pState = pFamilyState[nActFamily-1].get();
1173     OUString aStyle;
1174     if(pState)
1175         aStyle = pState->GetStyleName();
1176     SelectStyle(aStyle, false);
1177     EnableDelete();
1178 }
1179 
1180 // Updated display: Watering the house
1181 void SfxCommonTemplateDialog_Impl::SetWaterCanState(const SfxBoolItem *pItem)
1182 {
1183     bWaterDisabled = (pItem == nullptr);
1184 
1185     if(!bWaterDisabled)
1186         //make sure the watercan is only activated when there is (only) one selection
1187         bWaterDisabled = !IsSafeForWaterCan();
1188 
1189     if(pItem && !bWaterDisabled)
1190     {
1191         CheckItem("watercan", pItem->GetValue());
1192         EnableItem("watercan");
1193     }
1194     else
1195     {
1196         if(!bWaterDisabled)
1197             EnableItem("watercan");
1198         else
1199             EnableItem("watercan", false);
1200     }
1201 
1202 // Ignore while in watercan mode statusupdates
1203 
1204     size_t nCount = pStyleFamilies->size();
1205     pBindings->EnterRegistrations();
1206     for(size_t n = 0; n < nCount; n++)
1207     {
1208         SfxControllerItem *pCItem=pBoundItems[n].get();
1209         bool bChecked = pItem && pItem->GetValue();
1210         if( pCItem->IsBound() == bChecked )
1211         {
1212             if( !bChecked )
1213                 pCItem->ReBind();
1214             else
1215                 pCItem->UnBind();
1216         }
1217     }
1218     pBindings->LeaveRegistrations();
1219 }
1220 
1221 // Item with the status of a Family is copied and noted
1222 // (is updated when all states have also been updated.)
1223 // See also: <SfxBindings::AddDoneHdl(const Link &)>
1224 void SfxCommonTemplateDialog_Impl::SetFamilyState( sal_uInt16 nSlotId, const SfxTemplateItem* pItem )
1225 {
1226     sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
1227     pFamilyState[nIdx].reset();
1228     if ( pItem )
1229         pFamilyState[nIdx].reset( new SfxTemplateItem(*pItem) );
1230     bUpdate = true;
1231 
1232     // If used templates (how the hell you find this out??)
1233     bUpdateFamily = true;
1234 }
1235 
1236 // Notice from SfxBindings that the update is completed. Pushes out the update
1237 // of the display.
1238 void SfxCommonTemplateDialog_Impl::Update_Impl()
1239 {
1240     bool bDocChanged=false;
1241     SfxStyleSheetBasePool* pNewPool = nullptr;
1242     SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
1243     SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
1244     if( pDocShell )
1245         pNewPool = pDocShell->GetStyleSheetPool();
1246 
1247     if ( pNewPool != pStyleSheetPool && pDocShell )
1248     {
1249         SfxModule* pNewModule = pDocShell->GetModule();
1250         if( pNewModule && pNewModule != pModule )
1251         {
1252             ClearResource();
1253             ReadResource();
1254         }
1255         if ( pStyleSheetPool )
1256         {
1257             EndListening(*pStyleSheetPool);
1258             pStyleSheetPool = nullptr;
1259         }
1260 
1261         if ( pNewPool )
1262         {
1263             StartListening(*pNewPool);
1264             pStyleSheetPool = pNewPool;
1265             bDocChanged=true;
1266         }
1267     }
1268 
1269     if (bUpdateFamily)
1270         UpdateFamily_Impl();
1271 
1272     sal_uInt16 i;
1273     for(i = 0; i < MAX_FAMILIES; ++i)
1274         if(pFamilyState[i])
1275             break;
1276     if(i == MAX_FAMILIES || !pNewPool)
1277         // nothing is allowed
1278         return;
1279 
1280     SfxTemplateItem *pItem = nullptr;
1281     // current region not within the allowed region or default
1282     if(nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get() ) )
1283     {
1284          CheckItem(OString::number(nActFamily), false);
1285          const size_t nFamilyCount = pStyleFamilies->size();
1286          size_t n;
1287          for( n = 0; n < nFamilyCount; n++ )
1288              if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break;
1289 
1290          std::unique_ptr<SfxTemplateItem> & pNewItem = pFamilyState[StyleNrToInfoOffset(n)];
1291          nAppFilter = pNewItem->GetValue();
1292          FamilySelect( StyleNrToInfoOffset(n) + 1 );
1293          pItem = pNewItem.get();
1294     }
1295     else if( bDocChanged )
1296     {
1297          // other DocShell -> all new
1298          CheckItem(OString::number(nActFamily));
1299          nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pDocShell ) );
1300          if ( 0xffff == nActFilter )
1301             nActFilter = pDocShell->GetAutoStyleFilterIndex();
1302 
1303          nAppFilter = pItem->GetValue();
1304          if (!mxTreeBox->get_visible())
1305          {
1306              UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
1307          }
1308          else
1309              FillTreeBox();
1310     }
1311     else
1312     {
1313          // other filters for automatic
1314          CheckItem(OString::number(nActFamily));
1315          const SfxStyleFamilyItem *pStyleItem =  GetFamilyItem_Impl();
1316          if ( pStyleItem && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[nActFilter].nFlags
1317             && nAppFilter != pItem->GetValue())
1318          {
1319              nAppFilter = pItem->GetValue();
1320              if (!mxTreeBox->get_visible())
1321                  UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
1322              else
1323                  FillTreeBox();
1324          }
1325          else
1326              nAppFilter = pItem->GetValue();
1327     }
1328     const OUString aStyle(pItem->GetStyleName());
1329     SelectStyle(aStyle, false);
1330     EnableDelete();
1331     EnableNew( bCanNew );
1332 }
1333 
1334 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, TimeOut, Timer *, void )
1335 {
1336     if(!bDontUpdate)
1337     {
1338         bDontUpdate=true;
1339         if (!mxTreeBox->get_visible())
1340             UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
1341         else
1342         {
1343             FillTreeBox();
1344             SfxTemplateItem *pState = pFamilyState[nActFamily-1].get();
1345             if(pState)
1346             {
1347                 SelectStyle(pState->GetStyleName(), false);
1348                 EnableDelete();
1349             }
1350         }
1351         bDontUpdate=false;
1352         pIdle.reset();
1353     }
1354     else
1355         pIdle->Start();
1356 }
1357 
1358 void SfxCommonTemplateDialog_Impl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1359 {
1360     const SfxHintId nId = rHint.GetId();
1361 
1362     // tap update
1363     switch(nId)
1364     {
1365         case SfxHintId::UpdateDone:
1366             {
1367                 SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
1368                 SfxObjectShell *pDocShell = pViewFrame->GetObjectShell();
1369                 if (
1370                         bUpdate &&
1371                         (
1372                          !IsCheckedItem("watercan") ||
1373                          (pDocShell && pDocShell->GetStyleSheetPool() != pStyleSheetPool)
1374                         )
1375                    )
1376                 {
1377                     bUpdate = false;
1378                     Update_Impl();
1379                 }
1380                 else if ( bUpdateFamily )
1381                 {
1382                     UpdateFamily_Impl();
1383                 }
1384 
1385                 if( pStyleSheetPool )
1386                 {
1387                     OUString aStr = GetSelectedEntry();
1388                     if (!aStr.isEmpty())
1389                     {
1390                         const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1391                         if( !pItem ) break;
1392                         const SfxStyleFamily eFam = pItem->GetFamily();
1393                         SfxStyleSheetBase *pStyle = pStyleSheetPool->Find( aStr, eFam );
1394                         if( pStyle )
1395                         {
1396                             bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
1397                             EnableEdit( bReadWrite );
1398                             EnableHide( bReadWrite && !pStyle->IsUsed( ) && !pStyle->IsHidden( ) );
1399                             EnableShow( bReadWrite && pStyle->IsHidden( ) );
1400                         }
1401                         else
1402                         {
1403                             EnableEdit(false);
1404                             EnableHide(false);
1405                             EnableShow(false);
1406                         }
1407                     }
1408                 }
1409                 break;
1410             }
1411 
1412             // Necessary if switching between documents and in both documents
1413             // the same template is used. Do not immediately call Update_Impl,
1414             // for the case that one of the documents is an internal InPlaceObject!
1415         case SfxHintId::DocChanged:
1416             bUpdate = true;
1417         break;
1418         case SfxHintId::Dying:
1419             {
1420                 EndListening(*pStyleSheetPool);
1421                 pStyleSheetPool=nullptr;
1422                 break;
1423             }
1424         default: break;
1425     }
1426 
1427     // Do not set timer when the stylesheet pool is in the box, because it is
1428     // possible that a new one is registered after the timer is up -
1429     // works bad in UpdateStyles_Impl ()!
1430 
1431     if(!bDontUpdate && nId != SfxHintId::Dying &&
1432        (dynamic_cast<const SfxStyleSheetPoolHint*>(&rHint) ||
1433         dynamic_cast<const SfxStyleSheetHint*>(&rHint) ||
1434         dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint) ||
1435         nId == SfxHintId::StyleSheetModified))
1436     {
1437         if(!pIdle)
1438         {
1439             pIdle.reset(new Idle("SfxCommonTemplate"));
1440             pIdle->SetPriority(TaskPriority::LOWEST);
1441             pIdle->SetInvokeHandler(LINK(this,SfxCommonTemplateDialog_Impl,TimeOut));
1442         }
1443         pIdle->Start();
1444 
1445     }
1446 }
1447 
1448 // Other filters; can be switched by the users or as a result of new or
1449 // editing, if the current document has been assigned a different filter.
1450 void SfxCommonTemplateDialog_Impl::FilterSelect(
1451                 sal_uInt16 nEntry,  // Idx of the new Filters
1452                 bool bForce )   // Force update, even if the new filter is
1453                                 // equal to the current
1454 {
1455     if( nEntry == nActFilter && !bForce )
1456         return;
1457 
1458     nActFilter = nEntry;
1459     SfxObjectShell *const pDocShell = SaveSelection();
1460     SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool;
1461     pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr;
1462     if ( pOldStyleSheetPool != pStyleSheetPool )
1463     {
1464         if ( pOldStyleSheetPool )
1465             EndListening(*pOldStyleSheetPool);
1466         if ( pStyleSheetPool )
1467             StartListening(*pStyleSheetPool);
1468     }
1469 
1470     UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
1471 }
1472 
1473 // Internal: Perform functions through the Dispatcher
1474 bool SfxCommonTemplateDialog_Impl::Execute_Impl(
1475     sal_uInt16 nId, const OUString &rStr, const OUString& rRefStr, sal_uInt16 nFamily,
1476     SfxStyleSearchBits nMask, sal_uInt16 *pIdx, const sal_uInt16* pModifier)
1477 {
1478     SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl();
1479     SfxStringItem aItem(nId, rStr);
1480     SfxUInt16Item aFamily(SID_STYLE_FAMILY, nFamily);
1481     SfxUInt16Item aMask( SID_STYLE_MASK, static_cast<sal_uInt16>(nMask) );
1482     SfxStringItem aUpdName(SID_STYLE_UPD_BY_EX_NAME, rStr);
1483     SfxStringItem aRefName( SID_STYLE_REFERENCE, rRefStr );
1484     const SfxPoolItem* pItems[ 6 ];
1485     sal_uInt16 nCount = 0;
1486     if( !rStr.isEmpty() )
1487         pItems[ nCount++ ] = &aItem;
1488     pItems[ nCount++ ] = &aFamily;
1489     if( nMask != SfxStyleSearchBits::Auto )
1490         pItems[ nCount++ ] = &aMask;
1491     if(SID_STYLE_UPDATE_BY_EXAMPLE == nId)
1492     {
1493         // Special solution for Numbering update in Writer
1494         const OUString aTemplName(GetSelectedEntry());
1495         aUpdName.SetValue(aTemplName);
1496         pItems[ nCount++ ] = &aUpdName;
1497     }
1498 
1499     if ( !rRefStr.isEmpty() )
1500         pItems[ nCount++ ] = &aRefName;
1501 
1502     pItems[ nCount++ ] = nullptr;
1503 
1504     DeletionWatcher aDeleted(*this);
1505     sal_uInt16 nModi = pModifier ? *pModifier : 0;
1506     const SfxPoolItem* pItem = rDispatcher.Execute(
1507         nId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
1508         pItems, nModi );
1509 
1510     // Dialog can be destroyed while in Execute() because started
1511     // subdialogs are not modal to it (#i97888#).
1512     if ( !pItem || aDeleted )
1513         return false;
1514 
1515     if ( (nId == SID_STYLE_NEW || SID_STYLE_EDIT == nId) && (mxTreeBox->get_visible() || mxFmtLb->count_selected_rows() <= 1) )
1516     {
1517         const SfxUInt16Item *pFilterItem = dynamic_cast< const SfxUInt16Item* >(pItem);
1518         assert(pFilterItem);
1519         SfxStyleSearchBits nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue()) & ~SfxStyleSearchBits::UserDefined;
1520         if(nFilterFlags == SfxStyleSearchBits::Auto)       // User Template?
1521             nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue());
1522         const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl();
1523         const size_t nFilterCount = pFamilyItem->GetFilterList().size();
1524 
1525         for ( size_t i = 0; i < nFilterCount; ++i )
1526         {
1527             const SfxFilterTuple &rTupel = pFamilyItem->GetFilterList()[ i ];
1528 
1529             if ( ( rTupel.nFlags & nFilterFlags ) == nFilterFlags && pIdx )
1530                 *pIdx = i;
1531         }
1532     }
1533 
1534     return true;
1535 }
1536 
1537 // Handler Listbox of Filter
1538 void SfxCommonTemplateDialog_Impl::EnableHierarchical(bool const bEnable)
1539 {
1540     if (bEnable)
1541     {
1542         if (!bHierarchical)
1543         {
1544             // Turn on treeView
1545             bHierarchical=true;
1546             m_bWantHierarchical = true;
1547             SaveSelection(); // fdo#61429 store "hierarchical"
1548             const OUString aSelectEntry( GetSelectedEntry());
1549             mxFmtLb->hide();
1550             FillTreeBox();
1551             SelectStyle(aSelectEntry, false);
1552             mxTreeBox->show();
1553         }
1554     }
1555     else
1556     {
1557         mxTreeBox->hide();
1558         mxFmtLb->show();
1559         // If bHierarchical, then the family can have changed
1560         // minus one since hierarchical is inserted at the start
1561         m_bWantHierarchical = false; // before FilterSelect
1562         FilterSelect(mxFilterLb->get_active() - 1, bHierarchical );
1563         bHierarchical=false;
1564     }
1565 }
1566 
1567 IMPL_LINK(SfxCommonTemplateDialog_Impl, FilterSelectHdl, weld::ComboBox&, rBox, void)
1568 {
1569     if (SfxResId(STR_STYLE_FILTER_HIERARCHICAL) == rBox.get_active_text())
1570     {
1571         EnableHierarchical(true);
1572     }
1573     else
1574     {
1575         EnableHierarchical(false);
1576     }
1577 }
1578 
1579 // Select-Handler for the Toolbox
1580 void SfxCommonTemplateDialog_Impl::FamilySelect(sal_uInt16 nEntry, bool bPreviewRefresh)
1581 {
1582     assert((0 < nEntry && nEntry <= MAX_FAMILIES) || 0xffff == nEntry);
1583     if( nEntry != nActFamily || bPreviewRefresh )
1584     {
1585         CheckItem(OString::number(nActFamily), false);
1586         nActFamily = nEntry;
1587         SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl();
1588         SfxUInt16Item const aItem(SID_STYLE_FAMILY,
1589                 static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
1590         pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
1591         pBindings->Invalidate( SID_STYLE_FAMILY );
1592         pBindings->Update( SID_STYLE_FAMILY );
1593         UpdateFamily_Impl();
1594     }
1595 }
1596 
1597 void SfxCommonTemplateDialog_Impl::ActionSelect(const OString& rEntry)
1598 {
1599     if (rEntry == "watercan")
1600     {
1601         const bool bOldState = !IsCheckedItem(rEntry);
1602         bool bCheck;
1603         SfxBoolItem aBool;
1604         // when a template is chosen.
1605         if (!bOldState && HasSelectedStyle())
1606         {
1607             const OUString aTemplName(
1608                 GetSelectedEntry());
1609             Execute_Impl(
1610                 SID_STYLE_WATERCAN, aTemplName, "",
1611                 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
1612             bCheck = true;
1613         }
1614         else
1615         {
1616             Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
1617             bCheck = false;
1618         }
1619         CheckItem(rEntry, bCheck);
1620         aBool.SetValue(bCheck);
1621         SetWaterCanState(&aBool);
1622     }
1623     else if (rEntry == "new" || rEntry == "newmenu")
1624     {
1625         if(pStyleSheetPool && nActFamily != 0xffff)
1626         {
1627             const SfxStyleFamily eFam=GetFamilyItem_Impl()->GetFamily();
1628             const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1629             SfxStyleSearchBits nFilter(SfxStyleSearchBits::Auto);
1630             if (pItem && nActFilter != 0xffff)
1631                 nFilter = pItem->GetFilterList()[nActFilter].nFlags;
1632             if (nFilter == SfxStyleSearchBits::Auto)    // automatic
1633                 nFilter = nAppFilter;
1634 
1635             // why? : FloatingWindow must not be parent of a modal dialog
1636             SfxNewStyleDlg aDlg(mpContainer, *pStyleSheetPool, eFam);
1637             auto nResult = aDlg.run();
1638             if (nResult ==  RET_OK)
1639             {
1640                 const OUString aTemplName(aDlg.GetName());
1641                 Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE,
1642                              aTemplName, "",
1643                              static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
1644                              nFilter);
1645                 UpdateFamily_Impl();
1646             }
1647         }
1648     }
1649     else if (rEntry == "update")
1650     {
1651         Execute_Impl(SID_STYLE_UPDATE_BY_EXAMPLE,
1652                 "", "",
1653                 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
1654     }
1655     else if (rEntry == "load")
1656         SfxGetpApp()->GetDispatcher_Impl()->Execute(SID_TEMPLATE_LOAD);
1657     else
1658         SAL_WARN("sfx", "not implemented: " << rEntry);
1659 }
1660 
1661 static OUString getModuleIdentifier( const Reference< XModuleManager2 >& i_xModMgr, SfxObjectShell const * i_pObjSh )
1662 {
1663     OSL_ENSURE( i_xModMgr.is(), "getModuleIdentifier(): no XModuleManager" );
1664     OSL_ENSURE( i_pObjSh, "getModuleIdentifier(): no ObjectShell" );
1665 
1666     OUString sIdentifier;
1667 
1668     try
1669     {
1670         sIdentifier = i_xModMgr->identify( i_pObjSh->GetModel() );
1671     }
1672     catch ( css::frame::UnknownModuleException& )
1673     {
1674         SAL_WARN("sfx", "getModuleIdentifier(): unknown module" );
1675     }
1676     catch ( Exception& )
1677     {
1678         TOOLS_WARN_EXCEPTION( "sfx", "getModuleIdentifier(): exception of XModuleManager::identify()" );
1679     }
1680 
1681     return sIdentifier;
1682 }
1683 
1684 sal_Int32 SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter( SfxObjectShell const * i_pObjSh )
1685 {
1686     OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );
1687 
1688     ::comphelper::SequenceAsHashMap aFactoryProps(
1689         xModuleManager->getByName( getModuleIdentifier( xModuleManager, i_pObjSh ) ) );
1690     sal_Int32 nFilter = aFactoryProps.getUnpackedValueOrDefault( "ooSetupFactoryStyleFilter", sal_Int32(-1) );
1691 
1692     m_bWantHierarchical = (nFilter & 0x1000) != 0;
1693     nFilter &= ~0x1000; // clear it
1694 
1695     return nFilter;
1696 }
1697 
1698 void SfxCommonTemplateDialog_Impl::SaveFactoryStyleFilter( SfxObjectShell const * i_pObjSh, sal_Int32 i_nFilter )
1699 {
1700     OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );
1701     Sequence< PropertyValue > lProps(1);
1702     lProps[0].Name = "ooSetupFactoryStyleFilter";
1703     lProps[0].Value <<= i_nFilter | (m_bWantHierarchical ? 0x1000 : 0);
1704     xModuleManager->replaceByName( getModuleIdentifier( xModuleManager, i_pObjSh ), makeAny( lProps ) );
1705 }
1706 
1707 SfxObjectShell* SfxCommonTemplateDialog_Impl::SaveSelection()
1708 {
1709     SfxViewFrame *const pViewFrame(pBindings->GetDispatcher_Impl()->GetFrame());
1710     SfxObjectShell *const pDocShell(pViewFrame->GetObjectShell());
1711     if (pDocShell)
1712     {
1713         pDocShell->SetAutoStyleFilterIndex(nActFilter);
1714         SaveFactoryStyleFilter( pDocShell, nActFilter );
1715     }
1716     return pDocShell;
1717 }
1718 
1719 void SfxCommonTemplateDialog_Impl::DropHdl(const OUString& rStyle, const OUString& rParent)
1720 {
1721     bDontUpdate = true;
1722     const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1723     const SfxStyleFamily eFam = pItem->GetFamily();
1724     pStyleSheetPool->SetParent(eFam, rStyle, rParent);
1725     bDontUpdate = false;
1726 }
1727 
1728 // Handler for the New-Buttons
1729 void SfxCommonTemplateDialog_Impl::NewHdl()
1730 {
1731     if ( nActFamily == 0xffff || !(mxTreeBox->get_visible() || mxFmtLb->count_selected_rows() <= 1))
1732         return;
1733 
1734     const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1735     const SfxStyleFamily eFam = pItem->GetFamily();
1736     SfxStyleSearchBits nMask(SfxStyleSearchBits::Auto);
1737     if (nActFilter != 0xffff)
1738         nMask = pItem->GetFilterList()[nActFilter].nFlags;
1739     if (nMask == SfxStyleSearchBits::Auto)    // automatic
1740         nMask = nAppFilter;
1741 
1742     Execute_Impl(SID_STYLE_NEW,
1743                  "", GetSelectedEntry(),
1744                  static_cast<sal_uInt16>(eFam),
1745                  nMask);
1746 }
1747 
1748 // Handler for the edit-Buttons
1749 void SfxCommonTemplateDialog_Impl::EditHdl()
1750 {
1751     if(IsInitialized() && HasSelectedStyle())
1752     {
1753         sal_uInt16 nFilter = nActFilter;
1754         OUString aTemplName(GetSelectedEntry());
1755         GetSelectedStyle(); // -Wall required??
1756         Execute_Impl( SID_STYLE_EDIT, aTemplName, OUString(),
1757                           static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()), SfxStyleSearchBits::Auto, &nFilter );
1758     }
1759 }
1760 
1761 // Handler for the Delete-Buttons
1762 void SfxCommonTemplateDialog_Impl::DeleteHdl()
1763 {
1764     if ( !IsInitialized() || !HasSelectedStyle() )
1765         return;
1766 
1767     bool bUsedStyle = false;     // one of the selected styles are used in the document?
1768 
1769     std::vector<std::unique_ptr<weld::TreeIter>> aList;
1770     weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
1771     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
1772 
1773     OUStringBuffer aMsg;
1774     aMsg.append(SfxResId(STR_DELETE_STYLE_USED)).append(SfxResId(STR_DELETE_STYLE));
1775 
1776     pTreeView->selected_foreach([this, pTreeView, pItem, &aList, &bUsedStyle, &aMsg](weld::TreeIter& rEntry){
1777         aList.emplace_back(pTreeView->make_iterator(&rEntry));
1778         // check the style is used or not
1779         const OUString aTemplName(pTreeView->get_text(rEntry));
1780 
1781         SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( aTemplName, pItem->GetFamily() );
1782 
1783         if ( pStyle->IsUsed() )  // pStyle is in use in the document?
1784         {
1785             if (bUsedStyle) // add a separator for the second and later styles
1786                 aMsg.append(", ");
1787             aMsg.append(aTemplName);
1788             bUsedStyle = true;
1789         }
1790 
1791         return false;
1792     });
1793 
1794     bool aApproved = false;
1795 
1796     // we only want to show the dialog once and if we want to delete a style in use (UX-advice)
1797     if (bUsedStyle)
1798     {
1799         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pTreeView,
1800                                                   VclMessageType::Question, VclButtonsType::YesNo,
1801                                                   aMsg.makeStringAndClear()));
1802         aApproved = xBox->run() == RET_YES;
1803     }
1804 
1805     // if there are no used styles selected or the user approved the changes
1806     if ( bUsedStyle && !aApproved )
1807         return;
1808 
1809     for (auto const& elem : aList)
1810     {
1811         const OUString aTemplName(pTreeView->get_text(*elem));
1812         bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting
1813         Execute_Impl( SID_STYLE_DELETE, aTemplName,
1814                       OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
1815 
1816         if (mxTreeBox->get_visible())
1817         {
1818             weld::RemoveParentKeepChildren(*mxTreeBox, *elem);
1819             bDontUpdate = false;
1820         }
1821     }
1822     bDontUpdate = false; //if everything is deleted set bDontUpdate back to false
1823     UpdateStyles_Impl(StyleFlags::UpdateFamilyList); //and force-update the list
1824 }
1825 
1826 void SfxCommonTemplateDialog_Impl::HideHdl()
1827 {
1828     if ( !IsInitialized() || !HasSelectedStyle() )
1829         return;
1830 
1831     weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
1832     pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry){
1833         OUString aTemplName = pTreeView->get_text(rEntry);
1834 
1835         Execute_Impl( SID_STYLE_HIDE, aTemplName,
1836                       OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
1837 
1838         return false;
1839     });
1840 }
1841 
1842 void SfxCommonTemplateDialog_Impl::ShowHdl()
1843 {
1844     if ( !IsInitialized() || !HasSelectedStyle() )
1845         return;
1846 
1847     weld::TreeView* pTreeView = mxTreeBox->get_visible() ? mxTreeBox.get() : mxFmtLb.get();
1848     pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry){
1849         OUString aTemplName = pTreeView->get_text(rEntry);
1850 
1851         Execute_Impl( SID_STYLE_SHOW, aTemplName,
1852                       OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
1853 
1854         return false;
1855     });
1856 }
1857 
1858 void SfxCommonTemplateDialog_Impl::EnableDelete()
1859 {
1860     bool bEnableDelete(false);
1861     if(IsInitialized() && HasSelectedStyle())
1862     {
1863         OSL_ENSURE(pStyleSheetPool, "No StyleSheetPool");
1864         const OUString aTemplName(GetSelectedEntry());
1865         const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1866         const SfxStyleFamily eFam = pItem->GetFamily();
1867         SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
1868         if (pItem->GetFilterList().size() > nActFilter)
1869             nFilter = pItem->GetFilterList()[nActFilter].nFlags;
1870         if(nFilter == SfxStyleSearchBits::Auto)    // automatic
1871             nFilter = nAppFilter;
1872         const SfxStyleSheetBase *pStyle =
1873             pStyleSheetPool->Find(aTemplName,eFam, mxTreeBox->get_visible() ? SfxStyleSearchBits::All : nFilter);
1874 
1875         OSL_ENSURE(pStyle, "Style not found");
1876         if (pStyle && pStyle->IsUserDefined())
1877         {
1878             if (pStyle->HasClearParentSupport() || !pStyle->IsUsed())
1879             {
1880                 bEnableDelete = true;
1881             }
1882             else if (pStyle->GetFamily() == SfxStyleFamily::Page)
1883             {
1884                 // Hack to allow Calc page styles to be deleted,
1885                 // remove when IsUsed is fixed for Calc page styles.
1886                 SfxViewFrame* pFrame = GetObjectShell()->GetFrame();
1887                 if (pFrame)
1888                 {
1889                     uno::Reference<frame::XFrame > xFrame = pFrame->GetFrame().GetFrameInterface();
1890                     if (vcl::CommandInfoProvider::GetModuleIdentifier(xFrame) == "com.sun.star.sheet.SpreadsheetDocument")
1891                     {
1892                         bEnableDelete = true;
1893                     }
1894                 }
1895             }
1896         }
1897     }
1898     EnableDel(bEnableDelete);
1899 }
1900 
1901 IMPL_LINK(SfxCommonTemplateDialog_Impl, MousePressHdl, const MouseEvent&, rMEvt, bool)
1902 {
1903     m_nModifier = rMEvt.GetModifier();
1904     return false;
1905 }
1906 
1907 // Double-click on a style sheet in the ListBox is applied.
1908 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, TreeListApplyHdl, weld::TreeView&, bool)
1909 {
1910     // only if that region is allowed
1911     if ( IsInitialized() && nullptr != pFamilyState[nActFamily-1] &&
1912          !GetSelectedEntry().isEmpty() )
1913     {
1914         Execute_Impl(SID_STYLE_APPLY,
1915                      GetSelectedEntry(), OUString(),
1916                      static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
1917                      SfxStyleSearchBits::Auto, nullptr, &m_nModifier);
1918     }
1919     // After selecting a focused item if possible again on the app window
1920     if ( dynamic_cast< const SfxTemplateDialog_Impl* >(this) !=  nullptr )
1921     {
1922         SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
1923         SfxViewShell *pVu = pViewFrame->GetViewShell();
1924         vcl::Window *pAppWin = pVu ? pVu->GetWindow(): nullptr;
1925         if(pAppWin)
1926             pAppWin->GrabFocus();
1927     }
1928 
1929     return true;
1930 }
1931 
1932 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, PreviewHdl, weld::Button&, void)
1933 {
1934     std::shared_ptr<comphelper::ConfigurationChanges> batch( comphelper::ConfigurationChanges::create() );
1935     bool bCustomPreview = mxPreviewCheckbox->get_active();
1936     officecfg::Office::Common::StylesAndFormatting::Preview::set(bCustomPreview, batch );
1937     batch->commit();
1938 
1939     mxFmtLb->clear();
1940     mxFmtLb->set_column_custom_renderer(0, bCustomPreview);
1941     mxTreeBox->clear();
1942     mxTreeBox->set_column_custom_renderer(0, bCustomPreview);
1943 
1944     FamilySelect(nActFamily, true);
1945 }
1946 
1947 // Selection of a template during the Watercan-Status
1948 IMPL_LINK(SfxCommonTemplateDialog_Impl, FmtSelectHdl, weld::TreeView&, rListBox, void)
1949 {
1950     std::unique_ptr<weld::TreeIter> xHdlEntry = rListBox.make_iterator();
1951     if (!rListBox.get_cursor(xHdlEntry.get()))
1952         return;
1953 
1954     if (rListBox.is_selected(*xHdlEntry))
1955         UpdateStyleDependents();
1956 
1957     SelectStyle(rListBox.get_text(*xHdlEntry), true);
1958 }
1959 
1960 void SfxCommonTemplateDialog_Impl::UpdateStyleDependents()
1961 {
1962     // Trigger Help PI. Only when the watercan is on
1963     if ( IsInitialized() &&
1964          IsCheckedItem("watercan") &&
1965          // only if that region is allowed
1966          nullptr != pFamilyState[nActFamily-1] && (mxTreeBox || mxFmtLb->count_selected_rows() <= 1) )
1967     {
1968         Execute_Impl(SID_STYLE_WATERCAN,
1969                      "", "", 0);
1970         Execute_Impl(SID_STYLE_WATERCAN,
1971                      GetSelectedEntry(), "",
1972                      static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
1973     }
1974     EnableItem("watercan", !bWaterDisabled);
1975     EnableDelete();
1976 }
1977 
1978 void SfxCommonTemplateDialog_Impl::MenuSelect(const OString& rIdent)
1979 {
1980     sLastItemIdent = rIdent;
1981     if (sLastItemIdent.isEmpty())
1982         return;
1983     Application::PostUserEvent(
1984         LINK(this, SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl));
1985 }
1986 
1987 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl, void*, void)
1988 {
1989     if (sLastItemIdent == "new")
1990         NewHdl();
1991     else if (sLastItemIdent == "edit")
1992         EditHdl();
1993     else if (sLastItemIdent == "delete")
1994         DeleteHdl();
1995     else if (sLastItemIdent == "hide")
1996         HideHdl();
1997     else if (sLastItemIdent == "show")
1998         ShowHdl();
1999 }
2000 
2001 SfxStyleFamily SfxCommonTemplateDialog_Impl::GetActualFamily() const
2002 {
2003     const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl();
2004     if( !pFamilyItem || nActFamily == 0xffff )
2005         return SfxStyleFamily::Para;
2006     else
2007         return pFamilyItem->GetFamily();
2008 }
2009 
2010 void SfxCommonTemplateDialog_Impl::EnableExample_Impl(sal_uInt16 nId, bool bEnable)
2011 {
2012     bool bDisable = !bEnable || !IsSafeForWaterCan();
2013     if (nId == SID_STYLE_NEW_BY_EXAMPLE)
2014     {
2015         bNewByExampleDisabled = bDisable;
2016         EnableItem("new", bEnable);
2017         EnableItem("newmenu", bEnable);
2018     }
2019     else if( nId == SID_STYLE_UPDATE_BY_EXAMPLE )
2020     {
2021         bUpdateByExampleDisabled = bDisable;
2022         EnableItem("update", bEnable);
2023     }
2024 }
2025 
2026 void SfxCommonTemplateDialog_Impl::CreateContextMenu()
2027 {
2028     if ( bBindingUpdate )
2029     {
2030         pBindings->Invalidate( SID_STYLE_NEW, true );
2031         pBindings->Update( SID_STYLE_NEW );
2032         bBindingUpdate = false;
2033     }
2034     mxMenu.reset();
2035     mxMenuBuilder.reset(Application::CreateBuilder(nullptr, "sfx/ui/stylecontextmenu.ui"));
2036     mxMenu = mxMenuBuilder->weld_menu("menu");
2037     mxMenu->set_sensitive("edit", bCanEdit);
2038     mxMenu->set_sensitive("delete", bCanDel);
2039     mxMenu->set_sensitive("new", bCanNew);
2040     mxMenu->set_sensitive("hide", bCanHide);
2041     mxMenu->set_sensitive("show", bCanShow);
2042 
2043     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
2044     if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
2045     {
2046         mxMenu->set_sensitive("edit", false);
2047         mxMenu->set_sensitive("new", false);
2048     }
2049 }
2050 
2051 SfxTemplateDialog_Impl::SfxTemplateDialog_Impl(SfxBindings* pB, SfxTemplatePanelControl* pDlgWindow)
2052     : SfxCommonTemplateDialog_Impl(pB, pDlgWindow->get_container(), pDlgWindow->get_builder())
2053     , m_xActionTbL(pDlgWindow->get_builder()->weld_toolbar("left"))
2054     , m_xActionTbR(pDlgWindow->get_builder()->weld_toolbar("right"))
2055     , m_xToolMenu(pDlgWindow->get_builder()->weld_menu("toolmenu"))
2056     , m_nActionTbLVisible(0)
2057 {
2058     m_xActionTbR->set_item_help_id("watercan", HID_TEMPLDLG_WATERCAN);
2059     // shown/hidden in SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
2060     m_xActionTbR->set_item_help_id("new", HID_TEMPLDLG_NEWBYEXAMPLE);
2061     m_xActionTbR->set_item_help_id("newmenu", HID_TEMPLDLG_NEWBYEXAMPLE);
2062     m_xActionTbR->set_item_menu("newmenu", m_xToolMenu.get());
2063     m_xToolMenu->connect_activate(LINK(this, SfxTemplateDialog_Impl, ToolMenuSelectHdl));
2064     m_xActionTbR->set_item_help_id("update", HID_TEMPLDLG_UPDATEBYEXAMPLE);
2065 
2066     Initialize();
2067 }
2068 
2069 class ToolbarDropTarget final : public DropTargetHelper
2070 {
2071 private:
2072     SfxTemplateDialog_Impl& m_rParent;
2073 
2074 public:
2075     ToolbarDropTarget(SfxTemplateDialog_Impl& rDialog, weld::Toolbar& rToolbar)
2076         : DropTargetHelper(rToolbar.get_drop_target())
2077         , m_rParent(rDialog)
2078     {
2079     }
2080 
2081     virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
2082     {
2083         return m_rParent.AcceptToolbarDrop(rEvt, *this);
2084     }
2085 
2086     virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
2087     {
2088         return m_rParent.ExecuteDrop(rEvt);
2089     }
2090 };
2091 
2092 void SfxTemplateDialog_Impl::Initialize()
2093 {
2094     SfxCommonTemplateDialog_Impl::Initialize();
2095 
2096     m_xActionTbL->connect_clicked(LINK(this, SfxTemplateDialog_Impl, ToolBoxLSelect));
2097     m_xActionTbR->connect_clicked(LINK(this, SfxTemplateDialog_Impl, ToolBoxRSelect));
2098     m_xActionTbL->set_help_id(HID_TEMPLDLG_TOOLBOX_LEFT);
2099 
2100     m_xToolbarDropTargetHelper.reset(new ToolbarDropTarget(*this, *m_xActionTbL));
2101 }
2102 
2103 void SfxTemplateDialog_Impl::EnableFamilyItem(sal_uInt16 nId, bool bEnable)
2104 {
2105     m_xActionTbL->set_item_sensitive(OString::number(nId), bEnable);
2106 }
2107 
2108 // Insert element into dropdown filter "Frame Styles", "List Styles", etc.
2109 void SfxTemplateDialog_Impl::InsertFamilyItem(sal_uInt16 nId, const SfxStyleFamilyItem &rItem)
2110 {
2111     OString sHelpId;
2112     switch( rItem.GetFamily() )
2113     {
2114         case SfxStyleFamily::Char:     sHelpId = ".uno:CharStyle"; break;
2115         case SfxStyleFamily::Para:     sHelpId = ".uno:ParaStyle"; break;
2116         case SfxStyleFamily::Frame:    sHelpId = ".uno:FrameStyle"; break;
2117         case SfxStyleFamily::Page:     sHelpId = ".uno:PageStyle"; break;
2118         case SfxStyleFamily::Pseudo:   sHelpId = ".uno:ListStyle"; break;
2119         case SfxStyleFamily::Table:    sHelpId = ".uno:TableStyle"; break;
2120         default: OSL_FAIL("unknown StyleFamily"); break;
2121     }
2122 
2123     OString sId(OString::number(nId));
2124     m_xActionTbL->set_item_visible(sId, true);
2125     m_xActionTbL->set_item_icon_name(sId, rItem.GetImage());
2126     m_xActionTbL->set_item_tooltip_text(sId, rItem.GetText());
2127     m_xActionTbL->set_item_help_id(sId, sHelpId);
2128     ++m_nActionTbLVisible;
2129 }
2130 
2131 void SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
2132 {
2133     m_xActionTbR->set_item_visible("update", false);
2134     m_xActionTbR->set_item_visible("new", false);
2135     m_xActionTbR->set_item_visible("newmenu", true);
2136     FillToolMenu();
2137 }
2138 
2139 void SfxTemplateDialog_Impl::ClearFamilyList()
2140 {
2141     for (int i = 0, nCount = m_xActionTbL->get_n_items(); i < nCount; ++i)
2142         m_xActionTbL->set_item_visible(m_xActionTbL->get_item_ident(i), false);
2143 
2144 }
2145 
2146 void SfxCommonTemplateDialog_Impl::InvalidateBindings()
2147 {
2148     pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
2149     pBindings->Update( SID_STYLE_NEW_BY_EXAMPLE );
2150     pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
2151     pBindings->Update( SID_STYLE_UPDATE_BY_EXAMPLE );
2152     pBindings->Invalidate( SID_STYLE_WATERCAN, true);
2153     pBindings->Update( SID_STYLE_WATERCAN );
2154     pBindings->Invalidate( SID_STYLE_NEW, true);
2155     pBindings->Update( SID_STYLE_NEW );
2156     pBindings->Invalidate( SID_STYLE_DRAGHIERARCHIE, true);
2157     pBindings->Update( SID_STYLE_DRAGHIERARCHIE );
2158 }
2159 
2160 SfxTemplateDialog_Impl::~SfxTemplateDialog_Impl()
2161 {
2162     m_xToolbarDropTargetHelper.reset();
2163     m_xActionTbL.reset();
2164     m_xActionTbR.reset();
2165 }
2166 
2167 void SfxTemplateDialog_Impl::EnableItem(const OString& rMesId, bool bCheck)
2168 {
2169     if (rMesId == "watercan" && !bCheck && IsCheckedItem("watercan"))
2170         Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
2171     m_xActionTbR->set_item_sensitive(rMesId, bCheck);
2172 }
2173 
2174 void SfxTemplateDialog_Impl::CheckItem(const OString &rMesId, bool bCheck)
2175 {
2176     if (rMesId == "watercan")
2177     {
2178         bIsWater=bCheck;
2179         m_xActionTbR->set_item_active("watercan", bCheck);
2180     }
2181     else
2182         m_xActionTbL->set_item_active(rMesId, bCheck);
2183 }
2184 
2185 bool SfxTemplateDialog_Impl::IsCheckedItem(const OString& rMesId)
2186 {
2187     if (rMesId == "watercan")
2188         return m_xActionTbR->get_item_active("watercan");
2189     return m_xActionTbL->get_item_active(rMesId);
2190 }
2191 
2192 IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxLSelect, const OString&, rEntry, void)
2193 {
2194     FamilySelect(rEntry.toUInt32());
2195 }
2196 
2197 IMPL_LINK(SfxTemplateDialog_Impl, ToolBoxRSelect, const OString&, rEntry, void)
2198 {
2199     if (rEntry == "newmenu")
2200         m_xActionTbR->set_menu_item_active(rEntry, !m_xActionTbR->get_menu_item_active(rEntry));
2201     else
2202         ActionSelect(rEntry);
2203 }
2204 
2205 void SfxTemplateDialog_Impl::FillToolMenu()
2206 {
2207     //create a popup menu in Writer
2208     OUString sTextDoc("com.sun.star.text.TextDocument");
2209 
2210     auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:StyleNewByExample", sTextDoc);
2211     OUString sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
2212     m_xToolMenu->append("new", sLabel);
2213     aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:StyleUpdateByExample", sTextDoc);
2214     sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
2215     m_xToolMenu->append("update", sLabel);
2216     m_xToolMenu->append_separator("separator");
2217 
2218     aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:LoadStyles", sTextDoc);
2219     sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
2220     m_xToolMenu->append("load", sLabel);
2221 }
2222 
2223 IMPL_LINK(SfxTemplateDialog_Impl, ToolMenuSelectHdl, const OString&, rMenuId, void)
2224 {
2225     if (rMenuId.isEmpty())
2226         return;
2227     ActionSelect(rMenuId);
2228 }
2229 
2230 void SfxCommonTemplateDialog_Impl::SetFamily(SfxStyleFamily const nFamily)
2231 {
2232     sal_uInt16 const nId(SfxTemplate::SfxFamilyIdToNId(nFamily));
2233     assert((0 < nId && nId <= MAX_FAMILIES) || 0xffff == nId);
2234     if ( nId != nActFamily )
2235     {
2236         if ( nActFamily != 0xFFFF )
2237             CheckItem(OString::number(nActFamily), false);
2238         nActFamily = nId;
2239         if ( nId != 0xFFFF )
2240             bUpdateFamily = true;
2241     }
2242 }
2243 
2244 void SfxCommonTemplateDialog_Impl::UpdateFamily_Impl()
2245 {
2246     bUpdateFamily = false;
2247 
2248     SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl();
2249     SfxViewFrame *pViewFrame = pDispat->GetFrame();
2250     SfxObjectShell *pDocShell = pViewFrame->GetObjectShell();
2251 
2252     SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool;
2253     pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr;
2254     if ( pOldStyleSheetPool != pStyleSheetPool )
2255     {
2256         if ( pOldStyleSheetPool )
2257             EndListening(*pOldStyleSheetPool);
2258         if ( pStyleSheetPool )
2259             StartListening(*pStyleSheetPool);
2260     }
2261 
2262     bWaterDisabled = false;
2263     bCanNew = mxTreeBox->get_visible() || mxFmtLb->count_selected_rows() <= 1;
2264     bTreeDrag = true;
2265     bUpdateByExampleDisabled = false;
2266 
2267     if (pStyleSheetPool)
2268     {
2269         if (!mxTreeBox->get_visible())
2270             UpdateStyles_Impl(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
2271         else
2272         {
2273             UpdateStyles_Impl(StyleFlags::UpdateFamily);
2274             FillTreeBox();
2275         }
2276     }
2277 
2278     InvalidateBindings();
2279 
2280     if (IsCheckedItem("watercan") &&
2281          // only if that area is allowed
2282          nullptr != pFamilyState[nActFamily - 1])
2283     {
2284         Execute_Impl(SID_STYLE_APPLY,
2285                      GetSelectedEntry(),
2286                      OUString(),
2287                      static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
2288     }
2289 }
2290 
2291 void SfxCommonTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
2292 {
2293     //does nothing
2294 }
2295 
2296 sal_Int8 SfxTemplateDialog_Impl::AcceptToolbarDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
2297 {
2298     sal_Int8 nReturn = DND_ACTION_NONE;
2299 
2300     // auto flip to the category under the mouse
2301     int nIndex = m_xActionTbL->get_drop_index(rEvt.maPosPixel);
2302     if (nIndex >= m_nActionTbLVisible)
2303         nIndex = m_nActionTbLVisible - 1;
2304 
2305     OString sIdent = m_xActionTbL->get_item_ident(nIndex);
2306     if (!sIdent.isEmpty() && !m_xActionTbL->get_item_active(sIdent))
2307         ToolBoxLSelect(sIdent);
2308 
2309     // special case: page styles are allowed to create new styles by example
2310     // but not allowed to be created by drag and drop
2311     if (sIdent.toUInt32() != SfxTemplate::SfxFamilyIdToNId(SfxStyleFamily::Page) &&
2312         rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR) &&
2313         !bNewByExampleDisabled)
2314     {
2315         nReturn = DND_ACTION_COPY;
2316     }
2317     return nReturn;
2318 }
2319 
2320 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2321