update dev300-m58
[ooovba.git] / sd / source / ui / view / ViewShellManager.cxx
blobec13f26614476e19215c69c479c1982fa5785f5e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ViewShellManager.cxx,v $
10 * $Revision: 1.21 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sd.hxx"
34 #include "ViewShellManager.hxx"
35 #include "ViewShell.hxx"
36 #include "ViewShellBase.hxx"
37 #include "Window.hxx"
38 #include "DrawDocShell.hxx"
39 #include "FormShellManager.hxx"
41 #include <sfx2/dispatch.hxx>
42 #include <svx/svxids.hrc>
43 #include <svx/fmshell.hxx>
45 #include <hash_map>
47 #undef VERBOSE
48 #define VERBOSE 2
50 namespace sd {
52 namespace {
54 /** The ShellDescriptor class is used to shells together with their ids and
55 the factory that was used to create the shell.
57 The shell pointer may be NULL. In that case the shell is created on
58 demand by a factory.
60 The factory pointer may be NULL. In that case the shell pointer is
61 given to the ViewShellManager.
63 Shell pointer and factory pointer can but should not be NULL at the same
64 time.
66 class ShellDescriptor {
67 public:
68 SfxShell* mpShell;
69 ShellId mnId;
70 ViewShellManager::SharedShellFactory mpFactory;
71 ShellDescriptor ();
72 ShellDescriptor (SfxShell* pShell, ShellId nId);
73 ShellDescriptor (const ShellDescriptor& rDescriptor);
74 ShellDescriptor& operator= (const ShellDescriptor& rDescriptor);
75 bool IsMainViewShell (void) const;
76 ::Window* GetWindow (void) const;
82 /** This functor can be used to search for a shell in an STL container when the
83 shell pointer is given.
85 class IsShell : public ::std::unary_function<ShellDescriptor,bool>
87 public:
88 IsShell (const SfxShell* pShell) : mpShell(pShell) {}
89 bool operator() (const ShellDescriptor& rDescriptor)
90 { return rDescriptor.mpShell == mpShell; }
91 private:
92 const SfxShell* mpShell;
98 /** This functor can be used to search for a shell in an STL container when the
99 id of the shell is given.
101 class IsId : public ::std::unary_function<ShellDescriptor,bool>
103 public:
104 IsId (ShellId nId) : mnId(nId) {}
105 bool operator() (const ShellDescriptor& rDescriptor)
106 { return rDescriptor.mnId == mnId; }
107 private:
108 ShellId mnId;
111 } // end of anonymous namespace
116 class ViewShellManager::Implementation
118 public:
119 Implementation (
120 ViewShellManager& rManager,
121 ViewShellBase& rBase);
122 ~Implementation (void);
124 void AddShellFactory (
125 const SfxShell* pViewShell,
126 const SharedShellFactory& rpFactory);
127 void RemoveShellFactory (
128 const SfxShell* pViewShell,
129 const SharedShellFactory& rpFactory);
130 ViewShell* ActivateViewShell (
131 ShellId nId,
132 ::Window* pParentWindow,
133 FrameView* pFrameView);
134 void ActivateViewShell (
135 ViewShell* pViewShell);
136 void DeactivateViewShell (const ViewShell& rShell);
137 void ActivateShell (SfxShell& rShell);
138 void DeactivateShell (const SfxShell& rShell);
139 void ActivateShell (const ShellDescriptor& rDescriptor);
140 void SetFormShell (const ViewShell* pViewShell, FmFormShell* pFormShell, bool bAbove);
141 void ActivateSubShell (const SfxShell& rParentShell, ShellId nId);
142 void DeactivateSubShell (const SfxShell& rParentShell, ShellId nId);
143 void DeactivateAllSubShells (const SfxShell& rViewShell);
144 void MoveSubShellToTop (const SfxShell& rParentShell, ShellId nId);
145 void MoveToTop (const SfxShell& rParentShell);
146 SfxShell* GetShell (ShellId nId) const;
147 SfxShell* GetTopShell (void) const;
148 ShellId GetShellId (const SfxShell* pShell) const;
149 void ReplaceUndoManager (SfxUndoManager* pManager, SfxUndoManager* pReplacement);
150 void Shutdown (void);
151 void InvalidateAllSubShells (const SfxShell* pParentShell);
153 /** Remove all shells from the SFX stack above and including the given
154 shell.
156 void TakeShellsFromStack (const SfxShell* pShell);
158 class UpdateLock
160 public:
161 UpdateLock (Implementation& rImpl) : mrImpl(rImpl) {mrImpl.LockUpdate();}
162 ~UpdateLock (void) {mrImpl.UnlockUpdate();};
163 private:
164 Implementation& mrImpl;
169 /** Prevent updates of the shell stack. While the sub shell manager is
170 locked it will update its internal data structures but not alter the
171 shell stack. Use this method when there are several modifications
172 to the shell stack to prevent multiple rebuilds of the shell stack
173 and resulting broadcasts.
175 void LockUpdate (void);
177 /** Allow updates of the shell stack. This method has to be called the
178 same number of times as LockUpdate() to really allow a rebuild of
179 the shell stack.
181 void UnlockUpdate (void);
183 private:
184 ViewShellBase& mrBase;
185 mutable ::osl::Mutex maMutex;
187 class ShellHash{public: size_t operator()(const SfxShell* p) const { return (size_t)p;} };
188 typedef ::std::hash_multimap<const SfxShell*,SharedShellFactory,ShellHash>
189 FactoryList;
190 FactoryList maShellFactories;
192 /** List of the active view shells. In order to create gather all shells
193 to put on the shell stack each view shell in this list is asked for
194 its sub-shells (typically toolbars).
196 typedef ::std::list<ShellDescriptor> ActiveShellList;
197 ActiveShellList maActiveViewShells;
199 typedef ::std::list<ShellDescriptor> SubShellSubList;
200 typedef ::std::hash_map<const SfxShell*,SubShellSubList,ShellHash> SubShellList;
201 SubShellList maActiveSubShells;
203 /** In this member we remember what shells we have pushed on the shell
204 stack.
206 typedef ::std::vector<SfxShell*> ShellStack;
208 int mnUpdateLockCount;
210 /** When this flag is set then the main view shell is always kept at the
211 top of the shell stack.
213 bool mbKeepMainViewShellOnTop;
215 /** The UpdateShellStack() method can be called recursively. This flag
216 is used to communicate between different levels of invocation: if
217 the stack has been updated in an inner call the outer call can (has
218 to) stop and return immediately.
220 bool mbShellStackIsUpToDate;
222 SfxShell* mpFormShell;
223 const ViewShell* mpFormShellParent;
224 bool mbFormShellAboveParent;
226 SfxShell* mpTopShell;
228 void GatherActiveShells (ShellStack& rShellList);
230 void UpdateShellStack (void);
232 void CreateShells (void);
234 /** This method rebuilds the stack of shells that are stacked upon the
235 view shell base.
237 void CreateTargetStack (ShellStack& rStack) const;
239 DECL_LINK(WindowEventHandler, VclWindowEvent*);
241 void DumpActiveShell (const ActiveShellList& rList);
242 void DumpShellStack (const ShellStack& rStack);
243 void DumpSfxShellStack (void);
245 /** To be called before a shell is taken fom the SFX shell stack. This
246 method deactivates an active text editing to avoid problems with
247 undo managers.
248 Afterwards the Deactivate() of the shell is called.
250 void Deactivate (SfxShell* pShell);
252 ShellDescriptor CreateViewShell (
253 ShellId nShellId,
254 ::Window* pParentWindow,
255 FrameView* pFrameView);
256 ShellDescriptor CreateSubShell (
257 SfxShell* pShell,
258 ShellId nShellId,
259 ::Window* pParentWindow,
260 FrameView* pFrameView);
261 void DestroyViewShell (const ShellDescriptor& rDescriptor);
262 void DestroySubShell (
263 const SfxShell& rViewShell,
264 const ShellDescriptor& rDescriptor);
270 //===== ViewShellManager ======================================================
272 ViewShellManager::ViewShellManager (ViewShellBase& rBase)
273 : mpImpl(new Implementation(*this,rBase)),
274 mbValid(true)
281 ViewShellManager::~ViewShellManager (void)
288 void ViewShellManager::AddSubShellFactory (
289 ViewShell* pViewShell,
290 const SharedShellFactory& rpFactory)
292 if (mbValid)
293 mpImpl->AddShellFactory(pViewShell, rpFactory);
299 void ViewShellManager::RemoveSubShellFactory (
300 ViewShell* pViewShell,
301 const SharedShellFactory& rpFactory)
303 if (mbValid)
304 mpImpl->RemoveShellFactory(pViewShell, rpFactory);
310 ViewShell* ViewShellManager::ActivateViewShell (
311 ShellId nShellId,
312 ::Window* pParentWindow,
313 FrameView* pFrameView)
315 if (mbValid)
316 return mpImpl->ActivateViewShell(nShellId,pParentWindow,pFrameView);
317 else
318 return NULL;
324 void ViewShellManager::ActivateViewShell (ViewShell* pViewShell)
326 if (mbValid)
327 return mpImpl->ActivateViewShell(pViewShell);
333 void ViewShellManager::DeactivateViewShell (const ViewShell* pShell)
335 if (mbValid && pShell!=NULL)
336 mpImpl->DeactivateViewShell(*pShell);
342 void ViewShellManager::MoveSubShellToTop (
343 const ViewShell& rParentShell,
344 ShellId nId)
346 if (mbValid)
347 mpImpl->MoveSubShellToTop(rParentShell, nId);
353 void ViewShellManager::SetFormShell (
354 const ViewShell* pParentShell,
355 FmFormShell* pFormShell,
356 bool bAbove)
358 if (mbValid)
359 mpImpl->SetFormShell(pParentShell,pFormShell,bAbove);
365 void ViewShellManager::ActivateSubShell (const ViewShell& rViewShell, ShellId nId)
367 if (mbValid)
368 mpImpl->ActivateSubShell(rViewShell,nId);
374 void ViewShellManager::DeactivateSubShell (const ViewShell& rViewShell, ShellId nId)
376 if (mbValid)
377 mpImpl->DeactivateSubShell(rViewShell,nId);
383 void ViewShellManager::DeactivateAllSubShells (const ViewShell& rViewShell)
385 if (mbValid)
386 mpImpl->DeactivateAllSubShells(rViewShell);
392 void ViewShellManager::InvalidateAllSubShells (ViewShell* pViewShell)
394 if (mbValid)
395 mpImpl->InvalidateAllSubShells(pViewShell);
401 void ViewShellManager::ActivateShell (SfxShell* pShell)
403 if (mbValid && pShell!=NULL)
404 mpImpl->ActivateShell(*pShell);
410 void ViewShellManager::DeactivateShell (const SfxShell* pShell)
412 if (mbValid && pShell!=NULL)
413 mpImpl->DeactivateShell(*pShell);
419 void ViewShellManager::InvalidateShellStack (const SfxShell* pShell)
421 if (mbValid)
422 mpImpl->TakeShellsFromStack(pShell);
428 void ViewShellManager::MoveToTop (const ViewShell& rParentShell)
430 if (mbValid)
431 mpImpl->MoveToTop(rParentShell);
437 SfxShell* ViewShellManager::GetShell (ShellId nId) const
439 if (mbValid)
440 return mpImpl->GetShell(nId);
441 else
442 return NULL;
448 SfxShell* ViewShellManager::GetTopShell (void) const
450 if (mbValid)
451 return mpImpl->GetTopShell();
452 else
453 return NULL;
459 ShellId ViewShellManager::GetShellId (const SfxShell* pShell) const
461 if (mbValid)
462 return mpImpl->GetShellId(pShell);
463 else
464 return snInvalidShellId;
470 void ViewShellManager::ReplaceUndoManager (SfxUndoManager* pManager, SfxUndoManager* pReplacement)
472 if (mbValid)
473 mpImpl->ReplaceUndoManager(pManager,pReplacement);
479 void ViewShellManager::Shutdown (void)
481 if (mbValid)
483 mpImpl->Shutdown();
484 mbValid = false;
490 void ViewShellManager::LockUpdate (void)
492 mpImpl->LockUpdate();
498 void ViewShellManager::UnlockUpdate (void)
500 mpImpl->UnlockUpdate();
506 //===== ViewShellManager::Implementation ======================================
508 ViewShellManager::Implementation::Implementation (
509 ViewShellManager& rManager,
510 ViewShellBase& rBase)
511 : mrBase(rBase),
512 maMutex(),
513 maShellFactories(),
514 maActiveViewShells(),
515 mnUpdateLockCount(0),
516 mbKeepMainViewShellOnTop(false),
517 mbShellStackIsUpToDate(true),
518 mpFormShell(NULL),
519 mpFormShellParent(NULL),
520 mbFormShellAboveParent(true),
521 mpTopShell(NULL)
523 (void)rManager;
529 ViewShellManager::Implementation::~Implementation (void)
531 Shutdown();
537 void ViewShellManager::Implementation::AddShellFactory (
538 const SfxShell* pViewShell,
539 const SharedShellFactory& rpFactory)
541 bool bAlreadyAdded (false);
543 // Check that the given factory has not already been added.
544 ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
545 maShellFactories.equal_range(pViewShell));
546 for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
547 if (iFactory->second == rpFactory)
549 bAlreadyAdded = true;
550 break;
553 // Add the factory if it is not already present.
554 if ( ! bAlreadyAdded)
555 maShellFactories.insert(FactoryList::value_type(pViewShell, rpFactory));
561 void ViewShellManager::Implementation::RemoveShellFactory (
562 const SfxShell* pViewShell,
563 const SharedShellFactory& rpFactory)
565 ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
566 maShellFactories.equal_range(pViewShell));
567 for (FactoryList::iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
568 if (iFactory->second == rpFactory)
570 maShellFactories.erase(iFactory);
571 break;
578 ViewShell* ViewShellManager::Implementation::ActivateViewShell (
579 ShellId nShellId,
580 ::Window* pParentWindow,
581 FrameView* pFrameView)
583 ::osl::MutexGuard aGuard (maMutex);
585 // Create a new shell or recycle on in the cache.
586 ShellDescriptor aDescriptor (CreateViewShell(nShellId, pParentWindow, pFrameView));
588 ActivateShell(aDescriptor);
590 return dynamic_cast<ViewShell*>(aDescriptor.mpShell);
596 void ViewShellManager::Implementation::ActivateViewShell (ViewShell* pViewShell)
598 ::osl::MutexGuard aGuard (maMutex);
600 ShellDescriptor aResult;
601 aResult.mpShell = pViewShell;
603 // Register as window listener so that the shells of the current
604 // window can be moved to the top of the shell stack.
605 if (aResult.mpShell != NULL)
607 ::Window* pWindow = aResult.GetWindow();
608 if (pWindow != NULL)
609 pWindow->AddEventListener(
610 LINK(this, ViewShellManager::Implementation, WindowEventHandler));
611 else
613 DBG_ASSERT(false,
614 "ViewShellManager::ActivateViewShell: "
615 "new view shell has no active window");
619 ActivateShell(aResult);
625 void ViewShellManager::Implementation::DeactivateViewShell (const ViewShell& rShell)
627 ::osl::MutexGuard aGuard (maMutex);
629 ActiveShellList::iterator iShell (::std::find_if (
630 maActiveViewShells.begin(),
631 maActiveViewShells.end(),
632 IsShell(&rShell)));
633 if (iShell != maActiveViewShells.end())
635 UpdateLock aLocker (*this);
637 ShellDescriptor aDescriptor(*iShell);
638 mrBase.GetDocShell()->Disconnect(dynamic_cast<ViewShell*>(aDescriptor.mpShell));
639 maActiveViewShells.erase(iShell);
640 TakeShellsFromStack(aDescriptor.mpShell);
642 // Deactivate sub shells.
643 SubShellList::iterator iList (maActiveSubShells.find(&rShell));
644 if (iList != maActiveSubShells.end())
646 SubShellSubList& rList (iList->second);
647 while ( ! rList.empty())
648 DeactivateSubShell(rShell, rList.front().mnId);
651 DestroyViewShell(aDescriptor);
658 void ViewShellManager::Implementation::ActivateShell (SfxShell& rShell)
660 ::osl::MutexGuard aGuard (maMutex);
662 // Create a new shell or recycle on in the cache.
663 ShellDescriptor aDescriptor;
664 aDescriptor.mpShell = &rShell;
666 ActivateShell(aDescriptor);
672 void ViewShellManager::Implementation::ActivateShell (const ShellDescriptor& rDescriptor)
674 // Put shell on top of the active view shells.
675 if (rDescriptor.mpShell != NULL)
677 // Determine where to put the view shell on the stack. By default
678 // it is put on top of the stack. When the view shell of the center
679 // pane is to be kept top most and the new view shell is not
680 // displayed in the center pane then it is inserted at the position
681 // one below the top.
682 ActiveShellList::iterator iInsertPosition (maActiveViewShells.begin());
683 if (iInsertPosition != maActiveViewShells.end()
684 && mbKeepMainViewShellOnTop
685 && ! rDescriptor.IsMainViewShell()
686 && iInsertPosition->IsMainViewShell())
688 ++iInsertPosition;
690 maActiveViewShells.insert(
691 iInsertPosition,
692 rDescriptor);
699 void ViewShellManager::Implementation::DeactivateShell (const SfxShell& rShell)
701 ::osl::MutexGuard aGuard (maMutex);
703 ActiveShellList::iterator iShell (::std::find_if (
704 maActiveViewShells.begin(),
705 maActiveViewShells.end(),
706 IsShell(&rShell)));
707 if (iShell != maActiveViewShells.end())
709 UpdateLock aLocker (*this);
711 ShellDescriptor aDescriptor(*iShell);
712 mrBase.GetDocShell()->Disconnect(dynamic_cast<ViewShell*>(aDescriptor.mpShell));
713 maActiveViewShells.erase(iShell);
714 TakeShellsFromStack(aDescriptor.mpShell);
716 // Deactivate sub shells.
717 SubShellList::iterator iList (maActiveSubShells.find(&rShell));
718 if (iList != maActiveSubShells.end())
720 SubShellSubList& rList (iList->second);
721 while ( ! rList.empty())
722 DeactivateSubShell(rShell, rList.front().mnId);
725 DestroyViewShell(aDescriptor);
732 void ViewShellManager::Implementation::ActivateSubShell (
733 const SfxShell& rParentShell,
734 ShellId nId)
736 ::osl::MutexGuard aGuard (maMutex);
740 // Check that the given view shell is active.
741 ActiveShellList::iterator iShell (::std::find_if (
742 maActiveViewShells.begin(),
743 maActiveViewShells.end(),
744 IsShell(&rParentShell)));
745 if (iShell == maActiveViewShells.end())
746 break;
748 // Create the sub shell list if it does not yet exist.
749 SubShellList::iterator iList (maActiveSubShells.find(&rParentShell));
750 if (iList == maActiveSubShells.end())
751 iList = maActiveSubShells.insert(
752 SubShellList::value_type(&rParentShell,SubShellSubList())).first;
754 // Do not activate an object bar that is already active. Requesting
755 // this is not exactly an error but may be an indication of one.
756 SubShellSubList& rList (iList->second);
757 if (::std::find_if(rList.begin(),rList.end(), IsId(nId)) != rList.end())
758 break;
760 // Add just the id of the sub shell. The actual shell is created
761 // later in CreateShells().
762 UpdateLock aLock (*this);
763 rList.push_back(ShellDescriptor(NULL, nId));
765 while (false);
771 void ViewShellManager::Implementation::DeactivateSubShell (
772 const SfxShell& rParentShell,
773 ShellId nId)
775 ::osl::MutexGuard aGuard (maMutex);
779 // Check that the given view shell is active.
780 SubShellList::iterator iList (maActiveSubShells.find(&rParentShell));
781 if (iList == maActiveSubShells.end())
782 break;
784 // Look up the sub shell.
785 SubShellSubList& rList (iList->second);
786 SubShellSubList::iterator iShell (
787 ::std::find_if(rList.begin(),rList.end(), IsId(nId)));
788 if (iShell == rList.end())
789 break;
790 SfxShell* pShell = iShell->mpShell;
791 if (pShell == NULL)
792 break;
794 UpdateLock aLock (*this);
796 ShellDescriptor aDescriptor(*iShell);
797 // Remove the sub shell from both the internal structure as well as the
798 // SFX shell stack above and including the sub shell.
799 rList.erase(iShell);
800 TakeShellsFromStack(pShell);
802 DestroySubShell(rParentShell, aDescriptor);
804 while (false);
810 void ViewShellManager::Implementation::MoveSubShellToTop (
811 const SfxShell& rParentShell,
812 ShellId nId)
814 SubShellList::iterator iList (maActiveSubShells.find(&rParentShell));
815 if (iList != maActiveSubShells.end())
817 // Look up the sub shell.
818 SubShellSubList& rList (iList->second);
819 SubShellSubList::iterator iShell (
820 ::std::find_if(rList.begin(),rList.end(), IsId(nId)));
821 if (iShell!=rList.end() && iShell!=rList.begin())
823 SubShellSubList::value_type aEntry (*iShell);
824 rList.erase(iShell);
825 rList.push_front(aEntry);
828 else
830 // Ignore this call when there are no sub shells for the given
831 // parent shell. We could remember the sub shell to move to the top
832 // but we do not. Do call this method at a later time instead.
838 void ViewShellManager::Implementation::MoveToTop (const SfxShell& rShell)
840 ::osl::MutexGuard aGuard (maMutex);
842 // Check that we have access to a dispatcher. If not, then we are
843 // (probably) called while the view shell is still being created or
844 // initialized. Without dispatcher we can not rebuild the shell stack
845 // to move the requested shell to the top. So return right away instead
846 // of making a mess without being able to clean up afterwards.
847 if (mrBase.GetDispatcher() == NULL)
848 return;
850 ActiveShellList::iterator iShell (::std::find_if (
851 maActiveViewShells.begin(),
852 maActiveViewShells.end(),
853 IsShell(&rShell)));
854 bool bMove = true;
855 if (iShell != maActiveViewShells.end())
857 // Is the shell already at the top of the stack? We have to keep
858 // the case in mind that mbKeepMainViewShellOnTop is true. Shells
859 // that are not the main view shell are placed on the second-to-top
860 // position in this case.
861 if (iShell == maActiveViewShells.begin()
862 && (iShell->IsMainViewShell() || ! mbKeepMainViewShellOnTop))
864 // The shell is at the top position and is either a) the main
865 // view shell or b) another shell but the main view shell is not
866 // kept at the top position. We do not have to move the shell.
867 bMove = false;
869 else if (iShell == ++maActiveViewShells.begin()
870 && ! iShell->IsMainViewShell()
871 && mbKeepMainViewShellOnTop)
873 // The shell is a the second-to-top position, not the main view
874 // shell and the main view shell is kept at the top position.
875 // Therefore we do not have to move the shell.
876 bMove = false;
879 else
881 // The shell is not on the stack. Therefore it can not be moved.
882 // We could insert it but we don't. Use ActivateViewShell() for
883 // that.
884 bMove = false;
887 // When the shell is not at the right position it is removed from the
888 // internal list of shells and inserted at the correct position.
889 if (bMove)
891 UpdateLock aLock (*this);
893 ShellDescriptor aDescriptor(*iShell);
895 TakeShellsFromStack(&rShell);
896 maActiveViewShells.erase(iShell);
898 // Find out whether to insert at the top or one below.
899 ActiveShellList::iterator aInsertPosition (maActiveViewShells.begin());
900 if (mbKeepMainViewShellOnTop && ! aDescriptor.IsMainViewShell())
902 if (maActiveViewShells.back().IsMainViewShell())
903 aInsertPosition++;
906 maActiveViewShells.insert(aInsertPosition, aDescriptor);
913 SfxShell* ViewShellManager::Implementation::GetShell (ShellId nId) const
915 ::osl::MutexGuard aGuard (maMutex);
917 SfxShell* pShell = NULL;
919 // First search the active view shells.
920 ActiveShellList::const_iterator iShell (
921 ::std::find_if (
922 maActiveViewShells.begin(),
923 maActiveViewShells.end(),
924 IsId(nId)));
925 if (iShell != maActiveViewShells.end())
926 pShell = iShell->mpShell;
927 else
929 // Now search the active sub shells of every active view shell.
930 SubShellList::const_iterator iList;
931 for (iList=maActiveSubShells.begin(); iList!=maActiveSubShells.end(); ++iList)
933 const SubShellSubList& rList (iList->second);
934 SubShellSubList::const_iterator iSubShell(
935 ::std::find_if(rList.begin(),rList.end(), IsId(nId)));
936 if (iSubShell != rList.end())
938 pShell = iSubShell->mpShell;
939 break;
944 return pShell;
950 SfxShell* ViewShellManager::Implementation::GetTopShell (void) const
952 OSL_ASSERT(mpTopShell == mrBase.GetSubShell(0));
953 return mpTopShell;
959 ShellId ViewShellManager::Implementation::GetShellId (const SfxShell* pShell) const
961 ::osl::MutexGuard aGuard (maMutex);
963 ShellId nId = snInvalidShellId;
965 // First search the active view shells.
966 const ViewShell* pViewShell = dynamic_cast<const ViewShell*>(pShell);
967 if (pShell != NULL)
969 ActiveShellList::const_iterator iShell (
970 ::std::find_if (
971 maActiveViewShells.begin(),
972 maActiveViewShells.end(),
973 IsShell(pViewShell)));
974 if (iShell != maActiveViewShells.end())
975 nId = iShell->mnId;
977 if (nId == snInvalidShellId)
979 // Now search the active sub shells of every active view shell.
980 SubShellList::const_iterator iList;
981 for (iList=maActiveSubShells.begin(); iList!=maActiveSubShells.end(); ++iList)
983 const SubShellSubList& rList (iList->second);
984 SubShellSubList::const_iterator iSubShell(
985 ::std::find_if(rList.begin(),rList.end(), IsShell(pShell)));
986 if (iSubShell != rList.end())
988 nId = iSubShell->mnId;
989 break;
994 return nId;
1000 void ViewShellManager::Implementation::ReplaceUndoManager (
1001 SfxUndoManager* pManager,
1002 SfxUndoManager* pReplacement)
1004 for (USHORT i=0; ;++i)
1006 SfxShell* pShell = mrBase.GetSubShell(i);
1007 if (pShell == NULL)
1008 break;
1009 if (pShell->GetUndoManager() == pManager)
1010 pShell->SetUndoManager(pReplacement);
1019 void ViewShellManager::Implementation::LockUpdate (void)
1021 mnUpdateLockCount++;
1027 void ViewShellManager::Implementation::UnlockUpdate (void)
1029 ::osl::MutexGuard aGuard (maMutex);
1031 mnUpdateLockCount--;
1032 if (mnUpdateLockCount < 0)
1034 // This should not happen.
1035 OSL_ASSERT (mnUpdateLockCount>=0);
1036 mnUpdateLockCount = 0;
1038 if (mnUpdateLockCount == 0)
1039 UpdateShellStack();
1045 /** Update the SFX shell stack (the portion that is visible to us) so that
1046 it matches the internal shell stack. This is done in six steps:
1047 1. Create the missing view shells and sub shells.
1048 2. Set up the internal shell stack.
1049 3. Get the SFX shell stack.
1050 4. Find the lowest shell in which the two stacks differ.
1051 5. Remove all shells above and including that shell from the SFX stack.
1052 6. Push all shells of the internal stack on the SFX shell stack that are
1053 not already present on the later.
1055 void ViewShellManager::Implementation::UpdateShellStack (void)
1057 ::osl::MutexGuard aGuard (maMutex);
1059 // Remember the undo manager from the top-most shell on the stack.
1060 SfxShell* pTopMostShell = mrBase.GetSubShell(0);
1061 SfxUndoManager* pUndoManager = (pTopMostShell!=NULL)
1062 ? pTopMostShell->GetUndoManager()
1063 : NULL;
1065 // 1. Create the missing shells.
1066 CreateShells();
1069 // 2. Create the internal target stack.
1070 ShellStack aTargetStack;
1071 CreateTargetStack(aTargetStack);
1074 // 3. Get SFX shell stack.
1075 ShellStack aSfxShellStack;
1076 USHORT nIndex (0);
1077 while (mrBase.GetSubShell(nIndex)!=NULL)
1078 ++nIndex;
1079 aSfxShellStack.reserve(nIndex);
1080 while (nIndex-- > 0)
1081 aSfxShellStack.push_back(mrBase.GetSubShell(nIndex));
1084 #ifdef VERBOSE
1085 OSL_TRACE("Current SFX Stack\r");
1086 DumpShellStack(aSfxShellStack);
1087 OSL_TRACE("Target Stack\r");
1088 DumpShellStack(aTargetStack);
1089 #endif
1092 // 4. Find the lowest shell in which the two stacks differ.
1093 ShellStack::const_iterator iSfxShell (aSfxShellStack.begin());
1094 ShellStack::iterator iTargetShell (aTargetStack.begin());
1095 while (iSfxShell != aSfxShellStack.end()
1096 && iTargetShell!=aTargetStack.end()
1097 && (*iSfxShell)==(*iTargetShell))
1099 ++iSfxShell;
1100 ++iTargetShell;
1104 // 5. Remove all shells above and including the differing shell from the
1105 // SFX stack starting with the shell on top of the stack.
1106 while (iSfxShell != aSfxShellStack.end())
1108 SfxShell* pShell = aSfxShellStack.back();
1109 aSfxShellStack.pop_back();
1110 #ifdef VERBOSE
1111 OSL_TRACE("removing shell %p from stack\r", pShell);
1112 #endif
1113 mrBase.RemoveSubShell(pShell);
1117 // 6. Push shells from the given stack onto the SFX stack.
1118 mbShellStackIsUpToDate = false;
1119 while (iTargetShell != aTargetStack.end())
1121 #ifdef VERBOSE
1122 OSL_TRACE("pushing shell %p on stack\r", *iTargetShell);
1123 #endif
1124 mrBase.AddSubShell(**iTargetShell);
1125 ++iTargetShell;
1127 // The pushing of the shell on to the shell stack may have lead to
1128 // another invocation of this method. In this case we have to abort
1129 // pushing shells on the stack and return immediately.
1130 if (mbShellStackIsUpToDate)
1131 break;
1133 if (mrBase.GetDispatcher() != NULL)
1134 mrBase.GetDispatcher()->Flush();
1136 // Update the pointer to the top-most shell and set its undo manager
1137 // to the one of the previous top-most shell.
1138 mpTopShell = mrBase.GetSubShell(0);
1139 if (mpTopShell!=NULL && pUndoManager!=NULL && mpTopShell->GetUndoManager()==NULL)
1140 mpTopShell->SetUndoManager(pUndoManager);
1142 // Finally tell an invocation of this method on a higher level that it can (has
1143 // to) abort and return immediately.
1144 mbShellStackIsUpToDate = true;
1146 #ifdef VERBOSE
1147 OSL_TRACE("New current stack\r");
1148 DumpSfxShellStack();
1149 #endif
1155 void ViewShellManager::Implementation::TakeShellsFromStack (const SfxShell* pShell)
1157 ::osl::MutexGuard aGuard (maMutex);
1159 // Remember the undo manager from the top-most shell on the stack.
1160 SfxShell* pTopMostShell = mrBase.GetSubShell(0);
1161 SfxUndoManager* pUndoManager = (pTopMostShell!=NULL)
1162 ? pTopMostShell->GetUndoManager()
1163 : NULL;
1165 #ifdef VERBOSE
1166 OSL_TRACE("TakeShellsFromStack(%p)\r", pShell);
1167 DumpSfxShellStack();
1168 #endif
1170 // 0.Make sure that the given shell is on the stack. This is a
1171 // preparation for the following assertion.
1172 for (USHORT nIndex=0; true; nIndex++)
1174 SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex);
1175 if (pShellOnStack == NULL)
1177 // Set pShell to NULL to indicate the following code that the
1178 // shell is not on the stack.
1179 pShell = NULL;
1180 break;
1182 else if (pShellOnStack == pShell)
1183 break;
1186 if (pShell != NULL)
1188 // 1. Deactivate our shells on the stack before they are removed so
1189 // that during the Deactivation() calls the stack is still intact.
1190 for (USHORT nIndex=0; true; nIndex++)
1192 SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex);
1193 Deactivate(pShellOnStack);
1194 if (pShellOnStack == pShell)
1195 break;
1198 // 2. Remove the shells from the stack.
1199 while (true)
1201 SfxShell* pShellOnStack = mrBase.GetSubShell(0);
1202 #ifdef VERBOSE
1203 OSL_TRACE("removing shell %p from stack\r", pShellOnStack);
1204 #endif
1205 mrBase.RemoveSubShell(pShellOnStack);
1206 if (pShellOnStack == pShell)
1207 break;
1210 // 3. Update the stack.
1211 if (mrBase.GetDispatcher() != NULL)
1212 mrBase.GetDispatcher()->Flush();
1214 // Update the pointer to the top-most shell and set its undo manager
1215 // to the one of the previous top-most shell.
1216 mpTopShell = mrBase.GetSubShell(0);
1217 if (mpTopShell!=NULL && pUndoManager!=NULL && mpTopShell->GetUndoManager()==NULL)
1218 mpTopShell->SetUndoManager(pUndoManager);
1221 #ifdef VERBOSE
1222 OSL_TRACE("Sfx shell stack is:\r");
1223 DumpSfxShellStack();
1224 #endif
1230 void ViewShellManager::Implementation::CreateShells (void)
1232 ::osl::MutexGuard aGuard (maMutex);
1234 // Iterate over all view shells.
1235 ShellStack aShellStack;
1236 ActiveShellList::reverse_iterator iShell;
1237 for (iShell=maActiveViewShells.rbegin(); iShell!=maActiveViewShells.rend(); ++iShell)
1239 // Get the list of associated sub shells.
1240 SubShellList::iterator iList (maActiveSubShells.find(iShell->mpShell));
1241 if (iList != maActiveSubShells.end())
1243 SubShellSubList& rList (iList->second);
1245 // Iterate over all sub shells of the current view shell.
1246 SubShellSubList::iterator iSubShell;
1247 for (iSubShell=rList.begin(); iSubShell!=rList.end(); ++iSubShell)
1249 if (iSubShell->mpShell == NULL)
1251 *iSubShell = CreateSubShell(iShell->mpShell,iSubShell->mnId,NULL,NULL);
1261 void ViewShellManager::Implementation::CreateTargetStack (ShellStack& rStack) const
1263 // Create a local stack of the shells that are to push on the shell
1264 // stack. We can thus safly create the required shells wile still
1265 // having a valid shell stack.
1266 for (ActiveShellList::const_reverse_iterator iViewShell (maActiveViewShells.rbegin());
1267 iViewShell != maActiveViewShells.rend();
1268 ++iViewShell)
1270 // Possibly place the form shell below the current view shell.
1271 if ( ! mbFormShellAboveParent
1272 && mpFormShell!=NULL
1273 && iViewShell->mpShell==mpFormShellParent)
1275 rStack.push_back(mpFormShell);
1278 // Put the view shell itself on the local stack.
1279 rStack.push_back (iViewShell->mpShell);
1281 // Possibly place the form shell above the current view shell.
1282 if (mbFormShellAboveParent
1283 && mpFormShell!=NULL
1284 && iViewShell->mpShell==mpFormShellParent)
1286 rStack.push_back(mpFormShell);
1289 // Add all other sub shells.
1290 SubShellList::const_iterator iList (maActiveSubShells.find(iViewShell->mpShell));
1291 if (iList != maActiveSubShells.end())
1293 const SubShellSubList& rList (iList->second);
1294 SubShellSubList::const_reverse_iterator iSubShell;
1295 for (iSubShell=rList.rbegin(); iSubShell!=rList.rend(); ++iSubShell)
1296 if (iSubShell->mpShell != mpFormShell)
1297 rStack.push_back(iSubShell->mpShell);
1305 IMPL_LINK(ViewShellManager::Implementation, WindowEventHandler, VclWindowEvent*, pEvent)
1307 if (pEvent != NULL)
1309 ::Window* pEventWindow
1310 = static_cast<VclWindowEvent*>(pEvent)->GetWindow();
1312 switch (pEvent->GetId())
1314 case VCLEVENT_WINDOW_GETFOCUS:
1316 for (ActiveShellList::iterator aI(maActiveViewShells.begin());
1317 aI!=maActiveViewShells.end();
1318 aI++)
1320 if (pEventWindow == static_cast< ::Window*>(aI->GetWindow()))
1322 MoveToTop(*aI->mpShell);
1323 break;
1327 break;
1329 case VCLEVENT_WINDOW_LOSEFOCUS:
1330 break;
1333 return TRUE;
1339 ShellDescriptor ViewShellManager::Implementation::CreateViewShell (
1340 ShellId nShellId,
1341 ::Window* pParentWindow,
1342 FrameView* pFrameView)
1344 ShellDescriptor aResult;
1346 if (pParentWindow != NULL)
1348 ShellDescriptor aDescriptor (
1349 CreateSubShell(NULL,nShellId,pParentWindow,pFrameView));
1350 aResult.mpShell = dynamic_cast<ViewShell*>(aDescriptor.mpShell);
1351 aResult.mpFactory = aDescriptor.mpFactory;
1352 aResult.mnId = aDescriptor.mnId;
1354 // Register as window listener so that the shells of the current
1355 // window can be moved to the top of the shell stack.
1356 if (aResult.mpShell != NULL)
1358 ::Window* pWindow = aResult.GetWindow();
1359 if (pWindow != NULL)
1360 pWindow->AddEventListener(
1361 LINK(this, ViewShellManager::Implementation, WindowEventHandler));
1362 else
1364 DBG_ASSERT (false,
1365 "ViewShellManager::ActivateViewShell: "
1366 "new view shell has no active window");
1371 return aResult;
1377 ShellDescriptor ViewShellManager::Implementation::CreateSubShell (
1378 SfxShell* pParentShell,
1379 ShellId nShellId,
1380 ::Window* pParentWindow,
1381 FrameView* pFrameView)
1383 ::osl::MutexGuard aGuard (maMutex);
1384 ShellDescriptor aResult;
1386 // Look up the factories for the parent shell.
1387 ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
1388 maShellFactories.equal_range(pParentShell));
1390 // Try all factories to create the shell.
1391 for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory)
1393 SharedShellFactory pFactory = iFactory->second;
1394 if (pFactory != NULL)
1395 aResult.mpShell = pFactory->CreateShell(nShellId, pParentWindow, pFrameView);
1397 // Exit the loop when the shell has been successfully created.
1398 if (aResult.mpShell != NULL)
1400 aResult.mpFactory = pFactory;
1401 aResult.mnId = nShellId;
1402 break;
1406 return aResult;
1412 void ViewShellManager::Implementation::DestroyViewShell (
1413 const ShellDescriptor& rDescriptor)
1415 OSL_ASSERT(rDescriptor.mpShell != NULL);
1417 ::Window* pWindow = rDescriptor.GetWindow();
1418 if (pWindow != NULL)
1420 pWindow->RemoveEventListener(
1421 LINK(this, ViewShellManager::Implementation, WindowEventHandler));
1424 // Destroy the sub shell factories.
1425 ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange(
1426 maShellFactories.equal_range(rDescriptor.mpShell));
1427 if (aRange.first != maShellFactories.end())
1428 maShellFactories.erase(aRange.first, aRange.second);
1430 // Release the shell.
1431 if (rDescriptor.mpFactory.get() != NULL)
1432 rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell);
1438 void ViewShellManager::Implementation::DestroySubShell (
1439 const SfxShell& rParentShell,
1440 const ShellDescriptor& rDescriptor)
1442 (void)rParentShell;
1443 OSL_ASSERT(rDescriptor.mpFactory.get() != NULL);
1444 rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell);
1450 void ViewShellManager::Implementation::InvalidateAllSubShells (const SfxShell* pParentShell)
1452 ::osl::MutexGuard aGuard (maMutex);
1454 SubShellList::iterator iList (maActiveSubShells.find(pParentShell));
1455 if (iList != maActiveSubShells.end())
1457 SubShellSubList& rList (iList->second);
1458 SubShellSubList::iterator iShell;
1459 for (iShell=rList.begin(); iShell!=rList.end(); ++iShell)
1460 if (iShell->mpShell != NULL)
1461 iShell->mpShell->Invalidate();
1468 void ViewShellManager::Implementation::Shutdown (void)
1470 ::osl::MutexGuard aGuard (maMutex);
1472 // Take stacked shells from stack.
1473 if ( ! maActiveViewShells.empty())
1475 UpdateLock aLock (*this);
1478 while ( ! maActiveViewShells.empty())
1480 SfxShell* pShell = maActiveViewShells.front().mpShell;
1481 if (pShell != NULL)
1483 ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell);
1484 if (pViewShell != NULL)
1485 DeactivateViewShell(*pViewShell);
1486 else
1487 DeactivateShell(*pShell);
1489 else
1491 DBG_ASSERT(false,
1492 "ViewShellManager::Implementation::Shutdown(): empty active shell descriptor");
1493 maActiveViewShells.pop_front();
1497 mrBase.RemoveSubShell (NULL);
1499 maShellFactories.clear();
1505 void ViewShellManager::Implementation::DumpActiveShell (const ActiveShellList& rList)
1507 for (ActiveShellList::const_iterator aI=rList.begin(); aI!=rList.end(); ++aI)
1508 OSL_TRACE (" %d %p\r", aI->mnId, aI->mpShell);
1514 void ViewShellManager::Implementation::DumpShellStack (const ShellStack& rStack)
1516 ShellStack::const_reverse_iterator iEntry;
1517 for (iEntry=rStack.rbegin(); iEntry!=rStack.rend(); ++iEntry)
1518 if (*iEntry != NULL)
1519 OSL_TRACE (" %p : %s\r",
1520 *iEntry,
1521 ::rtl::OUStringToOString((*iEntry)->GetName(),RTL_TEXTENCODING_UTF8).getStr());
1522 else
1523 OSL_TRACE(" null\r");
1529 void ViewShellManager::Implementation::DumpSfxShellStack (void)
1531 ShellStack aSfxShellStack;
1532 USHORT nIndex (0);
1533 while (mrBase.GetSubShell(nIndex)!=NULL)
1534 ++nIndex;
1535 aSfxShellStack.reserve(nIndex);
1536 while (nIndex-- > 0)
1537 aSfxShellStack.push_back(mrBase.GetSubShell(nIndex));
1538 DumpShellStack(aSfxShellStack);
1544 void ViewShellManager::Implementation::Deactivate (SfxShell* pShell)
1546 OSL_ASSERT(pShell!=NULL);
1548 // We have to end a text edit for view shells that are to be taken from
1549 // the shell stack.
1550 ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell);
1551 if (pViewShell != NULL)
1553 sd::View* pView = pViewShell->GetView();
1554 if (pView!=NULL && pView->IsTextEdit())
1556 pView->SdrEndTextEdit();
1557 pView->UnmarkAll();
1558 pViewShell->GetViewFrame()->GetDispatcher()->Execute(
1559 SID_OBJECT_SELECT,
1560 SFX_CALLMODE_ASYNCHRON);
1564 // Now we can deactivate the shell.
1565 pShell->Deactivate(TRUE);
1571 void ViewShellManager::Implementation::SetFormShell (
1572 const ViewShell* pFormShellParent,
1573 FmFormShell* pFormShell,
1574 bool bFormShellAboveParent)
1576 ::osl::MutexGuard aGuard (maMutex);
1578 mpFormShellParent = pFormShellParent;
1579 mpFormShell = pFormShell;
1580 mbFormShellAboveParent = bFormShellAboveParent;
1586 void ViewShellManager::Implementation::DeactivateAllSubShells (
1587 const SfxShell& rViewShell)
1589 ::osl::MutexGuard aGuard (maMutex);
1591 SubShellList::iterator iList (maActiveSubShells.find(&rViewShell));
1592 if (iList != maActiveSubShells.end())
1594 SubShellSubList& rList (iList->second);
1595 UpdateLock aLock (*this);
1596 while ( ! rList.empty())
1597 DeactivateSubShell(rViewShell, rList.front().mnId);
1604 namespace {
1606 ShellDescriptor::ShellDescriptor (void)
1607 : mpShell(NULL),
1608 mnId(0),
1609 mpFactory()
1616 ShellDescriptor::ShellDescriptor (
1617 SfxShell* pShell,
1618 ShellId nId)
1619 : mpShell(pShell),
1620 mnId(nId),
1621 mpFactory()
1628 ShellDescriptor::ShellDescriptor (const ShellDescriptor& rDescriptor)
1629 : mpShell(rDescriptor.mpShell),
1630 mnId(rDescriptor.mnId),
1631 mpFactory(rDescriptor.mpFactory)
1638 ShellDescriptor& ShellDescriptor::operator= (const ShellDescriptor& rDescriptor)
1640 mpShell = rDescriptor.mpShell;
1641 mnId = rDescriptor.mnId;
1642 mpFactory = rDescriptor.mpFactory;
1643 return *this;
1649 bool ShellDescriptor::IsMainViewShell (void) const
1651 ViewShell* pViewShell = dynamic_cast<ViewShell*>(mpShell);
1652 if (pViewShell != NULL)
1653 return pViewShell->IsMainViewShell();
1654 else
1655 return false;
1661 ::Window* ShellDescriptor::GetWindow (void) const
1663 ViewShell* pViewShell = dynamic_cast<ViewShell*>(mpShell);
1664 if (pViewShell != NULL)
1665 return pViewShell->GetActiveWindow();
1666 else
1667 return NULL;
1672 } // end of anonymous namespace
1674 } // end of namespace sd