Updated core
[LibreOffice.git] / sdext / source / presenter / PresenterNotesView.cxx
blob90450a414d97bde35bb5b809231f59fd47fc56b4
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 "PresenterNotesView.hxx"
21 #include "PresenterButton.hxx"
22 #include "PresenterCanvasHelper.hxx"
23 #include "PresenterGeometryHelper.hxx"
24 #include "PresenterPaintManager.hxx"
25 #include "PresenterScrollBar.hxx"
26 #include "PresenterTextView.hxx"
27 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
28 #include <com/sun/star/awt/Key.hpp>
29 #include <com/sun/star/awt/KeyModifier.hpp>
30 #include <com/sun/star/awt/PosSize.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
33 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
34 #include <com/sun/star/drawing/framework/XPane.hpp>
35 #include <com/sun/star/lang/XServiceName.hpp>
36 #include <com/sun/star/presentation/XPresentationPage.hpp>
37 #include <com/sun/star/rendering/CompositeOperation.hpp>
38 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
39 #include <com/sun/star/text/XTextRange.hpp>
40 #include <com/sun/star/util/XChangesBatch.hpp>
41 #include <com/sun/star/container/XChild.hpp>
42 #include <boost/bind.hpp>
43 #include <set>
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::drawing::framework;
49 static const sal_Int32 gnSpaceBelowSeparator (10);
50 static const sal_Int32 gnSpaceAboveSeparator (10);
51 static const sal_Int32 gnPartHeight (128);
52 /** Maximal size of memory used for bitmaps which show the notes text.
54 static const sal_Int32 gnMaximalCacheSize (8*1024*1024);
55 static const double gnLineScrollFactor (1.2);
57 namespace sdext { namespace presenter {
59 //===== PresenterNotesView ====================================================
61 PresenterNotesView::PresenterNotesView (
62 const Reference<XComponentContext>& rxComponentContext,
63 const Reference<XResourceId>& rxViewId,
64 const Reference<frame::XController>& rxController,
65 const ::rtl::Reference<PresenterController>& rpPresenterController)
66 : PresenterNotesViewInterfaceBase(m_aMutex),
67 mxViewId(rxViewId),
68 mpPresenterController(rpPresenterController),
69 mxCanvas(),
70 mxCurrentNotesPage(),
71 mpScrollBar(),
72 mxToolBarWindow(),
73 mxToolBarCanvas(),
74 mpToolBar(),
75 mpCloseButton(),
76 maSeparatorColor(0xffffff),
77 mnSeparatorYLocation(0),
78 maTextBoundingBox(),
79 mpBackground(),
80 mnTop(0),
81 mpFont(),
82 mpTextView()
84 try
86 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
87 Reference<XConfigurationController> xCC (xCM->getConfigurationController(), UNO_QUERY_THROW);
88 Reference<XPane> xPane (xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
90 mxParentWindow = xPane->getWindow();
91 mxCanvas = xPane->getCanvas();
92 mpTextView.reset(new PresenterTextView(
93 rxComponentContext,
94 mxCanvas,
95 mpPresenterController->GetPaintManager()->GetInvalidator(mxParentWindow)));
97 const OUString sResourceURL (mxViewId->getResourceURL());
98 mpFont.reset(new PresenterTheme::FontDescriptor(
99 rpPresenterController->GetViewFont(sResourceURL)));
100 maSeparatorColor = mpFont->mnColor;
101 mpTextView->SetFont(mpFont);
103 CreateToolBar(rxComponentContext, rpPresenterController);
105 mpCloseButton = PresenterButton::Create(
106 rxComponentContext,
107 mpPresenterController,
108 mpPresenterController->GetTheme(),
109 mxParentWindow,
110 mxCanvas,
111 "NotesViewCloser");
113 if (mxParentWindow.is())
115 mxParentWindow->addWindowListener(this);
116 mxParentWindow->addPaintListener(this);
117 mxParentWindow->addKeyListener(this);
118 mxParentWindow->setVisible(sal_True);
121 mpScrollBar = new PresenterVerticalScrollBar(
122 rxComponentContext,
123 mxParentWindow,
124 mpPresenterController->GetPaintManager(),
125 ::boost::bind(&PresenterNotesView::SetTop, this, _1));
126 mpScrollBar->SetBackground(
127 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()));
129 mpScrollBar->SetCanvas(mxCanvas);
131 Layout();
133 catch (RuntimeException&)
135 PresenterNotesView::disposing();
136 throw;
140 PresenterNotesView::~PresenterNotesView (void)
144 void SAL_CALL PresenterNotesView::disposing (void)
146 if (mxParentWindow.is())
148 mxParentWindow->removeWindowListener(this);
149 mxParentWindow->removePaintListener(this);
150 mxParentWindow->removeKeyListener(this);
151 mxParentWindow = NULL;
154 // Dispose tool bar.
156 Reference<XComponent> xComponent (static_cast<XWeak*>(mpToolBar.get()), UNO_QUERY);
157 mpToolBar = NULL;
158 if (xComponent.is())
159 xComponent->dispose();
162 Reference<XComponent> xComponent (mxToolBarCanvas, UNO_QUERY);
163 mxToolBarCanvas = NULL;
164 if (xComponent.is())
165 xComponent->dispose();
168 Reference<XComponent> xComponent (mxToolBarWindow, UNO_QUERY);
169 mxToolBarWindow = NULL;
170 if (xComponent.is())
171 xComponent->dispose();
174 // Dispose close button
176 Reference<XComponent> xComponent (static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY);
177 mpCloseButton = NULL;
178 if (xComponent.is())
179 xComponent->dispose();
182 // Create the tool bar.
184 mpScrollBar = NULL;
186 mxViewId = NULL;
189 void PresenterNotesView::CreateToolBar (
190 const css::uno::Reference<css::uno::XComponentContext>& rxContext,
191 const ::rtl::Reference<PresenterController>& rpPresenterController)
193 if (rpPresenterController.get() == NULL)
194 return;
196 Reference<drawing::XPresenterHelper> xPresenterHelper (
197 rpPresenterController->GetPresenterHelper());
198 if ( ! xPresenterHelper.is())
199 return;
201 // Create a new window as container of the tool bar.
202 mxToolBarWindow = xPresenterHelper->createWindow(
203 mxParentWindow,
204 sal_False,
205 sal_True,
206 sal_False,
207 sal_False);
208 mxToolBarCanvas = xPresenterHelper->createSharedCanvas (
209 Reference<rendering::XSpriteCanvas>(mxCanvas, UNO_QUERY),
210 mxParentWindow,
211 mxCanvas,
212 mxParentWindow,
213 mxToolBarWindow);
215 // Create the tool bar.
216 mpToolBar = new PresenterToolBar(
217 rxContext,
218 mxToolBarWindow,
219 mxToolBarCanvas,
220 rpPresenterController,
221 PresenterToolBar::Left);
222 mpToolBar->Initialize(
223 "PresenterScreenSettings/ToolBars/NotesToolBar");
226 void PresenterNotesView::SetSlide (const Reference<drawing::XDrawPage>& rxNotesPage)
228 static const OUString sNotesShapeName (
229 "com.sun.star.presentation.NotesShape");
230 static const OUString sTextShapeName (
231 "com.sun.star.drawing.TextShape");
233 Reference<container::XIndexAccess> xIndexAccess (rxNotesPage, UNO_QUERY);
234 if (xIndexAccess.is())
236 OUString sText;
238 // Iterate over all shapes and find the one that holds the text.
239 sal_Int32 nCount (xIndexAccess->getCount());
240 for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
243 Reference<lang::XServiceName> xServiceName (
244 xIndexAccess->getByIndex(nIndex), UNO_QUERY);
245 if (xServiceName.is()
246 && xServiceName->getServiceName().equals(sNotesShapeName))
248 Reference<text::XTextRange> xText (xServiceName, UNO_QUERY);
249 if (xText.is())
251 sText += xText->getString();
254 else
256 Reference<drawing::XShapeDescriptor> xShapeDescriptor (
257 xIndexAccess->getByIndex(nIndex), UNO_QUERY);
258 if (xShapeDescriptor.is())
260 OUString sType (xShapeDescriptor->getShapeType());
261 if (sType.equals(sNotesShapeName) || sType.equals(sTextShapeName))
263 Reference<text::XTextRange> xText (
264 xIndexAccess->getByIndex(nIndex), UNO_QUERY);
265 if (xText.is())
267 sText += xText->getString();
268 mpTextView->SetText(Reference<text::XText>(xText, UNO_QUERY));
275 Layout();
277 if (mpScrollBar.get() != NULL)
279 mpScrollBar->SetThumbPosition(0, false);
280 UpdateScrollBar();
283 Invalidate();
287 //----- lang::XEventListener -------------------------------------------------
289 void SAL_CALL PresenterNotesView::disposing (const lang::EventObject& rEventObject)
290 throw (RuntimeException)
292 if (rEventObject.Source == mxParentWindow)
293 mxParentWindow = NULL;
296 //----- XWindowListener -------------------------------------------------------
298 void SAL_CALL PresenterNotesView::windowResized (const awt::WindowEvent& rEvent)
299 throw (RuntimeException)
301 (void)rEvent;
302 Layout();
305 void SAL_CALL PresenterNotesView::windowMoved (const awt::WindowEvent& rEvent)
306 throw (RuntimeException)
308 (void)rEvent;
311 void SAL_CALL PresenterNotesView::windowShown (const lang::EventObject& rEvent)
312 throw (RuntimeException)
314 (void)rEvent;
317 void SAL_CALL PresenterNotesView::windowHidden (const lang::EventObject& rEvent)
318 throw (RuntimeException)
320 (void)rEvent;
323 //----- XPaintListener --------------------------------------------------------
325 void SAL_CALL PresenterNotesView::windowPaint (const awt::PaintEvent& rEvent)
326 throw (RuntimeException)
328 ThrowIfDisposed();
330 if ( ! mbIsPresenterViewActive)
331 return;
333 ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
334 Paint(rEvent.UpdateRect);
337 //----- XResourceId -----------------------------------------------------------
339 Reference<XResourceId> SAL_CALL PresenterNotesView::getResourceId (void)
340 throw (RuntimeException)
342 return mxViewId;
345 sal_Bool SAL_CALL PresenterNotesView::isAnchorOnly (void)
346 throw (RuntimeException)
348 return false;
351 //----- XDrawView -------------------------------------------------------------
353 void SAL_CALL PresenterNotesView::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
354 throw (RuntimeException)
356 // Get the associated notes page.
357 mxCurrentNotesPage = NULL;
360 Reference<presentation::XPresentationPage> xPresentationPage(rxSlide, UNO_QUERY);
361 if (xPresentationPage.is())
362 mxCurrentNotesPage = xPresentationPage->getNotesPage();
364 catch (RuntimeException&)
368 SetSlide(mxCurrentNotesPage);
371 Reference<drawing::XDrawPage> SAL_CALL PresenterNotesView::getCurrentPage (void)
372 throw (RuntimeException)
374 return NULL;
377 //----- XKeyListener ----------------------------------------------------------
379 void SAL_CALL PresenterNotesView::keyPressed (const awt::KeyEvent& rEvent)
380 throw (RuntimeException)
382 switch (rEvent.KeyCode)
384 case awt::Key::A:
385 Scroll(-gnLineScrollFactor * mpFont->mnSize);
386 break;
388 case awt::Key::Y:
389 case awt::Key::Z:
390 Scroll(+gnLineScrollFactor * mpFont->mnSize);
391 break;
393 case awt::Key::S:
394 ChangeFontSize(-1);
395 break;
397 case awt::Key::G:
398 ChangeFontSize(+1);
399 break;
401 case awt::Key::H:
402 if (mpTextView)
403 mpTextView->MoveCaret(
405 (rEvent.Modifiers == awt::KeyModifier::SHIFT)
406 ? cssa::AccessibleTextType::CHARACTER
407 : cssa::AccessibleTextType::WORD);
408 break;
410 case awt::Key::L:
411 if (mpTextView)
412 mpTextView->MoveCaret(
414 (rEvent.Modifiers == awt::KeyModifier::SHIFT)
415 ? cssa::AccessibleTextType::CHARACTER
416 : cssa::AccessibleTextType::WORD);
417 break;
421 void SAL_CALL PresenterNotesView::keyReleased (const awt::KeyEvent& rEvent)
422 throw (RuntimeException)
424 (void)rEvent;
427 //-----------------------------------------------------------------------------
429 void PresenterNotesView::Layout (void)
431 if ( ! mxParentWindow.is())
432 return;
433 awt::Rectangle aWindowBox (mxParentWindow->getPosSize());
434 geometry::RealRectangle2D aNewTextBoundingBox (0,0,aWindowBox.Width, aWindowBox.Height);
435 // Size the tool bar and the horizontal separator above it.
436 if (mxToolBarWindow.is())
438 const geometry::RealSize2D aToolBarSize (mpToolBar->GetMinimalSize());
439 const sal_Int32 nToolBarHeight = sal_Int32(aToolBarSize.Height + 0.5);
440 mxToolBarWindow->setPosSize(0, aWindowBox.Height - nToolBarHeight,
441 sal_Int32(aToolBarSize.Width + 0.5), nToolBarHeight,
442 awt::PosSize::POSSIZE);
443 aNewTextBoundingBox.Y2 -= nToolBarHeight;
444 mnSeparatorYLocation = aWindowBox.Height - nToolBarHeight - gnSpaceBelowSeparator;
445 aNewTextBoundingBox.Y2 = mnSeparatorYLocation - gnSpaceAboveSeparator;
446 // Place the close button.
447 if (mpCloseButton.get() != NULL)
448 mpCloseButton->SetCenter(geometry::RealPoint2D(
449 (aWindowBox.Width + aToolBarSize.Width) / 2,
450 aWindowBox.Height - aToolBarSize.Height/2));
452 // Check whether the vertical scroll bar is necessary.
453 if (mpScrollBar.get() != NULL)
455 bool bShowVerticalScrollbar (false);
458 const double nTextBoxHeight (aNewTextBoundingBox.Y2 - aNewTextBoundingBox.Y1);
459 const double nHeight (mpTextView->GetTotalTextHeight());
460 if (nHeight > nTextBoxHeight)
462 bShowVerticalScrollbar = true;
463 if(!Application::GetSettings().GetLayoutRTL())
464 aNewTextBoundingBox.X2 -= mpScrollBar->GetSize();
465 else
466 aNewTextBoundingBox.X1 += mpScrollBar->GetSize();
468 mpScrollBar->SetTotalSize(nHeight);
470 catch(beans::UnknownPropertyException&)
472 OSL_ASSERT(false);
474 if(Application::GetSettings().GetLayoutRTL())
476 mpScrollBar->SetVisible(bShowVerticalScrollbar);
477 mpScrollBar->SetPosSize(
478 geometry::RealRectangle2D(
479 aNewTextBoundingBox.X1 - mpScrollBar->GetSize(),
480 aNewTextBoundingBox.Y1,
481 aNewTextBoundingBox.X1,
482 aNewTextBoundingBox.Y2));
483 if( ! bShowVerticalScrollbar)
484 mpScrollBar->SetThumbPosition(0, false);
485 UpdateScrollBar();
487 else
489 mpScrollBar->SetVisible(bShowVerticalScrollbar);
490 mpScrollBar->SetPosSize(
491 geometry::RealRectangle2D(
492 aWindowBox.Width - mpScrollBar->GetSize(),
493 aNewTextBoundingBox.Y1,
494 aNewTextBoundingBox.X2 + mpScrollBar->GetSize(),
495 aNewTextBoundingBox.Y2));
496 if( ! bShowVerticalScrollbar)
497 mpScrollBar->SetThumbPosition(0, false);
498 UpdateScrollBar();
501 // Has the text area has changed it position or size?
502 if (aNewTextBoundingBox.X1 != maTextBoundingBox.X1
503 || aNewTextBoundingBox.Y1 != maTextBoundingBox.Y1
504 || aNewTextBoundingBox.X2 != maTextBoundingBox.X2
505 || aNewTextBoundingBox.Y2 != maTextBoundingBox.Y2)
507 maTextBoundingBox = aNewTextBoundingBox;
508 mpTextView->SetLocation(
509 geometry::RealPoint2D(
510 aNewTextBoundingBox.X1,
511 aNewTextBoundingBox.Y1));
512 mpTextView->SetSize(
513 geometry::RealSize2D(
514 aNewTextBoundingBox.X2 - aNewTextBoundingBox.X1,
515 aNewTextBoundingBox.Y2 - aNewTextBoundingBox.Y1));
519 void PresenterNotesView::Paint (const awt::Rectangle& rUpdateBox)
521 if ( ! mxParentWindow.is())
522 return;
523 if ( ! mxCanvas.is())
524 return;
526 if (mpBackground.get() == NULL)
527 mpBackground = mpPresenterController->GetViewBackground(mxViewId->getResourceURL());
529 if (rUpdateBox.Y < maTextBoundingBox.Y2
530 && rUpdateBox.X < maTextBoundingBox.X2)
532 PaintText(rUpdateBox);
535 mpTextView->Paint(rUpdateBox);
537 if (rUpdateBox.Y + rUpdateBox.Height > maTextBoundingBox.Y2)
539 PaintToolBar(rUpdateBox);
543 void PresenterNotesView::PaintToolBar (const awt::Rectangle& rUpdateBox)
545 awt::Rectangle aWindowBox (mxParentWindow->getPosSize());
547 rendering::ViewState aViewState (
548 geometry::AffineMatrix2D(1,0,0, 0,1,0),
549 NULL);
550 rendering::RenderState aRenderState(
551 geometry::AffineMatrix2D(1,0,0, 0,1,0),
552 NULL,
553 Sequence<double>(4),
554 rendering::CompositeOperation::SOURCE);
556 if (mpBackground.get() != NULL)
558 // Paint the background.
559 mpPresenterController->GetCanvasHelper()->Paint(
560 mpBackground,
561 mxCanvas,
562 rUpdateBox,
563 awt::Rectangle(0,sal_Int32(maTextBoundingBox.Y2),aWindowBox.Width,aWindowBox.Height),
564 awt::Rectangle());
567 // Paint the horizontal separator.
568 OSL_ASSERT(mxViewId.is());
569 PresenterCanvasHelper::SetDeviceColor(aRenderState, maSeparatorColor);
571 mxCanvas->drawLine(
572 geometry::RealPoint2D(0,mnSeparatorYLocation),
573 geometry::RealPoint2D(aWindowBox.Width,mnSeparatorYLocation),
574 aViewState,
575 aRenderState);
578 void PresenterNotesView::PaintText (const awt::Rectangle& rUpdateBox)
580 const awt::Rectangle aBox (PresenterGeometryHelper::Intersection(rUpdateBox,
581 PresenterGeometryHelper::ConvertRectangle(maTextBoundingBox)));
583 if (aBox.Width <= 0 || aBox.Height <= 0)
584 return;
586 rendering::ViewState aViewState (
587 geometry::AffineMatrix2D(1,0,0, 0,1,0),
588 PresenterGeometryHelper::CreatePolygon(aBox, mxCanvas->getDevice()));
589 rendering::RenderState aRenderState(
590 geometry::AffineMatrix2D(1,0,0, 0,1,0),
591 NULL,
592 Sequence<double>(3),
593 rendering::CompositeOperation::SOURCE);
595 if (mpBackground.get() != NULL)
597 // Paint the background.
598 mpPresenterController->GetCanvasHelper()->Paint(
599 mpBackground,
600 mxCanvas,
601 rUpdateBox,
602 aBox,
603 awt::Rectangle());
606 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
607 if (xSpriteCanvas.is())
608 xSpriteCanvas->updateScreen(sal_False);
611 void PresenterNotesView::Invalidate (void)
613 mpPresenterController->GetPaintManager()->Invalidate(
614 mxParentWindow,
615 PresenterGeometryHelper::ConvertRectangle(maTextBoundingBox));
618 void PresenterNotesView::Scroll (const double rnDistance)
622 mnTop += rnDistance;
623 mpTextView->SetOffset(0, mnTop);
625 UpdateScrollBar();
626 Invalidate();
628 catch (beans::UnknownPropertyException&)
632 void PresenterNotesView::SetTop (const double nTop)
636 mnTop = nTop;
637 mpTextView->SetOffset(0, mnTop);
639 UpdateScrollBar();
640 Invalidate();
642 catch (beans::UnknownPropertyException&)
646 void PresenterNotesView::ChangeFontSize (const sal_Int32 nSizeChange)
648 const sal_Int32 nNewSize (mpFont->mnSize + nSizeChange);
649 if (nNewSize > 5)
651 mpFont->mnSize = nNewSize;
652 mpFont->mxFont = NULL;
653 mpTextView->SetFont(mpFont);
655 Layout();
656 UpdateScrollBar();
657 Invalidate();
659 // Write the new font size to the configuration to make it persistent.
662 const OUString sStyleName (mpPresenterController->GetTheme()->GetStyleName(
663 mxViewId->getResourceURL()));
664 ::boost::shared_ptr<PresenterConfigurationAccess> pConfiguration (
665 mpPresenterController->GetTheme()->GetNodeForViewStyle(
666 sStyleName));
667 if (pConfiguration.get()==NULL || ! pConfiguration->IsValid())
668 return;
670 pConfiguration->GoToChild(OUString("Font"));
671 pConfiguration->SetProperty("Size", Any((sal_Int32)(nNewSize+0.5)));
672 pConfiguration->CommitChanges();
674 catch (Exception&)
676 OSL_ASSERT(false);
681 ::boost::shared_ptr<PresenterTextView> PresenterNotesView::GetTextView (void) const
683 return mpTextView;
686 void PresenterNotesView::UpdateScrollBar (void)
688 if (mpScrollBar.get() != NULL)
692 mpScrollBar->SetTotalSize(mpTextView->GetTotalTextHeight());
694 catch(beans::UnknownPropertyException&)
696 OSL_ASSERT(false);
699 mpScrollBar->SetLineHeight(mpFont->mnSize*1.2);
700 mpScrollBar->SetThumbPosition(mnTop, false);
702 mpScrollBar->SetThumbSize(maTextBoundingBox.Y2 - maTextBoundingBox.Y1);
703 mpScrollBar->CheckValues();
707 void PresenterNotesView::ThrowIfDisposed (void)
708 throw (::com::sun::star::lang::DisposedException)
710 if (rBHelper.bDisposed || rBHelper.bInDispose)
712 throw lang::DisposedException (
713 "PresenterNotesView object has already been disposed",
714 static_cast<uno::XWeak*>(this));
718 } } // end of namespace ::sdext::presenter
720 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */