merge the formfield patch from ooo-build
[ooovba.git] / sd / source / ui / framework / configuration / ConfigurationController.cxx
blob9ca6707a81bf2a74c311d0ef9114c1e97570a4db
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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;
58 using rtl::OUString;
59 using ::sd::framework::FrameworkHelper;
61 #undef VERBOSE
62 #define VERBOSE 3
65 namespace sd { namespace framework {
67 Reference<XInterface> SAL_CALL ConfigurationController_createInstance (
68 const Reference<XComponentContext>& rxContext)
70 (void)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
101 public:
102 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),
173 mpImplementation(),
174 mbIsDisposed(false)
181 ConfigurationController::~ConfigurationController (void) throw()
188 void SAL_CALL ConfigurationController::disposing (void)
190 if (mpImplementation.get() == NULL)
191 return;
193 #if defined VERBOSE && VERBOSE>=1
194 OSL_TRACE("ConfigurationController::disposing\n");
195 OSL_TRACE(" requesting empty configuration\n");
196 #endif
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");
204 #endif
206 // Now that all resources have been deactivated, mark the controller as
207 // disposed.
208 mbIsDisposed = true;
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)
243 return;
244 if (mpImplementation->mpQueueProcessor.get() == 0)
245 return;
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);
262 ThrowIfDisposed();
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);
276 ThrowIfDisposed();
277 mpImplementation->mpBroadcaster->RemoveListener(rxListener);
283 void SAL_CALL ConfigurationController::notifyEvent (
284 const ConfigurationChangeEvent& rEvent)
285 throw (RuntimeException)
287 ThrowIfDisposed();
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);
304 ThrowIfDisposed();
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)
324 ThrowIfDisposed();
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);
341 ThrowIfDisposed();
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",
352 OUStringToOString(
353 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr());
354 #endif
355 return;
358 #if defined VERBOSE && VERBOSE>=2
359 OSL_TRACE("ConfigurationController::requestResourceActivation() %s\n",
360 OUStringToOString(
361 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr());
362 #endif
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)
382 continue;
384 // Request the deactivation of a resource and all resources
385 // linked to it.
386 requestResourceDeactivation(aResourceList[nIndex]);
390 Reference<XConfigurationChangeRequest> xRequest(
391 new GenericConfigurationChangeRequest(
392 rxResourceId,
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);
406 ThrowIfDisposed();
408 #if defined VERBOSE && VERBOSE>=2
409 OSL_TRACE("ConfigurationController::requestResourceDeactivation() %s\n",
410 OUStringToOString(
411 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr());
412 #endif
414 if (rxResourceId.is())
416 // Request deactivation of all resources linked to the specified one
417 // as well.
418 const Sequence<Reference<XResourceId> > aLinkedResources (
419 mpImplementation->mxRequestedConfiguration->getResources(
420 rxResourceId,
421 OUString(),
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(
435 rxResourceId,
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);
449 ThrowIfDisposed();
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);
463 ThrowIfDisposed();
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());
471 else
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);
485 ThrowIfDisposed();
487 return ! mpImplementation->mpQueueProcessor->IsEmpty();
494 void SAL_CALL ConfigurationController::postChangeRequest (
495 const Reference<XConfigurationChangeRequest>& rxRequest)
496 throw (RuntimeException)
498 ::osl::MutexGuard aGuard (maMutex);
499 ThrowIfDisposed();
501 mpImplementation->mpQueueProcessor->AddRequest(rxRequest);
507 Reference<XConfiguration> SAL_CALL ConfigurationController::getRequestedConfiguration (void)
508 throw (RuntimeException)
510 ::osl::MutexGuard aGuard (maMutex);
511 ThrowIfDisposed();
513 if (mpImplementation->mxRequestedConfiguration.is())
514 return Reference<XConfiguration>(
515 mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY);
516 else
517 return Reference<XConfiguration>();
523 Reference<XConfiguration> SAL_CALL ConfigurationController::getCurrentConfiguration (void)
524 throw (RuntimeException)
526 ::osl::MutexGuard aGuard (maMutex);
527 ThrowIfDisposed();
529 Reference<XConfiguration> xCurrentConfiguration(
530 mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration());
531 if (xCurrentConfiguration.is())
532 return Reference<XConfiguration>(xCurrentConfiguration->createClone(), UNO_QUERY);
533 else
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);
548 ThrowIfDisposed();
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");
562 #endif
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());
572 #endif
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();
582 ++iResource)
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();
593 ++iResource)
595 requestResourceActivation(*iResource, ResourceActivationMode_ADD);
598 pLock.reset();
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);
612 ThrowIfDisposed();
613 mpImplementation->mpResourceFactoryContainer->AddFactory(sResourceURL, rxResourceFactory);
619 void SAL_CALL ConfigurationController::removeResourceFactoryForURL(
620 const OUString& sResourceURL)
621 throw (RuntimeException)
623 ::osl::MutexGuard aGuard (maMutex);
624 ThrowIfDisposed();
625 mpImplementation->mpResourceFactoryContainer->RemoveFactoryForURL(sResourceURL);
631 void SAL_CALL ConfigurationController::removeResourceFactoryForReference(
632 const Reference<XResourceFactory>& rxResourceFactory)
633 throw (RuntimeException)
635 ::osl::MutexGuard aGuard (maMutex);
636 ThrowIfDisposed();
637 mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory);
643 Reference<XResourceFactory> SAL_CALL ConfigurationController::getResourceFactory (
644 const OUString& sResourceURL)
645 throw (RuntimeException)
647 ::osl::MutexGuard aGuard (maMutex);
648 ThrowIfDisposed();
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(
668 *this,
669 Reference<frame::XController>(aArguments[0], UNO_QUERY_THROW)));
676 //-----------------------------------------------------------------------------
678 void ConfigurationController::ThrowIfDisposed (void) const
679 throw (::com::sun::star::lang::DisposedException)
681 if (mbIsDisposed)
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)),
710 mpBase(NULL),
711 mbIsInitialized(false),
712 mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager)),
713 mpResourceManager(
714 new ConfigurationControllerResourceManager(mpResourceFactoryContainer,mpBroadcaster)),
715 mpConfigurationUpdater(
716 new ConfigurationUpdater(mpBroadcaster, mpResourceManager,mxControllerManager)),
717 mpQueueProcessor(new ChangeRequestQueueProcessor(&rController,mpConfigurationUpdater)),
718 mpConfigurationUpdaterLock(),
719 mnLockCount(0)
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);
736 if (xTunnel.is())
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