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/weak.hxx>
37 #include <cppuhelper/compbase.hxx>
38 #include <sfx2/viewfrm.hxx>
40 using namespace ::com::sun::star
;
41 using namespace ::com::sun::star::lang
;
42 using namespace ::com::sun::star::uno
;
43 using namespace ::com::sun::star::drawing::framework
;
45 using ::sd::framework::FrameworkHelper
;
50 static const sal_Int32 ResourceActivationEvent
= 0;
51 static const sal_Int32 ResourceDeactivationEvent
= 1;
52 static const sal_Int32 ConfigurationUpdateEvent
= 2;
55 namespace sd
{ namespace tools
{
57 typedef cppu::WeakComponentImplHelper
<
58 css::beans::XPropertyChangeListener
,
59 css::frame::XFrameActionListener
,
60 css::view::XSelectionChangeListener
,
61 css::drawing::framework::XConfigurationChangeListener
62 > EventMultiplexerImplementationInterfaceBase
;
64 class EventMultiplexer::Implementation
65 : protected MutexOwner
,
66 public EventMultiplexerImplementationInterfaceBase
,
70 explicit Implementation (ViewShellBase
& rBase
);
71 virtual ~Implementation() override
;
73 void AddEventListener (
74 const Link
<EventMultiplexerEvent
&,void>& rCallback
);
76 void RemoveEventListener (
77 const Link
<EventMultiplexerEvent
&,void>& rCallback
);
79 void CallListeners (EventMultiplexerEvent
& rEvent
);
81 //===== lang::XEventListener ==============================================
83 disposing (const css::lang::EventObject
& rEventObject
) override
;
85 //===== beans::XPropertySetListener =======================================
88 const css::beans::PropertyChangeEvent
& rEvent
) override
;
90 //===== view::XSelectionChangeListener ====================================
93 const css::lang::EventObject
& rEvent
) override
;
95 //===== frame::XFrameActionListener ======================================
96 /** For certain actions the listener connects to a new controller of the
97 frame it is listening to. This usually happens when the view shell
98 in the center pane is replaced by another view shell.
100 virtual void SAL_CALL
101 frameAction (const css::frame::FrameActionEvent
& rEvent
) override
;
103 //===== drawing::framework::XConfigurationChangeListener ==================
104 virtual void SAL_CALL
105 notifyConfigurationChange (
106 const css::drawing::framework::ConfigurationChangeEvent
& rEvent
) override
;
108 virtual void SAL_CALL
disposing() override
;
111 virtual void Notify (
112 SfxBroadcaster
& rBroadcaster
,
113 const SfxHint
& rHint
) override
;
116 ViewShellBase
& mrBase
;
117 typedef ::std::vector
<Link
<EventMultiplexerEvent
&,void>> ListenerList
;
118 ListenerList maListeners
;
120 /// Remember whether we are listening to the UNO controller.
121 bool mbListeningToController
;
122 /// Remember whether we are listening to the frame.
123 bool mbListeningToFrame
;
125 css::uno::WeakReference
<css::frame::XController
> mxControllerWeak
;
126 css::uno::WeakReference
<css::frame::XFrame
> mxFrameWeak
;
127 SdDrawDocument
* mpDocument
;
128 css::uno::WeakReference
<css::drawing::framework::XConfigurationController
>
129 mxConfigurationControllerWeak
;
131 void ReleaseListeners();
133 void ConnectToController();
134 void DisconnectFromController();
137 EventMultiplexerEventId eId
,
138 void const * pUserData
= nullptr);
140 DECL_LINK(SlideSorterSelectionChangeListener
, LinkParamNone
*, void);
143 const char aCurrentPagePropertyName
[] = "CurrentPage";
144 const char aEditModePropertyName
[] = "IsMasterPageMode";
146 //===== EventMultiplexer ======================================================
148 EventMultiplexer::EventMultiplexer (ViewShellBase
& rBase
)
149 : mpImpl (new EventMultiplexer::Implementation(rBase
))
153 EventMultiplexer::~EventMultiplexer()
159 catch (const RuntimeException
&)
162 catch (const Exception
&)
167 void EventMultiplexer::AddEventListener (
168 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
170 mpImpl
->AddEventListener(rCallback
);
173 void EventMultiplexer::RemoveEventListener (
174 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
176 mpImpl
->RemoveEventListener(rCallback
);
179 void EventMultiplexer::MultiplexEvent(
180 EventMultiplexerEventId eEventId
,
181 void const * pUserData
)
183 EventMultiplexerEvent
aEvent(eEventId
, pUserData
);
184 mpImpl
->CallListeners(aEvent
);
187 //===== EventMultiplexer::Implementation ======================================
189 EventMultiplexer::Implementation::Implementation (ViewShellBase
& rBase
)
191 EventMultiplexerImplementationInterfaceBase(maMutex
),
194 mbListeningToController (false),
195 mbListeningToFrame (false),
196 mxControllerWeak(nullptr),
197 mxFrameWeak(nullptr),
199 mxConfigurationControllerWeak()
201 // Connect to the frame to listen for controllers being exchanged.
202 // Listen to changes of certain properties.
203 Reference
<frame::XFrame
> xFrame (
204 mrBase
.GetFrame()->GetFrame().GetFrameInterface(),
206 mxFrameWeak
= xFrame
;
209 xFrame
->addFrameActionListener (
210 Reference
<frame::XFrameActionListener
>(
211 static_cast<XWeak
*>(this), UNO_QUERY
));
212 mbListeningToFrame
= true;
215 // Connect to the current controller.
216 ConnectToController ();
218 // Listen for document changes.
219 mpDocument
= mrBase
.GetDocument();
220 if (mpDocument
!= nullptr)
221 StartListening (*mpDocument
);
223 // Listen for configuration changes.
224 Reference
<XControllerManager
> xControllerManager (
225 Reference
<XWeak
>(&mrBase
.GetDrawController()), UNO_QUERY
);
226 if (!xControllerManager
.is())
229 Reference
<XConfigurationController
> xConfigurationController (
230 xControllerManager
->getConfigurationController());
231 mxConfigurationControllerWeak
= xConfigurationController
;
232 if (!xConfigurationController
.is())
235 Reference
<XComponent
> xComponent (xConfigurationController
, UNO_QUERY
);
237 xComponent
->addEventListener(static_cast<beans::XPropertyChangeListener
*>(this));
239 xConfigurationController
->addConfigurationChangeListener(
241 FrameworkHelper::msResourceActivationEvent
,
242 makeAny(ResourceActivationEvent
));
243 xConfigurationController
->addConfigurationChangeListener(
245 FrameworkHelper::msResourceDeactivationEvent
,
246 makeAny(ResourceDeactivationEvent
));
247 xConfigurationController
->addConfigurationChangeListener(
249 FrameworkHelper::msConfigurationUpdateEndEvent
,
250 makeAny(ConfigurationUpdateEvent
));
253 EventMultiplexer::Implementation::~Implementation()
255 DBG_ASSERT( !mbListeningToFrame
,
256 "sd::EventMultiplexer::Implementation::~Implementation(), disposing was not called!" );
259 void EventMultiplexer::Implementation::ReleaseListeners()
261 if (mbListeningToFrame
)
263 mbListeningToFrame
= false;
265 // Stop listening for changes of certain properties.
266 Reference
<frame::XFrame
> xFrame (mxFrameWeak
);
269 xFrame
->removeFrameActionListener (
270 Reference
<frame::XFrameActionListener
>(
271 static_cast<XWeak
*>(this), UNO_QUERY
));
275 DisconnectFromController ();
277 if (mpDocument
!= nullptr)
279 EndListening (*mpDocument
);
280 mpDocument
= nullptr;
283 // Stop listening for configuration changes.
284 Reference
<XConfigurationController
> xConfigurationController (mxConfigurationControllerWeak
);
285 if (xConfigurationController
.is())
287 Reference
<XComponent
> xComponent (xConfigurationController
, UNO_QUERY
);
289 xComponent
->removeEventListener(static_cast<beans::XPropertyChangeListener
*>(this));
291 xConfigurationController
->removeConfigurationChangeListener(this);
295 void EventMultiplexer::Implementation::AddEventListener (
296 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
298 for (auto const & i
: maListeners
)
301 maListeners
.push_back(rCallback
);
304 void EventMultiplexer::Implementation::RemoveEventListener (
305 const Link
<EventMultiplexerEvent
&,void>& rCallback
)
307 auto iListener
= std::find(maListeners
.begin(), maListeners
.end(), rCallback
);
308 if (iListener
!= maListeners
.end())
309 maListeners
.erase(iListener
);
312 void EventMultiplexer::Implementation::ConnectToController()
314 // Just in case that we missed some event we now disconnect from the old
316 DisconnectFromController ();
318 // Register at the controller of the main view shell.
320 // We have to store a (weak) reference to the controller so that we can
321 // unregister without having to ask the mrBase member (which at that
322 // time may be destroyed.)
323 Reference
<frame::XController
> xController
= mrBase
.GetController();
324 mxControllerWeak
= mrBase
.GetController();
328 // Listen for disposing events.
329 Reference
<lang::XComponent
> xComponent (xController
, UNO_QUERY
);
332 xComponent
->addEventListener (
333 Reference
<lang::XEventListener
>(
334 static_cast<XWeak
*>(this), UNO_QUERY
));
335 mbListeningToController
= true;
338 // Listen to changes of certain properties.
339 Reference
<beans::XPropertySet
> xSet (xController
, UNO_QUERY
);
344 xSet
->addPropertyChangeListener(aCurrentPagePropertyName
, this);
346 catch (const beans::UnknownPropertyException
&)
348 SAL_WARN("sd", "EventMultiplexer::ConnectToController: CurrentPage unknown");
353 xSet
->addPropertyChangeListener(aEditModePropertyName
, this);
355 catch (const beans::UnknownPropertyException
&)
357 SAL_WARN("sd", "EventMultiplexer::ConnectToController: IsMasterPageMode unknown");
361 // Listen for selection change events.
362 Reference
<view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
365 xSelection
->addSelectionChangeListener(this);
368 catch (const lang::DisposedException
&)
370 mbListeningToController
= false;
374 void EventMultiplexer::Implementation::DisconnectFromController()
376 if (!mbListeningToController
)
379 mbListeningToController
= false;
381 Reference
<frame::XController
> xController
= mxControllerWeak
;
383 Reference
<beans::XPropertySet
> xSet (xController
, UNO_QUERY
);
384 // Remove the property listener.
389 xSet
->removePropertyChangeListener(aCurrentPagePropertyName
, this);
391 catch (const beans::UnknownPropertyException
&)
393 SAL_WARN("sd", "DisconnectFromController: CurrentPage unknown");
398 xSet
->removePropertyChangeListener(aEditModePropertyName
, this);
400 catch (const beans::UnknownPropertyException
&)
402 SAL_WARN("sd", "DisconnectFromController: IsMasterPageMode unknown");
406 // Remove selection change listener.
407 Reference
<view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
410 xSelection
->removeSelectionChangeListener(this);
413 // Remove listener for disposing events.
414 Reference
<lang::XComponent
> xComponent (xController
, UNO_QUERY
);
417 xComponent
->removeEventListener (
418 Reference
<lang::XEventListener
>(static_cast<XWeak
*>(this), UNO_QUERY
));
422 //===== lang::XEventListener ================================================
424 void SAL_CALL
EventMultiplexer::Implementation::disposing (
425 const lang::EventObject
& rEventObject
)
427 if (mbListeningToController
)
429 Reference
<frame::XController
> xController (mxControllerWeak
);
430 if (rEventObject
.Source
== xController
)
432 mbListeningToController
= false;
436 Reference
<XConfigurationController
> xConfigurationController (
437 mxConfigurationControllerWeak
);
438 if (xConfigurationController
.is()
439 && rEventObject
.Source
== xConfigurationController
)
441 mxConfigurationControllerWeak
.clear();
445 //===== beans::XPropertySetListener =========================================
447 void SAL_CALL
EventMultiplexer::Implementation::propertyChange (
448 const beans::PropertyChangeEvent
& rEvent
)
450 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
452 throw lang::DisposedException (
453 "SlideSorterController object has already been disposed",
454 static_cast<uno::XWeak
*>(this));
457 if ( rEvent
.PropertyName
== aCurrentPagePropertyName
)
459 CallListeners(EventMultiplexerEventId::CurrentPageChanged
);
461 else if ( rEvent
.PropertyName
== aEditModePropertyName
)
463 bool bIsMasterPageMode (false);
464 rEvent
.NewValue
>>= bIsMasterPageMode
;
465 if (bIsMasterPageMode
)
466 CallListeners(EventMultiplexerEventId::EditModeMaster
);
468 CallListeners(EventMultiplexerEventId::EditModeNormal
);
472 //===== frame::XFrameActionListener ==========================================
474 void SAL_CALL
EventMultiplexer::Implementation::frameAction (
475 const frame::FrameActionEvent
& rEvent
)
477 Reference
<frame::XFrame
> xFrame (mxFrameWeak
);
478 if (rEvent
.Frame
!= xFrame
)
481 switch (rEvent
.Action
)
483 case frame::FrameAction_COMPONENT_DETACHING
:
484 DisconnectFromController();
485 CallListeners (EventMultiplexerEventId::ControllerDetached
);
488 case frame::FrameAction_COMPONENT_REATTACHED
:
489 CallListeners (EventMultiplexerEventId::ControllerDetached
);
490 DisconnectFromController();
491 ConnectToController();
492 CallListeners (EventMultiplexerEventId::ControllerAttached
);
495 case frame::FrameAction_COMPONENT_ATTACHED
:
496 ConnectToController();
497 CallListeners (EventMultiplexerEventId::ControllerAttached
);
505 //===== view::XSelectionChangeListener ========================================
507 void SAL_CALL
EventMultiplexer::Implementation::selectionChanged (
508 const lang::EventObject
& )
510 CallListeners (EventMultiplexerEventId::EditViewSelection
);
513 //===== drawing::framework::XConfigurationChangeListener ==================
515 void SAL_CALL
EventMultiplexer::Implementation::notifyConfigurationChange (
516 const ConfigurationChangeEvent
& rEvent
)
518 sal_Int32 nEventType
= 0;
519 rEvent
.UserData
>>= nEventType
;
522 case ResourceActivationEvent
:
523 if (rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
))
525 CallListeners (EventMultiplexerEventId::ViewAdded
);
527 if (rEvent
.ResourceId
->isBoundToURL(
528 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
530 CallListeners (EventMultiplexerEventId::MainViewAdded
);
533 // Add selection change listener at slide sorter.
534 if (rEvent
.ResourceId
->getResourceURL() == FrameworkHelper::msSlideSorterURL
)
536 slidesorter::SlideSorterViewShell
* pViewShell
537 = dynamic_cast<slidesorter::SlideSorterViewShell
*>(
538 FrameworkHelper::GetViewShell(
539 Reference
<XView
>(rEvent
.ResourceObject
,UNO_QUERY
)).get());
540 if (pViewShell
!= nullptr)
541 pViewShell
->AddSelectionChangeListener (
543 EventMultiplexer::Implementation
,
544 SlideSorterSelectionChangeListener
));
549 case ResourceDeactivationEvent
:
550 if (rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
))
552 if (rEvent
.ResourceId
->isBoundToURL(
553 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
555 CallListeners (EventMultiplexerEventId::MainViewRemoved
);
558 // Remove selection change listener from slide sorter. Add
559 // selection change listener at slide sorter.
560 if (rEvent
.ResourceId
->getResourceURL() == FrameworkHelper::msSlideSorterURL
)
562 slidesorter::SlideSorterViewShell
* pViewShell
563 = dynamic_cast<slidesorter::SlideSorterViewShell
*>(
564 FrameworkHelper::GetViewShell(
565 Reference
<XView
>(rEvent
.ResourceObject
, UNO_QUERY
)).get());
566 if (pViewShell
!= nullptr)
567 pViewShell
->RemoveSelectionChangeListener (
569 EventMultiplexer::Implementation
,
570 SlideSorterSelectionChangeListener
));
575 case ConfigurationUpdateEvent
:
576 CallListeners (EventMultiplexerEventId::ConfigurationUpdated
);
582 void SAL_CALL
EventMultiplexer::Implementation::disposing()
584 CallListeners (EventMultiplexerEventId::Disposing
);
588 void EventMultiplexer::Implementation::Notify (
590 const SfxHint
& rHint
)
592 if (rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
)
594 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
595 switch (pSdrHint
->GetKind())
597 case SdrHintKind::ModelCleared
:
598 case SdrHintKind::PageOrderChange
:
599 CallListeners (EventMultiplexerEventId::PageOrder
);
602 case SdrHintKind::SwitchToPage
:
603 CallListeners (EventMultiplexerEventId::CurrentPageChanged
);
606 case SdrHintKind::ObjectChange
:
607 CallListeners(EventMultiplexerEventId::ShapeChanged
,
608 static_cast<const void*>(pSdrHint
->GetPage()));
611 case SdrHintKind::ObjectInserted
:
612 CallListeners(EventMultiplexerEventId::ShapeInserted
,
613 static_cast<const void*>(pSdrHint
->GetPage()));
616 case SdrHintKind::ObjectRemoved
:
617 CallListeners(EventMultiplexerEventId::ShapeRemoved
,
618 static_cast<const void*>(pSdrHint
->GetPage()));
626 if (rHint
.GetId() == SfxHintId::Dying
)
627 mpDocument
= nullptr;
631 void EventMultiplexer::Implementation::CallListeners (
632 EventMultiplexerEventId eId
,
633 void const * pUserData
)
635 EventMultiplexerEvent
aEvent(eId
, pUserData
);
636 CallListeners(aEvent
);
639 void EventMultiplexer::Implementation::CallListeners (EventMultiplexerEvent
& rEvent
)
641 ListenerList
aCopyListeners( maListeners
);
642 for (auto& rListener
: aCopyListeners
)
644 rListener
.Call(rEvent
);
648 IMPL_LINK_NOARG(EventMultiplexer::Implementation
, SlideSorterSelectionChangeListener
, LinkParamNone
*, void)
650 CallListeners(EventMultiplexerEventId::SlideSortedSelection
);
653 //===== EventMultiplexerEvent =================================================
655 EventMultiplexerEvent::EventMultiplexerEvent (
656 EventMultiplexerEventId eEventId
,
657 const void* pUserData
)
658 : meEventId(eEventId
),
659 mpUserData(pUserData
)
663 } } // end of namespace ::sd::tools
665 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */