LibreOffice Module sd (master) 1
SlsListener.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 "SlsListener.hxx"
21
22#include <SlideSorter.hxx>
23#include <ViewShell.hxx>
24#include <ViewShellHint.hxx>
34#include <drawdoc.hxx>
35#include <sdpage.hxx>
36#include <DrawDocShell.hxx>
37#include <svx/svdpage.hxx>
38
39#include <ViewShellBase.hxx>
40#include <EventMultiplexer.hxx>
41#include <com/sun/star/document/XEventBroadcaster.hpp>
42#include <com/sun/star/beans/XPropertySet.hpp>
43#include <com/sun/star/frame/FrameActionEvent.hpp>
44#include <com/sun/star/frame/FrameAction.hpp>
45#include <tools/debug.hxx>
47
48using namespace ::com::sun::star::accessibility;
49using namespace ::com::sun::star::beans;
50using namespace ::com::sun::star::uno;
51using namespace ::com::sun::star;
52
54
56 SlideSorter& rSlideSorter)
57 : mrSlideSorter(rSlideSorter),
59 mpBase(mrSlideSorter.GetViewShellBase()),
60 mbListeningToDocument (false),
61 mbListeningToUNODocument (false),
62 mbListeningToController (false),
63 mbListeningToFrame (false),
64 mbIsMainViewChangePending(false)
65{
69
70 // Connect to the UNO document.
71 Reference<document::XEventBroadcaster> xBroadcaster (
72 mrSlideSorter.GetModel().GetDocument()->getUnoModel(), uno::UNO_QUERY);
73 if (xBroadcaster.is())
74 {
75 xBroadcaster->addEventListener (this);
77 }
78
79 // Listen for disposing events from the document.
80 Reference<XComponent> xComponent (xBroadcaster, UNO_QUERY);
81 if (xComponent.is())
82 xComponent->addEventListener (
83 Reference<lang::XEventListener>(
84 static_cast<XWeak*>(this), UNO_QUERY));
85
86 // Connect to the frame to listen for controllers being exchanged.
87 bool bIsMainViewShell (false);
88 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
89 if (pViewShell != nullptr)
90 bIsMainViewShell = pViewShell->IsMainViewShell();
91 if ( ! bIsMainViewShell)
92 {
93 // Listen to changes of certain properties.
94 Reference<frame::XFrame> xFrame;
95 Reference<frame::XController> xController (mrSlideSorter.GetXController());
96 if (xController.is())
97 xFrame = xController->getFrame();
99 if (xFrame.is())
100 {
101 xFrame->addFrameActionListener(Reference<frame::XFrameActionListener>(this));
102 mbListeningToFrame = true;
103 }
104
105 // Connect to the current controller.
107 }
108
109 // Listen for hints of the MainViewShell as well. If that is not yet
110 // present then the EventMultiplexer will tell us when it is available.
111 if (mpBase != nullptr)
112 {
113 ViewShell* pMainViewShell = mpBase->GetMainViewShell().get();
114 if (pMainViewShell != nullptr
115 && pMainViewShell!=pViewShell)
116 {
117 StartListening(*pMainViewShell);
118 }
119
120 Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this, Listener, EventMultiplexerCallback));
121 mpBase->GetEventMultiplexer()->AddEventListener(aLink);
122 }
123}
124
126{
128 "sd::Listener::~Listener(), disposing() was not called, ask DBO!" );
129}
130
132{
134 {
137 mbListeningToDocument = false;
138 }
139
141 {
142 Reference<document::XEventBroadcaster> xBroadcaster (
144 if (xBroadcaster.is())
145 xBroadcaster->removeEventListener (this);
146
147 // Remove the dispose listener.
148 Reference<XComponent> xComponent (xBroadcaster, UNO_QUERY);
149 if (xComponent.is())
150 xComponent->removeEventListener (
151 Reference<lang::XEventListener>(
152 static_cast<XWeak*>(this), UNO_QUERY));
153
155 }
156
158 {
159 // Listen to changes of certain properties.
160 Reference<frame::XFrame> xFrame (mxFrameWeak);
161 if (xFrame.is())
162 {
163 xFrame->removeFrameActionListener(Reference<frame::XFrameActionListener>(this));
164 mbListeningToFrame = false;
165 }
166 }
167
169
170 if (mpBase != nullptr)
171 {
172 Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this, Listener, EventMultiplexerCallback));
173 mpBase->GetEventMultiplexer()->RemoveEventListener(aLink);
174 }
175}
176
178{
180
181 // Register at the controller of the main view shell (if we are that not
182 // ourself).
183 if (pShell!=nullptr && pShell->IsMainViewShell())
184 return;
185
186 Reference<frame::XController> xController (mrSlideSorter.GetXController());
187
188 // Listen to changes of certain properties.
189 Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
190 if (xSet.is())
191 {
192 try
193 {
194 xSet->addPropertyChangeListener("CurrentPage", this);
195 }
196 catch (beans::UnknownPropertyException&)
197 {
199 }
200 try
201 {
202 xSet->addPropertyChangeListener("IsMasterPageMode", this);
203 }
204 catch (beans::UnknownPropertyException&)
205 {
207 }
208 }
209
210 // Listen for disposing events.
211 if (xController.is())
212 {
213 xController->addEventListener (
214 Reference<lang::XEventListener>(static_cast<XWeak*>(this), UNO_QUERY));
215
218 }
219}
220
222{
224 return;
225
226 Reference<frame::XController> xController = mxControllerWeak;
227 Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
228 try
229 {
230 // Remove the property listener.
231 if (xSet.is())
232 {
233 xSet->removePropertyChangeListener( "CurrentPage", this );
234 xSet->removePropertyChangeListener( "IsMasterPageMode", this);
235 }
236
237 // Remove the dispose listener.
238 if (xController.is())
239 xController->removeEventListener (
240 Reference<lang::XEventListener>(
241 static_cast<XWeak*>(this), UNO_QUERY));
242 }
243 catch (beans::UnknownPropertyException&)
244 {
246 }
247
249 mxControllerWeak = Reference<frame::XController>();
250}
251
253 SfxBroadcaster& rBroadcaster,
254 const SfxHint& rHint)
255{
256 if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
257 {
258 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
259 switch (pSdrHint->GetKind())
260 {
261 case SdrHintKind::ModelCleared:
262 if (&rBroadcaster == mrSlideSorter.GetModel().GetDocument())
263 { // rhbz#965646 stop listening to dying document
264 EndListening(rBroadcaster);
265 return;
266 }
267 break;
268 case SdrHintKind::PageOrderChange:
269 if (&rBroadcaster == mrSlideSorter.GetModel().GetDocument())
270 HandleModelChange(pSdrHint->GetPage());
271 break;
272
273 default:
274 break;
275 }
276 }
277 else if (rHint.GetId() == SfxHintId::DocChanged)
278 {
281 }
282 else if (auto pViewShellHint = dynamic_cast<const ViewShellHint*>(&rHint))
283 {
284 switch (pViewShellHint->GetHintId())
285 {
287 // Initiate a model change but do nothing (well, not much)
288 // until we are told that all slides have been resized.
292 break;
293
295 // All slides have been resized. The model has to be updated.
296 mpModelChangeLock.reset();
297 break;
298
301 break;
302
305 break;
306
310 break;
311
313 mpModelChangeLock.reset();
314 break;
315 }
316 }
317}
318
319IMPL_LINK(Listener, EventMultiplexerCallback, ::sd::tools::EventMultiplexerEvent&, rEvent, void)
320{
321 switch (rEvent.meEventId)
322 {
324 {
325 if (mpBase != nullptr)
326 {
327 ViewShell* pMainViewShell = mpBase->GetMainViewShell().get();
328 if (pMainViewShell != nullptr)
329 EndListening(*pMainViewShell);
330 }
331 }
332 break;
333
335 mbIsMainViewChangePending = true;
336 break;
337
339 if (mbIsMainViewChangePending && mpBase != nullptr)
340 {
341 mbIsMainViewChangePending = false;
342 ViewShell* pMainViewShell = mpBase->GetMainViewShell().get();
343 if (pMainViewShell != nullptr
344 && pMainViewShell!=mrSlideSorter.GetViewShell())
345 {
346 StartListening (*pMainViewShell);
347 }
348 }
349 break;
350
352 {
353 ConnectToController();
354 // mrController.GetPageSelector().GetCoreSelection();
355 UpdateEditMode();
356 }
357 break;
358
360 DisconnectFromController();
361 break;
362
366 HandleShapeModification(static_cast<const SdrPage*>(rEvent.mpUserData));
367 break;
368
370 if (rEvent.mpUserData != nullptr)
371 {
372 const SdrObject* pObject = static_cast<const SdrObject*>(rEvent.mpUserData);
373 HandleShapeModification(pObject->getSdrPageFromSdrObject());
374 }
375 break;
376
377 default:
378 break;
379 }
380}
381
382//===== lang::XEventListener ================================================
383
384void SAL_CALL Listener::disposing (
385 const lang::EventObject& rEventObject)
386{
388 && mrSlideSorter.GetModel().GetDocument()!=nullptr
389 && rEventObject.Source
391 {
392 mbListeningToDocument = false;
394 }
396 {
397 Reference<frame::XController> xController (mxControllerWeak);
398 if (rEventObject.Source == xController)
399 {
401 }
402 }
403}
404
405//===== document::XEventListener ============================================
406
407void SAL_CALL Listener::notifyEvent (
408 const document::EventObject& )
409{
410}
411
412//===== beans::XPropertySetListener =========================================
413
415 const PropertyChangeEvent& rEvent)
416{
417 if (m_bDisposed)
418 {
419 throw lang::DisposedException ("SlideSorterController object has already been disposed",
420 static_cast<uno::XWeak*>(this));
421 }
422
423 if (rEvent.PropertyName == "CurrentPage")
424 {
425 Any aCurrentPage = rEvent.NewValue;
426 Reference<beans::XPropertySet> xPageSet (aCurrentPage, UNO_QUERY);
427 if (xPageSet.is())
428 {
429 try
430 {
431 Any aPageNumber = xPageSet->getPropertyValue ("Number");
432 sal_Int32 nCurrentPage = 0;
433 aPageNumber >>= nCurrentPage;
434 // The selection is already set but we call SelectPage()
435 // nevertheless in order to make the new current page the
436 // last recently selected page of the PageSelector. This is
437 // used when making the selection visible.
438 mrController.GetCurrentSlideManager()->NotifyCurrentSlideChange(nCurrentPage-1);
439 mrController.GetPageSelector().SelectPage(nCurrentPage-1);
440 }
441 catch (beans::UnknownPropertyException&)
442 {
444 }
445 catch (lang::DisposedException&)
446 {
447 // Something is already disposed. There is not much we can
448 // do, except not to crash.
449 }
450 }
451 }
452 else if (rEvent.PropertyName == "IsMasterPageMode")
453 {
454 bool bIsMasterPageMode = false;
455 rEvent.NewValue >>= bIsMasterPageMode;
457 bIsMasterPageMode ? EditMode::MasterPage : EditMode::Page);
458 }
459}
460
461//===== frame::XFrameActionListener ==========================================
462
463void SAL_CALL Listener::frameAction (const frame::FrameActionEvent& rEvent)
464{
465 switch (rEvent.Action)
466 {
467 case frame::FrameAction_COMPONENT_DETACHING:
469 break;
470
471 case frame::FrameAction_COMPONENT_REATTACHED:
472 {
476 }
477 break;
478
479 default:
480 break;
481 }
482}
483
484//===== accessibility::XAccessibleEventListener ==============================
485
486void SAL_CALL Listener::notifyEvent (
487 const AccessibleEventObject& )
488{
489}
490
491void Listener::disposing(std::unique_lock<std::mutex>&)
492{
494}
495
497{
498 // When there is a new controller then the edit mode may have changed at
499 // the same time.
500 Reference<frame::XController> xController (mxControllerWeak);
501 Reference<beans::XPropertySet> xSet (xController, UNO_QUERY);
502 bool bIsMasterPageMode = false;
503 if (xSet != nullptr)
504 {
505 try
506 {
507 Any aValue (xSet->getPropertyValue( "IsMasterPageMode" ));
508 aValue >>= bIsMasterPageMode;
509 }
510 catch (beans::UnknownPropertyException&)
511 {
512 // When the property is not supported then the master page mode
513 // is not supported, too.
514 bIsMasterPageMode = false;
515 }
516 }
518 bIsMasterPageMode ? EditMode::MasterPage : EditMode::Page);
519}
520
522{
523 // Notify model and selection observer about the page. The return value
524 // of the model call acts as filter as to which events to pass to the
525 // selection observer.
527 {
528 // The page of the hint belongs (or belonged) to the model.
529
530 // Tell the cache manager that the preview bitmaps for a deleted
531 // page can be removed from all caches.
532 if (pPage!=nullptr && ! pPage->IsInserted())
533 cache::PageCacheManager::Instance()->ReleasePreviewBitmap(pPage);
534
535 mrController.GetSelectionManager()->GetSelectionObserver()->NotifyPageEvent(pPage);
536 }
537
538 // Tell the controller about the model change only when the document is
539 // in a sane state, not just in the middle of a larger change.
541 if (pDocument != nullptr
543 {
544 // A model change can make updates of some text fields necessary
545 // (like page numbers and page count.) Invalidate all previews in
546 // the cache to cope with this. Doing this on demand would be a
547 // nice optimization.
548 cache::PageCacheManager::Instance()->InvalidateAllPreviewBitmaps(pDocument->getUnoModel());
549
551 }
552}
553
555{
556 if (pPage == nullptr)
557 return;
558
559 // Invalidate the preview of the page (in all slide sorters that display
560 // it.)
561 std::shared_ptr<cache::PageCacheManager> pCacheManager (cache::PageCacheManager::Instance());
562 if ( ! pCacheManager)
563 return;
565 if (pDocument == nullptr)
566 {
567 OSL_ASSERT(pDocument!=nullptr);
568 return;
569 }
570 pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pPage);
571 mrSlideSorter.GetView().GetPreviewCache()->RequestPreviewBitmap(pPage);
572
573 // When the page is a master page then invalidate the previews of all
574 // pages that are linked to this master page.
575 if (!pPage->IsMasterPage())
576 return;
577
578 for (sal_uInt16 nIndex=0,nCount=pDocument->GetSdPageCount(PageKind::Standard);
580 ++nIndex)
581 {
582 const SdPage* pCandidate = pDocument->GetSdPage(nIndex, PageKind::Standard);
583 if (pCandidate!=nullptr && pCandidate->TRG_HasMasterPage())
584 {
585 if (&pCandidate->TRG_GetMasterPage() == pPage)
586 pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pCandidate);
587 }
588 else
589 {
590 OSL_ASSERT(pCandidate!=nullptr && pCandidate->TRG_HasMasterPage());
591 }
592 }
593}
594
595} // end of namespace ::sd::slidesorter::controller
596
597/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
@ ControllerDetached
A UNO controller has been detached to the UNO frame.
@ ShapeRemoved
A shape has been removed from a page.
@ EndTextEdit
Text editing in one of the shapes in the MainViewShell has ended.
@ 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.
@ ShapeInserted
A shape has been inserted to a page.
@ ControllerAttached
A UNO controller has been attached to the UNO frame.
SlideSorterController & mrController
SlideSorter & mrSlideSorter
sal_uInt16 GetMasterSdPageCount(PageKind ePgKind) const
Definition: drawdoc2.cxx:222
SdPage * GetSdPage(sal_uInt16 nPgNum, PageKind ePgKind) const
Definition: drawdoc2.cxx:207
SAL_DLLPRIVATE::sd::DrawDocShell * GetDocSh() const
Definition: drawdoc.hxx:242
sal_uInt16 GetSdPageCount(PageKind ePgKind) const
Definition: drawdoc2.cxx:212
const SdrPage * GetPage() const
SdrHintKind GetKind() const
css::uno::Reference< css::uno::XInterface > const & getUnoModel()
bool IsInserted() const
SdrPage & TRG_GetMasterPage() const
bool IsMasterPage() const
bool TRG_HasMasterPage() const
SfxHintId GetId() const
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
void EndListening(SfxBroadcaster &rBroadcaster, bool bRemoveAllDuplicates=false)
std::shared_ptr< ViewShell > GetMainViewShell() const
Return the main view shell stacked on the called ViewShellBase object.
std::shared_ptr< tools::EventMultiplexer > const & GetEventMultiplexer() const
Return an event multiplexer.
Local derivation of the SfxHint class that defines some hint ids that are used by the ViewShell class...
Base class of the stacked shell hierarchy.
Definition: ViewShell.hxx:92
bool IsMainViewShell() const
Return <TRUE> when the called view shell is the main sub shell of its ViewShellBase object,...
Definition: viewshel.cxx:1493
Show previews for all the slides in a document and allow the user to insert or delete slides and modi...
Definition: SlideSorter.hxx:62
css::uno::Reference< css::frame::XController > GetXController() const
Return the XController object of the main view.
ViewShell * GetViewShell() const
Return the view shell that was given at construction.
model::SlideSorterModel & GetModel() const
view::SlideSorterView & GetView() const
static std::shared_ptr< PageCacheManager > Instance()
Return the one instance of the PageCacheManager class.
Listen for events of various types and sources and react to them.
Definition: SlsListener.hxx:63
css::uno::WeakReference< css::frame::XFrame > mxFrameWeak
void HandleModelChange(const SdrPage *pPage)
Handle a change in the order of slides or when the set of slides has changed, i.e.
void DisconnectFromController()
Disconnect from the current controller of the view shell as listener.
css::uno::WeakReference< css::frame::XController > mxControllerWeak
bool mbListeningToFrame
Remember whether we are listening to the frame.
void ConnectToController()
Connect to the current controller of the view shell as listener.
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 notifyEvent(const css::document::EventObject &rEventObject) override
virtual void Notify(SfxBroadcaster &rBroadcaster, const SfxHint &rHint) override
bool mbListeningToDocument
Remember whether we are listening to the document.
std::shared_ptr< SlideSorterController::ModelChangeLock > mpModelChangeLock
This object is used to lock the model between some events.
Listener(SlideSorter &rSlideSorter)
Definition: SlsListener.cxx:55
void HandleShapeModification(const SdrPage *pPage)
Handle a modification to a shape on the given page.
bool mbListeningToController
Remember whether we are listening to the UNO controller.
SlideSorterController & mrController
virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent &rEvent) override
void UpdateEditMode()
Called when the edit mode has changed.
bool mbListeningToUNODocument
Remember whether we are listening to the UNO document.
virtual void SAL_CALL disposing(const css::lang::EventObject &rEventObject) override
void GetCoreSelection()
Update the selection state of all page descriptors to be the same as that of the corresponding pages ...
void SelectPage(int nPageIndex)
Select the specified descriptor.
Create an object of this inner class to prevent updates due to model changes.
void HandleModelChange()
Handle a change of the model, that is, handle the removal and insertion of whole pages or a change of...
void PrepareEditModeChange()
Prepare for a change of the edit mode.
void ChangeEditMode(EditMode eEditMode)
Set a new edit mode and return whether the edit mode really has been changed.
std::shared_ptr< CurrentSlideManager > const & GetCurrentSlideManager() const
std::shared_ptr< SelectionManager > const & GetSelectionManager() const
void FinishEditModeChange()
Finish the change of the edit mode.
bool NotifyPageEvent(const SdrPage *pPage)
Typically called from controller::Listener this method handles the insertion and deletion of single p...
SdDrawDocument * GetDocument()
This method is present to let the view create a ShowView for displaying slides.
std::shared_ptr< cache::PageCache > const & GetPreviewCache()
int nCount
#define DBG_ASSERT(sCon, aError)
#define DBG_UNHANDLED_EXCEPTION(...)
virtual std::shared_ptr< SfxDialogController > GetController() override
EmbeddedObjectRef * pObject
sal_Int32 nIndex
IMPL_LINK(SlideSorterController, ApplicationEventHandler, VclSimpleEvent &, rEvent, void)
Reference< XController > xController
Reference< XFrame > xFrame