Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / sdext / source / presenter / PresenterNotesView.cxx
blob3413d4349dfac5421df22449499e9371785d1b50
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <vcl/svapp.hxx>
20 #include <vcl/settings.hxx>
21 #include "PresenterNotesView.hxx"
22 #include "PresenterButton.hxx"
23 #include "PresenterCanvasHelper.hxx"
24 #include "PresenterGeometryHelper.hxx"
25 #include "PresenterPaintManager.hxx"
26 #include "PresenterScrollBar.hxx"
27 #include "PresenterTextView.hxx"
28 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
29 #include <com/sun/star/awt/Key.hpp>
30 #include <com/sun/star/awt/KeyModifier.hpp>
31 #include <com/sun/star/awt/PosSize.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
34 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
35 #include <com/sun/star/drawing/framework/XPane.hpp>
36 #include <com/sun/star/lang/XServiceName.hpp>
37 #include <com/sun/star/presentation/XPresentationPage.hpp>
38 #include <com/sun/star/rendering/CompositeOperation.hpp>
39 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
40 #include <com/sun/star/text/XTextRange.hpp>
41 #include <com/sun/star/util/XChangesBatch.hpp>
42 #include <com/sun/star/container/XChild.hpp>
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::drawing::framework;
48 static const sal_Int32 gnSpaceBelowSeparator (10);
49 static const sal_Int32 gnSpaceAboveSeparator (10);
50 static const double gnLineScrollFactor (1.2);
52 namespace sdext { namespace presenter {
54 //===== PresenterNotesView ====================================================
56 PresenterNotesView::PresenterNotesView (
57 const Reference<XComponentContext>& rxComponentContext,
58 const Reference<XResourceId>& rxViewId,
59 const Reference<frame::XController>& rxController,
60 const ::rtl::Reference<PresenterController>& rpPresenterController)
61 : PresenterNotesViewInterfaceBase(m_aMutex),
62 mxViewId(rxViewId),
63 mpPresenterController(rpPresenterController),
64 mxCanvas(),
65 mxCurrentNotesPage(),
66 mpScrollBar(),
67 mxToolBarWindow(),
68 mxToolBarCanvas(),
69 mpToolBar(),
70 mpCloseButton(),
71 maSeparatorColor(0xffffff),
72 mnSeparatorYLocation(0),
73 maTextBoundingBox(),
74 mpBackground(),
75 mnTop(0),
76 mpFont(),
77 mpTextView()
79 try
81 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
82 Reference<XConfigurationController> xCC (xCM->getConfigurationController(), UNO_QUERY_THROW);
83 Reference<XPane> xPane (xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
85 mxParentWindow = xPane->getWindow();
86 mxCanvas = xPane->getCanvas();
87 mpTextView.reset(new PresenterTextView(
88 rxComponentContext,
89 mxCanvas,
90 mpPresenterController->GetPaintManager()->GetInvalidator(mxParentWindow)));
92 const OUString sResourceURL (mxViewId->getResourceURL());
93 mpFont.reset(new PresenterTheme::FontDescriptor(
94 rpPresenterController->GetViewFont(sResourceURL)));
95 maSeparatorColor = mpFont->mnColor;
96 mpTextView->SetFont(mpFont);
98 CreateToolBar(rxComponentContext, rpPresenterController);
100 mpCloseButton = PresenterButton::Create(
101 rxComponentContext,
102 mpPresenterController,
103 mpPresenterController->GetTheme(),
104 mxParentWindow,
105 mxCanvas,
106 "NotesViewCloser");
108 if (mxParentWindow.is())
110 mxParentWindow->addWindowListener(this);
111 mxParentWindow->addPaintListener(this);
112 mxParentWindow->addKeyListener(this);
113 mxParentWindow->setVisible(true);
116 mpScrollBar = new PresenterVerticalScrollBar(
117 rxComponentContext,
118 mxParentWindow,
119 mpPresenterController->GetPaintManager(),
120 [this](double f) { return this->SetTop(f); });
121 mpScrollBar->SetBackground(
122 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()));
124 mpScrollBar->SetCanvas(mxCanvas);
126 Layout();
128 catch (RuntimeException&)
130 PresenterNotesView::disposing();
131 throw;
135 PresenterNotesView::~PresenterNotesView()
139 void SAL_CALL PresenterNotesView::disposing()
141 if (mxParentWindow.is())
143 mxParentWindow->removeWindowListener(this);
144 mxParentWindow->removePaintListener(this);
145 mxParentWindow->removeKeyListener(this);
146 mxParentWindow = nullptr;
149 // Dispose tool bar.
151 Reference<XComponent> xComponent (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY);
152 mpToolBar = nullptr;
153 if (xComponent.is())
154 xComponent->dispose();
157 Reference<XComponent> xComponent (mxToolBarCanvas, UNO_QUERY);
158 mxToolBarCanvas = nullptr;
159 if (xComponent.is())
160 xComponent->dispose();
163 Reference<XComponent> xComponent (mxToolBarWindow, UNO_QUERY);
164 mxToolBarWindow = nullptr;
165 if (xComponent.is())
166 xComponent->dispose();
169 // Dispose close button
171 Reference<XComponent> xComponent (static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY);
172 mpCloseButton = nullptr;
173 if (xComponent.is())
174 xComponent->dispose();
177 // Create the tool bar.
179 mpScrollBar = nullptr;
181 mxViewId = nullptr;
184 void PresenterNotesView::CreateToolBar (
185 const css::uno::Reference<css::uno::XComponentContext>& rxContext,
186 const ::rtl::Reference<PresenterController>& rpPresenterController)
188 if (rpPresenterController.get() == nullptr)
189 return;
191 Reference<drawing::XPresenterHelper> xPresenterHelper (
192 rpPresenterController->GetPresenterHelper());
193 if ( ! xPresenterHelper.is())
194 return;
196 // Create a new window as container of the tool bar.
197 mxToolBarWindow = xPresenterHelper->createWindow(
198 mxParentWindow,
199 false,
200 true,
201 false,
202 false);
203 mxToolBarCanvas = xPresenterHelper->createSharedCanvas (
204 Reference<rendering::XSpriteCanvas>(mxCanvas, UNO_QUERY),
205 mxParentWindow,
206 mxCanvas,
207 mxParentWindow,
208 mxToolBarWindow);
210 // Create the tool bar.
211 mpToolBar = new PresenterToolBar(
212 rxContext,
213 mxToolBarWindow,
214 mxToolBarCanvas,
215 rpPresenterController,
216 PresenterToolBar::Left);
217 mpToolBar->Initialize(
218 "PresenterScreenSettings/ToolBars/NotesToolBar");
221 void PresenterNotesView::SetSlide (const Reference<drawing::XDrawPage>& rxNotesPage)
223 static const OUString sNotesShapeName (
224 "com.sun.star.presentation.NotesShape");
225 static const OUString sTextShapeName (
226 "com.sun.star.drawing.TextShape");
228 Reference<container::XIndexAccess> xIndexAccess (rxNotesPage, UNO_QUERY);
229 if (xIndexAccess.is())
231 // Iterate over all shapes and find the one that holds the text.
232 sal_Int32 nCount (xIndexAccess->getCount());
233 for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
236 Reference<lang::XServiceName> xServiceName (
237 xIndexAccess->getByIndex(nIndex), UNO_QUERY);
238 if (xServiceName.is()
239 && xServiceName->getServiceName() == sNotesShapeName)
242 else
244 Reference<drawing::XShapeDescriptor> xShapeDescriptor (
245 xIndexAccess->getByIndex(nIndex), UNO_QUERY);
246 if (xShapeDescriptor.is())
248 OUString sType (xShapeDescriptor->getShapeType());
249 if (sType == sNotesShapeName || sType == sTextShapeName)
251 Reference<text::XTextRange> xText (
252 xIndexAccess->getByIndex(nIndex), UNO_QUERY);
253 if (xText.is())
255 mpTextView->SetText(Reference<text::XText>(xText, UNO_QUERY));
262 Layout();
264 if (mpScrollBar.get() != nullptr)
266 mpScrollBar->SetThumbPosition(0, false);
267 UpdateScrollBar();
270 Invalidate();
274 //----- lang::XEventListener -------------------------------------------------
276 void SAL_CALL PresenterNotesView::disposing (const lang::EventObject& rEventObject)
278 if (rEventObject.Source == mxParentWindow)
279 mxParentWindow = nullptr;
282 //----- XWindowListener -------------------------------------------------------
284 void SAL_CALL PresenterNotesView::windowResized (const awt::WindowEvent&)
286 Layout();
289 void SAL_CALL PresenterNotesView::windowMoved (const awt::WindowEvent&) {}
291 void SAL_CALL PresenterNotesView::windowShown (const lang::EventObject&) {}
293 void SAL_CALL PresenterNotesView::windowHidden (const lang::EventObject&) {}
295 //----- XPaintListener --------------------------------------------------------
297 void SAL_CALL PresenterNotesView::windowPaint (const awt::PaintEvent& rEvent)
299 if (rBHelper.bDisposed || rBHelper.bInDispose)
301 throw lang::DisposedException (
302 "PresenterNotesView object has already been disposed",
303 static_cast<uno::XWeak*>(this));
306 if ( ! mbIsPresenterViewActive)
307 return;
309 ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
310 Paint(rEvent.UpdateRect);
313 //----- XResourceId -----------------------------------------------------------
315 Reference<XResourceId> SAL_CALL PresenterNotesView::getResourceId()
317 return mxViewId;
320 sal_Bool SAL_CALL PresenterNotesView::isAnchorOnly()
322 return false;
325 //----- XDrawView -------------------------------------------------------------
327 void SAL_CALL PresenterNotesView::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
329 // Get the associated notes page.
330 mxCurrentNotesPage = nullptr;
333 Reference<presentation::XPresentationPage> xPresentationPage(rxSlide, UNO_QUERY);
334 if (xPresentationPage.is())
335 mxCurrentNotesPage = xPresentationPage->getNotesPage();
337 catch (RuntimeException&)
341 SetSlide(mxCurrentNotesPage);
344 Reference<drawing::XDrawPage> SAL_CALL PresenterNotesView::getCurrentPage()
346 return nullptr;
349 //----- XKeyListener ----------------------------------------------------------
351 void SAL_CALL PresenterNotesView::keyPressed (const awt::KeyEvent& rEvent)
353 switch (rEvent.KeyCode)
355 case awt::Key::A:
356 Scroll(-gnLineScrollFactor * mpFont->mnSize);
357 break;
359 case awt::Key::Y:
360 case awt::Key::Z:
361 Scroll(+gnLineScrollFactor * mpFont->mnSize);
362 break;
364 case awt::Key::S:
365 ChangeFontSize(-1);
366 break;
368 case awt::Key::G:
369 ChangeFontSize(+1);
370 break;
372 case awt::Key::H:
373 if (mpTextView)
374 mpTextView->MoveCaret(
376 (rEvent.Modifiers == awt::KeyModifier::SHIFT)
377 ? css::accessibility::AccessibleTextType::CHARACTER
378 : css::accessibility::AccessibleTextType::WORD);
379 break;
381 case awt::Key::L:
382 if (mpTextView)
383 mpTextView->MoveCaret(
385 (rEvent.Modifiers == awt::KeyModifier::SHIFT)
386 ? css::accessibility::AccessibleTextType::CHARACTER
387 : css::accessibility::AccessibleTextType::WORD);
388 break;
392 void SAL_CALL PresenterNotesView::keyReleased (const awt::KeyEvent&) {}
395 void PresenterNotesView::Layout()
397 if ( ! mxParentWindow.is())
398 return;
399 awt::Rectangle aWindowBox (mxParentWindow->getPosSize());
400 geometry::RealRectangle2D aNewTextBoundingBox (0,0,aWindowBox.Width, aWindowBox.Height);
401 // Size the tool bar and the horizontal separator above it.
402 if (mxToolBarWindow.is())
404 const geometry::RealSize2D aToolBarSize (mpToolBar->GetMinimalSize());
405 const sal_Int32 nToolBarHeight = sal_Int32(aToolBarSize.Height + 0.5);
406 mxToolBarWindow->setPosSize(0, aWindowBox.Height - nToolBarHeight,
407 sal_Int32(aToolBarSize.Width + 0.5), nToolBarHeight,
408 awt::PosSize::POSSIZE);
409 aNewTextBoundingBox.Y2 -= nToolBarHeight;
410 mnSeparatorYLocation = aWindowBox.Height - nToolBarHeight - gnSpaceBelowSeparator;
411 aNewTextBoundingBox.Y2 = mnSeparatorYLocation - gnSpaceAboveSeparator;
412 // Place the close button.
413 if (mpCloseButton.get() != nullptr)
414 mpCloseButton->SetCenter(geometry::RealPoint2D(
415 (aWindowBox.Width + aToolBarSize.Width) / 2,
416 aWindowBox.Height - aToolBarSize.Height/2));
418 // Check whether the vertical scroll bar is necessary.
419 if (mpScrollBar.get() != nullptr)
421 bool bShowVerticalScrollbar (false);
424 const double nTextBoxHeight (aNewTextBoundingBox.Y2 - aNewTextBoundingBox.Y1);
425 const double nHeight (mpTextView->GetTotalTextHeight());
426 if (nHeight > nTextBoxHeight)
428 bShowVerticalScrollbar = true;
429 if(!AllSettings::GetLayoutRTL())
430 aNewTextBoundingBox.X2 -= mpScrollBar->GetSize();
431 else
432 aNewTextBoundingBox.X1 += mpScrollBar->GetSize();
434 mpScrollBar->SetTotalSize(nHeight);
436 catch(beans::UnknownPropertyException&)
438 OSL_ASSERT(false);
440 if(AllSettings::GetLayoutRTL())
442 mpScrollBar->SetVisible(bShowVerticalScrollbar);
443 mpScrollBar->SetPosSize(
444 geometry::RealRectangle2D(
445 aNewTextBoundingBox.X1 - mpScrollBar->GetSize(),
446 aNewTextBoundingBox.Y1,
447 aNewTextBoundingBox.X1,
448 aNewTextBoundingBox.Y2));
449 if( ! bShowVerticalScrollbar)
450 mpScrollBar->SetThumbPosition(0, false);
451 UpdateScrollBar();
453 else
455 mpScrollBar->SetVisible(bShowVerticalScrollbar);
456 mpScrollBar->SetPosSize(
457 geometry::RealRectangle2D(
458 aWindowBox.Width - mpScrollBar->GetSize(),
459 aNewTextBoundingBox.Y1,
460 aNewTextBoundingBox.X2 + mpScrollBar->GetSize(),
461 aNewTextBoundingBox.Y2));
462 if( ! bShowVerticalScrollbar)
463 mpScrollBar->SetThumbPosition(0, false);
464 UpdateScrollBar();
467 // Has the text area has changed it position or size?
468 if (aNewTextBoundingBox.X1 != maTextBoundingBox.X1
469 || aNewTextBoundingBox.Y1 != maTextBoundingBox.Y1
470 || aNewTextBoundingBox.X2 != maTextBoundingBox.X2
471 || aNewTextBoundingBox.Y2 != maTextBoundingBox.Y2)
473 maTextBoundingBox = aNewTextBoundingBox;
474 mpTextView->SetLocation(
475 geometry::RealPoint2D(
476 aNewTextBoundingBox.X1,
477 aNewTextBoundingBox.Y1));
478 mpTextView->SetSize(
479 geometry::RealSize2D(
480 aNewTextBoundingBox.X2 - aNewTextBoundingBox.X1,
481 aNewTextBoundingBox.Y2 - aNewTextBoundingBox.Y1));
485 void PresenterNotesView::Paint (const awt::Rectangle& rUpdateBox)
487 if ( ! mxParentWindow.is())
488 return;
489 if ( ! mxCanvas.is())
490 return;
492 if (mpBackground.get() == nullptr)
493 mpBackground = mpPresenterController->GetViewBackground(mxViewId->getResourceURL());
495 if (rUpdateBox.Y < maTextBoundingBox.Y2
496 && rUpdateBox.X < maTextBoundingBox.X2)
498 PaintText(rUpdateBox);
501 mpTextView->Paint(rUpdateBox);
503 if (rUpdateBox.Y + rUpdateBox.Height > maTextBoundingBox.Y2)
505 PaintToolBar(rUpdateBox);
509 void PresenterNotesView::PaintToolBar (const awt::Rectangle& rUpdateBox)
511 awt::Rectangle aWindowBox (mxParentWindow->getPosSize());
513 rendering::ViewState aViewState (
514 geometry::AffineMatrix2D(1,0,0, 0,1,0),
515 nullptr);
516 rendering::RenderState aRenderState(
517 geometry::AffineMatrix2D(1,0,0, 0,1,0),
518 nullptr,
519 Sequence<double>(4),
520 rendering::CompositeOperation::SOURCE);
522 if (mpBackground.get() != nullptr)
524 // Paint the background.
525 mpPresenterController->GetCanvasHelper()->Paint(
526 mpBackground,
527 mxCanvas,
528 rUpdateBox,
529 awt::Rectangle(0,sal_Int32(maTextBoundingBox.Y2),aWindowBox.Width,aWindowBox.Height),
530 awt::Rectangle());
533 // Paint the horizontal separator.
534 OSL_ASSERT(mxViewId.is());
535 PresenterCanvasHelper::SetDeviceColor(aRenderState, maSeparatorColor);
537 mxCanvas->drawLine(
538 geometry::RealPoint2D(0,mnSeparatorYLocation),
539 geometry::RealPoint2D(aWindowBox.Width,mnSeparatorYLocation),
540 aViewState,
541 aRenderState);
544 void PresenterNotesView::PaintText (const awt::Rectangle& rUpdateBox)
546 const awt::Rectangle aBox (PresenterGeometryHelper::Intersection(rUpdateBox,
547 PresenterGeometryHelper::ConvertRectangle(maTextBoundingBox)));
549 if (aBox.Width <= 0 || aBox.Height <= 0)
550 return;
552 rendering::ViewState aViewState (
553 geometry::AffineMatrix2D(1,0,0, 0,1,0),
554 PresenterGeometryHelper::CreatePolygon(aBox, mxCanvas->getDevice()));
555 rendering::RenderState aRenderState(
556 geometry::AffineMatrix2D(1,0,0, 0,1,0),
557 nullptr,
558 Sequence<double>(3),
559 rendering::CompositeOperation::SOURCE);
561 if (mpBackground.get() != nullptr)
563 // Paint the background.
564 mpPresenterController->GetCanvasHelper()->Paint(
565 mpBackground,
566 mxCanvas,
567 rUpdateBox,
568 aBox,
569 awt::Rectangle());
572 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
573 if (xSpriteCanvas.is())
574 xSpriteCanvas->updateScreen(false);
577 void PresenterNotesView::Invalidate()
579 mpPresenterController->GetPaintManager()->Invalidate(
580 mxParentWindow,
581 PresenterGeometryHelper::ConvertRectangle(maTextBoundingBox));
584 void PresenterNotesView::Scroll (const double rnDistance)
588 mnTop += rnDistance;
589 mpTextView->SetOffset(0, mnTop);
591 UpdateScrollBar();
592 Invalidate();
594 catch (beans::UnknownPropertyException&)
598 void PresenterNotesView::SetTop (const double nTop)
602 mnTop = nTop;
603 mpTextView->SetOffset(0, mnTop);
605 UpdateScrollBar();
606 Invalidate();
608 catch (beans::UnknownPropertyException&)
612 void PresenterNotesView::ChangeFontSize (const sal_Int32 nSizeChange)
614 const sal_Int32 nNewSize (mpFont->mnSize + nSizeChange);
615 if (nNewSize > 5)
617 mpFont->mnSize = nNewSize;
618 mpFont->mxFont = nullptr;
619 mpTextView->SetFont(mpFont);
621 Layout();
622 UpdateScrollBar();
623 Invalidate();
625 // Write the new font size to the configuration to make it persistent.
628 const OUString sStyleName (mpPresenterController->GetTheme()->GetStyleName(
629 mxViewId->getResourceURL()));
630 std::shared_ptr<PresenterConfigurationAccess> pConfiguration (
631 mpPresenterController->GetTheme()->GetNodeForViewStyle(
632 sStyleName));
633 if (pConfiguration.get()==nullptr || ! pConfiguration->IsValid())
634 return;
636 pConfiguration->GoToChild(OUString("Font"));
637 pConfiguration->SetProperty("Size", Any(static_cast<sal_Int32>(nNewSize+0.5)));
638 pConfiguration->CommitChanges();
640 catch (Exception&)
642 OSL_ASSERT(false);
647 const std::shared_ptr<PresenterTextView>& PresenterNotesView::GetTextView() const
649 return mpTextView;
652 void PresenterNotesView::UpdateScrollBar()
654 if (mpScrollBar.get() != nullptr)
658 mpScrollBar->SetTotalSize(mpTextView->GetTotalTextHeight());
660 catch(beans::UnknownPropertyException&)
662 OSL_ASSERT(false);
665 mpScrollBar->SetLineHeight(mpFont->mnSize*1.2);
666 mpScrollBar->SetThumbPosition(mnTop, false);
668 mpScrollBar->SetThumbSize(maTextBoundingBox.Y2 - maTextBoundingBox.Y1);
669 mpScrollBar->CheckValues();
673 } } // end of namespace ::sdext::presenter
675 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */