/src/libreoffice/sd/source/ui/view/ViewShellManager.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <ViewShellManager.hxx> |
21 | | #include <ViewShell.hxx> |
22 | | #include <ViewShellBase.hxx> |
23 | | #include <Window.hxx> |
24 | | #include <DrawDocShell.hxx> |
25 | | |
26 | | #include <sal/log.hxx> |
27 | | #include <sfx2/dispatch.hxx> |
28 | | #include <sfx2/viewfrm.hxx> |
29 | | #include <svx/svxids.hrc> |
30 | | #include <svx/fmshell.hxx> |
31 | | #include <vcl/vclevent.hxx> |
32 | | #include <osl/diagnose.h> |
33 | | |
34 | | #include <iterator> |
35 | | #include <list> |
36 | | #include <unordered_map> |
37 | | |
38 | | namespace sd { |
39 | | |
40 | | namespace { |
41 | | |
42 | | /** The ShellDescriptor class is used to shells together with their ids and |
43 | | the factory that was used to create the shell. |
44 | | |
45 | | The shell pointer may be NULL. In that case the shell is created on |
46 | | demand by a factory. |
47 | | |
48 | | The factory pointer may be NULL. In that case the shell pointer is |
49 | | given to the ViewShellManager. |
50 | | |
51 | | Shell pointer and factory pointer can but should not be NULL at the same |
52 | | time. |
53 | | */ |
54 | | class ShellDescriptor { |
55 | | public: |
56 | | SfxShell* mpShell; |
57 | | ShellId mnId; |
58 | | ViewShellManager::SharedShellFactory mpFactory; |
59 | | bool mbIsListenerAddedToWindow; |
60 | | |
61 | | ShellDescriptor (); |
62 | | explicit ShellDescriptor (ShellId nId); |
63 | | vcl::Window* GetWindow() const; |
64 | | }; |
65 | | |
66 | | /** This functor can be used to search for a shell in an STL container when the |
67 | | shell pointer is given. |
68 | | */ |
69 | | class IsShell |
70 | | { |
71 | | public: |
72 | 0 | explicit IsShell (const SfxShell* pShell) : mpShell(pShell) {} |
73 | | bool operator() (const ShellDescriptor& rDescriptor) |
74 | 0 | { return rDescriptor.mpShell == mpShell; } |
75 | | private: |
76 | | const SfxShell* mpShell; |
77 | | }; |
78 | | |
79 | | /** This functor can be used to search for a shell in an STL container when the |
80 | | id of the shell is given. |
81 | | */ |
82 | | class IsId |
83 | | { |
84 | | public: |
85 | 0 | explicit IsId (ShellId nId) : mnId(nId) {} |
86 | | bool operator() (const ShellDescriptor& rDescriptor) |
87 | 0 | { return rDescriptor.mnId == mnId; } |
88 | | private: |
89 | | ShellId mnId; |
90 | | }; |
91 | | |
92 | | } // end of anonymous namespace |
93 | | |
94 | | class ViewShellManager::Implementation |
95 | | { |
96 | | public: |
97 | | Implementation ( |
98 | | ViewShellBase& rBase); |
99 | | ~Implementation() COVERITY_NOEXCEPT_FALSE; |
100 | | |
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 ActivateLowPriorityShell (SfxShell& rShell); |
111 | | void DeactivateShell (const SfxShell& rShell); |
112 | | void ActivateShell (const ShellDescriptor& rDescriptor); |
113 | | void ActivateLowPriorityShell (const ShellDescriptor& rDescriptor); |
114 | | void SetFormShell (const ViewShell* pViewShell, FmFormShell* pFormShell, bool bAbove); |
115 | | void ActivateSubShell (const SfxShell& rParentShell, ShellId nId); |
116 | | void DeactivateSubShell (const SfxShell& rParentShell, ShellId nId); |
117 | | void RemoveOverridingMainShell(); |
118 | | void SetOverridingShell(const std::shared_ptr<ViewShell>& pViewShell); |
119 | | std::shared_ptr<ViewShell> GetOverridingShell(); |
120 | | void MoveToTop (const SfxShell& rParentShell); |
121 | | SfxShell* GetShell (ShellId nId) const; |
122 | | SfxShell* GetTopShell() const; |
123 | | SfxShell* GetTopViewShell() const; |
124 | | void Shutdown(); |
125 | | void InvalidateAllSubShells (const SfxShell* pParentShell); |
126 | | |
127 | | /** Remove all shells from the SFX stack above and including the given |
128 | | shell. |
129 | | */ |
130 | | void TakeShellsFromStack (const SfxShell& rShell); |
131 | | |
132 | | class UpdateLock |
133 | | { |
134 | | public: |
135 | 0 | explicit UpdateLock (Implementation& rImpl) : mrImpl(rImpl) {mrImpl.LockUpdate();} |
136 | 0 | ~UpdateLock() COVERITY_NOEXCEPT_FALSE {mrImpl.UnlockUpdate();} |
137 | | private: |
138 | | Implementation& mrImpl; |
139 | | }; |
140 | | |
141 | | /** Prevent updates of the shell stack. While the sub shell manager is |
142 | | locked it will update its internal data structures but not alter the |
143 | | shell stack. Use this method when there are several modifications |
144 | | to the shell stack to prevent multiple rebuilds of the shell stack |
145 | | and resulting broadcasts. |
146 | | */ |
147 | | void LockUpdate(); |
148 | | |
149 | | /** Allow updates of the shell stack. This method has to be called the |
150 | | same number of times as LockUpdate() to really allow a rebuild of |
151 | | the shell stack. |
152 | | */ |
153 | | void UnlockUpdate(); |
154 | | |
155 | | private: |
156 | | ViewShellBase& mrBase; |
157 | | mutable ::osl::Mutex maMutex; |
158 | | |
159 | 0 | class ShellHash { public: size_t operator()(const SfxShell* p) const { return reinterpret_cast<size_t>(p);} }; |
160 | | typedef std::unordered_multimap<const SfxShell*,SharedShellFactory,ShellHash> |
161 | | FactoryList; |
162 | | FactoryList maShellFactories; |
163 | | |
164 | | /** List of the active view shells. In order to create gather all shells |
165 | | to put on the shell stack each view shell in this list is asked for |
166 | | its sub-shells (typically toolbars). |
167 | | */ |
168 | | typedef std::list<ShellDescriptor> ActiveShellList; |
169 | | ActiveShellList maActiveViewShells; |
170 | | |
171 | | typedef std::list<ShellDescriptor> SubShellSubList; |
172 | | typedef std::unordered_map<const SfxShell*,SubShellSubList,ShellHash> SubShellList; |
173 | | SubShellList maActiveSubShells; |
174 | | |
175 | | /** In this member we remember what shells we have pushed on the shell |
176 | | stack. |
177 | | */ |
178 | | typedef ::std::vector<SfxShell*> ShellStack; |
179 | | |
180 | | int mnUpdateLockCount; |
181 | | |
182 | | /** The UpdateShellStack() method can be called recursively. This flag |
183 | | is used to communicate between different levels of invocation: if |
184 | | the stack has been updated in an inner call the outer call can (has |
185 | | to) stop and return immediately. |
186 | | */ |
187 | | bool mbShellStackIsUpToDate; |
188 | | |
189 | | SfxShell* mpFormShell; |
190 | | const ViewShell* mpFormShellParent; |
191 | | bool mbFormShellAboveParent; |
192 | | |
193 | | SfxShell* mpTopShell; |
194 | | SfxShell* mpTopViewShell; |
195 | | |
196 | | std::weak_ptr<ViewShell> mpOverridingShell; |
197 | | |
198 | | void UpdateShellStack(); |
199 | | |
200 | | void CreateShells(); |
201 | | |
202 | | /** This method rebuilds the stack of shells that are stacked upon the |
203 | | view shell base. |
204 | | */ |
205 | | void CreateTargetStack (ShellStack& rStack) const; |
206 | | |
207 | | DECL_LINK(WindowEventHandler, VclWindowEvent&, void); |
208 | | |
209 | | #if OSL_DEBUG_LEVEL >= 2 |
210 | | void DumpShellStack (const ShellStack& rStack); |
211 | | void DumpSfxShellStack(); |
212 | | #endif |
213 | | |
214 | | /** To be called before a shell is taken from the SFX shell stack. This |
215 | | method deactivates an active text editing to avoid problems with |
216 | | undo managers. |
217 | | Afterwards the Deactivate() of the shell is called. |
218 | | */ |
219 | | static void Deactivate (SfxShell* pShell); |
220 | | |
221 | | ShellDescriptor CreateSubShell ( |
222 | | SfxShell const * pShell, |
223 | | ShellId nShellId); |
224 | | void DestroyViewShell (ShellDescriptor& rDescriptor); |
225 | | static void DestroySubShell (const ShellDescriptor& rDescriptor); |
226 | | }; |
227 | | |
228 | | //===== ViewShellManager ====================================================== |
229 | | |
230 | | ViewShellManager::ViewShellManager (ViewShellBase& rBase) |
231 | 0 | : mpImpl(new Implementation(rBase)), |
232 | 0 | mbValid(true) |
233 | 0 | { |
234 | 0 | } |
235 | | |
236 | | ViewShellManager::~ViewShellManager() |
237 | 0 | { |
238 | 0 | } |
239 | | |
240 | | void ViewShellManager::AddSubShellFactory ( |
241 | | ViewShell const * pViewShell, |
242 | | const SharedShellFactory& rpFactory) |
243 | 0 | { |
244 | 0 | if (mbValid) |
245 | 0 | mpImpl->AddShellFactory(pViewShell, rpFactory); |
246 | 0 | } |
247 | | |
248 | | void ViewShellManager::RemoveSubShellFactory ( |
249 | | ViewShell const * pViewShell, |
250 | | const SharedShellFactory& rpFactory) |
251 | 0 | { |
252 | 0 | if (mbValid) |
253 | 0 | mpImpl->RemoveShellFactory(pViewShell, rpFactory); |
254 | 0 | } |
255 | | |
256 | | void ViewShellManager::ActivateViewShell (ViewShell* pViewShell) |
257 | 0 | { |
258 | 0 | if (mbValid) |
259 | 0 | return mpImpl->ActivateViewShell(pViewShell); |
260 | 0 | } |
261 | | |
262 | | void ViewShellManager::DeactivateViewShell (const ViewShell* pShell) |
263 | 0 | { |
264 | 0 | if (mbValid && pShell!=nullptr) |
265 | 0 | mpImpl->DeactivateViewShell(*pShell); |
266 | 0 | } |
267 | | |
268 | | |
269 | | void ViewShellManager::RemoveOverridingMainShell() |
270 | 0 | { |
271 | 0 | if(mbValid) |
272 | 0 | mpImpl->RemoveOverridingMainShell(); |
273 | 0 | } |
274 | | |
275 | | void ViewShellManager::SetOverridingMainShell(const std::shared_ptr<ViewShell>& pViewShell) |
276 | 0 | { |
277 | 0 | if(mbValid) |
278 | 0 | mpImpl->SetOverridingShell(pViewShell); |
279 | 0 | } |
280 | | |
281 | | std::shared_ptr<ViewShell> ViewShellManager::GetOverridingMainShell() |
282 | 0 | { |
283 | 0 | if(mbValid) |
284 | 0 | return mpImpl->GetOverridingShell(); |
285 | 0 | return {}; |
286 | 0 | } |
287 | | |
288 | | void ViewShellManager::SetFormShell ( |
289 | | const ViewShell* pParentShell, |
290 | | FmFormShell* pFormShell, |
291 | | bool bAbove) |
292 | 0 | { |
293 | 0 | if (mbValid) |
294 | 0 | mpImpl->SetFormShell(pParentShell,pFormShell,bAbove); |
295 | 0 | } |
296 | | |
297 | | void ViewShellManager::ActivateSubShell (const ViewShell& rViewShell, ShellId nId) |
298 | 0 | { |
299 | 0 | if (mbValid) |
300 | 0 | mpImpl->ActivateSubShell(rViewShell,nId); |
301 | 0 | } |
302 | | |
303 | | void ViewShellManager::DeactivateSubShell (const ViewShell& rViewShell, ShellId nId) |
304 | 0 | { |
305 | 0 | if (mbValid) |
306 | 0 | mpImpl->DeactivateSubShell(rViewShell,nId); |
307 | 0 | } |
308 | | |
309 | | void ViewShellManager::InvalidateAllSubShells (ViewShell const * pViewShell) |
310 | 0 | { |
311 | 0 | if (mbValid) |
312 | 0 | mpImpl->InvalidateAllSubShells(pViewShell); |
313 | 0 | } |
314 | | |
315 | | void ViewShellManager::ActivateLowPriorityShell (SfxShell* pShell) |
316 | 0 | { |
317 | 0 | if (mbValid && pShell!=nullptr) |
318 | 0 | mpImpl->ActivateLowPriorityShell(*pShell); |
319 | 0 | } |
320 | | |
321 | | void ViewShellManager::DeactivateShell (const SfxShell* pShell) |
322 | 0 | { |
323 | 0 | if (mbValid && pShell!=nullptr) |
324 | 0 | mpImpl->DeactivateShell(*pShell); |
325 | 0 | } |
326 | | |
327 | | void ViewShellManager::MoveToTop (const ViewShell& rParentShell) |
328 | 0 | { |
329 | 0 | if (mbValid) |
330 | 0 | mpImpl->MoveToTop(rParentShell); |
331 | 0 | } |
332 | | |
333 | | SfxShell* ViewShellManager::GetShell (ShellId nId) const |
334 | 0 | { |
335 | 0 | if (mbValid) |
336 | 0 | return mpImpl->GetShell(nId); |
337 | 0 | else |
338 | 0 | return nullptr; |
339 | 0 | } |
340 | | |
341 | | SfxShell* ViewShellManager::GetTopShell() const |
342 | 0 | { |
343 | 0 | if (mbValid) |
344 | 0 | return mpImpl->GetTopShell(); |
345 | 0 | else |
346 | 0 | return nullptr; |
347 | 0 | } |
348 | | |
349 | | SfxShell* ViewShellManager::GetTopViewShell() const |
350 | 0 | { |
351 | 0 | if (mbValid) |
352 | 0 | return mpImpl->GetTopViewShell(); |
353 | 0 | else |
354 | 0 | return nullptr; |
355 | 0 | } |
356 | | |
357 | | void ViewShellManager::Shutdown() |
358 | 0 | { |
359 | 0 | if (mbValid) |
360 | 0 | { |
361 | 0 | mpImpl->Shutdown(); |
362 | 0 | mbValid = false; |
363 | 0 | } |
364 | 0 | } |
365 | | |
366 | | void ViewShellManager::LockUpdate() |
367 | 0 | { |
368 | 0 | mpImpl->LockUpdate(); |
369 | 0 | } |
370 | | |
371 | | void ViewShellManager::UnlockUpdate() |
372 | 0 | { |
373 | 0 | mpImpl->UnlockUpdate(); |
374 | 0 | } |
375 | | |
376 | | //===== ViewShellManager::Implementation ====================================== |
377 | | |
378 | | ViewShellManager::Implementation::Implementation ( |
379 | | ViewShellBase& rBase) |
380 | 0 | : mrBase(rBase), |
381 | 0 | mnUpdateLockCount(0), |
382 | 0 | mbShellStackIsUpToDate(true), |
383 | 0 | mpFormShell(nullptr), |
384 | 0 | mpFormShellParent(nullptr), |
385 | 0 | mbFormShellAboveParent(true), |
386 | 0 | mpTopShell(nullptr), |
387 | 0 | mpTopViewShell(nullptr) |
388 | 0 | {} |
389 | | |
390 | | ViewShellManager::Implementation::~Implementation() COVERITY_NOEXCEPT_FALSE |
391 | 0 | { |
392 | 0 | Shutdown(); |
393 | 0 | } |
394 | | |
395 | | void ViewShellManager::Implementation::AddShellFactory ( |
396 | | const SfxShell* pViewShell, |
397 | | const SharedShellFactory& rpFactory) |
398 | 0 | { |
399 | 0 | bool bAlreadyAdded (false); |
400 | | |
401 | | // Check that the given factory has not already been added. |
402 | 0 | ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( |
403 | 0 | maShellFactories.equal_range(pViewShell)); |
404 | 0 | for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) |
405 | 0 | if (iFactory->second == rpFactory) |
406 | 0 | { |
407 | 0 | bAlreadyAdded = true; |
408 | 0 | break; |
409 | 0 | } |
410 | | |
411 | | // Add the factory if it is not already present. |
412 | 0 | if ( ! bAlreadyAdded) |
413 | 0 | maShellFactories.emplace(pViewShell, rpFactory); |
414 | 0 | } |
415 | | |
416 | | void ViewShellManager::Implementation::RemoveShellFactory ( |
417 | | const SfxShell* pViewShell, |
418 | | const SharedShellFactory& rpFactory) |
419 | 0 | { |
420 | 0 | ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( |
421 | 0 | maShellFactories.equal_range(pViewShell)); |
422 | 0 | for (FactoryList::iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) |
423 | 0 | if (iFactory->second == rpFactory) |
424 | 0 | { |
425 | 0 | maShellFactories.erase(iFactory); |
426 | 0 | break; |
427 | 0 | } |
428 | 0 | } |
429 | | |
430 | | void ViewShellManager::Implementation::ActivateViewShell (ViewShell* pViewShell) |
431 | 0 | { |
432 | 0 | ::osl::MutexGuard aGuard (maMutex); |
433 | |
|
434 | 0 | ShellDescriptor aResult; |
435 | 0 | aResult.mpShell = pViewShell; |
436 | | |
437 | | // Register as window listener so that the shells of the current |
438 | | // window can be moved to the top of the shell stack. |
439 | 0 | if (aResult.mpShell != nullptr) |
440 | 0 | { |
441 | 0 | vcl::Window* pWindow = aResult.GetWindow(); |
442 | 0 | if (pWindow != nullptr) |
443 | 0 | { |
444 | 0 | pWindow->AddEventListener( |
445 | 0 | LINK(this, ViewShellManager::Implementation, WindowEventHandler)); |
446 | 0 | aResult.mbIsListenerAddedToWindow = true; |
447 | 0 | } |
448 | 0 | else |
449 | 0 | { |
450 | 0 | SAL_WARN("sd.view", |
451 | 0 | "ViewShellManager::ActivateViewShell: " |
452 | 0 | "new view shell has no active window"); |
453 | 0 | } |
454 | 0 | } |
455 | | |
456 | 0 | ActivateShell(aResult); |
457 | 0 | } |
458 | | |
459 | | void ViewShellManager::Implementation::DeactivateViewShell (const ViewShell& rShell) |
460 | 0 | { |
461 | 0 | ::osl::MutexGuard aGuard (maMutex); |
462 | |
|
463 | 0 | ActiveShellList::iterator iShell (::std::find_if ( |
464 | 0 | maActiveViewShells.begin(), |
465 | 0 | maActiveViewShells.end(), |
466 | 0 | IsShell(&rShell))); |
467 | 0 | if (iShell == maActiveViewShells.end()) |
468 | 0 | return; |
469 | | |
470 | | // iShell points to a ShellDescriptor with mpShell pointing to rShell |
471 | | |
472 | 0 | UpdateLock aLocker (*this); |
473 | |
|
474 | 0 | ShellDescriptor aDescriptor(*iShell); |
475 | 0 | mrBase.GetDocShell()->Disconnect(&rShell); |
476 | 0 | maActiveViewShells.erase(iShell); |
477 | 0 | TakeShellsFromStack(rShell); |
478 | | |
479 | | // Deactivate sub shells. |
480 | 0 | SubShellList::iterator iList (maActiveSubShells.find(&rShell)); |
481 | 0 | if (iList != maActiveSubShells.end()) |
482 | 0 | { |
483 | 0 | SubShellSubList& rList (iList->second); |
484 | 0 | while ( ! rList.empty()) |
485 | 0 | DeactivateSubShell(rShell, rList.front().mnId); |
486 | 0 | } |
487 | |
|
488 | 0 | DestroyViewShell(aDescriptor); |
489 | 0 | } |
490 | | |
491 | | void ViewShellManager::Implementation::ActivateLowPriorityShell (SfxShell& rShell) |
492 | 0 | { |
493 | 0 | ::osl::MutexGuard aGuard (maMutex); |
494 | | |
495 | | // Create a new shell or recycle on in the cache. |
496 | 0 | ShellDescriptor aDescriptor; |
497 | 0 | aDescriptor.mpShell = &rShell; |
498 | |
|
499 | 0 | ActivateLowPriorityShell(aDescriptor); |
500 | 0 | } |
501 | | |
502 | | void ViewShellManager::Implementation::ActivateShell (const ShellDescriptor& rDescriptor) |
503 | 0 | { |
504 | | // Put shell on top of the active view shells. |
505 | 0 | if (rDescriptor.mpShell != nullptr) |
506 | 0 | { |
507 | 0 | maActiveViewShells.insert( maActiveViewShells.begin(), rDescriptor); |
508 | 0 | } |
509 | 0 | } |
510 | | |
511 | | void ViewShellManager::Implementation::ActivateLowPriorityShell (const ShellDescriptor& rDescriptor) |
512 | 0 | { |
513 | | // Put shell on bottom of the active view shells. |
514 | 0 | if (rDescriptor.mpShell != nullptr) |
515 | 0 | { |
516 | 0 | maActiveViewShells.push_back( rDescriptor ); |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | | void ViewShellManager::Implementation::DeactivateShell (const SfxShell& rShell) |
521 | 0 | { |
522 | 0 | ::osl::MutexGuard aGuard (maMutex); |
523 | |
|
524 | 0 | ActiveShellList::iterator iShell (::std::find_if ( |
525 | 0 | maActiveViewShells.begin(), |
526 | 0 | maActiveViewShells.end(), |
527 | 0 | IsShell(&rShell))); |
528 | 0 | if (iShell == maActiveViewShells.end()) |
529 | 0 | return; |
530 | | |
531 | | // iShell points to a ShellDescriptor with mpShell pointing to rShell |
532 | | |
533 | 0 | UpdateLock aLocker (*this); |
534 | |
|
535 | 0 | ShellDescriptor aDescriptor(*iShell); |
536 | 0 | mrBase.GetDocShell()->Disconnect(dynamic_cast<const ViewShell*>(&rShell)); |
537 | 0 | maActiveViewShells.erase(iShell); |
538 | 0 | TakeShellsFromStack(rShell); |
539 | | |
540 | | // Deactivate sub shells. |
541 | 0 | SubShellList::iterator iList (maActiveSubShells.find(&rShell)); |
542 | 0 | if (iList != maActiveSubShells.end()) |
543 | 0 | { |
544 | 0 | SubShellSubList& rList (iList->second); |
545 | 0 | while ( ! rList.empty()) |
546 | 0 | DeactivateSubShell(rShell, rList.front().mnId); |
547 | 0 | } |
548 | |
|
549 | 0 | DestroyViewShell(aDescriptor); |
550 | 0 | } |
551 | | |
552 | | void ViewShellManager::Implementation::ActivateSubShell ( |
553 | | const SfxShell& rParentShell, |
554 | | ShellId nId) |
555 | 0 | { |
556 | 0 | ::osl::MutexGuard aGuard (maMutex); |
557 | | |
558 | | // Check that the given view shell is active. |
559 | 0 | if (std::none_of (maActiveViewShells.begin(), maActiveViewShells.end(), IsShell(&rParentShell))) |
560 | 0 | return; |
561 | | |
562 | | // Create the sub shell list if it does not yet exist. |
563 | 0 | SubShellList::iterator iList (maActiveSubShells.find(&rParentShell)); |
564 | 0 | if (iList == maActiveSubShells.end()) |
565 | 0 | iList = maActiveSubShells.emplace(&rParentShell,SubShellSubList()).first; |
566 | | |
567 | | // Do not activate an object bar that is already active. Requesting |
568 | | // this is not exactly an error but may be an indication of one. |
569 | 0 | SubShellSubList& rList (iList->second); |
570 | 0 | if (std::any_of(rList.begin(),rList.end(), IsId(nId))) |
571 | 0 | return; |
572 | | |
573 | | // Add just the id of the sub shell. The actual shell is created |
574 | | // later in CreateShells(). |
575 | 0 | UpdateLock aLock (*this); |
576 | 0 | rList.emplace_back(nId); |
577 | 0 | } |
578 | | |
579 | | void ViewShellManager::Implementation::DeactivateSubShell ( |
580 | | const SfxShell& rParentShell, |
581 | | ShellId nId) |
582 | 0 | { |
583 | 0 | ::osl::MutexGuard aGuard (maMutex); |
584 | | |
585 | | // Check that the given view shell is active. |
586 | 0 | SubShellList::iterator iList (maActiveSubShells.find(&rParentShell)); |
587 | 0 | if (iList == maActiveSubShells.end()) |
588 | 0 | return; |
589 | | |
590 | | // Look up the sub shell. |
591 | 0 | SubShellSubList& rList (iList->second); |
592 | 0 | SubShellSubList::iterator iShell ( |
593 | 0 | ::std::find_if(rList.begin(),rList.end(), IsId(nId))); |
594 | 0 | if (iShell == rList.end()) |
595 | 0 | return; |
596 | 0 | SfxShell* pShell = iShell->mpShell; |
597 | 0 | if (pShell == nullptr) |
598 | 0 | return; |
599 | | |
600 | 0 | UpdateLock aLock (*this); |
601 | |
|
602 | 0 | ShellDescriptor aDescriptor(*iShell); |
603 | | // Remove the sub shell from both the internal structure as well as the |
604 | | // SFX shell stack above and including the sub shell. |
605 | 0 | rList.erase(iShell); |
606 | 0 | TakeShellsFromStack(*pShell); |
607 | |
|
608 | 0 | DestroySubShell(aDescriptor); |
609 | 0 | } |
610 | | |
611 | | std::shared_ptr<ViewShell> ViewShellManager::Implementation::GetOverridingShell() |
612 | 0 | { |
613 | 0 | return mpOverridingShell.lock(); |
614 | 0 | } |
615 | | |
616 | | void ViewShellManager::Implementation::RemoveOverridingMainShell() |
617 | 0 | { |
618 | 0 | mpOverridingShell.reset(); |
619 | 0 | } |
620 | | |
621 | | void ViewShellManager::Implementation::SetOverridingShell(const std::shared_ptr<ViewShell>& pViewShell) |
622 | 0 | { |
623 | 0 | mpOverridingShell = pViewShell; |
624 | 0 | } |
625 | | |
626 | | void ViewShellManager::Implementation::MoveToTop (const SfxShell& rShell) |
627 | 0 | { |
628 | 0 | ::osl::MutexGuard aGuard (maMutex); |
629 | | |
630 | | // Check that we have access to a dispatcher. If not, then we are |
631 | | // (probably) called while the view shell is still being created or |
632 | | // initialized. Without dispatcher we can not rebuild the shell stack |
633 | | // to move the requested shell to the top. So return right away instead |
634 | | // of making a mess without being able to clean up afterwards. |
635 | 0 | if (mrBase.GetDispatcher() == nullptr) |
636 | 0 | return; |
637 | | |
638 | 0 | ActiveShellList::iterator iShell (::std::find_if ( |
639 | 0 | maActiveViewShells.begin(), |
640 | 0 | maActiveViewShells.end(), |
641 | 0 | IsShell(&rShell))); |
642 | 0 | bool bMove = true; |
643 | 0 | if (iShell != maActiveViewShells.end()) |
644 | 0 | { |
645 | | // Is the shell already at the top of the stack? We have to keep |
646 | | // the case in mind that mbKeepMainViewShellOnTop is true. Shells |
647 | | // that are not the main view shell are placed on the second-to-top |
648 | | // position in this case. |
649 | 0 | if (iShell == maActiveViewShells.begin()) |
650 | 0 | { |
651 | | // The shell is at the top position and is either a) the main |
652 | | // view shell or b) another shell but the main view shell is not |
653 | | // kept at the top position. We do not have to move the shell. |
654 | 0 | bMove = false; |
655 | 0 | } |
656 | 0 | } |
657 | 0 | else |
658 | 0 | { |
659 | | // The shell is not on the stack. Therefore it can not be moved. |
660 | | // We could insert it but we don't. Use ActivateViewShell() for |
661 | | // that. |
662 | 0 | bMove = false; |
663 | 0 | } |
664 | | |
665 | | // When the shell is not at the right position it is removed from the |
666 | | // internal list of shells and inserted at the correct position. |
667 | 0 | if (bMove) |
668 | 0 | { |
669 | 0 | UpdateLock aLock (*this); |
670 | |
|
671 | 0 | ShellDescriptor aDescriptor(*iShell); |
672 | |
|
673 | 0 | TakeShellsFromStack(rShell); |
674 | 0 | maActiveViewShells.erase(iShell); |
675 | |
|
676 | 0 | maActiveViewShells.insert(maActiveViewShells.begin(), aDescriptor); |
677 | 0 | } |
678 | 0 | } |
679 | | |
680 | | SfxShell* ViewShellManager::Implementation::GetShell (ShellId nId) const |
681 | 0 | { |
682 | 0 | ::osl::MutexGuard aGuard (maMutex); |
683 | |
|
684 | 0 | SfxShell* pShell = nullptr; |
685 | | |
686 | | // First search the active view shells. |
687 | 0 | ActiveShellList::const_iterator iShell ( |
688 | 0 | ::std::find_if ( |
689 | 0 | maActiveViewShells.begin(), |
690 | 0 | maActiveViewShells.end(), |
691 | 0 | IsId(nId))); |
692 | 0 | if (iShell != maActiveViewShells.end()) |
693 | 0 | pShell = iShell->mpShell; |
694 | 0 | else |
695 | 0 | { |
696 | | // Now search the active sub shells of every active view shell. |
697 | 0 | for (auto const& activeSubShell : maActiveSubShells) |
698 | 0 | { |
699 | 0 | const SubShellSubList& rList (activeSubShell.second); |
700 | 0 | SubShellSubList::const_iterator iSubShell( |
701 | 0 | ::std::find_if(rList.begin(),rList.end(), IsId(nId))); |
702 | 0 | if (iSubShell != rList.end()) |
703 | 0 | { |
704 | 0 | pShell = iSubShell->mpShell; |
705 | 0 | break; |
706 | 0 | } |
707 | 0 | } |
708 | 0 | } |
709 | |
|
710 | 0 | return pShell; |
711 | 0 | } |
712 | | |
713 | | SfxShell* ViewShellManager::Implementation::GetTopShell() const |
714 | 0 | { |
715 | 0 | OSL_ASSERT(mpTopShell == mrBase.GetSubShell(0)); |
716 | 0 | return mpTopShell; |
717 | 0 | } |
718 | | |
719 | | SfxShell* ViewShellManager::Implementation::GetTopViewShell() const |
720 | 0 | { |
721 | 0 | return mpTopViewShell; |
722 | 0 | } |
723 | | |
724 | | void ViewShellManager::Implementation::LockUpdate() |
725 | 0 | { |
726 | 0 | mnUpdateLockCount++; |
727 | 0 | } |
728 | | |
729 | | void ViewShellManager::Implementation::UnlockUpdate() |
730 | 0 | { |
731 | 0 | ::osl::MutexGuard aGuard (maMutex); |
732 | |
|
733 | 0 | mnUpdateLockCount--; |
734 | 0 | if (mnUpdateLockCount < 0) |
735 | 0 | { |
736 | | // This should not happen. |
737 | 0 | OSL_ASSERT (mnUpdateLockCount>=0); |
738 | 0 | mnUpdateLockCount = 0; |
739 | 0 | } |
740 | 0 | if (mnUpdateLockCount == 0) |
741 | 0 | UpdateShellStack(); |
742 | 0 | } |
743 | | |
744 | | /** Update the SFX shell stack (the portion that is visible to us) so that |
745 | | it matches the internal shell stack. This is done in six steps: |
746 | | 1. Create the missing view shells and sub shells. |
747 | | 2. Set up the internal shell stack. |
748 | | 3. Get the SFX shell stack. |
749 | | 4. Find the lowest shell in which the two stacks differ. |
750 | | 5. Remove all shells above and including that shell from the SFX stack. |
751 | | 6. Push all shells of the internal stack on the SFX shell stack that are |
752 | | not already present on the later. |
753 | | */ |
754 | | void ViewShellManager::Implementation::UpdateShellStack() |
755 | 0 | { |
756 | 0 | ::osl::MutexGuard aGuard (maMutex); |
757 | | |
758 | | // Remember the undo manager from the top-most shell on the stack. |
759 | 0 | SfxShell* pTopMostShell = mrBase.GetSubShell(0); |
760 | 0 | SfxUndoManager* pUndoManager = (pTopMostShell!=nullptr) |
761 | 0 | ? pTopMostShell->GetUndoManager() |
762 | 0 | : nullptr; |
763 | | |
764 | | // 1. Create the missing shells. |
765 | 0 | CreateShells(); |
766 | |
|
767 | 0 | SfxShell* pPreviousTopViewShell = mpTopViewShell; |
768 | | // Update the pointer to the top-most active view shell. |
769 | 0 | mpTopViewShell = (maActiveViewShells.empty() || mbFormShellAboveParent) |
770 | 0 | ? nullptr : maActiveViewShells.begin()->mpShell; |
771 | |
|
772 | 0 | bool bTopViewShellChanged = mpTopViewShell != pPreviousTopViewShell; |
773 | | |
774 | | // 2. Create the internal target stack. |
775 | 0 | ShellStack aTargetStack; |
776 | 0 | CreateTargetStack(aTargetStack); |
777 | | |
778 | | // 3. Get SFX shell stack. |
779 | 0 | ShellStack aSfxShellStack; |
780 | 0 | sal_uInt16 nIndex (0); |
781 | 0 | while (mrBase.GetSubShell(nIndex)!=nullptr) |
782 | 0 | ++nIndex; |
783 | 0 | aSfxShellStack.reserve(nIndex); |
784 | 0 | while (nIndex > 0) |
785 | 0 | { |
786 | 0 | --nIndex; |
787 | 0 | aSfxShellStack.push_back(mrBase.GetSubShell(nIndex)); |
788 | 0 | } |
789 | |
|
790 | | #if OSL_DEBUG_LEVEL >= 2 |
791 | | SAL_INFO("sd.view", __func__ << ": Current SFX Stack"); |
792 | | DumpShellStack(aSfxShellStack); |
793 | | SAL_INFO("sd.view", __func__ << ": Target Stack"); |
794 | | DumpShellStack(aTargetStack); |
795 | | #endif |
796 | | |
797 | | // 4. Find the lowest shell in which the two stacks differ. |
798 | 0 | auto mismatchIters = std::mismatch(aSfxShellStack.begin(), aSfxShellStack.end(), |
799 | 0 | aTargetStack.begin(), aTargetStack.end()); |
800 | 0 | ShellStack::iterator iSfxShell (mismatchIters.first); |
801 | 0 | ShellStack::iterator iTargetShell (mismatchIters.second); |
802 | | |
803 | | // 5. Remove all shells above and including the differing shell from the |
804 | | // SFX stack starting with the shell on top of the stack. |
805 | 0 | for (std::reverse_iterator<ShellStack::const_iterator> i(aSfxShellStack.end()), iLast(iSfxShell); |
806 | 0 | i != iLast; ++i) |
807 | 0 | { |
808 | 0 | SfxShell* const pShell = *i; |
809 | 0 | SAL_INFO("sd.view", __func__ << ": removing shell " << pShell << " from stack"); |
810 | 0 | mrBase.RemoveSubShell(pShell); |
811 | 0 | } |
812 | 0 | aSfxShellStack.erase(iSfxShell, aSfxShellStack.end()); |
813 | | |
814 | | // 6. Push shells from the given stack onto the SFX stack. |
815 | 0 | mbShellStackIsUpToDate = false; |
816 | 0 | while (iTargetShell != aTargetStack.end()) |
817 | 0 | { |
818 | 0 | SAL_INFO("sd.view", __func__ << ": pushing shell " << *iTargetShell << " on stack"); |
819 | 0 | mrBase.AddSubShell(**iTargetShell); |
820 | 0 | ++iTargetShell; |
821 | | |
822 | | // The pushing of the shell on to the shell stack may have lead to |
823 | | // another invocation of this method. In this case we have to abort |
824 | | // pushing shells on the stack and return immediately. |
825 | 0 | if (mbShellStackIsUpToDate) |
826 | 0 | break; |
827 | 0 | } |
828 | 0 | if (mrBase.GetDispatcher() != nullptr) |
829 | 0 | mrBase.GetDispatcher()->Flush(); |
830 | | |
831 | | // Update the pointer to the top-most shell and set its undo manager |
832 | | // to the one of the previous top-most shell. |
833 | 0 | mpTopShell = mrBase.GetSubShell(0); |
834 | 0 | if (mpTopShell!=nullptr && pUndoManager!=nullptr && mpTopShell->GetUndoManager()==nullptr) |
835 | 0 | mpTopShell->SetUndoManager(pUndoManager); |
836 | | |
837 | | // Only broadcast context for activation on the top-most ViewShell |
838 | 0 | if (mpTopViewShell && bTopViewShellChanged) |
839 | 0 | mpTopViewShell->BroadcastContextForActivation(true); |
840 | | |
841 | | // Finally tell an invocation of this method on a higher level that it can (has |
842 | | // to) abort and return immediately. |
843 | 0 | mbShellStackIsUpToDate = true; |
844 | |
|
845 | | #if OSL_DEBUG_LEVEL >= 2 |
846 | | SAL_INFO("sd.view", __func__ << ": New current stack"); |
847 | | DumpSfxShellStack(); |
848 | | #endif |
849 | 0 | } |
850 | | |
851 | | void ViewShellManager::Implementation::TakeShellsFromStack (const SfxShell& rShell) |
852 | 0 | { |
853 | 0 | ::osl::MutexGuard aGuard (maMutex); |
854 | | |
855 | | // Remember the undo manager from the top-most shell on the stack. |
856 | 0 | SfxShell* pTopMostShell = mrBase.GetSubShell(0); |
857 | 0 | SfxUndoManager* pUndoManager = (pTopMostShell!=nullptr) |
858 | 0 | ? pTopMostShell->GetUndoManager() |
859 | 0 | : nullptr; |
860 | |
|
861 | | #if OSL_DEBUG_LEVEL >= 2 |
862 | | SAL_INFO("sd.view", __func__ << "TakeShellsFromStack( " << pShell << ")"); |
863 | | DumpSfxShellStack(); |
864 | | #endif |
865 | | |
866 | | // 0.Make sure that the given shell is on the stack. This is a |
867 | | // preparation for the following assertion. |
868 | 0 | for (sal_uInt16 nIndex=0; true; nIndex++) |
869 | 0 | { |
870 | 0 | SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex); |
871 | 0 | if (pShellOnStack == nullptr) |
872 | 0 | { |
873 | | // the shell is not on the stack. |
874 | 0 | return; |
875 | 0 | } |
876 | 0 | else if (pShellOnStack == &rShell) |
877 | 0 | break; |
878 | 0 | } |
879 | | |
880 | | // 1. Deactivate our shells on the stack before they are removed so |
881 | | // that during the Deactivation() calls the stack is still intact. |
882 | 0 | for (sal_uInt16 nIndex=0; true; nIndex++) |
883 | 0 | { |
884 | 0 | SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex); |
885 | 0 | Deactivate(pShellOnStack); |
886 | 0 | if (pShellOnStack == &rShell) |
887 | 0 | break; |
888 | 0 | } |
889 | | |
890 | | // 2. Remove the shells from the stack. |
891 | 0 | while (true) |
892 | 0 | { |
893 | 0 | SfxShell* pShellOnStack = mrBase.GetSubShell(0); |
894 | 0 | SAL_INFO("sd.view", __func__ << "removing shell " << pShellOnStack << " from stack"); |
895 | 0 | mrBase.RemoveSubShell(pShellOnStack); |
896 | 0 | if (pShellOnStack == &rShell) |
897 | 0 | break; |
898 | 0 | } |
899 | | |
900 | | // 3. Update the stack. |
901 | 0 | if (mrBase.GetDispatcher() != nullptr) |
902 | 0 | mrBase.GetDispatcher()->Flush(); |
903 | | |
904 | | // Update the pointer to the top-most shell and set its undo manager |
905 | | // to the one of the previous top-most shell. |
906 | 0 | mpTopShell = mrBase.GetSubShell(0); |
907 | 0 | if (mpTopShell!=nullptr && pUndoManager!=nullptr && mpTopShell->GetUndoManager()==nullptr) |
908 | 0 | mpTopShell->SetUndoManager(pUndoManager); |
909 | |
|
910 | | #if OSL_DEBUG_LEVEL >= 2 |
911 | | SAL_INFO("sd.view", __func__ << "Sfx shell stack is:"); |
912 | | DumpSfxShellStack(); |
913 | | #endif |
914 | 0 | } |
915 | | |
916 | | void ViewShellManager::Implementation::CreateShells() |
917 | 0 | { |
918 | 0 | ::osl::MutexGuard aGuard (maMutex); |
919 | | |
920 | | // Iterate over all view shells. |
921 | 0 | ActiveShellList::reverse_iterator iShell; |
922 | 0 | for (iShell=maActiveViewShells.rbegin(); iShell!=maActiveViewShells.rend(); ++iShell) |
923 | 0 | { |
924 | | // Get the list of associated sub shells. |
925 | 0 | SubShellList::iterator iList (maActiveSubShells.find(iShell->mpShell)); |
926 | 0 | if (iList != maActiveSubShells.end()) |
927 | 0 | { |
928 | 0 | SubShellSubList& rList (iList->second); |
929 | | |
930 | | // Iterate over all sub shells of the current view shell. |
931 | 0 | for (auto & subShell : rList) |
932 | 0 | { |
933 | 0 | if (subShell.mpShell == nullptr) |
934 | 0 | { |
935 | 0 | subShell = CreateSubShell(iShell->mpShell,subShell.mnId); |
936 | 0 | } |
937 | 0 | } |
938 | 0 | } |
939 | 0 | } |
940 | 0 | } |
941 | | |
942 | | void ViewShellManager::Implementation::CreateTargetStack (ShellStack& rStack) const |
943 | 0 | { |
944 | | // Create a local stack of the shells that are to push on the shell |
945 | | // stack. We can thus safely create the required shells while still |
946 | | // having a valid shell stack. |
947 | 0 | for (ActiveShellList::const_reverse_iterator iViewShell (maActiveViewShells.rbegin()); |
948 | 0 | iViewShell != maActiveViewShells.rend(); |
949 | 0 | ++iViewShell) |
950 | 0 | { |
951 | | // Possibly place the form shell below the current view shell. |
952 | 0 | if ( ! mbFormShellAboveParent |
953 | 0 | && mpFormShell!=nullptr |
954 | 0 | && iViewShell->mpShell==mpFormShellParent) |
955 | 0 | { |
956 | 0 | rStack.push_back(mpFormShell); |
957 | 0 | } |
958 | | |
959 | | // Put the view shell itself on the local stack. |
960 | 0 | rStack.push_back (iViewShell->mpShell); |
961 | | |
962 | | // Possibly place the form shell above the current view shell. |
963 | 0 | if (mbFormShellAboveParent |
964 | 0 | && mpFormShell!=nullptr |
965 | 0 | && iViewShell->mpShell==mpFormShellParent) |
966 | 0 | { |
967 | 0 | rStack.push_back(mpFormShell); |
968 | 0 | } |
969 | | |
970 | | // Add all other sub shells. |
971 | 0 | SubShellList::const_iterator iList (maActiveSubShells.find(iViewShell->mpShell)); |
972 | 0 | if (iList != maActiveSubShells.end()) |
973 | 0 | { |
974 | 0 | const SubShellSubList& rList (iList->second); |
975 | 0 | SubShellSubList::const_reverse_iterator iSubShell; |
976 | 0 | for (iSubShell=rList.rbegin(); iSubShell!=rList.rend(); ++iSubShell) |
977 | 0 | if (iSubShell->mpShell != mpFormShell) |
978 | 0 | rStack.push_back(iSubShell->mpShell); |
979 | 0 | } |
980 | 0 | } |
981 | 0 | } |
982 | | |
983 | | IMPL_LINK(ViewShellManager::Implementation, WindowEventHandler, VclWindowEvent&, rEvent, void) |
984 | 0 | { |
985 | 0 | vcl::Window* pEventWindow = rEvent.GetWindow(); |
986 | |
|
987 | 0 | switch (rEvent.GetId()) |
988 | 0 | { |
989 | 0 | case VclEventId::WindowGetFocus: |
990 | 0 | { |
991 | 0 | for (auto const& activeShell : maActiveViewShells) |
992 | 0 | { |
993 | 0 | if (pEventWindow == activeShell.GetWindow()) |
994 | 0 | { |
995 | 0 | MoveToTop(*activeShell.mpShell); |
996 | 0 | break; |
997 | 0 | } |
998 | 0 | } |
999 | 0 | } |
1000 | 0 | break; |
1001 | | |
1002 | 0 | case VclEventId::WindowLoseFocus: |
1003 | 0 | break; |
1004 | | |
1005 | 0 | case VclEventId::ObjectDying: |
1006 | | // Remember that we do not have to remove the window |
1007 | | // listener for this window. |
1008 | 0 | for (auto & activeViewShell : maActiveViewShells) |
1009 | 0 | { |
1010 | 0 | if (activeViewShell.GetWindow() == pEventWindow) |
1011 | 0 | { |
1012 | 0 | activeViewShell.mbIsListenerAddedToWindow = false; |
1013 | 0 | break; |
1014 | 0 | } |
1015 | 0 | } |
1016 | 0 | break; |
1017 | | |
1018 | 0 | default: break; |
1019 | 0 | } |
1020 | 0 | } |
1021 | | |
1022 | | ShellDescriptor ViewShellManager::Implementation::CreateSubShell ( |
1023 | | SfxShell const * pParentShell, |
1024 | | ShellId nShellId) |
1025 | 0 | { |
1026 | 0 | ::osl::MutexGuard aGuard (maMutex); |
1027 | 0 | ShellDescriptor aResult; |
1028 | | |
1029 | | // Look up the factories for the parent shell. |
1030 | 0 | ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( |
1031 | 0 | maShellFactories.equal_range(pParentShell)); |
1032 | | |
1033 | | // Try all factories to create the shell. |
1034 | 0 | for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) |
1035 | 0 | { |
1036 | 0 | SharedShellFactory pFactory = iFactory->second; |
1037 | 0 | if (pFactory != nullptr) |
1038 | 0 | aResult.mpShell = pFactory->CreateShell(nShellId); |
1039 | | |
1040 | | // Exit the loop when the shell has been successfully created. |
1041 | 0 | if (aResult.mpShell != nullptr) |
1042 | 0 | { |
1043 | 0 | aResult.mpFactory = std::move(pFactory); |
1044 | 0 | aResult.mnId = nShellId; |
1045 | 0 | break; |
1046 | 0 | } |
1047 | 0 | } |
1048 | |
|
1049 | 0 | return aResult; |
1050 | 0 | } |
1051 | | |
1052 | | void ViewShellManager::Implementation::DestroyViewShell ( |
1053 | | ShellDescriptor& rDescriptor) |
1054 | 0 | { |
1055 | 0 | OSL_ASSERT(rDescriptor.mpShell != nullptr); |
1056 | |
|
1057 | 0 | if (rDescriptor.mbIsListenerAddedToWindow) |
1058 | 0 | { |
1059 | 0 | rDescriptor.mbIsListenerAddedToWindow = false; |
1060 | 0 | vcl::Window* pWindow = rDescriptor.GetWindow(); |
1061 | 0 | if (pWindow != nullptr) |
1062 | 0 | { |
1063 | 0 | pWindow->RemoveEventListener( |
1064 | 0 | LINK(this, ViewShellManager::Implementation, WindowEventHandler)); |
1065 | 0 | } |
1066 | 0 | } |
1067 | | |
1068 | | // Destroy the sub shell factories. |
1069 | 0 | ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( |
1070 | 0 | maShellFactories.equal_range(rDescriptor.mpShell)); |
1071 | 0 | if (aRange.first != maShellFactories.end()) |
1072 | 0 | maShellFactories.erase(aRange.first, aRange.second); |
1073 | | |
1074 | | // Release the shell. |
1075 | 0 | if (rDescriptor.mpFactory) |
1076 | 0 | rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell); |
1077 | 0 | } |
1078 | | |
1079 | | void ViewShellManager::Implementation::DestroySubShell ( |
1080 | | const ShellDescriptor& rDescriptor) |
1081 | 0 | { |
1082 | 0 | OSL_ASSERT(rDescriptor.mpFactory); |
1083 | 0 | rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell); |
1084 | 0 | } |
1085 | | |
1086 | | void ViewShellManager::Implementation::InvalidateAllSubShells (const SfxShell* pParentShell) |
1087 | 0 | { |
1088 | 0 | ::osl::MutexGuard aGuard (maMutex); |
1089 | |
|
1090 | 0 | SubShellList::iterator iList (maActiveSubShells.find(pParentShell)); |
1091 | 0 | if (iList != maActiveSubShells.end()) |
1092 | 0 | { |
1093 | 0 | SubShellSubList& rList (iList->second); |
1094 | 0 | for (auto const& shell : rList) |
1095 | 0 | if (shell.mpShell != nullptr) |
1096 | 0 | shell.mpShell->Invalidate(); |
1097 | 0 | } |
1098 | 0 | } |
1099 | | |
1100 | | void ViewShellManager::Implementation::Shutdown() |
1101 | 0 | { |
1102 | 0 | ::osl::MutexGuard aGuard (maMutex); |
1103 | | |
1104 | | // Take stacked shells from stack. |
1105 | 0 | if ( ! maActiveViewShells.empty()) |
1106 | 0 | { |
1107 | 0 | UpdateLock aLock (*this); |
1108 | |
|
1109 | 0 | while ( ! maActiveViewShells.empty()) |
1110 | 0 | { |
1111 | 0 | SfxShell* pShell = maActiveViewShells.front().mpShell; |
1112 | 0 | if (pShell != nullptr) |
1113 | 0 | { |
1114 | 0 | ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell); |
1115 | 0 | if (pViewShell != nullptr) |
1116 | 0 | DeactivateViewShell(*pViewShell); |
1117 | 0 | else |
1118 | 0 | DeactivateShell(*pShell); |
1119 | 0 | } |
1120 | 0 | else |
1121 | 0 | { |
1122 | 0 | SAL_WARN("sd.view", |
1123 | 0 | "ViewShellManager::Implementation::Shutdown(): empty active shell descriptor"); |
1124 | 0 | maActiveViewShells.pop_front(); |
1125 | 0 | } |
1126 | 0 | } |
1127 | 0 | } |
1128 | 0 | mrBase.RemoveSubShell (); |
1129 | |
|
1130 | 0 | maShellFactories.clear(); |
1131 | 0 | mpOverridingShell.reset(); |
1132 | 0 | } |
1133 | | |
1134 | | #if OSL_DEBUG_LEVEL >= 2 |
1135 | | void ViewShellManager::Implementation::DumpShellStack (const ShellStack& rStack) |
1136 | | { |
1137 | | ShellStack::const_reverse_iterator iEntry; |
1138 | | for (iEntry=rStack.rbegin(); iEntry!=rStack.rend(); ++iEntry) |
1139 | | if (*iEntry != NULL) |
1140 | | SAL_INFO("sd.view", __func__ << ": " << |
1141 | | *iEntry << " : " << |
1142 | | (*iEntry)->GetName()); |
1143 | | else |
1144 | | SAL_INFO("sd.view", __func__ << " null"); |
1145 | | } |
1146 | | |
1147 | | void ViewShellManager::Implementation::DumpSfxShellStack() |
1148 | | { |
1149 | | ShellStack aSfxShellStack; |
1150 | | sal_uInt16 nIndex (0); |
1151 | | while (mrBase.GetSubShell(nIndex)!=NULL) |
1152 | | ++nIndex; |
1153 | | aSfxShellStack.reserve(nIndex); |
1154 | | while (nIndex-- > 0) |
1155 | | aSfxShellStack.push_back(mrBase.GetSubShell(nIndex)); |
1156 | | DumpShellStack(aSfxShellStack); |
1157 | | } |
1158 | | #endif |
1159 | | |
1160 | | void ViewShellManager::Implementation::Deactivate (SfxShell* pShell) |
1161 | 0 | { |
1162 | 0 | OSL_ASSERT(pShell!=nullptr); |
1163 | | |
1164 | | // We have to end a text edit for view shells that are to be taken from |
1165 | | // the shell stack. |
1166 | 0 | ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell); |
1167 | 0 | if (pViewShell != nullptr) |
1168 | 0 | { |
1169 | 0 | sd::View* pView = pViewShell->GetView(); |
1170 | 0 | if (pView!=nullptr && pView->IsTextEdit()) |
1171 | 0 | { |
1172 | 0 | pView->SdrEndTextEdit(); |
1173 | 0 | pView->UnmarkAll(); |
1174 | | |
1175 | | // dispatch synchronously, otherwise it might execute while another |
1176 | | // ViewShell is active! |
1177 | 0 | pViewShell->GetViewFrame()->GetDispatcher()->Execute( |
1178 | 0 | SID_OBJECT_SELECT, |
1179 | 0 | SfxCallMode::SYNCHRON); |
1180 | 0 | } |
1181 | 0 | } |
1182 | | |
1183 | | // Now we can deactivate the shell. |
1184 | 0 | pShell->Deactivate(true); |
1185 | 0 | } |
1186 | | |
1187 | | void ViewShellManager::Implementation::SetFormShell ( |
1188 | | const ViewShell* pFormShellParent, |
1189 | | FmFormShell* pFormShell, |
1190 | | bool bFormShellAboveParent) |
1191 | 0 | { |
1192 | 0 | ::osl::MutexGuard aGuard (maMutex); |
1193 | |
|
1194 | 0 | mpFormShellParent = pFormShellParent; |
1195 | 0 | mpFormShell = pFormShell; |
1196 | 0 | mbFormShellAboveParent = bFormShellAboveParent; |
1197 | 0 | } |
1198 | | |
1199 | | namespace { |
1200 | | |
1201 | | ShellDescriptor::ShellDescriptor() |
1202 | 0 | : mpShell(nullptr), |
1203 | 0 | mnId(ToolbarId::None), |
1204 | 0 | mbIsListenerAddedToWindow(false) |
1205 | 0 | { |
1206 | 0 | } |
1207 | | |
1208 | | ShellDescriptor::ShellDescriptor ( |
1209 | | ShellId nId) |
1210 | 0 | : mpShell(nullptr), |
1211 | 0 | mnId(nId), |
1212 | 0 | mbIsListenerAddedToWindow(false) |
1213 | 0 | { |
1214 | 0 | } |
1215 | | |
1216 | | vcl::Window* ShellDescriptor::GetWindow() const |
1217 | 0 | { |
1218 | 0 | ViewShell* pViewShell = dynamic_cast<ViewShell*>(mpShell); |
1219 | 0 | if (pViewShell != nullptr) |
1220 | 0 | return pViewShell->GetActiveWindow(); |
1221 | 0 | else |
1222 | 0 | return nullptr; |
1223 | 0 | } |
1224 | | |
1225 | | } // end of anonymous namespace |
1226 | | |
1227 | | } // end of namespace sd |
1228 | | |
1229 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |