|  | /************************************************************** | 
|  | * | 
|  | * 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 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, | 
|  | * software distributed under the License is distributed on an | 
|  | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | * KIND, either express or implied.  See the License for the | 
|  | * specific language governing permissions and limitations | 
|  | * under the License. | 
|  | * | 
|  | *************************************************************/ | 
|  |  | 
|  |  | 
|  |  | 
|  | // MARKER(update_precomp.py): autogen include statement, do not remove | 
|  | #include "precompiled_sd.hxx" | 
|  |  | 
|  | #include "ViewShellManager.hxx" | 
|  | #include "ViewShell.hxx" | 
|  | #include "ViewShellBase.hxx" | 
|  | #include "Window.hxx" | 
|  | #include "DrawDocShell.hxx" | 
|  | #include "FormShellManager.hxx" | 
|  |  | 
|  | #include <sfx2/dispatch.hxx> | 
|  | #include <svx/svxids.hrc> | 
|  | #include <svx/fmshell.hxx> | 
|  |  | 
|  | #include <hash_map> | 
|  |  | 
|  | #undef VERBOSE | 
|  | //#define VERBOSE 2 | 
|  |  | 
|  | namespace sd { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | /** The ShellDescriptor class is used to shells together with their ids and | 
|  | the factory that was used to create the shell. | 
|  |  | 
|  | The shell pointer may be NULL.  In that case the shell is created on | 
|  | demand by a factory. | 
|  |  | 
|  | The factory pointer may be NULL.  In that case the shell pointer is | 
|  | given to the ViewShellManager. | 
|  |  | 
|  | Shell pointer and factory pointer can but should not be NULL at the same | 
|  | time. | 
|  | */ | 
|  | class ShellDescriptor { | 
|  | public: | 
|  | SfxShell* mpShell; | 
|  | ShellId mnId; | 
|  | ViewShellManager::SharedShellFactory mpFactory; | 
|  | bool mbIsListenerAddedToWindow; | 
|  |  | 
|  | ShellDescriptor (); | 
|  | ShellDescriptor (SfxShell* pShell, ShellId nId); | 
|  | ShellDescriptor (const ShellDescriptor& rDescriptor); | 
|  | ShellDescriptor& operator= (const ShellDescriptor& rDescriptor); | 
|  | bool IsMainViewShell (void) const; | 
|  | ::Window* GetWindow (void) const; | 
|  | }; | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | /** This functor can be used to search for a shell in an STL container when the | 
|  | shell pointer is given. | 
|  | */ | 
|  | class IsShell : public ::std::unary_function<ShellDescriptor,bool> | 
|  | { | 
|  | public: | 
|  | IsShell (const SfxShell* pShell) : mpShell(pShell) {} | 
|  | bool operator() (const ShellDescriptor& rDescriptor) | 
|  | { return rDescriptor.mpShell == mpShell; } | 
|  | private: | 
|  | const SfxShell* mpShell; | 
|  | }; | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | /** This functor can be used to search for a shell in an STL container when the | 
|  | id of the shell is given. | 
|  | */ | 
|  | class IsId : public ::std::unary_function<ShellDescriptor,bool> | 
|  | { | 
|  | public: | 
|  | IsId (ShellId nId) : mnId(nId) {} | 
|  | bool operator() (const ShellDescriptor& rDescriptor) | 
|  | { return rDescriptor.mnId == mnId; } | 
|  | private: | 
|  | ShellId mnId; | 
|  | }; | 
|  |  | 
|  | } // end of anonymous namespace | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | class ViewShellManager::Implementation | 
|  | { | 
|  | public: | 
|  | Implementation ( | 
|  | ViewShellManager& rManager, | 
|  | ViewShellBase& rBase); | 
|  | ~Implementation (void); | 
|  |  | 
|  | void AddShellFactory ( | 
|  | const SfxShell* pViewShell, | 
|  | const SharedShellFactory& rpFactory); | 
|  | void RemoveShellFactory ( | 
|  | const SfxShell* pViewShell, | 
|  | const SharedShellFactory& rpFactory); | 
|  | void ActivateViewShell ( | 
|  | ViewShell* pViewShell); | 
|  | void DeactivateViewShell (const ViewShell& rShell); | 
|  | void ActivateShell (SfxShell& rShell); | 
|  | void DeactivateShell (const SfxShell& rShell); | 
|  | void ActivateShell (const ShellDescriptor& rDescriptor); | 
|  | void SetFormShell (const ViewShell* pViewShell, FmFormShell* pFormShell, bool bAbove); | 
|  | void ActivateSubShell (const SfxShell& rParentShell, ShellId nId); | 
|  | void DeactivateSubShell (const SfxShell& rParentShell, ShellId nId); | 
|  | void MoveSubShellToTop (const SfxShell& rParentShell, ShellId nId); | 
|  | void MoveToTop (const SfxShell& rParentShell); | 
|  | SfxShell* GetShell (ShellId nId) const; | 
|  | SfxShell* GetTopShell (void) const; | 
|  | void Shutdown (void); | 
|  | void InvalidateAllSubShells (const SfxShell* pParentShell); | 
|  |  | 
|  | /** Remove all shells from the SFX stack above and including the given | 
|  | shell. | 
|  | */ | 
|  | void TakeShellsFromStack (const SfxShell* pShell); | 
|  |  | 
|  | class UpdateLock | 
|  | { | 
|  | public: | 
|  | UpdateLock (Implementation& rImpl) : mrImpl(rImpl) {mrImpl.LockUpdate();} | 
|  | ~UpdateLock (void) {mrImpl.UnlockUpdate();}; | 
|  | private: | 
|  | Implementation& mrImpl; | 
|  | }; | 
|  |  | 
|  |  | 
|  |  | 
|  | /** 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; | 
|  | mutable ::osl::Mutex maMutex; | 
|  |  | 
|  | class ShellHash{public: size_t operator()(const SfxShell* p) const { return (size_t)p;} }; | 
|  | typedef ::std::hash_multimap<const SfxShell*,SharedShellFactory,ShellHash> | 
|  | FactoryList; | 
|  | FactoryList maShellFactories; | 
|  |  | 
|  | /** 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<ShellDescriptor> ActiveShellList; | 
|  | ActiveShellList maActiveViewShells; | 
|  |  | 
|  | typedef ::std::list<ShellDescriptor> SubShellSubList; | 
|  | typedef ::std::hash_map<const SfxShell*,SubShellSubList,ShellHash> SubShellList; | 
|  | SubShellList maActiveSubShells; | 
|  |  | 
|  | /** In this member we remember what shells we have pushed on the shell | 
|  | stack. | 
|  | */ | 
|  | typedef ::std::vector<SfxShell*> ShellStack; | 
|  |  | 
|  | 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 UpdateShellStack() 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; | 
|  |  | 
|  | SfxShell* mpFormShell; | 
|  | const ViewShell* mpFormShellParent; | 
|  | bool mbFormShellAboveParent; | 
|  |  | 
|  | SfxShell* mpTopShell; | 
|  |  | 
|  | void GatherActiveShells (ShellStack& rShellList); | 
|  |  | 
|  | void UpdateShellStack (void); | 
|  |  | 
|  | void CreateShells (void); | 
|  |  | 
|  | /** This method rebuilds the stack of shells that are stacked upon the | 
|  | view shell base. | 
|  | */ | 
|  | void CreateTargetStack (ShellStack& rStack) const; | 
|  |  | 
|  | DECL_LINK(WindowEventHandler, VclWindowEvent*); | 
|  |  | 
|  | #ifdef VERBOSE | 
|  | void DumpShellStack (const ShellStack& rStack); | 
|  | void DumpSfxShellStack (void); | 
|  | #endif | 
|  |  | 
|  | /** To be called before a shell is taken fom the SFX shell stack.  This | 
|  | method deactivates an active text editing to avoid problems with | 
|  | undo managers. | 
|  | Afterwards the Deactivate() of the shell is called. | 
|  | */ | 
|  | void Deactivate (SfxShell* pShell); | 
|  |  | 
|  | ShellDescriptor CreateSubShell ( | 
|  | SfxShell* pShell, | 
|  | ShellId nShellId, | 
|  | ::Window* pParentWindow, | 
|  | FrameView* pFrameView); | 
|  | void DestroyViewShell (ShellDescriptor& rDescriptor); | 
|  | void DestroySubShell ( | 
|  | const SfxShell& rViewShell, | 
|  | const ShellDescriptor& rDescriptor); | 
|  | }; | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | //===== ViewShellManager ====================================================== | 
|  |  | 
|  | ViewShellManager::ViewShellManager (ViewShellBase& rBase) | 
|  | : mpImpl(new Implementation(*this,rBase)), | 
|  | mbValid(true) | 
|  | { | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | ViewShellManager::~ViewShellManager (void) | 
|  | { | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::AddSubShellFactory ( | 
|  | ViewShell* pViewShell, | 
|  | const SharedShellFactory& rpFactory) | 
|  | { | 
|  | if (mbValid) | 
|  | mpImpl->AddShellFactory(pViewShell, rpFactory); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::RemoveSubShellFactory ( | 
|  | ViewShell* pViewShell, | 
|  | const SharedShellFactory& rpFactory) | 
|  | { | 
|  | if (mbValid) | 
|  | mpImpl->RemoveShellFactory(pViewShell, rpFactory); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::ActivateViewShell (ViewShell* pViewShell) | 
|  | { | 
|  | if (mbValid) | 
|  | return mpImpl->ActivateViewShell(pViewShell); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::DeactivateViewShell (const ViewShell* pShell) | 
|  | { | 
|  | if (mbValid && pShell!=NULL) | 
|  | mpImpl->DeactivateViewShell(*pShell); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::MoveSubShellToTop ( | 
|  | const ViewShell& rParentShell, | 
|  | ShellId nId) | 
|  | { | 
|  | if (mbValid) | 
|  | mpImpl->MoveSubShellToTop(rParentShell, nId); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::SetFormShell ( | 
|  | const ViewShell* pParentShell, | 
|  | FmFormShell* pFormShell, | 
|  | bool bAbove) | 
|  | { | 
|  | if (mbValid) | 
|  | mpImpl->SetFormShell(pParentShell,pFormShell,bAbove); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::ActivateSubShell (const ViewShell& rViewShell, ShellId nId) | 
|  | { | 
|  | if (mbValid) | 
|  | mpImpl->ActivateSubShell(rViewShell,nId); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::DeactivateSubShell (const ViewShell& rViewShell, ShellId nId) | 
|  | { | 
|  | if (mbValid) | 
|  | mpImpl->DeactivateSubShell(rViewShell,nId); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::InvalidateAllSubShells (ViewShell* pViewShell) | 
|  | { | 
|  | if (mbValid) | 
|  | mpImpl->InvalidateAllSubShells(pViewShell); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::ActivateShell (SfxShell* pShell) | 
|  | { | 
|  | if (mbValid && pShell!=NULL) | 
|  | mpImpl->ActivateShell(*pShell); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::DeactivateShell (const SfxShell* pShell) | 
|  | { | 
|  | if (mbValid && pShell!=NULL) | 
|  | mpImpl->DeactivateShell(*pShell); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::MoveToTop (const ViewShell& rParentShell) | 
|  | { | 
|  | if (mbValid) | 
|  | mpImpl->MoveToTop(rParentShell); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | SfxShell* ViewShellManager::GetShell (ShellId nId) const | 
|  | { | 
|  | if (mbValid) | 
|  | return mpImpl->GetShell(nId); | 
|  | else | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | SfxShell* ViewShellManager::GetTopShell (void) const | 
|  | { | 
|  | if (mbValid) | 
|  | return mpImpl->GetTopShell(); | 
|  | else | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Shutdown (void) | 
|  | { | 
|  | if (mbValid) | 
|  | { | 
|  | mpImpl->Shutdown(); | 
|  | mbValid = false; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::LockUpdate (void) | 
|  | { | 
|  | mpImpl->LockUpdate(); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::UnlockUpdate (void) | 
|  | { | 
|  | mpImpl->UnlockUpdate(); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | //===== ViewShellManager::Implementation ====================================== | 
|  |  | 
|  | ViewShellManager::Implementation::Implementation ( | 
|  | ViewShellManager& rManager, | 
|  | ViewShellBase& rBase) | 
|  | : mrBase(rBase), | 
|  | maMutex(), | 
|  | maShellFactories(), | 
|  | maActiveViewShells(), | 
|  | mnUpdateLockCount(0), | 
|  | mbKeepMainViewShellOnTop(false), | 
|  | mbShellStackIsUpToDate(true), | 
|  | mpFormShell(NULL), | 
|  | mpFormShellParent(NULL), | 
|  | mbFormShellAboveParent(true), | 
|  | mpTopShell(NULL) | 
|  | { | 
|  | (void)rManager; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | ViewShellManager::Implementation::~Implementation (void) | 
|  | { | 
|  | Shutdown(); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::AddShellFactory ( | 
|  | const SfxShell* pViewShell, | 
|  | const SharedShellFactory& rpFactory) | 
|  | { | 
|  | bool bAlreadyAdded (false); | 
|  |  | 
|  | // Check that the given factory has not already been added. | 
|  | ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( | 
|  | maShellFactories.equal_range(pViewShell)); | 
|  | for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) | 
|  | if (iFactory->second == rpFactory) | 
|  | { | 
|  | bAlreadyAdded = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Add the factory if it is not already present. | 
|  | if ( ! bAlreadyAdded) | 
|  | maShellFactories.insert(FactoryList::value_type(pViewShell, rpFactory)); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::RemoveShellFactory ( | 
|  | const SfxShell* pViewShell, | 
|  | const SharedShellFactory& rpFactory) | 
|  | { | 
|  | ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( | 
|  | maShellFactories.equal_range(pViewShell)); | 
|  | for (FactoryList::iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) | 
|  | if (iFactory->second == rpFactory) | 
|  | { | 
|  | maShellFactories.erase(iFactory); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::ActivateViewShell (ViewShell* pViewShell) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | ShellDescriptor aResult; | 
|  | aResult.mpShell = pViewShell; | 
|  |  | 
|  | // Register as window listener so that the shells of the current | 
|  | // window can be moved to the top of the shell stack. | 
|  | if (aResult.mpShell != NULL) | 
|  | { | 
|  | ::Window* pWindow = aResult.GetWindow(); | 
|  | if (pWindow != NULL) | 
|  | { | 
|  | pWindow->AddEventListener( | 
|  | LINK(this, ViewShellManager::Implementation, WindowEventHandler)); | 
|  | aResult.mbIsListenerAddedToWindow = true; | 
|  | } | 
|  | else | 
|  | { | 
|  | DBG_ASSERT(false, | 
|  | "ViewShellManager::ActivateViewShell: " | 
|  | "new view shell has no active window"); | 
|  | } | 
|  | } | 
|  |  | 
|  | ActivateShell(aResult); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::DeactivateViewShell (const ViewShell& rShell) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | ActiveShellList::iterator iShell (::std::find_if ( | 
|  | maActiveViewShells.begin(), | 
|  | maActiveViewShells.end(), | 
|  | IsShell(&rShell))); | 
|  | if (iShell != maActiveViewShells.end()) | 
|  | { | 
|  | UpdateLock aLocker (*this); | 
|  |  | 
|  | ShellDescriptor aDescriptor(*iShell); | 
|  | mrBase.GetDocShell()->Disconnect(dynamic_cast<ViewShell*>(aDescriptor.mpShell)); | 
|  | maActiveViewShells.erase(iShell); | 
|  | TakeShellsFromStack(aDescriptor.mpShell); | 
|  |  | 
|  | // Deactivate sub shells. | 
|  | SubShellList::iterator iList (maActiveSubShells.find(&rShell)); | 
|  | if (iList != maActiveSubShells.end()) | 
|  | { | 
|  | SubShellSubList& rList (iList->second); | 
|  | while ( ! rList.empty()) | 
|  | DeactivateSubShell(rShell, rList.front().mnId); | 
|  | } | 
|  |  | 
|  | DestroyViewShell(aDescriptor); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::ActivateShell (SfxShell& rShell) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | // Create a new shell or recycle on in the cache. | 
|  | ShellDescriptor aDescriptor; | 
|  | aDescriptor.mpShell = &rShell; | 
|  |  | 
|  | ActivateShell(aDescriptor); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::ActivateShell (const ShellDescriptor& rDescriptor) | 
|  | { | 
|  | // Put shell on top of the active view shells. | 
|  | if (rDescriptor.mpShell != NULL) | 
|  | { | 
|  | // Determine where to put the view shell on the stack.  By default | 
|  | // it is put on top of the stack.  When the view shell of the center | 
|  | // pane is to be kept top most and the new view shell is not | 
|  | // displayed in the center pane then it is inserted at the position | 
|  | // one below the top. | 
|  | ActiveShellList::iterator iInsertPosition (maActiveViewShells.begin()); | 
|  | if (iInsertPosition != maActiveViewShells.end() | 
|  | && mbKeepMainViewShellOnTop | 
|  | && ! rDescriptor.IsMainViewShell() | 
|  | && iInsertPosition->IsMainViewShell()) | 
|  | { | 
|  | ++iInsertPosition; | 
|  | } | 
|  | maActiveViewShells.insert( | 
|  | iInsertPosition, | 
|  | rDescriptor); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::DeactivateShell (const SfxShell& rShell) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | ActiveShellList::iterator iShell (::std::find_if ( | 
|  | maActiveViewShells.begin(), | 
|  | maActiveViewShells.end(), | 
|  | IsShell(&rShell))); | 
|  | if (iShell != maActiveViewShells.end()) | 
|  | { | 
|  | UpdateLock aLocker (*this); | 
|  |  | 
|  | ShellDescriptor aDescriptor(*iShell); | 
|  | mrBase.GetDocShell()->Disconnect(dynamic_cast<ViewShell*>(aDescriptor.mpShell)); | 
|  | maActiveViewShells.erase(iShell); | 
|  | TakeShellsFromStack(aDescriptor.mpShell); | 
|  |  | 
|  | // Deactivate sub shells. | 
|  | SubShellList::iterator iList (maActiveSubShells.find(&rShell)); | 
|  | if (iList != maActiveSubShells.end()) | 
|  | { | 
|  | SubShellSubList& rList (iList->second); | 
|  | while ( ! rList.empty()) | 
|  | DeactivateSubShell(rShell, rList.front().mnId); | 
|  | } | 
|  |  | 
|  | DestroyViewShell(aDescriptor); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::ActivateSubShell ( | 
|  | const SfxShell& rParentShell, | 
|  | ShellId nId) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | do | 
|  | { | 
|  | // Check that the given view shell is active. | 
|  | ActiveShellList::iterator iShell (::std::find_if ( | 
|  | maActiveViewShells.begin(), | 
|  | maActiveViewShells.end(), | 
|  | IsShell(&rParentShell))); | 
|  | if (iShell == maActiveViewShells.end()) | 
|  | break; | 
|  |  | 
|  | // Create the sub shell list if it does not yet exist. | 
|  | SubShellList::iterator iList (maActiveSubShells.find(&rParentShell)); | 
|  | if (iList == maActiveSubShells.end()) | 
|  | iList = maActiveSubShells.insert( | 
|  | SubShellList::value_type(&rParentShell,SubShellSubList())).first; | 
|  |  | 
|  | // Do not activate an object bar that is already active.  Requesting | 
|  | // this is not exactly an error but may be an indication of one. | 
|  | SubShellSubList& rList (iList->second); | 
|  | if (::std::find_if(rList.begin(),rList.end(), IsId(nId)) != rList.end()) | 
|  | break; | 
|  |  | 
|  | // Add just the id of the sub shell. The actual shell is created | 
|  | // later in CreateShells(). | 
|  | UpdateLock aLock (*this); | 
|  | rList.push_back(ShellDescriptor(NULL, nId)); | 
|  | } | 
|  | while (false); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::DeactivateSubShell ( | 
|  | const SfxShell& rParentShell, | 
|  | ShellId nId) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | do | 
|  | { | 
|  | // Check that the given view shell is active. | 
|  | SubShellList::iterator iList (maActiveSubShells.find(&rParentShell)); | 
|  | if (iList == maActiveSubShells.end()) | 
|  | break; | 
|  |  | 
|  | // Look up the sub shell. | 
|  | SubShellSubList& rList (iList->second); | 
|  | SubShellSubList::iterator iShell ( | 
|  | ::std::find_if(rList.begin(),rList.end(), IsId(nId))); | 
|  | if (iShell == rList.end()) | 
|  | break; | 
|  | SfxShell* pShell = iShell->mpShell; | 
|  | if (pShell == NULL) | 
|  | break; | 
|  |  | 
|  | UpdateLock aLock (*this); | 
|  |  | 
|  | ShellDescriptor aDescriptor(*iShell); | 
|  | // Remove the sub shell from both the internal structure as well as the | 
|  | // SFX shell stack above and including the sub shell. | 
|  | rList.erase(iShell); | 
|  | TakeShellsFromStack(pShell); | 
|  |  | 
|  | DestroySubShell(rParentShell, aDescriptor); | 
|  | } | 
|  | while (false); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::MoveSubShellToTop ( | 
|  | const SfxShell& rParentShell, | 
|  | ShellId nId) | 
|  | { | 
|  | SubShellList::iterator iList (maActiveSubShells.find(&rParentShell)); | 
|  | if (iList != maActiveSubShells.end()) | 
|  | { | 
|  | // Look up the sub shell. | 
|  | SubShellSubList& rList (iList->second); | 
|  | SubShellSubList::iterator iShell ( | 
|  | ::std::find_if(rList.begin(),rList.end(), IsId(nId))); | 
|  | if (iShell!=rList.end() && iShell!=rList.begin()) | 
|  | { | 
|  | SubShellSubList::value_type aEntry (*iShell); | 
|  | rList.erase(iShell); | 
|  | rList.push_front(aEntry); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // Ignore this call when there are no sub shells for the given | 
|  | // parent shell.  We could remember the sub shell to move to the top | 
|  | // but we do not.  Do call this method at a later time instead. | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::MoveToTop (const SfxShell& rShell) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | // Check that we have access to a dispatcher.  If not, then we are | 
|  | // (probably) called while the view shell is still being created or | 
|  | // initialized.  Without dispatcher we can not rebuild the shell stack | 
|  | // to move the requested shell to the top.  So return right away instead | 
|  | // of making a mess without being able to clean up afterwards. | 
|  | if (mrBase.GetDispatcher() == NULL) | 
|  | return; | 
|  |  | 
|  | ActiveShellList::iterator iShell (::std::find_if ( | 
|  | maActiveViewShells.begin(), | 
|  | maActiveViewShells.end(), | 
|  | IsShell(&rShell))); | 
|  | bool bMove = true; | 
|  | if (iShell != 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 (iShell == maActiveViewShells.begin() | 
|  | && (iShell->IsMainViewShell() || ! mbKeepMainViewShellOnTop)) | 
|  | { | 
|  | // The shell is at the top position and is either a) the main | 
|  | // view shell or b) another shell but the main view shell is not | 
|  | // kept at the top position.  We do not have to move the shell. | 
|  | bMove = false; | 
|  | } | 
|  | else if (iShell == ++maActiveViewShells.begin() | 
|  | && ! iShell->IsMainViewShell() | 
|  | && mbKeepMainViewShellOnTop) | 
|  | { | 
|  | // The shell is a the second-to-top position, not the main view | 
|  | // shell and the main view shell is kept at the top position. | 
|  | // Therefore we do not have to move the shell. | 
|  | bMove = false; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // The shell is not on the stack.  Therefore it can not be moved. | 
|  | // We could insert it but we don't.  Use ActivateViewShell() for | 
|  | // that. | 
|  | bMove = false; | 
|  | } | 
|  |  | 
|  | // When the shell is not at the right position it is removed from the | 
|  | // internal list of shells and inserted at the correct position. | 
|  | if (bMove) | 
|  | { | 
|  | UpdateLock aLock (*this); | 
|  |  | 
|  | ShellDescriptor aDescriptor(*iShell); | 
|  |  | 
|  | TakeShellsFromStack(&rShell); | 
|  | maActiveViewShells.erase(iShell); | 
|  |  | 
|  | // Find out whether to insert at the top or one below. | 
|  | ActiveShellList::iterator aInsertPosition (maActiveViewShells.begin()); | 
|  | if (mbKeepMainViewShellOnTop && ! aDescriptor.IsMainViewShell()) | 
|  | { | 
|  | if (maActiveViewShells.back().IsMainViewShell()) | 
|  | aInsertPosition++; | 
|  | } | 
|  |  | 
|  | maActiveViewShells.insert(aInsertPosition, aDescriptor); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | SfxShell* ViewShellManager::Implementation::GetShell (ShellId nId) const | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | SfxShell* pShell = NULL; | 
|  |  | 
|  | // First search the active view shells. | 
|  | ActiveShellList::const_iterator iShell ( | 
|  | ::std::find_if ( | 
|  | maActiveViewShells.begin(), | 
|  | maActiveViewShells.end(), | 
|  | IsId(nId))); | 
|  | if (iShell != maActiveViewShells.end()) | 
|  | pShell = iShell->mpShell; | 
|  | else | 
|  | { | 
|  | // Now search the active sub shells of every active view shell. | 
|  | SubShellList::const_iterator iList; | 
|  | for (iList=maActiveSubShells.begin(); iList!=maActiveSubShells.end(); ++iList) | 
|  | { | 
|  | const SubShellSubList& rList (iList->second); | 
|  | SubShellSubList::const_iterator iSubShell( | 
|  | ::std::find_if(rList.begin(),rList.end(), IsId(nId))); | 
|  | if (iSubShell != rList.end()) | 
|  | { | 
|  | pShell = iSubShell->mpShell; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return pShell; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | SfxShell* ViewShellManager::Implementation::GetTopShell (void) const | 
|  | { | 
|  | OSL_ASSERT(mpTopShell == mrBase.GetSubShell(0)); | 
|  | return mpTopShell; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::LockUpdate (void) | 
|  | { | 
|  | mnUpdateLockCount++; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::UnlockUpdate (void) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | mnUpdateLockCount--; | 
|  | if (mnUpdateLockCount < 0) | 
|  | { | 
|  | // This should not happen. | 
|  | OSL_ASSERT (mnUpdateLockCount>=0); | 
|  | mnUpdateLockCount = 0; | 
|  | } | 
|  | if (mnUpdateLockCount == 0) | 
|  | UpdateShellStack(); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | /** Update the SFX shell stack (the portion that is visible to us) so that | 
|  | it matches the internal shell stack.  This is done in six steps: | 
|  | 1. Create the missing view shells and sub shells. | 
|  | 2. Set up the internal shell stack. | 
|  | 3. Get the SFX shell stack. | 
|  | 4. Find the lowest shell in which the two stacks differ. | 
|  | 5. Remove all shells above and including that shell from the SFX stack. | 
|  | 6. Push all shells of the internal stack on the SFX shell stack that are | 
|  | not already present on the later. | 
|  | */ | 
|  | void ViewShellManager::Implementation::UpdateShellStack (void) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | // Remember the undo manager from the top-most shell on the stack. | 
|  | SfxShell* pTopMostShell = mrBase.GetSubShell(0); | 
|  | ::svl::IUndoManager* pUndoManager = (pTopMostShell!=NULL) | 
|  | ? pTopMostShell->GetUndoManager() | 
|  | : NULL; | 
|  |  | 
|  | // 1. Create the missing shells. | 
|  | CreateShells(); | 
|  |  | 
|  |  | 
|  | // 2. Create the internal target stack. | 
|  | ShellStack aTargetStack; | 
|  | CreateTargetStack(aTargetStack); | 
|  |  | 
|  |  | 
|  | // 3. Get SFX shell stack. | 
|  | ShellStack aSfxShellStack; | 
|  | sal_uInt16 nIndex (0); | 
|  | while (mrBase.GetSubShell(nIndex)!=NULL) | 
|  | ++nIndex; | 
|  | aSfxShellStack.reserve(nIndex); | 
|  | while (nIndex-- > 0) | 
|  | aSfxShellStack.push_back(mrBase.GetSubShell(nIndex)); | 
|  |  | 
|  |  | 
|  | #ifdef VERBOSE | 
|  | OSL_TRACE("Current SFX Stack\r"); | 
|  | DumpShellStack(aSfxShellStack); | 
|  | OSL_TRACE("Target Stack\r"); | 
|  | DumpShellStack(aTargetStack); | 
|  | #endif | 
|  |  | 
|  |  | 
|  | // 4. Find the lowest shell in which the two stacks differ. | 
|  | ShellStack::const_iterator iSfxShell (aSfxShellStack.begin()); | 
|  | ShellStack::iterator iTargetShell (aTargetStack.begin()); | 
|  | while (iSfxShell != aSfxShellStack.end() | 
|  | && iTargetShell!=aTargetStack.end() | 
|  | && (*iSfxShell)==(*iTargetShell)) | 
|  | { | 
|  | ++iSfxShell; | 
|  | ++iTargetShell; | 
|  | } | 
|  |  | 
|  |  | 
|  | // 5. 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\r", pShell); | 
|  | #endif | 
|  | mrBase.RemoveSubShell(pShell); | 
|  | } | 
|  |  | 
|  |  | 
|  | // 6. Push shells from the given stack onto the SFX stack. | 
|  | mbShellStackIsUpToDate = false; | 
|  | while (iTargetShell != aTargetStack.end()) | 
|  | { | 
|  | #ifdef VERBOSE | 
|  | OSL_TRACE("pushing shell %p on stack\r", *iTargetShell); | 
|  | #endif | 
|  | mrBase.AddSubShell(**iTargetShell); | 
|  | ++iTargetShell; | 
|  |  | 
|  | // 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; | 
|  | } | 
|  | if (mrBase.GetDispatcher() != NULL) | 
|  | mrBase.GetDispatcher()->Flush(); | 
|  |  | 
|  | // Update the pointer to the top-most shell and set its undo manager | 
|  | // to the one of the previous top-most shell. | 
|  | mpTopShell = mrBase.GetSubShell(0); | 
|  | if (mpTopShell!=NULL && pUndoManager!=NULL && mpTopShell->GetUndoManager()==NULL) | 
|  | mpTopShell->SetUndoManager(pUndoManager); | 
|  |  | 
|  | // 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\r"); | 
|  | DumpSfxShellStack(); | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::TakeShellsFromStack (const SfxShell* pShell) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | // Remember the undo manager from the top-most shell on the stack. | 
|  | SfxShell* pTopMostShell = mrBase.GetSubShell(0); | 
|  | ::svl::IUndoManager* pUndoManager = (pTopMostShell!=NULL) | 
|  | ? pTopMostShell->GetUndoManager() | 
|  | : NULL; | 
|  |  | 
|  | #ifdef VERBOSE | 
|  | OSL_TRACE("TakeShellsFromStack(%p)\r", pShell); | 
|  | DumpSfxShellStack(); | 
|  | #endif | 
|  |  | 
|  | // 0.Make sure that the given shell is on the stack.  This is a | 
|  | // preparation for the following assertion. | 
|  | for (sal_uInt16 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; | 
|  | } | 
|  |  | 
|  | if (pShell != NULL) | 
|  | { | 
|  | // 1. Deactivate our shells on the stack before they are removed so | 
|  | // that during the Deactivation() calls the stack is still intact. | 
|  | for (sal_uInt16 nIndex=0; true; nIndex++) | 
|  | { | 
|  | SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex); | 
|  | Deactivate(pShellOnStack); | 
|  | 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\r", pShellOnStack); | 
|  | #endif | 
|  | mrBase.RemoveSubShell(pShellOnStack); | 
|  | if (pShellOnStack == pShell) | 
|  | break; | 
|  | } | 
|  |  | 
|  | // 3. Update the stack. | 
|  | if (mrBase.GetDispatcher() != NULL) | 
|  | mrBase.GetDispatcher()->Flush(); | 
|  |  | 
|  | // Update the pointer to the top-most shell and set its undo manager | 
|  | // to the one of the previous top-most shell. | 
|  | mpTopShell = mrBase.GetSubShell(0); | 
|  | if (mpTopShell!=NULL && pUndoManager!=NULL && mpTopShell->GetUndoManager()==NULL) | 
|  | mpTopShell->SetUndoManager(pUndoManager); | 
|  | } | 
|  |  | 
|  | #ifdef VERBOSE | 
|  | OSL_TRACE("Sfx shell stack is:\r"); | 
|  | DumpSfxShellStack(); | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::CreateShells (void) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | // Iterate over all view shells. | 
|  | ShellStack aShellStack; | 
|  | ActiveShellList::reverse_iterator iShell; | 
|  | for (iShell=maActiveViewShells.rbegin(); iShell!=maActiveViewShells.rend(); ++iShell) | 
|  | { | 
|  | // Get the list of associated sub shells. | 
|  | SubShellList::iterator iList (maActiveSubShells.find(iShell->mpShell)); | 
|  | if (iList != maActiveSubShells.end()) | 
|  | { | 
|  | SubShellSubList& rList (iList->second); | 
|  |  | 
|  | // Iterate over all sub shells of the current view shell. | 
|  | SubShellSubList::iterator iSubShell; | 
|  | for (iSubShell=rList.begin(); iSubShell!=rList.end(); ++iSubShell) | 
|  | { | 
|  | if (iSubShell->mpShell == NULL) | 
|  | { | 
|  | *iSubShell = CreateSubShell(iShell->mpShell,iSubShell->mnId,NULL,NULL); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::CreateTargetStack (ShellStack& rStack) const | 
|  | { | 
|  | // 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. | 
|  | for (ActiveShellList::const_reverse_iterator iViewShell (maActiveViewShells.rbegin()); | 
|  | iViewShell != maActiveViewShells.rend(); | 
|  | ++iViewShell) | 
|  | { | 
|  | // Possibly place the form shell below the current view shell. | 
|  | if ( ! mbFormShellAboveParent | 
|  | && mpFormShell!=NULL | 
|  | && iViewShell->mpShell==mpFormShellParent) | 
|  | { | 
|  | rStack.push_back(mpFormShell); | 
|  | } | 
|  |  | 
|  | // Put the view shell itself on the local stack. | 
|  | rStack.push_back (iViewShell->mpShell); | 
|  |  | 
|  | // Possibly place the form shell above the current view shell. | 
|  | if (mbFormShellAboveParent | 
|  | && mpFormShell!=NULL | 
|  | && iViewShell->mpShell==mpFormShellParent) | 
|  | { | 
|  | rStack.push_back(mpFormShell); | 
|  | } | 
|  |  | 
|  | // Add all other sub shells. | 
|  | SubShellList::const_iterator iList (maActiveSubShells.find(iViewShell->mpShell)); | 
|  | if (iList != maActiveSubShells.end()) | 
|  | { | 
|  | const SubShellSubList& rList (iList->second); | 
|  | SubShellSubList::const_reverse_iterator iSubShell; | 
|  | for (iSubShell=rList.rbegin(); iSubShell!=rList.rend(); ++iSubShell) | 
|  | if (iSubShell->mpShell != mpFormShell) | 
|  | rStack.push_back(iSubShell->mpShell); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | IMPL_LINK(ViewShellManager::Implementation, WindowEventHandler, VclWindowEvent*, pEvent) | 
|  | { | 
|  | if (pEvent != NULL) | 
|  | { | 
|  | ::Window* pEventWindow | 
|  | = static_cast<VclWindowEvent*>(pEvent)->GetWindow(); | 
|  |  | 
|  | switch (pEvent->GetId()) | 
|  | { | 
|  | case VCLEVENT_WINDOW_GETFOCUS: | 
|  | { | 
|  | for (ActiveShellList::iterator aI(maActiveViewShells.begin()); | 
|  | aI!=maActiveViewShells.end(); | 
|  | aI++) | 
|  | { | 
|  | if (pEventWindow == static_cast< ::Window*>(aI->GetWindow())) | 
|  | { | 
|  | MoveToTop(*aI->mpShell); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case VCLEVENT_WINDOW_LOSEFOCUS: | 
|  | break; | 
|  |  | 
|  | case VCLEVENT_OBJECT_DYING: | 
|  | // Remember that we do not have to remove the window | 
|  | // listener for this window. | 
|  | for (ActiveShellList::iterator | 
|  | iShell(maActiveViewShells.begin()), | 
|  | iEnd(maActiveViewShells.end()); | 
|  | iShell!=iEnd; | 
|  | ++iShell) | 
|  | { | 
|  | if (iShell->GetWindow() == pEventWindow) | 
|  | { | 
|  | iShell->mbIsListenerAddedToWindow = false; | 
|  | break; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | ShellDescriptor ViewShellManager::Implementation::CreateSubShell ( | 
|  | SfxShell* pParentShell, | 
|  | ShellId nShellId, | 
|  | ::Window* pParentWindow, | 
|  | FrameView* pFrameView) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  | ShellDescriptor aResult; | 
|  |  | 
|  | // Look up the factories for the parent shell. | 
|  | ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( | 
|  | maShellFactories.equal_range(pParentShell)); | 
|  |  | 
|  | // Try all factories to create the shell. | 
|  | for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) | 
|  | { | 
|  | SharedShellFactory pFactory = iFactory->second; | 
|  | if( bool(pFactory)) | 
|  | aResult.mpShell = pFactory->CreateShell(nShellId, pParentWindow, pFrameView); | 
|  |  | 
|  | // Exit the loop when the shell has been successfully created. | 
|  | if (aResult.mpShell != NULL) | 
|  | { | 
|  | aResult.mpFactory = pFactory; | 
|  | aResult.mnId = nShellId; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return aResult; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::DestroyViewShell ( | 
|  | ShellDescriptor& rDescriptor) | 
|  | { | 
|  | OSL_ASSERT(rDescriptor.mpShell != NULL); | 
|  |  | 
|  | if (rDescriptor.mbIsListenerAddedToWindow) | 
|  | { | 
|  | rDescriptor.mbIsListenerAddedToWindow = false; | 
|  | ::Window* pWindow = rDescriptor.GetWindow(); | 
|  | if (pWindow != NULL) | 
|  | { | 
|  | pWindow->RemoveEventListener( | 
|  | LINK(this, ViewShellManager::Implementation, WindowEventHandler)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Destroy the sub shell factories. | 
|  | ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( | 
|  | maShellFactories.equal_range(rDescriptor.mpShell)); | 
|  | if (aRange.first != maShellFactories.end()) | 
|  | maShellFactories.erase(aRange.first, aRange.second); | 
|  |  | 
|  | // Release the shell. | 
|  | if (rDescriptor.mpFactory.get() != NULL) | 
|  | rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::DestroySubShell ( | 
|  | const SfxShell& rParentShell, | 
|  | const ShellDescriptor& rDescriptor) | 
|  | { | 
|  | (void)rParentShell; | 
|  | OSL_ASSERT(rDescriptor.mpFactory.get() != NULL); | 
|  | rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::InvalidateAllSubShells (const SfxShell* pParentShell) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | SubShellList::iterator iList (maActiveSubShells.find(pParentShell)); | 
|  | if (iList != maActiveSubShells.end()) | 
|  | { | 
|  | SubShellSubList& rList (iList->second); | 
|  | SubShellSubList::iterator iShell; | 
|  | for (iShell=rList.begin(); iShell!=rList.end(); ++iShell) | 
|  | if (iShell->mpShell != NULL) | 
|  | iShell->mpShell->Invalidate(); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::Shutdown (void) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | // Take stacked shells from stack. | 
|  | if ( ! maActiveViewShells.empty()) | 
|  | { | 
|  | UpdateLock aLock (*this); | 
|  |  | 
|  |  | 
|  | while ( ! maActiveViewShells.empty()) | 
|  | { | 
|  | SfxShell* pShell = maActiveViewShells.front().mpShell; | 
|  | if (pShell != NULL) | 
|  | { | 
|  | ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell); | 
|  | if (pViewShell != NULL) | 
|  | DeactivateViewShell(*pViewShell); | 
|  | else | 
|  | DeactivateShell(*pShell); | 
|  | } | 
|  | else | 
|  | { | 
|  | DBG_ASSERT(false, | 
|  | "ViewShellManager::Implementation::Shutdown(): empty active shell descriptor"); | 
|  | maActiveViewShells.pop_front(); | 
|  | } | 
|  | } | 
|  | } | 
|  | mrBase.RemoveSubShell (NULL); | 
|  |  | 
|  | maShellFactories.clear(); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | #ifdef VERBOSE | 
|  | void ViewShellManager::Implementation::DumpShellStack (const ShellStack& rStack) | 
|  | { | 
|  | ShellStack::const_reverse_iterator iEntry; | 
|  | for (iEntry=rStack.rbegin(); iEntry!=rStack.rend(); ++iEntry) | 
|  | if (*iEntry != NULL) | 
|  | OSL_TRACE ("    %p : %s\r", | 
|  | *iEntry, | 
|  | ::rtl::OUStringToOString((*iEntry)->GetName(),RTL_TEXTENCODING_UTF8).getStr()); | 
|  | else | 
|  | OSL_TRACE("     null\r"); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::DumpSfxShellStack (void) | 
|  | { | 
|  | ShellStack aSfxShellStack; | 
|  | sal_uInt16 nIndex (0); | 
|  | while (mrBase.GetSubShell(nIndex)!=NULL) | 
|  | ++nIndex; | 
|  | aSfxShellStack.reserve(nIndex); | 
|  | while (nIndex-- > 0) | 
|  | aSfxShellStack.push_back(mrBase.GetSubShell(nIndex)); | 
|  | DumpShellStack(aSfxShellStack); | 
|  | } | 
|  | #endif | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::Deactivate (SfxShell* pShell) | 
|  | { | 
|  | OSL_ASSERT(pShell!=NULL); | 
|  |  | 
|  | // We have to end a text edit for view shells that are to be taken from | 
|  | // the shell stack. | 
|  | ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell); | 
|  | if (pViewShell != NULL) | 
|  | { | 
|  | sd::View* pView = pViewShell->GetView(); | 
|  | if (pView!=NULL && pView->IsTextEdit()) | 
|  | { | 
|  | pView->SdrEndTextEdit(); | 
|  | pView->UnmarkAll(); | 
|  | pViewShell->GetViewFrame()->GetDispatcher()->Execute( | 
|  | SID_OBJECT_SELECT, | 
|  | SFX_CALLMODE_ASYNCHRON); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Now we can deactivate the shell. | 
|  | pShell->Deactivate(true); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void ViewShellManager::Implementation::SetFormShell ( | 
|  | const ViewShell* pFormShellParent, | 
|  | FmFormShell* pFormShell, | 
|  | bool bFormShellAboveParent) | 
|  | { | 
|  | ::osl::MutexGuard aGuard (maMutex); | 
|  |  | 
|  | mpFormShellParent = pFormShellParent; | 
|  | mpFormShell = pFormShell; | 
|  | mbFormShellAboveParent = bFormShellAboveParent; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | ShellDescriptor::ShellDescriptor (void) | 
|  | : mpShell(NULL), | 
|  | mnId(0), | 
|  | mpFactory(), | 
|  | mbIsListenerAddedToWindow(false) | 
|  | { | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | ShellDescriptor::ShellDescriptor ( | 
|  | SfxShell* pShell, | 
|  | ShellId nId) | 
|  | : mpShell(pShell), | 
|  | mnId(nId), | 
|  | mpFactory(), | 
|  | mbIsListenerAddedToWindow(false) | 
|  | { | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | ShellDescriptor::ShellDescriptor (const ShellDescriptor& rDescriptor) | 
|  | : mpShell(rDescriptor.mpShell), | 
|  | mnId(rDescriptor.mnId), | 
|  | mpFactory(rDescriptor.mpFactory), | 
|  | mbIsListenerAddedToWindow(rDescriptor.mbIsListenerAddedToWindow) | 
|  | { | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | ShellDescriptor& ShellDescriptor::operator= (const ShellDescriptor& rDescriptor) | 
|  | { | 
|  | if (this != &rDescriptor) | 
|  | { | 
|  | mpShell = rDescriptor.mpShell; | 
|  | mnId = rDescriptor.mnId; | 
|  | mpFactory = rDescriptor.mpFactory; | 
|  | mbIsListenerAddedToWindow = rDescriptor.mbIsListenerAddedToWindow; | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | bool ShellDescriptor::IsMainViewShell (void) const | 
|  | { | 
|  | ViewShell* pViewShell = dynamic_cast<ViewShell*>(mpShell); | 
|  | if (pViewShell != NULL) | 
|  | return pViewShell->IsMainViewShell(); | 
|  | else | 
|  | return false; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | ::Window* ShellDescriptor::GetWindow (void) const | 
|  | { | 
|  | ViewShell* pViewShell = dynamic_cast<ViewShell*>(mpShell); | 
|  | if (pViewShell != NULL) | 
|  | return pViewShell->GetActiveWindow(); | 
|  | else | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | } // end of anonymous namespace | 
|  |  | 
|  | } // end of namespace sd |