xref: /core/sfx2/source/dialog/templdlg.cxx (revision f7804fc2)
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 <vcl/commandinfoprovider.hxx>
23 #include <vcl/event.hxx>
24 #include <vcl/help.hxx>
25 #include <vcl/menu.hxx>
26 #include <vcl/settings.hxx>
27 #include <vcl/svapp.hxx>
28 #include <svl/intitem.hxx>
29 #include <svl/stritem.hxx>
30 #include <svl/style.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/sequenceashashmap.hxx>
33 #include <unotools/intlwrapper.hxx>
34 #include <unotools/collatorwrapper.hxx>
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <com/sun/star/frame/ModuleManager.hpp>
37 #include <com/sun/star/frame/UnknownModuleException.hpp>
38 #include <officecfg/Office/Common.hxx>
39 
40 #include <sal/log.hxx>
41 #include <osl/diagnose.h>
42 #include <sfx2/app.hxx>
43 #include <sfx2/dispatch.hxx>
44 #include <sfx2/bindings.hxx>
45 #include <sfx2/templdlg.hxx>
46 #include <templdgi.hxx>
47 #include <tplcitem.hxx>
48 #include <sfx2/styfitem.hxx>
49 #include <sfx2/objsh.hxx>
50 #include <sfx2/viewsh.hxx>
51 #include <sfx2/newstyle.hxx>
52 #include <sfx2/tplpitem.hxx>
53 #include <sfx2/sfxresid.hxx>
54 
55 #include <sfx2/sfxsids.hrc>
56 #include <sfx2/strings.hrc>
57 #include <sfx2/docfac.hxx>
58 #include <sfx2/module.hxx>
59 #include <helpids.h>
60 #include <bitmaps.hlst>
61 #include <sfx2/viewfrm.hxx>
62 
63 #include <vcl/svlbitm.hxx>
64 #include <vcl/treelistentry.hxx>
65 #include <vcl/viewdataentry.hxx>
66 #include <comphelper/string.hxx>
67 
68 #include <sfx2/StyleManager.hxx>
69 #include <sfx2/StylePreviewRenderer.hxx>
70 
71 #define STD_ENTRY_HEIGHT 17
72 
73 using namespace css;
74 using namespace css::beans;
75 using namespace css::frame;
76 using namespace css::uno;
77 
78 namespace
79 {
80 
81 class StyleLBoxString : public SvLBoxString
82 {
83     SfxStyleFamily const meStyleFamily;
84     SvViewDataItem* mpViewData;
85 
86 public:
87     StyleLBoxString(const OUString& sText,
88                     const SfxStyleFamily& eStyleFamily);
89 
90     virtual void Paint(const Point& aPos,
91                        SvTreeListBox& rDevice,
92                        vcl::RenderContext& rRenderContext,
93                        const SvViewDataEntry* pView,
94                        const SvTreeListEntry& rEntry) override;
95 
96     virtual void InitViewData(SvTreeListBox* pView,
97                               SvTreeListEntry* pEntry,
98                               SvViewDataItem* pViewData = nullptr) override;
99 };
100 
101 
102 StyleLBoxString::StyleLBoxString(const OUString& sText, const SfxStyleFamily& eStyleFamily)
103     : SvLBoxString(sText)
104     , meStyleFamily(eStyleFamily)
105     , mpViewData(nullptr)
106 {}
107 
108 void StyleLBoxString::InitViewData(SvTreeListBox* pView, SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
109 {
110     if (!pViewData)
111     {
112         pViewData = pView->GetViewDataItem(pEntry, this);
113     }
114     mpViewData = pViewData;
115 }
116 
117 void StyleLBoxString::Paint(
118     const Point& aPos, SvTreeListBox& rDevice, vcl::RenderContext& rRenderContext,
119     const SvViewDataEntry* pView, const SvTreeListEntry& rEntry)
120 {
121     bool bPainted = false;
122 
123     SfxObjectShell* pShell = SfxObjectShell::Current();
124     sfx2::StyleManager* pStyleManager = pShell? pShell->GetStyleManager(): nullptr;
125 
126     if (pStyleManager)
127     {
128         SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(GetText(), meStyleFamily);
129 
130         if (pStyleSheet)
131         {
132             sal_Int32 nSize = 32 * rRenderContext.GetDPIScaleFactor();
133             std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
134                 pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
135 
136             if (pStylePreviewRenderer)
137             {
138                 if (pStylePreviewRenderer->recalculate())
139                 {
140                     Size aSize(pStylePreviewRenderer->getRenderSize());
141                     mpViewData->mnWidth = aSize.Width();
142                     mpViewData->mnHeight = aSize.Height();
143                 }
144                 else
145                 {
146                     SvLBoxString::InitViewData( &rDevice, const_cast<SvTreeListEntry*>(&rEntry), mpViewData);
147                 }
148 
149                 tools::Rectangle aPaintRectangle = pView->GetPaintRectangle();
150                 bPainted = pStylePreviewRenderer->render(aPaintRectangle);
151             }
152         }
153     }
154 
155     if (!bPainted)
156     {
157         rRenderContext.DrawText(aPos, GetText());
158     }
159 }
160 
161 } // end anonymous namespace
162 
163 // Window is now created dynamically. So here margins, etc.
164 
165 #define SFX_TEMPLDLG_HFRAME         3
166 #define SFX_TEMPLDLG_VTOPFRAME      3
167 
168 #define SFX_TEMPLDLG_VBOTFRAME      3
169 #define SFX_TEMPLDLG_MIDHSPACE      3
170 #define SFX_TEMPLDLG_MIDVSPACE      3
171 #define SFX_TEMPLDLG_FILTERHEIGHT   100
172 
173 // filter box has maximum 14 entries visible
174 #define MAX_FILTER_ENTRIES          14
175 
176 
177 class SfxCommonTemplateDialog_Impl::DeletionWatcher
178 {
179     typedef void (DeletionWatcher::* bool_type)();
180 
181 public:
182     explicit DeletionWatcher(SfxCommonTemplateDialog_Impl& rDialog)
183         : m_pDialog(&rDialog)
184         , m_pPrevious(m_pDialog->impl_setDeletionWatcher(this))
185     {
186     }
187 
188     ~DeletionWatcher()
189     {
190         if (m_pDialog)
191             m_pDialog->impl_setDeletionWatcher(m_pPrevious);
192     }
193 
194     DeletionWatcher(const DeletionWatcher&) = delete;
195     DeletionWatcher& operator=(const DeletionWatcher&) = delete;
196 
197     // Signal that the dialog was deleted
198     void signal()
199     {
200         m_pDialog = nullptr;
201         if (m_pPrevious)
202             m_pPrevious->signal();
203     }
204 
205     // Return true if the dialog was deleted
206     operator bool_type() const
207     {
208         return m_pDialog ? nullptr : &DeletionWatcher::signal;
209     }
210 
211 private:
212     SfxCommonTemplateDialog_Impl* m_pDialog;
213     DeletionWatcher *const m_pPrevious; /// let's add more epicycles!
214 };
215 
216 void DropListBox_Impl::MouseButtonDown( const MouseEvent& rMEvt )
217 {
218     nModifier = rMEvt.GetModifier();
219 
220     bool bHitEmptySpace = ( nullptr == GetEntry( rMEvt.GetPosPixel(), true ) );
221     if( bHitEmptySpace && ( rMEvt.GetClicks() == 2 ) && rMEvt.IsMod1() )
222         Control::MouseButtonDown( rMEvt );
223     else
224         SvTreeListBox::MouseButtonDown( rMEvt );
225 }
226 
227 /** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
228     create a style out of the current selection.
229 */
230 sal_Int8 DropListBox_Impl::AcceptDrop( const AcceptDropEvent& rEvt )
231 {
232     if ( IsDropFormatSupported( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
233     {
234         // special case: page styles are allowed to create new styles by example
235         // but not allowed to be created by drag and drop
236         if (pDialog->GetActualFamily() == SfxStyleFamily::Page ||
237                 pDialog->bNewByExampleDisabled)
238             return DND_ACTION_NONE;
239         else
240             return DND_ACTION_COPY;
241     }
242     return SvTreeListBox::AcceptDrop( rEvt );
243 }
244 
245 sal_Int8 DropListBox_Impl::ExecuteDrop( const ExecuteDropEvent& rEvt )
246 {
247     sal_Int8 nRet = DND_ACTION_NONE;
248     SfxObjectShell* pDocShell = pDialog->GetObjectShell();
249     TransferableDataHelper aHelper( rEvt.maDropEvent.Transferable );
250     sal_uInt32 nFormatCount = aHelper.GetFormatCount();
251     if ( pDocShell )
252     {
253         bool bFormatFound = false;
254 
255         for ( sal_uInt32 i = 0; i < nFormatCount; ++i )
256         {
257             SotClipboardFormatId nId = aHelper.GetFormat(i);
258             TransferableObjectDescriptor aDesc;
259 
260             if ( aHelper.GetTransferableObjectDescriptor( nId, aDesc ) )
261             {
262                 if ( aDesc.maClassName == pDocShell->GetFactory().GetClassId() )
263                 {
264                     PostUserEvent( LINK( this, DropListBox_Impl, OnAsyncExecuteDrop ), nullptr, true );
265 
266                     bFormatFound = true;
267                     nRet =  rEvt.mnAction;
268                     break;
269                 }
270             }
271         }
272 
273         if ( !bFormatFound )
274             return SvTreeListBox::ExecuteDrop( rEvt );
275     }
276 
277     return nRet;
278 }
279 
280 IMPL_LINK_NOARG(DropListBox_Impl, OnAsyncExecuteDrop, void*, void)
281 {
282     pDialog->ActionSelect( SID_STYLE_NEW_BY_EXAMPLE );
283 }
284 
285 bool DropListBox_Impl::EventNotify( NotifyEvent& rNEvt )
286 {
287     bool bRet = false;
288     if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
289     {
290         const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
291         if(!rKeyCode.GetModifier())
292         {
293             if( pDialog->bCanDel && KEY_DELETE == rKeyCode.GetCode())
294             {
295                 pDialog->DeleteHdl();
296                 bRet =  true;
297             }
298             else if( KEY_RETURN == rKeyCode.GetCode())
299             {
300                 GetDoubleClickHdl().Call(this);
301                 bRet = true;
302             }
303         }
304     }
305     if(!bRet)
306         bRet = SvTreeListBox::EventNotify( rNEvt );
307     return bRet;
308 }
309 
310 void DropListBox_Impl::RequestHelp(const HelpEvent& rHEvt)
311 {
312     if (rHEvt.GetMode() & HelpEventMode::QUICK)
313     {
314         Point aPos(ScreenToOutputPixel(rHEvt.GetMousePosPixel()));
315         SvTreeListEntry* pEntry = GetEntry(aPos);
316         if (pEntry)
317         {
318             const OUString aTemplName(GetEntryText(pEntry));
319             OUString sQuickHelpText(aTemplName);
320 
321             const SfxStyleFamilyItem* pItem = pDialog->GetFamilyItem_Impl();
322             SfxStyleSheetBase* pStyle = pDialog->pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
323 
324             if (pStyle && pStyle->IsUsed())  // pStyle is in use in the document?
325             {
326                 OUString sUsedBy;
327                 if (pStyle->GetFamily() == SfxStyleFamily::Pseudo)
328                 {
329                     sUsedBy = pStyle->GetUsedBy();
330                 }
331 
332                 if (!sUsedBy.isEmpty())
333                 {
334                     const sal_Int32 nMaxLen = 80;
335                     if (sUsedBy.getLength() > nMaxLen)
336                     {
337                         sUsedBy = sUsedBy.copy(0, nMaxLen) + "...";
338                     }
339 
340                     OUString aMessage = SfxResId(STR_STYLEUSEDBY);
341                     aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy);
342                     sQuickHelpText = aTemplName + " " + aMessage;
343                 }
344             }
345 
346             Size aSize(GetOutputSizePixel().Width(), GetEntryHeight());
347             tools::Rectangle aScreenRect(OutputToScreenPixel(GetEntryPosition(pEntry)), aSize);
348 
349             Help::ShowQuickHelp(this, aScreenRect,
350                                  sQuickHelpText, QuickHelpFlags::Left | QuickHelpFlags::VCenter);
351             return;
352         }
353     }
354     SvTreeListBox::RequestHelp(rHEvt);
355 }
356 
357 /** ListBox class that starts a PopupMenu (designer specific) in the
358     command handler.
359 */
360 SfxActionListBox::SfxActionListBox(SfxCommonTemplateDialog_Impl* pParent, WinBits nWinBits)
361     : DropListBox_Impl(pParent->GetWindow(), nWinBits, pParent)
362 {
363     EnableContextMenuHandling();
364 }
365 
366 void SfxActionListBox::Recalc()
367 {
368     if (officecfg::Office::Common::StylesAndFormatting::Preview::get())
369         SetEntryHeight(32 * GetDPIScaleFactor());
370     else
371         SetEntryHeight(STD_ENTRY_HEIGHT, true);
372     RecalcViewData();
373 }
374 
375 VclPtr<PopupMenu> SfxActionListBox::CreateContextMenu()
376 {
377 
378     if(  GetSelectionCount() <= 0 )
379     {
380         pDialog->EnableEdit( false );
381         pDialog->EnableDel( false );
382     }
383     return pDialog->CreateContextMenu();
384 }
385 
386 SfxTemplatePanelControl::SfxTemplatePanelControl(SfxBindings* pBindings, vcl::Window* pParentWindow)
387     : Window(pParentWindow, WB_DIALOGCONTROL)
388     , pImpl(new SfxTemplateDialog_Impl(pBindings, this))
389     , mpBindings(pBindings)
390 {
391     OSL_ASSERT(mpBindings!=nullptr);
392 
393     SetStyle(GetStyle() & ~WB_DOCKABLE);
394 }
395 
396 SfxTemplatePanelControl::~SfxTemplatePanelControl()
397 {
398     disposeOnce();
399 }
400 
401 void SfxTemplatePanelControl::dispose()
402 {
403     pImpl.reset();
404     Window::dispose();
405 }
406 
407 void SfxTemplatePanelControl::Resize()
408 {
409     if(pImpl)
410         pImpl->Resize();
411     Window::Resize();
412 }
413 
414 void SfxTemplatePanelControl::StateChanged( StateChangedType nStateChange )
415 {
416     if (nStateChange == StateChangedType::InitShow)
417     {
418         SfxViewFrame* pFrame = mpBindings->GetDispatcher_Impl()->GetFrame();
419         vcl::Window* pEditWin = pFrame->GetViewShell()->GetWindow();
420 
421         Size aSize = pEditWin->GetSizePixel();
422         Point aPoint = pEditWin->OutputToScreenPixel( pEditWin->GetPosPixel() );
423         aPoint = GetParent()->ScreenToOutputPixel( aPoint );
424         Size aWinSize = GetSizePixel();
425         aPoint.AdjustX(aSize.Width() - aWinSize.Width() - 20 );
426         aPoint.AdjustY(aSize.Height() / 2 - aWinSize.Height() / 2 );
427         // SetFloatingPos( aPoint );
428     }
429 
430     Window::StateChanged( nStateChange );
431 }
432 
433 void StyleTreeListBox_Impl::MakeExpanded_Impl(std::vector<OUString>& rEntries) const
434 {
435     SvTreeListEntry* pEntry;
436     for (pEntry = FirstVisible(); pEntry; pEntry = NextVisible(pEntry))
437     {
438         if (IsExpanded(pEntry))
439         {
440             rEntries.push_back(GetEntryText(pEntry));
441         }
442     }
443 }
444 
445 VclPtr<PopupMenu> StyleTreeListBox_Impl::CreateContextMenu()
446 {
447     return pDialog->CreateContextMenu();
448 }
449 
450 /** DoubleClick-Handler; calls the link.
451     SV virtual method.
452 */
453 bool StyleTreeListBox_Impl::DoubleClickHdl()
454 {
455     aDoubleClickLink.Call(nullptr);
456     return false;
457 }
458 
459 bool StyleTreeListBox_Impl::EventNotify( NotifyEvent& rNEvt )
460 {
461     // handle <RETURN> as double click
462 
463     bool bRet = false;
464     if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
465     {
466         const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
467         if ( !rKeyCode.GetModifier() && KEY_RETURN == rKeyCode.GetCode() )
468         {
469             aDoubleClickLink.Call( nullptr );
470             bRet = true;
471         }
472     }
473 
474     if ( !bRet )
475         bRet = DropListBox_Impl::EventNotify( rNEvt );
476 
477     return bRet;
478 }
479 
480 /** NotifyMoving Handler; This leads via a link on the event to the dialog.
481     SV virtual method.
482 */
483 TriState StyleTreeListBox_Impl::NotifyMoving(SvTreeListEntry*  pTarget,
484                                          SvTreeListEntry*  pEntry,
485                                          SvTreeListEntry*& rpNewParent,
486                                          sal_uLong& lPos)
487 {
488     if(!pTarget || !pEntry)
489         return TRISTATE_FALSE;
490     aParent = GetEntryText(pTarget);
491     aStyle  = GetEntryText(pEntry);
492     const bool bRet = aDropLink.Call(*this);
493     rpNewParent = pTarget;
494     lPos=0;
495     IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag());
496     const CollatorWrapper* pCollator = aIntlWrapper.getCaseCollator();
497     for(SvTreeListEntry *pTmpEntry=FirstChild(pTarget);
498         pTmpEntry && pCollator->compareString(
499             GetEntryText(pTmpEntry),GetEntryText(pEntry)) < 0;
500         pTmpEntry=pTmpEntry->NextSibling(),lPos++) ;
501 
502     return bRet ? TRISTATE_INDET : TRISTATE_FALSE;
503 }
504 
505 /** ExpandingHdl Handler; the current entry is noticed.
506     SV virtual method.
507 
508     [Cross-reference]
509     <StyleTreeListBox_Impl::ExpandedHdl()>
510 */
511 bool  StyleTreeListBox_Impl::ExpandingHdl()
512 {
513     pCurEntry = GetCurEntry();
514     return true;
515 }
516 
517 /**  ExpandedHdl Handler;
518     SV virtual method.
519 
520     [Cross-reference]
521     <StyleTreeListBox_Impl::ExpandingHdl()>
522 */
523 void  StyleTreeListBox_Impl::ExpandedHdl()
524 {
525     SvTreeListEntry *pEntry = GetHdlEntry();
526     if(!IsExpanded(pEntry) && pCurEntry != GetCurEntry())
527         SelectAll( false );
528     pCurEntry = nullptr;
529 }
530 
531 /** Constructor StyleTreeListBox_Impl */
532 StyleTreeListBox_Impl::StyleTreeListBox_Impl(SfxCommonTemplateDialog_Impl* pParent, WinBits nWinStyle)
533     : DropListBox_Impl(pParent->GetWindow(), nWinStyle, pParent)
534     , pCurEntry(nullptr)
535 {
536     EnableContextMenuHandling();
537 }
538 
539 void StyleTreeListBox_Impl::Recalc()
540 {
541     if (officecfg::Office::Common::StylesAndFormatting::Preview::get())
542         SetEntryHeight(32 * GetDPIScaleFactor());
543     else
544         SetEntryHeight(STD_ENTRY_HEIGHT, true);
545     RecalcViewData();
546 }
547 
548 /** Internal structure for the establishment of the hierarchical view */
549 namespace {
550 
551 class StyleTree_Impl;
552 
553 }
554 
555 typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;
556 
557 namespace {
558 
559 class StyleTree_Impl
560 {
561 private:
562     OUString const aName;
563     OUString const aParent;
564     StyleTreeArr_Impl pChildren;
565 
566 public:
567     bool HasParent() const { return !aParent.isEmpty(); }
568 
569     StyleTree_Impl(const OUString &rName, const OUString &rParent):
570         aName(rName), aParent(rParent), pChildren(0) {}
571 
572     const OUString& getName() const { return aName; }
573     const OUString& getParent() const { return aParent; }
574     StyleTreeArr_Impl& getChildren() { return pChildren; }
575 };
576 
577 }
578 
579 static void MakeTree_Impl(StyleTreeArr_Impl& rArr)
580 {
581     const comphelper::string::NaturalStringSorter aSorter(
582         ::comphelper::getProcessComponentContext(),
583         Application::GetSettings().GetLanguageTag().getLocale());
584 
585     std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
586     styleFinder.reserve(rArr.size());
587     for (const auto& pEntry : rArr)
588     {
589         styleFinder.emplace(pEntry->getName(), pEntry.get());
590     }
591 
592     // Arrange all under their Parents
593     for (auto& pEntry : rArr)
594     {
595         if (!pEntry->HasParent())
596             continue;
597         auto it = styleFinder.find(pEntry->getParent());
598         if (it != styleFinder.end())
599         {
600             StyleTree_Impl* pCmp = it->second;
601             // Insert child entries sorted
602             auto iPos = std::lower_bound(pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
603                 [&aSorter](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) { return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0; });
604             pCmp->getChildren().insert(iPos, std::move(pEntry));
605         }
606     }
607 
608     // Only keep tree roots in rArr, child elements can be accessed through the hierarchy
609     rArr.erase(std::remove_if(rArr.begin(), rArr.end(), [](std::unique_ptr<StyleTree_Impl> const & pEntry) { return !pEntry; }), rArr.end());
610 
611     // tdf#91106 sort top level styles
612     std::sort(rArr.begin(), rArr.end(),
613         [&aSorter](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) {
614             if (pEntry2->getName() == "Default Style")
615                 return false;
616             if (pEntry1->getName() == "Default Style")
617                 return true; // default always first
618             return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
619         });
620 }
621 
622 static bool IsExpanded_Impl( const std::vector<OUString>& rEntries,
623                              const OUString &rStr)
624 {
625     for (const auto & rEntry : rEntries)
626     {
627         if (rEntry == rStr)
628             return true;
629     }
630     return false;
631 }
632 
633 static SvTreeListEntry* FillBox_Impl(SvTreeListBox* pBox,
634                               StyleTree_Impl* pEntry,
635                               const std::vector<OUString>& rEntries,
636                               SfxStyleFamily eStyleFamily,
637                               SvTreeListEntry* pParent)
638 {
639     SvTreeListEntry* pTreeListEntry = pBox->InsertEntry(pEntry->getName(), pParent);
640 
641     if (officecfg::Office::Common::StylesAndFormatting::Preview::get())
642     {
643         pTreeListEntry->ReplaceItem(std::make_unique<StyleLBoxString>(pEntry->getName(), eStyleFamily), 1);
644     }
645 
646     pBox->GetModel()->InvalidateEntry(pTreeListEntry);
647 
648     for(size_t i = 0; i < pEntry->getChildren().size(); ++i)
649     {
650         FillBox_Impl(pBox, pEntry->getChildren()[i].get(), rEntries, eStyleFamily, pTreeListEntry);
651     }
652     return pTreeListEntry;
653 }
654 
655 
656 namespace SfxTemplate
657 {
658     // converts from SFX_STYLE_FAMILY Ids to 1-6
659     static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
660     {
661         switch ( nFamily )
662         {
663             case SfxStyleFamily::Char:   return 1;
664             case SfxStyleFamily::Para:   return 2;
665             case SfxStyleFamily::Frame:  return 3;
666             case SfxStyleFamily::Page:   return 4;
667             case SfxStyleFamily::Pseudo: return 5;
668             case SfxStyleFamily::Table:  return 6;
669             default:                     return 0xffff;
670         }
671     }
672 
673     // converts from 1-6 to SFX_STYLE_FAMILY Ids
674     static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
675     {
676         switch (nId)
677         {
678             case 1: return SfxStyleFamily::Char;
679             case 2: return SfxStyleFamily::Para;
680             case 3: return SfxStyleFamily::Frame;
681             case 4: return SfxStyleFamily::Page;
682             case 5: return SfxStyleFamily::Pseudo;
683             case 6: return SfxStyleFamily::Table;
684             default: return SfxStyleFamily::All;
685         }
686     }
687 }
688 
689 // Constructor
690 
691 SfxCommonTemplateDialog_Impl::SfxCommonTemplateDialog_Impl( SfxBindings* pB, vcl::Window* pW )
692     : pBindings(pB)
693     , pWindow(pW)
694     , pModule(nullptr)
695     , pStyleSheetPool(nullptr)
696     , pCurObjShell(nullptr)
697     , xModuleManager(frame::ModuleManager::create(::comphelper::getProcessComponentContext()))
698     , m_pDeletionWatcher(nullptr)
699 
700     , aFmtLb( VclPtr<SfxActionListBox>::Create(this, WB_BORDER | WB_TABSTOP | WB_SORT) )
701     , pTreeBox( VclPtr<StyleTreeListBox_Impl>::Create(this, WB_HASBUTTONS | WB_HASLINES |
702                                                       WB_BORDER | WB_TABSTOP | WB_HASLINESATROOT |
703                                                       WB_HASBUTTONSATROOT | WB_HIDESELECTION) )
704     , aPreviewCheckbox( VclPtr<CheckBox>::Create( pW, WB_VCENTER ))
705     , aFilterLb( VclPtr<ListBox>::Create(pW, WB_BORDER | WB_DROPDOWN | WB_TABSTOP) )
706 
707     , nActFamily(0xffff)
708     , nActFilter(0)
709     , nAppFilter(SfxStyleSearchBits::Auto)
710 
711     , bDontUpdate(false)
712     , bIsWater(false)
713     , bUpdate(false)
714     , bUpdateFamily(false)
715     , bCanEdit(false)
716     , bCanDel(false)
717     , bCanNew(true)
718     , bCanHide(true)
719     , bCanShow(false)
720     , bWaterDisabled(false)
721     , bNewByExampleDisabled(false)
722     , bUpdateByExampleDisabled(false)
723     , bTreeDrag(true)
724     , bHierarchical(false)
725     , m_bWantHierarchical(false)
726     , bBindingUpdate(true)
727 {
728     aFmtLb->SetQuickSearch(true);
729     aFmtLb->SetAccessibleName(SfxResId(STR_STYLE_ELEMTLIST));
730     aFmtLb->SetHelpId( HID_TEMPLATE_FMT );
731     aFilterLb->SetHelpId( HID_TEMPLATE_FILTER );
732     aFmtLb->SetStyle( aFmtLb->GetStyle() | WB_SORT | WB_HIDESELECTION );
733     vcl::Font aFont = aFmtLb->GetFont();
734     aFont.SetWeight( WEIGHT_NORMAL );
735     aFmtLb->SetFont( aFont );
736     pTreeBox->SetQuickSearch(true);
737     pTreeBox->SetNodeDefaultImages();
738     pTreeBox->SetOptimalImageIndent();
739     pTreeBox->SetAccessibleName(SfxResId(STR_STYLE_ELEMTLIST));
740     aPreviewCheckbox->Check(officecfg::Office::Common::StylesAndFormatting::Preview::get());
741     aPreviewCheckbox->SetText( SfxResId(STR_PREVIEW_CHECKBOX) );
742 }
743 
744 sal_uInt16 SfxCommonTemplateDialog_Impl::StyleNrToInfoOffset(sal_uInt16 nId)
745 {
746     const SfxStyleFamilyItem& rItem = pStyleFamilies->at( nId );
747     return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily())-1;
748 }
749 
750 void SfxTemplateDialog_Impl::EnableEdit(bool bEnable)
751 {
752     SfxCommonTemplateDialog_Impl::EnableEdit( bEnable );
753     if( !bEnable || !bUpdateByExampleDisabled )
754         EnableItem( SID_STYLE_UPDATE_BY_EXAMPLE, bEnable);
755 }
756 
757 void SfxCommonTemplateDialog_Impl::ReadResource()
758 {
759     // Read global user resource
760     for (auto & i : pFamilyState)
761         i.reset();
762 
763     SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
764     pCurObjShell = pViewFrame->GetObjectShell();
765     pModule = pCurObjShell ? pCurObjShell->GetModule() : nullptr;
766     if (pModule)
767         pStyleFamilies = pModule->CreateStyleFamilies();
768     if (!pStyleFamilies)
769         pStyleFamilies.reset(new SfxStyleFamilies);
770 
771     nActFilter = 0xffff;
772     if (pCurObjShell)
773     {
774         nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pCurObjShell ) );
775         if ( 0xffff == nActFilter )
776             nActFilter = pCurObjShell->GetAutoStyleFilterIndex();
777     }
778 
779     // Paste in the toolbox
780     // reverse order, since always inserted at the head
781     size_t nCount = pStyleFamilies->size();
782 
783     pBindings->ENTERREGISTRATIONS();
784 
785     size_t i;
786     for (i = 0; i < nCount; ++i)
787     {
788         sal_uInt16 nSlot = 0;
789         switch (pStyleFamilies->at(i).GetFamily())
790         {
791             case SfxStyleFamily::Char:
792                 nSlot = SID_STYLE_FAMILY1; break;
793             case SfxStyleFamily::Para:
794                 nSlot = SID_STYLE_FAMILY2; break;
795             case SfxStyleFamily::Frame:
796                 nSlot = SID_STYLE_FAMILY3; break;
797             case SfxStyleFamily::Page:
798                 nSlot = SID_STYLE_FAMILY4; break;
799             case SfxStyleFamily::Pseudo:
800                 nSlot = SID_STYLE_FAMILY5; break;
801             case SfxStyleFamily::Table:
802                 nSlot = SID_STYLE_FAMILY6; break;
803             default: OSL_FAIL("unknown StyleFamily"); break;
804         }
805         pBoundItems[i].reset(
806             new SfxTemplateControllerItem(nSlot, *this, *pBindings) );
807     }
808     pBoundItems[i++].reset( new SfxTemplateControllerItem(
809         SID_STYLE_WATERCAN, *this, *pBindings) );
810     pBoundItems[i++].reset( new SfxTemplateControllerItem(
811         SID_STYLE_NEW_BY_EXAMPLE, *this, *pBindings) );
812     pBoundItems[i++].reset( new SfxTemplateControllerItem(
813         SID_STYLE_UPDATE_BY_EXAMPLE, *this, *pBindings) );
814     pBoundItems[i++].reset( new SfxTemplateControllerItem(
815         SID_STYLE_NEW, *this, *pBindings) );
816     pBoundItems[i++].reset( new SfxTemplateControllerItem(
817         SID_STYLE_DRAGHIERARCHIE, *this, *pBindings) );
818     pBoundItems[i++].reset( new SfxTemplateControllerItem(
819         SID_STYLE_EDIT, *this, *pBindings) );
820     pBoundItems[i++].reset( new SfxTemplateControllerItem(
821         SID_STYLE_DELETE, *this, *pBindings) );
822     pBoundItems[i++].reset( new SfxTemplateControllerItem(
823         SID_STYLE_FAMILY, *this, *pBindings) );
824     pBindings->LEAVEREGISTRATIONS();
825 
826     for(; i < COUNT_BOUND_FUNC; ++i)
827         pBoundItems[i] = nullptr;
828 
829     StartListening(*pBindings);
830 
831 // Insert in the reverse order of occurrence in the Style Families. This is for
832 // the toolbar of the designer. The list box of the catalog respects the
833 // correct order by itself.
834 
835 // Sequences: the order of Resource = the order of Toolbar for example list box.
836 // Order of ascending SIDs: Low SIDs are displayed first when templates of
837 // several families are active.
838 
839     // in the Writer the UpdateStyleByExample Toolbox button is removed and
840     // the NewStyle button gets a PopupMenu
841     if(nCount > 4)
842         ReplaceUpdateButtonByMenu();
843 
844     for( ; nCount--; )
845     {
846         const SfxStyleFamilyItem &rItem = pStyleFamilies->at( nCount );
847         sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId( rItem.GetFamily() );
848         InsertFamilyItem(nId, rItem);
849     }
850 
851     LoadedFamilies();
852 
853     for ( i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++ )
854         pBindings->Update(i);
855 }
856 
857 void SfxCommonTemplateDialog_Impl::ClearResource()
858 {
859     ClearFamilyList();
860     impl_clear();
861 }
862 
863 void SfxCommonTemplateDialog_Impl::impl_clear()
864 {
865     pStyleFamilies.reset();
866     for (auto & i : pFamilyState)
867         i.reset();
868     for (auto & i : pBoundItems)
869         i.reset();
870     pCurObjShell = nullptr;
871 }
872 
873 SfxCommonTemplateDialog_Impl::DeletionWatcher *
874 SfxCommonTemplateDialog_Impl::impl_setDeletionWatcher(
875         DeletionWatcher *const pNewWatcher)
876 {
877     DeletionWatcher *const pRet(m_pDeletionWatcher);
878     m_pDeletionWatcher = pNewWatcher;
879     return pRet;
880 }
881 
882 void SfxCommonTemplateDialog_Impl::Initialize()
883 {
884     // Read global user resource
885     ReadResource();
886     pBindings->Invalidate( SID_STYLE_FAMILY );
887     pBindings->Update( SID_STYLE_FAMILY );
888 
889     Update_Impl();
890 
891     aFilterLb->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FilterSelectHdl ) );
892     aFmtLb->SetDoubleClickHdl( LINK( this, SfxCommonTemplateDialog_Impl, TreeListApplyHdl ) );
893     aFmtLb->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FmtSelectHdl ) );
894     aFmtLb->SetSelectionMode(SelectionMode::Multiple);
895     pTreeBox->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FmtSelectHdl ) );
896     pTreeBox->SetDoubleClickHdl( LINK( this, SfxCommonTemplateDialog_Impl,  ApplyHdl ) );
897     pTreeBox->SetDropHdl( LINK( this, SfxCommonTemplateDialog_Impl,  DropHdl ) );
898     aPreviewCheckbox->SetClickHdl( LINK(this, SfxCommonTemplateDialog_Impl, PreviewHdl));
899 
900 
901     aFilterLb->Show();
902     if (!bHierarchical)
903         aFmtLb->Show();
904     aPreviewCheckbox->Show();
905 }
906 
907 SfxCommonTemplateDialog_Impl::~SfxCommonTemplateDialog_Impl()
908 {
909 #if defined STYLESPREVIEW
910     Execute_Impl(SID_STYLE_END_PREVIEW,
911         OUString(), OUString(),
912         0, 0, 0, 0 );
913 #endif
914     if ( bIsWater )
915         Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
916     GetWindow()->Hide();
917     impl_clear();
918     if ( pStyleSheetPool )
919         EndListening(*pStyleSheetPool);
920     pStyleSheetPool = nullptr;
921     pTreeBox.disposeAndClear();
922     pIdle.reset();
923     if ( m_pDeletionWatcher )
924         m_pDeletionWatcher->signal();
925     aFmtLb.disposeAndClear();
926     aPreviewCheckbox.disposeAndClear();
927     aFilterLb.disposeAndClear();
928 }
929 
930 // Helper function: Access to the current family item
931 const SfxStyleFamilyItem *SfxCommonTemplateDialog_Impl::GetFamilyItem_Impl() const
932 {
933     const size_t nCount = pStyleFamilies->size();
934     for(size_t i = 0; i < nCount; ++i)
935     {
936         const SfxStyleFamilyItem &rItem = pStyleFamilies->at( i );
937         sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
938         if(nId == nActFamily)
939             return &rItem;
940     }
941     return nullptr;
942 }
943 
944 void SfxCommonTemplateDialog_Impl::GetSelectedStyle() const
945 {
946     if (!IsInitialized() || !pStyleSheetPool || !HasSelectedStyle())
947         return;
948     const OUString aTemplName( GetSelectedEntry() );
949     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
950     pStyleSheetPool->Find( aTemplName, pItem->GetFamily() );
951 }
952 
953 /**
954  * Is it safe to show the water-can / fill icon. If we've a
955  * hierarchical widget - we have only single select, otherwise
956  * we need to check if we have a multi-selection. We either have
957  * a pTreeBox showing or an aFmtLb (which we hide when not shown)
958  */
959 bool SfxCommonTemplateDialog_Impl::IsSafeForWaterCan() const
960 {
961     if ( pTreeBox->IsVisible() )
962         return pTreeBox->FirstSelected() != nullptr;
963     else
964         return aFmtLb->GetSelectionCount() == 1;
965 }
966 
967 void SfxCommonTemplateDialog_Impl::SelectStyle(const OUString &rStr)
968 {
969     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
970     if ( !pItem )
971         return;
972     const SfxStyleFamily eFam = pItem->GetFamily();
973     SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( rStr, eFam );
974     if( pStyle )
975     {
976         bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
977         EnableEdit( bReadWrite );
978         EnableHide( bReadWrite && !pStyle->IsHidden( ) && !pStyle->IsUsed( ) );
979         EnableShow( bReadWrite && pStyle->IsHidden( ) );
980     }
981     else
982     {
983         EnableEdit( false );
984         EnableHide( false );
985         EnableShow( false );
986     }
987 
988     if ( pTreeBox->IsVisible() )
989     {
990         if ( !rStr.isEmpty() )
991         {
992             SvTreeListEntry* pEntry = pTreeBox->First();
993             while ( pEntry )
994             {
995                 if ( pTreeBox->GetEntryText( pEntry ) == rStr )
996                 {
997                     pTreeBox->MakeVisible( pEntry );
998                     pTreeBox->Select( pEntry );
999                     return;
1000                 }
1001                 pEntry = pTreeBox->Next( pEntry );
1002             }
1003         }
1004         else
1005             pTreeBox->SelectAll( false );
1006     }
1007     else
1008     {
1009         bool bSelect = ! rStr.isEmpty();
1010         if ( bSelect )
1011         {
1012             SvTreeListEntry* pEntry = aFmtLb->FirstVisible();
1013             while ( pEntry && aFmtLb->GetEntryText( pEntry ) != rStr )
1014                 pEntry = aFmtLb->NextVisible( pEntry );
1015             if ( !pEntry )
1016                 bSelect = false;
1017             else
1018             {
1019                 if (!aFmtLb->IsSelected(pEntry))
1020                 {
1021                     aFmtLb->MakeVisible( pEntry );
1022                     aFmtLb->SelectAll(false);
1023                     aFmtLb->Select( pEntry );
1024                     bWaterDisabled = !IsSafeForWaterCan();
1025                     FmtSelectHdl( nullptr );
1026                 }
1027             }
1028         }
1029 
1030         if ( !bSelect )
1031         {
1032             aFmtLb->SelectAll( false );
1033             EnableEdit(false);
1034             EnableHide( false );
1035             EnableShow( false );
1036         }
1037     }
1038 }
1039 
1040 OUString SfxCommonTemplateDialog_Impl::GetSelectedEntry() const
1041 {
1042     OUString aRet;
1043     if ( pTreeBox->IsVisible() )
1044     {
1045         SvTreeListEntry* pEntry = pTreeBox->FirstSelected();
1046         if ( pEntry )
1047             aRet = pTreeBox->GetEntryText( pEntry );
1048     }
1049     else
1050     {
1051         SvTreeListEntry* pEntry = aFmtLb->FirstSelected();
1052         if ( pEntry )
1053             aRet = aFmtLb->GetEntryText( pEntry );
1054     }
1055     return aRet;
1056 }
1057 
1058 void SfxCommonTemplateDialog_Impl::EnableTreeDrag( bool bEnable )
1059 {
1060     if ( pStyleSheetPool )
1061     {
1062         SfxStyleSheetBase* pStyle = pStyleSheetPool->First();
1063         if ( pTreeBox->IsVisible() )
1064         {
1065             if ( pStyle && pStyle->HasParentSupport() && bEnable )
1066                 pTreeBox->SetDragDropMode(DragDropMode::CTRL_MOVE);
1067             else
1068                 pTreeBox->SetDragDropMode(DragDropMode::NONE);
1069         }
1070     }
1071     bTreeDrag = bEnable;
1072 }
1073 
1074 void SfxCommonTemplateDialog_Impl::FillTreeBox()
1075 {
1076     OSL_ENSURE( pTreeBox, "FillTreeBox() without treebox");
1077     if (!pStyleSheetPool || nActFamily == 0xffff)
1078         return;
1079 
1080     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
1081     if (!pItem)
1082         return;
1083     pStyleSheetPool->SetSearchMask(pItem->GetFamily(), SfxStyleSearchBits::AllVisible);
1084     StyleTreeArr_Impl aArr;
1085     SfxStyleSheetBase* pStyle = pStyleSheetPool->First();
1086 
1087     if(pStyle && pStyle->HasParentSupport() && bTreeDrag )
1088         pTreeBox->SetDragDropMode(DragDropMode::CTRL_MOVE);
1089     else
1090         pTreeBox->SetDragDropMode(DragDropMode::NONE);
1091 
1092     while (pStyle)
1093     {
1094         StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent());
1095         aArr.emplace_back(pNew);
1096         pStyle = pStyleSheetPool->Next();
1097     }
1098 
1099     MakeTree_Impl(aArr);
1100     std::vector<OUString> aEntries;
1101     pTreeBox->MakeExpanded_Impl(aEntries);
1102     pTreeBox->SetUpdateMode( false );
1103     pTreeBox->Clear();
1104     const sal_uInt16 nCount = aArr.size();
1105 
1106     for (sal_uInt16 i = 0; i < nCount; ++i)
1107     {
1108         FillBox_Impl(pTreeBox, aArr[i].get(), aEntries, pItem->GetFamily(), nullptr);
1109         aArr[i].reset();
1110     }
1111     pTreeBox->Recalc();
1112 
1113     EnableItem(SID_STYLE_WATERCAN, false);
1114 
1115     SfxTemplateItem* pState = pFamilyState[nActFamily - 1].get();
1116 
1117     if (nCount)
1118         pTreeBox->Expand(pTreeBox->First());
1119 
1120     for (SvTreeListEntry* pEntry = pTreeBox->First(); pEntry; pEntry = pTreeBox->Next(pEntry))
1121     {
1122         if (IsExpanded_Impl(aEntries, pTreeBox->GetEntryText(pEntry)))
1123             pTreeBox->Expand(pEntry);
1124     }
1125 
1126     pTreeBox->SetUpdateMode( true );
1127 
1128     OUString aStyle;
1129     if(pState)  // Select current entry
1130         aStyle = pState->GetStyleName();
1131     SelectStyle(aStyle);
1132     EnableDelete();
1133 }
1134 
1135 bool SfxCommonTemplateDialog_Impl::HasSelectedStyle() const
1136 {
1137     return pTreeBox->IsVisible()? pTreeBox->FirstSelected() != nullptr:
1138             aFmtLb->GetSelectionCount() != 0;
1139 }
1140 
1141 // internal: Refresh the display
1142 // nFlags: what we should update.
1143 void SfxCommonTemplateDialog_Impl::UpdateStyles_Impl(StyleFlags nFlags)
1144 {
1145     OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
1146     const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1147     if (!pItem)
1148     {
1149         // Is the case for the template catalog
1150         const size_t nFamilyCount = pStyleFamilies->size();
1151         size_t n;
1152         for( n = 0; n < nFamilyCount; n++ )
1153             if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break;
1154         if ( n == nFamilyCount )
1155             // It happens sometimes, God knows why
1156             return;
1157         nAppFilter = pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
1158         FamilySelect(  StyleNrToInfoOffset(n)+1 );
1159         pItem = GetFamilyItem_Impl();
1160     }
1161 
1162     const SfxStyleFamily eFam = pItem->GetFamily();
1163 
1164     SfxStyleSearchBits nFilter (nActFilter < pItem->GetFilterList().size() ? pItem->GetFilterList()[nActFilter].nFlags : SfxStyleSearchBits::Auto);
1165     if(nFilter == SfxStyleSearchBits::Auto)   // automatic
1166         nFilter = nAppFilter;
1167 
1168     OSL_ENSURE(pStyleSheetPool, "no StyleSheetPool");
1169     if(!pStyleSheetPool)
1170         return;
1171 
1172     pStyleSheetPool->SetSearchMask(eFam, nFilter);
1173     pItem = GetFamilyItem_Impl();
1174     if(nFlags & StyleFlags::UpdateFamily)   // Update view type list (Hierarchical, All, etc.
1175     {
1176         CheckItem(nActFamily);    // check Button in Toolbox
1177         aFilterLb->SetUpdateMode(false);
1178         aFilterLb->Clear();
1179         //insert hierarchical at the beginning
1180         sal_Int32 nPos = aFilterLb->InsertEntry(SfxResId(STR_STYLE_FILTER_HIERARCHICAL), 0);
1181         aFilterLb->SetEntryData( nPos, reinterpret_cast<void*>(SfxStyleSearchBits::All) );
1182         const SfxStyleFilter& rFilter = pItem->GetFilterList();
1183         for(const SfxFilterTuple& i : rFilter)
1184         {
1185             SfxStyleSearchBits nFilterFlags = i.nFlags;
1186             nPos = aFilterLb->InsertEntry( i.aName );
1187             aFilterLb->SetEntryData( nPos, reinterpret_cast<void*>(nFilterFlags) );
1188         }
1189         if(nActFilter < aFilterLb->GetEntryCount() - 1)
1190             aFilterLb->SelectEntryPos(nActFilter + 1);
1191         else
1192         {
1193             nActFilter = 0;
1194             aFilterLb->SelectEntryPos(1);
1195             SfxStyleSearchBits nFilterFlags = (nActFilter < rFilter.size()) ? rFilter[nActFilter].nFlags : SfxStyleSearchBits::Auto;
1196             pStyleSheetPool->SetSearchMask(eFam, nFilterFlags);
1197         }
1198 
1199         // if the tree view again, select family hierarchy
1200         if (pTreeBox->IsVisible() || m_bWantHierarchical)
1201         {
1202             aFilterLb->SelectEntry(SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
1203             EnableHierarchical(true);
1204         }
1205 
1206         // show maximum 14 entries
1207         aFilterLb->SetDropDownLineCount( MAX_FILTER_ENTRIES );
1208         aFilterLb->SetUpdateMode(true);
1209     }
1210     else
1211     {
1212         if (nActFilter < aFilterLb->GetEntryCount() - 1)
1213             aFilterLb->SelectEntryPos(nActFilter + 1);
1214         else
1215         {
1216             nActFilter = 0;
1217             aFilterLb->SelectEntryPos(1);
1218         }
1219     }
1220 
1221     if(!(nFlags & StyleFlags::UpdateFamilyList))
1222         return;
1223 
1224     EnableItem(SID_STYLE_WATERCAN,false);
1225 
1226     SfxStyleSheetBase *pStyle = pStyleSheetPool->First();
1227     SvTreeListEntry* pEntry = aFmtLb->First();
1228     std::vector<OUString> aStrings;
1229 
1230     comphelper::string::NaturalStringSorter aSorter(
1231         ::comphelper::getProcessComponentContext(),
1232         Application::GetSettings().GetLanguageTag().getLocale());
1233 
1234     while( pStyle )
1235     {
1236         aStrings.push_back(pStyle->GetName());
1237         pStyle = pStyleSheetPool->Next();
1238     }
1239 
1240     // Paradoxically, with a list and non-Latin style names,
1241     // sorting twice is faster than sorting once.
1242     // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
1243     // Then the second sort needs to call its (much more expensive) comparator less often.
1244     std::sort(aStrings.begin(), aStrings.end());
1245     std::sort(aStrings.begin(), aStrings.end(),
1246        [&aSorter](const OUString& rLHS, const OUString& rRHS) {
1247        return aSorter.compare(rLHS, rRHS) < 0;
1248        });
1249 
1250     size_t nCount = aStrings.size();
1251     size_t nPos = 0;
1252     while(nPos < nCount && pEntry &&
1253           aStrings[nPos] == aFmtLb->GetEntryText(pEntry))
1254     {
1255         ++nPos;
1256         pEntry = aFmtLb->Next( pEntry );
1257     }
1258 
1259     if( nPos < nCount || pEntry )
1260     {
1261         // Fills the display box
1262         aFmtLb->SetUpdateMode(false);
1263         aFmtLb->Clear();
1264 
1265         for(nPos = 0; nPos < nCount; ++nPos)
1266         {
1267             SvTreeListEntry* pTreeListEntry = aFmtLb->InsertEntry(aStrings[nPos], nullptr, false, nPos);
1268             if (officecfg::Office::Common::StylesAndFormatting::Preview::get())
1269             {
1270                 pTreeListEntry->ReplaceItem(std::make_unique<StyleLBoxString>(aStrings[nPos], eFam), 1);
1271             }
1272             aFmtLb->GetModel()->InvalidateEntry(pTreeListEntry);
1273         }
1274         aFmtLb->Recalc();
1275         aFmtLb->SetUpdateMode(true);
1276     }
1277     // Selects the current style if any
1278     SfxTemplateItem *pState = pFamilyState[nActFamily-1].get();
1279     OUString aStyle;
1280     if(pState)
1281         aStyle = pState->GetStyleName();
1282 #if defined STYLESPREVIEW
1283     mbIgnoreSelect = true; // in case we get a selection change
1284     // in any case we should stop any preview
1285     Execute_Impl(SID_STYLE_END_PREVIEW,
1286     OUString(), OUString(),
1287     0, 0, 0, 0 );
1288 #endif
1289     SelectStyle(aStyle);
1290     EnableDelete();
1291 }
1292 
1293 // Updated display: Watering the house
1294 void SfxCommonTemplateDialog_Impl::SetWaterCanState(const SfxBoolItem *pItem)
1295 {
1296     bWaterDisabled = (pItem == nullptr);
1297 
1298     if(!bWaterDisabled)
1299         //make sure the watercan is only activated when there is (only) one selection
1300         bWaterDisabled = !IsSafeForWaterCan();
1301 
1302     if(pItem && !bWaterDisabled)
1303     {
1304         CheckItem(SID_STYLE_WATERCAN, pItem->GetValue());
1305         EnableItem( SID_STYLE_WATERCAN );
1306     }
1307     else
1308     {
1309         if(!bWaterDisabled)
1310             EnableItem(SID_STYLE_WATERCAN);
1311         else
1312             EnableItem(SID_STYLE_WATERCAN, false);
1313     }
1314 
1315 // Ignore while in watercan mode statusupdates
1316 
1317     size_t nCount = pStyleFamilies->size();
1318     pBindings->EnterRegistrations();
1319     for(size_t n = 0; n < nCount; n++)
1320     {
1321         SfxControllerItem *pCItem=pBoundItems[n].get();
1322         bool bChecked = pItem && pItem->GetValue();
1323         if( pCItem->IsBound() == bChecked )
1324         {
1325             if( !bChecked )
1326                 pCItem->ReBind();
1327             else
1328                 pCItem->UnBind();
1329         }
1330     }
1331     pBindings->LeaveRegistrations();
1332 }
1333 
1334 // Item with the status of a Family is copied and noted
1335 // (is updated when all states have also been updated.)
1336 // See also: <SfxBindings::AddDoneHdl(const Link &)>
1337 void SfxCommonTemplateDialog_Impl::SetFamilyState( sal_uInt16 nSlotId, const SfxTemplateItem* pItem )
1338 {
1339     sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
1340     pFamilyState[nIdx].reset();
1341     if ( pItem )
1342         pFamilyState[nIdx].reset( new SfxTemplateItem(*pItem) );
1343     bUpdate = true;
1344 
1345     // If used templates (how the hell you find this out??)
1346     bUpdateFamily = true;
1347 }
1348 
1349 // Notice from SfxBindings that the update is completed. Pushes out the update
1350 // of the display.
1351 void SfxCommonTemplateDialog_Impl::Update_Impl()
1352 {
1353     bool bDocChanged=false;
1354     SfxStyleSheetBasePool* pNewPool = nullptr;
1355     SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
1356     SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
1357     if( pDocShell )
1358         pNewPool = pDocShell->GetStyleSheetPool();
1359 
1360     if ( pNewPool != pStyleSheetPool && pDocShell )
1361     {
1362         SfxModule* pNewModule = pDocShell->GetModule();
1363         if( pNewModule && pNewModule != pModule )
1364         {
1365             ClearResource();
1366             ReadResource();
1367         }
1368         if ( pStyleSheetPool )
1369         {
1370             EndListening(*pStyleSheetPool);
1371             pStyleSheetPool = nullptr;
1372         }
1373 
1374         if ( pNewPool )
1375         {
1376             StartListening(*pNewPool);
1377             pStyleSheetPool = pNewPool;
1378             bDocChanged=true;
1379         }
1380     }
1381 
1382     if (bUpdateFamily)
1383         UpdateFamily_Impl();
1384 
1385     sal_uInt16 i;
1386     for(i = 0; i < MAX_FAMILIES; ++i)
1387         if(pFamilyState[i])
1388             break;
1389     if(i == MAX_FAMILIES || !pNewPool)
1390         // nothing is allowed
1391         return;
1392 
1393     SfxTemplateItem *pItem = nullptr;
1394     // current region not within the allowed region or default
1395     if(nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get() ) )
1396     {
1397          CheckItem(nActFamily, false);
1398          const size_t nFamilyCount = pStyleFamilies->size();
1399          size_t n;
1400          for( n = 0; n < nFamilyCount; n++ )
1401              if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break;
1402 
1403          std::unique_ptr<SfxTemplateItem> & pNewItem = pFamilyState[StyleNrToInfoOffset(n)];
1404          nAppFilter = pNewItem->GetValue();
1405          FamilySelect( StyleNrToInfoOffset(n) + 1 );
1406          pItem = pNewItem.get();
1407     }
1408     else if( bDocChanged )
1409     {
1410          // other DocShell -> all new
1411          CheckItem( nActFamily );
1412          nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pDocShell ) );
1413          if ( 0xffff == nActFilter )
1414             nActFilter = pDocShell->GetAutoStyleFilterIndex();
1415 
1416          nAppFilter = pItem->GetValue();
1417          if(!pTreeBox->IsVisible())
1418          {
1419              UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
1420          }
1421          else
1422              FillTreeBox();
1423     }
1424     else
1425     {
1426          // other filters for automatic
1427          CheckItem( nActFamily );
1428          const SfxStyleFamilyItem *pStyleItem =  GetFamilyItem_Impl();
1429          if ( pStyleItem && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[nActFilter].nFlags
1430             && nAppFilter != pItem->GetValue())
1431          {
1432              nAppFilter = pItem->GetValue();
1433              if(!pTreeBox->IsVisible())
1434                  UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
1435              else
1436                  FillTreeBox();
1437          }
1438          else
1439              nAppFilter = pItem->GetValue();
1440     }
1441     const OUString aStyle(pItem->GetStyleName());
1442     SelectStyle(aStyle);
1443     EnableDelete();
1444     EnableNew( bCanNew );
1445 }
1446 
1447 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, TimeOut, Timer *, void )
1448 {
1449     if(!bDontUpdate)
1450     {
1451         bDontUpdate=true;
1452         if(!pTreeBox->IsVisible())
1453             UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
1454         else
1455         {
1456             FillTreeBox();
1457             SfxTemplateItem *pState = pFamilyState[nActFamily-1].get();
1458             if(pState)
1459             {
1460                 SelectStyle(pState->GetStyleName());
1461                 EnableDelete();
1462             }
1463         }
1464         bDontUpdate=false;
1465         pIdle.reset();
1466     }
1467     else
1468         pIdle->Start();
1469 }
1470 
1471 void SfxCommonTemplateDialog_Impl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1472 {
1473     const SfxHintId nId = rHint.GetId();
1474 
1475     // tap update
1476     switch(nId)
1477     {
1478         case SfxHintId::UpdateDone:
1479             {
1480                 SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
1481                 SfxObjectShell *pDocShell = pViewFrame->GetObjectShell();
1482                 if (
1483                         bUpdate &&
1484                         (
1485                          !IsCheckedItem(SID_STYLE_WATERCAN) ||
1486                          (pDocShell && pDocShell->GetStyleSheetPool() != pStyleSheetPool)
1487                         )
1488                    )
1489                 {
1490                     bUpdate = false;
1491                     Update_Impl();
1492                 }
1493                 else if ( bUpdateFamily )
1494                 {
1495                     UpdateFamily_Impl();
1496                 }
1497 
1498                 if( pStyleSheetPool )
1499                 {
1500                     OUString aStr = GetSelectedEntry();
1501                     if (!aStr.isEmpty())
1502                     {
1503                         const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1504                         if( !pItem ) break;
1505                         const SfxStyleFamily eFam = pItem->GetFamily();
1506                         SfxStyleSheetBase *pStyle = pStyleSheetPool->Find( aStr, eFam );
1507                         if( pStyle )
1508                         {
1509                             bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
1510                             EnableEdit( bReadWrite );
1511                             EnableHide( bReadWrite && !pStyle->IsUsed( ) && !pStyle->IsHidden( ) );
1512                             EnableShow( bReadWrite && pStyle->IsHidden( ) );
1513                         }
1514                         else
1515                         {
1516                             EnableEdit(false);
1517                             EnableHide(false);
1518                             EnableShow(false);
1519                         }
1520                     }
1521                 }
1522                 break;
1523             }
1524 
1525             // Necessary if switching between documents and in both documents
1526             // the same template is used. Do not immediately call Update_Impl,
1527             // for the case that one of the documents is an internal InPlaceObject!
1528         case SfxHintId::DocChanged:
1529             bUpdate = true;
1530         break;
1531         case SfxHintId::Dying:
1532             {
1533                 EndListening(*pStyleSheetPool);
1534                 pStyleSheetPool=nullptr;
1535                 break;
1536             }
1537         default: break;
1538     }
1539 
1540     // Do not set timer when the stylesheet pool is in the box, because it is
1541     // possible that a new one is registered after the timer is up -
1542     // works bad in UpdateStyles_Impl ()!
1543 
1544     if(!bDontUpdate && nId != SfxHintId::Dying &&
1545        (dynamic_cast<const SfxStyleSheetPoolHint*>(&rHint) ||
1546         dynamic_cast<const SfxStyleSheetHint*>(&rHint) ||
1547         dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint) ||
1548         nId == SfxHintId::StyleSheetModified))
1549     {
1550         if(!pIdle)
1551         {
1552             pIdle.reset(new Idle("SfxCommonTemplate"));
1553             pIdle->SetPriority(TaskPriority::LOWEST);
1554             pIdle->SetInvokeHandler(LINK(this,SfxCommonTemplateDialog_Impl,TimeOut));
1555         }
1556         pIdle->Start();
1557 
1558     }
1559 }
1560 
1561 // Other filters; can be switched by the users or as a result of new or
1562 // editing, if the current document has been assigned a different filter.
1563 void SfxCommonTemplateDialog_Impl::FilterSelect(
1564                 sal_uInt16 nEntry,  // Idx of the new Filters
1565                 bool bForce )   // Force update, even if the new filter is
1566                                 // equal to the current
1567 {
1568     if( nEntry == nActFilter && !bForce )
1569         return;
1570 
1571     nActFilter = nEntry;
1572     SfxObjectShell *const pDocShell = SaveSelection();
1573     SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool;
1574     pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr;
1575     if ( pOldStyleSheetPool != pStyleSheetPool )
1576     {
1577         if ( pOldStyleSheetPool )
1578             EndListening(*pOldStyleSheetPool);
1579         if ( pStyleSheetPool )
1580             StartListening(*pStyleSheetPool);
1581     }
1582 
1583     UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
1584 }
1585 
1586 // Internal: Perform functions through the Dispatcher
1587 bool SfxCommonTemplateDialog_Impl::Execute_Impl(
1588     sal_uInt16 nId, const OUString &rStr, const OUString& rRefStr, sal_uInt16 nFamily,
1589     SfxStyleSearchBits nMask, sal_uInt16 *pIdx, const sal_uInt16* pModifier)
1590 {
1591     SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl();
1592     SfxStringItem aItem(nId, rStr);
1593     SfxUInt16Item aFamily(SID_STYLE_FAMILY, nFamily);
1594     SfxUInt16Item aMask( SID_STYLE_MASK, static_cast<sal_uInt16>(nMask) );
1595     SfxStringItem aUpdName(SID_STYLE_UPD_BY_EX_NAME, rStr);
1596     SfxStringItem aRefName( SID_STYLE_REFERENCE, rRefStr );
1597     const SfxPoolItem* pItems[ 6 ];
1598     sal_uInt16 nCount = 0;
1599     if( !rStr.isEmpty() )
1600         pItems[ nCount++ ] = &aItem;
1601     pItems[ nCount++ ] = &aFamily;
1602     if( nMask != SfxStyleSearchBits::Auto )
1603         pItems[ nCount++ ] = &aMask;
1604     if(SID_STYLE_UPDATE_BY_EXAMPLE == nId)
1605     {
1606         // Special solution for Numbering update in Writer
1607         const OUString aTemplName(GetSelectedEntry());
1608         aUpdName.SetValue(aTemplName);
1609         pItems[ nCount++ ] = &aUpdName;
1610     }
1611 
1612     if ( !rRefStr.isEmpty() )
1613         pItems[ nCount++ ] = &aRefName;
1614 
1615     pItems[ nCount++ ] = nullptr;
1616 
1617     DeletionWatcher aDeleted(*this);
1618     sal_uInt16 nModi = pModifier ? *pModifier : 0;
1619     const SfxPoolItem* pItem = rDispatcher.Execute(
1620         nId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
1621         pItems, nModi );
1622 
1623     // Dialog can be destroyed while in Execute() because started
1624     // subdialogs are not modal to it (#i97888#).
1625     if ( !pItem || aDeleted )
1626         return false;
1627 
1628     if ( (nId == SID_STYLE_NEW || SID_STYLE_EDIT == nId) && (pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1) )
1629     {
1630         const SfxUInt16Item *pFilterItem = dynamic_cast< const SfxUInt16Item* >(pItem);
1631         assert(pFilterItem);
1632         SfxStyleSearchBits nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue()) & ~SfxStyleSearchBits::UserDefined;
1633         if(nFilterFlags == SfxStyleSearchBits::Auto)       // User Template?
1634             nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue());
1635         const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl();
1636         const size_t nFilterCount = pFamilyItem->GetFilterList().size();
1637 
1638         for ( size_t i = 0; i < nFilterCount; ++i )
1639         {
1640             const SfxFilterTuple &rTupel = pFamilyItem->GetFilterList()[ i ];
1641 
1642             if ( ( rTupel.nFlags & nFilterFlags ) == nFilterFlags && pIdx )
1643                 *pIdx = i;
1644         }
1645     }
1646 
1647     return true;
1648 }
1649 
1650 // Handler Listbox of Filter
1651 void SfxCommonTemplateDialog_Impl::EnableHierarchical(bool const bEnable)
1652 {
1653     if (bEnable)
1654     {
1655         if (!bHierarchical)
1656         {
1657             // Turn on treeView
1658             bHierarchical=true;
1659             m_bWantHierarchical = true;
1660             SaveSelection(); // fdo#61429 store "hierarchical"
1661             const OUString aSelectEntry( GetSelectedEntry());
1662             aFmtLb->Hide();
1663             pTreeBox->SetFont( aFmtLb->GetFont() );
1664             pTreeBox->SetPosSizePixel(aFmtLb->GetPosPixel(), aFmtLb->GetSizePixel());
1665             FillTreeBox();
1666             SelectStyle(aSelectEntry);
1667             pTreeBox->Show();
1668         }
1669     }
1670     else
1671     {
1672         pTreeBox->Hide();
1673         aFmtLb->Show();
1674         // If bHierarchical, then the family can have changed
1675         // minus one since hierarchical is inserted at the start
1676         m_bWantHierarchical = false; // before FilterSelect
1677         FilterSelect(aFilterLb->GetSelectedEntryPos() - 1, bHierarchical );
1678         bHierarchical=false;
1679     }
1680 }
1681 
1682 IMPL_LINK( SfxCommonTemplateDialog_Impl, FilterSelectHdl, ListBox&, rBox, void )
1683 {
1684     if (SfxResId(STR_STYLE_FILTER_HIERARCHICAL) == rBox.GetSelectedEntry())
1685     {
1686         EnableHierarchical(true);
1687     }
1688     else
1689     {
1690         EnableHierarchical(false);
1691     }
1692 }
1693 
1694 // Select-Handler for the Toolbox
1695 void SfxCommonTemplateDialog_Impl::FamilySelect(sal_uInt16 nEntry, bool bPreviewRefresh)
1696 {
1697     assert((0 < nEntry && nEntry <= MAX_FAMILIES) || 0xffff == nEntry);
1698     if( nEntry != nActFamily || bPreviewRefresh )
1699     {
1700         CheckItem( nActFamily, false );
1701         nActFamily = nEntry;
1702         SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl();
1703         SfxUInt16Item const aItem(SID_STYLE_FAMILY,
1704                 static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
1705         pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
1706         pBindings->Invalidate( SID_STYLE_FAMILY );
1707         pBindings->Update( SID_STYLE_FAMILY );
1708         UpdateFamily_Impl();
1709     }
1710 }
1711 
1712 void SfxCommonTemplateDialog_Impl::ActionSelect(sal_uInt16 nEntry)
1713 {
1714     switch(nEntry)
1715     {
1716         case SID_STYLE_WATERCAN:
1717         {
1718             const bool bState = IsCheckedItem(nEntry);
1719             bool bCheck;
1720             SfxBoolItem aBool;
1721             // when a template is chosen.
1722             if (!bState && HasSelectedStyle())
1723             {
1724                 const OUString aTemplName(
1725                     GetSelectedEntry());
1726                 Execute_Impl(
1727                     SID_STYLE_WATERCAN, aTemplName, "",
1728                     static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
1729                 bCheck = true;
1730             }
1731             else
1732             {
1733                 Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
1734                 bCheck = false;
1735             }
1736             CheckItem(nEntry, bCheck);
1737             aBool.SetValue(bCheck);
1738             SetWaterCanState(&aBool);
1739             break;
1740         }
1741         case SID_STYLE_NEW_BY_EXAMPLE:
1742         {
1743             if(pStyleSheetPool && nActFamily != 0xffff)
1744             {
1745                 const SfxStyleFamily eFam=GetFamilyItem_Impl()->GetFamily();
1746                 const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1747                 SfxStyleSearchBits nFilter;
1748                 if( pItem && nActFilter != 0xffff )
1749                 {
1750                     nFilter = pItem->GetFilterList()[nActFilter].nFlags;
1751                     if(nFilter == SfxStyleSearchBits::Auto)    // automatic
1752                         nFilter = nAppFilter;
1753                 }
1754                 else
1755                     nFilter=pStyleSheetPool->GetSearchMask();
1756                 pStyleSheetPool->SetSearchMask( eFam, SfxStyleSearchBits::UserDefined );
1757 
1758                 // why? : FloatingWindow must not be parent of a modal dialog
1759                 SfxNewStyleDlg aDlg(pWindow ? pWindow->GetFrameWeld() : nullptr, *pStyleSheetPool);
1760                 if (aDlg.run() ==  RET_OK)
1761                 {
1762                     pStyleSheetPool->SetSearchMask(eFam, nFilter);
1763                     const OUString aTemplName(aDlg.GetName());
1764                     Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE,
1765                                  aTemplName, "",
1766                                  static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
1767                                  nFilter);
1768                     UpdateFamily_Impl();
1769                 }
1770                 pStyleSheetPool->SetSearchMask( eFam, nFilter );
1771             }
1772             break;
1773         }
1774         case SID_STYLE_UPDATE_BY_EXAMPLE:
1775         {
1776             Execute_Impl(SID_STYLE_UPDATE_BY_EXAMPLE,
1777                     "", "",
1778                     static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
1779             break;
1780         }
1781         case SID_TEMPLATE_LOAD:
1782             SfxGetpApp()->GetDispatcher_Impl()->Execute(nEntry);
1783         break;
1784         default: OSL_FAIL("not implemented"); break;
1785     }
1786 }
1787 
1788 static OUString getModuleIdentifier( const Reference< XModuleManager2 >& i_xModMgr, SfxObjectShell const * i_pObjSh )
1789 {
1790     OSL_ENSURE( i_xModMgr.is(), "getModuleIdentifier(): no XModuleManager" );
1791     OSL_ENSURE( i_pObjSh, "getModuleIdentifier(): no ObjectShell" );
1792 
1793     OUString sIdentifier;
1794 
1795     try
1796     {
1797         sIdentifier = i_xModMgr->identify( i_pObjSh->GetModel() );
1798     }
1799     catch ( css::frame::UnknownModuleException& )
1800     {
1801         SAL_WARN("sfx", "getModuleIdentifier(): unknown module" );
1802     }
1803     catch ( Exception& )
1804     {
1805         OSL_FAIL( "getModuleIdentifier(): exception of XModuleManager::identify()" );
1806     }
1807 
1808     return sIdentifier;
1809 }
1810 
1811 sal_Int32 SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter( SfxObjectShell const * i_pObjSh )
1812 {
1813     OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );
1814 
1815     ::comphelper::SequenceAsHashMap aFactoryProps(
1816         xModuleManager->getByName( getModuleIdentifier( xModuleManager, i_pObjSh ) ) );
1817     sal_Int32 nFilter = aFactoryProps.getUnpackedValueOrDefault( "ooSetupFactoryStyleFilter", sal_Int32(-1) );
1818 
1819     m_bWantHierarchical = (nFilter & 0x1000) != 0;
1820     nFilter &= ~0x1000; // clear it
1821 
1822     return nFilter;
1823 }
1824 
1825 void SfxCommonTemplateDialog_Impl::SaveFactoryStyleFilter( SfxObjectShell const * i_pObjSh, sal_Int32 i_nFilter )
1826 {
1827     OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );
1828     Sequence< PropertyValue > lProps(1);
1829     lProps[0].Name = "ooSetupFactoryStyleFilter";
1830     lProps[0].Value <<= i_nFilter | (m_bWantHierarchical ? 0x1000 : 0);
1831     xModuleManager->replaceByName( getModuleIdentifier( xModuleManager, i_pObjSh ), makeAny( lProps ) );
1832 }
1833 
1834 SfxObjectShell* SfxCommonTemplateDialog_Impl::SaveSelection()
1835 {
1836     SfxViewFrame *const pViewFrame(pBindings->GetDispatcher_Impl()->GetFrame());
1837     SfxObjectShell *const pDocShell(pViewFrame->GetObjectShell());
1838     if (pDocShell)
1839     {
1840         pDocShell->SetAutoStyleFilterIndex(nActFilter);
1841         SaveFactoryStyleFilter( pDocShell, nActFilter );
1842     }
1843     return pDocShell;
1844 }
1845 
1846 IMPL_LINK( SfxCommonTemplateDialog_Impl, DropHdl, StyleTreeListBox_Impl&, rBox, bool )
1847 {
1848     bDontUpdate = true;
1849     const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1850     const SfxStyleFamily eFam = pItem->GetFamily();
1851     bool ret = pStyleSheetPool->SetParent(eFam, rBox.GetStyle(), rBox.GetParent());
1852     bDontUpdate = false;
1853     return ret;
1854 }
1855 
1856 // Handler for the New-Buttons
1857 void SfxCommonTemplateDialog_Impl::NewHdl()
1858 {
1859     if ( nActFamily == 0xffff || !(pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1))
1860         return;
1861 
1862     const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
1863     const SfxStyleFamily eFam=pItem->GetFamily();
1864     SfxStyleSearchBits nMask;
1865     if( nActFilter != 0xffff )
1866     {
1867         nMask = pItem->GetFilterList()[nActFilter].nFlags;
1868         if(nMask == SfxStyleSearchBits::Auto)    // automatic
1869             nMask = nAppFilter;
1870     }
1871     else
1872         nMask=pStyleSheetPool->GetSearchMask();
1873 
1874     pStyleSheetPool->SetSearchMask(eFam,nMask);
1875 
1876     Execute_Impl(SID_STYLE_NEW,
1877                  "", GetSelectedEntry(),
1878                  static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
1879                  nMask);
1880 }
1881 
1882 // Handler for the edit-Buttons
1883 void SfxCommonTemplateDialog_Impl::EditHdl()
1884 {
1885     if(IsInitialized() && HasSelectedStyle())
1886     {
1887         sal_uInt16 nFilter = nActFilter;
1888         OUString aTemplName(GetSelectedEntry());
1889         GetSelectedStyle(); // -Wall required??
1890         Execute_Impl( SID_STYLE_EDIT, aTemplName, OUString(),
1891                           static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()), SfxStyleSearchBits::Auto, &nFilter );
1892     }
1893 }
1894 
1895 // Handler for the Delete-Buttons
1896 void SfxCommonTemplateDialog_Impl::DeleteHdl()
1897 {
1898     if ( !IsInitialized() || !HasSelectedStyle() )
1899         return;
1900 
1901     bool bUsedStyle = false;     // one of the selected styles are used in the document?
1902 
1903     std::vector<SvTreeListEntry*> aList;
1904     SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected();
1905     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
1906 
1907     OUStringBuffer aMsg;
1908     aMsg.append(SfxResId(STR_DELETE_STYLE_USED)).append(SfxResId(STR_DELETE_STYLE));
1909 
1910     while (pEntry)
1911     {
1912         aList.push_back( pEntry );
1913         // check the style is used or not
1914         const OUString aTemplName(pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry));
1915 
1916         SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( aTemplName, pItem->GetFamily() );
1917 
1918         if ( pStyle->IsUsed() )  // pStyle is in use in the document?
1919         {
1920             if (bUsedStyle) // add a separator for the second and later styles
1921                 aMsg.append(", ");
1922             aMsg.append(aTemplName);
1923             bUsedStyle = true;
1924         }
1925 
1926         pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry);
1927     }
1928 
1929     bool aApproved = false;
1930 
1931     // we only want to show the dialog once and if we want to delete a style in use (UX-advice)
1932     if ( bUsedStyle )
1933     {
1934         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
1935                                                                  VclMessageType::Question, VclButtonsType::YesNo,
1936                                                                  aMsg.makeStringAndClear()));
1937         aApproved = xBox->run() == RET_YES;
1938     }
1939 
1940     // if there are no used styles selected or the user approved the changes
1941     if ( !(!bUsedStyle || aApproved) )
1942         return;
1943 
1944     for (auto const& elem : aList)
1945     {
1946         const OUString aTemplName(pTreeBox->IsVisible() ? pTreeBox->GetEntryText(elem) : aFmtLb->GetEntryText(elem));
1947         bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting
1948         Execute_Impl( SID_STYLE_DELETE, aTemplName,
1949                       OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
1950 
1951         if ( pTreeBox->IsVisible() )
1952         {
1953             pTreeBox->RemoveParentKeepChildren(elem);
1954             bDontUpdate = false;
1955         }
1956     }
1957     bDontUpdate = false; //if everything is deleted set bDontUpdate back to false
1958     UpdateStyles_Impl(StyleFlags::UpdateFamilyList); //and force-update the list
1959 }
1960 
1961 void SfxCommonTemplateDialog_Impl::HideHdl()
1962 {
1963     if ( !IsInitialized() || !HasSelectedStyle() )
1964         return;
1965 
1966     SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected();
1967 
1968     while (pEntry)
1969     {
1970         OUString aTemplName = pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry);
1971 
1972         Execute_Impl( SID_STYLE_HIDE, aTemplName,
1973                       OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
1974 
1975         pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry);
1976     }
1977 }
1978 
1979 void SfxCommonTemplateDialog_Impl::ShowHdl()
1980 {
1981     if ( !IsInitialized() || !HasSelectedStyle() )
1982         return;
1983 
1984     SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected();
1985 
1986     while (pEntry)
1987     {
1988         OUString aTemplName = pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry);
1989 
1990         Execute_Impl( SID_STYLE_SHOW, aTemplName,
1991                       OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
1992 
1993         pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry);
1994     }
1995 }
1996 
1997 void SfxCommonTemplateDialog_Impl::EnableDelete()
1998 {
1999     bool bEnableDelete(false);
2000     if(IsInitialized() && HasSelectedStyle())
2001     {
2002         OSL_ENSURE(pStyleSheetPool, "No StyleSheetPool");
2003         const OUString aTemplName(GetSelectedEntry());
2004         const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
2005         const SfxStyleFamily eFam = pItem->GetFamily();
2006         SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
2007         if (pItem->GetFilterList().size() > nActFilter)
2008             nFilter = pItem->GetFilterList()[nActFilter].nFlags;
2009         if(nFilter == SfxStyleSearchBits::Auto)    // automatic
2010             nFilter = nAppFilter;
2011         const SfxStyleSheetBase *pStyle =
2012             pStyleSheetPool->Find(aTemplName,eFam, pTreeBox->IsVisible()? SfxStyleSearchBits::All : nFilter);
2013 
2014         OSL_ENSURE(pStyle, "Style not found");
2015         if (pStyle && pStyle->IsUserDefined() && (pStyle->HasParentSupport() || !pStyle->IsUsed()))
2016             bEnableDelete = true;
2017     }
2018     EnableDel(bEnableDelete);
2019 }
2020 
2021 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, TreeListApplyHdl, SvTreeListBox *, bool )
2022 {
2023     ApplyHdl(nullptr);
2024     return false;
2025 }
2026 
2027 // Double-click on a style sheet in the ListBox is applied.
2028 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, ApplyHdl, LinkParamNone*, void )
2029 {
2030     // only if that region is allowed
2031     if ( IsInitialized() && nullptr != pFamilyState[nActFamily-1] &&
2032          !GetSelectedEntry().isEmpty() )
2033     {
2034         sal_uInt16 nModifier = aFmtLb->GetModifier();
2035         Execute_Impl(SID_STYLE_APPLY,
2036                      GetSelectedEntry(), OUString(),
2037                      static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
2038                      SfxStyleSearchBits::Auto, nullptr, &nModifier );
2039     }
2040     // After selecting a focused item if possible again on the app window
2041     if ( dynamic_cast< const SfxTemplateDialog_Impl* >(this) !=  nullptr )
2042     {
2043         SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
2044         SfxViewShell *pVu = pViewFrame->GetViewShell();
2045         vcl::Window *pAppWin = pVu ? pVu->GetWindow(): nullptr;
2046         if(pAppWin)
2047             pAppWin->GrabFocus();
2048     }
2049 }
2050 
2051 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, PreviewHdl, Button*, void)
2052 {
2053     std::shared_ptr<comphelper::ConfigurationChanges> batch( comphelper::ConfigurationChanges::create() );
2054     officecfg::Office::Common::StylesAndFormatting::Preview::set( aPreviewCheckbox->IsChecked(), batch );
2055     batch->commit();
2056     if(!bHierarchical)
2057     {
2058         sal_uInt16 nSize = aFmtLb->GetEntryCount();
2059         for (sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2060         {
2061             SvTreeListEntry* pTreeListEntry = aFmtLb->GetEntry(nPos);
2062             OUString aEntryStr = aFmtLb->GetEntryText(pTreeListEntry);
2063             const SfxStyleFamily eFam = aPreviewCheckbox->IsChecked() ? GetFamilyItem_Impl()->GetFamily(): SfxStyleFamily::None;
2064             pTreeListEntry->ReplaceItem(std::make_unique<StyleLBoxString>(aEntryStr, eFam), 1);
2065             aFmtLb->GetModel()->InvalidateEntry(pTreeListEntry);
2066             aFmtLb->Recalc();
2067         }
2068     }
2069     else
2070     {
2071         FamilySelect(nActFamily, true);
2072     }
2073 }
2074 
2075 // Selection of a template during the Watercan-Status
2076 IMPL_LINK( SfxCommonTemplateDialog_Impl, FmtSelectHdl, SvTreeListBox *, pListBox, void )
2077 {
2078     // Trigger Help PI, if this is permitted of call handlers and field
2079     if( !pListBox || pListBox->IsSelected( pListBox->GetHdlEntry() ) )
2080     {
2081         // Only when the watercan is on
2082         if ( IsInitialized() &&
2083              IsCheckedItem(SID_STYLE_WATERCAN) &&
2084              // only if that region is allowed
2085              nullptr != pFamilyState[nActFamily-1] && (pTreeBox || aFmtLb->GetSelectionCount() <= 1) )
2086         {
2087             Execute_Impl(SID_STYLE_WATERCAN,
2088                          "", "", 0);
2089             Execute_Impl(SID_STYLE_WATERCAN,
2090                          GetSelectedEntry(), "",
2091                          static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
2092         }
2093         EnableItem(SID_STYLE_WATERCAN, !bWaterDisabled);
2094         EnableDelete();
2095     }
2096     if( !pListBox )
2097         return;
2098 
2099     SelectStyle( pListBox->GetEntryText( pListBox->GetHdlEntry() ));
2100 #if defined STYLESPREVIEW
2101     sal_uInt16 nModifier = aFmtLb->GetModifier();
2102     if ( mbIgnoreSelect )
2103     {
2104         Execute_Impl(SID_STYLE_END_PREVIEW,
2105         OUString(), OUString(),
2106         0, 0, 0, 0 );
2107         mbIgnoreSelect = false;
2108     }
2109     else
2110     {
2111         Execute_Impl(SID_STYLE_PREVIEW,
2112                  GetSelectedEntry(), OUString(),
2113                  ( sal_uInt16 )GetFamilyItem_Impl()->GetFamily(),
2114                  0, 0, &nModifier );
2115     }
2116 #endif
2117 }
2118 
2119 IMPL_LINK( SfxCommonTemplateDialog_Impl, MenuSelectHdl, Menu*, pMenu, bool )
2120 {
2121     sLastItemIdent = pMenu->GetCurItemIdent();
2122     Application::PostUserEvent(
2123         LINK( this, SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl ) );
2124     return true;
2125 }
2126 
2127 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl, void*, void )
2128 {
2129     if (sLastItemIdent == "new")
2130         NewHdl();
2131     else if (sLastItemIdent == "edit")
2132         EditHdl();
2133     else if (sLastItemIdent == "delete")
2134         DeleteHdl();
2135     else if (sLastItemIdent == "hide")
2136         HideHdl();
2137     else if (sLastItemIdent == "show")
2138         ShowHdl();
2139 }
2140 
2141 SfxStyleFamily SfxCommonTemplateDialog_Impl::GetActualFamily() const
2142 {
2143     const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl();
2144     if( !pFamilyItem || nActFamily == 0xffff )
2145         return SfxStyleFamily::Para;
2146     else
2147         return pFamilyItem->GetFamily();
2148 }
2149 
2150 void SfxCommonTemplateDialog_Impl::EnableExample_Impl(sal_uInt16 nId, bool bEnable)
2151 {
2152     bool bDisable = !bEnable || !IsSafeForWaterCan();
2153     if( nId == SID_STYLE_NEW_BY_EXAMPLE )
2154         bNewByExampleDisabled = bDisable;
2155     else if( nId == SID_STYLE_UPDATE_BY_EXAMPLE )
2156         bUpdateByExampleDisabled = bDisable;
2157 
2158     EnableItem(nId, bEnable);
2159 }
2160 
2161 VclPtr<PopupMenu> const & SfxCommonTemplateDialog_Impl::CreateContextMenu()
2162 {
2163     if ( bBindingUpdate )
2164     {
2165         pBindings->Invalidate( SID_STYLE_NEW, true );
2166         pBindings->Update( SID_STYLE_NEW );
2167         bBindingUpdate = false;
2168     }
2169     mxMenu.disposeAndClear();
2170     mxBuilder.reset(new VclBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "sfx/ui/stylecontextmenu.ui", ""));
2171     mxMenu.set(mxBuilder->get_menu("menu"));
2172     mxMenu->SetMenuFlags(MenuFlags::AlwaysShowDisabledEntries);
2173     mxMenu->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, MenuSelectHdl ) );
2174     mxMenu->EnableItem(mxMenu->GetItemId("edit"), bCanEdit);
2175     mxMenu->EnableItem(mxMenu->GetItemId("delete"), bCanDel);
2176     mxMenu->EnableItem(mxMenu->GetItemId("new"), bCanNew);
2177     mxMenu->EnableItem(mxMenu->GetItemId("hide"), bCanHide);
2178     mxMenu->EnableItem(mxMenu->GetItemId("show"), bCanShow);
2179 
2180     const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
2181     if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
2182     {
2183         mxMenu->EnableItem(mxMenu->GetItemId("edit"), false);
2184         mxMenu->EnableItem(mxMenu->GetItemId("new"), false);
2185     }
2186 
2187     return mxMenu;
2188 }
2189 
2190 SfxTemplateDialog_Impl::SfxTemplateDialog_Impl(SfxBindings* pB, SfxTemplatePanelControl* pDlgWindow)
2191     : SfxCommonTemplateDialog_Impl(pB, pDlgWindow)
2192     , m_pFloat(pDlgWindow)
2193     , m_aActionTbL(VclPtrInstance<DropToolBox_Impl>(pDlgWindow, this))
2194     , m_aActionTbR(VclPtrInstance<ToolBox>(pDlgWindow))
2195 {
2196     m_aActionTbR->InsertItem(SID_STYLE_WATERCAN, Image(StockImage::Yes, RID_SFXBMP_WATERCAN), SfxResId(STR_STYLE_FILL_FORMAT_MODE));
2197     m_aActionTbR->SetHelpId(SID_STYLE_WATERCAN, HID_TEMPLDLG_WATERCAN);
2198 
2199     m_aActionTbR->InsertItem(SID_STYLE_NEW_BY_EXAMPLE, Image(StockImage::Yes, RID_SFXBMP_NEW_BY_EXAMPLE), SfxResId(STR_STYLE_NEW_STYLE_FROM_SELECTION));
2200     //renamed to SID_STYLE_NEW_BY_EXAMPLE in SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
2201     m_aActionTbR->SetHelpId(SID_STYLE_NEW_BY_EXAMPLE, HID_TEMPLDLG_NEWBYEXAMPLE);
2202 
2203     m_aActionTbR->InsertItem(SID_STYLE_UPDATE_BY_EXAMPLE, Image(StockImage::Yes, RID_SFXBMP_UPDATE_BY_EXAMPLE), SfxResId(STR_STYLE_UPDATE_STYLE));
2204     m_aActionTbR->SetHelpId(SID_STYLE_UPDATE_BY_EXAMPLE, HID_TEMPLDLG_UPDATEBYEXAMPLE);
2205 
2206     Initialize();
2207 }
2208 
2209 void SfxTemplateDialog_Impl::Initialize()
2210 {
2211     SfxCommonTemplateDialog_Impl::Initialize();
2212 
2213     m_aActionTbL->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxLSelect));
2214     m_aActionTbR->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxRSelect));
2215     m_aActionTbR->SetDropdownClickHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxRClick));
2216     m_aActionTbL->Show();
2217     m_aActionTbR->Show();
2218     vcl::Font aFont = aFilterLb->GetFont();
2219     aFont.SetWeight( WEIGHT_NORMAL );
2220     aFilterLb->SetFont( aFont );
2221     m_aActionTbL->SetHelpId( HID_TEMPLDLG_TOOLBOX_LEFT );
2222 }
2223 
2224 void SfxTemplateDialog_Impl::EnableFamilyItem( sal_uInt16 nId, bool bEnable )
2225 {
2226     m_aActionTbL->EnableItem( nId, bEnable );
2227 }
2228 
2229 // Insert element into dropdown filter "Frame Styles", "List Styles", etc.
2230 void SfxTemplateDialog_Impl::InsertFamilyItem(sal_uInt16 nId,const SfxStyleFamilyItem &rItem)
2231 {
2232     OString sHelpId;
2233     switch( rItem.GetFamily() )
2234     {
2235         case SfxStyleFamily::Char:     sHelpId = ".uno:CharStyle"; break;
2236         case SfxStyleFamily::Para:     sHelpId = ".uno:ParaStyle"; break;
2237         case SfxStyleFamily::Frame:    sHelpId = ".uno:FrameStyle"; break;
2238         case SfxStyleFamily::Page:     sHelpId = ".uno:PageStyle"; break;
2239         case SfxStyleFamily::Pseudo:   sHelpId = ".uno:ListStyle"; break;
2240         case SfxStyleFamily::Table:   sHelpId = ".uno:TableStyle"; break;
2241         default: OSL_FAIL("unknown StyleFamily"); break;
2242     }
2243     m_aActionTbL->InsertItem( nId, rItem.GetImage(), rItem.GetText(), ToolBoxItemBits::NONE, 0);
2244     m_aActionTbL->SetHelpId( nId, sHelpId );
2245 }
2246 
2247 void SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
2248 {
2249     m_aActionTbR->HideItem(SID_STYLE_UPDATE_BY_EXAMPLE);
2250     m_aActionTbR->SetItemBits( SID_STYLE_NEW_BY_EXAMPLE,
2251             ToolBoxItemBits::DROPDOWNONLY|m_aActionTbR->GetItemBits( SID_STYLE_NEW_BY_EXAMPLE ));
2252     //rename menu in case of Writer
2253     m_aActionTbR->SetItemText(SID_STYLE_NEW_BY_EXAMPLE, SfxResId(STR_STYLE_NEW_STYLE_ACTION));
2254 }
2255 
2256 void SfxTemplateDialog_Impl::ClearFamilyList()
2257 {
2258     m_aActionTbL->Clear();
2259 }
2260 
2261 void SfxCommonTemplateDialog_Impl::InvalidateBindings()
2262 {
2263     pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
2264     pBindings->Update( SID_STYLE_NEW_BY_EXAMPLE );
2265     pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
2266     pBindings->Update( SID_STYLE_UPDATE_BY_EXAMPLE );
2267     pBindings->Invalidate( SID_STYLE_WATERCAN, true);
2268     pBindings->Update( SID_STYLE_WATERCAN );
2269     pBindings->Invalidate( SID_STYLE_NEW, true);
2270     pBindings->Update( SID_STYLE_NEW );
2271     pBindings->Invalidate( SID_STYLE_DRAGHIERARCHIE, true);
2272     pBindings->Update( SID_STYLE_DRAGHIERARCHIE );
2273 }
2274 
2275 SfxTemplateDialog_Impl::~SfxTemplateDialog_Impl()
2276 {
2277     m_pFloat.clear();
2278     m_aActionTbL.disposeAndClear();
2279     m_aActionTbR.disposeAndClear();
2280 }
2281 
2282 void SfxTemplateDialog_Impl::LoadedFamilies()
2283 {
2284     Resize();
2285 }
2286 
2287 // Override Resize-Handler ( StarView )
2288 // The size of the Listboxen is adjusted
2289 void SfxTemplateDialog_Impl::Resize()
2290 {
2291     if (m_pFloat == nullptr)
2292         return;
2293     Size aDlgSize=m_pFloat->PixelToLogic(m_pFloat->GetOutputSizePixel());
2294     Size aSizeATL=m_pFloat->PixelToLogic(m_aActionTbL->CalcWindowSizePixel());
2295     Size aSizeATR=m_pFloat->PixelToLogic(m_aActionTbR->CalcWindowSizePixel());
2296     Size aMinSize = GetMinOutputSizePixel();
2297 
2298     long nListHeight = m_pFloat->PixelToLogic( aFilterLb->GetSizePixel() ).Height();
2299     long nWidth = aDlgSize.Width()- 2 * SFX_TEMPLDLG_HFRAME;
2300 
2301     m_aActionTbL->SetPosSizePixel(m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME,SFX_TEMPLDLG_VTOPFRAME)),
2302                                  m_pFloat->LogicToPixel(aSizeATL));
2303 
2304     // only change the position of the right toolbox, when the window is wide
2305     // enough
2306     Point aPosATR(aDlgSize.Width()-SFX_TEMPLDLG_HFRAME-aSizeATR.Width(),SFX_TEMPLDLG_VTOPFRAME);
2307     if(aDlgSize.Width() >= aMinSize.Width())
2308         m_aActionTbR->SetPosPixel(m_pFloat->LogicToPixel(aPosATR));
2309     else
2310         m_aActionTbR->SetPosPixel( m_pFloat->LogicToPixel(
2311             Point( SFX_TEMPLDLG_HFRAME + aSizeATL.Width() + SFX_TEMPLDLG_MIDHSPACE,
2312                    SFX_TEMPLDLG_VTOPFRAME ) ) );
2313 
2314     m_aActionTbR->SetSizePixel(m_pFloat->LogicToPixel(aSizeATR));
2315 
2316     Point aFilterPos(
2317         m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME,
2318             aDlgSize.Height()-SFX_TEMPLDLG_VBOTFRAME-nListHeight)) );
2319 
2320     Size aFilterSize(
2321         m_pFloat->LogicToPixel(Size(nWidth,SFX_TEMPLDLG_FILTERHEIGHT)) );
2322 
2323     Point aCheckBoxPos(
2324         m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME,
2325             aDlgSize.Height()-SFX_TEMPLDLG_VBOTFRAME-2*nListHeight)) );
2326 
2327     Size aCheckBoxSize(
2328         m_pFloat->LogicToPixel(Size(nWidth, nListHeight)) );
2329 
2330     Point aFmtPos(
2331         m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME, SFX_TEMPLDLG_VTOPFRAME +
2332                             SFX_TEMPLDLG_MIDVSPACE+aSizeATL.Height())) );
2333     Size aFmtSize(
2334         m_pFloat->LogicToPixel(Size(nWidth,
2335                     aDlgSize.Height() - SFX_TEMPLDLG_VBOTFRAME -
2336                     SFX_TEMPLDLG_VTOPFRAME - 2*SFX_TEMPLDLG_MIDVSPACE-
2337                     2*nListHeight-aSizeATL.Height())) );
2338 
2339     // only change the position of the listbox, when the window is high enough
2340     if(aDlgSize.Height() >= aMinSize.Height())
2341     {
2342         aFilterLb->SetPosPixel(aFilterPos);
2343         aFmtLb->SetPosPixel( aFmtPos );
2344         aPreviewCheckbox->SetPosPixel(aCheckBoxPos);
2345         if(pTreeBox->IsVisible())
2346             pTreeBox->SetPosPixel(aFmtPos);
2347     }
2348     else
2349         aFmtSize.AdjustHeight(aFilterSize.Height() );
2350 
2351     aFilterLb->SetSizePixel(aFilterSize);
2352     aFmtLb->SetSizePixel( aFmtSize );
2353     aPreviewCheckbox->SetSizePixel( aCheckBoxSize );
2354     if(pTreeBox->IsVisible())
2355         pTreeBox->SetSizePixel(aFmtSize);
2356 }
2357 
2358 Size SfxTemplateDialog_Impl::GetMinOutputSizePixel()
2359 {
2360     if (m_pFloat != nullptr)
2361     {
2362         Size aSizeATL=m_pFloat->PixelToLogic(m_aActionTbL->CalcWindowSizePixel());
2363         Size aSizeATR=m_pFloat->PixelToLogic(m_aActionTbR->CalcWindowSizePixel());
2364         Size aMinSize(
2365             aSizeATL.Width()+aSizeATR.Width()+
2366                 2*SFX_TEMPLDLG_HFRAME + SFX_TEMPLDLG_MIDHSPACE,
2367             4*aSizeATL.Height()+2*SFX_TEMPLDLG_MIDVSPACE);
2368         return aMinSize;
2369     }
2370     else
2371         return Size(0,0);
2372 }
2373 
2374 void SfxTemplateDialog_Impl::EnableItem(sal_uInt16 nMesId, bool bCheck)
2375 {
2376     switch(nMesId)
2377     {
2378         case SID_STYLE_WATERCAN :
2379             if(!bCheck && IsCheckedItem(SID_STYLE_WATERCAN))
2380                 Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
2381             [[fallthrough]];
2382         case SID_STYLE_NEW_BY_EXAMPLE:
2383         case SID_STYLE_UPDATE_BY_EXAMPLE:
2384             m_aActionTbR->EnableItem(nMesId,bCheck);
2385             break;
2386     }
2387 }
2388 
2389 void SfxTemplateDialog_Impl::CheckItem(sal_uInt16 nMesId, bool bCheck)
2390 {
2391     switch(nMesId)
2392     {
2393         case SID_STYLE_WATERCAN :
2394             bIsWater=bCheck;
2395             m_aActionTbR->CheckItem(SID_STYLE_WATERCAN,bCheck);
2396             break;
2397         default:
2398             m_aActionTbL->CheckItem(nMesId,bCheck); break;
2399     }
2400 }
2401 
2402 bool SfxTemplateDialog_Impl::IsCheckedItem(sal_uInt16 nMesId)
2403 {
2404     switch(nMesId)
2405     {
2406         case SID_STYLE_WATERCAN :
2407             return m_aActionTbR->GetItemState(SID_STYLE_WATERCAN)==TRISTATE_TRUE;
2408         default:
2409             return m_aActionTbL->GetItemState(nMesId)==TRISTATE_TRUE;
2410     }
2411 }
2412 
2413 IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxLSelect, ToolBox *, pBox, void )
2414 {
2415     const sal_uInt16 nEntry = pBox->GetCurItemId();
2416     FamilySelect(nEntry);
2417 }
2418 
2419 IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxRSelect, ToolBox *, pBox, void )
2420 {
2421     const sal_uInt16 nEntry = pBox->GetCurItemId();
2422     if(nEntry != SID_STYLE_NEW_BY_EXAMPLE ||
2423             ToolBoxItemBits::DROPDOWN != (pBox->GetItemBits(nEntry)&ToolBoxItemBits::DROPDOWN))
2424         ActionSelect(nEntry);
2425 }
2426 
2427 IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxRClick, ToolBox *, pBox, void )
2428 {
2429     const sal_uInt16 nEntry = pBox->GetCurItemId();
2430     if(nEntry != SID_STYLE_NEW_BY_EXAMPLE ||
2431             !(pBox->GetItemBits(nEntry) & ToolBoxItemBits::DROPDOWN))
2432         return;
2433 
2434     //create a popup menu in Writer
2435     ScopedVclPtrInstance<PopupMenu> pMenu;
2436     OUString sTextDoc("com.sun.star.text.TextDocument");
2437 
2438     auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:StyleNewByExample", sTextDoc);
2439     OUString sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
2440     pMenu->InsertItem( SID_STYLE_NEW_BY_EXAMPLE, sLabel );
2441     pMenu->SetHelpId(SID_STYLE_NEW_BY_EXAMPLE, HID_TEMPLDLG_NEWBYEXAMPLE);
2442 
2443     aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:StyleUpdateByExample", sTextDoc);
2444     sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
2445     pMenu->InsertItem( SID_STYLE_UPDATE_BY_EXAMPLE, sLabel );
2446     pMenu->SetHelpId(SID_STYLE_UPDATE_BY_EXAMPLE, HID_TEMPLDLG_UPDATEBYEXAMPLE);
2447 
2448     pMenu->InsertSeparator();
2449 
2450     aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:LoadStyles", sTextDoc);
2451     sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
2452     pMenu->InsertItem( SID_TEMPLATE_LOAD, sLabel );
2453     pMenu->SetHelpId(SID_TEMPLATE_LOAD, ".uno:LoadStyles");
2454 
2455     pMenu->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, MenuSelectHdl));
2456     pMenu->Execute( pBox,
2457                     pBox->GetItemRect(nEntry),
2458                     PopupMenuFlags::ExecuteDown );
2459     pBox->EndSelection();
2460     pBox->Invalidate();
2461 }
2462 
2463 IMPL_LINK( SfxTemplateDialog_Impl, MenuSelectHdl, Menu*, pMenu, bool)
2464 {
2465     sal_uInt16 nMenuId = pMenu->GetCurItemId();
2466     ActionSelect(nMenuId);
2467     return false;
2468 }
2469 
2470 void SfxCommonTemplateDialog_Impl::SetFamily(SfxStyleFamily const nFamily)
2471 {
2472     sal_uInt16 const nId(SfxTemplate::SfxFamilyIdToNId(nFamily));
2473     assert((0 < nId && nId <= MAX_FAMILIES) || 0xffff == nId);
2474     if ( nId != nActFamily )
2475     {
2476         if ( nActFamily != 0xFFFF )
2477             CheckItem( nActFamily, false );
2478         nActFamily = nId;
2479         if ( nId != 0xFFFF )
2480             bUpdateFamily = true;
2481     }
2482 }
2483 
2484 void SfxCommonTemplateDialog_Impl::UpdateFamily_Impl()
2485 {
2486     bUpdateFamily = false;
2487 
2488     SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl();
2489     SfxViewFrame *pViewFrame = pDispat->GetFrame();
2490     SfxObjectShell *pDocShell = pViewFrame->GetObjectShell();
2491 
2492     SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool;
2493     pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr;
2494     if ( pOldStyleSheetPool != pStyleSheetPool )
2495     {
2496         if ( pOldStyleSheetPool )
2497             EndListening(*pOldStyleSheetPool);
2498         if ( pStyleSheetPool )
2499             StartListening(*pStyleSheetPool);
2500     }
2501 
2502     bWaterDisabled = false;
2503     bCanNew = pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1;
2504     bTreeDrag = true;
2505     bUpdateByExampleDisabled = false;
2506 
2507     if (pStyleSheetPool)
2508     {
2509         if (!pTreeBox->IsVisible())
2510             UpdateStyles_Impl(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
2511         else
2512         {
2513             UpdateStyles_Impl(StyleFlags::UpdateFamily);
2514             FillTreeBox();
2515         }
2516     }
2517 
2518     InvalidateBindings();
2519 
2520     if (IsCheckedItem(SID_STYLE_WATERCAN) &&
2521          // only if that area is allowed
2522          nullptr != pFamilyState[nActFamily - 1])
2523     {
2524         Execute_Impl(SID_STYLE_APPLY,
2525                      GetSelectedEntry(),
2526                      OUString(),
2527                      static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
2528     }
2529 }
2530 
2531 void SfxCommonTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
2532 {
2533     //does nothing
2534 }
2535 
2536 DropToolBox_Impl::DropToolBox_Impl(vcl::Window* pParent, SfxTemplateDialog_Impl* pTemplateDialog) :
2537     ToolBox(pParent),
2538     DropTargetHelper(this),
2539     rParent(*pTemplateDialog)
2540 {
2541 }
2542 
2543 sal_Int8 DropToolBox_Impl::AcceptDrop( const AcceptDropEvent& rEvt )
2544 {
2545     sal_Int8 nReturn = DND_ACTION_NONE;
2546     sal_uInt16 nItemId = GetItemId( rEvt.maPosPixel );
2547     if(USHRT_MAX != nItemId && !IsItemChecked( nItemId ))
2548     {
2549         SetCurItemId(nItemId);
2550         GetSelectHdl().Call(this);
2551     }
2552     // special case: page styles are allowed to create new styles by example
2553     // but not allowed to be created by drag and drop
2554     if ( nItemId != SfxTemplate::SfxFamilyIdToNId( SfxStyleFamily::Page )&&
2555         IsDropFormatSupported( SotClipboardFormatId::OBJECTDESCRIPTOR ) &&
2556         !rParent.bNewByExampleDisabled )
2557     {
2558         nReturn = DND_ACTION_COPY;
2559     }
2560     return nReturn;
2561 }
2562 
2563 sal_Int8 DropToolBox_Impl::ExecuteDrop( const ExecuteDropEvent& rEvt )
2564 {
2565      return rParent.aFmtLb->ExecuteDrop(rEvt);
2566 }
2567 
2568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2569