cid#1607171 Data race condition
[LibreOffice.git] / sd / source / ui / view / ToolBarManager.cxx
blobd5dda2d3ce3154df1ba7d97e82476d12889f9854
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 <ToolBarManager.hxx>
22 #include <DrawViewShell.hxx>
23 #include <NotesPanelViewShell.hxx>
24 #include <EventMultiplexer.hxx>
25 #include <ViewShellBase.hxx>
26 #include <ViewShellManager.hxx>
27 #include <framework/FrameworkHelper.hxx>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/frame/XLayoutManager.hpp>
31 #include <sal/log.hxx>
32 #include <osl/mutex.hxx>
33 #include <o3tl/deleter.hxx>
34 #include <o3tl/enumrange.hxx>
35 #include <sfx2/docfile.hxx>
36 #include <sfx2/notebookbar/SfxNotebookBar.hxx>
37 #include <sfx2/objsh.hxx>
38 #include <sfx2/toolbarids.hxx>
39 #include <sfx2/viewfrm.hxx>
40 #include <svl/eitem.hxx>
41 #include <svx/svxids.hrc>
42 #include <svx/extrusionbar.hxx>
43 #include <svx/fontworkbar.hxx>
44 #include <tools/debug.hxx>
45 #include <tools/link.hxx>
46 #include <utility>
47 #include <vcl/svapp.hxx>
48 #include <osl/diagnose.h>
50 #include <map>
51 #include <memory>
52 #include <string_view>
53 #include <vector>
55 using namespace ::com::sun::star;
56 using namespace ::com::sun::star::uno;
58 namespace {
60 using namespace sd;
62 class ToolBarRules;
64 /** Lock of the frame::XLayoutManager.
66 class LayouterLock
68 Reference<frame::XLayoutManager> mxLayouter;
69 public:
70 explicit LayouterLock (const Reference<frame::XLayoutManager>& rxLayouter);
71 ~LayouterLock();
72 bool is() const { return mxLayouter.is(); }
75 /** Store a list of tool bars for each of the tool bar groups. From
76 this the list of requested tool bars is built.
78 class ToolBarList
80 public:
81 ToolBarList();
83 void ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup);
84 void AddToolBar (sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName);
85 bool RemoveToolBar (sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName);
87 void GetToolBarsToActivate (std::vector<OUString>& rToolBars) const;
88 void GetToolBarsToDeactivate (std::vector<OUString>& rToolBars) const;
90 void MarkToolBarAsActive (const OUString& rsName);
91 void MarkToolBarAsNotActive (const OUString& rsName);
92 void MarkAllToolBarsAsNotActive();
94 private:
95 typedef ::std::map<sd::ToolBarManager::ToolBarGroup, std::vector<OUString> > Groups;
96 Groups maGroups;
97 std::vector<OUString> maActiveToolBars;
99 void MakeRequestedToolBarList (std::vector<OUString>& rToolBars) const;
102 /** Manage tool bars that are implemented as sub shells of a view shell.
103 The typical procedure of updating the sub shells of a view shell is to
104 rebuild a list of sub shells that the caller would like to have active.
105 The methods ClearGroup() and AddShellId() allow the caller to do that. A
106 final call to UpdateShells() activates the requested shells that are not
107 active and deactivates the active shells that are not requested .
109 This is done by maintaining two lists. One (the current list)
110 reflects the current state. The other (the requested list) contains the
111 currently requested shells. UpdateShells() makes the requested
112 list the current list and clears the current list.
114 Each shell belongs to one group. Different groups can be modified
115 separately.
117 class ToolBarShellList
119 public:
120 /** Create a new object with an empty current list and an empty
121 requested list.
123 ToolBarShellList();
125 /** Remove all shells from a group. Calling this method should normally
126 not be necessary because after the construction or after a call to
127 UpdateShells() the requested list is empty.
128 @param eGroup
129 The group to clear. Shells in other groups are not modified.
131 void ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup);
133 /** Add a shell. When the specified shell has already been requested
134 for another group then it is moved to this group.
135 @param eGroup
136 The group to which to add the shell.
137 @param nId
138 The id of the shell to add.
140 void AddShellId (sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nId);
142 /** Releasing all shells means that the given ToolBarRules object is
143 informed that every shell managed by the called ToolBarShellList is
144 about to be removed and that the associated framework tool bars can
145 be removed as well. The caller still has to call UpdateShells().
147 void ReleaseAllShells (ToolBarRules& rRules);
149 /** The requested list is made the current list by activating all
150 shells in the requested list and by deactivating the shells in the
151 current list that are not in the requested list.
152 @param pMainViewShell
153 The shells that are activated or deactivated are sub shells of
154 this view shell.
155 @param rManager
156 This ViewShellManager is used to activate or deactivate shells.
158 void UpdateShells (
159 const std::shared_ptr<ViewShell>& rpMainViewShell,
160 const std::shared_ptr<ViewShellManager>& rpManager);
162 private:
163 class ShellDescriptor
164 {public:
165 ShellDescriptor (ShellId nId,sd::ToolBarManager::ToolBarGroup eGroup);
166 ShellId mnId;
167 sd::ToolBarManager::ToolBarGroup meGroup;
168 friend bool operator<(const ShellDescriptor& r1, const ShellDescriptor& r2)
169 { return r1.mnId < r2.mnId; }
172 /** The requested list of tool bar shells that will be active after the
173 next call to UpdateShells().
175 typedef ::std::set<ShellDescriptor> GroupedShellList;
176 GroupedShellList maNewList;
178 /** The list of tool bar shells that are currently on the shell stack.
179 Using a GroupedShellList is not strictly necessary but it makes
180 things easier and does not waste too much memory.
182 GroupedShellList maCurrentList;
185 /** This class concentrates the knowledge about when to show what tool bars
186 in one place.
188 class ToolBarRules
190 public:
191 ToolBarRules (
192 std::shared_ptr<ToolBarManager> pToolBarManager,
193 std::shared_ptr<ViewShellManager> pViewShellManager);
195 /** This method calls MainViewShellChanged() and SelectionHasChanged()
196 for the current main view shell and its view.
198 void Update (ViewShellBase const & rBase);
200 /** Reset all tool bars in all groups and add tool bars and tool bar
201 shells to the ToolBarGroup::Permanent group for the specified ViewShell type.
203 void MainViewShellChanged (ViewShell::ShellType nShellType);
205 /** Reset all tool bars in all groups and add tool bars and tool bar
206 shells to the ToolBarGroup::Permanent group for the specified ViewShell.
208 void MainViewShellChanged (const ViewShell& rMainViewShell);
210 /** Reset all tool bars in the ToolBarGroup::Function group and add tool bars and tool bar
211 shells to this group for the current selection.
213 void SelectionHasChanged (
214 const ::sd::ViewShell& rViewShell,
215 const SdrView& rView);
217 /** Add a tool bar for the specified tool bar shell.
219 void SubShellAdded (
220 ::sd::ToolBarManager::ToolBarGroup eGroup,
221 sd::ShellId nShellId);
223 /** Remove a tool bar for the specified tool bar shell.
225 void SubShellRemoved (
226 ::sd::ToolBarManager::ToolBarGroup eGroup,
227 sd::ShellId nShellId);
229 private:
230 std::shared_ptr<ToolBarManager> mpToolBarManager;
231 std::shared_ptr<ViewShellManager> mpViewShellManager;
234 } // end of anonymous namespace
236 namespace sd {
238 //===== ToolBarManager::Implementation ========================================
240 class ToolBarManager::Implementation
242 public:
243 /** This constructor takes three arguments even though the
244 ToolBarManager could be taken from the ViewShellBase. This is so to
245 state explicitly which information has to be present when this
246 constructor is called. The ViewShellBase may not have been fully
247 initialized at this point and must not be asked for this values.
249 Implementation (
250 ViewShellBase& rBase,
251 std::shared_ptr<sd::tools::EventMultiplexer> pMultiplexer,
252 const std::shared_ptr<ViewShellManager>& rpViewShellManager,
253 const std::shared_ptr<ToolBarManager>& rpToolBarManager);
254 ~Implementation();
256 void SetValid (bool bValid);
258 void ResetToolBars (ToolBarGroup eGroup);
259 void ResetAllToolBars();
260 void AddToolBar (ToolBarGroup eGroup, const OUString& rsToolBarName);
261 void AddToolBarShell (ToolBarGroup eGroup, ShellId nToolBarId, bool bAddBar = true);
262 void RemoveToolBar (ToolBarGroup eGroup, const OUString& rsToolBarName);
264 /** Release all tool bar shells and the associated framework tool bars.
265 Typically called when the main view shell is being replaced by
266 another, all tool bar shells are released. In that process the
267 shells are destroyed anyway and without calling this method they
268 would still be referenced.
270 void ReleaseAllToolBarShells();
272 void ToolBarsDestroyed();
274 void RequestUpdate();
276 void PreUpdate();
277 void PostUpdate();
278 /** Tell the XLayoutManager about the tool bars that we would like to be
279 shown.
280 @param rpLayouterLock
281 This typically is the mpSynchronousLayouterLock that is used in
282 this method and that is either released at its end or assigned
283 to mpAsynchronousLock in order to be unlocked later.
285 void Update (::std::unique_ptr<LayouterLock> pLayouterLock);
287 class UpdateLockImplementation
289 public:
290 explicit UpdateLockImplementation (Implementation& rImplementation)
291 : mrImplementation(rImplementation) { mrImplementation.LockUpdate(); }
292 ~UpdateLockImplementation() { suppress_fun_call_w_exception(mrImplementation.UnlockUpdate()); }
293 private:
294 Implementation& mrImplementation;
297 void LockViewShellManager();
298 void LockUpdate();
299 void UnlockUpdate();
301 ToolBarRules& GetToolBarRules() { return maToolBarRules;}
303 private:
304 mutable ::osl::Mutex maMutex;
305 ViewShellBase& mrBase;
306 std::shared_ptr<sd::tools::EventMultiplexer> mpEventMultiplexer;
307 bool mbIsValid;
308 ToolBarList maToolBarList;
309 ToolBarShellList maToolBarShellList;
310 Reference<frame::XLayoutManager> mxLayouter;
311 sal_Int32 mnLockCount;
312 bool mbPreUpdatePending;
313 bool mbPostUpdatePending;
314 /** The layouter locks manage the locking of the XLayoutManager. The
315 lock() and unlock() functions are not called directly because the
316 (final) unlocking is usually done asynchronously *after* the
317 list of requested toolbars is updated.
319 ::std::unique_ptr<LayouterLock> mpSynchronousLayouterLock;
320 ::std::unique_ptr<LayouterLock> mpAsynchronousLayouterLock;
321 ::std::unique_ptr<ViewShellManager::UpdateLock, o3tl::default_delete<ViewShellManager::UpdateLock>> mpViewShellManagerLock;
322 ImplSVEvent * mnPendingUpdateCall;
323 ImplSVEvent * mnPendingSetValidCall;
324 ToolBarRules maToolBarRules;
326 static OUString GetToolBarResourceName (std::u16string_view rsBaseName);
327 bool CheckPlugInMode (std::u16string_view rsName) const;
329 DECL_LINK(UpdateCallback, void *, void);
330 DECL_LINK(EventMultiplexerCallback, sd::tools::EventMultiplexerEvent&, void);
331 DECL_LINK(SetValidCallback, void*, void);
334 //===== ToolBarManager ========================================================
336 std::shared_ptr<ToolBarManager> ToolBarManager::Create (
337 ViewShellBase& rBase,
338 const std::shared_ptr<sd::tools::EventMultiplexer>& rpMultiplexer,
339 const std::shared_ptr<ViewShellManager>& rpViewShellManager)
341 std::shared_ptr<ToolBarManager> pManager (new ToolBarManager());
342 pManager->mpImpl.reset(
343 new Implementation(rBase,rpMultiplexer,rpViewShellManager,pManager));
344 return pManager;
347 ToolBarManager::ToolBarManager()
351 ToolBarManager::~ToolBarManager()
355 void ToolBarManager::Shutdown()
357 if (mpImpl != nullptr)
358 mpImpl.reset();
361 void ToolBarManager::ResetToolBars (ToolBarGroup eGroup)
363 if (mpImpl != nullptr)
365 UpdateLock aLock (shared_from_this());
366 mpImpl->ResetToolBars(eGroup);
370 void ToolBarManager::ResetAllToolBars()
372 if (mpImpl != nullptr)
374 UpdateLock aLock (shared_from_this());
375 mpImpl->ResetAllToolBars();
379 void ToolBarManager::AddToolBar (
380 ToolBarGroup eGroup,
381 const OUString& rsToolBarName)
383 if (mpImpl != nullptr)
385 UpdateLock aLock (shared_from_this());
386 mpImpl->AddToolBar(eGroup,rsToolBarName);
390 void ToolBarManager::AddToolBarShell (
391 ToolBarGroup eGroup,
392 ShellId nToolBarId)
394 if (mpImpl != nullptr)
396 UpdateLock aLock (shared_from_this());
397 mpImpl->AddToolBarShell(eGroup,nToolBarId,/*bAddBar*/true);
401 void ToolBarManager::RemoveToolBar (
402 ToolBarGroup eGroup,
403 const OUString& rsToolBarName)
405 if (mpImpl != nullptr)
407 UpdateLock aLock (shared_from_this());
408 mpImpl->RemoveToolBar(eGroup,rsToolBarName);
412 void ToolBarManager::SetToolBar (
413 ToolBarGroup eGroup,
414 const OUString& rsToolBarName)
416 if (mpImpl != nullptr)
418 UpdateLock aLock (shared_from_this());
419 mpImpl->ResetToolBars(eGroup);
420 mpImpl->AddToolBar(eGroup,rsToolBarName);
424 void ToolBarManager::SetToolBarShell (
425 ToolBarGroup eGroup,
426 ShellId nToolBarId)
428 if (mpImpl != nullptr)
430 UpdateLock aLock (shared_from_this());
431 mpImpl->ResetToolBars(eGroup);
432 mpImpl->AddToolBarShell(eGroup,nToolBarId);
436 void ToolBarManager::PreUpdate()
438 if (mpImpl != nullptr)
439 mpImpl->PreUpdate();
442 void ToolBarManager::RequestUpdate()
444 if (mpImpl != nullptr)
445 mpImpl->RequestUpdate();
448 void ToolBarManager::LockViewShellManager()
450 if (mpImpl != nullptr)
451 mpImpl->LockViewShellManager();
454 void ToolBarManager::LockUpdate()
456 if (mpImpl != nullptr)
457 mpImpl->LockUpdate();
460 void ToolBarManager::UnlockUpdate()
462 if (mpImpl != nullptr)
463 mpImpl->UnlockUpdate();
466 void ToolBarManager::MainViewShellChanged ()
468 if (mpImpl != nullptr)
470 mpImpl->ReleaseAllToolBarShells();
471 mpImpl->GetToolBarRules().MainViewShellChanged(ViewShell::ST_NONE);
475 void ToolBarManager::MainViewShellChanged (const ViewShell& rMainViewShell)
477 if (mpImpl != nullptr)
479 mpImpl->ReleaseAllToolBarShells();
480 mpImpl->GetToolBarRules().MainViewShellChanged(rMainViewShell);
484 void ToolBarManager::SelectionHasChanged (
485 const ViewShell& rViewShell,
486 const SdrView& rView)
488 if (mpImpl != nullptr)
489 mpImpl->GetToolBarRules().SelectionHasChanged(rViewShell,rView);
492 void ToolBarManager::ToolBarsDestroyed()
494 if (mpImpl != nullptr)
495 mpImpl->ToolBarsDestroyed();
498 //===== ToolBarManager::Implementation =======================================
500 ToolBarManager::Implementation::Implementation (
501 ViewShellBase& rBase,
502 std::shared_ptr<sd::tools::EventMultiplexer> pMultiplexer,
503 const std::shared_ptr<ViewShellManager>& rpViewShellManager,
504 const std::shared_ptr<ToolBarManager>& rpToolBarManager)
505 : mrBase(rBase),
506 mpEventMultiplexer(std::move(pMultiplexer)),
507 mbIsValid(false),
508 mnLockCount(0),
509 mbPreUpdatePending(false),
510 mbPostUpdatePending(false),
511 mnPendingUpdateCall(nullptr),
512 mnPendingSetValidCall(nullptr),
513 maToolBarRules(rpToolBarManager,rpViewShellManager)
515 Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,ToolBarManager::Implementation,EventMultiplexerCallback));
516 mpEventMultiplexer->AddEventListener( aLink );
519 /** The order of statements is important.
520 First unregister listeners, which may post user events.
521 Then remove pending user events.
523 ToolBarManager::Implementation::~Implementation()
525 // Unregister at broadcasters.
526 Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,ToolBarManager::Implementation,EventMultiplexerCallback));
527 mpEventMultiplexer->RemoveEventListener(aLink);
529 // Abort pending user calls.
530 if (mnPendingUpdateCall != nullptr)
531 Application::RemoveUserEvent(mnPendingUpdateCall);
532 if (mnPendingSetValidCall != nullptr)
533 Application::RemoveUserEvent(mnPendingSetValidCall);
536 void ToolBarManager::Implementation::ToolBarsDestroyed()
538 maToolBarList.MarkAllToolBarsAsNotActive();
541 void ToolBarManager::Implementation::SetValid (bool bValid)
543 ::osl::MutexGuard aGuard(maMutex);
545 if (mbIsValid == bValid)
546 return;
548 UpdateLockImplementation aUpdateLock (*this);
550 mbIsValid = bValid;
551 if (mbIsValid)
553 Reference<frame::XFrame> xFrame = mrBase.GetViewFrame().GetFrame().GetFrameInterface();
556 Reference<beans::XPropertySet> xFrameProperties (xFrame, UNO_QUERY_THROW);
557 Any aValue (xFrameProperties->getPropertyValue(u"LayoutManager"_ustr));
558 aValue >>= mxLayouter;
559 // tdf#119997 if mpSynchronousLayouterLock was created before mxLayouter was
560 // set then update it now that its available
561 if (mpSynchronousLayouterLock && !mpSynchronousLayouterLock->is())
562 mpSynchronousLayouterLock.reset(new LayouterLock(mxLayouter));
564 catch (const RuntimeException&)
568 GetToolBarRules().Update(mrBase);
570 else
572 ResetAllToolBars();
573 mxLayouter = nullptr;
577 void ToolBarManager::Implementation::ResetToolBars (ToolBarGroup eGroup)
579 ::osl::MutexGuard aGuard(maMutex);
581 maToolBarList.ClearGroup(eGroup);
582 maToolBarShellList.ClearGroup(eGroup);
584 mbPreUpdatePending = true;
587 void ToolBarManager::Implementation::ResetAllToolBars()
589 SAL_INFO("sd.view", __func__ << ": resetting all tool bars");
590 for (auto i : o3tl::enumrange<ToolBarGroup>())
591 ResetToolBars(i);
594 void ToolBarManager::Implementation::AddToolBar (
595 ToolBarGroup eGroup,
596 const OUString& rsToolBarName)
598 ::osl::MutexGuard aGuard(maMutex);
600 if (CheckPlugInMode(rsToolBarName))
602 maToolBarList.AddToolBar(eGroup,rsToolBarName);
604 mbPostUpdatePending = true;
605 if (mnLockCount == 0)
606 PostUpdate();
610 void ToolBarManager::Implementation::RemoveToolBar (
611 ToolBarGroup eGroup,
612 const OUString& rsToolBarName)
614 ::osl::MutexGuard aGuard(maMutex);
616 if (maToolBarList.RemoveToolBar(eGroup,rsToolBarName))
618 mbPreUpdatePending = true;
619 if (mnLockCount == 0)
620 PreUpdate();
624 void ToolBarManager::Implementation::AddToolBarShell (
625 ToolBarGroup eGroup,
626 ShellId nToolBarId,
627 bool bAddBar)
629 ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
630 if (pMainViewShell != nullptr)
632 maToolBarShellList.AddShellId(eGroup,nToolBarId);
633 if (bAddBar)
635 GetToolBarRules().SubShellAdded(eGroup, nToolBarId);
637 else
639 mbPostUpdatePending = true;
640 if (mnLockCount == 0)
641 PostUpdate();
646 void ToolBarManager::Implementation::ReleaseAllToolBarShells()
648 maToolBarShellList.ReleaseAllShells(GetToolBarRules());
649 maToolBarShellList.UpdateShells(mrBase.GetMainViewShell(), mrBase.GetViewShellManager());
652 void ToolBarManager::Implementation::RequestUpdate()
654 if (mnPendingUpdateCall == nullptr)
656 mnPendingUpdateCall = Application::PostUserEvent(
657 LINK(this,ToolBarManager::Implementation,UpdateCallback));
661 void ToolBarManager::Implementation::PreUpdate()
663 ::osl::MutexGuard aGuard(maMutex);
665 if (!(mbIsValid
666 && mbPreUpdatePending
667 && mxLayouter.is()))
668 return;
670 mbPreUpdatePending = false;
672 SAL_INFO("sd.view", __func__ << ": ToolBarManager::PreUpdate [");
674 // Get the list of tool bars that are not used anymore and are to be
675 // deactivated.
676 std::vector<OUString> aToolBars;
677 maToolBarList.GetToolBarsToDeactivate(aToolBars);
679 // Turn off the tool bars.
680 for (const auto& aToolBar : aToolBars)
682 OUString sFullName (GetToolBarResourceName(aToolBar));
683 SAL_INFO("sd.view", __func__ << ": turning off tool bar " << sFullName);
684 mxLayouter->destroyElement(sFullName);
685 maToolBarList.MarkToolBarAsNotActive(aToolBar);
688 SAL_INFO("sd.view", __func__ << ": ToolBarManager::PreUpdate ]");
691 void ToolBarManager::Implementation::PostUpdate()
693 ::osl::MutexGuard aGuard(maMutex);
695 if (!(mbIsValid
696 && mbPostUpdatePending
697 && mxLayouter.is()))
698 return;
700 mbPostUpdatePending = false;
702 // Create the list of requested tool bars.
703 std::vector<OUString> aToolBars;
704 maToolBarList.GetToolBarsToActivate(aToolBars);
706 SAL_INFO("sd.view", __func__ << ": ToolBarManager::PostUpdate [");
708 // Turn on the tool bars that are visible in the new context.
709 for (const auto& aToolBar : aToolBars)
711 OUString sFullName (GetToolBarResourceName(aToolBar));
712 SAL_INFO("sd.view", __func__ << ": turning on tool bar " << sFullName);
713 mxLayouter->requestElement(sFullName);
714 maToolBarList.MarkToolBarAsActive(aToolBar);
717 SAL_INFO("sd.view", __func__ << ": ToolBarManager::PostUpdate ]");
720 void ToolBarManager::Implementation::LockViewShellManager()
722 if (mpViewShellManagerLock == nullptr)
723 mpViewShellManagerLock.reset(
724 new ViewShellManager::UpdateLock(mrBase.GetViewShellManager()));
727 void ToolBarManager::Implementation::LockUpdate()
729 SAL_INFO("sd.view", __func__ << ": LockUpdate " << mnLockCount);
730 ::osl::MutexGuard aGuard(maMutex);
732 DBG_ASSERT(mnLockCount<100, "ToolBarManager lock count unusually high");
733 if (mnLockCount == 0)
735 OSL_ASSERT(mpSynchronousLayouterLock == nullptr);
737 mpSynchronousLayouterLock.reset(new LayouterLock(mxLayouter));
739 ++mnLockCount;
742 void ToolBarManager::Implementation::UnlockUpdate()
744 SAL_INFO("sd.view", __func__ << ": UnlockUpdate " << mnLockCount);
745 ::osl::MutexGuard aGuard(maMutex);
747 OSL_ASSERT(mnLockCount>0);
748 --mnLockCount;
749 if (mnLockCount == 0)
751 Update(std::move(mpSynchronousLayouterLock));
755 void ToolBarManager::Implementation::Update (
756 ::std::unique_ptr<LayouterLock> pLocalLayouterLock)
758 // When the lock is released and there are pending changes to the set of
759 // tool bars then update this set now.
760 if (mnLockCount != 0)
761 return;
763 // During creation of ViewShellBase we may have the situation that
764 // the controller has already been created and attached to the frame
765 // but that the ToolBarManager has not yet completed its
766 // initialization (by initializing the mxLayouter member.) We do
767 // this here so that we do not have to wait for the next Update()
768 // call to show the tool bars.
769 if (mnPendingSetValidCall != nullptr)
771 Application::RemoveUserEvent(mnPendingSetValidCall);
772 mnPendingSetValidCall = nullptr;
773 SetValid(true);
776 if (mbIsValid && mxLayouter.is() && (mbPreUpdatePending || mbPostUpdatePending))
778 // 1) Release UNO tool bars that are no longer used. Do this
779 // now so that they are not updated when the SFX shell stack is
780 // modified.
781 if (mbPreUpdatePending)
782 PreUpdate();
784 // 2) Update the requested shells that represent tool bar
785 // functionality. Those that are not used anymore are
786 // deactivated now. Those that are missing are activated in the
787 // next step together with the view shells.
788 if (mpViewShellManagerLock == nullptr)
789 mpViewShellManagerLock.reset(
790 new ViewShellManager::UpdateLock(mrBase.GetViewShellManager()));
791 maToolBarShellList.UpdateShells(
792 mrBase.GetMainViewShell(),
793 mrBase.GetViewShellManager());
795 // 3) Unlock the ViewShellManager::UpdateLock. This updates the
796 // shell stack.
797 mpViewShellManagerLock.reset();
799 // 4) Make the UNO tool bars visible. The outstanding call to
800 // PostUpdate() is done via PostUserEvent() so that it is
801 // guaranteed to be executed when the SFX shell stack has been
802 // updated (under the assumption that our lock to the
803 // ViewShellManager was the only one open. If that is not the
804 // case then all should still be well but not as fast.)
806 // Note that the lock count may have been increased since
807 // entering this method. In that case one of the next
808 // UnlockUpdate() calls will post the UpdateCallback.
809 if (mnLockCount==0)
811 mpAsynchronousLayouterLock = std::move(pLocalLayouterLock);
812 if (mnPendingUpdateCall==nullptr)
814 mnPendingUpdateCall = Application::PostUserEvent(
815 LINK(this,ToolBarManager::Implementation,UpdateCallback));
819 else
821 mpViewShellManagerLock.reset();
822 pLocalLayouterLock.reset();
826 IMPL_LINK_NOARG(ToolBarManager::Implementation, UpdateCallback, void*, void)
828 mnPendingUpdateCall = nullptr;
829 if (mnLockCount == 0)
831 if (mbPreUpdatePending)
832 PreUpdate();
833 if (mbPostUpdatePending)
834 PostUpdate();
835 if (mbIsValid && mxLayouter.is())
836 mpAsynchronousLayouterLock.reset();
840 IMPL_LINK(ToolBarManager::Implementation,EventMultiplexerCallback,
841 sd::tools::EventMultiplexerEvent&, rEvent, void)
843 SolarMutexGuard g;
844 switch (rEvent.meEventId)
846 case EventMultiplexerEventId::ControllerAttached:
847 if (mnPendingSetValidCall == nullptr)
848 mnPendingSetValidCall
849 = Application::PostUserEvent(LINK(this,Implementation,SetValidCallback));
850 break;
852 case EventMultiplexerEventId::ControllerDetached:
853 SetValid(false);
854 break;
856 default: break;
860 IMPL_LINK_NOARG(ToolBarManager::Implementation, SetValidCallback, void*, void)
862 mnPendingSetValidCall = nullptr;
863 SetValid(true);
866 OUString ToolBarManager::Implementation::GetToolBarResourceName (
867 std::u16string_view rsBaseName)
869 return OUString::Concat("private:resource/toolbar/") + rsBaseName;
872 bool ToolBarManager::Implementation::CheckPlugInMode (std::u16string_view rsName) const
874 bool bValid (false);
876 // Determine the plug in mode.
877 bool bIsPlugInMode (false);
880 SfxObjectShell* pObjectShell = mrBase.GetObjectShell();
881 if (pObjectShell == nullptr)
882 break;
884 SfxMedium* pMedium = pObjectShell->GetMedium();
885 if (pMedium == nullptr)
886 break;
888 const SfxBoolItem* pViewOnlyItem = pMedium->GetItemSet().GetItem(SID_VIEWONLY, false);
889 if (pViewOnlyItem == nullptr)
890 break;
892 bIsPlugInMode = pViewOnlyItem->GetValue();
894 while (false);
896 if (rsName == msViewerToolBar)
897 bValid = bIsPlugInMode;
898 else
899 bValid = ! bIsPlugInMode;
901 return bValid;
904 } // end of namespace sd
906 namespace {
908 using namespace ::sd;
910 //===== LayouterLock ==========================================================
912 LayouterLock::LayouterLock (const Reference<frame::XLayoutManager>& rxLayouter)
913 : mxLayouter(rxLayouter)
915 SAL_INFO("sd.view", __func__ << ": LayouterLock " << (mxLayouter.is() ? 1 :0));
916 if (mxLayouter.is())
917 mxLayouter->lock();
920 LayouterLock::~LayouterLock()
922 SAL_INFO("sd.view", __func__ << ": ~LayouterLock " << (mxLayouter.is() ? 1 :0));
923 if (mxLayouter.is())
924 mxLayouter->unlock();
927 //===== ToolBarRules ==========================================================
929 ToolBarRules::ToolBarRules (
930 std::shared_ptr<sd::ToolBarManager> pToolBarManager,
931 std::shared_ptr<sd::ViewShellManager> pViewShellManager)
932 : mpToolBarManager(std::move(pToolBarManager)),
933 mpViewShellManager(std::move(pViewShellManager))
937 void ToolBarRules::Update (ViewShellBase const & rBase)
939 ViewShell* pMainViewShell = rBase.GetMainViewShell().get();
940 if (pMainViewShell != nullptr)
942 MainViewShellChanged(pMainViewShell->GetShellType());
943 if (pMainViewShell->GetView())
944 SelectionHasChanged (*pMainViewShell, *pMainViewShell->GetView());
946 else
947 MainViewShellChanged(ViewShell::ST_NONE);
950 void ToolBarRules::MainViewShellChanged (ViewShell::ShellType nShellType)
952 ::sd::ToolBarManager::UpdateLock aToolBarManagerLock (mpToolBarManager);
953 ::sd::ViewShellManager::UpdateLock aViewShellManagerLock (mpViewShellManager);
955 mpToolBarManager->ResetAllToolBars();
957 switch(nShellType)
959 case ::sd::ViewShell::ST_IMPRESS:
960 case ::sd::ViewShell::ST_NOTES:
961 case ::sd::ViewShell::ST_HANDOUT:
962 case ::sd::ViewShell::ST_DRAW:
963 mpToolBarManager->AddToolBar(
964 ToolBarManager::ToolBarGroup::Permanent,
965 ToolBarManager::msToolBar);
966 mpToolBarManager->AddToolBar(
967 ToolBarManager::ToolBarGroup::Permanent,
968 ToolBarManager::msOptionsToolBar);
969 mpToolBarManager->AddToolBar(
970 ToolBarManager::ToolBarGroup::Permanent,
971 ToolBarManager::msViewerToolBar);
972 break;
974 case ::sd::ViewShell::ST_NOTESPANEL:
975 mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Permanent,
976 ToolbarId::Draw_Text_Toolbox_Sd);
977 break;
979 case ViewShell::ST_OUTLINE:
980 mpToolBarManager->AddToolBar(
981 ToolBarManager::ToolBarGroup::Permanent,
982 ToolBarManager::msOutlineToolBar);
983 mpToolBarManager->AddToolBar(
984 ToolBarManager::ToolBarGroup::Permanent,
985 ToolBarManager::msViewerToolBar);
986 mpToolBarManager->AddToolBarShell(
987 ToolBarManager::ToolBarGroup::Permanent, ToolbarId::Draw_Text_Toolbox_Sd);
988 break;
990 case ViewShell::ST_SLIDE_SORTER:
991 mpToolBarManager->AddToolBar(
992 ToolBarManager::ToolBarGroup::Permanent,
993 ToolBarManager::msViewerToolBar);
994 mpToolBarManager->AddToolBar(
995 ToolBarManager::ToolBarGroup::Permanent,
996 ToolBarManager::msSlideSorterToolBar);
997 mpToolBarManager->AddToolBar(
998 ToolBarManager::ToolBarGroup::Permanent,
999 ToolBarManager::msSlideSorterObjectBar);
1000 break;
1002 case ViewShell::ST_NONE:
1003 case ViewShell::ST_PRESENTATION:
1004 case ViewShell::ST_SIDEBAR:
1005 default:
1006 break;
1010 void ToolBarRules::MainViewShellChanged (const ViewShell& rMainViewShell)
1012 ::sd::ToolBarManager::UpdateLock aToolBarManagerLock (mpToolBarManager);
1013 ::sd::ViewShellManager::UpdateLock aViewShellManagerLock (mpViewShellManager);
1015 MainViewShellChanged(rMainViewShell.GetShellType());
1016 switch(rMainViewShell.GetShellType())
1018 case ::sd::ViewShell::ST_IMPRESS:
1019 case ::sd::ViewShell::ST_DRAW:
1020 case ::sd::ViewShell::ST_NOTES:
1022 const DrawViewShell* pDrawViewShell
1023 = dynamic_cast<const DrawViewShell*>(&rMainViewShell);
1024 if (pDrawViewShell != nullptr)
1026 if (pDrawViewShell->GetEditMode() == EditMode::MasterPage)
1027 mpToolBarManager->AddToolBar(
1028 ToolBarManager::ToolBarGroup::MasterMode,
1029 ToolBarManager::msMasterViewToolBar);
1030 else if ( rMainViewShell.GetShellType() != ::sd::ViewShell::ST_DRAW )
1031 mpToolBarManager->AddToolBar(
1032 ToolBarManager::ToolBarGroup::CommonTask,
1033 ToolBarManager::msCommonTaskToolBar);
1035 break;
1038 default:
1039 break;
1043 void ToolBarRules::SelectionHasChanged (
1044 const ::sd::ViewShell& rViewShell,
1045 const SdrView& rView)
1047 ::sd::ToolBarManager::UpdateLock aLock (mpToolBarManager);
1048 mpToolBarManager->LockViewShellManager();
1049 bool bTextEdit = rView.IsTextEdit();
1051 mpToolBarManager->ResetToolBars(ToolBarManager::ToolBarGroup::Function);
1053 switch (rView.GetContext())
1055 case SdrViewContext::Graphic:
1056 if (!bTextEdit)
1057 mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function,
1058 ToolbarId::Draw_Graf_Toolbox);
1059 break;
1061 case SdrViewContext::Media:
1062 if (!bTextEdit)
1063 mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function,
1064 ToolbarId::Draw_Media_Toolbox);
1065 break;
1067 case SdrViewContext::Table:
1068 mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function,
1069 ToolbarId::Draw_Table_Toolbox);
1070 bTextEdit = true;
1071 break;
1073 case SdrViewContext::Standard:
1074 default:
1075 if (!bTextEdit)
1077 switch(rViewShell.GetShellType())
1079 case ::sd::ViewShell::ST_IMPRESS:
1080 case ::sd::ViewShell::ST_DRAW:
1081 case ::sd::ViewShell::ST_NOTES:
1082 case ::sd::ViewShell::ST_HANDOUT:
1083 mpToolBarManager->SetToolBar(ToolBarManager::ToolBarGroup::Function,
1084 ToolBarManager::msDrawingObjectToolBar);
1085 mpToolBarManager->SetToolBar(ToolBarManager::ToolBarGroup::Permanent,
1086 ToolBarManager::msToolBar);
1087 break;
1088 default:
1089 break;
1091 break;
1095 if( bTextEdit )
1096 mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Text_Toolbox_Sd);
1098 SdrView* pView = &const_cast<SdrView&>(rView);
1099 // Check if the extrusion tool bar and the fontwork tool bar have to
1100 // be activated.
1101 if (svx::checkForSelectedCustomShapes(pView, true /* bOnlyExtruded */ ))
1102 mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Svx_Extrusion_Bar);
1104 if (svx::checkForSelectedFontWork(pView))
1105 mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Svx_Fontwork_Bar);
1107 // Switch on additional context-sensitive tool bars.
1108 if (rView.GetContext() == SdrViewContext::PointEdit)
1109 mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Bezier_Toolbox_Sd);
1112 void ToolBarRules::SubShellAdded (
1113 ::sd::ToolBarManager::ToolBarGroup eGroup,
1114 sd::ShellId nShellId)
1116 // For some tool bar shells (those defined in sd) we have to add the
1117 // actual tool bar here.
1118 switch (nShellId)
1120 case ToolbarId::Draw_Graf_Toolbox:
1121 mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msGraphicObjectBar);
1122 break;
1124 case ToolbarId::Draw_Media_Toolbox:
1125 mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msMediaObjectBar);
1126 break;
1128 case ToolbarId::Draw_Text_Toolbox_Sd:
1129 mpToolBarManager->RemoveToolBar(ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msToolBar);
1130 mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msTextObjectBar);
1131 break;
1133 case ToolbarId::Bezier_Toolbox_Sd:
1134 mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msBezierObjectBar);
1135 break;
1137 case ToolbarId::Draw_Table_Toolbox:
1138 // tdf#142489 Do not show the table toolbar when the Notebookbar UI is active
1139 if (!sfx2::SfxNotebookBar::IsActive(true))
1140 mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msTableObjectBar);
1141 break;
1143 default:
1144 break;
1148 void ToolBarRules::SubShellRemoved (
1149 ::sd::ToolBarManager::ToolBarGroup eGroup,
1150 sd::ShellId nShellId)
1152 // For some tool bar shells (those defined in sd) we have to add the
1153 // actual tool bar here.
1154 switch (nShellId)
1156 case ToolbarId::Draw_Graf_Toolbox:
1157 mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msGraphicObjectBar);
1158 break;
1160 case ToolbarId::Draw_Media_Toolbox:
1161 mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msMediaObjectBar);
1162 break;
1164 case ToolbarId::Draw_Text_Toolbox_Sd:
1165 mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msTextObjectBar);
1166 break;
1168 case ToolbarId::Bezier_Toolbox_Sd:
1169 mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msBezierObjectBar);
1170 break;
1172 case ToolbarId::Draw_Table_Toolbox:
1173 mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msTableObjectBar);
1174 break;
1176 default:
1177 break;
1181 //===== ToolBarList ===========================================================
1183 ToolBarList::ToolBarList()
1187 void ToolBarList::ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup)
1189 Groups::iterator iGroup (maGroups.find(eGroup));
1190 if (iGroup != maGroups.end())
1192 iGroup->second.clear();
1196 void ToolBarList::AddToolBar (
1197 sd::ToolBarManager::ToolBarGroup eGroup,
1198 const OUString& rsName)
1200 Groups::iterator iGroup (maGroups.find(eGroup));
1201 if (iGroup == maGroups.end())
1202 iGroup = maGroups.emplace(eGroup,std::vector<OUString>()).first;
1204 if (iGroup != maGroups.end())
1206 auto iBar (std::find(iGroup->second.cbegin(),iGroup->second.cend(),rsName));
1207 if (iBar == iGroup->second.cend())
1209 iGroup->second.push_back(rsName);
1214 bool ToolBarList::RemoveToolBar (
1215 sd::ToolBarManager::ToolBarGroup eGroup,
1216 const OUString& rsName)
1218 Groups::iterator iGroup (maGroups.find(eGroup));
1219 if (iGroup != maGroups.end())
1221 auto iBar (std::find(iGroup->second.begin(),iGroup->second.end(),rsName));
1222 if (iBar != iGroup->second.end())
1224 iGroup->second.erase(iBar);
1225 return true;
1228 return false;
1231 void ToolBarList::MakeRequestedToolBarList (std::vector<OUString>& rRequestedToolBars) const
1233 for (auto eGroup : o3tl::enumrange<sd::ToolBarManager::ToolBarGroup>())
1235 Groups::const_iterator iGroup (maGroups.find(eGroup));
1236 if (iGroup != maGroups.end())
1237 rRequestedToolBars.insert( rRequestedToolBars.end(),
1238 iGroup->second.begin(),
1239 iGroup->second.end() );
1243 void ToolBarList::GetToolBarsToActivate (std::vector<OUString>& rToolBars) const
1245 std::vector<OUString> aRequestedToolBars;
1246 MakeRequestedToolBarList(aRequestedToolBars);
1248 for (const auto& aToolBar : aRequestedToolBars)
1250 if (::std::find(maActiveToolBars.begin(),maActiveToolBars.end(),aToolBar)
1251 == maActiveToolBars.end())
1253 rToolBars.push_back(aToolBar);
1258 void ToolBarList::GetToolBarsToDeactivate (std::vector<OUString>& rToolBars) const
1260 std::vector<OUString> aRequestedToolBars;
1261 MakeRequestedToolBarList(aRequestedToolBars);
1263 for (auto& aToolBar : maActiveToolBars)
1265 if (::std::find(aRequestedToolBars.begin(),aRequestedToolBars.end(),aToolBar)
1266 == aRequestedToolBars.end())
1268 rToolBars.push_back(aToolBar);
1273 void ToolBarList::MarkToolBarAsActive (const OUString& rsName)
1275 maActiveToolBars.push_back(rsName);
1278 void ToolBarList::MarkToolBarAsNotActive (const OUString& rsName)
1280 maActiveToolBars.erase(
1281 ::std::find(maActiveToolBars.begin(),maActiveToolBars.end(), rsName));
1284 void ToolBarList::MarkAllToolBarsAsNotActive()
1286 maActiveToolBars.clear();
1289 //===== ToolBarShellList ======================================================
1291 ToolBarShellList::ShellDescriptor::ShellDescriptor (
1292 ShellId nId,
1293 sd::ToolBarManager::ToolBarGroup eGroup)
1294 : mnId(nId),
1295 meGroup(eGroup)
1299 ToolBarShellList::ToolBarShellList()
1303 void ToolBarShellList::ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup)
1305 for (GroupedShellList::iterator iDescriptor = maNewList.begin(); iDescriptor != maNewList.end(); )
1306 if (iDescriptor->meGroup == eGroup)
1307 iDescriptor = maNewList.erase(iDescriptor);
1308 else
1309 ++iDescriptor;
1312 void ToolBarShellList::AddShellId (sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nId)
1314 // Make sure that the shell is not added twice (and possibly in
1315 // different groups.)
1316 ShellDescriptor aDescriptor (nId,eGroup);
1317 GroupedShellList::iterator iDescriptor (maNewList.find(aDescriptor));
1318 if (iDescriptor != maNewList.end())
1320 // The shell is already requested.
1321 if (iDescriptor->meGroup != eGroup)
1323 // It is now being requested for another group.
1324 // (Is this an error?)
1325 // Move it to that group.
1326 maNewList.erase(iDescriptor);
1327 maNewList.insert(aDescriptor);
1329 // else nothing to do.
1331 else
1332 maNewList.insert(aDescriptor);
1335 void ToolBarShellList::ReleaseAllShells (ToolBarRules& rRules)
1337 // Release the currently active tool bars.
1338 GroupedShellList aList (maCurrentList);
1339 for (const auto& rDescriptor : aList)
1341 rRules.SubShellRemoved(rDescriptor.meGroup, rDescriptor.mnId);
1344 // Clear the list of requested tool bars.
1345 maNewList.clear();
1348 void ToolBarShellList::UpdateShells (
1349 const std::shared_ptr<ViewShell>& rpMainViewShell,
1350 const std::shared_ptr<ViewShellManager>& rpManager)
1352 if (rpMainViewShell == nullptr)
1353 return;
1355 const std::shared_ptr<ViewShell> pCurrentMainViewShell
1356 = rpManager->GetOverridingMainShell() ? rpManager->GetOverridingMainShell() : rpMainViewShell;
1358 GroupedShellList aList;
1360 // Deactivate shells that are in maCurrentList, but not in
1361 // maNewList.
1362 ::std::set_difference(maCurrentList.begin(), maCurrentList.end(),
1363 maNewList.begin(), maNewList.end(),
1364 std::insert_iterator<GroupedShellList>(aList,aList.begin()));
1365 for (const auto& rShell : aList)
1367 SAL_INFO("sd.view", __func__ << ": deactivating tool bar shell " << static_cast<sal_uInt32>(rShell.mnId));
1368 rpManager->DeactivateSubShell(*pCurrentMainViewShell, rShell.mnId);
1371 // Activate shells that are in maNewList, but not in
1372 // maCurrentList.
1373 aList.clear();
1374 ::std::set_difference(maNewList.begin(), maNewList.end(),
1375 maCurrentList.begin(), maCurrentList.end(),
1376 std::insert_iterator<GroupedShellList>(aList,aList.begin()));
1377 for (const auto& rShell : aList)
1379 SAL_INFO("sd.view", __func__ << ": activating tool bar shell " << static_cast<sal_uInt32>(rShell.mnId));
1380 rpManager->ActivateSubShell(*pCurrentMainViewShell, rShell.mnId);
1383 // The maNewList now reflects the current state and thus is made
1384 // maCurrentList.
1385 maCurrentList = maNewList;
1388 } // end of anonymous namespace
1390 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */