update credits
[LibreOffice.git] / sdext / source / presenter / PresenterController.cxx
blob86b57ca7379494b981ec1f7b0608d561e4c52eea
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <string_view>
24 #include "PresenterController.hxx"
26 #include "PresenterAccessibility.hxx"
27 #include "PresenterCanvasHelper.hxx"
28 #include "PresenterCurrentSlideObserver.hxx"
29 #include "PresenterScreen.hxx"
30 #include "PresenterPaintManager.hxx"
31 #include "PresenterPaneBase.hxx"
32 #include "PresenterPaneContainer.hxx"
33 #include "PresenterPaneBorderPainter.hxx"
34 #include "PresenterTheme.hxx"
35 #include "PresenterViewFactory.hxx"
36 #include "PresenterWindowManager.hxx"
38 #include <com/sun/star/awt/Key.hpp>
39 #include <com/sun/star/awt/KeyModifier.hpp>
40 #include <com/sun/star/awt/MouseButton.hpp>
41 #include <com/sun/star/container/XNamed.hpp>
42 #include <com/sun/star/drawing/XDrawView.hpp>
43 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
44 #include <com/sun/star/drawing/framework/ResourceActivationMode.hpp>
45 #include <com/sun/star/drawing/framework/ResourceId.hpp>
46 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
47 #include <com/sun/star/frame/FrameSearchFlag.hpp>
48 #include <com/sun/star/frame/XDispatchProvider.hpp>
49 #include <com/sun/star/presentation/AnimationEffect.hpp>
50 #include <com/sun/star/presentation/XPresentation.hpp>
51 #include <com/sun/star/presentation/XPresentationSupplier.hpp>
52 #include <com/sun/star/rendering/TextDirection.hpp>
53 #include <com/sun/star/util/URLTransformer.hpp>
55 #include <rtl/ustrbuf.hxx>
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::presentation;
60 using namespace ::com::sun::star::drawing::framework;
62 namespace {
63 const sal_Int32 ResourceActivationEventType = 0;
64 const sal_Int32 ResourceDeactivationEventType = 1;
65 const sal_Int32 ConfigurationUpdateEndEventType = 2;
68 namespace sdext::presenter {
70 IPresentationTime::~IPresentationTime()
74 PresenterController::InstanceContainer PresenterController::maInstances;
76 ::rtl::Reference<PresenterController> PresenterController::Instance (
77 const css::uno::Reference<css::frame::XFrame>& rxFrame)
79 InstanceContainer::const_iterator iInstance (maInstances.find(rxFrame));
80 if (iInstance != maInstances.end())
81 return iInstance->second;
82 else
83 return ::rtl::Reference<PresenterController>();
86 PresenterController::PresenterController (
87 const css::uno::WeakReference<css::lang::XEventListener> &rxScreen,
88 const Reference<XComponentContext>& rxContext,
89 const Reference<frame::XController>& rxController,
90 const Reference<presentation::XSlideShowController>& rxSlideShowController,
91 const rtl::Reference<PresenterPaneContainer>& rpPaneContainer,
92 const Reference<XResourceId>& rxMainPaneId)
93 : PresenterControllerInterfaceBase(m_aMutex),
94 mxScreen(rxScreen),
95 mxComponentContext(rxContext),
96 mxController(rxController),
97 mxConfigurationController(),
98 mxSlideShowController(rxSlideShowController),
99 mxMainPaneId(rxMainPaneId),
100 mpPaneContainer(rpPaneContainer),
101 mnCurrentSlideIndex(-1),
102 mxCurrentSlide(),
103 mxNextSlide(),
104 mpWindowManager(new PresenterWindowManager(rxContext,mpPaneContainer,this)),
105 mpTheme(),
106 mxMainWindow(),
107 mpPaneBorderPainter(),
108 mpCanvasHelper(std::make_shared<PresenterCanvasHelper>()),
109 mxPresenterHelper(),
110 mpPaintManager(),
111 mnPendingSlideNumber(-1),
112 mxUrlTransformer(),
113 mpAccessibleObject(),
114 mbIsAccessibilityActive(false)
116 OSL_ASSERT(mxController.is());
118 if ( ! mxSlideShowController.is())
119 throw lang::IllegalArgumentException(
120 "missing slide show controller",
121 static_cast<XWeak*>(this),
124 new PresenterCurrentSlideObserver(this,rxSlideShowController);
126 // Listen for configuration changes.
127 Reference<XControllerManager> xCM (mxController, UNO_QUERY_THROW);
128 mxConfigurationController = xCM->getConfigurationController();
129 if (mxConfigurationController.is())
131 mxConfigurationController->addConfigurationChangeListener(
132 this,
133 "ResourceActivation",
134 Any(ResourceActivationEventType));
135 mxConfigurationController->addConfigurationChangeListener(
136 this,
137 "ResourceDeactivation",
138 Any(ResourceDeactivationEventType));
139 mxConfigurationController->addConfigurationChangeListener(
140 this,
141 "ConfigurationUpdateEnd",
142 Any(ConfigurationUpdateEndEventType));
145 // Listen for the frame being activated.
146 Reference<frame::XFrame> xFrame (mxController->getFrame());
147 if (xFrame.is())
148 xFrame->addFrameActionListener(this);
150 // Create the border painter.
151 mpPaneBorderPainter = new PresenterPaneBorderPainter(rxContext);
152 mpWindowManager->SetPaneBorderPainter(mpPaneBorderPainter);
154 // Create an object that is able to load the bitmaps in a format that is
155 // supported by the canvas.
156 Reference<lang::XMultiComponentFactory> xFactory =
157 rxContext->getServiceManager();
158 if ( ! xFactory.is())
159 return;
160 mxPresenterHelper.set(
161 xFactory->createInstanceWithContext(
162 "com.sun.star.drawing.PresenterHelper",
163 rxContext),
164 UNO_QUERY_THROW);
166 if (mxSlideShowController.is())
168 mxSlideShowController->activate();
169 Reference<beans::XPropertySet> xProperties (mxSlideShowController, UNO_QUERY);
170 if (xProperties.is())
172 Reference<awt::XWindow> xWindow (
173 xProperties->getPropertyValue("ParentWindow"), UNO_QUERY);
174 if (xWindow.is())
175 xWindow->addKeyListener(this);
179 UpdateCurrentSlide(0);
181 maInstances[mxController->getFrame()] = this;
183 // Create a URLTransformer.
184 if (xFactory.is())
186 mxUrlTransformer.set(util::URLTransformer::create(mxComponentContext));
190 PresenterController::~PresenterController()
194 void PresenterController::disposing()
196 maInstances.erase(mxController->getFrame());
198 if (mxMainWindow.is())
200 mxMainWindow->removeKeyListener(this);
201 mxMainWindow->removeMouseListener(this);
202 mxMainWindow = nullptr;
204 if (mxConfigurationController.is())
205 mxConfigurationController->removeConfigurationChangeListener(this);
207 if (mxController.is())
209 Reference<frame::XFrame> xFrame (mxController->getFrame());
210 if (xFrame.is())
211 xFrame->removeFrameActionListener(this);
212 mxController = nullptr;
215 Reference<XComponent> xWindowManagerComponent (
216 static_cast<XWeak*>(mpWindowManager.get()), UNO_QUERY);
217 mpWindowManager = nullptr;
218 if (xWindowManagerComponent.is())
219 xWindowManagerComponent->dispose();
221 mxComponentContext = nullptr;
222 mxConfigurationController = nullptr;
223 mxSlideShowController = nullptr;
224 mxMainPaneId = nullptr;
225 mpPaneContainer = nullptr;
226 mnCurrentSlideIndex = -1;
227 mxCurrentSlide = nullptr;
228 mxNextSlide = nullptr;
229 mpTheme.reset();
231 Reference<lang::XComponent> xComponent (
232 static_cast<XWeak*>(mpPaneBorderPainter.get()), UNO_QUERY);
233 mpPaneBorderPainter = nullptr;
234 if (xComponent.is())
235 xComponent->dispose();
237 mpCanvasHelper.reset();
239 Reference<lang::XComponent> xComponent (mxPresenterHelper, UNO_QUERY);
240 mxPresenterHelper = nullptr;
241 if (xComponent.is())
242 xComponent->dispose();
244 mpPaintManager.reset();
245 mnPendingSlideNumber = -1;
247 Reference<lang::XComponent> xComponent (mxUrlTransformer, UNO_QUERY);
248 mxUrlTransformer = nullptr;
249 if (xComponent.is())
250 xComponent->dispose();
254 void PresenterController::UpdateCurrentSlide (const sal_Int32 nOffset)
256 // std::cerr << "Updating current Slide to " << nOffset << std::endl;
257 GetSlides(nOffset);
258 UpdatePaneTitles();
259 UpdateViews();
261 // Update the accessibility object.
262 if (IsAccessibilityActive())
264 mpAccessibleObject->NotifyCurrentSlideChange();
268 void PresenterController::GetSlides (const sal_Int32 nOffset)
270 if ( ! mxSlideShowController.is())
271 return;
273 // Get the current slide from the slide show controller.
274 mxCurrentSlide = nullptr;
275 Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
278 sal_Int32 nSlideIndex = mxSlideShowController->getCurrentSlideIndex() + nOffset;
279 if (mxSlideShowController->isPaused())
280 nSlideIndex = -1;
282 if (xIndexAccess.is() && nSlideIndex>=0)
284 if (nSlideIndex < xIndexAccess->getCount())
286 mnCurrentSlideIndex = nSlideIndex;
287 mxCurrentSlide.set( xIndexAccess->getByIndex(nSlideIndex), UNO_QUERY);
291 catch (RuntimeException&)
295 // Get the next slide.
296 mxNextSlide = nullptr;
299 const sal_Int32 nNextSlideIndex (mxSlideShowController->getNextSlideIndex()+nOffset);
300 if (nNextSlideIndex >= 0)
302 if (xIndexAccess.is())
304 if (nNextSlideIndex < xIndexAccess->getCount())
305 mxNextSlide.set( xIndexAccess->getByIndex(nNextSlideIndex), UNO_QUERY);
309 catch (RuntimeException&)
314 void PresenterController::UpdatePaneTitles()
316 if ( ! mxSlideShowController.is())
317 return;
319 // Get placeholders and their values.
320 static const OUStringLiteral sCurrentSlideNumberPlaceholder (u"CURRENT_SLIDE_NUMBER");
321 static const OUStringLiteral sCurrentSlideNamePlaceholder (u"CURRENT_SLIDE_NAME");
322 static const OUStringLiteral sSlideCountPlaceholder (u"SLIDE_COUNT");
324 // Get string for slide count.
325 OUString sSlideCount ("---");
326 Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
327 if (xIndexAccess.is())
328 sSlideCount = OUString::number(xIndexAccess->getCount());
330 // Get string for current slide index.
331 OUString sCurrentSlideNumber (OUString::number(mnCurrentSlideIndex + 1));
333 // Get name of the current slide.
334 OUString sCurrentSlideName;
335 Reference<container::XNamed> xNamedSlide (mxCurrentSlide, UNO_QUERY);
336 if (xNamedSlide.is())
337 sCurrentSlideName = xNamedSlide->getName();
338 Reference<beans::XPropertySet> xSlideProperties (mxCurrentSlide, UNO_QUERY);
339 if (xSlideProperties.is())
343 OUString sName;
344 if (xSlideProperties->getPropertyValue("LinkDisplayName") >>= sName)
346 // Find out whether the name of the current slide has been
347 // automatically created or has been set by the user.
348 if (sName != sCurrentSlideName)
349 sCurrentSlideName = sName;
352 catch (const beans::UnknownPropertyException&)
357 // Replace the placeholders with their current values.
358 for (auto& rxPane : mpPaneContainer->maPanes)
360 OSL_ASSERT(rxPane != nullptr);
362 OUString sTemplate (IsAccessibilityActive()
363 ? rxPane->msAccessibleTitleTemplate
364 : rxPane->msTitleTemplate);
365 if (sTemplate.isEmpty())
366 continue;
368 OUStringBuffer sResult;
369 sResult.ensureCapacity(sTemplate.getLength());
371 sal_Int32 nIndex (0);
372 while (true)
374 sal_Int32 nStartIndex = sTemplate.indexOf('%', nIndex);
375 if (nStartIndex < 0)
377 // Add the remaining part of the string.
378 sResult.append(sTemplate.subView(nIndex));
379 break;
381 else
383 // Add the part preceding the next %.
384 sResult.append(sTemplate.subView(nIndex, nStartIndex-nIndex));
386 // Get the placeholder
387 ++nStartIndex;
388 const sal_Int32 nEndIndex (sTemplate.indexOf('%', nStartIndex+1));
389 const OUString sPlaceholder (sTemplate.copy(nStartIndex, nEndIndex-nStartIndex));
390 nIndex = nEndIndex+1;
392 // Replace the placeholder with its current value.
393 if (sPlaceholder == sCurrentSlideNumberPlaceholder)
394 sResult.append(sCurrentSlideNumber);
395 else if (sPlaceholder == sCurrentSlideNamePlaceholder)
396 sResult.append(sCurrentSlideName);
397 else if (sPlaceholder == sSlideCountPlaceholder)
398 sResult.append(sSlideCount);
402 rxPane->msTitle = sResult.makeStringAndClear();
403 if (rxPane->mxPane.is())
404 rxPane->mxPane->SetTitle(rxPane->msTitle);
408 void PresenterController::UpdateViews()
410 // Tell all views about the slides they should display.
411 for (const auto& rxPane : mpPaneContainer->maPanes)
413 Reference<drawing::XDrawView> xDrawView (rxPane->mxView, UNO_QUERY);
414 if (xDrawView.is())
415 xDrawView->setCurrentPage(mxCurrentSlide);
419 SharedBitmapDescriptor
420 PresenterController::GetViewBackground (const OUString& rsViewURL) const
422 if (mpTheme != nullptr)
424 const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
425 return mpTheme->GetBitmap(sStyleName, "Background");
427 return SharedBitmapDescriptor();
430 PresenterTheme::SharedFontDescriptor
431 PresenterController::GetViewFont (const OUString& rsViewURL) const
433 if (mpTheme != nullptr)
435 const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
436 return mpTheme->GetFont(sStyleName);
438 return PresenterTheme::SharedFontDescriptor();
441 const std::shared_ptr<PresenterTheme>& PresenterController::GetTheme() const
443 return mpTheme;
446 const ::rtl::Reference<PresenterWindowManager>& PresenterController::GetWindowManager() const
448 return mpWindowManager;
451 const Reference<presentation::XSlideShowController>&
452 PresenterController::GetSlideShowController() const
454 return mxSlideShowController;
457 const rtl::Reference<PresenterPaneContainer>& PresenterController::GetPaneContainer() const
459 return mpPaneContainer;
462 const ::rtl::Reference<PresenterPaneBorderPainter>& PresenterController::GetPaneBorderPainter() const
464 return mpPaneBorderPainter;
467 const std::shared_ptr<PresenterCanvasHelper>& PresenterController::GetCanvasHelper() const
469 return mpCanvasHelper;
472 const Reference<drawing::XPresenterHelper>& PresenterController::GetPresenterHelper() const
474 return mxPresenterHelper;
477 const std::shared_ptr<PresenterPaintManager>& PresenterController::GetPaintManager() const
479 return mpPaintManager;
482 void PresenterController::ShowView (const OUString& rsViewURL)
484 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
485 mpPaneContainer->FindViewURL(rsViewURL));
486 if (!pDescriptor)
487 return;
489 pDescriptor->mbIsActive = true;
490 mxConfigurationController->requestResourceActivation(
491 pDescriptor->mxPaneId,
492 ResourceActivationMode_ADD);
493 mxConfigurationController->requestResourceActivation(
494 ResourceId::createWithAnchor(
495 mxComponentContext,
496 rsViewURL,
497 pDescriptor->mxPaneId),
498 ResourceActivationMode_REPLACE);
501 void PresenterController::HideView (const OUString& rsViewURL)
503 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
504 mpPaneContainer->FindViewURL(rsViewURL));
505 if (pDescriptor)
507 mxConfigurationController->requestResourceDeactivation(
508 ResourceId::createWithAnchor(
509 mxComponentContext,
510 rsViewURL,
511 pDescriptor->mxPaneId));
515 void PresenterController::DispatchUnoCommand (const OUString& rsCommand) const
517 if ( ! mxUrlTransformer.is())
518 return;
520 util::URL aURL;
521 aURL.Complete = rsCommand;
522 mxUrlTransformer->parseStrict(aURL);
524 Reference<frame::XDispatch> xDispatch (GetDispatch(aURL));
525 if ( ! xDispatch.is())
526 return;
528 xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>());
531 Reference<css::frame::XDispatch> PresenterController::GetDispatch (const util::URL& rURL) const
533 if ( ! mxController.is())
534 return nullptr;
536 Reference<frame::XDispatchProvider> xDispatchProvider (mxController->getFrame(), UNO_QUERY);
537 if ( ! xDispatchProvider.is())
538 return nullptr;
540 return xDispatchProvider->queryDispatch(
541 rURL,
542 OUString(),
543 frame::FrameSearchFlag::SELF);
546 util::URL PresenterController::CreateURLFromString (const OUString& rsURL) const
548 util::URL aURL;
550 if (mxUrlTransformer.is())
552 aURL.Complete = rsURL;
553 mxUrlTransformer->parseStrict(aURL);
556 return aURL;
559 const Reference<drawing::framework::XConfigurationController>&
560 PresenterController::GetConfigurationController() const
562 return mxConfigurationController;
565 const Reference<drawing::XDrawPage>& PresenterController::GetCurrentSlide() const
567 return mxCurrentSlide;
570 bool PresenterController::HasTransition (Reference<drawing::XDrawPage> const & rxPage)
572 bool bTransition = false;
573 if( rxPage.is() )
575 Reference<beans::XPropertySet> xSlidePropertySet (rxPage, UNO_QUERY);
578 sal_uInt16 aTransitionType = 0;
579 xSlidePropertySet->getPropertyValue("TransitionType") >>= aTransitionType;
580 if (aTransitionType > 0)
582 bTransition = true;
585 catch (const beans::UnknownPropertyException&)
589 return bTransition;
592 bool PresenterController::HasCustomAnimation (Reference<drawing::XDrawPage> const & rxPage)
594 bool bCustomAnimation = false;
595 if( rxPage.is() )
597 sal_uInt32 i, nCount = rxPage->getCount();
598 for ( i = 0; i < nCount; i++ )
600 Reference<drawing::XShape> xShape(rxPage->getByIndex(i), UNO_QUERY);
601 Reference<beans::XPropertySet> xShapePropertySet(xShape, UNO_QUERY);
602 presentation::AnimationEffect aEffect = presentation::AnimationEffect_NONE;
603 presentation::AnimationEffect aTextEffect = presentation::AnimationEffect_NONE;
606 xShapePropertySet->getPropertyValue("Effect") >>= aEffect;
607 xShapePropertySet->getPropertyValue("TextEffect") >>= aTextEffect;
609 catch (const beans::UnknownPropertyException&)
612 if( aEffect != presentation::AnimationEffect_NONE ||
613 aTextEffect != presentation::AnimationEffect_NONE )
615 bCustomAnimation = true;
616 break;
620 return bCustomAnimation;
623 void PresenterController::SetAccessibilityActiveState (const bool bIsActive)
625 if ( mbIsAccessibilityActive != bIsActive)
627 mbIsAccessibilityActive = bIsActive;
628 UpdatePaneTitles();
633 void PresenterController::HandleMouseClick (const awt::MouseEvent& rEvent)
635 if (!mxSlideShowController.is())
636 return;
638 switch (rEvent.Buttons)
640 case awt::MouseButton::LEFT:
641 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
642 mxSlideShowController->gotoNextSlide();
643 else
644 mxSlideShowController->gotoNextEffect();
645 break;
647 case awt::MouseButton::RIGHT:
648 mxSlideShowController->gotoPreviousSlide();
649 break;
651 default:
652 // Other or multiple buttons.
653 break;
657 void PresenterController::RequestViews (
658 const bool bIsSlideSorterActive,
659 const bool bIsNotesViewActive,
660 const bool bIsHelpViewActive)
662 for (const auto& rxPane : mpPaneContainer->maPanes)
664 bool bActivate (true);
665 const OUString sViewURL (rxPane->msViewURL);
666 if (sViewURL == PresenterViewFactory::msNotesViewURL)
668 bActivate = bIsNotesViewActive && !bIsSlideSorterActive && !bIsHelpViewActive;
670 else if (sViewURL == PresenterViewFactory::msSlideSorterURL)
672 bActivate = bIsSlideSorterActive;
674 else if (sViewURL == PresenterViewFactory::msCurrentSlidePreviewViewURL
675 || sViewURL == PresenterViewFactory::msNextSlidePreviewViewURL)
677 bActivate = !bIsSlideSorterActive && ! bIsHelpViewActive;
679 else if (sViewURL == PresenterViewFactory::msToolBarViewURL)
681 bActivate = true;
683 else if (sViewURL == PresenterViewFactory::msHelpViewURL)
685 bActivate = bIsHelpViewActive;
688 if (bActivate)
689 ShowView(sViewURL);
690 else
691 HideView(sViewURL);
695 void PresenterController::SetPresentationTime(IPresentationTime* pPresentationTime)
697 mpPresentationTime = pPresentationTime;
700 IPresentationTime* PresenterController::GetPresentationTime()
702 return mpPresentationTime;
705 //----- XConfigurationChangeListener ------------------------------------------
707 void SAL_CALL PresenterController::notifyConfigurationChange (
708 const ConfigurationChangeEvent& rEvent)
710 if (rBHelper.bDisposed || rBHelper.bInDispose)
712 throw lang::DisposedException (
713 "PresenterController object has already been disposed",
714 static_cast<uno::XWeak*>(this));
717 sal_Int32 nType (0);
718 if ( ! (rEvent.UserData >>= nType))
719 return;
721 switch (nType)
723 case ResourceActivationEventType:
724 if (rEvent.ResourceId->compareTo(mxMainPaneId) == 0)
726 InitializeMainPane(Reference<XPane>(rEvent.ResourceObject,UNO_QUERY));
728 else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_DIRECT))
730 // A pane bound to the main pane has been created and is
731 // stored in the pane container.
732 Reference<XPane> xPane (rEvent.ResourceObject,UNO_QUERY);
733 if (xPane.is())
735 mpPaneContainer->FindPaneId(xPane->getResourceId());
738 else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
740 // A view bound to one of the panes has been created and is
741 // stored in the pane container along with its pane.
742 Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
743 if (xView.is())
745 mpPaneContainer->StoreView(xView);
746 UpdateViews();
747 mpWindowManager->NotifyViewCreation(xView);
750 break;
752 case ResourceDeactivationEventType:
753 if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
755 // If this is a view then remove it from the pane container.
756 Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
757 if (xView.is())
759 PresenterPaneContainer::SharedPaneDescriptor pDescriptor(
760 mpPaneContainer->RemoveView(xView));
762 // A possibly opaque view has been removed. Update()
763 // updates the clip polygon.
764 mpWindowManager->Update();
765 // Request the repainting of the area previously
766 // occupied by the view.
767 if (pDescriptor)
768 GetPaintManager()->Invalidate(pDescriptor->mxBorderWindow);
771 break;
773 case ConfigurationUpdateEndEventType:
774 if (IsAccessibilityActive())
776 mpAccessibleObject->UpdateAccessibilityHierarchy();
777 UpdateCurrentSlide(0);
779 break;
783 //----- XEventListener --------------------------------------------------------
785 void SAL_CALL PresenterController::disposing (
786 const lang::EventObject& rEvent)
788 if (rEvent.Source == mxController)
789 mxController = nullptr;
790 else if (rEvent.Source == mxConfigurationController)
791 mxConfigurationController = nullptr;
792 else if (rEvent.Source == mxSlideShowController)
793 mxSlideShowController = nullptr;
794 else if (rEvent.Source == mxMainWindow)
795 mxMainWindow = nullptr;
798 //----- XFrameActionListener --------------------------------------------------
800 void SAL_CALL PresenterController::frameAction (
801 const frame::FrameActionEvent& rEvent)
803 if (rEvent.Action == frame::FrameAction_FRAME_ACTIVATED)
805 if (mxSlideShowController.is())
806 mxSlideShowController->activate();
810 //----- XKeyListener ----------------------------------------------------------
812 void SAL_CALL PresenterController::keyPressed (const awt::KeyEvent& rEvent)
814 // Tell all views about the unhandled key event.
815 for (const auto& rxPane : mpPaneContainer->maPanes)
817 if ( ! rxPane->mbIsActive)
818 continue;
820 Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
821 if (xKeyListener.is())
822 xKeyListener->keyPressed(rEvent);
826 void SAL_CALL PresenterController::keyReleased (const awt::KeyEvent& rEvent)
828 if (rEvent.Source != mxMainWindow)
829 return;
831 switch (rEvent.KeyCode)
833 case awt::Key::ESCAPE:
834 case awt::Key::SUBTRACT:
836 if( mxController.is() )
838 Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
839 if( xPS.is() )
841 Reference< XPresentation > xP( xPS->getPresentation() );
842 if( xP.is() )
843 xP->end();
847 break;
849 case awt::Key::PAGEDOWN:
850 if (mxSlideShowController.is())
852 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
853 mxSlideShowController->gotoNextSlide();
854 else
855 mxSlideShowController->gotoNextEffect();
857 break;
859 case awt::Key::RIGHT:
860 case awt::Key::SPACE:
861 case awt::Key::DOWN:
862 if (mxSlideShowController.is())
864 mxSlideShowController->gotoNextEffect();
866 break;
868 case awt::Key::PAGEUP:
869 if (mxSlideShowController.is())
871 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
872 mxSlideShowController->gotoPreviousSlide();
873 else
874 mxSlideShowController->gotoPreviousEffect();
876 break;
878 case awt::Key::LEFT:
879 case awt::Key::UP:
880 case awt::Key::BACKSPACE:
881 if (mxSlideShowController.is())
883 mxSlideShowController->gotoPreviousEffect();
885 break;
887 case awt::Key::P:
888 if (mxSlideShowController.is())
890 bool bPenEnabled = mxSlideShowController->getUsePen();
891 mxSlideShowController->setUsePen( !bPenEnabled );
893 break;
895 case awt::Key::E:
896 if (mxSlideShowController.is())
898 mxSlideShowController->setEraseAllInk( true );
900 break;
902 case awt::Key::HOME:
903 if (mxSlideShowController.is())
905 mxSlideShowController->gotoFirstSlide();
907 break;
909 case awt::Key::END:
910 if (mxSlideShowController.is())
912 mxSlideShowController->gotoLastSlide();
914 break;
916 case awt::Key::W:
917 case awt::Key::COMMA:
918 if (mxSlideShowController.is())
920 if (mxSlideShowController->isPaused())
921 mxSlideShowController->resume();
922 else
923 mxSlideShowController->blankScreen(0x00ffffff);
925 break;
927 case awt::Key::B:
928 case awt::Key::POINT:
929 if (mxSlideShowController.is())
931 if (mxSlideShowController->isPaused())
932 mxSlideShowController->resume();
933 else
934 mxSlideShowController->blankScreen(0x00000000);
936 break;
938 case awt::Key::NUM0:
939 case awt::Key::NUM1:
940 case awt::Key::NUM2:
941 case awt::Key::NUM3:
942 case awt::Key::NUM4:
943 case awt::Key::NUM5:
944 case awt::Key::NUM6:
945 case awt::Key::NUM7:
946 case awt::Key::NUM8:
947 case awt::Key::NUM9:
948 HandleNumericKeyPress(rEvent.KeyCode-awt::Key::NUM0, rEvent.Modifiers);
949 break;
951 case awt::Key::RETURN:
952 if (mnPendingSlideNumber > 0)
954 if (mxSlideShowController.is())
955 mxSlideShowController->gotoSlideIndex(mnPendingSlideNumber - 1);
956 mnPendingSlideNumber = -1;
958 else
960 if (mxSlideShowController.is())
961 mxSlideShowController->gotoNextEffect();
964 break;
966 case awt::Key::F1:
967 // Toggle the help view.
968 if (mpWindowManager)
970 if (mpWindowManager->GetViewMode() != PresenterWindowManager::VM_Help)
971 mpWindowManager->SetViewMode(PresenterWindowManager::VM_Help);
972 else
973 mpWindowManager->SetHelpViewState(false);
976 break;
978 default:
979 // Tell all views about the unhandled key event.
980 for (const auto& rxPane : mpPaneContainer->maPanes)
982 if ( ! rxPane->mbIsActive)
983 continue;
985 Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
986 if (xKeyListener.is())
987 xKeyListener->keyReleased(rEvent);
989 break;
993 void PresenterController::HandleNumericKeyPress (
994 const sal_Int32 nKey,
995 const sal_Int32 nModifiers)
997 switch (nModifiers)
999 case 0:
1000 if (mnPendingSlideNumber == -1)
1001 mnPendingSlideNumber = 0;
1002 UpdatePendingSlideNumber(mnPendingSlideNumber * 10 + nKey);
1003 break;
1005 case awt::KeyModifier::MOD1:
1006 // Ctrl-1, Ctrl-2, and Ctrl-3 are used to switch between views
1007 // (slide view, notes view, normal). Ctrl-4 switches monitors
1008 mnPendingSlideNumber = -1;
1009 if (!mpWindowManager)
1010 return;
1011 switch(nKey)
1013 case 1:
1014 mpWindowManager->SetViewMode(PresenterWindowManager::VM_Standard);
1015 break;
1016 case 2:
1017 mpWindowManager->SetViewMode(PresenterWindowManager::VM_Notes);
1018 break;
1019 case 3:
1020 mpWindowManager->SetViewMode(PresenterWindowManager::VM_SlideOverview);
1021 break;
1022 case 4:
1023 SwitchMonitors();
1024 break;
1025 default:
1026 // Ignore unsupported key.
1027 break;
1029 break;
1031 default:
1032 // Ignore unsupported modifiers.
1033 break;
1037 //----- XMouseListener --------------------------------------------------------
1039 void SAL_CALL PresenterController::mousePressed (const css::awt::MouseEvent&)
1041 if (mxMainWindow.is())
1042 mxMainWindow->setFocus();
1045 void SAL_CALL PresenterController::mouseReleased (const css::awt::MouseEvent&) {}
1047 void SAL_CALL PresenterController::mouseEntered (const css::awt::MouseEvent&) {}
1049 void SAL_CALL PresenterController::mouseExited (const css::awt::MouseEvent&) {}
1051 void PresenterController::InitializeMainPane (const Reference<XPane>& rxPane)
1053 if ( ! rxPane.is())
1054 return;
1056 mpAccessibleObject = new PresenterAccessible(
1057 mxComponentContext,
1058 this,
1059 rxPane);
1061 LoadTheme(rxPane);
1063 // Main pane has been created and is now observed by the window
1064 // manager.
1065 mpWindowManager->SetParentPane(rxPane);
1066 mpWindowManager->SetTheme(mpTheme);
1068 if (mpPaneBorderPainter)
1069 mpPaneBorderPainter->SetTheme(mpTheme);
1071 // Add key listener
1072 mxMainWindow = rxPane->getWindow();
1073 if (mxMainWindow.is())
1075 mxMainWindow->addKeyListener(this);
1076 mxMainWindow->addMouseListener(this);
1078 Reference<XPane2> xPane2 (rxPane, UNO_QUERY);
1079 if (xPane2.is())
1080 xPane2->setVisible(true);
1082 mpPaintManager = std::make_shared<PresenterPaintManager>(mxMainWindow, mxPresenterHelper, mpPaneContainer);
1084 mxCanvas.set(rxPane->getCanvas(), UNO_QUERY);
1086 if (mxSlideShowController.is())
1087 mxSlideShowController->activate();
1089 UpdateCurrentSlide(0);
1092 void PresenterController::LoadTheme (const Reference<XPane>& rxPane)
1094 // Create (load) the current theme.
1095 if (rxPane.is())
1096 mpTheme = std::make_shared<PresenterTheme>(mxComponentContext, rxPane->getCanvas());
1099 double PresenterController::GetSlideAspectRatio() const
1101 double nSlideAspectRatio (28.0/21.0);
1105 if (mxController.is())
1107 Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
1108 mxController->getModel(), UNO_QUERY_THROW);
1109 Reference<drawing::XDrawPages> xSlides (xSlideSupplier->getDrawPages());
1110 if (xSlides.is() && xSlides->getCount()>0)
1112 Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
1113 sal_Int32 nWidth (28000);
1114 sal_Int32 nHeight (21000);
1115 if ((xProperties->getPropertyValue("Width") >>= nWidth)
1116 && (xProperties->getPropertyValue("Height") >>= nHeight)
1117 && nHeight > 0)
1119 nSlideAspectRatio = double(nWidth) / double(nHeight);
1124 catch (RuntimeException&)
1126 OSL_ASSERT(false);
1129 return nSlideAspectRatio;
1132 void PresenterController::UpdatePendingSlideNumber (const sal_Int32 nPendingSlideNumber)
1134 mnPendingSlideNumber = nPendingSlideNumber;
1136 if (mpTheme == nullptr)
1137 return;
1139 if ( ! mxMainWindow.is())
1140 return;
1142 PresenterTheme::SharedFontDescriptor pFont (
1143 mpTheme->GetFont("PendingSlideNumberFont"));
1144 if (!pFont)
1145 return;
1147 pFont->PrepareFont(mxCanvas);
1148 if ( ! pFont->mxFont.is())
1149 return;
1151 const OUString sText (OUString::number(mnPendingSlideNumber));
1152 rendering::StringContext aContext (sText, 0, sText.getLength());
1153 pFont->mxFont->createTextLayout(
1154 aContext,
1155 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1159 void PresenterController::SwitchMonitors()
1161 Reference<lang::XEventListener> xScreen( mxScreen );
1162 if (!xScreen.is())
1163 return;
1165 PresenterScreen *pScreen = dynamic_cast<PresenterScreen *>(xScreen.get());
1166 if (!pScreen)
1167 return;
1169 pScreen->SwitchMonitors();
1172 void PresenterController::ExitPresenter()
1174 if( mxController.is() )
1176 Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
1177 if( xPS.is() )
1179 Reference< XPresentation > xP( xPS->getPresentation() );
1180 if( xP.is() )
1181 xP->end();
1186 } // end of namespace ::sdext::presenter
1188 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */