xref: /core/sd/source/ui/slideshow/slideshowimpl.cxx (revision a4d53515)
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 <sal/config.h>
21 
22 #include <algorithm>
23 
24 #include <config_features.h>
25 
26 #include <com/sun/star/frame/theAutoRecovery.hpp>
27 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
28 #include <com/sun/star/document/XEventsSupplier.hpp>
29 #include <com/sun/star/drawing/XMasterPageTarget.hpp>
30 #include <com/sun/star/beans/PropertyValue.hpp>
31 #include <com/sun/star/beans/XPropertySetInfo.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/awt/SystemPointer.hpp>
34 #include <com/sun/star/util/URLTransformer.hpp>
35 #include <com/sun/star/util/XURLTransformer.hpp>
36 #include <com/sun/star/frame/XDispatch.hpp>
37 #include <com/sun/star/frame/XLayoutManager.hpp>
38 #include <com/sun/star/presentation/SlideShow.hpp>
39 #include <com/sun/star/media/XPlayer.hpp>
40 #include <officecfg/Office/Impress.hxx>
41 #include <officecfg/Office/Recovery.hxx>
42 #include <svl/stritem.hxx>
43 #include <svl/urihelper.hxx>
44 #include <basic/sbstar.hxx>
45 
46 #include <toolkit/helper/vclunohelper.hxx>
47 #include <comphelper/diagnose_ex.hxx>
48 #include <comphelper/sequence.hxx>
49 
50 #include <sfx2/infobar.hxx>
51 #include <sfx2/dispatch.hxx>
52 #include <sfx2/docfile.hxx>
53 #include <sfx2/app.hxx>
54 #include <sfx2/viewfrm.hxx>
55 #include <svx/svdoole2.hxx>
56 #include <svx/f3dchild.hxx>
57 #include <svx/imapdlg.hxx>
58 #include <svx/fontwork.hxx>
59 #include <svx/SvxColorChildWindow.hxx>
60 #include <svx/bmpmask.hxx>
61 #include <svx/srchdlg.hxx>
62 #include <svx/hyperdlg.hxx>
63 #include <svx/svxids.hrc>
64 #include <svx/unoapi.hxx>
65 #include <AnimationChildWindow.hxx>
66 #include <notifydocumentevent.hxx>
67 #include "slideshowimpl.hxx"
68 #include "slideshowviewimpl.hxx"
69 #include "PaneHider.hxx"
70 
71 #include <bitmaps.hlst>
72 #include <strings.hrc>
73 #include <sdresid.hxx>
74 #include <utility>
75 #include <vcl/canvastools.hxx>
76 #include <vcl/commandevent.hxx>
77 #include <vcl/weldutils.hxx>
78 
79 #include <vcl/settings.hxx>
80 #include <vcl/svapp.hxx>
81 #include <vcl/help.hxx>
82 #include <comphelper/processfactory.hxx>
83 #include <comphelper/propertyvalue.hxx>
84 #include <rtl/ref.hxx>
85 #include <o3tl/safeint.hxx>
86 #include <o3tl/string_view.hxx>
87 #include <avmedia/mediawindow.hxx>
88 #include <svtools/colrdlg.hxx>
89 #include <DrawDocShell.hxx>
90 #include <ViewShellBase.hxx>
91 #include <PresentationViewShell.hxx>
92 #include <RemoteServer.hxx>
93 #include <customshowlist.hxx>
94 #include <unopage.hxx>
95 #include <sdpage.hxx>
96 #include <sdmod.hxx>
97 #include <app.hrc>
98 #include <cusshow.hxx>
99 #include <optsitem.hxx>
100 
101 #define CM_SLIDES       21
102 
103 using ::com::sun::star::animations::XAnimationNode;
104 using ::com::sun::star::animations::XAnimationListener;
105 using ::com::sun::star::awt::XWindow;
106 using namespace ::com::sun::star;
107 using namespace ::com::sun::star::lang;
108 using namespace ::com::sun::star::uno;
109 using namespace ::com::sun::star::drawing;
110 using namespace ::com::sun::star::container;
111 using namespace ::com::sun::star::presentation;
112 using namespace ::com::sun::star::beans;
113 
114 namespace sd
115 {
116 /** Slots, which will be disabled in the slide show and are managed by Sfx.
117     Have to be sorted in the order of the SIDs */
118 sal_uInt16 const pAllowed[] =
119 {
120     SID_OPENDOC                             , //     5501   ///< that internally jumps work
121     SID_JUMPTOMARK                          , //     5598
122     SID_OPENHYPERLINK                       , //     6676
123     SID_PRESENTATION_END                     //    27218
124 };
125 
126 class AnimationSlideController
127 {
128 public:
129     enum Mode { ALL, FROM, CUSTOM, PREVIEW };
130 
131 public:
132     AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode );
133 
setStartSlideNumber(sal_Int32 nSlideNumber)134     void setStartSlideNumber( sal_Int32 nSlideNumber ) { mnStartSlideNumber = nSlideNumber; }
135     sal_Int32 getStartSlideIndex() const;
136 
137     sal_Int32 getCurrentSlideNumber() const;
138     sal_Int32 getCurrentSlideIndex() const;
139 
getSlideIndexCount() const140     sal_Int32 getSlideIndexCount() const { return maSlideNumbers.size(); }
getSlideNumberCount() const141     sal_Int32 getSlideNumberCount() const { return mnSlideCount; }
142 
143     sal_Int32 getSlideNumber( sal_Int32 nSlideIndex ) const;
144 
145     void insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible = true );
146     void setPreviewNode( const Reference< XAnimationNode >& xPreviewNode );
147 
148     bool jumpToSlideIndex( sal_Int32 nNewSlideIndex );
149     bool jumpToSlideNumber( sal_Int32 nNewSlideIndex );
150 
151     bool nextSlide();
152     bool previousSlide();
153 
154     void displayCurrentSlide( const Reference< XSlideShow >& xShow,
155                               const Reference< XDrawPagesSupplier>& xDrawPages,
156                               const bool bSkipAllMainSequenceEffects );
157 
158     sal_Int32 getNextSlideIndex() const;
159     sal_Int32 getPreviousSlideIndex() const;
160 
161     bool isVisibleSlideNumber( sal_Int32 nSlideNumber ) const;
162 
163     Reference< XDrawPage > getSlideByNumber( sal_Int32 nSlideNumber ) const;
164 
165     sal_Int32 getNextSlideNumber() const;
166 
hasSlides() const167     bool hasSlides() const { return !maSlideNumbers.empty(); }
168 
169     // for InteractiveSlideShow we need to temporarily change the program
170     // and mode, so allow save/restore that settings
171     void pushForPreview();
172     void popFromPreview();
173 private:
174     bool getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode );
175     sal_Int32 findSlideIndex( sal_Int32 nSlideNumber ) const;
176 
isValidIndex(sal_Int32 nIndex) const177     bool isValidIndex( sal_Int32 nIndex ) const { return (nIndex >= 0) && (o3tl::make_unsigned(nIndex) < maSlideNumbers.size()); }
isValidSlideNumber(sal_Int32 nSlideNumber) const178     bool isValidSlideNumber( sal_Int32 nSlideNumber ) const { return (nSlideNumber >= 0) && (nSlideNumber < mnSlideCount); }
179 
180 private:
181     Mode meMode;
182     sal_Int32 mnStartSlideNumber;
183     std::vector< sal_Int32 > maSlideNumbers;
184     std::vector< bool > maSlideVisible;
185     std::vector< bool > maSlideVisited;
186     Reference< XAnimationNode > mxPreviewNode;
187     sal_Int32 mnSlideCount;
188     sal_Int32 mnCurrentSlideIndex;
189     sal_Int32 mnHiddenSlideNumber;
190     Reference< XIndexAccess > mxSlides;
191 
192     // IASS data for push/pop
193     std::vector< sal_Int32 > maSlideNumbers2;
194     std::vector< bool > maSlideVisible2;
195     std::vector< bool > maSlideVisited2;
196     Reference< XAnimationNode > mxPreviewNode2;
197     Mode meMode2;
198 };
199 
pushForPreview()200 void AnimationSlideController::pushForPreview()
201 {
202     maSlideNumbers2 = maSlideNumbers;
203     maSlideVisible2 = maSlideVisible;
204     maSlideVisited2 = maSlideVisited;
205     maSlideNumbers.clear();
206     maSlideVisible.clear();
207     maSlideVisited.clear();
208     mxPreviewNode2 = mxPreviewNode;
209     meMode2 = meMode;
210     meMode = AnimationSlideController::PREVIEW;
211 }
212 
popFromPreview()213 void AnimationSlideController::popFromPreview()
214 {
215     maSlideNumbers = maSlideNumbers2;
216     maSlideVisible = maSlideVisible2;
217     maSlideVisited = maSlideVisited2;
218     maSlideNumbers2.clear();
219     maSlideVisible2.clear();
220     maSlideVisited2.clear();
221     mxPreviewNode = mxPreviewNode2;
222     meMode = meMode2;
223 }
224 
getSlideByNumber(sal_Int32 nSlideNumber) const225 Reference< XDrawPage > AnimationSlideController::getSlideByNumber( sal_Int32 nSlideNumber ) const
226 {
227     Reference< XDrawPage > xSlide;
228     if( mxSlides.is() && (nSlideNumber >= 0) && (nSlideNumber < mxSlides->getCount()) )
229         mxSlides->getByIndex( nSlideNumber ) >>= xSlide;
230     return xSlide;
231 }
232 
isVisibleSlideNumber(sal_Int32 nSlideNumber) const233 bool AnimationSlideController::isVisibleSlideNumber( sal_Int32 nSlideNumber ) const
234 {
235     sal_Int32 nIndex = findSlideIndex( nSlideNumber );
236 
237     if( nIndex != -1 )
238         return maSlideVisible[ nIndex ];
239     else
240         return false;
241 }
242 
setPreviewNode(const Reference<XAnimationNode> & xPreviewNode)243 void AnimationSlideController::setPreviewNode( const Reference< XAnimationNode >& xPreviewNode )
244 {
245     mxPreviewNode = xPreviewNode;
246 }
247 
AnimationSlideController(Reference<XIndexAccess> const & xSlides,Mode eMode)248 AnimationSlideController::AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode  )
249 :   meMode( eMode )
250 ,   mnStartSlideNumber(-1)
251 ,   mnSlideCount( 0 )
252 ,   mnCurrentSlideIndex(0)
253 ,   mnHiddenSlideNumber( -1 )
254 ,   mxSlides( xSlides )
255 ,   meMode2( eMode )
256 {
257     if( mxSlides.is() )
258         mnSlideCount = xSlides->getCount();
259 }
260 
getStartSlideIndex() const261 sal_Int32 AnimationSlideController::getStartSlideIndex() const
262 {
263     if( mnStartSlideNumber >= 0 )
264     {
265         sal_Int32 nIndex;
266         const sal_Int32 nCount = maSlideNumbers.size();
267 
268         for( nIndex = 0; nIndex < nCount; nIndex++ )
269         {
270             if( maSlideNumbers[nIndex] == mnStartSlideNumber )
271                 return nIndex;
272         }
273     }
274 
275     return 0;
276 }
277 
getCurrentSlideNumber() const278 sal_Int32 AnimationSlideController::getCurrentSlideNumber() const
279 {
280     if( mnHiddenSlideNumber != -1 )
281         return mnHiddenSlideNumber;
282     else if( !maSlideNumbers.empty() )
283         return maSlideNumbers[mnCurrentSlideIndex];
284     else
285         return 0;
286 }
287 
getCurrentSlideIndex() const288 sal_Int32 AnimationSlideController::getCurrentSlideIndex() const
289 {
290     if( mnHiddenSlideNumber != -1 )
291         return -1;
292     else
293         return mnCurrentSlideIndex;
294 }
295 
jumpToSlideIndex(sal_Int32 nNewSlideIndex)296 bool AnimationSlideController::jumpToSlideIndex( sal_Int32 nNewSlideIndex )
297 {
298     if( isValidIndex( nNewSlideIndex ) )
299     {
300         mnCurrentSlideIndex = nNewSlideIndex;
301         mnHiddenSlideNumber = -1;
302         maSlideVisited[mnCurrentSlideIndex] = true;
303         return true;
304     }
305     else
306     {
307         return false;
308     }
309 }
310 
jumpToSlideNumber(sal_Int32 nNewSlideNumber)311 bool AnimationSlideController::jumpToSlideNumber( sal_Int32 nNewSlideNumber )
312 {
313     sal_Int32 nIndex = findSlideIndex( nNewSlideNumber );
314     if( isValidIndex( nIndex ) )
315     {
316         return jumpToSlideIndex( nIndex );
317     }
318     else if( (nNewSlideNumber >= 0) && (nNewSlideNumber < mnSlideCount) )
319     {
320         // jump to a hidden slide
321         mnHiddenSlideNumber = nNewSlideNumber;
322         return true;
323     }
324     else
325     {
326         return false;
327     }
328 }
329 
getSlideNumber(sal_Int32 nSlideIndex) const330 sal_Int32 AnimationSlideController::getSlideNumber( sal_Int32 nSlideIndex ) const
331 {
332     if( isValidIndex( nSlideIndex ) )
333         return maSlideNumbers[nSlideIndex];
334     else
335         return -1;
336 }
337 
insertSlideNumber(sal_Int32 nSlideNumber,bool bVisible)338 void AnimationSlideController::insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible /* = true */ )
339 {
340     DBG_ASSERT( isValidSlideNumber( nSlideNumber ), "sd::AnimationSlideController::insertSlideNumber(), illegal index" );
341     if( isValidSlideNumber( nSlideNumber ) )
342     {
343         maSlideNumbers.push_back( nSlideNumber );
344         maSlideVisible.push_back( bVisible );
345         maSlideVisited.push_back( false );
346     }
347 }
348 
getSlideAPI(sal_Int32 nSlideNumber,Reference<XDrawPage> & xSlide,Reference<XAnimationNode> & xAnimNode)349 bool AnimationSlideController::getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode )
350 {
351     if( isValidSlideNumber( nSlideNumber ) ) try
352     {
353         xSlide.set( mxSlides->getByIndex(nSlideNumber), UNO_QUERY_THROW );
354 
355         if( meMode == PREVIEW )
356         {
357             xAnimNode = mxPreviewNode;
358         }
359         else
360         {
361             Reference< animations::XAnimationNodeSupplier > xAnimNodeSupplier( xSlide, UNO_QUERY_THROW );
362             xAnimNode = xAnimNodeSupplier->getAnimationNode();
363         }
364 
365         return true;
366     }
367     catch( Exception& )
368     {
369         TOOLS_WARN_EXCEPTION( "sd", "sd::AnimationSlideController::getSlideAPI()" );
370     }
371 
372     return false;
373 }
374 
findSlideIndex(sal_Int32 nSlideNumber) const375 sal_Int32 AnimationSlideController::findSlideIndex( sal_Int32 nSlideNumber ) const
376 {
377     sal_Int32 nIndex;
378     const sal_Int32 nCount = maSlideNumbers.size();
379 
380     for( nIndex = 0; nIndex < nCount; nIndex++ )
381     {
382         if( maSlideNumbers[nIndex] == nSlideNumber )
383             return nIndex;
384     }
385 
386     return -1;
387 }
388 
getNextSlideIndex() const389 sal_Int32 AnimationSlideController::getNextSlideIndex() const
390 {
391     switch( meMode )
392     {
393     case ALL:
394         {
395             sal_Int32 nNewSlideIndex = mnCurrentSlideIndex + 1;
396             if( isValidIndex( nNewSlideIndex ) )
397             {
398                 // if the current slide is not excluded, make sure the
399                 // next slide is also not excluded.
400                 // if the current slide is excluded, we want to go
401                 // to the next slide, even if this is also excluded.
402                 if( maSlideVisible[mnCurrentSlideIndex] )
403                 {
404                     while( isValidIndex( nNewSlideIndex ) )
405                     {
406                         if( maSlideVisible[nNewSlideIndex] )
407                             break;
408 
409                         nNewSlideIndex++;
410                     }
411                 }
412             }
413             return isValidIndex( nNewSlideIndex ) ? nNewSlideIndex : -1;
414         }
415 
416     case FROM:
417     case CUSTOM:
418         return mnHiddenSlideNumber == -1 ? mnCurrentSlideIndex + 1 : mnCurrentSlideIndex;
419 
420     default:
421     case PREVIEW:
422         return -1;
423 
424     }
425 }
426 
getNextSlideNumber() const427 sal_Int32 AnimationSlideController::getNextSlideNumber() const
428 {
429     sal_Int32 nNextSlideIndex = getNextSlideIndex();
430     if( isValidIndex( nNextSlideIndex ) )
431     {
432         return maSlideNumbers[nNextSlideIndex];
433     }
434     else
435     {
436         return -1;
437     }
438 }
439 
nextSlide()440 bool AnimationSlideController::nextSlide()
441 {
442     return jumpToSlideIndex( getNextSlideIndex() );
443 }
444 
getPreviousSlideIndex() const445 sal_Int32 AnimationSlideController::getPreviousSlideIndex() const
446 {
447     sal_Int32 nNewSlideIndex = mnCurrentSlideIndex - 1;
448 
449     switch( meMode )
450     {
451         case ALL:
452         {
453             // make sure the previous slide is visible
454             // or was already visited
455             while( isValidIndex( nNewSlideIndex ) )
456             {
457                 if( maSlideVisible[nNewSlideIndex] || maSlideVisited[nNewSlideIndex] )
458                     break;
459 
460                 nNewSlideIndex--;
461             }
462 
463             break;
464         }
465 
466         case PREVIEW:
467             return -1;
468 
469         default:
470             break;
471     }
472 
473     return nNewSlideIndex;
474 }
475 
previousSlide()476 bool AnimationSlideController::previousSlide()
477 {
478     return jumpToSlideIndex( getPreviousSlideIndex() );
479 }
480 
displayCurrentSlide(const Reference<XSlideShow> & xShow,const Reference<XDrawPagesSupplier> & xDrawPages,const bool bSkipAllMainSequenceEffects)481 void AnimationSlideController::displayCurrentSlide( const Reference< XSlideShow >& xShow,
482                                                     const Reference< XDrawPagesSupplier>& xDrawPages,
483                                                     const bool bSkipAllMainSequenceEffects )
484 {
485     const sal_Int32 nCurrentSlideNumber = getCurrentSlideNumber();
486 
487     if( !(xShow.is() && (nCurrentSlideNumber != -1 )) )
488         return;
489 
490     Reference< XDrawPage > xSlide;
491     Reference< XAnimationNode > xAnimNode;
492     ::std::vector<PropertyValue> aProperties;
493 
494     const sal_Int32 nNextSlideNumber = getNextSlideNumber();
495     if( getSlideAPI( nNextSlideNumber, xSlide, xAnimNode )  )
496     {
497         Sequence< Any > aValue{ Any(xSlide), Any(xAnimNode) };
498         aProperties.emplace_back( "Prefetch" ,
499                 -1,
500                 Any(aValue),
501                 PropertyState_DIRECT_VALUE);
502     }
503     if (bSkipAllMainSequenceEffects)
504     {
505         // Add one property that prevents the slide transition from being
506         // shown (to speed up the transition to the previous slide) and
507         // one to show all main sequence effects so that the user can
508         // continue to undo effects.
509         aProperties.emplace_back( "SkipAllMainSequenceEffects",
510                 -1,
511                 Any(true),
512                 PropertyState_DIRECT_VALUE);
513         aProperties.emplace_back("SkipSlideTransition",
514                 -1,
515                 Any(true),
516                 PropertyState_DIRECT_VALUE);
517     }
518 
519     if( getSlideAPI( nCurrentSlideNumber, xSlide, xAnimNode ) )
520         xShow->displaySlide( xSlide, xDrawPages, xAnimNode, comphelper::containerToSequence(aProperties) );
521 }
522 
523 constexpr OUString gsOnClick( u"OnClick"_ustr );
524 constexpr OUString gsBookmark( u"Bookmark"_ustr );
525 constexpr OUString gsVerb( u"Verb"_ustr );
526 
SlideshowImpl(const Reference<XPresentation2> & xPresentation,ViewShell * pViewSh,::sd::View * pView,SdDrawDocument * pDoc,vcl::Window * pParentWindow)527 SlideshowImpl::SlideshowImpl( const Reference< XPresentation2 >& xPresentation, ViewShell* pViewSh, ::sd::View* pView, SdDrawDocument* pDoc, vcl::Window* pParentWindow )
528 : mxShow()
529 , mxView()
530 , mxModel(pDoc->getUnoModel())
531 , maUpdateTimer("SlideShowImpl maUpdateTimer")
532 , maInputFreezeTimer("SlideShowImpl maInputFreezeTimer")
533 , maDeactivateTimer("SlideShowImpl maDeactivateTimer")
534 , mpView(pView)
535 , mpViewShell(pViewSh)
536 , mpDocSh(pDoc->GetDocSh())
537 , mpDoc(pDoc)
538 , mpParentWindow(pParentWindow)
539 , mpShowWindow(nullptr)
540 , mpSlideController()
541 , mnRestoreSlide(0)
542 , maPopupMousePos()
543 , maPresSize( -1, -1 )
544 , meAnimationMode(ANIMATIONMODE_SHOW)
545 , maCharBuffer()
546 , mpOldActiveWindow(nullptr)
547 , maStarBASICGlobalErrorHdl()
548 , mnChildMask( 0 )
549 , mbDisposed(false)
550 , mbAutoSaveWasOn(false)
551 , mbRehearseTimings(false)
552 , mbIsPaused(false)
553 , mbWasPaused(false)
554 , mbInputFreeze(false)
555 , mbActive(false)
556 , maPresSettings( pDoc->getPresentationSettings() )
557 , mnUserPaintColor( 0x80ff0000L )
558 , mbUsePen(false)
559 , mdUserPaintStrokeWidth ( 150.0 )
560 , maShapeEventMap()
561 , mxPreviewDrawPage()
562 , mxPreviewAnimationNode()
563 , mxPlayer()
564 , mpPaneHider()
565 , mnEndShowEvent(nullptr)
566 , mnContextMenuEvent(nullptr)
567 , mnEventObjectChange(nullptr)
568 , mnEventObjectInserted(nullptr)
569 , mnEventObjectRemoved(nullptr)
570 , mnEventPageOrderChange(nullptr)
571 , mxPresentation( xPresentation )
572 , mxListenerProxy()
573 , mxShow2()
574 , mxView2()
575 , meAnimationMode2()
576 , mbInterActiveSetup(false)
577 , maPresSettings2()
578 , mxPreviewDrawPage2()
579 , mxPreviewAnimationNode2()
580 , mnSlideIndex(0)
581 {
582     if( mpViewShell )
583         mpOldActiveWindow = mpViewShell->GetActiveWindow();
584 
585     maUpdateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, updateHdl));
586     // Priority must not be too high or we'll starve input handling etc.
587     maUpdateTimer.SetPriority(TaskPriority::REPAINT);
588 
589     maDeactivateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, deactivateHdl));
590     maDeactivateTimer.SetTimeout( 20 );
591 
592     maInputFreezeTimer.SetInvokeHandler( LINK( this, SlideshowImpl, ReadyForNextInputHdl ) );
593     maInputFreezeTimer.SetTimeout( 20 );
594 
595         // no autosave during show
596     if (officecfg::Office::Recovery::AutoSave::Enabled::get())
597         mbAutoSaveWasOn = true;
598 
599     Application::AddEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) );
600 
601     mbUsePen = maPresSettings.mbMouseAsPen;
602 
603     SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
604     if( pOptions )
605     {
606         mnUserPaintColor = pOptions->GetPresentationPenColor();
607         mdUserPaintStrokeWidth = pOptions->GetPresentationPenWidth();
608     }
609 
610     // to be able to react on various changes in the DrawModel, this class
611     // is now derived from SfxListener and registers itself at the DrawModel
612     if (nullptr != mpDoc)
613         StartListening(*mpDoc);
614 }
615 
~SlideshowImpl()616 SlideshowImpl::~SlideshowImpl()
617 {
618     // stop listening to DrawModel (see above)
619     if (nullptr != mpDoc)
620         EndListening(*mpDoc);
621 
622     SdModule *pModule = SD_MOD();
623     //rhbz#806663 SlideshowImpl can outlive SdModule
624     SdOptions* pOptions = pModule ?
625         pModule->GetSdOptions(DocumentType::Impress) : nullptr;
626     if( pOptions )
627     {
628         pOptions->SetPresentationPenColor(mnUserPaintColor);
629         pOptions->SetPresentationPenWidth(mdUserPaintStrokeWidth);
630     }
631 
632     Application::RemoveEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) );
633 
634     maDeactivateTimer.Stop();
635 
636     if( !mbDisposed )
637     {
638         OSL_FAIL("SlideshowImpl::~SlideshowImpl(), component was not disposed!");
639         std::unique_lock g(m_aMutex);
640         disposing(g);
641     }
642 }
643 
disposing(std::unique_lock<std::mutex> &)644 void SlideshowImpl::disposing(std::unique_lock<std::mutex>&)
645 {
646 #ifdef ENABLE_SDREMOTE
647     RemoteServer::presentationStopped();
648 #endif
649     // IASS: This is the central methodology to 'steer' the
650     // PresenterConsole - in this case, to shut it down
651     if( mxShow.is() && mpDoc )
652         NotifyDocumentEvent(
653             *mpDoc,
654             u"OnEndPresentation"_ustr );
655 
656     if( mbAutoSaveWasOn )
657         setAutoSaveState( true );
658 
659     if( mnEndShowEvent )
660         Application::RemoveUserEvent( mnEndShowEvent );
661     if( mnContextMenuEvent )
662         Application::RemoveUserEvent( mnContextMenuEvent );
663     if( mnEventObjectChange )
664         Application::RemoveUserEvent( mnEventObjectChange );
665     if( mnEventObjectInserted )
666         Application::RemoveUserEvent( mnEventObjectInserted );
667     if( mnEventObjectRemoved )
668         Application::RemoveUserEvent( mnEventObjectRemoved );
669     if( mnEventPageOrderChange )
670         Application::RemoveUserEvent( mnEventPageOrderChange );
671 
672     maInputFreezeTimer.Stop();
673 
674     SolarMutexGuard aSolarGuard;
675 
676     if( !mxShow.is() )
677         return;
678 
679     if( mxPresentation.is() )
680         mxPresentation->end();
681 
682     maUpdateTimer.Stop();
683 
684     removeShapeEvents();
685 
686     if( mxListenerProxy.is() )
687         mxListenerProxy->removeAsSlideShowListener();
688 
689     try
690     {
691         if( mxView.is() )
692             mxShow->removeView( mxView );
693 
694         Reference< XComponent > xComponent( mxShow, UNO_QUERY );
695         if( xComponent.is() )
696             xComponent->dispose();
697 
698         if( mxView.is() )
699             mxView->dispose();
700     }
701     catch( Exception& )
702     {
703         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" );
704     }
705 
706     mxShow.clear();
707     mxView.clear();
708     mxListenerProxy.clear();
709     mpSlideController.reset();
710 
711     // take DrawView from presentation window, but give the old window back
712     if( mpShowWindow && mpView )
713         mpView->DeleteDeviceFromPaintView( *mpShowWindow->GetOutDev() );
714 
715     if( mpView )
716         mpView->SetAnimationPause( false );
717 
718     if( mpViewShell )
719     {
720         mpViewShell->SetActiveWindow(mpOldActiveWindow);
721         if (mpShowWindow)
722             mpShowWindow->SetViewShell( nullptr );
723     }
724 
725     if( mpView )
726         mpView->InvalidateAllWin();
727 
728     if( maPresSettings.mbFullScreen )
729     {
730 #if HAVE_FEATURE_SCRIPTING
731         // restore StarBASICErrorHdl
732         StarBASIC::SetGlobalErrorHdl(maStarBASICGlobalErrorHdl);
733         maStarBASICGlobalErrorHdl = Link<StarBASIC*,bool>();
734 #endif
735     }
736     else
737     {
738         if( mpShowWindow )
739             mpShowWindow->Hide();
740     }
741 
742     if( meAnimationMode == ANIMATIONMODE_SHOW )
743     {
744         mpDocSh->SetSlotFilter();
745         mpDocSh->ApplySlotFilter();
746 
747         Help::EnableContextHelp();
748         Help::EnableExtHelp();
749 
750         showChildWindows();
751         mnChildMask = 0;
752     }
753 
754     // show current window again
755     if( mpViewShell && dynamic_cast< PresentationViewShell *>( mpViewShell ) ==  nullptr)
756     {
757         if( meAnimationMode == ANIMATIONMODE_SHOW )
758         {
759             mpViewShell->GetViewShellBase().ShowUIControls (true);
760             mpPaneHider.reset();
761         }
762         else if( meAnimationMode == ANIMATIONMODE_PREVIEW )
763         {
764             mpViewShell->ShowUIControls(true);
765         }
766     }
767 
768     if( mpShowWindow )
769         mpShowWindow->Hide();
770     mpShowWindow.disposeAndClear();
771 
772     if ( mpViewShell )
773     {
774         if( meAnimationMode == ANIMATIONMODE_SHOW )
775         {
776             ::sd::Window* pActWin = mpViewShell->GetActiveWindow();
777 
778             if (pActWin)
779             {
780                 Size aVisSizePixel = pActWin->GetOutputSizePixel();
781                 ::tools::Rectangle aVisAreaWin = pActWin->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
782                 mpViewShell->VisAreaChanged(aVisAreaWin);
783                 if (mpView)
784                     mpView->VisAreaChanged(pActWin->GetOutDev());
785                 pActWin->GrabFocus();
786             }
787         }
788 
789         // restart the custom show dialog if he started us
790         if( mpViewShell->IsStartShowWithDialog() && getDispatcher() )
791         {
792             mpViewShell->SetStartShowWithDialog( false );
793             getDispatcher()->Execute( SID_CUSTOMSHOW_DLG, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
794         }
795 
796         mpViewShell->GetViewShellBase().UpdateBorder(true);
797     }
798 
799     if( mpShowWindow )
800     {
801         mpShowWindow.disposeAndClear();
802     }
803 
804     setActiveXToolbarsVisible( true );
805 
806     mbDisposed = true;
807 }
808 
isInteractiveSetup() const809 bool SlideshowImpl::isInteractiveSetup() const
810 {
811     return mbInterActiveSetup;
812 }
813 
startInteractivePreview(const Reference<XDrawPage> & xDrawPage,const Reference<XAnimationNode> & xAnimationNode)814 void SlideshowImpl::startInteractivePreview( const Reference< XDrawPage >& xDrawPage, const Reference< XAnimationNode >& xAnimationNode )
815 {
816     // set flag that we are in IASS mode
817     mbInterActiveSetup = true;
818 
819     // save stuff that will be replaced temporarily
820     mxShow2 = mxShow;
821     mxView2 = mxView;
822     mxPreviewDrawPage2 = mxPreviewDrawPage;
823     mxPreviewAnimationNode2 = mxPreviewAnimationNode;
824     meAnimationMode2 = meAnimationMode;
825     maPresSettings2 = maPresSettings;
826 
827     // remember slide shown before preview
828     mnSlideIndex = getCurrentSlideIndex();
829 
830     // set DrawPage/AnimationNode
831     mxPreviewDrawPage = xDrawPage;
832     mxPreviewAnimationNode = xAnimationNode;
833     meAnimationMode = ANIMATIONMODE_PREVIEW;
834 
835     // set PresSettings for preview
836     maPresSettings.mbAll = false;
837     maPresSettings.mbEndless = false;
838     maPresSettings.mbCustomShow = false;
839     maPresSettings.mbManual = false;
840     maPresSettings.mbMouseVisible = false;
841     maPresSettings.mbMouseAsPen = false;
842     maPresSettings.mbLockedPages = false;
843     maPresSettings.mbAlwaysOnTop = false;
844     maPresSettings.mbFullScreen = false;
845     maPresSettings.mbAnimationAllowed = true;
846     maPresSettings.mnPauseTimeout = 0;
847     maPresSettings.mbShowPauseLogo = false;
848 
849     // create a new temporary AnimationSlideController
850     mpSlideController->pushForPreview();
851     // Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
852     // Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
853     // mpSlideController = std::make_shared<AnimationSlideController>( xSlides, AnimationSlideController::PREVIEW );
854     sal_Int32 nSlideNumber = 0;
855     Reference< XPropertySet > xSet( xDrawPage, UNO_QUERY_THROW );
856     xSet->getPropertyValue( u"Number"_ustr ) >>= nSlideNumber;
857     mpSlideController->insertSlideNumber( nSlideNumber-1 );
858     mpSlideController->setPreviewNode( xAnimationNode );
859 
860     // prepare properties
861     sal_Int32 nPropertyCount = 1;
862     if( xAnimationNode.is() )
863         nPropertyCount++;
864     Sequence< beans::PropertyValue > aProperties(nPropertyCount);
865     auto pProperties = aProperties.getArray();
866     pProperties[0].Name = "AutomaticAdvancement";
867     pProperties[0].Value <<= 1.0; // one second timeout
868 
869     if( xAnimationNode.is() )
870     {
871         pProperties[1].Name = "NoSlideTransitions";
872         pProperties[1].Value <<= true;
873     }
874 
875     // start preview
876     startShowImpl( aProperties );
877 }
878 
endInteractivePreview()879 void SlideshowImpl::endInteractivePreview()
880 {
881     if (!mbInterActiveSetup)
882         // not in use, nothing to do
883         return;
884 
885     // cleanup Show/View
886     try
887     {
888         if( mxView.is() )
889             mxShow->removeView( mxView );
890 
891         Reference< XComponent > xComponent( mxShow, UNO_QUERY );
892         if( xComponent.is() )
893             xComponent->dispose();
894 
895         if( mxView.is() )
896             mxView->dispose();
897     }
898     catch( Exception& )
899     {
900         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" );
901     }
902     mxShow.clear();
903     mxView.clear();
904     mxView = mxView2;
905     mxShow = mxShow2;
906 
907     // restore SlideController
908     mpSlideController->popFromPreview();
909 
910     // restore other settings and cleanup temporary incarnations
911     maPresSettings = maPresSettings2;
912     meAnimationMode = meAnimationMode2;
913     mxPreviewAnimationNode = mxPreviewAnimationNode2;
914     mxPreviewAnimationNode2.clear();
915     mxPreviewDrawPage = mxPreviewDrawPage2;
916     mxPreviewDrawPage2.clear();
917 
918     // go back to slide shown before preview
919     gotoSlideIndex(mnSlideIndex);
920 
921     // reset IASS mode flag
922     mbInterActiveSetup = false;
923 }
924 
startPreview(const Reference<XDrawPage> & xDrawPage,const Reference<XAnimationNode> & xAnimationNode,vcl::Window * pParent)925 bool SlideshowImpl::startPreview(
926         const Reference< XDrawPage >& xDrawPage,
927         const Reference< XAnimationNode >& xAnimationNode,
928         vcl::Window * pParent )
929 {
930     bool bRet = false;
931 
932     try
933     {
934         const Reference<lang::XServiceInfo> xServiceInfo( xDrawPage, UNO_QUERY );
935         if (xServiceInfo.is()) {
936             const Sequence<OUString> supportedServices(
937                 xServiceInfo->getSupportedServiceNames() );
938             if (comphelper::findValue(supportedServices, "com.sun.star.drawing.MasterPage") != -1) {
939                 OSL_FAIL("sd::SlideshowImpl::startPreview() "
940                           "not allowed on master page!");
941                 return false;
942             }
943         }
944 
945         mxPreviewDrawPage = xDrawPage;
946         mxPreviewAnimationNode = xAnimationNode;
947         meAnimationMode = ANIMATIONMODE_PREVIEW;
948 
949         maPresSettings.mbAll = false;
950         maPresSettings.mbEndless = false;
951         maPresSettings.mbCustomShow = false;
952         maPresSettings.mbManual = false;
953         maPresSettings.mbMouseVisible = false;
954         maPresSettings.mbMouseAsPen = false;
955         maPresSettings.mbLockedPages = false;
956         maPresSettings.mbAlwaysOnTop = false;
957         maPresSettings.mbFullScreen = false;
958         maPresSettings.mbAnimationAllowed = true;
959         maPresSettings.mnPauseTimeout = 0;
960         maPresSettings.mbShowPauseLogo = false;
961 
962         Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
963         Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
964         mpSlideController = std::make_shared<AnimationSlideController>( xSlides, AnimationSlideController::PREVIEW );
965 
966         sal_Int32 nSlideNumber = 0;
967         Reference< XPropertySet > xSet( mxPreviewDrawPage, UNO_QUERY_THROW );
968         xSet->getPropertyValue( u"Number"_ustr ) >>= nSlideNumber;
969         mpSlideController->insertSlideNumber( nSlideNumber-1 );
970         mpSlideController->setPreviewNode( xAnimationNode );
971 
972         mpShowWindow = VclPtr<ShowWindow>::Create( this, ((pParent == nullptr) && mpViewShell) ?  mpParentWindow.get() : pParent );
973         if( mpViewShell )
974         {
975             mpViewShell->SetActiveWindow( mpShowWindow );
976             mpShowWindow->SetViewShell (mpViewShell);
977             mpViewShell->ShowUIControls (false);
978         }
979 
980         if( mpView )
981         {
982             mpView->AddDeviceToPaintView( *mpShowWindow->GetOutDev(), nullptr );
983             mpView->SetAnimationPause( true );
984         }
985 
986         // call resize handler
987         if( pParent )
988         {
989             maPresSize = pParent->GetSizePixel();
990         }
991         else if( mpViewShell )
992         {
993             ::tools::Rectangle aContentRect (mpViewShell->GetViewShellBase().getClientRectangle());
994             if (AllSettings::GetLayoutRTL())
995             {
996                 aContentRect.SetLeft( aContentRect.Right() );
997                 aContentRect.AdjustRight(aContentRect.Right() );
998             }
999             maPresSize = aContentRect.GetSize();
1000             mpShowWindow->SetPosPixel( aContentRect.TopLeft() );
1001         }
1002         else
1003         {
1004             OSL_FAIL("sd::SlideshowImpl::startPreview(), I need either a parent window or a viewshell!");
1005         }
1006         resize( maPresSize );
1007 
1008         sal_Int32 nPropertyCount = 1;
1009         if( mxPreviewAnimationNode.is() )
1010             nPropertyCount++;
1011 
1012         Sequence< beans::PropertyValue > aProperties(nPropertyCount);
1013         auto pProperties = aProperties.getArray();
1014         pProperties[0].Name = "AutomaticAdvancement";
1015         pProperties[0].Value <<= 1.0; // one second timeout
1016 
1017         if( mxPreviewAnimationNode.is() )
1018         {
1019             pProperties[1].Name = "NoSlideTransitions";
1020             pProperties[1].Value <<= true;
1021         }
1022 
1023         bRet = startShowImpl( aProperties );
1024 
1025         if( mpShowWindow != nullptr && meAnimationMode == ANIMATIONMODE_PREVIEW )
1026             mpShowWindow->SetPreviewMode();
1027 
1028     }
1029     catch( Exception& )
1030     {
1031         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startPreview()" );
1032         bRet = false;
1033     }
1034 
1035     return bRet;
1036 }
1037 
startShow(PresentationSettingsEx const * pPresSettings)1038 bool SlideshowImpl::startShow( PresentationSettingsEx const * pPresSettings )
1039 {
1040     const rtl::Reference<SlideshowImpl> xKeepAlive(this);
1041 
1042     DBG_ASSERT( !mxShow.is(), "sd::SlideshowImpl::startShow(), called twice!" );
1043     if( mxShow.is() )
1044         return true;
1045     DBG_ASSERT( mpParentWindow!=nullptr, "sd::SlideshowImpl::startShow() called without parent window" );
1046     if (mpParentWindow == nullptr)
1047         return false;
1048 
1049     // Autoplay (pps/ppsx)
1050     if (mpViewShell->GetDoc()->GetStartWithPresentation())
1051     {
1052         mpViewShell->GetDoc()->SetExitAfterPresenting(true);
1053     }
1054 
1055     bool bRet = false;
1056 
1057     try
1058     {
1059         if( pPresSettings )
1060         {
1061             maPresSettings = *pPresSettings;
1062             mbRehearseTimings = pPresSettings->mbRehearseTimings;
1063         }
1064 
1065         OUString  aPresSlide( maPresSettings.maPresPage );
1066         SdPage* pStartPage = mpViewShell->GetActualPage();
1067         bool    bStartWithActualSlide =  pStartPage;
1068 
1069         // times should be measured?
1070         if( mbRehearseTimings )
1071         {
1072             maPresSettings.mbEndless = false;
1073             maPresSettings.mbManual = true;
1074             maPresSettings.mbMouseVisible = true;
1075             maPresSettings.mbMouseAsPen = false;
1076             maPresSettings.mnPauseTimeout = 0;
1077             maPresSettings.mbShowPauseLogo = false;
1078         }
1079 
1080         if( pStartPage )
1081         {
1082             if( pStartPage->GetPageKind() == PageKind::Notes )
1083             {
1084                 // we are in notes page mode, so get
1085                 // the corresponding draw page
1086                 const sal_uInt16 nPgNum = ( pStartPage->GetPageNum() - 2 ) >> 1;
1087                 pStartPage = mpDoc->GetSdPage( nPgNum, PageKind::Standard );
1088             }
1089         }
1090 
1091         if( bStartWithActualSlide )
1092         {
1093             if ( aPresSlide.isEmpty())
1094             {
1095                 // no preset slide yet, so pick current on one
1096                 aPresSlide = pStartPage->GetName();
1097                 // if the starting slide is hidden, we can't set slide controller to ALL mode
1098                 maPresSettings.mbAll = !pStartPage->IsExcluded();
1099             }
1100 
1101             if( meAnimationMode != ANIMATIONMODE_SHOW )
1102             {
1103                 if( pStartPage->GetPageKind() == PageKind::Standard )
1104                 {
1105                     maPresSettings.mbAll = false;
1106                 }
1107             }
1108         }
1109 
1110         // build page list
1111         createSlideList( maPresSettings.mbAll, aPresSlide );
1112 
1113         // remember Slide number from where the show was started
1114         if( pStartPage )
1115             mnRestoreSlide = ( pStartPage->GetPageNum() - 1 ) / 2;
1116 
1117         if( mpSlideController->hasSlides() )
1118         {
1119             // hide child windows
1120             hideChildWindows();
1121 
1122             mpShowWindow = VclPtr<ShowWindow>::Create( this, mpParentWindow );
1123             mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
1124             mpViewShell->SetActiveWindow( mpShowWindow );
1125             mpShowWindow->SetViewShell (mpViewShell);
1126             mpViewShell->GetViewShellBase().ShowUIControls (false);
1127             // Hide the side panes for in-place presentations.
1128             if ( ! maPresSettings.mbFullScreen)
1129                 mpPaneHider.reset(new PaneHider(*mpViewShell,this));
1130 
1131             // these Slots are forbidden in other views for this document
1132             if( mpDocSh && pPresSettings && !pPresSettings->mbInteractive) // IASS
1133             {
1134                 mpDocSh->SetSlotFilter( true, pAllowed );
1135                 mpDocSh->ApplySlotFilter();
1136             }
1137 
1138             Help::DisableContextHelp();
1139             Help::DisableExtHelp();
1140 
1141             if( maPresSettings.mbFullScreen )
1142             {
1143 #if HAVE_FEATURE_SCRIPTING
1144                 // disable basic ide error handling
1145                 maStarBASICGlobalErrorHdl = StarBASIC::GetGlobalErrorHdl();
1146                 StarBASIC::SetGlobalErrorHdl( Link<StarBASIC*,bool>() );
1147 #endif
1148             }
1149 
1150             // call resize handler
1151             maPresSize = mpParentWindow->GetSizePixel();
1152             if (!maPresSettings.mbFullScreen)
1153             {
1154                 const ::tools::Rectangle& aClientRect = mpViewShell->GetViewShellBase().getClientRectangle();
1155                 maPresSize = aClientRect.GetSize();
1156                 mpShowWindow->SetPosPixel( aClientRect.TopLeft() );
1157                 resize( maPresSize );
1158             }
1159 
1160             // #i41824#
1161             // Note: In FullScreen Mode the OS (window manager) sends a resize to
1162             // the WorkWindow once it actually resized it to full size.  The
1163             // WorkWindow propagates the resize to the DrawViewShell which calls
1164             // resize() at the SlideShow (this).  Calling resize here results in a
1165             // temporary display of a black window in the window's default size
1166 
1167             if( mpView )
1168             {
1169                 mpView->AddDeviceToPaintView( *mpShowWindow->GetOutDev(), nullptr );
1170                 mpView->SetAnimationPause( true );
1171             }
1172 
1173             SfxBindings* pBindings = getBindings();
1174             if( pBindings )
1175             {
1176                 pBindings->Invalidate( SID_PRESENTATION );
1177                 pBindings->Invalidate( SID_REHEARSE_TIMINGS );
1178             }
1179 
1180             // Defer the sd::ShowWindow's GrabFocus to SlideShow::activate. so that the accessible event can be fired correctly.
1181             //mpShowWindow->GrabFocus();
1182 
1183             std::vector<beans::PropertyValue> aProperties;
1184             aProperties.reserve( 4 );
1185 
1186             aProperties.emplace_back( "AdvanceOnClick" ,
1187                     -1, Any( !maPresSettings.mbLockedPages ),
1188                     beans::PropertyState_DIRECT_VALUE );
1189 
1190             aProperties.emplace_back( "ImageAnimationsAllowed" ,
1191                     -1, Any( maPresSettings.mbAnimationAllowed ),
1192                     beans::PropertyState_DIRECT_VALUE );
1193 
1194             const bool bZOrderEnabled(
1195                 SD_MOD()->GetSdOptions( mpDoc->GetDocumentType() )->IsSlideshowRespectZOrder() );
1196             aProperties.emplace_back( "DisableAnimationZOrder" ,
1197                     -1, Any( !bZOrderEnabled ),
1198                     beans::PropertyState_DIRECT_VALUE );
1199 
1200             aProperties.emplace_back( "ForceManualAdvance" ,
1201                     -1, Any( maPresSettings.mbManual ),
1202                     beans::PropertyState_DIRECT_VALUE );
1203 
1204             if( mbUsePen )
1205             {
1206                 aProperties.emplace_back( "UserPaintColor" ,
1207                         // User paint color is black by default.
1208                         -1, Any( mnUserPaintColor ),
1209                         beans::PropertyState_DIRECT_VALUE );
1210 
1211                 aProperties.emplace_back( "UserPaintStrokeWidth" ,
1212                         // User paint color is black by default.
1213                         -1, Any( mdUserPaintStrokeWidth ),
1214                         beans::PropertyState_DIRECT_VALUE );
1215             }
1216 
1217             if (mbRehearseTimings) {
1218                 aProperties.emplace_back( "RehearseTimings" ,
1219                         -1, Any(true), beans::PropertyState_DIRECT_VALUE );
1220             }
1221 
1222             bRet = startShowImpl( Sequence<beans::PropertyValue>(
1223                                       aProperties.data(), aProperties.size() ) );
1224 
1225         }
1226 
1227         setActiveXToolbarsVisible( false );
1228     }
1229     catch (const Exception&)
1230     {
1231         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShow()" );
1232         bRet = false;
1233     }
1234 
1235     return bRet;
1236 }
1237 
startShowImpl(const Sequence<beans::PropertyValue> & aProperties)1238 bool SlideshowImpl::startShowImpl( const Sequence< beans::PropertyValue >& aProperties )
1239 {
1240     try
1241     {
1242         mxShow.set( createSlideShow(), UNO_SET_THROW );
1243 
1244         mxView = new SlideShowView(
1245                                              *mpShowWindow,
1246                                              mpDoc,
1247                                              meAnimationMode,
1248                                              this,
1249                                              maPresSettings.mbFullScreen);
1250 
1251         // try add wait symbol to properties:
1252         const Reference<rendering::XSpriteCanvas> xSpriteCanvas(
1253             mxView->getCanvas() );
1254         if (xSpriteCanvas.is())
1255         {
1256             BitmapEx waitSymbolBitmap(BMP_WAIT_ICON);
1257             const Reference<rendering::XBitmap> xBitmap(
1258                 vcl::unotools::xBitmapFromBitmapEx( waitSymbolBitmap ) );
1259             if (xBitmap.is())
1260             {
1261                 mxShow->setProperty(
1262                     beans::PropertyValue( u"WaitSymbolBitmap"_ustr ,
1263                         -1,
1264                         Any( xBitmap ),
1265                         beans::PropertyState_DIRECT_VALUE ) );
1266             }
1267 
1268             BitmapEx pointerSymbolBitmap(BMP_POINTER_ICON);
1269             const Reference<rendering::XBitmap> xPointerBitmap(
1270                 vcl::unotools::xBitmapFromBitmapEx( pointerSymbolBitmap ) );
1271             if (xPointerBitmap.is())
1272             {
1273                 mxShow->setProperty(
1274                     beans::PropertyValue( u"PointerSymbolBitmap"_ustr ,
1275                         -1,
1276                         Any( xPointerBitmap ),
1277                         beans::PropertyState_DIRECT_VALUE ) );
1278             }
1279             if (officecfg::Office::Impress::Misc::Start::ShowNavigationPanel::get())
1280             {
1281                 NavbarButtonSize btnScale = static_cast<NavbarButtonSize>(officecfg::Office::Impress::Layout::Display::NavigationBtnScale::get());
1282                 OUString prevSlidePath = u""_ustr;
1283                 OUString nextSlidePath = u""_ustr;
1284                 OUString menuPath = u""_ustr;
1285                 switch (btnScale)
1286                 {
1287                     case NavbarButtonSize::Large:
1288                     {
1289                         prevSlidePath = BMP_PREV_SLIDE_LARGE;
1290                         nextSlidePath = BMP_NEXT_SLIDE_LARGE;
1291                         menuPath = BMP_MENU_SLIDE_LARGE;
1292                         break;
1293                     }
1294                     case NavbarButtonSize::XLarge:
1295                     {
1296                         prevSlidePath = BMP_PREV_SLIDE_EXTRALARGE;
1297                         nextSlidePath = BMP_NEXT_SLIDE_EXTRALARGE;
1298                         menuPath = BMP_MENU_SLIDE_EXTRALARGE;
1299                         break;
1300                     }
1301                     case NavbarButtonSize::Auto:
1302                     case NavbarButtonSize::Small:
1303                     default:
1304                     {
1305                         prevSlidePath = BMP_PREV_SLIDE_SMALL;
1306                         nextSlidePath = BMP_NEXT_SLIDE_SMALL;
1307                         menuPath = BMP_MENU_SLIDE_SMALL;
1308                         break;
1309                     }
1310                 }
1311                 BitmapEx prevSlideBm(prevSlidePath);
1312                 const Reference<rendering::XBitmap> xPrevSBitmap(
1313                     vcl::unotools::xBitmapFromBitmapEx(prevSlideBm));
1314                 if (xPrevSBitmap.is())
1315                 {
1316                     mxShow->setProperty(beans::PropertyValue(u"NavigationSlidePrev"_ustr, -1,
1317                                                              Any(xPrevSBitmap),
1318                                                              beans::PropertyState_DIRECT_VALUE));
1319                 }
1320                 BitmapEx menuSlideBm(menuPath);
1321                 const Reference<rendering::XBitmap> xMenuSBitmap(
1322                     vcl::unotools::xBitmapFromBitmapEx(menuSlideBm));
1323                 if (xMenuSBitmap.is())
1324                 {
1325                     mxShow->setProperty(beans::PropertyValue(u"NavigationSlideMenu"_ustr, -1,
1326                                                              Any(xMenuSBitmap),
1327                                                              beans::PropertyState_DIRECT_VALUE));
1328                 }
1329                 BitmapEx nextSlideBm(nextSlidePath);
1330                 const Reference<rendering::XBitmap> xNextSBitmap(
1331                     vcl::unotools::xBitmapFromBitmapEx(nextSlideBm));
1332                 if (xNextSBitmap.is())
1333                 {
1334                     mxShow->setProperty(beans::PropertyValue(u"NavigationSlideNext"_ustr, -1,
1335                                                              Any(xNextSBitmap),
1336                                                              beans::PropertyState_DIRECT_VALUE));
1337                 }
1338             }
1339         }
1340 
1341         for( const auto& rProp : aProperties )
1342             mxShow->setProperty( rProp );
1343 
1344         mxShow->addView( mxView );
1345 
1346         mxListenerProxy.set( new SlideShowListenerProxy( this, mxShow ) );
1347         mxListenerProxy->addAsSlideShowListener();
1348 
1349         // IASS: Do only startup the PresenterConsole if this is not
1350         // the SlideShow Preview mode (else would be double)
1351         if (!mbInterActiveSetup)
1352         {
1353             // IASS: This is the central methodology to 'steer' the
1354             // PresenterConsole - in this case, to start it up and make
1355             // it visible (if activated)
1356             NotifyDocumentEvent(
1357                 *mpDoc,
1358                 u"OnStartPresentation"_ustr);
1359         }
1360 
1361         displaySlideIndex( mpSlideController->getStartSlideIndex() );
1362 
1363         return true;
1364     }
1365     catch( Exception& )
1366     {
1367         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShowImpl()" );
1368         return false;
1369     }
1370 }
1371 
1372 /** called only by the slideshow view when the first paint event occurs.
1373     This actually starts the slideshow. */
onFirstPaint()1374 void SlideshowImpl::onFirstPaint()
1375 {
1376     if( mpShowWindow )
1377     {
1378         /*
1379         mpShowWindow->SetBackground( Wallpaper( COL_BLACK ) );
1380         mpShowWindow->Erase();
1381         mpShowWindow->SetBackground();
1382         */
1383     }
1384 
1385     SolarMutexGuard aSolarGuard;
1386     maUpdateTimer.SetTimeout( sal_uLong(100) );
1387     maUpdateTimer.Start();
1388 }
1389 
paint()1390 void SlideshowImpl::paint()
1391 {
1392     if( mxView.is() ) try
1393     {
1394         awt::PaintEvent aEvt;
1395         // aEvt.UpdateRect = TODO
1396         mxView->paint( aEvt );
1397     }
1398     catch( Exception& )
1399     {
1400         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::paint()" );
1401     }
1402 }
1403 
addSlideShowListener(const Reference<XSlideShowListener> & xListener)1404 void SAL_CALL SlideshowImpl::addSlideShowListener( const Reference< XSlideShowListener >& xListener )
1405 {
1406     if( mxListenerProxy.is() )
1407         mxListenerProxy->addSlideShowListener( xListener );
1408 }
1409 
removeSlideShowListener(const Reference<XSlideShowListener> & xListener)1410 void SAL_CALL SlideshowImpl::removeSlideShowListener( const Reference< XSlideShowListener >& xListener )
1411 {
1412     if( mxListenerProxy.is() )
1413         mxListenerProxy->removeSlideShowListener( xListener );
1414 }
1415 
slideEnded(const bool bReverse)1416 void SlideshowImpl::slideEnded(const bool bReverse)
1417 {
1418     if (bReverse)
1419         gotoPreviousSlide(true);
1420     else
1421         gotoNextSlide();
1422 }
1423 
swipe(const CommandGestureSwipeData & rSwipeData)1424 bool SlideshowImpl::swipe(const CommandGestureSwipeData &rSwipeData)
1425 {
1426     if (mbUsePen || mnContextMenuEvent)
1427         return false;
1428     double nVelocityX = rSwipeData.getVelocityX();
1429     // tdf#108475 make it swipe only if some reasonable movement was involved
1430     if (fabs(nVelocityX) < 50)
1431         return false;
1432     if (nVelocityX > 0)
1433     {
1434         gotoPreviousSlide();
1435     }
1436     else
1437     {
1438         gotoNextEffect();
1439     }
1440     //a swipe is followed by a mouse up, tell the view to ignore that mouse up as we've reacted
1441     //to the swipe instead
1442     mxView->ignoreNextMouseReleased();
1443     return true;
1444 }
1445 
longpress(const CommandGestureLongPressData & rLongPressData)1446 bool SlideshowImpl::longpress(const CommandGestureLongPressData &rLongPressData)
1447 {
1448     if (mnContextMenuEvent)
1449         return false;
1450 
1451     maPopupMousePos = Point(rLongPressData.getX(), rLongPressData.getY());
1452     mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
1453 
1454     return true;
1455 }
1456 
removeShapeEvents()1457 void SlideshowImpl::removeShapeEvents()
1458 {
1459     if( !(mxShow.is() && mxListenerProxy.is()) )
1460         return;
1461 
1462     try
1463     {
1464         for( const auto& rEntry : maShapeEventMap )
1465         {
1466             mxListenerProxy->removeShapeEventListener( rEntry.first );
1467             mxShow->setShapeCursor( rEntry.first, awt::SystemPointer::ARROW );
1468         }
1469 
1470         maShapeEventMap.clear();
1471     }
1472     catch( Exception& )
1473     {
1474         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::removeShapeEvents()" );
1475     }
1476 }
1477 
registerShapeEvents(sal_Int32 nSlideNumber)1478 void SlideshowImpl::registerShapeEvents(sal_Int32 nSlideNumber)
1479 {
1480     if( nSlideNumber < 0 )
1481         return;
1482 
1483     try
1484     {
1485         Reference< XDrawPagesSupplier > xDrawPages( mxModel, UNO_QUERY_THROW );
1486         Reference< XIndexAccess > xPages( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
1487 
1488         Reference< XShapes > xDrawPage;
1489         xPages->getByIndex(nSlideNumber) >>= xDrawPage;
1490 
1491         if( xDrawPage.is() )
1492         {
1493             Reference< XMasterPageTarget > xMasterPageTarget( xDrawPage, UNO_QUERY );
1494             if( xMasterPageTarget.is() )
1495             {
1496                 Reference< XShapes > xMasterPage = xMasterPageTarget->getMasterPage();
1497                 if( xMasterPage.is() )
1498                     registerShapeEvents( xMasterPage );
1499             }
1500             registerShapeEvents( xDrawPage );
1501         }
1502     }
1503     catch( Exception& )
1504     {
1505         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
1506     }
1507 }
1508 
registerShapeEvents(Reference<XShapes> const & xShapes)1509 void SlideshowImpl::registerShapeEvents( Reference< XShapes > const & xShapes )
1510 {
1511     try
1512     {
1513         const sal_Int32 nShapeCount = xShapes->getCount();
1514         sal_Int32 nShape;
1515         for( nShape = 0; nShape < nShapeCount; nShape++ )
1516         {
1517             Reference< XShape > xShape;
1518             xShapes->getByIndex( nShape ) >>= xShape;
1519 
1520             if( xShape.is() && xShape->getShapeType() == "com.sun.star.drawing.GroupShape" )
1521             {
1522                 Reference< XShapes > xSubShapes( xShape, UNO_QUERY );
1523                 if( xSubShapes.is() )
1524                     registerShapeEvents( xSubShapes );
1525             }
1526 
1527             Reference< XPropertySet > xSet( xShape, UNO_QUERY );
1528             if( !xSet.is() )
1529                 continue;
1530 
1531             Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1532             if( !xSetInfo.is() || !xSetInfo->hasPropertyByName( gsOnClick ) )
1533                 continue;
1534 
1535             WrappedShapeEventImplPtr pEvent = std::make_shared<WrappedShapeEventImpl>();
1536             xSet->getPropertyValue( gsOnClick ) >>= pEvent->meClickAction;
1537 
1538             switch( pEvent->meClickAction )
1539             {
1540             case ClickAction_PREVPAGE:
1541             case ClickAction_NEXTPAGE:
1542             case ClickAction_FIRSTPAGE:
1543             case ClickAction_LASTPAGE:
1544             case ClickAction_STOPPRESENTATION:
1545                 break;
1546             case ClickAction_BOOKMARK:
1547                 if( xSetInfo->hasPropertyByName( gsBookmark ) )
1548                     xSet->getPropertyValue( gsBookmark ) >>= pEvent->maStrBookmark;
1549                 if( getSlideNumberForBookmark( pEvent->maStrBookmark ) == -1 )
1550                     continue;
1551                 break;
1552             case ClickAction_DOCUMENT:
1553             case ClickAction_SOUND:
1554             case ClickAction_PROGRAM:
1555             case ClickAction_MACRO:
1556                 if( xSetInfo->hasPropertyByName( gsBookmark ) )
1557                     xSet->getPropertyValue( gsBookmark ) >>= pEvent->maStrBookmark;
1558                 break;
1559             case ClickAction_VERB:
1560                 if( xSetInfo->hasPropertyByName( gsVerb ) )
1561                     xSet->getPropertyValue( gsVerb ) >>= pEvent->mnVerb;
1562                 break;
1563             default:
1564                 continue; // skip all others
1565             }
1566 
1567             maShapeEventMap[ xShape ] = pEvent;
1568 
1569             if( mxListenerProxy.is() )
1570                 mxListenerProxy->addShapeEventListener( xShape );
1571             mxShow->setShapeCursor( xShape, awt::SystemPointer::REFHAND );
1572         }
1573     }
1574     catch( Exception& )
1575     {
1576         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
1577     }
1578 }
1579 
displayCurrentSlide(const bool bSkipAllMainSequenceEffects)1580 void SlideshowImpl::displayCurrentSlide (const bool bSkipAllMainSequenceEffects)
1581 {
1582     stopSound();
1583     removeShapeEvents();
1584 
1585     if( mpSlideController && mxShow.is() )
1586     {
1587         Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(),
1588                                                     UNO_QUERY_THROW );
1589         mpSlideController->displayCurrentSlide( mxShow, xDrawPages, bSkipAllMainSequenceEffects );
1590         registerShapeEvents(mpSlideController->getCurrentSlideNumber());
1591         update();
1592 
1593     }
1594     // send out page change event and notify to update all acc info for current page
1595     if (mpViewShell)
1596     {
1597         sal_Int32 currentPageIndex = getCurrentSlideIndex();
1598         mpViewShell->fireSwitchCurrentPage(currentPageIndex);
1599         mpViewShell->NotifyAccUpdate();
1600     }
1601 }
1602 
endPresentation()1603 void SlideshowImpl::endPresentation()
1604 {
1605     if( maPresSettings.mbMouseAsPen)
1606     {
1607         Reference< XMultiServiceFactory > xDocFactory(mpDoc->getUnoModel(), UNO_QUERY );
1608         if( xDocFactory.is() )
1609             mxShow->registerUserPaintPolygons(xDocFactory);
1610     }
1611 
1612     if( !mnEndShowEvent )
1613         mnEndShowEvent = Application::PostUserEvent( LINK(this, SlideshowImpl, endPresentationHdl) );
1614 }
1615 
IMPL_LINK_NOARG(SlideshowImpl,endPresentationHdl,void *,void)1616 IMPL_LINK_NOARG(SlideshowImpl, endPresentationHdl, void*, void)
1617 {
1618     mnEndShowEvent = nullptr;
1619 
1620     stopSound();
1621 
1622     if( mxPresentation.is() )
1623         mxPresentation->end();
1624 }
1625 
pause()1626 void SAL_CALL SlideshowImpl::pause()
1627 {
1628     SolarMutexGuard aSolarGuard;
1629 
1630     if( mbIsPaused )
1631         return;
1632 
1633     try
1634     {
1635         mbIsPaused = true;
1636         if( mxShow.is() )
1637         {
1638             mxShow->pause(true);
1639 
1640             if( mxListenerProxy.is() )
1641                 mxListenerProxy->paused();
1642         }
1643     }
1644     catch( Exception& )
1645     {
1646         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::pause()" );
1647     }
1648 }
1649 
resume()1650 void SAL_CALL SlideshowImpl::resume()
1651 {
1652     SolarMutexGuard aSolarGuard;
1653 
1654     if( mbIsPaused ) try
1655     {
1656         if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK || mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
1657         {
1658             mpShowWindow->RestartShow();
1659         }
1660         else
1661         {
1662             mbIsPaused = false;
1663             if( mxShow.is() )
1664             {
1665                 mxShow->pause(false);
1666                 update();
1667 
1668                 if( mxListenerProxy.is() )
1669                     mxListenerProxy->resumed();
1670             }
1671         }
1672     }
1673     catch( Exception& )
1674     {
1675         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resume()" );
1676     }
1677 #ifdef ENABLE_SDREMOTE
1678     RemoteServer::presentationStarted( this );
1679 #endif
1680 }
1681 
isPaused()1682 sal_Bool SAL_CALL SlideshowImpl::isPaused()
1683 {
1684     SolarMutexGuard aSolarGuard;
1685     return mbIsPaused;
1686 }
1687 
blankScreen(sal_Int32 nColor)1688 void SAL_CALL SlideshowImpl::blankScreen( sal_Int32 nColor )
1689 {
1690     SolarMutexGuard aSolarGuard;
1691 
1692     if( mpShowWindow && mpSlideController )
1693     {
1694         if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), Color(ColorTransparency, nColor) ) )
1695         {
1696             pause();
1697         }
1698     }
1699 }
1700 
1701 // XShapeEventListener
1702 
click(const Reference<XShape> & xShape)1703 void SlideshowImpl::click( const Reference< XShape >& xShape )
1704 {
1705     SolarMutexGuard aSolarGuard;
1706 
1707     WrappedShapeEventImplPtr pEvent = maShapeEventMap[xShape];
1708     if( !pEvent )
1709         return;
1710 
1711     switch( pEvent->meClickAction )
1712     {
1713     case ClickAction_PREVPAGE:          gotoPreviousSlide();        break;
1714     case ClickAction_NEXTPAGE:          gotoNextSlide();            break;
1715     case ClickAction_FIRSTPAGE:         gotoFirstSlide();           break;
1716     case ClickAction_LASTPAGE:          gotoLastSlide();            break;
1717     case ClickAction_STOPPRESENTATION:  endPresentation();          break;
1718     case ClickAction_BOOKMARK:
1719     {
1720         gotoBookmark( pEvent->maStrBookmark );
1721     }
1722     break;
1723     case ClickAction_SOUND:
1724     {
1725 #if HAVE_FEATURE_AVMEDIA
1726         try
1727         {
1728             mxPlayer.set(avmedia::MediaWindow::createPlayer(pEvent->maStrBookmark, u""_ustr/*TODO?*/), uno::UNO_SET_THROW );
1729             mxPlayer->start();
1730         }
1731         catch( uno::Exception& )
1732         {
1733             TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::click()" );
1734         }
1735 #endif
1736     }
1737     break;
1738 
1739     case ClickAction_DOCUMENT:
1740     {
1741         OUString aBookmark( pEvent->maStrBookmark );
1742 
1743         sal_Int32 nPos = aBookmark.indexOf( '#' );
1744         if( nPos >= 0 )
1745         {
1746             OUString aURL( aBookmark.copy( 0, nPos+1 ) );
1747             OUString aName( aBookmark.copy( nPos+1 ) );
1748             aURL += getUiNameFromPageApiNameImpl( aName );
1749             aBookmark = aURL;
1750         }
1751 
1752         mpDocSh->OpenBookmark( aBookmark );
1753     }
1754     break;
1755 
1756     case ClickAction_PROGRAM:
1757     {
1758         INetURLObject aURL(
1759             ::URIHelper::SmartRel2Abs(
1760                 INetURLObject(mpDocSh->GetMedium()->GetBaseURL()),
1761                 pEvent->maStrBookmark, ::URIHelper::GetMaybeFileHdl(), true,
1762                 false, INetURLObject::EncodeMechanism::WasEncoded,
1763                 INetURLObject::DecodeMechanism::Unambiguous ) );
1764 
1765         if( INetProtocol::File == aURL.GetProtocol() )
1766         {
1767             SfxStringItem aUrl( SID_FILE_NAME, aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1768             SfxBoolItem aBrowsing( SID_BROWSE, true );
1769 
1770             if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
1771             {
1772                 SfxUnoFrameItem aDocFrame(SID_FILLFRAME, pViewFrm->GetFrame().GetFrameInterface());
1773                 pViewFrm->GetDispatcher()->ExecuteList( SID_OPENDOC,
1774                     SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
1775                     { &aUrl, &aBrowsing }, { &aDocFrame } );
1776             }
1777         }
1778     }
1779     break;
1780 
1781 #if HAVE_FEATURE_SCRIPTING
1782     case presentation::ClickAction_MACRO:
1783     {
1784         const OUString aMacro( pEvent->maStrBookmark );
1785 
1786         if ( SfxApplication::IsXScriptURL( aMacro ) )
1787         {
1788             Any aRet;
1789             Sequence< sal_Int16 > aOutArgsIndex;
1790             Sequence< Any > aOutArgs;
1791             Sequence< Any >* pInArgs = new Sequence< Any >(0);
1792             mpDocSh->CallXScript( aMacro, *pInArgs, aRet, aOutArgsIndex, aOutArgs);
1793         }
1794         else
1795         {
1796             // aMacro has the following syntax:
1797             // "Macroname.Modulname.Libname.Documentname" or
1798             // "Macroname.Modulname.Libname.Applicationname"
1799             sal_Int32 nIdx{ 0 };
1800             const std::u16string_view aMacroName = o3tl::getToken(aMacro, 0, '.', nIdx);
1801             const std::u16string_view aModulName = o3tl::getToken(aMacro, 0, '.', nIdx);
1802 
1803             // todo: is the limitation still given that only
1804             // Modulname+Macroname can be used here?
1805             OUString aExecMacro = OUString::Concat(aModulName) + "." + aMacroName;
1806             mpDocSh->GetBasic()->Call(aExecMacro);
1807         }
1808     }
1809     break;
1810 #endif
1811 
1812     case ClickAction_VERB:
1813     {
1814         // todo, better do it async?
1815         SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
1816         SdrOle2Obj* pOleObject = dynamic_cast< SdrOle2Obj* >(pObj);
1817         if (pOleObject && mpViewShell )
1818             mpViewShell->ActivateObject(pOleObject, pEvent->mnVerb);
1819     }
1820     break;
1821     default:
1822         break;
1823     }
1824 }
1825 
getSlideNumberForBookmark(const OUString & rStrBookmark)1826 sal_Int32 SlideshowImpl::getSlideNumberForBookmark( const OUString& rStrBookmark )
1827 {
1828     bool bIsMasterPage;
1829     OUString aBookmark = getUiNameFromPageApiNameImpl( rStrBookmark );
1830     sal_uInt16 nPgNum = mpDoc->GetPageByName( aBookmark, bIsMasterPage );
1831 
1832     if( nPgNum == SDRPAGE_NOTFOUND )
1833     {
1834         // Is the bookmark an object?
1835         SdrObject* pObj = mpDoc->GetObj( aBookmark );
1836 
1837         if( pObj )
1838         {
1839             nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
1840             bIsMasterPage = pObj->getSdrPageFromSdrObject()->IsMasterPage();
1841         }
1842     }
1843 
1844     if( (nPgNum == SDRPAGE_NOTFOUND) || bIsMasterPage || static_cast<SdPage*>(mpDoc->GetPage(nPgNum))->GetPageKind() != PageKind::Standard )
1845         return -1;
1846 
1847     return ( nPgNum - 1) >> 1;
1848 }
1849 
contextMenuShow(const css::awt::Point & point)1850 void SlideshowImpl::contextMenuShow(const css::awt::Point& point)
1851 {
1852     maPopupMousePos = { point.X, point.Y };
1853     mnContextMenuEvent = Application::PostUserEvent(LINK(this, SlideshowImpl, ContextMenuHdl));
1854 }
1855 
hyperLinkClicked(OUString const & aHyperLink)1856 void SlideshowImpl::hyperLinkClicked( OUString const& aHyperLink )
1857 {
1858     OUString aBookmark( aHyperLink );
1859 
1860     sal_Int32 nPos = aBookmark.indexOf( '#' );
1861     if( nPos >= 0 )
1862     {
1863         OUString aURL( aBookmark.copy( 0, nPos+1 ) );
1864         OUString aName( aBookmark.copy( nPos+1 ) );
1865         aURL += getUiNameFromPageApiNameImpl( aName );
1866         aBookmark = aURL;
1867     }
1868 
1869     mpDocSh->OpenBookmark( aBookmark );
1870 }
1871 
displaySlideNumber(sal_Int32 nSlideNumber)1872 void SlideshowImpl::displaySlideNumber( sal_Int32 nSlideNumber )
1873 {
1874     if( mpSlideController )
1875     {
1876         if( mpSlideController->jumpToSlideNumber( nSlideNumber ) )
1877         {
1878             displayCurrentSlide();
1879         }
1880     }
1881 }
1882 
1883 /** nSlideIndex == -1 displays current slide again */
displaySlideIndex(sal_Int32 nSlideIndex)1884 void SlideshowImpl::displaySlideIndex( sal_Int32 nSlideIndex )
1885 {
1886     if( mpSlideController )
1887     {
1888         if( (nSlideIndex == -1) || mpSlideController->jumpToSlideIndex( nSlideIndex ) )
1889         {
1890             displayCurrentSlide();
1891         }
1892     }
1893 }
1894 
jumpToBookmark(const OUString & sBookmark)1895 void SlideshowImpl::jumpToBookmark( const OUString& sBookmark )
1896 {
1897     sal_Int32 nSlideNumber = getSlideNumberForBookmark( sBookmark );
1898     if( nSlideNumber != -1 )
1899         displaySlideNumber( nSlideNumber );
1900 }
1901 
getCurrentSlideNumber() const1902 sal_Int32 SlideshowImpl::getCurrentSlideNumber() const
1903 {
1904     return mpSlideController ? mpSlideController->getCurrentSlideNumber() : -1;
1905 }
1906 
isEndless()1907 sal_Bool SAL_CALL SlideshowImpl::isEndless()
1908 {
1909     SolarMutexGuard aSolarGuard;
1910     return maPresSettings.mbEndless;
1911 }
1912 
update()1913 void SlideshowImpl::update()
1914 {
1915     startUpdateTimer();
1916 }
1917 
startUpdateTimer()1918 void SlideshowImpl::startUpdateTimer()
1919 {
1920     SolarMutexGuard aSolarGuard;
1921     maUpdateTimer.SetTimeout( 0 );
1922     maUpdateTimer.Start();
1923 }
1924 
1925 /** this timer is called 20ms after a new slide was displayed.
1926     This is used to unfreeze user input that was disabled after
1927     slide change to skip input that was buffered during slide
1928     transition preparation */
IMPL_LINK_NOARG(SlideshowImpl,ReadyForNextInputHdl,Timer *,void)1929 IMPL_LINK_NOARG(SlideshowImpl, ReadyForNextInputHdl, Timer *, void)
1930 {
1931     mbInputFreeze = false;
1932 }
1933 
1934 /** if I catch someone someday who calls this method by hand
1935     and not by using the timer, I will personally punish this
1936     person seriously, even if this person is me.
1937 */
IMPL_LINK_NOARG(SlideshowImpl,updateHdl,Timer *,void)1938 IMPL_LINK_NOARG(SlideshowImpl, updateHdl, Timer *, void)
1939 {
1940     updateSlideShow();
1941 }
1942 
updateSlideShow()1943 void SlideshowImpl::updateSlideShow()
1944 {
1945     // prevent me from deletion when recursing (App::EnableYieldMode does)
1946     const rtl::Reference<SlideshowImpl> xKeepAlive(this);
1947 
1948     Reference< XSlideShow > xShow( mxShow );
1949     if ( ! xShow.is())
1950         return;
1951 
1952     try
1953     {
1954         double fUpdate = 0.0;
1955         if( !xShow->update(fUpdate) )
1956             fUpdate = -1.0;
1957 
1958         if (mxShow.is() && (fUpdate >= 0.0))
1959         {
1960             if (::basegfx::fTools::equalZero(fUpdate))
1961             {
1962                 // Make sure idle tasks don't starve when we don't have to wait.
1963                 // Don't process any events generated after invoking the function.
1964                 Application::Reschedule(/*bHandleAllCurrentEvents=*/true);
1965             }
1966             else
1967             {
1968                 // Avoid busy loop when the previous call to update()
1969                 // returns a small positive number but not 0 (which is
1970                 // handled above).  Also, make sure that calls to update()
1971                 // have a minimum frequency.
1972                 // => Allow up to 60 frames per second.  Call at least once
1973                 // every 4 seconds.
1974                 const static sal_Int32 nMaximumFrameCount (60);
1975                 const static double nMinimumTimeout (1.0 / nMaximumFrameCount);
1976                 const static double nMaximumTimeout (4.0);
1977                 fUpdate = std::clamp(fUpdate, nMinimumTimeout, nMaximumTimeout);
1978 
1979                 // Make sure that the maximum frame count has not been set
1980                 // too high (only then conversion to milliseconds and long
1981                 // integer may lead to zero value.)
1982                 OSL_ASSERT(static_cast<sal_uLong>(fUpdate * 1000.0) > 0);
1983             }
1984 
1985             // Use our high resolution timers for the asynchronous callback.
1986             maUpdateTimer.SetTimeout(static_cast<sal_uLong>(fUpdate * 1000.0));
1987             maUpdateTimer.Start();
1988         }
1989     }
1990     catch( Exception& )
1991     {
1992         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::updateSlideShow()" );
1993     }
1994 }
1995 
keyInput(const KeyEvent & rKEvt)1996 bool SlideshowImpl::keyInput(const KeyEvent& rKEvt)
1997 {
1998     if( !mxShow.is() || mbInputFreeze )
1999         return false;
2000 
2001     bool bRet = true;
2002 
2003     try
2004     {
2005         const int nKeyCode = rKEvt.GetKeyCode().GetCode();
2006         switch( nKeyCode )
2007         {
2008             case awt::Key::CONTEXTMENU:
2009                 if( !mnContextMenuEvent )
2010                 {
2011                     if( mpShowWindow )
2012                         maPopupMousePos = mpShowWindow->GetPointerState().maPos;
2013                     mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
2014                 }
2015                 break;
2016 
2017             // cancel show
2018             case KEY_ESCAPE:
2019             case KEY_SUBTRACT:
2020                 // in case the user cancels the presentation, switch to current slide
2021                 // in edit mode
2022                 if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
2023                 {
2024                     if( mpSlideController->getCurrentSlideNumber() != -1 )
2025                         mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
2026                 }
2027                 endPresentation();
2028                 break;
2029 
2030             // advance show
2031             case KEY_PAGEDOWN:
2032                 if(rKEvt.GetKeyCode().IsMod2())
2033                 {
2034                     gotoNextSlide();
2035                     break;
2036                 }
2037                 [[fallthrough]];
2038             case KEY_SPACE:
2039             case KEY_RIGHT:
2040             case KEY_DOWN:
2041             case KEY_XF86FORWARD:
2042                 gotoNextEffect();
2043                 break;
2044 
2045             case KEY_RETURN:
2046             {
2047                 if( !maCharBuffer.isEmpty() )
2048                 {
2049                     if( mpSlideController )
2050                     {
2051                         if( mpSlideController->jumpToSlideNumber( maCharBuffer.toInt32() - 1 ) )
2052                             displayCurrentSlide();
2053                     }
2054                     maCharBuffer.clear();
2055                 }
2056                 else
2057                 {
2058                     gotoNextEffect();
2059                 }
2060             }
2061             break;
2062 
2063             // numeric: add to buffer
2064             case KEY_0:
2065             case KEY_1:
2066             case KEY_2:
2067             case KEY_3:
2068             case KEY_4:
2069             case KEY_5:
2070             case KEY_6:
2071             case KEY_7:
2072             case KEY_8:
2073             case KEY_9:
2074                 maCharBuffer += OUStringChar( rKEvt.GetCharCode() );
2075                 break;
2076 
2077             case KEY_PAGEUP:
2078                 if(rKEvt.GetKeyCode().IsMod2())
2079                 {
2080                     gotoPreviousSlide();
2081                     break;
2082                 }
2083                 [[fallthrough]];
2084             case KEY_LEFT:
2085             case KEY_UP:
2086             case KEY_BACKSPACE:
2087             case KEY_XF86BACK:
2088                 gotoPreviousEffect();
2089                 break;
2090 
2091             case KEY_P:
2092                 setUsePen( !mbUsePen );
2093                 break;
2094 
2095             // tdf#149351 Ctrl+A disables pointer as pen mode
2096             case KEY_A:
2097                 if(rKEvt.GetKeyCode().IsMod1())
2098                 {
2099                     setUsePen( false );
2100                     break;
2101                 }
2102             break;
2103 
2104             case KEY_E:
2105                 setEraseAllInk( true );
2106                 updateSlideShow();
2107                 break;
2108 
2109             case KEY_HOME:
2110                 gotoFirstSlide();
2111                 break;
2112 
2113             case KEY_END:
2114                 gotoLastSlide();
2115                 break;
2116 
2117             case KEY_B:
2118             case KEY_W:
2119             case KEY_POINT:
2120             case KEY_COMMA:
2121             {
2122                 blankScreen( ((nKeyCode == KEY_W ) || (nKeyCode == KEY_COMMA)) ? 0x00ffffff : 0x00000000 );
2123             }
2124             break;
2125 
2126             default:
2127                 bRet = false;
2128             break;
2129         }
2130     }
2131     catch( Exception& )
2132     {
2133         bRet = false;
2134         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::keyInput()" );
2135     }
2136 
2137     return bRet;
2138 }
2139 
IMPL_LINK(SlideshowImpl,EventListenerHdl,VclSimpleEvent &,rSimpleEvent,void)2140 IMPL_LINK( SlideshowImpl, EventListenerHdl, VclSimpleEvent&, rSimpleEvent, void )
2141 {
2142     if( !mxShow.is() || mbInputFreeze )
2143         return;
2144 
2145     if( !((rSimpleEvent.GetId() == VclEventId::WindowCommand) && static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData()) )
2146         return;
2147 
2148     const CommandEvent& rEvent = *static_cast<const CommandEvent*>(static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData());
2149 
2150     if( rEvent.GetCommand() != CommandEventId::Media )
2151         return;
2152 
2153     CommandMediaData* pMediaData = rEvent.GetMediaData();
2154     pMediaData->SetPassThroughToOS(false);
2155     switch (pMediaData->GetMediaId())
2156     {
2157 #if defined( MACOSX )
2158     case MediaCommand::Menu:
2159         if( !mnContextMenuEvent )
2160         {
2161             if( mpShowWindow )
2162                 maPopupMousePos = mpShowWindow->GetPointerState().maPos;
2163             mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
2164         }
2165         break;
2166     case MediaCommand::VolumeDown:
2167         gotoPreviousSlide();
2168         break;
2169     case MediaCommand::VolumeUp:
2170         gotoNextEffect();
2171         break;
2172 #endif
2173     case MediaCommand::NextTrack:
2174         gotoNextEffect();
2175         break;
2176     case MediaCommand::Pause:
2177         if( !mbIsPaused )
2178             blankScreen(0);
2179         break;
2180     case MediaCommand::Play:
2181         if( mbIsPaused )
2182             resume();
2183         break;
2184 
2185     case MediaCommand::PlayPause:
2186         if( mbIsPaused )
2187             resume();
2188         else
2189             blankScreen(0);
2190         break;
2191     case MediaCommand::PreviousTrack:
2192         gotoPreviousSlide();
2193         break;
2194     case MediaCommand::NextTrackHold:
2195         gotoLastSlide();
2196         break;
2197 
2198     case MediaCommand::Rewind:
2199         gotoFirstSlide();
2200         break;
2201     case MediaCommand::Stop:
2202         // in case the user cancels the presentation, switch to current slide
2203         // in edit mode
2204         if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
2205         {
2206             if( mpSlideController->getCurrentSlideNumber() != -1 )
2207                 mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
2208         }
2209         endPresentation();
2210         break;
2211     default:
2212         pMediaData->SetPassThroughToOS(true);
2213         break;
2214     }
2215 }
2216 
mouseButtonUp(const MouseEvent & rMEvt)2217 void SlideshowImpl::mouseButtonUp(const MouseEvent& rMEvt)
2218 {
2219     if( rMEvt.IsRight() && !mnContextMenuEvent )
2220     {
2221         maPopupMousePos = rMEvt.GetPosPixel();
2222         mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
2223     }
2224 }
2225 
IMPL_LINK_NOARG(SlideshowImpl,ContextMenuHdl,void *,void)2226 IMPL_LINK_NOARG(SlideshowImpl, ContextMenuHdl, void*, void)
2227 {
2228     mnContextMenuEvent = nullptr;
2229 
2230     if (mpSlideController == nullptr)
2231         return;
2232 
2233     mbWasPaused = mbIsPaused;
2234     if( !mbWasPaused )
2235         pause();
2236 
2237     std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, u"modules/simpress/ui/slidecontextmenu.ui"_ustr));
2238     std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu(u"menu"_ustr));
2239     OUString sNextImage(BMP_MENU_NEXT), sPrevImage(BMP_MENU_PREV);
2240     xMenu->insert(0, u"next"_ustr, SdResId(RID_SVXSTR_MENU_NEXT), &sNextImage, nullptr, nullptr, TRISTATE_INDET);
2241     xMenu->insert(1, u"prev"_ustr, SdResId(RID_SVXSTR_MENU_PREV), &sPrevImage, nullptr, nullptr, TRISTATE_INDET);
2242 
2243     // Adding button to display if in Pen  mode
2244     xMenu->set_active(u"pen"_ustr, mbUsePen);
2245 
2246     const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
2247     xMenu->set_visible(u"next"_ustr, mpSlideController->getNextSlideIndex() != -1);
2248     xMenu->set_visible(u"prev"_ustr, (mpSlideController->getPreviousSlideIndex() != -1 ) || (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK));
2249     xMenu->set_visible(u"edit"_ustr, mpViewShell->GetDoc()->GetStartWithPresentation() != 0);
2250 
2251     std::unique_ptr<weld::Menu> xPageMenu(xBuilder->weld_menu(u"gotomenu"_ustr));
2252     OUString sFirstImage(BMP_MENU_FIRST), sLastImage(BMP_MENU_LAST);
2253     xPageMenu->insert(0, u"first"_ustr, SdResId(RID_SVXSTR_MENU_FIRST), &sFirstImage, nullptr, nullptr, TRISTATE_INDET);
2254     xPageMenu->insert(1, u"last"_ustr, SdResId(RID_SVXSTR_MENU_LAST), &sLastImage, nullptr, nullptr, TRISTATE_INDET);
2255 
2256     // populate slide goto list
2257     const sal_Int32 nPageNumberCount = mpSlideController->getSlideNumberCount();
2258     if( nPageNumberCount <= 1 )
2259     {
2260         xMenu->set_visible(u"goto"_ustr, false);
2261     }
2262     else
2263     {
2264         sal_Int32 nCurrentSlideNumber = mpSlideController->getCurrentSlideNumber();
2265         if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
2266             nCurrentSlideNumber = -1;
2267 
2268         xPageMenu->set_visible(u"first"_ustr, mpSlideController->getSlideNumber(0) != nCurrentSlideNumber);
2269         xPageMenu->set_visible(u"last"_ustr, mpSlideController->getSlideNumber(mpSlideController->getSlideIndexCount() - 1) != nCurrentSlideNumber);
2270 
2271         sal_Int32 nPageNumber;
2272 
2273         for( nPageNumber = 0; nPageNumber < nPageNumberCount; nPageNumber++ )
2274         {
2275             if( mpSlideController->isVisibleSlideNumber( nPageNumber ) )
2276             {
2277                 SdPage* pPage = mpDoc->GetSdPage(static_cast<sal_uInt16>(nPageNumber), PageKind::Standard);
2278                 if (pPage)
2279                 {
2280                     OUString sId(OUString::number(CM_SLIDES + nPageNumber));
2281                     xPageMenu->append_check(sId, pPage->GetName());
2282                     if (nPageNumber == nCurrentSlideNumber)
2283                         xPageMenu->set_active(sId, true);
2284                 }
2285             }
2286         }
2287     }
2288 
2289     std::unique_ptr<weld::Menu> xBlankMenu(xBuilder->weld_menu(u"screenmenu"_ustr));
2290 
2291     if (mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK)
2292     {
2293         xBlankMenu->set_active((mpShowWindow->GetBlankColor() == COL_WHITE) ? "white" : "black", true);
2294     }
2295 
2296     std::unique_ptr<weld::Menu> xWidthMenu(xBuilder->weld_menu(u"widthmenu"_ustr));
2297 
2298     // populate color width list
2299     sal_Int32 nIterator;
2300     double nWidth;
2301 
2302     nWidth = 4.0;
2303     for( nIterator = 1; nIterator < 6; nIterator++)
2304     {
2305         switch(nIterator)
2306         {
2307             case 1:
2308                 nWidth = 4.0;
2309                 break;
2310             case 2:
2311                 nWidth = 100.0;
2312                 break;
2313             case 3:
2314                 nWidth = 150.0;
2315                 break;
2316             case 4:
2317                 nWidth = 200.0;
2318                 break;
2319             case 5:
2320                 nWidth = 400.0;
2321                 break;
2322             default:
2323                 break;
2324         }
2325 
2326         if (nWidth == mdUserPaintStrokeWidth)
2327             xWidthMenu->set_active(OUString::number(nWidth), true);
2328     }
2329 
2330     ::tools::Rectangle aRect(maPopupMousePos, Size(1,1));
2331     weld::Window* pParent = weld::GetPopupParent(*mpShowWindow, aRect);
2332     ContextMenuSelectHdl(xMenu->popup_at_rect(pParent, aRect));
2333 
2334     if( mxView.is() )
2335         mxView->ignoreNextMouseReleased();
2336 
2337     if( !mbWasPaused )
2338         resume();
2339 }
2340 
ContextMenuSelectHdl(std::u16string_view rMenuId)2341 void SlideshowImpl::ContextMenuSelectHdl(std::u16string_view rMenuId)
2342 {
2343     if (rMenuId == u"prev")
2344     {
2345         gotoPreviousSlide();
2346         mbWasPaused = false;
2347     }
2348     else if(rMenuId == u"next")
2349     {
2350         gotoNextSlide();
2351         mbWasPaused = false;
2352     }
2353     else if (rMenuId == u"first")
2354     {
2355         gotoFirstSlide();
2356         mbWasPaused = false;
2357     }
2358     else if (rMenuId == u"last")
2359     {
2360         gotoLastSlide();
2361         mbWasPaused = false;
2362     }
2363     else if (rMenuId == u"black" || rMenuId == u"white")
2364     {
2365         const Color aBlankColor(rMenuId == u"white" ? COL_WHITE : COL_BLACK);
2366         if( mbWasPaused )
2367         {
2368             if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK )
2369             {
2370                 if( mpShowWindow->GetBlankColor() == aBlankColor )
2371                 {
2372                     mbWasPaused = false;
2373                     mpShowWindow->RestartShow();
2374                     return;
2375                 }
2376             }
2377             mpShowWindow->RestartShow();
2378         }
2379         if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), aBlankColor ) )
2380         {
2381             pause();
2382             mbWasPaused = true;
2383         }
2384     }
2385     else if (rMenuId == u"color")
2386     {
2387         //Open a color picker based on SvColorDialog
2388         ::Color aColor( ColorTransparency, mnUserPaintColor );
2389         SvColorDialog aColorDlg;
2390         aColorDlg.SetColor( aColor );
2391 
2392         if (aColorDlg.Execute(mpShowWindow->GetFrameWeld()))
2393         {
2394             aColor = aColorDlg.GetColor();
2395             setPenColor(sal_Int32(aColor));
2396         }
2397         mbWasPaused = false;
2398     }
2399     else if (rMenuId == u"4")
2400     {
2401         setPenWidth(4.0);
2402         mbWasPaused = false;
2403     }
2404     else if (rMenuId == u"100")
2405     {
2406         setPenWidth(100.0);
2407         mbWasPaused = false;
2408     }
2409     else if (rMenuId == u"150")
2410     {
2411         setPenWidth(150.0);
2412         mbWasPaused = false;
2413     }
2414     else if (rMenuId == u"200")
2415     {
2416         setPenWidth(200.0);
2417         mbWasPaused = false;
2418     }
2419     else if (rMenuId == u"400")
2420     {
2421         setPenWidth(400.0);
2422         mbWasPaused = false;
2423     }
2424     else if (rMenuId == u"erase")
2425     {
2426         setEraseAllInk(true);
2427         mbWasPaused = false;
2428     }
2429     else if (rMenuId == u"pen")
2430     {
2431         setUsePen(!mbUsePen);
2432         mbWasPaused = false;
2433     }
2434     else if (rMenuId == u"edit")
2435     {
2436         // When in autoplay mode (pps/ppsx), offer editing of the presentation
2437         // Turn autostart off, else Impress will close when exiting the Presentation
2438         mpViewShell->GetDoc()->SetExitAfterPresenting(false);
2439         if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
2440         {
2441             if( mpSlideController->getCurrentSlideNumber() != -1 )
2442             {
2443                 mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
2444             }
2445         }
2446         endPresentation();
2447     }
2448     else if (rMenuId == u"end")
2449     {
2450         // in case the user cancels the presentation, switch to current slide
2451         // in edit mode
2452         if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
2453         {
2454             if( mpSlideController->getCurrentSlideNumber() != -1 )
2455             {
2456                 mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
2457             }
2458         }
2459         endPresentation();
2460     }
2461     else if (!rMenuId.empty())
2462     {
2463         sal_Int32 nPageNumber = o3tl::toInt32(rMenuId) - CM_SLIDES;
2464         const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
2465         if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
2466         {
2467             mpShowWindow->RestartShow( nPageNumber );
2468         }
2469         else if( nPageNumber != mpSlideController->getCurrentSlideNumber() )
2470         {
2471             displaySlideNumber( nPageNumber );
2472         }
2473         mbWasPaused = false;
2474     }
2475 }
2476 
createSlideShow()2477 Reference< XSlideShow > SlideshowImpl::createSlideShow()
2478 {
2479     Reference< XSlideShow > xShow;
2480 
2481     try
2482     {
2483         Reference< uno::XComponentContext > xContext =
2484             ::comphelper::getProcessComponentContext();
2485 
2486         xShow.set( presentation::SlideShow::create(xContext), UNO_SET_THROW );
2487     }
2488     catch( uno::Exception& )
2489     {
2490         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::createSlideShow()" );
2491     }
2492 
2493     return xShow;
2494 }
2495 
createSlideList(bool bAll,std::u16string_view rPresSlide)2496 void SlideshowImpl::createSlideList( bool bAll, std::u16string_view rPresSlide )
2497 {
2498     const sal_uInt16 nSlideCount = mpDoc->GetSdPageCount( PageKind::Standard );
2499 
2500     if( !nSlideCount )
2501         return;
2502 
2503     SdCustomShow*   pCustomShow;
2504 
2505     if( mpDoc->GetCustomShowList() && maPresSettings.mbCustomShow )
2506         pCustomShow = mpDoc->GetCustomShowList()->GetCurObject();
2507     else
2508         pCustomShow = nullptr;
2509 
2510     // create animation slide controller
2511     AnimationSlideController::Mode eMode =
2512         ( pCustomShow && !pCustomShow->PagesVector().empty() ) ? AnimationSlideController::CUSTOM :
2513             (bAll ? AnimationSlideController::ALL : AnimationSlideController::FROM);
2514 
2515     Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
2516     Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
2517     mpSlideController = std::make_shared<AnimationSlideController>( xSlides, eMode );
2518 
2519     if( eMode != AnimationSlideController::CUSTOM )
2520     {
2521         sal_Int32 nFirstVisibleSlide = 0;
2522 
2523         // normal presentation
2524         if( !rPresSlide.empty() )
2525         {
2526             sal_Int32 nSlide;
2527             bool bTakeNextAvailable = false;
2528 
2529             for( nSlide = 0, nFirstVisibleSlide = -1;
2530                 ( nSlide < nSlideCount ) && ( -1 == nFirstVisibleSlide ); nSlide++ )
2531             {
2532                 SdPage* pTestSlide = mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard );
2533 
2534                 if( pTestSlide->GetName() == rPresSlide )
2535                 {
2536                     if( pTestSlide->IsExcluded() )
2537                         bTakeNextAvailable = true;
2538                     else
2539                         nFirstVisibleSlide = nSlide;
2540                 }
2541                 else if( bTakeNextAvailable && !pTestSlide->IsExcluded() )
2542                     nFirstVisibleSlide = nSlide;
2543             }
2544 
2545             if( -1 == nFirstVisibleSlide )
2546                 nFirstVisibleSlide = 0;
2547         }
2548 
2549         for( sal_Int32 i = 0; i < nSlideCount; i++ )
2550         {
2551             bool bVisible = ! mpDoc->GetSdPage( static_cast<sal_uInt16>(i), PageKind::Standard )->IsExcluded();
2552             if( bVisible || (eMode == AnimationSlideController::ALL) )
2553                 mpSlideController->insertSlideNumber( i, bVisible );
2554         }
2555 
2556         mpSlideController->setStartSlideNumber( nFirstVisibleSlide );
2557     }
2558     else
2559     {
2560         if( meAnimationMode != ANIMATIONMODE_SHOW && !rPresSlide.empty() )
2561         {
2562             sal_Int32 nSlide;
2563             for( nSlide = 0; nSlide < nSlideCount; nSlide++ )
2564                 if( rPresSlide == mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard )->GetName() )
2565                     break;
2566 
2567             if( nSlide < nSlideCount )
2568                 mpSlideController->insertSlideNumber( static_cast<sal_uInt16>(nSlide) );
2569         }
2570 
2571         for( const auto& rpPage : pCustomShow->PagesVector() )
2572         {
2573             const sal_uInt16 nSdSlide = ( rpPage->GetPageNum() - 1 ) / 2;
2574 
2575             if( ! mpDoc->GetSdPage( nSdSlide, PageKind::Standard )->IsExcluded())
2576                 mpSlideController->insertSlideNumber( nSdSlide );
2577         }
2578     }
2579 }
2580 
2581 typedef sal_uInt16 (*FncGetChildWindowId)();
2582 
2583 const FncGetChildWindowId aShowChildren[] =
2584 {
2585     &AnimationChildWindow::GetChildWindowId,
2586     &Svx3DChildWindow::GetChildWindowId,
2587     &SvxFontWorkChildWindow::GetChildWindowId,
2588     &SvxColorChildWindow::GetChildWindowId,
2589     &SvxSearchDialogWrapper::GetChildWindowId,
2590     &SvxBmpMaskChildWindow::GetChildWindowId,
2591     &SvxIMapDlgChildWindow::GetChildWindowId,
2592     &SvxHlinkDlgWrapper::GetChildWindowId,
2593     &SfxInfoBarContainerChild::GetChildWindowId
2594 };
2595 
hideChildWindows()2596 void SlideshowImpl::hideChildWindows()
2597 {
2598     mnChildMask = 0;
2599 
2600     if( ANIMATIONMODE_SHOW != meAnimationMode )
2601         return;
2602 
2603     SfxViewFrame* pViewFrame = getViewFrame();
2604 
2605     if( !pViewFrame )
2606         return;
2607 
2608     for( sal_uLong i = 0; i < SAL_N_ELEMENTS( aShowChildren ); i++ )
2609     {
2610         const sal_uInt16 nId = ( *aShowChildren[ i ] )();
2611 
2612         if( pViewFrame->GetChildWindow( nId ) )
2613         {
2614             pViewFrame->SetChildWindow( nId, false );
2615             mnChildMask |= ::tools::ULong(1) << i;
2616         }
2617     }
2618 }
2619 
showChildWindows()2620 void SlideshowImpl::showChildWindows()
2621 {
2622     if( ANIMATIONMODE_SHOW == meAnimationMode )
2623     {
2624         SfxViewFrame* pViewFrame = getViewFrame();
2625         if( pViewFrame )
2626         {
2627             for( sal_uLong i = 0; i < SAL_N_ELEMENTS(aShowChildren); i++ )
2628             {
2629                 if( mnChildMask & ( ::tools::ULong(1) << i ) )
2630                     pViewFrame->SetChildWindow( ( *aShowChildren[ i ] )(), true );
2631             }
2632         }
2633     }
2634 }
2635 
getViewFrame() const2636 SfxViewFrame* SlideshowImpl::getViewFrame() const
2637 {
2638     return mpViewShell ? mpViewShell->GetViewFrame() : nullptr;
2639 }
2640 
getDispatcher() const2641 SfxDispatcher* SlideshowImpl::getDispatcher() const
2642 {
2643     return (mpViewShell && mpViewShell->GetViewFrame()) ? mpViewShell->GetViewFrame()->GetDispatcher() : nullptr;
2644 }
2645 
getBindings() const2646 SfxBindings* SlideshowImpl::getBindings() const
2647 {
2648     return (mpViewShell && mpViewShell->GetViewFrame()) ? &mpViewShell->GetViewFrame()->GetBindings() : nullptr;
2649 }
2650 
resize(const Size & rSize)2651 void SlideshowImpl::resize( const Size& rSize )
2652 {
2653     maPresSize = rSize;
2654 
2655     if(mpShowWindow)
2656     {
2657         mpShowWindow->SetSizePixel( maPresSize );
2658         mpShowWindow->Show();
2659     }
2660 
2661     if( mxView.is() ) try
2662     {
2663         awt::WindowEvent aEvt;
2664         mxView->windowResized(aEvt);
2665     }
2666     catch( Exception& )
2667     {
2668         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resize()" );
2669     }
2670 }
2671 
setActiveXToolbarsVisible(bool bVisible)2672 void SlideshowImpl::setActiveXToolbarsVisible( bool bVisible )
2673 {
2674     // in case of ActiveX control the toolbars should not be visible if slide show runs in window mode
2675     // actually it runs always in window mode in case of ActiveX control
2676     if ( !(!maPresSettings.mbFullScreen && mpDocSh && mpDocSh->GetMedium()) )
2677         return;
2678 
2679     const SfxBoolItem* pItem = mpDocSh->GetMedium()->GetItemSet().GetItem(SID_VIEWONLY, false);
2680     if ( !(pItem && pItem->GetValue()) )
2681         return;
2682 
2683     // this is a plugin/activex mode, no toolbars should be visible during slide show
2684     // after the end of slide show they should be visible again
2685     SfxViewFrame* pViewFrame = getViewFrame();
2686     if( !pViewFrame )
2687         return;
2688 
2689     try
2690     {
2691         Reference< frame::XLayoutManager > xLayoutManager;
2692         Reference< beans::XPropertySet > xFrameProps( pViewFrame->GetFrame().GetFrameInterface(), UNO_QUERY_THROW );
2693         if ( ( xFrameProps->getPropertyValue( u"LayoutManager"_ustr )
2694                     >>= xLayoutManager )
2695           && xLayoutManager.is() )
2696         {
2697             xLayoutManager->setVisible( bVisible );
2698         }
2699     }
2700     catch( uno::Exception& )
2701     {}
2702 }
2703 
activate()2704 void SAL_CALL SlideshowImpl::activate()
2705 {
2706     SolarMutexGuard aSolarGuard;
2707 
2708     maDeactivateTimer.Stop();
2709 
2710     if( mbActive || !mxShow.is() )
2711         return;
2712 
2713     mbActive = true;
2714 
2715     if( ANIMATIONMODE_SHOW == meAnimationMode )
2716     {
2717         if( mbAutoSaveWasOn )
2718             setAutoSaveState( false );
2719 
2720         if( mpShowWindow )
2721         {
2722             SfxViewFrame* pViewFrame = getViewFrame();
2723             SfxDispatcher* pDispatcher = pViewFrame ? pViewFrame->GetDispatcher() : nullptr;
2724 
2725             hideChildWindows();
2726 
2727             if( pDispatcher )
2728             {
2729                 // filter all forbidden slots
2730                 pDispatcher->SetSlotFilter( SfxSlotFilterState::ENABLED, pAllowed );
2731             }
2732 
2733             if( getBindings() )
2734                 getBindings()->InvalidateAll(true);
2735 
2736             mpShowWindow->GrabFocus();
2737         }
2738     }
2739 
2740     resume();
2741 }
2742 
deactivate()2743 void SAL_CALL SlideshowImpl::deactivate()
2744 {
2745     SolarMutexGuard aSolarGuard;
2746 
2747     if( mbActive && mxShow.is() )
2748     {
2749         maDeactivateTimer.Start();
2750     }
2751 }
2752 
IMPL_LINK_NOARG(SlideshowImpl,deactivateHdl,Timer *,void)2753 IMPL_LINK_NOARG(SlideshowImpl, deactivateHdl, Timer *, void)
2754 {
2755     if( !(mbActive && mxShow.is()) )
2756         return;
2757 
2758     mbActive = false;
2759 
2760     pause();
2761 
2762     if( ANIMATIONMODE_SHOW == meAnimationMode )
2763     {
2764         if( mbAutoSaveWasOn )
2765             setAutoSaveState( true );
2766 
2767         if( mpShowWindow )
2768         {
2769             showChildWindows();
2770         }
2771     }
2772 }
2773 
isActive()2774 sal_Bool SAL_CALL SlideshowImpl::isActive()
2775 {
2776     SolarMutexGuard aSolarGuard;
2777     return mbActive;
2778 }
2779 
setAutoSaveState(bool bOn)2780 void SlideshowImpl::setAutoSaveState( bool bOn)
2781 {
2782     try
2783     {
2784         uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2785 
2786         uno::Reference< util::XURLTransformer > xParser(util::URLTransformer::create(xContext));
2787         util::URL aURL;
2788         aURL.Complete = "vnd.sun.star.autorecovery:/setAutoSaveState";
2789         xParser->parseStrict(aURL);
2790 
2791         Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue(u"AutoSaveState"_ustr, bOn) };
2792 
2793         uno::Reference< frame::XDispatch > xAutoSave = frame::theAutoRecovery::get(xContext);
2794         xAutoSave->dispatch(aURL, aArgs);
2795     }
2796     catch( Exception& )
2797     {
2798         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setAutoSaveState()");
2799     }
2800 }
2801 
getCurrentSlide()2802 Reference< XDrawPage > SAL_CALL SlideshowImpl::getCurrentSlide()
2803 {
2804     SolarMutexGuard aSolarGuard;
2805 
2806     Reference< XDrawPage > xSlide;
2807     if( mxShow.is() && mpSlideController )
2808     {
2809         sal_Int32 nSlide = getCurrentSlideNumber();
2810         if( (nSlide >= 0) && (nSlide < mpSlideController->getSlideNumberCount() ) )
2811             xSlide = mpSlideController->getSlideByNumber( nSlide );
2812     }
2813 
2814     return xSlide;
2815 }
2816 
getNextSlideIndex()2817 sal_Int32 SAL_CALL SlideshowImpl::getNextSlideIndex()
2818 {
2819     SolarMutexGuard aSolarGuard;
2820 
2821     if( mxShow.is() )
2822     {
2823         return mpSlideController->getNextSlideIndex();
2824     }
2825     else
2826     {
2827         return -1;
2828     }
2829 }
2830 
getCurrentSlideIndex()2831 sal_Int32 SAL_CALL SlideshowImpl::getCurrentSlideIndex()
2832 {
2833     return mpSlideController ? mpSlideController->getCurrentSlideIndex() : -1;
2834 }
2835 
2836 // css::presentation::XSlideShowController:
2837 
getSlideCount()2838 ::sal_Int32 SAL_CALL SlideshowImpl::getSlideCount()
2839 {
2840     return mpSlideController ? mpSlideController->getSlideIndexCount() : 0;
2841 }
2842 
getSlideByIndex(::sal_Int32 Index)2843 Reference< XDrawPage > SAL_CALL SlideshowImpl::getSlideByIndex(::sal_Int32 Index)
2844 {
2845     if ((mpSlideController == nullptr) || (Index < 0)
2846         || (Index >= mpSlideController->getSlideIndexCount()))
2847         throw IndexOutOfBoundsException();
2848 
2849     return mpSlideController->getSlideByNumber( mpSlideController->getSlideNumber( Index ) );
2850 }
2851 
getAlwaysOnTop()2852 sal_Bool SAL_CALL SlideshowImpl::getAlwaysOnTop()
2853 {
2854     SolarMutexGuard aSolarGuard;
2855     return maPresSettings.mbAlwaysOnTop;
2856 }
2857 
setAlwaysOnTop(sal_Bool bAlways)2858 void SAL_CALL SlideshowImpl::setAlwaysOnTop( sal_Bool bAlways )
2859 {
2860     SolarMutexGuard aSolarGuard;
2861     if( maPresSettings.mbAlwaysOnTop != bool(bAlways) )
2862     {
2863         maPresSettings.mbAlwaysOnTop = bAlways;
2864         // todo, can this be changed while running?
2865     }
2866 }
2867 
isFullScreen()2868 sal_Bool SAL_CALL SlideshowImpl::isFullScreen()
2869 {
2870     SolarMutexGuard aSolarGuard;
2871     return maPresSettings.mbFullScreen;
2872 }
2873 
getMouseVisible()2874 sal_Bool SAL_CALL SlideshowImpl::getMouseVisible()
2875 {
2876     SolarMutexGuard aSolarGuard;
2877     return maPresSettings.mbMouseVisible;
2878 }
2879 
setMouseVisible(sal_Bool bVisible)2880 void SAL_CALL SlideshowImpl::setMouseVisible( sal_Bool bVisible )
2881 {
2882     SolarMutexGuard aSolarGuard;
2883     if( maPresSettings.mbMouseVisible != bool(bVisible) )
2884     {
2885         maPresSettings.mbMouseVisible = bVisible;
2886         if( mpShowWindow )
2887             mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
2888     }
2889 }
2890 
getUsePen()2891 sal_Bool SAL_CALL SlideshowImpl::getUsePen()
2892 {
2893     SolarMutexGuard aSolarGuard;
2894     return mbUsePen;
2895 }
2896 
setUsePen(sal_Bool bMouseAsPen)2897 void SAL_CALL SlideshowImpl::setUsePen( sal_Bool bMouseAsPen )
2898 {
2899     SolarMutexGuard aSolarGuard;
2900     mbUsePen = bMouseAsPen;
2901     if( !mxShow.is() )
2902         return;
2903 
2904     try
2905     {
2906         // For Pencolor;
2907         Any aValue;
2908         if( mbUsePen )
2909             aValue <<= mnUserPaintColor;
2910         beans::PropertyValue aPenProp;
2911         aPenProp.Name = "UserPaintColor";
2912         aPenProp.Value = aValue;
2913         mxShow->setProperty( aPenProp );
2914 
2915         //for StrokeWidth :
2916         if( mbUsePen )
2917         {
2918             beans::PropertyValue aPenPropWidth;
2919             aPenPropWidth.Name = "UserPaintStrokeWidth";
2920             aPenPropWidth.Value <<= mdUserPaintStrokeWidth;
2921             mxShow->setProperty( aPenPropWidth );
2922 
2923             // for Pen Mode
2924             beans::PropertyValue aPenPropSwitchPenMode;
2925             aPenPropSwitchPenMode.Name = "SwitchPenMode";
2926             aPenPropSwitchPenMode.Value <<= true;
2927             mxShow->setProperty( aPenPropSwitchPenMode );
2928         }
2929     }
2930     catch( Exception& )
2931     {
2932         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setUsePen()" );
2933     }
2934 }
2935 
getPenWidth()2936 double SAL_CALL SlideshowImpl::getPenWidth()
2937 {
2938     SolarMutexGuard aSolarGuard;
2939     return mdUserPaintStrokeWidth;
2940 }
2941 
setPenWidth(double dStrokeWidth)2942 void SAL_CALL SlideshowImpl::setPenWidth( double dStrokeWidth )
2943 {
2944     SolarMutexGuard aSolarGuard;
2945     mdUserPaintStrokeWidth = dStrokeWidth;
2946     setUsePen( true ); // enable pen mode, update color and width
2947 }
2948 
getPenColor()2949 sal_Int32 SAL_CALL SlideshowImpl::getPenColor()
2950 {
2951     SolarMutexGuard aSolarGuard;
2952     return mnUserPaintColor;
2953 }
2954 
setPenColor(sal_Int32 nColor)2955 void SAL_CALL SlideshowImpl::setPenColor( sal_Int32 nColor )
2956 {
2957     SolarMutexGuard aSolarGuard;
2958     mnUserPaintColor = nColor;
2959     setUsePen( true ); // enable pen mode, update color
2960 }
2961 
setEraseAllInk(sal_Bool bEraseAllInk)2962 void SAL_CALL SlideshowImpl::setEraseAllInk(sal_Bool bEraseAllInk)
2963 {
2964     if( !bEraseAllInk )
2965         return;
2966 
2967     SolarMutexGuard aSolarGuard;
2968     if( !mxShow.is() )
2969         return;
2970 
2971     try
2972     {
2973         beans::PropertyValue aPenPropEraseAllInk;
2974         aPenPropEraseAllInk.Name = "EraseAllInk";
2975         aPenPropEraseAllInk.Value <<= bEraseAllInk;
2976         mxShow->setProperty( aPenPropEraseAllInk );
2977     }
2978     catch( Exception& )
2979     {
2980         TOOLS_WARN_EXCEPTION( "sd.slideshow", "sd::SlideshowImpl::setEraseAllInk()" );
2981     }
2982 }
2983 
2984 // XSlideShowController Methods
isRunning()2985 sal_Bool SAL_CALL SlideshowImpl::isRunning(  )
2986 {
2987     SolarMutexGuard aSolarGuard;
2988     return mxShow.is();
2989 }
2990 
gotoNextEffect()2991 void SAL_CALL SlideshowImpl::gotoNextEffect(  )
2992 {
2993     SolarMutexGuard aSolarGuard;
2994 
2995     if( !(mxShow.is() && mpSlideController && mpShowWindow) )
2996         return;
2997 
2998     if( mbIsPaused && mpShowWindow->GetShowWindowMode() != SHOWWINDOWMODE_END )
2999         resume();
3000 
3001     const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
3002     if( eMode == SHOWWINDOWMODE_END )
3003     {
3004         endPresentation();
3005     }
3006     else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
3007     {
3008         mpShowWindow->RestartShow();
3009     }
3010     else
3011     {
3012         mxShow->nextEffect();
3013         update();
3014     }
3015 }
3016 
gotoPreviousEffect()3017 void SAL_CALL SlideshowImpl::gotoPreviousEffect(  )
3018 {
3019     SolarMutexGuard aSolarGuard;
3020 
3021     if( !(mxShow.is() && mpSlideController && mpShowWindow) )
3022         return;
3023 
3024     const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
3025     if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) || mbIsPaused )
3026     {
3027         resume();
3028     }
3029     else
3030     {
3031         mxShow->previousEffect();
3032         update();
3033     }
3034 }
3035 
gotoFirstSlide()3036 void SAL_CALL SlideshowImpl::gotoFirstSlide(  )
3037 {
3038     SolarMutexGuard aSolarGuard;
3039 
3040     if( !(mpShowWindow && mpSlideController) )
3041         return;
3042 
3043     if( mbIsPaused )
3044         resume();
3045 
3046     if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
3047     {
3048         if( mpSlideController->getSlideIndexCount() )
3049             mpShowWindow->RestartShow( 0);
3050     }
3051     else
3052     {
3053         displaySlideIndex( 0 );
3054     }
3055 }
3056 
gotoNextSlide()3057 void SAL_CALL SlideshowImpl::gotoNextSlide(  )
3058 {
3059     SolarMutexGuard aSolarGuard;
3060 
3061     if( mbIsPaused )
3062         resume();
3063 
3064     const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
3065     if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
3066     {
3067         mpShowWindow->RestartShow();
3068     }
3069     else
3070     {
3071         // if this is a show, ignore user inputs and
3072         // start 20ms timer to reenable inputs to filter
3073         // buffered inputs during slide transition
3074         if( meAnimationMode == ANIMATIONMODE_SHOW )
3075         {
3076             mbInputFreeze = true;
3077             maInputFreezeTimer.Start();
3078         }
3079 
3080         if( mpSlideController )
3081         {
3082             if( mpSlideController->nextSlide() )
3083             {
3084                 displayCurrentSlide();
3085             }
3086             else
3087             {
3088                 stopSound();
3089 
3090                 if( meAnimationMode == ANIMATIONMODE_PREVIEW )
3091                 {
3092                     endPresentation();
3093                 }
3094                 else if( maPresSettings.mbEndless )
3095                 {
3096                     if( maPresSettings.mnPauseTimeout )
3097                     {
3098                         if( mpShowWindow )
3099                         {
3100                             if ( maPresSettings.mbShowPauseLogo )
3101                             {
3102                                 Graphic aGraphic(SfxApplication::GetApplicationLogo(360));
3103                                 mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout, &aGraphic );
3104                             }
3105                             else
3106                                 mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout );
3107                         }
3108                     }
3109                     else
3110                     {
3111                         displaySlideIndex( 0 );
3112                     }
3113                 }
3114                 else
3115                 {
3116                     if( mpShowWindow )
3117                     {
3118                         mpShowWindow->SetEndMode();
3119                         if (!mpViewShell->GetDoc()->GetStartWithPresentation())
3120                             pause();
3121                     }
3122                 }
3123             }
3124         }
3125     }
3126 }
3127 
gotoPreviousSlide()3128 void SAL_CALL SlideshowImpl::gotoPreviousSlide(  )
3129 {
3130     gotoPreviousSlide(false);
3131 }
3132 
gotoPreviousSlide(const bool bSkipAllMainSequenceEffects)3133 void SlideshowImpl::gotoPreviousSlide (const bool bSkipAllMainSequenceEffects)
3134 {
3135     SolarMutexGuard aSolarGuard;
3136 
3137     if( !(mxShow.is() && mpSlideController) )
3138         return;
3139 
3140     try
3141     {
3142         if( mbIsPaused )
3143             resume();
3144 
3145         const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
3146         if( eMode == SHOWWINDOWMODE_END )
3147         {
3148             mpShowWindow->RestartShow( mpSlideController->getCurrentSlideIndex() );
3149         }
3150         else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
3151         {
3152             mpShowWindow->RestartShow();
3153         }
3154         else
3155         {
3156             if( mpSlideController->previousSlide())
3157                 displayCurrentSlide(bSkipAllMainSequenceEffects);
3158             else if (bSkipAllMainSequenceEffects)
3159             {
3160                 // We could not go to the previous slide (probably because
3161                 // the current slide is already the first one).  We still
3162                 // have to call displayCurrentSlide because the calling
3163                 // slideshow can not determine whether there is a previous
3164                 // slide or not and has already prepared for a slide change.
3165                 // This slide change has to be completed now, even when
3166                 // changing to the same slide.
3167                 // Note that in this special case we do NOT pass
3168                 // bSkipAllMainSequenceEffects because we display the same
3169                 // slide as before and do not want to show all its effects.
3170                 displayCurrentSlide();
3171             }
3172         }
3173     }
3174     catch( Exception& )
3175     {
3176         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::gotoPreviousSlide()" );
3177     }
3178 }
3179 
gotoLastSlide()3180 void SAL_CALL SlideshowImpl::gotoLastSlide()
3181 {
3182     SolarMutexGuard aSolarGuard;
3183 
3184     if( !mpSlideController )
3185         return;
3186 
3187     if( mbIsPaused )
3188         resume();
3189 
3190     const sal_Int32 nLastSlideIndex = mpSlideController->getSlideIndexCount() - 1;
3191     if( nLastSlideIndex >= 0 )
3192     {
3193         if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
3194         {
3195             mpShowWindow->RestartShow( nLastSlideIndex );
3196         }
3197         else
3198         {
3199             displaySlideIndex( nLastSlideIndex );
3200         }
3201     }
3202 }
3203 
gotoBookmark(const OUString & rBookmark)3204 void SAL_CALL SlideshowImpl::gotoBookmark( const OUString& rBookmark )
3205 {
3206     SolarMutexGuard aSolarGuard;
3207 
3208     if( mbIsPaused )
3209         resume();
3210 
3211     sal_Int32 nSlideNumber = getSlideNumberForBookmark( rBookmark );
3212     if( nSlideNumber != -1 )
3213         displaySlideNumber( nSlideNumber );
3214 }
3215 
gotoSlide(const Reference<XDrawPage> & xSlide)3216 void SAL_CALL SlideshowImpl::gotoSlide( const Reference< XDrawPage >& xSlide )
3217 {
3218     SolarMutexGuard aSolarGuard;
3219 
3220     if( !(mpSlideController && xSlide.is()) )
3221         return;
3222 
3223     if( mbIsPaused )
3224         resume();
3225 
3226     const sal_Int32 nSlideCount = mpSlideController->getSlideNumberCount();
3227     for( sal_Int32 nSlide = 0; nSlide < nSlideCount; nSlide++ )
3228     {
3229         if( mpSlideController->getSlideByNumber( nSlide ) == xSlide )
3230         {
3231             displaySlideNumber( nSlide );
3232         }
3233     }
3234 }
3235 
gotoSlideIndex(sal_Int32 nIndex)3236 void SAL_CALL SlideshowImpl::gotoSlideIndex( sal_Int32 nIndex )
3237 {
3238     SolarMutexGuard aSolarGuard;
3239 
3240     if( mbIsPaused )
3241         resume();
3242 
3243     displaySlideIndex( nIndex );
3244 }
3245 
stopSound()3246 void SAL_CALL SlideshowImpl::stopSound(  )
3247 {
3248     SolarMutexGuard aSolarGuard;
3249 
3250     try
3251     {
3252         if( mxPlayer.is() )
3253         {
3254             mxPlayer->stop();
3255             mxPlayer.clear();
3256         }
3257     }
3258     catch( Exception& )
3259     {
3260         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stopSound()" );
3261     }
3262 }
3263 
3264 // XIndexAccess
3265 
getCount()3266 ::sal_Int32 SAL_CALL SlideshowImpl::getCount(  )
3267 {
3268     return getSlideCount();
3269 }
3270 
getByIndex(::sal_Int32 Index)3271 css::uno::Any SAL_CALL SlideshowImpl::getByIndex( ::sal_Int32 Index )
3272 {
3273     return Any( getSlideByIndex( Index ) );
3274 }
3275 
getElementType()3276 css::uno::Type SAL_CALL SlideshowImpl::getElementType(  )
3277 {
3278     return cppu::UnoType<XDrawPage>::get();
3279 }
3280 
hasElements()3281 sal_Bool SAL_CALL SlideshowImpl::hasElements(  )
3282 {
3283     return getSlideCount() != 0;
3284 }
3285 
3286 namespace
3287 {
3288     class AsyncUpdateSlideshow_Impl
3289     {
3290     public:
3291         struct AsyncUpdateSlideshowData
3292         {
3293             SlideshowImpl* pSlideshowImpl;
3294             uno::Reference< css::drawing::XDrawPage > XCurrentSlide;
3295             SdrHintKind eHintKind;
3296         };
3297 
AsyncUpdateSlideshow(SlideshowImpl * pSlideshowImpl,uno::Reference<css::drawing::XDrawPage> & rXCurrentSlide,SdrHintKind eHintKind)3298         static ImplSVEvent* AsyncUpdateSlideshow(
3299             SlideshowImpl* pSlideshowImpl,
3300             uno::Reference< css::drawing::XDrawPage >& rXCurrentSlide,
3301             SdrHintKind eHintKind)
3302         {
3303             AsyncUpdateSlideshowData* pNew(new AsyncUpdateSlideshowData);
3304             pNew->pSlideshowImpl = pSlideshowImpl;
3305             pNew->XCurrentSlide = rXCurrentSlide;
3306             pNew->eHintKind = eHintKind;
3307             return Application::PostUserEvent(LINK(nullptr, AsyncUpdateSlideshow_Impl, Update), pNew);
3308             // coverity[leaked_storage] - pDisruptor takes care of its own destruction at idle time
3309         }
3310 
3311         DECL_STATIC_LINK(AsyncUpdateSlideshow_Impl, Update, void*, void);
3312     };
3313 
IMPL_STATIC_LINK(AsyncUpdateSlideshow_Impl,Update,void *,pData,void)3314     IMPL_STATIC_LINK(AsyncUpdateSlideshow_Impl, Update, void*, pData, void)
3315     {
3316         AsyncUpdateSlideshowData* pSlideData(static_cast<AsyncUpdateSlideshowData*>(pData));
3317         pSlideData->pSlideshowImpl->AsyncNotifyEvent(pSlideData->XCurrentSlide, pSlideData->eHintKind);
3318         delete pSlideData;
3319     }
3320 }
3321 
AsyncNotifyEvent(const uno::Reference<css::drawing::XDrawPage> & rXCurrentSlide,const SdrHintKind eHintKind)3322 void SlideshowImpl::AsyncNotifyEvent(
3323     const uno::Reference< css::drawing::XDrawPage >& rXCurrentSlide,
3324     const SdrHintKind eHintKind)
3325 {
3326     switch (eHintKind)
3327     {
3328         case SdrHintKind::ObjectInserted:
3329         {
3330             mnEventObjectInserted = nullptr;
3331 
3332             // refresh single slide
3333             gotoSlide(rXCurrentSlide);
3334             break;
3335         }
3336         case SdrHintKind::ObjectRemoved:
3337         {
3338             mnEventObjectRemoved = nullptr;
3339 
3340             // refresh single slide
3341             gotoSlide(rXCurrentSlide);
3342             break;
3343         }
3344         case SdrHintKind::ObjectChange:
3345         {
3346             mnEventObjectChange = nullptr;
3347 
3348             // refresh single slide
3349             gotoSlide(rXCurrentSlide);
3350             break;
3351         }
3352         case SdrHintKind::PageOrderChange:
3353         {
3354             mnEventPageOrderChange = nullptr;
3355 
3356             // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
3357             // rXCurrentSlide is the current slide before the change.
3358             Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
3359             Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
3360             const sal_Int32 nNewSlideCount(xSlides.is() ? xSlides->getCount() : 0);
3361 
3362             if (nNewSlideCount != mpSlideController->getSlideNumberCount())
3363             {
3364                 // need to reinitialize AnimationSlideController
3365                 OUString aPresSlide( maPresSettings.maPresPage );
3366                 createSlideList( maPresSettings.mbAll, aPresSlide );
3367             }
3368 
3369             // Check if current slide before change is still valid (maybe removed)
3370             const sal_Int32 nSlideCount(mpSlideController->getSlideNumberCount());
3371             bool bSlideStillValid(false);
3372 
3373             for (sal_Int32 nSlide(0); !bSlideStillValid && nSlide < nSlideCount; nSlide++)
3374             {
3375                 if (rXCurrentSlide == mpSlideController->getSlideByNumber(nSlide))
3376                 {
3377                     bSlideStillValid = true;
3378                 }
3379             }
3380 
3381             if(bSlideStillValid)
3382             {
3383                 // stay on that slide
3384                 gotoSlide(rXCurrentSlide);
3385             }
3386             else
3387             {
3388                 // not possible to stay on that slide, go to 1st slide (kinda restart)
3389                 gotoFirstSlide();
3390             }
3391             break;
3392         }
3393         default:
3394             break;
3395     }
3396 }
3397 
isCurrentSlideInvolved(const SdrHint & rHint)3398 bool SlideshowImpl::isCurrentSlideInvolved(const SdrHint& rHint)
3399 {
3400     // get current slide
3401     uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
3402     if (!XCurrentSlide.is())
3403         return false;
3404 
3405     SdrPage* pCurrentSlide(GetSdrPageFromXDrawPage(XCurrentSlide));
3406     if (nullptr == pCurrentSlide)
3407         return false;
3408 
3409     const SdrPage* pHintPage(rHint.GetPage());
3410     if (nullptr == pHintPage)
3411         return false;
3412 
3413     if (pHintPage->IsMasterPage())
3414     {
3415         if (pCurrentSlide->TRG_HasMasterPage())
3416         {
3417             // current slide uses MasterPage on which the change happened
3418             return pHintPage == &pCurrentSlide->TRG_GetMasterPage();
3419         }
3420     }
3421 
3422     // object on current slide was changed
3423     return pHintPage == pCurrentSlide;
3424 }
3425 
sendHintSlideChanged(const SdrPage * pChangedPage) const3426 void SlideshowImpl::sendHintSlideChanged(const SdrPage* pChangedPage) const
3427 {
3428     if (nullptr == pChangedPage)
3429         return;
3430 
3431     if (!mxShow.is())
3432         return;
3433 
3434     mxShow->setProperty(
3435         beans::PropertyValue( u"HintSlideChanged"_ustr ,
3436             -1,
3437             Any( GetXDrawPageForSdrPage(const_cast<SdrPage*>(pChangedPage)) ),
3438             beans::PropertyState_DIRECT_VALUE ) );
3439 }
3440 
Notify(SfxBroadcaster &,const SfxHint & rHint)3441 void SlideshowImpl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
3442 {
3443     if (SfxHintId::ThisIsAnSdrHint != rHint.GetId())
3444         // nothing to do for non-SdrHints
3445         return;
3446 
3447     if (nullptr == mpDoc)
3448         // better do nothing when no DrawModel (should not happen)
3449         return;
3450 
3451     // tdf#158664 I am surprised, but the 'this' instance keeps incarnated
3452     // when the slideshow was running once, so need to check for
3453     // SlideShow instance/running to be safe.
3454     // NOTE: isRunning() checks mxShow.is(), that is what we want
3455     if (!isRunning())
3456         // no SlideShow instance or not running, nothing to do
3457         return;
3458 
3459     const SdrHint& rSdrHint(static_cast<const SdrHint&>(rHint));
3460     const SdrHintKind eHintKind(rSdrHint.GetKind());
3461 
3462     switch (eHintKind)
3463     {
3464         case SdrHintKind::ObjectInserted:
3465         {
3466             if (nullptr != mnEventObjectInserted)
3467                 // avoid multiple events
3468                 return;
3469 
3470             // tdf#160669 IASS: inform about ALL changed slides due to prefetch
3471             sendHintSlideChanged(rSdrHint.GetPage());
3472 
3473             if (!isCurrentSlideInvolved(rSdrHint))
3474                 // nothing to do when current slide is not involved
3475                 return;
3476 
3477             // Refresh current slide
3478             uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
3479             mnEventObjectInserted = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
3480             break;
3481         }
3482         case SdrHintKind::ObjectRemoved:
3483         {
3484             if (nullptr != mnEventObjectRemoved)
3485                 // avoid multiple events
3486                 return;
3487 
3488             // tdf#160669 IASS: inform about ALL changed slides due to prefetch
3489             sendHintSlideChanged(rSdrHint.GetPage());
3490 
3491             if (!isCurrentSlideInvolved(rSdrHint))
3492                 // nothing to do when current slide is not involved
3493                 return;
3494 
3495             // Refresh current slide
3496             uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
3497             mnEventObjectRemoved = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
3498             break;
3499         }
3500         case SdrHintKind::ObjectChange:
3501         {
3502             if (nullptr != mnEventObjectChange)
3503                 // avoid multiple events
3504                 return;
3505 
3506             // tdf#160669 IASS: inform about ALL changed slides due to prefetch
3507             sendHintSlideChanged(rSdrHint.GetPage());
3508 
3509             if (!isCurrentSlideInvolved(rSdrHint))
3510                 // nothing to do when current slide is not involved
3511                 return;
3512 
3513             // Refresh current slide. Need to do that asynchronous, else e.g.
3514             // text edit changes EditEngine/Outliner are not progressed far
3515             // enough (ObjectChanged broadcast which we are in here seems
3516             // too early for some cases)
3517             uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
3518             mnEventObjectChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
3519             break;
3520         }
3521         case SdrHintKind::PageOrderChange:
3522         {
3523             // Unfortunately we get multiple events, e.g. when drag/drop position change in
3524             // slide sorter on left side of EditView. This includes some with page number +1,
3525             // then again -1 (it's a position change). Problem is that in-between already
3526             // a re-schedule seems to happen, so indeed AsyncNotifyEvent will change to +1/-1
3527             // already. Since we get even more, at least try to take the last one. I found no
3528             // good solution yet for this.
3529             if (nullptr != mnEventPageOrderChange)
3530                 Application::RemoveUserEvent( mnEventPageOrderChange );
3531 
3532             // tdf#160669 IASS: inform about ALL changed slides due to prefetch
3533             sendHintSlideChanged(rSdrHint.GetPage());
3534 
3535             // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
3536             uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
3537             mnEventPageOrderChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
3538             break;
3539         }
3540         case SdrHintKind::ModelCleared:
3541         {
3542             // immediately end presentation
3543             endPresentation();
3544             break;
3545         }
3546         default:
3547             break;
3548     }
3549 }
3550 
getSlideShow()3551 Reference< XSlideShow > SAL_CALL SlideshowImpl::getSlideShow()
3552 {
3553     return mxShow;
3554 }
3555 
PresentationSettingsEx(const PresentationSettingsEx & r)3556 PresentationSettingsEx::PresentationSettingsEx( const PresentationSettingsEx& r )
3557 : PresentationSettings( r )
3558 , mbRehearseTimings(r.mbRehearseTimings)
3559 , mbPreview(r.mbPreview)
3560 , mpParentWindow( nullptr )
3561 {
3562 }
3563 
PresentationSettingsEx(PresentationSettings const & r)3564 PresentationSettingsEx::PresentationSettingsEx( PresentationSettings const & r )
3565 : PresentationSettings( r )
3566 , mbRehearseTimings(false)
3567 , mbPreview(false)
3568 , mpParentWindow(nullptr)
3569 {
3570 }
3571 
SetArguments(const Sequence<PropertyValue> & rArguments)3572 void PresentationSettingsEx::SetArguments( const Sequence< PropertyValue >& rArguments )
3573 {
3574     for( const PropertyValue& rValue : rArguments )
3575     {
3576         SetPropertyValue( rValue.Name, rValue.Value );
3577     }
3578 }
3579 
SetPropertyValue(std::u16string_view rProperty,const Any & rValue)3580 void PresentationSettingsEx::SetPropertyValue( std::u16string_view rProperty, const Any& rValue )
3581 {
3582     if ( rProperty == u"RehearseTimings" )
3583     {
3584         if( rValue >>= mbRehearseTimings )
3585             return;
3586     }
3587     else if ( rProperty == u"Preview" )
3588     {
3589         if( rValue >>= mbPreview )
3590             return;
3591     }
3592     else if ( rProperty == u"AnimationNode" )
3593     {
3594         if( rValue >>= mxAnimationNode )
3595             return;
3596     }
3597     else if ( rProperty == u"ParentWindow" )
3598     {
3599         Reference< XWindow > xWindow;
3600         if( rValue >>= xWindow )
3601         {
3602             mpParentWindow = xWindow.is() ? VCLUnoHelper::GetWindow( xWindow )
3603                                           : nullptr;
3604             return;
3605         }
3606     }
3607     else if ( rProperty == u"AllowAnimations" )
3608     {
3609         if( rValue >>= mbAnimationAllowed )
3610             return;
3611     }
3612     else if ( rProperty == u"FirstPage" )
3613     {
3614         OUString aPresPage;
3615         if( rValue >>= aPresPage )
3616         {
3617             maPresPage = getUiNameFromPageApiNameImpl(aPresPage);
3618             mbCustomShow = false;
3619             mbAll = false;
3620             return;
3621         }
3622         else
3623         {
3624             if( rValue >>= mxStartPage )
3625                 return;
3626         }
3627     }
3628     else if ( rProperty == u"IsAlwaysOnTop" )
3629     {
3630         if( rValue >>= mbAlwaysOnTop )
3631             return;
3632     }
3633     else if ( rProperty == u"IsAutomatic" )
3634     {
3635         if( rValue >>= mbManual )
3636             return;
3637     }
3638     else if ( rProperty == u"IsEndless" )
3639     {
3640         if( rValue >>= mbEndless )
3641             return;
3642     }
3643     else if ( rProperty == u"IsFullScreen" )
3644     {
3645         if( rValue >>= mbFullScreen )
3646             return;
3647     }
3648     else if ( rProperty == u"IsMouseVisible" )
3649     {
3650         if( rValue >>= mbMouseVisible )
3651             return;
3652     }
3653     else if ( rProperty == u"Pause" )
3654     {
3655         sal_Int32 nPause = -1;
3656         if( (rValue >>= nPause) && (nPause >= 0) )
3657         {
3658             mnPauseTimeout = nPause;
3659             return;
3660         }
3661     }
3662     else if ( rProperty == u"UsePen" )
3663     {
3664         if( rValue >>= mbMouseAsPen )
3665             return;
3666     }
3667     throw IllegalArgumentException();
3668 }
3669 
3670 // XAnimationListener
3671 
SlideShowListenerProxy(rtl::Reference<SlideshowImpl> xController,css::uno::Reference<css::presentation::XSlideShow> xSlideShow)3672 SlideShowListenerProxy::SlideShowListenerProxy( rtl::Reference< SlideshowImpl > xController, css::uno::Reference< css::presentation::XSlideShow > xSlideShow )
3673 : mxController(std::move( xController ))
3674 , mxSlideShow(std::move( xSlideShow ))
3675 {
3676 }
3677 
~SlideShowListenerProxy()3678 SlideShowListenerProxy::~SlideShowListenerProxy()
3679 {
3680 }
3681 
addAsSlideShowListener()3682 void SlideShowListenerProxy::addAsSlideShowListener()
3683 {
3684     if( mxSlideShow.is() )
3685     {
3686         Reference< XSlideShowListener > xSlideShowListener( this );
3687         mxSlideShow->addSlideShowListener( xSlideShowListener );
3688     }
3689 }
3690 
removeAsSlideShowListener()3691 void SlideShowListenerProxy::removeAsSlideShowListener()
3692 {
3693     if( mxSlideShow.is() )
3694     {
3695         Reference< XSlideShowListener > xSlideShowListener( this );
3696         mxSlideShow->removeSlideShowListener( xSlideShowListener );
3697     }
3698 }
3699 
addShapeEventListener(const css::uno::Reference<css::drawing::XShape> & xShape)3700 void SlideShowListenerProxy::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape )
3701 {
3702     if( mxSlideShow.is() )
3703     {
3704         Reference< XShapeEventListener > xListener( this );
3705         mxSlideShow->addShapeEventListener( xListener, xShape );
3706     }
3707 }
3708 
removeShapeEventListener(const css::uno::Reference<css::drawing::XShape> & xShape)3709 void SlideShowListenerProxy::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape )
3710 {
3711     if( mxSlideShow.is() )
3712     {
3713         Reference< XShapeEventListener > xListener( this );
3714         mxSlideShow->removeShapeEventListener( xListener, xShape );
3715     }
3716 }
3717 
addSlideShowListener(const css::uno::Reference<css::presentation::XSlideShowListener> & xListener)3718 void SlideShowListenerProxy::addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener )
3719 {
3720     std::unique_lock g(m_aMutex);
3721     maListeners.addInterface(g, xListener);
3722 }
3723 
removeSlideShowListener(const css::uno::Reference<css::presentation::XSlideShowListener> & xListener)3724 void SlideShowListenerProxy::removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener )
3725 {
3726     std::unique_lock g(m_aMutex);
3727     maListeners.removeInterface(g, xListener);
3728 }
3729 
beginEvent(const Reference<XAnimationNode> & xNode)3730 void SAL_CALL SlideShowListenerProxy::beginEvent( const Reference< XAnimationNode >& xNode )
3731 {
3732     std::unique_lock aGuard( m_aMutex );
3733 
3734     if( maListeners.getLength(aGuard) >= 0 )
3735     {
3736         maListeners.forEach(aGuard,
3737             [&] (Reference<XAnimationListener> const& xListener) {
3738                 return xListener->beginEvent(xNode);
3739             } );
3740     }
3741 }
3742 
endEvent(const Reference<XAnimationNode> & xNode)3743 void SAL_CALL SlideShowListenerProxy::endEvent( const Reference< XAnimationNode >& xNode )
3744 {
3745     std::unique_lock aGuard( m_aMutex );
3746 
3747     if( maListeners.getLength(aGuard) >= 0 )
3748     {
3749         maListeners.forEach(aGuard,
3750             [&] (Reference<XAnimationListener> const& xListener) {
3751                 return xListener->endEvent(xNode);
3752             } );
3753     }
3754 }
3755 
repeat(const Reference<XAnimationNode> & xNode,::sal_Int32 nRepeat)3756 void SAL_CALL SlideShowListenerProxy::repeat( const Reference< XAnimationNode >& xNode, ::sal_Int32 nRepeat )
3757 {
3758     std::unique_lock aGuard( m_aMutex );
3759 
3760     if( maListeners.getLength(aGuard) >= 0 )
3761     {
3762         maListeners.forEach(aGuard,
3763             [&] (Reference<XAnimationListener> const& xListener) {
3764                 return xListener->repeat(xNode, nRepeat);
3765             } );
3766     }
3767 }
3768 
3769 // css::presentation::XSlideShowListener:
3770 
paused()3771 void SAL_CALL SlideShowListenerProxy::paused(  )
3772 {
3773     std::unique_lock aGuard( m_aMutex );
3774 
3775     maListeners.forEach(aGuard,
3776         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3777         {
3778             xListener->paused();
3779         });
3780 }
3781 
resumed()3782 void SAL_CALL SlideShowListenerProxy::resumed(  )
3783 {
3784     std::unique_lock aGuard( m_aMutex );
3785 
3786     maListeners.forEach(aGuard,
3787         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3788         {
3789             xListener->resumed();
3790         });
3791 }
3792 
slideTransitionStarted()3793 void SAL_CALL SlideShowListenerProxy::slideTransitionStarted( )
3794 {
3795     std::unique_lock aGuard( m_aMutex );
3796 
3797     maListeners.forEach(aGuard,
3798         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3799         {
3800             xListener->slideTransitionStarted();
3801         });
3802 }
3803 
slideTransitionEnded()3804 void SAL_CALL SlideShowListenerProxy::slideTransitionEnded( )
3805 {
3806     std::unique_lock aGuard( m_aMutex );
3807 
3808     maListeners.forEach(aGuard,
3809         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3810         {
3811             xListener->slideTransitionEnded ();
3812         });
3813 }
3814 
slideAnimationsEnded()3815 void SAL_CALL SlideShowListenerProxy::slideAnimationsEnded(  )
3816 {
3817     std::unique_lock aGuard( m_aMutex );
3818 
3819     maListeners.forEach(aGuard,
3820         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3821         {
3822             xListener->slideAnimationsEnded ();
3823         });
3824 }
3825 
slideEnded(sal_Bool bReverse)3826 void SlideShowListenerProxy::slideEnded(sal_Bool bReverse)
3827 {
3828     {
3829         std::unique_lock aGuard( m_aMutex );
3830 
3831         if( maListeners.getLength(aGuard) >= 0 )
3832         {
3833             maListeners.forEach(aGuard,
3834                 [&] (Reference<XSlideShowListener> const& xListener) {
3835                     return xListener->slideEnded(bReverse);
3836                 } );
3837         }
3838     }
3839 
3840     {
3841         SolarMutexGuard aSolarGuard;
3842         if( mxController.is() )
3843             mxController->slideEnded(bReverse);
3844     }
3845 }
3846 
hyperLinkClicked(OUString const & aHyperLink)3847 void SlideShowListenerProxy::hyperLinkClicked( OUString const& aHyperLink )
3848 {
3849     {
3850         std::unique_lock aGuard( m_aMutex );
3851 
3852         if( maListeners.getLength(aGuard) >= 0 )
3853         {
3854             maListeners.forEach(aGuard,
3855                 [&] (Reference<XSlideShowListener> const& xListener) {
3856                     return xListener->hyperLinkClicked(aHyperLink);
3857                 } );
3858         }
3859     }
3860 
3861     {
3862         SolarMutexGuard aSolarGuard;
3863         if( mxController.is() )
3864             mxController->hyperLinkClicked(aHyperLink);
3865     }
3866 }
3867 
3868 // XEventListener
3869 
disposing(const css::lang::EventObject & aDisposeEvent)3870 void SAL_CALL SlideShowListenerProxy::disposing( const css::lang::EventObject& aDisposeEvent )
3871 {
3872     std::unique_lock g(m_aMutex);
3873     maListeners.disposeAndClear( g, aDisposeEvent );
3874     mxController.clear();
3875     mxSlideShow.clear();
3876 }
3877 
3878 // XShapeEventListener
3879 
click(const Reference<XShape> & xShape,const css::awt::MouseEvent &)3880 void SAL_CALL SlideShowListenerProxy::click( const Reference< XShape >& xShape, const css::awt::MouseEvent& /*aOriginalEvent*/ )
3881 {
3882     SolarMutexGuard aSolarGuard;
3883     if( mxController.is() )
3884         mxController->click(xShape );
3885 }
3886 
contextMenuShow(const css::awt::Point & point)3887 void SAL_CALL SlideShowListenerProxy::contextMenuShow(const css::awt::Point& point)
3888 {
3889     SolarMutexGuard aSolarGuard;
3890     if (mxController.is())
3891         mxController->contextMenuShow(point);
3892 }
3893 
3894 } // namespace ::sd
3895 
3896 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3897