1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: PresenterHelpView.cxx,v $
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>
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
;
58 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
61 namespace sdext
{ namespace presenter
{
64 const static sal_Int32
gnHorizontalGap (20);
65 const static sal_Int32
gnVerticalBorder (30);
66 const static sal_Int32
gnVerticalButtonPadding (12);
73 const OUString
& rsLine
,
74 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
);
75 bool IsEmpty (void) const;
78 geometry::RealSize2D maSize
;
79 double mnVerticalOffset
;
81 void CalculateSize (const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
);
84 class LineDescriptorList
88 const OUString
& rsText
,
89 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
90 const sal_Int32 nMaximalWidth
);
93 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
94 const sal_Int32 nMaximalWidth
);
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;
106 const OUString msText
;
107 ::boost::shared_ptr
<vector
<LineDescriptor
> > mpLineDescriptors
;
109 void SplitText (const ::rtl::OUString
& rsText
, vector
<rtl::OUString
>& rTextParts
);
111 const vector
<rtl::OUString
>& rTextParts
,
112 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
113 const sal_Int32 nMaximalWidth
);
119 Block (const Block
& rBlock
);
121 const OUString
& rsLeftText
,
122 const OUString
& rsRightText
,
123 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
124 const sal_Int32 nMaximalWidth
);
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
),
150 mpPresenterController(rpPresenterController
),
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();
168 mxWindow
->addWindowListener(this);
169 mxWindow
->addPaintListener(this);
170 Reference
<awt::XWindowPeer
> xPeer (mxWindow
, UNO_QUERY
);
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(
187 mpPresenterController
,
188 mpPresenterController
->GetTheme(),
191 A2S("HelpViewCloser"));
196 catch (RuntimeException
&)
207 PresenterHelpView::~PresenterHelpView (void)
214 void SAL_CALL
PresenterHelpView::disposing (void)
218 if (mpCloseButton
.is())
220 Reference
<lang::XComponent
> xComponent (
221 static_cast<XWeak
*>(mpCloseButton
.get()), UNO_QUERY
);
222 mpCloseButton
= NULL
;
224 xComponent
->dispose();
229 mxWindow
->removeWindowListener(this);
230 mxWindow
->removePaintListener(this);
237 //----- lang::XEventListener --------------------------------------------------
239 void SAL_CALL
PresenterHelpView::disposing (const lang::EventObject
& rEventObject
)
240 throw (RuntimeException
)
242 if (rEventObject
.Source
== mxCanvas
)
246 else if (rEventObject
.Source
== mxWindow
)
256 //----- XWindowListener -------------------------------------------------------
258 void SAL_CALL
PresenterHelpView::windowResized (const awt::WindowEvent
& rEvent
)
259 throw (uno::RuntimeException
)
269 void SAL_CALL
PresenterHelpView::windowMoved (const awt::WindowEvent
& rEvent
)
270 throw (uno::RuntimeException
)
279 void SAL_CALL
PresenterHelpView::windowShown (const lang::EventObject
& rEvent
)
280 throw (uno::RuntimeException
)
290 void SAL_CALL
PresenterHelpView::windowHidden (const lang::EventObject
& rEvent
)
291 throw (uno::RuntimeException
)
300 //----- XPaintListener --------------------------------------------------------
302 void SAL_CALL
PresenterHelpView::windowPaint (const css::awt::PaintEvent
& rEvent
)
303 throw (RuntimeException
)
305 Paint(rEvent
.UpdateRect
);
311 void PresenterHelpView::Paint (const awt::Rectangle
& rUpdateBox
)
314 if ( ! mxCanvas
.is())
318 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
319 mpPresenterController
->GetCanvasHelper()->Paint(
320 mpPresenterController
->GetViewBackground(mxViewId
->getResourceURL()),
321 Reference
<rendering::XCanvas
>(mxCanvas
, UNO_QUERY
),
323 awt::Rectangle(0,0,aWindowBox
.Width
,aWindowBox
.Height
),
326 // Paint vertical divider.
328 rendering::ViewState
aViewState(
329 geometry::AffineMatrix2D(1,0,0, 0,1,0),
330 PresenterGeometryHelper::CreatePolygon(rUpdateBox
, mxCanvas
->getDevice()));
332 rendering::RenderState
aRenderState (
333 geometry::AffineMatrix2D(1,0,0, 0,1,0),
336 rendering::CompositeOperation::SOURCE
);
337 PresenterCanvasHelper::SetDeviceColor(aRenderState
, mpFont
->mnColor
);
340 geometry::RealPoint2D(aWindowBox
.Width
/2, gnVerticalBorder
),
341 geometry::RealPoint2D(aWindowBox
.Width
/2, mnSeparatorY
- gnVerticalBorder
),
345 // Paint the horizontal separator.
347 geometry::RealPoint2D(0, mnSeparatorY
),
348 geometry::RealPoint2D(aWindowBox
.Width
, mnSeparatorY
),
353 double nY (gnVerticalBorder
);
354 TextContainer::const_iterator
iBlock (mpTextContainer
->begin());
355 TextContainer::const_iterator
iBlockEnd (mpTextContainer
->end());
356 for ( ; iBlock
!=iBlockEnd
; ++iBlock
)
358 const double nLeftHeight (
359 (*iBlock
)->maLeft
.Paint(mxCanvas
,
360 geometry::RealRectangle2D(
363 aWindowBox
.Width
/2 - gnHorizontalGap
,
364 aWindowBox
.Height
- gnVerticalBorder
),
369 const double nRightHeight (
370 (*iBlock
)->maRight
.Paint(mxCanvas
,
371 geometry::RealRectangle2D(
372 aWindowBox
.Width
/2 + gnHorizontalGap
,
374 aWindowBox
.Width
- gnHorizontalGap
,
375 aWindowBox
.Height
- gnVerticalBorder
),
380 nY
+= ::std::max(nLeftHeight
,nRightHeight
);
383 Reference
<rendering::XSpriteCanvas
> xSpriteCanvas (mxCanvas
, UNO_QUERY
);
384 if (xSpriteCanvas
.is())
385 xSpriteCanvas
->updateScreen(sal_False
);
391 void PresenterHelpView::ReadHelpStrings (void)
393 mpTextContainer
.reset(new TextContainer());
394 PresenterConfigurationAccess
aConfiguration (
396 OUString::createFromAscii("/org.openoffice.Office.extension.PresenterScreen/"),
397 PresenterConfigurationAccess::READ_ONLY
);
398 Reference
<container::XNameAccess
> xStrings (
399 aConfiguration
.GetConfigurationNode(A2S("PresenterScreenSettings/HelpView/HelpStrings")),
401 PresenterConfigurationAccess::ForAll(
403 ::boost::bind(&PresenterHelpView::ProcessString
, this, _2
));
409 void PresenterHelpView::ProcessString (
410 const Reference
<beans::XPropertySet
>& rsProperties
)
412 if ( ! rsProperties
.is())
416 PresenterConfigurationAccess::GetProperty(rsProperties
, A2S("Left")) >>= sLeftText
;
418 PresenterConfigurationAccess::GetProperty(rsProperties
, A2S("Right")) >>= sRightText
;
420 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
421 mpTextContainer
->push_back(
422 ::boost::shared_ptr
<Block
>(
423 new Block(sLeftText
, sRightText
, mpFont
->mxFont
, mnMaximalWidth
)));
429 void PresenterHelpView::CheckFontSize (void)
431 if (mpFont
.get() == NULL
)
434 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
435 if (aWindowBox
.Width
<=0 || aWindowBox
.Height
<=0)
438 sal_Int32
nBestSize (6);
440 // Scaling down and then reformatting can cause the text to be too large
441 // still. So do this again and again until the text size is
442 // small enough. Restrict the number of loops.
443 for (int nLoopCount
=0; nLoopCount
<5; ++nLoopCount
)
445 double nY (gnVerticalBorder
);
446 TextContainer::iterator
iBlock (mpTextContainer
->begin());
447 TextContainer::const_iterator
iBlockEnd (mpTextContainer
->end());
448 for ( ; iBlock
!=iBlockEnd
; ++iBlock
)
450 (*iBlock
)->maLeft
.GetHeight(),
451 (*iBlock
)->maRight
.GetHeight());
453 const double nHeightDifference (nY
- (aWindowBox
.Height
-gnVerticalBorder
));
454 if (nHeightDifference
<= 0 && nHeightDifference
> -50)
456 // We have found a good font size that is large and leaves not
457 // too much space below the help text.
461 // Font is too large. Make it smaller.
463 // Use a simple linear transformation to calculate initial guess of
464 // a size that lets all help text be shown inside the window.
465 const double nScale (double(aWindowBox
.Height
-gnVerticalBorder
) / nY
);
466 if (nScale
> 0.95 && nScale
<1.05)
469 sal_Int32
nFontSizeGuess (::std::max(sal_Int32(1),sal_Int32(mpFont
->mnSize
* nScale
)));
470 if (nHeightDifference
<0 && mpFont
->mnSize
>nBestSize
)
471 nBestSize
= mpFont
->mnSize
;
472 mpFont
->mnSize
= nFontSizeGuess
;
473 mpFont
->mxFont
= NULL
;
474 mpFont
->PrepareFont(mxCanvas
);
477 for (iBlock
=mpTextContainer
->begin(); iBlock
!=iBlockEnd
; ++iBlock
)
478 (*iBlock
)->Update(mpFont
->mxFont
, mnMaximalWidth
);
481 if (nBestSize
!= mpFont
->mnSize
)
483 mpFont
->mnSize
= nBestSize
;
484 mpFont
->mxFont
= NULL
;
485 mpFont
->PrepareFont(mxCanvas
);
488 for (TextContainer::iterator
489 iBlock (mpTextContainer
->begin()),
490 iEnd (mpTextContainer
->end());
494 (*iBlock
)->Update(mpFont
->mxFont
, mnMaximalWidth
);
502 //----- XResourceId -----------------------------------------------------------
504 Reference
<XResourceId
> SAL_CALL
PresenterHelpView::getResourceId (void)
505 throw (RuntimeException
)
514 sal_Bool SAL_CALL
PresenterHelpView::isAnchorOnly (void)
515 throw (RuntimeException
)
523 //-----------------------------------------------------------------------------
525 void PresenterHelpView::ProvideCanvas (void)
527 if ( ! mxCanvas
.is() && mxPane
.is())
529 mxCanvas
= mxPane
->getCanvas();
530 if ( ! mxCanvas
.is())
532 Reference
<lang::XComponent
> xComponent (mxCanvas
, UNO_QUERY
);
534 xComponent
->addEventListener(static_cast<awt::XPaintListener
*>(this));
536 if (mpCloseButton
.is())
537 mpCloseButton
->SetCanvas(mxCanvas
, mxWindow
);
544 void PresenterHelpView::Resize (void)
546 if (mpCloseButton
.get() != NULL
&& mxWindow
.is())
548 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
549 mnMaximalWidth
= (mxWindow
->getPosSize().Width
- 4*gnHorizontalGap
) / 2;
551 // Place vertical separator.
552 mnSeparatorY
= aWindowBox
.Height
553 - mpCloseButton
->GetSize().Height
- gnVerticalButtonPadding
;
555 mpCloseButton
->SetCenter(geometry::RealPoint2D(
557 aWindowBox
.Height
- mpCloseButton
->GetSize().Height
/2));
566 void PresenterHelpView::ThrowIfDisposed (void)
567 throw (lang::DisposedException
)
569 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
571 throw lang::DisposedException (
572 OUString(RTL_CONSTASCII_USTRINGPARAM(
573 "PresenterHelpView has been already disposed")),
574 const_cast<uno::XWeak
*>(static_cast<const uno::XWeak
*>(this)));
581 //===== LineDescritor =========================================================
585 LineDescriptor::LineDescriptor (void)
595 void LineDescriptor::AddPart (
596 const OUString
& rsLine
,
597 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
)
601 CalculateSize(rxFont
);
607 bool LineDescriptor::IsEmpty (void) const
609 return msLine
.getLength()==0;
615 void LineDescriptor::CalculateSize (
616 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
)
618 OSL_ASSERT(rxFont
.is());
620 rendering::StringContext
aContext (msLine
, 0, msLine
.getLength());
621 Reference
<rendering::XTextLayout
> xLayout (
622 rxFont
->createTextLayout(aContext
, rendering::TextDirection::WEAK_LEFT_TO_RIGHT
, 0));
623 const geometry::RealRectangle2D
aTextBBox (xLayout
->queryTextBounds());
624 maSize
= css::geometry::RealSize2D(aTextBBox
.X2
- aTextBBox
.X1
, aTextBBox
.Y2
- aTextBBox
.Y1
);
625 mnVerticalOffset
= aTextBBox
.Y2
;
628 } // end of anonymous namespace
633 //===== LineDescriptorList ====================================================
637 LineDescriptorList::LineDescriptorList (
638 const OUString
& rsText
,
639 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
640 const sal_Int32 nMaximalWidth
)
643 Update(rxFont
, nMaximalWidth
);
649 double LineDescriptorList::Paint(
650 const Reference
<rendering::XCanvas
>& rxCanvas
,
651 const geometry::RealRectangle2D
& rBBox
,
652 const bool bFlushLeft
,
653 const rendering::ViewState
& rViewState
,
654 rendering::RenderState
& rRenderState
,
655 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
) const
657 if ( ! rxCanvas
.is())
660 double nY (rBBox
.Y1
);
661 vector
<LineDescriptor
>::const_iterator
iLine (mpLineDescriptors
->begin());
662 vector
<LineDescriptor
>::const_iterator
iEnd (mpLineDescriptors
->end());
663 for ( ; iLine
!=iEnd
; ++iLine
)
665 double nX (rBBox
.X1
);
667 nX
= rBBox
.X2
- iLine
->maSize
.Width
;
668 rRenderState
.AffineTransform
.m02
= nX
;
669 rRenderState
.AffineTransform
.m12
= nY
+ iLine
->maSize
.Height
- iLine
->mnVerticalOffset
;
671 const rendering::StringContext
aContext (iLine
->msLine
, 0, iLine
->msLine
.getLength());
678 rendering::TextDirection::WEAK_LEFT_TO_RIGHT
);
680 nY
+= iLine
->maSize
.Height
* 1.2;
683 return nY
- rBBox
.Y1
;
689 double LineDescriptorList::GetHeight (void) const
692 vector
<LineDescriptor
>::const_iterator
iLine (mpLineDescriptors
->begin());
693 vector
<LineDescriptor
>::const_iterator
iEnd (mpLineDescriptors
->end());
694 for ( ; iLine
!=iEnd
; ++iLine
)
695 nHeight
+= iLine
->maSize
.Height
* 1.2;
703 void LineDescriptorList::Update (
704 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
705 const sal_Int32 nMaximalWidth
)
707 vector
<OUString
> aTextParts
;
708 SplitText(msText
, aTextParts
);
709 FormatText(aTextParts
, rxFont
, nMaximalWidth
);
715 void LineDescriptorList::SplitText (
716 const OUString
& rsText
,
717 vector
<OUString
>& rTextParts
)
719 const sal_Char
cQuote ('\'');
720 const sal_Char
cSeparator (',');
722 sal_Int32
nIndex (0);
723 sal_Int32
nStart (0);
724 sal_Int32
nLength (rsText
.getLength());
725 bool bIsQuoted (false);
726 while (nIndex
< nLength
)
728 const sal_Int32
nQuoteIndex (rsText
.indexOf(cQuote
, nIndex
));
729 const sal_Int32
nSeparatorIndex (rsText
.indexOf(cSeparator
, nIndex
));
730 if (nQuoteIndex
>=0 && (nSeparatorIndex
==-1 || nQuoteIndex
<nSeparatorIndex
))
732 bIsQuoted
= !bIsQuoted
;
733 nIndex
= nQuoteIndex
+1;
737 const sal_Int32 nNextIndex
= nSeparatorIndex
;
742 else if ( ! bIsQuoted
)
744 rTextParts
.push_back(rsText
.copy(nStart
, nNextIndex
-nStart
));
745 nStart
= nNextIndex
+ 1;
747 nIndex
= nNextIndex
+1;
749 if (nStart
< nLength
)
750 rTextParts
.push_back(rsText
.copy(nStart
, nLength
-nStart
));
756 void LineDescriptorList::FormatText (
757 const vector
<OUString
>& rTextParts
,
758 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
759 const sal_Int32 nMaximalWidth
)
761 LineDescriptor aLineDescriptor
;
763 mpLineDescriptors
.reset(new vector
<LineDescriptor
>());
765 vector
<OUString
>::const_iterator
iPart (rTextParts
.begin());
766 vector
<OUString
>::const_iterator
iEnd (rTextParts
.end());
767 for ( ; iPart
!=iEnd
; ++iPart
)
769 if (aLineDescriptor
.IsEmpty())
771 // Avoid empty lines.
772 aLineDescriptor
.AddPart(*iPart
, rxFont
);
774 else if (PresenterCanvasHelper::GetTextSize(
775 rxFont
, aLineDescriptor
.msLine
+A2S(", ")+*iPart
).Width
> nMaximalWidth
)
777 aLineDescriptor
.AddPart(A2S(","), rxFont
);
778 mpLineDescriptors
->push_back(aLineDescriptor
);
779 aLineDescriptor
= LineDescriptor();
780 aLineDescriptor
.AddPart(*iPart
, rxFont
);
784 aLineDescriptor
.AddPart(A2S(", ")+*iPart
, rxFont
);
787 if ( ! aLineDescriptor
.IsEmpty())
789 mpLineDescriptors
->push_back(aLineDescriptor
);
794 } // end of anonymous namespace
799 //===== Block =================================================================
804 const OUString
& rsLeftText
,
805 const OUString
& rsRightText
,
806 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
807 const sal_Int32 nMaximalWidth
)
808 : maLeft(rsLeftText
, rxFont
, nMaximalWidth
),
809 maRight(rsRightText
, rxFont
, nMaximalWidth
)
816 const css::uno::Reference
<css::rendering::XCanvasFont
>& rxFont
,
817 const sal_Int32 nMaximalWidth
)
819 maLeft
.Update(rxFont
, nMaximalWidth
);
820 maRight
.Update(rxFont
, nMaximalWidth
);
823 } // end of anonymous namespace
825 } } // end of namespace ::sdext::presenter