diff options
author | Oliver Bolte <obo@openoffice.org> | 2005-01-28 15:33:16 +0000 |
---|---|---|
committer | Oliver Bolte <obo@openoffice.org> | 2005-01-28 15:33:16 +0000 |
commit | 07c49e9c4dbd21f29be8530127d85d4b61d3dbf9 (patch) | |
tree | fc0e5bbb848f74998fca4c96d5a05a63cec633db /sd/source/ui/view/ViewShellManager.cxx | |
parent | 6f3f44a132b773802c175fec00a656be66afeff9 (diff) |
INTEGRATION: CWS impress20 (1.4.28); FILE MERGED
2005/01/12 14:23:33 af 1.4.28.9: RESYNC: (1.7-1.8); FILE MERGED
2004/12/17 11:12:57 af 1.4.28.8: #118543# Added #ifdefs around OSL_TRACEs.
2004/12/16 17:26:22 af 1.4.28.7: #i37354# Reverted mbKeepMainViewShellOnTop to correct 'false' default value.
2004/12/16 17:04:49 af 1.4.28.6: #i33487# Corrected order of shells pushed on stack to remove merge problem.
2004/12/16 14:52:19 af 1.4.28.5: Resolved merge problem.
2004/12/10 15:35:06 af 1.4.28.4: RESYNC: (1.6-1.7); FILE MERGED
2004/12/10 15:16:43 af 1.4.28.3: Resolved merge problems.
2004/12/07 17:27:42 af 1.4.28.2: RESYNC: (1.4-1.6); FILE MERGED
2004/11/23 17:46:47 af 1.4.28.1: #118543# Introduction of inner Implementation class. Major modification of how the internal and the SFX shell stacks are synchronized.
Diffstat (limited to 'sd/source/ui/view/ViewShellManager.cxx')
-rwxr-xr-x | sd/source/ui/view/ViewShellManager.cxx | 725 |
1 files changed, 520 insertions, 205 deletions
diff --git a/sd/source/ui/view/ViewShellManager.cxx b/sd/source/ui/view/ViewShellManager.cxx index ae0f05400776..fb322f6a95b4 100755 --- a/sd/source/ui/view/ViewShellManager.cxx +++ b/sd/source/ui/view/ViewShellManager.cxx @@ -2,9 +2,9 @@ * * $RCSfile: ViewShellManager.cxx,v $ * - * $Revision: 1.9 $ + * $Revision: 1.10 $ * - * last change: $Author: obo $ $Date: 2005-01-25 15:19:43 $ + * last change: $Author: obo $ $Date: 2005-01-28 16:33:16 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -77,23 +77,20 @@ #include <hash_map> +#undef VERBOSE namespace sd { -class ViewShellManager::SpecializedFactoryList - : public ::std::hash_map<ShellId, ViewShellFactory*>{}; +namespace { + class ActiveShellDescriptor { public: ActiveShellDescriptor (ViewShell* pViewShell, ShellId nId) - : mpViewShell(pViewShell), mnId(nId), mbIsOnStack(false) {} + : mpViewShell(pViewShell), mnId(nId) {} ViewShell* mpViewShell; ShellId mnId; - bool mbIsOnStack; }; -class ViewShellManager::ActiveShellList - : public ::std::list<ActiveShellDescriptor>{}; -namespace { class IsShell { public: @@ -104,6 +101,7 @@ public: } const ViewShell* mpShell; }; + class IsId { public: @@ -115,31 +113,117 @@ public: ShellId mnId; }; -#define TRACE_ACTIVE_SHELLS \ - {ActiveShellList::const_iterator aI (mpActiveViewShells->begin());\ - for (; aI!=mpActiveViewShells->end(); ++aI) { \ - OSL_TRACE (" %d %p", aI->mnId, aI->mpViewShell); } } +} // end of anonymous namespace -} +class ViewShellManager::Implementation +{ +public: + Implementation ( + ViewShellManager& rManager, + ViewShellBase& rBase); + ~Implementation (void); + + void RegisterDefaultFactory (::std::auto_ptr<ViewShellFactory> pFactory); + void RegisterFactory ( + ShellId nId, + ::std::auto_ptr<ViewShellFactory> pFactory); + ViewShell* ActivateViewShell ( + ShellId nId, + ::Window* pParentWindow, + FrameView* pFrameView); + void DeactivateViewShell (const ViewShell* pShell); + void MoveToTop (const ViewShell* pShell); + ViewShell* GetShell (ShellId nId); + ShellId GetShellId (const ViewShell* pShell); + ViewShellBase& GetViewShellBase (void) const; + void Shutdown (void); + ViewShell* CreateViewShell ( + ShellId nShellId, + ::Window* pParentWindow, + FrameView* pFrameView); + + /** Remove all shells from the SFX stack above and including the given + shell. + */ + void TakeShellsFromStack (const SfxShell* pShell); + + /** Prevent updates of the shell stack. While the sub shell manager is + locked it will update its internal data structures but not alter the + shell stack. Use this method when there are several modifications + to the shell stack to prevent multiple rebuilds of the shell stack + and resulting broadcasts. + */ + void LockUpdate (void); + + /** Allow updates of the shell stack. This method has to be called the + same number of times as LockUpdate() to really allow a rebuild of + the shell stack. + */ + void UnlockUpdate (void); + +private: + ViewShellBase& mrBase; + + ::std::auto_ptr<ViewShellFactory> mpDefaultFactory; + + typedef ::std::hash_map<ShellId,ViewShellFactory*> SpecializedFactoryList; + SpecializedFactoryList maSpecializedFactories; + + /** List of the active view shells. In order to create gather all shells + to put on the shell stack each view shell in this list is asked for + its sub-shells (typically toolbars). + */ + typedef ::std::list<ActiveShellDescriptor> ActiveShellList; + ActiveShellList maActiveViewShells; + + /** In this member we remember what shells we have pushed on the shell + stack. + */ + typedef ::std::vector<SfxShell*> ShellStack; + + ViewShellCache maCache; + + int mnUpdateLockCount; + + /** When this flag is set then the main view shell is always kept at the + top of the shell stack. + */ + bool mbKeepMainViewShellOnTop; + + /** The PushShellsOnStack() method can be called recursively. This flag + is used to communicate between different levels of invocation: if + the stack has been updated in an inner call the outer call can (has + to) stop and return immediately. + */ + bool mbShellStackIsUpToDate; + + void GatherActiveShells (ShellStack& rShellList); + + /** This method rebuilds the stack of shells that are stacked upon the + view shell base. + */ + void PushShellsOnStack (void); + + DECL_LINK(WindowEventHandler, VclWindowEvent*); + + void DumpActiveShell (const ActiveShellList& rList); + void DumpShellStack (const ShellStack& rStack); + void DumpSfxShellStack (void); + + void UpdateShellStack (ShellStack& rRequestedStack); +}; + + + + +//===== ViewShellManager ====================================================== ViewShellManager::ViewShellManager (ViewShellBase& rBase) - : mrBase(rBase), - mpDefaultFactory (NULL), - mpSpecializedFactories ( - ::std::auto_ptr<SpecializedFactoryList>( - new SpecializedFactoryList())), - mpActiveViewShells( - ::std::auto_ptr<ActiveShellList>( - new ActiveShellList())), - mpCache (new ViewShellCache(*this)), - mnUpdateLockCount(0), - mbKeepMainViewShellOnTop(false), - mbIsValid (true), - mbTakeShellsFromStackPending(false), - mbShellStackIsUpToDate(true) + : mpImpl(new Implementation(*this,rBase)), + mbValid(true) { } @@ -148,49 +232,155 @@ ViewShellManager::ViewShellManager (ViewShellBase& rBase) ViewShellManager::~ViewShellManager (void) { - // Shutdown() should have been called by now but since it is safe to be - // called twice we call it again just in case. It is, however, unlikely - // that this does work without crashing. - DBG_ASSERT (mpCache.get()==NULL, - "ViewShellManager::Shutdown() has to be called prior to destructor"); - Shutdown(); } -void ViewShellManager::Shutdown (void) +void ViewShellManager::RegisterDefaultFactory ( + ::std::auto_ptr<ViewShellFactory> pFactory) { - // Take stacked shells from stack. - if ( ! mpActiveViewShells->empty()) - { - UpdateLocker aLock (*this); + if (mbValid) + mpImpl->RegisterDefaultFactory(pFactory); +} - while ( ! mpActiveViewShells->empty()) - { - DeactivateViewShell(mpActiveViewShells->front().mpViewShell); - } - } - mrBase.RemoveSubShell (NULL); - // We have the ownership of the factories and because they can not be - // auto_ptrs in an stl list we have to delete them now by hand. - for (SpecializedFactoryList::iterator aI (mpSpecializedFactories->begin()); - aI!=mpSpecializedFactories->end(); - aI++) + + +void ViewShellManager::RegisterFactory ( + ShellId nId, + ::std::auto_ptr<ViewShellFactory> pFactory) +{ + if (mbValid) + mpImpl->RegisterFactory(nId,pFactory); +} + + + + +ViewShell* ViewShellManager::ActivateViewShell ( + ShellId nShellId, + ::Window* pParentWindow, + FrameView* pFrameView) +{ + if (mbValid) + return mpImpl->ActivateViewShell(nShellId,pParentWindow,pFrameView); + else + return NULL; +} + + + + +void ViewShellManager::DeactivateViewShell (const ViewShell* pShell) +{ + if (mbValid) + mpImpl->DeactivateViewShell(pShell); +} + + + + +void ViewShellManager::InvalidateShellStack (const SfxShell* pShell) +{ + if (mbValid) + mpImpl->TakeShellsFromStack(pShell); +} + + + + +void ViewShellManager::MoveToTop (const ViewShell* pShell) +{ + if (mbValid) + mpImpl->MoveToTop(pShell); +} + + + + +ViewShell* ViewShellManager::GetShell (ShellId nId) +{ + if (mbValid) + return mpImpl->GetShell(nId); + else + return NULL; +} + + + + +ShellId ViewShellManager::GetShellId (const ViewShell* pShell) +{ + if (mbValid) + return mpImpl->GetShellId(pShell); + else + return snInvalidShellId; +} + + + + +ViewShellBase& ViewShellManager::GetViewShellBase (void) const +{ + return mpImpl->GetViewShellBase(); +} + + + + +void ViewShellManager::Shutdown (void) +{ + if (mbValid) { - delete aI->second; + mpImpl->Shutdown(); + mbValid = false; } +} - // Destroy members. - mpCache.reset(); - mpDefaultFactory.reset(); + + + +ViewShell* ViewShellManager::CreateViewShell ( + ShellId nShellId, + ::Window* pParentWindow, + FrameView* pFrameView) +{ + if (mbValid) + return mpImpl->CreateViewShell(nShellId,pParentWindow,pFrameView); + else + return NULL; } -void ViewShellManager::RegisterDefaultFactory ( +//===== ViewShellManager::Implementation ====================================== + +ViewShellManager::Implementation::Implementation ( + ViewShellManager& rManager, + ViewShellBase& rBase) + : mrBase(rBase), + mpDefaultFactory (NULL), + maSpecializedFactories (), + maActiveViewShells(), + maCache (rManager), + mnUpdateLockCount(0), + mbKeepMainViewShellOnTop(false), + mbShellStackIsUpToDate(true) +{ +} + + + + +ViewShellManager::Implementation::~Implementation (void) +{ + Shutdown(); +} + + +void ViewShellManager::Implementation::RegisterDefaultFactory ( ::std::auto_ptr<ViewShellFactory> pFactory) { mpDefaultFactory = pFactory; @@ -199,26 +389,24 @@ void ViewShellManager::RegisterDefaultFactory ( -void ViewShellManager::RegisterFactory ( +void ViewShellManager::Implementation::RegisterFactory ( ShellId nId, ::std::auto_ptr<ViewShellFactory> pFactory) { - (*mpSpecializedFactories)[nId] = pFactory.get(); + maSpecializedFactories[nId] = pFactory.get(); pFactory.release(); } -ViewShell* ViewShellManager::ActivateViewShell ( +ViewShell* ViewShellManager::Implementation::ActivateViewShell ( ShellId nShellId, ::Window* pParentWindow, FrameView* pFrameView) { - PrepareStackModification(); - // Create a new shell or recycle on in the cache. - ViewShell* pViewShell = mpCache->GetViewShell ( + ViewShell* pViewShell = maCache.GetViewShell ( nShellId, pParentWindow, pFrameView); @@ -231,7 +419,7 @@ ViewShell* ViewShellManager::ActivateViewShell ( pWindow->AddEventListener( LINK( this, - ViewShellManager, + ViewShellManager::Implementation, WindowEventHandler)); else { @@ -245,15 +433,15 @@ ViewShell* ViewShellManager::ActivateViewShell ( // displayed in the center pane then it is inserted at the position // one below the top. ActiveShellList::iterator iInsertPosition ( - mpActiveViewShells->begin()); - if (iInsertPosition != mpActiveViewShells->end() + maActiveViewShells.begin()); + if (iInsertPosition != maActiveViewShells.end() && mbKeepMainViewShellOnTop && ! pViewShell->IsMainViewShell() && iInsertPosition->mpViewShell->IsMainViewShell()) { ++iInsertPosition; } - mpActiveViewShells->insert( + maActiveViewShells.insert( iInsertPosition, ActiveShellDescriptor(pViewShell, nShellId)); } @@ -264,58 +452,46 @@ ViewShell* ViewShellManager::ActivateViewShell ( -void ViewShellManager::DeactivateViewShell (const ViewShell* pShell) +void ViewShellManager::Implementation::DeactivateViewShell (const ViewShell* pShell) { - PrepareStackModification (); - ActiveShellList::iterator aI (::std::find_if ( - mpActiveViewShells->begin(), - mpActiveViewShells->end(), + maActiveViewShells.begin(), + maActiveViewShells.end(), IsShell(pShell))); - if (aI != mpActiveViewShells->end()) + if (aI != maActiveViewShells.end()) { - UpdateLocker aLocker (*this); + UpdateLock aLocker (*this); ViewShell* pViewShell = aI->mpViewShell; pViewShell->GetObjectBarManager().Clear(); - mpActiveViewShells->erase (aI); + maActiveViewShells.erase (aI); pViewShell->GetActiveWindow()->RemoveEventListener( LINK( this, - ViewShellManager, + ViewShellManager::Implementation, WindowEventHandler)); - mrBase.RemoveSubShell(pViewShell); - mpCache->ReleaseViewShell (pViewShell); + TakeShellsFromStack(pViewShell); + maCache.ReleaseViewShell (pViewShell); } } -void ViewShellManager::InvalidateShellStack (void) -{ - // Call PrepareStackModification() to force a PushShellsOnStack() at the - // next UnlockUpdate() to lock level 0. - PrepareStackModification (); -} - - - - -void ViewShellManager::MoveToTop (const ViewShell* pShell) +void ViewShellManager::Implementation::MoveToTop (const ViewShell* pShell) { ActiveShellList::iterator aI (::std::find_if ( - mpActiveViewShells->begin(), - mpActiveViewShells->end(), + maActiveViewShells.begin(), + maActiveViewShells.end(), IsShell(pShell))); bool bMove = true; - if (aI != mpActiveViewShells->end()) + if (aI != maActiveViewShells.end()) { // Is the shell already at the top of the stack? We have to keep // the case in mind that mbKeepMainViewShellOnTop is true. Shells // that are not the main view shell are placed on the second-to-top // position in this case. - if (aI == mpActiveViewShells->begin() + if (aI == maActiveViewShells.begin() && (aI->mpViewShell->IsMainViewShell() || ! mbKeepMainViewShellOnTop)) { // The shell is at the top position and is either a) the main @@ -323,7 +499,7 @@ void ViewShellManager::MoveToTop (const ViewShell* pShell) // kept at the top position. We do not have to move the shell. bMove = false; } - else if (aI == ++mpActiveViewShells->begin() + else if (aI == ++maActiveViewShells.begin() && ! aI->mpViewShell->IsMainViewShell() && mbKeepMainViewShellOnTop) { @@ -343,24 +519,23 @@ void ViewShellManager::MoveToTop (const ViewShell* pShell) // internal list of shells and inserted at the correct position. if (bMove) { - UpdateLocker aLock (*this); - InvalidateShellStack(); + UpdateLock aLock (*this); + TakeShellsFromStack(pShell); ViewShell* pNonConstViewShell = aI->mpViewShell; ShellId nId = aI->mnId; - mpActiveViewShells->erase (aI); + maActiveViewShells.erase(aI); // Find out whether to insert at the top or one below. ActiveShellList::iterator aInsertPosition ( - mpActiveViewShells->begin()); + maActiveViewShells.begin()); if (mbKeepMainViewShellOnTop && ! aI->mpViewShell->IsMainViewShell()) { - if (mpActiveViewShells->back().mpViewShell->IsMainViewShell()) + if (maActiveViewShells.back().mpViewShell->IsMainViewShell()) aInsertPosition++; } - PrepareStackModification(); - mpActiveViewShells->insert ( + maActiveViewShells.insert ( aInsertPosition, ActiveShellDescriptor(pNonConstViewShell,nId)); } @@ -369,13 +544,13 @@ void ViewShellManager::MoveToTop (const ViewShell* pShell) -ViewShell* ViewShellManager::GetShell (ShellId nId) +ViewShell* ViewShellManager::Implementation::GetShell (ShellId nId) { ActiveShellList::iterator aI (::std::find_if ( - mpActiveViewShells->begin(), - mpActiveViewShells->end(), + maActiveViewShells.begin(), + maActiveViewShells.end(), IsId(nId))); - if (aI != mpActiveViewShells->end()) + if (aI != maActiveViewShells.end()) return aI->mpViewShell; else return NULL; @@ -384,13 +559,13 @@ ViewShell* ViewShellManager::GetShell (ShellId nId) -ShellId ViewShellManager::GetShellId (const ViewShell* pShell) +ShellId ViewShellManager::Implementation::GetShellId (const ViewShell* pShell) { ActiveShellList::iterator aI (::std::find_if ( - mpActiveViewShells->begin(), - mpActiveViewShells->end(), + maActiveViewShells.begin(), + maActiveViewShells.end(), IsShell(pShell))); - if (aI != mpActiveViewShells->end()) + if (aI != maActiveViewShells.end()) return aI->mnId; else return snInvalidShellId; @@ -399,17 +574,15 @@ ShellId ViewShellManager::GetShellId (const ViewShell* pShell) -void ViewShellManager::LockUpdate (void) +void ViewShellManager::Implementation::LockUpdate (void) { - if (mnUpdateLockCount == 0) - mbTakeShellsFromStackPending = true; mnUpdateLockCount++; } -void ViewShellManager::UnlockUpdate (void) +void ViewShellManager::Implementation::UnlockUpdate (void) { mnUpdateLockCount--; if (mnUpdateLockCount < 0) @@ -419,117 +592,197 @@ void ViewShellManager::UnlockUpdate (void) mnUpdateLockCount = 0; } if (mnUpdateLockCount == 0) - if ( ! mbTakeShellsFromStackPending) - PushShellsOnStack(); + PushShellsOnStack(); } -void ViewShellManager::GatherActiveShells ( - ::std::vector<SfxShell*>& rShellList) +void ViewShellManager::Implementation::PushShellsOnStack (void) { - for (ActiveShellList::iterator aI (mpActiveViewShells->begin()); - aI!=mpActiveViewShells->end(); - aI++) + // Create a local stack of the shells that are to push on the shell + // stack. We can thus safly create the required shells wile still + // having a valid shell stack. + ShellStack aShellStack; + for (ActiveShellList::reverse_iterator aI (maActiveViewShells.rbegin()); + aI!=maActiveViewShells.rend(); + ++aI) { - // Get all its sub shells that are placed above the shell. - aI->mpViewShell->GetUpperShellList (rShellList); + // Get all its sub shells that are placed below the shell. + aI->mpViewShell->GetLowerShellList (aShellStack); // Put the shell itself on the local stack. - rShellList.push_back (aI->mpViewShell); + aShellStack.push_back (aI->mpViewShell); - // Get all its sub shells that are placed below the shell. - aI->mpViewShell->GetLowerShellList (rShellList); + // Get all its sub shells that are placed above the shell. + aI->mpViewShell->GetUpperShellList (aShellStack); } - OSL_TRACE ("gathered shell list:"); - ::std::vector<SfxShell*>::iterator iShell; - for (iShell=rShellList.begin(); iShell!=rShellList.end(); iShell++) - OSL_TRACE (" %p: %s", - *iShell, - ::rtl::OUStringToOString((*iShell)->GetName(), - RTL_TEXTENCODING_UTF8).getStr()); + // Now update the SFX stack to look like the local stack. + UpdateShellStack (aShellStack); } -void ViewShellManager::TakeShellsFromStack (void) +/** Update the SFX shell stack (the portion that is visible to us) so that + it matches the internal shell stack. Since we can not look at the + shells on the SFX stack directly we use the copy that we created the + last time when we rebuilt the SFX stack. This is done in three steps: + 1. Find the lowest shell in which the two stack differ. + 2. Remove all shells above and including that shell from the SFX stack. + This should not be necessary because deactivated shells should have been + removed already. + 3. Push all shells of the internal stack on the SFX shell stack that are + not already present on the later. +*/ +void ViewShellManager::Implementation::UpdateShellStack (ShellStack& rRequestedStack) { - // Now do the actual removing. - if (mbIsValid) - { - ::std::vector<SfxShell*> aShellsToRemove; - GatherActiveShells (aShellsToRemove); + ShellStack aSfxShellStack; + ShellStack::const_iterator iSfxShell; + ShellStack::iterator iRequestedShell; - ::std::vector<SfxShell*>::iterator iShell; - // Deactivate our shells on the stack before they are removed so - // that during the Deactivation() calls the stack is still intact. - for (iShell=aShellsToRemove.begin(); - iShell!=aShellsToRemove.end(); - iShell++) - { - (*iShell)->Deactivate(TRUE); - } - for (iShell=aShellsToRemove.begin(); - iShell!=aShellsToRemove.end(); - iShell++) + mbShellStackIsUpToDate = false; + +#ifdef VERBOSE + OSL_TRACE("UpdateShellStack"); + OSL_TRACE("Current SFX Stack"); + DumpSfxShellStack(); + OSL_TRACE("Requested Stack"); + DumpShellStack(rRequestedStack); +#endif + + // 1. Put the SFX shell stack in a local data structure so that it can + // be searched properly. + for (USHORT nIndex=0; true; nIndex++) + { + if (mrBase.GetSubShell(nIndex)==NULL) { - mrBase.RemoveSubShell (*iShell); + aSfxShellStack.reserve(nIndex); + while (nIndex-- > 0) + aSfxShellStack.push_back(mrBase.GetSubShell(nIndex)); + break; } - if (mrBase.GetDispatcher() != NULL) - mrBase.GetDispatcher()->Flush(); } + + // 2. Find the lowest shell in which the two stacks differ. + iSfxShell = aSfxShellStack.begin(); + iRequestedShell = rRequestedStack.begin(); + while (iSfxShell != aSfxShellStack.end() + && iRequestedShell!=rRequestedStack.end() + && (*iSfxShell)==(*iRequestedShell)) + { + ++iSfxShell; + ++iRequestedShell; + } + + // 3. Remove all shells above and including the differing shell from the + // SFX stack starting with the shell on top of the stack. + while (iSfxShell != aSfxShellStack.end()) + { + SfxShell* pShell = aSfxShellStack.back(); + aSfxShellStack.pop_back(); +#ifdef VERBOSE + OSL_TRACE("removing shell %p from stack", pShell); +#endif + mrBase.RemoveSubShell(pShell); + } + + // 4. Push shells from the given stack onto the SFX stack. + while (iRequestedShell != rRequestedStack.end()) + { +#ifdef VERBOSE + OSL_TRACE("pushing shell %p on stack", *iRequestedShell); +#endif + mrBase.AddSubShell(**iRequestedShell); + ++iRequestedShell; + + // The pushing of the shell on to the shell stack may have lead to + // another invocation of this method. In this case we have to abort + // pushing shells on the stack and return immediately. + if (mbShellStackIsUpToDate) + break; + } + + // 5. Tell the dispatcher to update the SFX shell. + if (mrBase.GetDispatcher() != NULL) + mrBase.GetDispatcher()->Flush(); + + // 6. Finally Tell an invocation of this method on a higher level that it can (has + // to) abort and return immediately. + mbShellStackIsUpToDate = true; + +#ifdef VERBOSE + OSL_TRACE("New current stack"); + DumpSfxShellStack(); +#endif } -void ViewShellManager::PushShellsOnStack (void) +void ViewShellManager::Implementation::TakeShellsFromStack (const SfxShell* pShell) { - mbShellStackIsUpToDate = false; +#ifdef VERBOSE + OSL_TRACE("TakeShellsFromStack(%p)", pShell); + DumpSfxShellStack(); +#endif - // Remove all stacked shells. - mrBase.RemoveSubShell (NULL); + // 0.Make sure that the given shell is on the stack. This is a + // preparation for the following assertion. + for (USHORT nIndex=0; true; nIndex++) + { + SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex); + if (pShellOnStack == NULL) + { + // Set pShell to NULL to indicate the following code that the + // shell is not on the stack. + pShell = NULL; + break; + } + else if (pShellOnStack == pShell) + break; + } - // Create a local stack of the shells that are to push on the shell - // stack. We can thus safly create the required shells wile still - // having a valid shell stack. - if (mbIsValid) + if (pShell != NULL) { - ::std::vector<SfxShell*> aShellsToPush; - GatherActiveShells (aShellsToPush); - - // Now do the actual pushing. - ::std::vector<SfxShell*>::reverse_iterator iShell; - for (iShell=aShellsToPush.rbegin(); - iShell!=aShellsToPush.rend(); - iShell++) + // 1. Deactivate our shells on the stack before they are removed so + // that during the Deactivation() calls the stack is still intact. + for (USHORT nIndex=0; true; nIndex++) { - OSL_TRACE (" putting %s on stack", - ::rtl::OUStringToOString((*iShell)->GetName(),RTL_TEXTENCODING_UTF8).getStr()); - mrBase.AddSubShell (**iShell); - - // The pushing of the shell on to the shell stack may have lead - // to another invocation of this method. In this case we have - // to abort pushing shells on the stack and return immediately. - if (mbShellStackIsUpToDate) + SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex); + pShellOnStack->Deactivate(TRUE); + if (pShellOnStack == pShell) + break; + } + + // 2. Remove the shells from the stack. + while (true) + { + SfxShell* pShellOnStack = mrBase.GetSubShell(0); +#ifdef VERBOSE + OSL_TRACE("removing shell %p from stack", pShellOnStack); +#endif + mrBase.RemoveSubShell(pShellOnStack); + if (pShellOnStack == pShell) break; } + + // 3. Update the stack. if (mrBase.GetDispatcher() != NULL) mrBase.GetDispatcher()->Flush(); } - // Tell an invocation of this method on a higher level that it can (has - // to) abort and return immediately. - mbShellStackIsUpToDate = true; +#ifdef VERBOSE + OSL_TRACE("Sfx shell stack is:"); + DumpSfxShellStack(); +#endif } -ViewShellBase& ViewShellManager::GetViewShellBase (void) const +ViewShellBase& ViewShellManager::Implementation::GetViewShellBase (void) const { return mrBase; } @@ -537,15 +790,7 @@ ViewShellBase& ViewShellManager::GetViewShellBase (void) const -void ViewShellManager::ShutDown (void) -{ - mbIsValid = false; -} - - - - -IMPL_LINK(ViewShellManager, WindowEventHandler, VclWindowEvent*, pEvent) +IMPL_LINK(ViewShellManager::Implementation, WindowEventHandler, VclWindowEvent*, pEvent) { if (pEvent != NULL) { @@ -556,8 +801,8 @@ IMPL_LINK(ViewShellManager, WindowEventHandler, VclWindowEvent*, pEvent) { case VCLEVENT_WINDOW_GETFOCUS: { - for (ActiveShellList::iterator aI(mpActiveViewShells->begin()); - aI!=mpActiveViewShells->end(); + for (ActiveShellList::iterator aI(maActiveViewShells.begin()); + aI!=maActiveViewShells.end(); aI++) { if (pEventWindow == static_cast< ::Window*>( @@ -580,7 +825,7 @@ IMPL_LINK(ViewShellManager, WindowEventHandler, VclWindowEvent*, pEvent) -ViewShell* ViewShellManager::CreateViewShell ( +ViewShell* ViewShellManager::Implementation::CreateViewShell ( ShellId nShellId, ::Window* pParentWindow, FrameView* pFrameView) @@ -591,12 +836,11 @@ ViewShell* ViewShellManager::CreateViewShell ( ViewShellFactory* pFactory = mpDefaultFactory.get(); // Look up a specialized factory. - SpecializedFactoryList::iterator aI ( - mpSpecializedFactories->find(nShellId)); - if (aI != mpSpecializedFactories->end()) + SpecializedFactoryList::iterator aI (maSpecializedFactories.find(nShellId)); + if (aI != maSpecializedFactories.end()) pFactory = aI->second; - UpdateLocker aLocker (*this); + UpdateLock aLocker (*this); if (pFactory!=NULL && pParentWindow!=NULL) { @@ -613,32 +857,103 @@ ViewShell* ViewShellManager::CreateViewShell ( -void ViewShellManager::PrepareStackModification (void) +void ViewShellManager::Implementation::Shutdown (void) { - if (mbTakeShellsFromStackPending) + // Take stacked shells from stack. + if ( ! maActiveViewShells.empty()) + { + UpdateLock aLock (*this); + + while ( ! maActiveViewShells.empty()) + { + DeactivateViewShell(maActiveViewShells.front().mpViewShell); + } + } + mrBase.RemoveSubShell (NULL); + + // We have the ownership of the factories and because they can not be + // auto_ptrs in an stl list we have to delete them now by hand. + for (SpecializedFactoryList::iterator aI (maSpecializedFactories.begin()); + aI!=maSpecializedFactories.end(); + aI++) { - mbTakeShellsFromStackPending = false; - TakeShellsFromStack(); + delete aI->second; + } + + // Destroy members. + maCache.Shutdown(); + mpDefaultFactory.reset(); +} + + + + +void ViewShellManager::Implementation::DumpActiveShell (const ActiveShellList& rList) +{ + ActiveShellList::const_iterator aI; + for (aI=rList.begin(); aI!=rList.end(); ++aI) + { + OSL_TRACE (" %d %p", + aI->mnId, + aI->mpViewShell); + } +} + + + + +void ViewShellManager::Implementation::DumpShellStack (const ShellStack& rStack) +{ + ShellStack::const_reverse_iterator iEntry; + for (iEntry=rStack.rbegin(); iEntry!=rStack.rend(); ++iEntry) + OSL_TRACE (" %p: %s", + *iEntry, + ::rtl::OUStringToOString((*iEntry)->GetName(),RTL_TEXTENCODING_UTF8).getStr()); +} + + + + +void ViewShellManager::Implementation::DumpSfxShellStack (void) +{ + USHORT nIndex; + for (nIndex=0; true; nIndex++) + { + SfxShell* pShell = mrBase.GetSubShell(nIndex); + if (pShell == NULL) + break; + OSL_TRACE (" %d : %p: %s", + nIndex, + pShell, + ::rtl::OUStringToOString(pShell->GetName(),RTL_TEXTENCODING_UTF8).getStr()); } } +//===== ViewShellManager::UpdateLock ========================================== + +ViewShellManager::UpdateLock::UpdateLock (ViewShellManager& rManager) + : mrManagerImplementation(*rManager.mpImpl.get()) +{ + mrManagerImplementation.LockUpdate(); +} + + -//===== ViewShellManager::UpdateLocker ======================================== -ViewShellManager::UpdateLocker::UpdateLocker (ViewShellManager& rManager) - : mrManager(rManager) +ViewShellManager::UpdateLock::UpdateLock (ViewShellManager::Implementation& rManagerImplementation) + : mrManagerImplementation(rManagerImplementation) { - mrManager.LockUpdate(); + mrManagerImplementation.LockUpdate(); } -ViewShellManager::UpdateLocker::~UpdateLocker (void) +ViewShellManager::UpdateLock::~UpdateLock (void) { - mrManager.UnlockUpdate(); + mrManagerImplementation.UnlockUpdate(); } |