diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sd/source/ui/framework/tools | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source/ui/framework/tools')
-rw-r--r-- | sd/source/ui/framework/tools/FrameworkHelper.cxx | 952 |
1 files changed, 952 insertions, 0 deletions
diff --git a/sd/source/ui/framework/tools/FrameworkHelper.cxx b/sd/source/ui/framework/tools/FrameworkHelper.cxx new file mode 100644 index 000000000..dceecd510 --- /dev/null +++ b/sd/source/ui/framework/tools/FrameworkHelper.cxx @@ -0,0 +1,952 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <osl/time.h> + +#include <framework/FrameworkHelper.hxx> + +#include <framework/ConfigurationController.hxx> +#include <framework/ResourceId.hxx> +#include <framework/ViewShellWrapper.hxx> +#include <ViewShellBase.hxx> +#include <DrawViewShell.hxx> +#include <ViewShellHint.hxx> +#include <app.hrc> +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <comphelper/servicehelper.hxx> +#include <comphelper/compbase.hxx> +#include <svl/lstner.hxx> +#include <rtl/ustrbuf.hxx> + +#include <sfx2/request.hxx> + +#include <vcl/svapp.hxx> +#include <osl/doublecheckedlocking.h> +#include <osl/getglobalmutex.hxx> +#include <tools/diagnose_ex.h> +#include <memory> +#include <unordered_map> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +namespace { + +//----- CallbackCaller -------------------------------------------------------- + +typedef comphelper::WeakComponentImplHelper < + css::drawing::framework::XConfigurationChangeListener + > CallbackCallerInterfaceBase; + +/** A CallbackCaller registers as listener at an XConfigurationController + object and waits for the notification of one type of event. When that + event is received, or when the CallbackCaller detects at its + construction that the event will not be sent in the near future, the + actual callback object is called and the CallbackCaller destroys itself. +*/ +class CallbackCaller + : public CallbackCallerInterfaceBase +{ +public: + /** Create a new CallbackCaller object. This object controls its own + lifetime by acquiring a reference to itself in the constructor. + When it detects that the event will not be notified in the near + future (because the queue of pending configuration change operations + is empty and therefore no event will be sent int the near future, it + does not acquires a reference and thus initiates its destruction in + the constructor.) + @param rBase + This ViewShellBase object is used to determine the + XConfigurationController at which to register. + @param rsEventType + The event type which the callback is waiting for. + @param pCallback + The callback object which is to be notified. The caller will + typically release his reference to the caller so that when the + CallbackCaller dies (after having called the callback) the + callback is destroyed. + */ + CallbackCaller ( + const ::sd::ViewShellBase& rBase, + const OUString& rsEventType, + const ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter& rFilter, + const ::sd::framework::FrameworkHelper::Callback& rCallback); + + virtual void disposing(std::unique_lock<std::mutex>&) override; + // XEventListener + virtual void SAL_CALL disposing (const lang::EventObject& rEvent) override; + // XConfigurationChangeListener + virtual void SAL_CALL notifyConfigurationChange (const ConfigurationChangeEvent& rEvent) override; + +private: + OUString msEventType; + Reference<XConfigurationController> mxConfigurationController; + ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter maFilter; + ::sd::framework::FrameworkHelper::Callback maCallback; +}; + +//----- LifetimeController ---------------------------------------------------- + +typedef comphelper::WeakComponentImplHelper < + css::lang::XEventListener + > LifetimeControllerInterfaceBase; + +/** This class helps controlling the lifetime of the + FrameworkHelper. Register at a ViewShellBase object and an XController + object and call Dispose() at the associated FrameworkHelper object when + one of them and Release() when both of them are destroyed. +*/ +class LifetimeController + : public LifetimeControllerInterfaceBase, + public SfxListener +{ +public: + explicit LifetimeController (::sd::ViewShellBase& rBase); + virtual ~LifetimeController() override; + + /** XEventListener. This method is called when the frame::XController + is being destroyed. + */ + using WeakComponentImplHelperBase::disposing; + virtual void SAL_CALL disposing (const lang::EventObject& rEvent) override; + + /** This method is called when the ViewShellBase is being destroyed. + */ + virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override; + +private: + ::sd::ViewShellBase& mrBase; + bool mbListeningToViewShellBase; + bool mbListeningToController; + + /** When one or both of the mbListeningToViewShellBase and + mbListeningToController members were modified then call this method + to either dispose or release the associated FrameworkHelper. + */ + void Update(); +}; + +} // end of anonymous namespace + +namespace sd::framework { + +namespace { + + class FrameworkHelperAllPassFilter + { + public: + bool operator() (const css::drawing::framework::ConfigurationChangeEvent&) { return true; } + }; + + class FrameworkHelperResourceIdFilter + { + public: + explicit FrameworkHelperResourceIdFilter ( + const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId); + bool operator() (const css::drawing::framework::ConfigurationChangeEvent& rEvent) + { return mxResourceId.is() && rEvent.ResourceId.is() + && mxResourceId->compareTo(rEvent.ResourceId) == 0; } + private: + css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId; + }; + +} // end of anonymous namespace + +// Pane URLS. + +const OUString FrameworkHelper::msCenterPaneURL( msPaneURLPrefix + "CenterPane"); +const OUString FrameworkHelper::msFullScreenPaneURL( msPaneURLPrefix + "FullScreenPane"); +const OUString FrameworkHelper::msLeftImpressPaneURL( msPaneURLPrefix + "LeftImpressPane"); +const OUString FrameworkHelper::msLeftDrawPaneURL( msPaneURLPrefix + "LeftDrawPane"); + +// View URLs. + +const OUString FrameworkHelper::msImpressViewURL( msViewURLPrefix + "ImpressView"); +const OUString FrameworkHelper::msDrawViewURL( msViewURLPrefix + "GraphicView"); +const OUString FrameworkHelper::msOutlineViewURL( msViewURLPrefix + "OutlineView"); +const OUString FrameworkHelper::msNotesViewURL( msViewURLPrefix + "NotesView"); +const OUString FrameworkHelper::msHandoutViewURL( msViewURLPrefix + "HandoutView"); +const OUString FrameworkHelper::msSlideSorterURL( msViewURLPrefix + "SlideSorter"); +const OUString FrameworkHelper::msPresentationViewURL( msViewURLPrefix + "PresentationView"); +const OUString FrameworkHelper::msSidebarViewURL( msViewURLPrefix + "SidebarView"); + +// Tool bar URLs. + +const OUString FrameworkHelper::msViewTabBarURL( msToolBarURLPrefix + "ViewTabBar"); + +//----- helper ---------------------------------------------------------------- +namespace +{ + ::std::shared_ptr< ViewShell > lcl_getViewShell( const Reference< XResource >& i_rViewShellWrapper ) + { + ::std::shared_ptr< ViewShell > pViewShell; + try + { + Reference<lang::XUnoTunnel> xViewTunnel( i_rViewShellWrapper, UNO_QUERY_THROW ); + if (auto pWrapper = comphelper::getFromUnoTunnel<ViewShellWrapper>(xViewTunnel)) + pViewShell = pWrapper->GetViewShell(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("sd"); + } + return pViewShell; + } + Reference< XResource > lcl_getFirstViewInPane( const Reference< XConfigurationController >& i_rConfigController, + const Reference< XResourceId >& i_rPaneId ) + { + try + { + Reference< XConfiguration > xConfiguration( i_rConfigController->getRequestedConfiguration(), UNO_SET_THROW ); + Sequence< Reference< XResourceId > > aViewIds( xConfiguration->getResources( + i_rPaneId, FrameworkHelper::msViewURLPrefix, AnchorBindingMode_DIRECT ) ); + if ( aViewIds.hasElements() ) + return i_rConfigController->getResource( aViewIds[0] ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("sd"); + } + return nullptr; + } +} + +//----- FrameworkHelper::ViewURLMap ------------------------------------------- + +/** The ViewURLMap is used to translate between the view URLs used by the + drawing framework and the enums defined in the ViewShell class. +*/ +class FrameworkHelper::ViewURLMap + : public std::unordered_map< + OUString, + ViewShell::ShellType> +{ +public: + ViewURLMap() {} +}; + +//----- Framework::DisposeListener --------------------------------------------- + +namespace { + typedef comphelper::WeakComponentImplHelper < + css::lang::XEventListener + > FrameworkHelperDisposeListenerInterfaceBase; +} + +class FrameworkHelper::DisposeListener + : public FrameworkHelperDisposeListenerInterfaceBase +{ +public: + explicit DisposeListener (const ::std::shared_ptr<FrameworkHelper>& rpHelper); + + virtual void disposing(std::unique_lock<std::mutex>&) override; + + virtual void SAL_CALL disposing (const lang::EventObject& rEventObject) override; + +private: + ::std::shared_ptr<FrameworkHelper> mpHelper; +}; + +//----- FrameworkHelper::Deleter ---------------------------------------------- + +class FrameworkHelper::Deleter +{ +public: + void operator()(FrameworkHelper* pObject) + { + delete pObject; + } +}; + +//----- FrameworkHelper ------------------------------------------------------- + +FrameworkHelper::ViewURLMap FrameworkHelper::maViewURLMap; + +FrameworkHelper::InstanceMap FrameworkHelper::maInstanceMap; + +::std::shared_ptr<FrameworkHelper> FrameworkHelper::Instance (ViewShellBase& rBase) +{ + + ::std::shared_ptr<FrameworkHelper> pHelper; + + InstanceMap::const_iterator iHelper (maInstanceMap.find(&rBase)); + if (iHelper == maInstanceMap.end()) + { + ::osl::GetGlobalMutex aMutexFunctor; + ::osl::MutexGuard aGuard (aMutexFunctor()); + if (iHelper == maInstanceMap.end()) + { + pHelper = ::std::shared_ptr<FrameworkHelper>( + new FrameworkHelper(rBase), + FrameworkHelper::Deleter()); + pHelper->Initialize(); + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + maInstanceMap[&rBase] = pHelper; + } + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + pHelper = iHelper->second; + } + + return pHelper; +} + +void FrameworkHelper::DisposeInstance (const ViewShellBase& rBase) +{ + InstanceMap::iterator iHelper (maInstanceMap.find(&rBase)); + if (iHelper != maInstanceMap.end()) + { + iHelper->second->Dispose(); + } +} + +void FrameworkHelper::ReleaseInstance (const ViewShellBase& rBase) +{ + InstanceMap::iterator iHelper (maInstanceMap.find(&rBase)); + if (iHelper != maInstanceMap.end()) + maInstanceMap.erase(iHelper); +} + +FrameworkHelper::FrameworkHelper (ViewShellBase& rBase) + : mrBase(rBase) +{ + Reference<XControllerManager> xControllerManager (rBase.GetController(), UNO_QUERY); + if (xControllerManager.is()) + { + mxConfigurationController = xControllerManager->getConfigurationController(); + } + + new LifetimeController(mrBase); +} + +void FrameworkHelper::Initialize() +{ + mxDisposeListener = new DisposeListener(shared_from_this()); +} + +FrameworkHelper::~FrameworkHelper() +{ +} + +void FrameworkHelper::Dispose() +{ + if (mxDisposeListener.is()) + mxDisposeListener->dispose(); + mxConfigurationController = nullptr; +} + +bool FrameworkHelper::IsValid() const +{ + return mxConfigurationController.is(); +} + +::std::shared_ptr<ViewShell> FrameworkHelper::GetViewShell (const OUString& rsPaneURL) +{ + if ( !mxConfigurationController.is() ) + return ::std::shared_ptr<ViewShell>(); + + Reference<XResourceId> xPaneId( CreateResourceId( rsPaneURL ) ); + return lcl_getViewShell( lcl_getFirstViewInPane( mxConfigurationController, xPaneId ) ); +} + +::std::shared_ptr<ViewShell> FrameworkHelper::GetViewShell (const Reference<XView>& rxView) +{ + return lcl_getViewShell( rxView ); +} + +Reference<XView> FrameworkHelper::GetView (const Reference<XResourceId>& rxPaneOrViewId) +{ + Reference<XView> xView; + + if ( ! rxPaneOrViewId.is() || ! mxConfigurationController.is()) + return nullptr; + + try + { + if (rxPaneOrViewId->getResourceURL().match(msViewURLPrefix)) + { + xView.set( mxConfigurationController->getResource( rxPaneOrViewId ), UNO_QUERY ); + } + else + { + xView.set( lcl_getFirstViewInPane( mxConfigurationController, rxPaneOrViewId ), UNO_QUERY ); + } + } + catch (lang::DisposedException&) + { + Dispose(); + } + catch (RuntimeException&) + { + } + + return xView; +} + +Reference<XResourceId> FrameworkHelper::RequestView ( + const OUString& rsResourceURL, + const OUString& rsAnchorURL) +{ + Reference<XResourceId> xViewId; + + try + { + if (mxConfigurationController.is()) + { + mxConfigurationController->requestResourceActivation( + CreateResourceId(rsAnchorURL), + ResourceActivationMode_ADD); + xViewId = CreateResourceId(rsResourceURL, rsAnchorURL); + mxConfigurationController->requestResourceActivation( + xViewId, + ResourceActivationMode_REPLACE); + } + } + catch (lang::DisposedException&) + { + Dispose(); + xViewId = nullptr; + } + catch (RuntimeException&) + { + xViewId = nullptr; + } + + return xViewId; +} + +ViewShell::ShellType FrameworkHelper::GetViewId (const OUString& rsViewURL) +{ + if (maViewURLMap.empty()) + { + maViewURLMap[msImpressViewURL] = ViewShell::ST_IMPRESS; + maViewURLMap[msDrawViewURL] = ViewShell::ST_DRAW; + maViewURLMap[msOutlineViewURL] = ViewShell::ST_OUTLINE; + maViewURLMap[msNotesViewURL] = ViewShell::ST_NOTES; + maViewURLMap[msHandoutViewURL] = ViewShell::ST_HANDOUT; + maViewURLMap[msSlideSorterURL] = ViewShell::ST_SLIDE_SORTER; + maViewURLMap[msPresentationViewURL] = ViewShell::ST_PRESENTATION; + maViewURLMap[msSidebarViewURL] = ViewShell::ST_SIDEBAR; + } + ViewURLMap::const_iterator iView (maViewURLMap.find(rsViewURL)); + if (iView != maViewURLMap.end()) + return iView->second; + else + return ViewShell::ST_NONE; +} + +OUString FrameworkHelper::GetViewURL (ViewShell::ShellType eType) +{ + switch (eType) + { + case ViewShell::ST_IMPRESS : return msImpressViewURL; + case ViewShell::ST_DRAW : return msDrawViewURL; + case ViewShell::ST_OUTLINE : return msOutlineViewURL; + case ViewShell::ST_NOTES : return msNotesViewURL; + case ViewShell::ST_HANDOUT : return msHandoutViewURL; + case ViewShell::ST_SLIDE_SORTER : return msSlideSorterURL; + case ViewShell::ST_PRESENTATION : return msPresentationViewURL; + case ViewShell::ST_SIDEBAR : return msSidebarViewURL; + default: + return OUString(); + } +} + +namespace +{ + +void updateEditMode(const Reference<XView> &xView, const EditMode eEMode, bool updateFrameView) +{ + // Ensure we have the expected edit mode + // The check is only for DrawViewShell as OutlineViewShell + // and SlideSorterViewShell have no master mode + const ::std::shared_ptr<ViewShell> pCenterViewShell (FrameworkHelper::GetViewShell(xView)); + DrawViewShell* pDrawViewShell + = dynamic_cast<DrawViewShell*>(pCenterViewShell.get()); + if (pDrawViewShell != nullptr) + { + pCenterViewShell->Broadcast ( + ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START)); + + pDrawViewShell->ChangeEditMode(eEMode, pDrawViewShell->IsLayerModeActive()); + if (updateFrameView) + pDrawViewShell->WriteFrameViewData(); + + pCenterViewShell->Broadcast ( + ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END)); + } +} + +void asyncUpdateEditMode(FrameworkHelper* const pHelper, const EditMode eEMode) +{ + Reference<XResourceId> xPaneId ( + FrameworkHelper::CreateResourceId(framework::FrameworkHelper::msCenterPaneURL)); + Reference<XView> xView (pHelper->GetView(xPaneId)); + updateEditMode(xView, eEMode, true); +} + +} + +void FrameworkHelper::HandleModeChangeSlot ( + sal_uInt16 nSlotId, + SfxRequest const & rRequest) +{ + if ( ! mxConfigurationController.is()) + return; + + // Parameters are allowed for NotesMasterPage and SlideMasterPage + // for these command, transfor xxxxMasterPage with param = false + // to ActivatexxxxxMode + if (nSlotId == SID_NOTES_MASTER_MODE || nSlotId == SID_SLIDE_MASTER_MODE) + { + const SfxItemSet* pRequestArguments = rRequest.GetArgs(); + if (pRequestArguments) + { + const SfxBoolItem* pIsActive = rRequest.GetArg<SfxBoolItem>(nSlotId); + if (!pIsActive->GetValue ()) + { + if (nSlotId == SID_NOTES_MASTER_MODE) + nSlotId = SID_NOTES_MODE; + else + nSlotId = SID_NORMAL_MULTI_PANE_GUI; + } + } + } + + try + { + if ( ! mxConfigurationController.is()) + throw RuntimeException(); + + Reference<XResourceId> xPaneId ( + CreateResourceId(framework::FrameworkHelper::msCenterPaneURL)); + Reference<XView> xView (GetView(xPaneId)); + + // Compute requested view + OUString sRequestedView; + switch (nSlotId) + { + // draw + case SID_DRAWINGMODE: + // impress + case SID_NORMAL_MULTI_PANE_GUI: + case SID_SLIDE_MASTER_MODE: + sRequestedView = FrameworkHelper::msImpressViewURL; + break; + + case SID_NOTES_MODE: + case SID_NOTES_MASTER_MODE: + sRequestedView = FrameworkHelper::msNotesViewURL; + break; + + case SID_HANDOUT_MASTER_MODE: + sRequestedView = FrameworkHelper::msHandoutViewURL; + break; + + case SID_SLIDE_SORTER_MULTI_PANE_GUI: + case SID_SLIDE_SORTER_MODE: + sRequestedView = FrameworkHelper::msSlideSorterURL; + break; + + case SID_OUTLINE_MODE: + sRequestedView = FrameworkHelper::msOutlineViewURL; + break; + } + + // Compute requested mode + EditMode eEMode = EditMode::Page; + if (nSlotId == SID_SLIDE_MASTER_MODE + || nSlotId == SID_NOTES_MASTER_MODE + || nSlotId == SID_HANDOUT_MASTER_MODE) + eEMode = EditMode::MasterPage; + // Ensure we have the expected view shell + if (!(xView.is() && xView->getResourceId()->getResourceURL() == sRequestedView)) + + { + const auto xId = CreateResourceId(sRequestedView, msCenterPaneURL); + mxConfigurationController->requestResourceActivation( + xId, + ResourceActivationMode_REPLACE); + RunOnResourceActivation(xId, std::bind(&asyncUpdateEditMode, this, eEMode)); + } + else + { + updateEditMode(xView, eEMode, false); + } + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("sd"); + } +} + +void FrameworkHelper::RunOnConfigurationEvent( + const OUString& rsEventType, + const Callback& rCallback) +{ + RunOnEvent( + rsEventType, + FrameworkHelperAllPassFilter(), + rCallback); +} + +void FrameworkHelper::RunOnResourceActivation( + const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId, + const Callback& rCallback) +{ + if (mxConfigurationController.is() + && mxConfigurationController->getResource(rxResourceId).is()) + { + rCallback(false); + } + else + { + RunOnEvent( + msResourceActivationEvent, + FrameworkHelperResourceIdFilter(rxResourceId), + rCallback); + } +} + +namespace { + +/** A callback that sets a flag to a specified value when the callback is + called. +*/ +class FlagUpdater +{ +public: + explicit FlagUpdater (bool& rFlag) : mrFlag(rFlag) {} + void operator() (bool) const {mrFlag = true;} +private: + bool& mrFlag; +}; + +} + +void FrameworkHelper::RequestSynchronousUpdate() +{ + rtl::Reference<ConfigurationController> pCC ( + dynamic_cast<ConfigurationController*>(mxConfigurationController.get())); + if (pCC.is()) + pCC->RequestSynchronousUpdate(); +} + +void FrameworkHelper::WaitForEvent (const OUString& rsEventType) const +{ + bool bConfigurationUpdateSeen (false); + + RunOnEvent( + rsEventType, + FrameworkHelperAllPassFilter(), + FlagUpdater(bConfigurationUpdateSeen)); + + sal_uInt32 nStartTime = osl_getGlobalTimer(); + while ( ! bConfigurationUpdateSeen) + { + Application::Reschedule(); + + if( (osl_getGlobalTimer() - nStartTime) > 60000 ) + { + OSL_FAIL("FrameworkHelper::WaitForEvent(), no event for a minute? giving up!"); + break; + } + } +} + +void FrameworkHelper::WaitForUpdate() const +{ + WaitForEvent(msConfigurationUpdateEndEvent); +} + +void FrameworkHelper::RunOnEvent( + const OUString& rsEventType, + const ConfigurationChangeEventFilter& rFilter, + const Callback& rCallback) const +{ + new CallbackCaller(mrBase,rsEventType,rFilter,rCallback); +} + +void FrameworkHelper::disposing (const lang::EventObject& rEventObject) +{ + if (rEventObject.Source == mxConfigurationController) + mxConfigurationController = nullptr; +} + +void FrameworkHelper::UpdateConfiguration() +{ + if (!mxConfigurationController.is()) + return; + + try + { + if (mxConfigurationController.is()) + mxConfigurationController->update(); + } + catch (lang::DisposedException&) + { + Dispose(); + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("sd"); + } +} + +OUString FrameworkHelper::ResourceIdToString (const Reference<XResourceId>& rxResourceId) +{ + OUStringBuffer sString; + if (rxResourceId.is()) + { + sString.append(rxResourceId->getResourceURL()); + if (rxResourceId->hasAnchor()) + { + const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs()); + for (const auto& rAnchorURL : aAnchorURLs) + { + sString.append(" | "); + sString.append(rAnchorURL); + } + } + } + return sString.makeStringAndClear(); +} + +Reference<XResourceId> FrameworkHelper::CreateResourceId (const OUString& rsResourceURL) +{ + return new ::sd::framework::ResourceId(rsResourceURL); +} + +Reference<XResourceId> FrameworkHelper::CreateResourceId ( + const OUString& rsResourceURL, + const OUString& rsAnchorURL) +{ + return new ::sd::framework::ResourceId(rsResourceURL, rsAnchorURL); +} + +Reference<XResourceId> FrameworkHelper::CreateResourceId ( + const OUString& rsResourceURL, + const Reference<XResourceId>& rxAnchorId) +{ + if (rxAnchorId.is()) + return new ::sd::framework::ResourceId( + rsResourceURL, + rxAnchorId->getResourceURL(), + rxAnchorId->getAnchorURLs()); + else + return new ::sd::framework::ResourceId(rsResourceURL); +} + +//----- FrameworkHelper::DisposeListener -------------------------------------- + +FrameworkHelper::DisposeListener::DisposeListener ( + const ::std::shared_ptr<FrameworkHelper>& rpHelper) + : mpHelper(rpHelper) +{ + Reference<XComponent> xComponent (mpHelper->mxConfigurationController, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); +} + +void FrameworkHelper::DisposeListener::disposing(std::unique_lock<std::mutex>&) +{ + Reference<XComponent> xComponent (mpHelper->mxConfigurationController, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(this); + + mpHelper.reset(); +} + +void SAL_CALL FrameworkHelper::DisposeListener::disposing (const lang::EventObject& rEventObject) +{ + if (mpHelper != nullptr) + mpHelper->disposing(rEventObject); +} + +//===== FrameworkHelperResourceIdFilter ======================================= + +FrameworkHelperResourceIdFilter::FrameworkHelperResourceIdFilter ( + const Reference<XResourceId>& rxResourceId) + : mxResourceId(rxResourceId) +{ +} + +} // end of namespace sd::framework + +namespace { + +//===== CallbackCaller ======================================================== + +CallbackCaller::CallbackCaller ( + const ::sd::ViewShellBase& rBase, + const OUString& rsEventType, + const ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter& rFilter, + const ::sd::framework::FrameworkHelper::Callback& rCallback) + : msEventType(rsEventType), + maFilter(rFilter), + maCallback(rCallback) +{ + try + { + Reference<XControllerManager> xControllerManager (rBase.GetController(), UNO_QUERY_THROW); + mxConfigurationController = xControllerManager->getConfigurationController(); + if (mxConfigurationController.is()) + { + if (mxConfigurationController->hasPendingRequests()) + mxConfigurationController->addConfigurationChangeListener(this,msEventType,Any()); + else + { + // There are no requests waiting to be processed. Therefore + // no event, especially not the one we are waiting for, will + // be sent in the near future and the callback would never be + // called. + // Call the callback now and tell him that the event it is + // waiting for was not sent. + mxConfigurationController = nullptr; + maCallback(false); + } + } + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("sd"); + } +} + +void CallbackCaller::disposing(std::unique_lock<std::mutex>&) +{ + try + { + if (mxConfigurationController.is()) + { + Reference<XConfigurationController> xCC (mxConfigurationController); + mxConfigurationController = nullptr; + xCC->removeConfigurationChangeListener(this); + } + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("sd"); + } +} + +void SAL_CALL CallbackCaller::disposing (const lang::EventObject& rEvent) +{ + if (rEvent.Source == mxConfigurationController) + { + mxConfigurationController = nullptr; + maCallback(false); + } +} + +void SAL_CALL CallbackCaller::notifyConfigurationChange ( + const ConfigurationChangeEvent& rEvent) +{ + if (!(rEvent.Type == msEventType && maFilter(rEvent))) + return; + + maCallback(true); + if (mxConfigurationController.is()) + { + // Reset the reference to the configuration controller so that + // dispose() will not try to remove the listener a second time. + Reference<XConfigurationController> xCC (mxConfigurationController); + mxConfigurationController = nullptr; + + // Removing this object from the controller may very likely lead + // to its destruction, so no calls after that. + xCC->removeConfigurationChangeListener(this); + } +} + +//----- LifetimeController ------------------------------------------------- + +LifetimeController::LifetimeController (::sd::ViewShellBase& rBase) + : mrBase(rBase), + mbListeningToViewShellBase(false), + mbListeningToController(false) +{ + // Register as listener at the ViewShellBase. Because that is not done + // via a reference we have to increase the reference count manually. + // This is necessary even though listening to the XController did + // increase the reference count because the controller may release its + // reference to us before the ViewShellBase is destroyed. + StartListening(mrBase); + acquire(); + mbListeningToViewShellBase = true; + + Reference<XComponent> xComponent = rBase.GetController(); + if (xComponent.is()) + { + xComponent->addEventListener(this); + mbListeningToController = true; + } +} + +LifetimeController::~LifetimeController() +{ + OSL_ASSERT(!mbListeningToController && !mbListeningToViewShellBase); +} + +void SAL_CALL LifetimeController::disposing (const lang::EventObject&) +{ + mbListeningToController = false; + Update(); +} + +void LifetimeController::Notify (SfxBroadcaster&, const SfxHint& rHint) +{ + if (rHint.GetId() == SfxHintId::Dying) + { + mbListeningToViewShellBase = false; + Update(); + release(); + } +} + +void LifetimeController::Update() +{ + if (mbListeningToViewShellBase && mbListeningToController) + { + // Both the controller and the ViewShellBase are alive. Keep + // waiting for their destruction. + } + else if (mbListeningToViewShellBase) + { + // The controller has been destroyed but the ViewShellBase is still + // alive. Dispose the associated FrameworkHelper but keep it around + // so that no new instance is created for the dying framework. + ::sd::framework::FrameworkHelper::DisposeInstance(mrBase); + } + else + { + // Both the controller and the ViewShellBase have been destroyed. + // Remove the FrameworkHelper so that the next call its Instance() + // method can create a new instance. + ::sd::framework::FrameworkHelper::ReleaseInstance(mrBase); + } +} + +} // end of anonymous namespace. + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |