945 lines
29 KiB
C++
945 lines
29 KiB
C++
/* -*- 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 <DrawController.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 <utility>
|
|
#include <vcl/svapp.hxx>
|
|
#include <comphelper/diagnose_ex.hxx>
|
|
#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,
|
|
OUString sEventType,
|
|
::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter aFilter,
|
|
::sd::framework::FrameworkHelper::Callback aCallback);
|
|
|
|
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::msBottomImpressPaneURL( msPaneURLPrefix + "BottomImpressPane");
|
|
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");
|
|
const OUString FrameworkHelper::msNotesPanelViewURL( msViewURLPrefix + "NotesPanelView");
|
|
|
|
// 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
|
|
{
|
|
if (auto pWrapper = dynamic_cast<ViewShellWrapper*>(i_rViewShellWrapper.get()))
|
|
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 (::std::shared_ptr<FrameworkHelper> pHelper);
|
|
|
|
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::mutex FrameworkHelper::maInstanceMapMutex;
|
|
|
|
::std::shared_ptr<FrameworkHelper> FrameworkHelper::Instance (ViewShellBase& rBase)
|
|
{
|
|
std::unique_lock aGuard(maInstanceMapMutex);
|
|
|
|
InstanceMap::const_iterator iHelper (maInstanceMap.find(&rBase));
|
|
if (iHelper != maInstanceMap.end())
|
|
return iHelper->second;
|
|
|
|
::std::shared_ptr<FrameworkHelper> pHelper(
|
|
new FrameworkHelper(rBase),
|
|
FrameworkHelper::Deleter());
|
|
pHelper->Initialize();
|
|
maInstanceMap[&rBase] = pHelper;
|
|
|
|
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)
|
|
{
|
|
DrawController* pDrawController = rBase.GetDrawController();
|
|
if (pDrawController)
|
|
{
|
|
mxConfigurationController = pDrawController->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;
|
|
maViewURLMap[msNotesPanelViewURL] = ViewShell::ST_NOTESPANEL;
|
|
}
|
|
ViewURLMap::const_iterator iView (maViewURLMap.find(rsViewURL));
|
|
if (iView != maViewURLMap.end())
|
|
return iView->second;
|
|
else
|
|
return ViewShell::ST_NONE;
|
|
}
|
|
|
|
const 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;
|
|
case ViewShell::ST_NOTESPANEL: return msNotesPanelViewURL;
|
|
default:
|
|
return EMPTY_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(" | " + 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 (
|
|
::std::shared_ptr<FrameworkHelper> pHelper)
|
|
: mpHelper(std::move(pHelper))
|
|
{
|
|
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,
|
|
OUString rsEventType,
|
|
::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter aFilter,
|
|
::sd::framework::FrameworkHelper::Callback aCallback)
|
|
: msEventType(std::move(rsEventType)),
|
|
maFilter(std::move(aFilter)),
|
|
maCallback(std::move(aCallback))
|
|
{
|
|
try
|
|
{
|
|
sd::DrawController* pDrawController = rBase.GetDrawController();
|
|
if (!pDrawController)
|
|
return;
|
|
mxConfigurationController = pDrawController->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: */
|