bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / framework / configuration / ConfigurationController.cxx
blobe2ecae03f79d95823e83a6f8a78f741fbb656d58
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/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"
33 #include "facreg.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
51 public:
52 Implementation (
53 ConfigurationController& rController,
54 const Reference<frame::XController>& rxController);
55 ~Implementation();
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())
97 mxController->lock();
100 ConfigurationController::Lock::~Lock()
102 if (mxController.is())
103 mxController->unlock();
106 //===== ConfigurationController ===============================================
108 ConfigurationController::ConfigurationController() throw()
109 : ConfigurationControllerInterfaceBase(MutexOwner::maMutex)
110 , mpImplementation()
111 , mbIsDisposed(false)
115 ConfigurationController::~ConfigurationController() throw()
119 void SAL_CALL ConfigurationController::disposing()
121 if (mpImplementation.get() == NULL)
122 return;
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
134 // disposed.
135 mbIsDisposed = true;
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)
164 return;
165 if (mpImplementation->mpQueueProcessor.get() == 0)
166 return;
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);
180 ThrowIfDisposed();
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);
191 ThrowIfDisposed();
192 mpImplementation->mpBroadcaster->RemoveListener(rxListener);
195 void SAL_CALL ConfigurationController::notifyEvent (
196 const ConfigurationChangeEvent& rEvent)
197 throw (RuntimeException, std::exception)
199 ThrowIfDisposed();
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);
212 ThrowIfDisposed();
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)
228 ThrowIfDisposed();
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);
242 ThrowIfDisposed();
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 " <<
252 OUStringToOString(
253 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr());
254 return;
257 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationController::requestResourceActivation() " <<
258 OUStringToOString(
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)
279 continue;
281 // Request the deactivation of a resource and all resources
282 // linked to it.
283 requestResourceDeactivation(aResourceList[nIndex]);
287 Reference<XConfigurationChangeRequest> xRequest(
288 new GenericConfigurationChangeRequest(
289 rxResourceId,
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);
300 ThrowIfDisposed();
302 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationController::requestResourceDeactivation() " <<
303 OUStringToOString(
304 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr());
306 if (rxResourceId.is())
308 // Request deactivation of all resources linked to the specified one
309 // as well.
310 const Sequence<Reference<XResourceId> > aLinkedResources (
311 mpImplementation->mxRequestedConfiguration->getResources(
312 rxResourceId,
313 OUString(),
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(
327 rxResourceId,
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);
338 ThrowIfDisposed();
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);
349 ThrowIfDisposed();
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());
357 else
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);
368 ThrowIfDisposed();
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);
378 ThrowIfDisposed();
380 mpImplementation->mpQueueProcessor->AddRequest(rxRequest);
383 Reference<XConfiguration> SAL_CALL ConfigurationController::getRequestedConfiguration()
384 throw (RuntimeException, std::exception)
386 ::osl::MutexGuard aGuard (maMutex);
387 ThrowIfDisposed();
389 if (mpImplementation->mxRequestedConfiguration.is())
390 return Reference<XConfiguration>(
391 mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY);
392 else
393 return Reference<XConfiguration>();
396 Reference<XConfiguration> SAL_CALL ConfigurationController::getCurrentConfiguration()
397 throw (RuntimeException, std::exception)
399 ::osl::MutexGuard aGuard (maMutex);
400 ThrowIfDisposed();
402 Reference<XConfiguration> xCurrentConfiguration(
403 mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration());
404 if (xCurrentConfiguration.is())
405 return Reference<XConfiguration>(xCurrentConfiguration->createClone(), UNO_QUERY);
406 else
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);
418 ThrowIfDisposed();
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");
432 #endif
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());
442 #endif
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();
452 ++iResource)
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();
463 ++iResource)
465 requestResourceActivation(*iResource, ResourceActivationMode_ADD);
468 pLock.reset();
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);
479 ThrowIfDisposed();
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);
488 ThrowIfDisposed();
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);
497 ThrowIfDisposed();
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);
506 ThrowIfDisposed();
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(
523 *this,
524 Reference<frame::XController>(aArguments[0], UNO_QUERY_THROW)));
528 void ConfigurationController::ThrowIfDisposed () const
529 throw (css::lang::DisposedException, css::uno::RuntimeException)
531 if (mbIsDisposed)
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)),
553 mpBase(NULL),
554 mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager)),
555 mpResourceManager(
556 new ConfigurationControllerResourceManager(mpResourceFactoryContainer,mpBroadcaster)),
557 mpConfigurationUpdater(
558 new ConfigurationUpdater(mpBroadcaster, mpResourceManager,mxControllerManager)),
559 mpQueueProcessor(new ChangeRequestQueueProcessor(&rController,mpConfigurationUpdater)),
560 mpConfigurationUpdaterLock(),
561 mnLockCount(0)
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: */