diff options
Diffstat (limited to 'sd/source/ui/framework/configuration')
24 files changed, 5188 insertions, 0 deletions
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx b/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx new file mode 100644 index 000000000000..c46a89df8ee8 --- /dev/null +++ b/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx @@ -0,0 +1,38 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "ChangeRequestQueue.hxx" + +namespace sd { namespace framework { + +ChangeRequestQueue::ChangeRequestQueue (void) +{ +} + +} } // end of namespace sd::framework diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx b/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx new file mode 100644 index 000000000000..bad80ff50d69 --- /dev/null +++ b/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_CHANGE_OPERATION_QUEUE_HXX +#define SD_FRAMEWORK_CHANGE_OPERATION_QUEUE_HXX + +#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp> + +#include <list> + +namespace sd { namespace framework { + + +/** The ChangeRequestQueue stores the pending requests for changes to the + requested configuration. It is the task of the + ChangeRequestQueueProcessor to process these requests. +*/ +class ChangeRequestQueue + : public ::std::list<com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfigurationChangeRequest> > +{ +public: + /** Create an empty queue. + */ + ChangeRequestQueue (void); +}; + + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx new file mode 100755 index 000000000000..bf3571cbd8f4 --- /dev/null +++ b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx @@ -0,0 +1,237 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "ChangeRequestQueueProcessor.hxx" +#include "ConfigurationTracer.hxx" + +#include "framework/ConfigurationController.hxx" +#include "ConfigurationUpdater.hxx" + +#include <vcl/svapp.hxx> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/drawing/framework/XConfiguration.hpp> +#include <com/sun/star/drawing/framework/ConfigurationChangeEvent.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +#undef VERBOSE +//#define VERBOSE 1 + +namespace { + +#ifdef VERBOSE + +void TraceRequest (const Reference<XConfigurationChangeRequest>& rxRequest) +{ + Reference<container::XNamed> xNamed (rxRequest, UNO_QUERY); + if (xNamed.is()) + OSL_TRACE(" %s\n", + ::rtl::OUStringToOString(xNamed->getName(), RTL_TEXTENCODING_UTF8).getStr()); +} + +#endif + +} // end of anonymous namespace + + +namespace sd { namespace framework { + +ChangeRequestQueueProcessor::ChangeRequestQueueProcessor ( + const ::rtl::Reference<ConfigurationController>& rpConfigurationController, + const ::boost::shared_ptr<ConfigurationUpdater>& rpConfigurationUpdater) + : maMutex(), + maQueue(), + mnUserEventId(0), + mxConfiguration(), + mpConfigurationController(rpConfigurationController), + mpConfigurationUpdater(rpConfigurationUpdater) +{ +} + + + + +ChangeRequestQueueProcessor::~ChangeRequestQueueProcessor (void) +{ + if (mnUserEventId != 0) + Application::RemoveUserEvent(mnUserEventId); +} + + + + +void ChangeRequestQueueProcessor::SetConfiguration ( + const Reference<XConfiguration>& rxConfiguration) +{ + ::osl::MutexGuard aGuard (maMutex); + + mxConfiguration = rxConfiguration; + StartProcessing(); +} + + + + +void ChangeRequestQueueProcessor::AddRequest ( + const Reference<XConfigurationChangeRequest>& rxRequest) +{ + ::osl::MutexGuard aGuard (maMutex); + +#ifdef VERBOSE + if (maQueue.empty()) + { + OSL_TRACE("Adding requests to empty queue\n"); + ConfigurationTracer::TraceConfiguration( + mxConfiguration, "current configuration of queue processor"); + } + OSL_TRACE("Adding request\n"); + TraceRequest(rxRequest); +#endif + + maQueue.push_back(rxRequest); + StartProcessing(); +} + + + + +void ChangeRequestQueueProcessor::StartProcessing (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + if (mnUserEventId == 0 + && mxConfiguration.is() + && ! maQueue.empty()) + { +#ifdef VERBOSE + OSL_TRACE("ChangeRequestQueueProcessor scheduling processing\n"); +#endif + mnUserEventId = Application::PostUserEvent( + LINK(this,ChangeRequestQueueProcessor,ProcessEvent)); + } +} + + + + +IMPL_LINK(ChangeRequestQueueProcessor, ProcessEvent, void*, pUnused) +{ + (void)pUnused; + + ::osl::MutexGuard aGuard (maMutex); + + mnUserEventId = 0; + + ProcessOneEvent(); + + if ( ! maQueue.empty()) + { + // Schedule the processing of the next event. + StartProcessing(); + } + + return 0; +} + + + + +void ChangeRequestQueueProcessor::ProcessOneEvent (void) +{ + ::osl::MutexGuard aGuard (maMutex); + +#ifdef VERBOSE + OSL_TRACE("ProcessOneEvent\n"); +#endif + + if (mxConfiguration.is() + && ! maQueue.empty()) + { + // Get and remove the first entry from the queue. + Reference<XConfigurationChangeRequest> xRequest (maQueue.front()); + maQueue.pop_front(); + + // Execute the change request. + if (xRequest.is()) + { +#ifdef VERBOSE + TraceRequest(xRequest); +#endif + xRequest->execute(mxConfiguration); + } + + if (maQueue.empty()) + { +#ifdef VERBOSE + OSL_TRACE("All requests are processed\n"); +#endif + // The queue is empty so tell the ConfigurationManager to update + // its state. + if (mpConfigurationUpdater.get() != NULL) + { +#ifdef VERBOSE + ConfigurationTracer::TraceConfiguration ( + mxConfiguration, "updating to configuration"); +#endif + mpConfigurationUpdater->RequestUpdate(mxConfiguration); + } + } + } +} + + + + +bool ChangeRequestQueueProcessor::IsEmpty (void) const +{ + return maQueue.empty(); +} + + + + +void ChangeRequestQueueProcessor::ProcessUntilEmpty (void) +{ + while ( ! IsEmpty()) + ProcessOneEvent(); +} + + + + +void ChangeRequestQueueProcessor::Clear (void) +{ + ::osl::MutexGuard aGuard (maMutex); + maQueue.clear(); +} + + +} } // end of namespace sd::framework::configuration diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx new file mode 100755 index 000000000000..3dd151ae3d29 --- /dev/null +++ b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_CHANGE_REQUEST_QUEUE_PROCESSOR_HXX +#define SD_FRAMEWORK_CHANGE_REQUEST_QUEUE_PROCESSOR_HXX + +#include "ChangeRequestQueue.hxx" +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> +#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp> +#include <com/sun/star/drawing/framework/ConfigurationChangeEvent.hpp> + +#include <cppuhelper/interfacecontainer.hxx> +#include <tools/link.hxx> + +#include <boost/shared_ptr.hpp> + +namespace sd { namespace framework { + +class ConfigurationController; +class ConfigurationUpdater; + +/** The ChangeRequestQueueProcessor ownes the ChangeRequestQueue and + processes the configuration change requests. + + When after processing one entry the queue is empty then the + XConfigurationController::update() method is called so that the changes + made to the local XConfiguration reference are reflected by the UI. + + Queue entries are processed asynchronously by calling PostUserEvent(). +*/ +class ChangeRequestQueueProcessor +{ +public: + /** The queue processor is created with a reference to an + ConfigurationController so that its UpdateConfiguration() method can + be called when the queue becomes empty. + */ + ChangeRequestQueueProcessor ( + const ::rtl::Reference<ConfigurationController>& rxController, + const ::boost::shared_ptr<ConfigurationUpdater>& rpUpdater); + ~ChangeRequestQueueProcessor (void); + + /** Sets the configuration who will be changed by subsequent change + requests. This method should be called only by the configuration + controller who owns the configuration. + */ + void SetConfiguration ( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration>& rxConfiguration); + + /** The given request is appended to the end of the queue and will + eventually be processed when all other entries in front of it have + been processed. + */ + void AddRequest (const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfigurationChangeRequest>& rxRequest); + + /** Returns </sal_True> when the queue is empty. + */ + bool IsEmpty (void) const; + + /** Process all events in the queue synchronously. + + <p>This method is typically called when the framework is shut down + to establish an empty configuration.</p> + */ + void ProcessUntilEmpty (void); + + /** Process the first event in queue. + */ + void ProcessOneEvent (void); + + /** Remove all events from the queue. + + <p>This method is typically called when the framework is shut down + to avoid the processing of still pending activation requests.</p> + */ + void Clear (void); + +private: + mutable ::osl::Mutex maMutex; + + ChangeRequestQueue maQueue; + + /** The id returned by the last PostUserEvent() call. This id is stored + so that a pending user event can be removed whent he queue processor + is destroyed. + */ + sal_uIntPtr mnUserEventId; + + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration> mxConfiguration; + + ::rtl::Reference<ConfigurationController> mpConfigurationController; + + ::boost::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater; + + /** Initiate the processing of the entries in the queue. The actual + processing starts asynchronously. + */ + void StartProcessing (void); + + /** Callback function for the PostUserEvent() call. + */ + DECL_LINK(ProcessEvent,void*); +}; + + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/Configuration.cxx b/sd/source/ui/framework/configuration/Configuration.cxx new file mode 100644 index 000000000000..2637a9ac1413 --- /dev/null +++ b/sd/source/ui/framework/configuration/Configuration.cxx @@ -0,0 +1,420 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "framework/Configuration.hxx" + +#include "framework/FrameworkHelper.hxx" +#include <comphelper/stl_types.hxx> + + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::sd::framework::FrameworkHelper; +using ::rtl::OUString; + +#undef VERBOSE + +namespace { +/** Use the XResourceId::compareTo() method to implement a compare operator + for STL containers. +*/ +class XResourceIdLess + : public ::std::binary_function <Reference<XResourceId>, Reference<XResourceId>, bool> +{ +public: + bool operator () (const Reference<XResourceId>& rId1, const Reference<XResourceId>& rId2) const + { + return rId1->compareTo(rId2) == -1; + } +}; + +} // end of anonymous namespace + + + + +namespace sd { namespace framework { + + +class Configuration::ResourceContainer + : public ::std::set<Reference<XResourceId>, XResourceIdLess> +{ +public: + ResourceContainer (void) {} +}; + + + + +//----- Service --------------------------------------------------------------- + +Reference<XInterface> SAL_CALL Configuration_createInstance ( + const Reference<XComponentContext>& rxContext) +{ + (void)rxContext; + return Reference<XInterface>(static_cast<XWeak*>(new Configuration(NULL,false))); +} + + + + +OUString Configuration_getImplementationName (void) throw(RuntimeException) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.comp.Draw.framework.configuration.Configuration")); +} + + + + +Sequence<rtl::OUString> SAL_CALL Configuration_getSupportedServiceNames (void) + throw (RuntimeException) +{ + static const OUString sServiceName(OUString::createFromAscii( + "com.sun.star.drawing.framework.Configuration")); + return Sequence<rtl::OUString>(&sServiceName, 1); +} + + + + +//===== Configuration ========================================================= + +Configuration::Configuration ( + const Reference<XConfigurationControllerBroadcaster>& rxBroadcaster, + bool bBroadcastRequestEvents) + : ConfigurationInterfaceBase(MutexOwner::maMutex), + mpResourceContainer(new ResourceContainer()), + mxBroadcaster(rxBroadcaster), + mbBroadcastRequestEvents(bBroadcastRequestEvents) +{ +} + + + +Configuration::Configuration ( + const Reference<XConfigurationControllerBroadcaster>& rxBroadcaster, + bool bBroadcastRequestEvents, + const ResourceContainer& rResourceContainer) + : ConfigurationInterfaceBase(MutexOwner::maMutex), + mpResourceContainer(new ResourceContainer(rResourceContainer)), + mxBroadcaster(rxBroadcaster), + mbBroadcastRequestEvents(bBroadcastRequestEvents) +{ +} + + + + +Configuration::~Configuration (void) +{ +} + + + + +void SAL_CALL Configuration::disposing (void) +{ + ::osl::MutexGuard aGuard (maMutex); + mpResourceContainer->clear(); + mxBroadcaster = NULL; +} + + + + +//----- XConfiguration -------------------------------------------------------- + +void SAL_CALL Configuration::addResource (const Reference<XResourceId>& rxResourceId) + throw (RuntimeException) +{ + ThrowIfDisposed(); + + if ( ! rxResourceId.is() || rxResourceId->getResourceURL().getLength()==0) + throw ::com::sun::star::lang::IllegalArgumentException(); + + if (mpResourceContainer->find(rxResourceId) == mpResourceContainer->end()) + { +#ifdef VERBOSE + OSL_TRACE("Configuration::addResource() %s", + OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); +#endif + mpResourceContainer->insert(rxResourceId); + PostEvent(rxResourceId, true); + } +} + + + + +void SAL_CALL Configuration::removeResource (const Reference<XResourceId>& rxResourceId) + throw (RuntimeException) +{ + ThrowIfDisposed(); + + if ( ! rxResourceId.is() || rxResourceId->getResourceURL().getLength()==0) + throw ::com::sun::star::lang::IllegalArgumentException(); + + ResourceContainer::iterator iResource (mpResourceContainer->find(rxResourceId)); + if (iResource != mpResourceContainer->end()) + { +#ifdef VERBOSE + OSL_TRACE("Configuration::removeResource() %s", + OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); +#endif + PostEvent(rxResourceId,false); + mpResourceContainer->erase(iResource); + } +} + + + + +Sequence<Reference<XResourceId> > SAL_CALL Configuration::getResources ( + const Reference<XResourceId>& rxAnchorId, + const ::rtl::OUString& rsResourceURLPrefix, + AnchorBindingMode eMode) + throw (::com::sun::star::uno::RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + bool bFilterResources (rsResourceURLPrefix.getLength() > 0); + + // Collect the matching resources in a vector. + ::std::vector<Reference<XResourceId> > aResources; + ResourceContainer::const_iterator iResource; + for (iResource=mpResourceContainer->begin(); + iResource!=mpResourceContainer->end(); + ++iResource) + { + if ( ! (*iResource)->isBoundTo(rxAnchorId,eMode)) + continue; + + + if (bFilterResources) + { + // Apply the given resource prefix as filter. + + // Make sure that the resource is bound directly to the anchor. + if (eMode != AnchorBindingMode_DIRECT + && ! (*iResource)->isBoundTo(rxAnchorId, AnchorBindingMode_DIRECT)) + { + continue; + } + + // Make sure that the resource URL matches the given prefix. + if ( ! (*iResource)->getResourceURL().match(rsResourceURLPrefix)) + { + continue; + } + } + + aResources.push_back(*iResource); + } + + // Copy the resources from the vector into a new sequence. + Sequence<Reference<XResourceId> > aResult (aResources.size()); + for (sal_uInt32 nIndex=0; nIndex<aResources.size(); ++nIndex) + aResult[nIndex] = aResources[nIndex]; + + return aResult; +} + + + + +sal_Bool SAL_CALL Configuration::hasResource (const Reference<XResourceId>& rxResourceId) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + return rxResourceId.is() + && mpResourceContainer->find(rxResourceId) != mpResourceContainer->end(); +} + + + + +//----- XCloneable ------------------------------------------------------------ + +Reference<util::XCloneable> SAL_CALL Configuration::createClone (void) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + Configuration* pConfiguration = new Configuration( + mxBroadcaster, + mbBroadcastRequestEvents, + *mpResourceContainer); + + return Reference<util::XCloneable>(pConfiguration); +} + + + + +//----- XNamed ---------------------------------------------------------------- + +OUString SAL_CALL Configuration::getName (void) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + OUString aString; + + if (rBHelper.bDisposed || rBHelper.bInDispose) + aString += OUString::createFromAscii("DISPOSED "); + aString += OUString::createFromAscii("Configuration["); + + ResourceContainer::const_iterator iResource; + for (iResource=mpResourceContainer->begin(); + iResource!=mpResourceContainer->end(); + ++iResource) + { + if (iResource != mpResourceContainer->begin()) + aString += OUString::createFromAscii(", "); + aString += FrameworkHelper::ResourceIdToString(*iResource); + } + aString += OUString::createFromAscii("]"); + + return aString; +} + + + + +void SAL_CALL Configuration::setName (const OUString& rsName) + throw (RuntimeException) +{ + (void)rsName; // rsName is ignored. +} + + + + + +// ---------------------------------------------------------------------------- + +void Configuration::PostEvent ( + const Reference<XResourceId>& rxResourceId, + const bool bActivation) +{ + OSL_ASSERT(rxResourceId.is()); + + if (mxBroadcaster.is()) + { + ConfigurationChangeEvent aEvent; + aEvent.ResourceId = rxResourceId; + if (bActivation) + if (mbBroadcastRequestEvents) + aEvent.Type = FrameworkHelper::msResourceActivationRequestEvent; + else + aEvent.Type = FrameworkHelper::msResourceActivationEvent; + else + if (mbBroadcastRequestEvents) + aEvent.Type = FrameworkHelper::msResourceDeactivationRequestEvent; + else + aEvent.Type = FrameworkHelper::msResourceDeactivationEvent; + aEvent.Configuration = this; + + mxBroadcaster->notifyEvent(aEvent); + } +} + + + + +void Configuration::ThrowIfDisposed (void) const + throw (::com::sun::star::lang::DisposedException) +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + throw lang::DisposedException ( + OUString(RTL_CONSTASCII_USTRINGPARAM( + "Configuration object has already been disposed")), + const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this))); + } +} + + + + +//============================================================================= + +bool AreConfigurationsEquivalent ( + const Reference<XConfiguration>& rxConfiguration1, + const Reference<XConfiguration>& rxConfiguration2) +{ + if (rxConfiguration1.is() != rxConfiguration2.is()) + return false; + if ( ! rxConfiguration1.is() && ! rxConfiguration2.is()) + return true; + + // Get the lists of resources from the two given configurations. + const Sequence<Reference<XResourceId> > aResources1( + rxConfiguration1->getResources( + NULL, OUString(), AnchorBindingMode_INDIRECT)); + const Sequence<Reference<XResourceId> > aResources2( + rxConfiguration2->getResources( + NULL, OUString(), AnchorBindingMode_INDIRECT)); + + // When the number of resources differ then the configurations can not + // be equivalent. + const sal_Int32 nCount (aResources1.getLength()); + const sal_Int32 nCount2 (aResources2.getLength()); + if (nCount != nCount2) + return false; + + // Comparison of the two lists of resource ids relies on their + // ordering. + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + const Reference<XResourceId> xResource1 (aResources1[nIndex]); + const Reference<XResourceId> xResource2 (aResources2[nIndex]); + if (xResource1.is() && xResource2.is()) + { + if (xResource1->compareTo(xResource2) != 0) + return false; + } + else if (xResource1.is() != xResource2.is()) + { + return false; + } + } + + return true; +} + +} } // end of namespace sd::framework diff --git a/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx b/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx new file mode 100755 index 000000000000..55e22361ad3a --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx @@ -0,0 +1,238 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "ConfigurationClassifier.hxx" + +#include "framework/FrameworkHelper.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::rtl::OUString; + +#undef VERBOSE +//#define VERBOSE 2 + + +namespace sd { namespace framework { + +ConfigurationClassifier::ConfigurationClassifier ( + const Reference<XConfiguration>& rxConfiguration1, + const Reference<XConfiguration>& rxConfiguration2) + : mxConfiguration1(rxConfiguration1), + mxConfiguration2(rxConfiguration2), + maC1minusC2(), + maC2minusC1(), + maC1andC2() +{ +} + + + + +bool ConfigurationClassifier::Partition (void) +{ + maC1minusC2.clear(); + maC2minusC1.clear(); + maC1andC2.clear(); + + PartitionResources( + mxConfiguration1->getResources(NULL, OUString(), AnchorBindingMode_DIRECT), + mxConfiguration2->getResources(NULL, OUString(), AnchorBindingMode_DIRECT)); + + return !maC1minusC2.empty() || !maC2minusC1.empty(); +} + + + + +const ConfigurationClassifier::ResourceIdVector& ConfigurationClassifier::GetC1minusC2 (void) const +{ + return maC1minusC2; +} + + + + +const ConfigurationClassifier::ResourceIdVector& ConfigurationClassifier::GetC2minusC1 (void) const +{ + return maC2minusC1; +} + + + +const ConfigurationClassifier::ResourceIdVector& ConfigurationClassifier::GetC1andC2 (void) const +{ + return maC1andC2; +} + + +void ConfigurationClassifier::PartitionResources ( + const ::com::sun::star::uno::Sequence<Reference<XResourceId> >& rS1, + const ::com::sun::star::uno::Sequence<Reference<XResourceId> >& rS2) +{ + ResourceIdVector aC1minusC2; + ResourceIdVector aC2minusC1; + ResourceIdVector aC1andC2; + + // Classify the resources in the configurations that are not bound to + // other resources. + ClassifyResources( + rS1, + rS2, + aC1minusC2, + aC2minusC1, + aC1andC2); + +#if defined VERBOSE && VERBOSE >= 2 + OSL_TRACE("copying resource ids to C1-C2\r"); +#endif + CopyResources(aC1minusC2, mxConfiguration1, maC1minusC2); +#if defined VERBOSE && VERBOSE >= 2 + OSL_TRACE("copying resource ids to C2-C1\r"); +#endif + CopyResources(aC2minusC1, mxConfiguration2, maC2minusC1); + + // Process the unique resources that belong to both configurations. + ResourceIdVector::const_iterator iResource; + for (iResource=aC1andC2.begin(); iResource!=aC1andC2.end(); ++iResource) + { + maC1andC2.push_back(*iResource); + PartitionResources( + mxConfiguration1->getResources(*iResource, OUString(), AnchorBindingMode_DIRECT), + mxConfiguration2->getResources(*iResource, OUString(), AnchorBindingMode_DIRECT)); + } +} + + + + +void ConfigurationClassifier::ClassifyResources ( + const ::com::sun::star::uno::Sequence<Reference<XResourceId> >& rS1, + const ::com::sun::star::uno::Sequence<Reference<XResourceId> >& rS2, + ResourceIdVector& rS1minusS2, + ResourceIdVector& rS2minusS1, + ResourceIdVector& rS1andS2) +{ + // Get arrays from the sequences for faster iteration. + const Reference<XResourceId>* aA1 = rS1.getConstArray(); + const Reference<XResourceId>* aA2 = rS2.getConstArray(); + sal_Int32 nL1 (rS1.getLength()); + sal_Int32 nL2 (rS2.getLength()); + + // Find all elements in rS1 and place them in rS1minusS2 or rS1andS2 + // depending on whether they are in rS2 or not. + for (sal_Int32 i=0; i<nL1; ++i) + { + bool bFound (false); + for (sal_Int32 j=0; j<nL2 && !bFound; ++j) + if (aA1[i]->getResourceURL().equals(aA2[j]->getResourceURL())) + bFound = true; + + if (bFound) + rS1andS2.push_back(aA1[i]); + else + rS1minusS2.push_back(aA1[i]); + } + + // Find all elements in rS2 that are not in rS1. The elements that are + // in both rS1 and rS2 have been handled above and are therefore ignored + // here. + for (sal_Int32 j=0; j<nL2; ++j) + { + bool bFound (false); + for (sal_Int32 i=0; i<nL1 && !bFound; ++i) + if (aA2[j]->getResourceURL().equals(aA1[i]->getResourceURL())) + bFound = true; + + if ( ! bFound) + rS2minusS1.push_back(aA2[j]); + } +} + + + + +void ConfigurationClassifier::CopyResources ( + const ResourceIdVector& rSource, + const Reference<XConfiguration>& rxConfiguration, + ResourceIdVector& rTarget) +{ + // Copy all resources bound to the ones in aC1minusC2Unique to rC1minusC2. + ResourceIdVector::const_iterator iResource (rSource.begin()); + ResourceIdVector::const_iterator iEnd(rSource.end()); + for ( ; iResource!=iEnd; ++iResource) + { + const Sequence<Reference<XResourceId> > aBoundResources ( + rxConfiguration->getResources( + *iResource, + OUString(), + AnchorBindingMode_INDIRECT)); + const sal_Int32 nL (aBoundResources.getLength()); + + rTarget.reserve(rTarget.size() + 1 + nL); + rTarget.push_back(*iResource); + +#if defined VERBOSE && VERBOSE >= 2 + OSL_TRACE(" copying %s\r", + OUStringToOString(FrameworkHelper::ResourceIdToString(*iResource), + RTL_TEXTENCODING_UTF8).getStr()); +#endif + + const Reference<XResourceId>* aA = aBoundResources.getConstArray(); + for (sal_Int32 i=0; i<nL; ++i) + { + rTarget.push_back(aA[i]); +#if defined VERBOSE && VERBOSE >= 2 + OSL_TRACE(" copying %s\r", + OUStringToOString(FrameworkHelper::ResourceIdToString(aA[i]), + RTL_TEXTENCODING_UTF8).getStr()); +#endif + } + } +} + + +void ConfigurationClassifier::TraceResourceIdVector ( + const sal_Char* pMessage, + const ResourceIdVector& rResources) const +{ + + OSL_TRACE(pMessage); + ResourceIdVector::const_iterator iResource; + for (iResource=rResources.begin(); iResource!=rResources.end(); ++iResource) + { + OUString sResource (FrameworkHelper::ResourceIdToString(*iResource)); + OSL_TRACE(" %s\r", + OUStringToOString(sResource, RTL_TEXTENCODING_UTF8).getStr()); + } +} + + +} } // end of namespace sd::framework diff --git a/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx b/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx new file mode 100755 index 000000000000..b19f8c1459a5 --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx @@ -0,0 +1,183 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_CONFIGURATION_CLASSIFIER_HXX +#define SD_FRAMEWORK_CONFIGURATION_CLASSIFIER_HXX + +#include <com/sun/star/drawing/framework/XConfiguration.hpp> + +#include <vector> + +namespace sd { namespace framework { + +/** A ConfigurationClassifier object compares two configurations of + resources and gives access to the differences. It is used mainly when + changes to the current configuration have been requested and the various + resource controllers have to be supplied with the set of resources that + are to be activated or deactivated. +*/ +class ConfigurationClassifier +{ +public: + /** Create a new ConfigurationClassifier object that will compare the + two given configurations. + */ + ConfigurationClassifier ( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration>& rxConfiguration1, + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration>& rxConfiguration2); + + /** Calculate three lists of resource ids. These contain the resources + that belong to one configuration but not the other, or that belong + to both configurations. + @return + When the two configurations differ then return <TRUE/>. When + they are equivalent then return <FALSE/>. + */ + bool Partition (void); + + typedef ::std::vector<com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XResourceId> > ResourceIdVector; + + /** Return the resources that belong to the configuration given as + rxConfiguration1 to the constructor but that do not belong to + rxConfiguration2. + @return + A reference to the, possibly empty, list of resources is + returned. This reference remains valid as long as the called + ConfigurationClassifier object stays alive. + */ + const ResourceIdVector& GetC1minusC2 (void) const; + + /** Return the resources that belong to the configuration given as + rxConfiguration2 to the constructor but that do not belong to + rxConfiguration1. + @return + A reference to the, possibly empty, list of resources is + returned. This reference remains valid as long as the called + ConfigurationClassifier object stays alive. + */ + const ResourceIdVector& GetC2minusC1 (void) const; + + /** Return the resources that belong to both the configurations that + where given to the constructor. + @return + A reference to the, possibly empty, list of resources is + returned. This reference remains valid as long as the called + ConfigurationClassifier object stays alive. + */ + const ResourceIdVector& GetC1andC2 (void) const; + + void TraceResourceIdVector ( + const sal_Char* pMessage, + const ResourceIdVector& rResources) const; + +private: + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration> mxConfiguration1; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration> mxConfiguration2; + + /** After the call to Classify() this vector holds all elements from + mxConfiguration1 that are not in mxConfiguration2. + */ + ResourceIdVector maC1minusC2; + + /** After the call to Classify() this vector holds all elements from + mxConfiguration2 that are not in mxConfiguration1. + */ + ResourceIdVector maC2minusC1; + + /** After the call to Classify() this vector holds all elements that are + member both of mxConfiguration1 and mxConfiguration2. + */ + ResourceIdVector maC1andC2; + + /** Put all the elements in the two gven sequences of resource ids and + copy them into one of the resource id result vectors maC1minusC2, + maC2minusC1, and maC1andC2. This is done by using only the resource + URLs for classification. Therefor this method calls itself + recursively. + @param rS1 + One sequence of XResourceId objects. + @param rS2 + Another sequence of XResourceId objects. + */ + void PartitionResources ( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XResourceId> >& rS1, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XResourceId> >& rS2); + + /** Compare the given sequences of resource ids and put their elements + in one of three vectors depending on whether an element belongs to + both sequences or to one but not the other. Note that only the + resource URLs of the XResourceId objects are used for the + classification. + @param rS1 + One sequence of XResourceId objects. + @param rS2 + Another sequence of XResourceId objects. + */ + void ClassifyResources ( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XResourceId> >& rS1, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XResourceId> >& rS2, + ResourceIdVector& rS1minusS2, + ResourceIdVector& rS2minusS1, + ResourceIdVector& rS1andS2); + + + /** Copy the resources given in rSource to the list of resources + specified by rTarget. Resources bound to the ones in rSource, + either directly or indirectly, are copied as well. + @param rSource + All resources and the ones bound to them, either directly or + indirectly, are copied. + @param rxConfiguration + This configuration is used to determine the resources bound to + the ones in rSource. + @param rTarget + This list is filled with resources from rSource and the ones + bound to them. + */ + void CopyResources ( + const ResourceIdVector& rSource, + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration>& rxConfiguration, + ResourceIdVector& rTarget); +}; + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/ConfigurationController.cxx b/sd/source/ui/framework/configuration/ConfigurationController.cxx new file mode 100755 index 000000000000..2f846e50be25 --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationController.cxx @@ -0,0 +1,726 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "framework/ConfigurationController.hxx" + +#include "framework/Configuration.hxx" +#include "framework/FrameworkHelper.hxx" +#include "ConfigurationUpdater.hxx" +#include "ConfigurationControllerBroadcaster.hxx" +#include "ConfigurationTracer.hxx" +#include "GenericConfigurationChangeRequest.hxx" +#include "ResourceFactoryManager.hxx" +#include "UpdateRequest.hxx" +#include "ChangeRequestQueueProcessor.hxx" +#include "ConfigurationClassifier.hxx" +#include "ViewShellBase.hxx" +#include "UpdateLockManager.hxx" +#include "DrawController.hxx" +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <comphelper/stl_types.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using rtl::OUString; +using ::sd::framework::FrameworkHelper; + +#undef VERBOSE +//#define VERBOSE 3 + + +namespace sd { namespace framework { + +Reference<XInterface> SAL_CALL ConfigurationController_createInstance ( + const Reference<XComponentContext>& rxContext) +{ + (void)rxContext; + return static_cast<XWeak*>(new ConfigurationController()); +} + + + + +OUString ConfigurationController_getImplementationName (void) throw(RuntimeException) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.comp.Draw.framework.configuration.ConfigurationController")); +} + + + + +Sequence<rtl::OUString> SAL_CALL ConfigurationController_getSupportedServiceNames (void) + throw (RuntimeException) +{ + static const OUString sServiceName(OUString::createFromAscii( + "com.sun.star.drawing.framework.ConfigurationController")); + return Sequence<rtl::OUString>(&sServiceName, 1); +} + + + + +//----- ConfigurationController::Implementation ------------------------------- + +class ConfigurationController::Implementation +{ +public: + Implementation ( + ConfigurationController& rController, + const Reference<frame::XController>& rxController); + ~Implementation (void); + + Reference<XControllerManager> mxControllerManager; + + /** The Broadcaster class implements storing and calling of listeners. + */ + ::boost::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster; + + /** The requested configuration which is modifed (asynchronously) by + calls to requestResourceActivation() and + requestResourceDeactivation(). The mpConfigurationUpdater makes the + current configuration reflect the content of this one. + */ + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration> mxRequestedConfiguration; + + ViewShellBase* mpBase; + + ::boost::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer; + + ::boost::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager; + + ::boost::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater; + + /** The queue processor ownes the queue of configuration change request + objects and processes the objects. + */ + ::boost::scoped_ptr<ChangeRequestQueueProcessor> mpQueueProcessor; + + ::boost::shared_ptr<ConfigurationUpdaterLock> mpConfigurationUpdaterLock; + + sal_Int32 mnLockCount; +}; + + + + +//===== ConfigurationController::Lock ========================================= + +ConfigurationController::Lock::Lock (const Reference<XConfigurationController>& rxController) + : mxController(rxController) +{ + OSL_ASSERT(mxController.is()); + + if (mxController.is()) + mxController->lock(); +} + + + + +ConfigurationController::Lock::~Lock (void) +{ + if (mxController.is()) + mxController->unlock(); +} + + + + +//===== ConfigurationController =============================================== + +ConfigurationController::ConfigurationController (void) throw() + : ConfigurationControllerInterfaceBase(MutexOwner::maMutex), + mpImplementation(), + mbIsDisposed(false) +{ +} + + + + +ConfigurationController::~ConfigurationController (void) throw() +{ +} + + + + +void SAL_CALL ConfigurationController::disposing (void) +{ + if (mpImplementation.get() == NULL) + return; + +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE("ConfigurationController::disposing\n"); + OSL_TRACE(" requesting empty configuration\n"); +#endif + // To destroy all resources an empty configuration is requested and then, + // synchronously, all resulting requests are processed. + mpImplementation->mpQueueProcessor->Clear(); + restoreConfiguration(new Configuration(this,false)); + mpImplementation->mpQueueProcessor->ProcessUntilEmpty(); +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE(" all requests processed\n"); +#endif + + // Now that all resources have been deactivated, mark the controller as + // disposed. + mbIsDisposed = true; + + // Release the listeners. + lang::EventObject aEvent; + aEvent.Source = uno::Reference<uno::XInterface>((cppu::OWeakObject*)this); + + { + const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); + mpImplementation->mpBroadcaster->DisposeAndClear(); + } + + mpImplementation->mpQueueProcessor.reset(); + mpImplementation->mxRequestedConfiguration = NULL; + mpImplementation.reset(); +} + + + + +void ConfigurationController::ProcessEvent (void) +{ + if (mpImplementation.get() != NULL) + { + OSL_ASSERT(mpImplementation->mpQueueProcessor.get()!=NULL); + + mpImplementation->mpQueueProcessor->ProcessOneEvent(); + } +} + + + + +void ConfigurationController::RequestSynchronousUpdate (void) +{ + if (mpImplementation.get() == NULL) + return; + if (mpImplementation->mpQueueProcessor.get() == 0) + return; + mpImplementation->mpQueueProcessor->ProcessUntilEmpty(); +} + + + + +//----- XConfigurationControllerBroadcaster ----------------------------------- + +void SAL_CALL ConfigurationController::addConfigurationChangeListener ( + const Reference<XConfigurationChangeListener>& rxListener, + const ::rtl::OUString& rsEventType, + const Any& rUserData) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + + ThrowIfDisposed(); + OSL_ASSERT(mpImplementation.get()!=NULL); + mpImplementation->mpBroadcaster->AddListener(rxListener, rsEventType, rUserData); +} + + + + +void SAL_CALL ConfigurationController::removeConfigurationChangeListener ( + const Reference<XConfigurationChangeListener>& rxListener) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + + ThrowIfDisposed(); + mpImplementation->mpBroadcaster->RemoveListener(rxListener); +} + + + + +void SAL_CALL ConfigurationController::notifyEvent ( + const ConfigurationChangeEvent& rEvent) + throw (RuntimeException) +{ + ThrowIfDisposed(); + mpImplementation->mpBroadcaster->NotifyListeners(rEvent); +} + + + + + +//----- XConfigurationController ---------------------------------------------- + +void SAL_CALL ConfigurationController::lock (void) + throw (RuntimeException) +{ + OSL_ASSERT(mpImplementation.get()!=NULL); + OSL_ASSERT(mpImplementation->mpConfigurationUpdater.get()!=NULL); + + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + + ++mpImplementation->mnLockCount; + if (mpImplementation->mpConfigurationUpdaterLock.get()==NULL) + mpImplementation->mpConfigurationUpdaterLock + = mpImplementation->mpConfigurationUpdater->GetLock(); +} + + + + +void SAL_CALL ConfigurationController::unlock (void) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Allow unlocking while the ConfigurationController is being disposed + // (but not when that is done and the controller is disposed.) + if (rBHelper.bDisposed) + ThrowIfDisposed(); + + OSL_ASSERT(mpImplementation->mnLockCount>0); + --mpImplementation->mnLockCount; + if (mpImplementation->mnLockCount == 0) + mpImplementation->mpConfigurationUpdaterLock.reset(); +} + + + + +void SAL_CALL ConfigurationController::requestResourceActivation ( + const Reference<XResourceId>& rxResourceId, + ResourceActivationMode eMode) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + // Check whether we are being disposed. This is handled differently + // then being completely disposed because the first thing disposing() + // does is to deactivate all remaining resources. This is done via + // regular methods which must not throw DisposedExceptions. Therefore + // we just return silently during that stage. + if (rBHelper.bInDispose) + { +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE("ConfigurationController::requestResourceActivation(): ignoring %s\n", + OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); +#endif + return; + } + +#if defined VERBOSE && VERBOSE>=2 + OSL_TRACE("ConfigurationController::requestResourceActivation() %s\n", + OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); +#endif + + if (rxResourceId.is()) + { + if (eMode == ResourceActivationMode_REPLACE) + { + // Get a list of the matching resources and create deactivation + // requests for them. + Sequence<Reference<XResourceId> > aResourceList ( + mpImplementation->mxRequestedConfiguration->getResources( + rxResourceId->getAnchor(), + rxResourceId->getResourceTypePrefix(), + AnchorBindingMode_DIRECT)); + + for (sal_Int32 nIndex=0; nIndex<aResourceList.getLength(); ++nIndex) + { + // Do not request the deactivation of the resource for which + // this method was called. Doing it would not change the + // outcome but would result in unnecessary work. + if (rxResourceId->compareTo(aResourceList[nIndex]) == 0) + continue; + + // Request the deactivation of a resource and all resources + // linked to it. + requestResourceDeactivation(aResourceList[nIndex]); + } + } + + Reference<XConfigurationChangeRequest> xRequest( + new GenericConfigurationChangeRequest( + rxResourceId, + GenericConfigurationChangeRequest::Activation)); + postChangeRequest(xRequest); + } +} + + + + +void SAL_CALL ConfigurationController::requestResourceDeactivation ( + const Reference<XResourceId>& rxResourceId) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + +#if defined VERBOSE && VERBOSE>=2 + OSL_TRACE("ConfigurationController::requestResourceDeactivation() %s\n", + OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); +#endif + + if (rxResourceId.is()) + { + // Request deactivation of all resources linked to the specified one + // as well. + const Sequence<Reference<XResourceId> > aLinkedResources ( + mpImplementation->mxRequestedConfiguration->getResources( + rxResourceId, + OUString(), + AnchorBindingMode_DIRECT)); + const sal_Int32 nCount (aLinkedResources.getLength()); + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + // We do not add deactivation requests directly but call this + // method recursively, so that when one time there are resources + // linked to linked resources, these are handled correctly, too. + requestResourceDeactivation(aLinkedResources[nIndex]); + } + + // Add a deactivation request for the specified resource. + Reference<XConfigurationChangeRequest> xRequest( + new GenericConfigurationChangeRequest( + rxResourceId, + GenericConfigurationChangeRequest::Deactivation)); + postChangeRequest(xRequest); + } +} + + + + +Reference<XResource> SAL_CALL ConfigurationController::getResource ( + const Reference<XResourceId>& rxResourceId) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + ConfigurationControllerResourceManager::ResourceDescriptor aDescriptor ( + mpImplementation->mpResourceManager->GetResource(rxResourceId)); + return aDescriptor.mxResource; +} + + + + +void SAL_CALL ConfigurationController::update (void) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + if (mpImplementation->mpQueueProcessor->IsEmpty()) + { + // The queue is empty. Add another request that does nothing but + // asynchronously trigger a request for an update. + mpImplementation->mpQueueProcessor->AddRequest(new UpdateRequest()); + } + else + { + // The queue is not empty, so we rely on the queue processor to + // request an update automatically when the queue becomes empty. + } +} + + + + +sal_Bool SAL_CALL ConfigurationController::hasPendingRequests (void) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + return ! mpImplementation->mpQueueProcessor->IsEmpty(); +} + + + + + +void SAL_CALL ConfigurationController::postChangeRequest ( + const Reference<XConfigurationChangeRequest>& rxRequest) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + mpImplementation->mpQueueProcessor->AddRequest(rxRequest); +} + + + + +Reference<XConfiguration> SAL_CALL ConfigurationController::getRequestedConfiguration (void) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + if (mpImplementation->mxRequestedConfiguration.is()) + return Reference<XConfiguration>( + mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY); + else + return Reference<XConfiguration>(); +} + + + + +Reference<XConfiguration> SAL_CALL ConfigurationController::getCurrentConfiguration (void) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + Reference<XConfiguration> xCurrentConfiguration( + mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration()); + if (xCurrentConfiguration.is()) + return Reference<XConfiguration>(xCurrentConfiguration->createClone(), UNO_QUERY); + else + return Reference<XConfiguration>(); +} + + + + +/** The given configuration is restored by generating the appropriate set of + activation and deactivation requests. +*/ +void SAL_CALL ConfigurationController::restoreConfiguration ( + const Reference<XConfiguration>& rxNewConfiguration) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + // We will probably be making a couple of activation and deactivation + // requests so lock the configuration controller and let it later update + // all changes at once. + ::boost::shared_ptr<ConfigurationUpdaterLock> pLock ( + mpImplementation->mpConfigurationUpdater->GetLock()); + + // Get lists of resources that are to be activated or deactivated. + Reference<XConfiguration> xCurrentConfiguration (mpImplementation->mxRequestedConfiguration); +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE("ConfigurationController::restoreConfiguration(\n"); + ConfigurationTracer::TraceConfiguration(rxNewConfiguration, "requested configuration"); + ConfigurationTracer::TraceConfiguration(xCurrentConfiguration, "current configuration"); +#endif + ConfigurationClassifier aClassifier (rxNewConfiguration, xCurrentConfiguration); + aClassifier.Partition(); +#if defined VERBOSE && VERBOSE>=3 + aClassifier.TraceResourceIdVector( + "requested but not current resources:\n", aClassifier.GetC1minusC2()); + aClassifier.TraceResourceIdVector( + "current but not requested resources:\n", aClassifier.GetC2minusC1()); + aClassifier.TraceResourceIdVector( + "requested and current resources:\n", aClassifier.GetC1andC2()); +#endif + + ConfigurationClassifier::ResourceIdVector::const_iterator iResource; + + // Request the deactivation of resources that are not requested in the + // new configuration. + const ConfigurationClassifier::ResourceIdVector& rResourcesToDeactivate ( + aClassifier.GetC2minusC1()); + for (iResource=rResourcesToDeactivate.begin(); + iResource!=rResourcesToDeactivate.end(); + ++iResource) + { + requestResourceDeactivation(*iResource); + } + + // Request the activation of resources that are requested in the + // new configuration but are not part of the current configuration. + const ConfigurationClassifier::ResourceIdVector& rResourcesToActivate ( + aClassifier.GetC1minusC2()); + for (iResource=rResourcesToActivate.begin(); + iResource!=rResourcesToActivate.end(); + ++iResource) + { + requestResourceActivation(*iResource, ResourceActivationMode_ADD); + } + + pLock.reset(); +} + + + + +//----- XResourceFactoryManager ----------------------------------------------- + +void SAL_CALL ConfigurationController::addResourceFactory( + const OUString& sResourceURL, + const Reference<XResourceFactory>& rxResourceFactory) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + mpImplementation->mpResourceFactoryContainer->AddFactory(sResourceURL, rxResourceFactory); +} + + + + +void SAL_CALL ConfigurationController::removeResourceFactoryForURL( + const OUString& sResourceURL) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + mpImplementation->mpResourceFactoryContainer->RemoveFactoryForURL(sResourceURL); +} + + + + +void SAL_CALL ConfigurationController::removeResourceFactoryForReference( + const Reference<XResourceFactory>& rxResourceFactory) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory); +} + + + + +Reference<XResourceFactory> SAL_CALL ConfigurationController::getResourceFactory ( + const OUString& sResourceURL) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + ThrowIfDisposed(); + + return mpImplementation->mpResourceFactoryContainer->GetFactory(sResourceURL); +} + + + + +//----- XInitialization ------------------------------------------------------- + +void SAL_CALL ConfigurationController::initialize (const Sequence<Any>& aArguments) + throw (Exception, RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + + if (aArguments.getLength() == 1) + { + const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); + + mpImplementation.reset(new Implementation( + *this, + Reference<frame::XController>(aArguments[0], UNO_QUERY_THROW))); + } +} + + + + +//----------------------------------------------------------------------------- + +void ConfigurationController::ThrowIfDisposed (void) const + throw (::com::sun::star::lang::DisposedException) +{ + if (mbIsDisposed) + { + throw lang::DisposedException ( + OUString(RTL_CONSTASCII_USTRINGPARAM( + "ConfigurationController object has already been disposed")), + const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this))); + } + + if (mpImplementation.get() == NULL) + { + OSL_ASSERT(mpImplementation.get() != NULL); + throw RuntimeException( + OUString(RTL_CONSTASCII_USTRINGPARAM( + "ConfigurationController not initialized")), + const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this))); + } +} + + + + +//===== ConfigurationController::Implementation =============================== + +ConfigurationController::Implementation::Implementation ( + ConfigurationController& rController, + const Reference<frame::XController>& rxController) + : mxControllerManager(rxController, UNO_QUERY_THROW), + mpBroadcaster(new ConfigurationControllerBroadcaster(&rController)), + mxRequestedConfiguration(new Configuration(&rController, true)), + mpBase(NULL), + mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager)), + mpResourceManager( + new ConfigurationControllerResourceManager(mpResourceFactoryContainer,mpBroadcaster)), + mpConfigurationUpdater( + new ConfigurationUpdater(mpBroadcaster, mpResourceManager,mxControllerManager)), + mpQueueProcessor(new ChangeRequestQueueProcessor(&rController,mpConfigurationUpdater)), + mpConfigurationUpdaterLock(), + mnLockCount(0) +{ + mpQueueProcessor->SetConfiguration(mxRequestedConfiguration); +} + + + + +ConfigurationController::Implementation::~Implementation (void) +{ +} + + + + +} } // end of namespace sd::framework diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx new file mode 100755 index 000000000000..ff167f07520a --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx @@ -0,0 +1,231 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "ConfigurationControllerBroadcaster.hxx" +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using rtl::OUString; + +namespace sd { namespace framework { + +ConfigurationControllerBroadcaster::ConfigurationControllerBroadcaster ( + const Reference<XConfigurationController>& rxController) + : mxConfigurationController(rxController), + maListenerMap() +{ +} + + + + +void ConfigurationControllerBroadcaster::AddListener( + const Reference<XConfigurationChangeListener>& rxListener, + const ::rtl::OUString& rsEventType, + const Any& rUserData) +{ + if ( ! rxListener.is()) + throw lang::IllegalArgumentException( + OUString::createFromAscii("invalid listener"), + mxConfigurationController, + 0); + + if (maListenerMap.find(rsEventType) == maListenerMap.end()) + maListenerMap[rsEventType] = ListenerList(); + ListenerDescriptor aDescriptor; + aDescriptor.mxListener = rxListener; + aDescriptor.maUserData = rUserData; + maListenerMap[rsEventType].push_back(aDescriptor); +} + + + + +void ConfigurationControllerBroadcaster::RemoveListener( + const Reference<XConfigurationChangeListener>& rxListener) +{ + if ( ! rxListener.is()) + throw lang::IllegalArgumentException( + OUString::createFromAscii("invalid listener"), + mxConfigurationController, + 0); + + ListenerMap::iterator iMap; + ListenerList::iterator iList; + for (iMap=maListenerMap.begin(); iMap!=maListenerMap.end(); ++iMap) + { + for (iList=iMap->second.begin(); iList!=iMap->second.end(); ++iList) + { + if (iList->mxListener == rxListener) + { + iMap->second.erase(iList); + break; + } + } + } +} + + + + +void ConfigurationControllerBroadcaster::NotifyListeners ( + const ListenerList& rList, + const ConfigurationChangeEvent& rEvent) +{ + // Create a local copy of the event in which the user data is modified + // for every listener. + ConfigurationChangeEvent aEvent (rEvent); + + ListenerList::const_iterator iListener; + for (iListener=rList.begin(); iListener!=rList.end(); ++iListener) + { + try + { + aEvent.UserData = iListener->maUserData; + iListener->mxListener->notifyConfigurationChange(aEvent); + } + catch (lang::DisposedException& rException) + { + // When the exception comes from the listener itself then + // unregister it. + if (rException.Context == iListener->mxListener) + RemoveListener(iListener->mxListener); + } + catch(RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } +} + + + + +void ConfigurationControllerBroadcaster::NotifyListeners (const ConfigurationChangeEvent& rEvent) +{ + // Notify the specialized listeners. + ListenerMap::const_iterator iMap (maListenerMap.find(rEvent.Type)); + if (iMap != maListenerMap.end()) + { + // Create a local list of the listeners to avoid problems with + // concurrent changes and to be able to remove disposed listeners. + ListenerList aList (iMap->second.begin(), iMap->second.end()); + NotifyListeners(aList,rEvent); + } + + // Notify the universal listeners. + iMap = maListenerMap.find(OUString()); + if (iMap != maListenerMap.end()) + { + // Create a local list of the listeners to avoid problems with + // concurrent changes and to be able to remove disposed listeners. + ListenerList aList (iMap->second.begin(), iMap->second.end()); + NotifyListeners(aList,rEvent); + } +} + + + + +void ConfigurationControllerBroadcaster::NotifyListeners ( + const OUString& rsEventType, + const Reference<XResourceId>& rxResourceId, + const Reference<XResource>& rxResourceObject) +{ + ConfigurationChangeEvent aEvent; + aEvent.Type = rsEventType; + aEvent.ResourceId = rxResourceId; + aEvent.ResourceObject = rxResourceObject; + try + { + NotifyListeners(aEvent); + } + catch (lang::DisposedException) + { + } +} + + + + + +void ConfigurationControllerBroadcaster::DisposeAndClear (void) +{ + lang::EventObject aEvent; + aEvent.Source = mxConfigurationController; + while (maListenerMap.size() > 0) + { + ListenerMap::iterator iMap (maListenerMap.begin()); + if (iMap == maListenerMap.end()) + break; + + // When the first vector is empty then remove it from the map. + if (iMap->second.size() == 0) + { + maListenerMap.erase(iMap); + continue; + } + else + { + Reference<lang::XEventListener> xListener ( + iMap->second.front().mxListener, UNO_QUERY); + if (xListener.is()) + { + // Tell the listener that the configuration controller is + // being disposed and remove the listener (for all event + // types). + try + { + RemoveListener(iMap->second.front().mxListener); + xListener->disposing(aEvent); + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + else + { + // Remove just this reference to the listener. + iMap->second.erase(iMap->second.begin()); + } + } + } +} + + + + +} } // end of namespace sd::framework + diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx new file mode 100644 index 000000000000..a5939386d7b7 --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx @@ -0,0 +1,151 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_CONFIGURATION_CONTROLLER_BROADCASTER_HXX +#define SD_FRAMEWORK_CONFIGURATION_CONTROLLER_BROADCASTER_HXX + +#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp> +#include <com/sun/star/drawing/framework/XConfigurationController.hpp> +#include <com/sun/star/drawing/framework/ConfigurationChangeEvent.hpp> + +#include <comphelper/stl_types.hxx> +#include <vector> +#include <hash_map> + +namespace css = ::com::sun::star; + +namespace sd { namespace framework { + +/** This class manages the set of XConfigurationChangeListeners and + calls them when the ConfigurationController wants to broadcast an + event. + + For every registered combination of listener and event type a user data + object is stored. This user data object is then given to the listener + whenever it is called for an event. With this the listener can use + a switch statement to handle different event types. +*/ +class ConfigurationControllerBroadcaster +{ +public: + /** The given controller is used as origin of thrown exceptions. + */ + ConfigurationControllerBroadcaster ( + const css::uno::Reference< + css::drawing::framework::XConfigurationController>& rxController); + + /** Add a listener for one type of event. When one listener is + interested in more than one event type this method has to be called + once for every event type. Alternatively it can register as + universal listener that will be called for all event types. + @param rxListener + A valid reference to a listener. + @param rsEventType + The type of event that the listener will be called for. The + empty string is a special value in that the listener will be + called for all event types. + @param rUserData + This object is passed to the listener whenever it is called for + the specified event type. For different event types different + user data objects can be provided. + @throws IllegalArgumentException + when an empty listener reference is given. + */ + void AddListener( + const css::uno::Reference< + css::drawing::framework::XConfigurationChangeListener>& rxListener, + const ::rtl::OUString& rsEventType, + const css::uno::Any& rUserData); + + /** Remove all references to the given listener. When one listener has + been registered for more than one type of event then it is removed + for all of them. + @param rxListener + A valid reference to a listener. + @throws IllegalArgumentException + when an empty listener reference is given. + */ + void RemoveListener( + const css::uno::Reference< + css::drawing::framework::XConfigurationChangeListener>& rxListener); + + /** Broadcast the given event to all listeners that have been registered + for its type of event as well as all universal listeners. + + When calling a listener results in a DisposedException being thrown + the listener is unregistered automatically. + */ + void NotifyListeners ( + const css::drawing::framework::ConfigurationChangeEvent& rEvent); + + /** This convenience variant of NotifyListeners create the event from + the given arguments. + */ + void NotifyListeners ( + const ::rtl::OUString& rsEventType, + const ::css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId, + const ::css::uno::Reference<css::drawing::framework::XResource>& rxResourceObject); + + /** Call all listeners and inform them that the + ConfigurationController is being disposed. When this method returns + the list of registered listeners is empty. Further calls to + RemoveListener() are not necessary but do not result in an error. + */ + void DisposeAndClear (void); + +private: + css::uno::Reference< + com::sun::star::drawing::framework::XConfigurationController> mxConfigurationController; + class ListenerDescriptor {public: + css::uno::Reference< + css::drawing::framework::XConfigurationChangeListener> mxListener; + css::uno::Any maUserData; + }; + typedef ::std::vector<ListenerDescriptor> ListenerList; + typedef ::std::hash_map + <rtl::OUString, + ListenerList, + ::comphelper::UStringHash, + ::comphelper::UStringEqual> ListenerMap; + ListenerMap maListenerMap; + + /** Broadcast the given event to all listeners in the given list. + + When calling a listener results in a DisposedException being thrown + the listener is unregistered automatically. + */ + void NotifyListeners ( + const ListenerList& rList, + const css::drawing::framework::ConfigurationChangeEvent& rEvent); +}; + + + + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx new file mode 100755 index 000000000000..93ff7ee54e00 --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx @@ -0,0 +1,352 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "ConfigurationControllerResourceManager.hxx" +#include "ConfigurationControllerBroadcaster.hxx" +#include "ResourceFactoryManager.hxx" +#include "framework/FrameworkHelper.hxx" +#include <com/sun/star/lang/DisposedException.hpp> +#include <tools/diagnose_ex.h> +#include <algorithm> +#include <boost/bind.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::rtl::OUString; + +#undef VERBOSE +//#define VERBOSE 1 + +namespace sd { namespace framework { + +//===== ConfigurationControllerResourceManager ================================ + +ConfigurationControllerResourceManager::ConfigurationControllerResourceManager ( + const ::boost::shared_ptr<ResourceFactoryManager>& rpResourceFactoryContainer, + const ::boost::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster) + : maResourceMap(ResourceComparator()), + mpResourceFactoryContainer(rpResourceFactoryContainer), + mpBroadcaster(rpBroadcaster) +{ +} + + + + +ConfigurationControllerResourceManager::~ConfigurationControllerResourceManager (void) +{ +} + + + + +ConfigurationControllerResourceManager::ResourceDescriptor + ConfigurationControllerResourceManager::GetResource ( + const Reference<XResourceId>& rxResourceId) +{ + ::osl::MutexGuard aGuard (maMutex); + ResourceMap::const_iterator iResource (maResourceMap.find(rxResourceId)); + if (iResource != maResourceMap.end()) + return iResource->second; + else + return ResourceDescriptor(); +} + + + + +void ConfigurationControllerResourceManager::ActivateResources ( + const ::std::vector<Reference<XResourceId> >& rResources, + const Reference<XConfiguration>& rxConfiguration) +{ + ::osl::MutexGuard aGuard (maMutex); + // Iterate in normal order over the resources that are to be + // activated so that resources on which others depend are activated + // beforet the depending resources are activated. + ::std::for_each( + rResources.begin(), + rResources.end(), + ::boost::bind(&ConfigurationControllerResourceManager::ActivateResource, + this, _1, rxConfiguration)); +} + + + + +void ConfigurationControllerResourceManager::DeactivateResources ( + const ::std::vector<Reference<XResourceId> >& rResources, + const Reference<XConfiguration>& rxConfiguration) +{ + ::osl::MutexGuard aGuard (maMutex); + // Iterate in reverese order over the resources that are to be + // deactivated so that resources on which others depend are deactivated + // only when the depending resources have already been deactivated. + ::std::for_each( + rResources.rbegin(), + rResources.rend(), + ::boost::bind(&ConfigurationControllerResourceManager::DeactivateResource, + this, _1, rxConfiguration)); +} + + + + +/* In this method we do following steps. + 1. Get the factory with which the resource will be created. + 2. Create the resource. + 3. Add the resource to the URL->Object map of the configuration + controller. + 4. Add the resource id to the current configuration. + 5. Notify listeners. +*/ +void ConfigurationControllerResourceManager::ActivateResource ( + const Reference<XResourceId>& rxResourceId, + const Reference<XConfiguration>& rxConfiguration) +{ + if ( ! rxResourceId.is()) + { + OSL_ASSERT(rxResourceId.is()); + return; + } + +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE("activating resource %s\n", OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); +#endif + + // 1. Get the factory. + const OUString sResourceURL (rxResourceId->getResourceURL()); + Reference<XResourceFactory> xFactory (mpResourceFactoryContainer->GetFactory(sResourceURL)); + if ( ! xFactory.is()) + { +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE(" no factory found fo %s\n", + OUStringToOString(sResourceURL, RTL_TEXTENCODING_UTF8).getStr()); +#endif + return; + } + + try + { + // 2. Create the resource. + Reference<XResource> xResource; + try + { + xResource = xFactory->createResource(rxResourceId); + } + catch (lang::DisposedException&) + { + // The factory is disposed and can be removed from the list + // of registered factories. + mpResourceFactoryContainer->RemoveFactoryForReference(xFactory); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if (xResource.is()) + { +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE(" successfully created\n"); +#endif + // 3. Add resource to URL->Object map. + AddResource(xResource, xFactory); + + // 4. Add resource id to current configuration. + rxConfiguration->addResource(rxResourceId); + + // 5. Notify the new resource to listeners of the ConfigurationController. + mpBroadcaster->NotifyListeners( + FrameworkHelper::msResourceActivationEvent, + rxResourceId, + xResource); + } + else + { +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE(" resource creation failed\n"); +#endif + } + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + + + + +/* In this method we do following steps. + 1. Remove the resource from the URL->Object map of the configuration + controller. + 2. Notify listeners. + 3. Remove the resource id from the current configuration. + 4. Release the resource. +*/ +void ConfigurationControllerResourceManager::DeactivateResource ( + const Reference<XResourceId>& rxResourceId, + const Reference<XConfiguration>& rxConfiguration) +{ + if ( ! rxResourceId.is()) + return; + + bool bSuccess (false); + try + { + // 1. Remove resource from URL->Object map. + ResourceDescriptor aDescriptor (RemoveResource(rxResourceId)); + + if (aDescriptor.mxResource.is() && aDescriptor.mxResourceFactory.is()) + { + // 2. Notifiy listeners that the resource is being deactivated. + mpBroadcaster->NotifyListeners( + FrameworkHelper::msResourceDeactivationEvent, + rxResourceId, + aDescriptor.mxResource); + + // 3. Remove resource id from current configuration. + rxConfiguration->removeResource(rxResourceId); + + // 4. Release the resource. + try + { + aDescriptor.mxResourceFactory->releaseResource(aDescriptor.mxResource); + } + catch (lang::DisposedException& rException) + { + if ( ! rException.Context.is() + || rException.Context == aDescriptor.mxResourceFactory) + { + // The factory is disposed and can be removed from the + // list of registered factories. + mpResourceFactoryContainer->RemoveFactoryForReference( + aDescriptor.mxResourceFactory); + } + } + + bSuccess = true; + } + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION(); + } + +#if defined VERBOSE && VERBOSE>=1 + if (bSuccess) + OSL_TRACE("successfully deactivated %s\n", OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); + else + OSL_TRACE("activating resource %s failed\n", OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); +#endif +} + + + + +void ConfigurationControllerResourceManager::AddResource ( + const Reference<XResource>& rxResource, + const Reference<XResourceFactory>& rxFactory) +{ + if ( ! rxResource.is()) + { + OSL_ASSERT(rxResource.is()); + return; + } + + // Add the resource to the resource container. + ResourceDescriptor aDescriptor; + aDescriptor.mxResource = rxResource; + aDescriptor.mxResourceFactory = rxFactory; + maResourceMap[rxResource->getResourceId()] = aDescriptor; + +#if defined VERBOSE && VERBOSE>=2 + OSL_TRACE("ConfigurationControllerResourceManager::AddResource(): added %s -> %x\n", + OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResource->getResourceId()), + RTL_TEXTENCODING_UTF8).getStr(), + rxResource.get()); +#endif +} + + + + +ConfigurationControllerResourceManager::ResourceDescriptor + ConfigurationControllerResourceManager::RemoveResource ( + const Reference<XResourceId>& rxResourceId) +{ + ResourceDescriptor aDescriptor; + + ResourceMap::iterator iResource (maResourceMap.find(rxResourceId)); + if (iResource != maResourceMap.end()) + { +#if defined VERBOSE && VERBOSE>=2 + OSL_TRACE("ConfigurationControllerResourceManager::RemoveResource(): removing %s -> %x\n", + OUStringToOString( + FrameworkHelper::ResourceIdToString(rxResourceId), + RTL_TEXTENCODING_UTF8).getStr(), + *iResource); +#endif + + aDescriptor = iResource->second; + maResourceMap.erase(rxResourceId); + } + + return aDescriptor; +} + + + + +//===== ConfigurationControllerResourceManager::ResourceComparator ============ + +bool ConfigurationControllerResourceManager::ResourceComparator::operator() ( + const Reference<XResourceId>& rxId1, + const Reference<XResourceId>& rxId2) const +{ + if (rxId1.is() && rxId2.is()) + return rxId1->compareTo(rxId2)<0; + else if (rxId1.is()) + return true; + else if (rxId2.is()) + return false; + else + return false; +} + + + + +} } // end of namespace sd::framework + diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx new file mode 100644 index 000000000000..0c095df50fdf --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx @@ -0,0 +1,145 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_RESOURCE_MANAGER_HXX +#define SD_FRAMEWORK_RESOURCE_MANAGER_HXX + +#include <com/sun/star/drawing/framework/XConfiguration.hpp> +#include <com/sun/star/drawing/framework/XResource.hpp> +#include <com/sun/star/drawing/framework/XResourceFactory.hpp> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <map> +#include <vector> + +namespace css = ::com::sun::star; + +namespace sd { namespace framework { + +class ConfigurationControllerBroadcaster; +class ResourceFactoryManager; + +/** Manage the set of active resources. Activate and deactivate resources. +*/ +class ConfigurationControllerResourceManager + : ::boost::noncopyable +{ +public: + /** For every active resource both the resource itself as well as its + creating factory are remembered, so that on deactivation, the + resource can be deactivated by this factory. + */ + class ResourceDescriptor + { + public: + css::uno::Reference<css::drawing::framework::XResource> mxResource; + css::uno::Reference<css::drawing::framework::XResourceFactory> mxResourceFactory; + }; + + /** A new ResourceManager object is created with the resource factory + container for creating resources and the event broadcaster for + notifying ConfigurationChangeListeners of activated or deactivated + resources. + */ + ConfigurationControllerResourceManager ( + const ::boost::shared_ptr<ResourceFactoryManager>& rpResourceFactoryContainer, + const ::boost::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster); + + ~ConfigurationControllerResourceManager (void); + + /** Activate all the resources that are specified by resource ids in + rResources. The resource ids of activated resources are added to + the given configuration. Activated resources are notified to all + interested ConfigurationChangeListeners. + */ + void ActivateResources ( + const ::std::vector< + css::uno::Reference<css::drawing::framework::XResourceId> >& rResources, + const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration); + + /** Deactivate all the resources that are specified by resource ids in + rResources. The resource ids of deactivated resources are removed + from the given configuration. Activated resources are notified to all + interested ConfigurationChangeListeners. + */ + void DeactivateResources ( + const ::std::vector< + css::uno::Reference<css::drawing::framework::XResourceId> >& rResources, + const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration); + + /** Return the descriptor for the specified resource. + @return + When there is no active resource for the given resource id then + an empty descriptor is returned. + */ + ResourceDescriptor GetResource ( + const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId); + +private: + osl::Mutex maMutex; + + class ResourceComparator + { + public: + bool operator() ( + const css::uno::Reference<css::drawing::framework::XResourceId>& rxId1, + const css::uno::Reference<css::drawing::framework::XResourceId>& rxId2) const; + }; + + typedef ::std::map< + css::uno::Reference<css::drawing::framework::XResourceId>, + ResourceDescriptor, + ResourceComparator> ResourceMap; + ResourceMap maResourceMap; + + ::boost::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer; + + /** This broadcaster is used to notify the activation and deactivation + of resources. + */ + ::boost::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster; + + void ActivateResource ( + const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId, + const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration); + + void DeactivateResource ( + const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId, + const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration); + + void AddResource ( + const css::uno::Reference<css::drawing::framework::XResource>& rxResource, + const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory); + + ResourceDescriptor RemoveResource ( + const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId); +}; + + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/ConfigurationTracer.cxx b/sd/source/ui/framework/configuration/ConfigurationTracer.cxx new file mode 100755 index 000000000000..b9552940060e --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationTracer.cxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "ConfigurationTracer.hxx" + +#include <cstdio> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +namespace sd { namespace framework { + +void ConfigurationTracer::TraceConfiguration ( + const Reference<XConfiguration>& rxConfiguration, + const char* pMessage) +{ +#ifdef DEBUG + OSL_TRACE("%s at %p {", pMessage, rxConfiguration.get()); + if (rxConfiguration.is()) + { + TraceBoundResources(rxConfiguration, NULL, 0); + } + else + { + OSL_TRACE(" empty"); + } + OSL_TRACE("}"); +#else + (void)rxConfiguration; + (void)pMessage; +#endif +} + + + + +#ifdef DEBUG +void ConfigurationTracer::TraceBoundResources ( + const Reference<XConfiguration>& rxConfiguration, + const Reference<XResourceId>& rxResourceId, + const int nIndentation) +{ + Sequence<Reference<XResourceId> > aResourceList ( + rxConfiguration->getResources(rxResourceId, ::rtl::OUString(), AnchorBindingMode_DIRECT)); + const ::rtl::OUString sIndentation (::rtl::OUString::createFromAscii(" ")); + for (sal_Int32 nIndex=0; nIndex<aResourceList.getLength(); ++nIndex) + { + ::rtl::OUString sLine (aResourceList[nIndex]->getResourceURL()); + for (int i=0; i<nIndentation; ++i) + sLine = sIndentation + sLine; + OSL_TRACE("%s", OUStringToOString(sLine, RTL_TEXTENCODING_UTF8).getStr()); + TraceBoundResources(rxConfiguration, aResourceList[nIndex], nIndentation+1); + } +} +#endif + +} } // end of namespace sd::framework diff --git a/sd/source/ui/framework/configuration/ConfigurationTracer.hxx b/sd/source/ui/framework/configuration/ConfigurationTracer.hxx new file mode 100755 index 000000000000..b04206fd65e1 --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationTracer.hxx @@ -0,0 +1,57 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_CONFIGURATION_TRACER_HXX +#define SD_FRAMEWORK_CONFIGURATION_TRACER_HXX + +#include <com/sun/star/drawing/framework/XConfiguration.hpp> + +namespace sd { namespace framework { + +/** Print debug information about configurations to the standard error + output channel. +*/ +class ConfigurationTracer +{ +public: + static void TraceConfiguration ( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration>& rxConfiguration, + const char* pMessage); +#ifdef DEBUG + static void TraceBoundResources ( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XConfiguration>& rxConfiguration, + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::framework::XResourceId>& rxResourceId, + const int nIndentation); +#endif +}; + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx b/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx new file mode 100755 index 000000000000..4ab361a9490d --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx @@ -0,0 +1,468 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "ConfigurationUpdater.hxx" +#include "ConfigurationTracer.hxx" +#include "ConfigurationClassifier.hxx" +#include "ConfigurationControllerBroadcaster.hxx" +#include "framework/Configuration.hxx" +#include "framework/FrameworkHelper.hxx" + +#include <comphelper/scopeguard.hxx> +#include <tools/diagnose_ex.h> + +#include <boost/bind.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::sd::framework::FrameworkHelper; +using ::rtl::OUString; +using ::std::vector; + +#undef VERBOSE +//#define VERBOSE 2 + +namespace { +static const sal_Int32 snShortTimeout (100); +static const sal_Int32 snNormalTimeout (1000); +static const sal_Int32 snLongTimeout (10000); +static const sal_Int32 snShortTimeoutCountThreshold (1); +static const sal_Int32 snNormalTimeoutCountThreshold (5); +} + +namespace sd { namespace framework { + + +//===== ConfigurationUpdaterLock ============================================== + +class ConfigurationUpdaterLock +{ +public: + ConfigurationUpdaterLock (ConfigurationUpdater& rUpdater) + : mrUpdater(rUpdater) { mrUpdater.LockUpdates(); } + ~ConfigurationUpdaterLock(void) { mrUpdater.UnlockUpdates(); } +private: + ConfigurationUpdater& mrUpdater; +}; + + + + +//===== ConfigurationUpdater ================================================== + +ConfigurationUpdater::ConfigurationUpdater ( + const ::boost::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster, + const ::boost::shared_ptr<ConfigurationControllerResourceManager>& rpResourceManager, + const Reference<XControllerManager>& rxControllerManager) + : mxControllerManager(), + mpBroadcaster(rpBroadcaster), + mxCurrentConfiguration(Reference<XConfiguration>(new Configuration(NULL, false))), + mxRequestedConfiguration(), + mbUpdatePending(false), + mbUpdateBeingProcessed(false), + mnLockCount(0), + maUpdateTimer(), + mnFailedUpdateCount(0), + mpResourceManager(rpResourceManager) +{ + // Prepare the timer that is started when after an update the current + // and the requested configuration differ. With the timer we try + // updates until the two configurations are the same. + maUpdateTimer.SetTimeout(snNormalTimeout); + maUpdateTimer.SetTimeoutHdl(LINK(this,ConfigurationUpdater,TimeoutHandler)); + SetControllerManager(rxControllerManager); +} + + + + +ConfigurationUpdater::~ConfigurationUpdater (void) +{ + maUpdateTimer.Stop(); +} + + + + +void ConfigurationUpdater::SetControllerManager( + const Reference<XControllerManager>& rxControllerManager) +{ + mxControllerManager = rxControllerManager; +} + + + + +void ConfigurationUpdater::RequestUpdate ( + const Reference<XConfiguration>& rxRequestedConfiguration) +{ + mxRequestedConfiguration = rxRequestedConfiguration; + + // Find out whether we really can update the configuration. + if (IsUpdatePossible()) + { +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE("UpdateConfiguration start"); +#endif + + // Call UpdateConfiguration while that is possible and while someone + // set mbUpdatePending to true in the middle of it. + do + { + UpdateConfiguration(); + + if (mbUpdatePending && IsUpdatePossible()) + continue; + } + while (false); + } + else + { + mbUpdatePending = true; +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE("scheduling update for later"); +#endif + } +} + + + + +Reference<XConfiguration> ConfigurationUpdater::GetCurrentConfiguration (void) const +{ + return mxCurrentConfiguration; +} + + + + +bool ConfigurationUpdater::IsUpdatePossible (void) +{ + return ! mbUpdateBeingProcessed + && mxControllerManager.is() + && mnLockCount==0 + && mxRequestedConfiguration.is() + && mxCurrentConfiguration.is(); +} + + + + +void ConfigurationUpdater::UpdateConfiguration (void) +{ +#if defined VERBOSE && VERBOSE>=1 + OSL_TRACE("UpdateConfiguration update"); +#endif + SetUpdateBeingProcessed(true); + comphelper::ScopeGuard aScopeGuard ( + ::boost::bind(&ConfigurationUpdater::SetUpdateBeingProcessed, this, false)); + + try + { + mbUpdatePending = false; + + CleanRequestedConfiguration(); + ConfigurationClassifier aClassifier(mxRequestedConfiguration, mxCurrentConfiguration); + if (aClassifier.Partition()) + { +#if defined VERBOSE && VERBOSE>=2 + OSL_TRACE("ConfigurationUpdater::UpdateConfiguration("); + ConfigurationTracer::TraceConfiguration( + mxRequestedConfiguration, "requested configuration"); + ConfigurationTracer::TraceConfiguration( + mxCurrentConfiguration, "current configuration"); +#endif + // Notify the begining of the update. + ConfigurationChangeEvent aEvent; + aEvent.Type = FrameworkHelper::msConfigurationUpdateStartEvent; + aEvent.Configuration = mxRequestedConfiguration; + mpBroadcaster->NotifyListeners(aEvent); + + // Do the actual update. All exceptions are caught and ignored, + // so that the the end of the update is notified always. + try + { + if (mnLockCount == 0) + UpdateCore(aClassifier); + } + catch(RuntimeException) + { + } + + // Notify the end of the update. + aEvent.Type = FrameworkHelper::msConfigurationUpdateEndEvent; + mpBroadcaster->NotifyListeners(aEvent); + + CheckUpdateSuccess(); + } + else + { +#if defined VERBOSE && VERBOSE>0 + OSL_TRACE("nothing to do"); +#if defined VERBOSE && VERBOSE>=2 + ConfigurationTracer::TraceConfiguration( + mxRequestedConfiguration, "requested configuration"); + ConfigurationTracer::TraceConfiguration( + mxCurrentConfiguration, "current configuration"); +#endif +#endif + } + } + catch (RuntimeException e) + { + DBG_UNHANDLED_EXCEPTION(); + } + +#if defined VERBOSE && VERBOSE>0 + OSL_TRACE("ConfigurationUpdater::UpdateConfiguration)"); + OSL_TRACE("UpdateConfiguration end"); +#endif +} + + + + +void ConfigurationUpdater::CleanRequestedConfiguration (void) +{ + if (mxControllerManager.is()) + { + // Request the deactivation of pure anchors that have no child. + vector<Reference<XResourceId> > aResourcesToDeactivate; + CheckPureAnchors(mxRequestedConfiguration, aResourcesToDeactivate); + if (aResourcesToDeactivate.size() > 0) + { + Reference<XConfigurationController> xCC ( + mxControllerManager->getConfigurationController()); + vector<Reference<XResourceId> >::iterator iId; + for (iId=aResourcesToDeactivate.begin(); iId!=aResourcesToDeactivate.end(); ++iId) + if (iId->is()) + xCC->requestResourceDeactivation(*iId); + } + } +} + + + + +void ConfigurationUpdater::CheckUpdateSuccess (void) +{ + // When the two configurations differ then start the timer to call + // another update later. + if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration)) + { + if (mnFailedUpdateCount <= snShortTimeoutCountThreshold) + maUpdateTimer.SetTimeout(snShortTimeout); + else if (mnFailedUpdateCount < snNormalTimeoutCountThreshold) + maUpdateTimer.SetTimeout(snNormalTimeout); + else + maUpdateTimer.SetTimeout(snLongTimeout); + ++mnFailedUpdateCount; + maUpdateTimer.Start(); + } + else + { + // Update was successfull. Reset the failed update count. + mnFailedUpdateCount = 0; + } +} + + + + +void ConfigurationUpdater::UpdateCore (const ConfigurationClassifier& rClassifier) +{ + try + { +#if defined VERBOSE && VERBOSE>=2 + rClassifier.TraceResourceIdVector( + "requested but not current resources:", rClassifier.GetC1minusC2()); + rClassifier.TraceResourceIdVector( + "current but not requested resources:", rClassifier.GetC2minusC1()); + rClassifier.TraceResourceIdVector( + "requested and current resources:", rClassifier.GetC1andC2()); +#endif + + // Updating of the sub controllers is done in two steps. In the + // first the sub controllers typically shut down resources that are + // not requested anymore. In the second the sub controllers + // typically set up resources that have been newly requested. + mpResourceManager->DeactivateResources(rClassifier.GetC2minusC1(), mxCurrentConfiguration); + mpResourceManager->ActivateResources(rClassifier.GetC1minusC2(), mxCurrentConfiguration); + +#if defined VERBOSE && VERBOSE>=2 + OSL_TRACE("ConfigurationController::UpdateConfiguration)"); + ConfigurationTracer::TraceConfiguration( + mxRequestedConfiguration, "requested configuration"); + ConfigurationTracer::TraceConfiguration( + mxCurrentConfiguration, "current configuration"); +#endif + + // Deactivate pure anchors that have no child. + vector<Reference<XResourceId> > aResourcesToDeactivate; + CheckPureAnchors(mxCurrentConfiguration, aResourcesToDeactivate); + if (aResourcesToDeactivate.size() > 0) + mpResourceManager->DeactivateResources(aResourcesToDeactivate, mxCurrentConfiguration); + } + catch(RuntimeException) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + + + + +void ConfigurationUpdater::CheckPureAnchors ( + const Reference<XConfiguration>& rxConfiguration, + vector<Reference<XResourceId> >& rResourcesToDeactivate) +{ + if ( ! rxConfiguration.is()) + return; + + // Get a list of all resources in the configuration. + Sequence<Reference<XResourceId> > aResources( + rxConfiguration->getResources( + NULL, OUString(), AnchorBindingMode_INDIRECT)); + sal_Int32 nCount (aResources.getLength()); + + // Prepare the list of pure anchors that have to be deactivated. + rResourcesToDeactivate.clear(); + + // Iterate over the list in reverse order because when there is a chain + // of pure anchors with only the last one having no child then the whole + // list has to be deactivated. + sal_Int32 nIndex (nCount-1); + while (nIndex >= 0) + { + const Reference<XResourceId> xResourceId (aResources[nIndex]); + const Reference<XResource> xResource ( + mpResourceManager->GetResource(xResourceId).mxResource); + bool bDeactiveCurrentResource (false); + + // Skip all resources that are no pure anchors. + if (xResource.is() && xResource->isAnchorOnly()) + { + // When xResource is not an anchor of the the next resource in + // the list then it is the anchor of no resource at all. + if (nIndex == nCount-1) + { + // No following anchors, deactivate this one, then remove it + // from the list. + bDeactiveCurrentResource = true; + } + else + { + const Reference<XResourceId> xPrevResourceId (aResources[nIndex+1]); + if ( ! xPrevResourceId.is() + || ! xPrevResourceId->isBoundTo(xResourceId, AnchorBindingMode_DIRECT)) + { + // The previous resource (id) does not exist or is not bound to + // the current anchor. + bDeactiveCurrentResource = true; + } + } + } + + if (bDeactiveCurrentResource) + { +#if defined VERBOSE && VERBOSE>=2 + OSL_TRACE("deactiving pure anchor %s because it has no children", + OUStringToOString( + FrameworkHelper::ResourceIdToString(xResourceId), + RTL_TEXTENCODING_UTF8).getStr()); +#endif + // Erase element from current configuration. + for (sal_Int32 nI=nIndex; nI<nCount-2; ++nI) + aResources[nI] = aResources[nI+1]; + nCount -= 1; + + rResourcesToDeactivate.push_back(xResourceId); + } + nIndex -= 1; + } +} + + + + +void ConfigurationUpdater::LockUpdates (void) +{ + ++mnLockCount; +} + + + + +void ConfigurationUpdater::UnlockUpdates (void) +{ + --mnLockCount; + if (mnLockCount == 0 && mbUpdatePending) + { + RequestUpdate(mxRequestedConfiguration); + } +} + + + + +::boost::shared_ptr<ConfigurationUpdaterLock> ConfigurationUpdater::GetLock (void) +{ + return ::boost::shared_ptr<ConfigurationUpdaterLock>(new ConfigurationUpdaterLock(*this)); +} + + + + +void ConfigurationUpdater::SetUpdateBeingProcessed (bool bValue) +{ + mbUpdateBeingProcessed = bValue; +} + + + + +IMPL_LINK(ConfigurationUpdater, TimeoutHandler, Timer*, EMPTYARG) +{ + OSL_TRACE("configuration update timer"); + if ( ! mbUpdateBeingProcessed + && mxCurrentConfiguration.is() + && mxRequestedConfiguration.is()) + { + if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration)) + { + OSL_TRACE("configurations differ, requesting update"); + RequestUpdate(mxRequestedConfiguration); + } + } + return 0; +} + + +} } // end of namespace sd::framework diff --git a/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx b/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx new file mode 100755 index 000000000000..8e59c3ec8585 --- /dev/null +++ b/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx @@ -0,0 +1,215 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_CONFIGURATION_UPDATER_HXX +#define SD_FRAMEWORK_CONFIGURATION_UPDATER_HXX + +#include "ConfigurationControllerResourceManager.hxx" +#include <com/sun/star/drawing/framework/XResourceId.hpp> +#include <com/sun/star/drawing/framework/XConfiguration.hpp> +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <vcl/timer.hxx> +#include <vector> +#include <boost/shared_ptr.hpp> + +namespace css = ::com::sun::star; + +namespace sd { namespace framework { + +class ConfigurationClassifier; +class ConfigurationUpdaterLock; + +/** This is a helper class for the ConfigurationController. It handles the + update of the current configuration so that it looks like a requested + configuration. An update is made by activating or deactivating drawing + framework resources. + + When an update is not successfull, i.e. after the update the current + configuration is not equivalent to the requested configuration, then a + timer is started to repeat the update after a short time. +*/ +class ConfigurationUpdater +{ +public: + /** Create a new ConfigurationUpdater object that notifies configuration + changes and the start and end of updates via the given broadcaster. + */ + ConfigurationUpdater ( + const ::boost::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster, + const ::boost::shared_ptr<ConfigurationControllerResourceManager>& rpResourceManager, + const css::uno::Reference< + css::drawing::framework::XControllerManager>& rxControllerManager); + ~ConfigurationUpdater (void); + + /** This method is typically called once, when the controller manager is + accessible to the caller. + */ + void SetControllerManager( + const css::uno::Reference< + css::drawing::framework::XControllerManager>& rxControllerManager); + + /** Request an update of the current configuration so that it looks like + the given requested configuration. It checks whether an update of + the current configuration can be done. Calls UpdateConfiguration() + if that is the case. Otherwise it schedules a later call to + UpdateConfiguration(). + */ + void RequestUpdate (const css::uno::Reference< + css::drawing::framework::XConfiguration>& rxRequestedConfiguration); + + css::uno::Reference< + css::drawing::framework::XConfiguration> GetCurrentConfiguration (void) const; + + friend class ConfigurationUpdaterLock; + /** Return a lock of the called ConfigurationUpdater. While the + returned object exists no update of the current configuration is + made. + */ + ::boost::shared_ptr<ConfigurationUpdaterLock> GetLock (void); + +private: + /** A reference to the XControllerManager is kept so that + UpdateConfiguration() has access to the other sub controllers. + */ + css::uno::Reference< + css::drawing::framework::XControllerManager> mxControllerManager; + + ::boost::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster; + + /** The current configuration holds the resources that are currently + active. It is modified during an update. + */ + css::uno::Reference< + css::drawing::framework::XConfiguration> mxCurrentConfiguration; + + /** The requested configuration holds the resources that have been + requested to activate or to deactivate since the last update. It is + (usually) not modified during an update. This configuration is + maintained by the ConfigurationController and given to the + ConfigurationUpdater in the RequestUpdate() method. + */ + css::uno::Reference< + css::drawing::framework::XConfiguration> mxRequestedConfiguration; + + /** This flag is set to </sal_True> when an update of the current + configurtion was requested (because the last request in the queue + was processed) but could not be exected because the + ConfigurationController was locked. A call to UpdateConfiguration() + resets the flag to </sal_False>. + */ + bool mbUpdatePending; + + /** This flag is set to </sal_True> while the UpdateConfiguration() method + is running. It is used to prevent reentrance problems with this + method. + */ + bool mbUpdateBeingProcessed; + + /** The ConfigurationController is locked when this count has a value + larger then zero. If the controller is locked then updates of the + current configuration are not made. + */ + sal_Int32 mnLockCount; + + /** This timer is used to check from time to time whether the requested + configuration and the current configuration are identcal and request + an update when they are not. + This is used to overcome problems with resources that become + available asynchronously. + */ + Timer maUpdateTimer; + + /** The number of failed updates (those after which the current + configuration is not equivalent to the requested configuration) is + used to determine how long to wait before another update is made. + */ + sal_Int32 mnFailedUpdateCount; + + ::boost::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager; + + /** This method does the main work of an update. It calls the sub + controllers that are responsible for the various types of resources + and tells them to update their active resources. It notifies + listeners about the start and end of the configuration update. + */ + void UpdateConfiguration (void); + + /** Basically calls UpdaterStart() andUpdateEnd() and makes some debug + output. + */ + void UpdateCore (const ConfigurationClassifier& rClassifier); + + /** Check for all pure anchors if they have at least one child. + Childless pure anchors are deactivated. + This affects only the current configuration. + */ + void CheckPureAnchors ( + const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration, + ::std::vector<css::uno::Reference<css::drawing::framework::XResourceId> >& + rResourcesToDeactivate); + + /** Remove from the requested configration all pure anchors that have no + child. Requested but not yet activated anchors can not be removed + because without the actual resource the 'pureness' of an anchor can + not be determined. + */ + void CleanRequestedConfiguration (void); + + /** Check the success of a recently executed configuration update. + When the update failed then start the timer. + */ + void CheckUpdateSuccess (void); + + /** This method sets the mbUpdateBeingProcessed member that is used to + prevent reentrance problems. This method allows function objects + easyly and safely to modify the variable. + */ + void SetUpdateBeingProcessed (bool bValue); + + /** Return whether it is possible to do an update of the configuration. + This takes into account whether another update is currently being + executed, the lock count, and whether the configuration controller + is still valid. + */ + bool IsUpdatePossible (void); + + /** Lock updates of the current configuration. For intermediate requests + for updates mbUpdatePending is set to <TRUE/>. + */ + void LockUpdates (void); + + /** When an update was requested since the last LockUpdates() call then + RequestUpdate() is called. + */ + void UnlockUpdates (void); + + DECL_LINK(TimeoutHandler, Timer*); +}; + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx new file mode 100644 index 000000000000..18c80b8b1243 --- /dev/null +++ b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "GenericConfigurationChangeRequest.hxx" + +#include "framework/FrameworkHelper.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +using ::rtl::OUString; + +namespace sd { namespace framework { + +GenericConfigurationChangeRequest::GenericConfigurationChangeRequest ( + const Reference<XResourceId>& rxResourceId, + const Mode eMode) throw(::com::sun::star::lang::IllegalArgumentException) + : GenericConfigurationChangeRequestInterfaceBase(MutexOwner::maMutex), + mxResourceId(rxResourceId), + meMode(eMode) +{ + if ( ! rxResourceId.is() || rxResourceId->getResourceURL().getLength()==0) + throw ::com::sun::star::lang::IllegalArgumentException(); +} + + + + +GenericConfigurationChangeRequest::~GenericConfigurationChangeRequest (void) throw() +{ +} + + + + +void SAL_CALL GenericConfigurationChangeRequest::execute ( + const Reference<XConfiguration>& rxConfiguration) + throw (RuntimeException) +{ + if (rxConfiguration.is()) + { + switch (meMode) + { + case Activation: + rxConfiguration->addResource(mxResourceId); + break; + + case Deactivation: + rxConfiguration->removeResource(mxResourceId); + break; + } + } +} + + + + +OUString SAL_CALL GenericConfigurationChangeRequest::getName (void) + throw (RuntimeException) +{ + return OUString::createFromAscii("GenericConfigurationChangeRequest ") + + OUString::createFromAscii(meMode==Activation ? "activate " : "deactivate ") + + FrameworkHelper::ResourceIdToString(mxResourceId); +} + + + + +void SAL_CALL GenericConfigurationChangeRequest::setName (const OUString& rsName) + throw (RuntimeException) +{ + (void)rsName; + // Ignored. +} + +} } // end of namespace sd::framework + diff --git a/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx new file mode 100644 index 000000000000..ce708e1fa71a --- /dev/null +++ b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx @@ -0,0 +1,123 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_GENERIC_CONFIGURATTION_CHANGE_REQUEST_HXX +#define SD_FRAMEWORK_GENERIC_CONFIGURATTION_CHANGE_REQUEST_HXX + +#include "MutexOwner.hxx" +#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/drawing/framework/XConfiguration.hpp> +#include <com/sun/star/drawing/framework/XResourceId.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <cppuhelper/compbase2.hxx> + +namespace css = ::com::sun::star; + +namespace { + +typedef ::cppu::WeakComponentImplHelper2 < + ::com::sun::star::drawing::framework::XConfigurationChangeRequest, + ::com::sun::star::container::XNamed + > GenericConfigurationChangeRequestInterfaceBase; + +} // end of anonymous namespace. + + +namespace sd { namespace framework { + +/** This implementation of the XConfigurationChangeRequest interface + represents a single explicit request for a configuration change. On its + execution it may result in other, implicit, configuration changes. For + example this is the case when the deactivation of a unique resource is + requested: the resources linked to it have to be deactivated as well. +*/ +class GenericConfigurationChangeRequest + : private MutexOwner, + public GenericConfigurationChangeRequestInterfaceBase +{ +public: + /** This enum specified whether the activation or deactivation of a + resource is requested. + */ + enum Mode { Activation, Deactivation }; + + /** Create a new object that represents the request for activation or + deactivation of the specified resource. + @param rxsResourceId + Id of the resource that is to be activated or deactivated. + @param eMode + The mode specifies whether to activate or to deactivate the + resource. + */ + GenericConfigurationChangeRequest ( + const ::com::sun::star::uno::Reference<com::sun::star::drawing::framework::XResourceId>& + rxResourceId, + const Mode eMode) + throw (::com::sun::star::lang::IllegalArgumentException); + + virtual ~GenericConfigurationChangeRequest (void) throw(); + + + // XConfigurationChangeOperation + + /** The requested configuration change is executed on the given + configuration. Additionally to the explicitly requested change + other changes have to be made as well. See class description for an + example. + @param rxConfiguration + The configuration to which the requested change is made. + */ + virtual void SAL_CALL execute ( + const ::com::sun::star::uno::Reference< + com::sun::star::drawing::framework::XConfiguration>& rxConfiguration) + throw (::com::sun::star::uno::RuntimeException); + + + // XNamed + + /** Return a human readable string representation. This is used for + debugging purposes. + */ + virtual ::rtl::OUString SAL_CALL getName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** This call is ignored because the XNamed interface is (mis)used to + give access to a human readable name for debugging purposes. + */ + virtual void SAL_CALL setName (const ::rtl::OUString& rName) + throw (::com::sun::star::uno::RuntimeException); + +private: + const css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId; + const Mode meMode; +}; + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx b/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx new file mode 100644 index 000000000000..1df3c77d78ba --- /dev/null +++ b/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx @@ -0,0 +1,230 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "ResourceFactoryManager.hxx" +#include <tools/wldcrd.hxx> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <comphelper/processfactory.hxx> +#include <boost/bind.hpp> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::rtl::OUString; + +namespace sd { namespace framework { + +ResourceFactoryManager::ResourceFactoryManager (const Reference<XControllerManager>& rxManager) + : maMutex(), + maFactoryMap(), + maFactoryPatternList(), + mxControllerManager(rxManager), + mxURLTransformer() +{ + // Create the URL transformer. + Reference<lang::XMultiServiceFactory> xServiceManager ( + ::comphelper::getProcessServiceFactory()); + mxURLTransformer = Reference<util::XURLTransformer>( + xServiceManager->createInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer"))), + UNO_QUERY); +} + + + + +ResourceFactoryManager::~ResourceFactoryManager (void) +{ + Reference<lang::XComponent> xComponent (mxURLTransformer, UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); +} + + + + +void ResourceFactoryManager::AddFactory ( + const OUString& rsURL, + const Reference<XResourceFactory>& rxFactory) + throw (RuntimeException) +{ + if ( ! rxFactory.is()) + throw lang::IllegalArgumentException(); + if (rsURL.getLength() == 0) + throw lang::IllegalArgumentException(); + + ::osl::MutexGuard aGuard (maMutex); + + if (rsURL.indexOf('*') >= 0 || rsURL.indexOf('?') >= 0) + { + // The URL is a URL pattern not an single URL. + maFactoryPatternList.push_back(FactoryPatternList::value_type(rsURL, rxFactory)); + } + else + { + maFactoryMap[rsURL] = rxFactory; + } +} + + + + +void ResourceFactoryManager::RemoveFactoryForURL ( + const OUString& rsURL) + throw (RuntimeException) +{ + if (rsURL.getLength() == 0) + throw lang::IllegalArgumentException(); + + ::osl::MutexGuard aGuard (maMutex); + + FactoryMap::iterator iFactory (maFactoryMap.find(rsURL)); + if (iFactory != maFactoryMap.end()) + { + maFactoryMap.erase(iFactory); + } + else + { + // The URL may be a pattern. Look that up. + FactoryPatternList::iterator iPattern; + for (iPattern=maFactoryPatternList.begin(); + iPattern!=maFactoryPatternList.end(); + ++iPattern) + { + if (iPattern->first == rsURL) + { + // Found the pattern. Remove it. + maFactoryPatternList.erase(iPattern); + break; + } + } + } +} + + + + + +void ResourceFactoryManager::RemoveFactoryForReference( + const Reference<XResourceFactory>& rxFactory) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Collect a list with all keys that map to the given factory. + ::std::vector<OUString> aKeys; + FactoryMap::const_iterator iFactory; + for (iFactory=maFactoryMap.begin(); iFactory!=maFactoryMap.end(); ++iFactory) + if (iFactory->second == rxFactory) + aKeys.push_back(iFactory->first); + + // Remove the entries whose keys we just have collected. + ::std::vector<OUString>::const_iterator iKey; + for (iKey=aKeys.begin(); iKey!=aKeys.end(); ++iKey) + maFactoryMap.erase(maFactoryMap.find(*iKey)); + + // Remove the pattern entries whose factories are identical to the given + // factory. + FactoryPatternList::iterator iNewEnd ( + std::remove_if( + maFactoryPatternList.begin(), + maFactoryPatternList.end(), + ::boost::bind( + std::equal_to<Reference<XResourceFactory> >(), + ::boost::bind(&FactoryPatternList::value_type::second, _1), + rxFactory))); + if (iNewEnd != maFactoryPatternList.end()) + maFactoryPatternList.erase(iNewEnd, maFactoryPatternList.end()); +} + + + + +Reference<XResourceFactory> ResourceFactoryManager::GetFactory ( + const OUString& rsCompleteURL) + throw (RuntimeException) +{ + OUString sURLBase (rsCompleteURL); + if (mxURLTransformer.is()) + { + util::URL aURL; + aURL.Complete = rsCompleteURL; + if (mxURLTransformer->parseStrict(aURL)) + sURLBase = aURL.Main; + } + + Reference<XResourceFactory> xFactory = FindFactory(sURLBase); + + if ( ! xFactory.is() && mxControllerManager.is()) + { + Reference<XModuleController> xModuleController(mxControllerManager->getModuleController()); + if (xModuleController.is()) + { + // Ask the module controller to provide a factory of the + // requested view type. Note that this can (and should) cause + // intermediate calls to AddFactory(). + xModuleController->requestResource(sURLBase); + + xFactory = FindFactory(sURLBase); + } + } + + return xFactory; +} + + + + +Reference<XResourceFactory> ResourceFactoryManager::FindFactory (const OUString& rsURLBase) + throw (RuntimeException) +{ + ::osl::MutexGuard aGuard (maMutex); + FactoryMap::const_iterator iFactory (maFactoryMap.find(rsURLBase)); + if (iFactory != maFactoryMap.end()) + return iFactory->second; + else + { + // Check the URL patterns. + FactoryPatternList::const_iterator iPattern; + for (iPattern=maFactoryPatternList.begin(); + iPattern!=maFactoryPatternList.end(); + ++iPattern) + { + WildCard aWildCard (iPattern->first); + if (aWildCard.Matches(rsURLBase)) + return iPattern->second; + } + } + return NULL; +} + +} } // end of namespace sd::framework diff --git a/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx b/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx new file mode 100644 index 000000000000..dc7d2574dbfc --- /dev/null +++ b/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx @@ -0,0 +1,128 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_RESOURCE_FACTORY_MANAGER_HXX +#define SD_FRAMEWORK_RESOURCE_FACTORY_MANAGER_HXX + +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/drawing/framework/XModuleController.hpp> +#include <com/sun/star/drawing/framework/XResourceFactoryManager.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <osl/mutex.hxx> +#include <comphelper/stl_types.hxx> +#include <hash_map> + +namespace css = ::com::sun::star; + +namespace sd { namespace framework { + +/** Container of resource factories of the drawing framework. +*/ +class ResourceFactoryManager +{ +public: + ResourceFactoryManager ( + const css::uno::Reference<css::drawing::framework::XControllerManager>& rxManager); + + ~ResourceFactoryManager (void); + + /** Register a resource factory for one type of resource. + @param rsURL + The type of the resource that will be created by the factory. + @param rxFactory + The factory that will create resource objects of the specfied type. + */ + void AddFactory ( + const ::rtl::OUString& rsURL, + const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory) + throw (css::uno::RuntimeException); + + /** Unregister the specifed factory. + @param rsURL + Unregister only the factory for this URL. When the same factory + is registered for other URLs then these remain registered. + */ + void RemoveFactoryForURL( + const ::rtl::OUString& rsURL) + throw (css::uno::RuntimeException); + + /** Unregister the specified factory. + @param rxFactory + Unregister the this factory for all URLs that it has been + registered for. + */ + void RemoveFactoryForReference( + const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory) + throw (css::uno::RuntimeException); + + /** Return a factory that can create resources specified by the given URL. + @param rsCompleteURL + This URL specifies the type of the resource. It may contain arguments. + @return + When a factory for the specified URL has been registered by a + previous call to AddFactory() then a reference to that factory + is returned. Otherwise an empty reference is returned. + */ + css::uno::Reference<css::drawing::framework::XResourceFactory> GetFactory ( + const ::rtl::OUString& rsURL) + throw (css::uno::RuntimeException); + +private: + ::osl::Mutex maMutex; + typedef ::std::hash_map< + ::rtl::OUString, + css::uno::Reference<css::drawing::framework::XResourceFactory>, + ::comphelper::UStringHash, + ::comphelper::UStringEqual> FactoryMap; + FactoryMap maFactoryMap; + + typedef ::std::vector< + ::std::pair< + rtl::OUString, + css::uno::Reference<css::drawing::framework::XResourceFactory> > > + FactoryPatternList; + FactoryPatternList maFactoryPatternList; + + css::uno::Reference<css::drawing::framework::XControllerManager> mxControllerManager; + css::uno::Reference<css::util::XURLTransformer> mxURLTransformer; + + /** Look up the factory for the given URL. + @param rsURLBase + The css::tools::URL.Main part of a URL. Arguments have to be + stripped off by the caller. + @return + When the factory has not yet been added then return NULL. + */ + css::uno::Reference<css::drawing::framework::XResourceFactory> FindFactory ( + const ::rtl::OUString& rsURLBase) + throw (css::uno::RuntimeException); +}; + + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/ResourceId.cxx b/sd/source/ui/framework/configuration/ResourceId.cxx new file mode 100755 index 000000000000..15d7c3a6f4ec --- /dev/null +++ b/sd/source/ui/framework/configuration/ResourceId.cxx @@ -0,0 +1,626 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "framework/ResourceId.hxx" +#include "framework/FrameworkHelper.hxx" +#include "tools/SdGlobalResourceContainer.hxx" +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <comphelper/processfactory.hxx> +#include <rtl/ref.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::drawing::framework; +using ::rtl::OUString; + +/** When the USE_OPTIMIZATIONS symbol is defined then at some optimizations + are activated that work only together with XResourceId objects that are + implemented by the ResourceId class. For other implementations of when + the USE_OPTIMIZATIONS symbol is not defined then alternative code is + used instead. +*/ +#define USE_OPTIMIZATIONS + +namespace sd { namespace framework { + +Reference<XInterface> SAL_CALL ResourceId_createInstance ( + const Reference<XComponentContext>& rxContext) +{ + (void)rxContext; + return Reference<XInterface>(static_cast<XWeak*>(new ::sd::framework::ResourceId())); +} + + + + +::rtl::OUString ResourceId_getImplementationName (void) throw(RuntimeException) +{ + return ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Draw.framework.ResourceId")); +} + + + + +Sequence<rtl::OUString> SAL_CALL ResourceId_getSupportedServiceNames (void) + throw (RuntimeException) +{ + static const ::rtl::OUString sServiceName( + ::rtl::OUString::createFromAscii("com.sun.star.drawing.framework.ResourceId")); + return Sequence<rtl::OUString>(&sServiceName, 1); +} + + + + +//===== ResourceId ============================================================ + +WeakReference<util::XURLTransformer> ResourceId::mxURLTransformerWeak; + +ResourceId::ResourceId (void) + : ResourceIdInterfaceBase(), + maResourceURLs(0), + mpURL() +{ +} + + + + +ResourceId::ResourceId ( + const std::vector<OUString>& rResourceURLs) + : ResourceIdInterfaceBase(), + maResourceURLs(rResourceURLs), + mpURL() +{ + ParseResourceURL(); +} + + + + +ResourceId::ResourceId ( + const OUString& rsResourceURL) + : ResourceIdInterfaceBase(), + maResourceURLs(1, rsResourceURL), + mpURL() +{ + // Handle the special case of an empty resource URL. + if (rsResourceURL.getLength() == 0) + maResourceURLs.clear(); + ParseResourceURL(); +} + + + + +ResourceId::ResourceId ( + const OUString& rsResourceURL, + const OUString& rsAnchorURL) + : ResourceIdInterfaceBase(), + maResourceURLs(2), + mpURL() +{ + maResourceURLs[0] = rsResourceURL; + maResourceURLs[1] = rsAnchorURL; + ParseResourceURL(); +} + + + + +ResourceId::ResourceId ( + const OUString& rsResourceURL, + const ::std::vector<OUString>& rAnchorURLs) + : ResourceIdInterfaceBase(), + maResourceURLs(1+rAnchorURLs.size()), + mpURL() +{ + maResourceURLs[0] = rsResourceURL; + for (sal_uInt32 nIndex=0; nIndex<rAnchorURLs.size(); ++nIndex) + maResourceURLs[nIndex+1] = rAnchorURLs[nIndex]; + ParseResourceURL(); +} + + + + +ResourceId::ResourceId ( + const OUString& rsResourceURL, + const OUString& rsFirstAnchorURL, + const Sequence<OUString>& rAnchorURLs) + : ResourceIdInterfaceBase(), + maResourceURLs(2+rAnchorURLs.getLength()), + mpURL() +{ + maResourceURLs[0] = rsResourceURL; + maResourceURLs[1] = rsFirstAnchorURL; + for (sal_Int32 nIndex=0; nIndex<rAnchorURLs.getLength(); ++nIndex) + maResourceURLs[nIndex+2] = rAnchorURLs[nIndex]; + ParseResourceURL(); +} + + + + +ResourceId::~ResourceId (void) +{ + mpURL.reset(); +} + + + + +OUString SAL_CALL + ResourceId::getResourceURL (void) + throw(com::sun::star::uno::RuntimeException) +{ + if (maResourceURLs.size() > 0) + return maResourceURLs[0]; + else + return OUString(); +} + + + + +util::URL SAL_CALL + ResourceId::getFullResourceURL (void) + throw(com::sun::star::uno::RuntimeException) +{ + if (mpURL.get() != NULL) + return *mpURL; + + Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak); + if (xURLTransformer.is() && maResourceURLs.size() > 0) + { + mpURL.reset(new util::URL); + mpURL->Complete = maResourceURLs[0]; + xURLTransformer->parseStrict(*mpURL); + return *mpURL; + } + + util::URL aURL; + if (maResourceURLs.size() > 0) + aURL.Complete = maResourceURLs[0]; + return aURL; +} + + + + +sal_Bool SAL_CALL + ResourceId::hasAnchor (void) + throw (RuntimeException) +{ + return maResourceURLs.size()>1; +} + + + + +Reference<XResourceId> SAL_CALL + ResourceId::getAnchor (void) + throw (RuntimeException) +{ + ::rtl::Reference<ResourceId> rResourceId (new ResourceId()); + const sal_Int32 nAnchorCount (maResourceURLs.size()-1); + if (nAnchorCount > 0) + { + rResourceId->maResourceURLs.resize(nAnchorCount); + for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex) + rResourceId->maResourceURLs[nIndex] = maResourceURLs[nIndex+1]; + } + return Reference<XResourceId>(rResourceId.get()); +} + + + + +Sequence<OUString> SAL_CALL + ResourceId::getAnchorURLs (void) + throw (RuntimeException) +{ + const sal_Int32 nAnchorCount (maResourceURLs.size() - 1); + if (nAnchorCount > 0) + { + Sequence<OUString> aAnchorURLs (nAnchorCount); + for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex) + aAnchorURLs[nIndex] = maResourceURLs[nIndex+1]; + return aAnchorURLs; + } + else + return Sequence<OUString>(); +} + + + + +OUString SAL_CALL + ResourceId::getResourceTypePrefix (void) + throw (RuntimeException) +{ + if (maResourceURLs.size() > 0) + { + // Return the "private:resource/<type>/" prefix. + + // Get the the prefix that ends with the second "/". + const OUString& rsResourceURL (maResourceURLs[0]); + sal_Int32 nPrefixEnd (rsResourceURL.indexOf(sal_Unicode('/'), 0)); + if (nPrefixEnd >= 0) + nPrefixEnd = rsResourceURL.indexOf(sal_Unicode('/'), nPrefixEnd+1) + 1; + else + nPrefixEnd = 0; + + return rsResourceURL.copy(0,nPrefixEnd); + } + else + return OUString(); +} + + + + +sal_Int16 SAL_CALL + ResourceId::compareTo (const Reference<XResourceId>& rxResourceId) + throw (RuntimeException) +{ + sal_Int16 nResult (0); + + if ( ! rxResourceId.is()) + { + // The empty reference is interpreted as empty resource id object. + if (maResourceURLs.size() > 0) + nResult = +1; + else + nResult = 0; + } + else + { + ResourceId* pId = NULL; +#ifdef USE_OPTIMIZATIONS + pId = dynamic_cast<ResourceId*>(rxResourceId.get()); +#endif + if (pId != NULL) + { + // We have direct access to the implementation of the given + // resource id object. + nResult = CompareToLocalImplementation(*pId); + } + else + { + // We have to do the comparison via the UNO interface of the + // given resource id object. + nResult = CompareToExternalImplementation(rxResourceId); + } + } + + return nResult; +} + + + + +sal_Int16 ResourceId::CompareToLocalImplementation (const ResourceId& rId) const +{ + sal_Int16 nResult (0); + + const sal_uInt32 nLocalURLCount (maResourceURLs.size()); + const sal_uInt32 nURLCount(rId.maResourceURLs.size()); + + // Start comparison with the top most anchors. + for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1; + nIndex>=0 && nLocalIndex>=0; + --nIndex,--nLocalIndex) + { + const OUString sLocalURL (maResourceURLs[nLocalIndex]); + const OUString sURL (rId.maResourceURLs[nIndex]); + const sal_Int32 nLocalResult (sURL.compareTo(sLocalURL)); + if (nLocalResult != 0) + { + if (nLocalResult < 0) + nResult = -1; + else + nResult = +1; + break; + } + } + + if (nResult == 0) + { + // No difference found yet. When the lengths are the same then the + // two resource ids are equivalent. Otherwise the shorter comes + // first. + if (nLocalURLCount != nURLCount) + { + if (nLocalURLCount < nURLCount) + nResult = -1; + else + nResult = +1; + } + } + + return nResult; +} + + + + +sal_Int16 ResourceId::CompareToExternalImplementation (const Reference<XResourceId>& rxId) const +{ + sal_Int16 nResult (0); + + const Sequence<OUString> aAnchorURLs (rxId->getAnchorURLs()); + const sal_uInt32 nLocalURLCount (maResourceURLs.size()); + const sal_uInt32 nURLCount(1+aAnchorURLs.getLength()); + + // Start comparison with the top most anchors. + sal_Int32 nLocalResult (0); + for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1; + nIndex>=0&&nLocalIndex>=0; + --nIndex,--nLocalIndex) + { + if (nIndex == 0 ) + nLocalResult = maResourceURLs[nIndex].compareTo(rxId->getResourceURL()); + else + nLocalResult = maResourceURLs[nIndex].compareTo(aAnchorURLs[nIndex-1]); + if (nLocalResult != 0) + { + if (nLocalResult < 0) + nResult = -1; + else + nResult = +1; + break; + } + } + + if (nResult == 0) + { + // No difference found yet. When the lengths are the same then the + // two resource ids are equivalent. Otherwise the shorter comes + // first. + if (nLocalURLCount != nURLCount) + { + if (nLocalURLCount < nURLCount) + nResult = -1; + else + nResult = +1; + } + } + + return nResult; +} + + + + +sal_Bool SAL_CALL + ResourceId::isBoundTo ( + const Reference<XResourceId>& rxResourceId, + AnchorBindingMode eMode) + throw (RuntimeException) +{ + if ( ! rxResourceId.is()) + { + // An empty reference is interpreted as empty resource id. + return IsBoundToAnchor(NULL, NULL, eMode); + } + + ResourceId* pId = NULL; +#ifdef USE_OPTIMIZATIONS + pId = dynamic_cast<ResourceId*>(rxResourceId.get()); +#endif + if (pId != NULL) + { + return IsBoundToAnchor(pId->maResourceURLs, eMode); + } + else + { + const OUString sResourceURL (rxResourceId->getResourceURL()); + const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs()); + return IsBoundToAnchor(&sResourceURL, &aAnchorURLs, eMode); + } +} + + + + +sal_Bool SAL_CALL + ResourceId::isBoundToURL ( + const OUString& rsAnchorURL, + AnchorBindingMode eMode) + throw (RuntimeException) +{ + return IsBoundToAnchor(&rsAnchorURL, NULL, eMode); +} + + + + +Reference<XResourceId> SAL_CALL + ResourceId::clone (void) + throw(RuntimeException) +{ + return new ResourceId(maResourceURLs); +} + + + + +//----- XInitialization ------------------------------------------------------- + +void SAL_CALL ResourceId::initialize (const Sequence<Any>& aArguments) + throw (RuntimeException) +{ + sal_uInt32 nCount (aArguments.getLength()); + for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex) + { + OUString sResourceURL; + if (aArguments[nIndex] >>= sResourceURL) + maResourceURLs.push_back(sResourceURL); + else + { + Reference<XResourceId> xAnchor; + if (aArguments[nIndex] >>= xAnchor) + { + if (xAnchor.is()) + { + maResourceURLs.push_back(xAnchor->getResourceURL()); + Sequence<OUString> aAnchorURLs (xAnchor->getAnchorURLs()); + for (sal_Int32 nURLIndex=0; nURLIndex<aAnchorURLs.getLength(); ++nURLIndex) + { + maResourceURLs.push_back(aAnchorURLs[nURLIndex]); + } + } + } + } + } + ParseResourceURL(); +} + + + + +//----------------------------------------------------------------------------- + +/** When eMode is DIRECTLY then the anchor of the called object and the + anchor represented by the given sequence of anchor URLs have to be + identical. When eMode is RECURSIVE then the anchor of the called + object has to start with the given anchor URLs. +*/ +bool ResourceId::IsBoundToAnchor ( + const OUString* psFirstAnchorURL, + const Sequence<OUString>* paAnchorURLs, + AnchorBindingMode eMode) const +{ + const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1); + const bool bHasFirstAnchorURL (psFirstAnchorURL!=NULL); + const sal_uInt32 nAnchorURLCount ((bHasFirstAnchorURL?1:0) + + (paAnchorURLs!=NULL ? paAnchorURLs->getLength() : 0)); + + // Check the lengths. + if (nLocalAnchorURLCount<nAnchorURLCount || + (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount)) + { + return false; + } + + // Compare the nAnchorURLCount bottom-most anchor URLs of this resource + // id and the given anchor. + sal_uInt32 nOffset = 0; + if (paAnchorURLs != NULL) + { + sal_uInt32 nCount = paAnchorURLs->getLength(); + while (nOffset < nCount) + { + if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals( + (*paAnchorURLs)[nCount - 1 - nOffset])) + { + return false; + } + ++nOffset; + } + } + if (bHasFirstAnchorURL) + { + if ( ! psFirstAnchorURL->equals(maResourceURLs[nLocalAnchorURLCount - nOffset])) + return false; + } + + return true; +} + + + + +bool ResourceId::IsBoundToAnchor ( + const ::std::vector<OUString>& rAnchorURLs, + AnchorBindingMode eMode) const +{ + const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1); + const sal_uInt32 nAnchorURLCount (rAnchorURLs.size()); + + // Check the lengths. + if (nLocalAnchorURLCount<nAnchorURLCount || + (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount)) + { + return false; + } + + // Compare the nAnchorURLCount bottom-most anchor URLs of this resource + // id and the given anchor. + for (sal_uInt32 nOffset=0; nOffset<nAnchorURLCount; ++nOffset) + { + if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals( + rAnchorURLs[nAnchorURLCount - 1 - nOffset])) + { + return false; + } + } + + return true; +} + + + + +void ResourceId::ParseResourceURL (void) +{ + ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex()); + Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak); + if ( ! xURLTransformer.is()) + { + // Create the URL transformer. + Reference<lang::XMultiServiceFactory> xServiceManager ( + ::comphelper::getProcessServiceFactory()); + xURLTransformer = Reference<util::XURLTransformer>( + xServiceManager->createInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer"))), + UNO_QUERY); + mxURLTransformerWeak = xURLTransformer; + SdGlobalResourceContainer::Instance().AddResource( + Reference<XInterface>(xURLTransformer,UNO_QUERY)); + } + + if (xURLTransformer.is() && maResourceURLs.size() > 0) + { + mpURL.reset(new util::URL); + mpURL->Complete = maResourceURLs[0]; + xURLTransformer->parseStrict(*mpURL); + if (mpURL->Main == maResourceURLs[0]) + mpURL.reset(); + else + maResourceURLs[0] = mpURL->Main; + } +} + + +} } // end of namespace sd::framework diff --git a/sd/source/ui/framework/configuration/UpdateRequest.cxx b/sd/source/ui/framework/configuration/UpdateRequest.cxx new file mode 100644 index 000000000000..1c39006b29c7 --- /dev/null +++ b/sd/source/ui/framework/configuration/UpdateRequest.cxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "UpdateRequest.hxx" + +#include "framework/FrameworkHelper.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +using ::rtl::OUString; + +namespace sd { namespace framework { + +UpdateRequest::UpdateRequest (void) + throw() + : UpdateRequestInterfaceBase(MutexOwner::maMutex) +{ +} + + + + +UpdateRequest::~UpdateRequest (void) throw() +{ +} + + + + +void SAL_CALL UpdateRequest::execute (const Reference<XConfiguration>& rxConfiguration) + throw (RuntimeException) +{ + (void)rxConfiguration; + // Do nothing here. The configuration is updated when the request queue + // becomes empty. +} + + + + +OUString SAL_CALL UpdateRequest::getName (void) + throw (RuntimeException) +{ + return OUString::createFromAscii("UpdateRequest"); +} + + + + +void SAL_CALL UpdateRequest::setName (const OUString& rsName) + throw (RuntimeException) +{ + (void)rsName; + // Ignored. +} + +} } // end of namespace sd::framework + diff --git a/sd/source/ui/framework/configuration/UpdateRequest.hxx b/sd/source/ui/framework/configuration/UpdateRequest.hxx new file mode 100644 index 000000000000..e3fc159d4b11 --- /dev/null +++ b/sd/source/ui/framework/configuration/UpdateRequest.hxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_FRAMEWORK_UPDATE_REQUEST_HXX +#define SD_FRAMEWORK_UPDATE_REQUEST_HXX + +#include "MutexOwner.hxx" +#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/drawing/framework/XConfiguration.hpp> +#include <cppuhelper/compbase2.hxx> + + +namespace { + +typedef ::cppu::WeakComponentImplHelper2 < + ::com::sun::star::drawing::framework::XConfigurationChangeRequest, + ::com::sun::star::container::XNamed + > UpdateRequestInterfaceBase; + +} // end of anonymous namespace. + + + +namespace sd { namespace framework { + +/** This update request is used to request configuration updates + asynchronous when no other requests are being processed. When there are + other requests then we can simply wait until the last one is executed: + the configuration is updated when the request queue becomes empty. This + is use by this implementation as well. The execute() method does not + really do anything. This request just triggers the update of the + configuration when it is removed as last request from the queue. +*/ +class UpdateRequest + : private MutexOwner, + public UpdateRequestInterfaceBase +{ +public: + UpdateRequest (void) throw(); + virtual ~UpdateRequest (void) throw(); + + + // XConfigurationChangeOperation + + virtual void SAL_CALL execute ( + const ::com::sun::star::uno::Reference< + com::sun::star::drawing::framework::XConfiguration>& rxConfiguration) + throw (::com::sun::star::uno::RuntimeException); + + + // XNamed + + /** Return a human readable string representation. This is used for + debugging purposes. + */ + virtual ::rtl::OUString SAL_CALL getName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** This call is ignored because the XNamed interface is (mis)used to + give access to a human readable name for debugging purposes. + */ + virtual void SAL_CALL setName (const ::rtl::OUString& rName) + throw (::com::sun::star::uno::RuntimeException); +}; + +} } // end of namespace sd::framework + +#endif diff --git a/sd/source/ui/framework/configuration/makefile.mk b/sd/source/ui/framework/configuration/makefile.mk new file mode 100644 index 000000000000..cdc41491b307 --- /dev/null +++ b/sd/source/ui/framework/configuration/makefile.mk @@ -0,0 +1,63 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=framework_configuration +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/ChangeRequestQueue.obj \ + $(SLO)$/ChangeRequestQueueProcessor.obj \ + $(SLO)$/Configuration.obj \ + $(SLO)$/ConfigurationClassifier.obj \ + $(SLO)$/ConfigurationController.obj \ + $(SLO)$/ConfigurationControllerBroadcaster.obj \ + $(SLO)$/ConfigurationControllerResourceManager.obj \ + $(SLO)$/ConfigurationTracer.obj \ + $(SLO)$/ConfigurationUpdater.obj \ + $(SLO)$/GenericConfigurationChangeRequest.obj \ + $(SLO)$/ResourceId.obj \ + $(SLO)$/ResourceFactoryManager.obj \ + $(SLO)$/UpdateRequest.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + |