/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; namespace { using namespace sd; class ToolBarRules; /** Lock of the frame::XLayoutManager. */ class LayouterLock { Reference mxLayouter; public: explicit LayouterLock (const Reference& rxLayouter); ~LayouterLock(); bool is() const { return mxLayouter.is(); } }; /** Store a list of tool bars for each of the tool bar groups. From this the list of requested tool bars is built. */ class ToolBarList { public: ToolBarList(); void ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup); void AddToolBar (sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName); bool RemoveToolBar (sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName); void GetToolBarsToActivate (std::vector& rToolBars) const; void GetToolBarsToDeactivate (std::vector& rToolBars) const; void MarkToolBarAsActive (const OUString& rsName); void MarkToolBarAsNotActive (const OUString& rsName); void MarkAllToolBarsAsNotActive(); private: typedef ::std::map > Groups; Groups maGroups; std::vector maActiveToolBars; void MakeRequestedToolBarList (std::vector& rToolBars) const; }; /** Manage tool bars that are implemented as sub shells of a view shell. The typical procedure of updating the sub shells of a view shell is to rebuild a list of sub shells that the caller would like to have active. The methods ClearGroup() and AddShellId() allow the caller to do that. A final call to UpdateShells() activates the requested shells that are not active and deactivates the active shells that are not requested . This is done by maintaining two lists. One (the current list) reflects the current state. The other (the requested list) contains the currently requested shells. UpdateShells() makes the requested list the current list and clears the current list. Each shell belongs to one group. Different groups can be modified separately. */ class ToolBarShellList { public: /** Create a new object with an empty current list and an empty requested list. */ ToolBarShellList(); /** Remove all shells from a group. Calling this method should normally not be necessary because after the construction or after a call to UpdateShells() the requested list is empty. @param eGroup The group to clear. Shells in other groups are not modified. */ void ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup); /** Add a shell. When the specified shell has already been requested for another group then it is moved to this group. @param eGroup The group to which to add the shell. @param nId The id of the shell to add. */ void AddShellId (sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nId); /** Releasing all shells means that the given ToolBarRules object is informed that every shell managed by the called ToolBarShellList is about to be removed and that the associated framework tool bars can be removed as well. The caller still has to call UpdateShells(). */ void ReleaseAllShells (ToolBarRules& rRules); /** The requested list is made the current list by activating all shells in the requested list and by deactivating the shells in the current list that are not in the requested list. @param pMainViewShell The shells that are activated or deactivated are sub shells of this view shell. @param rManager This ViewShellManager is used to activate or deactivate shells. */ void UpdateShells ( const std::shared_ptr& rpMainViewShell, const std::shared_ptr& rpManager); private: class ShellDescriptor {public: ShellDescriptor (ShellId nId,sd::ToolBarManager::ToolBarGroup eGroup); ShellId mnId; sd::ToolBarManager::ToolBarGroup meGroup; friend bool operator<(const ShellDescriptor& r1, const ShellDescriptor& r2) { return r1.mnId < r2.mnId; } }; /** The requested list of tool bar shells that will be active after the next call to UpdateShells(). */ typedef ::std::set GroupedShellList; GroupedShellList maNewList; /** The list of tool bar shells that are currently on the shell stack. Using a GroupedShellList is not strictly necessary but it makes things easier and does not waste too much memory. */ GroupedShellList maCurrentList; }; /** This class concentrates the knowledge about when to show what tool bars in one place. */ class ToolBarRules { public: ToolBarRules ( std::shared_ptr pToolBarManager, std::shared_ptr pViewShellManager); /** This method calls MainViewShellChanged() and SelectionHasChanged() for the current main view shell and its view. */ void Update (ViewShellBase const & rBase); /** Reset all tool bars in all groups and add tool bars and tool bar shells to the ToolBarGroup::Permanent group for the specified ViewShell type. */ void MainViewShellChanged (ViewShell::ShellType nShellType); /** Reset all tool bars in all groups and add tool bars and tool bar shells to the ToolBarGroup::Permanent group for the specified ViewShell. */ void MainViewShellChanged (const ViewShell& rMainViewShell); /** Reset all tool bars in the ToolBarGroup::Function group and add tool bars and tool bar shells to this group for the current selection. */ void SelectionHasChanged ( const ::sd::ViewShell& rViewShell, const SdrView& rView); /** Add a tool bar for the specified tool bar shell. */ void SubShellAdded ( ::sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nShellId); /** Remove a tool bar for the specified tool bar shell. */ void SubShellRemoved ( ::sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nShellId); private: std::shared_ptr mpToolBarManager; std::shared_ptr mpViewShellManager; }; } // end of anonymous namespace namespace sd { //===== ToolBarManager::Implementation ======================================== class ToolBarManager::Implementation { public: /** This constructor takes three arguments even though the ToolBarManager could be taken from the ViewShellBase. This is so to state explicitly which information has to be present when this constructor is called. The ViewShellBase may not have been fully initialized at this point and must not be asked for this values. */ Implementation ( ViewShellBase& rBase, std::shared_ptr pMultiplexer, const std::shared_ptr& rpViewShellManager, const std::shared_ptr& rpToolBarManager); ~Implementation(); void SetValid (bool bValid); void ResetToolBars (ToolBarGroup eGroup); void ResetAllToolBars(); void AddToolBar (ToolBarGroup eGroup, const OUString& rsToolBarName); void AddToolBarShell (ToolBarGroup eGroup, ShellId nToolBarId, bool bAddBar = true); void RemoveToolBar (ToolBarGroup eGroup, const OUString& rsToolBarName); /** Release all tool bar shells and the associated framework tool bars. Typically called when the main view shell is being replaced by another, all tool bar shells are released. In that process the shells are destroyed anyway and without calling this method they would still be referenced. */ void ReleaseAllToolBarShells(); void ToolBarsDestroyed(); void RequestUpdate(); void PreUpdate(); void PostUpdate(); /** Tell the XLayoutManager about the tool bars that we would like to be shown. @param rpLayouterLock This typically is the mpSynchronousLayouterLock that is used in this method and that is either released at its end or assigned to mpAsynchronousLock in order to be unlocked later. */ void Update (::std::unique_ptr pLayouterLock); class UpdateLockImplementation { public: explicit UpdateLockImplementation (Implementation& rImplementation) : mrImplementation(rImplementation) { mrImplementation.LockUpdate(); } ~UpdateLockImplementation() { suppress_fun_call_w_exception(mrImplementation.UnlockUpdate()); } private: Implementation& mrImplementation; }; void LockViewShellManager(); void LockUpdate(); void UnlockUpdate(); ToolBarRules& GetToolBarRules() { return maToolBarRules;} private: mutable ::osl::Mutex maMutex; ViewShellBase& mrBase; std::shared_ptr mpEventMultiplexer; bool mbIsValid; ToolBarList maToolBarList; ToolBarShellList maToolBarShellList; Reference mxLayouter; sal_Int32 mnLockCount; bool mbPreUpdatePending; bool mbPostUpdatePending; /** The layouter locks manage the locking of the XLayoutManager. The lock() and unlock() functions are not called directly because the (final) unlocking is usually done asynchronously *after* the list of requested toolbars is updated. */ ::std::unique_ptr mpSynchronousLayouterLock; ::std::unique_ptr mpAsynchronousLayouterLock; ::std::unique_ptr> mpViewShellManagerLock; ImplSVEvent * mnPendingUpdateCall; ImplSVEvent * mnPendingSetValidCall; ToolBarRules maToolBarRules; static OUString GetToolBarResourceName (std::u16string_view rsBaseName); bool CheckPlugInMode (std::u16string_view rsName) const; DECL_LINK(UpdateCallback, void *, void); DECL_LINK(EventMultiplexerCallback, sd::tools::EventMultiplexerEvent&, void); DECL_LINK(SetValidCallback, void*, void); }; //===== ToolBarManager ======================================================== std::shared_ptr ToolBarManager::Create ( ViewShellBase& rBase, const std::shared_ptr& rpMultiplexer, const std::shared_ptr& rpViewShellManager) { std::shared_ptr pManager (new ToolBarManager()); pManager->mpImpl.reset( new Implementation(rBase,rpMultiplexer,rpViewShellManager,pManager)); return pManager; } ToolBarManager::ToolBarManager() { } ToolBarManager::~ToolBarManager() { } void ToolBarManager::Shutdown() { if (mpImpl != nullptr) mpImpl.reset(); } void ToolBarManager::ResetToolBars (ToolBarGroup eGroup) { if (mpImpl != nullptr) { UpdateLock aLock (shared_from_this()); mpImpl->ResetToolBars(eGroup); } } void ToolBarManager::ResetAllToolBars() { if (mpImpl != nullptr) { UpdateLock aLock (shared_from_this()); mpImpl->ResetAllToolBars(); } } void ToolBarManager::AddToolBar ( ToolBarGroup eGroup, const OUString& rsToolBarName) { if (mpImpl != nullptr) { UpdateLock aLock (shared_from_this()); mpImpl->AddToolBar(eGroup,rsToolBarName); } } void ToolBarManager::AddToolBarShell ( ToolBarGroup eGroup, ShellId nToolBarId) { if (mpImpl != nullptr) { UpdateLock aLock (shared_from_this()); mpImpl->AddToolBarShell(eGroup,nToolBarId,/*bAddBar*/true); } } void ToolBarManager::RemoveToolBar ( ToolBarGroup eGroup, const OUString& rsToolBarName) { if (mpImpl != nullptr) { UpdateLock aLock (shared_from_this()); mpImpl->RemoveToolBar(eGroup,rsToolBarName); } } void ToolBarManager::SetToolBar ( ToolBarGroup eGroup, const OUString& rsToolBarName) { if (mpImpl != nullptr) { UpdateLock aLock (shared_from_this()); mpImpl->ResetToolBars(eGroup); mpImpl->AddToolBar(eGroup,rsToolBarName); } } void ToolBarManager::SetToolBarShell ( ToolBarGroup eGroup, ShellId nToolBarId) { if (mpImpl != nullptr) { UpdateLock aLock (shared_from_this()); mpImpl->ResetToolBars(eGroup); mpImpl->AddToolBarShell(eGroup,nToolBarId); } } void ToolBarManager::PreUpdate() { if (mpImpl != nullptr) mpImpl->PreUpdate(); } void ToolBarManager::RequestUpdate() { if (mpImpl != nullptr) mpImpl->RequestUpdate(); } void ToolBarManager::LockViewShellManager() { if (mpImpl != nullptr) mpImpl->LockViewShellManager(); } void ToolBarManager::LockUpdate() { if (mpImpl != nullptr) mpImpl->LockUpdate(); } void ToolBarManager::UnlockUpdate() { if (mpImpl != nullptr) mpImpl->UnlockUpdate(); } void ToolBarManager::MainViewShellChanged () { if (mpImpl != nullptr) { mpImpl->ReleaseAllToolBarShells(); mpImpl->GetToolBarRules().MainViewShellChanged(ViewShell::ST_NONE); } } void ToolBarManager::MainViewShellChanged (const ViewShell& rMainViewShell) { if (mpImpl != nullptr) { mpImpl->ReleaseAllToolBarShells(); mpImpl->GetToolBarRules().MainViewShellChanged(rMainViewShell); } } void ToolBarManager::SelectionHasChanged ( const ViewShell& rViewShell, const SdrView& rView) { if (mpImpl != nullptr) mpImpl->GetToolBarRules().SelectionHasChanged(rViewShell,rView); } void ToolBarManager::ToolBarsDestroyed() { if (mpImpl != nullptr) mpImpl->ToolBarsDestroyed(); } //===== ToolBarManager::Implementation ======================================= ToolBarManager::Implementation::Implementation ( ViewShellBase& rBase, std::shared_ptr pMultiplexer, const std::shared_ptr& rpViewShellManager, const std::shared_ptr& rpToolBarManager) : mrBase(rBase), mpEventMultiplexer(std::move(pMultiplexer)), mbIsValid(false), mnLockCount(0), mbPreUpdatePending(false), mbPostUpdatePending(false), mnPendingUpdateCall(nullptr), mnPendingSetValidCall(nullptr), maToolBarRules(rpToolBarManager,rpViewShellManager) { Link aLink (LINK(this,ToolBarManager::Implementation,EventMultiplexerCallback)); mpEventMultiplexer->AddEventListener( aLink ); } /** The order of statements is important. First unregister listeners, which may post user events. Then remove pending user events. */ ToolBarManager::Implementation::~Implementation() { // Unregister at broadcasters. Link aLink (LINK(this,ToolBarManager::Implementation,EventMultiplexerCallback)); mpEventMultiplexer->RemoveEventListener(aLink); // Abort pending user calls. if (mnPendingUpdateCall != nullptr) Application::RemoveUserEvent(mnPendingUpdateCall); if (mnPendingSetValidCall != nullptr) Application::RemoveUserEvent(mnPendingSetValidCall); } void ToolBarManager::Implementation::ToolBarsDestroyed() { maToolBarList.MarkAllToolBarsAsNotActive(); } void ToolBarManager::Implementation::SetValid (bool bValid) { ::osl::MutexGuard aGuard(maMutex); if (mbIsValid == bValid) return; UpdateLockImplementation aUpdateLock (*this); mbIsValid = bValid; if (mbIsValid) { Reference xFrame = mrBase.GetViewFrame().GetFrame().GetFrameInterface(); try { Reference xFrameProperties (xFrame, UNO_QUERY_THROW); Any aValue (xFrameProperties->getPropertyValue(u"LayoutManager"_ustr)); aValue >>= mxLayouter; // tdf#119997 if mpSynchronousLayouterLock was created before mxLayouter was // set then update it now that its available if (mpSynchronousLayouterLock && !mpSynchronousLayouterLock->is()) mpSynchronousLayouterLock.reset(new LayouterLock(mxLayouter)); } catch (const RuntimeException&) { } GetToolBarRules().Update(mrBase); } else { ResetAllToolBars(); mxLayouter = nullptr; } } void ToolBarManager::Implementation::ResetToolBars (ToolBarGroup eGroup) { ::osl::MutexGuard aGuard(maMutex); maToolBarList.ClearGroup(eGroup); maToolBarShellList.ClearGroup(eGroup); mbPreUpdatePending = true; } void ToolBarManager::Implementation::ResetAllToolBars() { SAL_INFO("sd.view", __func__ << ": resetting all tool bars"); for (auto i : o3tl::enumrange()) ResetToolBars(i); } void ToolBarManager::Implementation::AddToolBar ( ToolBarGroup eGroup, const OUString& rsToolBarName) { ::osl::MutexGuard aGuard(maMutex); if (CheckPlugInMode(rsToolBarName)) { maToolBarList.AddToolBar(eGroup,rsToolBarName); mbPostUpdatePending = true; if (mnLockCount == 0) PostUpdate(); } } void ToolBarManager::Implementation::RemoveToolBar ( ToolBarGroup eGroup, const OUString& rsToolBarName) { ::osl::MutexGuard aGuard(maMutex); if (maToolBarList.RemoveToolBar(eGroup,rsToolBarName)) { mbPreUpdatePending = true; if (mnLockCount == 0) PreUpdate(); } } void ToolBarManager::Implementation::AddToolBarShell ( ToolBarGroup eGroup, ShellId nToolBarId, bool bAddBar) { ViewShell* pMainViewShell = mrBase.GetMainViewShell().get(); if (pMainViewShell != nullptr) { maToolBarShellList.AddShellId(eGroup,nToolBarId); if (bAddBar) { GetToolBarRules().SubShellAdded(eGroup, nToolBarId); } else { mbPostUpdatePending = true; if (mnLockCount == 0) PostUpdate(); } } } void ToolBarManager::Implementation::ReleaseAllToolBarShells() { maToolBarShellList.ReleaseAllShells(GetToolBarRules()); maToolBarShellList.UpdateShells(mrBase.GetMainViewShell(), mrBase.GetViewShellManager()); } void ToolBarManager::Implementation::RequestUpdate() { if (mnPendingUpdateCall == nullptr) { mnPendingUpdateCall = Application::PostUserEvent( LINK(this,ToolBarManager::Implementation,UpdateCallback)); } } void ToolBarManager::Implementation::PreUpdate() { ::osl::MutexGuard aGuard(maMutex); if (!(mbIsValid && mbPreUpdatePending && mxLayouter.is())) return; mbPreUpdatePending = false; SAL_INFO("sd.view", __func__ << ": ToolBarManager::PreUpdate ["); // Get the list of tool bars that are not used anymore and are to be // deactivated. std::vector aToolBars; maToolBarList.GetToolBarsToDeactivate(aToolBars); // Turn off the tool bars. for (const auto& aToolBar : aToolBars) { OUString sFullName (GetToolBarResourceName(aToolBar)); SAL_INFO("sd.view", __func__ << ": turning off tool bar " << sFullName); mxLayouter->destroyElement(sFullName); maToolBarList.MarkToolBarAsNotActive(aToolBar); } SAL_INFO("sd.view", __func__ << ": ToolBarManager::PreUpdate ]"); } void ToolBarManager::Implementation::PostUpdate() { ::osl::MutexGuard aGuard(maMutex); if (!(mbIsValid && mbPostUpdatePending && mxLayouter.is())) return; mbPostUpdatePending = false; // Create the list of requested tool bars. std::vector aToolBars; maToolBarList.GetToolBarsToActivate(aToolBars); SAL_INFO("sd.view", __func__ << ": ToolBarManager::PostUpdate ["); // Turn on the tool bars that are visible in the new context. for (const auto& aToolBar : aToolBars) { OUString sFullName (GetToolBarResourceName(aToolBar)); SAL_INFO("sd.view", __func__ << ": turning on tool bar " << sFullName); mxLayouter->requestElement(sFullName); maToolBarList.MarkToolBarAsActive(aToolBar); } SAL_INFO("sd.view", __func__ << ": ToolBarManager::PostUpdate ]"); } void ToolBarManager::Implementation::LockViewShellManager() { if (mpViewShellManagerLock == nullptr) mpViewShellManagerLock.reset( new ViewShellManager::UpdateLock(mrBase.GetViewShellManager())); } void ToolBarManager::Implementation::LockUpdate() { SAL_INFO("sd.view", __func__ << ": LockUpdate " << mnLockCount); ::osl::MutexGuard aGuard(maMutex); DBG_ASSERT(mnLockCount<100, "ToolBarManager lock count unusually high"); if (mnLockCount == 0) { OSL_ASSERT(mpSynchronousLayouterLock == nullptr); mpSynchronousLayouterLock.reset(new LayouterLock(mxLayouter)); } ++mnLockCount; } void ToolBarManager::Implementation::UnlockUpdate() { SAL_INFO("sd.view", __func__ << ": UnlockUpdate " << mnLockCount); ::osl::MutexGuard aGuard(maMutex); OSL_ASSERT(mnLockCount>0); --mnLockCount; if (mnLockCount == 0) { Update(std::move(mpSynchronousLayouterLock)); } } void ToolBarManager::Implementation::Update ( ::std::unique_ptr pLocalLayouterLock) { // When the lock is released and there are pending changes to the set of // tool bars then update this set now. if (mnLockCount != 0) return; // During creation of ViewShellBase we may have the situation that // the controller has already been created and attached to the frame // but that the ToolBarManager has not yet completed its // initialization (by initializing the mxLayouter member.) We do // this here so that we do not have to wait for the next Update() // call to show the tool bars. if (mnPendingSetValidCall != nullptr) { Application::RemoveUserEvent(mnPendingSetValidCall); mnPendingSetValidCall = nullptr; SetValid(true); } if (mbIsValid && mxLayouter.is() && (mbPreUpdatePending || mbPostUpdatePending)) { // 1) Release UNO tool bars that are no longer used. Do this // now so that they are not updated when the SFX shell stack is // modified. if (mbPreUpdatePending) PreUpdate(); // 2) Update the requested shells that represent tool bar // functionality. Those that are not used anymore are // deactivated now. Those that are missing are activated in the // next step together with the view shells. if (mpViewShellManagerLock == nullptr) mpViewShellManagerLock.reset( new ViewShellManager::UpdateLock(mrBase.GetViewShellManager())); maToolBarShellList.UpdateShells( mrBase.GetMainViewShell(), mrBase.GetViewShellManager()); // 3) Unlock the ViewShellManager::UpdateLock. This updates the // shell stack. mpViewShellManagerLock.reset(); // 4) Make the UNO tool bars visible. The outstanding call to // PostUpdate() is done via PostUserEvent() so that it is // guaranteed to be executed when the SFX shell stack has been // updated (under the assumption that our lock to the // ViewShellManager was the only one open. If that is not the // case then all should still be well but not as fast.) // Note that the lock count may have been increased since // entering this method. In that case one of the next // UnlockUpdate() calls will post the UpdateCallback. if (mnLockCount==0) { mpAsynchronousLayouterLock = std::move(pLocalLayouterLock); if (mnPendingUpdateCall==nullptr) { mnPendingUpdateCall = Application::PostUserEvent( LINK(this,ToolBarManager::Implementation,UpdateCallback)); } } } else { mpViewShellManagerLock.reset(); pLocalLayouterLock.reset(); } } IMPL_LINK_NOARG(ToolBarManager::Implementation, UpdateCallback, void*, void) { mnPendingUpdateCall = nullptr; if (mnLockCount == 0) { if (mbPreUpdatePending) PreUpdate(); if (mbPostUpdatePending) PostUpdate(); if (mbIsValid && mxLayouter.is()) mpAsynchronousLayouterLock.reset(); } } IMPL_LINK(ToolBarManager::Implementation,EventMultiplexerCallback, sd::tools::EventMultiplexerEvent&, rEvent, void) { SolarMutexGuard g; switch (rEvent.meEventId) { case EventMultiplexerEventId::ControllerAttached: if (mnPendingSetValidCall == nullptr) mnPendingSetValidCall = Application::PostUserEvent(LINK(this,Implementation,SetValidCallback)); break; case EventMultiplexerEventId::ControllerDetached: SetValid(false); break; default: break; } } IMPL_LINK_NOARG(ToolBarManager::Implementation, SetValidCallback, void*, void) { mnPendingSetValidCall = nullptr; SetValid(true); } OUString ToolBarManager::Implementation::GetToolBarResourceName ( std::u16string_view rsBaseName) { return OUString::Concat("private:resource/toolbar/") + rsBaseName; } bool ToolBarManager::Implementation::CheckPlugInMode (std::u16string_view rsName) const { bool bValid (false); // Determine the plug in mode. bool bIsPlugInMode (false); do { SfxObjectShell* pObjectShell = mrBase.GetObjectShell(); if (pObjectShell == nullptr) break; SfxMedium* pMedium = pObjectShell->GetMedium(); if (pMedium == nullptr) break; const SfxBoolItem* pViewOnlyItem = pMedium->GetItemSet().GetItem(SID_VIEWONLY, false); if (pViewOnlyItem == nullptr) break; bIsPlugInMode = pViewOnlyItem->GetValue(); } while (false); if (rsName == msViewerToolBar) bValid = bIsPlugInMode; else bValid = ! bIsPlugInMode; return bValid; } } // end of namespace sd namespace { using namespace ::sd; //===== LayouterLock ========================================================== LayouterLock::LayouterLock (const Reference& rxLayouter) : mxLayouter(rxLayouter) { SAL_INFO("sd.view", __func__ << ": LayouterLock " << (mxLayouter.is() ? 1 :0)); if (mxLayouter.is()) mxLayouter->lock(); } LayouterLock::~LayouterLock() { SAL_INFO("sd.view", __func__ << ": ~LayouterLock " << (mxLayouter.is() ? 1 :0)); if (mxLayouter.is()) mxLayouter->unlock(); } //===== ToolBarRules ========================================================== ToolBarRules::ToolBarRules ( std::shared_ptr pToolBarManager, std::shared_ptr pViewShellManager) : mpToolBarManager(std::move(pToolBarManager)), mpViewShellManager(std::move(pViewShellManager)) { } void ToolBarRules::Update (ViewShellBase const & rBase) { ViewShell* pMainViewShell = rBase.GetMainViewShell().get(); if (pMainViewShell != nullptr) { MainViewShellChanged(pMainViewShell->GetShellType()); if (pMainViewShell->GetView()) SelectionHasChanged (*pMainViewShell, *pMainViewShell->GetView()); } else MainViewShellChanged(ViewShell::ST_NONE); } void ToolBarRules::MainViewShellChanged (ViewShell::ShellType nShellType) { ::sd::ToolBarManager::UpdateLock aToolBarManagerLock (mpToolBarManager); ::sd::ViewShellManager::UpdateLock aViewShellManagerLock (mpViewShellManager); mpToolBarManager->ResetAllToolBars(); switch(nShellType) { case ::sd::ViewShell::ST_IMPRESS: case ::sd::ViewShell::ST_NOTES: case ::sd::ViewShell::ST_HANDOUT: case ::sd::ViewShell::ST_DRAW: mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msToolBar); mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msOptionsToolBar); mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msViewerToolBar); break; case ::sd::ViewShell::ST_NOTESPANEL: mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Permanent, ToolbarId::Draw_Text_Toolbox_Sd); break; case ViewShell::ST_OUTLINE: mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msOutlineToolBar); mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msViewerToolBar); mpToolBarManager->AddToolBarShell( ToolBarManager::ToolBarGroup::Permanent, ToolbarId::Draw_Text_Toolbox_Sd); break; case ViewShell::ST_SLIDE_SORTER: mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msViewerToolBar); mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msSlideSorterToolBar); mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msSlideSorterObjectBar); break; case ViewShell::ST_NONE: case ViewShell::ST_PRESENTATION: case ViewShell::ST_SIDEBAR: default: break; } } void ToolBarRules::MainViewShellChanged (const ViewShell& rMainViewShell) { ::sd::ToolBarManager::UpdateLock aToolBarManagerLock (mpToolBarManager); ::sd::ViewShellManager::UpdateLock aViewShellManagerLock (mpViewShellManager); MainViewShellChanged(rMainViewShell.GetShellType()); switch(rMainViewShell.GetShellType()) { case ::sd::ViewShell::ST_IMPRESS: case ::sd::ViewShell::ST_DRAW: case ::sd::ViewShell::ST_NOTES: { const DrawViewShell* pDrawViewShell = dynamic_cast(&rMainViewShell); if (pDrawViewShell != nullptr) { if (pDrawViewShell->GetEditMode() == EditMode::MasterPage) mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::MasterMode, ToolBarManager::msMasterViewToolBar); else if ( rMainViewShell.GetShellType() != ::sd::ViewShell::ST_DRAW ) mpToolBarManager->AddToolBar( ToolBarManager::ToolBarGroup::CommonTask, ToolBarManager::msCommonTaskToolBar); } break; } default: break; } } void ToolBarRules::SelectionHasChanged ( const ::sd::ViewShell& rViewShell, const SdrView& rView) { ::sd::ToolBarManager::UpdateLock aLock (mpToolBarManager); mpToolBarManager->LockViewShellManager(); bool bTextEdit = rView.IsTextEdit(); mpToolBarManager->ResetToolBars(ToolBarManager::ToolBarGroup::Function); switch (rView.GetContext()) { case SdrViewContext::Graphic: if (!bTextEdit) mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Graf_Toolbox); break; case SdrViewContext::Media: if (!bTextEdit) mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Media_Toolbox); break; case SdrViewContext::Table: mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Table_Toolbox); bTextEdit = true; break; case SdrViewContext::Standard: default: if (!bTextEdit) { switch(rViewShell.GetShellType()) { case ::sd::ViewShell::ST_IMPRESS: case ::sd::ViewShell::ST_DRAW: case ::sd::ViewShell::ST_NOTES: case ::sd::ViewShell::ST_HANDOUT: mpToolBarManager->SetToolBar(ToolBarManager::ToolBarGroup::Function, ToolBarManager::msDrawingObjectToolBar); mpToolBarManager->SetToolBar(ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msToolBar); break; default: break; } break; } } if( bTextEdit ) mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Text_Toolbox_Sd); SdrView* pView = &const_cast(rView); // Check if the extrusion tool bar and the fontwork tool bar have to // be activated. if (svx::checkForSelectedCustomShapes(pView, true /* bOnlyExtruded */ )) mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Svx_Extrusion_Bar); if (svx::checkForSelectedFontWork(pView)) mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Svx_Fontwork_Bar); // Switch on additional context-sensitive tool bars. if (rView.GetContext() == SdrViewContext::PointEdit) mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Bezier_Toolbox_Sd); } void ToolBarRules::SubShellAdded ( ::sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nShellId) { // For some tool bar shells (those defined in sd) we have to add the // actual tool bar here. switch (nShellId) { case ToolbarId::Draw_Graf_Toolbox: mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msGraphicObjectBar); break; case ToolbarId::Draw_Media_Toolbox: mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msMediaObjectBar); break; case ToolbarId::Draw_Text_Toolbox_Sd: mpToolBarManager->RemoveToolBar(ToolBarManager::ToolBarGroup::Permanent, ToolBarManager::msToolBar); mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msTextObjectBar); break; case ToolbarId::Bezier_Toolbox_Sd: mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msBezierObjectBar); break; case ToolbarId::Draw_Table_Toolbox: // tdf#142489 Do not show the table toolbar when the Notebookbar UI is active if (!sfx2::SfxNotebookBar::IsActive(true)) mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msTableObjectBar); break; default: break; } } void ToolBarRules::SubShellRemoved ( ::sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nShellId) { // For some tool bar shells (those defined in sd) we have to add the // actual tool bar here. switch (nShellId) { case ToolbarId::Draw_Graf_Toolbox: mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msGraphicObjectBar); break; case ToolbarId::Draw_Media_Toolbox: mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msMediaObjectBar); break; case ToolbarId::Draw_Text_Toolbox_Sd: mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msTextObjectBar); break; case ToolbarId::Bezier_Toolbox_Sd: mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msBezierObjectBar); break; case ToolbarId::Draw_Table_Toolbox: mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msTableObjectBar); break; default: break; } } //===== ToolBarList =========================================================== ToolBarList::ToolBarList() { } void ToolBarList::ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup) { Groups::iterator iGroup (maGroups.find(eGroup)); if (iGroup != maGroups.end()) { iGroup->second.clear(); } } void ToolBarList::AddToolBar ( sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName) { Groups::iterator iGroup (maGroups.find(eGroup)); if (iGroup == maGroups.end()) iGroup = maGroups.emplace(eGroup,std::vector()).first; if (iGroup != maGroups.end()) { auto iBar (std::find(iGroup->second.cbegin(),iGroup->second.cend(),rsName)); if (iBar == iGroup->second.cend()) { iGroup->second.push_back(rsName); } } } bool ToolBarList::RemoveToolBar ( sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName) { Groups::iterator iGroup (maGroups.find(eGroup)); if (iGroup != maGroups.end()) { auto iBar (std::find(iGroup->second.begin(),iGroup->second.end(),rsName)); if (iBar != iGroup->second.end()) { iGroup->second.erase(iBar); return true; } } return false; } void ToolBarList::MakeRequestedToolBarList (std::vector& rRequestedToolBars) const { for (auto eGroup : o3tl::enumrange()) { Groups::const_iterator iGroup (maGroups.find(eGroup)); if (iGroup != maGroups.end()) rRequestedToolBars.insert( rRequestedToolBars.end(), iGroup->second.begin(), iGroup->second.end() ); } } void ToolBarList::GetToolBarsToActivate (std::vector& rToolBars) const { std::vector aRequestedToolBars; MakeRequestedToolBarList(aRequestedToolBars); for (const auto& aToolBar : aRequestedToolBars) { if (::std::find(maActiveToolBars.begin(),maActiveToolBars.end(),aToolBar) == maActiveToolBars.end()) { rToolBars.push_back(aToolBar); } } } void ToolBarList::GetToolBarsToDeactivate (std::vector& rToolBars) const { std::vector aRequestedToolBars; MakeRequestedToolBarList(aRequestedToolBars); for (auto& aToolBar : maActiveToolBars) { if (::std::find(aRequestedToolBars.begin(),aRequestedToolBars.end(),aToolBar) == aRequestedToolBars.end()) { rToolBars.push_back(aToolBar); } } } void ToolBarList::MarkToolBarAsActive (const OUString& rsName) { maActiveToolBars.push_back(rsName); } void ToolBarList::MarkToolBarAsNotActive (const OUString& rsName) { maActiveToolBars.erase( ::std::find(maActiveToolBars.begin(),maActiveToolBars.end(), rsName)); } void ToolBarList::MarkAllToolBarsAsNotActive() { maActiveToolBars.clear(); } //===== ToolBarShellList ====================================================== ToolBarShellList::ShellDescriptor::ShellDescriptor ( ShellId nId, sd::ToolBarManager::ToolBarGroup eGroup) : mnId(nId), meGroup(eGroup) { } ToolBarShellList::ToolBarShellList() { } void ToolBarShellList::ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup) { for (GroupedShellList::iterator iDescriptor = maNewList.begin(); iDescriptor != maNewList.end(); ) if (iDescriptor->meGroup == eGroup) iDescriptor = maNewList.erase(iDescriptor); else ++iDescriptor; } void ToolBarShellList::AddShellId (sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nId) { // Make sure that the shell is not added twice (and possibly in // different groups.) ShellDescriptor aDescriptor (nId,eGroup); GroupedShellList::iterator iDescriptor (maNewList.find(aDescriptor)); if (iDescriptor != maNewList.end()) { // The shell is already requested. if (iDescriptor->meGroup != eGroup) { // It is now being requested for another group. // (Is this an error?) // Move it to that group. maNewList.erase(iDescriptor); maNewList.insert(aDescriptor); } // else nothing to do. } else maNewList.insert(aDescriptor); } void ToolBarShellList::ReleaseAllShells (ToolBarRules& rRules) { // Release the currently active tool bars. GroupedShellList aList (maCurrentList); for (const auto& rDescriptor : aList) { rRules.SubShellRemoved(rDescriptor.meGroup, rDescriptor.mnId); } // Clear the list of requested tool bars. maNewList.clear(); } void ToolBarShellList::UpdateShells ( const std::shared_ptr& rpMainViewShell, const std::shared_ptr& rpManager) { if (rpMainViewShell == nullptr) return; const std::shared_ptr pCurrentMainViewShell = rpManager->GetOverridingMainShell() ? rpManager->GetOverridingMainShell() : rpMainViewShell; GroupedShellList aList; // Deactivate shells that are in maCurrentList, but not in // maNewList. ::std::set_difference(maCurrentList.begin(), maCurrentList.end(), maNewList.begin(), maNewList.end(), std::insert_iterator(aList,aList.begin())); for (const auto& rShell : aList) { SAL_INFO("sd.view", __func__ << ": deactivating tool bar shell " << static_cast(rShell.mnId)); rpManager->DeactivateSubShell(*pCurrentMainViewShell, rShell.mnId); } // Activate shells that are in maNewList, but not in // maCurrentList. aList.clear(); ::std::set_difference(maNewList.begin(), maNewList.end(), maCurrentList.begin(), maCurrentList.end(), std::insert_iterator(aList,aList.begin())); for (const auto& rShell : aList) { SAL_INFO("sd.view", __func__ << ": activating tool bar shell " << static_cast(rShell.mnId)); rpManager->ActivateSubShell(*pCurrentMainViewShell, rShell.mnId); } // The maNewList now reflects the current state and thus is made // maCurrentList. maCurrentList = maNewList; } } // end of anonymous namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */