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
22 #include <string_view>
23
24 #include "PresenterController.hxx"
25
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"
37
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>
54
55 #include <rtl/ustrbuf.hxx>
56
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;
61
62 namespace {
63 const sal_Int32 ResourceActivationEventType = 0;
64 const sal_Int32 ResourceDeactivationEventType = 1;
65 const sal_Int32 ConfigurationUpdateEndEventType = 2;
66 }
67
68 namespace sdext::presenter {
69
~IPresentationTime()70 IPresentationTime::~IPresentationTime()
71 {
72 }
73
74 PresenterController::InstanceContainer PresenterController::maInstances;
75
Instance(const css::uno::Reference<css::frame::XFrame> & rxFrame)76 ::rtl::Reference<PresenterController> PresenterController::Instance (
77 const css::uno::Reference<css::frame::XFrame>& rxFrame)
78 {
79 InstanceContainer::const_iterator iInstance (maInstances.find(rxFrame));
80 if (iInstance != maInstances.end())
81 return iInstance->second;
82 else
83 return ::rtl::Reference<PresenterController>();
84 }
85
PresenterController(const css::uno::WeakReference<css::lang::XEventListener> & rxScreen,const Reference<XComponentContext> & rxContext,const Reference<frame::XController> & rxController,const Reference<presentation::XSlideShowController> & rxSlideShowController,const rtl::Reference<PresenterPaneContainer> & rpPaneContainer,const Reference<XResourceId> & rxMainPaneId)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)
115 {
116 OSL_ASSERT(mxController.is());
117
118 if ( ! mxSlideShowController.is())
119 throw lang::IllegalArgumentException(
120 "missing slide show controller",
121 static_cast<XWeak*>(this),
122 2);
123
124 new PresenterCurrentSlideObserver(this,rxSlideShowController);
125
126 // Listen for configuration changes.
127 Reference<XControllerManager> xCM (mxController, UNO_QUERY_THROW);
128 mxConfigurationController = xCM->getConfigurationController();
129 if (mxConfigurationController.is())
130 {
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));
143 }
144
145 // Listen for the frame being activated.
146 Reference<frame::XFrame> xFrame (mxController->getFrame());
147 if (xFrame.is())
148 xFrame->addFrameActionListener(this);
149
150 // Create the border painter.
151 mpPaneBorderPainter = new PresenterPaneBorderPainter(rxContext);
152 mpWindowManager->SetPaneBorderPainter(mpPaneBorderPainter);
153
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);
165
166 if (mxSlideShowController.is())
167 {
168 mxSlideShowController->activate();
169 Reference<beans::XPropertySet> xProperties (mxSlideShowController, UNO_QUERY);
170 if (xProperties.is())
171 {
172 Reference<awt::XWindow> xWindow (
173 xProperties->getPropertyValue("ParentWindow"), UNO_QUERY);
174 if (xWindow.is())
175 xWindow->addKeyListener(this);
176 }
177 }
178
179 UpdateCurrentSlide(0);
180
181 maInstances[mxController->getFrame()] = this;
182
183 // Create a URLTransformer.
184 if (xFactory.is())
185 {
186 mxUrlTransformer.set(util::URLTransformer::create(mxComponentContext));
187 }
188 }
189
~PresenterController()190 PresenterController::~PresenterController()
191 {
192 }
193
disposing()194 void PresenterController::disposing()
195 {
196 maInstances.erase(mxController->getFrame());
197
198 if (mxMainWindow.is())
199 {
200 mxMainWindow->removeKeyListener(this);
201 mxMainWindow->removeMouseListener(this);
202 mxMainWindow = nullptr;
203 }
204 if (mxConfigurationController.is())
205 mxConfigurationController->removeConfigurationChangeListener(this);
206
207 if (mxController.is())
208 {
209 Reference<frame::XFrame> xFrame (mxController->getFrame());
210 if (xFrame.is())
211 xFrame->removeFrameActionListener(this);
212 mxController = nullptr;
213 }
214
215 Reference<XComponent> xWindowManagerComponent (
216 static_cast<XWeak*>(mpWindowManager.get()), UNO_QUERY);
217 mpWindowManager = nullptr;
218 if (xWindowManagerComponent.is())
219 xWindowManagerComponent->dispose();
220
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();
230 {
231 Reference<lang::XComponent> xComponent (
232 static_cast<XWeak*>(mpPaneBorderPainter.get()), UNO_QUERY);
233 mpPaneBorderPainter = nullptr;
234 if (xComponent.is())
235 xComponent->dispose();
236 }
237 mpCanvasHelper.reset();
238 {
239 Reference<lang::XComponent> xComponent (mxPresenterHelper, UNO_QUERY);
240 mxPresenterHelper = nullptr;
241 if (xComponent.is())
242 xComponent->dispose();
243 }
244 mpPaintManager.reset();
245 mnPendingSlideNumber = -1;
246 {
247 Reference<lang::XComponent> xComponent (mxUrlTransformer, UNO_QUERY);
248 mxUrlTransformer = nullptr;
249 if (xComponent.is())
250 xComponent->dispose();
251 }
252 }
253
UpdateCurrentSlide(const sal_Int32 nOffset)254 void PresenterController::UpdateCurrentSlide (const sal_Int32 nOffset)
255 {
256 // std::cerr << "Updating current Slide to " << nOffset << std::endl;
257 GetSlides(nOffset);
258 UpdatePaneTitles();
259 UpdateViews();
260
261 // Update the accessibility object.
262 if (IsAccessibilityActive())
263 {
264 mpAccessibleObject->NotifyCurrentSlideChange();
265 }
266 }
267
GetSlides(const sal_Int32 nOffset)268 void PresenterController::GetSlides (const sal_Int32 nOffset)
269 {
270 if ( ! mxSlideShowController.is())
271 return;
272
273 // Get the current slide from the slide show controller.
274 mxCurrentSlide = nullptr;
275 Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
276 try
277 {
278 sal_Int32 nSlideIndex = mxSlideShowController->getCurrentSlideIndex() + nOffset;
279 if (mxSlideShowController->isPaused())
280 nSlideIndex = -1;
281
282 if (xIndexAccess.is() && nSlideIndex>=0)
283 {
284 if (nSlideIndex < xIndexAccess->getCount())
285 {
286 mnCurrentSlideIndex = nSlideIndex;
287 mxCurrentSlide.set( xIndexAccess->getByIndex(nSlideIndex), UNO_QUERY);
288 }
289 }
290 }
291 catch (RuntimeException&)
292 {
293 }
294
295 // Get the next slide.
296 mxNextSlide = nullptr;
297 try
298 {
299 const sal_Int32 nNextSlideIndex (mxSlideShowController->getNextSlideIndex()+nOffset);
300 if (nNextSlideIndex >= 0)
301 {
302 if (xIndexAccess.is())
303 {
304 if (nNextSlideIndex < xIndexAccess->getCount())
305 mxNextSlide.set( xIndexAccess->getByIndex(nNextSlideIndex), UNO_QUERY);
306 }
307 }
308 }
309 catch (RuntimeException&)
310 {
311 }
312 }
313
UpdatePaneTitles()314 void PresenterController::UpdatePaneTitles()
315 {
316 if ( ! mxSlideShowController.is())
317 return;
318
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");
323
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());
329
330 // Get string for current slide index.
331 OUString sCurrentSlideNumber (OUString::number(mnCurrentSlideIndex + 1));
332
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())
340 {
341 try
342 {
343 OUString sName;
344 if (xSlideProperties->getPropertyValue("LinkDisplayName") >>= sName)
345 {
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;
350 }
351 }
352 catch (const beans::UnknownPropertyException&)
353 {
354 }
355 }
356
357 // Replace the placeholders with their current values.
358 for (auto& rxPane : mpPaneContainer->maPanes)
359 {
360 OSL_ASSERT(rxPane != nullptr);
361
362 OUString sTemplate (IsAccessibilityActive()
363 ? rxPane->msAccessibleTitleTemplate
364 : rxPane->msTitleTemplate);
365 if (sTemplate.isEmpty())
366 continue;
367
368 OUStringBuffer sResult;
369 sResult.ensureCapacity(sTemplate.getLength());
370
371 sal_Int32 nIndex (0);
372 while (true)
373 {
374 sal_Int32 nStartIndex = sTemplate.indexOf('%', nIndex);
375 if (nStartIndex < 0)
376 {
377 // Add the remaining part of the string.
378 sResult.append(sTemplate.subView(nIndex));
379 break;
380 }
381 else
382 {
383 // Add the part preceding the next %.
384 sResult.append(sTemplate.subView(nIndex, nStartIndex-nIndex));
385
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;
391
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);
399 }
400 }
401
402 rxPane->msTitle = sResult.makeStringAndClear();
403 if (rxPane->mxPane.is())
404 rxPane->mxPane->SetTitle(rxPane->msTitle);
405 }
406 }
407
UpdateViews()408 void PresenterController::UpdateViews()
409 {
410 // Tell all views about the slides they should display.
411 for (const auto& rxPane : mpPaneContainer->maPanes)
412 {
413 Reference<drawing::XDrawView> xDrawView (rxPane->mxView, UNO_QUERY);
414 if (xDrawView.is())
415 xDrawView->setCurrentPage(mxCurrentSlide);
416 }
417 }
418
419 SharedBitmapDescriptor
GetViewBackground(const OUString & rsViewURL) const420 PresenterController::GetViewBackground (const OUString& rsViewURL) const
421 {
422 if (mpTheme != nullptr)
423 {
424 const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
425 return mpTheme->GetBitmap(sStyleName, "Background");
426 }
427 return SharedBitmapDescriptor();
428 }
429
430 PresenterTheme::SharedFontDescriptor
GetViewFont(const OUString & rsViewURL) const431 PresenterController::GetViewFont (const OUString& rsViewURL) const
432 {
433 if (mpTheme != nullptr)
434 {
435 const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
436 return mpTheme->GetFont(sStyleName);
437 }
438 return PresenterTheme::SharedFontDescriptor();
439 }
440
GetTheme() const441 const std::shared_ptr<PresenterTheme>& PresenterController::GetTheme() const
442 {
443 return mpTheme;
444 }
445
GetWindowManager() const446 const ::rtl::Reference<PresenterWindowManager>& PresenterController::GetWindowManager() const
447 {
448 return mpWindowManager;
449 }
450
451 const Reference<presentation::XSlideShowController>&
GetSlideShowController() const452 PresenterController::GetSlideShowController() const
453 {
454 return mxSlideShowController;
455 }
456
GetPaneContainer() const457 const rtl::Reference<PresenterPaneContainer>& PresenterController::GetPaneContainer() const
458 {
459 return mpPaneContainer;
460 }
461
GetPaneBorderPainter() const462 const ::rtl::Reference<PresenterPaneBorderPainter>& PresenterController::GetPaneBorderPainter() const
463 {
464 return mpPaneBorderPainter;
465 }
466
GetCanvasHelper() const467 const std::shared_ptr<PresenterCanvasHelper>& PresenterController::GetCanvasHelper() const
468 {
469 return mpCanvasHelper;
470 }
471
GetPresenterHelper() const472 const Reference<drawing::XPresenterHelper>& PresenterController::GetPresenterHelper() const
473 {
474 return mxPresenterHelper;
475 }
476
GetPaintManager() const477 const std::shared_ptr<PresenterPaintManager>& PresenterController::GetPaintManager() const
478 {
479 return mpPaintManager;
480 }
481
ShowView(const OUString & rsViewURL)482 void PresenterController::ShowView (const OUString& rsViewURL)
483 {
484 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
485 mpPaneContainer->FindViewURL(rsViewURL));
486 if (!pDescriptor)
487 return;
488
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);
499 }
500
HideView(const OUString & rsViewURL)501 void PresenterController::HideView (const OUString& rsViewURL)
502 {
503 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
504 mpPaneContainer->FindViewURL(rsViewURL));
505 if (pDescriptor)
506 {
507 mxConfigurationController->requestResourceDeactivation(
508 ResourceId::createWithAnchor(
509 mxComponentContext,
510 rsViewURL,
511 pDescriptor->mxPaneId));
512 }
513 }
514
DispatchUnoCommand(const OUString & rsCommand) const515 void PresenterController::DispatchUnoCommand (const OUString& rsCommand) const
516 {
517 if ( ! mxUrlTransformer.is())
518 return;
519
520 util::URL aURL;
521 aURL.Complete = rsCommand;
522 mxUrlTransformer->parseStrict(aURL);
523
524 Reference<frame::XDispatch> xDispatch (GetDispatch(aURL));
525 if ( ! xDispatch.is())
526 return;
527
528 xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>());
529 }
530
GetDispatch(const util::URL & rURL) const531 Reference<css::frame::XDispatch> PresenterController::GetDispatch (const util::URL& rURL) const
532 {
533 if ( ! mxController.is())
534 return nullptr;
535
536 Reference<frame::XDispatchProvider> xDispatchProvider (mxController->getFrame(), UNO_QUERY);
537 if ( ! xDispatchProvider.is())
538 return nullptr;
539
540 return xDispatchProvider->queryDispatch(
541 rURL,
542 OUString(),
543 frame::FrameSearchFlag::SELF);
544 }
545
CreateURLFromString(const OUString & rsURL) const546 util::URL PresenterController::CreateURLFromString (const OUString& rsURL) const
547 {
548 util::URL aURL;
549
550 if (mxUrlTransformer.is())
551 {
552 aURL.Complete = rsURL;
553 mxUrlTransformer->parseStrict(aURL);
554 }
555
556 return aURL;
557 }
558
559 const Reference<drawing::framework::XConfigurationController>&
GetConfigurationController() const560 PresenterController::GetConfigurationController() const
561 {
562 return mxConfigurationController;
563 }
564
GetCurrentSlide() const565 const Reference<drawing::XDrawPage>& PresenterController::GetCurrentSlide() const
566 {
567 return mxCurrentSlide;
568 }
569
HasTransition(Reference<drawing::XDrawPage> const & rxPage)570 bool PresenterController::HasTransition (Reference<drawing::XDrawPage> const & rxPage)
571 {
572 bool bTransition = false;
573 if( rxPage.is() )
574 {
575 Reference<beans::XPropertySet> xSlidePropertySet (rxPage, UNO_QUERY);
576 try
577 {
578 sal_uInt16 aTransitionType = 0;
579 xSlidePropertySet->getPropertyValue("TransitionType") >>= aTransitionType;
580 if (aTransitionType > 0)
581 {
582 bTransition = true;
583 }
584 }
585 catch (const beans::UnknownPropertyException&)
586 {
587 }
588 }
589 return bTransition;
590 }
591
HasCustomAnimation(Reference<drawing::XDrawPage> const & rxPage)592 bool PresenterController::HasCustomAnimation (Reference<drawing::XDrawPage> const & rxPage)
593 {
594 bool bCustomAnimation = false;
595 if( rxPage.is() )
596 {
597 sal_uInt32 i, nCount = rxPage->getCount();
598 for ( i = 0; i < nCount; i++ )
599 {
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;
604 try
605 {
606 xShapePropertySet->getPropertyValue("Effect") >>= aEffect;
607 xShapePropertySet->getPropertyValue("TextEffect") >>= aTextEffect;
608 }
609 catch (const beans::UnknownPropertyException&)
610 {
611 }
612 if( aEffect != presentation::AnimationEffect_NONE ||
613 aTextEffect != presentation::AnimationEffect_NONE )
614 {
615 bCustomAnimation = true;
616 break;
617 }
618 }
619 }
620 return bCustomAnimation;
621 }
622
SetAccessibilityActiveState(const bool bIsActive)623 void PresenterController::SetAccessibilityActiveState (const bool bIsActive)
624 {
625 if ( mbIsAccessibilityActive != bIsActive)
626 {
627 mbIsAccessibilityActive = bIsActive;
628 UpdatePaneTitles();
629 }
630 }
631
632
HandleMouseClick(const awt::MouseEvent & rEvent)633 void PresenterController::HandleMouseClick (const awt::MouseEvent& rEvent)
634 {
635 if (!mxSlideShowController.is())
636 return;
637
638 switch (rEvent.Buttons)
639 {
640 case awt::MouseButton::LEFT:
641 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
642 mxSlideShowController->gotoNextSlide();
643 else
644 mxSlideShowController->gotoNextEffect();
645 break;
646
647 case awt::MouseButton::RIGHT:
648 mxSlideShowController->gotoPreviousSlide();
649 break;
650
651 default:
652 // Other or multiple buttons.
653 break;
654 }
655 }
656
RequestViews(const bool bIsSlideSorterActive,const bool bIsNotesViewActive,const bool bIsHelpViewActive)657 void PresenterController::RequestViews (
658 const bool bIsSlideSorterActive,
659 const bool bIsNotesViewActive,
660 const bool bIsHelpViewActive)
661 {
662 for (const auto& rxPane : mpPaneContainer->maPanes)
663 {
664 bool bActivate (true);
665 const OUString sViewURL (rxPane->msViewURL);
666 if (sViewURL == PresenterViewFactory::msNotesViewURL)
667 {
668 bActivate = bIsNotesViewActive && !bIsSlideSorterActive && !bIsHelpViewActive;
669 }
670 else if (sViewURL == PresenterViewFactory::msSlideSorterURL)
671 {
672 bActivate = bIsSlideSorterActive;
673 }
674 else if (sViewURL == PresenterViewFactory::msCurrentSlidePreviewViewURL
675 || sViewURL == PresenterViewFactory::msNextSlidePreviewViewURL)
676 {
677 bActivate = !bIsSlideSorterActive && ! bIsHelpViewActive;
678 }
679 else if (sViewURL == PresenterViewFactory::msToolBarViewURL)
680 {
681 bActivate = true;
682 }
683 else if (sViewURL == PresenterViewFactory::msHelpViewURL)
684 {
685 bActivate = bIsHelpViewActive;
686 }
687
688 if (bActivate)
689 ShowView(sViewURL);
690 else
691 HideView(sViewURL);
692 }
693 }
694
SetPresentationTime(IPresentationTime * pPresentationTime)695 void PresenterController::SetPresentationTime(IPresentationTime* pPresentationTime)
696 {
697 mpPresentationTime = pPresentationTime;
698 }
699
GetPresentationTime()700 IPresentationTime* PresenterController::GetPresentationTime()
701 {
702 return mpPresentationTime;
703 }
704
705 //----- XConfigurationChangeListener ------------------------------------------
706
notifyConfigurationChange(const ConfigurationChangeEvent & rEvent)707 void SAL_CALL PresenterController::notifyConfigurationChange (
708 const ConfigurationChangeEvent& rEvent)
709 {
710 if (rBHelper.bDisposed || rBHelper.bInDispose)
711 {
712 throw lang::DisposedException (
713 "PresenterController object has already been disposed",
714 static_cast<uno::XWeak*>(this));
715 }
716
717 sal_Int32 nType (0);
718 if ( ! (rEvent.UserData >>= nType))
719 return;
720
721 switch (nType)
722 {
723 case ResourceActivationEventType:
724 if (rEvent.ResourceId->compareTo(mxMainPaneId) == 0)
725 {
726 InitializeMainPane(Reference<XPane>(rEvent.ResourceObject,UNO_QUERY));
727 }
728 else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_DIRECT))
729 {
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())
734 {
735 mpPaneContainer->FindPaneId(xPane->getResourceId());
736 }
737 }
738 else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
739 {
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())
744 {
745 mpPaneContainer->StoreView(xView);
746 UpdateViews();
747 mpWindowManager->NotifyViewCreation(xView);
748 }
749 }
750 break;
751
752 case ResourceDeactivationEventType:
753 if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
754 {
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())
758 {
759 PresenterPaneContainer::SharedPaneDescriptor pDescriptor(
760 mpPaneContainer->RemoveView(xView));
761
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);
769 }
770 }
771 break;
772
773 case ConfigurationUpdateEndEventType:
774 if (IsAccessibilityActive())
775 {
776 mpAccessibleObject->UpdateAccessibilityHierarchy();
777 UpdateCurrentSlide(0);
778 }
779 break;
780 }
781 }
782
783 //----- XEventListener --------------------------------------------------------
784
disposing(const lang::EventObject & rEvent)785 void SAL_CALL PresenterController::disposing (
786 const lang::EventObject& rEvent)
787 {
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;
796 }
797
798 //----- XFrameActionListener --------------------------------------------------
799
frameAction(const frame::FrameActionEvent & rEvent)800 void SAL_CALL PresenterController::frameAction (
801 const frame::FrameActionEvent& rEvent)
802 {
803 if (rEvent.Action == frame::FrameAction_FRAME_ACTIVATED)
804 {
805 if (mxSlideShowController.is())
806 mxSlideShowController->activate();
807 }
808 }
809
810 //----- XKeyListener ----------------------------------------------------------
811
keyPressed(const awt::KeyEvent & rEvent)812 void SAL_CALL PresenterController::keyPressed (const awt::KeyEvent& rEvent)
813 {
814 // Tell all views about the unhandled key event.
815 for (const auto& rxPane : mpPaneContainer->maPanes)
816 {
817 if ( ! rxPane->mbIsActive)
818 continue;
819
820 Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
821 if (xKeyListener.is())
822 xKeyListener->keyPressed(rEvent);
823 }
824 }
825
keyReleased(const awt::KeyEvent & rEvent)826 void SAL_CALL PresenterController::keyReleased (const awt::KeyEvent& rEvent)
827 {
828 if (rEvent.Source != mxMainWindow)
829 return;
830
831 switch (rEvent.KeyCode)
832 {
833 case awt::Key::ESCAPE:
834 case awt::Key::SUBTRACT:
835 {
836 if( mxController.is() )
837 {
838 Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
839 if( xPS.is() )
840 {
841 Reference< XPresentation > xP( xPS->getPresentation() );
842 if( xP.is() )
843 xP->end();
844 }
845 }
846 }
847 break;
848
849 case awt::Key::PAGEDOWN:
850 if (mxSlideShowController.is())
851 {
852 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
853 mxSlideShowController->gotoNextSlide();
854 else
855 mxSlideShowController->gotoNextEffect();
856 }
857 break;
858
859 case awt::Key::RIGHT:
860 case awt::Key::SPACE:
861 case awt::Key::DOWN:
862 if (mxSlideShowController.is())
863 {
864 mxSlideShowController->gotoNextEffect();
865 }
866 break;
867
868 case awt::Key::PAGEUP:
869 if (mxSlideShowController.is())
870 {
871 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
872 mxSlideShowController->gotoPreviousSlide();
873 else
874 mxSlideShowController->gotoPreviousEffect();
875 }
876 break;
877
878 case awt::Key::LEFT:
879 case awt::Key::UP:
880 case awt::Key::BACKSPACE:
881 if (mxSlideShowController.is())
882 {
883 mxSlideShowController->gotoPreviousEffect();
884 }
885 break;
886
887 case awt::Key::P:
888 if (mxSlideShowController.is())
889 {
890 bool bPenEnabled = mxSlideShowController->getUsePen();
891 mxSlideShowController->setUsePen( !bPenEnabled );
892 }
893 break;
894
895 case awt::Key::E:
896 if (mxSlideShowController.is())
897 {
898 mxSlideShowController->setEraseAllInk( true );
899 }
900 break;
901
902 case awt::Key::HOME:
903 if (mxSlideShowController.is())
904 {
905 mxSlideShowController->gotoFirstSlide();
906 }
907 break;
908
909 case awt::Key::END:
910 if (mxSlideShowController.is())
911 {
912 mxSlideShowController->gotoLastSlide();
913 }
914 break;
915
916 case awt::Key::W:
917 case awt::Key::COMMA:
918 if (mxSlideShowController.is())
919 {
920 if (mxSlideShowController->isPaused())
921 mxSlideShowController->resume();
922 else
923 mxSlideShowController->blankScreen(0x00ffffff);
924 }
925 break;
926
927 case awt::Key::B:
928 case awt::Key::POINT:
929 if (mxSlideShowController.is())
930 {
931 if (mxSlideShowController->isPaused())
932 mxSlideShowController->resume();
933 else
934 mxSlideShowController->blankScreen(0x00000000);
935 }
936 break;
937
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;
950
951 case awt::Key::RETURN:
952 if (mnPendingSlideNumber > 0)
953 {
954 if (mxSlideShowController.is())
955 mxSlideShowController->gotoSlideIndex(mnPendingSlideNumber - 1);
956 mnPendingSlideNumber = -1;
957 }
958 else
959 {
960 if (mxSlideShowController.is())
961 mxSlideShowController->gotoNextEffect();
962 }
963
964 break;
965
966 case awt::Key::F1:
967 // Toggle the help view.
968 if (mpWindowManager)
969 {
970 if (mpWindowManager->GetViewMode() != PresenterWindowManager::VM_Help)
971 mpWindowManager->SetViewMode(PresenterWindowManager::VM_Help);
972 else
973 mpWindowManager->SetHelpViewState(false);
974 }
975
976 break;
977
978 default:
979 // Tell all views about the unhandled key event.
980 for (const auto& rxPane : mpPaneContainer->maPanes)
981 {
982 if ( ! rxPane->mbIsActive)
983 continue;
984
985 Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
986 if (xKeyListener.is())
987 xKeyListener->keyReleased(rEvent);
988 }
989 break;
990 }
991 }
992
HandleNumericKeyPress(const sal_Int32 nKey,const sal_Int32 nModifiers)993 void PresenterController::HandleNumericKeyPress (
994 const sal_Int32 nKey,
995 const sal_Int32 nModifiers)
996 {
997 switch (nModifiers)
998 {
999 case 0:
1000 if (mnPendingSlideNumber == -1)
1001 mnPendingSlideNumber = 0;
1002 UpdatePendingSlideNumber(mnPendingSlideNumber * 10 + nKey);
1003 break;
1004
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)
1012 {
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;
1028 }
1029 break;
1030
1031 default:
1032 // Ignore unsupported modifiers.
1033 break;
1034 }
1035 }
1036
1037 //----- XMouseListener --------------------------------------------------------
1038
mousePressed(const css::awt::MouseEvent &)1039 void SAL_CALL PresenterController::mousePressed (const css::awt::MouseEvent&)
1040 {
1041 if (mxMainWindow.is())
1042 mxMainWindow->setFocus();
1043 }
1044
mouseReleased(const css::awt::MouseEvent &)1045 void SAL_CALL PresenterController::mouseReleased (const css::awt::MouseEvent&) {}
1046
mouseEntered(const css::awt::MouseEvent &)1047 void SAL_CALL PresenterController::mouseEntered (const css::awt::MouseEvent&) {}
1048
mouseExited(const css::awt::MouseEvent &)1049 void SAL_CALL PresenterController::mouseExited (const css::awt::MouseEvent&) {}
1050
InitializeMainPane(const Reference<XPane> & rxPane)1051 void PresenterController::InitializeMainPane (const Reference<XPane>& rxPane)
1052 {
1053 if ( ! rxPane.is())
1054 return;
1055
1056 mpAccessibleObject = new PresenterAccessible(
1057 mxComponentContext,
1058 this,
1059 rxPane);
1060
1061 LoadTheme(rxPane);
1062
1063 // Main pane has been created and is now observed by the window
1064 // manager.
1065 mpWindowManager->SetParentPane(rxPane);
1066 mpWindowManager->SetTheme(mpTheme);
1067
1068 if (mpPaneBorderPainter)
1069 mpPaneBorderPainter->SetTheme(mpTheme);
1070
1071 // Add key listener
1072 mxMainWindow = rxPane->getWindow();
1073 if (mxMainWindow.is())
1074 {
1075 mxMainWindow->addKeyListener(this);
1076 mxMainWindow->addMouseListener(this);
1077 }
1078 Reference<XPane2> xPane2 (rxPane, UNO_QUERY);
1079 if (xPane2.is())
1080 xPane2->setVisible(true);
1081
1082 mpPaintManager = std::make_shared<PresenterPaintManager>(mxMainWindow, mxPresenterHelper, mpPaneContainer);
1083
1084 mxCanvas.set(rxPane->getCanvas(), UNO_QUERY);
1085
1086 if (mxSlideShowController.is())
1087 mxSlideShowController->activate();
1088
1089 UpdateCurrentSlide(0);
1090 }
1091
LoadTheme(const Reference<XPane> & rxPane)1092 void PresenterController::LoadTheme (const Reference<XPane>& rxPane)
1093 {
1094 // Create (load) the current theme.
1095 if (rxPane.is())
1096 mpTheme = std::make_shared<PresenterTheme>(mxComponentContext, rxPane->getCanvas());
1097 }
1098
GetSlideAspectRatio() const1099 double PresenterController::GetSlideAspectRatio() const
1100 {
1101 double nSlideAspectRatio (28.0/21.0);
1102
1103 try
1104 {
1105 if (mxController.is())
1106 {
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)
1111 {
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)
1118 {
1119 nSlideAspectRatio = double(nWidth) / double(nHeight);
1120 }
1121 }
1122 }
1123 }
1124 catch (RuntimeException&)
1125 {
1126 OSL_ASSERT(false);
1127 }
1128
1129 return nSlideAspectRatio;
1130 }
1131
UpdatePendingSlideNumber(const sal_Int32 nPendingSlideNumber)1132 void PresenterController::UpdatePendingSlideNumber (const sal_Int32 nPendingSlideNumber)
1133 {
1134 mnPendingSlideNumber = nPendingSlideNumber;
1135
1136 if (mpTheme == nullptr)
1137 return;
1138
1139 if ( ! mxMainWindow.is())
1140 return;
1141
1142 PresenterTheme::SharedFontDescriptor pFont (
1143 mpTheme->GetFont("PendingSlideNumberFont"));
1144 if (!pFont)
1145 return;
1146
1147 pFont->PrepareFont(mxCanvas);
1148 if ( ! pFont->mxFont.is())
1149 return;
1150
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,
1156 0);
1157 }
1158
SwitchMonitors()1159 void PresenterController::SwitchMonitors()
1160 {
1161 Reference<lang::XEventListener> xScreen( mxScreen );
1162 if (!xScreen.is())
1163 return;
1164
1165 PresenterScreen *pScreen = dynamic_cast<PresenterScreen *>(xScreen.get());
1166 if (!pScreen)
1167 return;
1168
1169 pScreen->SwitchMonitors();
1170 }
1171
ExitPresenter()1172 void PresenterController::ExitPresenter()
1173 {
1174 if( mxController.is() )
1175 {
1176 Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
1177 if( xPS.is() )
1178 {
1179 Reference< XPresentation > xP( xPS->getPresentation() );
1180 if( xP.is() )
1181 xP->end();
1182 }
1183 }
1184 }
1185
1186 } // end of namespace ::sdext::presenter
1187
1188 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1189