From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- sdext/source/presenter/PresenterSlideShowView.cxx | 969 ++++++++++++++++++++++ 1 file changed, 969 insertions(+) create mode 100644 sdext/source/presenter/PresenterSlideShowView.cxx (limited to 'sdext/source/presenter/PresenterSlideShowView.cxx') diff --git a/sdext/source/presenter/PresenterSlideShowView.cxx b/sdext/source/presenter/PresenterSlideShowView.cxx new file mode 100644 index 000000000..609b2d856 --- /dev/null +++ b/sdext/source/presenter/PresenterSlideShowView.cxx @@ -0,0 +1,969 @@ + +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "PresenterSlideShowView.hxx" +#include "PresenterCanvasHelper.hxx" +#include "PresenterGeometryHelper.hxx" +#include "PresenterHelper.hxx" +#include "PresenterPaneContainer.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +namespace sdext::presenter { + +//===== PresenterSlideShowView ================================================ + +PresenterSlideShowView::PresenterSlideShowView ( + const css::uno::Reference& rxContext, + const css::uno::Reference& rxViewId, + const css::uno::Reference& rxController, + const ::rtl::Reference& rpPresenterController) + : PresenterSlideShowViewInterfaceBase(m_aMutex), + mxComponentContext(rxContext), + mpPresenterController(rpPresenterController), + mxViewId(rxViewId), + mxController(rxController), + mxSlideShowController(PresenterHelper::GetSlideShowController(rxController)), + mxSlideShow(), + mxCanvas(), + mxViewCanvas(), + mxPointer(), + mxWindow(), + mxViewWindow(), + mxTopPane(), + mxPresenterHelper(), + mxBackgroundPolygon1(), + mxBackgroundPolygon2(), + mbIsViewAdded(false), + mnPageAspectRatio(28.0/21.0), + maBroadcaster(m_aMutex), + mpBackground(), + mbIsForcedPaintPending(false), + mbIsPaintPending(true), + msClickToExitPresentationText(), + msClickToExitPresentationTitle(), + msTitleTemplate(), + mbIsEndSlideVisible(false), + mxCurrentSlide() +{ + if (mpPresenterController.get() != nullptr) + { + mnPageAspectRatio = mpPresenterController->GetSlideAspectRatio(); + mpBackground = mpPresenterController->GetViewBackground(mxViewId->getResourceURL()); + } +} + +void PresenterSlideShowView::LateInit() +{ + mxSlideShow.set( mxSlideShowController->getSlideShow(), UNO_SET_THROW); + Reference xSlideShowComponent (mxSlideShow, UNO_QUERY); + xSlideShowComponent->addEventListener(static_cast(this)); + + Reference xFactory ( + mxComponentContext->getServiceManager(), UNO_SET_THROW); + mxPresenterHelper.set (xFactory->createInstanceWithContext( + "com.sun.star.comp.Draw.PresenterHelper", + mxComponentContext), + UNO_QUERY_THROW); + + // Use view id and controller to retrieve window and canvas from + // configuration controller. + Reference xCM (mxController, UNO_QUERY_THROW); + Reference xCC (xCM->getConfigurationController()); + + if (xCC.is()) + { + mxTopPane.set(xCC->getResource(mxViewId->getAnchor()->getAnchor()), UNO_QUERY); + + Reference xPane (xCC->getResource(mxViewId->getAnchor()), UNO_QUERY_THROW); + + mxWindow = xPane->getWindow(); + mxCanvas = xPane->getCanvas(); + + if (mxWindow.is()) + { + mxWindow->addPaintListener(this); + mxWindow->addWindowListener(this); + } + + // The window does not have to paint a background. We do + // that ourself. + Reference xPeer (mxWindow, UNO_QUERY); + if (xPeer.is()) + xPeer->setBackground(util::Color(0xff000000)); + } + + // Create a window for the actual slide show view. It is places + // centered and with maximal size inside the pane. + mxViewWindow = CreateViewWindow(mxWindow); + + mxViewCanvas = CreateViewCanvas(mxViewWindow); + + if (mxViewWindow.is()) + { + // Register listeners at window. + mxViewWindow->addPaintListener(this); + mxViewWindow->addMouseListener(this); + mxViewWindow->addMouseMotionListener(this); + } + + if (mxViewWindow.is()) + Resize(); + + if (mxWindow.is()) + mxWindow->setVisible(true); + + // Add the new slide show view to the slide show. + if (mxSlideShow.is() && ! mbIsViewAdded) + { + impl_addAndConfigureView(); + mbIsViewAdded = true; + } + + // Read text for one past last slide. + PresenterConfigurationAccess aConfiguration ( + mxComponentContext, + PresenterConfigurationAccess::msPresenterScreenRootName, + PresenterConfigurationAccess::READ_ONLY); + aConfiguration.GetConfigurationNode( + "Presenter/Views/CurrentSlidePreview/" + "Strings/ClickToExitPresentationText/String") + >>= msClickToExitPresentationText; + aConfiguration.GetConfigurationNode( + "Presenter/Views/CurrentSlidePreview/" + "Strings/ClickToExitPresentationTitle/String") + >>= msClickToExitPresentationTitle; +} + +PresenterSlideShowView::~PresenterSlideShowView() +{ +} + +void PresenterSlideShowView::disposing() +{ + // Tell all listeners that we are disposed. + lang::EventObject aEvent; + aEvent.Source = static_cast(this); + + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + pIterator->disposeAndClear(aEvent); + + // Do this for + // XPaintListener, XModifyListener,XMouseListener,XMouseMotionListener,XWindowListener? + + if (mxWindow.is()) + { + mxWindow->removePaintListener(this); + mxWindow->removeMouseListener(this); + mxWindow->removeMouseMotionListener(this); + mxWindow->removeWindowListener(this); + mxWindow = nullptr; + } + mxSlideShowController = nullptr; + mxSlideShow = nullptr; + if (mxViewCanvas.is()) + { + Reference xComponent (mxViewCanvas, UNO_QUERY); + mxViewCanvas = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + if (mxViewWindow.is()) + { + Reference xComponent = mxViewWindow; + mxViewWindow = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + if (mxPointer.is()) + { + Reference xComponent (mxPointer, UNO_QUERY); + mxPointer = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + if (mxBackgroundPolygon1.is()) + { + Reference xComponent (mxBackgroundPolygon1, UNO_QUERY); + mxBackgroundPolygon1 = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + if (mxBackgroundPolygon2.is()) + { + Reference xComponent (mxBackgroundPolygon2, UNO_QUERY); + mxBackgroundPolygon2 = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + + mxComponentContext = nullptr; + mpPresenterController = nullptr; + mxViewId = nullptr; + mxController = nullptr; + mxCanvas = nullptr; + mpBackground.reset(); + msClickToExitPresentationText.clear(); + msClickToExitPresentationTitle.clear(); + msTitleTemplate.clear(); + mxCurrentSlide = nullptr; +} + +//----- XDrawView ------------------------------------------------------------- + +void SAL_CALL PresenterSlideShowView::setCurrentPage ( + const css::uno::Reference& rxSlide) +{ + mxCurrentSlide = rxSlide; + if (mpPresenterController.get() != nullptr + && mxSlideShowController.is() + && ! mpPresenterController->GetCurrentSlide().is() + && ! mxSlideShowController->isPaused()) + { + mbIsEndSlideVisible = true; + Reference xPeer (mxViewWindow, UNO_QUERY); + if (xPeer.is()) + xPeer->invalidate(awt::InvalidateStyle::NOTRANSPARENT); + + // For the end slide we use a special title, without the (n of m) + // part. Save the title template for the case that the user goes + // backwards. + PresenterPaneContainer::SharedPaneDescriptor pDescriptor ( + mpPresenterController->GetPaneContainer()->FindViewURL(mxViewId->getResourceURL())); + if (pDescriptor.get() != nullptr) + { + msTitleTemplate = pDescriptor->msTitleTemplate; + pDescriptor->msTitleTemplate = msClickToExitPresentationTitle; + mpPresenterController->UpdatePaneTitles(); + } + } + else if (mbIsEndSlideVisible) + { + mbIsEndSlideVisible = false; + + // Restore the title template. + PresenterPaneContainer::SharedPaneDescriptor pDescriptor ( + mpPresenterController->GetPaneContainer()->FindViewURL(mxViewId->getResourceURL())); + if (pDescriptor.get() != nullptr) + { + pDescriptor->msTitleTemplate = msTitleTemplate; + pDescriptor->msTitle.clear(); + mpPresenterController->UpdatePaneTitles(); + } + } +} + +css::uno::Reference SAL_CALL PresenterSlideShowView::getCurrentPage() +{ + return mxCurrentSlide; +} + +//----- CachablePresenterView ------------------------------------------------- + +void PresenterSlideShowView::ReleaseView() +{ + if (mxSlideShow.is() && mbIsViewAdded) + { + mxSlideShow->removeView(this); + mbIsViewAdded = false; + } +} + +//----- XSlideShowView -------------------------------------------------------- + +Reference SAL_CALL PresenterSlideShowView::getCanvas() +{ + ThrowIfDisposed(); + + return Reference(mxViewCanvas, UNO_QUERY); +} + +void SAL_CALL PresenterSlideShowView::clear() +{ + ThrowIfDisposed(); + mbIsForcedPaintPending = false; + mbIsPaintPending = false; + + if (!(mxViewCanvas.is() && mxViewWindow.is())) + return; + + // Create a polygon for the window outline. + awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize()); + Reference xPolygon (PresenterGeometryHelper::CreatePolygon( + awt::Rectangle(0,0, aViewWindowBox.Width,aViewWindowBox.Height), + mxViewCanvas->getDevice())); + + rendering::ViewState aViewState ( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + nullptr); + double const aColor[4] = {0,0,0,0}; + rendering::RenderState aRenderState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + nullptr, + Sequence(aColor,4), + rendering::CompositeOperation::SOURCE); + mxViewCanvas->fillPolyPolygon(xPolygon, aViewState, aRenderState); +} + +geometry::AffineMatrix2D SAL_CALL PresenterSlideShowView::getTransformation() +{ + ThrowIfDisposed(); + + if (mxViewWindow.is()) + { + // When the mbIsInModifyNotification is set then a slightly modified + // version of the transformation is returned in order to get past + // optimizations the avoid updates when the transformation is + // unchanged (when the window size changes then due to the constant + // aspect ratio the size of the preview may remain the same while + // the position changes. The position, however, is represented by + // the position of the view window. This transformation is given + // relative to the view window and therefore does not contain the + // position.) + const awt::Rectangle aWindowBox = mxViewWindow->getPosSize(); + return geometry::AffineMatrix2D( + aWindowBox.Width-1, 0, 0, + 0, aWindowBox.Height-1, 0); + } + else + { + return geometry::AffineMatrix2D(1,0,0, 0,1,0); + } +} + +geometry::IntegerSize2D SAL_CALL PresenterSlideShowView::getTranslationOffset() +{ + ThrowIfDisposed(); + return geometry::IntegerSize2D(0,0); +} + +void SAL_CALL PresenterSlideShowView::addTransformationChangedListener( + const Reference& rxListener) +{ + ThrowIfDisposed(); + maBroadcaster.addListener( + cppu::UnoType::get(), + rxListener); +} + +void SAL_CALL PresenterSlideShowView::removeTransformationChangedListener( + const Reference& rxListener) +{ + ThrowIfDisposed(); + maBroadcaster.removeListener( + cppu::UnoType::get(), + rxListener); +} + +void SAL_CALL PresenterSlideShowView::addPaintListener( + const Reference& rxListener) +{ + ThrowIfDisposed(); + maBroadcaster.addListener( + cppu::UnoType::get(), + rxListener); +} + +void SAL_CALL PresenterSlideShowView::removePaintListener( + const Reference& rxListener) +{ + ThrowIfDisposed(); + maBroadcaster.removeListener( + cppu::UnoType::get(), + rxListener); +} + +void SAL_CALL PresenterSlideShowView::addMouseListener( + const Reference& rxListener) +{ + ThrowIfDisposed(); + maBroadcaster.addListener( + cppu::UnoType::get(), + rxListener); +} + +void SAL_CALL PresenterSlideShowView::removeMouseListener( + const Reference& rxListener) +{ + ThrowIfDisposed(); + maBroadcaster.removeListener( + cppu::UnoType::get(), + rxListener); +} + +void SAL_CALL PresenterSlideShowView::addMouseMotionListener( + const Reference& rxListener) +{ + ThrowIfDisposed(); + maBroadcaster.addListener( + cppu::UnoType::get(), + rxListener); +} + +void SAL_CALL PresenterSlideShowView::removeMouseMotionListener( + const Reference& rxListener) +{ + ThrowIfDisposed(); + maBroadcaster.removeListener( + cppu::UnoType::get(), + rxListener); +} + +void SAL_CALL PresenterSlideShowView::setMouseCursor(::sal_Int16 nPointerShape) +{ + ThrowIfDisposed(); + + // Create a pointer when it does not yet exist. + if ( ! mxPointer.is()) + { + mxPointer = awt::Pointer::create(mxComponentContext); + } + + // Set the pointer to the given shape and the window(peer) to the + // pointer. + Reference xPeer (mxViewWindow, UNO_QUERY); + if (mxPointer.is() && xPeer.is()) + { + mxPointer->setType(nPointerShape); + xPeer->setPointer(mxPointer); + } +} + +awt::Rectangle SAL_CALL PresenterSlideShowView::getCanvasArea( ) +{ + if( mxViewWindow.is() && mxTopPane.is() ) + return mxPresenterHelper->getWindowExtentsRelative( mxViewWindow, mxTopPane->getWindow() ); + + awt::Rectangle aRectangle; + + aRectangle.X = aRectangle.Y = aRectangle.Width = aRectangle.Height = 0; + + return aRectangle; +} + +//----- lang::XEventListener -------------------------------------------------- + +void SAL_CALL PresenterSlideShowView::disposing (const lang::EventObject& rEvent) +{ + if (rEvent.Source == mxViewWindow) + mxViewWindow = nullptr; + else if (rEvent.Source == mxSlideShow) + mxSlideShow = nullptr; +} + +//----- XPaintListener -------------------------------------------------------- + +void SAL_CALL PresenterSlideShowView::windowPaint (const awt::PaintEvent& rEvent) +{ + // Deactivated views must not be painted. + if ( ! mbIsPresenterViewActive) + return; + + awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize()); + if (aViewWindowBox.Width <= 0 || aViewWindowBox.Height <= 0) + return; + + if (rEvent.Source == mxWindow) + PaintOuterWindow(rEvent.UpdateRect); + else if (mbIsEndSlideVisible) + PaintEndSlide(rEvent.UpdateRect); + else + PaintInnerWindow(rEvent); +} + +//----- XMouseListener -------------------------------------------------------- + +void SAL_CALL PresenterSlideShowView::mousePressed (const awt::MouseEvent& rEvent) +{ + awt::MouseEvent aEvent (rEvent); + aEvent.Source = static_cast(this); + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + { + pIterator->notifyEach(&awt::XMouseListener::mousePressed, aEvent); + } + + // Only when the end slide is displayed we forward the mouse event to + // the PresenterController so that it switches to the next slide and + // ends the presentation. + if (mbIsEndSlideVisible) + if (mpPresenterController.get() != nullptr) + mpPresenterController->HandleMouseClick(rEvent); +} + +void SAL_CALL PresenterSlideShowView::mouseReleased (const awt::MouseEvent& rEvent) +{ + awt::MouseEvent aEvent (rEvent); + aEvent.Source = static_cast(this); + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + { + pIterator->notifyEach(&awt::XMouseListener::mouseReleased, aEvent); + } +} + +void SAL_CALL PresenterSlideShowView::mouseEntered (const awt::MouseEvent& rEvent) +{ + awt::MouseEvent aEvent (rEvent); + aEvent.Source = static_cast(this); + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + { + pIterator->notifyEach(&awt::XMouseListener::mouseEntered, aEvent); + } +} + +void SAL_CALL PresenterSlideShowView::mouseExited (const awt::MouseEvent& rEvent) +{ + awt::MouseEvent aEvent (rEvent); + aEvent.Source = static_cast(this); + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + { + pIterator->notifyEach(&awt::XMouseListener::mouseExited, aEvent); + } +} + +//----- XMouseMotionListener -------------------------------------------------- + +void SAL_CALL PresenterSlideShowView::mouseDragged (const awt::MouseEvent& rEvent) +{ + awt::MouseEvent aEvent (rEvent); + aEvent.Source = static_cast(this); + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + { + pIterator->notifyEach(&awt::XMouseMotionListener::mouseDragged, aEvent); + } +} + +void SAL_CALL PresenterSlideShowView::mouseMoved (const awt::MouseEvent& rEvent) +{ + awt::MouseEvent aEvent (rEvent); + aEvent.Source = static_cast(this); + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + { + pIterator->notifyEach(&awt::XMouseMotionListener::mouseMoved, aEvent); + } +} + +//----- XWindowListener ------------------------------------------------------- + +void SAL_CALL PresenterSlideShowView::windowResized (const awt::WindowEvent&) +{ + ThrowIfDisposed(); + ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); + + Resize(); +} + +void SAL_CALL PresenterSlideShowView::windowMoved (const awt::WindowEvent&) +{ + if ( ! mbIsPaintPending) + mbIsForcedPaintPending = true; +} + +void SAL_CALL PresenterSlideShowView::windowShown (const lang::EventObject&) +{ + Resize(); +} + +void SAL_CALL PresenterSlideShowView::windowHidden (const lang::EventObject&) {} + +//----- XView ----------------------------------------------------------------- + +Reference SAL_CALL PresenterSlideShowView::getResourceId() +{ + return mxViewId; +} + +sal_Bool SAL_CALL PresenterSlideShowView::isAnchorOnly() +{ + return false; +} + +//----- CachablePresenterView ------------------------------------------------- + +void PresenterSlideShowView::ActivatePresenterView() +{ + if (mxSlideShow.is() && ! mbIsViewAdded) + { + impl_addAndConfigureView(); + mbIsViewAdded = true; + } +} + +void PresenterSlideShowView::DeactivatePresenterView() +{ + if (mxSlideShow.is() && mbIsViewAdded) + { + mxSlideShow->removeView(this); + mbIsViewAdded = false; + } +} + + +void PresenterSlideShowView::PaintOuterWindow (const awt::Rectangle& rRepaintBox) +{ + if ( ! mxCanvas.is()) + return; + + if (mpBackground.get() == nullptr) + return; + + const rendering::ViewState aViewState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + PresenterGeometryHelper::CreatePolygon(rRepaintBox, mxCanvas->getDevice())); + + rendering::RenderState aRenderState ( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + nullptr, + Sequence(4), + rendering::CompositeOperation::SOURCE); + + Reference xBackgroundBitmap (mpBackground->GetNormalBitmap()); + if (xBackgroundBitmap.is()) + { + Sequence aTextures (1); + const geometry::IntegerSize2D aBitmapSize(xBackgroundBitmap->getSize()); + aTextures[0] = rendering::Texture ( + geometry::AffineMatrix2D( + aBitmapSize.Width,0,0, + 0,aBitmapSize.Height,0), + 1, + 0, + xBackgroundBitmap, + nullptr, + nullptr, + rendering::StrokeAttributes(), + rendering::TexturingMode::REPEAT, + rendering::TexturingMode::REPEAT); + + if (mxBackgroundPolygon1.is()) + mxCanvas->fillTexturedPolyPolygon( + mxBackgroundPolygon1, + aViewState, + aRenderState, + aTextures); + if (mxBackgroundPolygon2.is()) + mxCanvas->fillTexturedPolyPolygon( + mxBackgroundPolygon2, + aViewState, + aRenderState, + aTextures); + } + else + { + PresenterCanvasHelper::SetDeviceColor(aRenderState, mpBackground->maReplacementColor); + + if (mxBackgroundPolygon1.is()) + mxCanvas->fillPolyPolygon(mxBackgroundPolygon1, aViewState, aRenderState); + if (mxBackgroundPolygon2.is()) + mxCanvas->fillPolyPolygon(mxBackgroundPolygon2, aViewState, aRenderState); + } +} + +void PresenterSlideShowView::PaintEndSlide (const awt::Rectangle& rRepaintBox) +{ + if ( ! mxCanvas.is()) + return; + + const rendering::ViewState aViewState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + PresenterGeometryHelper::CreatePolygon(rRepaintBox, mxCanvas->getDevice())); + + rendering::RenderState aRenderState ( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + nullptr, + Sequence(4), + rendering::CompositeOperation::SOURCE); + PresenterCanvasHelper::SetDeviceColor(aRenderState, util::Color(0x00000000)); + mxCanvas->fillPolyPolygon( + PresenterGeometryHelper::CreatePolygon(mxViewWindow->getPosSize(), mxCanvas->getDevice()), + aViewState, + aRenderState); + + do + { + if (mpPresenterController.get() == nullptr) + break; + std::shared_ptr pTheme (mpPresenterController->GetTheme()); + if (pTheme == nullptr) + break; + + const OUString sViewStyle (pTheme->GetStyleName(mxViewId->getResourceURL())); + PresenterTheme::SharedFontDescriptor pFont (pTheme->GetFont(sViewStyle)); + if (pFont.get() == nullptr) + break; + + /// this is responsible of the " presentation exit " text inside the slide windows + PresenterCanvasHelper::SetDeviceColor(aRenderState, util::Color(0x00ffffff)); + aRenderState.AffineTransform.m02 = 20; + aRenderState.AffineTransform.m12 = 40; + const rendering::StringContext aContext ( + msClickToExitPresentationText, 0, msClickToExitPresentationText.getLength()); + pFont->PrepareFont(mxCanvas); + const Reference xLayout ( + pFont->mxFont->createTextLayout(aContext,rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0)); + mxCanvas->drawTextLayout( + xLayout, + aViewState, + aRenderState); + } + while (false); + + // Finally, in double buffered environments, request the changes to be + // made visible. + Reference xSpriteCanvas (mxCanvas, UNO_QUERY); + if (xSpriteCanvas.is()) + xSpriteCanvas->updateScreen(true); +} + +void PresenterSlideShowView::PaintInnerWindow (const awt::PaintEvent& rEvent) +{ + // Forward window paint to listeners. + awt::PaintEvent aEvent (rEvent); + aEvent.Source = static_cast(this); + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + { + pIterator->notifyEach(&awt::XPaintListener::windowPaint, aEvent); + } + + /** The slide show relies on the back buffer of the canvas not being + modified. With a shared canvas there are times when that can not be + guaranteed. + */ + if (mbIsForcedPaintPending && mxSlideShow.is() && mbIsViewAdded) + { + mxSlideShow->removeView(this); + impl_addAndConfigureView(); + } + + // Finally, in double buffered environments, request the changes to be + // made visible. + Reference xSpriteCanvas (mxCanvas, UNO_QUERY); + if (xSpriteCanvas.is()) + xSpriteCanvas->updateScreen(true); +} + +Reference PresenterSlideShowView::CreateViewWindow ( + const Reference& rxParentWindow) const +{ + Reference xViewWindow; + try + { + Reference xFactory (mxComponentContext->getServiceManager()); + if ( ! xFactory.is()) + return xViewWindow; + + Reference xToolkit = awt::Toolkit::create(mxComponentContext); + awt::WindowDescriptor aWindowDescriptor ( + awt::WindowClass_CONTAINER, + OUString(), + Reference(rxParentWindow,UNO_QUERY_THROW), + -1, // parent index not available + awt::Rectangle(0,0,10,10), + awt::WindowAttribute::SIZEABLE + | awt::WindowAttribute::MOVEABLE + | awt::WindowAttribute::NODECORATION); + xViewWindow.set( xToolkit->createWindow(aWindowDescriptor),UNO_QUERY_THROW); + + // Make the background transparent. The slide show paints its own background. + Reference xPeer (xViewWindow, UNO_QUERY_THROW); + xPeer->setBackground(0xff000000); + + xViewWindow->setVisible(true); + } + catch (RuntimeException&) + { + } + return xViewWindow; +} + +Reference PresenterSlideShowView::CreateViewCanvas ( + const Reference& rxViewWindow) const +{ + // Create a canvas for the view window. + return mxPresenterHelper->createSharedCanvas( + Reference(mxTopPane->getCanvas(), UNO_QUERY), + mxTopPane->getWindow(), + mxTopPane->getCanvas(), + mxTopPane->getWindow(), + rxViewWindow); +} + +void PresenterSlideShowView::Resize() +{ + if ( ! mxWindow.is() || ! mxViewWindow.is()) + return; + + const awt::Rectangle aWindowBox (mxWindow->getPosSize()); + awt::Rectangle aViewWindowBox; + if (aWindowBox.Height > 0) + { + const double nWindowAspectRatio ( + double(aWindowBox.Width) / double(aWindowBox.Height)); + if (nWindowAspectRatio > mnPageAspectRatio) + { + // Slides will be painted with the full parent window height. + aViewWindowBox.Width = sal_Int32(aWindowBox.Height * mnPageAspectRatio + 0.5); + aViewWindowBox.Height = aWindowBox.Height; + aViewWindowBox.X = (aWindowBox.Width - aViewWindowBox.Width) / 2; + aViewWindowBox.Y = 0; + } + else + { + // Slides will be painted with the full parent window width. + aViewWindowBox.Width = aWindowBox.Width; + aViewWindowBox.Height = sal_Int32(aWindowBox.Width / mnPageAspectRatio + 0.5); + aViewWindowBox.X = 0; + aViewWindowBox.Y = (aWindowBox.Height - aViewWindowBox.Height) / 2; + } + mxViewWindow->setPosSize( + aViewWindowBox.X, + aViewWindowBox.Y, + aViewWindowBox.Width, + aViewWindowBox.Height, + awt::PosSize::POSSIZE); + } + + // Clear the background polygon so that on the next paint it is created + // for the new size. + CreateBackgroundPolygons(); + + // Notify listeners that the transformation that maps the view into the + // window has changed. + lang::EventObject aEvent (static_cast(this)); + ::cppu::OInterfaceContainerHelper* pIterator + = maBroadcaster.getContainer(cppu::UnoType::get()); + if (pIterator != nullptr) + { + pIterator->notifyEach(&util::XModifyListener::modified, aEvent); + } + + // Due to constant aspect ratio resizing may lead a preview that changes + // its position but not its size. This invalidates the back buffer and + // we have to enforce a complete repaint. + if ( ! mbIsPaintPending) + mbIsForcedPaintPending = true; +} + +void PresenterSlideShowView::CreateBackgroundPolygons() +{ + const awt::Rectangle aWindowBox (mxWindow->getPosSize()); + const awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize()); + if (aWindowBox.Height == aViewWindowBox.Height && aWindowBox.Width == aViewWindowBox.Width) + { + mxBackgroundPolygon1 = nullptr; + mxBackgroundPolygon2 = nullptr; + } + else if (aWindowBox.Height == aViewWindowBox.Height) + { + // Paint two boxes to the left and right of the view window. + mxBackgroundPolygon1 = PresenterGeometryHelper::CreatePolygon( + awt::Rectangle( + 0, + 0, + aViewWindowBox.X, + aWindowBox.Height), + mxCanvas->getDevice()); + mxBackgroundPolygon2 = PresenterGeometryHelper::CreatePolygon( + awt::Rectangle( + aViewWindowBox.X + aViewWindowBox.Width, + 0, + aWindowBox.Width - aViewWindowBox.X - aViewWindowBox.Width, + aWindowBox.Height), + mxCanvas->getDevice()); + } + else + { + // Paint two boxes above and below the view window. + mxBackgroundPolygon1 = PresenterGeometryHelper::CreatePolygon( + awt::Rectangle( + 0, + 0, + aWindowBox.Width, + aViewWindowBox.Y), + mxCanvas->getDevice()); + mxBackgroundPolygon2 = PresenterGeometryHelper::CreatePolygon( + awt::Rectangle( + 0, + aViewWindowBox.Y + aViewWindowBox.Height, + aWindowBox.Width, + aWindowBox.Height - aViewWindowBox.Y - aViewWindowBox.Height), + mxCanvas->getDevice()); + } +} + +void PresenterSlideShowView::ThrowIfDisposed() +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + throw lang::DisposedException ( + "PresenterSlideShowView object has already been disposed", + static_cast(this)); + } +} + +void PresenterSlideShowView::impl_addAndConfigureView() +{ + Reference xView (this); + mxSlideShow->addView(xView); + // Prevent embedded sounds being played twice at the same time by + // disabling sound for the new slide show view. + beans::PropertyValue aProperty; + aProperty.Name = "IsSoundEnabled"; + Sequence aValues (2); + aValues[0] <<= xView; + aValues[1] <<= false; + aProperty.Value <<= aValues; + mxSlideShow->setProperty(aProperty); +} + +} // end of namespace ::sd::presenter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3