1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ConfigurationController.cxx,v $
10 * $Revision: 1.7.68.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "precompiled_sd.hxx"
33 #include "framework/ConfigurationController.hxx"
35 #include "framework/Configuration.hxx"
36 #include "framework/FrameworkHelper.hxx"
37 #include "ConfigurationUpdater.hxx"
38 #include "ConfigurationControllerBroadcaster.hxx"
39 #include "ConfigurationTracer.hxx"
40 #include "GenericConfigurationChangeRequest.hxx"
41 #include "ResourceFactoryManager.hxx"
42 #include "UpdateRequest.hxx"
43 #include "ChangeRequestQueueProcessor.hxx"
44 #include "ConfigurationClassifier.hxx"
45 #include "ViewShellBase.hxx"
46 #include "UpdateLockManager.hxx"
47 #include "DrawController.hxx"
48 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
49 #include <com/sun/star/util/XURLTransformer.hpp>
51 #include <comphelper/stl_types.hxx>
52 #include <vos/mutex.hxx>
53 #include <vcl/svapp.hxx>
55 using namespace ::com::sun::star
;
56 using namespace ::com::sun::star::uno
;
57 using namespace ::com::sun::star::drawing::framework
;
59 using ::sd::framework::FrameworkHelper
;
65 namespace sd
{ namespace framework
{
67 Reference
<XInterface
> SAL_CALL
ConfigurationController_createInstance (
68 const Reference
<XComponentContext
>& rxContext
)
71 return static_cast<XWeak
*>(new ConfigurationController());
77 OUString
ConfigurationController_getImplementationName (void) throw(RuntimeException
)
79 return OUString(RTL_CONSTASCII_USTRINGPARAM(
80 "com.sun.star.comp.Draw.framework.configuration.ConfigurationController"));
86 Sequence
<rtl::OUString
> SAL_CALL
ConfigurationController_getSupportedServiceNames (void)
87 throw (RuntimeException
)
89 static const OUString
sServiceName(OUString::createFromAscii(
90 "com.sun.star.drawing.framework.ConfigurationController"));
91 return Sequence
<rtl::OUString
>(&sServiceName
, 1);
97 //----- ConfigurationController::Implementation -------------------------------
99 class ConfigurationController::Implementation
103 ConfigurationController
& rController
,
104 const Reference
<frame::XController
>& rxController
);
105 ~Implementation (void);
107 void Initialize (const Reference
<frame::XController
>& rxController
);
109 Reference
<XControllerManager
> mxControllerManager
;
111 /** The Broadcaster class implements storing and calling of listeners.
113 ::boost::shared_ptr
<ConfigurationControllerBroadcaster
> mpBroadcaster
;
115 /** The requested configuration which is modifed (asynchronously) by
116 calls to requestResourceActivation() and
117 requestResourceDeactivation(). The mpConfigurationUpdater makes the
118 current configuration reflect the content of this one.
120 ::com::sun::star::uno::Reference
<
121 ::com::sun::star::drawing::framework::XConfiguration
> mxRequestedConfiguration
;
123 ViewShellBase
* mpBase
;
125 bool mbIsInitialized
;
127 ::boost::shared_ptr
<ResourceFactoryManager
> mpResourceFactoryContainer
;
129 ::boost::shared_ptr
<ConfigurationControllerResourceManager
> mpResourceManager
;
131 ::boost::shared_ptr
<ConfigurationUpdater
> mpConfigurationUpdater
;
133 /** The queue processor ownes the queue of configuration change request
134 objects and processes the objects.
136 ::boost::scoped_ptr
<ChangeRequestQueueProcessor
> mpQueueProcessor
;
138 ::boost::shared_ptr
<ConfigurationUpdaterLock
> mpConfigurationUpdaterLock
;
140 sal_Int32 mnLockCount
;
146 //===== ConfigurationController::Lock =========================================
148 ConfigurationController::Lock::Lock (const Reference
<XConfigurationController
>& rxController
)
149 : mxController(rxController
)
151 OSL_ASSERT(mxController
.is());
153 if (mxController
.is())
154 mxController
->lock();
160 ConfigurationController::Lock::~Lock (void)
162 if (mxController
.is())
163 mxController
->unlock();
169 //===== ConfigurationController ===============================================
171 ConfigurationController::ConfigurationController (void) throw()
172 : ConfigurationControllerInterfaceBase(MutexOwner::maMutex
),
181 ConfigurationController::~ConfigurationController (void) throw()
188 void SAL_CALL
ConfigurationController::disposing (void)
190 if (mpImplementation
.get() == NULL
)
193 #if defined VERBOSE && VERBOSE>=1
194 OSL_TRACE("ConfigurationController::disposing\n");
195 OSL_TRACE(" requesting empty configuration\n");
197 // To destroy all resources an empty configuration is requested and then,
198 // synchronously, all resulting requests are processed.
199 mpImplementation
->mpQueueProcessor
->Clear();
200 restoreConfiguration(new Configuration(this,false));
201 mpImplementation
->mpQueueProcessor
->ProcessUntilEmpty();
202 #if defined VERBOSE && VERBOSE>=1
203 OSL_TRACE(" all requests processed\n");
206 // Now that all resources have been deactivated, mark the controller as
210 // Release the listeners.
211 lang::EventObject aEvent
;
212 aEvent
.Source
= uno::Reference
<uno::XInterface
>((cppu::OWeakObject
*)this);
215 const ::vos::OGuard
aSolarGuard (Application::GetSolarMutex());
216 mpImplementation
->mpBroadcaster
->DisposeAndClear();
219 mpImplementation
->mpQueueProcessor
.reset();
220 mpImplementation
->mxRequestedConfiguration
= NULL
;
221 mpImplementation
.reset();
227 void ConfigurationController::ProcessEvent (void)
229 if (mpImplementation
.get() != NULL
)
231 OSL_ASSERT(mpImplementation
->mpQueueProcessor
.get()!=NULL
);
233 mpImplementation
->mpQueueProcessor
->ProcessOneEvent();
240 void ConfigurationController::RequestSynchronousUpdate (void)
242 if (mpImplementation
.get() == NULL
)
244 if (mpImplementation
->mpQueueProcessor
.get() == 0)
246 mpImplementation
->mpQueueProcessor
->ProcessUntilEmpty();
252 //----- XConfigurationControllerBroadcaster -----------------------------------
254 void SAL_CALL
ConfigurationController::addConfigurationChangeListener (
255 const Reference
<XConfigurationChangeListener
>& rxListener
,
256 const ::rtl::OUString
& rsEventType
,
257 const Any
& rUserData
)
258 throw (RuntimeException
)
260 ::osl::MutexGuard
aGuard (maMutex
);
263 OSL_ASSERT(mpImplementation
.get()!=NULL
);
264 mpImplementation
->mpBroadcaster
->AddListener(rxListener
, rsEventType
, rUserData
);
270 void SAL_CALL
ConfigurationController::removeConfigurationChangeListener (
271 const Reference
<XConfigurationChangeListener
>& rxListener
)
272 throw (RuntimeException
)
274 ::osl::MutexGuard
aGuard (maMutex
);
277 mpImplementation
->mpBroadcaster
->RemoveListener(rxListener
);
283 void SAL_CALL
ConfigurationController::notifyEvent (
284 const ConfigurationChangeEvent
& rEvent
)
285 throw (RuntimeException
)
288 mpImplementation
->mpBroadcaster
->NotifyListeners(rEvent
);
295 //----- XConfigurationController ----------------------------------------------
297 void SAL_CALL
ConfigurationController::lock (void)
298 throw (RuntimeException
)
300 OSL_ASSERT(mpImplementation
.get()!=NULL
);
301 OSL_ASSERT(mpImplementation
->mpConfigurationUpdater
.get()!=NULL
);
303 ::osl::MutexGuard
aGuard (maMutex
);
307 ++mpImplementation
->mnLockCount
;
308 if (mpImplementation
->mpConfigurationUpdaterLock
.get()==NULL
)
309 mpImplementation
->mpConfigurationUpdaterLock
310 = mpImplementation
->mpConfigurationUpdater
->GetLock();
316 void SAL_CALL
ConfigurationController::unlock (void)
317 throw (RuntimeException
)
319 ::osl::MutexGuard
aGuard (maMutex
);
321 // Allow unlocking while the ConfigurationController is being disposed
322 // (but not when that is done and the controller is disposed.)
323 if (rBHelper
.bDisposed
)
326 OSL_ASSERT(mpImplementation
->mnLockCount
>0);
327 --mpImplementation
->mnLockCount
;
328 if (mpImplementation
->mnLockCount
== 0)
329 mpImplementation
->mpConfigurationUpdaterLock
.reset();
335 void SAL_CALL
ConfigurationController::requestResourceActivation (
336 const Reference
<XResourceId
>& rxResourceId
,
337 ResourceActivationMode eMode
)
338 throw (RuntimeException
)
340 ::osl::MutexGuard
aGuard (maMutex
);
343 // Check whether we are being disposed. This is handled differently
344 // then being completely disposed because the first thing disposing()
345 // does is to deactivate all remaining resources. This is done via
346 // regular methods which must not throw DisposedExceptions. Therefore
347 // we just return silently during that stage.
348 if (rBHelper
.bInDispose
)
350 #if defined VERBOSE && VERBOSE>=1
351 OSL_TRACE("ConfigurationController::requestResourceActivation(): ignoring %s\n",
353 FrameworkHelper::ResourceIdToString(rxResourceId
), RTL_TEXTENCODING_UTF8
).getStr());
358 #if defined VERBOSE && VERBOSE>=2
359 OSL_TRACE("ConfigurationController::requestResourceActivation() %s\n",
361 FrameworkHelper::ResourceIdToString(rxResourceId
), RTL_TEXTENCODING_UTF8
).getStr());
364 if (rxResourceId
.is())
366 if (eMode
== ResourceActivationMode_REPLACE
)
368 // Get a list of the matching resources and create deactivation
369 // requests for them.
370 Sequence
<Reference
<XResourceId
> > aResourceList (
371 mpImplementation
->mxRequestedConfiguration
->getResources(
372 rxResourceId
->getAnchor(),
373 rxResourceId
->getResourceTypePrefix(),
374 AnchorBindingMode_DIRECT
));
376 for (sal_Int32 nIndex
=0; nIndex
<aResourceList
.getLength(); ++nIndex
)
378 // Do not request the deactivation of the resource for which
379 // this method was called. Doing it would not change the
380 // outcome but would result in unnecessary work.
381 if (rxResourceId
->compareTo(aResourceList
[nIndex
]) == 0)
384 // Request the deactivation of a resource and all resources
386 requestResourceDeactivation(aResourceList
[nIndex
]);
390 Reference
<XConfigurationChangeRequest
> xRequest(
391 new GenericConfigurationChangeRequest(
393 GenericConfigurationChangeRequest::Activation
));
394 postChangeRequest(xRequest
);
401 void SAL_CALL
ConfigurationController::requestResourceDeactivation (
402 const Reference
<XResourceId
>& rxResourceId
)
403 throw (RuntimeException
)
405 ::osl::MutexGuard
aGuard (maMutex
);
408 #if defined VERBOSE && VERBOSE>=2
409 OSL_TRACE("ConfigurationController::requestResourceDeactivation() %s\n",
411 FrameworkHelper::ResourceIdToString(rxResourceId
), RTL_TEXTENCODING_UTF8
).getStr());
414 if (rxResourceId
.is())
416 // Request deactivation of all resources linked to the specified one
418 const Sequence
<Reference
<XResourceId
> > aLinkedResources (
419 mpImplementation
->mxRequestedConfiguration
->getResources(
422 AnchorBindingMode_DIRECT
));
423 const sal_Int32
nCount (aLinkedResources
.getLength());
424 for (sal_Int32 nIndex
=0; nIndex
<nCount
; ++nIndex
)
426 // We do not add deactivation requests directly but call this
427 // method recursively, so that when one time there are resources
428 // linked to linked resources, these are handled correctly, too.
429 requestResourceDeactivation(aLinkedResources
[nIndex
]);
432 // Add a deactivation request for the specified resource.
433 Reference
<XConfigurationChangeRequest
> xRequest(
434 new GenericConfigurationChangeRequest(
436 GenericConfigurationChangeRequest::Deactivation
));
437 postChangeRequest(xRequest
);
444 Reference
<XResource
> SAL_CALL
ConfigurationController::getResource (
445 const Reference
<XResourceId
>& rxResourceId
)
446 throw (RuntimeException
)
448 ::osl::MutexGuard
aGuard (maMutex
);
451 ConfigurationControllerResourceManager::ResourceDescriptor
aDescriptor (
452 mpImplementation
->mpResourceManager
->GetResource(rxResourceId
));
453 return aDescriptor
.mxResource
;
459 void SAL_CALL
ConfigurationController::update (void)
460 throw (RuntimeException
)
462 ::osl::MutexGuard
aGuard (maMutex
);
465 if (mpImplementation
->mpQueueProcessor
->IsEmpty())
467 // The queue is empty. Add another request that does nothing but
468 // asynchronously trigger a request for an update.
469 mpImplementation
->mpQueueProcessor
->AddRequest(new UpdateRequest());
473 // The queue is not empty, so we rely on the queue processor to
474 // request an update automatically when the queue becomes empty.
481 sal_Bool SAL_CALL
ConfigurationController::hasPendingRequests (void)
482 throw (RuntimeException
)
484 ::osl::MutexGuard
aGuard (maMutex
);
487 return ! mpImplementation
->mpQueueProcessor
->IsEmpty();
494 void SAL_CALL
ConfigurationController::postChangeRequest (
495 const Reference
<XConfigurationChangeRequest
>& rxRequest
)
496 throw (RuntimeException
)
498 ::osl::MutexGuard
aGuard (maMutex
);
501 mpImplementation
->mpQueueProcessor
->AddRequest(rxRequest
);
507 Reference
<XConfiguration
> SAL_CALL
ConfigurationController::getRequestedConfiguration (void)
508 throw (RuntimeException
)
510 ::osl::MutexGuard
aGuard (maMutex
);
513 if (mpImplementation
->mxRequestedConfiguration
.is())
514 return Reference
<XConfiguration
>(
515 mpImplementation
->mxRequestedConfiguration
->createClone(), UNO_QUERY
);
517 return Reference
<XConfiguration
>();
523 Reference
<XConfiguration
> SAL_CALL
ConfigurationController::getCurrentConfiguration (void)
524 throw (RuntimeException
)
526 ::osl::MutexGuard
aGuard (maMutex
);
529 Reference
<XConfiguration
> xCurrentConfiguration(
530 mpImplementation
->mpConfigurationUpdater
->GetCurrentConfiguration());
531 if (xCurrentConfiguration
.is())
532 return Reference
<XConfiguration
>(xCurrentConfiguration
->createClone(), UNO_QUERY
);
534 return Reference
<XConfiguration
>();
540 /** The given configuration is restored by generating the appropriate set of
541 activation and deactivation requests.
543 void SAL_CALL
ConfigurationController::restoreConfiguration (
544 const Reference
<XConfiguration
>& rxNewConfiguration
)
545 throw (RuntimeException
)
547 ::osl::MutexGuard
aGuard (maMutex
);
550 // We will probably be making a couple of activation and deactivation
551 // requests so lock the configuration controller and let it later update
552 // all changes at once.
553 ::boost::shared_ptr
<ConfigurationUpdaterLock
> pLock (
554 mpImplementation
->mpConfigurationUpdater
->GetLock());
556 // Get lists of resources that are to be activated or deactivated.
557 Reference
<XConfiguration
> xCurrentConfiguration (mpImplementation
->mxRequestedConfiguration
);
558 #if defined VERBOSE && VERBOSE>=1
559 OSL_TRACE("ConfigurationController::restoreConfiguration(\n");
560 ConfigurationTracer::TraceConfiguration(rxNewConfiguration
, "requested configuration");
561 ConfigurationTracer::TraceConfiguration(xCurrentConfiguration
, "current configuration");
563 ConfigurationClassifier
aClassifier (rxNewConfiguration
, xCurrentConfiguration
);
564 aClassifier
.Partition();
565 #if defined VERBOSE && VERBOSE>=3
566 aClassifier
.TraceResourceIdVector(
567 "requested but not current resources:\n", aClassifier
.GetC1minusC2());
568 aClassifier
.TraceResourceIdVector(
569 "current but not requested resources:\n", aClassifier
.GetC2minusC1());
570 aClassifier
.TraceResourceIdVector(
571 "requested and current resources:\n", aClassifier
.GetC1andC2());
574 ConfigurationClassifier::ResourceIdVector::const_iterator iResource
;
576 // Request the deactivation of resources that are not requested in the
577 // new configuration.
578 const ConfigurationClassifier::ResourceIdVector
& rResourcesToDeactivate (
579 aClassifier
.GetC2minusC1());
580 for (iResource
=rResourcesToDeactivate
.begin();
581 iResource
!=rResourcesToDeactivate
.end();
584 requestResourceDeactivation(*iResource
);
587 // Request the activation of resources that are requested in the
588 // new configuration but are not part of the current configuration.
589 const ConfigurationClassifier::ResourceIdVector
& rResourcesToActivate (
590 aClassifier
.GetC1minusC2());
591 for (iResource
=rResourcesToActivate
.begin();
592 iResource
!=rResourcesToActivate
.end();
595 requestResourceActivation(*iResource
, ResourceActivationMode_ADD
);
604 //----- XResourceFactoryManager -----------------------------------------------
606 void SAL_CALL
ConfigurationController::addResourceFactory(
607 const OUString
& sResourceURL
,
608 const Reference
<XResourceFactory
>& rxResourceFactory
)
609 throw (RuntimeException
)
611 ::osl::MutexGuard
aGuard (maMutex
);
613 mpImplementation
->mpResourceFactoryContainer
->AddFactory(sResourceURL
, rxResourceFactory
);
619 void SAL_CALL
ConfigurationController::removeResourceFactoryForURL(
620 const OUString
& sResourceURL
)
621 throw (RuntimeException
)
623 ::osl::MutexGuard
aGuard (maMutex
);
625 mpImplementation
->mpResourceFactoryContainer
->RemoveFactoryForURL(sResourceURL
);
631 void SAL_CALL
ConfigurationController::removeResourceFactoryForReference(
632 const Reference
<XResourceFactory
>& rxResourceFactory
)
633 throw (RuntimeException
)
635 ::osl::MutexGuard
aGuard (maMutex
);
637 mpImplementation
->mpResourceFactoryContainer
->RemoveFactoryForReference(rxResourceFactory
);
643 Reference
<XResourceFactory
> SAL_CALL
ConfigurationController::getResourceFactory (
644 const OUString
& sResourceURL
)
645 throw (RuntimeException
)
647 ::osl::MutexGuard
aGuard (maMutex
);
650 return mpImplementation
->mpResourceFactoryContainer
->GetFactory(sResourceURL
);
656 //----- XInitialization -------------------------------------------------------
658 void SAL_CALL
ConfigurationController::initialize (const Sequence
<Any
>& aArguments
)
659 throw (Exception
, RuntimeException
)
661 ::osl::MutexGuard
aGuard (maMutex
);
663 if (aArguments
.getLength() == 1)
665 const ::vos::OGuard
aSolarGuard (Application::GetSolarMutex());
667 mpImplementation
.reset(new Implementation(
669 Reference
<frame::XController
>(aArguments
[0], UNO_QUERY_THROW
)));
676 //-----------------------------------------------------------------------------
678 void ConfigurationController::ThrowIfDisposed (void) const
679 throw (::com::sun::star::lang::DisposedException
)
683 throw lang::DisposedException (
684 OUString(RTL_CONSTASCII_USTRINGPARAM(
685 "ConfigurationController object has already been disposed")),
686 const_cast<uno::XWeak
*>(static_cast<const uno::XWeak
*>(this)));
689 if (mpImplementation
.get() == NULL
)
691 OSL_ASSERT(mpImplementation
.get() != NULL
);
692 throw RuntimeException(
693 OUString(RTL_CONSTASCII_USTRINGPARAM(
694 "ConfigurationController not initialized")),
695 const_cast<uno::XWeak
*>(static_cast<const uno::XWeak
*>(this)));
702 //===== ConfigurationController::Implementation ===============================
704 ConfigurationController::Implementation::Implementation (
705 ConfigurationController
& rController
,
706 const Reference
<frame::XController
>& rxController
)
707 : mxControllerManager(rxController
, UNO_QUERY_THROW
),
708 mpBroadcaster(new ConfigurationControllerBroadcaster(&rController
)),
709 mxRequestedConfiguration(new Configuration(&rController
, true)),
711 mbIsInitialized(false),
712 mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager
)),
714 new ConfigurationControllerResourceManager(mpResourceFactoryContainer
,mpBroadcaster
)),
715 mpConfigurationUpdater(
716 new ConfigurationUpdater(mpBroadcaster
, mpResourceManager
,mxControllerManager
)),
717 mpQueueProcessor(new ChangeRequestQueueProcessor(&rController
,mpConfigurationUpdater
)),
718 mpConfigurationUpdaterLock(),
721 mpQueueProcessor
->SetConfiguration(mxRequestedConfiguration
);
727 void ConfigurationController::Implementation::Initialize (
728 const Reference
<frame::XController
>& rxController
)
730 mxControllerManager
= Reference
<XControllerManager
>(rxController
, UNO_QUERY_THROW
);
732 mpConfigurationUpdater
->SetControllerManager(mxControllerManager
);
734 // Tunnel through the controller to obtain a ViewShellBase.
735 Reference
<lang::XUnoTunnel
> xTunnel (rxController
, UNO_QUERY_THROW
);
738 ::sd::DrawController
* pController
= reinterpret_cast<sd::DrawController
*>(
739 xTunnel
->getSomething(sd::DrawController::getUnoTunnelId()));
740 if (pController
!= NULL
)
741 mpBase
= pController
->GetViewShellBase();
748 ConfigurationController::Implementation::~Implementation (void)
755 } } // end of namespace sd::framework