29#include <svx/svxids.hrc>
32#include <osl/diagnose.h>
36#include <unordered_map>
54class ShellDescriptor {
59 bool mbIsListenerAddedToWindow;
62 explicit ShellDescriptor (
ShellId nId);
72 explicit IsShell (
const SfxShell* pShell) : mpShell(pShell) {}
73 bool operator() (
const ShellDescriptor& rDescriptor)
74 {
return rDescriptor.mpShell == mpShell; }
86 bool operator() (
const ShellDescriptor& rDescriptor)
87 {
return rDescriptor.mnId ==
mnId; }
156 typedef std::unordered_multimap<const SfxShell*,SharedShellFactory,ShellHash>
168 typedef std::unordered_map<const SfxShell*,SubShellSubList,ShellHash>
SubShellList;
204#if OSL_DEBUG_LEVEL >= 2
240 mpImpl->AddShellFactory(pViewShell, rpFactory);
248 mpImpl->RemoveShellFactory(pViewShell, rpFactory);
254 return mpImpl->ActivateViewShell(pViewShell);
259 if (
mbValid && pShell!=
nullptr)
260 mpImpl->DeactivateViewShell(*pShell);
269 mpImpl->SetFormShell(pParentShell,pFormShell,bAbove);
275 mpImpl->ActivateSubShell(rViewShell,
nId);
281 mpImpl->DeactivateSubShell(rViewShell,
nId);
287 mpImpl->InvalidateAllSubShells(pViewShell);
292 if (
mbValid && pShell!=
nullptr)
293 mpImpl->ActivateShell(*pShell);
298 if (
mbValid && pShell!=
nullptr)
299 mpImpl->DeactivateShell(*pShell);
305 mpImpl->MoveToTop(rParentShell);
319 return mpImpl->GetTopShell();
327 return mpImpl->GetTopViewShell();
356 mnUpdateLockCount(0),
357 mbShellStackIsUpToDate(true),
358 mpFormShell(nullptr),
359 mpFormShellParent(nullptr),
360 mbFormShellAboveParent(true),
362 mpTopViewShell(nullptr)
374 bool bAlreadyAdded (
false);
377 ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
378 maShellFactories.equal_range(pViewShell));
379 for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
380 if (iFactory->second == rpFactory)
382 bAlreadyAdded =
true;
387 if ( ! bAlreadyAdded)
388 maShellFactories.emplace(pViewShell, rpFactory);
395 ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
396 maShellFactories.equal_range(pViewShell));
397 for (FactoryList::iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
398 if (iFactory->second == rpFactory)
400 maShellFactories.erase(iFactory);
407 ::osl::MutexGuard aGuard (
maMutex);
409 ShellDescriptor aResult;
410 aResult.mpShell = pViewShell;
414 if (aResult.mpShell !=
nullptr)
417 if (pWindow !=
nullptr)
421 aResult.mbIsListenerAddedToWindow =
true;
426 "ViewShellManager::ActivateViewShell: "
427 "new view shell has no active window");
436 ::osl::MutexGuard aGuard (
maMutex);
438 ActiveShellList::iterator iShell (::std::find_if (
439 maActiveViewShells.begin(),
440 maActiveViewShells.end(),
442 if (iShell == maActiveViewShells.end())
447 ShellDescriptor aDescriptor(*iShell);
448 mrBase.GetDocShell()->Disconnect(
dynamic_cast<ViewShell*
>(aDescriptor.mpShell));
449 maActiveViewShells.erase(iShell);
450 TakeShellsFromStack(aDescriptor.mpShell);
453 SubShellList::iterator iList (maActiveSubShells.find(&rShell));
454 if (iList != maActiveSubShells.end())
457 while ( ! rList.empty())
461 DestroyViewShell(aDescriptor);
466 ::osl::MutexGuard aGuard (
maMutex);
469 ShellDescriptor aDescriptor;
470 aDescriptor.mpShell = &rShell;
478 if (rDescriptor.mpShell !=
nullptr)
480 maActiveViewShells.insert( maActiveViewShells.begin(), rDescriptor);
486 ::osl::MutexGuard aGuard (
maMutex);
488 ActiveShellList::iterator iShell (::std::find_if (
489 maActiveViewShells.begin(),
490 maActiveViewShells.end(),
492 if (iShell == maActiveViewShells.end())
497 ShellDescriptor aDescriptor(*iShell);
498 mrBase.GetDocShell()->Disconnect(
dynamic_cast<ViewShell*
>(aDescriptor.mpShell));
499 maActiveViewShells.erase(iShell);
500 TakeShellsFromStack(aDescriptor.mpShell);
503 SubShellList::iterator iList (maActiveSubShells.find(&rShell));
504 if (iList != maActiveSubShells.end())
507 while ( ! rList.empty())
511 DestroyViewShell(aDescriptor);
518 ::osl::MutexGuard aGuard (
maMutex);
521 if (std::none_of (maActiveViewShells.begin(), maActiveViewShells.end(), IsShell(&rParentShell)))
525 SubShellList::iterator iList (maActiveSubShells.find(&rParentShell));
526 if (iList == maActiveSubShells.end())
527 iList = maActiveSubShells.emplace(&rParentShell,
SubShellSubList()).first;
532 if (std::any_of(rList.begin(),rList.end(), IsId(
nId)))
538 rList.emplace_back(
nId);
545 ::osl::MutexGuard aGuard (
maMutex);
548 SubShellList::iterator iList (maActiveSubShells.find(&rParentShell));
549 if (iList == maActiveSubShells.end())
554 SubShellSubList::iterator iShell (
555 ::std::find_if(rList.begin(),rList.end(), IsId(
nId)));
556 if (iShell == rList.end())
559 if (pShell ==
nullptr)
564 ShellDescriptor aDescriptor(*iShell);
568 TakeShellsFromStack(pShell);
570 DestroySubShell(aDescriptor);
575 ::osl::MutexGuard aGuard (
maMutex);
582 if (mrBase.GetDispatcher() ==
nullptr)
585 ActiveShellList::iterator iShell (::std::find_if (
586 maActiveViewShells.begin(),
587 maActiveViewShells.end(),
590 if (iShell != maActiveViewShells.end())
596 if (iShell == maActiveViewShells.begin())
618 ShellDescriptor aDescriptor(*iShell);
620 TakeShellsFromStack(&rShell);
621 maActiveViewShells.erase(iShell);
623 maActiveViewShells.insert(maActiveViewShells.begin(), aDescriptor);
629 ::osl::MutexGuard aGuard (
maMutex);
634 ActiveShellList::const_iterator iShell (
636 maActiveViewShells.begin(),
637 maActiveViewShells.end(),
639 if (iShell != maActiveViewShells.end())
640 pShell = iShell->mpShell;
644 for (
auto const& activeSubShell : maActiveSubShells)
647 SubShellSubList::const_iterator iSubShell(
648 ::std::find_if(rList.begin(),rList.end(), IsId(
nId)));
649 if (iSubShell != rList.end())
651 pShell = iSubShell->mpShell;
662 OSL_ASSERT(mpTopShell == mrBase.GetSubShell(0));
668 return mpTopViewShell;
678 ::osl::MutexGuard aGuard (
maMutex);
681 if (mnUpdateLockCount < 0)
684 OSL_ASSERT (mnUpdateLockCount>=0);
685 mnUpdateLockCount = 0;
687 if (mnUpdateLockCount == 0)
703 ::osl::MutexGuard aGuard (
maMutex);
706 SfxShell* pTopMostShell = mrBase.GetSubShell(0);
715 mpTopViewShell = (maActiveViewShells.empty())
716 ?
nullptr : maActiveViewShells.begin()->mpShell;
721 CreateTargetStack(aTargetStack);
726 while (mrBase.GetSubShell(
nIndex)!=
nullptr)
728 aSfxShellStack.reserve(
nIndex);
730 aSfxShellStack.push_back(mrBase.GetSubShell(
nIndex));
732#if OSL_DEBUG_LEVEL >= 2
733 SAL_INFO(
"sd.view", __func__ <<
": Current SFX Stack");
734 DumpShellStack(aSfxShellStack);
735 SAL_INFO(
"sd.view", __func__ <<
": Target Stack");
736 DumpShellStack(aTargetStack);
740 auto mismatchIters = std::mismatch(aSfxShellStack.begin(), aSfxShellStack.end(),
741 aTargetStack.begin(), aTargetStack.end());
742 ShellStack::iterator iSfxShell (mismatchIters.first);
743 ShellStack::iterator iTargetShell (mismatchIters.second);
747 for (std::reverse_iterator<ShellStack::const_iterator>
i(aSfxShellStack.end()), iLast(iSfxShell);
751 SAL_INFO(
"sd.view", __func__ <<
": removing shell " << pShell <<
" from stack");
752 mrBase.RemoveSubShell(pShell);
754 aSfxShellStack.erase(iSfxShell, aSfxShellStack.end());
757 mbShellStackIsUpToDate =
false;
758 while (iTargetShell != aTargetStack.end())
760 SAL_INFO(
"sd.view", __func__ <<
": pushing shell " << *iTargetShell <<
" on stack");
761 mrBase.AddSubShell(**iTargetShell);
767 if (mbShellStackIsUpToDate)
770 if (mrBase.GetDispatcher() !=
nullptr)
771 mrBase.GetDispatcher()->Flush();
775 mpTopShell = mrBase.GetSubShell(0);
776 if (mpTopShell!=
nullptr && pUndoManager!=
nullptr && mpTopShell->GetUndoManager()==
nullptr)
777 mpTopShell->SetUndoManager(pUndoManager);
781 mbShellStackIsUpToDate =
true;
783#if OSL_DEBUG_LEVEL >= 2
784 SAL_INFO(
"sd.view", __func__ <<
": New current stack");
791 ::osl::MutexGuard aGuard (
maMutex);
794 SfxShell* pTopMostShell = mrBase.GetSubShell(0);
799#if OSL_DEBUG_LEVEL >= 2
800 SAL_INFO(
"sd.view", __func__ <<
"TakeShellsFromStack( " << pShell <<
")");
809 if (pShellOnStack ==
nullptr)
816 else if (pShellOnStack == pShell)
820 if (pShell ==
nullptr)
828 Deactivate(pShellOnStack);
829 if (pShellOnStack == pShell)
836 SfxShell* pShellOnStack = mrBase.GetSubShell(0);
837 SAL_INFO(
"sd.view", __func__ <<
"removing shell " << pShellOnStack <<
" from stack");
838 mrBase.RemoveSubShell(pShellOnStack);
839 if (pShellOnStack == pShell)
844 if (mrBase.GetDispatcher() !=
nullptr)
845 mrBase.GetDispatcher()->Flush();
849 mpTopShell = mrBase.GetSubShell(0);
850 if (mpTopShell!=
nullptr && pUndoManager!=
nullptr && mpTopShell->GetUndoManager()==
nullptr)
851 mpTopShell->SetUndoManager(pUndoManager);
853#if OSL_DEBUG_LEVEL >= 2
854 SAL_INFO(
"sd.view", __func__ <<
"Sfx shell stack is:");
861 ::osl::MutexGuard aGuard (
maMutex);
864 ActiveShellList::reverse_iterator iShell;
865 for (iShell=maActiveViewShells.rbegin(); iShell!=maActiveViewShells.rend(); ++iShell)
868 SubShellList::iterator iList (maActiveSubShells.find(iShell->mpShell));
869 if (iList != maActiveSubShells.end())
874 for (
auto & subShell : rList)
876 if (subShell.mpShell ==
nullptr)
878 subShell = CreateSubShell(iShell->mpShell,subShell.mnId);
890 for (ActiveShellList::const_reverse_iterator iViewShell (maActiveViewShells.rbegin());
891 iViewShell != maActiveViewShells.rend();
895 if ( ! mbFormShellAboveParent
896 && mpFormShell!=
nullptr
897 && iViewShell->mpShell==mpFormShellParent)
899 rStack.push_back(mpFormShell);
903 rStack.push_back (iViewShell->mpShell);
906 if (mbFormShellAboveParent
907 && mpFormShell!=
nullptr
908 && iViewShell->mpShell==mpFormShellParent)
910 rStack.push_back(mpFormShell);
914 SubShellList::const_iterator iList (maActiveSubShells.find(iViewShell->mpShell));
915 if (iList != maActiveSubShells.end())
918 SubShellSubList::const_reverse_iterator iSubShell;
919 for (iSubShell=rList.rbegin(); iSubShell!=rList.rend(); ++iSubShell)
920 if (iSubShell->mpShell != mpFormShell)
921 rStack.push_back(iSubShell->mpShell);
930 switch (rEvent.GetId())
932 case VclEventId::WindowGetFocus:
934 for (
auto const& activeShell : maActiveViewShells)
936 if (pEventWindow == activeShell.
GetWindow())
945 case VclEventId::WindowLoseFocus:
948 case VclEventId::ObjectDying:
951 for (
auto & activeViewShell : maActiveViewShells)
953 if (activeViewShell.GetWindow() == pEventWindow)
955 activeViewShell.mbIsListenerAddedToWindow =
false;
969 ::osl::MutexGuard aGuard (
maMutex);
970 ShellDescriptor aResult;
973 ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
974 maShellFactories.equal_range(pParentShell));
977 for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
980 if (pFactory !=
nullptr)
981 aResult.mpShell = pFactory->CreateShell(nShellId);
984 if (aResult.mpShell !=
nullptr)
986 aResult.mpFactory = pFactory;
987 aResult.mnId = nShellId;
996 ShellDescriptor& rDescriptor)
998 OSL_ASSERT(rDescriptor.mpShell !=
nullptr);
1000 if (rDescriptor.mbIsListenerAddedToWindow)
1002 rDescriptor.mbIsListenerAddedToWindow =
false;
1004 if (pWindow !=
nullptr)
1012 ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
1013 maShellFactories.equal_range(rDescriptor.mpShell));
1014 if (aRange.first != maShellFactories.end())
1015 maShellFactories.erase(aRange.first, aRange.second);
1018 if (rDescriptor.mpFactory)
1019 rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell);
1023 const ShellDescriptor& rDescriptor)
1025 OSL_ASSERT(rDescriptor.mpFactory);
1026 rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell);
1031 ::osl::MutexGuard aGuard (
maMutex);
1033 SubShellList::iterator iList (maActiveSubShells.find(pParentShell));
1034 if (iList != maActiveSubShells.end())
1037 for (
auto const&
shell : rList)
1038 if (
shell.mpShell !=
nullptr)
1039 shell.mpShell->Invalidate();
1045 ::osl::MutexGuard aGuard (
maMutex);
1048 if ( ! maActiveViewShells.empty())
1052 while ( ! maActiveViewShells.empty())
1054 SfxShell* pShell = maActiveViewShells.front().mpShell;
1055 if (pShell !=
nullptr)
1058 if (pViewShell !=
nullptr)
1066 "ViewShellManager::Implementation::Shutdown(): empty active shell descriptor");
1067 maActiveViewShells.pop_front();
1071 mrBase.RemoveSubShell ();
1073 maShellFactories.clear();
1076#if OSL_DEBUG_LEVEL >= 2
1079 ShellStack::const_reverse_iterator iEntry;
1080 for (iEntry=rStack.rbegin(); iEntry!=rStack.rend(); ++iEntry)
1081 if (*iEntry !=
NULL)
1082 SAL_INFO(
"sd.view", __func__ <<
": " <<
1084 (*iEntry)->GetName());
1086 SAL_INFO(
"sd.view", __func__ <<
" null");
1095 aSfxShellStack.reserve(
nIndex);
1097 aSfxShellStack.push_back(mrBase.GetSubShell(
nIndex));
1098 DumpShellStack(aSfxShellStack);
1104 OSL_ASSERT(pShell!=
nullptr);
1109 if (pViewShell !=
nullptr)
1118 SfxCallMode::ASYNCHRON);
1129 bool bFormShellAboveParent)
1131 ::osl::MutexGuard aGuard (
maMutex);
1133 mpFormShellParent = pFormShellParent;
1134 mpFormShell = pFormShell;
1135 mbFormShellAboveParent = bFormShellAboveParent;
1140ShellDescriptor::ShellDescriptor()
1143 mbIsListenerAddedToWindow(false)
1147ShellDescriptor::ShellDescriptor (
1151 mbIsListenerAddedToWindow(false)
1157 ViewShell* pViewShell =
dynamic_cast<ViewShell*
>(mpShell);
1158 if (pViewShell !=
nullptr)
1159 return pViewShell->GetActiveWindow();
virtual bool IsTextEdit() const final override
const SfxPoolItem * Execute(sal_uInt16 nSlot, SfxCallMode nCall=SfxCallMode::SLOT, const SfxPoolItem **pArgs=nullptr, sal_uInt16 nModi=0, const SfxPoolItem **pInternalArgs=nullptr)
virtual void Deactivate(bool bMDI)
virtual SfxUndoManager * GetUndoManager()
SfxDispatcher * GetDispatcher()
SfxViewShell descendant that the stacked Draw/Impress shells are based on.
size_t operator()(const SfxShell *p) const
~UpdateLock() COVERITY_NOEXCEPT_FALSE
UpdateLock(Implementation &rImpl)
void TakeShellsFromStack(const SfxShell *pShell)
Remove all shells from the SFX stack above and including the given shell.
void AddShellFactory(const SfxShell *pViewShell, const SharedShellFactory &rpFactory)
std::list< ShellDescriptor > ActiveShellList
List of the active view shells.
static void DestroySubShell(const ShellDescriptor &rDescriptor)
ActiveShellList maActiveViewShells
std::unordered_map< const SfxShell *, SubShellSubList, ShellHash > SubShellList
SubShellList maActiveSubShells
void DumpShellStack(const ShellStack &rStack)
FactoryList maShellFactories
bool mbFormShellAboveParent
const ViewShell * mpFormShellParent
void InvalidateAllSubShells(const SfxShell *pParentShell)
DECL_LINK(WindowEventHandler, VclWindowEvent &, void)
void ActivateShell(SfxShell &rShell)
void RemoveShellFactory(const SfxShell *pViewShell, const SharedShellFactory &rpFactory)
void SetFormShell(const ViewShell *pViewShell, FmFormShell *pFormShell, bool bAbove)
::std::vector< SfxShell * > ShellStack
In this member we remember what shells we have pushed on the shell stack.
SfxShell * mpTopViewShell
void CreateTargetStack(ShellStack &rStack) const
This method rebuilds the stack of shells that are stacked upon the view shell base.
mutable::osl::Mutex maMutex
void DeactivateSubShell(const SfxShell &rParentShell, ShellId nId)
void UpdateShellStack()
Update the SFX shell stack (the portion that is visible to us) so that it matches the internal shell ...
void DeactivateViewShell(const ViewShell &rShell)
void MoveToTop(const SfxShell &rParentShell)
SfxShell * GetTopShell() const
void ActivateViewShell(ViewShell *pViewShell)
void DestroyViewShell(ShellDescriptor &rDescriptor)
std::list< ShellDescriptor > SubShellSubList
Implementation(ViewShellBase &rBase)
void DeactivateShell(const SfxShell &rShell)
~Implementation() COVERITY_NOEXCEPT_FALSE
ShellDescriptor CreateSubShell(SfxShell const *pShell, ShellId nShellId)
std::unordered_multimap< const SfxShell *, SharedShellFactory, ShellHash > FactoryList
void UnlockUpdate()
Allow updates of the shell stack.
void LockUpdate()
Prevent updates of the shell stack.
bool mbShellStackIsUpToDate
The UpdateShellStack() method can be called recursively.
SfxShell * GetTopViewShell() const
void ActivateSubShell(const SfxShell &rParentShell, ShellId nId)
static void Deactivate(SfxShell *pShell)
To be called before a shell is taken from the SFX shell stack.
SfxShell * GetShell(ShellId nId) const
std::shared_ptr< ShellFactory< SfxShell > > SharedShellFactory
void ActivateShell(SfxShell *pShell)
Activate the given shell which is not a view shell.
std::unique_ptr< ViewShellManager::Implementation, o3tl::default_delete< ViewShellManager::Implementation > > mpImpl
void DeactivateSubShell(const ViewShell &rParentShell, ShellId nId)
Deactivate the specified sub shell.
void AddSubShellFactory(ViewShell const *pViewShell, const SharedShellFactory &rpFactory)
Set the factory for sub shells of the specified view shell.
SfxShell * GetShell(ShellId nId) const
Return the first, i.e.
void DeactivateViewShell(const ViewShell *pShell)
Deactivate the specified shell, i.e.
~ViewShellManager()
Before the destructor is called the method Shutdown() has to have been called.
ViewShellManager(ViewShellBase &rBase)
SfxShell * GetTopViewShell() const
Return the top-most active view shell on the internal shell stack.
void InvalidateAllSubShells(ViewShell const *pViewShell)
Send all sub shells of the specified view shell an Invalidate() call.
void DeactivateShell(const SfxShell *pShell)
Deactivate the specified shell.
void Shutdown()
Tell a ViewShellManager object to prepare to be deleted, i.e.
void ActivateViewShell(ViewShell *pViewShell)
Activate the given view shell.
void RemoveSubShellFactory(ViewShell const *pViewShell, const SharedShellFactory &rpFactory)
void ActivateSubShell(const ViewShell &rParentShell, ShellId nId)
Activate the specified shell as sub shell for the given view shell.
void MoveToTop(const ViewShell &rShell)
Move the specified view shell to the top most position on the stack of view shells in relation to the...
void SetFormShell(const ViewShell *pParentShell, FmFormShell *pFormShell, bool bAbove)
Associate the form shell with a view shell and their relative position.
SfxShell * GetTopShell() const
Return the top-most shell on the SFX shell stack regardless of whether that is a view shell or a sub ...
Base class of the stacked shell hierarchy.
::sd::View * GetView() const
SD_DLLPUBLIC SfxViewFrame * GetViewFrame() const
virtual SdrEndTextEditKind SdrEndTextEdit(bool bDontDeleteReally=false) override
ends current text editing
void RemoveEventListener(const Link< VclWindowEvent &, void > &rEventListener)
vcl::Window * GetWindow(GetWindowType nType) const
void AddEventListener(const Link< VclWindowEvent &, void > &rEventListener)
#define LINK(Instance, Class, Member)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
IMPL_LINK(SdCharHeightPropertyBox, implMenuSelectHdl, const OUString &, rIdent, void)