1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <framework/ConfigurationController.hxx>
21 #include <framework/Configuration.hxx>
22 #include <framework/FrameworkHelper.hxx>
23 #include <DrawController.hxx>
24 #include "ConfigurationUpdater.hxx"
25 #include "ConfigurationControllerBroadcaster.hxx"
26 #include "ConfigurationTracer.hxx"
27 #include "GenericConfigurationChangeRequest.hxx"
28 #include "ConfigurationControllerResourceManager.hxx"
29 #include "ResourceFactoryManager.hxx"
30 #include "UpdateRequest.hxx"
31 #include "ChangeRequestQueueProcessor.hxx"
32 #include "ConfigurationClassifier.hxx"
33 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
34 #include <com/sun/star/frame/XController.hpp>
36 #include <sal/log.hxx>
37 #include <osl/mutex.hxx>
38 #include <vcl/svapp.hxx>
41 using namespace ::com::sun::star
;
42 using namespace ::com::sun::star::uno
;
43 using namespace ::com::sun::star::drawing::framework
;
44 using ::sd::framework::FrameworkHelper
;
46 namespace sd::framework
{
48 //----- ConfigurationController::Implementation -------------------------------
50 class ConfigurationController::Implementation
54 ConfigurationController
& rController
,
55 const rtl::Reference
<::sd::DrawController
>& rxController
);
57 rtl::Reference
<::sd::DrawController
> mxControllerManager
;
59 /** The Broadcaster class implements storing and calling of listeners.
61 std::shared_ptr
<ConfigurationControllerBroadcaster
> mpBroadcaster
;
63 /** The requested configuration which is modified (asynchronously) by
64 calls to requestResourceActivation() and
65 requestResourceDeactivation(). The mpConfigurationUpdater makes the
66 current configuration reflect the content of this one.
68 css::uno::Reference
<css::drawing::framework::XConfiguration
> mxRequestedConfiguration
;
70 std::shared_ptr
<ResourceFactoryManager
> mpResourceFactoryContainer
;
72 std::shared_ptr
<ConfigurationControllerResourceManager
> mpResourceManager
;
74 std::shared_ptr
<ConfigurationUpdater
> mpConfigurationUpdater
;
76 /** The queue processor owns the queue of configuration change request
77 objects and processes the objects.
79 std::unique_ptr
<ChangeRequestQueueProcessor
> mpQueueProcessor
;
81 std::shared_ptr
<ConfigurationUpdaterLock
> mpConfigurationUpdaterLock
;
83 sal_Int32 mnLockCount
;
86 //===== ConfigurationController::Lock =========================================
88 ConfigurationController::Lock::Lock (const Reference
<XConfigurationController
>& rxController
)
89 : mxController(rxController
)
91 OSL_ASSERT(mxController
.is());
93 if (mxController
.is())
97 ConfigurationController::Lock::~Lock()
99 if (mxController
.is())
100 mxController
->unlock();
103 //===== ConfigurationController ===============================================
105 ConfigurationController::ConfigurationController(const rtl::Reference
<::sd::DrawController
>& rxController
)
106 : ConfigurationControllerInterfaceBase(m_aMutex
)
107 , mbIsDisposed(false)
109 const SolarMutexGuard aSolarGuard
;
111 mpImplementation
.reset(new Implementation(
116 ConfigurationController::~ConfigurationController() noexcept
120 void SAL_CALL
ConfigurationController::disposing()
122 if (mpImplementation
== nullptr)
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");
134 // Now that all resources have been deactivated, mark the controller as
138 // Release the listeners.
139 lang::EventObject aEvent
;
140 aEvent
.Source
= uno::Reference
<uno::XInterface
>(static_cast<cppu::OWeakObject
*>(this));
143 const SolarMutexGuard aSolarGuard
;
144 mpImplementation
->mpBroadcaster
->DisposeAndClear();
147 mpImplementation
->mpQueueProcessor
.reset();
148 mpImplementation
->mxRequestedConfiguration
= nullptr;
149 mpImplementation
.reset();
152 void ConfigurationController::ProcessEvent()
154 if (mpImplementation
!= nullptr)
156 OSL_ASSERT(mpImplementation
->mpQueueProcessor
!= nullptr);
158 mpImplementation
->mpQueueProcessor
->ProcessOneEvent();
162 void ConfigurationController::RequestSynchronousUpdate()
164 if (mpImplementation
== nullptr)
166 if (mpImplementation
->mpQueueProcessor
== nullptr)
168 mpImplementation
->mpQueueProcessor
->ProcessUntilEmpty();
171 //----- XConfigurationControllerBroadcaster -----------------------------------
173 void SAL_CALL
ConfigurationController::addConfigurationChangeListener (
174 const Reference
<XConfigurationChangeListener
>& rxListener
,
175 const OUString
& rsEventType
,
176 const Any
& rUserData
)
178 ::osl::MutexGuard
aGuard (m_aMutex
);
181 OSL_ASSERT(mpImplementation
!= nullptr);
182 mpImplementation
->mpBroadcaster
->AddListener(rxListener
, rsEventType
, rUserData
);
185 void SAL_CALL
ConfigurationController::removeConfigurationChangeListener (
186 const Reference
<XConfigurationChangeListener
>& rxListener
)
188 ::osl::MutexGuard
aGuard (m_aMutex
);
191 mpImplementation
->mpBroadcaster
->RemoveListener(rxListener
);
194 void SAL_CALL
ConfigurationController::notifyEvent (
195 const ConfigurationChangeEvent
& rEvent
)
198 mpImplementation
->mpBroadcaster
->NotifyListeners(rEvent
);
201 //----- XConfigurationController ----------------------------------------------
203 void SAL_CALL
ConfigurationController::lock()
205 OSL_ASSERT(mpImplementation
!= nullptr);
206 OSL_ASSERT(mpImplementation
->mpConfigurationUpdater
!= nullptr);
208 ::osl::MutexGuard
aGuard (m_aMutex
);
211 ++mpImplementation
->mnLockCount
;
212 if (mpImplementation
->mpConfigurationUpdaterLock
== nullptr)
213 mpImplementation
->mpConfigurationUpdaterLock
214 = mpImplementation
->mpConfigurationUpdater
->GetLock();
217 void SAL_CALL
ConfigurationController::unlock()
219 ::osl::MutexGuard
aGuard (m_aMutex
);
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
)
226 OSL_ASSERT(mpImplementation
->mnLockCount
>0);
227 --mpImplementation
->mnLockCount
;
228 if (mpImplementation
->mnLockCount
== 0)
229 mpImplementation
->mpConfigurationUpdaterLock
.reset();
232 void SAL_CALL
ConfigurationController::requestResourceActivation (
233 const Reference
<XResourceId
>& rxResourceId
,
234 ResourceActivationMode eMode
)
236 ::osl::MutexGuard
aGuard (m_aMutex
);
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
)
246 SAL_INFO("sd.fwk", __func__
<< ": ConfigurationController::requestResourceActivation(): ignoring " <<
247 FrameworkHelper::ResourceIdToString(rxResourceId
));
251 SAL_INFO("sd.fwk", __func__
<< ": ConfigurationController::requestResourceActivation() " <<
252 FrameworkHelper::ResourceIdToString(rxResourceId
));
254 if (!rxResourceId
.is())
257 if (eMode
== ResourceActivationMode_REPLACE
)
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
));
267 for (const auto& rResource
: aResourceList
)
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)
275 // Request the deactivation of a resource and all resources
277 requestResourceDeactivation(rResource
);
281 Reference
<XConfigurationChangeRequest
> xRequest(
282 new GenericConfigurationChangeRequest(
284 GenericConfigurationChangeRequest::Activation
));
285 postChangeRequest(xRequest
);
288 void SAL_CALL
ConfigurationController::requestResourceDeactivation (
289 const Reference
<XResourceId
>& rxResourceId
)
291 ::osl::MutexGuard
aGuard (m_aMutex
);
294 SAL_INFO("sd.fwk", __func__
<< ": ConfigurationController::requestResourceDeactivation() " <<
295 FrameworkHelper::ResourceIdToString(rxResourceId
));
297 if (!rxResourceId
.is())
300 // Request deactivation of all resources linked to the specified one
302 const Sequence
<Reference
<XResourceId
> > aLinkedResources (
303 mpImplementation
->mxRequestedConfiguration
->getResources(
306 AnchorBindingMode_DIRECT
));
307 for (const auto& rLinkedResource
: aLinkedResources
)
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
);
315 // Add a deactivation request for the specified resource.
316 Reference
<XConfigurationChangeRequest
> xRequest(
317 new GenericConfigurationChangeRequest(
319 GenericConfigurationChangeRequest::Deactivation
));
320 postChangeRequest(xRequest
);
323 Reference
<XResource
> SAL_CALL
ConfigurationController::getResource (
324 const Reference
<XResourceId
>& rxResourceId
)
326 ::osl::MutexGuard
aGuard (m_aMutex
);
329 ConfigurationControllerResourceManager::ResourceDescriptor
aDescriptor (
330 mpImplementation
->mpResourceManager
->GetResource(rxResourceId
));
331 return aDescriptor
.mxResource
;
334 void SAL_CALL
ConfigurationController::update()
336 ::osl::MutexGuard
aGuard (m_aMutex
);
339 if (mpImplementation
->mpQueueProcessor
->IsEmpty())
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());
347 // The queue is not empty, so we rely on the queue processor to
348 // request an update automatically when the queue becomes empty.
352 sal_Bool SAL_CALL
ConfigurationController::hasPendingRequests()
354 ::osl::MutexGuard
aGuard (m_aMutex
);
357 return ! mpImplementation
->mpQueueProcessor
->IsEmpty();
360 void SAL_CALL
ConfigurationController::postChangeRequest (
361 const Reference
<XConfigurationChangeRequest
>& rxRequest
)
363 ::osl::MutexGuard
aGuard (m_aMutex
);
366 mpImplementation
->mpQueueProcessor
->AddRequest(rxRequest
);
369 Reference
<XConfiguration
> SAL_CALL
ConfigurationController::getRequestedConfiguration()
371 ::osl::MutexGuard
aGuard (m_aMutex
);
374 if (mpImplementation
->mxRequestedConfiguration
.is())
375 return Reference
<XConfiguration
>(
376 mpImplementation
->mxRequestedConfiguration
->createClone(), UNO_QUERY
);
378 return Reference
<XConfiguration
>();
381 Reference
<XConfiguration
> SAL_CALL
ConfigurationController::getCurrentConfiguration()
383 ::osl::MutexGuard
aGuard (m_aMutex
);
386 Reference
<XConfiguration
> xCurrentConfiguration(
387 mpImplementation
->mpConfigurationUpdater
->GetCurrentConfiguration());
388 if (xCurrentConfiguration
.is())
389 return Reference
<XConfiguration
>(xCurrentConfiguration
->createClone(), UNO_QUERY
);
391 return Reference
<XConfiguration
>();
394 /** The given configuration is restored by generating the appropriate set of
395 activation and deactivation requests.
397 void SAL_CALL
ConfigurationController::restoreConfiguration (
398 const Reference
<XConfiguration
>& rxNewConfiguration
)
400 ::osl::MutexGuard
aGuard (m_aMutex
);
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());
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");
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());
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
)
433 requestResourceDeactivation(rxResource
);
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
)
442 requestResourceActivation(rxResource
, ResourceActivationMode_ADD
);
448 //----- XResourceFactoryManager -----------------------------------------------
450 void SAL_CALL
ConfigurationController::addResourceFactory(
451 const OUString
& sResourceURL
,
452 const Reference
<XResourceFactory
>& rxResourceFactory
)
454 ::osl::MutexGuard
aGuard (m_aMutex
);
456 mpImplementation
->mpResourceFactoryContainer
->AddFactory(sResourceURL
, rxResourceFactory
);
459 void SAL_CALL
ConfigurationController::removeResourceFactoryForURL(
460 const OUString
& sResourceURL
)
462 ::osl::MutexGuard
aGuard (m_aMutex
);
464 mpImplementation
->mpResourceFactoryContainer
->RemoveFactoryForURL(sResourceURL
);
467 void SAL_CALL
ConfigurationController::removeResourceFactoryForReference(
468 const Reference
<XResourceFactory
>& rxResourceFactory
)
470 ::osl::MutexGuard
aGuard (m_aMutex
);
472 mpImplementation
->mpResourceFactoryContainer
->RemoveFactoryForReference(rxResourceFactory
);
475 Reference
<XResourceFactory
> SAL_CALL
ConfigurationController::getResourceFactory (
476 const OUString
& sResourceURL
)
478 ::osl::MutexGuard
aGuard (m_aMutex
);
481 return mpImplementation
->mpResourceFactoryContainer
->GetFactory(sResourceURL
);
484 void ConfigurationController::ThrowIfDisposed () const
488 throw lang::DisposedException ("ConfigurationController object has already been disposed",
489 const_cast<uno::XWeak
*>(static_cast<const uno::XWeak
*>(this)));
492 if (mpImplementation
== nullptr)
494 OSL_ASSERT(mpImplementation
!= nullptr);
495 throw RuntimeException("ConfigurationController not initialized",
496 const_cast<uno::XWeak
*>(static_cast<const uno::XWeak
*>(this)));
500 //===== ConfigurationController::Implementation ===============================
502 ConfigurationController::Implementation::Implementation (
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
)),
510 std::make_shared
<ConfigurationControllerResourceManager
>(mpResourceFactoryContainer
,mpBroadcaster
)),
511 mpConfigurationUpdater(
512 std::make_shared
<ConfigurationUpdater
>(mpBroadcaster
, mpResourceManager
,mxControllerManager
)),
513 mpQueueProcessor(new ChangeRequestQueueProcessor(mpConfigurationUpdater
)),
516 mpQueueProcessor
->SetConfiguration(mxRequestedConfiguration
);
519 } // end of namespace sd::framework
522 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */