1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "ViewShellManager.hxx"
21 #include "ViewShell.hxx"
22 #include "ViewShellBase.hxx"
24 #include "DrawDocShell.hxx"
25 #include "FormShellManager.hxx"
27 #include <sfx2/dispatch.hxx>
28 #include <svx/svxids.hrc>
29 #include <svx/fmshell.hxx>
32 #include <unordered_map>
38 /** The ShellDescriptor class is used to shells together with their ids and
39 the factory that was used to create the shell.
41 The shell pointer may be NULL. In that case the shell is created on
44 The factory pointer may be NULL. In that case the shell pointer is
45 given to the ViewShellManager.
47 Shell pointer and factory pointer can but should not be NULL at the same
50 class ShellDescriptor
{
54 ViewShellManager::SharedShellFactory mpFactory
;
55 bool mbIsListenerAddedToWindow
;
58 ShellDescriptor (SfxShell
* pShell
, ShellId nId
);
59 ShellDescriptor (const ShellDescriptor
& rDescriptor
);
60 ShellDescriptor
& operator= (const ShellDescriptor
& rDescriptor
);
61 bool IsMainViewShell() const;
62 vcl::Window
* GetWindow() const;
65 /** This functor can be used to search for a shell in an STL container when the
66 shell pointer is given.
68 class IsShell
: public ::std::unary_function
<ShellDescriptor
,bool>
71 IsShell (const SfxShell
* pShell
) : mpShell(pShell
) {}
72 bool operator() (const ShellDescriptor
& rDescriptor
)
73 { return rDescriptor
.mpShell
== mpShell
; }
75 const SfxShell
* mpShell
;
78 /** This functor can be used to search for a shell in an STL container when the
79 id of the shell is given.
81 class IsId
: public ::std::unary_function
<ShellDescriptor
,bool>
84 IsId (ShellId nId
) : mnId(nId
) {}
85 bool operator() (const ShellDescriptor
& rDescriptor
)
86 { return rDescriptor
.mnId
== mnId
; }
91 } // end of anonymous namespace
93 class ViewShellManager::Implementation
97 ViewShellManager
& rManager
,
98 ViewShellBase
& rBase
);
101 void AddShellFactory (
102 const SfxShell
* pViewShell
,
103 const SharedShellFactory
& rpFactory
);
104 void RemoveShellFactory (
105 const SfxShell
* pViewShell
,
106 const SharedShellFactory
& rpFactory
);
107 void ActivateViewShell (
108 ViewShell
* pViewShell
);
109 void DeactivateViewShell (const ViewShell
& rShell
);
110 void ActivateShell (SfxShell
& rShell
);
111 void DeactivateShell (const SfxShell
& rShell
);
112 void ActivateShell (const ShellDescriptor
& rDescriptor
);
113 void SetFormShell (const ViewShell
* pViewShell
, FmFormShell
* pFormShell
, bool bAbove
);
114 void ActivateSubShell (const SfxShell
& rParentShell
, ShellId nId
);
115 void DeactivateSubShell (const SfxShell
& rParentShell
, ShellId nId
);
116 void MoveToTop (const SfxShell
& rParentShell
);
117 SfxShell
* GetShell (ShellId nId
) const;
118 SfxShell
* GetTopShell() const;
119 SfxShell
* GetTopViewShell() const;
121 void InvalidateAllSubShells (const SfxShell
* pParentShell
);
123 /** Remove all shells from the SFX stack above and including the given
126 void TakeShellsFromStack (const SfxShell
* pShell
);
131 UpdateLock (Implementation
& rImpl
) : mrImpl(rImpl
) {mrImpl
.LockUpdate();}
132 ~UpdateLock() {mrImpl
.UnlockUpdate();};
134 Implementation
& mrImpl
;
137 /** Prevent updates of the shell stack. While the sub shell manager is
138 locked it will update its internal data structures but not alter the
139 shell stack. Use this method when there are several modifications
140 to the shell stack to prevent multiple rebuilds of the shell stack
141 and resulting broadcasts.
145 /** Allow updates of the shell stack. This method has to be called the
146 same number of times as LockUpdate() to really allow a rebuild of
152 ViewShellBase
& mrBase
;
153 mutable ::osl::Mutex maMutex
;
155 class ShellHash
{ public: size_t operator()(const SfxShell
* p
) const { return reinterpret_cast<size_t>(p
);} };
156 typedef std::unordered_multimap
<const SfxShell
*,SharedShellFactory
,ShellHash
>
158 FactoryList maShellFactories
;
160 /** List of the active view shells. In order to create gather all shells
161 to put on the shell stack each view shell in this list is asked for
162 its sub-shells (typically toolbars).
164 typedef std::list
<ShellDescriptor
> ActiveShellList
;
165 ActiveShellList maActiveViewShells
;
167 typedef std::list
<ShellDescriptor
> SubShellSubList
;
168 typedef std::unordered_map
<const SfxShell
*,SubShellSubList
,ShellHash
> SubShellList
;
169 SubShellList maActiveSubShells
;
171 /** In this member we remember what shells we have pushed on the shell
174 typedef ::std::vector
<SfxShell
*> ShellStack
;
176 int mnUpdateLockCount
;
178 /** When this flag is set then the main view shell is always kept at the
179 top of the shell stack.
181 bool mbKeepMainViewShellOnTop
;
183 /** The UpdateShellStack() method can be called recursively. This flag
184 is used to communicate between different levels of invocation: if
185 the stack has been updated in an inner call the outer call can (has
186 to) stop and return immediately.
188 bool mbShellStackIsUpToDate
;
190 SfxShell
* mpFormShell
;
191 const ViewShell
* mpFormShellParent
;
192 bool mbFormShellAboveParent
;
194 SfxShell
* mpTopShell
;
195 SfxShell
* mpTopViewShell
;
198 void UpdateShellStack();
202 /** This method rebuilds the stack of shells that are stacked upon the
205 void CreateTargetStack (ShellStack
& rStack
) const;
207 DECL_LINK(WindowEventHandler
, VclWindowEvent
*);
209 #if OSL_DEBUG_LEVEL >= 2
210 void DumpShellStack (const ShellStack
& rStack
);
211 void DumpSfxShellStack();
214 /** To be called before a shell is taken fom the SFX shell stack. This
215 method deactivates an active text editing to avoid problems with
217 Afterwards the Deactivate() of the shell is called.
219 static void Deactivate (SfxShell
* pShell
);
221 ShellDescriptor
CreateSubShell (
224 vcl::Window
* pParentWindow
,
225 FrameView
* pFrameView
);
226 void DestroyViewShell (ShellDescriptor
& rDescriptor
);
227 static void DestroySubShell (
228 const SfxShell
& rViewShell
,
229 const ShellDescriptor
& rDescriptor
);
232 //===== ViewShellManager ======================================================
234 ViewShellManager::ViewShellManager (ViewShellBase
& rBase
)
235 : mpImpl(new Implementation(*this,rBase
)),
240 ViewShellManager::~ViewShellManager()
244 void ViewShellManager::AddSubShellFactory (
245 ViewShell
* pViewShell
,
246 const SharedShellFactory
& rpFactory
)
249 mpImpl
->AddShellFactory(pViewShell
, rpFactory
);
252 void ViewShellManager::RemoveSubShellFactory (
253 ViewShell
* pViewShell
,
254 const SharedShellFactory
& rpFactory
)
257 mpImpl
->RemoveShellFactory(pViewShell
, rpFactory
);
260 void ViewShellManager::ActivateViewShell (ViewShell
* pViewShell
)
263 return mpImpl
->ActivateViewShell(pViewShell
);
266 void ViewShellManager::DeactivateViewShell (const ViewShell
* pShell
)
268 if (mbValid
&& pShell
!=NULL
)
269 mpImpl
->DeactivateViewShell(*pShell
);
272 void ViewShellManager::SetFormShell (
273 const ViewShell
* pParentShell
,
274 FmFormShell
* pFormShell
,
278 mpImpl
->SetFormShell(pParentShell
,pFormShell
,bAbove
);
281 void ViewShellManager::ActivateSubShell (const ViewShell
& rViewShell
, ShellId nId
)
284 mpImpl
->ActivateSubShell(rViewShell
,nId
);
287 void ViewShellManager::DeactivateSubShell (const ViewShell
& rViewShell
, ShellId nId
)
290 mpImpl
->DeactivateSubShell(rViewShell
,nId
);
293 void ViewShellManager::InvalidateAllSubShells (ViewShell
* pViewShell
)
296 mpImpl
->InvalidateAllSubShells(pViewShell
);
299 void ViewShellManager::ActivateShell (SfxShell
* pShell
)
301 if (mbValid
&& pShell
!=NULL
)
302 mpImpl
->ActivateShell(*pShell
);
305 void ViewShellManager::DeactivateShell (const SfxShell
* pShell
)
307 if (mbValid
&& pShell
!=NULL
)
308 mpImpl
->DeactivateShell(*pShell
);
311 void ViewShellManager::MoveToTop (const ViewShell
& rParentShell
)
314 mpImpl
->MoveToTop(rParentShell
);
317 SfxShell
* ViewShellManager::GetShell (ShellId nId
) const
320 return mpImpl
->GetShell(nId
);
325 SfxShell
* ViewShellManager::GetTopShell() const
328 return mpImpl
->GetTopShell();
333 SfxShell
* ViewShellManager::GetTopViewShell() const
336 return mpImpl
->GetTopViewShell();
341 void ViewShellManager::Shutdown()
350 void ViewShellManager::LockUpdate()
352 mpImpl
->LockUpdate();
355 void ViewShellManager::UnlockUpdate()
357 mpImpl
->UnlockUpdate();
360 //===== ViewShellManager::Implementation ======================================
362 ViewShellManager::Implementation::Implementation (
363 ViewShellManager
& rManager
,
364 ViewShellBase
& rBase
)
368 maActiveViewShells(),
369 mnUpdateLockCount(0),
370 mbKeepMainViewShellOnTop(false),
371 mbShellStackIsUpToDate(true),
373 mpFormShellParent(NULL
),
374 mbFormShellAboveParent(true),
381 ViewShellManager::Implementation::~Implementation()
386 void ViewShellManager::Implementation::AddShellFactory (
387 const SfxShell
* pViewShell
,
388 const SharedShellFactory
& rpFactory
)
390 bool bAlreadyAdded (false);
392 // Check that the given factory has not already been added.
393 ::std::pair
<FactoryList::iterator
,FactoryList::iterator
> aRange(
394 maShellFactories
.equal_range(pViewShell
));
395 for (FactoryList::const_iterator iFactory
=aRange
.first
; iFactory
!=aRange
.second
; ++iFactory
)
396 if (iFactory
->second
== rpFactory
)
398 bAlreadyAdded
= true;
402 // Add the factory if it is not already present.
403 if ( ! bAlreadyAdded
)
404 maShellFactories
.insert(FactoryList::value_type(pViewShell
, rpFactory
));
407 void ViewShellManager::Implementation::RemoveShellFactory (
408 const SfxShell
* pViewShell
,
409 const SharedShellFactory
& rpFactory
)
411 ::std::pair
<FactoryList::iterator
,FactoryList::iterator
> aRange(
412 maShellFactories
.equal_range(pViewShell
));
413 for (FactoryList::iterator iFactory
=aRange
.first
; iFactory
!=aRange
.second
; ++iFactory
)
414 if (iFactory
->second
== rpFactory
)
416 maShellFactories
.erase(iFactory
);
421 void ViewShellManager::Implementation::ActivateViewShell (ViewShell
* pViewShell
)
423 ::osl::MutexGuard
aGuard (maMutex
);
425 ShellDescriptor aResult
;
426 aResult
.mpShell
= pViewShell
;
428 // Register as window listener so that the shells of the current
429 // window can be moved to the top of the shell stack.
430 if (aResult
.mpShell
!= NULL
)
432 vcl::Window
* pWindow
= aResult
.GetWindow();
435 pWindow
->AddEventListener(
436 LINK(this, ViewShellManager::Implementation
, WindowEventHandler
));
437 aResult
.mbIsListenerAddedToWindow
= true;
442 "ViewShellManager::ActivateViewShell: "
443 "new view shell has no active window");
447 ActivateShell(aResult
);
450 void ViewShellManager::Implementation::DeactivateViewShell (const ViewShell
& rShell
)
452 ::osl::MutexGuard
aGuard (maMutex
);
454 ActiveShellList::iterator
iShell (::std::find_if (
455 maActiveViewShells
.begin(),
456 maActiveViewShells
.end(),
458 if (iShell
!= maActiveViewShells
.end())
460 UpdateLock
aLocker (*this);
462 ShellDescriptor
aDescriptor(*iShell
);
463 mrBase
.GetDocShell()->Disconnect(dynamic_cast<ViewShell
*>(aDescriptor
.mpShell
));
464 maActiveViewShells
.erase(iShell
);
465 TakeShellsFromStack(aDescriptor
.mpShell
);
467 // Deactivate sub shells.
468 SubShellList::iterator
iList (maActiveSubShells
.find(&rShell
));
469 if (iList
!= maActiveSubShells
.end())
471 SubShellSubList
& rList (iList
->second
);
472 while ( ! rList
.empty())
473 DeactivateSubShell(rShell
, rList
.front().mnId
);
476 DestroyViewShell(aDescriptor
);
480 void ViewShellManager::Implementation::ActivateShell (SfxShell
& rShell
)
482 ::osl::MutexGuard
aGuard (maMutex
);
484 // Create a new shell or recycle on in the cache.
485 ShellDescriptor aDescriptor
;
486 aDescriptor
.mpShell
= &rShell
;
488 ActivateShell(aDescriptor
);
491 void ViewShellManager::Implementation::ActivateShell (const ShellDescriptor
& rDescriptor
)
493 // Put shell on top of the active view shells.
494 if (rDescriptor
.mpShell
!= NULL
)
496 // Determine where to put the view shell on the stack. By default
497 // it is put on top of the stack. When the view shell of the center
498 // pane is to be kept top most and the new view shell is not
499 // displayed in the center pane then it is inserted at the position
500 // one below the top.
501 ActiveShellList::iterator
iInsertPosition (maActiveViewShells
.begin());
502 if (iInsertPosition
!= maActiveViewShells
.end()
503 && mbKeepMainViewShellOnTop
504 && ! rDescriptor
.IsMainViewShell()
505 && iInsertPosition
->IsMainViewShell())
509 maActiveViewShells
.insert(
515 void ViewShellManager::Implementation::DeactivateShell (const SfxShell
& rShell
)
517 ::osl::MutexGuard
aGuard (maMutex
);
519 ActiveShellList::iterator
iShell (::std::find_if (
520 maActiveViewShells
.begin(),
521 maActiveViewShells
.end(),
523 if (iShell
!= maActiveViewShells
.end())
525 UpdateLock
aLocker (*this);
527 ShellDescriptor
aDescriptor(*iShell
);
528 mrBase
.GetDocShell()->Disconnect(dynamic_cast<ViewShell
*>(aDescriptor
.mpShell
));
529 maActiveViewShells
.erase(iShell
);
530 TakeShellsFromStack(aDescriptor
.mpShell
);
532 // Deactivate sub shells.
533 SubShellList::iterator
iList (maActiveSubShells
.find(&rShell
));
534 if (iList
!= maActiveSubShells
.end())
536 SubShellSubList
& rList (iList
->second
);
537 while ( ! rList
.empty())
538 DeactivateSubShell(rShell
, rList
.front().mnId
);
541 DestroyViewShell(aDescriptor
);
545 void ViewShellManager::Implementation::ActivateSubShell (
546 const SfxShell
& rParentShell
,
549 ::osl::MutexGuard
aGuard (maMutex
);
551 // Check that the given view shell is active.
552 ActiveShellList::iterator
iShell (::std::find_if (
553 maActiveViewShells
.begin(),
554 maActiveViewShells
.end(),
555 IsShell(&rParentShell
)));
556 if (iShell
== maActiveViewShells
.end())
559 // Create the sub shell list if it does not yet exist.
560 SubShellList::iterator
iList (maActiveSubShells
.find(&rParentShell
));
561 if (iList
== maActiveSubShells
.end())
562 iList
= maActiveSubShells
.insert(
563 SubShellList::value_type(&rParentShell
,SubShellSubList())).first
;
565 // Do not activate an object bar that is already active. Requesting
566 // this is not exactly an error but may be an indication of one.
567 SubShellSubList
& rList (iList
->second
);
568 if (::std::find_if(rList
.begin(),rList
.end(), IsId(nId
)) != rList
.end())
571 // Add just the id of the sub shell. The actual shell is created
572 // later in CreateShells().
573 UpdateLock
aLock (*this);
574 rList
.push_back(ShellDescriptor(NULL
, nId
));
577 void ViewShellManager::Implementation::DeactivateSubShell (
578 const SfxShell
& rParentShell
,
581 ::osl::MutexGuard
aGuard (maMutex
);
583 // Check that the given view shell is active.
584 SubShellList::iterator
iList (maActiveSubShells
.find(&rParentShell
));
585 if (iList
== maActiveSubShells
.end())
588 // Look up the sub shell.
589 SubShellSubList
& rList (iList
->second
);
590 SubShellSubList::iterator
iShell (
591 ::std::find_if(rList
.begin(),rList
.end(), IsId(nId
)));
592 if (iShell
== rList
.end())
594 SfxShell
* pShell
= iShell
->mpShell
;
598 UpdateLock
aLock (*this);
600 ShellDescriptor
aDescriptor(*iShell
);
601 // Remove the sub shell from both the internal structure as well as the
602 // SFX shell stack above and including the sub shell.
604 TakeShellsFromStack(pShell
);
606 DestroySubShell(rParentShell
, aDescriptor
);
609 void ViewShellManager::Implementation::MoveToTop (const SfxShell
& rShell
)
611 ::osl::MutexGuard
aGuard (maMutex
);
613 // Check that we have access to a dispatcher. If not, then we are
614 // (probably) called while the view shell is still being created or
615 // initialized. Without dispatcher we can not rebuild the shell stack
616 // to move the requested shell to the top. So return right away instead
617 // of making a mess without being able to clean up afterwards.
618 if (mrBase
.GetDispatcher() == NULL
)
621 ActiveShellList::iterator
iShell (::std::find_if (
622 maActiveViewShells
.begin(),
623 maActiveViewShells
.end(),
626 if (iShell
!= maActiveViewShells
.end())
628 // Is the shell already at the top of the stack? We have to keep
629 // the case in mind that mbKeepMainViewShellOnTop is true. Shells
630 // that are not the main view shell are placed on the second-to-top
631 // position in this case.
632 if (iShell
== maActiveViewShells
.begin()
633 && (iShell
->IsMainViewShell() || ! mbKeepMainViewShellOnTop
))
635 // The shell is at the top position and is either a) the main
636 // view shell or b) another shell but the main view shell is not
637 // kept at the top position. We do not have to move the shell.
640 else if (iShell
== ++maActiveViewShells
.begin()
641 && ! iShell
->IsMainViewShell()
642 && mbKeepMainViewShellOnTop
)
644 // The shell is a the second-to-top position, not the main view
645 // shell and the main view shell is kept at the top position.
646 // Therefore we do not have to move the shell.
652 // The shell is not on the stack. Therefore it can not be moved.
653 // We could insert it but we don't. Use ActivateViewShell() for
658 // When the shell is not at the right position it is removed from the
659 // internal list of shells and inserted at the correct position.
662 UpdateLock
aLock (*this);
664 ShellDescriptor
aDescriptor(*iShell
);
666 TakeShellsFromStack(&rShell
);
667 maActiveViewShells
.erase(iShell
);
669 // Find out whether to insert at the top or one below.
670 ActiveShellList::iterator
aInsertPosition (maActiveViewShells
.begin());
671 if (mbKeepMainViewShellOnTop
&& ! aDescriptor
.IsMainViewShell())
673 if (maActiveViewShells
.back().IsMainViewShell())
677 maActiveViewShells
.insert(aInsertPosition
, aDescriptor
);
681 SfxShell
* ViewShellManager::Implementation::GetShell (ShellId nId
) const
683 ::osl::MutexGuard
aGuard (maMutex
);
685 SfxShell
* pShell
= NULL
;
687 // First search the active view shells.
688 ActiveShellList::const_iterator
iShell (
690 maActiveViewShells
.begin(),
691 maActiveViewShells
.end(),
693 if (iShell
!= maActiveViewShells
.end())
694 pShell
= iShell
->mpShell
;
697 // Now search the active sub shells of every active view shell.
698 SubShellList::const_iterator iList
;
699 for (iList
=maActiveSubShells
.begin(); iList
!=maActiveSubShells
.end(); ++iList
)
701 const SubShellSubList
& rList (iList
->second
);
702 SubShellSubList::const_iterator
iSubShell(
703 ::std::find_if(rList
.begin(),rList
.end(), IsId(nId
)));
704 if (iSubShell
!= rList
.end())
706 pShell
= iSubShell
->mpShell
;
715 SfxShell
* ViewShellManager::Implementation::GetTopShell() const
717 OSL_ASSERT(mpTopShell
== mrBase
.GetSubShell(0));
721 SfxShell
* ViewShellManager::Implementation::GetTopViewShell() const
723 return mpTopViewShell
;
726 void ViewShellManager::Implementation::LockUpdate()
731 void ViewShellManager::Implementation::UnlockUpdate()
733 ::osl::MutexGuard
aGuard (maMutex
);
736 if (mnUpdateLockCount
< 0)
738 // This should not happen.
739 OSL_ASSERT (mnUpdateLockCount
>=0);
740 mnUpdateLockCount
= 0;
742 if (mnUpdateLockCount
== 0)
746 /** Update the SFX shell stack (the portion that is visible to us) so that
747 it matches the internal shell stack. This is done in six steps:
748 1. Create the missing view shells and sub shells.
749 2. Set up the internal shell stack.
750 3. Get the SFX shell stack.
751 4. Find the lowest shell in which the two stacks differ.
752 5. Remove all shells above and including that shell from the SFX stack.
753 6. Push all shells of the internal stack on the SFX shell stack that are
754 not already present on the later.
756 void ViewShellManager::Implementation::UpdateShellStack()
758 ::osl::MutexGuard
aGuard (maMutex
);
760 // Remember the undo manager from the top-most shell on the stack.
761 SfxShell
* pTopMostShell
= mrBase
.GetSubShell(0);
762 ::svl::IUndoManager
* pUndoManager
= (pTopMostShell
!=NULL
)
763 ? pTopMostShell
->GetUndoManager()
766 // 1. Create the missing shells.
769 // Update the pointer to the top-most active view shell.
770 mpTopViewShell
= (maActiveViewShells
.empty())
771 ? 0 : maActiveViewShells
.begin()->mpShell
;
774 // 2. Create the internal target stack.
775 ShellStack aTargetStack
;
776 CreateTargetStack(aTargetStack
);
778 // 3. Get SFX shell stack.
779 ShellStack aSfxShellStack
;
780 sal_uInt16
nIndex (0);
781 while (mrBase
.GetSubShell(nIndex
)!=NULL
)
783 aSfxShellStack
.reserve(nIndex
);
785 aSfxShellStack
.push_back(mrBase
.GetSubShell(nIndex
));
787 #if OSL_DEBUG_LEVEL >= 2
788 SAL_INFO("sd.view", OSL_THIS_FUNC
<< ": Current SFX Stack");
789 DumpShellStack(aSfxShellStack
);
790 SAL_INFO("sd.view", OSL_THIS_FUNC
<< ": Target Stack");
791 DumpShellStack(aTargetStack
);
794 // 4. Find the lowest shell in which the two stacks differ.
795 ShellStack::iterator
iSfxShell (aSfxShellStack
.begin());
796 ShellStack::iterator
iTargetShell (aTargetStack
.begin());
797 while (iSfxShell
!= aSfxShellStack
.end()
798 && iTargetShell
!=aTargetStack
.end()
799 && (*iSfxShell
)==(*iTargetShell
))
805 // 5. Remove all shells above and including the differing shell from the
806 // SFX stack starting with the shell on top of the stack.
807 for (std::reverse_iterator
<ShellStack::const_iterator
> i(aSfxShellStack
.end()), iLast(iSfxShell
);
810 SfxShell
* const pShell
= *i
;
811 SAL_INFO("sd.view", OSL_THIS_FUNC
<< ": removing shell " << pShell
<< " from stack");
812 mrBase
.RemoveSubShell(pShell
);
814 aSfxShellStack
.erase(iSfxShell
, aSfxShellStack
.end());
816 // 6. Push shells from the given stack onto the SFX stack.
817 mbShellStackIsUpToDate
= false;
818 while (iTargetShell
!= aTargetStack
.end())
820 SAL_INFO("sd.view", OSL_THIS_FUNC
<< ": pushing shell " << *iTargetShell
<< " on stack");
821 mrBase
.AddSubShell(**iTargetShell
);
824 // The pushing of the shell on to the shell stack may have lead to
825 // another invocation of this method. In this case we have to abort
826 // pushing shells on the stack and return immediately.
827 if (mbShellStackIsUpToDate
)
830 if (mrBase
.GetDispatcher() != NULL
)
831 mrBase
.GetDispatcher()->Flush();
833 // Update the pointer to the top-most shell and set its undo manager
834 // to the one of the previous top-most shell.
835 mpTopShell
= mrBase
.GetSubShell(0);
836 if (mpTopShell
!=NULL
&& pUndoManager
!=NULL
&& mpTopShell
->GetUndoManager()==NULL
)
837 mpTopShell
->SetUndoManager(pUndoManager
);
839 // Finally tell an invocation of this method on a higher level that it can (has
840 // to) abort and return immediately.
841 mbShellStackIsUpToDate
= true;
843 #if OSL_DEBUG_LEVEL >= 2
844 SAL_INFO("sd.view", OSL_THIS_FUNC
<< ": New current stack");
849 void ViewShellManager::Implementation::TakeShellsFromStack (const SfxShell
* pShell
)
851 ::osl::MutexGuard
aGuard (maMutex
);
853 // Remember the undo manager from the top-most shell on the stack.
854 SfxShell
* pTopMostShell
= mrBase
.GetSubShell(0);
855 ::svl::IUndoManager
* pUndoManager
= (pTopMostShell
!=NULL
)
856 ? pTopMostShell
->GetUndoManager()
859 #if OSL_DEBUG_LEVEL >= 2
860 SAL_INFO("sd.view", OSL_THIS_FUNC
<< "TakeShellsFromStack( " << pShell
<< ")");
864 // 0.Make sure that the given shell is on the stack. This is a
865 // preparation for the following assertion.
866 for (sal_uInt16 nIndex
=0; true; nIndex
++)
868 SfxShell
* pShellOnStack
= mrBase
.GetSubShell(nIndex
);
869 if (pShellOnStack
== NULL
)
871 // Set pShell to NULL to indicate the following code that the
872 // shell is not on the stack.
876 else if (pShellOnStack
== pShell
)
882 // 1. Deactivate our shells on the stack before they are removed so
883 // that during the Deactivation() calls the stack is still intact.
884 for (sal_uInt16 nIndex
=0; true; nIndex
++)
886 SfxShell
* pShellOnStack
= mrBase
.GetSubShell(nIndex
);
887 Deactivate(pShellOnStack
);
888 if (pShellOnStack
== pShell
)
892 // 2. Remove the shells from the stack.
895 SfxShell
* pShellOnStack
= mrBase
.GetSubShell(0);
896 SAL_INFO("sd.view", OSL_THIS_FUNC
<< "removing shell " << pShellOnStack
<< " from stack");
897 mrBase
.RemoveSubShell(pShellOnStack
);
898 if (pShellOnStack
== pShell
)
902 // 3. Update the stack.
903 if (mrBase
.GetDispatcher() != NULL
)
904 mrBase
.GetDispatcher()->Flush();
906 // Update the pointer to the top-most shell and set its undo manager
907 // to the one of the previous top-most shell.
908 mpTopShell
= mrBase
.GetSubShell(0);
909 if (mpTopShell
!=NULL
&& pUndoManager
!=NULL
&& mpTopShell
->GetUndoManager()==NULL
)
910 mpTopShell
->SetUndoManager(pUndoManager
);
913 #if OSL_DEBUG_LEVEL >= 2
914 SAL_INFO("sd.view", OSL_THIS_FUNC
<< "Sfx shell stack is:");
919 void ViewShellManager::Implementation::CreateShells()
921 ::osl::MutexGuard
aGuard (maMutex
);
923 // Iterate over all view shells.
924 ActiveShellList::reverse_iterator iShell
;
925 for (iShell
=maActiveViewShells
.rbegin(); iShell
!=maActiveViewShells
.rend(); ++iShell
)
927 // Get the list of associated sub shells.
928 SubShellList::iterator
iList (maActiveSubShells
.find(iShell
->mpShell
));
929 if (iList
!= maActiveSubShells
.end())
931 SubShellSubList
& rList (iList
->second
);
933 // Iterate over all sub shells of the current view shell.
934 SubShellSubList::iterator iSubShell
;
935 for (iSubShell
=rList
.begin(); iSubShell
!=rList
.end(); ++iSubShell
)
937 if (iSubShell
->mpShell
== NULL
)
939 *iSubShell
= CreateSubShell(iShell
->mpShell
,iSubShell
->mnId
,NULL
,NULL
);
946 void ViewShellManager::Implementation::CreateTargetStack (ShellStack
& rStack
) const
948 // Create a local stack of the shells that are to push on the shell
949 // stack. We can thus safly create the required shells wile still
950 // having a valid shell stack.
951 for (ActiveShellList::const_reverse_iterator
iViewShell (maActiveViewShells
.rbegin());
952 iViewShell
!= maActiveViewShells
.rend();
955 // Possibly place the form shell below the current view shell.
956 if ( ! mbFormShellAboveParent
958 && iViewShell
->mpShell
==mpFormShellParent
)
960 rStack
.push_back(mpFormShell
);
963 // Put the view shell itself on the local stack.
964 rStack
.push_back (iViewShell
->mpShell
);
966 // Possibly place the form shell above the current view shell.
967 if (mbFormShellAboveParent
969 && iViewShell
->mpShell
==mpFormShellParent
)
971 rStack
.push_back(mpFormShell
);
974 // Add all other sub shells.
975 SubShellList::const_iterator
iList (maActiveSubShells
.find(iViewShell
->mpShell
));
976 if (iList
!= maActiveSubShells
.end())
978 const SubShellSubList
& rList (iList
->second
);
979 SubShellSubList::const_reverse_iterator iSubShell
;
980 for (iSubShell
=rList
.rbegin(); iSubShell
!=rList
.rend(); ++iSubShell
)
981 if (iSubShell
->mpShell
!= mpFormShell
)
982 rStack
.push_back(iSubShell
->mpShell
);
987 IMPL_LINK(ViewShellManager::Implementation
, WindowEventHandler
, VclWindowEvent
*, pEvent
)
991 vcl::Window
* pEventWindow
992 = static_cast<VclWindowEvent
*>(pEvent
)->GetWindow();
994 switch (pEvent
->GetId())
996 case VCLEVENT_WINDOW_GETFOCUS
:
998 for (ActiveShellList::iterator
aI(maActiveViewShells
.begin());
999 aI
!=maActiveViewShells
.end();
1002 if (pEventWindow
== static_cast< vcl::Window
*>(aI
->GetWindow()))
1004 MoveToTop(*aI
->mpShell
);
1011 case VCLEVENT_WINDOW_LOSEFOCUS
:
1014 case VCLEVENT_OBJECT_DYING
:
1015 // Remember that we do not have to remove the window
1016 // listener for this window.
1017 for (ActiveShellList::iterator
1018 iShell(maActiveViewShells
.begin()),
1019 iEnd(maActiveViewShells
.end());
1023 if (iShell
->GetWindow() == pEventWindow
)
1025 iShell
->mbIsListenerAddedToWindow
= false;
1032 return sal_IntPtr(true);
1035 ShellDescriptor
ViewShellManager::Implementation::CreateSubShell (
1036 SfxShell
* pParentShell
,
1038 vcl::Window
* pParentWindow
,
1039 FrameView
* pFrameView
)
1041 ::osl::MutexGuard
aGuard (maMutex
);
1042 ShellDescriptor aResult
;
1044 // Look up the factories for the parent shell.
1045 ::std::pair
<FactoryList::iterator
,FactoryList::iterator
> aRange(
1046 maShellFactories
.equal_range(pParentShell
));
1048 // Try all factories to create the shell.
1049 for (FactoryList::const_iterator iFactory
=aRange
.first
; iFactory
!=aRange
.second
; ++iFactory
)
1051 SharedShellFactory pFactory
= iFactory
->second
;
1053 aResult
.mpShell
= pFactory
->CreateShell(nShellId
, pParentWindow
, pFrameView
);
1055 // Exit the loop when the shell has been successfully created.
1056 if (aResult
.mpShell
!= NULL
)
1058 aResult
.mpFactory
= pFactory
;
1059 aResult
.mnId
= nShellId
;
1067 void ViewShellManager::Implementation::DestroyViewShell (
1068 ShellDescriptor
& rDescriptor
)
1070 OSL_ASSERT(rDescriptor
.mpShell
!= NULL
);
1072 if (rDescriptor
.mbIsListenerAddedToWindow
)
1074 rDescriptor
.mbIsListenerAddedToWindow
= false;
1075 vcl::Window
* pWindow
= rDescriptor
.GetWindow();
1076 if (pWindow
!= NULL
)
1078 pWindow
->RemoveEventListener(
1079 LINK(this, ViewShellManager::Implementation
, WindowEventHandler
));
1083 // Destroy the sub shell factories.
1084 ::std::pair
<FactoryList::iterator
,FactoryList::iterator
> aRange(
1085 maShellFactories
.equal_range(rDescriptor
.mpShell
));
1086 if (aRange
.first
!= maShellFactories
.end())
1087 maShellFactories
.erase(aRange
.first
, aRange
.second
);
1089 // Release the shell.
1090 if (rDescriptor
.mpFactory
.get() != NULL
)
1091 rDescriptor
.mpFactory
->ReleaseShell(rDescriptor
.mpShell
);
1094 void ViewShellManager::Implementation::DestroySubShell (
1095 const SfxShell
& rParentShell
,
1096 const ShellDescriptor
& rDescriptor
)
1099 OSL_ASSERT(rDescriptor
.mpFactory
.get() != NULL
);
1100 rDescriptor
.mpFactory
->ReleaseShell(rDescriptor
.mpShell
);
1103 void ViewShellManager::Implementation::InvalidateAllSubShells (const SfxShell
* pParentShell
)
1105 ::osl::MutexGuard
aGuard (maMutex
);
1107 SubShellList::iterator
iList (maActiveSubShells
.find(pParentShell
));
1108 if (iList
!= maActiveSubShells
.end())
1110 SubShellSubList
& rList (iList
->second
);
1111 SubShellSubList::iterator iShell
;
1112 for (iShell
=rList
.begin(); iShell
!=rList
.end(); ++iShell
)
1113 if (iShell
->mpShell
!= NULL
)
1114 iShell
->mpShell
->Invalidate();
1118 void ViewShellManager::Implementation::Shutdown()
1120 ::osl::MutexGuard
aGuard (maMutex
);
1122 // Take stacked shells from stack.
1123 if ( ! maActiveViewShells
.empty())
1125 UpdateLock
aLock (*this);
1127 while ( ! maActiveViewShells
.empty())
1129 SfxShell
* pShell
= maActiveViewShells
.front().mpShell
;
1132 ViewShell
* pViewShell
= dynamic_cast<ViewShell
*>(pShell
);
1133 if (pViewShell
!= NULL
)
1134 DeactivateViewShell(*pViewShell
);
1136 DeactivateShell(*pShell
);
1141 "ViewShellManager::Implementation::Shutdown(): empty active shell descriptor");
1142 maActiveViewShells
.pop_front();
1146 mrBase
.RemoveSubShell (NULL
);
1148 maShellFactories
.clear();
1151 #if OSL_DEBUG_LEVEL >= 2
1152 void ViewShellManager::Implementation::DumpShellStack (const ShellStack
& rStack
)
1154 ShellStack::const_reverse_iterator iEntry
;
1155 for (iEntry
=rStack
.rbegin(); iEntry
!=rStack
.rend(); ++iEntry
)
1156 if (*iEntry
!= NULL
)
1157 SAL_INFO("sd.view", OSL_THIS_FUNC
<< ": " <<
1159 OUStringToOString((*iEntry
)->GetName(),RTL_TEXTENCODING_UTF8
).getStr());
1161 SAL_INFO("sd.view", OSL_THIS_FUNC
<< " null");
1164 void ViewShellManager::Implementation::DumpSfxShellStack()
1166 ShellStack aSfxShellStack
;
1167 sal_uInt16
nIndex (0);
1168 while (mrBase
.GetSubShell(nIndex
)!=NULL
)
1170 aSfxShellStack
.reserve(nIndex
);
1171 while (nIndex
-- > 0)
1172 aSfxShellStack
.push_back(mrBase
.GetSubShell(nIndex
));
1173 DumpShellStack(aSfxShellStack
);
1177 void ViewShellManager::Implementation::Deactivate (SfxShell
* pShell
)
1179 OSL_ASSERT(pShell
!=NULL
);
1181 // We have to end a text edit for view shells that are to be taken from
1183 ViewShell
* pViewShell
= dynamic_cast<ViewShell
*>(pShell
);
1184 if (pViewShell
!= NULL
)
1186 sd::View
* pView
= pViewShell
->GetView();
1187 if (pView
!=NULL
&& pView
->IsTextEdit())
1189 pView
->SdrEndTextEdit();
1191 pViewShell
->GetViewFrame()->GetDispatcher()->Execute(
1193 SfxCallMode::ASYNCHRON
);
1197 // Now we can deactivate the shell.
1198 pShell
->Deactivate(true);
1201 void ViewShellManager::Implementation::SetFormShell (
1202 const ViewShell
* pFormShellParent
,
1203 FmFormShell
* pFormShell
,
1204 bool bFormShellAboveParent
)
1206 ::osl::MutexGuard
aGuard (maMutex
);
1208 mpFormShellParent
= pFormShellParent
;
1209 mpFormShell
= pFormShell
;
1210 mbFormShellAboveParent
= bFormShellAboveParent
;
1215 ShellDescriptor::ShellDescriptor()
1219 mbIsListenerAddedToWindow(false)
1223 ShellDescriptor::ShellDescriptor (
1229 mbIsListenerAddedToWindow(false)
1233 ShellDescriptor::ShellDescriptor (const ShellDescriptor
& rDescriptor
)
1234 : mpShell(rDescriptor
.mpShell
),
1235 mnId(rDescriptor
.mnId
),
1236 mpFactory(rDescriptor
.mpFactory
),
1237 mbIsListenerAddedToWindow(rDescriptor
.mbIsListenerAddedToWindow
)
1241 ShellDescriptor
& ShellDescriptor::operator= (const ShellDescriptor
& rDescriptor
)
1243 if (this != &rDescriptor
)
1245 mpShell
= rDescriptor
.mpShell
;
1246 mnId
= rDescriptor
.mnId
;
1247 mpFactory
= rDescriptor
.mpFactory
;
1248 mbIsListenerAddedToWindow
= rDescriptor
.mbIsListenerAddedToWindow
;
1253 bool ShellDescriptor::IsMainViewShell() const
1255 ViewShell
* pViewShell
= dynamic_cast<ViewShell
*>(mpShell
);
1256 if (pViewShell
!= NULL
)
1257 return pViewShell
->IsMainViewShell();
1262 vcl::Window
* ShellDescriptor::GetWindow() const
1264 ViewShell
* pViewShell
= dynamic_cast<ViewShell
*>(mpShell
);
1265 if (pViewShell
!= NULL
)
1266 return pViewShell
->GetActiveWindow();
1271 } // end of anonymous namespace
1273 } // end of namespace sd
1275 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */