1
2 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4 * This file is part of the LibreOffice project.
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * This file incorporates work covered by the following license notice:
11 *
12 * Licensed to the Apache Software Foundation (ASF) under one or more
13 * contributor license agreements. See the NOTICE file distributed
14 * with this work for additional information regarding copyright
15 * ownership. The ASF licenses this file to you under the Apache
16 * License, Version 2.0 (the "License"); you may not use this file
17 * except in compliance with the License. You may obtain a copy of
18 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 */
20
21 #include "PresenterSlideShowView.hxx"
22 #include "PresenterCanvasHelper.hxx"
23 #include "PresenterGeometryHelper.hxx"
24 #include "PresenterHelper.hxx"
25 #include "PresenterPaneContainer.hxx"
26 #include <com/sun/star/awt/InvalidateStyle.hpp>
27 #include <com/sun/star/awt/PosSize.hpp>
28 #include <com/sun/star/awt/Pointer.hpp>
29 #include <com/sun/star/awt/Toolkit.hpp>
30 #include <com/sun/star/awt/WindowAttribute.hpp>
31 #include <com/sun/star/awt/XWindow.hpp>
32 #include <com/sun/star/awt/XWindowPeer.hpp>
33 #include <com/sun/star/drawing/XPresenterHelper.hpp>
34 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
35 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
36 #include <com/sun/star/rendering/CompositeOperation.hpp>
37 #include <com/sun/star/rendering/TextDirection.hpp>
38 #include <com/sun/star/rendering/TexturingMode.hpp>
39 #include <osl/mutex.hxx>
40
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::drawing::framework;
44
45 namespace sdext::presenter {
46
47 //===== PresenterSlideShowView ================================================
48
PresenterSlideShowView(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::uno::Reference<css::drawing::framework::XResourceId> & rxViewId,const css::uno::Reference<css::frame::XController> & rxController,const::rtl::Reference<PresenterController> & rpPresenterController)49 PresenterSlideShowView::PresenterSlideShowView (
50 const css::uno::Reference<css::uno::XComponentContext>& rxContext,
51 const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
52 const css::uno::Reference<css::frame::XController>& rxController,
53 const ::rtl::Reference<PresenterController>& rpPresenterController)
54 : PresenterSlideShowViewInterfaceBase(m_aMutex),
55 mxComponentContext(rxContext),
56 mpPresenterController(rpPresenterController),
57 mxViewId(rxViewId),
58 mxController(rxController),
59 mxSlideShowController(PresenterHelper::GetSlideShowController(rxController)),
60 mxSlideShow(),
61 mxCanvas(),
62 mxViewCanvas(),
63 mxPointer(),
64 mxWindow(),
65 mxViewWindow(),
66 mxTopPane(),
67 mxPresenterHelper(),
68 mxBackgroundPolygon1(),
69 mxBackgroundPolygon2(),
70 mbIsViewAdded(false),
71 mnPageAspectRatio(28.0/21.0),
72 maBroadcaster(m_aMutex),
73 mpBackground(),
74 mbIsForcedPaintPending(false),
75 mbIsPaintPending(true),
76 msClickToExitPresentationText(),
77 msClickToExitPresentationTitle(),
78 msTitleTemplate(),
79 mbIsEndSlideVisible(false),
80 mxCurrentSlide()
81 {
82 if (mpPresenterController)
83 {
84 mnPageAspectRatio = mpPresenterController->GetSlideAspectRatio();
85 mpBackground = mpPresenterController->GetViewBackground(mxViewId->getResourceURL());
86 }
87 }
88
LateInit()89 void PresenterSlideShowView::LateInit()
90 {
91 mxSlideShow.set( mxSlideShowController->getSlideShow(), UNO_SET_THROW);
92 Reference<lang::XComponent> xSlideShowComponent (mxSlideShow, UNO_QUERY);
93 xSlideShowComponent->addEventListener(static_cast<awt::XWindowListener*>(this));
94
95 Reference<lang::XMultiComponentFactory> xFactory (
96 mxComponentContext->getServiceManager(), UNO_SET_THROW);
97 mxPresenterHelper.set (xFactory->createInstanceWithContext(
98 "com.sun.star.comp.Draw.PresenterHelper",
99 mxComponentContext),
100 UNO_QUERY_THROW);
101
102 // Use view id and controller to retrieve window and canvas from
103 // configuration controller.
104 Reference<XControllerManager> xCM (mxController, UNO_QUERY_THROW);
105 Reference<XConfigurationController> xCC (xCM->getConfigurationController());
106
107 if (xCC.is())
108 {
109 mxTopPane.set(xCC->getResource(mxViewId->getAnchor()->getAnchor()), UNO_QUERY);
110
111 Reference<XPane> xPane (xCC->getResource(mxViewId->getAnchor()), UNO_QUERY_THROW);
112
113 mxWindow = xPane->getWindow();
114 mxCanvas = xPane->getCanvas();
115
116 if (mxWindow.is())
117 {
118 mxWindow->addPaintListener(this);
119 mxWindow->addWindowListener(this);
120 }
121
122 // The window does not have to paint a background. We do
123 // that ourself.
124 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
125 if (xPeer.is())
126 xPeer->setBackground(util::Color(0xff000000));
127 }
128
129 // Create a window for the actual slide show view. It is places
130 // centered and with maximal size inside the pane.
131 mxViewWindow = CreateViewWindow(mxWindow);
132
133 mxViewCanvas = CreateViewCanvas(mxViewWindow);
134
135 if (mxViewWindow.is())
136 {
137 // Register listeners at window.
138 mxViewWindow->addPaintListener(this);
139 mxViewWindow->addMouseListener(this);
140 mxViewWindow->addMouseMotionListener(this);
141 }
142
143 if (mxViewWindow.is())
144 Resize();
145
146 if (mxWindow.is())
147 mxWindow->setVisible(true);
148
149 // Add the new slide show view to the slide show.
150 if (mxSlideShow.is() && ! mbIsViewAdded)
151 {
152 impl_addAndConfigureView();
153 mbIsViewAdded = true;
154 }
155
156 // Read text for one past last slide.
157 PresenterConfigurationAccess aConfiguration (
158 mxComponentContext,
159 PresenterConfigurationAccess::msPresenterScreenRootName,
160 PresenterConfigurationAccess::READ_ONLY);
161 aConfiguration.GetConfigurationNode(
162 "Presenter/Views/CurrentSlidePreview/"
163 "Strings/ClickToExitPresentationText/String")
164 >>= msClickToExitPresentationText;
165 aConfiguration.GetConfigurationNode(
166 "Presenter/Views/CurrentSlidePreview/"
167 "Strings/ClickToExitPresentationTitle/String")
168 >>= msClickToExitPresentationTitle;
169 }
170
~PresenterSlideShowView()171 PresenterSlideShowView::~PresenterSlideShowView()
172 {
173 }
174
disposing()175 void PresenterSlideShowView::disposing()
176 {
177 // Tell all listeners that we are disposed.
178 lang::EventObject aEvent;
179 aEvent.Source = static_cast<XWeak*>(this);
180
181 ::cppu::OInterfaceContainerHelper* pIterator
182 = maBroadcaster.getContainer(cppu::UnoType<lang::XEventListener>::get());
183 if (pIterator != nullptr)
184 pIterator->disposeAndClear(aEvent);
185
186 // Do this for
187 // XPaintListener, XModifyListener,XMouseListener,XMouseMotionListener,XWindowListener?
188
189 if (mxWindow.is())
190 {
191 mxWindow->removePaintListener(this);
192 mxWindow->removeMouseListener(this);
193 mxWindow->removeMouseMotionListener(this);
194 mxWindow->removeWindowListener(this);
195 mxWindow = nullptr;
196 }
197 mxSlideShowController = nullptr;
198 mxSlideShow = nullptr;
199 if (mxViewCanvas.is())
200 {
201 Reference<XComponent> xComponent (mxViewCanvas, UNO_QUERY);
202 mxViewCanvas = nullptr;
203 if (xComponent.is())
204 xComponent->dispose();
205 }
206 if (mxViewWindow.is())
207 {
208 Reference<XComponent> xComponent = mxViewWindow;
209 mxViewWindow = nullptr;
210 if (xComponent.is())
211 xComponent->dispose();
212 }
213 if (mxPointer.is())
214 {
215 Reference<XComponent> xComponent (mxPointer, UNO_QUERY);
216 mxPointer = nullptr;
217 if (xComponent.is())
218 xComponent->dispose();
219 }
220 if (mxBackgroundPolygon1.is())
221 {
222 Reference<XComponent> xComponent (mxBackgroundPolygon1, UNO_QUERY);
223 mxBackgroundPolygon1 = nullptr;
224 if (xComponent.is())
225 xComponent->dispose();
226 }
227 if (mxBackgroundPolygon2.is())
228 {
229 Reference<XComponent> xComponent (mxBackgroundPolygon2, UNO_QUERY);
230 mxBackgroundPolygon2 = nullptr;
231 if (xComponent.is())
232 xComponent->dispose();
233 }
234
235 mxComponentContext = nullptr;
236 mpPresenterController = nullptr;
237 mxViewId = nullptr;
238 mxController = nullptr;
239 mxCanvas = nullptr;
240 mpBackground.reset();
241 msClickToExitPresentationText.clear();
242 msClickToExitPresentationTitle.clear();
243 msTitleTemplate.clear();
244 mxCurrentSlide = nullptr;
245 }
246
247 //----- XDrawView -------------------------------------------------------------
248
setCurrentPage(const css::uno::Reference<css::drawing::XDrawPage> & rxSlide)249 void SAL_CALL PresenterSlideShowView::setCurrentPage (
250 const css::uno::Reference<css::drawing::XDrawPage>& rxSlide)
251 {
252 mxCurrentSlide = rxSlide;
253 if (mpPresenterController
254 && mxSlideShowController.is()
255 && ! mpPresenterController->GetCurrentSlide().is()
256 && ! mxSlideShowController->isPaused())
257 {
258 mbIsEndSlideVisible = true;
259 Reference<awt::XWindowPeer> xPeer (mxViewWindow, UNO_QUERY);
260 if (xPeer.is())
261 xPeer->invalidate(awt::InvalidateStyle::NOTRANSPARENT);
262
263 // For the end slide we use a special title, without the (n of m)
264 // part. Save the title template for the case that the user goes
265 // backwards.
266 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
267 mpPresenterController->GetPaneContainer()->FindViewURL(mxViewId->getResourceURL()));
268 if (pDescriptor)
269 {
270 msTitleTemplate = pDescriptor->msTitleTemplate;
271 pDescriptor->msTitleTemplate = msClickToExitPresentationTitle;
272 mpPresenterController->UpdatePaneTitles();
273 }
274 }
275 else if (mbIsEndSlideVisible)
276 {
277 mbIsEndSlideVisible = false;
278
279 // Restore the title template.
280 PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
281 mpPresenterController->GetPaneContainer()->FindViewURL(mxViewId->getResourceURL()));
282 if (pDescriptor)
283 {
284 pDescriptor->msTitleTemplate = msTitleTemplate;
285 pDescriptor->msTitle.clear();
286 mpPresenterController->UpdatePaneTitles();
287 }
288 }
289 }
290
getCurrentPage()291 css::uno::Reference<css::drawing::XDrawPage> SAL_CALL PresenterSlideShowView::getCurrentPage()
292 {
293 return mxCurrentSlide;
294 }
295
296 //----- CachablePresenterView -------------------------------------------------
297
ReleaseView()298 void PresenterSlideShowView::ReleaseView()
299 {
300 if (mxSlideShow.is() && mbIsViewAdded)
301 {
302 mxSlideShow->removeView(this);
303 mbIsViewAdded = false;
304 }
305 }
306
307 //----- XSlideShowView --------------------------------------------------------
308
getCanvas()309 Reference<rendering::XSpriteCanvas> SAL_CALL PresenterSlideShowView::getCanvas()
310 {
311 ThrowIfDisposed();
312
313 return Reference<rendering::XSpriteCanvas>(mxViewCanvas, UNO_QUERY);
314 }
315
clear()316 void SAL_CALL PresenterSlideShowView::clear()
317 {
318 ThrowIfDisposed();
319 mbIsForcedPaintPending = false;
320 mbIsPaintPending = false;
321
322 if (!(mxViewCanvas.is() && mxViewWindow.is()))
323 return;
324
325 // Create a polygon for the window outline.
326 awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize());
327 Reference<rendering::XPolyPolygon2D> xPolygon (PresenterGeometryHelper::CreatePolygon(
328 awt::Rectangle(0,0, aViewWindowBox.Width,aViewWindowBox.Height),
329 mxViewCanvas->getDevice()));
330
331 rendering::ViewState aViewState (
332 geometry::AffineMatrix2D(1,0,0, 0,1,0),
333 nullptr);
334 double const aColor[4] = {0,0,0,0};
335 rendering::RenderState aRenderState(
336 geometry::AffineMatrix2D(1,0,0, 0,1,0),
337 nullptr,
338 Sequence<double>(aColor,4),
339 rendering::CompositeOperation::SOURCE);
340 mxViewCanvas->fillPolyPolygon(xPolygon, aViewState, aRenderState);
341 }
342
getTransformation()343 geometry::AffineMatrix2D SAL_CALL PresenterSlideShowView::getTransformation()
344 {
345 ThrowIfDisposed();
346
347 if (mxViewWindow.is())
348 {
349 // When the mbIsInModifyNotification is set then a slightly modified
350 // version of the transformation is returned in order to get past
351 // optimizations the avoid updates when the transformation is
352 // unchanged (when the window size changes then due to the constant
353 // aspect ratio the size of the preview may remain the same while
354 // the position changes. The position, however, is represented by
355 // the position of the view window. This transformation is given
356 // relative to the view window and therefore does not contain the
357 // position.)
358 const awt::Rectangle aWindowBox = mxViewWindow->getPosSize();
359 return geometry::AffineMatrix2D(
360 aWindowBox.Width-1, 0, 0,
361 0, aWindowBox.Height-1, 0);
362 }
363 else
364 {
365 return geometry::AffineMatrix2D(1,0,0, 0,1,0);
366 }
367 }
368
getTranslationOffset()369 geometry::IntegerSize2D SAL_CALL PresenterSlideShowView::getTranslationOffset()
370 {
371 ThrowIfDisposed();
372 return geometry::IntegerSize2D(0,0);
373 }
374
addTransformationChangedListener(const Reference<util::XModifyListener> & rxListener)375 void SAL_CALL PresenterSlideShowView::addTransformationChangedListener(
376 const Reference<util::XModifyListener>& rxListener)
377 {
378 ThrowIfDisposed();
379 maBroadcaster.addListener(
380 cppu::UnoType<util::XModifyListener>::get(),
381 rxListener);
382 }
383
removeTransformationChangedListener(const Reference<util::XModifyListener> & rxListener)384 void SAL_CALL PresenterSlideShowView::removeTransformationChangedListener(
385 const Reference<util::XModifyListener>& rxListener)
386 {
387 ThrowIfDisposed();
388 maBroadcaster.removeListener(
389 cppu::UnoType<util::XModifyListener>::get(),
390 rxListener);
391 }
392
addPaintListener(const Reference<awt::XPaintListener> & rxListener)393 void SAL_CALL PresenterSlideShowView::addPaintListener(
394 const Reference<awt::XPaintListener>& rxListener)
395 {
396 ThrowIfDisposed();
397 maBroadcaster.addListener(
398 cppu::UnoType<awt::XPaintListener>::get(),
399 rxListener);
400 }
401
removePaintListener(const Reference<awt::XPaintListener> & rxListener)402 void SAL_CALL PresenterSlideShowView::removePaintListener(
403 const Reference<awt::XPaintListener>& rxListener)
404 {
405 ThrowIfDisposed();
406 maBroadcaster.removeListener(
407 cppu::UnoType<awt::XPaintListener>::get(),
408 rxListener);
409 }
410
addMouseListener(const Reference<awt::XMouseListener> & rxListener)411 void SAL_CALL PresenterSlideShowView::addMouseListener(
412 const Reference<awt::XMouseListener>& rxListener)
413 {
414 ThrowIfDisposed();
415 maBroadcaster.addListener(
416 cppu::UnoType<awt::XMouseListener>::get(),
417 rxListener);
418 }
419
removeMouseListener(const Reference<awt::XMouseListener> & rxListener)420 void SAL_CALL PresenterSlideShowView::removeMouseListener(
421 const Reference<awt::XMouseListener>& rxListener)
422 {
423 ThrowIfDisposed();
424 maBroadcaster.removeListener(
425 cppu::UnoType<awt::XMouseListener>::get(),
426 rxListener);
427 }
428
addMouseMotionListener(const Reference<awt::XMouseMotionListener> & rxListener)429 void SAL_CALL PresenterSlideShowView::addMouseMotionListener(
430 const Reference<awt::XMouseMotionListener>& rxListener)
431 {
432 ThrowIfDisposed();
433 maBroadcaster.addListener(
434 cppu::UnoType<awt::XMouseMotionListener>::get(),
435 rxListener);
436 }
437
removeMouseMotionListener(const Reference<awt::XMouseMotionListener> & rxListener)438 void SAL_CALL PresenterSlideShowView::removeMouseMotionListener(
439 const Reference<awt::XMouseMotionListener>& rxListener)
440 {
441 ThrowIfDisposed();
442 maBroadcaster.removeListener(
443 cppu::UnoType<awt::XMouseMotionListener>::get(),
444 rxListener);
445 }
446
setMouseCursor(::sal_Int16 nPointerShape)447 void SAL_CALL PresenterSlideShowView::setMouseCursor(::sal_Int16 nPointerShape)
448 {
449 ThrowIfDisposed();
450
451 // Create a pointer when it does not yet exist.
452 if ( ! mxPointer.is())
453 {
454 mxPointer = awt::Pointer::create(mxComponentContext);
455 }
456
457 // Set the pointer to the given shape and the window(peer) to the
458 // pointer.
459 Reference<awt::XWindowPeer> xPeer (mxViewWindow, UNO_QUERY);
460 if (mxPointer.is() && xPeer.is())
461 {
462 mxPointer->setType(nPointerShape);
463 xPeer->setPointer(mxPointer);
464 }
465 }
466
getCanvasArea()467 awt::Rectangle SAL_CALL PresenterSlideShowView::getCanvasArea( )
468 {
469 if( mxViewWindow.is() && mxTopPane.is() )
470 return mxPresenterHelper->getWindowExtentsRelative( mxViewWindow, mxTopPane->getWindow() );
471
472 awt::Rectangle aRectangle;
473
474 aRectangle.X = aRectangle.Y = aRectangle.Width = aRectangle.Height = 0;
475
476 return aRectangle;
477 }
478
479 //----- lang::XEventListener --------------------------------------------------
480
disposing(const lang::EventObject & rEvent)481 void SAL_CALL PresenterSlideShowView::disposing (const lang::EventObject& rEvent)
482 {
483 if (rEvent.Source == mxViewWindow)
484 mxViewWindow = nullptr;
485 else if (rEvent.Source == mxSlideShow)
486 mxSlideShow = nullptr;
487 }
488
489 //----- XPaintListener --------------------------------------------------------
490
windowPaint(const awt::PaintEvent & rEvent)491 void SAL_CALL PresenterSlideShowView::windowPaint (const awt::PaintEvent& rEvent)
492 {
493 // Deactivated views must not be painted.
494 if ( ! mbIsPresenterViewActive)
495 return;
496
497 awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize());
498 if (aViewWindowBox.Width <= 0 || aViewWindowBox.Height <= 0)
499 return;
500
501 if (rEvent.Source == mxWindow)
502 PaintOuterWindow(rEvent.UpdateRect);
503 else if (mbIsEndSlideVisible)
504 PaintEndSlide(rEvent.UpdateRect);
505 else
506 PaintInnerWindow(rEvent);
507 }
508
509 //----- XMouseListener --------------------------------------------------------
510
mousePressed(const awt::MouseEvent & rEvent)511 void SAL_CALL PresenterSlideShowView::mousePressed (const awt::MouseEvent& rEvent)
512 {
513 awt::MouseEvent aEvent (rEvent);
514 aEvent.Source = static_cast<XWeak*>(this);
515 ::cppu::OInterfaceContainerHelper* pIterator
516 = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseListener>::get());
517 if (pIterator != nullptr)
518 {
519 pIterator->notifyEach(&awt::XMouseListener::mousePressed, aEvent);
520 }
521
522 // Only when the end slide is displayed we forward the mouse event to
523 // the PresenterController so that it switches to the next slide and
524 // ends the presentation.
525 if (mbIsEndSlideVisible)
526 if (mpPresenterController)
527 mpPresenterController->HandleMouseClick(rEvent);
528 }
529
mouseReleased(const awt::MouseEvent & rEvent)530 void SAL_CALL PresenterSlideShowView::mouseReleased (const awt::MouseEvent& rEvent)
531 {
532 awt::MouseEvent aEvent (rEvent);
533 aEvent.Source = static_cast<XWeak*>(this);
534 ::cppu::OInterfaceContainerHelper* pIterator
535 = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseListener>::get());
536 if (pIterator != nullptr)
537 {
538 pIterator->notifyEach(&awt::XMouseListener::mouseReleased, aEvent);
539 }
540 }
541
mouseEntered(const awt::MouseEvent & rEvent)542 void SAL_CALL PresenterSlideShowView::mouseEntered (const awt::MouseEvent& rEvent)
543 {
544 awt::MouseEvent aEvent (rEvent);
545 aEvent.Source = static_cast<XWeak*>(this);
546 ::cppu::OInterfaceContainerHelper* pIterator
547 = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseListener>::get());
548 if (pIterator != nullptr)
549 {
550 pIterator->notifyEach(&awt::XMouseListener::mouseEntered, aEvent);
551 }
552 }
553
mouseExited(const awt::MouseEvent & rEvent)554 void SAL_CALL PresenterSlideShowView::mouseExited (const awt::MouseEvent& rEvent)
555 {
556 awt::MouseEvent aEvent (rEvent);
557 aEvent.Source = static_cast<XWeak*>(this);
558 ::cppu::OInterfaceContainerHelper* pIterator
559 = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseListener>::get());
560 if (pIterator != nullptr)
561 {
562 pIterator->notifyEach(&awt::XMouseListener::mouseExited, aEvent);
563 }
564 }
565
566 //----- XMouseMotionListener --------------------------------------------------
567
mouseDragged(const awt::MouseEvent & rEvent)568 void SAL_CALL PresenterSlideShowView::mouseDragged (const awt::MouseEvent& rEvent)
569 {
570 awt::MouseEvent aEvent (rEvent);
571 aEvent.Source = static_cast<XWeak*>(this);
572 ::cppu::OInterfaceContainerHelper* pIterator
573 = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseMotionListener>::get());
574 if (pIterator != nullptr)
575 {
576 pIterator->notifyEach(&awt::XMouseMotionListener::mouseDragged, aEvent);
577 }
578 }
579
mouseMoved(const awt::MouseEvent & rEvent)580 void SAL_CALL PresenterSlideShowView::mouseMoved (const awt::MouseEvent& rEvent)
581 {
582 awt::MouseEvent aEvent (rEvent);
583 aEvent.Source = static_cast<XWeak*>(this);
584 ::cppu::OInterfaceContainerHelper* pIterator
585 = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseMotionListener>::get());
586 if (pIterator != nullptr)
587 {
588 pIterator->notifyEach(&awt::XMouseMotionListener::mouseMoved, aEvent);
589 }
590 }
591
592 //----- XWindowListener -------------------------------------------------------
593
windowResized(const awt::WindowEvent &)594 void SAL_CALL PresenterSlideShowView::windowResized (const awt::WindowEvent&)
595 {
596 ThrowIfDisposed();
597 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
598
599 Resize();
600 }
601
windowMoved(const awt::WindowEvent &)602 void SAL_CALL PresenterSlideShowView::windowMoved (const awt::WindowEvent&)
603 {
604 if ( ! mbIsPaintPending)
605 mbIsForcedPaintPending = true;
606 }
607
windowShown(const lang::EventObject &)608 void SAL_CALL PresenterSlideShowView::windowShown (const lang::EventObject&)
609 {
610 Resize();
611 }
612
windowHidden(const lang::EventObject &)613 void SAL_CALL PresenterSlideShowView::windowHidden (const lang::EventObject&) {}
614
615 //----- XView -----------------------------------------------------------------
616
getResourceId()617 Reference<XResourceId> SAL_CALL PresenterSlideShowView::getResourceId()
618 {
619 return mxViewId;
620 }
621
isAnchorOnly()622 sal_Bool SAL_CALL PresenterSlideShowView::isAnchorOnly()
623 {
624 return false;
625 }
626
627 //----- CachablePresenterView -------------------------------------------------
628
ActivatePresenterView()629 void PresenterSlideShowView::ActivatePresenterView()
630 {
631 if (mxSlideShow.is() && ! mbIsViewAdded)
632 {
633 impl_addAndConfigureView();
634 mbIsViewAdded = true;
635 }
636 }
637
DeactivatePresenterView()638 void PresenterSlideShowView::DeactivatePresenterView()
639 {
640 if (mxSlideShow.is() && mbIsViewAdded)
641 {
642 mxSlideShow->removeView(this);
643 mbIsViewAdded = false;
644 }
645 }
646
647
PaintOuterWindow(const awt::Rectangle & rRepaintBox)648 void PresenterSlideShowView::PaintOuterWindow (const awt::Rectangle& rRepaintBox)
649 {
650 if ( ! mxCanvas.is())
651 return;
652
653 if (!mpBackground)
654 return;
655
656 const rendering::ViewState aViewState(
657 geometry::AffineMatrix2D(1,0,0, 0,1,0),
658 PresenterGeometryHelper::CreatePolygon(rRepaintBox, mxCanvas->getDevice()));
659
660 rendering::RenderState aRenderState (
661 geometry::AffineMatrix2D(1,0,0, 0,1,0),
662 nullptr,
663 Sequence<double>(4),
664 rendering::CompositeOperation::SOURCE);
665
666 Reference<rendering::XBitmap> xBackgroundBitmap (mpBackground->GetNormalBitmap());
667 if (xBackgroundBitmap.is())
668 {
669 const geometry::IntegerSize2D aBitmapSize(xBackgroundBitmap->getSize());
670 Sequence<rendering::Texture> aTextures
671 {
672 {
673 geometry::AffineMatrix2D( aBitmapSize.Width,0,0, 0,aBitmapSize.Height,0),
674 1,
675 0,
676 xBackgroundBitmap,
677 nullptr,
678 nullptr,
679 rendering::StrokeAttributes(),
680 rendering::TexturingMode::REPEAT,
681 rendering::TexturingMode::REPEAT
682 }
683 };
684
685 if (mxBackgroundPolygon1.is())
686 mxCanvas->fillTexturedPolyPolygon(
687 mxBackgroundPolygon1,
688 aViewState,
689 aRenderState,
690 aTextures);
691 if (mxBackgroundPolygon2.is())
692 mxCanvas->fillTexturedPolyPolygon(
693 mxBackgroundPolygon2,
694 aViewState,
695 aRenderState,
696 aTextures);
697 }
698 else
699 {
700 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpBackground->maReplacementColor);
701
702 if (mxBackgroundPolygon1.is())
703 mxCanvas->fillPolyPolygon(mxBackgroundPolygon1, aViewState, aRenderState);
704 if (mxBackgroundPolygon2.is())
705 mxCanvas->fillPolyPolygon(mxBackgroundPolygon2, aViewState, aRenderState);
706 }
707 }
708
PaintEndSlide(const awt::Rectangle & rRepaintBox)709 void PresenterSlideShowView::PaintEndSlide (const awt::Rectangle& rRepaintBox)
710 {
711 if ( ! mxCanvas.is())
712 return;
713
714 const rendering::ViewState aViewState(
715 geometry::AffineMatrix2D(1,0,0, 0,1,0),
716 PresenterGeometryHelper::CreatePolygon(rRepaintBox, mxCanvas->getDevice()));
717
718 rendering::RenderState aRenderState (
719 geometry::AffineMatrix2D(1,0,0, 0,1,0),
720 nullptr,
721 Sequence<double>(4),
722 rendering::CompositeOperation::SOURCE);
723 PresenterCanvasHelper::SetDeviceColor(aRenderState, util::Color(0x00000000));
724 mxCanvas->fillPolyPolygon(
725 PresenterGeometryHelper::CreatePolygon(mxViewWindow->getPosSize(), mxCanvas->getDevice()),
726 aViewState,
727 aRenderState);
728
729 do
730 {
731 if (!mpPresenterController)
732 break;
733 std::shared_ptr<PresenterTheme> pTheme (mpPresenterController->GetTheme());
734 if (pTheme == nullptr)
735 break;
736
737 const OUString sViewStyle (pTheme->GetStyleName(mxViewId->getResourceURL()));
738 PresenterTheme::SharedFontDescriptor pFont (pTheme->GetFont(sViewStyle));
739 if (!pFont)
740 break;
741
742 /// this is responsible of the " presentation exit " text inside the slide windows
743 PresenterCanvasHelper::SetDeviceColor(aRenderState, util::Color(0x00ffffff));
744 aRenderState.AffineTransform.m02 = 20;
745 aRenderState.AffineTransform.m12 = 40;
746 const rendering::StringContext aContext (
747 msClickToExitPresentationText, 0, msClickToExitPresentationText.getLength());
748 pFont->PrepareFont(mxCanvas);
749 const Reference<rendering::XTextLayout> xLayout (
750 pFont->mxFont->createTextLayout(aContext,rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0));
751 mxCanvas->drawTextLayout(
752 xLayout,
753 aViewState,
754 aRenderState);
755 }
756 while (false);
757
758 // Finally, in double buffered environments, request the changes to be
759 // made visible.
760 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
761 if (xSpriteCanvas.is())
762 xSpriteCanvas->updateScreen(true);
763 }
764
PaintInnerWindow(const awt::PaintEvent & rEvent)765 void PresenterSlideShowView::PaintInnerWindow (const awt::PaintEvent& rEvent)
766 {
767 // Forward window paint to listeners.
768 awt::PaintEvent aEvent (rEvent);
769 aEvent.Source = static_cast<XWeak*>(this);
770 ::cppu::OInterfaceContainerHelper* pIterator
771 = maBroadcaster.getContainer(cppu::UnoType<awt::XPaintListener>::get());
772 if (pIterator != nullptr)
773 {
774 pIterator->notifyEach(&awt::XPaintListener::windowPaint, aEvent);
775 }
776
777 /** The slide show relies on the back buffer of the canvas not being
778 modified. With a shared canvas there are times when that can not be
779 guaranteed.
780 */
781 if (mbIsForcedPaintPending && mxSlideShow.is() && mbIsViewAdded)
782 {
783 mxSlideShow->removeView(this);
784 impl_addAndConfigureView();
785 }
786
787 // Finally, in double buffered environments, request the changes to be
788 // made visible.
789 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
790 if (xSpriteCanvas.is())
791 xSpriteCanvas->updateScreen(true);
792 }
793
CreateViewWindow(const Reference<awt::XWindow> & rxParentWindow) const794 Reference<awt::XWindow> PresenterSlideShowView::CreateViewWindow (
795 const Reference<awt::XWindow>& rxParentWindow) const
796 {
797 Reference<awt::XWindow> xViewWindow;
798 try
799 {
800 Reference<lang::XMultiComponentFactory> xFactory (mxComponentContext->getServiceManager());
801 if ( ! xFactory.is())
802 return xViewWindow;
803
804 Reference<awt::XToolkit2> xToolkit = awt::Toolkit::create(mxComponentContext);
805 awt::WindowDescriptor aWindowDescriptor (
806 awt::WindowClass_CONTAINER,
807 OUString(),
808 Reference<awt::XWindowPeer>(rxParentWindow,UNO_QUERY_THROW),
809 -1, // parent index not available
810 awt::Rectangle(0,0,10,10),
811 awt::WindowAttribute::SIZEABLE
812 | awt::WindowAttribute::MOVEABLE
813 | awt::WindowAttribute::NODECORATION);
814 xViewWindow.set( xToolkit->createWindow(aWindowDescriptor),UNO_QUERY_THROW);
815
816 // Make the background transparent. The slide show paints its own background.
817 Reference<awt::XWindowPeer> xPeer (xViewWindow, UNO_QUERY_THROW);
818 xPeer->setBackground(0xff000000);
819
820 xViewWindow->setVisible(true);
821 }
822 catch (RuntimeException&)
823 {
824 }
825 return xViewWindow;
826 }
827
CreateViewCanvas(const Reference<awt::XWindow> & rxViewWindow) const828 Reference<rendering::XCanvas> PresenterSlideShowView::CreateViewCanvas (
829 const Reference<awt::XWindow>& rxViewWindow) const
830 {
831 // Create a canvas for the view window.
832 return mxPresenterHelper->createSharedCanvas(
833 Reference<rendering::XSpriteCanvas>(mxTopPane->getCanvas(), UNO_QUERY),
834 mxTopPane->getWindow(),
835 mxTopPane->getCanvas(),
836 mxTopPane->getWindow(),
837 rxViewWindow);
838 }
839
Resize()840 void PresenterSlideShowView::Resize()
841 {
842 if ( ! mxWindow.is() || ! mxViewWindow.is())
843 return;
844
845 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
846 if (aWindowBox.Height > 0)
847 {
848 awt::Rectangle aViewWindowBox;
849 const double nWindowAspectRatio (
850 double(aWindowBox.Width) / double(aWindowBox.Height));
851 if (nWindowAspectRatio > mnPageAspectRatio)
852 {
853 // Slides will be painted with the full parent window height.
854 aViewWindowBox.Width = sal_Int32(aWindowBox.Height * mnPageAspectRatio + 0.5);
855 aViewWindowBox.Height = aWindowBox.Height;
856 aViewWindowBox.X = (aWindowBox.Width - aViewWindowBox.Width) / 2;
857 aViewWindowBox.Y = 0;
858 }
859 else
860 {
861 // Slides will be painted with the full parent window width.
862 aViewWindowBox.Width = aWindowBox.Width;
863 aViewWindowBox.Height = sal_Int32(aWindowBox.Width / mnPageAspectRatio + 0.5);
864 aViewWindowBox.X = 0;
865 aViewWindowBox.Y = (aWindowBox.Height - aViewWindowBox.Height) / 2;
866 }
867 mxViewWindow->setPosSize(
868 aViewWindowBox.X,
869 aViewWindowBox.Y,
870 aViewWindowBox.Width,
871 aViewWindowBox.Height,
872 awt::PosSize::POSSIZE);
873 }
874
875 // Clear the background polygon so that on the next paint it is created
876 // for the new size.
877 CreateBackgroundPolygons();
878
879 // Notify listeners that the transformation that maps the view into the
880 // window has changed.
881 lang::EventObject aEvent (static_cast<XWeak*>(this));
882 ::cppu::OInterfaceContainerHelper* pIterator
883 = maBroadcaster.getContainer(cppu::UnoType<util::XModifyListener>::get());
884 if (pIterator != nullptr)
885 {
886 pIterator->notifyEach(&util::XModifyListener::modified, aEvent);
887 }
888
889 // Due to constant aspect ratio resizing may lead a preview that changes
890 // its position but not its size. This invalidates the back buffer and
891 // we have to enforce a complete repaint.
892 if ( ! mbIsPaintPending)
893 mbIsForcedPaintPending = true;
894 }
895
CreateBackgroundPolygons()896 void PresenterSlideShowView::CreateBackgroundPolygons()
897 {
898 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
899 const awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize());
900 if (aWindowBox.Height == aViewWindowBox.Height && aWindowBox.Width == aViewWindowBox.Width)
901 {
902 mxBackgroundPolygon1 = nullptr;
903 mxBackgroundPolygon2 = nullptr;
904 }
905 else if (aWindowBox.Height == aViewWindowBox.Height)
906 {
907 // Paint two boxes to the left and right of the view window.
908 mxBackgroundPolygon1 = PresenterGeometryHelper::CreatePolygon(
909 awt::Rectangle(
910 0,
911 0,
912 aViewWindowBox.X,
913 aWindowBox.Height),
914 mxCanvas->getDevice());
915 mxBackgroundPolygon2 = PresenterGeometryHelper::CreatePolygon(
916 awt::Rectangle(
917 aViewWindowBox.X + aViewWindowBox.Width,
918 0,
919 aWindowBox.Width - aViewWindowBox.X - aViewWindowBox.Width,
920 aWindowBox.Height),
921 mxCanvas->getDevice());
922 }
923 else
924 {
925 // Paint two boxes above and below the view window.
926 mxBackgroundPolygon1 = PresenterGeometryHelper::CreatePolygon(
927 awt::Rectangle(
928 0,
929 0,
930 aWindowBox.Width,
931 aViewWindowBox.Y),
932 mxCanvas->getDevice());
933 mxBackgroundPolygon2 = PresenterGeometryHelper::CreatePolygon(
934 awt::Rectangle(
935 0,
936 aViewWindowBox.Y + aViewWindowBox.Height,
937 aWindowBox.Width,
938 aWindowBox.Height - aViewWindowBox.Y - aViewWindowBox.Height),
939 mxCanvas->getDevice());
940 }
941 }
942
ThrowIfDisposed()943 void PresenterSlideShowView::ThrowIfDisposed()
944 {
945 if (rBHelper.bDisposed || rBHelper.bInDispose)
946 {
947 throw lang::DisposedException (
948 "PresenterSlideShowView object has already been disposed",
949 static_cast<uno::XWeak*>(this));
950 }
951 }
952
impl_addAndConfigureView()953 void PresenterSlideShowView::impl_addAndConfigureView()
954 {
955 Reference<presentation::XSlideShowView> xView (this);
956 mxSlideShow->addView(xView);
957 // Prevent embedded sounds being played twice at the same time by
958 // disabling sound for the new slide show view.
959 beans::PropertyValue aProperty;
960 aProperty.Name = "IsSoundEnabled";
961 Sequence<Any> aValues (2);
962 aValues[0] <<= xView;
963 aValues[1] <<= false;
964 aProperty.Value <<= aValues;
965 mxSlideShow->setProperty(aProperty);
966 }
967
968 } // end of namespace ::sd::presenter
969
970 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
971