LibreOffice Module sd (master) 1
EventMultiplexer.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <EventMultiplexer.hxx>
21
22#include <ViewShellBase.hxx>
23#include <drawdoc.hxx>
24#include <DrawController.hxx>
27#include <sal/log.hxx>
28#include <tools/debug.hxx>
29
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>
36#include <sfx2/viewfrm.hxx>
37
38using namespace ::com::sun::star;
39using namespace ::com::sun::star::lang;
40using namespace ::com::sun::star::uno;
42
43using ::sd::framework::FrameworkHelper;
44
45class SdDrawDocument;
46
47namespace {
48const sal_Int32 ResourceActivationEvent = 0;
49const sal_Int32 ResourceDeactivationEvent = 1;
50const sal_Int32 ConfigurationUpdateEvent = 2;
51}
52
53namespace sd::tools {
54
56 css::beans::XPropertyChangeListener,
57 css::frame::XFrameActionListener,
58 css::view::XSelectionChangeListener,
59 css::drawing::framework::XConfigurationChangeListener
61
64 public SfxListener
65{
66public:
67 explicit Implementation (ViewShellBase& rBase);
68 virtual ~Implementation() override;
69
70 void AddEventListener (
71 const Link<EventMultiplexerEvent&,void>& rCallback);
72
74 const Link<EventMultiplexerEvent&,void>& rCallback);
75
77
78 //===== lang::XEventListener ==============================================
79 virtual void SAL_CALL
80 disposing (const css::lang::EventObject& rEventObject) override;
81
82 //===== beans::XPropertySetListener =======================================
83 virtual void SAL_CALL
85 const css::beans::PropertyChangeEvent& rEvent) override;
86
87 //===== view::XSelectionChangeListener ====================================
88 virtual void SAL_CALL
90 const css::lang::EventObject& rEvent) override;
91
92 //===== frame::XFrameActionListener ======================================
97 virtual void SAL_CALL
98 frameAction (const css::frame::FrameActionEvent& rEvent) override;
99
100 //===== drawing::framework::XConfigurationChangeListener ==================
101 virtual void SAL_CALL
103 const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
104
105 virtual void disposing(std::unique_lock<std::mutex>&) override;
106
107protected:
108 virtual void Notify (
109 SfxBroadcaster& rBroadcaster,
110 const SfxHint& rHint) override;
111
112private:
114 typedef ::std::vector<Link<EventMultiplexerEvent&,void>> ListenerList;
116
121
122 css::uno::WeakReference<css::frame::XController> mxControllerWeak;
123 css::uno::WeakReference<css::frame::XFrame> mxFrameWeak;
125 css::uno::WeakReference<css::drawing::framework::XConfigurationController>
127
128 void ReleaseListeners();
129
130 void ConnectToController();
132
133 void CallListeners (
135 void const * pUserData = nullptr);
136
137 DECL_LINK(SlideSorterSelectionChangeListener, LinkParamNone*, void);
138};
139
140constexpr OUStringLiteral aCurrentPagePropertyName = u"CurrentPage";
141constexpr OUStringLiteral aEditModePropertyName = u"IsMasterPageMode";
142
143//===== EventMultiplexer ======================================================
144
146 : mpImpl (new EventMultiplexer::Implementation(rBase))
147{
148}
149
151{
152 try
153 {
154 mpImpl->dispose();
155 }
156 catch (const RuntimeException&)
157 {
158 }
159 catch (const Exception&)
160 {
161 }
162}
163
165 const Link<EventMultiplexerEvent&,void>& rCallback)
166{
167 mpImpl->AddEventListener(rCallback);
168}
169
171 const Link<EventMultiplexerEvent&,void>& rCallback)
172{
173 mpImpl->RemoveEventListener(rCallback);
174}
175
178 void const * pUserData )
179{
180 EventMultiplexerEvent aEvent(eEventId, pUserData);
181 mpImpl->CallListeners(aEvent);
182}
183
184//===== EventMultiplexer::Implementation ======================================
185
187 : mrBase (rBase),
188 mbListeningToController (false),
189 mbListeningToFrame (false),
190 mxControllerWeak(nullptr),
191 mxFrameWeak(nullptr),
192 mpDocument(nullptr)
193{
194 // Connect to the frame to listen for controllers being exchanged.
195 // Listen to changes of certain properties.
196 Reference<frame::XFrame> xFrame =
199 if (xFrame.is())
200 {
201 xFrame->addFrameActionListener ( Reference<frame::XFrameActionListener>(this) );
202 mbListeningToFrame = true;
203 }
204
205 // Connect to the current controller.
207
208 // Listen for document changes.
210 if (mpDocument != nullptr)
212
213 // Listen for configuration changes.
214 DrawController& rDrawController = *mrBase.GetDrawController();
215
216 Reference<XConfigurationController> xConfigurationController (
217 rDrawController.getConfigurationController());
218 mxConfigurationControllerWeak = xConfigurationController;
219 if (!xConfigurationController.is())
220 return;
221
222 Reference<XComponent> xComponent (xConfigurationController, UNO_QUERY);
223 if (xComponent.is())
224 xComponent->addEventListener(static_cast<beans::XPropertyChangeListener*>(this));
225
226 xConfigurationController->addConfigurationChangeListener(
227 this,
228 FrameworkHelper::msResourceActivationEvent,
229 Any(ResourceActivationEvent));
230 xConfigurationController->addConfigurationChangeListener(
231 this,
232 FrameworkHelper::msResourceDeactivationEvent,
233 Any(ResourceDeactivationEvent));
234 xConfigurationController->addConfigurationChangeListener(
235 this,
236 FrameworkHelper::msConfigurationUpdateEndEvent,
237 Any(ConfigurationUpdateEvent));
238}
239
241{
242 DBG_ASSERT( !mbListeningToFrame,
243 "sd::EventMultiplexer::Implementation::~Implementation(), disposing was not called!" );
244}
245
247{
248 if (mbListeningToFrame)
249 {
250 mbListeningToFrame = false;
251
252 // Stop listening for changes of certain properties.
253 Reference<frame::XFrame> xFrame (mxFrameWeak);
254 if (xFrame.is())
255 {
256 xFrame->removeFrameActionListener (
257 Reference<frame::XFrameActionListener>(this) );
258 }
259 }
260
261 DisconnectFromController ();
262
263 if (mpDocument != nullptr)
264 {
265 EndListening (*mpDocument);
266 mpDocument = nullptr;
267 }
268
269 // Stop listening for configuration changes.
270 Reference<XConfigurationController> xConfigurationController (mxConfigurationControllerWeak);
271 if (xConfigurationController.is())
272 {
273 Reference<XComponent> xComponent (xConfigurationController, UNO_QUERY);
274 if (xComponent.is())
275 xComponent->removeEventListener(static_cast<beans::XPropertyChangeListener*>(this));
276
277 xConfigurationController->removeConfigurationChangeListener(this);
278 }
279}
280
282 const Link<EventMultiplexerEvent&,void>& rCallback)
283{
284 for (auto const & i : maListeners)
285 if (i == rCallback)
286 return;
287 maListeners.push_back(rCallback);
288}
289
291 const Link<EventMultiplexerEvent&,void>& rCallback)
292{
293 auto iListener = std::find(maListeners.begin(), maListeners.end(), rCallback);
294 if (iListener != maListeners.end())
295 maListeners.erase(iListener);
296}
297
299{
300 // Just in case that we missed some event we now disconnect from the old
301 // controller.
302 DisconnectFromController ();
303
304 // Register at the controller of the main view shell.
305
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();
311
312 try
313 {
314 // Listen for disposing events.
315 if (xController.is())
316 {
317 xController->addEventListener (
318 Reference<lang::XEventListener>(
319 static_cast<XWeak*>(this), UNO_QUERY));
320 mbListeningToController = true;
321 }
322
323 // Listen to changes of certain properties.
324 Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
325 if (xSet.is())
326 {
327 try
328 {
329 xSet->addPropertyChangeListener(aCurrentPagePropertyName, this);
330 }
331 catch (const beans::UnknownPropertyException&)
332 {
333 SAL_WARN("sd", "EventMultiplexer::ConnectToController: CurrentPage unknown");
334 }
335
336 try
337 {
338 xSet->addPropertyChangeListener(aEditModePropertyName, this);
339 }
340 catch (const beans::UnknownPropertyException&)
341 {
342 SAL_WARN("sd", "EventMultiplexer::ConnectToController: IsMasterPageMode unknown");
343 }
344 }
345
346 // Listen for selection change events.
347 Reference<view::XSelectionSupplier> xSelection (xController, UNO_QUERY);
348 if (xSelection.is())
349 {
350 xSelection->addSelectionChangeListener(this);
351 }
352 }
353 catch (const lang::DisposedException&)
354 {
355 mbListeningToController = false;
356 }
357}
358
360{
361 if (!mbListeningToController)
362 return;
363
364 mbListeningToController = false;
365
366 Reference<frame::XController> xController = mxControllerWeak;
367
368 Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
369 // Remove the property listener.
370 if (xSet.is())
371 {
372 try
373 {
374 xSet->removePropertyChangeListener(aCurrentPagePropertyName, this);
375 }
376 catch (const beans::UnknownPropertyException&)
377 {
378 SAL_WARN("sd", "DisconnectFromController: CurrentPage unknown");
379 }
380
381 try
382 {
383 xSet->removePropertyChangeListener(aEditModePropertyName, this);
384 }
385 catch (const beans::UnknownPropertyException&)
386 {
387 SAL_WARN("sd", "DisconnectFromController: IsMasterPageMode unknown");
388 }
389 }
390
391 // Remove selection change listener.
392 Reference<view::XSelectionSupplier> xSelection (xController, UNO_QUERY);
393 if (xSelection.is())
394 {
395 xSelection->removeSelectionChangeListener(this);
396 }
397
398 // Remove listener for disposing events.
399 if (xController.is())
400 {
401 xController->removeEventListener (
402 Reference<lang::XEventListener>(static_cast<XWeak*>(this), UNO_QUERY));
403 }
404}
405
406//===== lang::XEventListener ================================================
407
409 const lang::EventObject& rEventObject)
410{
411 if (mbListeningToController)
412 {
413 Reference<frame::XController> xController (mxControllerWeak);
414 if (rEventObject.Source == xController)
415 {
416 mbListeningToController = false;
417 }
418 }
419
420 Reference<XConfigurationController> xConfigurationController (
421 mxConfigurationControllerWeak);
422 if (xConfigurationController.is()
423 && rEventObject.Source == xConfigurationController)
424 {
425 mxConfigurationControllerWeak.clear();
426 }
427}
428
429//===== beans::XPropertySetListener =========================================
430
432 const beans::PropertyChangeEvent& rEvent)
433{
434 if (m_bDisposed)
435 {
436 throw lang::DisposedException (
437 "SlideSorterController object has already been disposed",
438 static_cast<uno::XWeak*>(this));
439 }
440
441 if ( rEvent.PropertyName == aCurrentPagePropertyName )
442 {
444 }
445 else if ( rEvent.PropertyName == aEditModePropertyName )
446 {
447 bool bIsMasterPageMode (false);
448 rEvent.NewValue >>= bIsMasterPageMode;
449 if (bIsMasterPageMode)
451 else
453 }
454}
455
456//===== frame::XFrameActionListener ==========================================
457
459 const frame::FrameActionEvent& rEvent)
460{
461 Reference<frame::XFrame> xFrame (mxFrameWeak);
462 if (rEvent.Frame != xFrame)
463 return;
464
465 switch (rEvent.Action)
466 {
467 case frame::FrameAction_COMPONENT_DETACHING:
468 DisconnectFromController();
470 break;
471
472 case frame::FrameAction_COMPONENT_REATTACHED:
474 DisconnectFromController();
475 ConnectToController();
477 break;
478
479 case frame::FrameAction_COMPONENT_ATTACHED:
480 ConnectToController();
482 break;
483
484 default:
485 break;
486 }
487}
488
489//===== view::XSelectionChangeListener ========================================
490
492 const lang::EventObject& )
493{
495}
496
497//===== drawing::framework::XConfigurationChangeListener ==================
498
500 const ConfigurationChangeEvent& rEvent)
501{
502 sal_Int32 nEventType = 0;
503 rEvent.UserData >>= nEventType;
504 switch (nEventType)
505 {
506 case ResourceActivationEvent:
507 if (rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix))
508 {
510
511 if (rEvent.ResourceId->isBoundToURL(
512 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
513 {
515 }
516
517 // Add selection change listener at slide sorter.
518 if (rEvent.ResourceId->getResourceURL() == FrameworkHelper::msSlideSorterURL)
519 {
521 = dynamic_cast<slidesorter::SlideSorterViewShell*>(
522 FrameworkHelper::GetViewShell(
523 Reference<XView>(rEvent.ResourceObject,UNO_QUERY)).get());
524 if (pViewShell != nullptr)
525 pViewShell->AddSelectionChangeListener (
526 LINK(this,
528 SlideSorterSelectionChangeListener));
529 }
530 }
531 break;
532
533 case ResourceDeactivationEvent:
534 if (rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix))
535 {
536 if (rEvent.ResourceId->isBoundToURL(
537 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
538 {
540 }
541
542 // Remove selection change listener from slide sorter. Add
543 // selection change listener at slide sorter.
544 if (rEvent.ResourceId->getResourceURL() == FrameworkHelper::msSlideSorterURL)
545 {
547 = dynamic_cast<slidesorter::SlideSorterViewShell*>(
548 FrameworkHelper::GetViewShell(
549 Reference<XView>(rEvent.ResourceObject, UNO_QUERY)).get());
550 if (pViewShell != nullptr)
552 LINK(this,
554 SlideSorterSelectionChangeListener));
555 }
556 }
557 break;
558
559 case ConfigurationUpdateEvent:
561 break;
562 }
563
564}
565
566void EventMultiplexer::Implementation::disposing(std::unique_lock<std::mutex>& rGuard)
567{
568 ListenerList aCopyListeners( maListeners );
569
570 rGuard.unlock();
571
573 for (const auto& rListener : aCopyListeners)
574 rListener.Call(rEvent);
575
576 rGuard.lock();
577
578 ReleaseListeners();
579}
580
583 const SfxHint& rHint)
584{
585 if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
586 {
587 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
588 switch (pSdrHint->GetKind())
589 {
590 case SdrHintKind::ModelCleared:
591 case SdrHintKind::PageOrderChange:
593 break;
594
595 case SdrHintKind::SwitchToPage:
597 break;
598
599 case SdrHintKind::ObjectChange:
601 static_cast<const void*>(pSdrHint->GetPage()));
602 break;
603
604 case SdrHintKind::ObjectInserted:
606 static_cast<const void*>(pSdrHint->GetPage()));
607 break;
608
609 case SdrHintKind::ObjectRemoved:
611 static_cast<const void*>(pSdrHint->GetPage()));
612 break;
613 default:
614 break;
615 }
616 }
617 else
618 {
619 if (rHint.GetId() == SfxHintId::Dying)
620 mpDocument = nullptr;
621 }
622}
623
626 void const * pUserData)
627{
628 EventMultiplexerEvent aEvent(eId, pUserData);
629 CallListeners(aEvent);
630}
631
633{
634 ListenerList aCopyListeners( maListeners );
635 for (const auto& rListener : aCopyListeners)
636 {
637 rListener.Call(rEvent);
638 }
639}
640
641IMPL_LINK_NOARG(EventMultiplexer::Implementation, SlideSorterSelectionChangeListener, LinkParamNone*, void)
642{
644}
645
646//===== EventMultiplexerEvent =================================================
647
650 const void* pUserData)
651 : meEventId(eEventId),
652 mpUserData(pUserData)
653{
654}
655
656} // end of namespace ::sd::tools
657
658/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
EventMultiplexerEventId
@ EditViewSelection
The selection in the center pane has changed.
@ ControllerDetached
A UNO controller has been detached to the UNO frame.
@ ShapeRemoved
A shape has been removed from a page.
@ PageOrder
One or more pages have been inserted into or deleted from the model.
@ EditModeNormal
Edit mode was (or is being) switched to normal mode.
@ SlideSortedSelection
The selection in the slide sorter has changed, regardless of whether the slide sorter is displayed in...
@ EditModeMaster
Edit mode was (or is being) switched to master mode.
@ ViewAdded
A new ViewShell is being displayed in one of the panes.
@ Disposing
The EventMultiplexer itself is being disposed.
@ MainViewRemoved
The current MainViewShell (the ViewShell displayed in the center pane) has been removed.
@ ShapeChanged
The state of a shape has changed.
@ MainViewAdded
A new ViewShell has been made the MainViewShell.
@ ConfigurationUpdated
A configuration update has been completed.
@ CurrentPageChanged
The current page has changed.
@ ShapeInserted
A shape has been inserted to a page.
@ ControllerAttached
A UNO controller has been attached to the UNO frame.
AnyEventRef aEvent
const SdrPage * GetPage() const
SdrHintKind GetKind() const
const css::uno::Reference< css::frame::XFrame > & GetFrameInterface() const
SfxHintId GetId() const
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
SfxViewFrame * GetFrame() const
SfxFrame & GetFrame() const
The DrawController is the UNO controller for Impress and Draw.
virtual css::uno::Reference< css::drawing::framework::XConfigurationController > SAL_CALL getConfigurationController() override
SfxViewShell descendant that the stacked Draw/Impress shells are based on.
DrawController * GetDrawController() const
SdDrawDocument * GetDocument() const
void AddSelectionChangeListener(const Link< LinkParamNone *, void > &rListener)
Add a listener that is called when the selection of the slide sorter changes.
void RemoveSelectionChangeListener(const Link< LinkParamNone *, void > &rListener)
Remove a listener that was called when the selection of the slide sorter changes.
EventMultiplexerEvent(EventMultiplexerEventId eEventId, const void *pUserData)
void AddEventListener(const Link< EventMultiplexerEvent &, void > &rCallback)
css::uno::WeakReference< css::frame::XController > mxControllerWeak
void RemoveEventListener(const Link< EventMultiplexerEvent &, void > &rCallback)
virtual void SAL_CALL notifyConfigurationChange(const css::drawing::framework::ConfigurationChangeEvent &rEvent) override
virtual void SAL_CALL selectionChanged(const css::lang::EventObject &rEvent) override
void CallListeners(EventMultiplexerEvent &rEvent)
virtual void Notify(SfxBroadcaster &rBroadcaster, const SfxHint &rHint) override
bool mbListeningToFrame
Remember whether we are listening to the frame.
DECL_LINK(SlideSorterSelectionChangeListener, LinkParamNone *, void)
virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent &rEvent) override
For certain actions the listener connects to a new controller of the frame it is listening to.
virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent &rEvent) override
css::uno::WeakReference< css::frame::XFrame > mxFrameWeak
bool mbListeningToController
Remember whether we are listening to the UNO controller.
css::uno::WeakReference< css::drawing::framework::XConfigurationController > mxConfigurationControllerWeak
::std::vector< Link< EventMultiplexerEvent &, void > > ListenerList
virtual void SAL_CALL disposing(const css::lang::EventObject &rEventObject) override
This convenience class makes it easy to listen to various events that originally are broadcasted via ...
void MultiplexEvent(EventMultiplexerEventId eEventId, void const *pUserData)
This method is used for out-of-line events.
rtl::Reference< Implementation > mpImpl
void RemoveEventListener(const Link< EventMultiplexerEvent &, void > &rCallback)
Remove an event listener for the specified event types.
EventMultiplexer(ViewShellBase &rBase)
Create new EventMultiplexer for the given ViewShellBase object.
void AddEventListener(const Link< EventMultiplexerEvent &, void > &rCallback)
Add an event listener that will be informed about the specified event types.
#define DBG_ASSERT(sCon, aError)
float u
bool m_bDisposed
#define SAL_WARN(area, stream)
@ Exception
int i
comphelper::WeakComponentImplHelper< css::beans::XPropertyChangeListener, css::frame::XFrameActionListener, css::view::XSelectionChangeListener, css::drawing::framework::XConfigurationChangeListener > EventMultiplexerImplementationInterfaceBase
IMPL_LINK_NOARG(EventMultiplexer::Implementation, SlideSorterSelectionChangeListener, LinkParamNone *, void)
constexpr OUStringLiteral aCurrentPagePropertyName
constexpr OUStringLiteral aEditModePropertyName
Reference< XController > xController
Reference< XFrame > xFrame