cid#1607171 Data race condition
[LibreOffice.git] / sd / source / ui / framework / factories / BasicViewFactory.cxx
blobf94cf08a498a5825652266c31346f6584e910bc6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <framework/factories/BasicViewFactory.hxx>
22 #include <framework/ViewShellWrapper.hxx>
23 #include <framework/FrameworkHelper.hxx>
24 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
25 #include <com/sun/star/lang/IllegalArgumentException.hpp>
26 #include <framework/Pane.hxx>
27 #include <DrawController.hxx>
28 #include <ViewShellBase.hxx>
29 #include <ViewShellManager.hxx>
30 #include <DrawDocShell.hxx>
31 #include <DrawViewShell.hxx>
32 #include <GraphicViewShell.hxx>
33 #include <OutlineViewShell.hxx>
34 #include <NotesPanelViewShell.hxx>
35 #include <PresentationViewShell.hxx>
36 #include <SlideSorterViewShell.hxx>
37 #include <FrameView.hxx>
38 #include <Window.hxx>
40 #include <comphelper/servicehelper.hxx>
41 #include <sfx2/viewfrm.hxx>
42 #include <vcl/wrkwin.hxx>
43 #include <toolkit/helper/vclunohelper.hxx>
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::lang;
49 using namespace ::com::sun::star::drawing::framework;
51 using ::sd::framework::FrameworkHelper;
53 namespace sd::framework {
55 //===== ViewDescriptor ========================================================
57 class BasicViewFactory::ViewDescriptor
59 public:
60 rtl::Reference<ViewShellWrapper> mxView;
61 std::shared_ptr<sd::ViewShell> mpViewShell;
62 Reference<XResourceId> mxViewId;
63 static bool CompareView (const std::shared_ptr<ViewDescriptor>& rpDescriptor,
64 const Reference<XResource>& rxView)
65 { return rpDescriptor->mxView.get() == rxView.get(); }
68 //===== BasicViewFactory::ViewShellContainer ==================================
70 class BasicViewFactory::ViewShellContainer
71 : public ::std::vector<std::shared_ptr<ViewDescriptor> >
73 public:
74 ViewShellContainer() {};
77 class BasicViewFactory::ViewCache
78 : public ::std::vector<std::shared_ptr<ViewDescriptor> >
80 public:
81 ViewCache() {};
84 //===== ViewFactory ===========================================================
86 BasicViewFactory::BasicViewFactory (const rtl::Reference<::sd::DrawController>& rxController)
87 : mpViewShellContainer(new ViewShellContainer()),
88 mpBase(nullptr),
89 mpFrameView(nullptr),
90 mpWindow(VclPtr<WorkWindow>::Create(nullptr,WB_STDWORK)),
91 mpViewCache(std::make_shared<ViewCache>()),
92 mxLocalPane(new Pane(Reference<XResourceId>(), mpWindow.get()))
94 try
96 // Tunnel through the controller to obtain a ViewShellBase.
97 mpBase = rxController->GetViewShellBase();
99 // Register the factory for its supported views.
100 mxConfigurationController = rxController->getConfigurationController();
101 if ( ! mxConfigurationController.is())
102 throw RuntimeException();
103 mxConfigurationController->addResourceFactory(FrameworkHelper::msImpressViewURL, this);
104 mxConfigurationController->addResourceFactory(FrameworkHelper::msDrawViewURL, this);
105 mxConfigurationController->addResourceFactory(FrameworkHelper::msOutlineViewURL, this);
106 mxConfigurationController->addResourceFactory(FrameworkHelper::msNotesViewURL, this);
107 mxConfigurationController->addResourceFactory(FrameworkHelper::msHandoutViewURL, this);
108 mxConfigurationController->addResourceFactory(FrameworkHelper::msPresentationViewURL, this);
109 mxConfigurationController->addResourceFactory(FrameworkHelper::msSlideSorterURL, this);
110 mxConfigurationController->addResourceFactory(FrameworkHelper::msNotesPanelViewURL, this);
112 catch (RuntimeException&)
114 mpBase = nullptr;
115 if (mxConfigurationController.is())
116 mxConfigurationController->removeResourceFactoryForReference(this);
117 throw;
121 BasicViewFactory::~BasicViewFactory()
125 void BasicViewFactory::disposing(std::unique_lock<std::mutex>&)
127 // Disconnect from the frame view.
128 if (mpFrameView != nullptr)
130 mpFrameView->Disconnect();
131 mpFrameView = nullptr;
134 // Release the view cache.
135 for (const auto& rxView : *mpViewCache)
137 ReleaseView(rxView, true);
140 // Release the view shell container. At this point no one other than us
141 // should hold references to the view shells (at the moment this is a
142 // trivial requirement, because no one other than us holds a shared
143 // pointer).
144 // ViewShellContainer::const_iterator iView;
145 for (const auto& rxView : *mpViewShellContainer)
147 OSL_ASSERT(rxView->mpViewShell.use_count() == 1);
149 mpViewShellContainer.reset();
152 Reference<XResource> SAL_CALL BasicViewFactory::createResource (
153 const Reference<XResourceId>& rxViewId)
155 Reference<XResource> xView;
156 const bool bIsCenterPane (
157 rxViewId->isBoundToURL(FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT));
159 // Get the pane for the anchor URL.
160 Reference<XPane> xPane;
161 if (mxConfigurationController.is())
162 xPane.set(mxConfigurationController->getResource(rxViewId->getAnchor()), UNO_QUERY);
164 // For main views use the frame view of the last main view.
165 ::sd::FrameView* pFrameView = nullptr;
166 if (xPane.is() && bIsCenterPane)
168 pFrameView = mpFrameView;
171 // Get Window pointer for XWindow of the pane.
172 vcl::Window* pWindow = nullptr;
173 if (xPane.is())
174 pWindow = VCLUnoHelper::GetWindow(xPane->getWindow());
176 // Get the view frame.
177 SfxViewFrame* pFrame = nullptr;
178 if (mpBase != nullptr)
179 pFrame = &mpBase->GetViewFrame();
181 if (pFrame != nullptr && mpBase!=nullptr && pWindow!=nullptr)
183 // Try to get the view from the cache.
184 std::shared_ptr<ViewDescriptor> pDescriptor (GetViewFromCache(rxViewId, xPane));
186 // When the requested view is not in the cache then create a new view.
187 if (pDescriptor == nullptr)
189 pDescriptor = CreateView(rxViewId, *pFrame, *pWindow, xPane, pFrameView, bIsCenterPane);
192 xView = pDescriptor->mxView;
194 mpViewShellContainer->push_back(pDescriptor);
196 if (bIsCenterPane)
197 ActivateCenterView(pDescriptor);
198 else
199 pWindow->Resize();
202 return xView;
205 void SAL_CALL BasicViewFactory::releaseResource (const Reference<XResource>& rxView)
207 if ( ! rxView.is())
208 throw lang::IllegalArgumentException();
210 if (!rxView.is() || !mpBase)
211 return;
213 ViewShellContainer::iterator iViewShell (
214 ::std::find_if(
215 mpViewShellContainer->begin(),
216 mpViewShellContainer->end(),
217 [&] (std::shared_ptr<ViewDescriptor> const& pVD) {
218 return ViewDescriptor::CompareView(pVD, rxView);
219 } ));
220 if (iViewShell == mpViewShellContainer->end())
222 throw lang::IllegalArgumentException();
225 std::shared_ptr<ViewShell> pViewShell ((*iViewShell)->mpViewShell);
227 if ((*iViewShell)->mxViewId->isBoundToURL(
228 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
230 // Obtain a pointer to and connect to the frame view of the
231 // view. The next view, that is created, will be
232 // initialized with this frame view.
233 if (mpFrameView == nullptr)
235 mpFrameView = pViewShell->GetFrameView();
236 if (mpFrameView)
237 mpFrameView->Connect();
240 // With the view in the center pane the sub controller is
241 // released, too.
242 mpBase->GetDrawController()->SetSubController(
243 Reference<drawing::XDrawSubController>());
245 SfxViewShell* pSfxViewShell = pViewShell->GetViewShell();
246 if (pSfxViewShell != nullptr)
247 pSfxViewShell->DisconnectAllClients();
250 ReleaseView(*iViewShell, false);
252 mpViewShellContainer->erase(iViewShell);
255 std::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::CreateView (
256 const Reference<XResourceId>& rxViewId,
257 SfxViewFrame& rFrame,
258 vcl::Window& rWindow,
259 const Reference<XPane>& rxPane,
260 FrameView* pFrameView,
261 const bool bIsCenterPane)
263 auto pDescriptor = std::make_shared<ViewDescriptor>();
265 pDescriptor->mpViewShell = CreateViewShell(
266 rxViewId,
267 rFrame,
268 rWindow,
269 pFrameView);
270 pDescriptor->mxViewId = rxViewId;
272 if (pDescriptor->mpViewShell != nullptr)
274 pDescriptor->mpViewShell->Init(bIsCenterPane);
275 mpBase->GetViewShellManager()->ActivateViewShell(pDescriptor->mpViewShell.get());
277 Reference<awt::XWindow> xWindow(rxPane->getWindow());
278 rtl::Reference<ViewShellWrapper> wrapper(new ViewShellWrapper(
279 pDescriptor->mpViewShell,
280 rxViewId,
281 xWindow));
283 // register ViewShellWrapper on pane window
284 if (xWindow.is())
286 xWindow->addWindowListener(wrapper);
287 if (pDescriptor->mpViewShell != nullptr)
289 pDescriptor->mpViewShell->Resize();
293 pDescriptor->mxView = wrapper.get();
296 return pDescriptor;
299 std::shared_ptr<ViewShell> BasicViewFactory::CreateViewShell (
300 const Reference<XResourceId>& rxViewId,
301 SfxViewFrame& rFrame,
302 vcl::Window& rWindow,
303 FrameView* pFrameView)
305 std::shared_ptr<ViewShell> pViewShell;
306 const OUString sViewURL (rxViewId->getResourceURL());
307 if (sViewURL == FrameworkHelper::msImpressViewURL)
309 pViewShell =
310 std::make_shared<DrawViewShell>(
311 *mpBase,
312 &rWindow,
313 PageKind::Standard,
314 pFrameView);
315 pViewShell->GetContentWindow()->set_id(u"impress_win"_ustr);
317 else if (sViewURL == FrameworkHelper::msDrawViewURL)
319 pViewShell = std::shared_ptr<GraphicViewShell>(
320 new GraphicViewShell(*mpBase, &rWindow, pFrameView),
321 o3tl::default_delete<GraphicViewShell>());
322 pViewShell->GetContentWindow()->set_id(u"draw_win"_ustr);
324 else if (sViewURL == FrameworkHelper::msOutlineViewURL)
326 pViewShell =
327 std::make_shared<OutlineViewShell>(
328 &rFrame,
329 *mpBase,
330 &rWindow,
331 pFrameView);
332 pViewShell->GetContentWindow()->set_id(u"outline_win"_ustr);
334 else if (sViewURL == FrameworkHelper::msNotesViewURL)
336 pViewShell =
337 std::make_shared<DrawViewShell>(
338 *mpBase,
339 &rWindow,
340 PageKind::Notes,
341 pFrameView);
342 pViewShell->GetContentWindow()->set_id(u"notes_win"_ustr);
344 else if (sViewURL == FrameworkHelper::msHandoutViewURL)
346 pViewShell =
347 std::make_shared<DrawViewShell>(
348 *mpBase,
349 &rWindow,
350 PageKind::Handout,
351 pFrameView);
352 pViewShell->GetContentWindow()->set_id(u"handout_win"_ustr);
354 else if (sViewURL == FrameworkHelper::msPresentationViewURL)
356 pViewShell =
357 std::make_shared<PresentationViewShell>(
358 *mpBase,
359 &rWindow,
360 pFrameView);
361 pViewShell->GetContentWindow()->set_id(u"presentation_win"_ustr);
363 else if (sViewURL == FrameworkHelper::msSlideSorterURL)
365 pViewShell = ::sd::slidesorter::SlideSorterViewShell::Create (
366 &rFrame,
367 *mpBase,
368 &rWindow,
369 pFrameView);
370 pViewShell->GetContentWindow()->set_id(u"slidesorter"_ustr);
372 else if (sViewURL == FrameworkHelper::msNotesPanelViewURL)
374 pViewShell = std::make_shared<NotesPanelViewShell>(&rFrame, *mpBase, &rWindow, pFrameView);
375 pViewShell->GetContentWindow()->set_id(u"notes_panel_win"_ustr);
378 return pViewShell;
381 void BasicViewFactory::ReleaseView (
382 const std::shared_ptr<ViewDescriptor>& rpDescriptor,
383 bool bDoNotCache)
385 bool bIsCacheable (!bDoNotCache && IsCacheable(rpDescriptor));
387 if (bIsCacheable)
389 if (rpDescriptor->mxView)
391 if (mxLocalPane.is())
392 if (rpDescriptor->mxView->relocateToAnchor(mxLocalPane))
393 mpViewCache->push_back(rpDescriptor);
394 else
395 bIsCacheable = false;
396 else
397 bIsCacheable = false;
399 else
401 bIsCacheable = false;
405 if ( ! bIsCacheable)
407 // Shut down the current view shell.
408 rpDescriptor->mpViewShell->Shutdown ();
409 mpBase->GetDocShell()->Disconnect(rpDescriptor->mpViewShell.get());
410 mpBase->GetViewShellManager()->DeactivateViewShell(rpDescriptor->mpViewShell.get());
412 if (rpDescriptor->mxView)
413 rpDescriptor->mxView->dispose();
417 bool BasicViewFactory::IsCacheable (const std::shared_ptr<ViewDescriptor>& rpDescriptor)
419 bool bIsCacheable (false);
421 if (rpDescriptor->mxView)
423 static ::std::vector<Reference<XResourceId> > s_aCacheableResources = [&]()
425 ::std::vector<Reference<XResourceId> > tmp;
426 FrameworkHelper::Instance(*mpBase);
428 // The slide sorter and the task panel are cacheable and relocatable.
429 tmp.push_back(FrameworkHelper::CreateResourceId(
430 FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftDrawPaneURL));
431 tmp.push_back(FrameworkHelper::CreateResourceId(
432 FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftImpressPaneURL));
433 return tmp;
434 }();
436 bIsCacheable = std::any_of(s_aCacheableResources.begin(), s_aCacheableResources.end(),
437 [&rpDescriptor](const Reference<XResourceId>& rxId) { return rxId->compareTo(rpDescriptor->mxViewId) == 0; });
440 return bIsCacheable;
443 std::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::GetViewFromCache (
444 const Reference<XResourceId>& rxViewId,
445 const Reference<XPane>& rxPane)
447 std::shared_ptr<ViewDescriptor> pDescriptor;
449 // Search for the requested view in the cache.
450 ViewCache::iterator iEntry = std::find_if(mpViewCache->begin(), mpViewCache->end(),
451 [&rxViewId](const ViewCache::value_type& rxEntry) { return rxEntry->mxViewId->compareTo(rxViewId) == 0; });
452 if (iEntry != mpViewCache->end())
454 pDescriptor = *iEntry;
455 mpViewCache->erase(iEntry);
458 // When the view has been found then relocate it to the given pane and
459 // remove it from the cache.
460 if (pDescriptor != nullptr)
462 bool bRelocationSuccessful (false);
463 if (pDescriptor->mxView && rxPane.is())
465 if (pDescriptor->mxView->relocateToAnchor(rxPane))
466 bRelocationSuccessful = true;
469 if ( ! bRelocationSuccessful)
471 ReleaseView(pDescriptor, true);
472 pDescriptor.reset();
476 return pDescriptor;
479 void BasicViewFactory::ActivateCenterView (
480 const std::shared_ptr<ViewDescriptor>& rpDescriptor)
482 mpBase->GetDocShell()->Connect(rpDescriptor->mpViewShell.get());
484 // During the creation of the new sub-shell, resize requests were not
485 // forwarded to it because it was not yet registered. Therefore, we
486 // have to request a resize now.
487 rpDescriptor->mpViewShell->UIFeatureChanged();
488 if (mpBase->GetDocShell()->IsInPlaceActive())
489 mpBase->GetViewFrame().Resize(true);
491 mpBase->GetDrawController()->SetSubController(
492 rpDescriptor->mpViewShell->CreateSubController());
495 } // end of namespace sd::framework
498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */