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 <MutexOwner.hxx>
23 #include <ViewShellBase.hxx>
24 #include <drawdoc.hxx>
25 #include <DrawController.hxx>
26 #include <SlideSorterViewShell.hxx>
27 #include <framework/FrameworkHelper.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 <cppuhelper/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 cppu::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 : protected MutexOwner
,
65 public EventMultiplexerImplementationInterfaceBase
,
69 explicit Implementation (ViewShellBase
& rBase
);
70 virtual ~Implementation() override
;
72 void AddEventListener (
73 const Link
<EventMultiplexerEvent
&,void>& rCallback
);
75 void RemoveEventListener (
76 const Link
<EventMultiplexerEvent
&,void>& rCallback
);
78 void CallListeners (EventMultiplexerEvent
& rEvent
);
80 //===== lang::XEventListener ==============================================
82 disposing (const css::lang::EventObject
& rEventObject
) override
;
84 //===== beans::XPropertySetListener =======================================
87 const css::beans::PropertyChangeEvent
& rEvent
) override
;
89 //===== view::XSelectionChangeListener ====================================
92 const css::lang::EventObject
& rEvent
) override
;
94 //===== frame::XFrameActionListener ======================================
95 /** For certain actions the listener connects to a new controller of the
96 frame it is listening to. This usually happens when the view shell
97 in the center pane is replaced by another view shell.
100 frameAction (const css::frame::FrameActionEvent
& rEvent
) override
;
102 //===== drawing::framework::XConfigurationChangeListener ==================
103 virtual void SAL_CALL
104 notifyConfigurationChange (
105 const css::drawing::framework::ConfigurationChangeEvent
& rEvent
) override
;
107 virtual void SAL_CALL
disposing() override
;
110 virtual void Notify (
111 SfxBroadcaster
& rBroadcaster
,
112 const SfxHint
& rHint
) override
;
115 ViewShellBase
& mrBase
;
116 typedef ::std::vector
<Link
<EventMultiplexerEvent
&,void>> ListenerList
;
117 ListenerList maListeners
;
119 /// Remember whether we are listening to the UNO controller.
120 bool mbListeningToController
;
121 /// Remember whether we are listening to the frame.
122 bool mbListeningToFrame
;
124 css::uno::WeakReference
<css::frame::XController
> mxControllerWeak
;
125 css::uno::WeakReference
<css::frame::XFrame
> mxFrameWeak
;
126 SdDrawDocument
* mpDocument
;
127 css::uno::WeakReference
<css::drawing::framework::XConfigurationController
>
128 mxConfigurationControllerWeak
;
130 void ReleaseListeners();
132 void ConnectToController();
133 void DisconnectFromController();
136 EventMultiplexerEventId eId
,
137 void const * pUserData
= nullptr);
139 DECL_LINK(SlideSorterSelectionChangeListener
, LinkParamNone
*, void);
142 const char aCurrentPagePropertyName
[] = "CurrentPage";
143 const char aEditModePropertyName
[] = "IsMasterPageMode";
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(
179 EventMultiplexerEventId eEventId
,
180 void const * pUserData
)
182 EventMultiplexerEvent
aEvent(eEventId
, pUserData
);
183 mpImpl
->CallListeners(aEvent
);
186 //===== EventMultiplexer::Implementation ======================================
188 EventMultiplexer::Implementation::Implementation (ViewShellBase
& rBase
)
190 EventMultiplexerImplementationInterfaceBase(maMutex
),
193 mbListeningToController (false),
194 mbListeningToFrame (false),
195 mxControllerWeak(nullptr),
196 mxFrameWeak(nullptr),
198 mxConfigurationControllerWeak()
200 // Connect to the frame to listen for controllers being exchanged.
201 // Listen to changes of certain properties.
202 Reference
<frame::XFrame
> xFrame
=
203 mrBase
.GetFrame()->GetFrame().GetFrameInterface();
204 mxFrameWeak
= xFrame
;
207 xFrame
->addFrameActionListener (
208 Reference
<frame::XFrameActionListener
>(
209 static_cast<XWeak
*>(this), UNO_QUERY
));
210 mbListeningToFrame
= true;
213 // Connect to the current controller.
214 ConnectToController ();
216 // Listen for document changes.
217 mpDocument
= mrBase
.GetDocument();
218 if (mpDocument
!= nullptr)
219 StartListening (*mpDocument
);
221 // Listen for configuration changes.
222 Reference
<XControllerManager
> xControllerManager (
223 Reference
<XWeak
>(&mrBase
.GetDrawController()), UNO_QUERY
);
224 if (!xControllerManager
.is())
227 Reference
<XConfigurationController
> xConfigurationController (
228 xControllerManager
->getConfigurationController());
229 mxConfigurationControllerWeak
= xConfigurationController
;
230 if (!xConfigurationController
.is())
233 Reference
<XComponent
> xComponent (xConfigurationController
, UNO_QUERY
);
235 xComponent
->addEventListener(static_cast<beans::XPropertyChangeListener
*>(this));
237 xConfigurationController
->addConfigurationChangeListener(
239 FrameworkHelper::msResourceActivationEvent
,
240 makeAny(ResourceActivationEvent
));
241 xConfigurationController
->addConfigurationChangeListener(
243 FrameworkHelper::msResourceDeactivationEvent
,
244 makeAny(ResourceDeactivationEvent
));
245 xConfigurationController
->addConfigurationChangeListener(
247 FrameworkHelper::msConfigurationUpdateEndEvent
,
248 makeAny(ConfigurationUpdateEvent
));
251 EventMultiplexer::Implementation::~Implementation()
253 DBG_ASSERT( !mbListeningToFrame
,
254 "sd::EventMultiplexer::Implementation::~Implementation(), disposing was not called!" );
257 void EventMultiplexer::Implementation::ReleaseListeners()
259 if (mbListeningToFrame
)
261 mbListeningToFrame
= false;
263 // Stop listening for changes of certain properties.
264 Reference
<frame::XFrame
> xFrame (mxFrameWeak
);
267 xFrame
->removeFrameActionListener (
268 Reference
<frame::XFrameActionListener
>(
269 static_cast<XWeak
*>(this), UNO_QUERY
));
273 DisconnectFromController ();
275 if (mpDocument
!= nullptr)
277 EndListening (*mpDocument
);
278 mpDocument
= nullptr;
281 // Stop listening for configuration changes.
282 Reference
<XConfigurationController
> xConfigurationController (mxConfigurationControllerWeak
);
283 if (xConfigurationController
.is())
285 Reference
<XComponent
> xComponent (xConfigurationController
, UNO_QUERY
);
287 xComponent
->removeEventListener(static_cast<beans::XPropertyChangeListener
*>(this));
289 xConfigurationController
->removeConfigurationChangeListener(this);
293 void EventMultiplexer::Implementation::AddEventListener (
294 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
296 for (auto const & i
: maListeners
)
299 maListeners
.push_back(rCallback
);
302 void EventMultiplexer::Implementation::RemoveEventListener (
303 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
305 auto iListener
= std::find(maListeners
.begin(), maListeners
.end(), rCallback
);
306 if (iListener
!= maListeners
.end())
307 maListeners
.erase(iListener
);
310 void EventMultiplexer::Implementation::ConnectToController()
312 // Just in case that we missed some event we now disconnect from the old
314 DisconnectFromController ();
316 // Register at the controller of the main view shell.
318 // We have to store a (weak) reference to the controller so that we can
319 // unregister without having to ask the mrBase member (which at that
320 // time may be destroyed.)
321 Reference
<frame::XController
> xController
= mrBase
.GetController();
322 mxControllerWeak
= mrBase
.GetController();
326 // Listen for disposing events.
327 if (xController
.is())
329 xController
->addEventListener (
330 Reference
<lang::XEventListener
>(
331 static_cast<XWeak
*>(this), UNO_QUERY
));
332 mbListeningToController
= true;
335 // Listen to changes of certain properties.
336 Reference
<beans::XPropertySet
> xSet (xController
, UNO_QUERY
);
341 xSet
->addPropertyChangeListener(aCurrentPagePropertyName
, this);
343 catch (const beans::UnknownPropertyException
&)
345 SAL_WARN("sd", "EventMultiplexer::ConnectToController: CurrentPage unknown");
350 xSet
->addPropertyChangeListener(aEditModePropertyName
, this);
352 catch (const beans::UnknownPropertyException
&)
354 SAL_WARN("sd", "EventMultiplexer::ConnectToController: IsMasterPageMode unknown");
358 // Listen for selection change events.
359 Reference
<view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
362 xSelection
->addSelectionChangeListener(this);
365 catch (const lang::DisposedException
&)
367 mbListeningToController
= false;
371 void EventMultiplexer::Implementation::DisconnectFromController()
373 if (!mbListeningToController
)
376 mbListeningToController
= false;
378 Reference
<frame::XController
> xController
= mxControllerWeak
;
380 Reference
<beans::XPropertySet
> xSet (xController
, UNO_QUERY
);
381 // Remove the property listener.
386 xSet
->removePropertyChangeListener(aCurrentPagePropertyName
, this);
388 catch (const beans::UnknownPropertyException
&)
390 SAL_WARN("sd", "DisconnectFromController: CurrentPage unknown");
395 xSet
->removePropertyChangeListener(aEditModePropertyName
, this);
397 catch (const beans::UnknownPropertyException
&)
399 SAL_WARN("sd", "DisconnectFromController: IsMasterPageMode unknown");
403 // Remove selection change listener.
404 Reference
<view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
407 xSelection
->removeSelectionChangeListener(this);
410 // Remove listener for disposing events.
411 if (xController
.is())
413 xController
->removeEventListener (
414 Reference
<lang::XEventListener
>(static_cast<XWeak
*>(this), UNO_QUERY
));
418 //===== lang::XEventListener ================================================
420 void SAL_CALL
EventMultiplexer::Implementation::disposing (
421 const lang::EventObject
& rEventObject
)
423 if (mbListeningToController
)
425 Reference
<frame::XController
> xController (mxControllerWeak
);
426 if (rEventObject
.Source
== xController
)
428 mbListeningToController
= false;
432 Reference
<XConfigurationController
> xConfigurationController (
433 mxConfigurationControllerWeak
);
434 if (xConfigurationController
.is()
435 && rEventObject
.Source
== xConfigurationController
)
437 mxConfigurationControllerWeak
.clear();
441 //===== beans::XPropertySetListener =========================================
443 void SAL_CALL
EventMultiplexer::Implementation::propertyChange (
444 const beans::PropertyChangeEvent
& rEvent
)
446 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
448 throw lang::DisposedException (
449 "SlideSorterController object has already been disposed",
450 static_cast<uno::XWeak
*>(this));
453 if ( rEvent
.PropertyName
== aCurrentPagePropertyName
)
455 CallListeners(EventMultiplexerEventId::CurrentPageChanged
);
457 else if ( rEvent
.PropertyName
== aEditModePropertyName
)
459 bool bIsMasterPageMode (false);
460 rEvent
.NewValue
>>= bIsMasterPageMode
;
461 if (bIsMasterPageMode
)
462 CallListeners(EventMultiplexerEventId::EditModeMaster
);
464 CallListeners(EventMultiplexerEventId::EditModeNormal
);
468 //===== frame::XFrameActionListener ==========================================
470 void SAL_CALL
EventMultiplexer::Implementation::frameAction (
471 const frame::FrameActionEvent
& rEvent
)
473 Reference
<frame::XFrame
> xFrame (mxFrameWeak
);
474 if (rEvent
.Frame
!= xFrame
)
477 switch (rEvent
.Action
)
479 case frame::FrameAction_COMPONENT_DETACHING
:
480 DisconnectFromController();
481 CallListeners (EventMultiplexerEventId::ControllerDetached
);
484 case frame::FrameAction_COMPONENT_REATTACHED
:
485 CallListeners (EventMultiplexerEventId::ControllerDetached
);
486 DisconnectFromController();
487 ConnectToController();
488 CallListeners (EventMultiplexerEventId::ControllerAttached
);
491 case frame::FrameAction_COMPONENT_ATTACHED
:
492 ConnectToController();
493 CallListeners (EventMultiplexerEventId::ControllerAttached
);
501 //===== view::XSelectionChangeListener ========================================
503 void SAL_CALL
EventMultiplexer::Implementation::selectionChanged (
504 const lang::EventObject
& )
506 CallListeners (EventMultiplexerEventId::EditViewSelection
);
509 //===== drawing::framework::XConfigurationChangeListener ==================
511 void SAL_CALL
EventMultiplexer::Implementation::notifyConfigurationChange (
512 const ConfigurationChangeEvent
& rEvent
)
514 sal_Int32 nEventType
= 0;
515 rEvent
.UserData
>>= nEventType
;
518 case ResourceActivationEvent
:
519 if (rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
))
521 CallListeners (EventMultiplexerEventId::ViewAdded
);
523 if (rEvent
.ResourceId
->isBoundToURL(
524 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
526 CallListeners (EventMultiplexerEventId::MainViewAdded
);
529 // Add selection change listener at slide sorter.
530 if (rEvent
.ResourceId
->getResourceURL() == FrameworkHelper::msSlideSorterURL
)
532 slidesorter::SlideSorterViewShell
* pViewShell
533 = dynamic_cast<slidesorter::SlideSorterViewShell
*>(
534 FrameworkHelper::GetViewShell(
535 Reference
<XView
>(rEvent
.ResourceObject
,UNO_QUERY
)).get());
536 if (pViewShell
!= nullptr)
537 pViewShell
->AddSelectionChangeListener (
539 EventMultiplexer::Implementation
,
540 SlideSorterSelectionChangeListener
));
545 case ResourceDeactivationEvent
:
546 if (rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
))
548 if (rEvent
.ResourceId
->isBoundToURL(
549 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
551 CallListeners (EventMultiplexerEventId::MainViewRemoved
);
554 // Remove selection change listener from slide sorter. Add
555 // selection change listener at slide sorter.
556 if (rEvent
.ResourceId
->getResourceURL() == FrameworkHelper::msSlideSorterURL
)
558 slidesorter::SlideSorterViewShell
* pViewShell
559 = dynamic_cast<slidesorter::SlideSorterViewShell
*>(
560 FrameworkHelper::GetViewShell(
561 Reference
<XView
>(rEvent
.ResourceObject
, UNO_QUERY
)).get());
562 if (pViewShell
!= nullptr)
563 pViewShell
->RemoveSelectionChangeListener (
565 EventMultiplexer::Implementation
,
566 SlideSorterSelectionChangeListener
));
571 case ConfigurationUpdateEvent
:
572 CallListeners (EventMultiplexerEventId::ConfigurationUpdated
);
578 void SAL_CALL
EventMultiplexer::Implementation::disposing()
580 CallListeners (EventMultiplexerEventId::Disposing
);
584 void EventMultiplexer::Implementation::Notify (
586 const SfxHint
& rHint
)
588 if (rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
)
590 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
591 switch (pSdrHint
->GetKind())
593 case SdrHintKind::ModelCleared
:
594 case SdrHintKind::PageOrderChange
:
595 CallListeners (EventMultiplexerEventId::PageOrder
);
598 case SdrHintKind::SwitchToPage
:
599 CallListeners (EventMultiplexerEventId::CurrentPageChanged
);
602 case SdrHintKind::ObjectChange
:
603 CallListeners(EventMultiplexerEventId::ShapeChanged
,
604 static_cast<const void*>(pSdrHint
->GetPage()));
607 case SdrHintKind::ObjectInserted
:
608 CallListeners(EventMultiplexerEventId::ShapeInserted
,
609 static_cast<const void*>(pSdrHint
->GetPage()));
612 case SdrHintKind::ObjectRemoved
:
613 CallListeners(EventMultiplexerEventId::ShapeRemoved
,
614 static_cast<const void*>(pSdrHint
->GetPage()));
622 if (rHint
.GetId() == SfxHintId::Dying
)
623 mpDocument
= nullptr;
627 void EventMultiplexer::Implementation::CallListeners (
628 EventMultiplexerEventId eId
,
629 void const * pUserData
)
631 EventMultiplexerEvent
aEvent(eId
, pUserData
);
632 CallListeners(aEvent
);
635 void EventMultiplexer::Implementation::CallListeners (EventMultiplexerEvent
& rEvent
)
637 ListenerList
aCopyListeners( maListeners
);
638 for (const auto& rListener
: aCopyListeners
)
640 rListener
.Call(rEvent
);
644 IMPL_LINK_NOARG(EventMultiplexer::Implementation
, SlideSorterSelectionChangeListener
, LinkParamNone
*, void)
646 CallListeners(EventMultiplexerEventId::SlideSortedSelection
);
649 //===== EventMultiplexerEvent =================================================
651 EventMultiplexerEvent::EventMultiplexerEvent (
652 EventMultiplexerEventId eEventId
,
653 const void* pUserData
)
654 : meEventId(eEventId
),
655 mpUserData(pUserData
)
659 } // end of namespace ::sd::tools
661 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */