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