cid#1636690 Dereference after null check
[LibreOffice.git] / sfx2 / source / dialog / templdlg.cxx
blob09e320e05357efa20290b68cb84904d906191e42
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
22 #include <vcl/commandinfoprovider.hxx>
23 #include <svl/intitem.hxx>
24 #include <svl/stritem.hxx>
25 #include <svl/style.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/propertyvalue.hxx>
28 #include <comphelper/sequenceashashmap.hxx>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/frame/ModuleManager.hpp>
31 #include <com/sun/star/frame/UnknownModuleException.hpp>
32 #include <officecfg/Office/Common.hxx>
34 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
36 #include <comphelper/diagnose_ex.hxx>
37 #include <sfx2/app.hxx>
38 #include <sfx2/dispatch.hxx>
39 #include <sfx2/bindings.hxx>
40 #include <sfx2/templdlg.hxx>
41 #include <templdgi.hxx>
42 #include <sfx2/styfitem.hxx>
43 #include <sfx2/objsh.hxx>
44 #include <sfx2/tplpitem.hxx>
45 #include <sfx2/sfxresid.hxx>
46 #include <svl/itemset.hxx>
48 #include <sfx2/sfxsids.hrc>
49 #include <sfx2/strings.hrc>
50 #include <helpids.h>
51 #include <sfx2/viewfrm.hxx>
53 using namespace css;
54 using namespace css::beans;
55 using namespace css::frame;
56 using namespace css::uno;
58 class SfxCommonTemplateDialog_Impl::DeletionWatcher
60 typedef void (DeletionWatcher::* bool_type)();
62 public:
63 explicit DeletionWatcher(SfxCommonTemplateDialog_Impl& rDialog)
64 : m_pDialog(&rDialog)
65 , m_pPrevious(m_pDialog->impl_setDeletionWatcher(this))
69 ~DeletionWatcher()
71 if (m_pDialog)
72 m_pDialog->impl_setDeletionWatcher(m_pPrevious);
75 DeletionWatcher(const DeletionWatcher&) = delete;
76 DeletionWatcher& operator=(const DeletionWatcher&) = delete;
78 // Signal that the dialog was deleted
79 void signal()
81 m_pDialog = nullptr;
82 if (m_pPrevious)
83 m_pPrevious->signal();
86 // Return true if the dialog was deleted
87 operator bool_type() const
89 return m_pDialog ? nullptr : &DeletionWatcher::signal;
92 private:
93 SfxCommonTemplateDialog_Impl* m_pDialog;
94 DeletionWatcher *const m_pPrevious; /// let's add more epicycles!
97 sal_Int8 SfxCommonTemplateDialog_Impl::ExecuteDrop(const ExecuteDropEvent& rEvt)
99 // handle drop of content into the treeview to create a new style
100 m_aStyleListExecuteDrop.Call(rEvt);
101 return DND_ACTION_NONE;
104 IMPL_LINK(SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop, void*, pStyleList, void)
106 StyleList* pStyle = static_cast<StyleList*>(pStyleList);
107 if (pStyle == &m_aStyleList)
108 ActionSelect(u"new"_ustr, m_aStyleList);
111 namespace SfxTemplate
113 // converts from SFX_STYLE_FAMILY Ids to 1-6
114 static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
116 switch ( nFamily )
118 case SfxStyleFamily::Char: return 1;
119 case SfxStyleFamily::Para: return 2;
120 case SfxStyleFamily::Frame: return 3;
121 case SfxStyleFamily::Page: return 4;
122 case SfxStyleFamily::Pseudo: return 5;
123 case SfxStyleFamily::Table: return 6;
124 default: return 0xffff;
127 // converts from 1-6 to SFX_STYLE_FAMILY Ids
128 static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
130 switch (nId)
132 case 1:
133 return SfxStyleFamily::Char;
134 case 2:
135 return SfxStyleFamily::Para;
136 case 3:
137 return SfxStyleFamily::Frame;
138 case 4:
139 return SfxStyleFamily::Page;
140 case 5:
141 return SfxStyleFamily::Pseudo;
142 case 6:
143 return SfxStyleFamily::Table;
144 default:
145 return SfxStyleFamily::All;
150 SfxTemplatePanelControl::SfxTemplatePanelControl(SfxBindings* pBindings, weld::Widget* pParent)
151 : PanelLayout(pParent, u"TemplatePanel"_ustr, u"sfx/ui/templatepanel.ui"_ustr)
152 , m_aSpotlightParaStyles(SID_SPOTLIGHT_PARASTYLES, *pBindings, *this)
153 , m_aSpotlightCharStyles(SID_SPOTLIGHT_CHARSTYLES, *pBindings, *this)
154 , pImpl(new SfxTemplateDialog_Impl(pBindings, this))
156 OSL_ASSERT(pBindings!=nullptr);
159 SfxTemplatePanelControl::~SfxTemplatePanelControl()
161 m_aSpotlightParaStyles.dispose();
162 m_aSpotlightCharStyles.dispose();
165 void SfxTemplatePanelControl::NotifyItemUpdate(const sal_uInt16 nSId, const SfxItemState eState,
166 const SfxPoolItem* pState)
168 switch (nSId)
170 case SID_SPOTLIGHT_PARASTYLES:
171 if (eState >= SfxItemState::DEFAULT)
173 const SfxBoolItem* pItem = dynamic_cast<const SfxBoolItem*>(pState);
174 if (pItem)
176 bool bValue = pItem->GetValue();
177 if (bValue || (!bValue && pImpl->m_aStyleList.IsHighlightParaStyles()))
179 pImpl->m_aStyleList.SetHighlightParaStyles(bValue);
180 pImpl->FamilySelect(SfxTemplate::SfxFamilyIdToNId(SfxStyleFamily::Para),
181 pImpl->m_aStyleList, true);
185 break;
186 case SID_SPOTLIGHT_CHARSTYLES:
187 if (eState >= SfxItemState::DEFAULT)
189 const SfxBoolItem* pItem = dynamic_cast<const SfxBoolItem*>(pState);
190 if (pItem)
192 bool bValue = pItem->GetValue();
193 if (bValue || (!bValue && pImpl->m_aStyleList.IsHighlightCharStyles()))
195 pImpl->m_aStyleList.SetHighlightCharStyles(bValue);
196 pImpl->FamilySelect(SfxTemplate::SfxFamilyIdToNId(SfxStyleFamily::Char),
197 pImpl->m_aStyleList, true);
201 break;
205 void SfxCommonTemplateDialog_Impl::connect_stylelist_execute_drop(
206 const Link<const ExecuteDropEvent&, sal_Int8>& rLink)
208 m_aStyleListExecuteDrop = rLink;
211 void SfxCommonTemplateDialog_Impl::connect_stylelist_has_selected_style(const Link<void*, bool>& rLink)
213 m_aStyleListHasSelectedStyle = rLink;
216 void SfxCommonTemplateDialog_Impl::connect_stylelist_update_style_dependents(const Link<void*, void>& rLink)
218 m_aStyleListUpdateStyleDependents = rLink;
221 void SfxCommonTemplateDialog_Impl::connect_stylelist_enable_tree_drag(const Link<bool, void> rLink)
223 m_aStyleListEnableTreeDrag = rLink;
226 void SfxCommonTemplateDialog_Impl::connect_stylelist_enable_delete(const Link<void*, void> rLink)
228 m_aStyleListEnableDelete = rLink;
231 void SfxCommonTemplateDialog_Impl::connect_stylelist_set_water_can_state(
232 const Link<const SfxBoolItem*, void> rLink)
234 m_aStyleListSetWaterCanState = rLink;
237 // Constructor
239 SfxCommonTemplateDialog_Impl::SfxCommonTemplateDialog_Impl(SfxBindings* pB, weld::Container* pC, weld::Builder* pBuilder)
240 : pBindings(pB)
241 , xModuleManager(frame::ModuleManager::create(::comphelper::getProcessComponentContext()))
242 , m_pDeletionWatcher(nullptr)
243 , m_aStyleList(pBuilder, pB, this, pC, u"treeview"_ustr, u"flatview"_ustr)
244 , mxPreviewCheckbox(pBuilder->weld_check_button(u"showpreview"_ustr))
245 , mxHighlightCheckbox(pBuilder->weld_check_button(u"highlightstyles"_ustr))
246 , mxFilterLb(pBuilder->weld_combo_box(u"filter"_ustr))
247 , nActFamily(0xffff)
248 , nActFilter(0)
249 , bIsWater(false)
250 , bUpdate(false)
251 , bWaterDisabled(false)
252 , bNewByExampleDisabled(false)
253 , bUpdateByExampleDisabled(false)
254 , m_bWantHierarchical(false)
256 mxFilterLb->set_help_id(HID_TEMPLATE_FILTER);
257 mxPreviewCheckbox->set_active(officecfg::Office::Common::StylesAndFormatting::Preview::get());
260 void SfxTemplateDialog_Impl::EnableEdit(bool bEnable, StyleList* rStyleList)
262 if(rStyleList == &m_aStyleList || rStyleList == nullptr)
263 SfxCommonTemplateDialog_Impl::EnableEdit( bEnable, &m_aStyleList );
264 if( !bEnable || !bUpdateByExampleDisabled )
265 EnableItem(u"update"_ustr, bEnable);
268 IMPL_LINK(SfxCommonTemplateDialog_Impl, ReadResource_Hdl, StyleList&, rStyleList, void)
270 nActFilter = 0xffff;
272 SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
273 SfxObjectShell* pCurObjShell = pViewFrame->GetObjectShell();
274 if (pCurObjShell)
276 nActFilter = static_cast<sal_uInt16>(LoadFactoryStyleFilter_Hdl(pCurObjShell));
277 if (0xffff == nActFilter)
279 nActFilter = pCurObjShell->GetAutoStyleFilterIndex();
283 size_t nCount = m_aStyleListReadResource.Call(nullptr);
285 // Insert in the reverse order of occurrence in the Style Families. This is for
286 // the toolbar of the designer. The list box of the catalog respects the
287 // correct order by itself.
289 // Sequences: the order of Resource = the order of Toolbar for example list box.
290 // Order of ascending SIDs: Low SIDs are displayed first when templates of
291 // several families are active.
293 // in the Writer the UpdateStyleByExample Toolbox button is removed and
294 // the NewStyle button gets a PopupMenu
295 if(nCount > 4)
296 ReplaceUpdateButtonByMenu();
298 while (nCount)
300 --nCount;
301 const SfxStyleFamilyItem &rItem = rStyleList.GetFamilyItemByIndex( nCount );
302 sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId( rItem.GetFamily() );
303 InsertFamilyItem(nId, rItem);
307 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, ClearResource_Hdl, void*, void)
309 ClearFamilyList();
310 m_aStyleListClear.Call(nullptr);
313 SfxCommonTemplateDialog_Impl::DeletionWatcher *
314 SfxCommonTemplateDialog_Impl::impl_setDeletionWatcher(
315 DeletionWatcher *const pNewWatcher)
317 DeletionWatcher *const pRet(m_pDeletionWatcher);
318 m_pDeletionWatcher = pNewWatcher;
319 return pRet;
322 void SfxCommonTemplateDialog_Impl::Initialize()
324 m_aStyleList.connect_ReadResource(LINK(this, SfxCommonTemplateDialog_Impl, ReadResource_Hdl));
325 m_aStyleList.connect_ClearResource(LINK(this, SfxCommonTemplateDialog_Impl, ClearResource_Hdl));
326 m_aStyleList.connect_LoadFactoryStyleFilter(LINK(this, SfxCommonTemplateDialog_Impl, LoadFactoryStyleFilter_Hdl));
327 m_aStyleList.connect_SaveSelection(LINK(this, SfxCommonTemplateDialog_Impl, SaveSelection_Hdl));
328 m_aStyleList.connect_UpdateFamily(LINK(this, SfxCommonTemplateDialog_Impl, UpdateFamily_Hdl));
329 m_aStyleList.connect_UpdateStyles(LINK(this, SfxCommonTemplateDialog_Impl, UpdateStyles_Hdl));
331 mxFilterLb->connect_changed(LINK(this, SfxCommonTemplateDialog_Impl, FilterSelectHdl));
332 mxPreviewCheckbox->connect_toggled(LINK(this, SfxCommonTemplateDialog_Impl, PreviewHdl));
333 mxHighlightCheckbox->connect_toggled(LINK(this, SfxCommonTemplateDialog_Impl, HighlightHdl));
335 m_aStyleList.Initialize();
337 SfxStyleFamily eFam = SfxTemplate::NIdToSfxFamilyId(nActFamily);
338 mxHighlightCheckbox->set_visible(m_aStyleList.HasStylesHighlighterFeature()
339 && (eFam == SfxStyleFamily::Para || eFam == SfxStyleFamily::Char));
342 IMPL_LINK(SfxCommonTemplateDialog_Impl, UpdateStyles_Hdl, StyleFlags, nFlags, void)
344 const SfxStyleFamilyItem* pItem = m_aStyleList.GetFamilyItem();
346 if (nFlags & StyleFlags::UpdateFamily) // Update view type list (Hierarchical, All, etc.
348 CheckItem(OUString::number(nActFamily)); // check Button in Toolbox
350 mxFilterLb->freeze();
351 mxFilterLb->clear();
353 //insert hierarchical at the beginning
354 mxFilterLb->append(OUString::number(static_cast<int>(SfxStyleSearchBits::All)),
355 SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
356 const SfxStyleFilter& rFilter = pItem->GetFilterList();
357 for (const SfxFilterTuple& i : rFilter)
358 mxFilterLb->append(OUString::number(static_cast<int>(i.nFlags)), i.aName);
359 mxFilterLb->thaw();
361 if (nActFilter < mxFilterLb->get_count() - 1)
362 mxFilterLb->set_active(nActFilter + 1);
363 else
365 nActFilter = 0;
366 m_aStyleList.FilterSelect(nActFilter, false);
367 mxFilterLb->set_active(1);
370 // if the tree view again, select family hierarchy
371 if (m_aStyleList.IsTreeView() || m_bWantHierarchical)
373 mxFilterLb->set_active_text(SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
374 EnableHierarchical(true, m_aStyleList);
377 else
379 if (nActFilter < mxFilterLb->get_count() - 1)
380 mxFilterLb->set_active(nActFilter + 1);
381 else
383 nActFilter = 0;
384 m_aStyleList.FilterSelect(nActFilter, false);
385 mxFilterLb->set_active(1);
389 if (!(nFlags & StyleFlags::UpdateFamilyList))
390 return;
392 EnableItem(u"watercan"_ustr, false);
395 SfxCommonTemplateDialog_Impl::~SfxCommonTemplateDialog_Impl()
397 // Set the UNO's in an 'off' state. FN_PARAM_1 is used to prevent the sidebar from trying to
398 // reopen while it is being closed here.
399 if (m_aStyleList.IsHighlightParaStyles())
401 SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl();
402 SfxFlagItem aParam(FN_PARAM_1);
403 rDispatcher.ExecuteList(SID_SPOTLIGHT_PARASTYLES, SfxCallMode::SYNCHRON, { &aParam });
405 if (m_aStyleList.IsHighlightCharStyles())
407 SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl();
408 SfxFlagItem aParam(FN_PARAM_1);
409 rDispatcher.ExecuteList(SID_SPOTLIGHT_CHARSTYLES, SfxCallMode::SYNCHRON, { &aParam });
412 if ( bIsWater )
413 Execute_Impl(SID_STYLE_WATERCAN, u""_ustr, u""_ustr, 0, m_aStyleList);
414 m_aStyleListClear.Call(nullptr);
415 m_aStyleListCleanup.Call(nullptr);
416 if ( m_pDeletionWatcher )
417 m_pDeletionWatcher->signal();
418 mxPreviewCheckbox.reset();
419 mxFilterLb.reset();
423 * Is it safe to show the water-can / fill icon. If we've a
424 * hierarchical widget - we have only single select, otherwise
425 * we need to check if we have a multi-selection. We either have
426 * a mxTreeBox showing or an mxFmtLb (which we hide when not shown)
428 bool SfxCommonTemplateDialog_Impl::IsSafeForWaterCan() const
430 return m_aStyleListWaterCan.Call(nullptr);
433 void SfxCommonTemplateDialog_Impl::SelectStyle(const OUString &rStr, bool bIsCallback, StyleList& rStyleList)
435 rStyleList.SelectStyle(rStr, bIsCallback);
437 bWaterDisabled = !IsSafeForWaterCan();
439 // tdf#134598 call UpdateStyleDependents to update watercan
440 UpdateStyleDependents_Hdl(nullptr);
443 void SfxCommonTemplateDialog_Impl::EnableTreeDrag(bool bEnable)
445 m_aStyleListEnableTreeDrag.Call(bEnable);
448 // Updated display: Watering the house
449 void SfxCommonTemplateDialog_Impl::SetWaterCanState(const SfxBoolItem *pItem)
451 bWaterDisabled = (pItem == nullptr);
453 if(!bWaterDisabled)
454 //make sure the watercan is only activated when there is (only) one selection
455 bWaterDisabled = !IsSafeForWaterCan();
457 if(pItem && !bWaterDisabled)
459 CheckItem(u"watercan"_ustr, pItem->GetValue());
460 EnableItem(u"watercan"_ustr);
462 else
464 if(!bWaterDisabled)
465 EnableItem(u"watercan"_ustr);
466 else
467 EnableItem(u"watercan"_ustr, false);
470 // Ignore while in watercan mode statusupdates
472 m_aStyleListSetWaterCanState.Call(pItem);
475 // Item with the status of a Family is copied and noted
476 // (is updated when all states have also been updated.)
477 // See also: <SfxBindings::AddDoneHdl(const Link &)>
478 void SfxCommonTemplateDialog_Impl::SetFamilyState( sal_uInt16 nSlotId, const SfxTemplateItem* pItem )
480 m_aStyleList.SetFamilyState(nSlotId, pItem);
481 bUpdate = true;
484 // Internal: Perform functions through the Dispatcher
485 bool SfxCommonTemplateDialog_Impl::Execute_Impl(
486 sal_uInt16 nId, const OUString &rStr, const OUString& rRefStr, sal_uInt16 nFamily, StyleList& rStyleList,
487 SfxStyleSearchBits nMask, sal_uInt16 *pIdx, const sal_uInt16* pModifier)
489 SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl();
490 SfxStringItem aItem(nId, rStr);
491 SfxUInt16Item aFamily(SID_STYLE_FAMILY, nFamily);
492 SfxUInt16Item aMask( SID_STYLE_MASK, static_cast<sal_uInt16>(nMask) );
493 SfxStringItem aUpdName(SID_STYLE_UPD_BY_EX_NAME, rStr);
494 SfxStringItem aRefName( SID_STYLE_REFERENCE, rRefStr );
495 const SfxPoolItem* pItems[ 6 ];
496 sal_uInt16 nCount = 0;
497 if( !rStr.isEmpty() )
498 pItems[ nCount++ ] = &aItem;
499 pItems[ nCount++ ] = &aFamily;
500 if( nMask != SfxStyleSearchBits::Auto )
501 pItems[ nCount++ ] = &aMask;
502 if(SID_STYLE_UPDATE_BY_EXAMPLE == nId)
504 // Special solution for Numbering update in Writer
505 const OUString aTemplName(rStyleList.GetSelectedEntry());
506 aUpdName.SetValue(aTemplName);
507 pItems[ nCount++ ] = &aUpdName;
510 if ( !rRefStr.isEmpty() )
511 pItems[ nCount++ ] = &aRefName;
513 pItems[ nCount++ ] = nullptr;
515 DeletionWatcher aDeleted(*this);
516 sal_uInt16 nModi = pModifier ? *pModifier : 0;
517 const SfxPoolItemHolder aResult(rDispatcher.Execute(
518 nId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
519 pItems, nModi));
521 // Dialog can be destroyed while in Execute() because started
522 // subdialogs are not modal to it (#i97888#).
523 if (!aResult || aDeleted )
524 return false;
526 if ((nId == SID_STYLE_NEW || SID_STYLE_EDIT == nId)
527 && rStyleList.EnableExecute())
529 const SfxUInt16Item* pFilterItem(dynamic_cast<const SfxUInt16Item*>(aResult.getItem()));
530 assert(pFilterItem);
531 SfxStyleSearchBits nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue()) & ~SfxStyleSearchBits::UserDefined;
532 if(nFilterFlags == SfxStyleSearchBits::Auto) // User Template?
533 nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue());
534 const SfxStyleFamilyItem *pFamilyItem = rStyleList.GetFamilyItem();
535 const size_t nFilterCount = pFamilyItem->GetFilterList().size();
537 for ( size_t i = 0; i < nFilterCount; ++i )
539 const SfxFilterTuple &rTupel = pFamilyItem->GetFilterList()[ i ];
541 if ( ( rTupel.nFlags & nFilterFlags ) == nFilterFlags && pIdx )
542 *pIdx = i;
546 return true;
549 // Handler Listbox of Filter
550 void SfxCommonTemplateDialog_Impl::EnableHierarchical(bool const bEnable, StyleList& rStyleList)
552 OUString aSelectedEntry = rStyleList.GetSelectedEntry();
553 if (bEnable)
555 if (!rStyleList.IsHierarchical())
557 // Turn on treeView
558 m_bWantHierarchical = true;
559 SaveSelection_Hdl(rStyleList); // fdo#61429 store "hierarchical"
560 m_aStyleList.SetHierarchical();
563 else
565 m_aStyleList.SetFilterControlsHandle();
566 // If bHierarchical, then the family can have changed
567 // minus one since hierarchical is inserted at the start
568 m_bWantHierarchical = false; // before FilterSelect
569 FilterSelect(mxFilterLb->get_active() - 1);
571 SelectStyle(aSelectedEntry, false, rStyleList);
574 // Other filters; can be switched by the users or as a result of new or
575 // editing, if the current document has been assigned a different filter.
576 void SfxCommonTemplateDialog_Impl::FilterSelect(
577 sal_uInt16 nEntry // Idx of the new Filters
580 nActFilter = nEntry;
581 m_aStyleList.FilterSelect(nActFilter, true);
584 void SfxCommonTemplateDialog_Impl::IsUpdate(StyleList&)
586 SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
587 SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
588 nActFilter = static_cast<sal_uInt16>(LoadFactoryStyleFilter_Hdl(pDocShell));
589 if (0xffff == nActFilter)
591 nActFilter = pDocShell->GetAutoStyleFilterIndex();
595 IMPL_LINK(SfxCommonTemplateDialog_Impl, FilterSelectHdl, weld::ComboBox&, rBox, void)
597 if (SfxResId(STR_STYLE_FILTER_HIERARCHICAL) == rBox.get_active_text())
599 EnableHierarchical(true, m_aStyleList);
601 else
603 EnableHierarchical(false, m_aStyleList);
607 // Select-Handler for the Toolbox
608 void SfxCommonTemplateDialog_Impl::FamilySelect(sal_uInt16 nEntry, StyleList&, bool bRefresh)
610 assert((0 < nEntry && nEntry <= MAX_FAMILIES) || 0xffff == nEntry);
611 if( nEntry != nActFamily || bRefresh )
613 CheckItem(OUString::number(nActFamily), false);
614 nActFamily = nEntry;
615 m_aStyleList.FamilySelect(nEntry, bRefresh);
617 SfxStyleFamily eFam = SfxTemplate::NIdToSfxFamilyId(nActFamily);
618 mxHighlightCheckbox->set_visible(m_aStyleList.HasStylesHighlighterFeature()
619 && (eFam == SfxStyleFamily::Para || eFam == SfxStyleFamily::Char));
620 if (mxHighlightCheckbox->is_visible())
622 bool bActive = false;
623 if (eFam == SfxStyleFamily::Para)
624 bActive = m_aStyleList.IsHighlightParaStyles();
625 else if (eFam == SfxStyleFamily::Char)
626 bActive = m_aStyleList.IsHighlightCharStyles();
627 mxHighlightCheckbox->set_active(bActive);
632 void SfxCommonTemplateDialog_Impl::ActionSelect(const OUString& rEntry, StyleList& rStyleList)
634 if (rEntry == "watercan")
636 const bool bOldState = !IsCheckedItem(rEntry);
637 bool bCheck;
638 SfxBoolItem aBool;
639 // when a template is chosen.
640 if (!bOldState && m_aStyleListHasSelectedStyle.Call(nullptr))
642 const OUString aTemplName(rStyleList.GetSelectedEntry());
643 Execute_Impl(SID_STYLE_WATERCAN, aTemplName, u""_ustr,
644 static_cast<sal_uInt16>(m_aStyleList.GetFamilyItem()->GetFamily()), rStyleList);
645 bCheck = true;
647 else
649 Execute_Impl(SID_STYLE_WATERCAN, u""_ustr, u""_ustr, 0, rStyleList);
650 bCheck = false;
652 CheckItem(rEntry, bCheck);
653 aBool.SetValue(bCheck);
654 SetWaterCanState(&aBool);
656 else if (rEntry == "new" || rEntry == "newmenu")
658 m_aStyleListNewMenu.Call(nullptr);
660 else if (rEntry == "update")
662 Execute_Impl(SID_STYLE_UPDATE_BY_EXAMPLE,
663 u""_ustr, u""_ustr,
664 static_cast<sal_uInt16>(m_aStyleList.GetFamilyItem()->GetFamily()), rStyleList);
666 else if (rEntry == "load")
667 SfxGetpApp()->GetDispatcher_Impl()->Execute(SID_TEMPLATE_LOAD);
668 else
669 SAL_WARN("sfx", "not implemented: " << rEntry);
672 static OUString getModuleIdentifier( const Reference< XModuleManager2 >& i_xModMgr, SfxObjectShell const * i_pObjSh )
674 assert(i_xModMgr.is() && "getModuleIdentifier(): no XModuleManager");
675 assert(i_pObjSh && "getModuleIdentifier(): no ObjectShell");
677 OUString sIdentifier;
681 sIdentifier = i_xModMgr->identify( i_pObjSh->GetModel() );
683 catch ( css::frame::UnknownModuleException& )
685 SAL_WARN("sfx", "getModuleIdentifier(): unknown module" );
687 catch ( Exception& )
689 TOOLS_WARN_EXCEPTION( "sfx", "getModuleIdentifier(): exception of XModuleManager::identify()" );
692 return sIdentifier;
695 IMPL_LINK(SfxCommonTemplateDialog_Impl, LoadFactoryStyleFilter_Hdl, SfxObjectShell const*, i_pObjSh, sal_Int32)
697 OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );
699 ::comphelper::SequenceAsHashMap aFactoryProps(
700 xModuleManager->getByName( getModuleIdentifier( xModuleManager, i_pObjSh ) ) );
701 sal_Int32 nFilter = aFactoryProps.getUnpackedValueOrDefault( u"ooSetupFactoryStyleFilter"_ustr, sal_Int32(-1) );
703 m_bWantHierarchical = (nFilter & 0x1000) != 0;
704 nFilter &= ~0x1000; // clear it
706 return nFilter;
709 void SfxCommonTemplateDialog_Impl::SaveFactoryStyleFilter( SfxObjectShell const * i_pObjSh, sal_Int32 i_nFilter )
711 OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );
712 Sequence< PropertyValue > lProps{ comphelper::makePropertyValue(
713 u"ooSetupFactoryStyleFilter"_ustr, i_nFilter | (m_bWantHierarchical ? 0x1000 : 0)) };
714 xModuleManager->replaceByName( getModuleIdentifier( xModuleManager, i_pObjSh ), Any( lProps ) );
717 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, SaveSelection_Hdl, StyleList&, SfxObjectShell*)
719 SfxViewFrame *const pViewFrame(pBindings->GetDispatcher_Impl()->GetFrame());
720 SfxObjectShell *const pDocShell(pViewFrame->GetObjectShell());
721 if (pDocShell)
723 pDocShell->SetAutoStyleFilterIndex(nActFilter);
724 SaveFactoryStyleFilter( pDocShell, nActFilter );
726 return pDocShell;
729 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, PreviewHdl, weld::Toggleable&, void)
731 std::shared_ptr<comphelper::ConfigurationChanges> batch( comphelper::ConfigurationChanges::create() );
732 bool bCustomPreview = mxPreviewCheckbox->get_active();
733 officecfg::Office::Common::StylesAndFormatting::Preview::set(bCustomPreview, batch );
734 batch->commit();
736 FamilySelect(nActFamily, m_aStyleList, true);
739 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, HighlightHdl, weld::Toggleable&, void)
741 SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl();
742 SfxStyleFamily eFam = SfxTemplate::NIdToSfxFamilyId(nActFamily);
743 if (eFam == SfxStyleFamily::Para)
744 rDispatcher.Execute(SID_SPOTLIGHT_PARASTYLES, SfxCallMode::SYNCHRON);
745 else if (eFam == SfxStyleFamily::Char)
746 rDispatcher.Execute(SID_SPOTLIGHT_CHARSTYLES, SfxCallMode::SYNCHRON);
749 IMPL_LINK_NOARG(SfxCommonTemplateDialog_Impl, UpdateStyleDependents_Hdl, void*, void)
751 m_aStyleListUpdateStyleDependents.Call(nullptr);
752 EnableItem(u"watercan"_ustr, !bWaterDisabled);
753 m_aStyleListEnableDelete.Call(nullptr);
756 void SfxCommonTemplateDialog_Impl::EnableExample_Impl(sal_uInt16 nId, bool bEnable)
758 bool bDisable = !bEnable || !IsSafeForWaterCan();
759 if (nId == SID_STYLE_NEW_BY_EXAMPLE)
761 bNewByExampleDisabled = bDisable;
762 m_aStyleList.EnableNewByExample(bNewByExampleDisabled);
763 EnableItem(u"new"_ustr, bEnable);
764 EnableItem(u"newmenu"_ustr, bEnable);
766 else if( nId == SID_STYLE_UPDATE_BY_EXAMPLE )
768 bUpdateByExampleDisabled = bDisable;
769 EnableItem(u"update"_ustr, bEnable);
773 class ToolbarDropTarget final : public DropTargetHelper
775 private:
776 SfxTemplateDialog_Impl& m_rParent;
778 public:
779 ToolbarDropTarget(SfxTemplateDialog_Impl& rDialog, weld::Toolbar& rToolbar)
780 : DropTargetHelper(rToolbar.get_drop_target())
781 , m_rParent(rDialog)
785 virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
787 return m_rParent.AcceptToolbarDrop(rEvt, *this);
790 virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
792 return m_rParent.ExecuteDrop(rEvt);
796 SfxTemplateDialog_Impl::SfxTemplateDialog_Impl(SfxBindings* pB, SfxTemplatePanelControl* pDlgWindow)
797 : SfxCommonTemplateDialog_Impl(pB, pDlgWindow->get_container(), pDlgWindow->get_builder())
798 , m_xActionTbL(pDlgWindow->get_builder()->weld_toolbar(u"left"_ustr))
799 , m_xActionTbR(pDlgWindow->get_builder()->weld_toolbar(u"right"_ustr))
800 , m_xToolMenu(pDlgWindow->get_builder()->weld_menu(u"toolmenu"_ustr))
801 , m_nActionTbLVisible(0)
803 m_xActionTbR->set_item_help_id(u"watercan"_ustr, HID_TEMPLDLG_WATERCAN);
804 // shown/hidden in SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
805 m_xActionTbR->set_item_help_id(u"new"_ustr, HID_TEMPLDLG_NEWBYEXAMPLE);
806 m_xActionTbR->set_item_help_id(u"newmenu"_ustr, HID_TEMPLDLG_NEWBYEXAMPLE);
807 m_xActionTbR->set_item_menu(u"newmenu"_ustr, m_xToolMenu.get());
808 m_xToolMenu->connect_activate(LINK(this, SfxTemplateDialog_Impl, ToolMenuSelectHdl));
809 m_xActionTbR->set_item_help_id(u"update"_ustr, HID_TEMPLDLG_UPDATEBYEXAMPLE);
811 Initialize();
814 void SfxTemplateDialog_Impl::Initialize()
816 SfxCommonTemplateDialog_Impl::Initialize();
818 m_xActionTbL->connect_clicked(LINK(this, SfxTemplateDialog_Impl, ToolBoxLSelect));
819 m_xActionTbR->connect_clicked(LINK(this, SfxTemplateDialog_Impl, ToolBoxRSelect));
820 m_xActionTbL->set_help_id(HID_TEMPLDLG_TOOLBOX_LEFT);
822 m_xToolbarDropTargetHelper.reset(new ToolbarDropTarget(*this, *m_xActionTbL));
825 void SfxTemplateDialog_Impl::EnableFamilyItem(sal_uInt16 nId, bool bEnable)
827 m_xActionTbL->set_item_sensitive(OUString::number(nId), bEnable);
830 // Insert element into dropdown filter "Frame Styles", "List Styles", etc.
831 void SfxTemplateDialog_Impl::InsertFamilyItem(sal_uInt16 nId, const SfxStyleFamilyItem &rItem)
833 OUString sHelpId;
834 switch( rItem.GetFamily() )
836 case SfxStyleFamily::Char: sHelpId = ".uno:CharStyle"; break;
837 case SfxStyleFamily::Para: sHelpId = ".uno:ParaStyle"; break;
838 case SfxStyleFamily::Frame: sHelpId = ".uno:FrameStyle"; break;
839 case SfxStyleFamily::Page: sHelpId = ".uno:PageStyle"; break;
840 case SfxStyleFamily::Pseudo: sHelpId = ".uno:ListStyle"; break;
841 case SfxStyleFamily::Table: sHelpId = ".uno:TableStyle"; break;
842 default: OSL_FAIL("unknown StyleFamily"); break;
845 OUString sId(OUString::number(nId));
846 m_xActionTbL->set_item_visible(sId, true);
847 m_xActionTbL->set_item_icon_name(sId, rItem.GetImage());
848 m_xActionTbL->set_item_tooltip_text(sId, rItem.GetText());
849 m_xActionTbL->set_item_help_id(sId, sHelpId);
850 ++m_nActionTbLVisible;
853 void SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
855 m_xActionTbR->set_item_visible(u"update"_ustr, false);
856 m_xActionTbR->set_item_visible(u"new"_ustr, false);
857 m_xActionTbR->set_item_visible(u"newmenu"_ustr, true);
858 FillToolMenu();
861 void SfxTemplateDialog_Impl::ClearFamilyList()
863 for (int i = 0, nCount = m_xActionTbL->get_n_items(); i < nCount; ++i)
864 m_xActionTbL->set_item_visible(m_xActionTbL->get_item_ident(i), false);
868 SfxTemplateDialog_Impl::~SfxTemplateDialog_Impl()
870 m_xToolbarDropTargetHelper.reset();
871 m_xActionTbL.reset();
872 m_xActionTbR.reset();
875 void SfxTemplateDialog_Impl::EnableItem(const OUString& rMesId, bool bCheck)
877 if (rMesId == "watercan" && !bCheck && IsCheckedItem(u"watercan"_ustr))
878 Execute_Impl(SID_STYLE_WATERCAN, u""_ustr, u""_ustr, 0, m_aStyleList);
879 m_xActionTbR->set_item_sensitive(rMesId, bCheck);
882 void SfxTemplateDialog_Impl::CheckItem(const OUString &rMesId, bool bCheck)
884 if (rMesId == "watercan")
886 bIsWater=bCheck;
887 m_xActionTbR->set_item_active(u"watercan"_ustr, bCheck);
889 else
890 m_xActionTbL->set_item_active(rMesId, bCheck);
893 bool SfxTemplateDialog_Impl::IsCheckedItem(const OUString& rMesId)
895 if (rMesId == "watercan")
896 return m_xActionTbR->get_item_active(u"watercan"_ustr);
897 return m_xActionTbL->get_item_active(rMesId);
900 IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxLSelect, const OUString&, rEntry, void)
902 FamilySelect(rEntry.toUInt32(), m_aStyleList);
905 IMPL_LINK(SfxTemplateDialog_Impl, ToolBoxRSelect, const OUString&, rEntry, void)
907 if (rEntry == "newmenu")
908 m_xActionTbR->set_menu_item_active(rEntry, !m_xActionTbR->get_menu_item_active(rEntry));
909 else
910 ActionSelect(rEntry, m_aStyleList);
913 void SfxTemplateDialog_Impl::FillToolMenu()
915 //create a popup menu in Writer
916 OUString sTextDoc(u"com.sun.star.text.TextDocument"_ustr);
918 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(u".uno:StyleNewByExample"_ustr, sTextDoc);
919 OUString sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
920 m_xToolMenu->append(u"new"_ustr, sLabel);
921 aProperties = vcl::CommandInfoProvider::GetCommandProperties(u".uno:StyleUpdateByExample"_ustr, sTextDoc);
922 sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
923 m_xToolMenu->append(u"update"_ustr, sLabel);
924 m_xToolMenu->append_separator(u"separator"_ustr);
926 aProperties = vcl::CommandInfoProvider::GetCommandProperties(u".uno:LoadStyles"_ustr, sTextDoc);
927 sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
928 m_xToolMenu->append(u"load"_ustr, sLabel);
931 IMPL_LINK(SfxTemplateDialog_Impl, ToolMenuSelectHdl, const OUString&, rMenuId, void)
933 if (rMenuId.isEmpty())
934 return;
935 ActionSelect(rMenuId, m_aStyleList);
938 void SfxCommonTemplateDialog_Impl::SetFamily(SfxStyleFamily const nFamily)
940 sal_uInt16 const nId(SfxTemplate::SfxFamilyIdToNId(nFamily));
941 assert((0 < nId && nId <= MAX_FAMILIES) || 0xffff == nId);
942 if ( nId != nActFamily )
944 m_aStyleListSetFamily.Call(nId);
945 nActFamily = nId;
949 IMPL_LINK(SfxCommonTemplateDialog_Impl, UpdateFamily_Hdl, StyleList&, rStyleList, void)
951 bWaterDisabled = false;
952 bUpdateByExampleDisabled = false;
954 if (IsCheckedItem(u"watercan"_ustr) &&
955 // only if that area is allowed
956 rStyleList.CurrentFamilyHasState())
958 Execute_Impl(SID_STYLE_APPLY, rStyleList.GetSelectedEntry(), OUString(),
959 static_cast<sal_uInt16>(rStyleList.GetFamilyItem()->GetFamily()), rStyleList);
963 void SfxCommonTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
965 //does nothing
968 sal_Int8 SfxTemplateDialog_Impl::AcceptToolbarDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
970 sal_Int8 nReturn = DND_ACTION_NONE;
972 // auto flip to the category under the mouse
973 int nIndex = m_xActionTbL->get_drop_index(rEvt.maPosPixel);
974 if (nIndex >= m_nActionTbLVisible)
975 nIndex = m_nActionTbLVisible - 1;
977 OUString sIdent = m_xActionTbL->get_item_ident(nIndex);
978 if (!sIdent.isEmpty() && !m_xActionTbL->get_item_active(sIdent))
979 ToolBoxLSelect(sIdent);
981 // special case: page styles are allowed to create new styles by example
982 // but not allowed to be created by drag and drop
983 if (sIdent.toUInt32() != SfxTemplate::SfxFamilyIdToNId(SfxStyleFamily::Page) &&
984 rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR) &&
985 !bNewByExampleDisabled)
987 nReturn = DND_ACTION_COPY;
989 return nReturn;
992 void SfxCommonTemplateDialog_Impl::EnableEdit(bool b, StyleList* rStyleList)
994 if (rStyleList == &m_aStyleList || rStyleList == nullptr)
995 m_aStyleList.Enableedit(b);
997 void SfxCommonTemplateDialog_Impl::EnableDel(bool b, const StyleList* rStyleList)
999 if (rStyleList == &m_aStyleList || rStyleList == nullptr)
1000 m_aStyleList.Enabledel(b);
1002 void SfxCommonTemplateDialog_Impl::EnableNew(bool b, const StyleList* rStyleList)
1004 if (rStyleList == &m_aStyleList || rStyleList == nullptr)
1005 m_aStyleList.Enablenew(b);
1007 void SfxCommonTemplateDialog_Impl::EnableHide(bool b, const StyleList* rStyleList)
1009 if (rStyleList == &m_aStyleList || rStyleList == nullptr)
1010 m_aStyleList.Enablehide(b);
1012 void SfxCommonTemplateDialog_Impl::EnableShow(bool b, const StyleList* rStyleList)
1014 if (rStyleList == &m_aStyleList || rStyleList == nullptr)
1015 m_aStyleList.Enableshow(b);
1017 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */