update dev300-m58
[ooovba.git] / sdext / source / presenter / PresenterHelpView.cxx
blob5bc11400e87a9e0d2904c7431c258c9fc70e7d80
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: PresenterHelpView.cxx,v $
11 * $Revision: 1.6 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_sdext.hxx"
35 #include "PresenterHelpView.hxx"
36 #include "PresenterButton.hxx"
37 #include "PresenterCanvasHelper.hxx"
38 #include "PresenterGeometryHelper.hxx"
39 #include "PresenterHelper.hxx"
40 #include "PresenterWindowManager.hxx"
41 #include <com/sun/star/awt/XWindowPeer.hpp>
42 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
44 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
45 #include <com/sun/star/rendering/CompositeOperation.hpp>
46 #include <com/sun/star/rendering/TextDirection.hpp>
47 #include <com/sun/star/util/Color.hpp>
48 #include <algorithm>
49 #include <vector>
50 #include <boost/bind.hpp>
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::drawing::framework;
55 using ::rtl::OUString;
56 using ::std::vector;
58 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
61 namespace sdext { namespace presenter {
63 namespace {
64 const static sal_Int32 gnHorizontalGap (20);
65 const static sal_Int32 gnVerticalBorder (30);
66 const static sal_Int32 gnVerticalButtonPadding (12);
68 class LineDescriptor
70 public:
71 LineDescriptor(void);
72 void AddPart (
73 const OUString& rsLine,
74 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont);
75 bool IsEmpty (void) const;
77 OUString msLine;
78 geometry::RealSize2D maSize;
79 double mnVerticalOffset;
81 void CalculateSize (const css::uno::Reference<css::rendering::XCanvasFont>& rxFont);
84 class LineDescriptorList
86 public:
87 LineDescriptorList (
88 const OUString& rsText,
89 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
90 const sal_Int32 nMaximalWidth);
92 void Update (
93 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
94 const sal_Int32 nMaximalWidth);
96 double Paint(
97 const Reference<rendering::XCanvas>& rxCanvas,
98 const geometry::RealRectangle2D& rBBox,
99 const bool bFlushLeft,
100 const rendering::ViewState& rViewState,
101 rendering::RenderState& rRenderState,
102 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont) const;
103 double GetHeight (void) const;
105 private:
106 const OUString msText;
107 ::boost::shared_ptr<vector<LineDescriptor> > mpLineDescriptors;
109 void SplitText (const ::rtl::OUString& rsText, vector<rtl::OUString>& rTextParts);
110 void FormatText (
111 const vector<rtl::OUString>& rTextParts,
112 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
113 const sal_Int32 nMaximalWidth);
116 class Block
118 public:
119 Block (const Block& rBlock);
120 Block (
121 const OUString& rsLeftText,
122 const OUString& rsRightText,
123 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
124 const sal_Int32 nMaximalWidth);
125 void Update (
126 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
127 const sal_Int32 nMaximalWidth);
129 LineDescriptorList maLeft;
130 LineDescriptorList maRight;
132 } // end of anonymous namespace
134 class PresenterHelpView::TextContainer : public vector<boost::shared_ptr<Block> >
139 PresenterHelpView::PresenterHelpView (
140 const Reference<uno::XComponentContext>& rxContext,
141 const Reference<XResourceId>& rxViewId,
142 const Reference<frame::XController>& rxController,
143 const ::rtl::Reference<PresenterController>& rpPresenterController)
144 : PresenterHelpViewInterfaceBase(m_aMutex),
145 mxComponentContext(rxContext),
146 mxViewId(rxViewId),
147 mxPane(),
148 mxWindow(),
149 mxCanvas(),
150 mpPresenterController(rpPresenterController),
151 mpFont(),
152 mpTextContainer(),
153 mpCloseButton(),
154 mnSeparatorY(0),
155 mnMaximalWidth(0)
159 // Get the content window via the pane anchor.
160 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
161 Reference<XConfigurationController> xCC (
162 xCM->getConfigurationController(), UNO_QUERY_THROW);
163 mxPane = Reference<XPane>(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
165 mxWindow = mxPane->getWindow();
166 ProvideCanvas();
168 mxWindow->addWindowListener(this);
169 mxWindow->addPaintListener(this);
170 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
171 if (xPeer.is())
172 xPeer->setBackground(util::Color(0xff000000));
173 mxWindow->setVisible(sal_True);
175 if (mpPresenterController.is())
177 mpFont = mpPresenterController->GetViewFont(mxViewId->getResourceURL());
178 if (mpFont.get() != NULL)
180 mpFont->PrepareFont(mxCanvas);
184 // Create the close button.
185 mpCloseButton = PresenterButton::Create(
186 mxComponentContext,
187 mpPresenterController,
188 mpPresenterController->GetTheme(),
189 mxWindow,
190 mxCanvas,
191 A2S("HelpViewCloser"));
193 mnMaximalWidth = (mxWindow->getPosSize().Width - 4*gnHorizontalGap) / 2;
194 ReadHelpStrings();
195 CheckFontSize();
196 Resize();
198 catch (RuntimeException&)
200 mxViewId = NULL;
201 mxWindow = NULL;
202 throw;
209 PresenterHelpView::~PresenterHelpView (void)
216 void SAL_CALL PresenterHelpView::disposing (void)
218 mxViewId = NULL;
220 if (mpCloseButton.is())
222 Reference<lang::XComponent> xComponent (
223 static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY);
224 mpCloseButton = NULL;
225 if (xComponent.is())
226 xComponent->dispose();
229 if (mxWindow.is())
231 mxWindow->removeWindowListener(this);
232 mxWindow->removePaintListener(this);
239 //----- lang::XEventListener --------------------------------------------------
241 void SAL_CALL PresenterHelpView::disposing (const lang::EventObject& rEventObject)
242 throw (RuntimeException)
244 if (rEventObject.Source == mxCanvas)
246 mxCanvas = NULL;
248 else if (rEventObject.Source == mxWindow)
250 mxWindow = NULL;
251 dispose();
258 //----- XWindowListener -------------------------------------------------------
260 void SAL_CALL PresenterHelpView::windowResized (const awt::WindowEvent& rEvent)
261 throw (uno::RuntimeException)
263 (void)rEvent;
264 ThrowIfDisposed();
265 Resize();
271 void SAL_CALL PresenterHelpView::windowMoved (const awt::WindowEvent& rEvent)
272 throw (uno::RuntimeException)
274 (void)rEvent;
275 ThrowIfDisposed();
281 void SAL_CALL PresenterHelpView::windowShown (const lang::EventObject& rEvent)
282 throw (uno::RuntimeException)
284 (void)rEvent;
285 ThrowIfDisposed();
286 Resize();
292 void SAL_CALL PresenterHelpView::windowHidden (const lang::EventObject& rEvent)
293 throw (uno::RuntimeException)
295 (void)rEvent;
296 ThrowIfDisposed();
302 //----- XPaintListener --------------------------------------------------------
304 void SAL_CALL PresenterHelpView::windowPaint (const css::awt::PaintEvent& rEvent)
305 throw (RuntimeException)
307 Paint(rEvent.UpdateRect);
313 void PresenterHelpView::Paint (const awt::Rectangle& rUpdateBox)
315 ProvideCanvas();
316 if ( ! mxCanvas.is())
317 return;
319 // Clear background.
320 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
321 mpPresenterController->GetCanvasHelper()->Paint(
322 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
323 Reference<rendering::XCanvas>(mxCanvas, UNO_QUERY),
324 rUpdateBox,
325 awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
326 awt::Rectangle());
328 // Paint vertical divider.
330 rendering::ViewState aViewState(
331 geometry::AffineMatrix2D(1,0,0, 0,1,0),
332 PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
334 rendering::RenderState aRenderState (
335 geometry::AffineMatrix2D(1,0,0, 0,1,0),
336 NULL,
337 Sequence<double>(4),
338 rendering::CompositeOperation::SOURCE);
339 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
341 mxCanvas->drawLine(
342 geometry::RealPoint2D(aWindowBox.Width/2, gnVerticalBorder),
343 geometry::RealPoint2D(aWindowBox.Width/2, mnSeparatorY - gnVerticalBorder),
344 aViewState,
345 aRenderState);
347 // Paint the horizontal separator.
348 mxCanvas->drawLine(
349 geometry::RealPoint2D(0, mnSeparatorY),
350 geometry::RealPoint2D(aWindowBox.Width, mnSeparatorY),
351 aViewState,
352 aRenderState);
354 // Paint text.
355 double nY (gnVerticalBorder);
356 TextContainer::const_iterator iBlock (mpTextContainer->begin());
357 TextContainer::const_iterator iBlockEnd (mpTextContainer->end());
358 for ( ; iBlock!=iBlockEnd; ++iBlock)
360 const double nLeftHeight (
361 (*iBlock)->maLeft.Paint(mxCanvas,
362 geometry::RealRectangle2D(
363 gnHorizontalGap,
365 aWindowBox.Width/2 - gnHorizontalGap,
366 aWindowBox.Height - gnVerticalBorder),
367 false,
368 aViewState,
369 aRenderState,
370 mpFont->mxFont));
371 const double nRightHeight (
372 (*iBlock)->maRight.Paint(mxCanvas,
373 geometry::RealRectangle2D(
374 aWindowBox.Width/2 + gnHorizontalGap,
376 aWindowBox.Width - gnHorizontalGap,
377 aWindowBox.Height - gnVerticalBorder),
378 true,
379 aViewState,
380 aRenderState,
381 mpFont->mxFont));
382 nY += ::std::max(nLeftHeight,nRightHeight);
385 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
386 if (xSpriteCanvas.is())
387 xSpriteCanvas->updateScreen(sal_False);
393 void PresenterHelpView::ReadHelpStrings (void)
395 mpTextContainer.reset(new TextContainer());
396 PresenterConfigurationAccess aConfiguration (
397 mxComponentContext,
398 OUString::createFromAscii("/org.openoffice.Office.extension.PresenterScreen/"),
399 PresenterConfigurationAccess::READ_ONLY);
400 Reference<container::XNameAccess> xStrings (
401 aConfiguration.GetConfigurationNode(A2S("PresenterScreenSettings/HelpView/HelpStrings")),
402 UNO_QUERY);
403 PresenterConfigurationAccess::ForAll(
404 xStrings,
405 ::boost::bind(&PresenterHelpView::ProcessString, this, _2));
411 void PresenterHelpView::ProcessString (
412 const Reference<beans::XPropertySet>& rsProperties)
414 if ( ! rsProperties.is())
415 return;
417 OUString sLeftText;
418 PresenterConfigurationAccess::GetProperty(rsProperties, A2S("Left")) >>= sLeftText;
419 OUString sRightText;
420 PresenterConfigurationAccess::GetProperty(rsProperties, A2S("Right")) >>= sRightText;
422 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
423 mpTextContainer->push_back(
424 ::boost::shared_ptr<Block>(
425 new Block(sLeftText, sRightText, mpFont->mxFont, mnMaximalWidth)));
431 void PresenterHelpView::CheckFontSize (void)
433 if (mpFont.get() == NULL)
434 return;
436 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
438 // Scaling down and then reformatting can cause the text to be too large
439 // still. So do this again and again until the text size is
440 // small enough. Restrict the number of loops.
441 for (int nLoopCount=0; nLoopCount<5; ++nLoopCount)
443 double nY (gnVerticalBorder);
444 TextContainer::iterator iBlock (mpTextContainer->begin());
445 TextContainer::const_iterator iBlockEnd (mpTextContainer->end());
446 for ( ; iBlock!=iBlockEnd; ++iBlock)
447 nY += ::std::max(
448 (*iBlock)->maLeft.GetHeight(),
449 (*iBlock)->maRight.GetHeight());
451 if (nY <= aWindowBox.Height-gnVerticalBorder)
452 break;
454 // Font is too large. Make it smaller.
456 // Use a simple linear transformation to calculate initial guess of
457 // a size that lets all help text be shown inside the window.
458 const double nScale (::std::min(0.95,double(aWindowBox.Height-gnVerticalBorder) / nY));
459 sal_Int32 nFontSizeGuess (::std::max(sal_Int32(1),sal_Int32(mpFont->mnSize * nScale)));
460 mpFont->mnSize = nFontSizeGuess;
461 mpFont->mxFont = NULL;
462 mpFont->PrepareFont(mxCanvas);
464 // Reformat blocks.
465 for (iBlock=mpTextContainer->begin(); iBlock!=iBlockEnd; ++iBlock)
466 (*iBlock)->Update(mpFont->mxFont, mnMaximalWidth);
473 //----- XResourceId -----------------------------------------------------------
475 Reference<XResourceId> SAL_CALL PresenterHelpView::getResourceId (void)
476 throw (RuntimeException)
478 ThrowIfDisposed();
479 return mxViewId;
485 sal_Bool SAL_CALL PresenterHelpView::isAnchorOnly (void)
486 throw (RuntimeException)
488 return false;
494 //-----------------------------------------------------------------------------
496 void PresenterHelpView::ProvideCanvas (void)
498 if ( ! mxCanvas.is() && mxPane.is())
500 mxCanvas = mxPane->getCanvas();
501 if ( ! mxCanvas.is())
502 return;
503 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
504 if (xComponent.is())
505 xComponent->addEventListener(static_cast<awt::XPaintListener*>(this));
507 if (mpCloseButton.is())
508 mpCloseButton->SetCanvas(mxCanvas, mxWindow);
515 void PresenterHelpView::Resize (void)
517 if (mpCloseButton.get() != NULL && mxWindow.is())
519 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
521 // Place vertical separator.
522 mnSeparatorY = aWindowBox.Height
523 - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
525 mpCloseButton->SetCenter(geometry::RealPoint2D(
526 aWindowBox.Width/2,
527 aWindowBox.Height - mpCloseButton->GetSize().Height/2));
534 void PresenterHelpView::ThrowIfDisposed (void)
535 throw (lang::DisposedException)
537 if (rBHelper.bDisposed || rBHelper.bInDispose)
539 throw lang::DisposedException (
540 OUString(RTL_CONSTASCII_USTRINGPARAM(
541 "PresenterHelpView has been already disposed")),
542 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
549 //===== LineDescritor =========================================================
551 namespace {
553 LineDescriptor::LineDescriptor (void)
554 : msLine(),
555 maSize(0,0),
556 mnVerticalOffset(0)
563 void LineDescriptor::AddPart (
564 const OUString& rsLine,
565 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
567 msLine += rsLine;
569 CalculateSize(rxFont);
575 bool LineDescriptor::IsEmpty (void) const
577 return msLine.getLength()==0;
583 void LineDescriptor::CalculateSize (
584 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
586 OSL_ASSERT(rxFont.is());
588 rendering::StringContext aContext (msLine, 0, msLine.getLength());
589 Reference<rendering::XTextLayout> xLayout (
590 rxFont->createTextLayout(aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
591 const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
592 maSize = css::geometry::RealSize2D(aTextBBox.X2 - aTextBBox.X1, aTextBBox.Y2 - aTextBBox.Y1);
593 mnVerticalOffset = aTextBBox.Y2;
596 } // end of anonymous namespace
601 //===== LineDescriptorList ====================================================
603 namespace {
605 LineDescriptorList::LineDescriptorList (
606 const OUString& rsText,
607 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
608 const sal_Int32 nMaximalWidth)
609 : msText(rsText)
611 Update(rxFont, nMaximalWidth);
617 double LineDescriptorList::Paint(
618 const Reference<rendering::XCanvas>& rxCanvas,
619 const geometry::RealRectangle2D& rBBox,
620 const bool bFlushLeft,
621 const rendering::ViewState& rViewState,
622 rendering::RenderState& rRenderState,
623 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont) const
625 if ( ! rxCanvas.is())
626 return 0;
628 double nY (rBBox.Y1);
629 vector<LineDescriptor>::const_iterator iLine (mpLineDescriptors->begin());
630 vector<LineDescriptor>::const_iterator iEnd (mpLineDescriptors->end());
631 for ( ; iLine!=iEnd; ++iLine)
633 double nX (rBBox.X1);
634 if ( ! bFlushLeft)
635 nX = rBBox.X2 - iLine->maSize.Width;
636 rRenderState.AffineTransform.m02 = nX;
637 rRenderState.AffineTransform.m12 = nY + iLine->maSize.Height - iLine->mnVerticalOffset;
639 const rendering::StringContext aContext (iLine->msLine, 0, iLine->msLine.getLength());
641 rxCanvas->drawText (
642 aContext,
643 rxFont,
644 rViewState,
645 rRenderState,
646 rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
648 nY += iLine->maSize.Height * 1.2;
651 return nY - rBBox.Y1;
657 double LineDescriptorList::GetHeight (void) const
659 double nHeight (0);
660 vector<LineDescriptor>::const_iterator iLine (mpLineDescriptors->begin());
661 vector<LineDescriptor>::const_iterator iEnd (mpLineDescriptors->end());
662 for ( ; iLine!=iEnd; ++iLine)
663 nHeight += iLine->maSize.Height * 1.2;
665 return nHeight;
671 void LineDescriptorList::Update (
672 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
673 const sal_Int32 nMaximalWidth)
675 vector<OUString> aTextParts;
676 SplitText(msText, aTextParts);
677 FormatText(aTextParts, rxFont, nMaximalWidth);
683 void LineDescriptorList::SplitText (
684 const OUString& rsText,
685 vector<OUString>& rTextParts)
687 const sal_Char cQuote ('\'');
688 const sal_Char cSeparator (',');
690 sal_Int32 nIndex (0);
691 sal_Int32 nStart (0);
692 sal_Int32 nLength (rsText.getLength());
693 bool bIsQuoted (false);
694 while (nIndex < nLength)
696 const sal_Int32 nQuoteIndex (rsText.indexOf(cQuote, nIndex));
697 const sal_Int32 nSeparatorIndex (rsText.indexOf(cSeparator, nIndex));
698 if (nQuoteIndex>=0 && (nSeparatorIndex==-1 || nQuoteIndex<nSeparatorIndex))
700 bIsQuoted = !bIsQuoted;
701 nIndex = nQuoteIndex+1;
702 continue;
705 const sal_Int32 nNextIndex = nSeparatorIndex;
706 if (nNextIndex < 0)
708 break;
710 else if ( ! bIsQuoted)
712 rTextParts.push_back(rsText.copy(nStart, nNextIndex-nStart));
713 nStart = nNextIndex + 1;
715 nIndex = nNextIndex+1;
717 if (nStart < nLength)
718 rTextParts.push_back(rsText.copy(nStart, nLength-nStart));
724 void LineDescriptorList::FormatText (
725 const vector<OUString>& rTextParts,
726 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
727 const sal_Int32 nMaximalWidth)
729 LineDescriptor aLineDescriptor;
731 mpLineDescriptors.reset(new vector<LineDescriptor>());
733 vector<OUString>::const_iterator iPart (rTextParts.begin());
734 vector<OUString>::const_iterator iEnd (rTextParts.end());
735 for ( ; iPart!=iEnd; ++iPart)
737 if (aLineDescriptor.IsEmpty())
739 // Avoid empty lines.
740 aLineDescriptor.AddPart(*iPart, rxFont);
742 else if (PresenterCanvasHelper::GetTextSize(
743 rxFont, aLineDescriptor.msLine+A2S(", ")+*iPart).Width > nMaximalWidth)
745 aLineDescriptor.AddPart(A2S(","), rxFont);
746 mpLineDescriptors->push_back(aLineDescriptor);
747 aLineDescriptor = LineDescriptor();
748 aLineDescriptor.AddPart(*iPart, rxFont);
750 else
752 aLineDescriptor.AddPart(A2S(", ")+*iPart, rxFont);
755 if ( ! aLineDescriptor.IsEmpty())
756 mpLineDescriptors->push_back(aLineDescriptor);
760 } // end of anonymous namespace
765 //===== Block =================================================================
767 namespace {
769 Block::Block (
770 const OUString& rsLeftText,
771 const OUString& rsRightText,
772 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
773 const sal_Int32 nMaximalWidth)
774 : maLeft(rsLeftText, rxFont, nMaximalWidth),
775 maRight(rsRightText, rxFont, nMaximalWidth)
781 void Block::Update (
782 const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
783 const sal_Int32 nMaximalWidth)
785 maLeft.Update(rxFont, nMaximalWidth);
786 maRight.Update(rxFont, nMaximalWidth);
789 } // end of anonymous namespace
791 } } // end of namespace ::sdext::presenter