LibreOffice Module sd (master) 1
ConfigurationController.cxx
Go to the documentation of this file.
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
23#include <DrawController.hxx>
30#include "UpdateRequest.hxx"
33#include <com/sun/star/drawing/framework/XControllerManager.hpp>
34#include <com/sun/star/frame/XController.hpp>
35
36#include <sal/log.hxx>
37#include <osl/mutex.hxx>
38#include <vcl/svapp.hxx>
39#include <memory>
40
41using namespace ::com::sun::star;
42using namespace ::com::sun::star::uno;
44using ::sd::framework::FrameworkHelper;
45
46namespace sd::framework {
47
48//----- ConfigurationController::Implementation -------------------------------
49
51{
52public:
54 ConfigurationController& rController,
55 const rtl::Reference<::sd::DrawController>& rxController);
56
58
61 std::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster;
62
68 css::uno::Reference<css::drawing::framework::XConfiguration> mxRequestedConfiguration;
69
70 std::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer;
71
72 std::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager;
73
74 std::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater;
75
79 std::unique_ptr<ChangeRequestQueueProcessor> mpQueueProcessor;
80
81 std::shared_ptr<ConfigurationUpdaterLock> mpConfigurationUpdaterLock;
82
83 sal_Int32 mnLockCount;
84};
85
86//===== ConfigurationController::Lock =========================================
87
88ConfigurationController::Lock::Lock (const Reference<XConfigurationController>& rxController)
89 : mxController(rxController)
90{
91 OSL_ASSERT(mxController.is());
92
93 if (mxController.is())
94 mxController->lock();
95}
96
98{
99 if (mxController.is())
100 mxController->unlock();
101}
102
103//===== ConfigurationController ===============================================
104
107 , mbIsDisposed(false)
108{
109 const SolarMutexGuard aSolarGuard;
110
112 *this,
113 rxController));
114}
115
117{
118}
119
121{
122 if (mpImplementation == nullptr)
123 return;
124
125 SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::disposing");
126 SAL_INFO("sd.fwk", __func__ << ": requesting empty configuration");
127 // To destroy all resources an empty configuration is requested and then,
128 // synchronously, all resulting requests are processed.
129 mpImplementation->mpQueueProcessor->Clear();
130 restoreConfiguration(new Configuration(this,false));
131 mpImplementation->mpQueueProcessor->ProcessUntilEmpty();
132 SAL_INFO("sd.fwk", __func__ << ": all requests processed");
133
134 // Now that all resources have been deactivated, mark the controller as
135 // disposed.
136 mbIsDisposed = true;
137
138 // Release the listeners.
139 lang::EventObject aEvent;
140 aEvent.Source = uno::Reference<uno::XInterface>(static_cast<cppu::OWeakObject*>(this));
141
142 {
143 const SolarMutexGuard aSolarGuard;
144 mpImplementation->mpBroadcaster->DisposeAndClear();
145 }
146
147 mpImplementation->mpQueueProcessor.reset();
148 mpImplementation->mxRequestedConfiguration = nullptr;
149 mpImplementation.reset();
150}
151
153{
154 if (mpImplementation != nullptr)
155 {
156 OSL_ASSERT(mpImplementation->mpQueueProcessor != nullptr);
157
158 mpImplementation->mpQueueProcessor->ProcessOneEvent();
159 }
160}
161
163{
164 if (mpImplementation == nullptr)
165 return;
166 if (mpImplementation->mpQueueProcessor == nullptr)
167 return;
168 mpImplementation->mpQueueProcessor->ProcessUntilEmpty();
169}
170
171//----- XConfigurationControllerBroadcaster -----------------------------------
172
174 const Reference<XConfigurationChangeListener>& rxListener,
175 const OUString& rsEventType,
176 const Any& rUserData)
177{
178 ::osl::MutexGuard aGuard (m_aMutex);
179
181 OSL_ASSERT(mpImplementation != nullptr);
182 mpImplementation->mpBroadcaster->AddListener(rxListener, rsEventType, rUserData);
183}
184
186 const Reference<XConfigurationChangeListener>& rxListener)
187{
188 ::osl::MutexGuard aGuard (m_aMutex);
189
191 mpImplementation->mpBroadcaster->RemoveListener(rxListener);
192}
193
195 const ConfigurationChangeEvent& rEvent)
196{
198 mpImplementation->mpBroadcaster->NotifyListeners(rEvent);
199}
200
201//----- XConfigurationController ----------------------------------------------
202
204{
205 OSL_ASSERT(mpImplementation != nullptr);
206 OSL_ASSERT(mpImplementation->mpConfigurationUpdater != nullptr);
207
208 ::osl::MutexGuard aGuard (m_aMutex);
210
211 ++mpImplementation->mnLockCount;
212 if (mpImplementation->mpConfigurationUpdaterLock == nullptr)
213 mpImplementation->mpConfigurationUpdaterLock
214 = mpImplementation->mpConfigurationUpdater->GetLock();
215}
216
218{
219 ::osl::MutexGuard aGuard (m_aMutex);
220
221 // Allow unlocking while the ConfigurationController is being disposed
222 // (but not when that is done and the controller is disposed.)
223 if (rBHelper.bDisposed)
225
226 OSL_ASSERT(mpImplementation->mnLockCount>0);
227 --mpImplementation->mnLockCount;
228 if (mpImplementation->mnLockCount == 0)
229 mpImplementation->mpConfigurationUpdaterLock.reset();
230}
231
233 const Reference<XResourceId>& rxResourceId,
234 ResourceActivationMode eMode)
235{
236 ::osl::MutexGuard aGuard (m_aMutex);
238
239 // Check whether we are being disposed. This is handled differently
240 // then being completely disposed because the first thing disposing()
241 // does is to deactivate all remaining resources. This is done via
242 // regular methods which must not throw DisposedExceptions. Therefore
243 // we just return silently during that stage.
244 if (rBHelper.bInDispose)
245 {
246 SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceActivation(): ignoring " <<
248 return;
249 }
250
251 SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceActivation() " <<
253
254 if (!rxResourceId.is())
255 return;
256
257 if (eMode == ResourceActivationMode_REPLACE)
258 {
259 // Get a list of the matching resources and create deactivation
260 // requests for them.
261 const Sequence<Reference<XResourceId> > aResourceList (
262 mpImplementation->mxRequestedConfiguration->getResources(
263 rxResourceId->getAnchor(),
264 rxResourceId->getResourceTypePrefix(),
265 AnchorBindingMode_DIRECT));
266
267 for (const auto& rResource : aResourceList)
268 {
269 // Do not request the deactivation of the resource for which
270 // this method was called. Doing it would not change the
271 // outcome but would result in unnecessary work.
272 if (rxResourceId->compareTo(rResource) == 0)
273 continue;
274
275 // Request the deactivation of a resource and all resources
276 // linked to it.
278 }
279 }
280
281 Reference<XConfigurationChangeRequest> xRequest(
283 rxResourceId,
285 postChangeRequest(xRequest);
286}
287
289 const Reference<XResourceId>& rxResourceId)
290{
291 ::osl::MutexGuard aGuard (m_aMutex);
293
294 SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceDeactivation() " <<
296
297 if (!rxResourceId.is())
298 return;
299
300 // Request deactivation of all resources linked to the specified one
301 // as well.
302 const Sequence<Reference<XResourceId> > aLinkedResources (
303 mpImplementation->mxRequestedConfiguration->getResources(
304 rxResourceId,
305 OUString(),
306 AnchorBindingMode_DIRECT));
307 for (const auto& rLinkedResource : aLinkedResources)
308 {
309 // We do not add deactivation requests directly but call this
310 // method recursively, so that when one time there are resources
311 // linked to linked resources, these are handled correctly, too.
312 requestResourceDeactivation(rLinkedResource);
313 }
314
315 // Add a deactivation request for the specified resource.
316 Reference<XConfigurationChangeRequest> xRequest(
318 rxResourceId,
320 postChangeRequest(xRequest);
321}
322
323Reference<XResource> SAL_CALL ConfigurationController::getResource (
324 const Reference<XResourceId>& rxResourceId)
325{
326 ::osl::MutexGuard aGuard (m_aMutex);
328
330 mpImplementation->mpResourceManager->GetResource(rxResourceId));
331 return aDescriptor.mxResource;
332}
333
335{
336 ::osl::MutexGuard aGuard (m_aMutex);
338
339 if (mpImplementation->mpQueueProcessor->IsEmpty())
340 {
341 // The queue is empty. Add another request that does nothing but
342 // asynchronously trigger a request for an update.
343 mpImplementation->mpQueueProcessor->AddRequest(new UpdateRequest());
344 }
345 else
346 {
347 // The queue is not empty, so we rely on the queue processor to
348 // request an update automatically when the queue becomes empty.
349 }
350}
351
353{
354 ::osl::MutexGuard aGuard (m_aMutex);
356
357 return ! mpImplementation->mpQueueProcessor->IsEmpty();
358}
359
361 const Reference<XConfigurationChangeRequest>& rxRequest)
362{
363 ::osl::MutexGuard aGuard (m_aMutex);
365
366 mpImplementation->mpQueueProcessor->AddRequest(rxRequest);
367}
368
369Reference<XConfiguration> SAL_CALL ConfigurationController::getRequestedConfiguration()
370{
371 ::osl::MutexGuard aGuard (m_aMutex);
373
374 if (mpImplementation->mxRequestedConfiguration.is())
375 return Reference<XConfiguration>(
376 mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY);
377 else
378 return Reference<XConfiguration>();
379}
380
381Reference<XConfiguration> SAL_CALL ConfigurationController::getCurrentConfiguration()
382{
383 ::osl::MutexGuard aGuard (m_aMutex);
385
386 Reference<XConfiguration> xCurrentConfiguration(
387 mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration());
388 if (xCurrentConfiguration.is())
389 return Reference<XConfiguration>(xCurrentConfiguration->createClone(), UNO_QUERY);
390 else
391 return Reference<XConfiguration>();
392}
393
398 const Reference<XConfiguration>& rxNewConfiguration)
399{
400 ::osl::MutexGuard aGuard (m_aMutex);
402
403 // We will probably be making a couple of activation and deactivation
404 // requests so lock the configuration controller and let it later update
405 // all changes at once.
406 std::shared_ptr<ConfigurationUpdaterLock> pLock (
407 mpImplementation->mpConfigurationUpdater->GetLock());
408
409 // Get lists of resources that are to be activated or deactivated.
410 Reference<XConfiguration> xCurrentConfiguration (mpImplementation->mxRequestedConfiguration);
411#if OSL_DEBUG_LEVEL >=1
412 SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::restoreConfiguration(");
413 ConfigurationTracer::TraceConfiguration(rxNewConfiguration, "requested configuration");
414 ConfigurationTracer::TraceConfiguration(xCurrentConfiguration, "current configuration");
415#endif
416 ConfigurationClassifier aClassifier (rxNewConfiguration, xCurrentConfiguration);
417 aClassifier.Partition();
418#if DEBUG_SD_CONFIGURATION_TRACE
419 aClassifier.TraceResourceIdVector(
420 "requested but not current resources:\n", aClassifier.GetC1minusC2());
421 aClassifier.TraceResourceIdVector(
422 "current but not requested resources:\n", aClassifier.GetC2minusC1());
423 aClassifier.TraceResourceIdVector(
424 "requested and current resources:\n", aClassifier.GetC1andC2());
425#endif
426
427 // Request the deactivation of resources that are not requested in the
428 // new configuration.
429 const ConfigurationClassifier::ResourceIdVector& rResourcesToDeactivate (
430 aClassifier.GetC2minusC1());
431 for (const auto& rxResource : rResourcesToDeactivate)
432 {
433 requestResourceDeactivation(rxResource);
434 }
435
436 // Request the activation of resources that are requested in the
437 // new configuration but are not part of the current configuration.
438 const ConfigurationClassifier::ResourceIdVector& rResourcesToActivate (
439 aClassifier.GetC1minusC2());
440 for (const auto& rxResource : rResourcesToActivate)
441 {
442 requestResourceActivation(rxResource, ResourceActivationMode_ADD);
443 }
444
445 pLock.reset();
446}
447
448//----- XResourceFactoryManager -----------------------------------------------
449
451 const OUString& sResourceURL,
452 const Reference<XResourceFactory>& rxResourceFactory)
453{
454 ::osl::MutexGuard aGuard (m_aMutex);
456 mpImplementation->mpResourceFactoryContainer->AddFactory(sResourceURL, rxResourceFactory);
457}
458
460 const OUString& sResourceURL)
461{
462 ::osl::MutexGuard aGuard (m_aMutex);
464 mpImplementation->mpResourceFactoryContainer->RemoveFactoryForURL(sResourceURL);
465}
466
468 const Reference<XResourceFactory>& rxResourceFactory)
469{
470 ::osl::MutexGuard aGuard (m_aMutex);
472 mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory);
473}
474
475Reference<XResourceFactory> SAL_CALL ConfigurationController::getResourceFactory (
476 const OUString& sResourceURL)
477{
478 ::osl::MutexGuard aGuard (m_aMutex);
480
481 return mpImplementation->mpResourceFactoryContainer->GetFactory(sResourceURL);
482}
483
485{
486 if (mbIsDisposed)
487 {
488 throw lang::DisposedException ("ConfigurationController object has already been disposed",
489 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
490 }
491
492 if (mpImplementation == nullptr)
493 {
494 OSL_ASSERT(mpImplementation != nullptr);
495 throw RuntimeException("ConfigurationController not initialized",
496 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
497 }
498}
499
500//===== ConfigurationController::Implementation ===============================
501
503 ConfigurationController& rController,
504 const rtl::Reference<::sd::DrawController>& rxController)
505 : mxControllerManager(rxController, UNO_QUERY_THROW),
506 mpBroadcaster(std::make_shared<ConfigurationControllerBroadcaster>(&rController)),
507 mxRequestedConfiguration(new Configuration(&rController, true)),
508 mpResourceFactoryContainer(std::make_shared<ResourceFactoryManager>(mxControllerManager)),
509 mpResourceManager(
510 std::make_shared<ConfigurationControllerResourceManager>(mpResourceFactoryContainer,mpBroadcaster)),
511 mpConfigurationUpdater(
512 std::make_shared<ConfigurationUpdater>(mpBroadcaster, mpResourceManager,mxControllerManager)),
513 mpQueueProcessor(new ChangeRequestQueueProcessor(mpConfigurationUpdater)),
514 mnLockCount(0)
515{
517}
518
519} // end of namespace sd::framework
520
521
522/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AnyEventRef aEvent
mutable::osl::Mutex m_aMutex
The ChangeRequestQueueProcessor owns the ChangeRequestQueue and processes the configuration change re...
A ConfigurationClassifier object compares two configurations of resources and gives access to the dif...
const ResourceIdVector & GetC2minusC1() const
Return the resources that belong to the configuration given as rxConfiguration2 to the constructor bu...
const ResourceIdVector & GetC1minusC2() const
Return the resources that belong to the configuration given as rxConfiguration1 to the constructor bu...
bool Partition()
Calculate three lists of resource ids.
::std::vector< css::uno::Reference< css::drawing::framework::XResourceId > > ResourceIdVector
This class manages the set of XConfigurationChangeListeners and calls them when the ConfigurationCont...
For every active resource both the resource itself as well as its creating factory are remembered,...
std::shared_ptr< ConfigurationControllerResourceManager > mpResourceManager
std::shared_ptr< ConfigurationUpdater > mpConfigurationUpdater
css::uno::Reference< css::drawing::framework::XConfiguration > mxRequestedConfiguration
The requested configuration which is modified (asynchronously) by calls to requestResourceActivation(...
std::shared_ptr< ConfigurationControllerBroadcaster > mpBroadcaster
The Broadcaster class implements storing and calling of listeners.
std::shared_ptr< ConfigurationUpdaterLock > mpConfigurationUpdaterLock
std::unique_ptr< ChangeRequestQueueProcessor > mpQueueProcessor
The queue processor owns the queue of configuration change request objects and processes the objects.
Implementation(ConfigurationController &rController, const rtl::Reference<::sd::DrawController > &rxController)
std::shared_ptr< ResourceFactoryManager > mpResourceFactoryContainer
Lock(const css::uno::Reference< css::drawing::framework::XConfigurationController > &rxController)
css::uno::Reference< css::drawing::framework::XConfigurationController > mxController
The configuration controller is responsible for maintaining the current configuration.
std::unique_ptr< Implementation > mpImplementation
virtual void SAL_CALL requestResourceDeactivation(const css::uno::Reference< css::drawing::framework::XResourceId > &rxResourceId) override
virtual void SAL_CALL addResourceFactory(const OUString &sResourceURL, const css::uno::Reference< css::drawing::framework::XResourceFactory > &rxResourceFactory) override
void ThrowIfDisposed() const
When the called object has already been disposed this method throws an exception and does not return.
void RequestSynchronousUpdate()
Normally the requested changes of the configuration are executed asynchronously.
virtual void SAL_CALL postChangeRequest(const css::uno::Reference< css::drawing::framework::XConfigurationChangeRequest > &rxRequest) override
virtual void SAL_CALL disposing() override
virtual css::uno::Reference< css::drawing::framework::XConfiguration > SAL_CALL getCurrentConfiguration() override
virtual css::uno::Reference< css::drawing::framework::XResourceFactory > SAL_CALL getResourceFactory(const OUString &sResourceURL) override
ConfigurationController(const rtl::Reference<::sd::DrawController > &rxController)
virtual ~ConfigurationController() noexcept override
virtual void SAL_CALL addConfigurationChangeListener(const css::uno::Reference< css::drawing::framework::XConfigurationChangeListener > &rxListener, const OUString &rsEventType, const css::uno::Any &rUserData) override
virtual void SAL_CALL restoreConfiguration(const css::uno::Reference< css::drawing::framework::XConfiguration > &rxConfiguration) override
The given configuration is restored by generating the appropriate set of activation and deactivation ...
virtual void SAL_CALL removeResourceFactoryForReference(const css::uno::Reference< css::drawing::framework::XResourceFactory > &rxResourceFactory) override
virtual void SAL_CALL removeResourceFactoryForURL(const OUString &sResourceURL) override
virtual css::uno::Reference< css::drawing::framework::XConfiguration > SAL_CALL getRequestedConfiguration() override
virtual void SAL_CALL removeConfigurationChangeListener(const css::uno::Reference< css::drawing::framework::XConfigurationChangeListener > &rxListener) override
virtual void SAL_CALL notifyEvent(const css::drawing::framework::ConfigurationChangeEvent &rEvent) override
virtual css::uno::Reference< css::drawing::framework::XResource > SAL_CALL getResource(const css::uno::Reference< css::drawing::framework::XResourceId > &rxResourceId) override
virtual sal_Bool SAL_CALL hasPendingRequests() override
virtual void SAL_CALL requestResourceActivation(const css::uno::Reference< css::drawing::framework::XResourceId > &rxResourceId, css::drawing::framework::ResourceActivationMode eMode) override
static void TraceConfiguration(const css::uno::Reference< css::drawing::framework::XConfiguration > &rxConfiguration, const char *pMessage)
This is a helper class for the ConfigurationController.
A configuration describes the resources of an application like panes, views, and tool bars and their ...
static OUString ResourceIdToString(const css::uno::Reference< css::drawing::framework::XResourceId > &rxResourceId)
Return a string representation of the given XResourceId object.
This implementation of the XConfigurationChangeRequest interface represents a single explicit request...
Container of resource factories of the drawing framework.
This update request is used to request configuration updates asynchronous when no other requests are ...
Mode eMode
#define SAL_INFO(area, stream)
std::shared_ptr< T > make_shared(Args &&... args)
::cppu::WeakComponentImplHelper< css::drawing::framework::XConfigurationController > ConfigurationControllerInterfaceBase
unsigned char sal_Bool