diff options
Diffstat (limited to 'sdext/source/presenter/PresenterNotesView.cxx')
-rw-r--r-- | sdext/source/presenter/PresenterNotesView.cxx | 661 |
1 files changed, 661 insertions, 0 deletions
diff --git a/sdext/source/presenter/PresenterNotesView.cxx b/sdext/source/presenter/PresenterNotesView.cxx new file mode 100644 index 000000000..c271875fe --- /dev/null +++ b/sdext/source/presenter/PresenterNotesView.cxx @@ -0,0 +1,661 @@ +/* -*- 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 <vcl/settings.hxx> +#include "PresenterNotesView.hxx" +#include "PresenterButton.hxx" +#include "PresenterCanvasHelper.hxx" +#include "PresenterGeometryHelper.hxx" +#include "PresenterPaintManager.hxx" +#include "PresenterScrollBar.hxx" +#include "PresenterTextView.hxx" +#include <com/sun/star/accessibility/AccessibleTextType.hpp> +#include <com/sun/star/awt/Key.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/drawing/framework/XConfigurationController.hpp> +#include <com/sun/star/drawing/framework/XPane.hpp> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/presentation/XPresentationPage.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +static const sal_Int32 gnSpaceBelowSeparator (10); +static const sal_Int32 gnSpaceAboveSeparator (10); +static const double gnLineScrollFactor (1.2); + +namespace sdext::presenter { + +//===== PresenterNotesView ==================================================== + +PresenterNotesView::PresenterNotesView ( + const Reference<XComponentContext>& rxComponentContext, + const Reference<XResourceId>& rxViewId, + const Reference<frame::XController>& rxController, + const ::rtl::Reference<PresenterController>& rpPresenterController) + : PresenterNotesViewInterfaceBase(m_aMutex), + mxViewId(rxViewId), + mpPresenterController(rpPresenterController), + mxCanvas(), + mxCurrentNotesPage(), + mpScrollBar(), + mxToolBarWindow(), + mxToolBarCanvas(), + mpToolBar(), + mpCloseButton(), + maSeparatorColor(0xffffff), + mnSeparatorYLocation(0), + maTextBoundingBox(), + mpBackground(), + mnTop(0), + mpFont(), + mpTextView() +{ + try + { + Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW); + Reference<XConfigurationController> xCC (xCM->getConfigurationController(), UNO_SET_THROW); + Reference<XPane> xPane (xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW); + + mxParentWindow = xPane->getWindow(); + mxCanvas = xPane->getCanvas(); + mpTextView = std::make_shared<PresenterTextView>( + rxComponentContext, + mxCanvas, + mpPresenterController->GetPaintManager()->GetInvalidator(mxParentWindow)); + + const OUString sResourceURL (mxViewId->getResourceURL()); + mpFont = std::make_shared<PresenterTheme::FontDescriptor>( + rpPresenterController->GetViewFont(sResourceURL)); + maSeparatorColor = mpFont->mnColor; + mpTextView->SetFont(mpFont); + + CreateToolBar(rxComponentContext, rpPresenterController); + + mpCloseButton = PresenterButton::Create( + rxComponentContext, + mpPresenterController, + mpPresenterController->GetTheme(), + mxParentWindow, + mxCanvas, + "NotesViewCloser"); + + if (mxParentWindow.is()) + { + mxParentWindow->addWindowListener(this); + mxParentWindow->addPaintListener(this); + mxParentWindow->addKeyListener(this); + mxParentWindow->setVisible(true); + } + + mpScrollBar = new PresenterVerticalScrollBar( + rxComponentContext, + mxParentWindow, + mpPresenterController->GetPaintManager(), + [this](double f) { return this->SetTop(f); }); + mpScrollBar->SetBackground( + mpPresenterController->GetViewBackground(mxViewId->getResourceURL())); + + mpScrollBar->SetCanvas(mxCanvas); + + Layout(); + } + catch (RuntimeException&) + { + PresenterNotesView::disposing(); + throw; + } +} + +PresenterNotesView::~PresenterNotesView() +{ +} + +void SAL_CALL PresenterNotesView::disposing() +{ + if (mxParentWindow.is()) + { + mxParentWindow->removeWindowListener(this); + mxParentWindow->removePaintListener(this); + mxParentWindow->removeKeyListener(this); + mxParentWindow = nullptr; + } + + // Dispose tool bar. + { + Reference<XComponent> xComponent (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY); + mpToolBar = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + { + Reference<XComponent> xComponent (mxToolBarCanvas, UNO_QUERY); + mxToolBarCanvas = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + { + Reference<XComponent> xComponent = mxToolBarWindow; + mxToolBarWindow = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + + // Dispose close button + { + Reference<XComponent> xComponent (static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY); + mpCloseButton = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + + // Create the tool bar. + + mpScrollBar = nullptr; + + mxViewId = nullptr; +} + +void PresenterNotesView::CreateToolBar ( + const css::uno::Reference<css::uno::XComponentContext>& rxContext, + const ::rtl::Reference<PresenterController>& rpPresenterController) +{ + if (rpPresenterController.get() == nullptr) + return; + + Reference<drawing::XPresenterHelper> xPresenterHelper ( + rpPresenterController->GetPresenterHelper()); + if ( ! xPresenterHelper.is()) + return; + + // Create a new window as container of the tool bar. + mxToolBarWindow = xPresenterHelper->createWindow( + mxParentWindow, + false, + true, + false, + false); + mxToolBarCanvas = xPresenterHelper->createSharedCanvas ( + Reference<rendering::XSpriteCanvas>(mxCanvas, UNO_QUERY), + mxParentWindow, + mxCanvas, + mxParentWindow, + mxToolBarWindow); + + // Create the tool bar. + mpToolBar = new PresenterToolBar( + rxContext, + mxToolBarWindow, + mxToolBarCanvas, + rpPresenterController, + PresenterToolBar::Left); + mpToolBar->Initialize( + "PresenterScreenSettings/ToolBars/NotesToolBar"); +} + +void PresenterNotesView::SetSlide (const Reference<drawing::XDrawPage>& rxNotesPage) +{ + static const OUString sNotesShapeName ( + "com.sun.star.presentation.NotesShape"); + static const OUString sTextShapeName ( + "com.sun.star.drawing.TextShape"); + + if (!rxNotesPage.is()) + return; + + // Iterate over all shapes and find the one that holds the text. + sal_Int32 nCount (rxNotesPage->getCount()); + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + + Reference<lang::XServiceName> xServiceName ( + rxNotesPage->getByIndex(nIndex), UNO_QUERY); + if (xServiceName.is() + && xServiceName->getServiceName() == sNotesShapeName) + { + } + else + { + Reference<drawing::XShapeDescriptor> xShapeDescriptor ( + rxNotesPage->getByIndex(nIndex), UNO_QUERY); + if (xShapeDescriptor.is()) + { + OUString sType (xShapeDescriptor->getShapeType()); + if (sType == sNotesShapeName || sType == sTextShapeName) + { + Reference<text::XTextRange> xText ( + rxNotesPage->getByIndex(nIndex), UNO_QUERY); + if (xText.is()) + { + mpTextView->SetText(Reference<text::XText>(xText, UNO_QUERY)); + } + } + } + } + } + + Layout(); + + if (mpScrollBar.get() != nullptr) + { + mpScrollBar->SetThumbPosition(0, false); + UpdateScrollBar(); + } + + Invalidate(); +} + +//----- lang::XEventListener ------------------------------------------------- + +void SAL_CALL PresenterNotesView::disposing (const lang::EventObject& rEventObject) +{ + if (rEventObject.Source == mxParentWindow) + mxParentWindow = nullptr; +} + +//----- XWindowListener ------------------------------------------------------- + +void SAL_CALL PresenterNotesView::windowResized (const awt::WindowEvent&) +{ + Layout(); +} + +void SAL_CALL PresenterNotesView::windowMoved (const awt::WindowEvent&) {} + +void SAL_CALL PresenterNotesView::windowShown (const lang::EventObject&) {} + +void SAL_CALL PresenterNotesView::windowHidden (const lang::EventObject&) {} + +//----- XPaintListener -------------------------------------------------------- + +void SAL_CALL PresenterNotesView::windowPaint (const awt::PaintEvent& rEvent) +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + throw lang::DisposedException ( + "PresenterNotesView object has already been disposed", + static_cast<uno::XWeak*>(this)); + } + + if ( ! mbIsPresenterViewActive) + return; + + ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex()); + Paint(rEvent.UpdateRect); +} + +//----- XResourceId ----------------------------------------------------------- + +Reference<XResourceId> SAL_CALL PresenterNotesView::getResourceId() +{ + return mxViewId; +} + +sal_Bool SAL_CALL PresenterNotesView::isAnchorOnly() +{ + return false; +} + +//----- XDrawView ------------------------------------------------------------- + +void SAL_CALL PresenterNotesView::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide) +{ + // Get the associated notes page. + mxCurrentNotesPage = nullptr; + try + { + Reference<presentation::XPresentationPage> xPresentationPage(rxSlide, UNO_QUERY); + if (xPresentationPage.is()) + mxCurrentNotesPage = xPresentationPage->getNotesPage(); + } + catch (RuntimeException&) + { + } + + SetSlide(mxCurrentNotesPage); +} + +Reference<drawing::XDrawPage> SAL_CALL PresenterNotesView::getCurrentPage() +{ + return nullptr; +} + +//----- XKeyListener ---------------------------------------------------------- + +void SAL_CALL PresenterNotesView::keyPressed (const awt::KeyEvent& rEvent) +{ + switch (rEvent.KeyCode) + { + case awt::Key::A: + Scroll(-gnLineScrollFactor * mpFont->mnSize); + break; + + case awt::Key::Y: + case awt::Key::Z: + Scroll(+gnLineScrollFactor * mpFont->mnSize); + break; + + case awt::Key::S: + ChangeFontSize(-1); + break; + + case awt::Key::G: + ChangeFontSize(+1); + break; + + case awt::Key::H: + if (mpTextView) + mpTextView->MoveCaret( + -1, + (rEvent.Modifiers == awt::KeyModifier::SHIFT) + ? css::accessibility::AccessibleTextType::CHARACTER + : css::accessibility::AccessibleTextType::WORD); + break; + + case awt::Key::L: + if (mpTextView) + mpTextView->MoveCaret( + +1, + (rEvent.Modifiers == awt::KeyModifier::SHIFT) + ? css::accessibility::AccessibleTextType::CHARACTER + : css::accessibility::AccessibleTextType::WORD); + break; + } +} + +void SAL_CALL PresenterNotesView::keyReleased (const awt::KeyEvent&) {} + + +void PresenterNotesView::Layout() +{ + if ( ! mxParentWindow.is()) + return; + awt::Rectangle aWindowBox (mxParentWindow->getPosSize()); + geometry::RealRectangle2D aNewTextBoundingBox (0,0,aWindowBox.Width, aWindowBox.Height); + // Size the tool bar and the horizontal separator above it. + if (mxToolBarWindow.is()) + { + const geometry::RealSize2D aToolBarSize (mpToolBar->GetMinimalSize()); + const sal_Int32 nToolBarHeight = sal_Int32(aToolBarSize.Height + 0.5); + mxToolBarWindow->setPosSize(0, aWindowBox.Height - nToolBarHeight, + sal_Int32(aToolBarSize.Width + 0.5), nToolBarHeight, + awt::PosSize::POSSIZE); + mnSeparatorYLocation = aWindowBox.Height - nToolBarHeight - gnSpaceBelowSeparator; + aNewTextBoundingBox.Y2 = mnSeparatorYLocation - gnSpaceAboveSeparator; + // Place the close button. + if (mpCloseButton.get() != nullptr) + mpCloseButton->SetCenter(geometry::RealPoint2D( + (aWindowBox.Width + aToolBarSize.Width) / 2, + aWindowBox.Height - aToolBarSize.Height/2)); + } + // Check whether the vertical scroll bar is necessary. + if (mpScrollBar.get() != nullptr) + { + bool bShowVerticalScrollbar (false); + try + { + const double nTextBoxHeight (aNewTextBoundingBox.Y2 - aNewTextBoundingBox.Y1); + const double nHeight (mpTextView->GetTotalTextHeight()); + if (nHeight > nTextBoxHeight) + { + bShowVerticalScrollbar = true; + if(!AllSettings::GetLayoutRTL()) + aNewTextBoundingBox.X2 -= mpScrollBar->GetSize(); + else + aNewTextBoundingBox.X1 += mpScrollBar->GetSize(); + } + mpScrollBar->SetTotalSize(nHeight); + } + catch(beans::UnknownPropertyException&) + { + OSL_ASSERT(false); + } + if(AllSettings::GetLayoutRTL()) + { + mpScrollBar->SetVisible(bShowVerticalScrollbar); + mpScrollBar->SetPosSize( + geometry::RealRectangle2D( + aNewTextBoundingBox.X1 - mpScrollBar->GetSize(), + aNewTextBoundingBox.Y1, + aNewTextBoundingBox.X1, + aNewTextBoundingBox.Y2)); + if( ! bShowVerticalScrollbar) + mpScrollBar->SetThumbPosition(0, false); + UpdateScrollBar(); + } + else + { + mpScrollBar->SetVisible(bShowVerticalScrollbar); + mpScrollBar->SetPosSize( + geometry::RealRectangle2D( + aWindowBox.Width - mpScrollBar->GetSize(), + aNewTextBoundingBox.Y1, + aNewTextBoundingBox.X2 + mpScrollBar->GetSize(), + aNewTextBoundingBox.Y2)); + if( ! bShowVerticalScrollbar) + mpScrollBar->SetThumbPosition(0, false); + UpdateScrollBar(); + } + } + // Has the text area has changed it position or size? + if (aNewTextBoundingBox.X1 != maTextBoundingBox.X1 + || aNewTextBoundingBox.Y1 != maTextBoundingBox.Y1 + || aNewTextBoundingBox.X2 != maTextBoundingBox.X2 + || aNewTextBoundingBox.Y2 != maTextBoundingBox.Y2) + { + maTextBoundingBox = aNewTextBoundingBox; + mpTextView->SetLocation( + geometry::RealPoint2D( + aNewTextBoundingBox.X1, + aNewTextBoundingBox.Y1)); + mpTextView->SetSize( + geometry::RealSize2D( + aNewTextBoundingBox.X2 - aNewTextBoundingBox.X1, + aNewTextBoundingBox.Y2 - aNewTextBoundingBox.Y1)); + } +} + +void PresenterNotesView::Paint (const awt::Rectangle& rUpdateBox) +{ + if ( ! mxParentWindow.is()) + return; + if ( ! mxCanvas.is()) + return; + + if (mpBackground.get() == nullptr) + mpBackground = mpPresenterController->GetViewBackground(mxViewId->getResourceURL()); + + if (rUpdateBox.Y < maTextBoundingBox.Y2 + && rUpdateBox.X < maTextBoundingBox.X2) + { + PaintText(rUpdateBox); + } + + mpTextView->Paint(rUpdateBox); + + if (rUpdateBox.Y + rUpdateBox.Height > maTextBoundingBox.Y2) + { + PaintToolBar(rUpdateBox); + } +} + +void PresenterNotesView::PaintToolBar (const awt::Rectangle& rUpdateBox) +{ + awt::Rectangle aWindowBox (mxParentWindow->getPosSize()); + + rendering::ViewState aViewState ( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + nullptr); + rendering::RenderState aRenderState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + nullptr, + Sequence<double>(4), + rendering::CompositeOperation::SOURCE); + + if (mpBackground.get() != nullptr) + { + // Paint the background. + mpPresenterController->GetCanvasHelper()->Paint( + mpBackground, + mxCanvas, + rUpdateBox, + awt::Rectangle(0,sal_Int32(maTextBoundingBox.Y2),aWindowBox.Width,aWindowBox.Height), + awt::Rectangle()); + } + + // Paint the horizontal separator. + OSL_ASSERT(mxViewId.is()); + PresenterCanvasHelper::SetDeviceColor(aRenderState, maSeparatorColor); + + mxCanvas->drawLine( + geometry::RealPoint2D(0,mnSeparatorYLocation), + geometry::RealPoint2D(aWindowBox.Width,mnSeparatorYLocation), + aViewState, + aRenderState); +} + +void PresenterNotesView::PaintText (const awt::Rectangle& rUpdateBox) +{ + const awt::Rectangle aBox (PresenterGeometryHelper::Intersection(rUpdateBox, + PresenterGeometryHelper::ConvertRectangle(maTextBoundingBox))); + + if (aBox.Width <= 0 || aBox.Height <= 0) + return; + + if (mpBackground.get() != nullptr) + { + // Paint the background. + mpPresenterController->GetCanvasHelper()->Paint( + mpBackground, + mxCanvas, + rUpdateBox, + aBox, + awt::Rectangle()); + } + + Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); + if (xSpriteCanvas.is()) + xSpriteCanvas->updateScreen(false); +} + +void PresenterNotesView::Invalidate() +{ + mpPresenterController->GetPaintManager()->Invalidate( + mxParentWindow, + PresenterGeometryHelper::ConvertRectangle(maTextBoundingBox)); +} + +void PresenterNotesView::Scroll (const double rnDistance) +{ + try + { + mnTop += rnDistance; + mpTextView->SetOffset(0, mnTop); + + UpdateScrollBar(); + Invalidate(); + } + catch (beans::UnknownPropertyException&) + {} +} + +void PresenterNotesView::SetTop (const double nTop) +{ + try + { + mnTop = nTop; + mpTextView->SetOffset(0, mnTop); + + UpdateScrollBar(); + Invalidate(); + } + catch (beans::UnknownPropertyException&) + {} +} + +void PresenterNotesView::ChangeFontSize (const sal_Int32 nSizeChange) +{ + const sal_Int32 nNewSize (mpFont->mnSize + nSizeChange); + if (nNewSize <= 5) + return; + + mpFont->mnSize = nNewSize; + mpFont->mxFont = nullptr; + mpTextView->SetFont(mpFont); + + Layout(); + UpdateScrollBar(); + Invalidate(); + + // Write the new font size to the configuration to make it persistent. + try + { + const OUString sStyleName (mpPresenterController->GetTheme()->GetStyleName( + mxViewId->getResourceURL())); + std::shared_ptr<PresenterConfigurationAccess> pConfiguration ( + mpPresenterController->GetTheme()->GetNodeForViewStyle( + sStyleName)); + if (pConfiguration == nullptr || !pConfiguration->IsValid()) + return; + + pConfiguration->GoToChild("Font"); + pConfiguration->SetProperty("Size", Any(static_cast<sal_Int32>(nNewSize+0.5))); + pConfiguration->CommitChanges(); + } + catch (Exception&) + { + OSL_ASSERT(false); + } +} + +const std::shared_ptr<PresenterTextView>& PresenterNotesView::GetTextView() const +{ + return mpTextView; +} + +void PresenterNotesView::UpdateScrollBar() +{ + if (mpScrollBar.get() == nullptr) + return; + + try + { + mpScrollBar->SetTotalSize(mpTextView->GetTotalTextHeight()); + } + catch(beans::UnknownPropertyException&) + { + OSL_ASSERT(false); + } + + mpScrollBar->SetLineHeight(mpFont->mnSize*1.2); + mpScrollBar->SetThumbPosition(mnTop, false); + + mpScrollBar->SetThumbSize(maTextBoundingBox.Y2 - maTextBoundingBox.Y1); + mpScrollBar->CheckValues(); +} + +} // end of namespace ::sdext::presenter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |