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 "ConfigurationUpdater.hxx"
24 #include "ConfigurationControllerBroadcaster.hxx"
25 #include "ConfigurationTracer.hxx"
26 #include "GenericConfigurationChangeRequest.hxx"
27 #include "ResourceFactoryManager.hxx"
28 #include "UpdateRequest.hxx"
29 #include "ChangeRequestQueueProcessor.hxx"
30 #include "ConfigurationClassifier.hxx"
31 #include "ViewShellBase.hxx"
32 #include "DrawController.hxx"
34 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
35 #include <com/sun/star/util/XURLTransformer.hpp>
37 #include <osl/mutex.hxx>
38 #include <vcl/svapp.hxx>
40 using namespace ::com::sun::star
;
41 using namespace ::com::sun::star::uno
;
42 using namespace ::com::sun::star::drawing::framework
;
43 using ::sd::framework::FrameworkHelper
;
45 namespace sd
{ namespace framework
{
47 //----- ConfigurationController::Implementation -------------------------------
49 class ConfigurationController::Implementation
53 ConfigurationController
& rController
,
54 const Reference
<frame::XController
>& rxController
);
57 Reference
<XControllerManager
> mxControllerManager
;
59 /** The Broadcaster class implements storing and calling of listeners.
61 ::boost::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 ::com::sun::star::uno::Reference
<
69 ::com::sun::star::drawing::framework::XConfiguration
> mxRequestedConfiguration
;
71 ViewShellBase
* mpBase
;
73 ::boost::shared_ptr
<ResourceFactoryManager
> mpResourceFactoryContainer
;
75 ::boost::shared_ptr
<ConfigurationControllerResourceManager
> mpResourceManager
;
77 ::boost::shared_ptr
<ConfigurationUpdater
> mpConfigurationUpdater
;
79 /** The queue processor ownes the queue of configuration change request
80 objects and processes the objects.
82 ::boost::scoped_ptr
<ChangeRequestQueueProcessor
> mpQueueProcessor
;
84 ::boost::shared_ptr
<ConfigurationUpdaterLock
> mpConfigurationUpdaterLock
;
86 sal_Int32 mnLockCount
;
89 //===== ConfigurationController::Lock =========================================
91 ConfigurationController::Lock::Lock (const Reference
<XConfigurationController
>& rxController
)
92 : mxController(rxController
)
94 OSL_ASSERT(mxController
.is());
96 if (mxController
.is())
100 ConfigurationController::Lock::~Lock()
102 if (mxController
.is())
103 mxController
->unlock();
106 //===== ConfigurationController ===============================================
108 ConfigurationController::ConfigurationController() throw()
109 : ConfigurationControllerInterfaceBase(MutexOwner::maMutex
)
111 , mbIsDisposed(false)
115 ConfigurationController::~ConfigurationController() throw()
119 void SAL_CALL
ConfigurationController::disposing()
121 if (mpImplementation
.get() == NULL
)
124 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": ConfigurationController::disposing");
125 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": requesting empty configuration");
126 // To destroy all resources an empty configuration is requested and then,
127 // synchronously, all resulting requests are processed.
128 mpImplementation
->mpQueueProcessor
->Clear();
129 restoreConfiguration(new Configuration(this,false));
130 mpImplementation
->mpQueueProcessor
->ProcessUntilEmpty();
131 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": all requests processed");
133 // Now that all resources have been deactivated, mark the controller as
137 // Release the listeners.
138 lang::EventObject aEvent
;
139 aEvent
.Source
= uno::Reference
<uno::XInterface
>((cppu::OWeakObject
*)this);
142 const SolarMutexGuard aSolarGuard
;
143 mpImplementation
->mpBroadcaster
->DisposeAndClear();
146 mpImplementation
->mpQueueProcessor
.reset();
147 mpImplementation
->mxRequestedConfiguration
= NULL
;
148 mpImplementation
.reset();
151 void ConfigurationController::ProcessEvent()
153 if (mpImplementation
.get() != NULL
)
155 OSL_ASSERT(mpImplementation
->mpQueueProcessor
.get()!=NULL
);
157 mpImplementation
->mpQueueProcessor
->ProcessOneEvent();
161 void ConfigurationController::RequestSynchronousUpdate()
163 if (mpImplementation
.get() == NULL
)
165 if (mpImplementation
->mpQueueProcessor
.get() == 0)
167 mpImplementation
->mpQueueProcessor
->ProcessUntilEmpty();
170 //----- XConfigurationControllerBroadcaster -----------------------------------
172 void SAL_CALL
ConfigurationController::addConfigurationChangeListener (
173 const Reference
<XConfigurationChangeListener
>& rxListener
,
174 const OUString
& rsEventType
,
175 const Any
& rUserData
)
176 throw (RuntimeException
, std::exception
)
178 ::osl::MutexGuard
aGuard (maMutex
);
181 OSL_ASSERT(mpImplementation
.get()!=NULL
);
182 mpImplementation
->mpBroadcaster
->AddListener(rxListener
, rsEventType
, rUserData
);
185 void SAL_CALL
ConfigurationController::removeConfigurationChangeListener (
186 const Reference
<XConfigurationChangeListener
>& rxListener
)
187 throw (RuntimeException
, std::exception
)
189 ::osl::MutexGuard
aGuard (maMutex
);
192 mpImplementation
->mpBroadcaster
->RemoveListener(rxListener
);
195 void SAL_CALL
ConfigurationController::notifyEvent (
196 const ConfigurationChangeEvent
& rEvent
)
197 throw (RuntimeException
, std::exception
)
200 mpImplementation
->mpBroadcaster
->NotifyListeners(rEvent
);
203 //----- XConfigurationController ----------------------------------------------
205 void SAL_CALL
ConfigurationController::lock()
206 throw (RuntimeException
, std::exception
)
208 OSL_ASSERT(mpImplementation
.get()!=NULL
);
209 OSL_ASSERT(mpImplementation
->mpConfigurationUpdater
.get()!=NULL
);
211 ::osl::MutexGuard
aGuard (maMutex
);
214 ++mpImplementation
->mnLockCount
;
215 if (mpImplementation
->mpConfigurationUpdaterLock
.get()==NULL
)
216 mpImplementation
->mpConfigurationUpdaterLock
217 = mpImplementation
->mpConfigurationUpdater
->GetLock();
220 void SAL_CALL
ConfigurationController::unlock()
221 throw (RuntimeException
, std::exception
)
223 ::osl::MutexGuard
aGuard (maMutex
);
225 // Allow unlocking while the ConfigurationController is being disposed
226 // (but not when that is done and the controller is disposed.)
227 if (rBHelper
.bDisposed
)
230 OSL_ASSERT(mpImplementation
->mnLockCount
>0);
231 --mpImplementation
->mnLockCount
;
232 if (mpImplementation
->mnLockCount
== 0)
233 mpImplementation
->mpConfigurationUpdaterLock
.reset();
236 void SAL_CALL
ConfigurationController::requestResourceActivation (
237 const Reference
<XResourceId
>& rxResourceId
,
238 ResourceActivationMode eMode
)
239 throw (RuntimeException
, std::exception
)
241 ::osl::MutexGuard
aGuard (maMutex
);
244 // Check whether we are being disposed. This is handled differently
245 // then being completely disposed because the first thing disposing()
246 // does is to deactivate all remaining resources. This is done via
247 // regular methods which must not throw DisposedExceptions. Therefore
248 // we just return silently during that stage.
249 if (rBHelper
.bInDispose
)
251 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": ConfigurationController::requestResourceActivation(): ignoring " <<
253 FrameworkHelper::ResourceIdToString(rxResourceId
), RTL_TEXTENCODING_UTF8
).getStr());
257 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": ConfigurationController::requestResourceActivation() " <<
259 FrameworkHelper::ResourceIdToString(rxResourceId
), RTL_TEXTENCODING_UTF8
).getStr());
261 if (rxResourceId
.is())
263 if (eMode
== ResourceActivationMode_REPLACE
)
265 // Get a list of the matching resources and create deactivation
266 // requests for them.
267 Sequence
<Reference
<XResourceId
> > aResourceList (
268 mpImplementation
->mxRequestedConfiguration
->getResources(
269 rxResourceId
->getAnchor(),
270 rxResourceId
->getResourceTypePrefix(),
271 AnchorBindingMode_DIRECT
));
273 for (sal_Int32 nIndex
=0; nIndex
<aResourceList
.getLength(); ++nIndex
)
275 // Do not request the deactivation of the resource for which
276 // this method was called. Doing it would not change the
277 // outcome but would result in unnecessary work.
278 if (rxResourceId
->compareTo(aResourceList
[nIndex
]) == 0)
281 // Request the deactivation of a resource and all resources
283 requestResourceDeactivation(aResourceList
[nIndex
]);
287 Reference
<XConfigurationChangeRequest
> xRequest(
288 new GenericConfigurationChangeRequest(
290 GenericConfigurationChangeRequest::Activation
));
291 postChangeRequest(xRequest
);
295 void SAL_CALL
ConfigurationController::requestResourceDeactivation (
296 const Reference
<XResourceId
>& rxResourceId
)
297 throw (RuntimeException
, std::exception
)
299 ::osl::MutexGuard
aGuard (maMutex
);
302 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": ConfigurationController::requestResourceDeactivation() " <<
304 FrameworkHelper::ResourceIdToString(rxResourceId
), RTL_TEXTENCODING_UTF8
).getStr());
306 if (rxResourceId
.is())
308 // Request deactivation of all resources linked to the specified one
310 const Sequence
<Reference
<XResourceId
> > aLinkedResources (
311 mpImplementation
->mxRequestedConfiguration
->getResources(
314 AnchorBindingMode_DIRECT
));
315 const sal_Int32
nCount (aLinkedResources
.getLength());
316 for (sal_Int32 nIndex
=0; nIndex
<nCount
; ++nIndex
)
318 // We do not add deactivation requests directly but call this
319 // method recursively, so that when one time there are resources
320 // linked to linked resources, these are handled correctly, too.
321 requestResourceDeactivation(aLinkedResources
[nIndex
]);
324 // Add a deactivation request for the specified resource.
325 Reference
<XConfigurationChangeRequest
> xRequest(
326 new GenericConfigurationChangeRequest(
328 GenericConfigurationChangeRequest::Deactivation
));
329 postChangeRequest(xRequest
);
333 Reference
<XResource
> SAL_CALL
ConfigurationController::getResource (
334 const Reference
<XResourceId
>& rxResourceId
)
335 throw (RuntimeException
, std::exception
)
337 ::osl::MutexGuard
aGuard (maMutex
);
340 ConfigurationControllerResourceManager::ResourceDescriptor
aDescriptor (
341 mpImplementation
->mpResourceManager
->GetResource(rxResourceId
));
342 return aDescriptor
.mxResource
;
345 void SAL_CALL
ConfigurationController::update()
346 throw (RuntimeException
, std::exception
)
348 ::osl::MutexGuard
aGuard (maMutex
);
351 if (mpImplementation
->mpQueueProcessor
->IsEmpty())
353 // The queue is empty. Add another request that does nothing but
354 // asynchronously trigger a request for an update.
355 mpImplementation
->mpQueueProcessor
->AddRequest(new UpdateRequest());
359 // The queue is not empty, so we rely on the queue processor to
360 // request an update automatically when the queue becomes empty.
364 sal_Bool SAL_CALL
ConfigurationController::hasPendingRequests()
365 throw (RuntimeException
, std::exception
)
367 ::osl::MutexGuard
aGuard (maMutex
);
370 return ! mpImplementation
->mpQueueProcessor
->IsEmpty();
373 void SAL_CALL
ConfigurationController::postChangeRequest (
374 const Reference
<XConfigurationChangeRequest
>& rxRequest
)
375 throw (RuntimeException
, std::exception
)
377 ::osl::MutexGuard
aGuard (maMutex
);
380 mpImplementation
->mpQueueProcessor
->AddRequest(rxRequest
);
383 Reference
<XConfiguration
> SAL_CALL
ConfigurationController::getRequestedConfiguration()
384 throw (RuntimeException
, std::exception
)
386 ::osl::MutexGuard
aGuard (maMutex
);
389 if (mpImplementation
->mxRequestedConfiguration
.is())
390 return Reference
<XConfiguration
>(
391 mpImplementation
->mxRequestedConfiguration
->createClone(), UNO_QUERY
);
393 return Reference
<XConfiguration
>();
396 Reference
<XConfiguration
> SAL_CALL
ConfigurationController::getCurrentConfiguration()
397 throw (RuntimeException
, std::exception
)
399 ::osl::MutexGuard
aGuard (maMutex
);
402 Reference
<XConfiguration
> xCurrentConfiguration(
403 mpImplementation
->mpConfigurationUpdater
->GetCurrentConfiguration());
404 if (xCurrentConfiguration
.is())
405 return Reference
<XConfiguration
>(xCurrentConfiguration
->createClone(), UNO_QUERY
);
407 return Reference
<XConfiguration
>();
410 /** The given configuration is restored by generating the appropriate set of
411 activation and deactivation requests.
413 void SAL_CALL
ConfigurationController::restoreConfiguration (
414 const Reference
<XConfiguration
>& rxNewConfiguration
)
415 throw (RuntimeException
, std::exception
)
417 ::osl::MutexGuard
aGuard (maMutex
);
420 // We will probably be making a couple of activation and deactivation
421 // requests so lock the configuration controller and let it later update
422 // all changes at once.
423 ::boost::shared_ptr
<ConfigurationUpdaterLock
> pLock (
424 mpImplementation
->mpConfigurationUpdater
->GetLock());
426 // Get lists of resources that are to be activated or deactivated.
427 Reference
<XConfiguration
> xCurrentConfiguration (mpImplementation
->mxRequestedConfiguration
);
428 #if OSL_DEBUG_LEVEL >=1
429 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": ConfigurationController::restoreConfiguration(");
430 ConfigurationTracer::TraceConfiguration(rxNewConfiguration
, "requested configuration");
431 ConfigurationTracer::TraceConfiguration(xCurrentConfiguration
, "current configuration");
433 ConfigurationClassifier
aClassifier (rxNewConfiguration
, xCurrentConfiguration
);
434 aClassifier
.Partition();
435 #if OSL_DEBUG_LEVEL >=2
436 aClassifier
.TraceResourceIdVector(
437 "requested but not current resources:\n", aClassifier
.GetC1minusC2());
438 aClassifier
.TraceResourceIdVector(
439 "current but not requested resources:\n", aClassifier
.GetC2minusC1());
440 aClassifier
.TraceResourceIdVector(
441 "requested and current resources:\n", aClassifier
.GetC1andC2());
444 ConfigurationClassifier::ResourceIdVector::const_iterator iResource
;
446 // Request the deactivation of resources that are not requested in the
447 // new configuration.
448 const ConfigurationClassifier::ResourceIdVector
& rResourcesToDeactivate (
449 aClassifier
.GetC2minusC1());
450 for (iResource
=rResourcesToDeactivate
.begin();
451 iResource
!=rResourcesToDeactivate
.end();
454 requestResourceDeactivation(*iResource
);
457 // Request the activation of resources that are requested in the
458 // new configuration but are not part of the current configuration.
459 const ConfigurationClassifier::ResourceIdVector
& rResourcesToActivate (
460 aClassifier
.GetC1minusC2());
461 for (iResource
=rResourcesToActivate
.begin();
462 iResource
!=rResourcesToActivate
.end();
465 requestResourceActivation(*iResource
, ResourceActivationMode_ADD
);
471 //----- XResourceFactoryManager -----------------------------------------------
473 void SAL_CALL
ConfigurationController::addResourceFactory(
474 const OUString
& sResourceURL
,
475 const Reference
<XResourceFactory
>& rxResourceFactory
)
476 throw (RuntimeException
, std::exception
)
478 ::osl::MutexGuard
aGuard (maMutex
);
480 mpImplementation
->mpResourceFactoryContainer
->AddFactory(sResourceURL
, rxResourceFactory
);
483 void SAL_CALL
ConfigurationController::removeResourceFactoryForURL(
484 const OUString
& sResourceURL
)
485 throw (RuntimeException
, std::exception
)
487 ::osl::MutexGuard
aGuard (maMutex
);
489 mpImplementation
->mpResourceFactoryContainer
->RemoveFactoryForURL(sResourceURL
);
492 void SAL_CALL
ConfigurationController::removeResourceFactoryForReference(
493 const Reference
<XResourceFactory
>& rxResourceFactory
)
494 throw (RuntimeException
, std::exception
)
496 ::osl::MutexGuard
aGuard (maMutex
);
498 mpImplementation
->mpResourceFactoryContainer
->RemoveFactoryForReference(rxResourceFactory
);
501 Reference
<XResourceFactory
> SAL_CALL
ConfigurationController::getResourceFactory (
502 const OUString
& sResourceURL
)
503 throw (RuntimeException
, std::exception
)
505 ::osl::MutexGuard
aGuard (maMutex
);
508 return mpImplementation
->mpResourceFactoryContainer
->GetFactory(sResourceURL
);
511 //----- XInitialization -------------------------------------------------------
513 void SAL_CALL
ConfigurationController::initialize (const Sequence
<Any
>& aArguments
)
514 throw (Exception
, RuntimeException
, std::exception
)
516 ::osl::MutexGuard
aGuard (maMutex
);
518 if (aArguments
.getLength() == 1)
520 const SolarMutexGuard aSolarGuard
;
522 mpImplementation
.reset(new Implementation(
524 Reference
<frame::XController
>(aArguments
[0], UNO_QUERY_THROW
)));
528 void ConfigurationController::ThrowIfDisposed () const
529 throw (css::lang::DisposedException
, css::uno::RuntimeException
)
533 throw lang::DisposedException ("ConfigurationController object has already been disposed",
534 const_cast<uno::XWeak
*>(static_cast<const uno::XWeak
*>(this)));
537 if (mpImplementation
.get() == NULL
)
539 OSL_ASSERT(mpImplementation
.get() != NULL
);
540 throw RuntimeException("ConfigurationController not initialized",
541 const_cast<uno::XWeak
*>(static_cast<const uno::XWeak
*>(this)));
545 //===== ConfigurationController::Implementation ===============================
547 ConfigurationController::Implementation::Implementation (
548 ConfigurationController
& rController
,
549 const Reference
<frame::XController
>& rxController
)
550 : mxControllerManager(rxController
, UNO_QUERY_THROW
),
551 mpBroadcaster(new ConfigurationControllerBroadcaster(&rController
)),
552 mxRequestedConfiguration(new Configuration(&rController
, true)),
554 mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager
)),
556 new ConfigurationControllerResourceManager(mpResourceFactoryContainer
,mpBroadcaster
)),
557 mpConfigurationUpdater(
558 new ConfigurationUpdater(mpBroadcaster
, mpResourceManager
,mxControllerManager
)),
559 mpQueueProcessor(new ChangeRequestQueueProcessor(&rController
,mpConfigurationUpdater
)),
560 mpConfigurationUpdaterLock(),
563 mpQueueProcessor
->SetConfiguration(mxRequestedConfiguration
);
566 ConfigurationController::Implementation::~Implementation()
570 } } // end of namespace sd::framework
573 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface
* SAL_CALL
574 com_sun_star_comp_Draw_framework_configuration_ConfigurationController_get_implementation(
575 ::com::sun::star::uno::XComponentContext
*,
576 ::com::sun::star::uno::Sequence
<css::uno::Any
> const &)
578 return cppu::acquire(new sd::framework::ConfigurationController());
582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */