summaryrefslogtreecommitdiffstats
path: root/sdext/source/presenter/PresenterNotesView.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sdext/source/presenter/PresenterNotesView.cxx661
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: */