1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <EventMultiplexer.hxx>
22 #include <ViewShellBase.hxx>
23 #include <drawdoc.hxx>
24 #include <DrawController.hxx>
25 #include <SlideSorterViewShell.hxx>
26 #include <framework/FrameworkHelper.hxx>
27 #include <framework/ConfigurationController.hxx>
28 #include <sal/log.hxx>
29 #include <tools/debug.hxx>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/frame/XFrame.hpp>
33 #include <com/sun/star/lang/DisposedException.hpp>
34 #include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
35 #include <com/sun/star/drawing/framework/XView.hpp>
36 #include <comphelper/compbase.hxx>
37 #include <sfx2/viewfrm.hxx>
39 using namespace ::com::sun::star
;
40 using namespace ::com::sun::star::lang
;
41 using namespace ::com::sun::star::uno
;
42 using namespace ::com::sun::star::drawing::framework
;
44 using ::sd::framework::FrameworkHelper
;
49 const sal_Int32 ResourceActivationEvent
= 0;
50 const sal_Int32 ResourceDeactivationEvent
= 1;
51 const sal_Int32 ConfigurationUpdateEvent
= 2;
56 typedef comphelper::WeakComponentImplHelper
<
57 css::beans::XPropertyChangeListener
,
58 css::frame::XFrameActionListener
,
59 css::view::XSelectionChangeListener
,
60 css::drawing::framework::XConfigurationChangeListener
61 > EventMultiplexerImplementationInterfaceBase
;
63 class EventMultiplexer::Implementation
64 : public EventMultiplexerImplementationInterfaceBase
,
68 explicit Implementation (ViewShellBase
& rBase
);
69 virtual ~Implementation() override
;
71 void AddEventListener (
72 const Link
<EventMultiplexerEvent
&,void>& rCallback
);
74 void RemoveEventListener (
75 const Link
<EventMultiplexerEvent
&,void>& rCallback
);
77 void CallListeners (EventMultiplexerEvent
& rEvent
);
79 //===== lang::XEventListener ==============================================
81 disposing (const css::lang::EventObject
& rEventObject
) override
;
83 //===== beans::XPropertySetListener =======================================
86 const css::beans::PropertyChangeEvent
& rEvent
) override
;
88 //===== view::XSelectionChangeListener ====================================
91 const css::lang::EventObject
& rEvent
) override
;
93 //===== frame::XFrameActionListener ======================================
94 /** For certain actions the listener connects to a new controller of the
95 frame it is listening to. This usually happens when the view shell
96 in the center pane is replaced by another view shell.
99 frameAction (const css::frame::FrameActionEvent
& rEvent
) override
;
101 //===== drawing::framework::XConfigurationChangeListener ==================
102 virtual void SAL_CALL
103 notifyConfigurationChange (
104 const css::drawing::framework::ConfigurationChangeEvent
& rEvent
) override
;
106 virtual void disposing(std::unique_lock
<std::mutex
>&) override
;
109 virtual void Notify (
110 SfxBroadcaster
& rBroadcaster
,
111 const SfxHint
& rHint
) override
;
114 ViewShellBase
& mrBase
;
115 typedef ::std::vector
<Link
<EventMultiplexerEvent
&,void>> ListenerList
;
116 ListenerList maListeners
;
118 /// Remember whether we are listening to the UNO controller.
119 bool mbListeningToController
;
120 /// Remember whether we are listening to the frame.
121 bool mbListeningToFrame
;
123 css::uno::WeakReference
<css::frame::XController
> mxControllerWeak
;
124 css::uno::WeakReference
<css::frame::XFrame
> mxFrameWeak
;
125 SdDrawDocument
* mpDocument
;
126 unotools::WeakReference
<sd::framework::ConfigurationController
>
127 mxConfigurationControllerWeak
;
129 void ReleaseListeners();
131 void ConnectToController();
132 void DisconnectFromController();
135 EventMultiplexerEventId eId
,
136 void const * pUserData
= nullptr,
137 const css::uno::Reference
<css::uno::XInterface
>& xUserData
= {});
139 DECL_LINK(SlideSorterSelectionChangeListener
, LinkParamNone
*, void);
142 constexpr OUString aCurrentPagePropertyName
= u
"CurrentPage"_ustr
;
143 constexpr OUString aEditModePropertyName
= u
"IsMasterPageMode"_ustr
;
145 //===== EventMultiplexer ======================================================
147 EventMultiplexer::EventMultiplexer (ViewShellBase
& rBase
)
148 : mpImpl (new EventMultiplexer::Implementation(rBase
))
152 EventMultiplexer::~EventMultiplexer()
158 catch (const RuntimeException
&)
161 catch (const Exception
&)
166 void EventMultiplexer::AddEventListener (
167 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
169 mpImpl
->AddEventListener(rCallback
);
172 void EventMultiplexer::RemoveEventListener (
173 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
175 mpImpl
->RemoveEventListener(rCallback
);
178 void EventMultiplexer::MultiplexEvent(EventMultiplexerEventId eEventId
, void const* pUserData
,
179 const css::uno::Reference
<css::uno::XInterface
>& xUserData
)
181 EventMultiplexerEvent
aEvent(eEventId
, pUserData
, xUserData
);
182 mpImpl
->CallListeners(aEvent
);
185 //===== EventMultiplexer::Implementation ======================================
187 EventMultiplexer::Implementation::Implementation (ViewShellBase
& rBase
)
189 mbListeningToController (false),
190 mbListeningToFrame (false),
191 mxControllerWeak(nullptr),
192 mxFrameWeak(nullptr),
195 // Connect to the frame to listen for controllers being exchanged.
196 // Listen to changes of certain properties.
197 Reference
<frame::XFrame
> xFrame
;
198 if (SfxViewFrame
* pFrame
= mrBase
.GetFrame())
199 xFrame
= pFrame
->GetFrame().GetFrameInterface();
200 mxFrameWeak
= xFrame
;
203 xFrame
->addFrameActionListener ( Reference
<frame::XFrameActionListener
>(this) );
204 mbListeningToFrame
= true;
207 // Connect to the current controller.
208 ConnectToController ();
210 // Listen for document changes.
211 mpDocument
= mrBase
.GetDocument();
212 if (mpDocument
!= nullptr)
213 StartListening (*mpDocument
);
215 // Listen for configuration changes.
216 DrawController
& rDrawController
= *mrBase
.GetDrawController();
218 rtl::Reference
<sd::framework::ConfigurationController
> xConfigurationController (
219 rDrawController
.getConfigurationControllerImpl());
220 mxConfigurationControllerWeak
= xConfigurationController
.get();
221 if (!xConfigurationController
.is())
224 xConfigurationController
->addEventListener(static_cast<beans::XPropertyChangeListener
*>(this));
226 xConfigurationController
->addConfigurationChangeListener(
228 FrameworkHelper::msResourceActivationEvent
,
229 Any(ResourceActivationEvent
));
230 xConfigurationController
->addConfigurationChangeListener(
232 FrameworkHelper::msResourceDeactivationEvent
,
233 Any(ResourceDeactivationEvent
));
234 xConfigurationController
->addConfigurationChangeListener(
236 FrameworkHelper::msConfigurationUpdateEndEvent
,
237 Any(ConfigurationUpdateEvent
));
240 EventMultiplexer::Implementation::~Implementation()
242 DBG_ASSERT( !mbListeningToFrame
,
243 "sd::EventMultiplexer::Implementation::~Implementation(), disposing was not called!" );
246 void EventMultiplexer::Implementation::ReleaseListeners()
248 if (mbListeningToFrame
)
250 mbListeningToFrame
= false;
252 // Stop listening for changes of certain properties.
253 Reference
<frame::XFrame
> xFrame (mxFrameWeak
);
256 xFrame
->removeFrameActionListener (
257 Reference
<frame::XFrameActionListener
>(this) );
261 DisconnectFromController ();
263 if (mpDocument
!= nullptr)
265 EndListening (*mpDocument
);
266 mpDocument
= nullptr;
269 // Stop listening for configuration changes.
270 rtl::Reference
<sd::framework::ConfigurationController
> xConfigurationController (mxConfigurationControllerWeak
.get());
271 if (xConfigurationController
.is())
273 xConfigurationController
->removeEventListener(static_cast<beans::XPropertyChangeListener
*>(this));
274 xConfigurationController
->removeConfigurationChangeListener(this);
278 void EventMultiplexer::Implementation::AddEventListener (
279 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
281 for (auto const & i
: maListeners
)
284 maListeners
.push_back(rCallback
);
287 void EventMultiplexer::Implementation::RemoveEventListener (
288 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
290 auto iListener
= std::find(maListeners
.begin(), maListeners
.end(), rCallback
);
291 if (iListener
!= maListeners
.end())
292 maListeners
.erase(iListener
);
295 void EventMultiplexer::Implementation::ConnectToController()
297 // Just in case that we missed some event we now disconnect from the old
299 DisconnectFromController ();
301 // Register at the controller of the main view shell.
303 // We have to store a (weak) reference to the controller so that we can
304 // unregister without having to ask the mrBase member (which at that
305 // time may be destroyed.)
306 Reference
<frame::XController
> xController
= mrBase
.GetController();
307 mxControllerWeak
= mrBase
.GetController();
311 // Listen for disposing events.
312 if (xController
.is())
314 xController
->addEventListener (
315 Reference
<lang::XEventListener
>(
316 static_cast<XWeak
*>(this), UNO_QUERY
));
317 mbListeningToController
= true;
320 // Listen to changes of certain properties.
321 Reference
<beans::XPropertySet
> xSet (xController
, UNO_QUERY
);
326 xSet
->addPropertyChangeListener(aCurrentPagePropertyName
, this);
328 catch (const beans::UnknownPropertyException
&)
330 SAL_WARN("sd", "EventMultiplexer::ConnectToController: CurrentPage unknown");
335 xSet
->addPropertyChangeListener(aEditModePropertyName
, this);
337 catch (const beans::UnknownPropertyException
&)
339 SAL_WARN("sd", "EventMultiplexer::ConnectToController: IsMasterPageMode unknown");
343 // Listen for selection change events.
344 Reference
<view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
347 xSelection
->addSelectionChangeListener(this);
350 catch (const lang::DisposedException
&)
352 mbListeningToController
= false;
356 void EventMultiplexer::Implementation::DisconnectFromController()
358 if (!mbListeningToController
)
361 mbListeningToController
= false;
363 Reference
<frame::XController
> xController
= mxControllerWeak
;
365 Reference
<beans::XPropertySet
> xSet (xController
, UNO_QUERY
);
366 // Remove the property listener.
371 xSet
->removePropertyChangeListener(aCurrentPagePropertyName
, this);
373 catch (const beans::UnknownPropertyException
&)
375 SAL_WARN("sd", "DisconnectFromController: CurrentPage unknown");
380 xSet
->removePropertyChangeListener(aEditModePropertyName
, this);
382 catch (const beans::UnknownPropertyException
&)
384 SAL_WARN("sd", "DisconnectFromController: IsMasterPageMode unknown");
388 // Remove selection change listener.
389 Reference
<view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
392 xSelection
->removeSelectionChangeListener(this);
395 // Remove listener for disposing events.
396 if (xController
.is())
398 xController
->removeEventListener (
399 Reference
<lang::XEventListener
>(static_cast<XWeak
*>(this), UNO_QUERY
));
403 //===== lang::XEventListener ================================================
405 void SAL_CALL
EventMultiplexer::Implementation::disposing (
406 const lang::EventObject
& rEventObject
)
408 if (mbListeningToController
)
410 Reference
<frame::XController
> xController (mxControllerWeak
);
411 if (rEventObject
.Source
== xController
)
413 mbListeningToController
= false;
417 rtl::Reference
<sd::framework::ConfigurationController
> xConfigurationController (
418 mxConfigurationControllerWeak
);
419 if (xConfigurationController
.is()
420 && rEventObject
.Source
== cppu::getXWeak(xConfigurationController
.get()))
422 mxConfigurationControllerWeak
.clear();
426 //===== beans::XPropertySetListener =========================================
428 void SAL_CALL
EventMultiplexer::Implementation::propertyChange (
429 const beans::PropertyChangeEvent
& rEvent
)
433 throw lang::DisposedException (
434 u
"SlideSorterController object has already been disposed"_ustr
,
435 static_cast<uno::XWeak
*>(this));
438 if ( rEvent
.PropertyName
== aCurrentPagePropertyName
)
440 CallListeners(EventMultiplexerEventId::CurrentPageChanged
);
442 else if ( rEvent
.PropertyName
== aEditModePropertyName
)
444 bool bIsMasterPageMode (false);
445 rEvent
.NewValue
>>= bIsMasterPageMode
;
446 if (bIsMasterPageMode
)
447 CallListeners(EventMultiplexerEventId::EditModeMaster
);
449 CallListeners(EventMultiplexerEventId::EditModeNormal
);
453 //===== frame::XFrameActionListener ==========================================
455 void SAL_CALL
EventMultiplexer::Implementation::frameAction (
456 const frame::FrameActionEvent
& rEvent
)
458 Reference
<frame::XFrame
> xFrame (mxFrameWeak
);
459 if (rEvent
.Frame
!= xFrame
)
462 switch (rEvent
.Action
)
464 case frame::FrameAction_COMPONENT_DETACHING
:
465 DisconnectFromController();
466 CallListeners (EventMultiplexerEventId::ControllerDetached
);
469 case frame::FrameAction_COMPONENT_REATTACHED
:
470 CallListeners (EventMultiplexerEventId::ControllerDetached
);
471 DisconnectFromController();
472 ConnectToController();
473 CallListeners (EventMultiplexerEventId::ControllerAttached
);
476 case frame::FrameAction_COMPONENT_ATTACHED
:
477 ConnectToController();
478 CallListeners (EventMultiplexerEventId::ControllerAttached
);
486 //===== view::XSelectionChangeListener ========================================
488 void SAL_CALL
EventMultiplexer::Implementation::selectionChanged (
489 const lang::EventObject
& )
491 CallListeners (EventMultiplexerEventId::EditViewSelection
);
494 //===== drawing::framework::XConfigurationChangeListener ==================
496 void SAL_CALL
EventMultiplexer::Implementation::notifyConfigurationChange (
497 const ConfigurationChangeEvent
& rEvent
)
499 sal_Int32 nEventType
= 0;
500 rEvent
.UserData
>>= nEventType
;
503 case ResourceActivationEvent
:
504 if (rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
))
506 CallListeners (EventMultiplexerEventId::ViewAdded
);
508 if (rEvent
.ResourceId
->isBoundToURL(
509 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
511 CallListeners (EventMultiplexerEventId::MainViewAdded
);
514 // Add selection change listener at slide sorter.
515 if (rEvent
.ResourceId
->getResourceURL() == FrameworkHelper::msSlideSorterURL
)
517 slidesorter::SlideSorterViewShell
* pViewShell
518 = dynamic_cast<slidesorter::SlideSorterViewShell
*>(
519 FrameworkHelper::GetViewShell(
520 Reference
<XView
>(rEvent
.ResourceObject
,UNO_QUERY
)).get());
521 if (pViewShell
!= nullptr)
522 pViewShell
->AddSelectionChangeListener (
524 EventMultiplexer::Implementation
,
525 SlideSorterSelectionChangeListener
));
530 case ResourceDeactivationEvent
:
531 if (rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
))
533 if (rEvent
.ResourceId
->isBoundToURL(
534 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
536 CallListeners (EventMultiplexerEventId::MainViewRemoved
);
539 // Remove selection change listener from slide sorter. Add
540 // selection change listener at slide sorter.
541 if (rEvent
.ResourceId
->getResourceURL() == FrameworkHelper::msSlideSorterURL
)
543 slidesorter::SlideSorterViewShell
* pViewShell
544 = dynamic_cast<slidesorter::SlideSorterViewShell
*>(
545 FrameworkHelper::GetViewShell(
546 Reference
<XView
>(rEvent
.ResourceObject
, UNO_QUERY
)).get());
547 if (pViewShell
!= nullptr)
548 pViewShell
->RemoveSelectionChangeListener (
550 EventMultiplexer::Implementation
,
551 SlideSorterSelectionChangeListener
));
556 case ConfigurationUpdateEvent
:
557 CallListeners (EventMultiplexerEventId::ConfigurationUpdated
);
563 void EventMultiplexer::Implementation::disposing(std::unique_lock
<std::mutex
>& rGuard
)
565 ListenerList
aCopyListeners( maListeners
);
569 EventMultiplexerEvent
rEvent(EventMultiplexerEventId::Disposing
, nullptr);
570 for (const auto& rListener
: aCopyListeners
)
571 rListener
.Call(rEvent
);
578 void EventMultiplexer::Implementation::Notify (
580 const SfxHint
& rHint
)
582 if (rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
)
584 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
585 switch (pSdrHint
->GetKind())
587 case SdrHintKind::ModelCleared
:
588 case SdrHintKind::PageOrderChange
:
589 CallListeners (EventMultiplexerEventId::PageOrder
);
592 case SdrHintKind::SwitchToPage
:
593 CallListeners (EventMultiplexerEventId::CurrentPageChanged
);
596 case SdrHintKind::ObjectChange
:
597 CallListeners(EventMultiplexerEventId::ShapeChanged
,
598 static_cast<const void*>(pSdrHint
->GetPage()));
601 case SdrHintKind::ObjectInserted
:
602 CallListeners(EventMultiplexerEventId::ShapeInserted
,
603 static_cast<const void*>(pSdrHint
->GetPage()));
606 case SdrHintKind::ObjectRemoved
:
607 CallListeners(EventMultiplexerEventId::ShapeRemoved
,
608 static_cast<const void*>(pSdrHint
->GetPage()));
616 if (rHint
.GetId() == SfxHintId::Dying
)
617 mpDocument
= nullptr;
621 void EventMultiplexer::Implementation::CallListeners(
622 EventMultiplexerEventId eId
, void const* pUserData
,
623 const css::uno::Reference
<css::uno::XInterface
>& xUserData
)
625 EventMultiplexerEvent
aEvent(eId
, pUserData
, xUserData
);
626 CallListeners(aEvent
);
629 void EventMultiplexer::Implementation::CallListeners (EventMultiplexerEvent
& rEvent
)
631 ListenerList
aCopyListeners( maListeners
);
632 for (const auto& rListener
: aCopyListeners
)
634 rListener
.Call(rEvent
);
638 IMPL_LINK_NOARG(EventMultiplexer::Implementation
, SlideSorterSelectionChangeListener
, LinkParamNone
*, void)
640 CallListeners(EventMultiplexerEventId::SlideSortedSelection
);
643 //===== EventMultiplexerEvent =================================================
645 EventMultiplexerEvent::EventMultiplexerEvent (
646 EventMultiplexerEventId eEventId
,
647 const void* pUserData
,
648 const css::uno::Reference
<css::uno::XInterface
>& xUserData
)
649 : meEventId(eEventId
),
650 mpUserData(pUserData
),
651 mxUserData(xUserData
)
655 } // end of namespace ::sd::tools
657 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */