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 <sal/log.hxx>
28 #include <tools/debug.hxx>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/frame/XFrame.hpp>
32 #include <com/sun/star/lang/DisposedException.hpp>
33 #include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
34 #include <com/sun/star/drawing/framework/XView.hpp>
35 #include <comphelper/compbase.hxx>
36 #include <sfx2/viewfrm.hxx>
38 using namespace ::com::sun::star
;
39 using namespace ::com::sun::star::lang
;
40 using namespace ::com::sun::star::uno
;
41 using namespace ::com::sun::star::drawing::framework
;
43 using ::sd::framework::FrameworkHelper
;
48 const sal_Int32 ResourceActivationEvent
= 0;
49 const sal_Int32 ResourceDeactivationEvent
= 1;
50 const sal_Int32 ConfigurationUpdateEvent
= 2;
55 typedef comphelper::WeakComponentImplHelper
<
56 css::beans::XPropertyChangeListener
,
57 css::frame::XFrameActionListener
,
58 css::view::XSelectionChangeListener
,
59 css::drawing::framework::XConfigurationChangeListener
60 > EventMultiplexerImplementationInterfaceBase
;
62 class EventMultiplexer::Implementation
63 : public EventMultiplexerImplementationInterfaceBase
,
67 explicit Implementation (ViewShellBase
& rBase
);
68 virtual ~Implementation() override
;
70 void AddEventListener (
71 const Link
<EventMultiplexerEvent
&,void>& rCallback
);
73 void RemoveEventListener (
74 const Link
<EventMultiplexerEvent
&,void>& rCallback
);
76 void CallListeners (EventMultiplexerEvent
& rEvent
);
78 //===== lang::XEventListener ==============================================
80 disposing (const css::lang::EventObject
& rEventObject
) override
;
82 //===== beans::XPropertySetListener =======================================
85 const css::beans::PropertyChangeEvent
& rEvent
) override
;
87 //===== view::XSelectionChangeListener ====================================
90 const css::lang::EventObject
& rEvent
) override
;
92 //===== frame::XFrameActionListener ======================================
93 /** For certain actions the listener connects to a new controller of the
94 frame it is listening to. This usually happens when the view shell
95 in the center pane is replaced by another view shell.
98 frameAction (const css::frame::FrameActionEvent
& rEvent
) override
;
100 //===== drawing::framework::XConfigurationChangeListener ==================
101 virtual void SAL_CALL
102 notifyConfigurationChange (
103 const css::drawing::framework::ConfigurationChangeEvent
& rEvent
) override
;
105 virtual void disposing(std::unique_lock
<std::mutex
>&) override
;
108 virtual void Notify (
109 SfxBroadcaster
& rBroadcaster
,
110 const SfxHint
& rHint
) override
;
113 ViewShellBase
& mrBase
;
114 typedef ::std::vector
<Link
<EventMultiplexerEvent
&,void>> ListenerList
;
115 ListenerList maListeners
;
117 /// Remember whether we are listening to the UNO controller.
118 bool mbListeningToController
;
119 /// Remember whether we are listening to the frame.
120 bool mbListeningToFrame
;
122 css::uno::WeakReference
<css::frame::XController
> mxControllerWeak
;
123 css::uno::WeakReference
<css::frame::XFrame
> mxFrameWeak
;
124 SdDrawDocument
* mpDocument
;
125 css::uno::WeakReference
<css::drawing::framework::XConfigurationController
>
126 mxConfigurationControllerWeak
;
128 void ReleaseListeners();
130 void ConnectToController();
131 void DisconnectFromController();
134 EventMultiplexerEventId eId
,
135 void const * pUserData
= nullptr);
137 DECL_LINK(SlideSorterSelectionChangeListener
, LinkParamNone
*, void);
140 constexpr OUStringLiteral aCurrentPagePropertyName
= u
"CurrentPage";
141 constexpr OUStringLiteral aEditModePropertyName
= u
"IsMasterPageMode";
143 //===== EventMultiplexer ======================================================
145 EventMultiplexer::EventMultiplexer (ViewShellBase
& rBase
)
146 : mpImpl (new EventMultiplexer::Implementation(rBase
))
150 EventMultiplexer::~EventMultiplexer()
156 catch (const RuntimeException
&)
159 catch (const Exception
&)
164 void EventMultiplexer::AddEventListener (
165 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
167 mpImpl
->AddEventListener(rCallback
);
170 void EventMultiplexer::RemoveEventListener (
171 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
173 mpImpl
->RemoveEventListener(rCallback
);
176 void EventMultiplexer::MultiplexEvent(
177 EventMultiplexerEventId eEventId
,
178 void const * pUserData
)
180 EventMultiplexerEvent
aEvent(eEventId
, pUserData
);
181 mpImpl
->CallListeners(aEvent
);
184 //===== EventMultiplexer::Implementation ======================================
186 EventMultiplexer::Implementation::Implementation (ViewShellBase
& rBase
)
188 mbListeningToController (false),
189 mbListeningToFrame (false),
190 mxControllerWeak(nullptr),
191 mxFrameWeak(nullptr),
194 // Connect to the frame to listen for controllers being exchanged.
195 // Listen to changes of certain properties.
196 Reference
<frame::XFrame
> xFrame
=
197 mrBase
.GetFrame()->GetFrame().GetFrameInterface();
198 mxFrameWeak
= xFrame
;
201 xFrame
->addFrameActionListener ( Reference
<frame::XFrameActionListener
>(this) );
202 mbListeningToFrame
= true;
205 // Connect to the current controller.
206 ConnectToController ();
208 // Listen for document changes.
209 mpDocument
= mrBase
.GetDocument();
210 if (mpDocument
!= nullptr)
211 StartListening (*mpDocument
);
213 // Listen for configuration changes.
214 DrawController
& rDrawController
= *mrBase
.GetDrawController();
216 Reference
<XConfigurationController
> xConfigurationController (
217 rDrawController
.getConfigurationController());
218 mxConfigurationControllerWeak
= xConfigurationController
;
219 if (!xConfigurationController
.is())
222 Reference
<XComponent
> xComponent (xConfigurationController
, UNO_QUERY
);
224 xComponent
->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 Reference
<XConfigurationController
> xConfigurationController (mxConfigurationControllerWeak
);
271 if (xConfigurationController
.is())
273 Reference
<XComponent
> xComponent (xConfigurationController
, UNO_QUERY
);
275 xComponent
->removeEventListener(static_cast<beans::XPropertyChangeListener
*>(this));
277 xConfigurationController
->removeConfigurationChangeListener(this);
281 void EventMultiplexer::Implementation::AddEventListener (
282 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
284 for (auto const & i
: maListeners
)
287 maListeners
.push_back(rCallback
);
290 void EventMultiplexer::Implementation::RemoveEventListener (
291 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
293 auto iListener
= std::find(maListeners
.begin(), maListeners
.end(), rCallback
);
294 if (iListener
!= maListeners
.end())
295 maListeners
.erase(iListener
);
298 void EventMultiplexer::Implementation::ConnectToController()
300 // Just in case that we missed some event we now disconnect from the old
302 DisconnectFromController ();
304 // Register at the controller of the main view shell.
306 // We have to store a (weak) reference to the controller so that we can
307 // unregister without having to ask the mrBase member (which at that
308 // time may be destroyed.)
309 Reference
<frame::XController
> xController
= mrBase
.GetController();
310 mxControllerWeak
= mrBase
.GetController();
314 // Listen for disposing events.
315 if (xController
.is())
317 xController
->addEventListener (
318 Reference
<lang::XEventListener
>(
319 static_cast<XWeak
*>(this), UNO_QUERY
));
320 mbListeningToController
= true;
323 // Listen to changes of certain properties.
324 Reference
<beans::XPropertySet
> xSet (xController
, UNO_QUERY
);
329 xSet
->addPropertyChangeListener(aCurrentPagePropertyName
, this);
331 catch (const beans::UnknownPropertyException
&)
333 SAL_WARN("sd", "EventMultiplexer::ConnectToController: CurrentPage unknown");
338 xSet
->addPropertyChangeListener(aEditModePropertyName
, this);
340 catch (const beans::UnknownPropertyException
&)
342 SAL_WARN("sd", "EventMultiplexer::ConnectToController: IsMasterPageMode unknown");
346 // Listen for selection change events.
347 Reference
<view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
350 xSelection
->addSelectionChangeListener(this);
353 catch (const lang::DisposedException
&)
355 mbListeningToController
= false;
359 void EventMultiplexer::Implementation::DisconnectFromController()
361 if (!mbListeningToController
)
364 mbListeningToController
= false;
366 Reference
<frame::XController
> xController
= mxControllerWeak
;
368 Reference
<beans::XPropertySet
> xSet (xController
, UNO_QUERY
);
369 // Remove the property listener.
374 xSet
->removePropertyChangeListener(aCurrentPagePropertyName
, this);
376 catch (const beans::UnknownPropertyException
&)
378 SAL_WARN("sd", "DisconnectFromController: CurrentPage unknown");
383 xSet
->removePropertyChangeListener(aEditModePropertyName
, this);
385 catch (const beans::UnknownPropertyException
&)
387 SAL_WARN("sd", "DisconnectFromController: IsMasterPageMode unknown");
391 // Remove selection change listener.
392 Reference
<view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
395 xSelection
->removeSelectionChangeListener(this);
398 // Remove listener for disposing events.
399 if (xController
.is())
401 xController
->removeEventListener (
402 Reference
<lang::XEventListener
>(static_cast<XWeak
*>(this), UNO_QUERY
));
406 //===== lang::XEventListener ================================================
408 void SAL_CALL
EventMultiplexer::Implementation::disposing (
409 const lang::EventObject
& rEventObject
)
411 if (mbListeningToController
)
413 Reference
<frame::XController
> xController (mxControllerWeak
);
414 if (rEventObject
.Source
== xController
)
416 mbListeningToController
= false;
420 Reference
<XConfigurationController
> xConfigurationController (
421 mxConfigurationControllerWeak
);
422 if (xConfigurationController
.is()
423 && rEventObject
.Source
== xConfigurationController
)
425 mxConfigurationControllerWeak
.clear();
429 //===== beans::XPropertySetListener =========================================
431 void SAL_CALL
EventMultiplexer::Implementation::propertyChange (
432 const beans::PropertyChangeEvent
& rEvent
)
436 throw lang::DisposedException (
437 "SlideSorterController object has already been disposed",
438 static_cast<uno::XWeak
*>(this));
441 if ( rEvent
.PropertyName
== aCurrentPagePropertyName
)
443 CallListeners(EventMultiplexerEventId::CurrentPageChanged
);
445 else if ( rEvent
.PropertyName
== aEditModePropertyName
)
447 bool bIsMasterPageMode (false);
448 rEvent
.NewValue
>>= bIsMasterPageMode
;
449 if (bIsMasterPageMode
)
450 CallListeners(EventMultiplexerEventId::EditModeMaster
);
452 CallListeners(EventMultiplexerEventId::EditModeNormal
);
456 //===== frame::XFrameActionListener ==========================================
458 void SAL_CALL
EventMultiplexer::Implementation::frameAction (
459 const frame::FrameActionEvent
& rEvent
)
461 Reference
<frame::XFrame
> xFrame (mxFrameWeak
);
462 if (rEvent
.Frame
!= xFrame
)
465 switch (rEvent
.Action
)
467 case frame::FrameAction_COMPONENT_DETACHING
:
468 DisconnectFromController();
469 CallListeners (EventMultiplexerEventId::ControllerDetached
);
472 case frame::FrameAction_COMPONENT_REATTACHED
:
473 CallListeners (EventMultiplexerEventId::ControllerDetached
);
474 DisconnectFromController();
475 ConnectToController();
476 CallListeners (EventMultiplexerEventId::ControllerAttached
);
479 case frame::FrameAction_COMPONENT_ATTACHED
:
480 ConnectToController();
481 CallListeners (EventMultiplexerEventId::ControllerAttached
);
489 //===== view::XSelectionChangeListener ========================================
491 void SAL_CALL
EventMultiplexer::Implementation::selectionChanged (
492 const lang::EventObject
& )
494 CallListeners (EventMultiplexerEventId::EditViewSelection
);
497 //===== drawing::framework::XConfigurationChangeListener ==================
499 void SAL_CALL
EventMultiplexer::Implementation::notifyConfigurationChange (
500 const ConfigurationChangeEvent
& rEvent
)
502 sal_Int32 nEventType
= 0;
503 rEvent
.UserData
>>= nEventType
;
506 case ResourceActivationEvent
:
507 if (rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
))
509 CallListeners (EventMultiplexerEventId::ViewAdded
);
511 if (rEvent
.ResourceId
->isBoundToURL(
512 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
514 CallListeners (EventMultiplexerEventId::MainViewAdded
);
517 // Add selection change listener at slide sorter.
518 if (rEvent
.ResourceId
->getResourceURL() == FrameworkHelper::msSlideSorterURL
)
520 slidesorter::SlideSorterViewShell
* pViewShell
521 = dynamic_cast<slidesorter::SlideSorterViewShell
*>(
522 FrameworkHelper::GetViewShell(
523 Reference
<XView
>(rEvent
.ResourceObject
,UNO_QUERY
)).get());
524 if (pViewShell
!= nullptr)
525 pViewShell
->AddSelectionChangeListener (
527 EventMultiplexer::Implementation
,
528 SlideSorterSelectionChangeListener
));
533 case ResourceDeactivationEvent
:
534 if (rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
))
536 if (rEvent
.ResourceId
->isBoundToURL(
537 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
539 CallListeners (EventMultiplexerEventId::MainViewRemoved
);
542 // Remove selection change listener from slide sorter. Add
543 // selection change listener at slide sorter.
544 if (rEvent
.ResourceId
->getResourceURL() == FrameworkHelper::msSlideSorterURL
)
546 slidesorter::SlideSorterViewShell
* pViewShell
547 = dynamic_cast<slidesorter::SlideSorterViewShell
*>(
548 FrameworkHelper::GetViewShell(
549 Reference
<XView
>(rEvent
.ResourceObject
, UNO_QUERY
)).get());
550 if (pViewShell
!= nullptr)
551 pViewShell
->RemoveSelectionChangeListener (
553 EventMultiplexer::Implementation
,
554 SlideSorterSelectionChangeListener
));
559 case ConfigurationUpdateEvent
:
560 CallListeners (EventMultiplexerEventId::ConfigurationUpdated
);
566 void EventMultiplexer::Implementation::disposing(std::unique_lock
<std::mutex
>& rGuard
)
568 ListenerList
aCopyListeners( maListeners
);
572 EventMultiplexerEvent
rEvent(EventMultiplexerEventId::Disposing
, nullptr);
573 for (const auto& rListener
: aCopyListeners
)
574 rListener
.Call(rEvent
);
581 void EventMultiplexer::Implementation::Notify (
583 const SfxHint
& rHint
)
585 if (rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
)
587 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
588 switch (pSdrHint
->GetKind())
590 case SdrHintKind::ModelCleared
:
591 case SdrHintKind::PageOrderChange
:
592 CallListeners (EventMultiplexerEventId::PageOrder
);
595 case SdrHintKind::SwitchToPage
:
596 CallListeners (EventMultiplexerEventId::CurrentPageChanged
);
599 case SdrHintKind::ObjectChange
:
600 CallListeners(EventMultiplexerEventId::ShapeChanged
,
601 static_cast<const void*>(pSdrHint
->GetPage()));
604 case SdrHintKind::ObjectInserted
:
605 CallListeners(EventMultiplexerEventId::ShapeInserted
,
606 static_cast<const void*>(pSdrHint
->GetPage()));
609 case SdrHintKind::ObjectRemoved
:
610 CallListeners(EventMultiplexerEventId::ShapeRemoved
,
611 static_cast<const void*>(pSdrHint
->GetPage()));
619 if (rHint
.GetId() == SfxHintId::Dying
)
620 mpDocument
= nullptr;
624 void EventMultiplexer::Implementation::CallListeners (
625 EventMultiplexerEventId eId
,
626 void const * pUserData
)
628 EventMultiplexerEvent
aEvent(eId
, pUserData
);
629 CallListeners(aEvent
);
632 void EventMultiplexer::Implementation::CallListeners (EventMultiplexerEvent
& rEvent
)
634 ListenerList
aCopyListeners( maListeners
);
635 for (const auto& rListener
: aCopyListeners
)
637 rListener
.Call(rEvent
);
641 IMPL_LINK_NOARG(EventMultiplexer::Implementation
, SlideSorterSelectionChangeListener
, LinkParamNone
*, void)
643 CallListeners(EventMultiplexerEventId::SlideSortedSelection
);
646 //===== EventMultiplexerEvent =================================================
648 EventMultiplexerEvent::EventMultiplexerEvent (
649 EventMultiplexerEventId eEventId
,
650 const void* pUserData
)
651 : meEventId(eEventId
),
652 mpUserData(pUserData
)
656 } // end of namespace ::sd::tools
658 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */