cid#1607171 Data race condition
[LibreOffice.git] / sd / source / ui / framework / factories / BasicPaneFactory.cxx
blob62a42f2ec2b0571e7819747f97cba6c322d834bf
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 <memory>
21 #include <sal/config.h>
23 #include <framework/factories/BasicPaneFactory.hxx>
25 #include "ChildWindowPane.hxx"
26 #include "FrameWindowPane.hxx"
27 #include "FullScreenPane.hxx"
29 #include <comphelper/servicehelper.hxx>
30 #include <framework/FrameworkHelper.hxx>
31 #include <framework/ConfigurationController.hxx>
32 #include <PaneShells.hxx>
33 #include <ViewShellBase.hxx>
34 #include <PaneChildWindows.hxx>
35 #include <DrawController.hxx>
36 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::drawing::framework;
43 using ::sd::framework::FrameworkHelper;
45 namespace {
46 enum PaneId {
47 CenterPaneId,
48 FullScreenPaneId,
49 LeftImpressPaneId,
50 BottomImpressPaneId,
51 LeftDrawPaneId
54 const sal_Int32 gnConfigurationUpdateStartEvent(0);
55 const sal_Int32 gnConfigurationUpdateEndEvent(1);
58 namespace sd::framework {
60 /** Store URL, XPane reference and (local) PaneId for every pane factory
61 that is registered at the PaneController.
63 class BasicPaneFactory::PaneDescriptor
65 public:
66 OUString msPaneURL;
67 Reference<XResource> mxPane;
68 PaneId mePaneId;
69 /** The mbReleased flag is set when the pane has been released. Some
70 panes are just hidden and destroyed. When the pane is reused this
71 flag is reset.
73 bool mbIsReleased;
75 bool CompareURL(std::u16string_view rsPaneURL) const { return msPaneURL == rsPaneURL; }
76 bool ComparePane(const Reference<XResource>& rxPane) const { return mxPane == rxPane; }
79 class BasicPaneFactory::PaneContainer
80 : public ::std::vector<PaneDescriptor>
82 public:
83 PaneContainer() {}
86 //===== PaneFactory ===========================================================
88 BasicPaneFactory::BasicPaneFactory (
89 const Reference<XComponentContext>& rxContext,
90 const rtl::Reference<::sd::DrawController>& rxController)
91 : mxComponentContext(rxContext),
92 mpViewShellBase(nullptr),
93 mpPaneContainer(new PaneContainer)
95 try
97 // Tunnel through the controller to obtain access to the ViewShellBase.
98 mpViewShellBase = rxController->GetViewShellBase();
100 rtl::Reference<sd::framework::ConfigurationController> xCC (rxController->getConfigurationControllerImpl());
101 mxConfigurationControllerWeak = xCC.get();
103 // Add pane factories for the two left panes (one for Impress and one for
104 // Draw) and the center pane.
105 if (rxController.is() && xCC.is())
107 PaneDescriptor aDescriptor;
108 aDescriptor.msPaneURL = FrameworkHelper::msCenterPaneURL;
109 aDescriptor.mePaneId = CenterPaneId;
110 aDescriptor.mbIsReleased = false;
111 mpPaneContainer->push_back(aDescriptor);
112 xCC->addResourceFactory(aDescriptor.msPaneURL, this);
114 aDescriptor.msPaneURL = FrameworkHelper::msFullScreenPaneURL;
115 aDescriptor.mePaneId = FullScreenPaneId;
116 mpPaneContainer->push_back(aDescriptor);
117 xCC->addResourceFactory(aDescriptor.msPaneURL, this);
119 aDescriptor.msPaneURL = FrameworkHelper::msLeftImpressPaneURL;
120 aDescriptor.mePaneId = LeftImpressPaneId;
121 mpPaneContainer->push_back(aDescriptor);
122 xCC->addResourceFactory(aDescriptor.msPaneURL, this);
124 aDescriptor.msPaneURL = FrameworkHelper::msBottomImpressPaneURL;
125 aDescriptor.mePaneId = BottomImpressPaneId;
126 mpPaneContainer->push_back(aDescriptor);
127 xCC->addResourceFactory(aDescriptor.msPaneURL, this);
129 aDescriptor.msPaneURL = FrameworkHelper::msLeftDrawPaneURL;
130 aDescriptor.mePaneId = LeftDrawPaneId;
131 mpPaneContainer->push_back(aDescriptor);
132 xCC->addResourceFactory(aDescriptor.msPaneURL, this);
135 // Register as configuration change listener.
136 if (xCC.is())
138 xCC->addConfigurationChangeListener(
139 this,
140 FrameworkHelper::msConfigurationUpdateStartEvent,
141 Any(gnConfigurationUpdateStartEvent));
142 xCC->addConfigurationChangeListener(
143 this,
144 FrameworkHelper::msConfigurationUpdateEndEvent,
145 Any(gnConfigurationUpdateEndEvent));
148 catch (RuntimeException&)
150 rtl::Reference<ConfigurationController> xCC (mxConfigurationControllerWeak);
151 if (xCC.is())
152 xCC->removeResourceFactoryForReference(this);
156 BasicPaneFactory::~BasicPaneFactory()
160 void BasicPaneFactory::disposing(std::unique_lock<std::mutex>&)
162 rtl::Reference<ConfigurationController> xCC (mxConfigurationControllerWeak);
163 if (xCC.is())
165 xCC->removeResourceFactoryForReference(this);
166 xCC->removeConfigurationChangeListener(this);
167 mxConfigurationControllerWeak.clear();
170 for (const auto& rDescriptor : *mpPaneContainer)
172 if (rDescriptor.mbIsReleased)
174 Reference<XComponent> xComponent (rDescriptor.mxPane, UNO_QUERY);
175 if (xComponent.is())
177 xComponent->removeEventListener(this);
178 xComponent->dispose();
184 //===== XPaneFactory ==========================================================
186 Reference<XResource> SAL_CALL BasicPaneFactory::createResource (
187 const Reference<XResourceId>& rxPaneId)
189 ThrowIfDisposed();
191 Reference<XResource> xPane;
193 // Based on the ResourceURL of the given ResourceId look up the
194 // corresponding factory descriptor.
195 PaneContainer::iterator iDescriptor (
196 ::std::find_if (
197 mpPaneContainer->begin(),
198 mpPaneContainer->end(),
199 [&] (PaneDescriptor const& rPane) {
200 return rPane.CompareURL(rxPaneId->getResourceURL());
201 } ));
203 if (iDescriptor == mpPaneContainer->end())
205 // The requested pane can not be created by any of the factories
206 // managed by the called BasicPaneFactory object.
207 throw lang::IllegalArgumentException(u"BasicPaneFactory::createPane() called for unknown resource id"_ustr,
208 nullptr,
212 if (iDescriptor->mxPane.is())
214 // The pane has already been created and is still active (has
215 // not yet been released). This should not happen.
216 xPane = iDescriptor->mxPane;
218 else
220 // Create a new pane.
221 switch (iDescriptor->mePaneId)
223 case CenterPaneId:
224 xPane = CreateFrameWindowPane(rxPaneId);
225 break;
227 case FullScreenPaneId:
228 xPane = CreateFullScreenPane(mxComponentContext, rxPaneId);
229 break;
231 case LeftImpressPaneId:
232 case BottomImpressPaneId:
233 case LeftDrawPaneId:
234 xPane = CreateChildWindowPane(
235 rxPaneId,
236 *iDescriptor);
237 break;
239 iDescriptor->mxPane = xPane;
241 // Listen for the pane being disposed.
242 Reference<lang::XComponent> xComponent (xPane, UNO_QUERY);
243 if (xComponent.is())
244 xComponent->addEventListener(this);
246 iDescriptor->mbIsReleased = false;
249 return xPane;
252 void SAL_CALL BasicPaneFactory::releaseResource (
253 const Reference<XResource>& rxPane)
255 ThrowIfDisposed();
257 // Based on the given XPane reference look up the corresponding factory
258 // descriptor.
259 PaneContainer::iterator iDescriptor (
260 ::std::find_if(
261 mpPaneContainer->begin(),
262 mpPaneContainer->end(),
263 [&] (PaneDescriptor const& rPane) { return rPane.ComparePane(rxPane); } ));
265 if (iDescriptor == mpPaneContainer->end())
267 // The given XPane reference is either empty or the pane was not
268 // created by any of the factories managed by the called
269 // BasicPaneFactory object.
270 throw lang::IllegalArgumentException(u"BasicPaneFactory::releasePane() called for pane that was not created by same factory."_ustr,
271 nullptr,
275 // The given pane was created by one of the factories. Child
276 // windows are just hidden and will be reused when requested later.
277 // Other windows are disposed and their reference is reset so that
278 // on the next createPane() call for the same pane type the pane is
279 // created anew.
280 ChildWindowPane* pChildWindowPane = dynamic_cast<ChildWindowPane*>(rxPane.get());
281 if (pChildWindowPane != nullptr)
283 iDescriptor->mbIsReleased = true;
284 pChildWindowPane->Hide();
286 else
288 iDescriptor->mxPane = nullptr;
289 Reference<XComponent> xComponent (rxPane, UNO_QUERY);
290 if (xComponent.is())
292 // We are disposing the pane and do not have to be informed of
293 // that.
294 xComponent->removeEventListener(this);
295 xComponent->dispose();
301 //===== XConfigurationChangeListener ==========================================
303 void SAL_CALL BasicPaneFactory::notifyConfigurationChange (
304 const ConfigurationChangeEvent& /* rEvent */ )
306 // FIXME: nothing to do
309 //===== lang::XEventListener ==================================================
311 void SAL_CALL BasicPaneFactory::disposing (
312 const lang::EventObject& rEventObject)
314 if (uno::Reference<XInterface>(cppu::getXWeak(mxConfigurationControllerWeak.get().get())) == rEventObject.Source)
316 mxConfigurationControllerWeak.clear();
318 else
320 // Has one of the panes been disposed? If so, then release the
321 // reference to that pane, but not the pane descriptor.
322 Reference<XResource> xPane (rEventObject.Source, UNO_QUERY);
323 PaneContainer::iterator iDescriptor (
324 ::std::find_if (
325 mpPaneContainer->begin(),
326 mpPaneContainer->end(),
327 [&] (PaneDescriptor const& rPane) { return rPane.ComparePane(xPane); } ));
328 if (iDescriptor != mpPaneContainer->end())
330 iDescriptor->mxPane = nullptr;
335 Reference<XResource> BasicPaneFactory::CreateFrameWindowPane (
336 const Reference<XResourceId>& rxPaneId)
338 Reference<XResource> xPane;
340 if (mpViewShellBase != nullptr)
342 xPane = new FrameWindowPane(rxPaneId, mpViewShellBase->GetViewWindow());
345 return xPane;
348 Reference<XResource> BasicPaneFactory::CreateFullScreenPane (
349 const Reference<XComponentContext>& rxComponentContext,
350 const Reference<XResourceId>& rxPaneId)
352 Reference<XResource> xPane (
353 new FullScreenPane(
354 rxComponentContext,
355 rxPaneId,
356 mpViewShellBase->GetViewWindow(),
357 mpViewShellBase->GetDocShell()));
359 return xPane;
362 Reference<XResource> BasicPaneFactory::CreateChildWindowPane (
363 const Reference<XResourceId>& rxPaneId,
364 const PaneDescriptor& rDescriptor)
366 Reference<XResource> xPane;
368 if (mpViewShellBase != nullptr)
370 // Create the corresponding shell and determine the id of the child window.
371 sal_uInt16 nChildWindowId = 0;
372 ::std::unique_ptr<SfxShell> pShell;
373 switch (rDescriptor.mePaneId)
375 case LeftImpressPaneId:
376 pShell.reset(new LeftImpressPaneShell());
377 nChildWindowId = ::sd::LeftPaneImpressChildWindow::GetChildWindowId();
378 break;
380 case BottomImpressPaneId:
381 pShell.reset(new BottomImpressPaneShell());
382 nChildWindowId = ::sd::BottomPaneImpressChildWindow::GetChildWindowId();
383 break;
385 case LeftDrawPaneId:
386 pShell.reset(new LeftDrawPaneShell());
387 nChildWindowId = ::sd::LeftPaneDrawChildWindow::GetChildWindowId();
388 break;
390 default:
391 break;
394 // With shell and child window id create the ChildWindowPane
395 // wrapper.
396 if (pShell != nullptr)
398 xPane = new ChildWindowPane(
399 rxPaneId,
400 nChildWindowId,
401 *mpViewShellBase,
402 std::move(pShell));
406 return xPane;
409 void BasicPaneFactory::ThrowIfDisposed() const
411 if (m_bDisposed)
413 throw lang::DisposedException (u"BasicPaneFactory object has already been disposed"_ustr,
414 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
418 } // end of namespace sd::framework
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */