vcl: allow for overriding the default PDF rendering resolution
[LibreOffice.git] / sdext / source / presenter / PresenterController.cxx
blobb26dfc2fb3af98ddc6237959967e10e0c9ed9925
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 { namespace 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(new 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 Reference<XComponent> xWindowManagerComponent (
208 static_cast<XWeak*>(mpWindowManager.get()), UNO_QUERY);
209 mpWindowManager = nullptr;
210 if (xWindowManagerComponent.is())
211 xWindowManagerComponent->dispose();
213 if (mxController.is())
215 Reference<frame::XFrame> xFrame (mxController->getFrame());
216 if (xFrame.is())
217 xFrame->removeFrameActionListener(this);
218 mxController = nullptr;
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);
276 sal_Int32 nSlideIndex = -1;
279 nSlideIndex = mxSlideShowController->getCurrentSlideIndex() + nOffset;
280 if (mxSlideShowController->isPaused())
281 nSlideIndex = -1;
283 if (xIndexAccess.is() && nSlideIndex>=0)
285 if (nSlideIndex < xIndexAccess->getCount())
287 mnCurrentSlideIndex = nSlideIndex;
288 mxCurrentSlide.set( xIndexAccess->getByIndex(nSlideIndex), UNO_QUERY);
292 catch (RuntimeException&)
296 // Get the next slide.
297 mxNextSlide = nullptr;
300 const sal_Int32 nNextSlideIndex (mxSlideShowController->getNextSlideIndex()+nOffset);
301 if (nNextSlideIndex >= 0)
303 if (xIndexAccess.is())
305 if (nNextSlideIndex < xIndexAccess->getCount())
306 mxNextSlide.set( xIndexAccess->getByIndex(nNextSlideIndex), UNO_QUERY);
310 catch (RuntimeException&)
315 void PresenterController::UpdatePaneTitles()
317 if ( ! mxSlideShowController.is())
318 return;
320 // Get placeholders and their values.
321 const OUString sCurrentSlideNumberPlaceholder ("CURRENT_SLIDE_NUMBER");
322 const OUString sCurrentSlideNamePlaceholder ("CURRENT_SLIDE_NAME");
323 const OUString sSlideCountPlaceholder ("SLIDE_COUNT");
325 // Get string for slide count.
326 OUString sSlideCount ("---");
327 Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
328 if (xIndexAccess.is())
329 sSlideCount = OUString::number(xIndexAccess->getCount());
331 // Get string for current slide index.
332 OUString sCurrentSlideNumber (OUString::number(mnCurrentSlideIndex + 1));
334 // Get name of the current slide.
335 OUString sCurrentSlideName;
336 Reference<container::XNamed> xNamedSlide (mxCurrentSlide, UNO_QUERY);
337 if (xNamedSlide.is())
338 sCurrentSlideName = xNamedSlide->getName();
339 Reference<beans::XPropertySet> xSlideProperties (mxCurrentSlide, UNO_QUERY);
340 if (xSlideProperties.is())
344 OUString sName;
345 if (xSlideProperties->getPropertyValue("LinkDisplayName") >>= sName)
347 // Find out whether the name of the current slide has been
348 // automatically created or has been set by the user.
349 if (sName != sCurrentSlideName)
350 sCurrentSlideName = sName;
353 catch (const beans::UnknownPropertyException&)
358 // Replace the placeholders with their current values.
359 for (auto& rxPane : mpPaneContainer->maPanes)
361 OSL_ASSERT(rxPane != nullptr);
363 OUString sTemplate (IsAccessibilityActive()
364 ? rxPane->msAccessibleTitleTemplate
365 : rxPane->msTitleTemplate);
366 if (sTemplate.isEmpty())
367 continue;
369 OUStringBuffer sResult;
370 sResult.ensureCapacity(sTemplate.getLength());
372 sal_Int32 nIndex (0);
373 while (true)
375 sal_Int32 nStartIndex = sTemplate.indexOf('%', nIndex);
376 if (nStartIndex < 0)
378 // Add the remaining part of the string.
379 sResult.append(std::u16string_view(sTemplate).substr(nIndex));
380 break;
382 else
384 // Add the part preceding the next %.
385 sResult.append(std::u16string_view(sTemplate).substr(nIndex, nStartIndex-nIndex));
387 // Get the placeholder
388 ++nStartIndex;
389 const sal_Int32 nEndIndex (sTemplate.indexOf('%', nStartIndex+1));
390 const OUString sPlaceholder (sTemplate.copy(nStartIndex, nEndIndex-nStartIndex));
391 nIndex = nEndIndex+1;
393 // Replace the placeholder with its current value.
394 if (sPlaceholder == sCurrentSlideNumberPlaceholder)
395 sResult.append(sCurrentSlideNumber);
396 else if (sPlaceholder == sCurrentSlideNamePlaceholder)
397 sResult.append(sCurrentSlideName);
398 else if (sPlaceholder == sSlideCountPlaceholder)
399 sResult.append(sSlideCount);
403 rxPane->msTitle = sResult.makeStringAndClear();
404 if (rxPane->mxPane.is())
405 rxPane->mxPane->SetTitle(rxPane->msTitle);
409 void PresenterController::UpdateViews()
411 // Tell all views about the slides they should display.
412 for (const auto& rxPane : mpPaneContainer->maPanes)
414 Reference<drawing::XDrawView> xDrawView (rxPane->mxView, UNO_QUERY);
415 if (xDrawView.is())
416 xDrawView->setCurrentPage(mxCurrentSlide);
420 SharedBitmapDescriptor
421 PresenterController::GetViewBackground (const OUString& rsViewURL) const
423 if (mpTheme != nullptr)
425 const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
426 return mpTheme->GetBitmap(sStyleName, "Background");
428 return SharedBitmapDescriptor();
431 PresenterTheme::SharedFontDescriptor
432 PresenterController::GetViewFont (const OUString& rsViewURL) const
434 if (mpTheme != nullptr)
436 const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
437 return mpTheme->GetFont(sStyleName);
439 return PresenterTheme::SharedFontDescriptor();
442 const std::shared_ptr<PresenterTheme>& PresenterController::GetTheme() const
444 return mpTheme;
447 const ::rtl::Reference<PresenterWindowManager>& PresenterController::GetWindowManager() const
449 return mpWindowManager;
452 const Reference<presentation::XSlideShowController>&
453 PresenterController::GetSlideShowController() const
455 return mxSlideShowController;
458 const rtl::Reference<PresenterPaneContainer>& PresenterController::GetPaneContainer() const
460 return mpPaneContainer;
463 const ::rtl::Reference<PresenterPaneBorderPainter>& PresenterController::GetPaneBorderPainter() const
465 return mpPaneBorderPainter;
468 const std::shared_ptr<PresenterCanvasHelper>& PresenterController::GetCanvasHelper() const
470 return mpCanvasHelper;
473 const Reference<drawing::XPresenterHelper>& PresenterController::GetPresenterHelper() const
475 return mxPresenterHelper;
478 const std::shared_ptr<PresenterPaintManager>& PresenterController::GetPaintManager() const
480 return mpPaintManager;
483 void PresenterController::ShowView (const OUString& rsViewURL)
485 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
486 mpPaneContainer->FindViewURL(rsViewURL));
487 if (pDescriptor.get() == nullptr)
488 return;
490 pDescriptor->mbIsActive = true;
491 mxConfigurationController->requestResourceActivation(
492 pDescriptor->mxPaneId,
493 ResourceActivationMode_ADD);
494 mxConfigurationController->requestResourceActivation(
495 ResourceId::createWithAnchor(
496 mxComponentContext,
497 rsViewURL,
498 pDescriptor->mxPaneId),
499 ResourceActivationMode_REPLACE);
502 void PresenterController::HideView (const OUString& rsViewURL)
504 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
505 mpPaneContainer->FindViewURL(rsViewURL));
506 if (pDescriptor.get() != nullptr)
508 mxConfigurationController->requestResourceDeactivation(
509 ResourceId::createWithAnchor(
510 mxComponentContext,
511 rsViewURL,
512 pDescriptor->mxPaneId));
516 void PresenterController::DispatchUnoCommand (const OUString& rsCommand) const
518 if ( ! mxUrlTransformer.is())
519 return;
521 util::URL aURL;
522 aURL.Complete = rsCommand;
523 mxUrlTransformer->parseStrict(aURL);
525 Reference<frame::XDispatch> xDispatch (GetDispatch(aURL));
526 if ( ! xDispatch.is())
527 return;
529 xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>());
532 Reference<css::frame::XDispatch> PresenterController::GetDispatch (const util::URL& rURL) const
534 if ( ! mxController.is())
535 return nullptr;
537 Reference<frame::XDispatchProvider> xDispatchProvider (mxController->getFrame(), UNO_QUERY);
538 if ( ! xDispatchProvider.is())
539 return nullptr;
541 return xDispatchProvider->queryDispatch(
542 rURL,
543 OUString(),
544 frame::FrameSearchFlag::SELF);
547 util::URL PresenterController::CreateURLFromString (const OUString& rsURL) const
549 util::URL aURL;
551 if (mxUrlTransformer.is())
553 aURL.Complete = rsURL;
554 mxUrlTransformer->parseStrict(aURL);
557 return aURL;
560 const Reference<drawing::framework::XConfigurationController>&
561 PresenterController::GetConfigurationController() const
563 return mxConfigurationController;
566 const Reference<drawing::XDrawPage>& PresenterController::GetCurrentSlide() const
568 return mxCurrentSlide;
571 bool PresenterController::HasTransition (Reference<drawing::XDrawPage> const & rxPage)
573 bool bTransition = false;
574 sal_uInt16 aTransitionType = 0;
575 if( rxPage.is() )
577 Reference<beans::XPropertySet> xSlidePropertySet (rxPage, UNO_QUERY);
580 xSlidePropertySet->getPropertyValue("TransitionType") >>= aTransitionType;
581 if (aTransitionType > 0)
583 bTransition = true;
586 catch (const beans::UnknownPropertyException&)
590 return bTransition;
593 bool PresenterController::HasCustomAnimation (Reference<drawing::XDrawPage> const & rxPage)
595 bool bCustomAnimation = false;
596 if( rxPage.is() )
598 sal_uInt32 i, nCount = rxPage->getCount();
599 for ( i = 0; i < nCount; i++ )
601 Reference<drawing::XShape> xShape(rxPage->getByIndex(i), UNO_QUERY);
602 Reference<beans::XPropertySet> xShapePropertySet(xShape, UNO_QUERY);
603 presentation::AnimationEffect aEffect = presentation::AnimationEffect_NONE;
604 presentation::AnimationEffect aTextEffect = presentation::AnimationEffect_NONE;
607 xShapePropertySet->getPropertyValue("Effect") >>= aEffect;
608 xShapePropertySet->getPropertyValue("TextEffect") >>= aTextEffect;
610 catch (const beans::UnknownPropertyException&)
613 if( aEffect != presentation::AnimationEffect_NONE ||
614 aTextEffect != presentation::AnimationEffect_NONE )
616 bCustomAnimation = true;
617 break;
621 return bCustomAnimation;
624 void PresenterController::SetAccessibilityActiveState (const bool bIsActive)
626 if ( mbIsAccessibilityActive != bIsActive)
628 mbIsAccessibilityActive = bIsActive;
629 UpdatePaneTitles();
634 void PresenterController::HandleMouseClick (const awt::MouseEvent& rEvent)
636 if (!mxSlideShowController.is())
637 return;
639 switch (rEvent.Buttons)
641 case awt::MouseButton::LEFT:
642 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
643 mxSlideShowController->gotoNextSlide();
644 else
645 mxSlideShowController->gotoNextEffect();
646 break;
648 case awt::MouseButton::RIGHT:
649 mxSlideShowController->gotoPreviousSlide();
650 break;
652 default:
653 // Other or multiple buttons.
654 break;
658 void PresenterController::RequestViews (
659 const bool bIsSlideSorterActive,
660 const bool bIsNotesViewActive,
661 const bool bIsHelpViewActive)
663 for (const auto& rxPane : mpPaneContainer->maPanes)
665 bool bActivate (true);
666 const OUString sViewURL (rxPane->msViewURL);
667 if (sViewURL == PresenterViewFactory::msNotesViewURL)
669 bActivate = bIsNotesViewActive && !bIsSlideSorterActive && !bIsHelpViewActive;
671 else if (sViewURL == PresenterViewFactory::msSlideSorterURL)
673 bActivate = bIsSlideSorterActive;
675 else if (sViewURL == PresenterViewFactory::msCurrentSlidePreviewViewURL
676 || sViewURL == PresenterViewFactory::msNextSlidePreviewViewURL)
678 bActivate = !bIsSlideSorterActive && ! bIsHelpViewActive;
680 else if (sViewURL == PresenterViewFactory::msToolBarViewURL)
682 bActivate = true;
684 else if (sViewURL == PresenterViewFactory::msHelpViewURL)
686 bActivate = bIsHelpViewActive;
689 if (bActivate)
690 ShowView(sViewURL);
691 else
692 HideView(sViewURL);
696 void PresenterController::SetPresentationTime(IPresentationTime* pPresentationTime)
698 mpPresentationTime = pPresentationTime;
701 IPresentationTime* PresenterController::GetPresentationTime()
703 return mpPresentationTime;
706 //----- XConfigurationChangeListener ------------------------------------------
708 void SAL_CALL PresenterController::notifyConfigurationChange (
709 const ConfigurationChangeEvent& rEvent)
711 if (rBHelper.bDisposed || rBHelper.bInDispose)
713 throw lang::DisposedException (
714 "PresenterController object has already been disposed",
715 static_cast<uno::XWeak*>(this));
718 sal_Int32 nType (0);
719 if ( ! (rEvent.UserData >>= nType))
720 return;
722 switch (nType)
724 case ResourceActivationEventType:
725 if (rEvent.ResourceId->compareTo(mxMainPaneId) == 0)
727 InitializeMainPane(Reference<XPane>(rEvent.ResourceObject,UNO_QUERY));
729 else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_DIRECT))
731 // A pane bound to the main pane has been created and is
732 // stored in the pane container.
733 Reference<XPane> xPane (rEvent.ResourceObject,UNO_QUERY);
734 if (xPane.is())
736 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
737 mpPaneContainer->FindPaneId(xPane->getResourceId()));
740 else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
742 // A view bound to one of the panes has been created and is
743 // stored in the pane container along with its pane.
744 Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
745 if (xView.is())
747 mpPaneContainer->StoreView(xView);
748 UpdateViews();
749 mpWindowManager->NotifyViewCreation(xView);
752 break;
754 case ResourceDeactivationEventType:
755 if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
757 // If this is a view then remove it from the pane container.
758 Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
759 if (xView.is())
761 PresenterPaneContainer::SharedPaneDescriptor pDescriptor(
762 mpPaneContainer->RemoveView(xView));
764 // A possibly opaque view has been removed. Update()
765 // updates the clip polygon.
766 mpWindowManager->Update();
767 // Request the repainting of the area previously
768 // occupied by the view.
769 if (pDescriptor.get() != nullptr)
770 GetPaintManager()->Invalidate(pDescriptor->mxBorderWindow);
773 break;
775 case ConfigurationUpdateEndEventType:
776 if (IsAccessibilityActive())
778 mpAccessibleObject->UpdateAccessibilityHierarchy();
779 UpdateCurrentSlide(0);
781 break;
785 //----- XEventListener --------------------------------------------------------
787 void SAL_CALL PresenterController::disposing (
788 const lang::EventObject& rEvent)
790 if (rEvent.Source == mxController)
791 mxController = nullptr;
792 else if (rEvent.Source == mxConfigurationController)
793 mxConfigurationController = nullptr;
794 else if (rEvent.Source == mxSlideShowController)
795 mxSlideShowController = nullptr;
796 else if (rEvent.Source == mxMainWindow)
797 mxMainWindow = nullptr;
800 //----- XFrameActionListener --------------------------------------------------
802 void SAL_CALL PresenterController::frameAction (
803 const frame::FrameActionEvent& rEvent)
805 if (rEvent.Action == frame::FrameAction_FRAME_ACTIVATED)
807 if (mxSlideShowController.is())
808 mxSlideShowController->activate();
812 //----- XKeyListener ----------------------------------------------------------
814 void SAL_CALL PresenterController::keyPressed (const awt::KeyEvent& rEvent)
816 // Tell all views about the unhandled key event.
817 for (const auto& rxPane : mpPaneContainer->maPanes)
819 if ( ! rxPane->mbIsActive)
820 continue;
822 Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
823 if (xKeyListener.is())
824 xKeyListener->keyPressed(rEvent);
828 void SAL_CALL PresenterController::keyReleased (const awt::KeyEvent& rEvent)
830 if (rEvent.Source != mxMainWindow)
831 return;
833 switch (rEvent.KeyCode)
835 case awt::Key::ESCAPE:
836 case awt::Key::SUBTRACT:
838 if( mxController.is() )
840 Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
841 if( xPS.is() )
843 Reference< XPresentation > xP( xPS->getPresentation() );
844 if( xP.is() )
845 xP->end();
849 break;
851 case awt::Key::PAGEDOWN:
852 if (mxSlideShowController.is())
854 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
855 mxSlideShowController->gotoNextSlide();
856 else
857 mxSlideShowController->gotoNextEffect();
859 break;
861 case awt::Key::RIGHT:
862 case awt::Key::SPACE:
863 case awt::Key::DOWN:
864 case awt::Key::N:
865 if (mxSlideShowController.is())
867 mxSlideShowController->gotoNextEffect();
869 break;
871 case awt::Key::PAGEUP:
872 if (mxSlideShowController.is())
874 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
875 mxSlideShowController->gotoPreviousSlide();
876 else
877 mxSlideShowController->gotoPreviousEffect();
879 break;
881 case awt::Key::LEFT:
882 case awt::Key::UP:
883 case awt::Key::P:
884 case awt::Key::BACKSPACE:
885 if (mxSlideShowController.is())
887 mxSlideShowController->gotoPreviousEffect();
889 break;
891 case awt::Key::HOME:
892 if (mxSlideShowController.is())
894 mxSlideShowController->gotoFirstSlide();
896 break;
898 case awt::Key::END:
899 if (mxSlideShowController.is())
901 mxSlideShowController->gotoLastSlide();
903 break;
905 case awt::Key::W:
906 case awt::Key::COMMA:
907 if (mxSlideShowController.is())
909 if (mxSlideShowController->isPaused())
910 mxSlideShowController->resume();
911 else
912 mxSlideShowController->blankScreen(0x00ffffff);
914 break;
916 case awt::Key::B:
917 case awt::Key::POINT:
918 if (mxSlideShowController.is())
920 if (mxSlideShowController->isPaused())
921 mxSlideShowController->resume();
922 else
923 mxSlideShowController->blankScreen(0x00000000);
925 break;
927 case awt::Key::NUM0:
928 case awt::Key::NUM1:
929 case awt::Key::NUM2:
930 case awt::Key::NUM3:
931 case awt::Key::NUM4:
932 case awt::Key::NUM5:
933 case awt::Key::NUM6:
934 case awt::Key::NUM7:
935 case awt::Key::NUM8:
936 case awt::Key::NUM9:
937 HandleNumericKeyPress(rEvent.KeyCode-awt::Key::NUM0, rEvent.Modifiers);
938 break;
940 case awt::Key::RETURN:
941 if (mnPendingSlideNumber > 0)
943 if (mxSlideShowController.is())
944 mxSlideShowController->gotoSlideIndex(mnPendingSlideNumber - 1);
945 mnPendingSlideNumber = -1;
947 else
949 if (mxSlideShowController.is())
950 mxSlideShowController->gotoNextEffect();
953 break;
955 case awt::Key::F1:
956 // Toggle the help view.
957 if (mpWindowManager.get() != nullptr)
959 if (mpWindowManager->GetViewMode() != PresenterWindowManager::VM_Help)
960 mpWindowManager->SetViewMode(PresenterWindowManager::VM_Help);
961 else
962 mpWindowManager->SetHelpViewState(false);
965 break;
967 default:
968 // Tell all views about the unhandled key event.
969 for (const auto& rxPane : mpPaneContainer->maPanes)
971 if ( ! rxPane->mbIsActive)
972 continue;
974 Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
975 if (xKeyListener.is())
976 xKeyListener->keyReleased(rEvent);
978 break;
982 void PresenterController::HandleNumericKeyPress (
983 const sal_Int32 nKey,
984 const sal_Int32 nModifiers)
986 switch (nModifiers)
988 case 0:
989 if (mnPendingSlideNumber == -1)
990 mnPendingSlideNumber = 0;
991 UpdatePendingSlideNumber(mnPendingSlideNumber * 10 + nKey);
992 break;
994 case awt::KeyModifier::MOD1:
995 // Ctrl-1, Ctrl-2, and Ctrl-3 are used to switch between views
996 // (slide view, notes view, normal). Ctrl-4 switches monitors
997 mnPendingSlideNumber = -1;
998 if (mpWindowManager.get() == nullptr)
999 return;
1000 switch(nKey)
1002 case 1:
1003 mpWindowManager->SetViewMode(PresenterWindowManager::VM_Standard);
1004 break;
1005 case 2:
1006 mpWindowManager->SetViewMode(PresenterWindowManager::VM_Notes);
1007 break;
1008 case 3:
1009 mpWindowManager->SetViewMode(PresenterWindowManager::VM_SlideOverview);
1010 break;
1011 case 4:
1012 SwitchMonitors();
1013 break;
1014 default:
1015 // Ignore unsupported key.
1016 break;
1018 break;
1020 default:
1021 // Ignore unsupported modifiers.
1022 break;
1026 //----- XMouseListener --------------------------------------------------------
1028 void SAL_CALL PresenterController::mousePressed (const css::awt::MouseEvent&)
1030 if (mxMainWindow.is())
1031 mxMainWindow->setFocus();
1034 void SAL_CALL PresenterController::mouseReleased (const css::awt::MouseEvent&) {}
1036 void SAL_CALL PresenterController::mouseEntered (const css::awt::MouseEvent&) {}
1038 void SAL_CALL PresenterController::mouseExited (const css::awt::MouseEvent&) {}
1040 void PresenterController::InitializeMainPane (const Reference<XPane>& rxPane)
1042 if ( ! rxPane.is())
1043 return;
1045 mpAccessibleObject = new PresenterAccessible(
1046 mxComponentContext,
1047 this,
1048 rxPane);
1050 LoadTheme(rxPane);
1052 // Main pane has been created and is now observed by the window
1053 // manager.
1054 mpWindowManager->SetParentPane(rxPane);
1055 mpWindowManager->SetTheme(mpTheme);
1057 if (mpPaneBorderPainter.get() != nullptr)
1058 mpPaneBorderPainter->SetTheme(mpTheme);
1060 // Add key listener
1061 mxMainWindow = rxPane->getWindow();
1062 if (mxMainWindow.is())
1064 mxMainWindow->addKeyListener(this);
1065 mxMainWindow->addMouseListener(this);
1067 Reference<XPane2> xPane2 (rxPane, UNO_QUERY);
1068 if (xPane2.is())
1069 xPane2->setVisible(true);
1071 mpPaintManager.reset(new PresenterPaintManager(mxMainWindow, mxPresenterHelper, mpPaneContainer));
1073 mxCanvas.set(rxPane->getCanvas(), UNO_QUERY);
1075 if (mxSlideShowController.is())
1076 mxSlideShowController->activate();
1078 UpdateCurrentSlide(0);
1081 void PresenterController::LoadTheme (const Reference<XPane>& rxPane)
1083 // Create (load) the current theme.
1084 if (rxPane.is())
1085 mpTheme.reset(new PresenterTheme(mxComponentContext, rxPane->getCanvas()));
1088 double PresenterController::GetSlideAspectRatio() const
1090 double nSlideAspectRatio (28.0/21.0);
1094 if (mxController.is())
1096 Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
1097 mxController->getModel(), UNO_QUERY_THROW);
1098 Reference<drawing::XDrawPages> xSlides (xSlideSupplier->getDrawPages());
1099 if (xSlides.is() && xSlides->getCount()>0)
1101 Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
1102 sal_Int32 nWidth (28000);
1103 sal_Int32 nHeight (21000);
1104 if ((xProperties->getPropertyValue("Width") >>= nWidth)
1105 && (xProperties->getPropertyValue("Height") >>= nHeight)
1106 && nHeight > 0)
1108 nSlideAspectRatio = double(nWidth) / double(nHeight);
1113 catch (RuntimeException&)
1115 OSL_ASSERT(false);
1118 return nSlideAspectRatio;
1121 void PresenterController::UpdatePendingSlideNumber (const sal_Int32 nPendingSlideNumber)
1123 mnPendingSlideNumber = nPendingSlideNumber;
1125 if (mpTheme == nullptr)
1126 return;
1128 if ( ! mxMainWindow.is())
1129 return;
1131 PresenterTheme::SharedFontDescriptor pFont (
1132 mpTheme->GetFont("PendingSlideNumberFont"));
1133 if (pFont.get() == nullptr)
1134 return;
1136 pFont->PrepareFont(mxCanvas);
1137 if ( ! pFont->mxFont.is())
1138 return;
1140 const OUString sText (OUString::number(mnPendingSlideNumber));
1141 rendering::StringContext aContext (sText, 0, sText.getLength());
1142 pFont->mxFont->createTextLayout(
1143 aContext,
1144 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1148 void PresenterController::SwitchMonitors()
1150 Reference<lang::XEventListener> xScreen( mxScreen );
1151 if (!xScreen.is())
1152 return;
1154 PresenterScreen *pScreen = dynamic_cast<PresenterScreen *>(xScreen.get());
1155 if (!pScreen)
1156 return;
1158 pScreen->SwitchMonitors();
1161 } } // end of namespace ::sdext::presenter
1163 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */