bump product version to 4.1.6.2
[LibreOffice.git] / sd / source / ui / framework / configuration / ConfigurationController.cxx
blob275f1ab04553514617e63757a4ea4e5f237fcc5c
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 <com/sun/star/drawing/framework/XControllerManager.hpp>
34 #include <com/sun/star/util/XURLTransformer.hpp>
36 #include <comphelper/stl_types.hxx>
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 Reference<XInterface> SAL_CALL ConfigurationController_createInstance (
48 const Reference<XComponentContext>& rxContext)
50 (void)rxContext;
51 return static_cast<XWeak*>(new ConfigurationController());
57 OUString ConfigurationController_getImplementationName (void) throw(RuntimeException)
59 return OUString("com.sun.star.comp.Draw.framework.configuration.ConfigurationController");
65 Sequence<OUString> SAL_CALL ConfigurationController_getSupportedServiceNames (void)
66 throw (RuntimeException)
68 static const OUString sServiceName("com.sun.star.drawing.framework.ConfigurationController");
69 return Sequence<OUString>(&sServiceName, 1);
75 //----- ConfigurationController::Implementation -------------------------------
77 class ConfigurationController::Implementation
79 public:
80 Implementation (
81 ConfigurationController& rController,
82 const Reference<frame::XController>& rxController);
83 ~Implementation (void);
85 Reference<XControllerManager> mxControllerManager;
87 /** The Broadcaster class implements storing and calling of listeners.
89 ::boost::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster;
91 /** The requested configuration which is modifed (asynchronously) by
92 calls to requestResourceActivation() and
93 requestResourceDeactivation(). The mpConfigurationUpdater makes the
94 current configuration reflect the content of this one.
96 ::com::sun::star::uno::Reference<
97 ::com::sun::star::drawing::framework::XConfiguration> mxRequestedConfiguration;
99 ViewShellBase* mpBase;
101 ::boost::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer;
103 ::boost::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager;
105 ::boost::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater;
107 /** The queue processor ownes the queue of configuration change request
108 objects and processes the objects.
110 ::boost::scoped_ptr<ChangeRequestQueueProcessor> mpQueueProcessor;
112 ::boost::shared_ptr<ConfigurationUpdaterLock> mpConfigurationUpdaterLock;
114 sal_Int32 mnLockCount;
120 //===== ConfigurationController::Lock =========================================
122 ConfigurationController::Lock::Lock (const Reference<XConfigurationController>& rxController)
123 : mxController(rxController)
125 OSL_ASSERT(mxController.is());
127 if (mxController.is())
128 mxController->lock();
134 ConfigurationController::Lock::~Lock (void)
136 if (mxController.is())
137 mxController->unlock();
143 //===== ConfigurationController ===============================================
145 ConfigurationController::ConfigurationController (void) throw()
146 : ConfigurationControllerInterfaceBase(MutexOwner::maMutex)
147 , mpImplementation()
148 , mbIsDisposed(false)
152 ConfigurationController::~ConfigurationController (void) throw()
157 void SAL_CALL ConfigurationController::disposing (void)
159 if (mpImplementation.get() == NULL)
160 return;
162 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationController::disposing");
163 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": requesting empty configuration");
164 // To destroy all resources an empty configuration is requested and then,
165 // synchronously, all resulting requests are processed.
166 mpImplementation->mpQueueProcessor->Clear();
167 restoreConfiguration(new Configuration(this,false));
168 mpImplementation->mpQueueProcessor->ProcessUntilEmpty();
169 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": all requests processed");
171 // Now that all resources have been deactivated, mark the controller as
172 // disposed.
173 mbIsDisposed = true;
175 // Release the listeners.
176 lang::EventObject aEvent;
177 aEvent.Source = uno::Reference<uno::XInterface>((cppu::OWeakObject*)this);
180 const SolarMutexGuard aSolarGuard;
181 mpImplementation->mpBroadcaster->DisposeAndClear();
184 mpImplementation->mpQueueProcessor.reset();
185 mpImplementation->mxRequestedConfiguration = NULL;
186 mpImplementation.reset();
192 void ConfigurationController::ProcessEvent (void)
194 if (mpImplementation.get() != NULL)
196 OSL_ASSERT(mpImplementation->mpQueueProcessor.get()!=NULL);
198 mpImplementation->mpQueueProcessor->ProcessOneEvent();
205 void ConfigurationController::RequestSynchronousUpdate (void)
207 if (mpImplementation.get() == NULL)
208 return;
209 if (mpImplementation->mpQueueProcessor.get() == 0)
210 return;
211 mpImplementation->mpQueueProcessor->ProcessUntilEmpty();
217 //----- XConfigurationControllerBroadcaster -----------------------------------
219 void SAL_CALL ConfigurationController::addConfigurationChangeListener (
220 const Reference<XConfigurationChangeListener>& rxListener,
221 const OUString& rsEventType,
222 const Any& rUserData)
223 throw (RuntimeException)
225 ::osl::MutexGuard aGuard (maMutex);
227 ThrowIfDisposed();
228 OSL_ASSERT(mpImplementation.get()!=NULL);
229 mpImplementation->mpBroadcaster->AddListener(rxListener, rsEventType, rUserData);
235 void SAL_CALL ConfigurationController::removeConfigurationChangeListener (
236 const Reference<XConfigurationChangeListener>& rxListener)
237 throw (RuntimeException)
239 ::osl::MutexGuard aGuard (maMutex);
241 ThrowIfDisposed();
242 mpImplementation->mpBroadcaster->RemoveListener(rxListener);
248 void SAL_CALL ConfigurationController::notifyEvent (
249 const ConfigurationChangeEvent& rEvent)
250 throw (RuntimeException)
252 ThrowIfDisposed();
253 mpImplementation->mpBroadcaster->NotifyListeners(rEvent);
260 //----- XConfigurationController ----------------------------------------------
262 void SAL_CALL ConfigurationController::lock (void)
263 throw (RuntimeException)
265 OSL_ASSERT(mpImplementation.get()!=NULL);
266 OSL_ASSERT(mpImplementation->mpConfigurationUpdater.get()!=NULL);
268 ::osl::MutexGuard aGuard (maMutex);
269 ThrowIfDisposed();
272 ++mpImplementation->mnLockCount;
273 if (mpImplementation->mpConfigurationUpdaterLock.get()==NULL)
274 mpImplementation->mpConfigurationUpdaterLock
275 = mpImplementation->mpConfigurationUpdater->GetLock();
281 void SAL_CALL ConfigurationController::unlock (void)
282 throw (RuntimeException)
284 ::osl::MutexGuard aGuard (maMutex);
286 // Allow unlocking while the ConfigurationController is being disposed
287 // (but not when that is done and the controller is disposed.)
288 if (rBHelper.bDisposed)
289 ThrowIfDisposed();
291 OSL_ASSERT(mpImplementation->mnLockCount>0);
292 --mpImplementation->mnLockCount;
293 if (mpImplementation->mnLockCount == 0)
294 mpImplementation->mpConfigurationUpdaterLock.reset();
300 void SAL_CALL ConfigurationController::requestResourceActivation (
301 const Reference<XResourceId>& rxResourceId,
302 ResourceActivationMode eMode)
303 throw (RuntimeException)
305 ::osl::MutexGuard aGuard (maMutex);
306 ThrowIfDisposed();
308 // Check whether we are being disposed. This is handled differently
309 // then being completely disposed because the first thing disposing()
310 // does is to deactivate all remaining resources. This is done via
311 // regular methods which must not throw DisposedExceptions. Therefore
312 // we just return silently during that stage.
313 if (rBHelper.bInDispose)
315 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationController::requestResourceActivation(): ignoring " <<
316 OUStringToOString(
317 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr());
318 return;
321 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationController::requestResourceActivation() " <<
322 OUStringToOString(
323 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr());
325 if (rxResourceId.is())
327 if (eMode == ResourceActivationMode_REPLACE)
329 // Get a list of the matching resources and create deactivation
330 // requests for them.
331 Sequence<Reference<XResourceId> > aResourceList (
332 mpImplementation->mxRequestedConfiguration->getResources(
333 rxResourceId->getAnchor(),
334 rxResourceId->getResourceTypePrefix(),
335 AnchorBindingMode_DIRECT));
337 for (sal_Int32 nIndex=0; nIndex<aResourceList.getLength(); ++nIndex)
339 // Do not request the deactivation of the resource for which
340 // this method was called. Doing it would not change the
341 // outcome but would result in unnecessary work.
342 if (rxResourceId->compareTo(aResourceList[nIndex]) == 0)
343 continue;
345 // Request the deactivation of a resource and all resources
346 // linked to it.
347 requestResourceDeactivation(aResourceList[nIndex]);
351 Reference<XConfigurationChangeRequest> xRequest(
352 new GenericConfigurationChangeRequest(
353 rxResourceId,
354 GenericConfigurationChangeRequest::Activation));
355 postChangeRequest(xRequest);
362 void SAL_CALL ConfigurationController::requestResourceDeactivation (
363 const Reference<XResourceId>& rxResourceId)
364 throw (RuntimeException)
366 ::osl::MutexGuard aGuard (maMutex);
367 ThrowIfDisposed();
369 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationController::requestResourceDeactivation() " <<
370 OUStringToOString(
371 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr());
373 if (rxResourceId.is())
375 // Request deactivation of all resources linked to the specified one
376 // as well.
377 const Sequence<Reference<XResourceId> > aLinkedResources (
378 mpImplementation->mxRequestedConfiguration->getResources(
379 rxResourceId,
380 OUString(),
381 AnchorBindingMode_DIRECT));
382 const sal_Int32 nCount (aLinkedResources.getLength());
383 for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
385 // We do not add deactivation requests directly but call this
386 // method recursively, so that when one time there are resources
387 // linked to linked resources, these are handled correctly, too.
388 requestResourceDeactivation(aLinkedResources[nIndex]);
391 // Add a deactivation request for the specified resource.
392 Reference<XConfigurationChangeRequest> xRequest(
393 new GenericConfigurationChangeRequest(
394 rxResourceId,
395 GenericConfigurationChangeRequest::Deactivation));
396 postChangeRequest(xRequest);
403 Reference<XResource> SAL_CALL ConfigurationController::getResource (
404 const Reference<XResourceId>& rxResourceId)
405 throw (RuntimeException)
407 ::osl::MutexGuard aGuard (maMutex);
408 ThrowIfDisposed();
410 ConfigurationControllerResourceManager::ResourceDescriptor aDescriptor (
411 mpImplementation->mpResourceManager->GetResource(rxResourceId));
412 return aDescriptor.mxResource;
418 void SAL_CALL ConfigurationController::update (void)
419 throw (RuntimeException)
421 ::osl::MutexGuard aGuard (maMutex);
422 ThrowIfDisposed();
424 if (mpImplementation->mpQueueProcessor->IsEmpty())
426 // The queue is empty. Add another request that does nothing but
427 // asynchronously trigger a request for an update.
428 mpImplementation->mpQueueProcessor->AddRequest(new UpdateRequest());
430 else
432 // The queue is not empty, so we rely on the queue processor to
433 // request an update automatically when the queue becomes empty.
440 sal_Bool SAL_CALL ConfigurationController::hasPendingRequests (void)
441 throw (RuntimeException)
443 ::osl::MutexGuard aGuard (maMutex);
444 ThrowIfDisposed();
446 return ! mpImplementation->mpQueueProcessor->IsEmpty();
453 void SAL_CALL ConfigurationController::postChangeRequest (
454 const Reference<XConfigurationChangeRequest>& rxRequest)
455 throw (RuntimeException)
457 ::osl::MutexGuard aGuard (maMutex);
458 ThrowIfDisposed();
460 mpImplementation->mpQueueProcessor->AddRequest(rxRequest);
466 Reference<XConfiguration> SAL_CALL ConfigurationController::getRequestedConfiguration (void)
467 throw (RuntimeException)
469 ::osl::MutexGuard aGuard (maMutex);
470 ThrowIfDisposed();
472 if (mpImplementation->mxRequestedConfiguration.is())
473 return Reference<XConfiguration>(
474 mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY);
475 else
476 return Reference<XConfiguration>();
482 Reference<XConfiguration> SAL_CALL ConfigurationController::getCurrentConfiguration (void)
483 throw (RuntimeException)
485 ::osl::MutexGuard aGuard (maMutex);
486 ThrowIfDisposed();
488 Reference<XConfiguration> xCurrentConfiguration(
489 mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration());
490 if (xCurrentConfiguration.is())
491 return Reference<XConfiguration>(xCurrentConfiguration->createClone(), UNO_QUERY);
492 else
493 return Reference<XConfiguration>();
499 /** The given configuration is restored by generating the appropriate set of
500 activation and deactivation requests.
502 void SAL_CALL ConfigurationController::restoreConfiguration (
503 const Reference<XConfiguration>& rxNewConfiguration)
504 throw (RuntimeException)
506 ::osl::MutexGuard aGuard (maMutex);
507 ThrowIfDisposed();
509 // We will probably be making a couple of activation and deactivation
510 // requests so lock the configuration controller and let it later update
511 // all changes at once.
512 ::boost::shared_ptr<ConfigurationUpdaterLock> pLock (
513 mpImplementation->mpConfigurationUpdater->GetLock());
515 // Get lists of resources that are to be activated or deactivated.
516 Reference<XConfiguration> xCurrentConfiguration (mpImplementation->mxRequestedConfiguration);
517 #if OSL_DEBUG_LEVEL >=1
518 SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationController::restoreConfiguration(");
519 ConfigurationTracer::TraceConfiguration(rxNewConfiguration, "requested configuration");
520 ConfigurationTracer::TraceConfiguration(xCurrentConfiguration, "current configuration");
521 #endif
522 ConfigurationClassifier aClassifier (rxNewConfiguration, xCurrentConfiguration);
523 aClassifier.Partition();
524 #if OSL_DEBUG_LEVEL >=2
525 aClassifier.TraceResourceIdVector(
526 "requested but not current resources:\n", aClassifier.GetC1minusC2());
527 aClassifier.TraceResourceIdVector(
528 "current but not requested resources:\n", aClassifier.GetC2minusC1());
529 aClassifier.TraceResourceIdVector(
530 "requested and current resources:\n", aClassifier.GetC1andC2());
531 #endif
533 ConfigurationClassifier::ResourceIdVector::const_iterator iResource;
535 // Request the deactivation of resources that are not requested in the
536 // new configuration.
537 const ConfigurationClassifier::ResourceIdVector& rResourcesToDeactivate (
538 aClassifier.GetC2minusC1());
539 for (iResource=rResourcesToDeactivate.begin();
540 iResource!=rResourcesToDeactivate.end();
541 ++iResource)
543 requestResourceDeactivation(*iResource);
546 // Request the activation of resources that are requested in the
547 // new configuration but are not part of the current configuration.
548 const ConfigurationClassifier::ResourceIdVector& rResourcesToActivate (
549 aClassifier.GetC1minusC2());
550 for (iResource=rResourcesToActivate.begin();
551 iResource!=rResourcesToActivate.end();
552 ++iResource)
554 requestResourceActivation(*iResource, ResourceActivationMode_ADD);
557 pLock.reset();
563 //----- XResourceFactoryManager -----------------------------------------------
565 void SAL_CALL ConfigurationController::addResourceFactory(
566 const OUString& sResourceURL,
567 const Reference<XResourceFactory>& rxResourceFactory)
568 throw (RuntimeException)
570 ::osl::MutexGuard aGuard (maMutex);
571 ThrowIfDisposed();
572 mpImplementation->mpResourceFactoryContainer->AddFactory(sResourceURL, rxResourceFactory);
578 void SAL_CALL ConfigurationController::removeResourceFactoryForURL(
579 const OUString& sResourceURL)
580 throw (RuntimeException)
582 ::osl::MutexGuard aGuard (maMutex);
583 ThrowIfDisposed();
584 mpImplementation->mpResourceFactoryContainer->RemoveFactoryForURL(sResourceURL);
590 void SAL_CALL ConfigurationController::removeResourceFactoryForReference(
591 const Reference<XResourceFactory>& rxResourceFactory)
592 throw (RuntimeException)
594 ::osl::MutexGuard aGuard (maMutex);
595 ThrowIfDisposed();
596 mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory);
602 Reference<XResourceFactory> SAL_CALL ConfigurationController::getResourceFactory (
603 const OUString& sResourceURL)
604 throw (RuntimeException)
606 ::osl::MutexGuard aGuard (maMutex);
607 ThrowIfDisposed();
609 return mpImplementation->mpResourceFactoryContainer->GetFactory(sResourceURL);
615 //----- XInitialization -------------------------------------------------------
617 void SAL_CALL ConfigurationController::initialize (const Sequence<Any>& aArguments)
618 throw (Exception, RuntimeException)
620 ::osl::MutexGuard aGuard (maMutex);
622 if (aArguments.getLength() == 1)
624 const SolarMutexGuard aSolarGuard;
626 mpImplementation.reset(new Implementation(
627 *this,
628 Reference<frame::XController>(aArguments[0], UNO_QUERY_THROW)));
635 //-----------------------------------------------------------------------------
637 void ConfigurationController::ThrowIfDisposed (void) const
638 throw (::com::sun::star::lang::DisposedException)
640 if (mbIsDisposed)
642 throw lang::DisposedException ("ConfigurationController object has already been disposed",
643 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
646 if (mpImplementation.get() == NULL)
648 OSL_ASSERT(mpImplementation.get() != NULL);
649 throw RuntimeException("ConfigurationController not initialized",
650 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
657 //===== ConfigurationController::Implementation ===============================
659 ConfigurationController::Implementation::Implementation (
660 ConfigurationController& rController,
661 const Reference<frame::XController>& rxController)
662 : mxControllerManager(rxController, UNO_QUERY_THROW),
663 mpBroadcaster(new ConfigurationControllerBroadcaster(&rController)),
664 mxRequestedConfiguration(new Configuration(&rController, true)),
665 mpBase(NULL),
666 mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager)),
667 mpResourceManager(
668 new ConfigurationControllerResourceManager(mpResourceFactoryContainer,mpBroadcaster)),
669 mpConfigurationUpdater(
670 new ConfigurationUpdater(mpBroadcaster, mpResourceManager,mxControllerManager)),
671 mpQueueProcessor(new ChangeRequestQueueProcessor(&rController,mpConfigurationUpdater)),
672 mpConfigurationUpdaterLock(),
673 mnLockCount(0)
675 mpQueueProcessor->SetConfiguration(mxRequestedConfiguration);
681 ConfigurationController::Implementation::~Implementation (void)
688 } } // end of namespace sd::framework
690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */