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"
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
)
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
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
)
148 , mbIsDisposed(false)
152 ConfigurationController::~ConfigurationController (void) throw()
157 void SAL_CALL
ConfigurationController::disposing (void)
159 if (mpImplementation
.get() == NULL
)
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
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
)
209 if (mpImplementation
->mpQueueProcessor
.get() == 0)
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
);
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
);
242 mpImplementation
->mpBroadcaster
->RemoveListener(rxListener
);
248 void SAL_CALL
ConfigurationController::notifyEvent (
249 const ConfigurationChangeEvent
& rEvent
)
250 throw (RuntimeException
)
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
);
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
)
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
);
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 " <<
317 FrameworkHelper::ResourceIdToString(rxResourceId
), RTL_TEXTENCODING_UTF8
).getStr());
321 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": ConfigurationController::requestResourceActivation() " <<
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)
345 // Request the deactivation of a resource and all resources
347 requestResourceDeactivation(aResourceList
[nIndex
]);
351 Reference
<XConfigurationChangeRequest
> xRequest(
352 new GenericConfigurationChangeRequest(
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
);
369 SAL_INFO("sd.fwk", OSL_THIS_FUNC
<< ": ConfigurationController::requestResourceDeactivation() " <<
371 FrameworkHelper::ResourceIdToString(rxResourceId
), RTL_TEXTENCODING_UTF8
).getStr());
373 if (rxResourceId
.is())
375 // Request deactivation of all resources linked to the specified one
377 const Sequence
<Reference
<XResourceId
> > aLinkedResources (
378 mpImplementation
->mxRequestedConfiguration
->getResources(
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(
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
);
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
);
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());
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
);
446 return ! mpImplementation
->mpQueueProcessor
->IsEmpty();
453 void SAL_CALL
ConfigurationController::postChangeRequest (
454 const Reference
<XConfigurationChangeRequest
>& rxRequest
)
455 throw (RuntimeException
)
457 ::osl::MutexGuard
aGuard (maMutex
);
460 mpImplementation
->mpQueueProcessor
->AddRequest(rxRequest
);
466 Reference
<XConfiguration
> SAL_CALL
ConfigurationController::getRequestedConfiguration (void)
467 throw (RuntimeException
)
469 ::osl::MutexGuard
aGuard (maMutex
);
472 if (mpImplementation
->mxRequestedConfiguration
.is())
473 return Reference
<XConfiguration
>(
474 mpImplementation
->mxRequestedConfiguration
->createClone(), UNO_QUERY
);
476 return Reference
<XConfiguration
>();
482 Reference
<XConfiguration
> SAL_CALL
ConfigurationController::getCurrentConfiguration (void)
483 throw (RuntimeException
)
485 ::osl::MutexGuard
aGuard (maMutex
);
488 Reference
<XConfiguration
> xCurrentConfiguration(
489 mpImplementation
->mpConfigurationUpdater
->GetCurrentConfiguration());
490 if (xCurrentConfiguration
.is())
491 return Reference
<XConfiguration
>(xCurrentConfiguration
->createClone(), UNO_QUERY
);
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
);
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");
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());
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();
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();
554 requestResourceActivation(*iResource
, ResourceActivationMode_ADD
);
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
);
572 mpImplementation
->mpResourceFactoryContainer
->AddFactory(sResourceURL
, rxResourceFactory
);
578 void SAL_CALL
ConfigurationController::removeResourceFactoryForURL(
579 const OUString
& sResourceURL
)
580 throw (RuntimeException
)
582 ::osl::MutexGuard
aGuard (maMutex
);
584 mpImplementation
->mpResourceFactoryContainer
->RemoveFactoryForURL(sResourceURL
);
590 void SAL_CALL
ConfigurationController::removeResourceFactoryForReference(
591 const Reference
<XResourceFactory
>& rxResourceFactory
)
592 throw (RuntimeException
)
594 ::osl::MutexGuard
aGuard (maMutex
);
596 mpImplementation
->mpResourceFactoryContainer
->RemoveFactoryForReference(rxResourceFactory
);
602 Reference
<XResourceFactory
> SAL_CALL
ConfigurationController::getResourceFactory (
603 const OUString
& sResourceURL
)
604 throw (RuntimeException
)
606 ::osl::MutexGuard
aGuard (maMutex
);
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(
628 Reference
<frame::XController
>(aArguments
[0], UNO_QUERY_THROW
)));
635 //-----------------------------------------------------------------------------
637 void ConfigurationController::ThrowIfDisposed (void) const
638 throw (::com::sun::star::lang::DisposedException
)
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)),
666 mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager
)),
668 new ConfigurationControllerResourceManager(mpResourceFactoryContainer
,mpBroadcaster
)),
669 mpConfigurationUpdater(
670 new ConfigurationUpdater(mpBroadcaster
, mpResourceManager
,mxControllerManager
)),
671 mpQueueProcessor(new ChangeRequestQueueProcessor(&rController
,mpConfigurationUpdater
)),
672 mpConfigurationUpdaterLock(),
675 mpQueueProcessor
->SetConfiguration(mxRequestedConfiguration
);
681 ConfigurationController::Implementation::~Implementation (void)
688 } } // end of namespace sd::framework
690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */