1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ViewShellManager.cxx,v $
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"
38 #include "DrawDocShell.hxx"
39 #include "FormShellManager.hxx"
41 #include <sfx2/dispatch.hxx>
42 #include <svx/svxids.hrc>
43 #include <svx/fmshell.hxx>
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
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
66 class ShellDescriptor
{
70 ViewShellManager::SharedShellFactory mpFactory
;
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>
88 IsShell (const SfxShell
* pShell
) : mpShell(pShell
) {}
89 bool operator() (const ShellDescriptor
& rDescriptor
)
90 { return rDescriptor
.mpShell
== mpShell
; }
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>
104 IsId (ShellId nId
) : mnId(nId
) {}
105 bool operator() (const ShellDescriptor
& rDescriptor
)
106 { return rDescriptor
.mnId
== mnId
; }
111 } // end of anonymous namespace
116 class ViewShellManager::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 (
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
156 void TakeShellsFromStack (const SfxShell
* pShell
);
161 UpdateLock (Implementation
& rImpl
) : mrImpl(rImpl
) {mrImpl
.LockUpdate();}
162 ~UpdateLock (void) {mrImpl
.UnlockUpdate();};
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
181 void UnlockUpdate (void);
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
>
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
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
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
248 Afterwards the Deactivate() of the shell is called.
250 void Deactivate (SfxShell
* pShell
);
252 ShellDescriptor
CreateViewShell (
254 ::Window
* pParentWindow
,
255 FrameView
* pFrameView
);
256 ShellDescriptor
CreateSubShell (
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
)),
281 ViewShellManager::~ViewShellManager (void)
288 void ViewShellManager::AddSubShellFactory (
289 ViewShell
* pViewShell
,
290 const SharedShellFactory
& rpFactory
)
293 mpImpl
->AddShellFactory(pViewShell
, rpFactory
);
299 void ViewShellManager::RemoveSubShellFactory (
300 ViewShell
* pViewShell
,
301 const SharedShellFactory
& rpFactory
)
304 mpImpl
->RemoveShellFactory(pViewShell
, rpFactory
);
310 ViewShell
* ViewShellManager::ActivateViewShell (
312 ::Window
* pParentWindow
,
313 FrameView
* pFrameView
)
316 return mpImpl
->ActivateViewShell(nShellId
,pParentWindow
,pFrameView
);
324 void ViewShellManager::ActivateViewShell (ViewShell
* pViewShell
)
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
,
347 mpImpl
->MoveSubShellToTop(rParentShell
, nId
);
353 void ViewShellManager::SetFormShell (
354 const ViewShell
* pParentShell
,
355 FmFormShell
* pFormShell
,
359 mpImpl
->SetFormShell(pParentShell
,pFormShell
,bAbove
);
365 void ViewShellManager::ActivateSubShell (const ViewShell
& rViewShell
, ShellId nId
)
368 mpImpl
->ActivateSubShell(rViewShell
,nId
);
374 void ViewShellManager::DeactivateSubShell (const ViewShell
& rViewShell
, ShellId nId
)
377 mpImpl
->DeactivateSubShell(rViewShell
,nId
);
383 void ViewShellManager::DeactivateAllSubShells (const ViewShell
& rViewShell
)
386 mpImpl
->DeactivateAllSubShells(rViewShell
);
392 void ViewShellManager::InvalidateAllSubShells (ViewShell
* pViewShell
)
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
)
422 mpImpl
->TakeShellsFromStack(pShell
);
428 void ViewShellManager::MoveToTop (const ViewShell
& rParentShell
)
431 mpImpl
->MoveToTop(rParentShell
);
437 SfxShell
* ViewShellManager::GetShell (ShellId nId
) const
440 return mpImpl
->GetShell(nId
);
448 SfxShell
* ViewShellManager::GetTopShell (void) const
451 return mpImpl
->GetTopShell();
459 ShellId
ViewShellManager::GetShellId (const SfxShell
* pShell
) const
462 return mpImpl
->GetShellId(pShell
);
464 return snInvalidShellId
;
470 void ViewShellManager::ReplaceUndoManager (SfxUndoManager
* pManager
, SfxUndoManager
* pReplacement
)
473 mpImpl
->ReplaceUndoManager(pManager
,pReplacement
);
479 void ViewShellManager::Shutdown (void)
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
)
514 maActiveViewShells(),
515 mnUpdateLockCount(0),
516 mbKeepMainViewShellOnTop(false),
517 mbShellStackIsUpToDate(true),
519 mpFormShellParent(NULL
),
520 mbFormShellAboveParent(true),
529 ViewShellManager::Implementation::~Implementation (void)
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;
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
);
578 ViewShell
* ViewShellManager::Implementation::ActivateViewShell (
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();
609 pWindow
->AddEventListener(
610 LINK(this, ViewShellManager::Implementation
, WindowEventHandler
));
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(),
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())
690 maActiveViewShells
.insert(
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(),
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
,
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())
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())
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
));
771 void ViewShellManager::Implementation::DeactivateSubShell (
772 const SfxShell
& rParentShell
,
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())
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())
790 SfxShell
* pShell
= iShell
->mpShell
;
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.
800 TakeShellsFromStack(pShell
);
802 DestroySubShell(rParentShell
, aDescriptor
);
810 void ViewShellManager::Implementation::MoveSubShellToTop (
811 const SfxShell
& rParentShell
,
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
);
825 rList
.push_front(aEntry
);
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
)
850 ActiveShellList::iterator
iShell (::std::find_if (
851 maActiveViewShells
.begin(),
852 maActiveViewShells
.end(),
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.
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.
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
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.
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())
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 (
922 maActiveViewShells
.begin(),
923 maActiveViewShells
.end(),
925 if (iShell
!= maActiveViewShells
.end())
926 pShell
= iShell
->mpShell
;
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
;
950 SfxShell
* ViewShellManager::Implementation::GetTopShell (void) const
952 OSL_ASSERT(mpTopShell
== mrBase
.GetSubShell(0));
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
);
969 ActiveShellList::const_iterator
iShell (
971 maActiveViewShells
.begin(),
972 maActiveViewShells
.end(),
973 IsShell(pViewShell
)));
974 if (iShell
!= maActiveViewShells
.end())
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
;
1000 void ViewShellManager::Implementation::ReplaceUndoManager (
1001 SfxUndoManager
* pManager
,
1002 SfxUndoManager
* pReplacement
)
1004 for (USHORT i
=0; ;++i
)
1006 SfxShell
* pShell
= mrBase
.GetSubShell(i
);
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)
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()
1065 // 1. Create the missing shells.
1069 // 2. Create the internal target stack.
1070 ShellStack aTargetStack
;
1071 CreateTargetStack(aTargetStack
);
1074 // 3. Get SFX shell stack.
1075 ShellStack aSfxShellStack
;
1077 while (mrBase
.GetSubShell(nIndex
)!=NULL
)
1079 aSfxShellStack
.reserve(nIndex
);
1080 while (nIndex
-- > 0)
1081 aSfxShellStack
.push_back(mrBase
.GetSubShell(nIndex
));
1085 OSL_TRACE("Current SFX Stack\r");
1086 DumpShellStack(aSfxShellStack
);
1087 OSL_TRACE("Target Stack\r");
1088 DumpShellStack(aTargetStack
);
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
))
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();
1111 OSL_TRACE("removing shell %p from stack\r", pShell
);
1113 mrBase
.RemoveSubShell(pShell
);
1117 // 6. Push shells from the given stack onto the SFX stack.
1118 mbShellStackIsUpToDate
= false;
1119 while (iTargetShell
!= aTargetStack
.end())
1122 OSL_TRACE("pushing shell %p on stack\r", *iTargetShell
);
1124 mrBase
.AddSubShell(**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
)
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;
1147 OSL_TRACE("New current stack\r");
1148 DumpSfxShellStack();
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()
1166 OSL_TRACE("TakeShellsFromStack(%p)\r", pShell
);
1167 DumpSfxShellStack();
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.
1182 else if (pShellOnStack
== pShell
)
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
)
1198 // 2. Remove the shells from the stack.
1201 SfxShell
* pShellOnStack
= mrBase
.GetSubShell(0);
1203 OSL_TRACE("removing shell %p from stack\r", pShellOnStack
);
1205 mrBase
.RemoveSubShell(pShellOnStack
);
1206 if (pShellOnStack
== pShell
)
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
);
1222 OSL_TRACE("Sfx shell stack is:\r");
1223 DumpSfxShellStack();
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();
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
)
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();
1320 if (pEventWindow
== static_cast< ::Window
*>(aI
->GetWindow()))
1322 MoveToTop(*aI
->mpShell
);
1329 case VCLEVENT_WINDOW_LOSEFOCUS
:
1339 ShellDescriptor
ViewShellManager::Implementation::CreateViewShell (
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
));
1365 "ViewShellManager::ActivateViewShell: "
1366 "new view shell has no active window");
1377 ShellDescriptor
ViewShellManager::Implementation::CreateSubShell (
1378 SfxShell
* pParentShell
,
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
;
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
)
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
;
1483 ViewShell
* pViewShell
= dynamic_cast<ViewShell
*>(pShell
);
1484 if (pViewShell
!= NULL
)
1485 DeactivateViewShell(*pViewShell
);
1487 DeactivateShell(*pShell
);
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",
1521 ::rtl::OUStringToOString((*iEntry
)->GetName(),RTL_TEXTENCODING_UTF8
).getStr());
1523 OSL_TRACE(" null\r");
1529 void ViewShellManager::Implementation::DumpSfxShellStack (void)
1531 ShellStack aSfxShellStack
;
1533 while (mrBase
.GetSubShell(nIndex
)!=NULL
)
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
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();
1558 pViewShell
->GetViewFrame()->GetDispatcher()->Execute(
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
);
1606 ShellDescriptor::ShellDescriptor (void)
1616 ShellDescriptor::ShellDescriptor (
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
;
1649 bool ShellDescriptor::IsMainViewShell (void) const
1651 ViewShell
* pViewShell
= dynamic_cast<ViewShell
*>(mpShell
);
1652 if (pViewShell
!= NULL
)
1653 return pViewShell
->IsMainViewShell();
1661 ::Window
* ShellDescriptor::GetWindow (void) const
1663 ViewShell
* pViewShell
= dynamic_cast<ViewShell
*>(mpShell
);
1664 if (pViewShell
!= NULL
)
1665 return pViewShell
->GetActiveWindow();
1672 } // end of anonymous namespace
1674 } // end of namespace sd