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