1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
24 #include <config_features.h>
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>
46 #include <toolkit/helper/vclunohelper.hxx>
47 #include <comphelper/diagnose_ex.hxx>
48 #include <comphelper/sequence.hxx>
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"
71 #include <bitmaps.hlst>
72 #include <strings.hrc>
73 #include <sdresid.hxx>
75 #include <vcl/canvastools.hxx>
76 #include <vcl/commandevent.hxx>
77 #include <vcl/weldutils.hxx>
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>
98 #include <cusshow.hxx>
99 #include <optsitem.hxx>
100 #include <unomodel.hxx>
104 using ::com::sun::star::animations::XAnimationNode
;
105 using ::com::sun::star::animations::XAnimationListener
;
106 using ::com::sun::star::awt::XWindow
;
107 using namespace ::com::sun::star
;
108 using namespace ::com::sun::star::lang
;
109 using namespace ::com::sun::star::uno
;
110 using namespace ::com::sun::star::drawing
;
111 using namespace ::com::sun::star::container
;
112 using namespace ::com::sun::star::presentation
;
113 using namespace ::com::sun::star::beans
;
117 /** Slots, which will be disabled in the slide show and are managed by Sfx.
118 Have to be sorted in the order of the SIDs */
119 sal_uInt16
const pAllowed
[] =
121 SID_OPENDOC
, // 5501 ///< that internally jumps work
122 SID_JUMPTOMARK
, // 5598
123 SID_OPENHYPERLINK
, // 6676
124 SID_PRESENTATION_END
// 27218
127 class AnimationSlideController
130 enum Mode
{ ALL
, FROM
, CUSTOM
, PREVIEW
};
133 AnimationSlideController( Reference
< XIndexAccess
> const & xSlides
, Mode eMode
);
135 void setStartSlideNumber( sal_Int32 nSlideNumber
) { mnStartSlideNumber
= nSlideNumber
; }
136 sal_Int32
getStartSlideIndex() const;
138 sal_Int32
getCurrentSlideNumber() const;
139 sal_Int32
getCurrentSlideIndex() const;
141 sal_Int32
getSlideIndexCount() const { return maSlideNumbers
.size(); }
142 sal_Int32
getSlideNumberCount() const { return mnSlideCount
; }
144 sal_Int32
getSlideNumber( sal_Int32 nSlideIndex
) const;
146 void insertSlideNumber( sal_Int32 nSlideNumber
, bool bVisible
= true );
147 void setPreviewNode( const Reference
< XAnimationNode
>& xPreviewNode
);
149 bool jumpToSlideIndex( sal_Int32 nNewSlideIndex
);
150 bool jumpToSlideNumber( sal_Int32 nNewSlideIndex
);
153 bool previousSlide();
155 void displayCurrentSlide( const Reference
< XSlideShow
>& xShow
,
156 const Reference
< XDrawPagesSupplier
>& xDrawPages
,
157 const bool bSkipAllMainSequenceEffects
);
159 sal_Int32
getNextSlideIndex() const;
160 sal_Int32
getPreviousSlideIndex() const;
162 bool isVisibleSlideNumber( sal_Int32 nSlideNumber
) const;
164 Reference
< XDrawPage
> getSlideByNumber( sal_Int32 nSlideNumber
) const;
166 sal_Int32
getNextSlideNumber() const;
168 bool hasSlides() const { return !maSlideNumbers
.empty(); }
170 // for InteractiveSlideShow we need to temporarily change the program
171 // and mode, so allow save/restore that settings
172 void pushForPreview();
173 void popFromPreview();
175 bool getSlideAPI( sal_Int32 nSlideNumber
, Reference
< XDrawPage
>& xSlide
, Reference
< XAnimationNode
>& xAnimNode
);
176 sal_Int32
findSlideIndex( sal_Int32 nSlideNumber
) const;
178 bool isValidIndex( sal_Int32 nIndex
) const { return (nIndex
>= 0) && (o3tl::make_unsigned(nIndex
) < maSlideNumbers
.size()); }
179 bool isValidSlideNumber( sal_Int32 nSlideNumber
) const { return (nSlideNumber
>= 0) && (nSlideNumber
< mnSlideCount
); }
183 sal_Int32 mnStartSlideNumber
;
184 std::vector
< sal_Int32
> maSlideNumbers
;
185 std::vector
< bool > maSlideVisible
;
186 std::vector
< bool > maSlideVisited
;
187 Reference
< XAnimationNode
> mxPreviewNode
;
188 sal_Int32 mnSlideCount
;
189 sal_Int32 mnCurrentSlideIndex
;
190 sal_Int32 mnHiddenSlideNumber
;
191 Reference
< XIndexAccess
> mxSlides
;
193 // IASS data for push/pop
194 std::vector
< sal_Int32
> maSlideNumbers2
;
195 std::vector
< bool > maSlideVisible2
;
196 std::vector
< bool > maSlideVisited2
;
197 Reference
< XAnimationNode
> mxPreviewNode2
;
201 void AnimationSlideController::pushForPreview()
203 maSlideNumbers2
= maSlideNumbers
;
204 maSlideVisible2
= maSlideVisible
;
205 maSlideVisited2
= maSlideVisited
;
206 maSlideNumbers
.clear();
207 maSlideVisible
.clear();
208 maSlideVisited
.clear();
209 mxPreviewNode2
= mxPreviewNode
;
211 meMode
= AnimationSlideController::PREVIEW
;
214 void AnimationSlideController::popFromPreview()
216 maSlideNumbers
= maSlideNumbers2
;
217 maSlideVisible
= maSlideVisible2
;
218 maSlideVisited
= maSlideVisited2
;
219 maSlideNumbers2
.clear();
220 maSlideVisible2
.clear();
221 maSlideVisited2
.clear();
222 mxPreviewNode
= mxPreviewNode2
;
226 Reference
< XDrawPage
> AnimationSlideController::getSlideByNumber( sal_Int32 nSlideNumber
) const
228 Reference
< XDrawPage
> xSlide
;
229 if( mxSlides
.is() && (nSlideNumber
>= 0) && (nSlideNumber
< mxSlides
->getCount()) )
230 mxSlides
->getByIndex( nSlideNumber
) >>= xSlide
;
234 bool AnimationSlideController::isVisibleSlideNumber( sal_Int32 nSlideNumber
) const
236 sal_Int32 nIndex
= findSlideIndex( nSlideNumber
);
239 return maSlideVisible
[ nIndex
];
244 void AnimationSlideController::setPreviewNode( const Reference
< XAnimationNode
>& xPreviewNode
)
246 mxPreviewNode
= xPreviewNode
;
249 AnimationSlideController::AnimationSlideController( Reference
< XIndexAccess
> const & xSlides
, Mode eMode
)
251 , mnStartSlideNumber(-1)
253 , mnCurrentSlideIndex(0)
254 , mnHiddenSlideNumber( -1 )
255 , mxSlides( xSlides
)
259 mnSlideCount
= xSlides
->getCount();
262 sal_Int32
AnimationSlideController::getStartSlideIndex() const
264 if( mnStartSlideNumber
>= 0 )
267 const sal_Int32 nCount
= maSlideNumbers
.size();
269 for( nIndex
= 0; nIndex
< nCount
; nIndex
++ )
271 if( maSlideNumbers
[nIndex
] == mnStartSlideNumber
)
279 sal_Int32
AnimationSlideController::getCurrentSlideNumber() const
281 if( mnHiddenSlideNumber
!= -1 )
282 return mnHiddenSlideNumber
;
283 else if( !maSlideNumbers
.empty() )
284 return maSlideNumbers
[mnCurrentSlideIndex
];
289 sal_Int32
AnimationSlideController::getCurrentSlideIndex() const
291 if( mnHiddenSlideNumber
!= -1 )
294 return mnCurrentSlideIndex
;
297 bool AnimationSlideController::jumpToSlideIndex( sal_Int32 nNewSlideIndex
)
299 if( isValidIndex( nNewSlideIndex
) )
301 mnCurrentSlideIndex
= nNewSlideIndex
;
302 mnHiddenSlideNumber
= -1;
303 maSlideVisited
[mnCurrentSlideIndex
] = true;
312 bool AnimationSlideController::jumpToSlideNumber( sal_Int32 nNewSlideNumber
)
314 sal_Int32 nIndex
= findSlideIndex( nNewSlideNumber
);
315 if( isValidIndex( nIndex
) )
317 return jumpToSlideIndex( nIndex
);
319 else if( (nNewSlideNumber
>= 0) && (nNewSlideNumber
< mnSlideCount
) )
321 // jump to a hidden slide
322 mnHiddenSlideNumber
= nNewSlideNumber
;
331 sal_Int32
AnimationSlideController::getSlideNumber( sal_Int32 nSlideIndex
) const
333 if( isValidIndex( nSlideIndex
) )
334 return maSlideNumbers
[nSlideIndex
];
339 void AnimationSlideController::insertSlideNumber( sal_Int32 nSlideNumber
, bool bVisible
/* = true */ )
341 DBG_ASSERT( isValidSlideNumber( nSlideNumber
), "sd::AnimationSlideController::insertSlideNumber(), illegal index" );
342 if( isValidSlideNumber( nSlideNumber
) )
344 maSlideNumbers
.push_back( nSlideNumber
);
345 maSlideVisible
.push_back( bVisible
);
346 maSlideVisited
.push_back( false );
350 bool AnimationSlideController::getSlideAPI( sal_Int32 nSlideNumber
, Reference
< XDrawPage
>& xSlide
, Reference
< XAnimationNode
>& xAnimNode
)
352 if( isValidSlideNumber( nSlideNumber
) ) try
354 xSlide
.set( mxSlides
->getByIndex(nSlideNumber
), UNO_QUERY_THROW
);
356 if( meMode
== PREVIEW
)
358 xAnimNode
= mxPreviewNode
;
362 Reference
< animations::XAnimationNodeSupplier
> xAnimNodeSupplier( xSlide
, UNO_QUERY_THROW
);
363 xAnimNode
= xAnimNodeSupplier
->getAnimationNode();
370 TOOLS_WARN_EXCEPTION( "sd", "sd::AnimationSlideController::getSlideAPI()" );
376 sal_Int32
AnimationSlideController::findSlideIndex( sal_Int32 nSlideNumber
) const
379 const sal_Int32 nCount
= maSlideNumbers
.size();
381 for( nIndex
= 0; nIndex
< nCount
; nIndex
++ )
383 if( maSlideNumbers
[nIndex
] == nSlideNumber
)
390 sal_Int32
AnimationSlideController::getNextSlideIndex() const
396 sal_Int32 nNewSlideIndex
= mnCurrentSlideIndex
+ 1;
397 if( isValidIndex( nNewSlideIndex
) )
399 // if the current slide is not excluded, make sure the
400 // next slide is also not excluded.
401 // if the current slide is excluded, we want to go
402 // to the next slide, even if this is also excluded.
403 if( maSlideVisible
[mnCurrentSlideIndex
] )
405 while( isValidIndex( nNewSlideIndex
) )
407 if( maSlideVisible
[nNewSlideIndex
] )
414 return isValidIndex( nNewSlideIndex
) ? nNewSlideIndex
: -1;
419 return mnHiddenSlideNumber
== -1 ? mnCurrentSlideIndex
+ 1 : mnCurrentSlideIndex
;
428 sal_Int32
AnimationSlideController::getNextSlideNumber() const
430 sal_Int32 nNextSlideIndex
= getNextSlideIndex();
431 if( isValidIndex( nNextSlideIndex
) )
433 return maSlideNumbers
[nNextSlideIndex
];
441 bool AnimationSlideController::nextSlide()
443 return jumpToSlideIndex( getNextSlideIndex() );
446 sal_Int32
AnimationSlideController::getPreviousSlideIndex() const
448 sal_Int32 nNewSlideIndex
= mnCurrentSlideIndex
- 1;
454 // make sure the previous slide is visible
455 // or was already visited
456 while( isValidIndex( nNewSlideIndex
) )
458 if( maSlideVisible
[nNewSlideIndex
] || maSlideVisited
[nNewSlideIndex
] )
474 return nNewSlideIndex
;
477 bool AnimationSlideController::previousSlide()
479 return jumpToSlideIndex( getPreviousSlideIndex() );
482 void AnimationSlideController::displayCurrentSlide( const Reference
< XSlideShow
>& xShow
,
483 const Reference
< XDrawPagesSupplier
>& xDrawPages
,
484 const bool bSkipAllMainSequenceEffects
)
486 const sal_Int32 nCurrentSlideNumber
= getCurrentSlideNumber();
488 if( !(xShow
.is() && (nCurrentSlideNumber
!= -1 )) )
491 Reference
< XDrawPage
> xSlide
;
492 Reference
< XAnimationNode
> xAnimNode
;
493 ::std::vector
<PropertyValue
> aProperties
;
495 const sal_Int32 nNextSlideNumber
= getNextSlideNumber();
496 if( getSlideAPI( nNextSlideNumber
, xSlide
, xAnimNode
) )
498 Sequence
< Any
> aValue
{ Any(xSlide
), Any(xAnimNode
) };
499 aProperties
.emplace_back( "Prefetch" ,
502 PropertyState_DIRECT_VALUE
);
504 if (bSkipAllMainSequenceEffects
)
506 // Add one property that prevents the slide transition from being
507 // shown (to speed up the transition to the previous slide) and
508 // one to show all main sequence effects so that the user can
509 // continue to undo effects.
510 aProperties
.emplace_back( "SkipAllMainSequenceEffects",
513 PropertyState_DIRECT_VALUE
);
514 aProperties
.emplace_back("SkipSlideTransition",
517 PropertyState_DIRECT_VALUE
);
520 if( getSlideAPI( nCurrentSlideNumber
, xSlide
, xAnimNode
) )
521 xShow
->displaySlide( xSlide
, xDrawPages
, xAnimNode
, comphelper::containerToSequence(aProperties
) );
524 constexpr OUString
gsOnClick( u
"OnClick"_ustr
);
525 constexpr OUString
gsBookmark( u
"Bookmark"_ustr
);
526 constexpr OUString
gsVerb( u
"Verb"_ustr
);
528 SlideshowImpl::SlideshowImpl( const Reference
< XPresentation2
>& xPresentation
, ViewShell
* pViewSh
, ::sd::View
* pView
, SdDrawDocument
* pDoc
, vcl::Window
* pParentWindow
)
531 , mxModel(pDoc
->getUnoModel())
532 , maUpdateTimer("SlideShowImpl maUpdateTimer")
533 , maInputFreezeTimer("SlideShowImpl maInputFreezeTimer")
534 , maDeactivateTimer("SlideShowImpl maDeactivateTimer")
536 , mpViewShell(pViewSh
)
537 , mpDocSh(pDoc
->GetDocSh())
539 , mpParentWindow(pParentWindow
)
540 , mpShowWindow(nullptr)
541 , mpSlideController()
544 , maPresSize( -1, -1 )
545 , meAnimationMode(ANIMATIONMODE_SHOW
)
547 , mpOldActiveWindow(nullptr)
548 , maStarBASICGlobalErrorHdl()
551 , mbAutoSaveWasOn(false)
552 , mbRehearseTimings(false)
555 , mbInputFreeze(false)
557 , maPresSettings( pDoc
->getPresentationSettings() )
558 , mnUserPaintColor( 0x80ff0000L
)
560 , mdUserPaintStrokeWidth ( 150.0 )
562 , mxPreviewDrawPage()
563 , mxPreviewAnimationNode()
566 , mnEndShowEvent(nullptr)
567 , mnContextMenuEvent(nullptr)
568 , mnEventObjectChange(nullptr)
569 , mnEventObjectInserted(nullptr)
570 , mnEventObjectRemoved(nullptr)
571 , mnEventPageOrderChange(nullptr)
572 , mxPresentation( xPresentation
)
577 , mbInterActiveSetup(false)
579 , mxPreviewDrawPage2()
580 , mxPreviewAnimationNode2()
584 mpOldActiveWindow
= mpViewShell
->GetActiveWindow();
586 maUpdateTimer
.SetInvokeHandler(LINK(this, SlideshowImpl
, updateHdl
));
587 // Priority must not be too high or we'll starve input handling etc.
588 maUpdateTimer
.SetPriority(TaskPriority::REPAINT
);
590 maDeactivateTimer
.SetInvokeHandler(LINK(this, SlideshowImpl
, deactivateHdl
));
591 maDeactivateTimer
.SetTimeout( 20 );
593 maInputFreezeTimer
.SetInvokeHandler( LINK( this, SlideshowImpl
, ReadyForNextInputHdl
) );
594 maInputFreezeTimer
.SetTimeout( 20 );
596 // no autosave during show
597 if (officecfg::Office::Recovery::AutoSave::Enabled::get())
598 mbAutoSaveWasOn
= true;
600 Application::AddEventListener( LINK( this, SlideshowImpl
, EventListenerHdl
) );
602 mbUsePen
= maPresSettings
.mbMouseAsPen
;
604 SdOptions
* pOptions
= SdModule::get()->GetSdOptions(DocumentType::Impress
);
607 mnUserPaintColor
= pOptions
->GetPresentationPenColor();
608 mdUserPaintStrokeWidth
= pOptions
->GetPresentationPenWidth();
611 // to be able to react on various changes in the DrawModel, this class
612 // is now derived from SfxListener and registers itself at the DrawModel
613 if (nullptr != mpDoc
)
614 StartListening(*mpDoc
);
617 SlideshowImpl::~SlideshowImpl()
619 // stop listening to DrawModel (see above)
620 if (nullptr != mpDoc
)
621 EndListening(*mpDoc
);
623 SdModule
* pModule
= SdModule::get();
624 //rhbz#806663 SlideshowImpl can outlive SdModule
625 SdOptions
* pOptions
= pModule
?
626 pModule
->GetSdOptions(DocumentType::Impress
) : nullptr;
629 pOptions
->SetPresentationPenColor(mnUserPaintColor
);
630 pOptions
->SetPresentationPenWidth(mdUserPaintStrokeWidth
);
633 Application::RemoveEventListener( LINK( this, SlideshowImpl
, EventListenerHdl
) );
635 maDeactivateTimer
.Stop();
639 OSL_FAIL("SlideshowImpl::~SlideshowImpl(), component was not disposed!");
640 std::unique_lock
g(m_aMutex
);
645 void SlideshowImpl::disposing(std::unique_lock
<std::mutex
>&)
647 #ifdef ENABLE_SDREMOTE
648 RemoteServer::presentationStopped();
650 // IASS: This is the central methodology to 'steer' the
651 // PresenterConsole - in this case, to shut it down
652 if( mxShow
.is() && mpDoc
)
655 u
"OnEndPresentation"_ustr
);
657 if( mbAutoSaveWasOn
)
658 setAutoSaveState( true );
661 Application::RemoveUserEvent( mnEndShowEvent
);
662 if( mnContextMenuEvent
)
663 Application::RemoveUserEvent( mnContextMenuEvent
);
664 if( mnEventObjectChange
)
665 Application::RemoveUserEvent( mnEventObjectChange
);
666 if( mnEventObjectInserted
)
667 Application::RemoveUserEvent( mnEventObjectInserted
);
668 if( mnEventObjectRemoved
)
669 Application::RemoveUserEvent( mnEventObjectRemoved
);
670 if( mnEventPageOrderChange
)
671 Application::RemoveUserEvent( mnEventPageOrderChange
);
673 maInputFreezeTimer
.Stop();
675 SolarMutexGuard aSolarGuard
;
680 if( mxPresentation
.is() )
681 mxPresentation
->end();
683 maUpdateTimer
.Stop();
687 if( mxListenerProxy
.is() )
688 mxListenerProxy
->removeAsSlideShowListener();
693 mxShow
->removeView( mxView
);
695 Reference
< XComponent
> xComponent( mxShow
, UNO_QUERY
);
696 if( xComponent
.is() )
697 xComponent
->dispose();
704 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" );
709 mxListenerProxy
.clear();
710 mpSlideController
.reset();
712 // take DrawView from presentation window, but give the old window back
713 if( mpShowWindow
&& mpView
)
714 mpView
->DeleteDeviceFromPaintView( *mpShowWindow
->GetOutDev() );
717 mpView
->SetAnimationPause( false );
721 mpViewShell
->SetActiveWindow(mpOldActiveWindow
);
723 mpShowWindow
->SetViewShell( nullptr );
727 mpView
->InvalidateAllWin();
729 if( maPresSettings
.mbFullScreen
)
731 #if HAVE_FEATURE_SCRIPTING
732 // restore StarBASICErrorHdl
733 StarBASIC::SetGlobalErrorHdl(maStarBASICGlobalErrorHdl
);
734 maStarBASICGlobalErrorHdl
= Link
<StarBASIC
*,bool>();
740 mpShowWindow
->Hide();
743 if( meAnimationMode
== ANIMATIONMODE_SHOW
)
745 mpDocSh
->SetSlotFilter();
746 mpDocSh
->ApplySlotFilter();
748 Help::EnableContextHelp();
749 Help::EnableExtHelp();
755 // show current window again
756 if( mpViewShell
&& dynamic_cast< PresentationViewShell
*>( mpViewShell
) == nullptr)
758 if( meAnimationMode
== ANIMATIONMODE_SHOW
)
760 mpViewShell
->GetViewShellBase().ShowUIControls (true);
763 else if( meAnimationMode
== ANIMATIONMODE_PREVIEW
)
765 mpViewShell
->ShowUIControls(true);
770 mpShowWindow
->Hide();
771 mpShowWindow
.disposeAndClear();
775 if( meAnimationMode
== ANIMATIONMODE_SHOW
)
777 ::sd::Window
* pActWin
= mpViewShell
->GetActiveWindow();
781 Size aVisSizePixel
= pActWin
->GetOutputSizePixel();
782 ::tools::Rectangle aVisAreaWin
= pActWin
->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel
) );
783 mpViewShell
->VisAreaChanged(aVisAreaWin
);
785 mpView
->VisAreaChanged(pActWin
->GetOutDev());
786 pActWin
->GrabFocus();
790 // restart the custom show dialog if he started us
791 if( mpViewShell
->IsStartShowWithDialog() && getDispatcher() )
793 mpViewShell
->SetStartShowWithDialog( false );
794 getDispatcher()->Execute( SID_CUSTOMSHOW_DLG
, SfxCallMode::ASYNCHRON
| SfxCallMode::RECORD
);
797 mpViewShell
->GetViewShellBase().UpdateBorder(true);
802 mpShowWindow
.disposeAndClear();
805 setActiveXToolbarsVisible( true );
810 bool SlideshowImpl::isInteractiveSetup() const
812 return mbInterActiveSetup
;
815 void SlideshowImpl::startInteractivePreview( const Reference
< XDrawPage
>& xDrawPage
, const Reference
< XAnimationNode
>& xAnimationNode
)
817 // set flag that we are in IASS mode
818 mbInterActiveSetup
= true;
820 // save stuff that will be replaced temporarily
823 mxPreviewDrawPage2
= mxPreviewDrawPage
;
824 mxPreviewAnimationNode2
= mxPreviewAnimationNode
;
825 meAnimationMode2
= meAnimationMode
;
826 maPresSettings2
= maPresSettings
;
828 // remember slide shown before preview
829 mnSlideIndex
= getCurrentSlideIndex();
831 // set DrawPage/AnimationNode
832 mxPreviewDrawPage
= xDrawPage
;
833 mxPreviewAnimationNode
= xAnimationNode
;
834 meAnimationMode
= ANIMATIONMODE_PREVIEW
;
836 // set PresSettings for preview
837 maPresSettings
.mbAll
= false;
838 maPresSettings
.mbEndless
= false;
839 maPresSettings
.mbCustomShow
= false;
840 maPresSettings
.mbManual
= false;
841 maPresSettings
.mbMouseVisible
= false;
842 maPresSettings
.mbMouseAsPen
= false;
843 maPresSettings
.mbLockedPages
= false;
844 maPresSettings
.mbAlwaysOnTop
= false;
845 maPresSettings
.mbFullScreen
= false;
846 maPresSettings
.mbAnimationAllowed
= true;
847 maPresSettings
.mnPauseTimeout
= 0;
848 maPresSettings
.mbShowPauseLogo
= false;
850 // create a new temporary AnimationSlideController
851 mpSlideController
->pushForPreview();
852 // Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
853 // Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
854 // mpSlideController = std::make_shared<AnimationSlideController>( xSlides, AnimationSlideController::PREVIEW );
855 sal_Int32 nSlideNumber
= 0;
856 Reference
< XPropertySet
> xSet( xDrawPage
, UNO_QUERY_THROW
);
857 xSet
->getPropertyValue( u
"Number"_ustr
) >>= nSlideNumber
;
858 mpSlideController
->insertSlideNumber( nSlideNumber
-1 );
859 mpSlideController
->setPreviewNode( xAnimationNode
);
861 // prepare properties
862 sal_Int32 nPropertyCount
= 1;
863 if( xAnimationNode
.is() )
865 Sequence
< beans::PropertyValue
> aProperties(nPropertyCount
);
866 auto pProperties
= aProperties
.getArray();
867 pProperties
[0].Name
= "AutomaticAdvancement";
868 pProperties
[0].Value
<<= 1.0; // one second timeout
870 if( xAnimationNode
.is() )
872 pProperties
[1].Name
= "NoSlideTransitions";
873 pProperties
[1].Value
<<= true;
877 startShowImpl( aProperties
);
880 void SlideshowImpl::endInteractivePreview()
882 if (!mbInterActiveSetup
)
883 // not in use, nothing to do
890 mxShow
->removeView( mxView
);
892 Reference
< XComponent
> xComponent( mxShow
, UNO_QUERY
);
893 if( xComponent
.is() )
894 xComponent
->dispose();
901 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" );
908 // restore SlideController
909 mpSlideController
->popFromPreview();
911 // restore other settings and cleanup temporary incarnations
912 maPresSettings
= maPresSettings2
;
913 meAnimationMode
= meAnimationMode2
;
914 mxPreviewAnimationNode
= mxPreviewAnimationNode2
;
915 mxPreviewAnimationNode2
.clear();
916 mxPreviewDrawPage
= mxPreviewDrawPage2
;
917 mxPreviewDrawPage2
.clear();
919 // go back to slide shown before preview
920 gotoSlideIndex(mnSlideIndex
);
922 // reset IASS mode flag
923 mbInterActiveSetup
= false;
926 bool SlideshowImpl::startPreview(
927 const Reference
< XDrawPage
>& xDrawPage
,
928 const Reference
< XAnimationNode
>& xAnimationNode
,
929 vcl::Window
* pParent
)
935 const Reference
<lang::XServiceInfo
> xServiceInfo( xDrawPage
, UNO_QUERY
);
936 if (xServiceInfo
.is()) {
937 const Sequence
<OUString
> supportedServices(
938 xServiceInfo
->getSupportedServiceNames() );
939 if (comphelper::findValue(supportedServices
, "com.sun.star.drawing.MasterPage") != -1) {
940 OSL_FAIL("sd::SlideshowImpl::startPreview() "
941 "not allowed on master page!");
946 mxPreviewDrawPage
= xDrawPage
;
947 mxPreviewAnimationNode
= xAnimationNode
;
948 meAnimationMode
= ANIMATIONMODE_PREVIEW
;
950 maPresSettings
.mbAll
= false;
951 maPresSettings
.mbEndless
= false;
952 maPresSettings
.mbCustomShow
= false;
953 maPresSettings
.mbManual
= false;
954 maPresSettings
.mbMouseVisible
= false;
955 maPresSettings
.mbMouseAsPen
= false;
956 maPresSettings
.mbLockedPages
= false;
957 maPresSettings
.mbAlwaysOnTop
= false;
958 maPresSettings
.mbFullScreen
= false;
959 maPresSettings
.mbAnimationAllowed
= true;
960 maPresSettings
.mnPauseTimeout
= 0;
961 maPresSettings
.mbShowPauseLogo
= false;
963 rtl::Reference
< SdXImpressDocument
> xDrawPages( mpDoc
->getUnoModel() );
964 Reference
< XIndexAccess
> xSlides( xDrawPages
->getDrawPages(), UNO_QUERY_THROW
);
965 mpSlideController
= std::make_shared
<AnimationSlideController
>( xSlides
, AnimationSlideController::PREVIEW
);
967 sal_Int32 nSlideNumber
= 0;
968 Reference
< XPropertySet
> xSet( mxPreviewDrawPage
, UNO_QUERY_THROW
);
969 xSet
->getPropertyValue( u
"Number"_ustr
) >>= nSlideNumber
;
970 mpSlideController
->insertSlideNumber( nSlideNumber
-1 );
971 mpSlideController
->setPreviewNode( xAnimationNode
);
973 mpShowWindow
= VclPtr
<ShowWindow
>::Create( this, ((pParent
== nullptr) && mpViewShell
) ? mpParentWindow
.get() : pParent
);
976 mpViewShell
->SetActiveWindow( mpShowWindow
);
977 mpShowWindow
->SetViewShell (mpViewShell
);
978 mpViewShell
->ShowUIControls (false);
983 mpView
->AddDeviceToPaintView( *mpShowWindow
->GetOutDev(), nullptr );
984 mpView
->SetAnimationPause( true );
987 // call resize handler
990 maPresSize
= pParent
->GetSizePixel();
992 else if( mpViewShell
)
994 ::tools::Rectangle
aContentRect (mpViewShell
->GetViewShellBase().getClientRectangle());
995 if (AllSettings::GetLayoutRTL())
997 aContentRect
.SetLeft( aContentRect
.Right() );
998 aContentRect
.AdjustRight(aContentRect
.Right() );
1000 maPresSize
= aContentRect
.GetSize();
1001 mpShowWindow
->SetPosPixel( aContentRect
.TopLeft() );
1005 OSL_FAIL("sd::SlideshowImpl::startPreview(), I need either a parent window or a viewshell!");
1007 resize( maPresSize
);
1009 sal_Int32 nPropertyCount
= 1;
1010 if( mxPreviewAnimationNode
.is() )
1013 Sequence
< beans::PropertyValue
> aProperties(nPropertyCount
);
1014 auto pProperties
= aProperties
.getArray();
1015 pProperties
[0].Name
= "AutomaticAdvancement";
1016 pProperties
[0].Value
<<= 1.0; // one second timeout
1018 if( mxPreviewAnimationNode
.is() )
1020 pProperties
[1].Name
= "NoSlideTransitions";
1021 pProperties
[1].Value
<<= true;
1024 bRet
= startShowImpl( aProperties
);
1026 if( mpShowWindow
!= nullptr && meAnimationMode
== ANIMATIONMODE_PREVIEW
)
1027 mpShowWindow
->SetPreviewMode();
1032 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startPreview()" );
1039 bool SlideshowImpl::startShow( PresentationSettingsEx
const * pPresSettings
)
1041 const rtl::Reference
<SlideshowImpl
> xKeepAlive(this);
1043 DBG_ASSERT( !mxShow
.is(), "sd::SlideshowImpl::startShow(), called twice!" );
1046 DBG_ASSERT( mpParentWindow
!=nullptr, "sd::SlideshowImpl::startShow() called without parent window" );
1047 if (mpParentWindow
== nullptr)
1050 // Autoplay (pps/ppsx)
1051 if (mpViewShell
->GetDoc()->GetStartWithPresentation())
1053 mpViewShell
->GetDoc()->SetExitAfterPresenting(true);
1062 maPresSettings
= *pPresSettings
;
1063 mbRehearseTimings
= pPresSettings
->mbRehearseTimings
;
1066 OUString
aPresSlide( maPresSettings
.maPresPage
);
1067 SdPage
* pStartPage
= mpViewShell
->GetActualPage();
1068 bool bStartWithActualSlide
= pStartPage
;
1070 // times should be measured?
1071 if( mbRehearseTimings
)
1073 maPresSettings
.mbEndless
= false;
1074 maPresSettings
.mbManual
= true;
1075 maPresSettings
.mbMouseVisible
= true;
1076 maPresSettings
.mbMouseAsPen
= false;
1077 maPresSettings
.mnPauseTimeout
= 0;
1078 maPresSettings
.mbShowPauseLogo
= false;
1083 if( pStartPage
->GetPageKind() == PageKind::Notes
)
1085 // we are in notes page mode, so get
1086 // the corresponding draw page
1087 const sal_uInt16 nNotePgNum
= pStartPage
->GetPageNum();
1088 assert(nNotePgNum
>= 2);
1089 const sal_uInt16 nPgNum
= ( nNotePgNum
- 2 ) >> 1;
1090 pStartPage
= mpDoc
->GetSdPage( nPgNum
, PageKind::Standard
);
1094 if( bStartWithActualSlide
)
1096 if ( aPresSlide
.isEmpty())
1098 // no preset slide yet, so pick current on one
1099 aPresSlide
= pStartPage
->GetName();
1100 // if the starting slide is hidden, we can't set slide controller to ALL mode
1101 maPresSettings
.mbAll
= !pStartPage
->IsExcluded();
1104 if( meAnimationMode
!= ANIMATIONMODE_SHOW
)
1106 if( pStartPage
->GetPageKind() == PageKind::Standard
)
1108 maPresSettings
.mbAll
= false;
1114 createSlideList( maPresSettings
.mbAll
, aPresSlide
);
1116 // remember Slide number from where the show was started
1118 mnRestoreSlide
= ( pStartPage
->GetPageNum() - 1 ) / 2;
1120 if( mpSlideController
->hasSlides() )
1122 // hide child windows
1125 mpShowWindow
= VclPtr
<ShowWindow
>::Create( this, mpParentWindow
);
1126 mpShowWindow
->SetMouseAutoHide( !maPresSettings
.mbMouseVisible
);
1127 mpViewShell
->SetActiveWindow( mpShowWindow
);
1128 mpShowWindow
->SetViewShell (mpViewShell
);
1129 mpViewShell
->GetViewShellBase().ShowUIControls (false);
1130 // Hide the side panes for in-place presentations.
1131 if ( ! maPresSettings
.mbFullScreen
)
1132 mpPaneHider
.reset(new PaneHider(*mpViewShell
,this));
1134 // these Slots are forbidden in other views for this document
1135 if( mpDocSh
&& pPresSettings
&& !pPresSettings
->mbInteractive
) // IASS
1137 mpDocSh
->SetSlotFilter( true, pAllowed
);
1138 mpDocSh
->ApplySlotFilter();
1141 Help::DisableContextHelp();
1142 Help::DisableExtHelp();
1144 if( maPresSettings
.mbFullScreen
)
1146 #if HAVE_FEATURE_SCRIPTING
1147 // disable basic ide error handling
1148 maStarBASICGlobalErrorHdl
= StarBASIC::GetGlobalErrorHdl();
1149 StarBASIC::SetGlobalErrorHdl( Link
<StarBASIC
*,bool>() );
1153 // call resize handler
1154 maPresSize
= mpParentWindow
->GetSizePixel();
1155 if (!maPresSettings
.mbFullScreen
)
1157 const ::tools::Rectangle
& aClientRect
= mpViewShell
->GetViewShellBase().getClientRectangle();
1158 maPresSize
= aClientRect
.GetSize();
1159 mpShowWindow
->SetPosPixel( aClientRect
.TopLeft() );
1160 resize( maPresSize
);
1164 // Note: In FullScreen Mode the OS (window manager) sends a resize to
1165 // the WorkWindow once it actually resized it to full size. The
1166 // WorkWindow propagates the resize to the DrawViewShell which calls
1167 // resize() at the SlideShow (this). Calling resize here results in a
1168 // temporary display of a black window in the window's default size
1172 mpView
->AddDeviceToPaintView( *mpShowWindow
->GetOutDev(), nullptr );
1173 mpView
->SetAnimationPause( true );
1176 SfxBindings
* pBindings
= getBindings();
1179 pBindings
->Invalidate( SID_PRESENTATION
);
1180 pBindings
->Invalidate( SID_REHEARSE_TIMINGS
);
1183 // Defer the sd::ShowWindow's GrabFocus to SlideShow::activate. so that the accessible event can be fired correctly.
1184 //mpShowWindow->GrabFocus();
1186 std::vector
<beans::PropertyValue
> aProperties
;
1187 aProperties
.reserve( 4 );
1189 aProperties
.emplace_back( "AdvanceOnClick" ,
1190 -1, Any( !maPresSettings
.mbLockedPages
),
1191 beans::PropertyState_DIRECT_VALUE
);
1193 aProperties
.emplace_back( "ImageAnimationsAllowed" ,
1194 -1, Any( maPresSettings
.mbAnimationAllowed
),
1195 beans::PropertyState_DIRECT_VALUE
);
1197 const bool bZOrderEnabled(
1198 SdModule::get()->GetSdOptions( mpDoc
->GetDocumentType() )->IsSlideshowRespectZOrder() );
1199 aProperties
.emplace_back( "DisableAnimationZOrder" ,
1200 -1, Any( !bZOrderEnabled
),
1201 beans::PropertyState_DIRECT_VALUE
);
1203 aProperties
.emplace_back( "ForceManualAdvance" ,
1204 -1, Any( maPresSettings
.mbManual
),
1205 beans::PropertyState_DIRECT_VALUE
);
1209 aProperties
.emplace_back( "UserPaintColor" ,
1210 // User paint color is black by default.
1211 -1, Any( mnUserPaintColor
),
1212 beans::PropertyState_DIRECT_VALUE
);
1214 aProperties
.emplace_back( "UserPaintStrokeWidth" ,
1215 // User paint color is black by default.
1216 -1, Any( mdUserPaintStrokeWidth
),
1217 beans::PropertyState_DIRECT_VALUE
);
1220 if (mbRehearseTimings
) {
1221 aProperties
.emplace_back( "RehearseTimings" ,
1222 -1, Any(true), beans::PropertyState_DIRECT_VALUE
);
1225 bRet
= startShowImpl( Sequence
<beans::PropertyValue
>(
1226 aProperties
.data(), aProperties
.size() ) );
1230 setActiveXToolbarsVisible( false );
1232 catch (const Exception
&)
1234 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShow()" );
1241 bool SlideshowImpl::startShowImpl( const Sequence
< beans::PropertyValue
>& aProperties
)
1245 mxShow
.set( createSlideShow(), UNO_SET_THROW
);
1247 mxView
= new SlideShowView(
1252 maPresSettings
.mbFullScreen
);
1254 // try add wait symbol to properties:
1255 const Reference
<rendering::XSpriteCanvas
> xSpriteCanvas(
1256 mxView
->getCanvas() );
1257 if (xSpriteCanvas
.is())
1259 BitmapEx
waitSymbolBitmap(BMP_WAIT_ICON
);
1260 const Reference
<rendering::XBitmap
> xBitmap(
1261 vcl::unotools::xBitmapFromBitmapEx( waitSymbolBitmap
) );
1264 mxShow
->setProperty(
1265 beans::PropertyValue( u
"WaitSymbolBitmap"_ustr
,
1268 beans::PropertyState_DIRECT_VALUE
) );
1271 BitmapEx
pointerSymbolBitmap(BMP_POINTER_ICON
);
1272 const Reference
<rendering::XBitmap
> xPointerBitmap(
1273 vcl::unotools::xBitmapFromBitmapEx( pointerSymbolBitmap
) );
1274 if (xPointerBitmap
.is())
1276 mxShow
->setProperty(
1277 beans::PropertyValue( u
"PointerSymbolBitmap"_ustr
,
1279 Any( xPointerBitmap
),
1280 beans::PropertyState_DIRECT_VALUE
) );
1282 if (officecfg::Office::Impress::Misc::Start::ShowNavigationPanel::get())
1284 NavbarButtonSize btnScale
= static_cast<NavbarButtonSize
>(officecfg::Office::Impress::Layout::Display::NavigationBtnScale::get());
1285 OUString prevSlidePath
= u
""_ustr
;
1286 OUString nextSlidePath
= u
""_ustr
;
1287 OUString menuPath
= u
""_ustr
;
1290 case NavbarButtonSize::Large
:
1292 prevSlidePath
= BMP_PREV_SLIDE_LARGE
;
1293 nextSlidePath
= BMP_NEXT_SLIDE_LARGE
;
1294 menuPath
= BMP_MENU_SLIDE_LARGE
;
1297 case NavbarButtonSize::XLarge
:
1299 prevSlidePath
= BMP_PREV_SLIDE_EXTRALARGE
;
1300 nextSlidePath
= BMP_NEXT_SLIDE_EXTRALARGE
;
1301 menuPath
= BMP_MENU_SLIDE_EXTRALARGE
;
1304 case NavbarButtonSize::Auto
:
1305 case NavbarButtonSize::Small
:
1308 prevSlidePath
= BMP_PREV_SLIDE_SMALL
;
1309 nextSlidePath
= BMP_NEXT_SLIDE_SMALL
;
1310 menuPath
= BMP_MENU_SLIDE_SMALL
;
1314 BitmapEx
prevSlideBm(prevSlidePath
);
1315 const Reference
<rendering::XBitmap
> xPrevSBitmap(
1316 vcl::unotools::xBitmapFromBitmapEx(prevSlideBm
));
1317 if (xPrevSBitmap
.is())
1319 mxShow
->setProperty(beans::PropertyValue(u
"NavigationSlidePrev"_ustr
, -1,
1321 beans::PropertyState_DIRECT_VALUE
));
1323 BitmapEx
menuSlideBm(menuPath
);
1324 const Reference
<rendering::XBitmap
> xMenuSBitmap(
1325 vcl::unotools::xBitmapFromBitmapEx(menuSlideBm
));
1326 if (xMenuSBitmap
.is())
1328 mxShow
->setProperty(beans::PropertyValue(u
"NavigationSlideMenu"_ustr
, -1,
1330 beans::PropertyState_DIRECT_VALUE
));
1332 BitmapEx
nextSlideBm(nextSlidePath
);
1333 const Reference
<rendering::XBitmap
> xNextSBitmap(
1334 vcl::unotools::xBitmapFromBitmapEx(nextSlideBm
));
1335 if (xNextSBitmap
.is())
1337 mxShow
->setProperty(beans::PropertyValue(u
"NavigationSlideNext"_ustr
, -1,
1339 beans::PropertyState_DIRECT_VALUE
));
1344 for( const auto& rProp
: aProperties
)
1345 mxShow
->setProperty( rProp
);
1347 mxShow
->addView( mxView
);
1349 mxListenerProxy
.set( new SlideShowListenerProxy( this, mxShow
) );
1350 mxListenerProxy
->addAsSlideShowListener();
1352 // IASS: Do only startup the PresenterConsole if this is not
1353 // the SlideShow Preview mode (else would be double)
1354 if (!mbInterActiveSetup
)
1356 // IASS: This is the central methodology to 'steer' the
1357 // PresenterConsole - in this case, to start it up and make
1358 // it visible (if activated)
1359 NotifyDocumentEvent(
1361 u
"OnStartPresentation"_ustr
);
1364 displaySlideIndex( mpSlideController
->getStartSlideIndex() );
1370 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShowImpl()" );
1375 /** called only by the slideshow view when the first paint event occurs.
1376 This actually starts the slideshow. */
1377 void SlideshowImpl::onFirstPaint()
1382 mpShowWindow->SetBackground( Wallpaper( COL_BLACK ) );
1383 mpShowWindow->Erase();
1384 mpShowWindow->SetBackground();
1388 SolarMutexGuard aSolarGuard
;
1389 maUpdateTimer
.SetTimeout( sal_uLong(100) );
1390 maUpdateTimer
.Start();
1393 void SlideshowImpl::paint()
1395 if( mxView
.is() ) try
1397 awt::PaintEvent aEvt
;
1398 // aEvt.UpdateRect = TODO
1399 mxView
->paint( aEvt
);
1403 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::paint()" );
1407 void SAL_CALL
SlideshowImpl::addSlideShowListener( const Reference
< XSlideShowListener
>& xListener
)
1409 if( mxListenerProxy
.is() )
1410 mxListenerProxy
->addSlideShowListener( xListener
);
1413 void SAL_CALL
SlideshowImpl::removeSlideShowListener( const Reference
< XSlideShowListener
>& xListener
)
1415 if( mxListenerProxy
.is() )
1416 mxListenerProxy
->removeSlideShowListener( xListener
);
1419 void SlideshowImpl::slideEnded(const bool bReverse
)
1422 gotoPreviousSlide(true);
1427 bool SlideshowImpl::swipe(const CommandGestureSwipeData
&rSwipeData
)
1429 if (mbUsePen
|| mnContextMenuEvent
)
1431 double nVelocityX
= rSwipeData
.getVelocityX();
1432 // tdf#108475 make it swipe only if some reasonable movement was involved
1433 if (fabs(nVelocityX
) < 50)
1437 gotoPreviousSlide();
1443 //a swipe is followed by a mouse up, tell the view to ignore that mouse up as we've reacted
1444 //to the swipe instead
1445 mxView
->ignoreNextMouseReleased();
1449 bool SlideshowImpl::longpress(const CommandGestureLongPressData
&rLongPressData
)
1451 if (mnContextMenuEvent
)
1454 maPopupMousePos
= Point(rLongPressData
.getX(), rLongPressData
.getY());
1455 mnContextMenuEvent
= Application::PostUserEvent( LINK( this, SlideshowImpl
, ContextMenuHdl
) );
1460 void SlideshowImpl::removeShapeEvents()
1462 if( !(mxShow
.is() && mxListenerProxy
.is()) )
1467 for( const auto& rEntry
: maShapeEventMap
)
1469 mxListenerProxy
->removeShapeEventListener( rEntry
.first
);
1470 mxShow
->setShapeCursor( rEntry
.first
, awt::SystemPointer::ARROW
);
1473 maShapeEventMap
.clear();
1477 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::removeShapeEvents()" );
1481 void SlideshowImpl::registerShapeEvents(sal_Int32 nSlideNumber
)
1483 if( nSlideNumber
< 0 )
1488 Reference
< XIndexAccess
> xPages( mxModel
->getDrawPages(), UNO_QUERY_THROW
);
1490 Reference
< XShapes
> xDrawPage
;
1491 xPages
->getByIndex(nSlideNumber
) >>= xDrawPage
;
1493 if( xDrawPage
.is() )
1495 Reference
< XMasterPageTarget
> xMasterPageTarget( xDrawPage
, UNO_QUERY
);
1496 if( xMasterPageTarget
.is() )
1498 Reference
< XShapes
> xMasterPage
= xMasterPageTarget
->getMasterPage();
1499 if( xMasterPage
.is() )
1500 registerShapeEvents( xMasterPage
);
1502 registerShapeEvents( xDrawPage
);
1507 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
1511 void SlideshowImpl::registerShapeEvents( Reference
< XShapes
> const & xShapes
)
1515 const sal_Int32 nShapeCount
= xShapes
->getCount();
1517 for( nShape
= 0; nShape
< nShapeCount
; nShape
++ )
1519 Reference
< XShape
> xShape
;
1520 xShapes
->getByIndex( nShape
) >>= xShape
;
1522 if( xShape
.is() && xShape
->getShapeType() == "com.sun.star.drawing.GroupShape" )
1524 Reference
< XShapes
> xSubShapes( xShape
, UNO_QUERY
);
1525 if( xSubShapes
.is() )
1526 registerShapeEvents( xSubShapes
);
1529 Reference
< XPropertySet
> xSet( xShape
, UNO_QUERY
);
1533 Reference
< XPropertySetInfo
> xSetInfo( xSet
->getPropertySetInfo() );
1534 if( !xSetInfo
.is() || !xSetInfo
->hasPropertyByName( gsOnClick
) )
1537 WrappedShapeEventImplPtr pEvent
= std::make_shared
<WrappedShapeEventImpl
>();
1538 xSet
->getPropertyValue( gsOnClick
) >>= pEvent
->meClickAction
;
1540 switch( pEvent
->meClickAction
)
1542 case ClickAction_PREVPAGE
:
1543 case ClickAction_NEXTPAGE
:
1544 case ClickAction_FIRSTPAGE
:
1545 case ClickAction_LASTPAGE
:
1546 case ClickAction_STOPPRESENTATION
:
1548 case ClickAction_BOOKMARK
:
1549 if( xSetInfo
->hasPropertyByName( gsBookmark
) )
1550 xSet
->getPropertyValue( gsBookmark
) >>= pEvent
->maStrBookmark
;
1551 if( getSlideNumberForBookmark( pEvent
->maStrBookmark
) == -1 )
1554 case ClickAction_DOCUMENT
:
1555 case ClickAction_SOUND
:
1556 case ClickAction_PROGRAM
:
1557 case ClickAction_MACRO
:
1558 if( xSetInfo
->hasPropertyByName( gsBookmark
) )
1559 xSet
->getPropertyValue( gsBookmark
) >>= pEvent
->maStrBookmark
;
1561 case ClickAction_VERB
:
1562 if( xSetInfo
->hasPropertyByName( gsVerb
) )
1563 xSet
->getPropertyValue( gsVerb
) >>= pEvent
->mnVerb
;
1566 continue; // skip all others
1569 maShapeEventMap
[ xShape
] = std::move(pEvent
);
1571 if( mxListenerProxy
.is() )
1572 mxListenerProxy
->addShapeEventListener( xShape
);
1573 mxShow
->setShapeCursor( xShape
, awt::SystemPointer::REFHAND
);
1578 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
1582 void SlideshowImpl::displayCurrentSlide (const bool bSkipAllMainSequenceEffects
)
1585 removeShapeEvents();
1587 if( mpSlideController
&& mxShow
.is() )
1589 rtl::Reference
< SdXImpressDocument
> xDrawPages( mpDoc
->getUnoModel() );
1590 mpSlideController
->displayCurrentSlide( mxShow
, xDrawPages
, bSkipAllMainSequenceEffects
);
1591 registerShapeEvents(mpSlideController
->getCurrentSlideNumber());
1595 // send out page change event and notify to update all acc info for current page
1598 sal_Int32 currentPageIndex
= getCurrentSlideIndex();
1599 mpViewShell
->fireSwitchCurrentPage(currentPageIndex
);
1600 mpViewShell
->NotifyAccUpdate();
1604 void SlideshowImpl::endPresentation()
1606 if( maPresSettings
.mbMouseAsPen
)
1608 rtl::Reference
< SdXImpressDocument
> xDocFactory(mpDoc
->getUnoModel() );
1609 if( xDocFactory
.is() )
1610 mxShow
->registerUserPaintPolygons(xDocFactory
);
1613 if( !mnEndShowEvent
)
1614 mnEndShowEvent
= Application::PostUserEvent( LINK(this, SlideshowImpl
, endPresentationHdl
) );
1617 IMPL_LINK_NOARG(SlideshowImpl
, endPresentationHdl
, void*, void)
1619 mnEndShowEvent
= nullptr;
1623 if( mxPresentation
.is() )
1624 mxPresentation
->end();
1627 void SAL_CALL
SlideshowImpl::pause()
1629 SolarMutexGuard aSolarGuard
;
1639 mxShow
->pause(true);
1641 if( mxListenerProxy
.is() )
1642 mxListenerProxy
->paused();
1647 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::pause()" );
1651 void SAL_CALL
SlideshowImpl::resume()
1653 SolarMutexGuard aSolarGuard
;
1655 if( mbIsPaused
) try
1657 if( mpShowWindow
->GetShowWindowMode() == SHOWWINDOWMODE_BLANK
|| mpShowWindow
->GetShowWindowMode() == SHOWWINDOWMODE_END
)
1659 mpShowWindow
->RestartShow();
1666 mxShow
->pause(false);
1669 if( mxListenerProxy
.is() )
1670 mxListenerProxy
->resumed();
1676 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resume()" );
1678 #ifdef ENABLE_SDREMOTE
1679 RemoteServer::presentationStarted( this );
1683 sal_Bool SAL_CALL
SlideshowImpl::isPaused()
1685 SolarMutexGuard aSolarGuard
;
1689 void SAL_CALL
SlideshowImpl::blankScreen( sal_Int32 nColor
)
1691 SolarMutexGuard aSolarGuard
;
1693 if( mpShowWindow
&& mpSlideController
)
1695 if( mpShowWindow
->SetBlankMode( mpSlideController
->getCurrentSlideIndex(), Color(ColorTransparency
, nColor
) ) )
1702 // XShapeEventListener
1704 void SlideshowImpl::click( const Reference
< XShape
>& xShape
)
1706 SolarMutexGuard aSolarGuard
;
1708 WrappedShapeEventImplPtr pEvent
= maShapeEventMap
[xShape
];
1712 switch( pEvent
->meClickAction
)
1714 case ClickAction_PREVPAGE
: gotoPreviousSlide(); break;
1715 case ClickAction_NEXTPAGE
: gotoNextSlide(); break;
1716 case ClickAction_FIRSTPAGE
: gotoFirstSlide(); break;
1717 case ClickAction_LASTPAGE
: gotoLastSlide(); break;
1718 case ClickAction_STOPPRESENTATION
: endPresentation(); break;
1719 case ClickAction_BOOKMARK
:
1721 gotoBookmark( pEvent
->maStrBookmark
);
1724 case ClickAction_SOUND
:
1726 #if HAVE_FEATURE_AVMEDIA
1729 mxPlayer
.set(avmedia::MediaWindow::createPlayer(pEvent
->maStrBookmark
, u
""_ustr
/*TODO?*/), uno::UNO_SET_THROW
);
1732 catch( uno::Exception
& )
1734 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::click()" );
1740 case ClickAction_DOCUMENT
:
1742 OUString
aBookmark( pEvent
->maStrBookmark
);
1744 sal_Int32 nPos
= aBookmark
.indexOf( '#' );
1747 OUString
aURL( aBookmark
.copy( 0, nPos
+1 ) );
1748 OUString
aName( aBookmark
.copy( nPos
+1 ) );
1749 aURL
+= getUiNameFromPageApiNameImpl( aName
);
1753 mpDocSh
->OpenBookmark( aBookmark
);
1757 case ClickAction_PROGRAM
:
1760 ::URIHelper::SmartRel2Abs(
1761 INetURLObject(mpDocSh
->GetMedium()->GetBaseURL()),
1762 pEvent
->maStrBookmark
, ::URIHelper::GetMaybeFileHdl(), true,
1763 false, INetURLObject::EncodeMechanism::WasEncoded
,
1764 INetURLObject::DecodeMechanism::Unambiguous
) );
1766 if( INetProtocol::File
== aURL
.GetProtocol() )
1768 SfxStringItem
aUrl( SID_FILE_NAME
, aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1769 SfxBoolItem
aBrowsing( SID_BROWSE
, true );
1771 if (SfxViewFrame
* pViewFrm
= SfxViewFrame::Current())
1773 SfxUnoFrameItem
aDocFrame(SID_FILLFRAME
, pViewFrm
->GetFrame().GetFrameInterface());
1774 pViewFrm
->GetDispatcher()->ExecuteList( SID_OPENDOC
,
1775 SfxCallMode::ASYNCHRON
| SfxCallMode::RECORD
,
1776 { &aUrl
, &aBrowsing
}, { &aDocFrame
} );
1782 #if HAVE_FEATURE_SCRIPTING
1783 case presentation::ClickAction_MACRO
:
1785 const OUString
aMacro( pEvent
->maStrBookmark
);
1787 if ( SfxApplication::IsXScriptURL( aMacro
) )
1790 Sequence
< sal_Int16
> aOutArgsIndex
;
1791 Sequence
< Any
> aOutArgs
;
1792 Sequence
< Any
>* pInArgs
= new Sequence
< Any
>(0);
1793 mpDocSh
->CallXScript( aMacro
, *pInArgs
, aRet
, aOutArgsIndex
, aOutArgs
);
1797 // aMacro has the following syntax:
1798 // "Macroname.Modulname.Libname.Documentname" or
1799 // "Macroname.Modulname.Libname.Applicationname"
1800 sal_Int32 nIdx
{ 0 };
1801 const std::u16string_view aMacroName
= o3tl::getToken(aMacro
, 0, '.', nIdx
);
1802 const std::u16string_view aModulName
= o3tl::getToken(aMacro
, 0, '.', nIdx
);
1804 // todo: is the limitation still given that only
1805 // Modulname+Macroname can be used here?
1806 OUString aExecMacro
= OUString::Concat(aModulName
) + "." + aMacroName
;
1807 mpDocSh
->GetBasic()->Call(aExecMacro
);
1813 case ClickAction_VERB
:
1815 // todo, better do it async?
1816 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(xShape
);
1817 SdrOle2Obj
* pOleObject
= dynamic_cast< SdrOle2Obj
* >(pObj
);
1818 if (pOleObject
&& mpViewShell
)
1819 mpViewShell
->ActivateObject(pOleObject
, pEvent
->mnVerb
);
1827 sal_Int32
SlideshowImpl::getSlideNumberForBookmark( const OUString
& rStrBookmark
)
1830 OUString aBookmark
= getUiNameFromPageApiNameImpl( rStrBookmark
);
1831 sal_uInt16 nPgNum
= mpDoc
->GetPageByName( aBookmark
, bIsMasterPage
);
1833 if( nPgNum
== SDRPAGE_NOTFOUND
)
1835 // Is the bookmark an object?
1836 SdrObject
* pObj
= mpDoc
->GetObj( aBookmark
);
1840 nPgNum
= pObj
->getSdrPageFromSdrObject()->GetPageNum();
1841 bIsMasterPage
= pObj
->getSdrPageFromSdrObject()->IsMasterPage();
1845 if( (nPgNum
== SDRPAGE_NOTFOUND
) || bIsMasterPage
|| static_cast<SdPage
*>(mpDoc
->GetPage(nPgNum
))->GetPageKind() != PageKind::Standard
)
1848 return ( nPgNum
- 1) >> 1;
1851 void SlideshowImpl::contextMenuShow(const css::awt::Point
& point
)
1853 maPopupMousePos
= { point
.X
, point
.Y
};
1854 mnContextMenuEvent
= Application::PostUserEvent(LINK(this, SlideshowImpl
, ContextMenuHdl
));
1857 void SlideshowImpl::hyperLinkClicked( OUString
const& aHyperLink
)
1859 OUString
aBookmark( aHyperLink
);
1861 sal_Int32 nPos
= aBookmark
.indexOf( '#' );
1864 OUString
aURL( aBookmark
.copy( 0, nPos
+1 ) );
1865 OUString
aName( aBookmark
.copy( nPos
+1 ) );
1866 aURL
+= getUiNameFromPageApiNameImpl( aName
);
1870 mpDocSh
->OpenBookmark( aBookmark
);
1873 void SlideshowImpl::displaySlideNumber( sal_Int32 nSlideNumber
)
1875 if( mpSlideController
)
1877 if( mpSlideController
->jumpToSlideNumber( nSlideNumber
) )
1879 displayCurrentSlide();
1884 /** nSlideIndex == -1 displays current slide again */
1885 void SlideshowImpl::displaySlideIndex( sal_Int32 nSlideIndex
)
1887 if( mpSlideController
)
1889 if( (nSlideIndex
== -1) || mpSlideController
->jumpToSlideIndex( nSlideIndex
) )
1891 displayCurrentSlide();
1896 void SlideshowImpl::jumpToBookmark( const OUString
& sBookmark
)
1898 sal_Int32 nSlideNumber
= getSlideNumberForBookmark( sBookmark
);
1899 if( nSlideNumber
!= -1 )
1900 displaySlideNumber( nSlideNumber
);
1903 sal_Int32
SlideshowImpl::getCurrentSlideNumber() const
1905 return mpSlideController
? mpSlideController
->getCurrentSlideNumber() : -1;
1908 sal_Bool SAL_CALL
SlideshowImpl::isEndless()
1910 SolarMutexGuard aSolarGuard
;
1911 return maPresSettings
.mbEndless
;
1914 void SlideshowImpl::update()
1919 void SlideshowImpl::startUpdateTimer()
1921 SolarMutexGuard aSolarGuard
;
1922 maUpdateTimer
.SetTimeout( 0 );
1923 maUpdateTimer
.Start();
1926 /** this timer is called 20ms after a new slide was displayed.
1927 This is used to unfreeze user input that was disabled after
1928 slide change to skip input that was buffered during slide
1929 transition preparation */
1930 IMPL_LINK_NOARG(SlideshowImpl
, ReadyForNextInputHdl
, Timer
*, void)
1932 mbInputFreeze
= false;
1935 /** if I catch someone someday who calls this method by hand
1936 and not by using the timer, I will personally punish this
1937 person seriously, even if this person is me.
1939 IMPL_LINK_NOARG(SlideshowImpl
, updateHdl
, Timer
*, void)
1944 void SlideshowImpl::updateSlideShow()
1946 // prevent me from deletion when recursing (App::EnableYieldMode does)
1947 const rtl::Reference
<SlideshowImpl
> xKeepAlive(this);
1949 Reference
< XSlideShow
> xShow( mxShow
);
1955 double fUpdate
= 0.0;
1956 if( !xShow
->update(fUpdate
) )
1959 if (mxShow
.is() && (fUpdate
>= 0.0))
1961 if (::basegfx::fTools::equalZero(fUpdate
))
1963 // Make sure idle tasks don't starve when we don't have to wait.
1964 // Don't process any events generated after invoking the function.
1965 Application::Reschedule(/*bHandleAllCurrentEvents=*/true);
1969 // Avoid busy loop when the previous call to update()
1970 // returns a small positive number but not 0 (which is
1971 // handled above). Also, make sure that calls to update()
1972 // have a minimum frequency.
1973 // => Allow up to 60 frames per second. Call at least once
1975 const static sal_Int32
nMaximumFrameCount (60);
1976 const static double nMinimumTimeout (1.0 / nMaximumFrameCount
);
1977 const static double nMaximumTimeout (4.0);
1978 fUpdate
= std::clamp(fUpdate
, nMinimumTimeout
, nMaximumTimeout
);
1980 // Make sure that the maximum frame count has not been set
1981 // too high (only then conversion to milliseconds and long
1982 // integer may lead to zero value.)
1983 OSL_ASSERT(static_cast<sal_uLong
>(fUpdate
* 1000.0) > 0);
1986 // Use our high resolution timers for the asynchronous callback.
1987 maUpdateTimer
.SetTimeout(static_cast<sal_uLong
>(fUpdate
* 1000.0));
1988 maUpdateTimer
.Start();
1993 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::updateSlideShow()" );
1997 bool SlideshowImpl::keyInput(const KeyEvent
& rKEvt
)
1999 if( !mxShow
.is() || mbInputFreeze
)
2006 const int nKeyCode
= rKEvt
.GetKeyCode().GetCode();
2009 case awt::Key::CONTEXTMENU
:
2010 if( !mnContextMenuEvent
)
2013 maPopupMousePos
= mpShowWindow
->GetPointerState().maPos
;
2014 mnContextMenuEvent
= Application::PostUserEvent( LINK( this, SlideshowImpl
, ContextMenuHdl
) );
2021 // in case the user cancels the presentation, switch to current slide
2023 if( mpSlideController
&& (ANIMATIONMODE_SHOW
== meAnimationMode
) )
2025 if( mpSlideController
->getCurrentSlideNumber() != -1 )
2026 mnRestoreSlide
= mpSlideController
->getCurrentSlideNumber();
2033 if(rKEvt
.GetKeyCode().IsMod2())
2042 case KEY_XF86FORWARD
:
2048 if( !maCharBuffer
.isEmpty() )
2050 if( mpSlideController
)
2052 if( mpSlideController
->jumpToSlideNumber( maCharBuffer
.toInt32() - 1 ) )
2053 displayCurrentSlide();
2055 maCharBuffer
.clear();
2064 // numeric: add to buffer
2075 maCharBuffer
+= OUStringChar( rKEvt
.GetCharCode() );
2079 if(rKEvt
.GetKeyCode().IsMod2())
2081 gotoPreviousSlide();
2089 gotoPreviousEffect();
2093 setUsePen( !mbUsePen
);
2096 // tdf#149351 Ctrl+A disables pointer as pen mode
2098 if(rKEvt
.GetKeyCode().IsMod1())
2106 setEraseAllInk( true );
2123 blankScreen( ((nKeyCode
== KEY_W
) || (nKeyCode
== KEY_COMMA
)) ? 0x00ffffff : 0x00000000 );
2135 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::keyInput()" );
2141 IMPL_LINK( SlideshowImpl
, EventListenerHdl
, VclSimpleEvent
&, rSimpleEvent
, void )
2143 if( !mxShow
.is() || mbInputFreeze
)
2146 if( !((rSimpleEvent
.GetId() == VclEventId::WindowCommand
) && static_cast<VclWindowEvent
*>(&rSimpleEvent
)->GetData()) )
2149 const CommandEvent
& rEvent
= *static_cast<const CommandEvent
*>(static_cast<VclWindowEvent
*>(&rSimpleEvent
)->GetData());
2151 if( rEvent
.GetCommand() != CommandEventId::Media
)
2154 CommandMediaData
* pMediaData
= rEvent
.GetMediaData();
2155 pMediaData
->SetPassThroughToOS(false);
2156 switch (pMediaData
->GetMediaId())
2158 #if defined( MACOSX )
2159 case MediaCommand::Menu
:
2160 if( !mnContextMenuEvent
)
2163 maPopupMousePos
= mpShowWindow
->GetPointerState().maPos
;
2164 mnContextMenuEvent
= Application::PostUserEvent( LINK( this, SlideshowImpl
, ContextMenuHdl
) );
2167 case MediaCommand::VolumeDown
:
2168 gotoPreviousSlide();
2170 case MediaCommand::VolumeUp
:
2174 case MediaCommand::NextTrack
:
2177 case MediaCommand::Pause
:
2181 case MediaCommand::Play
:
2186 case MediaCommand::PlayPause
:
2192 case MediaCommand::PreviousTrack
:
2193 gotoPreviousSlide();
2195 case MediaCommand::NextTrackHold
:
2199 case MediaCommand::Rewind
:
2202 case MediaCommand::Stop
:
2203 // in case the user cancels the presentation, switch to current slide
2205 if( mpSlideController
&& (ANIMATIONMODE_SHOW
== meAnimationMode
) )
2207 if( mpSlideController
->getCurrentSlideNumber() != -1 )
2208 mnRestoreSlide
= mpSlideController
->getCurrentSlideNumber();
2213 pMediaData
->SetPassThroughToOS(true);
2218 void SlideshowImpl::mouseButtonUp(const MouseEvent
& rMEvt
)
2220 if( rMEvt
.IsRight() && !mnContextMenuEvent
)
2222 maPopupMousePos
= rMEvt
.GetPosPixel();
2223 mnContextMenuEvent
= Application::PostUserEvent( LINK( this, SlideshowImpl
, ContextMenuHdl
) );
2227 IMPL_LINK_NOARG(SlideshowImpl
, ContextMenuHdl
, void*, void)
2229 mnContextMenuEvent
= nullptr;
2231 if (mpSlideController
== nullptr)
2234 mbWasPaused
= mbIsPaused
;
2238 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(nullptr, u
"modules/simpress/ui/slidecontextmenu.ui"_ustr
));
2239 std::unique_ptr
<weld::Menu
> xMenu(xBuilder
->weld_menu(u
"menu"_ustr
));
2240 OUString
sNextImage(BMP_MENU_NEXT
), sPrevImage(BMP_MENU_PREV
);
2241 xMenu
->insert(0, u
"next"_ustr
, SdResId(RID_SVXSTR_MENU_NEXT
), &sNextImage
, nullptr, nullptr, TRISTATE_INDET
);
2242 xMenu
->insert(1, u
"prev"_ustr
, SdResId(RID_SVXSTR_MENU_PREV
), &sPrevImage
, nullptr, nullptr, TRISTATE_INDET
);
2244 // Adding button to display if in Pen mode
2245 xMenu
->set_active(u
"pen"_ustr
, mbUsePen
);
2247 const ShowWindowMode eMode
= mpShowWindow
->GetShowWindowMode();
2248 xMenu
->set_visible(u
"next"_ustr
, mpSlideController
->getNextSlideIndex() != -1);
2249 xMenu
->set_visible(u
"prev"_ustr
, (mpSlideController
->getPreviousSlideIndex() != -1 ) || (eMode
== SHOWWINDOWMODE_END
) || (eMode
== SHOWWINDOWMODE_PAUSE
) || (eMode
== SHOWWINDOWMODE_BLANK
));
2250 xMenu
->set_visible(u
"edit"_ustr
, mpViewShell
->GetDoc()->GetStartWithPresentation() != 0);
2252 std::unique_ptr
<weld::Menu
> xPageMenu(xBuilder
->weld_menu(u
"gotomenu"_ustr
));
2253 OUString
sFirstImage(BMP_MENU_FIRST
), sLastImage(BMP_MENU_LAST
);
2254 xPageMenu
->insert(0, u
"first"_ustr
, SdResId(RID_SVXSTR_MENU_FIRST
), &sFirstImage
, nullptr, nullptr, TRISTATE_INDET
);
2255 xPageMenu
->insert(1, u
"last"_ustr
, SdResId(RID_SVXSTR_MENU_LAST
), &sLastImage
, nullptr, nullptr, TRISTATE_INDET
);
2257 // populate slide goto list
2258 const sal_Int32 nPageNumberCount
= mpSlideController
->getSlideNumberCount();
2259 if( nPageNumberCount
<= 1 )
2261 xMenu
->set_visible(u
"goto"_ustr
, false);
2265 sal_Int32 nCurrentSlideNumber
= mpSlideController
->getCurrentSlideNumber();
2266 if( (eMode
== SHOWWINDOWMODE_END
) || (eMode
== SHOWWINDOWMODE_PAUSE
) || (eMode
== SHOWWINDOWMODE_BLANK
) )
2267 nCurrentSlideNumber
= -1;
2269 xPageMenu
->set_visible(u
"first"_ustr
, mpSlideController
->getSlideNumber(0) != nCurrentSlideNumber
);
2270 xPageMenu
->set_visible(u
"last"_ustr
, mpSlideController
->getSlideNumber(mpSlideController
->getSlideIndexCount() - 1) != nCurrentSlideNumber
);
2272 sal_Int32 nPageNumber
;
2274 for( nPageNumber
= 0; nPageNumber
< nPageNumberCount
; nPageNumber
++ )
2276 if( mpSlideController
->isVisibleSlideNumber( nPageNumber
) )
2278 SdPage
* pPage
= mpDoc
->GetSdPage(static_cast<sal_uInt16
>(nPageNumber
), PageKind::Standard
);
2281 OUString
sId(OUString::number(CM_SLIDES
+ nPageNumber
));
2282 xPageMenu
->append_check(sId
, pPage
->GetName());
2283 if (nPageNumber
== nCurrentSlideNumber
)
2284 xPageMenu
->set_active(sId
, true);
2290 std::unique_ptr
<weld::Menu
> xBlankMenu(xBuilder
->weld_menu(u
"screenmenu"_ustr
));
2292 if (mpShowWindow
->GetShowWindowMode() == SHOWWINDOWMODE_BLANK
)
2294 xBlankMenu
->set_active((mpShowWindow
->GetBlankColor() == COL_WHITE
) ? "white" : "black", true);
2297 std::unique_ptr
<weld::Menu
> xWidthMenu(xBuilder
->weld_menu(u
"widthmenu"_ustr
));
2299 // populate color width list
2300 sal_Int32 nIterator
;
2304 for( nIterator
= 1; nIterator
< 6; nIterator
++)
2327 if (nWidth
== mdUserPaintStrokeWidth
)
2328 xWidthMenu
->set_active(OUString::number(nWidth
), true);
2331 ::tools::Rectangle
aRect(maPopupMousePos
, Size(1,1));
2332 weld::Window
* pParent
= weld::GetPopupParent(*mpShowWindow
, aRect
);
2333 ContextMenuSelectHdl(xMenu
->popup_at_rect(pParent
, aRect
));
2336 mxView
->ignoreNextMouseReleased();
2342 void SlideshowImpl::ContextMenuSelectHdl(std::u16string_view rMenuId
)
2344 if (rMenuId
== u
"prev")
2346 gotoPreviousSlide();
2347 mbWasPaused
= false;
2349 else if(rMenuId
== u
"next")
2352 mbWasPaused
= false;
2354 else if (rMenuId
== u
"first")
2357 mbWasPaused
= false;
2359 else if (rMenuId
== u
"last")
2362 mbWasPaused
= false;
2364 else if (rMenuId
== u
"black" || rMenuId
== u
"white")
2366 const Color
aBlankColor(rMenuId
== u
"white" ? COL_WHITE
: COL_BLACK
);
2369 if( mpShowWindow
->GetShowWindowMode() == SHOWWINDOWMODE_BLANK
)
2371 if( mpShowWindow
->GetBlankColor() == aBlankColor
)
2373 mbWasPaused
= false;
2374 mpShowWindow
->RestartShow();
2378 mpShowWindow
->RestartShow();
2380 if( mpShowWindow
->SetBlankMode( mpSlideController
->getCurrentSlideIndex(), aBlankColor
) )
2386 else if (rMenuId
== u
"color")
2388 //Open a color picker based on SvColorDialog
2389 ::Color
aColor( ColorTransparency
, mnUserPaintColor
);
2390 SvColorDialog aColorDlg
;
2391 aColorDlg
.SetColor( aColor
);
2393 if (aColorDlg
.Execute(mpShowWindow
->GetFrameWeld()))
2395 aColor
= aColorDlg
.GetColor();
2396 setPenColor(sal_Int32(aColor
));
2398 mbWasPaused
= false;
2400 else if (rMenuId
== u
"4")
2403 mbWasPaused
= false;
2405 else if (rMenuId
== u
"100")
2408 mbWasPaused
= false;
2410 else if (rMenuId
== u
"150")
2413 mbWasPaused
= false;
2415 else if (rMenuId
== u
"200")
2418 mbWasPaused
= false;
2420 else if (rMenuId
== u
"400")
2423 mbWasPaused
= false;
2425 else if (rMenuId
== u
"erase")
2427 setEraseAllInk(true);
2428 mbWasPaused
= false;
2430 else if (rMenuId
== u
"pen")
2432 setUsePen(!mbUsePen
);
2433 mbWasPaused
= false;
2435 else if (rMenuId
== u
"edit")
2437 // When in autoplay mode (pps/ppsx), offer editing of the presentation
2438 // Turn autostart off, else Impress will close when exiting the Presentation
2439 mpViewShell
->GetDoc()->SetExitAfterPresenting(false);
2440 if( mpSlideController
&& (ANIMATIONMODE_SHOW
== meAnimationMode
) )
2442 if( mpSlideController
->getCurrentSlideNumber() != -1 )
2444 mnRestoreSlide
= mpSlideController
->getCurrentSlideNumber();
2449 else if (rMenuId
== u
"end")
2451 // in case the user cancels the presentation, switch to current slide
2453 if( mpSlideController
&& (ANIMATIONMODE_SHOW
== meAnimationMode
) )
2455 if( mpSlideController
->getCurrentSlideNumber() != -1 )
2457 mnRestoreSlide
= mpSlideController
->getCurrentSlideNumber();
2462 else if (!rMenuId
.empty())
2464 sal_Int32 nPageNumber
= o3tl::toInt32(rMenuId
) - CM_SLIDES
;
2465 const ShowWindowMode eMode
= mpShowWindow
->GetShowWindowMode();
2466 if( (eMode
== SHOWWINDOWMODE_END
) || (eMode
== SHOWWINDOWMODE_PAUSE
) || (eMode
== SHOWWINDOWMODE_BLANK
) )
2468 mpShowWindow
->RestartShow( nPageNumber
);
2470 else if( nPageNumber
!= mpSlideController
->getCurrentSlideNumber() )
2472 displaySlideNumber( nPageNumber
);
2474 mbWasPaused
= false;
2478 Reference
< XSlideShow
> SlideshowImpl::createSlideShow()
2480 Reference
< XSlideShow
> xShow
;
2484 const Reference
< uno::XComponentContext
>& xContext
=
2485 ::comphelper::getProcessComponentContext();
2487 xShow
.set( presentation::SlideShow::create(xContext
), UNO_SET_THROW
);
2489 catch( uno::Exception
& )
2491 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::createSlideShow()" );
2497 void SlideshowImpl::createSlideList( bool bAll
, std::u16string_view rPresSlide
)
2499 const sal_uInt16 nSlideCount
= mpDoc
->GetSdPageCount( PageKind::Standard
);
2504 SdCustomShow
* pCustomShow
;
2506 if( mpDoc
->GetCustomShowList() && maPresSettings
.mbCustomShow
)
2507 pCustomShow
= mpDoc
->GetCustomShowList()->GetCurObject();
2509 pCustomShow
= nullptr;
2511 // create animation slide controller
2512 AnimationSlideController::Mode eMode
=
2513 ( pCustomShow
&& !pCustomShow
->PagesVector().empty() ) ? AnimationSlideController::CUSTOM
:
2514 (bAll
? AnimationSlideController::ALL
: AnimationSlideController::FROM
);
2516 rtl::Reference
< SdXImpressDocument
> xDrawPages( mpDoc
->getUnoModel() );
2517 Reference
< XIndexAccess
> xSlides( xDrawPages
->getDrawPages(), UNO_QUERY_THROW
);
2518 mpSlideController
= std::make_shared
<AnimationSlideController
>( xSlides
, eMode
);
2520 if( eMode
!= AnimationSlideController::CUSTOM
)
2522 sal_Int32 nFirstVisibleSlide
= 0;
2524 // normal presentation
2525 if( !rPresSlide
.empty() )
2528 bool bTakeNextAvailable
= false;
2530 for( nSlide
= 0, nFirstVisibleSlide
= -1;
2531 ( nSlide
< nSlideCount
) && ( -1 == nFirstVisibleSlide
); nSlide
++ )
2533 SdPage
* pTestSlide
= mpDoc
->GetSdPage( static_cast<sal_uInt16
>(nSlide
), PageKind::Standard
);
2535 if( pTestSlide
->GetName() == rPresSlide
)
2537 if( pTestSlide
->IsExcluded() )
2538 bTakeNextAvailable
= true;
2540 nFirstVisibleSlide
= nSlide
;
2542 else if( bTakeNextAvailable
&& !pTestSlide
->IsExcluded() )
2543 nFirstVisibleSlide
= nSlide
;
2546 if( -1 == nFirstVisibleSlide
)
2547 nFirstVisibleSlide
= 0;
2550 for( sal_Int32 i
= 0; i
< nSlideCount
; i
++ )
2552 bool bVisible
= ! mpDoc
->GetSdPage( static_cast<sal_uInt16
>(i
), PageKind::Standard
)->IsExcluded();
2553 if( bVisible
|| (eMode
== AnimationSlideController::ALL
) )
2554 mpSlideController
->insertSlideNumber( i
, bVisible
);
2557 mpSlideController
->setStartSlideNumber( nFirstVisibleSlide
);
2561 if( meAnimationMode
!= ANIMATIONMODE_SHOW
&& !rPresSlide
.empty() )
2564 for( nSlide
= 0; nSlide
< nSlideCount
; nSlide
++ )
2565 if( rPresSlide
== mpDoc
->GetSdPage( static_cast<sal_uInt16
>(nSlide
), PageKind::Standard
)->GetName() )
2568 if( nSlide
< nSlideCount
)
2569 mpSlideController
->insertSlideNumber( static_cast<sal_uInt16
>(nSlide
) );
2572 for( const auto& rpPage
: pCustomShow
->PagesVector() )
2574 const sal_uInt16 nSdSlide
= ( rpPage
->GetPageNum() - 1 ) / 2;
2576 if( ! mpDoc
->GetSdPage( nSdSlide
, PageKind::Standard
)->IsExcluded())
2577 mpSlideController
->insertSlideNumber( nSdSlide
);
2582 typedef sal_uInt16 (*FncGetChildWindowId
)();
2584 const FncGetChildWindowId aShowChildren
[] =
2586 &AnimationChildWindow::GetChildWindowId
,
2587 &Svx3DChildWindow::GetChildWindowId
,
2588 &SvxFontWorkChildWindow::GetChildWindowId
,
2589 &SvxColorChildWindow::GetChildWindowId
,
2590 &SvxSearchDialogWrapper::GetChildWindowId
,
2591 &SvxBmpMaskChildWindow::GetChildWindowId
,
2592 &SvxIMapDlgChildWindow::GetChildWindowId
,
2593 &SvxHlinkDlgWrapper::GetChildWindowId
,
2594 &SfxInfoBarContainerChild::GetChildWindowId
2597 void SlideshowImpl::hideChildWindows()
2601 if( ANIMATIONMODE_SHOW
!= meAnimationMode
)
2604 SfxViewFrame
* pViewFrame
= getViewFrame();
2609 for( sal_uLong i
= 0; i
< SAL_N_ELEMENTS( aShowChildren
); i
++ )
2611 const sal_uInt16 nId
= ( *aShowChildren
[ i
] )();
2613 if( pViewFrame
->GetChildWindow( nId
) )
2615 pViewFrame
->SetChildWindow( nId
, false );
2616 mnChildMask
|= ::tools::ULong(1) << i
;
2621 void SlideshowImpl::showChildWindows()
2623 if( ANIMATIONMODE_SHOW
== meAnimationMode
)
2625 SfxViewFrame
* pViewFrame
= getViewFrame();
2628 for( sal_uLong i
= 0; i
< SAL_N_ELEMENTS(aShowChildren
); i
++ )
2630 if( mnChildMask
& ( ::tools::ULong(1) << i
) )
2631 pViewFrame
->SetChildWindow( ( *aShowChildren
[ i
] )(), true );
2637 SfxViewFrame
* SlideshowImpl::getViewFrame() const
2639 return mpViewShell
? mpViewShell
->GetViewFrame() : nullptr;
2642 SfxDispatcher
* SlideshowImpl::getDispatcher() const
2644 return (mpViewShell
&& mpViewShell
->GetViewFrame()) ? mpViewShell
->GetViewFrame()->GetDispatcher() : nullptr;
2647 SfxBindings
* SlideshowImpl::getBindings() const
2649 return (mpViewShell
&& mpViewShell
->GetViewFrame()) ? &mpViewShell
->GetViewFrame()->GetBindings() : nullptr;
2652 void SlideshowImpl::resize( const Size
& rSize
)
2658 mpShowWindow
->SetSizePixel( maPresSize
);
2659 mpShowWindow
->Show();
2662 if( mxView
.is() ) try
2664 awt::WindowEvent aEvt
;
2665 mxView
->windowResized(aEvt
);
2669 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resize()" );
2673 void SlideshowImpl::setActiveXToolbarsVisible( bool bVisible
)
2675 // in case of ActiveX control the toolbars should not be visible if slide show runs in window mode
2676 // actually it runs always in window mode in case of ActiveX control
2677 if ( !(!maPresSettings
.mbFullScreen
&& mpDocSh
&& mpDocSh
->GetMedium()) )
2680 const SfxBoolItem
* pItem
= mpDocSh
->GetMedium()->GetItemSet().GetItem(SID_VIEWONLY
, false);
2681 if ( !(pItem
&& pItem
->GetValue()) )
2684 // this is a plugin/activex mode, no toolbars should be visible during slide show
2685 // after the end of slide show they should be visible again
2686 SfxViewFrame
* pViewFrame
= getViewFrame();
2692 Reference
< frame::XLayoutManager
> xLayoutManager
;
2693 Reference
< beans::XPropertySet
> xFrameProps( pViewFrame
->GetFrame().GetFrameInterface(), UNO_QUERY_THROW
);
2694 if ( ( xFrameProps
->getPropertyValue( u
"LayoutManager"_ustr
)
2695 >>= xLayoutManager
)
2696 && xLayoutManager
.is() )
2698 xLayoutManager
->setVisible( bVisible
);
2701 catch( uno::Exception
& )
2705 void SAL_CALL
SlideshowImpl::activate()
2707 SolarMutexGuard aSolarGuard
;
2709 maDeactivateTimer
.Stop();
2711 if( mbActive
|| !mxShow
.is() )
2716 if( ANIMATIONMODE_SHOW
== meAnimationMode
)
2718 if( mbAutoSaveWasOn
)
2719 setAutoSaveState( false );
2723 SfxViewFrame
* pViewFrame
= getViewFrame();
2724 SfxDispatcher
* pDispatcher
= pViewFrame
? pViewFrame
->GetDispatcher() : nullptr;
2730 // filter all forbidden slots
2731 pDispatcher
->SetSlotFilter( SfxSlotFilterState::ENABLED
, pAllowed
);
2735 getBindings()->InvalidateAll(true);
2737 mpShowWindow
->GrabFocus();
2744 void SAL_CALL
SlideshowImpl::deactivate()
2746 SolarMutexGuard aSolarGuard
;
2748 if( mbActive
&& mxShow
.is() )
2750 maDeactivateTimer
.Start();
2754 IMPL_LINK_NOARG(SlideshowImpl
, deactivateHdl
, Timer
*, void)
2756 if( !(mbActive
&& mxShow
.is()) )
2763 if( ANIMATIONMODE_SHOW
== meAnimationMode
)
2765 if( mbAutoSaveWasOn
)
2766 setAutoSaveState( true );
2775 sal_Bool SAL_CALL
SlideshowImpl::isActive()
2777 SolarMutexGuard aSolarGuard
;
2781 void SlideshowImpl::setAutoSaveState( bool bOn
)
2785 const uno::Reference
<uno::XComponentContext
>& xContext( ::comphelper::getProcessComponentContext() );
2787 uno::Reference
< util::XURLTransformer
> xParser(util::URLTransformer::create(xContext
));
2789 aURL
.Complete
= "vnd.sun.star.autorecovery:/setAutoSaveState";
2790 xParser
->parseStrict(aURL
);
2792 Sequence
< beans::PropertyValue
> aArgs
{ comphelper::makePropertyValue(u
"AutoSaveState"_ustr
, bOn
) };
2794 uno::Reference
< frame::XDispatch
> xAutoSave
= frame::theAutoRecovery::get(xContext
);
2795 xAutoSave
->dispatch(aURL
, aArgs
);
2799 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setAutoSaveState()");
2803 Reference
< XDrawPage
> SAL_CALL
SlideshowImpl::getCurrentSlide()
2805 SolarMutexGuard aSolarGuard
;
2807 Reference
< XDrawPage
> xSlide
;
2808 if( mxShow
.is() && mpSlideController
)
2810 sal_Int32 nSlide
= getCurrentSlideNumber();
2811 if( (nSlide
>= 0) && (nSlide
< mpSlideController
->getSlideNumberCount() ) )
2812 xSlide
= mpSlideController
->getSlideByNumber( nSlide
);
2818 sal_Int32 SAL_CALL
SlideshowImpl::getNextSlideIndex()
2820 SolarMutexGuard aSolarGuard
;
2824 return mpSlideController
->getNextSlideIndex();
2832 sal_Int32 SAL_CALL
SlideshowImpl::getCurrentSlideIndex()
2834 return mpSlideController
? mpSlideController
->getCurrentSlideIndex() : -1;
2837 // css::presentation::XSlideShowController:
2839 ::sal_Int32 SAL_CALL
SlideshowImpl::getSlideCount()
2841 return mpSlideController
? mpSlideController
->getSlideIndexCount() : 0;
2844 Reference
< XDrawPage
> SAL_CALL
SlideshowImpl::getSlideByIndex(::sal_Int32 Index
)
2846 if ((mpSlideController
== nullptr) || (Index
< 0)
2847 || (Index
>= mpSlideController
->getSlideIndexCount()))
2848 throw IndexOutOfBoundsException();
2850 return mpSlideController
->getSlideByNumber( mpSlideController
->getSlideNumber( Index
) );
2853 sal_Bool SAL_CALL
SlideshowImpl::getAlwaysOnTop()
2855 SolarMutexGuard aSolarGuard
;
2856 return maPresSettings
.mbAlwaysOnTop
;
2859 void SAL_CALL
SlideshowImpl::setAlwaysOnTop( sal_Bool bAlways
)
2861 SolarMutexGuard aSolarGuard
;
2862 if( maPresSettings
.mbAlwaysOnTop
!= bool(bAlways
) )
2864 maPresSettings
.mbAlwaysOnTop
= bAlways
;
2865 // todo, can this be changed while running?
2869 sal_Bool SAL_CALL
SlideshowImpl::isFullScreen()
2871 SolarMutexGuard aSolarGuard
;
2872 return maPresSettings
.mbFullScreen
;
2875 sal_Bool SAL_CALL
SlideshowImpl::getMouseVisible()
2877 SolarMutexGuard aSolarGuard
;
2878 return maPresSettings
.mbMouseVisible
;
2881 void SAL_CALL
SlideshowImpl::setMouseVisible( sal_Bool bVisible
)
2883 SolarMutexGuard aSolarGuard
;
2884 if( maPresSettings
.mbMouseVisible
!= bool(bVisible
) )
2886 maPresSettings
.mbMouseVisible
= bVisible
;
2888 mpShowWindow
->SetMouseAutoHide( !maPresSettings
.mbMouseVisible
);
2892 sal_Bool SAL_CALL
SlideshowImpl::getUsePen()
2894 SolarMutexGuard aSolarGuard
;
2898 void SAL_CALL
SlideshowImpl::setUsePen( sal_Bool bMouseAsPen
)
2900 SolarMutexGuard aSolarGuard
;
2901 mbUsePen
= bMouseAsPen
;
2908 beans::PropertyValue aPenProp
;
2909 aPenProp
.Name
= "UserPaintColor";
2911 aPenProp
.Value
<<= mnUserPaintColor
;
2912 mxShow
->setProperty( aPenProp
);
2917 beans::PropertyValue aPenPropWidth
;
2918 aPenPropWidth
.Name
= "UserPaintStrokeWidth";
2919 aPenPropWidth
.Value
<<= mdUserPaintStrokeWidth
;
2920 mxShow
->setProperty( aPenPropWidth
);
2923 beans::PropertyValue aPenPropSwitchPenMode
;
2924 aPenPropSwitchPenMode
.Name
= "SwitchPenMode";
2925 aPenPropSwitchPenMode
.Value
<<= true;
2926 mxShow
->setProperty( aPenPropSwitchPenMode
);
2931 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setUsePen()" );
2935 double SAL_CALL
SlideshowImpl::getPenWidth()
2937 SolarMutexGuard aSolarGuard
;
2938 return mdUserPaintStrokeWidth
;
2941 void SAL_CALL
SlideshowImpl::setPenWidth( double dStrokeWidth
)
2943 SolarMutexGuard aSolarGuard
;
2944 mdUserPaintStrokeWidth
= dStrokeWidth
;
2945 setUsePen( true ); // enable pen mode, update color and width
2948 sal_Int32 SAL_CALL
SlideshowImpl::getPenColor()
2950 SolarMutexGuard aSolarGuard
;
2951 return mnUserPaintColor
;
2954 void SAL_CALL
SlideshowImpl::setPenColor( sal_Int32 nColor
)
2956 SolarMutexGuard aSolarGuard
;
2957 mnUserPaintColor
= nColor
;
2958 setUsePen( true ); // enable pen mode, update color
2961 void SAL_CALL
SlideshowImpl::setEraseAllInk(sal_Bool bEraseAllInk
)
2966 SolarMutexGuard aSolarGuard
;
2972 beans::PropertyValue aPenPropEraseAllInk
;
2973 aPenPropEraseAllInk
.Name
= "EraseAllInk";
2974 aPenPropEraseAllInk
.Value
<<= bEraseAllInk
;
2975 mxShow
->setProperty( aPenPropEraseAllInk
);
2979 TOOLS_WARN_EXCEPTION( "sd.slideshow", "sd::SlideshowImpl::setEraseAllInk()" );
2983 // XSlideShowController Methods
2984 sal_Bool SAL_CALL
SlideshowImpl::isRunning( )
2986 SolarMutexGuard aSolarGuard
;
2990 void SAL_CALL
SlideshowImpl::gotoNextEffect( )
2992 SolarMutexGuard aSolarGuard
;
2994 if( !(mxShow
.is() && mpSlideController
&& mpShowWindow
) )
2997 if( mbIsPaused
&& mpShowWindow
->GetShowWindowMode() != SHOWWINDOWMODE_END
)
3000 const ShowWindowMode eMode
= mpShowWindow
->GetShowWindowMode();
3001 if( eMode
== SHOWWINDOWMODE_END
)
3005 else if( (eMode
== SHOWWINDOWMODE_PAUSE
) || (eMode
== SHOWWINDOWMODE_BLANK
) )
3007 mpShowWindow
->RestartShow();
3011 mxShow
->nextEffect();
3016 void SAL_CALL
SlideshowImpl::gotoPreviousEffect( )
3018 SolarMutexGuard aSolarGuard
;
3020 if( !(mxShow
.is() && mpSlideController
&& mpShowWindow
) )
3023 const ShowWindowMode eMode
= mpShowWindow
->GetShowWindowMode();
3024 if( (eMode
== SHOWWINDOWMODE_PAUSE
) || (eMode
== SHOWWINDOWMODE_BLANK
) || mbIsPaused
)
3030 mxShow
->previousEffect();
3035 void SAL_CALL
SlideshowImpl::gotoFirstSlide( )
3037 SolarMutexGuard aSolarGuard
;
3039 if( !(mpShowWindow
&& mpSlideController
) )
3045 if( mpShowWindow
->GetShowWindowMode() == SHOWWINDOWMODE_END
)
3047 if( mpSlideController
->getSlideIndexCount() )
3048 mpShowWindow
->RestartShow( 0);
3052 displaySlideIndex( 0 );
3056 void SAL_CALL
SlideshowImpl::gotoNextSlide( )
3058 SolarMutexGuard aSolarGuard
;
3063 const ShowWindowMode eMode
= mpShowWindow
->GetShowWindowMode();
3064 if( (eMode
== SHOWWINDOWMODE_PAUSE
) || (eMode
== SHOWWINDOWMODE_BLANK
) )
3066 mpShowWindow
->RestartShow();
3070 // if this is a show, ignore user inputs and
3071 // start 20ms timer to reenable inputs to filter
3072 // buffered inputs during slide transition
3073 if( meAnimationMode
== ANIMATIONMODE_SHOW
)
3075 mbInputFreeze
= true;
3076 maInputFreezeTimer
.Start();
3079 if( mpSlideController
)
3081 if( mpSlideController
->nextSlide() )
3083 displayCurrentSlide();
3089 if( meAnimationMode
== ANIMATIONMODE_PREVIEW
)
3093 else if( maPresSettings
.mbEndless
)
3095 if( maPresSettings
.mnPauseTimeout
)
3099 if ( maPresSettings
.mbShowPauseLogo
)
3101 Graphic
aGraphic(SfxApplication::GetApplicationLogo(360));
3102 mpShowWindow
->SetPauseMode( maPresSettings
.mnPauseTimeout
, &aGraphic
);
3105 mpShowWindow
->SetPauseMode( maPresSettings
.mnPauseTimeout
);
3110 displaySlideIndex( 0 );
3117 mpShowWindow
->SetEndMode();
3118 if (!mpViewShell
->GetDoc()->GetStartWithPresentation())
3127 void SAL_CALL
SlideshowImpl::gotoPreviousSlide( )
3129 gotoPreviousSlide(false);
3132 void SlideshowImpl::gotoPreviousSlide (const bool bSkipAllMainSequenceEffects
)
3134 SolarMutexGuard aSolarGuard
;
3136 if( !(mxShow
.is() && mpSlideController
) )
3144 const ShowWindowMode eMode
= mpShowWindow
->GetShowWindowMode();
3145 if( eMode
== SHOWWINDOWMODE_END
)
3147 mpShowWindow
->RestartShow( mpSlideController
->getCurrentSlideIndex() );
3149 else if( (eMode
== SHOWWINDOWMODE_PAUSE
) || (eMode
== SHOWWINDOWMODE_BLANK
) )
3151 mpShowWindow
->RestartShow();
3155 if( mpSlideController
->previousSlide())
3156 displayCurrentSlide(bSkipAllMainSequenceEffects
);
3157 else if (bSkipAllMainSequenceEffects
)
3159 // We could not go to the previous slide (probably because
3160 // the current slide is already the first one). We still
3161 // have to call displayCurrentSlide because the calling
3162 // slideshow can not determine whether there is a previous
3163 // slide or not and has already prepared for a slide change.
3164 // This slide change has to be completed now, even when
3165 // changing to the same slide.
3166 // Note that in this special case we do NOT pass
3167 // bSkipAllMainSequenceEffects because we display the same
3168 // slide as before and do not want to show all its effects.
3169 displayCurrentSlide();
3175 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::gotoPreviousSlide()" );
3179 void SAL_CALL
SlideshowImpl::gotoLastSlide()
3181 SolarMutexGuard aSolarGuard
;
3183 if( !mpSlideController
)
3189 const sal_Int32 nLastSlideIndex
= mpSlideController
->getSlideIndexCount() - 1;
3190 if( nLastSlideIndex
>= 0 )
3192 if( mpShowWindow
->GetShowWindowMode() == SHOWWINDOWMODE_END
)
3194 mpShowWindow
->RestartShow( nLastSlideIndex
);
3198 displaySlideIndex( nLastSlideIndex
);
3203 void SAL_CALL
SlideshowImpl::gotoBookmark( const OUString
& rBookmark
)
3205 SolarMutexGuard aSolarGuard
;
3210 sal_Int32 nSlideNumber
= getSlideNumberForBookmark( rBookmark
);
3211 if( nSlideNumber
!= -1 )
3212 displaySlideNumber( nSlideNumber
);
3215 void SAL_CALL
SlideshowImpl::gotoSlide( const Reference
< XDrawPage
>& xSlide
)
3217 SolarMutexGuard aSolarGuard
;
3219 if( !(mpSlideController
&& xSlide
.is()) )
3225 const sal_Int32 nSlideCount
= mpSlideController
->getSlideNumberCount();
3226 for( sal_Int32 nSlide
= 0; nSlide
< nSlideCount
; nSlide
++ )
3228 if( mpSlideController
->getSlideByNumber( nSlide
) == xSlide
)
3230 displaySlideNumber( nSlide
);
3235 void SAL_CALL
SlideshowImpl::gotoSlideIndex( sal_Int32 nIndex
)
3237 SolarMutexGuard aSolarGuard
;
3242 displaySlideIndex( nIndex
);
3245 void SAL_CALL
SlideshowImpl::stopSound( )
3247 SolarMutexGuard aSolarGuard
;
3259 TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stopSound()" );
3265 ::sal_Int32 SAL_CALL
SlideshowImpl::getCount( )
3267 return getSlideCount();
3270 css::uno::Any SAL_CALL
SlideshowImpl::getByIndex( ::sal_Int32 Index
)
3272 return Any( getSlideByIndex( Index
) );
3275 css::uno::Type SAL_CALL
SlideshowImpl::getElementType( )
3277 return cppu::UnoType
<XDrawPage
>::get();
3280 sal_Bool SAL_CALL
SlideshowImpl::hasElements( )
3282 return getSlideCount() != 0;
3287 class AsyncUpdateSlideshow_Impl
3290 struct AsyncUpdateSlideshowData
3292 SlideshowImpl
* pSlideshowImpl
;
3293 uno::Reference
< css::drawing::XDrawPage
> XCurrentSlide
;
3294 SdrHintKind eHintKind
;
3297 static ImplSVEvent
* AsyncUpdateSlideshow(
3298 SlideshowImpl
* pSlideshowImpl
,
3299 uno::Reference
< css::drawing::XDrawPage
>& rXCurrentSlide
,
3300 SdrHintKind eHintKind
)
3302 AsyncUpdateSlideshowData
* pNew(new AsyncUpdateSlideshowData
);
3303 pNew
->pSlideshowImpl
= pSlideshowImpl
;
3304 pNew
->XCurrentSlide
= rXCurrentSlide
;
3305 pNew
->eHintKind
= eHintKind
;
3306 return Application::PostUserEvent(LINK(nullptr, AsyncUpdateSlideshow_Impl
, Update
), pNew
);
3307 // coverity[leaked_storage] - pDisruptor takes care of its own destruction at idle time
3310 DECL_STATIC_LINK(AsyncUpdateSlideshow_Impl
, Update
, void*, void);
3313 IMPL_STATIC_LINK(AsyncUpdateSlideshow_Impl
, Update
, void*, pData
, void)
3315 AsyncUpdateSlideshowData
* pSlideData(static_cast<AsyncUpdateSlideshowData
*>(pData
));
3316 pSlideData
->pSlideshowImpl
->AsyncNotifyEvent(pSlideData
->XCurrentSlide
, pSlideData
->eHintKind
);
3321 void SlideshowImpl::AsyncNotifyEvent(
3322 const uno::Reference
< css::drawing::XDrawPage
>& rXCurrentSlide
,
3323 const SdrHintKind eHintKind
)
3327 case SdrHintKind::ObjectInserted
:
3329 mnEventObjectInserted
= nullptr;
3331 // refresh single slide
3332 gotoSlide(rXCurrentSlide
);
3335 case SdrHintKind::ObjectRemoved
:
3337 mnEventObjectRemoved
= nullptr;
3339 // refresh single slide
3340 gotoSlide(rXCurrentSlide
);
3343 case SdrHintKind::ObjectChange
:
3345 mnEventObjectChange
= nullptr;
3347 // refresh single slide
3348 gotoSlide(rXCurrentSlide
);
3351 case SdrHintKind::PageOrderChange
:
3353 mnEventPageOrderChange
= nullptr;
3355 // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
3356 // rXCurrentSlide is the current slide before the change.
3357 rtl::Reference
< SdXImpressDocument
> xDrawPages( mpDoc
->getUnoModel() );
3358 Reference
< XIndexAccess
> xSlides( xDrawPages
->getDrawPages(), UNO_QUERY_THROW
);
3359 const sal_Int32
nNewSlideCount(xSlides
.is() ? xSlides
->getCount() : 0);
3361 if (nNewSlideCount
!= mpSlideController
->getSlideNumberCount())
3363 // need to reinitialize AnimationSlideController
3364 OUString
aPresSlide( maPresSettings
.maPresPage
);
3365 createSlideList( maPresSettings
.mbAll
, aPresSlide
);
3368 // Check if current slide before change is still valid (maybe removed)
3369 const sal_Int32
nSlideCount(mpSlideController
->getSlideNumberCount());
3370 bool bSlideStillValid(false);
3372 for (sal_Int32
nSlide(0); !bSlideStillValid
&& nSlide
< nSlideCount
; nSlide
++)
3374 if (rXCurrentSlide
== mpSlideController
->getSlideByNumber(nSlide
))
3376 bSlideStillValid
= true;
3380 if(bSlideStillValid
)
3382 // stay on that slide
3383 gotoSlide(rXCurrentSlide
);
3387 // not possible to stay on that slide, go to 1st slide (kinda restart)
3397 bool SlideshowImpl::isCurrentSlideInvolved(const SdrHint
& rHint
)
3399 // get current slide
3400 uno::Reference
< css::drawing::XDrawPage
> XCurrentSlide(getCurrentSlide());
3401 if (!XCurrentSlide
.is())
3404 SdrPage
* pCurrentSlide(GetSdrPageFromXDrawPage(XCurrentSlide
));
3405 if (nullptr == pCurrentSlide
)
3408 const SdrPage
* pHintPage(rHint
.GetPage());
3409 if (nullptr == pHintPage
)
3412 if (pHintPage
->IsMasterPage())
3414 if (pCurrentSlide
->TRG_HasMasterPage())
3416 // current slide uses MasterPage on which the change happened
3417 return pHintPage
== &pCurrentSlide
->TRG_GetMasterPage();
3421 // object on current slide was changed
3422 return pHintPage
== pCurrentSlide
;
3425 void SlideshowImpl::sendHintSlideChanged(const SdrPage
* pChangedPage
) const
3427 if (nullptr == pChangedPage
)
3433 mxShow
->setProperty(
3434 beans::PropertyValue( u
"HintSlideChanged"_ustr
,
3436 Any( GetXDrawPageForSdrPage(const_cast<SdrPage
*>(pChangedPage
)) ),
3437 beans::PropertyState_DIRECT_VALUE
) );
3440 void SlideshowImpl::Notify(SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
3442 if (SfxHintId::ThisIsAnSdrHint
!= rHint
.GetId())
3443 // nothing to do for non-SdrHints
3446 if (nullptr == mpDoc
)
3447 // better do nothing when no DrawModel (should not happen)
3450 // tdf#158664 I am surprised, but the 'this' instance keeps incarnated
3451 // when the slideshow was running once, so need to check for
3452 // SlideShow instance/running to be safe.
3453 // NOTE: isRunning() checks mxShow.is(), that is what we want
3455 // no SlideShow instance or not running, nothing to do
3458 const SdrHint
& rSdrHint(static_cast<const SdrHint
&>(rHint
));
3459 const SdrHintKind
eHintKind(rSdrHint
.GetKind());
3463 case SdrHintKind::ObjectInserted
:
3465 if (nullptr != mnEventObjectInserted
)
3466 // avoid multiple events
3469 // tdf#160669 IASS: inform about ALL changed slides due to prefetch
3470 sendHintSlideChanged(rSdrHint
.GetPage());
3472 if (!isCurrentSlideInvolved(rSdrHint
))
3473 // nothing to do when current slide is not involved
3476 // Refresh current slide
3477 uno::Reference
< css::drawing::XDrawPage
> XCurrentSlide(getCurrentSlide());
3478 mnEventObjectInserted
= AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide
, eHintKind
);
3481 case SdrHintKind::ObjectRemoved
:
3483 if (nullptr != mnEventObjectRemoved
)
3484 // avoid multiple events
3487 // tdf#160669 IASS: inform about ALL changed slides due to prefetch
3488 sendHintSlideChanged(rSdrHint
.GetPage());
3490 if (!isCurrentSlideInvolved(rSdrHint
))
3491 // nothing to do when current slide is not involved
3494 // Refresh current slide
3495 uno::Reference
< css::drawing::XDrawPage
> XCurrentSlide(getCurrentSlide());
3496 mnEventObjectRemoved
= AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide
, eHintKind
);
3499 case SdrHintKind::ObjectChange
:
3501 if (nullptr != mnEventObjectChange
)
3502 // avoid multiple events
3505 // tdf#160669 IASS: inform about ALL changed slides due to prefetch
3506 sendHintSlideChanged(rSdrHint
.GetPage());
3508 if (!isCurrentSlideInvolved(rSdrHint
))
3509 // nothing to do when current slide is not involved
3512 // Refresh current slide. Need to do that asynchronous, else e.g.
3513 // text edit changes EditEngine/Outliner are not progressed far
3514 // enough (ObjectChanged broadcast which we are in here seems
3515 // too early for some cases)
3516 uno::Reference
< css::drawing::XDrawPage
> XCurrentSlide(getCurrentSlide());
3517 mnEventObjectChange
= AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide
, eHintKind
);
3520 case SdrHintKind::PageOrderChange
:
3522 // Unfortunately we get multiple events, e.g. when drag/drop position change in
3523 // slide sorter on left side of EditView. This includes some with page number +1,
3524 // then again -1 (it's a position change). Problem is that in-between already
3525 // a re-schedule seems to happen, so indeed AsyncNotifyEvent will change to +1/-1
3526 // already. Since we get even more, at least try to take the last one. I found no
3527 // good solution yet for this.
3528 if (nullptr != mnEventPageOrderChange
)
3529 Application::RemoveUserEvent( mnEventPageOrderChange
);
3531 // tdf#160669 IASS: inform about ALL changed slides due to prefetch
3532 sendHintSlideChanged(rSdrHint
.GetPage());
3534 // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
3535 uno::Reference
< css::drawing::XDrawPage
> XCurrentSlide(getCurrentSlide());
3536 mnEventPageOrderChange
= AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide
, eHintKind
);
3539 case SdrHintKind::ModelCleared
:
3541 // immediately end presentation
3550 Reference
< XSlideShow
> SAL_CALL
SlideshowImpl::getSlideShow()
3555 PresentationSettingsEx::PresentationSettingsEx( const PresentationSettingsEx
& r
)
3556 : PresentationSettings( r
)
3557 , mbRehearseTimings(r
.mbRehearseTimings
)
3558 , mbPreview(r
.mbPreview
)
3559 , mpParentWindow( nullptr )
3563 PresentationSettingsEx::PresentationSettingsEx( PresentationSettings
const & r
)
3564 : PresentationSettings( r
)
3565 , mbRehearseTimings(false)
3567 , mpParentWindow(nullptr)
3571 void PresentationSettingsEx::SetArguments( const Sequence
< PropertyValue
>& rArguments
)
3573 for( const PropertyValue
& rValue
: rArguments
)
3575 SetPropertyValue( rValue
.Name
, rValue
.Value
);
3579 void PresentationSettingsEx::SetPropertyValue( std::u16string_view rProperty
, const Any
& rValue
)
3581 if ( rProperty
== u
"RehearseTimings" )
3583 if( rValue
>>= mbRehearseTimings
)
3586 else if ( rProperty
== u
"Preview" )
3588 if( rValue
>>= mbPreview
)
3591 else if ( rProperty
== u
"AnimationNode" )
3593 if( rValue
>>= mxAnimationNode
)
3596 else if ( rProperty
== u
"ParentWindow" )
3598 Reference
< XWindow
> xWindow
;
3599 if( rValue
>>= xWindow
)
3601 mpParentWindow
= xWindow
.is() ? VCLUnoHelper::GetWindow( xWindow
)
3606 else if ( rProperty
== u
"AllowAnimations" )
3608 if( rValue
>>= mbAnimationAllowed
)
3611 else if ( rProperty
== u
"FirstPage" )
3614 if( rValue
>>= aPresPage
)
3616 maPresPage
= getUiNameFromPageApiNameImpl(aPresPage
);
3617 mbCustomShow
= false;
3623 if( rValue
>>= mxStartPage
)
3627 else if ( rProperty
== u
"IsAlwaysOnTop" )
3629 if( rValue
>>= mbAlwaysOnTop
)
3632 else if ( rProperty
== u
"IsAutomatic" )
3634 if( rValue
>>= mbManual
)
3637 else if ( rProperty
== u
"IsEndless" )
3639 if( rValue
>>= mbEndless
)
3642 else if ( rProperty
== u
"IsFullScreen" )
3644 if( rValue
>>= mbFullScreen
)
3647 else if ( rProperty
== u
"IsMouseVisible" )
3649 if( rValue
>>= mbMouseVisible
)
3652 else if ( rProperty
== u
"Pause" )
3654 sal_Int32 nPause
= -1;
3655 if( (rValue
>>= nPause
) && (nPause
>= 0) )
3657 mnPauseTimeout
= nPause
;
3661 else if ( rProperty
== u
"UsePen" )
3663 if( rValue
>>= mbMouseAsPen
)
3666 throw IllegalArgumentException();
3669 // XAnimationListener
3671 SlideShowListenerProxy::SlideShowListenerProxy( rtl::Reference
< SlideshowImpl
> xController
, css::uno::Reference
< css::presentation::XSlideShow
> xSlideShow
)
3672 : mxController(std::move( xController
))
3673 , mxSlideShow(std::move( xSlideShow
))
3677 SlideShowListenerProxy::~SlideShowListenerProxy()
3681 void SlideShowListenerProxy::addAsSlideShowListener()
3683 if( mxSlideShow
.is() )
3685 Reference
< XSlideShowListener
> xSlideShowListener( this );
3686 mxSlideShow
->addSlideShowListener( xSlideShowListener
);
3690 void SlideShowListenerProxy::removeAsSlideShowListener()
3692 if( mxSlideShow
.is() )
3694 Reference
< XSlideShowListener
> xSlideShowListener( this );
3695 mxSlideShow
->removeSlideShowListener( xSlideShowListener
);
3699 void SlideShowListenerProxy::addShapeEventListener( const css::uno::Reference
< css::drawing::XShape
>& xShape
)
3701 if( mxSlideShow
.is() )
3703 Reference
< XShapeEventListener
> xListener( this );
3704 mxSlideShow
->addShapeEventListener( xListener
, xShape
);
3708 void SlideShowListenerProxy::removeShapeEventListener( const css::uno::Reference
< css::drawing::XShape
>& xShape
)
3710 if( mxSlideShow
.is() )
3712 Reference
< XShapeEventListener
> xListener( this );
3713 mxSlideShow
->removeShapeEventListener( xListener
, xShape
);
3717 void SlideShowListenerProxy::addSlideShowListener( const css::uno::Reference
< css::presentation::XSlideShowListener
>& xListener
)
3719 std::unique_lock
g(m_aMutex
);
3720 maListeners
.addInterface(g
, xListener
);
3723 void SlideShowListenerProxy::removeSlideShowListener( const css::uno::Reference
< css::presentation::XSlideShowListener
>& xListener
)
3725 std::unique_lock
g(m_aMutex
);
3726 maListeners
.removeInterface(g
, xListener
);
3729 void SAL_CALL
SlideShowListenerProxy::beginEvent( const Reference
< XAnimationNode
>& xNode
)
3731 std::unique_lock
aGuard( m_aMutex
);
3733 if( maListeners
.getLength(aGuard
) >= 0 )
3735 maListeners
.forEach(aGuard
,
3736 [&] (Reference
<XAnimationListener
> const& xListener
) {
3737 return xListener
->beginEvent(xNode
);
3742 void SAL_CALL
SlideShowListenerProxy::endEvent( const Reference
< XAnimationNode
>& xNode
)
3744 std::unique_lock
aGuard( m_aMutex
);
3746 if( maListeners
.getLength(aGuard
) >= 0 )
3748 maListeners
.forEach(aGuard
,
3749 [&] (Reference
<XAnimationListener
> const& xListener
) {
3750 return xListener
->endEvent(xNode
);
3755 void SAL_CALL
SlideShowListenerProxy::repeat( const Reference
< XAnimationNode
>& xNode
, ::sal_Int32 nRepeat
)
3757 std::unique_lock
aGuard( m_aMutex
);
3759 if( maListeners
.getLength(aGuard
) >= 0 )
3761 maListeners
.forEach(aGuard
,
3762 [&] (Reference
<XAnimationListener
> const& xListener
) {
3763 return xListener
->repeat(xNode
, nRepeat
);
3768 // css::presentation::XSlideShowListener:
3770 void SAL_CALL
SlideShowListenerProxy::paused( )
3772 std::unique_lock
aGuard( m_aMutex
);
3774 maListeners
.forEach(aGuard
,
3775 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
3777 xListener
->paused();
3781 void SAL_CALL
SlideShowListenerProxy::resumed( )
3783 std::unique_lock
aGuard( m_aMutex
);
3785 maListeners
.forEach(aGuard
,
3786 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
3788 xListener
->resumed();
3792 void SAL_CALL
SlideShowListenerProxy::slideTransitionStarted( )
3794 std::unique_lock
aGuard( m_aMutex
);
3796 maListeners
.forEach(aGuard
,
3797 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
3799 xListener
->slideTransitionStarted();
3803 void SAL_CALL
SlideShowListenerProxy::slideTransitionEnded( )
3805 std::unique_lock
aGuard( m_aMutex
);
3807 maListeners
.forEach(aGuard
,
3808 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
3810 xListener
->slideTransitionEnded ();
3814 void SAL_CALL
SlideShowListenerProxy::slideAnimationsEnded( )
3816 std::unique_lock
aGuard( m_aMutex
);
3818 maListeners
.forEach(aGuard
,
3819 [](uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
3821 xListener
->slideAnimationsEnded ();
3825 void SlideShowListenerProxy::slideEnded(sal_Bool bReverse
)
3828 std::unique_lock
aGuard( m_aMutex
);
3830 if( maListeners
.getLength(aGuard
) >= 0 )
3832 maListeners
.forEach(aGuard
,
3833 [&] (Reference
<XSlideShowListener
> const& xListener
) {
3834 return xListener
->slideEnded(bReverse
);
3840 SolarMutexGuard aSolarGuard
;
3841 if( mxController
.is() )
3842 mxController
->slideEnded(bReverse
);
3846 void SlideShowListenerProxy::hyperLinkClicked( OUString
const& aHyperLink
)
3849 std::unique_lock
aGuard( m_aMutex
);
3851 if( maListeners
.getLength(aGuard
) >= 0 )
3853 maListeners
.forEach(aGuard
,
3854 [&] (Reference
<XSlideShowListener
> const& xListener
) {
3855 return xListener
->hyperLinkClicked(aHyperLink
);
3861 SolarMutexGuard aSolarGuard
;
3862 if( mxController
.is() )
3863 mxController
->hyperLinkClicked(aHyperLink
);
3869 void SAL_CALL
SlideShowListenerProxy::disposing( const css::lang::EventObject
& aDisposeEvent
)
3871 std::unique_lock
g(m_aMutex
);
3872 maListeners
.disposeAndClear( g
, aDisposeEvent
);
3873 mxController
.clear();
3874 mxSlideShow
.clear();
3877 // XShapeEventListener
3879 void SAL_CALL
SlideShowListenerProxy::click( const Reference
< XShape
>& xShape
, const css::awt::MouseEvent
& /*aOriginalEvent*/ )
3881 SolarMutexGuard aSolarGuard
;
3882 if( mxController
.is() )
3883 mxController
->click(xShape
);
3886 void SAL_CALL
SlideShowListenerProxy::contextMenuShow(const css::awt::Point
& point
)
3888 SolarMutexGuard aSolarGuard
;
3889 if (mxController
.is())
3890 mxController
->contextMenuShow(point
);
3895 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */