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