LibreOffice Module sd (master) 1
PresenterController.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
23
27#include "PresenterScreen.hxx"
29#include "PresenterPaneBase.hxx"
32#include "PresenterTheme.hxx"
35#include <DrawController.hxx>
36
37#include <com/sun/star/awt/Key.hpp>
38#include <com/sun/star/awt/KeyModifier.hpp>
39#include <com/sun/star/awt/MouseButton.hpp>
40#include <com/sun/star/container/XNamed.hpp>
41#include <com/sun/star/drawing/XDrawView.hpp>
42#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
43#include <com/sun/star/drawing/framework/ResourceActivationMode.hpp>
44#include <com/sun/star/drawing/framework/ResourceId.hpp>
45#include <com/sun/star/frame/FrameSearchFlag.hpp>
46#include <com/sun/star/frame/XDispatchProvider.hpp>
47#include <com/sun/star/presentation/AnimationEffect.hpp>
48#include <com/sun/star/presentation/XPresentation.hpp>
49#include <com/sun/star/presentation/XPresentationSupplier.hpp>
50#include <com/sun/star/rendering/TextDirection.hpp>
51#include <com/sun/star/util/URLTransformer.hpp>
52
53#include <rtl/ustrbuf.hxx>
54#include <utility>
55
56using namespace ::com::sun::star;
57using namespace ::com::sun::star::uno;
58using namespace ::com::sun::star::presentation;
60
61namespace {
62 const sal_Int32 ResourceActivationEventType = 0;
63 const sal_Int32 ResourceDeactivationEventType = 1;
64 const sal_Int32 ConfigurationUpdateEndEventType = 2;
65}
66
67namespace sdext::presenter {
68
70{
71}
72
74
76 const css::uno::Reference<css::frame::XFrame>& rxFrame)
77{
78 InstanceContainer::const_iterator iInstance (maInstances.find(rxFrame));
79 if (iInstance != maInstances.end())
80 return iInstance->second;
81 else
82 return ::rtl::Reference<PresenterController>();
83}
84
87 const Reference<XComponentContext>& rxContext,
88 const rtl::Reference<::sd::DrawController>& rxController,
89 const Reference<presentation::XSlideShowController>& rxSlideShowController,
91 const Reference<XResourceId>& rxMainPaneId)
93 mxScreen(std::move(xScreen)),
94 mxComponentContext(rxContext),
95 mxController(rxController),
96 mxSlideShowController(rxSlideShowController),
97 mxMainPaneId(rxMainPaneId),
98 mpPaneContainer(std::move(xPaneContainer)),
99 mnCurrentSlideIndex(-1),
100 mpWindowManager(new PresenterWindowManager(rxContext,mpPaneContainer,this)),
101 mpCanvasHelper(std::make_shared<PresenterCanvasHelper>()),
102 mnPendingSlideNumber(-1),
103 mbIsAccessibilityActive(false)
104{
105 OSL_ASSERT(mxController.is());
106
107 if ( ! mxSlideShowController.is())
108 throw lang::IllegalArgumentException(
109 "missing slide show controller",
110 static_cast<XWeak*>(this),
111 2);
112
113 new PresenterCurrentSlideObserver(this,rxSlideShowController);
114
115 // Listen for configuration changes.
116 mxConfigurationController = mxController->getConfigurationController();
118 {
119 mxConfigurationController->addConfigurationChangeListener(
120 this,
121 "ResourceActivation",
122 Any(ResourceActivationEventType));
123 mxConfigurationController->addConfigurationChangeListener(
124 this,
125 "ResourceDeactivation",
126 Any(ResourceDeactivationEventType));
127 mxConfigurationController->addConfigurationChangeListener(
128 this,
129 "ConfigurationUpdateEnd",
130 Any(ConfigurationUpdateEndEventType));
131 }
132
133 // Listen for the frame being activated.
134 Reference<frame::XFrame> xFrame (mxController->getFrame());
135 if (xFrame.is())
136 xFrame->addFrameActionListener(this);
137
138 // Create the border painter.
140 mpWindowManager->SetPaneBorderPainter(mpPaneBorderPainter);
141
142 // Create an object that is able to load the bitmaps in a format that is
143 // supported by the canvas.
144 Reference<lang::XMultiComponentFactory> xFactory =
145 rxContext->getServiceManager();
146 if ( ! xFactory.is())
147 return;
149 xFactory->createInstanceWithContext(
150 "com.sun.star.drawing.PresenterHelper",
151 rxContext),
152 UNO_QUERY_THROW);
153
154 if (mxSlideShowController.is())
155 {
156 mxSlideShowController->activate();
157 Reference<beans::XPropertySet> xProperties (mxSlideShowController, UNO_QUERY);
158 if (xProperties.is())
159 {
160 Reference<awt::XWindow> xWindow (
161 xProperties->getPropertyValue("ParentWindow"), UNO_QUERY);
162 if (xWindow.is())
163 xWindow->addKeyListener(this);
164 }
165 }
166
168
169 maInstances[mxController->getFrame()] = this;
170
171 // Create a URLTransformer.
172 if (xFactory.is())
173 {
174 mxUrlTransformer.set(util::URLTransformer::create(mxComponentContext));
175 }
176}
177
179{
180}
181
183{
184 maInstances.erase(mxController->getFrame());
185
186 if (mxMainWindow.is())
187 {
188 mxMainWindow->removeKeyListener(this);
189 mxMainWindow->removeMouseListener(this);
190 mxMainWindow = nullptr;
191 }
193 mxConfigurationController->removeConfigurationChangeListener(this);
194
195 if (mxController.is())
196 {
197 Reference<frame::XFrame> xFrame (mxController->getFrame());
198 if (xFrame.is())
199 xFrame->removeFrameActionListener(this);
200 mxController = nullptr;
201 }
202
203 Reference<XComponent> xWindowManagerComponent = mpWindowManager;
204 mpWindowManager = nullptr;
205 if (xWindowManagerComponent.is())
206 xWindowManagerComponent->dispose();
207
208 mxComponentContext = nullptr;
210 mxSlideShowController = nullptr;
211 mxMainPaneId = nullptr;
212 mpPaneContainer = nullptr;
214 mxCurrentSlide = nullptr;
215 mxNextSlide = nullptr;
216 mpTheme.reset();
217 {
218 Reference<lang::XComponent> xComponent = mpPaneBorderPainter;
219 mpPaneBorderPainter = nullptr;
220 if (xComponent.is())
221 xComponent->dispose();
222 }
223 mpCanvasHelper.reset();
224 {
225 Reference<lang::XComponent> xComponent (mxPresenterHelper, UNO_QUERY);
226 mxPresenterHelper = nullptr;
227 if (xComponent.is())
228 xComponent->dispose();
229 }
230 mpPaintManager.reset();
232 {
233 Reference<lang::XComponent> xComponent (mxUrlTransformer, UNO_QUERY);
234 mxUrlTransformer = nullptr;
235 if (xComponent.is())
236 xComponent->dispose();
237 }
238}
239
240void PresenterController::UpdateCurrentSlide (const sal_Int32 nOffset)
241{
242 // std::cerr << "Updating current Slide to " << nOffset << std::endl;
243 GetSlides(nOffset);
245 UpdateViews();
246
247 // Update the accessibility object.
249 {
250 mpAccessibleObject->NotifyCurrentSlideChange();
251 }
252}
253
254void PresenterController::GetSlides (const sal_Int32 nOffset)
255{
256 if ( ! mxSlideShowController.is())
257 return;
258
259 // Get the current slide from the slide show controller.
260 mxCurrentSlide = nullptr;
261 Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
262 try
263 {
264 sal_Int32 nSlideIndex = mxSlideShowController->getCurrentSlideIndex() + nOffset;
265 if (mxSlideShowController->isPaused())
266 nSlideIndex = -1;
267
268 if (xIndexAccess.is() && nSlideIndex>=0)
269 {
270 if (nSlideIndex < xIndexAccess->getCount())
271 {
272 mnCurrentSlideIndex = nSlideIndex;
273 mxCurrentSlide.set( xIndexAccess->getByIndex(nSlideIndex), UNO_QUERY);
274 }
275 }
276 }
277 catch (RuntimeException&)
278 {
279 }
280
281 // Get the next slide.
282 mxNextSlide = nullptr;
283 try
284 {
285 const sal_Int32 nNextSlideIndex (mxSlideShowController->getNextSlideIndex()+nOffset);
286 if (nNextSlideIndex >= 0)
287 {
288 if (xIndexAccess.is())
289 {
290 if (nNextSlideIndex < xIndexAccess->getCount())
291 mxNextSlide.set( xIndexAccess->getByIndex(nNextSlideIndex), UNO_QUERY);
292 }
293 }
294 }
295 catch (RuntimeException&)
296 {
297 }
298}
299
301{
302 if ( ! mxSlideShowController.is())
303 return;
304
305 // Get placeholders and their values.
306 static constexpr OUStringLiteral sCurrentSlideNumberPlaceholder (u"CURRENT_SLIDE_NUMBER");
307 static constexpr OUStringLiteral sCurrentSlideNamePlaceholder (u"CURRENT_SLIDE_NAME");
308 static constexpr OUStringLiteral sSlideCountPlaceholder (u"SLIDE_COUNT");
309
310 // Get string for slide count.
311 OUString sSlideCount ("---");
312 Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
313 if (xIndexAccess.is())
314 sSlideCount = OUString::number(xIndexAccess->getCount());
315
316 // Get string for current slide index.
317 OUString sCurrentSlideNumber (OUString::number(mnCurrentSlideIndex + 1));
318
319 // Get name of the current slide.
320 OUString sCurrentSlideName;
321 Reference<container::XNamed> xNamedSlide (mxCurrentSlide, UNO_QUERY);
322 if (xNamedSlide.is())
323 sCurrentSlideName = xNamedSlide->getName();
324 Reference<beans::XPropertySet> xSlideProperties (mxCurrentSlide, UNO_QUERY);
325 if (xSlideProperties.is())
326 {
327 try
328 {
329 OUString sName;
330 if (xSlideProperties->getPropertyValue("LinkDisplayName") >>= sName)
331 {
332 // Find out whether the name of the current slide has been
333 // automatically created or has been set by the user.
334 if (sName != sCurrentSlideName)
335 sCurrentSlideName = sName;
336 }
337 }
338 catch (const beans::UnknownPropertyException&)
339 {
340 }
341 }
342
343 // Replace the placeholders with their current values.
344 for (auto& rxPane : mpPaneContainer->maPanes)
345 {
346 OSL_ASSERT(rxPane != nullptr);
347
348 OUString sTemplate (IsAccessibilityActive()
349 ? rxPane->msAccessibleTitleTemplate
350 : rxPane->msTitleTemplate);
351 if (sTemplate.isEmpty())
352 continue;
353
354 OUStringBuffer sResult;
355 sResult.ensureCapacity(sTemplate.getLength());
356
357 sal_Int32 nIndex (0);
358 while (true)
359 {
360 sal_Int32 nStartIndex = sTemplate.indexOf('%', nIndex);
361 if (nStartIndex < 0)
362 {
363 // Add the remaining part of the string.
364 sResult.append(sTemplate.subView(nIndex));
365 break;
366 }
367 else
368 {
369 // Add the part preceding the next %.
370 sResult.append(sTemplate.subView(nIndex, nStartIndex-nIndex));
371
372 // Get the placeholder
373 ++nStartIndex;
374 const sal_Int32 nEndIndex (sTemplate.indexOf('%', nStartIndex+1));
375 const std::u16string_view sPlaceholder (sTemplate.subView(nStartIndex, nEndIndex-nStartIndex));
376 nIndex = nEndIndex+1;
377
378 // Replace the placeholder with its current value.
379 if (sPlaceholder == sCurrentSlideNumberPlaceholder)
380 sResult.append(sCurrentSlideNumber);
381 else if (sPlaceholder == sCurrentSlideNamePlaceholder)
382 sResult.append(sCurrentSlideName);
383 else if (sPlaceholder == sSlideCountPlaceholder)
384 sResult.append(sSlideCount);
385 }
386 }
387
388 rxPane->msTitle = sResult.makeStringAndClear();
389 if (rxPane->mxPane.is())
390 rxPane->mxPane->SetTitle(rxPane->msTitle);
391 }
392}
393
395{
396 // Tell all views about the slides they should display.
397 for (const auto& rxPane : mpPaneContainer->maPanes)
398 {
399 Reference<drawing::XDrawView> xDrawView (rxPane->mxView, UNO_QUERY);
400 if (xDrawView.is())
401 xDrawView->setCurrentPage(mxCurrentSlide);
402 }
403}
404
406 PresenterController::GetViewBackground (const OUString& rsViewURL) const
407{
408 if (mpTheme != nullptr)
409 {
410 const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
411 return mpTheme->GetBitmap(sStyleName, "Background");
412 }
413 return SharedBitmapDescriptor();
414}
415
417 PresenterController::GetViewFont (const OUString& rsViewURL) const
418{
419 if (mpTheme != nullptr)
420 {
421 const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
422 return mpTheme->GetFont(sStyleName);
423 }
425}
426
427const std::shared_ptr<PresenterTheme>& PresenterController::GetTheme() const
428{
429 return mpTheme;
430}
431
432const ::rtl::Reference<PresenterWindowManager>& PresenterController::GetWindowManager() const
433{
434 return mpWindowManager;
435}
436
437const Reference<presentation::XSlideShowController>&
439{
441}
442
444{
445 return mpPaneContainer;
446}
447
448const ::rtl::Reference<PresenterPaneBorderPainter>& PresenterController::GetPaneBorderPainter() const
449{
450 return mpPaneBorderPainter;
451}
452
453const std::shared_ptr<PresenterCanvasHelper>& PresenterController::GetCanvasHelper() const
454{
455 return mpCanvasHelper;
456}
457
458const Reference<drawing::XPresenterHelper>& PresenterController::GetPresenterHelper() const
459{
460 return mxPresenterHelper;
461}
462
463const std::shared_ptr<PresenterPaintManager>& PresenterController::GetPaintManager() const
464{
465 return mpPaintManager;
466}
467
468void PresenterController::ShowView (const OUString& rsViewURL)
469{
471 mpPaneContainer->FindViewURL(rsViewURL));
472 if (!pDescriptor)
473 return;
474
475 pDescriptor->mbIsActive = true;
476 mxConfigurationController->requestResourceActivation(
477 pDescriptor->mxPaneId,
478 ResourceActivationMode_ADD);
479 mxConfigurationController->requestResourceActivation(
480 ResourceId::createWithAnchor(
482 rsViewURL,
483 pDescriptor->mxPaneId),
484 ResourceActivationMode_REPLACE);
485}
486
487void PresenterController::HideView (const OUString& rsViewURL)
488{
490 mpPaneContainer->FindViewURL(rsViewURL));
491 if (pDescriptor)
492 {
493 mxConfigurationController->requestResourceDeactivation(
494 ResourceId::createWithAnchor(
496 rsViewURL,
497 pDescriptor->mxPaneId));
498 }
499}
500
501void PresenterController::DispatchUnoCommand (const OUString& rsCommand) const
502{
503 if ( ! mxUrlTransformer.is())
504 return;
505
506 util::URL aURL;
507 aURL.Complete = rsCommand;
508 mxUrlTransformer->parseStrict(aURL);
509
510 Reference<frame::XDispatch> xDispatch (GetDispatch(aURL));
511 if ( ! xDispatch.is())
512 return;
513
514 xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>());
515}
516
517Reference<css::frame::XDispatch> PresenterController::GetDispatch (const util::URL& rURL) const
518{
519 if ( ! mxController.is())
520 return nullptr;
521
522 Reference<frame::XDispatchProvider> xDispatchProvider (mxController->getFrame(), UNO_QUERY);
523 if ( ! xDispatchProvider.is())
524 return nullptr;
525
526 return xDispatchProvider->queryDispatch(
527 rURL,
528 OUString(),
529 frame::FrameSearchFlag::SELF);
530}
531
532util::URL PresenterController::CreateURLFromString (const OUString& rsURL) const
533{
534 util::URL aURL;
535
536 if (mxUrlTransformer.is())
537 {
538 aURL.Complete = rsURL;
539 mxUrlTransformer->parseStrict(aURL);
540 }
541
542 return aURL;
543}
544
545const Reference<drawing::framework::XConfigurationController>&
547{
549}
550
551const Reference<drawing::XDrawPage>& PresenterController::GetCurrentSlide() const
552{
553 return mxCurrentSlide;
554}
555
556bool PresenterController::HasTransition (Reference<drawing::XDrawPage> const & rxPage)
557{
558 bool bTransition = false;
559 if( rxPage.is() )
560 {
561 Reference<beans::XPropertySet> xSlidePropertySet (rxPage, UNO_QUERY);
562 try
563 {
564 sal_uInt16 aTransitionType = 0;
565 xSlidePropertySet->getPropertyValue("TransitionType") >>= aTransitionType;
566 if (aTransitionType > 0)
567 {
568 bTransition = true;
569 }
570 }
571 catch (const beans::UnknownPropertyException&)
572 {
573 }
574 }
575 return bTransition;
576}
577
578bool PresenterController::HasCustomAnimation (Reference<drawing::XDrawPage> const & rxPage)
579{
580 bool bCustomAnimation = false;
581 if( rxPage.is() )
582 {
583 sal_uInt32 i, nCount = rxPage->getCount();
584 for ( i = 0; i < nCount; i++ )
585 {
586 Reference<drawing::XShape> xShape(rxPage->getByIndex(i), UNO_QUERY);
587 Reference<beans::XPropertySet> xShapePropertySet(xShape, UNO_QUERY);
588 presentation::AnimationEffect aEffect = presentation::AnimationEffect_NONE;
589 presentation::AnimationEffect aTextEffect = presentation::AnimationEffect_NONE;
590 try
591 {
592 xShapePropertySet->getPropertyValue("Effect") >>= aEffect;
593 xShapePropertySet->getPropertyValue("TextEffect") >>= aTextEffect;
594 }
595 catch (const beans::UnknownPropertyException&)
596 {
597 }
598 if( aEffect != presentation::AnimationEffect_NONE ||
599 aTextEffect != presentation::AnimationEffect_NONE )
600 {
601 bCustomAnimation = true;
602 break;
603 }
604 }
605 }
606 return bCustomAnimation;
607}
608
610{
611 if ( mbIsAccessibilityActive != bIsActive)
612 {
613 mbIsAccessibilityActive = bIsActive;
615 }
616}
617
618
619void PresenterController::HandleMouseClick (const awt::MouseEvent& rEvent)
620{
621 if (!mxSlideShowController.is())
622 return;
623
624 switch (rEvent.Buttons)
625 {
626 case awt::MouseButton::LEFT:
627 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
628 mxSlideShowController->gotoNextSlide();
629 else
630 mxSlideShowController->gotoNextEffect();
631 break;
632
633 case awt::MouseButton::RIGHT:
634 mxSlideShowController->gotoPreviousSlide();
635 break;
636
637 default:
638 // Other or multiple buttons.
639 break;
640 }
641}
642
644 const bool bIsSlideSorterActive,
645 const bool bIsNotesViewActive,
646 const bool bIsHelpViewActive)
647{
648 for (const auto& rxPane : mpPaneContainer->maPanes)
649 {
650 bool bActivate (true);
651 const OUString sViewURL (rxPane->msViewURL);
653 {
654 bActivate = bIsNotesViewActive && !bIsSlideSorterActive && !bIsHelpViewActive;
655 }
656 else if (sViewURL == PresenterViewFactory::msSlideSorterURL)
657 {
658 bActivate = bIsSlideSorterActive;
659 }
662 {
663 bActivate = !bIsSlideSorterActive && ! bIsHelpViewActive;
664 }
665 else if (sViewURL == PresenterViewFactory::msToolBarViewURL)
666 {
667 bActivate = true;
668 }
669 else if (sViewURL == PresenterViewFactory::msHelpViewURL)
670 {
671 bActivate = bIsHelpViewActive;
672 }
673
674 if (bActivate)
675 ShowView(sViewURL);
676 else
677 HideView(sViewURL);
678 }
679}
680
682{
683 mpPresentationTime = pPresentationTime;
684}
685
687{
688 return mpPresentationTime;
689}
690
691//----- XConfigurationChangeListener ------------------------------------------
692
694 const ConfigurationChangeEvent& rEvent)
695{
696 if (rBHelper.bDisposed || rBHelper.bInDispose)
697 {
698 throw lang::DisposedException (
699 "PresenterController object has already been disposed",
700 static_cast<uno::XWeak*>(this));
701 }
702
703 sal_Int32 nType (0);
704 if ( ! (rEvent.UserData >>= nType))
705 return;
706
707 switch (nType)
708 {
709 case ResourceActivationEventType:
710 if (rEvent.ResourceId->compareTo(mxMainPaneId) == 0)
711 {
712 InitializeMainPane(Reference<XPane>(rEvent.ResourceObject,UNO_QUERY));
713 }
714 else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_DIRECT))
715 {
716 // A pane bound to the main pane has been created and is
717 // stored in the pane container.
718 Reference<XPane> xPane (rEvent.ResourceObject,UNO_QUERY);
719 if (xPane.is())
720 {
721 mpPaneContainer->FindPaneId(xPane->getResourceId());
722 }
723 }
724 else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
725 {
726 // A view bound to one of the panes has been created and is
727 // stored in the pane container along with its pane.
728 Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
729 if (xView.is())
730 {
731 mpPaneContainer->StoreView(xView);
732 UpdateViews();
733 mpWindowManager->NotifyViewCreation(xView);
734 }
735 }
736 break;
737
738 case ResourceDeactivationEventType:
739 if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
740 {
741 // If this is a view then remove it from the pane container.
742 Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
743 if (xView.is())
744 {
746 mpPaneContainer->RemoveView(xView));
747
748 // A possibly opaque view has been removed. Update()
749 // updates the clip polygon.
750 mpWindowManager->Update();
751 // Request the repainting of the area previously
752 // occupied by the view.
753 if (pDescriptor)
754 GetPaintManager()->Invalidate(pDescriptor->mxBorderWindow);
755 }
756 }
757 break;
758
759 case ConfigurationUpdateEndEventType:
761 {
762 mpAccessibleObject->UpdateAccessibilityHierarchy();
764 }
765 break;
766 }
767}
768
769//----- XEventListener --------------------------------------------------------
770
771void SAL_CALL PresenterController::disposing (
772 const lang::EventObject& rEvent)
773{
774 if (rEvent.Source.get() == static_cast<cppu::OWeakObject*>(mxController.get()))
775 mxController = nullptr;
776 else if (rEvent.Source == mxConfigurationController)
778 else if (rEvent.Source == mxSlideShowController)
779 mxSlideShowController = nullptr;
780 else if (rEvent.Source == mxMainWindow)
781 mxMainWindow = nullptr;
782}
783
784//----- XFrameActionListener --------------------------------------------------
785
787 const frame::FrameActionEvent& rEvent)
788{
789 if (rEvent.Action == frame::FrameAction_FRAME_ACTIVATED)
790 {
791 if (mxSlideShowController.is())
792 mxSlideShowController->activate();
793 }
794}
795
796//----- XKeyListener ----------------------------------------------------------
797
798void SAL_CALL PresenterController::keyPressed (const awt::KeyEvent& rEvent)
799{
800 // Tell all views about the unhandled key event.
801 for (const auto& rxPane : mpPaneContainer->maPanes)
802 {
803 if ( ! rxPane->mbIsActive)
804 continue;
805
806 Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
807 if (xKeyListener.is())
808 xKeyListener->keyPressed(rEvent);
809 }
810}
811
812void SAL_CALL PresenterController::keyReleased (const awt::KeyEvent& rEvent)
813{
814 if (rEvent.Source != mxMainWindow)
815 return;
816
817 switch (rEvent.KeyCode)
818 {
819 case awt::Key::ESCAPE:
820 case awt::Key::SUBTRACT:
821 {
822 if( mxController.is() )
823 {
824 Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
825 if( xPS.is() )
826 {
827 Reference< XPresentation > xP( xPS->getPresentation() );
828 if( xP.is() )
829 xP->end();
830 }
831 }
832 }
833 break;
834
835 case awt::Key::PAGEDOWN:
836 if (mxSlideShowController.is())
837 {
838 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
839 mxSlideShowController->gotoNextSlide();
840 else
841 mxSlideShowController->gotoNextEffect();
842 }
843 break;
844
845 case awt::Key::RIGHT:
846 case awt::Key::SPACE:
847 case awt::Key::DOWN:
848 if (mxSlideShowController.is())
849 {
850 mxSlideShowController->gotoNextEffect();
851 }
852 break;
853
854 case awt::Key::PAGEUP:
855 if (mxSlideShowController.is())
856 {
857 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
858 mxSlideShowController->gotoPreviousSlide();
859 else
860 mxSlideShowController->gotoPreviousEffect();
861 }
862 break;
863
864 case awt::Key::LEFT:
865 case awt::Key::UP:
866 case awt::Key::BACKSPACE:
867 if (mxSlideShowController.is())
868 {
869 mxSlideShowController->gotoPreviousEffect();
870 }
871 break;
872
873 case awt::Key::P:
874 if (mxSlideShowController.is())
875 {
876 bool bPenEnabled = mxSlideShowController->getUsePen();
877 mxSlideShowController->setUsePen( !bPenEnabled );
878 }
879 break;
880
881 // tdf#149351 Ctrl+A disables pointer as pen mode
882 case awt::Key::A:
883 if (mxSlideShowController.is())
884 {
885 if (rEvent.Modifiers == awt::KeyModifier::MOD1)
886 {
887 mxSlideShowController->setUsePen( false );
888 }
889 }
890 break;
891
892 case awt::Key::E:
893 if (mxSlideShowController.is())
894 {
895 mxSlideShowController->setEraseAllInk( true );
896 }
897 break;
898
899 case awt::Key::HOME:
900 if (mxSlideShowController.is())
901 {
902 mxSlideShowController->gotoFirstSlide();
903 }
904 break;
905
906 case awt::Key::END:
907 if (mxSlideShowController.is())
908 {
909 mxSlideShowController->gotoLastSlide();
910 }
911 break;
912
913 case awt::Key::W:
914 case awt::Key::COMMA:
915 if (mxSlideShowController.is())
916 {
917 if (mxSlideShowController->isPaused())
918 mxSlideShowController->resume();
919 else
920 mxSlideShowController->blankScreen(0x00ffffff);
921 }
922 break;
923
924 case awt::Key::B:
925 case awt::Key::POINT:
926 if (mxSlideShowController.is())
927 {
928 if (mxSlideShowController->isPaused())
929 mxSlideShowController->resume();
930 else
931 mxSlideShowController->blankScreen(0x00000000);
932 }
933 break;
934
935 case awt::Key::NUM0:
936 case awt::Key::NUM1:
937 case awt::Key::NUM2:
938 case awt::Key::NUM3:
939 case awt::Key::NUM4:
940 case awt::Key::NUM5:
941 case awt::Key::NUM6:
942 case awt::Key::NUM7:
943 case awt::Key::NUM8:
944 case awt::Key::NUM9:
945 HandleNumericKeyPress(rEvent.KeyCode-awt::Key::NUM0, rEvent.Modifiers);
946 break;
947
948 case awt::Key::RETURN:
949 if (mnPendingSlideNumber > 0)
950 {
951 if (mxSlideShowController.is())
952 mxSlideShowController->gotoSlideIndex(mnPendingSlideNumber - 1);
954 }
955 else
956 {
957 if (mxSlideShowController.is())
958 mxSlideShowController->gotoNextEffect();
959 }
960
961 break;
962
963 case awt::Key::F1:
964 // Toggle the help view.
965 if (mpWindowManager)
966 {
969 else
970 mpWindowManager->SetHelpViewState(false);
971 }
972
973 break;
974
975 default:
976 // Tell all views about the unhandled key event.
977 for (const auto& rxPane : mpPaneContainer->maPanes)
978 {
979 if ( ! rxPane->mbIsActive)
980 continue;
981
982 Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
983 if (xKeyListener.is())
984 xKeyListener->keyReleased(rEvent);
985 }
986 break;
987 }
988}
989
991 const sal_Int32 nKey,
992 const sal_Int32 nModifiers)
993{
994 switch (nModifiers)
995 {
996 case 0:
997 if (mnPendingSlideNumber == -1)
1000 break;
1001
1002 case awt::KeyModifier::MOD1:
1003 // Ctrl-1, Ctrl-2, and Ctrl-3 are used to switch between views
1004 // (slide view, notes view, normal). Ctrl-4 switches monitors
1006 if (!mpWindowManager)
1007 return;
1008 switch(nKey)
1009 {
1010 case 1:
1012 break;
1013 case 2:
1015 break;
1016 case 3:
1018 break;
1019 case 4:
1021 break;
1022 default:
1023 // Ignore unsupported key.
1024 break;
1025 }
1026 break;
1027
1028 default:
1029 // Ignore unsupported modifiers.
1030 break;
1031 }
1032}
1033
1034//----- XMouseListener --------------------------------------------------------
1035
1036void SAL_CALL PresenterController::mousePressed (const css::awt::MouseEvent&)
1037{
1038 if (mxMainWindow.is())
1039 mxMainWindow->setFocus();
1040}
1041
1042void SAL_CALL PresenterController::mouseReleased (const css::awt::MouseEvent&) {}
1043
1044void SAL_CALL PresenterController::mouseEntered (const css::awt::MouseEvent&) {}
1045
1046void SAL_CALL PresenterController::mouseExited (const css::awt::MouseEvent&) {}
1047
1048void PresenterController::InitializeMainPane (const Reference<XPane>& rxPane)
1049{
1050 if ( ! rxPane.is())
1051 return;
1052
1055 this,
1056 rxPane);
1057
1058 LoadTheme(rxPane);
1059
1060 // Main pane has been created and is now observed by the window
1061 // manager.
1062 mpWindowManager->SetParentPane(rxPane);
1063 mpWindowManager->SetTheme(mpTheme);
1064
1066 mpPaneBorderPainter->SetTheme(mpTheme);
1067
1068 // Add key listener
1069 mxMainWindow = rxPane->getWindow();
1070 if (mxMainWindow.is())
1071 {
1072 mxMainWindow->addKeyListener(this);
1073 mxMainWindow->addMouseListener(this);
1074 }
1075 Reference<XPane2> xPane2 (rxPane, UNO_QUERY);
1076 if (xPane2.is())
1077 xPane2->setVisible(true);
1078
1079 mpPaintManager = std::make_shared<PresenterPaintManager>(mxMainWindow, mxPresenterHelper, mpPaneContainer);
1080
1081 mxCanvas.set(rxPane->getCanvas(), UNO_QUERY);
1082
1083 if (mxSlideShowController.is())
1084 mxSlideShowController->activate();
1085
1087}
1088
1089void PresenterController::LoadTheme (const Reference<XPane>& rxPane)
1090{
1091 // Create (load) the current theme.
1092 if (rxPane.is())
1093 mpTheme = std::make_shared<PresenterTheme>(mxComponentContext, rxPane->getCanvas());
1094}
1095
1097{
1098 double nSlideAspectRatio (28.0/21.0);
1099
1100 try
1101 {
1102 if (mxController.is())
1103 {
1104 Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
1105 mxController->getModel(), UNO_QUERY_THROW);
1106 Reference<drawing::XDrawPages> xSlides (xSlideSupplier->getDrawPages());
1107 if (xSlides.is() && xSlides->getCount()>0)
1108 {
1109 Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
1110 sal_Int32 nWidth (28000);
1111 sal_Int32 nHeight (21000);
1112 if ((xProperties->getPropertyValue("Width") >>= nWidth)
1113 && (xProperties->getPropertyValue("Height") >>= nHeight)
1114 && nHeight > 0)
1115 {
1116 nSlideAspectRatio = double(nWidth) / double(nHeight);
1117 }
1118 }
1119 }
1120 }
1121 catch (RuntimeException&)
1122 {
1123 OSL_ASSERT(false);
1124 }
1125
1126 return nSlideAspectRatio;
1127}
1128
1129void PresenterController::UpdatePendingSlideNumber (const sal_Int32 nPendingSlideNumber)
1130{
1131 mnPendingSlideNumber = nPendingSlideNumber;
1132
1133 if (mpTheme == nullptr)
1134 return;
1135
1136 if ( ! mxMainWindow.is())
1137 return;
1138
1140 mpTheme->GetFont("PendingSlideNumberFont"));
1141 if (!pFont)
1142 return;
1143
1144 pFont->PrepareFont(mxCanvas);
1145 if ( ! pFont->mxFont.is())
1146 return;
1147
1148 const OUString sText (OUString::number(mnPendingSlideNumber));
1149 rendering::StringContext aContext (sText, 0, sText.getLength());
1150 pFont->mxFont->createTextLayout(
1151 aContext,
1152 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1153 0);
1154}
1155
1157{
1159 if (!pScreen)
1160 return;
1161
1162 pScreen->SwitchMonitors();
1163}
1164
1166{
1167 if( mxController.is() )
1168 {
1169 Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
1170 if( xPS.is() )
1171 {
1172 Reference< XPresentation > xP( xPS->getPresentation() );
1173 if( xP.is() )
1174 xP->end();
1175 }
1176 }
1177}
1178
1179} // end of namespace ::sdext::presenter
1180
1181/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::uno::XComponentContext > mxComponentContext
Represents an element in the toolbar that shows the time elapsed since the presentation started.
Collection of functions to ease the life of a canvas user.
void SetAccessibilityActiveState(const bool bIsActive)
css::uno::Reference< css::uno::XComponentContext > mxComponentContext
virtual void SAL_CALL mouseReleased(const css::awt::MouseEvent &rEvent) override
css::uno::Reference< css::presentation::XSlideShowController > mxSlideShowController
void GetSlides(const sal_Int32 nOffset)
const std::shared_ptr< PresenterPaintManager > & GetPaintManager() const
rtl::Reference<::sd::DrawController > mxController
void SetPresentationTime(IPresentationTime *pPresentationTime)
css::uno::Reference< css::drawing::XPresenterHelper > mxPresenterHelper
void InitializeMainPane(const css::uno::Reference< css::drawing::framework::XPane > &rxPane)
virtual void SAL_CALL notifyConfigurationChange(const css::drawing::framework::ConfigurationChangeEvent &rEvent) override
virtual void SAL_CALL keyPressed(const css::awt::KeyEvent &rEvent) override
const css::uno::Reference< css::drawing::framework::XConfigurationController > & GetConfigurationController() const
void HandleMouseClick(const css::awt::MouseEvent &rEvent)
css::uno::Reference< css::drawing::XDrawPage > mxCurrentSlide
void ShowView(const OUString &rsViewURL)
const css::uno::Reference< css::drawing::XDrawPage > & GetCurrentSlide() const
const ::rtl::Reference< PresenterWindowManager > & GetWindowManager() const
css::uno::Reference< css::rendering::XSpriteCanvas > mxCanvas
css::uno::Reference< css::frame::XDispatch > GetDispatch(const css::util::URL &rURL) const
virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent &rEvent) override
void DispatchUnoCommand(const OUString &rsCommand) const
virtual void SAL_CALL keyReleased(const css::awt::KeyEvent &rEvent) override
void UpdatePendingSlideNumber(const sal_Int32 nPendingSlideNumber)
const ::rtl::Reference< PresenterPaneBorderPainter > & GetPaneBorderPainter() const
virtual void SAL_CALL mouseExited(const css::awt::MouseEvent &rEvent) override
std::shared_ptr< PresenterCanvasHelper > mpCanvasHelper
virtual void SAL_CALL disposing() override
static bool HasTransition(css::uno::Reference< css::drawing::XDrawPage > const &rxPage)
const std::shared_ptr< PresenterCanvasHelper > & GetCanvasHelper() const
static bool HasCustomAnimation(css::uno::Reference< css::drawing::XDrawPage > const &rxPage)
const rtl::Reference< PresenterPaneContainer > & GetPaneContainer() const
PresenterTheme::SharedFontDescriptor GetViewFont(const OUString &rsViewURL) const
css::uno::Reference< css::awt::XWindow > mxMainWindow
virtual void SAL_CALL mousePressed(const css::awt::MouseEvent &rEvent) override
static ::rtl::Reference< PresenterController > Instance(const css::uno::Reference< css::frame::XFrame > &rxFrame)
const css::uno::Reference< css::drawing::XPresenterHelper > & GetPresenterHelper() const
std::shared_ptr< PresenterPaintManager > mpPaintManager
void LoadTheme(const css::uno::Reference< css::drawing::framework::XPane > &rxPane)
css::uno::Reference< css::util::XURLTransformer > mxUrlTransformer
void HandleNumericKeyPress(const sal_Int32 nKey, const sal_Int32 nModifiers)
This method is called when the user pressed one of the numerical keys.
void HideView(const OUString &rsViewURL)
rtl::Reference< PresenterPaneContainer > mpPaneContainer
SharedBitmapDescriptor GetViewBackground(const OUString &rsViewURL) const
std::shared_ptr< PresenterTheme > mpTheme
const css::uno::Reference< css::presentation::XSlideShowController > & GetSlideShowController() const
const std::shared_ptr< PresenterTheme > & GetTheme() const
::std::map< css::uno::Reference< css::frame::XFrame >, rtl::Reference< PresenterController > > InstanceContainer
css::uno::Reference< css::drawing::framework::XResourceId > mxMainPaneId
css::uno::Reference< css::drawing::XDrawPage > mxNextSlide
virtual void SAL_CALL mouseEntered(const css::awt::MouseEvent &rEvent) override
unotools::WeakReference< PresenterScreen > mxScreen
void UpdateCurrentSlide(const sal_Int32 nOffset)
::rtl::Reference< PresenterPaneBorderPainter > mpPaneBorderPainter
css::util::URL CreateURLFromString(const OUString &rsURL) const
::rtl::Reference< PresenterAccessible > mpAccessibleObject
css::uno::Reference< css::drawing::framework::XConfigurationController > mxConfigurationController
void RequestViews(const bool bIsSlideSorterActive, const bool bIsNotesViewActive, const bool bIsHelpViewActive)
Request activation or deactivation of (some of) the views according to the given parameters.
::rtl::Reference< PresenterWindowManager > mpWindowManager
PresenterController(unotools::WeakReference< PresenterScreen > xScreen, const css::uno::Reference< css::uno::XComponentContext > &rxContext, const rtl::Reference<::sd::DrawController > &rxController, const css::uno::Reference< css::presentation::XSlideShowController > &rxSlideShowController, rtl::Reference< PresenterPaneContainer > xPaneContainer, const css::uno::Reference< css::drawing::framework::XResourceId > &rxMainPaneId)
Check periodically the slide show controller and the frame::XController whether the current slide has...
This class is responsible for painting window borders of PresenterPane objects.
std::shared_ptr< PaneDescriptor > SharedPaneDescriptor
std::shared_ptr< FontDescriptor > SharedFontDescriptor
static constexpr OUStringLiteral msCurrentSlidePreviewViewURL
static constexpr OUStringLiteral msToolBarViewURL
static constexpr OUStringLiteral msNotesViewURL
static constexpr OUStringLiteral msSlideSorterURL
static constexpr OUStringLiteral msNextSlidePreviewViewURL
static constexpr OUStringLiteral msHelpViewURL
A simple manager of the positions of the panes of the presenter screen.
int nCount
Reference< XDispatch > xDispatch
URL aURL
float u
Reference< XSingleServiceFactory > xFactory
OUString sName
std::mutex m_aMutex
sal_Int32 nIndex
int i
std::shared_ptr< T > make_shared(Args &&... args)
::cppu::WeakComponentImplHelper< css::drawing::framework::XConfigurationChangeListener, css::frame::XFrameActionListener, css::awt::XKeyListener, css::awt::XMouseListener > PresenterControllerInterfaceBase
std::shared_ptr< PresenterBitmapContainer::BitmapDescriptor > SharedBitmapDescriptor
QPRO_FUNC_TYPE nType
Reference< XFrame > xFrame